18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. 38c2ecf20Sopenharmony_ci// Copyright (c) 2017-2018, Linaro Limited 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <linux/slab.h> 68c2ecf20Sopenharmony_ci#include <sound/soc.h> 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/delay.h> 98c2ecf20Sopenharmony_ci#include "wcd9335.h" 108c2ecf20Sopenharmony_ci#include "wcd-clsh-v2.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistruct wcd_clsh_ctrl { 138c2ecf20Sopenharmony_ci int state; 148c2ecf20Sopenharmony_ci int mode; 158c2ecf20Sopenharmony_ci int flyback_users; 168c2ecf20Sopenharmony_ci int buck_users; 178c2ecf20Sopenharmony_ci int clsh_users; 188c2ecf20Sopenharmony_ci int codec_version; 198c2ecf20Sopenharmony_ci struct snd_soc_component *comp; 208c2ecf20Sopenharmony_ci}; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* Class-H registers for codecs from and above WCD9335 */ 238c2ecf20Sopenharmony_ci#define WCD9XXX_A_CDC_RX0_RX_PATH_CFG0 WCD9335_REG(0xB, 0x42) 248c2ecf20Sopenharmony_ci#define WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK BIT(6) 258c2ecf20Sopenharmony_ci#define WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE BIT(6) 268c2ecf20Sopenharmony_ci#define WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE 0 278c2ecf20Sopenharmony_ci#define WCD9XXX_A_CDC_RX1_RX_PATH_CFG0 WCD9335_REG(0xB, 0x56) 288c2ecf20Sopenharmony_ci#define WCD9XXX_A_CDC_RX2_RX_PATH_CFG0 WCD9335_REG(0xB, 0x6A) 298c2ecf20Sopenharmony_ci#define WCD9XXX_A_CDC_CLSH_K1_MSB WCD9335_REG(0xC, 0x08) 308c2ecf20Sopenharmony_ci#define WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK GENMASK(3, 0) 318c2ecf20Sopenharmony_ci#define WCD9XXX_A_CDC_CLSH_K1_LSB WCD9335_REG(0xC, 0x09) 328c2ecf20Sopenharmony_ci#define WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK GENMASK(7, 0) 338c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_RX_SUPPLIES WCD9335_REG(0x6, 0x08) 348c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK BIT(1) 358c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H 0 368c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_AB BIT(1) 378c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK BIT(2) 388c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_UHQA BIT(2) 398c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_DEFAULT 0 408c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK BIT(3) 418c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_UHQA BIT(3) 428c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT 0 438c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_RX_VNEG_EN_MASK BIT(6) 448c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_RX_VNEG_EN_SHIFT 6 458c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_RX_VNEG_ENABLE BIT(6) 468c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_RX_VNEG_DISABLE 0 478c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_RX_VPOS_EN_MASK BIT(7) 488c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_RX_VPOS_EN_SHIFT 7 498c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_RX_VPOS_ENABLE BIT(7) 508c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_RX_VPOS_DISABLE 0 518c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_HPH WCD9335_REG(0x6, 0x09) 528c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK GENMASK(3, 2) 538c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_HPH_PWR_LEVEL_UHQA 0x08 548c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_HPH_PWR_LEVEL_LP 0x04 558c2ecf20Sopenharmony_ci#define WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL 0x0 568c2ecf20Sopenharmony_ci#define WCD9XXX_A_CDC_CLSH_CRC WCD9335_REG(0xC, 0x01) 578c2ecf20Sopenharmony_ci#define WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK BIT(0) 588c2ecf20Sopenharmony_ci#define WCD9XXX_A_CDC_CLSH_CRC_CLK_ENABLE BIT(0) 598c2ecf20Sopenharmony_ci#define WCD9XXX_A_CDC_CLSH_CRC_CLK_DISABLE 0 608c2ecf20Sopenharmony_ci#define WCD9XXX_FLYBACK_EN WCD9335_REG(0x6, 0xA4) 618c2ecf20Sopenharmony_ci#define WCD9XXX_FLYBACK_EN_DELAY_SEL_MASK GENMASK(6, 5) 628c2ecf20Sopenharmony_ci#define WCD9XXX_FLYBACK_EN_DELAY_26P25_US 0x40 638c2ecf20Sopenharmony_ci#define WCD9XXX_FLYBACK_EN_RESET_BY_EXT_MASK BIT(4) 648c2ecf20Sopenharmony_ci#define WCD9XXX_FLYBACK_EN_PWDN_WITHOUT_DELAY BIT(4) 658c2ecf20Sopenharmony_ci#define WCD9XXX_FLYBACK_EN_PWDN_WITH_DELAY 0 668c2ecf20Sopenharmony_ci#define WCD9XXX_RX_BIAS_FLYB_BUFF WCD9335_REG(0x6, 0xC7) 678c2ecf20Sopenharmony_ci#define WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK GENMASK(7, 4) 688c2ecf20Sopenharmony_ci#define WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK GENMASK(3, 0) 698c2ecf20Sopenharmony_ci#define WCD9XXX_HPH_L_EN WCD9335_REG(0x6, 0xD3) 708c2ecf20Sopenharmony_ci#define WCD9XXX_HPH_CONST_SEL_L_MASK GENMASK(7, 3) 718c2ecf20Sopenharmony_ci#define WCD9XXX_HPH_CONST_SEL_BYPASS 0 728c2ecf20Sopenharmony_ci#define WCD9XXX_HPH_CONST_SEL_LP_PATH 0x40 738c2ecf20Sopenharmony_ci#define WCD9XXX_HPH_CONST_SEL_HQ_PATH 0x80 748c2ecf20Sopenharmony_ci#define WCD9XXX_HPH_R_EN WCD9335_REG(0x6, 0xD6) 758c2ecf20Sopenharmony_ci#define WCD9XXX_HPH_REFBUFF_UHQA_CTL WCD9335_REG(0x6, 0xDD) 768c2ecf20Sopenharmony_ci#define WCD9XXX_HPH_REFBUFF_UHQA_GAIN_MASK GENMASK(2, 0) 778c2ecf20Sopenharmony_ci#define WCD9XXX_CLASSH_CTRL_VCL_2 WCD9335_REG(0x6, 0x9B) 788c2ecf20Sopenharmony_ci#define WCD9XXX_CLASSH_CTRL_VCL_2_VREF_FILT_1_MASK GENMASK(5, 4) 798c2ecf20Sopenharmony_ci#define WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_50KOHM 0x20 808c2ecf20Sopenharmony_ci#define WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_0KOHM 0x0 818c2ecf20Sopenharmony_ci#define WCD9XXX_CDC_RX1_RX_PATH_CTL WCD9335_REG(0xB, 0x55) 828c2ecf20Sopenharmony_ci#define WCD9XXX_CDC_RX2_RX_PATH_CTL WCD9335_REG(0xB, 0x69) 838c2ecf20Sopenharmony_ci#define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_CONTROL WCD9335_REG(0xD, 0x41) 848c2ecf20Sopenharmony_ci#define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_EN_MASK BIT(0) 858c2ecf20Sopenharmony_ci#define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_11P3_EN_MASK BIT(1) 868c2ecf20Sopenharmony_ci#define WCD9XXX_CLASSH_CTRL_CCL_1 WCD9335_REG(0x6, 0x9C) 878c2ecf20Sopenharmony_ci#define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_MASK GENMASK(7, 4) 888c2ecf20Sopenharmony_ci#define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA 0x50 898c2ecf20Sopenharmony_ci#define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA 0x30 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci#define CLSH_REQ_ENABLE true 928c2ecf20Sopenharmony_ci#define CLSH_REQ_DISABLE false 938c2ecf20Sopenharmony_ci#define WCD_USLEEP_RANGE 50 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cienum { 968c2ecf20Sopenharmony_ci DAC_GAIN_0DB = 0, 978c2ecf20Sopenharmony_ci DAC_GAIN_0P2DB, 988c2ecf20Sopenharmony_ci DAC_GAIN_0P4DB, 998c2ecf20Sopenharmony_ci DAC_GAIN_0P6DB, 1008c2ecf20Sopenharmony_ci DAC_GAIN_0P8DB, 1018c2ecf20Sopenharmony_ci DAC_GAIN_M0P2DB, 1028c2ecf20Sopenharmony_ci DAC_GAIN_M0P4DB, 1038c2ecf20Sopenharmony_ci DAC_GAIN_M0P6DB, 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic inline void wcd_enable_clsh_block(struct wcd_clsh_ctrl *ctrl, 1078c2ecf20Sopenharmony_ci bool enable) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci struct snd_soc_component *comp = ctrl->comp; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if ((enable && ++ctrl->clsh_users == 1) || 1128c2ecf20Sopenharmony_ci (!enable && --ctrl->clsh_users == 0)) 1138c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, WCD9XXX_A_CDC_CLSH_CRC, 1148c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK, 1158c2ecf20Sopenharmony_ci enable); 1168c2ecf20Sopenharmony_ci if (ctrl->clsh_users < 0) 1178c2ecf20Sopenharmony_ci ctrl->clsh_users = 0; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic inline bool wcd_clsh_enable_status(struct snd_soc_component *comp) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci return snd_soc_component_read(comp, WCD9XXX_A_CDC_CLSH_CRC) & 1238c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic inline void wcd_clsh_set_buck_mode(struct snd_soc_component *comp, 1278c2ecf20Sopenharmony_ci int mode) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci /* set to HIFI */ 1308c2ecf20Sopenharmony_ci if (mode == CLS_H_HIFI) 1318c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, 1328c2ecf20Sopenharmony_ci WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK, 1338c2ecf20Sopenharmony_ci WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_UHQA); 1348c2ecf20Sopenharmony_ci else 1358c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, 1368c2ecf20Sopenharmony_ci WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK, 1378c2ecf20Sopenharmony_ci WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT); 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic inline void wcd_clsh_set_flyback_mode(struct snd_soc_component *comp, 1418c2ecf20Sopenharmony_ci int mode) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci /* set to HIFI */ 1448c2ecf20Sopenharmony_ci if (mode == CLS_H_HIFI) 1458c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, 1468c2ecf20Sopenharmony_ci WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK, 1478c2ecf20Sopenharmony_ci WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_UHQA); 1488c2ecf20Sopenharmony_ci else 1498c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, 1508c2ecf20Sopenharmony_ci WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK, 1518c2ecf20Sopenharmony_ci WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_DEFAULT); 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic void wcd_clsh_buck_ctrl(struct wcd_clsh_ctrl *ctrl, 1558c2ecf20Sopenharmony_ci int mode, 1568c2ecf20Sopenharmony_ci bool enable) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct snd_soc_component *comp = ctrl->comp; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* enable/disable buck */ 1618c2ecf20Sopenharmony_ci if ((enable && (++ctrl->buck_users == 1)) || 1628c2ecf20Sopenharmony_ci (!enable && (--ctrl->buck_users == 0))) 1638c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, 1648c2ecf20Sopenharmony_ci WCD9XXX_A_ANA_RX_VPOS_EN_MASK, 1658c2ecf20Sopenharmony_ci enable << WCD9XXX_A_ANA_RX_VPOS_EN_SHIFT); 1668c2ecf20Sopenharmony_ci /* 1678c2ecf20Sopenharmony_ci * 500us sleep is required after buck enable/disable 1688c2ecf20Sopenharmony_ci * as per HW requirement 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_ci usleep_range(500, 500 + WCD_USLEEP_RANGE); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic void wcd_clsh_flyback_ctrl(struct wcd_clsh_ctrl *ctrl, 1748c2ecf20Sopenharmony_ci int mode, 1758c2ecf20Sopenharmony_ci bool enable) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct snd_soc_component *comp = ctrl->comp; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* enable/disable flyback */ 1808c2ecf20Sopenharmony_ci if ((enable && (++ctrl->flyback_users == 1)) || 1818c2ecf20Sopenharmony_ci (!enable && (--ctrl->flyback_users == 0))) { 1828c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, 1838c2ecf20Sopenharmony_ci WCD9XXX_A_ANA_RX_VNEG_EN_MASK, 1848c2ecf20Sopenharmony_ci enable << WCD9XXX_A_ANA_RX_VNEG_EN_SHIFT); 1858c2ecf20Sopenharmony_ci /* 100usec delay is needed as per HW requirement */ 1868c2ecf20Sopenharmony_ci usleep_range(100, 110); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci /* 1898c2ecf20Sopenharmony_ci * 500us sleep is required after flyback enable/disable 1908c2ecf20Sopenharmony_ci * as per HW requirement 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_ci usleep_range(500, 500 + WCD_USLEEP_RANGE); 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic void wcd_clsh_set_gain_path(struct wcd_clsh_ctrl *ctrl, int mode) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci struct snd_soc_component *comp = ctrl->comp; 1988c2ecf20Sopenharmony_ci int val = 0; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci switch (mode) { 2018c2ecf20Sopenharmony_ci case CLS_H_NORMAL: 2028c2ecf20Sopenharmony_ci case CLS_AB: 2038c2ecf20Sopenharmony_ci val = WCD9XXX_HPH_CONST_SEL_BYPASS; 2048c2ecf20Sopenharmony_ci break; 2058c2ecf20Sopenharmony_ci case CLS_H_HIFI: 2068c2ecf20Sopenharmony_ci val = WCD9XXX_HPH_CONST_SEL_HQ_PATH; 2078c2ecf20Sopenharmony_ci break; 2088c2ecf20Sopenharmony_ci case CLS_H_LP: 2098c2ecf20Sopenharmony_ci val = WCD9XXX_HPH_CONST_SEL_LP_PATH; 2108c2ecf20Sopenharmony_ci break; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, WCD9XXX_HPH_L_EN, 2148c2ecf20Sopenharmony_ci WCD9XXX_HPH_CONST_SEL_L_MASK, 2158c2ecf20Sopenharmony_ci val); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, WCD9XXX_HPH_R_EN, 2188c2ecf20Sopenharmony_ci WCD9XXX_HPH_CONST_SEL_L_MASK, 2198c2ecf20Sopenharmony_ci val); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic void wcd_clsh_set_hph_mode(struct snd_soc_component *comp, 2238c2ecf20Sopenharmony_ci int mode) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci int val = 0, gain = 0, res_val; 2268c2ecf20Sopenharmony_ci int ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci res_val = WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_0KOHM; 2298c2ecf20Sopenharmony_ci switch (mode) { 2308c2ecf20Sopenharmony_ci case CLS_H_NORMAL: 2318c2ecf20Sopenharmony_ci res_val = WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_50KOHM; 2328c2ecf20Sopenharmony_ci val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL; 2338c2ecf20Sopenharmony_ci gain = DAC_GAIN_0DB; 2348c2ecf20Sopenharmony_ci ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; 2358c2ecf20Sopenharmony_ci break; 2368c2ecf20Sopenharmony_ci case CLS_AB: 2378c2ecf20Sopenharmony_ci val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL; 2388c2ecf20Sopenharmony_ci gain = DAC_GAIN_0DB; 2398c2ecf20Sopenharmony_ci ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; 2408c2ecf20Sopenharmony_ci break; 2418c2ecf20Sopenharmony_ci case CLS_H_HIFI: 2428c2ecf20Sopenharmony_ci val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_UHQA; 2438c2ecf20Sopenharmony_ci gain = DAC_GAIN_M0P2DB; 2448c2ecf20Sopenharmony_ci ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; 2458c2ecf20Sopenharmony_ci break; 2468c2ecf20Sopenharmony_ci case CLS_H_LP: 2478c2ecf20Sopenharmony_ci val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_LP; 2488c2ecf20Sopenharmony_ci ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA; 2498c2ecf20Sopenharmony_ci break; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_HPH, 2538c2ecf20Sopenharmony_ci WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK, val); 2548c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, WCD9XXX_CLASSH_CTRL_VCL_2, 2558c2ecf20Sopenharmony_ci WCD9XXX_CLASSH_CTRL_VCL_2_VREF_FILT_1_MASK, 2568c2ecf20Sopenharmony_ci res_val); 2578c2ecf20Sopenharmony_ci if (mode != CLS_H_LP) 2588c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, 2598c2ecf20Sopenharmony_ci WCD9XXX_HPH_REFBUFF_UHQA_CTL, 2608c2ecf20Sopenharmony_ci WCD9XXX_HPH_REFBUFF_UHQA_GAIN_MASK, 2618c2ecf20Sopenharmony_ci gain); 2628c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, WCD9XXX_CLASSH_CTRL_CCL_1, 2638c2ecf20Sopenharmony_ci WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_MASK, 2648c2ecf20Sopenharmony_ci ipeak); 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic void wcd_clsh_set_flyback_current(struct snd_soc_component *comp, 2688c2ecf20Sopenharmony_ci int mode) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, WCD9XXX_RX_BIAS_FLYB_BUFF, 2728c2ecf20Sopenharmony_ci WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK, 0x0A); 2738c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, WCD9XXX_RX_BIAS_FLYB_BUFF, 2748c2ecf20Sopenharmony_ci WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK, 0x0A); 2758c2ecf20Sopenharmony_ci /* Sleep needed to avoid click and pop as per HW requirement */ 2768c2ecf20Sopenharmony_ci usleep_range(100, 110); 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic void wcd_clsh_set_buck_regulator_mode(struct snd_soc_component *comp, 2808c2ecf20Sopenharmony_ci int mode) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci if (mode == CLS_AB) 2838c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, 2848c2ecf20Sopenharmony_ci WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK, 2858c2ecf20Sopenharmony_ci WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_AB); 2868c2ecf20Sopenharmony_ci else 2878c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES, 2888c2ecf20Sopenharmony_ci WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK, 2898c2ecf20Sopenharmony_ci WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H); 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic void wcd_clsh_state_lo(struct wcd_clsh_ctrl *ctrl, int req_state, 2938c2ecf20Sopenharmony_ci bool is_enable, int mode) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci struct snd_soc_component *comp = ctrl->comp; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (mode != CLS_AB) { 2988c2ecf20Sopenharmony_ci dev_err(comp->dev, "%s: LO cannot be in this mode: %d\n", 2998c2ecf20Sopenharmony_ci __func__, mode); 3008c2ecf20Sopenharmony_ci return; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (is_enable) { 3048c2ecf20Sopenharmony_ci wcd_clsh_set_buck_regulator_mode(comp, mode); 3058c2ecf20Sopenharmony_ci wcd_clsh_set_buck_mode(comp, mode); 3068c2ecf20Sopenharmony_ci wcd_clsh_set_flyback_mode(comp, mode); 3078c2ecf20Sopenharmony_ci wcd_clsh_flyback_ctrl(ctrl, mode, true); 3088c2ecf20Sopenharmony_ci wcd_clsh_set_flyback_current(comp, mode); 3098c2ecf20Sopenharmony_ci wcd_clsh_buck_ctrl(ctrl, mode, true); 3108c2ecf20Sopenharmony_ci } else { 3118c2ecf20Sopenharmony_ci wcd_clsh_buck_ctrl(ctrl, mode, false); 3128c2ecf20Sopenharmony_ci wcd_clsh_flyback_ctrl(ctrl, mode, false); 3138c2ecf20Sopenharmony_ci wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); 3148c2ecf20Sopenharmony_ci wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); 3158c2ecf20Sopenharmony_ci wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL); 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic void wcd_clsh_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state, 3208c2ecf20Sopenharmony_ci bool is_enable, int mode) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci struct snd_soc_component *comp = ctrl->comp; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (mode == CLS_H_NORMAL) { 3258c2ecf20Sopenharmony_ci dev_err(comp->dev, "%s: Normal mode not applicable for hph_r\n", 3268c2ecf20Sopenharmony_ci __func__); 3278c2ecf20Sopenharmony_ci return; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if (is_enable) { 3318c2ecf20Sopenharmony_ci if (mode != CLS_AB) { 3328c2ecf20Sopenharmony_ci wcd_enable_clsh_block(ctrl, true); 3338c2ecf20Sopenharmony_ci /* 3348c2ecf20Sopenharmony_ci * These K1 values depend on the Headphone Impedance 3358c2ecf20Sopenharmony_ci * For now it is assumed to be 16 ohm 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, 3388c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_CLSH_K1_MSB, 3398c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK, 3408c2ecf20Sopenharmony_ci 0x00); 3418c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, 3428c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_CLSH_K1_LSB, 3438c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK, 3448c2ecf20Sopenharmony_ci 0xC0); 3458c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, 3468c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, 3478c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, 3488c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci wcd_clsh_set_buck_regulator_mode(comp, mode); 3518c2ecf20Sopenharmony_ci wcd_clsh_set_flyback_mode(comp, mode); 3528c2ecf20Sopenharmony_ci wcd_clsh_flyback_ctrl(ctrl, mode, true); 3538c2ecf20Sopenharmony_ci wcd_clsh_set_flyback_current(comp, mode); 3548c2ecf20Sopenharmony_ci wcd_clsh_set_buck_mode(comp, mode); 3558c2ecf20Sopenharmony_ci wcd_clsh_buck_ctrl(ctrl, mode, true); 3568c2ecf20Sopenharmony_ci wcd_clsh_set_hph_mode(comp, mode); 3578c2ecf20Sopenharmony_ci wcd_clsh_set_gain_path(ctrl, mode); 3588c2ecf20Sopenharmony_ci } else { 3598c2ecf20Sopenharmony_ci wcd_clsh_set_hph_mode(comp, CLS_H_NORMAL); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (mode != CLS_AB) { 3628c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, 3638c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, 3648c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, 3658c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); 3668c2ecf20Sopenharmony_ci wcd_enable_clsh_block(ctrl, false); 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci /* buck and flyback set to default mode and disable */ 3698c2ecf20Sopenharmony_ci wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false); 3708c2ecf20Sopenharmony_ci wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false); 3718c2ecf20Sopenharmony_ci wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); 3728c2ecf20Sopenharmony_ci wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); 3738c2ecf20Sopenharmony_ci wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL); 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic void wcd_clsh_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state, 3788c2ecf20Sopenharmony_ci bool is_enable, int mode) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci struct snd_soc_component *comp = ctrl->comp; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (mode == CLS_H_NORMAL) { 3838c2ecf20Sopenharmony_ci dev_err(comp->dev, "%s: Normal mode not applicable for hph_l\n", 3848c2ecf20Sopenharmony_ci __func__); 3858c2ecf20Sopenharmony_ci return; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (is_enable) { 3898c2ecf20Sopenharmony_ci if (mode != CLS_AB) { 3908c2ecf20Sopenharmony_ci wcd_enable_clsh_block(ctrl, true); 3918c2ecf20Sopenharmony_ci /* 3928c2ecf20Sopenharmony_ci * These K1 values depend on the Headphone Impedance 3938c2ecf20Sopenharmony_ci * For now it is assumed to be 16 ohm 3948c2ecf20Sopenharmony_ci */ 3958c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, 3968c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_CLSH_K1_MSB, 3978c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK, 3988c2ecf20Sopenharmony_ci 0x00); 3998c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, 4008c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_CLSH_K1_LSB, 4018c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK, 4028c2ecf20Sopenharmony_ci 0xC0); 4038c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, 4048c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, 4058c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, 4068c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci wcd_clsh_set_buck_regulator_mode(comp, mode); 4098c2ecf20Sopenharmony_ci wcd_clsh_set_flyback_mode(comp, mode); 4108c2ecf20Sopenharmony_ci wcd_clsh_flyback_ctrl(ctrl, mode, true); 4118c2ecf20Sopenharmony_ci wcd_clsh_set_flyback_current(comp, mode); 4128c2ecf20Sopenharmony_ci wcd_clsh_set_buck_mode(comp, mode); 4138c2ecf20Sopenharmony_ci wcd_clsh_buck_ctrl(ctrl, mode, true); 4148c2ecf20Sopenharmony_ci wcd_clsh_set_hph_mode(comp, mode); 4158c2ecf20Sopenharmony_ci wcd_clsh_set_gain_path(ctrl, mode); 4168c2ecf20Sopenharmony_ci } else { 4178c2ecf20Sopenharmony_ci wcd_clsh_set_hph_mode(comp, CLS_H_NORMAL); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (mode != CLS_AB) { 4208c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, 4218c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, 4228c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, 4238c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); 4248c2ecf20Sopenharmony_ci wcd_enable_clsh_block(ctrl, false); 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci /* set buck and flyback to Default Mode */ 4278c2ecf20Sopenharmony_ci wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false); 4288c2ecf20Sopenharmony_ci wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false); 4298c2ecf20Sopenharmony_ci wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); 4308c2ecf20Sopenharmony_ci wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); 4318c2ecf20Sopenharmony_ci wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL); 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic void wcd_clsh_state_ear(struct wcd_clsh_ctrl *ctrl, int req_state, 4368c2ecf20Sopenharmony_ci bool is_enable, int mode) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci struct snd_soc_component *comp = ctrl->comp; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (mode != CLS_H_NORMAL) { 4418c2ecf20Sopenharmony_ci dev_err(comp->dev, "%s: mode: %d cannot be used for EAR\n", 4428c2ecf20Sopenharmony_ci __func__, mode); 4438c2ecf20Sopenharmony_ci return; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (is_enable) { 4478c2ecf20Sopenharmony_ci wcd_enable_clsh_block(ctrl, true); 4488c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, 4498c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, 4508c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, 4518c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE); 4528c2ecf20Sopenharmony_ci wcd_clsh_set_buck_mode(comp, mode); 4538c2ecf20Sopenharmony_ci wcd_clsh_set_flyback_mode(comp, mode); 4548c2ecf20Sopenharmony_ci wcd_clsh_flyback_ctrl(ctrl, mode, true); 4558c2ecf20Sopenharmony_ci wcd_clsh_set_flyback_current(comp, mode); 4568c2ecf20Sopenharmony_ci wcd_clsh_buck_ctrl(ctrl, mode, true); 4578c2ecf20Sopenharmony_ci } else { 4588c2ecf20Sopenharmony_ci snd_soc_component_update_bits(comp, 4598c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, 4608c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK, 4618c2ecf20Sopenharmony_ci WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE); 4628c2ecf20Sopenharmony_ci wcd_enable_clsh_block(ctrl, false); 4638c2ecf20Sopenharmony_ci wcd_clsh_buck_ctrl(ctrl, mode, false); 4648c2ecf20Sopenharmony_ci wcd_clsh_flyback_ctrl(ctrl, mode, false); 4658c2ecf20Sopenharmony_ci wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL); 4668c2ecf20Sopenharmony_ci wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL); 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic int _wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, int req_state, 4718c2ecf20Sopenharmony_ci bool is_enable, int mode) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci switch (req_state) { 4748c2ecf20Sopenharmony_ci case WCD_CLSH_STATE_EAR: 4758c2ecf20Sopenharmony_ci wcd_clsh_state_ear(ctrl, req_state, is_enable, mode); 4768c2ecf20Sopenharmony_ci break; 4778c2ecf20Sopenharmony_ci case WCD_CLSH_STATE_HPHL: 4788c2ecf20Sopenharmony_ci wcd_clsh_state_hph_l(ctrl, req_state, is_enable, mode); 4798c2ecf20Sopenharmony_ci break; 4808c2ecf20Sopenharmony_ci case WCD_CLSH_STATE_HPHR: 4818c2ecf20Sopenharmony_ci wcd_clsh_state_hph_r(ctrl, req_state, is_enable, mode); 4828c2ecf20Sopenharmony_ci break; 4838c2ecf20Sopenharmony_ci break; 4848c2ecf20Sopenharmony_ci case WCD_CLSH_STATE_LO: 4858c2ecf20Sopenharmony_ci wcd_clsh_state_lo(ctrl, req_state, is_enable, mode); 4868c2ecf20Sopenharmony_ci break; 4878c2ecf20Sopenharmony_ci default: 4888c2ecf20Sopenharmony_ci break; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci return 0; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci/* 4958c2ecf20Sopenharmony_ci * Function: wcd_clsh_is_state_valid 4968c2ecf20Sopenharmony_ci * Params: state 4978c2ecf20Sopenharmony_ci * Description: 4988c2ecf20Sopenharmony_ci * Provides information on valid states of Class H configuration 4998c2ecf20Sopenharmony_ci */ 5008c2ecf20Sopenharmony_cistatic bool wcd_clsh_is_state_valid(int state) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci switch (state) { 5038c2ecf20Sopenharmony_ci case WCD_CLSH_STATE_IDLE: 5048c2ecf20Sopenharmony_ci case WCD_CLSH_STATE_EAR: 5058c2ecf20Sopenharmony_ci case WCD_CLSH_STATE_HPHL: 5068c2ecf20Sopenharmony_ci case WCD_CLSH_STATE_HPHR: 5078c2ecf20Sopenharmony_ci case WCD_CLSH_STATE_LO: 5088c2ecf20Sopenharmony_ci return true; 5098c2ecf20Sopenharmony_ci default: 5108c2ecf20Sopenharmony_ci return false; 5118c2ecf20Sopenharmony_ci }; 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci/* 5158c2ecf20Sopenharmony_ci * Function: wcd_clsh_fsm 5168c2ecf20Sopenharmony_ci * Params: ctrl, req_state, req_type, clsh_event 5178c2ecf20Sopenharmony_ci * Description: 5188c2ecf20Sopenharmony_ci * This function handles PRE DAC and POST DAC conditions of different devices 5198c2ecf20Sopenharmony_ci * and updates class H configuration of different combination of devices 5208c2ecf20Sopenharmony_ci * based on validity of their states. ctrl will contain current 5218c2ecf20Sopenharmony_ci * class h state information 5228c2ecf20Sopenharmony_ci */ 5238c2ecf20Sopenharmony_ciint wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, 5248c2ecf20Sopenharmony_ci enum wcd_clsh_event clsh_event, 5258c2ecf20Sopenharmony_ci int nstate, 5268c2ecf20Sopenharmony_ci enum wcd_clsh_mode mode) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci struct snd_soc_component *comp = ctrl->comp; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if (nstate == ctrl->state) 5318c2ecf20Sopenharmony_ci return 0; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (!wcd_clsh_is_state_valid(nstate)) { 5348c2ecf20Sopenharmony_ci dev_err(comp->dev, "Class-H not a valid new state:\n"); 5358c2ecf20Sopenharmony_ci return -EINVAL; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci switch (clsh_event) { 5398c2ecf20Sopenharmony_ci case WCD_CLSH_EVENT_PRE_DAC: 5408c2ecf20Sopenharmony_ci _wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_ENABLE, mode); 5418c2ecf20Sopenharmony_ci break; 5428c2ecf20Sopenharmony_ci case WCD_CLSH_EVENT_POST_PA: 5438c2ecf20Sopenharmony_ci _wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_DISABLE, mode); 5448c2ecf20Sopenharmony_ci break; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci ctrl->state = nstate; 5488c2ecf20Sopenharmony_ci ctrl->mode = mode; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci return 0; 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ciint wcd_clsh_ctrl_get_state(struct wcd_clsh_ctrl *ctrl) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci return ctrl->state; 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_cistruct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc(struct snd_soc_component *comp, 5598c2ecf20Sopenharmony_ci int version) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci struct wcd_clsh_ctrl *ctrl; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); 5648c2ecf20Sopenharmony_ci if (!ctrl) 5658c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci ctrl->state = WCD_CLSH_STATE_IDLE; 5688c2ecf20Sopenharmony_ci ctrl->comp = comp; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci return ctrl; 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_civoid wcd_clsh_ctrl_free(struct wcd_clsh_ctrl *ctrl) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci kfree(ctrl); 5768c2ecf20Sopenharmony_ci} 577