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 Pontis MS300 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/interrupt.h> 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci#include <linux/mutex.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <sound/core.h> 1762306a36Sopenharmony_ci#include <sound/info.h> 1862306a36Sopenharmony_ci#include <sound/tlv.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "ice1712.h" 2162306a36Sopenharmony_ci#include "envy24ht.h" 2262306a36Sopenharmony_ci#include "pontis.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* I2C addresses */ 2562306a36Sopenharmony_ci#define WM_DEV 0x34 2662306a36Sopenharmony_ci#define CS_DEV 0x20 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* WM8776 registers */ 2962306a36Sopenharmony_ci#define WM_HP_ATTEN_L 0x00 /* headphone left attenuation */ 3062306a36Sopenharmony_ci#define WM_HP_ATTEN_R 0x01 /* headphone left attenuation */ 3162306a36Sopenharmony_ci#define WM_HP_MASTER 0x02 /* headphone master (both channels) */ 3262306a36Sopenharmony_ci /* override LLR */ 3362306a36Sopenharmony_ci#define WM_DAC_ATTEN_L 0x03 /* digital left attenuation */ 3462306a36Sopenharmony_ci#define WM_DAC_ATTEN_R 0x04 3562306a36Sopenharmony_ci#define WM_DAC_MASTER 0x05 3662306a36Sopenharmony_ci#define WM_PHASE_SWAP 0x06 /* DAC phase swap */ 3762306a36Sopenharmony_ci#define WM_DAC_CTRL1 0x07 3862306a36Sopenharmony_ci#define WM_DAC_MUTE 0x08 3962306a36Sopenharmony_ci#define WM_DAC_CTRL2 0x09 4062306a36Sopenharmony_ci#define WM_DAC_INT 0x0a 4162306a36Sopenharmony_ci#define WM_ADC_INT 0x0b 4262306a36Sopenharmony_ci#define WM_MASTER_CTRL 0x0c 4362306a36Sopenharmony_ci#define WM_POWERDOWN 0x0d 4462306a36Sopenharmony_ci#define WM_ADC_ATTEN_L 0x0e 4562306a36Sopenharmony_ci#define WM_ADC_ATTEN_R 0x0f 4662306a36Sopenharmony_ci#define WM_ALC_CTRL1 0x10 4762306a36Sopenharmony_ci#define WM_ALC_CTRL2 0x11 4862306a36Sopenharmony_ci#define WM_ALC_CTRL3 0x12 4962306a36Sopenharmony_ci#define WM_NOISE_GATE 0x13 5062306a36Sopenharmony_ci#define WM_LIMITER 0x14 5162306a36Sopenharmony_ci#define WM_ADC_MUX 0x15 5262306a36Sopenharmony_ci#define WM_OUT_MUX 0x16 5362306a36Sopenharmony_ci#define WM_RESET 0x17 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* 5662306a36Sopenharmony_ci * GPIO 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_ci#define PONTIS_CS_CS (1<<4) /* CS */ 5962306a36Sopenharmony_ci#define PONTIS_CS_CLK (1<<5) /* CLK */ 6062306a36Sopenharmony_ci#define PONTIS_CS_RDATA (1<<6) /* CS8416 -> VT1720 */ 6162306a36Sopenharmony_ci#define PONTIS_CS_WDATA (1<<7) /* VT1720 -> CS8416 */ 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* 6562306a36Sopenharmony_ci * get the current register value of WM codec 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_cistatic unsigned short wm_get(struct snd_ice1712 *ice, int reg) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci reg <<= 1; 7062306a36Sopenharmony_ci return ((unsigned short)ice->akm[0].images[reg] << 8) | 7162306a36Sopenharmony_ci ice->akm[0].images[reg + 1]; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* 7562306a36Sopenharmony_ci * set the register value of WM codec and remember it 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_cistatic void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci unsigned short cval; 8062306a36Sopenharmony_ci cval = (reg << 9) | val; 8162306a36Sopenharmony_ci snd_vt1724_write_i2c(ice, WM_DEV, cval >> 8, cval & 0xff); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci wm_put_nocache(ice, reg, val); 8762306a36Sopenharmony_ci reg <<= 1; 8862306a36Sopenharmony_ci ice->akm[0].images[reg] = val >> 8; 8962306a36Sopenharmony_ci ice->akm[0].images[reg + 1] = val; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* 9362306a36Sopenharmony_ci * DAC volume attenuation mixer control (-64dB to 0dB) 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci#define DAC_0dB 0xff 9762306a36Sopenharmony_ci#define DAC_RES 128 9862306a36Sopenharmony_ci#define DAC_MIN (DAC_0dB - DAC_RES) 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic int wm_dac_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 10362306a36Sopenharmony_ci uinfo->count = 2; 10462306a36Sopenharmony_ci uinfo->value.integer.min = 0; /* mute */ 10562306a36Sopenharmony_ci uinfo->value.integer.max = DAC_RES; /* 0dB, 0.5dB step */ 10662306a36Sopenharmony_ci return 0; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic int wm_dac_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 11262306a36Sopenharmony_ci unsigned short val; 11362306a36Sopenharmony_ci int i; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 11662306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 11762306a36Sopenharmony_ci val = wm_get(ice, WM_DAC_ATTEN_L + i) & 0xff; 11862306a36Sopenharmony_ci val = val > DAC_MIN ? (val - DAC_MIN) : 0; 11962306a36Sopenharmony_ci ucontrol->value.integer.value[i] = val; 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 12262306a36Sopenharmony_ci return 0; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic int wm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 12862306a36Sopenharmony_ci unsigned short oval, nval; 12962306a36Sopenharmony_ci int i, idx, change = 0; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 13262306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 13362306a36Sopenharmony_ci nval = ucontrol->value.integer.value[i]; 13462306a36Sopenharmony_ci nval = (nval ? (nval + DAC_MIN) : 0) & 0xff; 13562306a36Sopenharmony_ci idx = WM_DAC_ATTEN_L + i; 13662306a36Sopenharmony_ci oval = wm_get(ice, idx) & 0xff; 13762306a36Sopenharmony_ci if (oval != nval) { 13862306a36Sopenharmony_ci wm_put(ice, idx, nval); 13962306a36Sopenharmony_ci wm_put_nocache(ice, idx, nval | 0x100); 14062306a36Sopenharmony_ci change = 1; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 14462306a36Sopenharmony_ci return change; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/* 14862306a36Sopenharmony_ci * ADC gain mixer control (-64dB to 0dB) 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci#define ADC_0dB 0xcf 15262306a36Sopenharmony_ci#define ADC_RES 128 15362306a36Sopenharmony_ci#define ADC_MIN (ADC_0dB - ADC_RES) 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic int wm_adc_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 15862306a36Sopenharmony_ci uinfo->count = 2; 15962306a36Sopenharmony_ci uinfo->value.integer.min = 0; /* mute (-64dB) */ 16062306a36Sopenharmony_ci uinfo->value.integer.max = ADC_RES; /* 0dB, 0.5dB step */ 16162306a36Sopenharmony_ci return 0; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic int wm_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 16762306a36Sopenharmony_ci unsigned short val; 16862306a36Sopenharmony_ci int i; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 17162306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 17262306a36Sopenharmony_ci val = wm_get(ice, WM_ADC_ATTEN_L + i) & 0xff; 17362306a36Sopenharmony_ci val = val > ADC_MIN ? (val - ADC_MIN) : 0; 17462306a36Sopenharmony_ci ucontrol->value.integer.value[i] = val; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 17762306a36Sopenharmony_ci return 0; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 18362306a36Sopenharmony_ci unsigned short ovol, nvol; 18462306a36Sopenharmony_ci int i, idx, change = 0; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 18762306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 18862306a36Sopenharmony_ci nvol = ucontrol->value.integer.value[i]; 18962306a36Sopenharmony_ci nvol = nvol ? (nvol + ADC_MIN) : 0; 19062306a36Sopenharmony_ci idx = WM_ADC_ATTEN_L + i; 19162306a36Sopenharmony_ci ovol = wm_get(ice, idx) & 0xff; 19262306a36Sopenharmony_ci if (ovol != nvol) { 19362306a36Sopenharmony_ci wm_put(ice, idx, nvol); 19462306a36Sopenharmony_ci change = 1; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 19862306a36Sopenharmony_ci return change; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci/* 20262306a36Sopenharmony_ci * ADC input mux mixer control 20362306a36Sopenharmony_ci */ 20462306a36Sopenharmony_ci#define wm_adc_mux_info snd_ctl_boolean_mono_info 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 20962306a36Sopenharmony_ci int bit = kcontrol->private_value; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 21262306a36Sopenharmony_ci ucontrol->value.integer.value[0] = (wm_get(ice, WM_ADC_MUX) & (1 << bit)) ? 1 : 0; 21362306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 21462306a36Sopenharmony_ci return 0; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 22062306a36Sopenharmony_ci int bit = kcontrol->private_value; 22162306a36Sopenharmony_ci unsigned short oval, nval; 22262306a36Sopenharmony_ci int change; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 22562306a36Sopenharmony_ci nval = oval = wm_get(ice, WM_ADC_MUX); 22662306a36Sopenharmony_ci if (ucontrol->value.integer.value[0]) 22762306a36Sopenharmony_ci nval |= (1 << bit); 22862306a36Sopenharmony_ci else 22962306a36Sopenharmony_ci nval &= ~(1 << bit); 23062306a36Sopenharmony_ci change = nval != oval; 23162306a36Sopenharmony_ci if (change) { 23262306a36Sopenharmony_ci wm_put(ice, WM_ADC_MUX, nval); 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 23562306a36Sopenharmony_ci return change; 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci/* 23962306a36Sopenharmony_ci * Analog bypass (In -> Out) 24062306a36Sopenharmony_ci */ 24162306a36Sopenharmony_ci#define wm_bypass_info snd_ctl_boolean_mono_info 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic int wm_bypass_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 24862306a36Sopenharmony_ci ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX) & 0x04) ? 1 : 0; 24962306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 25062306a36Sopenharmony_ci return 0; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic int wm_bypass_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 25662306a36Sopenharmony_ci unsigned short val, oval; 25762306a36Sopenharmony_ci int change = 0; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 26062306a36Sopenharmony_ci val = oval = wm_get(ice, WM_OUT_MUX); 26162306a36Sopenharmony_ci if (ucontrol->value.integer.value[0]) 26262306a36Sopenharmony_ci val |= 0x04; 26362306a36Sopenharmony_ci else 26462306a36Sopenharmony_ci val &= ~0x04; 26562306a36Sopenharmony_ci if (val != oval) { 26662306a36Sopenharmony_ci wm_put(ice, WM_OUT_MUX, val); 26762306a36Sopenharmony_ci change = 1; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 27062306a36Sopenharmony_ci return change; 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci/* 27462306a36Sopenharmony_ci * Left/Right swap 27562306a36Sopenharmony_ci */ 27662306a36Sopenharmony_ci#define wm_chswap_info snd_ctl_boolean_mono_info 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic int wm_chswap_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 28362306a36Sopenharmony_ci ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL1) & 0xf0) != 0x90; 28462306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 28562306a36Sopenharmony_ci return 0; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic int wm_chswap_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 29162306a36Sopenharmony_ci unsigned short val, oval; 29262306a36Sopenharmony_ci int change = 0; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 29562306a36Sopenharmony_ci oval = wm_get(ice, WM_DAC_CTRL1); 29662306a36Sopenharmony_ci val = oval & 0x0f; 29762306a36Sopenharmony_ci if (ucontrol->value.integer.value[0]) 29862306a36Sopenharmony_ci val |= 0x60; 29962306a36Sopenharmony_ci else 30062306a36Sopenharmony_ci val |= 0x90; 30162306a36Sopenharmony_ci if (val != oval) { 30262306a36Sopenharmony_ci wm_put(ice, WM_DAC_CTRL1, val); 30362306a36Sopenharmony_ci wm_put_nocache(ice, WM_DAC_CTRL1, val); 30462306a36Sopenharmony_ci change = 1; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 30762306a36Sopenharmony_ci return change; 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci/* 31162306a36Sopenharmony_ci * write data in the SPI mode 31262306a36Sopenharmony_ci */ 31362306a36Sopenharmony_cistatic void set_gpio_bit(struct snd_ice1712 *ice, unsigned int bit, int val) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci unsigned int tmp = snd_ice1712_gpio_read(ice); 31662306a36Sopenharmony_ci if (val) 31762306a36Sopenharmony_ci tmp |= bit; 31862306a36Sopenharmony_ci else 31962306a36Sopenharmony_ci tmp &= ~bit; 32062306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic void spi_send_byte(struct snd_ice1712 *ice, unsigned char data) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci int i; 32662306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 32762306a36Sopenharmony_ci set_gpio_bit(ice, PONTIS_CS_CLK, 0); 32862306a36Sopenharmony_ci udelay(1); 32962306a36Sopenharmony_ci set_gpio_bit(ice, PONTIS_CS_WDATA, data & 0x80); 33062306a36Sopenharmony_ci udelay(1); 33162306a36Sopenharmony_ci set_gpio_bit(ice, PONTIS_CS_CLK, 1); 33262306a36Sopenharmony_ci udelay(1); 33362306a36Sopenharmony_ci data <<= 1; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic unsigned int spi_read_byte(struct snd_ice1712 *ice) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci int i; 34062306a36Sopenharmony_ci unsigned int val = 0; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci for (i = 0; i < 8; i++) { 34362306a36Sopenharmony_ci val <<= 1; 34462306a36Sopenharmony_ci set_gpio_bit(ice, PONTIS_CS_CLK, 0); 34562306a36Sopenharmony_ci udelay(1); 34662306a36Sopenharmony_ci if (snd_ice1712_gpio_read(ice) & PONTIS_CS_RDATA) 34762306a36Sopenharmony_ci val |= 1; 34862306a36Sopenharmony_ci udelay(1); 34962306a36Sopenharmony_ci set_gpio_bit(ice, PONTIS_CS_CLK, 1); 35062306a36Sopenharmony_ci udelay(1); 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci return val; 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic void spi_write(struct snd_ice1712 *ice, unsigned int dev, unsigned int reg, unsigned int data) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci snd_ice1712_gpio_set_dir(ice, PONTIS_CS_CS|PONTIS_CS_WDATA|PONTIS_CS_CLK); 35962306a36Sopenharmony_ci snd_ice1712_gpio_set_mask(ice, ~(PONTIS_CS_CS|PONTIS_CS_WDATA|PONTIS_CS_CLK)); 36062306a36Sopenharmony_ci set_gpio_bit(ice, PONTIS_CS_CS, 0); 36162306a36Sopenharmony_ci spi_send_byte(ice, dev & ~1); /* WRITE */ 36262306a36Sopenharmony_ci spi_send_byte(ice, reg); /* MAP */ 36362306a36Sopenharmony_ci spi_send_byte(ice, data); /* DATA */ 36462306a36Sopenharmony_ci /* trigger */ 36562306a36Sopenharmony_ci set_gpio_bit(ice, PONTIS_CS_CS, 1); 36662306a36Sopenharmony_ci udelay(1); 36762306a36Sopenharmony_ci /* restore */ 36862306a36Sopenharmony_ci snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask); 36962306a36Sopenharmony_ci snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic unsigned int spi_read(struct snd_ice1712 *ice, unsigned int dev, unsigned int reg) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci unsigned int val; 37562306a36Sopenharmony_ci snd_ice1712_gpio_set_dir(ice, PONTIS_CS_CS|PONTIS_CS_WDATA|PONTIS_CS_CLK); 37662306a36Sopenharmony_ci snd_ice1712_gpio_set_mask(ice, ~(PONTIS_CS_CS|PONTIS_CS_WDATA|PONTIS_CS_CLK)); 37762306a36Sopenharmony_ci set_gpio_bit(ice, PONTIS_CS_CS, 0); 37862306a36Sopenharmony_ci spi_send_byte(ice, dev & ~1); /* WRITE */ 37962306a36Sopenharmony_ci spi_send_byte(ice, reg); /* MAP */ 38062306a36Sopenharmony_ci /* trigger */ 38162306a36Sopenharmony_ci set_gpio_bit(ice, PONTIS_CS_CS, 1); 38262306a36Sopenharmony_ci udelay(1); 38362306a36Sopenharmony_ci set_gpio_bit(ice, PONTIS_CS_CS, 0); 38462306a36Sopenharmony_ci spi_send_byte(ice, dev | 1); /* READ */ 38562306a36Sopenharmony_ci val = spi_read_byte(ice); 38662306a36Sopenharmony_ci /* trigger */ 38762306a36Sopenharmony_ci set_gpio_bit(ice, PONTIS_CS_CS, 1); 38862306a36Sopenharmony_ci udelay(1); 38962306a36Sopenharmony_ci /* restore */ 39062306a36Sopenharmony_ci snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask); 39162306a36Sopenharmony_ci snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); 39262306a36Sopenharmony_ci return val; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci/* 39762306a36Sopenharmony_ci * SPDIF input source 39862306a36Sopenharmony_ci */ 39962306a36Sopenharmony_cistatic int cs_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci static const char * const texts[] = { 40262306a36Sopenharmony_ci "Coax", /* RXP0 */ 40362306a36Sopenharmony_ci "Optical", /* RXP1 */ 40462306a36Sopenharmony_ci "CD", /* RXP2 */ 40562306a36Sopenharmony_ci }; 40662306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 3, texts); 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic int cs_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 41462306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = ice->gpio.saved[0]; 41562306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 41662306a36Sopenharmony_ci return 0; 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic int cs_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 42262306a36Sopenharmony_ci unsigned char val; 42362306a36Sopenharmony_ci int change = 0; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 42662306a36Sopenharmony_ci if (ucontrol->value.enumerated.item[0] != ice->gpio.saved[0]) { 42762306a36Sopenharmony_ci ice->gpio.saved[0] = ucontrol->value.enumerated.item[0] & 3; 42862306a36Sopenharmony_ci val = 0x80 | (ice->gpio.saved[0] << 3); 42962306a36Sopenharmony_ci spi_write(ice, CS_DEV, 0x04, val); 43062306a36Sopenharmony_ci change = 1; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 43362306a36Sopenharmony_ci return change; 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci/* 43862306a36Sopenharmony_ci * GPIO controls 43962306a36Sopenharmony_ci */ 44062306a36Sopenharmony_cistatic int pontis_gpio_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 44362306a36Sopenharmony_ci uinfo->count = 1; 44462306a36Sopenharmony_ci uinfo->value.integer.min = 0; 44562306a36Sopenharmony_ci uinfo->value.integer.max = 0xffff; /* 16bit */ 44662306a36Sopenharmony_ci return 0; 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic int pontis_gpio_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 45262306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 45362306a36Sopenharmony_ci /* 4-7 reserved */ 45462306a36Sopenharmony_ci ucontrol->value.integer.value[0] = (~ice->gpio.write_mask & 0xffff) | 0x00f0; 45562306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 45662306a36Sopenharmony_ci return 0; 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic int pontis_gpio_mask_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 46262306a36Sopenharmony_ci unsigned int val; 46362306a36Sopenharmony_ci int changed; 46462306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 46562306a36Sopenharmony_ci /* 4-7 reserved */ 46662306a36Sopenharmony_ci val = (~ucontrol->value.integer.value[0] & 0xffff) | 0x00f0; 46762306a36Sopenharmony_ci changed = val != ice->gpio.write_mask; 46862306a36Sopenharmony_ci ice->gpio.write_mask = val; 46962306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 47062306a36Sopenharmony_ci return changed; 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_cistatic int pontis_gpio_dir_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 47662306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 47762306a36Sopenharmony_ci /* 4-7 reserved */ 47862306a36Sopenharmony_ci ucontrol->value.integer.value[0] = ice->gpio.direction & 0xff0f; 47962306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 48062306a36Sopenharmony_ci return 0; 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic int pontis_gpio_dir_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 48662306a36Sopenharmony_ci unsigned int val; 48762306a36Sopenharmony_ci int changed; 48862306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 48962306a36Sopenharmony_ci /* 4-7 reserved */ 49062306a36Sopenharmony_ci val = ucontrol->value.integer.value[0] & 0xff0f; 49162306a36Sopenharmony_ci changed = (val != ice->gpio.direction); 49262306a36Sopenharmony_ci ice->gpio.direction = val; 49362306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 49462306a36Sopenharmony_ci return changed; 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic int pontis_gpio_data_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 50062306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 50162306a36Sopenharmony_ci snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); 50262306a36Sopenharmony_ci snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask); 50362306a36Sopenharmony_ci ucontrol->value.integer.value[0] = snd_ice1712_gpio_read(ice) & 0xffff; 50462306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 50562306a36Sopenharmony_ci return 0; 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic int pontis_gpio_data_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 51162306a36Sopenharmony_ci unsigned int val, nval; 51262306a36Sopenharmony_ci int changed = 0; 51362306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 51462306a36Sopenharmony_ci snd_ice1712_gpio_set_dir(ice, ice->gpio.direction); 51562306a36Sopenharmony_ci snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask); 51662306a36Sopenharmony_ci val = snd_ice1712_gpio_read(ice) & 0xffff; 51762306a36Sopenharmony_ci nval = ucontrol->value.integer.value[0] & 0xffff; 51862306a36Sopenharmony_ci if (val != nval) { 51962306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, nval); 52062306a36Sopenharmony_ci changed = 1; 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 52362306a36Sopenharmony_ci return changed; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_volume, -6400, 50, 1); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci/* 52962306a36Sopenharmony_ci * mixers 53062306a36Sopenharmony_ci */ 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic const struct snd_kcontrol_new pontis_controls[] = { 53362306a36Sopenharmony_ci { 53462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 53562306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 53662306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 53762306a36Sopenharmony_ci .name = "PCM Playback Volume", 53862306a36Sopenharmony_ci .info = wm_dac_vol_info, 53962306a36Sopenharmony_ci .get = wm_dac_vol_get, 54062306a36Sopenharmony_ci .put = wm_dac_vol_put, 54162306a36Sopenharmony_ci .tlv = { .p = db_scale_volume }, 54262306a36Sopenharmony_ci }, 54362306a36Sopenharmony_ci { 54462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 54562306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 54662306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 54762306a36Sopenharmony_ci .name = "Capture Volume", 54862306a36Sopenharmony_ci .info = wm_adc_vol_info, 54962306a36Sopenharmony_ci .get = wm_adc_vol_get, 55062306a36Sopenharmony_ci .put = wm_adc_vol_put, 55162306a36Sopenharmony_ci .tlv = { .p = db_scale_volume }, 55262306a36Sopenharmony_ci }, 55362306a36Sopenharmony_ci { 55462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 55562306a36Sopenharmony_ci .name = "CD Capture Switch", 55662306a36Sopenharmony_ci .info = wm_adc_mux_info, 55762306a36Sopenharmony_ci .get = wm_adc_mux_get, 55862306a36Sopenharmony_ci .put = wm_adc_mux_put, 55962306a36Sopenharmony_ci .private_value = 0, 56062306a36Sopenharmony_ci }, 56162306a36Sopenharmony_ci { 56262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 56362306a36Sopenharmony_ci .name = "Line Capture Switch", 56462306a36Sopenharmony_ci .info = wm_adc_mux_info, 56562306a36Sopenharmony_ci .get = wm_adc_mux_get, 56662306a36Sopenharmony_ci .put = wm_adc_mux_put, 56762306a36Sopenharmony_ci .private_value = 1, 56862306a36Sopenharmony_ci }, 56962306a36Sopenharmony_ci { 57062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 57162306a36Sopenharmony_ci .name = "Analog Bypass Switch", 57262306a36Sopenharmony_ci .info = wm_bypass_info, 57362306a36Sopenharmony_ci .get = wm_bypass_get, 57462306a36Sopenharmony_ci .put = wm_bypass_put, 57562306a36Sopenharmony_ci }, 57662306a36Sopenharmony_ci { 57762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 57862306a36Sopenharmony_ci .name = "Swap Output Channels", 57962306a36Sopenharmony_ci .info = wm_chswap_info, 58062306a36Sopenharmony_ci .get = wm_chswap_get, 58162306a36Sopenharmony_ci .put = wm_chswap_put, 58262306a36Sopenharmony_ci }, 58362306a36Sopenharmony_ci { 58462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 58562306a36Sopenharmony_ci .name = "IEC958 Input Source", 58662306a36Sopenharmony_ci .info = cs_source_info, 58762306a36Sopenharmony_ci .get = cs_source_get, 58862306a36Sopenharmony_ci .put = cs_source_put, 58962306a36Sopenharmony_ci }, 59062306a36Sopenharmony_ci /* FIXME: which interface? */ 59162306a36Sopenharmony_ci { 59262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_CARD, 59362306a36Sopenharmony_ci .name = "GPIO Mask", 59462306a36Sopenharmony_ci .info = pontis_gpio_mask_info, 59562306a36Sopenharmony_ci .get = pontis_gpio_mask_get, 59662306a36Sopenharmony_ci .put = pontis_gpio_mask_put, 59762306a36Sopenharmony_ci }, 59862306a36Sopenharmony_ci { 59962306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_CARD, 60062306a36Sopenharmony_ci .name = "GPIO Direction", 60162306a36Sopenharmony_ci .info = pontis_gpio_mask_info, 60262306a36Sopenharmony_ci .get = pontis_gpio_dir_get, 60362306a36Sopenharmony_ci .put = pontis_gpio_dir_put, 60462306a36Sopenharmony_ci }, 60562306a36Sopenharmony_ci { 60662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_CARD, 60762306a36Sopenharmony_ci .name = "GPIO Data", 60862306a36Sopenharmony_ci .info = pontis_gpio_mask_info, 60962306a36Sopenharmony_ci .get = pontis_gpio_data_get, 61062306a36Sopenharmony_ci .put = pontis_gpio_data_put, 61162306a36Sopenharmony_ci }, 61262306a36Sopenharmony_ci}; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci/* 61662306a36Sopenharmony_ci * WM codec registers 61762306a36Sopenharmony_ci */ 61862306a36Sopenharmony_cistatic void wm_proc_regs_write(struct snd_info_entry *entry, struct snd_info_buffer *buffer) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci struct snd_ice1712 *ice = entry->private_data; 62162306a36Sopenharmony_ci char line[64]; 62262306a36Sopenharmony_ci unsigned int reg, val; 62362306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 62462306a36Sopenharmony_ci while (!snd_info_get_line(buffer, line, sizeof(line))) { 62562306a36Sopenharmony_ci if (sscanf(line, "%x %x", ®, &val) != 2) 62662306a36Sopenharmony_ci continue; 62762306a36Sopenharmony_ci if (reg <= 0x17 && val <= 0xffff) 62862306a36Sopenharmony_ci wm_put(ice, reg, val); 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_cistatic void wm_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) 63462306a36Sopenharmony_ci{ 63562306a36Sopenharmony_ci struct snd_ice1712 *ice = entry->private_data; 63662306a36Sopenharmony_ci int reg, val; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 63962306a36Sopenharmony_ci for (reg = 0; reg <= 0x17; reg++) { 64062306a36Sopenharmony_ci val = wm_get(ice, reg); 64162306a36Sopenharmony_ci snd_iprintf(buffer, "%02x = %04x\n", reg, val); 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cistatic void wm_proc_init(struct snd_ice1712 *ice) 64762306a36Sopenharmony_ci{ 64862306a36Sopenharmony_ci snd_card_rw_proc_new(ice->card, "wm_codec", ice, wm_proc_regs_read, 64962306a36Sopenharmony_ci wm_proc_regs_write); 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic void cs_proc_regs_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci struct snd_ice1712 *ice = entry->private_data; 65562306a36Sopenharmony_ci int reg, val; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 65862306a36Sopenharmony_ci for (reg = 0; reg <= 0x26; reg++) { 65962306a36Sopenharmony_ci val = spi_read(ice, CS_DEV, reg); 66062306a36Sopenharmony_ci snd_iprintf(buffer, "%02x = %02x\n", reg, val); 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci val = spi_read(ice, CS_DEV, 0x7f); 66362306a36Sopenharmony_ci snd_iprintf(buffer, "%02x = %02x\n", 0x7f, val); 66462306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 66562306a36Sopenharmony_ci} 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_cistatic void cs_proc_init(struct snd_ice1712 *ice) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci snd_card_ro_proc_new(ice->card, "cs_codec", ice, cs_proc_regs_read); 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic int pontis_add_controls(struct snd_ice1712 *ice) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci unsigned int i; 67662306a36Sopenharmony_ci int err; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pontis_controls); i++) { 67962306a36Sopenharmony_ci err = snd_ctl_add(ice->card, snd_ctl_new1(&pontis_controls[i], ice)); 68062306a36Sopenharmony_ci if (err < 0) 68162306a36Sopenharmony_ci return err; 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci wm_proc_init(ice); 68562306a36Sopenharmony_ci cs_proc_init(ice); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci return 0; 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci/* 69262306a36Sopenharmony_ci * initialize the chip 69362306a36Sopenharmony_ci */ 69462306a36Sopenharmony_cistatic int pontis_init(struct snd_ice1712 *ice) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci static const unsigned short wm_inits[] = { 69762306a36Sopenharmony_ci /* These come first to reduce init pop noise */ 69862306a36Sopenharmony_ci WM_ADC_MUX, 0x00c0, /* ADC mute */ 69962306a36Sopenharmony_ci WM_DAC_MUTE, 0x0001, /* DAC softmute */ 70062306a36Sopenharmony_ci WM_DAC_CTRL1, 0x0000, /* DAC mute */ 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci WM_POWERDOWN, 0x0008, /* All power-up except HP */ 70362306a36Sopenharmony_ci WM_RESET, 0x0000, /* reset */ 70462306a36Sopenharmony_ci }; 70562306a36Sopenharmony_ci static const unsigned short wm_inits2[] = { 70662306a36Sopenharmony_ci WM_MASTER_CTRL, 0x0022, /* 256fs, slave mode */ 70762306a36Sopenharmony_ci WM_DAC_INT, 0x0022, /* I2S, normal polarity, 24bit */ 70862306a36Sopenharmony_ci WM_ADC_INT, 0x0022, /* I2S, normal polarity, 24bit */ 70962306a36Sopenharmony_ci WM_DAC_CTRL1, 0x0090, /* DAC L/R */ 71062306a36Sopenharmony_ci WM_OUT_MUX, 0x0001, /* OUT DAC */ 71162306a36Sopenharmony_ci WM_HP_ATTEN_L, 0x0179, /* HP 0dB */ 71262306a36Sopenharmony_ci WM_HP_ATTEN_R, 0x0179, /* HP 0dB */ 71362306a36Sopenharmony_ci WM_DAC_ATTEN_L, 0x0000, /* DAC 0dB */ 71462306a36Sopenharmony_ci WM_DAC_ATTEN_L, 0x0100, /* DAC 0dB */ 71562306a36Sopenharmony_ci WM_DAC_ATTEN_R, 0x0000, /* DAC 0dB */ 71662306a36Sopenharmony_ci WM_DAC_ATTEN_R, 0x0100, /* DAC 0dB */ 71762306a36Sopenharmony_ci /* WM_DAC_MASTER, 0x0100, */ /* DAC master muted */ 71862306a36Sopenharmony_ci WM_PHASE_SWAP, 0x0000, /* phase normal */ 71962306a36Sopenharmony_ci WM_DAC_CTRL2, 0x0000, /* no deemphasis, no ZFLG */ 72062306a36Sopenharmony_ci WM_ADC_ATTEN_L, 0x0000, /* ADC muted */ 72162306a36Sopenharmony_ci WM_ADC_ATTEN_R, 0x0000, /* ADC muted */ 72262306a36Sopenharmony_ci#if 0 72362306a36Sopenharmony_ci WM_ALC_CTRL1, 0x007b, /* */ 72462306a36Sopenharmony_ci WM_ALC_CTRL2, 0x0000, /* */ 72562306a36Sopenharmony_ci WM_ALC_CTRL3, 0x0000, /* */ 72662306a36Sopenharmony_ci WM_NOISE_GATE, 0x0000, /* */ 72762306a36Sopenharmony_ci#endif 72862306a36Sopenharmony_ci WM_DAC_MUTE, 0x0000, /* DAC unmute */ 72962306a36Sopenharmony_ci WM_ADC_MUX, 0x0003, /* ADC unmute, both CD/Line On */ 73062306a36Sopenharmony_ci }; 73162306a36Sopenharmony_ci static const unsigned char cs_inits[] = { 73262306a36Sopenharmony_ci 0x04, 0x80, /* RUN, RXP0 */ 73362306a36Sopenharmony_ci 0x05, 0x05, /* slave, 24bit */ 73462306a36Sopenharmony_ci 0x01, 0x00, 73562306a36Sopenharmony_ci 0x02, 0x00, 73662306a36Sopenharmony_ci 0x03, 0x00, 73762306a36Sopenharmony_ci }; 73862306a36Sopenharmony_ci unsigned int i; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci ice->vt1720 = 1; 74162306a36Sopenharmony_ci ice->num_total_dacs = 2; 74262306a36Sopenharmony_ci ice->num_total_adcs = 2; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci /* to remember the register values */ 74562306a36Sopenharmony_ci ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); 74662306a36Sopenharmony_ci if (! ice->akm) 74762306a36Sopenharmony_ci return -ENOMEM; 74862306a36Sopenharmony_ci ice->akm_codecs = 1; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci /* HACK - use this as the SPDIF source. 75162306a36Sopenharmony_ci * don't call snd_ice1712_gpio_get/put(), otherwise it's overwritten 75262306a36Sopenharmony_ci */ 75362306a36Sopenharmony_ci ice->gpio.saved[0] = 0; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci /* initialize WM8776 codec */ 75662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2) 75762306a36Sopenharmony_ci wm_put(ice, wm_inits[i], wm_inits[i+1]); 75862306a36Sopenharmony_ci schedule_timeout_uninterruptible(1); 75962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(wm_inits2); i += 2) 76062306a36Sopenharmony_ci wm_put(ice, wm_inits2[i], wm_inits2[i+1]); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci /* initialize CS8416 codec */ 76362306a36Sopenharmony_ci /* assert PRST#; MT05 bit 7 */ 76462306a36Sopenharmony_ci outb(inb(ICEMT1724(ice, AC97_CMD)) | 0x80, ICEMT1724(ice, AC97_CMD)); 76562306a36Sopenharmony_ci mdelay(5); 76662306a36Sopenharmony_ci /* deassert PRST# */ 76762306a36Sopenharmony_ci outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD)); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cs_inits); i += 2) 77062306a36Sopenharmony_ci spi_write(ice, CS_DEV, cs_inits[i], cs_inits[i+1]); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci return 0; 77362306a36Sopenharmony_ci} 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci/* 77762306a36Sopenharmony_ci * Pontis boards don't provide the EEPROM data at all. 77862306a36Sopenharmony_ci * hence the driver needs to sets up it properly. 77962306a36Sopenharmony_ci */ 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_cistatic const unsigned char pontis_eeprom[] = { 78262306a36Sopenharmony_ci [ICE_EEP2_SYSCONF] = 0x08, /* clock 256, mpu401, spdif-in/ADC, 1DAC */ 78362306a36Sopenharmony_ci [ICE_EEP2_ACLINK] = 0x80, /* I2S */ 78462306a36Sopenharmony_ci [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */ 78562306a36Sopenharmony_ci [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ 78662306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR] = 0x07, 78762306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR1] = 0x00, 78862306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR2] = 0x00, /* ignored */ 78962306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK] = 0x0f, /* 4-7 reserved for CS8416 */ 79062306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK1] = 0xff, 79162306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK2] = 0x00, /* ignored */ 79262306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE] = 0x06, /* 0-low, 1-high, 2-high */ 79362306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE1] = 0x00, 79462306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE2] = 0x00, /* ignored */ 79562306a36Sopenharmony_ci}; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci/* entry point */ 79862306a36Sopenharmony_cistruct snd_ice1712_card_info snd_vt1720_pontis_cards[] = { 79962306a36Sopenharmony_ci { 80062306a36Sopenharmony_ci .subvendor = VT1720_SUBDEVICE_PONTIS_MS300, 80162306a36Sopenharmony_ci .name = "Pontis MS300", 80262306a36Sopenharmony_ci .model = "ms300", 80362306a36Sopenharmony_ci .chip_init = pontis_init, 80462306a36Sopenharmony_ci .build_controls = pontis_add_controls, 80562306a36Sopenharmony_ci .eeprom_size = sizeof(pontis_eeprom), 80662306a36Sopenharmony_ci .eeprom_data = pontis_eeprom, 80762306a36Sopenharmony_ci }, 80862306a36Sopenharmony_ci { } /* terminator */ 80962306a36Sopenharmony_ci}; 810