18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> 48c2ecf20Sopenharmony_ci * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit 58c2ecf20Sopenharmony_ci * Version: 0.0.18 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * FEATURES currently supported: 88c2ecf20Sopenharmony_ci * See ca0106_main.c for features. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Changelog: 118c2ecf20Sopenharmony_ci * Support interrupts per period. 128c2ecf20Sopenharmony_ci * Removed noise from Center/LFE channel when in Analog mode. 138c2ecf20Sopenharmony_ci * Rename and remove mixer controls. 148c2ecf20Sopenharmony_ci * 0.0.6 158c2ecf20Sopenharmony_ci * Use separate card based DMA buffer for periods table list. 168c2ecf20Sopenharmony_ci * 0.0.7 178c2ecf20Sopenharmony_ci * Change remove and rename ctrls into lists. 188c2ecf20Sopenharmony_ci * 0.0.8 198c2ecf20Sopenharmony_ci * Try to fix capture sources. 208c2ecf20Sopenharmony_ci * 0.0.9 218c2ecf20Sopenharmony_ci * Fix AC3 output. 228c2ecf20Sopenharmony_ci * Enable S32_LE format support. 238c2ecf20Sopenharmony_ci * 0.0.10 248c2ecf20Sopenharmony_ci * Enable playback 48000 and 96000 rates. (Rates other that these do not work, even with "plug:front".) 258c2ecf20Sopenharmony_ci * 0.0.11 268c2ecf20Sopenharmony_ci * Add Model name recognition. 278c2ecf20Sopenharmony_ci * 0.0.12 288c2ecf20Sopenharmony_ci * Correct interrupt timing. interrupt at end of period, instead of in the middle of a playback period. 298c2ecf20Sopenharmony_ci * Remove redundent "voice" handling. 308c2ecf20Sopenharmony_ci * 0.0.13 318c2ecf20Sopenharmony_ci * Single trigger call for multi channels. 328c2ecf20Sopenharmony_ci * 0.0.14 338c2ecf20Sopenharmony_ci * Set limits based on what the sound card hardware can do. 348c2ecf20Sopenharmony_ci * playback periods_min=2, periods_max=8 358c2ecf20Sopenharmony_ci * capture hw constraints require period_size = n * 64 bytes. 368c2ecf20Sopenharmony_ci * playback hw constraints require period_size = n * 64 bytes. 378c2ecf20Sopenharmony_ci * 0.0.15 388c2ecf20Sopenharmony_ci * Separated ca0106.c into separate functional .c files. 398c2ecf20Sopenharmony_ci * 0.0.16 408c2ecf20Sopenharmony_ci * Modified Copyright message. 418c2ecf20Sopenharmony_ci * 0.0.17 428c2ecf20Sopenharmony_ci * Implement Mic and Line in Capture. 438c2ecf20Sopenharmony_ci * 0.0.18 448c2ecf20Sopenharmony_ci * Add support for mute control on SB Live 24bit (cards w/ SPI DAC) 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci * This code was initially based on code from ALSA's emu10k1x.c which is: 478c2ecf20Sopenharmony_ci * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_ci#include <linux/delay.h> 508c2ecf20Sopenharmony_ci#include <linux/init.h> 518c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 528c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 538c2ecf20Sopenharmony_ci#include <sound/core.h> 548c2ecf20Sopenharmony_ci#include <sound/initval.h> 558c2ecf20Sopenharmony_ci#include <sound/pcm.h> 568c2ecf20Sopenharmony_ci#include <sound/ac97_codec.h> 578c2ecf20Sopenharmony_ci#include <sound/info.h> 588c2ecf20Sopenharmony_ci#include <sound/tlv.h> 598c2ecf20Sopenharmony_ci#include <linux/io.h> 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#include "ca0106.h" 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic void ca0106_spdif_enable(struct snd_ca0106 *emu) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci unsigned int val; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (emu->spdif_enable) { 688c2ecf20Sopenharmony_ci /* Digital */ 698c2ecf20Sopenharmony_ci snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); 708c2ecf20Sopenharmony_ci snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000); 718c2ecf20Sopenharmony_ci val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000; 728c2ecf20Sopenharmony_ci snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val); 738c2ecf20Sopenharmony_ci val = inl(emu->port + GPIO) & ~0x101; 748c2ecf20Sopenharmony_ci outl(val, emu->port + GPIO); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci } else { 778c2ecf20Sopenharmony_ci /* Analog */ 788c2ecf20Sopenharmony_ci snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf); 798c2ecf20Sopenharmony_ci snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000); 808c2ecf20Sopenharmony_ci val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000; 818c2ecf20Sopenharmony_ci snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val); 828c2ecf20Sopenharmony_ci val = inl(emu->port + GPIO) | 0x101; 838c2ecf20Sopenharmony_ci outl(val, emu->port + GPIO); 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic void ca0106_set_capture_source(struct snd_ca0106 *emu) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci unsigned int val = emu->capture_source; 908c2ecf20Sopenharmony_ci unsigned int source, mask; 918c2ecf20Sopenharmony_ci source = (val << 28) | (val << 24) | (val << 20) | (val << 16); 928c2ecf20Sopenharmony_ci mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff; 938c2ecf20Sopenharmony_ci snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask); 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic void ca0106_set_i2c_capture_source(struct snd_ca0106 *emu, 978c2ecf20Sopenharmony_ci unsigned int val, int force) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci unsigned int ngain, ogain; 1008c2ecf20Sopenharmony_ci u32 source; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ 1038c2ecf20Sopenharmony_ci ngain = emu->i2c_capture_volume[val][0]; /* Left */ 1048c2ecf20Sopenharmony_ci ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ 1058c2ecf20Sopenharmony_ci if (force || ngain != ogain) 1068c2ecf20Sopenharmony_ci snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ngain & 0xff); 1078c2ecf20Sopenharmony_ci ngain = emu->i2c_capture_volume[val][1]; /* Right */ 1088c2ecf20Sopenharmony_ci ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */ 1098c2ecf20Sopenharmony_ci if (force || ngain != ogain) 1108c2ecf20Sopenharmony_ci snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ngain & 0xff); 1118c2ecf20Sopenharmony_ci source = 1 << val; 1128c2ecf20Sopenharmony_ci snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */ 1138c2ecf20Sopenharmony_ci emu->i2c_capture_source = val; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic void ca0106_set_capture_mic_line_in(struct snd_ca0106 *emu) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci u32 tmp; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (emu->capture_mic_line_in) { 1218c2ecf20Sopenharmony_ci /* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */ 1228c2ecf20Sopenharmony_ci tmp = inl(emu->port+GPIO) & ~0x400; 1238c2ecf20Sopenharmony_ci tmp = tmp | 0x400; 1248c2ecf20Sopenharmony_ci outl(tmp, emu->port+GPIO); 1258c2ecf20Sopenharmony_ci /* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); */ 1268c2ecf20Sopenharmony_ci } else { 1278c2ecf20Sopenharmony_ci /* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */ 1288c2ecf20Sopenharmony_ci tmp = inl(emu->port+GPIO) & ~0x400; 1298c2ecf20Sopenharmony_ci outl(tmp, emu->port+GPIO); 1308c2ecf20Sopenharmony_ci /* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); */ 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic void ca0106_set_spdif_bits(struct snd_ca0106 *emu, int idx) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, emu->spdif_str_bits[idx]); 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/* 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1); 1428c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci#define snd_ca0106_shared_spdif_info snd_ctl_boolean_mono_info 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic int snd_ca0106_shared_spdif_get(struct snd_kcontrol *kcontrol, 1478c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = emu->spdif_enable; 1528c2ecf20Sopenharmony_ci return 0; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic int snd_ca0106_shared_spdif_put(struct snd_kcontrol *kcontrol, 1568c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 1598c2ecf20Sopenharmony_ci unsigned int val; 1608c2ecf20Sopenharmony_ci int change = 0; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci val = !!ucontrol->value.integer.value[0]; 1638c2ecf20Sopenharmony_ci change = (emu->spdif_enable != val); 1648c2ecf20Sopenharmony_ci if (change) { 1658c2ecf20Sopenharmony_ci emu->spdif_enable = val; 1668c2ecf20Sopenharmony_ci ca0106_spdif_enable(emu); 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci return change; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic int snd_ca0106_capture_source_info(struct snd_kcontrol *kcontrol, 1728c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci static const char * const texts[6] = { 1758c2ecf20Sopenharmony_ci "IEC958 out", "i2s mixer out", "IEC958 in", "i2s in", "AC97 in", "SRC out" 1768c2ecf20Sopenharmony_ci }; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 6, texts); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic int snd_ca0106_capture_source_get(struct snd_kcontrol *kcontrol, 1828c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = emu->capture_source; 1878c2ecf20Sopenharmony_ci return 0; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol, 1918c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 1948c2ecf20Sopenharmony_ci unsigned int val; 1958c2ecf20Sopenharmony_ci int change = 0; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci val = ucontrol->value.enumerated.item[0] ; 1988c2ecf20Sopenharmony_ci if (val >= 6) 1998c2ecf20Sopenharmony_ci return -EINVAL; 2008c2ecf20Sopenharmony_ci change = (emu->capture_source != val); 2018c2ecf20Sopenharmony_ci if (change) { 2028c2ecf20Sopenharmony_ci emu->capture_source = val; 2038c2ecf20Sopenharmony_ci ca0106_set_capture_source(emu); 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci return change; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic int snd_ca0106_i2c_capture_source_info(struct snd_kcontrol *kcontrol, 2098c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci static const char * const texts[4] = { 2128c2ecf20Sopenharmony_ci "Phone", "Mic", "Line in", "Aux" 2138c2ecf20Sopenharmony_ci }; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 4, texts); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic int snd_ca0106_i2c_capture_source_get(struct snd_kcontrol *kcontrol, 2198c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = emu->i2c_capture_source; 2248c2ecf20Sopenharmony_ci return 0; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol, 2288c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 2318c2ecf20Sopenharmony_ci unsigned int source_id; 2328c2ecf20Sopenharmony_ci int change = 0; 2338c2ecf20Sopenharmony_ci /* If the capture source has changed, 2348c2ecf20Sopenharmony_ci * update the capture volume from the cached value 2358c2ecf20Sopenharmony_ci * for the particular source. 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_ci source_id = ucontrol->value.enumerated.item[0] ; 2388c2ecf20Sopenharmony_ci if (source_id >= 4) 2398c2ecf20Sopenharmony_ci return -EINVAL; 2408c2ecf20Sopenharmony_ci change = (emu->i2c_capture_source != source_id); 2418c2ecf20Sopenharmony_ci if (change) { 2428c2ecf20Sopenharmony_ci ca0106_set_i2c_capture_source(emu, source_id, 0); 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci return change; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic int snd_ca0106_capture_line_in_side_out_info(struct snd_kcontrol *kcontrol, 2488c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci static const char * const texts[2] = { "Side out", "Line in" }; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, texts); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic int snd_ca0106_capture_mic_line_in_info(struct snd_kcontrol *kcontrol, 2568c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci static const char * const texts[2] = { "Line in", "Mic in" }; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, texts); 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic int snd_ca0106_capture_mic_line_in_get(struct snd_kcontrol *kcontrol, 2648c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = emu->capture_mic_line_in; 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol, 2738c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 2768c2ecf20Sopenharmony_ci unsigned int val; 2778c2ecf20Sopenharmony_ci int change = 0; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci val = ucontrol->value.enumerated.item[0] ; 2808c2ecf20Sopenharmony_ci if (val > 1) 2818c2ecf20Sopenharmony_ci return -EINVAL; 2828c2ecf20Sopenharmony_ci change = (emu->capture_mic_line_in != val); 2838c2ecf20Sopenharmony_ci if (change) { 2848c2ecf20Sopenharmony_ci emu->capture_mic_line_in = val; 2858c2ecf20Sopenharmony_ci ca0106_set_capture_mic_line_in(emu); 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci return change; 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_ca0106_capture_mic_line_in = 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2938c2ecf20Sopenharmony_ci .name = "Shared Mic/Line in Capture Switch", 2948c2ecf20Sopenharmony_ci .info = snd_ca0106_capture_mic_line_in_info, 2958c2ecf20Sopenharmony_ci .get = snd_ca0106_capture_mic_line_in_get, 2968c2ecf20Sopenharmony_ci .put = snd_ca0106_capture_mic_line_in_put 2978c2ecf20Sopenharmony_ci}; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_ca0106_capture_line_in_side_out = 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3028c2ecf20Sopenharmony_ci .name = "Shared Line in/Side out Capture Switch", 3038c2ecf20Sopenharmony_ci .info = snd_ca0106_capture_line_in_side_out_info, 3048c2ecf20Sopenharmony_ci .get = snd_ca0106_capture_mic_line_in_get, 3058c2ecf20Sopenharmony_ci .put = snd_ca0106_capture_mic_line_in_put 3068c2ecf20Sopenharmony_ci}; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic int snd_ca0106_spdif_info(struct snd_kcontrol *kcontrol, 3108c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 3138c2ecf20Sopenharmony_ci uinfo->count = 1; 3148c2ecf20Sopenharmony_ci return 0; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic void decode_spdif_bits(unsigned char *status, unsigned int bits) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci status[0] = (bits >> 0) & 0xff; 3208c2ecf20Sopenharmony_ci status[1] = (bits >> 8) & 0xff; 3218c2ecf20Sopenharmony_ci status[2] = (bits >> 16) & 0xff; 3228c2ecf20Sopenharmony_ci status[3] = (bits >> 24) & 0xff; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic int snd_ca0106_spdif_get_default(struct snd_kcontrol *kcontrol, 3268c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 3298c2ecf20Sopenharmony_ci unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci decode_spdif_bits(ucontrol->value.iec958.status, 3328c2ecf20Sopenharmony_ci emu->spdif_bits[idx]); 3338c2ecf20Sopenharmony_ci return 0; 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic int snd_ca0106_spdif_get_stream(struct snd_kcontrol *kcontrol, 3378c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 3408c2ecf20Sopenharmony_ci unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci decode_spdif_bits(ucontrol->value.iec958.status, 3438c2ecf20Sopenharmony_ci emu->spdif_str_bits[idx]); 3448c2ecf20Sopenharmony_ci return 0; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic int snd_ca0106_spdif_get_mask(struct snd_kcontrol *kcontrol, 3488c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[0] = 0xff; 3518c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[1] = 0xff; 3528c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[2] = 0xff; 3538c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[3] = 0xff; 3548c2ecf20Sopenharmony_ci return 0; 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic unsigned int encode_spdif_bits(unsigned char *status) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci return ((unsigned int)status[0] << 0) | 3608c2ecf20Sopenharmony_ci ((unsigned int)status[1] << 8) | 3618c2ecf20Sopenharmony_ci ((unsigned int)status[2] << 16) | 3628c2ecf20Sopenharmony_ci ((unsigned int)status[3] << 24); 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic int snd_ca0106_spdif_put_default(struct snd_kcontrol *kcontrol, 3668c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 3698c2ecf20Sopenharmony_ci unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 3708c2ecf20Sopenharmony_ci unsigned int val; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci val = encode_spdif_bits(ucontrol->value.iec958.status); 3738c2ecf20Sopenharmony_ci if (val != emu->spdif_bits[idx]) { 3748c2ecf20Sopenharmony_ci emu->spdif_bits[idx] = val; 3758c2ecf20Sopenharmony_ci /* FIXME: this isn't safe, but needed to keep the compatibility 3768c2ecf20Sopenharmony_ci * with older alsa-lib config 3778c2ecf20Sopenharmony_ci */ 3788c2ecf20Sopenharmony_ci emu->spdif_str_bits[idx] = val; 3798c2ecf20Sopenharmony_ci ca0106_set_spdif_bits(emu, idx); 3808c2ecf20Sopenharmony_ci return 1; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci return 0; 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic int snd_ca0106_spdif_put_stream(struct snd_kcontrol *kcontrol, 3868c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 3898c2ecf20Sopenharmony_ci unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 3908c2ecf20Sopenharmony_ci unsigned int val; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci val = encode_spdif_bits(ucontrol->value.iec958.status); 3938c2ecf20Sopenharmony_ci if (val != emu->spdif_str_bits[idx]) { 3948c2ecf20Sopenharmony_ci emu->spdif_str_bits[idx] = val; 3958c2ecf20Sopenharmony_ci ca0106_set_spdif_bits(emu, idx); 3968c2ecf20Sopenharmony_ci return 1; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci return 0; 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic int snd_ca0106_volume_info(struct snd_kcontrol *kcontrol, 4028c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 4058c2ecf20Sopenharmony_ci uinfo->count = 2; 4068c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 4078c2ecf20Sopenharmony_ci uinfo->value.integer.max = 255; 4088c2ecf20Sopenharmony_ci return 0; 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic int snd_ca0106_volume_get(struct snd_kcontrol *kcontrol, 4128c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 4158c2ecf20Sopenharmony_ci unsigned int value; 4168c2ecf20Sopenharmony_ci int channel_id, reg; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci channel_id = (kcontrol->private_value >> 8) & 0xff; 4198c2ecf20Sopenharmony_ci reg = kcontrol->private_value & 0xff; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci value = snd_ca0106_ptr_read(emu, reg, channel_id); 4228c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 0xff - ((value >> 24) & 0xff); /* Left */ 4238c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = 0xff - ((value >> 16) & 0xff); /* Right */ 4248c2ecf20Sopenharmony_ci return 0; 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic int snd_ca0106_volume_put(struct snd_kcontrol *kcontrol, 4288c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 4318c2ecf20Sopenharmony_ci unsigned int oval, nval; 4328c2ecf20Sopenharmony_ci int channel_id, reg; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci channel_id = (kcontrol->private_value >> 8) & 0xff; 4358c2ecf20Sopenharmony_ci reg = kcontrol->private_value & 0xff; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci oval = snd_ca0106_ptr_read(emu, reg, channel_id); 4388c2ecf20Sopenharmony_ci nval = ((0xff - ucontrol->value.integer.value[0]) << 24) | 4398c2ecf20Sopenharmony_ci ((0xff - ucontrol->value.integer.value[1]) << 16); 4408c2ecf20Sopenharmony_ci nval |= ((0xff - ucontrol->value.integer.value[0]) << 8) | 4418c2ecf20Sopenharmony_ci ((0xff - ucontrol->value.integer.value[1]) ); 4428c2ecf20Sopenharmony_ci if (oval == nval) 4438c2ecf20Sopenharmony_ci return 0; 4448c2ecf20Sopenharmony_ci snd_ca0106_ptr_write(emu, reg, channel_id, nval); 4458c2ecf20Sopenharmony_ci return 1; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic int snd_ca0106_i2c_volume_info(struct snd_kcontrol *kcontrol, 4498c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 4528c2ecf20Sopenharmony_ci uinfo->count = 2; 4538c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 4548c2ecf20Sopenharmony_ci uinfo->value.integer.max = 255; 4558c2ecf20Sopenharmony_ci return 0; 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic int snd_ca0106_i2c_volume_get(struct snd_kcontrol *kcontrol, 4598c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 4628c2ecf20Sopenharmony_ci int source_id; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci source_id = kcontrol->private_value; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0]; 4678c2ecf20Sopenharmony_ci ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1]; 4688c2ecf20Sopenharmony_ci return 0; 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol, 4728c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 4758c2ecf20Sopenharmony_ci unsigned int ogain; 4768c2ecf20Sopenharmony_ci unsigned int ngain; 4778c2ecf20Sopenharmony_ci int source_id; 4788c2ecf20Sopenharmony_ci int change = 0; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci source_id = kcontrol->private_value; 4818c2ecf20Sopenharmony_ci ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ 4828c2ecf20Sopenharmony_ci ngain = ucontrol->value.integer.value[0]; 4838c2ecf20Sopenharmony_ci if (ngain > 0xff) 4848c2ecf20Sopenharmony_ci return -EINVAL; 4858c2ecf20Sopenharmony_ci if (ogain != ngain) { 4868c2ecf20Sopenharmony_ci if (emu->i2c_capture_source == source_id) 4878c2ecf20Sopenharmony_ci snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) ); 4888c2ecf20Sopenharmony_ci emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0]; 4898c2ecf20Sopenharmony_ci change = 1; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ 4928c2ecf20Sopenharmony_ci ngain = ucontrol->value.integer.value[1]; 4938c2ecf20Sopenharmony_ci if (ngain > 0xff) 4948c2ecf20Sopenharmony_ci return -EINVAL; 4958c2ecf20Sopenharmony_ci if (ogain != ngain) { 4968c2ecf20Sopenharmony_ci if (emu->i2c_capture_source == source_id) 4978c2ecf20Sopenharmony_ci snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); 4988c2ecf20Sopenharmony_ci emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1]; 4998c2ecf20Sopenharmony_ci change = 1; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci return change; 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci#define spi_mute_info snd_ctl_boolean_mono_info 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic int spi_mute_get(struct snd_kcontrol *kcontrol, 5088c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 5118c2ecf20Sopenharmony_ci unsigned int reg = kcontrol->private_value >> SPI_REG_SHIFT; 5128c2ecf20Sopenharmony_ci unsigned int bit = kcontrol->private_value & SPI_REG_MASK; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = !(emu->spi_dac_reg[reg] & bit); 5158c2ecf20Sopenharmony_ci return 0; 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic int spi_mute_put(struct snd_kcontrol *kcontrol, 5198c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 5228c2ecf20Sopenharmony_ci unsigned int reg = kcontrol->private_value >> SPI_REG_SHIFT; 5238c2ecf20Sopenharmony_ci unsigned int bit = kcontrol->private_value & SPI_REG_MASK; 5248c2ecf20Sopenharmony_ci int ret; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci ret = emu->spi_dac_reg[reg] & bit; 5278c2ecf20Sopenharmony_ci if (ucontrol->value.integer.value[0]) { 5288c2ecf20Sopenharmony_ci if (!ret) /* bit already cleared, do nothing */ 5298c2ecf20Sopenharmony_ci return 0; 5308c2ecf20Sopenharmony_ci emu->spi_dac_reg[reg] &= ~bit; 5318c2ecf20Sopenharmony_ci } else { 5328c2ecf20Sopenharmony_ci if (ret) /* bit already set, do nothing */ 5338c2ecf20Sopenharmony_ci return 0; 5348c2ecf20Sopenharmony_ci emu->spi_dac_reg[reg] |= bit; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci ret = snd_ca0106_spi_write(emu, emu->spi_dac_reg[reg]); 5388c2ecf20Sopenharmony_ci return ret ? -EINVAL : 1; 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci#define CA_VOLUME(xname,chid,reg) \ 5428c2ecf20Sopenharmony_ci{ \ 5438c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 5448c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ 5458c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 5468c2ecf20Sopenharmony_ci .info = snd_ca0106_volume_info, \ 5478c2ecf20Sopenharmony_ci .get = snd_ca0106_volume_get, \ 5488c2ecf20Sopenharmony_ci .put = snd_ca0106_volume_put, \ 5498c2ecf20Sopenharmony_ci .tlv = { .p = snd_ca0106_db_scale1 }, \ 5508c2ecf20Sopenharmony_ci .private_value = ((chid) << 8) | (reg) \ 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_ca0106_volume_ctls[] = { 5548c2ecf20Sopenharmony_ci CA_VOLUME("Analog Front Playback Volume", 5558c2ecf20Sopenharmony_ci CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2), 5568c2ecf20Sopenharmony_ci CA_VOLUME("Analog Rear Playback Volume", 5578c2ecf20Sopenharmony_ci CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME2), 5588c2ecf20Sopenharmony_ci CA_VOLUME("Analog Center/LFE Playback Volume", 5598c2ecf20Sopenharmony_ci CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME2), 5608c2ecf20Sopenharmony_ci CA_VOLUME("Analog Side Playback Volume", 5618c2ecf20Sopenharmony_ci CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME2), 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci CA_VOLUME("IEC958 Front Playback Volume", 5648c2ecf20Sopenharmony_ci CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME1), 5658c2ecf20Sopenharmony_ci CA_VOLUME("IEC958 Rear Playback Volume", 5668c2ecf20Sopenharmony_ci CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME1), 5678c2ecf20Sopenharmony_ci CA_VOLUME("IEC958 Center/LFE Playback Volume", 5688c2ecf20Sopenharmony_ci CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME1), 5698c2ecf20Sopenharmony_ci CA_VOLUME("IEC958 Unknown Playback Volume", 5708c2ecf20Sopenharmony_ci CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME1), 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci CA_VOLUME("CAPTURE feedback Playback Volume", 5738c2ecf20Sopenharmony_ci 1, CAPTURE_CONTROL), 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci { 5768c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 5778c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 5788c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), 5798c2ecf20Sopenharmony_ci .count = 4, 5808c2ecf20Sopenharmony_ci .info = snd_ca0106_spdif_info, 5818c2ecf20Sopenharmony_ci .get = snd_ca0106_spdif_get_mask 5828c2ecf20Sopenharmony_ci }, 5838c2ecf20Sopenharmony_ci { 5848c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5858c2ecf20Sopenharmony_ci .name = "IEC958 Playback Switch", 5868c2ecf20Sopenharmony_ci .info = snd_ca0106_shared_spdif_info, 5878c2ecf20Sopenharmony_ci .get = snd_ca0106_shared_spdif_get, 5888c2ecf20Sopenharmony_ci .put = snd_ca0106_shared_spdif_put 5898c2ecf20Sopenharmony_ci }, 5908c2ecf20Sopenharmony_ci { 5918c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5928c2ecf20Sopenharmony_ci .name = "Digital Source Capture Enum", 5938c2ecf20Sopenharmony_ci .info = snd_ca0106_capture_source_info, 5948c2ecf20Sopenharmony_ci .get = snd_ca0106_capture_source_get, 5958c2ecf20Sopenharmony_ci .put = snd_ca0106_capture_source_put 5968c2ecf20Sopenharmony_ci }, 5978c2ecf20Sopenharmony_ci { 5988c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5998c2ecf20Sopenharmony_ci .name = "Analog Source Capture Enum", 6008c2ecf20Sopenharmony_ci .info = snd_ca0106_i2c_capture_source_info, 6018c2ecf20Sopenharmony_ci .get = snd_ca0106_i2c_capture_source_get, 6028c2ecf20Sopenharmony_ci .put = snd_ca0106_i2c_capture_source_put 6038c2ecf20Sopenharmony_ci }, 6048c2ecf20Sopenharmony_ci { 6058c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 6068c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 6078c2ecf20Sopenharmony_ci .count = 4, 6088c2ecf20Sopenharmony_ci .info = snd_ca0106_spdif_info, 6098c2ecf20Sopenharmony_ci .get = snd_ca0106_spdif_get_default, 6108c2ecf20Sopenharmony_ci .put = snd_ca0106_spdif_put_default 6118c2ecf20Sopenharmony_ci }, 6128c2ecf20Sopenharmony_ci { 6138c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 6148c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM), 6158c2ecf20Sopenharmony_ci .count = 4, 6168c2ecf20Sopenharmony_ci .info = snd_ca0106_spdif_info, 6178c2ecf20Sopenharmony_ci .get = snd_ca0106_spdif_get_stream, 6188c2ecf20Sopenharmony_ci .put = snd_ca0106_spdif_put_stream 6198c2ecf20Sopenharmony_ci }, 6208c2ecf20Sopenharmony_ci}; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci#define I2C_VOLUME(xname,chid) \ 6238c2ecf20Sopenharmony_ci{ \ 6248c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 6258c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ 6268c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 6278c2ecf20Sopenharmony_ci .info = snd_ca0106_i2c_volume_info, \ 6288c2ecf20Sopenharmony_ci .get = snd_ca0106_i2c_volume_get, \ 6298c2ecf20Sopenharmony_ci .put = snd_ca0106_i2c_volume_put, \ 6308c2ecf20Sopenharmony_ci .tlv = { .p = snd_ca0106_db_scale2 }, \ 6318c2ecf20Sopenharmony_ci .private_value = chid \ 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] = { 6358c2ecf20Sopenharmony_ci I2C_VOLUME("Phone Capture Volume", 0), 6368c2ecf20Sopenharmony_ci I2C_VOLUME("Mic Capture Volume", 1), 6378c2ecf20Sopenharmony_ci I2C_VOLUME("Line in Capture Volume", 2), 6388c2ecf20Sopenharmony_ci I2C_VOLUME("Aux Capture Volume", 3), 6398c2ecf20Sopenharmony_ci}; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic const int spi_dmute_reg[] = { 6428c2ecf20Sopenharmony_ci SPI_DMUTE0_REG, 6438c2ecf20Sopenharmony_ci SPI_DMUTE1_REG, 6448c2ecf20Sopenharmony_ci SPI_DMUTE2_REG, 6458c2ecf20Sopenharmony_ci 0, 6468c2ecf20Sopenharmony_ci SPI_DMUTE4_REG, 6478c2ecf20Sopenharmony_ci}; 6488c2ecf20Sopenharmony_cistatic const int spi_dmute_bit[] = { 6498c2ecf20Sopenharmony_ci SPI_DMUTE0_BIT, 6508c2ecf20Sopenharmony_ci SPI_DMUTE1_BIT, 6518c2ecf20Sopenharmony_ci SPI_DMUTE2_BIT, 6528c2ecf20Sopenharmony_ci 0, 6538c2ecf20Sopenharmony_ci SPI_DMUTE4_BIT, 6548c2ecf20Sopenharmony_ci}; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_cistatic struct snd_kcontrol_new 6578c2ecf20Sopenharmony_cisnd_ca0106_volume_spi_dac_ctl(const struct snd_ca0106_details *details, 6588c2ecf20Sopenharmony_ci int channel_id) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci struct snd_kcontrol_new spi_switch = {0}; 6618c2ecf20Sopenharmony_ci int reg, bit; 6628c2ecf20Sopenharmony_ci int dac_id; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci spi_switch.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 6658c2ecf20Sopenharmony_ci spi_switch.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; 6668c2ecf20Sopenharmony_ci spi_switch.info = spi_mute_info; 6678c2ecf20Sopenharmony_ci spi_switch.get = spi_mute_get; 6688c2ecf20Sopenharmony_ci spi_switch.put = spi_mute_put; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci switch (channel_id) { 6718c2ecf20Sopenharmony_ci case PCM_FRONT_CHANNEL: 6728c2ecf20Sopenharmony_ci spi_switch.name = "Analog Front Playback Switch"; 6738c2ecf20Sopenharmony_ci dac_id = (details->spi_dac & 0xf000) >> (4 * 3); 6748c2ecf20Sopenharmony_ci break; 6758c2ecf20Sopenharmony_ci case PCM_REAR_CHANNEL: 6768c2ecf20Sopenharmony_ci spi_switch.name = "Analog Rear Playback Switch"; 6778c2ecf20Sopenharmony_ci dac_id = (details->spi_dac & 0x0f00) >> (4 * 2); 6788c2ecf20Sopenharmony_ci break; 6798c2ecf20Sopenharmony_ci case PCM_CENTER_LFE_CHANNEL: 6808c2ecf20Sopenharmony_ci spi_switch.name = "Analog Center/LFE Playback Switch"; 6818c2ecf20Sopenharmony_ci dac_id = (details->spi_dac & 0x00f0) >> (4 * 1); 6828c2ecf20Sopenharmony_ci break; 6838c2ecf20Sopenharmony_ci case PCM_UNKNOWN_CHANNEL: 6848c2ecf20Sopenharmony_ci spi_switch.name = "Analog Side Playback Switch"; 6858c2ecf20Sopenharmony_ci dac_id = (details->spi_dac & 0x000f) >> (4 * 0); 6868c2ecf20Sopenharmony_ci break; 6878c2ecf20Sopenharmony_ci default: 6888c2ecf20Sopenharmony_ci /* Unused channel */ 6898c2ecf20Sopenharmony_ci spi_switch.name = NULL; 6908c2ecf20Sopenharmony_ci dac_id = 0; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci reg = spi_dmute_reg[dac_id]; 6938c2ecf20Sopenharmony_ci bit = spi_dmute_bit[dac_id]; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci spi_switch.private_value = (reg << SPI_REG_SHIFT) | bit; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci return spi_switch; 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_cistatic int remove_ctl(struct snd_card *card, const char *name) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci struct snd_ctl_elem_id id; 7038c2ecf20Sopenharmony_ci memset(&id, 0, sizeof(id)); 7048c2ecf20Sopenharmony_ci strcpy(id.name, name); 7058c2ecf20Sopenharmony_ci id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 7068c2ecf20Sopenharmony_ci return snd_ctl_remove_id(card, &id); 7078c2ecf20Sopenharmony_ci} 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_cistatic struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name) 7108c2ecf20Sopenharmony_ci{ 7118c2ecf20Sopenharmony_ci struct snd_ctl_elem_id sid; 7128c2ecf20Sopenharmony_ci memset(&sid, 0, sizeof(sid)); 7138c2ecf20Sopenharmony_ci /* FIXME: strcpy is bad. */ 7148c2ecf20Sopenharmony_ci strcpy(sid.name, name); 7158c2ecf20Sopenharmony_ci sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 7168c2ecf20Sopenharmony_ci return snd_ctl_find_id(card, &sid); 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_cistatic int rename_ctl(struct snd_card *card, const char *src, const char *dst) 7208c2ecf20Sopenharmony_ci{ 7218c2ecf20Sopenharmony_ci struct snd_kcontrol *kctl = ctl_find(card, src); 7228c2ecf20Sopenharmony_ci if (kctl) { 7238c2ecf20Sopenharmony_ci strcpy(kctl->id.name, dst); 7248c2ecf20Sopenharmony_ci return 0; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci return -ENOENT; 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci#define ADD_CTLS(emu, ctls) \ 7308c2ecf20Sopenharmony_ci do { \ 7318c2ecf20Sopenharmony_ci int i, _err; \ 7328c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ctls); i++) { \ 7338c2ecf20Sopenharmony_ci _err = snd_ctl_add(card, snd_ctl_new1(&ctls[i], emu)); \ 7348c2ecf20Sopenharmony_ci if (_err < 0) \ 7358c2ecf20Sopenharmony_ci return _err; \ 7368c2ecf20Sopenharmony_ci } \ 7378c2ecf20Sopenharmony_ci } while (0) 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cistatic 7408c2ecf20Sopenharmony_ciDECLARE_TLV_DB_SCALE(snd_ca0106_master_db_scale, -6375, 25, 1); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_cistatic const char * const follower_vols[] = { 7438c2ecf20Sopenharmony_ci "Analog Front Playback Volume", 7448c2ecf20Sopenharmony_ci "Analog Rear Playback Volume", 7458c2ecf20Sopenharmony_ci "Analog Center/LFE Playback Volume", 7468c2ecf20Sopenharmony_ci "Analog Side Playback Volume", 7478c2ecf20Sopenharmony_ci "IEC958 Front Playback Volume", 7488c2ecf20Sopenharmony_ci "IEC958 Rear Playback Volume", 7498c2ecf20Sopenharmony_ci "IEC958 Center/LFE Playback Volume", 7508c2ecf20Sopenharmony_ci "IEC958 Unknown Playback Volume", 7518c2ecf20Sopenharmony_ci "CAPTURE feedback Playback Volume", 7528c2ecf20Sopenharmony_ci NULL 7538c2ecf20Sopenharmony_ci}; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_cistatic const char * const follower_sws[] = { 7568c2ecf20Sopenharmony_ci "Analog Front Playback Switch", 7578c2ecf20Sopenharmony_ci "Analog Rear Playback Switch", 7588c2ecf20Sopenharmony_ci "Analog Center/LFE Playback Switch", 7598c2ecf20Sopenharmony_ci "Analog Side Playback Switch", 7608c2ecf20Sopenharmony_ci "IEC958 Playback Switch", 7618c2ecf20Sopenharmony_ci NULL 7628c2ecf20Sopenharmony_ci}; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic void add_followers(struct snd_card *card, 7658c2ecf20Sopenharmony_ci struct snd_kcontrol *master, const char * const *list) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci for (; *list; list++) { 7688c2ecf20Sopenharmony_ci struct snd_kcontrol *follower = ctl_find(card, *list); 7698c2ecf20Sopenharmony_ci if (follower) 7708c2ecf20Sopenharmony_ci snd_ctl_add_follower(master, follower); 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ciint snd_ca0106_mixer(struct snd_ca0106 *emu) 7758c2ecf20Sopenharmony_ci{ 7768c2ecf20Sopenharmony_ci int err; 7778c2ecf20Sopenharmony_ci struct snd_card *card = emu->card; 7788c2ecf20Sopenharmony_ci const char * const *c; 7798c2ecf20Sopenharmony_ci struct snd_kcontrol *vmaster; 7808c2ecf20Sopenharmony_ci static const char * const ca0106_remove_ctls[] = { 7818c2ecf20Sopenharmony_ci "Master Mono Playback Switch", 7828c2ecf20Sopenharmony_ci "Master Mono Playback Volume", 7838c2ecf20Sopenharmony_ci "3D Control - Switch", 7848c2ecf20Sopenharmony_ci "3D Control Sigmatel - Depth", 7858c2ecf20Sopenharmony_ci "PCM Playback Switch", 7868c2ecf20Sopenharmony_ci "PCM Playback Volume", 7878c2ecf20Sopenharmony_ci "CD Playback Switch", 7888c2ecf20Sopenharmony_ci "CD Playback Volume", 7898c2ecf20Sopenharmony_ci "Phone Playback Switch", 7908c2ecf20Sopenharmony_ci "Phone Playback Volume", 7918c2ecf20Sopenharmony_ci "Video Playback Switch", 7928c2ecf20Sopenharmony_ci "Video Playback Volume", 7938c2ecf20Sopenharmony_ci "Beep Playback Switch", 7948c2ecf20Sopenharmony_ci "Beep Playback Volume", 7958c2ecf20Sopenharmony_ci "Mono Output Select", 7968c2ecf20Sopenharmony_ci "Capture Source", 7978c2ecf20Sopenharmony_ci "Capture Switch", 7988c2ecf20Sopenharmony_ci "Capture Volume", 7998c2ecf20Sopenharmony_ci "External Amplifier", 8008c2ecf20Sopenharmony_ci "Sigmatel 4-Speaker Stereo Playback Switch", 8018c2ecf20Sopenharmony_ci "Surround Phase Inversion Playback Switch", 8028c2ecf20Sopenharmony_ci NULL 8038c2ecf20Sopenharmony_ci }; 8048c2ecf20Sopenharmony_ci static const char * const ca0106_rename_ctls[] = { 8058c2ecf20Sopenharmony_ci "Master Playback Switch", "Capture Switch", 8068c2ecf20Sopenharmony_ci "Master Playback Volume", "Capture Volume", 8078c2ecf20Sopenharmony_ci "Line Playback Switch", "AC97 Line Capture Switch", 8088c2ecf20Sopenharmony_ci "Line Playback Volume", "AC97 Line Capture Volume", 8098c2ecf20Sopenharmony_ci "Aux Playback Switch", "AC97 Aux Capture Switch", 8108c2ecf20Sopenharmony_ci "Aux Playback Volume", "AC97 Aux Capture Volume", 8118c2ecf20Sopenharmony_ci "Mic Playback Switch", "AC97 Mic Capture Switch", 8128c2ecf20Sopenharmony_ci "Mic Playback Volume", "AC97 Mic Capture Volume", 8138c2ecf20Sopenharmony_ci "Mic Select", "AC97 Mic Select", 8148c2ecf20Sopenharmony_ci "Mic Boost (+20dB)", "AC97 Mic Boost (+20dB)", 8158c2ecf20Sopenharmony_ci NULL 8168c2ecf20Sopenharmony_ci }; 8178c2ecf20Sopenharmony_ci#if 1 8188c2ecf20Sopenharmony_ci for (c = ca0106_remove_ctls; *c; c++) 8198c2ecf20Sopenharmony_ci remove_ctl(card, *c); 8208c2ecf20Sopenharmony_ci for (c = ca0106_rename_ctls; *c; c += 2) 8218c2ecf20Sopenharmony_ci rename_ctl(card, c[0], c[1]); 8228c2ecf20Sopenharmony_ci#endif 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci ADD_CTLS(emu, snd_ca0106_volume_ctls); 8258c2ecf20Sopenharmony_ci if (emu->details->i2c_adc == 1) { 8268c2ecf20Sopenharmony_ci ADD_CTLS(emu, snd_ca0106_volume_i2c_adc_ctls); 8278c2ecf20Sopenharmony_ci if (emu->details->gpio_type == 1) 8288c2ecf20Sopenharmony_ci err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_mic_line_in, emu)); 8298c2ecf20Sopenharmony_ci else /* gpio_type == 2 */ 8308c2ecf20Sopenharmony_ci err = snd_ctl_add(card, snd_ctl_new1(&snd_ca0106_capture_line_in_side_out, emu)); 8318c2ecf20Sopenharmony_ci if (err < 0) 8328c2ecf20Sopenharmony_ci return err; 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci if (emu->details->spi_dac) { 8358c2ecf20Sopenharmony_ci int i; 8368c2ecf20Sopenharmony_ci for (i = 0;; i++) { 8378c2ecf20Sopenharmony_ci struct snd_kcontrol_new ctl; 8388c2ecf20Sopenharmony_ci ctl = snd_ca0106_volume_spi_dac_ctl(emu->details, i); 8398c2ecf20Sopenharmony_ci if (!ctl.name) 8408c2ecf20Sopenharmony_ci break; 8418c2ecf20Sopenharmony_ci err = snd_ctl_add(card, snd_ctl_new1(&ctl, emu)); 8428c2ecf20Sopenharmony_ci if (err < 0) 8438c2ecf20Sopenharmony_ci return err; 8448c2ecf20Sopenharmony_ci } 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci /* Create virtual master controls */ 8488c2ecf20Sopenharmony_ci vmaster = snd_ctl_make_virtual_master("Master Playback Volume", 8498c2ecf20Sopenharmony_ci snd_ca0106_master_db_scale); 8508c2ecf20Sopenharmony_ci if (!vmaster) 8518c2ecf20Sopenharmony_ci return -ENOMEM; 8528c2ecf20Sopenharmony_ci err = snd_ctl_add(card, vmaster); 8538c2ecf20Sopenharmony_ci if (err < 0) 8548c2ecf20Sopenharmony_ci return err; 8558c2ecf20Sopenharmony_ci add_followers(card, vmaster, follower_vols); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci if (emu->details->spi_dac) { 8588c2ecf20Sopenharmony_ci vmaster = snd_ctl_make_virtual_master("Master Playback Switch", 8598c2ecf20Sopenharmony_ci NULL); 8608c2ecf20Sopenharmony_ci if (!vmaster) 8618c2ecf20Sopenharmony_ci return -ENOMEM; 8628c2ecf20Sopenharmony_ci err = snd_ctl_add(card, vmaster); 8638c2ecf20Sopenharmony_ci if (err < 0) 8648c2ecf20Sopenharmony_ci return err; 8658c2ecf20Sopenharmony_ci add_followers(card, vmaster, follower_sws); 8668c2ecf20Sopenharmony_ci } 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci strcpy(card->mixername, "CA0106"); 8698c2ecf20Sopenharmony_ci return 0; 8708c2ecf20Sopenharmony_ci} 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 8738c2ecf20Sopenharmony_cistruct ca0106_vol_tbl { 8748c2ecf20Sopenharmony_ci unsigned int channel_id; 8758c2ecf20Sopenharmony_ci unsigned int reg; 8768c2ecf20Sopenharmony_ci}; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_cistatic const struct ca0106_vol_tbl saved_volumes[NUM_SAVED_VOLUMES] = { 8798c2ecf20Sopenharmony_ci { CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2 }, 8808c2ecf20Sopenharmony_ci { CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME2 }, 8818c2ecf20Sopenharmony_ci { CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME2 }, 8828c2ecf20Sopenharmony_ci { CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME2 }, 8838c2ecf20Sopenharmony_ci { CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME1 }, 8848c2ecf20Sopenharmony_ci { CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME1 }, 8858c2ecf20Sopenharmony_ci { CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME1 }, 8868c2ecf20Sopenharmony_ci { CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME1 }, 8878c2ecf20Sopenharmony_ci { 1, CAPTURE_CONTROL }, 8888c2ecf20Sopenharmony_ci}; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_civoid snd_ca0106_mixer_suspend(struct snd_ca0106 *chip) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci int i; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci /* save volumes */ 8958c2ecf20Sopenharmony_ci for (i = 0; i < NUM_SAVED_VOLUMES; i++) 8968c2ecf20Sopenharmony_ci chip->saved_vol[i] = 8978c2ecf20Sopenharmony_ci snd_ca0106_ptr_read(chip, saved_volumes[i].reg, 8988c2ecf20Sopenharmony_ci saved_volumes[i].channel_id); 8998c2ecf20Sopenharmony_ci} 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_civoid snd_ca0106_mixer_resume(struct snd_ca0106 *chip) 9028c2ecf20Sopenharmony_ci{ 9038c2ecf20Sopenharmony_ci int i; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci for (i = 0; i < NUM_SAVED_VOLUMES; i++) 9068c2ecf20Sopenharmony_ci snd_ca0106_ptr_write(chip, saved_volumes[i].reg, 9078c2ecf20Sopenharmony_ci saved_volumes[i].channel_id, 9088c2ecf20Sopenharmony_ci chip->saved_vol[i]); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci ca0106_spdif_enable(chip); 9118c2ecf20Sopenharmony_ci ca0106_set_capture_source(chip); 9128c2ecf20Sopenharmony_ci ca0106_set_i2c_capture_source(chip, chip->i2c_capture_source, 1); 9138c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 9148c2ecf20Sopenharmony_ci ca0106_set_spdif_bits(chip, i); 9158c2ecf20Sopenharmony_ci if (chip->details->i2c_adc) 9168c2ecf20Sopenharmony_ci ca0106_set_capture_mic_line_in(chip); 9178c2ecf20Sopenharmony_ci} 9188c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 919