blob: 5a158b73dcaa2050211bf55291d3de67b0621ebd [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:
25 * Audio controller: VIA Envy24HT-S (slightly trimmed down version of Envy24HT)
26 * Analog chip: AK4524 (partially via Philip's 74HCT125)
27 * Digital receiver: CS8414-CS (not supported in this release)
28 *
29 * Envy connects to AK4524
30 * - CS directly from GPIO 10
31 * - CCLK via 74HCT125's gate #4 from GPIO 4
32 * - CDTI via 74HCT125's gate #2 from GPIO 5
33 * CDTI may be completely blocked by 74HCT125's gate #1 controlled by GPIO 3
34 */
35
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <asm/io.h>
37#include <linux/delay.h>
38#include <linux/interrupt.h>
39#include <linux/init.h>
40#include <linux/slab.h>
Ingo Molnar62932df2006-01-16 16:34:20 +010041#include <linux/mutex.h>
42
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <sound/core.h>
44
45#include "ice1712.h"
46#include "envy24ht.h"
47#include "phase.h"
Takashi Iwaif640c322006-08-30 16:57:37 +020048#include <sound/tlv.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Takashi Iwai7cda8ba2008-01-18 13:36:07 +010050/* AC97 register cache for Phase28 */
51struct phase28_spec {
52 unsigned short master[2];
53 unsigned short vol[8];
Harvey Harrison008f3592008-02-29 11:46:32 +010054};
Takashi Iwai7cda8ba2008-01-18 13:36:07 +010055
Simone Zinanniaed058e2005-04-11 14:08:40 +020056/* WM8770 registers */
57#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */
58#define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */
59#define WM_DAC_DIG_ATTEN 0x09 /* DAC1-8 digital attenuation */
60#define WM_DAC_DIG_MASTER_ATTEN 0x11 /* DAC master digital attenuation */
61#define WM_PHASE_SWAP 0x12 /* DAC phase */
62#define WM_DAC_CTRL1 0x13 /* DAC control bits */
63#define WM_MUTE 0x14 /* mute controls */
64#define WM_DAC_CTRL2 0x15 /* de-emphasis and zefo-flag */
65#define WM_INT_CTRL 0x16 /* interface control */
66#define WM_MASTER 0x17 /* master clock and mode */
67#define WM_POWERDOWN 0x18 /* power-down controls */
68#define WM_ADC_GAIN 0x19 /* ADC gain L(19)/R(1a) */
69#define WM_ADC_MUX 0x1b /* input MUX */
70#define WM_OUT_MUX1 0x1c /* output MUX */
71#define WM_OUT_MUX2 0x1e /* output MUX */
72#define WM_RESET 0x1f /* software reset */
73
74
75/*
76 * Logarithmic volume values for WM8770
77 * Computed as 20 * Log10(255 / x)
78 */
Takashi Iwai32b47da2007-01-29 15:26:36 +010079static const unsigned char wm_vol[256] = {
Simone Zinanniaed058e2005-04-11 14:08:40 +020080 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
81 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
82 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
83 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11,
84 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8,
85 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,
86 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,
87 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,
88 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,
89 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,
90 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,
91 0, 0
92};
93
94#define WM_VOL_MAX (sizeof(wm_vol) - 1)
95#define WM_VOL_MUTE 0x8000
96
Takashi Iwai1b60f6b2007-03-13 22:13:47 +010097static struct snd_akm4xxx akm_phase22 __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 .type = SND_AK4524,
99 .num_dacs = 2,
100 .num_adcs = 2,
101};
102
Takashi Iwai1b60f6b2007-03-13 22:13:47 +0100103static struct snd_ak4xxx_private akm_phase22_priv __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 .caddr = 2,
105 .cif = 1,
106 .data_mask = 1 << 4,
107 .clk_mask = 1 << 5,
108 .cs_mask = 1 << 10,
109 .cs_addr = 1 << 10,
110 .cs_none = 0,
111 .add_flags = 1 << 3,
112 .mask_flags = 0,
113};
114
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100115static int __devinit phase22_init(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100117 struct snd_akm4xxx *ak;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 int err;
119
120 // Configure DAC/ADC description for generic part of ice1724
121 switch (ice->eeprom.subvendor) {
122 case VT1724_SUBDEVICE_PHASE22:
123 ice->num_total_dacs = 2;
124 ice->num_total_adcs = 2;
125 ice->vt1720 = 1; // Envy24HT-S have 16 bit wide GPIO
126 break;
127 default:
128 snd_BUG();
129 return -EINVAL;
130 }
131
132 // Initialize analog chips
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100133 ak = ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 if (! ak)
135 return -ENOMEM;
136 ice->akm_codecs = 1;
137 switch (ice->eeprom.subvendor) {
138 case VT1724_SUBDEVICE_PHASE22:
139 if ((err = snd_ice1712_akm4xxx_init(ak, &akm_phase22, &akm_phase22_priv, ice)) < 0)
140 return err;
141 break;
142 }
143
144 return 0;
145}
146
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100147static int __devinit phase22_add_controls(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148{
149 int err = 0;
150
151 switch (ice->eeprom.subvendor) {
152 case VT1724_SUBDEVICE_PHASE22:
153 err = snd_ice1712_akm4xxx_build_controls(ice);
154 if (err < 0)
155 return err;
156 }
157 return 0;
158}
159
Takashi Iwai1b60f6b2007-03-13 22:13:47 +0100160static unsigned char phase22_eeprom[] __devinitdata = {
Takashi Iwai189bc172007-01-29 15:25:40 +0100161 [ICE_EEP2_SYSCONF] = 0x00, /* 1xADC, 1xDACs */
162 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
163 [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit */
164 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
165 [ICE_EEP2_GPIO_DIR] = 0xff,
166 [ICE_EEP2_GPIO_DIR1] = 0xff,
167 [ICE_EEP2_GPIO_DIR2] = 0xff,
168 [ICE_EEP2_GPIO_MASK] = 0x00,
169 [ICE_EEP2_GPIO_MASK1] = 0x00,
170 [ICE_EEP2_GPIO_MASK2] = 0x00,
171 [ICE_EEP2_GPIO_STATE] = 0x00,
172 [ICE_EEP2_GPIO_STATE1] = 0x00,
173 [ICE_EEP2_GPIO_STATE2] = 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174};
175
Takashi Iwai1b60f6b2007-03-13 22:13:47 +0100176static unsigned char phase28_eeprom[] __devinitdata = {
Takashi Iwai189bc172007-01-29 15:25:40 +0100177 [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */
178 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
179 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
180 [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] = 0x5f,
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,
Simone Zinanniaed058e2005-04-11 14:08:40 +0200190};
191
192/*
193 * write data in the SPI mode
194 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100195static void phase28_spi_write(struct snd_ice1712 *ice, unsigned int cs, unsigned int data, int bits)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200196{
197 unsigned int tmp;
198 int i;
199
200 tmp = snd_ice1712_gpio_read(ice);
201
202 snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RW|PHASE28_SPI_MOSI|PHASE28_SPI_CLK|
203 PHASE28_WM_CS));
204 tmp |= PHASE28_WM_RW;
205 tmp &= ~cs;
206 snd_ice1712_gpio_write(ice, tmp);
207 udelay(1);
208
209 for (i = bits - 1; i >= 0; i--) {
210 tmp &= ~PHASE28_SPI_CLK;
211 snd_ice1712_gpio_write(ice, tmp);
212 udelay(1);
213 if (data & (1 << i))
214 tmp |= PHASE28_SPI_MOSI;
215 else
216 tmp &= ~PHASE28_SPI_MOSI;
217 snd_ice1712_gpio_write(ice, tmp);
218 udelay(1);
219 tmp |= PHASE28_SPI_CLK;
220 snd_ice1712_gpio_write(ice, tmp);
221 udelay(1);
222 }
223
224 tmp &= ~PHASE28_SPI_CLK;
225 tmp |= cs;
226 snd_ice1712_gpio_write(ice, tmp);
227 udelay(1);
228 tmp |= PHASE28_SPI_CLK;
229 snd_ice1712_gpio_write(ice, tmp);
230 udelay(1);
231}
232
233/*
234 * get the current register value of WM codec
235 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100236static unsigned short wm_get(struct snd_ice1712 *ice, int reg)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200237{
238 reg <<= 1;
239 return ((unsigned short)ice->akm[0].images[reg] << 8) |
240 ice->akm[0].images[reg + 1];
241}
242
243/*
244 * set the register value of WM codec
245 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100246static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200247{
248 phase28_spi_write(ice, PHASE28_WM_CS, (reg << 9) | (val & 0x1ff), 16);
249}
250
251/*
252 * set the register value of WM codec and remember it
253 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100254static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200255{
256 wm_put_nocache(ice, reg, val);
257 reg <<= 1;
258 ice->akm[0].images[reg] = val >> 8;
259 ice->akm[0].images[reg + 1] = val;
260}
261
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100262static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned short vol, unsigned short master)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200263{
264 unsigned char nvol;
265
266 if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
267 nvol = 0;
268 else
269 nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX];
270
271 wm_put(ice, index, nvol);
272 wm_put_nocache(ice, index, 0x180 | nvol);
273}
274
275/*
276 * DAC mute control
277 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200278#define wm_pcm_mute_info snd_ctl_boolean_mono_info
Simone Zinanniaed058e2005-04-11 14:08:40 +0200279
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100280static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200281{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100282 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200283
Ingo Molnar62932df2006-01-16 16:34:20 +0100284 mutex_lock(&ice->gpio_mutex);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200285 ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1;
Ingo Molnar62932df2006-01-16 16:34:20 +0100286 mutex_unlock(&ice->gpio_mutex);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200287 return 0;
288}
289
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100290static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200291{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100292 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200293 unsigned short nval, oval;
294 int change;
295
296 snd_ice1712_save_gpio_status(ice);
297 oval = wm_get(ice, WM_MUTE);
298 nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);
299 if ((change = (nval != oval)))
300 wm_put(ice, WM_MUTE, nval);
301 snd_ice1712_restore_gpio_status(ice);
302
303 return change;
304}
305
306/*
307 * Master volume attenuation mixer control
308 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100309static int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200310{
311 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
312 uinfo->count = 2;
313 uinfo->value.integer.min = 0;
314 uinfo->value.integer.max = WM_VOL_MAX;
315 return 0;
316}
317
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100318static int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200319{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100320 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100321 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200322 int i;
323 for (i=0; i<2; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100324 ucontrol->value.integer.value[i] = spec->master[i] & ~WM_VOL_MUTE;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200325 return 0;
326}
327
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100328static int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200329{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100330 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100331 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200332 int ch, change = 0;
333
334 snd_ice1712_save_gpio_status(ice);
335 for (ch = 0; ch < 2; ch++) {
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100336 unsigned int vol = ucontrol->value.integer.value[ch];
337 if (vol > WM_VOL_MAX)
338 continue;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100339 vol |= spec->master[ch] & WM_VOL_MUTE;
340 if (vol != spec->master[ch]) {
Simone Zinanniaed058e2005-04-11 14:08:40 +0200341 int dac;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100342 spec->master[ch] = vol;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200343 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
344 wm_set_vol(ice, WM_DAC_ATTEN + dac + ch,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100345 spec->vol[dac + ch],
346 spec->master[ch]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200347 change = 1;
348 }
349 }
350 snd_ice1712_restore_gpio_status(ice);
351 return change;
352}
353
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100354static int __devinit phase28_init(struct snd_ice1712 *ice)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200355{
Takashi Iwai32b47da2007-01-29 15:26:36 +0100356 static const unsigned short wm_inits_phase28[] = {
Simone Zinanniaed058e2005-04-11 14:08:40 +0200357 /* These come first to reduce init pop noise */
358 0x1b, 0x044, /* ADC Mux (AC'97 source) */
359 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
360 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
361
362 0x18, 0x000, /* All power-up */
363
364 0x16, 0x122, /* I2S, normal polarity, 24bit */
365 0x17, 0x022, /* 256fs, slave mode */
366 0x00, 0, /* DAC1 analog mute */
367 0x01, 0, /* DAC2 analog mute */
368 0x02, 0, /* DAC3 analog mute */
369 0x03, 0, /* DAC4 analog mute */
370 0x04, 0, /* DAC5 analog mute */
371 0x05, 0, /* DAC6 analog mute */
372 0x06, 0, /* DAC7 analog mute */
373 0x07, 0, /* DAC8 analog mute */
374 0x08, 0x100, /* master analog mute */
375 0x09, 0xff, /* DAC1 digital full */
376 0x0a, 0xff, /* DAC2 digital full */
377 0x0b, 0xff, /* DAC3 digital full */
378 0x0c, 0xff, /* DAC4 digital full */
379 0x0d, 0xff, /* DAC5 digital full */
380 0x0e, 0xff, /* DAC6 digital full */
381 0x0f, 0xff, /* DAC7 digital full */
382 0x10, 0xff, /* DAC8 digital full */
383 0x11, 0x1ff, /* master digital full */
384 0x12, 0x000, /* phase normal */
385 0x13, 0x090, /* unmute DAC L/R */
386 0x14, 0x000, /* all unmute */
387 0x15, 0x000, /* no deemphasis, no ZFLG */
388 0x19, 0x000, /* -12dB ADC/L */
389 0x1a, 0x000, /* -12dB ADC/R */
390 (unsigned short)-1
391 };
392
393 unsigned int tmp;
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100394 struct snd_akm4xxx *ak;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100395 struct phase28_spec *spec;
Takashi Iwai32b47da2007-01-29 15:26:36 +0100396 const unsigned short *p;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200397 int i;
398
399 ice->num_total_dacs = 8;
400 ice->num_total_adcs = 2;
401
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100402 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
403 if (!spec)
404 return -ENOMEM;
405 ice->spec = spec;
406
Simone Zinanniaed058e2005-04-11 14:08:40 +0200407 // Initialize analog chips
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100408 ak = ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200409 if (!ak)
410 return -ENOMEM;
411 ice->akm_codecs = 1;
412
413 snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */
414
415 /* reset the wm codec as the SPI mode */
416 snd_ice1712_save_gpio_status(ice);
417 snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RESET|PHASE28_WM_CS|PHASE28_HP_SEL));
418
419 tmp = snd_ice1712_gpio_read(ice);
420 tmp &= ~PHASE28_WM_RESET;
421 snd_ice1712_gpio_write(ice, tmp);
422 udelay(1);
423 tmp |= PHASE28_WM_CS;
424 snd_ice1712_gpio_write(ice, tmp);
425 udelay(1);
426 tmp |= PHASE28_WM_RESET;
427 snd_ice1712_gpio_write(ice, tmp);
428 udelay(1);
429
430 p = wm_inits_phase28;
431 for (; *p != (unsigned short)-1; p += 2)
432 wm_put(ice, p[0], p[1]);
433
434 snd_ice1712_restore_gpio_status(ice);
435
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100436 spec->master[0] = WM_VOL_MUTE;
437 spec->master[1] = WM_VOL_MUTE;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200438 for (i = 0; i < ice->num_total_dacs; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100439 spec->vol[i] = WM_VOL_MUTE;
440 wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200441 }
442
443 return 0;
444}
445
446/*
447 * DAC volume attenuation mixer control
448 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100449static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200450{
451 int voices = kcontrol->private_value >> 8;
452 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
453 uinfo->count = voices;
454 uinfo->value.integer.min = 0; /* mute (-101dB) */
455 uinfo->value.integer.max = 0x7F; /* 0dB */
456 return 0;
457}
458
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100459static int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200460{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100461 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100462 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200463 int i, ofs, voices;
464
465 voices = kcontrol->private_value >> 8;
466 ofs = kcontrol->private_value & 0xff;
467 for (i = 0; i < voices; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100468 ucontrol->value.integer.value[i] =
469 spec->vol[ofs+i] & ~WM_VOL_MUTE;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200470 return 0;
471}
472
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100473static int wm_vol_put(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, idx, ofs, voices;
478 int change = 0;
479
480 voices = kcontrol->private_value >> 8;
481 ofs = kcontrol->private_value & 0xff;
482 snd_ice1712_save_gpio_status(ice);
483 for (i = 0; i < voices; i++) {
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100484 unsigned int vol;
485 vol = ucontrol->value.integer.value[i];
486 if (vol > 0x7f)
487 continue;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100488 vol |= spec->vol[ofs+i] & WM_VOL_MUTE;
489 if (vol != spec->vol[ofs+i]) {
490 spec->vol[ofs+i] = vol;
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100491 idx = WM_DAC_ATTEN + ofs + i;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100492 wm_set_vol(ice, idx, spec->vol[ofs+i],
493 spec->master[i]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200494 change = 1;
495 }
496 }
497 snd_ice1712_restore_gpio_status(ice);
498 return change;
499}
500
501/*
502 * WM8770 mute control
503 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100504static int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) {
Simone Zinanniaed058e2005-04-11 14:08:40 +0200505 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
506 uinfo->count = kcontrol->private_value >> 8;
507 uinfo->value.integer.min = 0;
508 uinfo->value.integer.max = 1;
509 return 0;
510}
511
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100512static int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200513{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100514 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100515 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200516 int voices, ofs, i;
517
518 voices = kcontrol->private_value >> 8;
519 ofs = kcontrol->private_value & 0xFF;
520
521 for (i = 0; i < voices; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100522 ucontrol->value.integer.value[i] =
523 (spec->vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200524 return 0;
525}
526
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100527static int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200528{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100529 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100530 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200531 int change = 0, voices, ofs, i;
532
533 voices = kcontrol->private_value >> 8;
534 ofs = kcontrol->private_value & 0xFF;
535
536 snd_ice1712_save_gpio_status(ice);
537 for (i = 0; i < voices; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100538 int val = (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200539 if (ucontrol->value.integer.value[i] != val) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100540 spec->vol[ofs + i] &= ~WM_VOL_MUTE;
541 spec->vol[ofs + i] |=
Simone Zinanniaed058e2005-04-11 14:08:40 +0200542 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100543 wm_set_vol(ice, ofs + i, spec->vol[ofs + i],
544 spec->master[i]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200545 change = 1;
546 }
547 }
548 snd_ice1712_restore_gpio_status(ice);
549
550 return change;
551}
552
553/*
554 * WM8770 master mute control
555 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200556#define wm_master_mute_info snd_ctl_boolean_stereo_info
Simone Zinanniaed058e2005-04-11 14:08:40 +0200557
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100558static int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200559{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100560 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100561 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200562
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100563 ucontrol->value.integer.value[0] =
564 (spec->master[0] & WM_VOL_MUTE) ? 0 : 1;
565 ucontrol->value.integer.value[1] =
566 (spec->master[1] & WM_VOL_MUTE) ? 0 : 1;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200567 return 0;
568}
569
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100570static int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200571{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100572 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100573 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200574 int change = 0, i;
575
576 snd_ice1712_save_gpio_status(ice);
577 for (i = 0; i < 2; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100578 int val = (spec->master[i] & WM_VOL_MUTE) ? 0 : 1;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200579 if (ucontrol->value.integer.value[i] != val) {
580 int dac;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100581 spec->master[i] &= ~WM_VOL_MUTE;
582 spec->master[i] |=
Simone Zinanniaed058e2005-04-11 14:08:40 +0200583 ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE;
584 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
585 wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100586 spec->vol[dac + i],
587 spec->master[i]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200588 change = 1;
589 }
590 }
591 snd_ice1712_restore_gpio_status(ice);
592
593 return change;
594}
595
596/* digital master volume */
597#define PCM_0dB 0xff
598#define PCM_RES 128 /* -64dB */
599#define PCM_MIN (PCM_0dB - PCM_RES)
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100600static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200601{
602 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
603 uinfo->count = 1;
604 uinfo->value.integer.min = 0; /* mute (-64dB) */
605 uinfo->value.integer.max = PCM_RES; /* 0dB */
606 return 0;
607}
608
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100609static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, 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);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200612 unsigned short val;
613
Ingo Molnar62932df2006-01-16 16:34:20 +0100614 mutex_lock(&ice->gpio_mutex);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200615 val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
616 val = val > PCM_MIN ? (val - PCM_MIN) : 0;
617 ucontrol->value.integer.value[0] = val;
Ingo Molnar62932df2006-01-16 16:34:20 +0100618 mutex_unlock(&ice->gpio_mutex);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200619 return 0;
620}
621
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100622static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200623{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100624 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200625 unsigned short ovol, nvol;
626 int change = 0;
627
Simone Zinanniaed058e2005-04-11 14:08:40 +0200628 nvol = ucontrol->value.integer.value[0];
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100629 if (nvol > PCM_RES)
630 return -EINVAL;
631 snd_ice1712_save_gpio_status(ice);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200632 nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff;
633 ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
634 if (ovol != nvol) {
635 wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */
636 wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); /* update */
637 change = 1;
638 }
639 snd_ice1712_restore_gpio_status(ice);
640 return change;
641}
642
643/*
Simone Zinanniaed058e2005-04-11 14:08:40 +0200644 * Deemphasis
645 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200646#define phase28_deemp_info snd_ctl_boolean_mono_info
Simone Zinanniaed058e2005-04-11 14:08:40 +0200647
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100648static int phase28_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200649{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100650 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200651 ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf;
652 return 0;
653}
654
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100655static int phase28_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200656{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100657 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200658 int temp, temp2;
659 temp2 = temp = wm_get(ice, WM_DAC_CTRL2);
660 if (ucontrol->value.integer.value[0])
661 temp |= 0xf;
662 else
663 temp &= ~0xf;
664 if (temp != temp2) {
665 wm_put(ice, WM_DAC_CTRL2, temp);
666 return 1;
667 }
668 return 0;
669}
670
671/*
672 * ADC Oversampling
673 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100674static int phase28_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200675{
676 static char *texts[2] = { "128x", "64x" };
677
678 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
679 uinfo->count = 1;
680 uinfo->value.enumerated.items = 2;
681
682 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
683 uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
684 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
685
686 return 0;
687}
688
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100689static int phase28_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200690{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100691 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200692 ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8;
693 return 0;
694}
695
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100696static int phase28_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200697{
698 int temp, temp2;
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100699 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200700
701 temp2 = temp = wm_get(ice, WM_MASTER);
702
703 if (ucontrol->value.enumerated.item[0])
704 temp |= 0x8;
705 else
706 temp &= ~0x8;
707
708 if (temp != temp2) {
709 wm_put(ice, WM_MASTER, temp);
710 return 1;
711 }
712 return 0;
713}
714
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100715static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
716static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
Takashi Iwaif640c322006-08-30 16:57:37 +0200717
Takashi Iwai1b60f6b2007-03-13 22:13:47 +0100718static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = {
Simone Zinanniaed058e2005-04-11 14:08:40 +0200719 {
720 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
721 .name = "Master Playback Switch",
722 .info = wm_master_mute_info,
723 .get = wm_master_mute_get,
724 .put = wm_master_mute_put
725 },
726 {
727 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200728 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
729 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200730 .name = "Master Playback Volume",
731 .info = wm_master_vol_info,
732 .get = wm_master_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +0200733 .put = wm_master_vol_put,
734 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200735 },
736 {
737 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
738 .name = "Front Playback Switch",
739 .info = wm_mute_info,
740 .get = wm_mute_get,
741 .put = wm_mute_put,
742 .private_value = (2 << 8) | 0
743 },
744 {
745 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200746 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
747 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200748 .name = "Front Playback Volume",
749 .info = wm_vol_info,
750 .get = wm_vol_get,
751 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +0200752 .private_value = (2 << 8) | 0,
753 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200754 },
755 {
756 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
757 .name = "Rear Playback Switch",
758 .info = wm_mute_info,
759 .get = wm_mute_get,
760 .put = wm_mute_put,
761 .private_value = (2 << 8) | 2
762 },
763 {
764 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200765 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
766 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200767 .name = "Rear Playback Volume",
768 .info = wm_vol_info,
769 .get = wm_vol_get,
770 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +0200771 .private_value = (2 << 8) | 2,
772 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200773 },
774 {
775 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
776 .name = "Center Playback Switch",
777 .info = wm_mute_info,
778 .get = wm_mute_get,
779 .put = wm_mute_put,
780 .private_value = (1 << 8) | 4
781 },
782 {
783 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200784 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
785 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200786 .name = "Center Playback Volume",
787 .info = wm_vol_info,
788 .get = wm_vol_get,
789 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +0200790 .private_value = (1 << 8) | 4,
791 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200792 },
793 {
794 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
795 .name = "LFE Playback Switch",
796 .info = wm_mute_info,
797 .get = wm_mute_get,
798 .put = wm_mute_put,
799 .private_value = (1 << 8) | 5
800 },
801 {
802 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200803 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
804 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200805 .name = "LFE Playback Volume",
806 .info = wm_vol_info,
807 .get = wm_vol_get,
808 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +0200809 .private_value = (1 << 8) | 5,
810 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200811 },
812 {
813 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
814 .name = "Side Playback Switch",
815 .info = wm_mute_info,
816 .get = wm_mute_get,
817 .put = wm_mute_put,
818 .private_value = (2 << 8) | 6
819 },
820 {
821 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200822 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
823 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200824 .name = "Side Playback Volume",
825 .info = wm_vol_info,
826 .get = wm_vol_get,
827 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +0200828 .private_value = (2 << 8) | 6,
829 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200830 }
831};
832
Takashi Iwai1b60f6b2007-03-13 22:13:47 +0100833static struct snd_kcontrol_new wm_controls[] __devinitdata = {
Simone Zinanniaed058e2005-04-11 14:08:40 +0200834 {
835 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
836 .name = "PCM Playback Switch",
837 .info = wm_pcm_mute_info,
838 .get = wm_pcm_mute_get,
839 .put = wm_pcm_mute_put
840 },
841 {
842 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200843 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
844 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200845 .name = "PCM Playback Volume",
846 .info = wm_pcm_vol_info,
847 .get = wm_pcm_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +0200848 .put = wm_pcm_vol_put,
849 .tlv = { .p = db_scale_wm_pcm }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200850 },
851 {
852 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
853 .name = "DAC Deemphasis Switch",
854 .info = phase28_deemp_info,
855 .get = phase28_deemp_get,
856 .put = phase28_deemp_put
857 },
858 {
859 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
860 .name = "ADC Oversampling",
861 .info = phase28_oversampling_info,
862 .get = phase28_oversampling_get,
863 .put = phase28_oversampling_put
864 }
865};
866
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100867static int __devinit phase28_add_controls(struct snd_ice1712 *ice)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200868{
869 unsigned int i, counts;
870 int err;
871
872 counts = ARRAY_SIZE(phase28_dac_controls);
873 for (i = 0; i < counts; i++) {
874 err = snd_ctl_add(ice->card, snd_ctl_new1(&phase28_dac_controls[i], ice));
875 if (err < 0)
876 return err;
877 }
878
879 for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
880 err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice));
881 if (err < 0)
882 return err;
883 }
884
885 return 0;
886}
887
Takashi Iwai1b60f6b2007-03-13 22:13:47 +0100888struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 {
890 .subvendor = VT1724_SUBDEVICE_PHASE22,
891 .name = "Terratec PHASE 22",
892 .model = "phase22",
893 .chip_init = phase22_init,
894 .build_controls = phase22_add_controls,
895 .eeprom_size = sizeof(phase22_eeprom),
896 .eeprom_data = phase22_eeprom,
897 },
Simone Zinanniaed058e2005-04-11 14:08:40 +0200898 {
899 .subvendor = VT1724_SUBDEVICE_PHASE28,
900 .name = "Terratec PHASE 28",
901 .model = "phase28",
902 .chip_init = phase28_init,
903 .build_controls = phase28_add_controls,
904 .eeprom_size = sizeof(phase28_eeprom),
905 .eeprom_data = phase28_eeprom,
906 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 { } /* terminator */
908};