162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *   ALSA driver for ICEnsemble ICE1712 (Envy24)
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *   Lowlevel functions for M-Audio Audiophile 192, Revolution 7.1 and 5.1
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *	Copyright (c) 2003 Takashi Iwai <tiwai@suse.de>
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 <sound/core.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "ice1712.h"
1762306a36Sopenharmony_ci#include "envy24ht.h"
1862306a36Sopenharmony_ci#include "revo.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* a non-standard I2C device for revo51 */
2162306a36Sopenharmony_cistruct revo51_spec {
2262306a36Sopenharmony_ci	struct snd_i2c_device *dev;
2362306a36Sopenharmony_ci	struct snd_pt2258 *pt2258;
2462306a36Sopenharmony_ci	struct ak4114 *ak4114;
2562306a36Sopenharmony_ci};
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic void revo_i2s_mclk_changed(struct snd_ice1712 *ice)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	/* assert PRST# to converters; MT05 bit 7 */
3062306a36Sopenharmony_ci	outb(inb(ICEMT1724(ice, AC97_CMD)) | 0x80, ICEMT1724(ice, AC97_CMD));
3162306a36Sopenharmony_ci	mdelay(5);
3262306a36Sopenharmony_ci	/* deassert PRST# */
3362306a36Sopenharmony_ci	outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD));
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/*
3762306a36Sopenharmony_ci * change the rate of Envy24HT, AK4355 and AK4381
3862306a36Sopenharmony_ci */
3962306a36Sopenharmony_cistatic void revo_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	unsigned char old, tmp, dfs;
4262306a36Sopenharmony_ci	int reg, shift;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	if (rate == 0)	/* no hint - S/PDIF input is master, simply return */
4562306a36Sopenharmony_ci		return;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	/* adjust DFS on codecs */
4862306a36Sopenharmony_ci	if (rate > 96000)
4962306a36Sopenharmony_ci		dfs = 2;
5062306a36Sopenharmony_ci	else if (rate > 48000)
5162306a36Sopenharmony_ci		dfs = 1;
5262306a36Sopenharmony_ci	else
5362306a36Sopenharmony_ci		dfs = 0;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	if (ak->type == SND_AK4355 || ak->type == SND_AK4358) {
5662306a36Sopenharmony_ci		reg = 2;
5762306a36Sopenharmony_ci		shift = 4;
5862306a36Sopenharmony_ci	} else {
5962306a36Sopenharmony_ci		reg = 1;
6062306a36Sopenharmony_ci		shift = 3;
6162306a36Sopenharmony_ci	}
6262306a36Sopenharmony_ci	tmp = snd_akm4xxx_get(ak, 0, reg);
6362306a36Sopenharmony_ci	old = (tmp >> shift) & 0x03;
6462306a36Sopenharmony_ci	if (old == dfs)
6562306a36Sopenharmony_ci		return;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	/* reset DFS */
6862306a36Sopenharmony_ci	snd_akm4xxx_reset(ak, 1);
6962306a36Sopenharmony_ci	tmp = snd_akm4xxx_get(ak, 0, reg);
7062306a36Sopenharmony_ci	tmp &= ~(0x03 << shift);
7162306a36Sopenharmony_ci	tmp |= dfs << shift;
7262306a36Sopenharmony_ci	/* snd_akm4xxx_write(ak, 0, reg, tmp); */
7362306a36Sopenharmony_ci	snd_akm4xxx_set(ak, 0, reg, tmp); /* value is written in reset(0) */
7462306a36Sopenharmony_ci	snd_akm4xxx_reset(ak, 0);
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/*
7862306a36Sopenharmony_ci * I2C access to the PT2258 volume controller on GPIO 6/7 (Revolution 5.1)
7962306a36Sopenharmony_ci */
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic void revo_i2c_start(struct snd_i2c_bus *bus)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	struct snd_ice1712 *ice = bus->private_data;
8462306a36Sopenharmony_ci	snd_ice1712_save_gpio_status(ice);
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic void revo_i2c_stop(struct snd_i2c_bus *bus)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	struct snd_ice1712 *ice = bus->private_data;
9062306a36Sopenharmony_ci	snd_ice1712_restore_gpio_status(ice);
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic void revo_i2c_direction(struct snd_i2c_bus *bus, int clock, int data)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	struct snd_ice1712 *ice = bus->private_data;
9662306a36Sopenharmony_ci	unsigned int mask, val;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	val = 0;
9962306a36Sopenharmony_ci	if (clock)
10062306a36Sopenharmony_ci		val |= VT1724_REVO_I2C_CLOCK;	/* write SCL */
10162306a36Sopenharmony_ci	if (data)
10262306a36Sopenharmony_ci		val |= VT1724_REVO_I2C_DATA;	/* write SDA */
10362306a36Sopenharmony_ci	mask = VT1724_REVO_I2C_CLOCK | VT1724_REVO_I2C_DATA;
10462306a36Sopenharmony_ci	ice->gpio.direction &= ~mask;
10562306a36Sopenharmony_ci	ice->gpio.direction |= val;
10662306a36Sopenharmony_ci	snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
10762306a36Sopenharmony_ci	snd_ice1712_gpio_set_mask(ice, ~mask);
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic void revo_i2c_setlines(struct snd_i2c_bus *bus, int clk, int data)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	struct snd_ice1712 *ice = bus->private_data;
11362306a36Sopenharmony_ci	unsigned int val = 0;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	if (clk)
11662306a36Sopenharmony_ci		val |= VT1724_REVO_I2C_CLOCK;
11762306a36Sopenharmony_ci	if (data)
11862306a36Sopenharmony_ci		val |= VT1724_REVO_I2C_DATA;
11962306a36Sopenharmony_ci	snd_ice1712_gpio_write_bits(ice,
12062306a36Sopenharmony_ci				    VT1724_REVO_I2C_DATA |
12162306a36Sopenharmony_ci				    VT1724_REVO_I2C_CLOCK, val);
12262306a36Sopenharmony_ci	udelay(5);
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic int revo_i2c_getdata(struct snd_i2c_bus *bus, int ack)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	struct snd_ice1712 *ice = bus->private_data;
12862306a36Sopenharmony_ci	int bit;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	if (ack)
13162306a36Sopenharmony_ci		udelay(5);
13262306a36Sopenharmony_ci	bit = snd_ice1712_gpio_read_bits(ice, VT1724_REVO_I2C_DATA) ? 1 : 0;
13362306a36Sopenharmony_ci	return bit;
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic struct snd_i2c_bit_ops revo51_bit_ops = {
13762306a36Sopenharmony_ci	.start = revo_i2c_start,
13862306a36Sopenharmony_ci	.stop = revo_i2c_stop,
13962306a36Sopenharmony_ci	.direction = revo_i2c_direction,
14062306a36Sopenharmony_ci	.setlines = revo_i2c_setlines,
14162306a36Sopenharmony_ci	.getdata = revo_i2c_getdata,
14262306a36Sopenharmony_ci};
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic int revo51_i2c_init(struct snd_ice1712 *ice,
14562306a36Sopenharmony_ci			   struct snd_pt2258 *pt)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	struct revo51_spec *spec;
14862306a36Sopenharmony_ci	int err;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
15162306a36Sopenharmony_ci	if (!spec)
15262306a36Sopenharmony_ci		return -ENOMEM;
15362306a36Sopenharmony_ci	ice->spec = spec;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	/* create the I2C bus */
15662306a36Sopenharmony_ci	err = snd_i2c_bus_create(ice->card, "ICE1724 GPIO6", NULL, &ice->i2c);
15762306a36Sopenharmony_ci	if (err < 0)
15862306a36Sopenharmony_ci		return err;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	ice->i2c->private_data = ice;
16162306a36Sopenharmony_ci	ice->i2c->hw_ops.bit = &revo51_bit_ops;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	/* create the I2C device */
16462306a36Sopenharmony_ci	err = snd_i2c_device_create(ice->i2c, "PT2258", 0x40, &spec->dev);
16562306a36Sopenharmony_ci	if (err < 0)
16662306a36Sopenharmony_ci		return err;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	pt->card = ice->card;
16962306a36Sopenharmony_ci	pt->i2c_bus = ice->i2c;
17062306a36Sopenharmony_ci	pt->i2c_dev = spec->dev;
17162306a36Sopenharmony_ci	spec->pt2258 = pt;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	snd_pt2258_reset(pt);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	return 0;
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci/*
17962306a36Sopenharmony_ci * initialize the chips on M-Audio Revolution cards
18062306a36Sopenharmony_ci */
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci#define AK_DAC(xname,xch) { .name = xname, .num_channels = xch }
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic const struct snd_akm4xxx_dac_channel revo71_front[] = {
18562306a36Sopenharmony_ci	{
18662306a36Sopenharmony_ci		.name = "PCM Playback Volume",
18762306a36Sopenharmony_ci		.num_channels = 2,
18862306a36Sopenharmony_ci		/* front channels DAC supports muting */
18962306a36Sopenharmony_ci		.switch_name = "PCM Playback Switch",
19062306a36Sopenharmony_ci	},
19162306a36Sopenharmony_ci};
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic const struct snd_akm4xxx_dac_channel revo71_surround[] = {
19462306a36Sopenharmony_ci	AK_DAC("PCM Center Playback Volume", 1),
19562306a36Sopenharmony_ci	AK_DAC("PCM LFE Playback Volume", 1),
19662306a36Sopenharmony_ci	AK_DAC("PCM Side Playback Volume", 2),
19762306a36Sopenharmony_ci	AK_DAC("PCM Rear Playback Volume", 2),
19862306a36Sopenharmony_ci};
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic const struct snd_akm4xxx_dac_channel revo51_dac[] = {
20162306a36Sopenharmony_ci	AK_DAC("PCM Playback Volume", 2),
20262306a36Sopenharmony_ci	AK_DAC("PCM Center Playback Volume", 1),
20362306a36Sopenharmony_ci	AK_DAC("PCM LFE Playback Volume", 1),
20462306a36Sopenharmony_ci	AK_DAC("PCM Rear Playback Volume", 2),
20562306a36Sopenharmony_ci	AK_DAC("PCM Headphone Volume", 2),
20662306a36Sopenharmony_ci};
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic const char *revo51_adc_input_names[] = {
20962306a36Sopenharmony_ci	"Mic",
21062306a36Sopenharmony_ci	"Line",
21162306a36Sopenharmony_ci	"CD",
21262306a36Sopenharmony_ci	NULL
21362306a36Sopenharmony_ci};
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic const struct snd_akm4xxx_adc_channel revo51_adc[] = {
21662306a36Sopenharmony_ci	{
21762306a36Sopenharmony_ci		.name = "PCM Capture Volume",
21862306a36Sopenharmony_ci		.switch_name = "PCM Capture Switch",
21962306a36Sopenharmony_ci		.num_channels = 2,
22062306a36Sopenharmony_ci		.input_names = revo51_adc_input_names
22162306a36Sopenharmony_ci	},
22262306a36Sopenharmony_ci};
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic const struct snd_akm4xxx akm_revo_front = {
22562306a36Sopenharmony_ci	.type = SND_AK4381,
22662306a36Sopenharmony_ci	.num_dacs = 2,
22762306a36Sopenharmony_ci	.ops = {
22862306a36Sopenharmony_ci		.set_rate_val = revo_set_rate_val
22962306a36Sopenharmony_ci	},
23062306a36Sopenharmony_ci	.dac_info = revo71_front,
23162306a36Sopenharmony_ci};
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic const struct snd_ak4xxx_private akm_revo_front_priv = {
23462306a36Sopenharmony_ci	.caddr = 1,
23562306a36Sopenharmony_ci	.cif = 0,
23662306a36Sopenharmony_ci	.data_mask = VT1724_REVO_CDOUT,
23762306a36Sopenharmony_ci	.clk_mask = VT1724_REVO_CCLK,
23862306a36Sopenharmony_ci	.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
23962306a36Sopenharmony_ci	.cs_addr = VT1724_REVO_CS0 | VT1724_REVO_CS2,
24062306a36Sopenharmony_ci	.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
24162306a36Sopenharmony_ci	.add_flags = VT1724_REVO_CCLK, /* high at init */
24262306a36Sopenharmony_ci	.mask_flags = 0,
24362306a36Sopenharmony_ci};
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic const struct snd_akm4xxx akm_revo_surround = {
24662306a36Sopenharmony_ci	.type = SND_AK4355,
24762306a36Sopenharmony_ci	.idx_offset = 1,
24862306a36Sopenharmony_ci	.num_dacs = 6,
24962306a36Sopenharmony_ci	.ops = {
25062306a36Sopenharmony_ci		.set_rate_val = revo_set_rate_val
25162306a36Sopenharmony_ci	},
25262306a36Sopenharmony_ci	.dac_info = revo71_surround,
25362306a36Sopenharmony_ci};
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic const struct snd_ak4xxx_private akm_revo_surround_priv = {
25662306a36Sopenharmony_ci	.caddr = 3,
25762306a36Sopenharmony_ci	.cif = 0,
25862306a36Sopenharmony_ci	.data_mask = VT1724_REVO_CDOUT,
25962306a36Sopenharmony_ci	.clk_mask = VT1724_REVO_CCLK,
26062306a36Sopenharmony_ci	.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
26162306a36Sopenharmony_ci	.cs_addr = VT1724_REVO_CS0 | VT1724_REVO_CS1,
26262306a36Sopenharmony_ci	.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
26362306a36Sopenharmony_ci	.add_flags = VT1724_REVO_CCLK, /* high at init */
26462306a36Sopenharmony_ci	.mask_flags = 0,
26562306a36Sopenharmony_ci};
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic const struct snd_akm4xxx akm_revo51 = {
26862306a36Sopenharmony_ci	.type = SND_AK4358,
26962306a36Sopenharmony_ci	.num_dacs = 8,
27062306a36Sopenharmony_ci	.ops = {
27162306a36Sopenharmony_ci		.set_rate_val = revo_set_rate_val
27262306a36Sopenharmony_ci	},
27362306a36Sopenharmony_ci	.dac_info = revo51_dac,
27462306a36Sopenharmony_ci};
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic const struct snd_ak4xxx_private akm_revo51_priv = {
27762306a36Sopenharmony_ci	.caddr = 2,
27862306a36Sopenharmony_ci	.cif = 0,
27962306a36Sopenharmony_ci	.data_mask = VT1724_REVO_CDOUT,
28062306a36Sopenharmony_ci	.clk_mask = VT1724_REVO_CCLK,
28162306a36Sopenharmony_ci	.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1,
28262306a36Sopenharmony_ci	.cs_addr = VT1724_REVO_CS1,
28362306a36Sopenharmony_ci	.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1,
28462306a36Sopenharmony_ci	.add_flags = VT1724_REVO_CCLK, /* high at init */
28562306a36Sopenharmony_ci	.mask_flags = 0,
28662306a36Sopenharmony_ci};
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic const struct snd_akm4xxx akm_revo51_adc = {
28962306a36Sopenharmony_ci	.type = SND_AK5365,
29062306a36Sopenharmony_ci	.num_adcs = 2,
29162306a36Sopenharmony_ci	.adc_info = revo51_adc,
29262306a36Sopenharmony_ci};
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic const struct snd_ak4xxx_private akm_revo51_adc_priv = {
29562306a36Sopenharmony_ci	.caddr = 2,
29662306a36Sopenharmony_ci	.cif = 0,
29762306a36Sopenharmony_ci	.data_mask = VT1724_REVO_CDOUT,
29862306a36Sopenharmony_ci	.clk_mask = VT1724_REVO_CCLK,
29962306a36Sopenharmony_ci	.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1,
30062306a36Sopenharmony_ci	.cs_addr = VT1724_REVO_CS0,
30162306a36Sopenharmony_ci	.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1,
30262306a36Sopenharmony_ci	.add_flags = VT1724_REVO_CCLK, /* high at init */
30362306a36Sopenharmony_ci	.mask_flags = 0,
30462306a36Sopenharmony_ci};
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic struct snd_pt2258 ptc_revo51_volume;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci/* AK4358 for AP192 DAC, AK5385A for ADC */
30962306a36Sopenharmony_cistatic void ap192_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	struct snd_ice1712 *ice = ak->private_data[0];
31262306a36Sopenharmony_ci	int dfs;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	revo_set_rate_val(ak, rate);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	/* reset CKS */
31762306a36Sopenharmony_ci	snd_ice1712_gpio_write_bits(ice, 1 << 8, rate > 96000 ? 1 << 8 : 0);
31862306a36Sopenharmony_ci	/* reset DFS pins of AK5385A for ADC, too */
31962306a36Sopenharmony_ci	if (rate > 96000)
32062306a36Sopenharmony_ci		dfs = 2;
32162306a36Sopenharmony_ci	else if (rate > 48000)
32262306a36Sopenharmony_ci		dfs = 1;
32362306a36Sopenharmony_ci	else
32462306a36Sopenharmony_ci		dfs = 0;
32562306a36Sopenharmony_ci	snd_ice1712_gpio_write_bits(ice, 3 << 9, dfs << 9);
32662306a36Sopenharmony_ci	/* reset ADC */
32762306a36Sopenharmony_ci	snd_ice1712_gpio_write_bits(ice, 1 << 11, 0);
32862306a36Sopenharmony_ci	snd_ice1712_gpio_write_bits(ice, 1 << 11, 1 << 11);
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic const struct snd_akm4xxx_dac_channel ap192_dac[] = {
33262306a36Sopenharmony_ci	AK_DAC("PCM Playback Volume", 2)
33362306a36Sopenharmony_ci};
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic const struct snd_akm4xxx akm_ap192 = {
33662306a36Sopenharmony_ci	.type = SND_AK4358,
33762306a36Sopenharmony_ci	.num_dacs = 2,
33862306a36Sopenharmony_ci	.ops = {
33962306a36Sopenharmony_ci		.set_rate_val = ap192_set_rate_val
34062306a36Sopenharmony_ci	},
34162306a36Sopenharmony_ci	.dac_info = ap192_dac,
34262306a36Sopenharmony_ci};
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic const struct snd_ak4xxx_private akm_ap192_priv = {
34562306a36Sopenharmony_ci	.caddr = 2,
34662306a36Sopenharmony_ci	.cif = 0,
34762306a36Sopenharmony_ci	.data_mask = VT1724_REVO_CDOUT,
34862306a36Sopenharmony_ci	.clk_mask = VT1724_REVO_CCLK,
34962306a36Sopenharmony_ci	.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS3,
35062306a36Sopenharmony_ci	.cs_addr = VT1724_REVO_CS3,
35162306a36Sopenharmony_ci	.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS3,
35262306a36Sopenharmony_ci	.add_flags = VT1724_REVO_CCLK, /* high at init */
35362306a36Sopenharmony_ci	.mask_flags = 0,
35462306a36Sopenharmony_ci};
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci/* AK4114 support on Audiophile 192 */
35762306a36Sopenharmony_ci/* CDTO (pin 32) -- GPIO2 pin 52
35862306a36Sopenharmony_ci * CDTI (pin 33) -- GPIO3 pin 53 (shared with AK4358)
35962306a36Sopenharmony_ci * CCLK (pin 34) -- GPIO1 pin 51 (shared with AK4358)
36062306a36Sopenharmony_ci * CSN  (pin 35) -- GPIO7 pin 59
36162306a36Sopenharmony_ci */
36262306a36Sopenharmony_ci#define AK4114_ADDR	0x00
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic void write_data(struct snd_ice1712 *ice, unsigned int gpio,
36562306a36Sopenharmony_ci		       unsigned int data, int idx)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	for (; idx >= 0; idx--) {
36862306a36Sopenharmony_ci		/* drop clock */
36962306a36Sopenharmony_ci		gpio &= ~VT1724_REVO_CCLK;
37062306a36Sopenharmony_ci		snd_ice1712_gpio_write(ice, gpio);
37162306a36Sopenharmony_ci		udelay(1);
37262306a36Sopenharmony_ci		/* set data */
37362306a36Sopenharmony_ci		if (data & (1 << idx))
37462306a36Sopenharmony_ci			gpio |= VT1724_REVO_CDOUT;
37562306a36Sopenharmony_ci		else
37662306a36Sopenharmony_ci			gpio &= ~VT1724_REVO_CDOUT;
37762306a36Sopenharmony_ci		snd_ice1712_gpio_write(ice, gpio);
37862306a36Sopenharmony_ci		udelay(1);
37962306a36Sopenharmony_ci		/* raise clock */
38062306a36Sopenharmony_ci		gpio |= VT1724_REVO_CCLK;
38162306a36Sopenharmony_ci		snd_ice1712_gpio_write(ice, gpio);
38262306a36Sopenharmony_ci		udelay(1);
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistatic unsigned char read_data(struct snd_ice1712 *ice, unsigned int gpio,
38762306a36Sopenharmony_ci			       int idx)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	unsigned char data = 0;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	for (; idx >= 0; idx--) {
39262306a36Sopenharmony_ci		/* drop clock */
39362306a36Sopenharmony_ci		gpio &= ~VT1724_REVO_CCLK;
39462306a36Sopenharmony_ci		snd_ice1712_gpio_write(ice, gpio);
39562306a36Sopenharmony_ci		udelay(1);
39662306a36Sopenharmony_ci		/* read data */
39762306a36Sopenharmony_ci		if (snd_ice1712_gpio_read(ice) & VT1724_REVO_CDIN)
39862306a36Sopenharmony_ci			data |= (1 << idx);
39962306a36Sopenharmony_ci		udelay(1);
40062306a36Sopenharmony_ci		/* raise clock */
40162306a36Sopenharmony_ci		gpio |= VT1724_REVO_CCLK;
40262306a36Sopenharmony_ci		snd_ice1712_gpio_write(ice, gpio);
40362306a36Sopenharmony_ci		udelay(1);
40462306a36Sopenharmony_ci	}
40562306a36Sopenharmony_ci	return data;
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cistatic unsigned int ap192_4wire_start(struct snd_ice1712 *ice)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	unsigned int tmp;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	snd_ice1712_save_gpio_status(ice);
41362306a36Sopenharmony_ci	tmp = snd_ice1712_gpio_read(ice);
41462306a36Sopenharmony_ci	tmp |= VT1724_REVO_CCLK; /* high at init */
41562306a36Sopenharmony_ci	tmp |= VT1724_REVO_CS0;
41662306a36Sopenharmony_ci	tmp &= ~VT1724_REVO_CS3;
41762306a36Sopenharmony_ci	snd_ice1712_gpio_write(ice, tmp);
41862306a36Sopenharmony_ci	udelay(1);
41962306a36Sopenharmony_ci	return tmp;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic void ap192_4wire_finish(struct snd_ice1712 *ice, unsigned int tmp)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	tmp |= VT1724_REVO_CS3;
42562306a36Sopenharmony_ci	tmp |= VT1724_REVO_CS0;
42662306a36Sopenharmony_ci	snd_ice1712_gpio_write(ice, tmp);
42762306a36Sopenharmony_ci	udelay(1);
42862306a36Sopenharmony_ci	snd_ice1712_restore_gpio_status(ice);
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_cistatic void ap192_ak4114_write(void *private_data, unsigned char addr,
43262306a36Sopenharmony_ci			       unsigned char data)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	struct snd_ice1712 *ice = private_data;
43562306a36Sopenharmony_ci	unsigned int tmp, addrdata;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	tmp = ap192_4wire_start(ice);
43862306a36Sopenharmony_ci	addrdata = (AK4114_ADDR << 6) | 0x20 | (addr & 0x1f);
43962306a36Sopenharmony_ci	addrdata = (addrdata << 8) | data;
44062306a36Sopenharmony_ci	write_data(ice, tmp, addrdata, 15);
44162306a36Sopenharmony_ci	ap192_4wire_finish(ice, tmp);
44262306a36Sopenharmony_ci}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_cistatic unsigned char ap192_ak4114_read(void *private_data, unsigned char addr)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	struct snd_ice1712 *ice = private_data;
44762306a36Sopenharmony_ci	unsigned int tmp;
44862306a36Sopenharmony_ci	unsigned char data;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	tmp = ap192_4wire_start(ice);
45162306a36Sopenharmony_ci	write_data(ice, tmp, (AK4114_ADDR << 6) | (addr & 0x1f), 7);
45262306a36Sopenharmony_ci	data = read_data(ice, tmp, 7);
45362306a36Sopenharmony_ci	ap192_4wire_finish(ice, tmp);
45462306a36Sopenharmony_ci	return data;
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic int ap192_ak4114_init(struct snd_ice1712 *ice)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	static const unsigned char ak4114_init_vals[] = {
46062306a36Sopenharmony_ci		AK4114_RST | AK4114_PWN | AK4114_OCKS0,
46162306a36Sopenharmony_ci		AK4114_DIF_I24I2S,
46262306a36Sopenharmony_ci		AK4114_TX1E,
46362306a36Sopenharmony_ci		AK4114_EFH_1024 | AK4114_DIT | AK4114_IPS(0),
46462306a36Sopenharmony_ci		0,
46562306a36Sopenharmony_ci		0
46662306a36Sopenharmony_ci	};
46762306a36Sopenharmony_ci	static const unsigned char ak4114_init_txcsb[] = {
46862306a36Sopenharmony_ci		0x41, 0x02, 0x2c, 0x00, 0x00
46962306a36Sopenharmony_ci	};
47062306a36Sopenharmony_ci	int err;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	struct revo51_spec *spec;
47362306a36Sopenharmony_ci	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
47462306a36Sopenharmony_ci	if (!spec)
47562306a36Sopenharmony_ci		return -ENOMEM;
47662306a36Sopenharmony_ci	ice->spec = spec;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	err = snd_ak4114_create(ice->card,
47962306a36Sopenharmony_ci				 ap192_ak4114_read,
48062306a36Sopenharmony_ci				 ap192_ak4114_write,
48162306a36Sopenharmony_ci				 ak4114_init_vals, ak4114_init_txcsb,
48262306a36Sopenharmony_ci				 ice, &spec->ak4114);
48362306a36Sopenharmony_ci	if (err < 0)
48462306a36Sopenharmony_ci		return err;
48562306a36Sopenharmony_ci	/* AK4114 in Revo cannot detect external rate correctly.
48662306a36Sopenharmony_ci	 * No reason to stop capture stream due to incorrect checks */
48762306a36Sopenharmony_ci	spec->ak4114->check_flags = AK4114_CHECK_NO_RATE;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	return 0;
49062306a36Sopenharmony_ci}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_cistatic int revo_init(struct snd_ice1712 *ice)
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci	struct snd_akm4xxx *ak;
49562306a36Sopenharmony_ci	int err;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	/* determine I2C, DACs and ADCs */
49862306a36Sopenharmony_ci	switch (ice->eeprom.subvendor) {
49962306a36Sopenharmony_ci	case VT1724_SUBDEVICE_REVOLUTION71:
50062306a36Sopenharmony_ci		ice->num_total_dacs = 8;
50162306a36Sopenharmony_ci		ice->num_total_adcs = 2;
50262306a36Sopenharmony_ci		ice->gpio.i2s_mclk_changed = revo_i2s_mclk_changed;
50362306a36Sopenharmony_ci		break;
50462306a36Sopenharmony_ci	case VT1724_SUBDEVICE_REVOLUTION51:
50562306a36Sopenharmony_ci		ice->num_total_dacs = 8;
50662306a36Sopenharmony_ci		ice->num_total_adcs = 2;
50762306a36Sopenharmony_ci		break;
50862306a36Sopenharmony_ci	case VT1724_SUBDEVICE_AUDIOPHILE192:
50962306a36Sopenharmony_ci		ice->num_total_dacs = 2;
51062306a36Sopenharmony_ci		ice->num_total_adcs = 2;
51162306a36Sopenharmony_ci		break;
51262306a36Sopenharmony_ci	default:
51362306a36Sopenharmony_ci		snd_BUG();
51462306a36Sopenharmony_ci		return -EINVAL;
51562306a36Sopenharmony_ci	}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	/* second stage of initialization, analog parts and others */
51862306a36Sopenharmony_ci	ak = ice->akm = kcalloc(2, sizeof(struct snd_akm4xxx), GFP_KERNEL);
51962306a36Sopenharmony_ci	if (! ak)
52062306a36Sopenharmony_ci		return -ENOMEM;
52162306a36Sopenharmony_ci	switch (ice->eeprom.subvendor) {
52262306a36Sopenharmony_ci	case VT1724_SUBDEVICE_REVOLUTION71:
52362306a36Sopenharmony_ci		ice->akm_codecs = 2;
52462306a36Sopenharmony_ci		err = snd_ice1712_akm4xxx_init(ak, &akm_revo_front,
52562306a36Sopenharmony_ci						&akm_revo_front_priv, ice);
52662306a36Sopenharmony_ci		if (err < 0)
52762306a36Sopenharmony_ci			return err;
52862306a36Sopenharmony_ci		err = snd_ice1712_akm4xxx_init(ak+1, &akm_revo_surround,
52962306a36Sopenharmony_ci						&akm_revo_surround_priv, ice);
53062306a36Sopenharmony_ci		if (err < 0)
53162306a36Sopenharmony_ci			return err;
53262306a36Sopenharmony_ci		/* unmute all codecs */
53362306a36Sopenharmony_ci		snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE,
53462306a36Sopenharmony_ci						VT1724_REVO_MUTE);
53562306a36Sopenharmony_ci		break;
53662306a36Sopenharmony_ci	case VT1724_SUBDEVICE_REVOLUTION51:
53762306a36Sopenharmony_ci		ice->akm_codecs = 2;
53862306a36Sopenharmony_ci		err = snd_ice1712_akm4xxx_init(ak, &akm_revo51,
53962306a36Sopenharmony_ci					       &akm_revo51_priv, ice);
54062306a36Sopenharmony_ci		if (err < 0)
54162306a36Sopenharmony_ci			return err;
54262306a36Sopenharmony_ci		err = snd_ice1712_akm4xxx_init(ak+1, &akm_revo51_adc,
54362306a36Sopenharmony_ci					       &akm_revo51_adc_priv, ice);
54462306a36Sopenharmony_ci		if (err < 0)
54562306a36Sopenharmony_ci			return err;
54662306a36Sopenharmony_ci		err = revo51_i2c_init(ice, &ptc_revo51_volume);
54762306a36Sopenharmony_ci		if (err < 0)
54862306a36Sopenharmony_ci			return err;
54962306a36Sopenharmony_ci		/* unmute all codecs */
55062306a36Sopenharmony_ci		snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE,
55162306a36Sopenharmony_ci					    VT1724_REVO_MUTE);
55262306a36Sopenharmony_ci		break;
55362306a36Sopenharmony_ci	case VT1724_SUBDEVICE_AUDIOPHILE192:
55462306a36Sopenharmony_ci		ice->akm_codecs = 1;
55562306a36Sopenharmony_ci		err = snd_ice1712_akm4xxx_init(ak, &akm_ap192, &akm_ap192_priv,
55662306a36Sopenharmony_ci					       ice);
55762306a36Sopenharmony_ci		if (err < 0)
55862306a36Sopenharmony_ci			return err;
55962306a36Sopenharmony_ci		err = ap192_ak4114_init(ice);
56062306a36Sopenharmony_ci		if (err < 0)
56162306a36Sopenharmony_ci			return err;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci		/* unmute all codecs */
56462306a36Sopenharmony_ci		snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE,
56562306a36Sopenharmony_ci					    VT1724_REVO_MUTE);
56662306a36Sopenharmony_ci		break;
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	return 0;
57062306a36Sopenharmony_ci}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic int revo_add_controls(struct snd_ice1712 *ice)
57462306a36Sopenharmony_ci{
57562306a36Sopenharmony_ci	struct revo51_spec *spec = ice->spec;
57662306a36Sopenharmony_ci	int err;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	switch (ice->eeprom.subvendor) {
57962306a36Sopenharmony_ci	case VT1724_SUBDEVICE_REVOLUTION71:
58062306a36Sopenharmony_ci		err = snd_ice1712_akm4xxx_build_controls(ice);
58162306a36Sopenharmony_ci		if (err < 0)
58262306a36Sopenharmony_ci			return err;
58362306a36Sopenharmony_ci		break;
58462306a36Sopenharmony_ci	case VT1724_SUBDEVICE_REVOLUTION51:
58562306a36Sopenharmony_ci		err = snd_ice1712_akm4xxx_build_controls(ice);
58662306a36Sopenharmony_ci		if (err < 0)
58762306a36Sopenharmony_ci			return err;
58862306a36Sopenharmony_ci		spec = ice->spec;
58962306a36Sopenharmony_ci		err = snd_pt2258_build_controls(spec->pt2258);
59062306a36Sopenharmony_ci		if (err < 0)
59162306a36Sopenharmony_ci			return err;
59262306a36Sopenharmony_ci		break;
59362306a36Sopenharmony_ci	case VT1724_SUBDEVICE_AUDIOPHILE192:
59462306a36Sopenharmony_ci		err = snd_ice1712_akm4xxx_build_controls(ice);
59562306a36Sopenharmony_ci		if (err < 0)
59662306a36Sopenharmony_ci			return err;
59762306a36Sopenharmony_ci		/* only capture SPDIF over AK4114 */
59862306a36Sopenharmony_ci		err = snd_ak4114_build(spec->ak4114, NULL,
59962306a36Sopenharmony_ci		   ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
60062306a36Sopenharmony_ci		if (err < 0)
60162306a36Sopenharmony_ci			return err;
60262306a36Sopenharmony_ci		break;
60362306a36Sopenharmony_ci	}
60462306a36Sopenharmony_ci	return 0;
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci/* entry point */
60862306a36Sopenharmony_cistruct snd_ice1712_card_info snd_vt1724_revo_cards[] = {
60962306a36Sopenharmony_ci	{
61062306a36Sopenharmony_ci		.subvendor = VT1724_SUBDEVICE_REVOLUTION71,
61162306a36Sopenharmony_ci		.name = "M Audio Revolution-7.1",
61262306a36Sopenharmony_ci		.model = "revo71",
61362306a36Sopenharmony_ci		.chip_init = revo_init,
61462306a36Sopenharmony_ci		.build_controls = revo_add_controls,
61562306a36Sopenharmony_ci	},
61662306a36Sopenharmony_ci	{
61762306a36Sopenharmony_ci		.subvendor = VT1724_SUBDEVICE_REVOLUTION51,
61862306a36Sopenharmony_ci		.name = "M Audio Revolution-5.1",
61962306a36Sopenharmony_ci		.model = "revo51",
62062306a36Sopenharmony_ci		.chip_init = revo_init,
62162306a36Sopenharmony_ci		.build_controls = revo_add_controls,
62262306a36Sopenharmony_ci	},
62362306a36Sopenharmony_ci	{
62462306a36Sopenharmony_ci		.subvendor = VT1724_SUBDEVICE_AUDIOPHILE192,
62562306a36Sopenharmony_ci		.name = "M Audio Audiophile192",
62662306a36Sopenharmony_ci		.model = "ap192",
62762306a36Sopenharmony_ci		.chip_init = revo_init,
62862306a36Sopenharmony_ci		.build_controls = revo_add_controls,
62962306a36Sopenharmony_ci	},
63062306a36Sopenharmony_ci	{ } /* terminator */
63162306a36Sopenharmony_ci};
632