162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * ALSA driver for ICEnsemble VT1724 (Envy24HT) 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Lowlevel functions for AudioTrak Prodigy 192 cards 662306a36Sopenharmony_ci * Supported IEC958 input from optional MI/ODI/O add-on card. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Specifics (SW, HW): 962306a36Sopenharmony_ci * ------------------- 1062306a36Sopenharmony_ci * * 49.5MHz crystal 1162306a36Sopenharmony_ci * * SPDIF-OUT on the card: 1262306a36Sopenharmony_ci * - coax (through isolation transformer)/toslink supplied by 1362306a36Sopenharmony_ci * 74HC04 gates - 3 in parallel 1462306a36Sopenharmony_ci * - output switched between on-board CD drive dig-out connector 1562306a36Sopenharmony_ci * and ice1724 SPDTX pin, using 74HC02 NOR gates, controlled 1662306a36Sopenharmony_ci * by GPIO20 (0 = CD dig-out, 1 = SPDTX) 1762306a36Sopenharmony_ci * * SPDTX goes straight to MI/ODI/O card's SPDIF-OUT coax 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * * MI/ODI/O card: AK4114 based, used for iec958 input only 2062306a36Sopenharmony_ci * - toslink input -> RX0 2162306a36Sopenharmony_ci * - coax input -> RX1 2262306a36Sopenharmony_ci * - 4wire protocol: 2362306a36Sopenharmony_ci * AK4114 ICE1724 2462306a36Sopenharmony_ci * ------------------------------ 2562306a36Sopenharmony_ci * CDTO (pin 32) -- GPIO11 pin 86 2662306a36Sopenharmony_ci * CDTI (pin 33) -- GPIO10 pin 77 2762306a36Sopenharmony_ci * CCLK (pin 34) -- GPIO9 pin 76 2862306a36Sopenharmony_ci * CSN (pin 35) -- GPIO8 pin 75 2962306a36Sopenharmony_ci * - output data Mode 7 (24bit, I2S, slave) 3062306a36Sopenharmony_ci * - both MCKO1 and MCKO2 of ak4114 are fed to FPGA, which 3162306a36Sopenharmony_ci * outputs master clock to SPMCLKIN of ice1724. 3262306a36Sopenharmony_ci * Experimentally I found out that only a combination of 3362306a36Sopenharmony_ci * OCKS0=1, OCKS1=1 (128fs, 64fs output) and ice1724 - 3462306a36Sopenharmony_ci * VT1724_MT_I2S_MCLK_128X=0 (256fs input) yields correct 3562306a36Sopenharmony_ci * sampling rate. That means that the FPGA doubles the 3662306a36Sopenharmony_ci * MCK01 rate. 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * Copyright (c) 2003 Takashi Iwai <tiwai@suse.de> 3962306a36Sopenharmony_ci * Copyright (c) 2003 Dimitromanolakis Apostolos <apostol@cs.utoronto.ca> 4062306a36Sopenharmony_ci * Copyright (c) 2004 Kouichi ONO <co2b@ceres.dti.ne.jp> 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#include <linux/delay.h> 4462306a36Sopenharmony_ci#include <linux/interrupt.h> 4562306a36Sopenharmony_ci#include <linux/init.h> 4662306a36Sopenharmony_ci#include <linux/slab.h> 4762306a36Sopenharmony_ci#include <sound/core.h> 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#include "ice1712.h" 5062306a36Sopenharmony_ci#include "envy24ht.h" 5162306a36Sopenharmony_ci#include "prodigy192.h" 5262306a36Sopenharmony_ci#include "stac946x.h" 5362306a36Sopenharmony_ci#include <sound/tlv.h> 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistruct prodigy192_spec { 5662306a36Sopenharmony_ci struct ak4114 *ak4114; 5762306a36Sopenharmony_ci /* rate change needs atomic mute/unmute of all dacs*/ 5862306a36Sopenharmony_ci struct mutex mute_mutex; 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic inline void stac9460_put(struct snd_ice1712 *ice, int reg, unsigned char val) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci snd_vt1724_write_i2c(ice, PRODIGY192_STAC9460_ADDR, reg, val); 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci return snd_vt1724_read_i2c(ice, PRODIGY192_STAC9460_ADDR, reg); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* 7262306a36Sopenharmony_ci * DAC mute control 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* 7662306a36Sopenharmony_ci * idx = STAC9460 volume register number, mute: 0 = mute, 1 = unmute 7762306a36Sopenharmony_ci */ 7862306a36Sopenharmony_cistatic int stac9460_dac_mute(struct snd_ice1712 *ice, int idx, 7962306a36Sopenharmony_ci unsigned char mute) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci unsigned char new, old; 8262306a36Sopenharmony_ci int change; 8362306a36Sopenharmony_ci old = stac9460_get(ice, idx); 8462306a36Sopenharmony_ci new = (~mute << 7 & 0x80) | (old & ~0x80); 8562306a36Sopenharmony_ci change = (new != old); 8662306a36Sopenharmony_ci if (change) 8762306a36Sopenharmony_ci /* dev_dbg(ice->card->dev, "Volume register 0x%02x: 0x%02x\n", idx, new);*/ 8862306a36Sopenharmony_ci stac9460_put(ice, idx, new); 8962306a36Sopenharmony_ci return change; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci#define stac9460_dac_mute_info snd_ctl_boolean_mono_info 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 9762306a36Sopenharmony_ci unsigned char val; 9862306a36Sopenharmony_ci int idx; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (kcontrol->private_value) 10162306a36Sopenharmony_ci idx = STAC946X_MASTER_VOLUME; 10262306a36Sopenharmony_ci else 10362306a36Sopenharmony_ci idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; 10462306a36Sopenharmony_ci val = stac9460_get(ice, idx); 10562306a36Sopenharmony_ci ucontrol->value.integer.value[0] = (~val >> 7) & 0x1; 10662306a36Sopenharmony_ci return 0; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 11262306a36Sopenharmony_ci struct prodigy192_spec *spec = ice->spec; 11362306a36Sopenharmony_ci int idx, change; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci if (kcontrol->private_value) 11662306a36Sopenharmony_ci idx = STAC946X_MASTER_VOLUME; 11762306a36Sopenharmony_ci else 11862306a36Sopenharmony_ci idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; 11962306a36Sopenharmony_ci /* due to possible conflicts with stac9460_set_rate_val, mutexing */ 12062306a36Sopenharmony_ci mutex_lock(&spec->mute_mutex); 12162306a36Sopenharmony_ci /* 12262306a36Sopenharmony_ci dev_dbg(ice->card->dev, "Mute put: reg 0x%02x, ctrl value: 0x%02x\n", idx, 12362306a36Sopenharmony_ci ucontrol->value.integer.value[0]); 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_ci change = stac9460_dac_mute(ice, idx, ucontrol->value.integer.value[0]); 12662306a36Sopenharmony_ci mutex_unlock(&spec->mute_mutex); 12762306a36Sopenharmony_ci return change; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci/* 13162306a36Sopenharmony_ci * DAC volume attenuation mixer control 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_cistatic int stac9460_dac_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 13662306a36Sopenharmony_ci uinfo->count = 1; 13762306a36Sopenharmony_ci uinfo->value.integer.min = 0; /* mute */ 13862306a36Sopenharmony_ci uinfo->value.integer.max = 0x7f; /* 0dB */ 13962306a36Sopenharmony_ci return 0; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic int stac9460_dac_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 14562306a36Sopenharmony_ci int idx; 14662306a36Sopenharmony_ci unsigned char vol; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (kcontrol->private_value) 14962306a36Sopenharmony_ci idx = STAC946X_MASTER_VOLUME; 15062306a36Sopenharmony_ci else 15162306a36Sopenharmony_ci idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; 15262306a36Sopenharmony_ci vol = stac9460_get(ice, idx) & 0x7f; 15362306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 0x7f - vol; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return 0; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 16162306a36Sopenharmony_ci int idx; 16262306a36Sopenharmony_ci unsigned char tmp, ovol, nvol; 16362306a36Sopenharmony_ci int change; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci if (kcontrol->private_value) 16662306a36Sopenharmony_ci idx = STAC946X_MASTER_VOLUME; 16762306a36Sopenharmony_ci else 16862306a36Sopenharmony_ci idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; 16962306a36Sopenharmony_ci nvol = ucontrol->value.integer.value[0]; 17062306a36Sopenharmony_ci tmp = stac9460_get(ice, idx); 17162306a36Sopenharmony_ci ovol = 0x7f - (tmp & 0x7f); 17262306a36Sopenharmony_ci change = (ovol != nvol); 17362306a36Sopenharmony_ci if (change) { 17462306a36Sopenharmony_ci ovol = (0x7f - nvol) | (tmp & 0x80); 17562306a36Sopenharmony_ci /* 17662306a36Sopenharmony_ci dev_dbg(ice->card->dev, "DAC Volume: reg 0x%02x: 0x%02x\n", 17762306a36Sopenharmony_ci idx, ovol); 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_ci stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci return change; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci/* 18562306a36Sopenharmony_ci * ADC mute control 18662306a36Sopenharmony_ci */ 18762306a36Sopenharmony_ci#define stac9460_adc_mute_info snd_ctl_boolean_stereo_info 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 19262306a36Sopenharmony_ci unsigned char val; 19362306a36Sopenharmony_ci int i; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci for (i = 0; i < 2; ++i) { 19662306a36Sopenharmony_ci val = stac9460_get(ice, STAC946X_MIC_L_VOLUME + i); 19762306a36Sopenharmony_ci ucontrol->value.integer.value[i] = ~val>>7 & 0x1; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci return 0; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 20662306a36Sopenharmony_ci unsigned char new, old; 20762306a36Sopenharmony_ci int i, reg; 20862306a36Sopenharmony_ci int change; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci for (i = 0; i < 2; ++i) { 21162306a36Sopenharmony_ci reg = STAC946X_MIC_L_VOLUME + i; 21262306a36Sopenharmony_ci old = stac9460_get(ice, reg); 21362306a36Sopenharmony_ci new = (~ucontrol->value.integer.value[i]<<7&0x80) | (old&~0x80); 21462306a36Sopenharmony_ci change = (new != old); 21562306a36Sopenharmony_ci if (change) 21662306a36Sopenharmony_ci stac9460_put(ice, reg, new); 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci return change; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci/* 22362306a36Sopenharmony_ci * ADC gain mixer control 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_cistatic int stac9460_adc_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 22862306a36Sopenharmony_ci uinfo->count = 2; 22962306a36Sopenharmony_ci uinfo->value.integer.min = 0; /* 0dB */ 23062306a36Sopenharmony_ci uinfo->value.integer.max = 0x0f; /* 22.5dB */ 23162306a36Sopenharmony_ci return 0; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic int stac9460_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 23762306a36Sopenharmony_ci int i, reg; 23862306a36Sopenharmony_ci unsigned char vol; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci for (i = 0; i < 2; ++i) { 24162306a36Sopenharmony_ci reg = STAC946X_MIC_L_VOLUME + i; 24262306a36Sopenharmony_ci vol = stac9460_get(ice, reg) & 0x0f; 24362306a36Sopenharmony_ci ucontrol->value.integer.value[i] = 0x0f - vol; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci return 0; 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 25262306a36Sopenharmony_ci int i, reg; 25362306a36Sopenharmony_ci unsigned char ovol, nvol; 25462306a36Sopenharmony_ci int change; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci for (i = 0; i < 2; ++i) { 25762306a36Sopenharmony_ci reg = STAC946X_MIC_L_VOLUME + i; 25862306a36Sopenharmony_ci nvol = ucontrol->value.integer.value[i] & 0x0f; 25962306a36Sopenharmony_ci ovol = 0x0f - stac9460_get(ice, reg); 26062306a36Sopenharmony_ci change = ((ovol & 0x0f) != nvol); 26162306a36Sopenharmony_ci if (change) 26262306a36Sopenharmony_ci stac9460_put(ice, reg, (0x0f - nvol) | (ovol & ~0x0f)); 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return change; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol, 26962306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci static const char * const texts[2] = { "Line In", "Mic" }; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, texts); 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol, 27862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 28162306a36Sopenharmony_ci unsigned char val; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); 28462306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = (val >> 7) & 0x1; 28562306a36Sopenharmony_ci return 0; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol, 28962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 29262306a36Sopenharmony_ci unsigned char new, old; 29362306a36Sopenharmony_ci int change; 29462306a36Sopenharmony_ci old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); 29562306a36Sopenharmony_ci new = (ucontrol->value.enumerated.item[0] << 7 & 0x80) | (old & ~0x80); 29662306a36Sopenharmony_ci change = (new != old); 29762306a36Sopenharmony_ci if (change) 29862306a36Sopenharmony_ci stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new); 29962306a36Sopenharmony_ci return change; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci/* 30262306a36Sopenharmony_ci * Handler for setting correct codec rate - called when rate change is detected 30362306a36Sopenharmony_ci */ 30462306a36Sopenharmony_cistatic void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci unsigned char old, new; 30762306a36Sopenharmony_ci int idx; 30862306a36Sopenharmony_ci unsigned char changed[7]; 30962306a36Sopenharmony_ci struct prodigy192_spec *spec = ice->spec; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (rate == 0) /* no hint - S/PDIF input is master, simply return */ 31262306a36Sopenharmony_ci return; 31362306a36Sopenharmony_ci else if (rate <= 48000) 31462306a36Sopenharmony_ci new = 0x08; /* 256x, base rate mode */ 31562306a36Sopenharmony_ci else if (rate <= 96000) 31662306a36Sopenharmony_ci new = 0x11; /* 256x, mid rate mode */ 31762306a36Sopenharmony_ci else 31862306a36Sopenharmony_ci new = 0x12; /* 128x, high rate mode */ 31962306a36Sopenharmony_ci old = stac9460_get(ice, STAC946X_MASTER_CLOCKING); 32062306a36Sopenharmony_ci if (old == new) 32162306a36Sopenharmony_ci return; 32262306a36Sopenharmony_ci /* change detected, setting master clock, muting first */ 32362306a36Sopenharmony_ci /* due to possible conflicts with mute controls - mutexing */ 32462306a36Sopenharmony_ci mutex_lock(&spec->mute_mutex); 32562306a36Sopenharmony_ci /* we have to remember current mute status for each DAC */ 32662306a36Sopenharmony_ci for (idx = 0; idx < 7 ; ++idx) 32762306a36Sopenharmony_ci changed[idx] = stac9460_dac_mute(ice, 32862306a36Sopenharmony_ci STAC946X_MASTER_VOLUME + idx, 0); 32962306a36Sopenharmony_ci /*dev_dbg(ice->card->dev, "Rate change: %d, new MC: 0x%02x\n", rate, new);*/ 33062306a36Sopenharmony_ci stac9460_put(ice, STAC946X_MASTER_CLOCKING, new); 33162306a36Sopenharmony_ci udelay(10); 33262306a36Sopenharmony_ci /* unmuting - only originally unmuted dacs - 33362306a36Sopenharmony_ci * i.e. those changed when muting */ 33462306a36Sopenharmony_ci for (idx = 0; idx < 7 ; ++idx) { 33562306a36Sopenharmony_ci if (changed[idx]) 33662306a36Sopenharmony_ci stac9460_dac_mute(ice, STAC946X_MASTER_VOLUME + idx, 1); 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci mutex_unlock(&spec->mute_mutex); 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); 34362306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci/* 34662306a36Sopenharmony_ci * mixers 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic const struct snd_kcontrol_new stac_controls[] = { 35062306a36Sopenharmony_ci { 35162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 35262306a36Sopenharmony_ci .name = "Master Playback Switch", 35362306a36Sopenharmony_ci .info = stac9460_dac_mute_info, 35462306a36Sopenharmony_ci .get = stac9460_dac_mute_get, 35562306a36Sopenharmony_ci .put = stac9460_dac_mute_put, 35662306a36Sopenharmony_ci .private_value = 1, 35762306a36Sopenharmony_ci .tlv = { .p = db_scale_dac } 35862306a36Sopenharmony_ci }, 35962306a36Sopenharmony_ci { 36062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 36162306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 36262306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 36362306a36Sopenharmony_ci .name = "Master Playback Volume", 36462306a36Sopenharmony_ci .info = stac9460_dac_vol_info, 36562306a36Sopenharmony_ci .get = stac9460_dac_vol_get, 36662306a36Sopenharmony_ci .put = stac9460_dac_vol_put, 36762306a36Sopenharmony_ci .private_value = 1, 36862306a36Sopenharmony_ci .tlv = { .p = db_scale_dac } 36962306a36Sopenharmony_ci }, 37062306a36Sopenharmony_ci { 37162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 37262306a36Sopenharmony_ci .name = "DAC Switch", 37362306a36Sopenharmony_ci .count = 6, 37462306a36Sopenharmony_ci .info = stac9460_dac_mute_info, 37562306a36Sopenharmony_ci .get = stac9460_dac_mute_get, 37662306a36Sopenharmony_ci .put = stac9460_dac_mute_put, 37762306a36Sopenharmony_ci }, 37862306a36Sopenharmony_ci { 37962306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 38062306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 38162306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 38262306a36Sopenharmony_ci .name = "DAC Volume", 38362306a36Sopenharmony_ci .count = 6, 38462306a36Sopenharmony_ci .info = stac9460_dac_vol_info, 38562306a36Sopenharmony_ci .get = stac9460_dac_vol_get, 38662306a36Sopenharmony_ci .put = stac9460_dac_vol_put, 38762306a36Sopenharmony_ci .tlv = { .p = db_scale_dac } 38862306a36Sopenharmony_ci }, 38962306a36Sopenharmony_ci { 39062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 39162306a36Sopenharmony_ci .name = "ADC Capture Switch", 39262306a36Sopenharmony_ci .count = 1, 39362306a36Sopenharmony_ci .info = stac9460_adc_mute_info, 39462306a36Sopenharmony_ci .get = stac9460_adc_mute_get, 39562306a36Sopenharmony_ci .put = stac9460_adc_mute_put, 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci }, 39862306a36Sopenharmony_ci { 39962306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 40062306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 40162306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 40262306a36Sopenharmony_ci .name = "ADC Capture Volume", 40362306a36Sopenharmony_ci .count = 1, 40462306a36Sopenharmony_ci .info = stac9460_adc_vol_info, 40562306a36Sopenharmony_ci .get = stac9460_adc_vol_get, 40662306a36Sopenharmony_ci .put = stac9460_adc_vol_put, 40762306a36Sopenharmony_ci .tlv = { .p = db_scale_adc } 40862306a36Sopenharmony_ci }, 40962306a36Sopenharmony_ci { 41062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 41162306a36Sopenharmony_ci .name = "Analog Capture Input", 41262306a36Sopenharmony_ci .info = stac9460_mic_sw_info, 41362306a36Sopenharmony_ci .get = stac9460_mic_sw_get, 41462306a36Sopenharmony_ci .put = stac9460_mic_sw_put, 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci }, 41762306a36Sopenharmony_ci}; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci/* AK4114 - ICE1724 connections on Prodigy192 + MI/ODI/O */ 42062306a36Sopenharmony_ci/* CDTO (pin 32) -- GPIO11 pin 86 42162306a36Sopenharmony_ci * CDTI (pin 33) -- GPIO10 pin 77 42262306a36Sopenharmony_ci * CCLK (pin 34) -- GPIO9 pin 76 42362306a36Sopenharmony_ci * CSN (pin 35) -- GPIO8 pin 75 42462306a36Sopenharmony_ci */ 42562306a36Sopenharmony_ci#define AK4114_ADDR 0x00 /* C1-C0: Chip Address 42662306a36Sopenharmony_ci * (According to datasheet fixed to “00”) 42762306a36Sopenharmony_ci */ 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci/* 43062306a36Sopenharmony_ci * 4wire ak4114 protocol - writing data 43162306a36Sopenharmony_ci */ 43262306a36Sopenharmony_cistatic void write_data(struct snd_ice1712 *ice, unsigned int gpio, 43362306a36Sopenharmony_ci unsigned int data, int idx) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci for (; idx >= 0; idx--) { 43662306a36Sopenharmony_ci /* drop clock */ 43762306a36Sopenharmony_ci gpio &= ~VT1724_PRODIGY192_CCLK; 43862306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, gpio); 43962306a36Sopenharmony_ci udelay(1); 44062306a36Sopenharmony_ci /* set data */ 44162306a36Sopenharmony_ci if (data & (1 << idx)) 44262306a36Sopenharmony_ci gpio |= VT1724_PRODIGY192_CDOUT; 44362306a36Sopenharmony_ci else 44462306a36Sopenharmony_ci gpio &= ~VT1724_PRODIGY192_CDOUT; 44562306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, gpio); 44662306a36Sopenharmony_ci udelay(1); 44762306a36Sopenharmony_ci /* raise clock */ 44862306a36Sopenharmony_ci gpio |= VT1724_PRODIGY192_CCLK; 44962306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, gpio); 45062306a36Sopenharmony_ci udelay(1); 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci/* 45562306a36Sopenharmony_ci * 4wire ak4114 protocol - reading data 45662306a36Sopenharmony_ci */ 45762306a36Sopenharmony_cistatic unsigned char read_data(struct snd_ice1712 *ice, unsigned int gpio, 45862306a36Sopenharmony_ci int idx) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci unsigned char data = 0; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci for (; idx >= 0; idx--) { 46362306a36Sopenharmony_ci /* drop clock */ 46462306a36Sopenharmony_ci gpio &= ~VT1724_PRODIGY192_CCLK; 46562306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, gpio); 46662306a36Sopenharmony_ci udelay(1); 46762306a36Sopenharmony_ci /* read data */ 46862306a36Sopenharmony_ci if (snd_ice1712_gpio_read(ice) & VT1724_PRODIGY192_CDIN) 46962306a36Sopenharmony_ci data |= (1 << idx); 47062306a36Sopenharmony_ci udelay(1); 47162306a36Sopenharmony_ci /* raise clock */ 47262306a36Sopenharmony_ci gpio |= VT1724_PRODIGY192_CCLK; 47362306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, gpio); 47462306a36Sopenharmony_ci udelay(1); 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci return data; 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci/* 47962306a36Sopenharmony_ci * 4wire ak4114 protocol - starting sequence 48062306a36Sopenharmony_ci */ 48162306a36Sopenharmony_cistatic unsigned int prodigy192_4wire_start(struct snd_ice1712 *ice) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci unsigned int tmp; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 48662306a36Sopenharmony_ci tmp = snd_ice1712_gpio_read(ice); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci tmp |= VT1724_PRODIGY192_CCLK; /* high at init */ 48962306a36Sopenharmony_ci tmp &= ~VT1724_PRODIGY192_CS; /* drop chip select */ 49062306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 49162306a36Sopenharmony_ci udelay(1); 49262306a36Sopenharmony_ci return tmp; 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci/* 49662306a36Sopenharmony_ci * 4wire ak4114 protocol - final sequence 49762306a36Sopenharmony_ci */ 49862306a36Sopenharmony_cistatic void prodigy192_4wire_finish(struct snd_ice1712 *ice, unsigned int tmp) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci tmp |= VT1724_PRODIGY192_CS; /* raise chip select */ 50162306a36Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 50262306a36Sopenharmony_ci udelay(1); 50362306a36Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci/* 50762306a36Sopenharmony_ci * Write data to addr register of ak4114 50862306a36Sopenharmony_ci */ 50962306a36Sopenharmony_cistatic void prodigy192_ak4114_write(void *private_data, unsigned char addr, 51062306a36Sopenharmony_ci unsigned char data) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci struct snd_ice1712 *ice = private_data; 51362306a36Sopenharmony_ci unsigned int tmp, addrdata; 51462306a36Sopenharmony_ci tmp = prodigy192_4wire_start(ice); 51562306a36Sopenharmony_ci addrdata = (AK4114_ADDR << 6) | 0x20 | (addr & 0x1f); 51662306a36Sopenharmony_ci addrdata = (addrdata << 8) | data; 51762306a36Sopenharmony_ci write_data(ice, tmp, addrdata, 15); 51862306a36Sopenharmony_ci prodigy192_4wire_finish(ice, tmp); 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci/* 52262306a36Sopenharmony_ci * Read data from addr register of ak4114 52362306a36Sopenharmony_ci */ 52462306a36Sopenharmony_cistatic unsigned char prodigy192_ak4114_read(void *private_data, 52562306a36Sopenharmony_ci unsigned char addr) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci struct snd_ice1712 *ice = private_data; 52862306a36Sopenharmony_ci unsigned int tmp; 52962306a36Sopenharmony_ci unsigned char data; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci tmp = prodigy192_4wire_start(ice); 53262306a36Sopenharmony_ci write_data(ice, tmp, (AK4114_ADDR << 6) | (addr & 0x1f), 7); 53362306a36Sopenharmony_ci data = read_data(ice, tmp, 7); 53462306a36Sopenharmony_ci prodigy192_4wire_finish(ice, tmp); 53562306a36Sopenharmony_ci return data; 53662306a36Sopenharmony_ci} 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic int ak4114_input_sw_info(struct snd_kcontrol *kcontrol, 54062306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci static const char * const texts[2] = { "Toslink", "Coax" }; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, texts); 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic int ak4114_input_sw_get(struct snd_kcontrol *kcontrol, 54962306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 55262306a36Sopenharmony_ci unsigned char val; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci val = prodigy192_ak4114_read(ice, AK4114_REG_IO1); 55562306a36Sopenharmony_ci /* AK4114_IPS0 bit = 0 -> RX0 = Toslink 55662306a36Sopenharmony_ci * AK4114_IPS0 bit = 1 -> RX1 = Coax 55762306a36Sopenharmony_ci */ 55862306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = (val & AK4114_IPS0) ? 1 : 0; 55962306a36Sopenharmony_ci return 0; 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cistatic int ak4114_input_sw_put(struct snd_kcontrol *kcontrol, 56362306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 56662306a36Sopenharmony_ci unsigned char new, old, itemvalue; 56762306a36Sopenharmony_ci int change; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci old = prodigy192_ak4114_read(ice, AK4114_REG_IO1); 57062306a36Sopenharmony_ci /* AK4114_IPS0 could be any bit */ 57162306a36Sopenharmony_ci itemvalue = (ucontrol->value.enumerated.item[0]) ? 0xff : 0x00; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci new = (itemvalue & AK4114_IPS0) | (old & ~AK4114_IPS0); 57462306a36Sopenharmony_ci change = (new != old); 57562306a36Sopenharmony_ci if (change) 57662306a36Sopenharmony_ci prodigy192_ak4114_write(ice, AK4114_REG_IO1, new); 57762306a36Sopenharmony_ci return change; 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_cistatic const struct snd_kcontrol_new ak4114_controls[] = { 58262306a36Sopenharmony_ci { 58362306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 58462306a36Sopenharmony_ci .name = "MIODIO IEC958 Capture Input", 58562306a36Sopenharmony_ci .info = ak4114_input_sw_info, 58662306a36Sopenharmony_ci .get = ak4114_input_sw_get, 58762306a36Sopenharmony_ci .put = ak4114_input_sw_put, 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci}; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic int prodigy192_ak4114_init(struct snd_ice1712 *ice) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci static const unsigned char ak4114_init_vals[] = { 59662306a36Sopenharmony_ci AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1, 59762306a36Sopenharmony_ci /* ice1724 expects I2S and provides clock, 59862306a36Sopenharmony_ci * DEM0 disables the deemphasis filter 59962306a36Sopenharmony_ci */ 60062306a36Sopenharmony_ci AK4114_DIF_I24I2S | AK4114_DEM0 , 60162306a36Sopenharmony_ci AK4114_TX1E, 60262306a36Sopenharmony_ci AK4114_EFH_1024 | AK4114_DIT, /* default input RX0 */ 60362306a36Sopenharmony_ci 0, 60462306a36Sopenharmony_ci 0 60562306a36Sopenharmony_ci }; 60662306a36Sopenharmony_ci static const unsigned char ak4114_init_txcsb[] = { 60762306a36Sopenharmony_ci 0x41, 0x02, 0x2c, 0x00, 0x00 60862306a36Sopenharmony_ci }; 60962306a36Sopenharmony_ci struct prodigy192_spec *spec = ice->spec; 61062306a36Sopenharmony_ci int err; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci err = snd_ak4114_create(ice->card, 61362306a36Sopenharmony_ci prodigy192_ak4114_read, 61462306a36Sopenharmony_ci prodigy192_ak4114_write, 61562306a36Sopenharmony_ci ak4114_init_vals, ak4114_init_txcsb, 61662306a36Sopenharmony_ci ice, &spec->ak4114); 61762306a36Sopenharmony_ci if (err < 0) 61862306a36Sopenharmony_ci return err; 61962306a36Sopenharmony_ci /* AK4114 in Prodigy192 cannot detect external rate correctly. 62062306a36Sopenharmony_ci * No reason to stop capture stream due to incorrect checks */ 62162306a36Sopenharmony_ci spec->ak4114->check_flags = AK4114_CHECK_NO_RATE; 62262306a36Sopenharmony_ci return 0; 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic void stac9460_proc_regs_read(struct snd_info_entry *entry, 62662306a36Sopenharmony_ci struct snd_info_buffer *buffer) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci struct snd_ice1712 *ice = entry->private_data; 62962306a36Sopenharmony_ci int reg, val; 63062306a36Sopenharmony_ci /* registers 0x0 - 0x14 */ 63162306a36Sopenharmony_ci for (reg = 0; reg <= 0x15; reg++) { 63262306a36Sopenharmony_ci val = stac9460_get(ice, reg); 63362306a36Sopenharmony_ci snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val); 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci} 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic void stac9460_proc_init(struct snd_ice1712 *ice) 63962306a36Sopenharmony_ci{ 64062306a36Sopenharmony_ci snd_card_ro_proc_new(ice->card, "stac9460_codec", ice, 64162306a36Sopenharmony_ci stac9460_proc_regs_read); 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_cistatic int prodigy192_add_controls(struct snd_ice1712 *ice) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci struct prodigy192_spec *spec = ice->spec; 64862306a36Sopenharmony_ci unsigned int i; 64962306a36Sopenharmony_ci int err; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(stac_controls); i++) { 65262306a36Sopenharmony_ci err = snd_ctl_add(ice->card, 65362306a36Sopenharmony_ci snd_ctl_new1(&stac_controls[i], ice)); 65462306a36Sopenharmony_ci if (err < 0) 65562306a36Sopenharmony_ci return err; 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci if (spec->ak4114) { 65862306a36Sopenharmony_ci /* ak4114 is connected */ 65962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ak4114_controls); i++) { 66062306a36Sopenharmony_ci err = snd_ctl_add(ice->card, 66162306a36Sopenharmony_ci snd_ctl_new1(&ak4114_controls[i], 66262306a36Sopenharmony_ci ice)); 66362306a36Sopenharmony_ci if (err < 0) 66462306a36Sopenharmony_ci return err; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci err = snd_ak4114_build(spec->ak4114, 66762306a36Sopenharmony_ci NULL, /* ak4114 in MIO/DI/O handles no IEC958 output */ 66862306a36Sopenharmony_ci ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); 66962306a36Sopenharmony_ci if (err < 0) 67062306a36Sopenharmony_ci return err; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci stac9460_proc_init(ice); 67362306a36Sopenharmony_ci return 0; 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci/* 67762306a36Sopenharmony_ci * check for presence of MI/ODI/O add-on card with digital inputs 67862306a36Sopenharmony_ci */ 67962306a36Sopenharmony_cistatic int prodigy192_miodio_exists(struct snd_ice1712 *ice) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci unsigned char orig_value; 68362306a36Sopenharmony_ci const unsigned char test_data = 0xd1; /* random value */ 68462306a36Sopenharmony_ci unsigned char addr = AK4114_REG_INT0_MASK; /* random SAFE address */ 68562306a36Sopenharmony_ci int exists = 0; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci orig_value = prodigy192_ak4114_read(ice, addr); 68862306a36Sopenharmony_ci prodigy192_ak4114_write(ice, addr, test_data); 68962306a36Sopenharmony_ci if (prodigy192_ak4114_read(ice, addr) == test_data) { 69062306a36Sopenharmony_ci /* ak4114 seems to communicate, apparently exists */ 69162306a36Sopenharmony_ci /* writing back original value */ 69262306a36Sopenharmony_ci prodigy192_ak4114_write(ice, addr, orig_value); 69362306a36Sopenharmony_ci exists = 1; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci return exists; 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci/* 69962306a36Sopenharmony_ci * initialize the chip 70062306a36Sopenharmony_ci */ 70162306a36Sopenharmony_cistatic int prodigy192_init(struct snd_ice1712 *ice) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci static const unsigned short stac_inits_prodigy[] = { 70462306a36Sopenharmony_ci STAC946X_RESET, 0, 70562306a36Sopenharmony_ci STAC946X_MASTER_CLOCKING, 0x11, 70662306a36Sopenharmony_ci/* STAC946X_MASTER_VOLUME, 0, 70762306a36Sopenharmony_ci STAC946X_LF_VOLUME, 0, 70862306a36Sopenharmony_ci STAC946X_RF_VOLUME, 0, 70962306a36Sopenharmony_ci STAC946X_LR_VOLUME, 0, 71062306a36Sopenharmony_ci STAC946X_RR_VOLUME, 0, 71162306a36Sopenharmony_ci STAC946X_CENTER_VOLUME, 0, 71262306a36Sopenharmony_ci STAC946X_LFE_VOLUME, 0,*/ 71362306a36Sopenharmony_ci (unsigned short)-1 71462306a36Sopenharmony_ci }; 71562306a36Sopenharmony_ci const unsigned short *p; 71662306a36Sopenharmony_ci int err = 0; 71762306a36Sopenharmony_ci struct prodigy192_spec *spec; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci /* prodigy 192 */ 72062306a36Sopenharmony_ci ice->num_total_dacs = 6; 72162306a36Sopenharmony_ci ice->num_total_adcs = 2; 72262306a36Sopenharmony_ci ice->vt1720 = 0; /* ice1724, e.g. 23 GPIOs */ 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci spec = kzalloc(sizeof(*spec), GFP_KERNEL); 72562306a36Sopenharmony_ci if (!spec) 72662306a36Sopenharmony_ci return -ENOMEM; 72762306a36Sopenharmony_ci ice->spec = spec; 72862306a36Sopenharmony_ci mutex_init(&spec->mute_mutex); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* initialize codec */ 73162306a36Sopenharmony_ci p = stac_inits_prodigy; 73262306a36Sopenharmony_ci for (; *p != (unsigned short)-1; p += 2) 73362306a36Sopenharmony_ci stac9460_put(ice, p[0], p[1]); 73462306a36Sopenharmony_ci ice->gpio.set_pro_rate = stac9460_set_rate_val; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci /* MI/ODI/O add on card with AK4114 */ 73762306a36Sopenharmony_ci if (prodigy192_miodio_exists(ice)) { 73862306a36Sopenharmony_ci err = prodigy192_ak4114_init(ice); 73962306a36Sopenharmony_ci /* from this moment if err = 0 then 74062306a36Sopenharmony_ci * spec->ak4114 should not be null 74162306a36Sopenharmony_ci */ 74262306a36Sopenharmony_ci dev_dbg(ice->card->dev, 74362306a36Sopenharmony_ci "AK4114 initialized with status %d\n", err); 74462306a36Sopenharmony_ci } else 74562306a36Sopenharmony_ci dev_dbg(ice->card->dev, "AK4114 not found\n"); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci return err; 74862306a36Sopenharmony_ci} 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci/* 75262306a36Sopenharmony_ci * Aureon boards don't provide the EEPROM data except for the vendor IDs. 75362306a36Sopenharmony_ci * hence the driver needs to sets up it properly. 75462306a36Sopenharmony_ci */ 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_cistatic const unsigned char prodigy71_eeprom[] = { 75762306a36Sopenharmony_ci [ICE_EEP2_SYSCONF] = 0x6a, /* 49MHz crystal, mpu401, 75862306a36Sopenharmony_ci * spdif-in+ 1 stereo ADC, 75962306a36Sopenharmony_ci * 3 stereo DACs 76062306a36Sopenharmony_ci */ 76162306a36Sopenharmony_ci [ICE_EEP2_ACLINK] = 0x80, /* I2S */ 76262306a36Sopenharmony_ci [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */ 76362306a36Sopenharmony_ci [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ 76462306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR] = 0xff, 76562306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR1] = ~(VT1724_PRODIGY192_CDIN >> 8) , 76662306a36Sopenharmony_ci [ICE_EEP2_GPIO_DIR2] = 0xbf, 76762306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK] = 0x00, 76862306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK1] = 0x00, 76962306a36Sopenharmony_ci [ICE_EEP2_GPIO_MASK2] = 0x00, 77062306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE] = 0x00, 77162306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE1] = 0x00, 77262306a36Sopenharmony_ci [ICE_EEP2_GPIO_STATE2] = 0x10, /* GPIO20: 0 = CD drive dig. input 77362306a36Sopenharmony_ci * passthrough, 77462306a36Sopenharmony_ci * 1 = SPDIF-OUT from ice1724 77562306a36Sopenharmony_ci */ 77662306a36Sopenharmony_ci}; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci/* entry point */ 78062306a36Sopenharmony_cistruct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] = { 78162306a36Sopenharmony_ci { 78262306a36Sopenharmony_ci .subvendor = VT1724_SUBDEVICE_PRODIGY192VE, 78362306a36Sopenharmony_ci .name = "Audiotrak Prodigy 192", 78462306a36Sopenharmony_ci .model = "prodigy192", 78562306a36Sopenharmony_ci .chip_init = prodigy192_init, 78662306a36Sopenharmony_ci .build_controls = prodigy192_add_controls, 78762306a36Sopenharmony_ci .eeprom_size = sizeof(prodigy71_eeprom), 78862306a36Sopenharmony_ci .eeprom_data = prodigy71_eeprom, 78962306a36Sopenharmony_ci }, 79062306a36Sopenharmony_ci { } /* terminator */ 79162306a36Sopenharmony_ci}; 792