18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ALSA driver for ICEnsemble VT1724 (Envy24HT) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Lowlevel functions for AudioTrak Prodigy 192 cards 68c2ecf20Sopenharmony_ci * Supported IEC958 input from optional MI/ODI/O add-on card. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Specifics (SW, HW): 98c2ecf20Sopenharmony_ci * ------------------- 108c2ecf20Sopenharmony_ci * * 49.5MHz crystal 118c2ecf20Sopenharmony_ci * * SPDIF-OUT on the card: 128c2ecf20Sopenharmony_ci * - coax (through isolation transformer)/toslink supplied by 138c2ecf20Sopenharmony_ci * 74HC04 gates - 3 in parallel 148c2ecf20Sopenharmony_ci * - output switched between on-board CD drive dig-out connector 158c2ecf20Sopenharmony_ci * and ice1724 SPDTX pin, using 74HC02 NOR gates, controlled 168c2ecf20Sopenharmony_ci * by GPIO20 (0 = CD dig-out, 1 = SPDTX) 178c2ecf20Sopenharmony_ci * * SPDTX goes straight to MI/ODI/O card's SPDIF-OUT coax 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * * MI/ODI/O card: AK4114 based, used for iec958 input only 208c2ecf20Sopenharmony_ci * - toslink input -> RX0 218c2ecf20Sopenharmony_ci * - coax input -> RX1 228c2ecf20Sopenharmony_ci * - 4wire protocol: 238c2ecf20Sopenharmony_ci * AK4114 ICE1724 248c2ecf20Sopenharmony_ci * ------------------------------ 258c2ecf20Sopenharmony_ci * CDTO (pin 32) -- GPIO11 pin 86 268c2ecf20Sopenharmony_ci * CDTI (pin 33) -- GPIO10 pin 77 278c2ecf20Sopenharmony_ci * CCLK (pin 34) -- GPIO9 pin 76 288c2ecf20Sopenharmony_ci * CSN (pin 35) -- GPIO8 pin 75 298c2ecf20Sopenharmony_ci * - output data Mode 7 (24bit, I2S, slave) 308c2ecf20Sopenharmony_ci * - both MCKO1 and MCKO2 of ak4114 are fed to FPGA, which 318c2ecf20Sopenharmony_ci * outputs master clock to SPMCLKIN of ice1724. 328c2ecf20Sopenharmony_ci * Experimentally I found out that only a combination of 338c2ecf20Sopenharmony_ci * OCKS0=1, OCKS1=1 (128fs, 64fs output) and ice1724 - 348c2ecf20Sopenharmony_ci * VT1724_MT_I2S_MCLK_128X=0 (256fs input) yields correct 358c2ecf20Sopenharmony_ci * sampling rate. That means that the FPGA doubles the 368c2ecf20Sopenharmony_ci * MCK01 rate. 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * Copyright (c) 2003 Takashi Iwai <tiwai@suse.de> 398c2ecf20Sopenharmony_ci * Copyright (c) 2003 Dimitromanolakis Apostolos <apostol@cs.utoronto.ca> 408c2ecf20Sopenharmony_ci * Copyright (c) 2004 Kouichi ONO <co2b@ceres.dti.ne.jp> 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#include <linux/delay.h> 448c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 458c2ecf20Sopenharmony_ci#include <linux/init.h> 468c2ecf20Sopenharmony_ci#include <linux/slab.h> 478c2ecf20Sopenharmony_ci#include <sound/core.h> 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#include "ice1712.h" 508c2ecf20Sopenharmony_ci#include "envy24ht.h" 518c2ecf20Sopenharmony_ci#include "prodigy192.h" 528c2ecf20Sopenharmony_ci#include "stac946x.h" 538c2ecf20Sopenharmony_ci#include <sound/tlv.h> 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistruct prodigy192_spec { 568c2ecf20Sopenharmony_ci struct ak4114 *ak4114; 578c2ecf20Sopenharmony_ci /* rate change needs atomic mute/unmute of all dacs*/ 588c2ecf20Sopenharmony_ci struct mutex mute_mutex; 598c2ecf20Sopenharmony_ci}; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic inline void stac9460_put(struct snd_ice1712 *ice, int reg, unsigned char val) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci snd_vt1724_write_i2c(ice, PRODIGY192_STAC9460_ADDR, reg, val); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci return snd_vt1724_read_i2c(ice, PRODIGY192_STAC9460_ADDR, reg); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci/* 728c2ecf20Sopenharmony_ci * DAC mute control 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci/* 768c2ecf20Sopenharmony_ci * idx = STAC9460 volume register number, mute: 0 = mute, 1 = unmute 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_cistatic int stac9460_dac_mute(struct snd_ice1712 *ice, int idx, 798c2ecf20Sopenharmony_ci unsigned char mute) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci unsigned char new, old; 828c2ecf20Sopenharmony_ci int change; 838c2ecf20Sopenharmony_ci old = stac9460_get(ice, idx); 848c2ecf20Sopenharmony_ci new = (~mute << 7 & 0x80) | (old & ~0x80); 858c2ecf20Sopenharmony_ci change = (new != old); 868c2ecf20Sopenharmony_ci if (change) 878c2ecf20Sopenharmony_ci /* dev_dbg(ice->card->dev, "Volume register 0x%02x: 0x%02x\n", idx, new);*/ 888c2ecf20Sopenharmony_ci stac9460_put(ice, idx, new); 898c2ecf20Sopenharmony_ci return change; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#define stac9460_dac_mute_info snd_ctl_boolean_mono_info 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 978c2ecf20Sopenharmony_ci unsigned char val; 988c2ecf20Sopenharmony_ci int idx; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci if (kcontrol->private_value) 1018c2ecf20Sopenharmony_ci idx = STAC946X_MASTER_VOLUME; 1028c2ecf20Sopenharmony_ci else 1038c2ecf20Sopenharmony_ci idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; 1048c2ecf20Sopenharmony_ci val = stac9460_get(ice, idx); 1058c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = (~val >> 7) & 0x1; 1068c2ecf20Sopenharmony_ci return 0; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 1128c2ecf20Sopenharmony_ci struct prodigy192_spec *spec = ice->spec; 1138c2ecf20Sopenharmony_ci int idx, change; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (kcontrol->private_value) 1168c2ecf20Sopenharmony_ci idx = STAC946X_MASTER_VOLUME; 1178c2ecf20Sopenharmony_ci else 1188c2ecf20Sopenharmony_ci idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; 1198c2ecf20Sopenharmony_ci /* due to possible conflicts with stac9460_set_rate_val, mutexing */ 1208c2ecf20Sopenharmony_ci mutex_lock(&spec->mute_mutex); 1218c2ecf20Sopenharmony_ci /* 1228c2ecf20Sopenharmony_ci dev_dbg(ice->card->dev, "Mute put: reg 0x%02x, ctrl value: 0x%02x\n", idx, 1238c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0]); 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_ci change = stac9460_dac_mute(ice, idx, ucontrol->value.integer.value[0]); 1268c2ecf20Sopenharmony_ci mutex_unlock(&spec->mute_mutex); 1278c2ecf20Sopenharmony_ci return change; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* 1318c2ecf20Sopenharmony_ci * DAC volume attenuation mixer control 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_cistatic int stac9460_dac_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 1368c2ecf20Sopenharmony_ci uinfo->count = 1; 1378c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; /* mute */ 1388c2ecf20Sopenharmony_ci uinfo->value.integer.max = 0x7f; /* 0dB */ 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic int stac9460_dac_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 1458c2ecf20Sopenharmony_ci int idx; 1468c2ecf20Sopenharmony_ci unsigned char vol; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (kcontrol->private_value) 1498c2ecf20Sopenharmony_ci idx = STAC946X_MASTER_VOLUME; 1508c2ecf20Sopenharmony_ci else 1518c2ecf20Sopenharmony_ci idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; 1528c2ecf20Sopenharmony_ci vol = stac9460_get(ice, idx) & 0x7f; 1538c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 0x7f - vol; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci return 0; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 1618c2ecf20Sopenharmony_ci int idx; 1628c2ecf20Sopenharmony_ci unsigned char tmp, ovol, nvol; 1638c2ecf20Sopenharmony_ci int change; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (kcontrol->private_value) 1668c2ecf20Sopenharmony_ci idx = STAC946X_MASTER_VOLUME; 1678c2ecf20Sopenharmony_ci else 1688c2ecf20Sopenharmony_ci idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; 1698c2ecf20Sopenharmony_ci nvol = ucontrol->value.integer.value[0]; 1708c2ecf20Sopenharmony_ci tmp = stac9460_get(ice, idx); 1718c2ecf20Sopenharmony_ci ovol = 0x7f - (tmp & 0x7f); 1728c2ecf20Sopenharmony_ci change = (ovol != nvol); 1738c2ecf20Sopenharmony_ci if (change) { 1748c2ecf20Sopenharmony_ci ovol = (0x7f - nvol) | (tmp & 0x80); 1758c2ecf20Sopenharmony_ci /* 1768c2ecf20Sopenharmony_ci dev_dbg(ice->card->dev, "DAC Volume: reg 0x%02x: 0x%02x\n", 1778c2ecf20Sopenharmony_ci idx, ovol); 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_ci stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci return change; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci/* 1858c2ecf20Sopenharmony_ci * ADC mute control 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_ci#define stac9460_adc_mute_info snd_ctl_boolean_stereo_info 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 1928c2ecf20Sopenharmony_ci unsigned char val; 1938c2ecf20Sopenharmony_ci int i; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci for (i = 0; i < 2; ++i) { 1968c2ecf20Sopenharmony_ci val = stac9460_get(ice, STAC946X_MIC_L_VOLUME + i); 1978c2ecf20Sopenharmony_ci ucontrol->value.integer.value[i] = ~val>>7 & 0x1; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci return 0; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 2068c2ecf20Sopenharmony_ci unsigned char new, old; 2078c2ecf20Sopenharmony_ci int i, reg; 2088c2ecf20Sopenharmony_ci int change; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci for (i = 0; i < 2; ++i) { 2118c2ecf20Sopenharmony_ci reg = STAC946X_MIC_L_VOLUME + i; 2128c2ecf20Sopenharmony_ci old = stac9460_get(ice, reg); 2138c2ecf20Sopenharmony_ci new = (~ucontrol->value.integer.value[i]<<7&0x80) | (old&~0x80); 2148c2ecf20Sopenharmony_ci change = (new != old); 2158c2ecf20Sopenharmony_ci if (change) 2168c2ecf20Sopenharmony_ci stac9460_put(ice, reg, new); 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci return change; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci/* 2238c2ecf20Sopenharmony_ci * ADC gain mixer control 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_cistatic int stac9460_adc_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 2288c2ecf20Sopenharmony_ci uinfo->count = 2; 2298c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; /* 0dB */ 2308c2ecf20Sopenharmony_ci uinfo->value.integer.max = 0x0f; /* 22.5dB */ 2318c2ecf20Sopenharmony_ci return 0; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic int stac9460_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 2378c2ecf20Sopenharmony_ci int i, reg; 2388c2ecf20Sopenharmony_ci unsigned char vol; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci for (i = 0; i < 2; ++i) { 2418c2ecf20Sopenharmony_ci reg = STAC946X_MIC_L_VOLUME + i; 2428c2ecf20Sopenharmony_ci vol = stac9460_get(ice, reg) & 0x0f; 2438c2ecf20Sopenharmony_ci ucontrol->value.integer.value[i] = 0x0f - vol; 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci return 0; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 2528c2ecf20Sopenharmony_ci int i, reg; 2538c2ecf20Sopenharmony_ci unsigned char ovol, nvol; 2548c2ecf20Sopenharmony_ci int change; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci for (i = 0; i < 2; ++i) { 2578c2ecf20Sopenharmony_ci reg = STAC946X_MIC_L_VOLUME + i; 2588c2ecf20Sopenharmony_ci nvol = ucontrol->value.integer.value[i] & 0x0f; 2598c2ecf20Sopenharmony_ci ovol = 0x0f - stac9460_get(ice, reg); 2608c2ecf20Sopenharmony_ci change = ((ovol & 0x0f) != nvol); 2618c2ecf20Sopenharmony_ci if (change) 2628c2ecf20Sopenharmony_ci stac9460_put(ice, reg, (0x0f - nvol) | (ovol & ~0x0f)); 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci return change; 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol, 2698c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci static const char * const texts[2] = { "Line In", "Mic" }; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, texts); 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol, 2788c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 2818c2ecf20Sopenharmony_ci unsigned char val; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); 2848c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = (val >> 7) & 0x1; 2858c2ecf20Sopenharmony_ci return 0; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol, 2898c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 2928c2ecf20Sopenharmony_ci unsigned char new, old; 2938c2ecf20Sopenharmony_ci int change; 2948c2ecf20Sopenharmony_ci old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE); 2958c2ecf20Sopenharmony_ci new = (ucontrol->value.enumerated.item[0] << 7 & 0x80) | (old & ~0x80); 2968c2ecf20Sopenharmony_ci change = (new != old); 2978c2ecf20Sopenharmony_ci if (change) 2988c2ecf20Sopenharmony_ci stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new); 2998c2ecf20Sopenharmony_ci return change; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci/* 3028c2ecf20Sopenharmony_ci * Handler for setting correct codec rate - called when rate change is detected 3038c2ecf20Sopenharmony_ci */ 3048c2ecf20Sopenharmony_cistatic void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci unsigned char old, new; 3078c2ecf20Sopenharmony_ci int idx; 3088c2ecf20Sopenharmony_ci unsigned char changed[7]; 3098c2ecf20Sopenharmony_ci struct prodigy192_spec *spec = ice->spec; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (rate == 0) /* no hint - S/PDIF input is master, simply return */ 3128c2ecf20Sopenharmony_ci return; 3138c2ecf20Sopenharmony_ci else if (rate <= 48000) 3148c2ecf20Sopenharmony_ci new = 0x08; /* 256x, base rate mode */ 3158c2ecf20Sopenharmony_ci else if (rate <= 96000) 3168c2ecf20Sopenharmony_ci new = 0x11; /* 256x, mid rate mode */ 3178c2ecf20Sopenharmony_ci else 3188c2ecf20Sopenharmony_ci new = 0x12; /* 128x, high rate mode */ 3198c2ecf20Sopenharmony_ci old = stac9460_get(ice, STAC946X_MASTER_CLOCKING); 3208c2ecf20Sopenharmony_ci if (old == new) 3218c2ecf20Sopenharmony_ci return; 3228c2ecf20Sopenharmony_ci /* change detected, setting master clock, muting first */ 3238c2ecf20Sopenharmony_ci /* due to possible conflicts with mute controls - mutexing */ 3248c2ecf20Sopenharmony_ci mutex_lock(&spec->mute_mutex); 3258c2ecf20Sopenharmony_ci /* we have to remember current mute status for each DAC */ 3268c2ecf20Sopenharmony_ci for (idx = 0; idx < 7 ; ++idx) 3278c2ecf20Sopenharmony_ci changed[idx] = stac9460_dac_mute(ice, 3288c2ecf20Sopenharmony_ci STAC946X_MASTER_VOLUME + idx, 0); 3298c2ecf20Sopenharmony_ci /*dev_dbg(ice->card->dev, "Rate change: %d, new MC: 0x%02x\n", rate, new);*/ 3308c2ecf20Sopenharmony_ci stac9460_put(ice, STAC946X_MASTER_CLOCKING, new); 3318c2ecf20Sopenharmony_ci udelay(10); 3328c2ecf20Sopenharmony_ci /* unmuting - only originally unmuted dacs - 3338c2ecf20Sopenharmony_ci * i.e. those changed when muting */ 3348c2ecf20Sopenharmony_ci for (idx = 0; idx < 7 ; ++idx) { 3358c2ecf20Sopenharmony_ci if (changed[idx]) 3368c2ecf20Sopenharmony_ci stac9460_dac_mute(ice, STAC946X_MASTER_VOLUME + idx, 1); 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci mutex_unlock(&spec->mute_mutex); 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); 3438c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci/* 3468c2ecf20Sopenharmony_ci * mixers 3478c2ecf20Sopenharmony_ci */ 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new stac_controls[] = { 3508c2ecf20Sopenharmony_ci { 3518c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3528c2ecf20Sopenharmony_ci .name = "Master Playback Switch", 3538c2ecf20Sopenharmony_ci .info = stac9460_dac_mute_info, 3548c2ecf20Sopenharmony_ci .get = stac9460_dac_mute_get, 3558c2ecf20Sopenharmony_ci .put = stac9460_dac_mute_put, 3568c2ecf20Sopenharmony_ci .private_value = 1, 3578c2ecf20Sopenharmony_ci .tlv = { .p = db_scale_dac } 3588c2ecf20Sopenharmony_ci }, 3598c2ecf20Sopenharmony_ci { 3608c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3618c2ecf20Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 3628c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 3638c2ecf20Sopenharmony_ci .name = "Master Playback Volume", 3648c2ecf20Sopenharmony_ci .info = stac9460_dac_vol_info, 3658c2ecf20Sopenharmony_ci .get = stac9460_dac_vol_get, 3668c2ecf20Sopenharmony_ci .put = stac9460_dac_vol_put, 3678c2ecf20Sopenharmony_ci .private_value = 1, 3688c2ecf20Sopenharmony_ci .tlv = { .p = db_scale_dac } 3698c2ecf20Sopenharmony_ci }, 3708c2ecf20Sopenharmony_ci { 3718c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3728c2ecf20Sopenharmony_ci .name = "DAC Switch", 3738c2ecf20Sopenharmony_ci .count = 6, 3748c2ecf20Sopenharmony_ci .info = stac9460_dac_mute_info, 3758c2ecf20Sopenharmony_ci .get = stac9460_dac_mute_get, 3768c2ecf20Sopenharmony_ci .put = stac9460_dac_mute_put, 3778c2ecf20Sopenharmony_ci }, 3788c2ecf20Sopenharmony_ci { 3798c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3808c2ecf20Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 3818c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 3828c2ecf20Sopenharmony_ci .name = "DAC Volume", 3838c2ecf20Sopenharmony_ci .count = 6, 3848c2ecf20Sopenharmony_ci .info = stac9460_dac_vol_info, 3858c2ecf20Sopenharmony_ci .get = stac9460_dac_vol_get, 3868c2ecf20Sopenharmony_ci .put = stac9460_dac_vol_put, 3878c2ecf20Sopenharmony_ci .tlv = { .p = db_scale_dac } 3888c2ecf20Sopenharmony_ci }, 3898c2ecf20Sopenharmony_ci { 3908c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3918c2ecf20Sopenharmony_ci .name = "ADC Capture Switch", 3928c2ecf20Sopenharmony_ci .count = 1, 3938c2ecf20Sopenharmony_ci .info = stac9460_adc_mute_info, 3948c2ecf20Sopenharmony_ci .get = stac9460_adc_mute_get, 3958c2ecf20Sopenharmony_ci .put = stac9460_adc_mute_put, 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci }, 3988c2ecf20Sopenharmony_ci { 3998c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4008c2ecf20Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | 4018c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ), 4028c2ecf20Sopenharmony_ci .name = "ADC Capture Volume", 4038c2ecf20Sopenharmony_ci .count = 1, 4048c2ecf20Sopenharmony_ci .info = stac9460_adc_vol_info, 4058c2ecf20Sopenharmony_ci .get = stac9460_adc_vol_get, 4068c2ecf20Sopenharmony_ci .put = stac9460_adc_vol_put, 4078c2ecf20Sopenharmony_ci .tlv = { .p = db_scale_adc } 4088c2ecf20Sopenharmony_ci }, 4098c2ecf20Sopenharmony_ci { 4108c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 4118c2ecf20Sopenharmony_ci .name = "Analog Capture Input", 4128c2ecf20Sopenharmony_ci .info = stac9460_mic_sw_info, 4138c2ecf20Sopenharmony_ci .get = stac9460_mic_sw_get, 4148c2ecf20Sopenharmony_ci .put = stac9460_mic_sw_put, 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci }, 4178c2ecf20Sopenharmony_ci}; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci/* AK4114 - ICE1724 connections on Prodigy192 + MI/ODI/O */ 4208c2ecf20Sopenharmony_ci/* CDTO (pin 32) -- GPIO11 pin 86 4218c2ecf20Sopenharmony_ci * CDTI (pin 33) -- GPIO10 pin 77 4228c2ecf20Sopenharmony_ci * CCLK (pin 34) -- GPIO9 pin 76 4238c2ecf20Sopenharmony_ci * CSN (pin 35) -- GPIO8 pin 75 4248c2ecf20Sopenharmony_ci */ 4258c2ecf20Sopenharmony_ci#define AK4114_ADDR 0x00 /* C1-C0: Chip Address 4268c2ecf20Sopenharmony_ci * (According to datasheet fixed to “00”) 4278c2ecf20Sopenharmony_ci */ 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci/* 4308c2ecf20Sopenharmony_ci * 4wire ak4114 protocol - writing data 4318c2ecf20Sopenharmony_ci */ 4328c2ecf20Sopenharmony_cistatic void write_data(struct snd_ice1712 *ice, unsigned int gpio, 4338c2ecf20Sopenharmony_ci unsigned int data, int idx) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci for (; idx >= 0; idx--) { 4368c2ecf20Sopenharmony_ci /* drop clock */ 4378c2ecf20Sopenharmony_ci gpio &= ~VT1724_PRODIGY192_CCLK; 4388c2ecf20Sopenharmony_ci snd_ice1712_gpio_write(ice, gpio); 4398c2ecf20Sopenharmony_ci udelay(1); 4408c2ecf20Sopenharmony_ci /* set data */ 4418c2ecf20Sopenharmony_ci if (data & (1 << idx)) 4428c2ecf20Sopenharmony_ci gpio |= VT1724_PRODIGY192_CDOUT; 4438c2ecf20Sopenharmony_ci else 4448c2ecf20Sopenharmony_ci gpio &= ~VT1724_PRODIGY192_CDOUT; 4458c2ecf20Sopenharmony_ci snd_ice1712_gpio_write(ice, gpio); 4468c2ecf20Sopenharmony_ci udelay(1); 4478c2ecf20Sopenharmony_ci /* raise clock */ 4488c2ecf20Sopenharmony_ci gpio |= VT1724_PRODIGY192_CCLK; 4498c2ecf20Sopenharmony_ci snd_ice1712_gpio_write(ice, gpio); 4508c2ecf20Sopenharmony_ci udelay(1); 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci/* 4558c2ecf20Sopenharmony_ci * 4wire ak4114 protocol - reading data 4568c2ecf20Sopenharmony_ci */ 4578c2ecf20Sopenharmony_cistatic unsigned char read_data(struct snd_ice1712 *ice, unsigned int gpio, 4588c2ecf20Sopenharmony_ci int idx) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci unsigned char data = 0; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci for (; idx >= 0; idx--) { 4638c2ecf20Sopenharmony_ci /* drop clock */ 4648c2ecf20Sopenharmony_ci gpio &= ~VT1724_PRODIGY192_CCLK; 4658c2ecf20Sopenharmony_ci snd_ice1712_gpio_write(ice, gpio); 4668c2ecf20Sopenharmony_ci udelay(1); 4678c2ecf20Sopenharmony_ci /* read data */ 4688c2ecf20Sopenharmony_ci if (snd_ice1712_gpio_read(ice) & VT1724_PRODIGY192_CDIN) 4698c2ecf20Sopenharmony_ci data |= (1 << idx); 4708c2ecf20Sopenharmony_ci udelay(1); 4718c2ecf20Sopenharmony_ci /* raise clock */ 4728c2ecf20Sopenharmony_ci gpio |= VT1724_PRODIGY192_CCLK; 4738c2ecf20Sopenharmony_ci snd_ice1712_gpio_write(ice, gpio); 4748c2ecf20Sopenharmony_ci udelay(1); 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci return data; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci/* 4798c2ecf20Sopenharmony_ci * 4wire ak4114 protocol - starting sequence 4808c2ecf20Sopenharmony_ci */ 4818c2ecf20Sopenharmony_cistatic unsigned int prodigy192_4wire_start(struct snd_ice1712 *ice) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci unsigned int tmp; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci snd_ice1712_save_gpio_status(ice); 4868c2ecf20Sopenharmony_ci tmp = snd_ice1712_gpio_read(ice); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci tmp |= VT1724_PRODIGY192_CCLK; /* high at init */ 4898c2ecf20Sopenharmony_ci tmp &= ~VT1724_PRODIGY192_CS; /* drop chip select */ 4908c2ecf20Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 4918c2ecf20Sopenharmony_ci udelay(1); 4928c2ecf20Sopenharmony_ci return tmp; 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci/* 4968c2ecf20Sopenharmony_ci * 4wire ak4114 protocol - final sequence 4978c2ecf20Sopenharmony_ci */ 4988c2ecf20Sopenharmony_cistatic void prodigy192_4wire_finish(struct snd_ice1712 *ice, unsigned int tmp) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci tmp |= VT1724_PRODIGY192_CS; /* raise chip select */ 5018c2ecf20Sopenharmony_ci snd_ice1712_gpio_write(ice, tmp); 5028c2ecf20Sopenharmony_ci udelay(1); 5038c2ecf20Sopenharmony_ci snd_ice1712_restore_gpio_status(ice); 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci/* 5078c2ecf20Sopenharmony_ci * Write data to addr register of ak4114 5088c2ecf20Sopenharmony_ci */ 5098c2ecf20Sopenharmony_cistatic void prodigy192_ak4114_write(void *private_data, unsigned char addr, 5108c2ecf20Sopenharmony_ci unsigned char data) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = private_data; 5138c2ecf20Sopenharmony_ci unsigned int tmp, addrdata; 5148c2ecf20Sopenharmony_ci tmp = prodigy192_4wire_start(ice); 5158c2ecf20Sopenharmony_ci addrdata = (AK4114_ADDR << 6) | 0x20 | (addr & 0x1f); 5168c2ecf20Sopenharmony_ci addrdata = (addrdata << 8) | data; 5178c2ecf20Sopenharmony_ci write_data(ice, tmp, addrdata, 15); 5188c2ecf20Sopenharmony_ci prodigy192_4wire_finish(ice, tmp); 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci/* 5228c2ecf20Sopenharmony_ci * Read data from addr register of ak4114 5238c2ecf20Sopenharmony_ci */ 5248c2ecf20Sopenharmony_cistatic unsigned char prodigy192_ak4114_read(void *private_data, 5258c2ecf20Sopenharmony_ci unsigned char addr) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = private_data; 5288c2ecf20Sopenharmony_ci unsigned int tmp; 5298c2ecf20Sopenharmony_ci unsigned char data; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci tmp = prodigy192_4wire_start(ice); 5328c2ecf20Sopenharmony_ci write_data(ice, tmp, (AK4114_ADDR << 6) | (addr & 0x1f), 7); 5338c2ecf20Sopenharmony_ci data = read_data(ice, tmp, 7); 5348c2ecf20Sopenharmony_ci prodigy192_4wire_finish(ice, tmp); 5358c2ecf20Sopenharmony_ci return data; 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_cistatic int ak4114_input_sw_info(struct snd_kcontrol *kcontrol, 5408c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci static const char * const texts[2] = { "Toslink", "Coax" }; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 2, texts); 5458c2ecf20Sopenharmony_ci} 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic int ak4114_input_sw_get(struct snd_kcontrol *kcontrol, 5498c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 5528c2ecf20Sopenharmony_ci unsigned char val; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci val = prodigy192_ak4114_read(ice, AK4114_REG_IO1); 5558c2ecf20Sopenharmony_ci /* AK4114_IPS0 bit = 0 -> RX0 = Toslink 5568c2ecf20Sopenharmony_ci * AK4114_IPS0 bit = 1 -> RX1 = Coax 5578c2ecf20Sopenharmony_ci */ 5588c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = (val & AK4114_IPS0) ? 1 : 0; 5598c2ecf20Sopenharmony_ci return 0; 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cistatic int ak4114_input_sw_put(struct snd_kcontrol *kcontrol, 5638c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 5668c2ecf20Sopenharmony_ci unsigned char new, old, itemvalue; 5678c2ecf20Sopenharmony_ci int change; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci old = prodigy192_ak4114_read(ice, AK4114_REG_IO1); 5708c2ecf20Sopenharmony_ci /* AK4114_IPS0 could be any bit */ 5718c2ecf20Sopenharmony_ci itemvalue = (ucontrol->value.enumerated.item[0]) ? 0xff : 0x00; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci new = (itemvalue & AK4114_IPS0) | (old & ~AK4114_IPS0); 5748c2ecf20Sopenharmony_ci change = (new != old); 5758c2ecf20Sopenharmony_ci if (change) 5768c2ecf20Sopenharmony_ci prodigy192_ak4114_write(ice, AK4114_REG_IO1, new); 5778c2ecf20Sopenharmony_ci return change; 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new ak4114_controls[] = { 5828c2ecf20Sopenharmony_ci { 5838c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5848c2ecf20Sopenharmony_ci .name = "MIODIO IEC958 Capture Input", 5858c2ecf20Sopenharmony_ci .info = ak4114_input_sw_info, 5868c2ecf20Sopenharmony_ci .get = ak4114_input_sw_get, 5878c2ecf20Sopenharmony_ci .put = ak4114_input_sw_put, 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci}; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic int prodigy192_ak4114_init(struct snd_ice1712 *ice) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci static const unsigned char ak4114_init_vals[] = { 5968c2ecf20Sopenharmony_ci AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1, 5978c2ecf20Sopenharmony_ci /* ice1724 expects I2S and provides clock, 5988c2ecf20Sopenharmony_ci * DEM0 disables the deemphasis filter 5998c2ecf20Sopenharmony_ci */ 6008c2ecf20Sopenharmony_ci AK4114_DIF_I24I2S | AK4114_DEM0 , 6018c2ecf20Sopenharmony_ci AK4114_TX1E, 6028c2ecf20Sopenharmony_ci AK4114_EFH_1024 | AK4114_DIT, /* default input RX0 */ 6038c2ecf20Sopenharmony_ci 0, 6048c2ecf20Sopenharmony_ci 0 6058c2ecf20Sopenharmony_ci }; 6068c2ecf20Sopenharmony_ci static const unsigned char ak4114_init_txcsb[] = { 6078c2ecf20Sopenharmony_ci 0x41, 0x02, 0x2c, 0x00, 0x00 6088c2ecf20Sopenharmony_ci }; 6098c2ecf20Sopenharmony_ci struct prodigy192_spec *spec = ice->spec; 6108c2ecf20Sopenharmony_ci int err; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci err = snd_ak4114_create(ice->card, 6138c2ecf20Sopenharmony_ci prodigy192_ak4114_read, 6148c2ecf20Sopenharmony_ci prodigy192_ak4114_write, 6158c2ecf20Sopenharmony_ci ak4114_init_vals, ak4114_init_txcsb, 6168c2ecf20Sopenharmony_ci ice, &spec->ak4114); 6178c2ecf20Sopenharmony_ci if (err < 0) 6188c2ecf20Sopenharmony_ci return err; 6198c2ecf20Sopenharmony_ci /* AK4114 in Prodigy192 cannot detect external rate correctly. 6208c2ecf20Sopenharmony_ci * No reason to stop capture stream due to incorrect checks */ 6218c2ecf20Sopenharmony_ci spec->ak4114->check_flags = AK4114_CHECK_NO_RATE; 6228c2ecf20Sopenharmony_ci return 0; 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic void stac9460_proc_regs_read(struct snd_info_entry *entry, 6268c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = entry->private_data; 6298c2ecf20Sopenharmony_ci int reg, val; 6308c2ecf20Sopenharmony_ci /* registers 0x0 - 0x14 */ 6318c2ecf20Sopenharmony_ci for (reg = 0; reg <= 0x15; reg++) { 6328c2ecf20Sopenharmony_ci val = stac9460_get(ice, reg); 6338c2ecf20Sopenharmony_ci snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val); 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic void stac9460_proc_init(struct snd_ice1712 *ice) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci snd_card_ro_proc_new(ice->card, "stac9460_codec", ice, 6418c2ecf20Sopenharmony_ci stac9460_proc_regs_read); 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_cistatic int prodigy192_add_controls(struct snd_ice1712 *ice) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci struct prodigy192_spec *spec = ice->spec; 6488c2ecf20Sopenharmony_ci unsigned int i; 6498c2ecf20Sopenharmony_ci int err; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(stac_controls); i++) { 6528c2ecf20Sopenharmony_ci err = snd_ctl_add(ice->card, 6538c2ecf20Sopenharmony_ci snd_ctl_new1(&stac_controls[i], ice)); 6548c2ecf20Sopenharmony_ci if (err < 0) 6558c2ecf20Sopenharmony_ci return err; 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci if (spec->ak4114) { 6588c2ecf20Sopenharmony_ci /* ak4114 is connected */ 6598c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ak4114_controls); i++) { 6608c2ecf20Sopenharmony_ci err = snd_ctl_add(ice->card, 6618c2ecf20Sopenharmony_ci snd_ctl_new1(&ak4114_controls[i], 6628c2ecf20Sopenharmony_ci ice)); 6638c2ecf20Sopenharmony_ci if (err < 0) 6648c2ecf20Sopenharmony_ci return err; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci err = snd_ak4114_build(spec->ak4114, 6678c2ecf20Sopenharmony_ci NULL, /* ak4114 in MIO/DI/O handles no IEC958 output */ 6688c2ecf20Sopenharmony_ci ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); 6698c2ecf20Sopenharmony_ci if (err < 0) 6708c2ecf20Sopenharmony_ci return err; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci stac9460_proc_init(ice); 6738c2ecf20Sopenharmony_ci return 0; 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci/* 6778c2ecf20Sopenharmony_ci * check for presence of MI/ODI/O add-on card with digital inputs 6788c2ecf20Sopenharmony_ci */ 6798c2ecf20Sopenharmony_cistatic int prodigy192_miodio_exists(struct snd_ice1712 *ice) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci unsigned char orig_value; 6838c2ecf20Sopenharmony_ci const unsigned char test_data = 0xd1; /* random value */ 6848c2ecf20Sopenharmony_ci unsigned char addr = AK4114_REG_INT0_MASK; /* random SAFE address */ 6858c2ecf20Sopenharmony_ci int exists = 0; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci orig_value = prodigy192_ak4114_read(ice, addr); 6888c2ecf20Sopenharmony_ci prodigy192_ak4114_write(ice, addr, test_data); 6898c2ecf20Sopenharmony_ci if (prodigy192_ak4114_read(ice, addr) == test_data) { 6908c2ecf20Sopenharmony_ci /* ak4114 seems to communicate, apparently exists */ 6918c2ecf20Sopenharmony_ci /* writing back original value */ 6928c2ecf20Sopenharmony_ci prodigy192_ak4114_write(ice, addr, orig_value); 6938c2ecf20Sopenharmony_ci exists = 1; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci return exists; 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci/* 6998c2ecf20Sopenharmony_ci * initialize the chip 7008c2ecf20Sopenharmony_ci */ 7018c2ecf20Sopenharmony_cistatic int prodigy192_init(struct snd_ice1712 *ice) 7028c2ecf20Sopenharmony_ci{ 7038c2ecf20Sopenharmony_ci static const unsigned short stac_inits_prodigy[] = { 7048c2ecf20Sopenharmony_ci STAC946X_RESET, 0, 7058c2ecf20Sopenharmony_ci STAC946X_MASTER_CLOCKING, 0x11, 7068c2ecf20Sopenharmony_ci/* STAC946X_MASTER_VOLUME, 0, 7078c2ecf20Sopenharmony_ci STAC946X_LF_VOLUME, 0, 7088c2ecf20Sopenharmony_ci STAC946X_RF_VOLUME, 0, 7098c2ecf20Sopenharmony_ci STAC946X_LR_VOLUME, 0, 7108c2ecf20Sopenharmony_ci STAC946X_RR_VOLUME, 0, 7118c2ecf20Sopenharmony_ci STAC946X_CENTER_VOLUME, 0, 7128c2ecf20Sopenharmony_ci STAC946X_LFE_VOLUME, 0,*/ 7138c2ecf20Sopenharmony_ci (unsigned short)-1 7148c2ecf20Sopenharmony_ci }; 7158c2ecf20Sopenharmony_ci const unsigned short *p; 7168c2ecf20Sopenharmony_ci int err = 0; 7178c2ecf20Sopenharmony_ci struct prodigy192_spec *spec; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci /* prodigy 192 */ 7208c2ecf20Sopenharmony_ci ice->num_total_dacs = 6; 7218c2ecf20Sopenharmony_ci ice->num_total_adcs = 2; 7228c2ecf20Sopenharmony_ci ice->vt1720 = 0; /* ice1724, e.g. 23 GPIOs */ 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci spec = kzalloc(sizeof(*spec), GFP_KERNEL); 7258c2ecf20Sopenharmony_ci if (!spec) 7268c2ecf20Sopenharmony_ci return -ENOMEM; 7278c2ecf20Sopenharmony_ci ice->spec = spec; 7288c2ecf20Sopenharmony_ci mutex_init(&spec->mute_mutex); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci /* initialize codec */ 7318c2ecf20Sopenharmony_ci p = stac_inits_prodigy; 7328c2ecf20Sopenharmony_ci for (; *p != (unsigned short)-1; p += 2) 7338c2ecf20Sopenharmony_ci stac9460_put(ice, p[0], p[1]); 7348c2ecf20Sopenharmony_ci ice->gpio.set_pro_rate = stac9460_set_rate_val; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci /* MI/ODI/O add on card with AK4114 */ 7378c2ecf20Sopenharmony_ci if (prodigy192_miodio_exists(ice)) { 7388c2ecf20Sopenharmony_ci err = prodigy192_ak4114_init(ice); 7398c2ecf20Sopenharmony_ci /* from this moment if err = 0 then 7408c2ecf20Sopenharmony_ci * spec->ak4114 should not be null 7418c2ecf20Sopenharmony_ci */ 7428c2ecf20Sopenharmony_ci dev_dbg(ice->card->dev, 7438c2ecf20Sopenharmony_ci "AK4114 initialized with status %d\n", err); 7448c2ecf20Sopenharmony_ci } else 7458c2ecf20Sopenharmony_ci dev_dbg(ice->card->dev, "AK4114 not found\n"); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci return err; 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci/* 7528c2ecf20Sopenharmony_ci * Aureon boards don't provide the EEPROM data except for the vendor IDs. 7538c2ecf20Sopenharmony_ci * hence the driver needs to sets up it properly. 7548c2ecf20Sopenharmony_ci */ 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic const unsigned char prodigy71_eeprom[] = { 7578c2ecf20Sopenharmony_ci [ICE_EEP2_SYSCONF] = 0x6a, /* 49MHz crystal, mpu401, 7588c2ecf20Sopenharmony_ci * spdif-in+ 1 stereo ADC, 7598c2ecf20Sopenharmony_ci * 3 stereo DACs 7608c2ecf20Sopenharmony_ci */ 7618c2ecf20Sopenharmony_ci [ICE_EEP2_ACLINK] = 0x80, /* I2S */ 7628c2ecf20Sopenharmony_ci [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */ 7638c2ecf20Sopenharmony_ci [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ 7648c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_DIR] = 0xff, 7658c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_DIR1] = ~(VT1724_PRODIGY192_CDIN >> 8) , 7668c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_DIR2] = 0xbf, 7678c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_MASK] = 0x00, 7688c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_MASK1] = 0x00, 7698c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_MASK2] = 0x00, 7708c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_STATE] = 0x00, 7718c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_STATE1] = 0x00, 7728c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_STATE2] = 0x10, /* GPIO20: 0 = CD drive dig. input 7738c2ecf20Sopenharmony_ci * passthrough, 7748c2ecf20Sopenharmony_ci * 1 = SPDIF-OUT from ice1724 7758c2ecf20Sopenharmony_ci */ 7768c2ecf20Sopenharmony_ci}; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci/* entry point */ 7808c2ecf20Sopenharmony_cistruct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] = { 7818c2ecf20Sopenharmony_ci { 7828c2ecf20Sopenharmony_ci .subvendor = VT1724_SUBDEVICE_PRODIGY192VE, 7838c2ecf20Sopenharmony_ci .name = "Audiotrak Prodigy 192", 7848c2ecf20Sopenharmony_ci .model = "prodigy192", 7858c2ecf20Sopenharmony_ci .chip_init = prodigy192_init, 7868c2ecf20Sopenharmony_ci .build_controls = prodigy192_add_controls, 7878c2ecf20Sopenharmony_ci .eeprom_size = sizeof(prodigy71_eeprom), 7888c2ecf20Sopenharmony_ci .eeprom_data = prodigy71_eeprom, 7898c2ecf20Sopenharmony_ci }, 7908c2ecf20Sopenharmony_ci { } /* terminator */ 7918c2ecf20Sopenharmony_ci}; 792