162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *   ALSA driver for ICEnsemble VT1724 (Envy24HT)
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *   Lowlevel functions for Infrasonic Quartet
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *	Copyright (c) 2009 Pavel Hofman <pavel.hofman@ivitera.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/delay.h>
1162306a36Sopenharmony_ci#include <linux/interrupt.h>
1262306a36Sopenharmony_ci#include <linux/init.h>
1362306a36Sopenharmony_ci#include <linux/slab.h>
1462306a36Sopenharmony_ci#include <linux/string.h>
1562306a36Sopenharmony_ci#include <sound/core.h>
1662306a36Sopenharmony_ci#include <sound/tlv.h>
1762306a36Sopenharmony_ci#include <sound/info.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "ice1712.h"
2062306a36Sopenharmony_ci#include "envy24ht.h"
2162306a36Sopenharmony_ci#include <sound/ak4113.h>
2262306a36Sopenharmony_ci#include "quartet.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistruct qtet_spec {
2562306a36Sopenharmony_ci	struct ak4113 *ak4113;
2662306a36Sopenharmony_ci	unsigned int scr;	/* system control register */
2762306a36Sopenharmony_ci	unsigned int mcr;	/* monitoring control register */
2862306a36Sopenharmony_ci	unsigned int cpld;	/* cpld register */
2962306a36Sopenharmony_ci};
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistruct qtet_kcontrol_private {
3262306a36Sopenharmony_ci	unsigned int bit;
3362306a36Sopenharmony_ci	void (*set_register)(struct snd_ice1712 *ice, unsigned int val);
3462306a36Sopenharmony_ci	unsigned int (*get_register)(struct snd_ice1712 *ice);
3562306a36Sopenharmony_ci	const char * const texts[2];
3662306a36Sopenharmony_ci};
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cienum {
3962306a36Sopenharmony_ci	IN12_SEL = 0,
4062306a36Sopenharmony_ci	IN34_SEL,
4162306a36Sopenharmony_ci	AIN34_SEL,
4262306a36Sopenharmony_ci	COAX_OUT,
4362306a36Sopenharmony_ci	IN12_MON12,
4462306a36Sopenharmony_ci	IN12_MON34,
4562306a36Sopenharmony_ci	IN34_MON12,
4662306a36Sopenharmony_ci	IN34_MON34,
4762306a36Sopenharmony_ci	OUT12_MON34,
4862306a36Sopenharmony_ci	OUT34_MON12,
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic const char * const ext_clock_names[3] = {"IEC958 In", "Word Clock 1xFS",
5262306a36Sopenharmony_ci	"Word Clock 256xFS"};
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/* chip address on I2C bus */
5562306a36Sopenharmony_ci#define AK4113_ADDR		0x26	/* S/PDIF receiver */
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/* chip address on SPI bus */
5862306a36Sopenharmony_ci#define AK4620_ADDR		0x02	/* ADC/DAC */
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/*
6262306a36Sopenharmony_ci * GPIO pins
6362306a36Sopenharmony_ci */
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci/* GPIO0 - O - DATA0, def. 0 */
6662306a36Sopenharmony_ci#define GPIO_D0			(1<<0)
6762306a36Sopenharmony_ci/* GPIO1 - I/O - DATA1, Jack Detect Input0 (0:present, 1:missing), def. 1 */
6862306a36Sopenharmony_ci#define GPIO_D1_JACKDTC0	(1<<1)
6962306a36Sopenharmony_ci/* GPIO2 - I/O - DATA2, Jack Detect Input1 (0:present, 1:missing), def. 1 */
7062306a36Sopenharmony_ci#define GPIO_D2_JACKDTC1	(1<<2)
7162306a36Sopenharmony_ci/* GPIO3 - I/O - DATA3, def. 1 */
7262306a36Sopenharmony_ci#define GPIO_D3			(1<<3)
7362306a36Sopenharmony_ci/* GPIO4 - I/O - DATA4, SPI CDTO, def. 1 */
7462306a36Sopenharmony_ci#define GPIO_D4_SPI_CDTO	(1<<4)
7562306a36Sopenharmony_ci/* GPIO5 - I/O - DATA5, SPI CCLK, def. 1 */
7662306a36Sopenharmony_ci#define GPIO_D5_SPI_CCLK	(1<<5)
7762306a36Sopenharmony_ci/* GPIO6 - I/O - DATA6, Cable Detect Input (0:detected, 1:not detected */
7862306a36Sopenharmony_ci#define GPIO_D6_CD		(1<<6)
7962306a36Sopenharmony_ci/* GPIO7 - I/O - DATA7, Device Detect Input (0:detected, 1:not detected */
8062306a36Sopenharmony_ci#define GPIO_D7_DD		(1<<7)
8162306a36Sopenharmony_ci/* GPIO8 - O - CPLD Chip Select, def. 1 */
8262306a36Sopenharmony_ci#define GPIO_CPLD_CSN		(1<<8)
8362306a36Sopenharmony_ci/* GPIO9 - O - CPLD register read/write (0:write, 1:read), def. 0 */
8462306a36Sopenharmony_ci#define GPIO_CPLD_RW		(1<<9)
8562306a36Sopenharmony_ci/* GPIO10 - O - SPI Chip Select for CODEC#0, def. 1 */
8662306a36Sopenharmony_ci#define GPIO_SPI_CSN0		(1<<10)
8762306a36Sopenharmony_ci/* GPIO11 - O - SPI Chip Select for CODEC#1, def. 1 */
8862306a36Sopenharmony_ci#define GPIO_SPI_CSN1		(1<<11)
8962306a36Sopenharmony_ci/* GPIO12 - O - Ex. Register Output Enable (0:enable, 1:disable), def. 1,
9062306a36Sopenharmony_ci * init 0 */
9162306a36Sopenharmony_ci#define GPIO_EX_GPIOE		(1<<12)
9262306a36Sopenharmony_ci/* GPIO13 - O - Ex. Register0 Chip Select for System Control Register,
9362306a36Sopenharmony_ci * def. 1 */
9462306a36Sopenharmony_ci#define GPIO_SCR		(1<<13)
9562306a36Sopenharmony_ci/* GPIO14 - O - Ex. Register1 Chip Select for Monitor Control Register,
9662306a36Sopenharmony_ci * def. 1 */
9762306a36Sopenharmony_ci#define GPIO_MCR		(1<<14)
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci#define GPIO_SPI_ALL		(GPIO_D4_SPI_CDTO | GPIO_D5_SPI_CCLK |\
10062306a36Sopenharmony_ci		GPIO_SPI_CSN0 | GPIO_SPI_CSN1)
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci#define GPIO_DATA_MASK		(GPIO_D0 | GPIO_D1_JACKDTC0 | \
10362306a36Sopenharmony_ci		GPIO_D2_JACKDTC1 | GPIO_D3 | \
10462306a36Sopenharmony_ci		GPIO_D4_SPI_CDTO | GPIO_D5_SPI_CCLK | \
10562306a36Sopenharmony_ci		GPIO_D6_CD | GPIO_D7_DD)
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci/* System Control Register GPIO_SCR data bits */
10862306a36Sopenharmony_ci/* Mic/Line select relay (0:line, 1:mic) */
10962306a36Sopenharmony_ci#define SCR_RELAY		GPIO_D0
11062306a36Sopenharmony_ci/* Phantom power drive control (0:5V, 1:48V) */
11162306a36Sopenharmony_ci#define SCR_PHP_V		GPIO_D1_JACKDTC0
11262306a36Sopenharmony_ci/* H/W mute control (0:Normal, 1:Mute) */
11362306a36Sopenharmony_ci#define SCR_MUTE		GPIO_D2_JACKDTC1
11462306a36Sopenharmony_ci/* Phantom power control (0:Phantom on, 1:off) */
11562306a36Sopenharmony_ci#define SCR_PHP			GPIO_D3
11662306a36Sopenharmony_ci/* Analog input 1/2 Source Select */
11762306a36Sopenharmony_ci#define SCR_AIN12_SEL0		GPIO_D4_SPI_CDTO
11862306a36Sopenharmony_ci#define SCR_AIN12_SEL1		GPIO_D5_SPI_CCLK
11962306a36Sopenharmony_ci/* Analog input 3/4 Source Select (0:line, 1:hi-z) */
12062306a36Sopenharmony_ci#define SCR_AIN34_SEL		GPIO_D6_CD
12162306a36Sopenharmony_ci/* Codec Power Down (0:power down, 1:normal) */
12262306a36Sopenharmony_ci#define SCR_CODEC_PDN		GPIO_D7_DD
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci#define SCR_AIN12_LINE		(0)
12562306a36Sopenharmony_ci#define SCR_AIN12_MIC		(SCR_AIN12_SEL0)
12662306a36Sopenharmony_ci#define SCR_AIN12_LOWCUT	(SCR_AIN12_SEL1 | SCR_AIN12_SEL0)
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci/* Monitor Control Register GPIO_MCR data bits */
12962306a36Sopenharmony_ci/* Input 1/2 to Monitor 1/2 (0:off, 1:on) */
13062306a36Sopenharmony_ci#define MCR_IN12_MON12		GPIO_D0
13162306a36Sopenharmony_ci/* Input 1/2 to Monitor 3/4 (0:off, 1:on) */
13262306a36Sopenharmony_ci#define MCR_IN12_MON34		GPIO_D1_JACKDTC0
13362306a36Sopenharmony_ci/* Input 3/4 to Monitor 1/2 (0:off, 1:on) */
13462306a36Sopenharmony_ci#define MCR_IN34_MON12		GPIO_D2_JACKDTC1
13562306a36Sopenharmony_ci/* Input 3/4 to Monitor 3/4 (0:off, 1:on) */
13662306a36Sopenharmony_ci#define MCR_IN34_MON34		GPIO_D3
13762306a36Sopenharmony_ci/* Output to Monitor 1/2 (0:off, 1:on) */
13862306a36Sopenharmony_ci#define MCR_OUT34_MON12		GPIO_D4_SPI_CDTO
13962306a36Sopenharmony_ci/* Output to Monitor 3/4 (0:off, 1:on) */
14062306a36Sopenharmony_ci#define MCR_OUT12_MON34		GPIO_D5_SPI_CCLK
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/* CPLD Register DATA bits */
14362306a36Sopenharmony_ci/* Clock Rate Select */
14462306a36Sopenharmony_ci#define CPLD_CKS0		GPIO_D0
14562306a36Sopenharmony_ci#define CPLD_CKS1		GPIO_D1_JACKDTC0
14662306a36Sopenharmony_ci#define CPLD_CKS2		GPIO_D2_JACKDTC1
14762306a36Sopenharmony_ci/* Sync Source Select (0:Internal, 1:External) */
14862306a36Sopenharmony_ci#define CPLD_SYNC_SEL		GPIO_D3
14962306a36Sopenharmony_ci/* Word Clock FS Select (0:FS, 1:256FS) */
15062306a36Sopenharmony_ci#define CPLD_WORD_SEL		GPIO_D4_SPI_CDTO
15162306a36Sopenharmony_ci/* Coaxial Output Source (IS-Link) (0:SPDIF, 1:I2S) */
15262306a36Sopenharmony_ci#define CPLD_COAX_OUT		GPIO_D5_SPI_CCLK
15362306a36Sopenharmony_ci/* Input 1/2 Source Select (0:Analog12, 1:An34) */
15462306a36Sopenharmony_ci#define CPLD_IN12_SEL		GPIO_D6_CD
15562306a36Sopenharmony_ci/* Input 3/4 Source Select (0:Analog34, 1:Digital In) */
15662306a36Sopenharmony_ci#define CPLD_IN34_SEL		GPIO_D7_DD
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci/* internal clock (CPLD_SYNC_SEL = 0) options */
15962306a36Sopenharmony_ci#define CPLD_CKS_44100HZ	(0)
16062306a36Sopenharmony_ci#define CPLD_CKS_48000HZ	(CPLD_CKS0)
16162306a36Sopenharmony_ci#define CPLD_CKS_88200HZ	(CPLD_CKS1)
16262306a36Sopenharmony_ci#define CPLD_CKS_96000HZ	(CPLD_CKS1 | CPLD_CKS0)
16362306a36Sopenharmony_ci#define CPLD_CKS_176400HZ	(CPLD_CKS2)
16462306a36Sopenharmony_ci#define CPLD_CKS_192000HZ	(CPLD_CKS2 | CPLD_CKS0)
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci#define CPLD_CKS_MASK		(CPLD_CKS0 | CPLD_CKS1 | CPLD_CKS2)
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci/* external clock (CPLD_SYNC_SEL = 1) options */
16962306a36Sopenharmony_ci/* external clock - SPDIF */
17062306a36Sopenharmony_ci#define CPLD_EXT_SPDIF	(0 | CPLD_SYNC_SEL)
17162306a36Sopenharmony_ci/* external clock - WordClock 1xfs */
17262306a36Sopenharmony_ci#define CPLD_EXT_WORDCLOCK_1FS	(CPLD_CKS1 | CPLD_SYNC_SEL)
17362306a36Sopenharmony_ci/* external clock - WordClock 256xfs */
17462306a36Sopenharmony_ci#define CPLD_EXT_WORDCLOCK_256FS	(CPLD_CKS1 | CPLD_WORD_SEL |\
17562306a36Sopenharmony_ci		CPLD_SYNC_SEL)
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci#define EXT_SPDIF_TYPE			0
17862306a36Sopenharmony_ci#define EXT_WORDCLOCK_1FS_TYPE		1
17962306a36Sopenharmony_ci#define EXT_WORDCLOCK_256FS_TYPE	2
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci#define AK4620_DFS0		(1<<0)
18262306a36Sopenharmony_ci#define AK4620_DFS1		(1<<1)
18362306a36Sopenharmony_ci#define AK4620_CKS0		(1<<2)
18462306a36Sopenharmony_ci#define AK4620_CKS1		(1<<3)
18562306a36Sopenharmony_ci/* Clock and Format Control register */
18662306a36Sopenharmony_ci#define AK4620_DFS_REG		0x02
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci/* Deem and Volume Control register */
18962306a36Sopenharmony_ci#define AK4620_DEEMVOL_REG	0x03
19062306a36Sopenharmony_ci#define AK4620_SMUTE		(1<<7)
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci/*
19362306a36Sopenharmony_ci * Conversion from int value to its binary form. Used for debugging.
19462306a36Sopenharmony_ci * The output buffer must be allocated prior to calling the function.
19562306a36Sopenharmony_ci */
19662306a36Sopenharmony_cistatic char *get_binary(char *buffer, int value)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	int i, j, pos;
19962306a36Sopenharmony_ci	pos = 0;
20062306a36Sopenharmony_ci	for (i = 0; i < 4; ++i) {
20162306a36Sopenharmony_ci		for (j = 0; j < 8; ++j) {
20262306a36Sopenharmony_ci			if (value & (1 << (31-(i*8 + j))))
20362306a36Sopenharmony_ci				buffer[pos] = '1';
20462306a36Sopenharmony_ci			else
20562306a36Sopenharmony_ci				buffer[pos] = '0';
20662306a36Sopenharmony_ci			pos++;
20762306a36Sopenharmony_ci		}
20862306a36Sopenharmony_ci		if (i < 3) {
20962306a36Sopenharmony_ci			buffer[pos] = ' ';
21062306a36Sopenharmony_ci			pos++;
21162306a36Sopenharmony_ci		}
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci	buffer[pos] = '\0';
21462306a36Sopenharmony_ci	return buffer;
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci/*
21862306a36Sopenharmony_ci * Initial setup of the conversion array GPIO <-> rate
21962306a36Sopenharmony_ci */
22062306a36Sopenharmony_cistatic const unsigned int qtet_rates[] = {
22162306a36Sopenharmony_ci	44100, 48000, 88200,
22262306a36Sopenharmony_ci	96000, 176400, 192000,
22362306a36Sopenharmony_ci};
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic const unsigned int cks_vals[] = {
22662306a36Sopenharmony_ci	CPLD_CKS_44100HZ, CPLD_CKS_48000HZ, CPLD_CKS_88200HZ,
22762306a36Sopenharmony_ci	CPLD_CKS_96000HZ, CPLD_CKS_176400HZ, CPLD_CKS_192000HZ,
22862306a36Sopenharmony_ci};
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list qtet_rates_info = {
23162306a36Sopenharmony_ci	.count = ARRAY_SIZE(qtet_rates),
23262306a36Sopenharmony_ci	.list = qtet_rates,
23362306a36Sopenharmony_ci	.mask = 0,
23462306a36Sopenharmony_ci};
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic void qtet_ak4113_write(void *private_data, unsigned char reg,
23762306a36Sopenharmony_ci		unsigned char val)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	snd_vt1724_write_i2c((struct snd_ice1712 *)private_data, AK4113_ADDR,
24062306a36Sopenharmony_ci			reg, val);
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cistatic unsigned char qtet_ak4113_read(void *private_data, unsigned char reg)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	return snd_vt1724_read_i2c((struct snd_ice1712 *)private_data,
24662306a36Sopenharmony_ci			AK4113_ADDR, reg);
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci/*
25162306a36Sopenharmony_ci * AK4620 section
25262306a36Sopenharmony_ci */
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci/*
25562306a36Sopenharmony_ci * Write data to addr register of ak4620
25662306a36Sopenharmony_ci */
25762306a36Sopenharmony_cistatic void qtet_akm_write(struct snd_akm4xxx *ak, int chip,
25862306a36Sopenharmony_ci		unsigned char addr, unsigned char data)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	unsigned int tmp, orig_dir;
26162306a36Sopenharmony_ci	int idx;
26262306a36Sopenharmony_ci	unsigned int addrdata;
26362306a36Sopenharmony_ci	struct snd_ice1712 *ice = ak->private_data[0];
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	if (snd_BUG_ON(chip < 0 || chip >= 4))
26662306a36Sopenharmony_ci		return;
26762306a36Sopenharmony_ci	/*dev_dbg(ice->card->dev, "Writing to AK4620: chip=%d, addr=0x%x,
26862306a36Sopenharmony_ci	  data=0x%x\n", chip, addr, data);*/
26962306a36Sopenharmony_ci	orig_dir = ice->gpio.get_dir(ice);
27062306a36Sopenharmony_ci	ice->gpio.set_dir(ice, orig_dir | GPIO_SPI_ALL);
27162306a36Sopenharmony_ci	/* set mask - only SPI bits */
27262306a36Sopenharmony_ci	ice->gpio.set_mask(ice, ~GPIO_SPI_ALL);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	tmp = ice->gpio.get_data(ice);
27562306a36Sopenharmony_ci	/* high all */
27662306a36Sopenharmony_ci	tmp |= GPIO_SPI_ALL;
27762306a36Sopenharmony_ci	ice->gpio.set_data(ice, tmp);
27862306a36Sopenharmony_ci	udelay(100);
27962306a36Sopenharmony_ci	/* drop chip select */
28062306a36Sopenharmony_ci	if (chip)
28162306a36Sopenharmony_ci		/* CODEC 1 */
28262306a36Sopenharmony_ci		tmp &= ~GPIO_SPI_CSN1;
28362306a36Sopenharmony_ci	else
28462306a36Sopenharmony_ci		tmp &= ~GPIO_SPI_CSN0;
28562306a36Sopenharmony_ci	ice->gpio.set_data(ice, tmp);
28662306a36Sopenharmony_ci	udelay(100);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	/* build I2C address + data byte */
28962306a36Sopenharmony_ci	addrdata = (AK4620_ADDR << 6) | 0x20 | (addr & 0x1f);
29062306a36Sopenharmony_ci	addrdata = (addrdata << 8) | data;
29162306a36Sopenharmony_ci	for (idx = 15; idx >= 0; idx--) {
29262306a36Sopenharmony_ci		/* drop clock */
29362306a36Sopenharmony_ci		tmp &= ~GPIO_D5_SPI_CCLK;
29462306a36Sopenharmony_ci		ice->gpio.set_data(ice, tmp);
29562306a36Sopenharmony_ci		udelay(100);
29662306a36Sopenharmony_ci		/* set data */
29762306a36Sopenharmony_ci		if (addrdata & (1 << idx))
29862306a36Sopenharmony_ci			tmp |= GPIO_D4_SPI_CDTO;
29962306a36Sopenharmony_ci		else
30062306a36Sopenharmony_ci			tmp &= ~GPIO_D4_SPI_CDTO;
30162306a36Sopenharmony_ci		ice->gpio.set_data(ice, tmp);
30262306a36Sopenharmony_ci		udelay(100);
30362306a36Sopenharmony_ci		/* raise clock */
30462306a36Sopenharmony_ci		tmp |= GPIO_D5_SPI_CCLK;
30562306a36Sopenharmony_ci		ice->gpio.set_data(ice, tmp);
30662306a36Sopenharmony_ci		udelay(100);
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci	/* all back to 1 */
30962306a36Sopenharmony_ci	tmp |= GPIO_SPI_ALL;
31062306a36Sopenharmony_ci	ice->gpio.set_data(ice, tmp);
31162306a36Sopenharmony_ci	udelay(100);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	/* return all gpios to non-writable */
31462306a36Sopenharmony_ci	ice->gpio.set_mask(ice, 0xffffff);
31562306a36Sopenharmony_ci	/* restore GPIOs direction */
31662306a36Sopenharmony_ci	ice->gpio.set_dir(ice, orig_dir);
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistatic void qtet_akm_set_regs(struct snd_akm4xxx *ak, unsigned char addr,
32062306a36Sopenharmony_ci		unsigned char mask, unsigned char value)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	unsigned char tmp;
32362306a36Sopenharmony_ci	int chip;
32462306a36Sopenharmony_ci	for (chip = 0; chip < ak->num_chips; chip++) {
32562306a36Sopenharmony_ci		tmp = snd_akm4xxx_get(ak, chip, addr);
32662306a36Sopenharmony_ci		/* clear the bits */
32762306a36Sopenharmony_ci		tmp &= ~mask;
32862306a36Sopenharmony_ci		/* set the new bits */
32962306a36Sopenharmony_ci		tmp |= value;
33062306a36Sopenharmony_ci		snd_akm4xxx_write(ak, chip, addr, tmp);
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci/*
33562306a36Sopenharmony_ci * change the rate of AK4620
33662306a36Sopenharmony_ci */
33762306a36Sopenharmony_cistatic void qtet_akm_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	unsigned char ak4620_dfs;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	if (rate == 0)  /* no hint - S/PDIF input is master or the new spdif
34262306a36Sopenharmony_ci			   input rate undetected, simply return */
34362306a36Sopenharmony_ci		return;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/* adjust DFS on codecs - see datasheet */
34662306a36Sopenharmony_ci	if (rate > 108000)
34762306a36Sopenharmony_ci		ak4620_dfs = AK4620_DFS1 | AK4620_CKS1;
34862306a36Sopenharmony_ci	else if (rate > 54000)
34962306a36Sopenharmony_ci		ak4620_dfs = AK4620_DFS0 | AK4620_CKS0;
35062306a36Sopenharmony_ci	else
35162306a36Sopenharmony_ci		ak4620_dfs = 0;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	/* set new value */
35462306a36Sopenharmony_ci	qtet_akm_set_regs(ak, AK4620_DFS_REG, AK4620_DFS0 | AK4620_DFS1 |
35562306a36Sopenharmony_ci			AK4620_CKS0 | AK4620_CKS1, ak4620_dfs);
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci#define AK_CONTROL(xname, xch)	{ .name = xname, .num_channels = xch }
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci#define PCM_12_PLAYBACK_VOLUME	"PCM 1/2 Playback Volume"
36162306a36Sopenharmony_ci#define PCM_34_PLAYBACK_VOLUME	"PCM 3/4 Playback Volume"
36262306a36Sopenharmony_ci#define PCM_12_CAPTURE_VOLUME	"PCM 1/2 Capture Volume"
36362306a36Sopenharmony_ci#define PCM_34_CAPTURE_VOLUME	"PCM 3/4 Capture Volume"
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_cistatic const struct snd_akm4xxx_dac_channel qtet_dac[] = {
36662306a36Sopenharmony_ci	AK_CONTROL(PCM_12_PLAYBACK_VOLUME, 2),
36762306a36Sopenharmony_ci	AK_CONTROL(PCM_34_PLAYBACK_VOLUME, 2),
36862306a36Sopenharmony_ci};
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_cistatic const struct snd_akm4xxx_adc_channel qtet_adc[] = {
37162306a36Sopenharmony_ci	AK_CONTROL(PCM_12_CAPTURE_VOLUME, 2),
37262306a36Sopenharmony_ci	AK_CONTROL(PCM_34_CAPTURE_VOLUME, 2),
37362306a36Sopenharmony_ci};
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_cistatic const struct snd_akm4xxx akm_qtet_dac = {
37662306a36Sopenharmony_ci	.type = SND_AK4620,
37762306a36Sopenharmony_ci	.num_dacs = 4,	/* DAC1 - Output 12
37862306a36Sopenharmony_ci	*/
37962306a36Sopenharmony_ci	.num_adcs = 4,	/* ADC1 - Input 12
38062306a36Sopenharmony_ci	*/
38162306a36Sopenharmony_ci	.ops = {
38262306a36Sopenharmony_ci		.write = qtet_akm_write,
38362306a36Sopenharmony_ci		.set_rate_val = qtet_akm_set_rate_val,
38462306a36Sopenharmony_ci	},
38562306a36Sopenharmony_ci	.dac_info = qtet_dac,
38662306a36Sopenharmony_ci	.adc_info = qtet_adc,
38762306a36Sopenharmony_ci};
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci/* Communication routines with the CPLD */
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci/* Writes data to external register reg, both reg and data are
39362306a36Sopenharmony_ci * GPIO representations */
39462306a36Sopenharmony_cistatic void reg_write(struct snd_ice1712 *ice, unsigned int reg,
39562306a36Sopenharmony_ci		unsigned int data)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	unsigned int tmp;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	mutex_lock(&ice->gpio_mutex);
40062306a36Sopenharmony_ci	/* set direction of used GPIOs*/
40162306a36Sopenharmony_ci	/* all outputs */
40262306a36Sopenharmony_ci	tmp = 0x00ffff;
40362306a36Sopenharmony_ci	ice->gpio.set_dir(ice, tmp);
40462306a36Sopenharmony_ci	/* mask - writable bits */
40562306a36Sopenharmony_ci	ice->gpio.set_mask(ice, ~(tmp));
40662306a36Sopenharmony_ci	/* write the data */
40762306a36Sopenharmony_ci	tmp = ice->gpio.get_data(ice);
40862306a36Sopenharmony_ci	tmp &= ~GPIO_DATA_MASK;
40962306a36Sopenharmony_ci	tmp |= data;
41062306a36Sopenharmony_ci	ice->gpio.set_data(ice, tmp);
41162306a36Sopenharmony_ci	udelay(100);
41262306a36Sopenharmony_ci	/* drop output enable */
41362306a36Sopenharmony_ci	tmp &=  ~GPIO_EX_GPIOE;
41462306a36Sopenharmony_ci	ice->gpio.set_data(ice, tmp);
41562306a36Sopenharmony_ci	udelay(100);
41662306a36Sopenharmony_ci	/* drop the register gpio */
41762306a36Sopenharmony_ci	tmp &= ~reg;
41862306a36Sopenharmony_ci	ice->gpio.set_data(ice, tmp);
41962306a36Sopenharmony_ci	udelay(100);
42062306a36Sopenharmony_ci	/* raise the register GPIO */
42162306a36Sopenharmony_ci	tmp |= reg;
42262306a36Sopenharmony_ci	ice->gpio.set_data(ice, tmp);
42362306a36Sopenharmony_ci	udelay(100);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	/* raise all data gpios */
42662306a36Sopenharmony_ci	tmp |= GPIO_DATA_MASK;
42762306a36Sopenharmony_ci	ice->gpio.set_data(ice, tmp);
42862306a36Sopenharmony_ci	/* mask - immutable bits */
42962306a36Sopenharmony_ci	ice->gpio.set_mask(ice, 0xffffff);
43062306a36Sopenharmony_ci	/* outputs only 8-15 */
43162306a36Sopenharmony_ci	ice->gpio.set_dir(ice, 0x00ff00);
43262306a36Sopenharmony_ci	mutex_unlock(&ice->gpio_mutex);
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_cistatic unsigned int get_scr(struct snd_ice1712 *ice)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	struct qtet_spec *spec = ice->spec;
43862306a36Sopenharmony_ci	return spec->scr;
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cistatic unsigned int get_mcr(struct snd_ice1712 *ice)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	struct qtet_spec *spec = ice->spec;
44462306a36Sopenharmony_ci	return spec->mcr;
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistatic unsigned int get_cpld(struct snd_ice1712 *ice)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	struct qtet_spec *spec = ice->spec;
45062306a36Sopenharmony_ci	return spec->cpld;
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic void set_scr(struct snd_ice1712 *ice, unsigned int val)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	struct qtet_spec *spec = ice->spec;
45662306a36Sopenharmony_ci	reg_write(ice, GPIO_SCR, val);
45762306a36Sopenharmony_ci	spec->scr = val;
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_cistatic void set_mcr(struct snd_ice1712 *ice, unsigned int val)
46162306a36Sopenharmony_ci{
46262306a36Sopenharmony_ci	struct qtet_spec *spec = ice->spec;
46362306a36Sopenharmony_ci	reg_write(ice, GPIO_MCR, val);
46462306a36Sopenharmony_ci	spec->mcr = val;
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_cistatic void set_cpld(struct snd_ice1712 *ice, unsigned int val)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	struct qtet_spec *spec = ice->spec;
47062306a36Sopenharmony_ci	reg_write(ice, GPIO_CPLD_CSN, val);
47162306a36Sopenharmony_ci	spec->cpld = val;
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_cistatic void proc_regs_read(struct snd_info_entry *entry,
47562306a36Sopenharmony_ci		struct snd_info_buffer *buffer)
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci	struct snd_ice1712 *ice = entry->private_data;
47862306a36Sopenharmony_ci	char bin_buffer[36];
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	snd_iprintf(buffer, "SCR:	%s\n", get_binary(bin_buffer,
48162306a36Sopenharmony_ci				get_scr(ice)));
48262306a36Sopenharmony_ci	snd_iprintf(buffer, "MCR:	%s\n", get_binary(bin_buffer,
48362306a36Sopenharmony_ci				get_mcr(ice)));
48462306a36Sopenharmony_ci	snd_iprintf(buffer, "CPLD:	%s\n", get_binary(bin_buffer,
48562306a36Sopenharmony_ci				get_cpld(ice)));
48662306a36Sopenharmony_ci}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_cistatic void proc_init(struct snd_ice1712 *ice)
48962306a36Sopenharmony_ci{
49062306a36Sopenharmony_ci	snd_card_ro_proc_new(ice->card, "quartet", ice, proc_regs_read);
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic int qtet_mute_get(struct snd_kcontrol *kcontrol,
49462306a36Sopenharmony_ci		struct snd_ctl_elem_value *ucontrol)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
49762306a36Sopenharmony_ci	unsigned int val;
49862306a36Sopenharmony_ci	val = get_scr(ice) & SCR_MUTE;
49962306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = (val) ? 0 : 1;
50062306a36Sopenharmony_ci	return 0;
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_cistatic int qtet_mute_put(struct snd_kcontrol *kcontrol,
50462306a36Sopenharmony_ci		struct snd_ctl_elem_value *ucontrol)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
50762306a36Sopenharmony_ci	unsigned int old, new, smute;
50862306a36Sopenharmony_ci	old = get_scr(ice) & SCR_MUTE;
50962306a36Sopenharmony_ci	if (ucontrol->value.integer.value[0]) {
51062306a36Sopenharmony_ci		/* unmute */
51162306a36Sopenharmony_ci		new = 0;
51262306a36Sopenharmony_ci		/* un-smuting DAC */
51362306a36Sopenharmony_ci		smute = 0;
51462306a36Sopenharmony_ci	} else {
51562306a36Sopenharmony_ci		/* mute */
51662306a36Sopenharmony_ci		new = SCR_MUTE;
51762306a36Sopenharmony_ci		/* smuting DAC */
51862306a36Sopenharmony_ci		smute = AK4620_SMUTE;
51962306a36Sopenharmony_ci	}
52062306a36Sopenharmony_ci	if (old != new) {
52162306a36Sopenharmony_ci		struct snd_akm4xxx *ak = ice->akm;
52262306a36Sopenharmony_ci		set_scr(ice, (get_scr(ice) & ~SCR_MUTE) | new);
52362306a36Sopenharmony_ci		/* set smute */
52462306a36Sopenharmony_ci		qtet_akm_set_regs(ak, AK4620_DEEMVOL_REG, AK4620_SMUTE, smute);
52562306a36Sopenharmony_ci		return 1;
52662306a36Sopenharmony_ci	}
52762306a36Sopenharmony_ci	/* no change */
52862306a36Sopenharmony_ci	return 0;
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic int qtet_ain12_enum_info(struct snd_kcontrol *kcontrol,
53262306a36Sopenharmony_ci		struct snd_ctl_elem_info *uinfo)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	static const char * const texts[3] =
53562306a36Sopenharmony_ci		{"Line In 1/2", "Mic", "Mic + Low-cut"};
53662306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
53762306a36Sopenharmony_ci}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_cistatic int qtet_ain12_sw_get(struct snd_kcontrol *kcontrol,
54062306a36Sopenharmony_ci		struct snd_ctl_elem_value *ucontrol)
54162306a36Sopenharmony_ci{
54262306a36Sopenharmony_ci	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
54362306a36Sopenharmony_ci	unsigned int val, result;
54462306a36Sopenharmony_ci	val = get_scr(ice) & (SCR_AIN12_SEL1 | SCR_AIN12_SEL0);
54562306a36Sopenharmony_ci	switch (val) {
54662306a36Sopenharmony_ci	case SCR_AIN12_LINE:
54762306a36Sopenharmony_ci		result = 0;
54862306a36Sopenharmony_ci		break;
54962306a36Sopenharmony_ci	case SCR_AIN12_MIC:
55062306a36Sopenharmony_ci		result = 1;
55162306a36Sopenharmony_ci		break;
55262306a36Sopenharmony_ci	case SCR_AIN12_LOWCUT:
55362306a36Sopenharmony_ci		result = 2;
55462306a36Sopenharmony_ci		break;
55562306a36Sopenharmony_ci	default:
55662306a36Sopenharmony_ci		/* BUG - no other combinations allowed */
55762306a36Sopenharmony_ci		snd_BUG();
55862306a36Sopenharmony_ci		result = 0;
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = result;
56162306a36Sopenharmony_ci	return 0;
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_cistatic int qtet_ain12_sw_put(struct snd_kcontrol *kcontrol,
56562306a36Sopenharmony_ci		struct snd_ctl_elem_value *ucontrol)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
56862306a36Sopenharmony_ci	unsigned int old, new, tmp, masked_old;
56962306a36Sopenharmony_ci	old = get_scr(ice);
57062306a36Sopenharmony_ci	masked_old = old & (SCR_AIN12_SEL1 | SCR_AIN12_SEL0);
57162306a36Sopenharmony_ci	tmp = ucontrol->value.integer.value[0];
57262306a36Sopenharmony_ci	if (tmp == 2)
57362306a36Sopenharmony_ci		tmp = 3;	/* binary 10 is not supported */
57462306a36Sopenharmony_ci	tmp <<= 4;	/* shifting to SCR_AIN12_SEL0 */
57562306a36Sopenharmony_ci	if (tmp != masked_old) {
57662306a36Sopenharmony_ci		/* change requested */
57762306a36Sopenharmony_ci		switch (tmp) {
57862306a36Sopenharmony_ci		case SCR_AIN12_LINE:
57962306a36Sopenharmony_ci			new = old & ~(SCR_AIN12_SEL1 | SCR_AIN12_SEL0);
58062306a36Sopenharmony_ci			set_scr(ice, new);
58162306a36Sopenharmony_ci			/* turn off relay */
58262306a36Sopenharmony_ci			new &= ~SCR_RELAY;
58362306a36Sopenharmony_ci			set_scr(ice, new);
58462306a36Sopenharmony_ci			break;
58562306a36Sopenharmony_ci		case SCR_AIN12_MIC:
58662306a36Sopenharmony_ci			/* turn on relay */
58762306a36Sopenharmony_ci			new = old | SCR_RELAY;
58862306a36Sopenharmony_ci			set_scr(ice, new);
58962306a36Sopenharmony_ci			new = (new & ~SCR_AIN12_SEL1) | SCR_AIN12_SEL0;
59062306a36Sopenharmony_ci			set_scr(ice, new);
59162306a36Sopenharmony_ci			break;
59262306a36Sopenharmony_ci		case SCR_AIN12_LOWCUT:
59362306a36Sopenharmony_ci			/* turn on relay */
59462306a36Sopenharmony_ci			new = old | SCR_RELAY;
59562306a36Sopenharmony_ci			set_scr(ice, new);
59662306a36Sopenharmony_ci			new |= SCR_AIN12_SEL1 | SCR_AIN12_SEL0;
59762306a36Sopenharmony_ci			set_scr(ice, new);
59862306a36Sopenharmony_ci			break;
59962306a36Sopenharmony_ci		default:
60062306a36Sopenharmony_ci			snd_BUG();
60162306a36Sopenharmony_ci		}
60262306a36Sopenharmony_ci		return 1;
60362306a36Sopenharmony_ci	}
60462306a36Sopenharmony_ci	/* no change */
60562306a36Sopenharmony_ci	return 0;
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_cistatic int qtet_php_get(struct snd_kcontrol *kcontrol,
60962306a36Sopenharmony_ci		struct snd_ctl_elem_value *ucontrol)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
61262306a36Sopenharmony_ci	unsigned int val;
61362306a36Sopenharmony_ci	/* if phantom voltage =48V, phantom on */
61462306a36Sopenharmony_ci	val = get_scr(ice) & SCR_PHP_V;
61562306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = val ? 1 : 0;
61662306a36Sopenharmony_ci	return 0;
61762306a36Sopenharmony_ci}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_cistatic int qtet_php_put(struct snd_kcontrol *kcontrol,
62062306a36Sopenharmony_ci		struct snd_ctl_elem_value *ucontrol)
62162306a36Sopenharmony_ci{
62262306a36Sopenharmony_ci	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
62362306a36Sopenharmony_ci	unsigned int old, new;
62462306a36Sopenharmony_ci	old = new = get_scr(ice);
62562306a36Sopenharmony_ci	if (ucontrol->value.integer.value[0] /* phantom on requested */
62662306a36Sopenharmony_ci			&& (~old & SCR_PHP_V)) /* 0 = voltage 5V */ {
62762306a36Sopenharmony_ci		/* is off, turn on */
62862306a36Sopenharmony_ci		/* turn voltage on first, = 1 */
62962306a36Sopenharmony_ci		new = old | SCR_PHP_V;
63062306a36Sopenharmony_ci		set_scr(ice, new);
63162306a36Sopenharmony_ci		/* turn phantom on, = 0 */
63262306a36Sopenharmony_ci		new &= ~SCR_PHP;
63362306a36Sopenharmony_ci		set_scr(ice, new);
63462306a36Sopenharmony_ci	} else if (!ucontrol->value.integer.value[0] && (old & SCR_PHP_V)) {
63562306a36Sopenharmony_ci		/* phantom off requested and 1 = voltage 48V */
63662306a36Sopenharmony_ci		/* is on, turn off */
63762306a36Sopenharmony_ci		/* turn voltage off first, = 0 */
63862306a36Sopenharmony_ci		new = old & ~SCR_PHP_V;
63962306a36Sopenharmony_ci		set_scr(ice, new);
64062306a36Sopenharmony_ci		/* turn phantom off, = 1 */
64162306a36Sopenharmony_ci		new |= SCR_PHP;
64262306a36Sopenharmony_ci		set_scr(ice, new);
64362306a36Sopenharmony_ci	}
64462306a36Sopenharmony_ci	if (old != new)
64562306a36Sopenharmony_ci		return 1;
64662306a36Sopenharmony_ci	/* no change */
64762306a36Sopenharmony_ci	return 0;
64862306a36Sopenharmony_ci}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci#define PRIV_SW(xid, xbit, xreg)	[xid] = {.bit = xbit,\
65162306a36Sopenharmony_ci	.set_register = set_##xreg,\
65262306a36Sopenharmony_ci	.get_register = get_##xreg, }
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci#define PRIV_ENUM2(xid, xbit, xreg, xtext1, xtext2)	[xid] = {.bit = xbit,\
65662306a36Sopenharmony_ci	.set_register = set_##xreg,\
65762306a36Sopenharmony_ci	.get_register = get_##xreg,\
65862306a36Sopenharmony_ci	.texts = {xtext1, xtext2} }
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_cistatic const struct qtet_kcontrol_private qtet_privates[] = {
66162306a36Sopenharmony_ci	PRIV_ENUM2(IN12_SEL, CPLD_IN12_SEL, cpld, "An In 1/2", "An In 3/4"),
66262306a36Sopenharmony_ci	PRIV_ENUM2(IN34_SEL, CPLD_IN34_SEL, cpld, "An In 3/4", "IEC958 In"),
66362306a36Sopenharmony_ci	PRIV_ENUM2(AIN34_SEL, SCR_AIN34_SEL, scr, "Line In 3/4", "Hi-Z"),
66462306a36Sopenharmony_ci	PRIV_ENUM2(COAX_OUT, CPLD_COAX_OUT, cpld, "IEC958", "I2S"),
66562306a36Sopenharmony_ci	PRIV_SW(IN12_MON12, MCR_IN12_MON12, mcr),
66662306a36Sopenharmony_ci	PRIV_SW(IN12_MON34, MCR_IN12_MON34, mcr),
66762306a36Sopenharmony_ci	PRIV_SW(IN34_MON12, MCR_IN34_MON12, mcr),
66862306a36Sopenharmony_ci	PRIV_SW(IN34_MON34, MCR_IN34_MON34, mcr),
66962306a36Sopenharmony_ci	PRIV_SW(OUT12_MON34, MCR_OUT12_MON34, mcr),
67062306a36Sopenharmony_ci	PRIV_SW(OUT34_MON12, MCR_OUT34_MON12, mcr),
67162306a36Sopenharmony_ci};
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_cistatic int qtet_enum_info(struct snd_kcontrol *kcontrol,
67462306a36Sopenharmony_ci		struct snd_ctl_elem_info *uinfo)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	struct qtet_kcontrol_private private =
67762306a36Sopenharmony_ci		qtet_privates[kcontrol->private_value];
67862306a36Sopenharmony_ci	return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(private.texts),
67962306a36Sopenharmony_ci				 private.texts);
68062306a36Sopenharmony_ci}
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_cistatic int qtet_sw_get(struct snd_kcontrol *kcontrol,
68362306a36Sopenharmony_ci		struct snd_ctl_elem_value *ucontrol)
68462306a36Sopenharmony_ci{
68562306a36Sopenharmony_ci	struct qtet_kcontrol_private private =
68662306a36Sopenharmony_ci		qtet_privates[kcontrol->private_value];
68762306a36Sopenharmony_ci	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
68862306a36Sopenharmony_ci	ucontrol->value.integer.value[0] =
68962306a36Sopenharmony_ci		(private.get_register(ice) & private.bit) ? 1 : 0;
69062306a36Sopenharmony_ci	return 0;
69162306a36Sopenharmony_ci}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_cistatic int qtet_sw_put(struct snd_kcontrol *kcontrol,
69462306a36Sopenharmony_ci		struct snd_ctl_elem_value *ucontrol)
69562306a36Sopenharmony_ci{
69662306a36Sopenharmony_ci	struct qtet_kcontrol_private private =
69762306a36Sopenharmony_ci		qtet_privates[kcontrol->private_value];
69862306a36Sopenharmony_ci	struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
69962306a36Sopenharmony_ci	unsigned int old, new;
70062306a36Sopenharmony_ci	old = private.get_register(ice);
70162306a36Sopenharmony_ci	if (ucontrol->value.integer.value[0])
70262306a36Sopenharmony_ci		new = old | private.bit;
70362306a36Sopenharmony_ci	else
70462306a36Sopenharmony_ci		new = old & ~private.bit;
70562306a36Sopenharmony_ci	if (old != new) {
70662306a36Sopenharmony_ci		private.set_register(ice, new);
70762306a36Sopenharmony_ci		return 1;
70862306a36Sopenharmony_ci	}
70962306a36Sopenharmony_ci	/* no change */
71062306a36Sopenharmony_ci	return 0;
71162306a36Sopenharmony_ci}
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci#define qtet_sw_info	snd_ctl_boolean_mono_info
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci#define QTET_CONTROL(xname, xtype, xpriv)	\
71662306a36Sopenharmony_ci	{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,\
71762306a36Sopenharmony_ci	.name = xname,\
71862306a36Sopenharmony_ci	.info = qtet_##xtype##_info,\
71962306a36Sopenharmony_ci	.get = qtet_sw_get,\
72062306a36Sopenharmony_ci	.put = qtet_sw_put,\
72162306a36Sopenharmony_ci	.private_value = xpriv }
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_cistatic const struct snd_kcontrol_new qtet_controls[] = {
72462306a36Sopenharmony_ci	{
72562306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
72662306a36Sopenharmony_ci		.name = "Master Playback Switch",
72762306a36Sopenharmony_ci		.info = qtet_sw_info,
72862306a36Sopenharmony_ci		.get = qtet_mute_get,
72962306a36Sopenharmony_ci		.put = qtet_mute_put,
73062306a36Sopenharmony_ci		.private_value = 0
73162306a36Sopenharmony_ci	},
73262306a36Sopenharmony_ci	{
73362306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
73462306a36Sopenharmony_ci		.name = "Phantom Power",
73562306a36Sopenharmony_ci		.info = qtet_sw_info,
73662306a36Sopenharmony_ci		.get = qtet_php_get,
73762306a36Sopenharmony_ci		.put = qtet_php_put,
73862306a36Sopenharmony_ci		.private_value = 0
73962306a36Sopenharmony_ci	},
74062306a36Sopenharmony_ci	{
74162306a36Sopenharmony_ci		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
74262306a36Sopenharmony_ci		.name = "Analog In 1/2 Capture Switch",
74362306a36Sopenharmony_ci		.info = qtet_ain12_enum_info,
74462306a36Sopenharmony_ci		.get = qtet_ain12_sw_get,
74562306a36Sopenharmony_ci		.put = qtet_ain12_sw_put,
74662306a36Sopenharmony_ci		.private_value = 0
74762306a36Sopenharmony_ci	},
74862306a36Sopenharmony_ci	QTET_CONTROL("Analog In 3/4 Capture Switch", enum, AIN34_SEL),
74962306a36Sopenharmony_ci	QTET_CONTROL("PCM In 1/2 Capture Switch", enum, IN12_SEL),
75062306a36Sopenharmony_ci	QTET_CONTROL("PCM In 3/4 Capture Switch", enum, IN34_SEL),
75162306a36Sopenharmony_ci	QTET_CONTROL("Coax Output Source", enum, COAX_OUT),
75262306a36Sopenharmony_ci	QTET_CONTROL("Analog In 1/2 to Monitor 1/2", sw, IN12_MON12),
75362306a36Sopenharmony_ci	QTET_CONTROL("Analog In 1/2 to Monitor 3/4", sw, IN12_MON34),
75462306a36Sopenharmony_ci	QTET_CONTROL("Analog In 3/4 to Monitor 1/2", sw, IN34_MON12),
75562306a36Sopenharmony_ci	QTET_CONTROL("Analog In 3/4 to Monitor 3/4", sw, IN34_MON34),
75662306a36Sopenharmony_ci	QTET_CONTROL("Output 1/2 to Monitor 3/4", sw, OUT12_MON34),
75762306a36Sopenharmony_ci	QTET_CONTROL("Output 3/4 to Monitor 1/2", sw, OUT34_MON12),
75862306a36Sopenharmony_ci};
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_cistatic const char * const follower_vols[] = {
76162306a36Sopenharmony_ci	PCM_12_PLAYBACK_VOLUME,
76262306a36Sopenharmony_ci	PCM_34_PLAYBACK_VOLUME,
76362306a36Sopenharmony_ci	NULL
76462306a36Sopenharmony_ci};
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_cistatic
76762306a36Sopenharmony_ciDECLARE_TLV_DB_SCALE(qtet_master_db_scale, -6350, 50, 1);
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_cistatic int qtet_add_controls(struct snd_ice1712 *ice)
77062306a36Sopenharmony_ci{
77162306a36Sopenharmony_ci	struct qtet_spec *spec = ice->spec;
77262306a36Sopenharmony_ci	int err, i;
77362306a36Sopenharmony_ci	struct snd_kcontrol *vmaster;
77462306a36Sopenharmony_ci	err = snd_ice1712_akm4xxx_build_controls(ice);
77562306a36Sopenharmony_ci	if (err < 0)
77662306a36Sopenharmony_ci		return err;
77762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(qtet_controls); i++) {
77862306a36Sopenharmony_ci		err = snd_ctl_add(ice->card,
77962306a36Sopenharmony_ci				snd_ctl_new1(&qtet_controls[i], ice));
78062306a36Sopenharmony_ci		if (err < 0)
78162306a36Sopenharmony_ci			return err;
78262306a36Sopenharmony_ci	}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	/* Create virtual master control */
78562306a36Sopenharmony_ci	vmaster = snd_ctl_make_virtual_master("Master Playback Volume",
78662306a36Sopenharmony_ci			qtet_master_db_scale);
78762306a36Sopenharmony_ci	if (!vmaster)
78862306a36Sopenharmony_ci		return -ENOMEM;
78962306a36Sopenharmony_ci	err = snd_ctl_add(ice->card, vmaster);
79062306a36Sopenharmony_ci	if (err < 0)
79162306a36Sopenharmony_ci		return err;
79262306a36Sopenharmony_ci	err = snd_ctl_add_followers(ice->card, vmaster, follower_vols);
79362306a36Sopenharmony_ci	if (err < 0)
79462306a36Sopenharmony_ci		return err;
79562306a36Sopenharmony_ci	/* only capture SPDIF over AK4113 */
79662306a36Sopenharmony_ci	return snd_ak4113_build(spec->ak4113,
79762306a36Sopenharmony_ci			ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
79862306a36Sopenharmony_ci}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_cistatic inline int qtet_is_spdif_master(struct snd_ice1712 *ice)
80162306a36Sopenharmony_ci{
80262306a36Sopenharmony_ci	/* CPLD_SYNC_SEL: 0 = internal, 1 = external (i.e. spdif master) */
80362306a36Sopenharmony_ci	return (get_cpld(ice) & CPLD_SYNC_SEL) ? 1 : 0;
80462306a36Sopenharmony_ci}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_cistatic unsigned int qtet_get_rate(struct snd_ice1712 *ice)
80762306a36Sopenharmony_ci{
80862306a36Sopenharmony_ci	int i;
80962306a36Sopenharmony_ci	unsigned char result;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	result =  get_cpld(ice) & CPLD_CKS_MASK;
81262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(cks_vals); i++)
81362306a36Sopenharmony_ci		if (cks_vals[i] == result)
81462306a36Sopenharmony_ci			return qtet_rates[i];
81562306a36Sopenharmony_ci	return 0;
81662306a36Sopenharmony_ci}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_cistatic int get_cks_val(int rate)
81962306a36Sopenharmony_ci{
82062306a36Sopenharmony_ci	int i;
82162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(qtet_rates); i++)
82262306a36Sopenharmony_ci		if (qtet_rates[i] == rate)
82362306a36Sopenharmony_ci			return cks_vals[i];
82462306a36Sopenharmony_ci	return 0;
82562306a36Sopenharmony_ci}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci/* setting new rate */
82862306a36Sopenharmony_cistatic void qtet_set_rate(struct snd_ice1712 *ice, unsigned int rate)
82962306a36Sopenharmony_ci{
83062306a36Sopenharmony_ci	unsigned int new;
83162306a36Sopenharmony_ci	unsigned char val;
83262306a36Sopenharmony_ci	/* switching ice1724 to external clock - supplied by ext. circuits */
83362306a36Sopenharmony_ci	val = inb(ICEMT1724(ice, RATE));
83462306a36Sopenharmony_ci	outb(val | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE));
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	new =  (get_cpld(ice) & ~CPLD_CKS_MASK) | get_cks_val(rate);
83762306a36Sopenharmony_ci	/* switch to internal clock, drop CPLD_SYNC_SEL */
83862306a36Sopenharmony_ci	new &= ~CPLD_SYNC_SEL;
83962306a36Sopenharmony_ci	/* dev_dbg(ice->card->dev, "QT - set_rate: old %x, new %x\n",
84062306a36Sopenharmony_ci	   get_cpld(ice), new); */
84162306a36Sopenharmony_ci	set_cpld(ice, new);
84262306a36Sopenharmony_ci}
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_cistatic inline unsigned char qtet_set_mclk(struct snd_ice1712 *ice,
84562306a36Sopenharmony_ci		unsigned int rate)
84662306a36Sopenharmony_ci{
84762306a36Sopenharmony_ci	/* no change in master clock */
84862306a36Sopenharmony_ci	return 0;
84962306a36Sopenharmony_ci}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci/* setting clock to external - SPDIF */
85262306a36Sopenharmony_cistatic int qtet_set_spdif_clock(struct snd_ice1712 *ice, int type)
85362306a36Sopenharmony_ci{
85462306a36Sopenharmony_ci	unsigned int old, new;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	old = new = get_cpld(ice);
85762306a36Sopenharmony_ci	new &= ~(CPLD_CKS_MASK | CPLD_WORD_SEL);
85862306a36Sopenharmony_ci	switch (type) {
85962306a36Sopenharmony_ci	case EXT_SPDIF_TYPE:
86062306a36Sopenharmony_ci		new |= CPLD_EXT_SPDIF;
86162306a36Sopenharmony_ci		break;
86262306a36Sopenharmony_ci	case EXT_WORDCLOCK_1FS_TYPE:
86362306a36Sopenharmony_ci		new |= CPLD_EXT_WORDCLOCK_1FS;
86462306a36Sopenharmony_ci		break;
86562306a36Sopenharmony_ci	case EXT_WORDCLOCK_256FS_TYPE:
86662306a36Sopenharmony_ci		new |= CPLD_EXT_WORDCLOCK_256FS;
86762306a36Sopenharmony_ci		break;
86862306a36Sopenharmony_ci	default:
86962306a36Sopenharmony_ci		snd_BUG();
87062306a36Sopenharmony_ci	}
87162306a36Sopenharmony_ci	if (old != new) {
87262306a36Sopenharmony_ci		set_cpld(ice, new);
87362306a36Sopenharmony_ci		/* changed */
87462306a36Sopenharmony_ci		return 1;
87562306a36Sopenharmony_ci	}
87662306a36Sopenharmony_ci	return 0;
87762306a36Sopenharmony_ci}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_cistatic int qtet_get_spdif_master_type(struct snd_ice1712 *ice)
88062306a36Sopenharmony_ci{
88162306a36Sopenharmony_ci	unsigned int val;
88262306a36Sopenharmony_ci	int result;
88362306a36Sopenharmony_ci	val = get_cpld(ice);
88462306a36Sopenharmony_ci	/* checking only rate/clock-related bits */
88562306a36Sopenharmony_ci	val &= (CPLD_CKS_MASK | CPLD_WORD_SEL | CPLD_SYNC_SEL);
88662306a36Sopenharmony_ci	if (!(val & CPLD_SYNC_SEL)) {
88762306a36Sopenharmony_ci		/* switched to internal clock, is not any external type */
88862306a36Sopenharmony_ci		result = -1;
88962306a36Sopenharmony_ci	} else {
89062306a36Sopenharmony_ci		switch (val) {
89162306a36Sopenharmony_ci		case (CPLD_EXT_SPDIF):
89262306a36Sopenharmony_ci			result = EXT_SPDIF_TYPE;
89362306a36Sopenharmony_ci			break;
89462306a36Sopenharmony_ci		case (CPLD_EXT_WORDCLOCK_1FS):
89562306a36Sopenharmony_ci			result = EXT_WORDCLOCK_1FS_TYPE;
89662306a36Sopenharmony_ci			break;
89762306a36Sopenharmony_ci		case (CPLD_EXT_WORDCLOCK_256FS):
89862306a36Sopenharmony_ci			result = EXT_WORDCLOCK_256FS_TYPE;
89962306a36Sopenharmony_ci			break;
90062306a36Sopenharmony_ci		default:
90162306a36Sopenharmony_ci			/* undefined combination of external clock setup */
90262306a36Sopenharmony_ci			snd_BUG();
90362306a36Sopenharmony_ci			result = 0;
90462306a36Sopenharmony_ci		}
90562306a36Sopenharmony_ci	}
90662306a36Sopenharmony_ci	return result;
90762306a36Sopenharmony_ci}
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci/* Called when ak4113 detects change in the input SPDIF stream */
91062306a36Sopenharmony_cistatic void qtet_ak4113_change(struct ak4113 *ak4113, unsigned char c0,
91162306a36Sopenharmony_ci		unsigned char c1)
91262306a36Sopenharmony_ci{
91362306a36Sopenharmony_ci	struct snd_ice1712 *ice = ak4113->change_callback_private;
91462306a36Sopenharmony_ci	int rate;
91562306a36Sopenharmony_ci	if ((qtet_get_spdif_master_type(ice) == EXT_SPDIF_TYPE) &&
91662306a36Sopenharmony_ci			c1) {
91762306a36Sopenharmony_ci		/* only for SPDIF master mode, rate was changed */
91862306a36Sopenharmony_ci		rate = snd_ak4113_external_rate(ak4113);
91962306a36Sopenharmony_ci		/* dev_dbg(ice->card->dev, "ak4113 - input rate changed to %d\n",
92062306a36Sopenharmony_ci		   rate); */
92162306a36Sopenharmony_ci		qtet_akm_set_rate_val(ice->akm, rate);
92262306a36Sopenharmony_ci	}
92362306a36Sopenharmony_ci}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci/*
92662306a36Sopenharmony_ci * If clock slaved to SPDIF-IN, setting runtime rate
92762306a36Sopenharmony_ci * to the detected external rate
92862306a36Sopenharmony_ci */
92962306a36Sopenharmony_cistatic void qtet_spdif_in_open(struct snd_ice1712 *ice,
93062306a36Sopenharmony_ci		struct snd_pcm_substream *substream)
93162306a36Sopenharmony_ci{
93262306a36Sopenharmony_ci	struct qtet_spec *spec = ice->spec;
93362306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
93462306a36Sopenharmony_ci	int rate;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	if (qtet_get_spdif_master_type(ice) != EXT_SPDIF_TYPE)
93762306a36Sopenharmony_ci		/* not external SPDIF, no rate limitation */
93862306a36Sopenharmony_ci		return;
93962306a36Sopenharmony_ci	/* only external SPDIF can detect incoming sample rate */
94062306a36Sopenharmony_ci	rate = snd_ak4113_external_rate(spec->ak4113);
94162306a36Sopenharmony_ci	if (rate >= runtime->hw.rate_min && rate <= runtime->hw.rate_max) {
94262306a36Sopenharmony_ci		runtime->hw.rate_min = rate;
94362306a36Sopenharmony_ci		runtime->hw.rate_max = rate;
94462306a36Sopenharmony_ci	}
94562306a36Sopenharmony_ci}
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci/*
94862306a36Sopenharmony_ci * initialize the chip
94962306a36Sopenharmony_ci */
95062306a36Sopenharmony_cistatic int qtet_init(struct snd_ice1712 *ice)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	static const unsigned char ak4113_init_vals[] = {
95362306a36Sopenharmony_ci		/* AK4113_REG_PWRDN */	AK4113_RST | AK4113_PWN |
95462306a36Sopenharmony_ci			AK4113_OCKS0 | AK4113_OCKS1,
95562306a36Sopenharmony_ci		/* AK4113_REQ_FORMAT */	AK4113_DIF_I24I2S | AK4113_VTX |
95662306a36Sopenharmony_ci			AK4113_DEM_OFF | AK4113_DEAU,
95762306a36Sopenharmony_ci		/* AK4113_REG_IO0 */	AK4113_OPS2 | AK4113_TXE |
95862306a36Sopenharmony_ci			AK4113_XTL_24_576M,
95962306a36Sopenharmony_ci		/* AK4113_REG_IO1 */	AK4113_EFH_1024LRCLK | AK4113_IPS(0),
96062306a36Sopenharmony_ci		/* AK4113_REG_INT0_MASK */	0,
96162306a36Sopenharmony_ci		/* AK4113_REG_INT1_MASK */	0,
96262306a36Sopenharmony_ci		/* AK4113_REG_DATDTS */		0,
96362306a36Sopenharmony_ci	};
96462306a36Sopenharmony_ci	int err;
96562306a36Sopenharmony_ci	struct qtet_spec *spec;
96662306a36Sopenharmony_ci	struct snd_akm4xxx *ak;
96762306a36Sopenharmony_ci	unsigned char val;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	/* switching ice1724 to external clock - supplied by ext. circuits */
97062306a36Sopenharmony_ci	val = inb(ICEMT1724(ice, RATE));
97162306a36Sopenharmony_ci	outb(val | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE));
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
97462306a36Sopenharmony_ci	if (!spec)
97562306a36Sopenharmony_ci		return -ENOMEM;
97662306a36Sopenharmony_ci	/* qtet is clocked by Xilinx array */
97762306a36Sopenharmony_ci	ice->hw_rates = &qtet_rates_info;
97862306a36Sopenharmony_ci	ice->is_spdif_master = qtet_is_spdif_master;
97962306a36Sopenharmony_ci	ice->get_rate = qtet_get_rate;
98062306a36Sopenharmony_ci	ice->set_rate = qtet_set_rate;
98162306a36Sopenharmony_ci	ice->set_mclk = qtet_set_mclk;
98262306a36Sopenharmony_ci	ice->set_spdif_clock = qtet_set_spdif_clock;
98362306a36Sopenharmony_ci	ice->get_spdif_master_type = qtet_get_spdif_master_type;
98462306a36Sopenharmony_ci	ice->ext_clock_names = ext_clock_names;
98562306a36Sopenharmony_ci	ice->ext_clock_count = ARRAY_SIZE(ext_clock_names);
98662306a36Sopenharmony_ci	/* since Qtet can detect correct SPDIF-in rate, all streams can be
98762306a36Sopenharmony_ci	 * limited to this specific rate */
98862306a36Sopenharmony_ci	ice->spdif.ops.open = ice->pro_open = qtet_spdif_in_open;
98962306a36Sopenharmony_ci	ice->spec = spec;
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	/* Mute Off */
99262306a36Sopenharmony_ci	/* SCR Initialize*/
99362306a36Sopenharmony_ci	/* keep codec power down first */
99462306a36Sopenharmony_ci	set_scr(ice, SCR_PHP);
99562306a36Sopenharmony_ci	udelay(1);
99662306a36Sopenharmony_ci	/* codec power up */
99762306a36Sopenharmony_ci	set_scr(ice, SCR_PHP | SCR_CODEC_PDN);
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	/* MCR Initialize */
100062306a36Sopenharmony_ci	set_mcr(ice, 0);
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	/* CPLD Initialize */
100362306a36Sopenharmony_ci	set_cpld(ice, 0);
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	ice->num_total_dacs = 2;
100762306a36Sopenharmony_ci	ice->num_total_adcs = 2;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	ice->akm = kcalloc(2, sizeof(struct snd_akm4xxx), GFP_KERNEL);
101062306a36Sopenharmony_ci	ak = ice->akm;
101162306a36Sopenharmony_ci	if (!ak)
101262306a36Sopenharmony_ci		return -ENOMEM;
101362306a36Sopenharmony_ci	/* only one codec with two chips */
101462306a36Sopenharmony_ci	ice->akm_codecs = 1;
101562306a36Sopenharmony_ci	err = snd_ice1712_akm4xxx_init(ak, &akm_qtet_dac, NULL, ice);
101662306a36Sopenharmony_ci	if (err < 0)
101762306a36Sopenharmony_ci		return err;
101862306a36Sopenharmony_ci	err = snd_ak4113_create(ice->card,
101962306a36Sopenharmony_ci			qtet_ak4113_read,
102062306a36Sopenharmony_ci			qtet_ak4113_write,
102162306a36Sopenharmony_ci			ak4113_init_vals,
102262306a36Sopenharmony_ci			ice, &spec->ak4113);
102362306a36Sopenharmony_ci	if (err < 0)
102462306a36Sopenharmony_ci		return err;
102562306a36Sopenharmony_ci	/* callback for codecs rate setting */
102662306a36Sopenharmony_ci	spec->ak4113->change_callback = qtet_ak4113_change;
102762306a36Sopenharmony_ci	spec->ak4113->change_callback_private = ice;
102862306a36Sopenharmony_ci	/* AK41143 in Quartet can detect external rate correctly
102962306a36Sopenharmony_ci	 * (i.e. check_flags = 0) */
103062306a36Sopenharmony_ci	spec->ak4113->check_flags = 0;
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	proc_init(ice);
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	qtet_set_rate(ice, 44100);
103562306a36Sopenharmony_ci	return 0;
103662306a36Sopenharmony_ci}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_cistatic const unsigned char qtet_eeprom[] = {
103962306a36Sopenharmony_ci	[ICE_EEP2_SYSCONF]     = 0x28,	/* clock 256(24MHz), mpu401, 1xADC,
104062306a36Sopenharmony_ci					   1xDACs, SPDIF in */
104162306a36Sopenharmony_ci	[ICE_EEP2_ACLINK]      = 0x80,	/* I2S */
104262306a36Sopenharmony_ci	[ICE_EEP2_I2S]         = 0x78,	/* 96k, 24bit, 192k */
104362306a36Sopenharmony_ci	[ICE_EEP2_SPDIF]       = 0xc3,	/* out-en, out-int, in, out-ext */
104462306a36Sopenharmony_ci	[ICE_EEP2_GPIO_DIR]    = 0x00,	/* 0-7 inputs, switched to output
104562306a36Sopenharmony_ci					   only during output operations */
104662306a36Sopenharmony_ci	[ICE_EEP2_GPIO_DIR1]   = 0xff,  /* 8-15 outputs */
104762306a36Sopenharmony_ci	[ICE_EEP2_GPIO_DIR2]   = 0x00,
104862306a36Sopenharmony_ci	[ICE_EEP2_GPIO_MASK]   = 0xff,	/* changed only for OUT operations */
104962306a36Sopenharmony_ci	[ICE_EEP2_GPIO_MASK1]  = 0x00,
105062306a36Sopenharmony_ci	[ICE_EEP2_GPIO_MASK2]  = 0xff,
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	[ICE_EEP2_GPIO_STATE]  = 0x00, /* inputs */
105362306a36Sopenharmony_ci	[ICE_EEP2_GPIO_STATE1] = 0x7d, /* all 1, but GPIO_CPLD_RW
105462306a36Sopenharmony_ci					  and GPIO15 always zero */
105562306a36Sopenharmony_ci	[ICE_EEP2_GPIO_STATE2] = 0x00, /* inputs */
105662306a36Sopenharmony_ci};
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci/* entry point */
105962306a36Sopenharmony_cistruct snd_ice1712_card_info snd_vt1724_qtet_cards[] = {
106062306a36Sopenharmony_ci	{
106162306a36Sopenharmony_ci		.subvendor = VT1724_SUBDEVICE_QTET,
106262306a36Sopenharmony_ci		.name = "Infrasonic Quartet",
106362306a36Sopenharmony_ci		.model = "quartet",
106462306a36Sopenharmony_ci		.chip_init = qtet_init,
106562306a36Sopenharmony_ci		.build_controls = qtet_add_controls,
106662306a36Sopenharmony_ci		.eeprom_size = sizeof(qtet_eeprom),
106762306a36Sopenharmony_ci		.eeprom_data = qtet_eeprom,
106862306a36Sopenharmony_ci	},
106962306a36Sopenharmony_ci	{ } /* terminator */
107062306a36Sopenharmony_ci};
1071