cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

prodigy192.c (21316B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *   ALSA driver for ICEnsemble VT1724 (Envy24HT)
      4 *
      5 *   Lowlevel functions for AudioTrak Prodigy 192 cards
      6 *   Supported IEC958 input from optional MI/ODI/O add-on card.
      7 *
      8 *   Specifics (SW, HW):
      9 *   -------------------
     10 *   	* 49.5MHz crystal
     11 *   	* SPDIF-OUT on the card:
     12 *  	  - coax (through isolation transformer)/toslink supplied by
     13 *          74HC04 gates - 3 in parallel
     14 *   	  - output switched between on-board CD drive dig-out connector
     15 *          and ice1724 SPDTX pin, using 74HC02 NOR gates, controlled
     16 *          by GPIO20 (0 = CD dig-out, 1 = SPDTX)
     17 *   	* SPDTX goes straight to MI/ODI/O card's SPDIF-OUT coax
     18 *
     19 *   	* MI/ODI/O card: AK4114 based, used for iec958 input only
     20 *   		- toslink input -> RX0
     21 *   		- coax input -> RX1
     22 *   		- 4wire protocol:
     23 *   			AK4114		ICE1724
     24 *   			------------------------------
     25 * 			CDTO (pin 32) -- GPIO11 pin 86
     26 * 			CDTI (pin 33) -- GPIO10 pin 77
     27 * 			CCLK (pin 34) -- GPIO9 pin 76
     28 * 			CSN  (pin 35) -- GPIO8 pin 75
     29 *   		- output data Mode 7 (24bit, I2S, slave)
     30 *		- both MCKO1 and MCKO2 of ak4114 are fed to FPGA, which
     31 *		  outputs master clock to SPMCLKIN of ice1724.
     32 *		  Experimentally I found out that only a combination of
     33 *		  OCKS0=1, OCKS1=1 (128fs, 64fs output) and ice1724 -
     34 *		  VT1724_MT_I2S_MCLK_128X=0 (256fs input) yields correct
     35 *		  sampling rate. That means that the FPGA doubles the
     36 *		  MCK01 rate.
     37 *
     38 *	Copyright (c) 2003 Takashi Iwai <tiwai@suse.de>
     39 *      Copyright (c) 2003 Dimitromanolakis Apostolos <apostol@cs.utoronto.ca>
     40 *      Copyright (c) 2004 Kouichi ONO <co2b@ceres.dti.ne.jp>
     41 */      
     42
     43#include <linux/delay.h>
     44#include <linux/interrupt.h>
     45#include <linux/init.h>
     46#include <linux/slab.h>
     47#include <sound/core.h>
     48
     49#include "ice1712.h"
     50#include "envy24ht.h"
     51#include "prodigy192.h"
     52#include "stac946x.h"
     53#include <sound/tlv.h>
     54
     55struct prodigy192_spec {
     56	struct ak4114 *ak4114;
     57	/* rate change needs atomic mute/unmute of all dacs*/
     58	struct mutex mute_mutex;
     59};
     60
     61static inline void stac9460_put(struct snd_ice1712 *ice, int reg, unsigned char val)
     62{
     63	snd_vt1724_write_i2c(ice, PRODIGY192_STAC9460_ADDR, reg, val);
     64}
     65
     66static inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg)
     67{
     68	return snd_vt1724_read_i2c(ice, PRODIGY192_STAC9460_ADDR, reg);
     69}
     70
     71/*
     72 * DAC mute control
     73 */
     74
     75/*
     76 * idx = STAC9460 volume register number, mute: 0 = mute, 1 = unmute
     77 */
     78static int stac9460_dac_mute(struct snd_ice1712 *ice, int idx,
     79		unsigned char mute)
     80{
     81	unsigned char new, old;
     82	int change;
     83	old = stac9460_get(ice, idx);
     84	new = (~mute << 7 & 0x80) | (old & ~0x80);
     85	change = (new != old);
     86	if (change)
     87		/* dev_dbg(ice->card->dev, "Volume register 0x%02x: 0x%02x\n", idx, new);*/
     88		stac9460_put(ice, idx, new);
     89	return change;
     90}
     91
     92#define stac9460_dac_mute_info		snd_ctl_boolean_mono_info
     93
     94static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
     95{
     96	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
     97	unsigned char val;
     98	int idx;
     99
    100	if (kcontrol->private_value)
    101		idx = STAC946X_MASTER_VOLUME;
    102	else
    103		idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME;
    104	val = stac9460_get(ice, idx);
    105	ucontrol->value.integer.value[0] = (~val >> 7) & 0x1;
    106	return 0;
    107}
    108
    109static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
    110{
    111	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
    112	struct prodigy192_spec *spec = ice->spec;
    113	int idx, change;
    114
    115	if (kcontrol->private_value)
    116		idx = STAC946X_MASTER_VOLUME;
    117	else
    118		idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME;
    119	/* due to possible conflicts with stac9460_set_rate_val, mutexing */
    120	mutex_lock(&spec->mute_mutex);
    121	/*
    122	dev_dbg(ice->card->dev, "Mute put: reg 0x%02x, ctrl value: 0x%02x\n", idx,
    123	       ucontrol->value.integer.value[0]);
    124	*/
    125	change = stac9460_dac_mute(ice, idx, ucontrol->value.integer.value[0]);
    126	mutex_unlock(&spec->mute_mutex);
    127	return change;
    128}
    129
    130/*
    131 * DAC volume attenuation mixer control
    132 */
    133static int stac9460_dac_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
    134{
    135	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
    136	uinfo->count = 1;
    137	uinfo->value.integer.min = 0;			/* mute */
    138	uinfo->value.integer.max = 0x7f;		/* 0dB */
    139	return 0;
    140}
    141
    142static int stac9460_dac_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
    143{
    144	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
    145	int idx;
    146	unsigned char vol;
    147
    148	if (kcontrol->private_value)
    149		idx = STAC946X_MASTER_VOLUME;
    150	else
    151		idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME;
    152	vol = stac9460_get(ice, idx) & 0x7f;
    153	ucontrol->value.integer.value[0] = 0x7f - vol;
    154
    155	return 0;
    156}
    157
    158static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
    159{
    160	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
    161	int idx;
    162	unsigned char tmp, ovol, nvol;
    163	int change;
    164
    165	if (kcontrol->private_value)
    166		idx = STAC946X_MASTER_VOLUME;
    167	else
    168		idx  = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME;
    169	nvol = ucontrol->value.integer.value[0];
    170	tmp = stac9460_get(ice, idx);
    171	ovol = 0x7f - (tmp & 0x7f);
    172	change = (ovol != nvol);
    173	if (change) {
    174		ovol =  (0x7f - nvol) | (tmp & 0x80);
    175		/*
    176		dev_dbg(ice->card->dev, "DAC Volume: reg 0x%02x: 0x%02x\n",
    177		       idx, ovol);
    178		*/
    179		stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80));
    180	}
    181	return change;
    182}
    183
    184/*
    185 * ADC mute control
    186 */
    187#define stac9460_adc_mute_info		snd_ctl_boolean_stereo_info
    188
    189static int stac9460_adc_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
    190{
    191	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
    192	unsigned char val;
    193	int i;
    194
    195	for (i = 0; i < 2; ++i) {
    196		val = stac9460_get(ice, STAC946X_MIC_L_VOLUME + i);
    197		ucontrol->value.integer.value[i] = ~val>>7 & 0x1;
    198	}
    199
    200	return 0;
    201}
    202
    203static int stac9460_adc_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
    204{
    205	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
    206	unsigned char new, old;
    207	int i, reg;
    208	int change;
    209
    210	for (i = 0; i < 2; ++i) {
    211		reg = STAC946X_MIC_L_VOLUME + i;
    212		old = stac9460_get(ice, reg);
    213		new = (~ucontrol->value.integer.value[i]<<7&0x80) | (old&~0x80);
    214		change = (new != old);
    215		if (change)
    216			stac9460_put(ice, reg, new);
    217	}
    218
    219	return change;
    220}
    221
    222/*
    223 * ADC gain mixer control
    224 */
    225static int stac9460_adc_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
    226{
    227	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
    228	uinfo->count = 2;
    229	uinfo->value.integer.min = 0;		/* 0dB */
    230	uinfo->value.integer.max = 0x0f;	/* 22.5dB */
    231	return 0;
    232}
    233
    234static int stac9460_adc_vol_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
    235{
    236	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
    237	int i, reg;
    238	unsigned char vol;
    239
    240	for (i = 0; i < 2; ++i) {
    241		reg = STAC946X_MIC_L_VOLUME + i;
    242		vol = stac9460_get(ice, reg) & 0x0f;
    243		ucontrol->value.integer.value[i] = 0x0f - vol;
    244	}
    245
    246	return 0;
    247}
    248
    249static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
    250{
    251	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
    252	int i, reg;
    253	unsigned char ovol, nvol;
    254	int change;
    255
    256	for (i = 0; i < 2; ++i) {
    257		reg = STAC946X_MIC_L_VOLUME + i;
    258		nvol = ucontrol->value.integer.value[i] & 0x0f;
    259		ovol = 0x0f - stac9460_get(ice, reg);
    260		change = ((ovol & 0x0f)  != nvol);
    261		if (change)
    262			stac9460_put(ice, reg, (0x0f - nvol) | (ovol & ~0x0f));
    263	}
    264
    265	return change;
    266}
    267
    268static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol,
    269	       			struct snd_ctl_elem_info *uinfo)
    270{
    271	static const char * const texts[2] = { "Line In", "Mic" };
    272
    273	return snd_ctl_enum_info(uinfo, 1, 2, texts);
    274}
    275
    276
    277static int stac9460_mic_sw_get(struct snd_kcontrol *kcontrol,
    278	       		struct snd_ctl_elem_value *ucontrol)
    279{
    280	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
    281	unsigned char val;
    282		
    283	val = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
    284	ucontrol->value.enumerated.item[0] = (val >> 7) & 0x1;
    285	return 0;
    286}
    287
    288static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol,
    289	       		struct snd_ctl_elem_value *ucontrol)
    290{
    291	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
    292	unsigned char new, old;
    293	int change;
    294	old = stac9460_get(ice, STAC946X_GENERAL_PURPOSE);
    295	new = (ucontrol->value.enumerated.item[0] << 7 & 0x80) | (old & ~0x80);
    296	change = (new != old);
    297	if (change)
    298		stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new);
    299	return change;
    300}
    301/*
    302 * Handler for setting correct codec rate - called when rate change is detected
    303 */
    304static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate)
    305{
    306	unsigned char old, new;
    307	int idx;
    308	unsigned char changed[7];
    309	struct prodigy192_spec *spec = ice->spec;
    310
    311	if (rate == 0)  /* no hint - S/PDIF input is master, simply return */
    312		return;
    313	else if (rate <= 48000)
    314		new = 0x08;	/* 256x, base rate mode */
    315	else if (rate <= 96000)
    316		new = 0x11;	/* 256x, mid rate mode */
    317	else
    318		new = 0x12;	/* 128x, high rate mode */
    319	old = stac9460_get(ice, STAC946X_MASTER_CLOCKING);
    320	if (old == new)
    321		return;
    322	/* change detected, setting master clock, muting first */
    323	/* due to possible conflicts with mute controls - mutexing */
    324	mutex_lock(&spec->mute_mutex);
    325	/* we have to remember current mute status for each DAC */
    326	for (idx = 0; idx < 7 ; ++idx)
    327		changed[idx] = stac9460_dac_mute(ice,
    328				STAC946X_MASTER_VOLUME + idx, 0);
    329	/*dev_dbg(ice->card->dev, "Rate change: %d, new MC: 0x%02x\n", rate, new);*/
    330	stac9460_put(ice, STAC946X_MASTER_CLOCKING, new);
    331	udelay(10);
    332	/* unmuting - only originally unmuted dacs -
    333	 * i.e. those changed when muting */
    334	for (idx = 0; idx < 7 ; ++idx) {
    335		if (changed[idx])
    336			stac9460_dac_mute(ice, STAC946X_MASTER_VOLUME + idx, 1);
    337	}
    338	mutex_unlock(&spec->mute_mutex);
    339}
    340
    341
    342static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0);
    343static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0);
    344
    345/*
    346 * mixers
    347 */
    348
    349static const struct snd_kcontrol_new stac_controls[] = {
    350	{
    351		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    352		.name = "Master Playback Switch",
    353		.info = stac9460_dac_mute_info,
    354		.get = stac9460_dac_mute_get,
    355		.put = stac9460_dac_mute_put,
    356		.private_value = 1,
    357		.tlv = { .p = db_scale_dac }
    358	},
    359	{
    360		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    361		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
    362			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
    363		.name = "Master Playback Volume",
    364		.info = stac9460_dac_vol_info,
    365		.get = stac9460_dac_vol_get,
    366		.put = stac9460_dac_vol_put,
    367		.private_value = 1,
    368		.tlv = { .p = db_scale_dac }
    369	},
    370	{
    371		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    372		.name = "DAC Switch",
    373		.count = 6,
    374		.info = stac9460_dac_mute_info,
    375		.get = stac9460_dac_mute_get,
    376		.put = stac9460_dac_mute_put,
    377	},
    378	{
    379		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    380		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
    381			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
    382		.name = "DAC Volume",
    383		.count = 6,
    384		.info = stac9460_dac_vol_info,
    385		.get = stac9460_dac_vol_get,
    386		.put = stac9460_dac_vol_put,
    387		.tlv = { .p = db_scale_dac }
    388	},
    389	{
    390		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    391		.name = "ADC Capture Switch",
    392		.count = 1,
    393		.info = stac9460_adc_mute_info,
    394		.get = stac9460_adc_mute_get,
    395		.put = stac9460_adc_mute_put,
    396
    397	},
    398	{
    399		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    400		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
    401			   SNDRV_CTL_ELEM_ACCESS_TLV_READ),
    402		.name = "ADC Capture Volume",
    403		.count = 1,
    404		.info = stac9460_adc_vol_info,
    405		.get = stac9460_adc_vol_get,
    406		.put = stac9460_adc_vol_put,
    407		.tlv = { .p = db_scale_adc }
    408	},
    409	{
    410		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    411		.name = "Analog Capture Input",
    412		.info = stac9460_mic_sw_info,
    413		.get = stac9460_mic_sw_get,
    414		.put = stac9460_mic_sw_put,
    415
    416	},
    417};
    418
    419/* AK4114 - ICE1724 connections on Prodigy192 + MI/ODI/O */
    420/* CDTO (pin 32) -- GPIO11 pin 86
    421 * CDTI (pin 33) -- GPIO10 pin 77
    422 * CCLK (pin 34) -- GPIO9 pin 76
    423 * CSN  (pin 35) -- GPIO8 pin 75
    424 */
    425#define AK4114_ADDR	0x00 /* C1-C0: Chip Address
    426			      * (According to datasheet fixed to “00”)
    427			      */
    428
    429/*
    430 * 4wire ak4114 protocol - writing data
    431 */
    432static void write_data(struct snd_ice1712 *ice, unsigned int gpio,
    433		       unsigned int data, int idx)
    434{
    435	for (; idx >= 0; idx--) {
    436		/* drop clock */
    437		gpio &= ~VT1724_PRODIGY192_CCLK;
    438		snd_ice1712_gpio_write(ice, gpio);
    439		udelay(1);
    440		/* set data */
    441		if (data & (1 << idx))
    442			gpio |= VT1724_PRODIGY192_CDOUT;
    443		else
    444			gpio &= ~VT1724_PRODIGY192_CDOUT;
    445		snd_ice1712_gpio_write(ice, gpio);
    446		udelay(1);
    447		/* raise clock */
    448		gpio |= VT1724_PRODIGY192_CCLK;
    449		snd_ice1712_gpio_write(ice, gpio);
    450		udelay(1);
    451	}
    452}
    453
    454/*
    455 * 4wire ak4114 protocol - reading data
    456 */
    457static unsigned char read_data(struct snd_ice1712 *ice, unsigned int gpio,
    458			       int idx)
    459{
    460	unsigned char data = 0;
    461
    462	for (; idx >= 0; idx--) {
    463		/* drop clock */
    464		gpio &= ~VT1724_PRODIGY192_CCLK;
    465		snd_ice1712_gpio_write(ice, gpio);
    466		udelay(1);
    467		/* read data */
    468		if (snd_ice1712_gpio_read(ice) & VT1724_PRODIGY192_CDIN)
    469			data |= (1 << idx);
    470		udelay(1);
    471		/* raise clock */
    472		gpio |= VT1724_PRODIGY192_CCLK;
    473		snd_ice1712_gpio_write(ice, gpio);
    474		udelay(1);
    475	}
    476	return data;
    477}
    478/*
    479 * 4wire ak4114 protocol - starting sequence
    480 */
    481static unsigned int prodigy192_4wire_start(struct snd_ice1712 *ice)
    482{
    483	unsigned int tmp;
    484
    485	snd_ice1712_save_gpio_status(ice);
    486	tmp = snd_ice1712_gpio_read(ice);
    487
    488	tmp |= VT1724_PRODIGY192_CCLK; /* high at init */
    489	tmp &= ~VT1724_PRODIGY192_CS; /* drop chip select */
    490	snd_ice1712_gpio_write(ice, tmp);
    491	udelay(1);
    492	return tmp;
    493}
    494
    495/*
    496 * 4wire ak4114 protocol - final sequence
    497 */
    498static void prodigy192_4wire_finish(struct snd_ice1712 *ice, unsigned int tmp)
    499{
    500	tmp |= VT1724_PRODIGY192_CS; /* raise chip select */
    501	snd_ice1712_gpio_write(ice, tmp);
    502	udelay(1);
    503	snd_ice1712_restore_gpio_status(ice);
    504}
    505
    506/*
    507 * Write data to addr register of ak4114
    508 */
    509static void prodigy192_ak4114_write(void *private_data, unsigned char addr,
    510			       unsigned char data)
    511{
    512	struct snd_ice1712 *ice = private_data;
    513	unsigned int tmp, addrdata;
    514	tmp = prodigy192_4wire_start(ice);
    515	addrdata = (AK4114_ADDR << 6) | 0x20 | (addr & 0x1f);
    516	addrdata = (addrdata << 8) | data;
    517	write_data(ice, tmp, addrdata, 15);
    518	prodigy192_4wire_finish(ice, tmp);
    519}
    520
    521/*
    522 * Read data from addr register of ak4114
    523 */
    524static unsigned char prodigy192_ak4114_read(void *private_data,
    525					    unsigned char addr)
    526{
    527	struct snd_ice1712 *ice = private_data;
    528	unsigned int tmp;
    529	unsigned char data;
    530
    531	tmp = prodigy192_4wire_start(ice);
    532	write_data(ice, tmp, (AK4114_ADDR << 6) | (addr & 0x1f), 7);
    533	data = read_data(ice, tmp, 7);
    534	prodigy192_4wire_finish(ice, tmp);
    535	return data;
    536}
    537
    538
    539static int ak4114_input_sw_info(struct snd_kcontrol *kcontrol,
    540	       			struct snd_ctl_elem_info *uinfo)
    541{
    542	static const char * const texts[2] = { "Toslink", "Coax" };
    543
    544	return snd_ctl_enum_info(uinfo, 1, 2, texts);
    545}
    546
    547
    548static int ak4114_input_sw_get(struct snd_kcontrol *kcontrol,
    549	       		struct snd_ctl_elem_value *ucontrol)
    550{
    551	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
    552	unsigned char val;
    553		
    554	val = prodigy192_ak4114_read(ice, AK4114_REG_IO1);
    555	/* AK4114_IPS0 bit = 0 -> RX0 = Toslink
    556	 * AK4114_IPS0 bit = 1 -> RX1 = Coax
    557	 */
    558	ucontrol->value.enumerated.item[0] = (val & AK4114_IPS0) ? 1 : 0;
    559	return 0;
    560}
    561
    562static int ak4114_input_sw_put(struct snd_kcontrol *kcontrol,
    563	       		struct snd_ctl_elem_value *ucontrol)
    564{
    565	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
    566	unsigned char new, old, itemvalue;
    567	int change;
    568
    569	old = prodigy192_ak4114_read(ice, AK4114_REG_IO1);
    570	/* AK4114_IPS0 could be any bit */
    571	itemvalue = (ucontrol->value.enumerated.item[0]) ? 0xff : 0x00;
    572
    573	new = (itemvalue & AK4114_IPS0) | (old & ~AK4114_IPS0);
    574	change = (new != old);
    575	if (change)
    576		prodigy192_ak4114_write(ice, AK4114_REG_IO1, new);
    577	return change;
    578}
    579
    580
    581static const struct snd_kcontrol_new ak4114_controls[] = {
    582	{
    583		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    584		.name = "MIODIO IEC958 Capture Input",
    585		.info = ak4114_input_sw_info,
    586		.get = ak4114_input_sw_get,
    587		.put = ak4114_input_sw_put,
    588
    589	}
    590};
    591
    592
    593static int prodigy192_ak4114_init(struct snd_ice1712 *ice)
    594{
    595	static const unsigned char ak4114_init_vals[] = {
    596		AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1,
    597		/* ice1724 expects I2S and provides clock,
    598		 * DEM0 disables the deemphasis filter
    599		 */
    600		AK4114_DIF_I24I2S | AK4114_DEM0 ,
    601		AK4114_TX1E,
    602		AK4114_EFH_1024 | AK4114_DIT, /* default input RX0 */
    603		0,
    604		0
    605	};
    606	static const unsigned char ak4114_init_txcsb[] = {
    607		0x41, 0x02, 0x2c, 0x00, 0x00
    608	};
    609	struct prodigy192_spec *spec = ice->spec;
    610	int err;
    611
    612	err = snd_ak4114_create(ice->card,
    613				 prodigy192_ak4114_read,
    614				 prodigy192_ak4114_write,
    615				 ak4114_init_vals, ak4114_init_txcsb,
    616				 ice, &spec->ak4114);
    617	if (err < 0)
    618		return err;
    619	/* AK4114 in Prodigy192 cannot detect external rate correctly.
    620	 * No reason to stop capture stream due to incorrect checks */
    621	spec->ak4114->check_flags = AK4114_CHECK_NO_RATE;
    622	return 0;
    623}
    624
    625static void stac9460_proc_regs_read(struct snd_info_entry *entry,
    626		struct snd_info_buffer *buffer)
    627{
    628	struct snd_ice1712 *ice = entry->private_data;
    629	int reg, val;
    630	/* registers 0x0 - 0x14 */
    631	for (reg = 0; reg <= 0x15; reg++) {
    632		val = stac9460_get(ice, reg);
    633		snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val);
    634	}
    635}
    636
    637
    638static void stac9460_proc_init(struct snd_ice1712 *ice)
    639{
    640	snd_card_ro_proc_new(ice->card, "stac9460_codec", ice,
    641			     stac9460_proc_regs_read);
    642}
    643
    644
    645static int prodigy192_add_controls(struct snd_ice1712 *ice)
    646{
    647	struct prodigy192_spec *spec = ice->spec;
    648	unsigned int i;
    649	int err;
    650
    651	for (i = 0; i < ARRAY_SIZE(stac_controls); i++) {
    652		err = snd_ctl_add(ice->card,
    653				  snd_ctl_new1(&stac_controls[i], ice));
    654		if (err < 0)
    655			return err;
    656	}
    657	if (spec->ak4114) {
    658		/* ak4114 is connected */
    659		for (i = 0; i < ARRAY_SIZE(ak4114_controls); i++) {
    660			err = snd_ctl_add(ice->card,
    661					  snd_ctl_new1(&ak4114_controls[i],
    662						       ice));
    663			if (err < 0)
    664				return err;
    665		}
    666		err = snd_ak4114_build(spec->ak4114,
    667				NULL, /* ak4114 in MIO/DI/O handles no IEC958 output */
    668				ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
    669		if (err < 0)
    670			return err;
    671	}
    672	stac9460_proc_init(ice);
    673	return 0;
    674}
    675
    676/*
    677 * check for presence of MI/ODI/O add-on card with digital inputs
    678 */
    679static int prodigy192_miodio_exists(struct snd_ice1712 *ice)
    680{
    681
    682	unsigned char orig_value;
    683	const unsigned char test_data = 0xd1;	/* random value */
    684	unsigned char addr = AK4114_REG_INT0_MASK; /* random SAFE address */
    685	int exists = 0;
    686
    687	orig_value = prodigy192_ak4114_read(ice, addr);
    688	prodigy192_ak4114_write(ice, addr, test_data);
    689	if (prodigy192_ak4114_read(ice, addr) == test_data) {
    690		/* ak4114 seems to communicate, apparently exists */
    691		/* writing back original value */
    692		prodigy192_ak4114_write(ice, addr, orig_value);
    693		exists = 1;
    694	}
    695	return exists;
    696}
    697
    698/*
    699 * initialize the chip
    700 */
    701static int prodigy192_init(struct snd_ice1712 *ice)
    702{
    703	static const unsigned short stac_inits_prodigy[] = {
    704		STAC946X_RESET, 0,
    705		STAC946X_MASTER_CLOCKING, 0x11,
    706/*		STAC946X_MASTER_VOLUME, 0,
    707		STAC946X_LF_VOLUME, 0,
    708		STAC946X_RF_VOLUME, 0,
    709		STAC946X_LR_VOLUME, 0,
    710		STAC946X_RR_VOLUME, 0,
    711		STAC946X_CENTER_VOLUME, 0,
    712		STAC946X_LFE_VOLUME, 0,*/
    713		(unsigned short)-1
    714	};
    715	const unsigned short *p;
    716	int err = 0;
    717	struct prodigy192_spec *spec;
    718
    719	/* prodigy 192 */
    720	ice->num_total_dacs = 6;
    721	ice->num_total_adcs = 2;
    722	ice->vt1720 = 0;  /* ice1724, e.g. 23 GPIOs */
    723	
    724	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
    725	if (!spec)
    726		return -ENOMEM;
    727	ice->spec = spec;
    728	mutex_init(&spec->mute_mutex);
    729
    730	/* initialize codec */
    731	p = stac_inits_prodigy;
    732	for (; *p != (unsigned short)-1; p += 2)
    733		stac9460_put(ice, p[0], p[1]);
    734	ice->gpio.set_pro_rate = stac9460_set_rate_val;
    735
    736	/* MI/ODI/O add on card with AK4114 */
    737	if (prodigy192_miodio_exists(ice)) {
    738		err = prodigy192_ak4114_init(ice);
    739		/* from this moment if err = 0 then
    740		 * spec->ak4114 should not be null
    741		 */
    742		dev_dbg(ice->card->dev,
    743			"AK4114 initialized with status %d\n", err);
    744	} else
    745		dev_dbg(ice->card->dev, "AK4114 not found\n");
    746
    747	return err;
    748}
    749
    750
    751/*
    752 * Aureon boards don't provide the EEPROM data except for the vendor IDs.
    753 * hence the driver needs to sets up it properly.
    754 */
    755
    756static const unsigned char prodigy71_eeprom[] = {
    757	[ICE_EEP2_SYSCONF]     = 0x6a,	/* 49MHz crystal, mpu401,
    758					 * spdif-in+ 1 stereo ADC,
    759					 * 3 stereo DACs
    760					 */
    761	[ICE_EEP2_ACLINK]      = 0x80,	/* I2S */
    762	[ICE_EEP2_I2S]         = 0xf8,	/* vol, 96k, 24bit, 192k */
    763	[ICE_EEP2_SPDIF]       = 0xc3,	/* out-en, out-int, spdif-in */
    764	[ICE_EEP2_GPIO_DIR]    = 0xff,
    765	[ICE_EEP2_GPIO_DIR1]   = ~(VT1724_PRODIGY192_CDIN >> 8) ,
    766	[ICE_EEP2_GPIO_DIR2]   = 0xbf,
    767	[ICE_EEP2_GPIO_MASK]   = 0x00,
    768	[ICE_EEP2_GPIO_MASK1]  = 0x00,
    769	[ICE_EEP2_GPIO_MASK2]  = 0x00,
    770	[ICE_EEP2_GPIO_STATE]  = 0x00,
    771	[ICE_EEP2_GPIO_STATE1] = 0x00,
    772	[ICE_EEP2_GPIO_STATE2] = 0x10,  /* GPIO20: 0 = CD drive dig. input
    773					 * passthrough,
    774					 * 1 = SPDIF-OUT from ice1724
    775					 */
    776};
    777
    778
    779/* entry point */
    780struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] = {
    781	{
    782		.subvendor = VT1724_SUBDEVICE_PRODIGY192VE,
    783		.name = "Audiotrak Prodigy 192",
    784		.model = "prodigy192",
    785		.chip_init = prodigy192_init,
    786		.build_controls = prodigy192_add_controls,
    787		.eeprom_size = sizeof(prodigy71_eeprom),
    788		.eeprom_data = prodigy71_eeprom,
    789	},
    790	{ } /* terminator */
    791};