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 ESI Maya44 cards 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (c) 2009 Takashi Iwai <tiwai@suse.de> 862306a36Sopenharmony_ci * Based on the patches by Rainer Zimmermann <mail@lightshed.de> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <sound/core.h> 1462306a36Sopenharmony_ci#include <sound/control.h> 1562306a36Sopenharmony_ci#include <sound/pcm.h> 1662306a36Sopenharmony_ci#include <sound/tlv.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "ice1712.h" 1962306a36Sopenharmony_ci#include "envy24ht.h" 2062306a36Sopenharmony_ci#include "maya44.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* WM8776 register indexes */ 2362306a36Sopenharmony_ci#define WM8776_REG_HEADPHONE_L 0x00 2462306a36Sopenharmony_ci#define WM8776_REG_HEADPHONE_R 0x01 2562306a36Sopenharmony_ci#define WM8776_REG_HEADPHONE_MASTER 0x02 2662306a36Sopenharmony_ci#define WM8776_REG_DAC_ATTEN_L 0x03 2762306a36Sopenharmony_ci#define WM8776_REG_DAC_ATTEN_R 0x04 2862306a36Sopenharmony_ci#define WM8776_REG_DAC_ATTEN_MASTER 0x05 2962306a36Sopenharmony_ci#define WM8776_REG_DAC_PHASE 0x06 3062306a36Sopenharmony_ci#define WM8776_REG_DAC_CONTROL 0x07 3162306a36Sopenharmony_ci#define WM8776_REG_DAC_MUTE 0x08 3262306a36Sopenharmony_ci#define WM8776_REG_DAC_DEEMPH 0x09 3362306a36Sopenharmony_ci#define WM8776_REG_DAC_IF_CONTROL 0x0a 3462306a36Sopenharmony_ci#define WM8776_REG_ADC_IF_CONTROL 0x0b 3562306a36Sopenharmony_ci#define WM8776_REG_MASTER_MODE_CONTROL 0x0c 3662306a36Sopenharmony_ci#define WM8776_REG_POWERDOWN 0x0d 3762306a36Sopenharmony_ci#define WM8776_REG_ADC_ATTEN_L 0x0e 3862306a36Sopenharmony_ci#define WM8776_REG_ADC_ATTEN_R 0x0f 3962306a36Sopenharmony_ci#define WM8776_REG_ADC_ALC1 0x10 4062306a36Sopenharmony_ci#define WM8776_REG_ADC_ALC2 0x11 4162306a36Sopenharmony_ci#define WM8776_REG_ADC_ALC3 0x12 4262306a36Sopenharmony_ci#define WM8776_REG_ADC_NOISE_GATE 0x13 4362306a36Sopenharmony_ci#define WM8776_REG_ADC_LIMITER 0x14 4462306a36Sopenharmony_ci#define WM8776_REG_ADC_MUX 0x15 4562306a36Sopenharmony_ci#define WM8776_REG_OUTPUT_MUX 0x16 4662306a36Sopenharmony_ci#define WM8776_REG_RESET 0x17 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define WM8776_NUM_REGS 0x18 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* clock ratio identifiers for snd_wm8776_set_rate() */ 5162306a36Sopenharmony_ci#define WM8776_CLOCK_RATIO_128FS 0 5262306a36Sopenharmony_ci#define WM8776_CLOCK_RATIO_192FS 1 5362306a36Sopenharmony_ci#define WM8776_CLOCK_RATIO_256FS 2 5462306a36Sopenharmony_ci#define WM8776_CLOCK_RATIO_384FS 3 5562306a36Sopenharmony_ci#define WM8776_CLOCK_RATIO_512FS 4 5662306a36Sopenharmony_ci#define WM8776_CLOCK_RATIO_768FS 5 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cienum { WM_VOL_HP, WM_VOL_DAC, WM_VOL_ADC, WM_NUM_VOLS }; 5962306a36Sopenharmony_cienum { WM_SW_DAC, WM_SW_BYPASS, WM_NUM_SWITCHES }; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistruct snd_wm8776 { 6262306a36Sopenharmony_ci unsigned char addr; 6362306a36Sopenharmony_ci unsigned short regs[WM8776_NUM_REGS]; 6462306a36Sopenharmony_ci unsigned char volumes[WM_NUM_VOLS][2]; 6562306a36Sopenharmony_ci unsigned int switch_bits; 6662306a36Sopenharmony_ci}; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistruct snd_maya44 { 6962306a36Sopenharmony_ci struct snd_ice1712 *ice; 7062306a36Sopenharmony_ci struct snd_wm8776 wm[2]; 7162306a36Sopenharmony_ci struct mutex mutex; 7262306a36Sopenharmony_ci}; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* write the given register and save the data to the cache */ 7662306a36Sopenharmony_cistatic void wm8776_write(struct snd_ice1712 *ice, struct snd_wm8776 *wm, 7762306a36Sopenharmony_ci unsigned char reg, unsigned short val) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci /* 8062306a36Sopenharmony_ci * WM8776 registers are up to 9 bits wide, bit 8 is placed in the LSB 8162306a36Sopenharmony_ci * of the address field 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_ci snd_vt1724_write_i2c(ice, wm->addr, 8462306a36Sopenharmony_ci (reg << 1) | ((val >> 8) & 1), 8562306a36Sopenharmony_ci val & 0xff); 8662306a36Sopenharmony_ci wm->regs[reg] = val; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* 9062306a36Sopenharmony_ci * update the given register with and/or mask and save the data to the cache 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_cistatic int wm8776_write_bits(struct snd_ice1712 *ice, struct snd_wm8776 *wm, 9362306a36Sopenharmony_ci unsigned char reg, 9462306a36Sopenharmony_ci unsigned short mask, unsigned short val) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci val |= wm->regs[reg] & ~mask; 9762306a36Sopenharmony_ci if (val != wm->regs[reg]) { 9862306a36Sopenharmony_ci wm8776_write(ice, wm, reg, val); 9962306a36Sopenharmony_ci return 1; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci return 0; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* 10662306a36Sopenharmony_ci * WM8776 volume controls 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistruct maya_vol_info { 11062306a36Sopenharmony_ci unsigned int maxval; /* volume range: 0..maxval */ 11162306a36Sopenharmony_ci unsigned char regs[2]; /* left and right registers */ 11262306a36Sopenharmony_ci unsigned short mask; /* value mask */ 11362306a36Sopenharmony_ci unsigned short offset; /* zero-value offset */ 11462306a36Sopenharmony_ci unsigned short mute; /* mute bit */ 11562306a36Sopenharmony_ci unsigned short update; /* update bits */ 11662306a36Sopenharmony_ci unsigned char mux_bits[2]; /* extra bits for ADC mute */ 11762306a36Sopenharmony_ci}; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic const struct maya_vol_info vol_info[WM_NUM_VOLS] = { 12062306a36Sopenharmony_ci [WM_VOL_HP] = { 12162306a36Sopenharmony_ci .maxval = 80, 12262306a36Sopenharmony_ci .regs = { WM8776_REG_HEADPHONE_L, WM8776_REG_HEADPHONE_R }, 12362306a36Sopenharmony_ci .mask = 0x7f, 12462306a36Sopenharmony_ci .offset = 0x30, 12562306a36Sopenharmony_ci .mute = 0x00, 12662306a36Sopenharmony_ci .update = 0x180, /* update and zero-cross enable */ 12762306a36Sopenharmony_ci }, 12862306a36Sopenharmony_ci [WM_VOL_DAC] = { 12962306a36Sopenharmony_ci .maxval = 255, 13062306a36Sopenharmony_ci .regs = { WM8776_REG_DAC_ATTEN_L, WM8776_REG_DAC_ATTEN_R }, 13162306a36Sopenharmony_ci .mask = 0xff, 13262306a36Sopenharmony_ci .offset = 0x01, 13362306a36Sopenharmony_ci .mute = 0x00, 13462306a36Sopenharmony_ci .update = 0x100, /* zero-cross enable */ 13562306a36Sopenharmony_ci }, 13662306a36Sopenharmony_ci [WM_VOL_ADC] = { 13762306a36Sopenharmony_ci .maxval = 91, 13862306a36Sopenharmony_ci .regs = { WM8776_REG_ADC_ATTEN_L, WM8776_REG_ADC_ATTEN_R }, 13962306a36Sopenharmony_ci .mask = 0xff, 14062306a36Sopenharmony_ci .offset = 0xa5, 14162306a36Sopenharmony_ci .mute = 0xa5, 14262306a36Sopenharmony_ci .update = 0x100, /* update */ 14362306a36Sopenharmony_ci .mux_bits = { 0x80, 0x40 }, /* ADCMUX bits */ 14462306a36Sopenharmony_ci }, 14562306a36Sopenharmony_ci}; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci/* 14862306a36Sopenharmony_ci * dB tables 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ci/* headphone output: mute, -73..+6db (1db step) */ 15162306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_hp, -7400, 100, 1); 15262306a36Sopenharmony_ci/* DAC output: mute, -127..0db (0.5db step) */ 15362306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_dac, -12750, 50, 1); 15462306a36Sopenharmony_ci/* ADC gain: mute, -21..+24db (0.5db step) */ 15562306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_adc, -2100, 50, 1); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic int maya_vol_info(struct snd_kcontrol *kcontrol, 15862306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci unsigned int idx = kcontrol->private_value; 16162306a36Sopenharmony_ci const struct maya_vol_info *vol = &vol_info[idx]; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 16462306a36Sopenharmony_ci uinfo->count = 2; 16562306a36Sopenharmony_ci uinfo->value.integer.min = 0; 16662306a36Sopenharmony_ci uinfo->value.integer.max = vol->maxval; 16762306a36Sopenharmony_ci return 0; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic int maya_vol_get(struct snd_kcontrol *kcontrol, 17162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); 17462306a36Sopenharmony_ci struct snd_wm8776 *wm = 17562306a36Sopenharmony_ci &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; 17662306a36Sopenharmony_ci unsigned int idx = kcontrol->private_value; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci mutex_lock(&chip->mutex); 17962306a36Sopenharmony_ci ucontrol->value.integer.value[0] = wm->volumes[idx][0]; 18062306a36Sopenharmony_ci ucontrol->value.integer.value[1] = wm->volumes[idx][1]; 18162306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 18262306a36Sopenharmony_ci return 0; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic int maya_vol_put(struct snd_kcontrol *kcontrol, 18662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); 18962306a36Sopenharmony_ci struct snd_wm8776 *wm = 19062306a36Sopenharmony_ci &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; 19162306a36Sopenharmony_ci unsigned int idx = kcontrol->private_value; 19262306a36Sopenharmony_ci const struct maya_vol_info *vol = &vol_info[idx]; 19362306a36Sopenharmony_ci unsigned int val, data; 19462306a36Sopenharmony_ci int ch, changed = 0; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci mutex_lock(&chip->mutex); 19762306a36Sopenharmony_ci for (ch = 0; ch < 2; ch++) { 19862306a36Sopenharmony_ci val = ucontrol->value.integer.value[ch]; 19962306a36Sopenharmony_ci if (val > vol->maxval) 20062306a36Sopenharmony_ci val = vol->maxval; 20162306a36Sopenharmony_ci if (val == wm->volumes[idx][ch]) 20262306a36Sopenharmony_ci continue; 20362306a36Sopenharmony_ci if (!val) 20462306a36Sopenharmony_ci data = vol->mute; 20562306a36Sopenharmony_ci else 20662306a36Sopenharmony_ci data = (val - 1) + vol->offset; 20762306a36Sopenharmony_ci data |= vol->update; 20862306a36Sopenharmony_ci changed |= wm8776_write_bits(chip->ice, wm, vol->regs[ch], 20962306a36Sopenharmony_ci vol->mask | vol->update, data); 21062306a36Sopenharmony_ci if (vol->mux_bits[ch]) 21162306a36Sopenharmony_ci wm8776_write_bits(chip->ice, wm, WM8776_REG_ADC_MUX, 21262306a36Sopenharmony_ci vol->mux_bits[ch], 21362306a36Sopenharmony_ci val ? 0 : vol->mux_bits[ch]); 21462306a36Sopenharmony_ci wm->volumes[idx][ch] = val; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 21762306a36Sopenharmony_ci return changed; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci/* 22162306a36Sopenharmony_ci * WM8776 switch controls 22262306a36Sopenharmony_ci */ 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci#define COMPOSE_SW_VAL(idx, reg, mask) ((idx) | ((reg) << 8) | ((mask) << 16)) 22562306a36Sopenharmony_ci#define GET_SW_VAL_IDX(val) ((val) & 0xff) 22662306a36Sopenharmony_ci#define GET_SW_VAL_REG(val) (((val) >> 8) & 0xff) 22762306a36Sopenharmony_ci#define GET_SW_VAL_MASK(val) (((val) >> 16) & 0xff) 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci#define maya_sw_info snd_ctl_boolean_mono_info 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic int maya_sw_get(struct snd_kcontrol *kcontrol, 23262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); 23562306a36Sopenharmony_ci struct snd_wm8776 *wm = 23662306a36Sopenharmony_ci &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; 23762306a36Sopenharmony_ci unsigned int idx = GET_SW_VAL_IDX(kcontrol->private_value); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci ucontrol->value.integer.value[0] = (wm->switch_bits >> idx) & 1; 24062306a36Sopenharmony_ci return 0; 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic int maya_sw_put(struct snd_kcontrol *kcontrol, 24462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); 24762306a36Sopenharmony_ci struct snd_wm8776 *wm = 24862306a36Sopenharmony_ci &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; 24962306a36Sopenharmony_ci unsigned int idx = GET_SW_VAL_IDX(kcontrol->private_value); 25062306a36Sopenharmony_ci unsigned int mask, val; 25162306a36Sopenharmony_ci int changed; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci mutex_lock(&chip->mutex); 25462306a36Sopenharmony_ci mask = 1 << idx; 25562306a36Sopenharmony_ci wm->switch_bits &= ~mask; 25662306a36Sopenharmony_ci val = ucontrol->value.integer.value[0]; 25762306a36Sopenharmony_ci if (val) 25862306a36Sopenharmony_ci wm->switch_bits |= mask; 25962306a36Sopenharmony_ci mask = GET_SW_VAL_MASK(kcontrol->private_value); 26062306a36Sopenharmony_ci changed = wm8776_write_bits(chip->ice, wm, 26162306a36Sopenharmony_ci GET_SW_VAL_REG(kcontrol->private_value), 26262306a36Sopenharmony_ci mask, val ? mask : 0); 26362306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 26462306a36Sopenharmony_ci return changed; 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci/* 26862306a36Sopenharmony_ci * GPIO pins (known ones for maya44) 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_ci#define GPIO_PHANTOM_OFF 2 27162306a36Sopenharmony_ci#define GPIO_MIC_RELAY 4 27262306a36Sopenharmony_ci#define GPIO_SPDIF_IN_INV 5 27362306a36Sopenharmony_ci#define GPIO_MUST_BE_0 7 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci/* 27662306a36Sopenharmony_ci * GPIO switch controls 27762306a36Sopenharmony_ci */ 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci#define COMPOSE_GPIO_VAL(shift, inv) ((shift) | ((inv) << 8)) 28062306a36Sopenharmony_ci#define GET_GPIO_VAL_SHIFT(val) ((val) & 0xff) 28162306a36Sopenharmony_ci#define GET_GPIO_VAL_INV(val) (((val) >> 8) & 1) 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic int maya_set_gpio_bits(struct snd_ice1712 *ice, unsigned int mask, 28462306a36Sopenharmony_ci unsigned int bits) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci unsigned int data; 28762306a36Sopenharmony_ci data = snd_ice1712_gpio_read(ice); 28862306a36Sopenharmony_ci if ((data & mask) == bits) 28962306a36Sopenharmony_ci return 0; 29062306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, (data & ~mask) | bits); 29162306a36Sopenharmony_ci return 1; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci#define maya_gpio_sw_info snd_ctl_boolean_mono_info 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic int maya_gpio_sw_get(struct snd_kcontrol *kcontrol, 29762306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); 30062306a36Sopenharmony_ci unsigned int shift = GET_GPIO_VAL_SHIFT(kcontrol->private_value); 30162306a36Sopenharmony_ci unsigned int val; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci val = (snd_ice1712_gpio_read(chip->ice) >> shift) & 1; 30462306a36Sopenharmony_ci if (GET_GPIO_VAL_INV(kcontrol->private_value)) 30562306a36Sopenharmony_ci val = !val; 30662306a36Sopenharmony_ci ucontrol->value.integer.value[0] = val; 30762306a36Sopenharmony_ci return 0; 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic int maya_gpio_sw_put(struct snd_kcontrol *kcontrol, 31162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); 31462306a36Sopenharmony_ci unsigned int shift = GET_GPIO_VAL_SHIFT(kcontrol->private_value); 31562306a36Sopenharmony_ci unsigned int val, mask; 31662306a36Sopenharmony_ci int changed; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci mutex_lock(&chip->mutex); 31962306a36Sopenharmony_ci mask = 1 << shift; 32062306a36Sopenharmony_ci val = ucontrol->value.integer.value[0]; 32162306a36Sopenharmony_ci if (GET_GPIO_VAL_INV(kcontrol->private_value)) 32262306a36Sopenharmony_ci val = !val; 32362306a36Sopenharmony_ci val = val ? mask : 0; 32462306a36Sopenharmony_ci changed = maya_set_gpio_bits(chip->ice, mask, val); 32562306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 32662306a36Sopenharmony_ci return changed; 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci/* 33062306a36Sopenharmony_ci * capture source selection 33162306a36Sopenharmony_ci */ 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci/* known working input slots (0-4) */ 33462306a36Sopenharmony_ci#define MAYA_LINE_IN 1 /* in-2 */ 33562306a36Sopenharmony_ci#define MAYA_MIC_IN 3 /* in-4 */ 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic void wm8776_select_input(struct snd_maya44 *chip, int idx, int line) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci wm8776_write_bits(chip->ice, &chip->wm[idx], WM8776_REG_ADC_MUX, 34062306a36Sopenharmony_ci 0x1f, 1 << line); 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic int maya_rec_src_info(struct snd_kcontrol *kcontrol, 34462306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci static const char * const texts[] = { "Line", "Mic" }; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic int maya_rec_src_get(struct snd_kcontrol *kcontrol, 35262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); 35562306a36Sopenharmony_ci int sel; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci if (snd_ice1712_gpio_read(chip->ice) & (1 << GPIO_MIC_RELAY)) 35862306a36Sopenharmony_ci sel = 1; 35962306a36Sopenharmony_ci else 36062306a36Sopenharmony_ci sel = 0; 36162306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = sel; 36262306a36Sopenharmony_ci return 0; 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic int maya_rec_src_put(struct snd_kcontrol *kcontrol, 36662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); 36962306a36Sopenharmony_ci int sel = ucontrol->value.enumerated.item[0]; 37062306a36Sopenharmony_ci int changed; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci mutex_lock(&chip->mutex); 37362306a36Sopenharmony_ci changed = maya_set_gpio_bits(chip->ice, 1 << GPIO_MIC_RELAY, 37462306a36Sopenharmony_ci sel ? (1 << GPIO_MIC_RELAY) : 0); 37562306a36Sopenharmony_ci wm8776_select_input(chip, 0, sel ? MAYA_MIC_IN : MAYA_LINE_IN); 37662306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 37762306a36Sopenharmony_ci return changed; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci/* 38162306a36Sopenharmony_ci * Maya44 routing switch settings have different meanings than the standard 38262306a36Sopenharmony_ci * ice1724 switches as defined in snd_vt1724_pro_route_info (ice1724.c). 38362306a36Sopenharmony_ci */ 38462306a36Sopenharmony_cistatic int maya_pb_route_info(struct snd_kcontrol *kcontrol, 38562306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci static const char * const texts[] = { 38862306a36Sopenharmony_ci "PCM Out", /* 0 */ 38962306a36Sopenharmony_ci "Input 1", "Input 2", "Input 3", "Input 4" 39062306a36Sopenharmony_ci }; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic int maya_pb_route_shift(int idx) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci static const unsigned char shift[10] = 39862306a36Sopenharmony_ci { 8, 20, 0, 3, 11, 23, 14, 26, 17, 29 }; 39962306a36Sopenharmony_ci return shift[idx % 10]; 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic int maya_pb_route_get(struct snd_kcontrol *kcontrol, 40362306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); 40662306a36Sopenharmony_ci int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 40762306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = 40862306a36Sopenharmony_ci snd_ice1724_get_route_val(chip->ice, maya_pb_route_shift(idx)); 40962306a36Sopenharmony_ci return 0; 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic int maya_pb_route_put(struct snd_kcontrol *kcontrol, 41362306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); 41662306a36Sopenharmony_ci int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 41762306a36Sopenharmony_ci return snd_ice1724_put_route_val(chip->ice, 41862306a36Sopenharmony_ci ucontrol->value.enumerated.item[0], 41962306a36Sopenharmony_ci maya_pb_route_shift(idx)); 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci/* 42462306a36Sopenharmony_ci * controls to be added 42562306a36Sopenharmony_ci */ 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cistatic const struct snd_kcontrol_new maya_controls[] = { 42862306a36Sopenharmony_ci { 42962306a36Sopenharmony_ci .name = "Crossmix Playback Volume", 43062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 43162306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 43262306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ, 43362306a36Sopenharmony_ci .info = maya_vol_info, 43462306a36Sopenharmony_ci .get = maya_vol_get, 43562306a36Sopenharmony_ci .put = maya_vol_put, 43662306a36Sopenharmony_ci .tlv = { .p = db_scale_hp }, 43762306a36Sopenharmony_ci .private_value = WM_VOL_HP, 43862306a36Sopenharmony_ci .count = 2, 43962306a36Sopenharmony_ci }, 44062306a36Sopenharmony_ci { 44162306a36Sopenharmony_ci .name = "PCM Playback Volume", 44262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 44362306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 44462306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ, 44562306a36Sopenharmony_ci .info = maya_vol_info, 44662306a36Sopenharmony_ci .get = maya_vol_get, 44762306a36Sopenharmony_ci .put = maya_vol_put, 44862306a36Sopenharmony_ci .tlv = { .p = db_scale_dac }, 44962306a36Sopenharmony_ci .private_value = WM_VOL_DAC, 45062306a36Sopenharmony_ci .count = 2, 45162306a36Sopenharmony_ci }, 45262306a36Sopenharmony_ci { 45362306a36Sopenharmony_ci .name = "Line Capture Volume", 45462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 45562306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 45662306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ, 45762306a36Sopenharmony_ci .info = maya_vol_info, 45862306a36Sopenharmony_ci .get = maya_vol_get, 45962306a36Sopenharmony_ci .put = maya_vol_put, 46062306a36Sopenharmony_ci .tlv = { .p = db_scale_adc }, 46162306a36Sopenharmony_ci .private_value = WM_VOL_ADC, 46262306a36Sopenharmony_ci .count = 2, 46362306a36Sopenharmony_ci }, 46462306a36Sopenharmony_ci { 46562306a36Sopenharmony_ci .name = "PCM Playback Switch", 46662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 46762306a36Sopenharmony_ci .info = maya_sw_info, 46862306a36Sopenharmony_ci .get = maya_sw_get, 46962306a36Sopenharmony_ci .put = maya_sw_put, 47062306a36Sopenharmony_ci .private_value = COMPOSE_SW_VAL(WM_SW_DAC, 47162306a36Sopenharmony_ci WM8776_REG_OUTPUT_MUX, 0x01), 47262306a36Sopenharmony_ci .count = 2, 47362306a36Sopenharmony_ci }, 47462306a36Sopenharmony_ci { 47562306a36Sopenharmony_ci .name = "Bypass Playback Switch", 47662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 47762306a36Sopenharmony_ci .info = maya_sw_info, 47862306a36Sopenharmony_ci .get = maya_sw_get, 47962306a36Sopenharmony_ci .put = maya_sw_put, 48062306a36Sopenharmony_ci .private_value = COMPOSE_SW_VAL(WM_SW_BYPASS, 48162306a36Sopenharmony_ci WM8776_REG_OUTPUT_MUX, 0x04), 48262306a36Sopenharmony_ci .count = 2, 48362306a36Sopenharmony_ci }, 48462306a36Sopenharmony_ci { 48562306a36Sopenharmony_ci .name = "Capture Source", 48662306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 48762306a36Sopenharmony_ci .info = maya_rec_src_info, 48862306a36Sopenharmony_ci .get = maya_rec_src_get, 48962306a36Sopenharmony_ci .put = maya_rec_src_put, 49062306a36Sopenharmony_ci }, 49162306a36Sopenharmony_ci { 49262306a36Sopenharmony_ci .name = "Mic Phantom Power Switch", 49362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 49462306a36Sopenharmony_ci .info = maya_gpio_sw_info, 49562306a36Sopenharmony_ci .get = maya_gpio_sw_get, 49662306a36Sopenharmony_ci .put = maya_gpio_sw_put, 49762306a36Sopenharmony_ci .private_value = COMPOSE_GPIO_VAL(GPIO_PHANTOM_OFF, 1), 49862306a36Sopenharmony_ci }, 49962306a36Sopenharmony_ci { 50062306a36Sopenharmony_ci .name = "SPDIF Capture Switch", 50162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 50262306a36Sopenharmony_ci .info = maya_gpio_sw_info, 50362306a36Sopenharmony_ci .get = maya_gpio_sw_get, 50462306a36Sopenharmony_ci .put = maya_gpio_sw_put, 50562306a36Sopenharmony_ci .private_value = COMPOSE_GPIO_VAL(GPIO_SPDIF_IN_INV, 1), 50662306a36Sopenharmony_ci }, 50762306a36Sopenharmony_ci { 50862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 50962306a36Sopenharmony_ci .name = "H/W Playback Route", 51062306a36Sopenharmony_ci .info = maya_pb_route_info, 51162306a36Sopenharmony_ci .get = maya_pb_route_get, 51262306a36Sopenharmony_ci .put = maya_pb_route_put, 51362306a36Sopenharmony_ci .count = 4, /* FIXME: do controls 5-9 have any meaning? */ 51462306a36Sopenharmony_ci }, 51562306a36Sopenharmony_ci}; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic int maya44_add_controls(struct snd_ice1712 *ice) 51862306a36Sopenharmony_ci{ 51962306a36Sopenharmony_ci int err, i; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(maya_controls); i++) { 52262306a36Sopenharmony_ci err = snd_ctl_add(ice->card, snd_ctl_new1(&maya_controls[i], 52362306a36Sopenharmony_ci ice->spec)); 52462306a36Sopenharmony_ci if (err < 0) 52562306a36Sopenharmony_ci return err; 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci return 0; 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci/* 53262306a36Sopenharmony_ci * initialize a wm8776 chip 53362306a36Sopenharmony_ci */ 53462306a36Sopenharmony_cistatic void wm8776_init(struct snd_ice1712 *ice, 53562306a36Sopenharmony_ci struct snd_wm8776 *wm, unsigned int addr) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci static const unsigned short inits_wm8776[] = { 53862306a36Sopenharmony_ci 0x02, 0x100, /* R2: headphone L+R muted + update */ 53962306a36Sopenharmony_ci 0x05, 0x100, /* R5: DAC output L+R muted + update */ 54062306a36Sopenharmony_ci 0x06, 0x000, /* R6: DAC output phase normal */ 54162306a36Sopenharmony_ci 0x07, 0x091, /* R7: DAC enable zero cross detection, 54262306a36Sopenharmony_ci normal output */ 54362306a36Sopenharmony_ci 0x08, 0x000, /* R8: DAC soft mute off */ 54462306a36Sopenharmony_ci 0x09, 0x000, /* R9: no deemph, DAC zero detect disabled */ 54562306a36Sopenharmony_ci 0x0a, 0x022, /* R10: DAC I2C mode, std polarities, 24bit */ 54662306a36Sopenharmony_ci 0x0b, 0x022, /* R11: ADC I2C mode, std polarities, 24bit, 54762306a36Sopenharmony_ci highpass filter enabled */ 54862306a36Sopenharmony_ci 0x0c, 0x042, /* R12: ADC+DAC slave, ADC+DAC 44,1kHz */ 54962306a36Sopenharmony_ci 0x0d, 0x000, /* R13: all power up */ 55062306a36Sopenharmony_ci 0x0e, 0x100, /* R14: ADC left muted, 55162306a36Sopenharmony_ci enable zero cross detection */ 55262306a36Sopenharmony_ci 0x0f, 0x100, /* R15: ADC right muted, 55362306a36Sopenharmony_ci enable zero cross detection */ 55462306a36Sopenharmony_ci /* R16: ALC...*/ 55562306a36Sopenharmony_ci 0x11, 0x000, /* R17: disable ALC */ 55662306a36Sopenharmony_ci /* R18: ALC...*/ 55762306a36Sopenharmony_ci /* R19: noise gate...*/ 55862306a36Sopenharmony_ci 0x15, 0x000, /* R21: ADC input mux init, mute all inputs */ 55962306a36Sopenharmony_ci 0x16, 0x001, /* R22: output mux, select DAC */ 56062306a36Sopenharmony_ci 0xff, 0xff 56162306a36Sopenharmony_ci }; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci const unsigned short *ptr; 56462306a36Sopenharmony_ci unsigned char reg; 56562306a36Sopenharmony_ci unsigned short data; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci wm->addr = addr; 56862306a36Sopenharmony_ci /* enable DAC output; mute bypass, aux & all inputs */ 56962306a36Sopenharmony_ci wm->switch_bits = (1 << WM_SW_DAC); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci ptr = inits_wm8776; 57262306a36Sopenharmony_ci while (*ptr != 0xff) { 57362306a36Sopenharmony_ci reg = *ptr++; 57462306a36Sopenharmony_ci data = *ptr++; 57562306a36Sopenharmony_ci wm8776_write(ice, wm, reg, data); 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci/* 58162306a36Sopenharmony_ci * change the rate on the WM8776 codecs. 58262306a36Sopenharmony_ci * this assumes that the VT17xx's rate is changed by the calling function. 58362306a36Sopenharmony_ci * NOTE: even though the WM8776's are running in slave mode and rate 58462306a36Sopenharmony_ci * selection is automatic, we need to call snd_wm8776_set_rate() here 58562306a36Sopenharmony_ci * to make sure some flags are set correctly. 58662306a36Sopenharmony_ci */ 58762306a36Sopenharmony_cistatic void set_rate(struct snd_ice1712 *ice, unsigned int rate) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci struct snd_maya44 *chip = ice->spec; 59062306a36Sopenharmony_ci unsigned int ratio, adc_ratio, val; 59162306a36Sopenharmony_ci int i; 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci switch (rate) { 59462306a36Sopenharmony_ci case 192000: 59562306a36Sopenharmony_ci ratio = WM8776_CLOCK_RATIO_128FS; 59662306a36Sopenharmony_ci break; 59762306a36Sopenharmony_ci case 176400: 59862306a36Sopenharmony_ci ratio = WM8776_CLOCK_RATIO_128FS; 59962306a36Sopenharmony_ci break; 60062306a36Sopenharmony_ci case 96000: 60162306a36Sopenharmony_ci ratio = WM8776_CLOCK_RATIO_256FS; 60262306a36Sopenharmony_ci break; 60362306a36Sopenharmony_ci case 88200: 60462306a36Sopenharmony_ci ratio = WM8776_CLOCK_RATIO_384FS; 60562306a36Sopenharmony_ci break; 60662306a36Sopenharmony_ci case 48000: 60762306a36Sopenharmony_ci ratio = WM8776_CLOCK_RATIO_512FS; 60862306a36Sopenharmony_ci break; 60962306a36Sopenharmony_ci case 44100: 61062306a36Sopenharmony_ci ratio = WM8776_CLOCK_RATIO_512FS; 61162306a36Sopenharmony_ci break; 61262306a36Sopenharmony_ci case 32000: 61362306a36Sopenharmony_ci ratio = WM8776_CLOCK_RATIO_768FS; 61462306a36Sopenharmony_ci break; 61562306a36Sopenharmony_ci case 0: 61662306a36Sopenharmony_ci /* no hint - S/PDIF input is master, simply return */ 61762306a36Sopenharmony_ci return; 61862306a36Sopenharmony_ci default: 61962306a36Sopenharmony_ci snd_BUG(); 62062306a36Sopenharmony_ci return; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci /* 62462306a36Sopenharmony_ci * this currently sets the same rate for ADC and DAC, but limits 62562306a36Sopenharmony_ci * ADC rate to 256X (96kHz). For 256X mode (96kHz), this sets ADC 62662306a36Sopenharmony_ci * oversampling to 64x, as recommended by WM8776 datasheet. 62762306a36Sopenharmony_ci * Setting the rate is not really necessary in slave mode. 62862306a36Sopenharmony_ci */ 62962306a36Sopenharmony_ci adc_ratio = ratio; 63062306a36Sopenharmony_ci if (adc_ratio < WM8776_CLOCK_RATIO_256FS) 63162306a36Sopenharmony_ci adc_ratio = WM8776_CLOCK_RATIO_256FS; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci val = adc_ratio; 63462306a36Sopenharmony_ci if (adc_ratio == WM8776_CLOCK_RATIO_256FS) 63562306a36Sopenharmony_ci val |= 8; 63662306a36Sopenharmony_ci val |= ratio << 4; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci mutex_lock(&chip->mutex); 63962306a36Sopenharmony_ci for (i = 0; i < 2; i++) 64062306a36Sopenharmony_ci wm8776_write_bits(ice, &chip->wm[i], 64162306a36Sopenharmony_ci WM8776_REG_MASTER_MODE_CONTROL, 64262306a36Sopenharmony_ci 0x180, val); 64362306a36Sopenharmony_ci mutex_unlock(&chip->mutex); 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci/* 64762306a36Sopenharmony_ci * supported sample rates (to override the default one) 64862306a36Sopenharmony_ci */ 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cistatic const unsigned int rates[] = { 65162306a36Sopenharmony_ci 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000 65262306a36Sopenharmony_ci}; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci/* playback rates: 32..192 kHz */ 65562306a36Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list dac_rates = { 65662306a36Sopenharmony_ci .count = ARRAY_SIZE(rates), 65762306a36Sopenharmony_ci .list = rates, 65862306a36Sopenharmony_ci .mask = 0 65962306a36Sopenharmony_ci}; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci/* 66362306a36Sopenharmony_ci * chip addresses on I2C bus 66462306a36Sopenharmony_ci */ 66562306a36Sopenharmony_cistatic const unsigned char wm8776_addr[2] = { 66662306a36Sopenharmony_ci 0x34, 0x36, /* codec 0 & 1 */ 66762306a36Sopenharmony_ci}; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci/* 67062306a36Sopenharmony_ci * initialize the chip 67162306a36Sopenharmony_ci */ 67262306a36Sopenharmony_cistatic int maya44_init(struct snd_ice1712 *ice) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci int i; 67562306a36Sopenharmony_ci struct snd_maya44 *chip; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci chip = kzalloc(sizeof(*chip), GFP_KERNEL); 67862306a36Sopenharmony_ci if (!chip) 67962306a36Sopenharmony_ci return -ENOMEM; 68062306a36Sopenharmony_ci mutex_init(&chip->mutex); 68162306a36Sopenharmony_ci chip->ice = ice; 68262306a36Sopenharmony_ci ice->spec = chip; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci /* initialise codecs */ 68562306a36Sopenharmony_ci ice->num_total_dacs = 4; 68662306a36Sopenharmony_ci ice->num_total_adcs = 4; 68762306a36Sopenharmony_ci ice->akm_codecs = 0; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 69062306a36Sopenharmony_ci wm8776_init(ice, &chip->wm[i], wm8776_addr[i]); 69162306a36Sopenharmony_ci wm8776_select_input(chip, i, MAYA_LINE_IN); 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci /* set card specific rates */ 69562306a36Sopenharmony_ci ice->hw_rates = &dac_rates; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci /* register change rate notifier */ 69862306a36Sopenharmony_ci ice->gpio.set_pro_rate = set_rate; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci /* RDMA1 (2nd input channel) is used for ADC by default */ 70162306a36Sopenharmony_ci ice->force_rdma1 = 1; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci /* have an own routing control */ 70462306a36Sopenharmony_ci ice->own_routing = 1; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci return 0; 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci/* 71162306a36Sopenharmony_ci * Maya44 boards don't provide the EEPROM data except for the vendor IDs. 71262306a36Sopenharmony_ci * hence the driver needs to sets up it properly. 71362306a36Sopenharmony_ci */ 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic const unsigned char maya44_eeprom[] = { 71662306a36Sopenharmony_ci [ICE_EEP2_SYSCONF] = 0x45, 71762306a36Sopenharmony_ci /* clock xin1=49.152MHz, mpu401, 2 stereo ADCs+DACs */ 71862306a36Sopenharmony_ci [ICE_EEP2_ACLINK] = 0x80, 71962306a36Sopenharmony_ci /* I2S */ 72062306a36Sopenharmony_ci [ICE_EEP2_I2S] = 0xf8, 72162306a36Sopenharmony_ci /* vol, 96k, 24bit, 192k */ 72262306a36Sopenharmony_ci [ICE_EEP2_SPDIF] = 0xc3, 72362306a36Sopenharmony_ci /* enable spdif out, spdif out supp, spdif-in, ext spdif out */ 72462306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR] = 0xff, 72562306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR1] = 0xff, 72662306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR2] = 0xff, 72762306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK] = 0/*0x9f*/, 72862306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK1] = 0/*0xff*/, 72962306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK2] = 0/*0x7f*/, 73062306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE] = (1 << GPIO_PHANTOM_OFF) | 73162306a36Sopenharmony_ci (1 << GPIO_SPDIF_IN_INV), 73262306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE1] = 0x00, 73362306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE2] = 0x00, 73462306a36Sopenharmony_ci}; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci/* entry point */ 73762306a36Sopenharmony_cistruct snd_ice1712_card_info snd_vt1724_maya44_cards[] = { 73862306a36Sopenharmony_ci { 73962306a36Sopenharmony_ci .subvendor = VT1724_SUBDEVICE_MAYA44, 74062306a36Sopenharmony_ci .name = "ESI Maya44", 74162306a36Sopenharmony_ci .model = "maya44", 74262306a36Sopenharmony_ci .chip_init = maya44_init, 74362306a36Sopenharmony_ci .build_controls = maya44_add_controls, 74462306a36Sopenharmony_ci .eeprom_size = sizeof(maya44_eeprom), 74562306a36Sopenharmony_ci .eeprom_data = maya44_eeprom, 74662306a36Sopenharmony_ci }, 74762306a36Sopenharmony_ci { } /* terminator */ 74862306a36Sopenharmony_ci}; 749