xref: /openbmc/linux/sound/pci/ice1712/quartet.c (revision 157ac570)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
26ef80706SPavel Hofman /*
36ef80706SPavel Hofman  *   ALSA driver for ICEnsemble VT1724 (Envy24HT)
46ef80706SPavel Hofman  *
56ef80706SPavel Hofman  *   Lowlevel functions for Infrasonic Quartet
66ef80706SPavel Hofman  *
76ef80706SPavel Hofman  *	Copyright (c) 2009 Pavel Hofman <pavel.hofman@ivitera.com>
86ef80706SPavel Hofman  */
96ef80706SPavel Hofman 
106ef80706SPavel Hofman #include <linux/delay.h>
116ef80706SPavel Hofman #include <linux/interrupt.h>
126ef80706SPavel Hofman #include <linux/init.h>
136ef80706SPavel Hofman #include <linux/slab.h>
14338e17d3SJoey Pabalinas #include <linux/string.h>
156ef80706SPavel Hofman #include <sound/core.h>
166ef80706SPavel Hofman #include <sound/tlv.h>
176ef80706SPavel Hofman #include <sound/info.h>
186ef80706SPavel Hofman 
196ef80706SPavel Hofman #include "ice1712.h"
206ef80706SPavel Hofman #include "envy24ht.h"
216ef80706SPavel Hofman #include <sound/ak4113.h>
226ef80706SPavel Hofman #include "quartet.h"
236ef80706SPavel Hofman 
246ef80706SPavel Hofman struct qtet_spec {
256ef80706SPavel Hofman 	struct ak4113 *ak4113;
266ef80706SPavel Hofman 	unsigned int scr;	/* system control register */
276ef80706SPavel Hofman 	unsigned int mcr;	/* monitoring control register */
286ef80706SPavel Hofman 	unsigned int cpld;	/* cpld register */
296ef80706SPavel Hofman };
306ef80706SPavel Hofman 
316ef80706SPavel Hofman struct qtet_kcontrol_private {
326ef80706SPavel Hofman 	unsigned int bit;
336ef80706SPavel Hofman 	void (*set_register)(struct snd_ice1712 *ice, unsigned int val);
346ef80706SPavel Hofman 	unsigned int (*get_register)(struct snd_ice1712 *ice);
35597da2e4STakashi Iwai 	const char * const texts[2];
366ef80706SPavel Hofman };
376ef80706SPavel Hofman 
386ef80706SPavel Hofman enum {
396ef80706SPavel Hofman 	IN12_SEL = 0,
406ef80706SPavel Hofman 	IN34_SEL,
416ef80706SPavel Hofman 	AIN34_SEL,
426ef80706SPavel Hofman 	COAX_OUT,
436ef80706SPavel Hofman 	IN12_MON12,
446ef80706SPavel Hofman 	IN12_MON34,
456ef80706SPavel Hofman 	IN34_MON12,
466ef80706SPavel Hofman 	IN34_MON34,
476ef80706SPavel Hofman 	OUT12_MON34,
486ef80706SPavel Hofman 	OUT34_MON12,
496ef80706SPavel Hofman };
506ef80706SPavel Hofman 
51a2af050fSTakashi Iwai static const char * const ext_clock_names[3] = {"IEC958 In", "Word Clock 1xFS",
526ef80706SPavel Hofman 	"Word Clock 256xFS"};
536ef80706SPavel Hofman 
546ef80706SPavel Hofman /* chip address on I2C bus */
556ef80706SPavel Hofman #define AK4113_ADDR		0x26	/* S/PDIF receiver */
566ef80706SPavel Hofman 
576ef80706SPavel Hofman /* chip address on SPI bus */
586ef80706SPavel Hofman #define AK4620_ADDR		0x02	/* ADC/DAC */
596ef80706SPavel Hofman 
606ef80706SPavel Hofman 
616ef80706SPavel Hofman /*
626ef80706SPavel Hofman  * GPIO pins
636ef80706SPavel Hofman  */
646ef80706SPavel Hofman 
656ef80706SPavel Hofman /* GPIO0 - O - DATA0, def. 0 */
666ef80706SPavel Hofman #define GPIO_D0			(1<<0)
676ef80706SPavel Hofman /* GPIO1 - I/O - DATA1, Jack Detect Input0 (0:present, 1:missing), def. 1 */
686ef80706SPavel Hofman #define GPIO_D1_JACKDTC0	(1<<1)
696ef80706SPavel Hofman /* GPIO2 - I/O - DATA2, Jack Detect Input1 (0:present, 1:missing), def. 1 */
706ef80706SPavel Hofman #define GPIO_D2_JACKDTC1	(1<<2)
716ef80706SPavel Hofman /* GPIO3 - I/O - DATA3, def. 1 */
726ef80706SPavel Hofman #define GPIO_D3			(1<<3)
736ef80706SPavel Hofman /* GPIO4 - I/O - DATA4, SPI CDTO, def. 1 */
746ef80706SPavel Hofman #define GPIO_D4_SPI_CDTO	(1<<4)
756ef80706SPavel Hofman /* GPIO5 - I/O - DATA5, SPI CCLK, def. 1 */
766ef80706SPavel Hofman #define GPIO_D5_SPI_CCLK	(1<<5)
776ef80706SPavel Hofman /* GPIO6 - I/O - DATA6, Cable Detect Input (0:detected, 1:not detected */
786ef80706SPavel Hofman #define GPIO_D6_CD		(1<<6)
796ef80706SPavel Hofman /* GPIO7 - I/O - DATA7, Device Detect Input (0:detected, 1:not detected */
806ef80706SPavel Hofman #define GPIO_D7_DD		(1<<7)
816ef80706SPavel Hofman /* GPIO8 - O - CPLD Chip Select, def. 1 */
826ef80706SPavel Hofman #define GPIO_CPLD_CSN		(1<<8)
836ef80706SPavel Hofman /* GPIO9 - O - CPLD register read/write (0:write, 1:read), def. 0 */
846ef80706SPavel Hofman #define GPIO_CPLD_RW		(1<<9)
856ef80706SPavel Hofman /* GPIO10 - O - SPI Chip Select for CODEC#0, def. 1 */
866ef80706SPavel Hofman #define GPIO_SPI_CSN0		(1<<10)
876ef80706SPavel Hofman /* GPIO11 - O - SPI Chip Select for CODEC#1, def. 1 */
886ef80706SPavel Hofman #define GPIO_SPI_CSN1		(1<<11)
896ef80706SPavel Hofman /* GPIO12 - O - Ex. Register Output Enable (0:enable, 1:disable), def. 1,
906ef80706SPavel Hofman  * init 0 */
916ef80706SPavel Hofman #define GPIO_EX_GPIOE		(1<<12)
926ef80706SPavel Hofman /* GPIO13 - O - Ex. Register0 Chip Select for System Control Register,
936ef80706SPavel Hofman  * def. 1 */
946ef80706SPavel Hofman #define GPIO_SCR		(1<<13)
956ef80706SPavel Hofman /* GPIO14 - O - Ex. Register1 Chip Select for Monitor Control Register,
966ef80706SPavel Hofman  * def. 1 */
976ef80706SPavel Hofman #define GPIO_MCR		(1<<14)
986ef80706SPavel Hofman 
996ef80706SPavel Hofman #define GPIO_SPI_ALL		(GPIO_D4_SPI_CDTO | GPIO_D5_SPI_CCLK |\
1006ef80706SPavel Hofman 		GPIO_SPI_CSN0 | GPIO_SPI_CSN1)
1016ef80706SPavel Hofman 
1026ef80706SPavel Hofman #define GPIO_DATA_MASK		(GPIO_D0 | GPIO_D1_JACKDTC0 | \
1036ef80706SPavel Hofman 		GPIO_D2_JACKDTC1 | GPIO_D3 | \
1046ef80706SPavel Hofman 		GPIO_D4_SPI_CDTO | GPIO_D5_SPI_CCLK | \
1056ef80706SPavel Hofman 		GPIO_D6_CD | GPIO_D7_DD)
1066ef80706SPavel Hofman 
1076ef80706SPavel Hofman /* System Control Register GPIO_SCR data bits */
1086ef80706SPavel Hofman /* Mic/Line select relay (0:line, 1:mic) */
1096ef80706SPavel Hofman #define SCR_RELAY		GPIO_D0
1106ef80706SPavel Hofman /* Phantom power drive control (0:5V, 1:48V) */
1116ef80706SPavel Hofman #define SCR_PHP_V		GPIO_D1_JACKDTC0
1126ef80706SPavel Hofman /* H/W mute control (0:Normal, 1:Mute) */
1136ef80706SPavel Hofman #define SCR_MUTE		GPIO_D2_JACKDTC1
1146ef80706SPavel Hofman /* Phantom power control (0:Phantom on, 1:off) */
1156ef80706SPavel Hofman #define SCR_PHP			GPIO_D3
1166ef80706SPavel Hofman /* Analog input 1/2 Source Select */
1176ef80706SPavel Hofman #define SCR_AIN12_SEL0		GPIO_D4_SPI_CDTO
1186ef80706SPavel Hofman #define SCR_AIN12_SEL1		GPIO_D5_SPI_CCLK
1196ef80706SPavel Hofman /* Analog input 3/4 Source Select (0:line, 1:hi-z) */
1206ef80706SPavel Hofman #define SCR_AIN34_SEL		GPIO_D6_CD
1216ef80706SPavel Hofman /* Codec Power Down (0:power down, 1:normal) */
1226ef80706SPavel Hofman #define SCR_CODEC_PDN		GPIO_D7_DD
1236ef80706SPavel Hofman 
1246ef80706SPavel Hofman #define SCR_AIN12_LINE		(0)
1256ef80706SPavel Hofman #define SCR_AIN12_MIC		(SCR_AIN12_SEL0)
1266ef80706SPavel Hofman #define SCR_AIN12_LOWCUT	(SCR_AIN12_SEL1 | SCR_AIN12_SEL0)
1276ef80706SPavel Hofman 
1286ef80706SPavel Hofman /* Monitor Control Register GPIO_MCR data bits */
1296ef80706SPavel Hofman /* Input 1/2 to Monitor 1/2 (0:off, 1:on) */
1306ef80706SPavel Hofman #define MCR_IN12_MON12		GPIO_D0
1316ef80706SPavel Hofman /* Input 1/2 to Monitor 3/4 (0:off, 1:on) */
1326ef80706SPavel Hofman #define MCR_IN12_MON34		GPIO_D1_JACKDTC0
1336ef80706SPavel Hofman /* Input 3/4 to Monitor 1/2 (0:off, 1:on) */
1346ef80706SPavel Hofman #define MCR_IN34_MON12		GPIO_D2_JACKDTC1
1356ef80706SPavel Hofman /* Input 3/4 to Monitor 3/4 (0:off, 1:on) */
1366ef80706SPavel Hofman #define MCR_IN34_MON34		GPIO_D3
1376ef80706SPavel Hofman /* Output to Monitor 1/2 (0:off, 1:on) */
1386ef80706SPavel Hofman #define MCR_OUT34_MON12		GPIO_D4_SPI_CDTO
1396ef80706SPavel Hofman /* Output to Monitor 3/4 (0:off, 1:on) */
1406ef80706SPavel Hofman #define MCR_OUT12_MON34		GPIO_D5_SPI_CCLK
1416ef80706SPavel Hofman 
1426ef80706SPavel Hofman /* CPLD Register DATA bits */
1436ef80706SPavel Hofman /* Clock Rate Select */
1446ef80706SPavel Hofman #define CPLD_CKS0		GPIO_D0
1456ef80706SPavel Hofman #define CPLD_CKS1		GPIO_D1_JACKDTC0
1466ef80706SPavel Hofman #define CPLD_CKS2		GPIO_D2_JACKDTC1
1476ef80706SPavel Hofman /* Sync Source Select (0:Internal, 1:External) */
1486ef80706SPavel Hofman #define CPLD_SYNC_SEL		GPIO_D3
1496ef80706SPavel Hofman /* Word Clock FS Select (0:FS, 1:256FS) */
1506ef80706SPavel Hofman #define CPLD_WORD_SEL		GPIO_D4_SPI_CDTO
1516ef80706SPavel Hofman /* Coaxial Output Source (IS-Link) (0:SPDIF, 1:I2S) */
1526ef80706SPavel Hofman #define CPLD_COAX_OUT		GPIO_D5_SPI_CCLK
1536ef80706SPavel Hofman /* Input 1/2 Source Select (0:Analog12, 1:An34) */
1546ef80706SPavel Hofman #define CPLD_IN12_SEL		GPIO_D6_CD
1556ef80706SPavel Hofman /* Input 3/4 Source Select (0:Analog34, 1:Digital In) */
1566ef80706SPavel Hofman #define CPLD_IN34_SEL		GPIO_D7_DD
1576ef80706SPavel Hofman 
1586ef80706SPavel Hofman /* internal clock (CPLD_SYNC_SEL = 0) options */
1596ef80706SPavel Hofman #define CPLD_CKS_44100HZ	(0)
1606ef80706SPavel Hofman #define CPLD_CKS_48000HZ	(CPLD_CKS0)
1616ef80706SPavel Hofman #define CPLD_CKS_88200HZ	(CPLD_CKS1)
1626ef80706SPavel Hofman #define CPLD_CKS_96000HZ	(CPLD_CKS1 | CPLD_CKS0)
1636ef80706SPavel Hofman #define CPLD_CKS_176400HZ	(CPLD_CKS2)
1646ef80706SPavel Hofman #define CPLD_CKS_192000HZ	(CPLD_CKS2 | CPLD_CKS0)
1656ef80706SPavel Hofman 
1666ef80706SPavel Hofman #define CPLD_CKS_MASK		(CPLD_CKS0 | CPLD_CKS1 | CPLD_CKS2)
1676ef80706SPavel Hofman 
1686ef80706SPavel Hofman /* external clock (CPLD_SYNC_SEL = 1) options */
1696ef80706SPavel Hofman /* external clock - SPDIF */
1706ef80706SPavel Hofman #define CPLD_EXT_SPDIF	(0 | CPLD_SYNC_SEL)
1716ef80706SPavel Hofman /* external clock - WordClock 1xfs */
1726ef80706SPavel Hofman #define CPLD_EXT_WORDCLOCK_1FS	(CPLD_CKS1 | CPLD_SYNC_SEL)
1736ef80706SPavel Hofman /* external clock - WordClock 256xfs */
1746ef80706SPavel Hofman #define CPLD_EXT_WORDCLOCK_256FS	(CPLD_CKS1 | CPLD_WORD_SEL |\
1756ef80706SPavel Hofman 		CPLD_SYNC_SEL)
1766ef80706SPavel Hofman 
1776ef80706SPavel Hofman #define EXT_SPDIF_TYPE			0
1786ef80706SPavel Hofman #define EXT_WORDCLOCK_1FS_TYPE		1
1796ef80706SPavel Hofman #define EXT_WORDCLOCK_256FS_TYPE	2
1806ef80706SPavel Hofman 
1816ef80706SPavel Hofman #define AK4620_DFS0		(1<<0)
1826ef80706SPavel Hofman #define AK4620_DFS1		(1<<1)
1836ef80706SPavel Hofman #define AK4620_CKS0		(1<<2)
1846ef80706SPavel Hofman #define AK4620_CKS1		(1<<3)
1856ef80706SPavel Hofman /* Clock and Format Control register */
1866ef80706SPavel Hofman #define AK4620_DFS_REG		0x02
1876ef80706SPavel Hofman 
1886ef80706SPavel Hofman /* Deem and Volume Control register */
1896ef80706SPavel Hofman #define AK4620_DEEMVOL_REG	0x03
1906ef80706SPavel Hofman #define AK4620_SMUTE		(1<<7)
1916ef80706SPavel Hofman 
1926ef80706SPavel Hofman /*
1936ef80706SPavel Hofman  * Conversion from int value to its binary form. Used for debugging.
1946ef80706SPavel Hofman  * The output buffer must be allocated prior to calling the function.
1956ef80706SPavel Hofman  */
get_binary(char * buffer,int value)1966ef80706SPavel Hofman static char *get_binary(char *buffer, int value)
1976ef80706SPavel Hofman {
1986ef80706SPavel Hofman 	int i, j, pos;
1996ef80706SPavel Hofman 	pos = 0;
2006ef80706SPavel Hofman 	for (i = 0; i < 4; ++i) {
2016ef80706SPavel Hofman 		for (j = 0; j < 8; ++j) {
2026ef80706SPavel Hofman 			if (value & (1 << (31-(i*8 + j))))
2036ef80706SPavel Hofman 				buffer[pos] = '1';
2046ef80706SPavel Hofman 			else
2056ef80706SPavel Hofman 				buffer[pos] = '0';
2066ef80706SPavel Hofman 			pos++;
2076ef80706SPavel Hofman 		}
2086ef80706SPavel Hofman 		if (i < 3) {
2096ef80706SPavel Hofman 			buffer[pos] = ' ';
2106ef80706SPavel Hofman 			pos++;
2116ef80706SPavel Hofman 		}
2126ef80706SPavel Hofman 	}
2136ef80706SPavel Hofman 	buffer[pos] = '\0';
2146ef80706SPavel Hofman 	return buffer;
2156ef80706SPavel Hofman }
2166ef80706SPavel Hofman 
2176ef80706SPavel Hofman /*
2186ef80706SPavel Hofman  * Initial setup of the conversion array GPIO <-> rate
2196ef80706SPavel Hofman  */
220965f19beSTakashi Iwai static const unsigned int qtet_rates[] = {
2216ef80706SPavel Hofman 	44100, 48000, 88200,
2226ef80706SPavel Hofman 	96000, 176400, 192000,
2236ef80706SPavel Hofman };
2246ef80706SPavel Hofman 
225965f19beSTakashi Iwai static const unsigned int cks_vals[] = {
2266ef80706SPavel Hofman 	CPLD_CKS_44100HZ, CPLD_CKS_48000HZ, CPLD_CKS_88200HZ,
2276ef80706SPavel Hofman 	CPLD_CKS_96000HZ, CPLD_CKS_176400HZ, CPLD_CKS_192000HZ,
2286ef80706SPavel Hofman };
2296ef80706SPavel Hofman 
230965f19beSTakashi Iwai static const struct snd_pcm_hw_constraint_list qtet_rates_info = {
2316ef80706SPavel Hofman 	.count = ARRAY_SIZE(qtet_rates),
2326ef80706SPavel Hofman 	.list = qtet_rates,
2336ef80706SPavel Hofman 	.mask = 0,
2346ef80706SPavel Hofman };
2356ef80706SPavel Hofman 
qtet_ak4113_write(void * private_data,unsigned char reg,unsigned char val)2366ef80706SPavel Hofman static void qtet_ak4113_write(void *private_data, unsigned char reg,
2376ef80706SPavel Hofman 		unsigned char val)
2386ef80706SPavel Hofman {
2396ef80706SPavel Hofman 	snd_vt1724_write_i2c((struct snd_ice1712 *)private_data, AK4113_ADDR,
2406ef80706SPavel Hofman 			reg, val);
2416ef80706SPavel Hofman }
2426ef80706SPavel Hofman 
qtet_ak4113_read(void * private_data,unsigned char reg)2436ef80706SPavel Hofman static unsigned char qtet_ak4113_read(void *private_data, unsigned char reg)
2446ef80706SPavel Hofman {
2456ef80706SPavel Hofman 	return snd_vt1724_read_i2c((struct snd_ice1712 *)private_data,
2466ef80706SPavel Hofman 			AK4113_ADDR, reg);
2476ef80706SPavel Hofman }
2486ef80706SPavel Hofman 
2496ef80706SPavel Hofman 
2506ef80706SPavel Hofman /*
2516ef80706SPavel Hofman  * AK4620 section
2526ef80706SPavel Hofman  */
2536ef80706SPavel Hofman 
2546ef80706SPavel Hofman /*
2556ef80706SPavel Hofman  * Write data to addr register of ak4620
2566ef80706SPavel Hofman  */
qtet_akm_write(struct snd_akm4xxx * ak,int chip,unsigned char addr,unsigned char data)2576ef80706SPavel Hofman static void qtet_akm_write(struct snd_akm4xxx *ak, int chip,
2586ef80706SPavel Hofman 		unsigned char addr, unsigned char data)
2596ef80706SPavel Hofman {
2606ef80706SPavel Hofman 	unsigned int tmp, orig_dir;
2616ef80706SPavel Hofman 	int idx;
2626ef80706SPavel Hofman 	unsigned int addrdata;
2636ef80706SPavel Hofman 	struct snd_ice1712 *ice = ak->private_data[0];
2646ef80706SPavel Hofman 
2656ef80706SPavel Hofman 	if (snd_BUG_ON(chip < 0 || chip >= 4))
2666ef80706SPavel Hofman 		return;
2676dfb5affSTakashi Iwai 	/*dev_dbg(ice->card->dev, "Writing to AK4620: chip=%d, addr=0x%x,
2686ef80706SPavel Hofman 	  data=0x%x\n", chip, addr, data);*/
2696ef80706SPavel Hofman 	orig_dir = ice->gpio.get_dir(ice);
2706ef80706SPavel Hofman 	ice->gpio.set_dir(ice, orig_dir | GPIO_SPI_ALL);
2716ef80706SPavel Hofman 	/* set mask - only SPI bits */
2726ef80706SPavel Hofman 	ice->gpio.set_mask(ice, ~GPIO_SPI_ALL);
2736ef80706SPavel Hofman 
2746ef80706SPavel Hofman 	tmp = ice->gpio.get_data(ice);
2756ef80706SPavel Hofman 	/* high all */
2766ef80706SPavel Hofman 	tmp |= GPIO_SPI_ALL;
2776ef80706SPavel Hofman 	ice->gpio.set_data(ice, tmp);
2786ef80706SPavel Hofman 	udelay(100);
2796ef80706SPavel Hofman 	/* drop chip select */
2806ef80706SPavel Hofman 	if (chip)
2816ef80706SPavel Hofman 		/* CODEC 1 */
2826ef80706SPavel Hofman 		tmp &= ~GPIO_SPI_CSN1;
2836ef80706SPavel Hofman 	else
2846ef80706SPavel Hofman 		tmp &= ~GPIO_SPI_CSN0;
2856ef80706SPavel Hofman 	ice->gpio.set_data(ice, tmp);
2866ef80706SPavel Hofman 	udelay(100);
2876ef80706SPavel Hofman 
2886ef80706SPavel Hofman 	/* build I2C address + data byte */
2896ef80706SPavel Hofman 	addrdata = (AK4620_ADDR << 6) | 0x20 | (addr & 0x1f);
2906ef80706SPavel Hofman 	addrdata = (addrdata << 8) | data;
2916ef80706SPavel Hofman 	for (idx = 15; idx >= 0; idx--) {
2926ef80706SPavel Hofman 		/* drop clock */
2936ef80706SPavel Hofman 		tmp &= ~GPIO_D5_SPI_CCLK;
2946ef80706SPavel Hofman 		ice->gpio.set_data(ice, tmp);
2956ef80706SPavel Hofman 		udelay(100);
2966ef80706SPavel Hofman 		/* set data */
2976ef80706SPavel Hofman 		if (addrdata & (1 << idx))
2986ef80706SPavel Hofman 			tmp |= GPIO_D4_SPI_CDTO;
2996ef80706SPavel Hofman 		else
3006ef80706SPavel Hofman 			tmp &= ~GPIO_D4_SPI_CDTO;
3016ef80706SPavel Hofman 		ice->gpio.set_data(ice, tmp);
3026ef80706SPavel Hofman 		udelay(100);
3036ef80706SPavel Hofman 		/* raise clock */
3046ef80706SPavel Hofman 		tmp |= GPIO_D5_SPI_CCLK;
3056ef80706SPavel Hofman 		ice->gpio.set_data(ice, tmp);
3066ef80706SPavel Hofman 		udelay(100);
3076ef80706SPavel Hofman 	}
3086ef80706SPavel Hofman 	/* all back to 1 */
3096ef80706SPavel Hofman 	tmp |= GPIO_SPI_ALL;
3106ef80706SPavel Hofman 	ice->gpio.set_data(ice, tmp);
3116ef80706SPavel Hofman 	udelay(100);
3126ef80706SPavel Hofman 
3136ef80706SPavel Hofman 	/* return all gpios to non-writable */
3146ef80706SPavel Hofman 	ice->gpio.set_mask(ice, 0xffffff);
3156ef80706SPavel Hofman 	/* restore GPIOs direction */
3166ef80706SPavel Hofman 	ice->gpio.set_dir(ice, orig_dir);
3176ef80706SPavel Hofman }
3186ef80706SPavel Hofman 
qtet_akm_set_regs(struct snd_akm4xxx * ak,unsigned char addr,unsigned char mask,unsigned char value)3196ef80706SPavel Hofman static void qtet_akm_set_regs(struct snd_akm4xxx *ak, unsigned char addr,
3206ef80706SPavel Hofman 		unsigned char mask, unsigned char value)
3216ef80706SPavel Hofman {
3226ef80706SPavel Hofman 	unsigned char tmp;
3236ef80706SPavel Hofman 	int chip;
3246ef80706SPavel Hofman 	for (chip = 0; chip < ak->num_chips; chip++) {
3256ef80706SPavel Hofman 		tmp = snd_akm4xxx_get(ak, chip, addr);
3266ef80706SPavel Hofman 		/* clear the bits */
3276ef80706SPavel Hofman 		tmp &= ~mask;
3286ef80706SPavel Hofman 		/* set the new bits */
3296ef80706SPavel Hofman 		tmp |= value;
3306ef80706SPavel Hofman 		snd_akm4xxx_write(ak, chip, addr, tmp);
3316ef80706SPavel Hofman 	}
3326ef80706SPavel Hofman }
3336ef80706SPavel Hofman 
3346ef80706SPavel Hofman /*
3356ef80706SPavel Hofman  * change the rate of AK4620
3366ef80706SPavel Hofman  */
qtet_akm_set_rate_val(struct snd_akm4xxx * ak,unsigned int rate)3376ef80706SPavel Hofman static void qtet_akm_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
3386ef80706SPavel Hofman {
3396ef80706SPavel Hofman 	unsigned char ak4620_dfs;
3406ef80706SPavel Hofman 
3416ef80706SPavel Hofman 	if (rate == 0)  /* no hint - S/PDIF input is master or the new spdif
3426ef80706SPavel Hofman 			   input rate undetected, simply return */
3436ef80706SPavel Hofman 		return;
3446ef80706SPavel Hofman 
3456ef80706SPavel Hofman 	/* adjust DFS on codecs - see datasheet */
3466ef80706SPavel Hofman 	if (rate > 108000)
3476ef80706SPavel Hofman 		ak4620_dfs = AK4620_DFS1 | AK4620_CKS1;
3486ef80706SPavel Hofman 	else if (rate > 54000)
3496ef80706SPavel Hofman 		ak4620_dfs = AK4620_DFS0 | AK4620_CKS0;
3506ef80706SPavel Hofman 	else
3516ef80706SPavel Hofman 		ak4620_dfs = 0;
3526ef80706SPavel Hofman 
3536ef80706SPavel Hofman 	/* set new value */
3546ef80706SPavel Hofman 	qtet_akm_set_regs(ak, AK4620_DFS_REG, AK4620_DFS0 | AK4620_DFS1 |
3556ef80706SPavel Hofman 			AK4620_CKS0 | AK4620_CKS1, ak4620_dfs);
3566ef80706SPavel Hofman }
3576ef80706SPavel Hofman 
3586ef80706SPavel Hofman #define AK_CONTROL(xname, xch)	{ .name = xname, .num_channels = xch }
3596ef80706SPavel Hofman 
3606ef80706SPavel Hofman #define PCM_12_PLAYBACK_VOLUME	"PCM 1/2 Playback Volume"
3616ef80706SPavel Hofman #define PCM_34_PLAYBACK_VOLUME	"PCM 3/4 Playback Volume"
3626ef80706SPavel Hofman #define PCM_12_CAPTURE_VOLUME	"PCM 1/2 Capture Volume"
3636ef80706SPavel Hofman #define PCM_34_CAPTURE_VOLUME	"PCM 3/4 Capture Volume"
3646ef80706SPavel Hofman 
3656ef80706SPavel Hofman static const struct snd_akm4xxx_dac_channel qtet_dac[] = {
3666ef80706SPavel Hofman 	AK_CONTROL(PCM_12_PLAYBACK_VOLUME, 2),
3676ef80706SPavel Hofman 	AK_CONTROL(PCM_34_PLAYBACK_VOLUME, 2),
3686ef80706SPavel Hofman };
3696ef80706SPavel Hofman 
3706ef80706SPavel Hofman static const struct snd_akm4xxx_adc_channel qtet_adc[] = {
3716ef80706SPavel Hofman 	AK_CONTROL(PCM_12_CAPTURE_VOLUME, 2),
3726ef80706SPavel Hofman 	AK_CONTROL(PCM_34_CAPTURE_VOLUME, 2),
3736ef80706SPavel Hofman };
3746ef80706SPavel Hofman 
3753135432eSBhumika Goyal static const struct snd_akm4xxx akm_qtet_dac = {
3766ef80706SPavel Hofman 	.type = SND_AK4620,
3776ef80706SPavel Hofman 	.num_dacs = 4,	/* DAC1 - Output 12
3786ef80706SPavel Hofman 	*/
3796ef80706SPavel Hofman 	.num_adcs = 4,	/* ADC1 - Input 12
3806ef80706SPavel Hofman 	*/
3816ef80706SPavel Hofman 	.ops = {
3826ef80706SPavel Hofman 		.write = qtet_akm_write,
3836ef80706SPavel Hofman 		.set_rate_val = qtet_akm_set_rate_val,
3846ef80706SPavel Hofman 	},
3856ef80706SPavel Hofman 	.dac_info = qtet_dac,
3866ef80706SPavel Hofman 	.adc_info = qtet_adc,
3876ef80706SPavel Hofman };
3886ef80706SPavel Hofman 
3896ef80706SPavel Hofman /* Communication routines with the CPLD */
3906ef80706SPavel Hofman 
3916ef80706SPavel Hofman 
3926ef80706SPavel Hofman /* Writes data to external register reg, both reg and data are
3936ef80706SPavel Hofman  * GPIO representations */
reg_write(struct snd_ice1712 * ice,unsigned int reg,unsigned int data)3946ef80706SPavel Hofman static void reg_write(struct snd_ice1712 *ice, unsigned int reg,
3956ef80706SPavel Hofman 		unsigned int data)
3966ef80706SPavel Hofman {
3976ef80706SPavel Hofman 	unsigned int tmp;
3986ef80706SPavel Hofman 
3996ef80706SPavel Hofman 	mutex_lock(&ice->gpio_mutex);
4006ef80706SPavel Hofman 	/* set direction of used GPIOs*/
4016ef80706SPavel Hofman 	/* all outputs */
4026ef80706SPavel Hofman 	tmp = 0x00ffff;
4036ef80706SPavel Hofman 	ice->gpio.set_dir(ice, tmp);
4046ef80706SPavel Hofman 	/* mask - writable bits */
4056ef80706SPavel Hofman 	ice->gpio.set_mask(ice, ~(tmp));
4066ef80706SPavel Hofman 	/* write the data */
4076ef80706SPavel Hofman 	tmp = ice->gpio.get_data(ice);
4086ef80706SPavel Hofman 	tmp &= ~GPIO_DATA_MASK;
4096ef80706SPavel Hofman 	tmp |= data;
4106ef80706SPavel Hofman 	ice->gpio.set_data(ice, tmp);
4116ef80706SPavel Hofman 	udelay(100);
4126ef80706SPavel Hofman 	/* drop output enable */
4136ef80706SPavel Hofman 	tmp &=  ~GPIO_EX_GPIOE;
4146ef80706SPavel Hofman 	ice->gpio.set_data(ice, tmp);
4156ef80706SPavel Hofman 	udelay(100);
4166ef80706SPavel Hofman 	/* drop the register gpio */
4176ef80706SPavel Hofman 	tmp &= ~reg;
4186ef80706SPavel Hofman 	ice->gpio.set_data(ice, tmp);
4196ef80706SPavel Hofman 	udelay(100);
4206ef80706SPavel Hofman 	/* raise the register GPIO */
4216ef80706SPavel Hofman 	tmp |= reg;
4226ef80706SPavel Hofman 	ice->gpio.set_data(ice, tmp);
4236ef80706SPavel Hofman 	udelay(100);
4246ef80706SPavel Hofman 
4256ef80706SPavel Hofman 	/* raise all data gpios */
4266ef80706SPavel Hofman 	tmp |= GPIO_DATA_MASK;
4276ef80706SPavel Hofman 	ice->gpio.set_data(ice, tmp);
4286ef80706SPavel Hofman 	/* mask - immutable bits */
4296ef80706SPavel Hofman 	ice->gpio.set_mask(ice, 0xffffff);
4306ef80706SPavel Hofman 	/* outputs only 8-15 */
4316ef80706SPavel Hofman 	ice->gpio.set_dir(ice, 0x00ff00);
4326ef80706SPavel Hofman 	mutex_unlock(&ice->gpio_mutex);
4336ef80706SPavel Hofman }
4346ef80706SPavel Hofman 
get_scr(struct snd_ice1712 * ice)4356ef80706SPavel Hofman static unsigned int get_scr(struct snd_ice1712 *ice)
4366ef80706SPavel Hofman {
4376ef80706SPavel Hofman 	struct qtet_spec *spec = ice->spec;
4386ef80706SPavel Hofman 	return spec->scr;
4396ef80706SPavel Hofman }
4406ef80706SPavel Hofman 
get_mcr(struct snd_ice1712 * ice)4416ef80706SPavel Hofman static unsigned int get_mcr(struct snd_ice1712 *ice)
4426ef80706SPavel Hofman {
4436ef80706SPavel Hofman 	struct qtet_spec *spec = ice->spec;
4446ef80706SPavel Hofman 	return spec->mcr;
4456ef80706SPavel Hofman }
4466ef80706SPavel Hofman 
get_cpld(struct snd_ice1712 * ice)4476ef80706SPavel Hofman static unsigned int get_cpld(struct snd_ice1712 *ice)
4486ef80706SPavel Hofman {
4496ef80706SPavel Hofman 	struct qtet_spec *spec = ice->spec;
4506ef80706SPavel Hofman 	return spec->cpld;
4516ef80706SPavel Hofman }
4526ef80706SPavel Hofman 
set_scr(struct snd_ice1712 * ice,unsigned int val)4536ef80706SPavel Hofman static void set_scr(struct snd_ice1712 *ice, unsigned int val)
4546ef80706SPavel Hofman {
4556ef80706SPavel Hofman 	struct qtet_spec *spec = ice->spec;
4566ef80706SPavel Hofman 	reg_write(ice, GPIO_SCR, val);
4576ef80706SPavel Hofman 	spec->scr = val;
4586ef80706SPavel Hofman }
4596ef80706SPavel Hofman 
set_mcr(struct snd_ice1712 * ice,unsigned int val)4606ef80706SPavel Hofman static void set_mcr(struct snd_ice1712 *ice, unsigned int val)
4616ef80706SPavel Hofman {
4626ef80706SPavel Hofman 	struct qtet_spec *spec = ice->spec;
4636ef80706SPavel Hofman 	reg_write(ice, GPIO_MCR, val);
4646ef80706SPavel Hofman 	spec->mcr = val;
4656ef80706SPavel Hofman }
4666ef80706SPavel Hofman 
set_cpld(struct snd_ice1712 * ice,unsigned int val)4676ef80706SPavel Hofman static void set_cpld(struct snd_ice1712 *ice, unsigned int val)
4686ef80706SPavel Hofman {
4696ef80706SPavel Hofman 	struct qtet_spec *spec = ice->spec;
4706ef80706SPavel Hofman 	reg_write(ice, GPIO_CPLD_CSN, val);
4716ef80706SPavel Hofman 	spec->cpld = val;
4726ef80706SPavel Hofman }
4733270f0ddSTakashi Iwai 
proc_regs_read(struct snd_info_entry * entry,struct snd_info_buffer * buffer)4746ef80706SPavel Hofman static void proc_regs_read(struct snd_info_entry *entry,
4756ef80706SPavel Hofman 		struct snd_info_buffer *buffer)
4766ef80706SPavel Hofman {
4776ef80706SPavel Hofman 	struct snd_ice1712 *ice = entry->private_data;
4786ef80706SPavel Hofman 	char bin_buffer[36];
4796ef80706SPavel Hofman 
4806ef80706SPavel Hofman 	snd_iprintf(buffer, "SCR:	%s\n", get_binary(bin_buffer,
4816ef80706SPavel Hofman 				get_scr(ice)));
4826ef80706SPavel Hofman 	snd_iprintf(buffer, "MCR:	%s\n", get_binary(bin_buffer,
4836ef80706SPavel Hofman 				get_mcr(ice)));
4846ef80706SPavel Hofman 	snd_iprintf(buffer, "CPLD:	%s\n", get_binary(bin_buffer,
4856ef80706SPavel Hofman 				get_cpld(ice)));
4866ef80706SPavel Hofman }
4876ef80706SPavel Hofman 
proc_init(struct snd_ice1712 * ice)4886ef80706SPavel Hofman static void proc_init(struct snd_ice1712 *ice)
4896ef80706SPavel Hofman {
49047f2769bSTakashi Iwai 	snd_card_ro_proc_new(ice->card, "quartet", ice, proc_regs_read);
4916ef80706SPavel Hofman }
4926ef80706SPavel Hofman 
qtet_mute_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)4936ef80706SPavel Hofman static int qtet_mute_get(struct snd_kcontrol *kcontrol,
4946ef80706SPavel Hofman 		struct snd_ctl_elem_value *ucontrol)
4956ef80706SPavel Hofman {
4966ef80706SPavel Hofman 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
4976ef80706SPavel Hofman 	unsigned int val;
4986ef80706SPavel Hofman 	val = get_scr(ice) & SCR_MUTE;
4996ef80706SPavel Hofman 	ucontrol->value.integer.value[0] = (val) ? 0 : 1;
5006ef80706SPavel Hofman 	return 0;
5016ef80706SPavel Hofman }
5026ef80706SPavel Hofman 
qtet_mute_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)5036ef80706SPavel Hofman static int qtet_mute_put(struct snd_kcontrol *kcontrol,
5046ef80706SPavel Hofman 		struct snd_ctl_elem_value *ucontrol)
5056ef80706SPavel Hofman {
5066ef80706SPavel Hofman 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
5076ef80706SPavel Hofman 	unsigned int old, new, smute;
5086ef80706SPavel Hofman 	old = get_scr(ice) & SCR_MUTE;
5096ef80706SPavel Hofman 	if (ucontrol->value.integer.value[0]) {
5106ef80706SPavel Hofman 		/* unmute */
5116ef80706SPavel Hofman 		new = 0;
5126ef80706SPavel Hofman 		/* un-smuting DAC */
5136ef80706SPavel Hofman 		smute = 0;
5146ef80706SPavel Hofman 	} else {
5156ef80706SPavel Hofman 		/* mute */
5166ef80706SPavel Hofman 		new = SCR_MUTE;
5176ef80706SPavel Hofman 		/* smuting DAC */
5186ef80706SPavel Hofman 		smute = AK4620_SMUTE;
5196ef80706SPavel Hofman 	}
5206ef80706SPavel Hofman 	if (old != new) {
5216ef80706SPavel Hofman 		struct snd_akm4xxx *ak = ice->akm;
5226ef80706SPavel Hofman 		set_scr(ice, (get_scr(ice) & ~SCR_MUTE) | new);
5236ef80706SPavel Hofman 		/* set smute */
5246ef80706SPavel Hofman 		qtet_akm_set_regs(ak, AK4620_DEEMVOL_REG, AK4620_SMUTE, smute);
5256ef80706SPavel Hofman 		return 1;
5266ef80706SPavel Hofman 	}
5276ef80706SPavel Hofman 	/* no change */
5286ef80706SPavel Hofman 	return 0;
5296ef80706SPavel Hofman }
5306ef80706SPavel Hofman 
qtet_ain12_enum_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)5316ef80706SPavel Hofman static int qtet_ain12_enum_info(struct snd_kcontrol *kcontrol,
5326ef80706SPavel Hofman 		struct snd_ctl_elem_info *uinfo)
5336ef80706SPavel Hofman {
534a2af050fSTakashi Iwai 	static const char * const texts[3] =
535a2af050fSTakashi Iwai 		{"Line In 1/2", "Mic", "Mic + Low-cut"};
536597da2e4STakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
5376ef80706SPavel Hofman }
5386ef80706SPavel Hofman 
qtet_ain12_sw_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)5396ef80706SPavel Hofman static int qtet_ain12_sw_get(struct snd_kcontrol *kcontrol,
5406ef80706SPavel Hofman 		struct snd_ctl_elem_value *ucontrol)
5416ef80706SPavel Hofman {
5426ef80706SPavel Hofman 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
5436ef80706SPavel Hofman 	unsigned int val, result;
5446ef80706SPavel Hofman 	val = get_scr(ice) & (SCR_AIN12_SEL1 | SCR_AIN12_SEL0);
5456ef80706SPavel Hofman 	switch (val) {
5466ef80706SPavel Hofman 	case SCR_AIN12_LINE:
5476ef80706SPavel Hofman 		result = 0;
5486ef80706SPavel Hofman 		break;
5496ef80706SPavel Hofman 	case SCR_AIN12_MIC:
5506ef80706SPavel Hofman 		result = 1;
5516ef80706SPavel Hofman 		break;
5526ef80706SPavel Hofman 	case SCR_AIN12_LOWCUT:
5536ef80706SPavel Hofman 		result = 2;
5546ef80706SPavel Hofman 		break;
5556ef80706SPavel Hofman 	default:
5566ef80706SPavel Hofman 		/* BUG - no other combinations allowed */
5576ef80706SPavel Hofman 		snd_BUG();
5586ef80706SPavel Hofman 		result = 0;
5596ef80706SPavel Hofman 	}
5606ef80706SPavel Hofman 	ucontrol->value.integer.value[0] = result;
5616ef80706SPavel Hofman 	return 0;
5626ef80706SPavel Hofman }
5636ef80706SPavel Hofman 
qtet_ain12_sw_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)5646ef80706SPavel Hofman static int qtet_ain12_sw_put(struct snd_kcontrol *kcontrol,
5656ef80706SPavel Hofman 		struct snd_ctl_elem_value *ucontrol)
5666ef80706SPavel Hofman {
5676ef80706SPavel Hofman 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
5686ef80706SPavel Hofman 	unsigned int old, new, tmp, masked_old;
569666d3b61SColin Ian King 	old = get_scr(ice);
5706ef80706SPavel Hofman 	masked_old = old & (SCR_AIN12_SEL1 | SCR_AIN12_SEL0);
5716ef80706SPavel Hofman 	tmp = ucontrol->value.integer.value[0];
5726ef80706SPavel Hofman 	if (tmp == 2)
5736ef80706SPavel Hofman 		tmp = 3;	/* binary 10 is not supported */
5746ef80706SPavel Hofman 	tmp <<= 4;	/* shifting to SCR_AIN12_SEL0 */
5756ef80706SPavel Hofman 	if (tmp != masked_old) {
5766ef80706SPavel Hofman 		/* change requested */
5776ef80706SPavel Hofman 		switch (tmp) {
5786ef80706SPavel Hofman 		case SCR_AIN12_LINE:
5796ef80706SPavel Hofman 			new = old & ~(SCR_AIN12_SEL1 | SCR_AIN12_SEL0);
5806ef80706SPavel Hofman 			set_scr(ice, new);
5816ef80706SPavel Hofman 			/* turn off relay */
5826ef80706SPavel Hofman 			new &= ~SCR_RELAY;
5836ef80706SPavel Hofman 			set_scr(ice, new);
5846ef80706SPavel Hofman 			break;
5856ef80706SPavel Hofman 		case SCR_AIN12_MIC:
5866ef80706SPavel Hofman 			/* turn on relay */
5876ef80706SPavel Hofman 			new = old | SCR_RELAY;
5886ef80706SPavel Hofman 			set_scr(ice, new);
5896ef80706SPavel Hofman 			new = (new & ~SCR_AIN12_SEL1) | SCR_AIN12_SEL0;
5906ef80706SPavel Hofman 			set_scr(ice, new);
5916ef80706SPavel Hofman 			break;
5926ef80706SPavel Hofman 		case SCR_AIN12_LOWCUT:
5936ef80706SPavel Hofman 			/* turn on relay */
5946ef80706SPavel Hofman 			new = old | SCR_RELAY;
5956ef80706SPavel Hofman 			set_scr(ice, new);
5966ef80706SPavel Hofman 			new |= SCR_AIN12_SEL1 | SCR_AIN12_SEL0;
5976ef80706SPavel Hofman 			set_scr(ice, new);
5986ef80706SPavel Hofman 			break;
5996ef80706SPavel Hofman 		default:
6006ef80706SPavel Hofman 			snd_BUG();
6016ef80706SPavel Hofman 		}
6026ef80706SPavel Hofman 		return 1;
6036ef80706SPavel Hofman 	}
6046ef80706SPavel Hofman 	/* no change */
6056ef80706SPavel Hofman 	return 0;
6066ef80706SPavel Hofman }
6076ef80706SPavel Hofman 
qtet_php_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)6086ef80706SPavel Hofman static int qtet_php_get(struct snd_kcontrol *kcontrol,
6096ef80706SPavel Hofman 		struct snd_ctl_elem_value *ucontrol)
6106ef80706SPavel Hofman {
6116ef80706SPavel Hofman 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
6126ef80706SPavel Hofman 	unsigned int val;
6136ef80706SPavel Hofman 	/* if phantom voltage =48V, phantom on */
6146ef80706SPavel Hofman 	val = get_scr(ice) & SCR_PHP_V;
6156ef80706SPavel Hofman 	ucontrol->value.integer.value[0] = val ? 1 : 0;
6166ef80706SPavel Hofman 	return 0;
6176ef80706SPavel Hofman }
6186ef80706SPavel Hofman 
qtet_php_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)6196ef80706SPavel Hofman static int qtet_php_put(struct snd_kcontrol *kcontrol,
6206ef80706SPavel Hofman 		struct snd_ctl_elem_value *ucontrol)
6216ef80706SPavel Hofman {
6226ef80706SPavel Hofman 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
6236ef80706SPavel Hofman 	unsigned int old, new;
6246ef80706SPavel Hofman 	old = new = get_scr(ice);
6256ef80706SPavel Hofman 	if (ucontrol->value.integer.value[0] /* phantom on requested */
6266ef80706SPavel Hofman 			&& (~old & SCR_PHP_V)) /* 0 = voltage 5V */ {
6276ef80706SPavel Hofman 		/* is off, turn on */
6286ef80706SPavel Hofman 		/* turn voltage on first, = 1 */
6296ef80706SPavel Hofman 		new = old | SCR_PHP_V;
6306ef80706SPavel Hofman 		set_scr(ice, new);
6316ef80706SPavel Hofman 		/* turn phantom on, = 0 */
6326ef80706SPavel Hofman 		new &= ~SCR_PHP;
6336ef80706SPavel Hofman 		set_scr(ice, new);
6346ef80706SPavel Hofman 	} else if (!ucontrol->value.integer.value[0] && (old & SCR_PHP_V)) {
6356ef80706SPavel Hofman 		/* phantom off requested and 1 = voltage 48V */
6366ef80706SPavel Hofman 		/* is on, turn off */
6376ef80706SPavel Hofman 		/* turn voltage off first, = 0 */
6386ef80706SPavel Hofman 		new = old & ~SCR_PHP_V;
6396ef80706SPavel Hofman 		set_scr(ice, new);
6406ef80706SPavel Hofman 		/* turn phantom off, = 1 */
6416ef80706SPavel Hofman 		new |= SCR_PHP;
6426ef80706SPavel Hofman 		set_scr(ice, new);
6436ef80706SPavel Hofman 	}
6446ef80706SPavel Hofman 	if (old != new)
6456ef80706SPavel Hofman 		return 1;
6466ef80706SPavel Hofman 	/* no change */
6476ef80706SPavel Hofman 	return 0;
6486ef80706SPavel Hofman }
6496ef80706SPavel Hofman 
6506ef80706SPavel Hofman #define PRIV_SW(xid, xbit, xreg)	[xid] = {.bit = xbit,\
6516ef80706SPavel Hofman 	.set_register = set_##xreg,\
6526ef80706SPavel Hofman 	.get_register = get_##xreg, }
6536ef80706SPavel Hofman 
6546ef80706SPavel Hofman 
6556ef80706SPavel Hofman #define PRIV_ENUM2(xid, xbit, xreg, xtext1, xtext2)	[xid] = {.bit = xbit,\
6566ef80706SPavel Hofman 	.set_register = set_##xreg,\
6576ef80706SPavel Hofman 	.get_register = get_##xreg,\
6586ef80706SPavel Hofman 	.texts = {xtext1, xtext2} }
6596ef80706SPavel Hofman 
660f16a4e96STakashi Iwai static const struct qtet_kcontrol_private qtet_privates[] = {
6616ef80706SPavel Hofman 	PRIV_ENUM2(IN12_SEL, CPLD_IN12_SEL, cpld, "An In 1/2", "An In 3/4"),
6626ef80706SPavel Hofman 	PRIV_ENUM2(IN34_SEL, CPLD_IN34_SEL, cpld, "An In 3/4", "IEC958 In"),
6636ef80706SPavel Hofman 	PRIV_ENUM2(AIN34_SEL, SCR_AIN34_SEL, scr, "Line In 3/4", "Hi-Z"),
6646ef80706SPavel Hofman 	PRIV_ENUM2(COAX_OUT, CPLD_COAX_OUT, cpld, "IEC958", "I2S"),
6656ef80706SPavel Hofman 	PRIV_SW(IN12_MON12, MCR_IN12_MON12, mcr),
6666ef80706SPavel Hofman 	PRIV_SW(IN12_MON34, MCR_IN12_MON34, mcr),
6676ef80706SPavel Hofman 	PRIV_SW(IN34_MON12, MCR_IN34_MON12, mcr),
6686ef80706SPavel Hofman 	PRIV_SW(IN34_MON34, MCR_IN34_MON34, mcr),
6696ef80706SPavel Hofman 	PRIV_SW(OUT12_MON34, MCR_OUT12_MON34, mcr),
6706ef80706SPavel Hofman 	PRIV_SW(OUT34_MON12, MCR_OUT34_MON12, mcr),
6716ef80706SPavel Hofman };
6726ef80706SPavel Hofman 
qtet_enum_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)6736ef80706SPavel Hofman static int qtet_enum_info(struct snd_kcontrol *kcontrol,
6746ef80706SPavel Hofman 		struct snd_ctl_elem_info *uinfo)
6756ef80706SPavel Hofman {
6766ef80706SPavel Hofman 	struct qtet_kcontrol_private private =
6776ef80706SPavel Hofman 		qtet_privates[kcontrol->private_value];
678597da2e4STakashi Iwai 	return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(private.texts),
679597da2e4STakashi Iwai 				 private.texts);
6806ef80706SPavel Hofman }
6816ef80706SPavel Hofman 
qtet_sw_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)6826ef80706SPavel Hofman static int qtet_sw_get(struct snd_kcontrol *kcontrol,
6836ef80706SPavel Hofman 		struct snd_ctl_elem_value *ucontrol)
6846ef80706SPavel Hofman {
6856ef80706SPavel Hofman 	struct qtet_kcontrol_private private =
6866ef80706SPavel Hofman 		qtet_privates[kcontrol->private_value];
6876ef80706SPavel Hofman 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
6886ef80706SPavel Hofman 	ucontrol->value.integer.value[0] =
6896ef80706SPavel Hofman 		(private.get_register(ice) & private.bit) ? 1 : 0;
6906ef80706SPavel Hofman 	return 0;
6916ef80706SPavel Hofman }
6926ef80706SPavel Hofman 
qtet_sw_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)6936ef80706SPavel Hofman static int qtet_sw_put(struct snd_kcontrol *kcontrol,
6946ef80706SPavel Hofman 		struct snd_ctl_elem_value *ucontrol)
6956ef80706SPavel Hofman {
6966ef80706SPavel Hofman 	struct qtet_kcontrol_private private =
6976ef80706SPavel Hofman 		qtet_privates[kcontrol->private_value];
6986ef80706SPavel Hofman 	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
6996ef80706SPavel Hofman 	unsigned int old, new;
7006ef80706SPavel Hofman 	old = private.get_register(ice);
7016ef80706SPavel Hofman 	if (ucontrol->value.integer.value[0])
7026ef80706SPavel Hofman 		new = old | private.bit;
7036ef80706SPavel Hofman 	else
7046ef80706SPavel Hofman 		new = old & ~private.bit;
7056ef80706SPavel Hofman 	if (old != new) {
7066ef80706SPavel Hofman 		private.set_register(ice, new);
7076ef80706SPavel Hofman 		return 1;
7086ef80706SPavel Hofman 	}
7096ef80706SPavel Hofman 	/* no change */
7106ef80706SPavel Hofman 	return 0;
7116ef80706SPavel Hofman }
7126ef80706SPavel Hofman 
7136ef80706SPavel Hofman #define qtet_sw_info	snd_ctl_boolean_mono_info
7146ef80706SPavel Hofman 
7156ef80706SPavel Hofman #define QTET_CONTROL(xname, xtype, xpriv)	\
7166ef80706SPavel Hofman 	{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,\
7176ef80706SPavel Hofman 	.name = xname,\
7186ef80706SPavel Hofman 	.info = qtet_##xtype##_info,\
7196ef80706SPavel Hofman 	.get = qtet_sw_get,\
7206ef80706SPavel Hofman 	.put = qtet_sw_put,\
7216ef80706SPavel Hofman 	.private_value = xpriv }
7226ef80706SPavel Hofman 
723b4e5e707STakashi Iwai static const struct snd_kcontrol_new qtet_controls[] = {
7246ef80706SPavel Hofman 	{
7256ef80706SPavel Hofman 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7266ef80706SPavel Hofman 		.name = "Master Playback Switch",
7276ef80706SPavel Hofman 		.info = qtet_sw_info,
7286ef80706SPavel Hofman 		.get = qtet_mute_get,
7296ef80706SPavel Hofman 		.put = qtet_mute_put,
7306ef80706SPavel Hofman 		.private_value = 0
7316ef80706SPavel Hofman 	},
7326ef80706SPavel Hofman 	{
7336ef80706SPavel Hofman 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7346ef80706SPavel Hofman 		.name = "Phantom Power",
7356ef80706SPavel Hofman 		.info = qtet_sw_info,
7366ef80706SPavel Hofman 		.get = qtet_php_get,
7376ef80706SPavel Hofman 		.put = qtet_php_put,
7386ef80706SPavel Hofman 		.private_value = 0
7396ef80706SPavel Hofman 	},
7406ef80706SPavel Hofman 	{
7416ef80706SPavel Hofman 		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
7426ef80706SPavel Hofman 		.name = "Analog In 1/2 Capture Switch",
7436ef80706SPavel Hofman 		.info = qtet_ain12_enum_info,
7446ef80706SPavel Hofman 		.get = qtet_ain12_sw_get,
7456ef80706SPavel Hofman 		.put = qtet_ain12_sw_put,
7466ef80706SPavel Hofman 		.private_value = 0
7476ef80706SPavel Hofman 	},
7486ef80706SPavel Hofman 	QTET_CONTROL("Analog In 3/4 Capture Switch", enum, AIN34_SEL),
7496ef80706SPavel Hofman 	QTET_CONTROL("PCM In 1/2 Capture Switch", enum, IN12_SEL),
7506ef80706SPavel Hofman 	QTET_CONTROL("PCM In 3/4 Capture Switch", enum, IN34_SEL),
7516ef80706SPavel Hofman 	QTET_CONTROL("Coax Output Source", enum, COAX_OUT),
7526ef80706SPavel Hofman 	QTET_CONTROL("Analog In 1/2 to Monitor 1/2", sw, IN12_MON12),
7536ef80706SPavel Hofman 	QTET_CONTROL("Analog In 1/2 to Monitor 3/4", sw, IN12_MON34),
7546ef80706SPavel Hofman 	QTET_CONTROL("Analog In 3/4 to Monitor 1/2", sw, IN34_MON12),
7556ef80706SPavel Hofman 	QTET_CONTROL("Analog In 3/4 to Monitor 3/4", sw, IN34_MON34),
7566ef80706SPavel Hofman 	QTET_CONTROL("Output 1/2 to Monitor 3/4", sw, OUT12_MON34),
7576ef80706SPavel Hofman 	QTET_CONTROL("Output 3/4 to Monitor 1/2", sw, OUT34_MON12),
7586ef80706SPavel Hofman };
7596ef80706SPavel Hofman 
7609ab0cb30STakashi Iwai static const char * const follower_vols[] = {
7616ef80706SPavel Hofman 	PCM_12_PLAYBACK_VOLUME,
7626ef80706SPavel Hofman 	PCM_34_PLAYBACK_VOLUME,
7636ef80706SPavel Hofman 	NULL
7646ef80706SPavel Hofman };
7656ef80706SPavel Hofman 
766e23e7a14SBill Pemberton static
7676ef80706SPavel Hofman DECLARE_TLV_DB_SCALE(qtet_master_db_scale, -6350, 50, 1);
7686ef80706SPavel Hofman 
qtet_add_controls(struct snd_ice1712 * ice)769e23e7a14SBill Pemberton static int qtet_add_controls(struct snd_ice1712 *ice)
7706ef80706SPavel Hofman {
7716ef80706SPavel Hofman 	struct qtet_spec *spec = ice->spec;
7726ef80706SPavel Hofman 	int err, i;
7736ef80706SPavel Hofman 	struct snd_kcontrol *vmaster;
7746ef80706SPavel Hofman 	err = snd_ice1712_akm4xxx_build_controls(ice);
7756ef80706SPavel Hofman 	if (err < 0)
7766ef80706SPavel Hofman 		return err;
7776ef80706SPavel Hofman 	for (i = 0; i < ARRAY_SIZE(qtet_controls); i++) {
7786ef80706SPavel Hofman 		err = snd_ctl_add(ice->card,
7796ef80706SPavel Hofman 				snd_ctl_new1(&qtet_controls[i], ice));
7806ef80706SPavel Hofman 		if (err < 0)
7816ef80706SPavel Hofman 			return err;
7826ef80706SPavel Hofman 	}
7836ef80706SPavel Hofman 
7846ef80706SPavel Hofman 	/* Create virtual master control */
7856ef80706SPavel Hofman 	vmaster = snd_ctl_make_virtual_master("Master Playback Volume",
7866ef80706SPavel Hofman 			qtet_master_db_scale);
7876ef80706SPavel Hofman 	if (!vmaster)
7886ef80706SPavel Hofman 		return -ENOMEM;
7896ef80706SPavel Hofman 	err = snd_ctl_add(ice->card, vmaster);
7906ef80706SPavel Hofman 	if (err < 0)
7916ef80706SPavel Hofman 		return err;
792*157ac570STakashi Iwai 	err = snd_ctl_add_followers(ice->card, vmaster, follower_vols);
793*157ac570STakashi Iwai 	if (err < 0)
794*157ac570STakashi Iwai 		return err;
7956ef80706SPavel Hofman 	/* only capture SPDIF over AK4113 */
796387417b5SSudip Mukherjee 	return snd_ak4113_build(spec->ak4113,
7976ef80706SPavel Hofman 			ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
7986ef80706SPavel Hofman }
7996ef80706SPavel Hofman 
qtet_is_spdif_master(struct snd_ice1712 * ice)8006ef80706SPavel Hofman static inline int qtet_is_spdif_master(struct snd_ice1712 *ice)
8016ef80706SPavel Hofman {
8026ef80706SPavel Hofman 	/* CPLD_SYNC_SEL: 0 = internal, 1 = external (i.e. spdif master) */
8036ef80706SPavel Hofman 	return (get_cpld(ice) & CPLD_SYNC_SEL) ? 1 : 0;
8046ef80706SPavel Hofman }
8056ef80706SPavel Hofman 
qtet_get_rate(struct snd_ice1712 * ice)8066ef80706SPavel Hofman static unsigned int qtet_get_rate(struct snd_ice1712 *ice)
8076ef80706SPavel Hofman {
8086ef80706SPavel Hofman 	int i;
8096ef80706SPavel Hofman 	unsigned char result;
8106ef80706SPavel Hofman 
8116ef80706SPavel Hofman 	result =  get_cpld(ice) & CPLD_CKS_MASK;
8126ef80706SPavel Hofman 	for (i = 0; i < ARRAY_SIZE(cks_vals); i++)
8136ef80706SPavel Hofman 		if (cks_vals[i] == result)
8146ef80706SPavel Hofman 			return qtet_rates[i];
8156ef80706SPavel Hofman 	return 0;
8166ef80706SPavel Hofman }
8176ef80706SPavel Hofman 
get_cks_val(int rate)8186ef80706SPavel Hofman static int get_cks_val(int rate)
8196ef80706SPavel Hofman {
8206ef80706SPavel Hofman 	int i;
8216ef80706SPavel Hofman 	for (i = 0; i < ARRAY_SIZE(qtet_rates); i++)
8226ef80706SPavel Hofman 		if (qtet_rates[i] == rate)
8236ef80706SPavel Hofman 			return cks_vals[i];
8246ef80706SPavel Hofman 	return 0;
8256ef80706SPavel Hofman }
8266ef80706SPavel Hofman 
8276ef80706SPavel Hofman /* setting new rate */
qtet_set_rate(struct snd_ice1712 * ice,unsigned int rate)8286ef80706SPavel Hofman static void qtet_set_rate(struct snd_ice1712 *ice, unsigned int rate)
8296ef80706SPavel Hofman {
8306ef80706SPavel Hofman 	unsigned int new;
8316ef80706SPavel Hofman 	unsigned char val;
8326ef80706SPavel Hofman 	/* switching ice1724 to external clock - supplied by ext. circuits */
8336ef80706SPavel Hofman 	val = inb(ICEMT1724(ice, RATE));
8346ef80706SPavel Hofman 	outb(val | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE));
8356ef80706SPavel Hofman 
8366ef80706SPavel Hofman 	new =  (get_cpld(ice) & ~CPLD_CKS_MASK) | get_cks_val(rate);
8376ef80706SPavel Hofman 	/* switch to internal clock, drop CPLD_SYNC_SEL */
8386ef80706SPavel Hofman 	new &= ~CPLD_SYNC_SEL;
8396dfb5affSTakashi Iwai 	/* dev_dbg(ice->card->dev, "QT - set_rate: old %x, new %x\n",
8406ef80706SPavel Hofman 	   get_cpld(ice), new); */
8416ef80706SPavel Hofman 	set_cpld(ice, new);
8426ef80706SPavel Hofman }
8436ef80706SPavel Hofman 
qtet_set_mclk(struct snd_ice1712 * ice,unsigned int rate)8446ef80706SPavel Hofman static inline unsigned char qtet_set_mclk(struct snd_ice1712 *ice,
8456ef80706SPavel Hofman 		unsigned int rate)
8466ef80706SPavel Hofman {
8476ef80706SPavel Hofman 	/* no change in master clock */
8486ef80706SPavel Hofman 	return 0;
8496ef80706SPavel Hofman }
8506ef80706SPavel Hofman 
8516ef80706SPavel Hofman /* setting clock to external - SPDIF */
qtet_set_spdif_clock(struct snd_ice1712 * ice,int type)8526ef80706SPavel Hofman static int qtet_set_spdif_clock(struct snd_ice1712 *ice, int type)
8536ef80706SPavel Hofman {
8546ef80706SPavel Hofman 	unsigned int old, new;
8556ef80706SPavel Hofman 
8566ef80706SPavel Hofman 	old = new = get_cpld(ice);
8576ef80706SPavel Hofman 	new &= ~(CPLD_CKS_MASK | CPLD_WORD_SEL);
8586ef80706SPavel Hofman 	switch (type) {
8596ef80706SPavel Hofman 	case EXT_SPDIF_TYPE:
8606ef80706SPavel Hofman 		new |= CPLD_EXT_SPDIF;
8616ef80706SPavel Hofman 		break;
8626ef80706SPavel Hofman 	case EXT_WORDCLOCK_1FS_TYPE:
8636ef80706SPavel Hofman 		new |= CPLD_EXT_WORDCLOCK_1FS;
8646ef80706SPavel Hofman 		break;
8656ef80706SPavel Hofman 	case EXT_WORDCLOCK_256FS_TYPE:
8666ef80706SPavel Hofman 		new |= CPLD_EXT_WORDCLOCK_256FS;
8676ef80706SPavel Hofman 		break;
8686ef80706SPavel Hofman 	default:
8696ef80706SPavel Hofman 		snd_BUG();
8706ef80706SPavel Hofman 	}
8716ef80706SPavel Hofman 	if (old != new) {
8726ef80706SPavel Hofman 		set_cpld(ice, new);
8736ef80706SPavel Hofman 		/* changed */
8746ef80706SPavel Hofman 		return 1;
8756ef80706SPavel Hofman 	}
8766ef80706SPavel Hofman 	return 0;
8776ef80706SPavel Hofman }
8786ef80706SPavel Hofman 
qtet_get_spdif_master_type(struct snd_ice1712 * ice)8796ef80706SPavel Hofman static int qtet_get_spdif_master_type(struct snd_ice1712 *ice)
8806ef80706SPavel Hofman {
8816ef80706SPavel Hofman 	unsigned int val;
8826ef80706SPavel Hofman 	int result;
8836ef80706SPavel Hofman 	val = get_cpld(ice);
8846ef80706SPavel Hofman 	/* checking only rate/clock-related bits */
8856ef80706SPavel Hofman 	val &= (CPLD_CKS_MASK | CPLD_WORD_SEL | CPLD_SYNC_SEL);
8866ef80706SPavel Hofman 	if (!(val & CPLD_SYNC_SEL)) {
8876ef80706SPavel Hofman 		/* switched to internal clock, is not any external type */
8886ef80706SPavel Hofman 		result = -1;
8896ef80706SPavel Hofman 	} else {
8906ef80706SPavel Hofman 		switch (val) {
8916ef80706SPavel Hofman 		case (CPLD_EXT_SPDIF):
8926ef80706SPavel Hofman 			result = EXT_SPDIF_TYPE;
8936ef80706SPavel Hofman 			break;
8946ef80706SPavel Hofman 		case (CPLD_EXT_WORDCLOCK_1FS):
8956ef80706SPavel Hofman 			result = EXT_WORDCLOCK_1FS_TYPE;
8966ef80706SPavel Hofman 			break;
8976ef80706SPavel Hofman 		case (CPLD_EXT_WORDCLOCK_256FS):
8986ef80706SPavel Hofman 			result = EXT_WORDCLOCK_256FS_TYPE;
8996ef80706SPavel Hofman 			break;
9006ef80706SPavel Hofman 		default:
9016ef80706SPavel Hofman 			/* undefined combination of external clock setup */
9026ef80706SPavel Hofman 			snd_BUG();
9036ef80706SPavel Hofman 			result = 0;
9046ef80706SPavel Hofman 		}
9056ef80706SPavel Hofman 	}
9066ef80706SPavel Hofman 	return result;
9076ef80706SPavel Hofman }
9086ef80706SPavel Hofman 
9096ef80706SPavel Hofman /* Called when ak4113 detects change in the input SPDIF stream */
qtet_ak4113_change(struct ak4113 * ak4113,unsigned char c0,unsigned char c1)9106ef80706SPavel Hofman static void qtet_ak4113_change(struct ak4113 *ak4113, unsigned char c0,
9116ef80706SPavel Hofman 		unsigned char c1)
9126ef80706SPavel Hofman {
9136ef80706SPavel Hofman 	struct snd_ice1712 *ice = ak4113->change_callback_private;
9146ef80706SPavel Hofman 	int rate;
9156ef80706SPavel Hofman 	if ((qtet_get_spdif_master_type(ice) == EXT_SPDIF_TYPE) &&
9166ef80706SPavel Hofman 			c1) {
9176ef80706SPavel Hofman 		/* only for SPDIF master mode, rate was changed */
9186ef80706SPavel Hofman 		rate = snd_ak4113_external_rate(ak4113);
9196dfb5affSTakashi Iwai 		/* dev_dbg(ice->card->dev, "ak4113 - input rate changed to %d\n",
9206ef80706SPavel Hofman 		   rate); */
9216ef80706SPavel Hofman 		qtet_akm_set_rate_val(ice->akm, rate);
9226ef80706SPavel Hofman 	}
9236ef80706SPavel Hofman }
9246ef80706SPavel Hofman 
9256ef80706SPavel Hofman /*
9266ef80706SPavel Hofman  * If clock slaved to SPDIF-IN, setting runtime rate
9276ef80706SPavel Hofman  * to the detected external rate
9286ef80706SPavel Hofman  */
qtet_spdif_in_open(struct snd_ice1712 * ice,struct snd_pcm_substream * substream)9296ef80706SPavel Hofman static void qtet_spdif_in_open(struct snd_ice1712 *ice,
9306ef80706SPavel Hofman 		struct snd_pcm_substream *substream)
9316ef80706SPavel Hofman {
9326ef80706SPavel Hofman 	struct qtet_spec *spec = ice->spec;
9336ef80706SPavel Hofman 	struct snd_pcm_runtime *runtime = substream->runtime;
9346ef80706SPavel Hofman 	int rate;
9356ef80706SPavel Hofman 
9366ef80706SPavel Hofman 	if (qtet_get_spdif_master_type(ice) != EXT_SPDIF_TYPE)
9376ef80706SPavel Hofman 		/* not external SPDIF, no rate limitation */
9386ef80706SPavel Hofman 		return;
9396ef80706SPavel Hofman 	/* only external SPDIF can detect incoming sample rate */
9406ef80706SPavel Hofman 	rate = snd_ak4113_external_rate(spec->ak4113);
9416ef80706SPavel Hofman 	if (rate >= runtime->hw.rate_min && rate <= runtime->hw.rate_max) {
9426ef80706SPavel Hofman 		runtime->hw.rate_min = rate;
9436ef80706SPavel Hofman 		runtime->hw.rate_max = rate;
9446ef80706SPavel Hofman 	}
9456ef80706SPavel Hofman }
9466ef80706SPavel Hofman 
9476ef80706SPavel Hofman /*
9486ef80706SPavel Hofman  * initialize the chip
9496ef80706SPavel Hofman  */
qtet_init(struct snd_ice1712 * ice)950e23e7a14SBill Pemberton static int qtet_init(struct snd_ice1712 *ice)
9516ef80706SPavel Hofman {
9526ef80706SPavel Hofman 	static const unsigned char ak4113_init_vals[] = {
9536ef80706SPavel Hofman 		/* AK4113_REG_PWRDN */	AK4113_RST | AK4113_PWN |
9546ef80706SPavel Hofman 			AK4113_OCKS0 | AK4113_OCKS1,
9556ef80706SPavel Hofman 		/* AK4113_REQ_FORMAT */	AK4113_DIF_I24I2S | AK4113_VTX |
9566ef80706SPavel Hofman 			AK4113_DEM_OFF | AK4113_DEAU,
9576ef80706SPavel Hofman 		/* AK4113_REG_IO0 */	AK4113_OPS2 | AK4113_TXE |
9586ef80706SPavel Hofman 			AK4113_XTL_24_576M,
9596ef80706SPavel Hofman 		/* AK4113_REG_IO1 */	AK4113_EFH_1024LRCLK | AK4113_IPS(0),
9606ef80706SPavel Hofman 		/* AK4113_REG_INT0_MASK */	0,
9616ef80706SPavel Hofman 		/* AK4113_REG_INT1_MASK */	0,
9626ef80706SPavel Hofman 		/* AK4113_REG_DATDTS */		0,
9636ef80706SPavel Hofman 	};
9646ef80706SPavel Hofman 	int err;
9656ef80706SPavel Hofman 	struct qtet_spec *spec;
9666ef80706SPavel Hofman 	struct snd_akm4xxx *ak;
9676ef80706SPavel Hofman 	unsigned char val;
9686ef80706SPavel Hofman 
9696ef80706SPavel Hofman 	/* switching ice1724 to external clock - supplied by ext. circuits */
9706ef80706SPavel Hofman 	val = inb(ICEMT1724(ice, RATE));
9716ef80706SPavel Hofman 	outb(val | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE));
9726ef80706SPavel Hofman 
9736ef80706SPavel Hofman 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
9746ef80706SPavel Hofman 	if (!spec)
9756ef80706SPavel Hofman 		return -ENOMEM;
9766ef80706SPavel Hofman 	/* qtet is clocked by Xilinx array */
9776ef80706SPavel Hofman 	ice->hw_rates = &qtet_rates_info;
9786ef80706SPavel Hofman 	ice->is_spdif_master = qtet_is_spdif_master;
9796ef80706SPavel Hofman 	ice->get_rate = qtet_get_rate;
9806ef80706SPavel Hofman 	ice->set_rate = qtet_set_rate;
9816ef80706SPavel Hofman 	ice->set_mclk = qtet_set_mclk;
9826ef80706SPavel Hofman 	ice->set_spdif_clock = qtet_set_spdif_clock;
9836ef80706SPavel Hofman 	ice->get_spdif_master_type = qtet_get_spdif_master_type;
9846ef80706SPavel Hofman 	ice->ext_clock_names = ext_clock_names;
9856ef80706SPavel Hofman 	ice->ext_clock_count = ARRAY_SIZE(ext_clock_names);
9866ef80706SPavel Hofman 	/* since Qtet can detect correct SPDIF-in rate, all streams can be
9876ef80706SPavel Hofman 	 * limited to this specific rate */
9886ef80706SPavel Hofman 	ice->spdif.ops.open = ice->pro_open = qtet_spdif_in_open;
9896ef80706SPavel Hofman 	ice->spec = spec;
9906ef80706SPavel Hofman 
9916ef80706SPavel Hofman 	/* Mute Off */
9926ef80706SPavel Hofman 	/* SCR Initialize*/
9936ef80706SPavel Hofman 	/* keep codec power down first */
9946ef80706SPavel Hofman 	set_scr(ice, SCR_PHP);
9956ef80706SPavel Hofman 	udelay(1);
9966ef80706SPavel Hofman 	/* codec power up */
9976ef80706SPavel Hofman 	set_scr(ice, SCR_PHP | SCR_CODEC_PDN);
9986ef80706SPavel Hofman 
9996ef80706SPavel Hofman 	/* MCR Initialize */
10006ef80706SPavel Hofman 	set_mcr(ice, 0);
10016ef80706SPavel Hofman 
10026ef80706SPavel Hofman 	/* CPLD Initialize */
10036ef80706SPavel Hofman 	set_cpld(ice, 0);
10046ef80706SPavel Hofman 
10056ef80706SPavel Hofman 
10066ef80706SPavel Hofman 	ice->num_total_dacs = 2;
10076ef80706SPavel Hofman 	ice->num_total_adcs = 2;
10086ef80706SPavel Hofman 
10096ef80706SPavel Hofman 	ice->akm = kcalloc(2, sizeof(struct snd_akm4xxx), GFP_KERNEL);
10106ef80706SPavel Hofman 	ak = ice->akm;
10116ef80706SPavel Hofman 	if (!ak)
10126ef80706SPavel Hofman 		return -ENOMEM;
10136ef80706SPavel Hofman 	/* only one codec with two chips */
10146ef80706SPavel Hofman 	ice->akm_codecs = 1;
10156ef80706SPavel Hofman 	err = snd_ice1712_akm4xxx_init(ak, &akm_qtet_dac, NULL, ice);
10166ef80706SPavel Hofman 	if (err < 0)
10176ef80706SPavel Hofman 		return err;
10186ef80706SPavel Hofman 	err = snd_ak4113_create(ice->card,
10196ef80706SPavel Hofman 			qtet_ak4113_read,
10206ef80706SPavel Hofman 			qtet_ak4113_write,
10216ef80706SPavel Hofman 			ak4113_init_vals,
10226ef80706SPavel Hofman 			ice, &spec->ak4113);
10236ef80706SPavel Hofman 	if (err < 0)
10246ef80706SPavel Hofman 		return err;
10256ef80706SPavel Hofman 	/* callback for codecs rate setting */
10266ef80706SPavel Hofman 	spec->ak4113->change_callback = qtet_ak4113_change;
10276ef80706SPavel Hofman 	spec->ak4113->change_callback_private = ice;
10286ef80706SPavel Hofman 	/* AK41143 in Quartet can detect external rate correctly
10296ef80706SPavel Hofman 	 * (i.e. check_flags = 0) */
10306ef80706SPavel Hofman 	spec->ak4113->check_flags = 0;
10316ef80706SPavel Hofman 
10326ef80706SPavel Hofman 	proc_init(ice);
10336ef80706SPavel Hofman 
10346ef80706SPavel Hofman 	qtet_set_rate(ice, 44100);
10356ef80706SPavel Hofman 	return 0;
10366ef80706SPavel Hofman }
10376ef80706SPavel Hofman 
1038f16a4e96STakashi Iwai static const unsigned char qtet_eeprom[] = {
10396ef80706SPavel Hofman 	[ICE_EEP2_SYSCONF]     = 0x28,	/* clock 256(24MHz), mpu401, 1xADC,
10406ef80706SPavel Hofman 					   1xDACs, SPDIF in */
10416ef80706SPavel Hofman 	[ICE_EEP2_ACLINK]      = 0x80,	/* I2S */
10426ef80706SPavel Hofman 	[ICE_EEP2_I2S]         = 0x78,	/* 96k, 24bit, 192k */
10436ef80706SPavel Hofman 	[ICE_EEP2_SPDIF]       = 0xc3,	/* out-en, out-int, in, out-ext */
10446ef80706SPavel Hofman 	[ICE_EEP2_GPIO_DIR]    = 0x00,	/* 0-7 inputs, switched to output
10456ef80706SPavel Hofman 					   only during output operations */
10466ef80706SPavel Hofman 	[ICE_EEP2_GPIO_DIR1]   = 0xff,  /* 8-15 outputs */
10476ef80706SPavel Hofman 	[ICE_EEP2_GPIO_DIR2]   = 0x00,
10486ef80706SPavel Hofman 	[ICE_EEP2_GPIO_MASK]   = 0xff,	/* changed only for OUT operations */
10496ef80706SPavel Hofman 	[ICE_EEP2_GPIO_MASK1]  = 0x00,
10506ef80706SPavel Hofman 	[ICE_EEP2_GPIO_MASK2]  = 0xff,
10516ef80706SPavel Hofman 
10526ef80706SPavel Hofman 	[ICE_EEP2_GPIO_STATE]  = 0x00, /* inputs */
10536ef80706SPavel Hofman 	[ICE_EEP2_GPIO_STATE1] = 0x7d, /* all 1, but GPIO_CPLD_RW
10546ef80706SPavel Hofman 					  and GPIO15 always zero */
10556ef80706SPavel Hofman 	[ICE_EEP2_GPIO_STATE2] = 0x00, /* inputs */
10566ef80706SPavel Hofman };
10576ef80706SPavel Hofman 
10586ef80706SPavel Hofman /* entry point */
1059e23e7a14SBill Pemberton struct snd_ice1712_card_info snd_vt1724_qtet_cards[] = {
10606ef80706SPavel Hofman 	{
10616ef80706SPavel Hofman 		.subvendor = VT1724_SUBDEVICE_QTET,
10626ef80706SPavel Hofman 		.name = "Infrasonic Quartet",
10636ef80706SPavel Hofman 		.model = "quartet",
10646ef80706SPavel Hofman 		.chip_init = qtet_init,
10656ef80706SPavel Hofman 		.build_controls = qtet_add_controls,
10666ef80706SPavel Hofman 		.eeprom_size = sizeof(qtet_eeprom),
10676ef80706SPavel Hofman 		.eeprom_data = qtet_eeprom,
10686ef80706SPavel Hofman 	},
10696ef80706SPavel Hofman 	{ } /* terminator */
10706ef80706SPavel Hofman };
1071