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