blob: 7bf093c51ce5a5569f6cec1a1f9e53a88763236f [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);
Matteo Frigo3737e2b2012-09-12 10:12:06 -0400300static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100301
302static struct snd_kcontrol_new prodigy_hd2_controls[] __devinitdata = {
303 {
304 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
305 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
306 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
307 .name = "Front Playback Volume",
308 .info = ak4396_dac_vol_info,
309 .get = ak4396_dac_vol_get,
310 .put = ak4396_dac_vol_put,
Matteo Frigo3737e2b2012-09-12 10:12:06 -0400311 .tlv = { .p = ak4396_db_scale },
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100312 },
313};
314
315
316/* --------------- */
317
318/*
319 * Logarithmic volume values for WM87*6
320 * Computed as 20 * Log10(255 / x)
321 */
322static const unsigned char wm_vol[256] = {
323 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23,
324 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17,
325 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13,
326 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11,
327 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8,
328 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,
329 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,
330 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,
331 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,
332 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,
333 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,
334 0, 0
335};
336
337#define WM_VOL_MAX (sizeof(wm_vol) - 1)
338#define WM_VOL_MUTE 0x8000
339
340
341#define DAC_0dB 0xff
342#define DAC_RES 128
343#define DAC_MIN (DAC_0dB - DAC_RES)
344
345
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100346static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index,
347 unsigned short vol, unsigned short master)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100348{
349 unsigned char nvol;
350
351 if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
352 nvol = 0;
353 else {
354 nvol = (((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 128)
355 & WM_VOL_MAX;
356 nvol = (nvol ? (nvol + DAC_MIN) : 0) & 0xff;
357 }
358
359 wm_put(ice, index, nvol);
360 wm_put_nocache(ice, index, 0x100 | nvol);
361}
362
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100363static void wm8766_set_vol(struct snd_ice1712 *ice, unsigned int index,
364 unsigned short vol, unsigned short master)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100365{
366 unsigned char nvol;
367
368 if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
369 nvol = 0;
370 else {
371 nvol = (((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 128)
372 & WM_VOL_MAX;
373 nvol = (nvol ? (nvol + DAC_MIN) : 0) & 0xff;
374 }
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100375
376 wm8766_spi_write(ice, index, (0x0100 | nvol));
377}
378
379
380/*
381 * DAC volume attenuation mixer control (-64dB to 0dB)
382 */
383
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100384static int wm_dac_vol_info(struct snd_kcontrol *kcontrol,
385 struct snd_ctl_elem_info *uinfo)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100386{
387 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
388 uinfo->count = 2;
389 uinfo->value.integer.min = 0; /* mute */
390 uinfo->value.integer.max = DAC_RES; /* 0dB, 0.5dB step */
391 return 0;
392}
393
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100394static int wm_dac_vol_get(struct snd_kcontrol *kcontrol,
395 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100396{
397 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100398 struct prodigy_hifi_spec *spec = ice->spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100399 int i;
400
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100401 for (i = 0; i < 2; i++)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100402 ucontrol->value.integer.value[i] =
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100403 spec->vol[2 + i] & ~WM_VOL_MUTE;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100404 return 0;
405}
406
407static int wm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
408{
409 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100410 struct prodigy_hifi_spec *spec = ice->spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100411 int i, idx, change = 0;
412
413 mutex_lock(&ice->gpio_mutex);
414 for (i = 0; i < 2; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100415 if (ucontrol->value.integer.value[i] != spec->vol[2 + i]) {
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100416 idx = WM_DAC_ATTEN_L + i;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100417 spec->vol[2 + i] &= WM_VOL_MUTE;
418 spec->vol[2 + i] |= ucontrol->value.integer.value[i];
419 wm_set_vol(ice, idx, spec->vol[2 + i], spec->master[i]);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100420 change = 1;
421 }
422 }
423 mutex_unlock(&ice->gpio_mutex);
424 return change;
425}
426
427
428/*
429 * WM8766 DAC volume attenuation mixer control
430 */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100431static int wm8766_vol_info(struct snd_kcontrol *kcontrol,
432 struct snd_ctl_elem_info *uinfo)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100433{
434 int voices = kcontrol->private_value >> 8;
435 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
436 uinfo->count = voices;
437 uinfo->value.integer.min = 0; /* mute */
438 uinfo->value.integer.max = DAC_RES; /* 0dB */
439 return 0;
440}
441
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100442static int wm8766_vol_get(struct snd_kcontrol *kcontrol,
443 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100444{
445 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100446 struct prodigy_hifi_spec *spec = ice->spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100447 int i, ofs, voices;
448
449 voices = kcontrol->private_value >> 8;
450 ofs = kcontrol->private_value & 0xff;
451 for (i = 0; i < voices; i++)
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100452 ucontrol->value.integer.value[i] = spec->vol[ofs + i];
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100453 return 0;
454}
455
456static int wm8766_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
457{
458 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100459 struct prodigy_hifi_spec *spec = ice->spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100460 int i, idx, ofs, voices;
461 int change = 0;
462
463 voices = kcontrol->private_value >> 8;
464 ofs = kcontrol->private_value & 0xff;
465 mutex_lock(&ice->gpio_mutex);
466 for (i = 0; i < voices; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100467 if (ucontrol->value.integer.value[i] != spec->vol[ofs + i]) {
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100468 idx = WM8766_LDA1 + ofs + i;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100469 spec->vol[ofs + i] &= WM_VOL_MUTE;
470 spec->vol[ofs + i] |= ucontrol->value.integer.value[i];
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100471 wm8766_set_vol(ice, idx,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100472 spec->vol[ofs + i], spec->master[i]);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100473 change = 1;
474 }
475 }
476 mutex_unlock(&ice->gpio_mutex);
477 return change;
478}
479
480/*
481 * Master volume attenuation mixer control / applied to WM8776+WM8766
482 */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100483static int wm_master_vol_info(struct snd_kcontrol *kcontrol,
484 struct snd_ctl_elem_info *uinfo)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100485{
486 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
487 uinfo->count = 2;
488 uinfo->value.integer.min = 0;
489 uinfo->value.integer.max = DAC_RES;
490 return 0;
491}
492
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100493static int wm_master_vol_get(struct snd_kcontrol *kcontrol,
494 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100495{
496 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100497 struct prodigy_hifi_spec *spec = ice->spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100498 int i;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100499 for (i = 0; i < 2; i++)
500 ucontrol->value.integer.value[i] = spec->master[i];
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100501 return 0;
502}
503
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100504static int wm_master_vol_put(struct snd_kcontrol *kcontrol,
505 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100506{
507 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100508 struct prodigy_hifi_spec *spec = ice->spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100509 int ch, change = 0;
510
511 mutex_lock(&ice->gpio_mutex);
512 for (ch = 0; ch < 2; ch++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100513 if (ucontrol->value.integer.value[ch] != spec->master[ch]) {
514 spec->master[ch] = ucontrol->value.integer.value[ch];
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100515
516 /* Apply to front DAC */
517 wm_set_vol(ice, WM_DAC_ATTEN_L + ch,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100518 spec->vol[2 + ch], spec->master[ch]);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100519
520 wm8766_set_vol(ice, WM8766_LDA1 + ch,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100521 spec->vol[0 + ch], spec->master[ch]);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100522
523 wm8766_set_vol(ice, WM8766_LDA2 + ch,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100524 spec->vol[4 + ch], spec->master[ch]);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100525
526 wm8766_set_vol(ice, WM8766_LDA3 + ch,
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100527 spec->vol[6 + ch], spec->master[ch]);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100528 change = 1;
529 }
530 }
531 mutex_unlock(&ice->gpio_mutex);
532 return change;
533}
534
535
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100536/* KONSTI */
537
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100538static int wm_adc_mux_enum_info(struct snd_kcontrol *kcontrol,
539 struct snd_ctl_elem_info *uinfo)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100540{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100541 static char* texts[32] = {
542 "NULL", WM_AIN1, WM_AIN2, WM_AIN1 "+" WM_AIN2,
543 WM_AIN3, WM_AIN1 "+" WM_AIN3, WM_AIN2 "+" WM_AIN3,
544 WM_AIN1 "+" WM_AIN2 "+" WM_AIN3,
545 WM_AIN4, WM_AIN1 "+" WM_AIN4, WM_AIN2 "+" WM_AIN4,
546 WM_AIN1 "+" WM_AIN2 "+" WM_AIN4,
547 WM_AIN3 "+" WM_AIN4, WM_AIN1 "+" WM_AIN3 "+" WM_AIN4,
548 WM_AIN2 "+" WM_AIN3 "+" WM_AIN4,
549 WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4,
550 WM_AIN5, WM_AIN1 "+" WM_AIN5, WM_AIN2 "+" WM_AIN5,
551 WM_AIN1 "+" WM_AIN2 "+" WM_AIN5,
552 WM_AIN3 "+" WM_AIN5, WM_AIN1 "+" WM_AIN3 "+" WM_AIN5,
553 WM_AIN2 "+" WM_AIN3 "+" WM_AIN5,
554 WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN5,
555 WM_AIN4 "+" WM_AIN5, WM_AIN1 "+" WM_AIN4 "+" WM_AIN5,
556 WM_AIN2 "+" WM_AIN4 "+" WM_AIN5,
557 WM_AIN1 "+" WM_AIN2 "+" WM_AIN4 "+" WM_AIN5,
558 WM_AIN3 "+" WM_AIN4 "+" WM_AIN5,
559 WM_AIN1 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5,
560 WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5,
561 WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5
562 };
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100563
564 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
565 uinfo->count = 1;
566 uinfo->value.enumerated.items = 32;
567 if (uinfo->value.enumerated.item > 31)
568 uinfo->value.enumerated.item = 31;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100569 strcpy(uinfo->value.enumerated.name,
570 texts[uinfo->value.enumerated.item]);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100571 return 0;
572}
573
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100574static int wm_adc_mux_enum_get(struct snd_kcontrol *kcontrol,
575 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100576{
577 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
578
579 mutex_lock(&ice->gpio_mutex);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100580 ucontrol->value.integer.value[0] = wm_get(ice, WM_ADC_MUX) & 0x1f;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100581 mutex_unlock(&ice->gpio_mutex);
582 return 0;
583}
584
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100585static int wm_adc_mux_enum_put(struct snd_kcontrol *kcontrol,
586 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100587{
588 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
589 unsigned short oval, nval;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100590 int change = 0;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100591
592 mutex_lock(&ice->gpio_mutex);
593 oval = wm_get(ice, WM_ADC_MUX);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100594 nval = (oval & 0xe0) | ucontrol->value.integer.value[0];
595 if (nval != oval) {
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100596 wm_put(ice, WM_ADC_MUX, nval);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100597 change = 1;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100598 }
599 mutex_unlock(&ice->gpio_mutex);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100600 return change;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100601}
602
603/* KONSTI */
604
605/*
606 * ADC gain mixer control (-64dB to 0dB)
607 */
608
609#define ADC_0dB 0xcf
610#define ADC_RES 128
611#define ADC_MIN (ADC_0dB - ADC_RES)
612
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100613static int wm_adc_vol_info(struct snd_kcontrol *kcontrol,
614 struct snd_ctl_elem_info *uinfo)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100615{
616 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
617 uinfo->count = 2;
618 uinfo->value.integer.min = 0; /* mute (-64dB) */
619 uinfo->value.integer.max = ADC_RES; /* 0dB, 0.5dB step */
620 return 0;
621}
622
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100623static int wm_adc_vol_get(struct snd_kcontrol *kcontrol,
624 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100625{
626 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
627 unsigned short val;
628 int i;
629
630 mutex_lock(&ice->gpio_mutex);
631 for (i = 0; i < 2; i++) {
632 val = wm_get(ice, WM_ADC_ATTEN_L + i) & 0xff;
633 val = val > ADC_MIN ? (val - ADC_MIN) : 0;
634 ucontrol->value.integer.value[i] = val;
635 }
636 mutex_unlock(&ice->gpio_mutex);
637 return 0;
638}
639
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100640static int wm_adc_vol_put(struct snd_kcontrol *kcontrol,
641 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100642{
643 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
644 unsigned short ovol, nvol;
645 int i, idx, change = 0;
646
647 mutex_lock(&ice->gpio_mutex);
648 for (i = 0; i < 2; i++) {
649 nvol = ucontrol->value.integer.value[i];
650 nvol = nvol ? (nvol + ADC_MIN) : 0;
651 idx = WM_ADC_ATTEN_L + i;
652 ovol = wm_get(ice, idx) & 0xff;
653 if (ovol != nvol) {
654 wm_put(ice, idx, nvol);
655 change = 1;
656 }
657 }
658 mutex_unlock(&ice->gpio_mutex);
659 return change;
660}
661
662/*
663 * ADC input mux mixer control
664 */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100665#define wm_adc_mux_info snd_ctl_boolean_mono_info
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100666
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100667static int wm_adc_mux_get(struct snd_kcontrol *kcontrol,
668 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100669{
670 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
671 int bit = kcontrol->private_value;
672
673 mutex_lock(&ice->gpio_mutex);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100674 ucontrol->value.integer.value[0] =
675 (wm_get(ice, WM_ADC_MUX) & (1 << bit)) ? 1 : 0;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100676 mutex_unlock(&ice->gpio_mutex);
677 return 0;
678}
679
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100680static int wm_adc_mux_put(struct snd_kcontrol *kcontrol,
681 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100682{
683 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
684 int bit = kcontrol->private_value;
685 unsigned short oval, nval;
686 int change;
687
688 mutex_lock(&ice->gpio_mutex);
689 nval = oval = wm_get(ice, WM_ADC_MUX);
690 if (ucontrol->value.integer.value[0])
691 nval |= (1 << bit);
692 else
693 nval &= ~(1 << bit);
694 change = nval != oval;
695 if (change) {
696 wm_put(ice, WM_ADC_MUX, nval);
697 }
698 mutex_unlock(&ice->gpio_mutex);
699 return 0;
700}
701
702/*
703 * Analog bypass (In -> Out)
704 */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100705#define wm_bypass_info snd_ctl_boolean_mono_info
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100706
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100707static int wm_bypass_get(struct snd_kcontrol *kcontrol,
708 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100709{
710 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
711
712 mutex_lock(&ice->gpio_mutex);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100713 ucontrol->value.integer.value[0] =
714 (wm_get(ice, WM_OUT_MUX) & 0x04) ? 1 : 0;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100715 mutex_unlock(&ice->gpio_mutex);
716 return 0;
717}
718
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100719static int wm_bypass_put(struct snd_kcontrol *kcontrol,
720 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100721{
722 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
723 unsigned short val, oval;
724 int change = 0;
725
726 mutex_lock(&ice->gpio_mutex);
727 val = oval = wm_get(ice, WM_OUT_MUX);
728 if (ucontrol->value.integer.value[0])
729 val |= 0x04;
730 else
731 val &= ~0x04;
732 if (val != oval) {
733 wm_put(ice, WM_OUT_MUX, val);
734 change = 1;
735 }
736 mutex_unlock(&ice->gpio_mutex);
737 return change;
738}
739
740/*
741 * Left/Right swap
742 */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100743#define wm_chswap_info snd_ctl_boolean_mono_info
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100744
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100745static int wm_chswap_get(struct snd_kcontrol *kcontrol,
746 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100747{
748 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
749
750 mutex_lock(&ice->gpio_mutex);
751 ucontrol->value.integer.value[0] =
752 (wm_get(ice, WM_DAC_CTRL1) & 0xf0) != 0x90;
753 mutex_unlock(&ice->gpio_mutex);
754 return 0;
755}
756
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100757static int wm_chswap_put(struct snd_kcontrol *kcontrol,
758 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100759{
760 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
761 unsigned short val, oval;
762 int change = 0;
763
764 mutex_lock(&ice->gpio_mutex);
765 oval = wm_get(ice, WM_DAC_CTRL1);
766 val = oval & 0x0f;
767 if (ucontrol->value.integer.value[0])
768 val |= 0x60;
769 else
770 val |= 0x90;
771 if (val != oval) {
772 wm_put(ice, WM_DAC_CTRL1, val);
773 wm_put_nocache(ice, WM_DAC_CTRL1, val);
774 change = 1;
775 }
776 mutex_unlock(&ice->gpio_mutex);
777 return change;
778}
779
780
781/*
782 * mixers
783 */
784
785static struct snd_kcontrol_new prodigy_hifi_controls[] __devinitdata = {
786 {
787 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
788 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
789 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
790 .name = "Master Playback Volume",
791 .info = wm_master_vol_info,
792 .get = wm_master_vol_get,
793 .put = wm_master_vol_put,
794 .tlv = { .p = db_scale_wm_dac }
795 },
796 {
797 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
798 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
799 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
800 .name = "Front Playback Volume",
801 .info = wm_dac_vol_info,
802 .get = wm_dac_vol_get,
803 .put = wm_dac_vol_put,
804 .tlv = { .p = db_scale_wm_dac },
805 },
806 {
807 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
808 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
809 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
810 .name = "Rear Playback Volume",
811 .info = wm8766_vol_info,
812 .get = wm8766_vol_get,
813 .put = wm8766_vol_put,
814 .private_value = (2 << 8) | 0,
815 .tlv = { .p = db_scale_wm_dac },
816 },
817 {
818 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
819 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
820 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
821 .name = "Center Playback Volume",
822 .info = wm8766_vol_info,
823 .get = wm8766_vol_get,
824 .put = wm8766_vol_put,
825 .private_value = (1 << 8) | 4,
826 .tlv = { .p = db_scale_wm_dac }
827 },
828 {
829 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
830 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
831 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
832 .name = "LFE Playback Volume",
833 .info = wm8766_vol_info,
834 .get = wm8766_vol_get,
835 .put = wm8766_vol_put,
836 .private_value = (1 << 8) | 5,
837 .tlv = { .p = db_scale_wm_dac }
838 },
839 {
840 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
841 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
842 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
843 .name = "Side Playback Volume",
844 .info = wm8766_vol_info,
845 .get = wm8766_vol_get,
846 .put = wm8766_vol_put,
847 .private_value = (2 << 8) | 6,
848 .tlv = { .p = db_scale_wm_dac },
849 },
850 {
851 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
852 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
853 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
854 .name = "Capture Volume",
855 .info = wm_adc_vol_info,
856 .get = wm_adc_vol_get,
857 .put = wm_adc_vol_put,
858 .tlv = { .p = db_scale_wm_dac },
859 },
860 {
861 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
862 .name = "CD Capture Switch",
863 .info = wm_adc_mux_info,
864 .get = wm_adc_mux_get,
865 .put = wm_adc_mux_put,
866 .private_value = 0,
867 },
868 {
869 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
870 .name = "Line Capture Switch",
871 .info = wm_adc_mux_info,
872 .get = wm_adc_mux_get,
873 .put = wm_adc_mux_put,
874 .private_value = 1,
875 },
876 {
877 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
878 .name = "Analog Bypass Switch",
879 .info = wm_bypass_info,
880 .get = wm_bypass_get,
881 .put = wm_bypass_put,
882 },
883 {
884 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
885 .name = "Swap Output Channels",
886 .info = wm_chswap_info,
887 .get = wm_chswap_get,
888 .put = wm_chswap_put,
889 },
890 {
891 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
892 .name = "Analog Capture Source",
893 .info = wm_adc_mux_enum_info,
894 .get = wm_adc_mux_enum_get,
895 .put = wm_adc_mux_enum_put,
896 },
897};
898
899/*
900 * WM codec registers
901 */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100902static void wm_proc_regs_write(struct snd_info_entry *entry,
903 struct snd_info_buffer *buffer)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100904{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100905 struct snd_ice1712 *ice = entry->private_data;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100906 char line[64];
907 unsigned int reg, val;
908 mutex_lock(&ice->gpio_mutex);
909 while (!snd_info_get_line(buffer, line, sizeof(line))) {
910 if (sscanf(line, "%x %x", &reg, &val) != 2)
911 continue;
912 if (reg <= 0x17 && val <= 0xffff)
913 wm_put(ice, reg, val);
914 }
915 mutex_unlock(&ice->gpio_mutex);
916}
917
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100918static void wm_proc_regs_read(struct snd_info_entry *entry,
919 struct snd_info_buffer *buffer)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100920{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100921 struct snd_ice1712 *ice = entry->private_data;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100922 int reg, val;
923
924 mutex_lock(&ice->gpio_mutex);
925 for (reg = 0; reg <= 0x17; reg++) {
926 val = wm_get(ice, reg);
927 snd_iprintf(buffer, "%02x = %04x\n", reg, val);
928 }
929 mutex_unlock(&ice->gpio_mutex);
930}
931
932static void wm_proc_init(struct snd_ice1712 *ice)
933{
934 struct snd_info_entry *entry;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100935 if (!snd_card_proc_new(ice->card, "wm_codec", &entry)) {
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100936 snd_info_set_text_ops(entry, ice, wm_proc_regs_read);
937 entry->mode |= S_IWUSR;
938 entry->c.text.write = wm_proc_regs_write;
939 }
940}
941
942static int __devinit prodigy_hifi_add_controls(struct snd_ice1712 *ice)
943{
944 unsigned int i;
945 int err;
946
947 for (i = 0; i < ARRAY_SIZE(prodigy_hifi_controls); i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100948 err = snd_ctl_add(ice->card,
949 snd_ctl_new1(&prodigy_hifi_controls[i], ice));
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100950 if (err < 0)
951 return err;
952 }
953
954 wm_proc_init(ice);
955
956 return 0;
957}
958
959static int __devinit prodigy_hd2_add_controls(struct snd_ice1712 *ice)
960{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100961 unsigned int i;
962 int err;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100963
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100964 for (i = 0; i < ARRAY_SIZE(prodigy_hd2_controls); i++) {
965 err = snd_ctl_add(ice->card,
966 snd_ctl_new1(&prodigy_hd2_controls[i], ice));
967 if (err < 0)
968 return err;
969 }
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100970
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100971 wm_proc_init(ice);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100972
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100973 return 0;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100974}
975
976
977/*
978 * initialize the chip
979 */
980static int __devinit prodigy_hifi_init(struct snd_ice1712 *ice)
981{
982 static unsigned short wm_inits[] = {
983 /* These come first to reduce init pop noise */
984 WM_ADC_MUX, 0x0003, /* ADC mute */
985 /* 0x00c0 replaced by 0x0003 */
986
987 WM_DAC_MUTE, 0x0001, /* DAC softmute */
988 WM_DAC_CTRL1, 0x0000, /* DAC mute */
989
990 WM_POWERDOWN, 0x0008, /* All power-up except HP */
991 WM_RESET, 0x0000, /* reset */
992 };
993 static unsigned short wm_inits2[] = {
994 WM_MASTER_CTRL, 0x0022, /* 256fs, slave mode */
995 WM_DAC_INT, 0x0022, /* I2S, normal polarity, 24bit */
996 WM_ADC_INT, 0x0022, /* I2S, normal polarity, 24bit */
997 WM_DAC_CTRL1, 0x0090, /* DAC L/R */
998 WM_OUT_MUX, 0x0001, /* OUT DAC */
999 WM_HP_ATTEN_L, 0x0179, /* HP 0dB */
1000 WM_HP_ATTEN_R, 0x0179, /* HP 0dB */
1001 WM_DAC_ATTEN_L, 0x0000, /* DAC 0dB */
1002 WM_DAC_ATTEN_L, 0x0100, /* DAC 0dB */
1003 WM_DAC_ATTEN_R, 0x0000, /* DAC 0dB */
1004 WM_DAC_ATTEN_R, 0x0100, /* DAC 0dB */
1005 WM_PHASE_SWAP, 0x0000, /* phase normal */
1006#if 0
1007 WM_DAC_MASTER, 0x0100, /* DAC master muted */
1008#endif
1009 WM_DAC_CTRL2, 0x0000, /* no deemphasis, no ZFLG */
1010 WM_ADC_ATTEN_L, 0x0000, /* ADC muted */
1011 WM_ADC_ATTEN_R, 0x0000, /* ADC muted */
1012#if 1
1013 WM_ALC_CTRL1, 0x007b, /* */
1014 WM_ALC_CTRL2, 0x0000, /* */
1015 WM_ALC_CTRL3, 0x0000, /* */
1016 WM_NOISE_GATE, 0x0000, /* */
1017#endif
1018 WM_DAC_MUTE, 0x0000, /* DAC unmute */
1019 WM_ADC_MUX, 0x0003, /* ADC unmute, both CD/Line On */
1020 };
1021 static unsigned short wm8766_inits[] = {
1022 WM8766_RESET, 0x0000,
1023 WM8766_DAC_CTRL, 0x0120,
1024 WM8766_INT_CTRL, 0x0022, /* I2S Normal Mode, 24 bit */
1025 WM8766_DAC_CTRL2, 0x0001,
1026 WM8766_DAC_CTRL3, 0x0080,
1027 WM8766_LDA1, 0x0100,
1028 WM8766_LDA2, 0x0100,
1029 WM8766_LDA3, 0x0100,
1030 WM8766_RDA1, 0x0100,
1031 WM8766_RDA2, 0x0100,
1032 WM8766_RDA3, 0x0100,
1033 WM8766_MUTE1, 0x0000,
1034 WM8766_MUTE2, 0x0000,
1035 };
1036
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001037 struct prodigy_hifi_spec *spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001038 unsigned int i;
1039
1040 ice->vt1720 = 0;
1041 ice->vt1724 = 1;
1042
1043 ice->num_total_dacs = 8;
1044 ice->num_total_adcs = 1;
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001045
1046 /* HACK - use this as the SPDIF source.
1047 * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten
1048 */
1049 ice->gpio.saved[0] = 0;
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001050 /* to remember the register values */
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001051
1052 ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
1053 if (! ice->akm)
1054 return -ENOMEM;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001055 ice->akm_codecs = 1;
1056
1057 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1058 if (!spec)
1059 return -ENOMEM;
1060 ice->spec = spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001061
1062 /* initialize WM8776 codec */
1063 for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2)
1064 wm_put(ice, wm_inits[i], wm_inits[i+1]);
1065 schedule_timeout_uninterruptible(1);
1066 for (i = 0; i < ARRAY_SIZE(wm_inits2); i += 2)
1067 wm_put(ice, wm_inits2[i], wm_inits2[i+1]);
1068
1069 /* initialize WM8766 codec */
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001070 for (i = 0; i < ARRAY_SIZE(wm8766_inits); i += 2)
1071 wm8766_spi_write(ice, wm8766_inits[i], wm8766_inits[i+1]);
1072
1073
1074 return 0;
1075}
1076
1077
1078/*
1079 * initialize the chip
1080 */
Igor Chernyshevb40e9532009-06-25 09:31:07 +02001081static void ak4396_init(struct snd_ice1712 *ice)
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001082{
1083 static unsigned short ak4396_inits[] = {
1084 AK4396_CTRL1, 0x87, /* I2S Normal Mode, 24 bit */
1085 AK4396_CTRL2, 0x02,
1086 AK4396_CTRL3, 0x00,
1087 AK4396_LCH_ATT, 0x00,
1088 AK4396_RCH_ATT, 0x00,
1089 };
1090
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001091 unsigned int i;
1092
Igor Chernyshevb40e9532009-06-25 09:31:07 +02001093 /* initialize ak4396 codec */
1094 /* reset codec */
1095 ak4396_write(ice, AK4396_CTRL1, 0x86);
1096 msleep(100);
1097 ak4396_write(ice, AK4396_CTRL1, 0x87);
1098
1099 for (i = 0; i < ARRAY_SIZE(ak4396_inits); i += 2)
1100 ak4396_write(ice, ak4396_inits[i], ak4396_inits[i+1]);
1101}
1102
Takashi Iwaic7561cd2012-08-14 18:12:04 +02001103#ifdef CONFIG_PM_SLEEP
Takashi Iwai5e08fe52009-11-14 14:37:19 +01001104static int prodigy_hd2_resume(struct snd_ice1712 *ice)
Igor Chernyshevb40e9532009-06-25 09:31:07 +02001105{
1106 /* initialize ak4396 codec and restore previous mixer volumes */
1107 struct prodigy_hifi_spec *spec = ice->spec;
1108 int i;
1109 mutex_lock(&ice->gpio_mutex);
1110 ak4396_init(ice);
1111 for (i = 0; i < 2; i++)
1112 ak4396_write(ice, AK4396_LCH_ATT + i, spec->vol[i] & 0xff);
1113 mutex_unlock(&ice->gpio_mutex);
1114 return 0;
1115}
1116#endif
1117
1118static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice)
1119{
1120 struct prodigy_hifi_spec *spec;
1121
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001122 ice->vt1720 = 0;
1123 ice->vt1724 = 1;
1124
1125 ice->num_total_dacs = 1;
1126 ice->num_total_adcs = 1;
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001127
1128 /* HACK - use this as the SPDIF source.
1129 * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten
1130 */
1131 ice->gpio.saved[0] = 0;
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001132 /* to remember the register values */
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001133
1134 ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
1135 if (! ice->akm)
1136 return -ENOMEM;
1137 ice->akm_codecs = 1;
1138
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001139 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1140 if (!spec)
1141 return -ENOMEM;
1142 ice->spec = spec;
1143
Takashi Iwaic7561cd2012-08-14 18:12:04 +02001144#ifdef CONFIG_PM_SLEEP
Igor Chernyshevb40e9532009-06-25 09:31:07 +02001145 ice->pm_resume = &prodigy_hd2_resume;
1146 ice->pm_suspend_enabled = 1;
1147#endif
1148
1149 ak4396_init(ice);
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001150
1151 return 0;
1152}
1153
1154
1155static unsigned char prodigy71hifi_eeprom[] __devinitdata = {
1156 0x4b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
1157 0x80, /* ACLINK: I2S */
1158 0xfc, /* I2S: vol, 96k, 24bit, 192k */
1159 0xc3, /* SPDIF: out-en, out-int, spdif-in */
1160 0xff, /* GPIO_DIR */
1161 0xff, /* GPIO_DIR1 */
1162 0x5f, /* GPIO_DIR2 */
1163 0x00, /* GPIO_MASK */
1164 0x00, /* GPIO_MASK1 */
1165 0x00, /* GPIO_MASK2 */
1166 0x00, /* GPIO_STATE */
1167 0x00, /* GPIO_STATE1 */
1168 0x00, /* GPIO_STATE2 */
1169};
1170
1171static unsigned char prodigyhd2_eeprom[] __devinitdata = {
1172 0x4b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
1173 0x80, /* ACLINK: I2S */
1174 0xfc, /* I2S: vol, 96k, 24bit, 192k */
1175 0xc3, /* SPDIF: out-en, out-int, spdif-in */
1176 0xff, /* GPIO_DIR */
1177 0xff, /* GPIO_DIR1 */
1178 0x5f, /* GPIO_DIR2 */
1179 0x00, /* GPIO_MASK */
1180 0x00, /* GPIO_MASK1 */
1181 0x00, /* GPIO_MASK2 */
1182 0x00, /* GPIO_STATE */
1183 0x00, /* GPIO_STATE1 */
1184 0x00, /* GPIO_STATE2 */
1185};
1186
1187static unsigned char fortissimo4_eeprom[] __devinitdata = {
1188 0x43, /* SYSCONF: clock 512, ADC, 4DACs */
1189 0x80, /* ACLINK: I2S */
1190 0xfc, /* I2S: vol, 96k, 24bit, 192k */
1191 0xc1, /* SPDIF: out-en, out-int */
1192 0xff, /* GPIO_DIR */
1193 0xff, /* GPIO_DIR1 */
1194 0x5f, /* GPIO_DIR2 */
1195 0x00, /* GPIO_MASK */
1196 0x00, /* GPIO_MASK1 */
1197 0x00, /* GPIO_MASK2 */
1198 0x00, /* GPIO_STATE */
1199 0x00, /* GPIO_STATE1 */
1200 0x00, /* GPIO_STATE2 */
1201};
1202
1203/* entry point */
1204struct snd_ice1712_card_info snd_vt1724_prodigy_hifi_cards[] __devinitdata = {
1205 {
1206 .subvendor = VT1724_SUBDEVICE_PRODIGY_HIFI,
1207 .name = "Audiotrak Prodigy 7.1 HiFi",
1208 .model = "prodigy71hifi",
1209 .chip_init = prodigy_hifi_init,
1210 .build_controls = prodigy_hifi_add_controls,
1211 .eeprom_size = sizeof(prodigy71hifi_eeprom),
1212 .eeprom_data = prodigy71hifi_eeprom,
1213 .driver = "Prodigy71HIFI",
1214 },
1215 {
1216 .subvendor = VT1724_SUBDEVICE_PRODIGY_HD2,
1217 .name = "Audiotrak Prodigy HD2",
1218 .model = "prodigyhd2",
1219 .chip_init = prodigy_hd2_init,
1220 .build_controls = prodigy_hd2_add_controls,
1221 .eeprom_size = sizeof(prodigyhd2_eeprom),
1222 .eeprom_data = prodigyhd2_eeprom,
1223 .driver = "Prodigy71HD2",
1224 },
1225 {
1226 .subvendor = VT1724_SUBDEVICE_FORTISSIMO4,
1227 .name = "Hercules Fortissimo IV",
1228 .model = "fortissimo4",
1229 .chip_init = prodigy_hifi_init,
1230 .build_controls = prodigy_hifi_add_controls,
1231 .eeprom_size = sizeof(fortissimo4_eeprom),
1232 .eeprom_data = fortissimo4_eeprom,
1233 .driver = "Fortissimo4",
1234 },
1235 { } /* terminator */
1236};
1237