blob: 288926d2e2054b2706d8749b6be8ff8290bd1911 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <asm/io.h>
25#include <linux/delay.h>
26#include <linux/interrupt.h>
27#include <linux/init.h>
28#include <sound/core.h>
29#include <sound/control.h>
Takashi Iwai723b2b02006-08-30 16:49:54 +020030#include <sound/tlv.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <sound/ak4xxx-adda.h>
32
Jaroslav Kyselac1017a42007-10-15 09:50:19 +020033MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>");
Linus Torvalds1da177e2005-04-16 15:20:36 -070034MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters");
35MODULE_LICENSE("GPL");
36
Takashi Iwai723b2b02006-08-30 16:49:54 +020037/* write the given register and save the data to the cache */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020038void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg,
39 unsigned char val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070040{
41 ak->ops.lock(ak, chip);
42 ak->ops.write(ak, chip, reg, val);
43
44 /* save the data */
Takashi Iwai854b66e2006-09-08 12:27:38 +020045 snd_akm4xxx_set(ak, chip, reg, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 ak->ops.unlock(ak, chip);
47}
48
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020049EXPORT_SYMBOL(snd_akm4xxx_write);
50
51/* reset procedure for AK4524 and AK4528 */
52static void ak4524_reset(struct snd_akm4xxx *ak, int state)
53{
54 unsigned int chip;
55 unsigned char reg, maxreg;
56
57 if (ak->type == SND_AK4528)
58 maxreg = 0x06;
59 else
60 maxreg = 0x08;
61 for (chip = 0; chip < ak->num_dacs/2; chip++) {
62 snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03);
63 if (state)
64 continue;
65 /* DAC volumes */
66 for (reg = 0x04; reg < maxreg; reg++)
67 snd_akm4xxx_write(ak, chip, reg,
68 snd_akm4xxx_get(ak, chip, reg));
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020069 }
70}
71
72/* reset procedure for AK4355 and AK4358 */
Pavel Hofman841b23d2008-03-17 08:45:33 +010073static void ak435X_reset(struct snd_akm4xxx *ak, int state,
74 unsigned char total_regs)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020075{
76 unsigned char reg;
77
78 if (state) {
79 snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */
80 return;
81 }
Pavel Hofman841b23d2008-03-17 08:45:33 +010082 for (reg = 0x00; reg < total_regs; reg++)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020083 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:
Pavel Hofman841b23d2008-03-17 08:45:33 +0100122 ak435X_reset(ak, state, 0x0b);
123 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 case SND_AK4358:
Pavel Hofman841b23d2008-03-17 08:45:33 +0100125 ak435X_reset(ak, state, 0x10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 break;
127 case SND_AK4381:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200128 ak4381_reset(ak, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 break;
Takashi Iwaicf939072006-08-09 14:33:27 +0200130 default:
131 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 }
133}
134
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200135EXPORT_SYMBOL(snd_akm4xxx_reset);
136
Takashi Iwai723b2b02006-08-30 16:49:54 +0200137
138/*
139 * Volume conversion table for non-linear volumes
140 * from -63.5dB (mute) to 0dB step 0.5dB
141 *
142 * Used for AK4524 input/ouput attenuation, AK4528, and
143 * AK5365 input attenuation
144 */
Takashi Iwai517400c2007-01-29 15:27:56 +0100145static const unsigned char vol_cvt_datt[128] = {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200146 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04,
147 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06,
148 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a,
149 0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f,
150 0x10, 0x10, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14,
151 0x15, 0x16, 0x17, 0x17, 0x18, 0x19, 0x1a, 0x1c,
152 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x23,
153 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, 0x2b, 0x2d,
154 0x2e, 0x30, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
155 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3e, 0x3f, 0x40,
156 0x41, 0x42, 0x43, 0x44, 0x46, 0x47, 0x48, 0x4a,
157 0x4b, 0x4d, 0x4e, 0x50, 0x51, 0x52, 0x53, 0x54,
158 0x55, 0x56, 0x58, 0x59, 0x5b, 0x5c, 0x5e, 0x5f,
159 0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x69,
160 0x6a, 0x6c, 0x6d, 0x6f, 0x70, 0x71, 0x72, 0x73,
161 0x75, 0x76, 0x77, 0x79, 0x7a, 0x7c, 0x7d, 0x7f,
162};
163
164/*
165 * dB tables
166 */
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100167static const DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
168static const DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
169static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
170static const DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200171
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172/*
173 * initialize all the ak4xxx chips
174 */
Takashi Iwai97f02e02005-11-17 14:17:19 +0100175void snd_akm4xxx_init(struct snd_akm4xxx *ak)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176{
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100177 static const unsigned char inits_ak4524[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 0x00, 0x07, /* 0: all power up */
179 0x01, 0x00, /* 1: ADC/DAC reset */
180 0x02, 0x60, /* 2: 24bit I2S */
181 0x03, 0x19, /* 3: deemphasis off */
182 0x01, 0x03, /* 1: ADC/DAC enable */
183 0x04, 0x00, /* 4: ADC left muted */
184 0x05, 0x00, /* 5: ADC right muted */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 0x06, 0x00, /* 6: DAC left muted */
186 0x07, 0x00, /* 7: DAC right muted */
187 0xff, 0xff
188 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100189 static const unsigned char inits_ak4528[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 0x00, 0x07, /* 0: all power up */
191 0x01, 0x00, /* 1: ADC/DAC reset */
192 0x02, 0x60, /* 2: 24bit I2S */
193 0x03, 0x0d, /* 3: deemphasis off, turn LR highpass filters on */
194 0x01, 0x03, /* 1: ADC/DAC enable */
195 0x04, 0x00, /* 4: ADC left muted */
196 0x05, 0x00, /* 5: ADC right muted */
197 0xff, 0xff
198 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100199 static const unsigned char inits_ak4529[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 0x09, 0x01, /* 9: ATS=0, RSTN=1 */
201 0x0a, 0x3f, /* A: all power up, no zero/overflow detection */
202 0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */
203 0x01, 0x00, /* 1: ACKS=0, ADC, loop off */
204 0x02, 0xff, /* 2: LOUT1 muted */
205 0x03, 0xff, /* 3: ROUT1 muted */
206 0x04, 0xff, /* 4: LOUT2 muted */
207 0x05, 0xff, /* 5: ROUT2 muted */
208 0x06, 0xff, /* 6: LOUT3 muted */
209 0x07, 0xff, /* 7: ROUT3 muted */
210 0x0b, 0xff, /* B: LOUT4 muted */
211 0x0c, 0xff, /* C: ROUT4 muted */
212 0x08, 0x55, /* 8: deemphasis all off */
213 0xff, 0xff
214 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100215 static const unsigned char inits_ak4355[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 0x01, 0x02, /* 1: reset and soft-mute */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200217 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
218 * disable DZF, sharp roll-off, RSTN#=0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
220 // 0x02, 0x2e, /* quad speed */
221 0x03, 0x01, /* 3: de-emphasis off */
222 0x04, 0x00, /* 4: LOUT1 volume muted */
223 0x05, 0x00, /* 5: ROUT1 volume muted */
224 0x06, 0x00, /* 6: LOUT2 volume muted */
225 0x07, 0x00, /* 7: ROUT2 volume muted */
226 0x08, 0x00, /* 8: LOUT3 volume muted */
227 0x09, 0x00, /* 9: ROUT3 volume muted */
228 0x0a, 0x00, /* a: DATT speed=0, ignore DZF */
229 0x01, 0x01, /* 1: un-reset, unmute */
230 0xff, 0xff
231 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100232 static const unsigned char inits_ak4358[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 0x01, 0x02, /* 1: reset and soft-mute */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200234 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
235 * disable DZF, sharp roll-off, RSTN#=0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
237 // 0x02, 0x2e, /* quad speed */
238 0x03, 0x01, /* 3: de-emphasis off */
239 0x04, 0x00, /* 4: LOUT1 volume muted */
240 0x05, 0x00, /* 5: ROUT1 volume muted */
241 0x06, 0x00, /* 6: LOUT2 volume muted */
242 0x07, 0x00, /* 7: ROUT2 volume muted */
243 0x08, 0x00, /* 8: LOUT3 volume muted */
244 0x09, 0x00, /* 9: ROUT3 volume muted */
245 0x0b, 0x00, /* b: LOUT4 volume muted */
246 0x0c, 0x00, /* c: ROUT4 volume muted */
247 0x0a, 0x00, /* a: DATT speed=0, ignore DZF */
248 0x01, 0x01, /* 1: un-reset, unmute */
249 0xff, 0xff
250 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100251 static const unsigned char inits_ak4381[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200253 0x01, 0x02, /* 1: de-emphasis off, normal speed,
254 * sharp roll-off, DZF off */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 // 0x01, 0x12, /* quad speed */
256 0x02, 0x00, /* 2: DZF disabled */
257 0x03, 0x00, /* 3: LATT 0 */
258 0x04, 0x00, /* 4: RATT 0 */
259 0x00, 0x0f, /* 0: power-up, un-reset */
260 0xff, 0xff
261 };
262
263 int chip, num_chips;
Takashi Iwai517400c2007-01-29 15:27:56 +0100264 const unsigned char *ptr, *inits;
265 unsigned char reg, data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
Takashi Iwai723b2b02006-08-30 16:49:54 +0200267 memset(ak->images, 0, sizeof(ak->images));
268 memset(ak->volumes, 0, sizeof(ak->volumes));
269
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 switch (ak->type) {
271 case SND_AK4524:
272 inits = inits_ak4524;
273 num_chips = ak->num_dacs / 2;
274 break;
275 case SND_AK4528:
276 inits = inits_ak4528;
277 num_chips = ak->num_dacs / 2;
278 break;
279 case SND_AK4529:
280 inits = inits_ak4529;
281 num_chips = 1;
282 break;
283 case SND_AK4355:
284 inits = inits_ak4355;
285 num_chips = 1;
286 break;
287 case SND_AK4358:
288 inits = inits_ak4358;
289 num_chips = 1;
290 break;
291 case SND_AK4381:
292 inits = inits_ak4381;
293 num_chips = ak->num_dacs / 2;
294 break;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200295 case SND_AK5365:
296 /* FIXME: any init sequence? */
297 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 default:
299 snd_BUG();
300 return;
301 }
302
303 for (chip = 0; chip < num_chips; chip++) {
304 ptr = inits;
305 while (*ptr != 0xff) {
306 reg = *ptr++;
307 data = *ptr++;
308 snd_akm4xxx_write(ak, chip, reg, data);
309 }
310 }
311}
312
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200313EXPORT_SYMBOL(snd_akm4xxx_init);
314
Takashi Iwai723b2b02006-08-30 16:49:54 +0200315/*
316 * Mixer callbacks
317 */
Takashi Iwai854b66e2006-09-08 12:27:38 +0200318#define AK_IPGA (1<<20) /* including IPGA */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200319#define AK_VOL_CVT (1<<21) /* need dB conversion */
320#define AK_NEEDSMSB (1<<22) /* need MSB update bit */
321#define AK_INVERT (1<<23) /* data is inverted */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322#define AK_GET_CHIP(val) (((val) >> 8) & 0xff)
323#define AK_GET_ADDR(val) ((val) & 0xff)
Takashi Iwai854b66e2006-09-08 12:27:38 +0200324#define AK_GET_SHIFT(val) (((val) >> 16) & 0x0f)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200325#define AK_GET_VOL_CVT(val) (((val) >> 21) & 1)
Takashi Iwai854b66e2006-09-08 12:27:38 +0200326#define AK_GET_IPGA(val) (((val) >> 20) & 1)
Jochen Voss34793072006-08-23 18:35:35 +0200327#define AK_GET_NEEDSMSB(val) (((val) >> 22) & 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328#define AK_GET_INVERT(val) (((val) >> 23) & 1)
329#define AK_GET_MASK(val) (((val) >> 24) & 0xff)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200330#define AK_COMPOSE(chip,addr,shift,mask) \
331 (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
Takashi Iwai97f02e02005-11-17 14:17:19 +0100333static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol,
334 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335{
336 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
337
338 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
339 uinfo->count = 1;
340 uinfo->value.integer.min = 0;
341 uinfo->value.integer.max = mask;
342 return 0;
343}
344
Takashi Iwai97f02e02005-11-17 14:17:19 +0100345static int snd_akm4xxx_volume_get(struct snd_kcontrol *kcontrol,
346 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100348 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 int chip = AK_GET_CHIP(kcontrol->private_value);
350 int addr = AK_GET_ADDR(kcontrol->private_value);
Jochen Voss34793072006-08-23 18:35:35 +0200351
Takashi Iwai723b2b02006-08-30 16:49:54 +0200352 ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 return 0;
354}
355
Takashi Iwai723b2b02006-08-30 16:49:54 +0200356static int put_ak_reg(struct snd_kcontrol *kcontrol, int addr,
357 unsigned char nval)
358{
359 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
360 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
361 int chip = AK_GET_CHIP(kcontrol->private_value);
362
363 if (snd_akm4xxx_get_vol(ak, chip, addr) == nval)
364 return 0;
365
366 snd_akm4xxx_set_vol(ak, chip, addr, nval);
Takashi Iwai854b66e2006-09-08 12:27:38 +0200367 if (AK_GET_VOL_CVT(kcontrol->private_value) && nval < 128)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200368 nval = vol_cvt_datt[nval];
Takashi Iwai854b66e2006-09-08 12:27:38 +0200369 if (AK_GET_IPGA(kcontrol->private_value) && nval >= 128)
370 nval++; /* need to correct + 1 since both 127 and 128 are 0dB */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200371 if (AK_GET_INVERT(kcontrol->private_value))
372 nval = mask - nval;
373 if (AK_GET_NEEDSMSB(kcontrol->private_value))
374 nval |= 0x80;
Pavel Hofman841b23d2008-03-17 08:45:33 +0100375 /* printk(KERN_DEBUG "DEBUG - AK writing reg: chip %x addr %x,
376 nval %x\n", chip, addr, nval); */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200377 snd_akm4xxx_write(ak, chip, addr, nval);
378 return 1;
379}
380
Takashi Iwai97f02e02005-11-17 14:17:19 +0100381static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
382 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383{
Takashi Iwai02ff1322007-11-15 16:15:29 +0100384 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
385 unsigned int val = ucontrol->value.integer.value[0];
386 if (val > mask)
387 return -EINVAL;
388 return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value), val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389}
390
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200391static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol,
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200392 struct snd_ctl_elem_info *uinfo)
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200393{
394 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
395
396 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
397 uinfo->count = 2;
398 uinfo->value.integer.min = 0;
399 uinfo->value.integer.max = mask;
400 return 0;
401}
402
403static int snd_akm4xxx_stereo_volume_get(struct snd_kcontrol *kcontrol,
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200404 struct snd_ctl_elem_value *ucontrol)
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200405{
406 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
407 int chip = AK_GET_CHIP(kcontrol->private_value);
408 int addr = AK_GET_ADDR(kcontrol->private_value);
Jochen Voss34793072006-08-23 18:35:35 +0200409
Takashi Iwai723b2b02006-08-30 16:49:54 +0200410 ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
411 ucontrol->value.integer.value[1] = snd_akm4xxx_get_vol(ak, chip, addr+1);
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200412 return 0;
413}
414
415static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200416 struct snd_ctl_elem_value *ucontrol)
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200417{
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200418 int addr = AK_GET_ADDR(kcontrol->private_value);
Takashi Iwai02ff1322007-11-15 16:15:29 +0100419 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
420 unsigned int val[2];
Takashi Iwai723b2b02006-08-30 16:49:54 +0200421 int change;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200422
Takashi Iwai02ff1322007-11-15 16:15:29 +0100423 val[0] = ucontrol->value.integer.value[0];
424 val[1] = ucontrol->value.integer.value[1];
425 if (val[0] > mask || val[1] > mask)
426 return -EINVAL;
427 change = put_ak_reg(kcontrol, addr, val[0]);
428 change |= put_ak_reg(kcontrol, addr + 1, val[1]);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200429 return change;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200430}
431
Takashi Iwai97f02e02005-11-17 14:17:19 +0100432static int snd_akm4xxx_deemphasis_info(struct snd_kcontrol *kcontrol,
433 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434{
435 static char *texts[4] = {
436 "44.1kHz", "Off", "48kHz", "32kHz",
437 };
438 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
439 uinfo->count = 1;
440 uinfo->value.enumerated.items = 4;
441 if (uinfo->value.enumerated.item >= 4)
442 uinfo->value.enumerated.item = 3;
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200443 strcpy(uinfo->value.enumerated.name,
444 texts[uinfo->value.enumerated.item]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 return 0;
446}
447
Takashi Iwai97f02e02005-11-17 14:17:19 +0100448static int snd_akm4xxx_deemphasis_get(struct snd_kcontrol *kcontrol,
449 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100451 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 int chip = AK_GET_CHIP(kcontrol->private_value);
453 int addr = AK_GET_ADDR(kcontrol->private_value);
454 int shift = AK_GET_SHIFT(kcontrol->private_value);
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200455 ucontrol->value.enumerated.item[0] =
456 (snd_akm4xxx_get(ak, chip, addr) >> shift) & 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 return 0;
458}
459
Takashi Iwai97f02e02005-11-17 14:17:19 +0100460static int snd_akm4xxx_deemphasis_put(struct snd_kcontrol *kcontrol,
461 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100463 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 int chip = AK_GET_CHIP(kcontrol->private_value);
465 int addr = AK_GET_ADDR(kcontrol->private_value);
466 int shift = AK_GET_SHIFT(kcontrol->private_value);
467 unsigned char nval = ucontrol->value.enumerated.item[0] & 3;
468 int change;
469
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200470 nval = (nval << shift) |
471 (snd_akm4xxx_get(ak, chip, addr) & ~(3 << shift));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 change = snd_akm4xxx_get(ak, chip, addr) != nval;
473 if (change)
474 snd_akm4xxx_write(ak, chip, addr, nval);
475 return change;
476}
477
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200478#define ak4xxx_switch_info snd_ctl_boolean_mono_info
Jochen Voss30ba6e22006-08-09 14:26:26 +0200479
480static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol,
481 struct snd_ctl_elem_value *ucontrol)
482{
483 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
484 int chip = AK_GET_CHIP(kcontrol->private_value);
485 int addr = AK_GET_ADDR(kcontrol->private_value);
486 int shift = AK_GET_SHIFT(kcontrol->private_value);
487 int invert = AK_GET_INVERT(kcontrol->private_value);
Pavel Hofmanea7cfcd2007-05-19 17:21:04 +0200488 /* we observe the (1<<shift) bit only */
489 unsigned char val = snd_akm4xxx_get(ak, chip, addr) & (1<<shift);
Jochen Voss30ba6e22006-08-09 14:26:26 +0200490 if (invert)
491 val = ! val;
492 ucontrol->value.integer.value[0] = (val & (1<<shift)) != 0;
493 return 0;
494}
495
496static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
497 struct snd_ctl_elem_value *ucontrol)
498{
499 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
500 int chip = AK_GET_CHIP(kcontrol->private_value);
501 int addr = AK_GET_ADDR(kcontrol->private_value);
502 int shift = AK_GET_SHIFT(kcontrol->private_value);
503 int invert = AK_GET_INVERT(kcontrol->private_value);
504 long flag = ucontrol->value.integer.value[0];
505 unsigned char val, oval;
506 int change;
507
508 if (invert)
509 flag = ! flag;
510 oval = snd_akm4xxx_get(ak, chip, addr);
511 if (flag)
512 val = oval | (1<<shift);
513 else
514 val = oval & ~(1<<shift);
515 change = (oval != val);
516 if (change)
517 snd_akm4xxx_write(ak, chip, addr, val);
518 return change;
519}
520
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200521#define AK5365_NUM_INPUTS 5
522
Takashi Iwai02ff1322007-11-15 16:15:29 +0100523static int ak4xxx_capture_num_inputs(struct snd_akm4xxx *ak, int mixer_ch)
524{
525 int num_names;
526 const char **input_names;
527
528 input_names = ak->adc_info[mixer_ch].input_names;
529 num_names = 0;
530 while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
531 ++num_names;
532 return num_names;
533}
534
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200535static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
536 struct snd_ctl_elem_info *uinfo)
537{
538 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
539 int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
540 const char **input_names;
541 int num_names, idx;
542
Takashi Iwai02ff1322007-11-15 16:15:29 +0100543 num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
544 if (!num_names)
545 return -EINVAL;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200546 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
547 uinfo->count = 1;
548 uinfo->value.enumerated.items = num_names;
549 idx = uinfo->value.enumerated.item;
550 if (idx >= num_names)
551 return -EINVAL;
Takashi Iwai02ff1322007-11-15 16:15:29 +0100552 input_names = ak->adc_info[mixer_ch].input_names;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200553 strncpy(uinfo->value.enumerated.name, input_names[idx],
554 sizeof(uinfo->value.enumerated.name));
555 return 0;
556}
557
558static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol,
559 struct snd_ctl_elem_value *ucontrol)
560{
561 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
562 int chip = AK_GET_CHIP(kcontrol->private_value);
563 int addr = AK_GET_ADDR(kcontrol->private_value);
564 int mask = AK_GET_MASK(kcontrol->private_value);
565 unsigned char val;
566
567 val = snd_akm4xxx_get(ak, chip, addr) & mask;
568 ucontrol->value.enumerated.item[0] = val;
569 return 0;
570}
571
572static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol,
573 struct snd_ctl_elem_value *ucontrol)
574{
575 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Takashi Iwai02ff1322007-11-15 16:15:29 +0100576 int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200577 int chip = AK_GET_CHIP(kcontrol->private_value);
578 int addr = AK_GET_ADDR(kcontrol->private_value);
579 int mask = AK_GET_MASK(kcontrol->private_value);
580 unsigned char oval, val;
Takashi Iwai02ff1322007-11-15 16:15:29 +0100581 int num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
582
583 if (ucontrol->value.enumerated.item[0] >= num_names)
584 return -EINVAL;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200585
586 oval = snd_akm4xxx_get(ak, chip, addr);
587 val = oval & ~mask;
588 val |= ucontrol->value.enumerated.item[0] & mask;
589 if (val != oval) {
590 snd_akm4xxx_write(ak, chip, addr, val);
591 return 1;
592 }
593 return 0;
594}
595
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596/*
597 * build AK4xxx controls
598 */
599
Takashi Iwai723b2b02006-08-30 16:49:54 +0200600static int build_dac_controls(struct snd_akm4xxx *ak)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601{
Takashi Iwai723b2b02006-08-30 16:49:54 +0200602 int idx, err, mixer_ch, num_stereo;
603 struct snd_kcontrol_new knew;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604
Takashi Iwai723b2b02006-08-30 16:49:54 +0200605 mixer_ch = 0;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200606 for (idx = 0; idx < ak->num_dacs; ) {
Pavel Hofmanea7cfcd2007-05-19 17:21:04 +0200607 /* mute control for Revolution 7.1 - AK4381 */
608 if (ak->type == SND_AK4381
609 && ak->dac_info[mixer_ch].switch_name) {
610 memset(&knew, 0, sizeof(knew));
611 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
612 knew.count = 1;
613 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
614 knew.name = ak->dac_info[mixer_ch].switch_name;
615 knew.info = ak4xxx_switch_info;
616 knew.get = ak4xxx_switch_get;
617 knew.put = ak4xxx_switch_put;
618 knew.access = 0;
619 /* register 1, bit 0 (SMUTE): 0 = normal operation,
620 1 = mute */
621 knew.private_value =
622 AK_COMPOSE(idx/2, 1, 0, 0) | AK_INVERT;
623 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
624 if (err < 0)
625 return err;
626 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200627 memset(&knew, 0, sizeof(knew));
628 if (! ak->dac_info || ! ak->dac_info[mixer_ch].name) {
629 knew.name = "DAC Volume";
630 knew.index = mixer_ch + ak->idx_offset * 2;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200631 num_stereo = 1;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200632 } else {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200633 knew.name = ak->dac_info[mixer_ch].name;
634 num_stereo = ak->dac_info[mixer_ch].num_channels;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200635 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200636 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
637 knew.count = 1;
638 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
639 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200640 if (num_stereo == 2) {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200641 knew.info = snd_akm4xxx_stereo_volume_info;
642 knew.get = snd_akm4xxx_stereo_volume_get;
643 knew.put = snd_akm4xxx_stereo_volume_put;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200644 } else {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200645 knew.info = snd_akm4xxx_volume_info;
646 knew.get = snd_akm4xxx_volume_get;
647 knew.put = snd_akm4xxx_volume_put;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200648 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 switch (ak->type) {
650 case SND_AK4524:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200651 /* register 6 & 7 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200652 knew.private_value =
653 AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127) |
654 AK_VOL_CVT;
655 knew.tlv.p = db_scale_vol_datt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 break;
657 case SND_AK4528:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200658 /* register 4 & 5 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200659 knew.private_value =
660 AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127) |
661 AK_VOL_CVT;
662 knew.tlv.p = db_scale_vol_datt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 break;
664 case SND_AK4529: {
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200665 /* registers 2-7 and b,c */
666 int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200667 knew.private_value =
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200668 AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200669 knew.tlv.p = db_scale_8bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 break;
671 }
672 case SND_AK4355:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200673 /* register 4-9, chip #0 only */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200674 knew.private_value = AK_COMPOSE(0, idx + 4, 0, 255);
675 knew.tlv.p = db_scale_8bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 break;
Jochen Voss34793072006-08-23 18:35:35 +0200677 case SND_AK4358: {
678 /* register 4-9 and 11-12, chip #0 only */
679 int addr = idx < 6 ? idx + 4 : idx + 5;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200680 knew.private_value =
Jochen Voss34793072006-08-23 18:35:35 +0200681 AK_COMPOSE(0, addr, 0, 127) | AK_NEEDSMSB;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200682 knew.tlv.p = db_scale_7bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 break;
Jochen Voss34793072006-08-23 18:35:35 +0200684 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 case SND_AK4381:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200686 /* register 3 & 4 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200687 knew.private_value =
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200688 AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200689 knew.tlv.p = db_scale_linear;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 break;
691 default:
Takashi Iwai723b2b02006-08-30 16:49:54 +0200692 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 }
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200694
Takashi Iwai723b2b02006-08-30 16:49:54 +0200695 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200696 if (err < 0)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200697 return err;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200698
699 idx += num_stereo;
700 mixer_ch++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200702 return 0;
703}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
Takashi Iwai723b2b02006-08-30 16:49:54 +0200705static int build_adc_controls(struct snd_akm4xxx *ak)
706{
707 int idx, err, mixer_ch, num_stereo;
708 struct snd_kcontrol_new knew;
709
710 mixer_ch = 0;
711 for (idx = 0; idx < ak->num_adcs;) {
712 memset(&knew, 0, sizeof(knew));
713 if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) {
714 knew.name = "ADC Volume";
715 knew.index = mixer_ch + ak->idx_offset * 2;
716 num_stereo = 1;
717 } else {
718 knew.name = ak->adc_info[mixer_ch].name;
719 num_stereo = ak->adc_info[mixer_ch].num_channels;
720 }
721 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
722 knew.count = 1;
723 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
724 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
725 if (num_stereo == 2) {
726 knew.info = snd_akm4xxx_stereo_volume_info;
727 knew.get = snd_akm4xxx_stereo_volume_get;
728 knew.put = snd_akm4xxx_stereo_volume_put;
729 } else {
730 knew.info = snd_akm4xxx_volume_info;
731 knew.get = snd_akm4xxx_volume_get;
732 knew.put = snd_akm4xxx_volume_put;
733 }
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200734 /* register 4 & 5 */
Takashi Iwai854b66e2006-09-08 12:27:38 +0200735 if (ak->type == SND_AK5365)
736 knew.private_value =
737 AK_COMPOSE(idx/2, (idx%2) + 4, 0, 151) |
738 AK_VOL_CVT | AK_IPGA;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200739 else
Takashi Iwai854b66e2006-09-08 12:27:38 +0200740 knew.private_value =
741 AK_COMPOSE(idx/2, (idx%2) + 4, 0, 163) |
742 AK_VOL_CVT | AK_IPGA;
743 knew.tlv.p = db_scale_vol_datt;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200744 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
745 if (err < 0)
746 return err;
747
748 if (ak->type == SND_AK5365 && (idx % 2) == 0) {
749 if (! ak->adc_info ||
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200750 ! ak->adc_info[mixer_ch].switch_name) {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200751 knew.name = "Capture Switch";
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200752 knew.index = mixer_ch + ak->idx_offset * 2;
753 } else
Takashi Iwai723b2b02006-08-30 16:49:54 +0200754 knew.name = ak->adc_info[mixer_ch].switch_name;
755 knew.info = ak4xxx_switch_info;
756 knew.get = ak4xxx_switch_get;
757 knew.put = ak4xxx_switch_put;
758 knew.access = 0;
759 /* register 2, bit 0 (SMUTE): 0 = normal operation,
760 1 = mute */
761 knew.private_value =
762 AK_COMPOSE(idx/2, 2, 0, 0) | AK_INVERT;
763 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
764 if (err < 0)
765 return err;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200766
767 memset(&knew, 0, sizeof(knew));
768 knew.name = ak->adc_info[mixer_ch].selector_name;
769 if (!knew.name) {
770 knew.name = "Capture Channel";
771 knew.index = mixer_ch + ak->idx_offset * 2;
772 }
773
774 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
775 knew.info = ak4xxx_capture_source_info;
776 knew.get = ak4xxx_capture_source_get;
777 knew.put = ak4xxx_capture_source_put;
778 knew.access = 0;
779 /* input selector control: reg. 1, bits 0-2.
780 * mis-use 'shift' to pass mixer_ch */
781 knew.private_value
782 = AK_COMPOSE(idx/2, 1, mixer_ch, 0x07);
783 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
784 if (err < 0)
785 return err;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200786 }
787
788 idx += num_stereo;
789 mixer_ch++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200791 return 0;
792}
Jochen Voss683fe152006-08-08 21:12:44 +0200793
Takashi Iwai723b2b02006-08-30 16:49:54 +0200794static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
795{
796 int idx, err;
797 struct snd_kcontrol_new knew;
Jochen Voss30ba6e22006-08-09 14:26:26 +0200798
Takashi Iwai723b2b02006-08-30 16:49:54 +0200799 for (idx = 0; idx < num_emphs; idx++) {
800 memset(&knew, 0, sizeof(knew));
801 knew.name = "Deemphasis";
802 knew.index = idx + ak->idx_offset;
803 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
804 knew.count = 1;
805 knew.info = snd_akm4xxx_deemphasis_info;
806 knew.get = snd_akm4xxx_deemphasis_get;
807 knew.put = snd_akm4xxx_deemphasis_put;
808 switch (ak->type) {
809 case SND_AK4524:
810 case SND_AK4528:
811 /* register 3 */
812 knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
813 break;
814 case SND_AK4529: {
815 int shift = idx == 3 ? 6 : (2 - idx) * 2;
816 /* register 8 with shift */
817 knew.private_value = AK_COMPOSE(0, 8, shift, 0);
818 break;
819 }
820 case SND_AK4355:
821 case SND_AK4358:
822 knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
823 break;
824 case SND_AK4381:
825 knew.private_value = AK_COMPOSE(idx, 1, 1, 0);
826 break;
827 default:
828 return -EINVAL;
829 }
830 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
Jochen Voss30ba6e22006-08-09 14:26:26 +0200831 if (err < 0)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200832 return err;
833 }
834 return 0;
835}
836
837int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
838{
839 int err, num_emphs;
840
841 err = build_dac_controls(ak);
842 if (err < 0)
843 return err;
844
Takashi Iwai854b66e2006-09-08 12:27:38 +0200845 err = build_adc_controls(ak);
846 if (err < 0)
847 return err;
Jochen Voss683fe152006-08-08 21:12:44 +0200848
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
850 num_emphs = 1;
851 else
852 num_emphs = ak->num_dacs / 2;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200853 err = build_deemphasis(ak, num_emphs);
854 if (err < 0)
855 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856
Takashi Iwai723b2b02006-08-30 16:49:54 +0200857 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858}
Takashi Iwai723b2b02006-08-30 16:49:54 +0200859
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200860EXPORT_SYMBOL(snd_akm4xxx_build_controls);
861
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862static int __init alsa_akm4xxx_module_init(void)
863{
864 return 0;
865}
866
867static void __exit alsa_akm4xxx_module_exit(void)
868{
869}
870
871module_init(alsa_akm4xxx_module_init)
872module_exit(alsa_akm4xxx_module_exit)