diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/i2c/other/ak4xxx-adda.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'sound/i2c/other/ak4xxx-adda.c')
-rw-r--r-- | sound/i2c/other/ak4xxx-adda.c | 501 |
1 files changed, 501 insertions, 0 deletions
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c new file mode 100644 index 000000000000..db2b7274a9d6 --- /dev/null +++ b/sound/i2c/other/ak4xxx-adda.c | |||
@@ -0,0 +1,501 @@ | |||
1 | /* | ||
2 | * ALSA driver for AK4524 / AK4528 / AK4529 / AK4355 / AK4358 / AK4381 | ||
3 | * AD and DA converters | ||
4 | * | ||
5 | * Copyright (c) 2000-2004 Jaroslav Kysela <perex@suse.cz>, | ||
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 | * | ||
22 | */ | ||
23 | |||
24 | #include <sound/driver.h> | ||
25 | #include <asm/io.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <sound/core.h> | ||
30 | #include <sound/control.h> | ||
31 | #include <sound/ak4xxx-adda.h> | ||
32 | |||
33 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>"); | ||
34 | MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters"); | ||
35 | MODULE_LICENSE("GPL"); | ||
36 | |||
37 | void snd_akm4xxx_write(akm4xxx_t *ak, int chip, unsigned char reg, unsigned char val) | ||
38 | { | ||
39 | ak->ops.lock(ak, chip); | ||
40 | ak->ops.write(ak, chip, reg, val); | ||
41 | |||
42 | /* save the data */ | ||
43 | if (ak->type == SND_AK4524 || ak->type == SND_AK4528) { | ||
44 | if ((reg != 0x04 && reg != 0x05) || (val & 0x80) == 0) | ||
45 | snd_akm4xxx_set(ak, chip, reg, val); | ||
46 | else | ||
47 | snd_akm4xxx_set_ipga(ak, chip, reg, val); | ||
48 | } else { | ||
49 | /* AK4529, or else */ | ||
50 | snd_akm4xxx_set(ak, chip, reg, val); | ||
51 | } | ||
52 | ak->ops.unlock(ak, chip); | ||
53 | } | ||
54 | |||
55 | /* | ||
56 | * reset the AKM codecs | ||
57 | * @state: 1 = reset codec, 0 = restore the registers | ||
58 | * | ||
59 | * assert the reset operation and restores the register values to the chips. | ||
60 | */ | ||
61 | void snd_akm4xxx_reset(akm4xxx_t *ak, int state) | ||
62 | { | ||
63 | unsigned int chip; | ||
64 | unsigned char reg; | ||
65 | |||
66 | switch (ak->type) { | ||
67 | case SND_AK4524: | ||
68 | case SND_AK4528: | ||
69 | for (chip = 0; chip < ak->num_dacs/2; chip++) { | ||
70 | snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03); | ||
71 | if (state) | ||
72 | continue; | ||
73 | /* DAC volumes */ | ||
74 | for (reg = 0x04; reg < (ak->type == SND_AK4528 ? 0x06 : 0x08); reg++) | ||
75 | snd_akm4xxx_write(ak, chip, reg, snd_akm4xxx_get(ak, chip, reg)); | ||
76 | if (ak->type == SND_AK4528) | ||
77 | continue; | ||
78 | /* IPGA */ | ||
79 | for (reg = 0x04; reg < 0x06; reg++) | ||
80 | snd_akm4xxx_write(ak, chip, reg, snd_akm4xxx_get_ipga(ak, chip, reg)); | ||
81 | } | ||
82 | break; | ||
83 | case SND_AK4529: | ||
84 | /* FIXME: needed for ak4529? */ | ||
85 | break; | ||
86 | case SND_AK4355: | ||
87 | case SND_AK4358: | ||
88 | if (state) { | ||
89 | snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */ | ||
90 | return; | ||
91 | } | ||
92 | for (reg = 0x00; reg < 0x0b; reg++) | ||
93 | if (reg != 0x01) | ||
94 | snd_akm4xxx_write(ak, 0, reg, snd_akm4xxx_get(ak, 0, reg)); | ||
95 | snd_akm4xxx_write(ak, 0, 0x01, 0x01); /* un-reset, unmute */ | ||
96 | break; | ||
97 | case SND_AK4381: | ||
98 | for (chip = 0; chip < ak->num_dacs/2; chip++) { | ||
99 | snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f); | ||
100 | if (state) | ||
101 | continue; | ||
102 | for (reg = 0x01; reg < 0x05; reg++) | ||
103 | snd_akm4xxx_write(ak, chip, reg, snd_akm4xxx_get(ak, chip, reg)); | ||
104 | } | ||
105 | break; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | * initialize all the ak4xxx chips | ||
111 | */ | ||
112 | void snd_akm4xxx_init(akm4xxx_t *ak) | ||
113 | { | ||
114 | static unsigned char inits_ak4524[] = { | ||
115 | 0x00, 0x07, /* 0: all power up */ | ||
116 | 0x01, 0x00, /* 1: ADC/DAC reset */ | ||
117 | 0x02, 0x60, /* 2: 24bit I2S */ | ||
118 | 0x03, 0x19, /* 3: deemphasis off */ | ||
119 | 0x01, 0x03, /* 1: ADC/DAC enable */ | ||
120 | 0x04, 0x00, /* 4: ADC left muted */ | ||
121 | 0x05, 0x00, /* 5: ADC right muted */ | ||
122 | 0x04, 0x80, /* 4: ADC IPGA gain 0dB */ | ||
123 | 0x05, 0x80, /* 5: ADC IPGA gain 0dB */ | ||
124 | 0x06, 0x00, /* 6: DAC left muted */ | ||
125 | 0x07, 0x00, /* 7: DAC right muted */ | ||
126 | 0xff, 0xff | ||
127 | }; | ||
128 | static unsigned char inits_ak4528[] = { | ||
129 | 0x00, 0x07, /* 0: all power up */ | ||
130 | 0x01, 0x00, /* 1: ADC/DAC reset */ | ||
131 | 0x02, 0x60, /* 2: 24bit I2S */ | ||
132 | 0x03, 0x0d, /* 3: deemphasis off, turn LR highpass filters on */ | ||
133 | 0x01, 0x03, /* 1: ADC/DAC enable */ | ||
134 | 0x04, 0x00, /* 4: ADC left muted */ | ||
135 | 0x05, 0x00, /* 5: ADC right muted */ | ||
136 | 0xff, 0xff | ||
137 | }; | ||
138 | static unsigned char inits_ak4529[] = { | ||
139 | 0x09, 0x01, /* 9: ATS=0, RSTN=1 */ | ||
140 | 0x0a, 0x3f, /* A: all power up, no zero/overflow detection */ | ||
141 | 0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */ | ||
142 | 0x01, 0x00, /* 1: ACKS=0, ADC, loop off */ | ||
143 | 0x02, 0xff, /* 2: LOUT1 muted */ | ||
144 | 0x03, 0xff, /* 3: ROUT1 muted */ | ||
145 | 0x04, 0xff, /* 4: LOUT2 muted */ | ||
146 | 0x05, 0xff, /* 5: ROUT2 muted */ | ||
147 | 0x06, 0xff, /* 6: LOUT3 muted */ | ||
148 | 0x07, 0xff, /* 7: ROUT3 muted */ | ||
149 | 0x0b, 0xff, /* B: LOUT4 muted */ | ||
150 | 0x0c, 0xff, /* C: ROUT4 muted */ | ||
151 | 0x08, 0x55, /* 8: deemphasis all off */ | ||
152 | 0xff, 0xff | ||
153 | }; | ||
154 | static unsigned char inits_ak4355[] = { | ||
155 | 0x01, 0x02, /* 1: reset and soft-mute */ | ||
156 | 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, disable DZF, sharp roll-off, RSTN#=0 */ | ||
157 | 0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */ | ||
158 | // 0x02, 0x2e, /* quad speed */ | ||
159 | 0x03, 0x01, /* 3: de-emphasis off */ | ||
160 | 0x04, 0x00, /* 4: LOUT1 volume muted */ | ||
161 | 0x05, 0x00, /* 5: ROUT1 volume muted */ | ||
162 | 0x06, 0x00, /* 6: LOUT2 volume muted */ | ||
163 | 0x07, 0x00, /* 7: ROUT2 volume muted */ | ||
164 | 0x08, 0x00, /* 8: LOUT3 volume muted */ | ||
165 | 0x09, 0x00, /* 9: ROUT3 volume muted */ | ||
166 | 0x0a, 0x00, /* a: DATT speed=0, ignore DZF */ | ||
167 | 0x01, 0x01, /* 1: un-reset, unmute */ | ||
168 | 0xff, 0xff | ||
169 | }; | ||
170 | static unsigned char inits_ak4358[] = { | ||
171 | 0x01, 0x02, /* 1: reset and soft-mute */ | ||
172 | 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, disable DZF, sharp roll-off, RSTN#=0 */ | ||
173 | 0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */ | ||
174 | // 0x02, 0x2e, /* quad speed */ | ||
175 | 0x03, 0x01, /* 3: de-emphasis off */ | ||
176 | 0x04, 0x00, /* 4: LOUT1 volume muted */ | ||
177 | 0x05, 0x00, /* 5: ROUT1 volume muted */ | ||
178 | 0x06, 0x00, /* 6: LOUT2 volume muted */ | ||
179 | 0x07, 0x00, /* 7: ROUT2 volume muted */ | ||
180 | 0x08, 0x00, /* 8: LOUT3 volume muted */ | ||
181 | 0x09, 0x00, /* 9: ROUT3 volume muted */ | ||
182 | 0x0b, 0x00, /* b: LOUT4 volume muted */ | ||
183 | 0x0c, 0x00, /* c: ROUT4 volume muted */ | ||
184 | 0x0a, 0x00, /* a: DATT speed=0, ignore DZF */ | ||
185 | 0x01, 0x01, /* 1: un-reset, unmute */ | ||
186 | 0xff, 0xff | ||
187 | }; | ||
188 | static unsigned char inits_ak4381[] = { | ||
189 | 0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */ | ||
190 | 0x01, 0x02, /* 1: de-emphasis off, normal speed, sharp roll-off, DZF off */ | ||
191 | // 0x01, 0x12, /* quad speed */ | ||
192 | 0x02, 0x00, /* 2: DZF disabled */ | ||
193 | 0x03, 0x00, /* 3: LATT 0 */ | ||
194 | 0x04, 0x00, /* 4: RATT 0 */ | ||
195 | 0x00, 0x0f, /* 0: power-up, un-reset */ | ||
196 | 0xff, 0xff | ||
197 | }; | ||
198 | |||
199 | int chip, num_chips; | ||
200 | unsigned char *ptr, reg, data, *inits; | ||
201 | |||
202 | switch (ak->type) { | ||
203 | case SND_AK4524: | ||
204 | inits = inits_ak4524; | ||
205 | num_chips = ak->num_dacs / 2; | ||
206 | break; | ||
207 | case SND_AK4528: | ||
208 | inits = inits_ak4528; | ||
209 | num_chips = ak->num_dacs / 2; | ||
210 | break; | ||
211 | case SND_AK4529: | ||
212 | inits = inits_ak4529; | ||
213 | num_chips = 1; | ||
214 | break; | ||
215 | case SND_AK4355: | ||
216 | inits = inits_ak4355; | ||
217 | num_chips = 1; | ||
218 | break; | ||
219 | case SND_AK4358: | ||
220 | inits = inits_ak4358; | ||
221 | num_chips = 1; | ||
222 | break; | ||
223 | case SND_AK4381: | ||
224 | inits = inits_ak4381; | ||
225 | num_chips = ak->num_dacs / 2; | ||
226 | break; | ||
227 | default: | ||
228 | snd_BUG(); | ||
229 | return; | ||
230 | } | ||
231 | |||
232 | for (chip = 0; chip < num_chips; chip++) { | ||
233 | ptr = inits; | ||
234 | while (*ptr != 0xff) { | ||
235 | reg = *ptr++; | ||
236 | data = *ptr++; | ||
237 | snd_akm4xxx_write(ak, chip, reg, data); | ||
238 | } | ||
239 | } | ||
240 | } | ||
241 | |||
242 | #define AK_GET_CHIP(val) (((val) >> 8) & 0xff) | ||
243 | #define AK_GET_ADDR(val) ((val) & 0xff) | ||
244 | #define AK_GET_SHIFT(val) (((val) >> 16) & 0x7f) | ||
245 | #define AK_GET_INVERT(val) (((val) >> 23) & 1) | ||
246 | #define AK_GET_MASK(val) (((val) >> 24) & 0xff) | ||
247 | #define AK_COMPOSE(chip,addr,shift,mask) (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24)) | ||
248 | #define AK_INVERT (1<<23) | ||
249 | |||
250 | static int snd_akm4xxx_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | ||
251 | { | ||
252 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); | ||
253 | |||
254 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
255 | uinfo->count = 1; | ||
256 | uinfo->value.integer.min = 0; | ||
257 | uinfo->value.integer.max = mask; | ||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | static int snd_akm4xxx_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
262 | { | ||
263 | akm4xxx_t *ak = snd_kcontrol_chip(kcontrol); | ||
264 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
265 | int addr = AK_GET_ADDR(kcontrol->private_value); | ||
266 | int invert = AK_GET_INVERT(kcontrol->private_value); | ||
267 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); | ||
268 | unsigned char val = snd_akm4xxx_get(ak, chip, addr); | ||
269 | |||
270 | ucontrol->value.integer.value[0] = invert ? mask - val : val; | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static int snd_akm4xxx_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
275 | { | ||
276 | akm4xxx_t *ak = snd_kcontrol_chip(kcontrol); | ||
277 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
278 | int addr = AK_GET_ADDR(kcontrol->private_value); | ||
279 | int invert = AK_GET_INVERT(kcontrol->private_value); | ||
280 | unsigned int mask = AK_GET_MASK(kcontrol->private_value); | ||
281 | unsigned char nval = ucontrol->value.integer.value[0] % (mask+1); | ||
282 | int change; | ||
283 | |||
284 | if (invert) | ||
285 | nval = mask - nval; | ||
286 | change = snd_akm4xxx_get(ak, chip, addr) != nval; | ||
287 | if (change) | ||
288 | snd_akm4xxx_write(ak, chip, addr, nval); | ||
289 | return change; | ||
290 | } | ||
291 | |||
292 | static int snd_akm4xxx_ipga_gain_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | ||
293 | { | ||
294 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
295 | uinfo->count = 1; | ||
296 | uinfo->value.integer.min = 0; | ||
297 | uinfo->value.integer.max = 36; | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static int snd_akm4xxx_ipga_gain_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
302 | { | ||
303 | akm4xxx_t *ak = snd_kcontrol_chip(kcontrol); | ||
304 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
305 | int addr = AK_GET_ADDR(kcontrol->private_value); | ||
306 | ucontrol->value.integer.value[0] = snd_akm4xxx_get_ipga(ak, chip, addr) & 0x7f; | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static int snd_akm4xxx_ipga_gain_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
311 | { | ||
312 | akm4xxx_t *ak = snd_kcontrol_chip(kcontrol); | ||
313 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
314 | int addr = AK_GET_ADDR(kcontrol->private_value); | ||
315 | unsigned char nval = (ucontrol->value.integer.value[0] % 37) | 0x80; | ||
316 | int change = snd_akm4xxx_get_ipga(ak, chip, addr) != nval; | ||
317 | if (change) | ||
318 | snd_akm4xxx_write(ak, chip, addr, nval); | ||
319 | return change; | ||
320 | } | ||
321 | |||
322 | static int snd_akm4xxx_deemphasis_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) | ||
323 | { | ||
324 | static char *texts[4] = { | ||
325 | "44.1kHz", "Off", "48kHz", "32kHz", | ||
326 | }; | ||
327 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
328 | uinfo->count = 1; | ||
329 | uinfo->value.enumerated.items = 4; | ||
330 | if (uinfo->value.enumerated.item >= 4) | ||
331 | uinfo->value.enumerated.item = 3; | ||
332 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | static int snd_akm4xxx_deemphasis_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
337 | { | ||
338 | akm4xxx_t *ak = snd_kcontrol_chip(kcontrol); | ||
339 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
340 | int addr = AK_GET_ADDR(kcontrol->private_value); | ||
341 | int shift = AK_GET_SHIFT(kcontrol->private_value); | ||
342 | ucontrol->value.enumerated.item[0] = (snd_akm4xxx_get(ak, chip, addr) >> shift) & 3; | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static int snd_akm4xxx_deemphasis_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) | ||
347 | { | ||
348 | akm4xxx_t *ak = snd_kcontrol_chip(kcontrol); | ||
349 | int chip = AK_GET_CHIP(kcontrol->private_value); | ||
350 | int addr = AK_GET_ADDR(kcontrol->private_value); | ||
351 | int shift = AK_GET_SHIFT(kcontrol->private_value); | ||
352 | unsigned char nval = ucontrol->value.enumerated.item[0] & 3; | ||
353 | int change; | ||
354 | |||
355 | nval = (nval << shift) | (snd_akm4xxx_get(ak, chip, addr) & ~(3 << shift)); | ||
356 | change = snd_akm4xxx_get(ak, chip, addr) != nval; | ||
357 | if (change) | ||
358 | snd_akm4xxx_write(ak, chip, addr, nval); | ||
359 | return change; | ||
360 | } | ||
361 | |||
362 | /* | ||
363 | * build AK4xxx controls | ||
364 | */ | ||
365 | |||
366 | int snd_akm4xxx_build_controls(akm4xxx_t *ak) | ||
367 | { | ||
368 | unsigned int idx, num_emphs; | ||
369 | snd_kcontrol_t *ctl; | ||
370 | int err; | ||
371 | |||
372 | ctl = kmalloc(sizeof(*ctl), GFP_KERNEL); | ||
373 | if (! ctl) | ||
374 | return -ENOMEM; | ||
375 | |||
376 | for (idx = 0; idx < ak->num_dacs; ++idx) { | ||
377 | memset(ctl, 0, sizeof(*ctl)); | ||
378 | strcpy(ctl->id.name, "DAC Volume"); | ||
379 | ctl->id.index = idx + ak->idx_offset * 2; | ||
380 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
381 | ctl->count = 1; | ||
382 | ctl->info = snd_akm4xxx_volume_info; | ||
383 | ctl->get = snd_akm4xxx_volume_get; | ||
384 | ctl->put = snd_akm4xxx_volume_put; | ||
385 | switch (ak->type) { | ||
386 | case SND_AK4524: | ||
387 | ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127); /* register 6 & 7 */ | ||
388 | break; | ||
389 | case SND_AK4528: | ||
390 | ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */ | ||
391 | break; | ||
392 | case SND_AK4529: { | ||
393 | int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb; /* registers 2-7 and b,c */ | ||
394 | ctl->private_value = AK_COMPOSE(0, val, 0, 255) | AK_INVERT; | ||
395 | break; | ||
396 | } | ||
397 | case SND_AK4355: | ||
398 | ctl->private_value = AK_COMPOSE(0, idx + 4, 0, 255); /* register 4-9, chip #0 only */ | ||
399 | break; | ||
400 | case SND_AK4358: | ||
401 | if (idx >= 6) | ||
402 | ctl->private_value = AK_COMPOSE(0, idx + 5, 0, 255); /* register 4-9, chip #0 only */ | ||
403 | else | ||
404 | ctl->private_value = AK_COMPOSE(0, idx + 4, 0, 255); /* register 4-9, chip #0 only */ | ||
405 | break; | ||
406 | case SND_AK4381: | ||
407 | ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255); /* register 3 & 4 */ | ||
408 | break; | ||
409 | default: | ||
410 | err = -EINVAL; | ||
411 | goto __error; | ||
412 | } | ||
413 | ctl->private_data = ak; | ||
414 | if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0) | ||
415 | goto __error; | ||
416 | } | ||
417 | for (idx = 0; idx < ak->num_adcs && ak->type == SND_AK4524; ++idx) { | ||
418 | memset(ctl, 0, sizeof(*ctl)); | ||
419 | strcpy(ctl->id.name, "ADC Volume"); | ||
420 | ctl->id.index = idx + ak->idx_offset * 2; | ||
421 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
422 | ctl->count = 1; | ||
423 | ctl->info = snd_akm4xxx_volume_info; | ||
424 | ctl->get = snd_akm4xxx_volume_get; | ||
425 | ctl->put = snd_akm4xxx_volume_put; | ||
426 | ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */ | ||
427 | ctl->private_data = ak; | ||
428 | if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0) | ||
429 | goto __error; | ||
430 | |||
431 | memset(ctl, 0, sizeof(*ctl)); | ||
432 | strcpy(ctl->id.name, "IPGA Analog Capture Volume"); | ||
433 | ctl->id.index = idx + ak->idx_offset * 2; | ||
434 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
435 | ctl->count = 1; | ||
436 | ctl->info = snd_akm4xxx_ipga_gain_info; | ||
437 | ctl->get = snd_akm4xxx_ipga_gain_get; | ||
438 | ctl->put = snd_akm4xxx_ipga_gain_put; | ||
439 | ctl->private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 0); /* register 4 & 5 */ | ||
440 | ctl->private_data = ak; | ||
441 | if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0) | ||
442 | goto __error; | ||
443 | } | ||
444 | if (ak->type == SND_AK4355 || ak->type == SND_AK4358) | ||
445 | num_emphs = 1; | ||
446 | else | ||
447 | num_emphs = ak->num_dacs / 2; | ||
448 | for (idx = 0; idx < num_emphs; idx++) { | ||
449 | memset(ctl, 0, sizeof(*ctl)); | ||
450 | strcpy(ctl->id.name, "Deemphasis"); | ||
451 | ctl->id.index = idx + ak->idx_offset; | ||
452 | ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
453 | ctl->count = 1; | ||
454 | ctl->info = snd_akm4xxx_deemphasis_info; | ||
455 | ctl->get = snd_akm4xxx_deemphasis_get; | ||
456 | ctl->put = snd_akm4xxx_deemphasis_put; | ||
457 | switch (ak->type) { | ||
458 | case SND_AK4524: | ||
459 | case SND_AK4528: | ||
460 | ctl->private_value = AK_COMPOSE(idx, 3, 0, 0); /* register 3 */ | ||
461 | break; | ||
462 | case SND_AK4529: { | ||
463 | int shift = idx == 3 ? 6 : (2 - idx) * 2; | ||
464 | ctl->private_value = AK_COMPOSE(0, 8, shift, 0); /* register 8 with shift */ | ||
465 | break; | ||
466 | } | ||
467 | case SND_AK4355: | ||
468 | case SND_AK4358: | ||
469 | ctl->private_value = AK_COMPOSE(idx, 3, 0, 0); | ||
470 | break; | ||
471 | case SND_AK4381: | ||
472 | ctl->private_value = AK_COMPOSE(idx, 1, 1, 0); | ||
473 | break; | ||
474 | } | ||
475 | ctl->private_data = ak; | ||
476 | if ((err = snd_ctl_add(ak->card, snd_ctl_new(ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0) | ||
477 | goto __error; | ||
478 | } | ||
479 | err = 0; | ||
480 | |||
481 | __error: | ||
482 | kfree(ctl); | ||
483 | return err; | ||
484 | } | ||
485 | |||
486 | static int __init alsa_akm4xxx_module_init(void) | ||
487 | { | ||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | static void __exit alsa_akm4xxx_module_exit(void) | ||
492 | { | ||
493 | } | ||
494 | |||
495 | module_init(alsa_akm4xxx_module_init) | ||
496 | module_exit(alsa_akm4xxx_module_exit) | ||
497 | |||
498 | EXPORT_SYMBOL(snd_akm4xxx_write); | ||
499 | EXPORT_SYMBOL(snd_akm4xxx_reset); | ||
500 | EXPORT_SYMBOL(snd_akm4xxx_init); | ||
501 | EXPORT_SYMBOL(snd_akm4xxx_build_controls); | ||