11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * ALSA driver for AK4524 / AK4528 / AK4529 / AK4355 / AK4358 / AK4381
41da177e4SLinus Torvalds * AD and DA converters
51da177e4SLinus Torvalds *
6c1017a4cSJaroslav Kysela * Copyright (c) 2000-2004 Jaroslav Kysela <perex@perex.cz>,
71da177e4SLinus Torvalds * Takashi Iwai <tiwai@suse.de>
81da177e4SLinus Torvalds */
91da177e4SLinus Torvalds
106cbbfe1cSTakashi Iwai #include <linux/io.h>
111da177e4SLinus Torvalds #include <linux/delay.h>
121da177e4SLinus Torvalds #include <linux/interrupt.h>
131da177e4SLinus Torvalds #include <linux/init.h>
14da155d5bSPaul Gortmaker #include <linux/module.h>
151da177e4SLinus Torvalds #include <sound/core.h>
161da177e4SLinus Torvalds #include <sound/control.h>
17723b2b0dSTakashi Iwai #include <sound/tlv.h>
181da177e4SLinus Torvalds #include <sound/ak4xxx-adda.h>
198f34692fSPavel Hofman #include <sound/info.h>
201da177e4SLinus Torvalds
21c1017a4cSJaroslav Kysela MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>");
221da177e4SLinus Torvalds MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters");
231da177e4SLinus Torvalds MODULE_LICENSE("GPL");
241da177e4SLinus Torvalds
25723b2b0dSTakashi Iwai /* write the given register and save the data to the cache */
snd_akm4xxx_write(struct snd_akm4xxx * ak,int chip,unsigned char reg,unsigned char val)26cb9d24e4STakashi Iwai void snd_akm4xxx_write(struct snd_akm4xxx *ak, int chip, unsigned char reg,
27cb9d24e4STakashi Iwai unsigned char val)
281da177e4SLinus Torvalds {
291da177e4SLinus Torvalds ak->ops.lock(ak, chip);
301da177e4SLinus Torvalds ak->ops.write(ak, chip, reg, val);
311da177e4SLinus Torvalds
321da177e4SLinus Torvalds /* save the data */
331da177e4SLinus Torvalds snd_akm4xxx_set(ak, chip, reg, val);
341da177e4SLinus Torvalds ak->ops.unlock(ak, chip);
351da177e4SLinus Torvalds }
361da177e4SLinus Torvalds
37cb9d24e4STakashi Iwai EXPORT_SYMBOL(snd_akm4xxx_write);
38cb9d24e4STakashi Iwai
39cb9d24e4STakashi Iwai /* reset procedure for AK4524 and AK4528 */
ak4524_reset(struct snd_akm4xxx * ak,int state)40cb9d24e4STakashi Iwai static void ak4524_reset(struct snd_akm4xxx *ak, int state)
41cb9d24e4STakashi Iwai {
42cb9d24e4STakashi Iwai unsigned int chip;
438f34692fSPavel Hofman unsigned char reg;
44cb9d24e4STakashi Iwai
45cb9d24e4STakashi Iwai for (chip = 0; chip < ak->num_dacs/2; chip++) {
46cb9d24e4STakashi Iwai snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03);
47cb9d24e4STakashi Iwai if (state)
48cb9d24e4STakashi Iwai continue;
49cb9d24e4STakashi Iwai /* DAC volumes */
508f34692fSPavel Hofman for (reg = 0x04; reg < ak->total_regs; reg++)
51cb9d24e4STakashi Iwai snd_akm4xxx_write(ak, chip, reg,
52cb9d24e4STakashi Iwai snd_akm4xxx_get(ak, chip, reg));
53cb9d24e4STakashi Iwai }
54cb9d24e4STakashi Iwai }
55cb9d24e4STakashi Iwai
56cb9d24e4STakashi Iwai /* reset procedure for AK4355 and AK4358 */
ak435X_reset(struct snd_akm4xxx * ak,int state)578f34692fSPavel Hofman static void ak435X_reset(struct snd_akm4xxx *ak, int state)
58cb9d24e4STakashi Iwai {
59cb9d24e4STakashi Iwai unsigned char reg;
60cb9d24e4STakashi Iwai
61cb9d24e4STakashi Iwai if (state) {
62cb9d24e4STakashi Iwai snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */
63cb9d24e4STakashi Iwai return;
64cb9d24e4STakashi Iwai }
658f34692fSPavel Hofman for (reg = 0x00; reg < ak->total_regs; reg++)
66cb9d24e4STakashi Iwai if (reg != 0x01)
67cb9d24e4STakashi Iwai snd_akm4xxx_write(ak, 0, reg,
68cb9d24e4STakashi Iwai snd_akm4xxx_get(ak, 0, reg));
69cb9d24e4STakashi Iwai snd_akm4xxx_write(ak, 0, 0x01, 0x01); /* un-reset, unmute */
70cb9d24e4STakashi Iwai }
71cb9d24e4STakashi Iwai
72cb9d24e4STakashi Iwai /* reset procedure for AK4381 */
ak4381_reset(struct snd_akm4xxx * ak,int state)73cb9d24e4STakashi Iwai static void ak4381_reset(struct snd_akm4xxx *ak, int state)
74cb9d24e4STakashi Iwai {
75cb9d24e4STakashi Iwai unsigned int chip;
76cb9d24e4STakashi Iwai unsigned char reg;
77cb9d24e4STakashi Iwai for (chip = 0; chip < ak->num_dacs/2; chip++) {
78cb9d24e4STakashi Iwai snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f);
79cb9d24e4STakashi Iwai if (state)
80cb9d24e4STakashi Iwai continue;
818f34692fSPavel Hofman for (reg = 0x01; reg < ak->total_regs; reg++)
82cb9d24e4STakashi Iwai snd_akm4xxx_write(ak, chip, reg,
83cb9d24e4STakashi Iwai snd_akm4xxx_get(ak, chip, reg));
84cb9d24e4STakashi Iwai }
85cb9d24e4STakashi Iwai }
86cb9d24e4STakashi Iwai
871da177e4SLinus Torvalds /*
881da177e4SLinus Torvalds * reset the AKM codecs
891da177e4SLinus Torvalds * @state: 1 = reset codec, 0 = restore the registers
901da177e4SLinus Torvalds *
911da177e4SLinus Torvalds * assert the reset operation and restores the register values to the chips.
921da177e4SLinus Torvalds */
snd_akm4xxx_reset(struct snd_akm4xxx * ak,int state)9397f02e05STakashi Iwai void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state)
941da177e4SLinus Torvalds {
951da177e4SLinus Torvalds switch (ak->type) {
961da177e4SLinus Torvalds case SND_AK4524:
971da177e4SLinus Torvalds case SND_AK4528:
988f34692fSPavel Hofman case SND_AK4620:
99cb9d24e4STakashi Iwai ak4524_reset(ak, state);
1001da177e4SLinus Torvalds break;
1011da177e4SLinus Torvalds case SND_AK4529:
1021da177e4SLinus Torvalds /* FIXME: needed for ak4529? */
1031da177e4SLinus Torvalds break;
1041da177e4SLinus Torvalds case SND_AK4355:
1058f34692fSPavel Hofman ak435X_reset(ak, state);
106841b23d4SPavel Hofman break;
1071da177e4SLinus Torvalds case SND_AK4358:
1088f34692fSPavel Hofman ak435X_reset(ak, state);
1091da177e4SLinus Torvalds break;
1101da177e4SLinus Torvalds case SND_AK4381:
111cb9d24e4STakashi Iwai ak4381_reset(ak, state);
1121da177e4SLinus Torvalds break;
113cf93907bSTakashi Iwai default:
114cf93907bSTakashi Iwai break;
1151da177e4SLinus Torvalds }
1161da177e4SLinus Torvalds }
1171da177e4SLinus Torvalds
118cb9d24e4STakashi Iwai EXPORT_SYMBOL(snd_akm4xxx_reset);
119cb9d24e4STakashi Iwai
120723b2b0dSTakashi Iwai
121723b2b0dSTakashi Iwai /*
122723b2b0dSTakashi Iwai * Volume conversion table for non-linear volumes
123723b2b0dSTakashi Iwai * from -63.5dB (mute) to 0dB step 0.5dB
124723b2b0dSTakashi Iwai *
1258f34692fSPavel Hofman * Used for AK4524/AK4620 input/ouput attenuation, AK4528, and
126723b2b0dSTakashi Iwai * AK5365 input attenuation
127723b2b0dSTakashi Iwai */
128517400cbSTakashi Iwai static const unsigned char vol_cvt_datt[128] = {
129723b2b0dSTakashi Iwai 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04,
130723b2b0dSTakashi Iwai 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06,
131723b2b0dSTakashi Iwai 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x0a,
132723b2b0dSTakashi Iwai 0x0a, 0x0b, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f,
133723b2b0dSTakashi Iwai 0x10, 0x10, 0x11, 0x12, 0x12, 0x13, 0x13, 0x14,
134723b2b0dSTakashi Iwai 0x15, 0x16, 0x17, 0x17, 0x18, 0x19, 0x1a, 0x1c,
135723b2b0dSTakashi Iwai 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x23,
136723b2b0dSTakashi Iwai 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, 0x2b, 0x2d,
137723b2b0dSTakashi Iwai 0x2e, 0x30, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
138723b2b0dSTakashi Iwai 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3e, 0x3f, 0x40,
139723b2b0dSTakashi Iwai 0x41, 0x42, 0x43, 0x44, 0x46, 0x47, 0x48, 0x4a,
140723b2b0dSTakashi Iwai 0x4b, 0x4d, 0x4e, 0x50, 0x51, 0x52, 0x53, 0x54,
141723b2b0dSTakashi Iwai 0x55, 0x56, 0x58, 0x59, 0x5b, 0x5c, 0x5e, 0x5f,
142723b2b0dSTakashi Iwai 0x60, 0x61, 0x62, 0x64, 0x65, 0x66, 0x67, 0x69,
143723b2b0dSTakashi Iwai 0x6a, 0x6c, 0x6d, 0x6f, 0x70, 0x71, 0x72, 0x73,
144723b2b0dSTakashi Iwai 0x75, 0x76, 0x77, 0x79, 0x7a, 0x7c, 0x7d, 0x7f,
145723b2b0dSTakashi Iwai };
146723b2b0dSTakashi Iwai
147723b2b0dSTakashi Iwai /*
148723b2b0dSTakashi Iwai * dB tables
149723b2b0dSTakashi Iwai */
1500cb29ea0STakashi Iwai static const DECLARE_TLV_DB_SCALE(db_scale_vol_datt, -6350, 50, 1);
1510cb29ea0STakashi Iwai static const DECLARE_TLV_DB_SCALE(db_scale_8bit, -12750, 50, 1);
1520cb29ea0STakashi Iwai static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -6350, 50, 1);
1530cb29ea0STakashi Iwai static const DECLARE_TLV_DB_LINEAR(db_scale_linear, TLV_DB_GAIN_MUTE, 0);
154723b2b0dSTakashi Iwai
1551da177e4SLinus Torvalds /*
1561da177e4SLinus Torvalds * initialize all the ak4xxx chips
1571da177e4SLinus Torvalds */
snd_akm4xxx_init(struct snd_akm4xxx * ak)15897f02e05STakashi Iwai void snd_akm4xxx_init(struct snd_akm4xxx *ak)
1591da177e4SLinus Torvalds {
1600cb29ea0STakashi Iwai static const unsigned char inits_ak4524[] = {
1611da177e4SLinus Torvalds 0x00, 0x07, /* 0: all power up */
1621da177e4SLinus Torvalds 0x01, 0x00, /* 1: ADC/DAC reset */
1631da177e4SLinus Torvalds 0x02, 0x60, /* 2: 24bit I2S */
1641da177e4SLinus Torvalds 0x03, 0x19, /* 3: deemphasis off */
1651da177e4SLinus Torvalds 0x01, 0x03, /* 1: ADC/DAC enable */
1661da177e4SLinus Torvalds 0x04, 0x00, /* 4: ADC left muted */
1671da177e4SLinus Torvalds 0x05, 0x00, /* 5: ADC right muted */
1681da177e4SLinus Torvalds 0x06, 0x00, /* 6: DAC left muted */
1691da177e4SLinus Torvalds 0x07, 0x00, /* 7: DAC right muted */
1701da177e4SLinus Torvalds 0xff, 0xff
1711da177e4SLinus Torvalds };
172517400cbSTakashi Iwai static const unsigned char inits_ak4528[] = {
1731da177e4SLinus Torvalds 0x00, 0x07, /* 0: all power up */
1741da177e4SLinus Torvalds 0x01, 0x00, /* 1: ADC/DAC reset */
1751da177e4SLinus Torvalds 0x02, 0x60, /* 2: 24bit I2S */
1761da177e4SLinus Torvalds 0x03, 0x0d, /* 3: deemphasis off, turn LR highpass filters on */
1771da177e4SLinus Torvalds 0x01, 0x03, /* 1: ADC/DAC enable */
1781da177e4SLinus Torvalds 0x04, 0x00, /* 4: ADC left muted */
1791da177e4SLinus Torvalds 0x05, 0x00, /* 5: ADC right muted */
1801da177e4SLinus Torvalds 0xff, 0xff
1811da177e4SLinus Torvalds };
182517400cbSTakashi Iwai static const unsigned char inits_ak4529[] = {
1831da177e4SLinus Torvalds 0x09, 0x01, /* 9: ATS=0, RSTN=1 */
1841da177e4SLinus Torvalds 0x0a, 0x3f, /* A: all power up, no zero/overflow detection */
1851da177e4SLinus Torvalds 0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */
1861da177e4SLinus Torvalds 0x01, 0x00, /* 1: ACKS=0, ADC, loop off */
1871da177e4SLinus Torvalds 0x02, 0xff, /* 2: LOUT1 muted */
1881da177e4SLinus Torvalds 0x03, 0xff, /* 3: ROUT1 muted */
1891da177e4SLinus Torvalds 0x04, 0xff, /* 4: LOUT2 muted */
1901da177e4SLinus Torvalds 0x05, 0xff, /* 5: ROUT2 muted */
1911da177e4SLinus Torvalds 0x06, 0xff, /* 6: LOUT3 muted */
1921da177e4SLinus Torvalds 0x07, 0xff, /* 7: ROUT3 muted */
1931da177e4SLinus Torvalds 0x0b, 0xff, /* B: LOUT4 muted */
1941da177e4SLinus Torvalds 0x0c, 0xff, /* C: ROUT4 muted */
1951da177e4SLinus Torvalds 0x08, 0x55, /* 8: deemphasis all off */
1961da177e4SLinus Torvalds 0xff, 0xff
1971da177e4SLinus Torvalds };
198517400cbSTakashi Iwai static const unsigned char inits_ak4355[] = {
1991da177e4SLinus Torvalds 0x01, 0x02, /* 1: reset and soft-mute */
200cb9d24e4STakashi Iwai 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
201cb9d24e4STakashi Iwai * disable DZF, sharp roll-off, RSTN#=0 */
2021da177e4SLinus Torvalds 0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */
2031da177e4SLinus Torvalds // 0x02, 0x2e, /* quad speed */
2041da177e4SLinus Torvalds 0x03, 0x01, /* 3: de-emphasis off */
2051da177e4SLinus Torvalds 0x04, 0x00, /* 4: LOUT1 volume muted */
2061da177e4SLinus Torvalds 0x05, 0x00, /* 5: ROUT1 volume muted */
2071da177e4SLinus Torvalds 0x06, 0x00, /* 6: LOUT2 volume muted */
2081da177e4SLinus Torvalds 0x07, 0x00, /* 7: ROUT2 volume muted */
2091da177e4SLinus Torvalds 0x08, 0x00, /* 8: LOUT3 volume muted */
2101da177e4SLinus Torvalds 0x09, 0x00, /* 9: ROUT3 volume muted */
2111da177e4SLinus Torvalds 0x0a, 0x00, /* a: DATT speed=0, ignore DZF */
2121da177e4SLinus Torvalds 0x01, 0x01, /* 1: un-reset, unmute */
2131da177e4SLinus Torvalds 0xff, 0xff
2141da177e4SLinus Torvalds };
215517400cbSTakashi Iwai static const unsigned char inits_ak4358[] = {
2161da177e4SLinus Torvalds 0x01, 0x02, /* 1: reset and soft-mute */
217cb9d24e4STakashi Iwai 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect,
218cb9d24e4STakashi Iwai * disable DZF, sharp roll-off, RSTN#=0 */
21946480b3aSAlexander Beregalov 0x02, 0x4e, /* 2: DA's power up, normal speed, RSTN#=0 */
22046480b3aSAlexander Beregalov /* 0x02, 0x6e,*/ /* quad speed */
2211da177e4SLinus Torvalds 0x03, 0x01, /* 3: de-emphasis off */
2221da177e4SLinus Torvalds 0x04, 0x00, /* 4: LOUT1 volume muted */
2231da177e4SLinus Torvalds 0x05, 0x00, /* 5: ROUT1 volume muted */
2241da177e4SLinus Torvalds 0x06, 0x00, /* 6: LOUT2 volume muted */
2251da177e4SLinus Torvalds 0x07, 0x00, /* 7: ROUT2 volume muted */
2261da177e4SLinus Torvalds 0x08, 0x00, /* 8: LOUT3 volume muted */
2271da177e4SLinus Torvalds 0x09, 0x00, /* 9: ROUT3 volume muted */
2281da177e4SLinus Torvalds 0x0b, 0x00, /* b: LOUT4 volume muted */
2291da177e4SLinus Torvalds 0x0c, 0x00, /* c: ROUT4 volume muted */
2301da177e4SLinus Torvalds 0x0a, 0x00, /* a: DATT speed=0, ignore DZF */
2311da177e4SLinus Torvalds 0x01, 0x01, /* 1: un-reset, unmute */
2321da177e4SLinus Torvalds 0xff, 0xff
2331da177e4SLinus Torvalds };
234517400cbSTakashi Iwai static const unsigned char inits_ak4381[] = {
2351da177e4SLinus Torvalds 0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */
236cb9d24e4STakashi Iwai 0x01, 0x02, /* 1: de-emphasis off, normal speed,
237cb9d24e4STakashi Iwai * sharp roll-off, DZF off */
2381da177e4SLinus Torvalds // 0x01, 0x12, /* quad speed */
2391da177e4SLinus Torvalds 0x02, 0x00, /* 2: DZF disabled */
2401da177e4SLinus Torvalds 0x03, 0x00, /* 3: LATT 0 */
2411da177e4SLinus Torvalds 0x04, 0x00, /* 4: RATT 0 */
2421da177e4SLinus Torvalds 0x00, 0x0f, /* 0: power-up, un-reset */
2431da177e4SLinus Torvalds 0xff, 0xff
2441da177e4SLinus Torvalds };
2458f34692fSPavel Hofman static const unsigned char inits_ak4620[] = {
2468f34692fSPavel Hofman 0x00, 0x07, /* 0: normal */
2478f34692fSPavel Hofman 0x01, 0x00, /* 0: reset */
2488f34692fSPavel Hofman 0x01, 0x02, /* 1: RSTAD */
2498f34692fSPavel Hofman 0x01, 0x03, /* 1: RSTDA */
2508f34692fSPavel Hofman 0x01, 0x0f, /* 1: normal */
2518f34692fSPavel Hofman 0x02, 0x60, /* 2: 24bit I2S */
2528f34692fSPavel Hofman 0x03, 0x01, /* 3: deemphasis off */
2538f34692fSPavel Hofman 0x04, 0x00, /* 4: LIN muted */
2548f34692fSPavel Hofman 0x05, 0x00, /* 5: RIN muted */
2558f34692fSPavel Hofman 0x06, 0x00, /* 6: LOUT muted */
2568f34692fSPavel Hofman 0x07, 0x00, /* 7: ROUT muted */
2578f34692fSPavel Hofman 0xff, 0xff
2588f34692fSPavel Hofman };
2591da177e4SLinus Torvalds
2608f34692fSPavel Hofman int chip;
261517400cbSTakashi Iwai const unsigned char *ptr, *inits;
262517400cbSTakashi Iwai unsigned char reg, data;
2631da177e4SLinus Torvalds
264723b2b0dSTakashi Iwai memset(ak->images, 0, sizeof(ak->images));
265723b2b0dSTakashi Iwai memset(ak->volumes, 0, sizeof(ak->volumes));
266723b2b0dSTakashi Iwai
2671da177e4SLinus Torvalds switch (ak->type) {
2681da177e4SLinus Torvalds case SND_AK4524:
2691da177e4SLinus Torvalds inits = inits_ak4524;
2708f34692fSPavel Hofman ak->num_chips = ak->num_dacs / 2;
2718f34692fSPavel Hofman ak->name = "ak4524";
2728f34692fSPavel Hofman ak->total_regs = 0x08;
2731da177e4SLinus Torvalds break;
2741da177e4SLinus Torvalds case SND_AK4528:
2751da177e4SLinus Torvalds inits = inits_ak4528;
2768f34692fSPavel Hofman ak->num_chips = ak->num_dacs / 2;
2778f34692fSPavel Hofman ak->name = "ak4528";
2788f34692fSPavel Hofman ak->total_regs = 0x06;
2791da177e4SLinus Torvalds break;
2801da177e4SLinus Torvalds case SND_AK4529:
2811da177e4SLinus Torvalds inits = inits_ak4529;
2828f34692fSPavel Hofman ak->num_chips = 1;
2838f34692fSPavel Hofman ak->name = "ak4529";
2848f34692fSPavel Hofman ak->total_regs = 0x0d;
2851da177e4SLinus Torvalds break;
2861da177e4SLinus Torvalds case SND_AK4355:
2871da177e4SLinus Torvalds inits = inits_ak4355;
2888f34692fSPavel Hofman ak->num_chips = 1;
2898f34692fSPavel Hofman ak->name = "ak4355";
2908f34692fSPavel Hofman ak->total_regs = 0x0b;
2911da177e4SLinus Torvalds break;
2921da177e4SLinus Torvalds case SND_AK4358:
2931da177e4SLinus Torvalds inits = inits_ak4358;
2948f34692fSPavel Hofman ak->num_chips = 1;
2958f34692fSPavel Hofman ak->name = "ak4358";
2968f34692fSPavel Hofman ak->total_regs = 0x10;
2971da177e4SLinus Torvalds break;
2981da177e4SLinus Torvalds case SND_AK4381:
2991da177e4SLinus Torvalds inits = inits_ak4381;
3008f34692fSPavel Hofman ak->num_chips = ak->num_dacs / 2;
3018f34692fSPavel Hofman ak->name = "ak4381";
3028f34692fSPavel Hofman ak->total_regs = 0x05;
3031da177e4SLinus Torvalds break;
304723b2b0dSTakashi Iwai case SND_AK5365:
305723b2b0dSTakashi Iwai /* FIXME: any init sequence? */
3068f34692fSPavel Hofman ak->num_chips = 1;
3078f34692fSPavel Hofman ak->name = "ak5365";
3088f34692fSPavel Hofman ak->total_regs = 0x08;
309723b2b0dSTakashi Iwai return;
3108f34692fSPavel Hofman case SND_AK4620:
3118f34692fSPavel Hofman inits = inits_ak4620;
3128f34692fSPavel Hofman ak->num_chips = ak->num_dacs / 2;
3138f34692fSPavel Hofman ak->name = "ak4620";
3148f34692fSPavel Hofman ak->total_regs = 0x08;
3158f34692fSPavel Hofman break;
3161da177e4SLinus Torvalds default:
3171da177e4SLinus Torvalds snd_BUG();
3181da177e4SLinus Torvalds return;
3191da177e4SLinus Torvalds }
3201da177e4SLinus Torvalds
3218f34692fSPavel Hofman for (chip = 0; chip < ak->num_chips; chip++) {
3221da177e4SLinus Torvalds ptr = inits;
3231da177e4SLinus Torvalds while (*ptr != 0xff) {
3241da177e4SLinus Torvalds reg = *ptr++;
3251da177e4SLinus Torvalds data = *ptr++;
3261da177e4SLinus Torvalds snd_akm4xxx_write(ak, chip, reg, data);
3278f34692fSPavel Hofman udelay(10);
3281da177e4SLinus Torvalds }
3291da177e4SLinus Torvalds }
3301da177e4SLinus Torvalds }
3311da177e4SLinus Torvalds
332cb9d24e4STakashi Iwai EXPORT_SYMBOL(snd_akm4xxx_init);
333cb9d24e4STakashi Iwai
334723b2b0dSTakashi Iwai /*
335723b2b0dSTakashi Iwai * Mixer callbacks
336723b2b0dSTakashi Iwai */
337854b66e4STakashi Iwai #define AK_IPGA (1<<20) /* including IPGA */
338723b2b0dSTakashi Iwai #define AK_VOL_CVT (1<<21) /* need dB conversion */
339723b2b0dSTakashi Iwai #define AK_NEEDSMSB (1<<22) /* need MSB update bit */
340723b2b0dSTakashi Iwai #define AK_INVERT (1<<23) /* data is inverted */
3411da177e4SLinus Torvalds #define AK_GET_CHIP(val) (((val) >> 8) & 0xff)
3421da177e4SLinus Torvalds #define AK_GET_ADDR(val) ((val) & 0xff)
343854b66e4STakashi Iwai #define AK_GET_SHIFT(val) (((val) >> 16) & 0x0f)
344723b2b0dSTakashi Iwai #define AK_GET_VOL_CVT(val) (((val) >> 21) & 1)
345854b66e4STakashi Iwai #define AK_GET_IPGA(val) (((val) >> 20) & 1)
3463479307fSJochen Voss #define AK_GET_NEEDSMSB(val) (((val) >> 22) & 1)
3471da177e4SLinus Torvalds #define AK_GET_INVERT(val) (((val) >> 23) & 1)
3481da177e4SLinus Torvalds #define AK_GET_MASK(val) (((val) >> 24) & 0xff)
349cb9d24e4STakashi Iwai #define AK_COMPOSE(chip,addr,shift,mask) \
350cb9d24e4STakashi Iwai (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24))
3511da177e4SLinus Torvalds
snd_akm4xxx_volume_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)35297f02e05STakashi Iwai static int snd_akm4xxx_volume_info(struct snd_kcontrol *kcontrol,
35397f02e05STakashi Iwai struct snd_ctl_elem_info *uinfo)
3541da177e4SLinus Torvalds {
3551da177e4SLinus Torvalds unsigned int mask = AK_GET_MASK(kcontrol->private_value);
3561da177e4SLinus Torvalds
3571da177e4SLinus Torvalds uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
3581da177e4SLinus Torvalds uinfo->count = 1;
3591da177e4SLinus Torvalds uinfo->value.integer.min = 0;
3601da177e4SLinus Torvalds uinfo->value.integer.max = mask;
3611da177e4SLinus Torvalds return 0;
3621da177e4SLinus Torvalds }
3631da177e4SLinus Torvalds
snd_akm4xxx_volume_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)36497f02e05STakashi Iwai static int snd_akm4xxx_volume_get(struct snd_kcontrol *kcontrol,
36597f02e05STakashi Iwai struct snd_ctl_elem_value *ucontrol)
3661da177e4SLinus Torvalds {
36797f02e05STakashi Iwai struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
3681da177e4SLinus Torvalds int chip = AK_GET_CHIP(kcontrol->private_value);
3691da177e4SLinus Torvalds int addr = AK_GET_ADDR(kcontrol->private_value);
3701da177e4SLinus Torvalds
371723b2b0dSTakashi Iwai ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
3721da177e4SLinus Torvalds return 0;
3731da177e4SLinus Torvalds }
3741da177e4SLinus Torvalds
put_ak_reg(struct snd_kcontrol * kcontrol,int addr,unsigned char nval)375723b2b0dSTakashi Iwai static int put_ak_reg(struct snd_kcontrol *kcontrol, int addr,
376723b2b0dSTakashi Iwai unsigned char nval)
377723b2b0dSTakashi Iwai {
378723b2b0dSTakashi Iwai struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
379723b2b0dSTakashi Iwai unsigned int mask = AK_GET_MASK(kcontrol->private_value);
380723b2b0dSTakashi Iwai int chip = AK_GET_CHIP(kcontrol->private_value);
381723b2b0dSTakashi Iwai
382723b2b0dSTakashi Iwai if (snd_akm4xxx_get_vol(ak, chip, addr) == nval)
383723b2b0dSTakashi Iwai return 0;
384723b2b0dSTakashi Iwai
385723b2b0dSTakashi Iwai snd_akm4xxx_set_vol(ak, chip, addr, nval);
386854b66e4STakashi Iwai if (AK_GET_VOL_CVT(kcontrol->private_value) && nval < 128)
387723b2b0dSTakashi Iwai nval = vol_cvt_datt[nval];
388854b66e4STakashi Iwai if (AK_GET_IPGA(kcontrol->private_value) && nval >= 128)
389854b66e4STakashi Iwai nval++; /* need to correct + 1 since both 127 and 128 are 0dB */
390723b2b0dSTakashi Iwai if (AK_GET_INVERT(kcontrol->private_value))
391723b2b0dSTakashi Iwai nval = mask - nval;
392723b2b0dSTakashi Iwai if (AK_GET_NEEDSMSB(kcontrol->private_value))
393723b2b0dSTakashi Iwai nval |= 0x80;
394841b23d4SPavel Hofman /* printk(KERN_DEBUG "DEBUG - AK writing reg: chip %x addr %x,
395841b23d4SPavel Hofman nval %x\n", chip, addr, nval); */
396723b2b0dSTakashi Iwai snd_akm4xxx_write(ak, chip, addr, nval);
397723b2b0dSTakashi Iwai return 1;
398723b2b0dSTakashi Iwai }
399723b2b0dSTakashi Iwai
snd_akm4xxx_volume_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)40097f02e05STakashi Iwai static int snd_akm4xxx_volume_put(struct snd_kcontrol *kcontrol,
40197f02e05STakashi Iwai struct snd_ctl_elem_value *ucontrol)
4021da177e4SLinus Torvalds {
40302ff1324STakashi Iwai unsigned int mask = AK_GET_MASK(kcontrol->private_value);
40402ff1324STakashi Iwai unsigned int val = ucontrol->value.integer.value[0];
40502ff1324STakashi Iwai if (val > mask)
40602ff1324STakashi Iwai return -EINVAL;
40702ff1324STakashi Iwai return put_ak_reg(kcontrol, AK_GET_ADDR(kcontrol->private_value), val);
4081da177e4SLinus Torvalds }
4091da177e4SLinus Torvalds
snd_akm4xxx_stereo_volume_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)410c83c0c47SJani Alinikula static int snd_akm4xxx_stereo_volume_info(struct snd_kcontrol *kcontrol,
411c83c0c47SJani Alinikula struct snd_ctl_elem_info *uinfo)
412c83c0c47SJani Alinikula {
413c83c0c47SJani Alinikula unsigned int mask = AK_GET_MASK(kcontrol->private_value);
414c83c0c47SJani Alinikula
415c83c0c47SJani Alinikula uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
416c83c0c47SJani Alinikula uinfo->count = 2;
417c83c0c47SJani Alinikula uinfo->value.integer.min = 0;
418c83c0c47SJani Alinikula uinfo->value.integer.max = mask;
419c83c0c47SJani Alinikula return 0;
420c83c0c47SJani Alinikula }
421c83c0c47SJani Alinikula
snd_akm4xxx_stereo_volume_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)422c83c0c47SJani Alinikula static int snd_akm4xxx_stereo_volume_get(struct snd_kcontrol *kcontrol,
423c83c0c47SJani Alinikula struct snd_ctl_elem_value *ucontrol)
424c83c0c47SJani Alinikula {
425c83c0c47SJani Alinikula struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
426c83c0c47SJani Alinikula int chip = AK_GET_CHIP(kcontrol->private_value);
427c83c0c47SJani Alinikula int addr = AK_GET_ADDR(kcontrol->private_value);
428c83c0c47SJani Alinikula
429723b2b0dSTakashi Iwai ucontrol->value.integer.value[0] = snd_akm4xxx_get_vol(ak, chip, addr);
430723b2b0dSTakashi Iwai ucontrol->value.integer.value[1] = snd_akm4xxx_get_vol(ak, chip, addr+1);
431c83c0c47SJani Alinikula return 0;
432c83c0c47SJani Alinikula }
433c83c0c47SJani Alinikula
snd_akm4xxx_stereo_volume_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)434c83c0c47SJani Alinikula static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
435c83c0c47SJani Alinikula struct snd_ctl_elem_value *ucontrol)
436c83c0c47SJani Alinikula {
437c83c0c47SJani Alinikula int addr = AK_GET_ADDR(kcontrol->private_value);
43802ff1324STakashi Iwai unsigned int mask = AK_GET_MASK(kcontrol->private_value);
43902ff1324STakashi Iwai unsigned int val[2];
440723b2b0dSTakashi Iwai int change;
441c83c0c47SJani Alinikula
44202ff1324STakashi Iwai val[0] = ucontrol->value.integer.value[0];
44302ff1324STakashi Iwai val[1] = ucontrol->value.integer.value[1];
44402ff1324STakashi Iwai if (val[0] > mask || val[1] > mask)
44502ff1324STakashi Iwai return -EINVAL;
44602ff1324STakashi Iwai change = put_ak_reg(kcontrol, addr, val[0]);
44702ff1324STakashi Iwai change |= put_ak_reg(kcontrol, addr + 1, val[1]);
448723b2b0dSTakashi Iwai return change;
449c83c0c47SJani Alinikula }
450c83c0c47SJani Alinikula
snd_akm4xxx_deemphasis_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)45197f02e05STakashi Iwai static int snd_akm4xxx_deemphasis_info(struct snd_kcontrol *kcontrol,
45297f02e05STakashi Iwai struct snd_ctl_elem_info *uinfo)
4531da177e4SLinus Torvalds {
454609e478bSTakashi Iwai static const char * const texts[4] = {
4551da177e4SLinus Torvalds "44.1kHz", "Off", "48kHz", "32kHz",
4561da177e4SLinus Torvalds };
457609e478bSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, 4, texts);
4581da177e4SLinus Torvalds }
4591da177e4SLinus Torvalds
snd_akm4xxx_deemphasis_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)46097f02e05STakashi Iwai static int snd_akm4xxx_deemphasis_get(struct snd_kcontrol *kcontrol,
46197f02e05STakashi Iwai struct snd_ctl_elem_value *ucontrol)
4621da177e4SLinus Torvalds {
46397f02e05STakashi Iwai struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
4641da177e4SLinus Torvalds int chip = AK_GET_CHIP(kcontrol->private_value);
4651da177e4SLinus Torvalds int addr = AK_GET_ADDR(kcontrol->private_value);
4661da177e4SLinus Torvalds int shift = AK_GET_SHIFT(kcontrol->private_value);
467cb9d24e4STakashi Iwai ucontrol->value.enumerated.item[0] =
468cb9d24e4STakashi Iwai (snd_akm4xxx_get(ak, chip, addr) >> shift) & 3;
4691da177e4SLinus Torvalds return 0;
4701da177e4SLinus Torvalds }
4711da177e4SLinus Torvalds
snd_akm4xxx_deemphasis_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)47297f02e05STakashi Iwai static int snd_akm4xxx_deemphasis_put(struct snd_kcontrol *kcontrol,
47397f02e05STakashi Iwai struct snd_ctl_elem_value *ucontrol)
4741da177e4SLinus Torvalds {
47597f02e05STakashi Iwai struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
4761da177e4SLinus Torvalds int chip = AK_GET_CHIP(kcontrol->private_value);
4771da177e4SLinus Torvalds int addr = AK_GET_ADDR(kcontrol->private_value);
4781da177e4SLinus Torvalds int shift = AK_GET_SHIFT(kcontrol->private_value);
4791da177e4SLinus Torvalds unsigned char nval = ucontrol->value.enumerated.item[0] & 3;
4801da177e4SLinus Torvalds int change;
4811da177e4SLinus Torvalds
482cb9d24e4STakashi Iwai nval = (nval << shift) |
483cb9d24e4STakashi Iwai (snd_akm4xxx_get(ak, chip, addr) & ~(3 << shift));
4841da177e4SLinus Torvalds change = snd_akm4xxx_get(ak, chip, addr) != nval;
4851da177e4SLinus Torvalds if (change)
4861da177e4SLinus Torvalds snd_akm4xxx_write(ak, chip, addr, nval);
4871da177e4SLinus Torvalds return change;
4881da177e4SLinus Torvalds }
4891da177e4SLinus Torvalds
490a5ce8890STakashi Iwai #define ak4xxx_switch_info snd_ctl_boolean_mono_info
49130ba6e20SJochen Voss
ak4xxx_switch_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)49230ba6e20SJochen Voss static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol,
49330ba6e20SJochen Voss struct snd_ctl_elem_value *ucontrol)
49430ba6e20SJochen Voss {
49530ba6e20SJochen Voss struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
49630ba6e20SJochen Voss int chip = AK_GET_CHIP(kcontrol->private_value);
49730ba6e20SJochen Voss int addr = AK_GET_ADDR(kcontrol->private_value);
49830ba6e20SJochen Voss int shift = AK_GET_SHIFT(kcontrol->private_value);
49930ba6e20SJochen Voss int invert = AK_GET_INVERT(kcontrol->private_value);
500ea7cfcdfSPavel Hofman /* we observe the (1<<shift) bit only */
501ea7cfcdfSPavel Hofman unsigned char val = snd_akm4xxx_get(ak, chip, addr) & (1<<shift);
50230ba6e20SJochen Voss if (invert)
50330ba6e20SJochen Voss val = ! val;
50430ba6e20SJochen Voss ucontrol->value.integer.value[0] = (val & (1<<shift)) != 0;
50530ba6e20SJochen Voss return 0;
50630ba6e20SJochen Voss }
50730ba6e20SJochen Voss
ak4xxx_switch_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)50830ba6e20SJochen Voss static int ak4xxx_switch_put(struct snd_kcontrol *kcontrol,
50930ba6e20SJochen Voss struct snd_ctl_elem_value *ucontrol)
51030ba6e20SJochen Voss {
51130ba6e20SJochen Voss struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
51230ba6e20SJochen Voss int chip = AK_GET_CHIP(kcontrol->private_value);
51330ba6e20SJochen Voss int addr = AK_GET_ADDR(kcontrol->private_value);
51430ba6e20SJochen Voss int shift = AK_GET_SHIFT(kcontrol->private_value);
51530ba6e20SJochen Voss int invert = AK_GET_INVERT(kcontrol->private_value);
51630ba6e20SJochen Voss long flag = ucontrol->value.integer.value[0];
51730ba6e20SJochen Voss unsigned char val, oval;
51830ba6e20SJochen Voss int change;
51930ba6e20SJochen Voss
52030ba6e20SJochen Voss if (invert)
52130ba6e20SJochen Voss flag = ! flag;
52230ba6e20SJochen Voss oval = snd_akm4xxx_get(ak, chip, addr);
52330ba6e20SJochen Voss if (flag)
52430ba6e20SJochen Voss val = oval | (1<<shift);
52530ba6e20SJochen Voss else
52630ba6e20SJochen Voss val = oval & ~(1<<shift);
52730ba6e20SJochen Voss change = (oval != val);
52830ba6e20SJochen Voss if (change)
52930ba6e20SJochen Voss snd_akm4xxx_write(ak, chip, addr, val);
53030ba6e20SJochen Voss return change;
53130ba6e20SJochen Voss }
53230ba6e20SJochen Voss
533a58e7cb1SJochen Voss #define AK5365_NUM_INPUTS 5
534a58e7cb1SJochen Voss
ak4xxx_capture_num_inputs(struct snd_akm4xxx * ak,int mixer_ch)53502ff1324STakashi Iwai static int ak4xxx_capture_num_inputs(struct snd_akm4xxx *ak, int mixer_ch)
53602ff1324STakashi Iwai {
53702ff1324STakashi Iwai int num_names;
53802ff1324STakashi Iwai const char **input_names;
53902ff1324STakashi Iwai
54002ff1324STakashi Iwai input_names = ak->adc_info[mixer_ch].input_names;
54102ff1324STakashi Iwai num_names = 0;
54202ff1324STakashi Iwai while (num_names < AK5365_NUM_INPUTS && input_names[num_names])
54302ff1324STakashi Iwai ++num_names;
54402ff1324STakashi Iwai return num_names;
54502ff1324STakashi Iwai }
54602ff1324STakashi Iwai
ak4xxx_capture_source_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)547a58e7cb1SJochen Voss static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
548a58e7cb1SJochen Voss struct snd_ctl_elem_info *uinfo)
549a58e7cb1SJochen Voss {
550a58e7cb1SJochen Voss struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
551a58e7cb1SJochen Voss int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
552609e478bSTakashi Iwai unsigned int num_names;
553a58e7cb1SJochen Voss
55402ff1324STakashi Iwai num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
55502ff1324STakashi Iwai if (!num_names)
55602ff1324STakashi Iwai return -EINVAL;
557609e478bSTakashi Iwai return snd_ctl_enum_info(uinfo, 1, num_names,
558609e478bSTakashi Iwai ak->adc_info[mixer_ch].input_names);
559a58e7cb1SJochen Voss }
560a58e7cb1SJochen Voss
ak4xxx_capture_source_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)561a58e7cb1SJochen Voss static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol,
562a58e7cb1SJochen Voss struct snd_ctl_elem_value *ucontrol)
563a58e7cb1SJochen Voss {
564a58e7cb1SJochen Voss struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
565a58e7cb1SJochen Voss int chip = AK_GET_CHIP(kcontrol->private_value);
566a58e7cb1SJochen Voss int addr = AK_GET_ADDR(kcontrol->private_value);
567a58e7cb1SJochen Voss int mask = AK_GET_MASK(kcontrol->private_value);
568a58e7cb1SJochen Voss unsigned char val;
569a58e7cb1SJochen Voss
570a58e7cb1SJochen Voss val = snd_akm4xxx_get(ak, chip, addr) & mask;
571a58e7cb1SJochen Voss ucontrol->value.enumerated.item[0] = val;
572a58e7cb1SJochen Voss return 0;
573a58e7cb1SJochen Voss }
574a58e7cb1SJochen Voss
ak4xxx_capture_source_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)575a58e7cb1SJochen Voss static int ak4xxx_capture_source_put(struct snd_kcontrol *kcontrol,
576a58e7cb1SJochen Voss struct snd_ctl_elem_value *ucontrol)
577a58e7cb1SJochen Voss {
578a58e7cb1SJochen Voss struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
57902ff1324STakashi Iwai int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
580a58e7cb1SJochen Voss int chip = AK_GET_CHIP(kcontrol->private_value);
581a58e7cb1SJochen Voss int addr = AK_GET_ADDR(kcontrol->private_value);
582a58e7cb1SJochen Voss int mask = AK_GET_MASK(kcontrol->private_value);
583a58e7cb1SJochen Voss unsigned char oval, val;
58402ff1324STakashi Iwai int num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
58502ff1324STakashi Iwai
58602ff1324STakashi Iwai if (ucontrol->value.enumerated.item[0] >= num_names)
58702ff1324STakashi Iwai return -EINVAL;
588a58e7cb1SJochen Voss
589a58e7cb1SJochen Voss oval = snd_akm4xxx_get(ak, chip, addr);
590a58e7cb1SJochen Voss val = oval & ~mask;
591a58e7cb1SJochen Voss val |= ucontrol->value.enumerated.item[0] & mask;
592a58e7cb1SJochen Voss if (val != oval) {
593a58e7cb1SJochen Voss snd_akm4xxx_write(ak, chip, addr, val);
594a58e7cb1SJochen Voss return 1;
595a58e7cb1SJochen Voss }
596a58e7cb1SJochen Voss return 0;
597a58e7cb1SJochen Voss }
598a58e7cb1SJochen Voss
5991da177e4SLinus Torvalds /*
6001da177e4SLinus Torvalds * build AK4xxx controls
6011da177e4SLinus Torvalds */
6021da177e4SLinus Torvalds
build_dac_controls(struct snd_akm4xxx * ak)603723b2b0dSTakashi Iwai static int build_dac_controls(struct snd_akm4xxx *ak)
6041da177e4SLinus Torvalds {
605723b2b0dSTakashi Iwai int idx, err, mixer_ch, num_stereo;
606723b2b0dSTakashi Iwai struct snd_kcontrol_new knew;
6071da177e4SLinus Torvalds
608723b2b0dSTakashi Iwai mixer_ch = 0;
609c83c0c47SJani Alinikula for (idx = 0; idx < ak->num_dacs; ) {
610ea7cfcdfSPavel Hofman /* mute control for Revolution 7.1 - AK4381 */
611ea7cfcdfSPavel Hofman if (ak->type == SND_AK4381
612ea7cfcdfSPavel Hofman && ak->dac_info[mixer_ch].switch_name) {
613ea7cfcdfSPavel Hofman memset(&knew, 0, sizeof(knew));
614ea7cfcdfSPavel Hofman knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
615ea7cfcdfSPavel Hofman knew.count = 1;
616ea7cfcdfSPavel Hofman knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
617ea7cfcdfSPavel Hofman knew.name = ak->dac_info[mixer_ch].switch_name;
618ea7cfcdfSPavel Hofman knew.info = ak4xxx_switch_info;
619ea7cfcdfSPavel Hofman knew.get = ak4xxx_switch_get;
620ea7cfcdfSPavel Hofman knew.put = ak4xxx_switch_put;
621ea7cfcdfSPavel Hofman knew.access = 0;
622ea7cfcdfSPavel Hofman /* register 1, bit 0 (SMUTE): 0 = normal operation,
623ea7cfcdfSPavel Hofman 1 = mute */
624ea7cfcdfSPavel Hofman knew.private_value =
625ea7cfcdfSPavel Hofman AK_COMPOSE(idx/2, 1, 0, 0) | AK_INVERT;
626ea7cfcdfSPavel Hofman err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
627ea7cfcdfSPavel Hofman if (err < 0)
628ea7cfcdfSPavel Hofman return err;
629ea7cfcdfSPavel Hofman }
630723b2b0dSTakashi Iwai memset(&knew, 0, sizeof(knew));
631723b2b0dSTakashi Iwai if (! ak->dac_info || ! ak->dac_info[mixer_ch].name) {
632723b2b0dSTakashi Iwai knew.name = "DAC Volume";
633723b2b0dSTakashi Iwai knew.index = mixer_ch + ak->idx_offset * 2;
634c83c0c47SJani Alinikula num_stereo = 1;
635c83c0c47SJani Alinikula } else {
636723b2b0dSTakashi Iwai knew.name = ak->dac_info[mixer_ch].name;
637723b2b0dSTakashi Iwai num_stereo = ak->dac_info[mixer_ch].num_channels;
638c83c0c47SJani Alinikula }
639723b2b0dSTakashi Iwai knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
640723b2b0dSTakashi Iwai knew.count = 1;
641723b2b0dSTakashi Iwai knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
642723b2b0dSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_READ;
643c83c0c47SJani Alinikula if (num_stereo == 2) {
644723b2b0dSTakashi Iwai knew.info = snd_akm4xxx_stereo_volume_info;
645723b2b0dSTakashi Iwai knew.get = snd_akm4xxx_stereo_volume_get;
646723b2b0dSTakashi Iwai knew.put = snd_akm4xxx_stereo_volume_put;
647c83c0c47SJani Alinikula } else {
648723b2b0dSTakashi Iwai knew.info = snd_akm4xxx_volume_info;
649723b2b0dSTakashi Iwai knew.get = snd_akm4xxx_volume_get;
650723b2b0dSTakashi Iwai knew.put = snd_akm4xxx_volume_put;
651c83c0c47SJani Alinikula }
6521da177e4SLinus Torvalds switch (ak->type) {
6531da177e4SLinus Torvalds case SND_AK4524:
654cb9d24e4STakashi Iwai /* register 6 & 7 */
655723b2b0dSTakashi Iwai knew.private_value =
656723b2b0dSTakashi Iwai AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127) |
657723b2b0dSTakashi Iwai AK_VOL_CVT;
658723b2b0dSTakashi Iwai knew.tlv.p = db_scale_vol_datt;
6591da177e4SLinus Torvalds break;
6601da177e4SLinus Torvalds case SND_AK4528:
661cb9d24e4STakashi Iwai /* register 4 & 5 */
662723b2b0dSTakashi Iwai knew.private_value =
663723b2b0dSTakashi Iwai AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127) |
664723b2b0dSTakashi Iwai AK_VOL_CVT;
665723b2b0dSTakashi Iwai knew.tlv.p = db_scale_vol_datt;
6661da177e4SLinus Torvalds break;
6671da177e4SLinus Torvalds case SND_AK4529: {
668cb9d24e4STakashi Iwai /* registers 2-7 and b,c */
669cb9d24e4STakashi Iwai int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb;
670723b2b0dSTakashi Iwai knew.private_value =
671cb9d24e4STakashi Iwai AK_COMPOSE(0, val, 0, 255) | AK_INVERT;
672723b2b0dSTakashi Iwai knew.tlv.p = db_scale_8bit;
6731da177e4SLinus Torvalds break;
6741da177e4SLinus Torvalds }
6751da177e4SLinus Torvalds case SND_AK4355:
676cb9d24e4STakashi Iwai /* register 4-9, chip #0 only */
677723b2b0dSTakashi Iwai knew.private_value = AK_COMPOSE(0, idx + 4, 0, 255);
678723b2b0dSTakashi Iwai knew.tlv.p = db_scale_8bit;
6791da177e4SLinus Torvalds break;
6803479307fSJochen Voss case SND_AK4358: {
6813479307fSJochen Voss /* register 4-9 and 11-12, chip #0 only */
6823479307fSJochen Voss int addr = idx < 6 ? idx + 4 : idx + 5;
683723b2b0dSTakashi Iwai knew.private_value =
6843479307fSJochen Voss AK_COMPOSE(0, addr, 0, 127) | AK_NEEDSMSB;
685723b2b0dSTakashi Iwai knew.tlv.p = db_scale_7bit;
6861da177e4SLinus Torvalds break;
6873479307fSJochen Voss }
6881da177e4SLinus Torvalds case SND_AK4381:
689cb9d24e4STakashi Iwai /* register 3 & 4 */
690723b2b0dSTakashi Iwai knew.private_value =
691cb9d24e4STakashi Iwai AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255);
692723b2b0dSTakashi Iwai knew.tlv.p = db_scale_linear;
6931da177e4SLinus Torvalds break;
6948f34692fSPavel Hofman case SND_AK4620:
6958f34692fSPavel Hofman /* register 6 & 7 */
6968f34692fSPavel Hofman knew.private_value =
6978f34692fSPavel Hofman AK_COMPOSE(idx/2, (idx%2) + 6, 0, 255);
6988f34692fSPavel Hofman knew.tlv.p = db_scale_linear;
6998f34692fSPavel Hofman break;
7001da177e4SLinus Torvalds default:
701723b2b0dSTakashi Iwai return -EINVAL;
7021da177e4SLinus Torvalds }
703c83c0c47SJani Alinikula
704723b2b0dSTakashi Iwai err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
705cb9d24e4STakashi Iwai if (err < 0)
706723b2b0dSTakashi Iwai return err;
707c83c0c47SJani Alinikula
708c83c0c47SJani Alinikula idx += num_stereo;
709c83c0c47SJani Alinikula mixer_ch++;
7101da177e4SLinus Torvalds }
711723b2b0dSTakashi Iwai return 0;
7121da177e4SLinus Torvalds }
713683fe153SJochen Voss
build_adc_controls(struct snd_akm4xxx * ak)714723b2b0dSTakashi Iwai static int build_adc_controls(struct snd_akm4xxx *ak)
715723b2b0dSTakashi Iwai {
7168f34692fSPavel Hofman int idx, err, mixer_ch, num_stereo, max_steps;
717723b2b0dSTakashi Iwai struct snd_kcontrol_new knew;
71830ba6e20SJochen Voss
719723b2b0dSTakashi Iwai mixer_ch = 0;
7208f34692fSPavel Hofman if (ak->type == SND_AK4528)
7218f34692fSPavel Hofman return 0; /* no controls */
722723b2b0dSTakashi Iwai for (idx = 0; idx < ak->num_adcs;) {
723723b2b0dSTakashi Iwai memset(&knew, 0, sizeof(knew));
724723b2b0dSTakashi Iwai if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) {
725723b2b0dSTakashi Iwai knew.name = "ADC Volume";
726723b2b0dSTakashi Iwai knew.index = mixer_ch + ak->idx_offset * 2;
727723b2b0dSTakashi Iwai num_stereo = 1;
728723b2b0dSTakashi Iwai } else {
729723b2b0dSTakashi Iwai knew.name = ak->adc_info[mixer_ch].name;
730723b2b0dSTakashi Iwai num_stereo = ak->adc_info[mixer_ch].num_channels;
731723b2b0dSTakashi Iwai }
732723b2b0dSTakashi Iwai knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
733723b2b0dSTakashi Iwai knew.count = 1;
734723b2b0dSTakashi Iwai knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
735723b2b0dSTakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_READ;
736723b2b0dSTakashi Iwai if (num_stereo == 2) {
737723b2b0dSTakashi Iwai knew.info = snd_akm4xxx_stereo_volume_info;
738723b2b0dSTakashi Iwai knew.get = snd_akm4xxx_stereo_volume_get;
739723b2b0dSTakashi Iwai knew.put = snd_akm4xxx_stereo_volume_put;
740723b2b0dSTakashi Iwai } else {
741723b2b0dSTakashi Iwai knew.info = snd_akm4xxx_volume_info;
742723b2b0dSTakashi Iwai knew.get = snd_akm4xxx_volume_get;
743723b2b0dSTakashi Iwai knew.put = snd_akm4xxx_volume_put;
744723b2b0dSTakashi Iwai }
745723b2b0dSTakashi Iwai /* register 4 & 5 */
746854b66e4STakashi Iwai if (ak->type == SND_AK5365)
7478f34692fSPavel Hofman max_steps = 152;
748723b2b0dSTakashi Iwai else
7498f34692fSPavel Hofman max_steps = 164;
750854b66e4STakashi Iwai knew.private_value =
7518f34692fSPavel Hofman AK_COMPOSE(idx/2, (idx%2) + 4, 0, max_steps) |
752854b66e4STakashi Iwai AK_VOL_CVT | AK_IPGA;
753854b66e4STakashi Iwai knew.tlv.p = db_scale_vol_datt;
754723b2b0dSTakashi Iwai err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
755723b2b0dSTakashi Iwai if (err < 0)
756723b2b0dSTakashi Iwai return err;
757723b2b0dSTakashi Iwai
758723b2b0dSTakashi Iwai if (ak->type == SND_AK5365 && (idx % 2) == 0) {
759723b2b0dSTakashi Iwai if (! ak->adc_info ||
760a58e7cb1SJochen Voss ! ak->adc_info[mixer_ch].switch_name) {
761723b2b0dSTakashi Iwai knew.name = "Capture Switch";
762a58e7cb1SJochen Voss knew.index = mixer_ch + ak->idx_offset * 2;
763a58e7cb1SJochen Voss } else
764723b2b0dSTakashi Iwai knew.name = ak->adc_info[mixer_ch].switch_name;
765723b2b0dSTakashi Iwai knew.info = ak4xxx_switch_info;
766723b2b0dSTakashi Iwai knew.get = ak4xxx_switch_get;
767723b2b0dSTakashi Iwai knew.put = ak4xxx_switch_put;
768723b2b0dSTakashi Iwai knew.access = 0;
769723b2b0dSTakashi Iwai /* register 2, bit 0 (SMUTE): 0 = normal operation,
770723b2b0dSTakashi Iwai 1 = mute */
771723b2b0dSTakashi Iwai knew.private_value =
772723b2b0dSTakashi Iwai AK_COMPOSE(idx/2, 2, 0, 0) | AK_INVERT;
773723b2b0dSTakashi Iwai err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
774723b2b0dSTakashi Iwai if (err < 0)
775723b2b0dSTakashi Iwai return err;
776a58e7cb1SJochen Voss
777a58e7cb1SJochen Voss memset(&knew, 0, sizeof(knew));
778*2127c01bSJia-Ju Bai if (!ak->adc_info ||
779*2127c01bSJia-Ju Bai !ak->adc_info[mixer_ch].selector_name) {
780a58e7cb1SJochen Voss knew.name = "Capture Channel";
781a58e7cb1SJochen Voss knew.index = mixer_ch + ak->idx_offset * 2;
782*2127c01bSJia-Ju Bai } else
783*2127c01bSJia-Ju Bai knew.name = ak->adc_info[mixer_ch].selector_name;
784a58e7cb1SJochen Voss
785a58e7cb1SJochen Voss knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
786a58e7cb1SJochen Voss knew.info = ak4xxx_capture_source_info;
787a58e7cb1SJochen Voss knew.get = ak4xxx_capture_source_get;
788a58e7cb1SJochen Voss knew.put = ak4xxx_capture_source_put;
789a58e7cb1SJochen Voss knew.access = 0;
790a58e7cb1SJochen Voss /* input selector control: reg. 1, bits 0-2.
791a58e7cb1SJochen Voss * mis-use 'shift' to pass mixer_ch */
792a58e7cb1SJochen Voss knew.private_value
793a58e7cb1SJochen Voss = AK_COMPOSE(idx/2, 1, mixer_ch, 0x07);
794a58e7cb1SJochen Voss err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
795a58e7cb1SJochen Voss if (err < 0)
796a58e7cb1SJochen Voss return err;
797723b2b0dSTakashi Iwai }
798723b2b0dSTakashi Iwai
799723b2b0dSTakashi Iwai idx += num_stereo;
800723b2b0dSTakashi Iwai mixer_ch++;
801723b2b0dSTakashi Iwai }
802723b2b0dSTakashi Iwai return 0;
803723b2b0dSTakashi Iwai }
804723b2b0dSTakashi Iwai
build_deemphasis(struct snd_akm4xxx * ak,int num_emphs)805723b2b0dSTakashi Iwai static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs)
806723b2b0dSTakashi Iwai {
807723b2b0dSTakashi Iwai int idx, err;
808723b2b0dSTakashi Iwai struct snd_kcontrol_new knew;
809723b2b0dSTakashi Iwai
810723b2b0dSTakashi Iwai for (idx = 0; idx < num_emphs; idx++) {
811723b2b0dSTakashi Iwai memset(&knew, 0, sizeof(knew));
812723b2b0dSTakashi Iwai knew.name = "Deemphasis";
813723b2b0dSTakashi Iwai knew.index = idx + ak->idx_offset;
814723b2b0dSTakashi Iwai knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
815723b2b0dSTakashi Iwai knew.count = 1;
816723b2b0dSTakashi Iwai knew.info = snd_akm4xxx_deemphasis_info;
817723b2b0dSTakashi Iwai knew.get = snd_akm4xxx_deemphasis_get;
818723b2b0dSTakashi Iwai knew.put = snd_akm4xxx_deemphasis_put;
819723b2b0dSTakashi Iwai switch (ak->type) {
820723b2b0dSTakashi Iwai case SND_AK4524:
821723b2b0dSTakashi Iwai case SND_AK4528:
8228f34692fSPavel Hofman case SND_AK4620:
823723b2b0dSTakashi Iwai /* register 3 */
824723b2b0dSTakashi Iwai knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
825723b2b0dSTakashi Iwai break;
826723b2b0dSTakashi Iwai case SND_AK4529: {
827723b2b0dSTakashi Iwai int shift = idx == 3 ? 6 : (2 - idx) * 2;
828723b2b0dSTakashi Iwai /* register 8 with shift */
829723b2b0dSTakashi Iwai knew.private_value = AK_COMPOSE(0, 8, shift, 0);
830723b2b0dSTakashi Iwai break;
831723b2b0dSTakashi Iwai }
832723b2b0dSTakashi Iwai case SND_AK4355:
833723b2b0dSTakashi Iwai case SND_AK4358:
834723b2b0dSTakashi Iwai knew.private_value = AK_COMPOSE(idx, 3, 0, 0);
835723b2b0dSTakashi Iwai break;
836723b2b0dSTakashi Iwai case SND_AK4381:
837723b2b0dSTakashi Iwai knew.private_value = AK_COMPOSE(idx, 1, 1, 0);
838723b2b0dSTakashi Iwai break;
839723b2b0dSTakashi Iwai default:
840723b2b0dSTakashi Iwai return -EINVAL;
841723b2b0dSTakashi Iwai }
842723b2b0dSTakashi Iwai err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
843723b2b0dSTakashi Iwai if (err < 0)
844723b2b0dSTakashi Iwai return err;
845723b2b0dSTakashi Iwai }
846723b2b0dSTakashi Iwai return 0;
847723b2b0dSTakashi Iwai }
848723b2b0dSTakashi Iwai
proc_regs_read(struct snd_info_entry * entry,struct snd_info_buffer * buffer)8498f34692fSPavel Hofman static void proc_regs_read(struct snd_info_entry *entry,
8508f34692fSPavel Hofman struct snd_info_buffer *buffer)
8518f34692fSPavel Hofman {
8529fe856e4SJoe Perches struct snd_akm4xxx *ak = entry->private_data;
8538f34692fSPavel Hofman int reg, val, chip;
8548f34692fSPavel Hofman for (chip = 0; chip < ak->num_chips; chip++) {
8558f34692fSPavel Hofman for (reg = 0; reg < ak->total_regs; reg++) {
8568f34692fSPavel Hofman val = snd_akm4xxx_get(ak, chip, reg);
8578f34692fSPavel Hofman snd_iprintf(buffer, "chip %d: 0x%02x = 0x%02x\n", chip,
8588f34692fSPavel Hofman reg, val);
8598f34692fSPavel Hofman }
8608f34692fSPavel Hofman }
8618f34692fSPavel Hofman }
8628f34692fSPavel Hofman
proc_init(struct snd_akm4xxx * ak)8638f34692fSPavel Hofman static int proc_init(struct snd_akm4xxx *ak)
8648f34692fSPavel Hofman {
8655a170e9eSTakashi Iwai return snd_card_ro_proc_new(ak->card, ak->name, ak, proc_regs_read);
8668f34692fSPavel Hofman }
8678f34692fSPavel Hofman
snd_akm4xxx_build_controls(struct snd_akm4xxx * ak)868723b2b0dSTakashi Iwai int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak)
869723b2b0dSTakashi Iwai {
870723b2b0dSTakashi Iwai int err, num_emphs;
871723b2b0dSTakashi Iwai
872723b2b0dSTakashi Iwai err = build_dac_controls(ak);
873723b2b0dSTakashi Iwai if (err < 0)
874723b2b0dSTakashi Iwai return err;
875723b2b0dSTakashi Iwai
876723b2b0dSTakashi Iwai err = build_adc_controls(ak);
877723b2b0dSTakashi Iwai if (err < 0)
878723b2b0dSTakashi Iwai return err;
8791da177e4SLinus Torvalds if (ak->type == SND_AK4355 || ak->type == SND_AK4358)
8801da177e4SLinus Torvalds num_emphs = 1;
8818f34692fSPavel Hofman else if (ak->type == SND_AK4620)
8828f34692fSPavel Hofman num_emphs = 0;
8831da177e4SLinus Torvalds else
8841da177e4SLinus Torvalds num_emphs = ak->num_dacs / 2;
885723b2b0dSTakashi Iwai err = build_deemphasis(ak, num_emphs);
886cb9d24e4STakashi Iwai if (err < 0)
8871da177e4SLinus Torvalds return err;
8888f34692fSPavel Hofman err = proc_init(ak);
8898f34692fSPavel Hofman if (err < 0)
8908f34692fSPavel Hofman return err;
891723b2b0dSTakashi Iwai
892723b2b0dSTakashi Iwai return 0;
8931da177e4SLinus Torvalds }
894cb9d24e4STakashi Iwai EXPORT_SYMBOL(snd_akm4xxx_build_controls);
895