162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ALSA driver for ICEnsemble VT1724 (Envy24HT) 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Lowlevel functions for Audiotrak Prodigy 7.1 Hifi 662306a36Sopenharmony_ci * based on pontis.c 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Copyright (c) 2007 Julian Scheel <julian@jusst.de> 962306a36Sopenharmony_ci * Copyright (c) 2007 allank 1062306a36Sopenharmony_ci * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/delay.h> 1562306a36Sopenharmony_ci#include <linux/interrupt.h> 1662306a36Sopenharmony_ci#include <linux/init.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci#include <linux/mutex.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <sound/core.h> 2162306a36Sopenharmony_ci#include <sound/info.h> 2262306a36Sopenharmony_ci#include <sound/tlv.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "ice1712.h" 2562306a36Sopenharmony_ci#include "envy24ht.h" 2662306a36Sopenharmony_ci#include "prodigy_hifi.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistruct prodigy_hifi_spec { 2962306a36Sopenharmony_ci unsigned short master[2]; 3062306a36Sopenharmony_ci unsigned short vol[8]; 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* I2C addresses */ 3462306a36Sopenharmony_ci#define WM_DEV 0x34 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* WM8776 registers */ 3762306a36Sopenharmony_ci#define WM_HP_ATTEN_L 0x00 /* headphone left attenuation */ 3862306a36Sopenharmony_ci#define WM_HP_ATTEN_R 0x01 /* headphone left attenuation */ 3962306a36Sopenharmony_ci#define WM_HP_MASTER 0x02 /* headphone master (both channels), 4062306a36Sopenharmony_ci override LLR */ 4162306a36Sopenharmony_ci#define WM_DAC_ATTEN_L 0x03 /* digital left attenuation */ 4262306a36Sopenharmony_ci#define WM_DAC_ATTEN_R 0x04 4362306a36Sopenharmony_ci#define WM_DAC_MASTER 0x05 4462306a36Sopenharmony_ci#define WM_PHASE_SWAP 0x06 /* DAC phase swap */ 4562306a36Sopenharmony_ci#define WM_DAC_CTRL1 0x07 4662306a36Sopenharmony_ci#define WM_DAC_MUTE 0x08 4762306a36Sopenharmony_ci#define WM_DAC_CTRL2 0x09 4862306a36Sopenharmony_ci#define WM_DAC_INT 0x0a 4962306a36Sopenharmony_ci#define WM_ADC_INT 0x0b 5062306a36Sopenharmony_ci#define WM_MASTER_CTRL 0x0c 5162306a36Sopenharmony_ci#define WM_POWERDOWN 0x0d 5262306a36Sopenharmony_ci#define WM_ADC_ATTEN_L 0x0e 5362306a36Sopenharmony_ci#define WM_ADC_ATTEN_R 0x0f 5462306a36Sopenharmony_ci#define WM_ALC_CTRL1 0x10 5562306a36Sopenharmony_ci#define WM_ALC_CTRL2 0x11 5662306a36Sopenharmony_ci#define WM_ALC_CTRL3 0x12 5762306a36Sopenharmony_ci#define WM_NOISE_GATE 0x13 5862306a36Sopenharmony_ci#define WM_LIMITER 0x14 5962306a36Sopenharmony_ci#define WM_ADC_MUX 0x15 6062306a36Sopenharmony_ci#define WM_OUT_MUX 0x16 6162306a36Sopenharmony_ci#define WM_RESET 0x17 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* Analog Recording Source :- Mic, LineIn, CD/Video, */ 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* implement capture source select control for WM8776 */ 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#define WM_AIN1 "AIN1" 6862306a36Sopenharmony_ci#define WM_AIN2 "AIN2" 6962306a36Sopenharmony_ci#define WM_AIN3 "AIN3" 7062306a36Sopenharmony_ci#define WM_AIN4 "AIN4" 7162306a36Sopenharmony_ci#define WM_AIN5 "AIN5" 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/* GPIO pins of envy24ht connected to wm8766 */ 7462306a36Sopenharmony_ci#define WM8766_SPI_CLK (1<<17) /* CLK, Pin97 on ICE1724 */ 7562306a36Sopenharmony_ci#define WM8766_SPI_MD (1<<16) /* DATA VT1724 -> WM8766, Pin96 */ 7662306a36Sopenharmony_ci#define WM8766_SPI_ML (1<<18) /* Latch, Pin98 */ 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* WM8766 registers */ 7962306a36Sopenharmony_ci#define WM8766_DAC_CTRL 0x02 /* DAC Control */ 8062306a36Sopenharmony_ci#define WM8766_INT_CTRL 0x03 /* Interface Control */ 8162306a36Sopenharmony_ci#define WM8766_DAC_CTRL2 0x09 8262306a36Sopenharmony_ci#define WM8766_DAC_CTRL3 0x0a 8362306a36Sopenharmony_ci#define WM8766_RESET 0x1f 8462306a36Sopenharmony_ci#define WM8766_LDA1 0x00 8562306a36Sopenharmony_ci#define WM8766_LDA2 0x04 8662306a36Sopenharmony_ci#define WM8766_LDA3 0x06 8762306a36Sopenharmony_ci#define WM8766_RDA1 0x01 8862306a36Sopenharmony_ci#define WM8766_RDA2 0x05 8962306a36Sopenharmony_ci#define WM8766_RDA3 0x07 9062306a36Sopenharmony_ci#define WM8766_MUTE1 0x0C 9162306a36Sopenharmony_ci#define WM8766_MUTE2 0x0F 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/* 9562306a36Sopenharmony_ci * Prodigy HD2 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_ci#define AK4396_ADDR 0x00 9862306a36Sopenharmony_ci#define AK4396_CSN (1 << 8) /* CSN->GPIO8, pin 75 */ 9962306a36Sopenharmony_ci#define AK4396_CCLK (1 << 9) /* CCLK->GPIO9, pin 76 */ 10062306a36Sopenharmony_ci#define AK4396_CDTI (1 << 10) /* CDTI->GPIO10, pin 77 */ 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/* ak4396 registers */ 10362306a36Sopenharmony_ci#define AK4396_CTRL1 0x00 10462306a36Sopenharmony_ci#define AK4396_CTRL2 0x01 10562306a36Sopenharmony_ci#define AK4396_CTRL3 0x02 10662306a36Sopenharmony_ci#define AK4396_LCH_ATT 0x03 10762306a36Sopenharmony_ci#define AK4396_RCH_ATT 0x04 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci/* 11162306a36Sopenharmony_ci * get the current register value of WM codec 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_cistatic unsigned short wm_get(struct snd_ice1712 *ice, int reg) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci reg <<= 1; 11662306a36Sopenharmony_ci return ((unsigned short)ice->akm[0].images[reg] << 8) | 11762306a36Sopenharmony_ci ice->akm[0].images[reg + 1]; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/* 12162306a36Sopenharmony_ci * set the register value of WM codec and remember it 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_cistatic void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci unsigned short cval; 12662306a36Sopenharmony_ci cval = (reg << 9) | val; 12762306a36Sopenharmony_ci snd_vt1724_write_i2c(ice, WM_DEV, cval >> 8, cval & 0xff); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci wm_put_nocache(ice, reg, val); 13362306a36Sopenharmony_ci reg <<= 1; 13462306a36Sopenharmony_ci ice->akm[0].images[reg] = val >> 8; 13562306a36Sopenharmony_ci ice->akm[0].images[reg + 1] = val; 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci/* 13962306a36Sopenharmony_ci * write data in the SPI mode 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic void set_gpio_bit(struct snd_ice1712 *ice, unsigned int bit, int val) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci unsigned int tmp = snd_ice1712_gpio_read(ice); 14562306a36Sopenharmony_ci if (val) 14662306a36Sopenharmony_ci tmp |= bit; 14762306a36Sopenharmony_ci else 14862306a36Sopenharmony_ci tmp &= ~bit; 14962306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/* 15362306a36Sopenharmony_ci * SPI implementation for WM8766 codec - only writing supported, no readback 15462306a36Sopenharmony_ci */ 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic void wm8766_spi_send_word(struct snd_ice1712 *ice, unsigned int data) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci int i; 15962306a36Sopenharmony_ci for (i = 0; i < 16; i++) { 16062306a36Sopenharmony_ci set_gpio_bit(ice, WM8766_SPI_CLK, 0); 16162306a36Sopenharmony_ci udelay(1); 16262306a36Sopenharmony_ci set_gpio_bit(ice, WM8766_SPI_MD, data & 0x8000); 16362306a36Sopenharmony_ci udelay(1); 16462306a36Sopenharmony_ci set_gpio_bit(ice, WM8766_SPI_CLK, 1); 16562306a36Sopenharmony_ci udelay(1); 16662306a36Sopenharmony_ci data <<= 1; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic void wm8766_spi_write(struct snd_ice1712 *ice, unsigned int reg, 17162306a36Sopenharmony_ci unsigned int data) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci unsigned int block; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci snd_ice1712_gpio_set_dir(ice, WM8766_SPI_MD| 17662306a36Sopenharmony_ci WM8766_SPI_CLK|WM8766_SPI_ML); 17762306a36Sopenharmony_ci snd_ice1712_gpio_set_mask(ice, ~(WM8766_SPI_MD| 17862306a36Sopenharmony_ci WM8766_SPI_CLK|WM8766_SPI_ML)); 17962306a36Sopenharmony_ci /* latch must be low when writing */ 18062306a36Sopenharmony_ci set_gpio_bit(ice, WM8766_SPI_ML, 0); 18162306a36Sopenharmony_ci block = (reg << 9) | (data & 0x1ff); 18262306a36Sopenharmony_ci wm8766_spi_send_word(ice, block); /* REGISTER ADDRESS */ 18362306a36Sopenharmony_ci /* release latch */ 18462306a36Sopenharmony_ci set_gpio_bit(ice, WM8766_SPI_ML, 1); 18562306a36Sopenharmony_ci udelay(1); 18662306a36Sopenharmony_ci /* restore */ 18762306a36Sopenharmony_ci snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask); 18862306a36Sopenharmony_ci snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci/* 19362306a36Sopenharmony_ci * serial interface for ak4396 - only writing supported, no readback 19462306a36Sopenharmony_ci */ 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic void ak4396_send_word(struct snd_ice1712 *ice, unsigned int data) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci int i; 19962306a36Sopenharmony_ci for (i = 0; i < 16; i++) { 20062306a36Sopenharmony_ci set_gpio_bit(ice, AK4396_CCLK, 0); 20162306a36Sopenharmony_ci udelay(1); 20262306a36Sopenharmony_ci set_gpio_bit(ice, AK4396_CDTI, data & 0x8000); 20362306a36Sopenharmony_ci udelay(1); 20462306a36Sopenharmony_ci set_gpio_bit(ice, AK4396_CCLK, 1); 20562306a36Sopenharmony_ci udelay(1); 20662306a36Sopenharmony_ci data <<= 1; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic void ak4396_write(struct snd_ice1712 *ice, unsigned int reg, 21162306a36Sopenharmony_ci unsigned int data) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci unsigned int block; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci snd_ice1712_gpio_set_dir(ice, AK4396_CSN|AK4396_CCLK|AK4396_CDTI); 21662306a36Sopenharmony_ci snd_ice1712_gpio_set_mask(ice, ~(AK4396_CSN|AK4396_CCLK|AK4396_CDTI)); 21762306a36Sopenharmony_ci /* latch must be low when writing */ 21862306a36Sopenharmony_ci set_gpio_bit(ice, AK4396_CSN, 0); 21962306a36Sopenharmony_ci block = ((AK4396_ADDR & 0x03) << 14) | (1 << 13) | 22062306a36Sopenharmony_ci ((reg & 0x1f) << 8) | (data & 0xff); 22162306a36Sopenharmony_ci ak4396_send_word(ice, block); /* REGISTER ADDRESS */ 22262306a36Sopenharmony_ci /* release latch */ 22362306a36Sopenharmony_ci set_gpio_bit(ice, AK4396_CSN, 1); 22462306a36Sopenharmony_ci udelay(1); 22562306a36Sopenharmony_ci /* restore */ 22662306a36Sopenharmony_ci snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask); 22762306a36Sopenharmony_ci snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci/* 23262306a36Sopenharmony_ci * ak4396 mixers 23362306a36Sopenharmony_ci */ 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci/* 23862306a36Sopenharmony_ci * DAC volume attenuation mixer control (-64dB to 0dB) 23962306a36Sopenharmony_ci */ 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic int ak4396_dac_vol_info(struct snd_kcontrol *kcontrol, 24262306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 24562306a36Sopenharmony_ci uinfo->count = 2; 24662306a36Sopenharmony_ci uinfo->value.integer.min = 0; /* mute */ 24762306a36Sopenharmony_ci uinfo->value.integer.max = 0xFF; /* linear */ 24862306a36Sopenharmony_ci return 0; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic int ak4396_dac_vol_get(struct snd_kcontrol *kcontrol, 25262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 25562306a36Sopenharmony_ci struct prodigy_hifi_spec *spec = ice->spec; 25662306a36Sopenharmony_ci int i; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci for (i = 0; i < 2; i++) 25962306a36Sopenharmony_ci ucontrol->value.integer.value[i] = spec->vol[i]; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci return 0; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic int ak4396_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 26762306a36Sopenharmony_ci struct prodigy_hifi_spec *spec = ice->spec; 26862306a36Sopenharmony_ci int i; 26962306a36Sopenharmony_ci int change = 0; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 27262306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 27362306a36Sopenharmony_ci if (ucontrol->value.integer.value[i] != spec->vol[i]) { 27462306a36Sopenharmony_ci spec->vol[i] = ucontrol->value.integer.value[i]; 27562306a36Sopenharmony_ci ak4396_write(ice, AK4396_LCH_ATT + i, 27662306a36Sopenharmony_ci spec->vol[i] & 0xff); 27762306a36Sopenharmony_ci change = 1; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 28162306a36Sopenharmony_ci return change; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); 28562306a36Sopenharmony_cistatic const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic const struct snd_kcontrol_new prodigy_hd2_controls[] = { 28862306a36Sopenharmony_ci { 28962306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 29062306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 29162306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 29262306a36Sopenharmony_ci .name = "Front Playback Volume", 29362306a36Sopenharmony_ci .info = ak4396_dac_vol_info, 29462306a36Sopenharmony_ci .get = ak4396_dac_vol_get, 29562306a36Sopenharmony_ci .put = ak4396_dac_vol_put, 29662306a36Sopenharmony_ci .tlv = { .p = ak4396_db_scale }, 29762306a36Sopenharmony_ci }, 29862306a36Sopenharmony_ci}; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci/* --------------- */ 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci#define WM_VOL_MAX 255 30462306a36Sopenharmony_ci#define WM_VOL_MUTE 0x8000 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci#define DAC_0dB 0xff 30862306a36Sopenharmony_ci#define DAC_RES 128 30962306a36Sopenharmony_ci#define DAC_MIN (DAC_0dB - DAC_RES) 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, 31362306a36Sopenharmony_ci unsigned short vol, unsigned short master) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci unsigned char nvol; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) 31862306a36Sopenharmony_ci nvol = 0; 31962306a36Sopenharmony_ci else { 32062306a36Sopenharmony_ci nvol = (((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 128) 32162306a36Sopenharmony_ci & WM_VOL_MAX; 32262306a36Sopenharmony_ci nvol = (nvol ? (nvol + DAC_MIN) : 0) & 0xff; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci wm_put(ice, index, nvol); 32662306a36Sopenharmony_ci wm_put_nocache(ice, index, 0x100 | nvol); 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic void wm8766_set_vol(struct snd_ice1712 *ice, unsigned int index, 33062306a36Sopenharmony_ci unsigned short vol, unsigned short master) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci unsigned char nvol; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) 33562306a36Sopenharmony_ci nvol = 0; 33662306a36Sopenharmony_ci else { 33762306a36Sopenharmony_ci nvol = (((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 128) 33862306a36Sopenharmony_ci & WM_VOL_MAX; 33962306a36Sopenharmony_ci nvol = (nvol ? (nvol + DAC_MIN) : 0) & 0xff; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci wm8766_spi_write(ice, index, (0x0100 | nvol)); 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci/* 34762306a36Sopenharmony_ci * DAC volume attenuation mixer control (-64dB to 0dB) 34862306a36Sopenharmony_ci */ 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cistatic int wm_dac_vol_info(struct snd_kcontrol *kcontrol, 35162306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 35462306a36Sopenharmony_ci uinfo->count = 2; 35562306a36Sopenharmony_ci uinfo->value.integer.min = 0; /* mute */ 35662306a36Sopenharmony_ci uinfo->value.integer.max = DAC_RES; /* 0dB, 0.5dB step */ 35762306a36Sopenharmony_ci return 0; 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cistatic int wm_dac_vol_get(struct snd_kcontrol *kcontrol, 36162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 36462306a36Sopenharmony_ci struct prodigy_hifi_spec *spec = ice->spec; 36562306a36Sopenharmony_ci int i; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci for (i = 0; i < 2; i++) 36862306a36Sopenharmony_ci ucontrol->value.integer.value[i] = 36962306a36Sopenharmony_ci spec->vol[2 + i] & ~WM_VOL_MUTE; 37062306a36Sopenharmony_ci return 0; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic int wm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 37662306a36Sopenharmony_ci struct prodigy_hifi_spec *spec = ice->spec; 37762306a36Sopenharmony_ci int i, idx, change = 0; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 38062306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 38162306a36Sopenharmony_ci if (ucontrol->value.integer.value[i] != spec->vol[2 + i]) { 38262306a36Sopenharmony_ci idx = WM_DAC_ATTEN_L + i; 38362306a36Sopenharmony_ci spec->vol[2 + i] &= WM_VOL_MUTE; 38462306a36Sopenharmony_ci spec->vol[2 + i] |= ucontrol->value.integer.value[i]; 38562306a36Sopenharmony_ci wm_set_vol(ice, idx, spec->vol[2 + i], spec->master[i]); 38662306a36Sopenharmony_ci change = 1; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 39062306a36Sopenharmony_ci return change; 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci/* 39562306a36Sopenharmony_ci * WM8766 DAC volume attenuation mixer control 39662306a36Sopenharmony_ci */ 39762306a36Sopenharmony_cistatic int wm8766_vol_info(struct snd_kcontrol *kcontrol, 39862306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci int voices = kcontrol->private_value >> 8; 40162306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 40262306a36Sopenharmony_ci uinfo->count = voices; 40362306a36Sopenharmony_ci uinfo->value.integer.min = 0; /* mute */ 40462306a36Sopenharmony_ci uinfo->value.integer.max = DAC_RES; /* 0dB */ 40562306a36Sopenharmony_ci return 0; 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic int wm8766_vol_get(struct snd_kcontrol *kcontrol, 40962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 41262306a36Sopenharmony_ci struct prodigy_hifi_spec *spec = ice->spec; 41362306a36Sopenharmony_ci int i, ofs, voices; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci voices = kcontrol->private_value >> 8; 41662306a36Sopenharmony_ci ofs = kcontrol->private_value & 0xff; 41762306a36Sopenharmony_ci for (i = 0; i < voices; i++) 41862306a36Sopenharmony_ci ucontrol->value.integer.value[i] = spec->vol[ofs + i]; 41962306a36Sopenharmony_ci return 0; 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic int wm8766_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 42562306a36Sopenharmony_ci struct prodigy_hifi_spec *spec = ice->spec; 42662306a36Sopenharmony_ci int i, idx, ofs, voices; 42762306a36Sopenharmony_ci int change = 0; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci voices = kcontrol->private_value >> 8; 43062306a36Sopenharmony_ci ofs = kcontrol->private_value & 0xff; 43162306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 43262306a36Sopenharmony_ci for (i = 0; i < voices; i++) { 43362306a36Sopenharmony_ci if (ucontrol->value.integer.value[i] != spec->vol[ofs + i]) { 43462306a36Sopenharmony_ci idx = WM8766_LDA1 + ofs + i; 43562306a36Sopenharmony_ci spec->vol[ofs + i] &= WM_VOL_MUTE; 43662306a36Sopenharmony_ci spec->vol[ofs + i] |= ucontrol->value.integer.value[i]; 43762306a36Sopenharmony_ci wm8766_set_vol(ice, idx, 43862306a36Sopenharmony_ci spec->vol[ofs + i], spec->master[i]); 43962306a36Sopenharmony_ci change = 1; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 44362306a36Sopenharmony_ci return change; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci/* 44762306a36Sopenharmony_ci * Master volume attenuation mixer control / applied to WM8776+WM8766 44862306a36Sopenharmony_ci */ 44962306a36Sopenharmony_cistatic int wm_master_vol_info(struct snd_kcontrol *kcontrol, 45062306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 45362306a36Sopenharmony_ci uinfo->count = 2; 45462306a36Sopenharmony_ci uinfo->value.integer.min = 0; 45562306a36Sopenharmony_ci uinfo->value.integer.max = DAC_RES; 45662306a36Sopenharmony_ci return 0; 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic int wm_master_vol_get(struct snd_kcontrol *kcontrol, 46062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 46362306a36Sopenharmony_ci struct prodigy_hifi_spec *spec = ice->spec; 46462306a36Sopenharmony_ci int i; 46562306a36Sopenharmony_ci for (i = 0; i < 2; i++) 46662306a36Sopenharmony_ci ucontrol->value.integer.value[i] = spec->master[i]; 46762306a36Sopenharmony_ci return 0; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic int wm_master_vol_put(struct snd_kcontrol *kcontrol, 47162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 47462306a36Sopenharmony_ci struct prodigy_hifi_spec *spec = ice->spec; 47562306a36Sopenharmony_ci int ch, change = 0; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 47862306a36Sopenharmony_ci for (ch = 0; ch < 2; ch++) { 47962306a36Sopenharmony_ci if (ucontrol->value.integer.value[ch] != spec->master[ch]) { 48062306a36Sopenharmony_ci spec->master[ch] = ucontrol->value.integer.value[ch]; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* Apply to front DAC */ 48362306a36Sopenharmony_ci wm_set_vol(ice, WM_DAC_ATTEN_L + ch, 48462306a36Sopenharmony_ci spec->vol[2 + ch], spec->master[ch]); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci wm8766_set_vol(ice, WM8766_LDA1 + ch, 48762306a36Sopenharmony_ci spec->vol[0 + ch], spec->master[ch]); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci wm8766_set_vol(ice, WM8766_LDA2 + ch, 49062306a36Sopenharmony_ci spec->vol[4 + ch], spec->master[ch]); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci wm8766_set_vol(ice, WM8766_LDA3 + ch, 49362306a36Sopenharmony_ci spec->vol[6 + ch], spec->master[ch]); 49462306a36Sopenharmony_ci change = 1; 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 49862306a36Sopenharmony_ci return change; 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci/* KONSTI */ 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic int wm_adc_mux_enum_info(struct snd_kcontrol *kcontrol, 50562306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci static const char * const texts[32] = { 50862306a36Sopenharmony_ci "NULL", WM_AIN1, WM_AIN2, WM_AIN1 "+" WM_AIN2, 50962306a36Sopenharmony_ci WM_AIN3, WM_AIN1 "+" WM_AIN3, WM_AIN2 "+" WM_AIN3, 51062306a36Sopenharmony_ci WM_AIN1 "+" WM_AIN2 "+" WM_AIN3, 51162306a36Sopenharmony_ci WM_AIN4, WM_AIN1 "+" WM_AIN4, WM_AIN2 "+" WM_AIN4, 51262306a36Sopenharmony_ci WM_AIN1 "+" WM_AIN2 "+" WM_AIN4, 51362306a36Sopenharmony_ci WM_AIN3 "+" WM_AIN4, WM_AIN1 "+" WM_AIN3 "+" WM_AIN4, 51462306a36Sopenharmony_ci WM_AIN2 "+" WM_AIN3 "+" WM_AIN4, 51562306a36Sopenharmony_ci WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4, 51662306a36Sopenharmony_ci WM_AIN5, WM_AIN1 "+" WM_AIN5, WM_AIN2 "+" WM_AIN5, 51762306a36Sopenharmony_ci WM_AIN1 "+" WM_AIN2 "+" WM_AIN5, 51862306a36Sopenharmony_ci WM_AIN3 "+" WM_AIN5, WM_AIN1 "+" WM_AIN3 "+" WM_AIN5, 51962306a36Sopenharmony_ci WM_AIN2 "+" WM_AIN3 "+" WM_AIN5, 52062306a36Sopenharmony_ci WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN5, 52162306a36Sopenharmony_ci WM_AIN4 "+" WM_AIN5, WM_AIN1 "+" WM_AIN4 "+" WM_AIN5, 52262306a36Sopenharmony_ci WM_AIN2 "+" WM_AIN4 "+" WM_AIN5, 52362306a36Sopenharmony_ci WM_AIN1 "+" WM_AIN2 "+" WM_AIN4 "+" WM_AIN5, 52462306a36Sopenharmony_ci WM_AIN3 "+" WM_AIN4 "+" WM_AIN5, 52562306a36Sopenharmony_ci WM_AIN1 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5, 52662306a36Sopenharmony_ci WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5, 52762306a36Sopenharmony_ci WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5 52862306a36Sopenharmony_ci }; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 32, texts); 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic int wm_adc_mux_enum_get(struct snd_kcontrol *kcontrol, 53462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 53962306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = wm_get(ice, WM_ADC_MUX) & 0x1f; 54062306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 54162306a36Sopenharmony_ci return 0; 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistatic int wm_adc_mux_enum_put(struct snd_kcontrol *kcontrol, 54562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 54862306a36Sopenharmony_ci unsigned short oval, nval; 54962306a36Sopenharmony_ci int change = 0; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 55262306a36Sopenharmony_ci oval = wm_get(ice, WM_ADC_MUX); 55362306a36Sopenharmony_ci nval = (oval & 0xe0) | ucontrol->value.enumerated.item[0]; 55462306a36Sopenharmony_ci if (nval != oval) { 55562306a36Sopenharmony_ci wm_put(ice, WM_ADC_MUX, nval); 55662306a36Sopenharmony_ci change = 1; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 55962306a36Sopenharmony_ci return change; 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci/* KONSTI */ 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci/* 56562306a36Sopenharmony_ci * ADC gain mixer control (-64dB to 0dB) 56662306a36Sopenharmony_ci */ 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci#define ADC_0dB 0xcf 56962306a36Sopenharmony_ci#define ADC_RES 128 57062306a36Sopenharmony_ci#define ADC_MIN (ADC_0dB - ADC_RES) 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_cistatic int wm_adc_vol_info(struct snd_kcontrol *kcontrol, 57362306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 57662306a36Sopenharmony_ci uinfo->count = 2; 57762306a36Sopenharmony_ci uinfo->value.integer.min = 0; /* mute (-64dB) */ 57862306a36Sopenharmony_ci uinfo->value.integer.max = ADC_RES; /* 0dB, 0.5dB step */ 57962306a36Sopenharmony_ci return 0; 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic int wm_adc_vol_get(struct snd_kcontrol *kcontrol, 58362306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 58662306a36Sopenharmony_ci unsigned short val; 58762306a36Sopenharmony_ci int i; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 59062306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 59162306a36Sopenharmony_ci val = wm_get(ice, WM_ADC_ATTEN_L + i) & 0xff; 59262306a36Sopenharmony_ci val = val > ADC_MIN ? (val - ADC_MIN) : 0; 59362306a36Sopenharmony_ci ucontrol->value.integer.value[i] = val; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 59662306a36Sopenharmony_ci return 0; 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic int wm_adc_vol_put(struct snd_kcontrol *kcontrol, 60062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 60362306a36Sopenharmony_ci unsigned short ovol, nvol; 60462306a36Sopenharmony_ci int i, idx, change = 0; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 60762306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 60862306a36Sopenharmony_ci nvol = ucontrol->value.integer.value[i]; 60962306a36Sopenharmony_ci nvol = nvol ? (nvol + ADC_MIN) : 0; 61062306a36Sopenharmony_ci idx = WM_ADC_ATTEN_L + i; 61162306a36Sopenharmony_ci ovol = wm_get(ice, idx) & 0xff; 61262306a36Sopenharmony_ci if (ovol != nvol) { 61362306a36Sopenharmony_ci wm_put(ice, idx, nvol); 61462306a36Sopenharmony_ci change = 1; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 61862306a36Sopenharmony_ci return change; 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci/* 62262306a36Sopenharmony_ci * ADC input mux mixer control 62362306a36Sopenharmony_ci */ 62462306a36Sopenharmony_ci#define wm_adc_mux_info snd_ctl_boolean_mono_info 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic int wm_adc_mux_get(struct snd_kcontrol *kcontrol, 62762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 63062306a36Sopenharmony_ci int bit = kcontrol->private_value; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 63362306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 63462306a36Sopenharmony_ci (wm_get(ice, WM_ADC_MUX) & (1 << bit)) ? 1 : 0; 63562306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 63662306a36Sopenharmony_ci return 0; 63762306a36Sopenharmony_ci} 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_cistatic int wm_adc_mux_put(struct snd_kcontrol *kcontrol, 64062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 64362306a36Sopenharmony_ci int bit = kcontrol->private_value; 64462306a36Sopenharmony_ci unsigned short oval, nval; 64562306a36Sopenharmony_ci int change; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 64862306a36Sopenharmony_ci nval = oval = wm_get(ice, WM_ADC_MUX); 64962306a36Sopenharmony_ci if (ucontrol->value.integer.value[0]) 65062306a36Sopenharmony_ci nval |= (1 << bit); 65162306a36Sopenharmony_ci else 65262306a36Sopenharmony_ci nval &= ~(1 << bit); 65362306a36Sopenharmony_ci change = nval != oval; 65462306a36Sopenharmony_ci if (change) { 65562306a36Sopenharmony_ci wm_put(ice, WM_ADC_MUX, nval); 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 65862306a36Sopenharmony_ci return 0; 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci/* 66262306a36Sopenharmony_ci * Analog bypass (In -> Out) 66362306a36Sopenharmony_ci */ 66462306a36Sopenharmony_ci#define wm_bypass_info snd_ctl_boolean_mono_info 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_cistatic int wm_bypass_get(struct snd_kcontrol *kcontrol, 66762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 67262306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 67362306a36Sopenharmony_ci (wm_get(ice, WM_OUT_MUX) & 0x04) ? 1 : 0; 67462306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 67562306a36Sopenharmony_ci return 0; 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_cistatic int wm_bypass_put(struct snd_kcontrol *kcontrol, 67962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 68262306a36Sopenharmony_ci unsigned short val, oval; 68362306a36Sopenharmony_ci int change = 0; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 68662306a36Sopenharmony_ci val = oval = wm_get(ice, WM_OUT_MUX); 68762306a36Sopenharmony_ci if (ucontrol->value.integer.value[0]) 68862306a36Sopenharmony_ci val |= 0x04; 68962306a36Sopenharmony_ci else 69062306a36Sopenharmony_ci val &= ~0x04; 69162306a36Sopenharmony_ci if (val != oval) { 69262306a36Sopenharmony_ci wm_put(ice, WM_OUT_MUX, val); 69362306a36Sopenharmony_ci change = 1; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 69662306a36Sopenharmony_ci return change; 69762306a36Sopenharmony_ci} 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci/* 70062306a36Sopenharmony_ci * Left/Right swap 70162306a36Sopenharmony_ci */ 70262306a36Sopenharmony_ci#define wm_chswap_info snd_ctl_boolean_mono_info 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic int wm_chswap_get(struct snd_kcontrol *kcontrol, 70562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 70662306a36Sopenharmony_ci{ 70762306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 71062306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 71162306a36Sopenharmony_ci (wm_get(ice, WM_DAC_CTRL1) & 0xf0) != 0x90; 71262306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 71362306a36Sopenharmony_ci return 0; 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic int wm_chswap_put(struct snd_kcontrol *kcontrol, 71762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 72062306a36Sopenharmony_ci unsigned short val, oval; 72162306a36Sopenharmony_ci int change = 0; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 72462306a36Sopenharmony_ci oval = wm_get(ice, WM_DAC_CTRL1); 72562306a36Sopenharmony_ci val = oval & 0x0f; 72662306a36Sopenharmony_ci if (ucontrol->value.integer.value[0]) 72762306a36Sopenharmony_ci val |= 0x60; 72862306a36Sopenharmony_ci else 72962306a36Sopenharmony_ci val |= 0x90; 73062306a36Sopenharmony_ci if (val != oval) { 73162306a36Sopenharmony_ci wm_put(ice, WM_DAC_CTRL1, val); 73262306a36Sopenharmony_ci wm_put_nocache(ice, WM_DAC_CTRL1, val); 73362306a36Sopenharmony_ci change = 1; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 73662306a36Sopenharmony_ci return change; 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci/* 74162306a36Sopenharmony_ci * mixers 74262306a36Sopenharmony_ci */ 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_cistatic const struct snd_kcontrol_new prodigy_hifi_controls[] = { 74562306a36Sopenharmony_ci { 74662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 74762306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 74862306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 74962306a36Sopenharmony_ci .name = "Master Playback Volume", 75062306a36Sopenharmony_ci .info = wm_master_vol_info, 75162306a36Sopenharmony_ci .get = wm_master_vol_get, 75262306a36Sopenharmony_ci .put = wm_master_vol_put, 75362306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_dac } 75462306a36Sopenharmony_ci }, 75562306a36Sopenharmony_ci { 75662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 75762306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 75862306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 75962306a36Sopenharmony_ci .name = "Front Playback Volume", 76062306a36Sopenharmony_ci .info = wm_dac_vol_info, 76162306a36Sopenharmony_ci .get = wm_dac_vol_get, 76262306a36Sopenharmony_ci .put = wm_dac_vol_put, 76362306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_dac }, 76462306a36Sopenharmony_ci }, 76562306a36Sopenharmony_ci { 76662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 76762306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 76862306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 76962306a36Sopenharmony_ci .name = "Rear Playback Volume", 77062306a36Sopenharmony_ci .info = wm8766_vol_info, 77162306a36Sopenharmony_ci .get = wm8766_vol_get, 77262306a36Sopenharmony_ci .put = wm8766_vol_put, 77362306a36Sopenharmony_ci .private_value = (2 << 8) | 0, 77462306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_dac }, 77562306a36Sopenharmony_ci }, 77662306a36Sopenharmony_ci { 77762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 77862306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 77962306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 78062306a36Sopenharmony_ci .name = "Center Playback Volume", 78162306a36Sopenharmony_ci .info = wm8766_vol_info, 78262306a36Sopenharmony_ci .get = wm8766_vol_get, 78362306a36Sopenharmony_ci .put = wm8766_vol_put, 78462306a36Sopenharmony_ci .private_value = (1 << 8) | 4, 78562306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_dac } 78662306a36Sopenharmony_ci }, 78762306a36Sopenharmony_ci { 78862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 78962306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 79062306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 79162306a36Sopenharmony_ci .name = "LFE Playback Volume", 79262306a36Sopenharmony_ci .info = wm8766_vol_info, 79362306a36Sopenharmony_ci .get = wm8766_vol_get, 79462306a36Sopenharmony_ci .put = wm8766_vol_put, 79562306a36Sopenharmony_ci .private_value = (1 << 8) | 5, 79662306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_dac } 79762306a36Sopenharmony_ci }, 79862306a36Sopenharmony_ci { 79962306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 80062306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 80162306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 80262306a36Sopenharmony_ci .name = "Side Playback Volume", 80362306a36Sopenharmony_ci .info = wm8766_vol_info, 80462306a36Sopenharmony_ci .get = wm8766_vol_get, 80562306a36Sopenharmony_ci .put = wm8766_vol_put, 80662306a36Sopenharmony_ci .private_value = (2 << 8) | 6, 80762306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_dac }, 80862306a36Sopenharmony_ci }, 80962306a36Sopenharmony_ci { 81062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 81162306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 81262306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 81362306a36Sopenharmony_ci .name = "Capture Volume", 81462306a36Sopenharmony_ci .info = wm_adc_vol_info, 81562306a36Sopenharmony_ci .get = wm_adc_vol_get, 81662306a36Sopenharmony_ci .put = wm_adc_vol_put, 81762306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_dac }, 81862306a36Sopenharmony_ci }, 81962306a36Sopenharmony_ci { 82062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 82162306a36Sopenharmony_ci .name = "CD Capture Switch", 82262306a36Sopenharmony_ci .info = wm_adc_mux_info, 82362306a36Sopenharmony_ci .get = wm_adc_mux_get, 82462306a36Sopenharmony_ci .put = wm_adc_mux_put, 82562306a36Sopenharmony_ci .private_value = 0, 82662306a36Sopenharmony_ci }, 82762306a36Sopenharmony_ci { 82862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 82962306a36Sopenharmony_ci .name = "Line Capture Switch", 83062306a36Sopenharmony_ci .info = wm_adc_mux_info, 83162306a36Sopenharmony_ci .get = wm_adc_mux_get, 83262306a36Sopenharmony_ci .put = wm_adc_mux_put, 83362306a36Sopenharmony_ci .private_value = 1, 83462306a36Sopenharmony_ci }, 83562306a36Sopenharmony_ci { 83662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 83762306a36Sopenharmony_ci .name = "Analog Bypass Switch", 83862306a36Sopenharmony_ci .info = wm_bypass_info, 83962306a36Sopenharmony_ci .get = wm_bypass_get, 84062306a36Sopenharmony_ci .put = wm_bypass_put, 84162306a36Sopenharmony_ci }, 84262306a36Sopenharmony_ci { 84362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 84462306a36Sopenharmony_ci .name = "Swap Output Channels", 84562306a36Sopenharmony_ci .info = wm_chswap_info, 84662306a36Sopenharmony_ci .get = wm_chswap_get, 84762306a36Sopenharmony_ci .put = wm_chswap_put, 84862306a36Sopenharmony_ci }, 84962306a36Sopenharmony_ci { 85062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 85162306a36Sopenharmony_ci .name = "Analog Capture Source", 85262306a36Sopenharmony_ci .info = wm_adc_mux_enum_info, 85362306a36Sopenharmony_ci .get = wm_adc_mux_enum_get, 85462306a36Sopenharmony_ci .put = wm_adc_mux_enum_put, 85562306a36Sopenharmony_ci }, 85662306a36Sopenharmony_ci}; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci/* 85962306a36Sopenharmony_ci * WM codec registers 86062306a36Sopenharmony_ci */ 86162306a36Sopenharmony_cistatic void wm_proc_regs_write(struct snd_info_entry *entry, 86262306a36Sopenharmony_ci struct snd_info_buffer *buffer) 86362306a36Sopenharmony_ci{ 86462306a36Sopenharmony_ci struct snd_ice1712 *ice = entry->private_data; 86562306a36Sopenharmony_ci char line[64]; 86662306a36Sopenharmony_ci unsigned int reg, val; 86762306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 86862306a36Sopenharmony_ci while (!snd_info_get_line(buffer, line, sizeof(line))) { 86962306a36Sopenharmony_ci if (sscanf(line, "%x %x", ®, &val) != 2) 87062306a36Sopenharmony_ci continue; 87162306a36Sopenharmony_ci if (reg <= 0x17 && val <= 0xffff) 87262306a36Sopenharmony_ci wm_put(ice, reg, val); 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 87562306a36Sopenharmony_ci} 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_cistatic void wm_proc_regs_read(struct snd_info_entry *entry, 87862306a36Sopenharmony_ci struct snd_info_buffer *buffer) 87962306a36Sopenharmony_ci{ 88062306a36Sopenharmony_ci struct snd_ice1712 *ice = entry->private_data; 88162306a36Sopenharmony_ci int reg, val; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 88462306a36Sopenharmony_ci for (reg = 0; reg <= 0x17; reg++) { 88562306a36Sopenharmony_ci val = wm_get(ice, reg); 88662306a36Sopenharmony_ci snd_iprintf(buffer, "%02x = %04x\n", reg, val); 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 88962306a36Sopenharmony_ci} 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistatic void wm_proc_init(struct snd_ice1712 *ice) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci snd_card_rw_proc_new(ice->card, "wm_codec", ice, wm_proc_regs_read, 89462306a36Sopenharmony_ci wm_proc_regs_write); 89562306a36Sopenharmony_ci} 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_cistatic int prodigy_hifi_add_controls(struct snd_ice1712 *ice) 89862306a36Sopenharmony_ci{ 89962306a36Sopenharmony_ci unsigned int i; 90062306a36Sopenharmony_ci int err; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(prodigy_hifi_controls); i++) { 90362306a36Sopenharmony_ci err = snd_ctl_add(ice->card, 90462306a36Sopenharmony_ci snd_ctl_new1(&prodigy_hifi_controls[i], ice)); 90562306a36Sopenharmony_ci if (err < 0) 90662306a36Sopenharmony_ci return err; 90762306a36Sopenharmony_ci } 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci wm_proc_init(ice); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci return 0; 91262306a36Sopenharmony_ci} 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_cistatic int prodigy_hd2_add_controls(struct snd_ice1712 *ice) 91562306a36Sopenharmony_ci{ 91662306a36Sopenharmony_ci unsigned int i; 91762306a36Sopenharmony_ci int err; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(prodigy_hd2_controls); i++) { 92062306a36Sopenharmony_ci err = snd_ctl_add(ice->card, 92162306a36Sopenharmony_ci snd_ctl_new1(&prodigy_hd2_controls[i], ice)); 92262306a36Sopenharmony_ci if (err < 0) 92362306a36Sopenharmony_ci return err; 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci wm_proc_init(ice); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci return 0; 92962306a36Sopenharmony_ci} 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_cistatic void wm8766_init(struct snd_ice1712 *ice) 93262306a36Sopenharmony_ci{ 93362306a36Sopenharmony_ci static const unsigned short wm8766_inits[] = { 93462306a36Sopenharmony_ci WM8766_RESET, 0x0000, 93562306a36Sopenharmony_ci WM8766_DAC_CTRL, 0x0120, 93662306a36Sopenharmony_ci WM8766_INT_CTRL, 0x0022, /* I2S Normal Mode, 24 bit */ 93762306a36Sopenharmony_ci WM8766_DAC_CTRL2, 0x0001, 93862306a36Sopenharmony_ci WM8766_DAC_CTRL3, 0x0080, 93962306a36Sopenharmony_ci WM8766_LDA1, 0x0100, 94062306a36Sopenharmony_ci WM8766_LDA2, 0x0100, 94162306a36Sopenharmony_ci WM8766_LDA3, 0x0100, 94262306a36Sopenharmony_ci WM8766_RDA1, 0x0100, 94362306a36Sopenharmony_ci WM8766_RDA2, 0x0100, 94462306a36Sopenharmony_ci WM8766_RDA3, 0x0100, 94562306a36Sopenharmony_ci WM8766_MUTE1, 0x0000, 94662306a36Sopenharmony_ci WM8766_MUTE2, 0x0000, 94762306a36Sopenharmony_ci }; 94862306a36Sopenharmony_ci unsigned int i; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(wm8766_inits); i += 2) 95162306a36Sopenharmony_ci wm8766_spi_write(ice, wm8766_inits[i], wm8766_inits[i + 1]); 95262306a36Sopenharmony_ci} 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_cistatic void wm8776_init(struct snd_ice1712 *ice) 95562306a36Sopenharmony_ci{ 95662306a36Sopenharmony_ci static const unsigned short wm8776_inits[] = { 95762306a36Sopenharmony_ci /* These come first to reduce init pop noise */ 95862306a36Sopenharmony_ci WM_ADC_MUX, 0x0003, /* ADC mute */ 95962306a36Sopenharmony_ci /* 0x00c0 replaced by 0x0003 */ 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci WM_DAC_MUTE, 0x0001, /* DAC softmute */ 96262306a36Sopenharmony_ci WM_DAC_CTRL1, 0x0000, /* DAC mute */ 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci WM_POWERDOWN, 0x0008, /* All power-up except HP */ 96562306a36Sopenharmony_ci WM_RESET, 0x0000, /* reset */ 96662306a36Sopenharmony_ci }; 96762306a36Sopenharmony_ci unsigned int i; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(wm8776_inits); i += 2) 97062306a36Sopenharmony_ci wm_put(ice, wm8776_inits[i], wm8776_inits[i + 1]); 97162306a36Sopenharmony_ci} 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 97462306a36Sopenharmony_cistatic int prodigy_hifi_resume(struct snd_ice1712 *ice) 97562306a36Sopenharmony_ci{ 97662306a36Sopenharmony_ci static const unsigned short wm8776_reinit_registers[] = { 97762306a36Sopenharmony_ci WM_MASTER_CTRL, 97862306a36Sopenharmony_ci WM_DAC_INT, 97962306a36Sopenharmony_ci WM_ADC_INT, 98062306a36Sopenharmony_ci WM_OUT_MUX, 98162306a36Sopenharmony_ci WM_HP_ATTEN_L, 98262306a36Sopenharmony_ci WM_HP_ATTEN_R, 98362306a36Sopenharmony_ci WM_PHASE_SWAP, 98462306a36Sopenharmony_ci WM_DAC_CTRL2, 98562306a36Sopenharmony_ci WM_ADC_ATTEN_L, 98662306a36Sopenharmony_ci WM_ADC_ATTEN_R, 98762306a36Sopenharmony_ci WM_ALC_CTRL1, 98862306a36Sopenharmony_ci WM_ALC_CTRL2, 98962306a36Sopenharmony_ci WM_ALC_CTRL3, 99062306a36Sopenharmony_ci WM_NOISE_GATE, 99162306a36Sopenharmony_ci WM_ADC_MUX, 99262306a36Sopenharmony_ci /* no DAC attenuation here */ 99362306a36Sopenharmony_ci }; 99462306a36Sopenharmony_ci struct prodigy_hifi_spec *spec = ice->spec; 99562306a36Sopenharmony_ci int i, ch; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci /* reinitialize WM8776 and re-apply old register values */ 100062306a36Sopenharmony_ci wm8776_init(ice); 100162306a36Sopenharmony_ci schedule_timeout_uninterruptible(1); 100262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(wm8776_reinit_registers); i++) 100362306a36Sopenharmony_ci wm_put(ice, wm8776_reinit_registers[i], 100462306a36Sopenharmony_ci wm_get(ice, wm8776_reinit_registers[i])); 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci /* reinitialize WM8766 and re-apply volumes for all DACs */ 100762306a36Sopenharmony_ci wm8766_init(ice); 100862306a36Sopenharmony_ci for (ch = 0; ch < 2; ch++) { 100962306a36Sopenharmony_ci wm_set_vol(ice, WM_DAC_ATTEN_L + ch, 101062306a36Sopenharmony_ci spec->vol[2 + ch], spec->master[ch]); 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci wm8766_set_vol(ice, WM8766_LDA1 + ch, 101362306a36Sopenharmony_ci spec->vol[0 + ch], spec->master[ch]); 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci wm8766_set_vol(ice, WM8766_LDA2 + ch, 101662306a36Sopenharmony_ci spec->vol[4 + ch], spec->master[ch]); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci wm8766_set_vol(ice, WM8766_LDA3 + ch, 101962306a36Sopenharmony_ci spec->vol[6 + ch], spec->master[ch]); 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci /* unmute WM8776 DAC */ 102362306a36Sopenharmony_ci wm_put(ice, WM_DAC_MUTE, 0x00); 102462306a36Sopenharmony_ci wm_put(ice, WM_DAC_CTRL1, 0x90); 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 102762306a36Sopenharmony_ci return 0; 102862306a36Sopenharmony_ci} 102962306a36Sopenharmony_ci#endif 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci/* 103262306a36Sopenharmony_ci * initialize the chip 103362306a36Sopenharmony_ci */ 103462306a36Sopenharmony_cistatic int prodigy_hifi_init(struct snd_ice1712 *ice) 103562306a36Sopenharmony_ci{ 103662306a36Sopenharmony_ci static const unsigned short wm8776_defaults[] = { 103762306a36Sopenharmony_ci WM_MASTER_CTRL, 0x0022, /* 256fs, slave mode */ 103862306a36Sopenharmony_ci WM_DAC_INT, 0x0022, /* I2S, normal polarity, 24bit */ 103962306a36Sopenharmony_ci WM_ADC_INT, 0x0022, /* I2S, normal polarity, 24bit */ 104062306a36Sopenharmony_ci WM_DAC_CTRL1, 0x0090, /* DAC L/R */ 104162306a36Sopenharmony_ci WM_OUT_MUX, 0x0001, /* OUT DAC */ 104262306a36Sopenharmony_ci WM_HP_ATTEN_L, 0x0179, /* HP 0dB */ 104362306a36Sopenharmony_ci WM_HP_ATTEN_R, 0x0179, /* HP 0dB */ 104462306a36Sopenharmony_ci WM_DAC_ATTEN_L, 0x0000, /* DAC 0dB */ 104562306a36Sopenharmony_ci WM_DAC_ATTEN_L, 0x0100, /* DAC 0dB */ 104662306a36Sopenharmony_ci WM_DAC_ATTEN_R, 0x0000, /* DAC 0dB */ 104762306a36Sopenharmony_ci WM_DAC_ATTEN_R, 0x0100, /* DAC 0dB */ 104862306a36Sopenharmony_ci WM_PHASE_SWAP, 0x0000, /* phase normal */ 104962306a36Sopenharmony_ci#if 0 105062306a36Sopenharmony_ci WM_DAC_MASTER, 0x0100, /* DAC master muted */ 105162306a36Sopenharmony_ci#endif 105262306a36Sopenharmony_ci WM_DAC_CTRL2, 0x0000, /* no deemphasis, no ZFLG */ 105362306a36Sopenharmony_ci WM_ADC_ATTEN_L, 0x0000, /* ADC muted */ 105462306a36Sopenharmony_ci WM_ADC_ATTEN_R, 0x0000, /* ADC muted */ 105562306a36Sopenharmony_ci#if 1 105662306a36Sopenharmony_ci WM_ALC_CTRL1, 0x007b, /* */ 105762306a36Sopenharmony_ci WM_ALC_CTRL2, 0x0000, /* */ 105862306a36Sopenharmony_ci WM_ALC_CTRL3, 0x0000, /* */ 105962306a36Sopenharmony_ci WM_NOISE_GATE, 0x0000, /* */ 106062306a36Sopenharmony_ci#endif 106162306a36Sopenharmony_ci WM_DAC_MUTE, 0x0000, /* DAC unmute */ 106262306a36Sopenharmony_ci WM_ADC_MUX, 0x0003, /* ADC unmute, both CD/Line On */ 106362306a36Sopenharmony_ci }; 106462306a36Sopenharmony_ci struct prodigy_hifi_spec *spec; 106562306a36Sopenharmony_ci unsigned int i; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci ice->vt1720 = 0; 106862306a36Sopenharmony_ci ice->vt1724 = 1; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci ice->num_total_dacs = 8; 107162306a36Sopenharmony_ci ice->num_total_adcs = 1; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci /* HACK - use this as the SPDIF source. 107462306a36Sopenharmony_ci * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten 107562306a36Sopenharmony_ci */ 107662306a36Sopenharmony_ci ice->gpio.saved[0] = 0; 107762306a36Sopenharmony_ci /* to remember the register values */ 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); 108062306a36Sopenharmony_ci if (! ice->akm) 108162306a36Sopenharmony_ci return -ENOMEM; 108262306a36Sopenharmony_ci ice->akm_codecs = 1; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci spec = kzalloc(sizeof(*spec), GFP_KERNEL); 108562306a36Sopenharmony_ci if (!spec) 108662306a36Sopenharmony_ci return -ENOMEM; 108762306a36Sopenharmony_ci ice->spec = spec; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci /* initialize WM8776 codec */ 109062306a36Sopenharmony_ci wm8776_init(ice); 109162306a36Sopenharmony_ci schedule_timeout_uninterruptible(1); 109262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(wm8776_defaults); i += 2) 109362306a36Sopenharmony_ci wm_put(ice, wm8776_defaults[i], wm8776_defaults[i + 1]); 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci wm8766_init(ice); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 109862306a36Sopenharmony_ci ice->pm_resume = &prodigy_hifi_resume; 109962306a36Sopenharmony_ci ice->pm_suspend_enabled = 1; 110062306a36Sopenharmony_ci#endif 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci return 0; 110362306a36Sopenharmony_ci} 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci/* 110762306a36Sopenharmony_ci * initialize the chip 110862306a36Sopenharmony_ci */ 110962306a36Sopenharmony_cistatic void ak4396_init(struct snd_ice1712 *ice) 111062306a36Sopenharmony_ci{ 111162306a36Sopenharmony_ci static const unsigned short ak4396_inits[] = { 111262306a36Sopenharmony_ci AK4396_CTRL1, 0x87, /* I2S Normal Mode, 24 bit */ 111362306a36Sopenharmony_ci AK4396_CTRL2, 0x02, 111462306a36Sopenharmony_ci AK4396_CTRL3, 0x00, 111562306a36Sopenharmony_ci AK4396_LCH_ATT, 0x00, 111662306a36Sopenharmony_ci AK4396_RCH_ATT, 0x00, 111762306a36Sopenharmony_ci }; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci unsigned int i; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci /* initialize ak4396 codec */ 112262306a36Sopenharmony_ci /* reset codec */ 112362306a36Sopenharmony_ci ak4396_write(ice, AK4396_CTRL1, 0x86); 112462306a36Sopenharmony_ci msleep(100); 112562306a36Sopenharmony_ci ak4396_write(ice, AK4396_CTRL1, 0x87); 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ak4396_inits); i += 2) 112862306a36Sopenharmony_ci ak4396_write(ice, ak4396_inits[i], ak4396_inits[i+1]); 112962306a36Sopenharmony_ci} 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 113262306a36Sopenharmony_cistatic int prodigy_hd2_resume(struct snd_ice1712 *ice) 113362306a36Sopenharmony_ci{ 113462306a36Sopenharmony_ci /* initialize ak4396 codec and restore previous mixer volumes */ 113562306a36Sopenharmony_ci struct prodigy_hifi_spec *spec = ice->spec; 113662306a36Sopenharmony_ci int i; 113762306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 113862306a36Sopenharmony_ci ak4396_init(ice); 113962306a36Sopenharmony_ci for (i = 0; i < 2; i++) 114062306a36Sopenharmony_ci ak4396_write(ice, AK4396_LCH_ATT + i, spec->vol[i] & 0xff); 114162306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 114262306a36Sopenharmony_ci return 0; 114362306a36Sopenharmony_ci} 114462306a36Sopenharmony_ci#endif 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_cistatic int prodigy_hd2_init(struct snd_ice1712 *ice) 114762306a36Sopenharmony_ci{ 114862306a36Sopenharmony_ci struct prodigy_hifi_spec *spec; 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci ice->vt1720 = 0; 115162306a36Sopenharmony_ci ice->vt1724 = 1; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci ice->num_total_dacs = 1; 115462306a36Sopenharmony_ci ice->num_total_adcs = 1; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci /* HACK - use this as the SPDIF source. 115762306a36Sopenharmony_ci * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten 115862306a36Sopenharmony_ci */ 115962306a36Sopenharmony_ci ice->gpio.saved[0] = 0; 116062306a36Sopenharmony_ci /* to remember the register values */ 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); 116362306a36Sopenharmony_ci if (! ice->akm) 116462306a36Sopenharmony_ci return -ENOMEM; 116562306a36Sopenharmony_ci ice->akm_codecs = 1; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci spec = kzalloc(sizeof(*spec), GFP_KERNEL); 116862306a36Sopenharmony_ci if (!spec) 116962306a36Sopenharmony_ci return -ENOMEM; 117062306a36Sopenharmony_ci ice->spec = spec; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 117362306a36Sopenharmony_ci ice->pm_resume = &prodigy_hd2_resume; 117462306a36Sopenharmony_ci ice->pm_suspend_enabled = 1; 117562306a36Sopenharmony_ci#endif 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci ak4396_init(ice); 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci return 0; 118062306a36Sopenharmony_ci} 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_cistatic const unsigned char prodigy71hifi_eeprom[] = { 118462306a36Sopenharmony_ci 0x4b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */ 118562306a36Sopenharmony_ci 0x80, /* ACLINK: I2S */ 118662306a36Sopenharmony_ci 0xfc, /* I2S: vol, 96k, 24bit, 192k */ 118762306a36Sopenharmony_ci 0xc3, /* SPDIF: out-en, out-int, spdif-in */ 118862306a36Sopenharmony_ci 0xff, /* GPIO_DIR */ 118962306a36Sopenharmony_ci 0xff, /* GPIO_DIR1 */ 119062306a36Sopenharmony_ci 0x5f, /* GPIO_DIR2 */ 119162306a36Sopenharmony_ci 0x00, /* GPIO_MASK */ 119262306a36Sopenharmony_ci 0x00, /* GPIO_MASK1 */ 119362306a36Sopenharmony_ci 0x00, /* GPIO_MASK2 */ 119462306a36Sopenharmony_ci 0x00, /* GPIO_STATE */ 119562306a36Sopenharmony_ci 0x00, /* GPIO_STATE1 */ 119662306a36Sopenharmony_ci 0x00, /* GPIO_STATE2 */ 119762306a36Sopenharmony_ci}; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_cistatic const unsigned char prodigyhd2_eeprom[] = { 120062306a36Sopenharmony_ci 0x4b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */ 120162306a36Sopenharmony_ci 0x80, /* ACLINK: I2S */ 120262306a36Sopenharmony_ci 0xfc, /* I2S: vol, 96k, 24bit, 192k */ 120362306a36Sopenharmony_ci 0xc3, /* SPDIF: out-en, out-int, spdif-in */ 120462306a36Sopenharmony_ci 0xff, /* GPIO_DIR */ 120562306a36Sopenharmony_ci 0xff, /* GPIO_DIR1 */ 120662306a36Sopenharmony_ci 0x5f, /* GPIO_DIR2 */ 120762306a36Sopenharmony_ci 0x00, /* GPIO_MASK */ 120862306a36Sopenharmony_ci 0x00, /* GPIO_MASK1 */ 120962306a36Sopenharmony_ci 0x00, /* GPIO_MASK2 */ 121062306a36Sopenharmony_ci 0x00, /* GPIO_STATE */ 121162306a36Sopenharmony_ci 0x00, /* GPIO_STATE1 */ 121262306a36Sopenharmony_ci 0x00, /* GPIO_STATE2 */ 121362306a36Sopenharmony_ci}; 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_cistatic const unsigned char fortissimo4_eeprom[] = { 121662306a36Sopenharmony_ci 0x43, /* SYSCONF: clock 512, ADC, 4DACs */ 121762306a36Sopenharmony_ci 0x80, /* ACLINK: I2S */ 121862306a36Sopenharmony_ci 0xfc, /* I2S: vol, 96k, 24bit, 192k */ 121962306a36Sopenharmony_ci 0xc1, /* SPDIF: out-en, out-int */ 122062306a36Sopenharmony_ci 0xff, /* GPIO_DIR */ 122162306a36Sopenharmony_ci 0xff, /* GPIO_DIR1 */ 122262306a36Sopenharmony_ci 0x5f, /* GPIO_DIR2 */ 122362306a36Sopenharmony_ci 0x00, /* GPIO_MASK */ 122462306a36Sopenharmony_ci 0x00, /* GPIO_MASK1 */ 122562306a36Sopenharmony_ci 0x00, /* GPIO_MASK2 */ 122662306a36Sopenharmony_ci 0x00, /* GPIO_STATE */ 122762306a36Sopenharmony_ci 0x00, /* GPIO_STATE1 */ 122862306a36Sopenharmony_ci 0x00, /* GPIO_STATE2 */ 122962306a36Sopenharmony_ci}; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci/* entry point */ 123262306a36Sopenharmony_cistruct snd_ice1712_card_info snd_vt1724_prodigy_hifi_cards[] = { 123362306a36Sopenharmony_ci { 123462306a36Sopenharmony_ci .subvendor = VT1724_SUBDEVICE_PRODIGY_HIFI, 123562306a36Sopenharmony_ci .name = "Audiotrak Prodigy 7.1 HiFi", 123662306a36Sopenharmony_ci .model = "prodigy71hifi", 123762306a36Sopenharmony_ci .chip_init = prodigy_hifi_init, 123862306a36Sopenharmony_ci .build_controls = prodigy_hifi_add_controls, 123962306a36Sopenharmony_ci .eeprom_size = sizeof(prodigy71hifi_eeprom), 124062306a36Sopenharmony_ci .eeprom_data = prodigy71hifi_eeprom, 124162306a36Sopenharmony_ci .driver = "Prodigy71HIFI", 124262306a36Sopenharmony_ci }, 124362306a36Sopenharmony_ci { 124462306a36Sopenharmony_ci .subvendor = VT1724_SUBDEVICE_PRODIGY_HD2, 124562306a36Sopenharmony_ci .name = "Audiotrak Prodigy HD2", 124662306a36Sopenharmony_ci .model = "prodigyhd2", 124762306a36Sopenharmony_ci .chip_init = prodigy_hd2_init, 124862306a36Sopenharmony_ci .build_controls = prodigy_hd2_add_controls, 124962306a36Sopenharmony_ci .eeprom_size = sizeof(prodigyhd2_eeprom), 125062306a36Sopenharmony_ci .eeprom_data = prodigyhd2_eeprom, 125162306a36Sopenharmony_ci .driver = "Prodigy71HD2", 125262306a36Sopenharmony_ci }, 125362306a36Sopenharmony_ci { 125462306a36Sopenharmony_ci .subvendor = VT1724_SUBDEVICE_FORTISSIMO4, 125562306a36Sopenharmony_ci .name = "Hercules Fortissimo IV", 125662306a36Sopenharmony_ci .model = "fortissimo4", 125762306a36Sopenharmony_ci .chip_init = prodigy_hifi_init, 125862306a36Sopenharmony_ci .build_controls = prodigy_hifi_add_controls, 125962306a36Sopenharmony_ci .eeprom_size = sizeof(fortissimo4_eeprom), 126062306a36Sopenharmony_ci .eeprom_data = fortissimo4_eeprom, 126162306a36Sopenharmony_ci .driver = "Fortissimo4", 126262306a36Sopenharmony_ci }, 126362306a36Sopenharmony_ci { } /* terminator */ 126462306a36Sopenharmony_ci}; 126562306a36Sopenharmony_ci 1266