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