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