+
+/* AK4114 - ICE1724 connections on Prodigy192 + MI/ODI/O */
+/* CDTO (pin 32) -- GPIO11 pin 86
+ * CDTI (pin 33) -- GPIO10 pin 77
+ * CCLK (pin 34) -- GPIO9 pin 76
+ * CSN (pin 35) -- GPIO8 pin 75
+ */
+#define AK4114_ADDR 0x00 /* C1-C0: Chip Address
+ * (According to datasheet fixed to “00”)
+ */
+
+/*
+ * 4wire ak4114 protocol - writing data
+ */
+static void write_data(struct snd_ice1712 *ice, unsigned int gpio,
+ unsigned int data, int idx)
+{
+ for (; idx >= 0; idx--) {
+ /* drop clock */
+ gpio &= ~VT1724_PRODIGY192_CCLK;
+ snd_ice1712_gpio_write(ice, gpio);
+ udelay(1);
+ /* set data */
+ if (data & (1 << idx))
+ gpio |= VT1724_PRODIGY192_CDOUT;
+ else
+ gpio &= ~VT1724_PRODIGY192_CDOUT;
+ snd_ice1712_gpio_write(ice, gpio);
+ udelay(1);
+ /* raise clock */
+ gpio |= VT1724_PRODIGY192_CCLK;
+ snd_ice1712_gpio_write(ice, gpio);
+ udelay(1);
+ }
+}
+
+/*
+ * 4wire ak4114 protocol - reading data
+ */
+static unsigned char read_data(struct snd_ice1712 *ice, unsigned int gpio,
+ int idx)
+{
+ unsigned char data = 0;
+
+ for (; idx >= 0; idx--) {
+ /* drop clock */
+ gpio &= ~VT1724_PRODIGY192_CCLK;
+ snd_ice1712_gpio_write(ice, gpio);
+ udelay(1);
+ /* read data */
+ if (snd_ice1712_gpio_read(ice) & VT1724_PRODIGY192_CDIN)
+ data |= (1 << idx);
+ udelay(1);
+ /* raise clock */
+ gpio |= VT1724_PRODIGY192_CCLK;
+ snd_ice1712_gpio_write(ice, gpio);
+ udelay(1);
+ }
+ return data;
+}
+/*
+ * 4wire ak4114 protocol - starting sequence
+ */
+static unsigned int prodigy192_4wire_start(struct snd_ice1712 *ice)
+{
+ unsigned int tmp;
+
+ snd_ice1712_save_gpio_status(ice);
+ tmp = snd_ice1712_gpio_read(ice);
+
+ tmp |= VT1724_PRODIGY192_CCLK; /* high at init */
+ tmp &= ~VT1724_PRODIGY192_CS; /* drop chip select */
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(1);
+ return tmp;
+}
+
+/*
+ * 4wire ak4114 protocol - final sequence
+ */
+static void prodigy192_4wire_finish(struct snd_ice1712 *ice, unsigned int tmp)
+{
+ tmp |= VT1724_PRODIGY192_CS; /* raise chip select */
+ snd_ice1712_gpio_write(ice, tmp);
+ udelay(1);
+ snd_ice1712_restore_gpio_status(ice);
+}
+
+/*
+ * Write data to addr register of ak4114
+ */
+static void prodigy192_ak4114_write(void *private_data, unsigned char addr,
+ unsigned char data)
+{
+ struct snd_ice1712 *ice = private_data;
+ unsigned int tmp, addrdata;
+ tmp = prodigy192_4wire_start(ice);
+ addrdata = (AK4114_ADDR << 6) | 0x20 | (addr & 0x1f);
+ addrdata = (addrdata << 8) | data;
+ write_data(ice, tmp, addrdata, 15);
+ prodigy192_4wire_finish(ice, tmp);
+}
+
+/*
+ * Read data from addr register of ak4114
+ */
+static unsigned char prodigy192_ak4114_read(void *private_data,
+ unsigned char addr)
+{
+ struct snd_ice1712 *ice = private_data;
+ unsigned int tmp;
+ unsigned char data;
+
+ tmp = prodigy192_4wire_start(ice);
+ write_data(ice, tmp, (AK4114_ADDR << 6) | (addr & 0x1f), 7);
+ data = read_data(ice, tmp, 7);
+ prodigy192_4wire_finish(ice, tmp);
+ return data;
+}
+
+
+static int ak4114_input_sw_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static char *texts[2] = { "Toslink", "Coax" };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 2;
+ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+ uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+ strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
+ return 0;
+}
+
+
+static int ak4114_input_sw_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned char val;
+
+ val = prodigy192_ak4114_read(ice, AK4114_REG_IO1);
+ /* AK4114_IPS0 bit = 0 -> RX0 = Toslink
+ * AK4114_IPS0 bit = 1 -> RX1 = Coax
+ */
+ ucontrol->value.enumerated.item[0] = (val & AK4114_IPS0) ? 1 : 0;
+ return 0;
+}
+
+static int ak4114_input_sw_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
+ unsigned char new, old, itemvalue;
+ int change;
+
+ old = prodigy192_ak4114_read(ice, AK4114_REG_IO1);
+ /* AK4114_IPS0 could be any bit */
+ itemvalue = (ucontrol->value.enumerated.item[0]) ? 0xff : 0x00;
+
+ new = (itemvalue & AK4114_IPS0) | (old & ~AK4114_IPS0);
+ change = (new != old);
+ if (change)
+ prodigy192_ak4114_write(ice, AK4114_REG_IO1, new);
+ return change;
+}
+
+
+static struct snd_kcontrol_new ak4114_controls[] __devinitdata = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "MIODIO IEC958 Capture Input",
+ .info = ak4114_input_sw_info,
+ .get = ak4114_input_sw_get,
+ .put = ak4114_input_sw_put,
+
+ }
+};
+
+
+static int prodigy192_ak4114_init(struct snd_ice1712 *ice)
+{
+ static const unsigned char ak4114_init_vals[] = {
+ AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1,
+ /* ice1724 expects I2S and provides clock,
+ * DEM0 disables the deemphasis filter
+ */
+ AK4114_DIF_I24I2S | AK4114_DEM0 ,
+ AK4114_TX1E,
+ AK4114_EFH_1024 | AK4114_DIT, /* default input RX0 */
+ 0,
+ 0
+ };
+ static const unsigned char ak4114_init_txcsb[] = {
+ 0x41, 0x02, 0x2c, 0x00, 0x00
+ };
+
+ return snd_ak4114_create(ice->card,
+ prodigy192_ak4114_read,
+ prodigy192_ak4114_write,
+ ak4114_init_vals, ak4114_init_txcsb,
+ ice, &ice->spec.prodigy192.ak4114);
+}
+