blob: 6a614729280f1ec95995daa2832fc728638d771f [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:
40 * Audio controller: VIA Envy24HT (full untrimmed version, 8in/8out)
41 * 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] = {
Simone Zinanniaed058e2005-04-11 14:08:40 +020089 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
90 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
91 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
92 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11,
93 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8,
94 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6,
95 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
96 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3,
97 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
98 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
99 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
100 0, 0
101};
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
129 // Configure DAC/ADC description for generic part of ice1724
130 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;
135 ice->vt1720 = 1; // Envy24HT-S have 16 bit wide GPIO
136 break;
137 default:
138 snd_BUG();
139 return -EINVAL;
140 }
141
142 // Initialize analog chips
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100143 ak = ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 if (! ak)
145 return -ENOMEM;
146 ice->akm_codecs = 1;
147 switch (ice->eeprom.subvendor) {
148 case VT1724_SUBDEVICE_PHASE22:
Misha Zhilin740dc9c2008-08-01 12:45:14 +0200149 case VT1724_SUBDEVICE_TS22:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 if ((err = snd_ice1712_akm4xxx_init(ak, &akm_phase22, &akm_phase22_priv, ice)) < 0)
151 return err;
152 break;
153 }
154
155 return 0;
156}
157
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100158static int __devinit phase22_add_controls(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159{
160 int err = 0;
161
162 switch (ice->eeprom.subvendor) {
163 case VT1724_SUBDEVICE_PHASE22:
Misha Zhilin740dc9c2008-08-01 12:45:14 +0200164 case VT1724_SUBDEVICE_TS22:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 err = snd_ice1712_akm4xxx_build_controls(ice);
166 if (err < 0)
167 return err;
168 }
169 return 0;
170}
171
Takashi Iwai1b60f6b2007-03-13 22:13:47 +0100172static unsigned char phase22_eeprom[] __devinitdata = {
Vedran Mileticeee75a62008-08-29 18:31:13 +0200173 [ICE_EEP2_SYSCONF] = 0x28, /* clock 512, mpu 401,
174 spdif-in/1xADC, 1xDACs */
Takashi Iwai189bc172007-01-29 15:25:40 +0100175 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
Vedran Mileticeee75a62008-08-29 18:31:13 +0200176 [ICE_EEP2_I2S] = 0xf0, /* vol, 96k, 24bit */
Takashi Iwai189bc172007-01-29 15:25:40 +0100177 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
178 [ICE_EEP2_GPIO_DIR] = 0xff,
179 [ICE_EEP2_GPIO_DIR1] = 0xff,
180 [ICE_EEP2_GPIO_DIR2] = 0xff,
181 [ICE_EEP2_GPIO_MASK] = 0x00,
182 [ICE_EEP2_GPIO_MASK1] = 0x00,
183 [ICE_EEP2_GPIO_MASK2] = 0x00,
184 [ICE_EEP2_GPIO_STATE] = 0x00,
185 [ICE_EEP2_GPIO_STATE1] = 0x00,
186 [ICE_EEP2_GPIO_STATE2] = 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187};
188
Takashi Iwai1b60f6b2007-03-13 22:13:47 +0100189static unsigned char phase28_eeprom[] __devinitdata = {
Vedran Mileticeee75a62008-08-29 18:31:13 +0200190 [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401,
191 spdif-in/1xADC, 4xDACs */
Takashi Iwai189bc172007-01-29 15:25:40 +0100192 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
193 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
194 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
195 [ICE_EEP2_GPIO_DIR] = 0xff,
196 [ICE_EEP2_GPIO_DIR1] = 0xff,
197 [ICE_EEP2_GPIO_DIR2] = 0x5f,
198 [ICE_EEP2_GPIO_MASK] = 0x00,
199 [ICE_EEP2_GPIO_MASK1] = 0x00,
200 [ICE_EEP2_GPIO_MASK2] = 0x00,
201 [ICE_EEP2_GPIO_STATE] = 0x00,
202 [ICE_EEP2_GPIO_STATE1] = 0x00,
203 [ICE_EEP2_GPIO_STATE2] = 0x00,
Simone Zinanniaed058e2005-04-11 14:08:40 +0200204};
205
206/*
207 * write data in the SPI mode
208 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100209static void phase28_spi_write(struct snd_ice1712 *ice, unsigned int cs, unsigned int data, int bits)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200210{
211 unsigned int tmp;
212 int i;
213
214 tmp = snd_ice1712_gpio_read(ice);
215
216 snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RW|PHASE28_SPI_MOSI|PHASE28_SPI_CLK|
217 PHASE28_WM_CS));
218 tmp |= PHASE28_WM_RW;
219 tmp &= ~cs;
220 snd_ice1712_gpio_write(ice, tmp);
221 udelay(1);
222
223 for (i = bits - 1; i >= 0; i--) {
224 tmp &= ~PHASE28_SPI_CLK;
225 snd_ice1712_gpio_write(ice, tmp);
226 udelay(1);
227 if (data & (1 << i))
228 tmp |= PHASE28_SPI_MOSI;
229 else
230 tmp &= ~PHASE28_SPI_MOSI;
231 snd_ice1712_gpio_write(ice, tmp);
232 udelay(1);
233 tmp |= PHASE28_SPI_CLK;
234 snd_ice1712_gpio_write(ice, tmp);
235 udelay(1);
236 }
237
238 tmp &= ~PHASE28_SPI_CLK;
239 tmp |= cs;
240 snd_ice1712_gpio_write(ice, tmp);
241 udelay(1);
242 tmp |= PHASE28_SPI_CLK;
243 snd_ice1712_gpio_write(ice, tmp);
244 udelay(1);
245}
246
247/*
248 * get the current register value of WM codec
249 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100250static unsigned short wm_get(struct snd_ice1712 *ice, int reg)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200251{
252 reg <<= 1;
253 return ((unsigned short)ice->akm[0].images[reg] << 8) |
254 ice->akm[0].images[reg + 1];
255}
256
257/*
258 * set the register value of WM codec
259 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100260static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200261{
262 phase28_spi_write(ice, PHASE28_WM_CS, (reg << 9) | (val & 0x1ff), 16);
263}
264
265/*
266 * set the register value of WM codec and remember it
267 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100268static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200269{
270 wm_put_nocache(ice, reg, val);
271 reg <<= 1;
272 ice->akm[0].images[reg] = val >> 8;
273 ice->akm[0].images[reg + 1] = val;
274}
275
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100276static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned short vol, unsigned short master)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200277{
278 unsigned char nvol;
279
280 if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
281 nvol = 0;
282 else
283 nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX];
284
285 wm_put(ice, index, nvol);
286 wm_put_nocache(ice, index, 0x180 | nvol);
287}
288
289/*
290 * DAC mute control
291 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200292#define wm_pcm_mute_info snd_ctl_boolean_mono_info
Simone Zinanniaed058e2005-04-11 14:08:40 +0200293
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100294static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200295{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100296 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200297
Ingo Molnar62932df2006-01-16 16:34:20 +0100298 mutex_lock(&ice->gpio_mutex);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200299 ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;
Ingo Molnar62932df2006-01-16 16:34:20 +0100300 mutex_unlock(&ice->gpio_mutex);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200301 return 0;
302}
303
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100304static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200305{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100306 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200307 unsigned short nval, oval;
308 int change;
309
310 snd_ice1712_save_gpio_status(ice);
311 oval = wm_get(ice, WM_MUTE);
312 nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);
313 if ((change = (nval != oval)))
314 wm_put(ice, WM_MUTE, nval);
315 snd_ice1712_restore_gpio_status(ice);
316
317 return change;
318}
319
320/*
321 * Master volume attenuation mixer control
322 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100323static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200324{
325 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
326 uinfo->count = 2;
327 uinfo->value.integer.min = 0;
328 uinfo->value.integer.max = WM_VOL_MAX;
329 return 0;
330}
331
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100332static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200333{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100334 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100335 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200336 int i;
337 for (i=0; i<2; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100338 ucontrol->value.integer.value[i] = spec->master[i] & ~WM_VOL_MUTE;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200339 return 0;
340}
341
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100342static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200343{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100344 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100345 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200346 int ch, change = 0;
347
348 snd_ice1712_save_gpio_status(ice);
349 for (ch = 0; ch < 2; ch++) {
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100350 unsigned int vol = ucontrol->value.integer.value[ch];
351 if (vol > WM_VOL_MAX)
352 continue;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100353 vol |= spec->master[ch] & WM_VOL_MUTE;
354 if (vol != spec->master[ch]) {
Simone Zinanniaed058e2005-04-11 14:08:40 +0200355 int dac;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100356 spec->master[ch] = vol;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200357 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
358 wm_set_vol(ice, WM_DAC_ATTEN + dac + ch,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100359 spec->vol[dac + ch],
360 spec->master[ch]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200361 change = 1;
362 }
363 }
364 snd_ice1712_restore_gpio_status(ice);
365 return change;
366}
367
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100368static int __devinit phase28_init(struct snd_ice1712 *ice)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200369{
Takashi Iwai32b47da2007-01-29 15:26:36 +0100370 static const unsigned short wm_inits_phase28[] = {
Simone Zinanniaed058e2005-04-11 14:08:40 +0200371 /* These come first to reduce init pop noise */
372 0x1b, 0x044, /* ADC Mux (AC'97 source) */
373 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
374 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
375
376 0x18, 0x000, /* All power-up */
377
378 0x16, 0x122, /* I2S, normal polarity, 24bit */
379 0x17, 0x022, /* 256fs, slave mode */
380 0x00, 0, /* DAC1 analog mute */
381 0x01, 0, /* DAC2 analog mute */
382 0x02, 0, /* DAC3 analog mute */
383 0x03, 0, /* DAC4 analog mute */
384 0x04, 0, /* DAC5 analog mute */
385 0x05, 0, /* DAC6 analog mute */
386 0x06, 0, /* DAC7 analog mute */
387 0x07, 0, /* DAC8 analog mute */
388 0x08, 0x100, /* master analog mute */
389 0x09, 0xff, /* DAC1 digital full */
390 0x0a, 0xff, /* DAC2 digital full */
391 0x0b, 0xff, /* DAC3 digital full */
392 0x0c, 0xff, /* DAC4 digital full */
393 0x0d, 0xff, /* DAC5 digital full */
394 0x0e, 0xff, /* DAC6 digital full */
395 0x0f, 0xff, /* DAC7 digital full */
396 0x10, 0xff, /* DAC8 digital full */
397 0x11, 0x1ff, /* master digital full */
398 0x12, 0x000, /* phase normal */
399 0x13, 0x090, /* unmute DAC L/R */
400 0x14, 0x000, /* all unmute */
401 0x15, 0x000, /* no deemphasis, no ZFLG */
402 0x19, 0x000, /* -12dB ADC/L */
403 0x1a, 0x000, /* -12dB ADC/R */
404 (unsigned short)-1
405 };
406
407 unsigned int tmp;
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100408 struct snd_akm4xxx *ak;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100409 struct phase28_spec *spec;
Takashi Iwai32b47da2007-01-29 15:26:36 +0100410 const unsigned short *p;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200411 int i;
412
413 ice->num_total_dacs = 8;
414 ice->num_total_adcs = 2;
415
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100416 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
417 if (!spec)
418 return -ENOMEM;
419 ice->spec = spec;
420
Simone Zinanniaed058e2005-04-11 14:08:40 +0200421 // Initialize analog chips
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100422 ak = ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200423 if (!ak)
424 return -ENOMEM;
425 ice->akm_codecs = 1;
426
427 snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */
428
429 /* reset the wm codec as the SPI mode */
430 snd_ice1712_save_gpio_status(ice);
431 snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RESET|PHASE28_WM_CS|PHASE28_HP_SEL));
432
433 tmp = snd_ice1712_gpio_read(ice);
434 tmp &= ~PHASE28_WM_RESET;
435 snd_ice1712_gpio_write(ice, tmp);
436 udelay(1);
437 tmp |= PHASE28_WM_CS;
438 snd_ice1712_gpio_write(ice, tmp);
439 udelay(1);
440 tmp |= PHASE28_WM_RESET;
441 snd_ice1712_gpio_write(ice, tmp);
442 udelay(1);
443
444 p = wm_inits_phase28;
445 for (; *p != (unsigned short)-1; p += 2)
446 wm_put(ice, p[0], p[1]);
447
448 snd_ice1712_restore_gpio_status(ice);
449
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100450 spec->master[0] = WM_VOL_MUTE;
451 spec->master[1] = WM_VOL_MUTE;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200452 for (i = 0; i < ice->num_total_dacs; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100453 spec->vol[i] = WM_VOL_MUTE;
454 wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200455 }
456
457 return 0;
458}
459
460/*
461 * DAC volume attenuation mixer control
462 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100463static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200464{
465 int voices = kcontrol->private_value >> 8;
466 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
467 uinfo->count = voices;
468 uinfo->value.integer.min = 0; /* mute (-101dB) */
469 uinfo->value.integer.max = 0x7F; /* 0dB */
470 return 0;
471}
472
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100473static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200474{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100475 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100476 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200477 int i, ofs, voices;
478
479 voices = kcontrol->private_value >> 8;
480 ofs = kcontrol->private_value & 0xff;
481 for (i = 0; i < voices; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100482 ucontrol->value.integer.value[i] =
483 spec->vol[ofs+i] & ~WM_VOL_MUTE;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200484 return 0;
485}
486
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100487static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200488{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100489 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100490 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200491 int i, idx, ofs, voices;
492 int change = 0;
493
494 voices = kcontrol->private_value >> 8;
495 ofs = kcontrol->private_value & 0xff;
496 snd_ice1712_save_gpio_status(ice);
497 for (i = 0; i < voices; i++) {
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100498 unsigned int vol;
499 vol = ucontrol->value.integer.value[i];
500 if (vol > 0x7f)
501 continue;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100502 vol |= spec->vol[ofs+i] & WM_VOL_MUTE;
503 if (vol != spec->vol[ofs+i]) {
504 spec->vol[ofs+i] = vol;
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100505 idx = WM_DAC_ATTEN + ofs + i;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100506 wm_set_vol(ice, idx, spec->vol[ofs+i],
507 spec->master[i]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200508 change = 1;
509 }
510 }
511 snd_ice1712_restore_gpio_status(ice);
512 return change;
513}
514
515/*
516 * WM8770 mute control
517 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100518static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Simone Zinanniaed058e2005-04-11 14:08:40 +0200519 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
520 uinfo->count = kcontrol->private_value >> 8;
521 uinfo->value.integer.min = 0;
522 uinfo->value.integer.max = 1;
523 return 0;
524}
525
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100526static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200527{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100528 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100529 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200530 int voices, ofs, i;
531
532 voices = kcontrol->private_value >> 8;
533 ofs = kcontrol->private_value & 0xFF;
534
535 for (i = 0; i < voices; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100536 ucontrol->value.integer.value[i] =
537 (spec->vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200538 return 0;
539}
540
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100541static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200542{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100543 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100544 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200545 int change = 0, voices, ofs, i;
546
547 voices = kcontrol->private_value >> 8;
548 ofs = kcontrol->private_value & 0xFF;
549
550 snd_ice1712_save_gpio_status(ice);
551 for (i = 0; i < voices; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100552 int val = (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200553 if (ucontrol->value.integer.value[i] != val) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100554 spec->vol[ofs + i] &= ~WM_VOL_MUTE;
555 spec->vol[ofs + i] |=
Simone Zinanniaed058e2005-04-11 14:08:40 +0200556 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100557 wm_set_vol(ice, ofs + i, spec->vol[ofs + i],
558 spec->master[i]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200559 change = 1;
560 }
561 }
562 snd_ice1712_restore_gpio_status(ice);
563
564 return change;
565}
566
567/*
568 * WM8770 master mute control
569 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200570#define wm_master_mute_info snd_ctl_boolean_stereo_info
Simone Zinanniaed058e2005-04-11 14:08:40 +0200571
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100572static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200573{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100574 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100575 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200576
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100577 ucontrol->value.integer.value[0] =
578 (spec->master[0] & WM_VOL_MUTE) ? 0 : 1;
579 ucontrol->value.integer.value[1] =
580 (spec->master[1] & WM_VOL_MUTE) ? 0 : 1;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200581 return 0;
582}
583
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100584static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200585{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100586 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100587 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200588 int change = 0, i;
589
590 snd_ice1712_save_gpio_status(ice);
591 for (i = 0; i < 2; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100592 int val = (spec->master[i] & WM_VOL_MUTE) ? 0 : 1;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200593 if (ucontrol->value.integer.value[i] != val) {
594 int dac;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100595 spec->master[i] &= ~WM_VOL_MUTE;
596 spec->master[i] |=
Simone Zinanniaed058e2005-04-11 14:08:40 +0200597 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
598 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
599 wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100600 spec->vol[dac + i],
601 spec->master[i]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200602 change = 1;
603 }
604 }
605 snd_ice1712_restore_gpio_status(ice);
606
607 return change;
608}
609
610/* digital master volume */
611#define PCM_0dB 0xff
612#define PCM_RES 128 /* -64dB */
613#define PCM_MIN (PCM_0dB - PCM_RES)
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100614static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200615{
616 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
617 uinfo->count = 1;
618 uinfo->value.integer.min = 0; /* mute (-64dB) */
619 uinfo->value.integer.max = PCM_RES; /* 0dB */
620 return 0;
621}
622
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100623static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200624{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100625 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200626 unsigned short val;
627
Ingo Molnar62932df2006-01-16 16:34:20 +0100628 mutex_lock(&ice->gpio_mutex);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200629 val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
630 val = val > PCM_MIN ? (val - PCM_MIN) : 0;
631 ucontrol->value.integer.value[0] = val;
Ingo Molnar62932df2006-01-16 16:34:20 +0100632 mutex_unlock(&ice->gpio_mutex);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200633 return 0;
634}
635
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100636static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200637{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100638 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200639 unsigned short ovol, nvol;
640 int change = 0;
641
Simone Zinanniaed058e2005-04-11 14:08:40 +0200642 nvol = ucontrol->value.integer.value[0];
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100643 if (nvol > PCM_RES)
644 return -EINVAL;
645 snd_ice1712_save_gpio_status(ice);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200646 nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff;
647 ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
648 if (ovol != nvol) {
649 wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */
650 wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); /* update */
651 change = 1;
652 }
653 snd_ice1712_restore_gpio_status(ice);
654 return change;
655}
656
657/*
Simone Zinanniaed058e2005-04-11 14:08:40 +0200658 * Deemphasis
659 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200660#define phase28_deemp_info snd_ctl_boolean_mono_info
Simone Zinanniaed058e2005-04-11 14:08:40 +0200661
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100662static int phase28_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200663{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100664 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200665 ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf;
666 return 0;
667}
668
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100669static int phase28_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200670{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100671 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200672 int temp, temp2;
673 temp2 = temp = wm_get(ice, WM_DAC_CTRL2);
674 if (ucontrol->value.integer.value[0])
675 temp |= 0xf;
676 else
677 temp &= ~0xf;
678 if (temp != temp2) {
679 wm_put(ice, WM_DAC_CTRL2, temp);
680 return 1;
681 }
682 return 0;
683}
684
685/*
686 * ADC Oversampling
687 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100688static int phase28_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200689{
690 static char *texts[2] = { "128x", "64x" };
691
692 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
693 uinfo->count = 1;
694 uinfo->value.enumerated.items = 2;
695
696 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
697 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
698 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
699
700 return 0;
701}
702
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100703static int phase28_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200704{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100705 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200706 ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8;
707 return 0;
708}
709
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100710static int phase28_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200711{
712 int temp, temp2;
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100713 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200714
715 temp2 = temp = wm_get(ice, WM_MASTER);
716
717 if (ucontrol->value.enumerated.item[0])
718 temp |= 0x8;
719 else
720 temp &= ~0x8;
721
722 if (temp != temp2) {
723 wm_put(ice, WM_MASTER, temp);
724 return 1;
725 }
726 return 0;
727}
728
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100729static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
730static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
Takashi Iwaif640c322006-08-30 16:57:37 +0200731
Takashi Iwai1b60f6b2007-03-13 22:13:47 +0100732static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = {
Simone Zinanniaed058e2005-04-11 14:08:40 +0200733 {
734 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
735 .name = "Master Playback Switch",
736 .info = wm_master_mute_info,
737 .get = wm_master_mute_get,
738 .put = wm_master_mute_put
739 },
740 {
741 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200742 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
743 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200744 .name = "Master Playback Volume",
745 .info = wm_master_vol_info,
746 .get = wm_master_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +0200747 .put = wm_master_vol_put,
748 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200749 },
750 {
751 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
752 .name = "Front Playback Switch",
753 .info = wm_mute_info,
754 .get = wm_mute_get,
755 .put = wm_mute_put,
756 .private_value = (2 << 8) | 0
757 },
758 {
759 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200760 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
761 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200762 .name = "Front Playback Volume",
763 .info = wm_vol_info,
764 .get = wm_vol_get,
765 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +0200766 .private_value = (2 << 8) | 0,
767 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200768 },
769 {
770 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
771 .name = "Rear Playback Switch",
772 .info = wm_mute_info,
773 .get = wm_mute_get,
774 .put = wm_mute_put,
775 .private_value = (2 << 8) | 2
776 },
777 {
778 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200779 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
780 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200781 .name = "Rear Playback Volume",
782 .info = wm_vol_info,
783 .get = wm_vol_get,
784 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +0200785 .private_value = (2 << 8) | 2,
786 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200787 },
788 {
789 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
790 .name = "Center Playback Switch",
791 .info = wm_mute_info,
792 .get = wm_mute_get,
793 .put = wm_mute_put,
794 .private_value = (1 << 8) | 4
795 },
796 {
797 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200798 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
799 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200800 .name = "Center Playback Volume",
801 .info = wm_vol_info,
802 .get = wm_vol_get,
803 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +0200804 .private_value = (1 << 8) | 4,
805 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200806 },
807 {
808 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
809 .name = "LFE Playback Switch",
810 .info = wm_mute_info,
811 .get = wm_mute_get,
812 .put = wm_mute_put,
813 .private_value = (1 << 8) | 5
814 },
815 {
816 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200817 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
818 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200819 .name = "LFE Playback Volume",
820 .info = wm_vol_info,
821 .get = wm_vol_get,
822 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +0200823 .private_value = (1 << 8) | 5,
824 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200825 },
826 {
827 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
828 .name = "Side Playback Switch",
829 .info = wm_mute_info,
830 .get = wm_mute_get,
831 .put = wm_mute_put,
832 .private_value = (2 << 8) | 6
833 },
834 {
835 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200836 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
837 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200838 .name = "Side Playback Volume",
839 .info = wm_vol_info,
840 .get = wm_vol_get,
841 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +0200842 .private_value = (2 << 8) | 6,
843 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200844 }
845};
846
Takashi Iwai1b60f6b2007-03-13 22:13:47 +0100847static struct snd_kcontrol_new wm_controls[] __devinitdata = {
Simone Zinanniaed058e2005-04-11 14:08:40 +0200848 {
849 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
850 .name = "PCM Playback Switch",
851 .info = wm_pcm_mute_info,
852 .get = wm_pcm_mute_get,
853 .put = wm_pcm_mute_put
854 },
855 {
856 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200857 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
858 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200859 .name = "PCM Playback Volume",
860 .info = wm_pcm_vol_info,
861 .get = wm_pcm_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +0200862 .put = wm_pcm_vol_put,
863 .tlv = { .p = db_scale_wm_pcm }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200864 },
865 {
866 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
867 .name = "DAC Deemphasis Switch",
868 .info = phase28_deemp_info,
869 .get = phase28_deemp_get,
870 .put = phase28_deemp_put
871 },
872 {
873 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
874 .name = "ADC Oversampling",
875 .info = phase28_oversampling_info,
876 .get = phase28_oversampling_get,
877 .put = phase28_oversampling_put
878 }
879};
880
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100881static int __devinit phase28_add_controls(struct snd_ice1712 *ice)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200882{
883 unsigned int i, counts;
884 int err;
885
886 counts = ARRAY_SIZE(phase28_dac_controls);
887 for (i = 0; i < counts; i++) {
888 err = snd_ctl_add(ice->card, snd_ctl_new1(&phase28_dac_controls[i], ice));
889 if (err < 0)
890 return err;
891 }
892
893 for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
894 err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice));
895 if (err < 0)
896 return err;
897 }
898
899 return 0;
900}
901
Takashi Iwai1b60f6b2007-03-13 22:13:47 +0100902struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 {
904 .subvendor = VT1724_SUBDEVICE_PHASE22,
905 .name = "Terratec PHASE 22",
906 .model = "phase22",
907 .chip_init = phase22_init,
908 .build_controls = phase22_add_controls,
909 .eeprom_size = sizeof(phase22_eeprom),
910 .eeprom_data = phase22_eeprom,
911 },
Simone Zinanniaed058e2005-04-11 14:08:40 +0200912 {
913 .subvendor = VT1724_SUBDEVICE_PHASE28,
914 .name = "Terratec PHASE 28",
915 .model = "phase28",
916 .chip_init = phase28_init,
917 .build_controls = phase28_add_controls,
918 .eeprom_size = sizeof(phase28_eeprom),
919 .eeprom_data = phase28_eeprom,
920 },
Misha Zhilin740dc9c2008-08-01 12:45:14 +0200921 {
922 .subvendor = VT1724_SUBDEVICE_TS22,
923 .name = "Terrasoniq TS22 PCI",
924 .model = "TS22",
925 .chip_init = phase22_init,
926 .build_controls = phase22_add_controls,
927 .eeprom_size = sizeof(phase22_eeprom),
928 .eeprom_data = phase22_eeprom,
929 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 { } /* terminator */
931};