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/slab.h> 661da177e4SLinus Torvalds #include <linux/moduleparam.h> 671da177e4SLinus Torvalds #include <sound/core.h> 681da177e4SLinus Torvalds #include <sound/initval.h> 691da177e4SLinus Torvalds #include <sound/pcm.h> 701da177e4SLinus Torvalds #include <sound/ac97_codec.h> 711da177e4SLinus Torvalds #include <sound/info.h> 7242750b04SJaroslav Kysela #include <sound/tlv.h> 73*6473d160SJean Delvare #include <asm/io.h> 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds #include "ca0106.h" 761da177e4SLinus Torvalds 770cb29ea0STakashi Iwai static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1); 780cb29ea0STakashi Iwai static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1); 7942750b04SJaroslav Kysela 80e4a3d145STakashi Iwai static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol, 81e4a3d145STakashi Iwai struct snd_ctl_elem_info *uinfo) 821da177e4SLinus Torvalds { 831da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 841da177e4SLinus Torvalds uinfo->count = 1; 851da177e4SLinus Torvalds uinfo->value.integer.min = 0; 861da177e4SLinus Torvalds uinfo->value.integer.max = 1; 871da177e4SLinus Torvalds return 0; 881da177e4SLinus Torvalds } 891da177e4SLinus Torvalds 90e4a3d145STakashi Iwai static int snd_ca0106_shared_spdif_get(struct snd_kcontrol *kcontrol, 91e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 921da177e4SLinus Torvalds { 93e4a3d145STakashi Iwai struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = emu->spdif_enable; 961da177e4SLinus Torvalds return 0; 971da177e4SLinus Torvalds } 981da177e4SLinus Torvalds 99e4a3d145STakashi Iwai static int snd_ca0106_shared_spdif_put(struct snd_kcontrol *kcontrol, 100e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1011da177e4SLinus Torvalds { 102e4a3d145STakashi Iwai struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 1031da177e4SLinus Torvalds unsigned int val; 1041da177e4SLinus Torvalds int change = 0; 1051da177e4SLinus Torvalds u32 mask; 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds val = ucontrol->value.enumerated.item[0] ; 1081da177e4SLinus Torvalds change = (emu->spdif_enable != val); 1091da177e4SLinus Torvalds if (change) { 1101da177e4SLinus Torvalds emu->spdif_enable = val; 1111da177e4SLinus Torvalds if (val == 1) { 1121da177e4SLinus Torvalds /* Digital */ 1131da177e4SLinus Torvalds snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); 1141da177e4SLinus Torvalds snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000); 1151da177e4SLinus Torvalds snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, 1161da177e4SLinus Torvalds snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000); 1171da177e4SLinus Torvalds mask = inl(emu->port + GPIO) & ~0x101; 1181da177e4SLinus Torvalds outl(mask, emu->port + GPIO); 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds } else { 1211da177e4SLinus Torvalds /* Analog */ 1221da177e4SLinus Torvalds snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); 1231f82941eSJames Courtier-Dutton snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000); 1241da177e4SLinus Torvalds snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, 1251da177e4SLinus Torvalds snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000); 1261da177e4SLinus Torvalds mask = inl(emu->port + GPIO) | 0x101; 1271da177e4SLinus Torvalds outl(mask, emu->port + GPIO); 1281da177e4SLinus Torvalds } 1291da177e4SLinus Torvalds } 1301da177e4SLinus Torvalds return change; 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds 133e4a3d145STakashi Iwai static int snd_ca0106_capture_source_info(struct snd_kcontrol *kcontrol, 134e4a3d145STakashi Iwai struct snd_ctl_elem_info *uinfo) 1351da177e4SLinus Torvalds { 13695a98265STakashi Iwai static char *texts[6] = { 13739596dc8SJames Courtier-Dutton "IEC958 out", "i2s mixer out", "IEC958 in", "i2s in", "AC97 in", "SRC out" 13895a98265STakashi Iwai }; 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 1411da177e4SLinus Torvalds uinfo->count = 1; 1421da177e4SLinus Torvalds uinfo->value.enumerated.items = 6; 1431da177e4SLinus Torvalds if (uinfo->value.enumerated.item > 5) 1441da177e4SLinus Torvalds uinfo->value.enumerated.item = 5; 1451da177e4SLinus Torvalds strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 1461da177e4SLinus Torvalds return 0; 1471da177e4SLinus Torvalds } 1481da177e4SLinus Torvalds 149e4a3d145STakashi Iwai static int snd_ca0106_capture_source_get(struct snd_kcontrol *kcontrol, 150e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1511da177e4SLinus Torvalds { 152e4a3d145STakashi Iwai struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = emu->capture_source; 1551da177e4SLinus Torvalds return 0; 1561da177e4SLinus Torvalds } 1571da177e4SLinus Torvalds 158e4a3d145STakashi Iwai static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol, 159e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1601da177e4SLinus Torvalds { 161e4a3d145STakashi Iwai struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 1621da177e4SLinus Torvalds unsigned int val; 1631da177e4SLinus Torvalds int change = 0; 1641da177e4SLinus Torvalds u32 mask; 1651da177e4SLinus Torvalds u32 source; 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds val = ucontrol->value.enumerated.item[0] ; 1681da177e4SLinus Torvalds change = (emu->capture_source != val); 1691da177e4SLinus Torvalds if (change) { 1701da177e4SLinus Torvalds emu->capture_source = val; 1711da177e4SLinus Torvalds source = (val << 28) | (val << 24) | (val << 20) | (val << 16); 1721da177e4SLinus Torvalds mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff; 1731da177e4SLinus Torvalds snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask); 1741da177e4SLinus Torvalds } 1751da177e4SLinus Torvalds return change; 1761da177e4SLinus Torvalds } 1771da177e4SLinus Torvalds 1786129daaaSJames Courtier-Dutton static int snd_ca0106_i2c_capture_source_info(struct snd_kcontrol *kcontrol, 1796129daaaSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 1806129daaaSJames Courtier-Dutton { 1816129daaaSJames Courtier-Dutton static char *texts[6] = { 1826129daaaSJames Courtier-Dutton "Phone", "Mic", "Line in", "Aux" 1836129daaaSJames Courtier-Dutton }; 1846129daaaSJames Courtier-Dutton 1856129daaaSJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 1866129daaaSJames Courtier-Dutton uinfo->count = 1; 1876129daaaSJames Courtier-Dutton uinfo->value.enumerated.items = 4; 1886129daaaSJames Courtier-Dutton if (uinfo->value.enumerated.item > 3) 1896129daaaSJames Courtier-Dutton uinfo->value.enumerated.item = 3; 1906129daaaSJames Courtier-Dutton strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 1916129daaaSJames Courtier-Dutton return 0; 1926129daaaSJames Courtier-Dutton } 1936129daaaSJames Courtier-Dutton 1946129daaaSJames Courtier-Dutton static int snd_ca0106_i2c_capture_source_get(struct snd_kcontrol *kcontrol, 1956129daaaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 1966129daaaSJames Courtier-Dutton { 1976129daaaSJames Courtier-Dutton struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 1986129daaaSJames Courtier-Dutton 1996129daaaSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->i2c_capture_source; 2006129daaaSJames Courtier-Dutton return 0; 2016129daaaSJames Courtier-Dutton } 2026129daaaSJames Courtier-Dutton 2036129daaaSJames Courtier-Dutton static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol, 2046129daaaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 2056129daaaSJames Courtier-Dutton { 2066129daaaSJames Courtier-Dutton struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 2076129daaaSJames Courtier-Dutton unsigned int source_id; 2086129daaaSJames Courtier-Dutton unsigned int ngain, ogain; 2096129daaaSJames Courtier-Dutton int change = 0; 2106129daaaSJames Courtier-Dutton u32 source; 2116129daaaSJames Courtier-Dutton /* If the capture source has changed, 2126129daaaSJames Courtier-Dutton * update the capture volume from the cached value 2136129daaaSJames Courtier-Dutton * for the particular source. 2146129daaaSJames Courtier-Dutton */ 2156129daaaSJames Courtier-Dutton source_id = ucontrol->value.enumerated.item[0] ; 2166129daaaSJames Courtier-Dutton change = (emu->i2c_capture_source != source_id); 2176129daaaSJames Courtier-Dutton if (change) { 2186129daaaSJames Courtier-Dutton snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ 2196129daaaSJames Courtier-Dutton ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ 2206129daaaSJames Courtier-Dutton ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ 2216129daaaSJames Courtier-Dutton if (ngain != ogain) 2226129daaaSJames Courtier-Dutton snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); 2236129daaaSJames Courtier-Dutton ngain = emu->i2c_capture_volume[source_id][1]; /* Left */ 2246129daaaSJames Courtier-Dutton ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Left */ 2256129daaaSJames Courtier-Dutton if (ngain != ogain) 2266129daaaSJames Courtier-Dutton snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); 2276129daaaSJames Courtier-Dutton source = 1 << source_id; 2286129daaaSJames Courtier-Dutton snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */ 2296129daaaSJames Courtier-Dutton emu->i2c_capture_source = source_id; 2306129daaaSJames Courtier-Dutton } 2316129daaaSJames Courtier-Dutton return change; 2326129daaaSJames Courtier-Dutton } 2336129daaaSJames Courtier-Dutton 234be0b7b01SJames Courtier-Dutton static int snd_ca0106_capture_line_in_side_out_info(struct snd_kcontrol *kcontrol, 235be0b7b01SJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 236be0b7b01SJames Courtier-Dutton { 237be0b7b01SJames Courtier-Dutton static char *texts[2] = { "Side out", "Line in" }; 238be0b7b01SJames Courtier-Dutton 239be0b7b01SJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 240be0b7b01SJames Courtier-Dutton uinfo->count = 1; 241be0b7b01SJames Courtier-Dutton uinfo->value.enumerated.items = 2; 242be0b7b01SJames Courtier-Dutton if (uinfo->value.enumerated.item > 1) 243be0b7b01SJames Courtier-Dutton uinfo->value.enumerated.item = 1; 244be0b7b01SJames Courtier-Dutton strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 245be0b7b01SJames Courtier-Dutton return 0; 246be0b7b01SJames Courtier-Dutton } 247be0b7b01SJames Courtier-Dutton 248e4a3d145STakashi Iwai static int snd_ca0106_capture_mic_line_in_info(struct snd_kcontrol *kcontrol, 249e4a3d145STakashi Iwai struct snd_ctl_elem_info *uinfo) 250ed144f3cSJames Courtier-Dutton { 251ed144f3cSJames Courtier-Dutton static char *texts[2] = { "Line in", "Mic in" }; 252ed144f3cSJames Courtier-Dutton 253ed144f3cSJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 254ed144f3cSJames Courtier-Dutton uinfo->count = 1; 255ed144f3cSJames Courtier-Dutton uinfo->value.enumerated.items = 2; 256ed144f3cSJames Courtier-Dutton if (uinfo->value.enumerated.item > 1) 257ed144f3cSJames Courtier-Dutton uinfo->value.enumerated.item = 1; 258ed144f3cSJames Courtier-Dutton strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 259ed144f3cSJames Courtier-Dutton return 0; 260ed144f3cSJames Courtier-Dutton } 261ed144f3cSJames Courtier-Dutton 262e4a3d145STakashi Iwai static int snd_ca0106_capture_mic_line_in_get(struct snd_kcontrol *kcontrol, 263e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 264ed144f3cSJames Courtier-Dutton { 265e4a3d145STakashi Iwai struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 266ed144f3cSJames Courtier-Dutton 267ed144f3cSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->capture_mic_line_in; 268ed144f3cSJames Courtier-Dutton return 0; 269ed144f3cSJames Courtier-Dutton } 270ed144f3cSJames Courtier-Dutton 271e4a3d145STakashi Iwai static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol, 272e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 273ed144f3cSJames Courtier-Dutton { 274e4a3d145STakashi Iwai struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 275ed144f3cSJames Courtier-Dutton unsigned int val; 276ed144f3cSJames Courtier-Dutton int change = 0; 277ed144f3cSJames Courtier-Dutton u32 tmp; 278ed144f3cSJames Courtier-Dutton 279ed144f3cSJames Courtier-Dutton val = ucontrol->value.enumerated.item[0] ; 280ed144f3cSJames Courtier-Dutton change = (emu->capture_mic_line_in != val); 281ed144f3cSJames Courtier-Dutton if (change) { 282ed144f3cSJames Courtier-Dutton emu->capture_mic_line_in = val; 283ed144f3cSJames Courtier-Dutton if (val) { 2846129daaaSJames Courtier-Dutton //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ 285ed144f3cSJames Courtier-Dutton tmp = inl(emu->port+GPIO) & ~0x400; 286ed144f3cSJames Courtier-Dutton tmp = tmp | 0x400; 287ed144f3cSJames Courtier-Dutton outl(tmp, emu->port+GPIO); 2886129daaaSJames Courtier-Dutton //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); 289ed144f3cSJames Courtier-Dutton } else { 2906129daaaSJames Courtier-Dutton //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ 291ed144f3cSJames Courtier-Dutton tmp = inl(emu->port+GPIO) & ~0x400; 292ed144f3cSJames Courtier-Dutton outl(tmp, emu->port+GPIO); 2936129daaaSJames Courtier-Dutton //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); 294ed144f3cSJames Courtier-Dutton } 295ed144f3cSJames Courtier-Dutton } 296ed144f3cSJames Courtier-Dutton return change; 297ed144f3cSJames Courtier-Dutton } 298ed144f3cSJames Courtier-Dutton 299e4a3d145STakashi Iwai static struct snd_kcontrol_new snd_ca0106_capture_mic_line_in __devinitdata = 300ed144f3cSJames Courtier-Dutton { 301ed144f3cSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3026129daaaSJames Courtier-Dutton .name = "Shared Mic/Line in Capture Switch", 303ed144f3cSJames Courtier-Dutton .info = snd_ca0106_capture_mic_line_in_info, 304ed144f3cSJames Courtier-Dutton .get = snd_ca0106_capture_mic_line_in_get, 305ed144f3cSJames Courtier-Dutton .put = snd_ca0106_capture_mic_line_in_put 306ed144f3cSJames Courtier-Dutton }; 307ed144f3cSJames Courtier-Dutton 308be0b7b01SJames Courtier-Dutton static struct snd_kcontrol_new snd_ca0106_capture_line_in_side_out __devinitdata = 309be0b7b01SJames Courtier-Dutton { 310be0b7b01SJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 311be0b7b01SJames Courtier-Dutton .name = "Shared Line in/Side out Capture Switch", 312be0b7b01SJames Courtier-Dutton .info = snd_ca0106_capture_line_in_side_out_info, 313be0b7b01SJames Courtier-Dutton .get = snd_ca0106_capture_mic_line_in_get, 314be0b7b01SJames Courtier-Dutton .put = snd_ca0106_capture_mic_line_in_put 315be0b7b01SJames Courtier-Dutton }; 316be0b7b01SJames Courtier-Dutton 317be0b7b01SJames Courtier-Dutton 318e4a3d145STakashi Iwai static int snd_ca0106_spdif_info(struct snd_kcontrol *kcontrol, 319e4a3d145STakashi Iwai struct snd_ctl_elem_info *uinfo) 3201da177e4SLinus Torvalds { 3211da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 3221da177e4SLinus Torvalds uinfo->count = 1; 3231da177e4SLinus Torvalds return 0; 3241da177e4SLinus Torvalds } 3251da177e4SLinus Torvalds 326e4a3d145STakashi Iwai static int snd_ca0106_spdif_get(struct snd_kcontrol *kcontrol, 327e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3281da177e4SLinus Torvalds { 329e4a3d145STakashi Iwai struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 3301da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 3311da177e4SLinus Torvalds 3321da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; 3331da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; 3341da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff; 3351da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff; 3361da177e4SLinus Torvalds return 0; 3371da177e4SLinus Torvalds } 3381da177e4SLinus Torvalds 339e4a3d145STakashi Iwai static int snd_ca0106_spdif_get_mask(struct snd_kcontrol *kcontrol, 340e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3411da177e4SLinus Torvalds { 3421da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = 0xff; 3431da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = 0xff; 3441da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = 0xff; 3451da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = 0xff; 3461da177e4SLinus Torvalds return 0; 3471da177e4SLinus Torvalds } 3481da177e4SLinus Torvalds 349e4a3d145STakashi Iwai static int snd_ca0106_spdif_put(struct snd_kcontrol *kcontrol, 350e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3511da177e4SLinus Torvalds { 352e4a3d145STakashi Iwai struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 3531da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 3541da177e4SLinus Torvalds int change; 3551da177e4SLinus Torvalds unsigned int val; 3561da177e4SLinus Torvalds 3571da177e4SLinus Torvalds val = (ucontrol->value.iec958.status[0] << 0) | 3581da177e4SLinus Torvalds (ucontrol->value.iec958.status[1] << 8) | 3591da177e4SLinus Torvalds (ucontrol->value.iec958.status[2] << 16) | 3601da177e4SLinus Torvalds (ucontrol->value.iec958.status[3] << 24); 3611da177e4SLinus Torvalds change = val != emu->spdif_bits[idx]; 3621da177e4SLinus Torvalds if (change) { 3631da177e4SLinus Torvalds snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, val); 3641da177e4SLinus Torvalds emu->spdif_bits[idx] = val; 3651da177e4SLinus Torvalds } 3661da177e4SLinus Torvalds return change; 3671da177e4SLinus Torvalds } 3681da177e4SLinus Torvalds 369e4a3d145STakashi Iwai static int snd_ca0106_volume_info(struct snd_kcontrol *kcontrol, 370e4a3d145STakashi Iwai struct snd_ctl_elem_info *uinfo) 3711da177e4SLinus Torvalds { 3721da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 3731da177e4SLinus Torvalds uinfo->count = 2; 3741da177e4SLinus Torvalds uinfo->value.integer.min = 0; 3751da177e4SLinus Torvalds uinfo->value.integer.max = 255; 3761da177e4SLinus Torvalds return 0; 3771da177e4SLinus Torvalds } 3781da177e4SLinus Torvalds 379e4a3d145STakashi Iwai static int snd_ca0106_volume_get(struct snd_kcontrol *kcontrol, 380e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3811da177e4SLinus Torvalds { 382e4a3d145STakashi Iwai struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 3831da177e4SLinus Torvalds unsigned int value; 38495a98265STakashi Iwai int channel_id, reg; 38595a98265STakashi Iwai 38695a98265STakashi Iwai channel_id = (kcontrol->private_value >> 8) & 0xff; 38795a98265STakashi Iwai reg = kcontrol->private_value & 0xff; 3881da177e4SLinus Torvalds 3891da177e4SLinus Torvalds value = snd_ca0106_ptr_read(emu, reg, channel_id); 3901da177e4SLinus Torvalds ucontrol->value.integer.value[0] = 0xff - ((value >> 24) & 0xff); /* Left */ 3911da177e4SLinus Torvalds ucontrol->value.integer.value[1] = 0xff - ((value >> 16) & 0xff); /* Right */ 3921da177e4SLinus Torvalds return 0; 3931da177e4SLinus Torvalds } 3941da177e4SLinus Torvalds 395e4a3d145STakashi Iwai static int snd_ca0106_volume_put(struct snd_kcontrol *kcontrol, 396e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3971da177e4SLinus Torvalds { 398e4a3d145STakashi Iwai struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 39995a98265STakashi Iwai unsigned int oval, nval; 40095a98265STakashi Iwai int channel_id, reg; 40195a98265STakashi Iwai 40295a98265STakashi Iwai channel_id = (kcontrol->private_value >> 8) & 0xff; 40395a98265STakashi Iwai reg = kcontrol->private_value & 0xff; 40495a98265STakashi Iwai 40595a98265STakashi Iwai oval = snd_ca0106_ptr_read(emu, reg, channel_id); 40695a98265STakashi Iwai nval = ((0xff - ucontrol->value.integer.value[0]) << 24) | 40795a98265STakashi Iwai ((0xff - ucontrol->value.integer.value[1]) << 16); 40895a98265STakashi Iwai nval |= ((0xff - ucontrol->value.integer.value[0]) << 8) | 40995a98265STakashi Iwai ((0xff - ucontrol->value.integer.value[1]) ); 41095a98265STakashi Iwai if (oval == nval) 41195a98265STakashi Iwai return 0; 41295a98265STakashi Iwai snd_ca0106_ptr_write(emu, reg, channel_id, nval); 4131da177e4SLinus Torvalds return 1; 4141da177e4SLinus Torvalds } 41595a98265STakashi Iwai 4166129daaaSJames Courtier-Dutton static int snd_ca0106_i2c_volume_info(struct snd_kcontrol *kcontrol, 4176129daaaSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 4186129daaaSJames Courtier-Dutton { 4196129daaaSJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 4206129daaaSJames Courtier-Dutton uinfo->count = 2; 4216129daaaSJames Courtier-Dutton uinfo->value.integer.min = 0; 4226129daaaSJames Courtier-Dutton uinfo->value.integer.max = 255; 4236129daaaSJames Courtier-Dutton return 0; 4246129daaaSJames Courtier-Dutton } 4256129daaaSJames Courtier-Dutton 4266129daaaSJames Courtier-Dutton static int snd_ca0106_i2c_volume_get(struct snd_kcontrol *kcontrol, 4276129daaaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 4286129daaaSJames Courtier-Dutton { 4296129daaaSJames Courtier-Dutton struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 4306129daaaSJames Courtier-Dutton int source_id; 4316129daaaSJames Courtier-Dutton 4326129daaaSJames Courtier-Dutton source_id = kcontrol->private_value; 4336129daaaSJames Courtier-Dutton 4346129daaaSJames Courtier-Dutton ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0]; 4356129daaaSJames Courtier-Dutton ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1]; 4366129daaaSJames Courtier-Dutton return 0; 4376129daaaSJames Courtier-Dutton } 4386129daaaSJames Courtier-Dutton 4396129daaaSJames Courtier-Dutton static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol, 4406129daaaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 4416129daaaSJames Courtier-Dutton { 4426129daaaSJames Courtier-Dutton struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 4436129daaaSJames Courtier-Dutton unsigned int ogain; 4446129daaaSJames Courtier-Dutton unsigned int ngain; 4456129daaaSJames Courtier-Dutton int source_id; 4466129daaaSJames Courtier-Dutton int change = 0; 4476129daaaSJames Courtier-Dutton 4486129daaaSJames Courtier-Dutton source_id = kcontrol->private_value; 4496129daaaSJames Courtier-Dutton ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ 4506129daaaSJames Courtier-Dutton ngain = ucontrol->value.integer.value[0]; 4516129daaaSJames Courtier-Dutton if (ngain > 0xff) 4526129daaaSJames Courtier-Dutton return 0; 4536129daaaSJames Courtier-Dutton if (ogain != ngain) { 4546129daaaSJames Courtier-Dutton if (emu->i2c_capture_source == source_id) 4556129daaaSJames Courtier-Dutton snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) ); 4566129daaaSJames Courtier-Dutton emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0]; 4576129daaaSJames Courtier-Dutton change = 1; 4586129daaaSJames Courtier-Dutton } 4596129daaaSJames Courtier-Dutton ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ 4606129daaaSJames Courtier-Dutton ngain = ucontrol->value.integer.value[1]; 4616129daaaSJames Courtier-Dutton if (ngain > 0xff) 4626129daaaSJames Courtier-Dutton return 0; 4636129daaaSJames Courtier-Dutton if (ogain != ngain) { 4646129daaaSJames Courtier-Dutton if (emu->i2c_capture_source == source_id) 4656129daaaSJames Courtier-Dutton snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); 4666129daaaSJames Courtier-Dutton emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1]; 4676129daaaSJames Courtier-Dutton change = 1; 4686129daaaSJames Courtier-Dutton } 4696129daaaSJames Courtier-Dutton 4706129daaaSJames Courtier-Dutton return change; 4716129daaaSJames Courtier-Dutton } 4726129daaaSJames Courtier-Dutton 47395a98265STakashi Iwai #define CA_VOLUME(xname,chid,reg) \ 47495a98265STakashi Iwai { \ 47595a98265STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 476302e9c5aSJaroslav Kysela .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ 477302e9c5aSJaroslav Kysela SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 47895a98265STakashi Iwai .info = snd_ca0106_volume_info, \ 47995a98265STakashi Iwai .get = snd_ca0106_volume_get, \ 48095a98265STakashi Iwai .put = snd_ca0106_volume_put, \ 4817cf0a953STakashi Iwai .tlv = { .p = snd_ca0106_db_scale1 }, \ 48295a98265STakashi Iwai .private_value = ((chid) << 8) | (reg) \ 4831da177e4SLinus Torvalds } 4841da177e4SLinus Torvalds 485e4a3d145STakashi Iwai static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { 48695a98265STakashi Iwai CA_VOLUME("Analog Front Playback Volume", 48795a98265STakashi Iwai CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2), 48895a98265STakashi Iwai CA_VOLUME("Analog Rear Playback Volume", 48995a98265STakashi Iwai CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME2), 49095a98265STakashi Iwai CA_VOLUME("Analog Center/LFE Playback Volume", 49195a98265STakashi Iwai CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME2), 49295a98265STakashi Iwai CA_VOLUME("Analog Side Playback Volume", 49395a98265STakashi Iwai CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME2), 49495a98265STakashi Iwai 49539596dc8SJames Courtier-Dutton CA_VOLUME("IEC958 Front Playback Volume", 49695a98265STakashi Iwai CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME1), 49739596dc8SJames Courtier-Dutton CA_VOLUME("IEC958 Rear Playback Volume", 49895a98265STakashi Iwai CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME1), 49939596dc8SJames Courtier-Dutton CA_VOLUME("IEC958 Center/LFE Playback Volume", 50095a98265STakashi Iwai CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME1), 50139596dc8SJames Courtier-Dutton CA_VOLUME("IEC958 Unknown Playback Volume", 50295a98265STakashi Iwai CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME1), 50395a98265STakashi Iwai 50495a98265STakashi Iwai CA_VOLUME("CAPTURE feedback Playback Volume", 50595a98265STakashi Iwai 1, CAPTURE_CONTROL), 50695a98265STakashi Iwai 50795a98265STakashi Iwai { 50895a98265STakashi Iwai .access = SNDRV_CTL_ELEM_ACCESS_READ, 50995a98265STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_PCM, 51095a98265STakashi Iwai .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), 51195a98265STakashi Iwai .count = 4, 51295a98265STakashi Iwai .info = snd_ca0106_spdif_info, 51395a98265STakashi Iwai .get = snd_ca0106_spdif_get_mask 51495a98265STakashi Iwai }, 5151da177e4SLinus Torvalds { 5161da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 51739596dc8SJames Courtier-Dutton .name = "IEC958 Playback Switch", 51895a98265STakashi Iwai .info = snd_ca0106_shared_spdif_info, 51995a98265STakashi Iwai .get = snd_ca0106_shared_spdif_get, 52095a98265STakashi Iwai .put = snd_ca0106_shared_spdif_put 52195a98265STakashi Iwai }, 5221da177e4SLinus Torvalds { 5231da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 524e6327cf9SJames Courtier-Dutton .name = "Digital Source Capture Enum", 52595a98265STakashi Iwai .info = snd_ca0106_capture_source_info, 52695a98265STakashi Iwai .get = snd_ca0106_capture_source_get, 52795a98265STakashi Iwai .put = snd_ca0106_capture_source_put 52895a98265STakashi Iwai }, 5291da177e4SLinus Torvalds { 5306129daaaSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 531e6327cf9SJames Courtier-Dutton .name = "Analog Source Capture Enum", 5326129daaaSJames Courtier-Dutton .info = snd_ca0106_i2c_capture_source_info, 5336129daaaSJames Courtier-Dutton .get = snd_ca0106_i2c_capture_source_get, 5346129daaaSJames Courtier-Dutton .put = snd_ca0106_i2c_capture_source_put 5356129daaaSJames Courtier-Dutton }, 5366129daaaSJames Courtier-Dutton { 53795a98265STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_PCM, 53895a98265STakashi Iwai .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 53995a98265STakashi Iwai .count = 4, 54095a98265STakashi Iwai .info = snd_ca0106_spdif_info, 54195a98265STakashi Iwai .get = snd_ca0106_spdif_get, 54295a98265STakashi Iwai .put = snd_ca0106_spdif_put 54395a98265STakashi Iwai }, 5441da177e4SLinus Torvalds }; 5451da177e4SLinus Torvalds 5467c157069SJames Courtier-Dutton #define I2C_VOLUME(xname,chid) \ 5477c157069SJames Courtier-Dutton { \ 5487c157069SJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 5497c157069SJames Courtier-Dutton .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ 5507c157069SJames Courtier-Dutton SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 5517c157069SJames Courtier-Dutton .info = snd_ca0106_i2c_volume_info, \ 5527c157069SJames Courtier-Dutton .get = snd_ca0106_i2c_volume_get, \ 5537c157069SJames Courtier-Dutton .put = snd_ca0106_i2c_volume_put, \ 5547c157069SJames Courtier-Dutton .tlv = { .p = snd_ca0106_db_scale2 }, \ 5557c157069SJames Courtier-Dutton .private_value = chid \ 5567c157069SJames Courtier-Dutton } 5577c157069SJames Courtier-Dutton 5587c157069SJames Courtier-Dutton static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata = { 5597c157069SJames Courtier-Dutton I2C_VOLUME("Phone Capture Volume", 0), 5607c157069SJames Courtier-Dutton I2C_VOLUME("Mic Capture Volume", 1), 5617c157069SJames Courtier-Dutton I2C_VOLUME("Line in Capture Volume", 2), 5627c157069SJames Courtier-Dutton I2C_VOLUME("Aux Capture Volume", 3), 5637c157069SJames Courtier-Dutton }; 5647c157069SJames Courtier-Dutton 565e4a3d145STakashi Iwai static int __devinit remove_ctl(struct snd_card *card, const char *name) 5661da177e4SLinus Torvalds { 567e4a3d145STakashi Iwai struct snd_ctl_elem_id id; 5681da177e4SLinus Torvalds memset(&id, 0, sizeof(id)); 5691da177e4SLinus Torvalds strcpy(id.name, name); 5701da177e4SLinus Torvalds id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 5711da177e4SLinus Torvalds return snd_ctl_remove_id(card, &id); 5721da177e4SLinus Torvalds } 5731da177e4SLinus Torvalds 574e4a3d145STakashi Iwai static struct snd_kcontrol __devinit *ctl_find(struct snd_card *card, const char *name) 5751da177e4SLinus Torvalds { 576e4a3d145STakashi Iwai struct snd_ctl_elem_id sid; 5771da177e4SLinus Torvalds memset(&sid, 0, sizeof(sid)); 5781da177e4SLinus Torvalds /* FIXME: strcpy is bad. */ 5791da177e4SLinus Torvalds strcpy(sid.name, name); 5801da177e4SLinus Torvalds sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 5811da177e4SLinus Torvalds return snd_ctl_find_id(card, &sid); 5821da177e4SLinus Torvalds } 5831da177e4SLinus Torvalds 584e4a3d145STakashi Iwai static int __devinit rename_ctl(struct snd_card *card, const char *src, const char *dst) 5851da177e4SLinus Torvalds { 586e4a3d145STakashi Iwai struct snd_kcontrol *kctl = ctl_find(card, src); 5871da177e4SLinus Torvalds if (kctl) { 5881da177e4SLinus Torvalds strcpy(kctl->id.name, dst); 5891da177e4SLinus Torvalds return 0; 5901da177e4SLinus Torvalds } 5911da177e4SLinus Torvalds return -ENOENT; 5921da177e4SLinus Torvalds } 5931da177e4SLinus Torvalds 594e4a3d145STakashi Iwai int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) 5951da177e4SLinus Torvalds { 59695a98265STakashi Iwai int i, err; 597e4a3d145STakashi Iwai struct snd_card *card = emu->card; 5981da177e4SLinus Torvalds char **c; 5991da177e4SLinus Torvalds static char *ca0106_remove_ctls[] = { 6001da177e4SLinus Torvalds "Master Mono Playback Switch", 6011da177e4SLinus Torvalds "Master Mono Playback Volume", 6021da177e4SLinus Torvalds "3D Control - Switch", 6031da177e4SLinus Torvalds "3D Control Sigmatel - Depth", 6041da177e4SLinus Torvalds "PCM Playback Switch", 6051da177e4SLinus Torvalds "PCM Playback Volume", 6061da177e4SLinus Torvalds "CD Playback Switch", 6071da177e4SLinus Torvalds "CD Playback Volume", 6081da177e4SLinus Torvalds "Phone Playback Switch", 6091da177e4SLinus Torvalds "Phone Playback Volume", 6101da177e4SLinus Torvalds "Video Playback Switch", 6111da177e4SLinus Torvalds "Video Playback Volume", 6121da177e4SLinus Torvalds "PC Speaker Playback Switch", 6131da177e4SLinus Torvalds "PC Speaker Playback Volume", 6141da177e4SLinus Torvalds "Mono Output Select", 6151da177e4SLinus Torvalds "Capture Source", 6161da177e4SLinus Torvalds "Capture Switch", 6171da177e4SLinus Torvalds "Capture Volume", 6181da177e4SLinus Torvalds "External Amplifier", 6191da177e4SLinus Torvalds "Sigmatel 4-Speaker Stereo Playback Switch", 6201da177e4SLinus Torvalds "Sigmatel Surround Phase Inversion Playback ", 6211da177e4SLinus Torvalds NULL 6221da177e4SLinus Torvalds }; 6231da177e4SLinus Torvalds static char *ca0106_rename_ctls[] = { 6241da177e4SLinus Torvalds "Master Playback Switch", "Capture Switch", 6251da177e4SLinus Torvalds "Master Playback Volume", "Capture Volume", 6261da177e4SLinus Torvalds "Line Playback Switch", "AC97 Line Capture Switch", 6271da177e4SLinus Torvalds "Line Playback Volume", "AC97 Line Capture Volume", 6281da177e4SLinus Torvalds "Aux Playback Switch", "AC97 Aux Capture Switch", 6291da177e4SLinus Torvalds "Aux Playback Volume", "AC97 Aux Capture Volume", 6301da177e4SLinus Torvalds "Mic Playback Switch", "AC97 Mic Capture Switch", 6311da177e4SLinus Torvalds "Mic Playback Volume", "AC97 Mic Capture Volume", 6321da177e4SLinus Torvalds "Mic Select", "AC97 Mic Select", 6331da177e4SLinus Torvalds "Mic Boost (+20dB)", "AC97 Mic Boost (+20dB)", 6341da177e4SLinus Torvalds NULL 6351da177e4SLinus Torvalds }; 6361da177e4SLinus Torvalds #if 1 6371da177e4SLinus Torvalds for (c = ca0106_remove_ctls; *c; c++) 6381da177e4SLinus Torvalds remove_ctl(card, *c); 6391da177e4SLinus Torvalds for (c = ca0106_rename_ctls; *c; c += 2) 6401da177e4SLinus Torvalds rename_ctl(card, c[0], c[1]); 6411da177e4SLinus Torvalds #endif 6421da177e4SLinus Torvalds 64395a98265STakashi Iwai for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_ctls); i++) { 64495a98265STakashi Iwai err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_ctls[i], emu)); 64595a98265STakashi Iwai if (err < 0) 646ed144f3cSJames Courtier-Dutton return err; 647ed144f3cSJames Courtier-Dutton } 64895a98265STakashi Iwai if (emu->details->i2c_adc == 1) { 6497c157069SJames Courtier-Dutton for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_i2c_adc_ctls); i++) { 6507c157069SJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_i2c_adc_ctls[i], emu)); 6517c157069SJames Courtier-Dutton if (err < 0) 6527c157069SJames Courtier-Dutton return err; 6537c157069SJames Courtier-Dutton } 654be0b7b01SJames Courtier-Dutton if (emu->details->gpio_type == 1) 65595a98265STakashi Iwai err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu)); 656be0b7b01SJames Courtier-Dutton else /* gpio_type == 2 */ 657be0b7b01SJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_line_in_side_out, emu)); 65895a98265STakashi Iwai if (err < 0) 6591da177e4SLinus Torvalds return err; 66095a98265STakashi Iwai } 6611da177e4SLinus Torvalds return 0; 6621da177e4SLinus Torvalds } 6631da177e4SLinus Torvalds 664