11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * ALSA driver for ICEnsemble ICE1724 (Envy24)
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Lowlevel functions for Terratec PHASE 22
61da177e4SLinus Torvalds *
71da177e4SLinus Torvalds * Copyright (c) 2005 Misha Zhilin <misha@epiphan.com>
81da177e4SLinus Torvalds */
91da177e4SLinus Torvalds
101da177e4SLinus Torvalds /* PHASE 22 overview:
11eee75a6cSVedran Miletic * Audio controller: VIA Envy24HT-S (slightly trimmed down Envy24HT, 4in/4out)
121da177e4SLinus Torvalds * Analog chip: AK4524 (partially via Philip's 74HCT125)
13eee75a6cSVedran Miletic * Digital receiver: CS8414-CS (supported in this release)
14eee75a6cSVedran Miletic * PHASE 22 revision 2.0 and Terrasoniq/Musonik TS22PCI have CS8416
15eee75a6cSVedran Miletic * (support status unknown, please test and report)
161da177e4SLinus Torvalds *
171da177e4SLinus Torvalds * Envy connects to AK4524
181da177e4SLinus Torvalds * - CS directly from GPIO 10
191da177e4SLinus Torvalds * - CCLK via 74HCT125's gate #4 from GPIO 4
201da177e4SLinus Torvalds * - CDTI via 74HCT125's gate #2 from GPIO 5
21eee75a6cSVedran Miletic * CDTI may be completely blocked by 74HCT125's gate #1
22eee75a6cSVedran Miletic * controlled by GPIO 3
23eee75a6cSVedran Miletic */
24eee75a6cSVedran Miletic
25eee75a6cSVedran Miletic /* PHASE 28 overview:
26cc67b7f7SVedran Miletic * Audio controller: VIA Envy24HT (full untrimmed version, 4in/8out)
27eee75a6cSVedran Miletic * Analog chip: WM8770 (8 channel 192k DAC, 2 channel 96k ADC)
28eee75a6cSVedran Miletic * Digital receiver: CS8414-CS (supported in this release)
291da177e4SLinus Torvalds */
301da177e4SLinus Torvalds
311da177e4SLinus Torvalds #include <linux/delay.h>
321da177e4SLinus Torvalds #include <linux/interrupt.h>
331da177e4SLinus Torvalds #include <linux/init.h>
341da177e4SLinus Torvalds #include <linux/slab.h>
3562932df8SIngo Molnar #include <linux/mutex.h>
3662932df8SIngo Molnar
371da177e4SLinus Torvalds #include <sound/core.h>
381da177e4SLinus Torvalds
391da177e4SLinus Torvalds #include "ice1712.h"
401da177e4SLinus Torvalds #include "envy24ht.h"
411da177e4SLinus Torvalds #include "phase.h"
42f640c320STakashi Iwai #include <sound/tlv.h>
431da177e4SLinus Torvalds
447cda8ba9STakashi Iwai /* AC97 register cache for Phase28 */
457cda8ba9STakashi Iwai struct phase28_spec {
467cda8ba9STakashi Iwai unsigned short master[2];
477cda8ba9STakashi Iwai unsigned short vol[8];
48008f3599SHarvey Harrison };
497cda8ba9STakashi Iwai
50aed058e8SSimone Zinanni /* WM8770 registers */
51aed058e8SSimone Zinanni #define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */
52aed058e8SSimone Zinanni #define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */
53aed058e8SSimone Zinanni #define WM_DAC_DIG_ATTEN 0x09 /* DAC1-8 digital attenuation */
54aed058e8SSimone Zinanni #define WM_DAC_DIG_MASTER_ATTEN 0x11 /* DAC master digital attenuation */
55aed058e8SSimone Zinanni #define WM_PHASE_SWAP 0x12 /* DAC phase */
56aed058e8SSimone Zinanni #define WM_DAC_CTRL1 0x13 /* DAC control bits */
57aed058e8SSimone Zinanni #define WM_MUTE 0x14 /* mute controls */
58aed058e8SSimone Zinanni #define WM_DAC_CTRL2 0x15 /* de-emphasis and zefo-flag */
59aed058e8SSimone Zinanni #define WM_INT_CTRL 0x16 /* interface control */
60aed058e8SSimone Zinanni #define WM_MASTER 0x17 /* master clock and mode */
61aed058e8SSimone Zinanni #define WM_POWERDOWN 0x18 /* power-down controls */
62aed058e8SSimone Zinanni #define WM_ADC_GAIN 0x19 /* ADC gain L(19)/R(1a) */
63aed058e8SSimone Zinanni #define WM_ADC_MUX 0x1b /* input MUX */
64aed058e8SSimone Zinanni #define WM_OUT_MUX1 0x1c /* output MUX */
65aed058e8SSimone Zinanni #define WM_OUT_MUX2 0x1e /* output MUX */
66aed058e8SSimone Zinanni #define WM_RESET 0x1f /* software reset */
67aed058e8SSimone Zinanni
68aed058e8SSimone Zinanni
69aed058e8SSimone Zinanni /*
70aed058e8SSimone Zinanni * Logarithmic volume values for WM8770
71aed058e8SSimone Zinanni * Computed as 20 * Log10(255 / x)
72aed058e8SSimone Zinanni */
7332b47da0STakashi Iwai static const unsigned char wm_vol[256] = {
74cc67b7f7SVedran Miletic 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24,
75cc67b7f7SVedran Miletic 24, 23, 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18,
76cc67b7f7SVedran Miletic 17, 17, 17, 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14,
77cc67b7f7SVedran Miletic 14, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11,
78cc67b7f7SVedran Miletic 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9,
79cc67b7f7SVedran Miletic 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7,
80cc67b7f7SVedran Miletic 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5,
81cc67b7f7SVedran Miletic 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
82cc67b7f7SVedran Miletic 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
83cc67b7f7SVedran Miletic 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
84cc67b7f7SVedran Miletic 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
85cc67b7f7SVedran Miletic 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
86aed058e8SSimone Zinanni };
87aed058e8SSimone Zinanni
88aed058e8SSimone Zinanni #define WM_VOL_MAX (sizeof(wm_vol) - 1)
89aed058e8SSimone Zinanni #define WM_VOL_MUTE 0x8000
90aed058e8SSimone Zinanni
913135432eSBhumika Goyal static const struct snd_akm4xxx akm_phase22 = {
921da177e4SLinus Torvalds .type = SND_AK4524,
931da177e4SLinus Torvalds .num_dacs = 2,
941da177e4SLinus Torvalds .num_adcs = 2,
951da177e4SLinus Torvalds };
961da177e4SLinus Torvalds
974647e8d5SBhumika Goyal static const struct snd_ak4xxx_private akm_phase22_priv = {
981da177e4SLinus Torvalds .caddr = 2,
991da177e4SLinus Torvalds .cif = 1,
1001da177e4SLinus Torvalds .data_mask = 1 << 4,
1011da177e4SLinus Torvalds .clk_mask = 1 << 5,
1021da177e4SLinus Torvalds .cs_mask = 1 << 10,
1031da177e4SLinus Torvalds .cs_addr = 1 << 10,
1041da177e4SLinus Torvalds .cs_none = 0,
1051da177e4SLinus Torvalds .add_flags = 1 << 3,
1061da177e4SLinus Torvalds .mask_flags = 0,
1071da177e4SLinus Torvalds };
1081da177e4SLinus Torvalds
phase22_init(struct snd_ice1712 * ice)109e23e7a14SBill Pemberton static int phase22_init(struct snd_ice1712 *ice)
1101da177e4SLinus Torvalds {
111ab0c7d72STakashi Iwai struct snd_akm4xxx *ak;
1121da177e4SLinus Torvalds int err;
1131da177e4SLinus Torvalds
114cc67b7f7SVedran Miletic /* Configure DAC/ADC description for generic part of ice1724 */
1151da177e4SLinus Torvalds switch (ice->eeprom.subvendor) {
1161da177e4SLinus Torvalds case VT1724_SUBDEVICE_PHASE22:
117740dc9c4SMisha Zhilin case VT1724_SUBDEVICE_TS22:
1181da177e4SLinus Torvalds ice->num_total_dacs = 2;
1191da177e4SLinus Torvalds ice->num_total_adcs = 2;
120cc67b7f7SVedran Miletic ice->vt1720 = 1; /* Envy24HT-S have 16 bit wide GPIO */
1211da177e4SLinus Torvalds break;
1221da177e4SLinus Torvalds default:
1231da177e4SLinus Torvalds snd_BUG();
1241da177e4SLinus Torvalds return -EINVAL;
1251da177e4SLinus Torvalds }
1261da177e4SLinus Torvalds
127cc67b7f7SVedran Miletic /* Initialize analog chips */
128cc67b7f7SVedran Miletic ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
129cc67b7f7SVedran Miletic ak = ice->akm;
1301da177e4SLinus Torvalds if (!ak)
1311da177e4SLinus Torvalds return -ENOMEM;
1321da177e4SLinus Torvalds ice->akm_codecs = 1;
1331da177e4SLinus Torvalds switch (ice->eeprom.subvendor) {
1341da177e4SLinus Torvalds case VT1724_SUBDEVICE_PHASE22:
135740dc9c4SMisha Zhilin case VT1724_SUBDEVICE_TS22:
136cc67b7f7SVedran Miletic err = snd_ice1712_akm4xxx_init(ak, &akm_phase22,
137cc67b7f7SVedran Miletic &akm_phase22_priv, ice);
138cc67b7f7SVedran Miletic if (err < 0)
1391da177e4SLinus Torvalds return err;
1401da177e4SLinus Torvalds break;
1411da177e4SLinus Torvalds }
1421da177e4SLinus Torvalds
1431da177e4SLinus Torvalds return 0;
1441da177e4SLinus Torvalds }
1451da177e4SLinus Torvalds
phase22_add_controls(struct snd_ice1712 * ice)146e23e7a14SBill Pemberton static int phase22_add_controls(struct snd_ice1712 *ice)
1471da177e4SLinus Torvalds {
1481da177e4SLinus Torvalds int err = 0;
1491da177e4SLinus Torvalds
1501da177e4SLinus Torvalds switch (ice->eeprom.subvendor) {
1511da177e4SLinus Torvalds case VT1724_SUBDEVICE_PHASE22:
152740dc9c4SMisha Zhilin case VT1724_SUBDEVICE_TS22:
1531da177e4SLinus Torvalds err = snd_ice1712_akm4xxx_build_controls(ice);
1541da177e4SLinus Torvalds if (err < 0)
1551da177e4SLinus Torvalds return err;
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds return 0;
1581da177e4SLinus Torvalds }
1591da177e4SLinus Torvalds
160*f16a4e96STakashi Iwai static const unsigned char phase22_eeprom[] = {
161eee75a6cSVedran Miletic [ICE_EEP2_SYSCONF] = 0x28, /* clock 512, mpu 401,
162eee75a6cSVedran Miletic spdif-in/1xADC, 1xDACs */
163189bc171STakashi Iwai [ICE_EEP2_ACLINK] = 0x80, /* I2S */
164eee75a6cSVedran Miletic [ICE_EEP2_I2S] = 0xf0, /* vol, 96k, 24bit */
165189bc171STakashi Iwai [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
166189bc171STakashi Iwai [ICE_EEP2_GPIO_DIR] = 0xff,
167189bc171STakashi Iwai [ICE_EEP2_GPIO_DIR1] = 0xff,
168189bc171STakashi Iwai [ICE_EEP2_GPIO_DIR2] = 0xff,
169189bc171STakashi Iwai [ICE_EEP2_GPIO_MASK] = 0x00,
170189bc171STakashi Iwai [ICE_EEP2_GPIO_MASK1] = 0x00,
171189bc171STakashi Iwai [ICE_EEP2_GPIO_MASK2] = 0x00,
172189bc171STakashi Iwai [ICE_EEP2_GPIO_STATE] = 0x00,
173189bc171STakashi Iwai [ICE_EEP2_GPIO_STATE1] = 0x00,
174189bc171STakashi Iwai [ICE_EEP2_GPIO_STATE2] = 0x00,
1751da177e4SLinus Torvalds };
1761da177e4SLinus Torvalds
177*f16a4e96STakashi Iwai static const unsigned char phase28_eeprom[] = {
178eee75a6cSVedran Miletic [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401,
179eee75a6cSVedran Miletic spdif-in/1xADC, 4xDACs */
180189bc171STakashi Iwai [ICE_EEP2_ACLINK] = 0x80, /* I2S */
181189bc171STakashi Iwai [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
182189bc171STakashi Iwai [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
183189bc171STakashi Iwai [ICE_EEP2_GPIO_DIR] = 0xff,
184189bc171STakashi Iwai [ICE_EEP2_GPIO_DIR1] = 0xff,
185189bc171STakashi Iwai [ICE_EEP2_GPIO_DIR2] = 0x5f,
186189bc171STakashi Iwai [ICE_EEP2_GPIO_MASK] = 0x00,
187189bc171STakashi Iwai [ICE_EEP2_GPIO_MASK1] = 0x00,
188189bc171STakashi Iwai [ICE_EEP2_GPIO_MASK2] = 0x00,
189189bc171STakashi Iwai [ICE_EEP2_GPIO_STATE] = 0x00,
190189bc171STakashi Iwai [ICE_EEP2_GPIO_STATE1] = 0x00,
191189bc171STakashi Iwai [ICE_EEP2_GPIO_STATE2] = 0x00,
192aed058e8SSimone Zinanni };
193aed058e8SSimone Zinanni
194aed058e8SSimone Zinanni /*
195aed058e8SSimone Zinanni * write data in the SPI mode
196aed058e8SSimone Zinanni */
phase28_spi_write(struct snd_ice1712 * ice,unsigned int cs,unsigned int data,int bits)197cc67b7f7SVedran Miletic static void phase28_spi_write(struct snd_ice1712 *ice, unsigned int cs,
198cc67b7f7SVedran Miletic unsigned int data, int bits)
199aed058e8SSimone Zinanni {
200aed058e8SSimone Zinanni unsigned int tmp;
201aed058e8SSimone Zinanni int i;
202aed058e8SSimone Zinanni
203aed058e8SSimone Zinanni tmp = snd_ice1712_gpio_read(ice);
204aed058e8SSimone Zinanni
205cc67b7f7SVedran Miletic snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RW|PHASE28_SPI_MOSI|
206cc67b7f7SVedran Miletic PHASE28_SPI_CLK|PHASE28_WM_CS));
207aed058e8SSimone Zinanni tmp |= PHASE28_WM_RW;
208aed058e8SSimone Zinanni tmp &= ~cs;
209aed058e8SSimone Zinanni snd_ice1712_gpio_write(ice, tmp);
210aed058e8SSimone Zinanni udelay(1);
211aed058e8SSimone Zinanni
212aed058e8SSimone Zinanni for (i = bits - 1; i >= 0; i--) {
213aed058e8SSimone Zinanni tmp &= ~PHASE28_SPI_CLK;
214aed058e8SSimone Zinanni snd_ice1712_gpio_write(ice, tmp);
215aed058e8SSimone Zinanni udelay(1);
216aed058e8SSimone Zinanni if (data & (1 << i))
217aed058e8SSimone Zinanni tmp |= PHASE28_SPI_MOSI;
218aed058e8SSimone Zinanni else
219aed058e8SSimone Zinanni tmp &= ~PHASE28_SPI_MOSI;
220aed058e8SSimone Zinanni snd_ice1712_gpio_write(ice, tmp);
221aed058e8SSimone Zinanni udelay(1);
222aed058e8SSimone Zinanni tmp |= PHASE28_SPI_CLK;
223aed058e8SSimone Zinanni snd_ice1712_gpio_write(ice, tmp);
224aed058e8SSimone Zinanni udelay(1);
225aed058e8SSimone Zinanni }
226aed058e8SSimone Zinanni
227aed058e8SSimone Zinanni tmp &= ~PHASE28_SPI_CLK;
228aed058e8SSimone Zinanni tmp |= cs;
229aed058e8SSimone Zinanni snd_ice1712_gpio_write(ice, tmp);
230aed058e8SSimone Zinanni udelay(1);
231aed058e8SSimone Zinanni tmp |= PHASE28_SPI_CLK;
232aed058e8SSimone Zinanni snd_ice1712_gpio_write(ice, tmp);
233aed058e8SSimone Zinanni udelay(1);
234aed058e8SSimone Zinanni }
235aed058e8SSimone Zinanni
236aed058e8SSimone Zinanni /*
237aed058e8SSimone Zinanni * get the current register value of WM codec
238aed058e8SSimone Zinanni */
wm_get(struct snd_ice1712 * ice,int reg)239ab0c7d72STakashi Iwai static unsigned short wm_get(struct snd_ice1712 *ice, int reg)
240aed058e8SSimone Zinanni {
241aed058e8SSimone Zinanni reg <<= 1;
242aed058e8SSimone Zinanni return ((unsigned short)ice->akm[0].images[reg] << 8) |
243aed058e8SSimone Zinanni ice->akm[0].images[reg + 1];
244aed058e8SSimone Zinanni }
245aed058e8SSimone Zinanni
246aed058e8SSimone Zinanni /*
247aed058e8SSimone Zinanni * set the register value of WM codec
248aed058e8SSimone Zinanni */
wm_put_nocache(struct snd_ice1712 * ice,int reg,unsigned short val)249ab0c7d72STakashi Iwai static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
250aed058e8SSimone Zinanni {
251aed058e8SSimone Zinanni phase28_spi_write(ice, PHASE28_WM_CS, (reg << 9) | (val & 0x1ff), 16);
252aed058e8SSimone Zinanni }
253aed058e8SSimone Zinanni
254aed058e8SSimone Zinanni /*
255aed058e8SSimone Zinanni * set the register value of WM codec and remember it
256aed058e8SSimone Zinanni */
wm_put(struct snd_ice1712 * ice,int reg,unsigned short val)257ab0c7d72STakashi Iwai static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
258aed058e8SSimone Zinanni {
259aed058e8SSimone Zinanni wm_put_nocache(ice, reg, val);
260aed058e8SSimone Zinanni reg <<= 1;
261aed058e8SSimone Zinanni ice->akm[0].images[reg] = val >> 8;
262aed058e8SSimone Zinanni ice->akm[0].images[reg + 1] = val;
263aed058e8SSimone Zinanni }
264aed058e8SSimone Zinanni
wm_set_vol(struct snd_ice1712 * ice,unsigned int index,unsigned short vol,unsigned short master)265cc67b7f7SVedran Miletic static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index,
266cc67b7f7SVedran Miletic unsigned short vol, unsigned short master)
267aed058e8SSimone Zinanni {
268aed058e8SSimone Zinanni unsigned char nvol;
269aed058e8SSimone Zinanni
270aed058e8SSimone Zinanni if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
271aed058e8SSimone Zinanni nvol = 0;
272aed058e8SSimone Zinanni else
273cc67b7f7SVedran Miletic nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) *
274cc67b7f7SVedran Miletic (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX];
275aed058e8SSimone Zinanni
276aed058e8SSimone Zinanni wm_put(ice, index, nvol);
277aed058e8SSimone Zinanni wm_put_nocache(ice, index, 0x180 | nvol);
278aed058e8SSimone Zinanni }
279aed058e8SSimone Zinanni
280aed058e8SSimone Zinanni /*
281aed058e8SSimone Zinanni * DAC mute control
282aed058e8SSimone Zinanni */
283a5ce8890STakashi Iwai #define wm_pcm_mute_info snd_ctl_boolean_mono_info
284aed058e8SSimone Zinanni
wm_pcm_mute_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)285cc67b7f7SVedran Miletic static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol,
286cc67b7f7SVedran Miletic struct snd_ctl_elem_value *ucontrol)
287aed058e8SSimone Zinanni {
288ab0c7d72STakashi Iwai struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
289aed058e8SSimone Zinanni
29062932df8SIngo Molnar mutex_lock(&ice->gpio_mutex);
291cc67b7f7SVedran Miletic ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ?
292cc67b7f7SVedran Miletic 0 : 1;
29362932df8SIngo Molnar mutex_unlock(&ice->gpio_mutex);
294aed058e8SSimone Zinanni return 0;
295aed058e8SSimone Zinanni }
296aed058e8SSimone Zinanni
wm_pcm_mute_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)297cc67b7f7SVedran Miletic static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol,
298cc67b7f7SVedran Miletic struct snd_ctl_elem_value *ucontrol)
299aed058e8SSimone Zinanni {
300ab0c7d72STakashi Iwai struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
301aed058e8SSimone Zinanni unsigned short nval, oval;
302aed058e8SSimone Zinanni int change;
303aed058e8SSimone Zinanni
304aed058e8SSimone Zinanni snd_ice1712_save_gpio_status(ice);
305aed058e8SSimone Zinanni oval = wm_get(ice, WM_MUTE);
306aed058e8SSimone Zinanni nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);
307cc67b7f7SVedran Miletic change = (nval != oval);
308cc67b7f7SVedran Miletic if (change)
309aed058e8SSimone Zinanni wm_put(ice, WM_MUTE, nval);
310aed058e8SSimone Zinanni snd_ice1712_restore_gpio_status(ice);
311aed058e8SSimone Zinanni
312aed058e8SSimone Zinanni return change;
313aed058e8SSimone Zinanni }
314aed058e8SSimone Zinanni
315aed058e8SSimone Zinanni /*
316aed058e8SSimone Zinanni * Master volume attenuation mixer control
317aed058e8SSimone Zinanni */
wm_master_vol_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)318cc67b7f7SVedran Miletic static int wm_master_vol_info(struct snd_kcontrol *kcontrol,
319cc67b7f7SVedran Miletic struct snd_ctl_elem_info *uinfo)
320aed058e8SSimone Zinanni {
321aed058e8SSimone Zinanni uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
322aed058e8SSimone Zinanni uinfo->count = 2;
323aed058e8SSimone Zinanni uinfo->value.integer.min = 0;
324aed058e8SSimone Zinanni uinfo->value.integer.max = WM_VOL_MAX;
325aed058e8SSimone Zinanni return 0;
326aed058e8SSimone Zinanni }
327aed058e8SSimone Zinanni
wm_master_vol_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)328cc67b7f7SVedran Miletic static int wm_master_vol_get(struct snd_kcontrol *kcontrol,
329cc67b7f7SVedran Miletic struct snd_ctl_elem_value *ucontrol)
330aed058e8SSimone Zinanni {
331ab0c7d72STakashi Iwai struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
3327cda8ba9STakashi Iwai struct phase28_spec *spec = ice->spec;
333aed058e8SSimone Zinanni int i;
334aed058e8SSimone Zinanni for (i = 0; i < 2; i++)
335cc67b7f7SVedran Miletic ucontrol->value.integer.value[i] = spec->master[i] &
336cc67b7f7SVedran Miletic ~WM_VOL_MUTE;
337aed058e8SSimone Zinanni return 0;
338aed058e8SSimone Zinanni }
339aed058e8SSimone Zinanni
wm_master_vol_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)340cc67b7f7SVedran Miletic static int wm_master_vol_put(struct snd_kcontrol *kcontrol,
341cc67b7f7SVedran Miletic struct snd_ctl_elem_value *ucontrol)
342aed058e8SSimone Zinanni {
343ab0c7d72STakashi Iwai struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
3447cda8ba9STakashi Iwai struct phase28_spec *spec = ice->spec;
345aed058e8SSimone Zinanni int ch, change = 0;
346aed058e8SSimone Zinanni
347aed058e8SSimone Zinanni snd_ice1712_save_gpio_status(ice);
348aed058e8SSimone Zinanni for (ch = 0; ch < 2; ch++) {
3499cd17cd2STakashi Iwai unsigned int vol = ucontrol->value.integer.value[ch];
3509cd17cd2STakashi Iwai if (vol > WM_VOL_MAX)
3519cd17cd2STakashi Iwai continue;
3527cda8ba9STakashi Iwai vol |= spec->master[ch] & WM_VOL_MUTE;
3537cda8ba9STakashi Iwai if (vol != spec->master[ch]) {
354aed058e8SSimone Zinanni int dac;
3557cda8ba9STakashi Iwai spec->master[ch] = vol;
356aed058e8SSimone Zinanni for (dac = 0; dac < ice->num_total_dacs; dac += 2)
357aed058e8SSimone Zinanni wm_set_vol(ice, WM_DAC_ATTEN + dac + ch,
3587cda8ba9STakashi Iwai spec->vol[dac + ch],
3597cda8ba9STakashi Iwai spec->master[ch]);
360aed058e8SSimone Zinanni change = 1;
361aed058e8SSimone Zinanni }
362aed058e8SSimone Zinanni }
363aed058e8SSimone Zinanni snd_ice1712_restore_gpio_status(ice);
364aed058e8SSimone Zinanni return change;
365aed058e8SSimone Zinanni }
366aed058e8SSimone Zinanni
phase28_init(struct snd_ice1712 * ice)367e23e7a14SBill Pemberton static int phase28_init(struct snd_ice1712 *ice)
368aed058e8SSimone Zinanni {
36932b47da0STakashi Iwai static const unsigned short wm_inits_phase28[] = {
370aed058e8SSimone Zinanni /* These come first to reduce init pop noise */
371aed058e8SSimone Zinanni 0x1b, 0x044, /* ADC Mux (AC'97 source) */
372aed058e8SSimone Zinanni 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
373aed058e8SSimone Zinanni 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
374aed058e8SSimone Zinanni
375aed058e8SSimone Zinanni 0x18, 0x000, /* All power-up */
376aed058e8SSimone Zinanni
377aed058e8SSimone Zinanni 0x16, 0x122, /* I2S, normal polarity, 24bit */
378aed058e8SSimone Zinanni 0x17, 0x022, /* 256fs, slave mode */
379aed058e8SSimone Zinanni 0x00, 0, /* DAC1 analog mute */
380aed058e8SSimone Zinanni 0x01, 0, /* DAC2 analog mute */
381aed058e8SSimone Zinanni 0x02, 0, /* DAC3 analog mute */
382aed058e8SSimone Zinanni 0x03, 0, /* DAC4 analog mute */
383aed058e8SSimone Zinanni 0x04, 0, /* DAC5 analog mute */
384aed058e8SSimone Zinanni 0x05, 0, /* DAC6 analog mute */
385aed058e8SSimone Zinanni 0x06, 0, /* DAC7 analog mute */
386aed058e8SSimone Zinanni 0x07, 0, /* DAC8 analog mute */
387aed058e8SSimone Zinanni 0x08, 0x100, /* master analog mute */
388aed058e8SSimone Zinanni 0x09, 0xff, /* DAC1 digital full */
389aed058e8SSimone Zinanni 0x0a, 0xff, /* DAC2 digital full */
390aed058e8SSimone Zinanni 0x0b, 0xff, /* DAC3 digital full */
391aed058e8SSimone Zinanni 0x0c, 0xff, /* DAC4 digital full */
392aed058e8SSimone Zinanni 0x0d, 0xff, /* DAC5 digital full */
393aed058e8SSimone Zinanni 0x0e, 0xff, /* DAC6 digital full */
394aed058e8SSimone Zinanni 0x0f, 0xff, /* DAC7 digital full */
395aed058e8SSimone Zinanni 0x10, 0xff, /* DAC8 digital full */
396aed058e8SSimone Zinanni 0x11, 0x1ff, /* master digital full */
397aed058e8SSimone Zinanni 0x12, 0x000, /* phase normal */
398aed058e8SSimone Zinanni 0x13, 0x090, /* unmute DAC L/R */
399aed058e8SSimone Zinanni 0x14, 0x000, /* all unmute */
400aed058e8SSimone Zinanni 0x15, 0x000, /* no deemphasis, no ZFLG */
401aed058e8SSimone Zinanni 0x19, 0x000, /* -12dB ADC/L */
402aed058e8SSimone Zinanni 0x1a, 0x000, /* -12dB ADC/R */
403aed058e8SSimone Zinanni (unsigned short)-1
404aed058e8SSimone Zinanni };
405aed058e8SSimone Zinanni
406aed058e8SSimone Zinanni unsigned int tmp;
407ab0c7d72STakashi Iwai struct snd_akm4xxx *ak;
4087cda8ba9STakashi Iwai struct phase28_spec *spec;
40932b47da0STakashi Iwai const unsigned short *p;
410aed058e8SSimone Zinanni int i;
411aed058e8SSimone Zinanni
412aed058e8SSimone Zinanni ice->num_total_dacs = 8;
413aed058e8SSimone Zinanni ice->num_total_adcs = 2;
414aed058e8SSimone Zinanni
4157cda8ba9STakashi Iwai spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4167cda8ba9STakashi Iwai if (!spec)
4177cda8ba9STakashi Iwai return -ENOMEM;
4187cda8ba9STakashi Iwai ice->spec = spec;
4197cda8ba9STakashi Iwai
420cc67b7f7SVedran Miletic /* Initialize analog chips */
421cc67b7f7SVedran Miletic ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
422cc67b7f7SVedran Miletic ak = ice->akm;
423aed058e8SSimone Zinanni if (!ak)
424aed058e8SSimone Zinanni return -ENOMEM;
425aed058e8SSimone Zinanni ice->akm_codecs = 1;
426aed058e8SSimone Zinanni
427cc67b7f7SVedran Miletic snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for time being */
428aed058e8SSimone Zinanni
429aed058e8SSimone Zinanni /* reset the wm codec as the SPI mode */
430aed058e8SSimone Zinanni snd_ice1712_save_gpio_status(ice);
431cc67b7f7SVedran Miletic snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RESET|PHASE28_WM_CS|
432cc67b7f7SVedran Miletic PHASE28_HP_SEL));
433aed058e8SSimone Zinanni
434aed058e8SSimone Zinanni tmp = snd_ice1712_gpio_read(ice);
435aed058e8SSimone Zinanni tmp &= ~PHASE28_WM_RESET;
436aed058e8SSimone Zinanni snd_ice1712_gpio_write(ice, tmp);
437aed058e8SSimone Zinanni udelay(1);
438aed058e8SSimone Zinanni tmp |= PHASE28_WM_CS;
439aed058e8SSimone Zinanni snd_ice1712_gpio_write(ice, tmp);
440aed058e8SSimone Zinanni udelay(1);
441aed058e8SSimone Zinanni tmp |= PHASE28_WM_RESET;
442aed058e8SSimone Zinanni snd_ice1712_gpio_write(ice, tmp);
443aed058e8SSimone Zinanni udelay(1);
444aed058e8SSimone Zinanni
445aed058e8SSimone Zinanni p = wm_inits_phase28;
446aed058e8SSimone Zinanni for (; *p != (unsigned short)-1; p += 2)
447aed058e8SSimone Zinanni wm_put(ice, p[0], p[1]);
448aed058e8SSimone Zinanni
449aed058e8SSimone Zinanni snd_ice1712_restore_gpio_status(ice);
450aed058e8SSimone Zinanni
4517cda8ba9STakashi Iwai spec->master[0] = WM_VOL_MUTE;
4527cda8ba9STakashi Iwai spec->master[1] = WM_VOL_MUTE;
453aed058e8SSimone Zinanni for (i = 0; i < ice->num_total_dacs; i++) {
4547cda8ba9STakashi Iwai spec->vol[i] = WM_VOL_MUTE;
4557cda8ba9STakashi Iwai wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
456aed058e8SSimone Zinanni }
457aed058e8SSimone Zinanni
458aed058e8SSimone Zinanni return 0;
459aed058e8SSimone Zinanni }
460aed058e8SSimone Zinanni
461aed058e8SSimone Zinanni /*
462aed058e8SSimone Zinanni * DAC volume attenuation mixer control
463aed058e8SSimone Zinanni */
wm_vol_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)464cc67b7f7SVedran Miletic static int wm_vol_info(struct snd_kcontrol *kcontrol,
465cc67b7f7SVedran Miletic struct snd_ctl_elem_info *uinfo)
466aed058e8SSimone Zinanni {
467aed058e8SSimone Zinanni int voices = kcontrol->private_value >> 8;
468aed058e8SSimone Zinanni uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
469aed058e8SSimone Zinanni uinfo->count = voices;
470aed058e8SSimone Zinanni uinfo->value.integer.min = 0; /* mute (-101dB) */
471aed058e8SSimone Zinanni uinfo->value.integer.max = 0x7F; /* 0dB */
472aed058e8SSimone Zinanni return 0;
473aed058e8SSimone Zinanni }
474aed058e8SSimone Zinanni
wm_vol_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)475cc67b7f7SVedran Miletic static int wm_vol_get(struct snd_kcontrol *kcontrol,
476cc67b7f7SVedran Miletic struct snd_ctl_elem_value *ucontrol)
477aed058e8SSimone Zinanni {
478ab0c7d72STakashi Iwai struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
4797cda8ba9STakashi Iwai struct phase28_spec *spec = ice->spec;
480aed058e8SSimone Zinanni int i, ofs, voices;
481aed058e8SSimone Zinanni
482aed058e8SSimone Zinanni voices = kcontrol->private_value >> 8;
483aed058e8SSimone Zinanni ofs = kcontrol->private_value & 0xff;
484aed058e8SSimone Zinanni for (i = 0; i < voices; i++)
4857cda8ba9STakashi Iwai ucontrol->value.integer.value[i] =
4867cda8ba9STakashi Iwai spec->vol[ofs+i] & ~WM_VOL_MUTE;
487aed058e8SSimone Zinanni return 0;
488aed058e8SSimone Zinanni }
489aed058e8SSimone Zinanni
wm_vol_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)490cc67b7f7SVedran Miletic static int wm_vol_put(struct snd_kcontrol *kcontrol,
491cc67b7f7SVedran Miletic struct snd_ctl_elem_value *ucontrol)
492aed058e8SSimone Zinanni {
493ab0c7d72STakashi Iwai struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
4947cda8ba9STakashi Iwai struct phase28_spec *spec = ice->spec;
495aed058e8SSimone Zinanni int i, idx, ofs, voices;
496aed058e8SSimone Zinanni int change = 0;
497aed058e8SSimone Zinanni
498aed058e8SSimone Zinanni voices = kcontrol->private_value >> 8;
499aed058e8SSimone Zinanni ofs = kcontrol->private_value & 0xff;
500aed058e8SSimone Zinanni snd_ice1712_save_gpio_status(ice);
501aed058e8SSimone Zinanni for (i = 0; i < voices; i++) {
5029cd17cd2STakashi Iwai unsigned int vol;
5039cd17cd2STakashi Iwai vol = ucontrol->value.integer.value[i];
5049cd17cd2STakashi Iwai if (vol > 0x7f)
5059cd17cd2STakashi Iwai continue;
5067cda8ba9STakashi Iwai vol |= spec->vol[ofs+i] & WM_VOL_MUTE;
5077cda8ba9STakashi Iwai if (vol != spec->vol[ofs+i]) {
5087cda8ba9STakashi Iwai spec->vol[ofs+i] = vol;
509aed058e8SSimone Zinanni idx = WM_DAC_ATTEN + ofs + i;
5107cda8ba9STakashi Iwai wm_set_vol(ice, idx, spec->vol[ofs+i],
5117cda8ba9STakashi Iwai spec->master[i]);
512aed058e8SSimone Zinanni change = 1;
513aed058e8SSimone Zinanni }
514aed058e8SSimone Zinanni }
515aed058e8SSimone Zinanni snd_ice1712_restore_gpio_status(ice);
516aed058e8SSimone Zinanni return change;
517aed058e8SSimone Zinanni }
518aed058e8SSimone Zinanni
519aed058e8SSimone Zinanni /*
520aed058e8SSimone Zinanni * WM8770 mute control
521aed058e8SSimone Zinanni */
wm_mute_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)522cc67b7f7SVedran Miletic static int wm_mute_info(struct snd_kcontrol *kcontrol,
523cc67b7f7SVedran Miletic struct snd_ctl_elem_info *uinfo) {
524aed058e8SSimone Zinanni uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
525aed058e8SSimone Zinanni uinfo->count = kcontrol->private_value >> 8;
526aed058e8SSimone Zinanni uinfo->value.integer.min = 0;
527aed058e8SSimone Zinanni uinfo->value.integer.max = 1;
528aed058e8SSimone Zinanni return 0;
529aed058e8SSimone Zinanni }
530aed058e8SSimone Zinanni
wm_mute_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)531cc67b7f7SVedran Miletic static int wm_mute_get(struct snd_kcontrol *kcontrol,
532cc67b7f7SVedran Miletic struct snd_ctl_elem_value *ucontrol)
533aed058e8SSimone Zinanni {
534ab0c7d72STakashi Iwai struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
5357cda8ba9STakashi Iwai struct phase28_spec *spec = ice->spec;
536aed058e8SSimone Zinanni int voices, ofs, i;
537aed058e8SSimone Zinanni
538aed058e8SSimone Zinanni voices = kcontrol->private_value >> 8;
539aed058e8SSimone Zinanni ofs = kcontrol->private_value & 0xFF;
540aed058e8SSimone Zinanni
541aed058e8SSimone Zinanni for (i = 0; i < voices; i++)
5427cda8ba9STakashi Iwai ucontrol->value.integer.value[i] =
5437cda8ba9STakashi Iwai (spec->vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1;
544aed058e8SSimone Zinanni return 0;
545aed058e8SSimone Zinanni }
546aed058e8SSimone Zinanni
wm_mute_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)547cc67b7f7SVedran Miletic static int wm_mute_put(struct snd_kcontrol *kcontrol,
548cc67b7f7SVedran Miletic struct snd_ctl_elem_value *ucontrol)
549aed058e8SSimone Zinanni {
550ab0c7d72STakashi Iwai struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
5517cda8ba9STakashi Iwai struct phase28_spec *spec = ice->spec;
552aed058e8SSimone Zinanni int change = 0, voices, ofs, i;
553aed058e8SSimone Zinanni
554aed058e8SSimone Zinanni voices = kcontrol->private_value >> 8;
555aed058e8SSimone Zinanni ofs = kcontrol->private_value & 0xFF;
556aed058e8SSimone Zinanni
557aed058e8SSimone Zinanni snd_ice1712_save_gpio_status(ice);
558aed058e8SSimone Zinanni for (i = 0; i < voices; i++) {
5597cda8ba9STakashi Iwai int val = (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
560aed058e8SSimone Zinanni if (ucontrol->value.integer.value[i] != val) {
5617cda8ba9STakashi Iwai spec->vol[ofs + i] &= ~WM_VOL_MUTE;
5627cda8ba9STakashi Iwai spec->vol[ofs + i] |=
563cc67b7f7SVedran Miletic ucontrol->value.integer.value[i] ? 0 :
564cc67b7f7SVedran Miletic WM_VOL_MUTE;
5657cda8ba9STakashi Iwai wm_set_vol(ice, ofs + i, spec->vol[ofs + i],
5667cda8ba9STakashi Iwai spec->master[i]);
567aed058e8SSimone Zinanni change = 1;
568aed058e8SSimone Zinanni }
569aed058e8SSimone Zinanni }
570aed058e8SSimone Zinanni snd_ice1712_restore_gpio_status(ice);
571aed058e8SSimone Zinanni
572aed058e8SSimone Zinanni return change;
573aed058e8SSimone Zinanni }
574aed058e8SSimone Zinanni
575aed058e8SSimone Zinanni /*
576aed058e8SSimone Zinanni * WM8770 master mute control
577aed058e8SSimone Zinanni */
578a5ce8890STakashi Iwai #define wm_master_mute_info snd_ctl_boolean_stereo_info
579aed058e8SSimone Zinanni
wm_master_mute_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)580cc67b7f7SVedran Miletic static int wm_master_mute_get(struct snd_kcontrol *kcontrol,
581cc67b7f7SVedran Miletic struct snd_ctl_elem_value *ucontrol)
582aed058e8SSimone Zinanni {
583ab0c7d72STakashi Iwai struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
5847cda8ba9STakashi Iwai struct phase28_spec *spec = ice->spec;
585aed058e8SSimone Zinanni
5867cda8ba9STakashi Iwai ucontrol->value.integer.value[0] =
5877cda8ba9STakashi Iwai (spec->master[0] & WM_VOL_MUTE) ? 0 : 1;
5887cda8ba9STakashi Iwai ucontrol->value.integer.value[1] =
5897cda8ba9STakashi Iwai (spec->master[1] & WM_VOL_MUTE) ? 0 : 1;
590aed058e8SSimone Zinanni return 0;
591aed058e8SSimone Zinanni }
592aed058e8SSimone Zinanni
wm_master_mute_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)593cc67b7f7SVedran Miletic static int wm_master_mute_put(struct snd_kcontrol *kcontrol,
594cc67b7f7SVedran Miletic struct snd_ctl_elem_value *ucontrol)
595aed058e8SSimone Zinanni {
596ab0c7d72STakashi Iwai struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
5977cda8ba9STakashi Iwai struct phase28_spec *spec = ice->spec;
598aed058e8SSimone Zinanni int change = 0, i;
599aed058e8SSimone Zinanni
600aed058e8SSimone Zinanni snd_ice1712_save_gpio_status(ice);
601aed058e8SSimone Zinanni for (i = 0; i < 2; i++) {
6027cda8ba9STakashi Iwai int val = (spec->master[i] & WM_VOL_MUTE) ? 0 : 1;
603aed058e8SSimone Zinanni if (ucontrol->value.integer.value[i] != val) {
604aed058e8SSimone Zinanni int dac;
6057cda8ba9STakashi Iwai spec->master[i] &= ~WM_VOL_MUTE;
6067cda8ba9STakashi Iwai spec->master[i] |=
607cc67b7f7SVedran Miletic ucontrol->value.integer.value[i] ? 0 :
608cc67b7f7SVedran Miletic WM_VOL_MUTE;
609aed058e8SSimone Zinanni for (dac = 0; dac < ice->num_total_dacs; dac += 2)
610aed058e8SSimone Zinanni wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
6117cda8ba9STakashi Iwai spec->vol[dac + i],
6127cda8ba9STakashi Iwai spec->master[i]);
613aed058e8SSimone Zinanni change = 1;
614aed058e8SSimone Zinanni }
615aed058e8SSimone Zinanni }
616aed058e8SSimone Zinanni snd_ice1712_restore_gpio_status(ice);
617aed058e8SSimone Zinanni
618aed058e8SSimone Zinanni return change;
619aed058e8SSimone Zinanni }
620aed058e8SSimone Zinanni
621aed058e8SSimone Zinanni /* digital master volume */
622aed058e8SSimone Zinanni #define PCM_0dB 0xff
623aed058e8SSimone Zinanni #define PCM_RES 128 /* -64dB */
624aed058e8SSimone Zinanni #define PCM_MIN (PCM_0dB - PCM_RES)
wm_pcm_vol_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)625cc67b7f7SVedran Miletic static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol,
626cc67b7f7SVedran Miletic struct snd_ctl_elem_info *uinfo)
627aed058e8SSimone Zinanni {
628aed058e8SSimone Zinanni uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
629aed058e8SSimone Zinanni uinfo->count = 1;
630aed058e8SSimone Zinanni uinfo->value.integer.min = 0; /* mute (-64dB) */
631aed058e8SSimone Zinanni uinfo->value.integer.max = PCM_RES; /* 0dB */
632aed058e8SSimone Zinanni return 0;
633aed058e8SSimone Zinanni }
634aed058e8SSimone Zinanni
wm_pcm_vol_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)635cc67b7f7SVedran Miletic static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol,
636cc67b7f7SVedran Miletic struct snd_ctl_elem_value *ucontrol)
637aed058e8SSimone Zinanni {
638ab0c7d72STakashi Iwai struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
639aed058e8SSimone Zinanni unsigned short val;
640aed058e8SSimone Zinanni
64162932df8SIngo Molnar mutex_lock(&ice->gpio_mutex);
642aed058e8SSimone Zinanni val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
643aed058e8SSimone Zinanni val = val > PCM_MIN ? (val - PCM_MIN) : 0;
644aed058e8SSimone Zinanni ucontrol->value.integer.value[0] = val;
64562932df8SIngo Molnar mutex_unlock(&ice->gpio_mutex);
646aed058e8SSimone Zinanni return 0;
647aed058e8SSimone Zinanni }
648aed058e8SSimone Zinanni
wm_pcm_vol_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)649cc67b7f7SVedran Miletic static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol,
650cc67b7f7SVedran Miletic struct snd_ctl_elem_value *ucontrol)
651aed058e8SSimone Zinanni {
652ab0c7d72STakashi Iwai struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
653aed058e8SSimone Zinanni unsigned short ovol, nvol;
654aed058e8SSimone Zinanni int change = 0;
655aed058e8SSimone Zinanni
656aed058e8SSimone Zinanni nvol = ucontrol->value.integer.value[0];
6579cd17cd2STakashi Iwai if (nvol > PCM_RES)
6589cd17cd2STakashi Iwai return -EINVAL;
6599cd17cd2STakashi Iwai snd_ice1712_save_gpio_status(ice);
660aed058e8SSimone Zinanni nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff;
661aed058e8SSimone Zinanni ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
662aed058e8SSimone Zinanni if (ovol != nvol) {
663aed058e8SSimone Zinanni wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */
664cc67b7f7SVedran Miletic /* update */
665cc67b7f7SVedran Miletic wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100);
666aed058e8SSimone Zinanni change = 1;
667aed058e8SSimone Zinanni }
668aed058e8SSimone Zinanni snd_ice1712_restore_gpio_status(ice);
669aed058e8SSimone Zinanni return change;
670aed058e8SSimone Zinanni }
671aed058e8SSimone Zinanni
672aed058e8SSimone Zinanni /*
673aed058e8SSimone Zinanni * Deemphasis
674aed058e8SSimone Zinanni */
675a5ce8890STakashi Iwai #define phase28_deemp_info snd_ctl_boolean_mono_info
676aed058e8SSimone Zinanni
phase28_deemp_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)677cc67b7f7SVedran Miletic static int phase28_deemp_get(struct snd_kcontrol *kcontrol,
678cc67b7f7SVedran Miletic struct snd_ctl_elem_value *ucontrol)
679aed058e8SSimone Zinanni {
680ab0c7d72STakashi Iwai struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
681cc67b7f7SVedran Miletic ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) ==
682cc67b7f7SVedran Miletic 0xf;
683aed058e8SSimone Zinanni return 0;
684aed058e8SSimone Zinanni }
685aed058e8SSimone Zinanni
phase28_deemp_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)686cc67b7f7SVedran Miletic static int phase28_deemp_put(struct snd_kcontrol *kcontrol,
687cc67b7f7SVedran Miletic struct snd_ctl_elem_value *ucontrol)
688aed058e8SSimone Zinanni {
689ab0c7d72STakashi Iwai struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
690aed058e8SSimone Zinanni int temp, temp2;
691cc67b7f7SVedran Miletic temp = wm_get(ice, WM_DAC_CTRL2);
692cc67b7f7SVedran Miletic temp2 = temp;
693aed058e8SSimone Zinanni if (ucontrol->value.integer.value[0])
694aed058e8SSimone Zinanni temp |= 0xf;
695aed058e8SSimone Zinanni else
696aed058e8SSimone Zinanni temp &= ~0xf;
697aed058e8SSimone Zinanni if (temp != temp2) {
698aed058e8SSimone Zinanni wm_put(ice, WM_DAC_CTRL2, temp);
699aed058e8SSimone Zinanni return 1;
700aed058e8SSimone Zinanni }
701aed058e8SSimone Zinanni return 0;
702aed058e8SSimone Zinanni }
703aed058e8SSimone Zinanni
704aed058e8SSimone Zinanni /*
705aed058e8SSimone Zinanni * ADC Oversampling
706aed058e8SSimone Zinanni */
phase28_oversampling_info(struct snd_kcontrol * k,struct snd_ctl_elem_info * uinfo)707cc67b7f7SVedran Miletic static int phase28_oversampling_info(struct snd_kcontrol *k,
708cc67b7f7SVedran Miletic struct snd_ctl_elem_info *uinfo)
709aed058e8SSimone Zinanni {
710a2af050fSTakashi Iwai static const char * const texts[2] = { "128x", "64x" };
711aed058e8SSimone Zinanni
712597da2e4STakashi Iwai return snd_ctl_enum_info(uinfo, 1, 2, texts);
713aed058e8SSimone Zinanni }
714aed058e8SSimone Zinanni
phase28_oversampling_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)715cc67b7f7SVedran Miletic static int phase28_oversampling_get(struct snd_kcontrol *kcontrol,
716cc67b7f7SVedran Miletic struct snd_ctl_elem_value *ucontrol)
717aed058e8SSimone Zinanni {
718ab0c7d72STakashi Iwai struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
719cc67b7f7SVedran Miletic ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) ==
720cc67b7f7SVedran Miletic 0x8;
721aed058e8SSimone Zinanni return 0;
722aed058e8SSimone Zinanni }
723aed058e8SSimone Zinanni
phase28_oversampling_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)724cc67b7f7SVedran Miletic static int phase28_oversampling_put(struct snd_kcontrol *kcontrol,
725cc67b7f7SVedran Miletic struct snd_ctl_elem_value *ucontrol)
726aed058e8SSimone Zinanni {
727aed058e8SSimone Zinanni int temp, temp2;
728ab0c7d72STakashi Iwai struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
729aed058e8SSimone Zinanni
730cc67b7f7SVedran Miletic temp = wm_get(ice, WM_MASTER);
731cc67b7f7SVedran Miletic temp2 = temp;
732aed058e8SSimone Zinanni
733aed058e8SSimone Zinanni if (ucontrol->value.enumerated.item[0])
734aed058e8SSimone Zinanni temp |= 0x8;
735aed058e8SSimone Zinanni else
736aed058e8SSimone Zinanni temp &= ~0x8;
737aed058e8SSimone Zinanni
738aed058e8SSimone Zinanni if (temp != temp2) {
739aed058e8SSimone Zinanni wm_put(ice, WM_MASTER, temp);
740aed058e8SSimone Zinanni return 1;
741aed058e8SSimone Zinanni }
742aed058e8SSimone Zinanni return 0;
743aed058e8SSimone Zinanni }
744aed058e8SSimone Zinanni
7450cb29ea0STakashi Iwai static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
7460cb29ea0STakashi Iwai static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
747f640c320STakashi Iwai
748b4e5e707STakashi Iwai static const struct snd_kcontrol_new phase28_dac_controls[] = {
749aed058e8SSimone Zinanni {
750aed058e8SSimone Zinanni .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
751aed058e8SSimone Zinanni .name = "Master Playback Switch",
752aed058e8SSimone Zinanni .info = wm_master_mute_info,
753aed058e8SSimone Zinanni .get = wm_master_mute_get,
754aed058e8SSimone Zinanni .put = wm_master_mute_put
755aed058e8SSimone Zinanni },
756aed058e8SSimone Zinanni {
757aed058e8SSimone Zinanni .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
758f640c320STakashi Iwai .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
759f640c320STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_READ),
760aed058e8SSimone Zinanni .name = "Master Playback Volume",
761aed058e8SSimone Zinanni .info = wm_master_vol_info,
762aed058e8SSimone Zinanni .get = wm_master_vol_get,
763f640c320STakashi Iwai .put = wm_master_vol_put,
764f640c320STakashi Iwai .tlv = { .p = db_scale_wm_dac }
765aed058e8SSimone Zinanni },
766aed058e8SSimone Zinanni {
767aed058e8SSimone Zinanni .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
768aed058e8SSimone Zinanni .name = "Front Playback Switch",
769aed058e8SSimone Zinanni .info = wm_mute_info,
770aed058e8SSimone Zinanni .get = wm_mute_get,
771aed058e8SSimone Zinanni .put = wm_mute_put,
772aed058e8SSimone Zinanni .private_value = (2 << 8) | 0
773aed058e8SSimone Zinanni },
774aed058e8SSimone Zinanni {
775aed058e8SSimone Zinanni .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
776f640c320STakashi Iwai .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
777f640c320STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_READ),
778aed058e8SSimone Zinanni .name = "Front Playback Volume",
779aed058e8SSimone Zinanni .info = wm_vol_info,
780aed058e8SSimone Zinanni .get = wm_vol_get,
781aed058e8SSimone Zinanni .put = wm_vol_put,
782f640c320STakashi Iwai .private_value = (2 << 8) | 0,
783f640c320STakashi Iwai .tlv = { .p = db_scale_wm_dac }
784aed058e8SSimone Zinanni },
785aed058e8SSimone Zinanni {
786aed058e8SSimone Zinanni .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
787aed058e8SSimone Zinanni .name = "Rear Playback Switch",
788aed058e8SSimone Zinanni .info = wm_mute_info,
789aed058e8SSimone Zinanni .get = wm_mute_get,
790aed058e8SSimone Zinanni .put = wm_mute_put,
791aed058e8SSimone Zinanni .private_value = (2 << 8) | 2
792aed058e8SSimone Zinanni },
793aed058e8SSimone Zinanni {
794aed058e8SSimone Zinanni .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
795f640c320STakashi Iwai .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
796f640c320STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_READ),
797aed058e8SSimone Zinanni .name = "Rear Playback Volume",
798aed058e8SSimone Zinanni .info = wm_vol_info,
799aed058e8SSimone Zinanni .get = wm_vol_get,
800aed058e8SSimone Zinanni .put = wm_vol_put,
801f640c320STakashi Iwai .private_value = (2 << 8) | 2,
802f640c320STakashi Iwai .tlv = { .p = db_scale_wm_dac }
803aed058e8SSimone Zinanni },
804aed058e8SSimone Zinanni {
805aed058e8SSimone Zinanni .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
806aed058e8SSimone Zinanni .name = "Center Playback Switch",
807aed058e8SSimone Zinanni .info = wm_mute_info,
808aed058e8SSimone Zinanni .get = wm_mute_get,
809aed058e8SSimone Zinanni .put = wm_mute_put,
810aed058e8SSimone Zinanni .private_value = (1 << 8) | 4
811aed058e8SSimone Zinanni },
812aed058e8SSimone Zinanni {
813aed058e8SSimone Zinanni .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
814f640c320STakashi Iwai .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
815f640c320STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_READ),
816aed058e8SSimone Zinanni .name = "Center Playback Volume",
817aed058e8SSimone Zinanni .info = wm_vol_info,
818aed058e8SSimone Zinanni .get = wm_vol_get,
819aed058e8SSimone Zinanni .put = wm_vol_put,
820f640c320STakashi Iwai .private_value = (1 << 8) | 4,
821f640c320STakashi Iwai .tlv = { .p = db_scale_wm_dac }
822aed058e8SSimone Zinanni },
823aed058e8SSimone Zinanni {
824aed058e8SSimone Zinanni .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
825aed058e8SSimone Zinanni .name = "LFE Playback Switch",
826aed058e8SSimone Zinanni .info = wm_mute_info,
827aed058e8SSimone Zinanni .get = wm_mute_get,
828aed058e8SSimone Zinanni .put = wm_mute_put,
829aed058e8SSimone Zinanni .private_value = (1 << 8) | 5
830aed058e8SSimone Zinanni },
831aed058e8SSimone Zinanni {
832aed058e8SSimone Zinanni .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
833f640c320STakashi Iwai .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
834f640c320STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_READ),
835aed058e8SSimone Zinanni .name = "LFE Playback Volume",
836aed058e8SSimone Zinanni .info = wm_vol_info,
837aed058e8SSimone Zinanni .get = wm_vol_get,
838aed058e8SSimone Zinanni .put = wm_vol_put,
839f640c320STakashi Iwai .private_value = (1 << 8) | 5,
840f640c320STakashi Iwai .tlv = { .p = db_scale_wm_dac }
841aed058e8SSimone Zinanni },
842aed058e8SSimone Zinanni {
843aed058e8SSimone Zinanni .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
844aed058e8SSimone Zinanni .name = "Side Playback Switch",
845aed058e8SSimone Zinanni .info = wm_mute_info,
846aed058e8SSimone Zinanni .get = wm_mute_get,
847aed058e8SSimone Zinanni .put = wm_mute_put,
848aed058e8SSimone Zinanni .private_value = (2 << 8) | 6
849aed058e8SSimone Zinanni },
850aed058e8SSimone Zinanni {
851aed058e8SSimone Zinanni .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
852f640c320STakashi Iwai .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
853f640c320STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_READ),
854aed058e8SSimone Zinanni .name = "Side Playback Volume",
855aed058e8SSimone Zinanni .info = wm_vol_info,
856aed058e8SSimone Zinanni .get = wm_vol_get,
857aed058e8SSimone Zinanni .put = wm_vol_put,
858f640c320STakashi Iwai .private_value = (2 << 8) | 6,
859f640c320STakashi Iwai .tlv = { .p = db_scale_wm_dac }
860aed058e8SSimone Zinanni }
861aed058e8SSimone Zinanni };
862aed058e8SSimone Zinanni
863b4e5e707STakashi Iwai static const struct snd_kcontrol_new wm_controls[] = {
864aed058e8SSimone Zinanni {
865aed058e8SSimone Zinanni .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
866aed058e8SSimone Zinanni .name = "PCM Playback Switch",
867aed058e8SSimone Zinanni .info = wm_pcm_mute_info,
868aed058e8SSimone Zinanni .get = wm_pcm_mute_get,
869aed058e8SSimone Zinanni .put = wm_pcm_mute_put
870aed058e8SSimone Zinanni },
871aed058e8SSimone Zinanni {
872aed058e8SSimone Zinanni .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
873f640c320STakashi Iwai .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
874f640c320STakashi Iwai SNDRV_CTL_ELEM_ACCESS_TLV_READ),
875aed058e8SSimone Zinanni .name = "PCM Playback Volume",
876aed058e8SSimone Zinanni .info = wm_pcm_vol_info,
877aed058e8SSimone Zinanni .get = wm_pcm_vol_get,
878f640c320STakashi Iwai .put = wm_pcm_vol_put,
879f640c320STakashi Iwai .tlv = { .p = db_scale_wm_pcm }
880aed058e8SSimone Zinanni },
881aed058e8SSimone Zinanni {
882aed058e8SSimone Zinanni .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
883aed058e8SSimone Zinanni .name = "DAC Deemphasis Switch",
884aed058e8SSimone Zinanni .info = phase28_deemp_info,
885aed058e8SSimone Zinanni .get = phase28_deemp_get,
886aed058e8SSimone Zinanni .put = phase28_deemp_put
887aed058e8SSimone Zinanni },
888aed058e8SSimone Zinanni {
889aed058e8SSimone Zinanni .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
890aed058e8SSimone Zinanni .name = "ADC Oversampling",
891aed058e8SSimone Zinanni .info = phase28_oversampling_info,
892aed058e8SSimone Zinanni .get = phase28_oversampling_get,
893aed058e8SSimone Zinanni .put = phase28_oversampling_put
894aed058e8SSimone Zinanni }
895aed058e8SSimone Zinanni };
896aed058e8SSimone Zinanni
phase28_add_controls(struct snd_ice1712 * ice)897e23e7a14SBill Pemberton static int phase28_add_controls(struct snd_ice1712 *ice)
898aed058e8SSimone Zinanni {
899aed058e8SSimone Zinanni unsigned int i, counts;
900aed058e8SSimone Zinanni int err;
901aed058e8SSimone Zinanni
902aed058e8SSimone Zinanni counts = ARRAY_SIZE(phase28_dac_controls);
903aed058e8SSimone Zinanni for (i = 0; i < counts; i++) {
904cc67b7f7SVedran Miletic err = snd_ctl_add(ice->card,
905cc67b7f7SVedran Miletic snd_ctl_new1(&phase28_dac_controls[i],
906cc67b7f7SVedran Miletic ice));
907aed058e8SSimone Zinanni if (err < 0)
908aed058e8SSimone Zinanni return err;
909aed058e8SSimone Zinanni }
910aed058e8SSimone Zinanni
911aed058e8SSimone Zinanni for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
912cc67b7f7SVedran Miletic err = snd_ctl_add(ice->card,
913cc67b7f7SVedran Miletic snd_ctl_new1(&wm_controls[i], ice));
914aed058e8SSimone Zinanni if (err < 0)
915aed058e8SSimone Zinanni return err;
916aed058e8SSimone Zinanni }
917aed058e8SSimone Zinanni
918aed058e8SSimone Zinanni return 0;
919aed058e8SSimone Zinanni }
920aed058e8SSimone Zinanni
921e23e7a14SBill Pemberton struct snd_ice1712_card_info snd_vt1724_phase_cards[] = {
9221da177e4SLinus Torvalds {
9231da177e4SLinus Torvalds .subvendor = VT1724_SUBDEVICE_PHASE22,
9241da177e4SLinus Torvalds .name = "Terratec PHASE 22",
9251da177e4SLinus Torvalds .model = "phase22",
9261da177e4SLinus Torvalds .chip_init = phase22_init,
9271da177e4SLinus Torvalds .build_controls = phase22_add_controls,
9281da177e4SLinus Torvalds .eeprom_size = sizeof(phase22_eeprom),
9291da177e4SLinus Torvalds .eeprom_data = phase22_eeprom,
9301da177e4SLinus Torvalds },
931aed058e8SSimone Zinanni {
932aed058e8SSimone Zinanni .subvendor = VT1724_SUBDEVICE_PHASE28,
933aed058e8SSimone Zinanni .name = "Terratec PHASE 28",
934aed058e8SSimone Zinanni .model = "phase28",
935aed058e8SSimone Zinanni .chip_init = phase28_init,
936aed058e8SSimone Zinanni .build_controls = phase28_add_controls,
937aed058e8SSimone Zinanni .eeprom_size = sizeof(phase28_eeprom),
938aed058e8SSimone Zinanni .eeprom_data = phase28_eeprom,
939aed058e8SSimone Zinanni },
940740dc9c4SMisha Zhilin {
941740dc9c4SMisha Zhilin .subvendor = VT1724_SUBDEVICE_TS22,
942740dc9c4SMisha Zhilin .name = "Terrasoniq TS22 PCI",
943740dc9c4SMisha Zhilin .model = "TS22",
944740dc9c4SMisha Zhilin .chip_init = phase22_init,
945740dc9c4SMisha Zhilin .build_controls = phase22_add_controls,
946740dc9c4SMisha Zhilin .eeprom_size = sizeof(phase22_eeprom),
947740dc9c4SMisha Zhilin .eeprom_data = phase22_eeprom,
948740dc9c4SMisha Zhilin },
9491da177e4SLinus Torvalds { } /* terminator */
9501da177e4SLinus Torvalds };
951