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 Infrasonic Quartet 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (c) 2009 Pavel Hofman <pavel.hofman@ivitera.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/string.h> 158c2ecf20Sopenharmony_ci#include <sound/core.h> 168c2ecf20Sopenharmony_ci#include <sound/tlv.h> 178c2ecf20Sopenharmony_ci#include <sound/info.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "ice1712.h" 208c2ecf20Sopenharmony_ci#include "envy24ht.h" 218c2ecf20Sopenharmony_ci#include <sound/ak4113.h> 228c2ecf20Sopenharmony_ci#include "quartet.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistruct qtet_spec { 258c2ecf20Sopenharmony_ci struct ak4113 *ak4113; 268c2ecf20Sopenharmony_ci unsigned int scr; /* system control register */ 278c2ecf20Sopenharmony_ci unsigned int mcr; /* monitoring control register */ 288c2ecf20Sopenharmony_ci unsigned int cpld; /* cpld register */ 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistruct qtet_kcontrol_private { 328c2ecf20Sopenharmony_ci unsigned int bit; 338c2ecf20Sopenharmony_ci void (*set_register)(struct snd_ice1712 *ice, unsigned int val); 348c2ecf20Sopenharmony_ci unsigned int (*get_register)(struct snd_ice1712 *ice); 358c2ecf20Sopenharmony_ci const char * const texts[2]; 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cienum { 398c2ecf20Sopenharmony_ci IN12_SEL = 0, 408c2ecf20Sopenharmony_ci IN34_SEL, 418c2ecf20Sopenharmony_ci AIN34_SEL, 428c2ecf20Sopenharmony_ci COAX_OUT, 438c2ecf20Sopenharmony_ci IN12_MON12, 448c2ecf20Sopenharmony_ci IN12_MON34, 458c2ecf20Sopenharmony_ci IN34_MON12, 468c2ecf20Sopenharmony_ci IN34_MON34, 478c2ecf20Sopenharmony_ci OUT12_MON34, 488c2ecf20Sopenharmony_ci OUT34_MON12, 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic const char * const ext_clock_names[3] = {"IEC958 In", "Word Clock 1xFS", 528c2ecf20Sopenharmony_ci "Word Clock 256xFS"}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* chip address on I2C bus */ 558c2ecf20Sopenharmony_ci#define AK4113_ADDR 0x26 /* S/PDIF receiver */ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* chip address on SPI bus */ 588c2ecf20Sopenharmony_ci#define AK4620_ADDR 0x02 /* ADC/DAC */ 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * GPIO pins 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* GPIO0 - O - DATA0, def. 0 */ 668c2ecf20Sopenharmony_ci#define GPIO_D0 (1<<0) 678c2ecf20Sopenharmony_ci/* GPIO1 - I/O - DATA1, Jack Detect Input0 (0:present, 1:missing), def. 1 */ 688c2ecf20Sopenharmony_ci#define GPIO_D1_JACKDTC0 (1<<1) 698c2ecf20Sopenharmony_ci/* GPIO2 - I/O - DATA2, Jack Detect Input1 (0:present, 1:missing), def. 1 */ 708c2ecf20Sopenharmony_ci#define GPIO_D2_JACKDTC1 (1<<2) 718c2ecf20Sopenharmony_ci/* GPIO3 - I/O - DATA3, def. 1 */ 728c2ecf20Sopenharmony_ci#define GPIO_D3 (1<<3) 738c2ecf20Sopenharmony_ci/* GPIO4 - I/O - DATA4, SPI CDTO, def. 1 */ 748c2ecf20Sopenharmony_ci#define GPIO_D4_SPI_CDTO (1<<4) 758c2ecf20Sopenharmony_ci/* GPIO5 - I/O - DATA5, SPI CCLK, def. 1 */ 768c2ecf20Sopenharmony_ci#define GPIO_D5_SPI_CCLK (1<<5) 778c2ecf20Sopenharmony_ci/* GPIO6 - I/O - DATA6, Cable Detect Input (0:detected, 1:not detected */ 788c2ecf20Sopenharmony_ci#define GPIO_D6_CD (1<<6) 798c2ecf20Sopenharmony_ci/* GPIO7 - I/O - DATA7, Device Detect Input (0:detected, 1:not detected */ 808c2ecf20Sopenharmony_ci#define GPIO_D7_DD (1<<7) 818c2ecf20Sopenharmony_ci/* GPIO8 - O - CPLD Chip Select, def. 1 */ 828c2ecf20Sopenharmony_ci#define GPIO_CPLD_CSN (1<<8) 838c2ecf20Sopenharmony_ci/* GPIO9 - O - CPLD register read/write (0:write, 1:read), def. 0 */ 848c2ecf20Sopenharmony_ci#define GPIO_CPLD_RW (1<<9) 858c2ecf20Sopenharmony_ci/* GPIO10 - O - SPI Chip Select for CODEC#0, def. 1 */ 868c2ecf20Sopenharmony_ci#define GPIO_SPI_CSN0 (1<<10) 878c2ecf20Sopenharmony_ci/* GPIO11 - O - SPI Chip Select for CODEC#1, def. 1 */ 888c2ecf20Sopenharmony_ci#define GPIO_SPI_CSN1 (1<<11) 898c2ecf20Sopenharmony_ci/* GPIO12 - O - Ex. Register Output Enable (0:enable, 1:disable), def. 1, 908c2ecf20Sopenharmony_ci * init 0 */ 918c2ecf20Sopenharmony_ci#define GPIO_EX_GPIOE (1<<12) 928c2ecf20Sopenharmony_ci/* GPIO13 - O - Ex. Register0 Chip Select for System Control Register, 938c2ecf20Sopenharmony_ci * def. 1 */ 948c2ecf20Sopenharmony_ci#define GPIO_SCR (1<<13) 958c2ecf20Sopenharmony_ci/* GPIO14 - O - Ex. Register1 Chip Select for Monitor Control Register, 968c2ecf20Sopenharmony_ci * def. 1 */ 978c2ecf20Sopenharmony_ci#define GPIO_MCR (1<<14) 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci#define GPIO_SPI_ALL (GPIO_D4_SPI_CDTO | GPIO_D5_SPI_CCLK |\ 1008c2ecf20Sopenharmony_ci GPIO_SPI_CSN0 | GPIO_SPI_CSN1) 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci#define GPIO_DATA_MASK (GPIO_D0 | GPIO_D1_JACKDTC0 | \ 1038c2ecf20Sopenharmony_ci GPIO_D2_JACKDTC1 | GPIO_D3 | \ 1048c2ecf20Sopenharmony_ci GPIO_D4_SPI_CDTO | GPIO_D5_SPI_CCLK | \ 1058c2ecf20Sopenharmony_ci GPIO_D6_CD | GPIO_D7_DD) 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/* System Control Register GPIO_SCR data bits */ 1088c2ecf20Sopenharmony_ci/* Mic/Line select relay (0:line, 1:mic) */ 1098c2ecf20Sopenharmony_ci#define SCR_RELAY GPIO_D0 1108c2ecf20Sopenharmony_ci/* Phantom power drive control (0:5V, 1:48V) */ 1118c2ecf20Sopenharmony_ci#define SCR_PHP_V GPIO_D1_JACKDTC0 1128c2ecf20Sopenharmony_ci/* H/W mute control (0:Normal, 1:Mute) */ 1138c2ecf20Sopenharmony_ci#define SCR_MUTE GPIO_D2_JACKDTC1 1148c2ecf20Sopenharmony_ci/* Phantom power control (0:Phantom on, 1:off) */ 1158c2ecf20Sopenharmony_ci#define SCR_PHP GPIO_D3 1168c2ecf20Sopenharmony_ci/* Analog input 1/2 Source Select */ 1178c2ecf20Sopenharmony_ci#define SCR_AIN12_SEL0 GPIO_D4_SPI_CDTO 1188c2ecf20Sopenharmony_ci#define SCR_AIN12_SEL1 GPIO_D5_SPI_CCLK 1198c2ecf20Sopenharmony_ci/* Analog input 3/4 Source Select (0:line, 1:hi-z) */ 1208c2ecf20Sopenharmony_ci#define SCR_AIN34_SEL GPIO_D6_CD 1218c2ecf20Sopenharmony_ci/* Codec Power Down (0:power down, 1:normal) */ 1228c2ecf20Sopenharmony_ci#define SCR_CODEC_PDN GPIO_D7_DD 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#define SCR_AIN12_LINE (0) 1258c2ecf20Sopenharmony_ci#define SCR_AIN12_MIC (SCR_AIN12_SEL0) 1268c2ecf20Sopenharmony_ci#define SCR_AIN12_LOWCUT (SCR_AIN12_SEL1 | SCR_AIN12_SEL0) 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci/* Monitor Control Register GPIO_MCR data bits */ 1298c2ecf20Sopenharmony_ci/* Input 1/2 to Monitor 1/2 (0:off, 1:on) */ 1308c2ecf20Sopenharmony_ci#define MCR_IN12_MON12 GPIO_D0 1318c2ecf20Sopenharmony_ci/* Input 1/2 to Monitor 3/4 (0:off, 1:on) */ 1328c2ecf20Sopenharmony_ci#define MCR_IN12_MON34 GPIO_D1_JACKDTC0 1338c2ecf20Sopenharmony_ci/* Input 3/4 to Monitor 1/2 (0:off, 1:on) */ 1348c2ecf20Sopenharmony_ci#define MCR_IN34_MON12 GPIO_D2_JACKDTC1 1358c2ecf20Sopenharmony_ci/* Input 3/4 to Monitor 3/4 (0:off, 1:on) */ 1368c2ecf20Sopenharmony_ci#define MCR_IN34_MON34 GPIO_D3 1378c2ecf20Sopenharmony_ci/* Output to Monitor 1/2 (0:off, 1:on) */ 1388c2ecf20Sopenharmony_ci#define MCR_OUT34_MON12 GPIO_D4_SPI_CDTO 1398c2ecf20Sopenharmony_ci/* Output to Monitor 3/4 (0:off, 1:on) */ 1408c2ecf20Sopenharmony_ci#define MCR_OUT12_MON34 GPIO_D5_SPI_CCLK 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/* CPLD Register DATA bits */ 1438c2ecf20Sopenharmony_ci/* Clock Rate Select */ 1448c2ecf20Sopenharmony_ci#define CPLD_CKS0 GPIO_D0 1458c2ecf20Sopenharmony_ci#define CPLD_CKS1 GPIO_D1_JACKDTC0 1468c2ecf20Sopenharmony_ci#define CPLD_CKS2 GPIO_D2_JACKDTC1 1478c2ecf20Sopenharmony_ci/* Sync Source Select (0:Internal, 1:External) */ 1488c2ecf20Sopenharmony_ci#define CPLD_SYNC_SEL GPIO_D3 1498c2ecf20Sopenharmony_ci/* Word Clock FS Select (0:FS, 1:256FS) */ 1508c2ecf20Sopenharmony_ci#define CPLD_WORD_SEL GPIO_D4_SPI_CDTO 1518c2ecf20Sopenharmony_ci/* Coaxial Output Source (IS-Link) (0:SPDIF, 1:I2S) */ 1528c2ecf20Sopenharmony_ci#define CPLD_COAX_OUT GPIO_D5_SPI_CCLK 1538c2ecf20Sopenharmony_ci/* Input 1/2 Source Select (0:Analog12, 1:An34) */ 1548c2ecf20Sopenharmony_ci#define CPLD_IN12_SEL GPIO_D6_CD 1558c2ecf20Sopenharmony_ci/* Input 3/4 Source Select (0:Analog34, 1:Digital In) */ 1568c2ecf20Sopenharmony_ci#define CPLD_IN34_SEL GPIO_D7_DD 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci/* internal clock (CPLD_SYNC_SEL = 0) options */ 1598c2ecf20Sopenharmony_ci#define CPLD_CKS_44100HZ (0) 1608c2ecf20Sopenharmony_ci#define CPLD_CKS_48000HZ (CPLD_CKS0) 1618c2ecf20Sopenharmony_ci#define CPLD_CKS_88200HZ (CPLD_CKS1) 1628c2ecf20Sopenharmony_ci#define CPLD_CKS_96000HZ (CPLD_CKS1 | CPLD_CKS0) 1638c2ecf20Sopenharmony_ci#define CPLD_CKS_176400HZ (CPLD_CKS2) 1648c2ecf20Sopenharmony_ci#define CPLD_CKS_192000HZ (CPLD_CKS2 | CPLD_CKS0) 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci#define CPLD_CKS_MASK (CPLD_CKS0 | CPLD_CKS1 | CPLD_CKS2) 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci/* external clock (CPLD_SYNC_SEL = 1) options */ 1698c2ecf20Sopenharmony_ci/* external clock - SPDIF */ 1708c2ecf20Sopenharmony_ci#define CPLD_EXT_SPDIF (0 | CPLD_SYNC_SEL) 1718c2ecf20Sopenharmony_ci/* external clock - WordClock 1xfs */ 1728c2ecf20Sopenharmony_ci#define CPLD_EXT_WORDCLOCK_1FS (CPLD_CKS1 | CPLD_SYNC_SEL) 1738c2ecf20Sopenharmony_ci/* external clock - WordClock 256xfs */ 1748c2ecf20Sopenharmony_ci#define CPLD_EXT_WORDCLOCK_256FS (CPLD_CKS1 | CPLD_WORD_SEL |\ 1758c2ecf20Sopenharmony_ci CPLD_SYNC_SEL) 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci#define EXT_SPDIF_TYPE 0 1788c2ecf20Sopenharmony_ci#define EXT_WORDCLOCK_1FS_TYPE 1 1798c2ecf20Sopenharmony_ci#define EXT_WORDCLOCK_256FS_TYPE 2 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci#define AK4620_DFS0 (1<<0) 1828c2ecf20Sopenharmony_ci#define AK4620_DFS1 (1<<1) 1838c2ecf20Sopenharmony_ci#define AK4620_CKS0 (1<<2) 1848c2ecf20Sopenharmony_ci#define AK4620_CKS1 (1<<3) 1858c2ecf20Sopenharmony_ci/* Clock and Format Control register */ 1868c2ecf20Sopenharmony_ci#define AK4620_DFS_REG 0x02 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci/* Deem and Volume Control register */ 1898c2ecf20Sopenharmony_ci#define AK4620_DEEMVOL_REG 0x03 1908c2ecf20Sopenharmony_ci#define AK4620_SMUTE (1<<7) 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/* 1938c2ecf20Sopenharmony_ci * Conversion from int value to its binary form. Used for debugging. 1948c2ecf20Sopenharmony_ci * The output buffer must be allocated prior to calling the function. 1958c2ecf20Sopenharmony_ci */ 1968c2ecf20Sopenharmony_cistatic char *get_binary(char *buffer, int value) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci int i, j, pos; 1998c2ecf20Sopenharmony_ci pos = 0; 2008c2ecf20Sopenharmony_ci for (i = 0; i < 4; ++i) { 2018c2ecf20Sopenharmony_ci for (j = 0; j < 8; ++j) { 2028c2ecf20Sopenharmony_ci if (value & (1 << (31-(i*8 + j)))) 2038c2ecf20Sopenharmony_ci buffer[pos] = '1'; 2048c2ecf20Sopenharmony_ci else 2058c2ecf20Sopenharmony_ci buffer[pos] = '0'; 2068c2ecf20Sopenharmony_ci pos++; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci if (i < 3) { 2098c2ecf20Sopenharmony_ci buffer[pos] = ' '; 2108c2ecf20Sopenharmony_ci pos++; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci buffer[pos] = '\0'; 2148c2ecf20Sopenharmony_ci return buffer; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci/* 2188c2ecf20Sopenharmony_ci * Initial setup of the conversion array GPIO <-> rate 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_cistatic const unsigned int qtet_rates[] = { 2218c2ecf20Sopenharmony_ci 44100, 48000, 88200, 2228c2ecf20Sopenharmony_ci 96000, 176400, 192000, 2238c2ecf20Sopenharmony_ci}; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic const unsigned int cks_vals[] = { 2268c2ecf20Sopenharmony_ci CPLD_CKS_44100HZ, CPLD_CKS_48000HZ, CPLD_CKS_88200HZ, 2278c2ecf20Sopenharmony_ci CPLD_CKS_96000HZ, CPLD_CKS_176400HZ, CPLD_CKS_192000HZ, 2288c2ecf20Sopenharmony_ci}; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list qtet_rates_info = { 2318c2ecf20Sopenharmony_ci .count = ARRAY_SIZE(qtet_rates), 2328c2ecf20Sopenharmony_ci .list = qtet_rates, 2338c2ecf20Sopenharmony_ci .mask = 0, 2348c2ecf20Sopenharmony_ci}; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic void qtet_ak4113_write(void *private_data, unsigned char reg, 2378c2ecf20Sopenharmony_ci unsigned char val) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci snd_vt1724_write_i2c((struct snd_ice1712 *)private_data, AK4113_ADDR, 2408c2ecf20Sopenharmony_ci reg, val); 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic unsigned char qtet_ak4113_read(void *private_data, unsigned char reg) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci return snd_vt1724_read_i2c((struct snd_ice1712 *)private_data, 2468c2ecf20Sopenharmony_ci AK4113_ADDR, reg); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci/* 2518c2ecf20Sopenharmony_ci * AK4620 section 2528c2ecf20Sopenharmony_ci */ 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci/* 2558c2ecf20Sopenharmony_ci * Write data to addr register of ak4620 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_cistatic void qtet_akm_write(struct snd_akm4xxx *ak, int chip, 2588c2ecf20Sopenharmony_ci unsigned char addr, unsigned char data) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci unsigned int tmp, orig_dir; 2618c2ecf20Sopenharmony_ci int idx; 2628c2ecf20Sopenharmony_ci unsigned int addrdata; 2638c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = ak->private_data[0]; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (snd_BUG_ON(chip < 0 || chip >= 4)) 2668c2ecf20Sopenharmony_ci return; 2678c2ecf20Sopenharmony_ci /*dev_dbg(ice->card->dev, "Writing to AK4620: chip=%d, addr=0x%x, 2688c2ecf20Sopenharmony_ci data=0x%x\n", chip, addr, data);*/ 2698c2ecf20Sopenharmony_ci orig_dir = ice->gpio.get_dir(ice); 2708c2ecf20Sopenharmony_ci ice->gpio.set_dir(ice, orig_dir | GPIO_SPI_ALL); 2718c2ecf20Sopenharmony_ci /* set mask - only SPI bits */ 2728c2ecf20Sopenharmony_ci ice->gpio.set_mask(ice, ~GPIO_SPI_ALL); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci tmp = ice->gpio.get_data(ice); 2758c2ecf20Sopenharmony_ci /* high all */ 2768c2ecf20Sopenharmony_ci tmp |= GPIO_SPI_ALL; 2778c2ecf20Sopenharmony_ci ice->gpio.set_data(ice, tmp); 2788c2ecf20Sopenharmony_ci udelay(100); 2798c2ecf20Sopenharmony_ci /* drop chip select */ 2808c2ecf20Sopenharmony_ci if (chip) 2818c2ecf20Sopenharmony_ci /* CODEC 1 */ 2828c2ecf20Sopenharmony_ci tmp &= ~GPIO_SPI_CSN1; 2838c2ecf20Sopenharmony_ci else 2848c2ecf20Sopenharmony_ci tmp &= ~GPIO_SPI_CSN0; 2858c2ecf20Sopenharmony_ci ice->gpio.set_data(ice, tmp); 2868c2ecf20Sopenharmony_ci udelay(100); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* build I2C address + data byte */ 2898c2ecf20Sopenharmony_ci addrdata = (AK4620_ADDR << 6) | 0x20 | (addr & 0x1f); 2908c2ecf20Sopenharmony_ci addrdata = (addrdata << 8) | data; 2918c2ecf20Sopenharmony_ci for (idx = 15; idx >= 0; idx--) { 2928c2ecf20Sopenharmony_ci /* drop clock */ 2938c2ecf20Sopenharmony_ci tmp &= ~GPIO_D5_SPI_CCLK; 2948c2ecf20Sopenharmony_ci ice->gpio.set_data(ice, tmp); 2958c2ecf20Sopenharmony_ci udelay(100); 2968c2ecf20Sopenharmony_ci /* set data */ 2978c2ecf20Sopenharmony_ci if (addrdata & (1 << idx)) 2988c2ecf20Sopenharmony_ci tmp |= GPIO_D4_SPI_CDTO; 2998c2ecf20Sopenharmony_ci else 3008c2ecf20Sopenharmony_ci tmp &= ~GPIO_D4_SPI_CDTO; 3018c2ecf20Sopenharmony_ci ice->gpio.set_data(ice, tmp); 3028c2ecf20Sopenharmony_ci udelay(100); 3038c2ecf20Sopenharmony_ci /* raise clock */ 3048c2ecf20Sopenharmony_ci tmp |= GPIO_D5_SPI_CCLK; 3058c2ecf20Sopenharmony_ci ice->gpio.set_data(ice, tmp); 3068c2ecf20Sopenharmony_ci udelay(100); 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci /* all back to 1 */ 3098c2ecf20Sopenharmony_ci tmp |= GPIO_SPI_ALL; 3108c2ecf20Sopenharmony_ci ice->gpio.set_data(ice, tmp); 3118c2ecf20Sopenharmony_ci udelay(100); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* return all gpios to non-writable */ 3148c2ecf20Sopenharmony_ci ice->gpio.set_mask(ice, 0xffffff); 3158c2ecf20Sopenharmony_ci /* restore GPIOs direction */ 3168c2ecf20Sopenharmony_ci ice->gpio.set_dir(ice, orig_dir); 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic void qtet_akm_set_regs(struct snd_akm4xxx *ak, unsigned char addr, 3208c2ecf20Sopenharmony_ci unsigned char mask, unsigned char value) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci unsigned char tmp; 3238c2ecf20Sopenharmony_ci int chip; 3248c2ecf20Sopenharmony_ci for (chip = 0; chip < ak->num_chips; chip++) { 3258c2ecf20Sopenharmony_ci tmp = snd_akm4xxx_get(ak, chip, addr); 3268c2ecf20Sopenharmony_ci /* clear the bits */ 3278c2ecf20Sopenharmony_ci tmp &= ~mask; 3288c2ecf20Sopenharmony_ci /* set the new bits */ 3298c2ecf20Sopenharmony_ci tmp |= value; 3308c2ecf20Sopenharmony_ci snd_akm4xxx_write(ak, chip, addr, tmp); 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci/* 3358c2ecf20Sopenharmony_ci * change the rate of AK4620 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_cistatic void qtet_akm_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci unsigned char ak4620_dfs; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (rate == 0) /* no hint - S/PDIF input is master or the new spdif 3428c2ecf20Sopenharmony_ci input rate undetected, simply return */ 3438c2ecf20Sopenharmony_ci return; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci /* adjust DFS on codecs - see datasheet */ 3468c2ecf20Sopenharmony_ci if (rate > 108000) 3478c2ecf20Sopenharmony_ci ak4620_dfs = AK4620_DFS1 | AK4620_CKS1; 3488c2ecf20Sopenharmony_ci else if (rate > 54000) 3498c2ecf20Sopenharmony_ci ak4620_dfs = AK4620_DFS0 | AK4620_CKS0; 3508c2ecf20Sopenharmony_ci else 3518c2ecf20Sopenharmony_ci ak4620_dfs = 0; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci /* set new value */ 3548c2ecf20Sopenharmony_ci qtet_akm_set_regs(ak, AK4620_DFS_REG, AK4620_DFS0 | AK4620_DFS1 | 3558c2ecf20Sopenharmony_ci AK4620_CKS0 | AK4620_CKS1, ak4620_dfs); 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci#define AK_CONTROL(xname, xch) { .name = xname, .num_channels = xch } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci#define PCM_12_PLAYBACK_VOLUME "PCM 1/2 Playback Volume" 3618c2ecf20Sopenharmony_ci#define PCM_34_PLAYBACK_VOLUME "PCM 3/4 Playback Volume" 3628c2ecf20Sopenharmony_ci#define PCM_12_CAPTURE_VOLUME "PCM 1/2 Capture Volume" 3638c2ecf20Sopenharmony_ci#define PCM_34_CAPTURE_VOLUME "PCM 3/4 Capture Volume" 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic const struct snd_akm4xxx_dac_channel qtet_dac[] = { 3668c2ecf20Sopenharmony_ci AK_CONTROL(PCM_12_PLAYBACK_VOLUME, 2), 3678c2ecf20Sopenharmony_ci AK_CONTROL(PCM_34_PLAYBACK_VOLUME, 2), 3688c2ecf20Sopenharmony_ci}; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic const struct snd_akm4xxx_adc_channel qtet_adc[] = { 3718c2ecf20Sopenharmony_ci AK_CONTROL(PCM_12_CAPTURE_VOLUME, 2), 3728c2ecf20Sopenharmony_ci AK_CONTROL(PCM_34_CAPTURE_VOLUME, 2), 3738c2ecf20Sopenharmony_ci}; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic const struct snd_akm4xxx akm_qtet_dac = { 3768c2ecf20Sopenharmony_ci .type = SND_AK4620, 3778c2ecf20Sopenharmony_ci .num_dacs = 4, /* DAC1 - Output 12 3788c2ecf20Sopenharmony_ci */ 3798c2ecf20Sopenharmony_ci .num_adcs = 4, /* ADC1 - Input 12 3808c2ecf20Sopenharmony_ci */ 3818c2ecf20Sopenharmony_ci .ops = { 3828c2ecf20Sopenharmony_ci .write = qtet_akm_write, 3838c2ecf20Sopenharmony_ci .set_rate_val = qtet_akm_set_rate_val, 3848c2ecf20Sopenharmony_ci }, 3858c2ecf20Sopenharmony_ci .dac_info = qtet_dac, 3868c2ecf20Sopenharmony_ci .adc_info = qtet_adc, 3878c2ecf20Sopenharmony_ci}; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci/* Communication routines with the CPLD */ 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci/* Writes data to external register reg, both reg and data are 3938c2ecf20Sopenharmony_ci * GPIO representations */ 3948c2ecf20Sopenharmony_cistatic void reg_write(struct snd_ice1712 *ice, unsigned int reg, 3958c2ecf20Sopenharmony_ci unsigned int data) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci unsigned int tmp; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci mutex_lock(&ice->gpio_mutex); 4008c2ecf20Sopenharmony_ci /* set direction of used GPIOs*/ 4018c2ecf20Sopenharmony_ci /* all outputs */ 4028c2ecf20Sopenharmony_ci tmp = 0x00ffff; 4038c2ecf20Sopenharmony_ci ice->gpio.set_dir(ice, tmp); 4048c2ecf20Sopenharmony_ci /* mask - writable bits */ 4058c2ecf20Sopenharmony_ci ice->gpio.set_mask(ice, ~(tmp)); 4068c2ecf20Sopenharmony_ci /* write the data */ 4078c2ecf20Sopenharmony_ci tmp = ice->gpio.get_data(ice); 4088c2ecf20Sopenharmony_ci tmp &= ~GPIO_DATA_MASK; 4098c2ecf20Sopenharmony_ci tmp |= data; 4108c2ecf20Sopenharmony_ci ice->gpio.set_data(ice, tmp); 4118c2ecf20Sopenharmony_ci udelay(100); 4128c2ecf20Sopenharmony_ci /* drop output enable */ 4138c2ecf20Sopenharmony_ci tmp &= ~GPIO_EX_GPIOE; 4148c2ecf20Sopenharmony_ci ice->gpio.set_data(ice, tmp); 4158c2ecf20Sopenharmony_ci udelay(100); 4168c2ecf20Sopenharmony_ci /* drop the register gpio */ 4178c2ecf20Sopenharmony_ci tmp &= ~reg; 4188c2ecf20Sopenharmony_ci ice->gpio.set_data(ice, tmp); 4198c2ecf20Sopenharmony_ci udelay(100); 4208c2ecf20Sopenharmony_ci /* raise the register GPIO */ 4218c2ecf20Sopenharmony_ci tmp |= reg; 4228c2ecf20Sopenharmony_ci ice->gpio.set_data(ice, tmp); 4238c2ecf20Sopenharmony_ci udelay(100); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* raise all data gpios */ 4268c2ecf20Sopenharmony_ci tmp |= GPIO_DATA_MASK; 4278c2ecf20Sopenharmony_ci ice->gpio.set_data(ice, tmp); 4288c2ecf20Sopenharmony_ci /* mask - immutable bits */ 4298c2ecf20Sopenharmony_ci ice->gpio.set_mask(ice, 0xffffff); 4308c2ecf20Sopenharmony_ci /* outputs only 8-15 */ 4318c2ecf20Sopenharmony_ci ice->gpio.set_dir(ice, 0x00ff00); 4328c2ecf20Sopenharmony_ci mutex_unlock(&ice->gpio_mutex); 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic unsigned int get_scr(struct snd_ice1712 *ice) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci struct qtet_spec *spec = ice->spec; 4388c2ecf20Sopenharmony_ci return spec->scr; 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic unsigned int get_mcr(struct snd_ice1712 *ice) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci struct qtet_spec *spec = ice->spec; 4448c2ecf20Sopenharmony_ci return spec->mcr; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic unsigned int get_cpld(struct snd_ice1712 *ice) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci struct qtet_spec *spec = ice->spec; 4508c2ecf20Sopenharmony_ci return spec->cpld; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic void set_scr(struct snd_ice1712 *ice, unsigned int val) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci struct qtet_spec *spec = ice->spec; 4568c2ecf20Sopenharmony_ci reg_write(ice, GPIO_SCR, val); 4578c2ecf20Sopenharmony_ci spec->scr = val; 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic void set_mcr(struct snd_ice1712 *ice, unsigned int val) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci struct qtet_spec *spec = ice->spec; 4638c2ecf20Sopenharmony_ci reg_write(ice, GPIO_MCR, val); 4648c2ecf20Sopenharmony_ci spec->mcr = val; 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic void set_cpld(struct snd_ice1712 *ice, unsigned int val) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci struct qtet_spec *spec = ice->spec; 4708c2ecf20Sopenharmony_ci reg_write(ice, GPIO_CPLD_CSN, val); 4718c2ecf20Sopenharmony_ci spec->cpld = val; 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_cistatic void proc_regs_read(struct snd_info_entry *entry, 4758c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = entry->private_data; 4788c2ecf20Sopenharmony_ci char bin_buffer[36]; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci snd_iprintf(buffer, "SCR: %s\n", get_binary(bin_buffer, 4818c2ecf20Sopenharmony_ci get_scr(ice))); 4828c2ecf20Sopenharmony_ci snd_iprintf(buffer, "MCR: %s\n", get_binary(bin_buffer, 4838c2ecf20Sopenharmony_ci get_mcr(ice))); 4848c2ecf20Sopenharmony_ci snd_iprintf(buffer, "CPLD: %s\n", get_binary(bin_buffer, 4858c2ecf20Sopenharmony_ci get_cpld(ice))); 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic void proc_init(struct snd_ice1712 *ice) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci snd_card_ro_proc_new(ice->card, "quartet", ice, proc_regs_read); 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistatic int qtet_mute_get(struct snd_kcontrol *kcontrol, 4948c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 4978c2ecf20Sopenharmony_ci unsigned int val; 4988c2ecf20Sopenharmony_ci val = get_scr(ice) & SCR_MUTE; 4998c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = (val) ? 0 : 1; 5008c2ecf20Sopenharmony_ci return 0; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic int qtet_mute_put(struct snd_kcontrol *kcontrol, 5048c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 5078c2ecf20Sopenharmony_ci unsigned int old, new, smute; 5088c2ecf20Sopenharmony_ci old = get_scr(ice) & SCR_MUTE; 5098c2ecf20Sopenharmony_ci if (ucontrol->value.integer.value[0]) { 5108c2ecf20Sopenharmony_ci /* unmute */ 5118c2ecf20Sopenharmony_ci new = 0; 5128c2ecf20Sopenharmony_ci /* un-smuting DAC */ 5138c2ecf20Sopenharmony_ci smute = 0; 5148c2ecf20Sopenharmony_ci } else { 5158c2ecf20Sopenharmony_ci /* mute */ 5168c2ecf20Sopenharmony_ci new = SCR_MUTE; 5178c2ecf20Sopenharmony_ci /* smuting DAC */ 5188c2ecf20Sopenharmony_ci smute = AK4620_SMUTE; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci if (old != new) { 5218c2ecf20Sopenharmony_ci struct snd_akm4xxx *ak = ice->akm; 5228c2ecf20Sopenharmony_ci set_scr(ice, (get_scr(ice) & ~SCR_MUTE) | new); 5238c2ecf20Sopenharmony_ci /* set smute */ 5248c2ecf20Sopenharmony_ci qtet_akm_set_regs(ak, AK4620_DEEMVOL_REG, AK4620_SMUTE, smute); 5258c2ecf20Sopenharmony_ci return 1; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci /* no change */ 5288c2ecf20Sopenharmony_ci return 0; 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic int qtet_ain12_enum_info(struct snd_kcontrol *kcontrol, 5328c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci static const char * const texts[3] = 5358c2ecf20Sopenharmony_ci {"Line In 1/2", "Mic", "Mic + Low-cut"}; 5368c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts); 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_cistatic int qtet_ain12_sw_get(struct snd_kcontrol *kcontrol, 5408c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 5438c2ecf20Sopenharmony_ci unsigned int val, result; 5448c2ecf20Sopenharmony_ci val = get_scr(ice) & (SCR_AIN12_SEL1 | SCR_AIN12_SEL0); 5458c2ecf20Sopenharmony_ci switch (val) { 5468c2ecf20Sopenharmony_ci case SCR_AIN12_LINE: 5478c2ecf20Sopenharmony_ci result = 0; 5488c2ecf20Sopenharmony_ci break; 5498c2ecf20Sopenharmony_ci case SCR_AIN12_MIC: 5508c2ecf20Sopenharmony_ci result = 1; 5518c2ecf20Sopenharmony_ci break; 5528c2ecf20Sopenharmony_ci case SCR_AIN12_LOWCUT: 5538c2ecf20Sopenharmony_ci result = 2; 5548c2ecf20Sopenharmony_ci break; 5558c2ecf20Sopenharmony_ci default: 5568c2ecf20Sopenharmony_ci /* BUG - no other combinations allowed */ 5578c2ecf20Sopenharmony_ci snd_BUG(); 5588c2ecf20Sopenharmony_ci result = 0; 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = result; 5618c2ecf20Sopenharmony_ci return 0; 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cistatic int qtet_ain12_sw_put(struct snd_kcontrol *kcontrol, 5658c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5668c2ecf20Sopenharmony_ci{ 5678c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 5688c2ecf20Sopenharmony_ci unsigned int old, new, tmp, masked_old; 5698c2ecf20Sopenharmony_ci old = new = get_scr(ice); 5708c2ecf20Sopenharmony_ci masked_old = old & (SCR_AIN12_SEL1 | SCR_AIN12_SEL0); 5718c2ecf20Sopenharmony_ci tmp = ucontrol->value.integer.value[0]; 5728c2ecf20Sopenharmony_ci if (tmp == 2) 5738c2ecf20Sopenharmony_ci tmp = 3; /* binary 10 is not supported */ 5748c2ecf20Sopenharmony_ci tmp <<= 4; /* shifting to SCR_AIN12_SEL0 */ 5758c2ecf20Sopenharmony_ci if (tmp != masked_old) { 5768c2ecf20Sopenharmony_ci /* change requested */ 5778c2ecf20Sopenharmony_ci switch (tmp) { 5788c2ecf20Sopenharmony_ci case SCR_AIN12_LINE: 5798c2ecf20Sopenharmony_ci new = old & ~(SCR_AIN12_SEL1 | SCR_AIN12_SEL0); 5808c2ecf20Sopenharmony_ci set_scr(ice, new); 5818c2ecf20Sopenharmony_ci /* turn off relay */ 5828c2ecf20Sopenharmony_ci new &= ~SCR_RELAY; 5838c2ecf20Sopenharmony_ci set_scr(ice, new); 5848c2ecf20Sopenharmony_ci break; 5858c2ecf20Sopenharmony_ci case SCR_AIN12_MIC: 5868c2ecf20Sopenharmony_ci /* turn on relay */ 5878c2ecf20Sopenharmony_ci new = old | SCR_RELAY; 5888c2ecf20Sopenharmony_ci set_scr(ice, new); 5898c2ecf20Sopenharmony_ci new = (new & ~SCR_AIN12_SEL1) | SCR_AIN12_SEL0; 5908c2ecf20Sopenharmony_ci set_scr(ice, new); 5918c2ecf20Sopenharmony_ci break; 5928c2ecf20Sopenharmony_ci case SCR_AIN12_LOWCUT: 5938c2ecf20Sopenharmony_ci /* turn on relay */ 5948c2ecf20Sopenharmony_ci new = old | SCR_RELAY; 5958c2ecf20Sopenharmony_ci set_scr(ice, new); 5968c2ecf20Sopenharmony_ci new |= SCR_AIN12_SEL1 | SCR_AIN12_SEL0; 5978c2ecf20Sopenharmony_ci set_scr(ice, new); 5988c2ecf20Sopenharmony_ci break; 5998c2ecf20Sopenharmony_ci default: 6008c2ecf20Sopenharmony_ci snd_BUG(); 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci return 1; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci /* no change */ 6058c2ecf20Sopenharmony_ci return 0; 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cistatic int qtet_php_get(struct snd_kcontrol *kcontrol, 6098c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 6128c2ecf20Sopenharmony_ci unsigned int val; 6138c2ecf20Sopenharmony_ci /* if phantom voltage =48V, phantom on */ 6148c2ecf20Sopenharmony_ci val = get_scr(ice) & SCR_PHP_V; 6158c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = val ? 1 : 0; 6168c2ecf20Sopenharmony_ci return 0; 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cistatic int qtet_php_put(struct snd_kcontrol *kcontrol, 6208c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 6218c2ecf20Sopenharmony_ci{ 6228c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 6238c2ecf20Sopenharmony_ci unsigned int old, new; 6248c2ecf20Sopenharmony_ci old = new = get_scr(ice); 6258c2ecf20Sopenharmony_ci if (ucontrol->value.integer.value[0] /* phantom on requested */ 6268c2ecf20Sopenharmony_ci && (~old & SCR_PHP_V)) /* 0 = voltage 5V */ { 6278c2ecf20Sopenharmony_ci /* is off, turn on */ 6288c2ecf20Sopenharmony_ci /* turn voltage on first, = 1 */ 6298c2ecf20Sopenharmony_ci new = old | SCR_PHP_V; 6308c2ecf20Sopenharmony_ci set_scr(ice, new); 6318c2ecf20Sopenharmony_ci /* turn phantom on, = 0 */ 6328c2ecf20Sopenharmony_ci new &= ~SCR_PHP; 6338c2ecf20Sopenharmony_ci set_scr(ice, new); 6348c2ecf20Sopenharmony_ci } else if (!ucontrol->value.integer.value[0] && (old & SCR_PHP_V)) { 6358c2ecf20Sopenharmony_ci /* phantom off requested and 1 = voltage 48V */ 6368c2ecf20Sopenharmony_ci /* is on, turn off */ 6378c2ecf20Sopenharmony_ci /* turn voltage off first, = 0 */ 6388c2ecf20Sopenharmony_ci new = old & ~SCR_PHP_V; 6398c2ecf20Sopenharmony_ci set_scr(ice, new); 6408c2ecf20Sopenharmony_ci /* turn phantom off, = 1 */ 6418c2ecf20Sopenharmony_ci new |= SCR_PHP; 6428c2ecf20Sopenharmony_ci set_scr(ice, new); 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci if (old != new) 6458c2ecf20Sopenharmony_ci return 1; 6468c2ecf20Sopenharmony_ci /* no change */ 6478c2ecf20Sopenharmony_ci return 0; 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci#define PRIV_SW(xid, xbit, xreg) [xid] = {.bit = xbit,\ 6518c2ecf20Sopenharmony_ci .set_register = set_##xreg,\ 6528c2ecf20Sopenharmony_ci .get_register = get_##xreg, } 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci#define PRIV_ENUM2(xid, xbit, xreg, xtext1, xtext2) [xid] = {.bit = xbit,\ 6568c2ecf20Sopenharmony_ci .set_register = set_##xreg,\ 6578c2ecf20Sopenharmony_ci .get_register = get_##xreg,\ 6588c2ecf20Sopenharmony_ci .texts = {xtext1, xtext2} } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic const struct qtet_kcontrol_private qtet_privates[] = { 6618c2ecf20Sopenharmony_ci PRIV_ENUM2(IN12_SEL, CPLD_IN12_SEL, cpld, "An In 1/2", "An In 3/4"), 6628c2ecf20Sopenharmony_ci PRIV_ENUM2(IN34_SEL, CPLD_IN34_SEL, cpld, "An In 3/4", "IEC958 In"), 6638c2ecf20Sopenharmony_ci PRIV_ENUM2(AIN34_SEL, SCR_AIN34_SEL, scr, "Line In 3/4", "Hi-Z"), 6648c2ecf20Sopenharmony_ci PRIV_ENUM2(COAX_OUT, CPLD_COAX_OUT, cpld, "IEC958", "I2S"), 6658c2ecf20Sopenharmony_ci PRIV_SW(IN12_MON12, MCR_IN12_MON12, mcr), 6668c2ecf20Sopenharmony_ci PRIV_SW(IN12_MON34, MCR_IN12_MON34, mcr), 6678c2ecf20Sopenharmony_ci PRIV_SW(IN34_MON12, MCR_IN34_MON12, mcr), 6688c2ecf20Sopenharmony_ci PRIV_SW(IN34_MON34, MCR_IN34_MON34, mcr), 6698c2ecf20Sopenharmony_ci PRIV_SW(OUT12_MON34, MCR_OUT12_MON34, mcr), 6708c2ecf20Sopenharmony_ci PRIV_SW(OUT34_MON12, MCR_OUT34_MON12, mcr), 6718c2ecf20Sopenharmony_ci}; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic int qtet_enum_info(struct snd_kcontrol *kcontrol, 6748c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci struct qtet_kcontrol_private private = 6778c2ecf20Sopenharmony_ci qtet_privates[kcontrol->private_value]; 6788c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(private.texts), 6798c2ecf20Sopenharmony_ci private.texts); 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic int qtet_sw_get(struct snd_kcontrol *kcontrol, 6838c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci struct qtet_kcontrol_private private = 6868c2ecf20Sopenharmony_ci qtet_privates[kcontrol->private_value]; 6878c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 6888c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 6898c2ecf20Sopenharmony_ci (private.get_register(ice) & private.bit) ? 1 : 0; 6908c2ecf20Sopenharmony_ci return 0; 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_cistatic int qtet_sw_put(struct snd_kcontrol *kcontrol, 6948c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 6958c2ecf20Sopenharmony_ci{ 6968c2ecf20Sopenharmony_ci struct qtet_kcontrol_private private = 6978c2ecf20Sopenharmony_ci qtet_privates[kcontrol->private_value]; 6988c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); 6998c2ecf20Sopenharmony_ci unsigned int old, new; 7008c2ecf20Sopenharmony_ci old = private.get_register(ice); 7018c2ecf20Sopenharmony_ci if (ucontrol->value.integer.value[0]) 7028c2ecf20Sopenharmony_ci new = old | private.bit; 7038c2ecf20Sopenharmony_ci else 7048c2ecf20Sopenharmony_ci new = old & ~private.bit; 7058c2ecf20Sopenharmony_ci if (old != new) { 7068c2ecf20Sopenharmony_ci private.set_register(ice, new); 7078c2ecf20Sopenharmony_ci return 1; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci /* no change */ 7108c2ecf20Sopenharmony_ci return 0; 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci#define qtet_sw_info snd_ctl_boolean_mono_info 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci#define QTET_CONTROL(xname, xtype, xpriv) \ 7168c2ecf20Sopenharmony_ci {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,\ 7178c2ecf20Sopenharmony_ci .name = xname,\ 7188c2ecf20Sopenharmony_ci .info = qtet_##xtype##_info,\ 7198c2ecf20Sopenharmony_ci .get = qtet_sw_get,\ 7208c2ecf20Sopenharmony_ci .put = qtet_sw_put,\ 7218c2ecf20Sopenharmony_ci .private_value = xpriv } 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new qtet_controls[] = { 7248c2ecf20Sopenharmony_ci { 7258c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 7268c2ecf20Sopenharmony_ci .name = "Master Playback Switch", 7278c2ecf20Sopenharmony_ci .info = qtet_sw_info, 7288c2ecf20Sopenharmony_ci .get = qtet_mute_get, 7298c2ecf20Sopenharmony_ci .put = qtet_mute_put, 7308c2ecf20Sopenharmony_ci .private_value = 0 7318c2ecf20Sopenharmony_ci }, 7328c2ecf20Sopenharmony_ci { 7338c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 7348c2ecf20Sopenharmony_ci .name = "Phantom Power", 7358c2ecf20Sopenharmony_ci .info = qtet_sw_info, 7368c2ecf20Sopenharmony_ci .get = qtet_php_get, 7378c2ecf20Sopenharmony_ci .put = qtet_php_put, 7388c2ecf20Sopenharmony_ci .private_value = 0 7398c2ecf20Sopenharmony_ci }, 7408c2ecf20Sopenharmony_ci { 7418c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 7428c2ecf20Sopenharmony_ci .name = "Analog In 1/2 Capture Switch", 7438c2ecf20Sopenharmony_ci .info = qtet_ain12_enum_info, 7448c2ecf20Sopenharmony_ci .get = qtet_ain12_sw_get, 7458c2ecf20Sopenharmony_ci .put = qtet_ain12_sw_put, 7468c2ecf20Sopenharmony_ci .private_value = 0 7478c2ecf20Sopenharmony_ci }, 7488c2ecf20Sopenharmony_ci QTET_CONTROL("Analog In 3/4 Capture Switch", enum, AIN34_SEL), 7498c2ecf20Sopenharmony_ci QTET_CONTROL("PCM In 1/2 Capture Switch", enum, IN12_SEL), 7508c2ecf20Sopenharmony_ci QTET_CONTROL("PCM In 3/4 Capture Switch", enum, IN34_SEL), 7518c2ecf20Sopenharmony_ci QTET_CONTROL("Coax Output Source", enum, COAX_OUT), 7528c2ecf20Sopenharmony_ci QTET_CONTROL("Analog In 1/2 to Monitor 1/2", sw, IN12_MON12), 7538c2ecf20Sopenharmony_ci QTET_CONTROL("Analog In 1/2 to Monitor 3/4", sw, IN12_MON34), 7548c2ecf20Sopenharmony_ci QTET_CONTROL("Analog In 3/4 to Monitor 1/2", sw, IN34_MON12), 7558c2ecf20Sopenharmony_ci QTET_CONTROL("Analog In 3/4 to Monitor 3/4", sw, IN34_MON34), 7568c2ecf20Sopenharmony_ci QTET_CONTROL("Output 1/2 to Monitor 3/4", sw, OUT12_MON34), 7578c2ecf20Sopenharmony_ci QTET_CONTROL("Output 3/4 to Monitor 1/2", sw, OUT34_MON12), 7588c2ecf20Sopenharmony_ci}; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cistatic const char * const follower_vols[] = { 7618c2ecf20Sopenharmony_ci PCM_12_PLAYBACK_VOLUME, 7628c2ecf20Sopenharmony_ci PCM_34_PLAYBACK_VOLUME, 7638c2ecf20Sopenharmony_ci NULL 7648c2ecf20Sopenharmony_ci}; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_cistatic 7678c2ecf20Sopenharmony_ciDECLARE_TLV_DB_SCALE(qtet_master_db_scale, -6350, 50, 1); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_cistatic struct snd_kcontrol *ctl_find(struct snd_card *card, 7708c2ecf20Sopenharmony_ci const char *name) 7718c2ecf20Sopenharmony_ci{ 7728c2ecf20Sopenharmony_ci struct snd_ctl_elem_id sid = {0}; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci strlcpy(sid.name, name, sizeof(sid.name)); 7758c2ecf20Sopenharmony_ci sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 7768c2ecf20Sopenharmony_ci return snd_ctl_find_id(card, &sid); 7778c2ecf20Sopenharmony_ci} 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_cistatic void add_followers(struct snd_card *card, 7808c2ecf20Sopenharmony_ci struct snd_kcontrol *master, const char * const *list) 7818c2ecf20Sopenharmony_ci{ 7828c2ecf20Sopenharmony_ci for (; *list; list++) { 7838c2ecf20Sopenharmony_ci struct snd_kcontrol *follower = ctl_find(card, *list); 7848c2ecf20Sopenharmony_ci if (follower) 7858c2ecf20Sopenharmony_ci snd_ctl_add_follower(master, follower); 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_cistatic int qtet_add_controls(struct snd_ice1712 *ice) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci struct qtet_spec *spec = ice->spec; 7928c2ecf20Sopenharmony_ci int err, i; 7938c2ecf20Sopenharmony_ci struct snd_kcontrol *vmaster; 7948c2ecf20Sopenharmony_ci err = snd_ice1712_akm4xxx_build_controls(ice); 7958c2ecf20Sopenharmony_ci if (err < 0) 7968c2ecf20Sopenharmony_ci return err; 7978c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(qtet_controls); i++) { 7988c2ecf20Sopenharmony_ci err = snd_ctl_add(ice->card, 7998c2ecf20Sopenharmony_ci snd_ctl_new1(&qtet_controls[i], ice)); 8008c2ecf20Sopenharmony_ci if (err < 0) 8018c2ecf20Sopenharmony_ci return err; 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci /* Create virtual master control */ 8058c2ecf20Sopenharmony_ci vmaster = snd_ctl_make_virtual_master("Master Playback Volume", 8068c2ecf20Sopenharmony_ci qtet_master_db_scale); 8078c2ecf20Sopenharmony_ci if (!vmaster) 8088c2ecf20Sopenharmony_ci return -ENOMEM; 8098c2ecf20Sopenharmony_ci add_followers(ice->card, vmaster, follower_vols); 8108c2ecf20Sopenharmony_ci err = snd_ctl_add(ice->card, vmaster); 8118c2ecf20Sopenharmony_ci if (err < 0) 8128c2ecf20Sopenharmony_ci return err; 8138c2ecf20Sopenharmony_ci /* only capture SPDIF over AK4113 */ 8148c2ecf20Sopenharmony_ci return snd_ak4113_build(spec->ak4113, 8158c2ecf20Sopenharmony_ci ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_cistatic inline int qtet_is_spdif_master(struct snd_ice1712 *ice) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci /* CPLD_SYNC_SEL: 0 = internal, 1 = external (i.e. spdif master) */ 8218c2ecf20Sopenharmony_ci return (get_cpld(ice) & CPLD_SYNC_SEL) ? 1 : 0; 8228c2ecf20Sopenharmony_ci} 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_cistatic unsigned int qtet_get_rate(struct snd_ice1712 *ice) 8258c2ecf20Sopenharmony_ci{ 8268c2ecf20Sopenharmony_ci int i; 8278c2ecf20Sopenharmony_ci unsigned char result; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci result = get_cpld(ice) & CPLD_CKS_MASK; 8308c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cks_vals); i++) 8318c2ecf20Sopenharmony_ci if (cks_vals[i] == result) 8328c2ecf20Sopenharmony_ci return qtet_rates[i]; 8338c2ecf20Sopenharmony_ci return 0; 8348c2ecf20Sopenharmony_ci} 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_cistatic int get_cks_val(int rate) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci int i; 8398c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(qtet_rates); i++) 8408c2ecf20Sopenharmony_ci if (qtet_rates[i] == rate) 8418c2ecf20Sopenharmony_ci return cks_vals[i]; 8428c2ecf20Sopenharmony_ci return 0; 8438c2ecf20Sopenharmony_ci} 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci/* setting new rate */ 8468c2ecf20Sopenharmony_cistatic void qtet_set_rate(struct snd_ice1712 *ice, unsigned int rate) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci unsigned int new; 8498c2ecf20Sopenharmony_ci unsigned char val; 8508c2ecf20Sopenharmony_ci /* switching ice1724 to external clock - supplied by ext. circuits */ 8518c2ecf20Sopenharmony_ci val = inb(ICEMT1724(ice, RATE)); 8528c2ecf20Sopenharmony_ci outb(val | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE)); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci new = (get_cpld(ice) & ~CPLD_CKS_MASK) | get_cks_val(rate); 8558c2ecf20Sopenharmony_ci /* switch to internal clock, drop CPLD_SYNC_SEL */ 8568c2ecf20Sopenharmony_ci new &= ~CPLD_SYNC_SEL; 8578c2ecf20Sopenharmony_ci /* dev_dbg(ice->card->dev, "QT - set_rate: old %x, new %x\n", 8588c2ecf20Sopenharmony_ci get_cpld(ice), new); */ 8598c2ecf20Sopenharmony_ci set_cpld(ice, new); 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_cistatic inline unsigned char qtet_set_mclk(struct snd_ice1712 *ice, 8638c2ecf20Sopenharmony_ci unsigned int rate) 8648c2ecf20Sopenharmony_ci{ 8658c2ecf20Sopenharmony_ci /* no change in master clock */ 8668c2ecf20Sopenharmony_ci return 0; 8678c2ecf20Sopenharmony_ci} 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci/* setting clock to external - SPDIF */ 8708c2ecf20Sopenharmony_cistatic int qtet_set_spdif_clock(struct snd_ice1712 *ice, int type) 8718c2ecf20Sopenharmony_ci{ 8728c2ecf20Sopenharmony_ci unsigned int old, new; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci old = new = get_cpld(ice); 8758c2ecf20Sopenharmony_ci new &= ~(CPLD_CKS_MASK | CPLD_WORD_SEL); 8768c2ecf20Sopenharmony_ci switch (type) { 8778c2ecf20Sopenharmony_ci case EXT_SPDIF_TYPE: 8788c2ecf20Sopenharmony_ci new |= CPLD_EXT_SPDIF; 8798c2ecf20Sopenharmony_ci break; 8808c2ecf20Sopenharmony_ci case EXT_WORDCLOCK_1FS_TYPE: 8818c2ecf20Sopenharmony_ci new |= CPLD_EXT_WORDCLOCK_1FS; 8828c2ecf20Sopenharmony_ci break; 8838c2ecf20Sopenharmony_ci case EXT_WORDCLOCK_256FS_TYPE: 8848c2ecf20Sopenharmony_ci new |= CPLD_EXT_WORDCLOCK_256FS; 8858c2ecf20Sopenharmony_ci break; 8868c2ecf20Sopenharmony_ci default: 8878c2ecf20Sopenharmony_ci snd_BUG(); 8888c2ecf20Sopenharmony_ci } 8898c2ecf20Sopenharmony_ci if (old != new) { 8908c2ecf20Sopenharmony_ci set_cpld(ice, new); 8918c2ecf20Sopenharmony_ci /* changed */ 8928c2ecf20Sopenharmony_ci return 1; 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci return 0; 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistatic int qtet_get_spdif_master_type(struct snd_ice1712 *ice) 8988c2ecf20Sopenharmony_ci{ 8998c2ecf20Sopenharmony_ci unsigned int val; 9008c2ecf20Sopenharmony_ci int result; 9018c2ecf20Sopenharmony_ci val = get_cpld(ice); 9028c2ecf20Sopenharmony_ci /* checking only rate/clock-related bits */ 9038c2ecf20Sopenharmony_ci val &= (CPLD_CKS_MASK | CPLD_WORD_SEL | CPLD_SYNC_SEL); 9048c2ecf20Sopenharmony_ci if (!(val & CPLD_SYNC_SEL)) { 9058c2ecf20Sopenharmony_ci /* switched to internal clock, is not any external type */ 9068c2ecf20Sopenharmony_ci result = -1; 9078c2ecf20Sopenharmony_ci } else { 9088c2ecf20Sopenharmony_ci switch (val) { 9098c2ecf20Sopenharmony_ci case (CPLD_EXT_SPDIF): 9108c2ecf20Sopenharmony_ci result = EXT_SPDIF_TYPE; 9118c2ecf20Sopenharmony_ci break; 9128c2ecf20Sopenharmony_ci case (CPLD_EXT_WORDCLOCK_1FS): 9138c2ecf20Sopenharmony_ci result = EXT_WORDCLOCK_1FS_TYPE; 9148c2ecf20Sopenharmony_ci break; 9158c2ecf20Sopenharmony_ci case (CPLD_EXT_WORDCLOCK_256FS): 9168c2ecf20Sopenharmony_ci result = EXT_WORDCLOCK_256FS_TYPE; 9178c2ecf20Sopenharmony_ci break; 9188c2ecf20Sopenharmony_ci default: 9198c2ecf20Sopenharmony_ci /* undefined combination of external clock setup */ 9208c2ecf20Sopenharmony_ci snd_BUG(); 9218c2ecf20Sopenharmony_ci result = 0; 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci return result; 9258c2ecf20Sopenharmony_ci} 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci/* Called when ak4113 detects change in the input SPDIF stream */ 9288c2ecf20Sopenharmony_cistatic void qtet_ak4113_change(struct ak4113 *ak4113, unsigned char c0, 9298c2ecf20Sopenharmony_ci unsigned char c1) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci struct snd_ice1712 *ice = ak4113->change_callback_private; 9328c2ecf20Sopenharmony_ci int rate; 9338c2ecf20Sopenharmony_ci if ((qtet_get_spdif_master_type(ice) == EXT_SPDIF_TYPE) && 9348c2ecf20Sopenharmony_ci c1) { 9358c2ecf20Sopenharmony_ci /* only for SPDIF master mode, rate was changed */ 9368c2ecf20Sopenharmony_ci rate = snd_ak4113_external_rate(ak4113); 9378c2ecf20Sopenharmony_ci /* dev_dbg(ice->card->dev, "ak4113 - input rate changed to %d\n", 9388c2ecf20Sopenharmony_ci rate); */ 9398c2ecf20Sopenharmony_ci qtet_akm_set_rate_val(ice->akm, rate); 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci} 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci/* 9448c2ecf20Sopenharmony_ci * If clock slaved to SPDIF-IN, setting runtime rate 9458c2ecf20Sopenharmony_ci * to the detected external rate 9468c2ecf20Sopenharmony_ci */ 9478c2ecf20Sopenharmony_cistatic void qtet_spdif_in_open(struct snd_ice1712 *ice, 9488c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci struct qtet_spec *spec = ice->spec; 9518c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 9528c2ecf20Sopenharmony_ci int rate; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci if (qtet_get_spdif_master_type(ice) != EXT_SPDIF_TYPE) 9558c2ecf20Sopenharmony_ci /* not external SPDIF, no rate limitation */ 9568c2ecf20Sopenharmony_ci return; 9578c2ecf20Sopenharmony_ci /* only external SPDIF can detect incoming sample rate */ 9588c2ecf20Sopenharmony_ci rate = snd_ak4113_external_rate(spec->ak4113); 9598c2ecf20Sopenharmony_ci if (rate >= runtime->hw.rate_min && rate <= runtime->hw.rate_max) { 9608c2ecf20Sopenharmony_ci runtime->hw.rate_min = rate; 9618c2ecf20Sopenharmony_ci runtime->hw.rate_max = rate; 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci} 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci/* 9668c2ecf20Sopenharmony_ci * initialize the chip 9678c2ecf20Sopenharmony_ci */ 9688c2ecf20Sopenharmony_cistatic int qtet_init(struct snd_ice1712 *ice) 9698c2ecf20Sopenharmony_ci{ 9708c2ecf20Sopenharmony_ci static const unsigned char ak4113_init_vals[] = { 9718c2ecf20Sopenharmony_ci /* AK4113_REG_PWRDN */ AK4113_RST | AK4113_PWN | 9728c2ecf20Sopenharmony_ci AK4113_OCKS0 | AK4113_OCKS1, 9738c2ecf20Sopenharmony_ci /* AK4113_REQ_FORMAT */ AK4113_DIF_I24I2S | AK4113_VTX | 9748c2ecf20Sopenharmony_ci AK4113_DEM_OFF | AK4113_DEAU, 9758c2ecf20Sopenharmony_ci /* AK4113_REG_IO0 */ AK4113_OPS2 | AK4113_TXE | 9768c2ecf20Sopenharmony_ci AK4113_XTL_24_576M, 9778c2ecf20Sopenharmony_ci /* AK4113_REG_IO1 */ AK4113_EFH_1024LRCLK | AK4113_IPS(0), 9788c2ecf20Sopenharmony_ci /* AK4113_REG_INT0_MASK */ 0, 9798c2ecf20Sopenharmony_ci /* AK4113_REG_INT1_MASK */ 0, 9808c2ecf20Sopenharmony_ci /* AK4113_REG_DATDTS */ 0, 9818c2ecf20Sopenharmony_ci }; 9828c2ecf20Sopenharmony_ci int err; 9838c2ecf20Sopenharmony_ci struct qtet_spec *spec; 9848c2ecf20Sopenharmony_ci struct snd_akm4xxx *ak; 9858c2ecf20Sopenharmony_ci unsigned char val; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci /* switching ice1724 to external clock - supplied by ext. circuits */ 9888c2ecf20Sopenharmony_ci val = inb(ICEMT1724(ice, RATE)); 9898c2ecf20Sopenharmony_ci outb(val | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE)); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci spec = kzalloc(sizeof(*spec), GFP_KERNEL); 9928c2ecf20Sopenharmony_ci if (!spec) 9938c2ecf20Sopenharmony_ci return -ENOMEM; 9948c2ecf20Sopenharmony_ci /* qtet is clocked by Xilinx array */ 9958c2ecf20Sopenharmony_ci ice->hw_rates = &qtet_rates_info; 9968c2ecf20Sopenharmony_ci ice->is_spdif_master = qtet_is_spdif_master; 9978c2ecf20Sopenharmony_ci ice->get_rate = qtet_get_rate; 9988c2ecf20Sopenharmony_ci ice->set_rate = qtet_set_rate; 9998c2ecf20Sopenharmony_ci ice->set_mclk = qtet_set_mclk; 10008c2ecf20Sopenharmony_ci ice->set_spdif_clock = qtet_set_spdif_clock; 10018c2ecf20Sopenharmony_ci ice->get_spdif_master_type = qtet_get_spdif_master_type; 10028c2ecf20Sopenharmony_ci ice->ext_clock_names = ext_clock_names; 10038c2ecf20Sopenharmony_ci ice->ext_clock_count = ARRAY_SIZE(ext_clock_names); 10048c2ecf20Sopenharmony_ci /* since Qtet can detect correct SPDIF-in rate, all streams can be 10058c2ecf20Sopenharmony_ci * limited to this specific rate */ 10068c2ecf20Sopenharmony_ci ice->spdif.ops.open = ice->pro_open = qtet_spdif_in_open; 10078c2ecf20Sopenharmony_ci ice->spec = spec; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci /* Mute Off */ 10108c2ecf20Sopenharmony_ci /* SCR Initialize*/ 10118c2ecf20Sopenharmony_ci /* keep codec power down first */ 10128c2ecf20Sopenharmony_ci set_scr(ice, SCR_PHP); 10138c2ecf20Sopenharmony_ci udelay(1); 10148c2ecf20Sopenharmony_ci /* codec power up */ 10158c2ecf20Sopenharmony_ci set_scr(ice, SCR_PHP | SCR_CODEC_PDN); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci /* MCR Initialize */ 10188c2ecf20Sopenharmony_ci set_mcr(ice, 0); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci /* CPLD Initialize */ 10218c2ecf20Sopenharmony_ci set_cpld(ice, 0); 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci ice->num_total_dacs = 2; 10258c2ecf20Sopenharmony_ci ice->num_total_adcs = 2; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci ice->akm = kcalloc(2, sizeof(struct snd_akm4xxx), GFP_KERNEL); 10288c2ecf20Sopenharmony_ci ak = ice->akm; 10298c2ecf20Sopenharmony_ci if (!ak) 10308c2ecf20Sopenharmony_ci return -ENOMEM; 10318c2ecf20Sopenharmony_ci /* only one codec with two chips */ 10328c2ecf20Sopenharmony_ci ice->akm_codecs = 1; 10338c2ecf20Sopenharmony_ci err = snd_ice1712_akm4xxx_init(ak, &akm_qtet_dac, NULL, ice); 10348c2ecf20Sopenharmony_ci if (err < 0) 10358c2ecf20Sopenharmony_ci return err; 10368c2ecf20Sopenharmony_ci err = snd_ak4113_create(ice->card, 10378c2ecf20Sopenharmony_ci qtet_ak4113_read, 10388c2ecf20Sopenharmony_ci qtet_ak4113_write, 10398c2ecf20Sopenharmony_ci ak4113_init_vals, 10408c2ecf20Sopenharmony_ci ice, &spec->ak4113); 10418c2ecf20Sopenharmony_ci if (err < 0) 10428c2ecf20Sopenharmony_ci return err; 10438c2ecf20Sopenharmony_ci /* callback for codecs rate setting */ 10448c2ecf20Sopenharmony_ci spec->ak4113->change_callback = qtet_ak4113_change; 10458c2ecf20Sopenharmony_ci spec->ak4113->change_callback_private = ice; 10468c2ecf20Sopenharmony_ci /* AK41143 in Quartet can detect external rate correctly 10478c2ecf20Sopenharmony_ci * (i.e. check_flags = 0) */ 10488c2ecf20Sopenharmony_ci spec->ak4113->check_flags = 0; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci proc_init(ice); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci qtet_set_rate(ice, 44100); 10538c2ecf20Sopenharmony_ci return 0; 10548c2ecf20Sopenharmony_ci} 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_cistatic const unsigned char qtet_eeprom[] = { 10578c2ecf20Sopenharmony_ci [ICE_EEP2_SYSCONF] = 0x28, /* clock 256(24MHz), mpu401, 1xADC, 10588c2ecf20Sopenharmony_ci 1xDACs, SPDIF in */ 10598c2ecf20Sopenharmony_ci [ICE_EEP2_ACLINK] = 0x80, /* I2S */ 10608c2ecf20Sopenharmony_ci [ICE_EEP2_I2S] = 0x78, /* 96k, 24bit, 192k */ 10618c2ecf20Sopenharmony_ci [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, in, out-ext */ 10628c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_DIR] = 0x00, /* 0-7 inputs, switched to output 10638c2ecf20Sopenharmony_ci only during output operations */ 10648c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_DIR1] = 0xff, /* 8-15 outputs */ 10658c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_DIR2] = 0x00, 10668c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_MASK] = 0xff, /* changed only for OUT operations */ 10678c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_MASK1] = 0x00, 10688c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_MASK2] = 0xff, 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_STATE] = 0x00, /* inputs */ 10718c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_STATE1] = 0x7d, /* all 1, but GPIO_CPLD_RW 10728c2ecf20Sopenharmony_ci and GPIO15 always zero */ 10738c2ecf20Sopenharmony_ci [ICE_EEP2_GPIO_STATE2] = 0x00, /* inputs */ 10748c2ecf20Sopenharmony_ci}; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci/* entry point */ 10778c2ecf20Sopenharmony_cistruct snd_ice1712_card_info snd_vt1724_qtet_cards[] = { 10788c2ecf20Sopenharmony_ci { 10798c2ecf20Sopenharmony_ci .subvendor = VT1724_SUBDEVICE_QTET, 10808c2ecf20Sopenharmony_ci .name = "Infrasonic Quartet", 10818c2ecf20Sopenharmony_ci .model = "quartet", 10828c2ecf20Sopenharmony_ci .chip_init = qtet_init, 10838c2ecf20Sopenharmony_ci .build_controls = qtet_add_controls, 10848c2ecf20Sopenharmony_ci .eeprom_size = sizeof(qtet_eeprom), 10858c2ecf20Sopenharmony_ci .eeprom_data = qtet_eeprom, 10868c2ecf20Sopenharmony_ci }, 10878c2ecf20Sopenharmony_ci { } /* terminator */ 10888c2ecf20Sopenharmony_ci}; 1089