xref: /openbmc/linux/sound/pci/ca0106/ca0106_mixer.c (revision 302e9c5af4fb3ea258917ee6a32e9e45f578b231)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk>
31da177e4SLinus Torvalds  *  Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit
4ed144f3cSJames Courtier-Dutton  *  Version: 0.0.17
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  *  FEATURES currently supported:
71da177e4SLinus Torvalds  *    See ca0106_main.c for features.
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *  Changelog:
101da177e4SLinus Torvalds  *    Support interrupts per period.
111da177e4SLinus Torvalds  *    Removed noise from Center/LFE channel when in Analog mode.
121da177e4SLinus Torvalds  *    Rename and remove mixer controls.
131da177e4SLinus Torvalds  *  0.0.6
141da177e4SLinus Torvalds  *    Use separate card based DMA buffer for periods table list.
151da177e4SLinus Torvalds  *  0.0.7
161da177e4SLinus Torvalds  *    Change remove and rename ctrls into lists.
171da177e4SLinus Torvalds  *  0.0.8
181da177e4SLinus Torvalds  *    Try to fix capture sources.
191da177e4SLinus Torvalds  *  0.0.9
201da177e4SLinus Torvalds  *    Fix AC3 output.
211da177e4SLinus Torvalds  *    Enable S32_LE format support.
221da177e4SLinus Torvalds  *  0.0.10
231da177e4SLinus Torvalds  *    Enable playback 48000 and 96000 rates. (Rates other that these do not work, even with "plug:front".)
241da177e4SLinus Torvalds  *  0.0.11
251da177e4SLinus Torvalds  *    Add Model name recognition.
261da177e4SLinus Torvalds  *  0.0.12
271da177e4SLinus Torvalds  *    Correct interrupt timing. interrupt at end of period, instead of in the middle of a playback period.
281da177e4SLinus Torvalds  *    Remove redundent "voice" handling.
291da177e4SLinus Torvalds  *  0.0.13
301da177e4SLinus Torvalds  *    Single trigger call for multi channels.
311da177e4SLinus Torvalds  *  0.0.14
321da177e4SLinus Torvalds  *    Set limits based on what the sound card hardware can do.
331da177e4SLinus Torvalds  *    playback periods_min=2, periods_max=8
341da177e4SLinus Torvalds  *    capture hw constraints require period_size = n * 64 bytes.
351da177e4SLinus Torvalds  *    playback hw constraints require period_size = n * 64 bytes.
361da177e4SLinus Torvalds  *  0.0.15
371da177e4SLinus Torvalds  *    Separated ca0106.c into separate functional .c files.
381da177e4SLinus Torvalds  *  0.0.16
391da177e4SLinus Torvalds  *    Modified Copyright message.
40ed144f3cSJames Courtier-Dutton  *  0.0.17
41ed144f3cSJames Courtier-Dutton  *    Implement Mic and Line in Capture.
421da177e4SLinus Torvalds  *
431da177e4SLinus Torvalds  *  This code was initally based on code from ALSA's emu10k1x.c which is:
441da177e4SLinus Torvalds  *  Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
451da177e4SLinus Torvalds  *
461da177e4SLinus Torvalds  *   This program is free software; you can redistribute it and/or modify
471da177e4SLinus Torvalds  *   it under the terms of the GNU General Public License as published by
481da177e4SLinus Torvalds  *   the Free Software Foundation; either version 2 of the License, or
491da177e4SLinus Torvalds  *   (at your option) any later version.
501da177e4SLinus Torvalds  *
511da177e4SLinus Torvalds  *   This program is distributed in the hope that it will be useful,
521da177e4SLinus Torvalds  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
531da177e4SLinus Torvalds  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
541da177e4SLinus Torvalds  *   GNU General Public License for more details.
551da177e4SLinus Torvalds  *
561da177e4SLinus Torvalds  *   You should have received a copy of the GNU General Public License
571da177e4SLinus Torvalds  *   along with this program; if not, write to the Free Software
581da177e4SLinus Torvalds  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
591da177e4SLinus Torvalds  *
601da177e4SLinus Torvalds  */
611da177e4SLinus Torvalds #include <sound/driver.h>
621da177e4SLinus Torvalds #include <linux/delay.h>
631da177e4SLinus Torvalds #include <linux/init.h>
641da177e4SLinus Torvalds #include <linux/interrupt.h>
651da177e4SLinus Torvalds #include <linux/pci.h>
661da177e4SLinus Torvalds #include <linux/slab.h>
671da177e4SLinus Torvalds #include <linux/moduleparam.h>
681da177e4SLinus Torvalds #include <sound/core.h>
691da177e4SLinus Torvalds #include <sound/initval.h>
701da177e4SLinus Torvalds #include <sound/pcm.h>
711da177e4SLinus Torvalds #include <sound/ac97_codec.h>
721da177e4SLinus Torvalds #include <sound/info.h>
7342750b04SJaroslav Kysela #include <sound/tlv.h>
741da177e4SLinus Torvalds 
751da177e4SLinus Torvalds #include "ca0106.h"
761da177e4SLinus Torvalds 
7742750b04SJaroslav Kysela static DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale, -5150, 75, 1);
7842750b04SJaroslav Kysela 
79e4a3d145STakashi Iwai static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol,
80e4a3d145STakashi Iwai 					struct snd_ctl_elem_info *uinfo)
811da177e4SLinus Torvalds {
821da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
831da177e4SLinus Torvalds 	uinfo->count = 1;
841da177e4SLinus Torvalds 	uinfo->value.integer.min = 0;
851da177e4SLinus Torvalds 	uinfo->value.integer.max = 1;
861da177e4SLinus Torvalds 	return 0;
871da177e4SLinus Torvalds }
881da177e4SLinus Torvalds 
89e4a3d145STakashi Iwai static int snd_ca0106_shared_spdif_get(struct snd_kcontrol *kcontrol,
90e4a3d145STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
911da177e4SLinus Torvalds {
92e4a3d145STakashi Iwai 	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds 	ucontrol->value.enumerated.item[0] = emu->spdif_enable;
951da177e4SLinus Torvalds 	return 0;
961da177e4SLinus Torvalds }
971da177e4SLinus Torvalds 
98e4a3d145STakashi Iwai static int snd_ca0106_shared_spdif_put(struct snd_kcontrol *kcontrol,
99e4a3d145STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
1001da177e4SLinus Torvalds {
101e4a3d145STakashi Iwai 	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
1021da177e4SLinus Torvalds 	unsigned int val;
1031da177e4SLinus Torvalds 	int change = 0;
1041da177e4SLinus Torvalds 	u32 mask;
1051da177e4SLinus Torvalds 
1061da177e4SLinus Torvalds 	val = ucontrol->value.enumerated.item[0] ;
1071da177e4SLinus Torvalds 	change = (emu->spdif_enable != val);
1081da177e4SLinus Torvalds 	if (change) {
1091da177e4SLinus Torvalds 		emu->spdif_enable = val;
1101da177e4SLinus Torvalds 		if (val == 1) {
1111da177e4SLinus Torvalds 			/* Digital */
1121da177e4SLinus Torvalds 			snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
1131da177e4SLinus Torvalds 			snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000);
1141da177e4SLinus Torvalds 			snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0,
1151da177e4SLinus Torvalds 				snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000);
1161da177e4SLinus Torvalds 			mask = inl(emu->port + GPIO) & ~0x101;
1171da177e4SLinus Torvalds 			outl(mask, emu->port + GPIO);
1181da177e4SLinus Torvalds 
1191da177e4SLinus Torvalds 		} else {
1201da177e4SLinus Torvalds 			/* Analog */
1211da177e4SLinus Torvalds 			snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
1221f82941eSJames Courtier-Dutton 			snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000);
1231da177e4SLinus Torvalds 			snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0,
1241da177e4SLinus Torvalds 				snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000);
1251da177e4SLinus Torvalds 			mask = inl(emu->port + GPIO) | 0x101;
1261da177e4SLinus Torvalds 			outl(mask, emu->port + GPIO);
1271da177e4SLinus Torvalds 		}
1281da177e4SLinus Torvalds 	}
1291da177e4SLinus Torvalds         return change;
1301da177e4SLinus Torvalds }
1311da177e4SLinus Torvalds 
132e4a3d145STakashi Iwai static int snd_ca0106_capture_source_info(struct snd_kcontrol *kcontrol,
133e4a3d145STakashi Iwai 					  struct snd_ctl_elem_info *uinfo)
1341da177e4SLinus Torvalds {
13595a98265STakashi Iwai 	static char *texts[6] = {
13639596dc8SJames Courtier-Dutton 		"IEC958 out", "i2s mixer out", "IEC958 in", "i2s in", "AC97 in", "SRC out"
13795a98265STakashi Iwai 	};
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1401da177e4SLinus Torvalds 	uinfo->count = 1;
1411da177e4SLinus Torvalds 	uinfo->value.enumerated.items = 6;
1421da177e4SLinus Torvalds 	if (uinfo->value.enumerated.item > 5)
1431da177e4SLinus Torvalds                 uinfo->value.enumerated.item = 5;
1441da177e4SLinus Torvalds 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1451da177e4SLinus Torvalds 	return 0;
1461da177e4SLinus Torvalds }
1471da177e4SLinus Torvalds 
148e4a3d145STakashi Iwai static int snd_ca0106_capture_source_get(struct snd_kcontrol *kcontrol,
149e4a3d145STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
1501da177e4SLinus Torvalds {
151e4a3d145STakashi Iwai 	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
1521da177e4SLinus Torvalds 
1531da177e4SLinus Torvalds 	ucontrol->value.enumerated.item[0] = emu->capture_source;
1541da177e4SLinus Torvalds 	return 0;
1551da177e4SLinus Torvalds }
1561da177e4SLinus Torvalds 
157e4a3d145STakashi Iwai static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol,
158e4a3d145STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
1591da177e4SLinus Torvalds {
160e4a3d145STakashi Iwai 	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
1611da177e4SLinus Torvalds 	unsigned int val;
1621da177e4SLinus Torvalds 	int change = 0;
1631da177e4SLinus Torvalds 	u32 mask;
1641da177e4SLinus Torvalds 	u32 source;
1651da177e4SLinus Torvalds 
1661da177e4SLinus Torvalds 	val = ucontrol->value.enumerated.item[0] ;
1671da177e4SLinus Torvalds 	change = (emu->capture_source != val);
1681da177e4SLinus Torvalds 	if (change) {
1691da177e4SLinus Torvalds 		emu->capture_source = val;
1701da177e4SLinus Torvalds 		source = (val << 28) | (val << 24) | (val << 20) | (val << 16);
1711da177e4SLinus Torvalds 		mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff;
1721da177e4SLinus Torvalds 		snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask);
1731da177e4SLinus Torvalds 	}
1741da177e4SLinus Torvalds         return change;
1751da177e4SLinus Torvalds }
1761da177e4SLinus Torvalds 
1776129daaaSJames Courtier-Dutton static int snd_ca0106_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
1786129daaaSJames Courtier-Dutton 					  struct snd_ctl_elem_info *uinfo)
1796129daaaSJames Courtier-Dutton {
1806129daaaSJames Courtier-Dutton 	static char *texts[6] = {
1816129daaaSJames Courtier-Dutton 		"Phone", "Mic", "Line in", "Aux"
1826129daaaSJames Courtier-Dutton 	};
1836129daaaSJames Courtier-Dutton 
1846129daaaSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1856129daaaSJames Courtier-Dutton 	uinfo->count = 1;
1866129daaaSJames Courtier-Dutton 	uinfo->value.enumerated.items = 4;
1876129daaaSJames Courtier-Dutton 	if (uinfo->value.enumerated.item > 3)
1886129daaaSJames Courtier-Dutton                 uinfo->value.enumerated.item = 3;
1896129daaaSJames Courtier-Dutton 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1906129daaaSJames Courtier-Dutton 	return 0;
1916129daaaSJames Courtier-Dutton }
1926129daaaSJames Courtier-Dutton 
1936129daaaSJames Courtier-Dutton static int snd_ca0106_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
1946129daaaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
1956129daaaSJames Courtier-Dutton {
1966129daaaSJames Courtier-Dutton 	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
1976129daaaSJames Courtier-Dutton 
1986129daaaSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
1996129daaaSJames Courtier-Dutton 	return 0;
2006129daaaSJames Courtier-Dutton }
2016129daaaSJames Courtier-Dutton 
2026129daaaSJames Courtier-Dutton static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
2036129daaaSJames Courtier-Dutton 					struct snd_ctl_elem_value *ucontrol)
2046129daaaSJames Courtier-Dutton {
2056129daaaSJames Courtier-Dutton 	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
2066129daaaSJames Courtier-Dutton 	unsigned int source_id;
2076129daaaSJames Courtier-Dutton 	unsigned int ngain, ogain;
2086129daaaSJames Courtier-Dutton 	int change = 0;
2096129daaaSJames Courtier-Dutton 	u32 source;
2106129daaaSJames Courtier-Dutton 	/* If the capture source has changed,
2116129daaaSJames Courtier-Dutton 	 * update the capture volume from the cached value
2126129daaaSJames Courtier-Dutton 	 * for the particular source.
2136129daaaSJames Courtier-Dutton 	 */
2146129daaaSJames Courtier-Dutton 	source_id = ucontrol->value.enumerated.item[0] ;
2156129daaaSJames Courtier-Dutton 	change = (emu->i2c_capture_source != source_id);
2166129daaaSJames Courtier-Dutton 	if (change) {
2176129daaaSJames Courtier-Dutton 		snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
2186129daaaSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
2196129daaaSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
2206129daaaSJames Courtier-Dutton 		if (ngain != ogain)
2216129daaaSJames Courtier-Dutton 			snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
2226129daaaSJames Courtier-Dutton 		ngain = emu->i2c_capture_volume[source_id][1]; /* Left */
2236129daaaSJames Courtier-Dutton 		ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Left */
2246129daaaSJames Courtier-Dutton 		if (ngain != ogain)
2256129daaaSJames Courtier-Dutton 			snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
2266129daaaSJames Courtier-Dutton 		source = 1 << source_id;
2276129daaaSJames Courtier-Dutton 		snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */
2286129daaaSJames Courtier-Dutton 		emu->i2c_capture_source = source_id;
2296129daaaSJames Courtier-Dutton 	}
2306129daaaSJames Courtier-Dutton         return change;
2316129daaaSJames Courtier-Dutton }
2326129daaaSJames Courtier-Dutton 
233be0b7b01SJames Courtier-Dutton static int snd_ca0106_capture_line_in_side_out_info(struct snd_kcontrol *kcontrol,
234be0b7b01SJames Courtier-Dutton 					       struct snd_ctl_elem_info *uinfo)
235be0b7b01SJames Courtier-Dutton {
236be0b7b01SJames Courtier-Dutton 	static char *texts[2] = { "Side out", "Line in" };
237be0b7b01SJames Courtier-Dutton 
238be0b7b01SJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
239be0b7b01SJames Courtier-Dutton 	uinfo->count = 1;
240be0b7b01SJames Courtier-Dutton 	uinfo->value.enumerated.items = 2;
241be0b7b01SJames Courtier-Dutton 	if (uinfo->value.enumerated.item > 1)
242be0b7b01SJames Courtier-Dutton                 uinfo->value.enumerated.item = 1;
243be0b7b01SJames Courtier-Dutton 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
244be0b7b01SJames Courtier-Dutton 	return 0;
245be0b7b01SJames Courtier-Dutton }
246be0b7b01SJames Courtier-Dutton 
247e4a3d145STakashi Iwai static int snd_ca0106_capture_mic_line_in_info(struct snd_kcontrol *kcontrol,
248e4a3d145STakashi Iwai 					       struct snd_ctl_elem_info *uinfo)
249ed144f3cSJames Courtier-Dutton {
250ed144f3cSJames Courtier-Dutton 	static char *texts[2] = { "Line in", "Mic in" };
251ed144f3cSJames Courtier-Dutton 
252ed144f3cSJames Courtier-Dutton 	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
253ed144f3cSJames Courtier-Dutton 	uinfo->count = 1;
254ed144f3cSJames Courtier-Dutton 	uinfo->value.enumerated.items = 2;
255ed144f3cSJames Courtier-Dutton 	if (uinfo->value.enumerated.item > 1)
256ed144f3cSJames Courtier-Dutton                 uinfo->value.enumerated.item = 1;
257ed144f3cSJames Courtier-Dutton 	strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
258ed144f3cSJames Courtier-Dutton 	return 0;
259ed144f3cSJames Courtier-Dutton }
260ed144f3cSJames Courtier-Dutton 
261e4a3d145STakashi Iwai static int snd_ca0106_capture_mic_line_in_get(struct snd_kcontrol *kcontrol,
262e4a3d145STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
263ed144f3cSJames Courtier-Dutton {
264e4a3d145STakashi Iwai 	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
265ed144f3cSJames Courtier-Dutton 
266ed144f3cSJames Courtier-Dutton 	ucontrol->value.enumerated.item[0] = emu->capture_mic_line_in;
267ed144f3cSJames Courtier-Dutton 	return 0;
268ed144f3cSJames Courtier-Dutton }
269ed144f3cSJames Courtier-Dutton 
270e4a3d145STakashi Iwai static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol,
271e4a3d145STakashi Iwai 					struct snd_ctl_elem_value *ucontrol)
272ed144f3cSJames Courtier-Dutton {
273e4a3d145STakashi Iwai 	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
274ed144f3cSJames Courtier-Dutton 	unsigned int val;
275ed144f3cSJames Courtier-Dutton 	int change = 0;
276ed144f3cSJames Courtier-Dutton 	u32 tmp;
277ed144f3cSJames Courtier-Dutton 
278ed144f3cSJames Courtier-Dutton 	val = ucontrol->value.enumerated.item[0] ;
279ed144f3cSJames Courtier-Dutton 	change = (emu->capture_mic_line_in != val);
280ed144f3cSJames Courtier-Dutton 	if (change) {
281ed144f3cSJames Courtier-Dutton 		emu->capture_mic_line_in = val;
282ed144f3cSJames Courtier-Dutton 		if (val) {
2836129daaaSJames Courtier-Dutton 			//snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
284ed144f3cSJames Courtier-Dutton 			tmp = inl(emu->port+GPIO) & ~0x400;
285ed144f3cSJames Courtier-Dutton 			tmp = tmp | 0x400;
286ed144f3cSJames Courtier-Dutton 			outl(tmp, emu->port+GPIO);
2876129daaaSJames Courtier-Dutton 			//snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC);
288ed144f3cSJames Courtier-Dutton 		} else {
2896129daaaSJames Courtier-Dutton 			//snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
290ed144f3cSJames Courtier-Dutton 			tmp = inl(emu->port+GPIO) & ~0x400;
291ed144f3cSJames Courtier-Dutton 			outl(tmp, emu->port+GPIO);
2926129daaaSJames Courtier-Dutton 			//snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN);
293ed144f3cSJames Courtier-Dutton 		}
294ed144f3cSJames Courtier-Dutton 	}
295ed144f3cSJames Courtier-Dutton         return change;
296ed144f3cSJames Courtier-Dutton }
297ed144f3cSJames Courtier-Dutton 
298e4a3d145STakashi Iwai static struct snd_kcontrol_new snd_ca0106_capture_mic_line_in __devinitdata =
299ed144f3cSJames Courtier-Dutton {
300ed144f3cSJames Courtier-Dutton 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
3016129daaaSJames Courtier-Dutton 	.name =		"Shared Mic/Line in Capture Switch",
302ed144f3cSJames Courtier-Dutton 	.info =		snd_ca0106_capture_mic_line_in_info,
303ed144f3cSJames Courtier-Dutton 	.get =		snd_ca0106_capture_mic_line_in_get,
304ed144f3cSJames Courtier-Dutton 	.put =		snd_ca0106_capture_mic_line_in_put
305ed144f3cSJames Courtier-Dutton };
306ed144f3cSJames Courtier-Dutton 
307be0b7b01SJames Courtier-Dutton static struct snd_kcontrol_new snd_ca0106_capture_line_in_side_out __devinitdata =
308be0b7b01SJames Courtier-Dutton {
309be0b7b01SJames Courtier-Dutton 	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
310be0b7b01SJames Courtier-Dutton 	.name =		"Shared Line in/Side out Capture Switch",
311be0b7b01SJames Courtier-Dutton 	.info =		snd_ca0106_capture_line_in_side_out_info,
312be0b7b01SJames Courtier-Dutton 	.get =		snd_ca0106_capture_mic_line_in_get,
313be0b7b01SJames Courtier-Dutton 	.put =		snd_ca0106_capture_mic_line_in_put
314be0b7b01SJames Courtier-Dutton };
315be0b7b01SJames Courtier-Dutton 
316be0b7b01SJames Courtier-Dutton 
317e4a3d145STakashi Iwai static int snd_ca0106_spdif_info(struct snd_kcontrol *kcontrol,
318e4a3d145STakashi Iwai 				 struct snd_ctl_elem_info *uinfo)
3191da177e4SLinus Torvalds {
3201da177e4SLinus Torvalds 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
3211da177e4SLinus Torvalds 	uinfo->count = 1;
3221da177e4SLinus Torvalds 	return 0;
3231da177e4SLinus Torvalds }
3241da177e4SLinus Torvalds 
325e4a3d145STakashi Iwai static int snd_ca0106_spdif_get(struct snd_kcontrol *kcontrol,
326e4a3d145STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
3271da177e4SLinus Torvalds {
328e4a3d145STakashi Iwai 	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
3291da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
3301da177e4SLinus Torvalds 
3311da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff;
3321da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff;
3331da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff;
3341da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff;
3351da177e4SLinus Torvalds         return 0;
3361da177e4SLinus Torvalds }
3371da177e4SLinus Torvalds 
338e4a3d145STakashi Iwai static int snd_ca0106_spdif_get_mask(struct snd_kcontrol *kcontrol,
339e4a3d145STakashi Iwai 				      struct snd_ctl_elem_value *ucontrol)
3401da177e4SLinus Torvalds {
3411da177e4SLinus Torvalds 	ucontrol->value.iec958.status[0] = 0xff;
3421da177e4SLinus Torvalds 	ucontrol->value.iec958.status[1] = 0xff;
3431da177e4SLinus Torvalds 	ucontrol->value.iec958.status[2] = 0xff;
3441da177e4SLinus Torvalds 	ucontrol->value.iec958.status[3] = 0xff;
3451da177e4SLinus Torvalds         return 0;
3461da177e4SLinus Torvalds }
3471da177e4SLinus Torvalds 
348e4a3d145STakashi Iwai static int snd_ca0106_spdif_put(struct snd_kcontrol *kcontrol,
349e4a3d145STakashi Iwai                                  struct snd_ctl_elem_value *ucontrol)
3501da177e4SLinus Torvalds {
351e4a3d145STakashi Iwai 	struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
3521da177e4SLinus Torvalds 	unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
3531da177e4SLinus Torvalds 	int change;
3541da177e4SLinus Torvalds 	unsigned int val;
3551da177e4SLinus Torvalds 
3561da177e4SLinus Torvalds 	val = (ucontrol->value.iec958.status[0] << 0) |
3571da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[1] << 8) |
3581da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[2] << 16) |
3591da177e4SLinus Torvalds 	      (ucontrol->value.iec958.status[3] << 24);
3601da177e4SLinus Torvalds 	change = val != emu->spdif_bits[idx];
3611da177e4SLinus Torvalds 	if (change) {
3621da177e4SLinus Torvalds 		snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, val);
3631da177e4SLinus Torvalds 		emu->spdif_bits[idx] = val;
3641da177e4SLinus Torvalds 	}
3651da177e4SLinus Torvalds         return change;
3661da177e4SLinus Torvalds }
3671da177e4SLinus Torvalds 
368e4a3d145STakashi Iwai static int snd_ca0106_volume_info(struct snd_kcontrol *kcontrol,
369e4a3d145STakashi Iwai 				  struct snd_ctl_elem_info *uinfo)
3701da177e4SLinus Torvalds {
3711da177e4SLinus Torvalds         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
3721da177e4SLinus Torvalds         uinfo->count = 2;
3731da177e4SLinus Torvalds         uinfo->value.integer.min = 0;
3741da177e4SLinus Torvalds         uinfo->value.integer.max = 255;
3751da177e4SLinus Torvalds         return 0;
3761da177e4SLinus Torvalds }
3771da177e4SLinus Torvalds 
378e4a3d145STakashi Iwai static int snd_ca0106_volume_get(struct snd_kcontrol *kcontrol,
379e4a3d145STakashi Iwai 				 struct snd_ctl_elem_value *ucontrol)
3801da177e4SLinus Torvalds {
381e4a3d145STakashi Iwai         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
3821da177e4SLinus Torvalds         unsigned int value;
38395a98265STakashi Iwai 	int channel_id, reg;
38495a98265STakashi Iwai 
38595a98265STakashi Iwai 	channel_id = (kcontrol->private_value >> 8) & 0xff;
38695a98265STakashi Iwai 	reg = kcontrol->private_value & 0xff;
3871da177e4SLinus Torvalds 
3881da177e4SLinus Torvalds         value = snd_ca0106_ptr_read(emu, reg, channel_id);
3891da177e4SLinus Torvalds         ucontrol->value.integer.value[0] = 0xff - ((value >> 24) & 0xff); /* Left */
3901da177e4SLinus Torvalds         ucontrol->value.integer.value[1] = 0xff - ((value >> 16) & 0xff); /* Right */
3911da177e4SLinus Torvalds         return 0;
3921da177e4SLinus Torvalds }
3931da177e4SLinus Torvalds 
394e4a3d145STakashi Iwai static int snd_ca0106_volume_put(struct snd_kcontrol *kcontrol,
395e4a3d145STakashi Iwai 				 struct snd_ctl_elem_value *ucontrol)
3961da177e4SLinus Torvalds {
397e4a3d145STakashi Iwai         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
39895a98265STakashi Iwai         unsigned int oval, nval;
39995a98265STakashi Iwai 	int channel_id, reg;
40095a98265STakashi Iwai 
40195a98265STakashi Iwai 	channel_id = (kcontrol->private_value >> 8) & 0xff;
40295a98265STakashi Iwai 	reg = kcontrol->private_value & 0xff;
40395a98265STakashi Iwai 
40495a98265STakashi Iwai 	oval = snd_ca0106_ptr_read(emu, reg, channel_id);
40595a98265STakashi Iwai 	nval = ((0xff - ucontrol->value.integer.value[0]) << 24) |
40695a98265STakashi Iwai 		((0xff - ucontrol->value.integer.value[1]) << 16);
40795a98265STakashi Iwai         nval |= ((0xff - ucontrol->value.integer.value[0]) << 8) |
40895a98265STakashi Iwai 		((0xff - ucontrol->value.integer.value[1]) );
40995a98265STakashi Iwai 	if (oval == nval)
41095a98265STakashi Iwai 		return 0;
41195a98265STakashi Iwai 	snd_ca0106_ptr_write(emu, reg, channel_id, nval);
4121da177e4SLinus Torvalds 	return 1;
4131da177e4SLinus Torvalds }
41495a98265STakashi Iwai 
4156129daaaSJames Courtier-Dutton static int snd_ca0106_i2c_volume_info(struct snd_kcontrol *kcontrol,
4166129daaaSJames Courtier-Dutton 				  struct snd_ctl_elem_info *uinfo)
4176129daaaSJames Courtier-Dutton {
4186129daaaSJames Courtier-Dutton         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
4196129daaaSJames Courtier-Dutton         uinfo->count = 2;
4206129daaaSJames Courtier-Dutton         uinfo->value.integer.min = 0;
4216129daaaSJames Courtier-Dutton         uinfo->value.integer.max = 255;
4226129daaaSJames Courtier-Dutton         return 0;
4236129daaaSJames Courtier-Dutton }
4246129daaaSJames Courtier-Dutton 
4256129daaaSJames Courtier-Dutton static int snd_ca0106_i2c_volume_get(struct snd_kcontrol *kcontrol,
4266129daaaSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
4276129daaaSJames Courtier-Dutton {
4286129daaaSJames Courtier-Dutton         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
4296129daaaSJames Courtier-Dutton 	int source_id;
4306129daaaSJames Courtier-Dutton 
4316129daaaSJames Courtier-Dutton 	source_id = kcontrol->private_value;
4326129daaaSJames Courtier-Dutton 
4336129daaaSJames Courtier-Dutton         ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
4346129daaaSJames Courtier-Dutton         ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
4356129daaaSJames Courtier-Dutton         return 0;
4366129daaaSJames Courtier-Dutton }
4376129daaaSJames Courtier-Dutton 
4386129daaaSJames Courtier-Dutton static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol,
4396129daaaSJames Courtier-Dutton 				 struct snd_ctl_elem_value *ucontrol)
4406129daaaSJames Courtier-Dutton {
4416129daaaSJames Courtier-Dutton         struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
4426129daaaSJames Courtier-Dutton         unsigned int ogain;
4436129daaaSJames Courtier-Dutton         unsigned int ngain;
4446129daaaSJames Courtier-Dutton 	int source_id;
4456129daaaSJames Courtier-Dutton 	int change = 0;
4466129daaaSJames Courtier-Dutton 
4476129daaaSJames Courtier-Dutton 	source_id = kcontrol->private_value;
4486129daaaSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
4496129daaaSJames Courtier-Dutton 	ngain = ucontrol->value.integer.value[0];
4506129daaaSJames Courtier-Dutton 	if (ngain > 0xff)
4516129daaaSJames Courtier-Dutton 		return 0;
4526129daaaSJames Courtier-Dutton 	if (ogain != ngain) {
4536129daaaSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
4546129daaaSJames Courtier-Dutton 			snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) );
4556129daaaSJames Courtier-Dutton 		emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0];
4566129daaaSJames Courtier-Dutton 		change = 1;
4576129daaaSJames Courtier-Dutton 	}
4586129daaaSJames Courtier-Dutton 	ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
4596129daaaSJames Courtier-Dutton 	ngain = ucontrol->value.integer.value[1];
4606129daaaSJames Courtier-Dutton 	if (ngain > 0xff)
4616129daaaSJames Courtier-Dutton 		return 0;
4626129daaaSJames Courtier-Dutton 	if (ogain != ngain) {
4636129daaaSJames Courtier-Dutton 		if (emu->i2c_capture_source == source_id)
4646129daaaSJames Courtier-Dutton 			snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
4656129daaaSJames Courtier-Dutton 		emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1];
4666129daaaSJames Courtier-Dutton 		change = 1;
4676129daaaSJames Courtier-Dutton 	}
4686129daaaSJames Courtier-Dutton 
4696129daaaSJames Courtier-Dutton 	return change;
4706129daaaSJames Courtier-Dutton }
4716129daaaSJames Courtier-Dutton 
47295a98265STakashi Iwai #define CA_VOLUME(xname,chid,reg) \
47395a98265STakashi Iwai {								\
47495a98265STakashi Iwai 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
475*302e9c5aSJaroslav Kysela 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |		\
476*302e9c5aSJaroslav Kysela 	          SNDRV_CTL_ELEM_ACCESS_TLV_READ,		\
47795a98265STakashi Iwai 	.info =	 snd_ca0106_volume_info,			\
47895a98265STakashi Iwai 	.get =   snd_ca0106_volume_get,				\
47995a98265STakashi Iwai 	.put =   snd_ca0106_volume_put,				\
480*302e9c5aSJaroslav Kysela 	.tlv.p = snd_ca0106_db_scale,				\
48195a98265STakashi Iwai 	.private_value = ((chid) << 8) | (reg)			\
4821da177e4SLinus Torvalds }
4831da177e4SLinus Torvalds 
4846129daaaSJames Courtier-Dutton #define I2C_VOLUME(xname,chid) \
4856129daaaSJames Courtier-Dutton {								\
4866129daaaSJames Courtier-Dutton 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,	\
4876129daaaSJames Courtier-Dutton 	.info =  snd_ca0106_i2c_volume_info,			\
4886129daaaSJames Courtier-Dutton 	.get =   snd_ca0106_i2c_volume_get,			\
4896129daaaSJames Courtier-Dutton 	.put =   snd_ca0106_i2c_volume_put,			\
4906129daaaSJames Courtier-Dutton 	.private_value = chid					\
4916129daaaSJames Courtier-Dutton }
4926129daaaSJames Courtier-Dutton 
4931da177e4SLinus Torvalds 
494e4a3d145STakashi Iwai static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
49595a98265STakashi Iwai 	CA_VOLUME("Analog Front Playback Volume",
49695a98265STakashi Iwai 		  CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2),
49795a98265STakashi Iwai         CA_VOLUME("Analog Rear Playback Volume",
49895a98265STakashi Iwai 		  CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME2),
49995a98265STakashi Iwai 	CA_VOLUME("Analog Center/LFE Playback Volume",
50095a98265STakashi Iwai 		  CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME2),
50195a98265STakashi Iwai         CA_VOLUME("Analog Side Playback Volume",
50295a98265STakashi Iwai 		  CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME2),
50395a98265STakashi Iwai 
50439596dc8SJames Courtier-Dutton         CA_VOLUME("IEC958 Front Playback Volume",
50595a98265STakashi Iwai 		  CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME1),
50639596dc8SJames Courtier-Dutton 	CA_VOLUME("IEC958 Rear Playback Volume",
50795a98265STakashi Iwai 		  CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME1),
50839596dc8SJames Courtier-Dutton 	CA_VOLUME("IEC958 Center/LFE Playback Volume",
50995a98265STakashi Iwai 		  CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME1),
51039596dc8SJames Courtier-Dutton 	CA_VOLUME("IEC958 Unknown Playback Volume",
51195a98265STakashi Iwai 		  CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME1),
51295a98265STakashi Iwai 
51395a98265STakashi Iwai         CA_VOLUME("CAPTURE feedback Playback Volume",
51495a98265STakashi Iwai 		  1, CAPTURE_CONTROL),
51595a98265STakashi Iwai 
5166129daaaSJames Courtier-Dutton         I2C_VOLUME("Phone Capture Volume", 0),
5176129daaaSJames Courtier-Dutton         I2C_VOLUME("Mic Capture Volume", 1),
5186129daaaSJames Courtier-Dutton         I2C_VOLUME("Line in Capture Volume", 2),
5196129daaaSJames Courtier-Dutton         I2C_VOLUME("Aux Capture Volume", 3),
5206129daaaSJames Courtier-Dutton 
52195a98265STakashi Iwai 	{
52295a98265STakashi Iwai 		.access =	SNDRV_CTL_ELEM_ACCESS_READ,
52395a98265STakashi Iwai 		.iface =        SNDRV_CTL_ELEM_IFACE_PCM,
52495a98265STakashi Iwai 		.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
52595a98265STakashi Iwai 		.count =	4,
52695a98265STakashi Iwai 		.info =         snd_ca0106_spdif_info,
52795a98265STakashi Iwai 		.get =          snd_ca0106_spdif_get_mask
52895a98265STakashi Iwai 	},
5291da177e4SLinus Torvalds 	{
5301da177e4SLinus Torvalds 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
53139596dc8SJames Courtier-Dutton 		.name =		"IEC958 Playback Switch",
53295a98265STakashi Iwai 		.info =		snd_ca0106_shared_spdif_info,
53395a98265STakashi Iwai 		.get =		snd_ca0106_shared_spdif_get,
53495a98265STakashi Iwai 		.put =		snd_ca0106_shared_spdif_put
53595a98265STakashi Iwai 	},
5361da177e4SLinus Torvalds 	{
5371da177e4SLinus Torvalds 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
5386129daaaSJames Courtier-Dutton 		.name =		"Digital Capture Source",
53995a98265STakashi Iwai 		.info =		snd_ca0106_capture_source_info,
54095a98265STakashi Iwai 		.get =		snd_ca0106_capture_source_get,
54195a98265STakashi Iwai 		.put =		snd_ca0106_capture_source_put
54295a98265STakashi Iwai 	},
5431da177e4SLinus Torvalds 	{
5446129daaaSJames Courtier-Dutton 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
5456129daaaSJames Courtier-Dutton 		.name =		"Capture Source",
5466129daaaSJames Courtier-Dutton 		.info =		snd_ca0106_i2c_capture_source_info,
5476129daaaSJames Courtier-Dutton 		.get =		snd_ca0106_i2c_capture_source_get,
5486129daaaSJames Courtier-Dutton 		.put =		snd_ca0106_i2c_capture_source_put
5496129daaaSJames Courtier-Dutton 	},
5506129daaaSJames Courtier-Dutton 	{
55195a98265STakashi Iwai 		.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
55295a98265STakashi Iwai 		.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
55395a98265STakashi Iwai 		.count =	4,
55495a98265STakashi Iwai 		.info =         snd_ca0106_spdif_info,
55595a98265STakashi Iwai 		.get =          snd_ca0106_spdif_get,
55695a98265STakashi Iwai 		.put =          snd_ca0106_spdif_put
55795a98265STakashi Iwai 	},
5581da177e4SLinus Torvalds };
5591da177e4SLinus Torvalds 
560e4a3d145STakashi Iwai static int __devinit remove_ctl(struct snd_card *card, const char *name)
5611da177e4SLinus Torvalds {
562e4a3d145STakashi Iwai 	struct snd_ctl_elem_id id;
5631da177e4SLinus Torvalds 	memset(&id, 0, sizeof(id));
5641da177e4SLinus Torvalds 	strcpy(id.name, name);
5651da177e4SLinus Torvalds 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
5661da177e4SLinus Torvalds 	return snd_ctl_remove_id(card, &id);
5671da177e4SLinus Torvalds }
5681da177e4SLinus Torvalds 
569e4a3d145STakashi Iwai static struct snd_kcontrol __devinit *ctl_find(struct snd_card *card, const char *name)
5701da177e4SLinus Torvalds {
571e4a3d145STakashi Iwai 	struct snd_ctl_elem_id sid;
5721da177e4SLinus Torvalds 	memset(&sid, 0, sizeof(sid));
5731da177e4SLinus Torvalds 	/* FIXME: strcpy is bad. */
5741da177e4SLinus Torvalds 	strcpy(sid.name, name);
5751da177e4SLinus Torvalds 	sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
5761da177e4SLinus Torvalds 	return snd_ctl_find_id(card, &sid);
5771da177e4SLinus Torvalds }
5781da177e4SLinus Torvalds 
579e4a3d145STakashi Iwai static int __devinit rename_ctl(struct snd_card *card, const char *src, const char *dst)
5801da177e4SLinus Torvalds {
581e4a3d145STakashi Iwai 	struct snd_kcontrol *kctl = ctl_find(card, src);
5821da177e4SLinus Torvalds 	if (kctl) {
5831da177e4SLinus Torvalds 		strcpy(kctl->id.name, dst);
5841da177e4SLinus Torvalds 		return 0;
5851da177e4SLinus Torvalds 	}
5861da177e4SLinus Torvalds 	return -ENOENT;
5871da177e4SLinus Torvalds }
5881da177e4SLinus Torvalds 
589e4a3d145STakashi Iwai int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
5901da177e4SLinus Torvalds {
59195a98265STakashi Iwai 	int i, err;
592e4a3d145STakashi Iwai         struct snd_card *card = emu->card;
5931da177e4SLinus Torvalds 	char **c;
5941da177e4SLinus Torvalds 	static char *ca0106_remove_ctls[] = {
5951da177e4SLinus Torvalds 		"Master Mono Playback Switch",
5961da177e4SLinus Torvalds 		"Master Mono Playback Volume",
5971da177e4SLinus Torvalds 		"3D Control - Switch",
5981da177e4SLinus Torvalds 		"3D Control Sigmatel - Depth",
5991da177e4SLinus Torvalds 		"PCM Playback Switch",
6001da177e4SLinus Torvalds 		"PCM Playback Volume",
6011da177e4SLinus Torvalds 		"CD Playback Switch",
6021da177e4SLinus Torvalds 		"CD Playback Volume",
6031da177e4SLinus Torvalds 		"Phone Playback Switch",
6041da177e4SLinus Torvalds 		"Phone Playback Volume",
6051da177e4SLinus Torvalds 		"Video Playback Switch",
6061da177e4SLinus Torvalds 		"Video Playback Volume",
6071da177e4SLinus Torvalds 		"PC Speaker Playback Switch",
6081da177e4SLinus Torvalds 		"PC Speaker Playback Volume",
6091da177e4SLinus Torvalds 		"Mono Output Select",
6101da177e4SLinus Torvalds 		"Capture Source",
6111da177e4SLinus Torvalds 		"Capture Switch",
6121da177e4SLinus Torvalds 		"Capture Volume",
6131da177e4SLinus Torvalds 		"External Amplifier",
6141da177e4SLinus Torvalds 		"Sigmatel 4-Speaker Stereo Playback Switch",
6151da177e4SLinus Torvalds 		"Sigmatel Surround Phase Inversion Playback ",
6161da177e4SLinus Torvalds 		NULL
6171da177e4SLinus Torvalds 	};
6181da177e4SLinus Torvalds 	static char *ca0106_rename_ctls[] = {
6191da177e4SLinus Torvalds 		"Master Playback Switch", "Capture Switch",
6201da177e4SLinus Torvalds 		"Master Playback Volume", "Capture Volume",
6211da177e4SLinus Torvalds 		"Line Playback Switch", "AC97 Line Capture Switch",
6221da177e4SLinus Torvalds 		"Line Playback Volume", "AC97 Line Capture Volume",
6231da177e4SLinus Torvalds 		"Aux Playback Switch", "AC97 Aux Capture Switch",
6241da177e4SLinus Torvalds 		"Aux Playback Volume", "AC97 Aux Capture Volume",
6251da177e4SLinus Torvalds 		"Mic Playback Switch", "AC97 Mic Capture Switch",
6261da177e4SLinus Torvalds 		"Mic Playback Volume", "AC97 Mic Capture Volume",
6271da177e4SLinus Torvalds 		"Mic Select", "AC97 Mic Select",
6281da177e4SLinus Torvalds 		"Mic Boost (+20dB)", "AC97 Mic Boost (+20dB)",
6291da177e4SLinus Torvalds 		NULL
6301da177e4SLinus Torvalds 	};
6311da177e4SLinus Torvalds #if 1
6321da177e4SLinus Torvalds 	for (c = ca0106_remove_ctls; *c; c++)
6331da177e4SLinus Torvalds 		remove_ctl(card, *c);
6341da177e4SLinus Torvalds 	for (c = ca0106_rename_ctls; *c; c += 2)
6351da177e4SLinus Torvalds 		rename_ctl(card, c[0], c[1]);
6361da177e4SLinus Torvalds #endif
6371da177e4SLinus Torvalds 
63895a98265STakashi Iwai 	for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_ctls); i++) {
63995a98265STakashi Iwai 		err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_ctls[i], emu));
64095a98265STakashi Iwai 		if (err < 0)
641ed144f3cSJames Courtier-Dutton 			return err;
642ed144f3cSJames Courtier-Dutton 	}
64395a98265STakashi Iwai 	if (emu->details->i2c_adc == 1) {
644be0b7b01SJames Courtier-Dutton 		if (emu->details->gpio_type == 1)
64595a98265STakashi Iwai 			err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu));
646be0b7b01SJames Courtier-Dutton 		else  /* gpio_type == 2 */
647be0b7b01SJames Courtier-Dutton 			err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_line_in_side_out, emu));
64895a98265STakashi Iwai 		if (err < 0)
6491da177e4SLinus Torvalds 			return err;
65095a98265STakashi Iwai 	}
6511da177e4SLinus Torvalds         return 0;
6521da177e4SLinus Torvalds }
6531da177e4SLinus Torvalds 
654