blob: de29be8c96574e8bd89eacf81b9aee5eb8a51518 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * ALSA driver for ICEnsemble ICE1724 (Envy24)
3 *
4 * Lowlevel functions for Terratec PHASE 22
5 *
6 * Copyright (c) 2005 Misha Zhilin <misha@epiphan.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24/* PHASE 22 overview:
Vedran Mileticeee75a62008-08-29 18:31:13 +020025 * Audio controller: VIA Envy24HT-S (slightly trimmed down Envy24HT, 4in/4out)
Linus Torvalds1da177e2005-04-16 15:20:36 -070026 * Analog chip: AK4524 (partially via Philip's 74HCT125)
Vedran Mileticeee75a62008-08-29 18:31:13 +020027 * Digital receiver: CS8414-CS (supported in this release)
28 * PHASE 22 revision 2.0 and Terrasoniq/Musonik TS22PCI have CS8416
29 * (support status unknown, please test and report)
Linus Torvalds1da177e2005-04-16 15:20:36 -070030 *
31 * Envy connects to AK4524
32 * - CS directly from GPIO 10
33 * - CCLK via 74HCT125's gate #4 from GPIO 4
34 * - CDTI via 74HCT125's gate #2 from GPIO 5
Vedran Mileticeee75a62008-08-29 18:31:13 +020035 * CDTI may be completely blocked by 74HCT125's gate #1
36 * controlled by GPIO 3
37 */
38
39/* PHASE 28 overview:
Vedran Mileticcc67b7f2008-09-07 12:00:02 +020040 * Audio controller: VIA Envy24HT (full untrimmed version, 4in/8out)
Vedran Mileticeee75a62008-08-29 18:31:13 +020041 * Analog chip: WM8770 (8 channel 192k DAC, 2 channel 96k ADC)
42 * Digital receiver: CS8414-CS (supported in this release)
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 */
44
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include <asm/io.h>
46#include <linux/delay.h>
47#include <linux/interrupt.h>
48#include <linux/init.h>
49#include <linux/slab.h>
Ingo Molnar62932df2006-01-16 16:34:20 +010050#include <linux/mutex.h>
51
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <sound/core.h>
53
54#include "ice1712.h"
55#include "envy24ht.h"
56#include "phase.h"
Takashi Iwaif640c322006-08-30 16:57:37 +020057#include <sound/tlv.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
Takashi Iwai7cda8ba2008-01-18 13:36:07 +010059/* AC97 register cache for Phase28 */
60struct phase28_spec {
61 unsigned short master[2];
62 unsigned short vol[8];
Harvey Harrison008f3592008-02-29 11:46:32 +010063};
Takashi Iwai7cda8ba2008-01-18 13:36:07 +010064
Simone Zinanniaed058e2005-04-11 14:08:40 +020065/* WM8770 registers */
66#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */
67#define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */
68#define WM_DAC_DIG_ATTEN 0x09 /* DAC1-8 digital attenuation */
69#define WM_DAC_DIG_MASTER_ATTEN 0x11 /* DAC master digital attenuation */
70#define WM_PHASE_SWAP 0x12 /* DAC phase */
71#define WM_DAC_CTRL1 0x13 /* DAC control bits */
72#define WM_MUTE 0x14 /* mute controls */
73#define WM_DAC_CTRL2 0x15 /* de-emphasis and zefo-flag */
74#define WM_INT_CTRL 0x16 /* interface control */
75#define WM_MASTER 0x17 /* master clock and mode */
76#define WM_POWERDOWN 0x18 /* power-down controls */
77#define WM_ADC_GAIN 0x19 /* ADC gain L(19)/R(1a) */
78#define WM_ADC_MUX 0x1b /* input MUX */
79#define WM_OUT_MUX1 0x1c /* output MUX */
80#define WM_OUT_MUX2 0x1e /* output MUX */
81#define WM_RESET 0x1f /* software reset */
82
83
84/*
85 * Logarithmic volume values for WM8770
86 * Computed as 20 * Log10(255 / x)
87 */
Takashi Iwai32b47da2007-01-29 15:26:36 +010088static const unsigned char wm_vol[256] = {
Vedran Mileticcc67b7f2008-09-07 12:00:02 +020089 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24,
90 24, 23, 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18,
91 17, 17, 17, 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14,
92 14, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11,
93 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9,
94 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7,
95 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5,
96 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
97 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
98 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
99 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
100 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
Simone Zinanniaed058e2005-04-11 14:08:40 +0200101};
102
103#define WM_VOL_MAX (sizeof(wm_vol) - 1)
104#define WM_VOL_MUTE 0x8000
105
Takashi Iwai1b60f6b2007-03-13 22:13:47 +0100106static struct snd_akm4xxx akm_phase22 __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 .type = SND_AK4524,
108 .num_dacs = 2,
109 .num_adcs = 2,
110};
111
Takashi Iwai1b60f6b2007-03-13 22:13:47 +0100112static struct snd_ak4xxx_private akm_phase22_priv __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 .caddr = 2,
114 .cif = 1,
115 .data_mask = 1 << 4,
116 .clk_mask = 1 << 5,
117 .cs_mask = 1 << 10,
118 .cs_addr = 1 << 10,
119 .cs_none = 0,
120 .add_flags = 1 << 3,
121 .mask_flags = 0,
122};
123
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100124static int __devinit phase22_init(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100126 struct snd_akm4xxx *ak;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 int err;
128
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200129 /* Configure DAC/ADC description for generic part of ice1724 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 switch (ice->eeprom.subvendor) {
131 case VT1724_SUBDEVICE_PHASE22:
Misha Zhilin740dc9c2008-08-01 12:45:14 +0200132 case VT1724_SUBDEVICE_TS22:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 ice->num_total_dacs = 2;
134 ice->num_total_adcs = 2;
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200135 ice->vt1720 = 1; /* Envy24HT-S have 16 bit wide GPIO */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 break;
137 default:
138 snd_BUG();
139 return -EINVAL;
140 }
141
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200142 /* Initialize analog chips */
143 ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
144 ak = ice->akm;
145 if (!ak)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 return -ENOMEM;
147 ice->akm_codecs = 1;
148 switch (ice->eeprom.subvendor) {
149 case VT1724_SUBDEVICE_PHASE22:
Misha Zhilin740dc9c2008-08-01 12:45:14 +0200150 case VT1724_SUBDEVICE_TS22:
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200151 err = snd_ice1712_akm4xxx_init(ak, &akm_phase22,
152 &akm_phase22_priv, ice);
153 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 return err;
155 break;
156 }
157
158 return 0;
159}
160
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100161static int __devinit phase22_add_controls(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162{
163 int err = 0;
164
165 switch (ice->eeprom.subvendor) {
166 case VT1724_SUBDEVICE_PHASE22:
Misha Zhilin740dc9c2008-08-01 12:45:14 +0200167 case VT1724_SUBDEVICE_TS22:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 err = snd_ice1712_akm4xxx_build_controls(ice);
169 if (err < 0)
170 return err;
171 }
172 return 0;
173}
174
Takashi Iwai1b60f6b2007-03-13 22:13:47 +0100175static unsigned char phase22_eeprom[] __devinitdata = {
Vedran Mileticeee75a62008-08-29 18:31:13 +0200176 [ICE_EEP2_SYSCONF] = 0x28, /* clock 512, mpu 401,
177 spdif-in/1xADC, 1xDACs */
Takashi Iwai189bc172007-01-29 15:25:40 +0100178 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
Vedran Mileticeee75a62008-08-29 18:31:13 +0200179 [ICE_EEP2_I2S] = 0xf0, /* vol, 96k, 24bit */
Takashi Iwai189bc172007-01-29 15:25:40 +0100180 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
181 [ICE_EEP2_GPIO_DIR] = 0xff,
182 [ICE_EEP2_GPIO_DIR1] = 0xff,
183 [ICE_EEP2_GPIO_DIR2] = 0xff,
184 [ICE_EEP2_GPIO_MASK] = 0x00,
185 [ICE_EEP2_GPIO_MASK1] = 0x00,
186 [ICE_EEP2_GPIO_MASK2] = 0x00,
187 [ICE_EEP2_GPIO_STATE] = 0x00,
188 [ICE_EEP2_GPIO_STATE1] = 0x00,
189 [ICE_EEP2_GPIO_STATE2] = 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190};
191
Takashi Iwai1b60f6b2007-03-13 22:13:47 +0100192static unsigned char phase28_eeprom[] __devinitdata = {
Vedran Mileticeee75a62008-08-29 18:31:13 +0200193 [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401,
194 spdif-in/1xADC, 4xDACs */
Takashi Iwai189bc172007-01-29 15:25:40 +0100195 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
196 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
197 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
198 [ICE_EEP2_GPIO_DIR] = 0xff,
199 [ICE_EEP2_GPIO_DIR1] = 0xff,
200 [ICE_EEP2_GPIO_DIR2] = 0x5f,
201 [ICE_EEP2_GPIO_MASK] = 0x00,
202 [ICE_EEP2_GPIO_MASK1] = 0x00,
203 [ICE_EEP2_GPIO_MASK2] = 0x00,
204 [ICE_EEP2_GPIO_STATE] = 0x00,
205 [ICE_EEP2_GPIO_STATE1] = 0x00,
206 [ICE_EEP2_GPIO_STATE2] = 0x00,
Simone Zinanniaed058e2005-04-11 14:08:40 +0200207};
208
209/*
210 * write data in the SPI mode
211 */
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200212static void phase28_spi_write(struct snd_ice1712 *ice, unsigned int cs,
213 unsigned int data, int bits)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200214{
215 unsigned int tmp;
216 int i;
217
218 tmp = snd_ice1712_gpio_read(ice);
219
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200220 snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RW|PHASE28_SPI_MOSI|
221 PHASE28_SPI_CLK|PHASE28_WM_CS));
Simone Zinanniaed058e2005-04-11 14:08:40 +0200222 tmp |= PHASE28_WM_RW;
223 tmp &= ~cs;
224 snd_ice1712_gpio_write(ice, tmp);
225 udelay(1);
226
227 for (i = bits - 1; i >= 0; i--) {
228 tmp &= ~PHASE28_SPI_CLK;
229 snd_ice1712_gpio_write(ice, tmp);
230 udelay(1);
231 if (data & (1 << i))
232 tmp |= PHASE28_SPI_MOSI;
233 else
234 tmp &= ~PHASE28_SPI_MOSI;
235 snd_ice1712_gpio_write(ice, tmp);
236 udelay(1);
237 tmp |= PHASE28_SPI_CLK;
238 snd_ice1712_gpio_write(ice, tmp);
239 udelay(1);
240 }
241
242 tmp &= ~PHASE28_SPI_CLK;
243 tmp |= cs;
244 snd_ice1712_gpio_write(ice, tmp);
245 udelay(1);
246 tmp |= PHASE28_SPI_CLK;
247 snd_ice1712_gpio_write(ice, tmp);
248 udelay(1);
249}
250
251/*
252 * get the current register value of WM codec
253 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100254static unsigned short wm_get(struct snd_ice1712 *ice, int reg)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200255{
256 reg <<= 1;
257 return ((unsigned short)ice->akm[0].images[reg] << 8) |
258 ice->akm[0].images[reg + 1];
259}
260
261/*
262 * set the register value of WM codec
263 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100264static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200265{
266 phase28_spi_write(ice, PHASE28_WM_CS, (reg << 9) | (val & 0x1ff), 16);
267}
268
269/*
270 * set the register value of WM codec and remember it
271 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100272static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200273{
274 wm_put_nocache(ice, reg, val);
275 reg <<= 1;
276 ice->akm[0].images[reg] = val >> 8;
277 ice->akm[0].images[reg + 1] = val;
278}
279
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200280static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index,
281 unsigned short vol, unsigned short master)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200282{
283 unsigned char nvol;
284
285 if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
286 nvol = 0;
287 else
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200288 nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) *
289 (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX];
Simone Zinanniaed058e2005-04-11 14:08:40 +0200290
291 wm_put(ice, index, nvol);
292 wm_put_nocache(ice, index, 0x180 | nvol);
293}
294
295/*
296 * DAC mute control
297 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200298#define wm_pcm_mute_info snd_ctl_boolean_mono_info
Simone Zinanniaed058e2005-04-11 14:08:40 +0200299
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200300static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol,
301 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200302{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100303 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200304
Ingo Molnar62932df2006-01-16 16:34:20 +0100305 mutex_lock(&ice->gpio_mutex);
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200306 ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ?
307 0 : 1;
Ingo Molnar62932df2006-01-16 16:34:20 +0100308 mutex_unlock(&ice->gpio_mutex);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200309 return 0;
310}
311
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200312static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol,
313 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200314{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100315 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200316 unsigned short nval, oval;
317 int change;
318
319 snd_ice1712_save_gpio_status(ice);
320 oval = wm_get(ice, WM_MUTE);
321 nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200322 change = (nval != oval);
323 if (change)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200324 wm_put(ice, WM_MUTE, nval);
325 snd_ice1712_restore_gpio_status(ice);
326
327 return change;
328}
329
330/*
331 * Master volume attenuation mixer control
332 */
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200333static int wm_master_vol_info(struct snd_kcontrol *kcontrol,
334 struct snd_ctl_elem_info *uinfo)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200335{
336 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
337 uinfo->count = 2;
338 uinfo->value.integer.min = 0;
339 uinfo->value.integer.max = WM_VOL_MAX;
340 return 0;
341}
342
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200343static int wm_master_vol_get(struct snd_kcontrol *kcontrol,
344 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200345{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100346 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100347 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200348 int i;
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200349 for (i = 0; i < 2; i++)
350 ucontrol->value.integer.value[i] = spec->master[i] &
351 ~WM_VOL_MUTE;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200352 return 0;
353}
354
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200355static int wm_master_vol_put(struct snd_kcontrol *kcontrol,
356 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200357{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100358 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100359 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200360 int ch, change = 0;
361
362 snd_ice1712_save_gpio_status(ice);
363 for (ch = 0; ch < 2; ch++) {
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100364 unsigned int vol = ucontrol->value.integer.value[ch];
365 if (vol > WM_VOL_MAX)
366 continue;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100367 vol |= spec->master[ch] & WM_VOL_MUTE;
368 if (vol != spec->master[ch]) {
Simone Zinanniaed058e2005-04-11 14:08:40 +0200369 int dac;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100370 spec->master[ch] = vol;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200371 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
372 wm_set_vol(ice, WM_DAC_ATTEN + dac + ch,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100373 spec->vol[dac + ch],
374 spec->master[ch]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200375 change = 1;
376 }
377 }
378 snd_ice1712_restore_gpio_status(ice);
379 return change;
380}
381
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100382static int __devinit phase28_init(struct snd_ice1712 *ice)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200383{
Takashi Iwai32b47da2007-01-29 15:26:36 +0100384 static const unsigned short wm_inits_phase28[] = {
Simone Zinanniaed058e2005-04-11 14:08:40 +0200385 /* These come first to reduce init pop noise */
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200386 0x1b, 0x044, /* ADC Mux (AC'97 source) */
387 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
388 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
Simone Zinanniaed058e2005-04-11 14:08:40 +0200389
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200390 0x18, 0x000, /* All power-up */
Simone Zinanniaed058e2005-04-11 14:08:40 +0200391
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200392 0x16, 0x122, /* I2S, normal polarity, 24bit */
393 0x17, 0x022, /* 256fs, slave mode */
394 0x00, 0, /* DAC1 analog mute */
395 0x01, 0, /* DAC2 analog mute */
396 0x02, 0, /* DAC3 analog mute */
397 0x03, 0, /* DAC4 analog mute */
398 0x04, 0, /* DAC5 analog mute */
399 0x05, 0, /* DAC6 analog mute */
400 0x06, 0, /* DAC7 analog mute */
401 0x07, 0, /* DAC8 analog mute */
402 0x08, 0x100, /* master analog mute */
403 0x09, 0xff, /* DAC1 digital full */
404 0x0a, 0xff, /* DAC2 digital full */
405 0x0b, 0xff, /* DAC3 digital full */
406 0x0c, 0xff, /* DAC4 digital full */
407 0x0d, 0xff, /* DAC5 digital full */
408 0x0e, 0xff, /* DAC6 digital full */
409 0x0f, 0xff, /* DAC7 digital full */
410 0x10, 0xff, /* DAC8 digital full */
411 0x11, 0x1ff, /* master digital full */
412 0x12, 0x000, /* phase normal */
413 0x13, 0x090, /* unmute DAC L/R */
414 0x14, 0x000, /* all unmute */
415 0x15, 0x000, /* no deemphasis, no ZFLG */
416 0x19, 0x000, /* -12dB ADC/L */
417 0x1a, 0x000, /* -12dB ADC/R */
Simone Zinanniaed058e2005-04-11 14:08:40 +0200418 (unsigned short)-1
419 };
420
421 unsigned int tmp;
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100422 struct snd_akm4xxx *ak;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100423 struct phase28_spec *spec;
Takashi Iwai32b47da2007-01-29 15:26:36 +0100424 const unsigned short *p;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200425 int i;
426
427 ice->num_total_dacs = 8;
428 ice->num_total_adcs = 2;
429
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100430 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
431 if (!spec)
432 return -ENOMEM;
433 ice->spec = spec;
434
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200435 /* Initialize analog chips */
436 ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
437 ak = ice->akm;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200438 if (!ak)
439 return -ENOMEM;
440 ice->akm_codecs = 1;
441
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200442 snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for time being */
Simone Zinanniaed058e2005-04-11 14:08:40 +0200443
444 /* reset the wm codec as the SPI mode */
445 snd_ice1712_save_gpio_status(ice);
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200446 snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RESET|PHASE28_WM_CS|
447 PHASE28_HP_SEL));
Simone Zinanniaed058e2005-04-11 14:08:40 +0200448
449 tmp = snd_ice1712_gpio_read(ice);
450 tmp &= ~PHASE28_WM_RESET;
451 snd_ice1712_gpio_write(ice, tmp);
452 udelay(1);
453 tmp |= PHASE28_WM_CS;
454 snd_ice1712_gpio_write(ice, tmp);
455 udelay(1);
456 tmp |= PHASE28_WM_RESET;
457 snd_ice1712_gpio_write(ice, tmp);
458 udelay(1);
459
460 p = wm_inits_phase28;
461 for (; *p != (unsigned short)-1; p += 2)
462 wm_put(ice, p[0], p[1]);
463
464 snd_ice1712_restore_gpio_status(ice);
465
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100466 spec->master[0] = WM_VOL_MUTE;
467 spec->master[1] = WM_VOL_MUTE;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200468 for (i = 0; i < ice->num_total_dacs; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100469 spec->vol[i] = WM_VOL_MUTE;
470 wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200471 }
472
473 return 0;
474}
475
476/*
477 * DAC volume attenuation mixer control
478 */
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200479static int wm_vol_info(struct snd_kcontrol *kcontrol,
480 struct snd_ctl_elem_info *uinfo)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200481{
482 int voices = kcontrol->private_value >> 8;
483 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
484 uinfo->count = voices;
485 uinfo->value.integer.min = 0; /* mute (-101dB) */
486 uinfo->value.integer.max = 0x7F; /* 0dB */
487 return 0;
488}
489
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200490static int wm_vol_get(struct snd_kcontrol *kcontrol,
491 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200492{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100493 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100494 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200495 int i, ofs, voices;
496
497 voices = kcontrol->private_value >> 8;
498 ofs = kcontrol->private_value & 0xff;
499 for (i = 0; i < voices; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100500 ucontrol->value.integer.value[i] =
501 spec->vol[ofs+i] & ~WM_VOL_MUTE;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200502 return 0;
503}
504
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200505static int wm_vol_put(struct snd_kcontrol *kcontrol,
506 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200507{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100508 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100509 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200510 int i, idx, ofs, voices;
511 int change = 0;
512
513 voices = kcontrol->private_value >> 8;
514 ofs = kcontrol->private_value & 0xff;
515 snd_ice1712_save_gpio_status(ice);
516 for (i = 0; i < voices; i++) {
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100517 unsigned int vol;
518 vol = ucontrol->value.integer.value[i];
519 if (vol > 0x7f)
520 continue;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100521 vol |= spec->vol[ofs+i] & WM_VOL_MUTE;
522 if (vol != spec->vol[ofs+i]) {
523 spec->vol[ofs+i] = vol;
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100524 idx = WM_DAC_ATTEN + ofs + i;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100525 wm_set_vol(ice, idx, spec->vol[ofs+i],
526 spec->master[i]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200527 change = 1;
528 }
529 }
530 snd_ice1712_restore_gpio_status(ice);
531 return change;
532}
533
534/*
535 * WM8770 mute control
536 */
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200537static int wm_mute_info(struct snd_kcontrol *kcontrol,
538 struct snd_ctl_elem_info *uinfo) {
Simone Zinanniaed058e2005-04-11 14:08:40 +0200539 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
540 uinfo->count = kcontrol->private_value >> 8;
541 uinfo->value.integer.min = 0;
542 uinfo->value.integer.max = 1;
543 return 0;
544}
545
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200546static int wm_mute_get(struct snd_kcontrol *kcontrol,
547 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200548{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100549 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100550 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200551 int voices, ofs, i;
552
553 voices = kcontrol->private_value >> 8;
554 ofs = kcontrol->private_value & 0xFF;
555
556 for (i = 0; i < voices; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100557 ucontrol->value.integer.value[i] =
558 (spec->vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200559 return 0;
560}
561
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200562static int wm_mute_put(struct snd_kcontrol *kcontrol,
563 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200564{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100565 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100566 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200567 int change = 0, voices, ofs, i;
568
569 voices = kcontrol->private_value >> 8;
570 ofs = kcontrol->private_value & 0xFF;
571
572 snd_ice1712_save_gpio_status(ice);
573 for (i = 0; i < voices; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100574 int val = (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200575 if (ucontrol->value.integer.value[i] != val) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100576 spec->vol[ofs + i] &= ~WM_VOL_MUTE;
577 spec->vol[ofs + i] |=
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200578 ucontrol->value.integer.value[i] ? 0 :
579 WM_VOL_MUTE;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100580 wm_set_vol(ice, ofs + i, spec->vol[ofs + i],
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200581 spec->master[i]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200582 change = 1;
583 }
584 }
585 snd_ice1712_restore_gpio_status(ice);
586
587 return change;
588}
589
590/*
591 * WM8770 master mute control
592 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200593#define wm_master_mute_info snd_ctl_boolean_stereo_info
Simone Zinanniaed058e2005-04-11 14:08:40 +0200594
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200595static int wm_master_mute_get(struct snd_kcontrol *kcontrol,
596 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200597{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100598 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100599 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200600
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100601 ucontrol->value.integer.value[0] =
602 (spec->master[0] & WM_VOL_MUTE) ? 0 : 1;
603 ucontrol->value.integer.value[1] =
604 (spec->master[1] & WM_VOL_MUTE) ? 0 : 1;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200605 return 0;
606}
607
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200608static int wm_master_mute_put(struct snd_kcontrol *kcontrol,
609 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200610{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100611 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100612 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200613 int change = 0, i;
614
615 snd_ice1712_save_gpio_status(ice);
616 for (i = 0; i < 2; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100617 int val = (spec->master[i] & WM_VOL_MUTE) ? 0 : 1;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200618 if (ucontrol->value.integer.value[i] != val) {
619 int dac;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100620 spec->master[i] &= ~WM_VOL_MUTE;
621 spec->master[i] |=
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200622 ucontrol->value.integer.value[i] ? 0 :
623 WM_VOL_MUTE;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200624 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
625 wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200626 spec->vol[dac + i],
627 spec->master[i]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200628 change = 1;
629 }
630 }
631 snd_ice1712_restore_gpio_status(ice);
632
633 return change;
634}
635
636/* digital master volume */
637#define PCM_0dB 0xff
638#define PCM_RES 128 /* -64dB */
639#define PCM_MIN (PCM_0dB - PCM_RES)
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200640static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol,
641 struct snd_ctl_elem_info *uinfo)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200642{
643 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
644 uinfo->count = 1;
645 uinfo->value.integer.min = 0; /* mute (-64dB) */
646 uinfo->value.integer.max = PCM_RES; /* 0dB */
647 return 0;
648}
649
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200650static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol,
651 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200652{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100653 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200654 unsigned short val;
655
Ingo Molnar62932df2006-01-16 16:34:20 +0100656 mutex_lock(&ice->gpio_mutex);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200657 val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
658 val = val > PCM_MIN ? (val - PCM_MIN) : 0;
659 ucontrol->value.integer.value[0] = val;
Ingo Molnar62932df2006-01-16 16:34:20 +0100660 mutex_unlock(&ice->gpio_mutex);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200661 return 0;
662}
663
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200664static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol,
665 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200666{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100667 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200668 unsigned short ovol, nvol;
669 int change = 0;
670
Simone Zinanniaed058e2005-04-11 14:08:40 +0200671 nvol = ucontrol->value.integer.value[0];
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100672 if (nvol > PCM_RES)
673 return -EINVAL;
674 snd_ice1712_save_gpio_status(ice);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200675 nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff;
676 ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
677 if (ovol != nvol) {
678 wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200679 /* update */
680 wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200681 change = 1;
682 }
683 snd_ice1712_restore_gpio_status(ice);
684 return change;
685}
686
687/*
Simone Zinanniaed058e2005-04-11 14:08:40 +0200688 * Deemphasis
689 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200690#define phase28_deemp_info snd_ctl_boolean_mono_info
Simone Zinanniaed058e2005-04-11 14:08:40 +0200691
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200692static int phase28_deemp_get(struct snd_kcontrol *kcontrol,
693 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200694{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100695 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200696 ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) ==
697 0xf;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200698 return 0;
699}
700
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200701static int phase28_deemp_put(struct snd_kcontrol *kcontrol,
702 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200703{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100704 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200705 int temp, temp2;
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200706 temp = wm_get(ice, WM_DAC_CTRL2);
707 temp2 = temp;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200708 if (ucontrol->value.integer.value[0])
709 temp |= 0xf;
710 else
711 temp &= ~0xf;
712 if (temp != temp2) {
713 wm_put(ice, WM_DAC_CTRL2, temp);
714 return 1;
715 }
716 return 0;
717}
718
719/*
720 * ADC Oversampling
721 */
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200722static int phase28_oversampling_info(struct snd_kcontrol *k,
723 struct snd_ctl_elem_info *uinfo)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200724{
725 static char *texts[2] = { "128x", "64x" };
726
727 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
728 uinfo->count = 1;
729 uinfo->value.enumerated.items = 2;
730
731 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200732 uinfo->value.enumerated.item = uinfo->value.enumerated.items -
733 1;
734 strcpy(uinfo->value.enumerated.name,
735 texts[uinfo->value.enumerated.item]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200736
Simone Zinanniaed058e2005-04-11 14:08:40 +0200737 return 0;
738}
739
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200740static int phase28_oversampling_get(struct snd_kcontrol *kcontrol,
741 struct snd_ctl_elem_value *ucontrol)
742{
743 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
744 ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) ==
745 0x8;
746 return 0;
747}
748
749static int phase28_oversampling_put(struct snd_kcontrol *kcontrol,
750 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200751{
752 int temp, temp2;
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100753 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200754
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200755 temp = wm_get(ice, WM_MASTER);
756 temp2 = temp;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200757
758 if (ucontrol->value.enumerated.item[0])
759 temp |= 0x8;
760 else
761 temp &= ~0x8;
762
763 if (temp != temp2) {
764 wm_put(ice, WM_MASTER, temp);
765 return 1;
766 }
767 return 0;
768}
769
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100770static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
771static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
Takashi Iwaif640c322006-08-30 16:57:37 +0200772
Takashi Iwai1b60f6b2007-03-13 22:13:47 +0100773static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = {
Simone Zinanniaed058e2005-04-11 14:08:40 +0200774 {
775 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
776 .name = "Master Playback Switch",
777 .info = wm_master_mute_info,
778 .get = wm_master_mute_get,
779 .put = wm_master_mute_put
780 },
781 {
782 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200783 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
784 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200785 .name = "Master Playback Volume",
786 .info = wm_master_vol_info,
787 .get = wm_master_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +0200788 .put = wm_master_vol_put,
789 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200790 },
791 {
792 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
793 .name = "Front Playback Switch",
794 .info = wm_mute_info,
795 .get = wm_mute_get,
796 .put = wm_mute_put,
797 .private_value = (2 << 8) | 0
798 },
799 {
800 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200801 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
802 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200803 .name = "Front Playback Volume",
804 .info = wm_vol_info,
805 .get = wm_vol_get,
806 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +0200807 .private_value = (2 << 8) | 0,
808 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200809 },
810 {
811 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
812 .name = "Rear Playback Switch",
813 .info = wm_mute_info,
814 .get = wm_mute_get,
815 .put = wm_mute_put,
816 .private_value = (2 << 8) | 2
817 },
818 {
819 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200820 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
821 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200822 .name = "Rear Playback Volume",
823 .info = wm_vol_info,
824 .get = wm_vol_get,
825 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +0200826 .private_value = (2 << 8) | 2,
827 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200828 },
829 {
830 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
831 .name = "Center Playback Switch",
832 .info = wm_mute_info,
833 .get = wm_mute_get,
834 .put = wm_mute_put,
835 .private_value = (1 << 8) | 4
836 },
837 {
838 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200839 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
840 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200841 .name = "Center Playback Volume",
842 .info = wm_vol_info,
843 .get = wm_vol_get,
844 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +0200845 .private_value = (1 << 8) | 4,
846 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200847 },
848 {
849 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
850 .name = "LFE Playback Switch",
851 .info = wm_mute_info,
852 .get = wm_mute_get,
853 .put = wm_mute_put,
854 .private_value = (1 << 8) | 5
855 },
856 {
857 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200858 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
859 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200860 .name = "LFE Playback Volume",
861 .info = wm_vol_info,
862 .get = wm_vol_get,
863 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +0200864 .private_value = (1 << 8) | 5,
865 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200866 },
867 {
868 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
869 .name = "Side Playback Switch",
870 .info = wm_mute_info,
871 .get = wm_mute_get,
872 .put = wm_mute_put,
873 .private_value = (2 << 8) | 6
874 },
875 {
876 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200877 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
878 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200879 .name = "Side Playback Volume",
880 .info = wm_vol_info,
881 .get = wm_vol_get,
882 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +0200883 .private_value = (2 << 8) | 6,
884 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200885 }
886};
887
Takashi Iwai1b60f6b2007-03-13 22:13:47 +0100888static struct snd_kcontrol_new wm_controls[] __devinitdata = {
Simone Zinanniaed058e2005-04-11 14:08:40 +0200889 {
890 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
891 .name = "PCM Playback Switch",
892 .info = wm_pcm_mute_info,
893 .get = wm_pcm_mute_get,
894 .put = wm_pcm_mute_put
895 },
896 {
897 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200898 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
899 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200900 .name = "PCM Playback Volume",
901 .info = wm_pcm_vol_info,
902 .get = wm_pcm_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +0200903 .put = wm_pcm_vol_put,
904 .tlv = { .p = db_scale_wm_pcm }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200905 },
906 {
907 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
908 .name = "DAC Deemphasis Switch",
909 .info = phase28_deemp_info,
910 .get = phase28_deemp_get,
911 .put = phase28_deemp_put
912 },
913 {
914 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
915 .name = "ADC Oversampling",
916 .info = phase28_oversampling_info,
917 .get = phase28_oversampling_get,
918 .put = phase28_oversampling_put
919 }
920};
921
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100922static int __devinit phase28_add_controls(struct snd_ice1712 *ice)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200923{
924 unsigned int i, counts;
925 int err;
926
927 counts = ARRAY_SIZE(phase28_dac_controls);
928 for (i = 0; i < counts; i++) {
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200929 err = snd_ctl_add(ice->card,
930 snd_ctl_new1(&phase28_dac_controls[i],
931 ice));
Simone Zinanniaed058e2005-04-11 14:08:40 +0200932 if (err < 0)
933 return err;
934 }
935
936 for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200937 err = snd_ctl_add(ice->card,
938 snd_ctl_new1(&wm_controls[i], ice));
Simone Zinanniaed058e2005-04-11 14:08:40 +0200939 if (err < 0)
940 return err;
941 }
942
943 return 0;
944}
945
Takashi Iwai1b60f6b2007-03-13 22:13:47 +0100946struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 {
948 .subvendor = VT1724_SUBDEVICE_PHASE22,
949 .name = "Terratec PHASE 22",
950 .model = "phase22",
951 .chip_init = phase22_init,
952 .build_controls = phase22_add_controls,
953 .eeprom_size = sizeof(phase22_eeprom),
954 .eeprom_data = phase22_eeprom,
955 },
Simone Zinanniaed058e2005-04-11 14:08:40 +0200956 {
957 .subvendor = VT1724_SUBDEVICE_PHASE28,
958 .name = "Terratec PHASE 28",
959 .model = "phase28",
960 .chip_init = phase28_init,
961 .build_controls = phase28_add_controls,
962 .eeprom_size = sizeof(phase28_eeprom),
963 .eeprom_data = phase28_eeprom,
964 },
Misha Zhilin740dc9c2008-08-01 12:45:14 +0200965 {
966 .subvendor = VT1724_SUBDEVICE_TS22,
967 .name = "Terrasoniq TS22 PCI",
968 .model = "TS22",
969 .chip_init = phase22_init,
970 .build_controls = phase22_add_controls,
971 .eeprom_size = sizeof(phase22_eeprom),
972 .eeprom_data = phase22_eeprom,
973 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 { } /* terminator */
975};