blob: cef813d23641afcd39b56a57c5fc8058cb99bfb0 [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>
Paul Gortmakerda155d52011-07-15 12:38:28 -040028#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#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>
Pavel Hofman8f346922009-09-16 22:25:36 +020033#include <sound/info.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Jaroslav Kyselac1017a42007-10-15 09:50:19 +020035MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>");
Linus Torvalds1da177e2005-04-16 15:20:36 -070036MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters");
37MODULE_LICENSE("GPL");
38
Takashi Iwai723b2b02006-08-30 16:49:54 +020039/* write the given register and save the data to the cache */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020040void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg,
41 unsigned char val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070042{
43 ak->ops.lock(ak, chip);
44 ak->ops.write(ak, chip, reg, val);
45
46 /* save the data */
Takashi Iwai854b66e2006-09-08 12:27:38 +020047 snd_akm4xxx_set(ak, chip, reg, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 ak->ops.unlock(ak, chip);
49}
50
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020051EXPORT_SYMBOL(snd_akm4xxx_write);
52
53/* reset procedure for AK4524 and AK4528 */
54static void ak4524_reset(struct snd_akm4xxx *ak, int state)
55{
56 unsigned int chip;
Pavel Hofman8f346922009-09-16 22:25:36 +020057 unsigned char reg;
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020058
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020059 for (chip = 0; chip < ak->num_dacs/2; chip++) {
60 snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03);
61 if (state)
62 continue;
63 /* DAC volumes */
Pavel Hofman8f346922009-09-16 22:25:36 +020064 for (reg = 0x04; reg < ak->total_regs; reg++)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020065 snd_akm4xxx_write(ak, chip, reg,
66 snd_akm4xxx_get(ak, chip, reg));
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020067 }
68}
69
70/* reset procedure for AK4355 and AK4358 */
Pavel Hofman8f346922009-09-16 22:25:36 +020071static void ak435X_reset(struct snd_akm4xxx *ak, int state)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020072{
73 unsigned char reg;
74
75 if (state) {
76 snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */
77 return;
78 }
Pavel Hofman8f346922009-09-16 22:25:36 +020079 for (reg = 0x00; reg < ak->total_regs; reg++)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020080 if (reg != 0x01)
81 snd_akm4xxx_write(ak, 0, reg,
82 snd_akm4xxx_get(ak, 0, reg));
83 snd_akm4xxx_write(ak, 0, 0x01, 0x01); /* un-reset, unmute */
84}
85
86/* reset procedure for AK4381 */
87static void ak4381_reset(struct snd_akm4xxx *ak, int state)
88{
89 unsigned int chip;
90 unsigned char reg;
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020091 for (chip = 0; chip < ak->num_dacs/2; chip++) {
92 snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f);
93 if (state)
94 continue;
Pavel Hofman8f346922009-09-16 22:25:36 +020095 for (reg = 0x01; reg < ak->total_regs; reg++)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020096 snd_akm4xxx_write(ak, chip, reg,
97 snd_akm4xxx_get(ak, chip, reg));
98 }
99}
100
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101/*
102 * reset the AKM codecs
103 * @state: 1 = reset codec, 0 = restore the registers
104 *
105 * assert the reset operation and restores the register values to the chips.
106 */
Takashi Iwai97f02e02005-11-17 14:17:19 +0100107void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 switch (ak->type) {
110 case SND_AK4524:
111 case SND_AK4528:
Pavel Hofman8f346922009-09-16 22:25:36 +0200112 case SND_AK4620:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200113 ak4524_reset(ak, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 break;
115 case SND_AK4529:
116 /* FIXME: needed for ak4529? */
117 break;
118 case SND_AK4355:
Pavel Hofman8f346922009-09-16 22:25:36 +0200119 ak435X_reset(ak, state);
Pavel Hofman841b23d2008-03-17 08:45:33 +0100120 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 case SND_AK4358:
Pavel Hofman8f346922009-09-16 22:25:36 +0200122 ak435X_reset(ak, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 break;
124 case SND_AK4381:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200125 ak4381_reset(ak, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 break;
Takashi Iwaicf939072006-08-09 14:33:27 +0200127 default:
128 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 }
130}
131
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200132EXPORT_SYMBOL(snd_akm4xxx_reset);
133
Takashi Iwai723b2b02006-08-30 16:49:54 +0200134
135/*
136 * Volume conversion table for non-linear volumes
137 * from -63.5dB (mute) to 0dB step 0.5dB
138 *
Pavel Hofman8f346922009-09-16 22:25:36 +0200139 * Used for AK4524/AK4620 input/ouput attenuation, AK4528, and
Takashi Iwai723b2b02006-08-30 16:49:54 +0200140 * AK5365 input attenuation
141 */
Takashi Iwai517400c2007-01-29 15:27:56 +0100142static const unsigned char vol_cvt_datt[128] = {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200143 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04,
144 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06,
145 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a,
146 0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f,
147 0x10, 0x10, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14,
148 0x15, 0x16, 0x17, 0x17, 0x18, 0x19, 0x1a, 0x1c,
149 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x23,
150 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, 0x2b, 0x2d,
151 0x2e, 0x30, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
152 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3e, 0x3f, 0x40,
153 0x41, 0x42, 0x43, 0x44, 0x46, 0x47, 0x48, 0x4a,
154 0x4b, 0x4d, 0x4e, 0x50, 0x51, 0x52, 0x53, 0x54,
155 0x55, 0x56, 0x58, 0x59, 0x5b, 0x5c, 0x5e, 0x5f,
156 0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x69,
157 0x6a, 0x6c, 0x6d, 0x6f, 0x70, 0x71, 0x72, 0x73,
158 0x75, 0x76, 0x77, 0x79, 0x7a, 0x7c, 0x7d, 0x7f,
159};
160
161/*
162 * dB tables
163 */
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100164static const DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
165static const DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
166static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
167static const DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200168
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169/*
170 * initialize all the ak4xxx chips
171 */
Takashi Iwai97f02e02005-11-17 14:17:19 +0100172void snd_akm4xxx_init(struct snd_akm4xxx *ak)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173{
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100174 static const unsigned char inits_ak4524[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 0x00, 0x07, /* 0: all power up */
176 0x01, 0x00, /* 1: ADC/DAC reset */
177 0x02, 0x60, /* 2: 24bit I2S */
178 0x03, 0x19, /* 3: deemphasis off */
179 0x01, 0x03, /* 1: ADC/DAC enable */
180 0x04, 0x00, /* 4: ADC left muted */
181 0x05, 0x00, /* 5: ADC right muted */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 0x06, 0x00, /* 6: DAC left muted */
183 0x07, 0x00, /* 7: DAC right muted */
184 0xff, 0xff
185 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100186 static const unsigned char inits_ak4528[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 0x00, 0x07, /* 0: all power up */
188 0x01, 0x00, /* 1: ADC/DAC reset */
189 0x02, 0x60, /* 2: 24bit I2S */
190 0x03, 0x0d, /* 3: deemphasis off, turn LR highpass filters on */
191 0x01, 0x03, /* 1: ADC/DAC enable */
192 0x04, 0x00, /* 4: ADC left muted */
193 0x05, 0x00, /* 5: ADC right muted */
194 0xff, 0xff
195 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100196 static const unsigned char inits_ak4529[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 0x09, 0x01, /* 9: ATS=0, RSTN=1 */
198 0x0a, 0x3f, /* A: all power up, no zero/overflow detection */
199 0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */
200 0x01, 0x00, /* 1: ACKS=0, ADC, loop off */
201 0x02, 0xff, /* 2: LOUT1 muted */
202 0x03, 0xff, /* 3: ROUT1 muted */
203 0x04, 0xff, /* 4: LOUT2 muted */
204 0x05, 0xff, /* 5: ROUT2 muted */
205 0x06, 0xff, /* 6: LOUT3 muted */
206 0x07, 0xff, /* 7: ROUT3 muted */
207 0x0b, 0xff, /* B: LOUT4 muted */
208 0x0c, 0xff, /* C: ROUT4 muted */
209 0x08, 0x55, /* 8: deemphasis all off */
210 0xff, 0xff
211 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100212 static const unsigned char inits_ak4355[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 0x01, 0x02, /* 1: reset and soft-mute */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200214 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
215 * disable DZF, sharp roll-off, RSTN#=0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
217 // 0x02, 0x2e, /* quad speed */
218 0x03, 0x01, /* 3: de-emphasis off */
219 0x04, 0x00, /* 4: LOUT1 volume muted */
220 0x05, 0x00, /* 5: ROUT1 volume muted */
221 0x06, 0x00, /* 6: LOUT2 volume muted */
222 0x07, 0x00, /* 7: ROUT2 volume muted */
223 0x08, 0x00, /* 8: LOUT3 volume muted */
224 0x09, 0x00, /* 9: ROUT3 volume muted */
225 0x0a, 0x00, /* a: DATT speed=0, ignore DZF */
226 0x01, 0x01, /* 1: un-reset, unmute */
227 0xff, 0xff
228 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100229 static const unsigned char inits_ak4358[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 0x01, 0x02, /* 1: reset and soft-mute */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200231 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
232 * disable DZF, sharp roll-off, RSTN#=0 */
Alexander Beregalov46480b32008-08-21 08:28:42 +0400233 0x02, 0x4e, /* 2: DA's power up, normal speed, RSTN#=0 */
234 /* 0x02, 0x6e,*/ /* quad speed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 0x03, 0x01, /* 3: de-emphasis off */
236 0x04, 0x00, /* 4: LOUT1 volume muted */
237 0x05, 0x00, /* 5: ROUT1 volume muted */
238 0x06, 0x00, /* 6: LOUT2 volume muted */
239 0x07, 0x00, /* 7: ROUT2 volume muted */
240 0x08, 0x00, /* 8: LOUT3 volume muted */
241 0x09, 0x00, /* 9: ROUT3 volume muted */
242 0x0b, 0x00, /* b: LOUT4 volume muted */
243 0x0c, 0x00, /* c: ROUT4 volume muted */
244 0x0a, 0x00, /* a: DATT speed=0, ignore DZF */
245 0x01, 0x01, /* 1: un-reset, unmute */
246 0xff, 0xff
247 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100248 static const unsigned char inits_ak4381[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200250 0x01, 0x02, /* 1: de-emphasis off, normal speed,
251 * sharp roll-off, DZF off */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 // 0x01, 0x12, /* quad speed */
253 0x02, 0x00, /* 2: DZF disabled */
254 0x03, 0x00, /* 3: LATT 0 */
255 0x04, 0x00, /* 4: RATT 0 */
256 0x00, 0x0f, /* 0: power-up, un-reset */
257 0xff, 0xff
258 };
Pavel Hofman8f346922009-09-16 22:25:36 +0200259 static const unsigned char inits_ak4620[] = {
260 0x00, 0x07, /* 0: normal */
261 0x01, 0x00, /* 0: reset */
262 0x01, 0x02, /* 1: RSTAD */
263 0x01, 0x03, /* 1: RSTDA */
264 0x01, 0x0f, /* 1: normal */
265 0x02, 0x60, /* 2: 24bit I2S */
266 0x03, 0x01, /* 3: deemphasis off */
267 0x04, 0x00, /* 4: LIN muted */
268 0x05, 0x00, /* 5: RIN muted */
269 0x06, 0x00, /* 6: LOUT muted */
270 0x07, 0x00, /* 7: ROUT muted */
271 0xff, 0xff
272 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
Pavel Hofman8f346922009-09-16 22:25:36 +0200274 int chip;
Takashi Iwai517400c2007-01-29 15:27:56 +0100275 const unsigned char *ptr, *inits;
276 unsigned char reg, data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
Takashi Iwai723b2b02006-08-30 16:49:54 +0200278 memset(ak->images, 0, sizeof(ak->images));
279 memset(ak->volumes, 0, sizeof(ak->volumes));
280
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 switch (ak->type) {
282 case SND_AK4524:
283 inits = inits_ak4524;
Pavel Hofman8f346922009-09-16 22:25:36 +0200284 ak->num_chips = ak->num_dacs / 2;
285 ak->name = "ak4524";
286 ak->total_regs = 0x08;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 break;
288 case SND_AK4528:
289 inits = inits_ak4528;
Pavel Hofman8f346922009-09-16 22:25:36 +0200290 ak->num_chips = ak->num_dacs / 2;
291 ak->name = "ak4528";
292 ak->total_regs = 0x06;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 break;
294 case SND_AK4529:
295 inits = inits_ak4529;
Pavel Hofman8f346922009-09-16 22:25:36 +0200296 ak->num_chips = 1;
297 ak->name = "ak4529";
298 ak->total_regs = 0x0d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 break;
300 case SND_AK4355:
301 inits = inits_ak4355;
Pavel Hofman8f346922009-09-16 22:25:36 +0200302 ak->num_chips = 1;
303 ak->name = "ak4355";
304 ak->total_regs = 0x0b;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 break;
306 case SND_AK4358:
307 inits = inits_ak4358;
Pavel Hofman8f346922009-09-16 22:25:36 +0200308 ak->num_chips = 1;
309 ak->name = "ak4358";
310 ak->total_regs = 0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 break;
312 case SND_AK4381:
313 inits = inits_ak4381;
Pavel Hofman8f346922009-09-16 22:25:36 +0200314 ak->num_chips = ak->num_dacs / 2;
315 ak->name = "ak4381";
316 ak->total_regs = 0x05;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 break;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200318 case SND_AK5365:
319 /* FIXME: any init sequence? */
Pavel Hofman8f346922009-09-16 22:25:36 +0200320 ak->num_chips = 1;
321 ak->name = "ak5365";
322 ak->total_regs = 0x08;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200323 return;
Pavel Hofman8f346922009-09-16 22:25:36 +0200324 case SND_AK4620:
325 inits = inits_ak4620;
326 ak->num_chips = ak->num_dacs / 2;
327 ak->name = "ak4620";
328 ak->total_regs = 0x08;
329 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 default:
331 snd_BUG();
332 return;
333 }
334
Pavel Hofman8f346922009-09-16 22:25:36 +0200335 for (chip = 0; chip < ak->num_chips; chip++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 ptr = inits;
337 while (*ptr != 0xff) {
338 reg = *ptr++;
339 data = *ptr++;
340 snd_akm4xxx_write(ak, chip, reg, data);
Pavel Hofman8f346922009-09-16 22:25:36 +0200341 udelay(10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 }
343 }
344}
345
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200346EXPORT_SYMBOL(snd_akm4xxx_init);
347
Takashi Iwai723b2b02006-08-30 16:49:54 +0200348/*
349 * Mixer callbacks
350 */
Takashi Iwai854b66e2006-09-08 12:27:38 +0200351#define AK_IPGA (1<<20) /* including IPGA */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200352#define AK_VOL_CVT (1<<21) /* need dB conversion */
353#define AK_NEEDSMSB (1<<22) /* need MSB update bit */
354#define AK_INVERT (1<<23) /* data is inverted */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355#define AK_GET_CHIP(val) (((val) >> 8) & 0xff)
356#define AK_GET_ADDR(val) ((val) & 0xff)
Takashi Iwai854b66e2006-09-08 12:27:38 +0200357#define AK_GET_SHIFT(val) (((val) >> 16) & 0x0f)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200358#define AK_GET_VOL_CVT(val) (((val) >> 21) & 1)
Takashi Iwai854b66e2006-09-08 12:27:38 +0200359#define AK_GET_IPGA(val) (((val) >> 20) & 1)
Jochen Voss34793072006-08-23 18:35:35 +0200360#define AK_GET_NEEDSMSB(val) (((val) >> 22) & 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361#define AK_GET_INVERT(val) (((val) >> 23) & 1)
362#define AK_GET_MASK(val) (((val) >> 24) & 0xff)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200363#define AK_COMPOSE(chip,addr,shift,mask) \
364 (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
Takashi Iwai97f02e02005-11-17 14:17:19 +0100366static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol,
367 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368{
369 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
370
371 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
372 uinfo->count = 1;
373 uinfo->value.integer.min = 0;
374 uinfo->value.integer.max = mask;
375 return 0;
376}
377
Takashi Iwai97f02e02005-11-17 14:17:19 +0100378static int snd_akm4xxx_volume_get(struct snd_kcontrol *kcontrol,
379 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100381 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 int chip = AK_GET_CHIP(kcontrol->private_value);
383 int addr = AK_GET_ADDR(kcontrol->private_value);
Jochen Voss34793072006-08-23 18:35:35 +0200384
Takashi Iwai723b2b02006-08-30 16:49:54 +0200385 ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 return 0;
387}
388
Takashi Iwai723b2b02006-08-30 16:49:54 +0200389static int put_ak_reg(struct snd_kcontrol *kcontrol, int addr,
390 unsigned char nval)
391{
392 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
393 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
394 int chip = AK_GET_CHIP(kcontrol->private_value);
395
396 if (snd_akm4xxx_get_vol(ak, chip, addr) == nval)
397 return 0;
398
399 snd_akm4xxx_set_vol(ak, chip, addr, nval);
Takashi Iwai854b66e2006-09-08 12:27:38 +0200400 if (AK_GET_VOL_CVT(kcontrol->private_value) && nval < 128)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200401 nval = vol_cvt_datt[nval];
Takashi Iwai854b66e2006-09-08 12:27:38 +0200402 if (AK_GET_IPGA(kcontrol->private_value) && nval >= 128)
403 nval++; /* need to correct + 1 since both 127 and 128 are 0dB */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200404 if (AK_GET_INVERT(kcontrol->private_value))
405 nval = mask - nval;
406 if (AK_GET_NEEDSMSB(kcontrol->private_value))
407 nval |= 0x80;
Pavel Hofman841b23d2008-03-17 08:45:33 +0100408 /* printk(KERN_DEBUG "DEBUG - AK writing reg: chip %x addr %x,
409 nval %x\n", chip, addr, nval); */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200410 snd_akm4xxx_write(ak, chip, addr, nval);
411 return 1;
412}
413
Takashi Iwai97f02e02005-11-17 14:17:19 +0100414static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
415 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416{
Takashi Iwai02ff1322007-11-15 16:15:29 +0100417 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
418 unsigned int val = ucontrol->value.integer.value[0];
419 if (val > mask)
420 return -EINVAL;
421 return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value), val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422}
423
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200424static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol,
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200425 struct snd_ctl_elem_info *uinfo)
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200426{
427 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
428
429 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
430 uinfo->count = 2;
431 uinfo->value.integer.min = 0;
432 uinfo->value.integer.max = mask;
433 return 0;
434}
435
436static int snd_akm4xxx_stereo_volume_get(struct snd_kcontrol *kcontrol,
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200437 struct snd_ctl_elem_value *ucontrol)
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200438{
439 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
440 int chip = AK_GET_CHIP(kcontrol->private_value);
441 int addr = AK_GET_ADDR(kcontrol->private_value);
Jochen Voss34793072006-08-23 18:35:35 +0200442
Takashi Iwai723b2b02006-08-30 16:49:54 +0200443 ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
444 ucontrol->value.integer.value[1] = snd_akm4xxx_get_vol(ak, chip, addr+1);
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200445 return 0;
446}
447
448static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200449 struct snd_ctl_elem_value *ucontrol)
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200450{
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200451 int addr = AK_GET_ADDR(kcontrol->private_value);
Takashi Iwai02ff1322007-11-15 16:15:29 +0100452 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
453 unsigned int val[2];
Takashi Iwai723b2b02006-08-30 16:49:54 +0200454 int change;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200455
Takashi Iwai02ff1322007-11-15 16:15:29 +0100456 val[0] = ucontrol->value.integer.value[0];
457 val[1] = ucontrol->value.integer.value[1];
458 if (val[0] > mask || val[1] > mask)
459 return -EINVAL;
460 change = put_ak_reg(kcontrol, addr, val[0]);
461 change |= put_ak_reg(kcontrol, addr + 1, val[1]);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200462 return change;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200463}
464
Takashi Iwai97f02e02005-11-17 14:17:19 +0100465static int snd_akm4xxx_deemphasis_info(struct snd_kcontrol *kcontrol,
466 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467{
468 static char *texts[4] = {
469 "44.1kHz", "Off", "48kHz", "32kHz",
470 };
471 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
472 uinfo->count = 1;
473 uinfo->value.enumerated.items = 4;
474 if (uinfo->value.enumerated.item >= 4)
475 uinfo->value.enumerated.item = 3;
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200476 strcpy(uinfo->value.enumerated.name,
477 texts[uinfo->value.enumerated.item]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 return 0;
479}
480
Takashi Iwai97f02e02005-11-17 14:17:19 +0100481static int snd_akm4xxx_deemphasis_get(struct snd_kcontrol *kcontrol,
482 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100484 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 int chip = AK_GET_CHIP(kcontrol->private_value);
486 int addr = AK_GET_ADDR(kcontrol->private_value);
487 int shift = AK_GET_SHIFT(kcontrol->private_value);
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200488 ucontrol->value.enumerated.item[0] =
489 (snd_akm4xxx_get(ak, chip, addr) >> shift) & 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 return 0;
491}
492
Takashi Iwai97f02e02005-11-17 14:17:19 +0100493static int snd_akm4xxx_deemphasis_put(struct snd_kcontrol *kcontrol,
494 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100496 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 int chip = AK_GET_CHIP(kcontrol->private_value);
498 int addr = AK_GET_ADDR(kcontrol->private_value);
499 int shift = AK_GET_SHIFT(kcontrol->private_value);
500 unsigned char nval = ucontrol->value.enumerated.item[0] & 3;
501 int change;
502
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200503 nval = (nval << shift) |
504 (snd_akm4xxx_get(ak, chip, addr) & ~(3 << shift));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 change = snd_akm4xxx_get(ak, chip, addr) != nval;
506 if (change)
507 snd_akm4xxx_write(ak, chip, addr, nval);
508 return change;
509}
510
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200511#define ak4xxx_switch_info snd_ctl_boolean_mono_info
Jochen Voss30ba6e22006-08-09 14:26:26 +0200512
513static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol,
514 struct snd_ctl_elem_value *ucontrol)
515{
516 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
517 int chip = AK_GET_CHIP(kcontrol->private_value);
518 int addr = AK_GET_ADDR(kcontrol->private_value);
519 int shift = AK_GET_SHIFT(kcontrol->private_value);
520 int invert = AK_GET_INVERT(kcontrol->private_value);
Pavel Hofmanea7cfcd2007-05-19 17:21:04 +0200521 /* we observe the (1<<shift) bit only */
522 unsigned char val = snd_akm4xxx_get(ak, chip, addr) & (1<<shift);
Jochen Voss30ba6e22006-08-09 14:26:26 +0200523 if (invert)
524 val = ! val;
525 ucontrol->value.integer.value[0] = (val & (1<<shift)) != 0;
526 return 0;
527}
528
529static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
530 struct snd_ctl_elem_value *ucontrol)
531{
532 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
533 int chip = AK_GET_CHIP(kcontrol->private_value);
534 int addr = AK_GET_ADDR(kcontrol->private_value);
535 int shift = AK_GET_SHIFT(kcontrol->private_value);
536 int invert = AK_GET_INVERT(kcontrol->private_value);
537 long flag = ucontrol->value.integer.value[0];
538 unsigned char val, oval;
539 int change;
540
541 if (invert)
542 flag = ! flag;
543 oval = snd_akm4xxx_get(ak, chip, addr);
544 if (flag)
545 val = oval | (1<<shift);
546 else
547 val = oval & ~(1<<shift);
548 change = (oval != val);
549 if (change)
550 snd_akm4xxx_write(ak, chip, addr, val);
551 return change;
552}
553
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200554#define AK5365_NUM_INPUTS 5
555
Takashi Iwai02ff1322007-11-15 16:15:29 +0100556static int ak4xxx_capture_num_inputs(struct snd_akm4xxx *ak, int mixer_ch)
557{
558 int num_names;
559 const char **input_names;
560
561 input_names = ak->adc_info[mixer_ch].input_names;
562 num_names = 0;
563 while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
564 ++num_names;
565 return num_names;
566}
567
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200568static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
569 struct snd_ctl_elem_info *uinfo)
570{
571 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
572 int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
573 const char **input_names;
574 int num_names, idx;
575
Takashi Iwai02ff1322007-11-15 16:15:29 +0100576 num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
577 if (!num_names)
578 return -EINVAL;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200579 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
580 uinfo->count = 1;
581 uinfo->value.enumerated.items = num_names;
582 idx = uinfo->value.enumerated.item;
583 if (idx >= num_names)
584 return -EINVAL;
Takashi Iwai02ff1322007-11-15 16:15:29 +0100585 input_names = ak->adc_info[mixer_ch].input_names;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200586 strncpy(uinfo->value.enumerated.name, input_names[idx],
587 sizeof(uinfo->value.enumerated.name));
588 return 0;
589}
590
591static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol,
592 struct snd_ctl_elem_value *ucontrol)
593{
594 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
595 int chip = AK_GET_CHIP(kcontrol->private_value);
596 int addr = AK_GET_ADDR(kcontrol->private_value);
597 int mask = AK_GET_MASK(kcontrol->private_value);
598 unsigned char val;
599
600 val = snd_akm4xxx_get(ak, chip, addr) & mask;
601 ucontrol->value.enumerated.item[0] = val;
602 return 0;
603}
604
605static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol,
606 struct snd_ctl_elem_value *ucontrol)
607{
608 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Takashi Iwai02ff1322007-11-15 16:15:29 +0100609 int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200610 int chip = AK_GET_CHIP(kcontrol->private_value);
611 int addr = AK_GET_ADDR(kcontrol->private_value);
612 int mask = AK_GET_MASK(kcontrol->private_value);
613 unsigned char oval, val;
Takashi Iwai02ff1322007-11-15 16:15:29 +0100614 int num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
615
616 if (ucontrol->value.enumerated.item[0] >= num_names)
617 return -EINVAL;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200618
619 oval = snd_akm4xxx_get(ak, chip, addr);
620 val = oval & ~mask;
621 val |= ucontrol->value.enumerated.item[0] & mask;
622 if (val != oval) {
623 snd_akm4xxx_write(ak, chip, addr, val);
624 return 1;
625 }
626 return 0;
627}
628
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629/*
630 * build AK4xxx controls
631 */
632
Takashi Iwai723b2b02006-08-30 16:49:54 +0200633static int build_dac_controls(struct snd_akm4xxx *ak)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634{
Takashi Iwai723b2b02006-08-30 16:49:54 +0200635 int idx, err, mixer_ch, num_stereo;
636 struct snd_kcontrol_new knew;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
Takashi Iwai723b2b02006-08-30 16:49:54 +0200638 mixer_ch = 0;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200639 for (idx = 0; idx < ak->num_dacs; ) {
Pavel Hofmanea7cfcd2007-05-19 17:21:04 +0200640 /* mute control for Revolution 7.1 - AK4381 */
641 if (ak->type == SND_AK4381
642 && ak->dac_info[mixer_ch].switch_name) {
643 memset(&knew, 0, sizeof(knew));
644 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
645 knew.count = 1;
646 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
647 knew.name = ak->dac_info[mixer_ch].switch_name;
648 knew.info = ak4xxx_switch_info;
649 knew.get = ak4xxx_switch_get;
650 knew.put = ak4xxx_switch_put;
651 knew.access = 0;
652 /* register 1, bit 0 (SMUTE): 0 = normal operation,
653 1 = mute */
654 knew.private_value =
655 AK_COMPOSE(idx/2, 1, 0, 0) | AK_INVERT;
656 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
657 if (err < 0)
658 return err;
659 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200660 memset(&knew, 0, sizeof(knew));
661 if (! ak->dac_info || ! ak->dac_info[mixer_ch].name) {
662 knew.name = "DAC Volume";
663 knew.index = mixer_ch + ak->idx_offset * 2;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200664 num_stereo = 1;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200665 } else {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200666 knew.name = ak->dac_info[mixer_ch].name;
667 num_stereo = ak->dac_info[mixer_ch].num_channels;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200668 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200669 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
670 knew.count = 1;
671 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
672 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200673 if (num_stereo == 2) {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200674 knew.info = snd_akm4xxx_stereo_volume_info;
675 knew.get = snd_akm4xxx_stereo_volume_get;
676 knew.put = snd_akm4xxx_stereo_volume_put;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200677 } else {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200678 knew.info = snd_akm4xxx_volume_info;
679 knew.get = snd_akm4xxx_volume_get;
680 knew.put = snd_akm4xxx_volume_put;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200681 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 switch (ak->type) {
683 case SND_AK4524:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200684 /* register 6 & 7 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200685 knew.private_value =
686 AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127) |
687 AK_VOL_CVT;
688 knew.tlv.p = db_scale_vol_datt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 break;
690 case SND_AK4528:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200691 /* register 4 & 5 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200692 knew.private_value =
693 AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127) |
694 AK_VOL_CVT;
695 knew.tlv.p = db_scale_vol_datt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 break;
697 case SND_AK4529: {
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200698 /* registers 2-7 and b,c */
699 int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200700 knew.private_value =
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200701 AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200702 knew.tlv.p = db_scale_8bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 break;
704 }
705 case SND_AK4355:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200706 /* register 4-9, chip #0 only */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200707 knew.private_value = AK_COMPOSE(0, idx + 4, 0, 255);
708 knew.tlv.p = db_scale_8bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 break;
Jochen Voss34793072006-08-23 18:35:35 +0200710 case SND_AK4358: {
711 /* register 4-9 and 11-12, chip #0 only */
712 int addr = idx < 6 ? idx + 4 : idx + 5;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200713 knew.private_value =
Jochen Voss34793072006-08-23 18:35:35 +0200714 AK_COMPOSE(0, addr, 0, 127) | AK_NEEDSMSB;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200715 knew.tlv.p = db_scale_7bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 break;
Jochen Voss34793072006-08-23 18:35:35 +0200717 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 case SND_AK4381:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200719 /* register 3 & 4 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200720 knew.private_value =
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200721 AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200722 knew.tlv.p = db_scale_linear;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 break;
Pavel Hofman8f346922009-09-16 22:25:36 +0200724 case SND_AK4620:
725 /* register 6 & 7 */
726 knew.private_value =
727 AK_COMPOSE(idx/2, (idx%2) + 6, 0, 255);
728 knew.tlv.p = db_scale_linear;
729 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 default:
Takashi Iwai723b2b02006-08-30 16:49:54 +0200731 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 }
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200733
Takashi Iwai723b2b02006-08-30 16:49:54 +0200734 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200735 if (err < 0)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200736 return err;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200737
738 idx += num_stereo;
739 mixer_ch++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200741 return 0;
742}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
Takashi Iwai723b2b02006-08-30 16:49:54 +0200744static int build_adc_controls(struct snd_akm4xxx *ak)
745{
Pavel Hofman8f346922009-09-16 22:25:36 +0200746 int idx, err, mixer_ch, num_stereo, max_steps;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200747 struct snd_kcontrol_new knew;
748
749 mixer_ch = 0;
Pavel Hofman8f346922009-09-16 22:25:36 +0200750 if (ak->type == SND_AK4528)
751 return 0; /* no controls */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200752 for (idx = 0; idx < ak->num_adcs;) {
753 memset(&knew, 0, sizeof(knew));
754 if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) {
755 knew.name = "ADC Volume";
756 knew.index = mixer_ch + ak->idx_offset * 2;
757 num_stereo = 1;
758 } else {
759 knew.name = ak->adc_info[mixer_ch].name;
760 num_stereo = ak->adc_info[mixer_ch].num_channels;
761 }
762 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
763 knew.count = 1;
764 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
765 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
766 if (num_stereo == 2) {
767 knew.info = snd_akm4xxx_stereo_volume_info;
768 knew.get = snd_akm4xxx_stereo_volume_get;
769 knew.put = snd_akm4xxx_stereo_volume_put;
770 } else {
771 knew.info = snd_akm4xxx_volume_info;
772 knew.get = snd_akm4xxx_volume_get;
773 knew.put = snd_akm4xxx_volume_put;
774 }
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200775 /* register 4 & 5 */
Takashi Iwai854b66e2006-09-08 12:27:38 +0200776 if (ak->type == SND_AK5365)
Pavel Hofman8f346922009-09-16 22:25:36 +0200777 max_steps = 152;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200778 else
Pavel Hofman8f346922009-09-16 22:25:36 +0200779 max_steps = 164;
780 knew.private_value =
781 AK_COMPOSE(idx/2, (idx%2) + 4, 0, max_steps) |
782 AK_VOL_CVT | AK_IPGA;
Takashi Iwai854b66e2006-09-08 12:27:38 +0200783 knew.tlv.p = db_scale_vol_datt;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200784 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
785 if (err < 0)
786 return err;
787
788 if (ak->type == SND_AK5365 && (idx % 2) == 0) {
789 if (! ak->adc_info ||
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200790 ! ak->adc_info[mixer_ch].switch_name) {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200791 knew.name = "Capture Switch";
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200792 knew.index = mixer_ch + ak->idx_offset * 2;
793 } else
Takashi Iwai723b2b02006-08-30 16:49:54 +0200794 knew.name = ak->adc_info[mixer_ch].switch_name;
795 knew.info = ak4xxx_switch_info;
796 knew.get = ak4xxx_switch_get;
797 knew.put = ak4xxx_switch_put;
798 knew.access = 0;
799 /* register 2, bit 0 (SMUTE): 0 = normal operation,
800 1 = mute */
801 knew.private_value =
802 AK_COMPOSE(idx/2, 2, 0, 0) | AK_INVERT;
803 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
804 if (err < 0)
805 return err;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200806
807 memset(&knew, 0, sizeof(knew));
808 knew.name = ak->adc_info[mixer_ch].selector_name;
809 if (!knew.name) {
810 knew.name = "Capture Channel";
811 knew.index = mixer_ch + ak->idx_offset * 2;
812 }
813
814 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
815 knew.info = ak4xxx_capture_source_info;
816 knew.get = ak4xxx_capture_source_get;
817 knew.put = ak4xxx_capture_source_put;
818 knew.access = 0;
819 /* input selector control: reg. 1, bits 0-2.
820 * mis-use 'shift' to pass mixer_ch */
821 knew.private_value
822 = AK_COMPOSE(idx/2, 1, mixer_ch, 0x07);
823 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
824 if (err < 0)
825 return err;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200826 }
827
828 idx += num_stereo;
829 mixer_ch++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200831 return 0;
832}
Jochen Voss683fe152006-08-08 21:12:44 +0200833
Takashi Iwai723b2b02006-08-30 16:49:54 +0200834static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
835{
836 int idx, err;
837 struct snd_kcontrol_new knew;
Jochen Voss30ba6e22006-08-09 14:26:26 +0200838
Takashi Iwai723b2b02006-08-30 16:49:54 +0200839 for (idx = 0; idx < num_emphs; idx++) {
840 memset(&knew, 0, sizeof(knew));
841 knew.name = "Deemphasis";
842 knew.index = idx + ak->idx_offset;
843 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
844 knew.count = 1;
845 knew.info = snd_akm4xxx_deemphasis_info;
846 knew.get = snd_akm4xxx_deemphasis_get;
847 knew.put = snd_akm4xxx_deemphasis_put;
848 switch (ak->type) {
849 case SND_AK4524:
850 case SND_AK4528:
Pavel Hofman8f346922009-09-16 22:25:36 +0200851 case SND_AK4620:
Takashi Iwai723b2b02006-08-30 16:49:54 +0200852 /* register 3 */
853 knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
854 break;
855 case SND_AK4529: {
856 int shift = idx == 3 ? 6 : (2 - idx) * 2;
857 /* register 8 with shift */
858 knew.private_value = AK_COMPOSE(0, 8, shift, 0);
859 break;
860 }
861 case SND_AK4355:
862 case SND_AK4358:
863 knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
864 break;
865 case SND_AK4381:
866 knew.private_value = AK_COMPOSE(idx, 1, 1, 0);
867 break;
868 default:
869 return -EINVAL;
870 }
871 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
Jochen Voss30ba6e22006-08-09 14:26:26 +0200872 if (err < 0)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200873 return err;
874 }
875 return 0;
876}
877
Pavel Hofman8f346922009-09-16 22:25:36 +0200878#ifdef CONFIG_PROC_FS
879static void proc_regs_read(struct snd_info_entry *entry,
880 struct snd_info_buffer *buffer)
881{
Joe Perches9fe856e2010-09-04 18:52:54 -0700882 struct snd_akm4xxx *ak = entry->private_data;
Pavel Hofman8f346922009-09-16 22:25:36 +0200883 int reg, val, chip;
884 for (chip = 0; chip < ak->num_chips; chip++) {
885 for (reg = 0; reg < ak->total_regs; reg++) {
886 val = snd_akm4xxx_get(ak, chip, reg);
887 snd_iprintf(buffer, "chip %d: 0x%02x = 0x%02x\n", chip,
888 reg, val);
889 }
890 }
891}
892
893static int proc_init(struct snd_akm4xxx *ak)
894{
895 struct snd_info_entry *entry;
896 int err;
897 err = snd_card_proc_new(ak->card, ak->name, &entry);
898 if (err < 0)
899 return err;
900 snd_info_set_text_ops(entry, ak, proc_regs_read);
901 return 0;
902}
903#else /* !CONFIG_PROC_FS */
Takashi Iwaie913b142010-09-30 22:59:12 +0200904static int proc_init(struct snd_akm4xxx *ak) { return 0; }
Pavel Hofman8f346922009-09-16 22:25:36 +0200905#endif
906
Takashi Iwai723b2b02006-08-30 16:49:54 +0200907int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
908{
909 int err, num_emphs;
910
911 err = build_dac_controls(ak);
912 if (err < 0)
913 return err;
914
Takashi Iwai854b66e2006-09-08 12:27:38 +0200915 err = build_adc_controls(ak);
916 if (err < 0)
917 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
919 num_emphs = 1;
Pavel Hofman8f346922009-09-16 22:25:36 +0200920 else if (ak->type == SND_AK4620)
921 num_emphs = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 else
923 num_emphs = ak->num_dacs / 2;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200924 err = build_deemphasis(ak, num_emphs);
925 if (err < 0)
926 return err;
Pavel Hofman8f346922009-09-16 22:25:36 +0200927 err = proc_init(ak);
928 if (err < 0)
929 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930
Takashi Iwai723b2b02006-08-30 16:49:54 +0200931 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932}
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200933EXPORT_SYMBOL(snd_akm4xxx_build_controls);
934
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935static int __init alsa_akm4xxx_module_init(void)
936{
937 return 0;
938}
939
940static void __exit alsa_akm4xxx_module_exit(void)
941{
942}
943
944module_init(alsa_akm4xxx_module_init)
945module_exit(alsa_akm4xxx_module_exit)