blob: c34cb4684607ca4b9c3c0cd0e95a63b36a45e426 [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 *
5 * Copyright (c) 2000-2004 Jaroslav Kysela <perex@suse.cz>,
6 * Takashi Iwai <tiwai@suse.de>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <sound/driver.h>
25#include <asm/io.h>
26#include <linux/delay.h>
27#include <linux/interrupt.h>
28#include <linux/init.h>
29#include <sound/core.h>
30#include <sound/control.h>
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
34MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>");
35MODULE_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 Iwai723b2b02006-08-30 16:49:54 +020046 /* don't overwrite with IPGA data */
47 if ((ak->type != SND_AK4524 && ak->type != SND_AK5365) ||
48 (reg != 0x04 && reg != 0x05) || (val & 0x80) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070049 snd_akm4xxx_set(ak, chip, reg, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 ak->ops.unlock(ak, chip);
51}
52
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020053EXPORT_SYMBOL(snd_akm4xxx_write);
54
55/* reset procedure for AK4524 and AK4528 */
56static void ak4524_reset(struct snd_akm4xxx *ak, int state)
57{
58 unsigned int chip;
59 unsigned char reg, maxreg;
60
61 if (ak->type == SND_AK4528)
62 maxreg = 0x06;
63 else
64 maxreg = 0x08;
65 for (chip = 0; chip < ak->num_dacs/2; chip++) {
66 snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03);
67 if (state)
68 continue;
69 /* DAC volumes */
70 for (reg = 0x04; reg < maxreg; reg++)
71 snd_akm4xxx_write(ak, chip, reg,
72 snd_akm4xxx_get(ak, chip, reg));
73 if (ak->type == SND_AK4528)
74 continue;
75 /* IPGA */
76 for (reg = 0x04; reg < 0x06; reg++)
77 snd_akm4xxx_write(ak, chip, reg,
Takashi Iwai723b2b02006-08-30 16:49:54 +020078 snd_akm4xxx_get_ipga(ak, chip, reg) | 0x80);
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020079 }
80}
81
82/* reset procedure for AK4355 and AK4358 */
83static void ak4355_reset(struct snd_akm4xxx *ak, int state)
84{
85 unsigned char reg;
86
87 if (state) {
88 snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */
89 return;
90 }
91 for (reg = 0x00; reg < 0x0b; reg++)
92 if (reg != 0x01)
93 snd_akm4xxx_write(ak, 0, reg,
94 snd_akm4xxx_get(ak, 0, reg));
95 snd_akm4xxx_write(ak, 0, 0x01, 0x01); /* un-reset, unmute */
96}
97
98/* reset procedure for AK4381 */
99static void ak4381_reset(struct snd_akm4xxx *ak, int state)
100{
101 unsigned int chip;
102 unsigned char reg;
103
104 for (chip = 0; chip < ak->num_dacs/2; chip++) {
105 snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f);
106 if (state)
107 continue;
108 for (reg = 0x01; reg < 0x05; reg++)
109 snd_akm4xxx_write(ak, chip, reg,
110 snd_akm4xxx_get(ak, chip, reg));
111 }
112}
113
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114/*
115 * reset the AKM codecs
116 * @state: 1 = reset codec, 0 = restore the registers
117 *
118 * assert the reset operation and restores the register values to the chips.
119 */
Takashi Iwai97f02e02005-11-17 14:17:19 +0100120void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 switch (ak->type) {
123 case SND_AK4524:
124 case SND_AK4528:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200125 ak4524_reset(ak, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 break;
127 case SND_AK4529:
128 /* FIXME: needed for ak4529? */
129 break;
130 case SND_AK4355:
131 case SND_AK4358:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200132 ak4355_reset(ak, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 break;
134 case SND_AK4381:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200135 ak4381_reset(ak, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 break;
Takashi Iwaicf939072006-08-09 14:33:27 +0200137 default:
138 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 }
140}
141
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200142EXPORT_SYMBOL(snd_akm4xxx_reset);
143
Takashi Iwai723b2b02006-08-30 16:49:54 +0200144
145/*
146 * Volume conversion table for non-linear volumes
147 * from -63.5dB (mute) to 0dB step 0.5dB
148 *
149 * Used for AK4524 input/ouput attenuation, AK4528, and
150 * AK5365 input attenuation
151 */
152static unsigned char vol_cvt_datt[128] = {
153 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04,
154 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06,
155 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a,
156 0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f,
157 0x10, 0x10, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14,
158 0x15, 0x16, 0x17, 0x17, 0x18, 0x19, 0x1a, 0x1c,
159 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x23,
160 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, 0x2b, 0x2d,
161 0x2e, 0x30, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
162 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3e, 0x3f, 0x40,
163 0x41, 0x42, 0x43, 0x44, 0x46, 0x47, 0x48, 0x4a,
164 0x4b, 0x4d, 0x4e, 0x50, 0x51, 0x52, 0x53, 0x54,
165 0x55, 0x56, 0x58, 0x59, 0x5b, 0x5c, 0x5e, 0x5f,
166 0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x69,
167 0x6a, 0x6c, 0x6d, 0x6f, 0x70, 0x71, 0x72, 0x73,
168 0x75, 0x76, 0x77, 0x79, 0x7a, 0x7c, 0x7d, 0x7f,
169};
170
171/*
172 * dB tables
173 */
174static DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
175static DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
176static DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
177static DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
178static DECLARE_TLV_DB_SCALE(db_scale_ipga, 0, 50, 0);
179
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180/*
181 * initialize all the ak4xxx chips
182 */
Takashi Iwai97f02e02005-11-17 14:17:19 +0100183void snd_akm4xxx_init(struct snd_akm4xxx *ak)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184{
185 static unsigned char inits_ak4524[] = {
186 0x00, 0x07, /* 0: all power up */
187 0x01, 0x00, /* 1: ADC/DAC reset */
188 0x02, 0x60, /* 2: 24bit I2S */
189 0x03, 0x19, /* 3: deemphasis off */
190 0x01, 0x03, /* 1: ADC/DAC enable */
191 0x04, 0x00, /* 4: ADC left muted */
192 0x05, 0x00, /* 5: ADC right muted */
193 0x04, 0x80, /* 4: ADC IPGA gain 0dB */
194 0x05, 0x80, /* 5: ADC IPGA gain 0dB */
195 0x06, 0x00, /* 6: DAC left muted */
196 0x07, 0x00, /* 7: DAC right muted */
197 0xff, 0xff
198 };
199 static unsigned char inits_ak4528[] = {
200 0x00, 0x07, /* 0: all power up */
201 0x01, 0x00, /* 1: ADC/DAC reset */
202 0x02, 0x60, /* 2: 24bit I2S */
203 0x03, 0x0d, /* 3: deemphasis off, turn LR highpass filters on */
204 0x01, 0x03, /* 1: ADC/DAC enable */
205 0x04, 0x00, /* 4: ADC left muted */
206 0x05, 0x00, /* 5: ADC right muted */
207 0xff, 0xff
208 };
209 static unsigned char inits_ak4529[] = {
210 0x09, 0x01, /* 9: ATS=0, RSTN=1 */
211 0x0a, 0x3f, /* A: all power up, no zero/overflow detection */
212 0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */
213 0x01, 0x00, /* 1: ACKS=0, ADC, loop off */
214 0x02, 0xff, /* 2: LOUT1 muted */
215 0x03, 0xff, /* 3: ROUT1 muted */
216 0x04, 0xff, /* 4: LOUT2 muted */
217 0x05, 0xff, /* 5: ROUT2 muted */
218 0x06, 0xff, /* 6: LOUT3 muted */
219 0x07, 0xff, /* 7: ROUT3 muted */
220 0x0b, 0xff, /* B: LOUT4 muted */
221 0x0c, 0xff, /* C: ROUT4 muted */
222 0x08, 0x55, /* 8: deemphasis all off */
223 0xff, 0xff
224 };
225 static unsigned char inits_ak4355[] = {
226 0x01, 0x02, /* 1: reset and soft-mute */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200227 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
228 * disable DZF, sharp roll-off, RSTN#=0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
230 // 0x02, 0x2e, /* quad speed */
231 0x03, 0x01, /* 3: de-emphasis off */
232 0x04, 0x00, /* 4: LOUT1 volume muted */
233 0x05, 0x00, /* 5: ROUT1 volume muted */
234 0x06, 0x00, /* 6: LOUT2 volume muted */
235 0x07, 0x00, /* 7: ROUT2 volume muted */
236 0x08, 0x00, /* 8: LOUT3 volume muted */
237 0x09, 0x00, /* 9: ROUT3 volume muted */
238 0x0a, 0x00, /* a: DATT speed=0, ignore DZF */
239 0x01, 0x01, /* 1: un-reset, unmute */
240 0xff, 0xff
241 };
242 static unsigned char inits_ak4358[] = {
243 0x01, 0x02, /* 1: reset and soft-mute */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200244 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
245 * disable DZF, sharp roll-off, RSTN#=0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
247 // 0x02, 0x2e, /* quad speed */
248 0x03, 0x01, /* 3: de-emphasis off */
249 0x04, 0x00, /* 4: LOUT1 volume muted */
250 0x05, 0x00, /* 5: ROUT1 volume muted */
251 0x06, 0x00, /* 6: LOUT2 volume muted */
252 0x07, 0x00, /* 7: ROUT2 volume muted */
253 0x08, 0x00, /* 8: LOUT3 volume muted */
254 0x09, 0x00, /* 9: ROUT3 volume muted */
255 0x0b, 0x00, /* b: LOUT4 volume muted */
256 0x0c, 0x00, /* c: ROUT4 volume muted */
257 0x0a, 0x00, /* a: DATT speed=0, ignore DZF */
258 0x01, 0x01, /* 1: un-reset, unmute */
259 0xff, 0xff
260 };
261 static unsigned char inits_ak4381[] = {
262 0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200263 0x01, 0x02, /* 1: de-emphasis off, normal speed,
264 * sharp roll-off, DZF off */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 // 0x01, 0x12, /* quad speed */
266 0x02, 0x00, /* 2: DZF disabled */
267 0x03, 0x00, /* 3: LATT 0 */
268 0x04, 0x00, /* 4: RATT 0 */
269 0x00, 0x0f, /* 0: power-up, un-reset */
270 0xff, 0xff
271 };
272
273 int chip, num_chips;
274 unsigned char *ptr, reg, data, *inits;
275
Takashi Iwai723b2b02006-08-30 16:49:54 +0200276 memset(ak->images, 0, sizeof(ak->images));
277 memset(ak->volumes, 0, sizeof(ak->volumes));
278
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 switch (ak->type) {
280 case SND_AK4524:
281 inits = inits_ak4524;
282 num_chips = ak->num_dacs / 2;
283 break;
284 case SND_AK4528:
285 inits = inits_ak4528;
286 num_chips = ak->num_dacs / 2;
287 break;
288 case SND_AK4529:
289 inits = inits_ak4529;
290 num_chips = 1;
291 break;
292 case SND_AK4355:
293 inits = inits_ak4355;
294 num_chips = 1;
295 break;
296 case SND_AK4358:
297 inits = inits_ak4358;
298 num_chips = 1;
299 break;
300 case SND_AK4381:
301 inits = inits_ak4381;
302 num_chips = ak->num_dacs / 2;
303 break;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200304 case SND_AK5365:
305 /* FIXME: any init sequence? */
306 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 default:
308 snd_BUG();
309 return;
310 }
311
312 for (chip = 0; chip < num_chips; chip++) {
313 ptr = inits;
314 while (*ptr != 0xff) {
315 reg = *ptr++;
316 data = *ptr++;
317 snd_akm4xxx_write(ak, chip, reg, data);
318 }
319 }
320}
321
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200322EXPORT_SYMBOL(snd_akm4xxx_init);
323
Takashi Iwai723b2b02006-08-30 16:49:54 +0200324/*
325 * Mixer callbacks
326 */
327#define AK_VOL_CVT (1<<21) /* need dB conversion */
328#define AK_NEEDSMSB (1<<22) /* need MSB update bit */
329#define AK_INVERT (1<<23) /* data is inverted */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330#define AK_GET_CHIP(val) (((val) >> 8) & 0xff)
331#define AK_GET_ADDR(val) ((val) & 0xff)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200332#define AK_GET_SHIFT(val) (((val) >> 16) & 0x1f)
333#define AK_GET_VOL_CVT(val) (((val) >> 21) & 1)
Jochen Voss34793072006-08-23 18:35:35 +0200334#define AK_GET_NEEDSMSB(val) (((val) >> 22) & 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335#define AK_GET_INVERT(val) (((val) >> 23) & 1)
336#define AK_GET_MASK(val) (((val) >> 24) & 0xff)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200337#define AK_COMPOSE(chip,addr,shift,mask) \
338 (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
Takashi Iwai97f02e02005-11-17 14:17:19 +0100340static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol,
341 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342{
343 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
344
345 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
346 uinfo->count = 1;
347 uinfo->value.integer.min = 0;
348 uinfo->value.integer.max = mask;
349 return 0;
350}
351
Takashi Iwai97f02e02005-11-17 14:17:19 +0100352static int snd_akm4xxx_volume_get(struct snd_kcontrol *kcontrol,
353 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100355 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 int chip = AK_GET_CHIP(kcontrol->private_value);
357 int addr = AK_GET_ADDR(kcontrol->private_value);
Jochen Voss34793072006-08-23 18:35:35 +0200358
Takashi Iwai723b2b02006-08-30 16:49:54 +0200359 ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 return 0;
361}
362
Takashi Iwai723b2b02006-08-30 16:49:54 +0200363static int put_ak_reg(struct snd_kcontrol *kcontrol, int addr,
364 unsigned char nval)
365{
366 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
367 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
368 int chip = AK_GET_CHIP(kcontrol->private_value);
369
370 if (snd_akm4xxx_get_vol(ak, chip, addr) == nval)
371 return 0;
372
373 snd_akm4xxx_set_vol(ak, chip, addr, nval);
374 if (AK_GET_VOL_CVT(kcontrol->private_value))
375 nval = vol_cvt_datt[nval];
376 if (AK_GET_INVERT(kcontrol->private_value))
377 nval = mask - nval;
378 if (AK_GET_NEEDSMSB(kcontrol->private_value))
379 nval |= 0x80;
380 snd_akm4xxx_write(ak, chip, addr, nval);
381 return 1;
382}
383
Takashi Iwai97f02e02005-11-17 14:17:19 +0100384static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
385 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386{
Takashi Iwai723b2b02006-08-30 16:49:54 +0200387 return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value),
388 ucontrol->value.integer.value[0]);
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 Iwai723b2b02006-08-30 16:49:54 +0200419 int change;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200420
Takashi Iwai723b2b02006-08-30 16:49:54 +0200421 change = put_ak_reg(kcontrol, addr, ucontrol->value.integer.value[0]);
422 change |= put_ak_reg(kcontrol, addr + 1,
423 ucontrol->value.integer.value[1]);
424 return change;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200425}
426
Takashi Iwai723b2b02006-08-30 16:49:54 +0200427#define snd_akm4xxx_ipga_gain_info snd_akm4xxx_volume_info
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
Takashi Iwai97f02e02005-11-17 14:17:19 +0100429static int snd_akm4xxx_ipga_gain_get(struct snd_kcontrol *kcontrol,
430 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100432 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 int chip = AK_GET_CHIP(kcontrol->private_value);
434 int addr = AK_GET_ADDR(kcontrol->private_value);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200435
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200436 ucontrol->value.integer.value[0] =
Takashi Iwai723b2b02006-08-30 16:49:54 +0200437 snd_akm4xxx_get_ipga(ak, chip, addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 return 0;
439}
440
Takashi Iwai723b2b02006-08-30 16:49:54 +0200441static int put_ak_ipga(struct snd_kcontrol *kcontrol, int addr,
442 unsigned char nval)
443{
444 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
445 int chip = AK_GET_CHIP(kcontrol->private_value);
446
447 if (snd_akm4xxx_get_ipga(ak, chip, addr) == nval)
448 return 0;
449 snd_akm4xxx_set_ipga(ak, chip, addr, nval);
450 snd_akm4xxx_write(ak, chip, addr, nval | 0x80); /* need MSB */
451 return 1;
452}
453
Takashi Iwai97f02e02005-11-17 14:17:19 +0100454static int snd_akm4xxx_ipga_gain_put(struct snd_kcontrol *kcontrol,
455 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456{
Takashi Iwai723b2b02006-08-30 16:49:54 +0200457 return put_ak_ipga(kcontrol, AK_GET_ADDR(kcontrol->private_value),
458 ucontrol->value.integer.value[0]);
459}
460
461#define snd_akm4xxx_stereo_gain_info snd_akm4xxx_stereo_volume_info
462
463static int snd_akm4xxx_stereo_gain_get(struct snd_kcontrol *kcontrol,
464 struct snd_ctl_elem_value *ucontrol)
465{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100466 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 int chip = AK_GET_CHIP(kcontrol->private_value);
468 int addr = AK_GET_ADDR(kcontrol->private_value);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200469
470 ucontrol->value.integer.value[0] =
471 snd_akm4xxx_get_ipga(ak, chip, addr);
472 ucontrol->value.integer.value[1] =
473 snd_akm4xxx_get_ipga(ak, chip, addr + 1);
474 return 0;
475}
476
477static int snd_akm4xxx_stereo_gain_put(struct snd_kcontrol *kcontrol,
478 struct snd_ctl_elem_value *ucontrol)
479{
480 int addr = AK_GET_ADDR(kcontrol->private_value);
481 int change;
482
483 change = put_ak_ipga(kcontrol, addr, ucontrol->value.integer.value[0]);
484 change |= put_ak_ipga(kcontrol, addr + 1,
485 ucontrol->value.integer.value[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 return change;
487}
488
Takashi Iwai97f02e02005-11-17 14:17:19 +0100489static int snd_akm4xxx_deemphasis_info(struct snd_kcontrol *kcontrol,
490 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491{
492 static char *texts[4] = {
493 "44.1kHz", "Off", "48kHz", "32kHz",
494 };
495 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
496 uinfo->count = 1;
497 uinfo->value.enumerated.items = 4;
498 if (uinfo->value.enumerated.item >= 4)
499 uinfo->value.enumerated.item = 3;
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200500 strcpy(uinfo->value.enumerated.name,
501 texts[uinfo->value.enumerated.item]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 return 0;
503}
504
Takashi Iwai97f02e02005-11-17 14:17:19 +0100505static int snd_akm4xxx_deemphasis_get(struct snd_kcontrol *kcontrol,
506 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100508 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 int chip = AK_GET_CHIP(kcontrol->private_value);
510 int addr = AK_GET_ADDR(kcontrol->private_value);
511 int shift = AK_GET_SHIFT(kcontrol->private_value);
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200512 ucontrol->value.enumerated.item[0] =
513 (snd_akm4xxx_get(ak, chip, addr) >> shift) & 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 return 0;
515}
516
Takashi Iwai97f02e02005-11-17 14:17:19 +0100517static int snd_akm4xxx_deemphasis_put(struct snd_kcontrol *kcontrol,
518 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100520 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 int chip = AK_GET_CHIP(kcontrol->private_value);
522 int addr = AK_GET_ADDR(kcontrol->private_value);
523 int shift = AK_GET_SHIFT(kcontrol->private_value);
524 unsigned char nval = ucontrol->value.enumerated.item[0] & 3;
525 int change;
526
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200527 nval = (nval << shift) |
528 (snd_akm4xxx_get(ak, chip, addr) & ~(3 << shift));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 change = snd_akm4xxx_get(ak, chip, addr) != nval;
530 if (change)
531 snd_akm4xxx_write(ak, chip, addr, nval);
532 return change;
533}
534
Jochen Voss30ba6e22006-08-09 14:26:26 +0200535static int ak4xxx_switch_info(struct snd_kcontrol *kcontrol,
536 struct snd_ctl_elem_info *uinfo)
537{
538 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
539 uinfo->count = 1;
540 uinfo->value.integer.min = 0;
541 uinfo->value.integer.max = 1;
542 return 0;
543}
544
545static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol,
546 struct snd_ctl_elem_value *ucontrol)
547{
548 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
549 int chip = AK_GET_CHIP(kcontrol->private_value);
550 int addr = AK_GET_ADDR(kcontrol->private_value);
551 int shift = AK_GET_SHIFT(kcontrol->private_value);
552 int invert = AK_GET_INVERT(kcontrol->private_value);
553 unsigned char val = snd_akm4xxx_get(ak, chip, addr);
554
555 if (invert)
556 val = ! val;
557 ucontrol->value.integer.value[0] = (val & (1<<shift)) != 0;
558 return 0;
559}
560
561static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
562 struct snd_ctl_elem_value *ucontrol)
563{
564 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
565 int chip = AK_GET_CHIP(kcontrol->private_value);
566 int addr = AK_GET_ADDR(kcontrol->private_value);
567 int shift = AK_GET_SHIFT(kcontrol->private_value);
568 int invert = AK_GET_INVERT(kcontrol->private_value);
569 long flag = ucontrol->value.integer.value[0];
570 unsigned char val, oval;
571 int change;
572
573 if (invert)
574 flag = ! flag;
575 oval = snd_akm4xxx_get(ak, chip, addr);
576 if (flag)
577 val = oval | (1<<shift);
578 else
579 val = oval & ~(1<<shift);
580 change = (oval != val);
581 if (change)
582 snd_akm4xxx_write(ak, chip, addr, val);
583 return change;
584}
585
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586/*
587 * build AK4xxx controls
588 */
589
Takashi Iwai723b2b02006-08-30 16:49:54 +0200590static int build_dac_controls(struct snd_akm4xxx *ak)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591{
Takashi Iwai723b2b02006-08-30 16:49:54 +0200592 int idx, err, mixer_ch, num_stereo;
593 struct snd_kcontrol_new knew;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
Takashi Iwai723b2b02006-08-30 16:49:54 +0200595 mixer_ch = 0;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200596 for (idx = 0; idx < ak->num_dacs; ) {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200597 memset(&knew, 0, sizeof(knew));
598 if (! ak->dac_info || ! ak->dac_info[mixer_ch].name) {
599 knew.name = "DAC Volume";
600 knew.index = mixer_ch + ak->idx_offset * 2;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200601 num_stereo = 1;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200602 } else {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200603 knew.name = ak->dac_info[mixer_ch].name;
604 num_stereo = ak->dac_info[mixer_ch].num_channels;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200605 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200606 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
607 knew.count = 1;
608 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
609 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200610 if (num_stereo == 2) {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200611 knew.info = snd_akm4xxx_stereo_volume_info;
612 knew.get = snd_akm4xxx_stereo_volume_get;
613 knew.put = snd_akm4xxx_stereo_volume_put;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200614 } else {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200615 knew.info = snd_akm4xxx_volume_info;
616 knew.get = snd_akm4xxx_volume_get;
617 knew.put = snd_akm4xxx_volume_put;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200618 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 switch (ak->type) {
620 case SND_AK4524:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200621 /* register 6 & 7 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200622 knew.private_value =
623 AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127) |
624 AK_VOL_CVT;
625 knew.tlv.p = db_scale_vol_datt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 break;
627 case SND_AK4528:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200628 /* register 4 & 5 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200629 knew.private_value =
630 AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127) |
631 AK_VOL_CVT;
632 knew.tlv.p = db_scale_vol_datt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 break;
634 case SND_AK4529: {
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200635 /* registers 2-7 and b,c */
636 int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200637 knew.private_value =
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200638 AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200639 knew.tlv.p = db_scale_8bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 break;
641 }
642 case SND_AK4355:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200643 /* register 4-9, chip #0 only */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200644 knew.private_value = AK_COMPOSE(0, idx + 4, 0, 255);
645 knew.tlv.p = db_scale_8bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 break;
Jochen Voss34793072006-08-23 18:35:35 +0200647 case SND_AK4358: {
648 /* register 4-9 and 11-12, chip #0 only */
649 int addr = idx < 6 ? idx + 4 : idx + 5;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200650 knew.private_value =
Jochen Voss34793072006-08-23 18:35:35 +0200651 AK_COMPOSE(0, addr, 0, 127) | AK_NEEDSMSB;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200652 knew.tlv.p = db_scale_7bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 break;
Jochen Voss34793072006-08-23 18:35:35 +0200654 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 case SND_AK4381:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200656 /* register 3 & 4 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200657 knew.private_value =
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200658 AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200659 knew.tlv.p = db_scale_linear;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 break;
661 default:
Takashi Iwai723b2b02006-08-30 16:49:54 +0200662 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 }
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200664
Takashi Iwai723b2b02006-08-30 16:49:54 +0200665 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200666 if (err < 0)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200667 return err;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200668
669 idx += num_stereo;
670 mixer_ch++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200672 return 0;
673}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
Takashi Iwai723b2b02006-08-30 16:49:54 +0200675static int build_adc_controls(struct snd_akm4xxx *ak)
676{
677 int idx, err, mixer_ch, num_stereo;
678 struct snd_kcontrol_new knew;
679
680 mixer_ch = 0;
681 for (idx = 0; idx < ak->num_adcs;) {
682 memset(&knew, 0, sizeof(knew));
683 if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) {
684 knew.name = "ADC Volume";
685 knew.index = mixer_ch + ak->idx_offset * 2;
686 num_stereo = 1;
687 } else {
688 knew.name = ak->adc_info[mixer_ch].name;
689 num_stereo = ak->adc_info[mixer_ch].num_channels;
690 }
691 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
692 knew.count = 1;
693 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
694 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
695 if (num_stereo == 2) {
696 knew.info = snd_akm4xxx_stereo_volume_info;
697 knew.get = snd_akm4xxx_stereo_volume_get;
698 knew.put = snd_akm4xxx_stereo_volume_put;
699 } else {
700 knew.info = snd_akm4xxx_volume_info;
701 knew.get = snd_akm4xxx_volume_get;
702 knew.put = snd_akm4xxx_volume_put;
703 }
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200704 /* register 4 & 5 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200705 knew.private_value =
706 AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127) |
707 AK_VOL_CVT;
708 knew.tlv.p = db_scale_vol_datt;
709 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200710 if (err < 0)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200711 return err;
712
713 if (! ak->adc_info || ! ak->adc_info[mixer_ch].gain_name)
714 knew.name = "IPGA Analog Capture Volume";
715 else
716 knew.name = ak->adc_info[mixer_ch].gain_name;
717 if (num_stereo == 2) {
718 knew.info = snd_akm4xxx_stereo_gain_info;
719 knew.get = snd_akm4xxx_stereo_gain_get;
720 knew.put = snd_akm4xxx_stereo_gain_put;
721 } else {
722 knew.info = snd_akm4xxx_ipga_gain_info;
723 knew.get = snd_akm4xxx_ipga_gain_get;
724 knew.put = snd_akm4xxx_ipga_gain_put;
725 }
726 /* register 4 & 5 */
727 if (ak->type == SND_AK4524)
728 knew.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0,
729 24);
730 else /* AK5365 */
731 knew.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0,
732 36);
733 knew.tlv.p = db_scale_ipga;
734 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
735 if (err < 0)
736 return err;
737
738 if (ak->type == SND_AK5365 && (idx % 2) == 0) {
739 if (! ak->adc_info ||
740 ! ak->adc_info[mixer_ch].switch_name)
741 knew.name = "Capture Switch";
742 else
743 knew.name = ak->adc_info[mixer_ch].switch_name;
744 knew.info = ak4xxx_switch_info;
745 knew.get = ak4xxx_switch_get;
746 knew.put = ak4xxx_switch_put;
747 knew.access = 0;
748 /* register 2, bit 0 (SMUTE): 0 = normal operation,
749 1 = mute */
750 knew.private_value =
751 AK_COMPOSE(idx/2, 2, 0, 0) | AK_INVERT;
752 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
753 if (err < 0)
754 return err;
755 }
756
757 idx += num_stereo;
758 mixer_ch++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200760 return 0;
761}
Jochen Voss683fe152006-08-08 21:12:44 +0200762
Takashi Iwai723b2b02006-08-30 16:49:54 +0200763static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
764{
765 int idx, err;
766 struct snd_kcontrol_new knew;
Jochen Voss30ba6e22006-08-09 14:26:26 +0200767
Takashi Iwai723b2b02006-08-30 16:49:54 +0200768 for (idx = 0; idx < num_emphs; idx++) {
769 memset(&knew, 0, sizeof(knew));
770 knew.name = "Deemphasis";
771 knew.index = idx + ak->idx_offset;
772 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
773 knew.count = 1;
774 knew.info = snd_akm4xxx_deemphasis_info;
775 knew.get = snd_akm4xxx_deemphasis_get;
776 knew.put = snd_akm4xxx_deemphasis_put;
777 switch (ak->type) {
778 case SND_AK4524:
779 case SND_AK4528:
780 /* register 3 */
781 knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
782 break;
783 case SND_AK4529: {
784 int shift = idx == 3 ? 6 : (2 - idx) * 2;
785 /* register 8 with shift */
786 knew.private_value = AK_COMPOSE(0, 8, shift, 0);
787 break;
788 }
789 case SND_AK4355:
790 case SND_AK4358:
791 knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
792 break;
793 case SND_AK4381:
794 knew.private_value = AK_COMPOSE(idx, 1, 1, 0);
795 break;
796 default:
797 return -EINVAL;
798 }
799 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
Jochen Voss30ba6e22006-08-09 14:26:26 +0200800 if (err < 0)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200801 return err;
802 }
803 return 0;
804}
805
806int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
807{
808 int err, num_emphs;
809
810 err = build_dac_controls(ak);
811 if (err < 0)
812 return err;
813
814 if (ak->type == SND_AK4524 || ak->type == SND_AK5365) {
815 err = build_adc_controls(ak);
816 if (err < 0)
817 return err;
Jochen Voss683fe152006-08-08 21:12:44 +0200818 }
819
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
821 num_emphs = 1;
822 else
823 num_emphs = ak->num_dacs / 2;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200824 err = build_deemphasis(ak, num_emphs);
825 if (err < 0)
826 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
Takashi Iwai723b2b02006-08-30 16:49:54 +0200828 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829}
Takashi Iwai723b2b02006-08-30 16:49:54 +0200830
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200831EXPORT_SYMBOL(snd_akm4xxx_build_controls);
832
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833static int __init alsa_akm4xxx_module_init(void)
834{
835 return 0;
836}
837
838static void __exit alsa_akm4xxx_module_exit(void)
839{
840}
841
842module_init(alsa_akm4xxx_module_init)
843module_exit(alsa_akm4xxx_module_exit)