162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ALSA driver for ICEnsemble ICE1724 (Envy24) 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Lowlevel functions for Terratec PHASE 22 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (c) 2005 Misha Zhilin <misha@epiphan.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* PHASE 22 overview: 1162306a36Sopenharmony_ci * Audio controller: VIA Envy24HT-S (slightly trimmed down Envy24HT, 4in/4out) 1262306a36Sopenharmony_ci * Analog chip: AK4524 (partially via Philip's 74HCT125) 1362306a36Sopenharmony_ci * Digital receiver: CS8414-CS (supported in this release) 1462306a36Sopenharmony_ci * PHASE 22 revision 2.0 and Terrasoniq/Musonik TS22PCI have CS8416 1562306a36Sopenharmony_ci * (support status unknown, please test and report) 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Envy connects to AK4524 1862306a36Sopenharmony_ci * - CS directly from GPIO 10 1962306a36Sopenharmony_ci * - CCLK via 74HCT125's gate #4 from GPIO 4 2062306a36Sopenharmony_ci * - CDTI via 74HCT125's gate #2 from GPIO 5 2162306a36Sopenharmony_ci * CDTI may be completely blocked by 74HCT125's gate #1 2262306a36Sopenharmony_ci * controlled by GPIO 3 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* PHASE 28 overview: 2662306a36Sopenharmony_ci * Audio controller: VIA Envy24HT (full untrimmed version, 4in/8out) 2762306a36Sopenharmony_ci * Analog chip: WM8770 (8 channel 192k DAC, 2 channel 96k ADC) 2862306a36Sopenharmony_ci * Digital receiver: CS8414-CS (supported in this release) 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <linux/delay.h> 3262306a36Sopenharmony_ci#include <linux/interrupt.h> 3362306a36Sopenharmony_ci#include <linux/init.h> 3462306a36Sopenharmony_ci#include <linux/slab.h> 3562306a36Sopenharmony_ci#include <linux/mutex.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include <sound/core.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include "ice1712.h" 4062306a36Sopenharmony_ci#include "envy24ht.h" 4162306a36Sopenharmony_ci#include "phase.h" 4262306a36Sopenharmony_ci#include <sound/tlv.h> 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* AC97 register cache for Phase28 */ 4562306a36Sopenharmony_cistruct phase28_spec { 4662306a36Sopenharmony_ci unsigned short master[2]; 4762306a36Sopenharmony_ci unsigned short vol[8]; 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* WM8770 registers */ 5162306a36Sopenharmony_ci#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ 5262306a36Sopenharmony_ci#define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */ 5362306a36Sopenharmony_ci#define WM_DAC_DIG_ATTEN 0x09 /* DAC1-8 digital attenuation */ 5462306a36Sopenharmony_ci#define WM_DAC_DIG_MASTER_ATTEN 0x11 /* DAC master digital attenuation */ 5562306a36Sopenharmony_ci#define WM_PHASE_SWAP 0x12 /* DAC phase */ 5662306a36Sopenharmony_ci#define WM_DAC_CTRL1 0x13 /* DAC control bits */ 5762306a36Sopenharmony_ci#define WM_MUTE 0x14 /* mute controls */ 5862306a36Sopenharmony_ci#define WM_DAC_CTRL2 0x15 /* de-emphasis and zefo-flag */ 5962306a36Sopenharmony_ci#define WM_INT_CTRL 0x16 /* interface control */ 6062306a36Sopenharmony_ci#define WM_MASTER 0x17 /* master clock and mode */ 6162306a36Sopenharmony_ci#define WM_POWERDOWN 0x18 /* power-down controls */ 6262306a36Sopenharmony_ci#define WM_ADC_GAIN 0x19 /* ADC gain L(19)/R(1a) */ 6362306a36Sopenharmony_ci#define WM_ADC_MUX 0x1b /* input MUX */ 6462306a36Sopenharmony_ci#define WM_OUT_MUX1 0x1c /* output MUX */ 6562306a36Sopenharmony_ci#define WM_OUT_MUX2 0x1e /* output MUX */ 6662306a36Sopenharmony_ci#define WM_RESET 0x1f /* software reset */ 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* 7062306a36Sopenharmony_ci * Logarithmic volume values for WM8770 7162306a36Sopenharmony_ci * Computed as 20 * Log10(255 / x) 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_cistatic const unsigned char wm_vol[256] = { 7462306a36Sopenharmony_ci 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 7562306a36Sopenharmony_ci 24, 23, 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 7662306a36Sopenharmony_ci 17, 17, 17, 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 7762306a36Sopenharmony_ci 14, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 7862306a36Sopenharmony_ci 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 7962306a36Sopenharmony_ci 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 8062306a36Sopenharmony_ci 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 8162306a36Sopenharmony_ci 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8262306a36Sopenharmony_ci 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 8362306a36Sopenharmony_ci 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 8462306a36Sopenharmony_ci 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 8562306a36Sopenharmony_ci 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 8662306a36Sopenharmony_ci}; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#define WM_VOL_MAX (sizeof(wm_vol) - 1) 8962306a36Sopenharmony_ci#define WM_VOL_MUTE 0x8000 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic const struct snd_akm4xxx akm_phase22 = { 9262306a36Sopenharmony_ci .type = SND_AK4524, 9362306a36Sopenharmony_ci .num_dacs = 2, 9462306a36Sopenharmony_ci .num_adcs = 2, 9562306a36Sopenharmony_ci}; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic const struct snd_ak4xxx_private akm_phase22_priv = { 9862306a36Sopenharmony_ci .caddr = 2, 9962306a36Sopenharmony_ci .cif = 1, 10062306a36Sopenharmony_ci .data_mask = 1 << 4, 10162306a36Sopenharmony_ci .clk_mask = 1 << 5, 10262306a36Sopenharmony_ci .cs_mask = 1 << 10, 10362306a36Sopenharmony_ci .cs_addr = 1 << 10, 10462306a36Sopenharmony_ci .cs_none = 0, 10562306a36Sopenharmony_ci .add_flags = 1 << 3, 10662306a36Sopenharmony_ci .mask_flags = 0, 10762306a36Sopenharmony_ci}; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic int phase22_init(struct snd_ice1712 *ice) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct snd_akm4xxx *ak; 11262306a36Sopenharmony_ci int err; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci /* Configure DAC/ADC description for generic part of ice1724 */ 11562306a36Sopenharmony_ci switch (ice->eeprom.subvendor) { 11662306a36Sopenharmony_ci case VT1724_SUBDEVICE_PHASE22: 11762306a36Sopenharmony_ci case VT1724_SUBDEVICE_TS22: 11862306a36Sopenharmony_ci ice->num_total_dacs = 2; 11962306a36Sopenharmony_ci ice->num_total_adcs = 2; 12062306a36Sopenharmony_ci ice->vt1720 = 1; /* Envy24HT-S have 16 bit wide GPIO */ 12162306a36Sopenharmony_ci break; 12262306a36Sopenharmony_ci default: 12362306a36Sopenharmony_ci snd_BUG(); 12462306a36Sopenharmony_ci return -EINVAL; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* Initialize analog chips */ 12862306a36Sopenharmony_ci ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); 12962306a36Sopenharmony_ci ak = ice->akm; 13062306a36Sopenharmony_ci if (!ak) 13162306a36Sopenharmony_ci return -ENOMEM; 13262306a36Sopenharmony_ci ice->akm_codecs = 1; 13362306a36Sopenharmony_ci switch (ice->eeprom.subvendor) { 13462306a36Sopenharmony_ci case VT1724_SUBDEVICE_PHASE22: 13562306a36Sopenharmony_ci case VT1724_SUBDEVICE_TS22: 13662306a36Sopenharmony_ci err = snd_ice1712_akm4xxx_init(ak, &akm_phase22, 13762306a36Sopenharmony_ci &akm_phase22_priv, ice); 13862306a36Sopenharmony_ci if (err < 0) 13962306a36Sopenharmony_ci return err; 14062306a36Sopenharmony_ci break; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci return 0; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic int phase22_add_controls(struct snd_ice1712 *ice) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci int err = 0; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci switch (ice->eeprom.subvendor) { 15162306a36Sopenharmony_ci case VT1724_SUBDEVICE_PHASE22: 15262306a36Sopenharmony_ci case VT1724_SUBDEVICE_TS22: 15362306a36Sopenharmony_ci err = snd_ice1712_akm4xxx_build_controls(ice); 15462306a36Sopenharmony_ci if (err < 0) 15562306a36Sopenharmony_ci return err; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci return 0; 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic const unsigned char phase22_eeprom[] = { 16162306a36Sopenharmony_ci [ICE_EEP2_SYSCONF] = 0x28, /* clock 512, mpu 401, 16262306a36Sopenharmony_ci spdif-in/1xADC, 1xDACs */ 16362306a36Sopenharmony_ci [ICE_EEP2_ACLINK] = 0x80, /* I2S */ 16462306a36Sopenharmony_ci [ICE_EEP2_I2S] = 0xf0, /* vol, 96k, 24bit */ 16562306a36Sopenharmony_ci [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ 16662306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR] = 0xff, 16762306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR1] = 0xff, 16862306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR2] = 0xff, 16962306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK] = 0x00, 17062306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK1] = 0x00, 17162306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK2] = 0x00, 17262306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE] = 0x00, 17362306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE1] = 0x00, 17462306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE2] = 0x00, 17562306a36Sopenharmony_ci}; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic const unsigned char phase28_eeprom[] = { 17862306a36Sopenharmony_ci [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401, 17962306a36Sopenharmony_ci spdif-in/1xADC, 4xDACs */ 18062306a36Sopenharmony_ci [ICE_EEP2_ACLINK] = 0x80, /* I2S */ 18162306a36Sopenharmony_ci [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ 18262306a36Sopenharmony_ci [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ 18362306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR] = 0xff, 18462306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR1] = 0xff, 18562306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR2] = 0x5f, 18662306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK] = 0x00, 18762306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK1] = 0x00, 18862306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK2] = 0x00, 18962306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE] = 0x00, 19062306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE1] = 0x00, 19162306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE2] = 0x00, 19262306a36Sopenharmony_ci}; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci/* 19562306a36Sopenharmony_ci * write data in the SPI mode 19662306a36Sopenharmony_ci */ 19762306a36Sopenharmony_cistatic void phase28_spi_write(struct snd_ice1712 *ice, unsigned int cs, 19862306a36Sopenharmony_ci unsigned int data, int bits) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci unsigned int tmp; 20162306a36Sopenharmony_ci int i; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci tmp = snd_ice1712_gpio_read(ice); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RW|PHASE28_SPI_MOSI| 20662306a36Sopenharmony_ci PHASE28_SPI_CLK|PHASE28_WM_CS)); 20762306a36Sopenharmony_ci tmp |= PHASE28_WM_RW; 20862306a36Sopenharmony_ci tmp &= ~cs; 20962306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 21062306a36Sopenharmony_ci udelay(1); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci for (i = bits - 1; i >= 0; i--) { 21362306a36Sopenharmony_ci tmp &= ~PHASE28_SPI_CLK; 21462306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 21562306a36Sopenharmony_ci udelay(1); 21662306a36Sopenharmony_ci if (data & (1 << i)) 21762306a36Sopenharmony_ci tmp |= PHASE28_SPI_MOSI; 21862306a36Sopenharmony_ci else 21962306a36Sopenharmony_ci tmp &= ~PHASE28_SPI_MOSI; 22062306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 22162306a36Sopenharmony_ci udelay(1); 22262306a36Sopenharmony_ci tmp |= PHASE28_SPI_CLK; 22362306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 22462306a36Sopenharmony_ci udelay(1); 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci tmp &= ~PHASE28_SPI_CLK; 22862306a36Sopenharmony_ci tmp |= cs; 22962306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 23062306a36Sopenharmony_ci udelay(1); 23162306a36Sopenharmony_ci tmp |= PHASE28_SPI_CLK; 23262306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 23362306a36Sopenharmony_ci udelay(1); 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci/* 23762306a36Sopenharmony_ci * get the current register value of WM codec 23862306a36Sopenharmony_ci */ 23962306a36Sopenharmony_cistatic unsigned short wm_get(struct snd_ice1712 *ice, int reg) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci reg <<= 1; 24262306a36Sopenharmony_ci return ((unsigned short)ice->akm[0].images[reg] << 8) | 24362306a36Sopenharmony_ci ice->akm[0].images[reg + 1]; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci/* 24762306a36Sopenharmony_ci * set the register value of WM codec 24862306a36Sopenharmony_ci */ 24962306a36Sopenharmony_cistatic void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci phase28_spi_write(ice, PHASE28_WM_CS, (reg << 9) | (val & 0x1ff), 16); 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci/* 25562306a36Sopenharmony_ci * set the register value of WM codec and remember it 25662306a36Sopenharmony_ci */ 25762306a36Sopenharmony_cistatic void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci wm_put_nocache(ice, reg, val); 26062306a36Sopenharmony_ci reg <<= 1; 26162306a36Sopenharmony_ci ice->akm[0].images[reg] = val >> 8; 26262306a36Sopenharmony_ci ice->akm[0].images[reg + 1] = val; 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, 26662306a36Sopenharmony_ci unsigned short vol, unsigned short master) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci unsigned char nvol; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) 27162306a36Sopenharmony_ci nvol = 0; 27262306a36Sopenharmony_ci else 27362306a36Sopenharmony_ci nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) * 27462306a36Sopenharmony_ci (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX]; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci wm_put(ice, index, nvol); 27762306a36Sopenharmony_ci wm_put_nocache(ice, index, 0x180 | nvol); 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci/* 28162306a36Sopenharmony_ci * DAC mute control 28262306a36Sopenharmony_ci */ 28362306a36Sopenharmony_ci#define wm_pcm_mute_info snd_ctl_boolean_mono_info 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, 28662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 29162306a36Sopenharmony_ci ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 29262306a36Sopenharmony_ci 0 : 1; 29362306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 29462306a36Sopenharmony_ci return 0; 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic int wm_pcm_mute_put(struct snd_kcontrol *kcontrol, 29862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 30162306a36Sopenharmony_ci unsigned short nval, oval; 30262306a36Sopenharmony_ci int change; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 30562306a36Sopenharmony_ci oval = wm_get(ice, WM_MUTE); 30662306a36Sopenharmony_ci nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10); 30762306a36Sopenharmony_ci change = (nval != oval); 30862306a36Sopenharmony_ci if (change) 30962306a36Sopenharmony_ci wm_put(ice, WM_MUTE, nval); 31062306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci return change; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci/* 31662306a36Sopenharmony_ci * Master volume attenuation mixer control 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_cistatic int wm_master_vol_info(struct snd_kcontrol *kcontrol, 31962306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 32262306a36Sopenharmony_ci uinfo->count = 2; 32362306a36Sopenharmony_ci uinfo->value.integer.min = 0; 32462306a36Sopenharmony_ci uinfo->value.integer.max = WM_VOL_MAX; 32562306a36Sopenharmony_ci return 0; 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic int wm_master_vol_get(struct snd_kcontrol *kcontrol, 32962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 33262306a36Sopenharmony_ci struct phase28_spec *spec = ice->spec; 33362306a36Sopenharmony_ci int i; 33462306a36Sopenharmony_ci for (i = 0; i < 2; i++) 33562306a36Sopenharmony_ci ucontrol->value.integer.value[i] = spec->master[i] & 33662306a36Sopenharmony_ci ~WM_VOL_MUTE; 33762306a36Sopenharmony_ci return 0; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic int wm_master_vol_put(struct snd_kcontrol *kcontrol, 34162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 34462306a36Sopenharmony_ci struct phase28_spec *spec = ice->spec; 34562306a36Sopenharmony_ci int ch, change = 0; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 34862306a36Sopenharmony_ci for (ch = 0; ch < 2; ch++) { 34962306a36Sopenharmony_ci unsigned int vol = ucontrol->value.integer.value[ch]; 35062306a36Sopenharmony_ci if (vol > WM_VOL_MAX) 35162306a36Sopenharmony_ci continue; 35262306a36Sopenharmony_ci vol |= spec->master[ch] & WM_VOL_MUTE; 35362306a36Sopenharmony_ci if (vol != spec->master[ch]) { 35462306a36Sopenharmony_ci int dac; 35562306a36Sopenharmony_ci spec->master[ch] = vol; 35662306a36Sopenharmony_ci for (dac = 0; dac < ice->num_total_dacs; dac += 2) 35762306a36Sopenharmony_ci wm_set_vol(ice, WM_DAC_ATTEN + dac + ch, 35862306a36Sopenharmony_ci spec->vol[dac + ch], 35962306a36Sopenharmony_ci spec->master[ch]); 36062306a36Sopenharmony_ci change = 1; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 36462306a36Sopenharmony_ci return change; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic int phase28_init(struct snd_ice1712 *ice) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci static const unsigned short wm_inits_phase28[] = { 37062306a36Sopenharmony_ci /* These come first to reduce init pop noise */ 37162306a36Sopenharmony_ci 0x1b, 0x044, /* ADC Mux (AC'97 source) */ 37262306a36Sopenharmony_ci 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */ 37362306a36Sopenharmony_ci 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */ 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci 0x18, 0x000, /* All power-up */ 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci 0x16, 0x122, /* I2S, normal polarity, 24bit */ 37862306a36Sopenharmony_ci 0x17, 0x022, /* 256fs, slave mode */ 37962306a36Sopenharmony_ci 0x00, 0, /* DAC1 analog mute */ 38062306a36Sopenharmony_ci 0x01, 0, /* DAC2 analog mute */ 38162306a36Sopenharmony_ci 0x02, 0, /* DAC3 analog mute */ 38262306a36Sopenharmony_ci 0x03, 0, /* DAC4 analog mute */ 38362306a36Sopenharmony_ci 0x04, 0, /* DAC5 analog mute */ 38462306a36Sopenharmony_ci 0x05, 0, /* DAC6 analog mute */ 38562306a36Sopenharmony_ci 0x06, 0, /* DAC7 analog mute */ 38662306a36Sopenharmony_ci 0x07, 0, /* DAC8 analog mute */ 38762306a36Sopenharmony_ci 0x08, 0x100, /* master analog mute */ 38862306a36Sopenharmony_ci 0x09, 0xff, /* DAC1 digital full */ 38962306a36Sopenharmony_ci 0x0a, 0xff, /* DAC2 digital full */ 39062306a36Sopenharmony_ci 0x0b, 0xff, /* DAC3 digital full */ 39162306a36Sopenharmony_ci 0x0c, 0xff, /* DAC4 digital full */ 39262306a36Sopenharmony_ci 0x0d, 0xff, /* DAC5 digital full */ 39362306a36Sopenharmony_ci 0x0e, 0xff, /* DAC6 digital full */ 39462306a36Sopenharmony_ci 0x0f, 0xff, /* DAC7 digital full */ 39562306a36Sopenharmony_ci 0x10, 0xff, /* DAC8 digital full */ 39662306a36Sopenharmony_ci 0x11, 0x1ff, /* master digital full */ 39762306a36Sopenharmony_ci 0x12, 0x000, /* phase normal */ 39862306a36Sopenharmony_ci 0x13, 0x090, /* unmute DAC L/R */ 39962306a36Sopenharmony_ci 0x14, 0x000, /* all unmute */ 40062306a36Sopenharmony_ci 0x15, 0x000, /* no deemphasis, no ZFLG */ 40162306a36Sopenharmony_ci 0x19, 0x000, /* -12dB ADC/L */ 40262306a36Sopenharmony_ci 0x1a, 0x000, /* -12dB ADC/R */ 40362306a36Sopenharmony_ci (unsigned short)-1 40462306a36Sopenharmony_ci }; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci unsigned int tmp; 40762306a36Sopenharmony_ci struct snd_akm4xxx *ak; 40862306a36Sopenharmony_ci struct phase28_spec *spec; 40962306a36Sopenharmony_ci const unsigned short *p; 41062306a36Sopenharmony_ci int i; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci ice->num_total_dacs = 8; 41362306a36Sopenharmony_ci ice->num_total_adcs = 2; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci spec = kzalloc(sizeof(*spec), GFP_KERNEL); 41662306a36Sopenharmony_ci if (!spec) 41762306a36Sopenharmony_ci return -ENOMEM; 41862306a36Sopenharmony_ci ice->spec = spec; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci /* Initialize analog chips */ 42162306a36Sopenharmony_ci ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); 42262306a36Sopenharmony_ci ak = ice->akm; 42362306a36Sopenharmony_ci if (!ak) 42462306a36Sopenharmony_ci return -ENOMEM; 42562306a36Sopenharmony_ci ice->akm_codecs = 1; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for time being */ 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci /* reset the wm codec as the SPI mode */ 43062306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 43162306a36Sopenharmony_ci snd_ice1712_gpio_set_mask(ice, ~(PHASE28_WM_RESET|PHASE28_WM_CS| 43262306a36Sopenharmony_ci PHASE28_HP_SEL)); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci tmp = snd_ice1712_gpio_read(ice); 43562306a36Sopenharmony_ci tmp &= ~PHASE28_WM_RESET; 43662306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 43762306a36Sopenharmony_ci udelay(1); 43862306a36Sopenharmony_ci tmp |= PHASE28_WM_CS; 43962306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 44062306a36Sopenharmony_ci udelay(1); 44162306a36Sopenharmony_ci tmp |= PHASE28_WM_RESET; 44262306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 44362306a36Sopenharmony_ci udelay(1); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci p = wm_inits_phase28; 44662306a36Sopenharmony_ci for (; *p != (unsigned short)-1; p += 2) 44762306a36Sopenharmony_ci wm_put(ice, p[0], p[1]); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci spec->master[0] = WM_VOL_MUTE; 45262306a36Sopenharmony_ci spec->master[1] = WM_VOL_MUTE; 45362306a36Sopenharmony_ci for (i = 0; i < ice->num_total_dacs; i++) { 45462306a36Sopenharmony_ci spec->vol[i] = WM_VOL_MUTE; 45562306a36Sopenharmony_ci wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]); 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci return 0; 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci/* 46262306a36Sopenharmony_ci * DAC volume attenuation mixer control 46362306a36Sopenharmony_ci */ 46462306a36Sopenharmony_cistatic int wm_vol_info(struct snd_kcontrol *kcontrol, 46562306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci int voices = kcontrol->private_value >> 8; 46862306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 46962306a36Sopenharmony_ci uinfo->count = voices; 47062306a36Sopenharmony_ci uinfo->value.integer.min = 0; /* mute (-101dB) */ 47162306a36Sopenharmony_ci uinfo->value.integer.max = 0x7F; /* 0dB */ 47262306a36Sopenharmony_ci return 0; 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic int wm_vol_get(struct snd_kcontrol *kcontrol, 47662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 47962306a36Sopenharmony_ci struct phase28_spec *spec = ice->spec; 48062306a36Sopenharmony_ci int i, ofs, voices; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci voices = kcontrol->private_value >> 8; 48362306a36Sopenharmony_ci ofs = kcontrol->private_value & 0xff; 48462306a36Sopenharmony_ci for (i = 0; i < voices; i++) 48562306a36Sopenharmony_ci ucontrol->value.integer.value[i] = 48662306a36Sopenharmony_ci spec->vol[ofs+i] & ~WM_VOL_MUTE; 48762306a36Sopenharmony_ci return 0; 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_cistatic int wm_vol_put(struct snd_kcontrol *kcontrol, 49162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 49462306a36Sopenharmony_ci struct phase28_spec *spec = ice->spec; 49562306a36Sopenharmony_ci int i, idx, ofs, voices; 49662306a36Sopenharmony_ci int change = 0; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci voices = kcontrol->private_value >> 8; 49962306a36Sopenharmony_ci ofs = kcontrol->private_value & 0xff; 50062306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 50162306a36Sopenharmony_ci for (i = 0; i < voices; i++) { 50262306a36Sopenharmony_ci unsigned int vol; 50362306a36Sopenharmony_ci vol = ucontrol->value.integer.value[i]; 50462306a36Sopenharmony_ci if (vol > 0x7f) 50562306a36Sopenharmony_ci continue; 50662306a36Sopenharmony_ci vol |= spec->vol[ofs+i] & WM_VOL_MUTE; 50762306a36Sopenharmony_ci if (vol != spec->vol[ofs+i]) { 50862306a36Sopenharmony_ci spec->vol[ofs+i] = vol; 50962306a36Sopenharmony_ci idx = WM_DAC_ATTEN + ofs + i; 51062306a36Sopenharmony_ci wm_set_vol(ice, idx, spec->vol[ofs+i], 51162306a36Sopenharmony_ci spec->master[i]); 51262306a36Sopenharmony_ci change = 1; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 51662306a36Sopenharmony_ci return change; 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci/* 52062306a36Sopenharmony_ci * WM8770 mute control 52162306a36Sopenharmony_ci */ 52262306a36Sopenharmony_cistatic int wm_mute_info(struct snd_kcontrol *kcontrol, 52362306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) { 52462306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 52562306a36Sopenharmony_ci uinfo->count = kcontrol->private_value >> 8; 52662306a36Sopenharmony_ci uinfo->value.integer.min = 0; 52762306a36Sopenharmony_ci uinfo->value.integer.max = 1; 52862306a36Sopenharmony_ci return 0; 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic int wm_mute_get(struct snd_kcontrol *kcontrol, 53262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 53562306a36Sopenharmony_ci struct phase28_spec *spec = ice->spec; 53662306a36Sopenharmony_ci int voices, ofs, i; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci voices = kcontrol->private_value >> 8; 53962306a36Sopenharmony_ci ofs = kcontrol->private_value & 0xFF; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci for (i = 0; i < voices; i++) 54262306a36Sopenharmony_ci ucontrol->value.integer.value[i] = 54362306a36Sopenharmony_ci (spec->vol[ofs+i] & WM_VOL_MUTE) ? 0 : 1; 54462306a36Sopenharmony_ci return 0; 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic int wm_mute_put(struct snd_kcontrol *kcontrol, 54862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 55162306a36Sopenharmony_ci struct phase28_spec *spec = ice->spec; 55262306a36Sopenharmony_ci int change = 0, voices, ofs, i; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci voices = kcontrol->private_value >> 8; 55562306a36Sopenharmony_ci ofs = kcontrol->private_value & 0xFF; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 55862306a36Sopenharmony_ci for (i = 0; i < voices; i++) { 55962306a36Sopenharmony_ci int val = (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1; 56062306a36Sopenharmony_ci if (ucontrol->value.integer.value[i] != val) { 56162306a36Sopenharmony_ci spec->vol[ofs + i] &= ~WM_VOL_MUTE; 56262306a36Sopenharmony_ci spec->vol[ofs + i] |= 56362306a36Sopenharmony_ci ucontrol->value.integer.value[i] ? 0 : 56462306a36Sopenharmony_ci WM_VOL_MUTE; 56562306a36Sopenharmony_ci wm_set_vol(ice, ofs + i, spec->vol[ofs + i], 56662306a36Sopenharmony_ci spec->master[i]); 56762306a36Sopenharmony_ci change = 1; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci return change; 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci/* 57662306a36Sopenharmony_ci * WM8770 master mute control 57762306a36Sopenharmony_ci */ 57862306a36Sopenharmony_ci#define wm_master_mute_info snd_ctl_boolean_stereo_info 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic int wm_master_mute_get(struct snd_kcontrol *kcontrol, 58162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 58462306a36Sopenharmony_ci struct phase28_spec *spec = ice->spec; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 58762306a36Sopenharmony_ci (spec->master[0] & WM_VOL_MUTE) ? 0 : 1; 58862306a36Sopenharmony_ci ucontrol->value.integer.value[1] = 58962306a36Sopenharmony_ci (spec->master[1] & WM_VOL_MUTE) ? 0 : 1; 59062306a36Sopenharmony_ci return 0; 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic int wm_master_mute_put(struct snd_kcontrol *kcontrol, 59462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 59762306a36Sopenharmony_ci struct phase28_spec *spec = ice->spec; 59862306a36Sopenharmony_ci int change = 0, i; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 60162306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 60262306a36Sopenharmony_ci int val = (spec->master[i] & WM_VOL_MUTE) ? 0 : 1; 60362306a36Sopenharmony_ci if (ucontrol->value.integer.value[i] != val) { 60462306a36Sopenharmony_ci int dac; 60562306a36Sopenharmony_ci spec->master[i] &= ~WM_VOL_MUTE; 60662306a36Sopenharmony_ci spec->master[i] |= 60762306a36Sopenharmony_ci ucontrol->value.integer.value[i] ? 0 : 60862306a36Sopenharmony_ci WM_VOL_MUTE; 60962306a36Sopenharmony_ci for (dac = 0; dac < ice->num_total_dacs; dac += 2) 61062306a36Sopenharmony_ci wm_set_vol(ice, WM_DAC_ATTEN + dac + i, 61162306a36Sopenharmony_ci spec->vol[dac + i], 61262306a36Sopenharmony_ci spec->master[i]); 61362306a36Sopenharmony_ci change = 1; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci return change; 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci/* digital master volume */ 62262306a36Sopenharmony_ci#define PCM_0dB 0xff 62362306a36Sopenharmony_ci#define PCM_RES 128 /* -64dB */ 62462306a36Sopenharmony_ci#define PCM_MIN (PCM_0dB - PCM_RES) 62562306a36Sopenharmony_cistatic int wm_pcm_vol_info(struct snd_kcontrol *kcontrol, 62662306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 62962306a36Sopenharmony_ci uinfo->count = 1; 63062306a36Sopenharmony_ci uinfo->value.integer.min = 0; /* mute (-64dB) */ 63162306a36Sopenharmony_ci uinfo->value.integer.max = PCM_RES; /* 0dB */ 63262306a36Sopenharmony_ci return 0; 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, 63662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 63962306a36Sopenharmony_ci unsigned short val; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 64262306a36Sopenharmony_ci val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; 64362306a36Sopenharmony_ci val = val > PCM_MIN ? (val - PCM_MIN) : 0; 64462306a36Sopenharmony_ci ucontrol->value.integer.value[0] = val; 64562306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 64662306a36Sopenharmony_ci return 0; 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistatic int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, 65062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 65162306a36Sopenharmony_ci{ 65262306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 65362306a36Sopenharmony_ci unsigned short ovol, nvol; 65462306a36Sopenharmony_ci int change = 0; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci nvol = ucontrol->value.integer.value[0]; 65762306a36Sopenharmony_ci if (nvol > PCM_RES) 65862306a36Sopenharmony_ci return -EINVAL; 65962306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 66062306a36Sopenharmony_ci nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff; 66162306a36Sopenharmony_ci ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; 66262306a36Sopenharmony_ci if (ovol != nvol) { 66362306a36Sopenharmony_ci wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */ 66462306a36Sopenharmony_ci /* update */ 66562306a36Sopenharmony_ci wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); 66662306a36Sopenharmony_ci change = 1; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 66962306a36Sopenharmony_ci return change; 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci/* 67362306a36Sopenharmony_ci * Deemphasis 67462306a36Sopenharmony_ci */ 67562306a36Sopenharmony_ci#define phase28_deemp_info snd_ctl_boolean_mono_info 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic int phase28_deemp_get(struct snd_kcontrol *kcontrol, 67862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 67962306a36Sopenharmony_ci{ 68062306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 68162306a36Sopenharmony_ci ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 68262306a36Sopenharmony_ci 0xf; 68362306a36Sopenharmony_ci return 0; 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic int phase28_deemp_put(struct snd_kcontrol *kcontrol, 68762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 68862306a36Sopenharmony_ci{ 68962306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 69062306a36Sopenharmony_ci int temp, temp2; 69162306a36Sopenharmony_ci temp = wm_get(ice, WM_DAC_CTRL2); 69262306a36Sopenharmony_ci temp2 = temp; 69362306a36Sopenharmony_ci if (ucontrol->value.integer.value[0]) 69462306a36Sopenharmony_ci temp |= 0xf; 69562306a36Sopenharmony_ci else 69662306a36Sopenharmony_ci temp &= ~0xf; 69762306a36Sopenharmony_ci if (temp != temp2) { 69862306a36Sopenharmony_ci wm_put(ice, WM_DAC_CTRL2, temp); 69962306a36Sopenharmony_ci return 1; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci return 0; 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci/* 70562306a36Sopenharmony_ci * ADC Oversampling 70662306a36Sopenharmony_ci */ 70762306a36Sopenharmony_cistatic int phase28_oversampling_info(struct snd_kcontrol *k, 70862306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci static const char * const texts[2] = { "128x", "64x" }; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, texts); 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic int phase28_oversampling_get(struct snd_kcontrol *kcontrol, 71662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 71962306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 72062306a36Sopenharmony_ci 0x8; 72162306a36Sopenharmony_ci return 0; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic int phase28_oversampling_put(struct snd_kcontrol *kcontrol, 72562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci int temp, temp2; 72862306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci temp = wm_get(ice, WM_MASTER); 73162306a36Sopenharmony_ci temp2 = temp; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci if (ucontrol->value.enumerated.item[0]) 73462306a36Sopenharmony_ci temp |= 0x8; 73562306a36Sopenharmony_ci else 73662306a36Sopenharmony_ci temp &= ~0x8; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci if (temp != temp2) { 73962306a36Sopenharmony_ci wm_put(ice, WM_MASTER, temp); 74062306a36Sopenharmony_ci return 1; 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci return 0; 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); 74662306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_cistatic const struct snd_kcontrol_new phase28_dac_controls[] = { 74962306a36Sopenharmony_ci { 75062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 75162306a36Sopenharmony_ci .name = "Master Playback Switch", 75262306a36Sopenharmony_ci .info = wm_master_mute_info, 75362306a36Sopenharmony_ci .get = wm_master_mute_get, 75462306a36Sopenharmony_ci .put = wm_master_mute_put 75562306a36Sopenharmony_ci }, 75662306a36Sopenharmony_ci { 75762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 75862306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 75962306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 76062306a36Sopenharmony_ci .name = "Master Playback Volume", 76162306a36Sopenharmony_ci .info = wm_master_vol_info, 76262306a36Sopenharmony_ci .get = wm_master_vol_get, 76362306a36Sopenharmony_ci .put = wm_master_vol_put, 76462306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_dac } 76562306a36Sopenharmony_ci }, 76662306a36Sopenharmony_ci { 76762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 76862306a36Sopenharmony_ci .name = "Front Playback Switch", 76962306a36Sopenharmony_ci .info = wm_mute_info, 77062306a36Sopenharmony_ci .get = wm_mute_get, 77162306a36Sopenharmony_ci .put = wm_mute_put, 77262306a36Sopenharmony_ci .private_value = (2 << 8) | 0 77362306a36Sopenharmony_ci }, 77462306a36Sopenharmony_ci { 77562306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 77662306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 77762306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 77862306a36Sopenharmony_ci .name = "Front Playback Volume", 77962306a36Sopenharmony_ci .info = wm_vol_info, 78062306a36Sopenharmony_ci .get = wm_vol_get, 78162306a36Sopenharmony_ci .put = wm_vol_put, 78262306a36Sopenharmony_ci .private_value = (2 << 8) | 0, 78362306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_dac } 78462306a36Sopenharmony_ci }, 78562306a36Sopenharmony_ci { 78662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 78762306a36Sopenharmony_ci .name = "Rear Playback Switch", 78862306a36Sopenharmony_ci .info = wm_mute_info, 78962306a36Sopenharmony_ci .get = wm_mute_get, 79062306a36Sopenharmony_ci .put = wm_mute_put, 79162306a36Sopenharmony_ci .private_value = (2 << 8) | 2 79262306a36Sopenharmony_ci }, 79362306a36Sopenharmony_ci { 79462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 79562306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 79662306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 79762306a36Sopenharmony_ci .name = "Rear Playback Volume", 79862306a36Sopenharmony_ci .info = wm_vol_info, 79962306a36Sopenharmony_ci .get = wm_vol_get, 80062306a36Sopenharmony_ci .put = wm_vol_put, 80162306a36Sopenharmony_ci .private_value = (2 << 8) | 2, 80262306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_dac } 80362306a36Sopenharmony_ci }, 80462306a36Sopenharmony_ci { 80562306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 80662306a36Sopenharmony_ci .name = "Center Playback Switch", 80762306a36Sopenharmony_ci .info = wm_mute_info, 80862306a36Sopenharmony_ci .get = wm_mute_get, 80962306a36Sopenharmony_ci .put = wm_mute_put, 81062306a36Sopenharmony_ci .private_value = (1 << 8) | 4 81162306a36Sopenharmony_ci }, 81262306a36Sopenharmony_ci { 81362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 81462306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 81562306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 81662306a36Sopenharmony_ci .name = "Center Playback Volume", 81762306a36Sopenharmony_ci .info = wm_vol_info, 81862306a36Sopenharmony_ci .get = wm_vol_get, 81962306a36Sopenharmony_ci .put = wm_vol_put, 82062306a36Sopenharmony_ci .private_value = (1 << 8) | 4, 82162306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_dac } 82262306a36Sopenharmony_ci }, 82362306a36Sopenharmony_ci { 82462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 82562306a36Sopenharmony_ci .name = "LFE Playback Switch", 82662306a36Sopenharmony_ci .info = wm_mute_info, 82762306a36Sopenharmony_ci .get = wm_mute_get, 82862306a36Sopenharmony_ci .put = wm_mute_put, 82962306a36Sopenharmony_ci .private_value = (1 << 8) | 5 83062306a36Sopenharmony_ci }, 83162306a36Sopenharmony_ci { 83262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 83362306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 83462306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 83562306a36Sopenharmony_ci .name = "LFE Playback Volume", 83662306a36Sopenharmony_ci .info = wm_vol_info, 83762306a36Sopenharmony_ci .get = wm_vol_get, 83862306a36Sopenharmony_ci .put = wm_vol_put, 83962306a36Sopenharmony_ci .private_value = (1 << 8) | 5, 84062306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_dac } 84162306a36Sopenharmony_ci }, 84262306a36Sopenharmony_ci { 84362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 84462306a36Sopenharmony_ci .name = "Side Playback Switch", 84562306a36Sopenharmony_ci .info = wm_mute_info, 84662306a36Sopenharmony_ci .get = wm_mute_get, 84762306a36Sopenharmony_ci .put = wm_mute_put, 84862306a36Sopenharmony_ci .private_value = (2 << 8) | 6 84962306a36Sopenharmony_ci }, 85062306a36Sopenharmony_ci { 85162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 85262306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 85362306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 85462306a36Sopenharmony_ci .name = "Side Playback Volume", 85562306a36Sopenharmony_ci .info = wm_vol_info, 85662306a36Sopenharmony_ci .get = wm_vol_get, 85762306a36Sopenharmony_ci .put = wm_vol_put, 85862306a36Sopenharmony_ci .private_value = (2 << 8) | 6, 85962306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_dac } 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci}; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_cistatic const struct snd_kcontrol_new wm_controls[] = { 86462306a36Sopenharmony_ci { 86562306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 86662306a36Sopenharmony_ci .name = "PCM Playback Switch", 86762306a36Sopenharmony_ci .info = wm_pcm_mute_info, 86862306a36Sopenharmony_ci .get = wm_pcm_mute_get, 86962306a36Sopenharmony_ci .put = wm_pcm_mute_put 87062306a36Sopenharmony_ci }, 87162306a36Sopenharmony_ci { 87262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 87362306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 87462306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 87562306a36Sopenharmony_ci .name = "PCM Playback Volume", 87662306a36Sopenharmony_ci .info = wm_pcm_vol_info, 87762306a36Sopenharmony_ci .get = wm_pcm_vol_get, 87862306a36Sopenharmony_ci .put = wm_pcm_vol_put, 87962306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_pcm } 88062306a36Sopenharmony_ci }, 88162306a36Sopenharmony_ci { 88262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 88362306a36Sopenharmony_ci .name = "DAC Deemphasis Switch", 88462306a36Sopenharmony_ci .info = phase28_deemp_info, 88562306a36Sopenharmony_ci .get = phase28_deemp_get, 88662306a36Sopenharmony_ci .put = phase28_deemp_put 88762306a36Sopenharmony_ci }, 88862306a36Sopenharmony_ci { 88962306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 89062306a36Sopenharmony_ci .name = "ADC Oversampling", 89162306a36Sopenharmony_ci .info = phase28_oversampling_info, 89262306a36Sopenharmony_ci .get = phase28_oversampling_get, 89362306a36Sopenharmony_ci .put = phase28_oversampling_put 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci}; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_cistatic int phase28_add_controls(struct snd_ice1712 *ice) 89862306a36Sopenharmony_ci{ 89962306a36Sopenharmony_ci unsigned int i, counts; 90062306a36Sopenharmony_ci int err; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci counts = ARRAY_SIZE(phase28_dac_controls); 90362306a36Sopenharmony_ci for (i = 0; i < counts; i++) { 90462306a36Sopenharmony_ci err = snd_ctl_add(ice->card, 90562306a36Sopenharmony_ci snd_ctl_new1(&phase28_dac_controls[i], 90662306a36Sopenharmony_ci ice)); 90762306a36Sopenharmony_ci if (err < 0) 90862306a36Sopenharmony_ci return err; 90962306a36Sopenharmony_ci } 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(wm_controls); i++) { 91262306a36Sopenharmony_ci err = snd_ctl_add(ice->card, 91362306a36Sopenharmony_ci snd_ctl_new1(&wm_controls[i], ice)); 91462306a36Sopenharmony_ci if (err < 0) 91562306a36Sopenharmony_ci return err; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci return 0; 91962306a36Sopenharmony_ci} 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_cistruct snd_ice1712_card_info snd_vt1724_phase_cards[] = { 92262306a36Sopenharmony_ci { 92362306a36Sopenharmony_ci .subvendor = VT1724_SUBDEVICE_PHASE22, 92462306a36Sopenharmony_ci .name = "Terratec PHASE 22", 92562306a36Sopenharmony_ci .model = "phase22", 92662306a36Sopenharmony_ci .chip_init = phase22_init, 92762306a36Sopenharmony_ci .build_controls = phase22_add_controls, 92862306a36Sopenharmony_ci .eeprom_size = sizeof(phase22_eeprom), 92962306a36Sopenharmony_ci .eeprom_data = phase22_eeprom, 93062306a36Sopenharmony_ci }, 93162306a36Sopenharmony_ci { 93262306a36Sopenharmony_ci .subvendor = VT1724_SUBDEVICE_PHASE28, 93362306a36Sopenharmony_ci .name = "Terratec PHASE 28", 93462306a36Sopenharmony_ci .model = "phase28", 93562306a36Sopenharmony_ci .chip_init = phase28_init, 93662306a36Sopenharmony_ci .build_controls = phase28_add_controls, 93762306a36Sopenharmony_ci .eeprom_size = sizeof(phase28_eeprom), 93862306a36Sopenharmony_ci .eeprom_data = phase28_eeprom, 93962306a36Sopenharmony_ci }, 94062306a36Sopenharmony_ci { 94162306a36Sopenharmony_ci .subvendor = VT1724_SUBDEVICE_TS22, 94262306a36Sopenharmony_ci .name = "Terrasoniq TS22 PCI", 94362306a36Sopenharmony_ci .model = "TS22", 94462306a36Sopenharmony_ci .chip_init = phase22_init, 94562306a36Sopenharmony_ci .build_controls = phase22_add_controls, 94662306a36Sopenharmony_ci .eeprom_size = sizeof(phase22_eeprom), 94762306a36Sopenharmony_ci .eeprom_data = phase22_eeprom, 94862306a36Sopenharmony_ci }, 94962306a36Sopenharmony_ci { } /* terminator */ 95062306a36Sopenharmony_ci}; 951