blob: fe61b92f4e47ba83dde1cabb02319877f7c58ea9 [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 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 */
143static unsigned char vol_cvt_datt[128] = {
144 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 */
165static DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
166static DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
167static DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
168static 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{
175 static unsigned char inits_ak4524[] = {
176 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 };
187 static unsigned char inits_ak4528[] = {
188 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 };
197 static unsigned char inits_ak4529[] = {
198 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 };
213 static unsigned char inits_ak4355[] = {
214 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 };
230 static unsigned char inits_ak4358[] = {
231 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 };
249 static unsigned char inits_ak4381[] = {
250 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;
262 unsigned char *ptr, reg, data, *inits;
263
Takashi Iwai723b2b02006-08-30 16:49:54 +0200264 memset(ak->images, 0, sizeof(ak->images));
265 memset(ak->volumes, 0, sizeof(ak->volumes));
266
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 switch (ak->type) {
268 case SND_AK4524:
269 inits = inits_ak4524;
270 num_chips = ak->num_dacs / 2;
271 break;
272 case SND_AK4528:
273 inits = inits_ak4528;
274 num_chips = ak->num_dacs / 2;
275 break;
276 case SND_AK4529:
277 inits = inits_ak4529;
278 num_chips = 1;
279 break;
280 case SND_AK4355:
281 inits = inits_ak4355;
282 num_chips = 1;
283 break;
284 case SND_AK4358:
285 inits = inits_ak4358;
286 num_chips = 1;
287 break;
288 case SND_AK4381:
289 inits = inits_ak4381;
290 num_chips = ak->num_dacs / 2;
291 break;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200292 case SND_AK5365:
293 /* FIXME: any init sequence? */
294 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 default:
296 snd_BUG();
297 return;
298 }
299
300 for (chip = 0; chip < num_chips; chip++) {
301 ptr = inits;
302 while (*ptr != 0xff) {
303 reg = *ptr++;
304 data = *ptr++;
305 snd_akm4xxx_write(ak, chip, reg, data);
306 }
307 }
308}
309
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200310EXPORT_SYMBOL(snd_akm4xxx_init);
311
Takashi Iwai723b2b02006-08-30 16:49:54 +0200312/*
313 * Mixer callbacks
314 */
Takashi Iwai854b66e2006-09-08 12:27:38 +0200315#define AK_IPGA (1<<20) /* including IPGA */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200316#define AK_VOL_CVT (1<<21) /* need dB conversion */
317#define AK_NEEDSMSB (1<<22) /* need MSB update bit */
318#define AK_INVERT (1<<23) /* data is inverted */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319#define AK_GET_CHIP(val) (((val) >> 8) & 0xff)
320#define AK_GET_ADDR(val) ((val) & 0xff)
Takashi Iwai854b66e2006-09-08 12:27:38 +0200321#define AK_GET_SHIFT(val) (((val) >> 16) & 0x0f)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200322#define AK_GET_VOL_CVT(val) (((val) >> 21) & 1)
Takashi Iwai854b66e2006-09-08 12:27:38 +0200323#define AK_GET_IPGA(val) (((val) >> 20) & 1)
Jochen Voss34793072006-08-23 18:35:35 +0200324#define AK_GET_NEEDSMSB(val) (((val) >> 22) & 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325#define AK_GET_INVERT(val) (((val) >> 23) & 1)
326#define AK_GET_MASK(val) (((val) >> 24) & 0xff)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200327#define AK_COMPOSE(chip,addr,shift,mask) \
328 (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
Takashi Iwai97f02e02005-11-17 14:17:19 +0100330static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol,
331 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332{
333 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
334
335 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
336 uinfo->count = 1;
337 uinfo->value.integer.min = 0;
338 uinfo->value.integer.max = mask;
339 return 0;
340}
341
Takashi Iwai97f02e02005-11-17 14:17:19 +0100342static int snd_akm4xxx_volume_get(struct snd_kcontrol *kcontrol,
343 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100345 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 int chip = AK_GET_CHIP(kcontrol->private_value);
347 int addr = AK_GET_ADDR(kcontrol->private_value);
Jochen Voss34793072006-08-23 18:35:35 +0200348
Takashi Iwai723b2b02006-08-30 16:49:54 +0200349 ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 return 0;
351}
352
Takashi Iwai723b2b02006-08-30 16:49:54 +0200353static int put_ak_reg(struct snd_kcontrol *kcontrol, int addr,
354 unsigned char nval)
355{
356 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
357 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
358 int chip = AK_GET_CHIP(kcontrol->private_value);
359
360 if (snd_akm4xxx_get_vol(ak, chip, addr) == nval)
361 return 0;
362
363 snd_akm4xxx_set_vol(ak, chip, addr, nval);
Takashi Iwai854b66e2006-09-08 12:27:38 +0200364 if (AK_GET_VOL_CVT(kcontrol->private_value) && nval < 128)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200365 nval = vol_cvt_datt[nval];
Takashi Iwai854b66e2006-09-08 12:27:38 +0200366 if (AK_GET_IPGA(kcontrol->private_value) && nval >= 128)
367 nval++; /* need to correct + 1 since both 127 and 128 are 0dB */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200368 if (AK_GET_INVERT(kcontrol->private_value))
369 nval = mask - nval;
370 if (AK_GET_NEEDSMSB(kcontrol->private_value))
371 nval |= 0x80;
372 snd_akm4xxx_write(ak, chip, addr, nval);
373 return 1;
374}
375
Takashi Iwai97f02e02005-11-17 14:17:19 +0100376static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
377 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378{
Takashi Iwai723b2b02006-08-30 16:49:54 +0200379 return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value),
380 ucontrol->value.integer.value[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381}
382
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200383static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol,
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200384 struct snd_ctl_elem_info *uinfo)
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200385{
386 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
387
388 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
389 uinfo->count = 2;
390 uinfo->value.integer.min = 0;
391 uinfo->value.integer.max = mask;
392 return 0;
393}
394
395static int snd_akm4xxx_stereo_volume_get(struct snd_kcontrol *kcontrol,
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200396 struct snd_ctl_elem_value *ucontrol)
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200397{
398 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
399 int chip = AK_GET_CHIP(kcontrol->private_value);
400 int addr = AK_GET_ADDR(kcontrol->private_value);
Jochen Voss34793072006-08-23 18:35:35 +0200401
Takashi Iwai723b2b02006-08-30 16:49:54 +0200402 ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
403 ucontrol->value.integer.value[1] = snd_akm4xxx_get_vol(ak, chip, addr+1);
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200404 return 0;
405}
406
407static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200408 struct snd_ctl_elem_value *ucontrol)
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200409{
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200410 int addr = AK_GET_ADDR(kcontrol->private_value);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200411 int change;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200412
Takashi Iwai723b2b02006-08-30 16:49:54 +0200413 change = put_ak_reg(kcontrol, addr, ucontrol->value.integer.value[0]);
414 change |= put_ak_reg(kcontrol, addr + 1,
415 ucontrol->value.integer.value[1]);
416 return change;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200417}
418
Takashi Iwai97f02e02005-11-17 14:17:19 +0100419static int snd_akm4xxx_deemphasis_info(struct snd_kcontrol *kcontrol,
420 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421{
422 static char *texts[4] = {
423 "44.1kHz", "Off", "48kHz", "32kHz",
424 };
425 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
426 uinfo->count = 1;
427 uinfo->value.enumerated.items = 4;
428 if (uinfo->value.enumerated.item >= 4)
429 uinfo->value.enumerated.item = 3;
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200430 strcpy(uinfo->value.enumerated.name,
431 texts[uinfo->value.enumerated.item]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 return 0;
433}
434
Takashi Iwai97f02e02005-11-17 14:17:19 +0100435static int snd_akm4xxx_deemphasis_get(struct snd_kcontrol *kcontrol,
436 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100438 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 int chip = AK_GET_CHIP(kcontrol->private_value);
440 int addr = AK_GET_ADDR(kcontrol->private_value);
441 int shift = AK_GET_SHIFT(kcontrol->private_value);
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200442 ucontrol->value.enumerated.item[0] =
443 (snd_akm4xxx_get(ak, chip, addr) >> shift) & 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 return 0;
445}
446
Takashi Iwai97f02e02005-11-17 14:17:19 +0100447static int snd_akm4xxx_deemphasis_put(struct snd_kcontrol *kcontrol,
448 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100450 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 int chip = AK_GET_CHIP(kcontrol->private_value);
452 int addr = AK_GET_ADDR(kcontrol->private_value);
453 int shift = AK_GET_SHIFT(kcontrol->private_value);
454 unsigned char nval = ucontrol->value.enumerated.item[0] & 3;
455 int change;
456
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200457 nval = (nval << shift) |
458 (snd_akm4xxx_get(ak, chip, addr) & ~(3 << shift));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 change = snd_akm4xxx_get(ak, chip, addr) != nval;
460 if (change)
461 snd_akm4xxx_write(ak, chip, addr, nval);
462 return change;
463}
464
Jochen Voss30ba6e22006-08-09 14:26:26 +0200465static int ak4xxx_switch_info(struct snd_kcontrol *kcontrol,
466 struct snd_ctl_elem_info *uinfo)
467{
468 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
469 uinfo->count = 1;
470 uinfo->value.integer.min = 0;
471 uinfo->value.integer.max = 1;
472 return 0;
473}
474
475static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol,
476 struct snd_ctl_elem_value *ucontrol)
477{
478 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
479 int chip = AK_GET_CHIP(kcontrol->private_value);
480 int addr = AK_GET_ADDR(kcontrol->private_value);
481 int shift = AK_GET_SHIFT(kcontrol->private_value);
482 int invert = AK_GET_INVERT(kcontrol->private_value);
483 unsigned char val = snd_akm4xxx_get(ak, chip, addr);
484
485 if (invert)
486 val = ! val;
487 ucontrol->value.integer.value[0] = (val & (1<<shift)) != 0;
488 return 0;
489}
490
491static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
492 struct snd_ctl_elem_value *ucontrol)
493{
494 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
495 int chip = AK_GET_CHIP(kcontrol->private_value);
496 int addr = AK_GET_ADDR(kcontrol->private_value);
497 int shift = AK_GET_SHIFT(kcontrol->private_value);
498 int invert = AK_GET_INVERT(kcontrol->private_value);
499 long flag = ucontrol->value.integer.value[0];
500 unsigned char val, oval;
501 int change;
502
503 if (invert)
504 flag = ! flag;
505 oval = snd_akm4xxx_get(ak, chip, addr);
506 if (flag)
507 val = oval | (1<<shift);
508 else
509 val = oval & ~(1<<shift);
510 change = (oval != val);
511 if (change)
512 snd_akm4xxx_write(ak, chip, addr, val);
513 return change;
514}
515
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200516#define AK5365_NUM_INPUTS 5
517
518static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
519 struct snd_ctl_elem_info *uinfo)
520{
521 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
522 int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
523 const char **input_names;
524 int num_names, idx;
525
526 input_names = ak->adc_info[mixer_ch].input_names;
527
528 num_names = 0;
529 while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
530 ++num_names;
531
532 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
533 uinfo->count = 1;
534 uinfo->value.enumerated.items = num_names;
535 idx = uinfo->value.enumerated.item;
536 if (idx >= num_names)
537 return -EINVAL;
538 strncpy(uinfo->value.enumerated.name, input_names[idx],
539 sizeof(uinfo->value.enumerated.name));
540 return 0;
541}
542
543static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol,
544 struct snd_ctl_elem_value *ucontrol)
545{
546 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
547 int chip = AK_GET_CHIP(kcontrol->private_value);
548 int addr = AK_GET_ADDR(kcontrol->private_value);
549 int mask = AK_GET_MASK(kcontrol->private_value);
550 unsigned char val;
551
552 val = snd_akm4xxx_get(ak, chip, addr) & mask;
553 ucontrol->value.enumerated.item[0] = val;
554 return 0;
555}
556
557static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol,
558 struct snd_ctl_elem_value *ucontrol)
559{
560 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
561 int chip = AK_GET_CHIP(kcontrol->private_value);
562 int addr = AK_GET_ADDR(kcontrol->private_value);
563 int mask = AK_GET_MASK(kcontrol->private_value);
564 unsigned char oval, val;
565
566 oval = snd_akm4xxx_get(ak, chip, addr);
567 val = oval & ~mask;
568 val |= ucontrol->value.enumerated.item[0] & mask;
569 if (val != oval) {
570 snd_akm4xxx_write(ak, chip, addr, val);
571 return 1;
572 }
573 return 0;
574}
575
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576/*
577 * build AK4xxx controls
578 */
579
Takashi Iwai723b2b02006-08-30 16:49:54 +0200580static int build_dac_controls(struct snd_akm4xxx *ak)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581{
Takashi Iwai723b2b02006-08-30 16:49:54 +0200582 int idx, err, mixer_ch, num_stereo;
583 struct snd_kcontrol_new knew;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584
Takashi Iwai723b2b02006-08-30 16:49:54 +0200585 mixer_ch = 0;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200586 for (idx = 0; idx < ak->num_dacs; ) {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200587 memset(&knew, 0, sizeof(knew));
588 if (! ak->dac_info || ! ak->dac_info[mixer_ch].name) {
589 knew.name = "DAC Volume";
590 knew.index = mixer_ch + ak->idx_offset * 2;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200591 num_stereo = 1;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200592 } else {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200593 knew.name = ak->dac_info[mixer_ch].name;
594 num_stereo = ak->dac_info[mixer_ch].num_channels;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200595 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200596 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
597 knew.count = 1;
598 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
599 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200600 if (num_stereo == 2) {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200601 knew.info = snd_akm4xxx_stereo_volume_info;
602 knew.get = snd_akm4xxx_stereo_volume_get;
603 knew.put = snd_akm4xxx_stereo_volume_put;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200604 } else {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200605 knew.info = snd_akm4xxx_volume_info;
606 knew.get = snd_akm4xxx_volume_get;
607 knew.put = snd_akm4xxx_volume_put;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 switch (ak->type) {
610 case SND_AK4524:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200611 /* register 6 & 7 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200612 knew.private_value =
613 AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127) |
614 AK_VOL_CVT;
615 knew.tlv.p = db_scale_vol_datt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 break;
617 case SND_AK4528:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200618 /* register 4 & 5 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200619 knew.private_value =
620 AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127) |
621 AK_VOL_CVT;
622 knew.tlv.p = db_scale_vol_datt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 break;
624 case SND_AK4529: {
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200625 /* registers 2-7 and b,c */
626 int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200627 knew.private_value =
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200628 AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200629 knew.tlv.p = db_scale_8bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 break;
631 }
632 case SND_AK4355:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200633 /* register 4-9, chip #0 only */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200634 knew.private_value = AK_COMPOSE(0, idx + 4, 0, 255);
635 knew.tlv.p = db_scale_8bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 break;
Jochen Voss34793072006-08-23 18:35:35 +0200637 case SND_AK4358: {
638 /* register 4-9 and 11-12, chip #0 only */
639 int addr = idx < 6 ? idx + 4 : idx + 5;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200640 knew.private_value =
Jochen Voss34793072006-08-23 18:35:35 +0200641 AK_COMPOSE(0, addr, 0, 127) | AK_NEEDSMSB;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200642 knew.tlv.p = db_scale_7bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 break;
Jochen Voss34793072006-08-23 18:35:35 +0200644 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 case SND_AK4381:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200646 /* register 3 & 4 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200647 knew.private_value =
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200648 AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200649 knew.tlv.p = db_scale_linear;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 break;
651 default:
Takashi Iwai723b2b02006-08-30 16:49:54 +0200652 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 }
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200654
Takashi Iwai723b2b02006-08-30 16:49:54 +0200655 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200656 if (err < 0)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200657 return err;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200658
659 idx += num_stereo;
660 mixer_ch++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200662 return 0;
663}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664
Takashi Iwai723b2b02006-08-30 16:49:54 +0200665static int build_adc_controls(struct snd_akm4xxx *ak)
666{
667 int idx, err, mixer_ch, num_stereo;
668 struct snd_kcontrol_new knew;
669
670 mixer_ch = 0;
671 for (idx = 0; idx < ak->num_adcs;) {
672 memset(&knew, 0, sizeof(knew));
673 if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) {
674 knew.name = "ADC Volume";
675 knew.index = mixer_ch + ak->idx_offset * 2;
676 num_stereo = 1;
677 } else {
678 knew.name = ak->adc_info[mixer_ch].name;
679 num_stereo = ak->adc_info[mixer_ch].num_channels;
680 }
681 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
682 knew.count = 1;
683 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
684 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
685 if (num_stereo == 2) {
686 knew.info = snd_akm4xxx_stereo_volume_info;
687 knew.get = snd_akm4xxx_stereo_volume_get;
688 knew.put = snd_akm4xxx_stereo_volume_put;
689 } else {
690 knew.info = snd_akm4xxx_volume_info;
691 knew.get = snd_akm4xxx_volume_get;
692 knew.put = snd_akm4xxx_volume_put;
693 }
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200694 /* register 4 & 5 */
Takashi Iwai854b66e2006-09-08 12:27:38 +0200695 if (ak->type == SND_AK5365)
696 knew.private_value =
697 AK_COMPOSE(idx/2, (idx%2) + 4, 0, 151) |
698 AK_VOL_CVT | AK_IPGA;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200699 else
Takashi Iwai854b66e2006-09-08 12:27:38 +0200700 knew.private_value =
701 AK_COMPOSE(idx/2, (idx%2) + 4, 0, 163) |
702 AK_VOL_CVT | AK_IPGA;
703 knew.tlv.p = db_scale_vol_datt;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200704 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
705 if (err < 0)
706 return err;
707
708 if (ak->type == SND_AK5365 && (idx % 2) == 0) {
709 if (! ak->adc_info ||
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200710 ! ak->adc_info[mixer_ch].switch_name) {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200711 knew.name = "Capture Switch";
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200712 knew.index = mixer_ch + ak->idx_offset * 2;
713 } else
Takashi Iwai723b2b02006-08-30 16:49:54 +0200714 knew.name = ak->adc_info[mixer_ch].switch_name;
715 knew.info = ak4xxx_switch_info;
716 knew.get = ak4xxx_switch_get;
717 knew.put = ak4xxx_switch_put;
718 knew.access = 0;
719 /* register 2, bit 0 (SMUTE): 0 = normal operation,
720 1 = mute */
721 knew.private_value =
722 AK_COMPOSE(idx/2, 2, 0, 0) | AK_INVERT;
723 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
724 if (err < 0)
725 return err;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200726
727 memset(&knew, 0, sizeof(knew));
728 knew.name = ak->adc_info[mixer_ch].selector_name;
729 if (!knew.name) {
730 knew.name = "Capture Channel";
731 knew.index = mixer_ch + ak->idx_offset * 2;
732 }
733
734 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
735 knew.info = ak4xxx_capture_source_info;
736 knew.get = ak4xxx_capture_source_get;
737 knew.put = ak4xxx_capture_source_put;
738 knew.access = 0;
739 /* input selector control: reg. 1, bits 0-2.
740 * mis-use 'shift' to pass mixer_ch */
741 knew.private_value
742 = AK_COMPOSE(idx/2, 1, mixer_ch, 0x07);
743 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
744 if (err < 0)
745 return err;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200746 }
747
748 idx += num_stereo;
749 mixer_ch++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200751 return 0;
752}
Jochen Voss683fe152006-08-08 21:12:44 +0200753
Takashi Iwai723b2b02006-08-30 16:49:54 +0200754static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
755{
756 int idx, err;
757 struct snd_kcontrol_new knew;
Jochen Voss30ba6e22006-08-09 14:26:26 +0200758
Takashi Iwai723b2b02006-08-30 16:49:54 +0200759 for (idx = 0; idx < num_emphs; idx++) {
760 memset(&knew, 0, sizeof(knew));
761 knew.name = "Deemphasis";
762 knew.index = idx + ak->idx_offset;
763 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
764 knew.count = 1;
765 knew.info = snd_akm4xxx_deemphasis_info;
766 knew.get = snd_akm4xxx_deemphasis_get;
767 knew.put = snd_akm4xxx_deemphasis_put;
768 switch (ak->type) {
769 case SND_AK4524:
770 case SND_AK4528:
771 /* register 3 */
772 knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
773 break;
774 case SND_AK4529: {
775 int shift = idx == 3 ? 6 : (2 - idx) * 2;
776 /* register 8 with shift */
777 knew.private_value = AK_COMPOSE(0, 8, shift, 0);
778 break;
779 }
780 case SND_AK4355:
781 case SND_AK4358:
782 knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
783 break;
784 case SND_AK4381:
785 knew.private_value = AK_COMPOSE(idx, 1, 1, 0);
786 break;
787 default:
788 return -EINVAL;
789 }
790 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
Jochen Voss30ba6e22006-08-09 14:26:26 +0200791 if (err < 0)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200792 return err;
793 }
794 return 0;
795}
796
797int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
798{
799 int err, num_emphs;
800
801 err = build_dac_controls(ak);
802 if (err < 0)
803 return err;
804
Takashi Iwai854b66e2006-09-08 12:27:38 +0200805 err = build_adc_controls(ak);
806 if (err < 0)
807 return err;
Jochen Voss683fe152006-08-08 21:12:44 +0200808
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
810 num_emphs = 1;
811 else
812 num_emphs = ak->num_dacs / 2;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200813 err = build_deemphasis(ak, num_emphs);
814 if (err < 0)
815 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
Takashi Iwai723b2b02006-08-30 16:49:54 +0200817 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818}
Takashi Iwai723b2b02006-08-30 16:49:54 +0200819
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200820EXPORT_SYMBOL(snd_akm4xxx_build_controls);
821
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822static int __init alsa_akm4xxx_module_init(void)
823{
824 return 0;
825}
826
827static void __exit alsa_akm4xxx_module_exit(void)
828{
829}
830
831module_init(alsa_akm4xxx_module_init)
832module_exit(alsa_akm4xxx_module_exit)