blob: 39bb03add7e17be5e8979507319daa69a299cdbc [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ALSA driver for AK4524 / AK4528 / AK4529 / AK4355 / AK4358 / AK4381
3 * AD and DA converters
4 *
Jaroslav Kyselac1017a42007-10-15 09:50:19 +02005 * Copyright (c) 2000-2004 Jaroslav Kysela <perex@perex.cz>,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * 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>
Takashi Iwai723b2b02006-08-30 16:49:54 +020031#include <sound/tlv.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <sound/ak4xxx-adda.h>
33
Jaroslav Kyselac1017a42007-10-15 09:50:19 +020034MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>");
Linus Torvalds1da177e2005-04-16 15:20:36 -070035MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters");
36MODULE_LICENSE("GPL");
37
Takashi Iwai723b2b02006-08-30 16:49:54 +020038/* write the given register and save the data to the cache */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020039void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg,
40 unsigned char val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070041{
42 ak->ops.lock(ak, chip);
43 ak->ops.write(ak, chip, reg, val);
44
45 /* save the data */
Takashi Iwai854b66e2006-09-08 12:27:38 +020046 snd_akm4xxx_set(ak, chip, reg, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -070047 ak->ops.unlock(ak, chip);
48}
49
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020050EXPORT_SYMBOL(snd_akm4xxx_write);
51
52/* reset procedure for AK4524 and AK4528 */
53static void ak4524_reset(struct snd_akm4xxx *ak, int state)
54{
55 unsigned int chip;
56 unsigned char reg, maxreg;
57
58 if (ak->type == SND_AK4528)
59 maxreg = 0x06;
60 else
61 maxreg = 0x08;
62 for (chip = 0; chip < ak->num_dacs/2; chip++) {
63 snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03);
64 if (state)
65 continue;
66 /* DAC volumes */
67 for (reg = 0x04; reg < maxreg; reg++)
68 snd_akm4xxx_write(ak, chip, reg,
69 snd_akm4xxx_get(ak, chip, reg));
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020070 }
71}
72
73/* reset procedure for AK4355 and AK4358 */
74static void ak4355_reset(struct snd_akm4xxx *ak, int state)
75{
76 unsigned char reg;
77
78 if (state) {
79 snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */
80 return;
81 }
82 for (reg = 0x00; reg < 0x0b; reg++)
83 if (reg != 0x01)
84 snd_akm4xxx_write(ak, 0, reg,
85 snd_akm4xxx_get(ak, 0, reg));
86 snd_akm4xxx_write(ak, 0, 0x01, 0x01); /* un-reset, unmute */
87}
88
89/* reset procedure for AK4381 */
90static void ak4381_reset(struct snd_akm4xxx *ak, int state)
91{
92 unsigned int chip;
93 unsigned char reg;
94
95 for (chip = 0; chip < ak->num_dacs/2; chip++) {
96 snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f);
97 if (state)
98 continue;
99 for (reg = 0x01; reg < 0x05; reg++)
100 snd_akm4xxx_write(ak, chip, reg,
101 snd_akm4xxx_get(ak, chip, reg));
102 }
103}
104
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105/*
106 * reset the AKM codecs
107 * @state: 1 = reset codec, 0 = restore the registers
108 *
109 * assert the reset operation and restores the register values to the chips.
110 */
Takashi Iwai97f02e02005-11-17 14:17:19 +0100111void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 switch (ak->type) {
114 case SND_AK4524:
115 case SND_AK4528:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200116 ak4524_reset(ak, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 break;
118 case SND_AK4529:
119 /* FIXME: needed for ak4529? */
120 break;
121 case SND_AK4355:
122 case SND_AK4358:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200123 ak4355_reset(ak, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 break;
125 case SND_AK4381:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200126 ak4381_reset(ak, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 break;
Takashi Iwaicf939072006-08-09 14:33:27 +0200128 default:
129 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 }
131}
132
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200133EXPORT_SYMBOL(snd_akm4xxx_reset);
134
Takashi Iwai723b2b02006-08-30 16:49:54 +0200135
136/*
137 * Volume conversion table for non-linear volumes
138 * from -63.5dB (mute) to 0dB step 0.5dB
139 *
140 * Used for AK4524 input/ouput attenuation, AK4528, and
141 * AK5365 input attenuation
142 */
Takashi Iwai517400c2007-01-29 15:27:56 +0100143static const unsigned char vol_cvt_datt[128] = {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200144 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04,
145 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06,
146 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a,
147 0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f,
148 0x10, 0x10, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14,
149 0x15, 0x16, 0x17, 0x17, 0x18, 0x19, 0x1a, 0x1c,
150 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x23,
151 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, 0x2b, 0x2d,
152 0x2e, 0x30, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
153 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3e, 0x3f, 0x40,
154 0x41, 0x42, 0x43, 0x44, 0x46, 0x47, 0x48, 0x4a,
155 0x4b, 0x4d, 0x4e, 0x50, 0x51, 0x52, 0x53, 0x54,
156 0x55, 0x56, 0x58, 0x59, 0x5b, 0x5c, 0x5e, 0x5f,
157 0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x69,
158 0x6a, 0x6c, 0x6d, 0x6f, 0x70, 0x71, 0x72, 0x73,
159 0x75, 0x76, 0x77, 0x79, 0x7a, 0x7c, 0x7d, 0x7f,
160};
161
162/*
163 * dB tables
164 */
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100165static const DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
166static const DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
167static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
168static const DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200169
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170/*
171 * initialize all the ak4xxx chips
172 */
Takashi Iwai97f02e02005-11-17 14:17:19 +0100173void snd_akm4xxx_init(struct snd_akm4xxx *ak)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174{
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100175 static const unsigned char inits_ak4524[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 0x00, 0x07, /* 0: all power up */
177 0x01, 0x00, /* 1: ADC/DAC reset */
178 0x02, 0x60, /* 2: 24bit I2S */
179 0x03, 0x19, /* 3: deemphasis off */
180 0x01, 0x03, /* 1: ADC/DAC enable */
181 0x04, 0x00, /* 4: ADC left muted */
182 0x05, 0x00, /* 5: ADC right muted */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 0x06, 0x00, /* 6: DAC left muted */
184 0x07, 0x00, /* 7: DAC right muted */
185 0xff, 0xff
186 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100187 static const unsigned char inits_ak4528[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 0x00, 0x07, /* 0: all power up */
189 0x01, 0x00, /* 1: ADC/DAC reset */
190 0x02, 0x60, /* 2: 24bit I2S */
191 0x03, 0x0d, /* 3: deemphasis off, turn LR highpass filters on */
192 0x01, 0x03, /* 1: ADC/DAC enable */
193 0x04, 0x00, /* 4: ADC left muted */
194 0x05, 0x00, /* 5: ADC right muted */
195 0xff, 0xff
196 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100197 static const unsigned char inits_ak4529[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 0x09, 0x01, /* 9: ATS=0, RSTN=1 */
199 0x0a, 0x3f, /* A: all power up, no zero/overflow detection */
200 0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */
201 0x01, 0x00, /* 1: ACKS=0, ADC, loop off */
202 0x02, 0xff, /* 2: LOUT1 muted */
203 0x03, 0xff, /* 3: ROUT1 muted */
204 0x04, 0xff, /* 4: LOUT2 muted */
205 0x05, 0xff, /* 5: ROUT2 muted */
206 0x06, 0xff, /* 6: LOUT3 muted */
207 0x07, 0xff, /* 7: ROUT3 muted */
208 0x0b, 0xff, /* B: LOUT4 muted */
209 0x0c, 0xff, /* C: ROUT4 muted */
210 0x08, 0x55, /* 8: deemphasis all off */
211 0xff, 0xff
212 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100213 static const unsigned char inits_ak4355[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 0x01, 0x02, /* 1: reset and soft-mute */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200215 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
216 * disable DZF, sharp roll-off, RSTN#=0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
218 // 0x02, 0x2e, /* quad speed */
219 0x03, 0x01, /* 3: de-emphasis off */
220 0x04, 0x00, /* 4: LOUT1 volume muted */
221 0x05, 0x00, /* 5: ROUT1 volume muted */
222 0x06, 0x00, /* 6: LOUT2 volume muted */
223 0x07, 0x00, /* 7: ROUT2 volume muted */
224 0x08, 0x00, /* 8: LOUT3 volume muted */
225 0x09, 0x00, /* 9: ROUT3 volume muted */
226 0x0a, 0x00, /* a: DATT speed=0, ignore DZF */
227 0x01, 0x01, /* 1: un-reset, unmute */
228 0xff, 0xff
229 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100230 static const unsigned char inits_ak4358[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 0x01, 0x02, /* 1: reset and soft-mute */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200232 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
233 * disable DZF, sharp roll-off, RSTN#=0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
235 // 0x02, 0x2e, /* quad speed */
236 0x03, 0x01, /* 3: de-emphasis off */
237 0x04, 0x00, /* 4: LOUT1 volume muted */
238 0x05, 0x00, /* 5: ROUT1 volume muted */
239 0x06, 0x00, /* 6: LOUT2 volume muted */
240 0x07, 0x00, /* 7: ROUT2 volume muted */
241 0x08, 0x00, /* 8: LOUT3 volume muted */
242 0x09, 0x00, /* 9: ROUT3 volume muted */
243 0x0b, 0x00, /* b: LOUT4 volume muted */
244 0x0c, 0x00, /* c: ROUT4 volume muted */
245 0x0a, 0x00, /* a: DATT speed=0, ignore DZF */
246 0x01, 0x01, /* 1: un-reset, unmute */
247 0xff, 0xff
248 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100249 static const unsigned char inits_ak4381[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200251 0x01, 0x02, /* 1: de-emphasis off, normal speed,
252 * sharp roll-off, DZF off */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 // 0x01, 0x12, /* quad speed */
254 0x02, 0x00, /* 2: DZF disabled */
255 0x03, 0x00, /* 3: LATT 0 */
256 0x04, 0x00, /* 4: RATT 0 */
257 0x00, 0x0f, /* 0: power-up, un-reset */
258 0xff, 0xff
259 };
260
261 int chip, num_chips;
Takashi Iwai517400c2007-01-29 15:27:56 +0100262 const unsigned char *ptr, *inits;
263 unsigned char reg, data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
Takashi Iwai723b2b02006-08-30 16:49:54 +0200265 memset(ak->images, 0, sizeof(ak->images));
266 memset(ak->volumes, 0, sizeof(ak->volumes));
267
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 switch (ak->type) {
269 case SND_AK4524:
270 inits = inits_ak4524;
271 num_chips = ak->num_dacs / 2;
272 break;
273 case SND_AK4528:
274 inits = inits_ak4528;
275 num_chips = ak->num_dacs / 2;
276 break;
277 case SND_AK4529:
278 inits = inits_ak4529;
279 num_chips = 1;
280 break;
281 case SND_AK4355:
282 inits = inits_ak4355;
283 num_chips = 1;
284 break;
285 case SND_AK4358:
286 inits = inits_ak4358;
287 num_chips = 1;
288 break;
289 case SND_AK4381:
290 inits = inits_ak4381;
291 num_chips = ak->num_dacs / 2;
292 break;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200293 case SND_AK5365:
294 /* FIXME: any init sequence? */
295 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 default:
297 snd_BUG();
298 return;
299 }
300
301 for (chip = 0; chip < num_chips; chip++) {
302 ptr = inits;
303 while (*ptr != 0xff) {
304 reg = *ptr++;
305 data = *ptr++;
306 snd_akm4xxx_write(ak, chip, reg, data);
307 }
308 }
309}
310
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200311EXPORT_SYMBOL(snd_akm4xxx_init);
312
Takashi Iwai723b2b02006-08-30 16:49:54 +0200313/*
314 * Mixer callbacks
315 */
Takashi Iwai854b66e2006-09-08 12:27:38 +0200316#define AK_IPGA (1<<20) /* including IPGA */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200317#define AK_VOL_CVT (1<<21) /* need dB conversion */
318#define AK_NEEDSMSB (1<<22) /* need MSB update bit */
319#define AK_INVERT (1<<23) /* data is inverted */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320#define AK_GET_CHIP(val) (((val) >> 8) & 0xff)
321#define AK_GET_ADDR(val) ((val) & 0xff)
Takashi Iwai854b66e2006-09-08 12:27:38 +0200322#define AK_GET_SHIFT(val) (((val) >> 16) & 0x0f)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200323#define AK_GET_VOL_CVT(val) (((val) >> 21) & 1)
Takashi Iwai854b66e2006-09-08 12:27:38 +0200324#define AK_GET_IPGA(val) (((val) >> 20) & 1)
Jochen Voss34793072006-08-23 18:35:35 +0200325#define AK_GET_NEEDSMSB(val) (((val) >> 22) & 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326#define AK_GET_INVERT(val) (((val) >> 23) & 1)
327#define AK_GET_MASK(val) (((val) >> 24) & 0xff)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200328#define AK_COMPOSE(chip,addr,shift,mask) \
329 (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
Takashi Iwai97f02e02005-11-17 14:17:19 +0100331static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol,
332 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333{
334 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
335
336 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
337 uinfo->count = 1;
338 uinfo->value.integer.min = 0;
339 uinfo->value.integer.max = mask;
340 return 0;
341}
342
Takashi Iwai97f02e02005-11-17 14:17:19 +0100343static int snd_akm4xxx_volume_get(struct snd_kcontrol *kcontrol,
344 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100346 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347 int chip = AK_GET_CHIP(kcontrol->private_value);
348 int addr = AK_GET_ADDR(kcontrol->private_value);
Jochen Voss34793072006-08-23 18:35:35 +0200349
Takashi Iwai723b2b02006-08-30 16:49:54 +0200350 ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 return 0;
352}
353
Takashi Iwai723b2b02006-08-30 16:49:54 +0200354static int put_ak_reg(struct snd_kcontrol *kcontrol, int addr,
355 unsigned char nval)
356{
357 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
358 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
359 int chip = AK_GET_CHIP(kcontrol->private_value);
360
361 if (snd_akm4xxx_get_vol(ak, chip, addr) == nval)
362 return 0;
363
364 snd_akm4xxx_set_vol(ak, chip, addr, nval);
Takashi Iwai854b66e2006-09-08 12:27:38 +0200365 if (AK_GET_VOL_CVT(kcontrol->private_value) && nval < 128)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200366 nval = vol_cvt_datt[nval];
Takashi Iwai854b66e2006-09-08 12:27:38 +0200367 if (AK_GET_IPGA(kcontrol->private_value) && nval >= 128)
368 nval++; /* need to correct + 1 since both 127 and 128 are 0dB */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200369 if (AK_GET_INVERT(kcontrol->private_value))
370 nval = mask - nval;
371 if (AK_GET_NEEDSMSB(kcontrol->private_value))
372 nval |= 0x80;
373 snd_akm4xxx_write(ak, chip, addr, nval);
374 return 1;
375}
376
Takashi Iwai97f02e02005-11-17 14:17:19 +0100377static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
378 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379{
Takashi Iwai02ff1322007-11-15 16:15:29 +0100380 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
381 unsigned int val = ucontrol->value.integer.value[0];
382 if (val > mask)
383 return -EINVAL;
384 return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value), val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385}
386
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200387static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol,
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200388 struct snd_ctl_elem_info *uinfo)
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200389{
390 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
391
392 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
393 uinfo->count = 2;
394 uinfo->value.integer.min = 0;
395 uinfo->value.integer.max = mask;
396 return 0;
397}
398
399static int snd_akm4xxx_stereo_volume_get(struct snd_kcontrol *kcontrol,
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200400 struct snd_ctl_elem_value *ucontrol)
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200401{
402 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
403 int chip = AK_GET_CHIP(kcontrol->private_value);
404 int addr = AK_GET_ADDR(kcontrol->private_value);
Jochen Voss34793072006-08-23 18:35:35 +0200405
Takashi Iwai723b2b02006-08-30 16:49:54 +0200406 ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
407 ucontrol->value.integer.value[1] = snd_akm4xxx_get_vol(ak, chip, addr+1);
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200408 return 0;
409}
410
411static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200412 struct snd_ctl_elem_value *ucontrol)
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200413{
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200414 int addr = AK_GET_ADDR(kcontrol->private_value);
Takashi Iwai02ff1322007-11-15 16:15:29 +0100415 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
416 unsigned int val[2];
Takashi Iwai723b2b02006-08-30 16:49:54 +0200417 int change;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200418
Takashi Iwai02ff1322007-11-15 16:15:29 +0100419 val[0] = ucontrol->value.integer.value[0];
420 val[1] = ucontrol->value.integer.value[1];
421 if (val[0] > mask || val[1] > mask)
422 return -EINVAL;
423 change = put_ak_reg(kcontrol, addr, val[0]);
424 change |= put_ak_reg(kcontrol, addr + 1, val[1]);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200425 return change;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200426}
427
Takashi Iwai97f02e02005-11-17 14:17:19 +0100428static int snd_akm4xxx_deemphasis_info(struct snd_kcontrol *kcontrol,
429 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430{
431 static char *texts[4] = {
432 "44.1kHz", "Off", "48kHz", "32kHz",
433 };
434 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
435 uinfo->count = 1;
436 uinfo->value.enumerated.items = 4;
437 if (uinfo->value.enumerated.item >= 4)
438 uinfo->value.enumerated.item = 3;
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200439 strcpy(uinfo->value.enumerated.name,
440 texts[uinfo->value.enumerated.item]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 return 0;
442}
443
Takashi Iwai97f02e02005-11-17 14:17:19 +0100444static int snd_akm4xxx_deemphasis_get(struct snd_kcontrol *kcontrol,
445 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100447 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 int chip = AK_GET_CHIP(kcontrol->private_value);
449 int addr = AK_GET_ADDR(kcontrol->private_value);
450 int shift = AK_GET_SHIFT(kcontrol->private_value);
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200451 ucontrol->value.enumerated.item[0] =
452 (snd_akm4xxx_get(ak, chip, addr) >> shift) & 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 return 0;
454}
455
Takashi Iwai97f02e02005-11-17 14:17:19 +0100456static int snd_akm4xxx_deemphasis_put(struct snd_kcontrol *kcontrol,
457 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100459 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 int chip = AK_GET_CHIP(kcontrol->private_value);
461 int addr = AK_GET_ADDR(kcontrol->private_value);
462 int shift = AK_GET_SHIFT(kcontrol->private_value);
463 unsigned char nval = ucontrol->value.enumerated.item[0] & 3;
464 int change;
465
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200466 nval = (nval << shift) |
467 (snd_akm4xxx_get(ak, chip, addr) & ~(3 << shift));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 change = snd_akm4xxx_get(ak, chip, addr) != nval;
469 if (change)
470 snd_akm4xxx_write(ak, chip, addr, nval);
471 return change;
472}
473
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200474#define ak4xxx_switch_info snd_ctl_boolean_mono_info
Jochen Voss30ba6e22006-08-09 14:26:26 +0200475
476static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol,
477 struct snd_ctl_elem_value *ucontrol)
478{
479 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
480 int chip = AK_GET_CHIP(kcontrol->private_value);
481 int addr = AK_GET_ADDR(kcontrol->private_value);
482 int shift = AK_GET_SHIFT(kcontrol->private_value);
483 int invert = AK_GET_INVERT(kcontrol->private_value);
Pavel Hofmanea7cfcd2007-05-19 17:21:04 +0200484 /* we observe the (1<<shift) bit only */
485 unsigned char val = snd_akm4xxx_get(ak, chip, addr) & (1<<shift);
Jochen Voss30ba6e22006-08-09 14:26:26 +0200486 if (invert)
487 val = ! val;
488 ucontrol->value.integer.value[0] = (val & (1<<shift)) != 0;
489 return 0;
490}
491
492static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
493 struct snd_ctl_elem_value *ucontrol)
494{
495 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
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 int invert = AK_GET_INVERT(kcontrol->private_value);
500 long flag = ucontrol->value.integer.value[0];
501 unsigned char val, oval;
502 int change;
503
504 if (invert)
505 flag = ! flag;
506 oval = snd_akm4xxx_get(ak, chip, addr);
507 if (flag)
508 val = oval | (1<<shift);
509 else
510 val = oval & ~(1<<shift);
511 change = (oval != val);
512 if (change)
513 snd_akm4xxx_write(ak, chip, addr, val);
514 return change;
515}
516
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200517#define AK5365_NUM_INPUTS 5
518
Takashi Iwai02ff1322007-11-15 16:15:29 +0100519static int ak4xxx_capture_num_inputs(struct snd_akm4xxx *ak, int mixer_ch)
520{
521 int num_names;
522 const char **input_names;
523
524 input_names = ak->adc_info[mixer_ch].input_names;
525 num_names = 0;
526 while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
527 ++num_names;
528 return num_names;
529}
530
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200531static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
532 struct snd_ctl_elem_info *uinfo)
533{
534 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
535 int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
536 const char **input_names;
537 int num_names, idx;
538
Takashi Iwai02ff1322007-11-15 16:15:29 +0100539 num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
540 if (!num_names)
541 return -EINVAL;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200542 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
543 uinfo->count = 1;
544 uinfo->value.enumerated.items = num_names;
545 idx = uinfo->value.enumerated.item;
546 if (idx >= num_names)
547 return -EINVAL;
Takashi Iwai02ff1322007-11-15 16:15:29 +0100548 input_names = ak->adc_info[mixer_ch].input_names;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200549 strncpy(uinfo->value.enumerated.name, input_names[idx],
550 sizeof(uinfo->value.enumerated.name));
551 return 0;
552}
553
554static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol,
555 struct snd_ctl_elem_value *ucontrol)
556{
557 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
558 int chip = AK_GET_CHIP(kcontrol->private_value);
559 int addr = AK_GET_ADDR(kcontrol->private_value);
560 int mask = AK_GET_MASK(kcontrol->private_value);
561 unsigned char val;
562
563 val = snd_akm4xxx_get(ak, chip, addr) & mask;
564 ucontrol->value.enumerated.item[0] = val;
565 return 0;
566}
567
568static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol,
569 struct snd_ctl_elem_value *ucontrol)
570{
571 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Takashi Iwai02ff1322007-11-15 16:15:29 +0100572 int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200573 int chip = AK_GET_CHIP(kcontrol->private_value);
574 int addr = AK_GET_ADDR(kcontrol->private_value);
575 int mask = AK_GET_MASK(kcontrol->private_value);
576 unsigned char oval, val;
Takashi Iwai02ff1322007-11-15 16:15:29 +0100577 int num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
578
579 if (ucontrol->value.enumerated.item[0] >= num_names)
580 return -EINVAL;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200581
582 oval = snd_akm4xxx_get(ak, chip, addr);
583 val = oval & ~mask;
584 val |= ucontrol->value.enumerated.item[0] & mask;
585 if (val != oval) {
586 snd_akm4xxx_write(ak, chip, addr, val);
587 return 1;
588 }
589 return 0;
590}
591
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592/*
593 * build AK4xxx controls
594 */
595
Takashi Iwai723b2b02006-08-30 16:49:54 +0200596static int build_dac_controls(struct snd_akm4xxx *ak)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597{
Takashi Iwai723b2b02006-08-30 16:49:54 +0200598 int idx, err, mixer_ch, num_stereo;
599 struct snd_kcontrol_new knew;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
Takashi Iwai723b2b02006-08-30 16:49:54 +0200601 mixer_ch = 0;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200602 for (idx = 0; idx < ak->num_dacs; ) {
Pavel Hofmanea7cfcd2007-05-19 17:21:04 +0200603 /* mute control for Revolution 7.1 - AK4381 */
604 if (ak->type == SND_AK4381
605 && ak->dac_info[mixer_ch].switch_name) {
606 memset(&knew, 0, sizeof(knew));
607 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
608 knew.count = 1;
609 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
610 knew.name = ak->dac_info[mixer_ch].switch_name;
611 knew.info = ak4xxx_switch_info;
612 knew.get = ak4xxx_switch_get;
613 knew.put = ak4xxx_switch_put;
614 knew.access = 0;
615 /* register 1, bit 0 (SMUTE): 0 = normal operation,
616 1 = mute */
617 knew.private_value =
618 AK_COMPOSE(idx/2, 1, 0, 0) | AK_INVERT;
619 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
620 if (err < 0)
621 return err;
622 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200623 memset(&knew, 0, sizeof(knew));
624 if (! ak->dac_info || ! ak->dac_info[mixer_ch].name) {
625 knew.name = "DAC Volume";
626 knew.index = mixer_ch + ak->idx_offset * 2;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200627 num_stereo = 1;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200628 } else {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200629 knew.name = ak->dac_info[mixer_ch].name;
630 num_stereo = ak->dac_info[mixer_ch].num_channels;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200631 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200632 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
633 knew.count = 1;
634 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
635 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200636 if (num_stereo == 2) {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200637 knew.info = snd_akm4xxx_stereo_volume_info;
638 knew.get = snd_akm4xxx_stereo_volume_get;
639 knew.put = snd_akm4xxx_stereo_volume_put;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200640 } else {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200641 knew.info = snd_akm4xxx_volume_info;
642 knew.get = snd_akm4xxx_volume_get;
643 knew.put = snd_akm4xxx_volume_put;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200644 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 switch (ak->type) {
646 case SND_AK4524:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200647 /* register 6 & 7 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200648 knew.private_value =
649 AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127) |
650 AK_VOL_CVT;
651 knew.tlv.p = db_scale_vol_datt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 break;
653 case SND_AK4528:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200654 /* register 4 & 5 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200655 knew.private_value =
656 AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127) |
657 AK_VOL_CVT;
658 knew.tlv.p = db_scale_vol_datt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 break;
660 case SND_AK4529: {
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200661 /* registers 2-7 and b,c */
662 int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200663 knew.private_value =
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200664 AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200665 knew.tlv.p = db_scale_8bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 break;
667 }
668 case SND_AK4355:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200669 /* register 4-9, chip #0 only */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200670 knew.private_value = AK_COMPOSE(0, idx + 4, 0, 255);
671 knew.tlv.p = db_scale_8bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 break;
Jochen Voss34793072006-08-23 18:35:35 +0200673 case SND_AK4358: {
674 /* register 4-9 and 11-12, chip #0 only */
675 int addr = idx < 6 ? idx + 4 : idx + 5;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200676 knew.private_value =
Jochen Voss34793072006-08-23 18:35:35 +0200677 AK_COMPOSE(0, addr, 0, 127) | AK_NEEDSMSB;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200678 knew.tlv.p = db_scale_7bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 break;
Jochen Voss34793072006-08-23 18:35:35 +0200680 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 case SND_AK4381:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200682 /* register 3 & 4 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200683 knew.private_value =
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200684 AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200685 knew.tlv.p = db_scale_linear;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 break;
687 default:
Takashi Iwai723b2b02006-08-30 16:49:54 +0200688 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 }
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200690
Takashi Iwai723b2b02006-08-30 16:49:54 +0200691 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200692 if (err < 0)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200693 return err;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200694
695 idx += num_stereo;
696 mixer_ch++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200698 return 0;
699}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
Takashi Iwai723b2b02006-08-30 16:49:54 +0200701static int build_adc_controls(struct snd_akm4xxx *ak)
702{
703 int idx, err, mixer_ch, num_stereo;
704 struct snd_kcontrol_new knew;
705
706 mixer_ch = 0;
707 for (idx = 0; idx < ak->num_adcs;) {
708 memset(&knew, 0, sizeof(knew));
709 if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) {
710 knew.name = "ADC Volume";
711 knew.index = mixer_ch + ak->idx_offset * 2;
712 num_stereo = 1;
713 } else {
714 knew.name = ak->adc_info[mixer_ch].name;
715 num_stereo = ak->adc_info[mixer_ch].num_channels;
716 }
717 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
718 knew.count = 1;
719 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
720 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
721 if (num_stereo == 2) {
722 knew.info = snd_akm4xxx_stereo_volume_info;
723 knew.get = snd_akm4xxx_stereo_volume_get;
724 knew.put = snd_akm4xxx_stereo_volume_put;
725 } else {
726 knew.info = snd_akm4xxx_volume_info;
727 knew.get = snd_akm4xxx_volume_get;
728 knew.put = snd_akm4xxx_volume_put;
729 }
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200730 /* register 4 & 5 */
Takashi Iwai854b66e2006-09-08 12:27:38 +0200731 if (ak->type == SND_AK5365)
732 knew.private_value =
733 AK_COMPOSE(idx/2, (idx%2) + 4, 0, 151) |
734 AK_VOL_CVT | AK_IPGA;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200735 else
Takashi Iwai854b66e2006-09-08 12:27:38 +0200736 knew.private_value =
737 AK_COMPOSE(idx/2, (idx%2) + 4, 0, 163) |
738 AK_VOL_CVT | AK_IPGA;
739 knew.tlv.p = db_scale_vol_datt;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200740 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
741 if (err < 0)
742 return err;
743
744 if (ak->type == SND_AK5365 && (idx % 2) == 0) {
745 if (! ak->adc_info ||
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200746 ! ak->adc_info[mixer_ch].switch_name) {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200747 knew.name = "Capture Switch";
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200748 knew.index = mixer_ch + ak->idx_offset * 2;
749 } else
Takashi Iwai723b2b02006-08-30 16:49:54 +0200750 knew.name = ak->adc_info[mixer_ch].switch_name;
751 knew.info = ak4xxx_switch_info;
752 knew.get = ak4xxx_switch_get;
753 knew.put = ak4xxx_switch_put;
754 knew.access = 0;
755 /* register 2, bit 0 (SMUTE): 0 = normal operation,
756 1 = mute */
757 knew.private_value =
758 AK_COMPOSE(idx/2, 2, 0, 0) | AK_INVERT;
759 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
760 if (err < 0)
761 return err;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200762
763 memset(&knew, 0, sizeof(knew));
764 knew.name = ak->adc_info[mixer_ch].selector_name;
765 if (!knew.name) {
766 knew.name = "Capture Channel";
767 knew.index = mixer_ch + ak->idx_offset * 2;
768 }
769
770 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
771 knew.info = ak4xxx_capture_source_info;
772 knew.get = ak4xxx_capture_source_get;
773 knew.put = ak4xxx_capture_source_put;
774 knew.access = 0;
775 /* input selector control: reg. 1, bits 0-2.
776 * mis-use 'shift' to pass mixer_ch */
777 knew.private_value
778 = AK_COMPOSE(idx/2, 1, mixer_ch, 0x07);
779 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
780 if (err < 0)
781 return err;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200782 }
783
784 idx += num_stereo;
785 mixer_ch++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200787 return 0;
788}
Jochen Voss683fe152006-08-08 21:12:44 +0200789
Takashi Iwai723b2b02006-08-30 16:49:54 +0200790static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
791{
792 int idx, err;
793 struct snd_kcontrol_new knew;
Jochen Voss30ba6e22006-08-09 14:26:26 +0200794
Takashi Iwai723b2b02006-08-30 16:49:54 +0200795 for (idx = 0; idx < num_emphs; idx++) {
796 memset(&knew, 0, sizeof(knew));
797 knew.name = "Deemphasis";
798 knew.index = idx + ak->idx_offset;
799 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
800 knew.count = 1;
801 knew.info = snd_akm4xxx_deemphasis_info;
802 knew.get = snd_akm4xxx_deemphasis_get;
803 knew.put = snd_akm4xxx_deemphasis_put;
804 switch (ak->type) {
805 case SND_AK4524:
806 case SND_AK4528:
807 /* register 3 */
808 knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
809 break;
810 case SND_AK4529: {
811 int shift = idx == 3 ? 6 : (2 - idx) * 2;
812 /* register 8 with shift */
813 knew.private_value = AK_COMPOSE(0, 8, shift, 0);
814 break;
815 }
816 case SND_AK4355:
817 case SND_AK4358:
818 knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
819 break;
820 case SND_AK4381:
821 knew.private_value = AK_COMPOSE(idx, 1, 1, 0);
822 break;
823 default:
824 return -EINVAL;
825 }
826 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
Jochen Voss30ba6e22006-08-09 14:26:26 +0200827 if (err < 0)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200828 return err;
829 }
830 return 0;
831}
832
833int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
834{
835 int err, num_emphs;
836
837 err = build_dac_controls(ak);
838 if (err < 0)
839 return err;
840
Takashi Iwai854b66e2006-09-08 12:27:38 +0200841 err = build_adc_controls(ak);
842 if (err < 0)
843 return err;
Jochen Voss683fe152006-08-08 21:12:44 +0200844
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
846 num_emphs = 1;
847 else
848 num_emphs = ak->num_dacs / 2;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200849 err = build_deemphasis(ak, num_emphs);
850 if (err < 0)
851 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852
Takashi Iwai723b2b02006-08-30 16:49:54 +0200853 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854}
Takashi Iwai723b2b02006-08-30 16:49:54 +0200855
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200856EXPORT_SYMBOL(snd_akm4xxx_build_controls);
857
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858static int __init alsa_akm4xxx_module_init(void)
859{
860 return 0;
861}
862
863static void __exit alsa_akm4xxx_module_exit(void)
864{
865}
866
867module_init(alsa_akm4xxx_module_init)
868module_exit(alsa_akm4xxx_module_exit)