110f514bdSNeil Armstrong // SPDX-License-Identifier: GPL-2.0-only 210f514bdSNeil Armstrong /* 310f514bdSNeil Armstrong * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. 410f514bdSNeil Armstrong * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. 510f514bdSNeil Armstrong * Copyright (c) 2023, Linaro Limited 610f514bdSNeil Armstrong */ 710f514bdSNeil Armstrong 810f514bdSNeil Armstrong #include <linux/module.h> 910f514bdSNeil Armstrong #include <linux/slab.h> 1010f514bdSNeil Armstrong #include <linux/platform_device.h> 1110f514bdSNeil Armstrong #include <linux/device.h> 1210f514bdSNeil Armstrong #include <linux/delay.h> 1310f514bdSNeil Armstrong #include <linux/gpio/consumer.h> 1410f514bdSNeil Armstrong #include <linux/kernel.h> 1510f514bdSNeil Armstrong #include <linux/pm_runtime.h> 1610f514bdSNeil Armstrong #include <linux/component.h> 1710f514bdSNeil Armstrong #include <sound/tlv.h> 1810f514bdSNeil Armstrong #include <linux/of_gpio.h> 1910f514bdSNeil Armstrong #include <linux/of_graph.h> 2010f514bdSNeil Armstrong #include <linux/of.h> 2110f514bdSNeil Armstrong #include <sound/jack.h> 2210f514bdSNeil Armstrong #include <sound/pcm.h> 2310f514bdSNeil Armstrong #include <sound/pcm_params.h> 2410f514bdSNeil Armstrong #include <linux/regmap.h> 2510f514bdSNeil Armstrong #include <sound/soc.h> 2610f514bdSNeil Armstrong #include <sound/soc-dapm.h> 2710f514bdSNeil Armstrong #include <linux/regulator/consumer.h> 2810f514bdSNeil Armstrong #include <linux/usb/typec_mux.h> 2910f514bdSNeil Armstrong #include <linux/usb/typec_altmode.h> 3010f514bdSNeil Armstrong 3110f514bdSNeil Armstrong #include "wcd-clsh-v2.h" 3210f514bdSNeil Armstrong #include "wcd-mbhc-v2.h" 3310f514bdSNeil Armstrong #include "wcd939x.h" 3410f514bdSNeil Armstrong 3510f514bdSNeil Armstrong #define WCD939X_MAX_MICBIAS (4) 3610f514bdSNeil Armstrong #define WCD939X_MAX_SUPPLY (4) 3710f514bdSNeil Armstrong #define WCD939X_MBHC_MAX_BUTTONS (8) 3810f514bdSNeil Armstrong #define TX_ADC_MAX (4) 3910f514bdSNeil Armstrong #define WCD_MBHC_HS_V_MAX 1600 4010f514bdSNeil Armstrong 4110f514bdSNeil Armstrong enum { 4210f514bdSNeil Armstrong WCD939X_VERSION_1_0 = 0, 4310f514bdSNeil Armstrong WCD939X_VERSION_1_1, 4410f514bdSNeil Armstrong WCD939X_VERSION_2_0, 4510f514bdSNeil Armstrong }; 4610f514bdSNeil Armstrong 4710f514bdSNeil Armstrong #define WCD939X_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ 4810f514bdSNeil Armstrong SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ 4910f514bdSNeil Armstrong SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\ 5010f514bdSNeil Armstrong SNDRV_PCM_RATE_384000) 5110f514bdSNeil Armstrong /* Fractional Rates */ 5210f514bdSNeil Armstrong #define WCD939X_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\ 5310f514bdSNeil Armstrong SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800) 5410f514bdSNeil Armstrong #define WCD939X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ 5510f514bdSNeil Armstrong SNDRV_PCM_FMTBIT_S24_LE |\ 5610f514bdSNeil Armstrong SNDRV_PCM_FMTBIT_S24_3LE |\ 5710f514bdSNeil Armstrong SNDRV_PCM_FMTBIT_S32_LE) 5810f514bdSNeil Armstrong 5910f514bdSNeil Armstrong /* Convert from vout ctl to micbias voltage in mV */ 6010f514bdSNeil Armstrong #define WCD_VOUT_CTL_TO_MICB(v) (1000 + (v) * 50) 6110f514bdSNeil Armstrong #define SWR_CLK_RATE_0P6MHZ (600000) 6210f514bdSNeil Armstrong #define SWR_CLK_RATE_1P2MHZ (1200000) 6310f514bdSNeil Armstrong #define SWR_CLK_RATE_2P4MHZ (2400000) 6410f514bdSNeil Armstrong #define SWR_CLK_RATE_4P8MHZ (4800000) 6510f514bdSNeil Armstrong #define SWR_CLK_RATE_9P6MHZ (9600000) 6610f514bdSNeil Armstrong #define SWR_CLK_RATE_11P2896MHZ (1128960) 6710f514bdSNeil Armstrong 6810f514bdSNeil Armstrong #define ADC_MODE_VAL_HIFI 0x01 6910f514bdSNeil Armstrong #define ADC_MODE_VAL_LO_HIF 0x02 7010f514bdSNeil Armstrong #define ADC_MODE_VAL_NORMAL 0x03 7110f514bdSNeil Armstrong #define ADC_MODE_VAL_LP 0x05 7210f514bdSNeil Armstrong #define ADC_MODE_VAL_ULP1 0x09 7310f514bdSNeil Armstrong #define ADC_MODE_VAL_ULP2 0x0B 7410f514bdSNeil Armstrong 7510f514bdSNeil Armstrong /* Z value defined in milliohm */ 7610f514bdSNeil Armstrong #define WCD939X_ZDET_VAL_32 (32000) 7710f514bdSNeil Armstrong #define WCD939X_ZDET_VAL_400 (400000) 7810f514bdSNeil Armstrong #define WCD939X_ZDET_VAL_1200 (1200000) 7910f514bdSNeil Armstrong #define WCD939X_ZDET_VAL_100K (100000000) 8010f514bdSNeil Armstrong 8110f514bdSNeil Armstrong /* Z floating defined in ohms */ 8210f514bdSNeil Armstrong #define WCD939X_ZDET_FLOATING_IMPEDANCE (0x0FFFFFFE) 8310f514bdSNeil Armstrong #define WCD939X_ZDET_NUM_MEASUREMENTS (900) 8410f514bdSNeil Armstrong #define WCD939X_MBHC_GET_C1(c) (((c) & 0xC000) >> 14) 8510f514bdSNeil Armstrong #define WCD939X_MBHC_GET_X1(x) ((x) & 0x3FFF) 8610f514bdSNeil Armstrong 8710f514bdSNeil Armstrong /* Z value compared in milliOhm */ 8810f514bdSNeil Armstrong #define WCD939X_MBHC_IS_SECOND_RAMP_REQUIRED(z) false 8910f514bdSNeil Armstrong #define WCD939X_ANA_MBHC_ZDET_CONST (1018 * 1024) 9010f514bdSNeil Armstrong 9110f514bdSNeil Armstrong enum { 9210f514bdSNeil Armstrong WCD9390 = 0, 9310f514bdSNeil Armstrong WCD9395 = 5, 9410f514bdSNeil Armstrong }; 9510f514bdSNeil Armstrong 9610f514bdSNeil Armstrong enum { 9710f514bdSNeil Armstrong /* INTR_CTRL_INT_MASK_0 */ 9810f514bdSNeil Armstrong WCD939X_IRQ_MBHC_BUTTON_PRESS_DET = 0, 9910f514bdSNeil Armstrong WCD939X_IRQ_MBHC_BUTTON_RELEASE_DET, 10010f514bdSNeil Armstrong WCD939X_IRQ_MBHC_ELECT_INS_REM_DET, 10110f514bdSNeil Armstrong WCD939X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 10210f514bdSNeil Armstrong WCD939X_IRQ_MBHC_SW_DET, 10310f514bdSNeil Armstrong WCD939X_IRQ_HPHR_OCP_INT, 10410f514bdSNeil Armstrong WCD939X_IRQ_HPHR_CNP_INT, 10510f514bdSNeil Armstrong WCD939X_IRQ_HPHL_OCP_INT, 10610f514bdSNeil Armstrong 10710f514bdSNeil Armstrong /* INTR_CTRL_INT_MASK_1 */ 10810f514bdSNeil Armstrong WCD939X_IRQ_HPHL_CNP_INT, 10910f514bdSNeil Armstrong WCD939X_IRQ_EAR_CNP_INT, 11010f514bdSNeil Armstrong WCD939X_IRQ_EAR_SCD_INT, 11110f514bdSNeil Armstrong WCD939X_IRQ_HPHL_PDM_WD_INT, 11210f514bdSNeil Armstrong WCD939X_IRQ_HPHR_PDM_WD_INT, 11310f514bdSNeil Armstrong WCD939X_IRQ_EAR_PDM_WD_INT, 11410f514bdSNeil Armstrong 11510f514bdSNeil Armstrong /* INTR_CTRL_INT_MASK_2 */ 11610f514bdSNeil Armstrong WCD939X_IRQ_MBHC_MOISTURE_INT, 11710f514bdSNeil Armstrong WCD939X_IRQ_HPHL_SURGE_DET_INT, 11810f514bdSNeil Armstrong WCD939X_IRQ_HPHR_SURGE_DET_INT, 11910f514bdSNeil Armstrong WCD939X_NUM_IRQS, 12010f514bdSNeil Armstrong }; 12110f514bdSNeil Armstrong 12210f514bdSNeil Armstrong enum { 12310f514bdSNeil Armstrong MICB_BIAS_DISABLE = 0, 12410f514bdSNeil Armstrong MICB_BIAS_ENABLE, 12510f514bdSNeil Armstrong MICB_BIAS_PULL_UP, 12610f514bdSNeil Armstrong MICB_BIAS_PULL_DOWN, 12710f514bdSNeil Armstrong }; 12810f514bdSNeil Armstrong 12910f514bdSNeil Armstrong enum { 13010f514bdSNeil Armstrong WCD_ADC1 = 0, 13110f514bdSNeil Armstrong WCD_ADC2, 13210f514bdSNeil Armstrong WCD_ADC3, 13310f514bdSNeil Armstrong WCD_ADC4, 13410f514bdSNeil Armstrong HPH_PA_DELAY, 13510f514bdSNeil Armstrong }; 13610f514bdSNeil Armstrong 13710f514bdSNeil Armstrong enum { 13810f514bdSNeil Armstrong ADC_MODE_INVALID = 0, 13910f514bdSNeil Armstrong ADC_MODE_HIFI, 14010f514bdSNeil Armstrong ADC_MODE_LO_HIF, 14110f514bdSNeil Armstrong ADC_MODE_NORMAL, 14210f514bdSNeil Armstrong ADC_MODE_LP, 14310f514bdSNeil Armstrong ADC_MODE_ULP1, 14410f514bdSNeil Armstrong ADC_MODE_ULP2, 14510f514bdSNeil Armstrong }; 14610f514bdSNeil Armstrong 14710f514bdSNeil Armstrong enum { 14810f514bdSNeil Armstrong AIF1_PB = 0, 14910f514bdSNeil Armstrong AIF1_CAP, 15010f514bdSNeil Armstrong NUM_CODEC_DAIS, 15110f514bdSNeil Armstrong }; 15210f514bdSNeil Armstrong 15310f514bdSNeil Armstrong static u8 tx_mode_bit[] = { 15410f514bdSNeil Armstrong [ADC_MODE_INVALID] = 0x00, 15510f514bdSNeil Armstrong [ADC_MODE_HIFI] = 0x01, 15610f514bdSNeil Armstrong [ADC_MODE_LO_HIF] = 0x02, 15710f514bdSNeil Armstrong [ADC_MODE_NORMAL] = 0x04, 15810f514bdSNeil Armstrong [ADC_MODE_LP] = 0x08, 15910f514bdSNeil Armstrong [ADC_MODE_ULP1] = 0x10, 16010f514bdSNeil Armstrong [ADC_MODE_ULP2] = 0x20, 16110f514bdSNeil Armstrong }; 16210f514bdSNeil Armstrong 16310f514bdSNeil Armstrong struct zdet_param { 16410f514bdSNeil Armstrong u16 ldo_ctl; 16510f514bdSNeil Armstrong u16 noff; 16610f514bdSNeil Armstrong u16 nshift; 16710f514bdSNeil Armstrong u16 btn5; 16810f514bdSNeil Armstrong u16 btn6; 16910f514bdSNeil Armstrong u16 btn7; 17010f514bdSNeil Armstrong }; 17110f514bdSNeil Armstrong 17210f514bdSNeil Armstrong struct wcd939x_priv { 17310f514bdSNeil Armstrong struct sdw_slave *tx_sdw_dev; 17410f514bdSNeil Armstrong struct wcd939x_sdw_priv *sdw_priv[NUM_CODEC_DAIS]; 17510f514bdSNeil Armstrong struct device *txdev; 17610f514bdSNeil Armstrong struct device *rxdev; 17710f514bdSNeil Armstrong struct device_node *rxnode, *txnode; 17810f514bdSNeil Armstrong struct regmap *regmap; 17910f514bdSNeil Armstrong struct snd_soc_component *component; 18010f514bdSNeil Armstrong /* micb setup lock */ 18110f514bdSNeil Armstrong struct mutex micb_lock; 18210f514bdSNeil Armstrong /* typec handling */ 18310f514bdSNeil Armstrong bool typec_analog_mux; 18410f514bdSNeil Armstrong #if IS_ENABLED(CONFIG_TYPEC) 18510f514bdSNeil Armstrong struct typec_mux_dev *typec_mux; 18610f514bdSNeil Armstrong struct typec_switch_dev *typec_sw; 18710f514bdSNeil Armstrong enum typec_orientation typec_orientation; 18810f514bdSNeil Armstrong unsigned long typec_mode; 18910f514bdSNeil Armstrong struct typec_switch *typec_switch; 19010f514bdSNeil Armstrong #endif /* CONFIG_TYPEC */ 19110f514bdSNeil Armstrong /* mbhc module */ 19210f514bdSNeil Armstrong struct wcd_mbhc *wcd_mbhc; 19310f514bdSNeil Armstrong struct wcd_mbhc_config mbhc_cfg; 19410f514bdSNeil Armstrong struct wcd_mbhc_intr intr_ids; 19510f514bdSNeil Armstrong struct wcd_clsh_ctrl *clsh_info; 19610f514bdSNeil Armstrong struct irq_domain *virq; 19710f514bdSNeil Armstrong struct regmap_irq_chip *wcd_regmap_irq_chip; 19810f514bdSNeil Armstrong struct regmap_irq_chip_data *irq_chip; 19910f514bdSNeil Armstrong struct regulator_bulk_data supplies[WCD939X_MAX_SUPPLY]; 20010f514bdSNeil Armstrong struct snd_soc_jack *jack; 20110f514bdSNeil Armstrong unsigned long status_mask; 20210f514bdSNeil Armstrong s32 micb_ref[WCD939X_MAX_MICBIAS]; 20310f514bdSNeil Armstrong s32 pullup_ref[WCD939X_MAX_MICBIAS]; 20410f514bdSNeil Armstrong u32 hph_mode; 20510f514bdSNeil Armstrong u32 tx_mode[TX_ADC_MAX]; 20610f514bdSNeil Armstrong int variant; 20710f514bdSNeil Armstrong int reset_gpio; 20810f514bdSNeil Armstrong u32 micb1_mv; 20910f514bdSNeil Armstrong u32 micb2_mv; 21010f514bdSNeil Armstrong u32 micb3_mv; 21110f514bdSNeil Armstrong u32 micb4_mv; 21210f514bdSNeil Armstrong int hphr_pdm_wd_int; 21310f514bdSNeil Armstrong int hphl_pdm_wd_int; 21410f514bdSNeil Armstrong int ear_pdm_wd_int; 21510f514bdSNeil Armstrong bool comp1_enable; 21610f514bdSNeil Armstrong bool comp2_enable; 21710f514bdSNeil Armstrong bool ldoh; 21810f514bdSNeil Armstrong }; 21910f514bdSNeil Armstrong 22010f514bdSNeil Armstrong static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800); 22110f514bdSNeil Armstrong static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); 22210f514bdSNeil Armstrong static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); 22310f514bdSNeil Armstrong 22410f514bdSNeil Armstrong static struct wcd_mbhc_field wcd_mbhc_fields[WCD_MBHC_REG_FUNC_MAX] = { 22510f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_L_DET_EN, WCD939X_ANA_MBHC_MECH, 0x80), 22610f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_GND_DET_EN, WCD939X_ANA_MBHC_MECH, 0x40), 22710f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_MECH_DETECTION_TYPE, WCD939X_ANA_MBHC_MECH, 0x20), 22810f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_MIC_CLAMP_CTL, WCD939X_MBHC_NEW_PLUG_DETECT_CTL, 0x30), 22910f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_ELECT_DETECTION_TYPE, WCD939X_ANA_MBHC_ELECT, 0x08), 23010f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_CTRL, WCD939X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x1F), 23110f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, WCD939X_ANA_MBHC_MECH, 0x04), 23210f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHL_PLUG_TYPE, WCD939X_ANA_MBHC_MECH, 0x10), 23310f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_GND_PLUG_TYPE, WCD939X_ANA_MBHC_MECH, 0x08), 23410f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_SW_HPH_LP_100K_TO_GND, WCD939X_ANA_MBHC_MECH, 0x01), 23510f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_ELECT_SCHMT_ISRC, WCD939X_ANA_MBHC_ELECT, 0x06), 23610f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_FSM_EN, WCD939X_ANA_MBHC_ELECT, 0x80), 23710f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_INSREM_DBNC, WCD939X_MBHC_NEW_PLUG_DETECT_CTL, 0x0F), 23810f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_BTN_DBNC, WCD939X_MBHC_NEW_CTL_1, 0x03), 23910f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HS_VREF, WCD939X_MBHC_NEW_CTL_2, 0x03), 24010f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HS_COMP_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0x08), 24110f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_IN2P_CLAMP_STATE, WCD939X_ANA_MBHC_RESULT_3, 0x10), 24210f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_MIC_SCHMT_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0x20), 24310f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHL_SCHMT_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0x80), 24410f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHR_SCHMT_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0x40), 24510f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_OCP_FSM_EN, WCD939X_HPH_OCP_CTL, 0x10), 24610f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_BTN_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0x07), 24710f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_BTN_ISRC_CTL, WCD939X_ANA_MBHC_ELECT, 0x70), 24810f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_ELECT_RESULT, WCD939X_ANA_MBHC_RESULT_3, 0xFF), 24910f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_MICB_CTRL, WCD939X_ANA_MICB2, 0xC0), 25010f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPH_CNP_WG_TIME, WCD939X_HPH_CNP_WG_TIME, 0xFF), 25110f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHR_PA_EN, WCD939X_ANA_HPH, 0x40), 25210f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHL_PA_EN, WCD939X_ANA_HPH, 0x80), 25310f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPH_PA_EN, WCD939X_ANA_HPH, 0xC0), 25410f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_SWCH_LEVEL_REMOVE, WCD939X_ANA_MBHC_RESULT_3, 0x10), 25510f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_ANC_DET_EN, WCD939X_MBHC_CTL_BCS, 0x02), 25610f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_FSM_STATUS, WCD939X_MBHC_NEW_FSM_STATUS, 0x01), 25710f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_MUX_CTL, WCD939X_MBHC_NEW_CTL_2, 0x70), 25810f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_MOISTURE_STATUS, WCD939X_MBHC_NEW_FSM_STATUS, 0x20), 25910f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHR_GND, WCD939X_HPH_PA_CTL2, 0x40), 26010f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHL_GND, WCD939X_HPH_PA_CTL2, 0x10), 26110f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_DET_EN, WCD939X_HPH_L_TEST, 0x01), 26210f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_DET_EN, WCD939X_HPH_R_TEST, 0x01), 26310f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHL_OCP_STATUS, WCD939X_DIGITAL_INTR_STATUS_0, 0x80), 26410f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_HPHR_OCP_STATUS, WCD939X_DIGITAL_INTR_STATUS_0, 0x20), 26510f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_ADC_EN, WCD939X_MBHC_NEW_CTL_1, 0x08), 26610f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_ADC_COMPLETE, WCD939X_MBHC_NEW_FSM_STATUS, 0x40), 26710f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_ADC_TIMEOUT, WCD939X_MBHC_NEW_FSM_STATUS, 0x80), 26810f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_ADC_RESULT, WCD939X_MBHC_NEW_ADC_RESULT, 0xFF), 26910f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_MICB2_VOUT, WCD939X_ANA_MICB2, 0x3F), 27010f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_ADC_MODE, WCD939X_MBHC_NEW_CTL_1, 0x10), 27110f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_DETECTION_DONE, WCD939X_MBHC_NEW_CTL_1, 0x04), 27210f514bdSNeil Armstrong WCD_MBHC_FIELD(WCD_MBHC_ELECT_ISRC_EN, WCD939X_ANA_MBHC_ZDET, 0x02), 27310f514bdSNeil Armstrong }; 27410f514bdSNeil Armstrong 27510f514bdSNeil Armstrong static const struct regmap_irq wcd939x_irqs[WCD939X_NUM_IRQS] = { 27610f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_BUTTON_PRESS_DET, 0, 0x01), 27710f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_BUTTON_RELEASE_DET, 0, 0x02), 27810f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_ELECT_INS_REM_DET, 0, 0x04), 27910f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 0, 0x08), 28010f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_SW_DET, 0, 0x10), 28110f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_OCP_INT, 0, 0x20), 28210f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_CNP_INT, 0, 0x40), 28310f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_HPHL_OCP_INT, 0, 0x80), 28410f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_HPHL_CNP_INT, 1, 0x01), 28510f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_EAR_CNP_INT, 1, 0x02), 28610f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_EAR_SCD_INT, 1, 0x04), 28710f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_HPHL_PDM_WD_INT, 1, 0x20), 28810f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_PDM_WD_INT, 1, 0x40), 28910f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_EAR_PDM_WD_INT, 1, 0x80), 29010f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_MBHC_MOISTURE_INT, 2, 0x02), 29110f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_HPHL_SURGE_DET_INT, 2, 0x04), 29210f514bdSNeil Armstrong REGMAP_IRQ_REG(WCD939X_IRQ_HPHR_SURGE_DET_INT, 2, 0x08), 29310f514bdSNeil Armstrong }; 29410f514bdSNeil Armstrong 29510f514bdSNeil Armstrong static struct regmap_irq_chip wcd939x_regmap_irq_chip = { 29610f514bdSNeil Armstrong .name = "wcd939x", 29710f514bdSNeil Armstrong .irqs = wcd939x_irqs, 29810f514bdSNeil Armstrong .num_irqs = ARRAY_SIZE(wcd939x_irqs), 29910f514bdSNeil Armstrong .num_regs = 3, 30010f514bdSNeil Armstrong .status_base = WCD939X_DIGITAL_INTR_STATUS_0, 30110f514bdSNeil Armstrong .mask_base = WCD939X_DIGITAL_INTR_MASK_0, 30210f514bdSNeil Armstrong .ack_base = WCD939X_DIGITAL_INTR_CLEAR_0, 30310f514bdSNeil Armstrong .use_ack = 1, 30410f514bdSNeil Armstrong .runtime_pm = true, 30510f514bdSNeil Armstrong .irq_drv_data = NULL, 30610f514bdSNeil Armstrong }; 30710f514bdSNeil Armstrong 30810f514bdSNeil Armstrong static int wcd939x_get_clk_rate(int mode) 30910f514bdSNeil Armstrong { 31010f514bdSNeil Armstrong int rate; 31110f514bdSNeil Armstrong 31210f514bdSNeil Armstrong switch (mode) { 31310f514bdSNeil Armstrong case ADC_MODE_ULP2: 31410f514bdSNeil Armstrong rate = SWR_CLK_RATE_0P6MHZ; 31510f514bdSNeil Armstrong break; 31610f514bdSNeil Armstrong case ADC_MODE_ULP1: 31710f514bdSNeil Armstrong rate = SWR_CLK_RATE_1P2MHZ; 31810f514bdSNeil Armstrong break; 31910f514bdSNeil Armstrong case ADC_MODE_LP: 32010f514bdSNeil Armstrong rate = SWR_CLK_RATE_4P8MHZ; 32110f514bdSNeil Armstrong break; 32210f514bdSNeil Armstrong case ADC_MODE_NORMAL: 32310f514bdSNeil Armstrong case ADC_MODE_LO_HIF: 32410f514bdSNeil Armstrong case ADC_MODE_HIFI: 32510f514bdSNeil Armstrong case ADC_MODE_INVALID: 32610f514bdSNeil Armstrong default: 32710f514bdSNeil Armstrong rate = SWR_CLK_RATE_9P6MHZ; 32810f514bdSNeil Armstrong break; 32910f514bdSNeil Armstrong } 33010f514bdSNeil Armstrong 33110f514bdSNeil Armstrong return rate; 33210f514bdSNeil Armstrong } 33310f514bdSNeil Armstrong 33410f514bdSNeil Armstrong static int wcd939x_set_swr_clk_rate(struct snd_soc_component *component, int rate, int bank) 33510f514bdSNeil Armstrong { 33610f514bdSNeil Armstrong u8 mask = (bank ? 0xF0 : 0x0F); 33710f514bdSNeil Armstrong u8 val = 0; 33810f514bdSNeil Armstrong 33910f514bdSNeil Armstrong switch (rate) { 34010f514bdSNeil Armstrong case SWR_CLK_RATE_0P6MHZ: 34110f514bdSNeil Armstrong val = 6; 34210f514bdSNeil Armstrong break; 34310f514bdSNeil Armstrong case SWR_CLK_RATE_1P2MHZ: 34410f514bdSNeil Armstrong val = 5; 34510f514bdSNeil Armstrong break; 34610f514bdSNeil Armstrong case SWR_CLK_RATE_2P4MHZ: 34710f514bdSNeil Armstrong val = 3; 34810f514bdSNeil Armstrong break; 34910f514bdSNeil Armstrong case SWR_CLK_RATE_4P8MHZ: 35010f514bdSNeil Armstrong val = 1; 35110f514bdSNeil Armstrong break; 35210f514bdSNeil Armstrong case SWR_CLK_RATE_9P6MHZ: 35310f514bdSNeil Armstrong default: 35410f514bdSNeil Armstrong val = 0; 35510f514bdSNeil Armstrong break; 35610f514bdSNeil Armstrong } 35710f514bdSNeil Armstrong 35810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_SWR_TX_CLK_RATE, mask, val); 35910f514bdSNeil Armstrong 36010f514bdSNeil Armstrong return 0; 36110f514bdSNeil Armstrong } 36210f514bdSNeil Armstrong 36310f514bdSNeil Armstrong static int wcd939x_io_init(struct snd_soc_component *component) 36410f514bdSNeil Armstrong { 36510f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_BIAS, 36610f514bdSNeil Armstrong WCD939X_BIAS_ANALOG_BIAS_EN, true); 36710f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_BIAS, 36810f514bdSNeil Armstrong WCD939X_BIAS_PRECHRG_EN, true); 36910f514bdSNeil Armstrong 37010f514bdSNeil Armstrong /* 10 msec delay as per HW requirement */ 37110f514bdSNeil Armstrong usleep_range(10000, 10010); 37210f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_BIAS, 37310f514bdSNeil Armstrong WCD939X_BIAS_PRECHRG_EN, false); 37410f514bdSNeil Armstrong 37510f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_L, 37610f514bdSNeil Armstrong WCD939X_RDAC_HD2_CTL_L_HD2_RES_DIV_CTL_L, 0x15); 37710f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_R, 37810f514bdSNeil Armstrong WCD939X_RDAC_HD2_CTL_R_HD2_RES_DIV_CTL_R, 0x15); 37910f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DMIC_CTL, 38010f514bdSNeil Armstrong WCD939X_CDC_DMIC_CTL_CLK_SCALE_EN, true); 38110f514bdSNeil Armstrong 38210f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2CASC_ULP, 38310f514bdSNeil Armstrong WCD939X_FE_ICTRL_STG2CASC_ULP_ICTRL_SCBIAS_ULP0P6M, 1); 38410f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2CASC_ULP, 38510f514bdSNeil Armstrong WCD939X_FE_ICTRL_STG2CASC_ULP_VALUE, 4); 38610f514bdSNeil Armstrong 38710f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_TX_COM_NEW_INT_FE_ICTRL_STG2MAIN_ULP, 38810f514bdSNeil Armstrong WCD939X_FE_ICTRL_STG2MAIN_ULP_VALUE, 8); 38910f514bdSNeil Armstrong 39010f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MICB1_TEST_CTL_1, 39110f514bdSNeil Armstrong WCD939X_TEST_CTL_1_NOISE_FILT_RES_VAL, 7); 39210f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MICB2_TEST_CTL_1, 39310f514bdSNeil Armstrong WCD939X_TEST_CTL_1_NOISE_FILT_RES_VAL, 7); 39410f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MICB3_TEST_CTL_1, 39510f514bdSNeil Armstrong WCD939X_TEST_CTL_1_NOISE_FILT_RES_VAL, 7); 39610f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MICB4_TEST_CTL_1, 39710f514bdSNeil Armstrong WCD939X_TEST_CTL_1_NOISE_FILT_RES_VAL, 7); 39810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_TX_3_4_TEST_BLK_EN2, 39910f514bdSNeil Armstrong WCD939X_TEST_BLK_EN2_TXFE2_MBHC_CLKRST_EN, false); 40010f514bdSNeil Armstrong 40110f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN, 40210f514bdSNeil Armstrong WCD939X_EN_EN_SURGE_PROTECTION_HPHL, false); 40310f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN, 40410f514bdSNeil Armstrong WCD939X_EN_EN_SURGE_PROTECTION_HPHR, false); 40510f514bdSNeil Armstrong 40610f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_OCP_CTL, 40710f514bdSNeil Armstrong WCD939X_OCP_CTL_OCP_FSM_EN, true); 40810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_OCP_CTL, 40910f514bdSNeil Armstrong WCD939X_OCP_CTL_SCD_OP_EN, true); 41010f514bdSNeil Armstrong 41110f514bdSNeil Armstrong snd_soc_component_write(component, WCD939X_E_CFG0, 41210f514bdSNeil Armstrong WCD939X_CFG0_IDLE_STEREO | 41310f514bdSNeil Armstrong WCD939X_CFG0_AUTO_DISABLE_ANC); 41410f514bdSNeil Armstrong 41510f514bdSNeil Armstrong return 0; 41610f514bdSNeil Armstrong } 41710f514bdSNeil Armstrong 41810f514bdSNeil Armstrong static int wcd939x_sdw_connect_port(struct wcd939x_sdw_ch_info *ch_info, 41910f514bdSNeil Armstrong struct sdw_port_config *port_config, 42010f514bdSNeil Armstrong u8 enable) 42110f514bdSNeil Armstrong { 42210f514bdSNeil Armstrong u8 ch_mask, port_num; 42310f514bdSNeil Armstrong 42410f514bdSNeil Armstrong port_num = ch_info->port_num; 42510f514bdSNeil Armstrong ch_mask = ch_info->ch_mask; 42610f514bdSNeil Armstrong 42710f514bdSNeil Armstrong port_config->num = port_num; 42810f514bdSNeil Armstrong 42910f514bdSNeil Armstrong if (enable) 43010f514bdSNeil Armstrong port_config->ch_mask |= ch_mask; 43110f514bdSNeil Armstrong else 43210f514bdSNeil Armstrong port_config->ch_mask &= ~ch_mask; 43310f514bdSNeil Armstrong 43410f514bdSNeil Armstrong return 0; 43510f514bdSNeil Armstrong } 43610f514bdSNeil Armstrong 43710f514bdSNeil Armstrong static int wcd939x_connect_port(struct wcd939x_sdw_priv *wcd, u8 port_num, u8 ch_id, u8 enable) 43810f514bdSNeil Armstrong { 43910f514bdSNeil Armstrong return wcd939x_sdw_connect_port(&wcd->ch_info[ch_id], 44010f514bdSNeil Armstrong &wcd->port_config[port_num - 1], 44110f514bdSNeil Armstrong enable); 44210f514bdSNeil Armstrong } 44310f514bdSNeil Armstrong 44410f514bdSNeil Armstrong static int wcd939x_codec_enable_rxclk(struct snd_soc_dapm_widget *w, 44510f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, 44610f514bdSNeil Armstrong int event) 44710f514bdSNeil Armstrong { 44810f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 44910f514bdSNeil Armstrong 45010f514bdSNeil Armstrong switch (event) { 45110f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 45210f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES, 45310f514bdSNeil Armstrong WCD939X_RX_SUPPLIES_RX_BIAS_ENABLE, true); 45410f514bdSNeil Armstrong 45510f514bdSNeil Armstrong /* Analog path clock controls */ 45610f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 45710f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_RX_CLK_EN, true); 45810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 45910f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV2_CLK_EN, 46010f514bdSNeil Armstrong true); 46110f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 46210f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV4_CLK_EN, 46310f514bdSNeil Armstrong true); 46410f514bdSNeil Armstrong 46510f514bdSNeil Armstrong /* Digital path clock controls */ 46610f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 46710f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_RXD0_CLK_EN, true); 46810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 46910f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_RXD1_CLK_EN, true); 47010f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 47110f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_RXD2_CLK_EN, true); 47210f514bdSNeil Armstrong break; 47310f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 47410f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES, 47510f514bdSNeil Armstrong WCD939X_RX_SUPPLIES_VNEG_EN, false); 47610f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES, 47710f514bdSNeil Armstrong WCD939X_RX_SUPPLIES_VPOS_EN, false); 47810f514bdSNeil Armstrong 47910f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 48010f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_RXD2_CLK_EN, false); 48110f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 48210f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_RXD1_CLK_EN, false); 48310f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 48410f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_RXD0_CLK_EN, false); 48510f514bdSNeil Armstrong 48610f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 48710f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV4_CLK_EN, 48810f514bdSNeil Armstrong false); 48910f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 49010f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_RX_DIV2_CLK_EN, 49110f514bdSNeil Armstrong false); 49210f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 49310f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_RX_CLK_EN, false); 49410f514bdSNeil Armstrong 49510f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES, 49610f514bdSNeil Armstrong WCD939X_RX_SUPPLIES_RX_BIAS_ENABLE, false); 49710f514bdSNeil Armstrong 49810f514bdSNeil Armstrong break; 49910f514bdSNeil Armstrong } 50010f514bdSNeil Armstrong 50110f514bdSNeil Armstrong return 0; 50210f514bdSNeil Armstrong } 50310f514bdSNeil Armstrong 50410f514bdSNeil Armstrong static int wcd939x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, 50510f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, 50610f514bdSNeil Armstrong int event) 50710f514bdSNeil Armstrong { 50810f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 50910f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 51010f514bdSNeil Armstrong 51110f514bdSNeil Armstrong switch (event) { 51210f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 51310f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_RDAC_CLK_CTL1, 51410f514bdSNeil Armstrong WCD939X_RDAC_CLK_CTL1_OPAMP_CHOP_CLK_EN, 51510f514bdSNeil Armstrong false); 51610f514bdSNeil Armstrong 51710f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_HPH_GAIN_CTL, 51810f514bdSNeil Armstrong WCD939X_CDC_HPH_GAIN_CTL_HPHL_RX_EN, true); 51910f514bdSNeil Armstrong break; 52010f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMU: 52110f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_L, 52210f514bdSNeil Armstrong WCD939X_RDAC_HD2_CTL_L_HD2_RES_DIV_CTL_L, 0x1d); 52310f514bdSNeil Armstrong if (wcd939x->comp1_enable) { 52410f514bdSNeil Armstrong snd_soc_component_write_field(component, 52510f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_COMP_CTL_0, 52610f514bdSNeil Armstrong WCD939X_CDC_COMP_CTL_0_HPHL_COMP_EN, 52710f514bdSNeil Armstrong true); 52810f514bdSNeil Armstrong /* 5msec compander delay as per HW requirement */ 52910f514bdSNeil Armstrong if (!wcd939x->comp2_enable || 53010f514bdSNeil Armstrong snd_soc_component_read_field(component, 53110f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_COMP_CTL_0, 53210f514bdSNeil Armstrong WCD939X_CDC_COMP_CTL_0_HPHR_COMP_EN)) 53310f514bdSNeil Armstrong usleep_range(5000, 5010); 53410f514bdSNeil Armstrong 53510f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_TIMER1, 53610f514bdSNeil Armstrong WCD939X_TIMER1_AUTOCHOP_TIMER_CTL_EN, 53710f514bdSNeil Armstrong false); 53810f514bdSNeil Armstrong } else { 53910f514bdSNeil Armstrong snd_soc_component_write_field(component, 54010f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_COMP_CTL_0, 54110f514bdSNeil Armstrong WCD939X_CDC_COMP_CTL_0_HPHL_COMP_EN, 54210f514bdSNeil Armstrong false); 54310f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_L_EN, 54410f514bdSNeil Armstrong WCD939X_L_EN_GAIN_SOURCE_SEL, true); 54510f514bdSNeil Armstrong } 54610f514bdSNeil Armstrong break; 54710f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 54810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_L, 54910f514bdSNeil Armstrong WCD939X_RDAC_HD2_CTL_L_HD2_RES_DIV_CTL_L, 1); 55010f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_HPH_GAIN_CTL, 55110f514bdSNeil Armstrong WCD939X_CDC_HPH_GAIN_CTL_HPHL_RX_EN, false); 55210f514bdSNeil Armstrong break; 55310f514bdSNeil Armstrong } 55410f514bdSNeil Armstrong 55510f514bdSNeil Armstrong return 0; 55610f514bdSNeil Armstrong } 55710f514bdSNeil Armstrong 55810f514bdSNeil Armstrong static int wcd939x_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, 55910f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, 56010f514bdSNeil Armstrong int event) 56110f514bdSNeil Armstrong { 56210f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 56310f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 56410f514bdSNeil Armstrong 56510f514bdSNeil Armstrong dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, 56610f514bdSNeil Armstrong w->name, event); 56710f514bdSNeil Armstrong 56810f514bdSNeil Armstrong switch (event) { 56910f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 57010f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_RDAC_CLK_CTL1, 57110f514bdSNeil Armstrong WCD939X_RDAC_CLK_CTL1_OPAMP_CHOP_CLK_EN, 57210f514bdSNeil Armstrong false); 57310f514bdSNeil Armstrong 57410f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_HPH_GAIN_CTL, 57510f514bdSNeil Armstrong WCD939X_CDC_HPH_GAIN_CTL_HPHR_RX_EN, true); 57610f514bdSNeil Armstrong break; 57710f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMU: 57810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_R, 57910f514bdSNeil Armstrong WCD939X_RDAC_HD2_CTL_R_HD2_RES_DIV_CTL_R, 0x1d); 58010f514bdSNeil Armstrong if (wcd939x->comp2_enable) { 58110f514bdSNeil Armstrong snd_soc_component_write_field(component, 58210f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_COMP_CTL_0, 58310f514bdSNeil Armstrong WCD939X_CDC_COMP_CTL_0_HPHR_COMP_EN, 58410f514bdSNeil Armstrong true); 58510f514bdSNeil Armstrong /* 5msec compander delay as per HW requirement */ 58610f514bdSNeil Armstrong if (!wcd939x->comp1_enable || 58710f514bdSNeil Armstrong snd_soc_component_read_field(component, 58810f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_COMP_CTL_0, 58910f514bdSNeil Armstrong WCD939X_CDC_COMP_CTL_0_HPHL_COMP_EN)) 59010f514bdSNeil Armstrong usleep_range(5000, 5010); 59110f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_TIMER1, 59210f514bdSNeil Armstrong WCD939X_TIMER1_AUTOCHOP_TIMER_CTL_EN, 59310f514bdSNeil Armstrong false); 59410f514bdSNeil Armstrong } else { 59510f514bdSNeil Armstrong snd_soc_component_write_field(component, 59610f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_COMP_CTL_0, 59710f514bdSNeil Armstrong WCD939X_CDC_COMP_CTL_0_HPHR_COMP_EN, 59810f514bdSNeil Armstrong false); 59910f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_R_EN, 60010f514bdSNeil Armstrong WCD939X_R_EN_GAIN_SOURCE_SEL, true); 60110f514bdSNeil Armstrong } 60210f514bdSNeil Armstrong break; 60310f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 60410f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_RDAC_HD2_CTL_R, 60510f514bdSNeil Armstrong WCD939X_RDAC_HD2_CTL_R_HD2_RES_DIV_CTL_R, 1); 60610f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_HPH_GAIN_CTL, 60710f514bdSNeil Armstrong WCD939X_CDC_HPH_GAIN_CTL_HPHR_RX_EN, false); 60810f514bdSNeil Armstrong break; 60910f514bdSNeil Armstrong } 61010f514bdSNeil Armstrong 61110f514bdSNeil Armstrong return 0; 61210f514bdSNeil Armstrong } 61310f514bdSNeil Armstrong 61410f514bdSNeil Armstrong static int wcd939x_codec_ear_dac_event(struct snd_soc_dapm_widget *w, 61510f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, 61610f514bdSNeil Armstrong int event) 61710f514bdSNeil Armstrong { 61810f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 61910f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 62010f514bdSNeil Armstrong 62110f514bdSNeil Armstrong switch (event) { 62210f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 62310f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_EAR_GAIN_CTL, 62410f514bdSNeil Armstrong WCD939X_CDC_EAR_GAIN_CTL_EAR_EN, true); 62510f514bdSNeil Armstrong 62610f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_EAR_DAC_CON, 62710f514bdSNeil Armstrong WCD939X_DAC_CON_DAC_SAMPLE_EDGE_SEL, false); 62810f514bdSNeil Armstrong 62910f514bdSNeil Armstrong /* 5 msec delay as per HW requirement */ 63010f514bdSNeil Armstrong usleep_range(5000, 5010); 63110f514bdSNeil Armstrong wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_PRE_DAC, 63210f514bdSNeil Armstrong WCD_CLSH_STATE_EAR, CLS_AB_HIFI); 63310f514bdSNeil Armstrong 63410f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_FLYBACK_VNEG_CTRL_4, 63510f514bdSNeil Armstrong WCD939X_VNEG_CTRL_4_ILIM_SEL, 0xd); 63610f514bdSNeil Armstrong break; 63710f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 63810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_EAR_DAC_CON, 63910f514bdSNeil Armstrong WCD939X_DAC_CON_DAC_SAMPLE_EDGE_SEL, true); 64010f514bdSNeil Armstrong break; 64110f514bdSNeil Armstrong } 64210f514bdSNeil Armstrong 64310f514bdSNeil Armstrong return 0; 64410f514bdSNeil Armstrong } 64510f514bdSNeil Armstrong 64610f514bdSNeil Armstrong static int wcd939x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, 64710f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, 64810f514bdSNeil Armstrong int event) 64910f514bdSNeil Armstrong { 65010f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 65110f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 65210f514bdSNeil Armstrong int hph_mode = wcd939x->hph_mode; 65310f514bdSNeil Armstrong 65410f514bdSNeil Armstrong switch (event) { 65510f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 65610f514bdSNeil Armstrong if (wcd939x->ldoh) 65710f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_LDOH_MODE, 65810f514bdSNeil Armstrong WCD939X_MODE_LDOH_EN, true); 65910f514bdSNeil Armstrong 66010f514bdSNeil Armstrong wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_PRE_DAC, 66110f514bdSNeil Armstrong WCD_CLSH_STATE_HPHR, hph_mode); 66210f514bdSNeil Armstrong wcd_clsh_set_hph_mode(wcd939x->clsh_info, CLS_H_HIFI); 66310f514bdSNeil Armstrong 66410f514bdSNeil Armstrong if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || hph_mode == CLS_H_ULP) 66510f514bdSNeil Armstrong snd_soc_component_write_field(component, 66610f514bdSNeil Armstrong WCD939X_HPH_REFBUFF_LP_CTL, 66710f514bdSNeil Armstrong WCD939X_REFBUFF_LP_CTL_PREREF_FILT_BYPASS, true); 66810f514bdSNeil Armstrong if (hph_mode == CLS_H_LOHIFI) 66910f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_HPH, 67010f514bdSNeil Armstrong WCD939X_HPH_PWR_LEVEL, 0); 67110f514bdSNeil Armstrong 67210f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_FLYBACK_VNEG_CTRL_4, 67310f514bdSNeil Armstrong WCD939X_VNEG_CTRL_4_ILIM_SEL, 0xd); 67410f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_HPH, 67510f514bdSNeil Armstrong WCD939X_HPH_HPHR_REF_ENABLE, true); 67610f514bdSNeil Armstrong 67710f514bdSNeil Armstrong if (snd_soc_component_read_field(component, WCD939X_ANA_HPH, 67810f514bdSNeil Armstrong WCD939X_HPH_HPHL_REF_ENABLE)) 67910f514bdSNeil Armstrong usleep_range(2500, 2600); /* 2.5msec delay as per HW requirement */ 68010f514bdSNeil Armstrong 68110f514bdSNeil Armstrong set_bit(HPH_PA_DELAY, &wcd939x->status_mask); 68210f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL1, 68310f514bdSNeil Armstrong WCD939X_PDM_WD_CTL1_PDM_WD_EN, 3); 68410f514bdSNeil Armstrong break; 68510f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMU: 68610f514bdSNeil Armstrong /* 68710f514bdSNeil Armstrong * 7ms sleep is required if compander is enabled as per 68810f514bdSNeil Armstrong * HW requirement. If compander is disabled, then 68910f514bdSNeil Armstrong * 20ms delay is required. 69010f514bdSNeil Armstrong */ 69110f514bdSNeil Armstrong if (test_bit(HPH_PA_DELAY, &wcd939x->status_mask)) { 69210f514bdSNeil Armstrong if (!wcd939x->comp2_enable) 69310f514bdSNeil Armstrong usleep_range(20000, 20100); 69410f514bdSNeil Armstrong else 69510f514bdSNeil Armstrong usleep_range(7000, 7100); 69610f514bdSNeil Armstrong 69710f514bdSNeil Armstrong if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || 69810f514bdSNeil Armstrong hph_mode == CLS_H_ULP) 69910f514bdSNeil Armstrong snd_soc_component_write_field(component, 70010f514bdSNeil Armstrong WCD939X_HPH_REFBUFF_LP_CTL, 70110f514bdSNeil Armstrong WCD939X_REFBUFF_LP_CTL_PREREF_FILT_BYPASS, 70210f514bdSNeil Armstrong false); 70310f514bdSNeil Armstrong clear_bit(HPH_PA_DELAY, &wcd939x->status_mask); 70410f514bdSNeil Armstrong } 70510f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_TIMER1, 70610f514bdSNeil Armstrong WCD939X_TIMER1_AUTOCHOP_TIMER_CTL_EN, true); 70710f514bdSNeil Armstrong if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI || 70810f514bdSNeil Armstrong hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) 70910f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES, 71010f514bdSNeil Armstrong WCD939X_RX_SUPPLIES_REGULATOR_MODE, 71110f514bdSNeil Armstrong true); 71210f514bdSNeil Armstrong 71310f514bdSNeil Armstrong enable_irq(wcd939x->hphr_pdm_wd_int); 71410f514bdSNeil Armstrong break; 71510f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMD: 71610f514bdSNeil Armstrong disable_irq_nosync(wcd939x->hphr_pdm_wd_int); 71710f514bdSNeil Armstrong /* 71810f514bdSNeil Armstrong * 7ms sleep is required if compander is enabled as per 71910f514bdSNeil Armstrong * HW requirement. If compander is disabled, then 72010f514bdSNeil Armstrong * 20ms delay is required. 72110f514bdSNeil Armstrong */ 72210f514bdSNeil Armstrong if (!wcd939x->comp2_enable) 72310f514bdSNeil Armstrong usleep_range(20000, 20100); 72410f514bdSNeil Armstrong else 72510f514bdSNeil Armstrong usleep_range(7000, 7100); 72610f514bdSNeil Armstrong 72710f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_HPH, 72810f514bdSNeil Armstrong WCD939X_HPH_HPHR_ENABLE, false); 72910f514bdSNeil Armstrong 73010f514bdSNeil Armstrong wcd_mbhc_event_notify(wcd939x->wcd_mbhc, 73110f514bdSNeil Armstrong WCD_EVENT_PRE_HPHR_PA_OFF); 73210f514bdSNeil Armstrong set_bit(HPH_PA_DELAY, &wcd939x->status_mask); 73310f514bdSNeil Armstrong break; 73410f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 73510f514bdSNeil Armstrong /* 73610f514bdSNeil Armstrong * 7ms sleep is required if compander is enabled as per 73710f514bdSNeil Armstrong * HW requirement. If compander is disabled, then 73810f514bdSNeil Armstrong * 20ms delay is required. 73910f514bdSNeil Armstrong */ 74010f514bdSNeil Armstrong if (test_bit(HPH_PA_DELAY, &wcd939x->status_mask)) { 74110f514bdSNeil Armstrong if (!wcd939x->comp2_enable) 74210f514bdSNeil Armstrong usleep_range(20000, 20100); 74310f514bdSNeil Armstrong else 74410f514bdSNeil Armstrong usleep_range(7000, 7100); 74510f514bdSNeil Armstrong clear_bit(HPH_PA_DELAY, &wcd939x->status_mask); 74610f514bdSNeil Armstrong } 74710f514bdSNeil Armstrong wcd_mbhc_event_notify(wcd939x->wcd_mbhc, 74810f514bdSNeil Armstrong WCD_EVENT_POST_HPHR_PA_OFF); 74910f514bdSNeil Armstrong 75010f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_HPH, 75110f514bdSNeil Armstrong WCD939X_HPH_HPHR_REF_ENABLE, false); 75210f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL1, 75310f514bdSNeil Armstrong WCD939X_PDM_WD_CTL1_PDM_WD_EN, 0); 75410f514bdSNeil Armstrong 75510f514bdSNeil Armstrong wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_POST_PA, 75610f514bdSNeil Armstrong WCD_CLSH_STATE_HPHR, hph_mode); 75710f514bdSNeil Armstrong if (wcd939x->ldoh) 75810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_LDOH_MODE, 75910f514bdSNeil Armstrong WCD939X_MODE_LDOH_EN, false); 76010f514bdSNeil Armstrong break; 76110f514bdSNeil Armstrong } 76210f514bdSNeil Armstrong 76310f514bdSNeil Armstrong return 0; 76410f514bdSNeil Armstrong } 76510f514bdSNeil Armstrong 76610f514bdSNeil Armstrong static int wcd939x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, 76710f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, 76810f514bdSNeil Armstrong int event) 76910f514bdSNeil Armstrong { 77010f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 77110f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 77210f514bdSNeil Armstrong int hph_mode = wcd939x->hph_mode; 77310f514bdSNeil Armstrong 77410f514bdSNeil Armstrong dev_dbg(component->dev, "%s wname: %s event: %d\n", __func__, 77510f514bdSNeil Armstrong w->name, event); 77610f514bdSNeil Armstrong 77710f514bdSNeil Armstrong switch (event) { 77810f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 77910f514bdSNeil Armstrong if (wcd939x->ldoh) 78010f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_LDOH_MODE, 78110f514bdSNeil Armstrong WCD939X_MODE_LDOH_EN, true); 78210f514bdSNeil Armstrong wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_PRE_DAC, 78310f514bdSNeil Armstrong WCD_CLSH_STATE_HPHL, hph_mode); 78410f514bdSNeil Armstrong wcd_clsh_set_hph_mode(wcd939x->clsh_info, CLS_H_HIFI); 78510f514bdSNeil Armstrong 78610f514bdSNeil Armstrong if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || hph_mode == CLS_H_ULP) 78710f514bdSNeil Armstrong snd_soc_component_write_field(component, 78810f514bdSNeil Armstrong WCD939X_HPH_REFBUFF_LP_CTL, 78910f514bdSNeil Armstrong WCD939X_REFBUFF_LP_CTL_PREREF_FILT_BYPASS, 79010f514bdSNeil Armstrong true); 79110f514bdSNeil Armstrong if (hph_mode == CLS_H_LOHIFI) 79210f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_HPH, 79310f514bdSNeil Armstrong WCD939X_HPH_PWR_LEVEL, 0); 79410f514bdSNeil Armstrong 79510f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_FLYBACK_VNEG_CTRL_4, 79610f514bdSNeil Armstrong WCD939X_VNEG_CTRL_4_ILIM_SEL, 0xd); 79710f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_HPH, 79810f514bdSNeil Armstrong WCD939X_HPH_HPHL_REF_ENABLE, true); 79910f514bdSNeil Armstrong 80010f514bdSNeil Armstrong if (snd_soc_component_read_field(component, WCD939X_ANA_HPH, 80110f514bdSNeil Armstrong WCD939X_HPH_HPHR_REF_ENABLE)) 80210f514bdSNeil Armstrong usleep_range(2500, 2600); /* 2.5msec delay as per HW requirement */ 80310f514bdSNeil Armstrong 80410f514bdSNeil Armstrong set_bit(HPH_PA_DELAY, &wcd939x->status_mask); 80510f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL0, 80610f514bdSNeil Armstrong WCD939X_PDM_WD_CTL0_PDM_WD_EN, 3); 80710f514bdSNeil Armstrong break; 80810f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMU: 80910f514bdSNeil Armstrong /* 81010f514bdSNeil Armstrong * 7ms sleep is required if compander is enabled as per 81110f514bdSNeil Armstrong * HW requirement. If compander is disabled, then 81210f514bdSNeil Armstrong * 20ms delay is required. 81310f514bdSNeil Armstrong */ 81410f514bdSNeil Armstrong if (test_bit(HPH_PA_DELAY, &wcd939x->status_mask)) { 81510f514bdSNeil Armstrong if (!wcd939x->comp1_enable) 81610f514bdSNeil Armstrong usleep_range(20000, 20100); 81710f514bdSNeil Armstrong else 81810f514bdSNeil Armstrong usleep_range(7000, 7100); 81910f514bdSNeil Armstrong if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || 82010f514bdSNeil Armstrong hph_mode == CLS_H_ULP) 82110f514bdSNeil Armstrong snd_soc_component_write_field(component, 82210f514bdSNeil Armstrong WCD939X_HPH_REFBUFF_LP_CTL, 82310f514bdSNeil Armstrong WCD939X_REFBUFF_LP_CTL_PREREF_FILT_BYPASS, 82410f514bdSNeil Armstrong false); 82510f514bdSNeil Armstrong clear_bit(HPH_PA_DELAY, &wcd939x->status_mask); 82610f514bdSNeil Armstrong } 82710f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_NEW_INT_TIMER1, 82810f514bdSNeil Armstrong WCD939X_TIMER1_AUTOCHOP_TIMER_CTL_EN, true); 82910f514bdSNeil Armstrong if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI || 83010f514bdSNeil Armstrong hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) 83110f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES, 83210f514bdSNeil Armstrong WCD939X_RX_SUPPLIES_REGULATOR_MODE, 83310f514bdSNeil Armstrong true); 83410f514bdSNeil Armstrong enable_irq(wcd939x->hphl_pdm_wd_int); 83510f514bdSNeil Armstrong break; 83610f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMD: 83710f514bdSNeil Armstrong disable_irq_nosync(wcd939x->hphl_pdm_wd_int); 83810f514bdSNeil Armstrong /* 83910f514bdSNeil Armstrong * 7ms sleep is required if compander is enabled as per 84010f514bdSNeil Armstrong * HW requirement. If compander is disabled, then 84110f514bdSNeil Armstrong * 20ms delay is required. 84210f514bdSNeil Armstrong */ 84310f514bdSNeil Armstrong if (!wcd939x->comp1_enable) 84410f514bdSNeil Armstrong usleep_range(20000, 20100); 84510f514bdSNeil Armstrong else 84610f514bdSNeil Armstrong usleep_range(7000, 7100); 84710f514bdSNeil Armstrong 84810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_HPH, 84910f514bdSNeil Armstrong WCD939X_HPH_HPHL_ENABLE, false); 85010f514bdSNeil Armstrong 85110f514bdSNeil Armstrong wcd_mbhc_event_notify(wcd939x->wcd_mbhc, WCD_EVENT_PRE_HPHL_PA_OFF); 85210f514bdSNeil Armstrong set_bit(HPH_PA_DELAY, &wcd939x->status_mask); 85310f514bdSNeil Armstrong break; 85410f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 85510f514bdSNeil Armstrong /* 85610f514bdSNeil Armstrong * 7ms sleep is required if compander is enabled as per 85710f514bdSNeil Armstrong * HW requirement. If compander is disabled, then 85810f514bdSNeil Armstrong * 20ms delay is required. 85910f514bdSNeil Armstrong */ 86010f514bdSNeil Armstrong if (test_bit(HPH_PA_DELAY, &wcd939x->status_mask)) { 86110f514bdSNeil Armstrong if (!wcd939x->comp1_enable) 86210f514bdSNeil Armstrong usleep_range(21000, 21100); 86310f514bdSNeil Armstrong else 86410f514bdSNeil Armstrong usleep_range(7000, 7100); 86510f514bdSNeil Armstrong clear_bit(HPH_PA_DELAY, &wcd939x->status_mask); 86610f514bdSNeil Armstrong } 86710f514bdSNeil Armstrong wcd_mbhc_event_notify(wcd939x->wcd_mbhc, 86810f514bdSNeil Armstrong WCD_EVENT_POST_HPHL_PA_OFF); 86910f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_HPH, 87010f514bdSNeil Armstrong WCD939X_HPH_HPHL_REF_ENABLE, false); 87110f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL0, 87210f514bdSNeil Armstrong WCD939X_PDM_WD_CTL0_PDM_WD_EN, 0); 87310f514bdSNeil Armstrong wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_POST_PA, 87410f514bdSNeil Armstrong WCD_CLSH_STATE_HPHL, hph_mode); 87510f514bdSNeil Armstrong if (wcd939x->ldoh) 87610f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_LDOH_MODE, 87710f514bdSNeil Armstrong WCD939X_MODE_LDOH_EN, false); 87810f514bdSNeil Armstrong break; 87910f514bdSNeil Armstrong } 88010f514bdSNeil Armstrong 88110f514bdSNeil Armstrong return 0; 88210f514bdSNeil Armstrong } 88310f514bdSNeil Armstrong 88410f514bdSNeil Armstrong static int wcd939x_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, 88510f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, int event) 88610f514bdSNeil Armstrong { 88710f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 88810f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 88910f514bdSNeil Armstrong 89010f514bdSNeil Armstrong switch (event) { 89110f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 89210f514bdSNeil Armstrong /* Enable watchdog interrupt for HPHL */ 89310f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL0, 89410f514bdSNeil Armstrong WCD939X_PDM_WD_CTL0_PDM_WD_EN, 3); 89510f514bdSNeil Armstrong /* For EAR, use CLASS_AB regulator mode */ 89610f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_RX_SUPPLIES, 89710f514bdSNeil Armstrong WCD939X_RX_SUPPLIES_REGULATOR_MODE, true); 89810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_EAR_COMPANDER_CTL, 89910f514bdSNeil Armstrong WCD939X_EAR_COMPANDER_CTL_GAIN_OVRD_REG, true); 90010f514bdSNeil Armstrong break; 90110f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMU: 90210f514bdSNeil Armstrong /* 6 msec delay as per HW requirement */ 90310f514bdSNeil Armstrong usleep_range(6000, 6010); 90410f514bdSNeil Armstrong enable_irq(wcd939x->ear_pdm_wd_int); 90510f514bdSNeil Armstrong break; 90610f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMD: 90710f514bdSNeil Armstrong disable_irq_nosync(wcd939x->ear_pdm_wd_int); 90810f514bdSNeil Armstrong break; 90910f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 91010f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_EAR_COMPANDER_CTL, 91110f514bdSNeil Armstrong WCD939X_EAR_COMPANDER_CTL_GAIN_OVRD_REG, 91210f514bdSNeil Armstrong false); 91310f514bdSNeil Armstrong /* 7 msec delay as per HW requirement */ 91410f514bdSNeil Armstrong usleep_range(7000, 7010); 91510f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_PDM_WD_CTL0, 91610f514bdSNeil Armstrong WCD939X_PDM_WD_CTL0_PDM_WD_EN, 0); 91710f514bdSNeil Armstrong wcd_clsh_ctrl_set_state(wcd939x->clsh_info, WCD_CLSH_EVENT_POST_PA, 91810f514bdSNeil Armstrong WCD_CLSH_STATE_EAR, CLS_AB_HIFI); 91910f514bdSNeil Armstrong break; 92010f514bdSNeil Armstrong } 92110f514bdSNeil Armstrong 92210f514bdSNeil Armstrong return 0; 92310f514bdSNeil Armstrong } 92410f514bdSNeil Armstrong 92510f514bdSNeil Armstrong /* TX Controls */ 92610f514bdSNeil Armstrong 92710f514bdSNeil Armstrong static int wcd939x_codec_enable_dmic(struct snd_soc_dapm_widget *w, 92810f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, 92910f514bdSNeil Armstrong int event) 93010f514bdSNeil Armstrong { 93110f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 93210f514bdSNeil Armstrong u16 dmic_clk_reg, dmic_clk_en_reg; 93310f514bdSNeil Armstrong u8 dmic_clk_en_mask; 93410f514bdSNeil Armstrong u8 dmic_ctl_mask; 93510f514bdSNeil Armstrong u8 dmic_clk_mask; 93610f514bdSNeil Armstrong 93710f514bdSNeil Armstrong switch (w->shift) { 93810f514bdSNeil Armstrong case 0: 93910f514bdSNeil Armstrong case 1: 94010f514bdSNeil Armstrong dmic_clk_reg = WCD939X_DIGITAL_CDC_DMIC_RATE_1_2; 94110f514bdSNeil Armstrong dmic_clk_en_reg = WCD939X_DIGITAL_CDC_DMIC1_CTL; 94210f514bdSNeil Armstrong dmic_clk_en_mask = WCD939X_CDC_DMIC1_CTL_DMIC_CLK_EN; 94310f514bdSNeil Armstrong dmic_clk_mask = WCD939X_CDC_DMIC_RATE_1_2_DMIC1_RATE; 94410f514bdSNeil Armstrong dmic_ctl_mask = WCD939X_CDC_AMIC_CTL_AMIC1_IN_SEL; 94510f514bdSNeil Armstrong break; 94610f514bdSNeil Armstrong case 2: 94710f514bdSNeil Armstrong case 3: 94810f514bdSNeil Armstrong dmic_clk_reg = WCD939X_DIGITAL_CDC_DMIC_RATE_1_2; 94910f514bdSNeil Armstrong dmic_clk_en_reg = WCD939X_DIGITAL_CDC_DMIC2_CTL; 95010f514bdSNeil Armstrong dmic_clk_en_mask = WCD939X_CDC_DMIC2_CTL_DMIC_CLK_EN; 95110f514bdSNeil Armstrong dmic_clk_mask = WCD939X_CDC_DMIC_RATE_1_2_DMIC2_RATE; 95210f514bdSNeil Armstrong dmic_ctl_mask = WCD939X_CDC_AMIC_CTL_AMIC3_IN_SEL; 95310f514bdSNeil Armstrong break; 95410f514bdSNeil Armstrong case 4: 95510f514bdSNeil Armstrong case 5: 95610f514bdSNeil Armstrong dmic_clk_reg = WCD939X_DIGITAL_CDC_DMIC_RATE_3_4; 95710f514bdSNeil Armstrong dmic_clk_en_reg = WCD939X_DIGITAL_CDC_DMIC3_CTL; 95810f514bdSNeil Armstrong dmic_clk_en_mask = WCD939X_CDC_DMIC3_CTL_DMIC_CLK_EN; 95910f514bdSNeil Armstrong dmic_clk_mask = WCD939X_CDC_DMIC_RATE_3_4_DMIC3_RATE; 96010f514bdSNeil Armstrong dmic_ctl_mask = WCD939X_CDC_AMIC_CTL_AMIC4_IN_SEL; 96110f514bdSNeil Armstrong break; 96210f514bdSNeil Armstrong case 6: 96310f514bdSNeil Armstrong case 7: 96410f514bdSNeil Armstrong dmic_clk_reg = WCD939X_DIGITAL_CDC_DMIC_RATE_3_4; 96510f514bdSNeil Armstrong dmic_clk_en_reg = WCD939X_DIGITAL_CDC_DMIC4_CTL; 96610f514bdSNeil Armstrong dmic_clk_en_mask = WCD939X_CDC_DMIC4_CTL_DMIC_CLK_EN; 96710f514bdSNeil Armstrong dmic_clk_mask = WCD939X_CDC_DMIC_RATE_3_4_DMIC4_RATE; 96810f514bdSNeil Armstrong dmic_ctl_mask = WCD939X_CDC_AMIC_CTL_AMIC5_IN_SEL; 96910f514bdSNeil Armstrong break; 97010f514bdSNeil Armstrong default: 97110f514bdSNeil Armstrong dev_err(component->dev, "%s: Invalid DMIC Selection\n", __func__); 97210f514bdSNeil Armstrong return -EINVAL; 973*e7214441SYang Li } 97410f514bdSNeil Armstrong 97510f514bdSNeil Armstrong switch (event) { 97610f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 97710f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_AMIC_CTL, 97810f514bdSNeil Armstrong dmic_ctl_mask, false); 97910f514bdSNeil Armstrong /* 250us sleep as per HW requirement */ 98010f514bdSNeil Armstrong usleep_range(250, 260); 98110f514bdSNeil Armstrong if (w->shift == 2) 98210f514bdSNeil Armstrong snd_soc_component_write_field(component, 98310f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DMIC2_CTL, 98410f514bdSNeil Armstrong WCD939X_CDC_DMIC2_CTL_DMIC_LEFT_EN, 98510f514bdSNeil Armstrong true); 98610f514bdSNeil Armstrong /* Setting DMIC clock rate to 2.4MHz */ 98710f514bdSNeil Armstrong snd_soc_component_write_field(component, dmic_clk_reg, 98810f514bdSNeil Armstrong dmic_clk_mask, 3); 98910f514bdSNeil Armstrong snd_soc_component_write_field(component, dmic_clk_en_reg, 99010f514bdSNeil Armstrong dmic_clk_en_mask, true); 99110f514bdSNeil Armstrong /* enable clock scaling */ 99210f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DMIC_CTL, 99310f514bdSNeil Armstrong WCD939X_CDC_DMIC_CTL_CLK_SCALE_EN, true); 99410f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_DMIC_CTL, 99510f514bdSNeil Armstrong WCD939X_CDC_DMIC_CTL_DMIC_DIV_BAK_EN, true); 99610f514bdSNeil Armstrong break; 99710f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 99810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_AMIC_CTL, 99910f514bdSNeil Armstrong dmic_ctl_mask, 1); 100010f514bdSNeil Armstrong if (w->shift == 2) 100110f514bdSNeil Armstrong snd_soc_component_write_field(component, 100210f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DMIC2_CTL, 100310f514bdSNeil Armstrong WCD939X_CDC_DMIC2_CTL_DMIC_LEFT_EN, 100410f514bdSNeil Armstrong false); 100510f514bdSNeil Armstrong snd_soc_component_write_field(component, dmic_clk_en_reg, 100610f514bdSNeil Armstrong dmic_clk_en_mask, 0); 100710f514bdSNeil Armstrong break; 100810f514bdSNeil Armstrong } 100910f514bdSNeil Armstrong return 0; 101010f514bdSNeil Armstrong } 101110f514bdSNeil Armstrong 101210f514bdSNeil Armstrong static int wcd939x_tx_swr_ctrl(struct snd_soc_dapm_widget *w, 101310f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, int event) 101410f514bdSNeil Armstrong { 101510f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 101610f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 101710f514bdSNeil Armstrong int bank; 101810f514bdSNeil Armstrong int rate; 101910f514bdSNeil Armstrong 102010f514bdSNeil Armstrong bank = wcd939x_swr_get_current_bank(wcd939x->sdw_priv[AIF1_CAP]->sdev); 102110f514bdSNeil Armstrong 102210f514bdSNeil Armstrong switch (event) { 102310f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 102410f514bdSNeil Armstrong if (strnstr(w->name, "ADC", sizeof("ADC"))) { 102510f514bdSNeil Armstrong int mode = 0; 102610f514bdSNeil Armstrong 102710f514bdSNeil Armstrong if (test_bit(WCD_ADC1, &wcd939x->status_mask)) 102810f514bdSNeil Armstrong mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC1]]; 102910f514bdSNeil Armstrong if (test_bit(WCD_ADC2, &wcd939x->status_mask)) 103010f514bdSNeil Armstrong mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC2]]; 103110f514bdSNeil Armstrong if (test_bit(WCD_ADC3, &wcd939x->status_mask)) 103210f514bdSNeil Armstrong mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC3]]; 103310f514bdSNeil Armstrong if (test_bit(WCD_ADC4, &wcd939x->status_mask)) 103410f514bdSNeil Armstrong mode |= tx_mode_bit[wcd939x->tx_mode[WCD_ADC4]]; 103510f514bdSNeil Armstrong 103610f514bdSNeil Armstrong if (mode) 103710f514bdSNeil Armstrong rate = wcd939x_get_clk_rate(ffs(mode) - 1); 103810f514bdSNeil Armstrong else 103910f514bdSNeil Armstrong rate = wcd939x_get_clk_rate(ADC_MODE_INVALID); 104010f514bdSNeil Armstrong wcd939x_set_swr_clk_rate(component, rate, bank); 104110f514bdSNeil Armstrong wcd939x_set_swr_clk_rate(component, rate, !bank); 104210f514bdSNeil Armstrong } 104310f514bdSNeil Armstrong break; 104410f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 104510f514bdSNeil Armstrong if (strnstr(w->name, "ADC", sizeof("ADC"))) { 104610f514bdSNeil Armstrong rate = wcd939x_get_clk_rate(ADC_MODE_INVALID); 104710f514bdSNeil Armstrong wcd939x_set_swr_clk_rate(component, rate, !bank); 104810f514bdSNeil Armstrong wcd939x_set_swr_clk_rate(component, rate, bank); 104910f514bdSNeil Armstrong } 105010f514bdSNeil Armstrong break; 105110f514bdSNeil Armstrong } 105210f514bdSNeil Armstrong 105310f514bdSNeil Armstrong return 0; 105410f514bdSNeil Armstrong } 105510f514bdSNeil Armstrong 105610f514bdSNeil Armstrong static int wcd939x_get_adc_mode(int val) 105710f514bdSNeil Armstrong { 105810f514bdSNeil Armstrong int ret = 0; 105910f514bdSNeil Armstrong 106010f514bdSNeil Armstrong switch (val) { 106110f514bdSNeil Armstrong case ADC_MODE_INVALID: 106210f514bdSNeil Armstrong ret = ADC_MODE_VAL_NORMAL; 106310f514bdSNeil Armstrong break; 106410f514bdSNeil Armstrong case ADC_MODE_HIFI: 106510f514bdSNeil Armstrong ret = ADC_MODE_VAL_HIFI; 106610f514bdSNeil Armstrong break; 106710f514bdSNeil Armstrong case ADC_MODE_LO_HIF: 106810f514bdSNeil Armstrong ret = ADC_MODE_VAL_LO_HIF; 106910f514bdSNeil Armstrong break; 107010f514bdSNeil Armstrong case ADC_MODE_NORMAL: 107110f514bdSNeil Armstrong ret = ADC_MODE_VAL_NORMAL; 107210f514bdSNeil Armstrong break; 107310f514bdSNeil Armstrong case ADC_MODE_LP: 107410f514bdSNeil Armstrong ret = ADC_MODE_VAL_LP; 107510f514bdSNeil Armstrong break; 107610f514bdSNeil Armstrong case ADC_MODE_ULP1: 107710f514bdSNeil Armstrong ret = ADC_MODE_VAL_ULP1; 107810f514bdSNeil Armstrong break; 107910f514bdSNeil Armstrong case ADC_MODE_ULP2: 108010f514bdSNeil Armstrong ret = ADC_MODE_VAL_ULP2; 108110f514bdSNeil Armstrong break; 108210f514bdSNeil Armstrong default: 108310f514bdSNeil Armstrong ret = -EINVAL; 108410f514bdSNeil Armstrong break; 108510f514bdSNeil Armstrong } 108610f514bdSNeil Armstrong return ret; 108710f514bdSNeil Armstrong } 108810f514bdSNeil Armstrong 108910f514bdSNeil Armstrong static int wcd939x_codec_enable_adc(struct snd_soc_dapm_widget *w, 109010f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, int event) 109110f514bdSNeil Armstrong { 109210f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 109310f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 109410f514bdSNeil Armstrong 109510f514bdSNeil Armstrong switch (event) { 109610f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 109710f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 109810f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_TX_CLK_EN, true); 109910f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 110010f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV2_CLK_EN, 110110f514bdSNeil Armstrong true); 110210f514bdSNeil Armstrong set_bit(w->shift, &wcd939x->status_mask); 110310f514bdSNeil Armstrong break; 110410f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 110510f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 110610f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV2_CLK_EN, 110710f514bdSNeil Armstrong false); 110810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 110910f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_TX_CLK_EN, 111010f514bdSNeil Armstrong false); 111110f514bdSNeil Armstrong clear_bit(w->shift, &wcd939x->status_mask); 111210f514bdSNeil Armstrong break; 111310f514bdSNeil Armstrong } 111410f514bdSNeil Armstrong 111510f514bdSNeil Armstrong return 0; 111610f514bdSNeil Armstrong } 111710f514bdSNeil Armstrong 111810f514bdSNeil Armstrong static void wcd939x_tx_channel_config(struct snd_soc_component *component, 111910f514bdSNeil Armstrong int channel, bool init) 112010f514bdSNeil Armstrong { 112110f514bdSNeil Armstrong int reg, mask; 112210f514bdSNeil Armstrong 112310f514bdSNeil Armstrong switch (channel) { 112410f514bdSNeil Armstrong case 0: 112510f514bdSNeil Armstrong reg = WCD939X_ANA_TX_CH2; 112610f514bdSNeil Armstrong mask = WCD939X_TX_CH2_HPF1_INIT; 112710f514bdSNeil Armstrong break; 112810f514bdSNeil Armstrong case 1: 112910f514bdSNeil Armstrong reg = WCD939X_ANA_TX_CH2; 113010f514bdSNeil Armstrong mask = WCD939X_TX_CH2_HPF2_INIT; 113110f514bdSNeil Armstrong break; 113210f514bdSNeil Armstrong case 2: 113310f514bdSNeil Armstrong reg = WCD939X_ANA_TX_CH4; 113410f514bdSNeil Armstrong mask = WCD939X_TX_CH4_HPF3_INIT; 113510f514bdSNeil Armstrong break; 113610f514bdSNeil Armstrong case 3: 113710f514bdSNeil Armstrong reg = WCD939X_ANA_TX_CH4; 113810f514bdSNeil Armstrong mask = WCD939X_TX_CH4_HPF4_INIT; 113910f514bdSNeil Armstrong break; 114010f514bdSNeil Armstrong default: 114110f514bdSNeil Armstrong return; 114210f514bdSNeil Armstrong } 114310f514bdSNeil Armstrong 114410f514bdSNeil Armstrong snd_soc_component_write_field(component, reg, mask, init); 114510f514bdSNeil Armstrong } 114610f514bdSNeil Armstrong 114710f514bdSNeil Armstrong static int wcd939x_adc_enable_req(struct snd_soc_dapm_widget *w, 114810f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, int event) 114910f514bdSNeil Armstrong { 115010f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 115110f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 115210f514bdSNeil Armstrong int mode; 115310f514bdSNeil Armstrong 115410f514bdSNeil Armstrong switch (event) { 115510f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 115610f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_REQ_CTL, 115710f514bdSNeil Armstrong WCD939X_CDC_REQ_CTL_FS_RATE_4P8, true); 115810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_DIGITAL_CDC_REQ_CTL, 115910f514bdSNeil Armstrong WCD939X_CDC_REQ_CTL_NO_NOTCH, false); 116010f514bdSNeil Armstrong 116110f514bdSNeil Armstrong wcd939x_tx_channel_config(component, w->shift, true); 116210f514bdSNeil Armstrong mode = wcd939x_get_adc_mode(wcd939x->tx_mode[w->shift]); 116310f514bdSNeil Armstrong if (mode < 0) { 116410f514bdSNeil Armstrong dev_info(component->dev, "Invalid ADC mode\n"); 116510f514bdSNeil Armstrong return -EINVAL; 116610f514bdSNeil Armstrong } 116710f514bdSNeil Armstrong 116810f514bdSNeil Armstrong switch (w->shift) { 116910f514bdSNeil Armstrong case 0: 117010f514bdSNeil Armstrong snd_soc_component_write_field(component, 117110f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1, 117210f514bdSNeil Armstrong WCD939X_CDC_TX_ANA_MODE_0_1_TXD0_MODE, 117310f514bdSNeil Armstrong mode); 117410f514bdSNeil Armstrong snd_soc_component_write_field(component, 117510f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 117610f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD0_CLK_EN, 117710f514bdSNeil Armstrong true); 117810f514bdSNeil Armstrong break; 117910f514bdSNeil Armstrong case 1: 118010f514bdSNeil Armstrong snd_soc_component_write_field(component, 118110f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1, 118210f514bdSNeil Armstrong WCD939X_CDC_TX_ANA_MODE_0_1_TXD1_MODE, 118310f514bdSNeil Armstrong mode); 118410f514bdSNeil Armstrong snd_soc_component_write_field(component, 118510f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 118610f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD1_CLK_EN, 118710f514bdSNeil Armstrong true); 118810f514bdSNeil Armstrong break; 118910f514bdSNeil Armstrong case 2: 119010f514bdSNeil Armstrong snd_soc_component_write_field(component, 119110f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3, 119210f514bdSNeil Armstrong WCD939X_CDC_TX_ANA_MODE_2_3_TXD2_MODE, 119310f514bdSNeil Armstrong mode); 119410f514bdSNeil Armstrong snd_soc_component_write_field(component, 119510f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 119610f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD2_CLK_EN, 119710f514bdSNeil Armstrong true); 119810f514bdSNeil Armstrong break; 119910f514bdSNeil Armstrong case 3: 120010f514bdSNeil Armstrong snd_soc_component_write_field(component, 120110f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3, 120210f514bdSNeil Armstrong WCD939X_CDC_TX_ANA_MODE_2_3_TXD3_MODE, 120310f514bdSNeil Armstrong mode); 120410f514bdSNeil Armstrong snd_soc_component_write_field(component, 120510f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 120610f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD3_CLK_EN, 120710f514bdSNeil Armstrong true); 120810f514bdSNeil Armstrong break; 120910f514bdSNeil Armstrong default: 121010f514bdSNeil Armstrong break; 121110f514bdSNeil Armstrong } 121210f514bdSNeil Armstrong 121310f514bdSNeil Armstrong wcd939x_tx_channel_config(component, w->shift, false); 121410f514bdSNeil Armstrong break; 121510f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 121610f514bdSNeil Armstrong switch (w->shift) { 121710f514bdSNeil Armstrong case 0: 121810f514bdSNeil Armstrong snd_soc_component_write_field(component, 121910f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1, 122010f514bdSNeil Armstrong WCD939X_CDC_TX_ANA_MODE_0_1_TXD0_MODE, 122110f514bdSNeil Armstrong false); 122210f514bdSNeil Armstrong snd_soc_component_write_field(component, 122310f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 122410f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD0_CLK_EN, 122510f514bdSNeil Armstrong false); 122610f514bdSNeil Armstrong break; 122710f514bdSNeil Armstrong case 1: 122810f514bdSNeil Armstrong snd_soc_component_write_field(component, 122910f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_TX_ANA_MODE_0_1, 123010f514bdSNeil Armstrong WCD939X_CDC_TX_ANA_MODE_0_1_TXD1_MODE, 123110f514bdSNeil Armstrong false); 123210f514bdSNeil Armstrong snd_soc_component_write_field(component, 123310f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 123410f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD1_CLK_EN, 123510f514bdSNeil Armstrong false); 123610f514bdSNeil Armstrong break; 123710f514bdSNeil Armstrong case 2: 123810f514bdSNeil Armstrong snd_soc_component_write_field(component, 123910f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3, 124010f514bdSNeil Armstrong WCD939X_CDC_TX_ANA_MODE_2_3_TXD2_MODE, 124110f514bdSNeil Armstrong false); 124210f514bdSNeil Armstrong snd_soc_component_write_field(component, 124310f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 124410f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD2_CLK_EN, 124510f514bdSNeil Armstrong false); 124610f514bdSNeil Armstrong break; 124710f514bdSNeil Armstrong case 3: 124810f514bdSNeil Armstrong snd_soc_component_write_field(component, 124910f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_TX_ANA_MODE_2_3, 125010f514bdSNeil Armstrong WCD939X_CDC_TX_ANA_MODE_2_3_TXD3_MODE, 125110f514bdSNeil Armstrong false); 125210f514bdSNeil Armstrong snd_soc_component_write_field(component, 125310f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 125410f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD3_CLK_EN, 125510f514bdSNeil Armstrong false); 125610f514bdSNeil Armstrong break; 125710f514bdSNeil Armstrong default: 125810f514bdSNeil Armstrong break; 125910f514bdSNeil Armstrong } 126010f514bdSNeil Armstrong break; 126110f514bdSNeil Armstrong } 126210f514bdSNeil Armstrong 126310f514bdSNeil Armstrong return 0; 126410f514bdSNeil Armstrong } 126510f514bdSNeil Armstrong 126610f514bdSNeil Armstrong static int wcd939x_micbias_control(struct snd_soc_component *component, 126710f514bdSNeil Armstrong int micb_num, int req, bool is_dapm) 126810f514bdSNeil Armstrong { 126910f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 127010f514bdSNeil Armstrong int micb_index = micb_num - 1; 127110f514bdSNeil Armstrong u16 micb_field; 127210f514bdSNeil Armstrong u16 micb_reg; 127310f514bdSNeil Armstrong 127410f514bdSNeil Armstrong switch (micb_num) { 127510f514bdSNeil Armstrong case MIC_BIAS_1: 127610f514bdSNeil Armstrong micb_reg = WCD939X_ANA_MICB1; 127710f514bdSNeil Armstrong micb_field = WCD939X_MICB1_ENABLE; 127810f514bdSNeil Armstrong break; 127910f514bdSNeil Armstrong case MIC_BIAS_2: 128010f514bdSNeil Armstrong micb_reg = WCD939X_ANA_MICB2; 128110f514bdSNeil Armstrong micb_field = WCD939X_MICB2_ENABLE; 128210f514bdSNeil Armstrong break; 128310f514bdSNeil Armstrong case MIC_BIAS_3: 128410f514bdSNeil Armstrong micb_reg = WCD939X_ANA_MICB3; 128510f514bdSNeil Armstrong micb_field = WCD939X_MICB3_ENABLE; 128610f514bdSNeil Armstrong break; 128710f514bdSNeil Armstrong case MIC_BIAS_4: 128810f514bdSNeil Armstrong micb_reg = WCD939X_ANA_MICB4; 128910f514bdSNeil Armstrong micb_field = WCD939X_MICB4_ENABLE; 129010f514bdSNeil Armstrong break; 129110f514bdSNeil Armstrong default: 129210f514bdSNeil Armstrong dev_err(component->dev, "%s: Invalid micbias number: %d\n", 129310f514bdSNeil Armstrong __func__, micb_num); 129410f514bdSNeil Armstrong return -EINVAL; 1295*e7214441SYang Li } 129610f514bdSNeil Armstrong 129710f514bdSNeil Armstrong switch (req) { 129810f514bdSNeil Armstrong case MICB_PULLUP_ENABLE: 129910f514bdSNeil Armstrong wcd939x->pullup_ref[micb_index]++; 130010f514bdSNeil Armstrong if (wcd939x->pullup_ref[micb_index] == 1 && 130110f514bdSNeil Armstrong wcd939x->micb_ref[micb_index] == 0) 130210f514bdSNeil Armstrong snd_soc_component_write_field(component, micb_reg, 130310f514bdSNeil Armstrong micb_field, MICB_BIAS_PULL_UP); 130410f514bdSNeil Armstrong break; 130510f514bdSNeil Armstrong case MICB_PULLUP_DISABLE: 130610f514bdSNeil Armstrong if (wcd939x->pullup_ref[micb_index] > 0) 130710f514bdSNeil Armstrong wcd939x->pullup_ref[micb_index]--; 130810f514bdSNeil Armstrong if (wcd939x->pullup_ref[micb_index] == 0 && 130910f514bdSNeil Armstrong wcd939x->micb_ref[micb_index] == 0) 131010f514bdSNeil Armstrong snd_soc_component_write_field(component, micb_reg, 131110f514bdSNeil Armstrong micb_field, MICB_BIAS_DISABLE); 131210f514bdSNeil Armstrong break; 131310f514bdSNeil Armstrong case MICB_ENABLE: 131410f514bdSNeil Armstrong wcd939x->micb_ref[micb_index]++; 131510f514bdSNeil Armstrong if (wcd939x->micb_ref[micb_index] == 1) { 131610f514bdSNeil Armstrong snd_soc_component_write_field(component, 131710f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 131810f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD3_CLK_EN, true); 131910f514bdSNeil Armstrong snd_soc_component_write_field(component, 132010f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 132110f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD2_CLK_EN, true); 132210f514bdSNeil Armstrong snd_soc_component_write_field(component, 132310f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 132410f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD1_CLK_EN, true); 132510f514bdSNeil Armstrong snd_soc_component_write_field(component, 132610f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_DIG_CLK_CTL, 132710f514bdSNeil Armstrong WCD939X_CDC_DIG_CLK_CTL_TXD0_CLK_EN, true); 132810f514bdSNeil Armstrong snd_soc_component_write_field(component, 132910f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_ANA_CLK_CTL, 133010f514bdSNeil Armstrong WCD939X_CDC_ANA_CLK_CTL_ANA_TX_DIV2_CLK_EN, 133110f514bdSNeil Armstrong true); 133210f514bdSNeil Armstrong snd_soc_component_write_field(component, 133310f514bdSNeil Armstrong WCD939X_DIGITAL_CDC_ANA_TX_CLK_CTL, 133410f514bdSNeil Armstrong WCD939X_CDC_ANA_TX_CLK_CTL_ANA_TXSCBIAS_CLK_EN, 133510f514bdSNeil Armstrong true); 133610f514bdSNeil Armstrong snd_soc_component_write_field(component, 133710f514bdSNeil Armstrong WCD939X_MICB1_TEST_CTL_2, 133810f514bdSNeil Armstrong WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER, true); 133910f514bdSNeil Armstrong snd_soc_component_write_field(component, 134010f514bdSNeil Armstrong WCD939X_MICB2_TEST_CTL_2, 134110f514bdSNeil Armstrong WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER, true); 134210f514bdSNeil Armstrong snd_soc_component_write_field(component, 134310f514bdSNeil Armstrong WCD939X_MICB3_TEST_CTL_2, 134410f514bdSNeil Armstrong WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER, true); 134510f514bdSNeil Armstrong snd_soc_component_write_field(component, 134610f514bdSNeil Armstrong WCD939X_MICB4_TEST_CTL_2, 134710f514bdSNeil Armstrong WCD939X_TEST_CTL_2_IBIAS_LDO_DRIVER, true); 134810f514bdSNeil Armstrong snd_soc_component_write_field(component, micb_reg, micb_field, 134910f514bdSNeil Armstrong MICB_BIAS_ENABLE); 135010f514bdSNeil Armstrong if (micb_num == MIC_BIAS_2) 135110f514bdSNeil Armstrong wcd_mbhc_event_notify(wcd939x->wcd_mbhc, 135210f514bdSNeil Armstrong WCD_EVENT_POST_MICBIAS_2_ON); 135310f514bdSNeil Armstrong } 135410f514bdSNeil Armstrong if (micb_num == MIC_BIAS_2 && is_dapm) 135510f514bdSNeil Armstrong wcd_mbhc_event_notify(wcd939x->wcd_mbhc, 135610f514bdSNeil Armstrong WCD_EVENT_POST_DAPM_MICBIAS_2_ON); 135710f514bdSNeil Armstrong break; 135810f514bdSNeil Armstrong case MICB_DISABLE: 135910f514bdSNeil Armstrong if (wcd939x->micb_ref[micb_index] > 0) 136010f514bdSNeil Armstrong wcd939x->micb_ref[micb_index]--; 136110f514bdSNeil Armstrong 136210f514bdSNeil Armstrong if (wcd939x->micb_ref[micb_index] == 0 && 136310f514bdSNeil Armstrong wcd939x->pullup_ref[micb_index] > 0) 136410f514bdSNeil Armstrong snd_soc_component_write_field(component, micb_reg, 136510f514bdSNeil Armstrong micb_field, MICB_BIAS_PULL_UP); 136610f514bdSNeil Armstrong else if (wcd939x->micb_ref[micb_index] == 0 && 136710f514bdSNeil Armstrong wcd939x->pullup_ref[micb_index] == 0) { 136810f514bdSNeil Armstrong if (micb_num == MIC_BIAS_2) 136910f514bdSNeil Armstrong wcd_mbhc_event_notify(wcd939x->wcd_mbhc, 137010f514bdSNeil Armstrong WCD_EVENT_PRE_MICBIAS_2_OFF); 137110f514bdSNeil Armstrong 137210f514bdSNeil Armstrong snd_soc_component_write_field(component, micb_reg, 137310f514bdSNeil Armstrong micb_field, MICB_BIAS_DISABLE); 137410f514bdSNeil Armstrong if (micb_num == MIC_BIAS_2) 137510f514bdSNeil Armstrong wcd_mbhc_event_notify(wcd939x->wcd_mbhc, 137610f514bdSNeil Armstrong WCD_EVENT_POST_MICBIAS_2_OFF); 137710f514bdSNeil Armstrong } 137810f514bdSNeil Armstrong if (is_dapm && micb_num == MIC_BIAS_2) 137910f514bdSNeil Armstrong wcd_mbhc_event_notify(wcd939x->wcd_mbhc, 138010f514bdSNeil Armstrong WCD_EVENT_POST_DAPM_MICBIAS_2_OFF); 138110f514bdSNeil Armstrong break; 138210f514bdSNeil Armstrong } 138310f514bdSNeil Armstrong 138410f514bdSNeil Armstrong return 0; 138510f514bdSNeil Armstrong } 138610f514bdSNeil Armstrong 138710f514bdSNeil Armstrong static int wcd939x_codec_enable_micbias(struct snd_soc_dapm_widget *w, 138810f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, 138910f514bdSNeil Armstrong int event) 139010f514bdSNeil Armstrong { 139110f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 139210f514bdSNeil Armstrong int micb_num = w->shift; 139310f514bdSNeil Armstrong 139410f514bdSNeil Armstrong switch (event) { 139510f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 139610f514bdSNeil Armstrong wcd939x_micbias_control(component, micb_num, MICB_ENABLE, true); 139710f514bdSNeil Armstrong break; 139810f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMU: 139910f514bdSNeil Armstrong /* 1 msec delay as per HW requirement */ 140010f514bdSNeil Armstrong usleep_range(1000, 1100); 140110f514bdSNeil Armstrong break; 140210f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 140310f514bdSNeil Armstrong wcd939x_micbias_control(component, micb_num, MICB_DISABLE, true); 140410f514bdSNeil Armstrong break; 140510f514bdSNeil Armstrong } 140610f514bdSNeil Armstrong 140710f514bdSNeil Armstrong return 0; 140810f514bdSNeil Armstrong } 140910f514bdSNeil Armstrong 141010f514bdSNeil Armstrong static int wcd939x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w, 141110f514bdSNeil Armstrong struct snd_kcontrol *kcontrol, 141210f514bdSNeil Armstrong int event) 141310f514bdSNeil Armstrong { 141410f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); 141510f514bdSNeil Armstrong int micb_num = w->shift; 141610f514bdSNeil Armstrong 141710f514bdSNeil Armstrong switch (event) { 141810f514bdSNeil Armstrong case SND_SOC_DAPM_PRE_PMU: 141910f514bdSNeil Armstrong wcd939x_micbias_control(component, micb_num, 142010f514bdSNeil Armstrong MICB_PULLUP_ENABLE, true); 142110f514bdSNeil Armstrong break; 142210f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMU: 142310f514bdSNeil Armstrong /* 1 msec delay as per HW requirement */ 142410f514bdSNeil Armstrong usleep_range(1000, 1100); 142510f514bdSNeil Armstrong break; 142610f514bdSNeil Armstrong case SND_SOC_DAPM_POST_PMD: 142710f514bdSNeil Armstrong wcd939x_micbias_control(component, micb_num, 142810f514bdSNeil Armstrong MICB_PULLUP_DISABLE, true); 142910f514bdSNeil Armstrong break; 143010f514bdSNeil Armstrong } 143110f514bdSNeil Armstrong 143210f514bdSNeil Armstrong return 0; 143310f514bdSNeil Armstrong } 143410f514bdSNeil Armstrong 143510f514bdSNeil Armstrong static int wcd939x_tx_mode_get(struct snd_kcontrol *kcontrol, 143610f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 143710f514bdSNeil Armstrong { 143810f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 143910f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 144010f514bdSNeil Armstrong struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 144110f514bdSNeil Armstrong int path = e->shift_l; 144210f514bdSNeil Armstrong 144310f514bdSNeil Armstrong ucontrol->value.enumerated.item[0] = wcd939x->tx_mode[path]; 144410f514bdSNeil Armstrong 144510f514bdSNeil Armstrong return 0; 144610f514bdSNeil Armstrong } 144710f514bdSNeil Armstrong 144810f514bdSNeil Armstrong static int wcd939x_tx_mode_put(struct snd_kcontrol *kcontrol, 144910f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 145010f514bdSNeil Armstrong { 145110f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 145210f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 145310f514bdSNeil Armstrong struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 145410f514bdSNeil Armstrong int path = e->shift_l; 145510f514bdSNeil Armstrong 145610f514bdSNeil Armstrong if (wcd939x->tx_mode[path] == ucontrol->value.enumerated.item[0]) 145710f514bdSNeil Armstrong return 0; 145810f514bdSNeil Armstrong 145910f514bdSNeil Armstrong wcd939x->tx_mode[path] = ucontrol->value.enumerated.item[0]; 146010f514bdSNeil Armstrong 146110f514bdSNeil Armstrong return 1; 146210f514bdSNeil Armstrong } 146310f514bdSNeil Armstrong 146410f514bdSNeil Armstrong /* RX Controls */ 146510f514bdSNeil Armstrong 146610f514bdSNeil Armstrong static int wcd939x_rx_hph_mode_get(struct snd_kcontrol *kcontrol, 146710f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 146810f514bdSNeil Armstrong { 146910f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 147010f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 147110f514bdSNeil Armstrong 147210f514bdSNeil Armstrong ucontrol->value.integer.value[0] = wcd939x->hph_mode; 147310f514bdSNeil Armstrong 147410f514bdSNeil Armstrong return 0; 147510f514bdSNeil Armstrong } 147610f514bdSNeil Armstrong 147710f514bdSNeil Armstrong static int wcd939x_rx_hph_mode_put(struct snd_kcontrol *kcontrol, 147810f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 147910f514bdSNeil Armstrong { 148010f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 148110f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 148210f514bdSNeil Armstrong u32 mode_val; 148310f514bdSNeil Armstrong 148410f514bdSNeil Armstrong mode_val = ucontrol->value.enumerated.item[0]; 148510f514bdSNeil Armstrong 148610f514bdSNeil Armstrong if (mode_val == wcd939x->hph_mode) 148710f514bdSNeil Armstrong return 0; 148810f514bdSNeil Armstrong 148910f514bdSNeil Armstrong if (wcd939x->variant == WCD9390) { 149010f514bdSNeil Armstrong switch (mode_val) { 149110f514bdSNeil Armstrong case CLS_H_NORMAL: 149210f514bdSNeil Armstrong case CLS_H_LP: 149310f514bdSNeil Armstrong case CLS_AB: 149410f514bdSNeil Armstrong case CLS_H_LOHIFI: 149510f514bdSNeil Armstrong case CLS_H_ULP: 149610f514bdSNeil Armstrong case CLS_AB_LP: 149710f514bdSNeil Armstrong case CLS_AB_LOHIFI: 149810f514bdSNeil Armstrong wcd939x->hph_mode = mode_val; 149910f514bdSNeil Armstrong return 1; 150010f514bdSNeil Armstrong } 150110f514bdSNeil Armstrong } else { 150210f514bdSNeil Armstrong switch (mode_val) { 150310f514bdSNeil Armstrong case CLS_H_NORMAL: 150410f514bdSNeil Armstrong case CLS_H_HIFI: 150510f514bdSNeil Armstrong case CLS_H_LP: 150610f514bdSNeil Armstrong case CLS_AB: 150710f514bdSNeil Armstrong case CLS_H_LOHIFI: 150810f514bdSNeil Armstrong case CLS_H_ULP: 150910f514bdSNeil Armstrong case CLS_AB_HIFI: 151010f514bdSNeil Armstrong case CLS_AB_LP: 151110f514bdSNeil Armstrong case CLS_AB_LOHIFI: 151210f514bdSNeil Armstrong wcd939x->hph_mode = mode_val; 151310f514bdSNeil Armstrong return 1; 151410f514bdSNeil Armstrong } 151510f514bdSNeil Armstrong } 151610f514bdSNeil Armstrong 151710f514bdSNeil Armstrong dev_dbg(component->dev, "%s: Invalid HPH Mode\n", __func__); 151810f514bdSNeil Armstrong return -EINVAL; 151910f514bdSNeil Armstrong } 152010f514bdSNeil Armstrong 152110f514bdSNeil Armstrong static int wcd939x_get_compander(struct snd_kcontrol *kcontrol, 152210f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 152310f514bdSNeil Armstrong { 152410f514bdSNeil Armstrong struct soc_mixer_control *mc = (struct soc_mixer_control *)(kcontrol->private_value); 152510f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 152610f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 152710f514bdSNeil Armstrong 152810f514bdSNeil Armstrong if (mc->shift) 152910f514bdSNeil Armstrong ucontrol->value.integer.value[0] = wcd939x->comp2_enable ? 1 : 0; 153010f514bdSNeil Armstrong else 153110f514bdSNeil Armstrong ucontrol->value.integer.value[0] = wcd939x->comp1_enable ? 1 : 0; 153210f514bdSNeil Armstrong 153310f514bdSNeil Armstrong return 0; 153410f514bdSNeil Armstrong } 153510f514bdSNeil Armstrong 153610f514bdSNeil Armstrong static int wcd939x_set_compander(struct snd_kcontrol *kcontrol, 153710f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 153810f514bdSNeil Armstrong { 153910f514bdSNeil Armstrong struct soc_mixer_control *mc = (struct soc_mixer_control *)(kcontrol->private_value); 154010f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 154110f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 154210f514bdSNeil Armstrong struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[AIF1_PB]; 154310f514bdSNeil Armstrong bool value = !!ucontrol->value.integer.value[0]; 154410f514bdSNeil Armstrong int portidx = wcd->ch_info[mc->reg].port_num; 154510f514bdSNeil Armstrong 154610f514bdSNeil Armstrong if (mc->shift) 154710f514bdSNeil Armstrong wcd939x->comp2_enable = value; 154810f514bdSNeil Armstrong else 154910f514bdSNeil Armstrong wcd939x->comp1_enable = value; 155010f514bdSNeil Armstrong 155110f514bdSNeil Armstrong if (value) 155210f514bdSNeil Armstrong wcd939x_connect_port(wcd, portidx, mc->reg, true); 155310f514bdSNeil Armstrong else 155410f514bdSNeil Armstrong wcd939x_connect_port(wcd, portidx, mc->reg, false); 155510f514bdSNeil Armstrong 155610f514bdSNeil Armstrong return 1; 155710f514bdSNeil Armstrong } 155810f514bdSNeil Armstrong 155910f514bdSNeil Armstrong static int wcd939x_ldoh_get(struct snd_kcontrol *kcontrol, 156010f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 156110f514bdSNeil Armstrong { 156210f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 156310f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 156410f514bdSNeil Armstrong 156510f514bdSNeil Armstrong ucontrol->value.integer.value[0] = wcd939x->ldoh ? 1 : 0; 156610f514bdSNeil Armstrong 156710f514bdSNeil Armstrong return 0; 156810f514bdSNeil Armstrong } 156910f514bdSNeil Armstrong 157010f514bdSNeil Armstrong static int wcd939x_ldoh_put(struct snd_kcontrol *kcontrol, 157110f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 157210f514bdSNeil Armstrong { 157310f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 157410f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 157510f514bdSNeil Armstrong 157610f514bdSNeil Armstrong if (wcd939x->ldoh == !!ucontrol->value.integer.value[0]) 157710f514bdSNeil Armstrong return 0; 157810f514bdSNeil Armstrong 157910f514bdSNeil Armstrong wcd939x->ldoh = !!ucontrol->value.integer.value[0]; 158010f514bdSNeil Armstrong 158110f514bdSNeil Armstrong return 1; 158210f514bdSNeil Armstrong } 158310f514bdSNeil Armstrong 158410f514bdSNeil Armstrong static const char * const tx_mode_mux_text_wcd9390[] = { 158510f514bdSNeil Armstrong "ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP", 158610f514bdSNeil Armstrong }; 158710f514bdSNeil Armstrong 158810f514bdSNeil Armstrong static const struct soc_enum tx0_mode_mux_enum_wcd9390 = 158910f514bdSNeil Armstrong SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tx_mode_mux_text_wcd9390), 159010f514bdSNeil Armstrong tx_mode_mux_text_wcd9390); 159110f514bdSNeil Armstrong 159210f514bdSNeil Armstrong static const struct soc_enum tx1_mode_mux_enum_wcd9390 = 159310f514bdSNeil Armstrong SOC_ENUM_SINGLE(SND_SOC_NOPM, 1, ARRAY_SIZE(tx_mode_mux_text_wcd9390), 159410f514bdSNeil Armstrong tx_mode_mux_text_wcd9390); 159510f514bdSNeil Armstrong 159610f514bdSNeil Armstrong static const struct soc_enum tx2_mode_mux_enum_wcd9390 = 159710f514bdSNeil Armstrong SOC_ENUM_SINGLE(SND_SOC_NOPM, 2, ARRAY_SIZE(tx_mode_mux_text_wcd9390), 159810f514bdSNeil Armstrong tx_mode_mux_text_wcd9390); 159910f514bdSNeil Armstrong 160010f514bdSNeil Armstrong static const struct soc_enum tx3_mode_mux_enum_wcd9390 = 160110f514bdSNeil Armstrong SOC_ENUM_SINGLE(SND_SOC_NOPM, 3, ARRAY_SIZE(tx_mode_mux_text_wcd9390), 160210f514bdSNeil Armstrong tx_mode_mux_text_wcd9390); 160310f514bdSNeil Armstrong 160410f514bdSNeil Armstrong static const char * const tx_mode_mux_text[] = { 160510f514bdSNeil Armstrong "ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP", 160610f514bdSNeil Armstrong "ADC_ULP1", "ADC_ULP2", 160710f514bdSNeil Armstrong }; 160810f514bdSNeil Armstrong 160910f514bdSNeil Armstrong static const struct soc_enum tx0_mode_mux_enum = 161010f514bdSNeil Armstrong SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tx_mode_mux_text), 161110f514bdSNeil Armstrong tx_mode_mux_text); 161210f514bdSNeil Armstrong 161310f514bdSNeil Armstrong static const struct soc_enum tx1_mode_mux_enum = 161410f514bdSNeil Armstrong SOC_ENUM_SINGLE(SND_SOC_NOPM, 1, ARRAY_SIZE(tx_mode_mux_text), 161510f514bdSNeil Armstrong tx_mode_mux_text); 161610f514bdSNeil Armstrong 161710f514bdSNeil Armstrong static const struct soc_enum tx2_mode_mux_enum = 161810f514bdSNeil Armstrong SOC_ENUM_SINGLE(SND_SOC_NOPM, 2, ARRAY_SIZE(tx_mode_mux_text), 161910f514bdSNeil Armstrong tx_mode_mux_text); 162010f514bdSNeil Armstrong 162110f514bdSNeil Armstrong static const struct soc_enum tx3_mode_mux_enum = 162210f514bdSNeil Armstrong SOC_ENUM_SINGLE(SND_SOC_NOPM, 3, ARRAY_SIZE(tx_mode_mux_text), 162310f514bdSNeil Armstrong tx_mode_mux_text); 162410f514bdSNeil Armstrong 162510f514bdSNeil Armstrong static const char * const rx_hph_mode_mux_text_wcd9390[] = { 162610f514bdSNeil Armstrong "CLS_H_NORMAL", "CLS_H_INVALID_1", "CLS_H_LP", "CLS_AB", 162710f514bdSNeil Armstrong "CLS_H_LOHIFI", "CLS_H_ULP", "CLS_H_INVALID_2", "CLS_AB_LP", 162810f514bdSNeil Armstrong "CLS_AB_LOHIFI", 162910f514bdSNeil Armstrong }; 163010f514bdSNeil Armstrong 163110f514bdSNeil Armstrong static const struct soc_enum rx_hph_mode_mux_enum_wcd9390 = 163210f514bdSNeil Armstrong SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text_wcd9390), 163310f514bdSNeil Armstrong rx_hph_mode_mux_text_wcd9390); 163410f514bdSNeil Armstrong 163510f514bdSNeil Armstrong static const char * const rx_hph_mode_mux_text[] = { 163610f514bdSNeil Armstrong "CLS_H_NORMAL", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", "CLS_H_LOHIFI", 163710f514bdSNeil Armstrong "CLS_H_ULP", "CLS_AB_HIFI", "CLS_AB_LP", "CLS_AB_LOHIFI", 163810f514bdSNeil Armstrong }; 163910f514bdSNeil Armstrong 164010f514bdSNeil Armstrong static const struct soc_enum rx_hph_mode_mux_enum = 164110f514bdSNeil Armstrong SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), 164210f514bdSNeil Armstrong rx_hph_mode_mux_text); 164310f514bdSNeil Armstrong 164410f514bdSNeil Armstrong static const struct snd_kcontrol_new wcd9390_snd_controls[] = { 164510f514bdSNeil Armstrong SOC_SINGLE_TLV("EAR_PA Volume", WCD939X_ANA_EAR_COMPANDER_CTL, 164610f514bdSNeil Armstrong 2, 0x10, 0, ear_pa_gain), 164710f514bdSNeil Armstrong 164810f514bdSNeil Armstrong SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum_wcd9390, 164910f514bdSNeil Armstrong wcd939x_rx_hph_mode_get, wcd939x_rx_hph_mode_put), 165010f514bdSNeil Armstrong 165110f514bdSNeil Armstrong SOC_ENUM_EXT("TX0 MODE", tx0_mode_mux_enum_wcd9390, 165210f514bdSNeil Armstrong wcd939x_tx_mode_get, wcd939x_tx_mode_put), 165310f514bdSNeil Armstrong SOC_ENUM_EXT("TX1 MODE", tx1_mode_mux_enum_wcd9390, 165410f514bdSNeil Armstrong wcd939x_tx_mode_get, wcd939x_tx_mode_put), 165510f514bdSNeil Armstrong SOC_ENUM_EXT("TX2 MODE", tx2_mode_mux_enum_wcd9390, 165610f514bdSNeil Armstrong wcd939x_tx_mode_get, wcd939x_tx_mode_put), 165710f514bdSNeil Armstrong SOC_ENUM_EXT("TX3 MODE", tx3_mode_mux_enum_wcd9390, 165810f514bdSNeil Armstrong wcd939x_tx_mode_get, wcd939x_tx_mode_put), 165910f514bdSNeil Armstrong }; 166010f514bdSNeil Armstrong 166110f514bdSNeil Armstrong static const struct snd_kcontrol_new wcd9395_snd_controls[] = { 166210f514bdSNeil Armstrong SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum, 166310f514bdSNeil Armstrong wcd939x_rx_hph_mode_get, wcd939x_rx_hph_mode_put), 166410f514bdSNeil Armstrong 166510f514bdSNeil Armstrong SOC_ENUM_EXT("TX0 MODE", tx0_mode_mux_enum, 166610f514bdSNeil Armstrong wcd939x_tx_mode_get, wcd939x_tx_mode_put), 166710f514bdSNeil Armstrong SOC_ENUM_EXT("TX1 MODE", tx1_mode_mux_enum, 166810f514bdSNeil Armstrong wcd939x_tx_mode_get, wcd939x_tx_mode_put), 166910f514bdSNeil Armstrong SOC_ENUM_EXT("TX2 MODE", tx2_mode_mux_enum, 167010f514bdSNeil Armstrong wcd939x_tx_mode_get, wcd939x_tx_mode_put), 167110f514bdSNeil Armstrong SOC_ENUM_EXT("TX3 MODE", tx3_mode_mux_enum, 167210f514bdSNeil Armstrong wcd939x_tx_mode_get, wcd939x_tx_mode_put), 167310f514bdSNeil Armstrong }; 167410f514bdSNeil Armstrong 167510f514bdSNeil Armstrong static const struct snd_kcontrol_new adc1_switch[] = { 167610f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 167710f514bdSNeil Armstrong }; 167810f514bdSNeil Armstrong 167910f514bdSNeil Armstrong static const struct snd_kcontrol_new adc2_switch[] = { 168010f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 168110f514bdSNeil Armstrong }; 168210f514bdSNeil Armstrong 168310f514bdSNeil Armstrong static const struct snd_kcontrol_new adc3_switch[] = { 168410f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 168510f514bdSNeil Armstrong }; 168610f514bdSNeil Armstrong 168710f514bdSNeil Armstrong static const struct snd_kcontrol_new adc4_switch[] = { 168810f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 168910f514bdSNeil Armstrong }; 169010f514bdSNeil Armstrong 169110f514bdSNeil Armstrong static const struct snd_kcontrol_new dmic1_switch[] = { 169210f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 169310f514bdSNeil Armstrong }; 169410f514bdSNeil Armstrong 169510f514bdSNeil Armstrong static const struct snd_kcontrol_new dmic2_switch[] = { 169610f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 169710f514bdSNeil Armstrong }; 169810f514bdSNeil Armstrong 169910f514bdSNeil Armstrong static const struct snd_kcontrol_new dmic3_switch[] = { 170010f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 170110f514bdSNeil Armstrong }; 170210f514bdSNeil Armstrong 170310f514bdSNeil Armstrong static const struct snd_kcontrol_new dmic4_switch[] = { 170410f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 170510f514bdSNeil Armstrong }; 170610f514bdSNeil Armstrong 170710f514bdSNeil Armstrong static const struct snd_kcontrol_new dmic5_switch[] = { 170810f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 170910f514bdSNeil Armstrong }; 171010f514bdSNeil Armstrong 171110f514bdSNeil Armstrong static const struct snd_kcontrol_new dmic6_switch[] = { 171210f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 171310f514bdSNeil Armstrong }; 171410f514bdSNeil Armstrong 171510f514bdSNeil Armstrong static const struct snd_kcontrol_new dmic7_switch[] = { 171610f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 171710f514bdSNeil Armstrong }; 171810f514bdSNeil Armstrong 171910f514bdSNeil Armstrong static const struct snd_kcontrol_new dmic8_switch[] = { 172010f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 172110f514bdSNeil Armstrong }; 172210f514bdSNeil Armstrong 172310f514bdSNeil Armstrong static const struct snd_kcontrol_new ear_rdac_switch[] = { 172410f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 172510f514bdSNeil Armstrong }; 172610f514bdSNeil Armstrong 172710f514bdSNeil Armstrong static const struct snd_kcontrol_new hphl_rdac_switch[] = { 172810f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 172910f514bdSNeil Armstrong }; 173010f514bdSNeil Armstrong 173110f514bdSNeil Armstrong static const struct snd_kcontrol_new hphr_rdac_switch[] = { 173210f514bdSNeil Armstrong SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) 173310f514bdSNeil Armstrong }; 173410f514bdSNeil Armstrong 173510f514bdSNeil Armstrong static const char * const adc1_mux_text[] = { 173610f514bdSNeil Armstrong "CH1_AMIC_DISABLE", "CH1_AMIC1", "CH1_AMIC2", "CH1_AMIC3", "CH1_AMIC4", "CH1_AMIC5" 173710f514bdSNeil Armstrong }; 173810f514bdSNeil Armstrong 173910f514bdSNeil Armstrong static const struct soc_enum adc1_enum = 174010f514bdSNeil Armstrong SOC_ENUM_SINGLE(WCD939X_TX_NEW_CH12_MUX, 0, 174110f514bdSNeil Armstrong ARRAY_SIZE(adc1_mux_text), adc1_mux_text); 174210f514bdSNeil Armstrong 174310f514bdSNeil Armstrong static const struct snd_kcontrol_new tx_adc1_mux = 174410f514bdSNeil Armstrong SOC_DAPM_ENUM("ADC1 MUX Mux", adc1_enum); 174510f514bdSNeil Armstrong 174610f514bdSNeil Armstrong static const char * const adc2_mux_text[] = { 174710f514bdSNeil Armstrong "CH2_AMIC_DISABLE", "CH2_AMIC1", "CH2_AMIC2", "CH2_AMIC3", "CH2_AMIC4", "CH2_AMIC5" 174810f514bdSNeil Armstrong }; 174910f514bdSNeil Armstrong 175010f514bdSNeil Armstrong static const struct soc_enum adc2_enum = 175110f514bdSNeil Armstrong SOC_ENUM_SINGLE(WCD939X_TX_NEW_CH12_MUX, 3, 175210f514bdSNeil Armstrong ARRAY_SIZE(adc2_mux_text), adc2_mux_text); 175310f514bdSNeil Armstrong 175410f514bdSNeil Armstrong static const struct snd_kcontrol_new tx_adc2_mux = 175510f514bdSNeil Armstrong SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum); 175610f514bdSNeil Armstrong 175710f514bdSNeil Armstrong static const char * const adc3_mux_text[] = { 175810f514bdSNeil Armstrong "CH3_AMIC_DISABLE", "CH3_AMIC1", "CH3_AMIC3", "CH3_AMIC4", "CH3_AMIC5" 175910f514bdSNeil Armstrong }; 176010f514bdSNeil Armstrong 176110f514bdSNeil Armstrong static const struct soc_enum adc3_enum = 176210f514bdSNeil Armstrong SOC_ENUM_SINGLE(WCD939X_TX_NEW_CH34_MUX, 0, 176310f514bdSNeil Armstrong ARRAY_SIZE(adc3_mux_text), adc3_mux_text); 176410f514bdSNeil Armstrong 176510f514bdSNeil Armstrong static const struct snd_kcontrol_new tx_adc3_mux = 176610f514bdSNeil Armstrong SOC_DAPM_ENUM("ADC3 MUX Mux", adc3_enum); 176710f514bdSNeil Armstrong 176810f514bdSNeil Armstrong static const char * const adc4_mux_text[] = { 176910f514bdSNeil Armstrong "CH4_AMIC_DISABLE", "CH4_AMIC1", "CH4_AMIC3", "CH4_AMIC4", "CH4_AMIC5" 177010f514bdSNeil Armstrong }; 177110f514bdSNeil Armstrong 177210f514bdSNeil Armstrong static const struct soc_enum adc4_enum = 177310f514bdSNeil Armstrong SOC_ENUM_SINGLE(WCD939X_TX_NEW_CH34_MUX, 3, 177410f514bdSNeil Armstrong ARRAY_SIZE(adc4_mux_text), adc4_mux_text); 177510f514bdSNeil Armstrong 177610f514bdSNeil Armstrong static const struct snd_kcontrol_new tx_adc4_mux = 177710f514bdSNeil Armstrong SOC_DAPM_ENUM("ADC4 MUX Mux", adc4_enum); 177810f514bdSNeil Armstrong 177910f514bdSNeil Armstrong static const char * const rdac3_mux_text[] = { 178010f514bdSNeil Armstrong "RX3", "RX1" 178110f514bdSNeil Armstrong }; 178210f514bdSNeil Armstrong 178310f514bdSNeil Armstrong static const struct soc_enum rdac3_enum = 178410f514bdSNeil Armstrong SOC_ENUM_SINGLE(WCD939X_DIGITAL_CDC_EAR_PATH_CTL, 0, 178510f514bdSNeil Armstrong ARRAY_SIZE(rdac3_mux_text), rdac3_mux_text); 178610f514bdSNeil Armstrong 178710f514bdSNeil Armstrong static const struct snd_kcontrol_new rx_rdac3_mux = 178810f514bdSNeil Armstrong SOC_DAPM_ENUM("RDAC3_MUX Mux", rdac3_enum); 178910f514bdSNeil Armstrong 179010f514bdSNeil Armstrong static int wcd939x_get_swr_port(struct snd_kcontrol *kcontrol, 179110f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 179210f514bdSNeil Armstrong { 179310f514bdSNeil Armstrong struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value; 179410f514bdSNeil Armstrong struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); 179510f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(comp); 179610f514bdSNeil Armstrong struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[mixer->shift]; 179710f514bdSNeil Armstrong unsigned int portidx = wcd->ch_info[mixer->reg].port_num; 179810f514bdSNeil Armstrong 179910f514bdSNeil Armstrong ucontrol->value.integer.value[0] = wcd->port_enable[portidx] ? 1 : 0; 180010f514bdSNeil Armstrong 180110f514bdSNeil Armstrong return 0; 180210f514bdSNeil Armstrong } 180310f514bdSNeil Armstrong 180410f514bdSNeil Armstrong static const char *version_to_str(u32 version) 180510f514bdSNeil Armstrong { 180610f514bdSNeil Armstrong switch (version) { 180710f514bdSNeil Armstrong case WCD939X_VERSION_1_0: 180810f514bdSNeil Armstrong return __stringify(WCD939X_1_0); 180910f514bdSNeil Armstrong case WCD939X_VERSION_1_1: 181010f514bdSNeil Armstrong return __stringify(WCD939X_1_1); 181110f514bdSNeil Armstrong case WCD939X_VERSION_2_0: 181210f514bdSNeil Armstrong return __stringify(WCD939X_2_0); 181310f514bdSNeil Armstrong } 181410f514bdSNeil Armstrong return NULL; 181510f514bdSNeil Armstrong } 181610f514bdSNeil Armstrong 181710f514bdSNeil Armstrong static int wcd939x_set_swr_port(struct snd_kcontrol *kcontrol, 181810f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 181910f514bdSNeil Armstrong { 182010f514bdSNeil Armstrong struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value; 182110f514bdSNeil Armstrong struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); 182210f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(comp); 182310f514bdSNeil Armstrong struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[mixer->shift]; 182410f514bdSNeil Armstrong unsigned int portidx = wcd->ch_info[mixer->reg].port_num; 182510f514bdSNeil Armstrong 182610f514bdSNeil Armstrong wcd->port_enable[portidx] = !!ucontrol->value.integer.value[0]; 182710f514bdSNeil Armstrong 182810f514bdSNeil Armstrong wcd939x_connect_port(wcd, portidx, mixer->reg, wcd->port_enable[portidx]); 182910f514bdSNeil Armstrong 183010f514bdSNeil Armstrong return 1; 183110f514bdSNeil Armstrong } 183210f514bdSNeil Armstrong 183310f514bdSNeil Armstrong /* MBHC Related */ 183410f514bdSNeil Armstrong 183510f514bdSNeil Armstrong static void wcd939x_mbhc_clk_setup(struct snd_soc_component *component, 183610f514bdSNeil Armstrong bool enable) 183710f514bdSNeil Armstrong { 183810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_1, 183910f514bdSNeil Armstrong WCD939X_CTL_1_RCO_EN, enable); 184010f514bdSNeil Armstrong } 184110f514bdSNeil Armstrong 184210f514bdSNeil Armstrong static void wcd939x_mbhc_mbhc_bias_control(struct snd_soc_component *component, 184310f514bdSNeil Armstrong bool enable) 184410f514bdSNeil Armstrong { 184510f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ELECT, 184610f514bdSNeil Armstrong WCD939X_MBHC_ELECT_BIAS_EN, enable); 184710f514bdSNeil Armstrong } 184810f514bdSNeil Armstrong 184910f514bdSNeil Armstrong static void wcd939x_mbhc_program_btn_thr(struct snd_soc_component *component, 185010f514bdSNeil Armstrong int *btn_low, int *btn_high, 185110f514bdSNeil Armstrong int num_btn, bool is_micbias) 185210f514bdSNeil Armstrong { 185310f514bdSNeil Armstrong int i, vth; 185410f514bdSNeil Armstrong 185510f514bdSNeil Armstrong if (num_btn > WCD_MBHC_DEF_BUTTONS) { 185610f514bdSNeil Armstrong dev_err(component->dev, "%s: invalid number of buttons: %d\n", 185710f514bdSNeil Armstrong __func__, num_btn); 185810f514bdSNeil Armstrong return; 185910f514bdSNeil Armstrong } 186010f514bdSNeil Armstrong 186110f514bdSNeil Armstrong for (i = 0; i < num_btn; i++) { 186210f514bdSNeil Armstrong vth = (btn_high[i] * 2) / 25; 186310f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_BTN0 + i, 186410f514bdSNeil Armstrong WCD939X_MBHC_BTN0_VTH, vth); 186510f514bdSNeil Armstrong dev_dbg(component->dev, "%s: btn_high[%d]: %d, vth: %d\n", 186610f514bdSNeil Armstrong __func__, i, btn_high[i], vth); 186710f514bdSNeil Armstrong } 186810f514bdSNeil Armstrong } 186910f514bdSNeil Armstrong 187010f514bdSNeil Armstrong static bool wcd939x_mbhc_micb_en_status(struct snd_soc_component *component, int micb_num) 187110f514bdSNeil Armstrong { 187210f514bdSNeil Armstrong 187310f514bdSNeil Armstrong if (micb_num == MIC_BIAS_2) { 187410f514bdSNeil Armstrong u8 val; 187510f514bdSNeil Armstrong 187610f514bdSNeil Armstrong val = FIELD_GET(WCD939X_MICB2_ENABLE, 187710f514bdSNeil Armstrong snd_soc_component_read(component, WCD939X_ANA_MICB2)); 187810f514bdSNeil Armstrong if (val == MICB_BIAS_ENABLE) 187910f514bdSNeil Armstrong return true; 188010f514bdSNeil Armstrong } 188110f514bdSNeil Armstrong 188210f514bdSNeil Armstrong return false; 188310f514bdSNeil Armstrong } 188410f514bdSNeil Armstrong 188510f514bdSNeil Armstrong static void wcd939x_mbhc_hph_l_pull_up_control(struct snd_soc_component *component, 188610f514bdSNeil Armstrong int pull_up_cur) 188710f514bdSNeil Armstrong { 188810f514bdSNeil Armstrong /* Default pull up current to 2uA */ 188910f514bdSNeil Armstrong if (pull_up_cur > HS_PULLUP_I_OFF || 189010f514bdSNeil Armstrong pull_up_cur < HS_PULLUP_I_3P0_UA || 189110f514bdSNeil Armstrong pull_up_cur == HS_PULLUP_I_DEFAULT) 189210f514bdSNeil Armstrong pull_up_cur = HS_PULLUP_I_2P0_UA; 189310f514bdSNeil Armstrong 189410f514bdSNeil Armstrong dev_dbg(component->dev, "%s: HS pull up current:%d\n", 189510f514bdSNeil Armstrong __func__, pull_up_cur); 189610f514bdSNeil Armstrong 189710f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_INT_MECH_DET_CURRENT, 189810f514bdSNeil Armstrong WCD939X_MECH_DET_CURRENT_HSDET_PULLUP_CTL, pull_up_cur); 189910f514bdSNeil Armstrong } 190010f514bdSNeil Armstrong 190110f514bdSNeil Armstrong static int wcd939x_mbhc_request_micbias(struct snd_soc_component *component, 190210f514bdSNeil Armstrong int micb_num, int req) 190310f514bdSNeil Armstrong { 190410f514bdSNeil Armstrong return wcd939x_micbias_control(component, micb_num, req, false); 190510f514bdSNeil Armstrong } 190610f514bdSNeil Armstrong 190710f514bdSNeil Armstrong static void wcd939x_mbhc_micb_ramp_control(struct snd_soc_component *component, 190810f514bdSNeil Armstrong bool enable) 190910f514bdSNeil Armstrong { 191010f514bdSNeil Armstrong if (enable) { 191110f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MICB2_RAMP, 191210f514bdSNeil Armstrong WCD939X_MICB2_RAMP_SHIFT_CTL, 3); 191310f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MICB2_RAMP, 191410f514bdSNeil Armstrong WCD939X_MICB2_RAMP_RAMP_ENABLE, true); 191510f514bdSNeil Armstrong } else { 191610f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MICB2_RAMP, 191710f514bdSNeil Armstrong WCD939X_MICB2_RAMP_RAMP_ENABLE, false); 191810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MICB2_RAMP, 191910f514bdSNeil Armstrong WCD939X_MICB2_RAMP_SHIFT_CTL, 0); 192010f514bdSNeil Armstrong } 192110f514bdSNeil Armstrong } 192210f514bdSNeil Armstrong 192310f514bdSNeil Armstrong static int wcd939x_get_micb_vout_ctl_val(u32 micb_mv) 192410f514bdSNeil Armstrong { 192510f514bdSNeil Armstrong /* min micbias voltage is 1V and maximum is 2.85V */ 192610f514bdSNeil Armstrong if (micb_mv < 1000 || micb_mv > 2850) { 192710f514bdSNeil Armstrong pr_err("%s: unsupported micbias voltage\n", __func__); 192810f514bdSNeil Armstrong return -EINVAL; 192910f514bdSNeil Armstrong } 193010f514bdSNeil Armstrong 193110f514bdSNeil Armstrong return (micb_mv - 1000) / 50; 193210f514bdSNeil Armstrong } 193310f514bdSNeil Armstrong 193410f514bdSNeil Armstrong static int wcd939x_mbhc_micb_adjust_voltage(struct snd_soc_component *component, 193510f514bdSNeil Armstrong int req_volt, int micb_num) 193610f514bdSNeil Armstrong { 193710f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 193810f514bdSNeil Armstrong unsigned int micb_en_field, micb_vout_ctl_field; 193910f514bdSNeil Armstrong unsigned int micb_reg, cur_vout_ctl, micb_en; 194010f514bdSNeil Armstrong int req_vout_ctl; 194110f514bdSNeil Armstrong int ret = 0; 194210f514bdSNeil Armstrong 194310f514bdSNeil Armstrong switch (micb_num) { 194410f514bdSNeil Armstrong case MIC_BIAS_1: 194510f514bdSNeil Armstrong micb_reg = WCD939X_ANA_MICB1; 194610f514bdSNeil Armstrong micb_en_field = WCD939X_MICB1_ENABLE; 194710f514bdSNeil Armstrong micb_vout_ctl_field = WCD939X_MICB1_VOUT_CTL; 194810f514bdSNeil Armstrong break; 194910f514bdSNeil Armstrong case MIC_BIAS_2: 195010f514bdSNeil Armstrong micb_reg = WCD939X_ANA_MICB2; 195110f514bdSNeil Armstrong micb_en_field = WCD939X_MICB2_ENABLE; 195210f514bdSNeil Armstrong micb_vout_ctl_field = WCD939X_MICB2_VOUT_CTL; 195310f514bdSNeil Armstrong break; 195410f514bdSNeil Armstrong case MIC_BIAS_3: 195510f514bdSNeil Armstrong micb_reg = WCD939X_ANA_MICB3; 195610f514bdSNeil Armstrong micb_en_field = WCD939X_MICB3_ENABLE; 195710f514bdSNeil Armstrong micb_vout_ctl_field = WCD939X_MICB1_VOUT_CTL; 195810f514bdSNeil Armstrong break; 195910f514bdSNeil Armstrong case MIC_BIAS_4: 196010f514bdSNeil Armstrong micb_reg = WCD939X_ANA_MICB4; 196110f514bdSNeil Armstrong micb_en_field = WCD939X_MICB4_ENABLE; 196210f514bdSNeil Armstrong micb_vout_ctl_field = WCD939X_MICB2_VOUT_CTL; 196310f514bdSNeil Armstrong break; 196410f514bdSNeil Armstrong default: 196510f514bdSNeil Armstrong return -EINVAL; 196610f514bdSNeil Armstrong } 196710f514bdSNeil Armstrong mutex_lock(&wcd939x->micb_lock); 196810f514bdSNeil Armstrong 196910f514bdSNeil Armstrong /* 197010f514bdSNeil Armstrong * If requested micbias voltage is same as current micbias 197110f514bdSNeil Armstrong * voltage, then just return. Otherwise, adjust voltage as 197210f514bdSNeil Armstrong * per requested value. If micbias is already enabled, then 197310f514bdSNeil Armstrong * to avoid slow micbias ramp-up or down enable pull-up 197410f514bdSNeil Armstrong * momentarily, change the micbias value and then re-enable 197510f514bdSNeil Armstrong * micbias. 197610f514bdSNeil Armstrong */ 197710f514bdSNeil Armstrong micb_en = snd_soc_component_read_field(component, micb_reg, 197810f514bdSNeil Armstrong micb_en_field); 197910f514bdSNeil Armstrong cur_vout_ctl = snd_soc_component_read_field(component, micb_reg, 198010f514bdSNeil Armstrong micb_vout_ctl_field); 198110f514bdSNeil Armstrong 198210f514bdSNeil Armstrong req_vout_ctl = wcd939x_get_micb_vout_ctl_val(req_volt); 198310f514bdSNeil Armstrong if (req_vout_ctl < 0) { 198410f514bdSNeil Armstrong ret = req_vout_ctl; 198510f514bdSNeil Armstrong goto exit; 198610f514bdSNeil Armstrong } 198710f514bdSNeil Armstrong 198810f514bdSNeil Armstrong if (cur_vout_ctl == req_vout_ctl) { 198910f514bdSNeil Armstrong ret = 0; 199010f514bdSNeil Armstrong goto exit; 199110f514bdSNeil Armstrong } 199210f514bdSNeil Armstrong 199310f514bdSNeil Armstrong dev_dbg(component->dev, "%s: micb_num: %d, cur_mv: %d, req_mv: %d, micb_en: %d\n", 199410f514bdSNeil Armstrong __func__, micb_num, WCD_VOUT_CTL_TO_MICB(cur_vout_ctl), 199510f514bdSNeil Armstrong req_volt, micb_en); 199610f514bdSNeil Armstrong 199710f514bdSNeil Armstrong if (micb_en == MICB_BIAS_ENABLE) 199810f514bdSNeil Armstrong snd_soc_component_write_field(component, micb_reg, 199910f514bdSNeil Armstrong micb_en_field, MICB_BIAS_PULL_DOWN); 200010f514bdSNeil Armstrong 200110f514bdSNeil Armstrong snd_soc_component_write_field(component, micb_reg, 200210f514bdSNeil Armstrong micb_vout_ctl_field, req_vout_ctl); 200310f514bdSNeil Armstrong 200410f514bdSNeil Armstrong if (micb_en == MICB_BIAS_ENABLE) { 200510f514bdSNeil Armstrong snd_soc_component_write_field(component, micb_reg, 200610f514bdSNeil Armstrong micb_en_field, MICB_BIAS_ENABLE); 200710f514bdSNeil Armstrong /* 200810f514bdSNeil Armstrong * Add 2ms delay as per HW requirement after enabling 200910f514bdSNeil Armstrong * micbias 201010f514bdSNeil Armstrong */ 201110f514bdSNeil Armstrong usleep_range(2000, 2100); 201210f514bdSNeil Armstrong } 201310f514bdSNeil Armstrong 201410f514bdSNeil Armstrong exit: 201510f514bdSNeil Armstrong mutex_unlock(&wcd939x->micb_lock); 201610f514bdSNeil Armstrong return ret; 201710f514bdSNeil Armstrong } 201810f514bdSNeil Armstrong 201910f514bdSNeil Armstrong static int wcd939x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *component, 202010f514bdSNeil Armstrong int micb_num, bool req_en) 202110f514bdSNeil Armstrong { 202210f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 202310f514bdSNeil Armstrong int micb_mv; 202410f514bdSNeil Armstrong 202510f514bdSNeil Armstrong if (micb_num != MIC_BIAS_2) 202610f514bdSNeil Armstrong return -EINVAL; 202710f514bdSNeil Armstrong /* 202810f514bdSNeil Armstrong * If device tree micbias level is already above the minimum 202910f514bdSNeil Armstrong * voltage needed to detect threshold microphone, then do 203010f514bdSNeil Armstrong * not change the micbias, just return. 203110f514bdSNeil Armstrong */ 203210f514bdSNeil Armstrong if (wcd939x->micb2_mv >= WCD_MBHC_THR_HS_MICB_MV) 203310f514bdSNeil Armstrong return 0; 203410f514bdSNeil Armstrong 203510f514bdSNeil Armstrong micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : wcd939x->micb2_mv; 203610f514bdSNeil Armstrong 203710f514bdSNeil Armstrong return wcd939x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2); 203810f514bdSNeil Armstrong } 203910f514bdSNeil Armstrong 204010f514bdSNeil Armstrong /* Selected by WCD939X_MBHC_GET_C1() */ 204110f514bdSNeil Armstrong static const s16 wcd939x_wcd_mbhc_d1_a[4] = { 204210f514bdSNeil Armstrong 0, 30, 30, 6 204310f514bdSNeil Armstrong }; 204410f514bdSNeil Armstrong 204510f514bdSNeil Armstrong /* Selected by zdet_param.noff */ 204610f514bdSNeil Armstrong static const int wcd939x_mbhc_mincode_param[] = { 204710f514bdSNeil Armstrong 3277, 1639, 820, 410, 205, 103, 52, 26 204810f514bdSNeil Armstrong }; 204910f514bdSNeil Armstrong 205010f514bdSNeil Armstrong static const struct zdet_param wcd939x_mbhc_zdet_param = { 205110f514bdSNeil Armstrong .ldo_ctl = 4, 205210f514bdSNeil Armstrong .noff = 0, 205310f514bdSNeil Armstrong .nshift = 6, 205410f514bdSNeil Armstrong .btn5 = 0x18, 205510f514bdSNeil Armstrong .btn6 = 0x60, 205610f514bdSNeil Armstrong .btn7 = 0x78, 205710f514bdSNeil Armstrong }; 205810f514bdSNeil Armstrong 205910f514bdSNeil Armstrong static void wcd939x_mbhc_get_result_params(struct snd_soc_component *component, 206010f514bdSNeil Armstrong int32_t *zdet) 206110f514bdSNeil Armstrong { 206210f514bdSNeil Armstrong const struct zdet_param *zdet_param = &wcd939x_mbhc_zdet_param; 206310f514bdSNeil Armstrong s32 x1, d1, denom; 206410f514bdSNeil Armstrong int val; 206510f514bdSNeil Armstrong s16 c1; 206610f514bdSNeil Armstrong int i; 206710f514bdSNeil Armstrong 206810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET, 206910f514bdSNeil Armstrong WCD939X_MBHC_ZDET_ZDET_CHG_EN, true); 207010f514bdSNeil Armstrong for (i = 0; i < WCD939X_ZDET_NUM_MEASUREMENTS; i++) { 207110f514bdSNeil Armstrong val = snd_soc_component_read_field(component, WCD939X_ANA_MBHC_RESULT_2, 207210f514bdSNeil Armstrong WCD939X_MBHC_RESULT_2_Z_RESULT_MSB); 207310f514bdSNeil Armstrong if (val & BIT(7)) 207410f514bdSNeil Armstrong break; 207510f514bdSNeil Armstrong } 207610f514bdSNeil Armstrong val = val << 8; 207710f514bdSNeil Armstrong val |= snd_soc_component_read_field(component, WCD939X_ANA_MBHC_RESULT_1, 207810f514bdSNeil Armstrong WCD939X_MBHC_RESULT_1_Z_RESULT_LSB); 207910f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET, 208010f514bdSNeil Armstrong WCD939X_MBHC_ZDET_ZDET_CHG_EN, false); 208110f514bdSNeil Armstrong x1 = WCD939X_MBHC_GET_X1(val); 208210f514bdSNeil Armstrong c1 = WCD939X_MBHC_GET_C1(val); 208310f514bdSNeil Armstrong 208410f514bdSNeil Armstrong /* If ramp is not complete, give additional 5ms */ 208510f514bdSNeil Armstrong if (c1 < 2 && x1) 208610f514bdSNeil Armstrong mdelay(5); 208710f514bdSNeil Armstrong 208810f514bdSNeil Armstrong if (!c1 || !x1) { 208910f514bdSNeil Armstrong dev_dbg(component->dev, 209010f514bdSNeil Armstrong "%s: Impedance detect ramp error, c1=%d, x1=0x%x\n", 209110f514bdSNeil Armstrong __func__, c1, x1); 209210f514bdSNeil Armstrong goto ramp_down; 209310f514bdSNeil Armstrong } 209410f514bdSNeil Armstrong 209510f514bdSNeil Armstrong d1 = wcd939x_wcd_mbhc_d1_a[c1]; 209610f514bdSNeil Armstrong denom = (x1 * d1) - (1 << (14 - zdet_param->noff)); 209710f514bdSNeil Armstrong if (denom > 0) 209810f514bdSNeil Armstrong *zdet = (WCD939X_ANA_MBHC_ZDET_CONST * 1000) / denom; 209910f514bdSNeil Armstrong else if (x1 < wcd939x_mbhc_mincode_param[zdet_param->noff]) 210010f514bdSNeil Armstrong *zdet = WCD939X_ZDET_FLOATING_IMPEDANCE; 210110f514bdSNeil Armstrong 210210f514bdSNeil Armstrong dev_dbg(component->dev, "%s: d1=%d, c1=%d, x1=0x%x, z_val=%d(milliOhm)\n", 210310f514bdSNeil Armstrong __func__, d1, c1, x1, *zdet); 210410f514bdSNeil Armstrong ramp_down: 210510f514bdSNeil Armstrong i = 0; 210610f514bdSNeil Armstrong while (x1) { 210710f514bdSNeil Armstrong val = snd_soc_component_read_field(component, WCD939X_ANA_MBHC_RESULT_1, 210810f514bdSNeil Armstrong WCD939X_MBHC_RESULT_1_Z_RESULT_LSB) << 8; 210910f514bdSNeil Armstrong val |= snd_soc_component_read_field(component, WCD939X_ANA_MBHC_RESULT_2, 211010f514bdSNeil Armstrong WCD939X_MBHC_RESULT_2_Z_RESULT_MSB); 211110f514bdSNeil Armstrong x1 = WCD939X_MBHC_GET_X1(val); 211210f514bdSNeil Armstrong i++; 211310f514bdSNeil Armstrong if (i == WCD939X_ZDET_NUM_MEASUREMENTS) 211410f514bdSNeil Armstrong break; 211510f514bdSNeil Armstrong } 211610f514bdSNeil Armstrong } 211710f514bdSNeil Armstrong 211810f514bdSNeil Armstrong static void wcd939x_mbhc_zdet_ramp(struct snd_soc_component *component, 211910f514bdSNeil Armstrong s32 *zl, int32_t *zr) 212010f514bdSNeil Armstrong { 212110f514bdSNeil Armstrong const struct zdet_param *zdet_param = &wcd939x_mbhc_zdet_param; 212210f514bdSNeil Armstrong s32 zdet = 0; 212310f514bdSNeil Armstrong 212410f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_ZDET_ANA_CTL, 212510f514bdSNeil Armstrong WCD939X_ZDET_ANA_CTL_MAXV_CTL, zdet_param->ldo_ctl); 212610f514bdSNeil Armstrong snd_soc_component_update_bits(component, WCD939X_ANA_MBHC_BTN5, WCD939X_MBHC_BTN5_VTH, 212710f514bdSNeil Armstrong zdet_param->btn5); 212810f514bdSNeil Armstrong snd_soc_component_update_bits(component, WCD939X_ANA_MBHC_BTN6, WCD939X_MBHC_BTN6_VTH, 212910f514bdSNeil Armstrong zdet_param->btn6); 213010f514bdSNeil Armstrong snd_soc_component_update_bits(component, WCD939X_ANA_MBHC_BTN7, WCD939X_MBHC_BTN7_VTH, 213110f514bdSNeil Armstrong zdet_param->btn7); 213210f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_ZDET_ANA_CTL, 213310f514bdSNeil Armstrong WCD939X_ZDET_ANA_CTL_RANGE_CTL, zdet_param->noff); 213410f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_ZDET_RAMP_CTL, 213510f514bdSNeil Armstrong WCD939X_ZDET_RAMP_CTL_TIME_CTL, zdet_param->nshift); 213610f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_ZDET_RAMP_CTL, 213710f514bdSNeil Armstrong WCD939X_ZDET_RAMP_CTL_ACC1_MIN_CTL, 6); /*acc1_min_63 */ 213810f514bdSNeil Armstrong 213910f514bdSNeil Armstrong if (!zl) 214010f514bdSNeil Armstrong goto z_right; 214110f514bdSNeil Armstrong 214210f514bdSNeil Armstrong /* Start impedance measurement for HPH_L */ 214310f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET, 214410f514bdSNeil Armstrong WCD939X_MBHC_ZDET_ZDET_L_MEAS_EN, true); 214510f514bdSNeil Armstrong dev_dbg(component->dev, "%s: ramp for HPH_L, noff = %d\n", 214610f514bdSNeil Armstrong __func__, zdet_param->noff); 214710f514bdSNeil Armstrong wcd939x_mbhc_get_result_params(component, &zdet); 214810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET, 214910f514bdSNeil Armstrong WCD939X_MBHC_ZDET_ZDET_L_MEAS_EN, false); 215010f514bdSNeil Armstrong 215110f514bdSNeil Armstrong *zl = zdet; 215210f514bdSNeil Armstrong 215310f514bdSNeil Armstrong z_right: 215410f514bdSNeil Armstrong if (!zr) 215510f514bdSNeil Armstrong return; 215610f514bdSNeil Armstrong 215710f514bdSNeil Armstrong /* Start impedance measurement for HPH_R */ 215810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET, 215910f514bdSNeil Armstrong WCD939X_MBHC_ZDET_ZDET_R_MEAS_EN, true); 216010f514bdSNeil Armstrong dev_dbg(component->dev, "%s: ramp for HPH_R, noff = %d\n", 216110f514bdSNeil Armstrong __func__, zdet_param->noff); 216210f514bdSNeil Armstrong wcd939x_mbhc_get_result_params(component, &zdet); 216310f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ZDET, 216410f514bdSNeil Armstrong WCD939X_MBHC_ZDET_ZDET_R_MEAS_EN, false); 216510f514bdSNeil Armstrong 216610f514bdSNeil Armstrong *zr = zdet; 216710f514bdSNeil Armstrong } 216810f514bdSNeil Armstrong 216910f514bdSNeil Armstrong static void wcd939x_wcd_mbhc_qfuse_cal(struct snd_soc_component *component, 217010f514bdSNeil Armstrong s32 *z_val, int flag_l_r) 217110f514bdSNeil Armstrong { 217210f514bdSNeil Armstrong int q1_cal; 217310f514bdSNeil Armstrong s16 q1; 217410f514bdSNeil Armstrong 217510f514bdSNeil Armstrong q1 = snd_soc_component_read(component, WCD939X_DIGITAL_EFUSE_REG_21 + flag_l_r); 217610f514bdSNeil Armstrong if (q1 & BIT(7)) 217710f514bdSNeil Armstrong q1_cal = (10000 - ((q1 & GENMASK(6, 0)) * 10)); 217810f514bdSNeil Armstrong else 217910f514bdSNeil Armstrong q1_cal = (10000 + (q1 * 10)); 218010f514bdSNeil Armstrong 218110f514bdSNeil Armstrong if (q1_cal > 0) 218210f514bdSNeil Armstrong *z_val = ((*z_val) * 10000) / q1_cal; 218310f514bdSNeil Armstrong } 218410f514bdSNeil Armstrong 218510f514bdSNeil Armstrong static void wcd939x_wcd_mbhc_calc_impedance(struct snd_soc_component *component, 218610f514bdSNeil Armstrong u32 *zl, uint32_t *zr) 218710f514bdSNeil Armstrong { 218810f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = dev_get_drvdata(component->dev); 218910f514bdSNeil Armstrong unsigned int reg0, reg1, reg2, reg3, reg4; 219010f514bdSNeil Armstrong int z_mono, z_diff1, z_diff2; 219110f514bdSNeil Armstrong bool is_fsm_disable = false; 219210f514bdSNeil Armstrong s32 z1l, z1r, z1ls; 219310f514bdSNeil Armstrong 219410f514bdSNeil Armstrong reg0 = snd_soc_component_read(component, WCD939X_ANA_MBHC_BTN5); 219510f514bdSNeil Armstrong reg1 = snd_soc_component_read(component, WCD939X_ANA_MBHC_BTN6); 219610f514bdSNeil Armstrong reg2 = snd_soc_component_read(component, WCD939X_ANA_MBHC_BTN7); 219710f514bdSNeil Armstrong reg3 = snd_soc_component_read(component, WCD939X_MBHC_CTL_CLK); 219810f514bdSNeil Armstrong reg4 = snd_soc_component_read(component, WCD939X_MBHC_NEW_ZDET_ANA_CTL); 219910f514bdSNeil Armstrong 220010f514bdSNeil Armstrong if (snd_soc_component_read_field(component, WCD939X_ANA_MBHC_ELECT, 220110f514bdSNeil Armstrong WCD939X_MBHC_ELECT_FSM_EN)) { 220210f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ELECT, 220310f514bdSNeil Armstrong WCD939X_MBHC_ELECT_FSM_EN, false); 220410f514bdSNeil Armstrong is_fsm_disable = true; 220510f514bdSNeil Armstrong } 220610f514bdSNeil Armstrong 220710f514bdSNeil Armstrong /* For NO-jack, disable L_DET_EN before Z-det measurements */ 220810f514bdSNeil Armstrong if (wcd939x->mbhc_cfg.hphl_swh) 220910f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, 221010f514bdSNeil Armstrong WCD939X_MBHC_MECH_L_DET_EN, false); 221110f514bdSNeil Armstrong 221210f514bdSNeil Armstrong /* Turn off 100k pull down on HPHL */ 221310f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, 221410f514bdSNeil Armstrong WCD939X_MBHC_MECH_SW_HPH_L_P_100K_TO_GND, 221510f514bdSNeil Armstrong false); 221610f514bdSNeil Armstrong 221710f514bdSNeil Armstrong /* 221810f514bdSNeil Armstrong * Disable surge protection before impedance detection. 221910f514bdSNeil Armstrong * This is done to give correct value for high impedance. 222010f514bdSNeil Armstrong */ 222110f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN, 222210f514bdSNeil Armstrong WCD939X_EN_EN_SURGE_PROTECTION_HPHR, false); 222310f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN, 222410f514bdSNeil Armstrong WCD939X_EN_EN_SURGE_PROTECTION_HPHL, false); 222510f514bdSNeil Armstrong 222610f514bdSNeil Armstrong /* 1ms delay needed after disable surge protection */ 222710f514bdSNeil Armstrong usleep_range(1000, 1010); 222810f514bdSNeil Armstrong 222910f514bdSNeil Armstrong /* First get impedance on Left */ 223010f514bdSNeil Armstrong wcd939x_mbhc_zdet_ramp(component, &z1l, NULL); 223110f514bdSNeil Armstrong if (z1l == WCD939X_ZDET_FLOATING_IMPEDANCE || z1l > WCD939X_ZDET_VAL_100K) { 223210f514bdSNeil Armstrong *zl = WCD939X_ZDET_FLOATING_IMPEDANCE; 223310f514bdSNeil Armstrong } else { 223410f514bdSNeil Armstrong *zl = z1l / 1000; 223510f514bdSNeil Armstrong wcd939x_wcd_mbhc_qfuse_cal(component, zl, 0); 223610f514bdSNeil Armstrong } 223710f514bdSNeil Armstrong dev_dbg(component->dev, "%s: impedance on HPH_L = %d(ohms)\n", 223810f514bdSNeil Armstrong __func__, *zl); 223910f514bdSNeil Armstrong 224010f514bdSNeil Armstrong /* Start of right impedance ramp and calculation */ 224110f514bdSNeil Armstrong wcd939x_mbhc_zdet_ramp(component, NULL, &z1r); 224210f514bdSNeil Armstrong if (z1r == WCD939X_ZDET_FLOATING_IMPEDANCE || z1r > WCD939X_ZDET_VAL_100K) { 224310f514bdSNeil Armstrong *zr = WCD939X_ZDET_FLOATING_IMPEDANCE; 224410f514bdSNeil Armstrong } else { 224510f514bdSNeil Armstrong *zr = z1r / 1000; 224610f514bdSNeil Armstrong wcd939x_wcd_mbhc_qfuse_cal(component, zr, 1); 224710f514bdSNeil Armstrong } 224810f514bdSNeil Armstrong dev_dbg(component->dev, "%s: impedance on HPH_R = %d(ohms)\n", 224910f514bdSNeil Armstrong __func__, *zr); 225010f514bdSNeil Armstrong 225110f514bdSNeil Armstrong /* Mono/stereo detection */ 225210f514bdSNeil Armstrong if (*zl == WCD939X_ZDET_FLOATING_IMPEDANCE && 225310f514bdSNeil Armstrong *zr == WCD939X_ZDET_FLOATING_IMPEDANCE) { 225410f514bdSNeil Armstrong dev_dbg(component->dev, 225510f514bdSNeil Armstrong "%s: plug type is invalid or extension cable\n", 225610f514bdSNeil Armstrong __func__); 225710f514bdSNeil Armstrong goto zdet_complete; 225810f514bdSNeil Armstrong } 225910f514bdSNeil Armstrong 226010f514bdSNeil Armstrong if (*zl == WCD939X_ZDET_FLOATING_IMPEDANCE || 226110f514bdSNeil Armstrong *zr == WCD939X_ZDET_FLOATING_IMPEDANCE || 226210f514bdSNeil Armstrong (*zl < WCD_MONO_HS_MIN_THR && *zr > WCD_MONO_HS_MIN_THR) || 226310f514bdSNeil Armstrong (*zl > WCD_MONO_HS_MIN_THR && *zr < WCD_MONO_HS_MIN_THR)) { 226410f514bdSNeil Armstrong dev_dbg(component->dev, 226510f514bdSNeil Armstrong "%s: Mono plug type with one ch floating or shorted to GND\n", 226610f514bdSNeil Armstrong __func__); 226710f514bdSNeil Armstrong wcd_mbhc_set_hph_type(wcd939x->wcd_mbhc, WCD_MBHC_HPH_MONO); 226810f514bdSNeil Armstrong goto zdet_complete; 226910f514bdSNeil Armstrong } 227010f514bdSNeil Armstrong 227110f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_R_ATEST, 227210f514bdSNeil Armstrong WCD939X_R_ATEST_HPH_GND_OVR, true); 227310f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_PA_CTL2, 227410f514bdSNeil Armstrong WCD939X_PA_CTL2_HPHPA_GND_R, true); 227510f514bdSNeil Armstrong wcd939x_mbhc_zdet_ramp(component, &z1ls, NULL); 227610f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_PA_CTL2, 227710f514bdSNeil Armstrong WCD939X_PA_CTL2_HPHPA_GND_R, false); 227810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_R_ATEST, 227910f514bdSNeil Armstrong WCD939X_R_ATEST_HPH_GND_OVR, false); 228010f514bdSNeil Armstrong 228110f514bdSNeil Armstrong z1ls /= 1000; 228210f514bdSNeil Armstrong wcd939x_wcd_mbhc_qfuse_cal(component, &z1ls, 0); 228310f514bdSNeil Armstrong 228410f514bdSNeil Armstrong /* Parallel of left Z and 9 ohm pull down resistor */ 228510f514bdSNeil Armstrong z_mono = (*zl * 9) / (*zl + 9); 228610f514bdSNeil Armstrong z_diff1 = z1ls > z_mono ? z1ls - z_mono : z_mono - z1ls; 228710f514bdSNeil Armstrong z_diff2 = *zl > z1ls ? *zl - z1ls : z1ls - *zl; 228810f514bdSNeil Armstrong if ((z_diff1 * (*zl + z1ls)) > (z_diff2 * (z1ls + z_mono))) { 228910f514bdSNeil Armstrong dev_dbg(component->dev, "%s: stereo plug type detected\n", 229010f514bdSNeil Armstrong __func__); 229110f514bdSNeil Armstrong wcd_mbhc_set_hph_type(wcd939x->wcd_mbhc, WCD_MBHC_HPH_STEREO); 229210f514bdSNeil Armstrong } else { 229310f514bdSNeil Armstrong dev_dbg(component->dev, "%s: MONO plug type detected\n", 229410f514bdSNeil Armstrong __func__); 229510f514bdSNeil Armstrong wcd_mbhc_set_hph_type(wcd939x->wcd_mbhc, WCD_MBHC_HPH_MONO); 229610f514bdSNeil Armstrong } 229710f514bdSNeil Armstrong 229810f514bdSNeil Armstrong /* Enable surge protection again after impedance detection */ 229910f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN, 230010f514bdSNeil Armstrong WCD939X_EN_EN_SURGE_PROTECTION_HPHR, true); 230110f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_SURGE_EN, 230210f514bdSNeil Armstrong WCD939X_EN_EN_SURGE_PROTECTION_HPHL, true); 230310f514bdSNeil Armstrong 230410f514bdSNeil Armstrong zdet_complete: 230510f514bdSNeil Armstrong snd_soc_component_write(component, WCD939X_ANA_MBHC_BTN5, reg0); 230610f514bdSNeil Armstrong snd_soc_component_write(component, WCD939X_ANA_MBHC_BTN6, reg1); 230710f514bdSNeil Armstrong snd_soc_component_write(component, WCD939X_ANA_MBHC_BTN7, reg2); 230810f514bdSNeil Armstrong 230910f514bdSNeil Armstrong /* Turn on 100k pull down on HPHL */ 231010f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, 231110f514bdSNeil Armstrong WCD939X_MBHC_MECH_SW_HPH_L_P_100K_TO_GND, true); 231210f514bdSNeil Armstrong 231310f514bdSNeil Armstrong /* For NO-jack, re-enable L_DET_EN after Z-det measurements */ 231410f514bdSNeil Armstrong if (wcd939x->mbhc_cfg.hphl_swh) 231510f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, 231610f514bdSNeil Armstrong WCD939X_MBHC_MECH_L_DET_EN, true); 231710f514bdSNeil Armstrong 231810f514bdSNeil Armstrong snd_soc_component_write(component, WCD939X_MBHC_NEW_ZDET_ANA_CTL, reg4); 231910f514bdSNeil Armstrong snd_soc_component_write(component, WCD939X_MBHC_CTL_CLK, reg3); 232010f514bdSNeil Armstrong 232110f514bdSNeil Armstrong if (is_fsm_disable) 232210f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_ELECT, 232310f514bdSNeil Armstrong WCD939X_MBHC_ELECT_FSM_EN, true); 232410f514bdSNeil Armstrong } 232510f514bdSNeil Armstrong 232610f514bdSNeil Armstrong static void wcd939x_mbhc_gnd_det_ctrl(struct snd_soc_component *component, 232710f514bdSNeil Armstrong bool enable) 232810f514bdSNeil Armstrong { 232910f514bdSNeil Armstrong if (enable) { 233010f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, 233110f514bdSNeil Armstrong WCD939X_MBHC_MECH_MECH_HS_G_PULLUP_COMP_EN, 233210f514bdSNeil Armstrong true); 233310f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, 233410f514bdSNeil Armstrong WCD939X_MBHC_MECH_GND_DET_EN, true); 233510f514bdSNeil Armstrong } else { 233610f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, 233710f514bdSNeil Armstrong WCD939X_MBHC_MECH_GND_DET_EN, false); 233810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_ANA_MBHC_MECH, 233910f514bdSNeil Armstrong WCD939X_MBHC_MECH_MECH_HS_G_PULLUP_COMP_EN, 234010f514bdSNeil Armstrong false); 234110f514bdSNeil Armstrong } 234210f514bdSNeil Armstrong } 234310f514bdSNeil Armstrong 234410f514bdSNeil Armstrong static void wcd939x_mbhc_hph_pull_down_ctrl(struct snd_soc_component *component, 234510f514bdSNeil Armstrong bool enable) 234610f514bdSNeil Armstrong { 234710f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_PA_CTL2, 234810f514bdSNeil Armstrong WCD939X_PA_CTL2_HPHPA_GND_R, enable); 234910f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_HPH_PA_CTL2, 235010f514bdSNeil Armstrong WCD939X_PA_CTL2_HPHPA_GND_L, enable); 235110f514bdSNeil Armstrong } 235210f514bdSNeil Armstrong 235310f514bdSNeil Armstrong static void wcd939x_mbhc_moisture_config(struct snd_soc_component *component) 235410f514bdSNeil Armstrong { 235510f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 235610f514bdSNeil Armstrong 235710f514bdSNeil Armstrong if (wcd939x->mbhc_cfg.moist_rref == R_OFF || wcd939x->typec_analog_mux) { 235810f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2, 235910f514bdSNeil Armstrong WCD939X_CTL_2_M_RTH_CTL, R_OFF); 236010f514bdSNeil Armstrong return; 236110f514bdSNeil Armstrong } 236210f514bdSNeil Armstrong 236310f514bdSNeil Armstrong /* Do not enable moisture detection if jack type is NC */ 236410f514bdSNeil Armstrong if (!wcd939x->mbhc_cfg.hphl_swh) { 236510f514bdSNeil Armstrong dev_dbg(component->dev, "%s: disable moisture detection for NC\n", 236610f514bdSNeil Armstrong __func__); 236710f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2, 236810f514bdSNeil Armstrong WCD939X_CTL_2_M_RTH_CTL, R_OFF); 236910f514bdSNeil Armstrong return; 237010f514bdSNeil Armstrong } 237110f514bdSNeil Armstrong 237210f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2, 237310f514bdSNeil Armstrong WCD939X_CTL_2_M_RTH_CTL, wcd939x->mbhc_cfg.moist_rref); 237410f514bdSNeil Armstrong } 237510f514bdSNeil Armstrong 237610f514bdSNeil Armstrong static void wcd939x_mbhc_moisture_detect_en(struct snd_soc_component *component, bool enable) 237710f514bdSNeil Armstrong { 237810f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 237910f514bdSNeil Armstrong 238010f514bdSNeil Armstrong if (enable) 238110f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2, 238210f514bdSNeil Armstrong WCD939X_CTL_2_M_RTH_CTL, 238310f514bdSNeil Armstrong wcd939x->mbhc_cfg.moist_rref); 238410f514bdSNeil Armstrong else 238510f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2, 238610f514bdSNeil Armstrong WCD939X_CTL_2_M_RTH_CTL, R_OFF); 238710f514bdSNeil Armstrong } 238810f514bdSNeil Armstrong 238910f514bdSNeil Armstrong static bool wcd939x_mbhc_get_moisture_status(struct snd_soc_component *component) 239010f514bdSNeil Armstrong { 239110f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 239210f514bdSNeil Armstrong bool ret = false; 239310f514bdSNeil Armstrong 239410f514bdSNeil Armstrong if (wcd939x->mbhc_cfg.moist_rref == R_OFF || wcd939x->typec_analog_mux) { 239510f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2, 239610f514bdSNeil Armstrong WCD939X_CTL_2_M_RTH_CTL, R_OFF); 239710f514bdSNeil Armstrong goto done; 239810f514bdSNeil Armstrong } 239910f514bdSNeil Armstrong 240010f514bdSNeil Armstrong /* Do not enable moisture detection if jack type is NC */ 240110f514bdSNeil Armstrong if (!wcd939x->mbhc_cfg.hphl_swh) { 240210f514bdSNeil Armstrong dev_dbg(component->dev, "%s: disable moisture detection for NC\n", 240310f514bdSNeil Armstrong __func__); 240410f514bdSNeil Armstrong snd_soc_component_write_field(component, WCD939X_MBHC_NEW_CTL_2, 240510f514bdSNeil Armstrong WCD939X_CTL_2_M_RTH_CTL, R_OFF); 240610f514bdSNeil Armstrong goto done; 240710f514bdSNeil Armstrong } 240810f514bdSNeil Armstrong 240910f514bdSNeil Armstrong /* 241010f514bdSNeil Armstrong * If moisture_en is already enabled, then skip to plug type 241110f514bdSNeil Armstrong * detection. 241210f514bdSNeil Armstrong */ 241310f514bdSNeil Armstrong if (snd_soc_component_read_field(component, WCD939X_MBHC_NEW_CTL_2, 241410f514bdSNeil Armstrong WCD939X_CTL_2_M_RTH_CTL)) 241510f514bdSNeil Armstrong goto done; 241610f514bdSNeil Armstrong 241710f514bdSNeil Armstrong wcd939x_mbhc_moisture_detect_en(component, true); 241810f514bdSNeil Armstrong 241910f514bdSNeil Armstrong /* Read moisture comparator status, invert of status bit */ 242010f514bdSNeil Armstrong ret = !snd_soc_component_read_field(component, WCD939X_MBHC_NEW_FSM_STATUS, 242110f514bdSNeil Armstrong WCD939X_FSM_STATUS_HS_M_COMP_STATUS); 242210f514bdSNeil Armstrong done: 242310f514bdSNeil Armstrong return ret; 242410f514bdSNeil Armstrong } 242510f514bdSNeil Armstrong 242610f514bdSNeil Armstrong static void wcd939x_mbhc_moisture_polling_ctrl(struct snd_soc_component *component, 242710f514bdSNeil Armstrong bool enable) 242810f514bdSNeil Armstrong { 242910f514bdSNeil Armstrong snd_soc_component_write_field(component, 243010f514bdSNeil Armstrong WCD939X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, 243110f514bdSNeil Armstrong WCD939X_MOISTURE_DET_POLLING_CTRL_MOIST_EN_POLLING, 243210f514bdSNeil Armstrong enable); 243310f514bdSNeil Armstrong } 243410f514bdSNeil Armstrong 243510f514bdSNeil Armstrong static const struct wcd_mbhc_cb mbhc_cb = { 243610f514bdSNeil Armstrong .clk_setup = wcd939x_mbhc_clk_setup, 243710f514bdSNeil Armstrong .mbhc_bias = wcd939x_mbhc_mbhc_bias_control, 243810f514bdSNeil Armstrong .set_btn_thr = wcd939x_mbhc_program_btn_thr, 243910f514bdSNeil Armstrong .micbias_enable_status = wcd939x_mbhc_micb_en_status, 244010f514bdSNeil Armstrong .hph_pull_up_control_v2 = wcd939x_mbhc_hph_l_pull_up_control, 244110f514bdSNeil Armstrong .mbhc_micbias_control = wcd939x_mbhc_request_micbias, 244210f514bdSNeil Armstrong .mbhc_micb_ramp_control = wcd939x_mbhc_micb_ramp_control, 244310f514bdSNeil Armstrong .mbhc_micb_ctrl_thr_mic = wcd939x_mbhc_micb_ctrl_threshold_mic, 244410f514bdSNeil Armstrong .compute_impedance = wcd939x_wcd_mbhc_calc_impedance, 244510f514bdSNeil Armstrong .mbhc_gnd_det_ctrl = wcd939x_mbhc_gnd_det_ctrl, 244610f514bdSNeil Armstrong .hph_pull_down_ctrl = wcd939x_mbhc_hph_pull_down_ctrl, 244710f514bdSNeil Armstrong .mbhc_moisture_config = wcd939x_mbhc_moisture_config, 244810f514bdSNeil Armstrong .mbhc_get_moisture_status = wcd939x_mbhc_get_moisture_status, 244910f514bdSNeil Armstrong .mbhc_moisture_polling_ctrl = wcd939x_mbhc_moisture_polling_ctrl, 245010f514bdSNeil Armstrong .mbhc_moisture_detect_en = wcd939x_mbhc_moisture_detect_en, 245110f514bdSNeil Armstrong }; 245210f514bdSNeil Armstrong 245310f514bdSNeil Armstrong static int wcd939x_get_hph_type(struct snd_kcontrol *kcontrol, 245410f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 245510f514bdSNeil Armstrong { 245610f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 245710f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 245810f514bdSNeil Armstrong 245910f514bdSNeil Armstrong ucontrol->value.integer.value[0] = wcd_mbhc_get_hph_type(wcd939x->wcd_mbhc); 246010f514bdSNeil Armstrong 246110f514bdSNeil Armstrong return 0; 246210f514bdSNeil Armstrong } 246310f514bdSNeil Armstrong 246410f514bdSNeil Armstrong static int wcd939x_hph_impedance_get(struct snd_kcontrol *kcontrol, 246510f514bdSNeil Armstrong struct snd_ctl_elem_value *ucontrol) 246610f514bdSNeil Armstrong { 246710f514bdSNeil Armstrong struct soc_mixer_control *mc = (struct soc_mixer_control *)(kcontrol->private_value); 246810f514bdSNeil Armstrong struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 246910f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 247010f514bdSNeil Armstrong bool hphr = mc->shift; 247110f514bdSNeil Armstrong u32 zl, zr; 247210f514bdSNeil Armstrong 247310f514bdSNeil Armstrong wcd_mbhc_get_impedance(wcd939x->wcd_mbhc, &zl, &zr); 247410f514bdSNeil Armstrong dev_dbg(component->dev, "%s: zl=%u(ohms), zr=%u(ohms)\n", __func__, zl, zr); 247510f514bdSNeil Armstrong ucontrol->value.integer.value[0] = hphr ? zr : zl; 247610f514bdSNeil Armstrong 247710f514bdSNeil Armstrong return 0; 247810f514bdSNeil Armstrong } 247910f514bdSNeil Armstrong 248010f514bdSNeil Armstrong static const struct snd_kcontrol_new hph_type_detect_controls[] = { 248110f514bdSNeil Armstrong SOC_SINGLE_EXT("HPH Type", 0, 0, UINT_MAX, 0, 248210f514bdSNeil Armstrong wcd939x_get_hph_type, NULL), 248310f514bdSNeil Armstrong }; 248410f514bdSNeil Armstrong 248510f514bdSNeil Armstrong static const struct snd_kcontrol_new impedance_detect_controls[] = { 248610f514bdSNeil Armstrong SOC_SINGLE_EXT("HPHL Impedance", 0, 0, UINT_MAX, 0, 248710f514bdSNeil Armstrong wcd939x_hph_impedance_get, NULL), 248810f514bdSNeil Armstrong SOC_SINGLE_EXT("HPHR Impedance", 0, 1, UINT_MAX, 0, 248910f514bdSNeil Armstrong wcd939x_hph_impedance_get, NULL), 249010f514bdSNeil Armstrong }; 249110f514bdSNeil Armstrong 249210f514bdSNeil Armstrong static int wcd939x_mbhc_init(struct snd_soc_component *component) 249310f514bdSNeil Armstrong { 249410f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 249510f514bdSNeil Armstrong struct wcd_mbhc_intr *intr_ids = &wcd939x->intr_ids; 249610f514bdSNeil Armstrong 249710f514bdSNeil Armstrong intr_ids->mbhc_sw_intr = regmap_irq_get_virq(wcd939x->irq_chip, 249810f514bdSNeil Armstrong WCD939X_IRQ_MBHC_SW_DET); 249910f514bdSNeil Armstrong intr_ids->mbhc_btn_press_intr = regmap_irq_get_virq(wcd939x->irq_chip, 250010f514bdSNeil Armstrong WCD939X_IRQ_MBHC_BUTTON_PRESS_DET); 250110f514bdSNeil Armstrong intr_ids->mbhc_btn_release_intr = regmap_irq_get_virq(wcd939x->irq_chip, 250210f514bdSNeil Armstrong WCD939X_IRQ_MBHC_BUTTON_RELEASE_DET); 250310f514bdSNeil Armstrong intr_ids->mbhc_hs_ins_intr = regmap_irq_get_virq(wcd939x->irq_chip, 250410f514bdSNeil Armstrong WCD939X_IRQ_MBHC_ELECT_INS_REM_LEG_DET); 250510f514bdSNeil Armstrong intr_ids->mbhc_hs_rem_intr = regmap_irq_get_virq(wcd939x->irq_chip, 250610f514bdSNeil Armstrong WCD939X_IRQ_MBHC_ELECT_INS_REM_DET); 250710f514bdSNeil Armstrong intr_ids->hph_left_ocp = regmap_irq_get_virq(wcd939x->irq_chip, 250810f514bdSNeil Armstrong WCD939X_IRQ_HPHL_OCP_INT); 250910f514bdSNeil Armstrong intr_ids->hph_right_ocp = regmap_irq_get_virq(wcd939x->irq_chip, 251010f514bdSNeil Armstrong WCD939X_IRQ_HPHR_OCP_INT); 251110f514bdSNeil Armstrong 251210f514bdSNeil Armstrong wcd939x->wcd_mbhc = wcd_mbhc_init(component, &mbhc_cb, intr_ids, wcd_mbhc_fields, true); 251310f514bdSNeil Armstrong if (IS_ERR(wcd939x->wcd_mbhc)) 251410f514bdSNeil Armstrong return PTR_ERR(wcd939x->wcd_mbhc); 251510f514bdSNeil Armstrong 251610f514bdSNeil Armstrong snd_soc_add_component_controls(component, impedance_detect_controls, 251710f514bdSNeil Armstrong ARRAY_SIZE(impedance_detect_controls)); 251810f514bdSNeil Armstrong snd_soc_add_component_controls(component, hph_type_detect_controls, 251910f514bdSNeil Armstrong ARRAY_SIZE(hph_type_detect_controls)); 252010f514bdSNeil Armstrong 252110f514bdSNeil Armstrong return 0; 252210f514bdSNeil Armstrong } 252310f514bdSNeil Armstrong 252410f514bdSNeil Armstrong static void wcd939x_mbhc_deinit(struct snd_soc_component *component) 252510f514bdSNeil Armstrong { 252610f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 252710f514bdSNeil Armstrong 252810f514bdSNeil Armstrong wcd_mbhc_deinit(wcd939x->wcd_mbhc); 252910f514bdSNeil Armstrong } 253010f514bdSNeil Armstrong 253110f514bdSNeil Armstrong /* END MBHC */ 253210f514bdSNeil Armstrong 253310f514bdSNeil Armstrong static const struct snd_kcontrol_new wcd939x_snd_controls[] = { 253410f514bdSNeil Armstrong /* RX Path */ 253510f514bdSNeil Armstrong SOC_SINGLE_EXT("HPHL_COMP Switch", WCD939X_COMP_L, 0, 1, 0, 253610f514bdSNeil Armstrong wcd939x_get_compander, wcd939x_set_compander), 253710f514bdSNeil Armstrong SOC_SINGLE_EXT("HPHR_COMP Switch", WCD939X_COMP_R, 1, 1, 0, 253810f514bdSNeil Armstrong wcd939x_get_compander, wcd939x_set_compander), 253910f514bdSNeil Armstrong SOC_SINGLE_EXT("HPHL Switch", WCD939X_HPH_L, 0, 1, 0, 254010f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 254110f514bdSNeil Armstrong SOC_SINGLE_EXT("HPHR Switch", WCD939X_HPH_R, 0, 1, 0, 254210f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 254310f514bdSNeil Armstrong SOC_SINGLE_EXT("CLSH Switch", WCD939X_CLSH, 0, 1, 0, 254410f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 254510f514bdSNeil Armstrong SOC_SINGLE_EXT("LO Switch", WCD939X_LO, 0, 1, 0, 254610f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 254710f514bdSNeil Armstrong SOC_SINGLE_EXT("DSD_L Switch", WCD939X_DSD_L, 0, 1, 0, 254810f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 254910f514bdSNeil Armstrong SOC_SINGLE_EXT("DSD_R Switch", WCD939X_DSD_R, 0, 1, 0, 255010f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 255110f514bdSNeil Armstrong SOC_SINGLE_TLV("HPHL Volume", WCD939X_HPH_L_EN, 0, 20, 1, line_gain), 255210f514bdSNeil Armstrong SOC_SINGLE_TLV("HPHR Volume", WCD939X_HPH_R_EN, 0, 20, 1, line_gain), 255310f514bdSNeil Armstrong SOC_SINGLE_EXT("LDOH Enable Switch", SND_SOC_NOPM, 0, 1, 0, 255410f514bdSNeil Armstrong wcd939x_ldoh_get, wcd939x_ldoh_put), 255510f514bdSNeil Armstrong 255610f514bdSNeil Armstrong /* TX Path */ 255710f514bdSNeil Armstrong SOC_SINGLE_EXT("ADC1 Switch", WCD939X_ADC1, 1, 1, 0, 255810f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 255910f514bdSNeil Armstrong SOC_SINGLE_EXT("ADC2 Switch", WCD939X_ADC2, 1, 1, 0, 256010f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 256110f514bdSNeil Armstrong SOC_SINGLE_EXT("ADC3 Switch", WCD939X_ADC3, 1, 1, 0, 256210f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 256310f514bdSNeil Armstrong SOC_SINGLE_EXT("ADC4 Switch", WCD939X_ADC4, 1, 1, 0, 256410f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 256510f514bdSNeil Armstrong SOC_SINGLE_EXT("DMIC0 Switch", WCD939X_DMIC0, 1, 1, 0, 256610f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 256710f514bdSNeil Armstrong SOC_SINGLE_EXT("DMIC1 Switch", WCD939X_DMIC1, 1, 1, 0, 256810f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 256910f514bdSNeil Armstrong SOC_SINGLE_EXT("MBHC Switch", WCD939X_MBHC, 1, 1, 0, 257010f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 257110f514bdSNeil Armstrong SOC_SINGLE_EXT("DMIC2 Switch", WCD939X_DMIC2, 1, 1, 0, 257210f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 257310f514bdSNeil Armstrong SOC_SINGLE_EXT("DMIC3 Switch", WCD939X_DMIC3, 1, 1, 0, 257410f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 257510f514bdSNeil Armstrong SOC_SINGLE_EXT("DMIC4 Switch", WCD939X_DMIC4, 1, 1, 0, 257610f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 257710f514bdSNeil Armstrong SOC_SINGLE_EXT("DMIC5 Switch", WCD939X_DMIC5, 1, 1, 0, 257810f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 257910f514bdSNeil Armstrong SOC_SINGLE_EXT("DMIC6 Switch", WCD939X_DMIC6, 1, 1, 0, 258010f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 258110f514bdSNeil Armstrong SOC_SINGLE_EXT("DMIC7 Switch", WCD939X_DMIC7, 1, 1, 0, 258210f514bdSNeil Armstrong wcd939x_get_swr_port, wcd939x_set_swr_port), 258310f514bdSNeil Armstrong SOC_SINGLE_TLV("ADC1 Volume", WCD939X_ANA_TX_CH1, 0, 20, 0, 258410f514bdSNeil Armstrong analog_gain), 258510f514bdSNeil Armstrong SOC_SINGLE_TLV("ADC2 Volume", WCD939X_ANA_TX_CH2, 0, 20, 0, 258610f514bdSNeil Armstrong analog_gain), 258710f514bdSNeil Armstrong SOC_SINGLE_TLV("ADC3 Volume", WCD939X_ANA_TX_CH3, 0, 20, 0, 258810f514bdSNeil Armstrong analog_gain), 258910f514bdSNeil Armstrong SOC_SINGLE_TLV("ADC4 Volume", WCD939X_ANA_TX_CH4, 0, 20, 0, 259010f514bdSNeil Armstrong analog_gain), 259110f514bdSNeil Armstrong }; 259210f514bdSNeil Armstrong 259310f514bdSNeil Armstrong static const struct snd_soc_dapm_widget wcd939x_dapm_widgets[] = { 259410f514bdSNeil Armstrong /*input widgets*/ 259510f514bdSNeil Armstrong SND_SOC_DAPM_INPUT("AMIC1"), 259610f514bdSNeil Armstrong SND_SOC_DAPM_INPUT("AMIC2"), 259710f514bdSNeil Armstrong SND_SOC_DAPM_INPUT("AMIC3"), 259810f514bdSNeil Armstrong SND_SOC_DAPM_INPUT("AMIC4"), 259910f514bdSNeil Armstrong SND_SOC_DAPM_INPUT("AMIC5"), 260010f514bdSNeil Armstrong 260110f514bdSNeil Armstrong SND_SOC_DAPM_MIC("Analog Mic1", NULL), 260210f514bdSNeil Armstrong SND_SOC_DAPM_MIC("Analog Mic2", NULL), 260310f514bdSNeil Armstrong SND_SOC_DAPM_MIC("Analog Mic3", NULL), 260410f514bdSNeil Armstrong SND_SOC_DAPM_MIC("Analog Mic4", NULL), 260510f514bdSNeil Armstrong SND_SOC_DAPM_MIC("Analog Mic5", NULL), 260610f514bdSNeil Armstrong 260710f514bdSNeil Armstrong /* TX widgets */ 260810f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("ADC1", NULL, SND_SOC_NOPM, 0, 0, 260910f514bdSNeil Armstrong wcd939x_codec_enable_adc, 261010f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 261110f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("ADC2", NULL, SND_SOC_NOPM, 1, 0, 261210f514bdSNeil Armstrong wcd939x_codec_enable_adc, 261310f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 261410f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("ADC3", NULL, SND_SOC_NOPM, 2, 0, 261510f514bdSNeil Armstrong wcd939x_codec_enable_adc, 261610f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 261710f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("ADC4", NULL, SND_SOC_NOPM, 3, 0, 261810f514bdSNeil Armstrong wcd939x_codec_enable_adc, 261910f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 262010f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, 262110f514bdSNeil Armstrong wcd939x_codec_enable_dmic, 262210f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 262310f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 1, 0, 262410f514bdSNeil Armstrong wcd939x_codec_enable_dmic, 262510f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 262610f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 2, 0, 262710f514bdSNeil Armstrong wcd939x_codec_enable_dmic, 262810f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 262910f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 3, 0, 263010f514bdSNeil Armstrong wcd939x_codec_enable_dmic, 263110f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 263210f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 4, 0, 263310f514bdSNeil Armstrong wcd939x_codec_enable_dmic, 263410f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 263510f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 5, 0, 263610f514bdSNeil Armstrong wcd939x_codec_enable_dmic, 263710f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 263810f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("DMIC7", NULL, SND_SOC_NOPM, 6, 0, 263910f514bdSNeil Armstrong wcd939x_codec_enable_dmic, 264010f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 264110f514bdSNeil Armstrong SND_SOC_DAPM_ADC_E("DMIC8", NULL, SND_SOC_NOPM, 7, 0, 264210f514bdSNeil Armstrong wcd939x_codec_enable_dmic, 264310f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 264410f514bdSNeil Armstrong 264510f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("ADC1 REQ", SND_SOC_NOPM, 0, 0, NULL, 0, 264610f514bdSNeil Armstrong wcd939x_adc_enable_req, 264710f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 264810f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("ADC2 REQ", SND_SOC_NOPM, 1, 0, NULL, 0, 264910f514bdSNeil Armstrong wcd939x_adc_enable_req, 265010f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 265110f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("ADC3 REQ", SND_SOC_NOPM, 2, 0, NULL, 0, 265210f514bdSNeil Armstrong wcd939x_adc_enable_req, 265310f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 265410f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("ADC4 REQ", SND_SOC_NOPM, 3, 0, NULL, 0, 265510f514bdSNeil Armstrong wcd939x_adc_enable_req, 265610f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 265710f514bdSNeil Armstrong 265810f514bdSNeil Armstrong SND_SOC_DAPM_MUX("ADC1 MUX", SND_SOC_NOPM, 0, 0, &tx_adc1_mux), 265910f514bdSNeil Armstrong SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, &tx_adc2_mux), 266010f514bdSNeil Armstrong SND_SOC_DAPM_MUX("ADC3 MUX", SND_SOC_NOPM, 0, 0, &tx_adc3_mux), 266110f514bdSNeil Armstrong SND_SOC_DAPM_MUX("ADC4 MUX", SND_SOC_NOPM, 0, 0, &tx_adc4_mux), 266210f514bdSNeil Armstrong 266310f514bdSNeil Armstrong /* tx mixers */ 266410f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("ADC1_MIXER", SND_SOC_NOPM, 0, 0, 266510f514bdSNeil Armstrong adc1_switch, ARRAY_SIZE(adc1_switch), wcd939x_tx_swr_ctrl, 266610f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 266710f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("ADC2_MIXER", SND_SOC_NOPM, 0, 0, 266810f514bdSNeil Armstrong adc2_switch, ARRAY_SIZE(adc2_switch), wcd939x_tx_swr_ctrl, 266910f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 267010f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("ADC3_MIXER", SND_SOC_NOPM, 0, 0, 267110f514bdSNeil Armstrong adc3_switch, ARRAY_SIZE(adc3_switch), wcd939x_tx_swr_ctrl, 267210f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 267310f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("ADC4_MIXER", SND_SOC_NOPM, 0, 0, 267410f514bdSNeil Armstrong adc4_switch, ARRAY_SIZE(adc4_switch), wcd939x_tx_swr_ctrl, 267510f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 267610f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, 0, 0, 267710f514bdSNeil Armstrong dmic1_switch, ARRAY_SIZE(dmic1_switch), wcd939x_tx_swr_ctrl, 267810f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 267910f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("DMIC2_MIXER", SND_SOC_NOPM, 0, 0, 268010f514bdSNeil Armstrong dmic2_switch, ARRAY_SIZE(dmic2_switch), wcd939x_tx_swr_ctrl, 268110f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 268210f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("DMIC3_MIXER", SND_SOC_NOPM, 0, 0, 268310f514bdSNeil Armstrong dmic3_switch, ARRAY_SIZE(dmic3_switch), wcd939x_tx_swr_ctrl, 268410f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 268510f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("DMIC4_MIXER", SND_SOC_NOPM, 0, 0, 268610f514bdSNeil Armstrong dmic4_switch, ARRAY_SIZE(dmic4_switch), wcd939x_tx_swr_ctrl, 268710f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 268810f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("DMIC5_MIXER", SND_SOC_NOPM, 0, 0, 268910f514bdSNeil Armstrong dmic5_switch, ARRAY_SIZE(dmic5_switch), wcd939x_tx_swr_ctrl, 269010f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 269110f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("DMIC6_MIXER", SND_SOC_NOPM, 0, 0, 269210f514bdSNeil Armstrong dmic6_switch, ARRAY_SIZE(dmic6_switch), wcd939x_tx_swr_ctrl, 269310f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 269410f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("DMIC7_MIXER", SND_SOC_NOPM, 0, 0, 269510f514bdSNeil Armstrong dmic7_switch, ARRAY_SIZE(dmic7_switch), wcd939x_tx_swr_ctrl, 269610f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 269710f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("DMIC8_MIXER", SND_SOC_NOPM, 0, 0, 269810f514bdSNeil Armstrong dmic8_switch, ARRAY_SIZE(dmic8_switch), wcd939x_tx_swr_ctrl, 269910f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 270010f514bdSNeil Armstrong 270110f514bdSNeil Armstrong /* micbias widgets */ 270210f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0, 270310f514bdSNeil Armstrong wcd939x_codec_enable_micbias, 270410f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 270510f514bdSNeil Armstrong SND_SOC_DAPM_POST_PMD), 270610f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0, 270710f514bdSNeil Armstrong wcd939x_codec_enable_micbias, 270810f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 270910f514bdSNeil Armstrong SND_SOC_DAPM_POST_PMD), 271010f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0, 271110f514bdSNeil Armstrong wcd939x_codec_enable_micbias, 271210f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 271310f514bdSNeil Armstrong SND_SOC_DAPM_POST_PMD), 271410f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY("MIC BIAS4", SND_SOC_NOPM, MIC_BIAS_4, 0, 271510f514bdSNeil Armstrong wcd939x_codec_enable_micbias, 271610f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 271710f514bdSNeil Armstrong SND_SOC_DAPM_POST_PMD), 271810f514bdSNeil Armstrong 271910f514bdSNeil Armstrong /* micbias pull up widgets */ 272010f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY("VA MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0, 272110f514bdSNeil Armstrong wcd939x_codec_enable_micbias_pullup, 272210f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 272310f514bdSNeil Armstrong SND_SOC_DAPM_POST_PMD), 272410f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY("VA MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0, 272510f514bdSNeil Armstrong wcd939x_codec_enable_micbias_pullup, 272610f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 272710f514bdSNeil Armstrong SND_SOC_DAPM_POST_PMD), 272810f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY("VA MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0, 272910f514bdSNeil Armstrong wcd939x_codec_enable_micbias_pullup, 273010f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 273110f514bdSNeil Armstrong SND_SOC_DAPM_POST_PMD), 273210f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY("VA MIC BIAS4", SND_SOC_NOPM, MIC_BIAS_4, 0, 273310f514bdSNeil Armstrong wcd939x_codec_enable_micbias_pullup, 273410f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 273510f514bdSNeil Armstrong SND_SOC_DAPM_POST_PMD), 273610f514bdSNeil Armstrong 273710f514bdSNeil Armstrong /* output widgets tx */ 273810f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("ADC1_OUTPUT"), 273910f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("ADC2_OUTPUT"), 274010f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("ADC3_OUTPUT"), 274110f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("ADC4_OUTPUT"), 274210f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("DMIC1_OUTPUT"), 274310f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("DMIC2_OUTPUT"), 274410f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("DMIC3_OUTPUT"), 274510f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("DMIC4_OUTPUT"), 274610f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("DMIC5_OUTPUT"), 274710f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("DMIC6_OUTPUT"), 274810f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("DMIC7_OUTPUT"), 274910f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("DMIC8_OUTPUT"), 275010f514bdSNeil Armstrong 275110f514bdSNeil Armstrong SND_SOC_DAPM_INPUT("IN1_HPHL"), 275210f514bdSNeil Armstrong SND_SOC_DAPM_INPUT("IN2_HPHR"), 275310f514bdSNeil Armstrong SND_SOC_DAPM_INPUT("IN3_EAR"), 275410f514bdSNeil Armstrong 275510f514bdSNeil Armstrong /* rx widgets */ 275610f514bdSNeil Armstrong SND_SOC_DAPM_PGA_E("EAR PGA", WCD939X_ANA_EAR, 7, 0, NULL, 0, 275710f514bdSNeil Armstrong wcd939x_codec_enable_ear_pa, 275810f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 275910f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), 276010f514bdSNeil Armstrong SND_SOC_DAPM_PGA_E("HPHL PGA", WCD939X_ANA_HPH, 7, 0, NULL, 0, 276110f514bdSNeil Armstrong wcd939x_codec_enable_hphl_pa, 276210f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 276310f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), 276410f514bdSNeil Armstrong SND_SOC_DAPM_PGA_E("HPHR PGA", WCD939X_ANA_HPH, 6, 0, NULL, 0, 276510f514bdSNeil Armstrong wcd939x_codec_enable_hphr_pa, 276610f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 276710f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), 276810f514bdSNeil Armstrong 276910f514bdSNeil Armstrong SND_SOC_DAPM_DAC_E("RDAC1", NULL, SND_SOC_NOPM, 0, 0, 277010f514bdSNeil Armstrong wcd939x_codec_hphl_dac_event, 277110f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 277210f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), 277310f514bdSNeil Armstrong SND_SOC_DAPM_DAC_E("RDAC2", NULL, SND_SOC_NOPM, 0, 0, 277410f514bdSNeil Armstrong wcd939x_codec_hphr_dac_event, 277510f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 277610f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), 277710f514bdSNeil Armstrong SND_SOC_DAPM_DAC_E("RDAC3", NULL, SND_SOC_NOPM, 0, 0, 277810f514bdSNeil Armstrong wcd939x_codec_ear_dac_event, 277910f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 278010f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), 278110f514bdSNeil Armstrong 278210f514bdSNeil Armstrong SND_SOC_DAPM_MUX("RDAC3_MUX", SND_SOC_NOPM, 0, 0, &rx_rdac3_mux), 278310f514bdSNeil Armstrong 278410f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY("VDD_BUCK", SND_SOC_NOPM, 0, 0, NULL, 0), 278510f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY("RXCLK", SND_SOC_NOPM, 0, 0, 278610f514bdSNeil Armstrong wcd939x_codec_enable_rxclk, 278710f514bdSNeil Armstrong SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | 278810f514bdSNeil Armstrong SND_SOC_DAPM_POST_PMD), 278910f514bdSNeil Armstrong 279010f514bdSNeil Armstrong SND_SOC_DAPM_SUPPLY_S("CLS_H_PORT", 1, SND_SOC_NOPM, 0, 0, NULL, 0), 279110f514bdSNeil Armstrong 279210f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("RX1", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0), 279310f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("RX2", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0), 279410f514bdSNeil Armstrong SND_SOC_DAPM_MIXER_E("RX3", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0), 279510f514bdSNeil Armstrong 279610f514bdSNeil Armstrong /* rx mixer widgets */ 279710f514bdSNeil Armstrong SND_SOC_DAPM_MIXER("EAR_RDAC", SND_SOC_NOPM, 0, 0, 279810f514bdSNeil Armstrong ear_rdac_switch, ARRAY_SIZE(ear_rdac_switch)), 279910f514bdSNeil Armstrong SND_SOC_DAPM_MIXER("HPHL_RDAC", SND_SOC_NOPM, 0, 0, 280010f514bdSNeil Armstrong hphl_rdac_switch, ARRAY_SIZE(hphl_rdac_switch)), 280110f514bdSNeil Armstrong SND_SOC_DAPM_MIXER("HPHR_RDAC", SND_SOC_NOPM, 0, 0, 280210f514bdSNeil Armstrong hphr_rdac_switch, ARRAY_SIZE(hphr_rdac_switch)), 280310f514bdSNeil Armstrong 280410f514bdSNeil Armstrong /* output widgets rx */ 280510f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("EAR"), 280610f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("HPHL"), 280710f514bdSNeil Armstrong SND_SOC_DAPM_OUTPUT("HPHR"), 280810f514bdSNeil Armstrong }; 280910f514bdSNeil Armstrong 281010f514bdSNeil Armstrong static const struct snd_soc_dapm_route wcd939x_audio_map[] = { 281110f514bdSNeil Armstrong /* TX Path */ 281210f514bdSNeil Armstrong {"ADC1_OUTPUT", NULL, "ADC1_MIXER"}, 281310f514bdSNeil Armstrong {"ADC1_MIXER", "Switch", "ADC1 REQ"}, 281410f514bdSNeil Armstrong {"ADC1 REQ", NULL, "ADC1"}, 281510f514bdSNeil Armstrong {"ADC1", NULL, "ADC1 MUX"}, 281610f514bdSNeil Armstrong {"ADC1 MUX", "CH1_AMIC1", "AMIC1"}, 281710f514bdSNeil Armstrong {"ADC1 MUX", "CH1_AMIC2", "AMIC2"}, 281810f514bdSNeil Armstrong {"ADC1 MUX", "CH1_AMIC3", "AMIC3"}, 281910f514bdSNeil Armstrong {"ADC1 MUX", "CH1_AMIC4", "AMIC4"}, 282010f514bdSNeil Armstrong {"ADC1 MUX", "CH1_AMIC5", "AMIC5"}, 282110f514bdSNeil Armstrong 282210f514bdSNeil Armstrong {"ADC2_OUTPUT", NULL, "ADC2_MIXER"}, 282310f514bdSNeil Armstrong {"ADC2_MIXER", "Switch", "ADC2 REQ"}, 282410f514bdSNeil Armstrong {"ADC2 REQ", NULL, "ADC2"}, 282510f514bdSNeil Armstrong {"ADC2", NULL, "ADC2 MUX"}, 282610f514bdSNeil Armstrong {"ADC2 MUX", "CH2_AMIC1", "AMIC1"}, 282710f514bdSNeil Armstrong {"ADC2 MUX", "CH2_AMIC2", "AMIC2"}, 282810f514bdSNeil Armstrong {"ADC2 MUX", "CH2_AMIC3", "AMIC3"}, 282910f514bdSNeil Armstrong {"ADC2 MUX", "CH2_AMIC4", "AMIC4"}, 283010f514bdSNeil Armstrong {"ADC2 MUX", "CH2_AMIC5", "AMIC5"}, 283110f514bdSNeil Armstrong 283210f514bdSNeil Armstrong {"ADC3_OUTPUT", NULL, "ADC3_MIXER"}, 283310f514bdSNeil Armstrong {"ADC3_MIXER", "Switch", "ADC3 REQ"}, 283410f514bdSNeil Armstrong {"ADC3 REQ", NULL, "ADC3"}, 283510f514bdSNeil Armstrong {"ADC3", NULL, "ADC3 MUX"}, 283610f514bdSNeil Armstrong {"ADC3 MUX", "CH3_AMIC1", "AMIC1"}, 283710f514bdSNeil Armstrong {"ADC3 MUX", "CH3_AMIC3", "AMIC3"}, 283810f514bdSNeil Armstrong {"ADC3 MUX", "CH3_AMIC4", "AMIC4"}, 283910f514bdSNeil Armstrong {"ADC3 MUX", "CH3_AMIC5", "AMIC5"}, 284010f514bdSNeil Armstrong 284110f514bdSNeil Armstrong {"ADC4_OUTPUT", NULL, "ADC4_MIXER"}, 284210f514bdSNeil Armstrong {"ADC4_MIXER", "Switch", "ADC4 REQ"}, 284310f514bdSNeil Armstrong {"ADC4 REQ", NULL, "ADC4"}, 284410f514bdSNeil Armstrong {"ADC4", NULL, "ADC4 MUX"}, 284510f514bdSNeil Armstrong {"ADC4 MUX", "CH4_AMIC1", "AMIC1"}, 284610f514bdSNeil Armstrong {"ADC4 MUX", "CH4_AMIC3", "AMIC3"}, 284710f514bdSNeil Armstrong {"ADC4 MUX", "CH4_AMIC4", "AMIC4"}, 284810f514bdSNeil Armstrong {"ADC4 MUX", "CH4_AMIC5", "AMIC5"}, 284910f514bdSNeil Armstrong 285010f514bdSNeil Armstrong {"DMIC1_OUTPUT", NULL, "DMIC1_MIXER"}, 285110f514bdSNeil Armstrong {"DMIC1_MIXER", "Switch", "DMIC1"}, 285210f514bdSNeil Armstrong 285310f514bdSNeil Armstrong {"DMIC2_OUTPUT", NULL, "DMIC2_MIXER"}, 285410f514bdSNeil Armstrong {"DMIC2_MIXER", "Switch", "DMIC2"}, 285510f514bdSNeil Armstrong 285610f514bdSNeil Armstrong {"DMIC3_OUTPUT", NULL, "DMIC3_MIXER"}, 285710f514bdSNeil Armstrong {"DMIC3_MIXER", "Switch", "DMIC3"}, 285810f514bdSNeil Armstrong 285910f514bdSNeil Armstrong {"DMIC4_OUTPUT", NULL, "DMIC4_MIXER"}, 286010f514bdSNeil Armstrong {"DMIC4_MIXER", "Switch", "DMIC4"}, 286110f514bdSNeil Armstrong 286210f514bdSNeil Armstrong {"DMIC5_OUTPUT", NULL, "DMIC5_MIXER"}, 286310f514bdSNeil Armstrong {"DMIC5_MIXER", "Switch", "DMIC5"}, 286410f514bdSNeil Armstrong 286510f514bdSNeil Armstrong {"DMIC6_OUTPUT", NULL, "DMIC6_MIXER"}, 286610f514bdSNeil Armstrong {"DMIC6_MIXER", "Switch", "DMIC6"}, 286710f514bdSNeil Armstrong 286810f514bdSNeil Armstrong {"DMIC7_OUTPUT", NULL, "DMIC7_MIXER"}, 286910f514bdSNeil Armstrong {"DMIC7_MIXER", "Switch", "DMIC7"}, 287010f514bdSNeil Armstrong 287110f514bdSNeil Armstrong {"DMIC8_OUTPUT", NULL, "DMIC8_MIXER"}, 287210f514bdSNeil Armstrong {"DMIC8_MIXER", "Switch", "DMIC8"}, 287310f514bdSNeil Armstrong 287410f514bdSNeil Armstrong /* RX Path */ 287510f514bdSNeil Armstrong {"IN1_HPHL", NULL, "VDD_BUCK"}, 287610f514bdSNeil Armstrong {"IN1_HPHL", NULL, "CLS_H_PORT"}, 287710f514bdSNeil Armstrong 287810f514bdSNeil Armstrong {"RX1", NULL, "IN1_HPHL"}, 287910f514bdSNeil Armstrong {"RX1", NULL, "RXCLK"}, 288010f514bdSNeil Armstrong {"RDAC1", NULL, "RX1"}, 288110f514bdSNeil Armstrong {"HPHL_RDAC", "Switch", "RDAC1"}, 288210f514bdSNeil Armstrong {"HPHL PGA", NULL, "HPHL_RDAC"}, 288310f514bdSNeil Armstrong {"HPHL", NULL, "HPHL PGA"}, 288410f514bdSNeil Armstrong 288510f514bdSNeil Armstrong {"IN2_HPHR", NULL, "VDD_BUCK"}, 288610f514bdSNeil Armstrong {"IN2_HPHR", NULL, "CLS_H_PORT"}, 288710f514bdSNeil Armstrong {"RX2", NULL, "IN2_HPHR"}, 288810f514bdSNeil Armstrong {"RDAC2", NULL, "RX2"}, 288910f514bdSNeil Armstrong {"RX2", NULL, "RXCLK"}, 289010f514bdSNeil Armstrong {"HPHR_RDAC", "Switch", "RDAC2"}, 289110f514bdSNeil Armstrong {"HPHR PGA", NULL, "HPHR_RDAC"}, 289210f514bdSNeil Armstrong {"HPHR", NULL, "HPHR PGA"}, 289310f514bdSNeil Armstrong 289410f514bdSNeil Armstrong {"IN3_EAR", NULL, "VDD_BUCK"}, 289510f514bdSNeil Armstrong {"RX3", NULL, "IN3_EAR"}, 289610f514bdSNeil Armstrong {"RX3", NULL, "RXCLK"}, 289710f514bdSNeil Armstrong 289810f514bdSNeil Armstrong {"RDAC3_MUX", "RX3", "RX3"}, 289910f514bdSNeil Armstrong {"RDAC3_MUX", "RX1", "RX1"}, 290010f514bdSNeil Armstrong {"RDAC3", NULL, "RDAC3_MUX"}, 290110f514bdSNeil Armstrong {"EAR_RDAC", "Switch", "RDAC3"}, 290210f514bdSNeil Armstrong {"EAR PGA", NULL, "EAR_RDAC"}, 290310f514bdSNeil Armstrong {"EAR", NULL, "EAR PGA"}, 290410f514bdSNeil Armstrong }; 290510f514bdSNeil Armstrong 290610f514bdSNeil Armstrong static int wcd939x_set_micbias_data(struct wcd939x_priv *wcd939x) 290710f514bdSNeil Armstrong { 290810f514bdSNeil Armstrong int vout_ctl_1, vout_ctl_2, vout_ctl_3, vout_ctl_4; 290910f514bdSNeil Armstrong 291010f514bdSNeil Armstrong /* set micbias voltage */ 291110f514bdSNeil Armstrong vout_ctl_1 = wcd939x_get_micb_vout_ctl_val(wcd939x->micb1_mv); 291210f514bdSNeil Armstrong vout_ctl_2 = wcd939x_get_micb_vout_ctl_val(wcd939x->micb2_mv); 291310f514bdSNeil Armstrong vout_ctl_3 = wcd939x_get_micb_vout_ctl_val(wcd939x->micb3_mv); 291410f514bdSNeil Armstrong vout_ctl_4 = wcd939x_get_micb_vout_ctl_val(wcd939x->micb4_mv); 291510f514bdSNeil Armstrong if (vout_ctl_1 < 0 || vout_ctl_2 < 0 || vout_ctl_3 < 0 || vout_ctl_4 < 0) 291610f514bdSNeil Armstrong return -EINVAL; 291710f514bdSNeil Armstrong 291810f514bdSNeil Armstrong regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB1, 291910f514bdSNeil Armstrong WCD939X_MICB1_VOUT_CTL, vout_ctl_1); 292010f514bdSNeil Armstrong regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB2, 292110f514bdSNeil Armstrong WCD939X_MICB2_VOUT_CTL, vout_ctl_2); 292210f514bdSNeil Armstrong regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB3, 292310f514bdSNeil Armstrong WCD939X_MICB3_VOUT_CTL, vout_ctl_3); 292410f514bdSNeil Armstrong regmap_update_bits(wcd939x->regmap, WCD939X_ANA_MICB4, 292510f514bdSNeil Armstrong WCD939X_MICB4_VOUT_CTL, vout_ctl_4); 292610f514bdSNeil Armstrong 292710f514bdSNeil Armstrong return 0; 292810f514bdSNeil Armstrong } 292910f514bdSNeil Armstrong 293010f514bdSNeil Armstrong static irqreturn_t wcd939x_wd_handle_irq(int irq, void *data) 293110f514bdSNeil Armstrong { 293210f514bdSNeil Armstrong /* 293310f514bdSNeil Armstrong * HPHR/HPHL/EAR Watchdog interrupt threaded handler 293410f514bdSNeil Armstrong * 293510f514bdSNeil Armstrong * Watchdog interrupts are expected to be enabled when switching 293610f514bdSNeil Armstrong * on the HPHL/R and EAR RX PGA in order to make sure the interrupts 293710f514bdSNeil Armstrong * are acked by the regmap_irq handler to allow PDM sync. 293810f514bdSNeil Armstrong * We could leave those interrupts masked but we would not have 293910f514bdSNeil Armstrong * any valid way to enable/disable them without violating irq layers. 294010f514bdSNeil Armstrong * 294110f514bdSNeil Armstrong * The HPHR/HPHL/EAR Watchdog interrupts are handled 294210f514bdSNeil Armstrong * by regmap_irq, so requesting a threaded handler is the 294310f514bdSNeil Armstrong * safest way to be able to ack those interrupts without 294410f514bdSNeil Armstrong * colliding with the regmap_irq setup. 294510f514bdSNeil Armstrong */ 294610f514bdSNeil Armstrong 294710f514bdSNeil Armstrong return IRQ_HANDLED; 294810f514bdSNeil Armstrong } 294910f514bdSNeil Armstrong 295010f514bdSNeil Armstrong /* 295110f514bdSNeil Armstrong * Setup a virtual interrupt domain to hook regmap_irq 295210f514bdSNeil Armstrong * The root domain will have a single interrupt which mapping 295310f514bdSNeil Armstrong * will trigger the regmap_irq handler. 295410f514bdSNeil Armstrong * 295510f514bdSNeil Armstrong * root: 295610f514bdSNeil Armstrong * wcd_irq_chip 295710f514bdSNeil Armstrong * [0] wcd939x_regmap_irq_chip 295810f514bdSNeil Armstrong * [0] MBHC_BUTTON_PRESS_DET 295910f514bdSNeil Armstrong * [1] MBHC_BUTTON_RELEASE_DET 296010f514bdSNeil Armstrong * ... 296110f514bdSNeil Armstrong * [16] HPHR_SURGE_DET_INT 296210f514bdSNeil Armstrong * 296310f514bdSNeil Armstrong * Interrupt trigger: 296410f514bdSNeil Armstrong * soundwire_interrupt_callback() 296510f514bdSNeil Armstrong * \-handle_nested_irq(0) 296610f514bdSNeil Armstrong * \- regmap_irq_thread() 296710f514bdSNeil Armstrong * \- handle_nested_irq(i) 296810f514bdSNeil Armstrong */ 296910f514bdSNeil Armstrong static struct irq_chip wcd_irq_chip = { 297010f514bdSNeil Armstrong .name = "WCD939x", 297110f514bdSNeil Armstrong }; 297210f514bdSNeil Armstrong 297310f514bdSNeil Armstrong static int wcd_irq_chip_map(struct irq_domain *irqd, unsigned int virq, 297410f514bdSNeil Armstrong irq_hw_number_t hw) 297510f514bdSNeil Armstrong { 297610f514bdSNeil Armstrong irq_set_chip_and_handler(virq, &wcd_irq_chip, handle_simple_irq); 297710f514bdSNeil Armstrong irq_set_nested_thread(virq, 1); 297810f514bdSNeil Armstrong irq_set_noprobe(virq); 297910f514bdSNeil Armstrong 298010f514bdSNeil Armstrong return 0; 298110f514bdSNeil Armstrong } 298210f514bdSNeil Armstrong 298310f514bdSNeil Armstrong static const struct irq_domain_ops wcd_domain_ops = { 298410f514bdSNeil Armstrong .map = wcd_irq_chip_map, 298510f514bdSNeil Armstrong }; 298610f514bdSNeil Armstrong 298710f514bdSNeil Armstrong static int wcd939x_irq_init(struct wcd939x_priv *wcd, struct device *dev) 298810f514bdSNeil Armstrong { 298910f514bdSNeil Armstrong wcd->virq = irq_domain_add_linear(NULL, 1, &wcd_domain_ops, NULL); 299010f514bdSNeil Armstrong if (!(wcd->virq)) { 299110f514bdSNeil Armstrong dev_err(dev, "%s: Failed to add IRQ domain\n", __func__); 299210f514bdSNeil Armstrong return -EINVAL; 299310f514bdSNeil Armstrong } 299410f514bdSNeil Armstrong 299510f514bdSNeil Armstrong return devm_regmap_add_irq_chip(dev, wcd->regmap, 299610f514bdSNeil Armstrong irq_create_mapping(wcd->virq, 0), 299710f514bdSNeil Armstrong IRQF_ONESHOT, 0, &wcd939x_regmap_irq_chip, 299810f514bdSNeil Armstrong &wcd->irq_chip); 299910f514bdSNeil Armstrong } 300010f514bdSNeil Armstrong 300110f514bdSNeil Armstrong static int wcd939x_soc_codec_probe(struct snd_soc_component *component) 300210f514bdSNeil Armstrong { 300310f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 300410f514bdSNeil Armstrong struct sdw_slave *tx_sdw_dev = wcd939x->tx_sdw_dev; 300510f514bdSNeil Armstrong struct device *dev = component->dev; 300610f514bdSNeil Armstrong unsigned long time_left; 300710f514bdSNeil Armstrong int ret, i; 300810f514bdSNeil Armstrong 300910f514bdSNeil Armstrong time_left = wait_for_completion_timeout(&tx_sdw_dev->initialization_complete, 301010f514bdSNeil Armstrong msecs_to_jiffies(2000)); 301110f514bdSNeil Armstrong if (!time_left) { 301210f514bdSNeil Armstrong dev_err(dev, "soundwire device init timeout\n"); 301310f514bdSNeil Armstrong return -ETIMEDOUT; 301410f514bdSNeil Armstrong } 301510f514bdSNeil Armstrong 301610f514bdSNeil Armstrong snd_soc_component_init_regmap(component, wcd939x->regmap); 301710f514bdSNeil Armstrong 301810f514bdSNeil Armstrong ret = pm_runtime_resume_and_get(dev); 301910f514bdSNeil Armstrong if (ret < 0) 302010f514bdSNeil Armstrong return ret; 302110f514bdSNeil Armstrong 302210f514bdSNeil Armstrong wcd939x->variant = snd_soc_component_read_field(component, 302310f514bdSNeil Armstrong WCD939X_DIGITAL_EFUSE_REG_0, 302410f514bdSNeil Armstrong WCD939X_EFUSE_REG_0_WCD939X_ID); 302510f514bdSNeil Armstrong 302610f514bdSNeil Armstrong wcd939x->clsh_info = wcd_clsh_ctrl_alloc(component, WCD939X); 302710f514bdSNeil Armstrong if (IS_ERR(wcd939x->clsh_info)) { 302810f514bdSNeil Armstrong pm_runtime_put(dev); 302910f514bdSNeil Armstrong return PTR_ERR(wcd939x->clsh_info); 303010f514bdSNeil Armstrong } 303110f514bdSNeil Armstrong 303210f514bdSNeil Armstrong wcd939x_io_init(component); 303310f514bdSNeil Armstrong 303410f514bdSNeil Armstrong /* Set all interrupts as edge triggered */ 303510f514bdSNeil Armstrong for (i = 0; i < wcd939x_regmap_irq_chip.num_regs; i++) 303610f514bdSNeil Armstrong regmap_write(wcd939x->regmap, 303710f514bdSNeil Armstrong (WCD939X_DIGITAL_INTR_LEVEL_0 + i), 0); 303810f514bdSNeil Armstrong 303910f514bdSNeil Armstrong pm_runtime_put(dev); 304010f514bdSNeil Armstrong 304110f514bdSNeil Armstrong /* Request for watchdog interrupt */ 304210f514bdSNeil Armstrong wcd939x->hphr_pdm_wd_int = regmap_irq_get_virq(wcd939x->irq_chip, 304310f514bdSNeil Armstrong WCD939X_IRQ_HPHR_PDM_WD_INT); 304410f514bdSNeil Armstrong wcd939x->hphl_pdm_wd_int = regmap_irq_get_virq(wcd939x->irq_chip, 304510f514bdSNeil Armstrong WCD939X_IRQ_HPHL_PDM_WD_INT); 304610f514bdSNeil Armstrong wcd939x->ear_pdm_wd_int = regmap_irq_get_virq(wcd939x->irq_chip, 304710f514bdSNeil Armstrong WCD939X_IRQ_EAR_PDM_WD_INT); 304810f514bdSNeil Armstrong 304910f514bdSNeil Armstrong ret = request_threaded_irq(wcd939x->hphr_pdm_wd_int, NULL, wcd939x_wd_handle_irq, 305010f514bdSNeil Armstrong IRQF_ONESHOT | IRQF_TRIGGER_RISING, 305110f514bdSNeil Armstrong "HPHR PDM WD INT", wcd939x); 305210f514bdSNeil Armstrong if (ret) { 305310f514bdSNeil Armstrong dev_err(dev, "Failed to request HPHR WD interrupt (%d)\n", ret); 305410f514bdSNeil Armstrong goto err_free_clsh_ctrl; 305510f514bdSNeil Armstrong } 305610f514bdSNeil Armstrong 305710f514bdSNeil Armstrong ret = request_threaded_irq(wcd939x->hphl_pdm_wd_int, NULL, wcd939x_wd_handle_irq, 305810f514bdSNeil Armstrong IRQF_ONESHOT | IRQF_TRIGGER_RISING, 305910f514bdSNeil Armstrong "HPHL PDM WD INT", wcd939x); 306010f514bdSNeil Armstrong if (ret) { 306110f514bdSNeil Armstrong dev_err(dev, "Failed to request HPHL WD interrupt (%d)\n", ret); 306210f514bdSNeil Armstrong goto err_free_hphr_pdm_wd_int; 306310f514bdSNeil Armstrong } 306410f514bdSNeil Armstrong 306510f514bdSNeil Armstrong ret = request_threaded_irq(wcd939x->ear_pdm_wd_int, NULL, wcd939x_wd_handle_irq, 306610f514bdSNeil Armstrong IRQF_ONESHOT | IRQF_TRIGGER_RISING, 306710f514bdSNeil Armstrong "AUX PDM WD INT", wcd939x); 306810f514bdSNeil Armstrong if (ret) { 306910f514bdSNeil Armstrong dev_err(dev, "Failed to request Aux WD interrupt (%d)\n", ret); 307010f514bdSNeil Armstrong goto err_free_hphl_pdm_wd_int; 307110f514bdSNeil Armstrong } 307210f514bdSNeil Armstrong 307310f514bdSNeil Armstrong /* Disable watchdog interrupt for HPH and AUX */ 307410f514bdSNeil Armstrong disable_irq_nosync(wcd939x->hphr_pdm_wd_int); 307510f514bdSNeil Armstrong disable_irq_nosync(wcd939x->hphl_pdm_wd_int); 307610f514bdSNeil Armstrong disable_irq_nosync(wcd939x->ear_pdm_wd_int); 307710f514bdSNeil Armstrong 307810f514bdSNeil Armstrong switch (wcd939x->variant) { 307910f514bdSNeil Armstrong case WCD9390: 308010f514bdSNeil Armstrong ret = snd_soc_add_component_controls(component, wcd9390_snd_controls, 308110f514bdSNeil Armstrong ARRAY_SIZE(wcd9390_snd_controls)); 308210f514bdSNeil Armstrong if (ret < 0) { 308310f514bdSNeil Armstrong dev_err(component->dev, 308410f514bdSNeil Armstrong "%s: Failed to add snd ctrls for variant: %d\n", 308510f514bdSNeil Armstrong __func__, wcd939x->variant); 308610f514bdSNeil Armstrong goto err_free_ear_pdm_wd_int; 308710f514bdSNeil Armstrong } 308810f514bdSNeil Armstrong break; 308910f514bdSNeil Armstrong case WCD9395: 309010f514bdSNeil Armstrong ret = snd_soc_add_component_controls(component, wcd9395_snd_controls, 309110f514bdSNeil Armstrong ARRAY_SIZE(wcd9395_snd_controls)); 309210f514bdSNeil Armstrong if (ret < 0) { 309310f514bdSNeil Armstrong dev_err(component->dev, 309410f514bdSNeil Armstrong "%s: Failed to add snd ctrls for variant: %d\n", 309510f514bdSNeil Armstrong __func__, wcd939x->variant); 309610f514bdSNeil Armstrong goto err_free_ear_pdm_wd_int; 309710f514bdSNeil Armstrong } 309810f514bdSNeil Armstrong break; 309910f514bdSNeil Armstrong default: 310010f514bdSNeil Armstrong break; 310110f514bdSNeil Armstrong } 310210f514bdSNeil Armstrong 310310f514bdSNeil Armstrong ret = wcd939x_mbhc_init(component); 310410f514bdSNeil Armstrong if (ret) { 310510f514bdSNeil Armstrong dev_err(component->dev, "mbhc initialization failed\n"); 310610f514bdSNeil Armstrong goto err_free_ear_pdm_wd_int; 310710f514bdSNeil Armstrong } 310810f514bdSNeil Armstrong 310910f514bdSNeil Armstrong return 0; 311010f514bdSNeil Armstrong 311110f514bdSNeil Armstrong err_free_ear_pdm_wd_int: 311210f514bdSNeil Armstrong free_irq(wcd939x->ear_pdm_wd_int, wcd939x); 311310f514bdSNeil Armstrong err_free_hphl_pdm_wd_int: 311410f514bdSNeil Armstrong free_irq(wcd939x->hphl_pdm_wd_int, wcd939x); 311510f514bdSNeil Armstrong err_free_hphr_pdm_wd_int: 311610f514bdSNeil Armstrong free_irq(wcd939x->hphr_pdm_wd_int, wcd939x); 311710f514bdSNeil Armstrong err_free_clsh_ctrl: 311810f514bdSNeil Armstrong wcd_clsh_ctrl_free(wcd939x->clsh_info); 311910f514bdSNeil Armstrong 312010f514bdSNeil Armstrong return ret; 312110f514bdSNeil Armstrong } 312210f514bdSNeil Armstrong 312310f514bdSNeil Armstrong static void wcd939x_soc_codec_remove(struct snd_soc_component *component) 312410f514bdSNeil Armstrong { 312510f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 312610f514bdSNeil Armstrong 312710f514bdSNeil Armstrong wcd939x_mbhc_deinit(component); 312810f514bdSNeil Armstrong 312910f514bdSNeil Armstrong free_irq(wcd939x->ear_pdm_wd_int, wcd939x); 313010f514bdSNeil Armstrong free_irq(wcd939x->hphl_pdm_wd_int, wcd939x); 313110f514bdSNeil Armstrong free_irq(wcd939x->hphr_pdm_wd_int, wcd939x); 313210f514bdSNeil Armstrong 313310f514bdSNeil Armstrong wcd_clsh_ctrl_free(wcd939x->clsh_info); 313410f514bdSNeil Armstrong } 313510f514bdSNeil Armstrong 313610f514bdSNeil Armstrong static int wcd939x_codec_set_jack(struct snd_soc_component *comp, 313710f514bdSNeil Armstrong struct snd_soc_jack *jack, void *data) 313810f514bdSNeil Armstrong { 313910f514bdSNeil Armstrong struct wcd939x_priv *wcd = dev_get_drvdata(comp->dev); 314010f514bdSNeil Armstrong 314110f514bdSNeil Armstrong if (jack) 314210f514bdSNeil Armstrong return wcd_mbhc_start(wcd->wcd_mbhc, &wcd->mbhc_cfg, jack); 314310f514bdSNeil Armstrong 314410f514bdSNeil Armstrong wcd_mbhc_stop(wcd->wcd_mbhc); 314510f514bdSNeil Armstrong 314610f514bdSNeil Armstrong return 0; 314710f514bdSNeil Armstrong } 314810f514bdSNeil Armstrong 314910f514bdSNeil Armstrong static const struct snd_soc_component_driver soc_codec_dev_wcd939x = { 315010f514bdSNeil Armstrong .name = "wcd939x_codec", 315110f514bdSNeil Armstrong .probe = wcd939x_soc_codec_probe, 315210f514bdSNeil Armstrong .remove = wcd939x_soc_codec_remove, 315310f514bdSNeil Armstrong .controls = wcd939x_snd_controls, 315410f514bdSNeil Armstrong .num_controls = ARRAY_SIZE(wcd939x_snd_controls), 315510f514bdSNeil Armstrong .dapm_widgets = wcd939x_dapm_widgets, 315610f514bdSNeil Armstrong .num_dapm_widgets = ARRAY_SIZE(wcd939x_dapm_widgets), 315710f514bdSNeil Armstrong .dapm_routes = wcd939x_audio_map, 315810f514bdSNeil Armstrong .num_dapm_routes = ARRAY_SIZE(wcd939x_audio_map), 315910f514bdSNeil Armstrong .set_jack = wcd939x_codec_set_jack, 316010f514bdSNeil Armstrong .endianness = 1, 316110f514bdSNeil Armstrong }; 316210f514bdSNeil Armstrong 316310f514bdSNeil Armstrong #if IS_ENABLED(CONFIG_TYPEC) 316410f514bdSNeil Armstrong /* Get USB-C plug orientation to provide swap event for MBHC */ 316510f514bdSNeil Armstrong static int wcd939x_typec_switch_set(struct typec_switch_dev *sw, 316610f514bdSNeil Armstrong enum typec_orientation orientation) 316710f514bdSNeil Armstrong { 316810f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = typec_switch_get_drvdata(sw); 316910f514bdSNeil Armstrong 317010f514bdSNeil Armstrong wcd939x->typec_orientation = orientation; 317110f514bdSNeil Armstrong 317210f514bdSNeil Armstrong return 0; 317310f514bdSNeil Armstrong } 317410f514bdSNeil Armstrong 317510f514bdSNeil Armstrong static int wcd939x_typec_mux_set(struct typec_mux_dev *mux, 317610f514bdSNeil Armstrong struct typec_mux_state *state) 317710f514bdSNeil Armstrong { 317810f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = typec_mux_get_drvdata(mux); 317910f514bdSNeil Armstrong unsigned int previous_mode = wcd939x->typec_mode; 318010f514bdSNeil Armstrong 318110f514bdSNeil Armstrong if (!wcd939x->wcd_mbhc) 318210f514bdSNeil Armstrong return -EINVAL; 318310f514bdSNeil Armstrong 318410f514bdSNeil Armstrong if (wcd939x->typec_mode != state->mode) { 318510f514bdSNeil Armstrong wcd939x->typec_mode = state->mode; 318610f514bdSNeil Armstrong 318710f514bdSNeil Armstrong if (wcd939x->typec_mode == TYPEC_MODE_AUDIO) 318810f514bdSNeil Armstrong return wcd_mbhc_typec_report_plug(wcd939x->wcd_mbhc); 318910f514bdSNeil Armstrong else if (previous_mode == TYPEC_MODE_AUDIO) 319010f514bdSNeil Armstrong return wcd_mbhc_typec_report_unplug(wcd939x->wcd_mbhc); 319110f514bdSNeil Armstrong } 319210f514bdSNeil Armstrong 319310f514bdSNeil Armstrong return 0; 319410f514bdSNeil Armstrong } 319510f514bdSNeil Armstrong #endif /* CONFIG_TYPEC */ 319610f514bdSNeil Armstrong 319710f514bdSNeil Armstrong static void wcd939x_dt_parse_micbias_info(struct device *dev, struct wcd939x_priv *wcd) 319810f514bdSNeil Armstrong { 319910f514bdSNeil Armstrong struct device_node *np = dev->of_node; 320010f514bdSNeil Armstrong u32 prop_val = 0; 320110f514bdSNeil Armstrong int rc = 0; 320210f514bdSNeil Armstrong 320310f514bdSNeil Armstrong rc = of_property_read_u32(np, "qcom,micbias1-microvolt", &prop_val); 320410f514bdSNeil Armstrong if (!rc) 320510f514bdSNeil Armstrong wcd->micb1_mv = prop_val / 1000; 320610f514bdSNeil Armstrong else 320710f514bdSNeil Armstrong dev_info(dev, "%s: Micbias1 DT property not found\n", __func__); 320810f514bdSNeil Armstrong 320910f514bdSNeil Armstrong rc = of_property_read_u32(np, "qcom,micbias2-microvolt", &prop_val); 321010f514bdSNeil Armstrong if (!rc) 321110f514bdSNeil Armstrong wcd->micb2_mv = prop_val / 1000; 321210f514bdSNeil Armstrong else 321310f514bdSNeil Armstrong dev_info(dev, "%s: Micbias2 DT property not found\n", __func__); 321410f514bdSNeil Armstrong 321510f514bdSNeil Armstrong rc = of_property_read_u32(np, "qcom,micbias3-microvolt", &prop_val); 321610f514bdSNeil Armstrong if (!rc) 321710f514bdSNeil Armstrong wcd->micb3_mv = prop_val / 1000; 321810f514bdSNeil Armstrong else 321910f514bdSNeil Armstrong dev_info(dev, "%s: Micbias3 DT property not found\n", __func__); 322010f514bdSNeil Armstrong 322110f514bdSNeil Armstrong rc = of_property_read_u32(np, "qcom,micbias4-microvolt", &prop_val); 322210f514bdSNeil Armstrong if (!rc) 322310f514bdSNeil Armstrong wcd->micb4_mv = prop_val / 1000; 322410f514bdSNeil Armstrong else 322510f514bdSNeil Armstrong dev_info(dev, "%s: Micbias4 DT property not found\n", __func__); 322610f514bdSNeil Armstrong } 322710f514bdSNeil Armstrong 322810f514bdSNeil Armstrong #if IS_ENABLED(CONFIG_TYPEC) 322910f514bdSNeil Armstrong static bool wcd939x_swap_gnd_mic(struct snd_soc_component *component, bool active) 323010f514bdSNeil Armstrong { 323110f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = snd_soc_component_get_drvdata(component); 323210f514bdSNeil Armstrong 323310f514bdSNeil Armstrong if (!wcd939x->typec_analog_mux || !wcd939x->typec_switch) 323410f514bdSNeil Armstrong return false; 323510f514bdSNeil Armstrong 323610f514bdSNeil Armstrong /* Report inversion via Type Switch of USBSS */ 323710f514bdSNeil Armstrong typec_switch_set(wcd939x->typec_switch, 323810f514bdSNeil Armstrong wcd939x->typec_orientation == TYPEC_ORIENTATION_REVERSE ? 323910f514bdSNeil Armstrong TYPEC_ORIENTATION_NORMAL : TYPEC_ORIENTATION_REVERSE); 324010f514bdSNeil Armstrong 324110f514bdSNeil Armstrong return true; 324210f514bdSNeil Armstrong } 324310f514bdSNeil Armstrong #endif /* CONFIG_TYPEC */ 324410f514bdSNeil Armstrong 324510f514bdSNeil Armstrong static int wcd939x_populate_dt_data(struct wcd939x_priv *wcd939x, struct device *dev) 324610f514bdSNeil Armstrong { 324710f514bdSNeil Armstrong struct wcd_mbhc_config *cfg = &wcd939x->mbhc_cfg; 324810f514bdSNeil Armstrong #if IS_ENABLED(CONFIG_TYPEC) 324910f514bdSNeil Armstrong struct device_node *np; 325010f514bdSNeil Armstrong #endif /* CONFIG_TYPEC */ 325110f514bdSNeil Armstrong int ret; 325210f514bdSNeil Armstrong 325310f514bdSNeil Armstrong wcd939x->reset_gpio = of_get_named_gpio(dev->of_node, "reset-gpios", 0); 325410f514bdSNeil Armstrong if (wcd939x->reset_gpio < 0) 325510f514bdSNeil Armstrong return dev_err_probe(dev, wcd939x->reset_gpio, 325610f514bdSNeil Armstrong "Failed to get reset gpio\n"); 325710f514bdSNeil Armstrong 325810f514bdSNeil Armstrong wcd939x->supplies[0].supply = "vdd-rxtx"; 325910f514bdSNeil Armstrong wcd939x->supplies[1].supply = "vdd-io"; 326010f514bdSNeil Armstrong wcd939x->supplies[2].supply = "vdd-buck"; 326110f514bdSNeil Armstrong wcd939x->supplies[3].supply = "vdd-mic-bias"; 326210f514bdSNeil Armstrong 326310f514bdSNeil Armstrong ret = regulator_bulk_get(dev, WCD939X_MAX_SUPPLY, wcd939x->supplies); 326410f514bdSNeil Armstrong if (ret) 326510f514bdSNeil Armstrong return dev_err_probe(dev, ret, "Failed to get supplies\n"); 326610f514bdSNeil Armstrong 326710f514bdSNeil Armstrong ret = regulator_bulk_enable(WCD939X_MAX_SUPPLY, wcd939x->supplies); 326810f514bdSNeil Armstrong if (ret) { 326910f514bdSNeil Armstrong regulator_bulk_free(WCD939X_MAX_SUPPLY, wcd939x->supplies); 327010f514bdSNeil Armstrong return dev_err_probe(dev, ret, "Failed to enable supplies\n"); 327110f514bdSNeil Armstrong } 327210f514bdSNeil Armstrong 327310f514bdSNeil Armstrong wcd939x_dt_parse_micbias_info(dev, wcd939x); 327410f514bdSNeil Armstrong 327510f514bdSNeil Armstrong cfg->mbhc_micbias = MIC_BIAS_2; 327610f514bdSNeil Armstrong cfg->anc_micbias = MIC_BIAS_2; 327710f514bdSNeil Armstrong cfg->v_hs_max = WCD_MBHC_HS_V_MAX; 327810f514bdSNeil Armstrong cfg->num_btn = WCD939X_MBHC_MAX_BUTTONS; 327910f514bdSNeil Armstrong cfg->micb_mv = wcd939x->micb2_mv; 328010f514bdSNeil Armstrong cfg->linein_th = 5000; 328110f514bdSNeil Armstrong cfg->hs_thr = 1700; 328210f514bdSNeil Armstrong cfg->hph_thr = 50; 328310f514bdSNeil Armstrong 328410f514bdSNeil Armstrong wcd_dt_parse_mbhc_data(dev, cfg); 328510f514bdSNeil Armstrong 328610f514bdSNeil Armstrong #if IS_ENABLED(CONFIG_TYPEC) 328710f514bdSNeil Armstrong /* 328810f514bdSNeil Armstrong * Is node has a port and a valid remote endpoint 328910f514bdSNeil Armstrong * consider HP lines are connected to the USBSS part 329010f514bdSNeil Armstrong */ 329110f514bdSNeil Armstrong np = of_graph_get_remote_node(dev->of_node, 0, 0); 329210f514bdSNeil Armstrong if (np) { 329310f514bdSNeil Armstrong wcd939x->typec_analog_mux = true; 329410f514bdSNeil Armstrong cfg->typec_analog_mux = true; 329510f514bdSNeil Armstrong cfg->swap_gnd_mic = wcd939x_swap_gnd_mic; 329610f514bdSNeil Armstrong } 329710f514bdSNeil Armstrong #endif /* CONFIG_TYPEC */ 329810f514bdSNeil Armstrong 329910f514bdSNeil Armstrong return 0; 330010f514bdSNeil Armstrong } 330110f514bdSNeil Armstrong 330210f514bdSNeil Armstrong static int wcd939x_reset(struct wcd939x_priv *wcd939x) 330310f514bdSNeil Armstrong { 330410f514bdSNeil Armstrong gpio_direction_output(wcd939x->reset_gpio, 0); 330510f514bdSNeil Armstrong /* 20us sleep required after pulling the reset gpio to LOW */ 330610f514bdSNeil Armstrong usleep_range(20, 30); 330710f514bdSNeil Armstrong gpio_set_value(wcd939x->reset_gpio, 1); 330810f514bdSNeil Armstrong /* 20us sleep required after pulling the reset gpio to HIGH */ 330910f514bdSNeil Armstrong usleep_range(20, 30); 331010f514bdSNeil Armstrong 331110f514bdSNeil Armstrong return 0; 331210f514bdSNeil Armstrong } 331310f514bdSNeil Armstrong 331410f514bdSNeil Armstrong static int wcd939x_codec_hw_params(struct snd_pcm_substream *substream, 331510f514bdSNeil Armstrong struct snd_pcm_hw_params *params, 331610f514bdSNeil Armstrong struct snd_soc_dai *dai) 331710f514bdSNeil Armstrong { 331810f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = dev_get_drvdata(dai->dev); 331910f514bdSNeil Armstrong struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[dai->id]; 332010f514bdSNeil Armstrong 332110f514bdSNeil Armstrong return wcd939x_sdw_hw_params(wcd, substream, params, dai); 332210f514bdSNeil Armstrong } 332310f514bdSNeil Armstrong 332410f514bdSNeil Armstrong static int wcd939x_codec_free(struct snd_pcm_substream *substream, 332510f514bdSNeil Armstrong struct snd_soc_dai *dai) 332610f514bdSNeil Armstrong { 332710f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = dev_get_drvdata(dai->dev); 332810f514bdSNeil Armstrong struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[dai->id]; 332910f514bdSNeil Armstrong 333010f514bdSNeil Armstrong return wcd939x_sdw_free(wcd, substream, dai); 333110f514bdSNeil Armstrong } 333210f514bdSNeil Armstrong 333310f514bdSNeil Armstrong static int wcd939x_codec_set_sdw_stream(struct snd_soc_dai *dai, 333410f514bdSNeil Armstrong void *stream, int direction) 333510f514bdSNeil Armstrong { 333610f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = dev_get_drvdata(dai->dev); 333710f514bdSNeil Armstrong struct wcd939x_sdw_priv *wcd = wcd939x->sdw_priv[dai->id]; 333810f514bdSNeil Armstrong 333910f514bdSNeil Armstrong return wcd939x_sdw_set_sdw_stream(wcd, dai, stream, direction); 334010f514bdSNeil Armstrong } 334110f514bdSNeil Armstrong 334210f514bdSNeil Armstrong static const struct snd_soc_dai_ops wcd939x_sdw_dai_ops = { 334310f514bdSNeil Armstrong .hw_params = wcd939x_codec_hw_params, 334410f514bdSNeil Armstrong .hw_free = wcd939x_codec_free, 334510f514bdSNeil Armstrong .set_stream = wcd939x_codec_set_sdw_stream, 334610f514bdSNeil Armstrong }; 334710f514bdSNeil Armstrong 334810f514bdSNeil Armstrong static struct snd_soc_dai_driver wcd939x_dais[] = { 334910f514bdSNeil Armstrong [0] = { 335010f514bdSNeil Armstrong .name = "wcd939x-sdw-rx", 335110f514bdSNeil Armstrong .playback = { 335210f514bdSNeil Armstrong .stream_name = "WCD AIF1 Playback", 335310f514bdSNeil Armstrong .rates = WCD939X_RATES_MASK | WCD939X_FRAC_RATES_MASK, 335410f514bdSNeil Armstrong .formats = WCD939X_FORMATS, 335510f514bdSNeil Armstrong .rate_max = 384000, 335610f514bdSNeil Armstrong .rate_min = 8000, 335710f514bdSNeil Armstrong .channels_min = 1, 335810f514bdSNeil Armstrong .channels_max = 2, 335910f514bdSNeil Armstrong }, 336010f514bdSNeil Armstrong .ops = &wcd939x_sdw_dai_ops, 336110f514bdSNeil Armstrong }, 336210f514bdSNeil Armstrong [1] = { 336310f514bdSNeil Armstrong .name = "wcd939x-sdw-tx", 336410f514bdSNeil Armstrong .capture = { 336510f514bdSNeil Armstrong .stream_name = "WCD AIF1 Capture", 336610f514bdSNeil Armstrong .rates = WCD939X_RATES_MASK | WCD939X_FRAC_RATES_MASK, 336710f514bdSNeil Armstrong .formats = WCD939X_FORMATS, 336810f514bdSNeil Armstrong .rate_min = 8000, 336910f514bdSNeil Armstrong .rate_max = 384000, 337010f514bdSNeil Armstrong .channels_min = 1, 337110f514bdSNeil Armstrong .channels_max = 4, 337210f514bdSNeil Armstrong }, 337310f514bdSNeil Armstrong .ops = &wcd939x_sdw_dai_ops, 337410f514bdSNeil Armstrong }, 337510f514bdSNeil Armstrong }; 337610f514bdSNeil Armstrong 337710f514bdSNeil Armstrong static int wcd939x_bind(struct device *dev) 337810f514bdSNeil Armstrong { 337910f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = dev_get_drvdata(dev); 338010f514bdSNeil Armstrong unsigned int version, id1, status1; 338110f514bdSNeil Armstrong int ret; 338210f514bdSNeil Armstrong 338310f514bdSNeil Armstrong #if IS_ENABLED(CONFIG_TYPEC) 338410f514bdSNeil Armstrong /* 338510f514bdSNeil Armstrong * Get USBSS type-c switch to send gnd/mic swap events 338610f514bdSNeil Armstrong * typec_switch is fetched now to avoid a probe deadlock since 338710f514bdSNeil Armstrong * the USBSS depends on the typec_mux register in wcd939x_probe() 338810f514bdSNeil Armstrong */ 338910f514bdSNeil Armstrong if (wcd939x->typec_analog_mux) { 339010f514bdSNeil Armstrong wcd939x->typec_switch = fwnode_typec_switch_get(dev->fwnode); 339110f514bdSNeil Armstrong if (IS_ERR(wcd939x->typec_switch)) 339210f514bdSNeil Armstrong return dev_err_probe(dev, PTR_ERR(wcd939x->typec_switch), 339310f514bdSNeil Armstrong "failed to acquire orientation-switch\n"); 339410f514bdSNeil Armstrong } 339510f514bdSNeil Armstrong #endif /* CONFIG_TYPEC */ 339610f514bdSNeil Armstrong 339710f514bdSNeil Armstrong ret = component_bind_all(dev, wcd939x); 339810f514bdSNeil Armstrong if (ret) { 339910f514bdSNeil Armstrong dev_err(dev, "%s: Slave bind failed, ret = %d\n", 340010f514bdSNeil Armstrong __func__, ret); 340110f514bdSNeil Armstrong goto err_put_typec_switch; 340210f514bdSNeil Armstrong } 340310f514bdSNeil Armstrong 340410f514bdSNeil Armstrong wcd939x->rxdev = wcd939x_sdw_device_get(wcd939x->rxnode); 340510f514bdSNeil Armstrong if (!wcd939x->rxdev) { 340610f514bdSNeil Armstrong dev_err(dev, "could not find slave with matching of node\n"); 340710f514bdSNeil Armstrong ret = -EINVAL; 340810f514bdSNeil Armstrong goto err_unbind; 340910f514bdSNeil Armstrong } 341010f514bdSNeil Armstrong wcd939x->sdw_priv[AIF1_PB] = dev_get_drvdata(wcd939x->rxdev); 341110f514bdSNeil Armstrong wcd939x->sdw_priv[AIF1_PB]->wcd939x = wcd939x; 341210f514bdSNeil Armstrong 341310f514bdSNeil Armstrong wcd939x->txdev = wcd939x_sdw_device_get(wcd939x->txnode); 341410f514bdSNeil Armstrong if (!wcd939x->txdev) { 341510f514bdSNeil Armstrong dev_err(dev, "could not find txslave with matching of node\n"); 341610f514bdSNeil Armstrong ret = -EINVAL; 341710f514bdSNeil Armstrong goto err_put_rxdev; 341810f514bdSNeil Armstrong } 341910f514bdSNeil Armstrong wcd939x->sdw_priv[AIF1_CAP] = dev_get_drvdata(wcd939x->txdev); 342010f514bdSNeil Armstrong wcd939x->sdw_priv[AIF1_CAP]->wcd939x = wcd939x; 342110f514bdSNeil Armstrong wcd939x->tx_sdw_dev = dev_to_sdw_dev(wcd939x->txdev); 342210f514bdSNeil Armstrong 342310f514bdSNeil Armstrong /* 342410f514bdSNeil Armstrong * As TX is main CSR reg interface, which should not be suspended first. 342510f514bdSNeil Armstrong * explicitly add the dependency link 342610f514bdSNeil Armstrong */ 342710f514bdSNeil Armstrong if (!device_link_add(wcd939x->rxdev, wcd939x->txdev, DL_FLAG_STATELESS | 342810f514bdSNeil Armstrong DL_FLAG_PM_RUNTIME)) { 342910f514bdSNeil Armstrong dev_err(dev, "could not devlink tx and rx\n"); 343010f514bdSNeil Armstrong ret = -EINVAL; 343110f514bdSNeil Armstrong goto err_put_txdev; 343210f514bdSNeil Armstrong } 343310f514bdSNeil Armstrong 343410f514bdSNeil Armstrong if (!device_link_add(dev, wcd939x->txdev, DL_FLAG_STATELESS | 343510f514bdSNeil Armstrong DL_FLAG_PM_RUNTIME)) { 343610f514bdSNeil Armstrong dev_err(dev, "could not devlink wcd and tx\n"); 343710f514bdSNeil Armstrong ret = -EINVAL; 343810f514bdSNeil Armstrong goto err_remove_rxtx_link; 343910f514bdSNeil Armstrong } 344010f514bdSNeil Armstrong 344110f514bdSNeil Armstrong if (!device_link_add(dev, wcd939x->rxdev, DL_FLAG_STATELESS | 344210f514bdSNeil Armstrong DL_FLAG_PM_RUNTIME)) { 344310f514bdSNeil Armstrong dev_err(dev, "could not devlink wcd and rx\n"); 344410f514bdSNeil Armstrong ret = -EINVAL; 344510f514bdSNeil Armstrong goto err_remove_tx_link; 344610f514bdSNeil Armstrong } 344710f514bdSNeil Armstrong 344810f514bdSNeil Armstrong /* Get regmap from TX SoundWire device */ 344910f514bdSNeil Armstrong wcd939x->regmap = wcd939x_swr_get_regmap(wcd939x->sdw_priv[AIF1_CAP]); 345010f514bdSNeil Armstrong if (IS_ERR(wcd939x->regmap)) { 345110f514bdSNeil Armstrong dev_err(dev, "could not get TX device regmap\n"); 345210f514bdSNeil Armstrong ret = PTR_ERR(wcd939x->regmap); 345310f514bdSNeil Armstrong goto err_remove_rx_link; 345410f514bdSNeil Armstrong } 345510f514bdSNeil Armstrong 345610f514bdSNeil Armstrong ret = wcd939x_irq_init(wcd939x, dev); 345710f514bdSNeil Armstrong if (ret) { 345810f514bdSNeil Armstrong dev_err(dev, "%s: IRQ init failed: %d\n", __func__, ret); 345910f514bdSNeil Armstrong goto err_remove_rx_link; 346010f514bdSNeil Armstrong } 346110f514bdSNeil Armstrong 346210f514bdSNeil Armstrong wcd939x->sdw_priv[AIF1_PB]->slave_irq = wcd939x->virq; 346310f514bdSNeil Armstrong wcd939x->sdw_priv[AIF1_CAP]->slave_irq = wcd939x->virq; 346410f514bdSNeil Armstrong 346510f514bdSNeil Armstrong ret = wcd939x_set_micbias_data(wcd939x); 346610f514bdSNeil Armstrong if (ret < 0) { 346710f514bdSNeil Armstrong dev_err(dev, "%s: bad micbias pdata\n", __func__); 346810f514bdSNeil Armstrong goto err_remove_rx_link; 346910f514bdSNeil Armstrong } 347010f514bdSNeil Armstrong 347110f514bdSNeil Armstrong /* Check WCD9395 version */ 347210f514bdSNeil Armstrong regmap_read(wcd939x->regmap, WCD939X_DIGITAL_CHIP_ID1, &id1); 347310f514bdSNeil Armstrong regmap_read(wcd939x->regmap, WCD939X_EAR_STATUS_REG_1, &status1); 347410f514bdSNeil Armstrong 347510f514bdSNeil Armstrong if (id1 == 0) 347610f514bdSNeil Armstrong version = ((status1 & 0x3) ? WCD939X_VERSION_1_1 : WCD939X_VERSION_1_0); 347710f514bdSNeil Armstrong else 347810f514bdSNeil Armstrong version = WCD939X_VERSION_2_0; 347910f514bdSNeil Armstrong 348010f514bdSNeil Armstrong dev_dbg(dev, "wcd939x version: %s\n", version_to_str(version)); 348110f514bdSNeil Armstrong 348210f514bdSNeil Armstrong ret = snd_soc_register_component(dev, &soc_codec_dev_wcd939x, 348310f514bdSNeil Armstrong wcd939x_dais, ARRAY_SIZE(wcd939x_dais)); 348410f514bdSNeil Armstrong if (ret) { 348510f514bdSNeil Armstrong dev_err(dev, "%s: Codec registration failed\n", 348610f514bdSNeil Armstrong __func__); 348710f514bdSNeil Armstrong goto err_remove_rx_link; 348810f514bdSNeil Armstrong } 348910f514bdSNeil Armstrong 349010f514bdSNeil Armstrong return 0; 349110f514bdSNeil Armstrong 349210f514bdSNeil Armstrong err_remove_rx_link: 349310f514bdSNeil Armstrong device_link_remove(dev, wcd939x->rxdev); 349410f514bdSNeil Armstrong err_remove_tx_link: 349510f514bdSNeil Armstrong device_link_remove(dev, wcd939x->txdev); 349610f514bdSNeil Armstrong err_remove_rxtx_link: 349710f514bdSNeil Armstrong device_link_remove(wcd939x->rxdev, wcd939x->txdev); 349810f514bdSNeil Armstrong err_put_txdev: 349910f514bdSNeil Armstrong put_device(wcd939x->txdev); 350010f514bdSNeil Armstrong err_put_rxdev: 350110f514bdSNeil Armstrong put_device(wcd939x->rxdev); 350210f514bdSNeil Armstrong err_unbind: 350310f514bdSNeil Armstrong component_unbind_all(dev, wcd939x); 350410f514bdSNeil Armstrong err_put_typec_switch: 350510f514bdSNeil Armstrong #if IS_ENABLED(CONFIG_TYPEC) 350610f514bdSNeil Armstrong if (wcd939x->typec_analog_mux) 350710f514bdSNeil Armstrong typec_switch_put(wcd939x->typec_switch); 350810f514bdSNeil Armstrong #endif /* CONFIG_TYPEC */ 350910f514bdSNeil Armstrong 351010f514bdSNeil Armstrong return ret; 351110f514bdSNeil Armstrong } 351210f514bdSNeil Armstrong 351310f514bdSNeil Armstrong static void wcd939x_unbind(struct device *dev) 351410f514bdSNeil Armstrong { 351510f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = dev_get_drvdata(dev); 351610f514bdSNeil Armstrong 351710f514bdSNeil Armstrong snd_soc_unregister_component(dev); 351810f514bdSNeil Armstrong device_link_remove(dev, wcd939x->txdev); 351910f514bdSNeil Armstrong device_link_remove(dev, wcd939x->rxdev); 352010f514bdSNeil Armstrong device_link_remove(wcd939x->rxdev, wcd939x->txdev); 352110f514bdSNeil Armstrong put_device(wcd939x->txdev); 352210f514bdSNeil Armstrong put_device(wcd939x->rxdev); 352310f514bdSNeil Armstrong component_unbind_all(dev, wcd939x); 352410f514bdSNeil Armstrong } 352510f514bdSNeil Armstrong 352610f514bdSNeil Armstrong static const struct component_master_ops wcd939x_comp_ops = { 352710f514bdSNeil Armstrong .bind = wcd939x_bind, 352810f514bdSNeil Armstrong .unbind = wcd939x_unbind, 352910f514bdSNeil Armstrong }; 353010f514bdSNeil Armstrong 353110f514bdSNeil Armstrong static int wcd939x_add_slave_components(struct wcd939x_priv *wcd939x, 353210f514bdSNeil Armstrong struct device *dev, 353310f514bdSNeil Armstrong struct component_match **matchptr) 353410f514bdSNeil Armstrong { 353510f514bdSNeil Armstrong struct device_node *np = dev->of_node; 353610f514bdSNeil Armstrong 353710f514bdSNeil Armstrong wcd939x->rxnode = of_parse_phandle(np, "qcom,rx-device", 0); 353810f514bdSNeil Armstrong if (!wcd939x->rxnode) { 353910f514bdSNeil Armstrong dev_err(dev, "%s: Rx-device node not defined\n", __func__); 354010f514bdSNeil Armstrong return -ENODEV; 354110f514bdSNeil Armstrong } 354210f514bdSNeil Armstrong 354310f514bdSNeil Armstrong of_node_get(wcd939x->rxnode); 354410f514bdSNeil Armstrong component_match_add_release(dev, matchptr, component_release_of, 354510f514bdSNeil Armstrong component_compare_of, wcd939x->rxnode); 354610f514bdSNeil Armstrong 354710f514bdSNeil Armstrong wcd939x->txnode = of_parse_phandle(np, "qcom,tx-device", 0); 354810f514bdSNeil Armstrong if (!wcd939x->txnode) { 354910f514bdSNeil Armstrong dev_err(dev, "%s: Tx-device node not defined\n", __func__); 355010f514bdSNeil Armstrong return -ENODEV; 355110f514bdSNeil Armstrong } 355210f514bdSNeil Armstrong of_node_get(wcd939x->txnode); 355310f514bdSNeil Armstrong component_match_add_release(dev, matchptr, component_release_of, 355410f514bdSNeil Armstrong component_compare_of, wcd939x->txnode); 355510f514bdSNeil Armstrong return 0; 355610f514bdSNeil Armstrong } 355710f514bdSNeil Armstrong 355810f514bdSNeil Armstrong static int wcd939x_probe(struct platform_device *pdev) 355910f514bdSNeil Armstrong { 356010f514bdSNeil Armstrong struct component_match *match = NULL; 356110f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = NULL; 356210f514bdSNeil Armstrong struct device *dev = &pdev->dev; 356310f514bdSNeil Armstrong int ret; 356410f514bdSNeil Armstrong 356510f514bdSNeil Armstrong wcd939x = devm_kzalloc(dev, sizeof(struct wcd939x_priv), 356610f514bdSNeil Armstrong GFP_KERNEL); 356710f514bdSNeil Armstrong if (!wcd939x) 356810f514bdSNeil Armstrong return -ENOMEM; 356910f514bdSNeil Armstrong 357010f514bdSNeil Armstrong dev_set_drvdata(dev, wcd939x); 357110f514bdSNeil Armstrong mutex_init(&wcd939x->micb_lock); 357210f514bdSNeil Armstrong 357310f514bdSNeil Armstrong ret = wcd939x_populate_dt_data(wcd939x, dev); 357410f514bdSNeil Armstrong if (ret) { 357510f514bdSNeil Armstrong dev_err(dev, "%s: Fail to obtain platform data\n", __func__); 357610f514bdSNeil Armstrong return -EINVAL; 357710f514bdSNeil Armstrong } 357810f514bdSNeil Armstrong 357910f514bdSNeil Armstrong #if IS_ENABLED(CONFIG_TYPEC) 358010f514bdSNeil Armstrong /* 358110f514bdSNeil Armstrong * Is USBSS is used to mux analog lines, 358210f514bdSNeil Armstrong * register a typec mux/switch to get typec events 358310f514bdSNeil Armstrong */ 358410f514bdSNeil Armstrong if (wcd939x->typec_analog_mux) { 358510f514bdSNeil Armstrong struct typec_mux_desc mux_desc = { 358610f514bdSNeil Armstrong .drvdata = wcd939x, 358710f514bdSNeil Armstrong .fwnode = dev_fwnode(dev), 358810f514bdSNeil Armstrong .set = wcd939x_typec_mux_set, 358910f514bdSNeil Armstrong }; 359010f514bdSNeil Armstrong struct typec_switch_desc sw_desc = { 359110f514bdSNeil Armstrong .drvdata = wcd939x, 359210f514bdSNeil Armstrong .fwnode = dev_fwnode(dev), 359310f514bdSNeil Armstrong .set = wcd939x_typec_switch_set, 359410f514bdSNeil Armstrong }; 359510f514bdSNeil Armstrong 359610f514bdSNeil Armstrong wcd939x->typec_mux = typec_mux_register(dev, &mux_desc); 359710f514bdSNeil Armstrong if (IS_ERR(wcd939x->typec_mux)) { 359810f514bdSNeil Armstrong ret = dev_err_probe(dev, PTR_ERR(wcd939x->typec_mux), 359910f514bdSNeil Armstrong "failed to register typec mux\n"); 360010f514bdSNeil Armstrong goto err_disable_regulators; 360110f514bdSNeil Armstrong } 360210f514bdSNeil Armstrong 360310f514bdSNeil Armstrong wcd939x->typec_sw = typec_switch_register(dev, &sw_desc); 360410f514bdSNeil Armstrong if (IS_ERR(wcd939x->typec_sw)) { 360510f514bdSNeil Armstrong ret = dev_err_probe(dev, PTR_ERR(wcd939x->typec_sw), 360610f514bdSNeil Armstrong "failed to register typec switch\n"); 360710f514bdSNeil Armstrong goto err_unregister_typec_mux; 360810f514bdSNeil Armstrong } 360910f514bdSNeil Armstrong } 361010f514bdSNeil Armstrong #endif /* CONFIG_TYPEC */ 361110f514bdSNeil Armstrong 361210f514bdSNeil Armstrong ret = wcd939x_add_slave_components(wcd939x, dev, &match); 361310f514bdSNeil Armstrong if (ret) 361410f514bdSNeil Armstrong goto err_unregister_typec_switch; 361510f514bdSNeil Armstrong 361610f514bdSNeil Armstrong wcd939x_reset(wcd939x); 361710f514bdSNeil Armstrong 361810f514bdSNeil Armstrong ret = component_master_add_with_match(dev, &wcd939x_comp_ops, match); 361910f514bdSNeil Armstrong if (ret) 362010f514bdSNeil Armstrong goto err_disable_regulators; 362110f514bdSNeil Armstrong 362210f514bdSNeil Armstrong pm_runtime_set_autosuspend_delay(dev, 1000); 362310f514bdSNeil Armstrong pm_runtime_use_autosuspend(dev); 362410f514bdSNeil Armstrong pm_runtime_mark_last_busy(dev); 362510f514bdSNeil Armstrong pm_runtime_set_active(dev); 362610f514bdSNeil Armstrong pm_runtime_enable(dev); 362710f514bdSNeil Armstrong pm_runtime_idle(dev); 362810f514bdSNeil Armstrong 362910f514bdSNeil Armstrong return 0; 363010f514bdSNeil Armstrong 363110f514bdSNeil Armstrong #if IS_ENABLED(CONFIG_TYPEC) 363210f514bdSNeil Armstrong err_unregister_typec_mux: 363310f514bdSNeil Armstrong if (wcd939x->typec_analog_mux) 363410f514bdSNeil Armstrong typec_mux_unregister(wcd939x->typec_mux); 363510f514bdSNeil Armstrong #endif /* CONFIG_TYPEC */ 363610f514bdSNeil Armstrong 363710f514bdSNeil Armstrong err_unregister_typec_switch: 363810f514bdSNeil Armstrong #if IS_ENABLED(CONFIG_TYPEC) 363910f514bdSNeil Armstrong if (wcd939x->typec_analog_mux) 364010f514bdSNeil Armstrong typec_switch_unregister(wcd939x->typec_sw); 364110f514bdSNeil Armstrong #endif /* CONFIG_TYPEC */ 364210f514bdSNeil Armstrong 364310f514bdSNeil Armstrong err_disable_regulators: 364410f514bdSNeil Armstrong regulator_bulk_disable(WCD939X_MAX_SUPPLY, wcd939x->supplies); 364510f514bdSNeil Armstrong regulator_bulk_free(WCD939X_MAX_SUPPLY, wcd939x->supplies); 364610f514bdSNeil Armstrong 364710f514bdSNeil Armstrong return ret; 364810f514bdSNeil Armstrong } 364910f514bdSNeil Armstrong 365010f514bdSNeil Armstrong static void wcd939x_remove(struct platform_device *pdev) 365110f514bdSNeil Armstrong { 365210f514bdSNeil Armstrong struct device *dev = &pdev->dev; 365310f514bdSNeil Armstrong struct wcd939x_priv *wcd939x = dev_get_drvdata(dev); 365410f514bdSNeil Armstrong 365510f514bdSNeil Armstrong component_master_del(dev, &wcd939x_comp_ops); 365610f514bdSNeil Armstrong 365710f514bdSNeil Armstrong pm_runtime_disable(dev); 365810f514bdSNeil Armstrong pm_runtime_set_suspended(dev); 365910f514bdSNeil Armstrong pm_runtime_dont_use_autosuspend(dev); 366010f514bdSNeil Armstrong 366110f514bdSNeil Armstrong regulator_bulk_disable(WCD939X_MAX_SUPPLY, wcd939x->supplies); 366210f514bdSNeil Armstrong regulator_bulk_free(WCD939X_MAX_SUPPLY, wcd939x->supplies); 366310f514bdSNeil Armstrong } 366410f514bdSNeil Armstrong 366510f514bdSNeil Armstrong #if defined(CONFIG_OF) 366610f514bdSNeil Armstrong static const struct of_device_id wcd939x_dt_match[] = { 366710f514bdSNeil Armstrong { .compatible = "qcom,wcd9390-codec" }, 366810f514bdSNeil Armstrong { .compatible = "qcom,wcd9395-codec" }, 366910f514bdSNeil Armstrong {} 367010f514bdSNeil Armstrong }; 367110f514bdSNeil Armstrong MODULE_DEVICE_TABLE(of, wcd939x_dt_match); 367210f514bdSNeil Armstrong #endif 367310f514bdSNeil Armstrong 367410f514bdSNeil Armstrong static struct platform_driver wcd939x_codec_driver = { 367510f514bdSNeil Armstrong .probe = wcd939x_probe, 367610f514bdSNeil Armstrong .remove_new = wcd939x_remove, 367710f514bdSNeil Armstrong .driver = { 367810f514bdSNeil Armstrong .name = "wcd939x_codec", 367910f514bdSNeil Armstrong .of_match_table = of_match_ptr(wcd939x_dt_match), 368010f514bdSNeil Armstrong .suppress_bind_attrs = true, 368110f514bdSNeil Armstrong }, 368210f514bdSNeil Armstrong }; 368310f514bdSNeil Armstrong 368410f514bdSNeil Armstrong module_platform_driver(wcd939x_codec_driver); 368510f514bdSNeil Armstrong MODULE_DESCRIPTION("WCD939X Codec driver"); 368610f514bdSNeil Armstrong MODULE_LICENSE("GPL"); 3687