blob: 0011e04f36a23bc08dbeb8fbc2af4ead158ed69d [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 <linux/delay.h>
46#include <linux/interrupt.h>
47#include <linux/init.h>
48#include <linux/slab.h>
Ingo Molnar62932df2006-01-16 16:34:20 +010049#include <linux/mutex.h>
50
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include <sound/core.h>
52
53#include "ice1712.h"
54#include "envy24ht.h"
55#include "phase.h"
Takashi Iwaif640c322006-08-30 16:57:37 +020056#include <sound/tlv.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Takashi Iwai7cda8ba2008-01-18 13:36:07 +010058/* AC97 register cache for Phase28 */
59struct phase28_spec {
60 unsigned short master[2];
61 unsigned short vol[8];
Harvey Harrison008f3592008-02-29 11:46:32 +010062};
Takashi Iwai7cda8ba2008-01-18 13:36:07 +010063
Simone Zinanniaed058e2005-04-11 14:08:40 +020064/* WM8770 registers */
65#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */
66#define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */
67#define WM_DAC_DIG_ATTEN 0x09 /* DAC1-8 digital attenuation */
68#define WM_DAC_DIG_MASTER_ATTEN 0x11 /* DAC master digital attenuation */
69#define WM_PHASE_SWAP 0x12 /* DAC phase */
70#define WM_DAC_CTRL1 0x13 /* DAC control bits */
71#define WM_MUTE 0x14 /* mute controls */
72#define WM_DAC_CTRL2 0x15 /* de-emphasis and zefo-flag */
73#define WM_INT_CTRL 0x16 /* interface control */
74#define WM_MASTER 0x17 /* master clock and mode */
75#define WM_POWERDOWN 0x18 /* power-down controls */
76#define WM_ADC_GAIN 0x19 /* ADC gain L(19)/R(1a) */
77#define WM_ADC_MUX 0x1b /* input MUX */
78#define WM_OUT_MUX1 0x1c /* output MUX */
79#define WM_OUT_MUX2 0x1e /* output MUX */
80#define WM_RESET 0x1f /* software reset */
81
82
83/*
84 * Logarithmic volume values for WM8770
85 * Computed as 20 * Log10(255 / x)
86 */
Takashi Iwai32b47da2007-01-29 15:26:36 +010087static const unsigned char wm_vol[256] = {
Vedran Mileticcc67b7f2008-09-07 12:00:02 +020088 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24,
89 24, 23, 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18,
90 17, 17, 17, 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14,
91 14, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11,
92 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9,
93 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7,
94 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5,
95 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
96 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
97 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
98 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
99 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 +0200100};
101
102#define WM_VOL_MAX (sizeof(wm_vol) - 1)
103#define WM_VOL_MUTE 0x8000
104
Bill Pembertone23e7a12012-12-06 12:35:10 -0500105static struct snd_akm4xxx akm_phase22 = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 .type = SND_AK4524,
107 .num_dacs = 2,
108 .num_adcs = 2,
109};
110
Bill Pembertone23e7a12012-12-06 12:35:10 -0500111static struct snd_ak4xxx_private akm_phase22_priv = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 .caddr = 2,
113 .cif = 1,
114 .data_mask = 1 << 4,
115 .clk_mask = 1 << 5,
116 .cs_mask = 1 << 10,
117 .cs_addr = 1 << 10,
118 .cs_none = 0,
119 .add_flags = 1 << 3,
120 .mask_flags = 0,
121};
122
Bill Pembertone23e7a12012-12-06 12:35:10 -0500123static int phase22_init(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100125 struct snd_akm4xxx *ak;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 int err;
127
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200128 /* Configure DAC/ADC description for generic part of ice1724 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 switch (ice->eeprom.subvendor) {
130 case VT1724_SUBDEVICE_PHASE22:
Misha Zhilin740dc9c2008-08-01 12:45:14 +0200131 case VT1724_SUBDEVICE_TS22:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 ice->num_total_dacs = 2;
133 ice->num_total_adcs = 2;
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200134 ice->vt1720 = 1; /* Envy24HT-S have 16 bit wide GPIO */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 break;
136 default:
137 snd_BUG();
138 return -EINVAL;
139 }
140
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200141 /* Initialize analog chips */
142 ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
143 ak = ice->akm;
144 if (!ak)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 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:
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200150 err = snd_ice1712_akm4xxx_init(ak, &akm_phase22,
151 &akm_phase22_priv, ice);
152 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 return err;
154 break;
155 }
156
157 return 0;
158}
159
Bill Pembertone23e7a12012-12-06 12:35:10 -0500160static int phase22_add_controls(struct snd_ice1712 *ice)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161{
162 int err = 0;
163
164 switch (ice->eeprom.subvendor) {
165 case VT1724_SUBDEVICE_PHASE22:
Misha Zhilin740dc9c2008-08-01 12:45:14 +0200166 case VT1724_SUBDEVICE_TS22:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 err = snd_ice1712_akm4xxx_build_controls(ice);
168 if (err < 0)
169 return err;
170 }
171 return 0;
172}
173
Bill Pembertone23e7a12012-12-06 12:35:10 -0500174static unsigned char phase22_eeprom[] = {
Vedran Mileticeee75a62008-08-29 18:31:13 +0200175 [ICE_EEP2_SYSCONF] = 0x28, /* clock 512, mpu 401,
176 spdif-in/1xADC, 1xDACs */
Takashi Iwai189bc172007-01-29 15:25:40 +0100177 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
Vedran Mileticeee75a62008-08-29 18:31:13 +0200178 [ICE_EEP2_I2S] = 0xf0, /* vol, 96k, 24bit */
Takashi Iwai189bc172007-01-29 15:25:40 +0100179 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
180 [ICE_EEP2_GPIO_DIR] = 0xff,
181 [ICE_EEP2_GPIO_DIR1] = 0xff,
182 [ICE_EEP2_GPIO_DIR2] = 0xff,
183 [ICE_EEP2_GPIO_MASK] = 0x00,
184 [ICE_EEP2_GPIO_MASK1] = 0x00,
185 [ICE_EEP2_GPIO_MASK2] = 0x00,
186 [ICE_EEP2_GPIO_STATE] = 0x00,
187 [ICE_EEP2_GPIO_STATE1] = 0x00,
188 [ICE_EEP2_GPIO_STATE2] = 0x00,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189};
190
Bill Pembertone23e7a12012-12-06 12:35:10 -0500191static unsigned char phase28_eeprom[] = {
Vedran Mileticeee75a62008-08-29 18:31:13 +0200192 [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401,
193 spdif-in/1xADC, 4xDACs */
Takashi Iwai189bc172007-01-29 15:25:40 +0100194 [ICE_EEP2_ACLINK] = 0x80, /* I2S */
195 [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */
196 [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */
197 [ICE_EEP2_GPIO_DIR] = 0xff,
198 [ICE_EEP2_GPIO_DIR1] = 0xff,
199 [ICE_EEP2_GPIO_DIR2] = 0x5f,
200 [ICE_EEP2_GPIO_MASK] = 0x00,
201 [ICE_EEP2_GPIO_MASK1] = 0x00,
202 [ICE_EEP2_GPIO_MASK2] = 0x00,
203 [ICE_EEP2_GPIO_STATE] = 0x00,
204 [ICE_EEP2_GPIO_STATE1] = 0x00,
205 [ICE_EEP2_GPIO_STATE2] = 0x00,
Simone Zinanniaed058e2005-04-11 14:08:40 +0200206};
207
208/*
209 * write data in the SPI mode
210 */
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200211static void phase28_spi_write(struct snd_ice1712 *ice, unsigned int cs,
212 unsigned int data, int bits)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200213{
214 unsigned int tmp;
215 int i;
216
217 tmp = snd_ice1712_gpio_read(ice);
218
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200219 snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RW|PHASE28_SPI_MOSI|
220 PHASE28_SPI_CLK|PHASE28_WM_CS));
Simone Zinanniaed058e2005-04-11 14:08:40 +0200221 tmp |= PHASE28_WM_RW;
222 tmp &= ~cs;
223 snd_ice1712_gpio_write(ice, tmp);
224 udelay(1);
225
226 for (i = bits - 1; i >= 0; i--) {
227 tmp &= ~PHASE28_SPI_CLK;
228 snd_ice1712_gpio_write(ice, tmp);
229 udelay(1);
230 if (data & (1 << i))
231 tmp |= PHASE28_SPI_MOSI;
232 else
233 tmp &= ~PHASE28_SPI_MOSI;
234 snd_ice1712_gpio_write(ice, tmp);
235 udelay(1);
236 tmp |= PHASE28_SPI_CLK;
237 snd_ice1712_gpio_write(ice, tmp);
238 udelay(1);
239 }
240
241 tmp &= ~PHASE28_SPI_CLK;
242 tmp |= cs;
243 snd_ice1712_gpio_write(ice, tmp);
244 udelay(1);
245 tmp |= PHASE28_SPI_CLK;
246 snd_ice1712_gpio_write(ice, tmp);
247 udelay(1);
248}
249
250/*
251 * get the current register value of WM codec
252 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100253static unsigned short wm_get(struct snd_ice1712 *ice, int reg)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200254{
255 reg <<= 1;
256 return ((unsigned short)ice->akm[0].images[reg] << 8) |
257 ice->akm[0].images[reg + 1];
258}
259
260/*
261 * set the register value of WM codec
262 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100263static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200264{
265 phase28_spi_write(ice, PHASE28_WM_CS, (reg << 9) | (val & 0x1ff), 16);
266}
267
268/*
269 * set the register value of WM codec and remember it
270 */
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100271static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200272{
273 wm_put_nocache(ice, reg, val);
274 reg <<= 1;
275 ice->akm[0].images[reg] = val >> 8;
276 ice->akm[0].images[reg + 1] = val;
277}
278
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200279static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index,
280 unsigned short vol, unsigned short master)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200281{
282 unsigned char nvol;
283
284 if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
285 nvol = 0;
286 else
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200287 nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) *
288 (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX];
Simone Zinanniaed058e2005-04-11 14:08:40 +0200289
290 wm_put(ice, index, nvol);
291 wm_put_nocache(ice, index, 0x180 | nvol);
292}
293
294/*
295 * DAC mute control
296 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200297#define wm_pcm_mute_info snd_ctl_boolean_mono_info
Simone Zinanniaed058e2005-04-11 14:08:40 +0200298
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200299static int wm_pcm_mute_get(struct snd_kcontrol *kcontrol,
300 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200301{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100302 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200303
Ingo Molnar62932df2006-01-16 16:34:20 +0100304 mutex_lock(&ice->gpio_mutex);
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200305 ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ?
306 0 : 1;
Ingo Molnar62932df2006-01-16 16:34:20 +0100307 mutex_unlock(&ice->gpio_mutex);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200308 return 0;
309}
310
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200311static int wm_pcm_mute_put(struct snd_kcontrol *kcontrol,
312 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200313{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100314 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200315 unsigned short nval, oval;
316 int change;
317
318 snd_ice1712_save_gpio_status(ice);
319 oval = wm_get(ice, WM_MUTE);
320 nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10);
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200321 change = (nval != oval);
322 if (change)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200323 wm_put(ice, WM_MUTE, nval);
324 snd_ice1712_restore_gpio_status(ice);
325
326 return change;
327}
328
329/*
330 * Master volume attenuation mixer control
331 */
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200332static int wm_master_vol_info(struct snd_kcontrol *kcontrol,
333 struct snd_ctl_elem_info *uinfo)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200334{
335 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
336 uinfo->count = 2;
337 uinfo->value.integer.min = 0;
338 uinfo->value.integer.max = WM_VOL_MAX;
339 return 0;
340}
341
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200342static int wm_master_vol_get(struct snd_kcontrol *kcontrol,
343 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200344{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100345 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100346 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200347 int i;
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200348 for (i = 0; i < 2; i++)
349 ucontrol->value.integer.value[i] = spec->master[i] &
350 ~WM_VOL_MUTE;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200351 return 0;
352}
353
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200354static int wm_master_vol_put(struct snd_kcontrol *kcontrol,
355 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200356{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100357 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100358 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200359 int ch, change = 0;
360
361 snd_ice1712_save_gpio_status(ice);
362 for (ch = 0; ch < 2; ch++) {
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100363 unsigned int vol = ucontrol->value.integer.value[ch];
364 if (vol > WM_VOL_MAX)
365 continue;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100366 vol |= spec->master[ch] & WM_VOL_MUTE;
367 if (vol != spec->master[ch]) {
Simone Zinanniaed058e2005-04-11 14:08:40 +0200368 int dac;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100369 spec->master[ch] = vol;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200370 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
371 wm_set_vol(ice, WM_DAC_ATTEN + dac + ch,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100372 spec->vol[dac + ch],
373 spec->master[ch]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200374 change = 1;
375 }
376 }
377 snd_ice1712_restore_gpio_status(ice);
378 return change;
379}
380
Bill Pembertone23e7a12012-12-06 12:35:10 -0500381static int phase28_init(struct snd_ice1712 *ice)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200382{
Takashi Iwai32b47da2007-01-29 15:26:36 +0100383 static const unsigned short wm_inits_phase28[] = {
Simone Zinanniaed058e2005-04-11 14:08:40 +0200384 /* These come first to reduce init pop noise */
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200385 0x1b, 0x044, /* ADC Mux (AC'97 source) */
386 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
387 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
Simone Zinanniaed058e2005-04-11 14:08:40 +0200388
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200389 0x18, 0x000, /* All power-up */
Simone Zinanniaed058e2005-04-11 14:08:40 +0200390
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200391 0x16, 0x122, /* I2S, normal polarity, 24bit */
392 0x17, 0x022, /* 256fs, slave mode */
393 0x00, 0, /* DAC1 analog mute */
394 0x01, 0, /* DAC2 analog mute */
395 0x02, 0, /* DAC3 analog mute */
396 0x03, 0, /* DAC4 analog mute */
397 0x04, 0, /* DAC5 analog mute */
398 0x05, 0, /* DAC6 analog mute */
399 0x06, 0, /* DAC7 analog mute */
400 0x07, 0, /* DAC8 analog mute */
401 0x08, 0x100, /* master analog mute */
402 0x09, 0xff, /* DAC1 digital full */
403 0x0a, 0xff, /* DAC2 digital full */
404 0x0b, 0xff, /* DAC3 digital full */
405 0x0c, 0xff, /* DAC4 digital full */
406 0x0d, 0xff, /* DAC5 digital full */
407 0x0e, 0xff, /* DAC6 digital full */
408 0x0f, 0xff, /* DAC7 digital full */
409 0x10, 0xff, /* DAC8 digital full */
410 0x11, 0x1ff, /* master digital full */
411 0x12, 0x000, /* phase normal */
412 0x13, 0x090, /* unmute DAC L/R */
413 0x14, 0x000, /* all unmute */
414 0x15, 0x000, /* no deemphasis, no ZFLG */
415 0x19, 0x000, /* -12dB ADC/L */
416 0x1a, 0x000, /* -12dB ADC/R */
Simone Zinanniaed058e2005-04-11 14:08:40 +0200417 (unsigned short)-1
418 };
419
420 unsigned int tmp;
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100421 struct snd_akm4xxx *ak;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100422 struct phase28_spec *spec;
Takashi Iwai32b47da2007-01-29 15:26:36 +0100423 const unsigned short *p;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200424 int i;
425
426 ice->num_total_dacs = 8;
427 ice->num_total_adcs = 2;
428
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100429 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
430 if (!spec)
431 return -ENOMEM;
432 ice->spec = spec;
433
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200434 /* Initialize analog chips */
435 ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
436 ak = ice->akm;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200437 if (!ak)
438 return -ENOMEM;
439 ice->akm_codecs = 1;
440
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200441 snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for time being */
Simone Zinanniaed058e2005-04-11 14:08:40 +0200442
443 /* reset the wm codec as the SPI mode */
444 snd_ice1712_save_gpio_status(ice);
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200445 snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RESET|PHASE28_WM_CS|
446 PHASE28_HP_SEL));
Simone Zinanniaed058e2005-04-11 14:08:40 +0200447
448 tmp = snd_ice1712_gpio_read(ice);
449 tmp &= ~PHASE28_WM_RESET;
450 snd_ice1712_gpio_write(ice, tmp);
451 udelay(1);
452 tmp |= PHASE28_WM_CS;
453 snd_ice1712_gpio_write(ice, tmp);
454 udelay(1);
455 tmp |= PHASE28_WM_RESET;
456 snd_ice1712_gpio_write(ice, tmp);
457 udelay(1);
458
459 p = wm_inits_phase28;
460 for (; *p != (unsigned short)-1; p += 2)
461 wm_put(ice, p[0], p[1]);
462
463 snd_ice1712_restore_gpio_status(ice);
464
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100465 spec->master[0] = WM_VOL_MUTE;
466 spec->master[1] = WM_VOL_MUTE;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200467 for (i = 0; i < ice->num_total_dacs; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100468 spec->vol[i] = WM_VOL_MUTE;
469 wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200470 }
471
472 return 0;
473}
474
475/*
476 * DAC volume attenuation mixer control
477 */
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200478static int wm_vol_info(struct snd_kcontrol *kcontrol,
479 struct snd_ctl_elem_info *uinfo)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200480{
481 int voices = kcontrol->private_value >> 8;
482 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
483 uinfo->count = voices;
484 uinfo->value.integer.min = 0; /* mute (-101dB) */
485 uinfo->value.integer.max = 0x7F; /* 0dB */
486 return 0;
487}
488
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200489static int wm_vol_get(struct snd_kcontrol *kcontrol,
490 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200491{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100492 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100493 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200494 int i, ofs, voices;
495
496 voices = kcontrol->private_value >> 8;
497 ofs = kcontrol->private_value & 0xff;
498 for (i = 0; i < voices; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100499 ucontrol->value.integer.value[i] =
500 spec->vol[ofs+i] & ~WM_VOL_MUTE;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200501 return 0;
502}
503
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200504static int wm_vol_put(struct snd_kcontrol *kcontrol,
505 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200506{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100507 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100508 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200509 int i, idx, ofs, voices;
510 int change = 0;
511
512 voices = kcontrol->private_value >> 8;
513 ofs = kcontrol->private_value & 0xff;
514 snd_ice1712_save_gpio_status(ice);
515 for (i = 0; i < voices; i++) {
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100516 unsigned int vol;
517 vol = ucontrol->value.integer.value[i];
518 if (vol > 0x7f)
519 continue;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100520 vol |= spec->vol[ofs+i] & WM_VOL_MUTE;
521 if (vol != spec->vol[ofs+i]) {
522 spec->vol[ofs+i] = vol;
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100523 idx = WM_DAC_ATTEN + ofs + i;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100524 wm_set_vol(ice, idx, spec->vol[ofs+i],
525 spec->master[i]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200526 change = 1;
527 }
528 }
529 snd_ice1712_restore_gpio_status(ice);
530 return change;
531}
532
533/*
534 * WM8770 mute control
535 */
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200536static int wm_mute_info(struct snd_kcontrol *kcontrol,
537 struct snd_ctl_elem_info *uinfo) {
Simone Zinanniaed058e2005-04-11 14:08:40 +0200538 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
539 uinfo->count = kcontrol->private_value >> 8;
540 uinfo->value.integer.min = 0;
541 uinfo->value.integer.max = 1;
542 return 0;
543}
544
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200545static int wm_mute_get(struct snd_kcontrol *kcontrol,
546 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200547{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100548 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100549 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200550 int voices, ofs, i;
551
552 voices = kcontrol->private_value >> 8;
553 ofs = kcontrol->private_value & 0xFF;
554
555 for (i = 0; i < voices; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100556 ucontrol->value.integer.value[i] =
557 (spec->vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200558 return 0;
559}
560
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200561static int wm_mute_put(struct snd_kcontrol *kcontrol,
562 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200563{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100564 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100565 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200566 int change = 0, voices, ofs, i;
567
568 voices = kcontrol->private_value >> 8;
569 ofs = kcontrol->private_value & 0xFF;
570
571 snd_ice1712_save_gpio_status(ice);
572 for (i = 0; i < voices; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100573 int val = (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200574 if (ucontrol->value.integer.value[i] != val) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100575 spec->vol[ofs + i] &= ~WM_VOL_MUTE;
576 spec->vol[ofs + i] |=
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200577 ucontrol->value.integer.value[i] ? 0 :
578 WM_VOL_MUTE;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100579 wm_set_vol(ice, ofs + i, spec->vol[ofs + i],
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200580 spec->master[i]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200581 change = 1;
582 }
583 }
584 snd_ice1712_restore_gpio_status(ice);
585
586 return change;
587}
588
589/*
590 * WM8770 master mute control
591 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200592#define wm_master_mute_info snd_ctl_boolean_stereo_info
Simone Zinanniaed058e2005-04-11 14:08:40 +0200593
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200594static int wm_master_mute_get(struct snd_kcontrol *kcontrol,
595 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200596{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100597 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100598 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200599
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100600 ucontrol->value.integer.value[0] =
601 (spec->master[0] & WM_VOL_MUTE) ? 0 : 1;
602 ucontrol->value.integer.value[1] =
603 (spec->master[1] & WM_VOL_MUTE) ? 0 : 1;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200604 return 0;
605}
606
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200607static int wm_master_mute_put(struct snd_kcontrol *kcontrol,
608 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200609{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100610 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100611 struct phase28_spec *spec = ice->spec;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200612 int change = 0, i;
613
614 snd_ice1712_save_gpio_status(ice);
615 for (i = 0; i < 2; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100616 int val = (spec->master[i] & WM_VOL_MUTE) ? 0 : 1;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200617 if (ucontrol->value.integer.value[i] != val) {
618 int dac;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100619 spec->master[i] &= ~WM_VOL_MUTE;
620 spec->master[i] |=
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200621 ucontrol->value.integer.value[i] ? 0 :
622 WM_VOL_MUTE;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200623 for (dac = 0; dac < ice->num_total_dacs; dac += 2)
624 wm_set_vol(ice, WM_DAC_ATTEN + dac + i,
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200625 spec->vol[dac + i],
626 spec->master[i]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200627 change = 1;
628 }
629 }
630 snd_ice1712_restore_gpio_status(ice);
631
632 return change;
633}
634
635/* digital master volume */
636#define PCM_0dB 0xff
637#define PCM_RES 128 /* -64dB */
638#define PCM_MIN (PCM_0dB - PCM_RES)
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200639static int wm_pcm_vol_info(struct snd_kcontrol *kcontrol,
640 struct snd_ctl_elem_info *uinfo)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200641{
642 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
643 uinfo->count = 1;
644 uinfo->value.integer.min = 0; /* mute (-64dB) */
645 uinfo->value.integer.max = PCM_RES; /* 0dB */
646 return 0;
647}
648
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200649static int wm_pcm_vol_get(struct snd_kcontrol *kcontrol,
650 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200651{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100652 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200653 unsigned short val;
654
Ingo Molnar62932df2006-01-16 16:34:20 +0100655 mutex_lock(&ice->gpio_mutex);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200656 val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
657 val = val > PCM_MIN ? (val - PCM_MIN) : 0;
658 ucontrol->value.integer.value[0] = val;
Ingo Molnar62932df2006-01-16 16:34:20 +0100659 mutex_unlock(&ice->gpio_mutex);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200660 return 0;
661}
662
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200663static int wm_pcm_vol_put(struct snd_kcontrol *kcontrol,
664 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200665{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100666 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200667 unsigned short ovol, nvol;
668 int change = 0;
669
Simone Zinanniaed058e2005-04-11 14:08:40 +0200670 nvol = ucontrol->value.integer.value[0];
Takashi Iwai9cd17cd2007-11-15 15:56:07 +0100671 if (nvol > PCM_RES)
672 return -EINVAL;
673 snd_ice1712_save_gpio_status(ice);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200674 nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff;
675 ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff;
676 if (ovol != nvol) {
677 wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200678 /* update */
679 wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200680 change = 1;
681 }
682 snd_ice1712_restore_gpio_status(ice);
683 return change;
684}
685
686/*
Simone Zinanniaed058e2005-04-11 14:08:40 +0200687 * Deemphasis
688 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200689#define phase28_deemp_info snd_ctl_boolean_mono_info
Simone Zinanniaed058e2005-04-11 14:08:40 +0200690
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200691static int phase28_deemp_get(struct snd_kcontrol *kcontrol,
692 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200693{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100694 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200695 ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) ==
696 0xf;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200697 return 0;
698}
699
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200700static int phase28_deemp_put(struct snd_kcontrol *kcontrol,
701 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200702{
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100703 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200704 int temp, temp2;
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200705 temp = wm_get(ice, WM_DAC_CTRL2);
706 temp2 = temp;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200707 if (ucontrol->value.integer.value[0])
708 temp |= 0xf;
709 else
710 temp &= ~0xf;
711 if (temp != temp2) {
712 wm_put(ice, WM_DAC_CTRL2, temp);
713 return 1;
714 }
715 return 0;
716}
717
718/*
719 * ADC Oversampling
720 */
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200721static int phase28_oversampling_info(struct snd_kcontrol *k,
722 struct snd_ctl_elem_info *uinfo)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200723{
Takashi Iwaia2af0502012-10-17 09:21:48 +0200724 static const char * const texts[2] = { "128x", "64x" };
Simone Zinanniaed058e2005-04-11 14:08:40 +0200725
726 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
727 uinfo->count = 1;
728 uinfo->value.enumerated.items = 2;
729
730 if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200731 uinfo->value.enumerated.item = uinfo->value.enumerated.items -
732 1;
733 strcpy(uinfo->value.enumerated.name,
734 texts[uinfo->value.enumerated.item]);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200735
Simone Zinanniaed058e2005-04-11 14:08:40 +0200736 return 0;
737}
738
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200739static int phase28_oversampling_get(struct snd_kcontrol *kcontrol,
740 struct snd_ctl_elem_value *ucontrol)
741{
742 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
743 ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) ==
744 0x8;
745 return 0;
746}
747
748static int phase28_oversampling_put(struct snd_kcontrol *kcontrol,
749 struct snd_ctl_elem_value *ucontrol)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200750{
751 int temp, temp2;
Takashi Iwaiab0c7d72005-11-17 15:00:18 +0100752 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Simone Zinanniaed058e2005-04-11 14:08:40 +0200753
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200754 temp = wm_get(ice, WM_MASTER);
755 temp2 = temp;
Simone Zinanniaed058e2005-04-11 14:08:40 +0200756
757 if (ucontrol->value.enumerated.item[0])
758 temp |= 0x8;
759 else
760 temp &= ~0x8;
761
762 if (temp != temp2) {
763 wm_put(ice, WM_MASTER, temp);
764 return 1;
765 }
766 return 0;
767}
768
Takashi Iwai0cb29ea2007-01-29 15:33:49 +0100769static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
770static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1);
Takashi Iwaif640c322006-08-30 16:57:37 +0200771
Bill Pembertone23e7a12012-12-06 12:35:10 -0500772static struct snd_kcontrol_new phase28_dac_controls[] = {
Simone Zinanniaed058e2005-04-11 14:08:40 +0200773 {
774 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
775 .name = "Master Playback Switch",
776 .info = wm_master_mute_info,
777 .get = wm_master_mute_get,
778 .put = wm_master_mute_put
779 },
780 {
781 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200782 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
783 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200784 .name = "Master Playback Volume",
785 .info = wm_master_vol_info,
786 .get = wm_master_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +0200787 .put = wm_master_vol_put,
788 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200789 },
790 {
791 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
792 .name = "Front Playback Switch",
793 .info = wm_mute_info,
794 .get = wm_mute_get,
795 .put = wm_mute_put,
796 .private_value = (2 << 8) | 0
797 },
798 {
799 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200800 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
801 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200802 .name = "Front Playback Volume",
803 .info = wm_vol_info,
804 .get = wm_vol_get,
805 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +0200806 .private_value = (2 << 8) | 0,
807 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200808 },
809 {
810 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
811 .name = "Rear Playback Switch",
812 .info = wm_mute_info,
813 .get = wm_mute_get,
814 .put = wm_mute_put,
815 .private_value = (2 << 8) | 2
816 },
817 {
818 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200819 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
820 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200821 .name = "Rear Playback Volume",
822 .info = wm_vol_info,
823 .get = wm_vol_get,
824 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +0200825 .private_value = (2 << 8) | 2,
826 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200827 },
828 {
829 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
830 .name = "Center Playback Switch",
831 .info = wm_mute_info,
832 .get = wm_mute_get,
833 .put = wm_mute_put,
834 .private_value = (1 << 8) | 4
835 },
836 {
837 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200838 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
839 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200840 .name = "Center Playback Volume",
841 .info = wm_vol_info,
842 .get = wm_vol_get,
843 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +0200844 .private_value = (1 << 8) | 4,
845 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200846 },
847 {
848 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
849 .name = "LFE Playback Switch",
850 .info = wm_mute_info,
851 .get = wm_mute_get,
852 .put = wm_mute_put,
853 .private_value = (1 << 8) | 5
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 = "LFE Playback Volume",
860 .info = wm_vol_info,
861 .get = wm_vol_get,
862 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +0200863 .private_value = (1 << 8) | 5,
864 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200865 },
866 {
867 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
868 .name = "Side Playback Switch",
869 .info = wm_mute_info,
870 .get = wm_mute_get,
871 .put = wm_mute_put,
872 .private_value = (2 << 8) | 6
873 },
874 {
875 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200876 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
877 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200878 .name = "Side Playback Volume",
879 .info = wm_vol_info,
880 .get = wm_vol_get,
881 .put = wm_vol_put,
Takashi Iwaif640c322006-08-30 16:57:37 +0200882 .private_value = (2 << 8) | 6,
883 .tlv = { .p = db_scale_wm_dac }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200884 }
885};
886
Bill Pembertone23e7a12012-12-06 12:35:10 -0500887static struct snd_kcontrol_new wm_controls[] = {
Simone Zinanniaed058e2005-04-11 14:08:40 +0200888 {
889 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
890 .name = "PCM Playback Switch",
891 .info = wm_pcm_mute_info,
892 .get = wm_pcm_mute_get,
893 .put = wm_pcm_mute_put
894 },
895 {
896 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwaif640c322006-08-30 16:57:37 +0200897 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
898 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
Simone Zinanniaed058e2005-04-11 14:08:40 +0200899 .name = "PCM Playback Volume",
900 .info = wm_pcm_vol_info,
901 .get = wm_pcm_vol_get,
Takashi Iwaif640c322006-08-30 16:57:37 +0200902 .put = wm_pcm_vol_put,
903 .tlv = { .p = db_scale_wm_pcm }
Simone Zinanniaed058e2005-04-11 14:08:40 +0200904 },
905 {
906 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
907 .name = "DAC Deemphasis Switch",
908 .info = phase28_deemp_info,
909 .get = phase28_deemp_get,
910 .put = phase28_deemp_put
911 },
912 {
913 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
914 .name = "ADC Oversampling",
915 .info = phase28_oversampling_info,
916 .get = phase28_oversampling_get,
917 .put = phase28_oversampling_put
918 }
919};
920
Bill Pembertone23e7a12012-12-06 12:35:10 -0500921static int phase28_add_controls(struct snd_ice1712 *ice)
Simone Zinanniaed058e2005-04-11 14:08:40 +0200922{
923 unsigned int i, counts;
924 int err;
925
926 counts = ARRAY_SIZE(phase28_dac_controls);
927 for (i = 0; i < counts; i++) {
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200928 err = snd_ctl_add(ice->card,
929 snd_ctl_new1(&phase28_dac_controls[i],
930 ice));
Simone Zinanniaed058e2005-04-11 14:08:40 +0200931 if (err < 0)
932 return err;
933 }
934
935 for (i = 0; i < ARRAY_SIZE(wm_controls); i++) {
Vedran Mileticcc67b7f2008-09-07 12:00:02 +0200936 err = snd_ctl_add(ice->card,
937 snd_ctl_new1(&wm_controls[i], ice));
Simone Zinanniaed058e2005-04-11 14:08:40 +0200938 if (err < 0)
939 return err;
940 }
941
942 return 0;
943}
944
Bill Pembertone23e7a12012-12-06 12:35:10 -0500945struct snd_ice1712_card_info snd_vt1724_phase_cards[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 {
947 .subvendor = VT1724_SUBDEVICE_PHASE22,
948 .name = "Terratec PHASE 22",
949 .model = "phase22",
950 .chip_init = phase22_init,
951 .build_controls = phase22_add_controls,
952 .eeprom_size = sizeof(phase22_eeprom),
953 .eeprom_data = phase22_eeprom,
954 },
Simone Zinanniaed058e2005-04-11 14:08:40 +0200955 {
956 .subvendor = VT1724_SUBDEVICE_PHASE28,
957 .name = "Terratec PHASE 28",
958 .model = "phase28",
959 .chip_init = phase28_init,
960 .build_controls = phase28_add_controls,
961 .eeprom_size = sizeof(phase28_eeprom),
962 .eeprom_data = phase28_eeprom,
963 },
Misha Zhilin740dc9c2008-08-01 12:45:14 +0200964 {
965 .subvendor = VT1724_SUBDEVICE_TS22,
966 .name = "Terrasoniq TS22 PCI",
967 .model = "TS22",
968 .chip_init = phase22_init,
969 .build_controls = phase22_add_controls,
970 .eeprom_size = sizeof(phase22_eeprom),
971 .eeprom_data = phase22_eeprom,
972 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 { } /* terminator */
974};