]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * ALSA driver for AK4524 / AK4528 / AK4529 / AK4355 / AK4358 / AK4381 | |
3 | * AD and DA converters | |
4 | * | |
c1017a4c | 5 | * Copyright (c) 2000-2004 Jaroslav Kysela <perex@perex.cz>, |
1da177e4 LT |
6 | * Takashi Iwai <tiwai@suse.de> |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2 of the License, or | |
11 | * (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 | * | |
8f34692f | 22 | */ |
1da177e4 | 23 | |
1da177e4 LT |
24 | #include <asm/io.h> |
25 | #include <linux/delay.h> | |
26 | #include <linux/interrupt.h> | |
27 | #include <linux/init.h> | |
28 | #include <sound/core.h> | |
29 | #include <sound/control.h> | |
723b2b0d | 30 | #include <sound/tlv.h> |
1da177e4 | 31 | #include <sound/ak4xxx-adda.h> |
8f34692f | 32 | #include <sound/info.h> |
1da177e4 | 33 | |
c1017a4c | 34 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>"); |
1da177e4 LT |
35 | MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters"); |
36 | MODULE_LICENSE("GPL"); | |
37 | ||
723b2b0d | 38 | /* write the given register and save the data to the cache */ |
cb9d24e4 TI |
39 | void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg, |
40 | unsigned char val) | |
1da177e4 LT |
41 | { |
42 | ak->ops.lock(ak, chip); | |
43 | ak->ops.write(ak, chip, reg, val); | |
44 | ||
45 | /* save the data */ | |
854b66e4 | 46 | snd_akm4xxx_set(ak, chip, reg, val); |
1da177e4 LT |
47 | ak->ops.unlock(ak, chip); |
48 | } | |
49 | ||
cb9d24e4 TI |
50 | EXPORT_SYMBOL(snd_akm4xxx_write); |
51 | ||
52 | /* reset procedure for AK4524 and AK4528 */ | |
53 | static void ak4524_reset(struct snd_akm4xxx *ak, int state) | |
54 | { | |
55 | unsigned int chip; | |
8f34692f | 56 | unsigned char reg; |
cb9d24e4 | 57 | |
cb9d24e4 TI |
58 | for (chip = 0; chip < ak->num_dacs/2; chip++) { |
59 | snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03); | |
60 | if (state) | |
61 | continue; | |
62 | /* DAC volumes */ | |
8f34692f | 63 | for (reg = 0x04; reg < ak->total_regs; reg++) |
cb9d24e4 TI |
64 | snd_akm4xxx_write(ak, chip, reg, |
65 | snd_akm4xxx_get(ak, chip, reg)); | |
cb9d24e4 TI |
66 | } |
67 | } | |
68 | ||
69 | /* reset procedure for AK4355 and AK4358 */ | |
8f34692f | 70 | static void ak435X_reset(struct snd_akm4xxx *ak, int state) |
cb9d24e4 TI |
71 | { |
72 | unsigned char reg; | |
73 | ||
74 | if (state) { | |
75 | snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */ | |
76 | return; | |
77 | } | |
8f34692f | 78 | for (reg = 0x00; reg < ak->total_regs; reg++) |
cb9d24e4 TI |
79 | if (reg != 0x01) |
80 | snd_akm4xxx_write(ak, 0, reg, | |
81 | snd_akm4xxx_get(ak, 0, reg)); | |
82 | snd_akm4xxx_write(ak, 0, 0x01, 0x01); /* un-reset, unmute */ | |
83 | } | |
84 | ||
85 | /* reset procedure for AK4381 */ | |
86 | static void ak4381_reset(struct snd_akm4xxx *ak, int state) | |
87 | { | |
88 | unsigned int chip; | |
89 | unsigned char reg; | |
cb9d24e4 TI |
90 | for (chip = 0; chip < ak->num_dacs/2; chip++) { |
91 | snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f); | |
92 | if (state) | |
93 | continue; | |
8f34692f | 94 | for (reg = 0x01; reg < ak->total_regs; reg++) |
cb9d24e4 TI |
95 | snd_akm4xxx_write(ak, chip, reg, |
96 | snd_akm4xxx_get(ak, chip, reg)); | |
97 | } | |
98 | } | |
99 | ||
1da177e4 LT |
100 | /* |
101 | * reset the AKM codecs | |
102 | * @state: 1 = reset codec, 0 = restore the registers | |
103 | * | |
104 | * assert the reset operation and restores the register values to the chips. | |
105 | */ | |
97f02e05 | 106 | void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state) |
1da177e4 | 107 | { |
1da177e4 LT |
108 | switch (ak->type) { |
109 | case SND_AK4524: | |
110 | case SND_AK4528: | |
8f34692f | 111 | case SND_AK4620: |
cb9d24e4 | 112 | ak4524_reset(ak, state); |
1da177e4 LT |
113 | break; |
114 | case SND_AK4529: | |
115 | /* FIXME: needed for ak4529? */ | |
116 | break; | |
117 | case SND_AK4355: | |
8f34692f | 118 | ak435X_reset(ak, state); |
841b23d4 | 119 | break; |
1da177e4 | 120 | case SND_AK4358: |
8f34692f | 121 | ak435X_reset(ak, state); |
1da177e4 LT |
122 | break; |
123 | case SND_AK4381: | |
cb9d24e4 | 124 | ak4381_reset(ak, state); |
1da177e4 | 125 | break; |
cf93907b TI |
126 | default: |
127 | break; | |
1da177e4 LT |
128 | } |
129 | } | |
130 | ||
cb9d24e4 TI |
131 | EXPORT_SYMBOL(snd_akm4xxx_reset); |
132 | ||
723b2b0d TI |
133 | |
134 | /* | |
135 | * Volume conversion table for non-linear volumes | |
136 | * from -63.5dB (mute) to 0dB step 0.5dB | |
137 | * | |
8f34692f | 138 | * Used for AK4524/AK4620 input/ouput attenuation, AK4528, and |
723b2b0d TI |
139 | * AK5365 input attenuation |
140 | */ | |
517400cb | 141 | static const unsigned char vol_cvt_datt[128] = { |
723b2b0d TI |
142 | 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, |
143 | 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, | |
144 | 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a, | |
145 | 0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, | |
146 | 0x10, 0x10, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14, | |
147 | 0x15, 0x16, 0x17, 0x17, 0x18, 0x19, 0x1a, 0x1c, | |
148 | 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x23, | |
149 | 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, 0x2b, 0x2d, | |
150 | 0x2e, 0x30, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, | |
151 | 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3e, 0x3f, 0x40, | |
152 | 0x41, 0x42, 0x43, 0x44, 0x46, 0x47, 0x48, 0x4a, | |
153 | 0x4b, 0x4d, 0x4e, 0x50, 0x51, 0x52, 0x53, 0x54, | |
154 | 0x55, 0x56, 0x58, 0x59, 0x5b, 0x5c, 0x5e, 0x5f, | |
155 | 0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x69, | |
156 | 0x6a, 0x6c, 0x6d, 0x6f, 0x70, 0x71, 0x72, 0x73, | |
157 | 0x75, 0x76, 0x77, 0x79, 0x7a, 0x7c, 0x7d, 0x7f, | |
158 | }; | |
159 | ||
160 | /* | |
161 | * dB tables | |
162 | */ | |
0cb29ea0 TI |
163 | static const DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1); |
164 | static const DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1); | |
165 | static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1); | |
166 | static const DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0); | |
723b2b0d | 167 | |
1da177e4 LT |
168 | /* |
169 | * initialize all the ak4xxx chips | |
170 | */ | |
97f02e05 | 171 | void snd_akm4xxx_init(struct snd_akm4xxx *ak) |
1da177e4 | 172 | { |
0cb29ea0 | 173 | static const unsigned char inits_ak4524[] = { |
1da177e4 LT |
174 | 0x00, 0x07, /* 0: all power up */ |
175 | 0x01, 0x00, /* 1: ADC/DAC reset */ | |
176 | 0x02, 0x60, /* 2: 24bit I2S */ | |
177 | 0x03, 0x19, /* 3: deemphasis off */ | |
178 | 0x01, 0x03, /* 1: ADC/DAC enable */ | |
179 | 0x04, 0x00, /* 4: ADC left muted */ | |
180 | 0x05, 0x00, /* 5: ADC right muted */ | |
1da177e4 LT |
181 | 0x06, 0x00, /* 6: DAC left muted */ |
182 | 0x07, 0x00, /* 7: DAC right muted */ | |
183 | 0xff, 0xff | |
184 | }; | |
517400cb | 185 | static const unsigned char inits_ak4528[] = { |
1da177e4 LT |
186 | 0x00, 0x07, /* 0: all power up */ |
187 | 0x01, 0x00, /* 1: ADC/DAC reset */ | |
188 | 0x02, 0x60, /* 2: 24bit I2S */ | |
189 | 0x03, 0x0d, /* 3: deemphasis off, turn LR highpass filters on */ | |
190 | 0x01, 0x03, /* 1: ADC/DAC enable */ | |
191 | 0x04, 0x00, /* 4: ADC left muted */ | |
192 | 0x05, 0x00, /* 5: ADC right muted */ | |
193 | 0xff, 0xff | |
194 | }; | |
517400cb | 195 | static const unsigned char inits_ak4529[] = { |
1da177e4 LT |
196 | 0x09, 0x01, /* 9: ATS=0, RSTN=1 */ |
197 | 0x0a, 0x3f, /* A: all power up, no zero/overflow detection */ | |
198 | 0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */ | |
199 | 0x01, 0x00, /* 1: ACKS=0, ADC, loop off */ | |
200 | 0x02, 0xff, /* 2: LOUT1 muted */ | |
201 | 0x03, 0xff, /* 3: ROUT1 muted */ | |
202 | 0x04, 0xff, /* 4: LOUT2 muted */ | |
203 | 0x05, 0xff, /* 5: ROUT2 muted */ | |
204 | 0x06, 0xff, /* 6: LOUT3 muted */ | |
205 | 0x07, 0xff, /* 7: ROUT3 muted */ | |
206 | 0x0b, 0xff, /* B: LOUT4 muted */ | |
207 | 0x0c, 0xff, /* C: ROUT4 muted */ | |
208 | 0x08, 0x55, /* 8: deemphasis all off */ | |
209 | 0xff, 0xff | |
210 | }; | |
517400cb | 211 | static const unsigned char inits_ak4355[] = { |
1da177e4 | 212 | 0x01, 0x02, /* 1: reset and soft-mute */ |
cb9d24e4 TI |
213 | 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, |
214 | * disable DZF, sharp roll-off, RSTN#=0 */ | |
1da177e4 LT |
215 | 0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */ |
216 | // 0x02, 0x2e, /* quad speed */ | |
217 | 0x03, 0x01, /* 3: de-emphasis off */ | |
218 | 0x04, 0x00, /* 4: LOUT1 volume muted */ | |
219 | 0x05, 0x00, /* 5: ROUT1 volume muted */ | |
220 | 0x06, 0x00, /* 6: LOUT2 volume muted */ | |
221 | 0x07, 0x00, /* 7: ROUT2 volume muted */ | |
222 | 0x08, 0x00, /* 8: LOUT3 volume muted */ | |
223 | 0x09, 0x00, /* 9: ROUT3 volume muted */ | |
224 | 0x0a, 0x00, /* a: DATT speed=0, ignore DZF */ | |
225 | 0x01, 0x01, /* 1: un-reset, unmute */ | |
226 | 0xff, 0xff | |
227 | }; | |
517400cb | 228 | static const unsigned char inits_ak4358[] = { |
1da177e4 | 229 | 0x01, 0x02, /* 1: reset and soft-mute */ |
cb9d24e4 TI |
230 | 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, |
231 | * disable DZF, sharp roll-off, RSTN#=0 */ | |
46480b3a AB |
232 | 0x02, 0x4e, /* 2: DA's power up, normal speed, RSTN#=0 */ |
233 | /* 0x02, 0x6e,*/ /* quad speed */ | |
1da177e4 LT |
234 | 0x03, 0x01, /* 3: de-emphasis off */ |
235 | 0x04, 0x00, /* 4: LOUT1 volume muted */ | |
236 | 0x05, 0x00, /* 5: ROUT1 volume muted */ | |
237 | 0x06, 0x00, /* 6: LOUT2 volume muted */ | |
238 | 0x07, 0x00, /* 7: ROUT2 volume muted */ | |
239 | 0x08, 0x00, /* 8: LOUT3 volume muted */ | |
240 | 0x09, 0x00, /* 9: ROUT3 volume muted */ | |
241 | 0x0b, 0x00, /* b: LOUT4 volume muted */ | |
242 | 0x0c, 0x00, /* c: ROUT4 volume muted */ | |
243 | 0x0a, 0x00, /* a: DATT speed=0, ignore DZF */ | |
244 | 0x01, 0x01, /* 1: un-reset, unmute */ | |
245 | 0xff, 0xff | |
246 | }; | |
517400cb | 247 | static const unsigned char inits_ak4381[] = { |
1da177e4 | 248 | 0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */ |
cb9d24e4 TI |
249 | 0x01, 0x02, /* 1: de-emphasis off, normal speed, |
250 | * sharp roll-off, DZF off */ | |
1da177e4 LT |
251 | // 0x01, 0x12, /* quad speed */ |
252 | 0x02, 0x00, /* 2: DZF disabled */ | |
253 | 0x03, 0x00, /* 3: LATT 0 */ | |
254 | 0x04, 0x00, /* 4: RATT 0 */ | |
255 | 0x00, 0x0f, /* 0: power-up, un-reset */ | |
256 | 0xff, 0xff | |
257 | }; | |
8f34692f PH |
258 | static const unsigned char inits_ak4620[] = { |
259 | 0x00, 0x07, /* 0: normal */ | |
260 | 0x01, 0x00, /* 0: reset */ | |
261 | 0x01, 0x02, /* 1: RSTAD */ | |
262 | 0x01, 0x03, /* 1: RSTDA */ | |
263 | 0x01, 0x0f, /* 1: normal */ | |
264 | 0x02, 0x60, /* 2: 24bit I2S */ | |
265 | 0x03, 0x01, /* 3: deemphasis off */ | |
266 | 0x04, 0x00, /* 4: LIN muted */ | |
267 | 0x05, 0x00, /* 5: RIN muted */ | |
268 | 0x06, 0x00, /* 6: LOUT muted */ | |
269 | 0x07, 0x00, /* 7: ROUT muted */ | |
270 | 0xff, 0xff | |
271 | }; | |
1da177e4 | 272 | |
8f34692f | 273 | int chip; |
517400cb TI |
274 | const unsigned char *ptr, *inits; |
275 | unsigned char reg, data; | |
1da177e4 | 276 | |
723b2b0d TI |
277 | memset(ak->images, 0, sizeof(ak->images)); |
278 | memset(ak->volumes, 0, sizeof(ak->volumes)); | |
279 | ||
1da177e4 LT |
280 | switch (ak->type) { |
281 | case SND_AK4524: | |
282 | inits = inits_ak4524; | |
8f34692f PH |
283 | ak->num_chips = ak->num_dacs / 2; |
284 | ak->name = "ak4524"; | |
285 | ak->total_regs = 0x08; | |
1da177e4 LT |
286 | break; |
287 | case SND_AK4528: | |
288 | inits = inits_ak4528; | |
8f34692f PH |
289 | ak->num_chips = ak->num_dacs / 2; |
290 | ak->name = "ak4528"; | |
291 | ak->total_regs = 0x06; | |
1da177e4 LT |
292 | break; |
293 | case SND_AK4529: | |
294 | inits = inits_ak4529; | |
8f34692f PH |
295 | ak->num_chips = 1; |
296 | ak->name = "ak4529"; | |
297 | ak->total_regs = 0x0d; | |
1da177e4 LT |
298 | break; |
299 | case SND_AK4355: | |
300 | inits = inits_ak4355; | |
8f34692f PH |
301 | ak->num_chips = 1; |
302 | ak->name = "ak4355"; | |
303 | ak->total_regs = 0x0b; | |
1da177e4 LT |
304 | break; |
305 | case SND_AK4358: | |
306 | inits = inits_ak4358; | |
8f34692f PH |
307 | ak->num_chips = 1; |
308 | ak->name = "ak4358"; | |
309 | ak->total_regs = 0x10; | |
1da177e4 LT |
310 | break; |
311 | case SND_AK4381: | |
312 | inits = inits_ak4381; | |
8f34692f PH |
313 | ak->num_chips = ak->num_dacs / 2; |
314 | ak->name = "ak4381"; | |
315 | ak->total_regs = 0x05; | |
1da177e4 | 316 | break; |
723b2b0d TI |
317 | case SND_AK5365: |
318 | /* FIXME: any init sequence? */ | |
8f34692f PH |
319 | ak->num_chips = 1; |
320 | ak->name = "ak5365"; | |
321 | ak->total_regs = 0x08; | |
723b2b0d | 322 | return; |
8f34692f PH |
323 | case SND_AK4620: |
324 | inits = inits_ak4620; | |
325 | ak->num_chips = ak->num_dacs / 2; | |
326 | ak->name = "ak4620"; | |
327 | ak->total_regs = 0x08; | |
328 | break; | |
1da177e4 LT |
329 | default: |
330 | snd_BUG(); | |
331 | return; | |
332 | } | |
333 | ||
8f34692f | 334 | for (chip = 0; chip < ak->num_chips; chip++) { |
1da177e4 LT |
335 | ptr = inits; |
336 | while (*ptr != 0xff) { | |
337 | reg = *ptr++; | |
338 | data = *ptr++; | |
339 | snd_akm4xxx_write(ak, chip, reg, data); | |
8f34692f | 340 | udelay(10); |
1da177e4 LT |
341 | } |
342 | } | |
343 | } | |
344 | ||
cb9d24e4 TI |
345 | EXPORT_SYMBOL(snd_akm4xxx_init); |
346 | ||
723b2b0d TI |
347 | /* |
348 | * Mixer callbacks | |
349 | */ | |
854b66e4 | 350 | #define AK_IPGA (1<<20) /* including IPGA */ |
723b2b0d TI |
351 | #define AK_VOL_CVT (1<<21) /* need dB conversion */ |
352 | #define AK_NEEDSMSB (1<<22) /* need MSB update bit */ | |
353 | #define AK_INVERT (1<<23) /* data is inverted */ | |
1da177e4 LT |
354 | #define AK_GET_CHIP(val) (((val) >> 8) & 0xff) |
355 | #define AK_GET_ADDR(val) ((val) & 0xff) | |
854b66e4 | 356 | #define AK_GET_SHIFT(val) (((val) >> 16) & 0x0f) |
723b2b0d | 357 | #define AK_GET_VOL_CVT(val) (((val) >> 21) & 1) |
854b66e4 | 358 | #define AK_GET_IPGA(val) (((val) >> 20) & 1) |
3479307f | 359 | #define AK_GET_NEEDSMSB(val) (((val) >> 22) & 1) |
1da177e4 LT |
360 | #define AK_GET_INVERT(val) (((val) >> 23) & 1) |
361 | #define AK_GET_MASK(val) (((val) >> 24) & 0xff) | |
cb9d24e4 TI |
362 | #define AK_COMPOSE(chip,addr,shift,mask) \ |
363 | (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24)) | |
1da177e4 | 364 | |
97f02e05 TI |
365 | static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol, |
366 | struct snd_ctl_elem_info *uinfo) | |
1da177e4 LT |
367 | { |
368 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); | |
369 | ||
370 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | |
371 | uinfo->count = 1; | |
372 | uinfo->value.integer.min = 0; | |
373 | uinfo->value.integer.max = mask; | |
374 | return 0; | |
375 | } | |
376 | ||
97f02e05 TI |
377 | static int snd_akm4xxx_volume_get(struct snd_kcontrol *kcontrol, |
378 | struct snd_ctl_elem_value *ucontrol) | |
1da177e4 | 379 | { |
97f02e05 | 380 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); |
1da177e4 LT |
381 | int chip = AK_GET_CHIP(kcontrol->private_value); |
382 | int addr = AK_GET_ADDR(kcontrol->private_value); | |
3479307f | 383 | |
723b2b0d | 384 | ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr); |
1da177e4 LT |
385 | return 0; |
386 | } | |
387 | ||
723b2b0d TI |
388 | static int put_ak_reg(struct snd_kcontrol *kcontrol, int addr, |
389 | unsigned char nval) | |
1da177e4 | 390 | { |
97f02e05 | 391 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); |
1da177e4 | 392 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); |
723b2b0d | 393 | int chip = AK_GET_CHIP(kcontrol->private_value); |
1da177e4 | 394 | |
723b2b0d TI |
395 | if (snd_akm4xxx_get_vol(ak, chip, addr) == nval) |
396 | return 0; | |
397 | ||
398 | snd_akm4xxx_set_vol(ak, chip, addr, nval); | |
854b66e4 | 399 | if (AK_GET_VOL_CVT(kcontrol->private_value) && nval < 128) |
723b2b0d | 400 | nval = vol_cvt_datt[nval]; |
854b66e4 TI |
401 | if (AK_GET_IPGA(kcontrol->private_value) && nval >= 128) |
402 | nval++; /* need to correct + 1 since both 127 and 128 are 0dB */ | |
723b2b0d | 403 | if (AK_GET_INVERT(kcontrol->private_value)) |
1da177e4 | 404 | nval = mask - nval; |
723b2b0d | 405 | if (AK_GET_NEEDSMSB(kcontrol->private_value)) |
3479307f | 406 | nval |= 0x80; |
841b23d4 PH |
407 | /* printk(KERN_DEBUG "DEBUG - AK writing reg: chip %x addr %x, |
408 | nval %x\n", chip, addr, nval); */ | |
723b2b0d TI |
409 | snd_akm4xxx_write(ak, chip, addr, nval); |
410 | return 1; | |
411 | } | |
412 | ||
413 | static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol, | |
414 | struct snd_ctl_elem_value *ucontrol) | |
415 | { | |
02ff1324 TI |
416 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); |
417 | unsigned int val = ucontrol->value.integer.value[0]; | |
418 | if (val > mask) | |
419 | return -EINVAL; | |
420 | return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value), val); | |
1da177e4 LT |
421 | } |
422 | ||
c83c0c47 | 423 | static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol, |
cb9d24e4 | 424 | struct snd_ctl_elem_info *uinfo) |
c83c0c47 JA |
425 | { |
426 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); | |
427 | ||
428 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | |
429 | uinfo->count = 2; | |
430 | uinfo->value.integer.min = 0; | |
431 | uinfo->value.integer.max = mask; | |
432 | return 0; | |
433 | } | |
434 | ||
435 | static int snd_akm4xxx_stereo_volume_get(struct snd_kcontrol *kcontrol, | |
cb9d24e4 | 436 | struct snd_ctl_elem_value *ucontrol) |
c83c0c47 JA |
437 | { |
438 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | |
439 | int chip = AK_GET_CHIP(kcontrol->private_value); | |
440 | int addr = AK_GET_ADDR(kcontrol->private_value); | |
c83c0c47 | 441 | |
723b2b0d TI |
442 | ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr); |
443 | ucontrol->value.integer.value[1] = snd_akm4xxx_get_vol(ak, chip, addr+1); | |
c83c0c47 JA |
444 | return 0; |
445 | } | |
446 | ||
447 | static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol, | |
cb9d24e4 | 448 | struct snd_ctl_elem_value *ucontrol) |
c83c0c47 | 449 | { |
c83c0c47 | 450 | int addr = AK_GET_ADDR(kcontrol->private_value); |
02ff1324 TI |
451 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); |
452 | unsigned int val[2]; | |
723b2b0d | 453 | int change; |
c83c0c47 | 454 | |
02ff1324 TI |
455 | val[0] = ucontrol->value.integer.value[0]; |
456 | val[1] = ucontrol->value.integer.value[1]; | |
457 | if (val[0] > mask || val[1] > mask) | |
458 | return -EINVAL; | |
459 | change = put_ak_reg(kcontrol, addr, val[0]); | |
460 | change |= put_ak_reg(kcontrol, addr + 1, val[1]); | |
723b2b0d | 461 | return change; |
c83c0c47 JA |
462 | } |
463 | ||
97f02e05 TI |
464 | static int snd_akm4xxx_deemphasis_info(struct snd_kcontrol *kcontrol, |
465 | struct snd_ctl_elem_info *uinfo) | |
1da177e4 LT |
466 | { |
467 | static char *texts[4] = { | |
468 | "44.1kHz", "Off", "48kHz", "32kHz", | |
469 | }; | |
470 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | |
471 | uinfo->count = 1; | |
472 | uinfo->value.enumerated.items = 4; | |
473 | if (uinfo->value.enumerated.item >= 4) | |
474 | uinfo->value.enumerated.item = 3; | |
cb9d24e4 TI |
475 | strcpy(uinfo->value.enumerated.name, |
476 | texts[uinfo->value.enumerated.item]); | |
1da177e4 LT |
477 | return 0; |
478 | } | |
479 | ||
97f02e05 TI |
480 | static int snd_akm4xxx_deemphasis_get(struct snd_kcontrol *kcontrol, |
481 | struct snd_ctl_elem_value *ucontrol) | |
1da177e4 | 482 | { |
97f02e05 | 483 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); |
1da177e4 LT |
484 | int chip = AK_GET_CHIP(kcontrol->private_value); |
485 | int addr = AK_GET_ADDR(kcontrol->private_value); | |
486 | int shift = AK_GET_SHIFT(kcontrol->private_value); | |
cb9d24e4 TI |
487 | ucontrol->value.enumerated.item[0] = |
488 | (snd_akm4xxx_get(ak, chip, addr) >> shift) & 3; | |
1da177e4 LT |
489 | return 0; |
490 | } | |
491 | ||
97f02e05 TI |
492 | static int snd_akm4xxx_deemphasis_put(struct snd_kcontrol *kcontrol, |
493 | struct snd_ctl_elem_value *ucontrol) | |
1da177e4 | 494 | { |
97f02e05 | 495 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); |
1da177e4 LT |
496 | int chip = AK_GET_CHIP(kcontrol->private_value); |
497 | int addr = AK_GET_ADDR(kcontrol->private_value); | |
498 | int shift = AK_GET_SHIFT(kcontrol->private_value); | |
499 | unsigned char nval = ucontrol->value.enumerated.item[0] & 3; | |
500 | int change; | |
501 | ||
cb9d24e4 TI |
502 | nval = (nval << shift) | |
503 | (snd_akm4xxx_get(ak, chip, addr) & ~(3 << shift)); | |
1da177e4 LT |
504 | change = snd_akm4xxx_get(ak, chip, addr) != nval; |
505 | if (change) | |
506 | snd_akm4xxx_write(ak, chip, addr, nval); | |
507 | return change; | |
508 | } | |
509 | ||
a5ce8890 | 510 | #define ak4xxx_switch_info snd_ctl_boolean_mono_info |
30ba6e20 JV |
511 | |
512 | static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol, | |
513 | struct snd_ctl_elem_value *ucontrol) | |
514 | { | |
515 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | |
516 | int chip = AK_GET_CHIP(kcontrol->private_value); | |
517 | int addr = AK_GET_ADDR(kcontrol->private_value); | |
518 | int shift = AK_GET_SHIFT(kcontrol->private_value); | |
519 | int invert = AK_GET_INVERT(kcontrol->private_value); | |
ea7cfcdf PH |
520 | /* we observe the (1<<shift) bit only */ |
521 | unsigned char val = snd_akm4xxx_get(ak, chip, addr) & (1<<shift); | |
30ba6e20 JV |
522 | if (invert) |
523 | val = ! val; | |
524 | ucontrol->value.integer.value[0] = (val & (1<<shift)) != 0; | |
525 | return 0; | |
526 | } | |
527 | ||
528 | static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol, | |
529 | struct snd_ctl_elem_value *ucontrol) | |
530 | { | |
531 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | |
532 | int chip = AK_GET_CHIP(kcontrol->private_value); | |
533 | int addr = AK_GET_ADDR(kcontrol->private_value); | |
534 | int shift = AK_GET_SHIFT(kcontrol->private_value); | |
535 | int invert = AK_GET_INVERT(kcontrol->private_value); | |
536 | long flag = ucontrol->value.integer.value[0]; | |
537 | unsigned char val, oval; | |
538 | int change; | |
539 | ||
540 | if (invert) | |
541 | flag = ! flag; | |
542 | oval = snd_akm4xxx_get(ak, chip, addr); | |
543 | if (flag) | |
544 | val = oval | (1<<shift); | |
545 | else | |
546 | val = oval & ~(1<<shift); | |
547 | change = (oval != val); | |
548 | if (change) | |
549 | snd_akm4xxx_write(ak, chip, addr, val); | |
550 | return change; | |
551 | } | |
552 | ||
a58e7cb1 JV |
553 | #define AK5365_NUM_INPUTS 5 |
554 | ||
02ff1324 TI |
555 | static int ak4xxx_capture_num_inputs(struct snd_akm4xxx *ak, int mixer_ch) |
556 | { | |
557 | int num_names; | |
558 | const char **input_names; | |
559 | ||
560 | input_names = ak->adc_info[mixer_ch].input_names; | |
561 | num_names = 0; | |
562 | while (num_names < AK5365_NUM_INPUTS && input_names[num_names]) | |
563 | ++num_names; | |
564 | return num_names; | |
565 | } | |
566 | ||
a58e7cb1 JV |
567 | static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol, |
568 | struct snd_ctl_elem_info *uinfo) | |
569 | { | |
570 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | |
571 | int mixer_ch = AK_GET_SHIFT(kcontrol->private_value); | |
572 | const char **input_names; | |
573 | int num_names, idx; | |
574 | ||
02ff1324 TI |
575 | num_names = ak4xxx_capture_num_inputs(ak, mixer_ch); |
576 | if (!num_names) | |
577 | return -EINVAL; | |
a58e7cb1 JV |
578 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
579 | uinfo->count = 1; | |
580 | uinfo->value.enumerated.items = num_names; | |
581 | idx = uinfo->value.enumerated.item; | |
582 | if (idx >= num_names) | |
583 | return -EINVAL; | |
02ff1324 | 584 | input_names = ak->adc_info[mixer_ch].input_names; |
a58e7cb1 JV |
585 | strncpy(uinfo->value.enumerated.name, input_names[idx], |
586 | sizeof(uinfo->value.enumerated.name)); | |
587 | return 0; | |
588 | } | |
589 | ||
590 | static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol, | |
591 | struct snd_ctl_elem_value *ucontrol) | |
592 | { | |
593 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | |
594 | int chip = AK_GET_CHIP(kcontrol->private_value); | |
595 | int addr = AK_GET_ADDR(kcontrol->private_value); | |
596 | int mask = AK_GET_MASK(kcontrol->private_value); | |
597 | unsigned char val; | |
598 | ||
599 | val = snd_akm4xxx_get(ak, chip, addr) & mask; | |
600 | ucontrol->value.enumerated.item[0] = val; | |
601 | return 0; | |
602 | } | |
603 | ||
604 | static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol, | |
605 | struct snd_ctl_elem_value *ucontrol) | |
606 | { | |
607 | struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol); | |
02ff1324 | 608 | int mixer_ch = AK_GET_SHIFT(kcontrol->private_value); |
a58e7cb1 JV |
609 | int chip = AK_GET_CHIP(kcontrol->private_value); |
610 | int addr = AK_GET_ADDR(kcontrol->private_value); | |
611 | int mask = AK_GET_MASK(kcontrol->private_value); | |
612 | unsigned char oval, val; | |
02ff1324 TI |
613 | int num_names = ak4xxx_capture_num_inputs(ak, mixer_ch); |
614 | ||
615 | if (ucontrol->value.enumerated.item[0] >= num_names) | |
616 | return -EINVAL; | |
a58e7cb1 JV |
617 | |
618 | oval = snd_akm4xxx_get(ak, chip, addr); | |
619 | val = oval & ~mask; | |
620 | val |= ucontrol->value.enumerated.item[0] & mask; | |
621 | if (val != oval) { | |
622 | snd_akm4xxx_write(ak, chip, addr, val); | |
623 | return 1; | |
624 | } | |
625 | return 0; | |
626 | } | |
627 | ||
1da177e4 LT |
628 | /* |
629 | * build AK4xxx controls | |
630 | */ | |
631 | ||
723b2b0d | 632 | static int build_dac_controls(struct snd_akm4xxx *ak) |
1da177e4 | 633 | { |
723b2b0d TI |
634 | int idx, err, mixer_ch, num_stereo; |
635 | struct snd_kcontrol_new knew; | |
1da177e4 | 636 | |
723b2b0d | 637 | mixer_ch = 0; |
c83c0c47 | 638 | for (idx = 0; idx < ak->num_dacs; ) { |
ea7cfcdf PH |
639 | /* mute control for Revolution 7.1 - AK4381 */ |
640 | if (ak->type == SND_AK4381 | |
641 | && ak->dac_info[mixer_ch].switch_name) { | |
642 | memset(&knew, 0, sizeof(knew)); | |
643 | knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | |
644 | knew.count = 1; | |
645 | knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | |
646 | knew.name = ak->dac_info[mixer_ch].switch_name; | |
647 | knew.info = ak4xxx_switch_info; | |
648 | knew.get = ak4xxx_switch_get; | |
649 | knew.put = ak4xxx_switch_put; | |
650 | knew.access = 0; | |
651 | /* register 1, bit 0 (SMUTE): 0 = normal operation, | |
652 | 1 = mute */ | |
653 | knew.private_value = | |
654 | AK_COMPOSE(idx/2, 1, 0, 0) | AK_INVERT; | |
655 | err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); | |
656 | if (err < 0) | |
657 | return err; | |
658 | } | |
723b2b0d TI |
659 | memset(&knew, 0, sizeof(knew)); |
660 | if (! ak->dac_info || ! ak->dac_info[mixer_ch].name) { | |
661 | knew.name = "DAC Volume"; | |
662 | knew.index = mixer_ch + ak->idx_offset * 2; | |
c83c0c47 | 663 | num_stereo = 1; |
c83c0c47 | 664 | } else { |
723b2b0d TI |
665 | knew.name = ak->dac_info[mixer_ch].name; |
666 | num_stereo = ak->dac_info[mixer_ch].num_channels; | |
c83c0c47 | 667 | } |
723b2b0d TI |
668 | knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
669 | knew.count = 1; | |
670 | knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | |
671 | SNDRV_CTL_ELEM_ACCESS_TLV_READ; | |
c83c0c47 | 672 | if (num_stereo == 2) { |
723b2b0d TI |
673 | knew.info = snd_akm4xxx_stereo_volume_info; |
674 | knew.get = snd_akm4xxx_stereo_volume_get; | |
675 | knew.put = snd_akm4xxx_stereo_volume_put; | |
c83c0c47 | 676 | } else { |
723b2b0d TI |
677 | knew.info = snd_akm4xxx_volume_info; |
678 | knew.get = snd_akm4xxx_volume_get; | |
679 | knew.put = snd_akm4xxx_volume_put; | |
c83c0c47 | 680 | } |
1da177e4 LT |
681 | switch (ak->type) { |
682 | case SND_AK4524: | |
cb9d24e4 | 683 | /* register 6 & 7 */ |
723b2b0d TI |
684 | knew.private_value = |
685 | AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127) | | |
686 | AK_VOL_CVT; | |
687 | knew.tlv.p = db_scale_vol_datt; | |
1da177e4 LT |
688 | break; |
689 | case SND_AK4528: | |
cb9d24e4 | 690 | /* register 4 & 5 */ |
723b2b0d TI |
691 | knew.private_value = |
692 | AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127) | | |
693 | AK_VOL_CVT; | |
694 | knew.tlv.p = db_scale_vol_datt; | |
1da177e4 LT |
695 | break; |
696 | case SND_AK4529: { | |
cb9d24e4 TI |
697 | /* registers 2-7 and b,c */ |
698 | int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb; | |
723b2b0d | 699 | knew.private_value = |
cb9d24e4 | 700 | AK_COMPOSE(0, val, 0, 255) | AK_INVERT; |
723b2b0d | 701 | knew.tlv.p = db_scale_8bit; |
1da177e4 LT |
702 | break; |
703 | } | |
704 | case SND_AK4355: | |
cb9d24e4 | 705 | /* register 4-9, chip #0 only */ |
723b2b0d TI |
706 | knew.private_value = AK_COMPOSE(0, idx + 4, 0, 255); |
707 | knew.tlv.p = db_scale_8bit; | |
1da177e4 | 708 | break; |
3479307f JV |
709 | case SND_AK4358: { |
710 | /* register 4-9 and 11-12, chip #0 only */ | |
711 | int addr = idx < 6 ? idx + 4 : idx + 5; | |
723b2b0d | 712 | knew.private_value = |
3479307f | 713 | AK_COMPOSE(0, addr, 0, 127) | AK_NEEDSMSB; |
723b2b0d | 714 | knew.tlv.p = db_scale_7bit; |
1da177e4 | 715 | break; |
3479307f | 716 | } |
1da177e4 | 717 | case SND_AK4381: |
cb9d24e4 | 718 | /* register 3 & 4 */ |
723b2b0d | 719 | knew.private_value = |
cb9d24e4 | 720 | AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255); |
723b2b0d | 721 | knew.tlv.p = db_scale_linear; |
1da177e4 | 722 | break; |
8f34692f PH |
723 | case SND_AK4620: |
724 | /* register 6 & 7 */ | |
725 | knew.private_value = | |
726 | AK_COMPOSE(idx/2, (idx%2) + 6, 0, 255); | |
727 | knew.tlv.p = db_scale_linear; | |
728 | break; | |
1da177e4 | 729 | default: |
723b2b0d | 730 | return -EINVAL; |
1da177e4 | 731 | } |
c83c0c47 | 732 | |
723b2b0d | 733 | err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); |
cb9d24e4 | 734 | if (err < 0) |
723b2b0d | 735 | return err; |
c83c0c47 JA |
736 | |
737 | idx += num_stereo; | |
738 | mixer_ch++; | |
1da177e4 | 739 | } |
723b2b0d TI |
740 | return 0; |
741 | } | |
742 | ||
743 | static int build_adc_controls(struct snd_akm4xxx *ak) | |
744 | { | |
8f34692f | 745 | int idx, err, mixer_ch, num_stereo, max_steps; |
723b2b0d TI |
746 | struct snd_kcontrol_new knew; |
747 | ||
748 | mixer_ch = 0; | |
8f34692f PH |
749 | if (ak->type == SND_AK4528) |
750 | return 0; /* no controls */ | |
723b2b0d TI |
751 | for (idx = 0; idx < ak->num_adcs;) { |
752 | memset(&knew, 0, sizeof(knew)); | |
753 | if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) { | |
754 | knew.name = "ADC Volume"; | |
755 | knew.index = mixer_ch + ak->idx_offset * 2; | |
756 | num_stereo = 1; | |
757 | } else { | |
758 | knew.name = ak->adc_info[mixer_ch].name; | |
759 | num_stereo = ak->adc_info[mixer_ch].num_channels; | |
760 | } | |
761 | knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | |
762 | knew.count = 1; | |
763 | knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | |
764 | SNDRV_CTL_ELEM_ACCESS_TLV_READ; | |
765 | if (num_stereo == 2) { | |
766 | knew.info = snd_akm4xxx_stereo_volume_info; | |
767 | knew.get = snd_akm4xxx_stereo_volume_get; | |
768 | knew.put = snd_akm4xxx_stereo_volume_put; | |
769 | } else { | |
770 | knew.info = snd_akm4xxx_volume_info; | |
771 | knew.get = snd_akm4xxx_volume_get; | |
772 | knew.put = snd_akm4xxx_volume_put; | |
773 | } | |
cb9d24e4 | 774 | /* register 4 & 5 */ |
854b66e4 | 775 | if (ak->type == SND_AK5365) |
8f34692f | 776 | max_steps = 152; |
683fe153 | 777 | else |
8f34692f PH |
778 | max_steps = 164; |
779 | knew.private_value = | |
780 | AK_COMPOSE(idx/2, (idx%2) + 4, 0, max_steps) | | |
781 | AK_VOL_CVT | AK_IPGA; | |
854b66e4 | 782 | knew.tlv.p = db_scale_vol_datt; |
723b2b0d | 783 | err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); |
683fe153 | 784 | if (err < 0) |
723b2b0d TI |
785 | return err; |
786 | ||
787 | if (ak->type == SND_AK5365 && (idx % 2) == 0) { | |
788 | if (! ak->adc_info || | |
a58e7cb1 | 789 | ! ak->adc_info[mixer_ch].switch_name) { |
723b2b0d | 790 | knew.name = "Capture Switch"; |
a58e7cb1 JV |
791 | knew.index = mixer_ch + ak->idx_offset * 2; |
792 | } else | |
723b2b0d TI |
793 | knew.name = ak->adc_info[mixer_ch].switch_name; |
794 | knew.info = ak4xxx_switch_info; | |
795 | knew.get = ak4xxx_switch_get; | |
796 | knew.put = ak4xxx_switch_put; | |
797 | knew.access = 0; | |
798 | /* register 2, bit 0 (SMUTE): 0 = normal operation, | |
799 | 1 = mute */ | |
800 | knew.private_value = | |
801 | AK_COMPOSE(idx/2, 2, 0, 0) | AK_INVERT; | |
802 | err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); | |
803 | if (err < 0) | |
804 | return err; | |
a58e7cb1 JV |
805 | |
806 | memset(&knew, 0, sizeof(knew)); | |
807 | knew.name = ak->adc_info[mixer_ch].selector_name; | |
808 | if (!knew.name) { | |
809 | knew.name = "Capture Channel"; | |
810 | knew.index = mixer_ch + ak->idx_offset * 2; | |
811 | } | |
812 | ||
813 | knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | |
814 | knew.info = ak4xxx_capture_source_info; | |
815 | knew.get = ak4xxx_capture_source_get; | |
816 | knew.put = ak4xxx_capture_source_put; | |
817 | knew.access = 0; | |
818 | /* input selector control: reg. 1, bits 0-2. | |
819 | * mis-use 'shift' to pass mixer_ch */ | |
820 | knew.private_value | |
821 | = AK_COMPOSE(idx/2, 1, mixer_ch, 0x07); | |
822 | err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); | |
823 | if (err < 0) | |
824 | return err; | |
723b2b0d | 825 | } |
30ba6e20 | 826 | |
723b2b0d TI |
827 | idx += num_stereo; |
828 | mixer_ch++; | |
683fe153 | 829 | } |
723b2b0d TI |
830 | return 0; |
831 | } | |
832 | ||
833 | static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs) | |
834 | { | |
835 | int idx, err; | |
836 | struct snd_kcontrol_new knew; | |
683fe153 | 837 | |
1da177e4 | 838 | for (idx = 0; idx < num_emphs; idx++) { |
723b2b0d TI |
839 | memset(&knew, 0, sizeof(knew)); |
840 | knew.name = "Deemphasis"; | |
841 | knew.index = idx + ak->idx_offset; | |
842 | knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | |
843 | knew.count = 1; | |
844 | knew.info = snd_akm4xxx_deemphasis_info; | |
845 | knew.get = snd_akm4xxx_deemphasis_get; | |
846 | knew.put = snd_akm4xxx_deemphasis_put; | |
1da177e4 LT |
847 | switch (ak->type) { |
848 | case SND_AK4524: | |
849 | case SND_AK4528: | |
8f34692f | 850 | case SND_AK4620: |
cb9d24e4 | 851 | /* register 3 */ |
723b2b0d | 852 | knew.private_value = AK_COMPOSE(idx, 3, 0, 0); |
1da177e4 LT |
853 | break; |
854 | case SND_AK4529: { | |
855 | int shift = idx == 3 ? 6 : (2 - idx) * 2; | |
cb9d24e4 | 856 | /* register 8 with shift */ |
723b2b0d | 857 | knew.private_value = AK_COMPOSE(0, 8, shift, 0); |
1da177e4 LT |
858 | break; |
859 | } | |
860 | case SND_AK4355: | |
861 | case SND_AK4358: | |
723b2b0d | 862 | knew.private_value = AK_COMPOSE(idx, 3, 0, 0); |
1da177e4 LT |
863 | break; |
864 | case SND_AK4381: | |
723b2b0d | 865 | knew.private_value = AK_COMPOSE(idx, 1, 1, 0); |
1da177e4 | 866 | break; |
cf93907b | 867 | default: |
723b2b0d | 868 | return -EINVAL; |
1da177e4 | 869 | } |
723b2b0d | 870 | err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); |
cb9d24e4 | 871 | if (err < 0) |
723b2b0d | 872 | return err; |
1da177e4 | 873 | } |
723b2b0d | 874 | return 0; |
1da177e4 LT |
875 | } |
876 | ||
8f34692f PH |
877 | #ifdef CONFIG_PROC_FS |
878 | static void proc_regs_read(struct snd_info_entry *entry, | |
879 | struct snd_info_buffer *buffer) | |
880 | { | |
881 | struct snd_akm4xxx *ak = (struct snd_akm4xxx *)entry->private_data; | |
882 | int reg, val, chip; | |
883 | for (chip = 0; chip < ak->num_chips; chip++) { | |
884 | for (reg = 0; reg < ak->total_regs; reg++) { | |
885 | val = snd_akm4xxx_get(ak, chip, reg); | |
886 | snd_iprintf(buffer, "chip %d: 0x%02x = 0x%02x\n", chip, | |
887 | reg, val); | |
888 | } | |
889 | } | |
890 | } | |
891 | ||
892 | static int proc_init(struct snd_akm4xxx *ak) | |
893 | { | |
894 | struct snd_info_entry *entry; | |
895 | int err; | |
896 | err = snd_card_proc_new(ak->card, ak->name, &entry); | |
897 | if (err < 0) | |
898 | return err; | |
899 | snd_info_set_text_ops(entry, ak, proc_regs_read); | |
900 | return 0; | |
901 | } | |
902 | #else /* !CONFIG_PROC_FS */ | |
e913b146 | 903 | static int proc_init(struct snd_akm4xxx *ak) { return 0; } |
8f34692f PH |
904 | #endif |
905 | ||
723b2b0d TI |
906 | int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak) |
907 | { | |
908 | int err, num_emphs; | |
909 | ||
910 | err = build_dac_controls(ak); | |
911 | if (err < 0) | |
912 | return err; | |
913 | ||
854b66e4 TI |
914 | err = build_adc_controls(ak); |
915 | if (err < 0) | |
916 | return err; | |
723b2b0d TI |
917 | if (ak->type == SND_AK4355 || ak->type == SND_AK4358) |
918 | num_emphs = 1; | |
8f34692f PH |
919 | else if (ak->type == SND_AK4620) |
920 | num_emphs = 0; | |
723b2b0d TI |
921 | else |
922 | num_emphs = ak->num_dacs / 2; | |
923 | err = build_deemphasis(ak, num_emphs); | |
8f34692f PH |
924 | if (err < 0) |
925 | return err; | |
926 | err = proc_init(ak); | |
723b2b0d TI |
927 | if (err < 0) |
928 | return err; | |
929 | ||
930 | return 0; | |
931 | } | |
cb9d24e4 TI |
932 | EXPORT_SYMBOL(snd_akm4xxx_build_controls); |
933 | ||
1da177e4 LT |
934 | static int __init alsa_akm4xxx_module_init(void) |
935 | { | |
936 | return 0; | |
937 | } | |
938 | ||
939 | static void __exit alsa_akm4xxx_module_exit(void) | |
940 | { | |
941 | } | |
942 | ||
943 | module_init(alsa_akm4xxx_module_init) | |
944 | module_exit(alsa_akm4xxx_module_exit) |