18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ALSA driver for ICEnsemble VT1724 (Envy24HT) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Lowlevel functions for ESI Juli@ cards 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (c) 2004 Jaroslav Kysela <perex@perex.cz> 88c2ecf20Sopenharmony_ci * 2008 Pavel Hofman <dustin@seznam.cz> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/string.h> 168c2ecf20Sopenharmony_ci#include <sound/core.h> 178c2ecf20Sopenharmony_ci#include <sound/tlv.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "ice1712.h" 208c2ecf20Sopenharmony_ci#include "envy24ht.h" 218c2ecf20Sopenharmony_ci#include "juli.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistruct juli_spec { 248c2ecf20Sopenharmony_ci struct ak4114 *ak4114; 258c2ecf20Sopenharmony_ci unsigned int analog:1; 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * chip addresses on I2C bus 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci#define AK4114_ADDR 0x20 /* S/PDIF receiver */ 328c2ecf20Sopenharmony_ci#define AK4358_ADDR 0x22 /* DAC */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* 358c2ecf20Sopenharmony_ci * Juli does not use the standard ICE1724 clock scheme. Juli's ice1724 chip is 368c2ecf20Sopenharmony_ci * supplied by external clock provided by Xilinx array and MK73-1 PLL frequency 378c2ecf20Sopenharmony_ci * multiplier. Actual frequency is set by ice1724 GPIOs hooked to the Xilinx. 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * The clock circuitry is supplied by the two ice1724 crystals. This 408c2ecf20Sopenharmony_ci * arrangement allows to generate independent clock signal for AK4114's input 418c2ecf20Sopenharmony_ci * rate detection circuit. As a result, Juli, unlike most other 428c2ecf20Sopenharmony_ci * ice1724+ak4114-based cards, detects spdif input rate correctly. 438c2ecf20Sopenharmony_ci * This fact is applied in the driver, allowing to modify PCM stream rate 448c2ecf20Sopenharmony_ci * parameter according to the actual input rate. 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci * Juli uses the remaining three stereo-channels of its DAC to optionally 478c2ecf20Sopenharmony_ci * monitor analog input, digital input, and digital output. The corresponding 488c2ecf20Sopenharmony_ci * I2S signals are routed by Xilinx, controlled by GPIOs. 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * The master mute is implemented using output muting transistors (GPIO) in 518c2ecf20Sopenharmony_ci * combination with smuting the DAC. 528c2ecf20Sopenharmony_ci * 538c2ecf20Sopenharmony_ci * The card itself has no HW master volume control, implemented using the 548c2ecf20Sopenharmony_ci * vmaster control. 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * TODO: 578c2ecf20Sopenharmony_ci * researching and fixing the input monitors 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* 618c2ecf20Sopenharmony_ci * GPIO pins 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_ci#define GPIO_FREQ_MASK (3<<0) 648c2ecf20Sopenharmony_ci#define GPIO_FREQ_32KHZ (0<<0) 658c2ecf20Sopenharmony_ci#define GPIO_FREQ_44KHZ (1<<0) 668c2ecf20Sopenharmony_ci#define GPIO_FREQ_48KHZ (2<<0) 678c2ecf20Sopenharmony_ci#define GPIO_MULTI_MASK (3<<2) 688c2ecf20Sopenharmony_ci#define GPIO_MULTI_4X (0<<2) 698c2ecf20Sopenharmony_ci#define GPIO_MULTI_2X (1<<2) 708c2ecf20Sopenharmony_ci#define GPIO_MULTI_1X (2<<2) /* also external */ 718c2ecf20Sopenharmony_ci#define GPIO_MULTI_HALF (3<<2) 728c2ecf20Sopenharmony_ci#define GPIO_INTERNAL_CLOCK (1<<4) /* 0 = external, 1 = internal */ 738c2ecf20Sopenharmony_ci#define GPIO_CLOCK_MASK (1<<4) 748c2ecf20Sopenharmony_ci#define GPIO_ANALOG_PRESENT (1<<5) /* RO only: 0 = present */ 758c2ecf20Sopenharmony_ci#define GPIO_RXMCLK_SEL (1<<7) /* must be 0 */ 768c2ecf20Sopenharmony_ci#define GPIO_AK5385A_CKS0 (1<<8) 778c2ecf20Sopenharmony_ci#define GPIO_AK5385A_DFS1 (1<<9) 788c2ecf20Sopenharmony_ci#define GPIO_AK5385A_DFS0 (1<<10) 798c2ecf20Sopenharmony_ci#define GPIO_DIGOUT_MONITOR (1<<11) /* 1 = active */ 808c2ecf20Sopenharmony_ci#define GPIO_DIGIN_MONITOR (1<<12) /* 1 = active */ 818c2ecf20Sopenharmony_ci#define GPIO_ANAIN_MONITOR (1<<13) /* 1 = active */ 828c2ecf20Sopenharmony_ci#define GPIO_AK5385A_CKS1 (1<<14) /* must be 0 */ 838c2ecf20Sopenharmony_ci#define GPIO_MUTE_CONTROL (1<<15) /* output mute, 1 = muted */ 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci#define GPIO_RATE_MASK (GPIO_FREQ_MASK | GPIO_MULTI_MASK | \ 868c2ecf20Sopenharmony_ci GPIO_CLOCK_MASK) 878c2ecf20Sopenharmony_ci#define GPIO_AK5385A_MASK (GPIO_AK5385A_CKS0 | GPIO_AK5385A_DFS0 | \ 888c2ecf20Sopenharmony_ci GPIO_AK5385A_DFS1 | GPIO_AK5385A_CKS1) 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci#define JULI_PCM_RATE (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ 918c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ 928c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \ 938c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \ 948c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#define GPIO_RATE_16000 (GPIO_FREQ_32KHZ | GPIO_MULTI_HALF | \ 978c2ecf20Sopenharmony_ci GPIO_INTERNAL_CLOCK) 988c2ecf20Sopenharmony_ci#define GPIO_RATE_22050 (GPIO_FREQ_44KHZ | GPIO_MULTI_HALF | \ 998c2ecf20Sopenharmony_ci GPIO_INTERNAL_CLOCK) 1008c2ecf20Sopenharmony_ci#define GPIO_RATE_24000 (GPIO_FREQ_48KHZ | GPIO_MULTI_HALF | \ 1018c2ecf20Sopenharmony_ci GPIO_INTERNAL_CLOCK) 1028c2ecf20Sopenharmony_ci#define GPIO_RATE_32000 (GPIO_FREQ_32KHZ | GPIO_MULTI_1X | \ 1038c2ecf20Sopenharmony_ci GPIO_INTERNAL_CLOCK) 1048c2ecf20Sopenharmony_ci#define GPIO_RATE_44100 (GPIO_FREQ_44KHZ | GPIO_MULTI_1X | \ 1058c2ecf20Sopenharmony_ci GPIO_INTERNAL_CLOCK) 1068c2ecf20Sopenharmony_ci#define GPIO_RATE_48000 (GPIO_FREQ_48KHZ | GPIO_MULTI_1X | \ 1078c2ecf20Sopenharmony_ci GPIO_INTERNAL_CLOCK) 1088c2ecf20Sopenharmony_ci#define GPIO_RATE_64000 (GPIO_FREQ_32KHZ | GPIO_MULTI_2X | \ 1098c2ecf20Sopenharmony_ci GPIO_INTERNAL_CLOCK) 1108c2ecf20Sopenharmony_ci#define GPIO_RATE_88200 (GPIO_FREQ_44KHZ | GPIO_MULTI_2X | \ 1118c2ecf20Sopenharmony_ci GPIO_INTERNAL_CLOCK) 1128c2ecf20Sopenharmony_ci#define GPIO_RATE_96000 (GPIO_FREQ_48KHZ | GPIO_MULTI_2X | \ 1138c2ecf20Sopenharmony_ci GPIO_INTERNAL_CLOCK) 1148c2ecf20Sopenharmony_ci#define GPIO_RATE_176400 (GPIO_FREQ_44KHZ | GPIO_MULTI_4X | \ 1158c2ecf20Sopenharmony_ci GPIO_INTERNAL_CLOCK) 1168c2ecf20Sopenharmony_ci#define GPIO_RATE_192000 (GPIO_FREQ_48KHZ | GPIO_MULTI_4X | \ 1178c2ecf20Sopenharmony_ci GPIO_INTERNAL_CLOCK) 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/* 1208c2ecf20Sopenharmony_ci * Initial setup of the conversion array GPIO <-> rate 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_cistatic const unsigned int juli_rates[] = { 1238c2ecf20Sopenharmony_ci 16000, 22050, 24000, 32000, 1248c2ecf20Sopenharmony_ci 44100, 48000, 64000, 88200, 1258c2ecf20Sopenharmony_ci 96000, 176400, 192000, 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic const unsigned int gpio_vals[] = { 1298c2ecf20Sopenharmony_ci GPIO_RATE_16000, GPIO_RATE_22050, GPIO_RATE_24000, GPIO_RATE_32000, 1308c2ecf20Sopenharmony_ci GPIO_RATE_44100, GPIO_RATE_48000, GPIO_RATE_64000, GPIO_RATE_88200, 1318c2ecf20Sopenharmony_ci GPIO_RATE_96000, GPIO_RATE_176400, GPIO_RATE_192000, 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list juli_rates_info = { 1358c2ecf20Sopenharmony_ci .count = ARRAY_SIZE(juli_rates), 1368c2ecf20Sopenharmony_ci .list = juli_rates, 1378c2ecf20Sopenharmony_ci .mask = 0, 1388c2ecf20Sopenharmony_ci}; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic int get_gpio_val(int rate) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci int i; 1438c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(juli_rates); i++) 1448c2ecf20Sopenharmony_ci if (juli_rates[i] == rate) 1458c2ecf20Sopenharmony_ci return gpio_vals[i]; 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic void juli_ak4114_write(void *private_data, unsigned char reg, 1508c2ecf20Sopenharmony_ci unsigned char val) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci snd_vt1724_write_i2c((struct snd_ice1712 *)private_data, AK4114_ADDR, 1538c2ecf20Sopenharmony_ci reg, val); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic unsigned char juli_ak4114_read(void *private_data, unsigned char reg) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci return snd_vt1724_read_i2c((struct snd_ice1712 *)private_data, 1598c2ecf20Sopenharmony_ci AK4114_ADDR, reg); 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci/* 1638c2ecf20Sopenharmony_ci * If SPDIF capture and slaved to SPDIF-IN, setting runtime rate 1648c2ecf20Sopenharmony_ci * to the external rate 1658c2ecf20Sopenharmony_ci */ 1668c2ecf20Sopenharmony_cistatic void juli_spdif_in_open(struct snd_ice1712 *ice, 1678c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct juli_spec *spec = ice->spec; 1708c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 1718c2ecf20Sopenharmony_ci int rate; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK || 1748c2ecf20Sopenharmony_ci !ice->is_spdif_master(ice)) 1758c2ecf20Sopenharmony_ci return; 1768c2ecf20Sopenharmony_ci rate = snd_ak4114_external_rate(spec->ak4114); 1778c2ecf20Sopenharmony_ci if (rate >= runtime->hw.rate_min && rate <= runtime->hw.rate_max) { 1788c2ecf20Sopenharmony_ci runtime->hw.rate_min = rate; 1798c2ecf20Sopenharmony_ci runtime->hw.rate_max = rate; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci/* 1848c2ecf20Sopenharmony_ci * AK4358 section 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic void juli_akm_lock(struct snd_akm4xxx *ak, int chip) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic void juli_akm_unlock(struct snd_akm4xxx *ak, int chip) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic void juli_akm_write(struct snd_akm4xxx *ak, int chip, 1968c2ecf20Sopenharmony_ci unsigned char addr, unsigned char data) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = ak->private_data[0]; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (snd_BUG_ON(chip)) 2018c2ecf20Sopenharmony_ci return; 2028c2ecf20Sopenharmony_ci snd_vt1724_write_i2c(ice, AK4358_ADDR, addr, data); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci/* 2068c2ecf20Sopenharmony_ci * change the rate of envy24HT, AK4358, AK5385 2078c2ecf20Sopenharmony_ci */ 2088c2ecf20Sopenharmony_cistatic void juli_akm_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci unsigned char old, tmp, ak4358_dfs; 2118c2ecf20Sopenharmony_ci unsigned int ak5385_pins, old_gpio, new_gpio; 2128c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = ak->private_data[0]; 2138c2ecf20Sopenharmony_ci struct juli_spec *spec = ice->spec; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (rate == 0) /* no hint - S/PDIF input is master or the new spdif 2168c2ecf20Sopenharmony_ci input rate undetected, simply return */ 2178c2ecf20Sopenharmony_ci return; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* adjust DFS on codecs */ 2208c2ecf20Sopenharmony_ci if (rate > 96000) { 2218c2ecf20Sopenharmony_ci ak4358_dfs = 2; 2228c2ecf20Sopenharmony_ci ak5385_pins = GPIO_AK5385A_DFS1 | GPIO_AK5385A_CKS0; 2238c2ecf20Sopenharmony_ci } else if (rate > 48000) { 2248c2ecf20Sopenharmony_ci ak4358_dfs = 1; 2258c2ecf20Sopenharmony_ci ak5385_pins = GPIO_AK5385A_DFS0; 2268c2ecf20Sopenharmony_ci } else { 2278c2ecf20Sopenharmony_ci ak4358_dfs = 0; 2288c2ecf20Sopenharmony_ci ak5385_pins = 0; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci /* AK5385 first, since it requires cold reset affecting both codecs */ 2318c2ecf20Sopenharmony_ci old_gpio = ice->gpio.get_data(ice); 2328c2ecf20Sopenharmony_ci new_gpio = (old_gpio & ~GPIO_AK5385A_MASK) | ak5385_pins; 2338c2ecf20Sopenharmony_ci /* dev_dbg(ice->card->dev, "JULI - ak5385 set_rate_val: new gpio 0x%x\n", 2348c2ecf20Sopenharmony_ci new_gpio); */ 2358c2ecf20Sopenharmony_ci ice->gpio.set_data(ice, new_gpio); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /* cold reset */ 2388c2ecf20Sopenharmony_ci old = inb(ICEMT1724(ice, AC97_CMD)); 2398c2ecf20Sopenharmony_ci outb(old | VT1724_AC97_COLD, ICEMT1724(ice, AC97_CMD)); 2408c2ecf20Sopenharmony_ci udelay(1); 2418c2ecf20Sopenharmony_ci outb(old & ~VT1724_AC97_COLD, ICEMT1724(ice, AC97_CMD)); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* AK4358 */ 2448c2ecf20Sopenharmony_ci /* set new value, reset DFS */ 2458c2ecf20Sopenharmony_ci tmp = snd_akm4xxx_get(ak, 0, 2); 2468c2ecf20Sopenharmony_ci snd_akm4xxx_reset(ak, 1); 2478c2ecf20Sopenharmony_ci tmp = snd_akm4xxx_get(ak, 0, 2); 2488c2ecf20Sopenharmony_ci tmp &= ~(0x03 << 4); 2498c2ecf20Sopenharmony_ci tmp |= ak4358_dfs << 4; 2508c2ecf20Sopenharmony_ci snd_akm4xxx_set(ak, 0, 2, tmp); 2518c2ecf20Sopenharmony_ci snd_akm4xxx_reset(ak, 0); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* reinit ak4114 */ 2548c2ecf20Sopenharmony_ci snd_ak4114_reinit(spec->ak4114); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci#define AK_DAC(xname, xch) { .name = xname, .num_channels = xch } 2588c2ecf20Sopenharmony_ci#define PCM_VOLUME "PCM Playback Volume" 2598c2ecf20Sopenharmony_ci#define MONITOR_AN_IN_VOLUME "Monitor Analog In Volume" 2608c2ecf20Sopenharmony_ci#define MONITOR_DIG_IN_VOLUME "Monitor Digital In Volume" 2618c2ecf20Sopenharmony_ci#define MONITOR_DIG_OUT_VOLUME "Monitor Digital Out Volume" 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic const struct snd_akm4xxx_dac_channel juli_dac[] = { 2648c2ecf20Sopenharmony_ci AK_DAC(PCM_VOLUME, 2), 2658c2ecf20Sopenharmony_ci AK_DAC(MONITOR_AN_IN_VOLUME, 2), 2668c2ecf20Sopenharmony_ci AK_DAC(MONITOR_DIG_OUT_VOLUME, 2), 2678c2ecf20Sopenharmony_ci AK_DAC(MONITOR_DIG_IN_VOLUME, 2), 2688c2ecf20Sopenharmony_ci}; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic const struct snd_akm4xxx akm_juli_dac = { 2728c2ecf20Sopenharmony_ci .type = SND_AK4358, 2738c2ecf20Sopenharmony_ci .num_dacs = 8, /* DAC1 - analog out 2748c2ecf20Sopenharmony_ci DAC2 - analog in monitor 2758c2ecf20Sopenharmony_ci DAC3 - digital out monitor 2768c2ecf20Sopenharmony_ci DAC4 - digital in monitor 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_ci .ops = { 2798c2ecf20Sopenharmony_ci .lock = juli_akm_lock, 2808c2ecf20Sopenharmony_ci .unlock = juli_akm_unlock, 2818c2ecf20Sopenharmony_ci .write = juli_akm_write, 2828c2ecf20Sopenharmony_ci .set_rate_val = juli_akm_set_rate_val 2838c2ecf20Sopenharmony_ci }, 2848c2ecf20Sopenharmony_ci .dac_info = juli_dac, 2858c2ecf20Sopenharmony_ci}; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci#define juli_mute_info snd_ctl_boolean_mono_info 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic int juli_mute_get(struct snd_kcontrol *kcontrol, 2908c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 2938c2ecf20Sopenharmony_ci unsigned int val; 2948c2ecf20Sopenharmony_ci val = ice->gpio.get_data(ice) & (unsigned int) kcontrol->private_value; 2958c2ecf20Sopenharmony_ci if (kcontrol->private_value == GPIO_MUTE_CONTROL) 2968c2ecf20Sopenharmony_ci /* val 0 = signal on */ 2978c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = (val) ? 0 : 1; 2988c2ecf20Sopenharmony_ci else 2998c2ecf20Sopenharmony_ci /* val 1 = signal on */ 3008c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = (val) ? 1 : 0; 3018c2ecf20Sopenharmony_ci return 0; 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic int juli_mute_put(struct snd_kcontrol *kcontrol, 3058c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 3088c2ecf20Sopenharmony_ci unsigned int old_gpio, new_gpio; 3098c2ecf20Sopenharmony_ci old_gpio = ice->gpio.get_data(ice); 3108c2ecf20Sopenharmony_ci if (ucontrol->value.integer.value[0]) { 3118c2ecf20Sopenharmony_ci /* unmute */ 3128c2ecf20Sopenharmony_ci if (kcontrol->private_value == GPIO_MUTE_CONTROL) { 3138c2ecf20Sopenharmony_ci /* 0 = signal on */ 3148c2ecf20Sopenharmony_ci new_gpio = old_gpio & ~GPIO_MUTE_CONTROL; 3158c2ecf20Sopenharmony_ci /* un-smuting DAC */ 3168c2ecf20Sopenharmony_ci snd_akm4xxx_write(ice->akm, 0, 0x01, 0x01); 3178c2ecf20Sopenharmony_ci } else 3188c2ecf20Sopenharmony_ci /* 1 = signal on */ 3198c2ecf20Sopenharmony_ci new_gpio = old_gpio | 3208c2ecf20Sopenharmony_ci (unsigned int) kcontrol->private_value; 3218c2ecf20Sopenharmony_ci } else { 3228c2ecf20Sopenharmony_ci /* mute */ 3238c2ecf20Sopenharmony_ci if (kcontrol->private_value == GPIO_MUTE_CONTROL) { 3248c2ecf20Sopenharmony_ci /* 1 = signal off */ 3258c2ecf20Sopenharmony_ci new_gpio = old_gpio | GPIO_MUTE_CONTROL; 3268c2ecf20Sopenharmony_ci /* smuting DAC */ 3278c2ecf20Sopenharmony_ci snd_akm4xxx_write(ice->akm, 0, 0x01, 0x03); 3288c2ecf20Sopenharmony_ci } else 3298c2ecf20Sopenharmony_ci /* 0 = signal off */ 3308c2ecf20Sopenharmony_ci new_gpio = old_gpio & 3318c2ecf20Sopenharmony_ci ~((unsigned int) kcontrol->private_value); 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci /* dev_dbg(ice->card->dev, 3348c2ecf20Sopenharmony_ci "JULI - mute/unmute: control_value: 0x%x, old_gpio: 0x%x, " 3358c2ecf20Sopenharmony_ci "new_gpio 0x%x\n", 3368c2ecf20Sopenharmony_ci (unsigned int)ucontrol->value.integer.value[0], old_gpio, 3378c2ecf20Sopenharmony_ci new_gpio); */ 3388c2ecf20Sopenharmony_ci if (old_gpio != new_gpio) { 3398c2ecf20Sopenharmony_ci ice->gpio.set_data(ice, new_gpio); 3408c2ecf20Sopenharmony_ci return 1; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci /* no change */ 3438c2ecf20Sopenharmony_ci return 0; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new juli_mute_controls[] = { 3478c2ecf20Sopenharmony_ci { 3488c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3498c2ecf20Sopenharmony_ci .name = "Master Playback Switch", 3508c2ecf20Sopenharmony_ci .info = juli_mute_info, 3518c2ecf20Sopenharmony_ci .get = juli_mute_get, 3528c2ecf20Sopenharmony_ci .put = juli_mute_put, 3538c2ecf20Sopenharmony_ci .private_value = GPIO_MUTE_CONTROL, 3548c2ecf20Sopenharmony_ci }, 3558c2ecf20Sopenharmony_ci /* Although the following functionality respects the succint NDA'd 3568c2ecf20Sopenharmony_ci * documentation from the card manufacturer, and the same way of 3578c2ecf20Sopenharmony_ci * operation is coded in OSS Juli driver, only Digital Out monitor 3588c2ecf20Sopenharmony_ci * seems to work. Surprisingly, Analog input monitor outputs Digital 3598c2ecf20Sopenharmony_ci * output data. The two are independent, as enabling both doubles 3608c2ecf20Sopenharmony_ci * volume of the monitor sound. 3618c2ecf20Sopenharmony_ci * 3628c2ecf20Sopenharmony_ci * Checking traces on the board suggests the functionality described 3638c2ecf20Sopenharmony_ci * by the manufacturer is correct - I2S from ADC and AK4114 3648c2ecf20Sopenharmony_ci * go to ICE as well as to Xilinx, I2S inputs of DAC2,3,4 (the monitor 3658c2ecf20Sopenharmony_ci * inputs) are fed from Xilinx. 3668c2ecf20Sopenharmony_ci * 3678c2ecf20Sopenharmony_ci * I even checked traces on board and coded a support in driver for 3688c2ecf20Sopenharmony_ci * an alternative possibility - the unused I2S ICE output channels 3698c2ecf20Sopenharmony_ci * switched to HW-IN/SPDIF-IN and providing the monitoring signal to 3708c2ecf20Sopenharmony_ci * the DAC - to no avail. The I2S outputs seem to be unconnected. 3718c2ecf20Sopenharmony_ci * 3728c2ecf20Sopenharmony_ci * The windows driver supports the monitoring correctly. 3738c2ecf20Sopenharmony_ci */ 3748c2ecf20Sopenharmony_ci { 3758c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3768c2ecf20Sopenharmony_ci .name = "Monitor Analog In Switch", 3778c2ecf20Sopenharmony_ci .info = juli_mute_info, 3788c2ecf20Sopenharmony_ci .get = juli_mute_get, 3798c2ecf20Sopenharmony_ci .put = juli_mute_put, 3808c2ecf20Sopenharmony_ci .private_value = GPIO_ANAIN_MONITOR, 3818c2ecf20Sopenharmony_ci }, 3828c2ecf20Sopenharmony_ci { 3838c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3848c2ecf20Sopenharmony_ci .name = "Monitor Digital Out Switch", 3858c2ecf20Sopenharmony_ci .info = juli_mute_info, 3868c2ecf20Sopenharmony_ci .get = juli_mute_get, 3878c2ecf20Sopenharmony_ci .put = juli_mute_put, 3888c2ecf20Sopenharmony_ci .private_value = GPIO_DIGOUT_MONITOR, 3898c2ecf20Sopenharmony_ci }, 3908c2ecf20Sopenharmony_ci { 3918c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 3928c2ecf20Sopenharmony_ci .name = "Monitor Digital In Switch", 3938c2ecf20Sopenharmony_ci .info = juli_mute_info, 3948c2ecf20Sopenharmony_ci .get = juli_mute_get, 3958c2ecf20Sopenharmony_ci .put = juli_mute_put, 3968c2ecf20Sopenharmony_ci .private_value = GPIO_DIGIN_MONITOR, 3978c2ecf20Sopenharmony_ci }, 3988c2ecf20Sopenharmony_ci}; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic const char * const follower_vols[] = { 4018c2ecf20Sopenharmony_ci PCM_VOLUME, 4028c2ecf20Sopenharmony_ci MONITOR_AN_IN_VOLUME, 4038c2ecf20Sopenharmony_ci MONITOR_DIG_IN_VOLUME, 4048c2ecf20Sopenharmony_ci MONITOR_DIG_OUT_VOLUME, 4058c2ecf20Sopenharmony_ci NULL 4068c2ecf20Sopenharmony_ci}; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic 4098c2ecf20Sopenharmony_ciDECLARE_TLV_DB_SCALE(juli_master_db_scale, -6350, 50, 1); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic struct snd_kcontrol *ctl_find(struct snd_card *card, 4128c2ecf20Sopenharmony_ci const char *name) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci struct snd_ctl_elem_id sid = {0}; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci strlcpy(sid.name, name, sizeof(sid.name)); 4178c2ecf20Sopenharmony_ci sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 4188c2ecf20Sopenharmony_ci return snd_ctl_find_id(card, &sid); 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic void add_followers(struct snd_card *card, 4228c2ecf20Sopenharmony_ci struct snd_kcontrol *master, 4238c2ecf20Sopenharmony_ci const char * const *list) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci for (; *list; list++) { 4268c2ecf20Sopenharmony_ci struct snd_kcontrol *follower = ctl_find(card, *list); 4278c2ecf20Sopenharmony_ci /* dev_dbg(card->dev, "add_followers - %s\n", *list); */ 4288c2ecf20Sopenharmony_ci if (follower) { 4298c2ecf20Sopenharmony_ci /* dev_dbg(card->dev, "follower %s found\n", *list); */ 4308c2ecf20Sopenharmony_ci snd_ctl_add_follower(master, follower); 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic int juli_add_controls(struct snd_ice1712 *ice) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci struct juli_spec *spec = ice->spec; 4388c2ecf20Sopenharmony_ci int err; 4398c2ecf20Sopenharmony_ci unsigned int i; 4408c2ecf20Sopenharmony_ci struct snd_kcontrol *vmaster; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci err = snd_ice1712_akm4xxx_build_controls(ice); 4438c2ecf20Sopenharmony_ci if (err < 0) 4448c2ecf20Sopenharmony_ci return err; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(juli_mute_controls); i++) { 4478c2ecf20Sopenharmony_ci err = snd_ctl_add(ice->card, 4488c2ecf20Sopenharmony_ci snd_ctl_new1(&juli_mute_controls[i], ice)); 4498c2ecf20Sopenharmony_ci if (err < 0) 4508c2ecf20Sopenharmony_ci return err; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci /* Create virtual master control */ 4538c2ecf20Sopenharmony_ci vmaster = snd_ctl_make_virtual_master("Master Playback Volume", 4548c2ecf20Sopenharmony_ci juli_master_db_scale); 4558c2ecf20Sopenharmony_ci if (!vmaster) 4568c2ecf20Sopenharmony_ci return -ENOMEM; 4578c2ecf20Sopenharmony_ci add_followers(ice->card, vmaster, follower_vols); 4588c2ecf20Sopenharmony_ci err = snd_ctl_add(ice->card, vmaster); 4598c2ecf20Sopenharmony_ci if (err < 0) 4608c2ecf20Sopenharmony_ci return err; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci /* only capture SPDIF over AK4114 */ 4638c2ecf20Sopenharmony_ci return snd_ak4114_build(spec->ak4114, NULL, 4648c2ecf20Sopenharmony_ci ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci/* 4688c2ecf20Sopenharmony_ci * suspend/resume 4698c2ecf20Sopenharmony_ci * */ 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 4728c2ecf20Sopenharmony_cistatic int juli_resume(struct snd_ice1712 *ice) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci struct snd_akm4xxx *ak = ice->akm; 4758c2ecf20Sopenharmony_ci struct juli_spec *spec = ice->spec; 4768c2ecf20Sopenharmony_ci /* akm4358 un-reset, un-mute */ 4778c2ecf20Sopenharmony_ci snd_akm4xxx_reset(ak, 0); 4788c2ecf20Sopenharmony_ci /* reinit ak4114 */ 4798c2ecf20Sopenharmony_ci snd_ak4114_resume(spec->ak4114); 4808c2ecf20Sopenharmony_ci return 0; 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic int juli_suspend(struct snd_ice1712 *ice) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci struct snd_akm4xxx *ak = ice->akm; 4868c2ecf20Sopenharmony_ci struct juli_spec *spec = ice->spec; 4878c2ecf20Sopenharmony_ci /* akm4358 reset and soft-mute */ 4888c2ecf20Sopenharmony_ci snd_akm4xxx_reset(ak, 1); 4898c2ecf20Sopenharmony_ci snd_ak4114_suspend(spec->ak4114); 4908c2ecf20Sopenharmony_ci return 0; 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci#endif 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci/* 4958c2ecf20Sopenharmony_ci * initialize the chip 4968c2ecf20Sopenharmony_ci */ 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic inline int juli_is_spdif_master(struct snd_ice1712 *ice) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci return (ice->gpio.get_data(ice) & GPIO_INTERNAL_CLOCK) ? 0 : 1; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic unsigned int juli_get_rate(struct snd_ice1712 *ice) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci int i; 5068c2ecf20Sopenharmony_ci unsigned char result; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci result = ice->gpio.get_data(ice) & GPIO_RATE_MASK; 5098c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(gpio_vals); i++) 5108c2ecf20Sopenharmony_ci if (gpio_vals[i] == result) 5118c2ecf20Sopenharmony_ci return juli_rates[i]; 5128c2ecf20Sopenharmony_ci return 0; 5138c2ecf20Sopenharmony_ci} 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci/* setting new rate */ 5168c2ecf20Sopenharmony_cistatic void juli_set_rate(struct snd_ice1712 *ice, unsigned int rate) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci unsigned int old, new; 5198c2ecf20Sopenharmony_ci unsigned char val; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci old = ice->gpio.get_data(ice); 5228c2ecf20Sopenharmony_ci new = (old & ~GPIO_RATE_MASK) | get_gpio_val(rate); 5238c2ecf20Sopenharmony_ci /* dev_dbg(ice->card->dev, "JULI - set_rate: old %x, new %x\n", 5248c2ecf20Sopenharmony_ci old & GPIO_RATE_MASK, 5258c2ecf20Sopenharmony_ci new & GPIO_RATE_MASK); */ 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci ice->gpio.set_data(ice, new); 5288c2ecf20Sopenharmony_ci /* switching to external clock - supplied by external circuits */ 5298c2ecf20Sopenharmony_ci val = inb(ICEMT1724(ice, RATE)); 5308c2ecf20Sopenharmony_ci outb(val | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE)); 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cistatic inline unsigned char juli_set_mclk(struct snd_ice1712 *ice, 5348c2ecf20Sopenharmony_ci unsigned int rate) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci /* no change in master clock */ 5378c2ecf20Sopenharmony_ci return 0; 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci/* setting clock to external - SPDIF */ 5418c2ecf20Sopenharmony_cistatic int juli_set_spdif_clock(struct snd_ice1712 *ice, int type) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci unsigned int old; 5448c2ecf20Sopenharmony_ci old = ice->gpio.get_data(ice); 5458c2ecf20Sopenharmony_ci /* external clock (= 0), multiply 1x, 48kHz */ 5468c2ecf20Sopenharmony_ci ice->gpio.set_data(ice, (old & ~GPIO_RATE_MASK) | GPIO_MULTI_1X | 5478c2ecf20Sopenharmony_ci GPIO_FREQ_48KHZ); 5488c2ecf20Sopenharmony_ci return 0; 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci/* Called when ak4114 detects change in the input SPDIF stream */ 5528c2ecf20Sopenharmony_cistatic void juli_ak4114_change(struct ak4114 *ak4114, unsigned char c0, 5538c2ecf20Sopenharmony_ci unsigned char c1) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = ak4114->change_callback_private; 5568c2ecf20Sopenharmony_ci int rate; 5578c2ecf20Sopenharmony_ci if (ice->is_spdif_master(ice) && c1) { 5588c2ecf20Sopenharmony_ci /* only for SPDIF master mode, rate was changed */ 5598c2ecf20Sopenharmony_ci rate = snd_ak4114_external_rate(ak4114); 5608c2ecf20Sopenharmony_ci /* dev_dbg(ice->card->dev, "ak4114 - input rate changed to %d\n", 5618c2ecf20Sopenharmony_ci rate); */ 5628c2ecf20Sopenharmony_ci juli_akm_set_rate_val(ice->akm, rate); 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic int juli_init(struct snd_ice1712 *ice) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci static const unsigned char ak4114_init_vals[] = { 5698c2ecf20Sopenharmony_ci /* AK4117_REG_PWRDN */ AK4114_RST | AK4114_PWN | 5708c2ecf20Sopenharmony_ci AK4114_OCKS0 | AK4114_OCKS1, 5718c2ecf20Sopenharmony_ci /* AK4114_REQ_FORMAT */ AK4114_DIF_I24I2S, 5728c2ecf20Sopenharmony_ci /* AK4114_REG_IO0 */ AK4114_TX1E, 5738c2ecf20Sopenharmony_ci /* AK4114_REG_IO1 */ AK4114_EFH_1024 | AK4114_DIT | 5748c2ecf20Sopenharmony_ci AK4114_IPS(1), 5758c2ecf20Sopenharmony_ci /* AK4114_REG_INT0_MASK */ 0, 5768c2ecf20Sopenharmony_ci /* AK4114_REG_INT1_MASK */ 0 5778c2ecf20Sopenharmony_ci }; 5788c2ecf20Sopenharmony_ci static const unsigned char ak4114_init_txcsb[] = { 5798c2ecf20Sopenharmony_ci 0x41, 0x02, 0x2c, 0x00, 0x00 5808c2ecf20Sopenharmony_ci }; 5818c2ecf20Sopenharmony_ci int err; 5828c2ecf20Sopenharmony_ci struct juli_spec *spec; 5838c2ecf20Sopenharmony_ci struct snd_akm4xxx *ak; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci spec = kzalloc(sizeof(*spec), GFP_KERNEL); 5868c2ecf20Sopenharmony_ci if (!spec) 5878c2ecf20Sopenharmony_ci return -ENOMEM; 5888c2ecf20Sopenharmony_ci ice->spec = spec; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci err = snd_ak4114_create(ice->card, 5918c2ecf20Sopenharmony_ci juli_ak4114_read, 5928c2ecf20Sopenharmony_ci juli_ak4114_write, 5938c2ecf20Sopenharmony_ci ak4114_init_vals, ak4114_init_txcsb, 5948c2ecf20Sopenharmony_ci ice, &spec->ak4114); 5958c2ecf20Sopenharmony_ci if (err < 0) 5968c2ecf20Sopenharmony_ci return err; 5978c2ecf20Sopenharmony_ci /* callback for codecs rate setting */ 5988c2ecf20Sopenharmony_ci spec->ak4114->change_callback = juli_ak4114_change; 5998c2ecf20Sopenharmony_ci spec->ak4114->change_callback_private = ice; 6008c2ecf20Sopenharmony_ci /* AK4114 in Juli can detect external rate correctly */ 6018c2ecf20Sopenharmony_ci spec->ak4114->check_flags = 0; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci#if 0 6048c2ecf20Sopenharmony_ci/* 6058c2ecf20Sopenharmony_ci * it seems that the analog doughter board detection does not work reliably, so 6068c2ecf20Sopenharmony_ci * force the analog flag; it should be very rare (if ever) to come at Juli@ 6078c2ecf20Sopenharmony_ci * used without the analog daughter board 6088c2ecf20Sopenharmony_ci */ 6098c2ecf20Sopenharmony_ci spec->analog = (ice->gpio.get_data(ice) & GPIO_ANALOG_PRESENT) ? 0 : 1; 6108c2ecf20Sopenharmony_ci#else 6118c2ecf20Sopenharmony_ci spec->analog = 1; 6128c2ecf20Sopenharmony_ci#endif 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci if (spec->analog) { 6158c2ecf20Sopenharmony_ci dev_info(ice->card->dev, "juli@: analog I/O detected\n"); 6168c2ecf20Sopenharmony_ci ice->num_total_dacs = 2; 6178c2ecf20Sopenharmony_ci ice->num_total_adcs = 2; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci ice->akm = kzalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); 6208c2ecf20Sopenharmony_ci ak = ice->akm; 6218c2ecf20Sopenharmony_ci if (!ak) 6228c2ecf20Sopenharmony_ci return -ENOMEM; 6238c2ecf20Sopenharmony_ci ice->akm_codecs = 1; 6248c2ecf20Sopenharmony_ci err = snd_ice1712_akm4xxx_init(ak, &akm_juli_dac, NULL, ice); 6258c2ecf20Sopenharmony_ci if (err < 0) 6268c2ecf20Sopenharmony_ci return err; 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci /* juli is clocked by Xilinx array */ 6308c2ecf20Sopenharmony_ci ice->hw_rates = &juli_rates_info; 6318c2ecf20Sopenharmony_ci ice->is_spdif_master = juli_is_spdif_master; 6328c2ecf20Sopenharmony_ci ice->get_rate = juli_get_rate; 6338c2ecf20Sopenharmony_ci ice->set_rate = juli_set_rate; 6348c2ecf20Sopenharmony_ci ice->set_mclk = juli_set_mclk; 6358c2ecf20Sopenharmony_ci ice->set_spdif_clock = juli_set_spdif_clock; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci ice->spdif.ops.open = juli_spdif_in_open; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 6408c2ecf20Sopenharmony_ci ice->pm_resume = juli_resume; 6418c2ecf20Sopenharmony_ci ice->pm_suspend = juli_suspend; 6428c2ecf20Sopenharmony_ci ice->pm_suspend_enabled = 1; 6438c2ecf20Sopenharmony_ci#endif 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci return 0; 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci/* 6508c2ecf20Sopenharmony_ci * Juli@ boards don't provide the EEPROM data except for the vendor IDs. 6518c2ecf20Sopenharmony_ci * hence the driver needs to sets up it properly. 6528c2ecf20Sopenharmony_ci */ 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_cistatic const unsigned char juli_eeprom[] = { 6558c2ecf20Sopenharmony_ci [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401, 1xADC, 1xDACs, 6568c2ecf20Sopenharmony_ci SPDIF in */ 6578c2ecf20Sopenharmony_ci [ICE_EEP2_ACLINK] = 0x80, /* I2S */ 6588c2ecf20Sopenharmony_ci [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */ 6598c2ecf20Sopenharmony_ci [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, spdif-in */ 6608c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_DIR] = 0x9f, /* 5, 6:inputs; 7, 4-0 outputs*/ 6618c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_DIR1] = 0xff, 6628c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_DIR2] = 0x7f, 6638c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_MASK] = 0x60, /* 5, 6: locked; 7, 4-0 writable */ 6648c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_MASK1] = 0x00, /* 0-7 writable */ 6658c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_MASK2] = 0x7f, 6668c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_STATE] = GPIO_FREQ_48KHZ | GPIO_MULTI_1X | 6678c2ecf20Sopenharmony_ci GPIO_INTERNAL_CLOCK, /* internal clock, multiple 1x, 48kHz*/ 6688c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_STATE1] = 0x00, /* unmuted */ 6698c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_STATE2] = 0x00, 6708c2ecf20Sopenharmony_ci}; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci/* entry point */ 6738c2ecf20Sopenharmony_cistruct snd_ice1712_card_info snd_vt1724_juli_cards[] = { 6748c2ecf20Sopenharmony_ci { 6758c2ecf20Sopenharmony_ci .subvendor = VT1724_SUBDEVICE_JULI, 6768c2ecf20Sopenharmony_ci .name = "ESI Juli@", 6778c2ecf20Sopenharmony_ci .model = "juli", 6788c2ecf20Sopenharmony_ci .chip_init = juli_init, 6798c2ecf20Sopenharmony_ci .build_controls = juli_add_controls, 6808c2ecf20Sopenharmony_ci .eeprom_size = sizeof(juli_eeprom), 6818c2ecf20Sopenharmony_ci .eeprom_data = juli_eeprom, 6828c2ecf20Sopenharmony_ci }, 6838c2ecf20Sopenharmony_ci { } /* terminator */ 6848c2ecf20Sopenharmony_ci}; 685