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