18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ALSA SoC CPCAP codec driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2017 - 2018 Sebastian Reichel <sre@kernel.org> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Very loosely based on original driver from Motorola: 88c2ecf20Sopenharmony_ci * Copyright (C) 2007 - 2009 Motorola, Inc. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/regmap.h> 138c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 148c2ecf20Sopenharmony_ci#include <linux/mfd/motorola-cpcap.h> 158c2ecf20Sopenharmony_ci#include <sound/core.h> 168c2ecf20Sopenharmony_ci#include <sound/soc.h> 178c2ecf20Sopenharmony_ci#include <sound/tlv.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* Register 513 CPCAP_REG_CC --- CODEC */ 208c2ecf20Sopenharmony_ci#define CPCAP_BIT_CDC_CLK2 15 218c2ecf20Sopenharmony_ci#define CPCAP_BIT_CDC_CLK1 14 228c2ecf20Sopenharmony_ci#define CPCAP_BIT_CDC_CLK0 13 238c2ecf20Sopenharmony_ci#define CPCAP_BIT_CDC_SR3 12 248c2ecf20Sopenharmony_ci#define CPCAP_BIT_CDC_SR2 11 258c2ecf20Sopenharmony_ci#define CPCAP_BIT_CDC_SR1 10 268c2ecf20Sopenharmony_ci#define CPCAP_BIT_CDC_SR0 9 278c2ecf20Sopenharmony_ci#define CPCAP_BIT_CDC_CLOCK_TREE_RESET 8 288c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC2_CDC_EN 7 298c2ecf20Sopenharmony_ci#define CPCAP_BIT_CDC_EN_RX 6 308c2ecf20Sopenharmony_ci#define CPCAP_BIT_DF_RESET 5 318c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC1_CDC_EN 4 328c2ecf20Sopenharmony_ci#define CPCAP_BIT_AUDOHPF_1 3 338c2ecf20Sopenharmony_ci#define CPCAP_BIT_AUDOHPF_0 2 348c2ecf20Sopenharmony_ci#define CPCAP_BIT_AUDIHPF_1 1 358c2ecf20Sopenharmony_ci#define CPCAP_BIT_AUDIHPF_0 0 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* Register 514 CPCAP_REG_CDI --- CODEC Digital Audio Interface */ 388c2ecf20Sopenharmony_ci#define CPCAP_BIT_CDC_PLL_SEL 15 398c2ecf20Sopenharmony_ci#define CPCAP_BIT_CLK_IN_SEL 13 408c2ecf20Sopenharmony_ci#define CPCAP_BIT_DIG_AUD_IN 12 418c2ecf20Sopenharmony_ci#define CPCAP_BIT_CDC_CLK_EN 11 428c2ecf20Sopenharmony_ci#define CPCAP_BIT_CDC_DIG_AUD_FS1 10 438c2ecf20Sopenharmony_ci#define CPCAP_BIT_CDC_DIG_AUD_FS0 9 448c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC2_TIMESLOT2 8 458c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC2_TIMESLOT1 7 468c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC2_TIMESLOT0 6 478c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC1_RX_TIMESLOT2 5 488c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC1_RX_TIMESLOT1 4 498c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC1_RX_TIMESLOT0 3 508c2ecf20Sopenharmony_ci#define CPCAP_BIT_FS_INV 2 518c2ecf20Sopenharmony_ci#define CPCAP_BIT_CLK_INV 1 528c2ecf20Sopenharmony_ci#define CPCAP_BIT_SMB_CDC 0 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* Register 515 CPCAP_REG_SDAC --- Stereo DAC */ 558c2ecf20Sopenharmony_ci#define CPCAP_BIT_FSYNC_CLK_IN_COMMON 11 568c2ecf20Sopenharmony_ci#define CPCAP_BIT_SLAVE_PLL_CLK_INPUT 10 578c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_CLOCK_TREE_RESET 9 588c2ecf20Sopenharmony_ci#define CPCAP_BIT_DF_RESET_ST_DAC 8 598c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_SR3 7 608c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_SR2 6 618c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_SR1 5 628c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_SR0 4 638c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_DAC_CLK2 3 648c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_DAC_CLK1 2 658c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_DAC_CLK0 1 668c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_DAC_EN 0 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* Register 516 CPCAP_REG_SDACDI --- Stereo DAC Digital Audio Interface */ 698c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_L_TIMESLOT2 13 708c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_L_TIMESLOT1 12 718c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_L_TIMESLOT0 11 728c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_R_TIMESLOT2 10 738c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_R_TIMESLOT1 9 748c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_R_TIMESLOT0 8 758c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_DAC_CLK_IN_SEL 7 768c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_FS_INV 6 778c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_CLK_INV 5 788c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_DIG_AUD_FS1 4 798c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_DIG_AUD_FS0 3 808c2ecf20Sopenharmony_ci#define CPCAP_BIT_DIG_AUD_IN_ST_DAC 2 818c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_CLK_EN 1 828c2ecf20Sopenharmony_ci#define CPCAP_BIT_SMB_ST_DAC 0 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* Register 517 CPCAP_REG_TXI --- TX Interface */ 858c2ecf20Sopenharmony_ci#define CPCAP_BIT_PTT_TH 15 868c2ecf20Sopenharmony_ci#define CPCAP_BIT_PTT_CMP_EN 14 878c2ecf20Sopenharmony_ci#define CPCAP_BIT_HS_ID_TX 13 888c2ecf20Sopenharmony_ci#define CPCAP_BIT_MB_ON2 12 898c2ecf20Sopenharmony_ci#define CPCAP_BIT_MB_ON1L 11 908c2ecf20Sopenharmony_ci#define CPCAP_BIT_MB_ON1R 10 918c2ecf20Sopenharmony_ci#define CPCAP_BIT_RX_L_ENCODE 9 928c2ecf20Sopenharmony_ci#define CPCAP_BIT_RX_R_ENCODE 8 938c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC2_MUX 7 948c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC2_PGA_EN 6 958c2ecf20Sopenharmony_ci#define CPCAP_BIT_CDET_DIS 5 968c2ecf20Sopenharmony_ci#define CPCAP_BIT_EMU_MIC_MUX 4 978c2ecf20Sopenharmony_ci#define CPCAP_BIT_HS_MIC_MUX 3 988c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC1_MUX 2 998c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC1_PGA_EN 1 1008c2ecf20Sopenharmony_ci#define CPCAP_BIT_DLM 0 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/* Register 518 CPCAP_REG_TXMP --- Mic Gain */ 1038c2ecf20Sopenharmony_ci#define CPCAP_BIT_MB_BIAS_R1 11 1048c2ecf20Sopenharmony_ci#define CPCAP_BIT_MB_BIAS_R0 10 1058c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC2_GAIN_4 9 1068c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC2_GAIN_3 8 1078c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC2_GAIN_2 7 1088c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC2_GAIN_1 6 1098c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC2_GAIN_0 5 1108c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC1_GAIN_4 4 1118c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC1_GAIN_3 3 1128c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC1_GAIN_2 2 1138c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC1_GAIN_1 1 1148c2ecf20Sopenharmony_ci#define CPCAP_BIT_MIC1_GAIN_0 0 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci/* Register 519 CPCAP_REG_RXOA --- RX Output Amplifier */ 1178c2ecf20Sopenharmony_ci#define CPCAP_BIT_UNUSED_519_15 15 1188c2ecf20Sopenharmony_ci#define CPCAP_BIT_UNUSED_519_14 14 1198c2ecf20Sopenharmony_ci#define CPCAP_BIT_UNUSED_519_13 13 1208c2ecf20Sopenharmony_ci#define CPCAP_BIT_STDAC_LOW_PWR_DISABLE 12 1218c2ecf20Sopenharmony_ci#define CPCAP_BIT_HS_LOW_PWR 11 1228c2ecf20Sopenharmony_ci#define CPCAP_BIT_HS_ID_RX 10 1238c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_HS_CP_EN 9 1248c2ecf20Sopenharmony_ci#define CPCAP_BIT_EMU_SPKR_R_EN 8 1258c2ecf20Sopenharmony_ci#define CPCAP_BIT_EMU_SPKR_L_EN 7 1268c2ecf20Sopenharmony_ci#define CPCAP_BIT_HS_L_EN 6 1278c2ecf20Sopenharmony_ci#define CPCAP_BIT_HS_R_EN 5 1288c2ecf20Sopenharmony_ci#define CPCAP_BIT_A4_LINEOUT_L_EN 4 1298c2ecf20Sopenharmony_ci#define CPCAP_BIT_A4_LINEOUT_R_EN 3 1308c2ecf20Sopenharmony_ci#define CPCAP_BIT_A2_LDSP_L_EN 2 1318c2ecf20Sopenharmony_ci#define CPCAP_BIT_A2_LDSP_R_EN 1 1328c2ecf20Sopenharmony_ci#define CPCAP_BIT_A1_EAR_EN 0 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/* Register 520 CPCAP_REG_RXVC --- RX Volume Control */ 1358c2ecf20Sopenharmony_ci#define CPCAP_BIT_VOL_EXT3 15 1368c2ecf20Sopenharmony_ci#define CPCAP_BIT_VOL_EXT2 14 1378c2ecf20Sopenharmony_ci#define CPCAP_BIT_VOL_EXT1 13 1388c2ecf20Sopenharmony_ci#define CPCAP_BIT_VOL_EXT0 12 1398c2ecf20Sopenharmony_ci#define CPCAP_BIT_VOL_DAC3 11 1408c2ecf20Sopenharmony_ci#define CPCAP_BIT_VOL_DAC2 10 1418c2ecf20Sopenharmony_ci#define CPCAP_BIT_VOL_DAC1 9 1428c2ecf20Sopenharmony_ci#define CPCAP_BIT_VOL_DAC0 8 1438c2ecf20Sopenharmony_ci#define CPCAP_BIT_VOL_DAC_LSB_1dB1 7 1448c2ecf20Sopenharmony_ci#define CPCAP_BIT_VOL_DAC_LSB_1dB0 6 1458c2ecf20Sopenharmony_ci#define CPCAP_BIT_VOL_CDC3 5 1468c2ecf20Sopenharmony_ci#define CPCAP_BIT_VOL_CDC2 4 1478c2ecf20Sopenharmony_ci#define CPCAP_BIT_VOL_CDC1 3 1488c2ecf20Sopenharmony_ci#define CPCAP_BIT_VOL_CDC0 2 1498c2ecf20Sopenharmony_ci#define CPCAP_BIT_VOL_CDC_LSB_1dB1 1 1508c2ecf20Sopenharmony_ci#define CPCAP_BIT_VOL_CDC_LSB_1dB0 0 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/* Register 521 CPCAP_REG_RXCOA --- Codec to Output Amp Switches */ 1538c2ecf20Sopenharmony_ci#define CPCAP_BIT_PGA_CDC_EN 10 1548c2ecf20Sopenharmony_ci#define CPCAP_BIT_CDC_SW 9 1558c2ecf20Sopenharmony_ci#define CPCAP_BIT_PGA_OUTR_USBDP_CDC_SW 8 1568c2ecf20Sopenharmony_ci#define CPCAP_BIT_PGA_OUTL_USBDN_CDC_SW 7 1578c2ecf20Sopenharmony_ci#define CPCAP_BIT_ALEFT_HS_CDC_SW 6 1588c2ecf20Sopenharmony_ci#define CPCAP_BIT_ARIGHT_HS_CDC_SW 5 1598c2ecf20Sopenharmony_ci#define CPCAP_BIT_A4_LINEOUT_L_CDC_SW 4 1608c2ecf20Sopenharmony_ci#define CPCAP_BIT_A4_LINEOUT_R_CDC_SW 3 1618c2ecf20Sopenharmony_ci#define CPCAP_BIT_A2_LDSP_L_CDC_SW 2 1628c2ecf20Sopenharmony_ci#define CPCAP_BIT_A2_LDSP_R_CDC_SW 1 1638c2ecf20Sopenharmony_ci#define CPCAP_BIT_A1_EAR_CDC_SW 0 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* Register 522 CPCAP_REG_RXSDOA --- RX Stereo DAC to Output Amp Switches */ 1668c2ecf20Sopenharmony_ci#define CPCAP_BIT_PGA_DAC_EN 12 1678c2ecf20Sopenharmony_ci#define CPCAP_BIT_ST_DAC_SW 11 1688c2ecf20Sopenharmony_ci#define CPCAP_BIT_MONO_DAC1 10 1698c2ecf20Sopenharmony_ci#define CPCAP_BIT_MONO_DAC0 9 1708c2ecf20Sopenharmony_ci#define CPCAP_BIT_PGA_OUTR_USBDP_DAC_SW 8 1718c2ecf20Sopenharmony_ci#define CPCAP_BIT_PGA_OUTL_USBDN_DAC_SW 7 1728c2ecf20Sopenharmony_ci#define CPCAP_BIT_ALEFT_HS_DAC_SW 6 1738c2ecf20Sopenharmony_ci#define CPCAP_BIT_ARIGHT_HS_DAC_SW 5 1748c2ecf20Sopenharmony_ci#define CPCAP_BIT_A4_LINEOUT_L_DAC_SW 4 1758c2ecf20Sopenharmony_ci#define CPCAP_BIT_A4_LINEOUT_R_DAC_SW 3 1768c2ecf20Sopenharmony_ci#define CPCAP_BIT_A2_LDSP_L_DAC_SW 2 1778c2ecf20Sopenharmony_ci#define CPCAP_BIT_A2_LDSP_R_DAC_SW 1 1788c2ecf20Sopenharmony_ci#define CPCAP_BIT_A1_EAR_DAC_SW 0 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci/* Register 523 CPCAP_REG_RXEPOA --- RX External PGA to Output Amp Switches */ 1818c2ecf20Sopenharmony_ci#define CPCAP_BIT_PGA_EXT_L_EN 14 1828c2ecf20Sopenharmony_ci#define CPCAP_BIT_PGA_EXT_R_EN 13 1838c2ecf20Sopenharmony_ci#define CPCAP_BIT_PGA_IN_L_SW 12 1848c2ecf20Sopenharmony_ci#define CPCAP_BIT_PGA_IN_R_SW 11 1858c2ecf20Sopenharmony_ci#define CPCAP_BIT_MONO_EXT1 10 1868c2ecf20Sopenharmony_ci#define CPCAP_BIT_MONO_EXT0 9 1878c2ecf20Sopenharmony_ci#define CPCAP_BIT_PGA_OUTR_USBDP_EXT_SW 8 1888c2ecf20Sopenharmony_ci#define CPCAP_BIT_PGA_OUTL_USBDN_EXT_SW 7 1898c2ecf20Sopenharmony_ci#define CPCAP_BIT_ALEFT_HS_EXT_SW 6 1908c2ecf20Sopenharmony_ci#define CPCAP_BIT_ARIGHT_HS_EXT_SW 5 1918c2ecf20Sopenharmony_ci#define CPCAP_BIT_A4_LINEOUT_L_EXT_SW 4 1928c2ecf20Sopenharmony_ci#define CPCAP_BIT_A4_LINEOUT_R_EXT_SW 3 1938c2ecf20Sopenharmony_ci#define CPCAP_BIT_A2_LDSP_L_EXT_SW 2 1948c2ecf20Sopenharmony_ci#define CPCAP_BIT_A2_LDSP_R_EXT_SW 1 1958c2ecf20Sopenharmony_ci#define CPCAP_BIT_A1_EAR_EXT_SW 0 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci/* Register 525 CPCAP_REG_A2LA --- SPK Amplifier and Clock Config for Headset */ 1988c2ecf20Sopenharmony_ci#define CPCAP_BIT_NCP_CLK_SYNC 7 1998c2ecf20Sopenharmony_ci#define CPCAP_BIT_A2_CLK_SYNC 6 2008c2ecf20Sopenharmony_ci#define CPCAP_BIT_A2_FREE_RUN 5 2018c2ecf20Sopenharmony_ci#define CPCAP_BIT_A2_CLK2 4 2028c2ecf20Sopenharmony_ci#define CPCAP_BIT_A2_CLK1 3 2038c2ecf20Sopenharmony_ci#define CPCAP_BIT_A2_CLK0 2 2048c2ecf20Sopenharmony_ci#define CPCAP_BIT_A2_CLK_IN 1 2058c2ecf20Sopenharmony_ci#define CPCAP_BIT_A2_CONFIG 0 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci#define SLEEP_ACTIVATE_POWER 2 2088c2ecf20Sopenharmony_ci#define CLOCK_TREE_RESET_TIME 1 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci/* constants for ST delay workaround */ 2118c2ecf20Sopenharmony_ci#define STM_STDAC_ACTIVATE_RAMP_TIME 1 2128c2ecf20Sopenharmony_ci#define STM_STDAC_EN_TEST_PRE 0x090C 2138c2ecf20Sopenharmony_ci#define STM_STDAC_EN_TEST_POST 0x0000 2148c2ecf20Sopenharmony_ci#define STM_STDAC_EN_ST_TEST1_PRE 0x2400 2158c2ecf20Sopenharmony_ci#define STM_STDAC_EN_ST_TEST1_POST 0x0400 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistruct cpcap_reg_info { 2188c2ecf20Sopenharmony_ci u16 reg; 2198c2ecf20Sopenharmony_ci u16 mask; 2208c2ecf20Sopenharmony_ci u16 val; 2218c2ecf20Sopenharmony_ci}; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic const struct cpcap_reg_info cpcap_default_regs[] = { 2248c2ecf20Sopenharmony_ci { CPCAP_REG_CC, 0xFFFF, 0x0000 }, 2258c2ecf20Sopenharmony_ci { CPCAP_REG_CC, 0xFFFF, 0x0000 }, 2268c2ecf20Sopenharmony_ci { CPCAP_REG_CDI, 0xBFFF, 0x0000 }, 2278c2ecf20Sopenharmony_ci { CPCAP_REG_SDAC, 0x0FFF, 0x0000 }, 2288c2ecf20Sopenharmony_ci { CPCAP_REG_SDACDI, 0x3FFF, 0x0000 }, 2298c2ecf20Sopenharmony_ci { CPCAP_REG_TXI, 0x0FDF, 0x0000 }, 2308c2ecf20Sopenharmony_ci { CPCAP_REG_TXMP, 0x0FFF, 0x0400 }, 2318c2ecf20Sopenharmony_ci { CPCAP_REG_RXOA, 0x01FF, 0x0000 }, 2328c2ecf20Sopenharmony_ci { CPCAP_REG_RXVC, 0xFF3C, 0x0000 }, 2338c2ecf20Sopenharmony_ci { CPCAP_REG_RXCOA, 0x07FF, 0x0000 }, 2348c2ecf20Sopenharmony_ci { CPCAP_REG_RXSDOA, 0x1FFF, 0x0000 }, 2358c2ecf20Sopenharmony_ci { CPCAP_REG_RXEPOA, 0x7FFF, 0x0000 }, 2368c2ecf20Sopenharmony_ci { CPCAP_REG_A2LA, BIT(CPCAP_BIT_A2_FREE_RUN), 2378c2ecf20Sopenharmony_ci BIT(CPCAP_BIT_A2_FREE_RUN) }, 2388c2ecf20Sopenharmony_ci}; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cienum cpcap_dai { 2418c2ecf20Sopenharmony_ci CPCAP_DAI_HIFI, 2428c2ecf20Sopenharmony_ci CPCAP_DAI_VOICE, 2438c2ecf20Sopenharmony_ci}; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistruct cpcap_audio { 2468c2ecf20Sopenharmony_ci struct snd_soc_component *component; 2478c2ecf20Sopenharmony_ci struct regmap *regmap; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci u16 vendor; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci int codec_clk_id; 2528c2ecf20Sopenharmony_ci int codec_freq; 2538c2ecf20Sopenharmony_ci int codec_format; 2548c2ecf20Sopenharmony_ci}; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic int cpcap_st_workaround(struct snd_soc_dapm_widget *w, 2578c2ecf20Sopenharmony_ci struct snd_kcontrol *kcontrol, int event) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 2608c2ecf20Sopenharmony_ci struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); 2618c2ecf20Sopenharmony_ci int err = 0; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* Only CPCAP from ST requires workaround */ 2648c2ecf20Sopenharmony_ci if (cpcap->vendor != CPCAP_VENDOR_ST) 2658c2ecf20Sopenharmony_ci return 0; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci switch (event) { 2688c2ecf20Sopenharmony_ci case SND_SOC_DAPM_PRE_PMU: 2698c2ecf20Sopenharmony_ci err = regmap_write(cpcap->regmap, CPCAP_REG_TEST, 2708c2ecf20Sopenharmony_ci STM_STDAC_EN_TEST_PRE); 2718c2ecf20Sopenharmony_ci if (err) 2728c2ecf20Sopenharmony_ci return err; 2738c2ecf20Sopenharmony_ci err = regmap_write(cpcap->regmap, CPCAP_REG_ST_TEST1, 2748c2ecf20Sopenharmony_ci STM_STDAC_EN_ST_TEST1_PRE); 2758c2ecf20Sopenharmony_ci break; 2768c2ecf20Sopenharmony_ci case SND_SOC_DAPM_POST_PMU: 2778c2ecf20Sopenharmony_ci msleep(STM_STDAC_ACTIVATE_RAMP_TIME); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci err = regmap_write(cpcap->regmap, CPCAP_REG_ST_TEST1, 2808c2ecf20Sopenharmony_ci STM_STDAC_EN_ST_TEST1_POST); 2818c2ecf20Sopenharmony_ci if (err) 2828c2ecf20Sopenharmony_ci return err; 2838c2ecf20Sopenharmony_ci err = regmap_write(cpcap->regmap, CPCAP_REG_TEST, 2848c2ecf20Sopenharmony_ci STM_STDAC_EN_TEST_POST); 2858c2ecf20Sopenharmony_ci break; 2868c2ecf20Sopenharmony_ci default: 2878c2ecf20Sopenharmony_ci break; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci return err; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci/* Capture Gain Control: 0dB to 31dB in 1dB steps */ 2948c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(mic_gain_tlv, 0, 100, 0); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci/* Playback Gain Control: -33dB to 12dB in 3dB steps */ 2978c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(vol_tlv, -3300, 300, 0); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cpcap_snd_controls[] = { 3008c2ecf20Sopenharmony_ci /* Playback Gain */ 3018c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("HiFi Playback Volume", 3028c2ecf20Sopenharmony_ci CPCAP_REG_RXVC, CPCAP_BIT_VOL_DAC0, 0xF, 0, vol_tlv), 3038c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Voice Playback Volume", 3048c2ecf20Sopenharmony_ci CPCAP_REG_RXVC, CPCAP_BIT_VOL_CDC0, 0xF, 0, vol_tlv), 3058c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Ext Playback Volume", 3068c2ecf20Sopenharmony_ci CPCAP_REG_RXVC, CPCAP_BIT_VOL_EXT0, 0xF, 0, vol_tlv), 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* Capture Gain */ 3098c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Mic1 Capture Volume", 3108c2ecf20Sopenharmony_ci CPCAP_REG_TXMP, CPCAP_BIT_MIC1_GAIN_0, 0x1F, 0, mic_gain_tlv), 3118c2ecf20Sopenharmony_ci SOC_SINGLE_TLV("Mic2 Capture Volume", 3128c2ecf20Sopenharmony_ci CPCAP_REG_TXMP, CPCAP_BIT_MIC2_GAIN_0, 0x1F, 0, mic_gain_tlv), 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci /* Phase Invert */ 3158c2ecf20Sopenharmony_ci SOC_SINGLE("Hifi Left Phase Invert Switch", 3168c2ecf20Sopenharmony_ci CPCAP_REG_RXSDOA, CPCAP_BIT_MONO_DAC0, 1, 0), 3178c2ecf20Sopenharmony_ci SOC_SINGLE("Ext Left Phase Invert Switch", 3188c2ecf20Sopenharmony_ci CPCAP_REG_RXEPOA, CPCAP_BIT_MONO_EXT0, 1, 0), 3198c2ecf20Sopenharmony_ci}; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic const char * const cpcap_out_mux_texts[] = { 3228c2ecf20Sopenharmony_ci "Off", "Voice", "HiFi", "Ext" 3238c2ecf20Sopenharmony_ci}; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic const char * const cpcap_in_right_mux_texts[] = { 3268c2ecf20Sopenharmony_ci "Off", "Mic 1", "Headset Mic", "EMU Mic", "Ext Right" 3278c2ecf20Sopenharmony_ci}; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic const char * const cpcap_in_left_mux_texts[] = { 3308c2ecf20Sopenharmony_ci "Off", "Mic 2", "Ext Left" 3318c2ecf20Sopenharmony_ci}; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci/* 3348c2ecf20Sopenharmony_ci * input muxes use unusual register layout, so that we need to use custom 3358c2ecf20Sopenharmony_ci * getter/setter methods 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_EXT_DECL(cpcap_input_left_mux_enum, 3388c2ecf20Sopenharmony_ci cpcap_in_left_mux_texts); 3398c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_EXT_DECL(cpcap_input_right_mux_enum, 3408c2ecf20Sopenharmony_ci cpcap_in_right_mux_texts); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci/* 3438c2ecf20Sopenharmony_ci * mux uses same bit in CPCAP_REG_RXCOA, CPCAP_REG_RXSDOA & CPCAP_REG_RXEPOA; 3448c2ecf20Sopenharmony_ci * even though the register layout makes it look like a mixer, this is a mux. 3458c2ecf20Sopenharmony_ci * Enabling multiple inputs will result in no audio being forwarded. 3468c2ecf20Sopenharmony_ci */ 3478c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(cpcap_earpiece_mux_enum, 0, 0, cpcap_out_mux_texts); 3488c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(cpcap_spkr_r_mux_enum, 0, 1, cpcap_out_mux_texts); 3498c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(cpcap_spkr_l_mux_enum, 0, 2, cpcap_out_mux_texts); 3508c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(cpcap_line_r_mux_enum, 0, 3, cpcap_out_mux_texts); 3518c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(cpcap_line_l_mux_enum, 0, 4, cpcap_out_mux_texts); 3528c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(cpcap_hs_r_mux_enum, 0, 5, cpcap_out_mux_texts); 3538c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(cpcap_hs_l_mux_enum, 0, 6, cpcap_out_mux_texts); 3548c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(cpcap_emu_l_mux_enum, 0, 7, cpcap_out_mux_texts); 3558c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(cpcap_emu_r_mux_enum, 0, 8, cpcap_out_mux_texts); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic int cpcap_output_mux_get_enum(struct snd_kcontrol *kcontrol, 3588c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); 3618c2ecf20Sopenharmony_ci struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); 3628c2ecf20Sopenharmony_ci struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 3638c2ecf20Sopenharmony_ci unsigned int shift = e->shift_l; 3648c2ecf20Sopenharmony_ci int reg_voice, reg_hifi, reg_ext, status; 3658c2ecf20Sopenharmony_ci int err; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci err = regmap_read(cpcap->regmap, CPCAP_REG_RXCOA, ®_voice); 3688c2ecf20Sopenharmony_ci if (err) 3698c2ecf20Sopenharmony_ci return err; 3708c2ecf20Sopenharmony_ci err = regmap_read(cpcap->regmap, CPCAP_REG_RXSDOA, ®_hifi); 3718c2ecf20Sopenharmony_ci if (err) 3728c2ecf20Sopenharmony_ci return err; 3738c2ecf20Sopenharmony_ci err = regmap_read(cpcap->regmap, CPCAP_REG_RXEPOA, ®_ext); 3748c2ecf20Sopenharmony_ci if (err) 3758c2ecf20Sopenharmony_ci return err; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci reg_voice = (reg_voice >> shift) & 1; 3788c2ecf20Sopenharmony_ci reg_hifi = (reg_hifi >> shift) & 1; 3798c2ecf20Sopenharmony_ci reg_ext = (reg_ext >> shift) & 1; 3808c2ecf20Sopenharmony_ci status = reg_ext << 2 | reg_hifi << 1 | reg_voice; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci switch (status) { 3838c2ecf20Sopenharmony_ci case 0x04: 3848c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 3; 3858c2ecf20Sopenharmony_ci break; 3868c2ecf20Sopenharmony_ci case 0x02: 3878c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 2; 3888c2ecf20Sopenharmony_ci break; 3898c2ecf20Sopenharmony_ci case 0x01: 3908c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 1; 3918c2ecf20Sopenharmony_ci break; 3928c2ecf20Sopenharmony_ci default: 3938c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 0; 3948c2ecf20Sopenharmony_ci break; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci return 0; 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic int cpcap_output_mux_put_enum(struct snd_kcontrol *kcontrol, 4018c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); 4048c2ecf20Sopenharmony_ci struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); 4058c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = 4068c2ecf20Sopenharmony_ci snd_soc_dapm_kcontrol_dapm(kcontrol); 4078c2ecf20Sopenharmony_ci struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 4088c2ecf20Sopenharmony_ci unsigned int muxval = ucontrol->value.enumerated.item[0]; 4098c2ecf20Sopenharmony_ci unsigned int mask = BIT(e->shift_l); 4108c2ecf20Sopenharmony_ci u16 reg_voice = 0x00, reg_hifi = 0x00, reg_ext = 0x00; 4118c2ecf20Sopenharmony_ci int err; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci switch (muxval) { 4148c2ecf20Sopenharmony_ci case 1: 4158c2ecf20Sopenharmony_ci reg_voice = mask; 4168c2ecf20Sopenharmony_ci break; 4178c2ecf20Sopenharmony_ci case 2: 4188c2ecf20Sopenharmony_ci reg_hifi = mask; 4198c2ecf20Sopenharmony_ci break; 4208c2ecf20Sopenharmony_ci case 3: 4218c2ecf20Sopenharmony_ci reg_ext = mask; 4228c2ecf20Sopenharmony_ci break; 4238c2ecf20Sopenharmony_ci default: 4248c2ecf20Sopenharmony_ci break; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXCOA, 4288c2ecf20Sopenharmony_ci mask, reg_voice); 4298c2ecf20Sopenharmony_ci if (err) 4308c2ecf20Sopenharmony_ci return err; 4318c2ecf20Sopenharmony_ci err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXSDOA, 4328c2ecf20Sopenharmony_ci mask, reg_hifi); 4338c2ecf20Sopenharmony_ci if (err) 4348c2ecf20Sopenharmony_ci return err; 4358c2ecf20Sopenharmony_ci err = regmap_update_bits(cpcap->regmap, CPCAP_REG_RXEPOA, 4368c2ecf20Sopenharmony_ci mask, reg_ext); 4378c2ecf20Sopenharmony_ci if (err) 4388c2ecf20Sopenharmony_ci return err; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci snd_soc_dapm_mux_update_power(dapm, kcontrol, muxval, e, NULL); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci return 0; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic int cpcap_input_right_mux_get_enum(struct snd_kcontrol *kcontrol, 4468c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); 4498c2ecf20Sopenharmony_ci struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); 4508c2ecf20Sopenharmony_ci int regval, mask; 4518c2ecf20Sopenharmony_ci int err; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci err = regmap_read(cpcap->regmap, CPCAP_REG_TXI, ®val); 4548c2ecf20Sopenharmony_ci if (err) 4558c2ecf20Sopenharmony_ci return err; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci mask = 0; 4588c2ecf20Sopenharmony_ci mask |= BIT(CPCAP_BIT_MIC1_MUX); 4598c2ecf20Sopenharmony_ci mask |= BIT(CPCAP_BIT_HS_MIC_MUX); 4608c2ecf20Sopenharmony_ci mask |= BIT(CPCAP_BIT_EMU_MIC_MUX); 4618c2ecf20Sopenharmony_ci mask |= BIT(CPCAP_BIT_RX_R_ENCODE); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci switch (regval & mask) { 4648c2ecf20Sopenharmony_ci case BIT(CPCAP_BIT_RX_R_ENCODE): 4658c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 4; 4668c2ecf20Sopenharmony_ci break; 4678c2ecf20Sopenharmony_ci case BIT(CPCAP_BIT_EMU_MIC_MUX): 4688c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 3; 4698c2ecf20Sopenharmony_ci break; 4708c2ecf20Sopenharmony_ci case BIT(CPCAP_BIT_HS_MIC_MUX): 4718c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 2; 4728c2ecf20Sopenharmony_ci break; 4738c2ecf20Sopenharmony_ci case BIT(CPCAP_BIT_MIC1_MUX): 4748c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 1; 4758c2ecf20Sopenharmony_ci break; 4768c2ecf20Sopenharmony_ci default: 4778c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 0; 4788c2ecf20Sopenharmony_ci break; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci return 0; 4828c2ecf20Sopenharmony_ci} 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_cistatic int cpcap_input_right_mux_put_enum(struct snd_kcontrol *kcontrol, 4858c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); 4888c2ecf20Sopenharmony_ci struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); 4898c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = 4908c2ecf20Sopenharmony_ci snd_soc_dapm_kcontrol_dapm(kcontrol); 4918c2ecf20Sopenharmony_ci struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 4928c2ecf20Sopenharmony_ci unsigned int muxval = ucontrol->value.enumerated.item[0]; 4938c2ecf20Sopenharmony_ci int regval = 0, mask; 4948c2ecf20Sopenharmony_ci int err; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci mask = 0; 4978c2ecf20Sopenharmony_ci mask |= BIT(CPCAP_BIT_MIC1_MUX); 4988c2ecf20Sopenharmony_ci mask |= BIT(CPCAP_BIT_HS_MIC_MUX); 4998c2ecf20Sopenharmony_ci mask |= BIT(CPCAP_BIT_EMU_MIC_MUX); 5008c2ecf20Sopenharmony_ci mask |= BIT(CPCAP_BIT_RX_R_ENCODE); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci switch (muxval) { 5038c2ecf20Sopenharmony_ci case 1: 5048c2ecf20Sopenharmony_ci regval = BIT(CPCAP_BIT_MIC1_MUX); 5058c2ecf20Sopenharmony_ci break; 5068c2ecf20Sopenharmony_ci case 2: 5078c2ecf20Sopenharmony_ci regval = BIT(CPCAP_BIT_HS_MIC_MUX); 5088c2ecf20Sopenharmony_ci break; 5098c2ecf20Sopenharmony_ci case 3: 5108c2ecf20Sopenharmony_ci regval = BIT(CPCAP_BIT_EMU_MIC_MUX); 5118c2ecf20Sopenharmony_ci break; 5128c2ecf20Sopenharmony_ci case 4: 5138c2ecf20Sopenharmony_ci regval = BIT(CPCAP_BIT_RX_R_ENCODE); 5148c2ecf20Sopenharmony_ci break; 5158c2ecf20Sopenharmony_ci default: 5168c2ecf20Sopenharmony_ci break; 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI, 5208c2ecf20Sopenharmony_ci mask, regval); 5218c2ecf20Sopenharmony_ci if (err) 5228c2ecf20Sopenharmony_ci return err; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci snd_soc_dapm_mux_update_power(dapm, kcontrol, muxval, e, NULL); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci return 0; 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_cistatic int cpcap_input_left_mux_get_enum(struct snd_kcontrol *kcontrol, 5308c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); 5338c2ecf20Sopenharmony_ci struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); 5348c2ecf20Sopenharmony_ci int regval, mask; 5358c2ecf20Sopenharmony_ci int err; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci err = regmap_read(cpcap->regmap, CPCAP_REG_TXI, ®val); 5388c2ecf20Sopenharmony_ci if (err) 5398c2ecf20Sopenharmony_ci return err; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci mask = 0; 5428c2ecf20Sopenharmony_ci mask |= BIT(CPCAP_BIT_MIC2_MUX); 5438c2ecf20Sopenharmony_ci mask |= BIT(CPCAP_BIT_RX_L_ENCODE); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci switch (regval & mask) { 5468c2ecf20Sopenharmony_ci case BIT(CPCAP_BIT_RX_L_ENCODE): 5478c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 2; 5488c2ecf20Sopenharmony_ci break; 5498c2ecf20Sopenharmony_ci case BIT(CPCAP_BIT_MIC2_MUX): 5508c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 1; 5518c2ecf20Sopenharmony_ci break; 5528c2ecf20Sopenharmony_ci default: 5538c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = 0; 5548c2ecf20Sopenharmony_ci break; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci return 0; 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic int cpcap_input_left_mux_put_enum(struct snd_kcontrol *kcontrol, 5618c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol); 5648c2ecf20Sopenharmony_ci struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); 5658c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = 5668c2ecf20Sopenharmony_ci snd_soc_dapm_kcontrol_dapm(kcontrol); 5678c2ecf20Sopenharmony_ci struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 5688c2ecf20Sopenharmony_ci unsigned int muxval = ucontrol->value.enumerated.item[0]; 5698c2ecf20Sopenharmony_ci int regval = 0, mask; 5708c2ecf20Sopenharmony_ci int err; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci mask = 0; 5738c2ecf20Sopenharmony_ci mask |= BIT(CPCAP_BIT_MIC2_MUX); 5748c2ecf20Sopenharmony_ci mask |= BIT(CPCAP_BIT_RX_L_ENCODE); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci switch (muxval) { 5778c2ecf20Sopenharmony_ci case 1: 5788c2ecf20Sopenharmony_ci regval = BIT(CPCAP_BIT_MIC2_MUX); 5798c2ecf20Sopenharmony_ci break; 5808c2ecf20Sopenharmony_ci case 2: 5818c2ecf20Sopenharmony_ci regval = BIT(CPCAP_BIT_RX_L_ENCODE); 5828c2ecf20Sopenharmony_ci break; 5838c2ecf20Sopenharmony_ci default: 5848c2ecf20Sopenharmony_ci break; 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci err = regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI, 5888c2ecf20Sopenharmony_ci mask, regval); 5898c2ecf20Sopenharmony_ci if (err) 5908c2ecf20Sopenharmony_ci return err; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci snd_soc_dapm_mux_update_power(dapm, kcontrol, muxval, e, NULL); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci return 0; 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cpcap_input_left_mux = 5988c2ecf20Sopenharmony_ci SOC_DAPM_ENUM_EXT("Input Left", cpcap_input_left_mux_enum, 5998c2ecf20Sopenharmony_ci cpcap_input_left_mux_get_enum, 6008c2ecf20Sopenharmony_ci cpcap_input_left_mux_put_enum); 6018c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cpcap_input_right_mux = 6028c2ecf20Sopenharmony_ci SOC_DAPM_ENUM_EXT("Input Right", cpcap_input_right_mux_enum, 6038c2ecf20Sopenharmony_ci cpcap_input_right_mux_get_enum, 6048c2ecf20Sopenharmony_ci cpcap_input_right_mux_put_enum); 6058c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cpcap_emu_left_mux = 6068c2ecf20Sopenharmony_ci SOC_DAPM_ENUM_EXT("EMU Left", cpcap_emu_l_mux_enum, 6078c2ecf20Sopenharmony_ci cpcap_output_mux_get_enum, cpcap_output_mux_put_enum); 6088c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cpcap_emu_right_mux = 6098c2ecf20Sopenharmony_ci SOC_DAPM_ENUM_EXT("EMU Right", cpcap_emu_r_mux_enum, 6108c2ecf20Sopenharmony_ci cpcap_output_mux_get_enum, cpcap_output_mux_put_enum); 6118c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cpcap_hs_left_mux = 6128c2ecf20Sopenharmony_ci SOC_DAPM_ENUM_EXT("Headset Left", cpcap_hs_l_mux_enum, 6138c2ecf20Sopenharmony_ci cpcap_output_mux_get_enum, cpcap_output_mux_put_enum); 6148c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cpcap_hs_right_mux = 6158c2ecf20Sopenharmony_ci SOC_DAPM_ENUM_EXT("Headset Right", cpcap_hs_r_mux_enum, 6168c2ecf20Sopenharmony_ci cpcap_output_mux_get_enum, cpcap_output_mux_put_enum); 6178c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cpcap_line_left_mux = 6188c2ecf20Sopenharmony_ci SOC_DAPM_ENUM_EXT("Line Left", cpcap_line_l_mux_enum, 6198c2ecf20Sopenharmony_ci cpcap_output_mux_get_enum, cpcap_output_mux_put_enum); 6208c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cpcap_line_right_mux = 6218c2ecf20Sopenharmony_ci SOC_DAPM_ENUM_EXT("Line Right", cpcap_line_r_mux_enum, 6228c2ecf20Sopenharmony_ci cpcap_output_mux_get_enum, cpcap_output_mux_put_enum); 6238c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cpcap_speaker_left_mux = 6248c2ecf20Sopenharmony_ci SOC_DAPM_ENUM_EXT("Speaker Left", cpcap_spkr_l_mux_enum, 6258c2ecf20Sopenharmony_ci cpcap_output_mux_get_enum, cpcap_output_mux_put_enum); 6268c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cpcap_speaker_right_mux = 6278c2ecf20Sopenharmony_ci SOC_DAPM_ENUM_EXT("Speaker Right", cpcap_spkr_r_mux_enum, 6288c2ecf20Sopenharmony_ci cpcap_output_mux_get_enum, cpcap_output_mux_put_enum); 6298c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cpcap_earpiece_mux = 6308c2ecf20Sopenharmony_ci SOC_DAPM_ENUM_EXT("Earpiece", cpcap_earpiece_mux_enum, 6318c2ecf20Sopenharmony_ci cpcap_output_mux_get_enum, cpcap_output_mux_put_enum); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cpcap_hifi_mono_mixer_controls[] = { 6348c2ecf20Sopenharmony_ci SOC_DAPM_SINGLE("HiFi Mono Playback Switch", 6358c2ecf20Sopenharmony_ci CPCAP_REG_RXSDOA, CPCAP_BIT_MONO_DAC1, 1, 0), 6368c2ecf20Sopenharmony_ci}; 6378c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cpcap_ext_mono_mixer_controls[] = { 6388c2ecf20Sopenharmony_ci SOC_DAPM_SINGLE("Ext Mono Playback Switch", 6398c2ecf20Sopenharmony_ci CPCAP_REG_RXEPOA, CPCAP_BIT_MONO_EXT0, 1, 0), 6408c2ecf20Sopenharmony_ci}; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cpcap_extr_mute_control = 6438c2ecf20Sopenharmony_ci SOC_DAPM_SINGLE("Switch", 6448c2ecf20Sopenharmony_ci CPCAP_REG_RXEPOA, CPCAP_BIT_PGA_IN_R_SW, 1, 0); 6458c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cpcap_extl_mute_control = 6468c2ecf20Sopenharmony_ci SOC_DAPM_SINGLE("Switch", 6478c2ecf20Sopenharmony_ci CPCAP_REG_RXEPOA, CPCAP_BIT_PGA_IN_L_SW, 1, 0); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new cpcap_voice_loopback = 6508c2ecf20Sopenharmony_ci SOC_DAPM_SINGLE("Switch", 6518c2ecf20Sopenharmony_ci CPCAP_REG_TXI, CPCAP_BIT_DLM, 1, 0); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget cpcap_dapm_widgets[] = { 6548c2ecf20Sopenharmony_ci /* DAIs */ 6558c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_IN("HiFi RX", NULL, 0, SND_SOC_NOPM, 0, 0), 6568c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_IN("Voice RX", NULL, 0, SND_SOC_NOPM, 0, 0), 6578c2ecf20Sopenharmony_ci SND_SOC_DAPM_AIF_OUT("Voice TX", NULL, 0, SND_SOC_NOPM, 0, 0), 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* Power Supply */ 6608c2ecf20Sopenharmony_ci SND_SOC_DAPM_REGULATOR_SUPPLY("VAUDIO", SLEEP_ACTIVATE_POWER, 0), 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci /* Highpass Filters */ 6638c2ecf20Sopenharmony_ci SND_SOC_DAPM_REG(snd_soc_dapm_pga, "Highpass Filter RX", 6648c2ecf20Sopenharmony_ci CPCAP_REG_CC, CPCAP_BIT_AUDIHPF_0, 0x3, 0x3, 0x0), 6658c2ecf20Sopenharmony_ci SND_SOC_DAPM_REG(snd_soc_dapm_pga, "Highpass Filter TX", 6668c2ecf20Sopenharmony_ci CPCAP_REG_CC, CPCAP_BIT_AUDOHPF_0, 0x3, 0x3, 0x0), 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci /* Clocks */ 6698c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("HiFi DAI Clock", 6708c2ecf20Sopenharmony_ci CPCAP_REG_SDACDI, CPCAP_BIT_ST_CLK_EN, 0, NULL, 0), 6718c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("Voice DAI Clock", 6728c2ecf20Sopenharmony_ci CPCAP_REG_CDI, CPCAP_BIT_CDC_CLK_EN, 0, NULL, 0), 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* Microphone Bias */ 6758c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("MIC1R Bias", 6768c2ecf20Sopenharmony_ci CPCAP_REG_TXI, CPCAP_BIT_MB_ON1R, 0, NULL, 0), 6778c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("MIC1L Bias", 6788c2ecf20Sopenharmony_ci CPCAP_REG_TXI, CPCAP_BIT_MB_ON1L, 0, NULL, 0), 6798c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("MIC2 Bias", 6808c2ecf20Sopenharmony_ci CPCAP_REG_TXI, CPCAP_BIT_MB_ON2, 0, NULL, 0), 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci /* Inputs */ 6838c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("MICR"), 6848c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("HSMIC"), 6858c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("EMUMIC"), 6868c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("MICL"), 6878c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("EXTR"), 6888c2ecf20Sopenharmony_ci SND_SOC_DAPM_INPUT("EXTL"), 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci /* Capture Route */ 6918c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Right Capture Route", 6928c2ecf20Sopenharmony_ci SND_SOC_NOPM, 0, 0, &cpcap_input_right_mux), 6938c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Left Capture Route", 6948c2ecf20Sopenharmony_ci SND_SOC_NOPM, 0, 0, &cpcap_input_left_mux), 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci /* Capture PGAs */ 6978c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA("Microphone 1 PGA", 6988c2ecf20Sopenharmony_ci CPCAP_REG_TXI, CPCAP_BIT_MIC1_PGA_EN, 0, NULL, 0), 6998c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA("Microphone 2 PGA", 7008c2ecf20Sopenharmony_ci CPCAP_REG_TXI, CPCAP_BIT_MIC2_PGA_EN, 0, NULL, 0), 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci /* ADC */ 7038c2ecf20Sopenharmony_ci SND_SOC_DAPM_ADC("ADC Right", NULL, 7048c2ecf20Sopenharmony_ci CPCAP_REG_CC, CPCAP_BIT_MIC1_CDC_EN, 0), 7058c2ecf20Sopenharmony_ci SND_SOC_DAPM_ADC("ADC Left", NULL, 7068c2ecf20Sopenharmony_ci CPCAP_REG_CC, CPCAP_BIT_MIC2_CDC_EN, 0), 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci /* DAC */ 7098c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC_E("DAC HiFi", NULL, 7108c2ecf20Sopenharmony_ci CPCAP_REG_SDAC, CPCAP_BIT_ST_DAC_EN, 0, 7118c2ecf20Sopenharmony_ci cpcap_st_workaround, 7128c2ecf20Sopenharmony_ci SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), 7138c2ecf20Sopenharmony_ci SND_SOC_DAPM_DAC_E("DAC Voice", NULL, 7148c2ecf20Sopenharmony_ci CPCAP_REG_CC, CPCAP_BIT_CDC_EN_RX, 0, 7158c2ecf20Sopenharmony_ci cpcap_st_workaround, 7168c2ecf20Sopenharmony_ci SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci /* Playback PGA */ 7198c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA("HiFi PGA", 7208c2ecf20Sopenharmony_ci CPCAP_REG_RXSDOA, CPCAP_BIT_PGA_DAC_EN, 0, NULL, 0), 7218c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA("Voice PGA", 7228c2ecf20Sopenharmony_ci CPCAP_REG_RXCOA, CPCAP_BIT_PGA_CDC_EN, 0, NULL, 0), 7238c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA_E("Ext Right PGA", 7248c2ecf20Sopenharmony_ci CPCAP_REG_RXEPOA, CPCAP_BIT_PGA_EXT_R_EN, 0, 7258c2ecf20Sopenharmony_ci NULL, 0, 7268c2ecf20Sopenharmony_ci cpcap_st_workaround, 7278c2ecf20Sopenharmony_ci SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), 7288c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA_E("Ext Left PGA", 7298c2ecf20Sopenharmony_ci CPCAP_REG_RXEPOA, CPCAP_BIT_PGA_EXT_L_EN, 0, 7308c2ecf20Sopenharmony_ci NULL, 0, 7318c2ecf20Sopenharmony_ci cpcap_st_workaround, 7328c2ecf20Sopenharmony_ci SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci /* Playback Switch */ 7358c2ecf20Sopenharmony_ci SND_SOC_DAPM_SWITCH("Ext Right Enable", SND_SOC_NOPM, 0, 0, 7368c2ecf20Sopenharmony_ci &cpcap_extr_mute_control), 7378c2ecf20Sopenharmony_ci SND_SOC_DAPM_SWITCH("Ext Left Enable", SND_SOC_NOPM, 0, 0, 7388c2ecf20Sopenharmony_ci &cpcap_extl_mute_control), 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci /* Loopback Switch */ 7418c2ecf20Sopenharmony_ci SND_SOC_DAPM_SWITCH("Voice Loopback", SND_SOC_NOPM, 0, 0, 7428c2ecf20Sopenharmony_ci &cpcap_voice_loopback), 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci /* Mono Mixer */ 7458c2ecf20Sopenharmony_ci SOC_MIXER_ARRAY("HiFi Mono Left Mixer", SND_SOC_NOPM, 0, 0, 7468c2ecf20Sopenharmony_ci cpcap_hifi_mono_mixer_controls), 7478c2ecf20Sopenharmony_ci SOC_MIXER_ARRAY("HiFi Mono Right Mixer", SND_SOC_NOPM, 0, 0, 7488c2ecf20Sopenharmony_ci cpcap_hifi_mono_mixer_controls), 7498c2ecf20Sopenharmony_ci SOC_MIXER_ARRAY("Ext Mono Left Mixer", SND_SOC_NOPM, 0, 0, 7508c2ecf20Sopenharmony_ci cpcap_ext_mono_mixer_controls), 7518c2ecf20Sopenharmony_ci SOC_MIXER_ARRAY("Ext Mono Right Mixer", SND_SOC_NOPM, 0, 0, 7528c2ecf20Sopenharmony_ci cpcap_ext_mono_mixer_controls), 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci /* Output Routes */ 7558c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Earpiece Playback Route", SND_SOC_NOPM, 0, 0, 7568c2ecf20Sopenharmony_ci &cpcap_earpiece_mux), 7578c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Speaker Right Playback Route", SND_SOC_NOPM, 0, 0, 7588c2ecf20Sopenharmony_ci &cpcap_speaker_right_mux), 7598c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Speaker Left Playback Route", SND_SOC_NOPM, 0, 0, 7608c2ecf20Sopenharmony_ci &cpcap_speaker_left_mux), 7618c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Lineout Right Playback Route", SND_SOC_NOPM, 0, 0, 7628c2ecf20Sopenharmony_ci &cpcap_line_right_mux), 7638c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Lineout Left Playback Route", SND_SOC_NOPM, 0, 0, 7648c2ecf20Sopenharmony_ci &cpcap_line_left_mux), 7658c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Headset Right Playback Route", SND_SOC_NOPM, 0, 0, 7668c2ecf20Sopenharmony_ci &cpcap_hs_right_mux), 7678c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Headset Left Playback Route", SND_SOC_NOPM, 0, 0, 7688c2ecf20Sopenharmony_ci &cpcap_hs_left_mux), 7698c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("EMU Right Playback Route", SND_SOC_NOPM, 0, 0, 7708c2ecf20Sopenharmony_ci &cpcap_emu_right_mux), 7718c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("EMU Left Playback Route", SND_SOC_NOPM, 0, 0, 7728c2ecf20Sopenharmony_ci &cpcap_emu_left_mux), 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci /* Output Amplifier */ 7758c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA("Earpiece PGA", 7768c2ecf20Sopenharmony_ci CPCAP_REG_RXOA, CPCAP_BIT_A1_EAR_EN, 0, NULL, 0), 7778c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA("Speaker Right PGA", 7788c2ecf20Sopenharmony_ci CPCAP_REG_RXOA, CPCAP_BIT_A2_LDSP_R_EN, 0, NULL, 0), 7798c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA("Speaker Left PGA", 7808c2ecf20Sopenharmony_ci CPCAP_REG_RXOA, CPCAP_BIT_A2_LDSP_L_EN, 0, NULL, 0), 7818c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA("Lineout Right PGA", 7828c2ecf20Sopenharmony_ci CPCAP_REG_RXOA, CPCAP_BIT_A4_LINEOUT_R_EN, 0, NULL, 0), 7838c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA("Lineout Left PGA", 7848c2ecf20Sopenharmony_ci CPCAP_REG_RXOA, CPCAP_BIT_A4_LINEOUT_L_EN, 0, NULL, 0), 7858c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA("Headset Right PGA", 7868c2ecf20Sopenharmony_ci CPCAP_REG_RXOA, CPCAP_BIT_HS_R_EN, 0, NULL, 0), 7878c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA("Headset Left PGA", 7888c2ecf20Sopenharmony_ci CPCAP_REG_RXOA, CPCAP_BIT_HS_L_EN, 0, NULL, 0), 7898c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA("EMU Right PGA", 7908c2ecf20Sopenharmony_ci CPCAP_REG_RXOA, CPCAP_BIT_EMU_SPKR_R_EN, 0, NULL, 0), 7918c2ecf20Sopenharmony_ci SND_SOC_DAPM_PGA("EMU Left PGA", 7928c2ecf20Sopenharmony_ci CPCAP_REG_RXOA, CPCAP_BIT_EMU_SPKR_L_EN, 0, NULL, 0), 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci /* Headet Charge Pump */ 7958c2ecf20Sopenharmony_ci SND_SOC_DAPM_SUPPLY("Headset Charge Pump", 7968c2ecf20Sopenharmony_ci CPCAP_REG_RXOA, CPCAP_BIT_ST_HS_CP_EN, 0, NULL, 0), 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci /* Outputs */ 7998c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("EP"), 8008c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("SPKR"), 8018c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("SPKL"), 8028c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("LINER"), 8038c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("LINEL"), 8048c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("HSR"), 8058c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("HSL"), 8068c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("EMUR"), 8078c2ecf20Sopenharmony_ci SND_SOC_DAPM_OUTPUT("EMUL"), 8088c2ecf20Sopenharmony_ci}; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route intercon[] = { 8118c2ecf20Sopenharmony_ci /* Power Supply */ 8128c2ecf20Sopenharmony_ci {"HiFi PGA", NULL, "VAUDIO"}, 8138c2ecf20Sopenharmony_ci {"Voice PGA", NULL, "VAUDIO"}, 8148c2ecf20Sopenharmony_ci {"Ext Right PGA", NULL, "VAUDIO"}, 8158c2ecf20Sopenharmony_ci {"Ext Left PGA", NULL, "VAUDIO"}, 8168c2ecf20Sopenharmony_ci {"Microphone 1 PGA", NULL, "VAUDIO"}, 8178c2ecf20Sopenharmony_ci {"Microphone 2 PGA", NULL, "VAUDIO"}, 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci /* Stream -> AIF */ 8208c2ecf20Sopenharmony_ci {"HiFi RX", NULL, "HiFi Playback"}, 8218c2ecf20Sopenharmony_ci {"Voice RX", NULL, "Voice Playback"}, 8228c2ecf20Sopenharmony_ci {"Voice Capture", NULL, "Voice TX"}, 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci /* AIF clocks */ 8258c2ecf20Sopenharmony_ci {"HiFi RX", NULL, "HiFi DAI Clock"}, 8268c2ecf20Sopenharmony_ci {"Voice RX", NULL, "Voice DAI Clock"}, 8278c2ecf20Sopenharmony_ci {"Voice TX", NULL, "Voice DAI Clock"}, 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci /* Digital Loopback */ 8308c2ecf20Sopenharmony_ci {"Voice Loopback", "Switch", "Voice TX"}, 8318c2ecf20Sopenharmony_ci {"Voice RX", NULL, "Voice Loopback"}, 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci /* Highpass Filters */ 8348c2ecf20Sopenharmony_ci {"Highpass Filter RX", NULL, "Voice RX"}, 8358c2ecf20Sopenharmony_ci {"Voice TX", NULL, "Highpass Filter TX"}, 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci /* AIF -> DAC mapping */ 8388c2ecf20Sopenharmony_ci {"DAC HiFi", NULL, "HiFi RX"}, 8398c2ecf20Sopenharmony_ci {"DAC Voice", NULL, "Highpass Filter RX"}, 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci /* DAC -> PGA */ 8428c2ecf20Sopenharmony_ci {"HiFi PGA", NULL, "DAC HiFi"}, 8438c2ecf20Sopenharmony_ci {"Voice PGA", NULL, "DAC Voice"}, 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci /* Ext Input -> PGA */ 8468c2ecf20Sopenharmony_ci {"Ext Right PGA", NULL, "EXTR"}, 8478c2ecf20Sopenharmony_ci {"Ext Left PGA", NULL, "EXTL"}, 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci /* Ext PGA -> Ext Playback Switch */ 8508c2ecf20Sopenharmony_ci {"Ext Right Enable", "Switch", "Ext Right PGA"}, 8518c2ecf20Sopenharmony_ci {"Ext Left Enable", "Switch", "Ext Left PGA"}, 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci /* HiFi PGA -> Mono Mixer */ 8548c2ecf20Sopenharmony_ci {"HiFi Mono Left Mixer", NULL, "HiFi PGA"}, 8558c2ecf20Sopenharmony_ci {"HiFi Mono Left Mixer", "HiFi Mono Playback Switch", "HiFi PGA"}, 8568c2ecf20Sopenharmony_ci {"HiFi Mono Right Mixer", NULL, "HiFi PGA"}, 8578c2ecf20Sopenharmony_ci {"HiFi Mono Right Mixer", "HiFi Mono Playback Switch", "HiFi PGA"}, 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci /* Ext Playback Switch -> Ext Mono Mixer */ 8608c2ecf20Sopenharmony_ci {"Ext Mono Right Mixer", NULL, "Ext Right Enable"}, 8618c2ecf20Sopenharmony_ci {"Ext Mono Right Mixer", "Ext Mono Playback Switch", "Ext Left Enable"}, 8628c2ecf20Sopenharmony_ci {"Ext Mono Left Mixer", NULL, "Ext Left Enable"}, 8638c2ecf20Sopenharmony_ci {"Ext Mono Left Mixer", "Ext Mono Playback Switch", "Ext Right Enable"}, 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci /* HiFi Mono Mixer -> Output Route */ 8668c2ecf20Sopenharmony_ci {"Earpiece Playback Route", "HiFi", "HiFi Mono Right Mixer"}, 8678c2ecf20Sopenharmony_ci {"Speaker Right Playback Route", "HiFi", "HiFi Mono Right Mixer"}, 8688c2ecf20Sopenharmony_ci {"Speaker Left Playback Route", "HiFi", "HiFi Mono Left Mixer"}, 8698c2ecf20Sopenharmony_ci {"Lineout Right Playback Route", "HiFi", "HiFi Mono Right Mixer"}, 8708c2ecf20Sopenharmony_ci {"Lineout Left Playback Route", "HiFi", "HiFi Mono Left Mixer"}, 8718c2ecf20Sopenharmony_ci {"Headset Right Playback Route", "HiFi", "HiFi Mono Right Mixer"}, 8728c2ecf20Sopenharmony_ci {"Headset Left Playback Route", "HiFi", "HiFi Mono Left Mixer"}, 8738c2ecf20Sopenharmony_ci {"EMU Right Playback Route", "HiFi", "HiFi Mono Right Mixer"}, 8748c2ecf20Sopenharmony_ci {"EMU Left Playback Route", "HiFi", "HiFi Mono Left Mixer"}, 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci /* Voice PGA -> Output Route */ 8778c2ecf20Sopenharmony_ci {"Earpiece Playback Route", "Voice", "Voice PGA"}, 8788c2ecf20Sopenharmony_ci {"Speaker Right Playback Route", "Voice", "Voice PGA"}, 8798c2ecf20Sopenharmony_ci {"Speaker Left Playback Route", "Voice", "Voice PGA"}, 8808c2ecf20Sopenharmony_ci {"Lineout Right Playback Route", "Voice", "Voice PGA"}, 8818c2ecf20Sopenharmony_ci {"Lineout Left Playback Route", "Voice", "Voice PGA"}, 8828c2ecf20Sopenharmony_ci {"Headset Right Playback Route", "Voice", "Voice PGA"}, 8838c2ecf20Sopenharmony_ci {"Headset Left Playback Route", "Voice", "Voice PGA"}, 8848c2ecf20Sopenharmony_ci {"EMU Right Playback Route", "Voice", "Voice PGA"}, 8858c2ecf20Sopenharmony_ci {"EMU Left Playback Route", "Voice", "Voice PGA"}, 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci /* Ext Mono Mixer -> Output Route */ 8888c2ecf20Sopenharmony_ci {"Earpiece Playback Route", "Ext", "Ext Mono Right Mixer"}, 8898c2ecf20Sopenharmony_ci {"Speaker Right Playback Route", "Ext", "Ext Mono Right Mixer"}, 8908c2ecf20Sopenharmony_ci {"Speaker Left Playback Route", "Ext", "Ext Mono Left Mixer"}, 8918c2ecf20Sopenharmony_ci {"Lineout Right Playback Route", "Ext", "Ext Mono Right Mixer"}, 8928c2ecf20Sopenharmony_ci {"Lineout Left Playback Route", "Ext", "Ext Mono Left Mixer"}, 8938c2ecf20Sopenharmony_ci {"Headset Right Playback Route", "Ext", "Ext Mono Right Mixer"}, 8948c2ecf20Sopenharmony_ci {"Headset Left Playback Route", "Ext", "Ext Mono Left Mixer"}, 8958c2ecf20Sopenharmony_ci {"EMU Right Playback Route", "Ext", "Ext Mono Right Mixer"}, 8968c2ecf20Sopenharmony_ci {"EMU Left Playback Route", "Ext", "Ext Mono Left Mixer"}, 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci /* Output Route -> Output Amplifier */ 8998c2ecf20Sopenharmony_ci {"Earpiece PGA", NULL, "Earpiece Playback Route"}, 9008c2ecf20Sopenharmony_ci {"Speaker Right PGA", NULL, "Speaker Right Playback Route"}, 9018c2ecf20Sopenharmony_ci {"Speaker Left PGA", NULL, "Speaker Left Playback Route"}, 9028c2ecf20Sopenharmony_ci {"Lineout Right PGA", NULL, "Lineout Right Playback Route"}, 9038c2ecf20Sopenharmony_ci {"Lineout Left PGA", NULL, "Lineout Left Playback Route"}, 9048c2ecf20Sopenharmony_ci {"Headset Right PGA", NULL, "Headset Right Playback Route"}, 9058c2ecf20Sopenharmony_ci {"Headset Left PGA", NULL, "Headset Left Playback Route"}, 9068c2ecf20Sopenharmony_ci {"EMU Right PGA", NULL, "EMU Right Playback Route"}, 9078c2ecf20Sopenharmony_ci {"EMU Left PGA", NULL, "EMU Left Playback Route"}, 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci /* Output Amplifier -> Output */ 9108c2ecf20Sopenharmony_ci {"EP", NULL, "Earpiece PGA"}, 9118c2ecf20Sopenharmony_ci {"SPKR", NULL, "Speaker Right PGA"}, 9128c2ecf20Sopenharmony_ci {"SPKL", NULL, "Speaker Left PGA"}, 9138c2ecf20Sopenharmony_ci {"LINER", NULL, "Lineout Right PGA"}, 9148c2ecf20Sopenharmony_ci {"LINEL", NULL, "Lineout Left PGA"}, 9158c2ecf20Sopenharmony_ci {"HSR", NULL, "Headset Right PGA"}, 9168c2ecf20Sopenharmony_ci {"HSL", NULL, "Headset Left PGA"}, 9178c2ecf20Sopenharmony_ci {"EMUR", NULL, "EMU Right PGA"}, 9188c2ecf20Sopenharmony_ci {"EMUL", NULL, "EMU Left PGA"}, 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci /* Headset Charge Pump -> Headset */ 9218c2ecf20Sopenharmony_ci {"HSR", NULL, "Headset Charge Pump"}, 9228c2ecf20Sopenharmony_ci {"HSL", NULL, "Headset Charge Pump"}, 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci /* Mic -> Mic Route */ 9258c2ecf20Sopenharmony_ci {"Right Capture Route", "Mic 1", "MICR"}, 9268c2ecf20Sopenharmony_ci {"Right Capture Route", "Headset Mic", "HSMIC"}, 9278c2ecf20Sopenharmony_ci {"Right Capture Route", "EMU Mic", "EMUMIC"}, 9288c2ecf20Sopenharmony_ci {"Right Capture Route", "Ext Right", "EXTR"}, 9298c2ecf20Sopenharmony_ci {"Left Capture Route", "Mic 2", "MICL"}, 9308c2ecf20Sopenharmony_ci {"Left Capture Route", "Ext Left", "EXTL"}, 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci /* Input Route -> Microphone PGA */ 9338c2ecf20Sopenharmony_ci {"Microphone 1 PGA", NULL, "Right Capture Route"}, 9348c2ecf20Sopenharmony_ci {"Microphone 2 PGA", NULL, "Left Capture Route"}, 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci /* Microphone PGA -> ADC */ 9378c2ecf20Sopenharmony_ci {"ADC Right", NULL, "Microphone 1 PGA"}, 9388c2ecf20Sopenharmony_ci {"ADC Left", NULL, "Microphone 2 PGA"}, 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci /* ADC -> Stream */ 9418c2ecf20Sopenharmony_ci {"Highpass Filter TX", NULL, "ADC Right"}, 9428c2ecf20Sopenharmony_ci {"Highpass Filter TX", NULL, "ADC Left"}, 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci /* Mic Bias */ 9458c2ecf20Sopenharmony_ci {"MICL", NULL, "MIC1L Bias"}, 9468c2ecf20Sopenharmony_ci {"MICR", NULL, "MIC1R Bias"}, 9478c2ecf20Sopenharmony_ci}; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_cistatic int cpcap_set_sysclk(struct cpcap_audio *cpcap, enum cpcap_dai dai, 9508c2ecf20Sopenharmony_ci int clk_id, int freq) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci u16 clkfreqreg, clkfreqshift; 9538c2ecf20Sopenharmony_ci u16 clkfreqmask, clkfreqval; 9548c2ecf20Sopenharmony_ci u16 clkidreg, clkidshift; 9558c2ecf20Sopenharmony_ci u16 mask, val; 9568c2ecf20Sopenharmony_ci int err; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci switch (dai) { 9598c2ecf20Sopenharmony_ci case CPCAP_DAI_HIFI: 9608c2ecf20Sopenharmony_ci clkfreqreg = CPCAP_REG_SDAC; 9618c2ecf20Sopenharmony_ci clkfreqshift = CPCAP_BIT_ST_DAC_CLK0; 9628c2ecf20Sopenharmony_ci clkidreg = CPCAP_REG_SDACDI; 9638c2ecf20Sopenharmony_ci clkidshift = CPCAP_BIT_ST_DAC_CLK_IN_SEL; 9648c2ecf20Sopenharmony_ci break; 9658c2ecf20Sopenharmony_ci case CPCAP_DAI_VOICE: 9668c2ecf20Sopenharmony_ci clkfreqreg = CPCAP_REG_CC; 9678c2ecf20Sopenharmony_ci clkfreqshift = CPCAP_BIT_CDC_CLK0; 9688c2ecf20Sopenharmony_ci clkidreg = CPCAP_REG_CDI; 9698c2ecf20Sopenharmony_ci clkidshift = CPCAP_BIT_CLK_IN_SEL; 9708c2ecf20Sopenharmony_ci break; 9718c2ecf20Sopenharmony_ci default: 9728c2ecf20Sopenharmony_ci dev_err(cpcap->component->dev, "invalid DAI: %d", dai); 9738c2ecf20Sopenharmony_ci return -EINVAL; 9748c2ecf20Sopenharmony_ci } 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci /* setup clk id */ 9778c2ecf20Sopenharmony_ci if (clk_id < 0 || clk_id > 1) { 9788c2ecf20Sopenharmony_ci dev_err(cpcap->component->dev, "invalid clk id %d", clk_id); 9798c2ecf20Sopenharmony_ci return -EINVAL; 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci err = regmap_update_bits(cpcap->regmap, clkidreg, BIT(clkidshift), 9828c2ecf20Sopenharmony_ci clk_id ? BIT(clkidshift) : 0); 9838c2ecf20Sopenharmony_ci if (err) 9848c2ecf20Sopenharmony_ci return err; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci /* enable PLL for Voice DAI */ 9878c2ecf20Sopenharmony_ci if (dai == CPCAP_DAI_VOICE) { 9888c2ecf20Sopenharmony_ci mask = BIT(CPCAP_BIT_CDC_PLL_SEL); 9898c2ecf20Sopenharmony_ci val = BIT(CPCAP_BIT_CDC_PLL_SEL); 9908c2ecf20Sopenharmony_ci err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI, 9918c2ecf20Sopenharmony_ci mask, val); 9928c2ecf20Sopenharmony_ci if (err) 9938c2ecf20Sopenharmony_ci return err; 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci /* setup frequency */ 9978c2ecf20Sopenharmony_ci clkfreqmask = 0x7 << clkfreqshift; 9988c2ecf20Sopenharmony_ci switch (freq) { 9998c2ecf20Sopenharmony_ci case 15360000: 10008c2ecf20Sopenharmony_ci clkfreqval = 0x01 << clkfreqshift; 10018c2ecf20Sopenharmony_ci break; 10028c2ecf20Sopenharmony_ci case 16800000: 10038c2ecf20Sopenharmony_ci clkfreqval = 0x02 << clkfreqshift; 10048c2ecf20Sopenharmony_ci break; 10058c2ecf20Sopenharmony_ci case 19200000: 10068c2ecf20Sopenharmony_ci clkfreqval = 0x03 << clkfreqshift; 10078c2ecf20Sopenharmony_ci break; 10088c2ecf20Sopenharmony_ci case 26000000: 10098c2ecf20Sopenharmony_ci clkfreqval = 0x04 << clkfreqshift; 10108c2ecf20Sopenharmony_ci break; 10118c2ecf20Sopenharmony_ci case 33600000: 10128c2ecf20Sopenharmony_ci clkfreqval = 0x05 << clkfreqshift; 10138c2ecf20Sopenharmony_ci break; 10148c2ecf20Sopenharmony_ci case 38400000: 10158c2ecf20Sopenharmony_ci clkfreqval = 0x06 << clkfreqshift; 10168c2ecf20Sopenharmony_ci break; 10178c2ecf20Sopenharmony_ci default: 10188c2ecf20Sopenharmony_ci dev_err(cpcap->component->dev, "unsupported freq %u", freq); 10198c2ecf20Sopenharmony_ci return -EINVAL; 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci err = regmap_update_bits(cpcap->regmap, clkfreqreg, 10238c2ecf20Sopenharmony_ci clkfreqmask, clkfreqval); 10248c2ecf20Sopenharmony_ci if (err) 10258c2ecf20Sopenharmony_ci return err; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci if (dai == CPCAP_DAI_VOICE) { 10288c2ecf20Sopenharmony_ci cpcap->codec_clk_id = clk_id; 10298c2ecf20Sopenharmony_ci cpcap->codec_freq = freq; 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci return 0; 10338c2ecf20Sopenharmony_ci} 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_cistatic int cpcap_set_samprate(struct cpcap_audio *cpcap, enum cpcap_dai dai, 10368c2ecf20Sopenharmony_ci int samplerate) 10378c2ecf20Sopenharmony_ci{ 10388c2ecf20Sopenharmony_ci struct snd_soc_component *component = cpcap->component; 10398c2ecf20Sopenharmony_ci u16 sampreg, sampmask, sampshift, sampval, sampreset; 10408c2ecf20Sopenharmony_ci int err, sampreadval; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci switch (dai) { 10438c2ecf20Sopenharmony_ci case CPCAP_DAI_HIFI: 10448c2ecf20Sopenharmony_ci sampreg = CPCAP_REG_SDAC; 10458c2ecf20Sopenharmony_ci sampshift = CPCAP_BIT_ST_SR0; 10468c2ecf20Sopenharmony_ci sampreset = BIT(CPCAP_BIT_DF_RESET_ST_DAC) | 10478c2ecf20Sopenharmony_ci BIT(CPCAP_BIT_ST_CLOCK_TREE_RESET); 10488c2ecf20Sopenharmony_ci break; 10498c2ecf20Sopenharmony_ci case CPCAP_DAI_VOICE: 10508c2ecf20Sopenharmony_ci sampreg = CPCAP_REG_CC; 10518c2ecf20Sopenharmony_ci sampshift = CPCAP_BIT_CDC_SR0; 10528c2ecf20Sopenharmony_ci sampreset = BIT(CPCAP_BIT_DF_RESET) | 10538c2ecf20Sopenharmony_ci BIT(CPCAP_BIT_CDC_CLOCK_TREE_RESET); 10548c2ecf20Sopenharmony_ci break; 10558c2ecf20Sopenharmony_ci default: 10568c2ecf20Sopenharmony_ci dev_err(component->dev, "invalid DAI: %d", dai); 10578c2ecf20Sopenharmony_ci return -EINVAL; 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci sampmask = 0xF << sampshift | sampreset; 10618c2ecf20Sopenharmony_ci switch (samplerate) { 10628c2ecf20Sopenharmony_ci case 48000: 10638c2ecf20Sopenharmony_ci sampval = 0x8 << sampshift; 10648c2ecf20Sopenharmony_ci break; 10658c2ecf20Sopenharmony_ci case 44100: 10668c2ecf20Sopenharmony_ci sampval = 0x7 << sampshift; 10678c2ecf20Sopenharmony_ci break; 10688c2ecf20Sopenharmony_ci case 32000: 10698c2ecf20Sopenharmony_ci sampval = 0x6 << sampshift; 10708c2ecf20Sopenharmony_ci break; 10718c2ecf20Sopenharmony_ci case 24000: 10728c2ecf20Sopenharmony_ci sampval = 0x5 << sampshift; 10738c2ecf20Sopenharmony_ci break; 10748c2ecf20Sopenharmony_ci case 22050: 10758c2ecf20Sopenharmony_ci sampval = 0x4 << sampshift; 10768c2ecf20Sopenharmony_ci break; 10778c2ecf20Sopenharmony_ci case 16000: 10788c2ecf20Sopenharmony_ci sampval = 0x3 << sampshift; 10798c2ecf20Sopenharmony_ci break; 10808c2ecf20Sopenharmony_ci case 12000: 10818c2ecf20Sopenharmony_ci sampval = 0x2 << sampshift; 10828c2ecf20Sopenharmony_ci break; 10838c2ecf20Sopenharmony_ci case 11025: 10848c2ecf20Sopenharmony_ci sampval = 0x1 << sampshift; 10858c2ecf20Sopenharmony_ci break; 10868c2ecf20Sopenharmony_ci case 8000: 10878c2ecf20Sopenharmony_ci sampval = 0x0 << sampshift; 10888c2ecf20Sopenharmony_ci break; 10898c2ecf20Sopenharmony_ci default: 10908c2ecf20Sopenharmony_ci dev_err(component->dev, "unsupported samplerate %d", samplerate); 10918c2ecf20Sopenharmony_ci return -EINVAL; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci err = regmap_update_bits(cpcap->regmap, sampreg, 10948c2ecf20Sopenharmony_ci sampmask, sampval | sampreset); 10958c2ecf20Sopenharmony_ci if (err) 10968c2ecf20Sopenharmony_ci return err; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci /* Wait for clock tree reset to complete */ 10998c2ecf20Sopenharmony_ci mdelay(CLOCK_TREE_RESET_TIME); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci err = regmap_read(cpcap->regmap, sampreg, &sampreadval); 11028c2ecf20Sopenharmony_ci if (err) 11038c2ecf20Sopenharmony_ci return err; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci if (sampreadval & sampreset) { 11068c2ecf20Sopenharmony_ci dev_err(component->dev, "reset self-clear failed: %04x", 11078c2ecf20Sopenharmony_ci sampreadval); 11088c2ecf20Sopenharmony_ci return -EIO; 11098c2ecf20Sopenharmony_ci } 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci return 0; 11128c2ecf20Sopenharmony_ci} 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_cistatic int cpcap_hifi_hw_params(struct snd_pcm_substream *substream, 11158c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 11168c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 11178c2ecf20Sopenharmony_ci{ 11188c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 11198c2ecf20Sopenharmony_ci struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); 11208c2ecf20Sopenharmony_ci int rate = params_rate(params); 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci dev_dbg(component->dev, "HiFi setup HW params: rate=%d", rate); 11238c2ecf20Sopenharmony_ci return cpcap_set_samprate(cpcap, CPCAP_DAI_HIFI, rate); 11248c2ecf20Sopenharmony_ci} 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_cistatic int cpcap_hifi_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, 11278c2ecf20Sopenharmony_ci unsigned int freq, int dir) 11288c2ecf20Sopenharmony_ci{ 11298c2ecf20Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 11308c2ecf20Sopenharmony_ci struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); 11318c2ecf20Sopenharmony_ci struct device *dev = component->dev; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci dev_dbg(dev, "HiFi setup sysclk: clk_id=%u, freq=%u", clk_id, freq); 11348c2ecf20Sopenharmony_ci return cpcap_set_sysclk(cpcap, CPCAP_DAI_HIFI, clk_id, freq); 11358c2ecf20Sopenharmony_ci} 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_cistatic int cpcap_hifi_set_dai_fmt(struct snd_soc_dai *codec_dai, 11388c2ecf20Sopenharmony_ci unsigned int fmt) 11398c2ecf20Sopenharmony_ci{ 11408c2ecf20Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 11418c2ecf20Sopenharmony_ci struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); 11428c2ecf20Sopenharmony_ci struct device *dev = component->dev; 11438c2ecf20Sopenharmony_ci static const u16 reg = CPCAP_REG_SDACDI; 11448c2ecf20Sopenharmony_ci static const u16 mask = 11458c2ecf20Sopenharmony_ci BIT(CPCAP_BIT_SMB_ST_DAC) | 11468c2ecf20Sopenharmony_ci BIT(CPCAP_BIT_ST_CLK_INV) | 11478c2ecf20Sopenharmony_ci BIT(CPCAP_BIT_ST_FS_INV) | 11488c2ecf20Sopenharmony_ci BIT(CPCAP_BIT_ST_DIG_AUD_FS0) | 11498c2ecf20Sopenharmony_ci BIT(CPCAP_BIT_ST_DIG_AUD_FS1) | 11508c2ecf20Sopenharmony_ci BIT(CPCAP_BIT_ST_L_TIMESLOT0) | 11518c2ecf20Sopenharmony_ci BIT(CPCAP_BIT_ST_L_TIMESLOT1) | 11528c2ecf20Sopenharmony_ci BIT(CPCAP_BIT_ST_L_TIMESLOT2) | 11538c2ecf20Sopenharmony_ci BIT(CPCAP_BIT_ST_R_TIMESLOT0) | 11548c2ecf20Sopenharmony_ci BIT(CPCAP_BIT_ST_R_TIMESLOT1) | 11558c2ecf20Sopenharmony_ci BIT(CPCAP_BIT_ST_R_TIMESLOT2); 11568c2ecf20Sopenharmony_ci u16 val = 0x0000; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci dev_dbg(dev, "HiFi setup dai format (%08x)", fmt); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci /* 11618c2ecf20Sopenharmony_ci * "HiFi Playback" should always be configured as 11628c2ecf20Sopenharmony_ci * SND_SOC_DAIFMT_CBM_CFM - codec clk & frm master 11638c2ecf20Sopenharmony_ci * SND_SOC_DAIFMT_I2S - I2S mode 11648c2ecf20Sopenharmony_ci */ 11658c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 11668c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBM_CFM: 11678c2ecf20Sopenharmony_ci val &= ~BIT(CPCAP_BIT_SMB_ST_DAC); 11688c2ecf20Sopenharmony_ci break; 11698c2ecf20Sopenharmony_ci default: 11708c2ecf20Sopenharmony_ci dev_err(dev, "HiFi dai fmt failed: CPCAP should be master"); 11718c2ecf20Sopenharmony_ci return -EINVAL; 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 11758c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_IB_IF: 11768c2ecf20Sopenharmony_ci val |= BIT(CPCAP_BIT_ST_FS_INV); 11778c2ecf20Sopenharmony_ci val |= BIT(CPCAP_BIT_ST_CLK_INV); 11788c2ecf20Sopenharmony_ci break; 11798c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 11808c2ecf20Sopenharmony_ci val &= ~BIT(CPCAP_BIT_ST_FS_INV); 11818c2ecf20Sopenharmony_ci val |= BIT(CPCAP_BIT_ST_CLK_INV); 11828c2ecf20Sopenharmony_ci break; 11838c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_NB_IF: 11848c2ecf20Sopenharmony_ci val |= BIT(CPCAP_BIT_ST_FS_INV); 11858c2ecf20Sopenharmony_ci val &= ~BIT(CPCAP_BIT_ST_CLK_INV); 11868c2ecf20Sopenharmony_ci break; 11878c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 11888c2ecf20Sopenharmony_ci val &= ~BIT(CPCAP_BIT_ST_FS_INV); 11898c2ecf20Sopenharmony_ci val &= ~BIT(CPCAP_BIT_ST_CLK_INV); 11908c2ecf20Sopenharmony_ci break; 11918c2ecf20Sopenharmony_ci default: 11928c2ecf20Sopenharmony_ci dev_err(dev, "HiFi dai fmt failed: unsupported clock invert mode"); 11938c2ecf20Sopenharmony_ci return -EINVAL; 11948c2ecf20Sopenharmony_ci } 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci if (val & BIT(CPCAP_BIT_ST_CLK_INV)) 11978c2ecf20Sopenharmony_ci val &= ~BIT(CPCAP_BIT_ST_CLK_INV); 11988c2ecf20Sopenharmony_ci else 11998c2ecf20Sopenharmony_ci val |= BIT(CPCAP_BIT_ST_CLK_INV); 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 12028c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 12038c2ecf20Sopenharmony_ci val |= BIT(CPCAP_BIT_ST_DIG_AUD_FS0); 12048c2ecf20Sopenharmony_ci val |= BIT(CPCAP_BIT_ST_DIG_AUD_FS1); 12058c2ecf20Sopenharmony_ci break; 12068c2ecf20Sopenharmony_ci default: 12078c2ecf20Sopenharmony_ci /* 01 - 4 slots network mode */ 12088c2ecf20Sopenharmony_ci val |= BIT(CPCAP_BIT_ST_DIG_AUD_FS0); 12098c2ecf20Sopenharmony_ci val &= ~BIT(CPCAP_BIT_ST_DIG_AUD_FS1); 12108c2ecf20Sopenharmony_ci /* L on slot 1 */ 12118c2ecf20Sopenharmony_ci val |= BIT(CPCAP_BIT_ST_L_TIMESLOT0); 12128c2ecf20Sopenharmony_ci break; 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci dev_dbg(dev, "HiFi dai format: val=%04x", val); 12168c2ecf20Sopenharmony_ci return regmap_update_bits(cpcap->regmap, reg, mask, val); 12178c2ecf20Sopenharmony_ci} 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_cistatic int cpcap_hifi_set_mute(struct snd_soc_dai *dai, int mute, int direction) 12208c2ecf20Sopenharmony_ci{ 12218c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 12228c2ecf20Sopenharmony_ci struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); 12238c2ecf20Sopenharmony_ci static const u16 reg = CPCAP_REG_RXSDOA; 12248c2ecf20Sopenharmony_ci static const u16 mask = BIT(CPCAP_BIT_ST_DAC_SW); 12258c2ecf20Sopenharmony_ci u16 val; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci if (mute) 12288c2ecf20Sopenharmony_ci val = 0; 12298c2ecf20Sopenharmony_ci else 12308c2ecf20Sopenharmony_ci val = BIT(CPCAP_BIT_ST_DAC_SW); 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci dev_dbg(component->dev, "HiFi mute: %d", mute); 12338c2ecf20Sopenharmony_ci return regmap_update_bits(cpcap->regmap, reg, mask, val); 12348c2ecf20Sopenharmony_ci} 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops cpcap_dai_hifi_ops = { 12378c2ecf20Sopenharmony_ci .hw_params = cpcap_hifi_hw_params, 12388c2ecf20Sopenharmony_ci .set_sysclk = cpcap_hifi_set_dai_sysclk, 12398c2ecf20Sopenharmony_ci .set_fmt = cpcap_hifi_set_dai_fmt, 12408c2ecf20Sopenharmony_ci .mute_stream = cpcap_hifi_set_mute, 12418c2ecf20Sopenharmony_ci .no_capture_mute = 1, 12428c2ecf20Sopenharmony_ci}; 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_cistatic int cpcap_voice_hw_params(struct snd_pcm_substream *substream, 12458c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 12468c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 12478c2ecf20Sopenharmony_ci{ 12488c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 12498c2ecf20Sopenharmony_ci struct device *dev = component->dev; 12508c2ecf20Sopenharmony_ci struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); 12518c2ecf20Sopenharmony_ci static const u16 reg_cdi = CPCAP_REG_CDI; 12528c2ecf20Sopenharmony_ci int rate = params_rate(params); 12538c2ecf20Sopenharmony_ci int channels = params_channels(params); 12548c2ecf20Sopenharmony_ci int direction = substream->stream; 12558c2ecf20Sopenharmony_ci u16 val, mask; 12568c2ecf20Sopenharmony_ci int err; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci dev_dbg(dev, "Voice setup HW params: rate=%d, direction=%d, chan=%d", 12598c2ecf20Sopenharmony_ci rate, direction, channels); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci err = cpcap_set_samprate(cpcap, CPCAP_DAI_VOICE, rate); 12628c2ecf20Sopenharmony_ci if (err) 12638c2ecf20Sopenharmony_ci return err; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci if (direction == SNDRV_PCM_STREAM_CAPTURE) { 12668c2ecf20Sopenharmony_ci mask = 0x0000; 12678c2ecf20Sopenharmony_ci mask |= BIT(CPCAP_BIT_MIC1_RX_TIMESLOT0); 12688c2ecf20Sopenharmony_ci mask |= BIT(CPCAP_BIT_MIC1_RX_TIMESLOT1); 12698c2ecf20Sopenharmony_ci mask |= BIT(CPCAP_BIT_MIC1_RX_TIMESLOT2); 12708c2ecf20Sopenharmony_ci mask |= BIT(CPCAP_BIT_MIC2_TIMESLOT0); 12718c2ecf20Sopenharmony_ci mask |= BIT(CPCAP_BIT_MIC2_TIMESLOT1); 12728c2ecf20Sopenharmony_ci mask |= BIT(CPCAP_BIT_MIC2_TIMESLOT2); 12738c2ecf20Sopenharmony_ci val = 0x0000; 12748c2ecf20Sopenharmony_ci if (channels >= 2) 12758c2ecf20Sopenharmony_ci val = BIT(CPCAP_BIT_MIC1_RX_TIMESLOT0); 12768c2ecf20Sopenharmony_ci err = regmap_update_bits(cpcap->regmap, reg_cdi, mask, val); 12778c2ecf20Sopenharmony_ci if (err) 12788c2ecf20Sopenharmony_ci return err; 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci return 0; 12828c2ecf20Sopenharmony_ci} 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_cistatic int cpcap_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, 12858c2ecf20Sopenharmony_ci unsigned int freq, int dir) 12868c2ecf20Sopenharmony_ci{ 12878c2ecf20Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 12888c2ecf20Sopenharmony_ci struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci dev_dbg(component->dev, "Voice setup sysclk: clk_id=%u, freq=%u", 12918c2ecf20Sopenharmony_ci clk_id, freq); 12928c2ecf20Sopenharmony_ci return cpcap_set_sysclk(cpcap, CPCAP_DAI_VOICE, clk_id, freq); 12938c2ecf20Sopenharmony_ci} 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_cistatic int cpcap_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, 12968c2ecf20Sopenharmony_ci unsigned int fmt) 12978c2ecf20Sopenharmony_ci{ 12988c2ecf20Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 12998c2ecf20Sopenharmony_ci struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); 13008c2ecf20Sopenharmony_ci static const u16 mask = BIT(CPCAP_BIT_SMB_CDC) | 13018c2ecf20Sopenharmony_ci BIT(CPCAP_BIT_CLK_INV) | 13028c2ecf20Sopenharmony_ci BIT(CPCAP_BIT_FS_INV) | 13038c2ecf20Sopenharmony_ci BIT(CPCAP_BIT_CDC_DIG_AUD_FS0) | 13048c2ecf20Sopenharmony_ci BIT(CPCAP_BIT_CDC_DIG_AUD_FS1); 13058c2ecf20Sopenharmony_ci u16 val = 0x0000; 13068c2ecf20Sopenharmony_ci int err; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci dev_dbg(component->dev, "Voice setup dai format (%08x)", fmt); 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci /* 13118c2ecf20Sopenharmony_ci * "Voice Playback" and "Voice Capture" should always be 13128c2ecf20Sopenharmony_ci * configured as SND_SOC_DAIFMT_CBM_CFM - codec clk & frm 13138c2ecf20Sopenharmony_ci * master 13148c2ecf20Sopenharmony_ci */ 13158c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 13168c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBM_CFM: 13178c2ecf20Sopenharmony_ci val &= ~BIT(CPCAP_BIT_SMB_CDC); 13188c2ecf20Sopenharmony_ci break; 13198c2ecf20Sopenharmony_ci default: 13208c2ecf20Sopenharmony_ci dev_err(component->dev, "Voice dai fmt failed: CPCAP should be the master"); 13218c2ecf20Sopenharmony_ci val &= ~BIT(CPCAP_BIT_SMB_CDC); 13228c2ecf20Sopenharmony_ci break; 13238c2ecf20Sopenharmony_ci } 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 13268c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_IB_IF: 13278c2ecf20Sopenharmony_ci val |= BIT(CPCAP_BIT_CLK_INV); 13288c2ecf20Sopenharmony_ci val |= BIT(CPCAP_BIT_FS_INV); 13298c2ecf20Sopenharmony_ci break; 13308c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 13318c2ecf20Sopenharmony_ci val |= BIT(CPCAP_BIT_CLK_INV); 13328c2ecf20Sopenharmony_ci val &= ~BIT(CPCAP_BIT_FS_INV); 13338c2ecf20Sopenharmony_ci break; 13348c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_NB_IF: 13358c2ecf20Sopenharmony_ci val &= ~BIT(CPCAP_BIT_CLK_INV); 13368c2ecf20Sopenharmony_ci val |= BIT(CPCAP_BIT_FS_INV); 13378c2ecf20Sopenharmony_ci break; 13388c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 13398c2ecf20Sopenharmony_ci val &= ~BIT(CPCAP_BIT_CLK_INV); 13408c2ecf20Sopenharmony_ci val &= ~BIT(CPCAP_BIT_FS_INV); 13418c2ecf20Sopenharmony_ci break; 13428c2ecf20Sopenharmony_ci default: 13438c2ecf20Sopenharmony_ci dev_err(component->dev, "Voice dai fmt failed: unsupported clock invert mode"); 13448c2ecf20Sopenharmony_ci break; 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci if (val & BIT(CPCAP_BIT_CLK_INV)) 13488c2ecf20Sopenharmony_ci val &= ~BIT(CPCAP_BIT_CLK_INV); 13498c2ecf20Sopenharmony_ci else 13508c2ecf20Sopenharmony_ci val |= BIT(CPCAP_BIT_CLK_INV); 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 13538c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 13548c2ecf20Sopenharmony_ci /* 11 - true I2S mode */ 13558c2ecf20Sopenharmony_ci val |= BIT(CPCAP_BIT_CDC_DIG_AUD_FS0); 13568c2ecf20Sopenharmony_ci val |= BIT(CPCAP_BIT_CDC_DIG_AUD_FS1); 13578c2ecf20Sopenharmony_ci break; 13588c2ecf20Sopenharmony_ci default: 13598c2ecf20Sopenharmony_ci /* 4 timeslots network mode */ 13608c2ecf20Sopenharmony_ci val |= BIT(CPCAP_BIT_CDC_DIG_AUD_FS0); 13618c2ecf20Sopenharmony_ci val &= ~BIT(CPCAP_BIT_CDC_DIG_AUD_FS1); 13628c2ecf20Sopenharmony_ci break; 13638c2ecf20Sopenharmony_ci } 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci dev_dbg(component->dev, "Voice dai format: val=%04x", val); 13668c2ecf20Sopenharmony_ci err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI, mask, val); 13678c2ecf20Sopenharmony_ci if (err) 13688c2ecf20Sopenharmony_ci return err; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci cpcap->codec_format = val; 13718c2ecf20Sopenharmony_ci return 0; 13728c2ecf20Sopenharmony_ci} 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_cistatic int cpcap_voice_set_mute(struct snd_soc_dai *dai, 13758c2ecf20Sopenharmony_ci int mute, int direction) 13768c2ecf20Sopenharmony_ci{ 13778c2ecf20Sopenharmony_ci struct snd_soc_component *component = dai->component; 13788c2ecf20Sopenharmony_ci struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); 13798c2ecf20Sopenharmony_ci static const u16 reg = CPCAP_REG_RXCOA; 13808c2ecf20Sopenharmony_ci static const u16 mask = BIT(CPCAP_BIT_CDC_SW); 13818c2ecf20Sopenharmony_ci u16 val; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci if (mute) 13848c2ecf20Sopenharmony_ci val = 0; 13858c2ecf20Sopenharmony_ci else 13868c2ecf20Sopenharmony_ci val = BIT(CPCAP_BIT_CDC_SW); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci dev_dbg(component->dev, "Voice mute: %d", mute); 13898c2ecf20Sopenharmony_ci return regmap_update_bits(cpcap->regmap, reg, mask, val); 13908c2ecf20Sopenharmony_ci}; 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops cpcap_dai_voice_ops = { 13938c2ecf20Sopenharmony_ci .hw_params = cpcap_voice_hw_params, 13948c2ecf20Sopenharmony_ci .set_sysclk = cpcap_voice_set_dai_sysclk, 13958c2ecf20Sopenharmony_ci .set_fmt = cpcap_voice_set_dai_fmt, 13968c2ecf20Sopenharmony_ci .mute_stream = cpcap_voice_set_mute, 13978c2ecf20Sopenharmony_ci .no_capture_mute = 1, 13988c2ecf20Sopenharmony_ci}; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver cpcap_dai[] = { 14018c2ecf20Sopenharmony_ci{ 14028c2ecf20Sopenharmony_ci .id = 0, 14038c2ecf20Sopenharmony_ci .name = "cpcap-hifi", 14048c2ecf20Sopenharmony_ci .playback = { 14058c2ecf20Sopenharmony_ci .stream_name = "HiFi Playback", 14068c2ecf20Sopenharmony_ci .channels_min = 2, 14078c2ecf20Sopenharmony_ci .channels_max = 2, 14088c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_48000, 14098c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE, 14108c2ecf20Sopenharmony_ci }, 14118c2ecf20Sopenharmony_ci .ops = &cpcap_dai_hifi_ops, 14128c2ecf20Sopenharmony_ci}, 14138c2ecf20Sopenharmony_ci{ 14148c2ecf20Sopenharmony_ci .id = 1, 14158c2ecf20Sopenharmony_ci .name = "cpcap-voice", 14168c2ecf20Sopenharmony_ci .playback = { 14178c2ecf20Sopenharmony_ci .stream_name = "Voice Playback", 14188c2ecf20Sopenharmony_ci .channels_min = 1, 14198c2ecf20Sopenharmony_ci .channels_max = 1, 14208c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_48000, 14218c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 14228c2ecf20Sopenharmony_ci }, 14238c2ecf20Sopenharmony_ci .capture = { 14248c2ecf20Sopenharmony_ci .stream_name = "Voice Capture", 14258c2ecf20Sopenharmony_ci .channels_min = 1, 14268c2ecf20Sopenharmony_ci .channels_max = 2, 14278c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_48000, 14288c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 14298c2ecf20Sopenharmony_ci }, 14308c2ecf20Sopenharmony_ci .ops = &cpcap_dai_voice_ops, 14318c2ecf20Sopenharmony_ci}, 14328c2ecf20Sopenharmony_ci}; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_cistatic int cpcap_dai_mux(struct cpcap_audio *cpcap, bool swap_dai_configuration) 14358c2ecf20Sopenharmony_ci{ 14368c2ecf20Sopenharmony_ci u16 hifi_val, voice_val; 14378c2ecf20Sopenharmony_ci u16 hifi_mask = BIT(CPCAP_BIT_DIG_AUD_IN_ST_DAC); 14388c2ecf20Sopenharmony_ci u16 voice_mask = BIT(CPCAP_BIT_DIG_AUD_IN); 14398c2ecf20Sopenharmony_ci int err; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci if (!swap_dai_configuration) { 14448c2ecf20Sopenharmony_ci /* Codec on DAI0, HiFi on DAI1 */ 14458c2ecf20Sopenharmony_ci voice_val = 0; 14468c2ecf20Sopenharmony_ci hifi_val = hifi_mask; 14478c2ecf20Sopenharmony_ci } else { 14488c2ecf20Sopenharmony_ci /* Codec on DAI1, HiFi on DAI0 */ 14498c2ecf20Sopenharmony_ci voice_val = voice_mask; 14508c2ecf20Sopenharmony_ci hifi_val = 0; 14518c2ecf20Sopenharmony_ci } 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci err = regmap_update_bits(cpcap->regmap, CPCAP_REG_CDI, 14548c2ecf20Sopenharmony_ci voice_mask, voice_val); 14558c2ecf20Sopenharmony_ci if (err) 14568c2ecf20Sopenharmony_ci return err; 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci err = regmap_update_bits(cpcap->regmap, CPCAP_REG_SDACDI, 14598c2ecf20Sopenharmony_ci hifi_mask, hifi_val); 14608c2ecf20Sopenharmony_ci if (err) 14618c2ecf20Sopenharmony_ci return err; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci return 0; 14648c2ecf20Sopenharmony_ci} 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_cistatic int cpcap_audio_reset(struct snd_soc_component *component, 14678c2ecf20Sopenharmony_ci bool swap_dai_configuration) 14688c2ecf20Sopenharmony_ci{ 14698c2ecf20Sopenharmony_ci struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); 14708c2ecf20Sopenharmony_ci int i, err = 0; 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci dev_dbg(component->dev, "init audio codec"); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cpcap_default_regs); i++) { 14758c2ecf20Sopenharmony_ci err = regmap_update_bits(cpcap->regmap, 14768c2ecf20Sopenharmony_ci cpcap_default_regs[i].reg, 14778c2ecf20Sopenharmony_ci cpcap_default_regs[i].mask, 14788c2ecf20Sopenharmony_ci cpcap_default_regs[i].val); 14798c2ecf20Sopenharmony_ci if (err) 14808c2ecf20Sopenharmony_ci return err; 14818c2ecf20Sopenharmony_ci } 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci /* setup default settings */ 14848c2ecf20Sopenharmony_ci err = cpcap_dai_mux(cpcap, swap_dai_configuration); 14858c2ecf20Sopenharmony_ci if (err) 14868c2ecf20Sopenharmony_ci return err; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci err = cpcap_set_sysclk(cpcap, CPCAP_DAI_HIFI, 0, 26000000); 14898c2ecf20Sopenharmony_ci if (err) 14908c2ecf20Sopenharmony_ci return err; 14918c2ecf20Sopenharmony_ci err = cpcap_set_sysclk(cpcap, CPCAP_DAI_VOICE, 0, 26000000); 14928c2ecf20Sopenharmony_ci if (err) 14938c2ecf20Sopenharmony_ci return err; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci err = cpcap_set_samprate(cpcap, CPCAP_DAI_HIFI, 48000); 14968c2ecf20Sopenharmony_ci if (err) 14978c2ecf20Sopenharmony_ci return err; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci err = cpcap_set_samprate(cpcap, CPCAP_DAI_VOICE, 48000); 15008c2ecf20Sopenharmony_ci if (err) 15018c2ecf20Sopenharmony_ci return err; 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci return 0; 15048c2ecf20Sopenharmony_ci} 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_cistatic int cpcap_soc_probe(struct snd_soc_component *component) 15078c2ecf20Sopenharmony_ci{ 15088c2ecf20Sopenharmony_ci struct cpcap_audio *cpcap; 15098c2ecf20Sopenharmony_ci int err; 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci cpcap = devm_kzalloc(component->dev, sizeof(*cpcap), GFP_KERNEL); 15128c2ecf20Sopenharmony_ci if (!cpcap) 15138c2ecf20Sopenharmony_ci return -ENOMEM; 15148c2ecf20Sopenharmony_ci snd_soc_component_set_drvdata(component, cpcap); 15158c2ecf20Sopenharmony_ci cpcap->component = component; 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci cpcap->regmap = dev_get_regmap(component->dev->parent, NULL); 15188c2ecf20Sopenharmony_ci if (!cpcap->regmap) 15198c2ecf20Sopenharmony_ci return -ENODEV; 15208c2ecf20Sopenharmony_ci snd_soc_component_init_regmap(component, cpcap->regmap); 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci err = cpcap_get_vendor(component->dev, cpcap->regmap, &cpcap->vendor); 15238c2ecf20Sopenharmony_ci if (err) 15248c2ecf20Sopenharmony_ci return err; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci return cpcap_audio_reset(component, false); 15278c2ecf20Sopenharmony_ci} 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_cistatic struct snd_soc_component_driver soc_codec_dev_cpcap = { 15308c2ecf20Sopenharmony_ci .probe = cpcap_soc_probe, 15318c2ecf20Sopenharmony_ci .controls = cpcap_snd_controls, 15328c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(cpcap_snd_controls), 15338c2ecf20Sopenharmony_ci .dapm_widgets = cpcap_dapm_widgets, 15348c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(cpcap_dapm_widgets), 15358c2ecf20Sopenharmony_ci .dapm_routes = intercon, 15368c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(intercon), 15378c2ecf20Sopenharmony_ci .idle_bias_on = 1, 15388c2ecf20Sopenharmony_ci .use_pmdown_time = 1, 15398c2ecf20Sopenharmony_ci .endianness = 1, 15408c2ecf20Sopenharmony_ci .non_legacy_dai_naming = 1, 15418c2ecf20Sopenharmony_ci}; 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_cistatic int cpcap_codec_probe(struct platform_device *pdev) 15448c2ecf20Sopenharmony_ci{ 15458c2ecf20Sopenharmony_ci struct device_node *codec_node = 15468c2ecf20Sopenharmony_ci of_get_child_by_name(pdev->dev.parent->of_node, "audio-codec"); 15478c2ecf20Sopenharmony_ci if (!codec_node) 15488c2ecf20Sopenharmony_ci return -ENODEV; 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci pdev->dev.of_node = codec_node; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci return devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_cpcap, 15538c2ecf20Sopenharmony_ci cpcap_dai, ARRAY_SIZE(cpcap_dai)); 15548c2ecf20Sopenharmony_ci} 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_cistatic struct platform_driver cpcap_codec_driver = { 15578c2ecf20Sopenharmony_ci .probe = cpcap_codec_probe, 15588c2ecf20Sopenharmony_ci .driver = { 15598c2ecf20Sopenharmony_ci .name = "cpcap-codec", 15608c2ecf20Sopenharmony_ci }, 15618c2ecf20Sopenharmony_ci}; 15628c2ecf20Sopenharmony_cimodule_platform_driver(cpcap_codec_driver); 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:cpcap-codec"); 15658c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ASoC CPCAP codec driver"); 15668c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sebastian Reichel"); 15678c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1568