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 Terratec Aureon cards 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (c) 2003 Takashi Iwai <tiwai@suse.de> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * NOTES: 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * - we reuse the struct snd_akm4xxx record for storing the wm8770 codec data. 1262306a36Sopenharmony_ci * both wm and akm codecs are pretty similar, so we can integrate 1362306a36Sopenharmony_ci * both controls in the future, once if wm codecs are reused in 1462306a36Sopenharmony_ci * many boards. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * - DAC digital volumes are not implemented in the mixer. 1762306a36Sopenharmony_ci * if they show better response than DAC analog volumes, we can use them 1862306a36Sopenharmony_ci * instead. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * Lowlevel functions for AudioTrak Prodigy 7.1 (and possibly 192) cards 2162306a36Sopenharmony_ci * Copyright (c) 2003 Dimitromanolakis Apostolos <apostol@cs.utoronto.ca> 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * version 0.82: Stable / not all features work yet (no communication with AC97 secondary) 2462306a36Sopenharmony_ci * added 64x/128x oversampling switch (should be 64x only for 96khz) 2562306a36Sopenharmony_ci * fixed some recording labels (still need to check the rest) 2662306a36Sopenharmony_ci * recording is working probably thanks to correct wm8770 initialization 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * version 0.5: Initial release: 2962306a36Sopenharmony_ci * working: analog output, mixer, headphone amplifier switch 3062306a36Sopenharmony_ci * not working: prety much everything else, at least i could verify that 3162306a36Sopenharmony_ci * we have no digital output, no capture, pretty bad clicks and poops 3262306a36Sopenharmony_ci * on mixer switch and other coll stuff. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <linux/delay.h> 3662306a36Sopenharmony_ci#include <linux/interrupt.h> 3762306a36Sopenharmony_ci#include <linux/init.h> 3862306a36Sopenharmony_ci#include <linux/slab.h> 3962306a36Sopenharmony_ci#include <linux/mutex.h> 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#include <sound/core.h> 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#include "ice1712.h" 4462306a36Sopenharmony_ci#include "envy24ht.h" 4562306a36Sopenharmony_ci#include "aureon.h" 4662306a36Sopenharmony_ci#include <sound/tlv.h> 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* AC97 register cache for Aureon */ 4962306a36Sopenharmony_cistruct aureon_spec { 5062306a36Sopenharmony_ci unsigned short stac9744[64]; 5162306a36Sopenharmony_ci unsigned int cs8415_mux; 5262306a36Sopenharmony_ci unsigned short master[2]; 5362306a36Sopenharmony_ci unsigned short vol[8]; 5462306a36Sopenharmony_ci unsigned char pca9554_out; 5562306a36Sopenharmony_ci}; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* WM8770 registers */ 5862306a36Sopenharmony_ci#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ 5962306a36Sopenharmony_ci#define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */ 6062306a36Sopenharmony_ci#define WM_DAC_DIG_ATTEN 0x09 /* DAC1-8 digital attenuation */ 6162306a36Sopenharmony_ci#define WM_DAC_DIG_MASTER_ATTEN 0x11 /* DAC master digital attenuation */ 6262306a36Sopenharmony_ci#define WM_PHASE_SWAP 0x12 /* DAC phase */ 6362306a36Sopenharmony_ci#define WM_DAC_CTRL1 0x13 /* DAC control bits */ 6462306a36Sopenharmony_ci#define WM_MUTE 0x14 /* mute controls */ 6562306a36Sopenharmony_ci#define WM_DAC_CTRL2 0x15 /* de-emphasis and zefo-flag */ 6662306a36Sopenharmony_ci#define WM_INT_CTRL 0x16 /* interface control */ 6762306a36Sopenharmony_ci#define WM_MASTER 0x17 /* master clock and mode */ 6862306a36Sopenharmony_ci#define WM_POWERDOWN 0x18 /* power-down controls */ 6962306a36Sopenharmony_ci#define WM_ADC_GAIN 0x19 /* ADC gain L(19)/R(1a) */ 7062306a36Sopenharmony_ci#define WM_ADC_MUX 0x1b /* input MUX */ 7162306a36Sopenharmony_ci#define WM_OUT_MUX1 0x1c /* output MUX */ 7262306a36Sopenharmony_ci#define WM_OUT_MUX2 0x1e /* output MUX */ 7362306a36Sopenharmony_ci#define WM_RESET 0x1f /* software reset */ 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* CS8415A registers */ 7662306a36Sopenharmony_ci#define CS8415_CTRL1 0x01 7762306a36Sopenharmony_ci#define CS8415_CTRL2 0x02 7862306a36Sopenharmony_ci#define CS8415_QSUB 0x14 7962306a36Sopenharmony_ci#define CS8415_RATIO 0x1E 8062306a36Sopenharmony_ci#define CS8415_C_BUFFER 0x20 8162306a36Sopenharmony_ci#define CS8415_ID 0x7F 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* PCA9554 registers */ 8462306a36Sopenharmony_ci#define PCA9554_DEV 0x40 /* I2C device address */ 8562306a36Sopenharmony_ci#define PCA9554_IN 0x00 /* input port */ 8662306a36Sopenharmony_ci#define PCA9554_OUT 0x01 /* output port */ 8762306a36Sopenharmony_ci#define PCA9554_INVERT 0x02 /* input invert */ 8862306a36Sopenharmony_ci#define PCA9554_DIR 0x03 /* port directions */ 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/* 9162306a36Sopenharmony_ci * Aureon Universe additional controls using PCA9554 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/* 9562306a36Sopenharmony_ci * Send data to pca9554 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_cistatic void aureon_pca9554_write(struct snd_ice1712 *ice, unsigned char reg, 9862306a36Sopenharmony_ci unsigned char data) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci unsigned int tmp; 10162306a36Sopenharmony_ci int i, j; 10262306a36Sopenharmony_ci unsigned char dev = PCA9554_DEV; /* ID 0100000, write */ 10362306a36Sopenharmony_ci unsigned char val = 0; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci tmp = snd_ice1712_gpio_read(ice); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci snd_ice1712_gpio_set_mask(ice, ~(AUREON_SPI_MOSI|AUREON_SPI_CLK| 10862306a36Sopenharmony_ci AUREON_WM_RW|AUREON_WM_CS| 10962306a36Sopenharmony_ci AUREON_CS8415_CS)); 11062306a36Sopenharmony_ci tmp |= AUREON_WM_RW; 11162306a36Sopenharmony_ci tmp |= AUREON_CS8415_CS | AUREON_WM_CS; /* disable SPI devices */ 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci tmp &= ~AUREON_SPI_MOSI; 11462306a36Sopenharmony_ci tmp &= ~AUREON_SPI_CLK; 11562306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 11662306a36Sopenharmony_ci udelay(50); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* 11962306a36Sopenharmony_ci * send i2c stop condition and start condition 12062306a36Sopenharmony_ci * to obtain sane state 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_ci tmp |= AUREON_SPI_CLK; 12362306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 12462306a36Sopenharmony_ci udelay(50); 12562306a36Sopenharmony_ci tmp |= AUREON_SPI_MOSI; 12662306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 12762306a36Sopenharmony_ci udelay(100); 12862306a36Sopenharmony_ci tmp &= ~AUREON_SPI_MOSI; 12962306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 13062306a36Sopenharmony_ci udelay(50); 13162306a36Sopenharmony_ci tmp &= ~AUREON_SPI_CLK; 13262306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 13362306a36Sopenharmony_ci udelay(100); 13462306a36Sopenharmony_ci /* 13562306a36Sopenharmony_ci * send device address, command and value, 13662306a36Sopenharmony_ci * skipping ack cycles in between 13762306a36Sopenharmony_ci */ 13862306a36Sopenharmony_ci for (j = 0; j < 3; j++) { 13962306a36Sopenharmony_ci switch (j) { 14062306a36Sopenharmony_ci case 0: 14162306a36Sopenharmony_ci val = dev; 14262306a36Sopenharmony_ci break; 14362306a36Sopenharmony_ci case 1: 14462306a36Sopenharmony_ci val = reg; 14562306a36Sopenharmony_ci break; 14662306a36Sopenharmony_ci case 2: 14762306a36Sopenharmony_ci val = data; 14862306a36Sopenharmony_ci break; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci for (i = 7; i >= 0; i--) { 15162306a36Sopenharmony_ci tmp &= ~AUREON_SPI_CLK; 15262306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 15362306a36Sopenharmony_ci udelay(40); 15462306a36Sopenharmony_ci if (val & (1 << i)) 15562306a36Sopenharmony_ci tmp |= AUREON_SPI_MOSI; 15662306a36Sopenharmony_ci else 15762306a36Sopenharmony_ci tmp &= ~AUREON_SPI_MOSI; 15862306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 15962306a36Sopenharmony_ci udelay(40); 16062306a36Sopenharmony_ci tmp |= AUREON_SPI_CLK; 16162306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 16262306a36Sopenharmony_ci udelay(40); 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci tmp &= ~AUREON_SPI_CLK; 16562306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 16662306a36Sopenharmony_ci udelay(40); 16762306a36Sopenharmony_ci tmp |= AUREON_SPI_CLK; 16862306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 16962306a36Sopenharmony_ci udelay(40); 17062306a36Sopenharmony_ci tmp &= ~AUREON_SPI_CLK; 17162306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 17262306a36Sopenharmony_ci udelay(40); 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci tmp &= ~AUREON_SPI_CLK; 17562306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 17662306a36Sopenharmony_ci udelay(40); 17762306a36Sopenharmony_ci tmp &= ~AUREON_SPI_MOSI; 17862306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 17962306a36Sopenharmony_ci udelay(40); 18062306a36Sopenharmony_ci tmp |= AUREON_SPI_CLK; 18162306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 18262306a36Sopenharmony_ci udelay(50); 18362306a36Sopenharmony_ci tmp |= AUREON_SPI_MOSI; 18462306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 18562306a36Sopenharmony_ci udelay(100); 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic int aureon_universe_inmux_info(struct snd_kcontrol *kcontrol, 18962306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci static const char * const texts[3] = 19262306a36Sopenharmony_ci {"Internal Aux", "Wavetable", "Rear Line-In"}; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 3, texts); 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic int aureon_universe_inmux_get(struct snd_kcontrol *kcontrol, 19862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 20162306a36Sopenharmony_ci struct aureon_spec *spec = ice->spec; 20262306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = spec->pca9554_out; 20362306a36Sopenharmony_ci return 0; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic int aureon_universe_inmux_put(struct snd_kcontrol *kcontrol, 20762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 21062306a36Sopenharmony_ci struct aureon_spec *spec = ice->spec; 21162306a36Sopenharmony_ci unsigned char oval, nval; 21262306a36Sopenharmony_ci int change; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci nval = ucontrol->value.enumerated.item[0]; 21562306a36Sopenharmony_ci if (nval >= 3) 21662306a36Sopenharmony_ci return -EINVAL; 21762306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 21862306a36Sopenharmony_ci oval = spec->pca9554_out; 21962306a36Sopenharmony_ci change = (oval != nval); 22062306a36Sopenharmony_ci if (change) { 22162306a36Sopenharmony_ci aureon_pca9554_write(ice, PCA9554_OUT, nval); 22262306a36Sopenharmony_ci spec->pca9554_out = nval; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 22562306a36Sopenharmony_ci return change; 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic void aureon_ac97_write(struct snd_ice1712 *ice, unsigned short reg, 23062306a36Sopenharmony_ci unsigned short val) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci struct aureon_spec *spec = ice->spec; 23362306a36Sopenharmony_ci unsigned int tmp; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* Send address to XILINX chip */ 23662306a36Sopenharmony_ci tmp = (snd_ice1712_gpio_read(ice) & ~0xFF) | (reg & 0x7F); 23762306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 23862306a36Sopenharmony_ci udelay(10); 23962306a36Sopenharmony_ci tmp |= AUREON_AC97_ADDR; 24062306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 24162306a36Sopenharmony_ci udelay(10); 24262306a36Sopenharmony_ci tmp &= ~AUREON_AC97_ADDR; 24362306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 24462306a36Sopenharmony_ci udelay(10); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* Send low-order byte to XILINX chip */ 24762306a36Sopenharmony_ci tmp &= ~AUREON_AC97_DATA_MASK; 24862306a36Sopenharmony_ci tmp |= val & AUREON_AC97_DATA_MASK; 24962306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 25062306a36Sopenharmony_ci udelay(10); 25162306a36Sopenharmony_ci tmp |= AUREON_AC97_DATA_LOW; 25262306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 25362306a36Sopenharmony_ci udelay(10); 25462306a36Sopenharmony_ci tmp &= ~AUREON_AC97_DATA_LOW; 25562306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 25662306a36Sopenharmony_ci udelay(10); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* Send high-order byte to XILINX chip */ 25962306a36Sopenharmony_ci tmp &= ~AUREON_AC97_DATA_MASK; 26062306a36Sopenharmony_ci tmp |= (val >> 8) & AUREON_AC97_DATA_MASK; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 26362306a36Sopenharmony_ci udelay(10); 26462306a36Sopenharmony_ci tmp |= AUREON_AC97_DATA_HIGH; 26562306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 26662306a36Sopenharmony_ci udelay(10); 26762306a36Sopenharmony_ci tmp &= ~AUREON_AC97_DATA_HIGH; 26862306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 26962306a36Sopenharmony_ci udelay(10); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* Instruct XILINX chip to parse the data to the STAC9744 chip */ 27262306a36Sopenharmony_ci tmp |= AUREON_AC97_COMMIT; 27362306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 27462306a36Sopenharmony_ci udelay(10); 27562306a36Sopenharmony_ci tmp &= ~AUREON_AC97_COMMIT; 27662306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 27762306a36Sopenharmony_ci udelay(10); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* Store the data in out private buffer */ 28062306a36Sopenharmony_ci spec->stac9744[(reg & 0x7F) >> 1] = val; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic unsigned short aureon_ac97_read(struct snd_ice1712 *ice, unsigned short reg) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci struct aureon_spec *spec = ice->spec; 28662306a36Sopenharmony_ci return spec->stac9744[(reg & 0x7F) >> 1]; 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci/* 29062306a36Sopenharmony_ci * Initialize STAC9744 chip 29162306a36Sopenharmony_ci */ 29262306a36Sopenharmony_cistatic int aureon_ac97_init(struct snd_ice1712 *ice) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci struct aureon_spec *spec = ice->spec; 29562306a36Sopenharmony_ci int i; 29662306a36Sopenharmony_ci static const unsigned short ac97_defaults[] = { 29762306a36Sopenharmony_ci 0x00, 0x9640, 29862306a36Sopenharmony_ci 0x02, 0x8000, 29962306a36Sopenharmony_ci 0x04, 0x8000, 30062306a36Sopenharmony_ci 0x06, 0x8000, 30162306a36Sopenharmony_ci 0x0C, 0x8008, 30262306a36Sopenharmony_ci 0x0E, 0x8008, 30362306a36Sopenharmony_ci 0x10, 0x8808, 30462306a36Sopenharmony_ci 0x12, 0x8808, 30562306a36Sopenharmony_ci 0x14, 0x8808, 30662306a36Sopenharmony_ci 0x16, 0x8808, 30762306a36Sopenharmony_ci 0x18, 0x8808, 30862306a36Sopenharmony_ci 0x1C, 0x8000, 30962306a36Sopenharmony_ci 0x26, 0x000F, 31062306a36Sopenharmony_ci 0x28, 0x0201, 31162306a36Sopenharmony_ci 0x2C, 0xBB80, 31262306a36Sopenharmony_ci 0x32, 0xBB80, 31362306a36Sopenharmony_ci 0x7C, 0x8384, 31462306a36Sopenharmony_ci 0x7E, 0x7644, 31562306a36Sopenharmony_ci (unsigned short)-1 31662306a36Sopenharmony_ci }; 31762306a36Sopenharmony_ci unsigned int tmp; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* Cold reset */ 32062306a36Sopenharmony_ci tmp = (snd_ice1712_gpio_read(ice) | AUREON_AC97_RESET) & ~AUREON_AC97_DATA_MASK; 32162306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 32262306a36Sopenharmony_ci udelay(3); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci tmp &= ~AUREON_AC97_RESET; 32562306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 32662306a36Sopenharmony_ci udelay(3); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci tmp |= AUREON_AC97_RESET; 32962306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 33062306a36Sopenharmony_ci udelay(3); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci memset(&spec->stac9744, 0, sizeof(spec->stac9744)); 33362306a36Sopenharmony_ci for (i = 0; ac97_defaults[i] != (unsigned short)-1; i += 2) 33462306a36Sopenharmony_ci spec->stac9744[(ac97_defaults[i]) >> 1] = ac97_defaults[i+1]; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* Unmute AC'97 master volume permanently - muting is done by WM8770 */ 33762306a36Sopenharmony_ci aureon_ac97_write(ice, AC97_MASTER, 0x0000); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci return 0; 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci#define AUREON_AC97_STEREO 0x80 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci/* 34562306a36Sopenharmony_ci * AC'97 volume controls 34662306a36Sopenharmony_ci */ 34762306a36Sopenharmony_cistatic int aureon_ac97_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 35062306a36Sopenharmony_ci uinfo->count = kcontrol->private_value & AUREON_AC97_STEREO ? 2 : 1; 35162306a36Sopenharmony_ci uinfo->value.integer.min = 0; 35262306a36Sopenharmony_ci uinfo->value.integer.max = 31; 35362306a36Sopenharmony_ci return 0; 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic int aureon_ac97_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 35962306a36Sopenharmony_ci unsigned short vol; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci vol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F); 36462306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 0x1F - (vol & 0x1F); 36562306a36Sopenharmony_ci if (kcontrol->private_value & AUREON_AC97_STEREO) 36662306a36Sopenharmony_ci ucontrol->value.integer.value[1] = 0x1F - ((vol >> 8) & 0x1F); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 36962306a36Sopenharmony_ci return 0; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic int aureon_ac97_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 37562306a36Sopenharmony_ci unsigned short ovol, nvol; 37662306a36Sopenharmony_ci int change; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F); 38162306a36Sopenharmony_ci nvol = (0x1F - ucontrol->value.integer.value[0]) & 0x001F; 38262306a36Sopenharmony_ci if (kcontrol->private_value & AUREON_AC97_STEREO) 38362306a36Sopenharmony_ci nvol |= ((0x1F - ucontrol->value.integer.value[1]) << 8) & 0x1F00; 38462306a36Sopenharmony_ci nvol |= ovol & ~0x1F1F; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci change = (ovol != nvol); 38762306a36Sopenharmony_ci if (change) 38862306a36Sopenharmony_ci aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci return change; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci/* 39662306a36Sopenharmony_ci * AC'97 mute controls 39762306a36Sopenharmony_ci */ 39862306a36Sopenharmony_ci#define aureon_ac97_mute_info snd_ctl_boolean_mono_info 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic int aureon_ac97_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci ucontrol->value.integer.value[0] = aureon_ac97_read(ice, 40762306a36Sopenharmony_ci kcontrol->private_value & 0x7F) & 0x8000 ? 0 : 1; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 41062306a36Sopenharmony_ci return 0; 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic int aureon_ac97_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 41662306a36Sopenharmony_ci unsigned short ovol, nvol; 41762306a36Sopenharmony_ci int change; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci ovol = aureon_ac97_read(ice, kcontrol->private_value & 0x7F); 42262306a36Sopenharmony_ci nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x8000) | (ovol & ~0x8000); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci change = (ovol != nvol); 42562306a36Sopenharmony_ci if (change) 42662306a36Sopenharmony_ci aureon_ac97_write(ice, kcontrol->private_value & 0x7F, nvol); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci return change; 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci/* 43462306a36Sopenharmony_ci * AC'97 mute controls 43562306a36Sopenharmony_ci */ 43662306a36Sopenharmony_ci#define aureon_ac97_micboost_info snd_ctl_boolean_mono_info 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic int aureon_ac97_micboost_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 43962306a36Sopenharmony_ci{ 44062306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci ucontrol->value.integer.value[0] = aureon_ac97_read(ice, AC97_MIC) & 0x0020 ? 0 : 1; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 44762306a36Sopenharmony_ci return 0; 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic int aureon_ac97_micboost_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 45362306a36Sopenharmony_ci unsigned short ovol, nvol; 45462306a36Sopenharmony_ci int change; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci ovol = aureon_ac97_read(ice, AC97_MIC); 45962306a36Sopenharmony_ci nvol = (ucontrol->value.integer.value[0] ? 0x0000 : 0x0020) | (ovol & ~0x0020); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci change = (ovol != nvol); 46262306a36Sopenharmony_ci if (change) 46362306a36Sopenharmony_ci aureon_ac97_write(ice, AC97_MIC, nvol); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci return change; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci/* 47162306a36Sopenharmony_ci * write data in the SPI mode 47262306a36Sopenharmony_ci */ 47362306a36Sopenharmony_cistatic void aureon_spi_write(struct snd_ice1712 *ice, unsigned int cs, unsigned int data, int bits) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci unsigned int tmp; 47662306a36Sopenharmony_ci int i; 47762306a36Sopenharmony_ci unsigned int mosi, clk; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci tmp = snd_ice1712_gpio_read(ice); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT || 48262306a36Sopenharmony_ci ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) { 48362306a36Sopenharmony_ci snd_ice1712_gpio_set_mask(ice, ~(PRODIGY_SPI_MOSI|PRODIGY_SPI_CLK|PRODIGY_WM_CS)); 48462306a36Sopenharmony_ci mosi = PRODIGY_SPI_MOSI; 48562306a36Sopenharmony_ci clk = PRODIGY_SPI_CLK; 48662306a36Sopenharmony_ci } else { 48762306a36Sopenharmony_ci snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_SPI_MOSI|AUREON_SPI_CLK| 48862306a36Sopenharmony_ci AUREON_WM_CS|AUREON_CS8415_CS)); 48962306a36Sopenharmony_ci mosi = AUREON_SPI_MOSI; 49062306a36Sopenharmony_ci clk = AUREON_SPI_CLK; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci tmp |= AUREON_WM_RW; 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci tmp &= ~cs; 49662306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 49762306a36Sopenharmony_ci udelay(1); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci for (i = bits - 1; i >= 0; i--) { 50062306a36Sopenharmony_ci tmp &= ~clk; 50162306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 50262306a36Sopenharmony_ci udelay(1); 50362306a36Sopenharmony_ci if (data & (1 << i)) 50462306a36Sopenharmony_ci tmp |= mosi; 50562306a36Sopenharmony_ci else 50662306a36Sopenharmony_ci tmp &= ~mosi; 50762306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 50862306a36Sopenharmony_ci udelay(1); 50962306a36Sopenharmony_ci tmp |= clk; 51062306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 51162306a36Sopenharmony_ci udelay(1); 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci tmp &= ~clk; 51562306a36Sopenharmony_ci tmp |= cs; 51662306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 51762306a36Sopenharmony_ci udelay(1); 51862306a36Sopenharmony_ci tmp |= clk; 51962306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 52062306a36Sopenharmony_ci udelay(1); 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci/* 52462306a36Sopenharmony_ci * Read data in SPI mode 52562306a36Sopenharmony_ci */ 52662306a36Sopenharmony_cistatic void aureon_spi_read(struct snd_ice1712 *ice, unsigned int cs, 52762306a36Sopenharmony_ci unsigned int data, int bits, unsigned char *buffer, int size) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci int i, j; 53062306a36Sopenharmony_ci unsigned int tmp; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci tmp = (snd_ice1712_gpio_read(ice) & ~AUREON_SPI_CLK) | AUREON_CS8415_CS|AUREON_WM_CS; 53362306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 53462306a36Sopenharmony_ci tmp &= ~cs; 53562306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 53662306a36Sopenharmony_ci udelay(1); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci for (i = bits-1; i >= 0; i--) { 53962306a36Sopenharmony_ci if (data & (1 << i)) 54062306a36Sopenharmony_ci tmp |= AUREON_SPI_MOSI; 54162306a36Sopenharmony_ci else 54262306a36Sopenharmony_ci tmp &= ~AUREON_SPI_MOSI; 54362306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 54462306a36Sopenharmony_ci udelay(1); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci tmp |= AUREON_SPI_CLK; 54762306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 54862306a36Sopenharmony_ci udelay(1); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci tmp &= ~AUREON_SPI_CLK; 55162306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 55262306a36Sopenharmony_ci udelay(1); 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci for (j = 0; j < size; j++) { 55662306a36Sopenharmony_ci unsigned char outdata = 0; 55762306a36Sopenharmony_ci for (i = 7; i >= 0; i--) { 55862306a36Sopenharmony_ci tmp = snd_ice1712_gpio_read(ice); 55962306a36Sopenharmony_ci outdata <<= 1; 56062306a36Sopenharmony_ci outdata |= (tmp & AUREON_SPI_MISO) ? 1 : 0; 56162306a36Sopenharmony_ci udelay(1); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci tmp |= AUREON_SPI_CLK; 56462306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 56562306a36Sopenharmony_ci udelay(1); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci tmp &= ~AUREON_SPI_CLK; 56862306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 56962306a36Sopenharmony_ci udelay(1); 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci buffer[j] = outdata; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci tmp |= cs; 57562306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic unsigned char aureon_cs8415_get(struct snd_ice1712 *ice, int reg) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci unsigned char val; 58162306a36Sopenharmony_ci aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16); 58262306a36Sopenharmony_ci aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, &val, 1); 58362306a36Sopenharmony_ci return val; 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic void aureon_cs8415_read(struct snd_ice1712 *ice, int reg, 58762306a36Sopenharmony_ci unsigned char *buffer, int size) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci aureon_spi_write(ice, AUREON_CS8415_CS, 0x2000 | reg, 16); 59062306a36Sopenharmony_ci aureon_spi_read(ice, AUREON_CS8415_CS, 0x21, 8, buffer, size); 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic void aureon_cs8415_put(struct snd_ice1712 *ice, int reg, 59462306a36Sopenharmony_ci unsigned char val) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci aureon_spi_write(ice, AUREON_CS8415_CS, 0x200000 | (reg << 8) | val, 24); 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci/* 60062306a36Sopenharmony_ci * get the current register value of WM codec 60162306a36Sopenharmony_ci */ 60262306a36Sopenharmony_cistatic unsigned short wm_get(struct snd_ice1712 *ice, int reg) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci reg <<= 1; 60562306a36Sopenharmony_ci return ((unsigned short)ice->akm[0].images[reg] << 8) | 60662306a36Sopenharmony_ci ice->akm[0].images[reg + 1]; 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci/* 61062306a36Sopenharmony_ci * set the register value of WM codec 61162306a36Sopenharmony_ci */ 61262306a36Sopenharmony_cistatic void wm_put_nocache(struct snd_ice1712 *ice, int reg, unsigned short val) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci aureon_spi_write(ice, 61562306a36Sopenharmony_ci ((ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT || 61662306a36Sopenharmony_ci ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) ? 61762306a36Sopenharmony_ci PRODIGY_WM_CS : AUREON_WM_CS), 61862306a36Sopenharmony_ci (reg << 9) | (val & 0x1ff), 16); 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci/* 62262306a36Sopenharmony_ci * set the register value of WM codec and remember it 62362306a36Sopenharmony_ci */ 62462306a36Sopenharmony_cistatic void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci wm_put_nocache(ice, reg, val); 62762306a36Sopenharmony_ci reg <<= 1; 62862306a36Sopenharmony_ci ice->akm[0].images[reg] = val >> 8; 62962306a36Sopenharmony_ci ice->akm[0].images[reg + 1] = val; 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci/* 63362306a36Sopenharmony_ci */ 63462306a36Sopenharmony_ci#define aureon_mono_bool_info snd_ctl_boolean_mono_info 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci/* 63762306a36Sopenharmony_ci * AC'97 master playback mute controls (Mute on WM8770 chip) 63862306a36Sopenharmony_ci */ 63962306a36Sopenharmony_ci#define aureon_ac97_mmute_info snd_ctl_boolean_mono_info 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cistatic int aureon_ac97_mmute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci ucontrol->value.integer.value[0] = (wm_get(ice, WM_OUT_MUX1) >> 1) & 0x01; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 65062306a36Sopenharmony_ci return 0; 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 65662306a36Sopenharmony_ci unsigned short ovol, nvol; 65762306a36Sopenharmony_ci int change; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci ovol = wm_get(ice, WM_OUT_MUX1); 66262306a36Sopenharmony_ci nvol = (ovol & ~0x02) | (ucontrol->value.integer.value[0] ? 0x02 : 0x00); 66362306a36Sopenharmony_ci change = (ovol != nvol); 66462306a36Sopenharmony_ci if (change) 66562306a36Sopenharmony_ci wm_put(ice, WM_OUT_MUX1, nvol); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci return change; 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -10000, 100, 1); 67362306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1); 67462306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0); 67562306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0); 67662306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci#define WM_VOL_MAX 100 67962306a36Sopenharmony_ci#define WM_VOL_CNT 101 /* 0dB .. -100dB */ 68062306a36Sopenharmony_ci#define WM_VOL_MUTE 0x8000 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned short vol, unsigned short master) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci unsigned char nvol; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) { 68762306a36Sopenharmony_ci nvol = 0; 68862306a36Sopenharmony_ci } else { 68962306a36Sopenharmony_ci nvol = ((vol % WM_VOL_CNT) * (master % WM_VOL_CNT)) / 69062306a36Sopenharmony_ci WM_VOL_MAX; 69162306a36Sopenharmony_ci nvol += 0x1b; 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci wm_put(ice, index, nvol); 69562306a36Sopenharmony_ci wm_put_nocache(ice, index, 0x180 | nvol); 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci/* 69962306a36Sopenharmony_ci * DAC mute control 70062306a36Sopenharmony_ci */ 70162306a36Sopenharmony_ci#define wm_pcm_mute_info snd_ctl_boolean_mono_info 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_cistatic int wm_pcm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 70462306a36Sopenharmony_ci{ 70562306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 70862306a36Sopenharmony_ci ucontrol->value.integer.value[0] = (wm_get(ice, WM_MUTE) & 0x10) ? 0 : 1; 70962306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 71062306a36Sopenharmony_ci return 0; 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_cistatic int wm_pcm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 71462306a36Sopenharmony_ci{ 71562306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 71662306a36Sopenharmony_ci unsigned short nval, oval; 71762306a36Sopenharmony_ci int change; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 72062306a36Sopenharmony_ci oval = wm_get(ice, WM_MUTE); 72162306a36Sopenharmony_ci nval = (oval & ~0x10) | (ucontrol->value.integer.value[0] ? 0 : 0x10); 72262306a36Sopenharmony_ci change = (oval != nval); 72362306a36Sopenharmony_ci if (change) 72462306a36Sopenharmony_ci wm_put(ice, WM_MUTE, nval); 72562306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci return change; 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci/* 73162306a36Sopenharmony_ci * Master volume attenuation mixer control 73262306a36Sopenharmony_ci */ 73362306a36Sopenharmony_cistatic int wm_master_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 73662306a36Sopenharmony_ci uinfo->count = 2; 73762306a36Sopenharmony_ci uinfo->value.integer.min = 0; 73862306a36Sopenharmony_ci uinfo->value.integer.max = WM_VOL_MAX; 73962306a36Sopenharmony_ci return 0; 74062306a36Sopenharmony_ci} 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_cistatic int wm_master_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 74562306a36Sopenharmony_ci struct aureon_spec *spec = ice->spec; 74662306a36Sopenharmony_ci int i; 74762306a36Sopenharmony_ci for (i = 0; i < 2; i++) 74862306a36Sopenharmony_ci ucontrol->value.integer.value[i] = 74962306a36Sopenharmony_ci spec->master[i] & ~WM_VOL_MUTE; 75062306a36Sopenharmony_ci return 0; 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_cistatic int wm_master_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 75462306a36Sopenharmony_ci{ 75562306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 75662306a36Sopenharmony_ci struct aureon_spec *spec = ice->spec; 75762306a36Sopenharmony_ci int ch, change = 0; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 76062306a36Sopenharmony_ci for (ch = 0; ch < 2; ch++) { 76162306a36Sopenharmony_ci unsigned int vol = ucontrol->value.integer.value[ch]; 76262306a36Sopenharmony_ci if (vol > WM_VOL_MAX) 76362306a36Sopenharmony_ci vol = WM_VOL_MAX; 76462306a36Sopenharmony_ci vol |= spec->master[ch] & WM_VOL_MUTE; 76562306a36Sopenharmony_ci if (vol != spec->master[ch]) { 76662306a36Sopenharmony_ci int dac; 76762306a36Sopenharmony_ci spec->master[ch] = vol; 76862306a36Sopenharmony_ci for (dac = 0; dac < ice->num_total_dacs; dac += 2) 76962306a36Sopenharmony_ci wm_set_vol(ice, WM_DAC_ATTEN + dac + ch, 77062306a36Sopenharmony_ci spec->vol[dac + ch], 77162306a36Sopenharmony_ci spec->master[ch]); 77262306a36Sopenharmony_ci change = 1; 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 77662306a36Sopenharmony_ci return change; 77762306a36Sopenharmony_ci} 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci/* 78062306a36Sopenharmony_ci * DAC volume attenuation mixer control 78162306a36Sopenharmony_ci */ 78262306a36Sopenharmony_cistatic int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci int voices = kcontrol->private_value >> 8; 78562306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 78662306a36Sopenharmony_ci uinfo->count = voices; 78762306a36Sopenharmony_ci uinfo->value.integer.min = 0; /* mute (-101dB) */ 78862306a36Sopenharmony_ci uinfo->value.integer.max = WM_VOL_MAX; /* 0dB */ 78962306a36Sopenharmony_ci return 0; 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_cistatic int wm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 79362306a36Sopenharmony_ci{ 79462306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 79562306a36Sopenharmony_ci struct aureon_spec *spec = ice->spec; 79662306a36Sopenharmony_ci int i, ofs, voices; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci voices = kcontrol->private_value >> 8; 79962306a36Sopenharmony_ci ofs = kcontrol->private_value & 0xff; 80062306a36Sopenharmony_ci for (i = 0; i < voices; i++) 80162306a36Sopenharmony_ci ucontrol->value.integer.value[i] = 80262306a36Sopenharmony_ci spec->vol[ofs+i] & ~WM_VOL_MUTE; 80362306a36Sopenharmony_ci return 0; 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_cistatic int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 80962306a36Sopenharmony_ci struct aureon_spec *spec = ice->spec; 81062306a36Sopenharmony_ci int i, idx, ofs, voices; 81162306a36Sopenharmony_ci int change = 0; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci voices = kcontrol->private_value >> 8; 81462306a36Sopenharmony_ci ofs = kcontrol->private_value & 0xff; 81562306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 81662306a36Sopenharmony_ci for (i = 0; i < voices; i++) { 81762306a36Sopenharmony_ci unsigned int vol = ucontrol->value.integer.value[i]; 81862306a36Sopenharmony_ci if (vol > WM_VOL_MAX) 81962306a36Sopenharmony_ci vol = WM_VOL_MAX; 82062306a36Sopenharmony_ci vol |= spec->vol[ofs+i] & WM_VOL_MUTE; 82162306a36Sopenharmony_ci if (vol != spec->vol[ofs+i]) { 82262306a36Sopenharmony_ci spec->vol[ofs+i] = vol; 82362306a36Sopenharmony_ci idx = WM_DAC_ATTEN + ofs + i; 82462306a36Sopenharmony_ci wm_set_vol(ice, idx, spec->vol[ofs + i], 82562306a36Sopenharmony_ci spec->master[i]); 82662306a36Sopenharmony_ci change = 1; 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci } 82962306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 83062306a36Sopenharmony_ci return change; 83162306a36Sopenharmony_ci} 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci/* 83462306a36Sopenharmony_ci * WM8770 mute control 83562306a36Sopenharmony_ci */ 83662306a36Sopenharmony_cistatic int wm_mute_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 83762306a36Sopenharmony_ci{ 83862306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 83962306a36Sopenharmony_ci uinfo->count = kcontrol->private_value >> 8; 84062306a36Sopenharmony_ci uinfo->value.integer.min = 0; 84162306a36Sopenharmony_ci uinfo->value.integer.max = 1; 84262306a36Sopenharmony_ci return 0; 84362306a36Sopenharmony_ci} 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_cistatic int wm_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 84662306a36Sopenharmony_ci{ 84762306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 84862306a36Sopenharmony_ci struct aureon_spec *spec = ice->spec; 84962306a36Sopenharmony_ci int voices, ofs, i; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci voices = kcontrol->private_value >> 8; 85262306a36Sopenharmony_ci ofs = kcontrol->private_value & 0xFF; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci for (i = 0; i < voices; i++) 85562306a36Sopenharmony_ci ucontrol->value.integer.value[i] = 85662306a36Sopenharmony_ci (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1; 85762306a36Sopenharmony_ci return 0; 85862306a36Sopenharmony_ci} 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_cistatic int wm_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 86362306a36Sopenharmony_ci struct aureon_spec *spec = ice->spec; 86462306a36Sopenharmony_ci int change = 0, voices, ofs, i; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci voices = kcontrol->private_value >> 8; 86762306a36Sopenharmony_ci ofs = kcontrol->private_value & 0xFF; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 87062306a36Sopenharmony_ci for (i = 0; i < voices; i++) { 87162306a36Sopenharmony_ci int val = (spec->vol[ofs + i] & WM_VOL_MUTE) ? 0 : 1; 87262306a36Sopenharmony_ci if (ucontrol->value.integer.value[i] != val) { 87362306a36Sopenharmony_ci spec->vol[ofs + i] &= ~WM_VOL_MUTE; 87462306a36Sopenharmony_ci spec->vol[ofs + i] |= 87562306a36Sopenharmony_ci ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; 87662306a36Sopenharmony_ci wm_set_vol(ice, ofs + i, spec->vol[ofs + i], 87762306a36Sopenharmony_ci spec->master[i]); 87862306a36Sopenharmony_ci change = 1; 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci return change; 88462306a36Sopenharmony_ci} 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci/* 88762306a36Sopenharmony_ci * WM8770 master mute control 88862306a36Sopenharmony_ci */ 88962306a36Sopenharmony_ci#define wm_master_mute_info snd_ctl_boolean_stereo_info 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistatic int wm_master_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 89462306a36Sopenharmony_ci struct aureon_spec *spec = ice->spec; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 89762306a36Sopenharmony_ci (spec->master[0] & WM_VOL_MUTE) ? 0 : 1; 89862306a36Sopenharmony_ci ucontrol->value.integer.value[1] = 89962306a36Sopenharmony_ci (spec->master[1] & WM_VOL_MUTE) ? 0 : 1; 90062306a36Sopenharmony_ci return 0; 90162306a36Sopenharmony_ci} 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_cistatic int wm_master_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 90462306a36Sopenharmony_ci{ 90562306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 90662306a36Sopenharmony_ci struct aureon_spec *spec = ice->spec; 90762306a36Sopenharmony_ci int change = 0, i; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 91062306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 91162306a36Sopenharmony_ci int val = (spec->master[i] & WM_VOL_MUTE) ? 0 : 1; 91262306a36Sopenharmony_ci if (ucontrol->value.integer.value[i] != val) { 91362306a36Sopenharmony_ci int dac; 91462306a36Sopenharmony_ci spec->master[i] &= ~WM_VOL_MUTE; 91562306a36Sopenharmony_ci spec->master[i] |= 91662306a36Sopenharmony_ci ucontrol->value.integer.value[i] ? 0 : WM_VOL_MUTE; 91762306a36Sopenharmony_ci for (dac = 0; dac < ice->num_total_dacs; dac += 2) 91862306a36Sopenharmony_ci wm_set_vol(ice, WM_DAC_ATTEN + dac + i, 91962306a36Sopenharmony_ci spec->vol[dac + i], 92062306a36Sopenharmony_ci spec->master[i]); 92162306a36Sopenharmony_ci change = 1; 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci return change; 92762306a36Sopenharmony_ci} 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci/* digital master volume */ 93062306a36Sopenharmony_ci#define PCM_0dB 0xff 93162306a36Sopenharmony_ci#define PCM_RES 128 /* -64dB */ 93262306a36Sopenharmony_ci#define PCM_MIN (PCM_0dB - PCM_RES) 93362306a36Sopenharmony_cistatic int wm_pcm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 93462306a36Sopenharmony_ci{ 93562306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 93662306a36Sopenharmony_ci uinfo->count = 1; 93762306a36Sopenharmony_ci uinfo->value.integer.min = 0; /* mute (-64dB) */ 93862306a36Sopenharmony_ci uinfo->value.integer.max = PCM_RES; /* 0dB */ 93962306a36Sopenharmony_ci return 0; 94062306a36Sopenharmony_ci} 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_cistatic int wm_pcm_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 94362306a36Sopenharmony_ci{ 94462306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 94562306a36Sopenharmony_ci unsigned short val; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 94862306a36Sopenharmony_ci val = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; 94962306a36Sopenharmony_ci val = val > PCM_MIN ? (val - PCM_MIN) : 0; 95062306a36Sopenharmony_ci ucontrol->value.integer.value[0] = val; 95162306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 95262306a36Sopenharmony_ci return 0; 95362306a36Sopenharmony_ci} 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_cistatic int wm_pcm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 95662306a36Sopenharmony_ci{ 95762306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 95862306a36Sopenharmony_ci unsigned short ovol, nvol; 95962306a36Sopenharmony_ci int change = 0; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci nvol = ucontrol->value.integer.value[0]; 96262306a36Sopenharmony_ci if (nvol > PCM_RES) 96362306a36Sopenharmony_ci return -EINVAL; 96462306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 96562306a36Sopenharmony_ci nvol = (nvol ? (nvol + PCM_MIN) : 0) & 0xff; 96662306a36Sopenharmony_ci ovol = wm_get(ice, WM_DAC_DIG_MASTER_ATTEN) & 0xff; 96762306a36Sopenharmony_ci if (ovol != nvol) { 96862306a36Sopenharmony_ci wm_put(ice, WM_DAC_DIG_MASTER_ATTEN, nvol); /* prelatch */ 96962306a36Sopenharmony_ci wm_put_nocache(ice, WM_DAC_DIG_MASTER_ATTEN, nvol | 0x100); /* update */ 97062306a36Sopenharmony_ci change = 1; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 97362306a36Sopenharmony_ci return change; 97462306a36Sopenharmony_ci} 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci/* 97762306a36Sopenharmony_ci * ADC mute control 97862306a36Sopenharmony_ci */ 97962306a36Sopenharmony_ci#define wm_adc_mute_info snd_ctl_boolean_stereo_info 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_cistatic int wm_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 98262306a36Sopenharmony_ci{ 98362306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 98462306a36Sopenharmony_ci unsigned short val; 98562306a36Sopenharmony_ci int i; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 98862306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 98962306a36Sopenharmony_ci val = wm_get(ice, WM_ADC_GAIN + i); 99062306a36Sopenharmony_ci ucontrol->value.integer.value[i] = ~val>>5 & 0x1; 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 99362306a36Sopenharmony_ci return 0; 99462306a36Sopenharmony_ci} 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_cistatic int wm_adc_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 99762306a36Sopenharmony_ci{ 99862306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 99962306a36Sopenharmony_ci unsigned short new, old; 100062306a36Sopenharmony_ci int i, change = 0; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 100362306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 100462306a36Sopenharmony_ci old = wm_get(ice, WM_ADC_GAIN + i); 100562306a36Sopenharmony_ci new = (~ucontrol->value.integer.value[i]<<5&0x20) | (old&~0x20); 100662306a36Sopenharmony_ci if (new != old) { 100762306a36Sopenharmony_ci wm_put(ice, WM_ADC_GAIN + i, new); 100862306a36Sopenharmony_ci change = 1; 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci return change; 101462306a36Sopenharmony_ci} 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci/* 101762306a36Sopenharmony_ci * ADC gain mixer control 101862306a36Sopenharmony_ci */ 101962306a36Sopenharmony_cistatic int wm_adc_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 102062306a36Sopenharmony_ci{ 102162306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 102262306a36Sopenharmony_ci uinfo->count = 2; 102362306a36Sopenharmony_ci uinfo->value.integer.min = 0; /* -12dB */ 102462306a36Sopenharmony_ci uinfo->value.integer.max = 0x1f; /* 19dB */ 102562306a36Sopenharmony_ci return 0; 102662306a36Sopenharmony_ci} 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_cistatic int wm_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 102962306a36Sopenharmony_ci{ 103062306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 103162306a36Sopenharmony_ci int i, idx; 103262306a36Sopenharmony_ci unsigned short vol; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 103562306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 103662306a36Sopenharmony_ci idx = WM_ADC_GAIN + i; 103762306a36Sopenharmony_ci vol = wm_get(ice, idx) & 0x1f; 103862306a36Sopenharmony_ci ucontrol->value.integer.value[i] = vol; 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 104162306a36Sopenharmony_ci return 0; 104262306a36Sopenharmony_ci} 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_cistatic int wm_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 104562306a36Sopenharmony_ci{ 104662306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 104762306a36Sopenharmony_ci int i, idx; 104862306a36Sopenharmony_ci unsigned short ovol, nvol; 104962306a36Sopenharmony_ci int change = 0; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 105262306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 105362306a36Sopenharmony_ci idx = WM_ADC_GAIN + i; 105462306a36Sopenharmony_ci nvol = ucontrol->value.integer.value[i] & 0x1f; 105562306a36Sopenharmony_ci ovol = wm_get(ice, idx); 105662306a36Sopenharmony_ci if ((ovol & 0x1f) != nvol) { 105762306a36Sopenharmony_ci wm_put(ice, idx, nvol | (ovol & ~0x1f)); 105862306a36Sopenharmony_ci change = 1; 105962306a36Sopenharmony_ci } 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 106262306a36Sopenharmony_ci return change; 106362306a36Sopenharmony_ci} 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci/* 106662306a36Sopenharmony_ci * ADC input mux mixer control 106762306a36Sopenharmony_ci */ 106862306a36Sopenharmony_cistatic int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 106962306a36Sopenharmony_ci{ 107062306a36Sopenharmony_ci static const char * const texts[] = { 107162306a36Sopenharmony_ci "CD", /* AIN1 */ 107262306a36Sopenharmony_ci "Aux", /* AIN2 */ 107362306a36Sopenharmony_ci "Line", /* AIN3 */ 107462306a36Sopenharmony_ci "Mic", /* AIN4 */ 107562306a36Sopenharmony_ci "AC97" /* AIN5 */ 107662306a36Sopenharmony_ci }; 107762306a36Sopenharmony_ci static const char * const universe_texts[] = { 107862306a36Sopenharmony_ci "Aux1", /* AIN1 */ 107962306a36Sopenharmony_ci "CD", /* AIN2 */ 108062306a36Sopenharmony_ci "Phono", /* AIN3 */ 108162306a36Sopenharmony_ci "Line", /* AIN4 */ 108262306a36Sopenharmony_ci "Aux2", /* AIN5 */ 108362306a36Sopenharmony_ci "Mic", /* AIN6 */ 108462306a36Sopenharmony_ci "Aux3", /* AIN7 */ 108562306a36Sopenharmony_ci "AC97" /* AIN8 */ 108662306a36Sopenharmony_ci }; 108762306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) 109062306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 2, 8, universe_texts); 109162306a36Sopenharmony_ci else 109262306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 2, 5, texts); 109362306a36Sopenharmony_ci} 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_cistatic int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 109662306a36Sopenharmony_ci{ 109762306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 109862306a36Sopenharmony_ci unsigned short val; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 110162306a36Sopenharmony_ci val = wm_get(ice, WM_ADC_MUX); 110262306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = val & 7; 110362306a36Sopenharmony_ci ucontrol->value.enumerated.item[1] = (val >> 4) & 7; 110462306a36Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 110562306a36Sopenharmony_ci return 0; 110662306a36Sopenharmony_ci} 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_cistatic int wm_adc_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 110962306a36Sopenharmony_ci{ 111062306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 111162306a36Sopenharmony_ci unsigned short oval, nval; 111262306a36Sopenharmony_ci int change; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 111562306a36Sopenharmony_ci oval = wm_get(ice, WM_ADC_MUX); 111662306a36Sopenharmony_ci nval = oval & ~0x77; 111762306a36Sopenharmony_ci nval |= ucontrol->value.enumerated.item[0] & 7; 111862306a36Sopenharmony_ci nval |= (ucontrol->value.enumerated.item[1] & 7) << 4; 111962306a36Sopenharmony_ci change = (oval != nval); 112062306a36Sopenharmony_ci if (change) 112162306a36Sopenharmony_ci wm_put(ice, WM_ADC_MUX, nval); 112262306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 112362306a36Sopenharmony_ci return change; 112462306a36Sopenharmony_ci} 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci/* 112762306a36Sopenharmony_ci * CS8415 Input mux 112862306a36Sopenharmony_ci */ 112962306a36Sopenharmony_cistatic int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 113062306a36Sopenharmony_ci{ 113162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 113262306a36Sopenharmony_ci static const char * const aureon_texts[] = { 113362306a36Sopenharmony_ci "CD", /* RXP0 */ 113462306a36Sopenharmony_ci "Optical" /* RXP1 */ 113562306a36Sopenharmony_ci }; 113662306a36Sopenharmony_ci static const char * const prodigy_texts[] = { 113762306a36Sopenharmony_ci "CD", 113862306a36Sopenharmony_ci "Coax" 113962306a36Sopenharmony_ci }; 114062306a36Sopenharmony_ci if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71) 114162306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, prodigy_texts); 114262306a36Sopenharmony_ci else 114362306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, aureon_texts); 114462306a36Sopenharmony_ci} 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_cistatic int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 114762306a36Sopenharmony_ci{ 114862306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 114962306a36Sopenharmony_ci struct aureon_spec *spec = ice->spec; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci /* snd_ice1712_save_gpio_status(ice); */ 115262306a36Sopenharmony_ci /* val = aureon_cs8415_get(ice, CS8415_CTRL2); */ 115362306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = spec->cs8415_mux; 115462306a36Sopenharmony_ci /* snd_ice1712_restore_gpio_status(ice); */ 115562306a36Sopenharmony_ci return 0; 115662306a36Sopenharmony_ci} 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_cistatic int aureon_cs8415_mux_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 115962306a36Sopenharmony_ci{ 116062306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 116162306a36Sopenharmony_ci struct aureon_spec *spec = ice->spec; 116262306a36Sopenharmony_ci unsigned short oval, nval; 116362306a36Sopenharmony_ci int change; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 116662306a36Sopenharmony_ci oval = aureon_cs8415_get(ice, CS8415_CTRL2); 116762306a36Sopenharmony_ci nval = oval & ~0x07; 116862306a36Sopenharmony_ci nval |= ucontrol->value.enumerated.item[0] & 7; 116962306a36Sopenharmony_ci change = (oval != nval); 117062306a36Sopenharmony_ci if (change) 117162306a36Sopenharmony_ci aureon_cs8415_put(ice, CS8415_CTRL2, nval); 117262306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 117362306a36Sopenharmony_ci spec->cs8415_mux = ucontrol->value.enumerated.item[0]; 117462306a36Sopenharmony_ci return change; 117562306a36Sopenharmony_ci} 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_cistatic int aureon_cs8415_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 117862306a36Sopenharmony_ci{ 117962306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 118062306a36Sopenharmony_ci uinfo->count = 1; 118162306a36Sopenharmony_ci uinfo->value.integer.min = 0; 118262306a36Sopenharmony_ci uinfo->value.integer.max = 192000; 118362306a36Sopenharmony_ci return 0; 118462306a36Sopenharmony_ci} 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_cistatic int aureon_cs8415_rate_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 118762306a36Sopenharmony_ci{ 118862306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 118962306a36Sopenharmony_ci unsigned char ratio; 119062306a36Sopenharmony_ci ratio = aureon_cs8415_get(ice, CS8415_RATIO); 119162306a36Sopenharmony_ci ucontrol->value.integer.value[0] = (int)((unsigned int)ratio * 750); 119262306a36Sopenharmony_ci return 0; 119362306a36Sopenharmony_ci} 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci/* 119662306a36Sopenharmony_ci * CS8415A Mute 119762306a36Sopenharmony_ci */ 119862306a36Sopenharmony_ci#define aureon_cs8415_mute_info snd_ctl_boolean_mono_info 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_cistatic int aureon_cs8415_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 120162306a36Sopenharmony_ci{ 120262306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 120362306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 120462306a36Sopenharmony_ci ucontrol->value.integer.value[0] = (aureon_cs8415_get(ice, CS8415_CTRL1) & 0x20) ? 0 : 1; 120562306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 120662306a36Sopenharmony_ci return 0; 120762306a36Sopenharmony_ci} 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_cistatic int aureon_cs8415_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 121062306a36Sopenharmony_ci{ 121162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 121262306a36Sopenharmony_ci unsigned char oval, nval; 121362306a36Sopenharmony_ci int change; 121462306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 121562306a36Sopenharmony_ci oval = aureon_cs8415_get(ice, CS8415_CTRL1); 121662306a36Sopenharmony_ci if (ucontrol->value.integer.value[0]) 121762306a36Sopenharmony_ci nval = oval & ~0x20; 121862306a36Sopenharmony_ci else 121962306a36Sopenharmony_ci nval = oval | 0x20; 122062306a36Sopenharmony_ci change = (oval != nval); 122162306a36Sopenharmony_ci if (change) 122262306a36Sopenharmony_ci aureon_cs8415_put(ice, CS8415_CTRL1, nval); 122362306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 122462306a36Sopenharmony_ci return change; 122562306a36Sopenharmony_ci} 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci/* 122862306a36Sopenharmony_ci * CS8415A Q-Sub info 122962306a36Sopenharmony_ci */ 123062306a36Sopenharmony_cistatic int aureon_cs8415_qsub_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 123162306a36Sopenharmony_ci{ 123262306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; 123362306a36Sopenharmony_ci uinfo->count = 10; 123462306a36Sopenharmony_ci return 0; 123562306a36Sopenharmony_ci} 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_cistatic int aureon_cs8415_qsub_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 123862306a36Sopenharmony_ci{ 123962306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 124262306a36Sopenharmony_ci aureon_cs8415_read(ice, CS8415_QSUB, ucontrol->value.bytes.data, 10); 124362306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci return 0; 124662306a36Sopenharmony_ci} 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_cistatic int aureon_cs8415_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 124962306a36Sopenharmony_ci{ 125062306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 125162306a36Sopenharmony_ci uinfo->count = 1; 125262306a36Sopenharmony_ci return 0; 125362306a36Sopenharmony_ci} 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_cistatic int aureon_cs8415_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 125662306a36Sopenharmony_ci{ 125762306a36Sopenharmony_ci memset(ucontrol->value.iec958.status, 0xFF, 24); 125862306a36Sopenharmony_ci return 0; 125962306a36Sopenharmony_ci} 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_cistatic int aureon_cs8415_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 126262306a36Sopenharmony_ci{ 126362306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 126662306a36Sopenharmony_ci aureon_cs8415_read(ice, CS8415_C_BUFFER, ucontrol->value.iec958.status, 24); 126762306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 126862306a36Sopenharmony_ci return 0; 126962306a36Sopenharmony_ci} 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci/* 127262306a36Sopenharmony_ci * Headphone Amplifier 127362306a36Sopenharmony_ci */ 127462306a36Sopenharmony_cistatic int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable) 127562306a36Sopenharmony_ci{ 127662306a36Sopenharmony_ci unsigned int tmp, tmp2; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci tmp2 = tmp = snd_ice1712_gpio_read(ice); 127962306a36Sopenharmony_ci if (enable) 128062306a36Sopenharmony_ci if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT && 128162306a36Sopenharmony_ci ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) 128262306a36Sopenharmony_ci tmp |= AUREON_HP_SEL; 128362306a36Sopenharmony_ci else 128462306a36Sopenharmony_ci tmp |= PRODIGY_HP_SEL; 128562306a36Sopenharmony_ci else 128662306a36Sopenharmony_ci if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT && 128762306a36Sopenharmony_ci ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) 128862306a36Sopenharmony_ci tmp &= ~AUREON_HP_SEL; 128962306a36Sopenharmony_ci else 129062306a36Sopenharmony_ci tmp &= ~PRODIGY_HP_SEL; 129162306a36Sopenharmony_ci if (tmp != tmp2) { 129262306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 129362306a36Sopenharmony_ci return 1; 129462306a36Sopenharmony_ci } 129562306a36Sopenharmony_ci return 0; 129662306a36Sopenharmony_ci} 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_cistatic int aureon_get_headphone_amp(struct snd_ice1712 *ice) 129962306a36Sopenharmony_ci{ 130062306a36Sopenharmony_ci unsigned int tmp = snd_ice1712_gpio_read(ice); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci return (tmp & AUREON_HP_SEL) != 0; 130362306a36Sopenharmony_ci} 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci#define aureon_hpamp_info snd_ctl_boolean_mono_info 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_cistatic int aureon_hpamp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 130862306a36Sopenharmony_ci{ 130962306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci ucontrol->value.integer.value[0] = aureon_get_headphone_amp(ice); 131262306a36Sopenharmony_ci return 0; 131362306a36Sopenharmony_ci} 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_cistatic int aureon_hpamp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 131762306a36Sopenharmony_ci{ 131862306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci return aureon_set_headphone_amp(ice, ucontrol->value.integer.value[0]); 132162306a36Sopenharmony_ci} 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci/* 132462306a36Sopenharmony_ci * Deemphasis 132562306a36Sopenharmony_ci */ 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci#define aureon_deemp_info snd_ctl_boolean_mono_info 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_cistatic int aureon_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 133062306a36Sopenharmony_ci{ 133162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 133262306a36Sopenharmony_ci ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf; 133362306a36Sopenharmony_ci return 0; 133462306a36Sopenharmony_ci} 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_cistatic int aureon_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 133762306a36Sopenharmony_ci{ 133862306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 133962306a36Sopenharmony_ci int temp, temp2; 134062306a36Sopenharmony_ci temp2 = temp = wm_get(ice, WM_DAC_CTRL2); 134162306a36Sopenharmony_ci if (ucontrol->value.integer.value[0]) 134262306a36Sopenharmony_ci temp |= 0xf; 134362306a36Sopenharmony_ci else 134462306a36Sopenharmony_ci temp &= ~0xf; 134562306a36Sopenharmony_ci if (temp != temp2) { 134662306a36Sopenharmony_ci wm_put(ice, WM_DAC_CTRL2, temp); 134762306a36Sopenharmony_ci return 1; 134862306a36Sopenharmony_ci } 134962306a36Sopenharmony_ci return 0; 135062306a36Sopenharmony_ci} 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci/* 135362306a36Sopenharmony_ci * ADC Oversampling 135462306a36Sopenharmony_ci */ 135562306a36Sopenharmony_cistatic int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo) 135662306a36Sopenharmony_ci{ 135762306a36Sopenharmony_ci static const char * const texts[2] = { "128x", "64x" }; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, texts); 136062306a36Sopenharmony_ci} 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_cistatic int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 136362306a36Sopenharmony_ci{ 136462306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 136562306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8; 136662306a36Sopenharmony_ci return 0; 136762306a36Sopenharmony_ci} 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_cistatic int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 137062306a36Sopenharmony_ci{ 137162306a36Sopenharmony_ci int temp, temp2; 137262306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci temp2 = temp = wm_get(ice, WM_MASTER); 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci if (ucontrol->value.enumerated.item[0]) 137762306a36Sopenharmony_ci temp |= 0x8; 137862306a36Sopenharmony_ci else 137962306a36Sopenharmony_ci temp &= ~0x8; 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci if (temp != temp2) { 138262306a36Sopenharmony_ci wm_put(ice, WM_MASTER, temp); 138362306a36Sopenharmony_ci return 1; 138462306a36Sopenharmony_ci } 138562306a36Sopenharmony_ci return 0; 138662306a36Sopenharmony_ci} 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci/* 138962306a36Sopenharmony_ci * mixers 139062306a36Sopenharmony_ci */ 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_cistatic const struct snd_kcontrol_new aureon_dac_controls[] = { 139362306a36Sopenharmony_ci { 139462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 139562306a36Sopenharmony_ci .name = "Master Playback Switch", 139662306a36Sopenharmony_ci .info = wm_master_mute_info, 139762306a36Sopenharmony_ci .get = wm_master_mute_get, 139862306a36Sopenharmony_ci .put = wm_master_mute_put 139962306a36Sopenharmony_ci }, 140062306a36Sopenharmony_ci { 140162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 140262306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 140362306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 140462306a36Sopenharmony_ci .name = "Master Playback Volume", 140562306a36Sopenharmony_ci .info = wm_master_vol_info, 140662306a36Sopenharmony_ci .get = wm_master_vol_get, 140762306a36Sopenharmony_ci .put = wm_master_vol_put, 140862306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_dac } 140962306a36Sopenharmony_ci }, 141062306a36Sopenharmony_ci { 141162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 141262306a36Sopenharmony_ci .name = "Front Playback Switch", 141362306a36Sopenharmony_ci .info = wm_mute_info, 141462306a36Sopenharmony_ci .get = wm_mute_get, 141562306a36Sopenharmony_ci .put = wm_mute_put, 141662306a36Sopenharmony_ci .private_value = (2 << 8) | 0 141762306a36Sopenharmony_ci }, 141862306a36Sopenharmony_ci { 141962306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 142062306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 142162306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 142262306a36Sopenharmony_ci .name = "Front Playback Volume", 142362306a36Sopenharmony_ci .info = wm_vol_info, 142462306a36Sopenharmony_ci .get = wm_vol_get, 142562306a36Sopenharmony_ci .put = wm_vol_put, 142662306a36Sopenharmony_ci .private_value = (2 << 8) | 0, 142762306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_dac } 142862306a36Sopenharmony_ci }, 142962306a36Sopenharmony_ci { 143062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 143162306a36Sopenharmony_ci .name = "Rear Playback Switch", 143262306a36Sopenharmony_ci .info = wm_mute_info, 143362306a36Sopenharmony_ci .get = wm_mute_get, 143462306a36Sopenharmony_ci .put = wm_mute_put, 143562306a36Sopenharmony_ci .private_value = (2 << 8) | 2 143662306a36Sopenharmony_ci }, 143762306a36Sopenharmony_ci { 143862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 143962306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 144062306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 144162306a36Sopenharmony_ci .name = "Rear Playback Volume", 144262306a36Sopenharmony_ci .info = wm_vol_info, 144362306a36Sopenharmony_ci .get = wm_vol_get, 144462306a36Sopenharmony_ci .put = wm_vol_put, 144562306a36Sopenharmony_ci .private_value = (2 << 8) | 2, 144662306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_dac } 144762306a36Sopenharmony_ci }, 144862306a36Sopenharmony_ci { 144962306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 145062306a36Sopenharmony_ci .name = "Center Playback Switch", 145162306a36Sopenharmony_ci .info = wm_mute_info, 145262306a36Sopenharmony_ci .get = wm_mute_get, 145362306a36Sopenharmony_ci .put = wm_mute_put, 145462306a36Sopenharmony_ci .private_value = (1 << 8) | 4 145562306a36Sopenharmony_ci }, 145662306a36Sopenharmony_ci { 145762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 145862306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 145962306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 146062306a36Sopenharmony_ci .name = "Center Playback Volume", 146162306a36Sopenharmony_ci .info = wm_vol_info, 146262306a36Sopenharmony_ci .get = wm_vol_get, 146362306a36Sopenharmony_ci .put = wm_vol_put, 146462306a36Sopenharmony_ci .private_value = (1 << 8) | 4, 146562306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_dac } 146662306a36Sopenharmony_ci }, 146762306a36Sopenharmony_ci { 146862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 146962306a36Sopenharmony_ci .name = "LFE Playback Switch", 147062306a36Sopenharmony_ci .info = wm_mute_info, 147162306a36Sopenharmony_ci .get = wm_mute_get, 147262306a36Sopenharmony_ci .put = wm_mute_put, 147362306a36Sopenharmony_ci .private_value = (1 << 8) | 5 147462306a36Sopenharmony_ci }, 147562306a36Sopenharmony_ci { 147662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 147762306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 147862306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 147962306a36Sopenharmony_ci .name = "LFE Playback Volume", 148062306a36Sopenharmony_ci .info = wm_vol_info, 148162306a36Sopenharmony_ci .get = wm_vol_get, 148262306a36Sopenharmony_ci .put = wm_vol_put, 148362306a36Sopenharmony_ci .private_value = (1 << 8) | 5, 148462306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_dac } 148562306a36Sopenharmony_ci }, 148662306a36Sopenharmony_ci { 148762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 148862306a36Sopenharmony_ci .name = "Side Playback Switch", 148962306a36Sopenharmony_ci .info = wm_mute_info, 149062306a36Sopenharmony_ci .get = wm_mute_get, 149162306a36Sopenharmony_ci .put = wm_mute_put, 149262306a36Sopenharmony_ci .private_value = (2 << 8) | 6 149362306a36Sopenharmony_ci }, 149462306a36Sopenharmony_ci { 149562306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 149662306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 149762306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 149862306a36Sopenharmony_ci .name = "Side Playback Volume", 149962306a36Sopenharmony_ci .info = wm_vol_info, 150062306a36Sopenharmony_ci .get = wm_vol_get, 150162306a36Sopenharmony_ci .put = wm_vol_put, 150262306a36Sopenharmony_ci .private_value = (2 << 8) | 6, 150362306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_dac } 150462306a36Sopenharmony_ci } 150562306a36Sopenharmony_ci}; 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_cistatic const struct snd_kcontrol_new wm_controls[] = { 150862306a36Sopenharmony_ci { 150962306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 151062306a36Sopenharmony_ci .name = "PCM Playback Switch", 151162306a36Sopenharmony_ci .info = wm_pcm_mute_info, 151262306a36Sopenharmony_ci .get = wm_pcm_mute_get, 151362306a36Sopenharmony_ci .put = wm_pcm_mute_put 151462306a36Sopenharmony_ci }, 151562306a36Sopenharmony_ci { 151662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 151762306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 151862306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 151962306a36Sopenharmony_ci .name = "PCM Playback Volume", 152062306a36Sopenharmony_ci .info = wm_pcm_vol_info, 152162306a36Sopenharmony_ci .get = wm_pcm_vol_get, 152262306a36Sopenharmony_ci .put = wm_pcm_vol_put, 152362306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_pcm } 152462306a36Sopenharmony_ci }, 152562306a36Sopenharmony_ci { 152662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 152762306a36Sopenharmony_ci .name = "Capture Switch", 152862306a36Sopenharmony_ci .info = wm_adc_mute_info, 152962306a36Sopenharmony_ci .get = wm_adc_mute_get, 153062306a36Sopenharmony_ci .put = wm_adc_mute_put, 153162306a36Sopenharmony_ci }, 153262306a36Sopenharmony_ci { 153362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 153462306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 153562306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 153662306a36Sopenharmony_ci .name = "Capture Volume", 153762306a36Sopenharmony_ci .info = wm_adc_vol_info, 153862306a36Sopenharmony_ci .get = wm_adc_vol_get, 153962306a36Sopenharmony_ci .put = wm_adc_vol_put, 154062306a36Sopenharmony_ci .tlv = { .p = db_scale_wm_adc } 154162306a36Sopenharmony_ci }, 154262306a36Sopenharmony_ci { 154362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 154462306a36Sopenharmony_ci .name = "Capture Source", 154562306a36Sopenharmony_ci .info = wm_adc_mux_info, 154662306a36Sopenharmony_ci .get = wm_adc_mux_get, 154762306a36Sopenharmony_ci .put = wm_adc_mux_put, 154862306a36Sopenharmony_ci .private_value = 5 154962306a36Sopenharmony_ci }, 155062306a36Sopenharmony_ci { 155162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 155262306a36Sopenharmony_ci .name = "External Amplifier", 155362306a36Sopenharmony_ci .info = aureon_hpamp_info, 155462306a36Sopenharmony_ci .get = aureon_hpamp_get, 155562306a36Sopenharmony_ci .put = aureon_hpamp_put 155662306a36Sopenharmony_ci }, 155762306a36Sopenharmony_ci { 155862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 155962306a36Sopenharmony_ci .name = "DAC Deemphasis Switch", 156062306a36Sopenharmony_ci .info = aureon_deemp_info, 156162306a36Sopenharmony_ci .get = aureon_deemp_get, 156262306a36Sopenharmony_ci .put = aureon_deemp_put 156362306a36Sopenharmony_ci }, 156462306a36Sopenharmony_ci { 156562306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 156662306a36Sopenharmony_ci .name = "ADC Oversampling", 156762306a36Sopenharmony_ci .info = aureon_oversampling_info, 156862306a36Sopenharmony_ci .get = aureon_oversampling_get, 156962306a36Sopenharmony_ci .put = aureon_oversampling_put 157062306a36Sopenharmony_ci } 157162306a36Sopenharmony_ci}; 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_cistatic const struct snd_kcontrol_new ac97_controls[] = { 157462306a36Sopenharmony_ci { 157562306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 157662306a36Sopenharmony_ci .name = "AC97 Playback Switch", 157762306a36Sopenharmony_ci .info = aureon_ac97_mmute_info, 157862306a36Sopenharmony_ci .get = aureon_ac97_mmute_get, 157962306a36Sopenharmony_ci .put = aureon_ac97_mmute_put, 158062306a36Sopenharmony_ci .private_value = AC97_MASTER 158162306a36Sopenharmony_ci }, 158262306a36Sopenharmony_ci { 158362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 158462306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 158562306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 158662306a36Sopenharmony_ci .name = "AC97 Playback Volume", 158762306a36Sopenharmony_ci .info = aureon_ac97_vol_info, 158862306a36Sopenharmony_ci .get = aureon_ac97_vol_get, 158962306a36Sopenharmony_ci .put = aureon_ac97_vol_put, 159062306a36Sopenharmony_ci .private_value = AC97_MASTER|AUREON_AC97_STEREO, 159162306a36Sopenharmony_ci .tlv = { .p = db_scale_ac97_master } 159262306a36Sopenharmony_ci }, 159362306a36Sopenharmony_ci { 159462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 159562306a36Sopenharmony_ci .name = "CD Playback Switch", 159662306a36Sopenharmony_ci .info = aureon_ac97_mute_info, 159762306a36Sopenharmony_ci .get = aureon_ac97_mute_get, 159862306a36Sopenharmony_ci .put = aureon_ac97_mute_put, 159962306a36Sopenharmony_ci .private_value = AC97_CD 160062306a36Sopenharmony_ci }, 160162306a36Sopenharmony_ci { 160262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 160362306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 160462306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 160562306a36Sopenharmony_ci .name = "CD Playback Volume", 160662306a36Sopenharmony_ci .info = aureon_ac97_vol_info, 160762306a36Sopenharmony_ci .get = aureon_ac97_vol_get, 160862306a36Sopenharmony_ci .put = aureon_ac97_vol_put, 160962306a36Sopenharmony_ci .private_value = AC97_CD|AUREON_AC97_STEREO, 161062306a36Sopenharmony_ci .tlv = { .p = db_scale_ac97_gain } 161162306a36Sopenharmony_ci }, 161262306a36Sopenharmony_ci { 161362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 161462306a36Sopenharmony_ci .name = "Aux Playback Switch", 161562306a36Sopenharmony_ci .info = aureon_ac97_mute_info, 161662306a36Sopenharmony_ci .get = aureon_ac97_mute_get, 161762306a36Sopenharmony_ci .put = aureon_ac97_mute_put, 161862306a36Sopenharmony_ci .private_value = AC97_AUX, 161962306a36Sopenharmony_ci }, 162062306a36Sopenharmony_ci { 162162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 162262306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 162362306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 162462306a36Sopenharmony_ci .name = "Aux Playback Volume", 162562306a36Sopenharmony_ci .info = aureon_ac97_vol_info, 162662306a36Sopenharmony_ci .get = aureon_ac97_vol_get, 162762306a36Sopenharmony_ci .put = aureon_ac97_vol_put, 162862306a36Sopenharmony_ci .private_value = AC97_AUX|AUREON_AC97_STEREO, 162962306a36Sopenharmony_ci .tlv = { .p = db_scale_ac97_gain } 163062306a36Sopenharmony_ci }, 163162306a36Sopenharmony_ci { 163262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 163362306a36Sopenharmony_ci .name = "Line Playback Switch", 163462306a36Sopenharmony_ci .info = aureon_ac97_mute_info, 163562306a36Sopenharmony_ci .get = aureon_ac97_mute_get, 163662306a36Sopenharmony_ci .put = aureon_ac97_mute_put, 163762306a36Sopenharmony_ci .private_value = AC97_LINE 163862306a36Sopenharmony_ci }, 163962306a36Sopenharmony_ci { 164062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 164162306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 164262306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 164362306a36Sopenharmony_ci .name = "Line Playback Volume", 164462306a36Sopenharmony_ci .info = aureon_ac97_vol_info, 164562306a36Sopenharmony_ci .get = aureon_ac97_vol_get, 164662306a36Sopenharmony_ci .put = aureon_ac97_vol_put, 164762306a36Sopenharmony_ci .private_value = AC97_LINE|AUREON_AC97_STEREO, 164862306a36Sopenharmony_ci .tlv = { .p = db_scale_ac97_gain } 164962306a36Sopenharmony_ci }, 165062306a36Sopenharmony_ci { 165162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 165262306a36Sopenharmony_ci .name = "Mic Playback Switch", 165362306a36Sopenharmony_ci .info = aureon_ac97_mute_info, 165462306a36Sopenharmony_ci .get = aureon_ac97_mute_get, 165562306a36Sopenharmony_ci .put = aureon_ac97_mute_put, 165662306a36Sopenharmony_ci .private_value = AC97_MIC 165762306a36Sopenharmony_ci }, 165862306a36Sopenharmony_ci { 165962306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 166062306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 166162306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 166262306a36Sopenharmony_ci .name = "Mic Playback Volume", 166362306a36Sopenharmony_ci .info = aureon_ac97_vol_info, 166462306a36Sopenharmony_ci .get = aureon_ac97_vol_get, 166562306a36Sopenharmony_ci .put = aureon_ac97_vol_put, 166662306a36Sopenharmony_ci .private_value = AC97_MIC, 166762306a36Sopenharmony_ci .tlv = { .p = db_scale_ac97_gain } 166862306a36Sopenharmony_ci }, 166962306a36Sopenharmony_ci { 167062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 167162306a36Sopenharmony_ci .name = "Mic Boost (+20dB)", 167262306a36Sopenharmony_ci .info = aureon_ac97_micboost_info, 167362306a36Sopenharmony_ci .get = aureon_ac97_micboost_get, 167462306a36Sopenharmony_ci .put = aureon_ac97_micboost_put 167562306a36Sopenharmony_ci } 167662306a36Sopenharmony_ci}; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_cistatic const struct snd_kcontrol_new universe_ac97_controls[] = { 167962306a36Sopenharmony_ci { 168062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 168162306a36Sopenharmony_ci .name = "AC97 Playback Switch", 168262306a36Sopenharmony_ci .info = aureon_ac97_mmute_info, 168362306a36Sopenharmony_ci .get = aureon_ac97_mmute_get, 168462306a36Sopenharmony_ci .put = aureon_ac97_mmute_put, 168562306a36Sopenharmony_ci .private_value = AC97_MASTER 168662306a36Sopenharmony_ci }, 168762306a36Sopenharmony_ci { 168862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 168962306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 169062306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 169162306a36Sopenharmony_ci .name = "AC97 Playback Volume", 169262306a36Sopenharmony_ci .info = aureon_ac97_vol_info, 169362306a36Sopenharmony_ci .get = aureon_ac97_vol_get, 169462306a36Sopenharmony_ci .put = aureon_ac97_vol_put, 169562306a36Sopenharmony_ci .private_value = AC97_MASTER|AUREON_AC97_STEREO, 169662306a36Sopenharmony_ci .tlv = { .p = db_scale_ac97_master } 169762306a36Sopenharmony_ci }, 169862306a36Sopenharmony_ci { 169962306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 170062306a36Sopenharmony_ci .name = "CD Playback Switch", 170162306a36Sopenharmony_ci .info = aureon_ac97_mute_info, 170262306a36Sopenharmony_ci .get = aureon_ac97_mute_get, 170362306a36Sopenharmony_ci .put = aureon_ac97_mute_put, 170462306a36Sopenharmony_ci .private_value = AC97_AUX 170562306a36Sopenharmony_ci }, 170662306a36Sopenharmony_ci { 170762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 170862306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 170962306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 171062306a36Sopenharmony_ci .name = "CD Playback Volume", 171162306a36Sopenharmony_ci .info = aureon_ac97_vol_info, 171262306a36Sopenharmony_ci .get = aureon_ac97_vol_get, 171362306a36Sopenharmony_ci .put = aureon_ac97_vol_put, 171462306a36Sopenharmony_ci .private_value = AC97_AUX|AUREON_AC97_STEREO, 171562306a36Sopenharmony_ci .tlv = { .p = db_scale_ac97_gain } 171662306a36Sopenharmony_ci }, 171762306a36Sopenharmony_ci { 171862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 171962306a36Sopenharmony_ci .name = "Phono Playback Switch", 172062306a36Sopenharmony_ci .info = aureon_ac97_mute_info, 172162306a36Sopenharmony_ci .get = aureon_ac97_mute_get, 172262306a36Sopenharmony_ci .put = aureon_ac97_mute_put, 172362306a36Sopenharmony_ci .private_value = AC97_CD 172462306a36Sopenharmony_ci }, 172562306a36Sopenharmony_ci { 172662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 172762306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 172862306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 172962306a36Sopenharmony_ci .name = "Phono Playback Volume", 173062306a36Sopenharmony_ci .info = aureon_ac97_vol_info, 173162306a36Sopenharmony_ci .get = aureon_ac97_vol_get, 173262306a36Sopenharmony_ci .put = aureon_ac97_vol_put, 173362306a36Sopenharmony_ci .private_value = AC97_CD|AUREON_AC97_STEREO, 173462306a36Sopenharmony_ci .tlv = { .p = db_scale_ac97_gain } 173562306a36Sopenharmony_ci }, 173662306a36Sopenharmony_ci { 173762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 173862306a36Sopenharmony_ci .name = "Line Playback Switch", 173962306a36Sopenharmony_ci .info = aureon_ac97_mute_info, 174062306a36Sopenharmony_ci .get = aureon_ac97_mute_get, 174162306a36Sopenharmony_ci .put = aureon_ac97_mute_put, 174262306a36Sopenharmony_ci .private_value = AC97_LINE 174362306a36Sopenharmony_ci }, 174462306a36Sopenharmony_ci { 174562306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 174662306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 174762306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 174862306a36Sopenharmony_ci .name = "Line Playback Volume", 174962306a36Sopenharmony_ci .info = aureon_ac97_vol_info, 175062306a36Sopenharmony_ci .get = aureon_ac97_vol_get, 175162306a36Sopenharmony_ci .put = aureon_ac97_vol_put, 175262306a36Sopenharmony_ci .private_value = AC97_LINE|AUREON_AC97_STEREO, 175362306a36Sopenharmony_ci .tlv = { .p = db_scale_ac97_gain } 175462306a36Sopenharmony_ci }, 175562306a36Sopenharmony_ci { 175662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 175762306a36Sopenharmony_ci .name = "Mic Playback Switch", 175862306a36Sopenharmony_ci .info = aureon_ac97_mute_info, 175962306a36Sopenharmony_ci .get = aureon_ac97_mute_get, 176062306a36Sopenharmony_ci .put = aureon_ac97_mute_put, 176162306a36Sopenharmony_ci .private_value = AC97_MIC 176262306a36Sopenharmony_ci }, 176362306a36Sopenharmony_ci { 176462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 176562306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 176662306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 176762306a36Sopenharmony_ci .name = "Mic Playback Volume", 176862306a36Sopenharmony_ci .info = aureon_ac97_vol_info, 176962306a36Sopenharmony_ci .get = aureon_ac97_vol_get, 177062306a36Sopenharmony_ci .put = aureon_ac97_vol_put, 177162306a36Sopenharmony_ci .private_value = AC97_MIC, 177262306a36Sopenharmony_ci .tlv = { .p = db_scale_ac97_gain } 177362306a36Sopenharmony_ci }, 177462306a36Sopenharmony_ci { 177562306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 177662306a36Sopenharmony_ci .name = "Mic Boost (+20dB)", 177762306a36Sopenharmony_ci .info = aureon_ac97_micboost_info, 177862306a36Sopenharmony_ci .get = aureon_ac97_micboost_get, 177962306a36Sopenharmony_ci .put = aureon_ac97_micboost_put 178062306a36Sopenharmony_ci }, 178162306a36Sopenharmony_ci { 178262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 178362306a36Sopenharmony_ci .name = "Aux Playback Switch", 178462306a36Sopenharmony_ci .info = aureon_ac97_mute_info, 178562306a36Sopenharmony_ci .get = aureon_ac97_mute_get, 178662306a36Sopenharmony_ci .put = aureon_ac97_mute_put, 178762306a36Sopenharmony_ci .private_value = AC97_VIDEO, 178862306a36Sopenharmony_ci }, 178962306a36Sopenharmony_ci { 179062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 179162306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 179262306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 179362306a36Sopenharmony_ci .name = "Aux Playback Volume", 179462306a36Sopenharmony_ci .info = aureon_ac97_vol_info, 179562306a36Sopenharmony_ci .get = aureon_ac97_vol_get, 179662306a36Sopenharmony_ci .put = aureon_ac97_vol_put, 179762306a36Sopenharmony_ci .private_value = AC97_VIDEO|AUREON_AC97_STEREO, 179862306a36Sopenharmony_ci .tlv = { .p = db_scale_ac97_gain } 179962306a36Sopenharmony_ci }, 180062306a36Sopenharmony_ci { 180162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 180262306a36Sopenharmony_ci .name = "Aux Source", 180362306a36Sopenharmony_ci .info = aureon_universe_inmux_info, 180462306a36Sopenharmony_ci .get = aureon_universe_inmux_get, 180562306a36Sopenharmony_ci .put = aureon_universe_inmux_put 180662306a36Sopenharmony_ci } 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci}; 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_cistatic const struct snd_kcontrol_new cs8415_controls[] = { 181162306a36Sopenharmony_ci { 181262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 181362306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, SWITCH), 181462306a36Sopenharmony_ci .info = aureon_cs8415_mute_info, 181562306a36Sopenharmony_ci .get = aureon_cs8415_mute_get, 181662306a36Sopenharmony_ci .put = aureon_cs8415_mute_put 181762306a36Sopenharmony_ci }, 181862306a36Sopenharmony_ci { 181962306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 182062306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Source", 182162306a36Sopenharmony_ci .info = aureon_cs8415_mux_info, 182262306a36Sopenharmony_ci .get = aureon_cs8415_mux_get, 182362306a36Sopenharmony_ci .put = aureon_cs8415_mux_put, 182462306a36Sopenharmony_ci }, 182562306a36Sopenharmony_ci { 182662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 182762306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("Q-subcode ", CAPTURE, DEFAULT), 182862306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 182962306a36Sopenharmony_ci .info = aureon_cs8415_qsub_info, 183062306a36Sopenharmony_ci .get = aureon_cs8415_qsub_get, 183162306a36Sopenharmony_ci }, 183262306a36Sopenharmony_ci { 183362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 183462306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK), 183562306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 183662306a36Sopenharmony_ci .info = aureon_cs8415_spdif_info, 183762306a36Sopenharmony_ci .get = aureon_cs8415_mask_get 183862306a36Sopenharmony_ci }, 183962306a36Sopenharmony_ci { 184062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 184162306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), 184262306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 184362306a36Sopenharmony_ci .info = aureon_cs8415_spdif_info, 184462306a36Sopenharmony_ci .get = aureon_cs8415_spdif_get 184562306a36Sopenharmony_ci }, 184662306a36Sopenharmony_ci { 184762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 184862306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Rate", 184962306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, 185062306a36Sopenharmony_ci .info = aureon_cs8415_rate_info, 185162306a36Sopenharmony_ci .get = aureon_cs8415_rate_get 185262306a36Sopenharmony_ci } 185362306a36Sopenharmony_ci}; 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_cistatic int aureon_add_controls(struct snd_ice1712 *ice) 185662306a36Sopenharmony_ci{ 185762306a36Sopenharmony_ci unsigned int i, counts; 185862306a36Sopenharmony_ci int err; 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci counts = ARRAY_SIZE(aureon_dac_controls); 186162306a36Sopenharmony_ci if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) 186262306a36Sopenharmony_ci counts -= 2; /* no side */ 186362306a36Sopenharmony_ci for (i = 0; i < counts; i++) { 186462306a36Sopenharmony_ci err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon_dac_controls[i], ice)); 186562306a36Sopenharmony_ci if (err < 0) 186662306a36Sopenharmony_ci return err; 186762306a36Sopenharmony_ci } 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(wm_controls); i++) { 187062306a36Sopenharmony_ci err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice)); 187162306a36Sopenharmony_ci if (err < 0) 187262306a36Sopenharmony_ci return err; 187362306a36Sopenharmony_ci } 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) { 187662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(universe_ac97_controls); i++) { 187762306a36Sopenharmony_ci err = snd_ctl_add(ice->card, snd_ctl_new1(&universe_ac97_controls[i], ice)); 187862306a36Sopenharmony_ci if (err < 0) 187962306a36Sopenharmony_ci return err; 188062306a36Sopenharmony_ci } 188162306a36Sopenharmony_ci } else if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT && 188262306a36Sopenharmony_ci ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) { 188362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ac97_controls); i++) { 188462306a36Sopenharmony_ci err = snd_ctl_add(ice->card, snd_ctl_new1(&ac97_controls[i], ice)); 188562306a36Sopenharmony_ci if (err < 0) 188662306a36Sopenharmony_ci return err; 188762306a36Sopenharmony_ci } 188862306a36Sopenharmony_ci } 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT && 189162306a36Sopenharmony_ci ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) { 189262306a36Sopenharmony_ci unsigned char id; 189362306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 189462306a36Sopenharmony_ci id = aureon_cs8415_get(ice, CS8415_ID); 189562306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 189662306a36Sopenharmony_ci if (id != 0x41) 189762306a36Sopenharmony_ci dev_info(ice->card->dev, 189862306a36Sopenharmony_ci "No CS8415 chip. Skipping CS8415 controls.\n"); 189962306a36Sopenharmony_ci else { 190062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cs8415_controls); i++) { 190162306a36Sopenharmony_ci struct snd_kcontrol *kctl; 190262306a36Sopenharmony_ci kctl = snd_ctl_new1(&cs8415_controls[i], ice); 190362306a36Sopenharmony_ci if (i > 1) 190462306a36Sopenharmony_ci kctl->id.device = ice->pcm->device; 190562306a36Sopenharmony_ci err = snd_ctl_add(ice->card, kctl); 190662306a36Sopenharmony_ci if (err < 0) 190762306a36Sopenharmony_ci return err; 190862306a36Sopenharmony_ci } 190962306a36Sopenharmony_ci } 191062306a36Sopenharmony_ci } 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci return 0; 191362306a36Sopenharmony_ci} 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci/* 191662306a36Sopenharmony_ci * reset the chip 191762306a36Sopenharmony_ci */ 191862306a36Sopenharmony_cistatic int aureon_reset(struct snd_ice1712 *ice) 191962306a36Sopenharmony_ci{ 192062306a36Sopenharmony_ci static const unsigned short wm_inits_aureon[] = { 192162306a36Sopenharmony_ci /* These come first to reduce init pop noise */ 192262306a36Sopenharmony_ci 0x1b, 0x044, /* ADC Mux (AC'97 source) */ 192362306a36Sopenharmony_ci 0x1c, 0x00B, /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */ 192462306a36Sopenharmony_ci 0x1d, 0x009, /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */ 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci 0x18, 0x000, /* All power-up */ 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci 0x16, 0x122, /* I2S, normal polarity, 24bit */ 192962306a36Sopenharmony_ci 0x17, 0x022, /* 256fs, slave mode */ 193062306a36Sopenharmony_ci 0x00, 0, /* DAC1 analog mute */ 193162306a36Sopenharmony_ci 0x01, 0, /* DAC2 analog mute */ 193262306a36Sopenharmony_ci 0x02, 0, /* DAC3 analog mute */ 193362306a36Sopenharmony_ci 0x03, 0, /* DAC4 analog mute */ 193462306a36Sopenharmony_ci 0x04, 0, /* DAC5 analog mute */ 193562306a36Sopenharmony_ci 0x05, 0, /* DAC6 analog mute */ 193662306a36Sopenharmony_ci 0x06, 0, /* DAC7 analog mute */ 193762306a36Sopenharmony_ci 0x07, 0, /* DAC8 analog mute */ 193862306a36Sopenharmony_ci 0x08, 0x100, /* master analog mute */ 193962306a36Sopenharmony_ci 0x09, 0xff, /* DAC1 digital full */ 194062306a36Sopenharmony_ci 0x0a, 0xff, /* DAC2 digital full */ 194162306a36Sopenharmony_ci 0x0b, 0xff, /* DAC3 digital full */ 194262306a36Sopenharmony_ci 0x0c, 0xff, /* DAC4 digital full */ 194362306a36Sopenharmony_ci 0x0d, 0xff, /* DAC5 digital full */ 194462306a36Sopenharmony_ci 0x0e, 0xff, /* DAC6 digital full */ 194562306a36Sopenharmony_ci 0x0f, 0xff, /* DAC7 digital full */ 194662306a36Sopenharmony_ci 0x10, 0xff, /* DAC8 digital full */ 194762306a36Sopenharmony_ci 0x11, 0x1ff, /* master digital full */ 194862306a36Sopenharmony_ci 0x12, 0x000, /* phase normal */ 194962306a36Sopenharmony_ci 0x13, 0x090, /* unmute DAC L/R */ 195062306a36Sopenharmony_ci 0x14, 0x000, /* all unmute */ 195162306a36Sopenharmony_ci 0x15, 0x000, /* no deemphasis, no ZFLG */ 195262306a36Sopenharmony_ci 0x19, 0x000, /* -12dB ADC/L */ 195362306a36Sopenharmony_ci 0x1a, 0x000, /* -12dB ADC/R */ 195462306a36Sopenharmony_ci (unsigned short)-1 195562306a36Sopenharmony_ci }; 195662306a36Sopenharmony_ci static const unsigned short wm_inits_prodigy[] = { 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci /* These come first to reduce init pop noise */ 195962306a36Sopenharmony_ci 0x1b, 0x000, /* ADC Mux */ 196062306a36Sopenharmony_ci 0x1c, 0x009, /* Out Mux1 */ 196162306a36Sopenharmony_ci 0x1d, 0x009, /* Out Mux2 */ 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci 0x18, 0x000, /* All power-up */ 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci 0x16, 0x022, /* I2S, normal polarity, 24bit, high-pass on */ 196662306a36Sopenharmony_ci 0x17, 0x006, /* 128fs, slave mode */ 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci 0x00, 0, /* DAC1 analog mute */ 196962306a36Sopenharmony_ci 0x01, 0, /* DAC2 analog mute */ 197062306a36Sopenharmony_ci 0x02, 0, /* DAC3 analog mute */ 197162306a36Sopenharmony_ci 0x03, 0, /* DAC4 analog mute */ 197262306a36Sopenharmony_ci 0x04, 0, /* DAC5 analog mute */ 197362306a36Sopenharmony_ci 0x05, 0, /* DAC6 analog mute */ 197462306a36Sopenharmony_ci 0x06, 0, /* DAC7 analog mute */ 197562306a36Sopenharmony_ci 0x07, 0, /* DAC8 analog mute */ 197662306a36Sopenharmony_ci 0x08, 0x100, /* master analog mute */ 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci 0x09, 0x7f, /* DAC1 digital full */ 197962306a36Sopenharmony_ci 0x0a, 0x7f, /* DAC2 digital full */ 198062306a36Sopenharmony_ci 0x0b, 0x7f, /* DAC3 digital full */ 198162306a36Sopenharmony_ci 0x0c, 0x7f, /* DAC4 digital full */ 198262306a36Sopenharmony_ci 0x0d, 0x7f, /* DAC5 digital full */ 198362306a36Sopenharmony_ci 0x0e, 0x7f, /* DAC6 digital full */ 198462306a36Sopenharmony_ci 0x0f, 0x7f, /* DAC7 digital full */ 198562306a36Sopenharmony_ci 0x10, 0x7f, /* DAC8 digital full */ 198662306a36Sopenharmony_ci 0x11, 0x1FF, /* master digital full */ 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci 0x12, 0x000, /* phase normal */ 198962306a36Sopenharmony_ci 0x13, 0x090, /* unmute DAC L/R */ 199062306a36Sopenharmony_ci 0x14, 0x000, /* all unmute */ 199162306a36Sopenharmony_ci 0x15, 0x000, /* no deemphasis, no ZFLG */ 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci 0x19, 0x000, /* -12dB ADC/L */ 199462306a36Sopenharmony_ci 0x1a, 0x000, /* -12dB ADC/R */ 199562306a36Sopenharmony_ci (unsigned short)-1 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci }; 199862306a36Sopenharmony_ci static const unsigned short cs_inits[] = { 199962306a36Sopenharmony_ci 0x0441, /* RUN */ 200062306a36Sopenharmony_ci 0x0180, /* no mute, OMCK output on RMCK pin */ 200162306a36Sopenharmony_ci 0x0201, /* S/PDIF source on RXP1 */ 200262306a36Sopenharmony_ci 0x0605, /* slave, 24bit, MSB on second OSCLK, SDOUT for right channel when OLRCK is high */ 200362306a36Sopenharmony_ci (unsigned short)-1 200462306a36Sopenharmony_ci }; 200562306a36Sopenharmony_ci unsigned int tmp; 200662306a36Sopenharmony_ci const unsigned short *p; 200762306a36Sopenharmony_ci int err; 200862306a36Sopenharmony_ci struct aureon_spec *spec = ice->spec; 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ci err = aureon_ac97_init(ice); 201162306a36Sopenharmony_ci if (err != 0) 201262306a36Sopenharmony_ci return err; 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci snd_ice1712_gpio_set_dir(ice, 0x5fffff); /* fix this for the time being */ 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_ci /* reset the wm codec as the SPI mode */ 201762306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 201862306a36Sopenharmony_ci snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RESET|AUREON_WM_CS|AUREON_CS8415_CS|AUREON_HP_SEL)); 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci tmp = snd_ice1712_gpio_read(ice); 202162306a36Sopenharmony_ci tmp &= ~AUREON_WM_RESET; 202262306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 202362306a36Sopenharmony_ci udelay(1); 202462306a36Sopenharmony_ci tmp |= AUREON_WM_CS | AUREON_CS8415_CS; 202562306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 202662306a36Sopenharmony_ci udelay(1); 202762306a36Sopenharmony_ci tmp |= AUREON_WM_RESET; 202862306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 202962306a36Sopenharmony_ci udelay(1); 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci /* initialize WM8770 codec */ 203262306a36Sopenharmony_ci if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71 || 203362306a36Sopenharmony_ci ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71LT || 203462306a36Sopenharmony_ci ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71XT) 203562306a36Sopenharmony_ci p = wm_inits_prodigy; 203662306a36Sopenharmony_ci else 203762306a36Sopenharmony_ci p = wm_inits_aureon; 203862306a36Sopenharmony_ci for (; *p != (unsigned short)-1; p += 2) 203962306a36Sopenharmony_ci wm_put(ice, p[0], p[1]); 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_ci /* initialize CS8415A codec */ 204262306a36Sopenharmony_ci if (ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71LT && 204362306a36Sopenharmony_ci ice->eeprom.subvendor != VT1724_SUBDEVICE_PRODIGY71XT) { 204462306a36Sopenharmony_ci for (p = cs_inits; *p != (unsigned short)-1; p++) 204562306a36Sopenharmony_ci aureon_spi_write(ice, AUREON_CS8415_CS, *p | 0x200000, 24); 204662306a36Sopenharmony_ci spec->cs8415_mux = 1; 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_ci aureon_set_headphone_amp(ice, 1); 204962306a36Sopenharmony_ci } 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci /* initialize PCA9554 pin directions & set default input */ 205462306a36Sopenharmony_ci aureon_pca9554_write(ice, PCA9554_DIR, 0x00); 205562306a36Sopenharmony_ci aureon_pca9554_write(ice, PCA9554_OUT, 0x00); /* internal AUX */ 205662306a36Sopenharmony_ci return 0; 205762306a36Sopenharmony_ci} 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci/* 206062306a36Sopenharmony_ci * suspend/resume 206162306a36Sopenharmony_ci */ 206262306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 206362306a36Sopenharmony_cistatic int aureon_resume(struct snd_ice1712 *ice) 206462306a36Sopenharmony_ci{ 206562306a36Sopenharmony_ci struct aureon_spec *spec = ice->spec; 206662306a36Sopenharmony_ci int err, i; 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci err = aureon_reset(ice); 206962306a36Sopenharmony_ci if (err != 0) 207062306a36Sopenharmony_ci return err; 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci /* workaround for poking volume with alsamixer after resume: 207362306a36Sopenharmony_ci * just set stored volume again */ 207462306a36Sopenharmony_ci for (i = 0; i < ice->num_total_dacs; i++) 207562306a36Sopenharmony_ci wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]); 207662306a36Sopenharmony_ci return 0; 207762306a36Sopenharmony_ci} 207862306a36Sopenharmony_ci#endif 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci/* 208162306a36Sopenharmony_ci * initialize the chip 208262306a36Sopenharmony_ci */ 208362306a36Sopenharmony_cistatic int aureon_init(struct snd_ice1712 *ice) 208462306a36Sopenharmony_ci{ 208562306a36Sopenharmony_ci struct aureon_spec *spec; 208662306a36Sopenharmony_ci int i, err; 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_ci spec = kzalloc(sizeof(*spec), GFP_KERNEL); 208962306a36Sopenharmony_ci if (!spec) 209062306a36Sopenharmony_ci return -ENOMEM; 209162306a36Sopenharmony_ci ice->spec = spec; 209262306a36Sopenharmony_ci 209362306a36Sopenharmony_ci if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) { 209462306a36Sopenharmony_ci ice->num_total_dacs = 6; 209562306a36Sopenharmony_ci ice->num_total_adcs = 2; 209662306a36Sopenharmony_ci } else { 209762306a36Sopenharmony_ci /* aureon 7.1 and prodigy 7.1 */ 209862306a36Sopenharmony_ci ice->num_total_dacs = 8; 209962306a36Sopenharmony_ci ice->num_total_adcs = 2; 210062306a36Sopenharmony_ci } 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci /* to remember the register values of CS8415 */ 210362306a36Sopenharmony_ci ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); 210462306a36Sopenharmony_ci if (!ice->akm) 210562306a36Sopenharmony_ci return -ENOMEM; 210662306a36Sopenharmony_ci ice->akm_codecs = 1; 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci err = aureon_reset(ice); 210962306a36Sopenharmony_ci if (err != 0) 211062306a36Sopenharmony_ci return err; 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci spec->master[0] = WM_VOL_MUTE; 211362306a36Sopenharmony_ci spec->master[1] = WM_VOL_MUTE; 211462306a36Sopenharmony_ci for (i = 0; i < ice->num_total_dacs; i++) { 211562306a36Sopenharmony_ci spec->vol[i] = WM_VOL_MUTE; 211662306a36Sopenharmony_ci wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]); 211762306a36Sopenharmony_ci } 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 212062306a36Sopenharmony_ci ice->pm_resume = aureon_resume; 212162306a36Sopenharmony_ci ice->pm_suspend_enabled = 1; 212262306a36Sopenharmony_ci#endif 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci return 0; 212562306a36Sopenharmony_ci} 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci/* 212962306a36Sopenharmony_ci * Aureon boards don't provide the EEPROM data except for the vendor IDs. 213062306a36Sopenharmony_ci * hence the driver needs to sets up it properly. 213162306a36Sopenharmony_ci */ 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_cistatic const unsigned char aureon51_eeprom[] = { 213462306a36Sopenharmony_ci [ICE_EEP2_SYSCONF] = 0x0a, /* clock 512, spdif-in/ADC, 3DACs */ 213562306a36Sopenharmony_ci [ICE_EEP2_ACLINK] = 0x80, /* I2S */ 213662306a36Sopenharmony_ci [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ 213762306a36Sopenharmony_ci [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ 213862306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR] = 0xff, 213962306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR1] = 0xff, 214062306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR2] = 0x5f, 214162306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK] = 0x00, 214262306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK1] = 0x00, 214362306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK2] = 0x00, 214462306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE] = 0x00, 214562306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE1] = 0x00, 214662306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE2] = 0x00, 214762306a36Sopenharmony_ci}; 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_cistatic const unsigned char aureon71_eeprom[] = { 215062306a36Sopenharmony_ci [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */ 215162306a36Sopenharmony_ci [ICE_EEP2_ACLINK] = 0x80, /* I2S */ 215262306a36Sopenharmony_ci [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ 215362306a36Sopenharmony_ci [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ 215462306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR] = 0xff, 215562306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR1] = 0xff, 215662306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR2] = 0x5f, 215762306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK] = 0x00, 215862306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK1] = 0x00, 215962306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK2] = 0x00, 216062306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE] = 0x00, 216162306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE1] = 0x00, 216262306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE2] = 0x00, 216362306a36Sopenharmony_ci}; 216462306a36Sopenharmony_ci#define prodigy71_eeprom aureon71_eeprom 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_cistatic const unsigned char aureon71_universe_eeprom[] = { 216762306a36Sopenharmony_ci [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401, spdif-in/ADC, 216862306a36Sopenharmony_ci * 4DACs 216962306a36Sopenharmony_ci */ 217062306a36Sopenharmony_ci [ICE_EEP2_ACLINK] = 0x80, /* I2S */ 217162306a36Sopenharmony_ci [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ 217262306a36Sopenharmony_ci [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ 217362306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR] = 0xff, 217462306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR1] = 0xff, 217562306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR2] = 0x5f, 217662306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK] = 0x00, 217762306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK1] = 0x00, 217862306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK2] = 0x00, 217962306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE] = 0x00, 218062306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE1] = 0x00, 218162306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE2] = 0x00, 218262306a36Sopenharmony_ci}; 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_cistatic const unsigned char prodigy71lt_eeprom[] = { 218562306a36Sopenharmony_ci [ICE_EEP2_SYSCONF] = 0x4b, /* clock 384, spdif-in/ADC, 4DACs */ 218662306a36Sopenharmony_ci [ICE_EEP2_ACLINK] = 0x80, /* I2S */ 218762306a36Sopenharmony_ci [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ 218862306a36Sopenharmony_ci [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ 218962306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR] = 0xff, 219062306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR1] = 0xff, 219162306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR2] = 0x5f, 219262306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK] = 0x00, 219362306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK1] = 0x00, 219462306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK2] = 0x00, 219562306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE] = 0x00, 219662306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE1] = 0x00, 219762306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE2] = 0x00, 219862306a36Sopenharmony_ci}; 219962306a36Sopenharmony_ci#define prodigy71xt_eeprom prodigy71lt_eeprom 220062306a36Sopenharmony_ci 220162306a36Sopenharmony_ci/* entry point */ 220262306a36Sopenharmony_cistruct snd_ice1712_card_info snd_vt1724_aureon_cards[] = { 220362306a36Sopenharmony_ci { 220462306a36Sopenharmony_ci .subvendor = VT1724_SUBDEVICE_AUREON51_SKY, 220562306a36Sopenharmony_ci .name = "Terratec Aureon 5.1-Sky", 220662306a36Sopenharmony_ci .model = "aureon51", 220762306a36Sopenharmony_ci .chip_init = aureon_init, 220862306a36Sopenharmony_ci .build_controls = aureon_add_controls, 220962306a36Sopenharmony_ci .eeprom_size = sizeof(aureon51_eeprom), 221062306a36Sopenharmony_ci .eeprom_data = aureon51_eeprom, 221162306a36Sopenharmony_ci .driver = "Aureon51", 221262306a36Sopenharmony_ci }, 221362306a36Sopenharmony_ci { 221462306a36Sopenharmony_ci .subvendor = VT1724_SUBDEVICE_AUREON71_SPACE, 221562306a36Sopenharmony_ci .name = "Terratec Aureon 7.1-Space", 221662306a36Sopenharmony_ci .model = "aureon71", 221762306a36Sopenharmony_ci .chip_init = aureon_init, 221862306a36Sopenharmony_ci .build_controls = aureon_add_controls, 221962306a36Sopenharmony_ci .eeprom_size = sizeof(aureon71_eeprom), 222062306a36Sopenharmony_ci .eeprom_data = aureon71_eeprom, 222162306a36Sopenharmony_ci .driver = "Aureon71", 222262306a36Sopenharmony_ci }, 222362306a36Sopenharmony_ci { 222462306a36Sopenharmony_ci .subvendor = VT1724_SUBDEVICE_AUREON71_UNIVERSE, 222562306a36Sopenharmony_ci .name = "Terratec Aureon 7.1-Universe", 222662306a36Sopenharmony_ci .model = "universe", 222762306a36Sopenharmony_ci .chip_init = aureon_init, 222862306a36Sopenharmony_ci .build_controls = aureon_add_controls, 222962306a36Sopenharmony_ci .eeprom_size = sizeof(aureon71_universe_eeprom), 223062306a36Sopenharmony_ci .eeprom_data = aureon71_universe_eeprom, 223162306a36Sopenharmony_ci .driver = "Aureon71Univ", /* keep in 15 letters */ 223262306a36Sopenharmony_ci }, 223362306a36Sopenharmony_ci { 223462306a36Sopenharmony_ci .subvendor = VT1724_SUBDEVICE_PRODIGY71, 223562306a36Sopenharmony_ci .name = "Audiotrak Prodigy 7.1", 223662306a36Sopenharmony_ci .model = "prodigy71", 223762306a36Sopenharmony_ci .chip_init = aureon_init, 223862306a36Sopenharmony_ci .build_controls = aureon_add_controls, 223962306a36Sopenharmony_ci .eeprom_size = sizeof(prodigy71_eeprom), 224062306a36Sopenharmony_ci .eeprom_data = prodigy71_eeprom, 224162306a36Sopenharmony_ci .driver = "Prodigy71", /* should be identical with Aureon71 */ 224262306a36Sopenharmony_ci }, 224362306a36Sopenharmony_ci { 224462306a36Sopenharmony_ci .subvendor = VT1724_SUBDEVICE_PRODIGY71LT, 224562306a36Sopenharmony_ci .name = "Audiotrak Prodigy 7.1 LT", 224662306a36Sopenharmony_ci .model = "prodigy71lt", 224762306a36Sopenharmony_ci .chip_init = aureon_init, 224862306a36Sopenharmony_ci .build_controls = aureon_add_controls, 224962306a36Sopenharmony_ci .eeprom_size = sizeof(prodigy71lt_eeprom), 225062306a36Sopenharmony_ci .eeprom_data = prodigy71lt_eeprom, 225162306a36Sopenharmony_ci .driver = "Prodigy71LT", 225262306a36Sopenharmony_ci }, 225362306a36Sopenharmony_ci { 225462306a36Sopenharmony_ci .subvendor = VT1724_SUBDEVICE_PRODIGY71XT, 225562306a36Sopenharmony_ci .name = "Audiotrak Prodigy 7.1 XT", 225662306a36Sopenharmony_ci .model = "prodigy71xt", 225762306a36Sopenharmony_ci .chip_init = aureon_init, 225862306a36Sopenharmony_ci .build_controls = aureon_add_controls, 225962306a36Sopenharmony_ci .eeprom_size = sizeof(prodigy71xt_eeprom), 226062306a36Sopenharmony_ci .eeprom_data = prodigy71xt_eeprom, 226162306a36Sopenharmony_ci .driver = "Prodigy71LT", 226262306a36Sopenharmony_ci }, 226362306a36Sopenharmony_ci { } /* terminator */ 226462306a36Sopenharmony_ci}; 2265