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