xref: /linux/sound/pci/ice1712/prodigy_hifi.c (revision ead5d1f4d877e92c051e1a1ade623d0d30e71619)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
26b8d6e55SJulian Scheel /*
36b8d6e55SJulian Scheel  *   ALSA driver for ICEnsemble VT1724 (Envy24HT)
46b8d6e55SJulian Scheel  *
56b8d6e55SJulian Scheel  *   Lowlevel functions for Audiotrak Prodigy 7.1 Hifi
66b8d6e55SJulian Scheel  *   based on pontis.c
76b8d6e55SJulian Scheel  *
86b8d6e55SJulian Scheel  *      Copyright (c) 2007 Julian Scheel <julian@jusst.de>
96b8d6e55SJulian Scheel  *      Copyright (c) 2007 allank
106b8d6e55SJulian Scheel  *      Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
116b8d6e55SJulian Scheel  */
126b8d6e55SJulian Scheel 
136b8d6e55SJulian Scheel 
146b8d6e55SJulian Scheel #include <linux/delay.h>
156b8d6e55SJulian Scheel #include <linux/interrupt.h>
166b8d6e55SJulian Scheel #include <linux/init.h>
176b8d6e55SJulian Scheel #include <linux/slab.h>
186b8d6e55SJulian Scheel #include <linux/mutex.h>
196b8d6e55SJulian Scheel 
206b8d6e55SJulian Scheel #include <sound/core.h>
216b8d6e55SJulian Scheel #include <sound/info.h>
226b8d6e55SJulian Scheel #include <sound/tlv.h>
236b8d6e55SJulian Scheel 
246b8d6e55SJulian Scheel #include "ice1712.h"
256b8d6e55SJulian Scheel #include "envy24ht.h"
266b8d6e55SJulian Scheel #include "prodigy_hifi.h"
276b8d6e55SJulian Scheel 
287cda8ba9STakashi Iwai struct prodigy_hifi_spec {
297cda8ba9STakashi Iwai 	unsigned short master[2];
307cda8ba9STakashi Iwai 	unsigned short vol[8];
317cda8ba9STakashi Iwai };
327cda8ba9STakashi Iwai 
336b8d6e55SJulian Scheel /* I2C addresses */
346b8d6e55SJulian Scheel #define WM_DEV		0x34
356b8d6e55SJulian Scheel 
366b8d6e55SJulian Scheel /* WM8776 registers */
376b8d6e55SJulian Scheel #define WM_HP_ATTEN_L		0x00	/* headphone left attenuation */
386b8d6e55SJulian Scheel #define WM_HP_ATTEN_R		0x01	/* headphone left attenuation */
396b8d6e55SJulian Scheel #define WM_HP_MASTER		0x02	/* headphone master (both channels),
406b8d6e55SJulian Scheel 						override LLR */
416b8d6e55SJulian Scheel #define WM_DAC_ATTEN_L		0x03	/* digital left attenuation */
426b8d6e55SJulian Scheel #define WM_DAC_ATTEN_R		0x04
436b8d6e55SJulian Scheel #define WM_DAC_MASTER		0x05
446b8d6e55SJulian Scheel #define WM_PHASE_SWAP		0x06	/* DAC phase swap */
456b8d6e55SJulian Scheel #define WM_DAC_CTRL1		0x07
466b8d6e55SJulian Scheel #define WM_DAC_MUTE		0x08
476b8d6e55SJulian Scheel #define WM_DAC_CTRL2		0x09
486b8d6e55SJulian Scheel #define WM_DAC_INT		0x0a
496b8d6e55SJulian Scheel #define WM_ADC_INT		0x0b
506b8d6e55SJulian Scheel #define WM_MASTER_CTRL		0x0c
516b8d6e55SJulian Scheel #define WM_POWERDOWN		0x0d
526b8d6e55SJulian Scheel #define WM_ADC_ATTEN_L		0x0e
536b8d6e55SJulian Scheel #define WM_ADC_ATTEN_R		0x0f
546b8d6e55SJulian Scheel #define WM_ALC_CTRL1		0x10
556b8d6e55SJulian Scheel #define WM_ALC_CTRL2		0x11
566b8d6e55SJulian Scheel #define WM_ALC_CTRL3		0x12
576b8d6e55SJulian Scheel #define WM_NOISE_GATE		0x13
586b8d6e55SJulian Scheel #define WM_LIMITER		0x14
596b8d6e55SJulian Scheel #define WM_ADC_MUX		0x15
606b8d6e55SJulian Scheel #define WM_OUT_MUX		0x16
616b8d6e55SJulian Scheel #define WM_RESET		0x17
626b8d6e55SJulian Scheel 
636b8d6e55SJulian Scheel /* Analog Recording Source :- Mic, LineIn, CD/Video, */
646b8d6e55SJulian Scheel 
656b8d6e55SJulian Scheel /* implement capture source select control for WM8776 */
666b8d6e55SJulian Scheel 
676b8d6e55SJulian Scheel #define WM_AIN1 "AIN1"
686b8d6e55SJulian Scheel #define WM_AIN2 "AIN2"
696b8d6e55SJulian Scheel #define WM_AIN3 "AIN3"
706b8d6e55SJulian Scheel #define WM_AIN4 "AIN4"
716b8d6e55SJulian Scheel #define WM_AIN5 "AIN5"
726b8d6e55SJulian Scheel 
736b8d6e55SJulian Scheel /* GPIO pins of envy24ht connected to wm8766 */
746b8d6e55SJulian Scheel #define WM8766_SPI_CLK	 (1<<17) /* CLK, Pin97 on ICE1724 */
756b8d6e55SJulian Scheel #define WM8766_SPI_MD	  (1<<16) /* DATA VT1724 -> WM8766, Pin96 */
766b8d6e55SJulian Scheel #define WM8766_SPI_ML	  (1<<18) /* Latch, Pin98 */
776b8d6e55SJulian Scheel 
786b8d6e55SJulian Scheel /* WM8766 registers */
796b8d6e55SJulian Scheel #define WM8766_DAC_CTRL	 0x02   /* DAC Control */
806b8d6e55SJulian Scheel #define WM8766_INT_CTRL	 0x03   /* Interface Control */
816b8d6e55SJulian Scheel #define WM8766_DAC_CTRL2	0x09
826b8d6e55SJulian Scheel #define WM8766_DAC_CTRL3	0x0a
836b8d6e55SJulian Scheel #define WM8766_RESET	    0x1f
846b8d6e55SJulian Scheel #define WM8766_LDA1	     0x00
856b8d6e55SJulian Scheel #define WM8766_LDA2	     0x04
866b8d6e55SJulian Scheel #define WM8766_LDA3	     0x06
876b8d6e55SJulian Scheel #define WM8766_RDA1	     0x01
886b8d6e55SJulian Scheel #define WM8766_RDA2	     0x05
896b8d6e55SJulian Scheel #define WM8766_RDA3	     0x07
906b8d6e55SJulian Scheel #define WM8766_MUTE1	    0x0C
916b8d6e55SJulian Scheel #define WM8766_MUTE2	    0x0F
926b8d6e55SJulian Scheel 
936b8d6e55SJulian Scheel 
946b8d6e55SJulian Scheel /*
956b8d6e55SJulian Scheel  * Prodigy HD2
966b8d6e55SJulian Scheel  */
976b8d6e55SJulian Scheel #define AK4396_ADDR    0x00
986b8d6e55SJulian Scheel #define AK4396_CSN    (1 << 8)    /* CSN->GPIO8, pin 75 */
996b8d6e55SJulian Scheel #define AK4396_CCLK   (1 << 9)    /* CCLK->GPIO9, pin 76 */
1006b8d6e55SJulian Scheel #define AK4396_CDTI   (1 << 10)   /* CDTI->GPIO10, pin 77 */
1016b8d6e55SJulian Scheel 
1026b8d6e55SJulian Scheel /* ak4396 registers */
1036b8d6e55SJulian Scheel #define AK4396_CTRL1	    0x00
1046b8d6e55SJulian Scheel #define AK4396_CTRL2	    0x01
1056b8d6e55SJulian Scheel #define AK4396_CTRL3	    0x02
1066b8d6e55SJulian Scheel #define AK4396_LCH_ATT	  0x03
1076b8d6e55SJulian Scheel #define AK4396_RCH_ATT	  0x04
1086b8d6e55SJulian Scheel 
1096b8d6e55SJulian Scheel 
1106b8d6e55SJulian Scheel /*
1116b8d6e55SJulian Scheel  * get the current register value of WM codec
1126b8d6e55SJulian Scheel  */
wm_get(struct snd_ice1712 * ice,int reg)1136b8d6e55SJulian Scheel static unsigned short wm_get(struct snd_ice1712 *ice, int reg)
1146b8d6e55SJulian Scheel {
1156b8d6e55SJulian Scheel 	reg <<= 1;
1166b8d6e55SJulian Scheel 	return ((unsigned short)ice->akm[0].images[reg] << 8) |
1176b8d6e55SJulian Scheel 		ice->akm[0].images[reg + 1];
1186b8d6e55SJulian Scheel }
1196b8d6e55SJulian Scheel 
1206b8d6e55SJulian Scheel /*
1216b8d6e55SJulian Scheel  * set the register value of WM codec and remember it
1226b8d6e55SJulian Scheel  */
wm_put_nocache(struct snd_ice1712 * ice,int reg,unsigned short val)1236b8d6e55SJulian Scheel static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val)
1246b8d6e55SJulian Scheel {
1256b8d6e55SJulian Scheel 	unsigned short cval;
1266b8d6e55SJulian Scheel 	cval = (reg << 9) | val;
1276b8d6e55SJulian Scheel 	snd_vt1724_write_i2c(ice, WM_DEV, cval >> 8, cval & 0xff);
1286b8d6e55SJulian Scheel }
1296b8d6e55SJulian Scheel 
wm_put(struct snd_ice1712 * ice,int reg,unsigned short val)1306b8d6e55SJulian Scheel static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val)
1316b8d6e55SJulian Scheel {
1326b8d6e55SJulian Scheel 	wm_put_nocache(ice, reg, val);
1336b8d6e55SJulian Scheel 	reg <<= 1;
1346b8d6e55SJulian Scheel 	ice->akm[0].images[reg] = val >> 8;
1356b8d6e55SJulian Scheel 	ice->akm[0].images[reg + 1] = val;
1366b8d6e55SJulian Scheel }
1376b8d6e55SJulian Scheel 
1386b8d6e55SJulian Scheel /*
1396b8d6e55SJulian Scheel  * write data in the SPI mode
1406b8d6e55SJulian Scheel  */
1416b8d6e55SJulian Scheel 
set_gpio_bit(struct snd_ice1712 * ice,unsigned int bit,int val)1426b8d6e55SJulian Scheel static void set_gpio_bit(struct snd_ice1712 *ice, unsigned int bit, int val)
1436b8d6e55SJulian Scheel {
1446b8d6e55SJulian Scheel 	unsigned int tmp = snd_ice1712_gpio_read(ice);
1456b8d6e55SJulian Scheel 	if (val)
1466b8d6e55SJulian Scheel 		tmp |= bit;
1476b8d6e55SJulian Scheel 	else
1486b8d6e55SJulian Scheel 		tmp &= ~bit;
1496b8d6e55SJulian Scheel 	snd_ice1712_gpio_write(ice, tmp);
1506b8d6e55SJulian Scheel }
1516b8d6e55SJulian Scheel 
1526b8d6e55SJulian Scheel /*
1536b8d6e55SJulian Scheel  * SPI implementation for WM8766 codec - only writing supported, no readback
1546b8d6e55SJulian Scheel  */
1556b8d6e55SJulian Scheel 
wm8766_spi_send_word(struct snd_ice1712 * ice,unsigned int data)1566b8d6e55SJulian Scheel static void wm8766_spi_send_word(struct snd_ice1712 *ice, unsigned int data)
1576b8d6e55SJulian Scheel {
1586b8d6e55SJulian Scheel 	int i;
1596b8d6e55SJulian Scheel 	for (i = 0; i < 16; i++) {
1606b8d6e55SJulian Scheel 		set_gpio_bit(ice, WM8766_SPI_CLK, 0);
1616b8d6e55SJulian Scheel 		udelay(1);
1626b8d6e55SJulian Scheel 		set_gpio_bit(ice, WM8766_SPI_MD, data & 0x8000);
1636b8d6e55SJulian Scheel 		udelay(1);
1646b8d6e55SJulian Scheel 		set_gpio_bit(ice, WM8766_SPI_CLK, 1);
1656b8d6e55SJulian Scheel 		udelay(1);
1666b8d6e55SJulian Scheel 		data <<= 1;
1676b8d6e55SJulian Scheel 	}
1686b8d6e55SJulian Scheel }
1696b8d6e55SJulian Scheel 
wm8766_spi_write(struct snd_ice1712 * ice,unsigned int reg,unsigned int data)1707cda8ba9STakashi Iwai static void wm8766_spi_write(struct snd_ice1712 *ice, unsigned int reg,
1717cda8ba9STakashi Iwai 			     unsigned int data)
1726b8d6e55SJulian Scheel {
1736b8d6e55SJulian Scheel 	unsigned int block;
1746b8d6e55SJulian Scheel 
1756b8d6e55SJulian Scheel 	snd_ice1712_gpio_set_dir(ice, WM8766_SPI_MD|
1766b8d6e55SJulian Scheel 					WM8766_SPI_CLK|WM8766_SPI_ML);
1776b8d6e55SJulian Scheel 	snd_ice1712_gpio_set_mask(ice, ~(WM8766_SPI_MD|
1786b8d6e55SJulian Scheel 					WM8766_SPI_CLK|WM8766_SPI_ML));
1796b8d6e55SJulian Scheel 	/* latch must be low when writing */
1806b8d6e55SJulian Scheel 	set_gpio_bit(ice, WM8766_SPI_ML, 0);
1816b8d6e55SJulian Scheel 	block = (reg << 9) | (data & 0x1ff);
1826b8d6e55SJulian Scheel 	wm8766_spi_send_word(ice, block); /* REGISTER ADDRESS */
1836b8d6e55SJulian Scheel 	/* release latch */
1846b8d6e55SJulian Scheel 	set_gpio_bit(ice, WM8766_SPI_ML, 1);
1856b8d6e55SJulian Scheel 	udelay(1);
1866b8d6e55SJulian Scheel 	/* restore */
1876b8d6e55SJulian Scheel 	snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);
1886b8d6e55SJulian Scheel 	snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
1896b8d6e55SJulian Scheel }
1906b8d6e55SJulian Scheel 
1916b8d6e55SJulian Scheel 
1926b8d6e55SJulian Scheel /*
1936b8d6e55SJulian Scheel  * serial interface for ak4396 - only writing supported, no readback
1946b8d6e55SJulian Scheel  */
1956b8d6e55SJulian Scheel 
ak4396_send_word(struct snd_ice1712 * ice,unsigned int data)1966b8d6e55SJulian Scheel static void ak4396_send_word(struct snd_ice1712 *ice, unsigned int data)
1976b8d6e55SJulian Scheel {
1986b8d6e55SJulian Scheel 	int i;
1996b8d6e55SJulian Scheel 	for (i = 0; i < 16; i++) {
2006b8d6e55SJulian Scheel 		set_gpio_bit(ice, AK4396_CCLK, 0);
2016b8d6e55SJulian Scheel 		udelay(1);
2026b8d6e55SJulian Scheel 		set_gpio_bit(ice, AK4396_CDTI, data & 0x8000);
2036b8d6e55SJulian Scheel 		udelay(1);
2046b8d6e55SJulian Scheel 		set_gpio_bit(ice, AK4396_CCLK, 1);
2056b8d6e55SJulian Scheel 		udelay(1);
2066b8d6e55SJulian Scheel 		data <<= 1;
2076b8d6e55SJulian Scheel 	}
2086b8d6e55SJulian Scheel }
2096b8d6e55SJulian Scheel 
ak4396_write(struct snd_ice1712 * ice,unsigned int reg,unsigned int data)2107cda8ba9STakashi Iwai static void ak4396_write(struct snd_ice1712 *ice, unsigned int reg,
2117cda8ba9STakashi Iwai 			 unsigned int data)
2126b8d6e55SJulian Scheel {
2136b8d6e55SJulian Scheel 	unsigned int block;
2146b8d6e55SJulian Scheel 
2156b8d6e55SJulian Scheel 	snd_ice1712_gpio_set_dir(ice, AK4396_CSN|AK4396_CCLK|AK4396_CDTI);
2166b8d6e55SJulian Scheel 	snd_ice1712_gpio_set_mask(ice, ~(AK4396_CSN|AK4396_CCLK|AK4396_CDTI));
2176b8d6e55SJulian Scheel 	/* latch must be low when writing */
2186b8d6e55SJulian Scheel 	set_gpio_bit(ice, AK4396_CSN, 0);
2196b8d6e55SJulian Scheel 	block =  ((AK4396_ADDR & 0x03) << 14) | (1 << 13) |
2206b8d6e55SJulian Scheel 			((reg & 0x1f) << 8) | (data & 0xff);
2216b8d6e55SJulian Scheel 	ak4396_send_word(ice, block); /* REGISTER ADDRESS */
2226b8d6e55SJulian Scheel 	/* release latch */
2236b8d6e55SJulian Scheel 	set_gpio_bit(ice, AK4396_CSN, 1);
2246b8d6e55SJulian Scheel 	udelay(1);
2256b8d6e55SJulian Scheel 	/* restore */
2266b8d6e55SJulian Scheel 	snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask);
2276b8d6e55SJulian Scheel 	snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
2286b8d6e55SJulian Scheel }
2296b8d6e55SJulian Scheel 
2306b8d6e55SJulian Scheel 
2316b8d6e55SJulian Scheel /*
2326b8d6e55SJulian Scheel  * ak4396 mixers
2336b8d6e55SJulian Scheel  */
2346b8d6e55SJulian Scheel 
2356b8d6e55SJulian Scheel 
2366b8d6e55SJulian Scheel 
2376b8d6e55SJulian Scheel /*
2386b8d6e55SJulian Scheel  * DAC volume attenuation mixer control (-64dB to 0dB)
2396b8d6e55SJulian Scheel  */
2406b8d6e55SJulian Scheel 
ak4396_dac_vol_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)2417cda8ba9STakashi Iwai static int ak4396_dac_vol_info(struct snd_kcontrol *kcontrol,
2427cda8ba9STakashi Iwai 			       struct snd_ctl_elem_info *uinfo)
2436b8d6e55SJulian Scheel {
2446b8d6e55SJulian Scheel 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2456b8d6e55SJulian Scheel 	uinfo->count = 2;
2466b8d6e55SJulian Scheel 	uinfo->value.integer.min = 0;   /* mute */
2476b8d6e55SJulian Scheel 	uinfo->value.integer.max = 0xFF; /* linear */
2486b8d6e55SJulian Scheel 	return 0;
2496b8d6e55SJulian Scheel }
2506b8d6e55SJulian Scheel 
ak4396_dac_vol_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2517cda8ba9STakashi Iwai static int ak4396_dac_vol_get(struct snd_kcontrol *kcontrol,
2527cda8ba9STakashi Iwai 			      struct snd_ctl_elem_value *ucontrol)
2536b8d6e55SJulian Scheel {
2546b8d6e55SJulian Scheel 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
2557cda8ba9STakashi Iwai 	struct prodigy_hifi_spec *spec = ice->spec;
2566b8d6e55SJulian Scheel 	int i;
2576b8d6e55SJulian Scheel 
2587cda8ba9STakashi Iwai 	for (i = 0; i < 2; i++)
2597cda8ba9STakashi Iwai 		ucontrol->value.integer.value[i] = spec->vol[i];
2607cda8ba9STakashi Iwai 
2616b8d6e55SJulian Scheel 	return 0;
2626b8d6e55SJulian Scheel }
2636b8d6e55SJulian Scheel 
ak4396_dac_vol_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)2646b8d6e55SJulian Scheel static int ak4396_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
2656b8d6e55SJulian Scheel {
2666b8d6e55SJulian Scheel 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
2677cda8ba9STakashi Iwai 	struct prodigy_hifi_spec *spec = ice->spec;
2686b8d6e55SJulian Scheel 	int i;
2696b8d6e55SJulian Scheel 	int change = 0;
2706b8d6e55SJulian Scheel 
2716b8d6e55SJulian Scheel 	mutex_lock(&ice->gpio_mutex);
2726b8d6e55SJulian Scheel 	for (i = 0; i < 2; i++) {
2737cda8ba9STakashi Iwai 		if (ucontrol->value.integer.value[i] != spec->vol[i]) {
2747cda8ba9STakashi Iwai 			spec->vol[i] = ucontrol->value.integer.value[i];
2756b8d6e55SJulian Scheel 			ak4396_write(ice, AK4396_LCH_ATT + i,
2767cda8ba9STakashi Iwai 				     spec->vol[i] & 0xff);
2776b8d6e55SJulian Scheel 			change = 1;
2786b8d6e55SJulian Scheel 		}
2796b8d6e55SJulian Scheel 	}
2806b8d6e55SJulian Scheel 	mutex_unlock(&ice->gpio_mutex);
2816b8d6e55SJulian Scheel 	return change;
2826b8d6e55SJulian Scheel }
2836b8d6e55SJulian Scheel 
2846b8d6e55SJulian Scheel static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1);
2853737e2beSMatteo Frigo static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0);
2866b8d6e55SJulian Scheel 
287b4e5e707STakashi Iwai static const struct snd_kcontrol_new prodigy_hd2_controls[] = {
2886b8d6e55SJulian Scheel     {
2896b8d6e55SJulian Scheel 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2906b8d6e55SJulian Scheel 	.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
2916b8d6e55SJulian Scheel 		SNDRV_CTL_ELEM_ACCESS_TLV_READ),
2926b8d6e55SJulian Scheel 	.name = "Front Playback Volume",
2936b8d6e55SJulian Scheel 	.info = ak4396_dac_vol_info,
2946b8d6e55SJulian Scheel 	.get = ak4396_dac_vol_get,
2956b8d6e55SJulian Scheel 	.put = ak4396_dac_vol_put,
2963737e2beSMatteo Frigo 	.tlv = { .p = ak4396_db_scale },
2976b8d6e55SJulian Scheel     },
2986b8d6e55SJulian Scheel };
2996b8d6e55SJulian Scheel 
3006b8d6e55SJulian Scheel 
3016b8d6e55SJulian Scheel /* --------------- */
3026b8d6e55SJulian Scheel 
30301655193SStefan Agner #define WM_VOL_MAX	255
3046b8d6e55SJulian Scheel #define WM_VOL_MUTE	0x8000
3056b8d6e55SJulian Scheel 
3066b8d6e55SJulian Scheel 
3076b8d6e55SJulian Scheel #define DAC_0dB	0xff
3086b8d6e55SJulian Scheel #define DAC_RES	128
3096b8d6e55SJulian Scheel #define DAC_MIN	(DAC_0dB - DAC_RES)
3106b8d6e55SJulian Scheel 
3116b8d6e55SJulian Scheel 
wm_set_vol(struct snd_ice1712 * ice,unsigned int index,unsigned short vol,unsigned short master)3127cda8ba9STakashi Iwai static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index,
3137cda8ba9STakashi Iwai 		       unsigned short vol, unsigned short master)
3146b8d6e55SJulian Scheel {
3156b8d6e55SJulian Scheel 	unsigned char nvol;
3166b8d6e55SJulian Scheel 
3176b8d6e55SJulian Scheel 	if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
3186b8d6e55SJulian Scheel 		nvol = 0;
3196b8d6e55SJulian Scheel 	else {
3206b8d6e55SJulian Scheel 		nvol = (((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 128)
3216b8d6e55SJulian Scheel 				& WM_VOL_MAX;
3226b8d6e55SJulian Scheel 		nvol = (nvol ? (nvol + DAC_MIN) : 0) & 0xff;
3236b8d6e55SJulian Scheel 	}
3246b8d6e55SJulian Scheel 
3256b8d6e55SJulian Scheel 	wm_put(ice, index, nvol);
3266b8d6e55SJulian Scheel 	wm_put_nocache(ice, index, 0x100 | nvol);
3276b8d6e55SJulian Scheel }
3286b8d6e55SJulian Scheel 
wm8766_set_vol(struct snd_ice1712 * ice,unsigned int index,unsigned short vol,unsigned short master)3297cda8ba9STakashi Iwai static void wm8766_set_vol(struct snd_ice1712 *ice, unsigned int index,
3307cda8ba9STakashi Iwai 			   unsigned short vol, unsigned short master)
3316b8d6e55SJulian Scheel {
3326b8d6e55SJulian Scheel 	unsigned char nvol;
3336b8d6e55SJulian Scheel 
3346b8d6e55SJulian Scheel 	if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE))
3356b8d6e55SJulian Scheel 		nvol = 0;
3366b8d6e55SJulian Scheel 	else {
3376b8d6e55SJulian Scheel 		nvol = (((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 128)
3386b8d6e55SJulian Scheel 				& WM_VOL_MAX;
3396b8d6e55SJulian Scheel 		nvol = (nvol ? (nvol + DAC_MIN) : 0) & 0xff;
3406b8d6e55SJulian Scheel 	}
3416b8d6e55SJulian Scheel 
3426b8d6e55SJulian Scheel 	wm8766_spi_write(ice, index, (0x0100 | nvol));
3436b8d6e55SJulian Scheel }
3446b8d6e55SJulian Scheel 
3456b8d6e55SJulian Scheel 
3466b8d6e55SJulian Scheel /*
3476b8d6e55SJulian Scheel  * DAC volume attenuation mixer control (-64dB to 0dB)
3486b8d6e55SJulian Scheel  */
3496b8d6e55SJulian Scheel 
wm_dac_vol_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3507cda8ba9STakashi Iwai static int wm_dac_vol_info(struct snd_kcontrol *kcontrol,
3517cda8ba9STakashi Iwai 			   struct snd_ctl_elem_info *uinfo)
3526b8d6e55SJulian Scheel {
3536b8d6e55SJulian Scheel 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
3546b8d6e55SJulian Scheel 	uinfo->count = 2;
3556b8d6e55SJulian Scheel 	uinfo->value.integer.min = 0;	/* mute */
3566b8d6e55SJulian Scheel 	uinfo->value.integer.max = DAC_RES;	/* 0dB, 0.5dB step */
3576b8d6e55SJulian Scheel 	return 0;
3586b8d6e55SJulian Scheel }
3596b8d6e55SJulian Scheel 
wm_dac_vol_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3607cda8ba9STakashi Iwai static int wm_dac_vol_get(struct snd_kcontrol *kcontrol,
3617cda8ba9STakashi Iwai 			  struct snd_ctl_elem_value *ucontrol)
3626b8d6e55SJulian Scheel {
3636b8d6e55SJulian Scheel 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
3647cda8ba9STakashi Iwai 	struct prodigy_hifi_spec *spec = ice->spec;
3656b8d6e55SJulian Scheel 	int i;
3666b8d6e55SJulian Scheel 
3677cda8ba9STakashi Iwai 	for (i = 0; i < 2; i++)
3686b8d6e55SJulian Scheel 		ucontrol->value.integer.value[i] =
3697cda8ba9STakashi Iwai 			spec->vol[2 + i] & ~WM_VOL_MUTE;
3706b8d6e55SJulian Scheel 	return 0;
3716b8d6e55SJulian Scheel }
3726b8d6e55SJulian Scheel 
wm_dac_vol_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)3736b8d6e55SJulian Scheel static int wm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
3746b8d6e55SJulian Scheel {
3756b8d6e55SJulian Scheel 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
3767cda8ba9STakashi Iwai 	struct prodigy_hifi_spec *spec = ice->spec;
3776b8d6e55SJulian Scheel 	int i, idx, change = 0;
3786b8d6e55SJulian Scheel 
3796b8d6e55SJulian Scheel 	mutex_lock(&ice->gpio_mutex);
3806b8d6e55SJulian Scheel 	for (i = 0; i < 2; i++) {
3817cda8ba9STakashi Iwai 		if (ucontrol->value.integer.value[i] != spec->vol[2 + i]) {
3826b8d6e55SJulian Scheel 			idx = WM_DAC_ATTEN_L + i;
3837cda8ba9STakashi Iwai 			spec->vol[2 + i] &= WM_VOL_MUTE;
3847cda8ba9STakashi Iwai 			spec->vol[2 + i] |= ucontrol->value.integer.value[i];
3857cda8ba9STakashi Iwai 			wm_set_vol(ice, idx, spec->vol[2 + i], spec->master[i]);
3866b8d6e55SJulian Scheel 			change = 1;
3876b8d6e55SJulian Scheel 		}
3886b8d6e55SJulian Scheel 	}
3896b8d6e55SJulian Scheel 	mutex_unlock(&ice->gpio_mutex);
3906b8d6e55SJulian Scheel 	return change;
3916b8d6e55SJulian Scheel }
3926b8d6e55SJulian Scheel 
3936b8d6e55SJulian Scheel 
3946b8d6e55SJulian Scheel /*
3956b8d6e55SJulian Scheel  * WM8766 DAC volume attenuation mixer control
3966b8d6e55SJulian Scheel  */
wm8766_vol_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)3977cda8ba9STakashi Iwai static int wm8766_vol_info(struct snd_kcontrol *kcontrol,
3987cda8ba9STakashi Iwai 			   struct snd_ctl_elem_info *uinfo)
3996b8d6e55SJulian Scheel {
4006b8d6e55SJulian Scheel 	int voices = kcontrol->private_value >> 8;
4016b8d6e55SJulian Scheel 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
4026b8d6e55SJulian Scheel 	uinfo->count = voices;
4036b8d6e55SJulian Scheel 	uinfo->value.integer.min = 0;		/* mute */
4046b8d6e55SJulian Scheel 	uinfo->value.integer.max = DAC_RES;	/* 0dB */
4056b8d6e55SJulian Scheel 	return 0;
4066b8d6e55SJulian Scheel }
4076b8d6e55SJulian Scheel 
wm8766_vol_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4087cda8ba9STakashi Iwai static int wm8766_vol_get(struct snd_kcontrol *kcontrol,
4097cda8ba9STakashi Iwai 			  struct snd_ctl_elem_value *ucontrol)
4106b8d6e55SJulian Scheel {
4116b8d6e55SJulian Scheel 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
4127cda8ba9STakashi Iwai 	struct prodigy_hifi_spec *spec = ice->spec;
4136b8d6e55SJulian Scheel 	int i, ofs, voices;
4146b8d6e55SJulian Scheel 
4156b8d6e55SJulian Scheel 	voices = kcontrol->private_value >> 8;
4166b8d6e55SJulian Scheel 	ofs = kcontrol->private_value & 0xff;
4176b8d6e55SJulian Scheel 	for (i = 0; i < voices; i++)
4187cda8ba9STakashi Iwai 		ucontrol->value.integer.value[i] = spec->vol[ofs + i];
4196b8d6e55SJulian Scheel 	return 0;
4206b8d6e55SJulian Scheel }
4216b8d6e55SJulian Scheel 
wm8766_vol_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4226b8d6e55SJulian Scheel static int wm8766_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
4236b8d6e55SJulian Scheel {
4246b8d6e55SJulian Scheel 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
4257cda8ba9STakashi Iwai 	struct prodigy_hifi_spec *spec = ice->spec;
4266b8d6e55SJulian Scheel 	int i, idx, ofs, voices;
4276b8d6e55SJulian Scheel 	int change = 0;
4286b8d6e55SJulian Scheel 
4296b8d6e55SJulian Scheel 	voices = kcontrol->private_value >> 8;
4306b8d6e55SJulian Scheel 	ofs = kcontrol->private_value & 0xff;
4316b8d6e55SJulian Scheel 	mutex_lock(&ice->gpio_mutex);
4326b8d6e55SJulian Scheel 	for (i = 0; i < voices; i++) {
4337cda8ba9STakashi Iwai 		if (ucontrol->value.integer.value[i] != spec->vol[ofs + i]) {
4346b8d6e55SJulian Scheel 			idx = WM8766_LDA1 + ofs + i;
4357cda8ba9STakashi Iwai 			spec->vol[ofs + i] &= WM_VOL_MUTE;
4367cda8ba9STakashi Iwai 			spec->vol[ofs + i] |= ucontrol->value.integer.value[i];
4376b8d6e55SJulian Scheel 			wm8766_set_vol(ice, idx,
4387cda8ba9STakashi Iwai 				       spec->vol[ofs + i], spec->master[i]);
4396b8d6e55SJulian Scheel 			change = 1;
4406b8d6e55SJulian Scheel 		}
4416b8d6e55SJulian Scheel 	}
4426b8d6e55SJulian Scheel 	mutex_unlock(&ice->gpio_mutex);
4436b8d6e55SJulian Scheel 	return change;
4446b8d6e55SJulian Scheel }
4456b8d6e55SJulian Scheel 
4466b8d6e55SJulian Scheel /*
4476b8d6e55SJulian Scheel  * Master volume attenuation mixer control / applied to WM8776+WM8766
4486b8d6e55SJulian Scheel  */
wm_master_vol_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)4497cda8ba9STakashi Iwai static int wm_master_vol_info(struct snd_kcontrol *kcontrol,
4507cda8ba9STakashi Iwai 			      struct snd_ctl_elem_info *uinfo)
4516b8d6e55SJulian Scheel {
4526b8d6e55SJulian Scheel 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
4536b8d6e55SJulian Scheel 	uinfo->count = 2;
4546b8d6e55SJulian Scheel 	uinfo->value.integer.min = 0;
4556b8d6e55SJulian Scheel 	uinfo->value.integer.max = DAC_RES;
4566b8d6e55SJulian Scheel 	return 0;
4576b8d6e55SJulian Scheel }
4586b8d6e55SJulian Scheel 
wm_master_vol_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4597cda8ba9STakashi Iwai static int wm_master_vol_get(struct snd_kcontrol *kcontrol,
4607cda8ba9STakashi Iwai 			     struct snd_ctl_elem_value *ucontrol)
4616b8d6e55SJulian Scheel {
4626b8d6e55SJulian Scheel 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
4637cda8ba9STakashi Iwai 	struct prodigy_hifi_spec *spec = ice->spec;
4646b8d6e55SJulian Scheel 	int i;
4656b8d6e55SJulian Scheel 	for (i = 0; i < 2; i++)
4667cda8ba9STakashi Iwai 		ucontrol->value.integer.value[i] = spec->master[i];
4676b8d6e55SJulian Scheel 	return 0;
4686b8d6e55SJulian Scheel }
4696b8d6e55SJulian Scheel 
wm_master_vol_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4707cda8ba9STakashi Iwai static int wm_master_vol_put(struct snd_kcontrol *kcontrol,
4717cda8ba9STakashi Iwai 			     struct snd_ctl_elem_value *ucontrol)
4726b8d6e55SJulian Scheel {
4736b8d6e55SJulian Scheel 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
4747cda8ba9STakashi Iwai 	struct prodigy_hifi_spec *spec = ice->spec;
4756b8d6e55SJulian Scheel 	int ch, change = 0;
4766b8d6e55SJulian Scheel 
4776b8d6e55SJulian Scheel 	mutex_lock(&ice->gpio_mutex);
4786b8d6e55SJulian Scheel 	for (ch = 0; ch < 2; ch++) {
4797cda8ba9STakashi Iwai 		if (ucontrol->value.integer.value[ch] != spec->master[ch]) {
4807cda8ba9STakashi Iwai 			spec->master[ch] = ucontrol->value.integer.value[ch];
4816b8d6e55SJulian Scheel 
4826b8d6e55SJulian Scheel 			/* Apply to front DAC */
4836b8d6e55SJulian Scheel 			wm_set_vol(ice, WM_DAC_ATTEN_L + ch,
4847cda8ba9STakashi Iwai 				   spec->vol[2 + ch], spec->master[ch]);
4856b8d6e55SJulian Scheel 
4866b8d6e55SJulian Scheel 			wm8766_set_vol(ice, WM8766_LDA1 + ch,
4877cda8ba9STakashi Iwai 				       spec->vol[0 + ch], spec->master[ch]);
4886b8d6e55SJulian Scheel 
4896b8d6e55SJulian Scheel 			wm8766_set_vol(ice, WM8766_LDA2 + ch,
4907cda8ba9STakashi Iwai 				       spec->vol[4 + ch], spec->master[ch]);
4916b8d6e55SJulian Scheel 
4926b8d6e55SJulian Scheel 			wm8766_set_vol(ice, WM8766_LDA3 + ch,
4937cda8ba9STakashi Iwai 				       spec->vol[6 + ch], spec->master[ch]);
4946b8d6e55SJulian Scheel 			change = 1;
4956b8d6e55SJulian Scheel 		}
4966b8d6e55SJulian Scheel 	}
4976b8d6e55SJulian Scheel 	mutex_unlock(&ice->gpio_mutex);
4986b8d6e55SJulian Scheel 	return change;
4996b8d6e55SJulian Scheel }
5006b8d6e55SJulian Scheel 
5016b8d6e55SJulian Scheel 
5026b8d6e55SJulian Scheel /* KONSTI */
5036b8d6e55SJulian Scheel 
wm_adc_mux_enum_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)5047cda8ba9STakashi Iwai static int wm_adc_mux_enum_info(struct snd_kcontrol *kcontrol,
5057cda8ba9STakashi Iwai 				struct snd_ctl_elem_info *uinfo)
5066b8d6e55SJulian Scheel {
507597da2e4STakashi Iwai 	static const char * const texts[32] = {
5087cda8ba9STakashi Iwai 		"NULL", WM_AIN1, WM_AIN2, WM_AIN1 "+" WM_AIN2,
5096b8d6e55SJulian Scheel 		WM_AIN3, WM_AIN1 "+" WM_AIN3, WM_AIN2 "+" WM_AIN3,
5106b8d6e55SJulian Scheel 		WM_AIN1 "+" WM_AIN2 "+" WM_AIN3,
5116b8d6e55SJulian Scheel 		WM_AIN4, WM_AIN1 "+" WM_AIN4, WM_AIN2 "+" WM_AIN4,
5126b8d6e55SJulian Scheel 		WM_AIN1 "+" WM_AIN2 "+" WM_AIN4,
5136b8d6e55SJulian Scheel 		WM_AIN3 "+" WM_AIN4, WM_AIN1 "+" WM_AIN3 "+" WM_AIN4,
5146b8d6e55SJulian Scheel 		WM_AIN2 "+" WM_AIN3 "+" WM_AIN4,
5156b8d6e55SJulian Scheel 		WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4,
5166b8d6e55SJulian Scheel 		WM_AIN5, WM_AIN1 "+" WM_AIN5, WM_AIN2 "+" WM_AIN5,
5176b8d6e55SJulian Scheel 		WM_AIN1 "+" WM_AIN2 "+" WM_AIN5,
5186b8d6e55SJulian Scheel 		WM_AIN3 "+" WM_AIN5, WM_AIN1 "+" WM_AIN3 "+" WM_AIN5,
5196b8d6e55SJulian Scheel 		WM_AIN2 "+" WM_AIN3 "+" WM_AIN5,
5206b8d6e55SJulian Scheel 		WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN5,
5216b8d6e55SJulian Scheel 		WM_AIN4 "+" WM_AIN5, WM_AIN1 "+" WM_AIN4 "+" WM_AIN5,
5226b8d6e55SJulian Scheel 		WM_AIN2 "+" WM_AIN4 "+" WM_AIN5,
5236b8d6e55SJulian Scheel 		WM_AIN1 "+" WM_AIN2 "+" WM_AIN4 "+" WM_AIN5,
5246b8d6e55SJulian Scheel 		WM_AIN3 "+" WM_AIN4 "+" WM_AIN5,
5256b8d6e55SJulian Scheel 		WM_AIN1 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5,
5266b8d6e55SJulian Scheel 		WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5,
5277cda8ba9STakashi Iwai 		WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5
5287cda8ba9STakashi Iwai 	};
5296b8d6e55SJulian Scheel 
530597da2e4STakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, 32, texts);
5316b8d6e55SJulian Scheel }
5326b8d6e55SJulian Scheel 
wm_adc_mux_enum_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)5337cda8ba9STakashi Iwai static int wm_adc_mux_enum_get(struct snd_kcontrol *kcontrol,
5347cda8ba9STakashi Iwai 			       struct snd_ctl_elem_value *ucontrol)
5356b8d6e55SJulian Scheel {
5366b8d6e55SJulian Scheel 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
5376b8d6e55SJulian Scheel 
5386b8d6e55SJulian Scheel 	mutex_lock(&ice->gpio_mutex);
539*c47914c0STakashi Iwai 	ucontrol->value.enumerated.item[0] = wm_get(ice, WM_ADC_MUX) & 0x1f;
5406b8d6e55SJulian Scheel 	mutex_unlock(&ice->gpio_mutex);
5416b8d6e55SJulian Scheel 	return 0;
5426b8d6e55SJulian Scheel }
5436b8d6e55SJulian Scheel 
wm_adc_mux_enum_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)5447cda8ba9STakashi Iwai static int wm_adc_mux_enum_put(struct snd_kcontrol *kcontrol,
5457cda8ba9STakashi Iwai 			       struct snd_ctl_elem_value *ucontrol)
5466b8d6e55SJulian Scheel {
5476b8d6e55SJulian Scheel 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
5486b8d6e55SJulian Scheel 	unsigned short oval, nval;
5497cda8ba9STakashi Iwai 	int change = 0;
5506b8d6e55SJulian Scheel 
5516b8d6e55SJulian Scheel 	mutex_lock(&ice->gpio_mutex);
5526b8d6e55SJulian Scheel 	oval = wm_get(ice, WM_ADC_MUX);
553*c47914c0STakashi Iwai 	nval = (oval & 0xe0) | ucontrol->value.enumerated.item[0];
5546b8d6e55SJulian Scheel 	if (nval != oval) {
5556b8d6e55SJulian Scheel 		wm_put(ice, WM_ADC_MUX, nval);
5567cda8ba9STakashi Iwai 		change = 1;
5576b8d6e55SJulian Scheel 	}
5586b8d6e55SJulian Scheel 	mutex_unlock(&ice->gpio_mutex);
5597cda8ba9STakashi Iwai 	return change;
5606b8d6e55SJulian Scheel }
5616b8d6e55SJulian Scheel 
5626b8d6e55SJulian Scheel /* KONSTI */
5636b8d6e55SJulian Scheel 
5646b8d6e55SJulian Scheel /*
5656b8d6e55SJulian Scheel  * ADC gain mixer control (-64dB to 0dB)
5666b8d6e55SJulian Scheel  */
5676b8d6e55SJulian Scheel 
5686b8d6e55SJulian Scheel #define ADC_0dB	0xcf
5696b8d6e55SJulian Scheel #define ADC_RES	128
5706b8d6e55SJulian Scheel #define ADC_MIN	(ADC_0dB - ADC_RES)
5716b8d6e55SJulian Scheel 
wm_adc_vol_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)5727cda8ba9STakashi Iwai static int wm_adc_vol_info(struct snd_kcontrol *kcontrol,
5737cda8ba9STakashi Iwai 			   struct snd_ctl_elem_info *uinfo)
5746b8d6e55SJulian Scheel {
5756b8d6e55SJulian Scheel 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
5766b8d6e55SJulian Scheel 	uinfo->count = 2;
5776b8d6e55SJulian Scheel 	uinfo->value.integer.min = 0;	/* mute (-64dB) */
5786b8d6e55SJulian Scheel 	uinfo->value.integer.max = ADC_RES;	/* 0dB, 0.5dB step */
5796b8d6e55SJulian Scheel 	return 0;
5806b8d6e55SJulian Scheel }
5816b8d6e55SJulian Scheel 
wm_adc_vol_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)5827cda8ba9STakashi Iwai static int wm_adc_vol_get(struct snd_kcontrol *kcontrol,
5837cda8ba9STakashi Iwai 			  struct snd_ctl_elem_value *ucontrol)
5846b8d6e55SJulian Scheel {
5856b8d6e55SJulian Scheel 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
5866b8d6e55SJulian Scheel 	unsigned short val;
5876b8d6e55SJulian Scheel 	int i;
5886b8d6e55SJulian Scheel 
5896b8d6e55SJulian Scheel 	mutex_lock(&ice->gpio_mutex);
5906b8d6e55SJulian Scheel 	for (i = 0; i < 2; i++) {
5916b8d6e55SJulian Scheel 		val = wm_get(ice, WM_ADC_ATTEN_L + i) & 0xff;
5926b8d6e55SJulian Scheel 		val = val > ADC_MIN ? (val - ADC_MIN) : 0;
5936b8d6e55SJulian Scheel 		ucontrol->value.integer.value[i] = val;
5946b8d6e55SJulian Scheel 	}
5956b8d6e55SJulian Scheel 	mutex_unlock(&ice->gpio_mutex);
5966b8d6e55SJulian Scheel 	return 0;
5976b8d6e55SJulian Scheel }
5986b8d6e55SJulian Scheel 
wm_adc_vol_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)5997cda8ba9STakashi Iwai static int wm_adc_vol_put(struct snd_kcontrol *kcontrol,
6007cda8ba9STakashi Iwai 			  struct snd_ctl_elem_value *ucontrol)
6016b8d6e55SJulian Scheel {
6026b8d6e55SJulian Scheel 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
6036b8d6e55SJulian Scheel 	unsigned short ovol, nvol;
6046b8d6e55SJulian Scheel 	int i, idx, change = 0;
6056b8d6e55SJulian Scheel 
6066b8d6e55SJulian Scheel 	mutex_lock(&ice->gpio_mutex);
6076b8d6e55SJulian Scheel 	for (i = 0; i < 2; i++) {
6086b8d6e55SJulian Scheel 		nvol = ucontrol->value.integer.value[i];
6096b8d6e55SJulian Scheel 		nvol = nvol ? (nvol + ADC_MIN) : 0;
6106b8d6e55SJulian Scheel 		idx  = WM_ADC_ATTEN_L + i;
6116b8d6e55SJulian Scheel 		ovol = wm_get(ice, idx) & 0xff;
6126b8d6e55SJulian Scheel 		if (ovol != nvol) {
6136b8d6e55SJulian Scheel 			wm_put(ice, idx, nvol);
6146b8d6e55SJulian Scheel 			change = 1;
6156b8d6e55SJulian Scheel 		}
6166b8d6e55SJulian Scheel 	}
6176b8d6e55SJulian Scheel 	mutex_unlock(&ice->gpio_mutex);
6186b8d6e55SJulian Scheel 	return change;
6196b8d6e55SJulian Scheel }
6206b8d6e55SJulian Scheel 
6216b8d6e55SJulian Scheel /*
6226b8d6e55SJulian Scheel  * ADC input mux mixer control
6236b8d6e55SJulian Scheel  */
6247cda8ba9STakashi Iwai #define wm_adc_mux_info		snd_ctl_boolean_mono_info
6256b8d6e55SJulian Scheel 
wm_adc_mux_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)6267cda8ba9STakashi Iwai static int wm_adc_mux_get(struct snd_kcontrol *kcontrol,
6277cda8ba9STakashi Iwai 			  struct snd_ctl_elem_value *ucontrol)
6286b8d6e55SJulian Scheel {
6296b8d6e55SJulian Scheel 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
6306b8d6e55SJulian Scheel 	int bit = kcontrol->private_value;
6316b8d6e55SJulian Scheel 
6326b8d6e55SJulian Scheel 	mutex_lock(&ice->gpio_mutex);
6337cda8ba9STakashi Iwai 	ucontrol->value.integer.value[0] =
6347cda8ba9STakashi Iwai 		(wm_get(ice, WM_ADC_MUX) & (1 << bit)) ? 1 : 0;
6356b8d6e55SJulian Scheel 	mutex_unlock(&ice->gpio_mutex);
6366b8d6e55SJulian Scheel 	return 0;
6376b8d6e55SJulian Scheel }
6386b8d6e55SJulian Scheel 
wm_adc_mux_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)6397cda8ba9STakashi Iwai static int wm_adc_mux_put(struct snd_kcontrol *kcontrol,
6407cda8ba9STakashi Iwai 			  struct snd_ctl_elem_value *ucontrol)
6416b8d6e55SJulian Scheel {
6426b8d6e55SJulian Scheel 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
6436b8d6e55SJulian Scheel 	int bit = kcontrol->private_value;
6446b8d6e55SJulian Scheel 	unsigned short oval, nval;
6456b8d6e55SJulian Scheel 	int change;
6466b8d6e55SJulian Scheel 
6476b8d6e55SJulian Scheel 	mutex_lock(&ice->gpio_mutex);
6486b8d6e55SJulian Scheel 	nval = oval = wm_get(ice, WM_ADC_MUX);
6496b8d6e55SJulian Scheel 	if (ucontrol->value.integer.value[0])
6506b8d6e55SJulian Scheel 		nval |= (1 << bit);
6516b8d6e55SJulian Scheel 	else
6526b8d6e55SJulian Scheel 		nval &= ~(1 << bit);
6536b8d6e55SJulian Scheel 	change = nval != oval;
6546b8d6e55SJulian Scheel 	if (change) {
6556b8d6e55SJulian Scheel 		wm_put(ice, WM_ADC_MUX, nval);
6566b8d6e55SJulian Scheel 	}
6576b8d6e55SJulian Scheel 	mutex_unlock(&ice->gpio_mutex);
6586b8d6e55SJulian Scheel 	return 0;
6596b8d6e55SJulian Scheel }
6606b8d6e55SJulian Scheel 
6616b8d6e55SJulian Scheel /*
6626b8d6e55SJulian Scheel  * Analog bypass (In -> Out)
6636b8d6e55SJulian Scheel  */
6647cda8ba9STakashi Iwai #define wm_bypass_info		snd_ctl_boolean_mono_info
6656b8d6e55SJulian Scheel 
wm_bypass_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)6667cda8ba9STakashi Iwai static int wm_bypass_get(struct snd_kcontrol *kcontrol,
6677cda8ba9STakashi Iwai 			 struct snd_ctl_elem_value *ucontrol)
6686b8d6e55SJulian Scheel {
6696b8d6e55SJulian Scheel 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
6706b8d6e55SJulian Scheel 
6716b8d6e55SJulian Scheel 	mutex_lock(&ice->gpio_mutex);
6727cda8ba9STakashi Iwai 	ucontrol->value.integer.value[0] =
6737cda8ba9STakashi Iwai 		(wm_get(ice, WM_OUT_MUX) & 0x04) ? 1 : 0;
6746b8d6e55SJulian Scheel 	mutex_unlock(&ice->gpio_mutex);
6756b8d6e55SJulian Scheel 	return 0;
6766b8d6e55SJulian Scheel }
6776b8d6e55SJulian Scheel 
wm_bypass_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)6787cda8ba9STakashi Iwai static int wm_bypass_put(struct snd_kcontrol *kcontrol,
6797cda8ba9STakashi Iwai 			 struct snd_ctl_elem_value *ucontrol)
6806b8d6e55SJulian Scheel {
6816b8d6e55SJulian Scheel 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
6826b8d6e55SJulian Scheel 	unsigned short val, oval;
6836b8d6e55SJulian Scheel 	int change = 0;
6846b8d6e55SJulian Scheel 
6856b8d6e55SJulian Scheel 	mutex_lock(&ice->gpio_mutex);
6866b8d6e55SJulian Scheel 	val = oval = wm_get(ice, WM_OUT_MUX);
6876b8d6e55SJulian Scheel 	if (ucontrol->value.integer.value[0])
6886b8d6e55SJulian Scheel 		val |= 0x04;
6896b8d6e55SJulian Scheel 	else
6906b8d6e55SJulian Scheel 		val &= ~0x04;
6916b8d6e55SJulian Scheel 	if (val != oval) {
6926b8d6e55SJulian Scheel 		wm_put(ice, WM_OUT_MUX, val);
6936b8d6e55SJulian Scheel 		change = 1;
6946b8d6e55SJulian Scheel 	}
6956b8d6e55SJulian Scheel 	mutex_unlock(&ice->gpio_mutex);
6966b8d6e55SJulian Scheel 	return change;
6976b8d6e55SJulian Scheel }
6986b8d6e55SJulian Scheel 
6996b8d6e55SJulian Scheel /*
7006b8d6e55SJulian Scheel  * Left/Right swap
7016b8d6e55SJulian Scheel  */
7027cda8ba9STakashi Iwai #define wm_chswap_info		snd_ctl_boolean_mono_info
7036b8d6e55SJulian Scheel 
wm_chswap_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)7047cda8ba9STakashi Iwai static int wm_chswap_get(struct snd_kcontrol *kcontrol,
7057cda8ba9STakashi Iwai 			 struct snd_ctl_elem_value *ucontrol)
7066b8d6e55SJulian Scheel {
7076b8d6e55SJulian Scheel 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
7086b8d6e55SJulian Scheel 
7096b8d6e55SJulian Scheel 	mutex_lock(&ice->gpio_mutex);
7106b8d6e55SJulian Scheel 	ucontrol->value.integer.value[0] =
7116b8d6e55SJulian Scheel 			(wm_get(ice, WM_DAC_CTRL1) & 0xf0) != 0x90;
7126b8d6e55SJulian Scheel 	mutex_unlock(&ice->gpio_mutex);
7136b8d6e55SJulian Scheel 	return 0;
7146b8d6e55SJulian Scheel }
7156b8d6e55SJulian Scheel 
wm_chswap_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)7167cda8ba9STakashi Iwai static int wm_chswap_put(struct snd_kcontrol *kcontrol,
7177cda8ba9STakashi Iwai 			 struct snd_ctl_elem_value *ucontrol)
7186b8d6e55SJulian Scheel {
7196b8d6e55SJulian Scheel 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
7206b8d6e55SJulian Scheel 	unsigned short val, oval;
7216b8d6e55SJulian Scheel 	int change = 0;
7226b8d6e55SJulian Scheel 
7236b8d6e55SJulian Scheel 	mutex_lock(&ice->gpio_mutex);
7246b8d6e55SJulian Scheel 	oval = wm_get(ice, WM_DAC_CTRL1);
7256b8d6e55SJulian Scheel 	val = oval & 0x0f;
7266b8d6e55SJulian Scheel 	if (ucontrol->value.integer.value[0])
7276b8d6e55SJulian Scheel 		val |= 0x60;
7286b8d6e55SJulian Scheel 	else
7296b8d6e55SJulian Scheel 		val |= 0x90;
7306b8d6e55SJulian Scheel 	if (val != oval) {
7316b8d6e55SJulian Scheel 		wm_put(ice, WM_DAC_CTRL1, val);
7326b8d6e55SJulian Scheel 		wm_put_nocache(ice, WM_DAC_CTRL1, val);
7336b8d6e55SJulian Scheel 		change = 1;
7346b8d6e55SJulian Scheel 	}
7356b8d6e55SJulian Scheel 	mutex_unlock(&ice->gpio_mutex);
7366b8d6e55SJulian Scheel 	return change;
7376b8d6e55SJulian Scheel }
7386b8d6e55SJulian Scheel 
7396b8d6e55SJulian Scheel 
7406b8d6e55SJulian Scheel /*
7416b8d6e55SJulian Scheel  * mixers
7426b8d6e55SJulian Scheel  */
7436b8d6e55SJulian Scheel 
744b4e5e707STakashi Iwai static const struct snd_kcontrol_new prodigy_hifi_controls[] = {
7456b8d6e55SJulian Scheel 	{
7466b8d6e55SJulian Scheel 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7476b8d6e55SJulian Scheel 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
7486b8d6e55SJulian Scheel 			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
7496b8d6e55SJulian Scheel 		.name = "Master Playback Volume",
7506b8d6e55SJulian Scheel 		.info = wm_master_vol_info,
7516b8d6e55SJulian Scheel 		.get = wm_master_vol_get,
7526b8d6e55SJulian Scheel 		.put = wm_master_vol_put,
7536b8d6e55SJulian Scheel 		.tlv = { .p = db_scale_wm_dac }
7546b8d6e55SJulian Scheel 	},
7556b8d6e55SJulian Scheel 	{
7566b8d6e55SJulian Scheel 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7576b8d6e55SJulian Scheel 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
7586b8d6e55SJulian Scheel 			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
7596b8d6e55SJulian Scheel 		.name = "Front Playback Volume",
7606b8d6e55SJulian Scheel 		.info = wm_dac_vol_info,
7616b8d6e55SJulian Scheel 		.get = wm_dac_vol_get,
7626b8d6e55SJulian Scheel 		.put = wm_dac_vol_put,
7636b8d6e55SJulian Scheel 		.tlv = { .p = db_scale_wm_dac },
7646b8d6e55SJulian Scheel 	},
7656b8d6e55SJulian Scheel 	{
7666b8d6e55SJulian Scheel 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7676b8d6e55SJulian Scheel 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
7686b8d6e55SJulian Scheel 			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
7696b8d6e55SJulian Scheel 		.name = "Rear Playback Volume",
7706b8d6e55SJulian Scheel 		.info = wm8766_vol_info,
7716b8d6e55SJulian Scheel 		.get = wm8766_vol_get,
7726b8d6e55SJulian Scheel 		.put = wm8766_vol_put,
7736b8d6e55SJulian Scheel 		.private_value = (2 << 8) | 0,
7746b8d6e55SJulian Scheel 		.tlv = { .p = db_scale_wm_dac },
7756b8d6e55SJulian Scheel 	},
7766b8d6e55SJulian Scheel 	{
7776b8d6e55SJulian Scheel 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7786b8d6e55SJulian Scheel 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
7796b8d6e55SJulian Scheel 			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
7806b8d6e55SJulian Scheel 		.name = "Center Playback Volume",
7816b8d6e55SJulian Scheel 		.info = wm8766_vol_info,
7826b8d6e55SJulian Scheel 		.get = wm8766_vol_get,
7836b8d6e55SJulian Scheel 		.put = wm8766_vol_put,
7846b8d6e55SJulian Scheel 		.private_value = (1 << 8) | 4,
7856b8d6e55SJulian Scheel 		.tlv = { .p = db_scale_wm_dac }
7866b8d6e55SJulian Scheel 	},
7876b8d6e55SJulian Scheel 	{
7886b8d6e55SJulian Scheel 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7896b8d6e55SJulian Scheel 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
7906b8d6e55SJulian Scheel 			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
7916b8d6e55SJulian Scheel 		.name = "LFE Playback Volume",
7926b8d6e55SJulian Scheel 		.info = wm8766_vol_info,
7936b8d6e55SJulian Scheel 		.get = wm8766_vol_get,
7946b8d6e55SJulian Scheel 		.put = wm8766_vol_put,
7956b8d6e55SJulian Scheel 		.private_value = (1 << 8) | 5,
7966b8d6e55SJulian Scheel 		.tlv = { .p = db_scale_wm_dac }
7976b8d6e55SJulian Scheel 	},
7986b8d6e55SJulian Scheel 	{
7996b8d6e55SJulian Scheel 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8006b8d6e55SJulian Scheel 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
8016b8d6e55SJulian Scheel 			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
8026b8d6e55SJulian Scheel 		.name = "Side Playback Volume",
8036b8d6e55SJulian Scheel 		.info = wm8766_vol_info,
8046b8d6e55SJulian Scheel 		.get = wm8766_vol_get,
8056b8d6e55SJulian Scheel 		.put = wm8766_vol_put,
8066b8d6e55SJulian Scheel 		.private_value = (2 << 8) | 6,
8076b8d6e55SJulian Scheel 		.tlv = { .p = db_scale_wm_dac },
8086b8d6e55SJulian Scheel 	},
8096b8d6e55SJulian Scheel 	{
8106b8d6e55SJulian Scheel 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8116b8d6e55SJulian Scheel 		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
8126b8d6e55SJulian Scheel 			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
8136b8d6e55SJulian Scheel 		.name = "Capture Volume",
8146b8d6e55SJulian Scheel 		.info = wm_adc_vol_info,
8156b8d6e55SJulian Scheel 		.get = wm_adc_vol_get,
8166b8d6e55SJulian Scheel 		.put = wm_adc_vol_put,
8176b8d6e55SJulian Scheel 		.tlv = { .p = db_scale_wm_dac },
8186b8d6e55SJulian Scheel 	},
8196b8d6e55SJulian Scheel 	{
8206b8d6e55SJulian Scheel 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8216b8d6e55SJulian Scheel 		.name = "CD Capture Switch",
8226b8d6e55SJulian Scheel 		.info = wm_adc_mux_info,
8236b8d6e55SJulian Scheel 		.get = wm_adc_mux_get,
8246b8d6e55SJulian Scheel 		.put = wm_adc_mux_put,
8256b8d6e55SJulian Scheel 		.private_value = 0,
8266b8d6e55SJulian Scheel 	},
8276b8d6e55SJulian Scheel 	{
8286b8d6e55SJulian Scheel 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8296b8d6e55SJulian Scheel 		.name = "Line Capture Switch",
8306b8d6e55SJulian Scheel 		.info = wm_adc_mux_info,
8316b8d6e55SJulian Scheel 		.get = wm_adc_mux_get,
8326b8d6e55SJulian Scheel 		.put = wm_adc_mux_put,
8336b8d6e55SJulian Scheel 		.private_value = 1,
8346b8d6e55SJulian Scheel 	},
8356b8d6e55SJulian Scheel 	{
8366b8d6e55SJulian Scheel 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8376b8d6e55SJulian Scheel 		.name = "Analog Bypass Switch",
8386b8d6e55SJulian Scheel 		.info = wm_bypass_info,
8396b8d6e55SJulian Scheel 		.get = wm_bypass_get,
8406b8d6e55SJulian Scheel 		.put = wm_bypass_put,
8416b8d6e55SJulian Scheel 	},
8426b8d6e55SJulian Scheel 	{
8436b8d6e55SJulian Scheel 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8446b8d6e55SJulian Scheel 		.name = "Swap Output Channels",
8456b8d6e55SJulian Scheel 		.info = wm_chswap_info,
8466b8d6e55SJulian Scheel 		.get = wm_chswap_get,
8476b8d6e55SJulian Scheel 		.put = wm_chswap_put,
8486b8d6e55SJulian Scheel 	},
8496b8d6e55SJulian Scheel 	{
8506b8d6e55SJulian Scheel 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8516b8d6e55SJulian Scheel 		.name = "Analog Capture Source",
8526b8d6e55SJulian Scheel 		.info = wm_adc_mux_enum_info,
8536b8d6e55SJulian Scheel 		.get = wm_adc_mux_enum_get,
8546b8d6e55SJulian Scheel 		.put = wm_adc_mux_enum_put,
8556b8d6e55SJulian Scheel 	},
8566b8d6e55SJulian Scheel };
8576b8d6e55SJulian Scheel 
8586b8d6e55SJulian Scheel /*
8596b8d6e55SJulian Scheel  * WM codec registers
8606b8d6e55SJulian Scheel  */
wm_proc_regs_write(struct snd_info_entry * entry,struct snd_info_buffer * buffer)8617cda8ba9STakashi Iwai static void wm_proc_regs_write(struct snd_info_entry *entry,
8627cda8ba9STakashi Iwai 			       struct snd_info_buffer *buffer)
8636b8d6e55SJulian Scheel {
8647cda8ba9STakashi Iwai 	struct snd_ice1712 *ice = entry->private_data;
8656b8d6e55SJulian Scheel 	char line[64];
8666b8d6e55SJulian Scheel 	unsigned int reg, val;
8676b8d6e55SJulian Scheel 	mutex_lock(&ice->gpio_mutex);
8686b8d6e55SJulian Scheel 	while (!snd_info_get_line(buffer, line, sizeof(line))) {
8696b8d6e55SJulian Scheel 		if (sscanf(line, "%x %x", &reg, &val) != 2)
8706b8d6e55SJulian Scheel 			continue;
8716b8d6e55SJulian Scheel 		if (reg <= 0x17 && val <= 0xffff)
8726b8d6e55SJulian Scheel 			wm_put(ice, reg, val);
8736b8d6e55SJulian Scheel 	}
8746b8d6e55SJulian Scheel 	mutex_unlock(&ice->gpio_mutex);
8756b8d6e55SJulian Scheel }
8766b8d6e55SJulian Scheel 
wm_proc_regs_read(struct snd_info_entry * entry,struct snd_info_buffer * buffer)8777cda8ba9STakashi Iwai static void wm_proc_regs_read(struct snd_info_entry *entry,
8787cda8ba9STakashi Iwai 			      struct snd_info_buffer *buffer)
8796b8d6e55SJulian Scheel {
8807cda8ba9STakashi Iwai 	struct snd_ice1712 *ice = entry->private_data;
8816b8d6e55SJulian Scheel 	int reg, val;
8826b8d6e55SJulian Scheel 
8836b8d6e55SJulian Scheel 	mutex_lock(&ice->gpio_mutex);
8846b8d6e55SJulian Scheel 	for (reg = 0; reg <= 0x17; reg++) {
8856b8d6e55SJulian Scheel 		val = wm_get(ice, reg);
8866b8d6e55SJulian Scheel 		snd_iprintf(buffer, "%02x = %04x\n", reg, val);
8876b8d6e55SJulian Scheel 	}
8886b8d6e55SJulian Scheel 	mutex_unlock(&ice->gpio_mutex);
8896b8d6e55SJulian Scheel }
8906b8d6e55SJulian Scheel 
wm_proc_init(struct snd_ice1712 * ice)8916b8d6e55SJulian Scheel static void wm_proc_init(struct snd_ice1712 *ice)
8926b8d6e55SJulian Scheel {
89347f2769bSTakashi Iwai 	snd_card_rw_proc_new(ice->card, "wm_codec", ice, wm_proc_regs_read,
89447f2769bSTakashi Iwai 			     wm_proc_regs_write);
8956b8d6e55SJulian Scheel }
8966b8d6e55SJulian Scheel 
prodigy_hifi_add_controls(struct snd_ice1712 * ice)897e23e7a14SBill Pemberton static int prodigy_hifi_add_controls(struct snd_ice1712 *ice)
8986b8d6e55SJulian Scheel {
8996b8d6e55SJulian Scheel 	unsigned int i;
9006b8d6e55SJulian Scheel 	int err;
9016b8d6e55SJulian Scheel 
9026b8d6e55SJulian Scheel 	for (i = 0; i < ARRAY_SIZE(prodigy_hifi_controls); i++) {
9037cda8ba9STakashi Iwai 		err = snd_ctl_add(ice->card,
9047cda8ba9STakashi Iwai 				  snd_ctl_new1(&prodigy_hifi_controls[i], ice));
9056b8d6e55SJulian Scheel 		if (err < 0)
9066b8d6e55SJulian Scheel 			return err;
9076b8d6e55SJulian Scheel 	}
9086b8d6e55SJulian Scheel 
9096b8d6e55SJulian Scheel 	wm_proc_init(ice);
9106b8d6e55SJulian Scheel 
9116b8d6e55SJulian Scheel 	return 0;
9126b8d6e55SJulian Scheel }
9136b8d6e55SJulian Scheel 
prodigy_hd2_add_controls(struct snd_ice1712 * ice)914e23e7a14SBill Pemberton static int prodigy_hd2_add_controls(struct snd_ice1712 *ice)
9156b8d6e55SJulian Scheel {
9166b8d6e55SJulian Scheel 	unsigned int i;
9176b8d6e55SJulian Scheel 	int err;
9186b8d6e55SJulian Scheel 
9196b8d6e55SJulian Scheel 	for (i = 0; i < ARRAY_SIZE(prodigy_hd2_controls); i++) {
9207cda8ba9STakashi Iwai 		err = snd_ctl_add(ice->card,
9217cda8ba9STakashi Iwai 				  snd_ctl_new1(&prodigy_hd2_controls[i], ice));
9226b8d6e55SJulian Scheel 		if (err < 0)
9236b8d6e55SJulian Scheel 			return err;
9246b8d6e55SJulian Scheel 	}
9256b8d6e55SJulian Scheel 
9266b8d6e55SJulian Scheel 	wm_proc_init(ice);
9276b8d6e55SJulian Scheel 
9286b8d6e55SJulian Scheel 	return 0;
9296b8d6e55SJulian Scheel }
9306b8d6e55SJulian Scheel 
wm8766_init(struct snd_ice1712 * ice)9316dbc6cafSYussuf Khalil static void wm8766_init(struct snd_ice1712 *ice)
9326b8d6e55SJulian Scheel {
933f16a4e96STakashi Iwai 	static const unsigned short wm8766_inits[] = {
9346dbc6cafSYussuf Khalil 		WM8766_RESET,	   0x0000,
9356dbc6cafSYussuf Khalil 		WM8766_DAC_CTRL,	0x0120,
9366dbc6cafSYussuf Khalil 		WM8766_INT_CTRL,	0x0022, /* I2S Normal Mode, 24 bit */
9376dbc6cafSYussuf Khalil 		WM8766_DAC_CTRL2,       0x0001,
9386dbc6cafSYussuf Khalil 		WM8766_DAC_CTRL3,       0x0080,
9396dbc6cafSYussuf Khalil 		WM8766_LDA1,	    0x0100,
9406dbc6cafSYussuf Khalil 		WM8766_LDA2,	    0x0100,
9416dbc6cafSYussuf Khalil 		WM8766_LDA3,	    0x0100,
9426dbc6cafSYussuf Khalil 		WM8766_RDA1,	    0x0100,
9436dbc6cafSYussuf Khalil 		WM8766_RDA2,	    0x0100,
9446dbc6cafSYussuf Khalil 		WM8766_RDA3,	    0x0100,
9456dbc6cafSYussuf Khalil 		WM8766_MUTE1,	   0x0000,
9466dbc6cafSYussuf Khalil 		WM8766_MUTE2,	   0x0000,
9476dbc6cafSYussuf Khalil 	};
9486dbc6cafSYussuf Khalil 	unsigned int i;
9496dbc6cafSYussuf Khalil 
9506dbc6cafSYussuf Khalil 	for (i = 0; i < ARRAY_SIZE(wm8766_inits); i += 2)
9516dbc6cafSYussuf Khalil 		wm8766_spi_write(ice, wm8766_inits[i], wm8766_inits[i + 1]);
9526dbc6cafSYussuf Khalil }
9536dbc6cafSYussuf Khalil 
wm8776_init(struct snd_ice1712 * ice)9546dbc6cafSYussuf Khalil static void wm8776_init(struct snd_ice1712 *ice)
9556dbc6cafSYussuf Khalil {
956f16a4e96STakashi Iwai 	static const unsigned short wm8776_inits[] = {
9576b8d6e55SJulian Scheel 		/* These come first to reduce init pop noise */
9586b8d6e55SJulian Scheel 		WM_ADC_MUX,	0x0003,	/* ADC mute */
9596b8d6e55SJulian Scheel 		/* 0x00c0 replaced by 0x0003 */
9606b8d6e55SJulian Scheel 
9616b8d6e55SJulian Scheel 		WM_DAC_MUTE,	0x0001,	/* DAC softmute */
9626b8d6e55SJulian Scheel 		WM_DAC_CTRL1,	0x0000,	/* DAC mute */
9636b8d6e55SJulian Scheel 
9646b8d6e55SJulian Scheel 		WM_POWERDOWN,	0x0008,	/* All power-up except HP */
9656b8d6e55SJulian Scheel 		WM_RESET,	0x0000,	/* reset */
9666b8d6e55SJulian Scheel 	};
9676dbc6cafSYussuf Khalil 	unsigned int i;
9686dbc6cafSYussuf Khalil 
9696dbc6cafSYussuf Khalil 	for (i = 0; i < ARRAY_SIZE(wm8776_inits); i += 2)
9706dbc6cafSYussuf Khalil 		wm_put(ice, wm8776_inits[i], wm8776_inits[i + 1]);
9716dbc6cafSYussuf Khalil }
9726dbc6cafSYussuf Khalil 
9736dbc6cafSYussuf Khalil #ifdef CONFIG_PM_SLEEP
prodigy_hifi_resume(struct snd_ice1712 * ice)9746dbc6cafSYussuf Khalil static int prodigy_hifi_resume(struct snd_ice1712 *ice)
9756dbc6cafSYussuf Khalil {
976f16a4e96STakashi Iwai 	static const unsigned short wm8776_reinit_registers[] = {
9776dbc6cafSYussuf Khalil 		WM_MASTER_CTRL,
9786dbc6cafSYussuf Khalil 		WM_DAC_INT,
9796dbc6cafSYussuf Khalil 		WM_ADC_INT,
9806dbc6cafSYussuf Khalil 		WM_OUT_MUX,
9816dbc6cafSYussuf Khalil 		WM_HP_ATTEN_L,
9826dbc6cafSYussuf Khalil 		WM_HP_ATTEN_R,
9836dbc6cafSYussuf Khalil 		WM_PHASE_SWAP,
9846dbc6cafSYussuf Khalil 		WM_DAC_CTRL2,
9856dbc6cafSYussuf Khalil 		WM_ADC_ATTEN_L,
9866dbc6cafSYussuf Khalil 		WM_ADC_ATTEN_R,
9876dbc6cafSYussuf Khalil 		WM_ALC_CTRL1,
9886dbc6cafSYussuf Khalil 		WM_ALC_CTRL2,
9896dbc6cafSYussuf Khalil 		WM_ALC_CTRL3,
9906dbc6cafSYussuf Khalil 		WM_NOISE_GATE,
9916dbc6cafSYussuf Khalil 		WM_ADC_MUX,
9926dbc6cafSYussuf Khalil 		/* no DAC attenuation here */
9936dbc6cafSYussuf Khalil 	};
9946dbc6cafSYussuf Khalil 	struct prodigy_hifi_spec *spec = ice->spec;
9956dbc6cafSYussuf Khalil 	int i, ch;
9966dbc6cafSYussuf Khalil 
9976dbc6cafSYussuf Khalil 	mutex_lock(&ice->gpio_mutex);
9986dbc6cafSYussuf Khalil 
9996dbc6cafSYussuf Khalil 	/* reinitialize WM8776 and re-apply old register values */
10006dbc6cafSYussuf Khalil 	wm8776_init(ice);
10016dbc6cafSYussuf Khalil 	schedule_timeout_uninterruptible(1);
10026dbc6cafSYussuf Khalil 	for (i = 0; i < ARRAY_SIZE(wm8776_reinit_registers); i++)
10036dbc6cafSYussuf Khalil 		wm_put(ice, wm8776_reinit_registers[i],
10046dbc6cafSYussuf Khalil 		       wm_get(ice, wm8776_reinit_registers[i]));
10056dbc6cafSYussuf Khalil 
10066dbc6cafSYussuf Khalil 	/* reinitialize WM8766 and re-apply volumes for all DACs */
10076dbc6cafSYussuf Khalil 	wm8766_init(ice);
10086dbc6cafSYussuf Khalil 	for (ch = 0; ch < 2; ch++) {
10096dbc6cafSYussuf Khalil 		wm_set_vol(ice, WM_DAC_ATTEN_L + ch,
10106dbc6cafSYussuf Khalil 			   spec->vol[2 + ch], spec->master[ch]);
10116dbc6cafSYussuf Khalil 
10126dbc6cafSYussuf Khalil 		wm8766_set_vol(ice, WM8766_LDA1 + ch,
10136dbc6cafSYussuf Khalil 			       spec->vol[0 + ch], spec->master[ch]);
10146dbc6cafSYussuf Khalil 
10156dbc6cafSYussuf Khalil 		wm8766_set_vol(ice, WM8766_LDA2 + ch,
10166dbc6cafSYussuf Khalil 			       spec->vol[4 + ch], spec->master[ch]);
10176dbc6cafSYussuf Khalil 
10186dbc6cafSYussuf Khalil 		wm8766_set_vol(ice, WM8766_LDA3 + ch,
10196dbc6cafSYussuf Khalil 			       spec->vol[6 + ch], spec->master[ch]);
10206dbc6cafSYussuf Khalil 	}
10216dbc6cafSYussuf Khalil 
10226dbc6cafSYussuf Khalil 	/* unmute WM8776 DAC */
10236dbc6cafSYussuf Khalil 	wm_put(ice, WM_DAC_MUTE, 0x00);
10246dbc6cafSYussuf Khalil 	wm_put(ice, WM_DAC_CTRL1, 0x90);
10256dbc6cafSYussuf Khalil 
10266dbc6cafSYussuf Khalil 	mutex_unlock(&ice->gpio_mutex);
10276dbc6cafSYussuf Khalil 	return 0;
10286dbc6cafSYussuf Khalil }
10296dbc6cafSYussuf Khalil #endif
10306dbc6cafSYussuf Khalil 
10316dbc6cafSYussuf Khalil /*
10326dbc6cafSYussuf Khalil  * initialize the chip
10336dbc6cafSYussuf Khalil  */
prodigy_hifi_init(struct snd_ice1712 * ice)10346dbc6cafSYussuf Khalil static int prodigy_hifi_init(struct snd_ice1712 *ice)
10356dbc6cafSYussuf Khalil {
1036f16a4e96STakashi Iwai 	static const unsigned short wm8776_defaults[] = {
10376b8d6e55SJulian Scheel 		WM_MASTER_CTRL,  0x0022, /* 256fs, slave mode */
10386b8d6e55SJulian Scheel 		WM_DAC_INT,	0x0022,	/* I2S, normal polarity, 24bit */
10396b8d6e55SJulian Scheel 		WM_ADC_INT,	0x0022,	/* I2S, normal polarity, 24bit */
10406b8d6e55SJulian Scheel 		WM_DAC_CTRL1,	0x0090,	/* DAC L/R */
10416b8d6e55SJulian Scheel 		WM_OUT_MUX,	0x0001,	/* OUT DAC */
10426b8d6e55SJulian Scheel 		WM_HP_ATTEN_L,	0x0179,	/* HP 0dB */
10436b8d6e55SJulian Scheel 		WM_HP_ATTEN_R,	0x0179,	/* HP 0dB */
10446b8d6e55SJulian Scheel 		WM_DAC_ATTEN_L,	0x0000,	/* DAC 0dB */
10456b8d6e55SJulian Scheel 		WM_DAC_ATTEN_L,	0x0100,	/* DAC 0dB */
10466b8d6e55SJulian Scheel 		WM_DAC_ATTEN_R,	0x0000,	/* DAC 0dB */
10476b8d6e55SJulian Scheel 		WM_DAC_ATTEN_R,	0x0100,	/* DAC 0dB */
10486b8d6e55SJulian Scheel 		WM_PHASE_SWAP,	0x0000,	/* phase normal */
10496b8d6e55SJulian Scheel #if 0
10506b8d6e55SJulian Scheel 		WM_DAC_MASTER,	0x0100,	/* DAC master muted */
10516b8d6e55SJulian Scheel #endif
10526b8d6e55SJulian Scheel 		WM_DAC_CTRL2,	0x0000,	/* no deemphasis, no ZFLG */
10536b8d6e55SJulian Scheel 		WM_ADC_ATTEN_L,	0x0000,	/* ADC muted */
10546b8d6e55SJulian Scheel 		WM_ADC_ATTEN_R,	0x0000,	/* ADC muted */
10556b8d6e55SJulian Scheel #if 1
10566b8d6e55SJulian Scheel 		WM_ALC_CTRL1,	0x007b,	/* */
10576b8d6e55SJulian Scheel 		WM_ALC_CTRL2,	0x0000,	/* */
10586b8d6e55SJulian Scheel 		WM_ALC_CTRL3,	0x0000,	/* */
10596b8d6e55SJulian Scheel 		WM_NOISE_GATE,	0x0000,	/* */
10606b8d6e55SJulian Scheel #endif
10616b8d6e55SJulian Scheel 		WM_DAC_MUTE,	0x0000,	/* DAC unmute */
10626b8d6e55SJulian Scheel 		WM_ADC_MUX,	0x0003,	/* ADC unmute, both CD/Line On */
10636b8d6e55SJulian Scheel 	};
10647cda8ba9STakashi Iwai 	struct prodigy_hifi_spec *spec;
10656b8d6e55SJulian Scheel 	unsigned int i;
10666b8d6e55SJulian Scheel 
10676b8d6e55SJulian Scheel 	ice->vt1720 = 0;
10686b8d6e55SJulian Scheel 	ice->vt1724 = 1;
10696b8d6e55SJulian Scheel 
10706b8d6e55SJulian Scheel 	ice->num_total_dacs = 8;
10716b8d6e55SJulian Scheel 	ice->num_total_adcs = 1;
10726b8d6e55SJulian Scheel 
10736b8d6e55SJulian Scheel 	/* HACK - use this as the SPDIF source.
10746b8d6e55SJulian Scheel 	* don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten
10756b8d6e55SJulian Scheel 	*/
10766b8d6e55SJulian Scheel 	ice->gpio.saved[0] = 0;
107725985edcSLucas De Marchi 	/* to remember the register values */
10786b8d6e55SJulian Scheel 
10796b8d6e55SJulian Scheel 	ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
10806b8d6e55SJulian Scheel 	if (! ice->akm)
10816b8d6e55SJulian Scheel 		return -ENOMEM;
10826b8d6e55SJulian Scheel 	ice->akm_codecs = 1;
10836b8d6e55SJulian Scheel 
10847cda8ba9STakashi Iwai 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
10857cda8ba9STakashi Iwai 	if (!spec)
10867cda8ba9STakashi Iwai 		return -ENOMEM;
10877cda8ba9STakashi Iwai 	ice->spec = spec;
10887cda8ba9STakashi Iwai 
10896b8d6e55SJulian Scheel 	/* initialize WM8776 codec */
10906dbc6cafSYussuf Khalil 	wm8776_init(ice);
10916b8d6e55SJulian Scheel 	schedule_timeout_uninterruptible(1);
10926dbc6cafSYussuf Khalil 	for (i = 0; i < ARRAY_SIZE(wm8776_defaults); i += 2)
10936dbc6cafSYussuf Khalil 		wm_put(ice, wm8776_defaults[i], wm8776_defaults[i + 1]);
10946b8d6e55SJulian Scheel 
10956dbc6cafSYussuf Khalil 	wm8766_init(ice);
10966b8d6e55SJulian Scheel 
10976dbc6cafSYussuf Khalil #ifdef CONFIG_PM_SLEEP
10986dbc6cafSYussuf Khalil 	ice->pm_resume = &prodigy_hifi_resume;
10996dbc6cafSYussuf Khalil 	ice->pm_suspend_enabled = 1;
11006dbc6cafSYussuf Khalil #endif
11016b8d6e55SJulian Scheel 
11026b8d6e55SJulian Scheel 	return 0;
11036b8d6e55SJulian Scheel }
11046b8d6e55SJulian Scheel 
11056b8d6e55SJulian Scheel 
11066b8d6e55SJulian Scheel /*
11076b8d6e55SJulian Scheel  * initialize the chip
11086b8d6e55SJulian Scheel  */
ak4396_init(struct snd_ice1712 * ice)1109b40e9538SIgor Chernyshev static void ak4396_init(struct snd_ice1712 *ice)
11106b8d6e55SJulian Scheel {
1111f16a4e96STakashi Iwai 	static const unsigned short ak4396_inits[] = {
11126b8d6e55SJulian Scheel 		AK4396_CTRL1,	   0x87,   /* I2S Normal Mode, 24 bit */
11136b8d6e55SJulian Scheel 		AK4396_CTRL2,	   0x02,
11146b8d6e55SJulian Scheel 		AK4396_CTRL3,	   0x00,
11156b8d6e55SJulian Scheel 		AK4396_LCH_ATT,	 0x00,
11166b8d6e55SJulian Scheel 		AK4396_RCH_ATT,	 0x00,
11176b8d6e55SJulian Scheel 	};
11186b8d6e55SJulian Scheel 
11196b8d6e55SJulian Scheel 	unsigned int i;
11206b8d6e55SJulian Scheel 
1121b40e9538SIgor Chernyshev 	/* initialize ak4396 codec */
1122b40e9538SIgor Chernyshev 	/* reset codec */
1123b40e9538SIgor Chernyshev 	ak4396_write(ice, AK4396_CTRL1, 0x86);
1124b40e9538SIgor Chernyshev 	msleep(100);
1125b40e9538SIgor Chernyshev 	ak4396_write(ice, AK4396_CTRL1, 0x87);
1126b40e9538SIgor Chernyshev 
1127b40e9538SIgor Chernyshev 	for (i = 0; i < ARRAY_SIZE(ak4396_inits); i += 2)
1128b40e9538SIgor Chernyshev 		ak4396_write(ice, ak4396_inits[i], ak4396_inits[i+1]);
1129b40e9538SIgor Chernyshev }
1130b40e9538SIgor Chernyshev 
1131c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP
prodigy_hd2_resume(struct snd_ice1712 * ice)11325e08fe57STakashi Iwai static int prodigy_hd2_resume(struct snd_ice1712 *ice)
1133b40e9538SIgor Chernyshev {
1134b40e9538SIgor Chernyshev 	/* initialize ak4396 codec and restore previous mixer volumes */
1135b40e9538SIgor Chernyshev 	struct prodigy_hifi_spec *spec = ice->spec;
1136b40e9538SIgor Chernyshev 	int i;
1137b40e9538SIgor Chernyshev 	mutex_lock(&ice->gpio_mutex);
1138b40e9538SIgor Chernyshev 	ak4396_init(ice);
1139b40e9538SIgor Chernyshev 	for (i = 0; i < 2; i++)
1140b40e9538SIgor Chernyshev 		ak4396_write(ice, AK4396_LCH_ATT + i, spec->vol[i] & 0xff);
1141b40e9538SIgor Chernyshev 	mutex_unlock(&ice->gpio_mutex);
1142b40e9538SIgor Chernyshev 	return 0;
1143b40e9538SIgor Chernyshev }
1144b40e9538SIgor Chernyshev #endif
1145b40e9538SIgor Chernyshev 
prodigy_hd2_init(struct snd_ice1712 * ice)1146e23e7a14SBill Pemberton static int prodigy_hd2_init(struct snd_ice1712 *ice)
1147b40e9538SIgor Chernyshev {
1148b40e9538SIgor Chernyshev 	struct prodigy_hifi_spec *spec;
1149b40e9538SIgor Chernyshev 
11506b8d6e55SJulian Scheel 	ice->vt1720 = 0;
11516b8d6e55SJulian Scheel 	ice->vt1724 = 1;
11526b8d6e55SJulian Scheel 
11536b8d6e55SJulian Scheel 	ice->num_total_dacs = 1;
11546b8d6e55SJulian Scheel 	ice->num_total_adcs = 1;
11556b8d6e55SJulian Scheel 
11566b8d6e55SJulian Scheel 	/* HACK - use this as the SPDIF source.
11576b8d6e55SJulian Scheel 	* don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten
11586b8d6e55SJulian Scheel 	*/
11596b8d6e55SJulian Scheel 	ice->gpio.saved[0] = 0;
116025985edcSLucas De Marchi 	/* to remember the register values */
11616b8d6e55SJulian Scheel 
11626b8d6e55SJulian Scheel 	ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL);
11636b8d6e55SJulian Scheel 	if (! ice->akm)
11646b8d6e55SJulian Scheel 		return -ENOMEM;
11656b8d6e55SJulian Scheel 	ice->akm_codecs = 1;
11666b8d6e55SJulian Scheel 
11677cda8ba9STakashi Iwai 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
11687cda8ba9STakashi Iwai 	if (!spec)
11697cda8ba9STakashi Iwai 		return -ENOMEM;
11707cda8ba9STakashi Iwai 	ice->spec = spec;
11717cda8ba9STakashi Iwai 
1172c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP
1173b40e9538SIgor Chernyshev 	ice->pm_resume = &prodigy_hd2_resume;
1174b40e9538SIgor Chernyshev 	ice->pm_suspend_enabled = 1;
1175b40e9538SIgor Chernyshev #endif
11766b8d6e55SJulian Scheel 
1177b40e9538SIgor Chernyshev 	ak4396_init(ice);
11786b8d6e55SJulian Scheel 
11796b8d6e55SJulian Scheel 	return 0;
11806b8d6e55SJulian Scheel }
11816b8d6e55SJulian Scheel 
11826b8d6e55SJulian Scheel 
1183f16a4e96STakashi Iwai static const unsigned char prodigy71hifi_eeprom[] = {
11846b8d6e55SJulian Scheel 	0x4b,   /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
11856b8d6e55SJulian Scheel 	0x80,   /* ACLINK: I2S */
11866b8d6e55SJulian Scheel 	0xfc,   /* I2S: vol, 96k, 24bit, 192k */
11876b8d6e55SJulian Scheel 	0xc3,   /* SPDIF: out-en, out-int, spdif-in */
11886b8d6e55SJulian Scheel 	0xff,   /* GPIO_DIR */
11896b8d6e55SJulian Scheel 	0xff,   /* GPIO_DIR1 */
11906b8d6e55SJulian Scheel 	0x5f,   /* GPIO_DIR2 */
11916b8d6e55SJulian Scheel 	0x00,   /* GPIO_MASK */
11926b8d6e55SJulian Scheel 	0x00,   /* GPIO_MASK1 */
11936b8d6e55SJulian Scheel 	0x00,   /* GPIO_MASK2 */
11946b8d6e55SJulian Scheel 	0x00,   /* GPIO_STATE */
11956b8d6e55SJulian Scheel 	0x00,   /* GPIO_STATE1 */
11966b8d6e55SJulian Scheel 	0x00,   /* GPIO_STATE2 */
11976b8d6e55SJulian Scheel };
11986b8d6e55SJulian Scheel 
1199f16a4e96STakashi Iwai static const unsigned char prodigyhd2_eeprom[] = {
12006b8d6e55SJulian Scheel 	0x4b,   /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */
12016b8d6e55SJulian Scheel 	0x80,   /* ACLINK: I2S */
12026b8d6e55SJulian Scheel 	0xfc,   /* I2S: vol, 96k, 24bit, 192k */
12036b8d6e55SJulian Scheel 	0xc3,   /* SPDIF: out-en, out-int, spdif-in */
12046b8d6e55SJulian Scheel 	0xff,   /* GPIO_DIR */
12056b8d6e55SJulian Scheel 	0xff,   /* GPIO_DIR1 */
12066b8d6e55SJulian Scheel 	0x5f,   /* GPIO_DIR2 */
12076b8d6e55SJulian Scheel 	0x00,   /* GPIO_MASK */
12086b8d6e55SJulian Scheel 	0x00,   /* GPIO_MASK1 */
12096b8d6e55SJulian Scheel 	0x00,   /* GPIO_MASK2 */
12106b8d6e55SJulian Scheel 	0x00,   /* GPIO_STATE */
12116b8d6e55SJulian Scheel 	0x00,   /* GPIO_STATE1 */
12126b8d6e55SJulian Scheel 	0x00,   /* GPIO_STATE2 */
12136b8d6e55SJulian Scheel };
12146b8d6e55SJulian Scheel 
1215f16a4e96STakashi Iwai static const unsigned char fortissimo4_eeprom[] = {
12166b8d6e55SJulian Scheel 	0x43,   /* SYSCONF: clock 512, ADC, 4DACs */
12176b8d6e55SJulian Scheel 	0x80,   /* ACLINK: I2S */
12186b8d6e55SJulian Scheel 	0xfc,   /* I2S: vol, 96k, 24bit, 192k */
12196b8d6e55SJulian Scheel 	0xc1,   /* SPDIF: out-en, out-int */
12206b8d6e55SJulian Scheel 	0xff,   /* GPIO_DIR */
12216b8d6e55SJulian Scheel 	0xff,   /* GPIO_DIR1 */
12226b8d6e55SJulian Scheel 	0x5f,   /* GPIO_DIR2 */
12236b8d6e55SJulian Scheel 	0x00,   /* GPIO_MASK */
12246b8d6e55SJulian Scheel 	0x00,   /* GPIO_MASK1 */
12256b8d6e55SJulian Scheel 	0x00,   /* GPIO_MASK2 */
12266b8d6e55SJulian Scheel 	0x00,   /* GPIO_STATE */
12276b8d6e55SJulian Scheel 	0x00,   /* GPIO_STATE1 */
12286b8d6e55SJulian Scheel 	0x00,   /* GPIO_STATE2 */
12296b8d6e55SJulian Scheel };
12306b8d6e55SJulian Scheel 
12316b8d6e55SJulian Scheel /* entry point */
1232e23e7a14SBill Pemberton struct snd_ice1712_card_info snd_vt1724_prodigy_hifi_cards[] = {
12336b8d6e55SJulian Scheel 	{
12346b8d6e55SJulian Scheel 		.subvendor = VT1724_SUBDEVICE_PRODIGY_HIFI,
12356b8d6e55SJulian Scheel 		.name = "Audiotrak Prodigy 7.1 HiFi",
12366b8d6e55SJulian Scheel 		.model = "prodigy71hifi",
12376b8d6e55SJulian Scheel 		.chip_init = prodigy_hifi_init,
12386b8d6e55SJulian Scheel 		.build_controls = prodigy_hifi_add_controls,
12396b8d6e55SJulian Scheel 		.eeprom_size = sizeof(prodigy71hifi_eeprom),
12406b8d6e55SJulian Scheel 		.eeprom_data = prodigy71hifi_eeprom,
12416b8d6e55SJulian Scheel 		.driver = "Prodigy71HIFI",
12426b8d6e55SJulian Scheel 	},
12436b8d6e55SJulian Scheel 	{
12446b8d6e55SJulian Scheel 	.subvendor = VT1724_SUBDEVICE_PRODIGY_HD2,
12456b8d6e55SJulian Scheel 	.name = "Audiotrak Prodigy HD2",
12466b8d6e55SJulian Scheel 	.model = "prodigyhd2",
12476b8d6e55SJulian Scheel 	.chip_init = prodigy_hd2_init,
12486b8d6e55SJulian Scheel 	.build_controls = prodigy_hd2_add_controls,
12496b8d6e55SJulian Scheel 	.eeprom_size = sizeof(prodigyhd2_eeprom),
12506b8d6e55SJulian Scheel 	.eeprom_data = prodigyhd2_eeprom,
12516b8d6e55SJulian Scheel 	.driver = "Prodigy71HD2",
12526b8d6e55SJulian Scheel 	},
12536b8d6e55SJulian Scheel 	{
12546b8d6e55SJulian Scheel 		.subvendor = VT1724_SUBDEVICE_FORTISSIMO4,
12556b8d6e55SJulian Scheel 		.name = "Hercules Fortissimo IV",
12566b8d6e55SJulian Scheel 		.model = "fortissimo4",
12576b8d6e55SJulian Scheel 		.chip_init = prodigy_hifi_init,
12586b8d6e55SJulian Scheel 		.build_controls = prodigy_hifi_add_controls,
12596b8d6e55SJulian Scheel 		.eeprom_size = sizeof(fortissimo4_eeprom),
12606b8d6e55SJulian Scheel 		.eeprom_data = fortissimo4_eeprom,
12616b8d6e55SJulian Scheel 		.driver = "Fortissimo4",
12626b8d6e55SJulian Scheel 	},
12636b8d6e55SJulian Scheel 	{ } /* terminator */
12646b8d6e55SJulian Scheel };
12656b8d6e55SJulian Scheel 
1266