cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ca0106_mixer.c (27143B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk>
      4 *  Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit
      5 *  Version: 0.0.18
      6 *
      7 *  FEATURES currently supported:
      8 *    See ca0106_main.c for features.
      9 * 
     10 *  Changelog:
     11 *    Support interrupts per period.
     12 *    Removed noise from Center/LFE channel when in Analog mode.
     13 *    Rename and remove mixer controls.
     14 *  0.0.6
     15 *    Use separate card based DMA buffer for periods table list.
     16 *  0.0.7
     17 *    Change remove and rename ctrls into lists.
     18 *  0.0.8
     19 *    Try to fix capture sources.
     20 *  0.0.9
     21 *    Fix AC3 output.
     22 *    Enable S32_LE format support.
     23 *  0.0.10
     24 *    Enable playback 48000 and 96000 rates. (Rates other that these do not work, even with "plug:front".)
     25 *  0.0.11
     26 *    Add Model name recognition.
     27 *  0.0.12
     28 *    Correct interrupt timing. interrupt at end of period, instead of in the middle of a playback period.
     29 *    Remove redundent "voice" handling.
     30 *  0.0.13
     31 *    Single trigger call for multi channels.
     32 *  0.0.14
     33 *    Set limits based on what the sound card hardware can do.
     34 *    playback periods_min=2, periods_max=8
     35 *    capture hw constraints require period_size = n * 64 bytes.
     36 *    playback hw constraints require period_size = n * 64 bytes.
     37 *  0.0.15
     38 *    Separated ca0106.c into separate functional .c files.
     39 *  0.0.16
     40 *    Modified Copyright message.
     41 *  0.0.17
     42 *    Implement Mic and Line in Capture.
     43 *  0.0.18
     44 *    Add support for mute control on SB Live 24bit (cards w/ SPI DAC)
     45 *
     46 *  This code was initially based on code from ALSA's emu10k1x.c which is:
     47 *  Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
     48 */
     49#include <linux/delay.h>
     50#include <linux/init.h>
     51#include <linux/interrupt.h>
     52#include <linux/moduleparam.h>
     53#include <sound/core.h>
     54#include <sound/initval.h>
     55#include <sound/pcm.h>
     56#include <sound/ac97_codec.h>
     57#include <sound/info.h>
     58#include <sound/tlv.h>
     59#include <linux/io.h>
     60
     61#include "ca0106.h"
     62
     63static void ca0106_spdif_enable(struct snd_ca0106 *emu)
     64{
     65	unsigned int val;
     66
     67	if (emu->spdif_enable) {
     68		/* Digital */
     69		snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
     70		snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000);
     71		val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000;
     72		snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val);
     73		val = inl(emu->port + CA0106_GPIO) & ~0x101;
     74		outl(val, emu->port + CA0106_GPIO);
     75
     76	} else {
     77		/* Analog */
     78		snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
     79		snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000);
     80		val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000;
     81		snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val);
     82		val = inl(emu->port + CA0106_GPIO) | 0x101;
     83		outl(val, emu->port + CA0106_GPIO);
     84	}
     85}
     86
     87static void ca0106_set_capture_source(struct snd_ca0106 *emu)
     88{
     89	unsigned int val = emu->capture_source;
     90	unsigned int source, mask;
     91	source = (val << 28) | (val << 24) | (val << 20) | (val << 16);
     92	mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff;
     93	snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask);
     94}
     95
     96static void ca0106_set_i2c_capture_source(struct snd_ca0106 *emu,
     97					  unsigned int val, int force)
     98{
     99	unsigned int ngain, ogain;
    100	u32 source;
    101
    102	snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
    103	ngain = emu->i2c_capture_volume[val][0]; /* Left */
    104	ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
    105	if (force || ngain != ogain)
    106		snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ngain & 0xff);
    107	ngain = emu->i2c_capture_volume[val][1]; /* Right */
    108	ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
    109	if (force || ngain != ogain)
    110		snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ngain & 0xff);
    111	source = 1 << val;
    112	snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */
    113	emu->i2c_capture_source = val;
    114}
    115
    116static void ca0106_set_capture_mic_line_in(struct snd_ca0106 *emu)
    117{
    118	u32 tmp;
    119
    120	if (emu->capture_mic_line_in) {
    121		/* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */
    122		tmp = inl(emu->port + CA0106_GPIO) & ~0x400;
    123		tmp = tmp | 0x400;
    124		outl(tmp, emu->port + CA0106_GPIO);
    125		/* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); */
    126	} else {
    127		/* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */
    128		tmp = inl(emu->port + CA0106_GPIO) & ~0x400;
    129		outl(tmp, emu->port + CA0106_GPIO);
    130		/* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); */
    131	}
    132}
    133
    134static void ca0106_set_spdif_bits(struct snd_ca0106 *emu, int idx)
    135{
    136	snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, emu->spdif_str_bits[idx]);
    137}
    138
    139/*
    140 */
    141static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1);
    142static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1);
    143
    144#define snd_ca0106_shared_spdif_info	snd_ctl_boolean_mono_info
    145
    146static int snd_ca0106_shared_spdif_get(struct snd_kcontrol *kcontrol,
    147					struct snd_ctl_elem_value *ucontrol)
    148{
    149	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
    150
    151	ucontrol->value.integer.value[0] = emu->spdif_enable;
    152	return 0;
    153}
    154
    155static int snd_ca0106_shared_spdif_put(struct snd_kcontrol *kcontrol,
    156					struct snd_ctl_elem_value *ucontrol)
    157{
    158	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
    159	unsigned int val;
    160	int change = 0;
    161
    162	val = !!ucontrol->value.integer.value[0];
    163	change = (emu->spdif_enable != val);
    164	if (change) {
    165		emu->spdif_enable = val;
    166		ca0106_spdif_enable(emu);
    167	}
    168        return change;
    169}
    170
    171static int snd_ca0106_capture_source_info(struct snd_kcontrol *kcontrol,
    172					  struct snd_ctl_elem_info *uinfo)
    173{
    174	static const char * const texts[6] = {
    175		"IEC958 out", "i2s mixer out", "IEC958 in", "i2s in", "AC97 in", "SRC out"
    176	};
    177
    178	return snd_ctl_enum_info(uinfo, 1, 6, texts);
    179}
    180
    181static int snd_ca0106_capture_source_get(struct snd_kcontrol *kcontrol,
    182					struct snd_ctl_elem_value *ucontrol)
    183{
    184	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
    185
    186	ucontrol->value.enumerated.item[0] = emu->capture_source;
    187	return 0;
    188}
    189
    190static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol,
    191					struct snd_ctl_elem_value *ucontrol)
    192{
    193	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
    194	unsigned int val;
    195	int change = 0;
    196
    197	val = ucontrol->value.enumerated.item[0] ;
    198	if (val >= 6)
    199		return -EINVAL;
    200	change = (emu->capture_source != val);
    201	if (change) {
    202		emu->capture_source = val;
    203		ca0106_set_capture_source(emu);
    204	}
    205        return change;
    206}
    207
    208static int snd_ca0106_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
    209					  struct snd_ctl_elem_info *uinfo)
    210{
    211	static const char * const texts[4] = {
    212		"Phone", "Mic", "Line in", "Aux"
    213	};
    214
    215	return snd_ctl_enum_info(uinfo, 1, 4, texts);
    216}
    217
    218static int snd_ca0106_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
    219					struct snd_ctl_elem_value *ucontrol)
    220{
    221	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
    222
    223	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
    224	return 0;
    225}
    226
    227static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
    228					struct snd_ctl_elem_value *ucontrol)
    229{
    230	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
    231	unsigned int source_id;
    232	int change = 0;
    233	/* If the capture source has changed,
    234	 * update the capture volume from the cached value
    235	 * for the particular source.
    236	 */
    237	source_id = ucontrol->value.enumerated.item[0] ;
    238	if (source_id >= 4)
    239		return -EINVAL;
    240	change = (emu->i2c_capture_source != source_id);
    241	if (change) {
    242		ca0106_set_i2c_capture_source(emu, source_id, 0);
    243	}
    244        return change;
    245}
    246
    247static int snd_ca0106_capture_line_in_side_out_info(struct snd_kcontrol *kcontrol,
    248					       struct snd_ctl_elem_info *uinfo)
    249{
    250	static const char * const texts[2] = { "Side out", "Line in" };
    251
    252	return snd_ctl_enum_info(uinfo, 1, 2, texts);
    253}
    254
    255static int snd_ca0106_capture_mic_line_in_info(struct snd_kcontrol *kcontrol,
    256					       struct snd_ctl_elem_info *uinfo)
    257{
    258	static const char * const texts[2] = { "Line in", "Mic in" };
    259
    260	return snd_ctl_enum_info(uinfo, 1, 2, texts);
    261}
    262
    263static int snd_ca0106_capture_mic_line_in_get(struct snd_kcontrol *kcontrol,
    264					struct snd_ctl_elem_value *ucontrol)
    265{
    266	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
    267
    268	ucontrol->value.enumerated.item[0] = emu->capture_mic_line_in;
    269	return 0;
    270}
    271
    272static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol,
    273					struct snd_ctl_elem_value *ucontrol)
    274{
    275	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
    276	unsigned int val;
    277	int change = 0;
    278
    279	val = ucontrol->value.enumerated.item[0] ;
    280	if (val > 1)
    281		return -EINVAL;
    282	change = (emu->capture_mic_line_in != val);
    283	if (change) {
    284		emu->capture_mic_line_in = val;
    285		ca0106_set_capture_mic_line_in(emu);
    286	}
    287        return change;
    288}
    289
    290static const struct snd_kcontrol_new snd_ca0106_capture_mic_line_in =
    291{
    292	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
    293	.name =		"Shared Mic/Line in Capture Switch",
    294	.info =		snd_ca0106_capture_mic_line_in_info,
    295	.get =		snd_ca0106_capture_mic_line_in_get,
    296	.put =		snd_ca0106_capture_mic_line_in_put
    297};
    298
    299static const struct snd_kcontrol_new snd_ca0106_capture_line_in_side_out =
    300{
    301	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
    302	.name =		"Shared Line in/Side out Capture Switch",
    303	.info =		snd_ca0106_capture_line_in_side_out_info,
    304	.get =		snd_ca0106_capture_mic_line_in_get,
    305	.put =		snd_ca0106_capture_mic_line_in_put
    306};
    307
    308
    309static int snd_ca0106_spdif_info(struct snd_kcontrol *kcontrol,
    310				 struct snd_ctl_elem_info *uinfo)
    311{
    312	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
    313	uinfo->count = 1;
    314	return 0;
    315}
    316
    317static void decode_spdif_bits(unsigned char *status, unsigned int bits)
    318{
    319	status[0] = (bits >> 0) & 0xff;
    320	status[1] = (bits >> 8) & 0xff;
    321	status[2] = (bits >> 16) & 0xff;
    322	status[3] = (bits >> 24) & 0xff;
    323}
    324
    325static int snd_ca0106_spdif_get_default(struct snd_kcontrol *kcontrol,
    326                                 struct snd_ctl_elem_value *ucontrol)
    327{
    328	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
    329	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
    330
    331	decode_spdif_bits(ucontrol->value.iec958.status,
    332			  emu->spdif_bits[idx]);
    333        return 0;
    334}
    335
    336static int snd_ca0106_spdif_get_stream(struct snd_kcontrol *kcontrol,
    337                                 struct snd_ctl_elem_value *ucontrol)
    338{
    339	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
    340	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
    341
    342	decode_spdif_bits(ucontrol->value.iec958.status,
    343			  emu->spdif_str_bits[idx]);
    344        return 0;
    345}
    346
    347static int snd_ca0106_spdif_get_mask(struct snd_kcontrol *kcontrol,
    348				      struct snd_ctl_elem_value *ucontrol)
    349{
    350	ucontrol->value.iec958.status[0] = 0xff;
    351	ucontrol->value.iec958.status[1] = 0xff;
    352	ucontrol->value.iec958.status[2] = 0xff;
    353	ucontrol->value.iec958.status[3] = 0xff;
    354        return 0;
    355}
    356
    357static unsigned int encode_spdif_bits(unsigned char *status)
    358{
    359	return ((unsigned int)status[0] << 0) |
    360		((unsigned int)status[1] << 8) |
    361		((unsigned int)status[2] << 16) |
    362		((unsigned int)status[3] << 24);
    363}
    364
    365static int snd_ca0106_spdif_put_default(struct snd_kcontrol *kcontrol,
    366                                 struct snd_ctl_elem_value *ucontrol)
    367{
    368	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
    369	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
    370	unsigned int val;
    371
    372	val = encode_spdif_bits(ucontrol->value.iec958.status);
    373	if (val != emu->spdif_bits[idx]) {
    374		emu->spdif_bits[idx] = val;
    375		/* FIXME: this isn't safe, but needed to keep the compatibility
    376		 * with older alsa-lib config
    377		 */
    378		emu->spdif_str_bits[idx] = val;
    379		ca0106_set_spdif_bits(emu, idx);
    380		return 1;
    381	}
    382	return 0;
    383}
    384
    385static int snd_ca0106_spdif_put_stream(struct snd_kcontrol *kcontrol,
    386                                 struct snd_ctl_elem_value *ucontrol)
    387{
    388	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
    389	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
    390	unsigned int val;
    391
    392	val = encode_spdif_bits(ucontrol->value.iec958.status);
    393	if (val != emu->spdif_str_bits[idx]) {
    394		emu->spdif_str_bits[idx] = val;
    395		ca0106_set_spdif_bits(emu, idx);
    396		return 1;
    397	}
    398        return 0;
    399}
    400
    401static int snd_ca0106_volume_info(struct snd_kcontrol *kcontrol,
    402				  struct snd_ctl_elem_info *uinfo)
    403{
    404        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
    405        uinfo->count = 2;
    406        uinfo->value.integer.min = 0;
    407        uinfo->value.integer.max = 255;
    408        return 0;
    409}
    410
    411static int snd_ca0106_volume_get(struct snd_kcontrol *kcontrol,
    412				 struct snd_ctl_elem_value *ucontrol)
    413{
    414        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
    415        unsigned int value;
    416	int channel_id, reg;
    417
    418	channel_id = (kcontrol->private_value >> 8) & 0xff;
    419	reg = kcontrol->private_value & 0xff;
    420
    421        value = snd_ca0106_ptr_read(emu, reg, channel_id);
    422        ucontrol->value.integer.value[0] = 0xff - ((value >> 24) & 0xff); /* Left */
    423        ucontrol->value.integer.value[1] = 0xff - ((value >> 16) & 0xff); /* Right */
    424        return 0;
    425}
    426
    427static int snd_ca0106_volume_put(struct snd_kcontrol *kcontrol,
    428				 struct snd_ctl_elem_value *ucontrol)
    429{
    430        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
    431        unsigned int oval, nval;
    432	int channel_id, reg;
    433
    434	channel_id = (kcontrol->private_value >> 8) & 0xff;
    435	reg = kcontrol->private_value & 0xff;
    436
    437	oval = snd_ca0106_ptr_read(emu, reg, channel_id);
    438	nval = ((0xff - ucontrol->value.integer.value[0]) << 24) |
    439		((0xff - ucontrol->value.integer.value[1]) << 16);
    440        nval |= ((0xff - ucontrol->value.integer.value[0]) << 8) |
    441		((0xff - ucontrol->value.integer.value[1]) );
    442	if (oval == nval)
    443		return 0;
    444	snd_ca0106_ptr_write(emu, reg, channel_id, nval);
    445	return 1;
    446}
    447
    448static int snd_ca0106_i2c_volume_info(struct snd_kcontrol *kcontrol,
    449				  struct snd_ctl_elem_info *uinfo)
    450{
    451        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
    452        uinfo->count = 2;
    453        uinfo->value.integer.min = 0;
    454        uinfo->value.integer.max = 255;
    455        return 0;
    456}
    457
    458static int snd_ca0106_i2c_volume_get(struct snd_kcontrol *kcontrol,
    459				 struct snd_ctl_elem_value *ucontrol)
    460{
    461        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
    462	int source_id;
    463
    464	source_id = kcontrol->private_value;
    465
    466        ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
    467        ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
    468        return 0;
    469}
    470
    471static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol,
    472				 struct snd_ctl_elem_value *ucontrol)
    473{
    474        struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
    475        unsigned int ogain;
    476        unsigned int ngain;
    477	int source_id;
    478	int change = 0;
    479
    480	source_id = kcontrol->private_value;
    481	ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
    482	ngain = ucontrol->value.integer.value[0];
    483	if (ngain > 0xff)
    484		return -EINVAL;
    485	if (ogain != ngain) {
    486		if (emu->i2c_capture_source == source_id)
    487			snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) );
    488		emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0];
    489		change = 1;
    490	}
    491	ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
    492	ngain = ucontrol->value.integer.value[1];
    493	if (ngain > 0xff)
    494		return -EINVAL;
    495	if (ogain != ngain) {
    496		if (emu->i2c_capture_source == source_id)
    497			snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
    498		emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1];
    499		change = 1;
    500	}
    501
    502	return change;
    503}
    504
    505#define spi_mute_info	snd_ctl_boolean_mono_info
    506
    507static int spi_mute_get(struct snd_kcontrol *kcontrol,
    508			struct snd_ctl_elem_value *ucontrol)
    509{
    510	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
    511	unsigned int reg = kcontrol->private_value >> SPI_REG_SHIFT;
    512	unsigned int bit = kcontrol->private_value & SPI_REG_MASK;
    513
    514	ucontrol->value.integer.value[0] = !(emu->spi_dac_reg[reg] & bit);
    515	return 0;
    516}
    517
    518static int spi_mute_put(struct snd_kcontrol *kcontrol,
    519			struct snd_ctl_elem_value *ucontrol)
    520{
    521	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
    522	unsigned int reg = kcontrol->private_value >> SPI_REG_SHIFT;
    523	unsigned int bit = kcontrol->private_value & SPI_REG_MASK;
    524	int ret;
    525
    526	ret = emu->spi_dac_reg[reg] & bit;
    527	if (ucontrol->value.integer.value[0]) {
    528		if (!ret)	/* bit already cleared, do nothing */
    529			return 0;
    530		emu->spi_dac_reg[reg] &= ~bit;
    531	} else {
    532		if (ret)	/* bit already set, do nothing */
    533			return 0;
    534		emu->spi_dac_reg[reg] |= bit;
    535	}
    536
    537	ret = snd_ca0106_spi_write(emu, emu->spi_dac_reg[reg]);
    538	return ret ? -EINVAL : 1;
    539}
    540
    541#define CA_VOLUME(xname,chid,reg) \
    542{								\
    543	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
    544	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |		\
    545	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,		\
    546	.info =	 snd_ca0106_volume_info,			\
    547	.get =   snd_ca0106_volume_get,				\
    548	.put =   snd_ca0106_volume_put,				\
    549	.tlv = { .p = snd_ca0106_db_scale1 },			\
    550	.private_value = ((chid) << 8) | (reg)			\
    551}
    552
    553static const struct snd_kcontrol_new snd_ca0106_volume_ctls[] = {
    554	CA_VOLUME("Analog Front Playback Volume",
    555		  CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2),
    556        CA_VOLUME("Analog Rear Playback Volume",
    557		  CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME2),
    558	CA_VOLUME("Analog Center/LFE Playback Volume",
    559		  CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME2),
    560        CA_VOLUME("Analog Side Playback Volume",
    561		  CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME2),
    562
    563        CA_VOLUME("IEC958 Front Playback Volume",
    564		  CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME1),
    565	CA_VOLUME("IEC958 Rear Playback Volume",
    566		  CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME1),
    567	CA_VOLUME("IEC958 Center/LFE Playback Volume",
    568		  CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME1),
    569	CA_VOLUME("IEC958 Unknown Playback Volume",
    570		  CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME1),
    571
    572        CA_VOLUME("CAPTURE feedback Playback Volume",
    573		  1, CAPTURE_CONTROL),
    574
    575	{
    576		.access =	SNDRV_CTL_ELEM_ACCESS_READ,
    577		.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
    578		.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
    579		.count =	4,
    580		.info =         snd_ca0106_spdif_info,
    581		.get =          snd_ca0106_spdif_get_mask
    582	},
    583	{
    584		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
    585		.name =		"IEC958 Playback Switch",
    586		.info =		snd_ca0106_shared_spdif_info,
    587		.get =		snd_ca0106_shared_spdif_get,
    588		.put =		snd_ca0106_shared_spdif_put
    589	},
    590	{
    591		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
    592		.name =		"Digital Source Capture Enum",
    593		.info =		snd_ca0106_capture_source_info,
    594		.get =		snd_ca0106_capture_source_get,
    595		.put =		snd_ca0106_capture_source_put
    596	},
    597	{
    598		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
    599		.name =		"Analog Source Capture Enum",
    600		.info =		snd_ca0106_i2c_capture_source_info,
    601		.get =		snd_ca0106_i2c_capture_source_get,
    602		.put =		snd_ca0106_i2c_capture_source_put
    603	},
    604	{
    605		.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
    606		.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
    607		.count =	4,
    608		.info =         snd_ca0106_spdif_info,
    609		.get =          snd_ca0106_spdif_get_default,
    610		.put =          snd_ca0106_spdif_put_default
    611	},
    612	{
    613		.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
    614		.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
    615		.count =	4,
    616		.info =         snd_ca0106_spdif_info,
    617		.get =          snd_ca0106_spdif_get_stream,
    618		.put =          snd_ca0106_spdif_put_stream
    619	},
    620};
    621
    622#define I2C_VOLUME(xname,chid) \
    623{								\
    624	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
    625	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |		\
    626	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,		\
    627	.info =  snd_ca0106_i2c_volume_info,			\
    628	.get =   snd_ca0106_i2c_volume_get,			\
    629	.put =   snd_ca0106_i2c_volume_put,			\
    630	.tlv = { .p = snd_ca0106_db_scale2 },			\
    631	.private_value = chid					\
    632}
    633
    634static const struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] = {
    635        I2C_VOLUME("Phone Capture Volume", 0),
    636        I2C_VOLUME("Mic Capture Volume", 1),
    637        I2C_VOLUME("Line in Capture Volume", 2),
    638        I2C_VOLUME("Aux Capture Volume", 3),
    639};
    640
    641static const int spi_dmute_reg[] = {
    642	SPI_DMUTE0_REG,
    643	SPI_DMUTE1_REG,
    644	SPI_DMUTE2_REG,
    645	0,
    646	SPI_DMUTE4_REG,
    647};
    648static const int spi_dmute_bit[] = {
    649	SPI_DMUTE0_BIT,
    650	SPI_DMUTE1_BIT,
    651	SPI_DMUTE2_BIT,
    652	0,
    653	SPI_DMUTE4_BIT,
    654};
    655
    656static struct snd_kcontrol_new
    657snd_ca0106_volume_spi_dac_ctl(const struct snd_ca0106_details *details,
    658			      int channel_id)
    659{
    660	struct snd_kcontrol_new spi_switch = {0};
    661	int reg, bit;
    662	int dac_id;
    663
    664	spi_switch.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
    665	spi_switch.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
    666	spi_switch.info = spi_mute_info;
    667	spi_switch.get = spi_mute_get;
    668	spi_switch.put = spi_mute_put;
    669
    670	switch (channel_id) {
    671	case PCM_FRONT_CHANNEL:
    672		spi_switch.name = "Analog Front Playback Switch";
    673		dac_id = (details->spi_dac & 0xf000) >> (4 * 3);
    674		break;
    675	case PCM_REAR_CHANNEL:
    676		spi_switch.name = "Analog Rear Playback Switch";
    677		dac_id = (details->spi_dac & 0x0f00) >> (4 * 2);
    678		break;
    679	case PCM_CENTER_LFE_CHANNEL:
    680		spi_switch.name = "Analog Center/LFE Playback Switch";
    681		dac_id = (details->spi_dac & 0x00f0) >> (4 * 1);
    682		break;
    683	case PCM_UNKNOWN_CHANNEL:
    684		spi_switch.name = "Analog Side Playback Switch";
    685		dac_id = (details->spi_dac & 0x000f) >> (4 * 0);
    686		break;
    687	default:
    688		/* Unused channel */
    689		spi_switch.name = NULL;
    690		dac_id = 0;
    691	}
    692	reg = spi_dmute_reg[dac_id];
    693	bit = spi_dmute_bit[dac_id];
    694
    695	spi_switch.private_value = (reg << SPI_REG_SHIFT) | bit;
    696
    697	return spi_switch;
    698}
    699
    700static int remove_ctl(struct snd_card *card, const char *name)
    701{
    702	struct snd_ctl_elem_id id;
    703	memset(&id, 0, sizeof(id));
    704	strcpy(id.name, name);
    705	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
    706	return snd_ctl_remove_id(card, &id);
    707}
    708
    709static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name)
    710{
    711	struct snd_ctl_elem_id sid;
    712	memset(&sid, 0, sizeof(sid));
    713	/* FIXME: strcpy is bad. */
    714	strcpy(sid.name, name);
    715	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
    716	return snd_ctl_find_id(card, &sid);
    717}
    718
    719static int rename_ctl(struct snd_card *card, const char *src, const char *dst)
    720{
    721	struct snd_kcontrol *kctl = ctl_find(card, src);
    722	if (kctl) {
    723		strcpy(kctl->id.name, dst);
    724		return 0;
    725	}
    726	return -ENOENT;
    727}
    728
    729#define ADD_CTLS(emu, ctls)						\
    730	do {								\
    731		int i, _err;						\
    732		for (i = 0; i < ARRAY_SIZE(ctls); i++) {		\
    733			_err = snd_ctl_add(card, snd_ctl_new1(&ctls[i], emu)); \
    734			if (_err < 0)					\
    735				return _err;				\
    736		}							\
    737	} while (0)
    738
    739static
    740DECLARE_TLV_DB_SCALE(snd_ca0106_master_db_scale, -6375, 25, 1);
    741
    742static const char * const follower_vols[] = {
    743	"Analog Front Playback Volume",
    744        "Analog Rear Playback Volume",
    745	"Analog Center/LFE Playback Volume",
    746        "Analog Side Playback Volume",
    747        "IEC958 Front Playback Volume",
    748	"IEC958 Rear Playback Volume",
    749	"IEC958 Center/LFE Playback Volume",
    750	"IEC958 Unknown Playback Volume",
    751        "CAPTURE feedback Playback Volume",
    752	NULL
    753};
    754
    755static const char * const follower_sws[] = {
    756	"Analog Front Playback Switch",
    757	"Analog Rear Playback Switch",
    758	"Analog Center/LFE Playback Switch",
    759	"Analog Side Playback Switch",
    760	"IEC958 Playback Switch",
    761	NULL
    762};
    763
    764static void add_followers(struct snd_card *card,
    765			  struct snd_kcontrol *master, const char * const *list)
    766{
    767	for (; *list; list++) {
    768		struct snd_kcontrol *follower = ctl_find(card, *list);
    769		if (follower)
    770			snd_ctl_add_follower(master, follower);
    771	}
    772}
    773
    774int snd_ca0106_mixer(struct snd_ca0106 *emu)
    775{
    776	int err;
    777        struct snd_card *card = emu->card;
    778	const char * const *c;
    779	struct snd_kcontrol *vmaster;
    780	static const char * const ca0106_remove_ctls[] = {
    781		"Master Mono Playback Switch",
    782		"Master Mono Playback Volume",
    783		"3D Control - Switch",
    784		"3D Control Sigmatel - Depth",
    785		"PCM Playback Switch",
    786		"PCM Playback Volume",
    787		"CD Playback Switch",
    788		"CD Playback Volume",
    789		"Phone Playback Switch",
    790		"Phone Playback Volume",
    791		"Video Playback Switch",
    792		"Video Playback Volume",
    793		"Beep Playback Switch",
    794		"Beep Playback Volume",
    795		"Mono Output Select",
    796		"Capture Source",
    797		"Capture Switch",
    798		"Capture Volume",
    799		"External Amplifier",
    800		"Sigmatel 4-Speaker Stereo Playback Switch",
    801		"Surround Phase Inversion Playback Switch",
    802		NULL
    803	};
    804	static const char * const ca0106_rename_ctls[] = {
    805		"Master Playback Switch", "Capture Switch",
    806		"Master Playback Volume", "Capture Volume",
    807		"Line Playback Switch", "AC97 Line Capture Switch",
    808		"Line Playback Volume", "AC97 Line Capture Volume",
    809		"Aux Playback Switch", "AC97 Aux Capture Switch",
    810		"Aux Playback Volume", "AC97 Aux Capture Volume",
    811		"Mic Playback Switch", "AC97 Mic Capture Switch",
    812		"Mic Playback Volume", "AC97 Mic Capture Volume",
    813		"Mic Select", "AC97 Mic Select",
    814		"Mic Boost (+20dB)", "AC97 Mic Boost (+20dB)",
    815		NULL
    816	};
    817#if 1
    818	for (c = ca0106_remove_ctls; *c; c++)
    819		remove_ctl(card, *c);
    820	for (c = ca0106_rename_ctls; *c; c += 2)
    821		rename_ctl(card, c[0], c[1]);
    822#endif
    823
    824	ADD_CTLS(emu, snd_ca0106_volume_ctls);
    825	if (emu->details->i2c_adc == 1) {
    826		ADD_CTLS(emu, snd_ca0106_volume_i2c_adc_ctls);
    827		if (emu->details->gpio_type == 1)
    828			err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu));
    829		else  /* gpio_type == 2 */
    830			err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_line_in_side_out, emu));
    831		if (err < 0)
    832			return err;
    833	}
    834	if (emu->details->spi_dac) {
    835		int i;
    836		for (i = 0;; i++) {
    837			struct snd_kcontrol_new ctl;
    838			ctl = snd_ca0106_volume_spi_dac_ctl(emu->details, i);
    839			if (!ctl.name)
    840				break;
    841			err = snd_ctl_add(card, snd_ctl_new1(&ctl, emu));
    842			if (err < 0)
    843				return err;
    844		}
    845	}
    846
    847	/* Create virtual master controls */
    848	vmaster = snd_ctl_make_virtual_master("Master Playback Volume",
    849					      snd_ca0106_master_db_scale);
    850	if (!vmaster)
    851		return -ENOMEM;
    852	err = snd_ctl_add(card, vmaster);
    853	if (err < 0)
    854		return err;
    855	add_followers(card, vmaster, follower_vols);
    856
    857	if (emu->details->spi_dac) {
    858		vmaster = snd_ctl_make_virtual_master("Master Playback Switch",
    859						      NULL);
    860		if (!vmaster)
    861			return -ENOMEM;
    862		err = snd_ctl_add(card, vmaster);
    863		if (err < 0)
    864			return err;
    865		add_followers(card, vmaster, follower_sws);
    866	}
    867
    868	strcpy(card->mixername, "CA0106");
    869        return 0;
    870}
    871
    872#ifdef CONFIG_PM_SLEEP
    873struct ca0106_vol_tbl {
    874	unsigned int channel_id;
    875	unsigned int reg;
    876};
    877
    878static const struct ca0106_vol_tbl saved_volumes[NUM_SAVED_VOLUMES] = {
    879	{ CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2 },
    880	{ CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME2 },
    881	{ CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME2 },
    882	{ CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME2 },
    883	{ CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME1 },
    884	{ CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME1 },
    885	{ CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME1 },
    886	{ CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME1 },
    887	{ 1, CAPTURE_CONTROL },
    888};
    889
    890void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip)
    891{
    892	int i;
    893
    894	/* save volumes */
    895	for (i = 0; i < NUM_SAVED_VOLUMES; i++)
    896		chip->saved_vol[i] =
    897			snd_ca0106_ptr_read(chip, saved_volumes[i].reg,
    898					    saved_volumes[i].channel_id);
    899}
    900
    901void snd_ca0106_mixer_resume(struct snd_ca0106  *chip)
    902{
    903	int i;
    904
    905	for (i = 0; i < NUM_SAVED_VOLUMES; i++)
    906		snd_ca0106_ptr_write(chip, saved_volumes[i].reg,
    907				     saved_volumes[i].channel_id,
    908				     chip->saved_vol[i]);
    909
    910	ca0106_spdif_enable(chip);
    911	ca0106_set_capture_source(chip);
    912	ca0106_set_i2c_capture_source(chip, chip->i2c_capture_source, 1);
    913	for (i = 0; i < 4; i++)
    914		ca0106_set_spdif_bits(chip, i);
    915	if (chip->details->i2c_adc)
    916		ca0106_set_capture_mic_line_in(chip);
    917}
    918#endif /* CONFIG_PM_SLEEP */