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> 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds #include "ca0106.h" 751da177e4SLinus Torvalds 76e4a3d145STakashi Iwai static int snd_ca0106_shared_spdif_info(struct snd_kcontrol *kcontrol, 77e4a3d145STakashi Iwai struct snd_ctl_elem_info *uinfo) 781da177e4SLinus Torvalds { 791da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 801da177e4SLinus Torvalds uinfo->count = 1; 811da177e4SLinus Torvalds uinfo->value.integer.min = 0; 821da177e4SLinus Torvalds uinfo->value.integer.max = 1; 831da177e4SLinus Torvalds return 0; 841da177e4SLinus Torvalds } 851da177e4SLinus Torvalds 86e4a3d145STakashi Iwai static int snd_ca0106_shared_spdif_get(struct snd_kcontrol *kcontrol, 87e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 881da177e4SLinus Torvalds { 89e4a3d145STakashi Iwai struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = emu->spdif_enable; 921da177e4SLinus Torvalds return 0; 931da177e4SLinus Torvalds } 941da177e4SLinus Torvalds 95e4a3d145STakashi Iwai static int snd_ca0106_shared_spdif_put(struct snd_kcontrol *kcontrol, 96e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 971da177e4SLinus Torvalds { 98e4a3d145STakashi Iwai struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 991da177e4SLinus Torvalds unsigned int val; 1001da177e4SLinus Torvalds int change = 0; 1011da177e4SLinus Torvalds u32 mask; 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds val = ucontrol->value.enumerated.item[0] ; 1041da177e4SLinus Torvalds change = (emu->spdif_enable != val); 1051da177e4SLinus Torvalds if (change) { 1061da177e4SLinus Torvalds emu->spdif_enable = val; 1071da177e4SLinus Torvalds if (val == 1) { 1081da177e4SLinus Torvalds /* Digital */ 1091da177e4SLinus Torvalds snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); 1101da177e4SLinus Torvalds snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000); 1111da177e4SLinus Torvalds snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, 1121da177e4SLinus Torvalds snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000); 1131da177e4SLinus Torvalds mask = inl(emu->port + GPIO) & ~0x101; 1141da177e4SLinus Torvalds outl(mask, emu->port + GPIO); 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds } else { 1171da177e4SLinus Torvalds /* Analog */ 1181da177e4SLinus Torvalds snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); 1191f82941eSJames Courtier-Dutton snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000); 1201da177e4SLinus Torvalds snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, 1211da177e4SLinus Torvalds snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000); 1221da177e4SLinus Torvalds mask = inl(emu->port + GPIO) | 0x101; 1231da177e4SLinus Torvalds outl(mask, emu->port + GPIO); 1241da177e4SLinus Torvalds } 1251da177e4SLinus Torvalds } 1261da177e4SLinus Torvalds return change; 1271da177e4SLinus Torvalds } 1281da177e4SLinus Torvalds 129e4a3d145STakashi Iwai static int snd_ca0106_capture_source_info(struct snd_kcontrol *kcontrol, 130e4a3d145STakashi Iwai struct snd_ctl_elem_info *uinfo) 1311da177e4SLinus Torvalds { 13295a98265STakashi Iwai static char *texts[6] = { 13339596dc8SJames Courtier-Dutton "IEC958 out", "i2s mixer out", "IEC958 in", "i2s in", "AC97 in", "SRC out" 13495a98265STakashi Iwai }; 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 1371da177e4SLinus Torvalds uinfo->count = 1; 1381da177e4SLinus Torvalds uinfo->value.enumerated.items = 6; 1391da177e4SLinus Torvalds if (uinfo->value.enumerated.item > 5) 1401da177e4SLinus Torvalds uinfo->value.enumerated.item = 5; 1411da177e4SLinus Torvalds strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 1421da177e4SLinus Torvalds return 0; 1431da177e4SLinus Torvalds } 1441da177e4SLinus Torvalds 145e4a3d145STakashi Iwai static int snd_ca0106_capture_source_get(struct snd_kcontrol *kcontrol, 146e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1471da177e4SLinus Torvalds { 148e4a3d145STakashi Iwai struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds ucontrol->value.enumerated.item[0] = emu->capture_source; 1511da177e4SLinus Torvalds return 0; 1521da177e4SLinus Torvalds } 1531da177e4SLinus Torvalds 154e4a3d145STakashi Iwai static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol, 155e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 1561da177e4SLinus Torvalds { 157e4a3d145STakashi Iwai struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 1581da177e4SLinus Torvalds unsigned int val; 1591da177e4SLinus Torvalds int change = 0; 1601da177e4SLinus Torvalds u32 mask; 1611da177e4SLinus Torvalds u32 source; 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds val = ucontrol->value.enumerated.item[0] ; 1641da177e4SLinus Torvalds change = (emu->capture_source != val); 1651da177e4SLinus Torvalds if (change) { 1661da177e4SLinus Torvalds emu->capture_source = val; 1671da177e4SLinus Torvalds source = (val << 28) | (val << 24) | (val << 20) | (val << 16); 1681da177e4SLinus Torvalds mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff; 1691da177e4SLinus Torvalds snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask); 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds return change; 1721da177e4SLinus Torvalds } 1731da177e4SLinus Torvalds 1746129daaaSJames Courtier-Dutton static int snd_ca0106_i2c_capture_source_info(struct snd_kcontrol *kcontrol, 1756129daaaSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 1766129daaaSJames Courtier-Dutton { 1776129daaaSJames Courtier-Dutton static char *texts[6] = { 1786129daaaSJames Courtier-Dutton "Phone", "Mic", "Line in", "Aux" 1796129daaaSJames Courtier-Dutton }; 1806129daaaSJames Courtier-Dutton 1816129daaaSJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 1826129daaaSJames Courtier-Dutton uinfo->count = 1; 1836129daaaSJames Courtier-Dutton uinfo->value.enumerated.items = 4; 1846129daaaSJames Courtier-Dutton if (uinfo->value.enumerated.item > 3) 1856129daaaSJames Courtier-Dutton uinfo->value.enumerated.item = 3; 1866129daaaSJames Courtier-Dutton strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 1876129daaaSJames Courtier-Dutton return 0; 1886129daaaSJames Courtier-Dutton } 1896129daaaSJames Courtier-Dutton 1906129daaaSJames Courtier-Dutton static int snd_ca0106_i2c_capture_source_get(struct snd_kcontrol *kcontrol, 1916129daaaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 1926129daaaSJames Courtier-Dutton { 1936129daaaSJames Courtier-Dutton struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 1946129daaaSJames Courtier-Dutton 1956129daaaSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->i2c_capture_source; 1966129daaaSJames Courtier-Dutton return 0; 1976129daaaSJames Courtier-Dutton } 1986129daaaSJames Courtier-Dutton 1996129daaaSJames Courtier-Dutton static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol, 2006129daaaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 2016129daaaSJames Courtier-Dutton { 2026129daaaSJames Courtier-Dutton struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 2036129daaaSJames Courtier-Dutton unsigned int source_id; 2046129daaaSJames Courtier-Dutton unsigned int ngain, ogain; 2056129daaaSJames Courtier-Dutton int change = 0; 2066129daaaSJames Courtier-Dutton u32 source; 2076129daaaSJames Courtier-Dutton /* If the capture source has changed, 2086129daaaSJames Courtier-Dutton * update the capture volume from the cached value 2096129daaaSJames Courtier-Dutton * for the particular source. 2106129daaaSJames Courtier-Dutton */ 2116129daaaSJames Courtier-Dutton source_id = ucontrol->value.enumerated.item[0] ; 2126129daaaSJames Courtier-Dutton change = (emu->i2c_capture_source != source_id); 2136129daaaSJames Courtier-Dutton if (change) { 2146129daaaSJames Courtier-Dutton snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ 2156129daaaSJames Courtier-Dutton ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ 2166129daaaSJames Courtier-Dutton ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ 2176129daaaSJames Courtier-Dutton if (ngain != ogain) 2186129daaaSJames Courtier-Dutton snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); 2196129daaaSJames Courtier-Dutton ngain = emu->i2c_capture_volume[source_id][1]; /* Left */ 2206129daaaSJames Courtier-Dutton ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Left */ 2216129daaaSJames Courtier-Dutton if (ngain != ogain) 2226129daaaSJames Courtier-Dutton snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); 2236129daaaSJames Courtier-Dutton source = 1 << source_id; 2246129daaaSJames Courtier-Dutton snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */ 2256129daaaSJames Courtier-Dutton emu->i2c_capture_source = source_id; 2266129daaaSJames Courtier-Dutton } 2276129daaaSJames Courtier-Dutton return change; 2286129daaaSJames Courtier-Dutton } 2296129daaaSJames Courtier-Dutton 230*be0b7b01SJames Courtier-Dutton static int snd_ca0106_capture_line_in_side_out_info(struct snd_kcontrol *kcontrol, 231*be0b7b01SJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 232*be0b7b01SJames Courtier-Dutton { 233*be0b7b01SJames Courtier-Dutton static char *texts[2] = { "Side out", "Line in" }; 234*be0b7b01SJames Courtier-Dutton 235*be0b7b01SJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 236*be0b7b01SJames Courtier-Dutton uinfo->count = 1; 237*be0b7b01SJames Courtier-Dutton uinfo->value.enumerated.items = 2; 238*be0b7b01SJames Courtier-Dutton if (uinfo->value.enumerated.item > 1) 239*be0b7b01SJames Courtier-Dutton uinfo->value.enumerated.item = 1; 240*be0b7b01SJames Courtier-Dutton strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 241*be0b7b01SJames Courtier-Dutton return 0; 242*be0b7b01SJames Courtier-Dutton } 243*be0b7b01SJames Courtier-Dutton 244e4a3d145STakashi Iwai static int snd_ca0106_capture_mic_line_in_info(struct snd_kcontrol *kcontrol, 245e4a3d145STakashi Iwai struct snd_ctl_elem_info *uinfo) 246ed144f3cSJames Courtier-Dutton { 247ed144f3cSJames Courtier-Dutton static char *texts[2] = { "Line in", "Mic in" }; 248ed144f3cSJames Courtier-Dutton 249ed144f3cSJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 250ed144f3cSJames Courtier-Dutton uinfo->count = 1; 251ed144f3cSJames Courtier-Dutton uinfo->value.enumerated.items = 2; 252ed144f3cSJames Courtier-Dutton if (uinfo->value.enumerated.item > 1) 253ed144f3cSJames Courtier-Dutton uinfo->value.enumerated.item = 1; 254ed144f3cSJames Courtier-Dutton strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); 255ed144f3cSJames Courtier-Dutton return 0; 256ed144f3cSJames Courtier-Dutton } 257ed144f3cSJames Courtier-Dutton 258e4a3d145STakashi Iwai static int snd_ca0106_capture_mic_line_in_get(struct snd_kcontrol *kcontrol, 259e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 260ed144f3cSJames Courtier-Dutton { 261e4a3d145STakashi Iwai struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 262ed144f3cSJames Courtier-Dutton 263ed144f3cSJames Courtier-Dutton ucontrol->value.enumerated.item[0] = emu->capture_mic_line_in; 264ed144f3cSJames Courtier-Dutton return 0; 265ed144f3cSJames Courtier-Dutton } 266ed144f3cSJames Courtier-Dutton 267e4a3d145STakashi Iwai static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol, 268e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 269ed144f3cSJames Courtier-Dutton { 270e4a3d145STakashi Iwai struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 271ed144f3cSJames Courtier-Dutton unsigned int val; 272ed144f3cSJames Courtier-Dutton int change = 0; 273ed144f3cSJames Courtier-Dutton u32 tmp; 274ed144f3cSJames Courtier-Dutton 275ed144f3cSJames Courtier-Dutton val = ucontrol->value.enumerated.item[0] ; 276ed144f3cSJames Courtier-Dutton change = (emu->capture_mic_line_in != val); 277ed144f3cSJames Courtier-Dutton if (change) { 278ed144f3cSJames Courtier-Dutton emu->capture_mic_line_in = val; 279ed144f3cSJames Courtier-Dutton if (val) { 2806129daaaSJames Courtier-Dutton //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ 281ed144f3cSJames Courtier-Dutton tmp = inl(emu->port+GPIO) & ~0x400; 282ed144f3cSJames Courtier-Dutton tmp = tmp | 0x400; 283ed144f3cSJames Courtier-Dutton outl(tmp, emu->port+GPIO); 2846129daaaSJames Courtier-Dutton //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); 285ed144f3cSJames Courtier-Dutton } else { 2866129daaaSJames Courtier-Dutton //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ 287ed144f3cSJames Courtier-Dutton tmp = inl(emu->port+GPIO) & ~0x400; 288ed144f3cSJames Courtier-Dutton outl(tmp, emu->port+GPIO); 2896129daaaSJames Courtier-Dutton //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); 290ed144f3cSJames Courtier-Dutton } 291ed144f3cSJames Courtier-Dutton } 292ed144f3cSJames Courtier-Dutton return change; 293ed144f3cSJames Courtier-Dutton } 294ed144f3cSJames Courtier-Dutton 295e4a3d145STakashi Iwai static struct snd_kcontrol_new snd_ca0106_capture_mic_line_in __devinitdata = 296ed144f3cSJames Courtier-Dutton { 297ed144f3cSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2986129daaaSJames Courtier-Dutton .name = "Shared Mic/Line in Capture Switch", 299ed144f3cSJames Courtier-Dutton .info = snd_ca0106_capture_mic_line_in_info, 300ed144f3cSJames Courtier-Dutton .get = snd_ca0106_capture_mic_line_in_get, 301ed144f3cSJames Courtier-Dutton .put = snd_ca0106_capture_mic_line_in_put 302ed144f3cSJames Courtier-Dutton }; 303ed144f3cSJames Courtier-Dutton 304*be0b7b01SJames Courtier-Dutton static struct snd_kcontrol_new snd_ca0106_capture_line_in_side_out __devinitdata = 305*be0b7b01SJames Courtier-Dutton { 306*be0b7b01SJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 307*be0b7b01SJames Courtier-Dutton .name = "Shared Line in/Side out Capture Switch", 308*be0b7b01SJames Courtier-Dutton .info = snd_ca0106_capture_line_in_side_out_info, 309*be0b7b01SJames Courtier-Dutton .get = snd_ca0106_capture_mic_line_in_get, 310*be0b7b01SJames Courtier-Dutton .put = snd_ca0106_capture_mic_line_in_put 311*be0b7b01SJames Courtier-Dutton }; 312*be0b7b01SJames Courtier-Dutton 313*be0b7b01SJames Courtier-Dutton 314e4a3d145STakashi Iwai static int snd_ca0106_spdif_info(struct snd_kcontrol *kcontrol, 315e4a3d145STakashi Iwai struct snd_ctl_elem_info *uinfo) 3161da177e4SLinus Torvalds { 3171da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 3181da177e4SLinus Torvalds uinfo->count = 1; 3191da177e4SLinus Torvalds return 0; 3201da177e4SLinus Torvalds } 3211da177e4SLinus Torvalds 322e4a3d145STakashi Iwai static int snd_ca0106_spdif_get(struct snd_kcontrol *kcontrol, 323e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3241da177e4SLinus Torvalds { 325e4a3d145STakashi Iwai struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 3261da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; 3291da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; 3301da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff; 3311da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff; 3321da177e4SLinus Torvalds return 0; 3331da177e4SLinus Torvalds } 3341da177e4SLinus Torvalds 335e4a3d145STakashi Iwai static int snd_ca0106_spdif_get_mask(struct snd_kcontrol *kcontrol, 336e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3371da177e4SLinus Torvalds { 3381da177e4SLinus Torvalds ucontrol->value.iec958.status[0] = 0xff; 3391da177e4SLinus Torvalds ucontrol->value.iec958.status[1] = 0xff; 3401da177e4SLinus Torvalds ucontrol->value.iec958.status[2] = 0xff; 3411da177e4SLinus Torvalds ucontrol->value.iec958.status[3] = 0xff; 3421da177e4SLinus Torvalds return 0; 3431da177e4SLinus Torvalds } 3441da177e4SLinus Torvalds 345e4a3d145STakashi Iwai static int snd_ca0106_spdif_put(struct snd_kcontrol *kcontrol, 346e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3471da177e4SLinus Torvalds { 348e4a3d145STakashi Iwai struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 3491da177e4SLinus Torvalds unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 3501da177e4SLinus Torvalds int change; 3511da177e4SLinus Torvalds unsigned int val; 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds val = (ucontrol->value.iec958.status[0] << 0) | 3541da177e4SLinus Torvalds (ucontrol->value.iec958.status[1] << 8) | 3551da177e4SLinus Torvalds (ucontrol->value.iec958.status[2] << 16) | 3561da177e4SLinus Torvalds (ucontrol->value.iec958.status[3] << 24); 3571da177e4SLinus Torvalds change = val != emu->spdif_bits[idx]; 3581da177e4SLinus Torvalds if (change) { 3591da177e4SLinus Torvalds snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, val); 3601da177e4SLinus Torvalds emu->spdif_bits[idx] = val; 3611da177e4SLinus Torvalds } 3621da177e4SLinus Torvalds return change; 3631da177e4SLinus Torvalds } 3641da177e4SLinus Torvalds 365e4a3d145STakashi Iwai static int snd_ca0106_volume_info(struct snd_kcontrol *kcontrol, 366e4a3d145STakashi Iwai struct snd_ctl_elem_info *uinfo) 3671da177e4SLinus Torvalds { 3681da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 3691da177e4SLinus Torvalds uinfo->count = 2; 3701da177e4SLinus Torvalds uinfo->value.integer.min = 0; 3711da177e4SLinus Torvalds uinfo->value.integer.max = 255; 3721da177e4SLinus Torvalds return 0; 3731da177e4SLinus Torvalds } 3741da177e4SLinus Torvalds 375e4a3d145STakashi Iwai static int snd_ca0106_volume_get(struct snd_kcontrol *kcontrol, 376e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3771da177e4SLinus Torvalds { 378e4a3d145STakashi Iwai struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 3791da177e4SLinus Torvalds unsigned int value; 38095a98265STakashi Iwai int channel_id, reg; 38195a98265STakashi Iwai 38295a98265STakashi Iwai channel_id = (kcontrol->private_value >> 8) & 0xff; 38395a98265STakashi Iwai reg = kcontrol->private_value & 0xff; 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds value = snd_ca0106_ptr_read(emu, reg, channel_id); 3861da177e4SLinus Torvalds ucontrol->value.integer.value[0] = 0xff - ((value >> 24) & 0xff); /* Left */ 3871da177e4SLinus Torvalds ucontrol->value.integer.value[1] = 0xff - ((value >> 16) & 0xff); /* Right */ 3881da177e4SLinus Torvalds return 0; 3891da177e4SLinus Torvalds } 3901da177e4SLinus Torvalds 391e4a3d145STakashi Iwai static int snd_ca0106_volume_put(struct snd_kcontrol *kcontrol, 392e4a3d145STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3931da177e4SLinus Torvalds { 394e4a3d145STakashi Iwai struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 39595a98265STakashi Iwai unsigned int oval, nval; 39695a98265STakashi Iwai int channel_id, reg; 39795a98265STakashi Iwai 39895a98265STakashi Iwai channel_id = (kcontrol->private_value >> 8) & 0xff; 39995a98265STakashi Iwai reg = kcontrol->private_value & 0xff; 40095a98265STakashi Iwai 40195a98265STakashi Iwai oval = snd_ca0106_ptr_read(emu, reg, channel_id); 40295a98265STakashi Iwai nval = ((0xff - ucontrol->value.integer.value[0]) << 24) | 40395a98265STakashi Iwai ((0xff - ucontrol->value.integer.value[1]) << 16); 40495a98265STakashi Iwai nval |= ((0xff - ucontrol->value.integer.value[0]) << 8) | 40595a98265STakashi Iwai ((0xff - ucontrol->value.integer.value[1]) ); 40695a98265STakashi Iwai if (oval == nval) 40795a98265STakashi Iwai return 0; 40895a98265STakashi Iwai snd_ca0106_ptr_write(emu, reg, channel_id, nval); 4091da177e4SLinus Torvalds return 1; 4101da177e4SLinus Torvalds } 41195a98265STakashi Iwai 4126129daaaSJames Courtier-Dutton static int snd_ca0106_i2c_volume_info(struct snd_kcontrol *kcontrol, 4136129daaaSJames Courtier-Dutton struct snd_ctl_elem_info *uinfo) 4146129daaaSJames Courtier-Dutton { 4156129daaaSJames Courtier-Dutton uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 4166129daaaSJames Courtier-Dutton uinfo->count = 2; 4176129daaaSJames Courtier-Dutton uinfo->value.integer.min = 0; 4186129daaaSJames Courtier-Dutton uinfo->value.integer.max = 255; 4196129daaaSJames Courtier-Dutton return 0; 4206129daaaSJames Courtier-Dutton } 4216129daaaSJames Courtier-Dutton 4226129daaaSJames Courtier-Dutton static int snd_ca0106_i2c_volume_get(struct snd_kcontrol *kcontrol, 4236129daaaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 4246129daaaSJames Courtier-Dutton { 4256129daaaSJames Courtier-Dutton struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 4266129daaaSJames Courtier-Dutton int source_id; 4276129daaaSJames Courtier-Dutton 4286129daaaSJames Courtier-Dutton source_id = kcontrol->private_value; 4296129daaaSJames Courtier-Dutton 4306129daaaSJames Courtier-Dutton ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0]; 4316129daaaSJames Courtier-Dutton ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1]; 4326129daaaSJames Courtier-Dutton return 0; 4336129daaaSJames Courtier-Dutton } 4346129daaaSJames Courtier-Dutton 4356129daaaSJames Courtier-Dutton static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol, 4366129daaaSJames Courtier-Dutton struct snd_ctl_elem_value *ucontrol) 4376129daaaSJames Courtier-Dutton { 4386129daaaSJames Courtier-Dutton struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 4396129daaaSJames Courtier-Dutton unsigned int ogain; 4406129daaaSJames Courtier-Dutton unsigned int ngain; 4416129daaaSJames Courtier-Dutton int source_id; 4426129daaaSJames Courtier-Dutton int change = 0; 4436129daaaSJames Courtier-Dutton 4446129daaaSJames Courtier-Dutton source_id = kcontrol->private_value; 4456129daaaSJames Courtier-Dutton ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ 4466129daaaSJames Courtier-Dutton ngain = ucontrol->value.integer.value[0]; 4476129daaaSJames Courtier-Dutton if (ngain > 0xff) 4486129daaaSJames Courtier-Dutton return 0; 4496129daaaSJames Courtier-Dutton if (ogain != ngain) { 4506129daaaSJames Courtier-Dutton if (emu->i2c_capture_source == source_id) 4516129daaaSJames Courtier-Dutton snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) ); 4526129daaaSJames Courtier-Dutton emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0]; 4536129daaaSJames Courtier-Dutton change = 1; 4546129daaaSJames Courtier-Dutton } 4556129daaaSJames Courtier-Dutton ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ 4566129daaaSJames Courtier-Dutton ngain = ucontrol->value.integer.value[1]; 4576129daaaSJames Courtier-Dutton if (ngain > 0xff) 4586129daaaSJames Courtier-Dutton return 0; 4596129daaaSJames Courtier-Dutton if (ogain != ngain) { 4606129daaaSJames Courtier-Dutton if (emu->i2c_capture_source == source_id) 4616129daaaSJames Courtier-Dutton snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); 4626129daaaSJames Courtier-Dutton emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1]; 4636129daaaSJames Courtier-Dutton change = 1; 4646129daaaSJames Courtier-Dutton } 4656129daaaSJames Courtier-Dutton 4666129daaaSJames Courtier-Dutton return change; 4676129daaaSJames Courtier-Dutton } 4686129daaaSJames Courtier-Dutton 46995a98265STakashi Iwai #define CA_VOLUME(xname,chid,reg) \ 47095a98265STakashi Iwai { \ 47195a98265STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 47295a98265STakashi Iwai .info = snd_ca0106_volume_info, \ 47395a98265STakashi Iwai .get = snd_ca0106_volume_get, \ 47495a98265STakashi Iwai .put = snd_ca0106_volume_put, \ 47595a98265STakashi Iwai .private_value = ((chid) << 8) | (reg) \ 4761da177e4SLinus Torvalds } 4771da177e4SLinus Torvalds 4786129daaaSJames Courtier-Dutton #define I2C_VOLUME(xname,chid) \ 4796129daaaSJames Courtier-Dutton { \ 4806129daaaSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 4816129daaaSJames Courtier-Dutton .info = snd_ca0106_i2c_volume_info, \ 4826129daaaSJames Courtier-Dutton .get = snd_ca0106_i2c_volume_get, \ 4836129daaaSJames Courtier-Dutton .put = snd_ca0106_i2c_volume_put, \ 4846129daaaSJames Courtier-Dutton .private_value = chid \ 4856129daaaSJames Courtier-Dutton } 4866129daaaSJames Courtier-Dutton 4871da177e4SLinus Torvalds 488e4a3d145STakashi Iwai static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { 48995a98265STakashi Iwai CA_VOLUME("Analog Front Playback Volume", 49095a98265STakashi Iwai CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2), 49195a98265STakashi Iwai CA_VOLUME("Analog Rear Playback Volume", 49295a98265STakashi Iwai CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME2), 49395a98265STakashi Iwai CA_VOLUME("Analog Center/LFE Playback Volume", 49495a98265STakashi Iwai CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME2), 49595a98265STakashi Iwai CA_VOLUME("Analog Side Playback Volume", 49695a98265STakashi Iwai CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME2), 49795a98265STakashi Iwai 49839596dc8SJames Courtier-Dutton CA_VOLUME("IEC958 Front Playback Volume", 49995a98265STakashi Iwai CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME1), 50039596dc8SJames Courtier-Dutton CA_VOLUME("IEC958 Rear Playback Volume", 50195a98265STakashi Iwai CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME1), 50239596dc8SJames Courtier-Dutton CA_VOLUME("IEC958 Center/LFE Playback Volume", 50395a98265STakashi Iwai CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME1), 50439596dc8SJames Courtier-Dutton CA_VOLUME("IEC958 Unknown Playback Volume", 50595a98265STakashi Iwai CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME1), 50695a98265STakashi Iwai 50795a98265STakashi Iwai CA_VOLUME("CAPTURE feedback Playback Volume", 50895a98265STakashi Iwai 1, CAPTURE_CONTROL), 50995a98265STakashi Iwai 5106129daaaSJames Courtier-Dutton I2C_VOLUME("Phone Capture Volume", 0), 5116129daaaSJames Courtier-Dutton I2C_VOLUME("Mic Capture Volume", 1), 5126129daaaSJames Courtier-Dutton I2C_VOLUME("Line in Capture Volume", 2), 5136129daaaSJames Courtier-Dutton I2C_VOLUME("Aux Capture Volume", 3), 5146129daaaSJames Courtier-Dutton 51595a98265STakashi Iwai { 51695a98265STakashi Iwai .access = SNDRV_CTL_ELEM_ACCESS_READ, 51795a98265STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_PCM, 51895a98265STakashi Iwai .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), 51995a98265STakashi Iwai .count = 4, 52095a98265STakashi Iwai .info = snd_ca0106_spdif_info, 52195a98265STakashi Iwai .get = snd_ca0106_spdif_get_mask 52295a98265STakashi Iwai }, 5231da177e4SLinus Torvalds { 5241da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 52539596dc8SJames Courtier-Dutton .name = "IEC958 Playback Switch", 52695a98265STakashi Iwai .info = snd_ca0106_shared_spdif_info, 52795a98265STakashi Iwai .get = snd_ca0106_shared_spdif_get, 52895a98265STakashi Iwai .put = snd_ca0106_shared_spdif_put 52995a98265STakashi Iwai }, 5301da177e4SLinus Torvalds { 5311da177e4SLinus Torvalds .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5326129daaaSJames Courtier-Dutton .name = "Digital Capture Source", 53395a98265STakashi Iwai .info = snd_ca0106_capture_source_info, 53495a98265STakashi Iwai .get = snd_ca0106_capture_source_get, 53595a98265STakashi Iwai .put = snd_ca0106_capture_source_put 53695a98265STakashi Iwai }, 5371da177e4SLinus Torvalds { 5386129daaaSJames Courtier-Dutton .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5396129daaaSJames Courtier-Dutton .name = "Capture Source", 5406129daaaSJames Courtier-Dutton .info = snd_ca0106_i2c_capture_source_info, 5416129daaaSJames Courtier-Dutton .get = snd_ca0106_i2c_capture_source_get, 5426129daaaSJames Courtier-Dutton .put = snd_ca0106_i2c_capture_source_put 5436129daaaSJames Courtier-Dutton }, 5446129daaaSJames Courtier-Dutton { 54595a98265STakashi Iwai .iface = SNDRV_CTL_ELEM_IFACE_PCM, 54695a98265STakashi Iwai .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 54795a98265STakashi Iwai .count = 4, 54895a98265STakashi Iwai .info = snd_ca0106_spdif_info, 54995a98265STakashi Iwai .get = snd_ca0106_spdif_get, 55095a98265STakashi Iwai .put = snd_ca0106_spdif_put 55195a98265STakashi Iwai }, 5521da177e4SLinus Torvalds }; 5531da177e4SLinus Torvalds 554e4a3d145STakashi Iwai static int __devinit remove_ctl(struct snd_card *card, const char *name) 5551da177e4SLinus Torvalds { 556e4a3d145STakashi Iwai struct snd_ctl_elem_id id; 5571da177e4SLinus Torvalds memset(&id, 0, sizeof(id)); 5581da177e4SLinus Torvalds strcpy(id.name, name); 5591da177e4SLinus Torvalds id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 5601da177e4SLinus Torvalds return snd_ctl_remove_id(card, &id); 5611da177e4SLinus Torvalds } 5621da177e4SLinus Torvalds 563e4a3d145STakashi Iwai static struct snd_kcontrol __devinit *ctl_find(struct snd_card *card, const char *name) 5641da177e4SLinus Torvalds { 565e4a3d145STakashi Iwai struct snd_ctl_elem_id sid; 5661da177e4SLinus Torvalds memset(&sid, 0, sizeof(sid)); 5671da177e4SLinus Torvalds /* FIXME: strcpy is bad. */ 5681da177e4SLinus Torvalds strcpy(sid.name, name); 5691da177e4SLinus Torvalds sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 5701da177e4SLinus Torvalds return snd_ctl_find_id(card, &sid); 5711da177e4SLinus Torvalds } 5721da177e4SLinus Torvalds 573e4a3d145STakashi Iwai static int __devinit rename_ctl(struct snd_card *card, const char *src, const char *dst) 5741da177e4SLinus Torvalds { 575e4a3d145STakashi Iwai struct snd_kcontrol *kctl = ctl_find(card, src); 5761da177e4SLinus Torvalds if (kctl) { 5771da177e4SLinus Torvalds strcpy(kctl->id.name, dst); 5781da177e4SLinus Torvalds return 0; 5791da177e4SLinus Torvalds } 5801da177e4SLinus Torvalds return -ENOENT; 5811da177e4SLinus Torvalds } 5821da177e4SLinus Torvalds 583e4a3d145STakashi Iwai int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) 5841da177e4SLinus Torvalds { 58595a98265STakashi Iwai int i, err; 586e4a3d145STakashi Iwai struct snd_card *card = emu->card; 5871da177e4SLinus Torvalds char **c; 5881da177e4SLinus Torvalds static char *ca0106_remove_ctls[] = { 5891da177e4SLinus Torvalds "Master Mono Playback Switch", 5901da177e4SLinus Torvalds "Master Mono Playback Volume", 5911da177e4SLinus Torvalds "3D Control - Switch", 5921da177e4SLinus Torvalds "3D Control Sigmatel - Depth", 5931da177e4SLinus Torvalds "PCM Playback Switch", 5941da177e4SLinus Torvalds "PCM Playback Volume", 5951da177e4SLinus Torvalds "CD Playback Switch", 5961da177e4SLinus Torvalds "CD Playback Volume", 5971da177e4SLinus Torvalds "Phone Playback Switch", 5981da177e4SLinus Torvalds "Phone Playback Volume", 5991da177e4SLinus Torvalds "Video Playback Switch", 6001da177e4SLinus Torvalds "Video Playback Volume", 6011da177e4SLinus Torvalds "PC Speaker Playback Switch", 6021da177e4SLinus Torvalds "PC Speaker Playback Volume", 6031da177e4SLinus Torvalds "Mono Output Select", 6041da177e4SLinus Torvalds "Capture Source", 6051da177e4SLinus Torvalds "Capture Switch", 6061da177e4SLinus Torvalds "Capture Volume", 6071da177e4SLinus Torvalds "External Amplifier", 6081da177e4SLinus Torvalds "Sigmatel 4-Speaker Stereo Playback Switch", 6091da177e4SLinus Torvalds "Sigmatel Surround Phase Inversion Playback ", 6101da177e4SLinus Torvalds NULL 6111da177e4SLinus Torvalds }; 6121da177e4SLinus Torvalds static char *ca0106_rename_ctls[] = { 6131da177e4SLinus Torvalds "Master Playback Switch", "Capture Switch", 6141da177e4SLinus Torvalds "Master Playback Volume", "Capture Volume", 6151da177e4SLinus Torvalds "Line Playback Switch", "AC97 Line Capture Switch", 6161da177e4SLinus Torvalds "Line Playback Volume", "AC97 Line Capture Volume", 6171da177e4SLinus Torvalds "Aux Playback Switch", "AC97 Aux Capture Switch", 6181da177e4SLinus Torvalds "Aux Playback Volume", "AC97 Aux Capture Volume", 6191da177e4SLinus Torvalds "Mic Playback Switch", "AC97 Mic Capture Switch", 6201da177e4SLinus Torvalds "Mic Playback Volume", "AC97 Mic Capture Volume", 6211da177e4SLinus Torvalds "Mic Select", "AC97 Mic Select", 6221da177e4SLinus Torvalds "Mic Boost (+20dB)", "AC97 Mic Boost (+20dB)", 6231da177e4SLinus Torvalds NULL 6241da177e4SLinus Torvalds }; 6251da177e4SLinus Torvalds #if 1 6261da177e4SLinus Torvalds for (c = ca0106_remove_ctls; *c; c++) 6271da177e4SLinus Torvalds remove_ctl(card, *c); 6281da177e4SLinus Torvalds for (c = ca0106_rename_ctls; *c; c += 2) 6291da177e4SLinus Torvalds rename_ctl(card, c[0], c[1]); 6301da177e4SLinus Torvalds #endif 6311da177e4SLinus Torvalds 63295a98265STakashi Iwai for (i = 0; i < ARRAY_SIZE(snd_ca0106_volume_ctls); i++) { 63395a98265STakashi Iwai err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_volume_ctls[i], emu)); 63495a98265STakashi Iwai if (err < 0) 635ed144f3cSJames Courtier-Dutton return err; 636ed144f3cSJames Courtier-Dutton } 63795a98265STakashi Iwai if (emu->details->i2c_adc == 1) { 638*be0b7b01SJames Courtier-Dutton if (emu->details->gpio_type == 1) 63995a98265STakashi Iwai err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu)); 640*be0b7b01SJames Courtier-Dutton else /* gpio_type == 2 */ 641*be0b7b01SJames Courtier-Dutton err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_line_in_side_out, emu)); 64295a98265STakashi Iwai if (err < 0) 6431da177e4SLinus Torvalds return err; 64495a98265STakashi Iwai } 6451da177e4SLinus Torvalds return 0; 6461da177e4SLinus Torvalds } 6471da177e4SLinus Torvalds 648