blob: 57ccba88700d68bacc493d01d030175158f40196 [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 *
Pavel Hofman8f346922009-09-16 22:25:36 +020022 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
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>
Pavel Hofman8f346922009-09-16 22:25:36 +020032#include <sound/info.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
Jaroslav Kyselac1017a42007-10-15 09:50:19 +020034MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>");
Linus Torvalds1da177e2005-04-16 15:20:36 -070035MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters");
36MODULE_LICENSE("GPL");
37
Takashi Iwai723b2b02006-08-30 16:49:54 +020038/* write the given register and save the data to the cache */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020039void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg,
40 unsigned char val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070041{
42 ak->ops.lock(ak, chip);
43 ak->ops.write(ak, chip, reg, val);
44
45 /* save the data */
Takashi Iwai854b66e2006-09-08 12:27:38 +020046 snd_akm4xxx_set(ak, chip, reg, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -070047 ak->ops.unlock(ak, chip);
48}
49
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020050EXPORT_SYMBOL(snd_akm4xxx_write);
51
52/* reset procedure for AK4524 and AK4528 */
53static void ak4524_reset(struct snd_akm4xxx *ak, int state)
54{
55 unsigned int chip;
Pavel Hofman8f346922009-09-16 22:25:36 +020056 unsigned char reg;
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020057
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020058 for (chip = 0; chip < ak->num_dacs/2; chip++) {
59 snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03);
60 if (state)
61 continue;
62 /* DAC volumes */
Pavel Hofman8f346922009-09-16 22:25:36 +020063 for (reg = 0x04; reg < ak->total_regs; reg++)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020064 snd_akm4xxx_write(ak, chip, reg,
65 snd_akm4xxx_get(ak, chip, reg));
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020066 }
67}
68
69/* reset procedure for AK4355 and AK4358 */
Pavel Hofman8f346922009-09-16 22:25:36 +020070static void ak435X_reset(struct snd_akm4xxx *ak, int state)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020071{
72 unsigned char reg;
73
74 if (state) {
75 snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */
76 return;
77 }
Pavel Hofman8f346922009-09-16 22:25:36 +020078 for (reg = 0x00; reg < ak->total_regs; reg++)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020079 if (reg != 0x01)
80 snd_akm4xxx_write(ak, 0, reg,
81 snd_akm4xxx_get(ak, 0, reg));
82 snd_akm4xxx_write(ak, 0, 0x01, 0x01); /* un-reset, unmute */
83}
84
85/* reset procedure for AK4381 */
86static void ak4381_reset(struct snd_akm4xxx *ak, int state)
87{
88 unsigned int chip;
89 unsigned char reg;
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020090 for (chip = 0; chip < ak->num_dacs/2; chip++) {
91 snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f);
92 if (state)
93 continue;
Pavel Hofman8f346922009-09-16 22:25:36 +020094 for (reg = 0x01; reg < ak->total_regs; reg++)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020095 snd_akm4xxx_write(ak, chip, reg,
96 snd_akm4xxx_get(ak, chip, reg));
97 }
98}
99
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100/*
101 * reset the AKM codecs
102 * @state: 1 = reset codec, 0 = restore the registers
103 *
104 * assert the reset operation and restores the register values to the chips.
105 */
Takashi Iwai97f02e02005-11-17 14:17:19 +0100106void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 switch (ak->type) {
109 case SND_AK4524:
110 case SND_AK4528:
Pavel Hofman8f346922009-09-16 22:25:36 +0200111 case SND_AK4620:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200112 ak4524_reset(ak, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 break;
114 case SND_AK4529:
115 /* FIXME: needed for ak4529? */
116 break;
117 case SND_AK4355:
Pavel Hofman8f346922009-09-16 22:25:36 +0200118 ak435X_reset(ak, state);
Pavel Hofman841b23d2008-03-17 08:45:33 +0100119 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 case SND_AK4358:
Pavel Hofman8f346922009-09-16 22:25:36 +0200121 ak435X_reset(ak, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 break;
123 case SND_AK4381:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200124 ak4381_reset(ak, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 break;
Takashi Iwaicf939072006-08-09 14:33:27 +0200126 default:
127 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 }
129}
130
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200131EXPORT_SYMBOL(snd_akm4xxx_reset);
132
Takashi Iwai723b2b02006-08-30 16:49:54 +0200133
134/*
135 * Volume conversion table for non-linear volumes
136 * from -63.5dB (mute) to 0dB step 0.5dB
137 *
Pavel Hofman8f346922009-09-16 22:25:36 +0200138 * Used for AK4524/AK4620 input/ouput attenuation, AK4528, and
Takashi Iwai723b2b02006-08-30 16:49:54 +0200139 * AK5365 input attenuation
140 */
Takashi Iwai517400c2007-01-29 15:27:56 +0100141static const unsigned char vol_cvt_datt[128] = {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200142 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04,
143 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06,
144 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a,
145 0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f,
146 0x10, 0x10, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14,
147 0x15, 0x16, 0x17, 0x17, 0x18, 0x19, 0x1a, 0x1c,
148 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x23,
149 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, 0x2b, 0x2d,
150 0x2e, 0x30, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
151 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3e, 0x3f, 0x40,
152 0x41, 0x42, 0x43, 0x44, 0x46, 0x47, 0x48, 0x4a,
153 0x4b, 0x4d, 0x4e, 0x50, 0x51, 0x52, 0x53, 0x54,
154 0x55, 0x56, 0x58, 0x59, 0x5b, 0x5c, 0x5e, 0x5f,
155 0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x69,
156 0x6a, 0x6c, 0x6d, 0x6f, 0x70, 0x71, 0x72, 0x73,
157 0x75, 0x76, 0x77, 0x79, 0x7a, 0x7c, 0x7d, 0x7f,
158};
159
160/*
161 * dB tables
162 */
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100163static const DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
164static const DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
165static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
166static const DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200167
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168/*
169 * initialize all the ak4xxx chips
170 */
Takashi Iwai97f02e02005-11-17 14:17:19 +0100171void snd_akm4xxx_init(struct snd_akm4xxx *ak)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172{
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100173 static const unsigned char inits_ak4524[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 0x00, 0x07, /* 0: all power up */
175 0x01, 0x00, /* 1: ADC/DAC reset */
176 0x02, 0x60, /* 2: 24bit I2S */
177 0x03, 0x19, /* 3: deemphasis off */
178 0x01, 0x03, /* 1: ADC/DAC enable */
179 0x04, 0x00, /* 4: ADC left muted */
180 0x05, 0x00, /* 5: ADC right muted */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 0x06, 0x00, /* 6: DAC left muted */
182 0x07, 0x00, /* 7: DAC right muted */
183 0xff, 0xff
184 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100185 static const unsigned char inits_ak4528[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 0x00, 0x07, /* 0: all power up */
187 0x01, 0x00, /* 1: ADC/DAC reset */
188 0x02, 0x60, /* 2: 24bit I2S */
189 0x03, 0x0d, /* 3: deemphasis off, turn LR highpass filters on */
190 0x01, 0x03, /* 1: ADC/DAC enable */
191 0x04, 0x00, /* 4: ADC left muted */
192 0x05, 0x00, /* 5: ADC right muted */
193 0xff, 0xff
194 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100195 static const unsigned char inits_ak4529[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 0x09, 0x01, /* 9: ATS=0, RSTN=1 */
197 0x0a, 0x3f, /* A: all power up, no zero/overflow detection */
198 0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */
199 0x01, 0x00, /* 1: ACKS=0, ADC, loop off */
200 0x02, 0xff, /* 2: LOUT1 muted */
201 0x03, 0xff, /* 3: ROUT1 muted */
202 0x04, 0xff, /* 4: LOUT2 muted */
203 0x05, 0xff, /* 5: ROUT2 muted */
204 0x06, 0xff, /* 6: LOUT3 muted */
205 0x07, 0xff, /* 7: ROUT3 muted */
206 0x0b, 0xff, /* B: LOUT4 muted */
207 0x0c, 0xff, /* C: ROUT4 muted */
208 0x08, 0x55, /* 8: deemphasis all off */
209 0xff, 0xff
210 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100211 static const unsigned char inits_ak4355[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 0x01, 0x02, /* 1: reset and soft-mute */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200213 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
214 * disable DZF, sharp roll-off, RSTN#=0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
216 // 0x02, 0x2e, /* quad speed */
217 0x03, 0x01, /* 3: de-emphasis off */
218 0x04, 0x00, /* 4: LOUT1 volume muted */
219 0x05, 0x00, /* 5: ROUT1 volume muted */
220 0x06, 0x00, /* 6: LOUT2 volume muted */
221 0x07, 0x00, /* 7: ROUT2 volume muted */
222 0x08, 0x00, /* 8: LOUT3 volume muted */
223 0x09, 0x00, /* 9: ROUT3 volume muted */
224 0x0a, 0x00, /* a: DATT speed=0, ignore DZF */
225 0x01, 0x01, /* 1: un-reset, unmute */
226 0xff, 0xff
227 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100228 static const unsigned char inits_ak4358[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 0x01, 0x02, /* 1: reset and soft-mute */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200230 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
231 * disable DZF, sharp roll-off, RSTN#=0 */
Alexander Beregalov46480b32008-08-21 08:28:42 +0400232 0x02, 0x4e, /* 2: DA's power up, normal speed, RSTN#=0 */
233 /* 0x02, 0x6e,*/ /* quad speed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 0x03, 0x01, /* 3: de-emphasis off */
235 0x04, 0x00, /* 4: LOUT1 volume muted */
236 0x05, 0x00, /* 5: ROUT1 volume muted */
237 0x06, 0x00, /* 6: LOUT2 volume muted */
238 0x07, 0x00, /* 7: ROUT2 volume muted */
239 0x08, 0x00, /* 8: LOUT3 volume muted */
240 0x09, 0x00, /* 9: ROUT3 volume muted */
241 0x0b, 0x00, /* b: LOUT4 volume muted */
242 0x0c, 0x00, /* c: ROUT4 volume muted */
243 0x0a, 0x00, /* a: DATT speed=0, ignore DZF */
244 0x01, 0x01, /* 1: un-reset, unmute */
245 0xff, 0xff
246 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100247 static const unsigned char inits_ak4381[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200249 0x01, 0x02, /* 1: de-emphasis off, normal speed,
250 * sharp roll-off, DZF off */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 // 0x01, 0x12, /* quad speed */
252 0x02, 0x00, /* 2: DZF disabled */
253 0x03, 0x00, /* 3: LATT 0 */
254 0x04, 0x00, /* 4: RATT 0 */
255 0x00, 0x0f, /* 0: power-up, un-reset */
256 0xff, 0xff
257 };
Pavel Hofman8f346922009-09-16 22:25:36 +0200258 static const unsigned char inits_ak4620[] = {
259 0x00, 0x07, /* 0: normal */
260 0x01, 0x00, /* 0: reset */
261 0x01, 0x02, /* 1: RSTAD */
262 0x01, 0x03, /* 1: RSTDA */
263 0x01, 0x0f, /* 1: normal */
264 0x02, 0x60, /* 2: 24bit I2S */
265 0x03, 0x01, /* 3: deemphasis off */
266 0x04, 0x00, /* 4: LIN muted */
267 0x05, 0x00, /* 5: RIN muted */
268 0x06, 0x00, /* 6: LOUT muted */
269 0x07, 0x00, /* 7: ROUT muted */
270 0xff, 0xff
271 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
Pavel Hofman8f346922009-09-16 22:25:36 +0200273 int chip;
Takashi Iwai517400c2007-01-29 15:27:56 +0100274 const unsigned char *ptr, *inits;
275 unsigned char reg, data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
Takashi Iwai723b2b02006-08-30 16:49:54 +0200277 memset(ak->images, 0, sizeof(ak->images));
278 memset(ak->volumes, 0, sizeof(ak->volumes));
279
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 switch (ak->type) {
281 case SND_AK4524:
282 inits = inits_ak4524;
Pavel Hofman8f346922009-09-16 22:25:36 +0200283 ak->num_chips = ak->num_dacs / 2;
284 ak->name = "ak4524";
285 ak->total_regs = 0x08;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 break;
287 case SND_AK4528:
288 inits = inits_ak4528;
Pavel Hofman8f346922009-09-16 22:25:36 +0200289 ak->num_chips = ak->num_dacs / 2;
290 ak->name = "ak4528";
291 ak->total_regs = 0x06;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 break;
293 case SND_AK4529:
294 inits = inits_ak4529;
Pavel Hofman8f346922009-09-16 22:25:36 +0200295 ak->num_chips = 1;
296 ak->name = "ak4529";
297 ak->total_regs = 0x0d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 break;
299 case SND_AK4355:
300 inits = inits_ak4355;
Pavel Hofman8f346922009-09-16 22:25:36 +0200301 ak->num_chips = 1;
302 ak->name = "ak4355";
303 ak->total_regs = 0x0b;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 break;
305 case SND_AK4358:
306 inits = inits_ak4358;
Pavel Hofman8f346922009-09-16 22:25:36 +0200307 ak->num_chips = 1;
308 ak->name = "ak4358";
309 ak->total_regs = 0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 break;
311 case SND_AK4381:
312 inits = inits_ak4381;
Pavel Hofman8f346922009-09-16 22:25:36 +0200313 ak->num_chips = ak->num_dacs / 2;
314 ak->name = "ak4381";
315 ak->total_regs = 0x05;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 break;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200317 case SND_AK5365:
318 /* FIXME: any init sequence? */
Pavel Hofman8f346922009-09-16 22:25:36 +0200319 ak->num_chips = 1;
320 ak->name = "ak5365";
321 ak->total_regs = 0x08;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200322 return;
Pavel Hofman8f346922009-09-16 22:25:36 +0200323 case SND_AK4620:
324 inits = inits_ak4620;
325 ak->num_chips = ak->num_dacs / 2;
326 ak->name = "ak4620";
327 ak->total_regs = 0x08;
328 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 default:
330 snd_BUG();
331 return;
332 }
333
Pavel Hofman8f346922009-09-16 22:25:36 +0200334 for (chip = 0; chip < ak->num_chips; chip++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 ptr = inits;
336 while (*ptr != 0xff) {
337 reg = *ptr++;
338 data = *ptr++;
339 snd_akm4xxx_write(ak, chip, reg, data);
Pavel Hofman8f346922009-09-16 22:25:36 +0200340 udelay(10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 }
342 }
343}
344
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200345EXPORT_SYMBOL(snd_akm4xxx_init);
346
Takashi Iwai723b2b02006-08-30 16:49:54 +0200347/*
348 * Mixer callbacks
349 */
Takashi Iwai854b66e2006-09-08 12:27:38 +0200350#define AK_IPGA (1<<20) /* including IPGA */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200351#define AK_VOL_CVT (1<<21) /* need dB conversion */
352#define AK_NEEDSMSB (1<<22) /* need MSB update bit */
353#define AK_INVERT (1<<23) /* data is inverted */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354#define AK_GET_CHIP(val) (((val) >> 8) & 0xff)
355#define AK_GET_ADDR(val) ((val) & 0xff)
Takashi Iwai854b66e2006-09-08 12:27:38 +0200356#define AK_GET_SHIFT(val) (((val) >> 16) & 0x0f)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200357#define AK_GET_VOL_CVT(val) (((val) >> 21) & 1)
Takashi Iwai854b66e2006-09-08 12:27:38 +0200358#define AK_GET_IPGA(val) (((val) >> 20) & 1)
Jochen Voss34793072006-08-23 18:35:35 +0200359#define AK_GET_NEEDSMSB(val) (((val) >> 22) & 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360#define AK_GET_INVERT(val) (((val) >> 23) & 1)
361#define AK_GET_MASK(val) (((val) >> 24) & 0xff)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200362#define AK_COMPOSE(chip,addr,shift,mask) \
363 (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
Takashi Iwai97f02e02005-11-17 14:17:19 +0100365static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol,
366 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367{
368 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
369
370 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
371 uinfo->count = 1;
372 uinfo->value.integer.min = 0;
373 uinfo->value.integer.max = mask;
374 return 0;
375}
376
Takashi Iwai97f02e02005-11-17 14:17:19 +0100377static int snd_akm4xxx_volume_get(struct snd_kcontrol *kcontrol,
378 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100380 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 int chip = AK_GET_CHIP(kcontrol->private_value);
382 int addr = AK_GET_ADDR(kcontrol->private_value);
Jochen Voss34793072006-08-23 18:35:35 +0200383
Takashi Iwai723b2b02006-08-30 16:49:54 +0200384 ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 return 0;
386}
387
Takashi Iwai723b2b02006-08-30 16:49:54 +0200388static int put_ak_reg(struct snd_kcontrol *kcontrol, int addr,
389 unsigned char nval)
390{
391 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
392 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
393 int chip = AK_GET_CHIP(kcontrol->private_value);
394
395 if (snd_akm4xxx_get_vol(ak, chip, addr) == nval)
396 return 0;
397
398 snd_akm4xxx_set_vol(ak, chip, addr, nval);
Takashi Iwai854b66e2006-09-08 12:27:38 +0200399 if (AK_GET_VOL_CVT(kcontrol->private_value) && nval < 128)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200400 nval = vol_cvt_datt[nval];
Takashi Iwai854b66e2006-09-08 12:27:38 +0200401 if (AK_GET_IPGA(kcontrol->private_value) && nval >= 128)
402 nval++; /* need to correct + 1 since both 127 and 128 are 0dB */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200403 if (AK_GET_INVERT(kcontrol->private_value))
404 nval = mask - nval;
405 if (AK_GET_NEEDSMSB(kcontrol->private_value))
406 nval |= 0x80;
Pavel Hofman841b23d2008-03-17 08:45:33 +0100407 /* printk(KERN_DEBUG "DEBUG - AK writing reg: chip %x addr %x,
408 nval %x\n", chip, addr, nval); */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200409 snd_akm4xxx_write(ak, chip, addr, nval);
410 return 1;
411}
412
Takashi Iwai97f02e02005-11-17 14:17:19 +0100413static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
414 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415{
Takashi Iwai02ff1322007-11-15 16:15:29 +0100416 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
417 unsigned int val = ucontrol->value.integer.value[0];
418 if (val > mask)
419 return -EINVAL;
420 return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value), val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421}
422
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200423static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol,
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200424 struct snd_ctl_elem_info *uinfo)
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200425{
426 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
427
428 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
429 uinfo->count = 2;
430 uinfo->value.integer.min = 0;
431 uinfo->value.integer.max = mask;
432 return 0;
433}
434
435static int snd_akm4xxx_stereo_volume_get(struct snd_kcontrol *kcontrol,
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200436 struct snd_ctl_elem_value *ucontrol)
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200437{
438 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
439 int chip = AK_GET_CHIP(kcontrol->private_value);
440 int addr = AK_GET_ADDR(kcontrol->private_value);
Jochen Voss34793072006-08-23 18:35:35 +0200441
Takashi Iwai723b2b02006-08-30 16:49:54 +0200442 ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
443 ucontrol->value.integer.value[1] = snd_akm4xxx_get_vol(ak, chip, addr+1);
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200444 return 0;
445}
446
447static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200448 struct snd_ctl_elem_value *ucontrol)
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200449{
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200450 int addr = AK_GET_ADDR(kcontrol->private_value);
Takashi Iwai02ff1322007-11-15 16:15:29 +0100451 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
452 unsigned int val[2];
Takashi Iwai723b2b02006-08-30 16:49:54 +0200453 int change;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200454
Takashi Iwai02ff1322007-11-15 16:15:29 +0100455 val[0] = ucontrol->value.integer.value[0];
456 val[1] = ucontrol->value.integer.value[1];
457 if (val[0] > mask || val[1] > mask)
458 return -EINVAL;
459 change = put_ak_reg(kcontrol, addr, val[0]);
460 change |= put_ak_reg(kcontrol, addr + 1, val[1]);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200461 return change;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200462}
463
Takashi Iwai97f02e02005-11-17 14:17:19 +0100464static int snd_akm4xxx_deemphasis_info(struct snd_kcontrol *kcontrol,
465 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466{
467 static char *texts[4] = {
468 "44.1kHz", "Off", "48kHz", "32kHz",
469 };
470 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
471 uinfo->count = 1;
472 uinfo->value.enumerated.items = 4;
473 if (uinfo->value.enumerated.item >= 4)
474 uinfo->value.enumerated.item = 3;
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200475 strcpy(uinfo->value.enumerated.name,
476 texts[uinfo->value.enumerated.item]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 return 0;
478}
479
Takashi Iwai97f02e02005-11-17 14:17:19 +0100480static int snd_akm4xxx_deemphasis_get(struct snd_kcontrol *kcontrol,
481 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100483 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 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);
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200487 ucontrol->value.enumerated.item[0] =
488 (snd_akm4xxx_get(ak, chip, addr) >> shift) & 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 return 0;
490}
491
Takashi Iwai97f02e02005-11-17 14:17:19 +0100492static int snd_akm4xxx_deemphasis_put(struct snd_kcontrol *kcontrol,
493 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100495 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 int chip = AK_GET_CHIP(kcontrol->private_value);
497 int addr = AK_GET_ADDR(kcontrol->private_value);
498 int shift = AK_GET_SHIFT(kcontrol->private_value);
499 unsigned char nval = ucontrol->value.enumerated.item[0] & 3;
500 int change;
501
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200502 nval = (nval << shift) |
503 (snd_akm4xxx_get(ak, chip, addr) & ~(3 << shift));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 change = snd_akm4xxx_get(ak, chip, addr) != nval;
505 if (change)
506 snd_akm4xxx_write(ak, chip, addr, nval);
507 return change;
508}
509
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200510#define ak4xxx_switch_info snd_ctl_boolean_mono_info
Jochen Voss30ba6e22006-08-09 14:26:26 +0200511
512static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol,
513 struct snd_ctl_elem_value *ucontrol)
514{
515 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
516 int chip = AK_GET_CHIP(kcontrol->private_value);
517 int addr = AK_GET_ADDR(kcontrol->private_value);
518 int shift = AK_GET_SHIFT(kcontrol->private_value);
519 int invert = AK_GET_INVERT(kcontrol->private_value);
Pavel Hofmanea7cfcd2007-05-19 17:21:04 +0200520 /* we observe the (1<<shift) bit only */
521 unsigned char val = snd_akm4xxx_get(ak, chip, addr) & (1<<shift);
Jochen Voss30ba6e22006-08-09 14:26:26 +0200522 if (invert)
523 val = ! val;
524 ucontrol->value.integer.value[0] = (val & (1<<shift)) != 0;
525 return 0;
526}
527
528static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
529 struct snd_ctl_elem_value *ucontrol)
530{
531 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
532 int chip = AK_GET_CHIP(kcontrol->private_value);
533 int addr = AK_GET_ADDR(kcontrol->private_value);
534 int shift = AK_GET_SHIFT(kcontrol->private_value);
535 int invert = AK_GET_INVERT(kcontrol->private_value);
536 long flag = ucontrol->value.integer.value[0];
537 unsigned char val, oval;
538 int change;
539
540 if (invert)
541 flag = ! flag;
542 oval = snd_akm4xxx_get(ak, chip, addr);
543 if (flag)
544 val = oval | (1<<shift);
545 else
546 val = oval & ~(1<<shift);
547 change = (oval != val);
548 if (change)
549 snd_akm4xxx_write(ak, chip, addr, val);
550 return change;
551}
552
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200553#define AK5365_NUM_INPUTS 5
554
Takashi Iwai02ff1322007-11-15 16:15:29 +0100555static int ak4xxx_capture_num_inputs(struct snd_akm4xxx *ak, int mixer_ch)
556{
557 int num_names;
558 const char **input_names;
559
560 input_names = ak->adc_info[mixer_ch].input_names;
561 num_names = 0;
562 while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
563 ++num_names;
564 return num_names;
565}
566
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200567static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
568 struct snd_ctl_elem_info *uinfo)
569{
570 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
571 int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
572 const char **input_names;
573 int num_names, idx;
574
Takashi Iwai02ff1322007-11-15 16:15:29 +0100575 num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
576 if (!num_names)
577 return -EINVAL;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200578 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
579 uinfo->count = 1;
580 uinfo->value.enumerated.items = num_names;
581 idx = uinfo->value.enumerated.item;
582 if (idx >= num_names)
583 return -EINVAL;
Takashi Iwai02ff1322007-11-15 16:15:29 +0100584 input_names = ak->adc_info[mixer_ch].input_names;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200585 strncpy(uinfo->value.enumerated.name, input_names[idx],
586 sizeof(uinfo->value.enumerated.name));
587 return 0;
588}
589
590static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol,
591 struct snd_ctl_elem_value *ucontrol)
592{
593 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
594 int chip = AK_GET_CHIP(kcontrol->private_value);
595 int addr = AK_GET_ADDR(kcontrol->private_value);
596 int mask = AK_GET_MASK(kcontrol->private_value);
597 unsigned char val;
598
599 val = snd_akm4xxx_get(ak, chip, addr) & mask;
600 ucontrol->value.enumerated.item[0] = val;
601 return 0;
602}
603
604static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol,
605 struct snd_ctl_elem_value *ucontrol)
606{
607 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Takashi Iwai02ff1322007-11-15 16:15:29 +0100608 int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200609 int chip = AK_GET_CHIP(kcontrol->private_value);
610 int addr = AK_GET_ADDR(kcontrol->private_value);
611 int mask = AK_GET_MASK(kcontrol->private_value);
612 unsigned char oval, val;
Takashi Iwai02ff1322007-11-15 16:15:29 +0100613 int num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
614
615 if (ucontrol->value.enumerated.item[0] >= num_names)
616 return -EINVAL;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200617
618 oval = snd_akm4xxx_get(ak, chip, addr);
619 val = oval & ~mask;
620 val |= ucontrol->value.enumerated.item[0] & mask;
621 if (val != oval) {
622 snd_akm4xxx_write(ak, chip, addr, val);
623 return 1;
624 }
625 return 0;
626}
627
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628/*
629 * build AK4xxx controls
630 */
631
Takashi Iwai723b2b02006-08-30 16:49:54 +0200632static int build_dac_controls(struct snd_akm4xxx *ak)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633{
Takashi Iwai723b2b02006-08-30 16:49:54 +0200634 int idx, err, mixer_ch, num_stereo;
635 struct snd_kcontrol_new knew;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
Takashi Iwai723b2b02006-08-30 16:49:54 +0200637 mixer_ch = 0;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200638 for (idx = 0; idx < ak->num_dacs; ) {
Pavel Hofmanea7cfcd2007-05-19 17:21:04 +0200639 /* mute control for Revolution 7.1 - AK4381 */
640 if (ak->type == SND_AK4381
641 && ak->dac_info[mixer_ch].switch_name) {
642 memset(&knew, 0, sizeof(knew));
643 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
644 knew.count = 1;
645 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
646 knew.name = ak->dac_info[mixer_ch].switch_name;
647 knew.info = ak4xxx_switch_info;
648 knew.get = ak4xxx_switch_get;
649 knew.put = ak4xxx_switch_put;
650 knew.access = 0;
651 /* register 1, bit 0 (SMUTE): 0 = normal operation,
652 1 = mute */
653 knew.private_value =
654 AK_COMPOSE(idx/2, 1, 0, 0) | AK_INVERT;
655 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
656 if (err < 0)
657 return err;
658 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200659 memset(&knew, 0, sizeof(knew));
660 if (! ak->dac_info || ! ak->dac_info[mixer_ch].name) {
661 knew.name = "DAC Volume";
662 knew.index = mixer_ch + ak->idx_offset * 2;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200663 num_stereo = 1;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200664 } else {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200665 knew.name = ak->dac_info[mixer_ch].name;
666 num_stereo = ak->dac_info[mixer_ch].num_channels;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200667 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200668 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
669 knew.count = 1;
670 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
671 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200672 if (num_stereo == 2) {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200673 knew.info = snd_akm4xxx_stereo_volume_info;
674 knew.get = snd_akm4xxx_stereo_volume_get;
675 knew.put = snd_akm4xxx_stereo_volume_put;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200676 } else {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200677 knew.info = snd_akm4xxx_volume_info;
678 knew.get = snd_akm4xxx_volume_get;
679 knew.put = snd_akm4xxx_volume_put;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200680 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 switch (ak->type) {
682 case SND_AK4524:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200683 /* register 6 & 7 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200684 knew.private_value =
685 AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127) |
686 AK_VOL_CVT;
687 knew.tlv.p = db_scale_vol_datt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 break;
689 case SND_AK4528:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200690 /* register 4 & 5 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200691 knew.private_value =
692 AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127) |
693 AK_VOL_CVT;
694 knew.tlv.p = db_scale_vol_datt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 break;
696 case SND_AK4529: {
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200697 /* registers 2-7 and b,c */
698 int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200699 knew.private_value =
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200700 AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200701 knew.tlv.p = db_scale_8bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 break;
703 }
704 case SND_AK4355:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200705 /* register 4-9, chip #0 only */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200706 knew.private_value = AK_COMPOSE(0, idx + 4, 0, 255);
707 knew.tlv.p = db_scale_8bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 break;
Jochen Voss34793072006-08-23 18:35:35 +0200709 case SND_AK4358: {
710 /* register 4-9 and 11-12, chip #0 only */
711 int addr = idx < 6 ? idx + 4 : idx + 5;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200712 knew.private_value =
Jochen Voss34793072006-08-23 18:35:35 +0200713 AK_COMPOSE(0, addr, 0, 127) | AK_NEEDSMSB;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200714 knew.tlv.p = db_scale_7bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 break;
Jochen Voss34793072006-08-23 18:35:35 +0200716 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 case SND_AK4381:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200718 /* register 3 & 4 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200719 knew.private_value =
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200720 AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200721 knew.tlv.p = db_scale_linear;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 break;
Pavel Hofman8f346922009-09-16 22:25:36 +0200723 case SND_AK4620:
724 /* register 6 & 7 */
725 knew.private_value =
726 AK_COMPOSE(idx/2, (idx%2) + 6, 0, 255);
727 knew.tlv.p = db_scale_linear;
728 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 default:
Takashi Iwai723b2b02006-08-30 16:49:54 +0200730 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 }
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200732
Takashi Iwai723b2b02006-08-30 16:49:54 +0200733 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200734 if (err < 0)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200735 return err;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200736
737 idx += num_stereo;
738 mixer_ch++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200740 return 0;
741}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
Takashi Iwai723b2b02006-08-30 16:49:54 +0200743static int build_adc_controls(struct snd_akm4xxx *ak)
744{
Pavel Hofman8f346922009-09-16 22:25:36 +0200745 int idx, err, mixer_ch, num_stereo, max_steps;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200746 struct snd_kcontrol_new knew;
747
748 mixer_ch = 0;
Pavel Hofman8f346922009-09-16 22:25:36 +0200749 if (ak->type == SND_AK4528)
750 return 0; /* no controls */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200751 for (idx = 0; idx < ak->num_adcs;) {
752 memset(&knew, 0, sizeof(knew));
753 if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) {
754 knew.name = "ADC Volume";
755 knew.index = mixer_ch + ak->idx_offset * 2;
756 num_stereo = 1;
757 } else {
758 knew.name = ak->adc_info[mixer_ch].name;
759 num_stereo = ak->adc_info[mixer_ch].num_channels;
760 }
761 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
762 knew.count = 1;
763 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
764 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
765 if (num_stereo == 2) {
766 knew.info = snd_akm4xxx_stereo_volume_info;
767 knew.get = snd_akm4xxx_stereo_volume_get;
768 knew.put = snd_akm4xxx_stereo_volume_put;
769 } else {
770 knew.info = snd_akm4xxx_volume_info;
771 knew.get = snd_akm4xxx_volume_get;
772 knew.put = snd_akm4xxx_volume_put;
773 }
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200774 /* register 4 & 5 */
Takashi Iwai854b66e2006-09-08 12:27:38 +0200775 if (ak->type == SND_AK5365)
Pavel Hofman8f346922009-09-16 22:25:36 +0200776 max_steps = 152;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200777 else
Pavel Hofman8f346922009-09-16 22:25:36 +0200778 max_steps = 164;
779 knew.private_value =
780 AK_COMPOSE(idx/2, (idx%2) + 4, 0, max_steps) |
781 AK_VOL_CVT | AK_IPGA;
Takashi Iwai854b66e2006-09-08 12:27:38 +0200782 knew.tlv.p = db_scale_vol_datt;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200783 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
784 if (err < 0)
785 return err;
786
787 if (ak->type == SND_AK5365 && (idx % 2) == 0) {
788 if (! ak->adc_info ||
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200789 ! ak->adc_info[mixer_ch].switch_name) {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200790 knew.name = "Capture Switch";
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200791 knew.index = mixer_ch + ak->idx_offset * 2;
792 } else
Takashi Iwai723b2b02006-08-30 16:49:54 +0200793 knew.name = ak->adc_info[mixer_ch].switch_name;
794 knew.info = ak4xxx_switch_info;
795 knew.get = ak4xxx_switch_get;
796 knew.put = ak4xxx_switch_put;
797 knew.access = 0;
798 /* register 2, bit 0 (SMUTE): 0 = normal operation,
799 1 = mute */
800 knew.private_value =
801 AK_COMPOSE(idx/2, 2, 0, 0) | AK_INVERT;
802 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
803 if (err < 0)
804 return err;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200805
806 memset(&knew, 0, sizeof(knew));
807 knew.name = ak->adc_info[mixer_ch].selector_name;
808 if (!knew.name) {
809 knew.name = "Capture Channel";
810 knew.index = mixer_ch + ak->idx_offset * 2;
811 }
812
813 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
814 knew.info = ak4xxx_capture_source_info;
815 knew.get = ak4xxx_capture_source_get;
816 knew.put = ak4xxx_capture_source_put;
817 knew.access = 0;
818 /* input selector control: reg. 1, bits 0-2.
819 * mis-use 'shift' to pass mixer_ch */
820 knew.private_value
821 = AK_COMPOSE(idx/2, 1, mixer_ch, 0x07);
822 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
823 if (err < 0)
824 return err;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200825 }
826
827 idx += num_stereo;
828 mixer_ch++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200830 return 0;
831}
Jochen Voss683fe152006-08-08 21:12:44 +0200832
Takashi Iwai723b2b02006-08-30 16:49:54 +0200833static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
834{
835 int idx, err;
836 struct snd_kcontrol_new knew;
Jochen Voss30ba6e22006-08-09 14:26:26 +0200837
Takashi Iwai723b2b02006-08-30 16:49:54 +0200838 for (idx = 0; idx < num_emphs; idx++) {
839 memset(&knew, 0, sizeof(knew));
840 knew.name = "Deemphasis";
841 knew.index = idx + ak->idx_offset;
842 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
843 knew.count = 1;
844 knew.info = snd_akm4xxx_deemphasis_info;
845 knew.get = snd_akm4xxx_deemphasis_get;
846 knew.put = snd_akm4xxx_deemphasis_put;
847 switch (ak->type) {
848 case SND_AK4524:
849 case SND_AK4528:
Pavel Hofman8f346922009-09-16 22:25:36 +0200850 case SND_AK4620:
Takashi Iwai723b2b02006-08-30 16:49:54 +0200851 /* register 3 */
852 knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
853 break;
854 case SND_AK4529: {
855 int shift = idx == 3 ? 6 : (2 - idx) * 2;
856 /* register 8 with shift */
857 knew.private_value = AK_COMPOSE(0, 8, shift, 0);
858 break;
859 }
860 case SND_AK4355:
861 case SND_AK4358:
862 knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
863 break;
864 case SND_AK4381:
865 knew.private_value = AK_COMPOSE(idx, 1, 1, 0);
866 break;
867 default:
868 return -EINVAL;
869 }
870 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
Jochen Voss30ba6e22006-08-09 14:26:26 +0200871 if (err < 0)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200872 return err;
873 }
874 return 0;
875}
876
Pavel Hofman8f346922009-09-16 22:25:36 +0200877#ifdef CONFIG_PROC_FS
878static void proc_regs_read(struct snd_info_entry *entry,
879 struct snd_info_buffer *buffer)
880{
Joe Perches9fe856e2010-09-04 18:52:54 -0700881 struct snd_akm4xxx *ak = entry->private_data;
Pavel Hofman8f346922009-09-16 22:25:36 +0200882 int reg, val, chip;
883 for (chip = 0; chip < ak->num_chips; chip++) {
884 for (reg = 0; reg < ak->total_regs; reg++) {
885 val = snd_akm4xxx_get(ak, chip, reg);
886 snd_iprintf(buffer, "chip %d: 0x%02x = 0x%02x\n", chip,
887 reg, val);
888 }
889 }
890}
891
892static int proc_init(struct snd_akm4xxx *ak)
893{
894 struct snd_info_entry *entry;
895 int err;
896 err = snd_card_proc_new(ak->card, ak->name, &entry);
897 if (err < 0)
898 return err;
899 snd_info_set_text_ops(entry, ak, proc_regs_read);
900 return 0;
901}
902#else /* !CONFIG_PROC_FS */
Takashi Iwaie913b142010-09-30 22:59:12 +0200903static int proc_init(struct snd_akm4xxx *ak) { return 0; }
Pavel Hofman8f346922009-09-16 22:25:36 +0200904#endif
905
Takashi Iwai723b2b02006-08-30 16:49:54 +0200906int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
907{
908 int err, num_emphs;
909
910 err = build_dac_controls(ak);
911 if (err < 0)
912 return err;
913
Takashi Iwai854b66e2006-09-08 12:27:38 +0200914 err = build_adc_controls(ak);
915 if (err < 0)
916 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
918 num_emphs = 1;
Pavel Hofman8f346922009-09-16 22:25:36 +0200919 else if (ak->type == SND_AK4620)
920 num_emphs = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 else
922 num_emphs = ak->num_dacs / 2;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200923 err = build_deemphasis(ak, num_emphs);
924 if (err < 0)
925 return err;
Pavel Hofman8f346922009-09-16 22:25:36 +0200926 err = proc_init(ak);
927 if (err < 0)
928 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929
Takashi Iwai723b2b02006-08-30 16:49:54 +0200930 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931}
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200932EXPORT_SYMBOL(snd_akm4xxx_build_controls);
933
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934static int __init alsa_akm4xxx_module_init(void)
935{
936 return 0;
937}
938
939static void __exit alsa_akm4xxx_module_exit(void)
940{
941}
942
943module_init(alsa_akm4xxx_module_init)
944module_exit(alsa_akm4xxx_module_exit)