blob: fefa1ae57ad922f45771cef2cb00c4c0a4c3cdad [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;
Pavel Hofman6632d642007-12-03 12:44:28 +0100296 case NON_AKM:
297 /* fake value for non-akm codecs using akm infrastructure
298 * (e.g. of ice1724) - certainly FIXME
299 */
300 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 default:
302 snd_BUG();
303 return;
304 }
305
306 for (chip = 0; chip < num_chips; chip++) {
307 ptr = inits;
308 while (*ptr != 0xff) {
309 reg = *ptr++;
310 data = *ptr++;
311 snd_akm4xxx_write(ak, chip, reg, data);
312 }
313 }
314}
315
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200316EXPORT_SYMBOL(snd_akm4xxx_init);
317
Takashi Iwai723b2b02006-08-30 16:49:54 +0200318/*
319 * Mixer callbacks
320 */
Takashi Iwai854b66e2006-09-08 12:27:38 +0200321#define AK_IPGA (1<<20) /* including IPGA */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200322#define AK_VOL_CVT (1<<21) /* need dB conversion */
323#define AK_NEEDSMSB (1<<22) /* need MSB update bit */
324#define AK_INVERT (1<<23) /* data is inverted */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325#define AK_GET_CHIP(val) (((val) >> 8) & 0xff)
326#define AK_GET_ADDR(val) ((val) & 0xff)
Takashi Iwai854b66e2006-09-08 12:27:38 +0200327#define AK_GET_SHIFT(val) (((val) >> 16) & 0x0f)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200328#define AK_GET_VOL_CVT(val) (((val) >> 21) & 1)
Takashi Iwai854b66e2006-09-08 12:27:38 +0200329#define AK_GET_IPGA(val) (((val) >> 20) & 1)
Jochen Voss34793072006-08-23 18:35:35 +0200330#define AK_GET_NEEDSMSB(val) (((val) >> 22) & 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331#define AK_GET_INVERT(val) (((val) >> 23) & 1)
332#define AK_GET_MASK(val) (((val) >> 24) & 0xff)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200333#define AK_COMPOSE(chip,addr,shift,mask) \
334 (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335
Takashi Iwai97f02e02005-11-17 14:17:19 +0100336static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol,
337 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338{
339 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
340
341 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
342 uinfo->count = 1;
343 uinfo->value.integer.min = 0;
344 uinfo->value.integer.max = mask;
345 return 0;
346}
347
Takashi Iwai97f02e02005-11-17 14:17:19 +0100348static int snd_akm4xxx_volume_get(struct snd_kcontrol *kcontrol,
349 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100351 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 int chip = AK_GET_CHIP(kcontrol->private_value);
353 int addr = AK_GET_ADDR(kcontrol->private_value);
Jochen Voss34793072006-08-23 18:35:35 +0200354
Takashi Iwai723b2b02006-08-30 16:49:54 +0200355 ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 return 0;
357}
358
Takashi Iwai723b2b02006-08-30 16:49:54 +0200359static int put_ak_reg(struct snd_kcontrol *kcontrol, int addr,
360 unsigned char nval)
361{
362 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
363 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
364 int chip = AK_GET_CHIP(kcontrol->private_value);
365
366 if (snd_akm4xxx_get_vol(ak, chip, addr) == nval)
367 return 0;
368
369 snd_akm4xxx_set_vol(ak, chip, addr, nval);
Takashi Iwai854b66e2006-09-08 12:27:38 +0200370 if (AK_GET_VOL_CVT(kcontrol->private_value) && nval < 128)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200371 nval = vol_cvt_datt[nval];
Takashi Iwai854b66e2006-09-08 12:27:38 +0200372 if (AK_GET_IPGA(kcontrol->private_value) && nval >= 128)
373 nval++; /* need to correct + 1 since both 127 and 128 are 0dB */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200374 if (AK_GET_INVERT(kcontrol->private_value))
375 nval = mask - nval;
376 if (AK_GET_NEEDSMSB(kcontrol->private_value))
377 nval |= 0x80;
378 snd_akm4xxx_write(ak, chip, addr, nval);
379 return 1;
380}
381
Takashi Iwai97f02e02005-11-17 14:17:19 +0100382static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
383 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
Takashi Iwai02ff1322007-11-15 16:15:29 +0100385 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
386 unsigned int val = ucontrol->value.integer.value[0];
387 if (val > mask)
388 return -EINVAL;
389 return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value), val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390}
391
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200392static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol,
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200393 struct snd_ctl_elem_info *uinfo)
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200394{
395 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
396
397 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
398 uinfo->count = 2;
399 uinfo->value.integer.min = 0;
400 uinfo->value.integer.max = mask;
401 return 0;
402}
403
404static int snd_akm4xxx_stereo_volume_get(struct snd_kcontrol *kcontrol,
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200405 struct snd_ctl_elem_value *ucontrol)
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200406{
407 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
408 int chip = AK_GET_CHIP(kcontrol->private_value);
409 int addr = AK_GET_ADDR(kcontrol->private_value);
Jochen Voss34793072006-08-23 18:35:35 +0200410
Takashi Iwai723b2b02006-08-30 16:49:54 +0200411 ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
412 ucontrol->value.integer.value[1] = snd_akm4xxx_get_vol(ak, chip, addr+1);
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200413 return 0;
414}
415
416static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200417 struct snd_ctl_elem_value *ucontrol)
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200418{
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200419 int addr = AK_GET_ADDR(kcontrol->private_value);
Takashi Iwai02ff1322007-11-15 16:15:29 +0100420 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
421 unsigned int val[2];
Takashi Iwai723b2b02006-08-30 16:49:54 +0200422 int change;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200423
Takashi Iwai02ff1322007-11-15 16:15:29 +0100424 val[0] = ucontrol->value.integer.value[0];
425 val[1] = ucontrol->value.integer.value[1];
426 if (val[0] > mask || val[1] > mask)
427 return -EINVAL;
428 change = put_ak_reg(kcontrol, addr, val[0]);
429 change |= put_ak_reg(kcontrol, addr + 1, val[1]);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200430 return change;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200431}
432
Takashi Iwai97f02e02005-11-17 14:17:19 +0100433static int snd_akm4xxx_deemphasis_info(struct snd_kcontrol *kcontrol,
434 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435{
436 static char *texts[4] = {
437 "44.1kHz", "Off", "48kHz", "32kHz",
438 };
439 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
440 uinfo->count = 1;
441 uinfo->value.enumerated.items = 4;
442 if (uinfo->value.enumerated.item >= 4)
443 uinfo->value.enumerated.item = 3;
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200444 strcpy(uinfo->value.enumerated.name,
445 texts[uinfo->value.enumerated.item]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 return 0;
447}
448
Takashi Iwai97f02e02005-11-17 14:17:19 +0100449static int snd_akm4xxx_deemphasis_get(struct snd_kcontrol *kcontrol,
450 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100452 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 int chip = AK_GET_CHIP(kcontrol->private_value);
454 int addr = AK_GET_ADDR(kcontrol->private_value);
455 int shift = AK_GET_SHIFT(kcontrol->private_value);
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200456 ucontrol->value.enumerated.item[0] =
457 (snd_akm4xxx_get(ak, chip, addr) >> shift) & 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 return 0;
459}
460
Takashi Iwai97f02e02005-11-17 14:17:19 +0100461static int snd_akm4xxx_deemphasis_put(struct snd_kcontrol *kcontrol,
462 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100464 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 int chip = AK_GET_CHIP(kcontrol->private_value);
466 int addr = AK_GET_ADDR(kcontrol->private_value);
467 int shift = AK_GET_SHIFT(kcontrol->private_value);
468 unsigned char nval = ucontrol->value.enumerated.item[0] & 3;
469 int change;
470
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200471 nval = (nval << shift) |
472 (snd_akm4xxx_get(ak, chip, addr) & ~(3 << shift));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 change = snd_akm4xxx_get(ak, chip, addr) != nval;
474 if (change)
475 snd_akm4xxx_write(ak, chip, addr, nval);
476 return change;
477}
478
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200479#define ak4xxx_switch_info snd_ctl_boolean_mono_info
Jochen Voss30ba6e22006-08-09 14:26:26 +0200480
481static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol,
482 struct snd_ctl_elem_value *ucontrol)
483{
484 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
485 int chip = AK_GET_CHIP(kcontrol->private_value);
486 int addr = AK_GET_ADDR(kcontrol->private_value);
487 int shift = AK_GET_SHIFT(kcontrol->private_value);
488 int invert = AK_GET_INVERT(kcontrol->private_value);
Pavel Hofmanea7cfcd2007-05-19 17:21:04 +0200489 /* we observe the (1<<shift) bit only */
490 unsigned char val = snd_akm4xxx_get(ak, chip, addr) & (1<<shift);
Jochen Voss30ba6e22006-08-09 14:26:26 +0200491 if (invert)
492 val = ! val;
493 ucontrol->value.integer.value[0] = (val & (1<<shift)) != 0;
494 return 0;
495}
496
497static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
498 struct snd_ctl_elem_value *ucontrol)
499{
500 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
501 int chip = AK_GET_CHIP(kcontrol->private_value);
502 int addr = AK_GET_ADDR(kcontrol->private_value);
503 int shift = AK_GET_SHIFT(kcontrol->private_value);
504 int invert = AK_GET_INVERT(kcontrol->private_value);
505 long flag = ucontrol->value.integer.value[0];
506 unsigned char val, oval;
507 int change;
508
509 if (invert)
510 flag = ! flag;
511 oval = snd_akm4xxx_get(ak, chip, addr);
512 if (flag)
513 val = oval | (1<<shift);
514 else
515 val = oval & ~(1<<shift);
516 change = (oval != val);
517 if (change)
518 snd_akm4xxx_write(ak, chip, addr, val);
519 return change;
520}
521
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200522#define AK5365_NUM_INPUTS 5
523
Takashi Iwai02ff1322007-11-15 16:15:29 +0100524static int ak4xxx_capture_num_inputs(struct snd_akm4xxx *ak, int mixer_ch)
525{
526 int num_names;
527 const char **input_names;
528
529 input_names = ak->adc_info[mixer_ch].input_names;
530 num_names = 0;
531 while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
532 ++num_names;
533 return num_names;
534}
535
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200536static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
537 struct snd_ctl_elem_info *uinfo)
538{
539 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
540 int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
541 const char **input_names;
542 int num_names, idx;
543
Takashi Iwai02ff1322007-11-15 16:15:29 +0100544 num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
545 if (!num_names)
546 return -EINVAL;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200547 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
548 uinfo->count = 1;
549 uinfo->value.enumerated.items = num_names;
550 idx = uinfo->value.enumerated.item;
551 if (idx >= num_names)
552 return -EINVAL;
Takashi Iwai02ff1322007-11-15 16:15:29 +0100553 input_names = ak->adc_info[mixer_ch].input_names;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200554 strncpy(uinfo->value.enumerated.name, input_names[idx],
555 sizeof(uinfo->value.enumerated.name));
556 return 0;
557}
558
559static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol,
560 struct snd_ctl_elem_value *ucontrol)
561{
562 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
563 int chip = AK_GET_CHIP(kcontrol->private_value);
564 int addr = AK_GET_ADDR(kcontrol->private_value);
565 int mask = AK_GET_MASK(kcontrol->private_value);
566 unsigned char val;
567
568 val = snd_akm4xxx_get(ak, chip, addr) & mask;
569 ucontrol->value.enumerated.item[0] = val;
570 return 0;
571}
572
573static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol,
574 struct snd_ctl_elem_value *ucontrol)
575{
576 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Takashi Iwai02ff1322007-11-15 16:15:29 +0100577 int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200578 int chip = AK_GET_CHIP(kcontrol->private_value);
579 int addr = AK_GET_ADDR(kcontrol->private_value);
580 int mask = AK_GET_MASK(kcontrol->private_value);
581 unsigned char oval, val;
Takashi Iwai02ff1322007-11-15 16:15:29 +0100582 int num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
583
584 if (ucontrol->value.enumerated.item[0] >= num_names)
585 return -EINVAL;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200586
587 oval = snd_akm4xxx_get(ak, chip, addr);
588 val = oval & ~mask;
589 val |= ucontrol->value.enumerated.item[0] & mask;
590 if (val != oval) {
591 snd_akm4xxx_write(ak, chip, addr, val);
592 return 1;
593 }
594 return 0;
595}
596
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597/*
598 * build AK4xxx controls
599 */
600
Takashi Iwai723b2b02006-08-30 16:49:54 +0200601static int build_dac_controls(struct snd_akm4xxx *ak)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602{
Takashi Iwai723b2b02006-08-30 16:49:54 +0200603 int idx, err, mixer_ch, num_stereo;
604 struct snd_kcontrol_new knew;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605
Takashi Iwai723b2b02006-08-30 16:49:54 +0200606 mixer_ch = 0;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200607 for (idx = 0; idx < ak->num_dacs; ) {
Pavel Hofmanea7cfcd2007-05-19 17:21:04 +0200608 /* mute control for Revolution 7.1 - AK4381 */
609 if (ak->type == SND_AK4381
610 && ak->dac_info[mixer_ch].switch_name) {
611 memset(&knew, 0, sizeof(knew));
612 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
613 knew.count = 1;
614 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
615 knew.name = ak->dac_info[mixer_ch].switch_name;
616 knew.info = ak4xxx_switch_info;
617 knew.get = ak4xxx_switch_get;
618 knew.put = ak4xxx_switch_put;
619 knew.access = 0;
620 /* register 1, bit 0 (SMUTE): 0 = normal operation,
621 1 = mute */
622 knew.private_value =
623 AK_COMPOSE(idx/2, 1, 0, 0) | AK_INVERT;
624 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
625 if (err < 0)
626 return err;
627 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200628 memset(&knew, 0, sizeof(knew));
629 if (! ak->dac_info || ! ak->dac_info[mixer_ch].name) {
630 knew.name = "DAC Volume";
631 knew.index = mixer_ch + ak->idx_offset * 2;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200632 num_stereo = 1;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200633 } else {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200634 knew.name = ak->dac_info[mixer_ch].name;
635 num_stereo = ak->dac_info[mixer_ch].num_channels;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200636 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200637 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
638 knew.count = 1;
639 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
640 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200641 if (num_stereo == 2) {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200642 knew.info = snd_akm4xxx_stereo_volume_info;
643 knew.get = snd_akm4xxx_stereo_volume_get;
644 knew.put = snd_akm4xxx_stereo_volume_put;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200645 } else {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200646 knew.info = snd_akm4xxx_volume_info;
647 knew.get = snd_akm4xxx_volume_get;
648 knew.put = snd_akm4xxx_volume_put;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200649 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 switch (ak->type) {
651 case SND_AK4524:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200652 /* register 6 & 7 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200653 knew.private_value =
654 AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127) |
655 AK_VOL_CVT;
656 knew.tlv.p = db_scale_vol_datt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 break;
658 case SND_AK4528:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200659 /* register 4 & 5 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200660 knew.private_value =
661 AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127) |
662 AK_VOL_CVT;
663 knew.tlv.p = db_scale_vol_datt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 break;
665 case SND_AK4529: {
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200666 /* registers 2-7 and b,c */
667 int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200668 knew.private_value =
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200669 AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200670 knew.tlv.p = db_scale_8bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 break;
672 }
673 case SND_AK4355:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200674 /* register 4-9, chip #0 only */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200675 knew.private_value = AK_COMPOSE(0, idx + 4, 0, 255);
676 knew.tlv.p = db_scale_8bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 break;
Jochen Voss34793072006-08-23 18:35:35 +0200678 case SND_AK4358: {
679 /* register 4-9 and 11-12, chip #0 only */
680 int addr = idx < 6 ? idx + 4 : idx + 5;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200681 knew.private_value =
Jochen Voss34793072006-08-23 18:35:35 +0200682 AK_COMPOSE(0, addr, 0, 127) | AK_NEEDSMSB;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200683 knew.tlv.p = db_scale_7bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 break;
Jochen Voss34793072006-08-23 18:35:35 +0200685 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 case SND_AK4381:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200687 /* register 3 & 4 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200688 knew.private_value =
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200689 AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200690 knew.tlv.p = db_scale_linear;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 break;
692 default:
Takashi Iwai723b2b02006-08-30 16:49:54 +0200693 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 }
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200695
Takashi Iwai723b2b02006-08-30 16:49:54 +0200696 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200697 if (err < 0)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200698 return err;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200699
700 idx += num_stereo;
701 mixer_ch++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200703 return 0;
704}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
Takashi Iwai723b2b02006-08-30 16:49:54 +0200706static int build_adc_controls(struct snd_akm4xxx *ak)
707{
708 int idx, err, mixer_ch, num_stereo;
709 struct snd_kcontrol_new knew;
710
711 mixer_ch = 0;
712 for (idx = 0; idx < ak->num_adcs;) {
713 memset(&knew, 0, sizeof(knew));
714 if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) {
715 knew.name = "ADC Volume";
716 knew.index = mixer_ch + ak->idx_offset * 2;
717 num_stereo = 1;
718 } else {
719 knew.name = ak->adc_info[mixer_ch].name;
720 num_stereo = ak->adc_info[mixer_ch].num_channels;
721 }
722 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
723 knew.count = 1;
724 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
725 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
726 if (num_stereo == 2) {
727 knew.info = snd_akm4xxx_stereo_volume_info;
728 knew.get = snd_akm4xxx_stereo_volume_get;
729 knew.put = snd_akm4xxx_stereo_volume_put;
730 } else {
731 knew.info = snd_akm4xxx_volume_info;
732 knew.get = snd_akm4xxx_volume_get;
733 knew.put = snd_akm4xxx_volume_put;
734 }
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200735 /* register 4 & 5 */
Takashi Iwai854b66e2006-09-08 12:27:38 +0200736 if (ak->type == SND_AK5365)
737 knew.private_value =
738 AK_COMPOSE(idx/2, (idx%2) + 4, 0, 151) |
739 AK_VOL_CVT | AK_IPGA;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200740 else
Takashi Iwai854b66e2006-09-08 12:27:38 +0200741 knew.private_value =
742 AK_COMPOSE(idx/2, (idx%2) + 4, 0, 163) |
743 AK_VOL_CVT | AK_IPGA;
744 knew.tlv.p = db_scale_vol_datt;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200745 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
746 if (err < 0)
747 return err;
748
749 if (ak->type == SND_AK5365 && (idx % 2) == 0) {
750 if (! ak->adc_info ||
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200751 ! ak->adc_info[mixer_ch].switch_name) {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200752 knew.name = "Capture Switch";
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200753 knew.index = mixer_ch + ak->idx_offset * 2;
754 } else
Takashi Iwai723b2b02006-08-30 16:49:54 +0200755 knew.name = ak->adc_info[mixer_ch].switch_name;
756 knew.info = ak4xxx_switch_info;
757 knew.get = ak4xxx_switch_get;
758 knew.put = ak4xxx_switch_put;
759 knew.access = 0;
760 /* register 2, bit 0 (SMUTE): 0 = normal operation,
761 1 = mute */
762 knew.private_value =
763 AK_COMPOSE(idx/2, 2, 0, 0) | AK_INVERT;
764 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
765 if (err < 0)
766 return err;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200767
768 memset(&knew, 0, sizeof(knew));
769 knew.name = ak->adc_info[mixer_ch].selector_name;
770 if (!knew.name) {
771 knew.name = "Capture Channel";
772 knew.index = mixer_ch + ak->idx_offset * 2;
773 }
774
775 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
776 knew.info = ak4xxx_capture_source_info;
777 knew.get = ak4xxx_capture_source_get;
778 knew.put = ak4xxx_capture_source_put;
779 knew.access = 0;
780 /* input selector control: reg. 1, bits 0-2.
781 * mis-use 'shift' to pass mixer_ch */
782 knew.private_value
783 = AK_COMPOSE(idx/2, 1, mixer_ch, 0x07);
784 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
785 if (err < 0)
786 return err;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200787 }
788
789 idx += num_stereo;
790 mixer_ch++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200792 return 0;
793}
Jochen Voss683fe152006-08-08 21:12:44 +0200794
Takashi Iwai723b2b02006-08-30 16:49:54 +0200795static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
796{
797 int idx, err;
798 struct snd_kcontrol_new knew;
Jochen Voss30ba6e22006-08-09 14:26:26 +0200799
Takashi Iwai723b2b02006-08-30 16:49:54 +0200800 for (idx = 0; idx < num_emphs; idx++) {
801 memset(&knew, 0, sizeof(knew));
802 knew.name = "Deemphasis";
803 knew.index = idx + ak->idx_offset;
804 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
805 knew.count = 1;
806 knew.info = snd_akm4xxx_deemphasis_info;
807 knew.get = snd_akm4xxx_deemphasis_get;
808 knew.put = snd_akm4xxx_deemphasis_put;
809 switch (ak->type) {
810 case SND_AK4524:
811 case SND_AK4528:
812 /* register 3 */
813 knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
814 break;
815 case SND_AK4529: {
816 int shift = idx == 3 ? 6 : (2 - idx) * 2;
817 /* register 8 with shift */
818 knew.private_value = AK_COMPOSE(0, 8, shift, 0);
819 break;
820 }
821 case SND_AK4355:
822 case SND_AK4358:
823 knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
824 break;
825 case SND_AK4381:
826 knew.private_value = AK_COMPOSE(idx, 1, 1, 0);
827 break;
828 default:
829 return -EINVAL;
830 }
831 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
Jochen Voss30ba6e22006-08-09 14:26:26 +0200832 if (err < 0)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200833 return err;
834 }
835 return 0;
836}
837
838int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
839{
840 int err, num_emphs;
841
842 err = build_dac_controls(ak);
843 if (err < 0)
844 return err;
845
Takashi Iwai854b66e2006-09-08 12:27:38 +0200846 err = build_adc_controls(ak);
847 if (err < 0)
848 return err;
Jochen Voss683fe152006-08-08 21:12:44 +0200849
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
851 num_emphs = 1;
852 else
853 num_emphs = ak->num_dacs / 2;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200854 err = build_deemphasis(ak, num_emphs);
855 if (err < 0)
856 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857
Takashi Iwai723b2b02006-08-30 16:49:54 +0200858 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859}
Takashi Iwai723b2b02006-08-30 16:49:54 +0200860
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200861EXPORT_SYMBOL(snd_akm4xxx_build_controls);
862
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863static int __init alsa_akm4xxx_module_init(void)
864{
865 return 0;
866}
867
868static void __exit alsa_akm4xxx_module_exit(void)
869{
870}
871
872module_init(alsa_akm4xxx_module_init)
873module_exit(alsa_akm4xxx_module_exit)