1*10f514bdSNeil Armstrong // SPDX-License-Identifier: GPL-2.0-only 2*10f514bdSNeil Armstrong /* 3*10f514bdSNeil Armstrong * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. 4*10f514bdSNeil Armstrong * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. 5*10f514bdSNeil Armstrong * Copyright (c) 2023, Linaro Limited 6*10f514bdSNeil Armstrong */ 7*10f514bdSNeil Armstrong 8*10f514bdSNeil Armstrong #include <linux/module.h> 9*10f514bdSNeil Armstrong #include <linux/slab.h> 10*10f514bdSNeil Armstrong #include <linux/platform_device.h> 11*10f514bdSNeil Armstrong #include <linux/device.h> 12*10f514bdSNeil Armstrong #include <linux/delay.h> 13*10f514bdSNeil Armstrong #include <linux/gpio/consumer.h> 14*10f514bdSNeil Armstrong #include <linux/kernel.h> 15*10f514bdSNeil Armstrong #include <linux/pm_runtime.h> 16*10f514bdSNeil Armstrong #include <linux/component.h> 17*10f514bdSNeil Armstrong #include <sound/tlv.h> 18*10f514bdSNeil Armstrong #include <linux/of_gpio.h> 19*10f514bdSNeil Armstrong #include <linux/of_graph.h> 20*10f514bdSNeil Armstrong #include <linux/of.h> 21*10f514bdSNeil Armstrong #include <sound/jack.h> 22*10f514bdSNeil Armstrong #include <sound/pcm.h> 23*10f514bdSNeil Armstrong #include <sound/pcm_params.h> 24*10f514bdSNeil Armstrong #include <linux/regmap.h> 25*10f514bdSNeil Armstrong #include <sound/soc.h> 26*10f514bdSNeil Armstrong #include <sound/soc-dapm.h> 27*10f514bdSNeil Armstrong #include <linux/regulator/consumer.h> 28*10f514bdSNeil Armstrong #include <linux/usb/typec_mux.h> 29*10f514bdSNeil Armstrong #include <linux/usb/typec_altmode.h> 30*10f514bdSNeil Armstrong 31*10f514bdSNeil Armstrong #include "wcd-clsh-v2.h" 32*10f514bdSNeil Armstrong #include "wcd-mbhc-v2.h" 33*10f514bdSNeil Armstrong #include "wcd939x.h" 34*10f514bdSNeil Armstrong 35*10f514bdSNeil Armstrong #define WCD939X_MAX_MICBIAS (4) 36*10f514bdSNeil Armstrong #define WCD939X_MAX_SUPPLY (4) 37*10f514bdSNeil Armstrong #define WCD939X_MBHC_MAX_BUTTONS (8) 38*10f514bdSNeil Armstrong #define TX_ADC_MAX (4) 39*10f514bdSNeil Armstrong #define WCD_MBHC_HS_V_MAX 1600 40*10f514bdSNeil Armstrong 41*10f514bdSNeil Armstrong enum { 42*10f514bdSNeil Armstrong WCD939X_VERSION_1_0 = 0, 43*10f514bdSNeil Armstrong WCD939X_VERSION_1_1, 44*10f514bdSNeil Armstrong WCD939X_VERSION_2_0, 45*10f514bdSNeil Armstrong }; 46*10f514bdSNeil Armstrong 47*10f514bdSNeil Armstrong #define WCD939X_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ 48*10f514bdSNeil Armstrong SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ 49*10f514bdSNeil Armstrong SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\ 50*10f514bdSNeil Armstrong SNDRV_PCM_RATE_384000) 51*10f514bdSNeil Armstrong /* Fractional Rates */ 52*10f514bdSNeil Armstrong #define WCD939X_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\ 53*10f514bdSNeil Armstrong SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800) 54*10f514bdSNeil Armstrong #define WCD939X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ 55*10f514bdSNeil Armstrong SNDRV_PCM_FMTBIT_S24_LE |\ 56*10f514bdSNeil Armstrong SNDRV_PCM_FMTBIT_S24_3LE |\ 57*10f514bdSNeil Armstrong SNDRV_PCM_FMTBIT_S32_LE) 58*10f514bdSNeil Armstrong 59*10f514bdSNeil Armstrong /* Convert from vout ctl to micbias voltage in mV */ 60*10f514bdSNeil Armstrong #define WCD_VOUT_CTL_TO_MICB(v) (1000 + (v) * 50) 61*10f514bdSNeil Armstrong #define SWR_CLK_RATE_0P6MHZ (600000) 62*10f514bdSNeil Armstrong #define SWR_CLK_RATE_1P2MHZ (1200000) 63*10f514bdSNeil Armstrong #define SWR_CLK_RATE_2P4MHZ (2400000) 64*10f514bdSNeil Armstrong #define SWR_CLK_RATE_4P8MHZ (4800000) 65*10f514bdSNeil Armstrong #define SWR_CLK_RATE_9P6MHZ (9600000) 66*10f514bdSNeil Armstrong #define SWR_CLK_RATE_11P2896MHZ (1128960) 67*10f514bdSNeil Armstrong 68*10f514bdSNeil Armstrong #define ADC_MODE_VAL_HIFI 0x01 69*10f514bdSNeil Armstrong #define ADC_MODE_VAL_LO_HIF 0x02 70*10f514bdSNeil Armstrong #define ADC_MODE_VAL_NORMAL 0x03 71*10f514bdSNeil Armstrong #define ADC_MODE_VAL_LP 0x05 72*10f514bdSNeil Armstrong #define ADC_MODE_VAL_ULP1 0x09 73*10f514bdSNeil Armstrong #define ADC_MODE_VAL_ULP2 0x0B 74*10f514bdSNeil Armstrong 75*10f514bdSNeil Armstrong /* Z value defined in milliohm */ 76*10f514bdSNeil Armstrong #define WCD939X_ZDET_VAL_32 (32000) 77*10f514bdSNeil Armstrong #define WCD939X_ZDET_VAL_400 (400000) 78*10f514bdSNeil Armstrong #define WCD939X_ZDET_VAL_1200 (1200000) 79*10f514bdSNeil Armstrong #define WCD939X_ZDET_VAL_100K (100000000) 80*10f514bdSNeil Armstrong 81*10f514bdSNeil Armstrong /* Z floating defined in ohms */ 82*10f514bdSNeil Armstrong #define WCD939X_ZDET_FLOATING_IMPEDANCE (0x0FFFFFFE) 83*10f514bdSNeil Armstrong #define WCD939X_ZDET_NUM_MEASUREMENTS (900) 84*10f514bdSNeil Armstrong #define WCD939X_MBHC_GET_C1(c) (((c) & 0xC000) >> 14) 85*10f514bdSNeil Armstrong #define WCD939X_MBHC_GET_X1(x) ((x) & 0x3FFF) 86*10f514bdSNeil Armstrong 87*10f514bdSNeil Armstrong /* Z value compared in milliOhm */ 88*10f514bdSNeil Armstrong #define WCD939X_MBHC_IS_SECOND_RAMP_REQUIRED(z) false 89*10f514bdSNeil Armstrong #define WCD939X_ANA_MBHC_ZDET_CONST (1018 * 1024) 90*10f514bdSNeil Armstrong 91*10f514bdSNeil Armstrong enum { 92*10f514bdSNeil Armstrong WCD9390 = 0, 93*10f514bdSNeil Armstrong WCD9395 = 5, 94*10f514bdSNeil Armstrong }; 95*10f514bdSNeil Armstrong 96*10f514bdSNeil Armstrong enum { 97*10f514bdSNeil Armstrong /* INTR_CTRL_INT_MASK_0 */ 98*10f514bdSNeil Armstrong WCD939X_IRQ_MBHC_BUTTON_PRESS_DET = 0, 99*10f514bdSNeil Armstrong WCD939X_IRQ_MBHC_BUTTON_RELEASE_DET, 100*10f514bdSNeil Armstrong WCD939X_IRQ_MBHC_ELECT_INS_REM_DET, 101*10f514bdSNeil Armstrong WCD939X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 102*10f514bdSNeil Armstrong WCD939X_IRQ_MBHC_SW_DET, 103*10f514bdSNeil Armstrong WCD939X_IRQ_HPHR_OCP_INT, 104*10f514bdSNeil Armstrong WCD939X_IRQ_HPHR_CNP_INT, 105*10f514bdSNeil Armstrong WCD939X_IRQ_HPHL_OCP_INT, 106*10f514bdSNeil Armstrong 107*10f514bdSNeil Armstrong /* INTR_CTRL_INT_MASK_1 */ 108*10f514bdSNeil Armstrong WCD939X_IRQ_HPHL_CNP_INT, 109*10f514bdSNeil Armstrong WCD939X_IRQ_EAR_CNP_INT, 110*10f514bdSNeil Armstrong WCD939X_IRQ_EAR_SCD_INT, 111*10f514bdSNeil Armstrong WCD939X_IRQ_HPHL_PDM_WD_INT, 112*10f514bdSNeil Armstrong WCD939X_IRQ_HPHR_PDM_WD_INT, 113*10f514bdSNeil Armstrong WCD939X_IRQ_EAR_PDM_WD_INT, 114*10f514bdSNeil Armstrong 115*10f514bdSNeil Armstrong /* INTR_CTRL_INT_MASK_2 */ 116*10f514bdSNeil Armstrong WCD939X_IRQ_MBHC_MOISTURE_INT, 117*10f514bdSNeil Armstrong WCD939X_IRQ_HPHL_SURGE_DET_INT, 118*10f514bdSNeil Armstrong WCD939X_IRQ_HPHR_SURGE_DET_INT, 119*10f514bdSNeil Armstrong WCD939X_NUM_IRQS, 120*10f514bdSNeil Armstrong }; 121*10f514bdSNeil Armstrong 122*10f514bdSNeil Armstrong enum { 123*10f514bdSNeil Armstrong MICB_BIAS_DISABLE = 0, 124*10f514bdSNeil Armstrong MICB_BIAS_ENABLE, 125*10f514bdSNeil Armstrong MICB_BIAS_PULL_UP, 126*10f514bdSNeil Armstrong MICB_BIAS_PULL_DOWN, 127*10f514bdSNeil Armstrong }; 128*10f514bdSNeil Armstrong 129*10f514bdSNeil Armstrong enum { 130*10f514bdSNeil Armstrong WCD_ADC1 = 0, 131*10f514bdSNeil Armstrong WCD_ADC2, 132*10f514bdSNeil Armstrong WCD_ADC3, 133*10f514bdSNeil Armstrong WCD_ADC4, 134*10f514bdSNeil Armstrong HPH_PA_DELAY, 135*10f514bdSNeil Armstrong }; 136*10f514bdSNeil Armstrong 137*10f514bdSNeil Armstrong enum { 138*10f514bdSNeil Armstrong ADC_MODE_INVALID = 0, 139*10f514bdSNeil Armstrong ADC_MODE_HIFI, 140*10f514bdSNeil Armstrong ADC_MODE_LO_HIF, 141*10f514bdSNeil Armstrong ADC_MODE_NORMAL, 142*10f514bdSNeil Armstrong ADC_MODE_LP, 143*10f514bdSNeil Armstrong ADC_MODE_ULP1, 144*10f514bdSNeil Armstrong ADC_MODE_ULP2, 145*10f514bdSNeil Armstrong }; 146*10f514bdSNeil Armstrong 147*10f514bdSNeil Armstrong enum { 148*10f514bdSNeil Armstrong AIF1_PB = 0, 149*10f514bdSNeil Armstrong AIF1_CAP, 150*10f514bdSNeil Armstrong NUM_CODEC_DAIS, 151*10f514bdSNeil Armstrong }; 152*10f514bdSNeil Armstrong 153*10f514bdSNeil Armstrong static u8 tx_mode_bit[] = { 154*10f514bdSNeil Armstrong [ADC_MODE_INVALID] = 0x00, 155*10f514bdSNeil Armstrong [ADC_MODE_HIFI] = 0x01, 156*10f514bdSNeil Armstrong [ADC_MODE_LO_HIF] = 0x02, 157*10f514bdSNeil Armstrong [ADC_MODE_NORMAL] = 0x04, 158*10f514bdSNeil Armstrong [ADC_MODE_LP] = 0x08, 159*10f514bdSNeil Armstrong [ADC_MODE_ULP1] = 0x10, 160*10f514bdSNeil Armstrong [ADC_MODE_ULP2] = 0x20, 161*10f514bdSNeil Armstrong }; 162*10f514bdSNeil Armstrong 163*10f514bdSNeil Armstrong struct zdet_param { 164*10f514bdSNeil Armstrong u16 ldo_ctl; 165*10f514bdSNeil Armstrong u16 noff; 166*10f514bdSNeil Armstrong u16 nshift; 167*10f514bdSNeil Armstrong u16 btn5; 168*10f514bdSNeil Armstrong u16 btn6; 169*10f514bdSNeil Armstrong u16 btn7; 170*10f514bdSNeil Armstrong }; 171*10f514bdSNeil Armstrong 172*10f514bdSNeil Armstrong struct wcd939x_priv { 173*10f514bdSNeil Armstrong struct sdw_slave *tx_sdw_dev; 174*10f514bdSNeil Armstrong struct wcd939x_sdw_priv *sdw_priv[NUM_CODEC_DAIS]; 175*10f514bdSNeil Armstrong struct device *txdev; 176*10f514bdSNeil Armstrong struct device *rxdev; 177*10f514bdSNeil Armstrong struct device_node *rxnode, *txnode; 178*10f514bdSNeil Armstrong struct regmap *regmap; 179*10f514bdSNeil Armstrong struct snd_soc_component *component; 180*10f514bdSNeil Armstrong /* micb setup lock */ 181*10f514bdSNeil Armstrong struct mutex micb_lock; 182*10f514bdSNeil Armstrong /* typec handling */ 183*10f514bdSNeil Armstrong bool typec_analog_mux; 184*10f514bdSNeil Armstrong #if IS_ENABLED(CONFIG_TYPEC) 185*10f514bdSNeil Armstrong struct typec_mux_dev *typec_mux; 186*10f514bdSNeil Armstrong struct typec_switch_dev *typec_sw; 187*10f514bdSNeil Armstrong enum typec_orientation typec_orientation; 188*10f514bdSNeil Armstrong unsigned long typec_mode; 189*10f514bdSNeil Armstrong struct typec_switch *typec_switch; 190*10f514bdSNeil Armstrong #endif /* CONFIG_TYPEC */ 191*10f514bdSNeil Armstrong /* mbhc module */ 192*10f514bdSNeil Armstrong struct wcd_mbhc *wcd_mbhc; 193*10f514bdSNeil Armstrong struct wcd_mbhc_config mbhc_cfg; 194*10f514bdSNeil Armstrong struct wcd_mbhc_intr intr_ids; 195*10f514bdSNeil Armstrong struct wcd_clsh_ctrl *clsh_info; 196*10f514bdSNeil Armstrong struct irq_domain *virq; 197*10f514bdSNeil Armstrong struct regmap_irq_chip *wcd_regmap_irq_chip; 198*10f514bdSNeil Armstrong struct regmap_irq_chip_data *irq_chip; 199*10f514bdSNeil Armstrong struct regulator_bulk_data supplies[WCD939X_MAX_SUPPLY]; 200*10f514bdSNeil Armstrong struct snd_soc_jack *jack; 201*10f514bdSNeil Armstrong unsigned long status_mask; 202*10f514bdSNeil Armstrong s32 micb_ref[WCD939X_MAX_MICBIAS]; 203*10f514bdSNeil Armstrong s32 pullup_ref[WCD939X_MAX_MICBIAS]; 204*10f514bdSNeil Armstrong u32 hph_mode; 205*10f514bdSNeil Armstrong u32 tx_mode[TX_ADC_MAX]; 206*10f514bdSNeil Armstrong int variant; 207*10f514bdSNeil Armstrong int reset_gpio; 208*10f514bdSNeil Armstrong u32 micb1_mv; 209*10f514bdSNeil Armstrong u32 micb2_mv; 210*10f514bdSNeil Armstrong u32 micb3_mv; 211*10f514bdSNeil Armstrong u32 micb4_mv; 212*10f514bdSNeil Armstrong int hphr_pdm_wd_int; 213*10f514bdSNeil Armstrong int hphl_pdm_wd_int; 214*10f514bdSNeil Armstrong int ear_pdm_wd_int; 215*10f514bdSNeil Armstrong bool comp1_enable; 216*10f514bdSNeil Armstrong bool comp2_enable; 217*10f514bdSNeil Armstrong bool ldoh; 218*10f514bdSNeil Armstrong }; 219*10f514bdSNeil Armstrong 220*10f514bdSNeil Armstrong static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800); 221*10f514bdSNeil Armstrong static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); 222*10f514bdSNeil Armstrong static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); 223*10f514bdSNeil Armstrong 224*10f514bdSNeil Armstrong static struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = { 225*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD939X_ANA_MBHC_MECH, 0x80), 226*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD939X_ANA_MBHC_MECH, 0x40), 227*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD939X_ANA_MBHC_MECH, 0x20), 228*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_MIC_CLAMP_CTL, WCD939X_MBHC_NEW_PLUG_DETECT_CTL, 0x30), 229*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_ELECT_DETECTION_TYPE, WCD939X_ANA_MBHC_ELECT, 0x08), 230*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_CTRL, WCD939X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x1F), 231*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, WCD939X_ANA_MBHC_MECH, 0x04), 232*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHL_PLUG_TYPE, WCD939X_ANA_MBHC_MECH, 0x10), 233*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_GND_PLUG_TYPE, WCD939X_ANA_MBHC_MECH, 0x08), 234*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_SW_HPH_LP_100K_TO_GND, WCD939X_ANA_MBHC_MECH, 0x01), 235*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_ELECT_SCHMT_ISRC, WCD939X_ANA_MBHC_ELECT, 0x06), 236*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_FSM_EN, WCD939X_ANA_MBHC_ELECT, 0x80), 237*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_INSREM_DBNC, WCD939X_MBHC_NEW_PLUG_DETECT_CTL, 0x0F), 238*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_BTN_DBNC, WCD939X_MBHC_NEW_CTL_1, 0x03), 239*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HS_VREF, WCD939X_MBHC_NEW_CTL_2, 0x03), 240*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HS_COMP_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0x08), 241*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_IN2P_CLAMP_STATE, WCD939X_ANA_MBHC_RESULT_3, 0x10), 242*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_MIC_SCHMT_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0x20), 243*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHL_SCHMT_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0x80), 244*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHR_SCHMT_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0x40), 245*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_OCP_FSM_EN, WCD939X_HPH_OCP_CTL, 0x10), 246*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_BTN_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0x07), 247*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_BTN_ISRC_CTL, WCD939X_ANA_MBHC_ELECT, 0x70), 248*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_ELECT_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0xFF), 249*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_MICB_CTRL, WCD939X_ANA_MICB2, 0xC0), 250*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPH_CNP_WG_TIME, WCD939X_HPH_CNP_WG_TIME, 0xFF), 251*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHR_PA_EN, WCD939X_ANA_HPH, 0x40), 252*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHL_PA_EN, WCD939X_ANA_HPH, 0x80), 253*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPH_PA_EN, WCD939X_ANA_HPH, 0xC0), 254*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_SWCH_LEVEL_REMOVE, WCD939X_ANA_MBHC_RESULT_3, 0x10), 255*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_ANC_DET_EN, WCD939X_MBHC_CTL_BCS, 0x02), 256*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_FSM_STATUS, WCD939X_MBHC_NEW_FSM_STATUS, 0x01), 257*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_MUX_CTL, WCD939X_MBHC_NEW_CTL_2, 0x70), 258*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_MOISTURE_STATUS, WCD939X_MBHC_NEW_FSM_STATUS, 0x20), 259*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHR_GND, WCD939X_HPH_PA_CTL2, 0x40), 260*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHL_GND, WCD939X_HPH_PA_CTL2, 0x10), 261*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_DET_EN, WCD939X_HPH_L_TEST, 0x01), 262*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_DET_EN, WCD939X_HPH_R_TEST, 0x01), 263*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_STATUS, WCD939X_DIGITAL_INTR_STATUS_0, 0x80), 264*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_STATUS, WCD939X_DIGITAL_INTR_STATUS_0, 0x20), 265*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_ADC_EN, WCD939X_MBHC_NEW_CTL_1, 0x08), 266*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_ADC_COMPLETE, WCD939X_MBHC_NEW_FSM_STATUS, 0x40), 267*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_ADC_TIMEOUT, WCD939X_MBHC_NEW_FSM_STATUS, 0x80), 268*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_ADC_RESULT, WCD939X_MBHC_NEW_ADC_RESULT, 0xFF), 269*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_MICB2_VOUT, WCD939X_ANA_MICB2, 0x3F), 270*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_ADC_MODE, WCD939X_MBHC_NEW_CTL_1, 0x10), 271*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_DETECTION_DONE, WCD939X_MBHC_NEW_CTL_1, 0x04), 272*10f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_ELECT_ISRC_EN, WCD939X_ANA_MBHC_ZDET, 0x02), 273*10f514bdSNeil Armstrong }; 274*10f514bdSNeil Armstrong 275*10f514bdSNeil Armstrong static const struct regmap_irq wcd939x_irqs[WCD939X_NUM_IRQS] = { 276*10f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_BUTTON_PRESS_DET, 0, 0x01), 277*10f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_BUTTON_RELEASE_DET, 0, 0x02), 278*10f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_ELECT_INS_REM_DET, 0, 0x04), 279*10f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 0, 0x08), 280*10f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_SW_DET, 0, 0x10), 281*10f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_OCP_INT, 0, 0x20), 282*10f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_CNP_INT, 0, 0x40), 283*10f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_HPHL_OCP_INT, 0, 0x80), 284*10f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_HPHL_CNP_INT, 1, 0x01), 285*10f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_EAR_CNP_INT, 1, 0x02), 286*10f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_EAR_SCD_INT, 1, 0x04), 287*10f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_HPHL_PDM_WD_INT, 1, 0x20), 288*10f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_PDM_WD_INT, 1, 0x40), 289*10f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_EAR_PDM_WD_INT, 1, 0x80), 290*10f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_MOISTURE_INT, 2, 0x02), 291*10f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_HPHL_SURGE_DET_INT, 2, 0x04), 292*10f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_SURGE_DET_INT, 2, 0x08), 293*10f514bdSNeil Armstrong }; 294*10f514bdSNeil Armstrong 295*10f514bdSNeil Armstrong static struct regmap_irq_chip wcd939x_regmap_irq_chip = { 296*10f514bdSNeil Armstrong .name = "wcd939x", 297*10f514bdSNeil Armstrong .irqs = wcd939x_irqs, 298*10f514bdSNeil Armstrong .num_irqs = ARRAY_SIZE(wcd939x_irqs), 299*10f514bdSNeil Armstrong .num_regs = 3, 300*10f514bdSNeil Armstrong .status_base = WCD939X_DIGITAL_INTR_STATUS_0, 301*10f514bdSNeil Armstrong .mask_base = WCD939X_DIGITAL_INTR_MASK_0, 302*10f514bdSNeil Armstrong .ack_base = WCD939X_DIGITAL_INTR_CLEAR_0, 303*10f514bdSNeil Armstrong .use_ack = 1, 304*10f514bdSNeil Armstrong .runtime_pm = true, 305*10f514bdSNeil Armstrong .irq_drv_data = NULL, 306*10f514bdSNeil Armstrong }; 307*10f514bdSNeil Armstrong 308*10f514bdSNeil Armstrong static int wcd939x_get_clk_rate(int mode) 309*10f514bdSNeil Armstrong { 310*10f514bdSNeil Armstrong int rate; 311*10f514bdSNeil Armstrong 312*10f514bdSNeil Armstrong switch (mode) { 313*10f514bdSNeil Armstrong case ADC_MODE_ULP2: 314*10f514bdSNeil Armstrong rate = SWR_CLK_RATE_0P6MHZ; 315*10f514bdSNeil Armstrong break; 316*10f514bdSNeil Armstrong case ADC_MODE_ULP1: 317*10f514bdSNeil Armstrong rate = SWR_CLK_RATE_1P2MHZ; 318*10f514bdSNeil Armstrong break; 319*10f514bdSNeil Armstrong case ADC_MODE_LP: 320*10f514bdSNeil Armstrong rate = SWR_CLK_RATE_4P8MHZ; 321*10f514bdSNeil Armstrong break; 322*10f514bdSNeil Armstrong case ADC_MODE_NORMAL: 323*10f514bdSNeil Armstrong case ADC_MODE_LO_HIF: 324*10f514bdSNeil Armstrong case ADC_MODE_HIFI: 325*10f514bdSNeil Armstrong case ADC_MODE_INVALID: 326*10f514bdSNeil Armstrong default: 327*10f514bdSNeil Armstrong rate = SWR_CLK_RATE_9P6MHZ; 328*10f514bdSNeil Armstrong break; 329*10f514bdSNeil Armstrong } 330*10f514bdSNeil Armstrong 331*10f514bdSNeil Armstrong return rate; 332*10f514bdSNeil Armstrong } 333*10f514bdSNeil Armstrong 334*10f514bdSNeil Armstrong static int wcd939x_set_swr_clk_rate(struct snd_soc_component *component, int rate, int bank) 335*10f514bdSNeil Armstrong { 336*10f514bdSNeil Armstrong u8 mask = (bank ? 0xF0 : 0x0F); 337*10f514bdSNeil Armstrong u8 val = 0; 338*10f514bdSNeil Armstrong 339*10f514bdSNeil Armstrong switch (rate) { 340*10f514bdSNeil Armstrong case SWR_CLK_RATE_0P6MHZ: 341*10f514bdSNeil Armstrong val = 6; 342*10f514bdSNeil Armstrong break; 343*10f514bdSNeil Armstrong case SWR_CLK_RATE_1P2MHZ: 344*10f514bdSNeil Armstrong val = 5; 345*10f514bdSNeil Armstrong break; 346*10f514bdSNeil Armstrong case SWR_CLK_RATE_2P4MHZ: 347*10f514bdSNeil Armstrong val = 3; 348*10f514bdSNeil Armstrong break; 349*10f514bdSNeil Armstrong case SWR_CLK_RATE_4P8MHZ: 350*10f514bdSNeil Armstrong val = 1; 351*10f514bdSNeil Armstrong break; 352*10f514bdSNeil Armstrong case SWR_CLK_RATE_9P6MHZ: 353*10f514bdSNeil Armstrong default: 354*10f514bdSNeil Armstrong val = 0; 355*10f514bdSNeil Armstrong break; 356*10f514bdSNeil Armstrong } 357*10f514bdSNeil Armstrong 358*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_SWR_TX_CLK_RATE, mask, val); 359*10f514bdSNeil Armstrong 360*10f514bdSNeil Armstrong return 0; 361*10f514bdSNeil Armstrong } 362*10f514bdSNeil Armstrong 363*10f514bdSNeil Armstrong static int wcd939x_io_init(struct snd_soc_component *component) 364*10f514bdSNeil Armstrong { 365*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_BIAS, 366*10f514bdSNeil Armstrong WCD939X_BIAS_ANALOG_BIAS_EN, true); 367*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_BIAS, 368*10f514bdSNeil Armstrong WCD939X_BIAS_PRECHRG_EN, true); 369*10f514bdSNeil Armstrong 370*10f514bdSNeil Armstrong /* 10 msec delay as per HW requirement */ 371*10f514bdSNeil Armstrong usleep_range(10000, 10010); 372*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_BIAS, 373*10f514bdSNeil Armstrong WCD939X_BIAS_PRECHRG_EN, false); 374*10f514bdSNeil Armstrong 375*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_L, 376*10f514bdSNeil Armstrong WCD939X_RDAC_HD2_CTL_L_HD2_RES_DIV_CTL_L, 0x15); 377*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_R, 378*10f514bdSNeil Armstrong WCD939X_RDAC_HD2_CTL_R_HD2_RES_DIV_CTL_R, 0x15); 379*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DMIC_CTL, 380*10f514bdSNeil Armstrong WCD939X_CDC_DMIC_CTL_CLK_SCALE_EN, true); 381*10f514bdSNeil Armstrong 382*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2CASC_ULP, 383*10f514bdSNeil Armstrong WCD939X_FE_ICTRL_STG2CASC_ULP_ICTRL_SCBIAS_ULP0P6M, 1); 384*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2CASC_ULP, 385*10f514bdSNeil Armstrong WCD939X_FE_ICTRL_STG2CASC_ULP_VALUE, 4); 386*10f514bdSNeil Armstrong 387*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_ULP, 388*10f514bdSNeil Armstrong WCD939X_FE_ICTRL_STG2MAIN_ULP_VALUE, 8); 389*10f514bdSNeil Armstrong 390*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MICB1_TEST_CTL_1, 391*10f514bdSNeil Armstrong WCD939X_TEST_CTL_1_NOISE_FILT_RES_VAL, 7); 392*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MICB2_TEST_CTL_1, 393*10f514bdSNeil Armstrong WCD939X_TEST_CTL_1_NOISE_FILT_RES_VAL, 7); 394*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MICB3_TEST_CTL_1, 395*10f514bdSNeil Armstrong WCD939X_TEST_CTL_1_NOISE_FILT_RES_VAL, 7); 396*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MICB4_TEST_CTL_1, 397*10f514bdSNeil Armstrong WCD939X_TEST_CTL_1_NOISE_FILT_RES_VAL, 7); 398*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_TX_3_4_TEST_BLK_EN2, 399*10f514bdSNeil Armstrong WCD939X_TEST_BLK_EN2_TXFE2_MBHC_CLKRST_EN, false); 400*10f514bdSNeil Armstrong 401*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN, 402*10f514bdSNeil Armstrong WCD939X_EN_EN_SURGE_PROTECTION_HPHL, false); 403*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN, 404*10f514bdSNeil Armstrong WCD939X_EN_EN_SURGE_PROTECTION_HPHR, false); 405*10f514bdSNeil Armstrong 406*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_OCP_CTL, 407*10f514bdSNeil Armstrong WCD939X_OCP_CTL_OCP_FSM_EN, true); 408*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_OCP_CTL, 409*10f514bdSNeil Armstrong WCD939X_OCP_CTL_SCD_OP_EN, true); 410*10f514bdSNeil Armstrong 411*10f514bdSNeil Armstrong snd_soc_component_write(component, WCD939X_E_CFG0, 412*10f514bdSNeil Armstrong WCD939X_CFG0_IDLE_STEREO | 413*10f514bdSNeil Armstrong WCD939X_CFG0_AUTO_DISABLE_ANC); 414*10f514bdSNeil Armstrong 415*10f514bdSNeil Armstrong return 0; 416*10f514bdSNeil Armstrong } 417*10f514bdSNeil Armstrong 418*10f514bdSNeil Armstrong static int wcd939x_sdw_connect_port(struct wcd939x_sdw_ch_info *ch_info, 419*10f514bdSNeil Armstrong struct sdw_port_config *port_config, 420*10f514bdSNeil Armstrong u8 enable) 421*10f514bdSNeil Armstrong { 422*10f514bdSNeil Armstrong u8 ch_mask, port_num; 423*10f514bdSNeil Armstrong 424*10f514bdSNeil Armstrong port_num = ch_info->port_num; 425*10f514bdSNeil Armstrong ch_mask = ch_info->ch_mask; 426*10f514bdSNeil Armstrong 427*10f514bdSNeil Armstrong port_config->num = port_num; 428*10f514bdSNeil Armstrong 429*10f514bdSNeil Armstrong if (enable) 430*10f514bdSNeil Armstrong port_config->ch_mask |= ch_mask; 431*10f514bdSNeil Armstrong else 432*10f514bdSNeil Armstrong port_config->ch_mask &= ~ch_mask; 433*10f514bdSNeil Armstrong 434*10f514bdSNeil Armstrong return 0; 435*10f514bdSNeil Armstrong } 436*10f514bdSNeil Armstrong 437*10f514bdSNeil Armstrong static int wcd939x_connect_port(struct wcd939x_sdw_priv *wcd, u8 port_num, u8 ch_id, u8 enable) 438*10f514bdSNeil Armstrong { 439*10f514bdSNeil Armstrong return wcd939x_sdw_connect_port(&wcd->ch_info[ch_id], 440*10f514bdSNeil Armstrong &wcd->port_config[port_num - 1], 441*10f514bdSNeil Armstrong enable); 442*10f514bdSNeil Armstrong } 443*10f514bdSNeil Armstrong 444*10f514bdSNeil Armstrong static int wcd939x_codec_enable_rxclk(struct snd_soc_dapm_widget *w, 445*10f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, 446*10f514bdSNeil Armstrong int event) 447*10f514bdSNeil Armstrong { 448*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 449*10f514bdSNeil Armstrong 450*10f514bdSNeil Armstrong switch (event) { 451*10f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 452*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES, 453*10f514bdSNeil Armstrong WCD939X_RX_SUPPLIES_RX_BIAS_ENABLE, true); 454*10f514bdSNeil Armstrong 455*10f514bdSNeil Armstrong /* Analog path clock controls */ 456*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 457*10f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_RX_CLK_EN, true); 458*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 459*10f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV2_CLK_EN, 460*10f514bdSNeil Armstrong true); 461*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 462*10f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV4_CLK_EN, 463*10f514bdSNeil Armstrong true); 464*10f514bdSNeil Armstrong 465*10f514bdSNeil Armstrong /* Digital path clock controls */ 466*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 467*10f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_RXD0_CLK_EN, true); 468*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 469*10f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_RXD1_CLK_EN, true); 470*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 471*10f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_RXD2_CLK_EN, true); 472*10f514bdSNeil Armstrong break; 473*10f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 474*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES, 475*10f514bdSNeil Armstrong WCD939X_RX_SUPPLIES_VNEG_EN, false); 476*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES, 477*10f514bdSNeil Armstrong WCD939X_RX_SUPPLIES_VPOS_EN, false); 478*10f514bdSNeil Armstrong 479*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 480*10f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_RXD2_CLK_EN, false); 481*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 482*10f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_RXD1_CLK_EN, false); 483*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 484*10f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_RXD0_CLK_EN, false); 485*10f514bdSNeil Armstrong 486*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 487*10f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV4_CLK_EN, 488*10f514bdSNeil Armstrong false); 489*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 490*10f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV2_CLK_EN, 491*10f514bdSNeil Armstrong false); 492*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 493*10f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_RX_CLK_EN, false); 494*10f514bdSNeil Armstrong 495*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES, 496*10f514bdSNeil Armstrong WCD939X_RX_SUPPLIES_RX_BIAS_ENABLE, false); 497*10f514bdSNeil Armstrong 498*10f514bdSNeil Armstrong break; 499*10f514bdSNeil Armstrong } 500*10f514bdSNeil Armstrong 501*10f514bdSNeil Armstrong return 0; 502*10f514bdSNeil Armstrong } 503*10f514bdSNeil Armstrong 504*10f514bdSNeil Armstrong static int wcd939x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, 505*10f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, 506*10f514bdSNeil Armstrong int event) 507*10f514bdSNeil Armstrong { 508*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 509*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 510*10f514bdSNeil Armstrong 511*10f514bdSNeil Armstrong switch (event) { 512*10f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 513*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_RDAC_CLK_CTL1, 514*10f514bdSNeil Armstrong WCD939X_RDAC_CLK_CTL1_OPAMP_CHOP_CLK_EN, 515*10f514bdSNeil Armstrong false); 516*10f514bdSNeil Armstrong 517*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_HPH_GAIN_CTL, 518*10f514bdSNeil Armstrong WCD939X_CDC_HPH_GAIN_CTL_HPHL_RX_EN, true); 519*10f514bdSNeil Armstrong break; 520*10f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMU: 521*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_L, 522*10f514bdSNeil Armstrong WCD939X_RDAC_HD2_CTL_L_HD2_RES_DIV_CTL_L, 0x1d); 523*10f514bdSNeil Armstrong if (wcd939x->comp1_enable) { 524*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 525*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_COMP_CTL_0, 526*10f514bdSNeil Armstrong WCD939X_CDC_COMP_CTL_0_HPHL_COMP_EN, 527*10f514bdSNeil Armstrong true); 528*10f514bdSNeil Armstrong /* 5msec compander delay as per HW requirement */ 529*10f514bdSNeil Armstrong if (!wcd939x->comp2_enable || 530*10f514bdSNeil Armstrong snd_soc_component_read_field(component, 531*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_COMP_CTL_0, 532*10f514bdSNeil Armstrong WCD939X_CDC_COMP_CTL_0_HPHR_COMP_EN)) 533*10f514bdSNeil Armstrong usleep_range(5000, 5010); 534*10f514bdSNeil Armstrong 535*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_TIMER1, 536*10f514bdSNeil Armstrong WCD939X_TIMER1_AUTOCHOP_TIMER_CTL_EN, 537*10f514bdSNeil Armstrong false); 538*10f514bdSNeil Armstrong } else { 539*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 540*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_COMP_CTL_0, 541*10f514bdSNeil Armstrong WCD939X_CDC_COMP_CTL_0_HPHL_COMP_EN, 542*10f514bdSNeil Armstrong false); 543*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_L_EN, 544*10f514bdSNeil Armstrong WCD939X_L_EN_GAIN_SOURCE_SEL, true); 545*10f514bdSNeil Armstrong } 546*10f514bdSNeil Armstrong break; 547*10f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 548*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_L, 549*10f514bdSNeil Armstrong WCD939X_RDAC_HD2_CTL_L_HD2_RES_DIV_CTL_L, 1); 550*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_HPH_GAIN_CTL, 551*10f514bdSNeil Armstrong WCD939X_CDC_HPH_GAIN_CTL_HPHL_RX_EN, false); 552*10f514bdSNeil Armstrong break; 553*10f514bdSNeil Armstrong } 554*10f514bdSNeil Armstrong 555*10f514bdSNeil Armstrong return 0; 556*10f514bdSNeil Armstrong } 557*10f514bdSNeil Armstrong 558*10f514bdSNeil Armstrong static int wcd939x_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, 559*10f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, 560*10f514bdSNeil Armstrong int event) 561*10f514bdSNeil Armstrong { 562*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 563*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 564*10f514bdSNeil Armstrong 565*10f514bdSNeil Armstrong dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, 566*10f514bdSNeil Armstrong w->name, event); 567*10f514bdSNeil Armstrong 568*10f514bdSNeil Armstrong switch (event) { 569*10f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 570*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_RDAC_CLK_CTL1, 571*10f514bdSNeil Armstrong WCD939X_RDAC_CLK_CTL1_OPAMP_CHOP_CLK_EN, 572*10f514bdSNeil Armstrong false); 573*10f514bdSNeil Armstrong 574*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_HPH_GAIN_CTL, 575*10f514bdSNeil Armstrong WCD939X_CDC_HPH_GAIN_CTL_HPHR_RX_EN, true); 576*10f514bdSNeil Armstrong break; 577*10f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMU: 578*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_R, 579*10f514bdSNeil Armstrong WCD939X_RDAC_HD2_CTL_R_HD2_RES_DIV_CTL_R, 0x1d); 580*10f514bdSNeil Armstrong if (wcd939x->comp2_enable) { 581*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 582*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_COMP_CTL_0, 583*10f514bdSNeil Armstrong WCD939X_CDC_COMP_CTL_0_HPHR_COMP_EN, 584*10f514bdSNeil Armstrong true); 585*10f514bdSNeil Armstrong /* 5msec compander delay as per HW requirement */ 586*10f514bdSNeil Armstrong if (!wcd939x->comp1_enable || 587*10f514bdSNeil Armstrong snd_soc_component_read_field(component, 588*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_COMP_CTL_0, 589*10f514bdSNeil Armstrong WCD939X_CDC_COMP_CTL_0_HPHL_COMP_EN)) 590*10f514bdSNeil Armstrong usleep_range(5000, 5010); 591*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_TIMER1, 592*10f514bdSNeil Armstrong WCD939X_TIMER1_AUTOCHOP_TIMER_CTL_EN, 593*10f514bdSNeil Armstrong false); 594*10f514bdSNeil Armstrong } else { 595*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 596*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_COMP_CTL_0, 597*10f514bdSNeil Armstrong WCD939X_CDC_COMP_CTL_0_HPHR_COMP_EN, 598*10f514bdSNeil Armstrong false); 599*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_R_EN, 600*10f514bdSNeil Armstrong WCD939X_R_EN_GAIN_SOURCE_SEL, true); 601*10f514bdSNeil Armstrong } 602*10f514bdSNeil Armstrong break; 603*10f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 604*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_R, 605*10f514bdSNeil Armstrong WCD939X_RDAC_HD2_CTL_R_HD2_RES_DIV_CTL_R, 1); 606*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_HPH_GAIN_CTL, 607*10f514bdSNeil Armstrong WCD939X_CDC_HPH_GAIN_CTL_HPHR_RX_EN, false); 608*10f514bdSNeil Armstrong break; 609*10f514bdSNeil Armstrong } 610*10f514bdSNeil Armstrong 611*10f514bdSNeil Armstrong return 0; 612*10f514bdSNeil Armstrong } 613*10f514bdSNeil Armstrong 614*10f514bdSNeil Armstrong static int wcd939x_codec_ear_dac_event(struct snd_soc_dapm_widget *w, 615*10f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, 616*10f514bdSNeil Armstrong int event) 617*10f514bdSNeil Armstrong { 618*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 619*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 620*10f514bdSNeil Armstrong 621*10f514bdSNeil Armstrong switch (event) { 622*10f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 623*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_EAR_GAIN_CTL, 624*10f514bdSNeil Armstrong WCD939X_CDC_EAR_GAIN_CTL_EAR_EN, true); 625*10f514bdSNeil Armstrong 626*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_EAR_DAC_CON, 627*10f514bdSNeil Armstrong WCD939X_DAC_CON_DAC_SAMPLE_EDGE_SEL, false); 628*10f514bdSNeil Armstrong 629*10f514bdSNeil Armstrong /* 5 msec delay as per HW requirement */ 630*10f514bdSNeil Armstrong usleep_range(5000, 5010); 631*10f514bdSNeil Armstrong wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_PRE_DAC, 632*10f514bdSNeil Armstrong WCD_CLSH_STATE_EAR, CLS_AB_HIFI); 633*10f514bdSNeil Armstrong 634*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_FLYBACK_VNEG_CTRL_4, 635*10f514bdSNeil Armstrong WCD939X_VNEG_CTRL_4_ILIM_SEL, 0xd); 636*10f514bdSNeil Armstrong break; 637*10f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 638*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_EAR_DAC_CON, 639*10f514bdSNeil Armstrong WCD939X_DAC_CON_DAC_SAMPLE_EDGE_SEL, true); 640*10f514bdSNeil Armstrong break; 641*10f514bdSNeil Armstrong } 642*10f514bdSNeil Armstrong 643*10f514bdSNeil Armstrong return 0; 644*10f514bdSNeil Armstrong } 645*10f514bdSNeil Armstrong 646*10f514bdSNeil Armstrong static int wcd939x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, 647*10f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, 648*10f514bdSNeil Armstrong int event) 649*10f514bdSNeil Armstrong { 650*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 651*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 652*10f514bdSNeil Armstrong int hph_mode = wcd939x->hph_mode; 653*10f514bdSNeil Armstrong 654*10f514bdSNeil Armstrong switch (event) { 655*10f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 656*10f514bdSNeil Armstrong if (wcd939x->ldoh) 657*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_LDOH_MODE, 658*10f514bdSNeil Armstrong WCD939X_MODE_LDOH_EN, true); 659*10f514bdSNeil Armstrong 660*10f514bdSNeil Armstrong wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_PRE_DAC, 661*10f514bdSNeil Armstrong WCD_CLSH_STATE_HPHR, hph_mode); 662*10f514bdSNeil Armstrong wcd_clsh_set_hph_mode(wcd939x->clsh_info, CLS_H_HIFI); 663*10f514bdSNeil Armstrong 664*10f514bdSNeil Armstrong if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || hph_mode == CLS_H_ULP) 665*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 666*10f514bdSNeil Armstrong WCD939X_HPH_REFBUFF_LP_CTL, 667*10f514bdSNeil Armstrong WCD939X_REFBUFF_LP_CTL_PREREF_FILT_BYPASS, true); 668*10f514bdSNeil Armstrong if (hph_mode == CLS_H_LOHIFI) 669*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_HPH, 670*10f514bdSNeil Armstrong WCD939X_HPH_PWR_LEVEL, 0); 671*10f514bdSNeil Armstrong 672*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_FLYBACK_VNEG_CTRL_4, 673*10f514bdSNeil Armstrong WCD939X_VNEG_CTRL_4_ILIM_SEL, 0xd); 674*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_HPH, 675*10f514bdSNeil Armstrong WCD939X_HPH_HPHR_REF_ENABLE, true); 676*10f514bdSNeil Armstrong 677*10f514bdSNeil Armstrong if (snd_soc_component_read_field(component, WCD939X_ANA_HPH, 678*10f514bdSNeil Armstrong WCD939X_HPH_HPHL_REF_ENABLE)) 679*10f514bdSNeil Armstrong usleep_range(2500, 2600); /* 2.5msec delay as per HW requirement */ 680*10f514bdSNeil Armstrong 681*10f514bdSNeil Armstrong set_bit(HPH_PA_DELAY, &wcd939x->status_mask); 682*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL1, 683*10f514bdSNeil Armstrong WCD939X_PDM_WD_CTL1_PDM_WD_EN, 3); 684*10f514bdSNeil Armstrong break; 685*10f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMU: 686*10f514bdSNeil Armstrong /* 687*10f514bdSNeil Armstrong * 7ms sleep is required if compander is enabled as per 688*10f514bdSNeil Armstrong * HW requirement. If compander is disabled, then 689*10f514bdSNeil Armstrong * 20ms delay is required. 690*10f514bdSNeil Armstrong */ 691*10f514bdSNeil Armstrong if (test_bit(HPH_PA_DELAY, &wcd939x->status_mask)) { 692*10f514bdSNeil Armstrong if (!wcd939x->comp2_enable) 693*10f514bdSNeil Armstrong usleep_range(20000, 20100); 694*10f514bdSNeil Armstrong else 695*10f514bdSNeil Armstrong usleep_range(7000, 7100); 696*10f514bdSNeil Armstrong 697*10f514bdSNeil Armstrong if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || 698*10f514bdSNeil Armstrong hph_mode == CLS_H_ULP) 699*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 700*10f514bdSNeil Armstrong WCD939X_HPH_REFBUFF_LP_CTL, 701*10f514bdSNeil Armstrong WCD939X_REFBUFF_LP_CTL_PREREF_FILT_BYPASS, 702*10f514bdSNeil Armstrong false); 703*10f514bdSNeil Armstrong clear_bit(HPH_PA_DELAY, &wcd939x->status_mask); 704*10f514bdSNeil Armstrong } 705*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_TIMER1, 706*10f514bdSNeil Armstrong WCD939X_TIMER1_AUTOCHOP_TIMER_CTL_EN, true); 707*10f514bdSNeil Armstrong if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI || 708*10f514bdSNeil Armstrong hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) 709*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES, 710*10f514bdSNeil Armstrong WCD939X_RX_SUPPLIES_REGULATOR_MODE, 711*10f514bdSNeil Armstrong true); 712*10f514bdSNeil Armstrong 713*10f514bdSNeil Armstrong enable_irq(wcd939x->hphr_pdm_wd_int); 714*10f514bdSNeil Armstrong break; 715*10f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMD: 716*10f514bdSNeil Armstrong disable_irq_nosync(wcd939x->hphr_pdm_wd_int); 717*10f514bdSNeil Armstrong /* 718*10f514bdSNeil Armstrong * 7ms sleep is required if compander is enabled as per 719*10f514bdSNeil Armstrong * HW requirement. If compander is disabled, then 720*10f514bdSNeil Armstrong * 20ms delay is required. 721*10f514bdSNeil Armstrong */ 722*10f514bdSNeil Armstrong if (!wcd939x->comp2_enable) 723*10f514bdSNeil Armstrong usleep_range(20000, 20100); 724*10f514bdSNeil Armstrong else 725*10f514bdSNeil Armstrong usleep_range(7000, 7100); 726*10f514bdSNeil Armstrong 727*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_HPH, 728*10f514bdSNeil Armstrong WCD939X_HPH_HPHR_ENABLE, false); 729*10f514bdSNeil Armstrong 730*10f514bdSNeil Armstrong wcd_mbhc_event_notify(wcd939x->wcd_mbhc, 731*10f514bdSNeil Armstrong WCD_EVENT_PRE_HPHR_PA_OFF); 732*10f514bdSNeil Armstrong set_bit(HPH_PA_DELAY, &wcd939x->status_mask); 733*10f514bdSNeil Armstrong break; 734*10f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 735*10f514bdSNeil Armstrong /* 736*10f514bdSNeil Armstrong * 7ms sleep is required if compander is enabled as per 737*10f514bdSNeil Armstrong * HW requirement. If compander is disabled, then 738*10f514bdSNeil Armstrong * 20ms delay is required. 739*10f514bdSNeil Armstrong */ 740*10f514bdSNeil Armstrong if (test_bit(HPH_PA_DELAY, &wcd939x->status_mask)) { 741*10f514bdSNeil Armstrong if (!wcd939x->comp2_enable) 742*10f514bdSNeil Armstrong usleep_range(20000, 20100); 743*10f514bdSNeil Armstrong else 744*10f514bdSNeil Armstrong usleep_range(7000, 7100); 745*10f514bdSNeil Armstrong clear_bit(HPH_PA_DELAY, &wcd939x->status_mask); 746*10f514bdSNeil Armstrong } 747*10f514bdSNeil Armstrong wcd_mbhc_event_notify(wcd939x->wcd_mbhc, 748*10f514bdSNeil Armstrong WCD_EVENT_POST_HPHR_PA_OFF); 749*10f514bdSNeil Armstrong 750*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_HPH, 751*10f514bdSNeil Armstrong WCD939X_HPH_HPHR_REF_ENABLE, false); 752*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL1, 753*10f514bdSNeil Armstrong WCD939X_PDM_WD_CTL1_PDM_WD_EN, 0); 754*10f514bdSNeil Armstrong 755*10f514bdSNeil Armstrong wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_POST_PA, 756*10f514bdSNeil Armstrong WCD_CLSH_STATE_HPHR, hph_mode); 757*10f514bdSNeil Armstrong if (wcd939x->ldoh) 758*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_LDOH_MODE, 759*10f514bdSNeil Armstrong WCD939X_MODE_LDOH_EN, false); 760*10f514bdSNeil Armstrong break; 761*10f514bdSNeil Armstrong } 762*10f514bdSNeil Armstrong 763*10f514bdSNeil Armstrong return 0; 764*10f514bdSNeil Armstrong } 765*10f514bdSNeil Armstrong 766*10f514bdSNeil Armstrong static int wcd939x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, 767*10f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, 768*10f514bdSNeil Armstrong int event) 769*10f514bdSNeil Armstrong { 770*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 771*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 772*10f514bdSNeil Armstrong int hph_mode = wcd939x->hph_mode; 773*10f514bdSNeil Armstrong 774*10f514bdSNeil Armstrong dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, 775*10f514bdSNeil Armstrong w->name, event); 776*10f514bdSNeil Armstrong 777*10f514bdSNeil Armstrong switch (event) { 778*10f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 779*10f514bdSNeil Armstrong if (wcd939x->ldoh) 780*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_LDOH_MODE, 781*10f514bdSNeil Armstrong WCD939X_MODE_LDOH_EN, true); 782*10f514bdSNeil Armstrong wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_PRE_DAC, 783*10f514bdSNeil Armstrong WCD_CLSH_STATE_HPHL, hph_mode); 784*10f514bdSNeil Armstrong wcd_clsh_set_hph_mode(wcd939x->clsh_info, CLS_H_HIFI); 785*10f514bdSNeil Armstrong 786*10f514bdSNeil Armstrong if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || hph_mode == CLS_H_ULP) 787*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 788*10f514bdSNeil Armstrong WCD939X_HPH_REFBUFF_LP_CTL, 789*10f514bdSNeil Armstrong WCD939X_REFBUFF_LP_CTL_PREREF_FILT_BYPASS, 790*10f514bdSNeil Armstrong true); 791*10f514bdSNeil Armstrong if (hph_mode == CLS_H_LOHIFI) 792*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_HPH, 793*10f514bdSNeil Armstrong WCD939X_HPH_PWR_LEVEL, 0); 794*10f514bdSNeil Armstrong 795*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_FLYBACK_VNEG_CTRL_4, 796*10f514bdSNeil Armstrong WCD939X_VNEG_CTRL_4_ILIM_SEL, 0xd); 797*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_HPH, 798*10f514bdSNeil Armstrong WCD939X_HPH_HPHL_REF_ENABLE, true); 799*10f514bdSNeil Armstrong 800*10f514bdSNeil Armstrong if (snd_soc_component_read_field(component, WCD939X_ANA_HPH, 801*10f514bdSNeil Armstrong WCD939X_HPH_HPHR_REF_ENABLE)) 802*10f514bdSNeil Armstrong usleep_range(2500, 2600); /* 2.5msec delay as per HW requirement */ 803*10f514bdSNeil Armstrong 804*10f514bdSNeil Armstrong set_bit(HPH_PA_DELAY, &wcd939x->status_mask); 805*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL0, 806*10f514bdSNeil Armstrong WCD939X_PDM_WD_CTL0_PDM_WD_EN, 3); 807*10f514bdSNeil Armstrong break; 808*10f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMU: 809*10f514bdSNeil Armstrong /* 810*10f514bdSNeil Armstrong * 7ms sleep is required if compander is enabled as per 811*10f514bdSNeil Armstrong * HW requirement. If compander is disabled, then 812*10f514bdSNeil Armstrong * 20ms delay is required. 813*10f514bdSNeil Armstrong */ 814*10f514bdSNeil Armstrong if (test_bit(HPH_PA_DELAY, &wcd939x->status_mask)) { 815*10f514bdSNeil Armstrong if (!wcd939x->comp1_enable) 816*10f514bdSNeil Armstrong usleep_range(20000, 20100); 817*10f514bdSNeil Armstrong else 818*10f514bdSNeil Armstrong usleep_range(7000, 7100); 819*10f514bdSNeil Armstrong if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || 820*10f514bdSNeil Armstrong hph_mode == CLS_H_ULP) 821*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 822*10f514bdSNeil Armstrong WCD939X_HPH_REFBUFF_LP_CTL, 823*10f514bdSNeil Armstrong WCD939X_REFBUFF_LP_CTL_PREREF_FILT_BYPASS, 824*10f514bdSNeil Armstrong false); 825*10f514bdSNeil Armstrong clear_bit(HPH_PA_DELAY, &wcd939x->status_mask); 826*10f514bdSNeil Armstrong } 827*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_TIMER1, 828*10f514bdSNeil Armstrong WCD939X_TIMER1_AUTOCHOP_TIMER_CTL_EN, true); 829*10f514bdSNeil Armstrong if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI || 830*10f514bdSNeil Armstrong hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) 831*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES, 832*10f514bdSNeil Armstrong WCD939X_RX_SUPPLIES_REGULATOR_MODE, 833*10f514bdSNeil Armstrong true); 834*10f514bdSNeil Armstrong enable_irq(wcd939x->hphl_pdm_wd_int); 835*10f514bdSNeil Armstrong break; 836*10f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMD: 837*10f514bdSNeil Armstrong disable_irq_nosync(wcd939x->hphl_pdm_wd_int); 838*10f514bdSNeil Armstrong /* 839*10f514bdSNeil Armstrong * 7ms sleep is required if compander is enabled as per 840*10f514bdSNeil Armstrong * HW requirement. If compander is disabled, then 841*10f514bdSNeil Armstrong * 20ms delay is required. 842*10f514bdSNeil Armstrong */ 843*10f514bdSNeil Armstrong if (!wcd939x->comp1_enable) 844*10f514bdSNeil Armstrong usleep_range(20000, 20100); 845*10f514bdSNeil Armstrong else 846*10f514bdSNeil Armstrong usleep_range(7000, 7100); 847*10f514bdSNeil Armstrong 848*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_HPH, 849*10f514bdSNeil Armstrong WCD939X_HPH_HPHL_ENABLE, false); 850*10f514bdSNeil Armstrong 851*10f514bdSNeil Armstrong wcd_mbhc_event_notify(wcd939x->wcd_mbhc, WCD_EVENT_PRE_HPHL_PA_OFF); 852*10f514bdSNeil Armstrong set_bit(HPH_PA_DELAY, &wcd939x->status_mask); 853*10f514bdSNeil Armstrong break; 854*10f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 855*10f514bdSNeil Armstrong /* 856*10f514bdSNeil Armstrong * 7ms sleep is required if compander is enabled as per 857*10f514bdSNeil Armstrong * HW requirement. If compander is disabled, then 858*10f514bdSNeil Armstrong * 20ms delay is required. 859*10f514bdSNeil Armstrong */ 860*10f514bdSNeil Armstrong if (test_bit(HPH_PA_DELAY, &wcd939x->status_mask)) { 861*10f514bdSNeil Armstrong if (!wcd939x->comp1_enable) 862*10f514bdSNeil Armstrong usleep_range(21000, 21100); 863*10f514bdSNeil Armstrong else 864*10f514bdSNeil Armstrong usleep_range(7000, 7100); 865*10f514bdSNeil Armstrong clear_bit(HPH_PA_DELAY, &wcd939x->status_mask); 866*10f514bdSNeil Armstrong } 867*10f514bdSNeil Armstrong wcd_mbhc_event_notify(wcd939x->wcd_mbhc, 868*10f514bdSNeil Armstrong WCD_EVENT_POST_HPHL_PA_OFF); 869*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_HPH, 870*10f514bdSNeil Armstrong WCD939X_HPH_HPHL_REF_ENABLE, false); 871*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL0, 872*10f514bdSNeil Armstrong WCD939X_PDM_WD_CTL0_PDM_WD_EN, 0); 873*10f514bdSNeil Armstrong wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_POST_PA, 874*10f514bdSNeil Armstrong WCD_CLSH_STATE_HPHL, hph_mode); 875*10f514bdSNeil Armstrong if (wcd939x->ldoh) 876*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_LDOH_MODE, 877*10f514bdSNeil Armstrong WCD939X_MODE_LDOH_EN, false); 878*10f514bdSNeil Armstrong break; 879*10f514bdSNeil Armstrong } 880*10f514bdSNeil Armstrong 881*10f514bdSNeil Armstrong return 0; 882*10f514bdSNeil Armstrong } 883*10f514bdSNeil Armstrong 884*10f514bdSNeil Armstrong static int wcd939x_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, 885*10f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, int event) 886*10f514bdSNeil Armstrong { 887*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 888*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 889*10f514bdSNeil Armstrong 890*10f514bdSNeil Armstrong switch (event) { 891*10f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 892*10f514bdSNeil Armstrong /* Enable watchdog interrupt for HPHL */ 893*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL0, 894*10f514bdSNeil Armstrong WCD939X_PDM_WD_CTL0_PDM_WD_EN, 3); 895*10f514bdSNeil Armstrong /* For EAR, use CLASS_AB regulator mode */ 896*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES, 897*10f514bdSNeil Armstrong WCD939X_RX_SUPPLIES_REGULATOR_MODE, true); 898*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_EAR_COMPANDER_CTL, 899*10f514bdSNeil Armstrong WCD939X_EAR_COMPANDER_CTL_GAIN_OVRD_REG, true); 900*10f514bdSNeil Armstrong break; 901*10f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMU: 902*10f514bdSNeil Armstrong /* 6 msec delay as per HW requirement */ 903*10f514bdSNeil Armstrong usleep_range(6000, 6010); 904*10f514bdSNeil Armstrong enable_irq(wcd939x->ear_pdm_wd_int); 905*10f514bdSNeil Armstrong break; 906*10f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMD: 907*10f514bdSNeil Armstrong disable_irq_nosync(wcd939x->ear_pdm_wd_int); 908*10f514bdSNeil Armstrong break; 909*10f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 910*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_EAR_COMPANDER_CTL, 911*10f514bdSNeil Armstrong WCD939X_EAR_COMPANDER_CTL_GAIN_OVRD_REG, 912*10f514bdSNeil Armstrong false); 913*10f514bdSNeil Armstrong /* 7 msec delay as per HW requirement */ 914*10f514bdSNeil Armstrong usleep_range(7000, 7010); 915*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL0, 916*10f514bdSNeil Armstrong WCD939X_PDM_WD_CTL0_PDM_WD_EN, 0); 917*10f514bdSNeil Armstrong wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_POST_PA, 918*10f514bdSNeil Armstrong WCD_CLSH_STATE_EAR, CLS_AB_HIFI); 919*10f514bdSNeil Armstrong break; 920*10f514bdSNeil Armstrong } 921*10f514bdSNeil Armstrong 922*10f514bdSNeil Armstrong return 0; 923*10f514bdSNeil Armstrong } 924*10f514bdSNeil Armstrong 925*10f514bdSNeil Armstrong /* TX Controls */ 926*10f514bdSNeil Armstrong 927*10f514bdSNeil Armstrong static int wcd939x_codec_enable_dmic(struct snd_soc_dapm_widget *w, 928*10f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, 929*10f514bdSNeil Armstrong int event) 930*10f514bdSNeil Armstrong { 931*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 932*10f514bdSNeil Armstrong u16 dmic_clk_reg, dmic_clk_en_reg; 933*10f514bdSNeil Armstrong u8 dmic_clk_en_mask; 934*10f514bdSNeil Armstrong u8 dmic_ctl_mask; 935*10f514bdSNeil Armstrong u8 dmic_clk_mask; 936*10f514bdSNeil Armstrong 937*10f514bdSNeil Armstrong switch (w->shift) { 938*10f514bdSNeil Armstrong case 0: 939*10f514bdSNeil Armstrong case 1: 940*10f514bdSNeil Armstrong dmic_clk_reg = WCD939X_DIGITAL_CDC_DMIC_RATE_1_2; 941*10f514bdSNeil Armstrong dmic_clk_en_reg = WCD939X_DIGITAL_CDC_DMIC1_CTL; 942*10f514bdSNeil Armstrong dmic_clk_en_mask = WCD939X_CDC_DMIC1_CTL_DMIC_CLK_EN; 943*10f514bdSNeil Armstrong dmic_clk_mask = WCD939X_CDC_DMIC_RATE_1_2_DMIC1_RATE; 944*10f514bdSNeil Armstrong dmic_ctl_mask = WCD939X_CDC_AMIC_CTL_AMIC1_IN_SEL; 945*10f514bdSNeil Armstrong break; 946*10f514bdSNeil Armstrong case 2: 947*10f514bdSNeil Armstrong case 3: 948*10f514bdSNeil Armstrong dmic_clk_reg = WCD939X_DIGITAL_CDC_DMIC_RATE_1_2; 949*10f514bdSNeil Armstrong dmic_clk_en_reg = WCD939X_DIGITAL_CDC_DMIC2_CTL; 950*10f514bdSNeil Armstrong dmic_clk_en_mask = WCD939X_CDC_DMIC2_CTL_DMIC_CLK_EN; 951*10f514bdSNeil Armstrong dmic_clk_mask = WCD939X_CDC_DMIC_RATE_1_2_DMIC2_RATE; 952*10f514bdSNeil Armstrong dmic_ctl_mask = WCD939X_CDC_AMIC_CTL_AMIC3_IN_SEL; 953*10f514bdSNeil Armstrong break; 954*10f514bdSNeil Armstrong case 4: 955*10f514bdSNeil Armstrong case 5: 956*10f514bdSNeil Armstrong dmic_clk_reg = WCD939X_DIGITAL_CDC_DMIC_RATE_3_4; 957*10f514bdSNeil Armstrong dmic_clk_en_reg = WCD939X_DIGITAL_CDC_DMIC3_CTL; 958*10f514bdSNeil Armstrong dmic_clk_en_mask = WCD939X_CDC_DMIC3_CTL_DMIC_CLK_EN; 959*10f514bdSNeil Armstrong dmic_clk_mask = WCD939X_CDC_DMIC_RATE_3_4_DMIC3_RATE; 960*10f514bdSNeil Armstrong dmic_ctl_mask = WCD939X_CDC_AMIC_CTL_AMIC4_IN_SEL; 961*10f514bdSNeil Armstrong break; 962*10f514bdSNeil Armstrong case 6: 963*10f514bdSNeil Armstrong case 7: 964*10f514bdSNeil Armstrong dmic_clk_reg = WCD939X_DIGITAL_CDC_DMIC_RATE_3_4; 965*10f514bdSNeil Armstrong dmic_clk_en_reg = WCD939X_DIGITAL_CDC_DMIC4_CTL; 966*10f514bdSNeil Armstrong dmic_clk_en_mask = WCD939X_CDC_DMIC4_CTL_DMIC_CLK_EN; 967*10f514bdSNeil Armstrong dmic_clk_mask = WCD939X_CDC_DMIC_RATE_3_4_DMIC4_RATE; 968*10f514bdSNeil Armstrong dmic_ctl_mask = WCD939X_CDC_AMIC_CTL_AMIC5_IN_SEL; 969*10f514bdSNeil Armstrong break; 970*10f514bdSNeil Armstrong default: 971*10f514bdSNeil Armstrong dev_err(component->dev, "%s: Invalid DMIC Selection\n", __func__); 972*10f514bdSNeil Armstrong return -EINVAL; 973*10f514bdSNeil Armstrong }; 974*10f514bdSNeil Armstrong 975*10f514bdSNeil Armstrong switch (event) { 976*10f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 977*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_AMIC_CTL, 978*10f514bdSNeil Armstrong dmic_ctl_mask, false); 979*10f514bdSNeil Armstrong /* 250us sleep as per HW requirement */ 980*10f514bdSNeil Armstrong usleep_range(250, 260); 981*10f514bdSNeil Armstrong if (w->shift == 2) 982*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 983*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DMIC2_CTL, 984*10f514bdSNeil Armstrong WCD939X_CDC_DMIC2_CTL_DMIC_LEFT_EN, 985*10f514bdSNeil Armstrong true); 986*10f514bdSNeil Armstrong /* Setting DMIC clock rate to 2.4MHz */ 987*10f514bdSNeil Armstrong snd_soc_component_write_field(component, dmic_clk_reg, 988*10f514bdSNeil Armstrong dmic_clk_mask, 3); 989*10f514bdSNeil Armstrong snd_soc_component_write_field(component, dmic_clk_en_reg, 990*10f514bdSNeil Armstrong dmic_clk_en_mask, true); 991*10f514bdSNeil Armstrong /* enable clock scaling */ 992*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DMIC_CTL, 993*10f514bdSNeil Armstrong WCD939X_CDC_DMIC_CTL_CLK_SCALE_EN, true); 994*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DMIC_CTL, 995*10f514bdSNeil Armstrong WCD939X_CDC_DMIC_CTL_DMIC_DIV_BAK_EN, true); 996*10f514bdSNeil Armstrong break; 997*10f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 998*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_AMIC_CTL, 999*10f514bdSNeil Armstrong dmic_ctl_mask, 1); 1000*10f514bdSNeil Armstrong if (w->shift == 2) 1001*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1002*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DMIC2_CTL, 1003*10f514bdSNeil Armstrong WCD939X_CDC_DMIC2_CTL_DMIC_LEFT_EN, 1004*10f514bdSNeil Armstrong false); 1005*10f514bdSNeil Armstrong snd_soc_component_write_field(component, dmic_clk_en_reg, 1006*10f514bdSNeil Armstrong dmic_clk_en_mask, 0); 1007*10f514bdSNeil Armstrong break; 1008*10f514bdSNeil Armstrong } 1009*10f514bdSNeil Armstrong return 0; 1010*10f514bdSNeil Armstrong } 1011*10f514bdSNeil Armstrong 1012*10f514bdSNeil Armstrong static int wcd939x_tx_swr_ctrl(struct snd_soc_dapm_widget *w, 1013*10f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, int event) 1014*10f514bdSNeil Armstrong { 1015*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 1016*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 1017*10f514bdSNeil Armstrong int bank; 1018*10f514bdSNeil Armstrong int rate; 1019*10f514bdSNeil Armstrong 1020*10f514bdSNeil Armstrong bank = wcd939x_swr_get_current_bank(wcd939x->sdw_priv[AIF1_CAP]->sdev); 1021*10f514bdSNeil Armstrong 1022*10f514bdSNeil Armstrong switch (event) { 1023*10f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 1024*10f514bdSNeil Armstrong if (strnstr(w->name, "ADC", sizeof("ADC"))) { 1025*10f514bdSNeil Armstrong int mode = 0; 1026*10f514bdSNeil Armstrong 1027*10f514bdSNeil Armstrong if (test_bit(WCD_ADC1, &wcd939x->status_mask)) 1028*10f514bdSNeil Armstrong mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC1]]; 1029*10f514bdSNeil Armstrong if (test_bit(WCD_ADC2, &wcd939x->status_mask)) 1030*10f514bdSNeil Armstrong mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC2]]; 1031*10f514bdSNeil Armstrong if (test_bit(WCD_ADC3, &wcd939x->status_mask)) 1032*10f514bdSNeil Armstrong mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC3]]; 1033*10f514bdSNeil Armstrong if (test_bit(WCD_ADC4, &wcd939x->status_mask)) 1034*10f514bdSNeil Armstrong mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC4]]; 1035*10f514bdSNeil Armstrong 1036*10f514bdSNeil Armstrong if (mode) 1037*10f514bdSNeil Armstrong rate = wcd939x_get_clk_rate(ffs(mode) - 1); 1038*10f514bdSNeil Armstrong else 1039*10f514bdSNeil Armstrong rate = wcd939x_get_clk_rate(ADC_MODE_INVALID); 1040*10f514bdSNeil Armstrong wcd939x_set_swr_clk_rate(component, rate, bank); 1041*10f514bdSNeil Armstrong wcd939x_set_swr_clk_rate(component, rate, !bank); 1042*10f514bdSNeil Armstrong } 1043*10f514bdSNeil Armstrong break; 1044*10f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 1045*10f514bdSNeil Armstrong if (strnstr(w->name, "ADC", sizeof("ADC"))) { 1046*10f514bdSNeil Armstrong rate = wcd939x_get_clk_rate(ADC_MODE_INVALID); 1047*10f514bdSNeil Armstrong wcd939x_set_swr_clk_rate(component, rate, !bank); 1048*10f514bdSNeil Armstrong wcd939x_set_swr_clk_rate(component, rate, bank); 1049*10f514bdSNeil Armstrong } 1050*10f514bdSNeil Armstrong break; 1051*10f514bdSNeil Armstrong } 1052*10f514bdSNeil Armstrong 1053*10f514bdSNeil Armstrong return 0; 1054*10f514bdSNeil Armstrong } 1055*10f514bdSNeil Armstrong 1056*10f514bdSNeil Armstrong static int wcd939x_get_adc_mode(int val) 1057*10f514bdSNeil Armstrong { 1058*10f514bdSNeil Armstrong int ret = 0; 1059*10f514bdSNeil Armstrong 1060*10f514bdSNeil Armstrong switch (val) { 1061*10f514bdSNeil Armstrong case ADC_MODE_INVALID: 1062*10f514bdSNeil Armstrong ret = ADC_MODE_VAL_NORMAL; 1063*10f514bdSNeil Armstrong break; 1064*10f514bdSNeil Armstrong case ADC_MODE_HIFI: 1065*10f514bdSNeil Armstrong ret = ADC_MODE_VAL_HIFI; 1066*10f514bdSNeil Armstrong break; 1067*10f514bdSNeil Armstrong case ADC_MODE_LO_HIF: 1068*10f514bdSNeil Armstrong ret = ADC_MODE_VAL_LO_HIF; 1069*10f514bdSNeil Armstrong break; 1070*10f514bdSNeil Armstrong case ADC_MODE_NORMAL: 1071*10f514bdSNeil Armstrong ret = ADC_MODE_VAL_NORMAL; 1072*10f514bdSNeil Armstrong break; 1073*10f514bdSNeil Armstrong case ADC_MODE_LP: 1074*10f514bdSNeil Armstrong ret = ADC_MODE_VAL_LP; 1075*10f514bdSNeil Armstrong break; 1076*10f514bdSNeil Armstrong case ADC_MODE_ULP1: 1077*10f514bdSNeil Armstrong ret = ADC_MODE_VAL_ULP1; 1078*10f514bdSNeil Armstrong break; 1079*10f514bdSNeil Armstrong case ADC_MODE_ULP2: 1080*10f514bdSNeil Armstrong ret = ADC_MODE_VAL_ULP2; 1081*10f514bdSNeil Armstrong break; 1082*10f514bdSNeil Armstrong default: 1083*10f514bdSNeil Armstrong ret = -EINVAL; 1084*10f514bdSNeil Armstrong break; 1085*10f514bdSNeil Armstrong } 1086*10f514bdSNeil Armstrong return ret; 1087*10f514bdSNeil Armstrong } 1088*10f514bdSNeil Armstrong 1089*10f514bdSNeil Armstrong static int wcd939x_codec_enable_adc(struct snd_soc_dapm_widget *w, 1090*10f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, int event) 1091*10f514bdSNeil Armstrong { 1092*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 1093*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 1094*10f514bdSNeil Armstrong 1095*10f514bdSNeil Armstrong switch (event) { 1096*10f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 1097*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 1098*10f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_TX_CLK_EN, true); 1099*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 1100*10f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV2_CLK_EN, 1101*10f514bdSNeil Armstrong true); 1102*10f514bdSNeil Armstrong set_bit(w->shift, &wcd939x->status_mask); 1103*10f514bdSNeil Armstrong break; 1104*10f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 1105*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 1106*10f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV2_CLK_EN, 1107*10f514bdSNeil Armstrong false); 1108*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 1109*10f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_TX_CLK_EN, 1110*10f514bdSNeil Armstrong false); 1111*10f514bdSNeil Armstrong clear_bit(w->shift, &wcd939x->status_mask); 1112*10f514bdSNeil Armstrong break; 1113*10f514bdSNeil Armstrong } 1114*10f514bdSNeil Armstrong 1115*10f514bdSNeil Armstrong return 0; 1116*10f514bdSNeil Armstrong } 1117*10f514bdSNeil Armstrong 1118*10f514bdSNeil Armstrong static void wcd939x_tx_channel_config(struct snd_soc_component *component, 1119*10f514bdSNeil Armstrong int channel, bool init) 1120*10f514bdSNeil Armstrong { 1121*10f514bdSNeil Armstrong int reg, mask; 1122*10f514bdSNeil Armstrong 1123*10f514bdSNeil Armstrong switch (channel) { 1124*10f514bdSNeil Armstrong case 0: 1125*10f514bdSNeil Armstrong reg = WCD939X_ANA_TX_CH2; 1126*10f514bdSNeil Armstrong mask = WCD939X_TX_CH2_HPF1_INIT; 1127*10f514bdSNeil Armstrong break; 1128*10f514bdSNeil Armstrong case 1: 1129*10f514bdSNeil Armstrong reg = WCD939X_ANA_TX_CH2; 1130*10f514bdSNeil Armstrong mask = WCD939X_TX_CH2_HPF2_INIT; 1131*10f514bdSNeil Armstrong break; 1132*10f514bdSNeil Armstrong case 2: 1133*10f514bdSNeil Armstrong reg = WCD939X_ANA_TX_CH4; 1134*10f514bdSNeil Armstrong mask = WCD939X_TX_CH4_HPF3_INIT; 1135*10f514bdSNeil Armstrong break; 1136*10f514bdSNeil Armstrong case 3: 1137*10f514bdSNeil Armstrong reg = WCD939X_ANA_TX_CH4; 1138*10f514bdSNeil Armstrong mask = WCD939X_TX_CH4_HPF4_INIT; 1139*10f514bdSNeil Armstrong break; 1140*10f514bdSNeil Armstrong default: 1141*10f514bdSNeil Armstrong return; 1142*10f514bdSNeil Armstrong } 1143*10f514bdSNeil Armstrong 1144*10f514bdSNeil Armstrong snd_soc_component_write_field(component, reg, mask, init); 1145*10f514bdSNeil Armstrong } 1146*10f514bdSNeil Armstrong 1147*10f514bdSNeil Armstrong static int wcd939x_adc_enable_req(struct snd_soc_dapm_widget *w, 1148*10f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, int event) 1149*10f514bdSNeil Armstrong { 1150*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 1151*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 1152*10f514bdSNeil Armstrong int mode; 1153*10f514bdSNeil Armstrong 1154*10f514bdSNeil Armstrong switch (event) { 1155*10f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 1156*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_REQ_CTL, 1157*10f514bdSNeil Armstrong WCD939X_CDC_REQ_CTL_FS_RATE_4P8, true); 1158*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_REQ_CTL, 1159*10f514bdSNeil Armstrong WCD939X_CDC_REQ_CTL_NO_NOTCH, false); 1160*10f514bdSNeil Armstrong 1161*10f514bdSNeil Armstrong wcd939x_tx_channel_config(component, w->shift, true); 1162*10f514bdSNeil Armstrong mode = wcd939x_get_adc_mode(wcd939x->tx_mode[w->shift]); 1163*10f514bdSNeil Armstrong if (mode < 0) { 1164*10f514bdSNeil Armstrong dev_info(component->dev, "Invalid ADC mode\n"); 1165*10f514bdSNeil Armstrong return -EINVAL; 1166*10f514bdSNeil Armstrong } 1167*10f514bdSNeil Armstrong 1168*10f514bdSNeil Armstrong switch (w->shift) { 1169*10f514bdSNeil Armstrong case 0: 1170*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1171*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1, 1172*10f514bdSNeil Armstrong WCD939X_CDC_TX_ANA_MODE_0_1_TXD0_MODE, 1173*10f514bdSNeil Armstrong mode); 1174*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1175*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 1176*10f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD0_CLK_EN, 1177*10f514bdSNeil Armstrong true); 1178*10f514bdSNeil Armstrong break; 1179*10f514bdSNeil Armstrong case 1: 1180*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1181*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1, 1182*10f514bdSNeil Armstrong WCD939X_CDC_TX_ANA_MODE_0_1_TXD1_MODE, 1183*10f514bdSNeil Armstrong mode); 1184*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1185*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 1186*10f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD1_CLK_EN, 1187*10f514bdSNeil Armstrong true); 1188*10f514bdSNeil Armstrong break; 1189*10f514bdSNeil Armstrong case 2: 1190*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1191*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3, 1192*10f514bdSNeil Armstrong WCD939X_CDC_TX_ANA_MODE_2_3_TXD2_MODE, 1193*10f514bdSNeil Armstrong mode); 1194*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1195*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 1196*10f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD2_CLK_EN, 1197*10f514bdSNeil Armstrong true); 1198*10f514bdSNeil Armstrong break; 1199*10f514bdSNeil Armstrong case 3: 1200*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1201*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3, 1202*10f514bdSNeil Armstrong WCD939X_CDC_TX_ANA_MODE_2_3_TXD3_MODE, 1203*10f514bdSNeil Armstrong mode); 1204*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1205*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 1206*10f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD3_CLK_EN, 1207*10f514bdSNeil Armstrong true); 1208*10f514bdSNeil Armstrong break; 1209*10f514bdSNeil Armstrong default: 1210*10f514bdSNeil Armstrong break; 1211*10f514bdSNeil Armstrong } 1212*10f514bdSNeil Armstrong 1213*10f514bdSNeil Armstrong wcd939x_tx_channel_config(component, w->shift, false); 1214*10f514bdSNeil Armstrong break; 1215*10f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 1216*10f514bdSNeil Armstrong switch (w->shift) { 1217*10f514bdSNeil Armstrong case 0: 1218*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1219*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1, 1220*10f514bdSNeil Armstrong WCD939X_CDC_TX_ANA_MODE_0_1_TXD0_MODE, 1221*10f514bdSNeil Armstrong false); 1222*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1223*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 1224*10f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD0_CLK_EN, 1225*10f514bdSNeil Armstrong false); 1226*10f514bdSNeil Armstrong break; 1227*10f514bdSNeil Armstrong case 1: 1228*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1229*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1, 1230*10f514bdSNeil Armstrong WCD939X_CDC_TX_ANA_MODE_0_1_TXD1_MODE, 1231*10f514bdSNeil Armstrong false); 1232*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1233*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 1234*10f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD1_CLK_EN, 1235*10f514bdSNeil Armstrong false); 1236*10f514bdSNeil Armstrong break; 1237*10f514bdSNeil Armstrong case 2: 1238*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1239*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3, 1240*10f514bdSNeil Armstrong WCD939X_CDC_TX_ANA_MODE_2_3_TXD2_MODE, 1241*10f514bdSNeil Armstrong false); 1242*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1243*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 1244*10f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD2_CLK_EN, 1245*10f514bdSNeil Armstrong false); 1246*10f514bdSNeil Armstrong break; 1247*10f514bdSNeil Armstrong case 3: 1248*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1249*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3, 1250*10f514bdSNeil Armstrong WCD939X_CDC_TX_ANA_MODE_2_3_TXD3_MODE, 1251*10f514bdSNeil Armstrong false); 1252*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1253*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 1254*10f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD3_CLK_EN, 1255*10f514bdSNeil Armstrong false); 1256*10f514bdSNeil Armstrong break; 1257*10f514bdSNeil Armstrong default: 1258*10f514bdSNeil Armstrong break; 1259*10f514bdSNeil Armstrong } 1260*10f514bdSNeil Armstrong break; 1261*10f514bdSNeil Armstrong } 1262*10f514bdSNeil Armstrong 1263*10f514bdSNeil Armstrong return 0; 1264*10f514bdSNeil Armstrong } 1265*10f514bdSNeil Armstrong 1266*10f514bdSNeil Armstrong static int wcd939x_micbias_control(struct snd_soc_component *component, 1267*10f514bdSNeil Armstrong int micb_num, int req, bool is_dapm) 1268*10f514bdSNeil Armstrong { 1269*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 1270*10f514bdSNeil Armstrong int micb_index = micb_num - 1; 1271*10f514bdSNeil Armstrong u16 micb_field; 1272*10f514bdSNeil Armstrong u16 micb_reg; 1273*10f514bdSNeil Armstrong 1274*10f514bdSNeil Armstrong switch (micb_num) { 1275*10f514bdSNeil Armstrong case MIC_BIAS_1: 1276*10f514bdSNeil Armstrong micb_reg = WCD939X_ANA_MICB1; 1277*10f514bdSNeil Armstrong micb_field = WCD939X_MICB1_ENABLE; 1278*10f514bdSNeil Armstrong break; 1279*10f514bdSNeil Armstrong case MIC_BIAS_2: 1280*10f514bdSNeil Armstrong micb_reg = WCD939X_ANA_MICB2; 1281*10f514bdSNeil Armstrong micb_field = WCD939X_MICB2_ENABLE; 1282*10f514bdSNeil Armstrong break; 1283*10f514bdSNeil Armstrong case MIC_BIAS_3: 1284*10f514bdSNeil Armstrong micb_reg = WCD939X_ANA_MICB3; 1285*10f514bdSNeil Armstrong micb_field = WCD939X_MICB3_ENABLE; 1286*10f514bdSNeil Armstrong break; 1287*10f514bdSNeil Armstrong case MIC_BIAS_4: 1288*10f514bdSNeil Armstrong micb_reg = WCD939X_ANA_MICB4; 1289*10f514bdSNeil Armstrong micb_field = WCD939X_MICB4_ENABLE; 1290*10f514bdSNeil Armstrong break; 1291*10f514bdSNeil Armstrong default: 1292*10f514bdSNeil Armstrong dev_err(component->dev, "%s: Invalid micbias number: %d\n", 1293*10f514bdSNeil Armstrong __func__, micb_num); 1294*10f514bdSNeil Armstrong return -EINVAL; 1295*10f514bdSNeil Armstrong }; 1296*10f514bdSNeil Armstrong 1297*10f514bdSNeil Armstrong switch (req) { 1298*10f514bdSNeil Armstrong case MICB_PULLUP_ENABLE: 1299*10f514bdSNeil Armstrong wcd939x->pullup_ref[micb_index]++; 1300*10f514bdSNeil Armstrong if (wcd939x->pullup_ref[micb_index] == 1 && 1301*10f514bdSNeil Armstrong wcd939x->micb_ref[micb_index] == 0) 1302*10f514bdSNeil Armstrong snd_soc_component_write_field(component, micb_reg, 1303*10f514bdSNeil Armstrong micb_field, MICB_BIAS_PULL_UP); 1304*10f514bdSNeil Armstrong break; 1305*10f514bdSNeil Armstrong case MICB_PULLUP_DISABLE: 1306*10f514bdSNeil Armstrong if (wcd939x->pullup_ref[micb_index] > 0) 1307*10f514bdSNeil Armstrong wcd939x->pullup_ref[micb_index]--; 1308*10f514bdSNeil Armstrong if (wcd939x->pullup_ref[micb_index] == 0 && 1309*10f514bdSNeil Armstrong wcd939x->micb_ref[micb_index] == 0) 1310*10f514bdSNeil Armstrong snd_soc_component_write_field(component, micb_reg, 1311*10f514bdSNeil Armstrong micb_field, MICB_BIAS_DISABLE); 1312*10f514bdSNeil Armstrong break; 1313*10f514bdSNeil Armstrong case MICB_ENABLE: 1314*10f514bdSNeil Armstrong wcd939x->micb_ref[micb_index]++; 1315*10f514bdSNeil Armstrong if (wcd939x->micb_ref[micb_index] == 1) { 1316*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1317*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 1318*10f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD3_CLK_EN, true); 1319*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1320*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 1321*10f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD2_CLK_EN, true); 1322*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1323*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 1324*10f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD1_CLK_EN, true); 1325*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1326*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 1327*10f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD0_CLK_EN, true); 1328*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1329*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 1330*10f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV2_CLK_EN, 1331*10f514bdSNeil Armstrong true); 1332*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1333*10f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_ANA_TX_CLK_CTL, 1334*10f514bdSNeil Armstrong WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TXSCBIAS_CLK_EN, 1335*10f514bdSNeil Armstrong true); 1336*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1337*10f514bdSNeil Armstrong WCD939X_MICB1_TEST_CTL_2, 1338*10f514bdSNeil Armstrong WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER, true); 1339*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1340*10f514bdSNeil Armstrong WCD939X_MICB2_TEST_CTL_2, 1341*10f514bdSNeil Armstrong WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER, true); 1342*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1343*10f514bdSNeil Armstrong WCD939X_MICB3_TEST_CTL_2, 1344*10f514bdSNeil Armstrong WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER, true); 1345*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 1346*10f514bdSNeil Armstrong WCD939X_MICB4_TEST_CTL_2, 1347*10f514bdSNeil Armstrong WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER, true); 1348*10f514bdSNeil Armstrong snd_soc_component_write_field(component, micb_reg, micb_field, 1349*10f514bdSNeil Armstrong MICB_BIAS_ENABLE); 1350*10f514bdSNeil Armstrong if (micb_num == MIC_BIAS_2) 1351*10f514bdSNeil Armstrong wcd_mbhc_event_notify(wcd939x->wcd_mbhc, 1352*10f514bdSNeil Armstrong WCD_EVENT_POST_MICBIAS_2_ON); 1353*10f514bdSNeil Armstrong } 1354*10f514bdSNeil Armstrong if (micb_num == MIC_BIAS_2 && is_dapm) 1355*10f514bdSNeil Armstrong wcd_mbhc_event_notify(wcd939x->wcd_mbhc, 1356*10f514bdSNeil Armstrong WCD_EVENT_POST_DAPM_MICBIAS_2_ON); 1357*10f514bdSNeil Armstrong break; 1358*10f514bdSNeil Armstrong case MICB_DISABLE: 1359*10f514bdSNeil Armstrong if (wcd939x->micb_ref[micb_index] > 0) 1360*10f514bdSNeil Armstrong wcd939x->micb_ref[micb_index]--; 1361*10f514bdSNeil Armstrong 1362*10f514bdSNeil Armstrong if (wcd939x->micb_ref[micb_index] == 0 && 1363*10f514bdSNeil Armstrong wcd939x->pullup_ref[micb_index] > 0) 1364*10f514bdSNeil Armstrong snd_soc_component_write_field(component, micb_reg, 1365*10f514bdSNeil Armstrong micb_field, MICB_BIAS_PULL_UP); 1366*10f514bdSNeil Armstrong else if (wcd939x->micb_ref[micb_index] == 0 && 1367*10f514bdSNeil Armstrong wcd939x->pullup_ref[micb_index] == 0) { 1368*10f514bdSNeil Armstrong if (micb_num == MIC_BIAS_2) 1369*10f514bdSNeil Armstrong wcd_mbhc_event_notify(wcd939x->wcd_mbhc, 1370*10f514bdSNeil Armstrong WCD_EVENT_PRE_MICBIAS_2_OFF); 1371*10f514bdSNeil Armstrong 1372*10f514bdSNeil Armstrong snd_soc_component_write_field(component, micb_reg, 1373*10f514bdSNeil Armstrong micb_field, MICB_BIAS_DISABLE); 1374*10f514bdSNeil Armstrong if (micb_num == MIC_BIAS_2) 1375*10f514bdSNeil Armstrong wcd_mbhc_event_notify(wcd939x->wcd_mbhc, 1376*10f514bdSNeil Armstrong WCD_EVENT_POST_MICBIAS_2_OFF); 1377*10f514bdSNeil Armstrong } 1378*10f514bdSNeil Armstrong if (is_dapm && micb_num == MIC_BIAS_2) 1379*10f514bdSNeil Armstrong wcd_mbhc_event_notify(wcd939x->wcd_mbhc, 1380*10f514bdSNeil Armstrong WCD_EVENT_POST_DAPM_MICBIAS_2_OFF); 1381*10f514bdSNeil Armstrong break; 1382*10f514bdSNeil Armstrong } 1383*10f514bdSNeil Armstrong 1384*10f514bdSNeil Armstrong return 0; 1385*10f514bdSNeil Armstrong } 1386*10f514bdSNeil Armstrong 1387*10f514bdSNeil Armstrong static int wcd939x_codec_enable_micbias(struct snd_soc_dapm_widget *w, 1388*10f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, 1389*10f514bdSNeil Armstrong int event) 1390*10f514bdSNeil Armstrong { 1391*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 1392*10f514bdSNeil Armstrong int micb_num = w->shift; 1393*10f514bdSNeil Armstrong 1394*10f514bdSNeil Armstrong switch (event) { 1395*10f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 1396*10f514bdSNeil Armstrong wcd939x_micbias_control(component, micb_num, MICB_ENABLE, true); 1397*10f514bdSNeil Armstrong break; 1398*10f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMU: 1399*10f514bdSNeil Armstrong /* 1 msec delay as per HW requirement */ 1400*10f514bdSNeil Armstrong usleep_range(1000, 1100); 1401*10f514bdSNeil Armstrong break; 1402*10f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 1403*10f514bdSNeil Armstrong wcd939x_micbias_control(component, micb_num, MICB_DISABLE, true); 1404*10f514bdSNeil Armstrong break; 1405*10f514bdSNeil Armstrong } 1406*10f514bdSNeil Armstrong 1407*10f514bdSNeil Armstrong return 0; 1408*10f514bdSNeil Armstrong } 1409*10f514bdSNeil Armstrong 1410*10f514bdSNeil Armstrong static int wcd939x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w, 1411*10f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, 1412*10f514bdSNeil Armstrong int event) 1413*10f514bdSNeil Armstrong { 1414*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 1415*10f514bdSNeil Armstrong int micb_num = w->shift; 1416*10f514bdSNeil Armstrong 1417*10f514bdSNeil Armstrong switch (event) { 1418*10f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 1419*10f514bdSNeil Armstrong wcd939x_micbias_control(component, micb_num, 1420*10f514bdSNeil Armstrong MICB_PULLUP_ENABLE, true); 1421*10f514bdSNeil Armstrong break; 1422*10f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMU: 1423*10f514bdSNeil Armstrong /* 1 msec delay as per HW requirement */ 1424*10f514bdSNeil Armstrong usleep_range(1000, 1100); 1425*10f514bdSNeil Armstrong break; 1426*10f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 1427*10f514bdSNeil Armstrong wcd939x_micbias_control(component, micb_num, 1428*10f514bdSNeil Armstrong MICB_PULLUP_DISABLE, true); 1429*10f514bdSNeil Armstrong break; 1430*10f514bdSNeil Armstrong } 1431*10f514bdSNeil Armstrong 1432*10f514bdSNeil Armstrong return 0; 1433*10f514bdSNeil Armstrong } 1434*10f514bdSNeil Armstrong 1435*10f514bdSNeil Armstrong static int wcd939x_tx_mode_get(struct snd_kcontrol *kcontrol, 1436*10f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 1437*10f514bdSNeil Armstrong { 1438*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 1439*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 1440*10f514bdSNeil Armstrong struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 1441*10f514bdSNeil Armstrong int path = e->shift_l; 1442*10f514bdSNeil Armstrong 1443*10f514bdSNeil Armstrong ucontrol->value.enumerated.item[0] = wcd939x->tx_mode[path]; 1444*10f514bdSNeil Armstrong 1445*10f514bdSNeil Armstrong return 0; 1446*10f514bdSNeil Armstrong } 1447*10f514bdSNeil Armstrong 1448*10f514bdSNeil Armstrong static int wcd939x_tx_mode_put(struct snd_kcontrol *kcontrol, 1449*10f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 1450*10f514bdSNeil Armstrong { 1451*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 1452*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 1453*10f514bdSNeil Armstrong struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 1454*10f514bdSNeil Armstrong int path = e->shift_l; 1455*10f514bdSNeil Armstrong 1456*10f514bdSNeil Armstrong if (wcd939x->tx_mode[path] == ucontrol->value.enumerated.item[0]) 1457*10f514bdSNeil Armstrong return 0; 1458*10f514bdSNeil Armstrong 1459*10f514bdSNeil Armstrong wcd939x->tx_mode[path] = ucontrol->value.enumerated.item[0]; 1460*10f514bdSNeil Armstrong 1461*10f514bdSNeil Armstrong return 1; 1462*10f514bdSNeil Armstrong } 1463*10f514bdSNeil Armstrong 1464*10f514bdSNeil Armstrong /* RX Controls */ 1465*10f514bdSNeil Armstrong 1466*10f514bdSNeil Armstrong static int wcd939x_rx_hph_mode_get(struct snd_kcontrol *kcontrol, 1467*10f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 1468*10f514bdSNeil Armstrong { 1469*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 1470*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 1471*10f514bdSNeil Armstrong 1472*10f514bdSNeil Armstrong ucontrol->value.integer.value[0] = wcd939x->hph_mode; 1473*10f514bdSNeil Armstrong 1474*10f514bdSNeil Armstrong return 0; 1475*10f514bdSNeil Armstrong } 1476*10f514bdSNeil Armstrong 1477*10f514bdSNeil Armstrong static int wcd939x_rx_hph_mode_put(struct snd_kcontrol *kcontrol, 1478*10f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 1479*10f514bdSNeil Armstrong { 1480*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 1481*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 1482*10f514bdSNeil Armstrong u32 mode_val; 1483*10f514bdSNeil Armstrong 1484*10f514bdSNeil Armstrong mode_val = ucontrol->value.enumerated.item[0]; 1485*10f514bdSNeil Armstrong 1486*10f514bdSNeil Armstrong if (mode_val == wcd939x->hph_mode) 1487*10f514bdSNeil Armstrong return 0; 1488*10f514bdSNeil Armstrong 1489*10f514bdSNeil Armstrong if (wcd939x->variant == WCD9390) { 1490*10f514bdSNeil Armstrong switch (mode_val) { 1491*10f514bdSNeil Armstrong case CLS_H_NORMAL: 1492*10f514bdSNeil Armstrong case CLS_H_LP: 1493*10f514bdSNeil Armstrong case CLS_AB: 1494*10f514bdSNeil Armstrong case CLS_H_LOHIFI: 1495*10f514bdSNeil Armstrong case CLS_H_ULP: 1496*10f514bdSNeil Armstrong case CLS_AB_LP: 1497*10f514bdSNeil Armstrong case CLS_AB_LOHIFI: 1498*10f514bdSNeil Armstrong wcd939x->hph_mode = mode_val; 1499*10f514bdSNeil Armstrong return 1; 1500*10f514bdSNeil Armstrong } 1501*10f514bdSNeil Armstrong } else { 1502*10f514bdSNeil Armstrong switch (mode_val) { 1503*10f514bdSNeil Armstrong case CLS_H_NORMAL: 1504*10f514bdSNeil Armstrong case CLS_H_HIFI: 1505*10f514bdSNeil Armstrong case CLS_H_LP: 1506*10f514bdSNeil Armstrong case CLS_AB: 1507*10f514bdSNeil Armstrong case CLS_H_LOHIFI: 1508*10f514bdSNeil Armstrong case CLS_H_ULP: 1509*10f514bdSNeil Armstrong case CLS_AB_HIFI: 1510*10f514bdSNeil Armstrong case CLS_AB_LP: 1511*10f514bdSNeil Armstrong case CLS_AB_LOHIFI: 1512*10f514bdSNeil Armstrong wcd939x->hph_mode = mode_val; 1513*10f514bdSNeil Armstrong return 1; 1514*10f514bdSNeil Armstrong } 1515*10f514bdSNeil Armstrong } 1516*10f514bdSNeil Armstrong 1517*10f514bdSNeil Armstrong dev_dbg(component->dev, "%s: Invalid HPH Mode\n", __func__); 1518*10f514bdSNeil Armstrong return -EINVAL; 1519*10f514bdSNeil Armstrong } 1520*10f514bdSNeil Armstrong 1521*10f514bdSNeil Armstrong static int wcd939x_get_compander(struct snd_kcontrol *kcontrol, 1522*10f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 1523*10f514bdSNeil Armstrong { 1524*10f514bdSNeil Armstrong struct soc_mixer_control *mc = (struct soc_mixer_control *)(kcontrol->private_value); 1525*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 1526*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 1527*10f514bdSNeil Armstrong 1528*10f514bdSNeil Armstrong if (mc->shift) 1529*10f514bdSNeil Armstrong ucontrol->value.integer.value[0] = wcd939x->comp2_enable ? 1 : 0; 1530*10f514bdSNeil Armstrong else 1531*10f514bdSNeil Armstrong ucontrol->value.integer.value[0] = wcd939x->comp1_enable ? 1 : 0; 1532*10f514bdSNeil Armstrong 1533*10f514bdSNeil Armstrong return 0; 1534*10f514bdSNeil Armstrong } 1535*10f514bdSNeil Armstrong 1536*10f514bdSNeil Armstrong static int wcd939x_set_compander(struct snd_kcontrol *kcontrol, 1537*10f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 1538*10f514bdSNeil Armstrong { 1539*10f514bdSNeil Armstrong struct soc_mixer_control *mc = (struct soc_mixer_control *)(kcontrol->private_value); 1540*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 1541*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 1542*10f514bdSNeil Armstrong struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[AIF1_PB]; 1543*10f514bdSNeil Armstrong bool value = !!ucontrol->value.integer.value[0]; 1544*10f514bdSNeil Armstrong int portidx = wcd->ch_info[mc->reg].port_num; 1545*10f514bdSNeil Armstrong 1546*10f514bdSNeil Armstrong if (mc->shift) 1547*10f514bdSNeil Armstrong wcd939x->comp2_enable = value; 1548*10f514bdSNeil Armstrong else 1549*10f514bdSNeil Armstrong wcd939x->comp1_enable = value; 1550*10f514bdSNeil Armstrong 1551*10f514bdSNeil Armstrong if (value) 1552*10f514bdSNeil Armstrong wcd939x_connect_port(wcd, portidx, mc->reg, true); 1553*10f514bdSNeil Armstrong else 1554*10f514bdSNeil Armstrong wcd939x_connect_port(wcd, portidx, mc->reg, false); 1555*10f514bdSNeil Armstrong 1556*10f514bdSNeil Armstrong return 1; 1557*10f514bdSNeil Armstrong } 1558*10f514bdSNeil Armstrong 1559*10f514bdSNeil Armstrong static int wcd939x_ldoh_get(struct snd_kcontrol *kcontrol, 1560*10f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 1561*10f514bdSNeil Armstrong { 1562*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 1563*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 1564*10f514bdSNeil Armstrong 1565*10f514bdSNeil Armstrong ucontrol->value.integer.value[0] = wcd939x->ldoh ? 1 : 0; 1566*10f514bdSNeil Armstrong 1567*10f514bdSNeil Armstrong return 0; 1568*10f514bdSNeil Armstrong } 1569*10f514bdSNeil Armstrong 1570*10f514bdSNeil Armstrong static int wcd939x_ldoh_put(struct snd_kcontrol *kcontrol, 1571*10f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 1572*10f514bdSNeil Armstrong { 1573*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 1574*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 1575*10f514bdSNeil Armstrong 1576*10f514bdSNeil Armstrong if (wcd939x->ldoh == !!ucontrol->value.integer.value[0]) 1577*10f514bdSNeil Armstrong return 0; 1578*10f514bdSNeil Armstrong 1579*10f514bdSNeil Armstrong wcd939x->ldoh = !!ucontrol->value.integer.value[0]; 1580*10f514bdSNeil Armstrong 1581*10f514bdSNeil Armstrong return 1; 1582*10f514bdSNeil Armstrong } 1583*10f514bdSNeil Armstrong 1584*10f514bdSNeil Armstrong static const char * const tx_mode_mux_text_wcd9390[] = { 1585*10f514bdSNeil Armstrong "ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP", 1586*10f514bdSNeil Armstrong }; 1587*10f514bdSNeil Armstrong 1588*10f514bdSNeil Armstrong static const struct soc_enum tx0_mode_mux_enum_wcd9390 = 1589*10f514bdSNeil Armstrong SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tx_mode_mux_text_wcd9390), 1590*10f514bdSNeil Armstrong tx_mode_mux_text_wcd9390); 1591*10f514bdSNeil Armstrong 1592*10f514bdSNeil Armstrong static const struct soc_enum tx1_mode_mux_enum_wcd9390 = 1593*10f514bdSNeil Armstrong SOC_ENUM_SINGLE(SND_SOC_NOPM, 1, ARRAY_SIZE(tx_mode_mux_text_wcd9390), 1594*10f514bdSNeil Armstrong tx_mode_mux_text_wcd9390); 1595*10f514bdSNeil Armstrong 1596*10f514bdSNeil Armstrong static const struct soc_enum tx2_mode_mux_enum_wcd9390 = 1597*10f514bdSNeil Armstrong SOC_ENUM_SINGLE(SND_SOC_NOPM, 2, ARRAY_SIZE(tx_mode_mux_text_wcd9390), 1598*10f514bdSNeil Armstrong tx_mode_mux_text_wcd9390); 1599*10f514bdSNeil Armstrong 1600*10f514bdSNeil Armstrong static const struct soc_enum tx3_mode_mux_enum_wcd9390 = 1601*10f514bdSNeil Armstrong SOC_ENUM_SINGLE(SND_SOC_NOPM, 3, ARRAY_SIZE(tx_mode_mux_text_wcd9390), 1602*10f514bdSNeil Armstrong tx_mode_mux_text_wcd9390); 1603*10f514bdSNeil Armstrong 1604*10f514bdSNeil Armstrong static const char * const tx_mode_mux_text[] = { 1605*10f514bdSNeil Armstrong "ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP", 1606*10f514bdSNeil Armstrong "ADC_ULP1", "ADC_ULP2", 1607*10f514bdSNeil Armstrong }; 1608*10f514bdSNeil Armstrong 1609*10f514bdSNeil Armstrong static const struct soc_enum tx0_mode_mux_enum = 1610*10f514bdSNeil Armstrong SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tx_mode_mux_text), 1611*10f514bdSNeil Armstrong tx_mode_mux_text); 1612*10f514bdSNeil Armstrong 1613*10f514bdSNeil Armstrong static const struct soc_enum tx1_mode_mux_enum = 1614*10f514bdSNeil Armstrong SOC_ENUM_SINGLE(SND_SOC_NOPM, 1, ARRAY_SIZE(tx_mode_mux_text), 1615*10f514bdSNeil Armstrong tx_mode_mux_text); 1616*10f514bdSNeil Armstrong 1617*10f514bdSNeil Armstrong static const struct soc_enum tx2_mode_mux_enum = 1618*10f514bdSNeil Armstrong SOC_ENUM_SINGLE(SND_SOC_NOPM, 2, ARRAY_SIZE(tx_mode_mux_text), 1619*10f514bdSNeil Armstrong tx_mode_mux_text); 1620*10f514bdSNeil Armstrong 1621*10f514bdSNeil Armstrong static const struct soc_enum tx3_mode_mux_enum = 1622*10f514bdSNeil Armstrong SOC_ENUM_SINGLE(SND_SOC_NOPM, 3, ARRAY_SIZE(tx_mode_mux_text), 1623*10f514bdSNeil Armstrong tx_mode_mux_text); 1624*10f514bdSNeil Armstrong 1625*10f514bdSNeil Armstrong static const char * const rx_hph_mode_mux_text_wcd9390[] = { 1626*10f514bdSNeil Armstrong "CLS_H_NORMAL", "CLS_H_INVALID_1", "CLS_H_LP", "CLS_AB", 1627*10f514bdSNeil Armstrong "CLS_H_LOHIFI", "CLS_H_ULP", "CLS_H_INVALID_2", "CLS_AB_LP", 1628*10f514bdSNeil Armstrong "CLS_AB_LOHIFI", 1629*10f514bdSNeil Armstrong }; 1630*10f514bdSNeil Armstrong 1631*10f514bdSNeil Armstrong static const struct soc_enum rx_hph_mode_mux_enum_wcd9390 = 1632*10f514bdSNeil Armstrong SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text_wcd9390), 1633*10f514bdSNeil Armstrong rx_hph_mode_mux_text_wcd9390); 1634*10f514bdSNeil Armstrong 1635*10f514bdSNeil Armstrong static const char * const rx_hph_mode_mux_text[] = { 1636*10f514bdSNeil Armstrong "CLS_H_NORMAL", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", "CLS_H_LOHIFI", 1637*10f514bdSNeil Armstrong "CLS_H_ULP", "CLS_AB_HIFI", "CLS_AB_LP", "CLS_AB_LOHIFI", 1638*10f514bdSNeil Armstrong }; 1639*10f514bdSNeil Armstrong 1640*10f514bdSNeil Armstrong static const struct soc_enum rx_hph_mode_mux_enum = 1641*10f514bdSNeil Armstrong SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), 1642*10f514bdSNeil Armstrong rx_hph_mode_mux_text); 1643*10f514bdSNeil Armstrong 1644*10f514bdSNeil Armstrong static const struct snd_kcontrol_new wcd9390_snd_controls[] = { 1645*10f514bdSNeil Armstrong SOC_SINGLE_TLV("EAR_PA Volume", WCD939X_ANA_EAR_COMPANDER_CTL, 1646*10f514bdSNeil Armstrong 2, 0x10, 0, ear_pa_gain), 1647*10f514bdSNeil Armstrong 1648*10f514bdSNeil Armstrong SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum_wcd9390, 1649*10f514bdSNeil Armstrong wcd939x_rx_hph_mode_get, wcd939x_rx_hph_mode_put), 1650*10f514bdSNeil Armstrong 1651*10f514bdSNeil Armstrong SOC_ENUM_EXT("TX0 MODE", tx0_mode_mux_enum_wcd9390, 1652*10f514bdSNeil Armstrong wcd939x_tx_mode_get, wcd939x_tx_mode_put), 1653*10f514bdSNeil Armstrong SOC_ENUM_EXT("TX1 MODE", tx1_mode_mux_enum_wcd9390, 1654*10f514bdSNeil Armstrong wcd939x_tx_mode_get, wcd939x_tx_mode_put), 1655*10f514bdSNeil Armstrong SOC_ENUM_EXT("TX2 MODE", tx2_mode_mux_enum_wcd9390, 1656*10f514bdSNeil Armstrong wcd939x_tx_mode_get, wcd939x_tx_mode_put), 1657*10f514bdSNeil Armstrong SOC_ENUM_EXT("TX3 MODE", tx3_mode_mux_enum_wcd9390, 1658*10f514bdSNeil Armstrong wcd939x_tx_mode_get, wcd939x_tx_mode_put), 1659*10f514bdSNeil Armstrong }; 1660*10f514bdSNeil Armstrong 1661*10f514bdSNeil Armstrong static const struct snd_kcontrol_new wcd9395_snd_controls[] = { 1662*10f514bdSNeil Armstrong SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum, 1663*10f514bdSNeil Armstrong wcd939x_rx_hph_mode_get, wcd939x_rx_hph_mode_put), 1664*10f514bdSNeil Armstrong 1665*10f514bdSNeil Armstrong SOC_ENUM_EXT("TX0 MODE", tx0_mode_mux_enum, 1666*10f514bdSNeil Armstrong wcd939x_tx_mode_get, wcd939x_tx_mode_put), 1667*10f514bdSNeil Armstrong SOC_ENUM_EXT("TX1 MODE", tx1_mode_mux_enum, 1668*10f514bdSNeil Armstrong wcd939x_tx_mode_get, wcd939x_tx_mode_put), 1669*10f514bdSNeil Armstrong SOC_ENUM_EXT("TX2 MODE", tx2_mode_mux_enum, 1670*10f514bdSNeil Armstrong wcd939x_tx_mode_get, wcd939x_tx_mode_put), 1671*10f514bdSNeil Armstrong SOC_ENUM_EXT("TX3 MODE", tx3_mode_mux_enum, 1672*10f514bdSNeil Armstrong wcd939x_tx_mode_get, wcd939x_tx_mode_put), 1673*10f514bdSNeil Armstrong }; 1674*10f514bdSNeil Armstrong 1675*10f514bdSNeil Armstrong static const struct snd_kcontrol_new adc1_switch[] = { 1676*10f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 1677*10f514bdSNeil Armstrong }; 1678*10f514bdSNeil Armstrong 1679*10f514bdSNeil Armstrong static const struct snd_kcontrol_new adc2_switch[] = { 1680*10f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 1681*10f514bdSNeil Armstrong }; 1682*10f514bdSNeil Armstrong 1683*10f514bdSNeil Armstrong static const struct snd_kcontrol_new adc3_switch[] = { 1684*10f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 1685*10f514bdSNeil Armstrong }; 1686*10f514bdSNeil Armstrong 1687*10f514bdSNeil Armstrong static const struct snd_kcontrol_new adc4_switch[] = { 1688*10f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 1689*10f514bdSNeil Armstrong }; 1690*10f514bdSNeil Armstrong 1691*10f514bdSNeil Armstrong static const struct snd_kcontrol_new dmic1_switch[] = { 1692*10f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 1693*10f514bdSNeil Armstrong }; 1694*10f514bdSNeil Armstrong 1695*10f514bdSNeil Armstrong static const struct snd_kcontrol_new dmic2_switch[] = { 1696*10f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 1697*10f514bdSNeil Armstrong }; 1698*10f514bdSNeil Armstrong 1699*10f514bdSNeil Armstrong static const struct snd_kcontrol_new dmic3_switch[] = { 1700*10f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 1701*10f514bdSNeil Armstrong }; 1702*10f514bdSNeil Armstrong 1703*10f514bdSNeil Armstrong static const struct snd_kcontrol_new dmic4_switch[] = { 1704*10f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 1705*10f514bdSNeil Armstrong }; 1706*10f514bdSNeil Armstrong 1707*10f514bdSNeil Armstrong static const struct snd_kcontrol_new dmic5_switch[] = { 1708*10f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 1709*10f514bdSNeil Armstrong }; 1710*10f514bdSNeil Armstrong 1711*10f514bdSNeil Armstrong static const struct snd_kcontrol_new dmic6_switch[] = { 1712*10f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 1713*10f514bdSNeil Armstrong }; 1714*10f514bdSNeil Armstrong 1715*10f514bdSNeil Armstrong static const struct snd_kcontrol_new dmic7_switch[] = { 1716*10f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 1717*10f514bdSNeil Armstrong }; 1718*10f514bdSNeil Armstrong 1719*10f514bdSNeil Armstrong static const struct snd_kcontrol_new dmic8_switch[] = { 1720*10f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 1721*10f514bdSNeil Armstrong }; 1722*10f514bdSNeil Armstrong 1723*10f514bdSNeil Armstrong static const struct snd_kcontrol_new ear_rdac_switch[] = { 1724*10f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 1725*10f514bdSNeil Armstrong }; 1726*10f514bdSNeil Armstrong 1727*10f514bdSNeil Armstrong static const struct snd_kcontrol_new hphl_rdac_switch[] = { 1728*10f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 1729*10f514bdSNeil Armstrong }; 1730*10f514bdSNeil Armstrong 1731*10f514bdSNeil Armstrong static const struct snd_kcontrol_new hphr_rdac_switch[] = { 1732*10f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 1733*10f514bdSNeil Armstrong }; 1734*10f514bdSNeil Armstrong 1735*10f514bdSNeil Armstrong static const char * const adc1_mux_text[] = { 1736*10f514bdSNeil Armstrong "CH1_AMIC_DISABLE", "CH1_AMIC1", "CH1_AMIC2", "CH1_AMIC3", "CH1_AMIC4", "CH1_AMIC5" 1737*10f514bdSNeil Armstrong }; 1738*10f514bdSNeil Armstrong 1739*10f514bdSNeil Armstrong static const struct soc_enum adc1_enum = 1740*10f514bdSNeil Armstrong SOC_ENUM_SINGLE(WCD939X_TX_NEW_CH12_MUX, 0, 1741*10f514bdSNeil Armstrong ARRAY_SIZE(adc1_mux_text), adc1_mux_text); 1742*10f514bdSNeil Armstrong 1743*10f514bdSNeil Armstrong static const struct snd_kcontrol_new tx_adc1_mux = 1744*10f514bdSNeil Armstrong SOC_DAPM_ENUM("ADC1 MUX Mux", adc1_enum); 1745*10f514bdSNeil Armstrong 1746*10f514bdSNeil Armstrong static const char * const adc2_mux_text[] = { 1747*10f514bdSNeil Armstrong "CH2_AMIC_DISABLE", "CH2_AMIC1", "CH2_AMIC2", "CH2_AMIC3", "CH2_AMIC4", "CH2_AMIC5" 1748*10f514bdSNeil Armstrong }; 1749*10f514bdSNeil Armstrong 1750*10f514bdSNeil Armstrong static const struct soc_enum adc2_enum = 1751*10f514bdSNeil Armstrong SOC_ENUM_SINGLE(WCD939X_TX_NEW_CH12_MUX, 3, 1752*10f514bdSNeil Armstrong ARRAY_SIZE(adc2_mux_text), adc2_mux_text); 1753*10f514bdSNeil Armstrong 1754*10f514bdSNeil Armstrong static const struct snd_kcontrol_new tx_adc2_mux = 1755*10f514bdSNeil Armstrong SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum); 1756*10f514bdSNeil Armstrong 1757*10f514bdSNeil Armstrong static const char * const adc3_mux_text[] = { 1758*10f514bdSNeil Armstrong "CH3_AMIC_DISABLE", "CH3_AMIC1", "CH3_AMIC3", "CH3_AMIC4", "CH3_AMIC5" 1759*10f514bdSNeil Armstrong }; 1760*10f514bdSNeil Armstrong 1761*10f514bdSNeil Armstrong static const struct soc_enum adc3_enum = 1762*10f514bdSNeil Armstrong SOC_ENUM_SINGLE(WCD939X_TX_NEW_CH34_MUX, 0, 1763*10f514bdSNeil Armstrong ARRAY_SIZE(adc3_mux_text), adc3_mux_text); 1764*10f514bdSNeil Armstrong 1765*10f514bdSNeil Armstrong static const struct snd_kcontrol_new tx_adc3_mux = 1766*10f514bdSNeil Armstrong SOC_DAPM_ENUM("ADC3 MUX Mux", adc3_enum); 1767*10f514bdSNeil Armstrong 1768*10f514bdSNeil Armstrong static const char * const adc4_mux_text[] = { 1769*10f514bdSNeil Armstrong "CH4_AMIC_DISABLE", "CH4_AMIC1", "CH4_AMIC3", "CH4_AMIC4", "CH4_AMIC5" 1770*10f514bdSNeil Armstrong }; 1771*10f514bdSNeil Armstrong 1772*10f514bdSNeil Armstrong static const struct soc_enum adc4_enum = 1773*10f514bdSNeil Armstrong SOC_ENUM_SINGLE(WCD939X_TX_NEW_CH34_MUX, 3, 1774*10f514bdSNeil Armstrong ARRAY_SIZE(adc4_mux_text), adc4_mux_text); 1775*10f514bdSNeil Armstrong 1776*10f514bdSNeil Armstrong static const struct snd_kcontrol_new tx_adc4_mux = 1777*10f514bdSNeil Armstrong SOC_DAPM_ENUM("ADC4 MUX Mux", adc4_enum); 1778*10f514bdSNeil Armstrong 1779*10f514bdSNeil Armstrong static const char * const rdac3_mux_text[] = { 1780*10f514bdSNeil Armstrong "RX3", "RX1" 1781*10f514bdSNeil Armstrong }; 1782*10f514bdSNeil Armstrong 1783*10f514bdSNeil Armstrong static const struct soc_enum rdac3_enum = 1784*10f514bdSNeil Armstrong SOC_ENUM_SINGLE(WCD939X_DIGITAL_CDC_EAR_PATH_CTL, 0, 1785*10f514bdSNeil Armstrong ARRAY_SIZE(rdac3_mux_text), rdac3_mux_text); 1786*10f514bdSNeil Armstrong 1787*10f514bdSNeil Armstrong static const struct snd_kcontrol_new rx_rdac3_mux = 1788*10f514bdSNeil Armstrong SOC_DAPM_ENUM("RDAC3_MUX Mux", rdac3_enum); 1789*10f514bdSNeil Armstrong 1790*10f514bdSNeil Armstrong static int wcd939x_get_swr_port(struct snd_kcontrol *kcontrol, 1791*10f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 1792*10f514bdSNeil Armstrong { 1793*10f514bdSNeil Armstrong struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value; 1794*10f514bdSNeil Armstrong struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); 1795*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(comp); 1796*10f514bdSNeil Armstrong struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[mixer->shift]; 1797*10f514bdSNeil Armstrong unsigned int portidx = wcd->ch_info[mixer->reg].port_num; 1798*10f514bdSNeil Armstrong 1799*10f514bdSNeil Armstrong ucontrol->value.integer.value[0] = wcd->port_enable[portidx] ? 1 : 0; 1800*10f514bdSNeil Armstrong 1801*10f514bdSNeil Armstrong return 0; 1802*10f514bdSNeil Armstrong } 1803*10f514bdSNeil Armstrong 1804*10f514bdSNeil Armstrong static const char *version_to_str(u32 version) 1805*10f514bdSNeil Armstrong { 1806*10f514bdSNeil Armstrong switch (version) { 1807*10f514bdSNeil Armstrong case WCD939X_VERSION_1_0: 1808*10f514bdSNeil Armstrong return __stringify(WCD939X_1_0); 1809*10f514bdSNeil Armstrong case WCD939X_VERSION_1_1: 1810*10f514bdSNeil Armstrong return __stringify(WCD939X_1_1); 1811*10f514bdSNeil Armstrong case WCD939X_VERSION_2_0: 1812*10f514bdSNeil Armstrong return __stringify(WCD939X_2_0); 1813*10f514bdSNeil Armstrong } 1814*10f514bdSNeil Armstrong return NULL; 1815*10f514bdSNeil Armstrong } 1816*10f514bdSNeil Armstrong 1817*10f514bdSNeil Armstrong static int wcd939x_set_swr_port(struct snd_kcontrol *kcontrol, 1818*10f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 1819*10f514bdSNeil Armstrong { 1820*10f514bdSNeil Armstrong struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value; 1821*10f514bdSNeil Armstrong struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); 1822*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(comp); 1823*10f514bdSNeil Armstrong struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[mixer->shift]; 1824*10f514bdSNeil Armstrong unsigned int portidx = wcd->ch_info[mixer->reg].port_num; 1825*10f514bdSNeil Armstrong 1826*10f514bdSNeil Armstrong wcd->port_enable[portidx] = !!ucontrol->value.integer.value[0]; 1827*10f514bdSNeil Armstrong 1828*10f514bdSNeil Armstrong wcd939x_connect_port(wcd, portidx, mixer->reg, wcd->port_enable[portidx]); 1829*10f514bdSNeil Armstrong 1830*10f514bdSNeil Armstrong return 1; 1831*10f514bdSNeil Armstrong } 1832*10f514bdSNeil Armstrong 1833*10f514bdSNeil Armstrong /* MBHC Related */ 1834*10f514bdSNeil Armstrong 1835*10f514bdSNeil Armstrong static void wcd939x_mbhc_clk_setup(struct snd_soc_component *component, 1836*10f514bdSNeil Armstrong bool enable) 1837*10f514bdSNeil Armstrong { 1838*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_1, 1839*10f514bdSNeil Armstrong WCD939X_CTL_1_RCO_EN, enable); 1840*10f514bdSNeil Armstrong } 1841*10f514bdSNeil Armstrong 1842*10f514bdSNeil Armstrong static void wcd939x_mbhc_mbhc_bias_control(struct snd_soc_component *component, 1843*10f514bdSNeil Armstrong bool enable) 1844*10f514bdSNeil Armstrong { 1845*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ELECT, 1846*10f514bdSNeil Armstrong WCD939X_MBHC_ELECT_BIAS_EN, enable); 1847*10f514bdSNeil Armstrong } 1848*10f514bdSNeil Armstrong 1849*10f514bdSNeil Armstrong static void wcd939x_mbhc_program_btn_thr(struct snd_soc_component *component, 1850*10f514bdSNeil Armstrong int *btn_low, int *btn_high, 1851*10f514bdSNeil Armstrong int num_btn, bool is_micbias) 1852*10f514bdSNeil Armstrong { 1853*10f514bdSNeil Armstrong int i, vth; 1854*10f514bdSNeil Armstrong 1855*10f514bdSNeil Armstrong if (num_btn > WCD_MBHC_DEF_BUTTONS) { 1856*10f514bdSNeil Armstrong dev_err(component->dev, "%s: invalid number of buttons: %d\n", 1857*10f514bdSNeil Armstrong __func__, num_btn); 1858*10f514bdSNeil Armstrong return; 1859*10f514bdSNeil Armstrong } 1860*10f514bdSNeil Armstrong 1861*10f514bdSNeil Armstrong for (i = 0; i < num_btn; i++) { 1862*10f514bdSNeil Armstrong vth = (btn_high[i] * 2) / 25; 1863*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_BTN0 + i, 1864*10f514bdSNeil Armstrong WCD939X_MBHC_BTN0_VTH, vth); 1865*10f514bdSNeil Armstrong dev_dbg(component->dev, "%s: btn_high[%d]: %d, vth: %d\n", 1866*10f514bdSNeil Armstrong __func__, i, btn_high[i], vth); 1867*10f514bdSNeil Armstrong } 1868*10f514bdSNeil Armstrong } 1869*10f514bdSNeil Armstrong 1870*10f514bdSNeil Armstrong static bool wcd939x_mbhc_micb_en_status(struct snd_soc_component *component, int micb_num) 1871*10f514bdSNeil Armstrong { 1872*10f514bdSNeil Armstrong 1873*10f514bdSNeil Armstrong if (micb_num == MIC_BIAS_2) { 1874*10f514bdSNeil Armstrong u8 val; 1875*10f514bdSNeil Armstrong 1876*10f514bdSNeil Armstrong val = FIELD_GET(WCD939X_MICB2_ENABLE, 1877*10f514bdSNeil Armstrong snd_soc_component_read(component, WCD939X_ANA_MICB2)); 1878*10f514bdSNeil Armstrong if (val == MICB_BIAS_ENABLE) 1879*10f514bdSNeil Armstrong return true; 1880*10f514bdSNeil Armstrong } 1881*10f514bdSNeil Armstrong 1882*10f514bdSNeil Armstrong return false; 1883*10f514bdSNeil Armstrong } 1884*10f514bdSNeil Armstrong 1885*10f514bdSNeil Armstrong static void wcd939x_mbhc_hph_l_pull_up_control(struct snd_soc_component *component, 1886*10f514bdSNeil Armstrong int pull_up_cur) 1887*10f514bdSNeil Armstrong { 1888*10f514bdSNeil Armstrong /* Default pull up current to 2uA */ 1889*10f514bdSNeil Armstrong if (pull_up_cur > HS_PULLUP_I_OFF || 1890*10f514bdSNeil Armstrong pull_up_cur < HS_PULLUP_I_3P0_UA || 1891*10f514bdSNeil Armstrong pull_up_cur == HS_PULLUP_I_DEFAULT) 1892*10f514bdSNeil Armstrong pull_up_cur = HS_PULLUP_I_2P0_UA; 1893*10f514bdSNeil Armstrong 1894*10f514bdSNeil Armstrong dev_dbg(component->dev, "%s: HS pull up current:%d\n", 1895*10f514bdSNeil Armstrong __func__, pull_up_cur); 1896*10f514bdSNeil Armstrong 1897*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_INT_MECH_DET_CURRENT, 1898*10f514bdSNeil Armstrong WCD939X_MECH_DET_CURRENT_HSDET_PULLUP_CTL, pull_up_cur); 1899*10f514bdSNeil Armstrong } 1900*10f514bdSNeil Armstrong 1901*10f514bdSNeil Armstrong static int wcd939x_mbhc_request_micbias(struct snd_soc_component *component, 1902*10f514bdSNeil Armstrong int micb_num, int req) 1903*10f514bdSNeil Armstrong { 1904*10f514bdSNeil Armstrong return wcd939x_micbias_control(component, micb_num, req, false); 1905*10f514bdSNeil Armstrong } 1906*10f514bdSNeil Armstrong 1907*10f514bdSNeil Armstrong static void wcd939x_mbhc_micb_ramp_control(struct snd_soc_component *component, 1908*10f514bdSNeil Armstrong bool enable) 1909*10f514bdSNeil Armstrong { 1910*10f514bdSNeil Armstrong if (enable) { 1911*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MICB2_RAMP, 1912*10f514bdSNeil Armstrong WCD939X_MICB2_RAMP_SHIFT_CTL, 3); 1913*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MICB2_RAMP, 1914*10f514bdSNeil Armstrong WCD939X_MICB2_RAMP_RAMP_ENABLE, true); 1915*10f514bdSNeil Armstrong } else { 1916*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MICB2_RAMP, 1917*10f514bdSNeil Armstrong WCD939X_MICB2_RAMP_RAMP_ENABLE, false); 1918*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MICB2_RAMP, 1919*10f514bdSNeil Armstrong WCD939X_MICB2_RAMP_SHIFT_CTL, 0); 1920*10f514bdSNeil Armstrong } 1921*10f514bdSNeil Armstrong } 1922*10f514bdSNeil Armstrong 1923*10f514bdSNeil Armstrong static int wcd939x_get_micb_vout_ctl_val(u32 micb_mv) 1924*10f514bdSNeil Armstrong { 1925*10f514bdSNeil Armstrong /* min micbias voltage is 1V and maximum is 2.85V */ 1926*10f514bdSNeil Armstrong if (micb_mv < 1000 || micb_mv > 2850) { 1927*10f514bdSNeil Armstrong pr_err("%s: unsupported micbias voltage\n", __func__); 1928*10f514bdSNeil Armstrong return -EINVAL; 1929*10f514bdSNeil Armstrong } 1930*10f514bdSNeil Armstrong 1931*10f514bdSNeil Armstrong return (micb_mv - 1000) / 50; 1932*10f514bdSNeil Armstrong } 1933*10f514bdSNeil Armstrong 1934*10f514bdSNeil Armstrong static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, 1935*10f514bdSNeil Armstrong int req_volt, int micb_num) 1936*10f514bdSNeil Armstrong { 1937*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 1938*10f514bdSNeil Armstrong unsigned int micb_en_field, micb_vout_ctl_field; 1939*10f514bdSNeil Armstrong unsigned int micb_reg, cur_vout_ctl, micb_en; 1940*10f514bdSNeil Armstrong int req_vout_ctl; 1941*10f514bdSNeil Armstrong int ret = 0; 1942*10f514bdSNeil Armstrong 1943*10f514bdSNeil Armstrong switch (micb_num) { 1944*10f514bdSNeil Armstrong case MIC_BIAS_1: 1945*10f514bdSNeil Armstrong micb_reg = WCD939X_ANA_MICB1; 1946*10f514bdSNeil Armstrong micb_en_field = WCD939X_MICB1_ENABLE; 1947*10f514bdSNeil Armstrong micb_vout_ctl_field = WCD939X_MICB1_VOUT_CTL; 1948*10f514bdSNeil Armstrong break; 1949*10f514bdSNeil Armstrong case MIC_BIAS_2: 1950*10f514bdSNeil Armstrong micb_reg = WCD939X_ANA_MICB2; 1951*10f514bdSNeil Armstrong micb_en_field = WCD939X_MICB2_ENABLE; 1952*10f514bdSNeil Armstrong micb_vout_ctl_field = WCD939X_MICB2_VOUT_CTL; 1953*10f514bdSNeil Armstrong break; 1954*10f514bdSNeil Armstrong case MIC_BIAS_3: 1955*10f514bdSNeil Armstrong micb_reg = WCD939X_ANA_MICB3; 1956*10f514bdSNeil Armstrong micb_en_field = WCD939X_MICB3_ENABLE; 1957*10f514bdSNeil Armstrong micb_vout_ctl_field = WCD939X_MICB1_VOUT_CTL; 1958*10f514bdSNeil Armstrong break; 1959*10f514bdSNeil Armstrong case MIC_BIAS_4: 1960*10f514bdSNeil Armstrong micb_reg = WCD939X_ANA_MICB4; 1961*10f514bdSNeil Armstrong micb_en_field = WCD939X_MICB4_ENABLE; 1962*10f514bdSNeil Armstrong micb_vout_ctl_field = WCD939X_MICB2_VOUT_CTL; 1963*10f514bdSNeil Armstrong break; 1964*10f514bdSNeil Armstrong default: 1965*10f514bdSNeil Armstrong return -EINVAL; 1966*10f514bdSNeil Armstrong } 1967*10f514bdSNeil Armstrong mutex_lock(&wcd939x->micb_lock); 1968*10f514bdSNeil Armstrong 1969*10f514bdSNeil Armstrong /* 1970*10f514bdSNeil Armstrong * If requested micbias voltage is same as current micbias 1971*10f514bdSNeil Armstrong * voltage, then just return. Otherwise, adjust voltage as 1972*10f514bdSNeil Armstrong * per requested value. If micbias is already enabled, then 1973*10f514bdSNeil Armstrong * to avoid slow micbias ramp-up or down enable pull-up 1974*10f514bdSNeil Armstrong * momentarily, change the micbias value and then re-enable 1975*10f514bdSNeil Armstrong * micbias. 1976*10f514bdSNeil Armstrong */ 1977*10f514bdSNeil Armstrong micb_en = snd_soc_component_read_field(component, micb_reg, 1978*10f514bdSNeil Armstrong micb_en_field); 1979*10f514bdSNeil Armstrong cur_vout_ctl = snd_soc_component_read_field(component, micb_reg, 1980*10f514bdSNeil Armstrong micb_vout_ctl_field); 1981*10f514bdSNeil Armstrong 1982*10f514bdSNeil Armstrong req_vout_ctl = wcd939x_get_micb_vout_ctl_val(req_volt); 1983*10f514bdSNeil Armstrong if (req_vout_ctl < 0) { 1984*10f514bdSNeil Armstrong ret = req_vout_ctl; 1985*10f514bdSNeil Armstrong goto exit; 1986*10f514bdSNeil Armstrong } 1987*10f514bdSNeil Armstrong 1988*10f514bdSNeil Armstrong if (cur_vout_ctl == req_vout_ctl) { 1989*10f514bdSNeil Armstrong ret = 0; 1990*10f514bdSNeil Armstrong goto exit; 1991*10f514bdSNeil Armstrong } 1992*10f514bdSNeil Armstrong 1993*10f514bdSNeil Armstrong dev_dbg(component->dev, "%s: micb_num: %d, cur_mv: %d, req_mv: %d, micb_en: %d\n", 1994*10f514bdSNeil Armstrong __func__, micb_num, WCD_VOUT_CTL_TO_MICB(cur_vout_ctl), 1995*10f514bdSNeil Armstrong req_volt, micb_en); 1996*10f514bdSNeil Armstrong 1997*10f514bdSNeil Armstrong if (micb_en == MICB_BIAS_ENABLE) 1998*10f514bdSNeil Armstrong snd_soc_component_write_field(component, micb_reg, 1999*10f514bdSNeil Armstrong micb_en_field, MICB_BIAS_PULL_DOWN); 2000*10f514bdSNeil Armstrong 2001*10f514bdSNeil Armstrong snd_soc_component_write_field(component, micb_reg, 2002*10f514bdSNeil Armstrong micb_vout_ctl_field, req_vout_ctl); 2003*10f514bdSNeil Armstrong 2004*10f514bdSNeil Armstrong if (micb_en == MICB_BIAS_ENABLE) { 2005*10f514bdSNeil Armstrong snd_soc_component_write_field(component, micb_reg, 2006*10f514bdSNeil Armstrong micb_en_field, MICB_BIAS_ENABLE); 2007*10f514bdSNeil Armstrong /* 2008*10f514bdSNeil Armstrong * Add 2ms delay as per HW requirement after enabling 2009*10f514bdSNeil Armstrong * micbias 2010*10f514bdSNeil Armstrong */ 2011*10f514bdSNeil Armstrong usleep_range(2000, 2100); 2012*10f514bdSNeil Armstrong } 2013*10f514bdSNeil Armstrong 2014*10f514bdSNeil Armstrong exit: 2015*10f514bdSNeil Armstrong mutex_unlock(&wcd939x->micb_lock); 2016*10f514bdSNeil Armstrong return ret; 2017*10f514bdSNeil Armstrong } 2018*10f514bdSNeil Armstrong 2019*10f514bdSNeil Armstrong static int wcd939x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component, 2020*10f514bdSNeil Armstrong int micb_num, bool req_en) 2021*10f514bdSNeil Armstrong { 2022*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 2023*10f514bdSNeil Armstrong int micb_mv; 2024*10f514bdSNeil Armstrong 2025*10f514bdSNeil Armstrong if (micb_num != MIC_BIAS_2) 2026*10f514bdSNeil Armstrong return -EINVAL; 2027*10f514bdSNeil Armstrong /* 2028*10f514bdSNeil Armstrong * If device tree micbias level is already above the minimum 2029*10f514bdSNeil Armstrong * voltage needed to detect threshold microphone, then do 2030*10f514bdSNeil Armstrong * not change the micbias, just return. 2031*10f514bdSNeil Armstrong */ 2032*10f514bdSNeil Armstrong if (wcd939x->micb2_mv >= WCD_MBHC_THR_HS_MICB_MV) 2033*10f514bdSNeil Armstrong return 0; 2034*10f514bdSNeil Armstrong 2035*10f514bdSNeil Armstrong micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : wcd939x->micb2_mv; 2036*10f514bdSNeil Armstrong 2037*10f514bdSNeil Armstrong return wcd939x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2); 2038*10f514bdSNeil Armstrong } 2039*10f514bdSNeil Armstrong 2040*10f514bdSNeil Armstrong /* Selected by WCD939X_MBHC_GET_C1() */ 2041*10f514bdSNeil Armstrong static const s16 wcd939x_wcd_mbhc_d1_a[4] = { 2042*10f514bdSNeil Armstrong 0, 30, 30, 6 2043*10f514bdSNeil Armstrong }; 2044*10f514bdSNeil Armstrong 2045*10f514bdSNeil Armstrong /* Selected by zdet_param.noff */ 2046*10f514bdSNeil Armstrong static const int wcd939x_mbhc_mincode_param[] = { 2047*10f514bdSNeil Armstrong 3277, 1639, 820, 410, 205, 103, 52, 26 2048*10f514bdSNeil Armstrong }; 2049*10f514bdSNeil Armstrong 2050*10f514bdSNeil Armstrong static const struct zdet_param wcd939x_mbhc_zdet_param = { 2051*10f514bdSNeil Armstrong .ldo_ctl = 4, 2052*10f514bdSNeil Armstrong .noff = 0, 2053*10f514bdSNeil Armstrong .nshift = 6, 2054*10f514bdSNeil Armstrong .btn5 = 0x18, 2055*10f514bdSNeil Armstrong .btn6 = 0x60, 2056*10f514bdSNeil Armstrong .btn7 = 0x78, 2057*10f514bdSNeil Armstrong }; 2058*10f514bdSNeil Armstrong 2059*10f514bdSNeil Armstrong static void wcd939x_mbhc_get_result_params(struct snd_soc_component *component, 2060*10f514bdSNeil Armstrong int32_t *zdet) 2061*10f514bdSNeil Armstrong { 2062*10f514bdSNeil Armstrong const struct zdet_param *zdet_param = &wcd939x_mbhc_zdet_param; 2063*10f514bdSNeil Armstrong s32 x1, d1, denom; 2064*10f514bdSNeil Armstrong int val; 2065*10f514bdSNeil Armstrong s16 c1; 2066*10f514bdSNeil Armstrong int i; 2067*10f514bdSNeil Armstrong 2068*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET, 2069*10f514bdSNeil Armstrong WCD939X_MBHC_ZDET_ZDET_CHG_EN, true); 2070*10f514bdSNeil Armstrong for (i = 0; i < WCD939X_ZDET_NUM_MEASUREMENTS; i++) { 2071*10f514bdSNeil Armstrong val = snd_soc_component_read_field(component, WCD939X_ANA_MBHC_RESULT_2, 2072*10f514bdSNeil Armstrong WCD939X_MBHC_RESULT_2_Z_RESULT_MSB); 2073*10f514bdSNeil Armstrong if (val & BIT(7)) 2074*10f514bdSNeil Armstrong break; 2075*10f514bdSNeil Armstrong } 2076*10f514bdSNeil Armstrong val = val << 8; 2077*10f514bdSNeil Armstrong val |= snd_soc_component_read_field(component, WCD939X_ANA_MBHC_RESULT_1, 2078*10f514bdSNeil Armstrong WCD939X_MBHC_RESULT_1_Z_RESULT_LSB); 2079*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET, 2080*10f514bdSNeil Armstrong WCD939X_MBHC_ZDET_ZDET_CHG_EN, false); 2081*10f514bdSNeil Armstrong x1 = WCD939X_MBHC_GET_X1(val); 2082*10f514bdSNeil Armstrong c1 = WCD939X_MBHC_GET_C1(val); 2083*10f514bdSNeil Armstrong 2084*10f514bdSNeil Armstrong /* If ramp is not complete, give additional 5ms */ 2085*10f514bdSNeil Armstrong if (c1 < 2 && x1) 2086*10f514bdSNeil Armstrong mdelay(5); 2087*10f514bdSNeil Armstrong 2088*10f514bdSNeil Armstrong if (!c1 || !x1) { 2089*10f514bdSNeil Armstrong dev_dbg(component->dev, 2090*10f514bdSNeil Armstrong "%s: Impedance detect ramp error, c1=%d, x1=0x%x\n", 2091*10f514bdSNeil Armstrong __func__, c1, x1); 2092*10f514bdSNeil Armstrong goto ramp_down; 2093*10f514bdSNeil Armstrong } 2094*10f514bdSNeil Armstrong 2095*10f514bdSNeil Armstrong d1 = wcd939x_wcd_mbhc_d1_a[c1]; 2096*10f514bdSNeil Armstrong denom = (x1 * d1) - (1 << (14 - zdet_param->noff)); 2097*10f514bdSNeil Armstrong if (denom > 0) 2098*10f514bdSNeil Armstrong *zdet = (WCD939X_ANA_MBHC_ZDET_CONST * 1000) / denom; 2099*10f514bdSNeil Armstrong else if (x1 < wcd939x_mbhc_mincode_param[zdet_param->noff]) 2100*10f514bdSNeil Armstrong *zdet = WCD939X_ZDET_FLOATING_IMPEDANCE; 2101*10f514bdSNeil Armstrong 2102*10f514bdSNeil Armstrong dev_dbg(component->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n", 2103*10f514bdSNeil Armstrong __func__, d1, c1, x1, *zdet); 2104*10f514bdSNeil Armstrong ramp_down: 2105*10f514bdSNeil Armstrong i = 0; 2106*10f514bdSNeil Armstrong while (x1) { 2107*10f514bdSNeil Armstrong val = snd_soc_component_read_field(component, WCD939X_ANA_MBHC_RESULT_1, 2108*10f514bdSNeil Armstrong WCD939X_MBHC_RESULT_1_Z_RESULT_LSB) << 8; 2109*10f514bdSNeil Armstrong val |= snd_soc_component_read_field(component, WCD939X_ANA_MBHC_RESULT_2, 2110*10f514bdSNeil Armstrong WCD939X_MBHC_RESULT_2_Z_RESULT_MSB); 2111*10f514bdSNeil Armstrong x1 = WCD939X_MBHC_GET_X1(val); 2112*10f514bdSNeil Armstrong i++; 2113*10f514bdSNeil Armstrong if (i == WCD939X_ZDET_NUM_MEASUREMENTS) 2114*10f514bdSNeil Armstrong break; 2115*10f514bdSNeil Armstrong } 2116*10f514bdSNeil Armstrong } 2117*10f514bdSNeil Armstrong 2118*10f514bdSNeil Armstrong static void wcd939x_mbhc_zdet_ramp(struct snd_soc_component *component, 2119*10f514bdSNeil Armstrong s32 *zl, int32_t *zr) 2120*10f514bdSNeil Armstrong { 2121*10f514bdSNeil Armstrong const struct zdet_param *zdet_param = &wcd939x_mbhc_zdet_param; 2122*10f514bdSNeil Armstrong s32 zdet = 0; 2123*10f514bdSNeil Armstrong 2124*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_ZDET_ANA_CTL, 2125*10f514bdSNeil Armstrong WCD939X_ZDET_ANA_CTL_MAXV_CTL, zdet_param->ldo_ctl); 2126*10f514bdSNeil Armstrong snd_soc_component_update_bits(component, WCD939X_ANA_MBHC_BTN5, WCD939X_MBHC_BTN5_VTH, 2127*10f514bdSNeil Armstrong zdet_param->btn5); 2128*10f514bdSNeil Armstrong snd_soc_component_update_bits(component, WCD939X_ANA_MBHC_BTN6, WCD939X_MBHC_BTN6_VTH, 2129*10f514bdSNeil Armstrong zdet_param->btn6); 2130*10f514bdSNeil Armstrong snd_soc_component_update_bits(component, WCD939X_ANA_MBHC_BTN7, WCD939X_MBHC_BTN7_VTH, 2131*10f514bdSNeil Armstrong zdet_param->btn7); 2132*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_ZDET_ANA_CTL, 2133*10f514bdSNeil Armstrong WCD939X_ZDET_ANA_CTL_RANGE_CTL, zdet_param->noff); 2134*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_ZDET_RAMP_CTL, 2135*10f514bdSNeil Armstrong WCD939X_ZDET_RAMP_CTL_TIME_CTL, zdet_param->nshift); 2136*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_ZDET_RAMP_CTL, 2137*10f514bdSNeil Armstrong WCD939X_ZDET_RAMP_CTL_ACC1_MIN_CTL, 6); /*acc1_min_63 */ 2138*10f514bdSNeil Armstrong 2139*10f514bdSNeil Armstrong if (!zl) 2140*10f514bdSNeil Armstrong goto z_right; 2141*10f514bdSNeil Armstrong 2142*10f514bdSNeil Armstrong /* Start impedance measurement for HPH_L */ 2143*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET, 2144*10f514bdSNeil Armstrong WCD939X_MBHC_ZDET_ZDET_L_MEAS_EN, true); 2145*10f514bdSNeil Armstrong dev_dbg(component->dev, "%s: ramp for HPH_L, noff = %d\n", 2146*10f514bdSNeil Armstrong __func__, zdet_param->noff); 2147*10f514bdSNeil Armstrong wcd939x_mbhc_get_result_params(component, &zdet); 2148*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET, 2149*10f514bdSNeil Armstrong WCD939X_MBHC_ZDET_ZDET_L_MEAS_EN, false); 2150*10f514bdSNeil Armstrong 2151*10f514bdSNeil Armstrong *zl = zdet; 2152*10f514bdSNeil Armstrong 2153*10f514bdSNeil Armstrong z_right: 2154*10f514bdSNeil Armstrong if (!zr) 2155*10f514bdSNeil Armstrong return; 2156*10f514bdSNeil Armstrong 2157*10f514bdSNeil Armstrong /* Start impedance measurement for HPH_R */ 2158*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET, 2159*10f514bdSNeil Armstrong WCD939X_MBHC_ZDET_ZDET_R_MEAS_EN, true); 2160*10f514bdSNeil Armstrong dev_dbg(component->dev, "%s: ramp for HPH_R, noff = %d\n", 2161*10f514bdSNeil Armstrong __func__, zdet_param->noff); 2162*10f514bdSNeil Armstrong wcd939x_mbhc_get_result_params(component, &zdet); 2163*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET, 2164*10f514bdSNeil Armstrong WCD939X_MBHC_ZDET_ZDET_R_MEAS_EN, false); 2165*10f514bdSNeil Armstrong 2166*10f514bdSNeil Armstrong *zr = zdet; 2167*10f514bdSNeil Armstrong } 2168*10f514bdSNeil Armstrong 2169*10f514bdSNeil Armstrong static void wcd939x_wcd_mbhc_qfuse_cal(struct snd_soc_component *component, 2170*10f514bdSNeil Armstrong s32 *z_val, int flag_l_r) 2171*10f514bdSNeil Armstrong { 2172*10f514bdSNeil Armstrong int q1_cal; 2173*10f514bdSNeil Armstrong s16 q1; 2174*10f514bdSNeil Armstrong 2175*10f514bdSNeil Armstrong q1 = snd_soc_component_read(component, WCD939X_DIGITAL_EFUSE_REG_21 + flag_l_r); 2176*10f514bdSNeil Armstrong if (q1 & BIT(7)) 2177*10f514bdSNeil Armstrong q1_cal = (10000 - ((q1 & GENMASK(6, 0)) * 10)); 2178*10f514bdSNeil Armstrong else 2179*10f514bdSNeil Armstrong q1_cal = (10000 + (q1 * 10)); 2180*10f514bdSNeil Armstrong 2181*10f514bdSNeil Armstrong if (q1_cal > 0) 2182*10f514bdSNeil Armstrong *z_val = ((*z_val) * 10000) / q1_cal; 2183*10f514bdSNeil Armstrong } 2184*10f514bdSNeil Armstrong 2185*10f514bdSNeil Armstrong static void wcd939x_wcd_mbhc_calc_impedance(struct snd_soc_component *component, 2186*10f514bdSNeil Armstrong u32 *zl, uint32_t *zr) 2187*10f514bdSNeil Armstrong { 2188*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = dev_get_drvdata(component->dev); 2189*10f514bdSNeil Armstrong unsigned int reg0, reg1, reg2, reg3, reg4; 2190*10f514bdSNeil Armstrong int z_mono, z_diff1, z_diff2; 2191*10f514bdSNeil Armstrong bool is_fsm_disable = false; 2192*10f514bdSNeil Armstrong s32 z1l, z1r, z1ls; 2193*10f514bdSNeil Armstrong 2194*10f514bdSNeil Armstrong reg0 = snd_soc_component_read(component, WCD939X_ANA_MBHC_BTN5); 2195*10f514bdSNeil Armstrong reg1 = snd_soc_component_read(component, WCD939X_ANA_MBHC_BTN6); 2196*10f514bdSNeil Armstrong reg2 = snd_soc_component_read(component, WCD939X_ANA_MBHC_BTN7); 2197*10f514bdSNeil Armstrong reg3 = snd_soc_component_read(component, WCD939X_MBHC_CTL_CLK); 2198*10f514bdSNeil Armstrong reg4 = snd_soc_component_read(component, WCD939X_MBHC_NEW_ZDET_ANA_CTL); 2199*10f514bdSNeil Armstrong 2200*10f514bdSNeil Armstrong if (snd_soc_component_read_field(component, WCD939X_ANA_MBHC_ELECT, 2201*10f514bdSNeil Armstrong WCD939X_MBHC_ELECT_FSM_EN)) { 2202*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ELECT, 2203*10f514bdSNeil Armstrong WCD939X_MBHC_ELECT_FSM_EN, false); 2204*10f514bdSNeil Armstrong is_fsm_disable = true; 2205*10f514bdSNeil Armstrong } 2206*10f514bdSNeil Armstrong 2207*10f514bdSNeil Armstrong /* For NO-jack, disable L_DET_EN before Z-det measurements */ 2208*10f514bdSNeil Armstrong if (wcd939x->mbhc_cfg.hphl_swh) 2209*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, 2210*10f514bdSNeil Armstrong WCD939X_MBHC_MECH_L_DET_EN, false); 2211*10f514bdSNeil Armstrong 2212*10f514bdSNeil Armstrong /* Turn off 100k pull down on HPHL */ 2213*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, 2214*10f514bdSNeil Armstrong WCD939X_MBHC_MECH_SW_HPH_L_P_100K_TO_GND, 2215*10f514bdSNeil Armstrong false); 2216*10f514bdSNeil Armstrong 2217*10f514bdSNeil Armstrong /* 2218*10f514bdSNeil Armstrong * Disable surge protection before impedance detection. 2219*10f514bdSNeil Armstrong * This is done to give correct value for high impedance. 2220*10f514bdSNeil Armstrong */ 2221*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN, 2222*10f514bdSNeil Armstrong WCD939X_EN_EN_SURGE_PROTECTION_HPHR, false); 2223*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN, 2224*10f514bdSNeil Armstrong WCD939X_EN_EN_SURGE_PROTECTION_HPHL, false); 2225*10f514bdSNeil Armstrong 2226*10f514bdSNeil Armstrong /* 1ms delay needed after disable surge protection */ 2227*10f514bdSNeil Armstrong usleep_range(1000, 1010); 2228*10f514bdSNeil Armstrong 2229*10f514bdSNeil Armstrong /* First get impedance on Left */ 2230*10f514bdSNeil Armstrong wcd939x_mbhc_zdet_ramp(component, &z1l, NULL); 2231*10f514bdSNeil Armstrong if (z1l == WCD939X_ZDET_FLOATING_IMPEDANCE || z1l > WCD939X_ZDET_VAL_100K) { 2232*10f514bdSNeil Armstrong *zl = WCD939X_ZDET_FLOATING_IMPEDANCE; 2233*10f514bdSNeil Armstrong } else { 2234*10f514bdSNeil Armstrong *zl = z1l / 1000; 2235*10f514bdSNeil Armstrong wcd939x_wcd_mbhc_qfuse_cal(component, zl, 0); 2236*10f514bdSNeil Armstrong } 2237*10f514bdSNeil Armstrong dev_dbg(component->dev, "%s: impedance on HPH_L = %d(ohms)\n", 2238*10f514bdSNeil Armstrong __func__, *zl); 2239*10f514bdSNeil Armstrong 2240*10f514bdSNeil Armstrong /* Start of right impedance ramp and calculation */ 2241*10f514bdSNeil Armstrong wcd939x_mbhc_zdet_ramp(component, NULL, &z1r); 2242*10f514bdSNeil Armstrong if (z1r == WCD939X_ZDET_FLOATING_IMPEDANCE || z1r > WCD939X_ZDET_VAL_100K) { 2243*10f514bdSNeil Armstrong *zr = WCD939X_ZDET_FLOATING_IMPEDANCE; 2244*10f514bdSNeil Armstrong } else { 2245*10f514bdSNeil Armstrong *zr = z1r / 1000; 2246*10f514bdSNeil Armstrong wcd939x_wcd_mbhc_qfuse_cal(component, zr, 1); 2247*10f514bdSNeil Armstrong } 2248*10f514bdSNeil Armstrong dev_dbg(component->dev, "%s: impedance on HPH_R = %d(ohms)\n", 2249*10f514bdSNeil Armstrong __func__, *zr); 2250*10f514bdSNeil Armstrong 2251*10f514bdSNeil Armstrong /* Mono/stereo detection */ 2252*10f514bdSNeil Armstrong if (*zl == WCD939X_ZDET_FLOATING_IMPEDANCE && 2253*10f514bdSNeil Armstrong *zr == WCD939X_ZDET_FLOATING_IMPEDANCE) { 2254*10f514bdSNeil Armstrong dev_dbg(component->dev, 2255*10f514bdSNeil Armstrong "%s: plug type is invalid or extension cable\n", 2256*10f514bdSNeil Armstrong __func__); 2257*10f514bdSNeil Armstrong goto zdet_complete; 2258*10f514bdSNeil Armstrong } 2259*10f514bdSNeil Armstrong 2260*10f514bdSNeil Armstrong if (*zl == WCD939X_ZDET_FLOATING_IMPEDANCE || 2261*10f514bdSNeil Armstrong *zr == WCD939X_ZDET_FLOATING_IMPEDANCE || 2262*10f514bdSNeil Armstrong (*zl < WCD_MONO_HS_MIN_THR && *zr > WCD_MONO_HS_MIN_THR) || 2263*10f514bdSNeil Armstrong (*zl > WCD_MONO_HS_MIN_THR && *zr < WCD_MONO_HS_MIN_THR)) { 2264*10f514bdSNeil Armstrong dev_dbg(component->dev, 2265*10f514bdSNeil Armstrong "%s: Mono plug type with one ch floating or shorted to GND\n", 2266*10f514bdSNeil Armstrong __func__); 2267*10f514bdSNeil Armstrong wcd_mbhc_set_hph_type(wcd939x->wcd_mbhc, WCD_MBHC_HPH_MONO); 2268*10f514bdSNeil Armstrong goto zdet_complete; 2269*10f514bdSNeil Armstrong } 2270*10f514bdSNeil Armstrong 2271*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_R_ATEST, 2272*10f514bdSNeil Armstrong WCD939X_R_ATEST_HPH_GND_OVR, true); 2273*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_PA_CTL2, 2274*10f514bdSNeil Armstrong WCD939X_PA_CTL2_HPHPA_GND_R, true); 2275*10f514bdSNeil Armstrong wcd939x_mbhc_zdet_ramp(component, &z1ls, NULL); 2276*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_PA_CTL2, 2277*10f514bdSNeil Armstrong WCD939X_PA_CTL2_HPHPA_GND_R, false); 2278*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_R_ATEST, 2279*10f514bdSNeil Armstrong WCD939X_R_ATEST_HPH_GND_OVR, false); 2280*10f514bdSNeil Armstrong 2281*10f514bdSNeil Armstrong z1ls /= 1000; 2282*10f514bdSNeil Armstrong wcd939x_wcd_mbhc_qfuse_cal(component, &z1ls, 0); 2283*10f514bdSNeil Armstrong 2284*10f514bdSNeil Armstrong /* Parallel of left Z and 9 ohm pull down resistor */ 2285*10f514bdSNeil Armstrong z_mono = (*zl * 9) / (*zl + 9); 2286*10f514bdSNeil Armstrong z_diff1 = z1ls > z_mono ? z1ls - z_mono : z_mono - z1ls; 2287*10f514bdSNeil Armstrong z_diff2 = *zl > z1ls ? *zl - z1ls : z1ls - *zl; 2288*10f514bdSNeil Armstrong if ((z_diff1 * (*zl + z1ls)) > (z_diff2 * (z1ls + z_mono))) { 2289*10f514bdSNeil Armstrong dev_dbg(component->dev, "%s: stereo plug type detected\n", 2290*10f514bdSNeil Armstrong __func__); 2291*10f514bdSNeil Armstrong wcd_mbhc_set_hph_type(wcd939x->wcd_mbhc, WCD_MBHC_HPH_STEREO); 2292*10f514bdSNeil Armstrong } else { 2293*10f514bdSNeil Armstrong dev_dbg(component->dev, "%s: MONO plug type detected\n", 2294*10f514bdSNeil Armstrong __func__); 2295*10f514bdSNeil Armstrong wcd_mbhc_set_hph_type(wcd939x->wcd_mbhc, WCD_MBHC_HPH_MONO); 2296*10f514bdSNeil Armstrong } 2297*10f514bdSNeil Armstrong 2298*10f514bdSNeil Armstrong /* Enable surge protection again after impedance detection */ 2299*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN, 2300*10f514bdSNeil Armstrong WCD939X_EN_EN_SURGE_PROTECTION_HPHR, true); 2301*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN, 2302*10f514bdSNeil Armstrong WCD939X_EN_EN_SURGE_PROTECTION_HPHL, true); 2303*10f514bdSNeil Armstrong 2304*10f514bdSNeil Armstrong zdet_complete: 2305*10f514bdSNeil Armstrong snd_soc_component_write(component, WCD939X_ANA_MBHC_BTN5, reg0); 2306*10f514bdSNeil Armstrong snd_soc_component_write(component, WCD939X_ANA_MBHC_BTN6, reg1); 2307*10f514bdSNeil Armstrong snd_soc_component_write(component, WCD939X_ANA_MBHC_BTN7, reg2); 2308*10f514bdSNeil Armstrong 2309*10f514bdSNeil Armstrong /* Turn on 100k pull down on HPHL */ 2310*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, 2311*10f514bdSNeil Armstrong WCD939X_MBHC_MECH_SW_HPH_L_P_100K_TO_GND, true); 2312*10f514bdSNeil Armstrong 2313*10f514bdSNeil Armstrong /* For NO-jack, re-enable L_DET_EN after Z-det measurements */ 2314*10f514bdSNeil Armstrong if (wcd939x->mbhc_cfg.hphl_swh) 2315*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, 2316*10f514bdSNeil Armstrong WCD939X_MBHC_MECH_L_DET_EN, true); 2317*10f514bdSNeil Armstrong 2318*10f514bdSNeil Armstrong snd_soc_component_write(component, WCD939X_MBHC_NEW_ZDET_ANA_CTL, reg4); 2319*10f514bdSNeil Armstrong snd_soc_component_write(component, WCD939X_MBHC_CTL_CLK, reg3); 2320*10f514bdSNeil Armstrong 2321*10f514bdSNeil Armstrong if (is_fsm_disable) 2322*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ELECT, 2323*10f514bdSNeil Armstrong WCD939X_MBHC_ELECT_FSM_EN, true); 2324*10f514bdSNeil Armstrong } 2325*10f514bdSNeil Armstrong 2326*10f514bdSNeil Armstrong static void wcd939x_mbhc_gnd_det_ctrl(struct snd_soc_component *component, 2327*10f514bdSNeil Armstrong bool enable) 2328*10f514bdSNeil Armstrong { 2329*10f514bdSNeil Armstrong if (enable) { 2330*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, 2331*10f514bdSNeil Armstrong WCD939X_MBHC_MECH_MECH_HS_G_PULLUP_COMP_EN, 2332*10f514bdSNeil Armstrong true); 2333*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, 2334*10f514bdSNeil Armstrong WCD939X_MBHC_MECH_GND_DET_EN, true); 2335*10f514bdSNeil Armstrong } else { 2336*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, 2337*10f514bdSNeil Armstrong WCD939X_MBHC_MECH_GND_DET_EN, false); 2338*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, 2339*10f514bdSNeil Armstrong WCD939X_MBHC_MECH_MECH_HS_G_PULLUP_COMP_EN, 2340*10f514bdSNeil Armstrong false); 2341*10f514bdSNeil Armstrong } 2342*10f514bdSNeil Armstrong } 2343*10f514bdSNeil Armstrong 2344*10f514bdSNeil Armstrong static void wcd939x_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component, 2345*10f514bdSNeil Armstrong bool enable) 2346*10f514bdSNeil Armstrong { 2347*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_PA_CTL2, 2348*10f514bdSNeil Armstrong WCD939X_PA_CTL2_HPHPA_GND_R, enable); 2349*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_PA_CTL2, 2350*10f514bdSNeil Armstrong WCD939X_PA_CTL2_HPHPA_GND_L, enable); 2351*10f514bdSNeil Armstrong } 2352*10f514bdSNeil Armstrong 2353*10f514bdSNeil Armstrong static void wcd939x_mbhc_moisture_config(struct snd_soc_component *component) 2354*10f514bdSNeil Armstrong { 2355*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 2356*10f514bdSNeil Armstrong 2357*10f514bdSNeil Armstrong if (wcd939x->mbhc_cfg.moist_rref == R_OFF || wcd939x->typec_analog_mux) { 2358*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2, 2359*10f514bdSNeil Armstrong WCD939X_CTL_2_M_RTH_CTL, R_OFF); 2360*10f514bdSNeil Armstrong return; 2361*10f514bdSNeil Armstrong } 2362*10f514bdSNeil Armstrong 2363*10f514bdSNeil Armstrong /* Do not enable moisture detection if jack type is NC */ 2364*10f514bdSNeil Armstrong if (!wcd939x->mbhc_cfg.hphl_swh) { 2365*10f514bdSNeil Armstrong dev_dbg(component->dev, "%s: disable moisture detection for NC\n", 2366*10f514bdSNeil Armstrong __func__); 2367*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2, 2368*10f514bdSNeil Armstrong WCD939X_CTL_2_M_RTH_CTL, R_OFF); 2369*10f514bdSNeil Armstrong return; 2370*10f514bdSNeil Armstrong } 2371*10f514bdSNeil Armstrong 2372*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2, 2373*10f514bdSNeil Armstrong WCD939X_CTL_2_M_RTH_CTL, wcd939x->mbhc_cfg.moist_rref); 2374*10f514bdSNeil Armstrong } 2375*10f514bdSNeil Armstrong 2376*10f514bdSNeil Armstrong static void wcd939x_mbhc_moisture_detect_en(struct snd_soc_component *component, bool enable) 2377*10f514bdSNeil Armstrong { 2378*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 2379*10f514bdSNeil Armstrong 2380*10f514bdSNeil Armstrong if (enable) 2381*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2, 2382*10f514bdSNeil Armstrong WCD939X_CTL_2_M_RTH_CTL, 2383*10f514bdSNeil Armstrong wcd939x->mbhc_cfg.moist_rref); 2384*10f514bdSNeil Armstrong else 2385*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2, 2386*10f514bdSNeil Armstrong WCD939X_CTL_2_M_RTH_CTL, R_OFF); 2387*10f514bdSNeil Armstrong } 2388*10f514bdSNeil Armstrong 2389*10f514bdSNeil Armstrong static bool wcd939x_mbhc_get_moisture_status(struct snd_soc_component *component) 2390*10f514bdSNeil Armstrong { 2391*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 2392*10f514bdSNeil Armstrong bool ret = false; 2393*10f514bdSNeil Armstrong 2394*10f514bdSNeil Armstrong if (wcd939x->mbhc_cfg.moist_rref == R_OFF || wcd939x->typec_analog_mux) { 2395*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2, 2396*10f514bdSNeil Armstrong WCD939X_CTL_2_M_RTH_CTL, R_OFF); 2397*10f514bdSNeil Armstrong goto done; 2398*10f514bdSNeil Armstrong } 2399*10f514bdSNeil Armstrong 2400*10f514bdSNeil Armstrong /* Do not enable moisture detection if jack type is NC */ 2401*10f514bdSNeil Armstrong if (!wcd939x->mbhc_cfg.hphl_swh) { 2402*10f514bdSNeil Armstrong dev_dbg(component->dev, "%s: disable moisture detection for NC\n", 2403*10f514bdSNeil Armstrong __func__); 2404*10f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2, 2405*10f514bdSNeil Armstrong WCD939X_CTL_2_M_RTH_CTL, R_OFF); 2406*10f514bdSNeil Armstrong goto done; 2407*10f514bdSNeil Armstrong } 2408*10f514bdSNeil Armstrong 2409*10f514bdSNeil Armstrong /* 2410*10f514bdSNeil Armstrong * If moisture_en is already enabled, then skip to plug type 2411*10f514bdSNeil Armstrong * detection. 2412*10f514bdSNeil Armstrong */ 2413*10f514bdSNeil Armstrong if (snd_soc_component_read_field(component, WCD939X_MBHC_NEW_CTL_2, 2414*10f514bdSNeil Armstrong WCD939X_CTL_2_M_RTH_CTL)) 2415*10f514bdSNeil Armstrong goto done; 2416*10f514bdSNeil Armstrong 2417*10f514bdSNeil Armstrong wcd939x_mbhc_moisture_detect_en(component, true); 2418*10f514bdSNeil Armstrong 2419*10f514bdSNeil Armstrong /* Read moisture comparator status, invert of status bit */ 2420*10f514bdSNeil Armstrong ret = !snd_soc_component_read_field(component, WCD939X_MBHC_NEW_FSM_STATUS, 2421*10f514bdSNeil Armstrong WCD939X_FSM_STATUS_HS_M_COMP_STATUS); 2422*10f514bdSNeil Armstrong done: 2423*10f514bdSNeil Armstrong return ret; 2424*10f514bdSNeil Armstrong } 2425*10f514bdSNeil Armstrong 2426*10f514bdSNeil Armstrong static void wcd939x_mbhc_moisture_polling_ctrl(struct snd_soc_component *component, 2427*10f514bdSNeil Armstrong bool enable) 2428*10f514bdSNeil Armstrong { 2429*10f514bdSNeil Armstrong snd_soc_component_write_field(component, 2430*10f514bdSNeil Armstrong WCD939X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, 2431*10f514bdSNeil Armstrong WCD939X_MOISTURE_DET_POLLING_CTRL_MOIST_EN_POLLING, 2432*10f514bdSNeil Armstrong enable); 2433*10f514bdSNeil Armstrong } 2434*10f514bdSNeil Armstrong 2435*10f514bdSNeil Armstrong static const struct wcd_mbhc_cb mbhc_cb = { 2436*10f514bdSNeil Armstrong .clk_setup = wcd939x_mbhc_clk_setup, 2437*10f514bdSNeil Armstrong .mbhc_bias = wcd939x_mbhc_mbhc_bias_control, 2438*10f514bdSNeil Armstrong .set_btn_thr = wcd939x_mbhc_program_btn_thr, 2439*10f514bdSNeil Armstrong .micbias_enable_status = wcd939x_mbhc_micb_en_status, 2440*10f514bdSNeil Armstrong .hph_pull_up_control_v2 = wcd939x_mbhc_hph_l_pull_up_control, 2441*10f514bdSNeil Armstrong .mbhc_micbias_control = wcd939x_mbhc_request_micbias, 2442*10f514bdSNeil Armstrong .mbhc_micb_ramp_control = wcd939x_mbhc_micb_ramp_control, 2443*10f514bdSNeil Armstrong .mbhc_micb_ctrl_thr_mic = wcd939x_mbhc_micb_ctrl_threshold_mic, 2444*10f514bdSNeil Armstrong .compute_impedance = wcd939x_wcd_mbhc_calc_impedance, 2445*10f514bdSNeil Armstrong .mbhc_gnd_det_ctrl = wcd939x_mbhc_gnd_det_ctrl, 2446*10f514bdSNeil Armstrong .hph_pull_down_ctrl = wcd939x_mbhc_hph_pull_down_ctrl, 2447*10f514bdSNeil Armstrong .mbhc_moisture_config = wcd939x_mbhc_moisture_config, 2448*10f514bdSNeil Armstrong .mbhc_get_moisture_status = wcd939x_mbhc_get_moisture_status, 2449*10f514bdSNeil Armstrong .mbhc_moisture_polling_ctrl = wcd939x_mbhc_moisture_polling_ctrl, 2450*10f514bdSNeil Armstrong .mbhc_moisture_detect_en = wcd939x_mbhc_moisture_detect_en, 2451*10f514bdSNeil Armstrong }; 2452*10f514bdSNeil Armstrong 2453*10f514bdSNeil Armstrong static int wcd939x_get_hph_type(struct snd_kcontrol *kcontrol, 2454*10f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 2455*10f514bdSNeil Armstrong { 2456*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 2457*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 2458*10f514bdSNeil Armstrong 2459*10f514bdSNeil Armstrong ucontrol->value.integer.value[0] = wcd_mbhc_get_hph_type(wcd939x->wcd_mbhc); 2460*10f514bdSNeil Armstrong 2461*10f514bdSNeil Armstrong return 0; 2462*10f514bdSNeil Armstrong } 2463*10f514bdSNeil Armstrong 2464*10f514bdSNeil Armstrong static int wcd939x_hph_impedance_get(struct snd_kcontrol *kcontrol, 2465*10f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 2466*10f514bdSNeil Armstrong { 2467*10f514bdSNeil Armstrong struct soc_mixer_control *mc = (struct soc_mixer_control *)(kcontrol->private_value); 2468*10f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 2469*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 2470*10f514bdSNeil Armstrong bool hphr = mc->shift; 2471*10f514bdSNeil Armstrong u32 zl, zr; 2472*10f514bdSNeil Armstrong 2473*10f514bdSNeil Armstrong wcd_mbhc_get_impedance(wcd939x->wcd_mbhc, &zl, &zr); 2474*10f514bdSNeil Armstrong dev_dbg(component->dev, "%s: zl=%u(ohms), zr=%u(ohms)\n", __func__, zl, zr); 2475*10f514bdSNeil Armstrong ucontrol->value.integer.value[0] = hphr ? zr : zl; 2476*10f514bdSNeil Armstrong 2477*10f514bdSNeil Armstrong return 0; 2478*10f514bdSNeil Armstrong } 2479*10f514bdSNeil Armstrong 2480*10f514bdSNeil Armstrong static const struct snd_kcontrol_new hph_type_detect_controls[] = { 2481*10f514bdSNeil Armstrong SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0, 2482*10f514bdSNeil Armstrong wcd939x_get_hph_type, NULL), 2483*10f514bdSNeil Armstrong }; 2484*10f514bdSNeil Armstrong 2485*10f514bdSNeil Armstrong static const struct snd_kcontrol_new impedance_detect_controls[] = { 2486*10f514bdSNeil Armstrong SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0, 2487*10f514bdSNeil Armstrong wcd939x_hph_impedance_get, NULL), 2488*10f514bdSNeil Armstrong SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0, 2489*10f514bdSNeil Armstrong wcd939x_hph_impedance_get, NULL), 2490*10f514bdSNeil Armstrong }; 2491*10f514bdSNeil Armstrong 2492*10f514bdSNeil Armstrong static int wcd939x_mbhc_init(struct snd_soc_component *component) 2493*10f514bdSNeil Armstrong { 2494*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 2495*10f514bdSNeil Armstrong struct wcd_mbhc_intr *intr_ids = &wcd939x->intr_ids; 2496*10f514bdSNeil Armstrong 2497*10f514bdSNeil Armstrong intr_ids->mbhc_sw_intr = regmap_irq_get_virq(wcd939x->irq_chip, 2498*10f514bdSNeil Armstrong WCD939X_IRQ_MBHC_SW_DET); 2499*10f514bdSNeil Armstrong intr_ids->mbhc_btn_press_intr = regmap_irq_get_virq(wcd939x->irq_chip, 2500*10f514bdSNeil Armstrong WCD939X_IRQ_MBHC_BUTTON_PRESS_DET); 2501*10f514bdSNeil Armstrong intr_ids->mbhc_btn_release_intr = regmap_irq_get_virq(wcd939x->irq_chip, 2502*10f514bdSNeil Armstrong WCD939X_IRQ_MBHC_BUTTON_RELEASE_DET); 2503*10f514bdSNeil Armstrong intr_ids->mbhc_hs_ins_intr = regmap_irq_get_virq(wcd939x->irq_chip, 2504*10f514bdSNeil Armstrong WCD939X_IRQ_MBHC_ELECT_INS_REM_LEG_DET); 2505*10f514bdSNeil Armstrong intr_ids->mbhc_hs_rem_intr = regmap_irq_get_virq(wcd939x->irq_chip, 2506*10f514bdSNeil Armstrong WCD939X_IRQ_MBHC_ELECT_INS_REM_DET); 2507*10f514bdSNeil Armstrong intr_ids->hph_left_ocp = regmap_irq_get_virq(wcd939x->irq_chip, 2508*10f514bdSNeil Armstrong WCD939X_IRQ_HPHL_OCP_INT); 2509*10f514bdSNeil Armstrong intr_ids->hph_right_ocp = regmap_irq_get_virq(wcd939x->irq_chip, 2510*10f514bdSNeil Armstrong WCD939X_IRQ_HPHR_OCP_INT); 2511*10f514bdSNeil Armstrong 2512*10f514bdSNeil Armstrong wcd939x->wcd_mbhc = wcd_mbhc_init(component, &mbhc_cb, intr_ids, wcd_mbhc_fields, true); 2513*10f514bdSNeil Armstrong if (IS_ERR(wcd939x->wcd_mbhc)) 2514*10f514bdSNeil Armstrong return PTR_ERR(wcd939x->wcd_mbhc); 2515*10f514bdSNeil Armstrong 2516*10f514bdSNeil Armstrong snd_soc_add_component_controls(component, impedance_detect_controls, 2517*10f514bdSNeil Armstrong ARRAY_SIZE(impedance_detect_controls)); 2518*10f514bdSNeil Armstrong snd_soc_add_component_controls(component, hph_type_detect_controls, 2519*10f514bdSNeil Armstrong ARRAY_SIZE(hph_type_detect_controls)); 2520*10f514bdSNeil Armstrong 2521*10f514bdSNeil Armstrong return 0; 2522*10f514bdSNeil Armstrong } 2523*10f514bdSNeil Armstrong 2524*10f514bdSNeil Armstrong static void wcd939x_mbhc_deinit(struct snd_soc_component *component) 2525*10f514bdSNeil Armstrong { 2526*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 2527*10f514bdSNeil Armstrong 2528*10f514bdSNeil Armstrong wcd_mbhc_deinit(wcd939x->wcd_mbhc); 2529*10f514bdSNeil Armstrong } 2530*10f514bdSNeil Armstrong 2531*10f514bdSNeil Armstrong /* END MBHC */ 2532*10f514bdSNeil Armstrong 2533*10f514bdSNeil Armstrong static const struct snd_kcontrol_new wcd939x_snd_controls[] = { 2534*10f514bdSNeil Armstrong /* RX Path */ 2535*10f514bdSNeil Armstrong SOC_SINGLE_EXT("HPHL_COMP Switch", WCD939X_COMP_L, 0, 1, 0, 2536*10f514bdSNeil Armstrong wcd939x_get_compander, wcd939x_set_compander), 2537*10f514bdSNeil Armstrong SOC_SINGLE_EXT("HPHR_COMP Switch", WCD939X_COMP_R, 1, 1, 0, 2538*10f514bdSNeil Armstrong wcd939x_get_compander, wcd939x_set_compander), 2539*10f514bdSNeil Armstrong SOC_SINGLE_EXT("HPHL Switch", WCD939X_HPH_L, 0, 1, 0, 2540*10f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 2541*10f514bdSNeil Armstrong SOC_SINGLE_EXT("HPHR Switch", WCD939X_HPH_R, 0, 1, 0, 2542*10f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 2543*10f514bdSNeil Armstrong SOC_SINGLE_EXT("CLSH Switch", WCD939X_CLSH, 0, 1, 0, 2544*10f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 2545*10f514bdSNeil Armstrong SOC_SINGLE_EXT("LO Switch", WCD939X_LO, 0, 1, 0, 2546*10f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 2547*10f514bdSNeil Armstrong SOC_SINGLE_EXT("DSD_L Switch", WCD939X_DSD_L, 0, 1, 0, 2548*10f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 2549*10f514bdSNeil Armstrong SOC_SINGLE_EXT("DSD_R Switch", WCD939X_DSD_R, 0, 1, 0, 2550*10f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 2551*10f514bdSNeil Armstrong SOC_SINGLE_TLV("HPHL Volume", WCD939X_HPH_L_EN, 0, 20, 1, line_gain), 2552*10f514bdSNeil Armstrong SOC_SINGLE_TLV("HPHR Volume", WCD939X_HPH_R_EN, 0, 20, 1, line_gain), 2553*10f514bdSNeil Armstrong SOC_SINGLE_EXT("LDOH Enable Switch", SND_SOC_NOPM, 0, 1, 0, 2554*10f514bdSNeil Armstrong wcd939x_ldoh_get, wcd939x_ldoh_put), 2555*10f514bdSNeil Armstrong 2556*10f514bdSNeil Armstrong /* TX Path */ 2557*10f514bdSNeil Armstrong SOC_SINGLE_EXT("ADC1 Switch", WCD939X_ADC1, 1, 1, 0, 2558*10f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 2559*10f514bdSNeil Armstrong SOC_SINGLE_EXT("ADC2 Switch", WCD939X_ADC2, 1, 1, 0, 2560*10f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 2561*10f514bdSNeil Armstrong SOC_SINGLE_EXT("ADC3 Switch", WCD939X_ADC3, 1, 1, 0, 2562*10f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 2563*10f514bdSNeil Armstrong SOC_SINGLE_EXT("ADC4 Switch", WCD939X_ADC4, 1, 1, 0, 2564*10f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 2565*10f514bdSNeil Armstrong SOC_SINGLE_EXT("DMIC0 Switch", WCD939X_DMIC0, 1, 1, 0, 2566*10f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 2567*10f514bdSNeil Armstrong SOC_SINGLE_EXT("DMIC1 Switch", WCD939X_DMIC1, 1, 1, 0, 2568*10f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 2569*10f514bdSNeil Armstrong SOC_SINGLE_EXT("MBHC Switch", WCD939X_MBHC, 1, 1, 0, 2570*10f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 2571*10f514bdSNeil Armstrong SOC_SINGLE_EXT("DMIC2 Switch", WCD939X_DMIC2, 1, 1, 0, 2572*10f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 2573*10f514bdSNeil Armstrong SOC_SINGLE_EXT("DMIC3 Switch", WCD939X_DMIC3, 1, 1, 0, 2574*10f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 2575*10f514bdSNeil Armstrong SOC_SINGLE_EXT("DMIC4 Switch", WCD939X_DMIC4, 1, 1, 0, 2576*10f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 2577*10f514bdSNeil Armstrong SOC_SINGLE_EXT("DMIC5 Switch", WCD939X_DMIC5, 1, 1, 0, 2578*10f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 2579*10f514bdSNeil Armstrong SOC_SINGLE_EXT("DMIC6 Switch", WCD939X_DMIC6, 1, 1, 0, 2580*10f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 2581*10f514bdSNeil Armstrong SOC_SINGLE_EXT("DMIC7 Switch", WCD939X_DMIC7, 1, 1, 0, 2582*10f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 2583*10f514bdSNeil Armstrong SOC_SINGLE_TLV("ADC1 Volume", WCD939X_ANA_TX_CH1, 0, 20, 0, 2584*10f514bdSNeil Armstrong analog_gain), 2585*10f514bdSNeil Armstrong SOC_SINGLE_TLV("ADC2 Volume", WCD939X_ANA_TX_CH2, 0, 20, 0, 2586*10f514bdSNeil Armstrong analog_gain), 2587*10f514bdSNeil Armstrong SOC_SINGLE_TLV("ADC3 Volume", WCD939X_ANA_TX_CH3, 0, 20, 0, 2588*10f514bdSNeil Armstrong analog_gain), 2589*10f514bdSNeil Armstrong SOC_SINGLE_TLV("ADC4 Volume", WCD939X_ANA_TX_CH4, 0, 20, 0, 2590*10f514bdSNeil Armstrong analog_gain), 2591*10f514bdSNeil Armstrong }; 2592*10f514bdSNeil Armstrong 2593*10f514bdSNeil Armstrong static const struct snd_soc_dapm_widget wcd939x_dapm_widgets[] = { 2594*10f514bdSNeil Armstrong /*input widgets*/ 2595*10f514bdSNeil Armstrong SND_SOC_DAPM_INPUT("AMIC1"), 2596*10f514bdSNeil Armstrong SND_SOC_DAPM_INPUT("AMIC2"), 2597*10f514bdSNeil Armstrong SND_SOC_DAPM_INPUT("AMIC3"), 2598*10f514bdSNeil Armstrong SND_SOC_DAPM_INPUT("AMIC4"), 2599*10f514bdSNeil Armstrong SND_SOC_DAPM_INPUT("AMIC5"), 2600*10f514bdSNeil Armstrong 2601*10f514bdSNeil Armstrong SND_SOC_DAPM_MIC("Analog Mic1", NULL), 2602*10f514bdSNeil Armstrong SND_SOC_DAPM_MIC("Analog Mic2", NULL), 2603*10f514bdSNeil Armstrong SND_SOC_DAPM_MIC("Analog Mic3", NULL), 2604*10f514bdSNeil Armstrong SND_SOC_DAPM_MIC("Analog Mic4", NULL), 2605*10f514bdSNeil Armstrong SND_SOC_DAPM_MIC("Analog Mic5", NULL), 2606*10f514bdSNeil Armstrong 2607*10f514bdSNeil Armstrong /* TX widgets */ 2608*10f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("ADC1", NULL, SND_SOC_NOPM, 0, 0, 2609*10f514bdSNeil Armstrong wcd939x_codec_enable_adc, 2610*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2611*10f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("ADC2", NULL, SND_SOC_NOPM, 1, 0, 2612*10f514bdSNeil Armstrong wcd939x_codec_enable_adc, 2613*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2614*10f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("ADC3", NULL, SND_SOC_NOPM, 2, 0, 2615*10f514bdSNeil Armstrong wcd939x_codec_enable_adc, 2616*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2617*10f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("ADC4", NULL, SND_SOC_NOPM, 3, 0, 2618*10f514bdSNeil Armstrong wcd939x_codec_enable_adc, 2619*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2620*10f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, 2621*10f514bdSNeil Armstrong wcd939x_codec_enable_dmic, 2622*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2623*10f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 1, 0, 2624*10f514bdSNeil Armstrong wcd939x_codec_enable_dmic, 2625*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2626*10f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 2, 0, 2627*10f514bdSNeil Armstrong wcd939x_codec_enable_dmic, 2628*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2629*10f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 3, 0, 2630*10f514bdSNeil Armstrong wcd939x_codec_enable_dmic, 2631*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2632*10f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 4, 0, 2633*10f514bdSNeil Armstrong wcd939x_codec_enable_dmic, 2634*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2635*10f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 5, 0, 2636*10f514bdSNeil Armstrong wcd939x_codec_enable_dmic, 2637*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2638*10f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("DMIC7", NULL, SND_SOC_NOPM, 6, 0, 2639*10f514bdSNeil Armstrong wcd939x_codec_enable_dmic, 2640*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2641*10f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("DMIC8", NULL, SND_SOC_NOPM, 7, 0, 2642*10f514bdSNeil Armstrong wcd939x_codec_enable_dmic, 2643*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2644*10f514bdSNeil Armstrong 2645*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("ADC1 REQ", SND_SOC_NOPM, 0, 0, NULL, 0, 2646*10f514bdSNeil Armstrong wcd939x_adc_enable_req, 2647*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2648*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("ADC2 REQ", SND_SOC_NOPM, 1, 0, NULL, 0, 2649*10f514bdSNeil Armstrong wcd939x_adc_enable_req, 2650*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2651*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("ADC3 REQ", SND_SOC_NOPM, 2, 0, NULL, 0, 2652*10f514bdSNeil Armstrong wcd939x_adc_enable_req, 2653*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2654*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("ADC4 REQ", SND_SOC_NOPM, 3, 0, NULL, 0, 2655*10f514bdSNeil Armstrong wcd939x_adc_enable_req, 2656*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2657*10f514bdSNeil Armstrong 2658*10f514bdSNeil Armstrong SND_SOC_DAPM_MUX("ADC1 MUX", SND_SOC_NOPM, 0, 0, &tx_adc1_mux), 2659*10f514bdSNeil Armstrong SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, &tx_adc2_mux), 2660*10f514bdSNeil Armstrong SND_SOC_DAPM_MUX("ADC3 MUX", SND_SOC_NOPM, 0, 0, &tx_adc3_mux), 2661*10f514bdSNeil Armstrong SND_SOC_DAPM_MUX("ADC4 MUX", SND_SOC_NOPM, 0, 0, &tx_adc4_mux), 2662*10f514bdSNeil Armstrong 2663*10f514bdSNeil Armstrong /* tx mixers */ 2664*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("ADC1_MIXER", SND_SOC_NOPM, 0, 0, 2665*10f514bdSNeil Armstrong adc1_switch, ARRAY_SIZE(adc1_switch), wcd939x_tx_swr_ctrl, 2666*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2667*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("ADC2_MIXER", SND_SOC_NOPM, 0, 0, 2668*10f514bdSNeil Armstrong adc2_switch, ARRAY_SIZE(adc2_switch), wcd939x_tx_swr_ctrl, 2669*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2670*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("ADC3_MIXER", SND_SOC_NOPM, 0, 0, 2671*10f514bdSNeil Armstrong adc3_switch, ARRAY_SIZE(adc3_switch), wcd939x_tx_swr_ctrl, 2672*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2673*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("ADC4_MIXER", SND_SOC_NOPM, 0, 0, 2674*10f514bdSNeil Armstrong adc4_switch, ARRAY_SIZE(adc4_switch), wcd939x_tx_swr_ctrl, 2675*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2676*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, 0, 0, 2677*10f514bdSNeil Armstrong dmic1_switch, ARRAY_SIZE(dmic1_switch), wcd939x_tx_swr_ctrl, 2678*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2679*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("DMIC2_MIXER", SND_SOC_NOPM, 0, 0, 2680*10f514bdSNeil Armstrong dmic2_switch, ARRAY_SIZE(dmic2_switch), wcd939x_tx_swr_ctrl, 2681*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2682*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("DMIC3_MIXER", SND_SOC_NOPM, 0, 0, 2683*10f514bdSNeil Armstrong dmic3_switch, ARRAY_SIZE(dmic3_switch), wcd939x_tx_swr_ctrl, 2684*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2685*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("DMIC4_MIXER", SND_SOC_NOPM, 0, 0, 2686*10f514bdSNeil Armstrong dmic4_switch, ARRAY_SIZE(dmic4_switch), wcd939x_tx_swr_ctrl, 2687*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2688*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("DMIC5_MIXER", SND_SOC_NOPM, 0, 0, 2689*10f514bdSNeil Armstrong dmic5_switch, ARRAY_SIZE(dmic5_switch), wcd939x_tx_swr_ctrl, 2690*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2691*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("DMIC6_MIXER", SND_SOC_NOPM, 0, 0, 2692*10f514bdSNeil Armstrong dmic6_switch, ARRAY_SIZE(dmic6_switch), wcd939x_tx_swr_ctrl, 2693*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2694*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("DMIC7_MIXER", SND_SOC_NOPM, 0, 0, 2695*10f514bdSNeil Armstrong dmic7_switch, ARRAY_SIZE(dmic7_switch), wcd939x_tx_swr_ctrl, 2696*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2697*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("DMIC8_MIXER", SND_SOC_NOPM, 0, 0, 2698*10f514bdSNeil Armstrong dmic8_switch, ARRAY_SIZE(dmic8_switch), wcd939x_tx_swr_ctrl, 2699*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 2700*10f514bdSNeil Armstrong 2701*10f514bdSNeil Armstrong /* micbias widgets */ 2702*10f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0, 2703*10f514bdSNeil Armstrong wcd939x_codec_enable_micbias, 2704*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 2705*10f514bdSNeil Armstrong SND_SOC_DAPM_POST_PMD), 2706*10f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0, 2707*10f514bdSNeil Armstrong wcd939x_codec_enable_micbias, 2708*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 2709*10f514bdSNeil Armstrong SND_SOC_DAPM_POST_PMD), 2710*10f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0, 2711*10f514bdSNeil Armstrong wcd939x_codec_enable_micbias, 2712*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 2713*10f514bdSNeil Armstrong SND_SOC_DAPM_POST_PMD), 2714*10f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY("MIC BIAS4", SND_SOC_NOPM, MIC_BIAS_4, 0, 2715*10f514bdSNeil Armstrong wcd939x_codec_enable_micbias, 2716*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 2717*10f514bdSNeil Armstrong SND_SOC_DAPM_POST_PMD), 2718*10f514bdSNeil Armstrong 2719*10f514bdSNeil Armstrong /* micbias pull up widgets */ 2720*10f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY("VA MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0, 2721*10f514bdSNeil Armstrong wcd939x_codec_enable_micbias_pullup, 2722*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 2723*10f514bdSNeil Armstrong SND_SOC_DAPM_POST_PMD), 2724*10f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY("VA MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0, 2725*10f514bdSNeil Armstrong wcd939x_codec_enable_micbias_pullup, 2726*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 2727*10f514bdSNeil Armstrong SND_SOC_DAPM_POST_PMD), 2728*10f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY("VA MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0, 2729*10f514bdSNeil Armstrong wcd939x_codec_enable_micbias_pullup, 2730*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 2731*10f514bdSNeil Armstrong SND_SOC_DAPM_POST_PMD), 2732*10f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY("VA MIC BIAS4", SND_SOC_NOPM, MIC_BIAS_4, 0, 2733*10f514bdSNeil Armstrong wcd939x_codec_enable_micbias_pullup, 2734*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 2735*10f514bdSNeil Armstrong SND_SOC_DAPM_POST_PMD), 2736*10f514bdSNeil Armstrong 2737*10f514bdSNeil Armstrong /* output widgets tx */ 2738*10f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("ADC1_OUTPUT"), 2739*10f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("ADC2_OUTPUT"), 2740*10f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("ADC3_OUTPUT"), 2741*10f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("ADC4_OUTPUT"), 2742*10f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("DMIC1_OUTPUT"), 2743*10f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("DMIC2_OUTPUT"), 2744*10f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("DMIC3_OUTPUT"), 2745*10f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("DMIC4_OUTPUT"), 2746*10f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("DMIC5_OUTPUT"), 2747*10f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("DMIC6_OUTPUT"), 2748*10f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("DMIC7_OUTPUT"), 2749*10f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("DMIC8_OUTPUT"), 2750*10f514bdSNeil Armstrong 2751*10f514bdSNeil Armstrong SND_SOC_DAPM_INPUT("IN1_HPHL"), 2752*10f514bdSNeil Armstrong SND_SOC_DAPM_INPUT("IN2_HPHR"), 2753*10f514bdSNeil Armstrong SND_SOC_DAPM_INPUT("IN3_EAR"), 2754*10f514bdSNeil Armstrong 2755*10f514bdSNeil Armstrong /* rx widgets */ 2756*10f514bdSNeil Armstrong SND_SOC_DAPM_PGA_E("EAR PGA", WCD939X_ANA_EAR, 7, 0, NULL, 0, 2757*10f514bdSNeil Armstrong wcd939x_codec_enable_ear_pa, 2758*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 2759*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), 2760*10f514bdSNeil Armstrong SND_SOC_DAPM_PGA_E("HPHL PGA", WCD939X_ANA_HPH, 7, 0, NULL, 0, 2761*10f514bdSNeil Armstrong wcd939x_codec_enable_hphl_pa, 2762*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 2763*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), 2764*10f514bdSNeil Armstrong SND_SOC_DAPM_PGA_E("HPHR PGA", WCD939X_ANA_HPH, 6, 0, NULL, 0, 2765*10f514bdSNeil Armstrong wcd939x_codec_enable_hphr_pa, 2766*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 2767*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), 2768*10f514bdSNeil Armstrong 2769*10f514bdSNeil Armstrong SND_SOC_DAPM_DAC_E("RDAC1", NULL, SND_SOC_NOPM, 0, 0, 2770*10f514bdSNeil Armstrong wcd939x_codec_hphl_dac_event, 2771*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 2772*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), 2773*10f514bdSNeil Armstrong SND_SOC_DAPM_DAC_E("RDAC2", NULL, SND_SOC_NOPM, 0, 0, 2774*10f514bdSNeil Armstrong wcd939x_codec_hphr_dac_event, 2775*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 2776*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), 2777*10f514bdSNeil Armstrong SND_SOC_DAPM_DAC_E("RDAC3", NULL, SND_SOC_NOPM, 0, 0, 2778*10f514bdSNeil Armstrong wcd939x_codec_ear_dac_event, 2779*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 2780*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), 2781*10f514bdSNeil Armstrong 2782*10f514bdSNeil Armstrong SND_SOC_DAPM_MUX("RDAC3_MUX", SND_SOC_NOPM, 0, 0, &rx_rdac3_mux), 2783*10f514bdSNeil Armstrong 2784*10f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY("VDD_BUCK", SND_SOC_NOPM, 0, 0, NULL, 0), 2785*10f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY("RXCLK", SND_SOC_NOPM, 0, 0, 2786*10f514bdSNeil Armstrong wcd939x_codec_enable_rxclk, 2787*10f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 2788*10f514bdSNeil Armstrong SND_SOC_DAPM_POST_PMD), 2789*10f514bdSNeil Armstrong 2790*10f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY_S("CLS_H_PORT", 1, SND_SOC_NOPM, 0, 0, NULL, 0), 2791*10f514bdSNeil Armstrong 2792*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("RX1", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0), 2793*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("RX2", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0), 2794*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("RX3", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0), 2795*10f514bdSNeil Armstrong 2796*10f514bdSNeil Armstrong /* rx mixer widgets */ 2797*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER("EAR_RDAC", SND_SOC_NOPM, 0, 0, 2798*10f514bdSNeil Armstrong ear_rdac_switch, ARRAY_SIZE(ear_rdac_switch)), 2799*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER("HPHL_RDAC", SND_SOC_NOPM, 0, 0, 2800*10f514bdSNeil Armstrong hphl_rdac_switch, ARRAY_SIZE(hphl_rdac_switch)), 2801*10f514bdSNeil Armstrong SND_SOC_DAPM_MIXER("HPHR_RDAC", SND_SOC_NOPM, 0, 0, 2802*10f514bdSNeil Armstrong hphr_rdac_switch, ARRAY_SIZE(hphr_rdac_switch)), 2803*10f514bdSNeil Armstrong 2804*10f514bdSNeil Armstrong /* output widgets rx */ 2805*10f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("EAR"), 2806*10f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("HPHL"), 2807*10f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("HPHR"), 2808*10f514bdSNeil Armstrong }; 2809*10f514bdSNeil Armstrong 2810*10f514bdSNeil Armstrong static const struct snd_soc_dapm_route wcd939x_audio_map[] = { 2811*10f514bdSNeil Armstrong /* TX Path */ 2812*10f514bdSNeil Armstrong {"ADC1_OUTPUT", NULL, "ADC1_MIXER"}, 2813*10f514bdSNeil Armstrong {"ADC1_MIXER", "Switch", "ADC1 REQ"}, 2814*10f514bdSNeil Armstrong {"ADC1 REQ", NULL, "ADC1"}, 2815*10f514bdSNeil Armstrong {"ADC1", NULL, "ADC1 MUX"}, 2816*10f514bdSNeil Armstrong {"ADC1 MUX", "CH1_AMIC1", "AMIC1"}, 2817*10f514bdSNeil Armstrong {"ADC1 MUX", "CH1_AMIC2", "AMIC2"}, 2818*10f514bdSNeil Armstrong {"ADC1 MUX", "CH1_AMIC3", "AMIC3"}, 2819*10f514bdSNeil Armstrong {"ADC1 MUX", "CH1_AMIC4", "AMIC4"}, 2820*10f514bdSNeil Armstrong {"ADC1 MUX", "CH1_AMIC5", "AMIC5"}, 2821*10f514bdSNeil Armstrong 2822*10f514bdSNeil Armstrong {"ADC2_OUTPUT", NULL, "ADC2_MIXER"}, 2823*10f514bdSNeil Armstrong {"ADC2_MIXER", "Switch", "ADC2 REQ"}, 2824*10f514bdSNeil Armstrong {"ADC2 REQ", NULL, "ADC2"}, 2825*10f514bdSNeil Armstrong {"ADC2", NULL, "ADC2 MUX"}, 2826*10f514bdSNeil Armstrong {"ADC2 MUX", "CH2_AMIC1", "AMIC1"}, 2827*10f514bdSNeil Armstrong {"ADC2 MUX", "CH2_AMIC2", "AMIC2"}, 2828*10f514bdSNeil Armstrong {"ADC2 MUX", "CH2_AMIC3", "AMIC3"}, 2829*10f514bdSNeil Armstrong {"ADC2 MUX", "CH2_AMIC4", "AMIC4"}, 2830*10f514bdSNeil Armstrong {"ADC2 MUX", "CH2_AMIC5", "AMIC5"}, 2831*10f514bdSNeil Armstrong 2832*10f514bdSNeil Armstrong {"ADC3_OUTPUT", NULL, "ADC3_MIXER"}, 2833*10f514bdSNeil Armstrong {"ADC3_MIXER", "Switch", "ADC3 REQ"}, 2834*10f514bdSNeil Armstrong {"ADC3 REQ", NULL, "ADC3"}, 2835*10f514bdSNeil Armstrong {"ADC3", NULL, "ADC3 MUX"}, 2836*10f514bdSNeil Armstrong {"ADC3 MUX", "CH3_AMIC1", "AMIC1"}, 2837*10f514bdSNeil Armstrong {"ADC3 MUX", "CH3_AMIC3", "AMIC3"}, 2838*10f514bdSNeil Armstrong {"ADC3 MUX", "CH3_AMIC4", "AMIC4"}, 2839*10f514bdSNeil Armstrong {"ADC3 MUX", "CH3_AMIC5", "AMIC5"}, 2840*10f514bdSNeil Armstrong 2841*10f514bdSNeil Armstrong {"ADC4_OUTPUT", NULL, "ADC4_MIXER"}, 2842*10f514bdSNeil Armstrong {"ADC4_MIXER", "Switch", "ADC4 REQ"}, 2843*10f514bdSNeil Armstrong {"ADC4 REQ", NULL, "ADC4"}, 2844*10f514bdSNeil Armstrong {"ADC4", NULL, "ADC4 MUX"}, 2845*10f514bdSNeil Armstrong {"ADC4 MUX", "CH4_AMIC1", "AMIC1"}, 2846*10f514bdSNeil Armstrong {"ADC4 MUX", "CH4_AMIC3", "AMIC3"}, 2847*10f514bdSNeil Armstrong {"ADC4 MUX", "CH4_AMIC4", "AMIC4"}, 2848*10f514bdSNeil Armstrong {"ADC4 MUX", "CH4_AMIC5", "AMIC5"}, 2849*10f514bdSNeil Armstrong 2850*10f514bdSNeil Armstrong {"DMIC1_OUTPUT", NULL, "DMIC1_MIXER"}, 2851*10f514bdSNeil Armstrong {"DMIC1_MIXER", "Switch", "DMIC1"}, 2852*10f514bdSNeil Armstrong 2853*10f514bdSNeil Armstrong {"DMIC2_OUTPUT", NULL, "DMIC2_MIXER"}, 2854*10f514bdSNeil Armstrong {"DMIC2_MIXER", "Switch", "DMIC2"}, 2855*10f514bdSNeil Armstrong 2856*10f514bdSNeil Armstrong {"DMIC3_OUTPUT", NULL, "DMIC3_MIXER"}, 2857*10f514bdSNeil Armstrong {"DMIC3_MIXER", "Switch", "DMIC3"}, 2858*10f514bdSNeil Armstrong 2859*10f514bdSNeil Armstrong {"DMIC4_OUTPUT", NULL, "DMIC4_MIXER"}, 2860*10f514bdSNeil Armstrong {"DMIC4_MIXER", "Switch", "DMIC4"}, 2861*10f514bdSNeil Armstrong 2862*10f514bdSNeil Armstrong {"DMIC5_OUTPUT", NULL, "DMIC5_MIXER"}, 2863*10f514bdSNeil Armstrong {"DMIC5_MIXER", "Switch", "DMIC5"}, 2864*10f514bdSNeil Armstrong 2865*10f514bdSNeil Armstrong {"DMIC6_OUTPUT", NULL, "DMIC6_MIXER"}, 2866*10f514bdSNeil Armstrong {"DMIC6_MIXER", "Switch", "DMIC6"}, 2867*10f514bdSNeil Armstrong 2868*10f514bdSNeil Armstrong {"DMIC7_OUTPUT", NULL, "DMIC7_MIXER"}, 2869*10f514bdSNeil Armstrong {"DMIC7_MIXER", "Switch", "DMIC7"}, 2870*10f514bdSNeil Armstrong 2871*10f514bdSNeil Armstrong {"DMIC8_OUTPUT", NULL, "DMIC8_MIXER"}, 2872*10f514bdSNeil Armstrong {"DMIC8_MIXER", "Switch", "DMIC8"}, 2873*10f514bdSNeil Armstrong 2874*10f514bdSNeil Armstrong /* RX Path */ 2875*10f514bdSNeil Armstrong {"IN1_HPHL", NULL, "VDD_BUCK"}, 2876*10f514bdSNeil Armstrong {"IN1_HPHL", NULL, "CLS_H_PORT"}, 2877*10f514bdSNeil Armstrong 2878*10f514bdSNeil Armstrong {"RX1", NULL, "IN1_HPHL"}, 2879*10f514bdSNeil Armstrong {"RX1", NULL, "RXCLK"}, 2880*10f514bdSNeil Armstrong {"RDAC1", NULL, "RX1"}, 2881*10f514bdSNeil Armstrong {"HPHL_RDAC", "Switch", "RDAC1"}, 2882*10f514bdSNeil Armstrong {"HPHL PGA", NULL, "HPHL_RDAC"}, 2883*10f514bdSNeil Armstrong {"HPHL", NULL, "HPHL PGA"}, 2884*10f514bdSNeil Armstrong 2885*10f514bdSNeil Armstrong {"IN2_HPHR", NULL, "VDD_BUCK"}, 2886*10f514bdSNeil Armstrong {"IN2_HPHR", NULL, "CLS_H_PORT"}, 2887*10f514bdSNeil Armstrong {"RX2", NULL, "IN2_HPHR"}, 2888*10f514bdSNeil Armstrong {"RDAC2", NULL, "RX2"}, 2889*10f514bdSNeil Armstrong {"RX2", NULL, "RXCLK"}, 2890*10f514bdSNeil Armstrong {"HPHR_RDAC", "Switch", "RDAC2"}, 2891*10f514bdSNeil Armstrong {"HPHR PGA", NULL, "HPHR_RDAC"}, 2892*10f514bdSNeil Armstrong {"HPHR", NULL, "HPHR PGA"}, 2893*10f514bdSNeil Armstrong 2894*10f514bdSNeil Armstrong {"IN3_EAR", NULL, "VDD_BUCK"}, 2895*10f514bdSNeil Armstrong {"RX3", NULL, "IN3_EAR"}, 2896*10f514bdSNeil Armstrong {"RX3", NULL, "RXCLK"}, 2897*10f514bdSNeil Armstrong 2898*10f514bdSNeil Armstrong {"RDAC3_MUX", "RX3", "RX3"}, 2899*10f514bdSNeil Armstrong {"RDAC3_MUX", "RX1", "RX1"}, 2900*10f514bdSNeil Armstrong {"RDAC3", NULL, "RDAC3_MUX"}, 2901*10f514bdSNeil Armstrong {"EAR_RDAC", "Switch", "RDAC3"}, 2902*10f514bdSNeil Armstrong {"EAR PGA", NULL, "EAR_RDAC"}, 2903*10f514bdSNeil Armstrong {"EAR", NULL, "EAR PGA"}, 2904*10f514bdSNeil Armstrong }; 2905*10f514bdSNeil Armstrong 2906*10f514bdSNeil Armstrong static int wcd939x_set_micbias_data(struct wcd939x_priv *wcd939x) 2907*10f514bdSNeil Armstrong { 2908*10f514bdSNeil Armstrong int vout_ctl_1, vout_ctl_2, vout_ctl_3, vout_ctl_4; 2909*10f514bdSNeil Armstrong 2910*10f514bdSNeil Armstrong /* set micbias voltage */ 2911*10f514bdSNeil Armstrong vout_ctl_1 = wcd939x_get_micb_vout_ctl_val(wcd939x->micb1_mv); 2912*10f514bdSNeil Armstrong vout_ctl_2 = wcd939x_get_micb_vout_ctl_val(wcd939x->micb2_mv); 2913*10f514bdSNeil Armstrong vout_ctl_3 = wcd939x_get_micb_vout_ctl_val(wcd939x->micb3_mv); 2914*10f514bdSNeil Armstrong vout_ctl_4 = wcd939x_get_micb_vout_ctl_val(wcd939x->micb4_mv); 2915*10f514bdSNeil Armstrong if (vout_ctl_1 < 0 || vout_ctl_2 < 0 || vout_ctl_3 < 0 || vout_ctl_4 < 0) 2916*10f514bdSNeil Armstrong return -EINVAL; 2917*10f514bdSNeil Armstrong 2918*10f514bdSNeil Armstrong regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB1, 2919*10f514bdSNeil Armstrong WCD939X_MICB1_VOUT_CTL, vout_ctl_1); 2920*10f514bdSNeil Armstrong regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB2, 2921*10f514bdSNeil Armstrong WCD939X_MICB2_VOUT_CTL, vout_ctl_2); 2922*10f514bdSNeil Armstrong regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB3, 2923*10f514bdSNeil Armstrong WCD939X_MICB3_VOUT_CTL, vout_ctl_3); 2924*10f514bdSNeil Armstrong regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB4, 2925*10f514bdSNeil Armstrong WCD939X_MICB4_VOUT_CTL, vout_ctl_4); 2926*10f514bdSNeil Armstrong 2927*10f514bdSNeil Armstrong return 0; 2928*10f514bdSNeil Armstrong } 2929*10f514bdSNeil Armstrong 2930*10f514bdSNeil Armstrong static irqreturn_t wcd939x_wd_handle_irq(int irq, void *data) 2931*10f514bdSNeil Armstrong { 2932*10f514bdSNeil Armstrong /* 2933*10f514bdSNeil Armstrong * HPHR/HPHL/EAR Watchdog interrupt threaded handler 2934*10f514bdSNeil Armstrong * 2935*10f514bdSNeil Armstrong * Watchdog interrupts are expected to be enabled when switching 2936*10f514bdSNeil Armstrong * on the HPHL/R and EAR RX PGA in order to make sure the interrupts 2937*10f514bdSNeil Armstrong * are acked by the regmap_irq handler to allow PDM sync. 2938*10f514bdSNeil Armstrong * We could leave those interrupts masked but we would not have 2939*10f514bdSNeil Armstrong * any valid way to enable/disable them without violating irq layers. 2940*10f514bdSNeil Armstrong * 2941*10f514bdSNeil Armstrong * The HPHR/HPHL/EAR Watchdog interrupts are handled 2942*10f514bdSNeil Armstrong * by regmap_irq, so requesting a threaded handler is the 2943*10f514bdSNeil Armstrong * safest way to be able to ack those interrupts without 2944*10f514bdSNeil Armstrong * colliding with the regmap_irq setup. 2945*10f514bdSNeil Armstrong */ 2946*10f514bdSNeil Armstrong 2947*10f514bdSNeil Armstrong return IRQ_HANDLED; 2948*10f514bdSNeil Armstrong } 2949*10f514bdSNeil Armstrong 2950*10f514bdSNeil Armstrong /* 2951*10f514bdSNeil Armstrong * Setup a virtual interrupt domain to hook regmap_irq 2952*10f514bdSNeil Armstrong * The root domain will have a single interrupt which mapping 2953*10f514bdSNeil Armstrong * will trigger the regmap_irq handler. 2954*10f514bdSNeil Armstrong * 2955*10f514bdSNeil Armstrong * root: 2956*10f514bdSNeil Armstrong * wcd_irq_chip 2957*10f514bdSNeil Armstrong * [0] wcd939x_regmap_irq_chip 2958*10f514bdSNeil Armstrong * [0] MBHC_BUTTON_PRESS_DET 2959*10f514bdSNeil Armstrong * [1] MBHC_BUTTON_RELEASE_DET 2960*10f514bdSNeil Armstrong * ... 2961*10f514bdSNeil Armstrong * [16] HPHR_SURGE_DET_INT 2962*10f514bdSNeil Armstrong * 2963*10f514bdSNeil Armstrong * Interrupt trigger: 2964*10f514bdSNeil Armstrong * soundwire_interrupt_callback() 2965*10f514bdSNeil Armstrong * \-handle_nested_irq(0) 2966*10f514bdSNeil Armstrong * \- regmap_irq_thread() 2967*10f514bdSNeil Armstrong * \- handle_nested_irq(i) 2968*10f514bdSNeil Armstrong */ 2969*10f514bdSNeil Armstrong static struct irq_chip wcd_irq_chip = { 2970*10f514bdSNeil Armstrong .name = "WCD939x", 2971*10f514bdSNeil Armstrong }; 2972*10f514bdSNeil Armstrong 2973*10f514bdSNeil Armstrong static int wcd_irq_chip_map(struct irq_domain *irqd, unsigned int virq, 2974*10f514bdSNeil Armstrong irq_hw_number_t hw) 2975*10f514bdSNeil Armstrong { 2976*10f514bdSNeil Armstrong irq_set_chip_and_handler(virq, &wcd_irq_chip, handle_simple_irq); 2977*10f514bdSNeil Armstrong irq_set_nested_thread(virq, 1); 2978*10f514bdSNeil Armstrong irq_set_noprobe(virq); 2979*10f514bdSNeil Armstrong 2980*10f514bdSNeil Armstrong return 0; 2981*10f514bdSNeil Armstrong } 2982*10f514bdSNeil Armstrong 2983*10f514bdSNeil Armstrong static const struct irq_domain_ops wcd_domain_ops = { 2984*10f514bdSNeil Armstrong .map = wcd_irq_chip_map, 2985*10f514bdSNeil Armstrong }; 2986*10f514bdSNeil Armstrong 2987*10f514bdSNeil Armstrong static int wcd939x_irq_init(struct wcd939x_priv *wcd, struct device *dev) 2988*10f514bdSNeil Armstrong { 2989*10f514bdSNeil Armstrong wcd->virq = irq_domain_add_linear(NULL, 1, &wcd_domain_ops, NULL); 2990*10f514bdSNeil Armstrong if (!(wcd->virq)) { 2991*10f514bdSNeil Armstrong dev_err(dev, "%s: Failed to add IRQ domain\n", __func__); 2992*10f514bdSNeil Armstrong return -EINVAL; 2993*10f514bdSNeil Armstrong } 2994*10f514bdSNeil Armstrong 2995*10f514bdSNeil Armstrong return devm_regmap_add_irq_chip(dev, wcd->regmap, 2996*10f514bdSNeil Armstrong irq_create_mapping(wcd->virq, 0), 2997*10f514bdSNeil Armstrong IRQF_ONESHOT, 0, &wcd939x_regmap_irq_chip, 2998*10f514bdSNeil Armstrong &wcd->irq_chip); 2999*10f514bdSNeil Armstrong } 3000*10f514bdSNeil Armstrong 3001*10f514bdSNeil Armstrong static int wcd939x_soc_codec_probe(struct snd_soc_component *component) 3002*10f514bdSNeil Armstrong { 3003*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 3004*10f514bdSNeil Armstrong struct sdw_slave *tx_sdw_dev = wcd939x->tx_sdw_dev; 3005*10f514bdSNeil Armstrong struct device *dev = component->dev; 3006*10f514bdSNeil Armstrong unsigned long time_left; 3007*10f514bdSNeil Armstrong int ret, i; 3008*10f514bdSNeil Armstrong 3009*10f514bdSNeil Armstrong time_left = wait_for_completion_timeout(&tx_sdw_dev->initialization_complete, 3010*10f514bdSNeil Armstrong msecs_to_jiffies(2000)); 3011*10f514bdSNeil Armstrong if (!time_left) { 3012*10f514bdSNeil Armstrong dev_err(dev, "soundwire device init timeout\n"); 3013*10f514bdSNeil Armstrong return -ETIMEDOUT; 3014*10f514bdSNeil Armstrong } 3015*10f514bdSNeil Armstrong 3016*10f514bdSNeil Armstrong snd_soc_component_init_regmap(component, wcd939x->regmap); 3017*10f514bdSNeil Armstrong 3018*10f514bdSNeil Armstrong ret = pm_runtime_resume_and_get(dev); 3019*10f514bdSNeil Armstrong if (ret < 0) 3020*10f514bdSNeil Armstrong return ret; 3021*10f514bdSNeil Armstrong 3022*10f514bdSNeil Armstrong wcd939x->variant = snd_soc_component_read_field(component, 3023*10f514bdSNeil Armstrong WCD939X_DIGITAL_EFUSE_REG_0, 3024*10f514bdSNeil Armstrong WCD939X_EFUSE_REG_0_WCD939X_ID); 3025*10f514bdSNeil Armstrong 3026*10f514bdSNeil Armstrong wcd939x->clsh_info = wcd_clsh_ctrl_alloc(component, WCD939X); 3027*10f514bdSNeil Armstrong if (IS_ERR(wcd939x->clsh_info)) { 3028*10f514bdSNeil Armstrong pm_runtime_put(dev); 3029*10f514bdSNeil Armstrong return PTR_ERR(wcd939x->clsh_info); 3030*10f514bdSNeil Armstrong } 3031*10f514bdSNeil Armstrong 3032*10f514bdSNeil Armstrong wcd939x_io_init(component); 3033*10f514bdSNeil Armstrong 3034*10f514bdSNeil Armstrong /* Set all interrupts as edge triggered */ 3035*10f514bdSNeil Armstrong for (i = 0; i < wcd939x_regmap_irq_chip.num_regs; i++) 3036*10f514bdSNeil Armstrong regmap_write(wcd939x->regmap, 3037*10f514bdSNeil Armstrong (WCD939X_DIGITAL_INTR_LEVEL_0 + i), 0); 3038*10f514bdSNeil Armstrong 3039*10f514bdSNeil Armstrong pm_runtime_put(dev); 3040*10f514bdSNeil Armstrong 3041*10f514bdSNeil Armstrong /* Request for watchdog interrupt */ 3042*10f514bdSNeil Armstrong wcd939x->hphr_pdm_wd_int = regmap_irq_get_virq(wcd939x->irq_chip, 3043*10f514bdSNeil Armstrong WCD939X_IRQ_HPHR_PDM_WD_INT); 3044*10f514bdSNeil Armstrong wcd939x->hphl_pdm_wd_int = regmap_irq_get_virq(wcd939x->irq_chip, 3045*10f514bdSNeil Armstrong WCD939X_IRQ_HPHL_PDM_WD_INT); 3046*10f514bdSNeil Armstrong wcd939x->ear_pdm_wd_int = regmap_irq_get_virq(wcd939x->irq_chip, 3047*10f514bdSNeil Armstrong WCD939X_IRQ_EAR_PDM_WD_INT); 3048*10f514bdSNeil Armstrong 3049*10f514bdSNeil Armstrong ret = request_threaded_irq(wcd939x->hphr_pdm_wd_int, NULL, wcd939x_wd_handle_irq, 3050*10f514bdSNeil Armstrong IRQF_ONESHOT | IRQF_TRIGGER_RISING, 3051*10f514bdSNeil Armstrong "HPHR PDM WD INT", wcd939x); 3052*10f514bdSNeil Armstrong if (ret) { 3053*10f514bdSNeil Armstrong dev_err(dev, "Failed to request HPHR WD interrupt (%d)\n", ret); 3054*10f514bdSNeil Armstrong goto err_free_clsh_ctrl; 3055*10f514bdSNeil Armstrong } 3056*10f514bdSNeil Armstrong 3057*10f514bdSNeil Armstrong ret = request_threaded_irq(wcd939x->hphl_pdm_wd_int, NULL, wcd939x_wd_handle_irq, 3058*10f514bdSNeil Armstrong IRQF_ONESHOT | IRQF_TRIGGER_RISING, 3059*10f514bdSNeil Armstrong "HPHL PDM WD INT", wcd939x); 3060*10f514bdSNeil Armstrong if (ret) { 3061*10f514bdSNeil Armstrong dev_err(dev, "Failed to request HPHL WD interrupt (%d)\n", ret); 3062*10f514bdSNeil Armstrong goto err_free_hphr_pdm_wd_int; 3063*10f514bdSNeil Armstrong } 3064*10f514bdSNeil Armstrong 3065*10f514bdSNeil Armstrong ret = request_threaded_irq(wcd939x->ear_pdm_wd_int, NULL, wcd939x_wd_handle_irq, 3066*10f514bdSNeil Armstrong IRQF_ONESHOT | IRQF_TRIGGER_RISING, 3067*10f514bdSNeil Armstrong "AUX PDM WD INT", wcd939x); 3068*10f514bdSNeil Armstrong if (ret) { 3069*10f514bdSNeil Armstrong dev_err(dev, "Failed to request Aux WD interrupt (%d)\n", ret); 3070*10f514bdSNeil Armstrong goto err_free_hphl_pdm_wd_int; 3071*10f514bdSNeil Armstrong } 3072*10f514bdSNeil Armstrong 3073*10f514bdSNeil Armstrong /* Disable watchdog interrupt for HPH and AUX */ 3074*10f514bdSNeil Armstrong disable_irq_nosync(wcd939x->hphr_pdm_wd_int); 3075*10f514bdSNeil Armstrong disable_irq_nosync(wcd939x->hphl_pdm_wd_int); 3076*10f514bdSNeil Armstrong disable_irq_nosync(wcd939x->ear_pdm_wd_int); 3077*10f514bdSNeil Armstrong 3078*10f514bdSNeil Armstrong switch (wcd939x->variant) { 3079*10f514bdSNeil Armstrong case WCD9390: 3080*10f514bdSNeil Armstrong ret = snd_soc_add_component_controls(component, wcd9390_snd_controls, 3081*10f514bdSNeil Armstrong ARRAY_SIZE(wcd9390_snd_controls)); 3082*10f514bdSNeil Armstrong if (ret < 0) { 3083*10f514bdSNeil Armstrong dev_err(component->dev, 3084*10f514bdSNeil Armstrong "%s: Failed to add snd ctrls for variant: %d\n", 3085*10f514bdSNeil Armstrong __func__, wcd939x->variant); 3086*10f514bdSNeil Armstrong goto err_free_ear_pdm_wd_int; 3087*10f514bdSNeil Armstrong } 3088*10f514bdSNeil Armstrong break; 3089*10f514bdSNeil Armstrong case WCD9395: 3090*10f514bdSNeil Armstrong ret = snd_soc_add_component_controls(component, wcd9395_snd_controls, 3091*10f514bdSNeil Armstrong ARRAY_SIZE(wcd9395_snd_controls)); 3092*10f514bdSNeil Armstrong if (ret < 0) { 3093*10f514bdSNeil Armstrong dev_err(component->dev, 3094*10f514bdSNeil Armstrong "%s: Failed to add snd ctrls for variant: %d\n", 3095*10f514bdSNeil Armstrong __func__, wcd939x->variant); 3096*10f514bdSNeil Armstrong goto err_free_ear_pdm_wd_int; 3097*10f514bdSNeil Armstrong } 3098*10f514bdSNeil Armstrong break; 3099*10f514bdSNeil Armstrong default: 3100*10f514bdSNeil Armstrong break; 3101*10f514bdSNeil Armstrong } 3102*10f514bdSNeil Armstrong 3103*10f514bdSNeil Armstrong ret = wcd939x_mbhc_init(component); 3104*10f514bdSNeil Armstrong if (ret) { 3105*10f514bdSNeil Armstrong dev_err(component->dev, "mbhc initialization failed\n"); 3106*10f514bdSNeil Armstrong goto err_free_ear_pdm_wd_int; 3107*10f514bdSNeil Armstrong } 3108*10f514bdSNeil Armstrong 3109*10f514bdSNeil Armstrong return 0; 3110*10f514bdSNeil Armstrong 3111*10f514bdSNeil Armstrong err_free_ear_pdm_wd_int: 3112*10f514bdSNeil Armstrong free_irq(wcd939x->ear_pdm_wd_int, wcd939x); 3113*10f514bdSNeil Armstrong err_free_hphl_pdm_wd_int: 3114*10f514bdSNeil Armstrong free_irq(wcd939x->hphl_pdm_wd_int, wcd939x); 3115*10f514bdSNeil Armstrong err_free_hphr_pdm_wd_int: 3116*10f514bdSNeil Armstrong free_irq(wcd939x->hphr_pdm_wd_int, wcd939x); 3117*10f514bdSNeil Armstrong err_free_clsh_ctrl: 3118*10f514bdSNeil Armstrong wcd_clsh_ctrl_free(wcd939x->clsh_info); 3119*10f514bdSNeil Armstrong 3120*10f514bdSNeil Armstrong return ret; 3121*10f514bdSNeil Armstrong } 3122*10f514bdSNeil Armstrong 3123*10f514bdSNeil Armstrong static void wcd939x_soc_codec_remove(struct snd_soc_component *component) 3124*10f514bdSNeil Armstrong { 3125*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 3126*10f514bdSNeil Armstrong 3127*10f514bdSNeil Armstrong wcd939x_mbhc_deinit(component); 3128*10f514bdSNeil Armstrong 3129*10f514bdSNeil Armstrong free_irq(wcd939x->ear_pdm_wd_int, wcd939x); 3130*10f514bdSNeil Armstrong free_irq(wcd939x->hphl_pdm_wd_int, wcd939x); 3131*10f514bdSNeil Armstrong free_irq(wcd939x->hphr_pdm_wd_int, wcd939x); 3132*10f514bdSNeil Armstrong 3133*10f514bdSNeil Armstrong wcd_clsh_ctrl_free(wcd939x->clsh_info); 3134*10f514bdSNeil Armstrong } 3135*10f514bdSNeil Armstrong 3136*10f514bdSNeil Armstrong static int wcd939x_codec_set_jack(struct snd_soc_component *comp, 3137*10f514bdSNeil Armstrong struct snd_soc_jack *jack, void *data) 3138*10f514bdSNeil Armstrong { 3139*10f514bdSNeil Armstrong struct wcd939x_priv *wcd = dev_get_drvdata(comp->dev); 3140*10f514bdSNeil Armstrong 3141*10f514bdSNeil Armstrong if (jack) 3142*10f514bdSNeil Armstrong return wcd_mbhc_start(wcd->wcd_mbhc, &wcd->mbhc_cfg, jack); 3143*10f514bdSNeil Armstrong 3144*10f514bdSNeil Armstrong wcd_mbhc_stop(wcd->wcd_mbhc); 3145*10f514bdSNeil Armstrong 3146*10f514bdSNeil Armstrong return 0; 3147*10f514bdSNeil Armstrong } 3148*10f514bdSNeil Armstrong 3149*10f514bdSNeil Armstrong static const struct snd_soc_component_driver soc_codec_dev_wcd939x = { 3150*10f514bdSNeil Armstrong .name = "wcd939x_codec", 3151*10f514bdSNeil Armstrong .probe = wcd939x_soc_codec_probe, 3152*10f514bdSNeil Armstrong .remove = wcd939x_soc_codec_remove, 3153*10f514bdSNeil Armstrong .controls = wcd939x_snd_controls, 3154*10f514bdSNeil Armstrong .num_controls = ARRAY_SIZE(wcd939x_snd_controls), 3155*10f514bdSNeil Armstrong .dapm_widgets = wcd939x_dapm_widgets, 3156*10f514bdSNeil Armstrong .num_dapm_widgets = ARRAY_SIZE(wcd939x_dapm_widgets), 3157*10f514bdSNeil Armstrong .dapm_routes = wcd939x_audio_map, 3158*10f514bdSNeil Armstrong .num_dapm_routes = ARRAY_SIZE(wcd939x_audio_map), 3159*10f514bdSNeil Armstrong .set_jack = wcd939x_codec_set_jack, 3160*10f514bdSNeil Armstrong .endianness = 1, 3161*10f514bdSNeil Armstrong }; 3162*10f514bdSNeil Armstrong 3163*10f514bdSNeil Armstrong #if IS_ENABLED(CONFIG_TYPEC) 3164*10f514bdSNeil Armstrong /* Get USB-C plug orientation to provide swap event for MBHC */ 3165*10f514bdSNeil Armstrong static int wcd939x_typec_switch_set(struct typec_switch_dev *sw, 3166*10f514bdSNeil Armstrong enum typec_orientation orientation) 3167*10f514bdSNeil Armstrong { 3168*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = typec_switch_get_drvdata(sw); 3169*10f514bdSNeil Armstrong 3170*10f514bdSNeil Armstrong wcd939x->typec_orientation = orientation; 3171*10f514bdSNeil Armstrong 3172*10f514bdSNeil Armstrong return 0; 3173*10f514bdSNeil Armstrong } 3174*10f514bdSNeil Armstrong 3175*10f514bdSNeil Armstrong static int wcd939x_typec_mux_set(struct typec_mux_dev *mux, 3176*10f514bdSNeil Armstrong struct typec_mux_state *state) 3177*10f514bdSNeil Armstrong { 3178*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = typec_mux_get_drvdata(mux); 3179*10f514bdSNeil Armstrong unsigned int previous_mode = wcd939x->typec_mode; 3180*10f514bdSNeil Armstrong 3181*10f514bdSNeil Armstrong if (!wcd939x->wcd_mbhc) 3182*10f514bdSNeil Armstrong return -EINVAL; 3183*10f514bdSNeil Armstrong 3184*10f514bdSNeil Armstrong if (wcd939x->typec_mode != state->mode) { 3185*10f514bdSNeil Armstrong wcd939x->typec_mode = state->mode; 3186*10f514bdSNeil Armstrong 3187*10f514bdSNeil Armstrong if (wcd939x->typec_mode == TYPEC_MODE_AUDIO) 3188*10f514bdSNeil Armstrong return wcd_mbhc_typec_report_plug(wcd939x->wcd_mbhc); 3189*10f514bdSNeil Armstrong else if (previous_mode == TYPEC_MODE_AUDIO) 3190*10f514bdSNeil Armstrong return wcd_mbhc_typec_report_unplug(wcd939x->wcd_mbhc); 3191*10f514bdSNeil Armstrong } 3192*10f514bdSNeil Armstrong 3193*10f514bdSNeil Armstrong return 0; 3194*10f514bdSNeil Armstrong } 3195*10f514bdSNeil Armstrong #endif /* CONFIG_TYPEC */ 3196*10f514bdSNeil Armstrong 3197*10f514bdSNeil Armstrong static void wcd939x_dt_parse_micbias_info(struct device *dev, struct wcd939x_priv *wcd) 3198*10f514bdSNeil Armstrong { 3199*10f514bdSNeil Armstrong struct device_node *np = dev->of_node; 3200*10f514bdSNeil Armstrong u32 prop_val = 0; 3201*10f514bdSNeil Armstrong int rc = 0; 3202*10f514bdSNeil Armstrong 3203*10f514bdSNeil Armstrong rc = of_property_read_u32(np, "qcom,micbias1-microvolt", &prop_val); 3204*10f514bdSNeil Armstrong if (!rc) 3205*10f514bdSNeil Armstrong wcd->micb1_mv = prop_val / 1000; 3206*10f514bdSNeil Armstrong else 3207*10f514bdSNeil Armstrong dev_info(dev, "%s: Micbias1 DT property not found\n", __func__); 3208*10f514bdSNeil Armstrong 3209*10f514bdSNeil Armstrong rc = of_property_read_u32(np, "qcom,micbias2-microvolt", &prop_val); 3210*10f514bdSNeil Armstrong if (!rc) 3211*10f514bdSNeil Armstrong wcd->micb2_mv = prop_val / 1000; 3212*10f514bdSNeil Armstrong else 3213*10f514bdSNeil Armstrong dev_info(dev, "%s: Micbias2 DT property not found\n", __func__); 3214*10f514bdSNeil Armstrong 3215*10f514bdSNeil Armstrong rc = of_property_read_u32(np, "qcom,micbias3-microvolt", &prop_val); 3216*10f514bdSNeil Armstrong if (!rc) 3217*10f514bdSNeil Armstrong wcd->micb3_mv = prop_val / 1000; 3218*10f514bdSNeil Armstrong else 3219*10f514bdSNeil Armstrong dev_info(dev, "%s: Micbias3 DT property not found\n", __func__); 3220*10f514bdSNeil Armstrong 3221*10f514bdSNeil Armstrong rc = of_property_read_u32(np, "qcom,micbias4-microvolt", &prop_val); 3222*10f514bdSNeil Armstrong if (!rc) 3223*10f514bdSNeil Armstrong wcd->micb4_mv = prop_val / 1000; 3224*10f514bdSNeil Armstrong else 3225*10f514bdSNeil Armstrong dev_info(dev, "%s: Micbias4 DT property not found\n", __func__); 3226*10f514bdSNeil Armstrong } 3227*10f514bdSNeil Armstrong 3228*10f514bdSNeil Armstrong #if IS_ENABLED(CONFIG_TYPEC) 3229*10f514bdSNeil Armstrong static bool wcd939x_swap_gnd_mic(struct snd_soc_component *component, bool active) 3230*10f514bdSNeil Armstrong { 3231*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 3232*10f514bdSNeil Armstrong 3233*10f514bdSNeil Armstrong if (!wcd939x->typec_analog_mux || !wcd939x->typec_switch) 3234*10f514bdSNeil Armstrong return false; 3235*10f514bdSNeil Armstrong 3236*10f514bdSNeil Armstrong /* Report inversion via Type Switch of USBSS */ 3237*10f514bdSNeil Armstrong typec_switch_set(wcd939x->typec_switch, 3238*10f514bdSNeil Armstrong wcd939x->typec_orientation == TYPEC_ORIENTATION_REVERSE ? 3239*10f514bdSNeil Armstrong TYPEC_ORIENTATION_NORMAL : TYPEC_ORIENTATION_REVERSE); 3240*10f514bdSNeil Armstrong 3241*10f514bdSNeil Armstrong return true; 3242*10f514bdSNeil Armstrong } 3243*10f514bdSNeil Armstrong #endif /* CONFIG_TYPEC */ 3244*10f514bdSNeil Armstrong 3245*10f514bdSNeil Armstrong static int wcd939x_populate_dt_data(struct wcd939x_priv *wcd939x, struct device *dev) 3246*10f514bdSNeil Armstrong { 3247*10f514bdSNeil Armstrong struct wcd_mbhc_config *cfg = &wcd939x->mbhc_cfg; 3248*10f514bdSNeil Armstrong #if IS_ENABLED(CONFIG_TYPEC) 3249*10f514bdSNeil Armstrong struct device_node *np; 3250*10f514bdSNeil Armstrong #endif /* CONFIG_TYPEC */ 3251*10f514bdSNeil Armstrong int ret; 3252*10f514bdSNeil Armstrong 3253*10f514bdSNeil Armstrong wcd939x->reset_gpio = of_get_named_gpio(dev->of_node, "reset-gpios", 0); 3254*10f514bdSNeil Armstrong if (wcd939x->reset_gpio < 0) 3255*10f514bdSNeil Armstrong return dev_err_probe(dev, wcd939x->reset_gpio, 3256*10f514bdSNeil Armstrong "Failed to get reset gpio\n"); 3257*10f514bdSNeil Armstrong 3258*10f514bdSNeil Armstrong wcd939x->supplies[0].supply = "vdd-rxtx"; 3259*10f514bdSNeil Armstrong wcd939x->supplies[1].supply = "vdd-io"; 3260*10f514bdSNeil Armstrong wcd939x->supplies[2].supply = "vdd-buck"; 3261*10f514bdSNeil Armstrong wcd939x->supplies[3].supply = "vdd-mic-bias"; 3262*10f514bdSNeil Armstrong 3263*10f514bdSNeil Armstrong ret = regulator_bulk_get(dev, WCD939X_MAX_SUPPLY, wcd939x->supplies); 3264*10f514bdSNeil Armstrong if (ret) 3265*10f514bdSNeil Armstrong return dev_err_probe(dev, ret, "Failed to get supplies\n"); 3266*10f514bdSNeil Armstrong 3267*10f514bdSNeil Armstrong ret = regulator_bulk_enable(WCD939X_MAX_SUPPLY, wcd939x->supplies); 3268*10f514bdSNeil Armstrong if (ret) { 3269*10f514bdSNeil Armstrong regulator_bulk_free(WCD939X_MAX_SUPPLY, wcd939x->supplies); 3270*10f514bdSNeil Armstrong return dev_err_probe(dev, ret, "Failed to enable supplies\n"); 3271*10f514bdSNeil Armstrong } 3272*10f514bdSNeil Armstrong 3273*10f514bdSNeil Armstrong wcd939x_dt_parse_micbias_info(dev, wcd939x); 3274*10f514bdSNeil Armstrong 3275*10f514bdSNeil Armstrong cfg->mbhc_micbias = MIC_BIAS_2; 3276*10f514bdSNeil Armstrong cfg->anc_micbias = MIC_BIAS_2; 3277*10f514bdSNeil Armstrong cfg->v_hs_max = WCD_MBHC_HS_V_MAX; 3278*10f514bdSNeil Armstrong cfg->num_btn = WCD939X_MBHC_MAX_BUTTONS; 3279*10f514bdSNeil Armstrong cfg->micb_mv = wcd939x->micb2_mv; 3280*10f514bdSNeil Armstrong cfg->linein_th = 5000; 3281*10f514bdSNeil Armstrong cfg->hs_thr = 1700; 3282*10f514bdSNeil Armstrong cfg->hph_thr = 50; 3283*10f514bdSNeil Armstrong 3284*10f514bdSNeil Armstrong wcd_dt_parse_mbhc_data(dev, cfg); 3285*10f514bdSNeil Armstrong 3286*10f514bdSNeil Armstrong #if IS_ENABLED(CONFIG_TYPEC) 3287*10f514bdSNeil Armstrong /* 3288*10f514bdSNeil Armstrong * Is node has a port and a valid remote endpoint 3289*10f514bdSNeil Armstrong * consider HP lines are connected to the USBSS part 3290*10f514bdSNeil Armstrong */ 3291*10f514bdSNeil Armstrong np = of_graph_get_remote_node(dev->of_node, 0, 0); 3292*10f514bdSNeil Armstrong if (np) { 3293*10f514bdSNeil Armstrong wcd939x->typec_analog_mux = true; 3294*10f514bdSNeil Armstrong cfg->typec_analog_mux = true; 3295*10f514bdSNeil Armstrong cfg->swap_gnd_mic = wcd939x_swap_gnd_mic; 3296*10f514bdSNeil Armstrong } 3297*10f514bdSNeil Armstrong #endif /* CONFIG_TYPEC */ 3298*10f514bdSNeil Armstrong 3299*10f514bdSNeil Armstrong return 0; 3300*10f514bdSNeil Armstrong } 3301*10f514bdSNeil Armstrong 3302*10f514bdSNeil Armstrong static int wcd939x_reset(struct wcd939x_priv *wcd939x) 3303*10f514bdSNeil Armstrong { 3304*10f514bdSNeil Armstrong gpio_direction_output(wcd939x->reset_gpio, 0); 3305*10f514bdSNeil Armstrong /* 20us sleep required after pulling the reset gpio to LOW */ 3306*10f514bdSNeil Armstrong usleep_range(20, 30); 3307*10f514bdSNeil Armstrong gpio_set_value(wcd939x->reset_gpio, 1); 3308*10f514bdSNeil Armstrong /* 20us sleep required after pulling the reset gpio to HIGH */ 3309*10f514bdSNeil Armstrong usleep_range(20, 30); 3310*10f514bdSNeil Armstrong 3311*10f514bdSNeil Armstrong return 0; 3312*10f514bdSNeil Armstrong } 3313*10f514bdSNeil Armstrong 3314*10f514bdSNeil Armstrong static int wcd939x_codec_hw_params(struct snd_pcm_substream *substream, 3315*10f514bdSNeil Armstrong struct snd_pcm_hw_params *params, 3316*10f514bdSNeil Armstrong struct snd_soc_dai *dai) 3317*10f514bdSNeil Armstrong { 3318*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = dev_get_drvdata(dai->dev); 3319*10f514bdSNeil Armstrong struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[dai->id]; 3320*10f514bdSNeil Armstrong 3321*10f514bdSNeil Armstrong return wcd939x_sdw_hw_params(wcd, substream, params, dai); 3322*10f514bdSNeil Armstrong } 3323*10f514bdSNeil Armstrong 3324*10f514bdSNeil Armstrong static int wcd939x_codec_free(struct snd_pcm_substream *substream, 3325*10f514bdSNeil Armstrong struct snd_soc_dai *dai) 3326*10f514bdSNeil Armstrong { 3327*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = dev_get_drvdata(dai->dev); 3328*10f514bdSNeil Armstrong struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[dai->id]; 3329*10f514bdSNeil Armstrong 3330*10f514bdSNeil Armstrong return wcd939x_sdw_free(wcd, substream, dai); 3331*10f514bdSNeil Armstrong } 3332*10f514bdSNeil Armstrong 3333*10f514bdSNeil Armstrong static int wcd939x_codec_set_sdw_stream(struct snd_soc_dai *dai, 3334*10f514bdSNeil Armstrong void *stream, int direction) 3335*10f514bdSNeil Armstrong { 3336*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = dev_get_drvdata(dai->dev); 3337*10f514bdSNeil Armstrong struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[dai->id]; 3338*10f514bdSNeil Armstrong 3339*10f514bdSNeil Armstrong return wcd939x_sdw_set_sdw_stream(wcd, dai, stream, direction); 3340*10f514bdSNeil Armstrong } 3341*10f514bdSNeil Armstrong 3342*10f514bdSNeil Armstrong static const struct snd_soc_dai_ops wcd939x_sdw_dai_ops = { 3343*10f514bdSNeil Armstrong .hw_params = wcd939x_codec_hw_params, 3344*10f514bdSNeil Armstrong .hw_free = wcd939x_codec_free, 3345*10f514bdSNeil Armstrong .set_stream = wcd939x_codec_set_sdw_stream, 3346*10f514bdSNeil Armstrong }; 3347*10f514bdSNeil Armstrong 3348*10f514bdSNeil Armstrong static struct snd_soc_dai_driver wcd939x_dais[] = { 3349*10f514bdSNeil Armstrong [0] = { 3350*10f514bdSNeil Armstrong .name = "wcd939x-sdw-rx", 3351*10f514bdSNeil Armstrong .playback = { 3352*10f514bdSNeil Armstrong .stream_name = "WCD AIF1 Playback", 3353*10f514bdSNeil Armstrong .rates = WCD939X_RATES_MASK | WCD939X_FRAC_RATES_MASK, 3354*10f514bdSNeil Armstrong .formats = WCD939X_FORMATS, 3355*10f514bdSNeil Armstrong .rate_max = 384000, 3356*10f514bdSNeil Armstrong .rate_min = 8000, 3357*10f514bdSNeil Armstrong .channels_min = 1, 3358*10f514bdSNeil Armstrong .channels_max = 2, 3359*10f514bdSNeil Armstrong }, 3360*10f514bdSNeil Armstrong .ops = &wcd939x_sdw_dai_ops, 3361*10f514bdSNeil Armstrong }, 3362*10f514bdSNeil Armstrong [1] = { 3363*10f514bdSNeil Armstrong .name = "wcd939x-sdw-tx", 3364*10f514bdSNeil Armstrong .capture = { 3365*10f514bdSNeil Armstrong .stream_name = "WCD AIF1 Capture", 3366*10f514bdSNeil Armstrong .rates = WCD939X_RATES_MASK | WCD939X_FRAC_RATES_MASK, 3367*10f514bdSNeil Armstrong .formats = WCD939X_FORMATS, 3368*10f514bdSNeil Armstrong .rate_min = 8000, 3369*10f514bdSNeil Armstrong .rate_max = 384000, 3370*10f514bdSNeil Armstrong .channels_min = 1, 3371*10f514bdSNeil Armstrong .channels_max = 4, 3372*10f514bdSNeil Armstrong }, 3373*10f514bdSNeil Armstrong .ops = &wcd939x_sdw_dai_ops, 3374*10f514bdSNeil Armstrong }, 3375*10f514bdSNeil Armstrong }; 3376*10f514bdSNeil Armstrong 3377*10f514bdSNeil Armstrong static int wcd939x_bind(struct device *dev) 3378*10f514bdSNeil Armstrong { 3379*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = dev_get_drvdata(dev); 3380*10f514bdSNeil Armstrong unsigned int version, id1, status1; 3381*10f514bdSNeil Armstrong int ret; 3382*10f514bdSNeil Armstrong 3383*10f514bdSNeil Armstrong #if IS_ENABLED(CONFIG_TYPEC) 3384*10f514bdSNeil Armstrong /* 3385*10f514bdSNeil Armstrong * Get USBSS type-c switch to send gnd/mic swap events 3386*10f514bdSNeil Armstrong * typec_switch is fetched now to avoid a probe deadlock since 3387*10f514bdSNeil Armstrong * the USBSS depends on the typec_mux register in wcd939x_probe() 3388*10f514bdSNeil Armstrong */ 3389*10f514bdSNeil Armstrong if (wcd939x->typec_analog_mux) { 3390*10f514bdSNeil Armstrong wcd939x->typec_switch = fwnode_typec_switch_get(dev->fwnode); 3391*10f514bdSNeil Armstrong if (IS_ERR(wcd939x->typec_switch)) 3392*10f514bdSNeil Armstrong return dev_err_probe(dev, PTR_ERR(wcd939x->typec_switch), 3393*10f514bdSNeil Armstrong "failed to acquire orientation-switch\n"); 3394*10f514bdSNeil Armstrong } 3395*10f514bdSNeil Armstrong #endif /* CONFIG_TYPEC */ 3396*10f514bdSNeil Armstrong 3397*10f514bdSNeil Armstrong ret = component_bind_all(dev, wcd939x); 3398*10f514bdSNeil Armstrong if (ret) { 3399*10f514bdSNeil Armstrong dev_err(dev, "%s: Slave bind failed, ret = %d\n", 3400*10f514bdSNeil Armstrong __func__, ret); 3401*10f514bdSNeil Armstrong goto err_put_typec_switch; 3402*10f514bdSNeil Armstrong } 3403*10f514bdSNeil Armstrong 3404*10f514bdSNeil Armstrong wcd939x->rxdev = wcd939x_sdw_device_get(wcd939x->rxnode); 3405*10f514bdSNeil Armstrong if (!wcd939x->rxdev) { 3406*10f514bdSNeil Armstrong dev_err(dev, "could not find slave with matching of node\n"); 3407*10f514bdSNeil Armstrong ret = -EINVAL; 3408*10f514bdSNeil Armstrong goto err_unbind; 3409*10f514bdSNeil Armstrong } 3410*10f514bdSNeil Armstrong wcd939x->sdw_priv[AIF1_PB] = dev_get_drvdata(wcd939x->rxdev); 3411*10f514bdSNeil Armstrong wcd939x->sdw_priv[AIF1_PB]->wcd939x = wcd939x; 3412*10f514bdSNeil Armstrong 3413*10f514bdSNeil Armstrong wcd939x->txdev = wcd939x_sdw_device_get(wcd939x->txnode); 3414*10f514bdSNeil Armstrong if (!wcd939x->txdev) { 3415*10f514bdSNeil Armstrong dev_err(dev, "could not find txslave with matching of node\n"); 3416*10f514bdSNeil Armstrong ret = -EINVAL; 3417*10f514bdSNeil Armstrong goto err_put_rxdev; 3418*10f514bdSNeil Armstrong } 3419*10f514bdSNeil Armstrong wcd939x->sdw_priv[AIF1_CAP] = dev_get_drvdata(wcd939x->txdev); 3420*10f514bdSNeil Armstrong wcd939x->sdw_priv[AIF1_CAP]->wcd939x = wcd939x; 3421*10f514bdSNeil Armstrong wcd939x->tx_sdw_dev = dev_to_sdw_dev(wcd939x->txdev); 3422*10f514bdSNeil Armstrong 3423*10f514bdSNeil Armstrong /* 3424*10f514bdSNeil Armstrong * As TX is main CSR reg interface, which should not be suspended first. 3425*10f514bdSNeil Armstrong * explicitly add the dependency link 3426*10f514bdSNeil Armstrong */ 3427*10f514bdSNeil Armstrong if (!device_link_add(wcd939x->rxdev, wcd939x->txdev, DL_FLAG_STATELESS | 3428*10f514bdSNeil Armstrong DL_FLAG_PM_RUNTIME)) { 3429*10f514bdSNeil Armstrong dev_err(dev, "could not devlink tx and rx\n"); 3430*10f514bdSNeil Armstrong ret = -EINVAL; 3431*10f514bdSNeil Armstrong goto err_put_txdev; 3432*10f514bdSNeil Armstrong } 3433*10f514bdSNeil Armstrong 3434*10f514bdSNeil Armstrong if (!device_link_add(dev, wcd939x->txdev, DL_FLAG_STATELESS | 3435*10f514bdSNeil Armstrong DL_FLAG_PM_RUNTIME)) { 3436*10f514bdSNeil Armstrong dev_err(dev, "could not devlink wcd and tx\n"); 3437*10f514bdSNeil Armstrong ret = -EINVAL; 3438*10f514bdSNeil Armstrong goto err_remove_rxtx_link; 3439*10f514bdSNeil Armstrong } 3440*10f514bdSNeil Armstrong 3441*10f514bdSNeil Armstrong if (!device_link_add(dev, wcd939x->rxdev, DL_FLAG_STATELESS | 3442*10f514bdSNeil Armstrong DL_FLAG_PM_RUNTIME)) { 3443*10f514bdSNeil Armstrong dev_err(dev, "could not devlink wcd and rx\n"); 3444*10f514bdSNeil Armstrong ret = -EINVAL; 3445*10f514bdSNeil Armstrong goto err_remove_tx_link; 3446*10f514bdSNeil Armstrong } 3447*10f514bdSNeil Armstrong 3448*10f514bdSNeil Armstrong /* Get regmap from TX SoundWire device */ 3449*10f514bdSNeil Armstrong wcd939x->regmap = wcd939x_swr_get_regmap(wcd939x->sdw_priv[AIF1_CAP]); 3450*10f514bdSNeil Armstrong if (IS_ERR(wcd939x->regmap)) { 3451*10f514bdSNeil Armstrong dev_err(dev, "could not get TX device regmap\n"); 3452*10f514bdSNeil Armstrong ret = PTR_ERR(wcd939x->regmap); 3453*10f514bdSNeil Armstrong goto err_remove_rx_link; 3454*10f514bdSNeil Armstrong } 3455*10f514bdSNeil Armstrong 3456*10f514bdSNeil Armstrong ret = wcd939x_irq_init(wcd939x, dev); 3457*10f514bdSNeil Armstrong if (ret) { 3458*10f514bdSNeil Armstrong dev_err(dev, "%s: IRQ init failed: %d\n", __func__, ret); 3459*10f514bdSNeil Armstrong goto err_remove_rx_link; 3460*10f514bdSNeil Armstrong } 3461*10f514bdSNeil Armstrong 3462*10f514bdSNeil Armstrong wcd939x->sdw_priv[AIF1_PB]->slave_irq = wcd939x->virq; 3463*10f514bdSNeil Armstrong wcd939x->sdw_priv[AIF1_CAP]->slave_irq = wcd939x->virq; 3464*10f514bdSNeil Armstrong 3465*10f514bdSNeil Armstrong ret = wcd939x_set_micbias_data(wcd939x); 3466*10f514bdSNeil Armstrong if (ret < 0) { 3467*10f514bdSNeil Armstrong dev_err(dev, "%s: bad micbias pdata\n", __func__); 3468*10f514bdSNeil Armstrong goto err_remove_rx_link; 3469*10f514bdSNeil Armstrong } 3470*10f514bdSNeil Armstrong 3471*10f514bdSNeil Armstrong /* Check WCD9395 version */ 3472*10f514bdSNeil Armstrong regmap_read(wcd939x->regmap, WCD939X_DIGITAL_CHIP_ID1, &id1); 3473*10f514bdSNeil Armstrong regmap_read(wcd939x->regmap, WCD939X_EAR_STATUS_REG_1, &status1); 3474*10f514bdSNeil Armstrong 3475*10f514bdSNeil Armstrong if (id1 == 0) 3476*10f514bdSNeil Armstrong version = ((status1 & 0x3) ? WCD939X_VERSION_1_1 : WCD939X_VERSION_1_0); 3477*10f514bdSNeil Armstrong else 3478*10f514bdSNeil Armstrong version = WCD939X_VERSION_2_0; 3479*10f514bdSNeil Armstrong 3480*10f514bdSNeil Armstrong dev_dbg(dev, "wcd939x version: %s\n", version_to_str(version)); 3481*10f514bdSNeil Armstrong 3482*10f514bdSNeil Armstrong ret = snd_soc_register_component(dev, &soc_codec_dev_wcd939x, 3483*10f514bdSNeil Armstrong wcd939x_dais, ARRAY_SIZE(wcd939x_dais)); 3484*10f514bdSNeil Armstrong if (ret) { 3485*10f514bdSNeil Armstrong dev_err(dev, "%s: Codec registration failed\n", 3486*10f514bdSNeil Armstrong __func__); 3487*10f514bdSNeil Armstrong goto err_remove_rx_link; 3488*10f514bdSNeil Armstrong } 3489*10f514bdSNeil Armstrong 3490*10f514bdSNeil Armstrong return 0; 3491*10f514bdSNeil Armstrong 3492*10f514bdSNeil Armstrong err_remove_rx_link: 3493*10f514bdSNeil Armstrong device_link_remove(dev, wcd939x->rxdev); 3494*10f514bdSNeil Armstrong err_remove_tx_link: 3495*10f514bdSNeil Armstrong device_link_remove(dev, wcd939x->txdev); 3496*10f514bdSNeil Armstrong err_remove_rxtx_link: 3497*10f514bdSNeil Armstrong device_link_remove(wcd939x->rxdev, wcd939x->txdev); 3498*10f514bdSNeil Armstrong err_put_txdev: 3499*10f514bdSNeil Armstrong put_device(wcd939x->txdev); 3500*10f514bdSNeil Armstrong err_put_rxdev: 3501*10f514bdSNeil Armstrong put_device(wcd939x->rxdev); 3502*10f514bdSNeil Armstrong err_unbind: 3503*10f514bdSNeil Armstrong component_unbind_all(dev, wcd939x); 3504*10f514bdSNeil Armstrong err_put_typec_switch: 3505*10f514bdSNeil Armstrong #if IS_ENABLED(CONFIG_TYPEC) 3506*10f514bdSNeil Armstrong if (wcd939x->typec_analog_mux) 3507*10f514bdSNeil Armstrong typec_switch_put(wcd939x->typec_switch); 3508*10f514bdSNeil Armstrong #endif /* CONFIG_TYPEC */ 3509*10f514bdSNeil Armstrong 3510*10f514bdSNeil Armstrong return ret; 3511*10f514bdSNeil Armstrong } 3512*10f514bdSNeil Armstrong 3513*10f514bdSNeil Armstrong static void wcd939x_unbind(struct device *dev) 3514*10f514bdSNeil Armstrong { 3515*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = dev_get_drvdata(dev); 3516*10f514bdSNeil Armstrong 3517*10f514bdSNeil Armstrong snd_soc_unregister_component(dev); 3518*10f514bdSNeil Armstrong device_link_remove(dev, wcd939x->txdev); 3519*10f514bdSNeil Armstrong device_link_remove(dev, wcd939x->rxdev); 3520*10f514bdSNeil Armstrong device_link_remove(wcd939x->rxdev, wcd939x->txdev); 3521*10f514bdSNeil Armstrong put_device(wcd939x->txdev); 3522*10f514bdSNeil Armstrong put_device(wcd939x->rxdev); 3523*10f514bdSNeil Armstrong component_unbind_all(dev, wcd939x); 3524*10f514bdSNeil Armstrong } 3525*10f514bdSNeil Armstrong 3526*10f514bdSNeil Armstrong static const struct component_master_ops wcd939x_comp_ops = { 3527*10f514bdSNeil Armstrong .bind = wcd939x_bind, 3528*10f514bdSNeil Armstrong .unbind = wcd939x_unbind, 3529*10f514bdSNeil Armstrong }; 3530*10f514bdSNeil Armstrong 3531*10f514bdSNeil Armstrong static int wcd939x_add_slave_components(struct wcd939x_priv *wcd939x, 3532*10f514bdSNeil Armstrong struct device *dev, 3533*10f514bdSNeil Armstrong struct component_match **matchptr) 3534*10f514bdSNeil Armstrong { 3535*10f514bdSNeil Armstrong struct device_node *np = dev->of_node; 3536*10f514bdSNeil Armstrong 3537*10f514bdSNeil Armstrong wcd939x->rxnode = of_parse_phandle(np, "qcom,rx-device", 0); 3538*10f514bdSNeil Armstrong if (!wcd939x->rxnode) { 3539*10f514bdSNeil Armstrong dev_err(dev, "%s: Rx-device node not defined\n", __func__); 3540*10f514bdSNeil Armstrong return -ENODEV; 3541*10f514bdSNeil Armstrong } 3542*10f514bdSNeil Armstrong 3543*10f514bdSNeil Armstrong of_node_get(wcd939x->rxnode); 3544*10f514bdSNeil Armstrong component_match_add_release(dev, matchptr, component_release_of, 3545*10f514bdSNeil Armstrong component_compare_of, wcd939x->rxnode); 3546*10f514bdSNeil Armstrong 3547*10f514bdSNeil Armstrong wcd939x->txnode = of_parse_phandle(np, "qcom,tx-device", 0); 3548*10f514bdSNeil Armstrong if (!wcd939x->txnode) { 3549*10f514bdSNeil Armstrong dev_err(dev, "%s: Tx-device node not defined\n", __func__); 3550*10f514bdSNeil Armstrong return -ENODEV; 3551*10f514bdSNeil Armstrong } 3552*10f514bdSNeil Armstrong of_node_get(wcd939x->txnode); 3553*10f514bdSNeil Armstrong component_match_add_release(dev, matchptr, component_release_of, 3554*10f514bdSNeil Armstrong component_compare_of, wcd939x->txnode); 3555*10f514bdSNeil Armstrong return 0; 3556*10f514bdSNeil Armstrong } 3557*10f514bdSNeil Armstrong 3558*10f514bdSNeil Armstrong static int wcd939x_probe(struct platform_device *pdev) 3559*10f514bdSNeil Armstrong { 3560*10f514bdSNeil Armstrong struct component_match *match = NULL; 3561*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = NULL; 3562*10f514bdSNeil Armstrong struct device *dev = &pdev->dev; 3563*10f514bdSNeil Armstrong int ret; 3564*10f514bdSNeil Armstrong 3565*10f514bdSNeil Armstrong wcd939x = devm_kzalloc(dev, sizeof(struct wcd939x_priv), 3566*10f514bdSNeil Armstrong GFP_KERNEL); 3567*10f514bdSNeil Armstrong if (!wcd939x) 3568*10f514bdSNeil Armstrong return -ENOMEM; 3569*10f514bdSNeil Armstrong 3570*10f514bdSNeil Armstrong dev_set_drvdata(dev, wcd939x); 3571*10f514bdSNeil Armstrong mutex_init(&wcd939x->micb_lock); 3572*10f514bdSNeil Armstrong 3573*10f514bdSNeil Armstrong ret = wcd939x_populate_dt_data(wcd939x, dev); 3574*10f514bdSNeil Armstrong if (ret) { 3575*10f514bdSNeil Armstrong dev_err(dev, "%s: Fail to obtain platform data\n", __func__); 3576*10f514bdSNeil Armstrong return -EINVAL; 3577*10f514bdSNeil Armstrong } 3578*10f514bdSNeil Armstrong 3579*10f514bdSNeil Armstrong #if IS_ENABLED(CONFIG_TYPEC) 3580*10f514bdSNeil Armstrong /* 3581*10f514bdSNeil Armstrong * Is USBSS is used to mux analog lines, 3582*10f514bdSNeil Armstrong * register a typec mux/switch to get typec events 3583*10f514bdSNeil Armstrong */ 3584*10f514bdSNeil Armstrong if (wcd939x->typec_analog_mux) { 3585*10f514bdSNeil Armstrong struct typec_mux_desc mux_desc = { 3586*10f514bdSNeil Armstrong .drvdata = wcd939x, 3587*10f514bdSNeil Armstrong .fwnode = dev_fwnode(dev), 3588*10f514bdSNeil Armstrong .set = wcd939x_typec_mux_set, 3589*10f514bdSNeil Armstrong }; 3590*10f514bdSNeil Armstrong struct typec_switch_desc sw_desc = { 3591*10f514bdSNeil Armstrong .drvdata = wcd939x, 3592*10f514bdSNeil Armstrong .fwnode = dev_fwnode(dev), 3593*10f514bdSNeil Armstrong .set = wcd939x_typec_switch_set, 3594*10f514bdSNeil Armstrong }; 3595*10f514bdSNeil Armstrong 3596*10f514bdSNeil Armstrong wcd939x->typec_mux = typec_mux_register(dev, &mux_desc); 3597*10f514bdSNeil Armstrong if (IS_ERR(wcd939x->typec_mux)) { 3598*10f514bdSNeil Armstrong ret = dev_err_probe(dev, PTR_ERR(wcd939x->typec_mux), 3599*10f514bdSNeil Armstrong "failed to register typec mux\n"); 3600*10f514bdSNeil Armstrong goto err_disable_regulators; 3601*10f514bdSNeil Armstrong } 3602*10f514bdSNeil Armstrong 3603*10f514bdSNeil Armstrong wcd939x->typec_sw = typec_switch_register(dev, &sw_desc); 3604*10f514bdSNeil Armstrong if (IS_ERR(wcd939x->typec_sw)) { 3605*10f514bdSNeil Armstrong ret = dev_err_probe(dev, PTR_ERR(wcd939x->typec_sw), 3606*10f514bdSNeil Armstrong "failed to register typec switch\n"); 3607*10f514bdSNeil Armstrong goto err_unregister_typec_mux; 3608*10f514bdSNeil Armstrong } 3609*10f514bdSNeil Armstrong } 3610*10f514bdSNeil Armstrong #endif /* CONFIG_TYPEC */ 3611*10f514bdSNeil Armstrong 3612*10f514bdSNeil Armstrong ret = wcd939x_add_slave_components(wcd939x, dev, &match); 3613*10f514bdSNeil Armstrong if (ret) 3614*10f514bdSNeil Armstrong goto err_unregister_typec_switch; 3615*10f514bdSNeil Armstrong 3616*10f514bdSNeil Armstrong wcd939x_reset(wcd939x); 3617*10f514bdSNeil Armstrong 3618*10f514bdSNeil Armstrong ret = component_master_add_with_match(dev, &wcd939x_comp_ops, match); 3619*10f514bdSNeil Armstrong if (ret) 3620*10f514bdSNeil Armstrong goto err_disable_regulators; 3621*10f514bdSNeil Armstrong 3622*10f514bdSNeil Armstrong pm_runtime_set_autosuspend_delay(dev, 1000); 3623*10f514bdSNeil Armstrong pm_runtime_use_autosuspend(dev); 3624*10f514bdSNeil Armstrong pm_runtime_mark_last_busy(dev); 3625*10f514bdSNeil Armstrong pm_runtime_set_active(dev); 3626*10f514bdSNeil Armstrong pm_runtime_enable(dev); 3627*10f514bdSNeil Armstrong pm_runtime_idle(dev); 3628*10f514bdSNeil Armstrong 3629*10f514bdSNeil Armstrong return 0; 3630*10f514bdSNeil Armstrong 3631*10f514bdSNeil Armstrong #if IS_ENABLED(CONFIG_TYPEC) 3632*10f514bdSNeil Armstrong err_unregister_typec_mux: 3633*10f514bdSNeil Armstrong if (wcd939x->typec_analog_mux) 3634*10f514bdSNeil Armstrong typec_mux_unregister(wcd939x->typec_mux); 3635*10f514bdSNeil Armstrong #endif /* CONFIG_TYPEC */ 3636*10f514bdSNeil Armstrong 3637*10f514bdSNeil Armstrong err_unregister_typec_switch: 3638*10f514bdSNeil Armstrong #if IS_ENABLED(CONFIG_TYPEC) 3639*10f514bdSNeil Armstrong if (wcd939x->typec_analog_mux) 3640*10f514bdSNeil Armstrong typec_switch_unregister(wcd939x->typec_sw); 3641*10f514bdSNeil Armstrong #endif /* CONFIG_TYPEC */ 3642*10f514bdSNeil Armstrong 3643*10f514bdSNeil Armstrong err_disable_regulators: 3644*10f514bdSNeil Armstrong regulator_bulk_disable(WCD939X_MAX_SUPPLY, wcd939x->supplies); 3645*10f514bdSNeil Armstrong regulator_bulk_free(WCD939X_MAX_SUPPLY, wcd939x->supplies); 3646*10f514bdSNeil Armstrong 3647*10f514bdSNeil Armstrong return ret; 3648*10f514bdSNeil Armstrong } 3649*10f514bdSNeil Armstrong 3650*10f514bdSNeil Armstrong static void wcd939x_remove(struct platform_device *pdev) 3651*10f514bdSNeil Armstrong { 3652*10f514bdSNeil Armstrong struct device *dev = &pdev->dev; 3653*10f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = dev_get_drvdata(dev); 3654*10f514bdSNeil Armstrong 3655*10f514bdSNeil Armstrong component_master_del(dev, &wcd939x_comp_ops); 3656*10f514bdSNeil Armstrong 3657*10f514bdSNeil Armstrong pm_runtime_disable(dev); 3658*10f514bdSNeil Armstrong pm_runtime_set_suspended(dev); 3659*10f514bdSNeil Armstrong pm_runtime_dont_use_autosuspend(dev); 3660*10f514bdSNeil Armstrong 3661*10f514bdSNeil Armstrong regulator_bulk_disable(WCD939X_MAX_SUPPLY, wcd939x->supplies); 3662*10f514bdSNeil Armstrong regulator_bulk_free(WCD939X_MAX_SUPPLY, wcd939x->supplies); 3663*10f514bdSNeil Armstrong } 3664*10f514bdSNeil Armstrong 3665*10f514bdSNeil Armstrong #if defined(CONFIG_OF) 3666*10f514bdSNeil Armstrong static const struct of_device_id wcd939x_dt_match[] = { 3667*10f514bdSNeil Armstrong { .compatible = "qcom,wcd9390-codec" }, 3668*10f514bdSNeil Armstrong { .compatible = "qcom,wcd9395-codec" }, 3669*10f514bdSNeil Armstrong {} 3670*10f514bdSNeil Armstrong }; 3671*10f514bdSNeil Armstrong MODULE_DEVICE_TABLE(of, wcd939x_dt_match); 3672*10f514bdSNeil Armstrong #endif 3673*10f514bdSNeil Armstrong 3674*10f514bdSNeil Armstrong static struct platform_driver wcd939x_codec_driver = { 3675*10f514bdSNeil Armstrong .probe = wcd939x_probe, 3676*10f514bdSNeil Armstrong .remove_new = wcd939x_remove, 3677*10f514bdSNeil Armstrong .driver = { 3678*10f514bdSNeil Armstrong .name = "wcd939x_codec", 3679*10f514bdSNeil Armstrong .of_match_table = of_match_ptr(wcd939x_dt_match), 3680*10f514bdSNeil Armstrong .suppress_bind_attrs = true, 3681*10f514bdSNeil Armstrong }, 3682*10f514bdSNeil Armstrong }; 3683*10f514bdSNeil Armstrong 3684*10f514bdSNeil Armstrong module_platform_driver(wcd939x_codec_driver); 3685*10f514bdSNeil Armstrong MODULE_DESCRIPTION("WCD939X Codec driver"); 3686*10f514bdSNeil Armstrong MODULE_LICENSE("GPL"); 3687