18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *   ALSA driver for ICEnsemble ICE1712 (Envy24)
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *   Lowlevel functions for M-Audio Audiophile 192, Revolution 7.1 and 5.1
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *	Copyright (c) 2003 Takashi Iwai <tiwai@suse.de>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/delay.h>
118c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
128c2ecf20Sopenharmony_ci#include <linux/init.h>
138c2ecf20Sopenharmony_ci#include <linux/slab.h>
148c2ecf20Sopenharmony_ci#include <sound/core.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include "ice1712.h"
178c2ecf20Sopenharmony_ci#include "envy24ht.h"
188c2ecf20Sopenharmony_ci#include "revo.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/* a non-standard I2C device for revo51 */
218c2ecf20Sopenharmony_cistruct revo51_spec {
228c2ecf20Sopenharmony_ci	struct snd_i2c_device *dev;
238c2ecf20Sopenharmony_ci	struct snd_pt2258 *pt2258;
248c2ecf20Sopenharmony_ci	struct ak4114 *ak4114;
258c2ecf20Sopenharmony_ci};
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic void revo_i2s_mclk_changed(struct snd_ice1712 *ice)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	/* assert PRST# to converters; MT05 bit 7 */
308c2ecf20Sopenharmony_ci	outb(inb(ICEMT1724(ice, AC97_CMD)) | 0x80, ICEMT1724(ice, AC97_CMD));
318c2ecf20Sopenharmony_ci	mdelay(5);
328c2ecf20Sopenharmony_ci	/* deassert PRST# */
338c2ecf20Sopenharmony_ci	outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD));
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/*
378c2ecf20Sopenharmony_ci * change the rate of Envy24HT, AK4355 and AK4381
388c2ecf20Sopenharmony_ci */
398c2ecf20Sopenharmony_cistatic void revo_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	unsigned char old, tmp, dfs;
428c2ecf20Sopenharmony_ci	int reg, shift;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	if (rate == 0)	/* no hint - S/PDIF input is master, simply return */
458c2ecf20Sopenharmony_ci		return;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	/* adjust DFS on codecs */
488c2ecf20Sopenharmony_ci	if (rate > 96000)
498c2ecf20Sopenharmony_ci		dfs = 2;
508c2ecf20Sopenharmony_ci	else if (rate > 48000)
518c2ecf20Sopenharmony_ci		dfs = 1;
528c2ecf20Sopenharmony_ci	else
538c2ecf20Sopenharmony_ci		dfs = 0;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	if (ak->type == SND_AK4355 || ak->type == SND_AK4358) {
568c2ecf20Sopenharmony_ci		reg = 2;
578c2ecf20Sopenharmony_ci		shift = 4;
588c2ecf20Sopenharmony_ci	} else {
598c2ecf20Sopenharmony_ci		reg = 1;
608c2ecf20Sopenharmony_ci		shift = 3;
618c2ecf20Sopenharmony_ci	}
628c2ecf20Sopenharmony_ci	tmp = snd_akm4xxx_get(ak, 0, reg);
638c2ecf20Sopenharmony_ci	old = (tmp >> shift) & 0x03;
648c2ecf20Sopenharmony_ci	if (old == dfs)
658c2ecf20Sopenharmony_ci		return;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	/* reset DFS */
688c2ecf20Sopenharmony_ci	snd_akm4xxx_reset(ak, 1);
698c2ecf20Sopenharmony_ci	tmp = snd_akm4xxx_get(ak, 0, reg);
708c2ecf20Sopenharmony_ci	tmp &= ~(0x03 << shift);
718c2ecf20Sopenharmony_ci	tmp |= dfs << shift;
728c2ecf20Sopenharmony_ci	/* snd_akm4xxx_write(ak, 0, reg, tmp); */
738c2ecf20Sopenharmony_ci	snd_akm4xxx_set(ak, 0, reg, tmp); /* value is written in reset(0) */
748c2ecf20Sopenharmony_ci	snd_akm4xxx_reset(ak, 0);
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/*
788c2ecf20Sopenharmony_ci * I2C access to the PT2258 volume controller on GPIO 6/7 (Revolution 5.1)
798c2ecf20Sopenharmony_ci */
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic void revo_i2c_start(struct snd_i2c_bus *bus)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	struct snd_ice1712 *ice = bus->private_data;
848c2ecf20Sopenharmony_ci	snd_ice1712_save_gpio_status(ice);
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic void revo_i2c_stop(struct snd_i2c_bus *bus)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	struct snd_ice1712 *ice = bus->private_data;
908c2ecf20Sopenharmony_ci	snd_ice1712_restore_gpio_status(ice);
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic void revo_i2c_direction(struct snd_i2c_bus *bus, int clock, int data)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	struct snd_ice1712 *ice = bus->private_data;
968c2ecf20Sopenharmony_ci	unsigned int mask, val;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	val = 0;
998c2ecf20Sopenharmony_ci	if (clock)
1008c2ecf20Sopenharmony_ci		val |= VT1724_REVO_I2C_CLOCK;	/* write SCL */
1018c2ecf20Sopenharmony_ci	if (data)
1028c2ecf20Sopenharmony_ci		val |= VT1724_REVO_I2C_DATA;	/* write SDA */
1038c2ecf20Sopenharmony_ci	mask = VT1724_REVO_I2C_CLOCK | VT1724_REVO_I2C_DATA;
1048c2ecf20Sopenharmony_ci	ice->gpio.direction &= ~mask;
1058c2ecf20Sopenharmony_ci	ice->gpio.direction |= val;
1068c2ecf20Sopenharmony_ci	snd_ice1712_gpio_set_dir(ice, ice->gpio.direction);
1078c2ecf20Sopenharmony_ci	snd_ice1712_gpio_set_mask(ice, ~mask);
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic void revo_i2c_setlines(struct snd_i2c_bus *bus, int clk, int data)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	struct snd_ice1712 *ice = bus->private_data;
1138c2ecf20Sopenharmony_ci	unsigned int val = 0;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	if (clk)
1168c2ecf20Sopenharmony_ci		val |= VT1724_REVO_I2C_CLOCK;
1178c2ecf20Sopenharmony_ci	if (data)
1188c2ecf20Sopenharmony_ci		val |= VT1724_REVO_I2C_DATA;
1198c2ecf20Sopenharmony_ci	snd_ice1712_gpio_write_bits(ice,
1208c2ecf20Sopenharmony_ci				    VT1724_REVO_I2C_DATA |
1218c2ecf20Sopenharmony_ci				    VT1724_REVO_I2C_CLOCK, val);
1228c2ecf20Sopenharmony_ci	udelay(5);
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic int revo_i2c_getdata(struct snd_i2c_bus *bus, int ack)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	struct snd_ice1712 *ice = bus->private_data;
1288c2ecf20Sopenharmony_ci	int bit;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	if (ack)
1318c2ecf20Sopenharmony_ci		udelay(5);
1328c2ecf20Sopenharmony_ci	bit = snd_ice1712_gpio_read_bits(ice, VT1724_REVO_I2C_DATA) ? 1 : 0;
1338c2ecf20Sopenharmony_ci	return bit;
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic struct snd_i2c_bit_ops revo51_bit_ops = {
1378c2ecf20Sopenharmony_ci	.start = revo_i2c_start,
1388c2ecf20Sopenharmony_ci	.stop = revo_i2c_stop,
1398c2ecf20Sopenharmony_ci	.direction = revo_i2c_direction,
1408c2ecf20Sopenharmony_ci	.setlines = revo_i2c_setlines,
1418c2ecf20Sopenharmony_ci	.getdata = revo_i2c_getdata,
1428c2ecf20Sopenharmony_ci};
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic int revo51_i2c_init(struct snd_ice1712 *ice,
1458c2ecf20Sopenharmony_ci			   struct snd_pt2258 *pt)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	struct revo51_spec *spec;
1488c2ecf20Sopenharmony_ci	int err;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1518c2ecf20Sopenharmony_ci	if (!spec)
1528c2ecf20Sopenharmony_ci		return -ENOMEM;
1538c2ecf20Sopenharmony_ci	ice->spec = spec;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	/* create the I2C bus */
1568c2ecf20Sopenharmony_ci	err = snd_i2c_bus_create(ice->card, "ICE1724 GPIO6", NULL, &ice->i2c);
1578c2ecf20Sopenharmony_ci	if (err < 0)
1588c2ecf20Sopenharmony_ci		return err;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	ice->i2c->private_data = ice;
1618c2ecf20Sopenharmony_ci	ice->i2c->hw_ops.bit = &revo51_bit_ops;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	/* create the I2C device */
1648c2ecf20Sopenharmony_ci	err = snd_i2c_device_create(ice->i2c, "PT2258", 0x40, &spec->dev);
1658c2ecf20Sopenharmony_ci	if (err < 0)
1668c2ecf20Sopenharmony_ci		return err;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	pt->card = ice->card;
1698c2ecf20Sopenharmony_ci	pt->i2c_bus = ice->i2c;
1708c2ecf20Sopenharmony_ci	pt->i2c_dev = spec->dev;
1718c2ecf20Sopenharmony_ci	spec->pt2258 = pt;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	snd_pt2258_reset(pt);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	return 0;
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci/*
1798c2ecf20Sopenharmony_ci * initialize the chips on M-Audio Revolution cards
1808c2ecf20Sopenharmony_ci */
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci#define AK_DAC(xname,xch) { .name = xname, .num_channels = xch }
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic const struct snd_akm4xxx_dac_channel revo71_front[] = {
1858c2ecf20Sopenharmony_ci	{
1868c2ecf20Sopenharmony_ci		.name = "PCM Playback Volume",
1878c2ecf20Sopenharmony_ci		.num_channels = 2,
1888c2ecf20Sopenharmony_ci		/* front channels DAC supports muting */
1898c2ecf20Sopenharmony_ci		.switch_name = "PCM Playback Switch",
1908c2ecf20Sopenharmony_ci	},
1918c2ecf20Sopenharmony_ci};
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_cistatic const struct snd_akm4xxx_dac_channel revo71_surround[] = {
1948c2ecf20Sopenharmony_ci	AK_DAC("PCM Center Playback Volume", 1),
1958c2ecf20Sopenharmony_ci	AK_DAC("PCM LFE Playback Volume", 1),
1968c2ecf20Sopenharmony_ci	AK_DAC("PCM Side Playback Volume", 2),
1978c2ecf20Sopenharmony_ci	AK_DAC("PCM Rear Playback Volume", 2),
1988c2ecf20Sopenharmony_ci};
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic const struct snd_akm4xxx_dac_channel revo51_dac[] = {
2018c2ecf20Sopenharmony_ci	AK_DAC("PCM Playback Volume", 2),
2028c2ecf20Sopenharmony_ci	AK_DAC("PCM Center Playback Volume", 1),
2038c2ecf20Sopenharmony_ci	AK_DAC("PCM LFE Playback Volume", 1),
2048c2ecf20Sopenharmony_ci	AK_DAC("PCM Rear Playback Volume", 2),
2058c2ecf20Sopenharmony_ci	AK_DAC("PCM Headphone Volume", 2),
2068c2ecf20Sopenharmony_ci};
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic const char *revo51_adc_input_names[] = {
2098c2ecf20Sopenharmony_ci	"Mic",
2108c2ecf20Sopenharmony_ci	"Line",
2118c2ecf20Sopenharmony_ci	"CD",
2128c2ecf20Sopenharmony_ci	NULL
2138c2ecf20Sopenharmony_ci};
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic const struct snd_akm4xxx_adc_channel revo51_adc[] = {
2168c2ecf20Sopenharmony_ci	{
2178c2ecf20Sopenharmony_ci		.name = "PCM Capture Volume",
2188c2ecf20Sopenharmony_ci		.switch_name = "PCM Capture Switch",
2198c2ecf20Sopenharmony_ci		.num_channels = 2,
2208c2ecf20Sopenharmony_ci		.input_names = revo51_adc_input_names
2218c2ecf20Sopenharmony_ci	},
2228c2ecf20Sopenharmony_ci};
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_cistatic const struct snd_akm4xxx akm_revo_front = {
2258c2ecf20Sopenharmony_ci	.type = SND_AK4381,
2268c2ecf20Sopenharmony_ci	.num_dacs = 2,
2278c2ecf20Sopenharmony_ci	.ops = {
2288c2ecf20Sopenharmony_ci		.set_rate_val = revo_set_rate_val
2298c2ecf20Sopenharmony_ci	},
2308c2ecf20Sopenharmony_ci	.dac_info = revo71_front,
2318c2ecf20Sopenharmony_ci};
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_cistatic const struct snd_ak4xxx_private akm_revo_front_priv = {
2348c2ecf20Sopenharmony_ci	.caddr = 1,
2358c2ecf20Sopenharmony_ci	.cif = 0,
2368c2ecf20Sopenharmony_ci	.data_mask = VT1724_REVO_CDOUT,
2378c2ecf20Sopenharmony_ci	.clk_mask = VT1724_REVO_CCLK,
2388c2ecf20Sopenharmony_ci	.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
2398c2ecf20Sopenharmony_ci	.cs_addr = VT1724_REVO_CS0 | VT1724_REVO_CS2,
2408c2ecf20Sopenharmony_ci	.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
2418c2ecf20Sopenharmony_ci	.add_flags = VT1724_REVO_CCLK, /* high at init */
2428c2ecf20Sopenharmony_ci	.mask_flags = 0,
2438c2ecf20Sopenharmony_ci};
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic const struct snd_akm4xxx akm_revo_surround = {
2468c2ecf20Sopenharmony_ci	.type = SND_AK4355,
2478c2ecf20Sopenharmony_ci	.idx_offset = 1,
2488c2ecf20Sopenharmony_ci	.num_dacs = 6,
2498c2ecf20Sopenharmony_ci	.ops = {
2508c2ecf20Sopenharmony_ci		.set_rate_val = revo_set_rate_val
2518c2ecf20Sopenharmony_ci	},
2528c2ecf20Sopenharmony_ci	.dac_info = revo71_surround,
2538c2ecf20Sopenharmony_ci};
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic const struct snd_ak4xxx_private akm_revo_surround_priv = {
2568c2ecf20Sopenharmony_ci	.caddr = 3,
2578c2ecf20Sopenharmony_ci	.cif = 0,
2588c2ecf20Sopenharmony_ci	.data_mask = VT1724_REVO_CDOUT,
2598c2ecf20Sopenharmony_ci	.clk_mask = VT1724_REVO_CCLK,
2608c2ecf20Sopenharmony_ci	.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
2618c2ecf20Sopenharmony_ci	.cs_addr = VT1724_REVO_CS0 | VT1724_REVO_CS1,
2628c2ecf20Sopenharmony_ci	.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2,
2638c2ecf20Sopenharmony_ci	.add_flags = VT1724_REVO_CCLK, /* high at init */
2648c2ecf20Sopenharmony_ci	.mask_flags = 0,
2658c2ecf20Sopenharmony_ci};
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_cistatic const struct snd_akm4xxx akm_revo51 = {
2688c2ecf20Sopenharmony_ci	.type = SND_AK4358,
2698c2ecf20Sopenharmony_ci	.num_dacs = 8,
2708c2ecf20Sopenharmony_ci	.ops = {
2718c2ecf20Sopenharmony_ci		.set_rate_val = revo_set_rate_val
2728c2ecf20Sopenharmony_ci	},
2738c2ecf20Sopenharmony_ci	.dac_info = revo51_dac,
2748c2ecf20Sopenharmony_ci};
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic const struct snd_ak4xxx_private akm_revo51_priv = {
2778c2ecf20Sopenharmony_ci	.caddr = 2,
2788c2ecf20Sopenharmony_ci	.cif = 0,
2798c2ecf20Sopenharmony_ci	.data_mask = VT1724_REVO_CDOUT,
2808c2ecf20Sopenharmony_ci	.clk_mask = VT1724_REVO_CCLK,
2818c2ecf20Sopenharmony_ci	.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1,
2828c2ecf20Sopenharmony_ci	.cs_addr = VT1724_REVO_CS1,
2838c2ecf20Sopenharmony_ci	.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1,
2848c2ecf20Sopenharmony_ci	.add_flags = VT1724_REVO_CCLK, /* high at init */
2858c2ecf20Sopenharmony_ci	.mask_flags = 0,
2868c2ecf20Sopenharmony_ci};
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_cistatic const struct snd_akm4xxx akm_revo51_adc = {
2898c2ecf20Sopenharmony_ci	.type = SND_AK5365,
2908c2ecf20Sopenharmony_ci	.num_adcs = 2,
2918c2ecf20Sopenharmony_ci	.adc_info = revo51_adc,
2928c2ecf20Sopenharmony_ci};
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cistatic const struct snd_ak4xxx_private akm_revo51_adc_priv = {
2958c2ecf20Sopenharmony_ci	.caddr = 2,
2968c2ecf20Sopenharmony_ci	.cif = 0,
2978c2ecf20Sopenharmony_ci	.data_mask = VT1724_REVO_CDOUT,
2988c2ecf20Sopenharmony_ci	.clk_mask = VT1724_REVO_CCLK,
2998c2ecf20Sopenharmony_ci	.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1,
3008c2ecf20Sopenharmony_ci	.cs_addr = VT1724_REVO_CS0,
3018c2ecf20Sopenharmony_ci	.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1,
3028c2ecf20Sopenharmony_ci	.add_flags = VT1724_REVO_CCLK, /* high at init */
3038c2ecf20Sopenharmony_ci	.mask_flags = 0,
3048c2ecf20Sopenharmony_ci};
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic struct snd_pt2258 ptc_revo51_volume;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci/* AK4358 for AP192 DAC, AK5385A for ADC */
3098c2ecf20Sopenharmony_cistatic void ap192_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	struct snd_ice1712 *ice = ak->private_data[0];
3128c2ecf20Sopenharmony_ci	int dfs;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	revo_set_rate_val(ak, rate);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	/* reset CKS */
3178c2ecf20Sopenharmony_ci	snd_ice1712_gpio_write_bits(ice, 1 << 8, rate > 96000 ? 1 << 8 : 0);
3188c2ecf20Sopenharmony_ci	/* reset DFS pins of AK5385A for ADC, too */
3198c2ecf20Sopenharmony_ci	if (rate > 96000)
3208c2ecf20Sopenharmony_ci		dfs = 2;
3218c2ecf20Sopenharmony_ci	else if (rate > 48000)
3228c2ecf20Sopenharmony_ci		dfs = 1;
3238c2ecf20Sopenharmony_ci	else
3248c2ecf20Sopenharmony_ci		dfs = 0;
3258c2ecf20Sopenharmony_ci	snd_ice1712_gpio_write_bits(ice, 3 << 9, dfs << 9);
3268c2ecf20Sopenharmony_ci	/* reset ADC */
3278c2ecf20Sopenharmony_ci	snd_ice1712_gpio_write_bits(ice, 1 << 11, 0);
3288c2ecf20Sopenharmony_ci	snd_ice1712_gpio_write_bits(ice, 1 << 11, 1 << 11);
3298c2ecf20Sopenharmony_ci}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_cistatic const struct snd_akm4xxx_dac_channel ap192_dac[] = {
3328c2ecf20Sopenharmony_ci	AK_DAC("PCM Playback Volume", 2)
3338c2ecf20Sopenharmony_ci};
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic const struct snd_akm4xxx akm_ap192 = {
3368c2ecf20Sopenharmony_ci	.type = SND_AK4358,
3378c2ecf20Sopenharmony_ci	.num_dacs = 2,
3388c2ecf20Sopenharmony_ci	.ops = {
3398c2ecf20Sopenharmony_ci		.set_rate_val = ap192_set_rate_val
3408c2ecf20Sopenharmony_ci	},
3418c2ecf20Sopenharmony_ci	.dac_info = ap192_dac,
3428c2ecf20Sopenharmony_ci};
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_cistatic const struct snd_ak4xxx_private akm_ap192_priv = {
3458c2ecf20Sopenharmony_ci	.caddr = 2,
3468c2ecf20Sopenharmony_ci	.cif = 0,
3478c2ecf20Sopenharmony_ci	.data_mask = VT1724_REVO_CDOUT,
3488c2ecf20Sopenharmony_ci	.clk_mask = VT1724_REVO_CCLK,
3498c2ecf20Sopenharmony_ci	.cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS3,
3508c2ecf20Sopenharmony_ci	.cs_addr = VT1724_REVO_CS3,
3518c2ecf20Sopenharmony_ci	.cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS3,
3528c2ecf20Sopenharmony_ci	.add_flags = VT1724_REVO_CCLK, /* high at init */
3538c2ecf20Sopenharmony_ci	.mask_flags = 0,
3548c2ecf20Sopenharmony_ci};
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci/* AK4114 support on Audiophile 192 */
3578c2ecf20Sopenharmony_ci/* CDTO (pin 32) -- GPIO2 pin 52
3588c2ecf20Sopenharmony_ci * CDTI (pin 33) -- GPIO3 pin 53 (shared with AK4358)
3598c2ecf20Sopenharmony_ci * CCLK (pin 34) -- GPIO1 pin 51 (shared with AK4358)
3608c2ecf20Sopenharmony_ci * CSN  (pin 35) -- GPIO7 pin 59
3618c2ecf20Sopenharmony_ci */
3628c2ecf20Sopenharmony_ci#define AK4114_ADDR	0x00
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_cistatic void write_data(struct snd_ice1712 *ice, unsigned int gpio,
3658c2ecf20Sopenharmony_ci		       unsigned int data, int idx)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	for (; idx >= 0; idx--) {
3688c2ecf20Sopenharmony_ci		/* drop clock */
3698c2ecf20Sopenharmony_ci		gpio &= ~VT1724_REVO_CCLK;
3708c2ecf20Sopenharmony_ci		snd_ice1712_gpio_write(ice, gpio);
3718c2ecf20Sopenharmony_ci		udelay(1);
3728c2ecf20Sopenharmony_ci		/* set data */
3738c2ecf20Sopenharmony_ci		if (data & (1 << idx))
3748c2ecf20Sopenharmony_ci			gpio |= VT1724_REVO_CDOUT;
3758c2ecf20Sopenharmony_ci		else
3768c2ecf20Sopenharmony_ci			gpio &= ~VT1724_REVO_CDOUT;
3778c2ecf20Sopenharmony_ci		snd_ice1712_gpio_write(ice, gpio);
3788c2ecf20Sopenharmony_ci		udelay(1);
3798c2ecf20Sopenharmony_ci		/* raise clock */
3808c2ecf20Sopenharmony_ci		gpio |= VT1724_REVO_CCLK;
3818c2ecf20Sopenharmony_ci		snd_ice1712_gpio_write(ice, gpio);
3828c2ecf20Sopenharmony_ci		udelay(1);
3838c2ecf20Sopenharmony_ci	}
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_cistatic unsigned char read_data(struct snd_ice1712 *ice, unsigned int gpio,
3878c2ecf20Sopenharmony_ci			       int idx)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	unsigned char data = 0;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	for (; idx >= 0; idx--) {
3928c2ecf20Sopenharmony_ci		/* drop clock */
3938c2ecf20Sopenharmony_ci		gpio &= ~VT1724_REVO_CCLK;
3948c2ecf20Sopenharmony_ci		snd_ice1712_gpio_write(ice, gpio);
3958c2ecf20Sopenharmony_ci		udelay(1);
3968c2ecf20Sopenharmony_ci		/* read data */
3978c2ecf20Sopenharmony_ci		if (snd_ice1712_gpio_read(ice) & VT1724_REVO_CDIN)
3988c2ecf20Sopenharmony_ci			data |= (1 << idx);
3998c2ecf20Sopenharmony_ci		udelay(1);
4008c2ecf20Sopenharmony_ci		/* raise clock */
4018c2ecf20Sopenharmony_ci		gpio |= VT1724_REVO_CCLK;
4028c2ecf20Sopenharmony_ci		snd_ice1712_gpio_write(ice, gpio);
4038c2ecf20Sopenharmony_ci		udelay(1);
4048c2ecf20Sopenharmony_ci	}
4058c2ecf20Sopenharmony_ci	return data;
4068c2ecf20Sopenharmony_ci}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_cistatic unsigned int ap192_4wire_start(struct snd_ice1712 *ice)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	unsigned int tmp;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	snd_ice1712_save_gpio_status(ice);
4138c2ecf20Sopenharmony_ci	tmp = snd_ice1712_gpio_read(ice);
4148c2ecf20Sopenharmony_ci	tmp |= VT1724_REVO_CCLK; /* high at init */
4158c2ecf20Sopenharmony_ci	tmp |= VT1724_REVO_CS0;
4168c2ecf20Sopenharmony_ci	tmp &= ~VT1724_REVO_CS3;
4178c2ecf20Sopenharmony_ci	snd_ice1712_gpio_write(ice, tmp);
4188c2ecf20Sopenharmony_ci	udelay(1);
4198c2ecf20Sopenharmony_ci	return tmp;
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic void ap192_4wire_finish(struct snd_ice1712 *ice, unsigned int tmp)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	tmp |= VT1724_REVO_CS3;
4258c2ecf20Sopenharmony_ci	tmp |= VT1724_REVO_CS0;
4268c2ecf20Sopenharmony_ci	snd_ice1712_gpio_write(ice, tmp);
4278c2ecf20Sopenharmony_ci	udelay(1);
4288c2ecf20Sopenharmony_ci	snd_ice1712_restore_gpio_status(ice);
4298c2ecf20Sopenharmony_ci}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_cistatic void ap192_ak4114_write(void *private_data, unsigned char addr,
4328c2ecf20Sopenharmony_ci			       unsigned char data)
4338c2ecf20Sopenharmony_ci{
4348c2ecf20Sopenharmony_ci	struct snd_ice1712 *ice = private_data;
4358c2ecf20Sopenharmony_ci	unsigned int tmp, addrdata;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	tmp = ap192_4wire_start(ice);
4388c2ecf20Sopenharmony_ci	addrdata = (AK4114_ADDR << 6) | 0x20 | (addr & 0x1f);
4398c2ecf20Sopenharmony_ci	addrdata = (addrdata << 8) | data;
4408c2ecf20Sopenharmony_ci	write_data(ice, tmp, addrdata, 15);
4418c2ecf20Sopenharmony_ci	ap192_4wire_finish(ice, tmp);
4428c2ecf20Sopenharmony_ci}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_cistatic unsigned char ap192_ak4114_read(void *private_data, unsigned char addr)
4458c2ecf20Sopenharmony_ci{
4468c2ecf20Sopenharmony_ci	struct snd_ice1712 *ice = private_data;
4478c2ecf20Sopenharmony_ci	unsigned int tmp;
4488c2ecf20Sopenharmony_ci	unsigned char data;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	tmp = ap192_4wire_start(ice);
4518c2ecf20Sopenharmony_ci	write_data(ice, tmp, (AK4114_ADDR << 6) | (addr & 0x1f), 7);
4528c2ecf20Sopenharmony_ci	data = read_data(ice, tmp, 7);
4538c2ecf20Sopenharmony_ci	ap192_4wire_finish(ice, tmp);
4548c2ecf20Sopenharmony_ci	return data;
4558c2ecf20Sopenharmony_ci}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_cistatic int ap192_ak4114_init(struct snd_ice1712 *ice)
4588c2ecf20Sopenharmony_ci{
4598c2ecf20Sopenharmony_ci	static const unsigned char ak4114_init_vals[] = {
4608c2ecf20Sopenharmony_ci		AK4114_RST | AK4114_PWN | AK4114_OCKS0,
4618c2ecf20Sopenharmony_ci		AK4114_DIF_I24I2S,
4628c2ecf20Sopenharmony_ci		AK4114_TX1E,
4638c2ecf20Sopenharmony_ci		AK4114_EFH_1024 | AK4114_DIT | AK4114_IPS(0),
4648c2ecf20Sopenharmony_ci		0,
4658c2ecf20Sopenharmony_ci		0
4668c2ecf20Sopenharmony_ci	};
4678c2ecf20Sopenharmony_ci	static const unsigned char ak4114_init_txcsb[] = {
4688c2ecf20Sopenharmony_ci		0x41, 0x02, 0x2c, 0x00, 0x00
4698c2ecf20Sopenharmony_ci	};
4708c2ecf20Sopenharmony_ci	int err;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	struct revo51_spec *spec;
4738c2ecf20Sopenharmony_ci	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4748c2ecf20Sopenharmony_ci	if (!spec)
4758c2ecf20Sopenharmony_ci		return -ENOMEM;
4768c2ecf20Sopenharmony_ci	ice->spec = spec;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	err = snd_ak4114_create(ice->card,
4798c2ecf20Sopenharmony_ci				 ap192_ak4114_read,
4808c2ecf20Sopenharmony_ci				 ap192_ak4114_write,
4818c2ecf20Sopenharmony_ci				 ak4114_init_vals, ak4114_init_txcsb,
4828c2ecf20Sopenharmony_ci				 ice, &spec->ak4114);
4838c2ecf20Sopenharmony_ci	if (err < 0)
4848c2ecf20Sopenharmony_ci		return err;
4858c2ecf20Sopenharmony_ci	/* AK4114 in Revo cannot detect external rate correctly.
4868c2ecf20Sopenharmony_ci	 * No reason to stop capture stream due to incorrect checks */
4878c2ecf20Sopenharmony_ci	spec->ak4114->check_flags = AK4114_CHECK_NO_RATE;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	return 0;
4908c2ecf20Sopenharmony_ci}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_cistatic int revo_init(struct snd_ice1712 *ice)
4938c2ecf20Sopenharmony_ci{
4948c2ecf20Sopenharmony_ci	struct snd_akm4xxx *ak;
4958c2ecf20Sopenharmony_ci	int err;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	/* determine I2C, DACs and ADCs */
4988c2ecf20Sopenharmony_ci	switch (ice->eeprom.subvendor) {
4998c2ecf20Sopenharmony_ci	case VT1724_SUBDEVICE_REVOLUTION71:
5008c2ecf20Sopenharmony_ci		ice->num_total_dacs = 8;
5018c2ecf20Sopenharmony_ci		ice->num_total_adcs = 2;
5028c2ecf20Sopenharmony_ci		ice->gpio.i2s_mclk_changed = revo_i2s_mclk_changed;
5038c2ecf20Sopenharmony_ci		break;
5048c2ecf20Sopenharmony_ci	case VT1724_SUBDEVICE_REVOLUTION51:
5058c2ecf20Sopenharmony_ci		ice->num_total_dacs = 8;
5068c2ecf20Sopenharmony_ci		ice->num_total_adcs = 2;
5078c2ecf20Sopenharmony_ci		break;
5088c2ecf20Sopenharmony_ci	case VT1724_SUBDEVICE_AUDIOPHILE192:
5098c2ecf20Sopenharmony_ci		ice->num_total_dacs = 2;
5108c2ecf20Sopenharmony_ci		ice->num_total_adcs = 2;
5118c2ecf20Sopenharmony_ci		break;
5128c2ecf20Sopenharmony_ci	default:
5138c2ecf20Sopenharmony_ci		snd_BUG();
5148c2ecf20Sopenharmony_ci		return -EINVAL;
5158c2ecf20Sopenharmony_ci	}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	/* second stage of initialization, analog parts and others */
5188c2ecf20Sopenharmony_ci	ak = ice->akm = kcalloc(2, sizeof(struct snd_akm4xxx), GFP_KERNEL);
5198c2ecf20Sopenharmony_ci	if (! ak)
5208c2ecf20Sopenharmony_ci		return -ENOMEM;
5218c2ecf20Sopenharmony_ci	switch (ice->eeprom.subvendor) {
5228c2ecf20Sopenharmony_ci	case VT1724_SUBDEVICE_REVOLUTION71:
5238c2ecf20Sopenharmony_ci		ice->akm_codecs = 2;
5248c2ecf20Sopenharmony_ci		err = snd_ice1712_akm4xxx_init(ak, &akm_revo_front,
5258c2ecf20Sopenharmony_ci						&akm_revo_front_priv, ice);
5268c2ecf20Sopenharmony_ci		if (err < 0)
5278c2ecf20Sopenharmony_ci			return err;
5288c2ecf20Sopenharmony_ci		err = snd_ice1712_akm4xxx_init(ak+1, &akm_revo_surround,
5298c2ecf20Sopenharmony_ci						&akm_revo_surround_priv, ice);
5308c2ecf20Sopenharmony_ci		if (err < 0)
5318c2ecf20Sopenharmony_ci			return err;
5328c2ecf20Sopenharmony_ci		/* unmute all codecs */
5338c2ecf20Sopenharmony_ci		snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE,
5348c2ecf20Sopenharmony_ci						VT1724_REVO_MUTE);
5358c2ecf20Sopenharmony_ci		break;
5368c2ecf20Sopenharmony_ci	case VT1724_SUBDEVICE_REVOLUTION51:
5378c2ecf20Sopenharmony_ci		ice->akm_codecs = 2;
5388c2ecf20Sopenharmony_ci		err = snd_ice1712_akm4xxx_init(ak, &akm_revo51,
5398c2ecf20Sopenharmony_ci					       &akm_revo51_priv, ice);
5408c2ecf20Sopenharmony_ci		if (err < 0)
5418c2ecf20Sopenharmony_ci			return err;
5428c2ecf20Sopenharmony_ci		err = snd_ice1712_akm4xxx_init(ak+1, &akm_revo51_adc,
5438c2ecf20Sopenharmony_ci					       &akm_revo51_adc_priv, ice);
5448c2ecf20Sopenharmony_ci		if (err < 0)
5458c2ecf20Sopenharmony_ci			return err;
5468c2ecf20Sopenharmony_ci		err = revo51_i2c_init(ice, &ptc_revo51_volume);
5478c2ecf20Sopenharmony_ci		if (err < 0)
5488c2ecf20Sopenharmony_ci			return err;
5498c2ecf20Sopenharmony_ci		/* unmute all codecs */
5508c2ecf20Sopenharmony_ci		snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE,
5518c2ecf20Sopenharmony_ci					    VT1724_REVO_MUTE);
5528c2ecf20Sopenharmony_ci		break;
5538c2ecf20Sopenharmony_ci	case VT1724_SUBDEVICE_AUDIOPHILE192:
5548c2ecf20Sopenharmony_ci		ice->akm_codecs = 1;
5558c2ecf20Sopenharmony_ci		err = snd_ice1712_akm4xxx_init(ak, &akm_ap192, &akm_ap192_priv,
5568c2ecf20Sopenharmony_ci					       ice);
5578c2ecf20Sopenharmony_ci		if (err < 0)
5588c2ecf20Sopenharmony_ci			return err;
5598c2ecf20Sopenharmony_ci		err = ap192_ak4114_init(ice);
5608c2ecf20Sopenharmony_ci		if (err < 0)
5618c2ecf20Sopenharmony_ci			return err;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci		/* unmute all codecs */
5648c2ecf20Sopenharmony_ci		snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE,
5658c2ecf20Sopenharmony_ci					    VT1724_REVO_MUTE);
5668c2ecf20Sopenharmony_ci		break;
5678c2ecf20Sopenharmony_ci	}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	return 0;
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_cistatic int revo_add_controls(struct snd_ice1712 *ice)
5748c2ecf20Sopenharmony_ci{
5758c2ecf20Sopenharmony_ci	struct revo51_spec *spec = ice->spec;
5768c2ecf20Sopenharmony_ci	int err;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	switch (ice->eeprom.subvendor) {
5798c2ecf20Sopenharmony_ci	case VT1724_SUBDEVICE_REVOLUTION71:
5808c2ecf20Sopenharmony_ci		err = snd_ice1712_akm4xxx_build_controls(ice);
5818c2ecf20Sopenharmony_ci		if (err < 0)
5828c2ecf20Sopenharmony_ci			return err;
5838c2ecf20Sopenharmony_ci		break;
5848c2ecf20Sopenharmony_ci	case VT1724_SUBDEVICE_REVOLUTION51:
5858c2ecf20Sopenharmony_ci		err = snd_ice1712_akm4xxx_build_controls(ice);
5868c2ecf20Sopenharmony_ci		if (err < 0)
5878c2ecf20Sopenharmony_ci			return err;
5888c2ecf20Sopenharmony_ci		spec = ice->spec;
5898c2ecf20Sopenharmony_ci		err = snd_pt2258_build_controls(spec->pt2258);
5908c2ecf20Sopenharmony_ci		if (err < 0)
5918c2ecf20Sopenharmony_ci			return err;
5928c2ecf20Sopenharmony_ci		break;
5938c2ecf20Sopenharmony_ci	case VT1724_SUBDEVICE_AUDIOPHILE192:
5948c2ecf20Sopenharmony_ci		err = snd_ice1712_akm4xxx_build_controls(ice);
5958c2ecf20Sopenharmony_ci		if (err < 0)
5968c2ecf20Sopenharmony_ci			return err;
5978c2ecf20Sopenharmony_ci		/* only capture SPDIF over AK4114 */
5988c2ecf20Sopenharmony_ci		err = snd_ak4114_build(spec->ak4114, NULL,
5998c2ecf20Sopenharmony_ci		   ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
6008c2ecf20Sopenharmony_ci		if (err < 0)
6018c2ecf20Sopenharmony_ci			return err;
6028c2ecf20Sopenharmony_ci		break;
6038c2ecf20Sopenharmony_ci	}
6048c2ecf20Sopenharmony_ci	return 0;
6058c2ecf20Sopenharmony_ci}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci/* entry point */
6088c2ecf20Sopenharmony_cistruct snd_ice1712_card_info snd_vt1724_revo_cards[] = {
6098c2ecf20Sopenharmony_ci	{
6108c2ecf20Sopenharmony_ci		.subvendor = VT1724_SUBDEVICE_REVOLUTION71,
6118c2ecf20Sopenharmony_ci		.name = "M Audio Revolution-7.1",
6128c2ecf20Sopenharmony_ci		.model = "revo71",
6138c2ecf20Sopenharmony_ci		.chip_init = revo_init,
6148c2ecf20Sopenharmony_ci		.build_controls = revo_add_controls,
6158c2ecf20Sopenharmony_ci	},
6168c2ecf20Sopenharmony_ci	{
6178c2ecf20Sopenharmony_ci		.subvendor = VT1724_SUBDEVICE_REVOLUTION51,
6188c2ecf20Sopenharmony_ci		.name = "M Audio Revolution-5.1",
6198c2ecf20Sopenharmony_ci		.model = "revo51",
6208c2ecf20Sopenharmony_ci		.chip_init = revo_init,
6218c2ecf20Sopenharmony_ci		.build_controls = revo_add_controls,
6228c2ecf20Sopenharmony_ci	},
6238c2ecf20Sopenharmony_ci	{
6248c2ecf20Sopenharmony_ci		.subvendor = VT1724_SUBDEVICE_AUDIOPHILE192,
6258c2ecf20Sopenharmony_ci		.name = "M Audio Audiophile192",
6268c2ecf20Sopenharmony_ci		.model = "ap192",
6278c2ecf20Sopenharmony_ci		.chip_init = revo_init,
6288c2ecf20Sopenharmony_ci		.build_controls = revo_add_controls,
6298c2ecf20Sopenharmony_ci	},
6308c2ecf20Sopenharmony_ci	{ } /* terminator */
6318c2ecf20Sopenharmony_ci};
632