blob: 7d15093844b9232fc83ccfc16c1225ee00b43168 [file] [log] [blame]
Thomas Gleixner1a59d1b82019-05-27 08:55:05 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * ALSA driver for AK4524 / AK4528 / AK4529 / AK4355 / AK4358 / AK4381
4 * AD and DA converters
5 *
Jaroslav Kyselac1017a42007-10-15 09:50:19 +02006 * Copyright (c) 2000-2004 Jaroslav Kysela <perex@perex.cz>,
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * Takashi Iwai <tiwai@suse.de>
Pavel Hofman8f346922009-09-16 22:25:36 +02008 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07009
Takashi Iwai6cbbfe12015-01-28 16:49:33 +010010#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/delay.h>
12#include <linux/interrupt.h>
13#include <linux/init.h>
Paul Gortmakerda155d52011-07-15 12:38:28 -040014#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <sound/core.h>
16#include <sound/control.h>
Takashi Iwai723b2b02006-08-30 16:49:54 +020017#include <sound/tlv.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <sound/ak4xxx-adda.h>
Pavel Hofman8f346922009-09-16 22:25:36 +020019#include <sound/info.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
Jaroslav Kyselac1017a42007-10-15 09:50:19 +020021MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>");
Linus Torvalds1da177e2005-04-16 15:20:36 -070022MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters");
23MODULE_LICENSE("GPL");
24
Takashi Iwai723b2b02006-08-30 16:49:54 +020025/* write the given register and save the data to the cache */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020026void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg,
27 unsigned char val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070028{
29 ak->ops.lock(ak, chip);
30 ak->ops.write(ak, chip, reg, val);
31
32 /* save the data */
Takashi Iwai854b66e2006-09-08 12:27:38 +020033 snd_akm4xxx_set(ak, chip, reg, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -070034 ak->ops.unlock(ak, chip);
35}
36
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020037EXPORT_SYMBOL(snd_akm4xxx_write);
38
39/* reset procedure for AK4524 and AK4528 */
40static void ak4524_reset(struct snd_akm4xxx *ak, int state)
41{
42 unsigned int chip;
Pavel Hofman8f346922009-09-16 22:25:36 +020043 unsigned char reg;
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020044
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020045 for (chip = 0; chip < ak->num_dacs/2; chip++) {
46 snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03);
47 if (state)
48 continue;
49 /* DAC volumes */
Pavel Hofman8f346922009-09-16 22:25:36 +020050 for (reg = 0x04; reg < ak->total_regs; reg++)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020051 snd_akm4xxx_write(ak, chip, reg,
52 snd_akm4xxx_get(ak, chip, reg));
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020053 }
54}
55
56/* reset procedure for AK4355 and AK4358 */
Pavel Hofman8f346922009-09-16 22:25:36 +020057static void ak435X_reset(struct snd_akm4xxx *ak, int state)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020058{
59 unsigned char reg;
60
61 if (state) {
62 snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */
63 return;
64 }
Pavel Hofman8f346922009-09-16 22:25:36 +020065 for (reg = 0x00; reg < ak->total_regs; reg++)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020066 if (reg != 0x01)
67 snd_akm4xxx_write(ak, 0, reg,
68 snd_akm4xxx_get(ak, 0, reg));
69 snd_akm4xxx_write(ak, 0, 0x01, 0x01); /* un-reset, unmute */
70}
71
72/* reset procedure for AK4381 */
73static void ak4381_reset(struct snd_akm4xxx *ak, int state)
74{
75 unsigned int chip;
76 unsigned char reg;
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020077 for (chip = 0; chip < ak->num_dacs/2; chip++) {
78 snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f);
79 if (state)
80 continue;
Pavel Hofman8f346922009-09-16 22:25:36 +020081 for (reg = 0x01; reg < ak->total_regs; reg++)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020082 snd_akm4xxx_write(ak, chip, reg,
83 snd_akm4xxx_get(ak, chip, reg));
84 }
85}
86
Linus Torvalds1da177e2005-04-16 15:20:36 -070087/*
88 * reset the AKM codecs
89 * @state: 1 = reset codec, 0 = restore the registers
90 *
91 * assert the reset operation and restores the register values to the chips.
92 */
Takashi Iwai97f02e02005-11-17 14:17:19 +010093void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state)
Linus Torvalds1da177e2005-04-16 15:20:36 -070094{
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 switch (ak->type) {
96 case SND_AK4524:
97 case SND_AK4528:
Pavel Hofman8f346922009-09-16 22:25:36 +020098 case SND_AK4620:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +020099 ak4524_reset(ak, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 break;
101 case SND_AK4529:
102 /* FIXME: needed for ak4529? */
103 break;
104 case SND_AK4355:
Pavel Hofman8f346922009-09-16 22:25:36 +0200105 ak435X_reset(ak, state);
Pavel Hofman841b23d2008-03-17 08:45:33 +0100106 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 case SND_AK4358:
Pavel Hofman8f346922009-09-16 22:25:36 +0200108 ak435X_reset(ak, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 break;
110 case SND_AK4381:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200111 ak4381_reset(ak, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 break;
Takashi Iwaicf939072006-08-09 14:33:27 +0200113 default:
114 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 }
116}
117
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200118EXPORT_SYMBOL(snd_akm4xxx_reset);
119
Takashi Iwai723b2b02006-08-30 16:49:54 +0200120
121/*
122 * Volume conversion table for non-linear volumes
123 * from -63.5dB (mute) to 0dB step 0.5dB
124 *
Pavel Hofman8f346922009-09-16 22:25:36 +0200125 * Used for AK4524/AK4620 input/ouput attenuation, AK4528, and
Takashi Iwai723b2b02006-08-30 16:49:54 +0200126 * AK5365 input attenuation
127 */
Takashi Iwai517400c2007-01-29 15:27:56 +0100128static const unsigned char vol_cvt_datt[128] = {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200129 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04,
130 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06,
131 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a,
132 0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f,
133 0x10, 0x10, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14,
134 0x15, 0x16, 0x17, 0x17, 0x18, 0x19, 0x1a, 0x1c,
135 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x23,
136 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, 0x2b, 0x2d,
137 0x2e, 0x30, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
138 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3e, 0x3f, 0x40,
139 0x41, 0x42, 0x43, 0x44, 0x46, 0x47, 0x48, 0x4a,
140 0x4b, 0x4d, 0x4e, 0x50, 0x51, 0x52, 0x53, 0x54,
141 0x55, 0x56, 0x58, 0x59, 0x5b, 0x5c, 0x5e, 0x5f,
142 0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x69,
143 0x6a, 0x6c, 0x6d, 0x6f, 0x70, 0x71, 0x72, 0x73,
144 0x75, 0x76, 0x77, 0x79, 0x7a, 0x7c, 0x7d, 0x7f,
145};
146
147/*
148 * dB tables
149 */
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100150static const DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
151static const DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
152static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
153static const DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200154
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155/*
156 * initialize all the ak4xxx chips
157 */
Takashi Iwai97f02e02005-11-17 14:17:19 +0100158void snd_akm4xxx_init(struct snd_akm4xxx *ak)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159{
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100160 static const unsigned char inits_ak4524[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 0x00, 0x07, /* 0: all power up */
162 0x01, 0x00, /* 1: ADC/DAC reset */
163 0x02, 0x60, /* 2: 24bit I2S */
164 0x03, 0x19, /* 3: deemphasis off */
165 0x01, 0x03, /* 1: ADC/DAC enable */
166 0x04, 0x00, /* 4: ADC left muted */
167 0x05, 0x00, /* 5: ADC right muted */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 0x06, 0x00, /* 6: DAC left muted */
169 0x07, 0x00, /* 7: DAC right muted */
170 0xff, 0xff
171 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100172 static const unsigned char inits_ak4528[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 0x00, 0x07, /* 0: all power up */
174 0x01, 0x00, /* 1: ADC/DAC reset */
175 0x02, 0x60, /* 2: 24bit I2S */
176 0x03, 0x0d, /* 3: deemphasis off, turn LR highpass filters on */
177 0x01, 0x03, /* 1: ADC/DAC enable */
178 0x04, 0x00, /* 4: ADC left muted */
179 0x05, 0x00, /* 5: ADC right muted */
180 0xff, 0xff
181 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100182 static const unsigned char inits_ak4529[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 0x09, 0x01, /* 9: ATS=0, RSTN=1 */
184 0x0a, 0x3f, /* A: all power up, no zero/overflow detection */
185 0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */
186 0x01, 0x00, /* 1: ACKS=0, ADC, loop off */
187 0x02, 0xff, /* 2: LOUT1 muted */
188 0x03, 0xff, /* 3: ROUT1 muted */
189 0x04, 0xff, /* 4: LOUT2 muted */
190 0x05, 0xff, /* 5: ROUT2 muted */
191 0x06, 0xff, /* 6: LOUT3 muted */
192 0x07, 0xff, /* 7: ROUT3 muted */
193 0x0b, 0xff, /* B: LOUT4 muted */
194 0x0c, 0xff, /* C: ROUT4 muted */
195 0x08, 0x55, /* 8: deemphasis all off */
196 0xff, 0xff
197 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100198 static const unsigned char inits_ak4355[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 0x01, 0x02, /* 1: reset and soft-mute */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200200 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
201 * disable DZF, sharp roll-off, RSTN#=0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
203 // 0x02, 0x2e, /* quad speed */
204 0x03, 0x01, /* 3: de-emphasis off */
205 0x04, 0x00, /* 4: LOUT1 volume muted */
206 0x05, 0x00, /* 5: ROUT1 volume muted */
207 0x06, 0x00, /* 6: LOUT2 volume muted */
208 0x07, 0x00, /* 7: ROUT2 volume muted */
209 0x08, 0x00, /* 8: LOUT3 volume muted */
210 0x09, 0x00, /* 9: ROUT3 volume muted */
211 0x0a, 0x00, /* a: DATT speed=0, ignore DZF */
212 0x01, 0x01, /* 1: un-reset, unmute */
213 0xff, 0xff
214 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100215 static const unsigned char inits_ak4358[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 0x01, 0x02, /* 1: reset and soft-mute */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200217 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
218 * disable DZF, sharp roll-off, RSTN#=0 */
Alexander Beregalov46480b32008-08-21 08:28:42 +0400219 0x02, 0x4e, /* 2: DA's power up, normal speed, RSTN#=0 */
220 /* 0x02, 0x6e,*/ /* quad speed */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 0x03, 0x01, /* 3: de-emphasis off */
222 0x04, 0x00, /* 4: LOUT1 volume muted */
223 0x05, 0x00, /* 5: ROUT1 volume muted */
224 0x06, 0x00, /* 6: LOUT2 volume muted */
225 0x07, 0x00, /* 7: ROUT2 volume muted */
226 0x08, 0x00, /* 8: LOUT3 volume muted */
227 0x09, 0x00, /* 9: ROUT3 volume muted */
228 0x0b, 0x00, /* b: LOUT4 volume muted */
229 0x0c, 0x00, /* c: ROUT4 volume muted */
230 0x0a, 0x00, /* a: DATT speed=0, ignore DZF */
231 0x01, 0x01, /* 1: un-reset, unmute */
232 0xff, 0xff
233 };
Takashi Iwai517400c2007-01-29 15:27:56 +0100234 static const unsigned char inits_ak4381[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200236 0x01, 0x02, /* 1: de-emphasis off, normal speed,
237 * sharp roll-off, DZF off */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 // 0x01, 0x12, /* quad speed */
239 0x02, 0x00, /* 2: DZF disabled */
240 0x03, 0x00, /* 3: LATT 0 */
241 0x04, 0x00, /* 4: RATT 0 */
242 0x00, 0x0f, /* 0: power-up, un-reset */
243 0xff, 0xff
244 };
Pavel Hofman8f346922009-09-16 22:25:36 +0200245 static const unsigned char inits_ak4620[] = {
246 0x00, 0x07, /* 0: normal */
247 0x01, 0x00, /* 0: reset */
248 0x01, 0x02, /* 1: RSTAD */
249 0x01, 0x03, /* 1: RSTDA */
250 0x01, 0x0f, /* 1: normal */
251 0x02, 0x60, /* 2: 24bit I2S */
252 0x03, 0x01, /* 3: deemphasis off */
253 0x04, 0x00, /* 4: LIN muted */
254 0x05, 0x00, /* 5: RIN muted */
255 0x06, 0x00, /* 6: LOUT muted */
256 0x07, 0x00, /* 7: ROUT muted */
257 0xff, 0xff
258 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
Pavel Hofman8f346922009-09-16 22:25:36 +0200260 int chip;
Takashi Iwai517400c2007-01-29 15:27:56 +0100261 const unsigned char *ptr, *inits;
262 unsigned char reg, data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
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;
Pavel Hofman8f346922009-09-16 22:25:36 +0200270 ak->num_chips = ak->num_dacs / 2;
271 ak->name = "ak4524";
272 ak->total_regs = 0x08;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 break;
274 case SND_AK4528:
275 inits = inits_ak4528;
Pavel Hofman8f346922009-09-16 22:25:36 +0200276 ak->num_chips = ak->num_dacs / 2;
277 ak->name = "ak4528";
278 ak->total_regs = 0x06;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 break;
280 case SND_AK4529:
281 inits = inits_ak4529;
Pavel Hofman8f346922009-09-16 22:25:36 +0200282 ak->num_chips = 1;
283 ak->name = "ak4529";
284 ak->total_regs = 0x0d;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 break;
286 case SND_AK4355:
287 inits = inits_ak4355;
Pavel Hofman8f346922009-09-16 22:25:36 +0200288 ak->num_chips = 1;
289 ak->name = "ak4355";
290 ak->total_regs = 0x0b;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 break;
292 case SND_AK4358:
293 inits = inits_ak4358;
Pavel Hofman8f346922009-09-16 22:25:36 +0200294 ak->num_chips = 1;
295 ak->name = "ak4358";
296 ak->total_regs = 0x10;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 break;
298 case SND_AK4381:
299 inits = inits_ak4381;
Pavel Hofman8f346922009-09-16 22:25:36 +0200300 ak->num_chips = ak->num_dacs / 2;
301 ak->name = "ak4381";
302 ak->total_regs = 0x05;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 break;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200304 case SND_AK5365:
305 /* FIXME: any init sequence? */
Pavel Hofman8f346922009-09-16 22:25:36 +0200306 ak->num_chips = 1;
307 ak->name = "ak5365";
308 ak->total_regs = 0x08;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200309 return;
Pavel Hofman8f346922009-09-16 22:25:36 +0200310 case SND_AK4620:
311 inits = inits_ak4620;
312 ak->num_chips = ak->num_dacs / 2;
313 ak->name = "ak4620";
314 ak->total_regs = 0x08;
315 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 default:
317 snd_BUG();
318 return;
319 }
320
Pavel Hofman8f346922009-09-16 22:25:36 +0200321 for (chip = 0; chip < ak->num_chips; chip++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 ptr = inits;
323 while (*ptr != 0xff) {
324 reg = *ptr++;
325 data = *ptr++;
326 snd_akm4xxx_write(ak, chip, reg, data);
Pavel Hofman8f346922009-09-16 22:25:36 +0200327 udelay(10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 }
329 }
330}
331
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200332EXPORT_SYMBOL(snd_akm4xxx_init);
333
Takashi Iwai723b2b02006-08-30 16:49:54 +0200334/*
335 * Mixer callbacks
336 */
Takashi Iwai854b66e2006-09-08 12:27:38 +0200337#define AK_IPGA (1<<20) /* including IPGA */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200338#define AK_VOL_CVT (1<<21) /* need dB conversion */
339#define AK_NEEDSMSB (1<<22) /* need MSB update bit */
340#define AK_INVERT (1<<23) /* data is inverted */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341#define AK_GET_CHIP(val) (((val) >> 8) & 0xff)
342#define AK_GET_ADDR(val) ((val) & 0xff)
Takashi Iwai854b66e2006-09-08 12:27:38 +0200343#define AK_GET_SHIFT(val) (((val) >> 16) & 0x0f)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200344#define AK_GET_VOL_CVT(val) (((val) >> 21) & 1)
Takashi Iwai854b66e2006-09-08 12:27:38 +0200345#define AK_GET_IPGA(val) (((val) >> 20) & 1)
Jochen Voss34793072006-08-23 18:35:35 +0200346#define AK_GET_NEEDSMSB(val) (((val) >> 22) & 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347#define AK_GET_INVERT(val) (((val) >> 23) & 1)
348#define AK_GET_MASK(val) (((val) >> 24) & 0xff)
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200349#define AK_COMPOSE(chip,addr,shift,mask) \
350 (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Takashi Iwai97f02e02005-11-17 14:17:19 +0100352static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol,
353 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
355 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
356
357 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
358 uinfo->count = 1;
359 uinfo->value.integer.min = 0;
360 uinfo->value.integer.max = mask;
361 return 0;
362}
363
Takashi Iwai97f02e02005-11-17 14:17:19 +0100364static int snd_akm4xxx_volume_get(struct snd_kcontrol *kcontrol,
365 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100367 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 int chip = AK_GET_CHIP(kcontrol->private_value);
369 int addr = AK_GET_ADDR(kcontrol->private_value);
Jochen Voss34793072006-08-23 18:35:35 +0200370
Takashi Iwai723b2b02006-08-30 16:49:54 +0200371 ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 return 0;
373}
374
Takashi Iwai723b2b02006-08-30 16:49:54 +0200375static int put_ak_reg(struct snd_kcontrol *kcontrol, int addr,
376 unsigned char nval)
377{
378 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
379 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
380 int chip = AK_GET_CHIP(kcontrol->private_value);
381
382 if (snd_akm4xxx_get_vol(ak, chip, addr) == nval)
383 return 0;
384
385 snd_akm4xxx_set_vol(ak, chip, addr, nval);
Takashi Iwai854b66e2006-09-08 12:27:38 +0200386 if (AK_GET_VOL_CVT(kcontrol->private_value) && nval < 128)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200387 nval = vol_cvt_datt[nval];
Takashi Iwai854b66e2006-09-08 12:27:38 +0200388 if (AK_GET_IPGA(kcontrol->private_value) && nval >= 128)
389 nval++; /* need to correct + 1 since both 127 and 128 are 0dB */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200390 if (AK_GET_INVERT(kcontrol->private_value))
391 nval = mask - nval;
392 if (AK_GET_NEEDSMSB(kcontrol->private_value))
393 nval |= 0x80;
Pavel Hofman841b23d2008-03-17 08:45:33 +0100394 /* printk(KERN_DEBUG "DEBUG - AK writing reg: chip %x addr %x,
395 nval %x\n", chip, addr, nval); */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200396 snd_akm4xxx_write(ak, chip, addr, nval);
397 return 1;
398}
399
Takashi Iwai97f02e02005-11-17 14:17:19 +0100400static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
401 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402{
Takashi Iwai02ff1322007-11-15 16:15:29 +0100403 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
404 unsigned int val = ucontrol->value.integer.value[0];
405 if (val > mask)
406 return -EINVAL;
407 return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value), val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408}
409
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200410static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol,
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200411 struct snd_ctl_elem_info *uinfo)
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200412{
413 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
414
415 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
416 uinfo->count = 2;
417 uinfo->value.integer.min = 0;
418 uinfo->value.integer.max = mask;
419 return 0;
420}
421
422static int snd_akm4xxx_stereo_volume_get(struct snd_kcontrol *kcontrol,
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200423 struct snd_ctl_elem_value *ucontrol)
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200424{
425 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
426 int chip = AK_GET_CHIP(kcontrol->private_value);
427 int addr = AK_GET_ADDR(kcontrol->private_value);
Jochen Voss34793072006-08-23 18:35:35 +0200428
Takashi Iwai723b2b02006-08-30 16:49:54 +0200429 ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
430 ucontrol->value.integer.value[1] = snd_akm4xxx_get_vol(ak, chip, addr+1);
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200431 return 0;
432}
433
434static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200435 struct snd_ctl_elem_value *ucontrol)
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200436{
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200437 int addr = AK_GET_ADDR(kcontrol->private_value);
Takashi Iwai02ff1322007-11-15 16:15:29 +0100438 unsigned int mask = AK_GET_MASK(kcontrol->private_value);
439 unsigned int val[2];
Takashi Iwai723b2b02006-08-30 16:49:54 +0200440 int change;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200441
Takashi Iwai02ff1322007-11-15 16:15:29 +0100442 val[0] = ucontrol->value.integer.value[0];
443 val[1] = ucontrol->value.integer.value[1];
444 if (val[0] > mask || val[1] > mask)
445 return -EINVAL;
446 change = put_ak_reg(kcontrol, addr, val[0]);
447 change |= put_ak_reg(kcontrol, addr + 1, val[1]);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200448 return change;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200449}
450
Takashi Iwai97f02e02005-11-17 14:17:19 +0100451static int snd_akm4xxx_deemphasis_info(struct snd_kcontrol *kcontrol,
452 struct snd_ctl_elem_info *uinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453{
Takashi Iwai609e4782014-10-20 18:13:01 +0200454 static const char * const texts[4] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 "44.1kHz", "Off", "48kHz", "32kHz",
456 };
Takashi Iwai609e4782014-10-20 18:13:01 +0200457 return snd_ctl_enum_info(uinfo, 1, 4, texts);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458}
459
Takashi Iwai97f02e02005-11-17 14:17:19 +0100460static int snd_akm4xxx_deemphasis_get(struct snd_kcontrol *kcontrol,
461 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100463 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 int chip = AK_GET_CHIP(kcontrol->private_value);
465 int addr = AK_GET_ADDR(kcontrol->private_value);
466 int shift = AK_GET_SHIFT(kcontrol->private_value);
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200467 ucontrol->value.enumerated.item[0] =
468 (snd_akm4xxx_get(ak, chip, addr) >> shift) & 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 return 0;
470}
471
Takashi Iwai97f02e02005-11-17 14:17:19 +0100472static int snd_akm4xxx_deemphasis_put(struct snd_kcontrol *kcontrol,
473 struct snd_ctl_elem_value *ucontrol)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474{
Takashi Iwai97f02e02005-11-17 14:17:19 +0100475 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 int chip = AK_GET_CHIP(kcontrol->private_value);
477 int addr = AK_GET_ADDR(kcontrol->private_value);
478 int shift = AK_GET_SHIFT(kcontrol->private_value);
479 unsigned char nval = ucontrol->value.enumerated.item[0] & 3;
480 int change;
481
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200482 nval = (nval << shift) |
483 (snd_akm4xxx_get(ak, chip, addr) & ~(3 << shift));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 change = snd_akm4xxx_get(ak, chip, addr) != nval;
485 if (change)
486 snd_akm4xxx_write(ak, chip, addr, nval);
487 return change;
488}
489
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200490#define ak4xxx_switch_info snd_ctl_boolean_mono_info
Jochen Voss30ba6e22006-08-09 14:26:26 +0200491
492static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol,
493 struct snd_ctl_elem_value *ucontrol)
494{
495 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
496 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 int invert = AK_GET_INVERT(kcontrol->private_value);
Pavel Hofmanea7cfcd2007-05-19 17:21:04 +0200500 /* we observe the (1<<shift) bit only */
501 unsigned char val = snd_akm4xxx_get(ak, chip, addr) & (1<<shift);
Jochen Voss30ba6e22006-08-09 14:26:26 +0200502 if (invert)
503 val = ! val;
504 ucontrol->value.integer.value[0] = (val & (1<<shift)) != 0;
505 return 0;
506}
507
508static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
509 struct snd_ctl_elem_value *ucontrol)
510{
511 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
512 int chip = AK_GET_CHIP(kcontrol->private_value);
513 int addr = AK_GET_ADDR(kcontrol->private_value);
514 int shift = AK_GET_SHIFT(kcontrol->private_value);
515 int invert = AK_GET_INVERT(kcontrol->private_value);
516 long flag = ucontrol->value.integer.value[0];
517 unsigned char val, oval;
518 int change;
519
520 if (invert)
521 flag = ! flag;
522 oval = snd_akm4xxx_get(ak, chip, addr);
523 if (flag)
524 val = oval | (1<<shift);
525 else
526 val = oval & ~(1<<shift);
527 change = (oval != val);
528 if (change)
529 snd_akm4xxx_write(ak, chip, addr, val);
530 return change;
531}
532
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200533#define AK5365_NUM_INPUTS 5
534
Takashi Iwai02ff1322007-11-15 16:15:29 +0100535static int ak4xxx_capture_num_inputs(struct snd_akm4xxx *ak, int mixer_ch)
536{
537 int num_names;
538 const char **input_names;
539
540 input_names = ak->adc_info[mixer_ch].input_names;
541 num_names = 0;
542 while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
543 ++num_names;
544 return num_names;
545}
546
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200547static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
548 struct snd_ctl_elem_info *uinfo)
549{
550 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
551 int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
Takashi Iwai609e4782014-10-20 18:13:01 +0200552 unsigned int num_names;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200553
Takashi Iwai02ff1322007-11-15 16:15:29 +0100554 num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
555 if (!num_names)
556 return -EINVAL;
Takashi Iwai609e4782014-10-20 18:13:01 +0200557 return snd_ctl_enum_info(uinfo, 1, num_names,
558 ak->adc_info[mixer_ch].input_names);
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200559}
560
561static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol,
562 struct snd_ctl_elem_value *ucontrol)
563{
564 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
565 int chip = AK_GET_CHIP(kcontrol->private_value);
566 int addr = AK_GET_ADDR(kcontrol->private_value);
567 int mask = AK_GET_MASK(kcontrol->private_value);
568 unsigned char val;
569
570 val = snd_akm4xxx_get(ak, chip, addr) & mask;
571 ucontrol->value.enumerated.item[0] = val;
572 return 0;
573}
574
575static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol,
576 struct snd_ctl_elem_value *ucontrol)
577{
578 struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
Takashi Iwai02ff1322007-11-15 16:15:29 +0100579 int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200580 int chip = AK_GET_CHIP(kcontrol->private_value);
581 int addr = AK_GET_ADDR(kcontrol->private_value);
582 int mask = AK_GET_MASK(kcontrol->private_value);
583 unsigned char oval, val;
Takashi Iwai02ff1322007-11-15 16:15:29 +0100584 int num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
585
586 if (ucontrol->value.enumerated.item[0] >= num_names)
587 return -EINVAL;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200588
589 oval = snd_akm4xxx_get(ak, chip, addr);
590 val = oval & ~mask;
591 val |= ucontrol->value.enumerated.item[0] & mask;
592 if (val != oval) {
593 snd_akm4xxx_write(ak, chip, addr, val);
594 return 1;
595 }
596 return 0;
597}
598
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599/*
600 * build AK4xxx controls
601 */
602
Takashi Iwai723b2b02006-08-30 16:49:54 +0200603static int build_dac_controls(struct snd_akm4xxx *ak)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604{
Takashi Iwai723b2b02006-08-30 16:49:54 +0200605 int idx, err, mixer_ch, num_stereo;
606 struct snd_kcontrol_new knew;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
Takashi Iwai723b2b02006-08-30 16:49:54 +0200608 mixer_ch = 0;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200609 for (idx = 0; idx < ak->num_dacs; ) {
Pavel Hofmanea7cfcd2007-05-19 17:21:04 +0200610 /* mute control for Revolution 7.1 - AK4381 */
611 if (ak->type == SND_AK4381
612 && ak->dac_info[mixer_ch].switch_name) {
613 memset(&knew, 0, sizeof(knew));
614 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
615 knew.count = 1;
616 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
617 knew.name = ak->dac_info[mixer_ch].switch_name;
618 knew.info = ak4xxx_switch_info;
619 knew.get = ak4xxx_switch_get;
620 knew.put = ak4xxx_switch_put;
621 knew.access = 0;
622 /* register 1, bit 0 (SMUTE): 0 = normal operation,
623 1 = mute */
624 knew.private_value =
625 AK_COMPOSE(idx/2, 1, 0, 0) | AK_INVERT;
626 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
627 if (err < 0)
628 return err;
629 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200630 memset(&knew, 0, sizeof(knew));
631 if (! ak->dac_info || ! ak->dac_info[mixer_ch].name) {
632 knew.name = "DAC Volume";
633 knew.index = mixer_ch + ak->idx_offset * 2;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200634 num_stereo = 1;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200635 } else {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200636 knew.name = ak->dac_info[mixer_ch].name;
637 num_stereo = ak->dac_info[mixer_ch].num_channels;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200638 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200639 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
640 knew.count = 1;
641 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
642 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200643 if (num_stereo == 2) {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200644 knew.info = snd_akm4xxx_stereo_volume_info;
645 knew.get = snd_akm4xxx_stereo_volume_get;
646 knew.put = snd_akm4xxx_stereo_volume_put;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200647 } else {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200648 knew.info = snd_akm4xxx_volume_info;
649 knew.get = snd_akm4xxx_volume_get;
650 knew.put = snd_akm4xxx_volume_put;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200651 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 switch (ak->type) {
653 case SND_AK4524:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200654 /* register 6 & 7 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200655 knew.private_value =
656 AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127) |
657 AK_VOL_CVT;
658 knew.tlv.p = db_scale_vol_datt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 break;
660 case SND_AK4528:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200661 /* register 4 & 5 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200662 knew.private_value =
663 AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127) |
664 AK_VOL_CVT;
665 knew.tlv.p = db_scale_vol_datt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 break;
667 case SND_AK4529: {
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200668 /* registers 2-7 and b,c */
669 int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200670 knew.private_value =
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200671 AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200672 knew.tlv.p = db_scale_8bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 break;
674 }
675 case SND_AK4355:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200676 /* register 4-9, chip #0 only */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200677 knew.private_value = AK_COMPOSE(0, idx + 4, 0, 255);
678 knew.tlv.p = db_scale_8bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 break;
Jochen Voss34793072006-08-23 18:35:35 +0200680 case SND_AK4358: {
681 /* register 4-9 and 11-12, chip #0 only */
682 int addr = idx < 6 ? idx + 4 : idx + 5;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200683 knew.private_value =
Jochen Voss34793072006-08-23 18:35:35 +0200684 AK_COMPOSE(0, addr, 0, 127) | AK_NEEDSMSB;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200685 knew.tlv.p = db_scale_7bit;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 break;
Jochen Voss34793072006-08-23 18:35:35 +0200687 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 case SND_AK4381:
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200689 /* register 3 & 4 */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200690 knew.private_value =
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200691 AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255);
Takashi Iwai723b2b02006-08-30 16:49:54 +0200692 knew.tlv.p = db_scale_linear;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 break;
Pavel Hofman8f346922009-09-16 22:25:36 +0200694 case SND_AK4620:
695 /* register 6 & 7 */
696 knew.private_value =
697 AK_COMPOSE(idx/2, (idx%2) + 6, 0, 255);
698 knew.tlv.p = db_scale_linear;
699 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 default:
Takashi Iwai723b2b02006-08-30 16:49:54 +0200701 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 }
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200703
Takashi Iwai723b2b02006-08-30 16:49:54 +0200704 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200705 if (err < 0)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200706 return err;
Jani Alinikulac83c0c42006-06-27 15:00:55 +0200707
708 idx += num_stereo;
709 mixer_ch++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200711 return 0;
712}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
Takashi Iwai723b2b02006-08-30 16:49:54 +0200714static int build_adc_controls(struct snd_akm4xxx *ak)
715{
Pavel Hofman8f346922009-09-16 22:25:36 +0200716 int idx, err, mixer_ch, num_stereo, max_steps;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200717 struct snd_kcontrol_new knew;
718
719 mixer_ch = 0;
Pavel Hofman8f346922009-09-16 22:25:36 +0200720 if (ak->type == SND_AK4528)
721 return 0; /* no controls */
Takashi Iwai723b2b02006-08-30 16:49:54 +0200722 for (idx = 0; idx < ak->num_adcs;) {
723 memset(&knew, 0, sizeof(knew));
724 if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) {
725 knew.name = "ADC Volume";
726 knew.index = mixer_ch + ak->idx_offset * 2;
727 num_stereo = 1;
728 } else {
729 knew.name = ak->adc_info[mixer_ch].name;
730 num_stereo = ak->adc_info[mixer_ch].num_channels;
731 }
732 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
733 knew.count = 1;
734 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
735 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
736 if (num_stereo == 2) {
737 knew.info = snd_akm4xxx_stereo_volume_info;
738 knew.get = snd_akm4xxx_stereo_volume_get;
739 knew.put = snd_akm4xxx_stereo_volume_put;
740 } else {
741 knew.info = snd_akm4xxx_volume_info;
742 knew.get = snd_akm4xxx_volume_get;
743 knew.put = snd_akm4xxx_volume_put;
744 }
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200745 /* register 4 & 5 */
Takashi Iwai854b66e2006-09-08 12:27:38 +0200746 if (ak->type == SND_AK5365)
Pavel Hofman8f346922009-09-16 22:25:36 +0200747 max_steps = 152;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200748 else
Pavel Hofman8f346922009-09-16 22:25:36 +0200749 max_steps = 164;
750 knew.private_value =
751 AK_COMPOSE(idx/2, (idx%2) + 4, 0, max_steps) |
752 AK_VOL_CVT | AK_IPGA;
Takashi Iwai854b66e2006-09-08 12:27:38 +0200753 knew.tlv.p = db_scale_vol_datt;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200754 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
755 if (err < 0)
756 return err;
757
758 if (ak->type == SND_AK5365 && (idx % 2) == 0) {
759 if (! ak->adc_info ||
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200760 ! ak->adc_info[mixer_ch].switch_name) {
Takashi Iwai723b2b02006-08-30 16:49:54 +0200761 knew.name = "Capture Switch";
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200762 knew.index = mixer_ch + ak->idx_offset * 2;
763 } else
Takashi Iwai723b2b02006-08-30 16:49:54 +0200764 knew.name = ak->adc_info[mixer_ch].switch_name;
765 knew.info = ak4xxx_switch_info;
766 knew.get = ak4xxx_switch_get;
767 knew.put = ak4xxx_switch_put;
768 knew.access = 0;
769 /* register 2, bit 0 (SMUTE): 0 = normal operation,
770 1 = mute */
771 knew.private_value =
772 AK_COMPOSE(idx/2, 2, 0, 0) | AK_INVERT;
773 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
774 if (err < 0)
775 return err;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200776
777 memset(&knew, 0, sizeof(knew));
Jia-Ju Bai2127c012019-07-26 10:14:42 +0800778 if (!ak->adc_info ||
779 !ak->adc_info[mixer_ch].selector_name) {
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200780 knew.name = "Capture Channel";
781 knew.index = mixer_ch + ak->idx_offset * 2;
Jia-Ju Bai2127c012019-07-26 10:14:42 +0800782 } else
783 knew.name = ak->adc_info[mixer_ch].selector_name;
Jochen Vossa58e7cb2006-10-04 18:04:10 +0200784
785 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
786 knew.info = ak4xxx_capture_source_info;
787 knew.get = ak4xxx_capture_source_get;
788 knew.put = ak4xxx_capture_source_put;
789 knew.access = 0;
790 /* input selector control: reg. 1, bits 0-2.
791 * mis-use 'shift' to pass mixer_ch */
792 knew.private_value
793 = AK_COMPOSE(idx/2, 1, mixer_ch, 0x07);
794 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
795 if (err < 0)
796 return err;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200797 }
798
799 idx += num_stereo;
800 mixer_ch++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 }
Takashi Iwai723b2b02006-08-30 16:49:54 +0200802 return 0;
803}
Jochen Voss683fe152006-08-08 21:12:44 +0200804
Takashi Iwai723b2b02006-08-30 16:49:54 +0200805static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
806{
807 int idx, err;
808 struct snd_kcontrol_new knew;
Jochen Voss30ba6e22006-08-09 14:26:26 +0200809
Takashi Iwai723b2b02006-08-30 16:49:54 +0200810 for (idx = 0; idx < num_emphs; idx++) {
811 memset(&knew, 0, sizeof(knew));
812 knew.name = "Deemphasis";
813 knew.index = idx + ak->idx_offset;
814 knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
815 knew.count = 1;
816 knew.info = snd_akm4xxx_deemphasis_info;
817 knew.get = snd_akm4xxx_deemphasis_get;
818 knew.put = snd_akm4xxx_deemphasis_put;
819 switch (ak->type) {
820 case SND_AK4524:
821 case SND_AK4528:
Pavel Hofman8f346922009-09-16 22:25:36 +0200822 case SND_AK4620:
Takashi Iwai723b2b02006-08-30 16:49:54 +0200823 /* register 3 */
824 knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
825 break;
826 case SND_AK4529: {
827 int shift = idx == 3 ? 6 : (2 - idx) * 2;
828 /* register 8 with shift */
829 knew.private_value = AK_COMPOSE(0, 8, shift, 0);
830 break;
831 }
832 case SND_AK4355:
833 case SND_AK4358:
834 knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
835 break;
836 case SND_AK4381:
837 knew.private_value = AK_COMPOSE(idx, 1, 1, 0);
838 break;
839 default:
840 return -EINVAL;
841 }
842 err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
Jochen Voss30ba6e22006-08-09 14:26:26 +0200843 if (err < 0)
Takashi Iwai723b2b02006-08-30 16:49:54 +0200844 return err;
845 }
846 return 0;
847}
848
Pavel Hofman8f346922009-09-16 22:25:36 +0200849static void proc_regs_read(struct snd_info_entry *entry,
850 struct snd_info_buffer *buffer)
851{
Joe Perches9fe856e2010-09-04 18:52:54 -0700852 struct snd_akm4xxx *ak = entry->private_data;
Pavel Hofman8f346922009-09-16 22:25:36 +0200853 int reg, val, chip;
854 for (chip = 0; chip < ak->num_chips; chip++) {
855 for (reg = 0; reg < ak->total_regs; reg++) {
856 val = snd_akm4xxx_get(ak, chip, reg);
857 snd_iprintf(buffer, "chip %d: 0x%02x = 0x%02x\n", chip,
858 reg, val);
859 }
860 }
861}
862
863static int proc_init(struct snd_akm4xxx *ak)
864{
Takashi Iwai5a170e92019-02-04 16:00:54 +0100865 return snd_card_ro_proc_new(ak->card, ak->name, ak, proc_regs_read);
Pavel Hofman8f346922009-09-16 22:25:36 +0200866}
Pavel Hofman8f346922009-09-16 22:25:36 +0200867
Takashi Iwai723b2b02006-08-30 16:49:54 +0200868int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
869{
870 int err, num_emphs;
871
872 err = build_dac_controls(ak);
873 if (err < 0)
874 return err;
875
Takashi Iwai854b66e2006-09-08 12:27:38 +0200876 err = build_adc_controls(ak);
877 if (err < 0)
878 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
880 num_emphs = 1;
Pavel Hofman8f346922009-09-16 22:25:36 +0200881 else if (ak->type == SND_AK4620)
882 num_emphs = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 else
884 num_emphs = ak->num_dacs / 2;
Takashi Iwai723b2b02006-08-30 16:49:54 +0200885 err = build_deemphasis(ak, num_emphs);
886 if (err < 0)
887 return err;
Pavel Hofman8f346922009-09-16 22:25:36 +0200888 err = proc_init(ak);
889 if (err < 0)
890 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891
Takashi Iwai723b2b02006-08-30 16:49:54 +0200892 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893}
Takashi Iwaicb9d24e2006-06-27 17:49:12 +0200894EXPORT_SYMBOL(snd_akm4xxx_build_controls);