16b8d6e55SJulian Scheel /* 26b8d6e55SJulian Scheel * ALSA driver for ICEnsemble VT1724 (Envy24HT) 36b8d6e55SJulian Scheel * 46b8d6e55SJulian Scheel * Lowlevel functions for Audiotrak Prodigy 7.1 Hifi 56b8d6e55SJulian Scheel * based on pontis.c 66b8d6e55SJulian Scheel * 76b8d6e55SJulian Scheel * Copyright (c) 2007 Julian Scheel <julian@jusst.de> 86b8d6e55SJulian Scheel * Copyright (c) 2007 allank 96b8d6e55SJulian Scheel * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> 106b8d6e55SJulian Scheel * 116b8d6e55SJulian Scheel * This program is free software; you can redistribute it and/or modify 126b8d6e55SJulian Scheel * it under the terms of the GNU General Public License as published by 136b8d6e55SJulian Scheel * the Free Software Foundation; either version 2 of the License, or 146b8d6e55SJulian Scheel * (at your option) any later version. 156b8d6e55SJulian Scheel * 166b8d6e55SJulian Scheel * This program is distributed in the hope that it will be useful, 176b8d6e55SJulian Scheel * but WITHOUT ANY WARRANTY; without even the implied warranty of 186b8d6e55SJulian Scheel * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 196b8d6e55SJulian Scheel * GNU General Public License for more details. 206b8d6e55SJulian Scheel * 216b8d6e55SJulian Scheel * You should have received a copy of the GNU General Public License 226b8d6e55SJulian Scheel * along with this program; if not, write to the Free Software 236b8d6e55SJulian Scheel * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 246b8d6e55SJulian Scheel * 256b8d6e55SJulian Scheel */ 266b8d6e55SJulian Scheel 276b8d6e55SJulian Scheel 286b8d6e55SJulian Scheel #include <asm/io.h> 296b8d6e55SJulian Scheel #include <linux/delay.h> 306b8d6e55SJulian Scheel #include <linux/interrupt.h> 316b8d6e55SJulian Scheel #include <linux/init.h> 326b8d6e55SJulian Scheel #include <linux/slab.h> 336b8d6e55SJulian Scheel #include <linux/mutex.h> 346b8d6e55SJulian Scheel 356b8d6e55SJulian Scheel #include <sound/core.h> 366b8d6e55SJulian Scheel #include <sound/info.h> 376b8d6e55SJulian Scheel #include <sound/tlv.h> 386b8d6e55SJulian Scheel 396b8d6e55SJulian Scheel #include "ice1712.h" 406b8d6e55SJulian Scheel #include "envy24ht.h" 416b8d6e55SJulian Scheel #include "prodigy_hifi.h" 426b8d6e55SJulian Scheel 437cda8ba9STakashi Iwai struct prodigy_hifi_spec { 447cda8ba9STakashi Iwai unsigned short master[2]; 457cda8ba9STakashi Iwai unsigned short vol[8]; 467cda8ba9STakashi Iwai }; 477cda8ba9STakashi Iwai 486b8d6e55SJulian Scheel /* I2C addresses */ 496b8d6e55SJulian Scheel #define WM_DEV 0x34 506b8d6e55SJulian Scheel 516b8d6e55SJulian Scheel /* WM8776 registers */ 526b8d6e55SJulian Scheel #define WM_HP_ATTEN_L 0x00 /* headphone left attenuation */ 536b8d6e55SJulian Scheel #define WM_HP_ATTEN_R 0x01 /* headphone left attenuation */ 546b8d6e55SJulian Scheel #define WM_HP_MASTER 0x02 /* headphone master (both channels), 556b8d6e55SJulian Scheel override LLR */ 566b8d6e55SJulian Scheel #define WM_DAC_ATTEN_L 0x03 /* digital left attenuation */ 576b8d6e55SJulian Scheel #define WM_DAC_ATTEN_R 0x04 586b8d6e55SJulian Scheel #define WM_DAC_MASTER 0x05 596b8d6e55SJulian Scheel #define WM_PHASE_SWAP 0x06 /* DAC phase swap */ 606b8d6e55SJulian Scheel #define WM_DAC_CTRL1 0x07 616b8d6e55SJulian Scheel #define WM_DAC_MUTE 0x08 626b8d6e55SJulian Scheel #define WM_DAC_CTRL2 0x09 636b8d6e55SJulian Scheel #define WM_DAC_INT 0x0a 646b8d6e55SJulian Scheel #define WM_ADC_INT 0x0b 656b8d6e55SJulian Scheel #define WM_MASTER_CTRL 0x0c 666b8d6e55SJulian Scheel #define WM_POWERDOWN 0x0d 676b8d6e55SJulian Scheel #define WM_ADC_ATTEN_L 0x0e 686b8d6e55SJulian Scheel #define WM_ADC_ATTEN_R 0x0f 696b8d6e55SJulian Scheel #define WM_ALC_CTRL1 0x10 706b8d6e55SJulian Scheel #define WM_ALC_CTRL2 0x11 716b8d6e55SJulian Scheel #define WM_ALC_CTRL3 0x12 726b8d6e55SJulian Scheel #define WM_NOISE_GATE 0x13 736b8d6e55SJulian Scheel #define WM_LIMITER 0x14 746b8d6e55SJulian Scheel #define WM_ADC_MUX 0x15 756b8d6e55SJulian Scheel #define WM_OUT_MUX 0x16 766b8d6e55SJulian Scheel #define WM_RESET 0x17 776b8d6e55SJulian Scheel 786b8d6e55SJulian Scheel /* Analog Recording Source :- Mic, LineIn, CD/Video, */ 796b8d6e55SJulian Scheel 806b8d6e55SJulian Scheel /* implement capture source select control for WM8776 */ 816b8d6e55SJulian Scheel 826b8d6e55SJulian Scheel #define WM_AIN1 "AIN1" 836b8d6e55SJulian Scheel #define WM_AIN2 "AIN2" 846b8d6e55SJulian Scheel #define WM_AIN3 "AIN3" 856b8d6e55SJulian Scheel #define WM_AIN4 "AIN4" 866b8d6e55SJulian Scheel #define WM_AIN5 "AIN5" 876b8d6e55SJulian Scheel 886b8d6e55SJulian Scheel /* GPIO pins of envy24ht connected to wm8766 */ 896b8d6e55SJulian Scheel #define WM8766_SPI_CLK (1<<17) /* CLK, Pin97 on ICE1724 */ 906b8d6e55SJulian Scheel #define WM8766_SPI_MD (1<<16) /* DATA VT1724 -> WM8766, Pin96 */ 916b8d6e55SJulian Scheel #define WM8766_SPI_ML (1<<18) /* Latch, Pin98 */ 926b8d6e55SJulian Scheel 936b8d6e55SJulian Scheel /* WM8766 registers */ 946b8d6e55SJulian Scheel #define WM8766_DAC_CTRL 0x02 /* DAC Control */ 956b8d6e55SJulian Scheel #define WM8766_INT_CTRL 0x03 /* Interface Control */ 966b8d6e55SJulian Scheel #define WM8766_DAC_CTRL2 0x09 976b8d6e55SJulian Scheel #define WM8766_DAC_CTRL3 0x0a 986b8d6e55SJulian Scheel #define WM8766_RESET 0x1f 996b8d6e55SJulian Scheel #define WM8766_LDA1 0x00 1006b8d6e55SJulian Scheel #define WM8766_LDA2 0x04 1016b8d6e55SJulian Scheel #define WM8766_LDA3 0x06 1026b8d6e55SJulian Scheel #define WM8766_RDA1 0x01 1036b8d6e55SJulian Scheel #define WM8766_RDA2 0x05 1046b8d6e55SJulian Scheel #define WM8766_RDA3 0x07 1056b8d6e55SJulian Scheel #define WM8766_MUTE1 0x0C 1066b8d6e55SJulian Scheel #define WM8766_MUTE2 0x0F 1076b8d6e55SJulian Scheel 1086b8d6e55SJulian Scheel 1096b8d6e55SJulian Scheel /* 1106b8d6e55SJulian Scheel * Prodigy HD2 1116b8d6e55SJulian Scheel */ 1126b8d6e55SJulian Scheel #define AK4396_ADDR 0x00 1136b8d6e55SJulian Scheel #define AK4396_CSN (1 << 8) /* CSN->GPIO8, pin 75 */ 1146b8d6e55SJulian Scheel #define AK4396_CCLK (1 << 9) /* CCLK->GPIO9, pin 76 */ 1156b8d6e55SJulian Scheel #define AK4396_CDTI (1 << 10) /* CDTI->GPIO10, pin 77 */ 1166b8d6e55SJulian Scheel 1176b8d6e55SJulian Scheel /* ak4396 registers */ 1186b8d6e55SJulian Scheel #define AK4396_CTRL1 0x00 1196b8d6e55SJulian Scheel #define AK4396_CTRL2 0x01 1206b8d6e55SJulian Scheel #define AK4396_CTRL3 0x02 1216b8d6e55SJulian Scheel #define AK4396_LCH_ATT 0x03 1226b8d6e55SJulian Scheel #define AK4396_RCH_ATT 0x04 1236b8d6e55SJulian Scheel 1246b8d6e55SJulian Scheel 1256b8d6e55SJulian Scheel /* 1266b8d6e55SJulian Scheel * get the current register value of WM codec 1276b8d6e55SJulian Scheel */ 1286b8d6e55SJulian Scheel static unsigned short wm_get(struct snd_ice1712 *ice, int reg) 1296b8d6e55SJulian Scheel { 1306b8d6e55SJulian Scheel reg <<= 1; 1316b8d6e55SJulian Scheel return ((unsigned short)ice->akm[0].images[reg] << 8) | 1326b8d6e55SJulian Scheel ice->akm[0].images[reg + 1]; 1336b8d6e55SJulian Scheel } 1346b8d6e55SJulian Scheel 1356b8d6e55SJulian Scheel /* 1366b8d6e55SJulian Scheel * set the register value of WM codec and remember it 1376b8d6e55SJulian Scheel */ 1386b8d6e55SJulian Scheel static void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val) 1396b8d6e55SJulian Scheel { 1406b8d6e55SJulian Scheel unsigned short cval; 1416b8d6e55SJulian Scheel cval = (reg << 9) | val; 1426b8d6e55SJulian Scheel snd_vt1724_write_i2c(ice, WM_DEV, cval >> 8, cval & 0xff); 1436b8d6e55SJulian Scheel } 1446b8d6e55SJulian Scheel 1456b8d6e55SJulian Scheel static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val) 1466b8d6e55SJulian Scheel { 1476b8d6e55SJulian Scheel wm_put_nocache(ice, reg, val); 1486b8d6e55SJulian Scheel reg <<= 1; 1496b8d6e55SJulian Scheel ice->akm[0].images[reg] = val >> 8; 1506b8d6e55SJulian Scheel ice->akm[0].images[reg + 1] = val; 1516b8d6e55SJulian Scheel } 1526b8d6e55SJulian Scheel 1536b8d6e55SJulian Scheel /* 1546b8d6e55SJulian Scheel * write data in the SPI mode 1556b8d6e55SJulian Scheel */ 1566b8d6e55SJulian Scheel 1576b8d6e55SJulian Scheel static void set_gpio_bit(struct snd_ice1712 *ice, unsigned int bit, int val) 1586b8d6e55SJulian Scheel { 1596b8d6e55SJulian Scheel unsigned int tmp = snd_ice1712_gpio_read(ice); 1606b8d6e55SJulian Scheel if (val) 1616b8d6e55SJulian Scheel tmp |= bit; 1626b8d6e55SJulian Scheel else 1636b8d6e55SJulian Scheel tmp &= ~bit; 1646b8d6e55SJulian Scheel snd_ice1712_gpio_write(ice, tmp); 1656b8d6e55SJulian Scheel } 1666b8d6e55SJulian Scheel 1676b8d6e55SJulian Scheel /* 1686b8d6e55SJulian Scheel * SPI implementation for WM8766 codec - only writing supported, no readback 1696b8d6e55SJulian Scheel */ 1706b8d6e55SJulian Scheel 1716b8d6e55SJulian Scheel static void wm8766_spi_send_word(struct snd_ice1712 *ice, unsigned int data) 1726b8d6e55SJulian Scheel { 1736b8d6e55SJulian Scheel int i; 1746b8d6e55SJulian Scheel for (i = 0; i < 16; i++) { 1756b8d6e55SJulian Scheel set_gpio_bit(ice, WM8766_SPI_CLK, 0); 1766b8d6e55SJulian Scheel udelay(1); 1776b8d6e55SJulian Scheel set_gpio_bit(ice, WM8766_SPI_MD, data & 0x8000); 1786b8d6e55SJulian Scheel udelay(1); 1796b8d6e55SJulian Scheel set_gpio_bit(ice, WM8766_SPI_CLK, 1); 1806b8d6e55SJulian Scheel udelay(1); 1816b8d6e55SJulian Scheel data <<= 1; 1826b8d6e55SJulian Scheel } 1836b8d6e55SJulian Scheel } 1846b8d6e55SJulian Scheel 1857cda8ba9STakashi Iwai static void wm8766_spi_write(struct snd_ice1712 *ice, unsigned int reg, 1867cda8ba9STakashi Iwai unsigned int data) 1876b8d6e55SJulian Scheel { 1886b8d6e55SJulian Scheel unsigned int block; 1896b8d6e55SJulian Scheel 1906b8d6e55SJulian Scheel snd_ice1712_gpio_set_dir(ice, WM8766_SPI_MD| 1916b8d6e55SJulian Scheel WM8766_SPI_CLK|WM8766_SPI_ML); 1926b8d6e55SJulian Scheel snd_ice1712_gpio_set_mask(ice, ~(WM8766_SPI_MD| 1936b8d6e55SJulian Scheel WM8766_SPI_CLK|WM8766_SPI_ML)); 1946b8d6e55SJulian Scheel /* latch must be low when writing */ 1956b8d6e55SJulian Scheel set_gpio_bit(ice, WM8766_SPI_ML, 0); 1966b8d6e55SJulian Scheel block = (reg << 9) | (data & 0x1ff); 1976b8d6e55SJulian Scheel wm8766_spi_send_word(ice, block); /* REGISTER ADDRESS */ 1986b8d6e55SJulian Scheel /* release latch */ 1996b8d6e55SJulian Scheel set_gpio_bit(ice, WM8766_SPI_ML, 1); 2006b8d6e55SJulian Scheel udelay(1); 2016b8d6e55SJulian Scheel /* restore */ 2026b8d6e55SJulian Scheel snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask); 2036b8d6e55SJulian Scheel snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); 2046b8d6e55SJulian Scheel } 2056b8d6e55SJulian Scheel 2066b8d6e55SJulian Scheel 2076b8d6e55SJulian Scheel /* 2086b8d6e55SJulian Scheel * serial interface for ak4396 - only writing supported, no readback 2096b8d6e55SJulian Scheel */ 2106b8d6e55SJulian Scheel 2116b8d6e55SJulian Scheel static void ak4396_send_word(struct snd_ice1712 *ice, unsigned int data) 2126b8d6e55SJulian Scheel { 2136b8d6e55SJulian Scheel int i; 2146b8d6e55SJulian Scheel for (i = 0; i < 16; i++) { 2156b8d6e55SJulian Scheel set_gpio_bit(ice, AK4396_CCLK, 0); 2166b8d6e55SJulian Scheel udelay(1); 2176b8d6e55SJulian Scheel set_gpio_bit(ice, AK4396_CDTI, data & 0x8000); 2186b8d6e55SJulian Scheel udelay(1); 2196b8d6e55SJulian Scheel set_gpio_bit(ice, AK4396_CCLK, 1); 2206b8d6e55SJulian Scheel udelay(1); 2216b8d6e55SJulian Scheel data <<= 1; 2226b8d6e55SJulian Scheel } 2236b8d6e55SJulian Scheel } 2246b8d6e55SJulian Scheel 2257cda8ba9STakashi Iwai static void ak4396_write(struct snd_ice1712 *ice, unsigned int reg, 2267cda8ba9STakashi Iwai unsigned int data) 2276b8d6e55SJulian Scheel { 2286b8d6e55SJulian Scheel unsigned int block; 2296b8d6e55SJulian Scheel 2306b8d6e55SJulian Scheel snd_ice1712_gpio_set_dir(ice, AK4396_CSN|AK4396_CCLK|AK4396_CDTI); 2316b8d6e55SJulian Scheel snd_ice1712_gpio_set_mask(ice, ~(AK4396_CSN|AK4396_CCLK|AK4396_CDTI)); 2326b8d6e55SJulian Scheel /* latch must be low when writing */ 2336b8d6e55SJulian Scheel set_gpio_bit(ice, AK4396_CSN, 0); 2346b8d6e55SJulian Scheel block = ((AK4396_ADDR & 0x03) << 14) | (1 << 13) | 2356b8d6e55SJulian Scheel ((reg & 0x1f) << 8) | (data & 0xff); 2366b8d6e55SJulian Scheel ak4396_send_word(ice, block); /* REGISTER ADDRESS */ 2376b8d6e55SJulian Scheel /* release latch */ 2386b8d6e55SJulian Scheel set_gpio_bit(ice, AK4396_CSN, 1); 2396b8d6e55SJulian Scheel udelay(1); 2406b8d6e55SJulian Scheel /* restore */ 2416b8d6e55SJulian Scheel snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask); 2426b8d6e55SJulian Scheel snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); 2436b8d6e55SJulian Scheel } 2446b8d6e55SJulian Scheel 2456b8d6e55SJulian Scheel 2466b8d6e55SJulian Scheel /* 2476b8d6e55SJulian Scheel * ak4396 mixers 2486b8d6e55SJulian Scheel */ 2496b8d6e55SJulian Scheel 2506b8d6e55SJulian Scheel 2516b8d6e55SJulian Scheel 2526b8d6e55SJulian Scheel /* 2536b8d6e55SJulian Scheel * DAC volume attenuation mixer control (-64dB to 0dB) 2546b8d6e55SJulian Scheel */ 2556b8d6e55SJulian Scheel 2567cda8ba9STakashi Iwai static int ak4396_dac_vol_info(struct snd_kcontrol *kcontrol, 2577cda8ba9STakashi Iwai struct snd_ctl_elem_info *uinfo) 2586b8d6e55SJulian Scheel { 2596b8d6e55SJulian Scheel uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 2606b8d6e55SJulian Scheel uinfo->count = 2; 2616b8d6e55SJulian Scheel uinfo->value.integer.min = 0; /* mute */ 2626b8d6e55SJulian Scheel uinfo->value.integer.max = 0xFF; /* linear */ 2636b8d6e55SJulian Scheel return 0; 2646b8d6e55SJulian Scheel } 2656b8d6e55SJulian Scheel 2667cda8ba9STakashi Iwai static int ak4396_dac_vol_get(struct snd_kcontrol *kcontrol, 2677cda8ba9STakashi Iwai struct snd_ctl_elem_value *ucontrol) 2686b8d6e55SJulian Scheel { 2696b8d6e55SJulian Scheel struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 2707cda8ba9STakashi Iwai struct prodigy_hifi_spec *spec = ice->spec; 2716b8d6e55SJulian Scheel int i; 2726b8d6e55SJulian Scheel 2737cda8ba9STakashi Iwai for (i = 0; i < 2; i++) 2747cda8ba9STakashi Iwai ucontrol->value.integer.value[i] = spec->vol[i]; 2757cda8ba9STakashi Iwai 2766b8d6e55SJulian Scheel return 0; 2776b8d6e55SJulian Scheel } 2786b8d6e55SJulian Scheel 2796b8d6e55SJulian Scheel static int ak4396_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 2806b8d6e55SJulian Scheel { 2816b8d6e55SJulian Scheel struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 2827cda8ba9STakashi Iwai struct prodigy_hifi_spec *spec = ice->spec; 2836b8d6e55SJulian Scheel int i; 2846b8d6e55SJulian Scheel int change = 0; 2856b8d6e55SJulian Scheel 2866b8d6e55SJulian Scheel mutex_lock(&ice->gpio_mutex); 2876b8d6e55SJulian Scheel for (i = 0; i < 2; i++) { 2887cda8ba9STakashi Iwai if (ucontrol->value.integer.value[i] != spec->vol[i]) { 2897cda8ba9STakashi Iwai spec->vol[i] = ucontrol->value.integer.value[i]; 2906b8d6e55SJulian Scheel ak4396_write(ice, AK4396_LCH_ATT + i, 2917cda8ba9STakashi Iwai spec->vol[i] & 0xff); 2926b8d6e55SJulian Scheel change = 1; 2936b8d6e55SJulian Scheel } 2946b8d6e55SJulian Scheel } 2956b8d6e55SJulian Scheel mutex_unlock(&ice->gpio_mutex); 2966b8d6e55SJulian Scheel return change; 2976b8d6e55SJulian Scheel } 2986b8d6e55SJulian Scheel 2996b8d6e55SJulian Scheel static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); 3006b8d6e55SJulian Scheel 3016b8d6e55SJulian Scheel static struct snd_kcontrol_new prodigy_hd2_controls[] __devinitdata = { 3026b8d6e55SJulian Scheel { 3036b8d6e55SJulian Scheel .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3046b8d6e55SJulian Scheel .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 3056b8d6e55SJulian Scheel SNDRV_CTL_ELEM_ACCESS_TLV_READ), 3066b8d6e55SJulian Scheel .name = "Front Playback Volume", 3076b8d6e55SJulian Scheel .info = ak4396_dac_vol_info, 3086b8d6e55SJulian Scheel .get = ak4396_dac_vol_get, 3096b8d6e55SJulian Scheel .put = ak4396_dac_vol_put, 3106b8d6e55SJulian Scheel .tlv = { .p = db_scale_wm_dac }, 3116b8d6e55SJulian Scheel }, 3126b8d6e55SJulian Scheel }; 3136b8d6e55SJulian Scheel 3146b8d6e55SJulian Scheel 3156b8d6e55SJulian Scheel /* --------------- */ 3166b8d6e55SJulian Scheel 3176b8d6e55SJulian Scheel /* 3186b8d6e55SJulian Scheel * Logarithmic volume values for WM87*6 3196b8d6e55SJulian Scheel * Computed as 20 * Log10(255 / x) 3206b8d6e55SJulian Scheel */ 3216b8d6e55SJulian Scheel static const unsigned char wm_vol[256] = { 3226b8d6e55SJulian Scheel 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23, 3236b8d6e55SJulian Scheel 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, 3246b8d6e55SJulian Scheel 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, 3256b8d6e55SJulian Scheel 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 3266b8d6e55SJulian Scheel 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 3276b8d6e55SJulian Scheel 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, 3286b8d6e55SJulian Scheel 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, 3296b8d6e55SJulian Scheel 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, 3306b8d6e55SJulian Scheel 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, 3316b8d6e55SJulian Scheel 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, 3326b8d6e55SJulian Scheel 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, 3336b8d6e55SJulian Scheel 0, 0 3346b8d6e55SJulian Scheel }; 3356b8d6e55SJulian Scheel 3366b8d6e55SJulian Scheel #define WM_VOL_MAX (sizeof(wm_vol) - 1) 3376b8d6e55SJulian Scheel #define WM_VOL_MUTE 0x8000 3386b8d6e55SJulian Scheel 3396b8d6e55SJulian Scheel 3406b8d6e55SJulian Scheel #define DAC_0dB 0xff 3416b8d6e55SJulian Scheel #define DAC_RES 128 3426b8d6e55SJulian Scheel #define DAC_MIN (DAC_0dB - DAC_RES) 3436b8d6e55SJulian Scheel 3446b8d6e55SJulian Scheel 3457cda8ba9STakashi Iwai static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, 3467cda8ba9STakashi Iwai unsigned short vol, unsigned short master) 3476b8d6e55SJulian Scheel { 3486b8d6e55SJulian Scheel unsigned char nvol; 3496b8d6e55SJulian Scheel 3506b8d6e55SJulian Scheel if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) 3516b8d6e55SJulian Scheel nvol = 0; 3526b8d6e55SJulian Scheel else { 3536b8d6e55SJulian Scheel nvol = (((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 128) 3546b8d6e55SJulian Scheel & WM_VOL_MAX; 3556b8d6e55SJulian Scheel nvol = (nvol ? (nvol + DAC_MIN) : 0) & 0xff; 3566b8d6e55SJulian Scheel } 3576b8d6e55SJulian Scheel 3586b8d6e55SJulian Scheel wm_put(ice, index, nvol); 3596b8d6e55SJulian Scheel wm_put_nocache(ice, index, 0x100 | nvol); 3606b8d6e55SJulian Scheel } 3616b8d6e55SJulian Scheel 3627cda8ba9STakashi Iwai static void wm8766_set_vol(struct snd_ice1712 *ice, unsigned int index, 3637cda8ba9STakashi Iwai unsigned short vol, unsigned short master) 3646b8d6e55SJulian Scheel { 3656b8d6e55SJulian Scheel unsigned char nvol; 3666b8d6e55SJulian Scheel 3676b8d6e55SJulian Scheel if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) 3686b8d6e55SJulian Scheel nvol = 0; 3696b8d6e55SJulian Scheel else { 3706b8d6e55SJulian Scheel nvol = (((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 128) 3716b8d6e55SJulian Scheel & WM_VOL_MAX; 3726b8d6e55SJulian Scheel nvol = (nvol ? (nvol + DAC_MIN) : 0) & 0xff; 3736b8d6e55SJulian Scheel } 3746b8d6e55SJulian Scheel 3756b8d6e55SJulian Scheel wm8766_spi_write(ice, index, (0x0100 | nvol)); 3766b8d6e55SJulian Scheel } 3776b8d6e55SJulian Scheel 3786b8d6e55SJulian Scheel 3796b8d6e55SJulian Scheel /* 3806b8d6e55SJulian Scheel * DAC volume attenuation mixer control (-64dB to 0dB) 3816b8d6e55SJulian Scheel */ 3826b8d6e55SJulian Scheel 3837cda8ba9STakashi Iwai static int wm_dac_vol_info(struct snd_kcontrol *kcontrol, 3847cda8ba9STakashi Iwai struct snd_ctl_elem_info *uinfo) 3856b8d6e55SJulian Scheel { 3866b8d6e55SJulian Scheel uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 3876b8d6e55SJulian Scheel uinfo->count = 2; 3886b8d6e55SJulian Scheel uinfo->value.integer.min = 0; /* mute */ 3896b8d6e55SJulian Scheel uinfo->value.integer.max = DAC_RES; /* 0dB, 0.5dB step */ 3906b8d6e55SJulian Scheel return 0; 3916b8d6e55SJulian Scheel } 3926b8d6e55SJulian Scheel 3937cda8ba9STakashi Iwai static int wm_dac_vol_get(struct snd_kcontrol *kcontrol, 3947cda8ba9STakashi Iwai struct snd_ctl_elem_value *ucontrol) 3956b8d6e55SJulian Scheel { 3966b8d6e55SJulian Scheel struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 3977cda8ba9STakashi Iwai struct prodigy_hifi_spec *spec = ice->spec; 3986b8d6e55SJulian Scheel int i; 3996b8d6e55SJulian Scheel 4007cda8ba9STakashi Iwai for (i = 0; i < 2; i++) 4016b8d6e55SJulian Scheel ucontrol->value.integer.value[i] = 4027cda8ba9STakashi Iwai spec->vol[2 + i] & ~WM_VOL_MUTE; 4036b8d6e55SJulian Scheel return 0; 4046b8d6e55SJulian Scheel } 4056b8d6e55SJulian Scheel 4066b8d6e55SJulian Scheel static int wm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 4076b8d6e55SJulian Scheel { 4086b8d6e55SJulian Scheel struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 4097cda8ba9STakashi Iwai struct prodigy_hifi_spec *spec = ice->spec; 4106b8d6e55SJulian Scheel int i, idx, change = 0; 4116b8d6e55SJulian Scheel 4126b8d6e55SJulian Scheel mutex_lock(&ice->gpio_mutex); 4136b8d6e55SJulian Scheel for (i = 0; i < 2; i++) { 4147cda8ba9STakashi Iwai if (ucontrol->value.integer.value[i] != spec->vol[2 + i]) { 4156b8d6e55SJulian Scheel idx = WM_DAC_ATTEN_L + i; 4167cda8ba9STakashi Iwai spec->vol[2 + i] &= WM_VOL_MUTE; 4177cda8ba9STakashi Iwai spec->vol[2 + i] |= ucontrol->value.integer.value[i]; 4187cda8ba9STakashi Iwai wm_set_vol(ice, idx, spec->vol[2 + i], spec->master[i]); 4196b8d6e55SJulian Scheel change = 1; 4206b8d6e55SJulian Scheel } 4216b8d6e55SJulian Scheel } 4226b8d6e55SJulian Scheel mutex_unlock(&ice->gpio_mutex); 4236b8d6e55SJulian Scheel return change; 4246b8d6e55SJulian Scheel } 4256b8d6e55SJulian Scheel 4266b8d6e55SJulian Scheel 4276b8d6e55SJulian Scheel /* 4286b8d6e55SJulian Scheel * WM8766 DAC volume attenuation mixer control 4296b8d6e55SJulian Scheel */ 4307cda8ba9STakashi Iwai static int wm8766_vol_info(struct snd_kcontrol *kcontrol, 4317cda8ba9STakashi Iwai struct snd_ctl_elem_info *uinfo) 4326b8d6e55SJulian Scheel { 4336b8d6e55SJulian Scheel int voices = kcontrol->private_value >> 8; 4346b8d6e55SJulian Scheel uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 4356b8d6e55SJulian Scheel uinfo->count = voices; 4366b8d6e55SJulian Scheel uinfo->value.integer.min = 0; /* mute */ 4376b8d6e55SJulian Scheel uinfo->value.integer.max = DAC_RES; /* 0dB */ 4386b8d6e55SJulian Scheel return 0; 4396b8d6e55SJulian Scheel } 4406b8d6e55SJulian Scheel 4417cda8ba9STakashi Iwai static int wm8766_vol_get(struct snd_kcontrol *kcontrol, 4427cda8ba9STakashi Iwai struct snd_ctl_elem_value *ucontrol) 4436b8d6e55SJulian Scheel { 4446b8d6e55SJulian Scheel struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 4457cda8ba9STakashi Iwai struct prodigy_hifi_spec *spec = ice->spec; 4466b8d6e55SJulian Scheel int i, ofs, voices; 4476b8d6e55SJulian Scheel 4486b8d6e55SJulian Scheel voices = kcontrol->private_value >> 8; 4496b8d6e55SJulian Scheel ofs = kcontrol->private_value & 0xff; 4506b8d6e55SJulian Scheel for (i = 0; i < voices; i++) 4517cda8ba9STakashi Iwai ucontrol->value.integer.value[i] = spec->vol[ofs + i]; 4526b8d6e55SJulian Scheel return 0; 4536b8d6e55SJulian Scheel } 4546b8d6e55SJulian Scheel 4556b8d6e55SJulian Scheel static int wm8766_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 4566b8d6e55SJulian Scheel { 4576b8d6e55SJulian Scheel struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 4587cda8ba9STakashi Iwai struct prodigy_hifi_spec *spec = ice->spec; 4596b8d6e55SJulian Scheel int i, idx, ofs, voices; 4606b8d6e55SJulian Scheel int change = 0; 4616b8d6e55SJulian Scheel 4626b8d6e55SJulian Scheel voices = kcontrol->private_value >> 8; 4636b8d6e55SJulian Scheel ofs = kcontrol->private_value & 0xff; 4646b8d6e55SJulian Scheel mutex_lock(&ice->gpio_mutex); 4656b8d6e55SJulian Scheel for (i = 0; i < voices; i++) { 4667cda8ba9STakashi Iwai if (ucontrol->value.integer.value[i] != spec->vol[ofs + i]) { 4676b8d6e55SJulian Scheel idx = WM8766_LDA1 + ofs + i; 4687cda8ba9STakashi Iwai spec->vol[ofs + i] &= WM_VOL_MUTE; 4697cda8ba9STakashi Iwai spec->vol[ofs + i] |= ucontrol->value.integer.value[i]; 4706b8d6e55SJulian Scheel wm8766_set_vol(ice, idx, 4717cda8ba9STakashi Iwai spec->vol[ofs + i], spec->master[i]); 4726b8d6e55SJulian Scheel change = 1; 4736b8d6e55SJulian Scheel } 4746b8d6e55SJulian Scheel } 4756b8d6e55SJulian Scheel mutex_unlock(&ice->gpio_mutex); 4766b8d6e55SJulian Scheel return change; 4776b8d6e55SJulian Scheel } 4786b8d6e55SJulian Scheel 4796b8d6e55SJulian Scheel /* 4806b8d6e55SJulian Scheel * Master volume attenuation mixer control / applied to WM8776+WM8766 4816b8d6e55SJulian Scheel */ 4827cda8ba9STakashi Iwai static int wm_master_vol_info(struct snd_kcontrol *kcontrol, 4837cda8ba9STakashi Iwai struct snd_ctl_elem_info *uinfo) 4846b8d6e55SJulian Scheel { 4856b8d6e55SJulian Scheel uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 4866b8d6e55SJulian Scheel uinfo->count = 2; 4876b8d6e55SJulian Scheel uinfo->value.integer.min = 0; 4886b8d6e55SJulian Scheel uinfo->value.integer.max = DAC_RES; 4896b8d6e55SJulian Scheel return 0; 4906b8d6e55SJulian Scheel } 4916b8d6e55SJulian Scheel 4927cda8ba9STakashi Iwai static int wm_master_vol_get(struct snd_kcontrol *kcontrol, 4937cda8ba9STakashi Iwai struct snd_ctl_elem_value *ucontrol) 4946b8d6e55SJulian Scheel { 4956b8d6e55SJulian Scheel struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 4967cda8ba9STakashi Iwai struct prodigy_hifi_spec *spec = ice->spec; 4976b8d6e55SJulian Scheel int i; 4986b8d6e55SJulian Scheel for (i = 0; i < 2; i++) 4997cda8ba9STakashi Iwai ucontrol->value.integer.value[i] = spec->master[i]; 5006b8d6e55SJulian Scheel return 0; 5016b8d6e55SJulian Scheel } 5026b8d6e55SJulian Scheel 5037cda8ba9STakashi Iwai static int wm_master_vol_put(struct snd_kcontrol *kcontrol, 5047cda8ba9STakashi Iwai struct snd_ctl_elem_value *ucontrol) 5056b8d6e55SJulian Scheel { 5066b8d6e55SJulian Scheel struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 5077cda8ba9STakashi Iwai struct prodigy_hifi_spec *spec = ice->spec; 5086b8d6e55SJulian Scheel int ch, change = 0; 5096b8d6e55SJulian Scheel 5106b8d6e55SJulian Scheel mutex_lock(&ice->gpio_mutex); 5116b8d6e55SJulian Scheel for (ch = 0; ch < 2; ch++) { 5127cda8ba9STakashi Iwai if (ucontrol->value.integer.value[ch] != spec->master[ch]) { 5137cda8ba9STakashi Iwai spec->master[ch] = ucontrol->value.integer.value[ch]; 5146b8d6e55SJulian Scheel 5156b8d6e55SJulian Scheel /* Apply to front DAC */ 5166b8d6e55SJulian Scheel wm_set_vol(ice, WM_DAC_ATTEN_L + ch, 5177cda8ba9STakashi Iwai spec->vol[2 + ch], spec->master[ch]); 5186b8d6e55SJulian Scheel 5196b8d6e55SJulian Scheel wm8766_set_vol(ice, WM8766_LDA1 + ch, 5207cda8ba9STakashi Iwai spec->vol[0 + ch], spec->master[ch]); 5216b8d6e55SJulian Scheel 5226b8d6e55SJulian Scheel wm8766_set_vol(ice, WM8766_LDA2 + ch, 5237cda8ba9STakashi Iwai spec->vol[4 + ch], spec->master[ch]); 5246b8d6e55SJulian Scheel 5256b8d6e55SJulian Scheel wm8766_set_vol(ice, WM8766_LDA3 + ch, 5267cda8ba9STakashi Iwai spec->vol[6 + ch], spec->master[ch]); 5276b8d6e55SJulian Scheel change = 1; 5286b8d6e55SJulian Scheel } 5296b8d6e55SJulian Scheel } 5306b8d6e55SJulian Scheel mutex_unlock(&ice->gpio_mutex); 5316b8d6e55SJulian Scheel return change; 5326b8d6e55SJulian Scheel } 5336b8d6e55SJulian Scheel 5346b8d6e55SJulian Scheel 5356b8d6e55SJulian Scheel /* KONSTI */ 5366b8d6e55SJulian Scheel 5377cda8ba9STakashi Iwai static int wm_adc_mux_enum_info(struct snd_kcontrol *kcontrol, 5387cda8ba9STakashi Iwai struct snd_ctl_elem_info *uinfo) 5396b8d6e55SJulian Scheel { 5407cda8ba9STakashi Iwai static char* texts[32] = { 5417cda8ba9STakashi Iwai "NULL", WM_AIN1, WM_AIN2, WM_AIN1 "+" WM_AIN2, 5426b8d6e55SJulian Scheel WM_AIN3, WM_AIN1 "+" WM_AIN3, WM_AIN2 "+" WM_AIN3, 5436b8d6e55SJulian Scheel WM_AIN1 "+" WM_AIN2 "+" WM_AIN3, 5446b8d6e55SJulian Scheel WM_AIN4, WM_AIN1 "+" WM_AIN4, WM_AIN2 "+" WM_AIN4, 5456b8d6e55SJulian Scheel WM_AIN1 "+" WM_AIN2 "+" WM_AIN4, 5466b8d6e55SJulian Scheel WM_AIN3 "+" WM_AIN4, WM_AIN1 "+" WM_AIN3 "+" WM_AIN4, 5476b8d6e55SJulian Scheel WM_AIN2 "+" WM_AIN3 "+" WM_AIN4, 5486b8d6e55SJulian Scheel WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4, 5496b8d6e55SJulian Scheel WM_AIN5, WM_AIN1 "+" WM_AIN5, WM_AIN2 "+" WM_AIN5, 5506b8d6e55SJulian Scheel WM_AIN1 "+" WM_AIN2 "+" WM_AIN5, 5516b8d6e55SJulian Scheel WM_AIN3 "+" WM_AIN5, WM_AIN1 "+" WM_AIN3 "+" WM_AIN5, 5526b8d6e55SJulian Scheel WM_AIN2 "+" WM_AIN3 "+" WM_AIN5, 5536b8d6e55SJulian Scheel WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN5, 5546b8d6e55SJulian Scheel WM_AIN4 "+" WM_AIN5, WM_AIN1 "+" WM_AIN4 "+" WM_AIN5, 5556b8d6e55SJulian Scheel WM_AIN2 "+" WM_AIN4 "+" WM_AIN5, 5566b8d6e55SJulian Scheel WM_AIN1 "+" WM_AIN2 "+" WM_AIN4 "+" WM_AIN5, 5576b8d6e55SJulian Scheel WM_AIN3 "+" WM_AIN4 "+" WM_AIN5, 5586b8d6e55SJulian Scheel WM_AIN1 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5, 5596b8d6e55SJulian Scheel WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5, 5607cda8ba9STakashi Iwai WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5 5617cda8ba9STakashi Iwai }; 5626b8d6e55SJulian Scheel 5636b8d6e55SJulian Scheel uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; 5646b8d6e55SJulian Scheel uinfo->count = 1; 5656b8d6e55SJulian Scheel uinfo->value.enumerated.items = 32; 5666b8d6e55SJulian Scheel if (uinfo->value.enumerated.item > 31) 5676b8d6e55SJulian Scheel uinfo->value.enumerated.item = 31; 5687cda8ba9STakashi Iwai strcpy(uinfo->value.enumerated.name, 5697cda8ba9STakashi Iwai texts[uinfo->value.enumerated.item]); 5706b8d6e55SJulian Scheel return 0; 5716b8d6e55SJulian Scheel } 5726b8d6e55SJulian Scheel 5737cda8ba9STakashi Iwai static int wm_adc_mux_enum_get(struct snd_kcontrol *kcontrol, 5747cda8ba9STakashi Iwai struct snd_ctl_elem_value *ucontrol) 5756b8d6e55SJulian Scheel { 5766b8d6e55SJulian Scheel struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 5776b8d6e55SJulian Scheel 5786b8d6e55SJulian Scheel mutex_lock(&ice->gpio_mutex); 5796b8d6e55SJulian Scheel ucontrol->value.integer.value[0] = wm_get(ice, WM_ADC_MUX) & 0x1f; 5806b8d6e55SJulian Scheel mutex_unlock(&ice->gpio_mutex); 5816b8d6e55SJulian Scheel return 0; 5826b8d6e55SJulian Scheel } 5836b8d6e55SJulian Scheel 5847cda8ba9STakashi Iwai static int wm_adc_mux_enum_put(struct snd_kcontrol *kcontrol, 5857cda8ba9STakashi Iwai struct snd_ctl_elem_value *ucontrol) 5866b8d6e55SJulian Scheel { 5876b8d6e55SJulian Scheel struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 5886b8d6e55SJulian Scheel unsigned short oval, nval; 5897cda8ba9STakashi Iwai int change = 0; 5906b8d6e55SJulian Scheel 5916b8d6e55SJulian Scheel mutex_lock(&ice->gpio_mutex); 5926b8d6e55SJulian Scheel oval = wm_get(ice, WM_ADC_MUX); 5936b8d6e55SJulian Scheel nval = (oval & 0xe0) | ucontrol->value.integer.value[0]; 5946b8d6e55SJulian Scheel if (nval != oval) { 5956b8d6e55SJulian Scheel wm_put(ice, WM_ADC_MUX, nval); 5967cda8ba9STakashi Iwai change = 1; 5976b8d6e55SJulian Scheel } 5986b8d6e55SJulian Scheel mutex_unlock(&ice->gpio_mutex); 5997cda8ba9STakashi Iwai return change; 6006b8d6e55SJulian Scheel } 6016b8d6e55SJulian Scheel 6026b8d6e55SJulian Scheel /* KONSTI */ 6036b8d6e55SJulian Scheel 6046b8d6e55SJulian Scheel /* 6056b8d6e55SJulian Scheel * ADC gain mixer control (-64dB to 0dB) 6066b8d6e55SJulian Scheel */ 6076b8d6e55SJulian Scheel 6086b8d6e55SJulian Scheel #define ADC_0dB 0xcf 6096b8d6e55SJulian Scheel #define ADC_RES 128 6106b8d6e55SJulian Scheel #define ADC_MIN (ADC_0dB - ADC_RES) 6116b8d6e55SJulian Scheel 6127cda8ba9STakashi Iwai static int wm_adc_vol_info(struct snd_kcontrol *kcontrol, 6137cda8ba9STakashi Iwai struct snd_ctl_elem_info *uinfo) 6146b8d6e55SJulian Scheel { 6156b8d6e55SJulian Scheel uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 6166b8d6e55SJulian Scheel uinfo->count = 2; 6176b8d6e55SJulian Scheel uinfo->value.integer.min = 0; /* mute (-64dB) */ 6186b8d6e55SJulian Scheel uinfo->value.integer.max = ADC_RES; /* 0dB, 0.5dB step */ 6196b8d6e55SJulian Scheel return 0; 6206b8d6e55SJulian Scheel } 6216b8d6e55SJulian Scheel 6227cda8ba9STakashi Iwai static int wm_adc_vol_get(struct snd_kcontrol *kcontrol, 6237cda8ba9STakashi Iwai struct snd_ctl_elem_value *ucontrol) 6246b8d6e55SJulian Scheel { 6256b8d6e55SJulian Scheel struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 6266b8d6e55SJulian Scheel unsigned short val; 6276b8d6e55SJulian Scheel int i; 6286b8d6e55SJulian Scheel 6296b8d6e55SJulian Scheel mutex_lock(&ice->gpio_mutex); 6306b8d6e55SJulian Scheel for (i = 0; i < 2; i++) { 6316b8d6e55SJulian Scheel val = wm_get(ice, WM_ADC_ATTEN_L + i) & 0xff; 6326b8d6e55SJulian Scheel val = val > ADC_MIN ? (val - ADC_MIN) : 0; 6336b8d6e55SJulian Scheel ucontrol->value.integer.value[i] = val; 6346b8d6e55SJulian Scheel } 6356b8d6e55SJulian Scheel mutex_unlock(&ice->gpio_mutex); 6366b8d6e55SJulian Scheel return 0; 6376b8d6e55SJulian Scheel } 6386b8d6e55SJulian Scheel 6397cda8ba9STakashi Iwai static int wm_adc_vol_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 unsigned short ovol, nvol; 6446b8d6e55SJulian Scheel int i, idx, change = 0; 6456b8d6e55SJulian Scheel 6466b8d6e55SJulian Scheel mutex_lock(&ice->gpio_mutex); 6476b8d6e55SJulian Scheel for (i = 0; i < 2; i++) { 6486b8d6e55SJulian Scheel nvol = ucontrol->value.integer.value[i]; 6496b8d6e55SJulian Scheel nvol = nvol ? (nvol + ADC_MIN) : 0; 6506b8d6e55SJulian Scheel idx = WM_ADC_ATTEN_L + i; 6516b8d6e55SJulian Scheel ovol = wm_get(ice, idx) & 0xff; 6526b8d6e55SJulian Scheel if (ovol != nvol) { 6536b8d6e55SJulian Scheel wm_put(ice, idx, nvol); 6546b8d6e55SJulian Scheel change = 1; 6556b8d6e55SJulian Scheel } 6566b8d6e55SJulian Scheel } 6576b8d6e55SJulian Scheel mutex_unlock(&ice->gpio_mutex); 6586b8d6e55SJulian Scheel return change; 6596b8d6e55SJulian Scheel } 6606b8d6e55SJulian Scheel 6616b8d6e55SJulian Scheel /* 6626b8d6e55SJulian Scheel * ADC input mux mixer control 6636b8d6e55SJulian Scheel */ 6647cda8ba9STakashi Iwai #define wm_adc_mux_info snd_ctl_boolean_mono_info 6656b8d6e55SJulian Scheel 6667cda8ba9STakashi Iwai static int wm_adc_mux_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 int bit = kcontrol->private_value; 6716b8d6e55SJulian Scheel 6726b8d6e55SJulian Scheel mutex_lock(&ice->gpio_mutex); 6737cda8ba9STakashi Iwai ucontrol->value.integer.value[0] = 6747cda8ba9STakashi Iwai (wm_get(ice, WM_ADC_MUX) & (1 << bit)) ? 1 : 0; 6756b8d6e55SJulian Scheel mutex_unlock(&ice->gpio_mutex); 6766b8d6e55SJulian Scheel return 0; 6776b8d6e55SJulian Scheel } 6786b8d6e55SJulian Scheel 6797cda8ba9STakashi Iwai static int wm_adc_mux_put(struct snd_kcontrol *kcontrol, 6807cda8ba9STakashi Iwai struct snd_ctl_elem_value *ucontrol) 6816b8d6e55SJulian Scheel { 6826b8d6e55SJulian Scheel struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 6836b8d6e55SJulian Scheel int bit = kcontrol->private_value; 6846b8d6e55SJulian Scheel unsigned short oval, nval; 6856b8d6e55SJulian Scheel int change; 6866b8d6e55SJulian Scheel 6876b8d6e55SJulian Scheel mutex_lock(&ice->gpio_mutex); 6886b8d6e55SJulian Scheel nval = oval = wm_get(ice, WM_ADC_MUX); 6896b8d6e55SJulian Scheel if (ucontrol->value.integer.value[0]) 6906b8d6e55SJulian Scheel nval |= (1 << bit); 6916b8d6e55SJulian Scheel else 6926b8d6e55SJulian Scheel nval &= ~(1 << bit); 6936b8d6e55SJulian Scheel change = nval != oval; 6946b8d6e55SJulian Scheel if (change) { 6956b8d6e55SJulian Scheel wm_put(ice, WM_ADC_MUX, nval); 6966b8d6e55SJulian Scheel } 6976b8d6e55SJulian Scheel mutex_unlock(&ice->gpio_mutex); 6986b8d6e55SJulian Scheel return 0; 6996b8d6e55SJulian Scheel } 7006b8d6e55SJulian Scheel 7016b8d6e55SJulian Scheel /* 7026b8d6e55SJulian Scheel * Analog bypass (In -> Out) 7036b8d6e55SJulian Scheel */ 7047cda8ba9STakashi Iwai #define wm_bypass_info snd_ctl_boolean_mono_info 7056b8d6e55SJulian Scheel 7067cda8ba9STakashi Iwai static int wm_bypass_get(struct snd_kcontrol *kcontrol, 7077cda8ba9STakashi Iwai struct snd_ctl_elem_value *ucontrol) 7086b8d6e55SJulian Scheel { 7096b8d6e55SJulian Scheel struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 7106b8d6e55SJulian Scheel 7116b8d6e55SJulian Scheel mutex_lock(&ice->gpio_mutex); 7127cda8ba9STakashi Iwai ucontrol->value.integer.value[0] = 7137cda8ba9STakashi Iwai (wm_get(ice, WM_OUT_MUX) & 0x04) ? 1 : 0; 7146b8d6e55SJulian Scheel mutex_unlock(&ice->gpio_mutex); 7156b8d6e55SJulian Scheel return 0; 7166b8d6e55SJulian Scheel } 7176b8d6e55SJulian Scheel 7187cda8ba9STakashi Iwai static int wm_bypass_put(struct snd_kcontrol *kcontrol, 7197cda8ba9STakashi Iwai struct snd_ctl_elem_value *ucontrol) 7206b8d6e55SJulian Scheel { 7216b8d6e55SJulian Scheel struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 7226b8d6e55SJulian Scheel unsigned short val, oval; 7236b8d6e55SJulian Scheel int change = 0; 7246b8d6e55SJulian Scheel 7256b8d6e55SJulian Scheel mutex_lock(&ice->gpio_mutex); 7266b8d6e55SJulian Scheel val = oval = wm_get(ice, WM_OUT_MUX); 7276b8d6e55SJulian Scheel if (ucontrol->value.integer.value[0]) 7286b8d6e55SJulian Scheel val |= 0x04; 7296b8d6e55SJulian Scheel else 7306b8d6e55SJulian Scheel val &= ~0x04; 7316b8d6e55SJulian Scheel if (val != oval) { 7326b8d6e55SJulian Scheel wm_put(ice, WM_OUT_MUX, 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 * Left/Right swap 7416b8d6e55SJulian Scheel */ 7427cda8ba9STakashi Iwai #define wm_chswap_info snd_ctl_boolean_mono_info 7436b8d6e55SJulian Scheel 7447cda8ba9STakashi Iwai static int wm_chswap_get(struct snd_kcontrol *kcontrol, 7457cda8ba9STakashi Iwai struct snd_ctl_elem_value *ucontrol) 7466b8d6e55SJulian Scheel { 7476b8d6e55SJulian Scheel struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 7486b8d6e55SJulian Scheel 7496b8d6e55SJulian Scheel mutex_lock(&ice->gpio_mutex); 7506b8d6e55SJulian Scheel ucontrol->value.integer.value[0] = 7516b8d6e55SJulian Scheel (wm_get(ice, WM_DAC_CTRL1) & 0xf0) != 0x90; 7526b8d6e55SJulian Scheel mutex_unlock(&ice->gpio_mutex); 7536b8d6e55SJulian Scheel return 0; 7546b8d6e55SJulian Scheel } 7556b8d6e55SJulian Scheel 7567cda8ba9STakashi Iwai static int wm_chswap_put(struct snd_kcontrol *kcontrol, 7577cda8ba9STakashi Iwai struct snd_ctl_elem_value *ucontrol) 7586b8d6e55SJulian Scheel { 7596b8d6e55SJulian Scheel struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 7606b8d6e55SJulian Scheel unsigned short val, oval; 7616b8d6e55SJulian Scheel int change = 0; 7626b8d6e55SJulian Scheel 7636b8d6e55SJulian Scheel mutex_lock(&ice->gpio_mutex); 7646b8d6e55SJulian Scheel oval = wm_get(ice, WM_DAC_CTRL1); 7656b8d6e55SJulian Scheel val = oval & 0x0f; 7666b8d6e55SJulian Scheel if (ucontrol->value.integer.value[0]) 7676b8d6e55SJulian Scheel val |= 0x60; 7686b8d6e55SJulian Scheel else 7696b8d6e55SJulian Scheel val |= 0x90; 7706b8d6e55SJulian Scheel if (val != oval) { 7716b8d6e55SJulian Scheel wm_put(ice, WM_DAC_CTRL1, val); 7726b8d6e55SJulian Scheel wm_put_nocache(ice, WM_DAC_CTRL1, val); 7736b8d6e55SJulian Scheel change = 1; 7746b8d6e55SJulian Scheel } 7756b8d6e55SJulian Scheel mutex_unlock(&ice->gpio_mutex); 7766b8d6e55SJulian Scheel return change; 7776b8d6e55SJulian Scheel } 7786b8d6e55SJulian Scheel 7796b8d6e55SJulian Scheel 7806b8d6e55SJulian Scheel /* 7816b8d6e55SJulian Scheel * mixers 7826b8d6e55SJulian Scheel */ 7836b8d6e55SJulian Scheel 7846b8d6e55SJulian Scheel static struct snd_kcontrol_new prodigy_hifi_controls[] __devinitdata = { 7856b8d6e55SJulian Scheel { 7866b8d6e55SJulian Scheel .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 7876b8d6e55SJulian Scheel .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 7886b8d6e55SJulian Scheel SNDRV_CTL_ELEM_ACCESS_TLV_READ), 7896b8d6e55SJulian Scheel .name = "Master Playback Volume", 7906b8d6e55SJulian Scheel .info = wm_master_vol_info, 7916b8d6e55SJulian Scheel .get = wm_master_vol_get, 7926b8d6e55SJulian Scheel .put = wm_master_vol_put, 7936b8d6e55SJulian Scheel .tlv = { .p = db_scale_wm_dac } 7946b8d6e55SJulian Scheel }, 7956b8d6e55SJulian Scheel { 7966b8d6e55SJulian Scheel .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 7976b8d6e55SJulian Scheel .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 7986b8d6e55SJulian Scheel SNDRV_CTL_ELEM_ACCESS_TLV_READ), 7996b8d6e55SJulian Scheel .name = "Front Playback Volume", 8006b8d6e55SJulian Scheel .info = wm_dac_vol_info, 8016b8d6e55SJulian Scheel .get = wm_dac_vol_get, 8026b8d6e55SJulian Scheel .put = wm_dac_vol_put, 8036b8d6e55SJulian Scheel .tlv = { .p = db_scale_wm_dac }, 8046b8d6e55SJulian Scheel }, 8056b8d6e55SJulian Scheel { 8066b8d6e55SJulian Scheel .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8076b8d6e55SJulian Scheel .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 8086b8d6e55SJulian Scheel SNDRV_CTL_ELEM_ACCESS_TLV_READ), 8096b8d6e55SJulian Scheel .name = "Rear Playback Volume", 8106b8d6e55SJulian Scheel .info = wm8766_vol_info, 8116b8d6e55SJulian Scheel .get = wm8766_vol_get, 8126b8d6e55SJulian Scheel .put = wm8766_vol_put, 8136b8d6e55SJulian Scheel .private_value = (2 << 8) | 0, 8146b8d6e55SJulian Scheel .tlv = { .p = db_scale_wm_dac }, 8156b8d6e55SJulian Scheel }, 8166b8d6e55SJulian Scheel { 8176b8d6e55SJulian Scheel .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8186b8d6e55SJulian Scheel .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 8196b8d6e55SJulian Scheel SNDRV_CTL_ELEM_ACCESS_TLV_READ), 8206b8d6e55SJulian Scheel .name = "Center Playback Volume", 8216b8d6e55SJulian Scheel .info = wm8766_vol_info, 8226b8d6e55SJulian Scheel .get = wm8766_vol_get, 8236b8d6e55SJulian Scheel .put = wm8766_vol_put, 8246b8d6e55SJulian Scheel .private_value = (1 << 8) | 4, 8256b8d6e55SJulian Scheel .tlv = { .p = db_scale_wm_dac } 8266b8d6e55SJulian Scheel }, 8276b8d6e55SJulian Scheel { 8286b8d6e55SJulian Scheel .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8296b8d6e55SJulian Scheel .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 8306b8d6e55SJulian Scheel SNDRV_CTL_ELEM_ACCESS_TLV_READ), 8316b8d6e55SJulian Scheel .name = "LFE Playback Volume", 8326b8d6e55SJulian Scheel .info = wm8766_vol_info, 8336b8d6e55SJulian Scheel .get = wm8766_vol_get, 8346b8d6e55SJulian Scheel .put = wm8766_vol_put, 8356b8d6e55SJulian Scheel .private_value = (1 << 8) | 5, 8366b8d6e55SJulian Scheel .tlv = { .p = db_scale_wm_dac } 8376b8d6e55SJulian Scheel }, 8386b8d6e55SJulian Scheel { 8396b8d6e55SJulian Scheel .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8406b8d6e55SJulian Scheel .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 8416b8d6e55SJulian Scheel SNDRV_CTL_ELEM_ACCESS_TLV_READ), 8426b8d6e55SJulian Scheel .name = "Side Playback Volume", 8436b8d6e55SJulian Scheel .info = wm8766_vol_info, 8446b8d6e55SJulian Scheel .get = wm8766_vol_get, 8456b8d6e55SJulian Scheel .put = wm8766_vol_put, 8466b8d6e55SJulian Scheel .private_value = (2 << 8) | 6, 8476b8d6e55SJulian Scheel .tlv = { .p = db_scale_wm_dac }, 8486b8d6e55SJulian Scheel }, 8496b8d6e55SJulian Scheel { 8506b8d6e55SJulian Scheel .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8516b8d6e55SJulian Scheel .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 8526b8d6e55SJulian Scheel SNDRV_CTL_ELEM_ACCESS_TLV_READ), 8536b8d6e55SJulian Scheel .name = "Capture Volume", 8546b8d6e55SJulian Scheel .info = wm_adc_vol_info, 8556b8d6e55SJulian Scheel .get = wm_adc_vol_get, 8566b8d6e55SJulian Scheel .put = wm_adc_vol_put, 8576b8d6e55SJulian Scheel .tlv = { .p = db_scale_wm_dac }, 8586b8d6e55SJulian Scheel }, 8596b8d6e55SJulian Scheel { 8606b8d6e55SJulian Scheel .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8616b8d6e55SJulian Scheel .name = "CD Capture Switch", 8626b8d6e55SJulian Scheel .info = wm_adc_mux_info, 8636b8d6e55SJulian Scheel .get = wm_adc_mux_get, 8646b8d6e55SJulian Scheel .put = wm_adc_mux_put, 8656b8d6e55SJulian Scheel .private_value = 0, 8666b8d6e55SJulian Scheel }, 8676b8d6e55SJulian Scheel { 8686b8d6e55SJulian Scheel .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8696b8d6e55SJulian Scheel .name = "Line Capture Switch", 8706b8d6e55SJulian Scheel .info = wm_adc_mux_info, 8716b8d6e55SJulian Scheel .get = wm_adc_mux_get, 8726b8d6e55SJulian Scheel .put = wm_adc_mux_put, 8736b8d6e55SJulian Scheel .private_value = 1, 8746b8d6e55SJulian Scheel }, 8756b8d6e55SJulian Scheel { 8766b8d6e55SJulian Scheel .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8776b8d6e55SJulian Scheel .name = "Analog Bypass Switch", 8786b8d6e55SJulian Scheel .info = wm_bypass_info, 8796b8d6e55SJulian Scheel .get = wm_bypass_get, 8806b8d6e55SJulian Scheel .put = wm_bypass_put, 8816b8d6e55SJulian Scheel }, 8826b8d6e55SJulian Scheel { 8836b8d6e55SJulian Scheel .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8846b8d6e55SJulian Scheel .name = "Swap Output Channels", 8856b8d6e55SJulian Scheel .info = wm_chswap_info, 8866b8d6e55SJulian Scheel .get = wm_chswap_get, 8876b8d6e55SJulian Scheel .put = wm_chswap_put, 8886b8d6e55SJulian Scheel }, 8896b8d6e55SJulian Scheel { 8906b8d6e55SJulian Scheel .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8916b8d6e55SJulian Scheel .name = "Analog Capture Source", 8926b8d6e55SJulian Scheel .info = wm_adc_mux_enum_info, 8936b8d6e55SJulian Scheel .get = wm_adc_mux_enum_get, 8946b8d6e55SJulian Scheel .put = wm_adc_mux_enum_put, 8956b8d6e55SJulian Scheel }, 8966b8d6e55SJulian Scheel }; 8976b8d6e55SJulian Scheel 8986b8d6e55SJulian Scheel /* 8996b8d6e55SJulian Scheel * WM codec registers 9006b8d6e55SJulian Scheel */ 9017cda8ba9STakashi Iwai static void wm_proc_regs_write(struct snd_info_entry *entry, 9027cda8ba9STakashi Iwai struct snd_info_buffer *buffer) 9036b8d6e55SJulian Scheel { 9047cda8ba9STakashi Iwai struct snd_ice1712 *ice = entry->private_data; 9056b8d6e55SJulian Scheel char line[64]; 9066b8d6e55SJulian Scheel unsigned int reg, val; 9076b8d6e55SJulian Scheel mutex_lock(&ice->gpio_mutex); 9086b8d6e55SJulian Scheel while (!snd_info_get_line(buffer, line, sizeof(line))) { 9096b8d6e55SJulian Scheel if (sscanf(line, "%x %x", ®, &val) != 2) 9106b8d6e55SJulian Scheel continue; 9116b8d6e55SJulian Scheel if (reg <= 0x17 && val <= 0xffff) 9126b8d6e55SJulian Scheel wm_put(ice, reg, val); 9136b8d6e55SJulian Scheel } 9146b8d6e55SJulian Scheel mutex_unlock(&ice->gpio_mutex); 9156b8d6e55SJulian Scheel } 9166b8d6e55SJulian Scheel 9177cda8ba9STakashi Iwai static void wm_proc_regs_read(struct snd_info_entry *entry, 9187cda8ba9STakashi Iwai struct snd_info_buffer *buffer) 9196b8d6e55SJulian Scheel { 9207cda8ba9STakashi Iwai struct snd_ice1712 *ice = entry->private_data; 9216b8d6e55SJulian Scheel int reg, val; 9226b8d6e55SJulian Scheel 9236b8d6e55SJulian Scheel mutex_lock(&ice->gpio_mutex); 9246b8d6e55SJulian Scheel for (reg = 0; reg <= 0x17; reg++) { 9256b8d6e55SJulian Scheel val = wm_get(ice, reg); 9266b8d6e55SJulian Scheel snd_iprintf(buffer, "%02x = %04x\n", reg, val); 9276b8d6e55SJulian Scheel } 9286b8d6e55SJulian Scheel mutex_unlock(&ice->gpio_mutex); 9296b8d6e55SJulian Scheel } 9306b8d6e55SJulian Scheel 9316b8d6e55SJulian Scheel static void wm_proc_init(struct snd_ice1712 *ice) 9326b8d6e55SJulian Scheel { 9336b8d6e55SJulian Scheel struct snd_info_entry *entry; 9346b8d6e55SJulian Scheel if (!snd_card_proc_new(ice->card, "wm_codec", &entry)) { 9356b8d6e55SJulian Scheel snd_info_set_text_ops(entry, ice, wm_proc_regs_read); 9366b8d6e55SJulian Scheel entry->mode |= S_IWUSR; 9376b8d6e55SJulian Scheel entry->c.text.write = wm_proc_regs_write; 9386b8d6e55SJulian Scheel } 9396b8d6e55SJulian Scheel } 9406b8d6e55SJulian Scheel 9416b8d6e55SJulian Scheel static int __devinit prodigy_hifi_add_controls(struct snd_ice1712 *ice) 9426b8d6e55SJulian Scheel { 9436b8d6e55SJulian Scheel unsigned int i; 9446b8d6e55SJulian Scheel int err; 9456b8d6e55SJulian Scheel 9466b8d6e55SJulian Scheel for (i = 0; i < ARRAY_SIZE(prodigy_hifi_controls); i++) { 9477cda8ba9STakashi Iwai err = snd_ctl_add(ice->card, 9487cda8ba9STakashi Iwai snd_ctl_new1(&prodigy_hifi_controls[i], ice)); 9496b8d6e55SJulian Scheel if (err < 0) 9506b8d6e55SJulian Scheel return err; 9516b8d6e55SJulian Scheel } 9526b8d6e55SJulian Scheel 9536b8d6e55SJulian Scheel wm_proc_init(ice); 9546b8d6e55SJulian Scheel 9556b8d6e55SJulian Scheel return 0; 9566b8d6e55SJulian Scheel } 9576b8d6e55SJulian Scheel 9586b8d6e55SJulian Scheel static int __devinit prodigy_hd2_add_controls(struct snd_ice1712 *ice) 9596b8d6e55SJulian Scheel { 9606b8d6e55SJulian Scheel unsigned int i; 9616b8d6e55SJulian Scheel int err; 9626b8d6e55SJulian Scheel 9636b8d6e55SJulian Scheel for (i = 0; i < ARRAY_SIZE(prodigy_hd2_controls); i++) { 9647cda8ba9STakashi Iwai err = snd_ctl_add(ice->card, 9657cda8ba9STakashi Iwai snd_ctl_new1(&prodigy_hd2_controls[i], ice)); 9666b8d6e55SJulian Scheel if (err < 0) 9676b8d6e55SJulian Scheel return err; 9686b8d6e55SJulian Scheel } 9696b8d6e55SJulian Scheel 9706b8d6e55SJulian Scheel wm_proc_init(ice); 9716b8d6e55SJulian Scheel 9726b8d6e55SJulian Scheel return 0; 9736b8d6e55SJulian Scheel } 9746b8d6e55SJulian Scheel 9756b8d6e55SJulian Scheel 9766b8d6e55SJulian Scheel /* 9776b8d6e55SJulian Scheel * initialize the chip 9786b8d6e55SJulian Scheel */ 9796b8d6e55SJulian Scheel static int __devinit prodigy_hifi_init(struct snd_ice1712 *ice) 9806b8d6e55SJulian Scheel { 9816b8d6e55SJulian Scheel static unsigned short wm_inits[] = { 9826b8d6e55SJulian Scheel /* These come first to reduce init pop noise */ 9836b8d6e55SJulian Scheel WM_ADC_MUX, 0x0003, /* ADC mute */ 9846b8d6e55SJulian Scheel /* 0x00c0 replaced by 0x0003 */ 9856b8d6e55SJulian Scheel 9866b8d6e55SJulian Scheel WM_DAC_MUTE, 0x0001, /* DAC softmute */ 9876b8d6e55SJulian Scheel WM_DAC_CTRL1, 0x0000, /* DAC mute */ 9886b8d6e55SJulian Scheel 9896b8d6e55SJulian Scheel WM_POWERDOWN, 0x0008, /* All power-up except HP */ 9906b8d6e55SJulian Scheel WM_RESET, 0x0000, /* reset */ 9916b8d6e55SJulian Scheel }; 9926b8d6e55SJulian Scheel static unsigned short wm_inits2[] = { 9936b8d6e55SJulian Scheel WM_MASTER_CTRL, 0x0022, /* 256fs, slave mode */ 9946b8d6e55SJulian Scheel WM_DAC_INT, 0x0022, /* I2S, normal polarity, 24bit */ 9956b8d6e55SJulian Scheel WM_ADC_INT, 0x0022, /* I2S, normal polarity, 24bit */ 9966b8d6e55SJulian Scheel WM_DAC_CTRL1, 0x0090, /* DAC L/R */ 9976b8d6e55SJulian Scheel WM_OUT_MUX, 0x0001, /* OUT DAC */ 9986b8d6e55SJulian Scheel WM_HP_ATTEN_L, 0x0179, /* HP 0dB */ 9996b8d6e55SJulian Scheel WM_HP_ATTEN_R, 0x0179, /* HP 0dB */ 10006b8d6e55SJulian Scheel WM_DAC_ATTEN_L, 0x0000, /* DAC 0dB */ 10016b8d6e55SJulian Scheel WM_DAC_ATTEN_L, 0x0100, /* DAC 0dB */ 10026b8d6e55SJulian Scheel WM_DAC_ATTEN_R, 0x0000, /* DAC 0dB */ 10036b8d6e55SJulian Scheel WM_DAC_ATTEN_R, 0x0100, /* DAC 0dB */ 10046b8d6e55SJulian Scheel WM_PHASE_SWAP, 0x0000, /* phase normal */ 10056b8d6e55SJulian Scheel #if 0 10066b8d6e55SJulian Scheel WM_DAC_MASTER, 0x0100, /* DAC master muted */ 10076b8d6e55SJulian Scheel #endif 10086b8d6e55SJulian Scheel WM_DAC_CTRL2, 0x0000, /* no deemphasis, no ZFLG */ 10096b8d6e55SJulian Scheel WM_ADC_ATTEN_L, 0x0000, /* ADC muted */ 10106b8d6e55SJulian Scheel WM_ADC_ATTEN_R, 0x0000, /* ADC muted */ 10116b8d6e55SJulian Scheel #if 1 10126b8d6e55SJulian Scheel WM_ALC_CTRL1, 0x007b, /* */ 10136b8d6e55SJulian Scheel WM_ALC_CTRL2, 0x0000, /* */ 10146b8d6e55SJulian Scheel WM_ALC_CTRL3, 0x0000, /* */ 10156b8d6e55SJulian Scheel WM_NOISE_GATE, 0x0000, /* */ 10166b8d6e55SJulian Scheel #endif 10176b8d6e55SJulian Scheel WM_DAC_MUTE, 0x0000, /* DAC unmute */ 10186b8d6e55SJulian Scheel WM_ADC_MUX, 0x0003, /* ADC unmute, both CD/Line On */ 10196b8d6e55SJulian Scheel }; 10206b8d6e55SJulian Scheel static unsigned short wm8766_inits[] = { 10216b8d6e55SJulian Scheel WM8766_RESET, 0x0000, 10226b8d6e55SJulian Scheel WM8766_DAC_CTRL, 0x0120, 10236b8d6e55SJulian Scheel WM8766_INT_CTRL, 0x0022, /* I2S Normal Mode, 24 bit */ 10246b8d6e55SJulian Scheel WM8766_DAC_CTRL2, 0x0001, 10256b8d6e55SJulian Scheel WM8766_DAC_CTRL3, 0x0080, 10266b8d6e55SJulian Scheel WM8766_LDA1, 0x0100, 10276b8d6e55SJulian Scheel WM8766_LDA2, 0x0100, 10286b8d6e55SJulian Scheel WM8766_LDA3, 0x0100, 10296b8d6e55SJulian Scheel WM8766_RDA1, 0x0100, 10306b8d6e55SJulian Scheel WM8766_RDA2, 0x0100, 10316b8d6e55SJulian Scheel WM8766_RDA3, 0x0100, 10326b8d6e55SJulian Scheel WM8766_MUTE1, 0x0000, 10336b8d6e55SJulian Scheel WM8766_MUTE2, 0x0000, 10346b8d6e55SJulian Scheel }; 10356b8d6e55SJulian Scheel 10367cda8ba9STakashi Iwai struct prodigy_hifi_spec *spec; 10376b8d6e55SJulian Scheel unsigned int i; 10386b8d6e55SJulian Scheel 10396b8d6e55SJulian Scheel ice->vt1720 = 0; 10406b8d6e55SJulian Scheel ice->vt1724 = 1; 10416b8d6e55SJulian Scheel 10426b8d6e55SJulian Scheel ice->num_total_dacs = 8; 10436b8d6e55SJulian Scheel ice->num_total_adcs = 1; 10446b8d6e55SJulian Scheel 10456b8d6e55SJulian Scheel /* HACK - use this as the SPDIF source. 10466b8d6e55SJulian Scheel * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten 10476b8d6e55SJulian Scheel */ 10486b8d6e55SJulian Scheel ice->gpio.saved[0] = 0; 104925985edcSLucas De Marchi /* to remember the register values */ 10506b8d6e55SJulian Scheel 10516b8d6e55SJulian Scheel ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); 10526b8d6e55SJulian Scheel if (! ice->akm) 10536b8d6e55SJulian Scheel return -ENOMEM; 10546b8d6e55SJulian Scheel ice->akm_codecs = 1; 10556b8d6e55SJulian Scheel 10567cda8ba9STakashi Iwai spec = kzalloc(sizeof(*spec), GFP_KERNEL); 10577cda8ba9STakashi Iwai if (!spec) 10587cda8ba9STakashi Iwai return -ENOMEM; 10597cda8ba9STakashi Iwai ice->spec = spec; 10607cda8ba9STakashi Iwai 10616b8d6e55SJulian Scheel /* initialize WM8776 codec */ 10626b8d6e55SJulian Scheel for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2) 10636b8d6e55SJulian Scheel wm_put(ice, wm_inits[i], wm_inits[i+1]); 10646b8d6e55SJulian Scheel schedule_timeout_uninterruptible(1); 10656b8d6e55SJulian Scheel for (i = 0; i < ARRAY_SIZE(wm_inits2); i += 2) 10666b8d6e55SJulian Scheel wm_put(ice, wm_inits2[i], wm_inits2[i+1]); 10676b8d6e55SJulian Scheel 10686b8d6e55SJulian Scheel /* initialize WM8766 codec */ 10696b8d6e55SJulian Scheel for (i = 0; i < ARRAY_SIZE(wm8766_inits); i += 2) 10706b8d6e55SJulian Scheel wm8766_spi_write(ice, wm8766_inits[i], wm8766_inits[i+1]); 10716b8d6e55SJulian Scheel 10726b8d6e55SJulian Scheel 10736b8d6e55SJulian Scheel return 0; 10746b8d6e55SJulian Scheel } 10756b8d6e55SJulian Scheel 10766b8d6e55SJulian Scheel 10776b8d6e55SJulian Scheel /* 10786b8d6e55SJulian Scheel * initialize the chip 10796b8d6e55SJulian Scheel */ 1080b40e9538SIgor Chernyshev static void ak4396_init(struct snd_ice1712 *ice) 10816b8d6e55SJulian Scheel { 10826b8d6e55SJulian Scheel static unsigned short ak4396_inits[] = { 10836b8d6e55SJulian Scheel AK4396_CTRL1, 0x87, /* I2S Normal Mode, 24 bit */ 10846b8d6e55SJulian Scheel AK4396_CTRL2, 0x02, 10856b8d6e55SJulian Scheel AK4396_CTRL3, 0x00, 10866b8d6e55SJulian Scheel AK4396_LCH_ATT, 0x00, 10876b8d6e55SJulian Scheel AK4396_RCH_ATT, 0x00, 10886b8d6e55SJulian Scheel }; 10896b8d6e55SJulian Scheel 10906b8d6e55SJulian Scheel unsigned int i; 10916b8d6e55SJulian Scheel 1092b40e9538SIgor Chernyshev /* initialize ak4396 codec */ 1093b40e9538SIgor Chernyshev /* reset codec */ 1094b40e9538SIgor Chernyshev ak4396_write(ice, AK4396_CTRL1, 0x86); 1095b40e9538SIgor Chernyshev msleep(100); 1096b40e9538SIgor Chernyshev ak4396_write(ice, AK4396_CTRL1, 0x87); 1097b40e9538SIgor Chernyshev 1098b40e9538SIgor Chernyshev for (i = 0; i < ARRAY_SIZE(ak4396_inits); i += 2) 1099b40e9538SIgor Chernyshev ak4396_write(ice, ak4396_inits[i], ak4396_inits[i+1]); 1100b40e9538SIgor Chernyshev } 1101b40e9538SIgor Chernyshev 1102*c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP 11035e08fe57STakashi Iwai static int prodigy_hd2_resume(struct snd_ice1712 *ice) 1104b40e9538SIgor Chernyshev { 1105b40e9538SIgor Chernyshev /* initialize ak4396 codec and restore previous mixer volumes */ 1106b40e9538SIgor Chernyshev struct prodigy_hifi_spec *spec = ice->spec; 1107b40e9538SIgor Chernyshev int i; 1108b40e9538SIgor Chernyshev mutex_lock(&ice->gpio_mutex); 1109b40e9538SIgor Chernyshev ak4396_init(ice); 1110b40e9538SIgor Chernyshev for (i = 0; i < 2; i++) 1111b40e9538SIgor Chernyshev ak4396_write(ice, AK4396_LCH_ATT + i, spec->vol[i] & 0xff); 1112b40e9538SIgor Chernyshev mutex_unlock(&ice->gpio_mutex); 1113b40e9538SIgor Chernyshev return 0; 1114b40e9538SIgor Chernyshev } 1115b40e9538SIgor Chernyshev #endif 1116b40e9538SIgor Chernyshev 1117b40e9538SIgor Chernyshev static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice) 1118b40e9538SIgor Chernyshev { 1119b40e9538SIgor Chernyshev struct prodigy_hifi_spec *spec; 1120b40e9538SIgor Chernyshev 11216b8d6e55SJulian Scheel ice->vt1720 = 0; 11226b8d6e55SJulian Scheel ice->vt1724 = 1; 11236b8d6e55SJulian Scheel 11246b8d6e55SJulian Scheel ice->num_total_dacs = 1; 11256b8d6e55SJulian Scheel ice->num_total_adcs = 1; 11266b8d6e55SJulian Scheel 11276b8d6e55SJulian Scheel /* HACK - use this as the SPDIF source. 11286b8d6e55SJulian Scheel * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten 11296b8d6e55SJulian Scheel */ 11306b8d6e55SJulian Scheel ice->gpio.saved[0] = 0; 113125985edcSLucas De Marchi /* to remember the register values */ 11326b8d6e55SJulian Scheel 11336b8d6e55SJulian Scheel ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); 11346b8d6e55SJulian Scheel if (! ice->akm) 11356b8d6e55SJulian Scheel return -ENOMEM; 11366b8d6e55SJulian Scheel ice->akm_codecs = 1; 11376b8d6e55SJulian Scheel 11387cda8ba9STakashi Iwai spec = kzalloc(sizeof(*spec), GFP_KERNEL); 11397cda8ba9STakashi Iwai if (!spec) 11407cda8ba9STakashi Iwai return -ENOMEM; 11417cda8ba9STakashi Iwai ice->spec = spec; 11427cda8ba9STakashi Iwai 1143*c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP 1144b40e9538SIgor Chernyshev ice->pm_resume = &prodigy_hd2_resume; 1145b40e9538SIgor Chernyshev ice->pm_suspend_enabled = 1; 1146b40e9538SIgor Chernyshev #endif 11476b8d6e55SJulian Scheel 1148b40e9538SIgor Chernyshev ak4396_init(ice); 11496b8d6e55SJulian Scheel 11506b8d6e55SJulian Scheel return 0; 11516b8d6e55SJulian Scheel } 11526b8d6e55SJulian Scheel 11536b8d6e55SJulian Scheel 11546b8d6e55SJulian Scheel static unsigned char prodigy71hifi_eeprom[] __devinitdata = { 11556b8d6e55SJulian Scheel 0x4b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */ 11566b8d6e55SJulian Scheel 0x80, /* ACLINK: I2S */ 11576b8d6e55SJulian Scheel 0xfc, /* I2S: vol, 96k, 24bit, 192k */ 11586b8d6e55SJulian Scheel 0xc3, /* SPDIF: out-en, out-int, spdif-in */ 11596b8d6e55SJulian Scheel 0xff, /* GPIO_DIR */ 11606b8d6e55SJulian Scheel 0xff, /* GPIO_DIR1 */ 11616b8d6e55SJulian Scheel 0x5f, /* GPIO_DIR2 */ 11626b8d6e55SJulian Scheel 0x00, /* GPIO_MASK */ 11636b8d6e55SJulian Scheel 0x00, /* GPIO_MASK1 */ 11646b8d6e55SJulian Scheel 0x00, /* GPIO_MASK2 */ 11656b8d6e55SJulian Scheel 0x00, /* GPIO_STATE */ 11666b8d6e55SJulian Scheel 0x00, /* GPIO_STATE1 */ 11676b8d6e55SJulian Scheel 0x00, /* GPIO_STATE2 */ 11686b8d6e55SJulian Scheel }; 11696b8d6e55SJulian Scheel 11706b8d6e55SJulian Scheel static unsigned char prodigyhd2_eeprom[] __devinitdata = { 11716b8d6e55SJulian Scheel 0x4b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */ 11726b8d6e55SJulian Scheel 0x80, /* ACLINK: I2S */ 11736b8d6e55SJulian Scheel 0xfc, /* I2S: vol, 96k, 24bit, 192k */ 11746b8d6e55SJulian Scheel 0xc3, /* SPDIF: out-en, out-int, spdif-in */ 11756b8d6e55SJulian Scheel 0xff, /* GPIO_DIR */ 11766b8d6e55SJulian Scheel 0xff, /* GPIO_DIR1 */ 11776b8d6e55SJulian Scheel 0x5f, /* GPIO_DIR2 */ 11786b8d6e55SJulian Scheel 0x00, /* GPIO_MASK */ 11796b8d6e55SJulian Scheel 0x00, /* GPIO_MASK1 */ 11806b8d6e55SJulian Scheel 0x00, /* GPIO_MASK2 */ 11816b8d6e55SJulian Scheel 0x00, /* GPIO_STATE */ 11826b8d6e55SJulian Scheel 0x00, /* GPIO_STATE1 */ 11836b8d6e55SJulian Scheel 0x00, /* GPIO_STATE2 */ 11846b8d6e55SJulian Scheel }; 11856b8d6e55SJulian Scheel 11866b8d6e55SJulian Scheel static unsigned char fortissimo4_eeprom[] __devinitdata = { 11876b8d6e55SJulian Scheel 0x43, /* SYSCONF: clock 512, ADC, 4DACs */ 11886b8d6e55SJulian Scheel 0x80, /* ACLINK: I2S */ 11896b8d6e55SJulian Scheel 0xfc, /* I2S: vol, 96k, 24bit, 192k */ 11906b8d6e55SJulian Scheel 0xc1, /* SPDIF: out-en, out-int */ 11916b8d6e55SJulian Scheel 0xff, /* GPIO_DIR */ 11926b8d6e55SJulian Scheel 0xff, /* GPIO_DIR1 */ 11936b8d6e55SJulian Scheel 0x5f, /* GPIO_DIR2 */ 11946b8d6e55SJulian Scheel 0x00, /* GPIO_MASK */ 11956b8d6e55SJulian Scheel 0x00, /* GPIO_MASK1 */ 11966b8d6e55SJulian Scheel 0x00, /* GPIO_MASK2 */ 11976b8d6e55SJulian Scheel 0x00, /* GPIO_STATE */ 11986b8d6e55SJulian Scheel 0x00, /* GPIO_STATE1 */ 11996b8d6e55SJulian Scheel 0x00, /* GPIO_STATE2 */ 12006b8d6e55SJulian Scheel }; 12016b8d6e55SJulian Scheel 12026b8d6e55SJulian Scheel /* entry point */ 12036b8d6e55SJulian Scheel struct snd_ice1712_card_info snd_vt1724_prodigy_hifi_cards[] __devinitdata = { 12046b8d6e55SJulian Scheel { 12056b8d6e55SJulian Scheel .subvendor = VT1724_SUBDEVICE_PRODIGY_HIFI, 12066b8d6e55SJulian Scheel .name = "Audiotrak Prodigy 7.1 HiFi", 12076b8d6e55SJulian Scheel .model = "prodigy71hifi", 12086b8d6e55SJulian Scheel .chip_init = prodigy_hifi_init, 12096b8d6e55SJulian Scheel .build_controls = prodigy_hifi_add_controls, 12106b8d6e55SJulian Scheel .eeprom_size = sizeof(prodigy71hifi_eeprom), 12116b8d6e55SJulian Scheel .eeprom_data = prodigy71hifi_eeprom, 12126b8d6e55SJulian Scheel .driver = "Prodigy71HIFI", 12136b8d6e55SJulian Scheel }, 12146b8d6e55SJulian Scheel { 12156b8d6e55SJulian Scheel .subvendor = VT1724_SUBDEVICE_PRODIGY_HD2, 12166b8d6e55SJulian Scheel .name = "Audiotrak Prodigy HD2", 12176b8d6e55SJulian Scheel .model = "prodigyhd2", 12186b8d6e55SJulian Scheel .chip_init = prodigy_hd2_init, 12196b8d6e55SJulian Scheel .build_controls = prodigy_hd2_add_controls, 12206b8d6e55SJulian Scheel .eeprom_size = sizeof(prodigyhd2_eeprom), 12216b8d6e55SJulian Scheel .eeprom_data = prodigyhd2_eeprom, 12226b8d6e55SJulian Scheel .driver = "Prodigy71HD2", 12236b8d6e55SJulian Scheel }, 12246b8d6e55SJulian Scheel { 12256b8d6e55SJulian Scheel .subvendor = VT1724_SUBDEVICE_FORTISSIMO4, 12266b8d6e55SJulian Scheel .name = "Hercules Fortissimo IV", 12276b8d6e55SJulian Scheel .model = "fortissimo4", 12286b8d6e55SJulian Scheel .chip_init = prodigy_hifi_init, 12296b8d6e55SJulian Scheel .build_controls = prodigy_hifi_add_controls, 12306b8d6e55SJulian Scheel .eeprom_size = sizeof(fortissimo4_eeprom), 12316b8d6e55SJulian Scheel .eeprom_data = fortissimo4_eeprom, 12326b8d6e55SJulian Scheel .driver = "Fortissimo4", 12336b8d6e55SJulian Scheel }, 12346b8d6e55SJulian Scheel { } /* terminator */ 12356b8d6e55SJulian Scheel }; 12366b8d6e55SJulian Scheel 1237