11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 26ef80706SPavel Hofman /* 36ef80706SPavel Hofman * ALSA driver for ICEnsemble VT1724 (Envy24HT) 46ef80706SPavel Hofman * 56ef80706SPavel Hofman * Lowlevel functions for Infrasonic Quartet 66ef80706SPavel Hofman * 76ef80706SPavel Hofman * Copyright (c) 2009 Pavel Hofman <pavel.hofman@ivitera.com> 86ef80706SPavel Hofman */ 96ef80706SPavel Hofman 106ef80706SPavel Hofman #include <linux/delay.h> 116ef80706SPavel Hofman #include <linux/interrupt.h> 126ef80706SPavel Hofman #include <linux/init.h> 136ef80706SPavel Hofman #include <linux/slab.h> 14338e17d3SJoey Pabalinas #include <linux/string.h> 156ef80706SPavel Hofman #include <sound/core.h> 166ef80706SPavel Hofman #include <sound/tlv.h> 176ef80706SPavel Hofman #include <sound/info.h> 186ef80706SPavel Hofman 196ef80706SPavel Hofman #include "ice1712.h" 206ef80706SPavel Hofman #include "envy24ht.h" 216ef80706SPavel Hofman #include <sound/ak4113.h> 226ef80706SPavel Hofman #include "quartet.h" 236ef80706SPavel Hofman 246ef80706SPavel Hofman struct qtet_spec { 256ef80706SPavel Hofman struct ak4113 *ak4113; 266ef80706SPavel Hofman unsigned int scr; /* system control register */ 276ef80706SPavel Hofman unsigned int mcr; /* monitoring control register */ 286ef80706SPavel Hofman unsigned int cpld; /* cpld register */ 296ef80706SPavel Hofman }; 306ef80706SPavel Hofman 316ef80706SPavel Hofman struct qtet_kcontrol_private { 326ef80706SPavel Hofman unsigned int bit; 336ef80706SPavel Hofman void (*set_register)(struct snd_ice1712 *ice, unsigned int val); 346ef80706SPavel Hofman unsigned int (*get_register)(struct snd_ice1712 *ice); 35597da2e4STakashi Iwai const char * const texts[2]; 366ef80706SPavel Hofman }; 376ef80706SPavel Hofman 386ef80706SPavel Hofman enum { 396ef80706SPavel Hofman IN12_SEL = 0, 406ef80706SPavel Hofman IN34_SEL, 416ef80706SPavel Hofman AIN34_SEL, 426ef80706SPavel Hofman COAX_OUT, 436ef80706SPavel Hofman IN12_MON12, 446ef80706SPavel Hofman IN12_MON34, 456ef80706SPavel Hofman IN34_MON12, 466ef80706SPavel Hofman IN34_MON34, 476ef80706SPavel Hofman OUT12_MON34, 486ef80706SPavel Hofman OUT34_MON12, 496ef80706SPavel Hofman }; 506ef80706SPavel Hofman 51a2af050fSTakashi Iwai static const char * const ext_clock_names[3] = {"IEC958 In", "Word Clock 1xFS", 526ef80706SPavel Hofman "Word Clock 256xFS"}; 536ef80706SPavel Hofman 546ef80706SPavel Hofman /* chip address on I2C bus */ 556ef80706SPavel Hofman #define AK4113_ADDR 0x26 /* S/PDIF receiver */ 566ef80706SPavel Hofman 576ef80706SPavel Hofman /* chip address on SPI bus */ 586ef80706SPavel Hofman #define AK4620_ADDR 0x02 /* ADC/DAC */ 596ef80706SPavel Hofman 606ef80706SPavel Hofman 616ef80706SPavel Hofman /* 626ef80706SPavel Hofman * GPIO pins 636ef80706SPavel Hofman */ 646ef80706SPavel Hofman 656ef80706SPavel Hofman /* GPIO0 - O - DATA0, def. 0 */ 666ef80706SPavel Hofman #define GPIO_D0 (1<<0) 676ef80706SPavel Hofman /* GPIO1 - I/O - DATA1, Jack Detect Input0 (0:present, 1:missing), def. 1 */ 686ef80706SPavel Hofman #define GPIO_D1_JACKDTC0 (1<<1) 696ef80706SPavel Hofman /* GPIO2 - I/O - DATA2, Jack Detect Input1 (0:present, 1:missing), def. 1 */ 706ef80706SPavel Hofman #define GPIO_D2_JACKDTC1 (1<<2) 716ef80706SPavel Hofman /* GPIO3 - I/O - DATA3, def. 1 */ 726ef80706SPavel Hofman #define GPIO_D3 (1<<3) 736ef80706SPavel Hofman /* GPIO4 - I/O - DATA4, SPI CDTO, def. 1 */ 746ef80706SPavel Hofman #define GPIO_D4_SPI_CDTO (1<<4) 756ef80706SPavel Hofman /* GPIO5 - I/O - DATA5, SPI CCLK, def. 1 */ 766ef80706SPavel Hofman #define GPIO_D5_SPI_CCLK (1<<5) 776ef80706SPavel Hofman /* GPIO6 - I/O - DATA6, Cable Detect Input (0:detected, 1:not detected */ 786ef80706SPavel Hofman #define GPIO_D6_CD (1<<6) 796ef80706SPavel Hofman /* GPIO7 - I/O - DATA7, Device Detect Input (0:detected, 1:not detected */ 806ef80706SPavel Hofman #define GPIO_D7_DD (1<<7) 816ef80706SPavel Hofman /* GPIO8 - O - CPLD Chip Select, def. 1 */ 826ef80706SPavel Hofman #define GPIO_CPLD_CSN (1<<8) 836ef80706SPavel Hofman /* GPIO9 - O - CPLD register read/write (0:write, 1:read), def. 0 */ 846ef80706SPavel Hofman #define GPIO_CPLD_RW (1<<9) 856ef80706SPavel Hofman /* GPIO10 - O - SPI Chip Select for CODEC#0, def. 1 */ 866ef80706SPavel Hofman #define GPIO_SPI_CSN0 (1<<10) 876ef80706SPavel Hofman /* GPIO11 - O - SPI Chip Select for CODEC#1, def. 1 */ 886ef80706SPavel Hofman #define GPIO_SPI_CSN1 (1<<11) 896ef80706SPavel Hofman /* GPIO12 - O - Ex. Register Output Enable (0:enable, 1:disable), def. 1, 906ef80706SPavel Hofman * init 0 */ 916ef80706SPavel Hofman #define GPIO_EX_GPIOE (1<<12) 926ef80706SPavel Hofman /* GPIO13 - O - Ex. Register0 Chip Select for System Control Register, 936ef80706SPavel Hofman * def. 1 */ 946ef80706SPavel Hofman #define GPIO_SCR (1<<13) 956ef80706SPavel Hofman /* GPIO14 - O - Ex. Register1 Chip Select for Monitor Control Register, 966ef80706SPavel Hofman * def. 1 */ 976ef80706SPavel Hofman #define GPIO_MCR (1<<14) 986ef80706SPavel Hofman 996ef80706SPavel Hofman #define GPIO_SPI_ALL (GPIO_D4_SPI_CDTO | GPIO_D5_SPI_CCLK |\ 1006ef80706SPavel Hofman GPIO_SPI_CSN0 | GPIO_SPI_CSN1) 1016ef80706SPavel Hofman 1026ef80706SPavel Hofman #define GPIO_DATA_MASK (GPIO_D0 | GPIO_D1_JACKDTC0 | \ 1036ef80706SPavel Hofman GPIO_D2_JACKDTC1 | GPIO_D3 | \ 1046ef80706SPavel Hofman GPIO_D4_SPI_CDTO | GPIO_D5_SPI_CCLK | \ 1056ef80706SPavel Hofman GPIO_D6_CD | GPIO_D7_DD) 1066ef80706SPavel Hofman 1076ef80706SPavel Hofman /* System Control Register GPIO_SCR data bits */ 1086ef80706SPavel Hofman /* Mic/Line select relay (0:line, 1:mic) */ 1096ef80706SPavel Hofman #define SCR_RELAY GPIO_D0 1106ef80706SPavel Hofman /* Phantom power drive control (0:5V, 1:48V) */ 1116ef80706SPavel Hofman #define SCR_PHP_V GPIO_D1_JACKDTC0 1126ef80706SPavel Hofman /* H/W mute control (0:Normal, 1:Mute) */ 1136ef80706SPavel Hofman #define SCR_MUTE GPIO_D2_JACKDTC1 1146ef80706SPavel Hofman /* Phantom power control (0:Phantom on, 1:off) */ 1156ef80706SPavel Hofman #define SCR_PHP GPIO_D3 1166ef80706SPavel Hofman /* Analog input 1/2 Source Select */ 1176ef80706SPavel Hofman #define SCR_AIN12_SEL0 GPIO_D4_SPI_CDTO 1186ef80706SPavel Hofman #define SCR_AIN12_SEL1 GPIO_D5_SPI_CCLK 1196ef80706SPavel Hofman /* Analog input 3/4 Source Select (0:line, 1:hi-z) */ 1206ef80706SPavel Hofman #define SCR_AIN34_SEL GPIO_D6_CD 1216ef80706SPavel Hofman /* Codec Power Down (0:power down, 1:normal) */ 1226ef80706SPavel Hofman #define SCR_CODEC_PDN GPIO_D7_DD 1236ef80706SPavel Hofman 1246ef80706SPavel Hofman #define SCR_AIN12_LINE (0) 1256ef80706SPavel Hofman #define SCR_AIN12_MIC (SCR_AIN12_SEL0) 1266ef80706SPavel Hofman #define SCR_AIN12_LOWCUT (SCR_AIN12_SEL1 | SCR_AIN12_SEL0) 1276ef80706SPavel Hofman 1286ef80706SPavel Hofman /* Monitor Control Register GPIO_MCR data bits */ 1296ef80706SPavel Hofman /* Input 1/2 to Monitor 1/2 (0:off, 1:on) */ 1306ef80706SPavel Hofman #define MCR_IN12_MON12 GPIO_D0 1316ef80706SPavel Hofman /* Input 1/2 to Monitor 3/4 (0:off, 1:on) */ 1326ef80706SPavel Hofman #define MCR_IN12_MON34 GPIO_D1_JACKDTC0 1336ef80706SPavel Hofman /* Input 3/4 to Monitor 1/2 (0:off, 1:on) */ 1346ef80706SPavel Hofman #define MCR_IN34_MON12 GPIO_D2_JACKDTC1 1356ef80706SPavel Hofman /* Input 3/4 to Monitor 3/4 (0:off, 1:on) */ 1366ef80706SPavel Hofman #define MCR_IN34_MON34 GPIO_D3 1376ef80706SPavel Hofman /* Output to Monitor 1/2 (0:off, 1:on) */ 1386ef80706SPavel Hofman #define MCR_OUT34_MON12 GPIO_D4_SPI_CDTO 1396ef80706SPavel Hofman /* Output to Monitor 3/4 (0:off, 1:on) */ 1406ef80706SPavel Hofman #define MCR_OUT12_MON34 GPIO_D5_SPI_CCLK 1416ef80706SPavel Hofman 1426ef80706SPavel Hofman /* CPLD Register DATA bits */ 1436ef80706SPavel Hofman /* Clock Rate Select */ 1446ef80706SPavel Hofman #define CPLD_CKS0 GPIO_D0 1456ef80706SPavel Hofman #define CPLD_CKS1 GPIO_D1_JACKDTC0 1466ef80706SPavel Hofman #define CPLD_CKS2 GPIO_D2_JACKDTC1 1476ef80706SPavel Hofman /* Sync Source Select (0:Internal, 1:External) */ 1486ef80706SPavel Hofman #define CPLD_SYNC_SEL GPIO_D3 1496ef80706SPavel Hofman /* Word Clock FS Select (0:FS, 1:256FS) */ 1506ef80706SPavel Hofman #define CPLD_WORD_SEL GPIO_D4_SPI_CDTO 1516ef80706SPavel Hofman /* Coaxial Output Source (IS-Link) (0:SPDIF, 1:I2S) */ 1526ef80706SPavel Hofman #define CPLD_COAX_OUT GPIO_D5_SPI_CCLK 1536ef80706SPavel Hofman /* Input 1/2 Source Select (0:Analog12, 1:An34) */ 1546ef80706SPavel Hofman #define CPLD_IN12_SEL GPIO_D6_CD 1556ef80706SPavel Hofman /* Input 3/4 Source Select (0:Analog34, 1:Digital In) */ 1566ef80706SPavel Hofman #define CPLD_IN34_SEL GPIO_D7_DD 1576ef80706SPavel Hofman 1586ef80706SPavel Hofman /* internal clock (CPLD_SYNC_SEL = 0) options */ 1596ef80706SPavel Hofman #define CPLD_CKS_44100HZ (0) 1606ef80706SPavel Hofman #define CPLD_CKS_48000HZ (CPLD_CKS0) 1616ef80706SPavel Hofman #define CPLD_CKS_88200HZ (CPLD_CKS1) 1626ef80706SPavel Hofman #define CPLD_CKS_96000HZ (CPLD_CKS1 | CPLD_CKS0) 1636ef80706SPavel Hofman #define CPLD_CKS_176400HZ (CPLD_CKS2) 1646ef80706SPavel Hofman #define CPLD_CKS_192000HZ (CPLD_CKS2 | CPLD_CKS0) 1656ef80706SPavel Hofman 1666ef80706SPavel Hofman #define CPLD_CKS_MASK (CPLD_CKS0 | CPLD_CKS1 | CPLD_CKS2) 1676ef80706SPavel Hofman 1686ef80706SPavel Hofman /* external clock (CPLD_SYNC_SEL = 1) options */ 1696ef80706SPavel Hofman /* external clock - SPDIF */ 1706ef80706SPavel Hofman #define CPLD_EXT_SPDIF (0 | CPLD_SYNC_SEL) 1716ef80706SPavel Hofman /* external clock - WordClock 1xfs */ 1726ef80706SPavel Hofman #define CPLD_EXT_WORDCLOCK_1FS (CPLD_CKS1 | CPLD_SYNC_SEL) 1736ef80706SPavel Hofman /* external clock - WordClock 256xfs */ 1746ef80706SPavel Hofman #define CPLD_EXT_WORDCLOCK_256FS (CPLD_CKS1 | CPLD_WORD_SEL |\ 1756ef80706SPavel Hofman CPLD_SYNC_SEL) 1766ef80706SPavel Hofman 1776ef80706SPavel Hofman #define EXT_SPDIF_TYPE 0 1786ef80706SPavel Hofman #define EXT_WORDCLOCK_1FS_TYPE 1 1796ef80706SPavel Hofman #define EXT_WORDCLOCK_256FS_TYPE 2 1806ef80706SPavel Hofman 1816ef80706SPavel Hofman #define AK4620_DFS0 (1<<0) 1826ef80706SPavel Hofman #define AK4620_DFS1 (1<<1) 1836ef80706SPavel Hofman #define AK4620_CKS0 (1<<2) 1846ef80706SPavel Hofman #define AK4620_CKS1 (1<<3) 1856ef80706SPavel Hofman /* Clock and Format Control register */ 1866ef80706SPavel Hofman #define AK4620_DFS_REG 0x02 1876ef80706SPavel Hofman 1886ef80706SPavel Hofman /* Deem and Volume Control register */ 1896ef80706SPavel Hofman #define AK4620_DEEMVOL_REG 0x03 1906ef80706SPavel Hofman #define AK4620_SMUTE (1<<7) 1916ef80706SPavel Hofman 1926ef80706SPavel Hofman /* 1936ef80706SPavel Hofman * Conversion from int value to its binary form. Used for debugging. 1946ef80706SPavel Hofman * The output buffer must be allocated prior to calling the function. 1956ef80706SPavel Hofman */ 1966ef80706SPavel Hofman static char *get_binary(char *buffer, int value) 1976ef80706SPavel Hofman { 1986ef80706SPavel Hofman int i, j, pos; 1996ef80706SPavel Hofman pos = 0; 2006ef80706SPavel Hofman for (i = 0; i < 4; ++i) { 2016ef80706SPavel Hofman for (j = 0; j < 8; ++j) { 2026ef80706SPavel Hofman if (value & (1 << (31-(i*8 + j)))) 2036ef80706SPavel Hofman buffer[pos] = '1'; 2046ef80706SPavel Hofman else 2056ef80706SPavel Hofman buffer[pos] = '0'; 2066ef80706SPavel Hofman pos++; 2076ef80706SPavel Hofman } 2086ef80706SPavel Hofman if (i < 3) { 2096ef80706SPavel Hofman buffer[pos] = ' '; 2106ef80706SPavel Hofman pos++; 2116ef80706SPavel Hofman } 2126ef80706SPavel Hofman } 2136ef80706SPavel Hofman buffer[pos] = '\0'; 2146ef80706SPavel Hofman return buffer; 2156ef80706SPavel Hofman } 2166ef80706SPavel Hofman 2176ef80706SPavel Hofman /* 2186ef80706SPavel Hofman * Initial setup of the conversion array GPIO <-> rate 2196ef80706SPavel Hofman */ 220965f19beSTakashi Iwai static const unsigned int qtet_rates[] = { 2216ef80706SPavel Hofman 44100, 48000, 88200, 2226ef80706SPavel Hofman 96000, 176400, 192000, 2236ef80706SPavel Hofman }; 2246ef80706SPavel Hofman 225965f19beSTakashi Iwai static const unsigned int cks_vals[] = { 2266ef80706SPavel Hofman CPLD_CKS_44100HZ, CPLD_CKS_48000HZ, CPLD_CKS_88200HZ, 2276ef80706SPavel Hofman CPLD_CKS_96000HZ, CPLD_CKS_176400HZ, CPLD_CKS_192000HZ, 2286ef80706SPavel Hofman }; 2296ef80706SPavel Hofman 230965f19beSTakashi Iwai static const struct snd_pcm_hw_constraint_list qtet_rates_info = { 2316ef80706SPavel Hofman .count = ARRAY_SIZE(qtet_rates), 2326ef80706SPavel Hofman .list = qtet_rates, 2336ef80706SPavel Hofman .mask = 0, 2346ef80706SPavel Hofman }; 2356ef80706SPavel Hofman 2366ef80706SPavel Hofman static void qtet_ak4113_write(void *private_data, unsigned char reg, 2376ef80706SPavel Hofman unsigned char val) 2386ef80706SPavel Hofman { 2396ef80706SPavel Hofman snd_vt1724_write_i2c((struct snd_ice1712 *)private_data, AK4113_ADDR, 2406ef80706SPavel Hofman reg, val); 2416ef80706SPavel Hofman } 2426ef80706SPavel Hofman 2436ef80706SPavel Hofman static unsigned char qtet_ak4113_read(void *private_data, unsigned char reg) 2446ef80706SPavel Hofman { 2456ef80706SPavel Hofman return snd_vt1724_read_i2c((struct snd_ice1712 *)private_data, 2466ef80706SPavel Hofman AK4113_ADDR, reg); 2476ef80706SPavel Hofman } 2486ef80706SPavel Hofman 2496ef80706SPavel Hofman 2506ef80706SPavel Hofman /* 2516ef80706SPavel Hofman * AK4620 section 2526ef80706SPavel Hofman */ 2536ef80706SPavel Hofman 2546ef80706SPavel Hofman /* 2556ef80706SPavel Hofman * Write data to addr register of ak4620 2566ef80706SPavel Hofman */ 2576ef80706SPavel Hofman static void qtet_akm_write(struct snd_akm4xxx *ak, int chip, 2586ef80706SPavel Hofman unsigned char addr, unsigned char data) 2596ef80706SPavel Hofman { 2606ef80706SPavel Hofman unsigned int tmp, orig_dir; 2616ef80706SPavel Hofman int idx; 2626ef80706SPavel Hofman unsigned int addrdata; 2636ef80706SPavel Hofman struct snd_ice1712 *ice = ak->private_data[0]; 2646ef80706SPavel Hofman 2656ef80706SPavel Hofman if (snd_BUG_ON(chip < 0 || chip >= 4)) 2666ef80706SPavel Hofman return; 2676dfb5affSTakashi Iwai /*dev_dbg(ice->card->dev, "Writing to AK4620: chip=%d, addr=0x%x, 2686ef80706SPavel Hofman data=0x%x\n", chip, addr, data);*/ 2696ef80706SPavel Hofman orig_dir = ice->gpio.get_dir(ice); 2706ef80706SPavel Hofman ice->gpio.set_dir(ice, orig_dir | GPIO_SPI_ALL); 2716ef80706SPavel Hofman /* set mask - only SPI bits */ 2726ef80706SPavel Hofman ice->gpio.set_mask(ice, ~GPIO_SPI_ALL); 2736ef80706SPavel Hofman 2746ef80706SPavel Hofman tmp = ice->gpio.get_data(ice); 2756ef80706SPavel Hofman /* high all */ 2766ef80706SPavel Hofman tmp |= GPIO_SPI_ALL; 2776ef80706SPavel Hofman ice->gpio.set_data(ice, tmp); 2786ef80706SPavel Hofman udelay(100); 2796ef80706SPavel Hofman /* drop chip select */ 2806ef80706SPavel Hofman if (chip) 2816ef80706SPavel Hofman /* CODEC 1 */ 2826ef80706SPavel Hofman tmp &= ~GPIO_SPI_CSN1; 2836ef80706SPavel Hofman else 2846ef80706SPavel Hofman tmp &= ~GPIO_SPI_CSN0; 2856ef80706SPavel Hofman ice->gpio.set_data(ice, tmp); 2866ef80706SPavel Hofman udelay(100); 2876ef80706SPavel Hofman 2886ef80706SPavel Hofman /* build I2C address + data byte */ 2896ef80706SPavel Hofman addrdata = (AK4620_ADDR << 6) | 0x20 | (addr & 0x1f); 2906ef80706SPavel Hofman addrdata = (addrdata << 8) | data; 2916ef80706SPavel Hofman for (idx = 15; idx >= 0; idx--) { 2926ef80706SPavel Hofman /* drop clock */ 2936ef80706SPavel Hofman tmp &= ~GPIO_D5_SPI_CCLK; 2946ef80706SPavel Hofman ice->gpio.set_data(ice, tmp); 2956ef80706SPavel Hofman udelay(100); 2966ef80706SPavel Hofman /* set data */ 2976ef80706SPavel Hofman if (addrdata & (1 << idx)) 2986ef80706SPavel Hofman tmp |= GPIO_D4_SPI_CDTO; 2996ef80706SPavel Hofman else 3006ef80706SPavel Hofman tmp &= ~GPIO_D4_SPI_CDTO; 3016ef80706SPavel Hofman ice->gpio.set_data(ice, tmp); 3026ef80706SPavel Hofman udelay(100); 3036ef80706SPavel Hofman /* raise clock */ 3046ef80706SPavel Hofman tmp |= GPIO_D5_SPI_CCLK; 3056ef80706SPavel Hofman ice->gpio.set_data(ice, tmp); 3066ef80706SPavel Hofman udelay(100); 3076ef80706SPavel Hofman } 3086ef80706SPavel Hofman /* all back to 1 */ 3096ef80706SPavel Hofman tmp |= GPIO_SPI_ALL; 3106ef80706SPavel Hofman ice->gpio.set_data(ice, tmp); 3116ef80706SPavel Hofman udelay(100); 3126ef80706SPavel Hofman 3136ef80706SPavel Hofman /* return all gpios to non-writable */ 3146ef80706SPavel Hofman ice->gpio.set_mask(ice, 0xffffff); 3156ef80706SPavel Hofman /* restore GPIOs direction */ 3166ef80706SPavel Hofman ice->gpio.set_dir(ice, orig_dir); 3176ef80706SPavel Hofman } 3186ef80706SPavel Hofman 3196ef80706SPavel Hofman static void qtet_akm_set_regs(struct snd_akm4xxx *ak, unsigned char addr, 3206ef80706SPavel Hofman unsigned char mask, unsigned char value) 3216ef80706SPavel Hofman { 3226ef80706SPavel Hofman unsigned char tmp; 3236ef80706SPavel Hofman int chip; 3246ef80706SPavel Hofman for (chip = 0; chip < ak->num_chips; chip++) { 3256ef80706SPavel Hofman tmp = snd_akm4xxx_get(ak, chip, addr); 3266ef80706SPavel Hofman /* clear the bits */ 3276ef80706SPavel Hofman tmp &= ~mask; 3286ef80706SPavel Hofman /* set the new bits */ 3296ef80706SPavel Hofman tmp |= value; 3306ef80706SPavel Hofman snd_akm4xxx_write(ak, chip, addr, tmp); 3316ef80706SPavel Hofman } 3326ef80706SPavel Hofman } 3336ef80706SPavel Hofman 3346ef80706SPavel Hofman /* 3356ef80706SPavel Hofman * change the rate of AK4620 3366ef80706SPavel Hofman */ 3376ef80706SPavel Hofman static void qtet_akm_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) 3386ef80706SPavel Hofman { 3396ef80706SPavel Hofman unsigned char ak4620_dfs; 3406ef80706SPavel Hofman 3416ef80706SPavel Hofman if (rate == 0) /* no hint - S/PDIF input is master or the new spdif 3426ef80706SPavel Hofman input rate undetected, simply return */ 3436ef80706SPavel Hofman return; 3446ef80706SPavel Hofman 3456ef80706SPavel Hofman /* adjust DFS on codecs - see datasheet */ 3466ef80706SPavel Hofman if (rate > 108000) 3476ef80706SPavel Hofman ak4620_dfs = AK4620_DFS1 | AK4620_CKS1; 3486ef80706SPavel Hofman else if (rate > 54000) 3496ef80706SPavel Hofman ak4620_dfs = AK4620_DFS0 | AK4620_CKS0; 3506ef80706SPavel Hofman else 3516ef80706SPavel Hofman ak4620_dfs = 0; 3526ef80706SPavel Hofman 3536ef80706SPavel Hofman /* set new value */ 3546ef80706SPavel Hofman qtet_akm_set_regs(ak, AK4620_DFS_REG, AK4620_DFS0 | AK4620_DFS1 | 3556ef80706SPavel Hofman AK4620_CKS0 | AK4620_CKS1, ak4620_dfs); 3566ef80706SPavel Hofman } 3576ef80706SPavel Hofman 3586ef80706SPavel Hofman #define AK_CONTROL(xname, xch) { .name = xname, .num_channels = xch } 3596ef80706SPavel Hofman 3606ef80706SPavel Hofman #define PCM_12_PLAYBACK_VOLUME "PCM 1/2 Playback Volume" 3616ef80706SPavel Hofman #define PCM_34_PLAYBACK_VOLUME "PCM 3/4 Playback Volume" 3626ef80706SPavel Hofman #define PCM_12_CAPTURE_VOLUME "PCM 1/2 Capture Volume" 3636ef80706SPavel Hofman #define PCM_34_CAPTURE_VOLUME "PCM 3/4 Capture Volume" 3646ef80706SPavel Hofman 3656ef80706SPavel Hofman static const struct snd_akm4xxx_dac_channel qtet_dac[] = { 3666ef80706SPavel Hofman AK_CONTROL(PCM_12_PLAYBACK_VOLUME, 2), 3676ef80706SPavel Hofman AK_CONTROL(PCM_34_PLAYBACK_VOLUME, 2), 3686ef80706SPavel Hofman }; 3696ef80706SPavel Hofman 3706ef80706SPavel Hofman static const struct snd_akm4xxx_adc_channel qtet_adc[] = { 3716ef80706SPavel Hofman AK_CONTROL(PCM_12_CAPTURE_VOLUME, 2), 3726ef80706SPavel Hofman AK_CONTROL(PCM_34_CAPTURE_VOLUME, 2), 3736ef80706SPavel Hofman }; 3746ef80706SPavel Hofman 3753135432eSBhumika Goyal static const struct snd_akm4xxx akm_qtet_dac = { 3766ef80706SPavel Hofman .type = SND_AK4620, 3776ef80706SPavel Hofman .num_dacs = 4, /* DAC1 - Output 12 3786ef80706SPavel Hofman */ 3796ef80706SPavel Hofman .num_adcs = 4, /* ADC1 - Input 12 3806ef80706SPavel Hofman */ 3816ef80706SPavel Hofman .ops = { 3826ef80706SPavel Hofman .write = qtet_akm_write, 3836ef80706SPavel Hofman .set_rate_val = qtet_akm_set_rate_val, 3846ef80706SPavel Hofman }, 3856ef80706SPavel Hofman .dac_info = qtet_dac, 3866ef80706SPavel Hofman .adc_info = qtet_adc, 3876ef80706SPavel Hofman }; 3886ef80706SPavel Hofman 3896ef80706SPavel Hofman /* Communication routines with the CPLD */ 3906ef80706SPavel Hofman 3916ef80706SPavel Hofman 3926ef80706SPavel Hofman /* Writes data to external register reg, both reg and data are 3936ef80706SPavel Hofman * GPIO representations */ 3946ef80706SPavel Hofman static void reg_write(struct snd_ice1712 *ice, unsigned int reg, 3956ef80706SPavel Hofman unsigned int data) 3966ef80706SPavel Hofman { 3976ef80706SPavel Hofman unsigned int tmp; 3986ef80706SPavel Hofman 3996ef80706SPavel Hofman mutex_lock(&ice->gpio_mutex); 4006ef80706SPavel Hofman /* set direction of used GPIOs*/ 4016ef80706SPavel Hofman /* all outputs */ 4026ef80706SPavel Hofman tmp = 0x00ffff; 4036ef80706SPavel Hofman ice->gpio.set_dir(ice, tmp); 4046ef80706SPavel Hofman /* mask - writable bits */ 4056ef80706SPavel Hofman ice->gpio.set_mask(ice, ~(tmp)); 4066ef80706SPavel Hofman /* write the data */ 4076ef80706SPavel Hofman tmp = ice->gpio.get_data(ice); 4086ef80706SPavel Hofman tmp &= ~GPIO_DATA_MASK; 4096ef80706SPavel Hofman tmp |= data; 4106ef80706SPavel Hofman ice->gpio.set_data(ice, tmp); 4116ef80706SPavel Hofman udelay(100); 4126ef80706SPavel Hofman /* drop output enable */ 4136ef80706SPavel Hofman tmp &= ~GPIO_EX_GPIOE; 4146ef80706SPavel Hofman ice->gpio.set_data(ice, tmp); 4156ef80706SPavel Hofman udelay(100); 4166ef80706SPavel Hofman /* drop the register gpio */ 4176ef80706SPavel Hofman tmp &= ~reg; 4186ef80706SPavel Hofman ice->gpio.set_data(ice, tmp); 4196ef80706SPavel Hofman udelay(100); 4206ef80706SPavel Hofman /* raise the register GPIO */ 4216ef80706SPavel Hofman tmp |= reg; 4226ef80706SPavel Hofman ice->gpio.set_data(ice, tmp); 4236ef80706SPavel Hofman udelay(100); 4246ef80706SPavel Hofman 4256ef80706SPavel Hofman /* raise all data gpios */ 4266ef80706SPavel Hofman tmp |= GPIO_DATA_MASK; 4276ef80706SPavel Hofman ice->gpio.set_data(ice, tmp); 4286ef80706SPavel Hofman /* mask - immutable bits */ 4296ef80706SPavel Hofman ice->gpio.set_mask(ice, 0xffffff); 4306ef80706SPavel Hofman /* outputs only 8-15 */ 4316ef80706SPavel Hofman ice->gpio.set_dir(ice, 0x00ff00); 4326ef80706SPavel Hofman mutex_unlock(&ice->gpio_mutex); 4336ef80706SPavel Hofman } 4346ef80706SPavel Hofman 4356ef80706SPavel Hofman static unsigned int get_scr(struct snd_ice1712 *ice) 4366ef80706SPavel Hofman { 4376ef80706SPavel Hofman struct qtet_spec *spec = ice->spec; 4386ef80706SPavel Hofman return spec->scr; 4396ef80706SPavel Hofman } 4406ef80706SPavel Hofman 4416ef80706SPavel Hofman static unsigned int get_mcr(struct snd_ice1712 *ice) 4426ef80706SPavel Hofman { 4436ef80706SPavel Hofman struct qtet_spec *spec = ice->spec; 4446ef80706SPavel Hofman return spec->mcr; 4456ef80706SPavel Hofman } 4466ef80706SPavel Hofman 4476ef80706SPavel Hofman static unsigned int get_cpld(struct snd_ice1712 *ice) 4486ef80706SPavel Hofman { 4496ef80706SPavel Hofman struct qtet_spec *spec = ice->spec; 4506ef80706SPavel Hofman return spec->cpld; 4516ef80706SPavel Hofman } 4526ef80706SPavel Hofman 4536ef80706SPavel Hofman static void set_scr(struct snd_ice1712 *ice, unsigned int val) 4546ef80706SPavel Hofman { 4556ef80706SPavel Hofman struct qtet_spec *spec = ice->spec; 4566ef80706SPavel Hofman reg_write(ice, GPIO_SCR, val); 4576ef80706SPavel Hofman spec->scr = val; 4586ef80706SPavel Hofman } 4596ef80706SPavel Hofman 4606ef80706SPavel Hofman static void set_mcr(struct snd_ice1712 *ice, unsigned int val) 4616ef80706SPavel Hofman { 4626ef80706SPavel Hofman struct qtet_spec *spec = ice->spec; 4636ef80706SPavel Hofman reg_write(ice, GPIO_MCR, val); 4646ef80706SPavel Hofman spec->mcr = val; 4656ef80706SPavel Hofman } 4666ef80706SPavel Hofman 4676ef80706SPavel Hofman static void set_cpld(struct snd_ice1712 *ice, unsigned int val) 4686ef80706SPavel Hofman { 4696ef80706SPavel Hofman struct qtet_spec *spec = ice->spec; 4706ef80706SPavel Hofman reg_write(ice, GPIO_CPLD_CSN, val); 4716ef80706SPavel Hofman spec->cpld = val; 4726ef80706SPavel Hofman } 4733270f0ddSTakashi Iwai 4746ef80706SPavel Hofman static void proc_regs_read(struct snd_info_entry *entry, 4756ef80706SPavel Hofman struct snd_info_buffer *buffer) 4766ef80706SPavel Hofman { 4776ef80706SPavel Hofman struct snd_ice1712 *ice = entry->private_data; 4786ef80706SPavel Hofman char bin_buffer[36]; 4796ef80706SPavel Hofman 4806ef80706SPavel Hofman snd_iprintf(buffer, "SCR: %s\n", get_binary(bin_buffer, 4816ef80706SPavel Hofman get_scr(ice))); 4826ef80706SPavel Hofman snd_iprintf(buffer, "MCR: %s\n", get_binary(bin_buffer, 4836ef80706SPavel Hofman get_mcr(ice))); 4846ef80706SPavel Hofman snd_iprintf(buffer, "CPLD: %s\n", get_binary(bin_buffer, 4856ef80706SPavel Hofman get_cpld(ice))); 4866ef80706SPavel Hofman } 4876ef80706SPavel Hofman 4886ef80706SPavel Hofman static void proc_init(struct snd_ice1712 *ice) 4896ef80706SPavel Hofman { 49047f2769bSTakashi Iwai snd_card_ro_proc_new(ice->card, "quartet", ice, proc_regs_read); 4916ef80706SPavel Hofman } 4926ef80706SPavel Hofman 4936ef80706SPavel Hofman static int qtet_mute_get(struct snd_kcontrol *kcontrol, 4946ef80706SPavel Hofman struct snd_ctl_elem_value *ucontrol) 4956ef80706SPavel Hofman { 4966ef80706SPavel Hofman struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 4976ef80706SPavel Hofman unsigned int val; 4986ef80706SPavel Hofman val = get_scr(ice) & SCR_MUTE; 4996ef80706SPavel Hofman ucontrol->value.integer.value[0] = (val) ? 0 : 1; 5006ef80706SPavel Hofman return 0; 5016ef80706SPavel Hofman } 5026ef80706SPavel Hofman 5036ef80706SPavel Hofman static int qtet_mute_put(struct snd_kcontrol *kcontrol, 5046ef80706SPavel Hofman struct snd_ctl_elem_value *ucontrol) 5056ef80706SPavel Hofman { 5066ef80706SPavel Hofman struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 5076ef80706SPavel Hofman unsigned int old, new, smute; 5086ef80706SPavel Hofman old = get_scr(ice) & SCR_MUTE; 5096ef80706SPavel Hofman if (ucontrol->value.integer.value[0]) { 5106ef80706SPavel Hofman /* unmute */ 5116ef80706SPavel Hofman new = 0; 5126ef80706SPavel Hofman /* un-smuting DAC */ 5136ef80706SPavel Hofman smute = 0; 5146ef80706SPavel Hofman } else { 5156ef80706SPavel Hofman /* mute */ 5166ef80706SPavel Hofman new = SCR_MUTE; 5176ef80706SPavel Hofman /* smuting DAC */ 5186ef80706SPavel Hofman smute = AK4620_SMUTE; 5196ef80706SPavel Hofman } 5206ef80706SPavel Hofman if (old != new) { 5216ef80706SPavel Hofman struct snd_akm4xxx *ak = ice->akm; 5226ef80706SPavel Hofman set_scr(ice, (get_scr(ice) & ~SCR_MUTE) | new); 5236ef80706SPavel Hofman /* set smute */ 5246ef80706SPavel Hofman qtet_akm_set_regs(ak, AK4620_DEEMVOL_REG, AK4620_SMUTE, smute); 5256ef80706SPavel Hofman return 1; 5266ef80706SPavel Hofman } 5276ef80706SPavel Hofman /* no change */ 5286ef80706SPavel Hofman return 0; 5296ef80706SPavel Hofman } 5306ef80706SPavel Hofman 5316ef80706SPavel Hofman static int qtet_ain12_enum_info(struct snd_kcontrol *kcontrol, 5326ef80706SPavel Hofman struct snd_ctl_elem_info *uinfo) 5336ef80706SPavel Hofman { 534a2af050fSTakashi Iwai static const char * const texts[3] = 535a2af050fSTakashi Iwai {"Line In 1/2", "Mic", "Mic + Low-cut"}; 536597da2e4STakashi Iwai return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); 5376ef80706SPavel Hofman } 5386ef80706SPavel Hofman 5396ef80706SPavel Hofman static int qtet_ain12_sw_get(struct snd_kcontrol *kcontrol, 5406ef80706SPavel Hofman struct snd_ctl_elem_value *ucontrol) 5416ef80706SPavel Hofman { 5426ef80706SPavel Hofman struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 5436ef80706SPavel Hofman unsigned int val, result; 5446ef80706SPavel Hofman val = get_scr(ice) & (SCR_AIN12_SEL1 | SCR_AIN12_SEL0); 5456ef80706SPavel Hofman switch (val) { 5466ef80706SPavel Hofman case SCR_AIN12_LINE: 5476ef80706SPavel Hofman result = 0; 5486ef80706SPavel Hofman break; 5496ef80706SPavel Hofman case SCR_AIN12_MIC: 5506ef80706SPavel Hofman result = 1; 5516ef80706SPavel Hofman break; 5526ef80706SPavel Hofman case SCR_AIN12_LOWCUT: 5536ef80706SPavel Hofman result = 2; 5546ef80706SPavel Hofman break; 5556ef80706SPavel Hofman default: 5566ef80706SPavel Hofman /* BUG - no other combinations allowed */ 5576ef80706SPavel Hofman snd_BUG(); 5586ef80706SPavel Hofman result = 0; 5596ef80706SPavel Hofman } 5606ef80706SPavel Hofman ucontrol->value.integer.value[0] = result; 5616ef80706SPavel Hofman return 0; 5626ef80706SPavel Hofman } 5636ef80706SPavel Hofman 5646ef80706SPavel Hofman static int qtet_ain12_sw_put(struct snd_kcontrol *kcontrol, 5656ef80706SPavel Hofman struct snd_ctl_elem_value *ucontrol) 5666ef80706SPavel Hofman { 5676ef80706SPavel Hofman struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 5686ef80706SPavel Hofman unsigned int old, new, tmp, masked_old; 5696ef80706SPavel Hofman old = new = get_scr(ice); 5706ef80706SPavel Hofman masked_old = old & (SCR_AIN12_SEL1 | SCR_AIN12_SEL0); 5716ef80706SPavel Hofman tmp = ucontrol->value.integer.value[0]; 5726ef80706SPavel Hofman if (tmp == 2) 5736ef80706SPavel Hofman tmp = 3; /* binary 10 is not supported */ 5746ef80706SPavel Hofman tmp <<= 4; /* shifting to SCR_AIN12_SEL0 */ 5756ef80706SPavel Hofman if (tmp != masked_old) { 5766ef80706SPavel Hofman /* change requested */ 5776ef80706SPavel Hofman switch (tmp) { 5786ef80706SPavel Hofman case SCR_AIN12_LINE: 5796ef80706SPavel Hofman new = old & ~(SCR_AIN12_SEL1 | SCR_AIN12_SEL0); 5806ef80706SPavel Hofman set_scr(ice, new); 5816ef80706SPavel Hofman /* turn off relay */ 5826ef80706SPavel Hofman new &= ~SCR_RELAY; 5836ef80706SPavel Hofman set_scr(ice, new); 5846ef80706SPavel Hofman break; 5856ef80706SPavel Hofman case SCR_AIN12_MIC: 5866ef80706SPavel Hofman /* turn on relay */ 5876ef80706SPavel Hofman new = old | SCR_RELAY; 5886ef80706SPavel Hofman set_scr(ice, new); 5896ef80706SPavel Hofman new = (new & ~SCR_AIN12_SEL1) | SCR_AIN12_SEL0; 5906ef80706SPavel Hofman set_scr(ice, new); 5916ef80706SPavel Hofman break; 5926ef80706SPavel Hofman case SCR_AIN12_LOWCUT: 5936ef80706SPavel Hofman /* turn on relay */ 5946ef80706SPavel Hofman new = old | SCR_RELAY; 5956ef80706SPavel Hofman set_scr(ice, new); 5966ef80706SPavel Hofman new |= SCR_AIN12_SEL1 | SCR_AIN12_SEL0; 5976ef80706SPavel Hofman set_scr(ice, new); 5986ef80706SPavel Hofman break; 5996ef80706SPavel Hofman default: 6006ef80706SPavel Hofman snd_BUG(); 6016ef80706SPavel Hofman } 6026ef80706SPavel Hofman return 1; 6036ef80706SPavel Hofman } 6046ef80706SPavel Hofman /* no change */ 6056ef80706SPavel Hofman return 0; 6066ef80706SPavel Hofman } 6076ef80706SPavel Hofman 6086ef80706SPavel Hofman static int qtet_php_get(struct snd_kcontrol *kcontrol, 6096ef80706SPavel Hofman struct snd_ctl_elem_value *ucontrol) 6106ef80706SPavel Hofman { 6116ef80706SPavel Hofman struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 6126ef80706SPavel Hofman unsigned int val; 6136ef80706SPavel Hofman /* if phantom voltage =48V, phantom on */ 6146ef80706SPavel Hofman val = get_scr(ice) & SCR_PHP_V; 6156ef80706SPavel Hofman ucontrol->value.integer.value[0] = val ? 1 : 0; 6166ef80706SPavel Hofman return 0; 6176ef80706SPavel Hofman } 6186ef80706SPavel Hofman 6196ef80706SPavel Hofman static int qtet_php_put(struct snd_kcontrol *kcontrol, 6206ef80706SPavel Hofman struct snd_ctl_elem_value *ucontrol) 6216ef80706SPavel Hofman { 6226ef80706SPavel Hofman struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 6236ef80706SPavel Hofman unsigned int old, new; 6246ef80706SPavel Hofman old = new = get_scr(ice); 6256ef80706SPavel Hofman if (ucontrol->value.integer.value[0] /* phantom on requested */ 6266ef80706SPavel Hofman && (~old & SCR_PHP_V)) /* 0 = voltage 5V */ { 6276ef80706SPavel Hofman /* is off, turn on */ 6286ef80706SPavel Hofman /* turn voltage on first, = 1 */ 6296ef80706SPavel Hofman new = old | SCR_PHP_V; 6306ef80706SPavel Hofman set_scr(ice, new); 6316ef80706SPavel Hofman /* turn phantom on, = 0 */ 6326ef80706SPavel Hofman new &= ~SCR_PHP; 6336ef80706SPavel Hofman set_scr(ice, new); 6346ef80706SPavel Hofman } else if (!ucontrol->value.integer.value[0] && (old & SCR_PHP_V)) { 6356ef80706SPavel Hofman /* phantom off requested and 1 = voltage 48V */ 6366ef80706SPavel Hofman /* is on, turn off */ 6376ef80706SPavel Hofman /* turn voltage off first, = 0 */ 6386ef80706SPavel Hofman new = old & ~SCR_PHP_V; 6396ef80706SPavel Hofman set_scr(ice, new); 6406ef80706SPavel Hofman /* turn phantom off, = 1 */ 6416ef80706SPavel Hofman new |= SCR_PHP; 6426ef80706SPavel Hofman set_scr(ice, new); 6436ef80706SPavel Hofman } 6446ef80706SPavel Hofman if (old != new) 6456ef80706SPavel Hofman return 1; 6466ef80706SPavel Hofman /* no change */ 6476ef80706SPavel Hofman return 0; 6486ef80706SPavel Hofman } 6496ef80706SPavel Hofman 6506ef80706SPavel Hofman #define PRIV_SW(xid, xbit, xreg) [xid] = {.bit = xbit,\ 6516ef80706SPavel Hofman .set_register = set_##xreg,\ 6526ef80706SPavel Hofman .get_register = get_##xreg, } 6536ef80706SPavel Hofman 6546ef80706SPavel Hofman 6556ef80706SPavel Hofman #define PRIV_ENUM2(xid, xbit, xreg, xtext1, xtext2) [xid] = {.bit = xbit,\ 6566ef80706SPavel Hofman .set_register = set_##xreg,\ 6576ef80706SPavel Hofman .get_register = get_##xreg,\ 6586ef80706SPavel Hofman .texts = {xtext1, xtext2} } 6596ef80706SPavel Hofman 6606ef80706SPavel Hofman static struct qtet_kcontrol_private qtet_privates[] = { 6616ef80706SPavel Hofman PRIV_ENUM2(IN12_SEL, CPLD_IN12_SEL, cpld, "An In 1/2", "An In 3/4"), 6626ef80706SPavel Hofman PRIV_ENUM2(IN34_SEL, CPLD_IN34_SEL, cpld, "An In 3/4", "IEC958 In"), 6636ef80706SPavel Hofman PRIV_ENUM2(AIN34_SEL, SCR_AIN34_SEL, scr, "Line In 3/4", "Hi-Z"), 6646ef80706SPavel Hofman PRIV_ENUM2(COAX_OUT, CPLD_COAX_OUT, cpld, "IEC958", "I2S"), 6656ef80706SPavel Hofman PRIV_SW(IN12_MON12, MCR_IN12_MON12, mcr), 6666ef80706SPavel Hofman PRIV_SW(IN12_MON34, MCR_IN12_MON34, mcr), 6676ef80706SPavel Hofman PRIV_SW(IN34_MON12, MCR_IN34_MON12, mcr), 6686ef80706SPavel Hofman PRIV_SW(IN34_MON34, MCR_IN34_MON34, mcr), 6696ef80706SPavel Hofman PRIV_SW(OUT12_MON34, MCR_OUT12_MON34, mcr), 6706ef80706SPavel Hofman PRIV_SW(OUT34_MON12, MCR_OUT34_MON12, mcr), 6716ef80706SPavel Hofman }; 6726ef80706SPavel Hofman 6736ef80706SPavel Hofman static int qtet_enum_info(struct snd_kcontrol *kcontrol, 6746ef80706SPavel Hofman struct snd_ctl_elem_info *uinfo) 6756ef80706SPavel Hofman { 6766ef80706SPavel Hofman struct qtet_kcontrol_private private = 6776ef80706SPavel Hofman qtet_privates[kcontrol->private_value]; 678597da2e4STakashi Iwai return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(private.texts), 679597da2e4STakashi Iwai private.texts); 6806ef80706SPavel Hofman } 6816ef80706SPavel Hofman 6826ef80706SPavel Hofman static int qtet_sw_get(struct snd_kcontrol *kcontrol, 6836ef80706SPavel Hofman struct snd_ctl_elem_value *ucontrol) 6846ef80706SPavel Hofman { 6856ef80706SPavel Hofman struct qtet_kcontrol_private private = 6866ef80706SPavel Hofman qtet_privates[kcontrol->private_value]; 6876ef80706SPavel Hofman struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 6886ef80706SPavel Hofman ucontrol->value.integer.value[0] = 6896ef80706SPavel Hofman (private.get_register(ice) & private.bit) ? 1 : 0; 6906ef80706SPavel Hofman return 0; 6916ef80706SPavel Hofman } 6926ef80706SPavel Hofman 6936ef80706SPavel Hofman static int qtet_sw_put(struct snd_kcontrol *kcontrol, 6946ef80706SPavel Hofman struct snd_ctl_elem_value *ucontrol) 6956ef80706SPavel Hofman { 6966ef80706SPavel Hofman struct qtet_kcontrol_private private = 6976ef80706SPavel Hofman qtet_privates[kcontrol->private_value]; 6986ef80706SPavel Hofman struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 6996ef80706SPavel Hofman unsigned int old, new; 7006ef80706SPavel Hofman old = private.get_register(ice); 7016ef80706SPavel Hofman if (ucontrol->value.integer.value[0]) 7026ef80706SPavel Hofman new = old | private.bit; 7036ef80706SPavel Hofman else 7046ef80706SPavel Hofman new = old & ~private.bit; 7056ef80706SPavel Hofman if (old != new) { 7066ef80706SPavel Hofman private.set_register(ice, new); 7076ef80706SPavel Hofman return 1; 7086ef80706SPavel Hofman } 7096ef80706SPavel Hofman /* no change */ 7106ef80706SPavel Hofman return 0; 7116ef80706SPavel Hofman } 7126ef80706SPavel Hofman 7136ef80706SPavel Hofman #define qtet_sw_info snd_ctl_boolean_mono_info 7146ef80706SPavel Hofman 7156ef80706SPavel Hofman #define QTET_CONTROL(xname, xtype, xpriv) \ 7166ef80706SPavel Hofman {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,\ 7176ef80706SPavel Hofman .name = xname,\ 7186ef80706SPavel Hofman .info = qtet_##xtype##_info,\ 7196ef80706SPavel Hofman .get = qtet_sw_get,\ 7206ef80706SPavel Hofman .put = qtet_sw_put,\ 7216ef80706SPavel Hofman .private_value = xpriv } 7226ef80706SPavel Hofman 723b4e5e707STakashi Iwai static const struct snd_kcontrol_new qtet_controls[] = { 7246ef80706SPavel Hofman { 7256ef80706SPavel Hofman .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 7266ef80706SPavel Hofman .name = "Master Playback Switch", 7276ef80706SPavel Hofman .info = qtet_sw_info, 7286ef80706SPavel Hofman .get = qtet_mute_get, 7296ef80706SPavel Hofman .put = qtet_mute_put, 7306ef80706SPavel Hofman .private_value = 0 7316ef80706SPavel Hofman }, 7326ef80706SPavel Hofman { 7336ef80706SPavel Hofman .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 7346ef80706SPavel Hofman .name = "Phantom Power", 7356ef80706SPavel Hofman .info = qtet_sw_info, 7366ef80706SPavel Hofman .get = qtet_php_get, 7376ef80706SPavel Hofman .put = qtet_php_put, 7386ef80706SPavel Hofman .private_value = 0 7396ef80706SPavel Hofman }, 7406ef80706SPavel Hofman { 7416ef80706SPavel Hofman .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 7426ef80706SPavel Hofman .name = "Analog In 1/2 Capture Switch", 7436ef80706SPavel Hofman .info = qtet_ain12_enum_info, 7446ef80706SPavel Hofman .get = qtet_ain12_sw_get, 7456ef80706SPavel Hofman .put = qtet_ain12_sw_put, 7466ef80706SPavel Hofman .private_value = 0 7476ef80706SPavel Hofman }, 7486ef80706SPavel Hofman QTET_CONTROL("Analog In 3/4 Capture Switch", enum, AIN34_SEL), 7496ef80706SPavel Hofman QTET_CONTROL("PCM In 1/2 Capture Switch", enum, IN12_SEL), 7506ef80706SPavel Hofman QTET_CONTROL("PCM In 3/4 Capture Switch", enum, IN34_SEL), 7516ef80706SPavel Hofman QTET_CONTROL("Coax Output Source", enum, COAX_OUT), 7526ef80706SPavel Hofman QTET_CONTROL("Analog In 1/2 to Monitor 1/2", sw, IN12_MON12), 7536ef80706SPavel Hofman QTET_CONTROL("Analog In 1/2 to Monitor 3/4", sw, IN12_MON34), 7546ef80706SPavel Hofman QTET_CONTROL("Analog In 3/4 to Monitor 1/2", sw, IN34_MON12), 7556ef80706SPavel Hofman QTET_CONTROL("Analog In 3/4 to Monitor 3/4", sw, IN34_MON34), 7566ef80706SPavel Hofman QTET_CONTROL("Output 1/2 to Monitor 3/4", sw, OUT12_MON34), 7576ef80706SPavel Hofman QTET_CONTROL("Output 3/4 to Monitor 1/2", sw, OUT34_MON12), 7586ef80706SPavel Hofman }; 7596ef80706SPavel Hofman 760e23e7a14SBill Pemberton static char *slave_vols[] = { 7616ef80706SPavel Hofman PCM_12_PLAYBACK_VOLUME, 7626ef80706SPavel Hofman PCM_34_PLAYBACK_VOLUME, 7636ef80706SPavel Hofman NULL 7646ef80706SPavel Hofman }; 7656ef80706SPavel Hofman 766e23e7a14SBill Pemberton static 7676ef80706SPavel Hofman DECLARE_TLV_DB_SCALE(qtet_master_db_scale, -6350, 50, 1); 7686ef80706SPavel Hofman 769e23e7a14SBill Pemberton static struct snd_kcontrol *ctl_find(struct snd_card *card, 7706ef80706SPavel Hofman const char *name) 7716ef80706SPavel Hofman { 772338e17d3SJoey Pabalinas struct snd_ctl_elem_id sid = {0}; 773338e17d3SJoey Pabalinas 774338e17d3SJoey Pabalinas strlcpy(sid.name, name, sizeof(sid.name)); 7756ef80706SPavel Hofman sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 7766ef80706SPavel Hofman return snd_ctl_find_id(card, &sid); 7776ef80706SPavel Hofman } 7786ef80706SPavel Hofman 779e23e7a14SBill Pemberton static void add_slaves(struct snd_card *card, 780a2af050fSTakashi Iwai struct snd_kcontrol *master, char * const *list) 7816ef80706SPavel Hofman { 7826ef80706SPavel Hofman for (; *list; list++) { 7836ef80706SPavel Hofman struct snd_kcontrol *slave = ctl_find(card, *list); 7846ef80706SPavel Hofman if (slave) 7856ef80706SPavel Hofman snd_ctl_add_slave(master, slave); 7866ef80706SPavel Hofman } 7876ef80706SPavel Hofman } 7886ef80706SPavel Hofman 789e23e7a14SBill Pemberton static int qtet_add_controls(struct snd_ice1712 *ice) 7906ef80706SPavel Hofman { 7916ef80706SPavel Hofman struct qtet_spec *spec = ice->spec; 7926ef80706SPavel Hofman int err, i; 7936ef80706SPavel Hofman struct snd_kcontrol *vmaster; 7946ef80706SPavel Hofman err = snd_ice1712_akm4xxx_build_controls(ice); 7956ef80706SPavel Hofman if (err < 0) 7966ef80706SPavel Hofman return err; 7976ef80706SPavel Hofman for (i = 0; i < ARRAY_SIZE(qtet_controls); i++) { 7986ef80706SPavel Hofman err = snd_ctl_add(ice->card, 7996ef80706SPavel Hofman snd_ctl_new1(&qtet_controls[i], ice)); 8006ef80706SPavel Hofman if (err < 0) 8016ef80706SPavel Hofman return err; 8026ef80706SPavel Hofman } 8036ef80706SPavel Hofman 8046ef80706SPavel Hofman /* Create virtual master control */ 8056ef80706SPavel Hofman vmaster = snd_ctl_make_virtual_master("Master Playback Volume", 8066ef80706SPavel Hofman qtet_master_db_scale); 8076ef80706SPavel Hofman if (!vmaster) 8086ef80706SPavel Hofman return -ENOMEM; 8096ef80706SPavel Hofman add_slaves(ice->card, vmaster, slave_vols); 8106ef80706SPavel Hofman err = snd_ctl_add(ice->card, vmaster); 8116ef80706SPavel Hofman if (err < 0) 8126ef80706SPavel Hofman return err; 8136ef80706SPavel Hofman /* only capture SPDIF over AK4113 */ 814387417b5SSudip Mukherjee return snd_ak4113_build(spec->ak4113, 8156ef80706SPavel Hofman ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); 8166ef80706SPavel Hofman } 8176ef80706SPavel Hofman 8186ef80706SPavel Hofman static inline int qtet_is_spdif_master(struct snd_ice1712 *ice) 8196ef80706SPavel Hofman { 8206ef80706SPavel Hofman /* CPLD_SYNC_SEL: 0 = internal, 1 = external (i.e. spdif master) */ 8216ef80706SPavel Hofman return (get_cpld(ice) & CPLD_SYNC_SEL) ? 1 : 0; 8226ef80706SPavel Hofman } 8236ef80706SPavel Hofman 8246ef80706SPavel Hofman static unsigned int qtet_get_rate(struct snd_ice1712 *ice) 8256ef80706SPavel Hofman { 8266ef80706SPavel Hofman int i; 8276ef80706SPavel Hofman unsigned char result; 8286ef80706SPavel Hofman 8296ef80706SPavel Hofman result = get_cpld(ice) & CPLD_CKS_MASK; 8306ef80706SPavel Hofman for (i = 0; i < ARRAY_SIZE(cks_vals); i++) 8316ef80706SPavel Hofman if (cks_vals[i] == result) 8326ef80706SPavel Hofman return qtet_rates[i]; 8336ef80706SPavel Hofman return 0; 8346ef80706SPavel Hofman } 8356ef80706SPavel Hofman 8366ef80706SPavel Hofman static int get_cks_val(int rate) 8376ef80706SPavel Hofman { 8386ef80706SPavel Hofman int i; 8396ef80706SPavel Hofman for (i = 0; i < ARRAY_SIZE(qtet_rates); i++) 8406ef80706SPavel Hofman if (qtet_rates[i] == rate) 8416ef80706SPavel Hofman return cks_vals[i]; 8426ef80706SPavel Hofman return 0; 8436ef80706SPavel Hofman } 8446ef80706SPavel Hofman 8456ef80706SPavel Hofman /* setting new rate */ 8466ef80706SPavel Hofman static void qtet_set_rate(struct snd_ice1712 *ice, unsigned int rate) 8476ef80706SPavel Hofman { 8486ef80706SPavel Hofman unsigned int new; 8496ef80706SPavel Hofman unsigned char val; 8506ef80706SPavel Hofman /* switching ice1724 to external clock - supplied by ext. circuits */ 8516ef80706SPavel Hofman val = inb(ICEMT1724(ice, RATE)); 8526ef80706SPavel Hofman outb(val | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE)); 8536ef80706SPavel Hofman 8546ef80706SPavel Hofman new = (get_cpld(ice) & ~CPLD_CKS_MASK) | get_cks_val(rate); 8556ef80706SPavel Hofman /* switch to internal clock, drop CPLD_SYNC_SEL */ 8566ef80706SPavel Hofman new &= ~CPLD_SYNC_SEL; 8576dfb5affSTakashi Iwai /* dev_dbg(ice->card->dev, "QT - set_rate: old %x, new %x\n", 8586ef80706SPavel Hofman get_cpld(ice), new); */ 8596ef80706SPavel Hofman set_cpld(ice, new); 8606ef80706SPavel Hofman } 8616ef80706SPavel Hofman 8626ef80706SPavel Hofman static inline unsigned char qtet_set_mclk(struct snd_ice1712 *ice, 8636ef80706SPavel Hofman unsigned int rate) 8646ef80706SPavel Hofman { 8656ef80706SPavel Hofman /* no change in master clock */ 8666ef80706SPavel Hofman return 0; 8676ef80706SPavel Hofman } 8686ef80706SPavel Hofman 8696ef80706SPavel Hofman /* setting clock to external - SPDIF */ 8706ef80706SPavel Hofman static int qtet_set_spdif_clock(struct snd_ice1712 *ice, int type) 8716ef80706SPavel Hofman { 8726ef80706SPavel Hofman unsigned int old, new; 8736ef80706SPavel Hofman 8746ef80706SPavel Hofman old = new = get_cpld(ice); 8756ef80706SPavel Hofman new &= ~(CPLD_CKS_MASK | CPLD_WORD_SEL); 8766ef80706SPavel Hofman switch (type) { 8776ef80706SPavel Hofman case EXT_SPDIF_TYPE: 8786ef80706SPavel Hofman new |= CPLD_EXT_SPDIF; 8796ef80706SPavel Hofman break; 8806ef80706SPavel Hofman case EXT_WORDCLOCK_1FS_TYPE: 8816ef80706SPavel Hofman new |= CPLD_EXT_WORDCLOCK_1FS; 8826ef80706SPavel Hofman break; 8836ef80706SPavel Hofman case EXT_WORDCLOCK_256FS_TYPE: 8846ef80706SPavel Hofman new |= CPLD_EXT_WORDCLOCK_256FS; 8856ef80706SPavel Hofman break; 8866ef80706SPavel Hofman default: 8876ef80706SPavel Hofman snd_BUG(); 8886ef80706SPavel Hofman } 8896ef80706SPavel Hofman if (old != new) { 8906ef80706SPavel Hofman set_cpld(ice, new); 8916ef80706SPavel Hofman /* changed */ 8926ef80706SPavel Hofman return 1; 8936ef80706SPavel Hofman } 8946ef80706SPavel Hofman return 0; 8956ef80706SPavel Hofman } 8966ef80706SPavel Hofman 8976ef80706SPavel Hofman static int qtet_get_spdif_master_type(struct snd_ice1712 *ice) 8986ef80706SPavel Hofman { 8996ef80706SPavel Hofman unsigned int val; 9006ef80706SPavel Hofman int result; 9016ef80706SPavel Hofman val = get_cpld(ice); 9026ef80706SPavel Hofman /* checking only rate/clock-related bits */ 9036ef80706SPavel Hofman val &= (CPLD_CKS_MASK | CPLD_WORD_SEL | CPLD_SYNC_SEL); 9046ef80706SPavel Hofman if (!(val & CPLD_SYNC_SEL)) { 9056ef80706SPavel Hofman /* switched to internal clock, is not any external type */ 9066ef80706SPavel Hofman result = -1; 9076ef80706SPavel Hofman } else { 9086ef80706SPavel Hofman switch (val) { 9096ef80706SPavel Hofman case (CPLD_EXT_SPDIF): 9106ef80706SPavel Hofman result = EXT_SPDIF_TYPE; 9116ef80706SPavel Hofman break; 9126ef80706SPavel Hofman case (CPLD_EXT_WORDCLOCK_1FS): 9136ef80706SPavel Hofman result = EXT_WORDCLOCK_1FS_TYPE; 9146ef80706SPavel Hofman break; 9156ef80706SPavel Hofman case (CPLD_EXT_WORDCLOCK_256FS): 9166ef80706SPavel Hofman result = EXT_WORDCLOCK_256FS_TYPE; 9176ef80706SPavel Hofman break; 9186ef80706SPavel Hofman default: 9196ef80706SPavel Hofman /* undefined combination of external clock setup */ 9206ef80706SPavel Hofman snd_BUG(); 9216ef80706SPavel Hofman result = 0; 9226ef80706SPavel Hofman } 9236ef80706SPavel Hofman } 9246ef80706SPavel Hofman return result; 9256ef80706SPavel Hofman } 9266ef80706SPavel Hofman 9276ef80706SPavel Hofman /* Called when ak4113 detects change in the input SPDIF stream */ 9286ef80706SPavel Hofman static void qtet_ak4113_change(struct ak4113 *ak4113, unsigned char c0, 9296ef80706SPavel Hofman unsigned char c1) 9306ef80706SPavel Hofman { 9316ef80706SPavel Hofman struct snd_ice1712 *ice = ak4113->change_callback_private; 9326ef80706SPavel Hofman int rate; 9336ef80706SPavel Hofman if ((qtet_get_spdif_master_type(ice) == EXT_SPDIF_TYPE) && 9346ef80706SPavel Hofman c1) { 9356ef80706SPavel Hofman /* only for SPDIF master mode, rate was changed */ 9366ef80706SPavel Hofman rate = snd_ak4113_external_rate(ak4113); 9376dfb5affSTakashi Iwai /* dev_dbg(ice->card->dev, "ak4113 - input rate changed to %d\n", 9386ef80706SPavel Hofman rate); */ 9396ef80706SPavel Hofman qtet_akm_set_rate_val(ice->akm, rate); 9406ef80706SPavel Hofman } 9416ef80706SPavel Hofman } 9426ef80706SPavel Hofman 9436ef80706SPavel Hofman /* 9446ef80706SPavel Hofman * If clock slaved to SPDIF-IN, setting runtime rate 9456ef80706SPavel Hofman * to the detected external rate 9466ef80706SPavel Hofman */ 9476ef80706SPavel Hofman static void qtet_spdif_in_open(struct snd_ice1712 *ice, 9486ef80706SPavel Hofman struct snd_pcm_substream *substream) 9496ef80706SPavel Hofman { 9506ef80706SPavel Hofman struct qtet_spec *spec = ice->spec; 9516ef80706SPavel Hofman struct snd_pcm_runtime *runtime = substream->runtime; 9526ef80706SPavel Hofman int rate; 9536ef80706SPavel Hofman 9546ef80706SPavel Hofman if (qtet_get_spdif_master_type(ice) != EXT_SPDIF_TYPE) 9556ef80706SPavel Hofman /* not external SPDIF, no rate limitation */ 9566ef80706SPavel Hofman return; 9576ef80706SPavel Hofman /* only external SPDIF can detect incoming sample rate */ 9586ef80706SPavel Hofman rate = snd_ak4113_external_rate(spec->ak4113); 9596ef80706SPavel Hofman if (rate >= runtime->hw.rate_min && rate <= runtime->hw.rate_max) { 9606ef80706SPavel Hofman runtime->hw.rate_min = rate; 9616ef80706SPavel Hofman runtime->hw.rate_max = rate; 9626ef80706SPavel Hofman } 9636ef80706SPavel Hofman } 9646ef80706SPavel Hofman 9656ef80706SPavel Hofman /* 9666ef80706SPavel Hofman * initialize the chip 9676ef80706SPavel Hofman */ 968e23e7a14SBill Pemberton static int qtet_init(struct snd_ice1712 *ice) 9696ef80706SPavel Hofman { 9706ef80706SPavel Hofman static const unsigned char ak4113_init_vals[] = { 9716ef80706SPavel Hofman /* AK4113_REG_PWRDN */ AK4113_RST | AK4113_PWN | 9726ef80706SPavel Hofman AK4113_OCKS0 | AK4113_OCKS1, 9736ef80706SPavel Hofman /* AK4113_REQ_FORMAT */ AK4113_DIF_I24I2S | AK4113_VTX | 9746ef80706SPavel Hofman AK4113_DEM_OFF | AK4113_DEAU, 9756ef80706SPavel Hofman /* AK4113_REG_IO0 */ AK4113_OPS2 | AK4113_TXE | 9766ef80706SPavel Hofman AK4113_XTL_24_576M, 9776ef80706SPavel Hofman /* AK4113_REG_IO1 */ AK4113_EFH_1024LRCLK | AK4113_IPS(0), 9786ef80706SPavel Hofman /* AK4113_REG_INT0_MASK */ 0, 9796ef80706SPavel Hofman /* AK4113_REG_INT1_MASK */ 0, 9806ef80706SPavel Hofman /* AK4113_REG_DATDTS */ 0, 9816ef80706SPavel Hofman }; 9826ef80706SPavel Hofman int err; 9836ef80706SPavel Hofman struct qtet_spec *spec; 9846ef80706SPavel Hofman struct snd_akm4xxx *ak; 9856ef80706SPavel Hofman unsigned char val; 9866ef80706SPavel Hofman 9876ef80706SPavel Hofman /* switching ice1724 to external clock - supplied by ext. circuits */ 9886ef80706SPavel Hofman val = inb(ICEMT1724(ice, RATE)); 9896ef80706SPavel Hofman outb(val | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE)); 9906ef80706SPavel Hofman 9916ef80706SPavel Hofman spec = kzalloc(sizeof(*spec), GFP_KERNEL); 9926ef80706SPavel Hofman if (!spec) 9936ef80706SPavel Hofman return -ENOMEM; 9946ef80706SPavel Hofman /* qtet is clocked by Xilinx array */ 9956ef80706SPavel Hofman ice->hw_rates = &qtet_rates_info; 9966ef80706SPavel Hofman ice->is_spdif_master = qtet_is_spdif_master; 9976ef80706SPavel Hofman ice->get_rate = qtet_get_rate; 9986ef80706SPavel Hofman ice->set_rate = qtet_set_rate; 9996ef80706SPavel Hofman ice->set_mclk = qtet_set_mclk; 10006ef80706SPavel Hofman ice->set_spdif_clock = qtet_set_spdif_clock; 10016ef80706SPavel Hofman ice->get_spdif_master_type = qtet_get_spdif_master_type; 10026ef80706SPavel Hofman ice->ext_clock_names = ext_clock_names; 10036ef80706SPavel Hofman ice->ext_clock_count = ARRAY_SIZE(ext_clock_names); 10046ef80706SPavel Hofman /* since Qtet can detect correct SPDIF-in rate, all streams can be 10056ef80706SPavel Hofman * limited to this specific rate */ 10066ef80706SPavel Hofman ice->spdif.ops.open = ice->pro_open = qtet_spdif_in_open; 10076ef80706SPavel Hofman ice->spec = spec; 10086ef80706SPavel Hofman 10096ef80706SPavel Hofman /* Mute Off */ 10106ef80706SPavel Hofman /* SCR Initialize*/ 10116ef80706SPavel Hofman /* keep codec power down first */ 10126ef80706SPavel Hofman set_scr(ice, SCR_PHP); 10136ef80706SPavel Hofman udelay(1); 10146ef80706SPavel Hofman /* codec power up */ 10156ef80706SPavel Hofman set_scr(ice, SCR_PHP | SCR_CODEC_PDN); 10166ef80706SPavel Hofman 10176ef80706SPavel Hofman /* MCR Initialize */ 10186ef80706SPavel Hofman set_mcr(ice, 0); 10196ef80706SPavel Hofman 10206ef80706SPavel Hofman /* CPLD Initialize */ 10216ef80706SPavel Hofman set_cpld(ice, 0); 10226ef80706SPavel Hofman 10236ef80706SPavel Hofman 10246ef80706SPavel Hofman ice->num_total_dacs = 2; 10256ef80706SPavel Hofman ice->num_total_adcs = 2; 10266ef80706SPavel Hofman 10276ef80706SPavel Hofman ice->akm = kcalloc(2, sizeof(struct snd_akm4xxx), GFP_KERNEL); 10286ef80706SPavel Hofman ak = ice->akm; 10296ef80706SPavel Hofman if (!ak) 10306ef80706SPavel Hofman return -ENOMEM; 10316ef80706SPavel Hofman /* only one codec with two chips */ 10326ef80706SPavel Hofman ice->akm_codecs = 1; 10336ef80706SPavel Hofman err = snd_ice1712_akm4xxx_init(ak, &akm_qtet_dac, NULL, ice); 10346ef80706SPavel Hofman if (err < 0) 10356ef80706SPavel Hofman return err; 10366ef80706SPavel Hofman err = snd_ak4113_create(ice->card, 10376ef80706SPavel Hofman qtet_ak4113_read, 10386ef80706SPavel Hofman qtet_ak4113_write, 10396ef80706SPavel Hofman ak4113_init_vals, 10406ef80706SPavel Hofman ice, &spec->ak4113); 10416ef80706SPavel Hofman if (err < 0) 10426ef80706SPavel Hofman return err; 10436ef80706SPavel Hofman /* callback for codecs rate setting */ 10446ef80706SPavel Hofman spec->ak4113->change_callback = qtet_ak4113_change; 10456ef80706SPavel Hofman spec->ak4113->change_callback_private = ice; 10466ef80706SPavel Hofman /* AK41143 in Quartet can detect external rate correctly 10476ef80706SPavel Hofman * (i.e. check_flags = 0) */ 10486ef80706SPavel Hofman spec->ak4113->check_flags = 0; 10496ef80706SPavel Hofman 10506ef80706SPavel Hofman proc_init(ice); 10516ef80706SPavel Hofman 10526ef80706SPavel Hofman qtet_set_rate(ice, 44100); 10536ef80706SPavel Hofman return 0; 10546ef80706SPavel Hofman } 10556ef80706SPavel Hofman 1056e23e7a14SBill Pemberton static unsigned char qtet_eeprom[] = { 10576ef80706SPavel Hofman [ICE_EEP2_SYSCONF] = 0x28, /* clock 256(24MHz), mpu401, 1xADC, 10586ef80706SPavel Hofman 1xDACs, SPDIF in */ 10596ef80706SPavel Hofman [ICE_EEP2_ACLINK] = 0x80, /* I2S */ 10606ef80706SPavel Hofman [ICE_EEP2_I2S] = 0x78, /* 96k, 24bit, 192k */ 10616ef80706SPavel Hofman [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, in, out-ext */ 10626ef80706SPavel Hofman [ICE_EEP2_GPIO_DIR] = 0x00, /* 0-7 inputs, switched to output 10636ef80706SPavel Hofman only during output operations */ 10646ef80706SPavel Hofman [ICE_EEP2_GPIO_DIR1] = 0xff, /* 8-15 outputs */ 10656ef80706SPavel Hofman [ICE_EEP2_GPIO_DIR2] = 0x00, 10666ef80706SPavel Hofman [ICE_EEP2_GPIO_MASK] = 0xff, /* changed only for OUT operations */ 10676ef80706SPavel Hofman [ICE_EEP2_GPIO_MASK1] = 0x00, 10686ef80706SPavel Hofman [ICE_EEP2_GPIO_MASK2] = 0xff, 10696ef80706SPavel Hofman 10706ef80706SPavel Hofman [ICE_EEP2_GPIO_STATE] = 0x00, /* inputs */ 10716ef80706SPavel Hofman [ICE_EEP2_GPIO_STATE1] = 0x7d, /* all 1, but GPIO_CPLD_RW 10726ef80706SPavel Hofman and GPIO15 always zero */ 10736ef80706SPavel Hofman [ICE_EEP2_GPIO_STATE2] = 0x00, /* inputs */ 10746ef80706SPavel Hofman }; 10756ef80706SPavel Hofman 10766ef80706SPavel Hofman /* entry point */ 1077e23e7a14SBill Pemberton struct snd_ice1712_card_info snd_vt1724_qtet_cards[] = { 10786ef80706SPavel Hofman { 10796ef80706SPavel Hofman .subvendor = VT1724_SUBDEVICE_QTET, 10806ef80706SPavel Hofman .name = "Infrasonic Quartet", 10816ef80706SPavel Hofman .model = "quartet", 10826ef80706SPavel Hofman .chip_init = qtet_init, 10836ef80706SPavel Hofman .build_controls = qtet_add_controls, 10846ef80706SPavel Hofman .eeprom_size = sizeof(qtet_eeprom), 10856ef80706SPavel Hofman .eeprom_data = qtet_eeprom, 10866ef80706SPavel Hofman }, 10876ef80706SPavel Hofman { } /* terminator */ 10886ef80706SPavel Hofman }; 1089