blob: 2697402b5195799243e115fef1996c7293eb773d [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
Julian Scheel6b8d6e52008-01-16 19:50:00 +010028#include <linux/delay.h>
29#include <linux/interrupt.h>
30#include <linux/init.h>
31#include <linux/slab.h>
32#include <linux/mutex.h>
33
34#include <sound/core.h>
35#include <sound/info.h>
36#include <sound/tlv.h>
37
38#include "ice1712.h"
39#include "envy24ht.h"
40#include "prodigy_hifi.h"
41
Takashi Iwai7cda8ba2008-01-18 13:36:07 +010042struct prodigy_hifi_spec {
43 unsigned short master[2];
44 unsigned short vol[8];
45};
46
Julian Scheel6b8d6e52008-01-16 19:50:00 +010047/* I2C addresses */
48#define WM_DEV 0x34
49
50/* WM8776 registers */
51#define WM_HP_ATTEN_L 0x00 /* headphone left attenuation */
52#define WM_HP_ATTEN_R 0x01 /* headphone left attenuation */
53#define WM_HP_MASTER 0x02 /* headphone master (both channels),
54 override LLR */
55#define WM_DAC_ATTEN_L 0x03 /* digital left attenuation */
56#define WM_DAC_ATTEN_R 0x04
57#define WM_DAC_MASTER 0x05
58#define WM_PHASE_SWAP 0x06 /* DAC phase swap */
59#define WM_DAC_CTRL1 0x07
60#define WM_DAC_MUTE 0x08
61#define WM_DAC_CTRL2 0x09
62#define WM_DAC_INT 0x0a
63#define WM_ADC_INT 0x0b
64#define WM_MASTER_CTRL 0x0c
65#define WM_POWERDOWN 0x0d
66#define WM_ADC_ATTEN_L 0x0e
67#define WM_ADC_ATTEN_R 0x0f
68#define WM_ALC_CTRL1 0x10
69#define WM_ALC_CTRL2 0x11
70#define WM_ALC_CTRL3 0x12
71#define WM_NOISE_GATE 0x13
72#define WM_LIMITER 0x14
73#define WM_ADC_MUX 0x15
74#define WM_OUT_MUX 0x16
75#define WM_RESET 0x17
76
77/* Analog Recording Source :- Mic, LineIn, CD/Video, */
78
79/* implement capture source select control for WM8776 */
80
81#define WM_AIN1 "AIN1"
82#define WM_AIN2 "AIN2"
83#define WM_AIN3 "AIN3"
84#define WM_AIN4 "AIN4"
85#define WM_AIN5 "AIN5"
86
87/* GPIO pins of envy24ht connected to wm8766 */
88#define WM8766_SPI_CLK (1<<17) /* CLK, Pin97 on ICE1724 */
89#define WM8766_SPI_MD (1<<16) /* DATA VT1724 -> WM8766, Pin96 */
90#define WM8766_SPI_ML (1<<18) /* Latch, Pin98 */
91
92/* WM8766 registers */
93#define WM8766_DAC_CTRL 0x02 /* DAC Control */
94#define WM8766_INT_CTRL 0x03 /* Interface Control */
95#define WM8766_DAC_CTRL2 0x09
96#define WM8766_DAC_CTRL3 0x0a
97#define WM8766_RESET 0x1f
98#define WM8766_LDA1 0x00
99#define WM8766_LDA2 0x04
100#define WM8766_LDA3 0x06
101#define WM8766_RDA1 0x01
102#define WM8766_RDA2 0x05
103#define WM8766_RDA3 0x07
104#define WM8766_MUTE1 0x0C
105#define WM8766_MUTE2 0x0F
106
107
108/*
109 * Prodigy HD2
110 */
111#define AK4396_ADDR 0x00
112#define AK4396_CSN (1 << 8) /* CSN->GPIO8, pin 75 */
113#define AK4396_CCLK (1 << 9) /* CCLK->GPIO9, pin 76 */
114#define AK4396_CDTI (1 << 10) /* CDTI->GPIO10, pin 77 */
115
116/* ak4396 registers */
117#define AK4396_CTRL1 0x00
118#define AK4396_CTRL2 0x01
119#define AK4396_CTRL3 0x02
120#define AK4396_LCH_ATT 0x03
121#define AK4396_RCH_ATT 0x04
122
123
124/*
125 * get the current register value of WM codec
126 */
127static unsigned short wm_get(struct snd_ice1712 *ice, int reg)
128{
129 reg <<= 1;
130 return ((unsigned short)ice->akm[0].images[reg] << 8) |
131 ice->akm[0].images[reg + 1];
132}
133
134/*
135 * set the register value of WM codec and remember it
136 */
137static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
138{
139 unsigned short cval;
140 cval = (reg << 9) | val;
141 snd_vt1724_write_i2c(ice, WM_DEV, cval >> 8, cval & 0xff);
142}
143
144static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
145{
146 wm_put_nocache(ice, reg, val);
147 reg <<= 1;
148 ice->akm[0].images[reg] = val >> 8;
149 ice->akm[0].images[reg + 1] = val;
150}
151
152/*
153 * write data in the SPI mode
154 */
155
156static void set_gpio_bit(struct snd_ice1712 *ice, unsigned int bit, int val)
157{
158 unsigned int tmp = snd_ice1712_gpio_read(ice);
159 if (val)
160 tmp |= bit;
161 else
162 tmp &= ~bit;
163 snd_ice1712_gpio_write(ice, tmp);
164}
165
166/*
167 * SPI implementation for WM8766 codec - only writing supported, no readback
168 */
169
170static void wm8766_spi_send_word(struct snd_ice1712 *ice, unsigned int data)
171{
172 int i;
173 for (i = 0; i < 16; i++) {
174 set_gpio_bit(ice, WM8766_SPI_CLK, 0);
175 udelay(1);
176 set_gpio_bit(ice, WM8766_SPI_MD, data & 0x8000);
177 udelay(1);
178 set_gpio_bit(ice, WM8766_SPI_CLK, 1);
179 udelay(1);
180 data <<= 1;
181 }
182}
183
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100184static void wm8766_spi_write(struct snd_ice1712 *ice, unsigned int reg,
185 unsigned int data)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100186{
187 unsigned int block;
188
189 snd_ice1712_gpio_set_dir(ice, WM8766_SPI_MD|
190 WM8766_SPI_CLK|WM8766_SPI_ML);
191 snd_ice1712_gpio_set_mask(ice, ~(WM8766_SPI_MD|
192 WM8766_SPI_CLK|WM8766_SPI_ML));
193 /* latch must be low when writing */
194 set_gpio_bit(ice, WM8766_SPI_ML, 0);
195 block = (reg << 9) | (data & 0x1ff);
196 wm8766_spi_send_word(ice, block); /* REGISTER ADDRESS */
197 /* release latch */
198 set_gpio_bit(ice, WM8766_SPI_ML, 1);
199 udelay(1);
200 /* restore */
201 snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);
202 snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
203}
204
205
206/*
207 * serial interface for ak4396 - only writing supported, no readback
208 */
209
210static void ak4396_send_word(struct snd_ice1712 *ice, unsigned int data)
211{
212 int i;
213 for (i = 0; i < 16; i++) {
214 set_gpio_bit(ice, AK4396_CCLK, 0);
215 udelay(1);
216 set_gpio_bit(ice, AK4396_CDTI, data & 0x8000);
217 udelay(1);
218 set_gpio_bit(ice, AK4396_CCLK, 1);
219 udelay(1);
220 data <<= 1;
221 }
222}
223
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100224static void ak4396_write(struct snd_ice1712 *ice, unsigned int reg,
225 unsigned int data)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100226{
227 unsigned int block;
228
229 snd_ice1712_gpio_set_dir(ice, AK4396_CSN|AK4396_CCLK|AK4396_CDTI);
230 snd_ice1712_gpio_set_mask(ice, ~(AK4396_CSN|AK4396_CCLK|AK4396_CDTI));
231 /* latch must be low when writing */
232 set_gpio_bit(ice, AK4396_CSN, 0);
233 block = ((AK4396_ADDR & 0x03) << 14) | (1 << 13) |
234 ((reg & 0x1f) << 8) | (data & 0xff);
235 ak4396_send_word(ice, block); /* REGISTER ADDRESS */
236 /* release latch */
237 set_gpio_bit(ice, AK4396_CSN, 1);
238 udelay(1);
239 /* restore */
240 snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);
241 snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
242}
243
244
245/*
246 * ak4396 mixers
247 */
248
249
250
251/*
252 * DAC volume attenuation mixer control (-64dB to 0dB)
253 */
254
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100255static int ak4396_dac_vol_info(struct snd_kcontrol *kcontrol,
256 struct snd_ctl_elem_info *uinfo)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100257{
258 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
259 uinfo->count = 2;
260 uinfo->value.integer.min = 0; /* mute */
261 uinfo->value.integer.max = 0xFF; /* linear */
262 return 0;
263}
264
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100265static int ak4396_dac_vol_get(struct snd_kcontrol *kcontrol,
266 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100267{
268 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100269 struct prodigy_hifi_spec *spec = ice->spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100270 int i;
271
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100272 for (i = 0; i < 2; i++)
273 ucontrol->value.integer.value[i] = spec->vol[i];
274
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100275 return 0;
276}
277
278static int ak4396_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
279{
280 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100281 struct prodigy_hifi_spec *spec = ice->spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100282 int i;
283 int change = 0;
284
285 mutex_lock(&ice->gpio_mutex);
286 for (i = 0; i < 2; i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100287 if (ucontrol->value.integer.value[i] != spec->vol[i]) {
288 spec->vol[i] = ucontrol->value.integer.value[i];
289 ak4396_write(ice, AK4396_LCH_ATT + i,
290 spec->vol[i] & 0xff);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100291 change = 1;
292 }
293 }
294 mutex_unlock(&ice->gpio_mutex);
295 return change;
296}
297
298static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
Matteo Frigo3737e2b2012-09-12 10:12:06 -0400299static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100300
Bill Pembertone23e7a12012-12-06 12:35:10 -0500301static struct snd_kcontrol_new prodigy_hd2_controls[] = {
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100302 {
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,
Matteo Frigo3737e2b2012-09-12 10:12:06 -0400310 .tlv = { .p = ak4396_db_scale },
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100311 },
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 Iwai597da2e2014-10-20 18:18:50 +0200540 static const char * const texts[32] = {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100541 "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
Takashi Iwai597da2e2014-10-20 18:18:50 +0200563 return snd_ctl_enum_info(uinfo, 1, 32, texts);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100564}
565
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100566static int wm_adc_mux_enum_get(struct snd_kcontrol *kcontrol,
567 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100568{
569 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
570
571 mutex_lock(&ice->gpio_mutex);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100572 ucontrol->value.integer.value[0] = wm_get(ice, WM_ADC_MUX) & 0x1f;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100573 mutex_unlock(&ice->gpio_mutex);
574 return 0;
575}
576
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100577static int wm_adc_mux_enum_put(struct snd_kcontrol *kcontrol,
578 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100579{
580 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
581 unsigned short oval, nval;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100582 int change = 0;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100583
584 mutex_lock(&ice->gpio_mutex);
585 oval = wm_get(ice, WM_ADC_MUX);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100586 nval = (oval & 0xe0) | ucontrol->value.integer.value[0];
587 if (nval != oval) {
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100588 wm_put(ice, WM_ADC_MUX, nval);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100589 change = 1;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100590 }
591 mutex_unlock(&ice->gpio_mutex);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100592 return change;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100593}
594
595/* KONSTI */
596
597/*
598 * ADC gain mixer control (-64dB to 0dB)
599 */
600
601#define ADC_0dB 0xcf
602#define ADC_RES 128
603#define ADC_MIN (ADC_0dB - ADC_RES)
604
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100605static int wm_adc_vol_info(struct snd_kcontrol *kcontrol,
606 struct snd_ctl_elem_info *uinfo)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100607{
608 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
609 uinfo->count = 2;
610 uinfo->value.integer.min = 0; /* mute (-64dB) */
611 uinfo->value.integer.max = ADC_RES; /* 0dB, 0.5dB step */
612 return 0;
613}
614
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100615static int wm_adc_vol_get(struct snd_kcontrol *kcontrol,
616 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100617{
618 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
619 unsigned short val;
620 int i;
621
622 mutex_lock(&ice->gpio_mutex);
623 for (i = 0; i < 2; i++) {
624 val = wm_get(ice, WM_ADC_ATTEN_L + i) & 0xff;
625 val = val > ADC_MIN ? (val - ADC_MIN) : 0;
626 ucontrol->value.integer.value[i] = val;
627 }
628 mutex_unlock(&ice->gpio_mutex);
629 return 0;
630}
631
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100632static int wm_adc_vol_put(struct snd_kcontrol *kcontrol,
633 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100634{
635 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
636 unsigned short ovol, nvol;
637 int i, idx, change = 0;
638
639 mutex_lock(&ice->gpio_mutex);
640 for (i = 0; i < 2; i++) {
641 nvol = ucontrol->value.integer.value[i];
642 nvol = nvol ? (nvol + ADC_MIN) : 0;
643 idx = WM_ADC_ATTEN_L + i;
644 ovol = wm_get(ice, idx) & 0xff;
645 if (ovol != nvol) {
646 wm_put(ice, idx, nvol);
647 change = 1;
648 }
649 }
650 mutex_unlock(&ice->gpio_mutex);
651 return change;
652}
653
654/*
655 * ADC input mux mixer control
656 */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100657#define wm_adc_mux_info snd_ctl_boolean_mono_info
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100658
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100659static int wm_adc_mux_get(struct snd_kcontrol *kcontrol,
660 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100661{
662 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
663 int bit = kcontrol->private_value;
664
665 mutex_lock(&ice->gpio_mutex);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100666 ucontrol->value.integer.value[0] =
667 (wm_get(ice, WM_ADC_MUX) & (1 << bit)) ? 1 : 0;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100668 mutex_unlock(&ice->gpio_mutex);
669 return 0;
670}
671
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100672static int wm_adc_mux_put(struct snd_kcontrol *kcontrol,
673 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100674{
675 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
676 int bit = kcontrol->private_value;
677 unsigned short oval, nval;
678 int change;
679
680 mutex_lock(&ice->gpio_mutex);
681 nval = oval = wm_get(ice, WM_ADC_MUX);
682 if (ucontrol->value.integer.value[0])
683 nval |= (1 << bit);
684 else
685 nval &= ~(1 << bit);
686 change = nval != oval;
687 if (change) {
688 wm_put(ice, WM_ADC_MUX, nval);
689 }
690 mutex_unlock(&ice->gpio_mutex);
691 return 0;
692}
693
694/*
695 * Analog bypass (In -> Out)
696 */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100697#define wm_bypass_info snd_ctl_boolean_mono_info
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100698
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100699static int wm_bypass_get(struct snd_kcontrol *kcontrol,
700 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100701{
702 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
703
704 mutex_lock(&ice->gpio_mutex);
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100705 ucontrol->value.integer.value[0] =
706 (wm_get(ice, WM_OUT_MUX) & 0x04) ? 1 : 0;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100707 mutex_unlock(&ice->gpio_mutex);
708 return 0;
709}
710
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100711static int wm_bypass_put(struct snd_kcontrol *kcontrol,
712 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100713{
714 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
715 unsigned short val, oval;
716 int change = 0;
717
718 mutex_lock(&ice->gpio_mutex);
719 val = oval = wm_get(ice, WM_OUT_MUX);
720 if (ucontrol->value.integer.value[0])
721 val |= 0x04;
722 else
723 val &= ~0x04;
724 if (val != oval) {
725 wm_put(ice, WM_OUT_MUX, val);
726 change = 1;
727 }
728 mutex_unlock(&ice->gpio_mutex);
729 return change;
730}
731
732/*
733 * Left/Right swap
734 */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100735#define wm_chswap_info snd_ctl_boolean_mono_info
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100736
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100737static int wm_chswap_get(struct snd_kcontrol *kcontrol,
738 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100739{
740 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
741
742 mutex_lock(&ice->gpio_mutex);
743 ucontrol->value.integer.value[0] =
744 (wm_get(ice, WM_DAC_CTRL1) & 0xf0) != 0x90;
745 mutex_unlock(&ice->gpio_mutex);
746 return 0;
747}
748
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100749static int wm_chswap_put(struct snd_kcontrol *kcontrol,
750 struct snd_ctl_elem_value *ucontrol)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100751{
752 struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
753 unsigned short val, oval;
754 int change = 0;
755
756 mutex_lock(&ice->gpio_mutex);
757 oval = wm_get(ice, WM_DAC_CTRL1);
758 val = oval & 0x0f;
759 if (ucontrol->value.integer.value[0])
760 val |= 0x60;
761 else
762 val |= 0x90;
763 if (val != oval) {
764 wm_put(ice, WM_DAC_CTRL1, val);
765 wm_put_nocache(ice, WM_DAC_CTRL1, val);
766 change = 1;
767 }
768 mutex_unlock(&ice->gpio_mutex);
769 return change;
770}
771
772
773/*
774 * mixers
775 */
776
Bill Pembertone23e7a12012-12-06 12:35:10 -0500777static struct snd_kcontrol_new prodigy_hifi_controls[] = {
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100778 {
779 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
780 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
781 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
782 .name = "Master Playback Volume",
783 .info = wm_master_vol_info,
784 .get = wm_master_vol_get,
785 .put = wm_master_vol_put,
786 .tlv = { .p = db_scale_wm_dac }
787 },
788 {
789 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
790 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
791 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
792 .name = "Front Playback Volume",
793 .info = wm_dac_vol_info,
794 .get = wm_dac_vol_get,
795 .put = wm_dac_vol_put,
796 .tlv = { .p = db_scale_wm_dac },
797 },
798 {
799 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
800 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
801 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
802 .name = "Rear Playback Volume",
803 .info = wm8766_vol_info,
804 .get = wm8766_vol_get,
805 .put = wm8766_vol_put,
806 .private_value = (2 << 8) | 0,
807 .tlv = { .p = db_scale_wm_dac },
808 },
809 {
810 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
811 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
812 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
813 .name = "Center Playback Volume",
814 .info = wm8766_vol_info,
815 .get = wm8766_vol_get,
816 .put = wm8766_vol_put,
817 .private_value = (1 << 8) | 4,
818 .tlv = { .p = db_scale_wm_dac }
819 },
820 {
821 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
822 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
823 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
824 .name = "LFE Playback Volume",
825 .info = wm8766_vol_info,
826 .get = wm8766_vol_get,
827 .put = wm8766_vol_put,
828 .private_value = (1 << 8) | 5,
829 .tlv = { .p = db_scale_wm_dac }
830 },
831 {
832 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
833 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
834 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
835 .name = "Side Playback Volume",
836 .info = wm8766_vol_info,
837 .get = wm8766_vol_get,
838 .put = wm8766_vol_put,
839 .private_value = (2 << 8) | 6,
840 .tlv = { .p = db_scale_wm_dac },
841 },
842 {
843 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
844 .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
845 SNDRV_CTL_ELEM_ACCESS_TLV_READ),
846 .name = "Capture Volume",
847 .info = wm_adc_vol_info,
848 .get = wm_adc_vol_get,
849 .put = wm_adc_vol_put,
850 .tlv = { .p = db_scale_wm_dac },
851 },
852 {
853 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
854 .name = "CD Capture Switch",
855 .info = wm_adc_mux_info,
856 .get = wm_adc_mux_get,
857 .put = wm_adc_mux_put,
858 .private_value = 0,
859 },
860 {
861 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
862 .name = "Line Capture Switch",
863 .info = wm_adc_mux_info,
864 .get = wm_adc_mux_get,
865 .put = wm_adc_mux_put,
866 .private_value = 1,
867 },
868 {
869 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
870 .name = "Analog Bypass Switch",
871 .info = wm_bypass_info,
872 .get = wm_bypass_get,
873 .put = wm_bypass_put,
874 },
875 {
876 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
877 .name = "Swap Output Channels",
878 .info = wm_chswap_info,
879 .get = wm_chswap_get,
880 .put = wm_chswap_put,
881 },
882 {
883 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
884 .name = "Analog Capture Source",
885 .info = wm_adc_mux_enum_info,
886 .get = wm_adc_mux_enum_get,
887 .put = wm_adc_mux_enum_put,
888 },
889};
890
891/*
892 * WM codec registers
893 */
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100894static void wm_proc_regs_write(struct snd_info_entry *entry,
895 struct snd_info_buffer *buffer)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100896{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100897 struct snd_ice1712 *ice = entry->private_data;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100898 char line[64];
899 unsigned int reg, val;
900 mutex_lock(&ice->gpio_mutex);
901 while (!snd_info_get_line(buffer, line, sizeof(line))) {
902 if (sscanf(line, "%x %x", &reg, &val) != 2)
903 continue;
904 if (reg <= 0x17 && val <= 0xffff)
905 wm_put(ice, reg, val);
906 }
907 mutex_unlock(&ice->gpio_mutex);
908}
909
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100910static void wm_proc_regs_read(struct snd_info_entry *entry,
911 struct snd_info_buffer *buffer)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100912{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100913 struct snd_ice1712 *ice = entry->private_data;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100914 int reg, val;
915
916 mutex_lock(&ice->gpio_mutex);
917 for (reg = 0; reg <= 0x17; reg++) {
918 val = wm_get(ice, reg);
919 snd_iprintf(buffer, "%02x = %04x\n", reg, val);
920 }
921 mutex_unlock(&ice->gpio_mutex);
922}
923
924static void wm_proc_init(struct snd_ice1712 *ice)
925{
926 struct snd_info_entry *entry;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100927 if (!snd_card_proc_new(ice->card, "wm_codec", &entry)) {
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100928 snd_info_set_text_ops(entry, ice, wm_proc_regs_read);
929 entry->mode |= S_IWUSR;
930 entry->c.text.write = wm_proc_regs_write;
931 }
932}
933
Bill Pembertone23e7a12012-12-06 12:35:10 -0500934static int prodigy_hifi_add_controls(struct snd_ice1712 *ice)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100935{
936 unsigned int i;
937 int err;
938
939 for (i = 0; i < ARRAY_SIZE(prodigy_hifi_controls); i++) {
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100940 err = snd_ctl_add(ice->card,
941 snd_ctl_new1(&prodigy_hifi_controls[i], ice));
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100942 if (err < 0)
943 return err;
944 }
945
946 wm_proc_init(ice);
947
948 return 0;
949}
950
Bill Pembertone23e7a12012-12-06 12:35:10 -0500951static int prodigy_hd2_add_controls(struct snd_ice1712 *ice)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100952{
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100953 unsigned int i;
954 int err;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100955
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100956 for (i = 0; i < ARRAY_SIZE(prodigy_hd2_controls); i++) {
957 err = snd_ctl_add(ice->card,
958 snd_ctl_new1(&prodigy_hd2_controls[i], ice));
959 if (err < 0)
960 return err;
961 }
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100962
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100963 wm_proc_init(ice);
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100964
Takashi Iwai7cda8ba2008-01-18 13:36:07 +0100965 return 0;
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100966}
967
968
969/*
970 * initialize the chip
971 */
Bill Pembertone23e7a12012-12-06 12:35:10 -0500972static int prodigy_hifi_init(struct snd_ice1712 *ice)
Julian Scheel6b8d6e52008-01-16 19:50:00 +0100973{
974 static unsigned short wm_inits[] = {
975 /* These come first to reduce init pop noise */
976 WM_ADC_MUX, 0x0003, /* ADC mute */
977 /* 0x00c0 replaced by 0x0003 */
978
979 WM_DAC_MUTE, 0x0001, /* DAC softmute */
980 WM_DAC_CTRL1, 0x0000, /* DAC mute */
981
982 WM_POWERDOWN, 0x0008, /* All power-up except HP */
983 WM_RESET, 0x0000, /* reset */
984 };
985 static unsigned short wm_inits2[] = {
986 WM_MASTER_CTRL, 0x0022, /* 256fs, slave mode */
987 WM_DAC_INT, 0x0022, /* I2S, normal polarity, 24bit */
988 WM_ADC_INT, 0x0022, /* I2S, normal polarity, 24bit */
989 WM_DAC_CTRL1, 0x0090, /* DAC L/R */
990 WM_OUT_MUX, 0x0001, /* OUT DAC */
991 WM_HP_ATTEN_L, 0x0179, /* HP 0dB */
992 WM_HP_ATTEN_R, 0x0179, /* HP 0dB */
993 WM_DAC_ATTEN_L, 0x0000, /* DAC 0dB */
994 WM_DAC_ATTEN_L, 0x0100, /* DAC 0dB */
995 WM_DAC_ATTEN_R, 0x0000, /* DAC 0dB */
996 WM_DAC_ATTEN_R, 0x0100, /* DAC 0dB */
997 WM_PHASE_SWAP, 0x0000, /* phase normal */
998#if 0
999 WM_DAC_MASTER, 0x0100, /* DAC master muted */
1000#endif
1001 WM_DAC_CTRL2, 0x0000, /* no deemphasis, no ZFLG */
1002 WM_ADC_ATTEN_L, 0x0000, /* ADC muted */
1003 WM_ADC_ATTEN_R, 0x0000, /* ADC muted */
1004#if 1
1005 WM_ALC_CTRL1, 0x007b, /* */
1006 WM_ALC_CTRL2, 0x0000, /* */
1007 WM_ALC_CTRL3, 0x0000, /* */
1008 WM_NOISE_GATE, 0x0000, /* */
1009#endif
1010 WM_DAC_MUTE, 0x0000, /* DAC unmute */
1011 WM_ADC_MUX, 0x0003, /* ADC unmute, both CD/Line On */
1012 };
1013 static unsigned short wm8766_inits[] = {
1014 WM8766_RESET, 0x0000,
1015 WM8766_DAC_CTRL, 0x0120,
1016 WM8766_INT_CTRL, 0x0022, /* I2S Normal Mode, 24 bit */
1017 WM8766_DAC_CTRL2, 0x0001,
1018 WM8766_DAC_CTRL3, 0x0080,
1019 WM8766_LDA1, 0x0100,
1020 WM8766_LDA2, 0x0100,
1021 WM8766_LDA3, 0x0100,
1022 WM8766_RDA1, 0x0100,
1023 WM8766_RDA2, 0x0100,
1024 WM8766_RDA3, 0x0100,
1025 WM8766_MUTE1, 0x0000,
1026 WM8766_MUTE2, 0x0000,
1027 };
1028
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001029 struct prodigy_hifi_spec *spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001030 unsigned int i;
1031
1032 ice->vt1720 = 0;
1033 ice->vt1724 = 1;
1034
1035 ice->num_total_dacs = 8;
1036 ice->num_total_adcs = 1;
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001037
1038 /* HACK - use this as the SPDIF source.
1039 * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten
1040 */
1041 ice->gpio.saved[0] = 0;
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001042 /* to remember the register values */
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001043
1044 ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
1045 if (! ice->akm)
1046 return -ENOMEM;
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001047 ice->akm_codecs = 1;
1048
1049 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1050 if (!spec)
1051 return -ENOMEM;
1052 ice->spec = spec;
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001053
1054 /* initialize WM8776 codec */
1055 for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2)
1056 wm_put(ice, wm_inits[i], wm_inits[i+1]);
1057 schedule_timeout_uninterruptible(1);
1058 for (i = 0; i < ARRAY_SIZE(wm_inits2); i += 2)
1059 wm_put(ice, wm_inits2[i], wm_inits2[i+1]);
1060
1061 /* initialize WM8766 codec */
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001062 for (i = 0; i < ARRAY_SIZE(wm8766_inits); i += 2)
1063 wm8766_spi_write(ice, wm8766_inits[i], wm8766_inits[i+1]);
1064
1065
1066 return 0;
1067}
1068
1069
1070/*
1071 * initialize the chip
1072 */
Igor Chernyshevb40e9532009-06-25 09:31:07 +02001073static void ak4396_init(struct snd_ice1712 *ice)
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001074{
1075 static unsigned short ak4396_inits[] = {
1076 AK4396_CTRL1, 0x87, /* I2S Normal Mode, 24 bit */
1077 AK4396_CTRL2, 0x02,
1078 AK4396_CTRL3, 0x00,
1079 AK4396_LCH_ATT, 0x00,
1080 AK4396_RCH_ATT, 0x00,
1081 };
1082
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001083 unsigned int i;
1084
Igor Chernyshevb40e9532009-06-25 09:31:07 +02001085 /* initialize ak4396 codec */
1086 /* reset codec */
1087 ak4396_write(ice, AK4396_CTRL1, 0x86);
1088 msleep(100);
1089 ak4396_write(ice, AK4396_CTRL1, 0x87);
1090
1091 for (i = 0; i < ARRAY_SIZE(ak4396_inits); i += 2)
1092 ak4396_write(ice, ak4396_inits[i], ak4396_inits[i+1]);
1093}
1094
Takashi Iwaic7561cd2012-08-14 18:12:04 +02001095#ifdef CONFIG_PM_SLEEP
Takashi Iwai5e08fe52009-11-14 14:37:19 +01001096static int prodigy_hd2_resume(struct snd_ice1712 *ice)
Igor Chernyshevb40e9532009-06-25 09:31:07 +02001097{
1098 /* initialize ak4396 codec and restore previous mixer volumes */
1099 struct prodigy_hifi_spec *spec = ice->spec;
1100 int i;
1101 mutex_lock(&ice->gpio_mutex);
1102 ak4396_init(ice);
1103 for (i = 0; i < 2; i++)
1104 ak4396_write(ice, AK4396_LCH_ATT + i, spec->vol[i] & 0xff);
1105 mutex_unlock(&ice->gpio_mutex);
1106 return 0;
1107}
1108#endif
1109
Bill Pembertone23e7a12012-12-06 12:35:10 -05001110static int prodigy_hd2_init(struct snd_ice1712 *ice)
Igor Chernyshevb40e9532009-06-25 09:31:07 +02001111{
1112 struct prodigy_hifi_spec *spec;
1113
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001114 ice->vt1720 = 0;
1115 ice->vt1724 = 1;
1116
1117 ice->num_total_dacs = 1;
1118 ice->num_total_adcs = 1;
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001119
1120 /* HACK - use this as the SPDIF source.
1121 * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten
1122 */
1123 ice->gpio.saved[0] = 0;
Lucas De Marchi25985ed2011-03-30 22:57:33 -03001124 /* to remember the register values */
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001125
1126 ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
1127 if (! ice->akm)
1128 return -ENOMEM;
1129 ice->akm_codecs = 1;
1130
Takashi Iwai7cda8ba2008-01-18 13:36:07 +01001131 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1132 if (!spec)
1133 return -ENOMEM;
1134 ice->spec = spec;
1135
Takashi Iwaic7561cd2012-08-14 18:12:04 +02001136#ifdef CONFIG_PM_SLEEP
Igor Chernyshevb40e9532009-06-25 09:31:07 +02001137 ice->pm_resume = &prodigy_hd2_resume;
1138 ice->pm_suspend_enabled = 1;
1139#endif
1140
1141 ak4396_init(ice);
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001142
1143 return 0;
1144}
1145
1146
Bill Pembertone23e7a12012-12-06 12:35:10 -05001147static unsigned char prodigy71hifi_eeprom[] = {
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001148 0x4b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
1149 0x80, /* ACLINK: I2S */
1150 0xfc, /* I2S: vol, 96k, 24bit, 192k */
1151 0xc3, /* SPDIF: out-en, out-int, spdif-in */
1152 0xff, /* GPIO_DIR */
1153 0xff, /* GPIO_DIR1 */
1154 0x5f, /* GPIO_DIR2 */
1155 0x00, /* GPIO_MASK */
1156 0x00, /* GPIO_MASK1 */
1157 0x00, /* GPIO_MASK2 */
1158 0x00, /* GPIO_STATE */
1159 0x00, /* GPIO_STATE1 */
1160 0x00, /* GPIO_STATE2 */
1161};
1162
Bill Pembertone23e7a12012-12-06 12:35:10 -05001163static unsigned char prodigyhd2_eeprom[] = {
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001164 0x4b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
1165 0x80, /* ACLINK: I2S */
1166 0xfc, /* I2S: vol, 96k, 24bit, 192k */
1167 0xc3, /* SPDIF: out-en, out-int, spdif-in */
1168 0xff, /* GPIO_DIR */
1169 0xff, /* GPIO_DIR1 */
1170 0x5f, /* GPIO_DIR2 */
1171 0x00, /* GPIO_MASK */
1172 0x00, /* GPIO_MASK1 */
1173 0x00, /* GPIO_MASK2 */
1174 0x00, /* GPIO_STATE */
1175 0x00, /* GPIO_STATE1 */
1176 0x00, /* GPIO_STATE2 */
1177};
1178
Bill Pembertone23e7a12012-12-06 12:35:10 -05001179static unsigned char fortissimo4_eeprom[] = {
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001180 0x43, /* SYSCONF: clock 512, ADC, 4DACs */
1181 0x80, /* ACLINK: I2S */
1182 0xfc, /* I2S: vol, 96k, 24bit, 192k */
1183 0xc1, /* SPDIF: out-en, out-int */
1184 0xff, /* GPIO_DIR */
1185 0xff, /* GPIO_DIR1 */
1186 0x5f, /* GPIO_DIR2 */
1187 0x00, /* GPIO_MASK */
1188 0x00, /* GPIO_MASK1 */
1189 0x00, /* GPIO_MASK2 */
1190 0x00, /* GPIO_STATE */
1191 0x00, /* GPIO_STATE1 */
1192 0x00, /* GPIO_STATE2 */
1193};
1194
1195/* entry point */
Bill Pembertone23e7a12012-12-06 12:35:10 -05001196struct snd_ice1712_card_info snd_vt1724_prodigy_hifi_cards[] = {
Julian Scheel6b8d6e52008-01-16 19:50:00 +01001197 {
1198 .subvendor = VT1724_SUBDEVICE_PRODIGY_HIFI,
1199 .name = "Audiotrak Prodigy 7.1 HiFi",
1200 .model = "prodigy71hifi",
1201 .chip_init = prodigy_hifi_init,
1202 .build_controls = prodigy_hifi_add_controls,
1203 .eeprom_size = sizeof(prodigy71hifi_eeprom),
1204 .eeprom_data = prodigy71hifi_eeprom,
1205 .driver = "Prodigy71HIFI",
1206 },
1207 {
1208 .subvendor = VT1724_SUBDEVICE_PRODIGY_HD2,
1209 .name = "Audiotrak Prodigy HD2",
1210 .model = "prodigyhd2",
1211 .chip_init = prodigy_hd2_init,
1212 .build_controls = prodigy_hd2_add_controls,
1213 .eeprom_size = sizeof(prodigyhd2_eeprom),
1214 .eeprom_data = prodigyhd2_eeprom,
1215 .driver = "Prodigy71HD2",
1216 },
1217 {
1218 .subvendor = VT1724_SUBDEVICE_FORTISSIMO4,
1219 .name = "Hercules Fortissimo IV",
1220 .model = "fortissimo4",
1221 .chip_init = prodigy_hifi_init,
1222 .build_controls = prodigy_hifi_add_controls,
1223 .eeprom_size = sizeof(fortissimo4_eeprom),
1224 .eeprom_data = fortissimo4_eeprom,
1225 .driver = "Fortissimo4",
1226 },
1227 { } /* terminator */
1228};
1229