blob: c75515f5be6f0cd7ac4910cf52e930799984535c [file] [log] [blame]
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001/*
2 * ALSA driver for ICEnsemble VT1724 (Envy24HT)
3 *
4 * Lowlevel functions for Audiotrak Prodigy 7.1 Hifi
5 * based on pontis.c
6 *
7 * Copyright (c) 2007 Julian Scheel <julian@jusst.de>
8 * Copyright (c) 2007 allank
9 * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27
28#include <asm/io.h>
29#include <linux/delay.h>
30#include <linux/interrupt.h>
31#include <linux/init.h>
32#include <linux/slab.h>
33#include <linux/mutex.h>
34
35#include <sound/core.h>
36#include <sound/info.h>
37#include <sound/tlv.h>
38
39#include "ice1712.h"
40#include "envy24ht.h"
41#include "prodigy_hifi.h"
42
Takashi Iwai7cda8ba2008-01-18 13:36:07 +010043struct prodigy_hifi_spec {
44 unsigned short master[2];
45 unsigned short vol[8];
46};
47
Julian Scheel6b8d6e52008-01-16 19:50:00 +010048/* I2C addresses */
49#define WM_DEV 0x34
50
51/* WM8776 registers */
52#define WM_HP_ATTEN_L 0x00 /* headphone left attenuation */
53#define WM_HP_ATTEN_R 0x01 /* headphone left attenuation */
54#define WM_HP_MASTER 0x02 /* headphone master (both channels),
55 override LLR */
56#define WM_DAC_ATTEN_L 0x03 /* digital left attenuation */
57#define WM_DAC_ATTEN_R 0x04
58#define WM_DAC_MASTER 0x05
59#define WM_PHASE_SWAP 0x06 /* DAC phase swap */
60#define WM_DAC_CTRL1 0x07
61#define WM_DAC_MUTE 0x08
62#define WM_DAC_CTRL2 0x09
63#define WM_DAC_INT 0x0a
64#define WM_ADC_INT 0x0b
65#define WM_MASTER_CTRL 0x0c
66#define WM_POWERDOWN 0x0d
67#define WM_ADC_ATTEN_L 0x0e
68#define WM_ADC_ATTEN_R 0x0f
69#define WM_ALC_CTRL1 0x10
70#define WM_ALC_CTRL2 0x11
71#define WM_ALC_CTRL3 0x12
72#define WM_NOISE_GATE 0x13
73#define WM_LIMITER 0x14
74#define WM_ADC_MUX 0x15
75#define WM_OUT_MUX 0x16
76#define WM_RESET 0x17
77
78/* Analog Recording Source :- Mic, LineIn, CD/Video, */
79
80/* implement capture source select control for WM8776 */
81
82#define WM_AIN1 "AIN1"
83#define WM_AIN2 "AIN2"
84#define WM_AIN3 "AIN3"
85#define WM_AIN4 "AIN4"
86#define WM_AIN5 "AIN5"
87
88/* GPIO pins of envy24ht connected to wm8766 */
89#define WM8766_SPI_CLK (1<<17) /* CLK, Pin97 on ICE1724 */
90#define WM8766_SPI_MD (1<<16) /* DATA VT1724 -> WM8766, Pin96 */
91#define WM8766_SPI_ML (1<<18) /* Latch, Pin98 */
92
93/* WM8766 registers */
94#define WM8766_DAC_CTRL 0x02 /* DAC Control */
95#define WM8766_INT_CTRL 0x03 /* Interface Control */
96#define WM8766_DAC_CTRL2 0x09
97#define WM8766_DAC_CTRL3 0x0a
98#define WM8766_RESET 0x1f
99#define WM8766_LDA1 0x00
100#define WM8766_LDA2 0x04
101#define WM8766_LDA3 0x06
102#define WM8766_RDA1 0x01
103#define WM8766_RDA2 0x05
104#define WM8766_RDA3 0x07
105#define WM8766_MUTE1 0x0C
106#define WM8766_MUTE2 0x0F
107
108
109/*
110 * Prodigy HD2
111 */
112#define AK4396_ADDR 0x00
113#define AK4396_CSN (1 << 8) /* CSN->GPIO8, pin 75 */
114#define AK4396_CCLK (1 << 9) /* CCLK->GPIO9, pin 76 */
115#define AK4396_CDTI (1 << 10) /* CDTI->GPIO10, pin 77 */
116
117/* ak4396 registers */
118#define AK4396_CTRL1 0x00
119#define AK4396_CTRL2 0x01
120#define AK4396_CTRL3 0x02
121#define AK4396_LCH_ATT 0x03
122#define AK4396_RCH_ATT 0x04
123
124
125/*
126 * get the current register value of WM codec
127 */
128static unsigned short wm_get(struct snd_ice1712 *ice, int reg)
129{
130 reg <<= 1;
131 return ((unsigned short)ice->akm[0].images[reg] << 8) |
132 ice->akm[0].images[reg + 1];
133}
134
135/*
136 * set the register value of WM codec and remember it
137 */
138static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
139{
140 unsigned short cval;
141 cval = (reg << 9) | val;
142 snd_vt1724_write_i2c(ice, WM_DEV, cval >> 8, cval & 0xff);
143}
144
145static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
146{
147 wm_put_nocache(ice, reg, val);
148 reg <<= 1;
149 ice->akm[0].images[reg] = val >> 8;
150 ice->akm[0].images[reg + 1] = val;
151}
152
153/*
154 * write data in the SPI mode
155 */
156
157static void set_gpio_bit(struct snd_ice1712 *ice, unsigned int bit, int val)
158{
159 unsigned int tmp = snd_ice1712_gpio_read(ice);
160 if (val)
161 tmp |= bit;
162 else
163 tmp &= ~bit;
164 snd_ice1712_gpio_write(ice, tmp);
165}
166
167/*
168 * SPI implementation for WM8766 codec - only writing supported, no readback
169 */
170
171static void wm8766_spi_send_word(struct snd_ice1712 *ice, unsigned int data)
172{
173 int i;
174 for (i = 0; i < 16; i++) {
175 set_gpio_bit(ice, WM8766_SPI_CLK, 0);
176 udelay(1);
177 set_gpio_bit(ice, WM8766_SPI_MD, data & 0x8000);
178 udelay(1);
179 set_gpio_bit(ice, WM8766_SPI_CLK, 1);
180 udelay(1);
181 data <<= 1;
182 }
183}
184
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100185static void wm8766_spi_write(struct snd_ice1712 *ice, unsigned int reg,
186 unsigned int data)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100187{
188 unsigned int block;
189
190 snd_ice1712_gpio_set_dir(ice, WM8766_SPI_MD|
191 WM8766_SPI_CLK|WM8766_SPI_ML);
192 snd_ice1712_gpio_set_mask(ice, ~(WM8766_SPI_MD|
193 WM8766_SPI_CLK|WM8766_SPI_ML));
194 /* latch must be low when writing */
195 set_gpio_bit(ice, WM8766_SPI_ML, 0);
196 block = (reg << 9) | (data & 0x1ff);
197 wm8766_spi_send_word(ice, block); /* REGISTER ADDRESS */
198 /* release latch */
199 set_gpio_bit(ice, WM8766_SPI_ML, 1);
200 udelay(1);
201 /* restore */
202 snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);
203 snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
204}
205
206
207/*
208 * serial interface for ak4396 - only writing supported, no readback
209 */
210
211static void ak4396_send_word(struct snd_ice1712 *ice, unsigned int data)
212{
213 int i;
214 for (i = 0; i < 16; i++) {
215 set_gpio_bit(ice, AK4396_CCLK, 0);
216 udelay(1);
217 set_gpio_bit(ice, AK4396_CDTI, data & 0x8000);
218 udelay(1);
219 set_gpio_bit(ice, AK4396_CCLK, 1);
220 udelay(1);
221 data <<= 1;
222 }
223}
224
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100225static void ak4396_write(struct snd_ice1712 *ice, unsigned int reg,
226 unsigned int data)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100227{
228 unsigned int block;
229
230 snd_ice1712_gpio_set_dir(ice, AK4396_CSN|AK4396_CCLK|AK4396_CDTI);
231 snd_ice1712_gpio_set_mask(ice, ~(AK4396_CSN|AK4396_CCLK|AK4396_CDTI));
232 /* latch must be low when writing */
233 set_gpio_bit(ice, AK4396_CSN, 0);
234 block = ((AK4396_ADDR & 0x03) << 14) | (1 << 13) |
235 ((reg & 0x1f) << 8) | (data & 0xff);
236 ak4396_send_word(ice, block); /* REGISTER ADDRESS */
237 /* release latch */
238 set_gpio_bit(ice, AK4396_CSN, 1);
239 udelay(1);
240 /* restore */
241 snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);
242 snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
243}
244
245
246/*
247 * ak4396 mixers
248 */
249
250
251
252/*
253 * DAC volume attenuation mixer control (-64dB to 0dB)
254 */
255
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100256static int ak4396_dac_vol_info(struct snd_kcontrol *kcontrol,
257 struct snd_ctl_elem_info *uinfo)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100258{
259 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
260 uinfo->count = 2;
261 uinfo->value.integer.min = 0; /* mute */
262 uinfo->value.integer.max = 0xFF; /* linear */
263 return 0;
264}
265
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100266static int ak4396_dac_vol_get(struct snd_kcontrol *kcontrol,
267 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100268{
269 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100270 struct prodigy_hifi_spec *spec = ice->spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100271 int i;
272
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100273 for (i = 0; i < 2; i++)
274 ucontrol->value.integer.value[i] = spec->vol[i];
275
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100276 return 0;
277}
278
279static int ak4396_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
280{
281 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100282 struct prodigy_hifi_spec *spec = ice->spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100283 int i;
284 int change = 0;
285
286 mutex_lock(&ice->gpio_mutex);
287 for (i = 0; i < 2; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100288 if (ucontrol->value.integer.value[i] != spec->vol[i]) {
289 spec->vol[i] = ucontrol->value.integer.value[i];
290 ak4396_write(ice, AK4396_LCH_ATT + i,
291 spec->vol[i] & 0xff);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100292 change = 1;
293 }
294 }
295 mutex_unlock(&ice->gpio_mutex);
296 return change;
297}
298
299static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
300
301static struct snd_kcontrol_new prodigy_hd2_controls[] __devinitdata = {
302 {
303 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
304 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
305 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
306 .name = "Front Playback Volume",
307 .info = ak4396_dac_vol_info,
308 .get = ak4396_dac_vol_get,
309 .put = ak4396_dac_vol_put,
310 .tlv = { .p = db_scale_wm_dac },
311 },
312};
313
314
315/* --------------- */
316
317/*
318 * Logarithmic volume values for WM87*6
319 * Computed as 20 * Log10(255 / x)
320 */
321static const unsigned char wm_vol[256] = {
322 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
323 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
324 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
325 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11,
326 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8,
327 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,
328 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,
329 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,
330 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,
331 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,
332 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,
333 0, 0
334};
335
336#define WM_VOL_MAX (sizeof(wm_vol) - 1)
337#define WM_VOL_MUTE 0x8000
338
339
340#define DAC_0dB 0xff
341#define DAC_RES 128
342#define DAC_MIN (DAC_0dB - DAC_RES)
343
344
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100345static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index,
346 unsigned short vol, unsigned short master)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100347{
348 unsigned char nvol;
349
350 if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
351 nvol = 0;
352 else {
353 nvol = (((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 128)
354 & WM_VOL_MAX;
355 nvol = (nvol ? (nvol + DAC_MIN) : 0) & 0xff;
356 }
357
358 wm_put(ice, index, nvol);
359 wm_put_nocache(ice, index, 0x100 | nvol);
360}
361
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100362static void wm8766_set_vol(struct snd_ice1712 *ice, unsigned int index,
363 unsigned short vol, unsigned short master)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100364{
365 unsigned char nvol;
366
367 if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
368 nvol = 0;
369 else {
370 nvol = (((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 128)
371 & WM_VOL_MAX;
372 nvol = (nvol ? (nvol + DAC_MIN) : 0) & 0xff;
373 }
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100374
375 wm8766_spi_write(ice, index, (0x0100 | nvol));
376}
377
378
379/*
380 * DAC volume attenuation mixer control (-64dB to 0dB)
381 */
382
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100383static int wm_dac_vol_info(struct snd_kcontrol *kcontrol,
384 struct snd_ctl_elem_info *uinfo)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100385{
386 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
387 uinfo->count = 2;
388 uinfo->value.integer.min = 0; /* mute */
389 uinfo->value.integer.max = DAC_RES; /* 0dB, 0.5dB step */
390 return 0;
391}
392
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100393static int wm_dac_vol_get(struct snd_kcontrol *kcontrol,
394 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100395{
396 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100397 struct prodigy_hifi_spec *spec = ice->spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100398 int i;
399
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100400 for (i = 0; i < 2; i++)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100401 ucontrol->value.integer.value[i] =
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100402 spec->vol[2 + i] & ~WM_VOL_MUTE;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100403 return 0;
404}
405
406static int wm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
407{
408 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100409 struct prodigy_hifi_spec *spec = ice->spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100410 int i, idx, change = 0;
411
412 mutex_lock(&ice->gpio_mutex);
413 for (i = 0; i < 2; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100414 if (ucontrol->value.integer.value[i] != spec->vol[2 + i]) {
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100415 idx = WM_DAC_ATTEN_L + i;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100416 spec->vol[2 + i] &= WM_VOL_MUTE;
417 spec->vol[2 + i] |= ucontrol->value.integer.value[i];
418 wm_set_vol(ice, idx, spec->vol[2 + i], spec->master[i]);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100419 change = 1;
420 }
421 }
422 mutex_unlock(&ice->gpio_mutex);
423 return change;
424}
425
426
427/*
428 * WM8766 DAC volume attenuation mixer control
429 */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100430static int wm8766_vol_info(struct snd_kcontrol *kcontrol,
431 struct snd_ctl_elem_info *uinfo)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100432{
433 int voices = kcontrol->private_value >> 8;
434 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
435 uinfo->count = voices;
436 uinfo->value.integer.min = 0; /* mute */
437 uinfo->value.integer.max = DAC_RES; /* 0dB */
438 return 0;
439}
440
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100441static int wm8766_vol_get(struct snd_kcontrol *kcontrol,
442 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100443{
444 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100445 struct prodigy_hifi_spec *spec = ice->spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100446 int i, ofs, voices;
447
448 voices = kcontrol->private_value >> 8;
449 ofs = kcontrol->private_value & 0xff;
450 for (i = 0; i < voices; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100451 ucontrol->value.integer.value[i] = spec->vol[ofs + i];
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100452 return 0;
453}
454
455static int wm8766_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
456{
457 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100458 struct prodigy_hifi_spec *spec = ice->spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100459 int i, idx, ofs, voices;
460 int change = 0;
461
462 voices = kcontrol->private_value >> 8;
463 ofs = kcontrol->private_value & 0xff;
464 mutex_lock(&ice->gpio_mutex);
465 for (i = 0; i < voices; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100466 if (ucontrol->value.integer.value[i] != spec->vol[ofs + i]) {
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100467 idx = WM8766_LDA1 + ofs + i;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100468 spec->vol[ofs + i] &= WM_VOL_MUTE;
469 spec->vol[ofs + i] |= ucontrol->value.integer.value[i];
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100470 wm8766_set_vol(ice, idx,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100471 spec->vol[ofs + i], spec->master[i]);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100472 change = 1;
473 }
474 }
475 mutex_unlock(&ice->gpio_mutex);
476 return change;
477}
478
479/*
480 * Master volume attenuation mixer control / applied to WM8776+WM8766
481 */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100482static int wm_master_vol_info(struct snd_kcontrol *kcontrol,
483 struct snd_ctl_elem_info *uinfo)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100484{
485 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
486 uinfo->count = 2;
487 uinfo->value.integer.min = 0;
488 uinfo->value.integer.max = DAC_RES;
489 return 0;
490}
491
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100492static int wm_master_vol_get(struct snd_kcontrol *kcontrol,
493 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100494{
495 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100496 struct prodigy_hifi_spec *spec = ice->spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100497 int i;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100498 for (i = 0; i < 2; i++)
499 ucontrol->value.integer.value[i] = spec->master[i];
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100500 return 0;
501}
502
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100503static int wm_master_vol_put(struct snd_kcontrol *kcontrol,
504 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100505{
506 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100507 struct prodigy_hifi_spec *spec = ice->spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100508 int ch, change = 0;
509
510 mutex_lock(&ice->gpio_mutex);
511 for (ch = 0; ch < 2; ch++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100512 if (ucontrol->value.integer.value[ch] != spec->master[ch]) {
513 spec->master[ch] = ucontrol->value.integer.value[ch];
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100514
515 /* Apply to front DAC */
516 wm_set_vol(ice, WM_DAC_ATTEN_L + ch,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100517 spec->vol[2 + ch], spec->master[ch]);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100518
519 wm8766_set_vol(ice, WM8766_LDA1 + ch,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100520 spec->vol[0 + ch], spec->master[ch]);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100521
522 wm8766_set_vol(ice, WM8766_LDA2 + ch,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100523 spec->vol[4 + ch], spec->master[ch]);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100524
525 wm8766_set_vol(ice, WM8766_LDA3 + ch,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100526 spec->vol[6 + ch], spec->master[ch]);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100527 change = 1;
528 }
529 }
530 mutex_unlock(&ice->gpio_mutex);
531 return change;
532}
533
534
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100535/* KONSTI */
536
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100537static int wm_adc_mux_enum_info(struct snd_kcontrol *kcontrol,
538 struct snd_ctl_elem_info *uinfo)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100539{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100540 static char* texts[32] = {
541 "NULL", WM_AIN1, WM_AIN2, WM_AIN1 "+" WM_AIN2,
542 WM_AIN3, WM_AIN1 "+" WM_AIN3, WM_AIN2 "+" WM_AIN3,
543 WM_AIN1 "+" WM_AIN2 "+" WM_AIN3,
544 WM_AIN4, WM_AIN1 "+" WM_AIN4, WM_AIN2 "+" WM_AIN4,
545 WM_AIN1 "+" WM_AIN2 "+" WM_AIN4,
546 WM_AIN3 "+" WM_AIN4, WM_AIN1 "+" WM_AIN3 "+" WM_AIN4,
547 WM_AIN2 "+" WM_AIN3 "+" WM_AIN4,
548 WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4,
549 WM_AIN5, WM_AIN1 "+" WM_AIN5, WM_AIN2 "+" WM_AIN5,
550 WM_AIN1 "+" WM_AIN2 "+" WM_AIN5,
551 WM_AIN3 "+" WM_AIN5, WM_AIN1 "+" WM_AIN3 "+" WM_AIN5,
552 WM_AIN2 "+" WM_AIN3 "+" WM_AIN5,
553 WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN5,
554 WM_AIN4 "+" WM_AIN5, WM_AIN1 "+" WM_AIN4 "+" WM_AIN5,
555 WM_AIN2 "+" WM_AIN4 "+" WM_AIN5,
556 WM_AIN1 "+" WM_AIN2 "+" WM_AIN4 "+" WM_AIN5,
557 WM_AIN3 "+" WM_AIN4 "+" WM_AIN5,
558 WM_AIN1 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5,
559 WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5,
560 WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5
561 };
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100562
563 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
564 uinfo->count = 1;
565 uinfo->value.enumerated.items = 32;
566 if (uinfo->value.enumerated.item > 31)
567 uinfo->value.enumerated.item = 31;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100568 strcpy(uinfo->value.enumerated.name,
569 texts[uinfo->value.enumerated.item]);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100570 return 0;
571}
572
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100573static int wm_adc_mux_enum_get(struct snd_kcontrol *kcontrol,
574 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100575{
576 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
577
578 mutex_lock(&ice->gpio_mutex);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100579 ucontrol->value.integer.value[0] = wm_get(ice, WM_ADC_MUX) & 0x1f;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100580 mutex_unlock(&ice->gpio_mutex);
581 return 0;
582}
583
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100584static int wm_adc_mux_enum_put(struct snd_kcontrol *kcontrol,
585 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100586{
587 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
588 unsigned short oval, nval;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100589 int change = 0;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100590
591 mutex_lock(&ice->gpio_mutex);
592 oval = wm_get(ice, WM_ADC_MUX);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100593 nval = (oval & 0xe0) | ucontrol->value.integer.value[0];
594 if (nval != oval) {
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100595 wm_put(ice, WM_ADC_MUX, nval);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100596 change = 1;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100597 }
598 mutex_unlock(&ice->gpio_mutex);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100599 return change;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100600}
601
602/* KONSTI */
603
604/*
605 * ADC gain mixer control (-64dB to 0dB)
606 */
607
608#define ADC_0dB 0xcf
609#define ADC_RES 128
610#define ADC_MIN (ADC_0dB - ADC_RES)
611
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100612static int wm_adc_vol_info(struct snd_kcontrol *kcontrol,
613 struct snd_ctl_elem_info *uinfo)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100614{
615 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
616 uinfo->count = 2;
617 uinfo->value.integer.min = 0; /* mute (-64dB) */
618 uinfo->value.integer.max = ADC_RES; /* 0dB, 0.5dB step */
619 return 0;
620}
621
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100622static int wm_adc_vol_get(struct snd_kcontrol *kcontrol,
623 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100624{
625 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
626 unsigned short val;
627 int i;
628
629 mutex_lock(&ice->gpio_mutex);
630 for (i = 0; i < 2; i++) {
631 val = wm_get(ice, WM_ADC_ATTEN_L + i) & 0xff;
632 val = val > ADC_MIN ? (val - ADC_MIN) : 0;
633 ucontrol->value.integer.value[i] = val;
634 }
635 mutex_unlock(&ice->gpio_mutex);
636 return 0;
637}
638
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100639static int wm_adc_vol_put(struct snd_kcontrol *kcontrol,
640 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100641{
642 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
643 unsigned short ovol, nvol;
644 int i, idx, change = 0;
645
646 mutex_lock(&ice->gpio_mutex);
647 for (i = 0; i < 2; i++) {
648 nvol = ucontrol->value.integer.value[i];
649 nvol = nvol ? (nvol + ADC_MIN) : 0;
650 idx = WM_ADC_ATTEN_L + i;
651 ovol = wm_get(ice, idx) & 0xff;
652 if (ovol != nvol) {
653 wm_put(ice, idx, nvol);
654 change = 1;
655 }
656 }
657 mutex_unlock(&ice->gpio_mutex);
658 return change;
659}
660
661/*
662 * ADC input mux mixer control
663 */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100664#define wm_adc_mux_info snd_ctl_boolean_mono_info
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100665
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100666static int wm_adc_mux_get(struct snd_kcontrol *kcontrol,
667 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100668{
669 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
670 int bit = kcontrol->private_value;
671
672 mutex_lock(&ice->gpio_mutex);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100673 ucontrol->value.integer.value[0] =
674 (wm_get(ice, WM_ADC_MUX) & (1 << bit)) ? 1 : 0;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100675 mutex_unlock(&ice->gpio_mutex);
676 return 0;
677}
678
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100679static int wm_adc_mux_put(struct snd_kcontrol *kcontrol,
680 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100681{
682 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
683 int bit = kcontrol->private_value;
684 unsigned short oval, nval;
685 int change;
686
687 mutex_lock(&ice->gpio_mutex);
688 nval = oval = wm_get(ice, WM_ADC_MUX);
689 if (ucontrol->value.integer.value[0])
690 nval |= (1 << bit);
691 else
692 nval &= ~(1 << bit);
693 change = nval != oval;
694 if (change) {
695 wm_put(ice, WM_ADC_MUX, nval);
696 }
697 mutex_unlock(&ice->gpio_mutex);
698 return 0;
699}
700
701/*
702 * Analog bypass (In -> Out)
703 */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100704#define wm_bypass_info snd_ctl_boolean_mono_info
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100705
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100706static int wm_bypass_get(struct snd_kcontrol *kcontrol,
707 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100708{
709 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
710
711 mutex_lock(&ice->gpio_mutex);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100712 ucontrol->value.integer.value[0] =
713 (wm_get(ice, WM_OUT_MUX) & 0x04) ? 1 : 0;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100714 mutex_unlock(&ice->gpio_mutex);
715 return 0;
716}
717
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100718static int wm_bypass_put(struct snd_kcontrol *kcontrol,
719 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100720{
721 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
722 unsigned short val, oval;
723 int change = 0;
724
725 mutex_lock(&ice->gpio_mutex);
726 val = oval = wm_get(ice, WM_OUT_MUX);
727 if (ucontrol->value.integer.value[0])
728 val |= 0x04;
729 else
730 val &= ~0x04;
731 if (val != oval) {
732 wm_put(ice, WM_OUT_MUX, val);
733 change = 1;
734 }
735 mutex_unlock(&ice->gpio_mutex);
736 return change;
737}
738
739/*
740 * Left/Right swap
741 */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100742#define wm_chswap_info snd_ctl_boolean_mono_info
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100743
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100744static int wm_chswap_get(struct snd_kcontrol *kcontrol,
745 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100746{
747 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
748
749 mutex_lock(&ice->gpio_mutex);
750 ucontrol->value.integer.value[0] =
751 (wm_get(ice, WM_DAC_CTRL1) & 0xf0) != 0x90;
752 mutex_unlock(&ice->gpio_mutex);
753 return 0;
754}
755
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100756static int wm_chswap_put(struct snd_kcontrol *kcontrol,
757 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100758{
759 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
760 unsigned short val, oval;
761 int change = 0;
762
763 mutex_lock(&ice->gpio_mutex);
764 oval = wm_get(ice, WM_DAC_CTRL1);
765 val = oval & 0x0f;
766 if (ucontrol->value.integer.value[0])
767 val |= 0x60;
768 else
769 val |= 0x90;
770 if (val != oval) {
771 wm_put(ice, WM_DAC_CTRL1, val);
772 wm_put_nocache(ice, WM_DAC_CTRL1, val);
773 change = 1;
774 }
775 mutex_unlock(&ice->gpio_mutex);
776 return change;
777}
778
779
780/*
781 * mixers
782 */
783
784static struct snd_kcontrol_new prodigy_hifi_controls[] __devinitdata = {
785 {
786 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
787 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
788 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
789 .name = "Master Playback Volume",
790 .info = wm_master_vol_info,
791 .get = wm_master_vol_get,
792 .put = wm_master_vol_put,
793 .tlv = { .p = db_scale_wm_dac }
794 },
795 {
796 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
797 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
798 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
799 .name = "Front Playback Volume",
800 .info = wm_dac_vol_info,
801 .get = wm_dac_vol_get,
802 .put = wm_dac_vol_put,
803 .tlv = { .p = db_scale_wm_dac },
804 },
805 {
806 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
807 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
808 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
809 .name = "Rear Playback Volume",
810 .info = wm8766_vol_info,
811 .get = wm8766_vol_get,
812 .put = wm8766_vol_put,
813 .private_value = (2 << 8) | 0,
814 .tlv = { .p = db_scale_wm_dac },
815 },
816 {
817 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
818 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
819 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
820 .name = "Center Playback Volume",
821 .info = wm8766_vol_info,
822 .get = wm8766_vol_get,
823 .put = wm8766_vol_put,
824 .private_value = (1 << 8) | 4,
825 .tlv = { .p = db_scale_wm_dac }
826 },
827 {
828 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
829 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
830 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
831 .name = "LFE Playback Volume",
832 .info = wm8766_vol_info,
833 .get = wm8766_vol_get,
834 .put = wm8766_vol_put,
835 .private_value = (1 << 8) | 5,
836 .tlv = { .p = db_scale_wm_dac }
837 },
838 {
839 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
840 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
841 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
842 .name = "Side Playback Volume",
843 .info = wm8766_vol_info,
844 .get = wm8766_vol_get,
845 .put = wm8766_vol_put,
846 .private_value = (2 << 8) | 6,
847 .tlv = { .p = db_scale_wm_dac },
848 },
849 {
850 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
851 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
852 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
853 .name = "Capture Volume",
854 .info = wm_adc_vol_info,
855 .get = wm_adc_vol_get,
856 .put = wm_adc_vol_put,
857 .tlv = { .p = db_scale_wm_dac },
858 },
859 {
860 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
861 .name = "CD Capture Switch",
862 .info = wm_adc_mux_info,
863 .get = wm_adc_mux_get,
864 .put = wm_adc_mux_put,
865 .private_value = 0,
866 },
867 {
868 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
869 .name = "Line Capture Switch",
870 .info = wm_adc_mux_info,
871 .get = wm_adc_mux_get,
872 .put = wm_adc_mux_put,
873 .private_value = 1,
874 },
875 {
876 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
877 .name = "Analog Bypass Switch",
878 .info = wm_bypass_info,
879 .get = wm_bypass_get,
880 .put = wm_bypass_put,
881 },
882 {
883 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
884 .name = "Swap Output Channels",
885 .info = wm_chswap_info,
886 .get = wm_chswap_get,
887 .put = wm_chswap_put,
888 },
889 {
890 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
891 .name = "Analog Capture Source",
892 .info = wm_adc_mux_enum_info,
893 .get = wm_adc_mux_enum_get,
894 .put = wm_adc_mux_enum_put,
895 },
896};
897
898/*
899 * WM codec registers
900 */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100901static void wm_proc_regs_write(struct snd_info_entry *entry,
902 struct snd_info_buffer *buffer)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100903{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100904 struct snd_ice1712 *ice = entry->private_data;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100905 char line[64];
906 unsigned int reg, val;
907 mutex_lock(&ice->gpio_mutex);
908 while (!snd_info_get_line(buffer, line, sizeof(line))) {
909 if (sscanf(line, "%x %x", &reg, &val) != 2)
910 continue;
911 if (reg <= 0x17 && val <= 0xffff)
912 wm_put(ice, reg, val);
913 }
914 mutex_unlock(&ice->gpio_mutex);
915}
916
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100917static void wm_proc_regs_read(struct snd_info_entry *entry,
918 struct snd_info_buffer *buffer)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100919{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100920 struct snd_ice1712 *ice = entry->private_data;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100921 int reg, val;
922
923 mutex_lock(&ice->gpio_mutex);
924 for (reg = 0; reg <= 0x17; reg++) {
925 val = wm_get(ice, reg);
926 snd_iprintf(buffer, "%02x = %04x\n", reg, val);
927 }
928 mutex_unlock(&ice->gpio_mutex);
929}
930
931static void wm_proc_init(struct snd_ice1712 *ice)
932{
933 struct snd_info_entry *entry;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100934 if (!snd_card_proc_new(ice->card, "wm_codec", &entry)) {
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100935 snd_info_set_text_ops(entry, ice, wm_proc_regs_read);
936 entry->mode |= S_IWUSR;
937 entry->c.text.write = wm_proc_regs_write;
938 }
939}
940
941static int __devinit prodigy_hifi_add_controls(struct snd_ice1712 *ice)
942{
943 unsigned int i;
944 int err;
945
946 for (i = 0; i < ARRAY_SIZE(prodigy_hifi_controls); i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100947 err = snd_ctl_add(ice->card,
948 snd_ctl_new1(&prodigy_hifi_controls[i], ice));
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100949 if (err < 0)
950 return err;
951 }
952
953 wm_proc_init(ice);
954
955 return 0;
956}
957
958static int __devinit prodigy_hd2_add_controls(struct snd_ice1712 *ice)
959{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100960 unsigned int i;
961 int err;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100962
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100963 for (i = 0; i < ARRAY_SIZE(prodigy_hd2_controls); i++) {
964 err = snd_ctl_add(ice->card,
965 snd_ctl_new1(&prodigy_hd2_controls[i], ice));
966 if (err < 0)
967 return err;
968 }
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100969
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100970 wm_proc_init(ice);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100971
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100972 return 0;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100973}
974
975
976/*
977 * initialize the chip
978 */
979static int __devinit prodigy_hifi_init(struct snd_ice1712 *ice)
980{
981 static unsigned short wm_inits[] = {
982 /* These come first to reduce init pop noise */
983 WM_ADC_MUX, 0x0003, /* ADC mute */
984 /* 0x00c0 replaced by 0x0003 */
985
986 WM_DAC_MUTE, 0x0001, /* DAC softmute */
987 WM_DAC_CTRL1, 0x0000, /* DAC mute */
988
989 WM_POWERDOWN, 0x0008, /* All power-up except HP */
990 WM_RESET, 0x0000, /* reset */
991 };
992 static unsigned short wm_inits2[] = {
993 WM_MASTER_CTRL, 0x0022, /* 256fs, slave mode */
994 WM_DAC_INT, 0x0022, /* I2S, normal polarity, 24bit */
995 WM_ADC_INT, 0x0022, /* I2S, normal polarity, 24bit */
996 WM_DAC_CTRL1, 0x0090, /* DAC L/R */
997 WM_OUT_MUX, 0x0001, /* OUT DAC */
998 WM_HP_ATTEN_L, 0x0179, /* HP 0dB */
999 WM_HP_ATTEN_R, 0x0179, /* HP 0dB */
1000 WM_DAC_ATTEN_L, 0x0000, /* DAC 0dB */
1001 WM_DAC_ATTEN_L, 0x0100, /* DAC 0dB */
1002 WM_DAC_ATTEN_R, 0x0000, /* DAC 0dB */
1003 WM_DAC_ATTEN_R, 0x0100, /* DAC 0dB */
1004 WM_PHASE_SWAP, 0x0000, /* phase normal */
1005#if 0
1006 WM_DAC_MASTER, 0x0100, /* DAC master muted */
1007#endif
1008 WM_DAC_CTRL2, 0x0000, /* no deemphasis, no ZFLG */
1009 WM_ADC_ATTEN_L, 0x0000, /* ADC muted */
1010 WM_ADC_ATTEN_R, 0x0000, /* ADC muted */
1011#if 1
1012 WM_ALC_CTRL1, 0x007b, /* */
1013 WM_ALC_CTRL2, 0x0000, /* */
1014 WM_ALC_CTRL3, 0x0000, /* */
1015 WM_NOISE_GATE, 0x0000, /* */
1016#endif
1017 WM_DAC_MUTE, 0x0000, /* DAC unmute */
1018 WM_ADC_MUX, 0x0003, /* ADC unmute, both CD/Line On */
1019 };
1020 static unsigned short wm8766_inits[] = {
1021 WM8766_RESET, 0x0000,
1022 WM8766_DAC_CTRL, 0x0120,
1023 WM8766_INT_CTRL, 0x0022, /* I2S Normal Mode, 24 bit */
1024 WM8766_DAC_CTRL2, 0x0001,
1025 WM8766_DAC_CTRL3, 0x0080,
1026 WM8766_LDA1, 0x0100,
1027 WM8766_LDA2, 0x0100,
1028 WM8766_LDA3, 0x0100,
1029 WM8766_RDA1, 0x0100,
1030 WM8766_RDA2, 0x0100,
1031 WM8766_RDA3, 0x0100,
1032 WM8766_MUTE1, 0x0000,
1033 WM8766_MUTE2, 0x0000,
1034 };
1035
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001036 struct prodigy_hifi_spec *spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001037 unsigned int i;
1038
1039 ice->vt1720 = 0;
1040 ice->vt1724 = 1;
1041
1042 ice->num_total_dacs = 8;
1043 ice->num_total_adcs = 1;
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001044
1045 /* HACK - use this as the SPDIF source.
1046 * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten
1047 */
1048 ice->gpio.saved[0] = 0;
1049 /* to remeber the register values */
1050
1051 ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
1052 if (! ice->akm)
1053 return -ENOMEM;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001054 ice->akm_codecs = 1;
1055
1056 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1057 if (!spec)
1058 return -ENOMEM;
1059 ice->spec = spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001060
1061 /* initialize WM8776 codec */
1062 for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2)
1063 wm_put(ice, wm_inits[i], wm_inits[i+1]);
1064 schedule_timeout_uninterruptible(1);
1065 for (i = 0; i < ARRAY_SIZE(wm_inits2); i += 2)
1066 wm_put(ice, wm_inits2[i], wm_inits2[i+1]);
1067
1068 /* initialize WM8766 codec */
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001069 for (i = 0; i < ARRAY_SIZE(wm8766_inits); i += 2)
1070 wm8766_spi_write(ice, wm8766_inits[i], wm8766_inits[i+1]);
1071
1072
1073 return 0;
1074}
1075
1076
1077/*
1078 * initialize the chip
1079 */
Igor Chernyshevb40e9532009-06-25 09:31:07 +02001080static void ak4396_init(struct snd_ice1712 *ice)
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001081{
1082 static unsigned short ak4396_inits[] = {
1083 AK4396_CTRL1, 0x87, /* I2S Normal Mode, 24 bit */
1084 AK4396_CTRL2, 0x02,
1085 AK4396_CTRL3, 0x00,
1086 AK4396_LCH_ATT, 0x00,
1087 AK4396_RCH_ATT, 0x00,
1088 };
1089
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001090 unsigned int i;
1091
Igor Chernyshevb40e9532009-06-25 09:31:07 +02001092 /* initialize ak4396 codec */
1093 /* reset codec */
1094 ak4396_write(ice, AK4396_CTRL1, 0x86);
1095 msleep(100);
1096 ak4396_write(ice, AK4396_CTRL1, 0x87);
1097
1098 for (i = 0; i < ARRAY_SIZE(ak4396_inits); i += 2)
1099 ak4396_write(ice, ak4396_inits[i], ak4396_inits[i+1]);
1100}
1101
1102#ifdef CONFIG_PM
1103static int __devinit prodigy_hd2_resume(struct snd_ice1712 *ice)
1104{
1105 /* initialize ak4396 codec and restore previous mixer volumes */
1106 struct prodigy_hifi_spec *spec = ice->spec;
1107 int i;
1108 mutex_lock(&ice->gpio_mutex);
1109 ak4396_init(ice);
1110 for (i = 0; i < 2; i++)
1111 ak4396_write(ice, AK4396_LCH_ATT + i, spec->vol[i] & 0xff);
1112 mutex_unlock(&ice->gpio_mutex);
1113 return 0;
1114}
1115#endif
1116
1117static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice)
1118{
1119 struct prodigy_hifi_spec *spec;
1120
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001121 ice->vt1720 = 0;
1122 ice->vt1724 = 1;
1123
1124 ice->num_total_dacs = 1;
1125 ice->num_total_adcs = 1;
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001126
1127 /* HACK - use this as the SPDIF source.
1128 * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten
1129 */
1130 ice->gpio.saved[0] = 0;
1131 /* to remeber the register values */
1132
1133 ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
1134 if (! ice->akm)
1135 return -ENOMEM;
1136 ice->akm_codecs = 1;
1137
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001138 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1139 if (!spec)
1140 return -ENOMEM;
1141 ice->spec = spec;
1142
Igor Chernyshevb40e9532009-06-25 09:31:07 +02001143#ifdef CONFIG_PM
1144 ice->pm_resume = &prodigy_hd2_resume;
1145 ice->pm_suspend_enabled = 1;
1146#endif
1147
1148 ak4396_init(ice);
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001149
1150 return 0;
1151}
1152
1153
1154static unsigned char prodigy71hifi_eeprom[] __devinitdata = {
1155 0x4b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
1156 0x80, /* ACLINK: I2S */
1157 0xfc, /* I2S: vol, 96k, 24bit, 192k */
1158 0xc3, /* SPDIF: out-en, out-int, spdif-in */
1159 0xff, /* GPIO_DIR */
1160 0xff, /* GPIO_DIR1 */
1161 0x5f, /* GPIO_DIR2 */
1162 0x00, /* GPIO_MASK */
1163 0x00, /* GPIO_MASK1 */
1164 0x00, /* GPIO_MASK2 */
1165 0x00, /* GPIO_STATE */
1166 0x00, /* GPIO_STATE1 */
1167 0x00, /* GPIO_STATE2 */
1168};
1169
1170static unsigned char prodigyhd2_eeprom[] __devinitdata = {
1171 0x4b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
1172 0x80, /* ACLINK: I2S */
1173 0xfc, /* I2S: vol, 96k, 24bit, 192k */
1174 0xc3, /* SPDIF: out-en, out-int, spdif-in */
1175 0xff, /* GPIO_DIR */
1176 0xff, /* GPIO_DIR1 */
1177 0x5f, /* GPIO_DIR2 */
1178 0x00, /* GPIO_MASK */
1179 0x00, /* GPIO_MASK1 */
1180 0x00, /* GPIO_MASK2 */
1181 0x00, /* GPIO_STATE */
1182 0x00, /* GPIO_STATE1 */
1183 0x00, /* GPIO_STATE2 */
1184};
1185
1186static unsigned char fortissimo4_eeprom[] __devinitdata = {
1187 0x43, /* SYSCONF: clock 512, ADC, 4DACs */
1188 0x80, /* ACLINK: I2S */
1189 0xfc, /* I2S: vol, 96k, 24bit, 192k */
1190 0xc1, /* SPDIF: out-en, out-int */
1191 0xff, /* GPIO_DIR */
1192 0xff, /* GPIO_DIR1 */
1193 0x5f, /* GPIO_DIR2 */
1194 0x00, /* GPIO_MASK */
1195 0x00, /* GPIO_MASK1 */
1196 0x00, /* GPIO_MASK2 */
1197 0x00, /* GPIO_STATE */
1198 0x00, /* GPIO_STATE1 */
1199 0x00, /* GPIO_STATE2 */
1200};
1201
1202/* entry point */
1203struct snd_ice1712_card_info snd_vt1724_prodigy_hifi_cards[] __devinitdata = {
1204 {
1205 .subvendor = VT1724_SUBDEVICE_PRODIGY_HIFI,
1206 .name = "Audiotrak Prodigy 7.1 HiFi",
1207 .model = "prodigy71hifi",
1208 .chip_init = prodigy_hifi_init,
1209 .build_controls = prodigy_hifi_add_controls,
1210 .eeprom_size = sizeof(prodigy71hifi_eeprom),
1211 .eeprom_data = prodigy71hifi_eeprom,
1212 .driver = "Prodigy71HIFI",
1213 },
1214 {
1215 .subvendor = VT1724_SUBDEVICE_PRODIGY_HD2,
1216 .name = "Audiotrak Prodigy HD2",
1217 .model = "prodigyhd2",
1218 .chip_init = prodigy_hd2_init,
1219 .build_controls = prodigy_hd2_add_controls,
1220 .eeprom_size = sizeof(prodigyhd2_eeprom),
1221 .eeprom_data = prodigyhd2_eeprom,
1222 .driver = "Prodigy71HD2",
1223 },
1224 {
1225 .subvendor = VT1724_SUBDEVICE_FORTISSIMO4,
1226 .name = "Hercules Fortissimo IV",
1227 .model = "fortissimo4",
1228 .chip_init = prodigy_hifi_init,
1229 .build_controls = prodigy_hifi_add_controls,
1230 .eeprom_size = sizeof(fortissimo4_eeprom),
1231 .eeprom_data = fortissimo4_eeprom,
1232 .driver = "Fortissimo4",
1233 },
1234 { } /* terminator */
1235};
1236