[PATCH v8 0/9] ASoC: codecs: add wcd938x support
This patchset adds support for Qualcomm WCD938X codec.
Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC connected over SoundWire. This device has two SoundWire devices, RX and TX respectively supporting 4 x ADCs, ClassH, Ear, Aux PA, 2xHPH, 7 x TX diff inputs, 8 DMICs and MBHC.
Eventhough this device has two SoundWire devices, only tx device has access to main codec Control/Status Registers!
For codec driver to be functional it would need both tx and rx Soundwire devices to be up and this is taken care by using device component framework and device-links are used to ensure proper pm dependencies. Ex tx does not enter suspend before rx or codec is suspended.
This patchset along with other SoundWire patches on the list have been tested on SM8250 MTP device.
Thanks, srini
Changes since v7: - Fixed errors reported by kernel test robot by moving SoundWire specific bits to sdw driver.
Srinivas Kandagatla (9): ASoC: dt-bindings: wcd938x: add bindings for wcd938x ASoC: codecs: wcd-clsh: add new version support ASoC: codecs: wcd938x: add basic driver ASoC: dt-bindings: wcd938x-sdw: add bindings for wcd938x-sdw ASoC: codecs: wcd938x-sdw: add SoundWire driver ASoC: codecs: wcd938x: add basic controls ASoC: codecs: wcd938x: add playback dapm widgets ASoC: codecs: wcd938x: add capture dapm widgets ASoC: codecs: wcd938x: add audio routing
.../bindings/sound/qcom,wcd938x-sdw.yaml | 70 + .../bindings/sound/qcom,wcd938x.yaml | 146 + sound/soc/codecs/Kconfig | 13 + sound/soc/codecs/Makefile | 4 + sound/soc/codecs/wcd-clsh-v2.c | 348 +- sound/soc/codecs/wcd-clsh-v2.h | 16 + sound/soc/codecs/wcd938x-sdw.c | 315 ++ sound/soc/codecs/wcd938x.c | 3743 +++++++++++++++++ sound/soc/codecs/wcd938x.h | 720 ++++ 9 files changed, 5365 insertions(+), 10 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml create mode 100644 Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml create mode 100644 sound/soc/codecs/wcd938x-sdw.c create mode 100644 sound/soc/codecs/wcd938x.c create mode 100644 sound/soc/codecs/wcd938x.h
Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC connected over SoundWire. This device has two SoundWire device RX and TX respectively, supporting 4 x ADCs, ClassH, Ear, Aux PA, 2xHPH, 7 x TX diff inputs, 8 DMICs, MBHC.
Signed-off-by: Srinivas Kandagatla srinivas.kandagatla@linaro.org Reviewed-by: Rob Herring robh@kernel.org --- .../bindings/sound/qcom,wcd938x.yaml | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml
diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml b/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml new file mode 100644 index 000000000000..cb74ce40c2e6 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,wcd938x.yaml @@ -0,0 +1,146 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/qcom,wcd938x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Bindings for Qualcomm WCD9380/WCD9385 Audio Codec + +maintainers: + - Srinivas Kandagatla srinivas.kandagatla@linaro.org + +description: | + Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC. + It has RX and TX Soundwire slave devices. + +properties: + compatible: + enum: + - qcom,wcd9380-codec + - qcom,wcd9385-codec + + reset-gpios: + description: GPIO spec for reset line to use + maxItems: 1 + + vdd-buck-supply: + description: A reference to the 1.8V buck supply + + vdd-rxtx-supply: + description: A reference to the 1.8V rx supply + + vdd-io-supply: + description: A reference to the 1.8V I/O supply + + qcom,tx-device: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: A reference to Soundwire tx device phandle + + qcom,rx-device: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: A reference to Soundwire rx device phandle + + qcom,micbias1-microvolt: + description: micbias1 voltage + minimum: 1800000 + maximum: 2850000 + + qcom,micbias2-microvolt: + description: micbias2 voltage + minimum: 1800000 + maximum: 2850000 + + qcom,micbias3-microvolt: + description: micbias3 voltage + minimum: 1800000 + maximum: 2850000 + + qcom,micbias4-microvolt: + description: micbias4 voltage + minimum: 1800000 + maximum: 2850000 + + qcom,hphl-jack-type-normally-closed: + description: Indicates that HPHL jack switch type is normally closed + type: boolean + + qcom,ground-jack-type-normally-closed: + description: Indicates that Headset Ground switch type is normally closed + type: boolean + + qcom,mbhc-headset-vthreshold-microvolt: + description: Voltage threshold value for headset detection + minimum: 0 + maximum: 2850000 + + qcom,mbhc-headphone-vthreshold-microvolt: + description: Voltage threshold value for headphone detection + minimum: 0 + maximum: 2850000 + + qcom,mbhc-buttons-vthreshold-microvolt: + description: + Array of 8 Voltage threshold values corresponding to headset + button0 - button7 + minItems: 8 + maxItems: 8 + + '#sound-dai-cells': + const: 1 + +required: + - compatible + - reset-gpios + - qcom,tx-device + - qcom,rx-device + - qcom,micbias1-microvolt + - qcom,micbias2-microvolt + - qcom,micbias3-microvolt + - qcom,micbias4-microvolt + - "#sound-dai-cells" + +additionalProperties: false + +examples: + - | + codec { + compatible = "qcom,wcd9380-codec"; + reset-gpios = <&tlmm 32 0>; + #sound-dai-cells = <1>; + qcom,tx-device = <&wcd938x_tx>; + qcom,rx-device = <&wcd938x_rx>; + qcom,micbias1-microvolt = <1800000>; + qcom,micbias2-microvolt = <1800000>; + qcom,micbias3-microvolt = <1800000>; + qcom,micbias4-microvolt = <1800000>; + qcom,hphl-jack-type-normally-closed; + qcom,ground-jack-type-normally-closed; + qcom,mbhc-buttons-vthreshold-microvolt = <75000 150000 237000 500000 500000 500000 500000 500000>; + qcom,mbhc-headphone-vthreshold-microvolt = <50000>; + }; + + /* ... */ + + soundwire@3210000 { + #address-cells = <2>; + #size-cells = <0>; + reg = <0x03210000 0x2000>; + wcd938x_rx: codec@0,4 { + compatible = "sdw20217010d00"; + reg = <0 4>; + qcom,rx-port-mapping = <1 2 3 4 5>; + }; + }; + + soundwire@3230000 { + #address-cells = <2>; + #size-cells = <0>; + reg = <0x03230000 0x2000>; + wcd938x_tx: codec@0,3 { + compatible = "sdw20217010d00"; + reg = <0 3>; + qcom,tx-port-mapping = <2 3 4 5>; + }; + }; + +...
From WCD937X Class H controller has changed significantly, so add support
to this new version for WCD937X and WCD938X Codecs.
Signed-off-by: Srinivas Kandagatla srinivas.kandagatla@linaro.org --- sound/soc/codecs/wcd-clsh-v2.c | 348 ++++++++++++++++++++++++++++++++- sound/soc/codecs/wcd-clsh-v2.h | 16 ++ 2 files changed, 354 insertions(+), 10 deletions(-)
diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c index 817d8259758c..485d1932391a 100644 --- a/sound/soc/codecs/wcd-clsh-v2.c +++ b/sound/soc/codecs/wcd-clsh-v2.c @@ -88,6 +88,19 @@ struct wcd_clsh_ctrl { #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA 0x50 #define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA 0x30
+#define WCD9XXX_BASE_ADDRESS 0x3000 +#define WCD9XXX_ANA_RX_SUPPLIES (WCD9XXX_BASE_ADDRESS+0x008) +#define WCD9XXX_ANA_HPH (WCD9XXX_BASE_ADDRESS+0x009) +#define WCD9XXX_CLASSH_MODE_2 (WCD9XXX_BASE_ADDRESS+0x098) +#define WCD9XXX_CLASSH_MODE_3 (WCD9XXX_BASE_ADDRESS+0x099) +#define WCD9XXX_FLYBACK_VNEG_CTRL_1 (WCD9XXX_BASE_ADDRESS+0x0A5) +#define WCD9XXX_FLYBACK_VNEG_CTRL_4 (WCD9XXX_BASE_ADDRESS+0x0A8) +#define WCD9XXX_FLYBACK_VNEGDAC_CTRL_2 (WCD9XXX_BASE_ADDRESS+0x0AF) +#define WCD9XXX_RX_BIAS_HPH_LOWPOWER (WCD9XXX_BASE_ADDRESS+0x0BF) +#define WCD9XXX_V3_RX_BIAS_FLYB_BUFF (WCD9XXX_BASE_ADDRESS+0x0C7) +#define WCD9XXX_HPH_PA_CTL1 (WCD9XXX_BASE_ADDRESS+0x0D1) +#define WCD9XXX_HPH_NEW_INT_PA_MISC2 (WCD9XXX_BASE_ADDRESS+0x138) + #define CLSH_REQ_ENABLE true #define CLSH_REQ_DISABLE false #define WCD_USLEEP_RANGE 50 @@ -137,6 +150,20 @@ static inline void wcd_clsh_set_buck_mode(struct snd_soc_component *comp, WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT); }
+static void wcd_clsh_v3_set_buck_mode(struct snd_soc_component *component, + int mode) +{ + if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI || + mode == CLS_AB_HIFI || mode == CLS_AB_LOHIFI) + snd_soc_component_update_bits(component, + WCD9XXX_ANA_RX_SUPPLIES, + 0x08, 0x08); /* set to HIFI */ + else + snd_soc_component_update_bits(component, + WCD9XXX_ANA_RX_SUPPLIES, + 0x08, 0x00); /* set to default */ +} + static inline void wcd_clsh_set_flyback_mode(struct snd_soc_component *comp, int mode) { @@ -170,6 +197,36 @@ static void wcd_clsh_buck_ctrl(struct wcd_clsh_ctrl *ctrl, usleep_range(500, 500 + WCD_USLEEP_RANGE); }
+static void wcd_clsh_v3_buck_ctrl(struct snd_soc_component *component, + struct wcd_clsh_ctrl *ctrl, + int mode, + bool enable) +{ + /* enable/disable buck */ + if ((enable && (++ctrl->buck_users == 1)) || + (!enable && (--ctrl->buck_users == 0))) { + snd_soc_component_update_bits(component, + WCD9XXX_ANA_RX_SUPPLIES, + (1 << 7), (enable << 7)); + /* + * 500us sleep is required after buck enable/disable + * as per HW requirement + */ + usleep_range(500, 510); + if (mode == CLS_H_LOHIFI || mode == CLS_H_ULP || + mode == CLS_H_HIFI || mode == CLS_H_LP) + snd_soc_component_update_bits(component, + WCD9XXX_CLASSH_MODE_3, + 0x02, 0x00); + + snd_soc_component_update_bits(component, + WCD9XXX_CLASSH_MODE_2, + 0xFF, 0x3A); + /* 500usec delay is needed as per HW requirement */ + usleep_range(500, 500 + WCD_USLEEP_RANGE); + } +} + static void wcd_clsh_flyback_ctrl(struct wcd_clsh_ctrl *ctrl, int mode, bool enable) @@ -219,8 +276,7 @@ static void wcd_clsh_set_gain_path(struct wcd_clsh_ctrl *ctrl, int mode) val); }
-static void wcd_clsh_set_hph_mode(struct snd_soc_component *comp, - int mode) +static void wcd_clsh_v2_set_hph_mode(struct snd_soc_component *comp, int mode) { int val = 0, gain = 0, res_val; int ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA; @@ -264,6 +320,48 @@ static void wcd_clsh_set_hph_mode(struct snd_soc_component *comp, ipeak); }
+static void wcd_clsh_v3_set_hph_mode(struct snd_soc_component *component, + int mode) +{ + u8 val; + + switch (mode) { + case CLS_H_NORMAL: + val = 0x00; + break; + case CLS_AB: + case CLS_H_ULP: + val = 0x0C; + break; + case CLS_AB_HIFI: + case CLS_H_HIFI: + val = 0x08; + break; + case CLS_H_LP: + case CLS_H_LOHIFI: + case CLS_AB_LP: + case CLS_AB_LOHIFI: + val = 0x04; + break; + default: + dev_err(component->dev, "%s:Invalid mode %d\n", __func__, mode); + return; + }; + + snd_soc_component_update_bits(component, WCD9XXX_ANA_HPH, 0x0C, val); +} + +void wcd_clsh_set_hph_mode(struct wcd_clsh_ctrl *ctrl, int mode) +{ + struct snd_soc_component *comp = ctrl->comp; + + if (ctrl->codec_version >= WCD937X) + wcd_clsh_v3_set_hph_mode(comp, mode); + else + wcd_clsh_v2_set_hph_mode(comp, mode); + +} + static void wcd_clsh_set_flyback_current(struct snd_soc_component *comp, int mode) { @@ -289,6 +387,130 @@ static void wcd_clsh_set_buck_regulator_mode(struct snd_soc_component *comp, WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H); }
+static void wcd_clsh_v3_set_buck_regulator_mode(struct snd_soc_component *component, + int mode) +{ + snd_soc_component_update_bits(component, WCD9XXX_ANA_RX_SUPPLIES, + 0x02, 0x00); +} + +static void wcd_clsh_v3_set_flyback_mode(struct snd_soc_component *component, + int mode) +{ + if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI || + mode == CLS_AB_HIFI || mode == CLS_AB_LOHIFI) { + snd_soc_component_update_bits(component, + WCD9XXX_ANA_RX_SUPPLIES, + 0x04, 0x04); + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_VNEG_CTRL_4, + 0xF0, 0x80); + } else { + snd_soc_component_update_bits(component, + WCD9XXX_ANA_RX_SUPPLIES, + 0x04, 0x00); /* set to Default */ + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_VNEG_CTRL_4, + 0xF0, 0x70); + } +} + +static void wcd_clsh_v3_force_iq_ctl(struct snd_soc_component *component, + int mode, bool enable) +{ + if (enable) { + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_VNEGDAC_CTRL_2, + 0xE0, 0xA0); + /* 100usec delay is needed as per HW requirement */ + usleep_range(100, 110); + snd_soc_component_update_bits(component, + WCD9XXX_CLASSH_MODE_3, + 0x02, 0x02); + snd_soc_component_update_bits(component, + WCD9XXX_CLASSH_MODE_2, + 0xFF, 0x1C); + if (mode == CLS_H_LOHIFI || mode == CLS_AB_LOHIFI) { + snd_soc_component_update_bits(component, + WCD9XXX_HPH_NEW_INT_PA_MISC2, + 0x20, 0x20); + snd_soc_component_update_bits(component, + WCD9XXX_RX_BIAS_HPH_LOWPOWER, + 0xF0, 0xC0); + snd_soc_component_update_bits(component, + WCD9XXX_HPH_PA_CTL1, + 0x0E, 0x02); + } + } else { + snd_soc_component_update_bits(component, + WCD9XXX_HPH_NEW_INT_PA_MISC2, + 0x20, 0x00); + snd_soc_component_update_bits(component, + WCD9XXX_RX_BIAS_HPH_LOWPOWER, + 0xF0, 0x80); + snd_soc_component_update_bits(component, + WCD9XXX_HPH_PA_CTL1, + 0x0E, 0x06); + } +} + +static void wcd_clsh_v3_flyback_ctrl(struct snd_soc_component *component, + struct wcd_clsh_ctrl *ctrl, + int mode, + bool enable) +{ + /* enable/disable flyback */ + if ((enable && (++ctrl->flyback_users == 1)) || + (!enable && (--ctrl->flyback_users == 0))) { + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_VNEG_CTRL_1, + 0xE0, 0xE0); + snd_soc_component_update_bits(component, + WCD9XXX_ANA_RX_SUPPLIES, + (1 << 6), (enable << 6)); + /* + * 100us sleep is required after flyback enable/disable + * as per HW requirement + */ + usleep_range(100, 110); + snd_soc_component_update_bits(component, + WCD9XXX_FLYBACK_VNEGDAC_CTRL_2, + 0xE0, 0xE0); + /* 500usec delay is needed as per HW requirement */ + usleep_range(500, 500 + WCD_USLEEP_RANGE); + } +} + +static void wcd_clsh_v3_set_flyback_current(struct snd_soc_component *component, + int mode) +{ + snd_soc_component_update_bits(component, WCD9XXX_V3_RX_BIAS_FLYB_BUFF, + 0x0F, 0x0A); + snd_soc_component_update_bits(component, WCD9XXX_V3_RX_BIAS_FLYB_BUFF, + 0xF0, 0xA0); + /* Sleep needed to avoid click and pop as per HW requirement */ + usleep_range(100, 110); +} + +static void wcd_clsh_v3_state_aux(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *component = ctrl->comp; + + if (is_enable) { + wcd_clsh_v3_set_buck_mode(component, mode); + wcd_clsh_v3_set_flyback_mode(component, mode); + wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, true); + wcd_clsh_v3_set_flyback_current(component, mode); + wcd_clsh_v3_buck_ctrl(component, ctrl, mode, true); + } else { + wcd_clsh_v3_buck_ctrl(component, ctrl, mode, false); + wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, false); + wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL); + wcd_clsh_v3_set_buck_mode(component, CLS_H_NORMAL); + } +} + static void wcd_clsh_state_lo(struct wcd_clsh_ctrl *ctrl, int req_state, bool is_enable, int mode) { @@ -316,6 +538,38 @@ static void wcd_clsh_state_lo(struct wcd_clsh_ctrl *ctrl, int req_state, } }
+static void wcd_clsh_v3_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *component = ctrl->comp; + + if (mode == CLS_H_NORMAL) { + dev_dbg(component->dev, "%s: Normal mode not applicable for hph_r\n", + __func__); + return; + } + + if (is_enable) { + wcd_clsh_v3_set_buck_regulator_mode(component, mode); + wcd_clsh_v3_set_flyback_mode(component, mode); + wcd_clsh_v3_force_iq_ctl(component, mode, true); + wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, true); + wcd_clsh_v3_set_flyback_current(component, mode); + wcd_clsh_v3_set_buck_mode(component, mode); + wcd_clsh_v3_buck_ctrl(component, ctrl, mode, true); + wcd_clsh_v3_set_hph_mode(component, mode); + } else { + wcd_clsh_v3_set_hph_mode(component, CLS_H_NORMAL); + + /* buck and flyback set to default mode and disable */ + wcd_clsh_v3_flyback_ctrl(component, ctrl, CLS_H_NORMAL, false); + wcd_clsh_v3_buck_ctrl(component, ctrl, CLS_H_NORMAL, false); + wcd_clsh_v3_force_iq_ctl(component, CLS_H_NORMAL, false); + wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL); + wcd_clsh_v3_set_buck_mode(component, CLS_H_NORMAL); + } +} + static void wcd_clsh_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state, bool is_enable, int mode) { @@ -353,10 +607,10 @@ static void wcd_clsh_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state, wcd_clsh_set_flyback_current(comp, mode); wcd_clsh_set_buck_mode(comp, mode); wcd_clsh_buck_ctrl(ctrl, mode, true); - wcd_clsh_set_hph_mode(comp, mode); + wcd_clsh_v2_set_hph_mode(comp, mode); wcd_clsh_set_gain_path(ctrl, mode); } else { - wcd_clsh_set_hph_mode(comp, CLS_H_NORMAL); + wcd_clsh_v2_set_hph_mode(comp, CLS_H_NORMAL);
if (mode != CLS_AB) { snd_soc_component_update_bits(comp, @@ -374,6 +628,38 @@ static void wcd_clsh_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state, } }
+static void wcd_clsh_v3_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *component = ctrl->comp; + + if (mode == CLS_H_NORMAL) { + dev_dbg(component->dev, "%s: Normal mode not applicable for hph_l\n", + __func__); + return; + } + + if (is_enable) { + wcd_clsh_v3_set_buck_regulator_mode(component, mode); + wcd_clsh_v3_set_flyback_mode(component, mode); + wcd_clsh_v3_force_iq_ctl(component, mode, true); + wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, true); + wcd_clsh_v3_set_flyback_current(component, mode); + wcd_clsh_v3_set_buck_mode(component, mode); + wcd_clsh_v3_buck_ctrl(component, ctrl, mode, true); + wcd_clsh_v3_set_hph_mode(component, mode); + } else { + wcd_clsh_v3_set_hph_mode(component, CLS_H_NORMAL); + + /* set buck and flyback to Default Mode */ + wcd_clsh_v3_flyback_ctrl(component, ctrl, CLS_H_NORMAL, false); + wcd_clsh_v3_buck_ctrl(component, ctrl, CLS_H_NORMAL, false); + wcd_clsh_v3_force_iq_ctl(component, CLS_H_NORMAL, false); + wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL); + wcd_clsh_v3_set_buck_mode(component, CLS_H_NORMAL); + } +} + static void wcd_clsh_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state, bool is_enable, int mode) { @@ -411,10 +697,10 @@ static void wcd_clsh_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state, wcd_clsh_set_flyback_current(comp, mode); wcd_clsh_set_buck_mode(comp, mode); wcd_clsh_buck_ctrl(ctrl, mode, true); - wcd_clsh_set_hph_mode(comp, mode); + wcd_clsh_v2_set_hph_mode(comp, mode); wcd_clsh_set_gain_path(ctrl, mode); } else { - wcd_clsh_set_hph_mode(comp, CLS_H_NORMAL); + wcd_clsh_v2_set_hph_mode(comp, CLS_H_NORMAL);
if (mode != CLS_AB) { snd_soc_component_update_bits(comp, @@ -432,6 +718,32 @@ static void wcd_clsh_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state, } }
+static void wcd_clsh_v3_state_ear(struct wcd_clsh_ctrl *ctrl, int req_state, + bool is_enable, int mode) +{ + struct snd_soc_component *component = ctrl->comp; + + if (is_enable) { + wcd_clsh_v3_set_buck_regulator_mode(component, mode); + wcd_clsh_v3_set_flyback_mode(component, mode); + wcd_clsh_v3_force_iq_ctl(component, mode, true); + wcd_clsh_v3_flyback_ctrl(component, ctrl, mode, true); + wcd_clsh_v3_set_flyback_current(component, mode); + wcd_clsh_v3_set_buck_mode(component, mode); + wcd_clsh_v3_buck_ctrl(component, ctrl, mode, true); + wcd_clsh_v3_set_hph_mode(component, mode); + } else { + wcd_clsh_v3_set_hph_mode(component, CLS_H_NORMAL); + + /* set buck and flyback to Default Mode */ + wcd_clsh_v3_flyback_ctrl(component, ctrl, CLS_H_NORMAL, false); + wcd_clsh_v3_buck_ctrl(component, ctrl, CLS_H_NORMAL, false); + wcd_clsh_v3_force_iq_ctl(component, CLS_H_NORMAL, false); + wcd_clsh_v3_set_flyback_mode(component, CLS_H_NORMAL); + wcd_clsh_v3_set_buck_mode(component, CLS_H_NORMAL); + } +} + static void wcd_clsh_state_ear(struct wcd_clsh_ctrl *ctrl, int req_state, bool is_enable, int mode) { @@ -472,16 +784,30 @@ static int _wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, int req_state, { switch (req_state) { case WCD_CLSH_STATE_EAR: - wcd_clsh_state_ear(ctrl, req_state, is_enable, mode); + if (ctrl->codec_version >= WCD937X) + wcd_clsh_v3_state_ear(ctrl, req_state, is_enable, mode); + else + wcd_clsh_state_ear(ctrl, req_state, is_enable, mode); break; case WCD_CLSH_STATE_HPHL: - wcd_clsh_state_hph_l(ctrl, req_state, is_enable, mode); + if (ctrl->codec_version >= WCD937X) + wcd_clsh_v3_state_hph_l(ctrl, req_state, is_enable, mode); + else + wcd_clsh_state_hph_l(ctrl, req_state, is_enable, mode); break; case WCD_CLSH_STATE_HPHR: - wcd_clsh_state_hph_r(ctrl, req_state, is_enable, mode); + if (ctrl->codec_version >= WCD937X) + wcd_clsh_v3_state_hph_r(ctrl, req_state, is_enable, mode); + else + wcd_clsh_state_hph_r(ctrl, req_state, is_enable, mode); break; case WCD_CLSH_STATE_LO: - wcd_clsh_state_lo(ctrl, req_state, is_enable, mode); + if (ctrl->codec_version < WCD937X) + wcd_clsh_state_lo(ctrl, req_state, is_enable, mode); + break; + case WCD_CLSH_STATE_AUX: + if (ctrl->codec_version >= WCD937X) + wcd_clsh_v3_state_aux(ctrl, req_state, is_enable, mode); break; default: break; @@ -504,6 +830,7 @@ static bool wcd_clsh_is_state_valid(int state) case WCD_CLSH_STATE_HPHL: case WCD_CLSH_STATE_HPHR: case WCD_CLSH_STATE_LO: + case WCD_CLSH_STATE_AUX: return true; default: return false; @@ -565,6 +892,7 @@ struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc(struct snd_soc_component *comp,
ctrl->state = WCD_CLSH_STATE_IDLE; ctrl->comp = comp; + ctrl->codec_version = version;
return ctrl; } diff --git a/sound/soc/codecs/wcd-clsh-v2.h b/sound/soc/codecs/wcd-clsh-v2.h index a6d0f2d0e9e3..4e3653058275 100644 --- a/sound/soc/codecs/wcd-clsh-v2.h +++ b/sound/soc/codecs/wcd-clsh-v2.h @@ -22,8 +22,11 @@ enum wcd_clsh_event { #define WCD_CLSH_STATE_HPHL BIT(1) #define WCD_CLSH_STATE_HPHR BIT(2) #define WCD_CLSH_STATE_LO BIT(3) +#define WCD_CLSH_STATE_AUX BIT(4) #define WCD_CLSH_STATE_MAX 4 +#define WCD_CLSH_V3_STATE_MAX 5 #define NUM_CLSH_STATES_V2 BIT(WCD_CLSH_STATE_MAX) +#define NUM_CLSH_STATES_V3 BIT(WCD_CLSH_V3_STATE_MAX)
enum wcd_clsh_mode { CLS_H_NORMAL = 0, /* Class-H Default */ @@ -31,9 +34,20 @@ enum wcd_clsh_mode { CLS_H_LP, /* Class-H Low Power */ CLS_AB, /* Class-AB */ CLS_H_LOHIFI, /* LoHIFI */ + CLS_H_ULP, /* Ultra Low power */ + CLS_AB_HIFI, /* Class-AB */ + CLS_AB_LP, /* Class-AB Low Power */ + CLS_AB_LOHIFI, /* Class-AB Low HIFI */ CLS_NONE, /* None of the above modes */ };
+enum wcd_codec_version { + WCD9335 = 0, + WCD934X = 1, + /* New CLSH after this */ + WCD937X = 2, + WCD938X = 3, +}; struct wcd_clsh_ctrl;
extern struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc( @@ -45,5 +59,7 @@ extern int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, enum wcd_clsh_event clsh_event, int nstate, enum wcd_clsh_mode mode); +extern void wcd_clsh_set_hph_mode(struct wcd_clsh_ctrl *ctrl, + int mode);
#endif /* _WCD_CLSH_V2_H_ */
This patch adds basic SoundWire codec driver to support for WCD938X TX and RX devices.
Signed-off-by: Srinivas Kandagatla srinivas.kandagatla@linaro.org --- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/wcd938x.c | 1695 ++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wcd938x.h | 671 ++++++++++++++ 4 files changed, 2372 insertions(+) create mode 100644 sound/soc/codecs/wcd938x.c create mode 100644 sound/soc/codecs/wcd938x.h
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 196919bc27ab..f6ca59624e76 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -233,6 +233,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_UDA1380 imply SND_SOC_WCD9335 imply SND_SOC_WCD934X + imply SND_SOC_WCD938X imply SND_SOC_LPASS_RX_MACRO imply SND_SOC_LPASS_TX_MACRO imply SND_SOC_WL1273 @@ -1544,6 +1545,9 @@ config SND_SOC_WCD934X The WCD9340/9341 is a audio codec IC Integrated in Qualcomm SoCs like SDM845.
+config SND_SOC_WCD938X + tristate + config SND_SOC_WL1273 tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 8c7257035e4c..444f60269b80 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -253,6 +253,7 @@ snd-soc-uda134x-objs := uda134x.o snd-soc-uda1380-objs := uda1380.o snd-soc-wcd9335-objs := wcd-clsh-v2.o wcd9335.o snd-soc-wcd934x-objs := wcd-clsh-v2.o wcd934x.o +snd-soc-wcd938x-objs := wcd938x.o wcd-clsh-v2.o snd-soc-wl1273-objs := wl1273.o snd-soc-wm-adsp-objs := wm_adsp.o snd-soc-wm0010-objs := wm0010.o @@ -576,6 +577,7 @@ obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_WCD9335) += snd-soc-wcd9335.o obj-$(CONFIG_SND_SOC_WCD934X) += snd-soc-wcd934x.o +obj-$(CONFIG_SND_SOC_WCD938X) += snd-soc-wcd938x.o obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o obj-$(CONFIG_SND_SOC_WM0010) += snd-soc-wm0010.o obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c new file mode 100644 index 000000000000..6b8ee9971945 --- /dev/null +++ b/sound/soc/codecs/wcd938x.c @@ -0,0 +1,1695 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/pm_runtime.h> +#include <linux/component.h> +#include <sound/soc.h> +#include <sound/tlv.h> +#include <linux/of_gpio.h> +#include <linux/of.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <linux/regmap.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <linux/regulator/consumer.h> + +#include "wcd-clsh-v2.h" +#include "wcd938x.h" + +#define WCD938X_MAX_MICBIAS (4) +#define WCD938X_MAX_SUPPLY (4) +#define WCD938X_MBHC_MAX_BUTTONS (8) +#define TX_ADC_MAX (4) +#define WCD938X_TX_MAX_SWR_PORTS (5) + +#define WCD938X_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) +/* Fractional Rates */ +#define WCD938X_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\ + SNDRV_PCM_RATE_176400) +#define WCD938X_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE) +/* Convert from vout ctl to micbias voltage in mV */ +#define WCD_VOUT_CTL_TO_MICB(v) (1000 + v * 50) +#define SWR_CLK_RATE_0P6MHZ (600000) +#define SWR_CLK_RATE_1P2MHZ (1200000) +#define SWR_CLK_RATE_2P4MHZ (2400000) +#define SWR_CLK_RATE_4P8MHZ (4800000) +#define SWR_CLK_RATE_9P6MHZ (9600000) +#define SWR_CLK_RATE_11P2896MHZ (1128960) + +#define WCD938X_DRV_NAME "wcd938x_codec" +#define WCD938X_VERSION_1_0 (1) +#define EAR_RX_PATH_AUX (1) + +#define ADC_MODE_VAL_HIFI 0x01 +#define ADC_MODE_VAL_LO_HIF 0x02 +#define ADC_MODE_VAL_NORMAL 0x03 +#define ADC_MODE_VAL_LP 0x05 +#define ADC_MODE_VAL_ULP1 0x09 +#define ADC_MODE_VAL_ULP2 0x0B + +/* Z value defined in milliohm */ +#define WCD938X_ZDET_VAL_32 (32000) +#define WCD938X_ZDET_VAL_400 (400000) +#define WCD938X_ZDET_VAL_1200 (1200000) +#define WCD938X_ZDET_VAL_100K (100000000) +/* Z floating defined in ohms */ +#define WCD938X_ZDET_FLOATING_IMPEDANCE (0x0FFFFFFE) +#define WCD938X_ZDET_NUM_MEASUREMENTS (900) +#define WCD938X_MBHC_GET_C1(c) ((c & 0xC000) >> 14) +#define WCD938X_MBHC_GET_X1(x) (x & 0x3FFF) +/* Z value compared in milliOhm */ +#define WCD938X_MBHC_IS_SECOND_RAMP_REQUIRED(z) ((z > 400000) || (z < 32000)) +#define WCD938X_MBHC_ZDET_CONST (86 * 16384) +#define WCD938X_MBHC_MOISTURE_RREF R_24_KOHM +#define WCD_MBHC_HS_V_MAX 1600 + +enum { + WCD9380 = 0, + WCD9385 = 5, +}; + +enum { + TX_HDR12 = 0, + TX_HDR34, + TX_HDR_MAX, +}; + +enum { + WCD_RX1, + WCD_RX2, + WCD_RX3 +}; + +enum { + /* INTR_CTRL_INT_MASK_0 */ + WCD938X_IRQ_MBHC_BUTTON_PRESS_DET = 0, + WCD938X_IRQ_MBHC_BUTTON_RELEASE_DET, + WCD938X_IRQ_MBHC_ELECT_INS_REM_DET, + WCD938X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, + WCD938X_IRQ_MBHC_SW_DET, + WCD938X_IRQ_HPHR_OCP_INT, + WCD938X_IRQ_HPHR_CNP_INT, + WCD938X_IRQ_HPHL_OCP_INT, + + /* INTR_CTRL_INT_MASK_1 */ + WCD938X_IRQ_HPHL_CNP_INT, + WCD938X_IRQ_EAR_CNP_INT, + WCD938X_IRQ_EAR_SCD_INT, + WCD938X_IRQ_AUX_CNP_INT, + WCD938X_IRQ_AUX_SCD_INT, + WCD938X_IRQ_HPHL_PDM_WD_INT, + WCD938X_IRQ_HPHR_PDM_WD_INT, + WCD938X_IRQ_AUX_PDM_WD_INT, + + /* INTR_CTRL_INT_MASK_2 */ + WCD938X_IRQ_LDORT_SCD_INT, + WCD938X_IRQ_MBHC_MOISTURE_INT, + WCD938X_IRQ_HPHL_SURGE_DET_INT, + WCD938X_IRQ_HPHR_SURGE_DET_INT, + WCD938X_NUM_IRQS, +}; + +enum { + WCD_ADC1 = 0, + WCD_ADC2, + WCD_ADC3, + WCD_ADC4, + ALLOW_BUCK_DISABLE, + HPH_COMP_DELAY, + HPH_PA_DELAY, + AMIC2_BCS_ENABLE, + WCD_SUPPLIES_LPM_MODE, +}; + +enum { + ADC_MODE_INVALID = 0, + ADC_MODE_HIFI, + ADC_MODE_LO_HIF, + ADC_MODE_NORMAL, + ADC_MODE_LP, + ADC_MODE_ULP1, + ADC_MODE_ULP2, +}; + +enum { + AIF1_PB = 0, + AIF1_CAP, + NUM_CODEC_DAIS, +}; + +struct wcd938x_priv { + struct sdw_slave *tx_sdw_dev; + struct wcd938x_sdw_priv *sdw_priv[NUM_CODEC_DAIS]; + struct device *txdev; + struct device *rxdev; + struct device_node *rxnode, *txnode; + struct regmap *regmap; + struct wcd_clsh_ctrl *clsh_info; + struct irq_domain *virq; + struct regmap_irq_chip *wcd_regmap_irq_chip; + struct regmap_irq_chip_data *irq_chip; + struct regulator_bulk_data supplies[WCD938X_MAX_SUPPLY]; + struct snd_soc_jack *jack; + unsigned long status_mask; + s32 micb_ref[WCD938X_MAX_MICBIAS]; + s32 pullup_ref[WCD938X_MAX_MICBIAS]; + u32 hph_mode; + u32 tx_mode[TX_ADC_MAX]; + int flyback_cur_det_disable; + int ear_rx_path; + int variant; + int reset_gpio; + u32 micb1_mv; + u32 micb2_mv; + u32 micb3_mv; + u32 micb4_mv; + int hphr_pdm_wd_int; + int hphl_pdm_wd_int; + int aux_pdm_wd_int; + bool comp1_enable; + bool comp2_enable; + bool ldoh; + bool bcs_dis; +}; + +enum { + MIC_BIAS_1 = 1, + MIC_BIAS_2, + MIC_BIAS_3, + MIC_BIAS_4 +}; + +enum { + MICB_PULLUP_ENABLE, + MICB_PULLUP_DISABLE, + MICB_ENABLE, + MICB_DISABLE, +}; + +static const struct reg_default wcd938x_defaults[] = { + {WCD938X_ANA_PAGE_REGISTER, 0x00}, + {WCD938X_ANA_BIAS, 0x00}, + {WCD938X_ANA_RX_SUPPLIES, 0x00}, + {WCD938X_ANA_HPH, 0x0C}, + {WCD938X_ANA_EAR, 0x00}, + {WCD938X_ANA_EAR_COMPANDER_CTL, 0x02}, + {WCD938X_ANA_TX_CH1, 0x20}, + {WCD938X_ANA_TX_CH2, 0x00}, + {WCD938X_ANA_TX_CH3, 0x20}, + {WCD938X_ANA_TX_CH4, 0x00}, + {WCD938X_ANA_MICB1_MICB2_DSP_EN_LOGIC, 0x00}, + {WCD938X_ANA_MICB3_DSP_EN_LOGIC, 0x00}, + {WCD938X_ANA_MBHC_MECH, 0x39}, + {WCD938X_ANA_MBHC_ELECT, 0x08}, + {WCD938X_ANA_MBHC_ZDET, 0x00}, + {WCD938X_ANA_MBHC_RESULT_1, 0x00}, + {WCD938X_ANA_MBHC_RESULT_2, 0x00}, + {WCD938X_ANA_MBHC_RESULT_3, 0x00}, + {WCD938X_ANA_MBHC_BTN0, 0x00}, + {WCD938X_ANA_MBHC_BTN1, 0x10}, + {WCD938X_ANA_MBHC_BTN2, 0x20}, + {WCD938X_ANA_MBHC_BTN3, 0x30}, + {WCD938X_ANA_MBHC_BTN4, 0x40}, + {WCD938X_ANA_MBHC_BTN5, 0x50}, + {WCD938X_ANA_MBHC_BTN6, 0x60}, + {WCD938X_ANA_MBHC_BTN7, 0x70}, + {WCD938X_ANA_MICB1, 0x10}, + {WCD938X_ANA_MICB2, 0x10}, + {WCD938X_ANA_MICB2_RAMP, 0x00}, + {WCD938X_ANA_MICB3, 0x10}, + {WCD938X_ANA_MICB4, 0x10}, + {WCD938X_BIAS_CTL, 0x2A}, + {WCD938X_BIAS_VBG_FINE_ADJ, 0x55}, + {WCD938X_LDOL_VDDCX_ADJUST, 0x01}, + {WCD938X_LDOL_DISABLE_LDOL, 0x00}, + {WCD938X_MBHC_CTL_CLK, 0x00}, + {WCD938X_MBHC_CTL_ANA, 0x00}, + {WCD938X_MBHC_CTL_SPARE_1, 0x00}, + {WCD938X_MBHC_CTL_SPARE_2, 0x00}, + {WCD938X_MBHC_CTL_BCS, 0x00}, + {WCD938X_MBHC_MOISTURE_DET_FSM_STATUS, 0x00}, + {WCD938X_MBHC_TEST_CTL, 0x00}, + {WCD938X_LDOH_MODE, 0x2B}, + {WCD938X_LDOH_BIAS, 0x68}, + {WCD938X_LDOH_STB_LOADS, 0x00}, + {WCD938X_LDOH_SLOWRAMP, 0x50}, + {WCD938X_MICB1_TEST_CTL_1, 0x1A}, + {WCD938X_MICB1_TEST_CTL_2, 0x00}, + {WCD938X_MICB1_TEST_CTL_3, 0xA4}, + {WCD938X_MICB2_TEST_CTL_1, 0x1A}, + {WCD938X_MICB2_TEST_CTL_2, 0x00}, + {WCD938X_MICB2_TEST_CTL_3, 0x24}, + {WCD938X_MICB3_TEST_CTL_1, 0x1A}, + {WCD938X_MICB3_TEST_CTL_2, 0x00}, + {WCD938X_MICB3_TEST_CTL_3, 0xA4}, + {WCD938X_MICB4_TEST_CTL_1, 0x1A}, + {WCD938X_MICB4_TEST_CTL_2, 0x00}, + {WCD938X_MICB4_TEST_CTL_3, 0xA4}, + {WCD938X_TX_COM_ADC_VCM, 0x39}, + {WCD938X_TX_COM_BIAS_ATEST, 0xE0}, + {WCD938X_TX_COM_SPARE1, 0x00}, + {WCD938X_TX_COM_SPARE2, 0x00}, + {WCD938X_TX_COM_TXFE_DIV_CTL, 0x22}, + {WCD938X_TX_COM_TXFE_DIV_START, 0x00}, + {WCD938X_TX_COM_SPARE3, 0x00}, + {WCD938X_TX_COM_SPARE4, 0x00}, + {WCD938X_TX_1_2_TEST_EN, 0xCC}, + {WCD938X_TX_1_2_ADC_IB, 0xE9}, + {WCD938X_TX_1_2_ATEST_REFCTL, 0x0A}, + {WCD938X_TX_1_2_TEST_CTL, 0x38}, + {WCD938X_TX_1_2_TEST_BLK_EN1, 0xFF}, + {WCD938X_TX_1_2_TXFE1_CLKDIV, 0x00}, + {WCD938X_TX_1_2_SAR2_ERR, 0x00}, + {WCD938X_TX_1_2_SAR1_ERR, 0x00}, + {WCD938X_TX_3_4_TEST_EN, 0xCC}, + {WCD938X_TX_3_4_ADC_IB, 0xE9}, + {WCD938X_TX_3_4_ATEST_REFCTL, 0x0A}, + {WCD938X_TX_3_4_TEST_CTL, 0x38}, + {WCD938X_TX_3_4_TEST_BLK_EN3, 0xFF}, + {WCD938X_TX_3_4_TXFE3_CLKDIV, 0x00}, + {WCD938X_TX_3_4_SAR4_ERR, 0x00}, + {WCD938X_TX_3_4_SAR3_ERR, 0x00}, + {WCD938X_TX_3_4_TEST_BLK_EN2, 0xFB}, + {WCD938X_TX_3_4_TXFE2_CLKDIV, 0x00}, + {WCD938X_TX_3_4_SPARE1, 0x00}, + {WCD938X_TX_3_4_TEST_BLK_EN4, 0xFB}, + {WCD938X_TX_3_4_TXFE4_CLKDIV, 0x00}, + {WCD938X_TX_3_4_SPARE2, 0x00}, + {WCD938X_CLASSH_MODE_1, 0x40}, + {WCD938X_CLASSH_MODE_2, 0x3A}, + {WCD938X_CLASSH_MODE_3, 0x00}, + {WCD938X_CLASSH_CTRL_VCL_1, 0x70}, + {WCD938X_CLASSH_CTRL_VCL_2, 0x82}, + {WCD938X_CLASSH_CTRL_CCL_1, 0x31}, + {WCD938X_CLASSH_CTRL_CCL_2, 0x80}, + {WCD938X_CLASSH_CTRL_CCL_3, 0x80}, + {WCD938X_CLASSH_CTRL_CCL_4, 0x51}, + {WCD938X_CLASSH_CTRL_CCL_5, 0x00}, + {WCD938X_CLASSH_BUCK_TMUX_A_D, 0x00}, + {WCD938X_CLASSH_BUCK_SW_DRV_CNTL, 0x77}, + {WCD938X_CLASSH_SPARE, 0x00}, + {WCD938X_FLYBACK_EN, 0x4E}, + {WCD938X_FLYBACK_VNEG_CTRL_1, 0x0B}, + {WCD938X_FLYBACK_VNEG_CTRL_2, 0x45}, + {WCD938X_FLYBACK_VNEG_CTRL_3, 0x74}, + {WCD938X_FLYBACK_VNEG_CTRL_4, 0x7F}, + {WCD938X_FLYBACK_VNEG_CTRL_5, 0x83}, + {WCD938X_FLYBACK_VNEG_CTRL_6, 0x98}, + {WCD938X_FLYBACK_VNEG_CTRL_7, 0xA9}, + {WCD938X_FLYBACK_VNEG_CTRL_8, 0x68}, + {WCD938X_FLYBACK_VNEG_CTRL_9, 0x64}, + {WCD938X_FLYBACK_VNEGDAC_CTRL_1, 0xED}, + {WCD938X_FLYBACK_VNEGDAC_CTRL_2, 0xF0}, + {WCD938X_FLYBACK_VNEGDAC_CTRL_3, 0xA6}, + {WCD938X_FLYBACK_CTRL_1, 0x65}, + {WCD938X_FLYBACK_TEST_CTL, 0x00}, + {WCD938X_RX_AUX_SW_CTL, 0x00}, + {WCD938X_RX_PA_AUX_IN_CONN, 0x01}, + {WCD938X_RX_TIMER_DIV, 0x32}, + {WCD938X_RX_OCP_CTL, 0x1F}, + {WCD938X_RX_OCP_COUNT, 0x77}, + {WCD938X_RX_BIAS_EAR_DAC, 0xA0}, + {WCD938X_RX_BIAS_EAR_AMP, 0xAA}, + {WCD938X_RX_BIAS_HPH_LDO, 0xA9}, + {WCD938X_RX_BIAS_HPH_PA, 0xAA}, + {WCD938X_RX_BIAS_HPH_RDACBUFF_CNP2, 0x8A}, + {WCD938X_RX_BIAS_HPH_RDAC_LDO, 0x88}, + {WCD938X_RX_BIAS_HPH_CNP1, 0x82}, + {WCD938X_RX_BIAS_HPH_LOWPOWER, 0x82}, + {WCD938X_RX_BIAS_AUX_DAC, 0xA0}, + {WCD938X_RX_BIAS_AUX_AMP, 0xAA}, + {WCD938X_RX_BIAS_VNEGDAC_BLEEDER, 0x50}, + {WCD938X_RX_BIAS_MISC, 0x00}, + {WCD938X_RX_BIAS_BUCK_RST, 0x08}, + {WCD938X_RX_BIAS_BUCK_VREF_ERRAMP, 0x44}, + {WCD938X_RX_BIAS_FLYB_ERRAMP, 0x40}, + {WCD938X_RX_BIAS_FLYB_BUFF, 0xAA}, + {WCD938X_RX_BIAS_FLYB_MID_RST, 0x14}, + {WCD938X_HPH_L_STATUS, 0x04}, + {WCD938X_HPH_R_STATUS, 0x04}, + {WCD938X_HPH_CNP_EN, 0x80}, + {WCD938X_HPH_CNP_WG_CTL, 0x9A}, + {WCD938X_HPH_CNP_WG_TIME, 0x14}, + {WCD938X_HPH_OCP_CTL, 0x28}, + {WCD938X_HPH_AUTO_CHOP, 0x16}, + {WCD938X_HPH_CHOP_CTL, 0x83}, + {WCD938X_HPH_PA_CTL1, 0x46}, + {WCD938X_HPH_PA_CTL2, 0x50}, + {WCD938X_HPH_L_EN, 0x80}, + {WCD938X_HPH_L_TEST, 0xE0}, + {WCD938X_HPH_L_ATEST, 0x50}, + {WCD938X_HPH_R_EN, 0x80}, + {WCD938X_HPH_R_TEST, 0xE0}, + {WCD938X_HPH_R_ATEST, 0x54}, + {WCD938X_HPH_RDAC_CLK_CTL1, 0x99}, + {WCD938X_HPH_RDAC_CLK_CTL2, 0x9B}, + {WCD938X_HPH_RDAC_LDO_CTL, 0x33}, + {WCD938X_HPH_RDAC_CHOP_CLK_LP_CTL, 0x00}, + {WCD938X_HPH_REFBUFF_UHQA_CTL, 0x68}, + {WCD938X_HPH_REFBUFF_LP_CTL, 0x0E}, + {WCD938X_HPH_L_DAC_CTL, 0x20}, + {WCD938X_HPH_R_DAC_CTL, 0x20}, + {WCD938X_HPH_SURGE_HPHLR_SURGE_COMP_SEL, 0x55}, + {WCD938X_HPH_SURGE_HPHLR_SURGE_EN, 0x19}, + {WCD938X_HPH_SURGE_HPHLR_SURGE_MISC1, 0xA0}, + {WCD938X_HPH_SURGE_HPHLR_SURGE_STATUS, 0x00}, + {WCD938X_EAR_EAR_EN_REG, 0x22}, + {WCD938X_EAR_EAR_PA_CON, 0x44}, + {WCD938X_EAR_EAR_SP_CON, 0xDB}, + {WCD938X_EAR_EAR_DAC_CON, 0x80}, + {WCD938X_EAR_EAR_CNP_FSM_CON, 0xB2}, + {WCD938X_EAR_TEST_CTL, 0x00}, + {WCD938X_EAR_STATUS_REG_1, 0x00}, + {WCD938X_EAR_STATUS_REG_2, 0x08}, + {WCD938X_ANA_NEW_PAGE_REGISTER, 0x00}, + {WCD938X_HPH_NEW_ANA_HPH2, 0x00}, + {WCD938X_HPH_NEW_ANA_HPH3, 0x00}, + {WCD938X_SLEEP_CTL, 0x16}, + {WCD938X_SLEEP_WATCHDOG_CTL, 0x00}, + {WCD938X_MBHC_NEW_ELECT_REM_CLAMP_CTL, 0x00}, + {WCD938X_MBHC_NEW_CTL_1, 0x02}, + {WCD938X_MBHC_NEW_CTL_2, 0x05}, + {WCD938X_MBHC_NEW_PLUG_DETECT_CTL, 0xE9}, + {WCD938X_MBHC_NEW_ZDET_ANA_CTL, 0x0F}, + {WCD938X_MBHC_NEW_ZDET_RAMP_CTL, 0x00}, + {WCD938X_MBHC_NEW_FSM_STATUS, 0x00}, + {WCD938X_MBHC_NEW_ADC_RESULT, 0x00}, + {WCD938X_TX_NEW_AMIC_MUX_CFG, 0x00}, + {WCD938X_AUX_AUXPA, 0x00}, + {WCD938X_LDORXTX_MODE, 0x0C}, + {WCD938X_LDORXTX_CONFIG, 0x10}, + {WCD938X_DIE_CRACK_DIE_CRK_DET_EN, 0x00}, + {WCD938X_DIE_CRACK_DIE_CRK_DET_OUT, 0x00}, + {WCD938X_HPH_NEW_INT_RDAC_GAIN_CTL, 0x40}, + {WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x81}, + {WCD938X_HPH_NEW_INT_RDAC_VREF_CTL, 0x10}, + {WCD938X_HPH_NEW_INT_RDAC_OVERRIDE_CTL, 0x00}, + {WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x81}, + {WCD938X_HPH_NEW_INT_PA_MISC1, 0x22}, + {WCD938X_HPH_NEW_INT_PA_MISC2, 0x00}, + {WCD938X_HPH_NEW_INT_PA_RDAC_MISC, 0x00}, + {WCD938X_HPH_NEW_INT_HPH_TIMER1, 0xFE}, + {WCD938X_HPH_NEW_INT_HPH_TIMER2, 0x02}, + {WCD938X_HPH_NEW_INT_HPH_TIMER3, 0x4E}, + {WCD938X_HPH_NEW_INT_HPH_TIMER4, 0x54}, + {WCD938X_HPH_NEW_INT_PA_RDAC_MISC2, 0x00}, + {WCD938X_HPH_NEW_INT_PA_RDAC_MISC3, 0x00}, + {WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L_NEW, 0x90}, + {WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R_NEW, 0x90}, + {WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI, 0x62}, + {WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_ULP, 0x01}, + {WCD938X_RX_NEW_INT_HPH_RDAC_LDO_LP, 0x11}, + {WCD938X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL, 0x57}, + {WCD938X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL, 0x01}, + {WCD938X_MBHC_NEW_INT_MECH_DET_CURRENT, 0x00}, + {WCD938X_MBHC_NEW_INT_SPARE_2, 0x00}, + {WCD938X_EAR_INT_NEW_EAR_CHOPPER_CON, 0xA8}, + {WCD938X_EAR_INT_NEW_CNP_VCM_CON1, 0x42}, + {WCD938X_EAR_INT_NEW_CNP_VCM_CON2, 0x22}, + {WCD938X_EAR_INT_NEW_EAR_DYNAMIC_BIAS, 0x00}, + {WCD938X_AUX_INT_EN_REG, 0x00}, + {WCD938X_AUX_INT_PA_CTRL, 0x06}, + {WCD938X_AUX_INT_SP_CTRL, 0xD2}, + {WCD938X_AUX_INT_DAC_CTRL, 0x80}, + {WCD938X_AUX_INT_CLK_CTRL, 0x50}, + {WCD938X_AUX_INT_TEST_CTRL, 0x00}, + {WCD938X_AUX_INT_STATUS_REG, 0x00}, + {WCD938X_AUX_INT_MISC, 0x00}, + {WCD938X_LDORXTX_INT_BIAS, 0x6E}, + {WCD938X_LDORXTX_INT_STB_LOADS_DTEST, 0x50}, + {WCD938X_LDORXTX_INT_TEST0, 0x1C}, + {WCD938X_LDORXTX_INT_STARTUP_TIMER, 0xFF}, + {WCD938X_LDORXTX_INT_TEST1, 0x1F}, + {WCD938X_LDORXTX_INT_STATUS, 0x00}, + {WCD938X_SLEEP_INT_WATCHDOG_CTL_1, 0x0A}, + {WCD938X_SLEEP_INT_WATCHDOG_CTL_2, 0x0A}, + {WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT1, 0x02}, + {WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT2, 0x60}, + {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L2, 0xFF}, + {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L1, 0x7F}, + {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L0, 0x3F}, + {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP1P2M, 0x1F}, + {WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP0P6M, 0x0F}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L2L1, 0xD7}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L0, 0xC8}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_ULP, 0xC6}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L2L1, 0xD5}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L0, 0xCA}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_ULP, 0x05}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_L2L1L0, 0xA5}, + {WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_ULP, 0x13}, + {WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L2L1, 0x88}, + {WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L0ULP, 0x42}, + {WCD938X_TX_COM_NEW_INT_TXADC_INT_L2, 0xFF}, + {WCD938X_TX_COM_NEW_INT_TXADC_INT_L1, 0x64}, + {WCD938X_TX_COM_NEW_INT_TXADC_INT_L0, 0x64}, + {WCD938X_TX_COM_NEW_INT_TXADC_INT_ULP, 0x77}, + {WCD938X_DIGITAL_PAGE_REGISTER, 0x00}, + {WCD938X_DIGITAL_CHIP_ID0, 0x00}, + {WCD938X_DIGITAL_CHIP_ID1, 0x00}, + {WCD938X_DIGITAL_CHIP_ID2, 0x0D}, + {WCD938X_DIGITAL_CHIP_ID3, 0x01}, + {WCD938X_DIGITAL_SWR_TX_CLK_RATE, 0x00}, + {WCD938X_DIGITAL_CDC_RST_CTL, 0x03}, + {WCD938X_DIGITAL_TOP_CLK_CFG, 0x00}, + {WCD938X_DIGITAL_CDC_ANA_CLK_CTL, 0x00}, + {WCD938X_DIGITAL_CDC_DIG_CLK_CTL, 0xF0}, + {WCD938X_DIGITAL_SWR_RST_EN, 0x00}, + {WCD938X_DIGITAL_CDC_PATH_MODE, 0x55}, + {WCD938X_DIGITAL_CDC_RX_RST, 0x00}, + {WCD938X_DIGITAL_CDC_RX0_CTL, 0xFC}, + {WCD938X_DIGITAL_CDC_RX1_CTL, 0xFC}, + {WCD938X_DIGITAL_CDC_RX2_CTL, 0xFC}, + {WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, 0x00}, + {WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, 0x00}, + {WCD938X_DIGITAL_CDC_COMP_CTL_0, 0x00}, + {WCD938X_DIGITAL_CDC_ANA_TX_CLK_CTL, 0x1E}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A1_0, 0x00}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A1_1, 0x01}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A2_0, 0x63}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A2_1, 0x04}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A3_0, 0xAC}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A3_1, 0x04}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A4_0, 0x1A}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A4_1, 0x03}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A5_0, 0xBC}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A5_1, 0x02}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A6_0, 0xC7}, + {WCD938X_DIGITAL_CDC_HPH_DSM_A7_0, 0xF8}, + {WCD938X_DIGITAL_CDC_HPH_DSM_C_0, 0x47}, + {WCD938X_DIGITAL_CDC_HPH_DSM_C_1, 0x43}, + {WCD938X_DIGITAL_CDC_HPH_DSM_C_2, 0xB1}, + {WCD938X_DIGITAL_CDC_HPH_DSM_C_3, 0x17}, + {WCD938X_DIGITAL_CDC_HPH_DSM_R1, 0x4D}, + {WCD938X_DIGITAL_CDC_HPH_DSM_R2, 0x29}, + {WCD938X_DIGITAL_CDC_HPH_DSM_R3, 0x34}, + {WCD938X_DIGITAL_CDC_HPH_DSM_R4, 0x59}, + {WCD938X_DIGITAL_CDC_HPH_DSM_R5, 0x66}, + {WCD938X_DIGITAL_CDC_HPH_DSM_R6, 0x87}, + {WCD938X_DIGITAL_CDC_HPH_DSM_R7, 0x64}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A1_0, 0x00}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A1_1, 0x01}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A2_0, 0x96}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A2_1, 0x09}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A3_0, 0xAB}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A3_1, 0x05}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A4_0, 0x1C}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A4_1, 0x02}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A5_0, 0x17}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A5_1, 0x02}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A6_0, 0xAA}, + {WCD938X_DIGITAL_CDC_AUX_DSM_A7_0, 0xE3}, + {WCD938X_DIGITAL_CDC_AUX_DSM_C_0, 0x69}, + {WCD938X_DIGITAL_CDC_AUX_DSM_C_1, 0x54}, + {WCD938X_DIGITAL_CDC_AUX_DSM_C_2, 0x02}, + {WCD938X_DIGITAL_CDC_AUX_DSM_C_3, 0x15}, + {WCD938X_DIGITAL_CDC_AUX_DSM_R1, 0xA4}, + {WCD938X_DIGITAL_CDC_AUX_DSM_R2, 0xB5}, + {WCD938X_DIGITAL_CDC_AUX_DSM_R3, 0x86}, + {WCD938X_DIGITAL_CDC_AUX_DSM_R4, 0x85}, + {WCD938X_DIGITAL_CDC_AUX_DSM_R5, 0xAA}, + {WCD938X_DIGITAL_CDC_AUX_DSM_R6, 0xE2}, + {WCD938X_DIGITAL_CDC_AUX_DSM_R7, 0x62}, + {WCD938X_DIGITAL_CDC_HPH_GAIN_RX_0, 0x55}, + {WCD938X_DIGITAL_CDC_HPH_GAIN_RX_1, 0xA9}, + {WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_0, 0x3D}, + {WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_1, 0x2E}, + {WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_2, 0x01}, + {WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_0, 0x00}, + {WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_1, 0xFC}, + {WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_2, 0x01}, + {WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, 0x00}, + {WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, 0x00}, + {WCD938X_DIGITAL_CDC_EAR_PATH_CTL, 0x00}, + {WCD938X_DIGITAL_CDC_SWR_CLH, 0x00}, + {WCD938X_DIGITAL_SWR_CLH_BYP, 0x00}, + {WCD938X_DIGITAL_CDC_TX0_CTL, 0x68}, + {WCD938X_DIGITAL_CDC_TX1_CTL, 0x68}, + {WCD938X_DIGITAL_CDC_TX2_CTL, 0x68}, + {WCD938X_DIGITAL_CDC_TX_RST, 0x00}, + {WCD938X_DIGITAL_CDC_REQ_CTL, 0x01}, + {WCD938X_DIGITAL_CDC_RST, 0x00}, + {WCD938X_DIGITAL_CDC_AMIC_CTL, 0x0F}, + {WCD938X_DIGITAL_CDC_DMIC_CTL, 0x04}, + {WCD938X_DIGITAL_CDC_DMIC1_CTL, 0x01}, + {WCD938X_DIGITAL_CDC_DMIC2_CTL, 0x01}, + {WCD938X_DIGITAL_CDC_DMIC3_CTL, 0x01}, + {WCD938X_DIGITAL_CDC_DMIC4_CTL, 0x01}, + {WCD938X_DIGITAL_EFUSE_PRG_CTL, 0x00}, + {WCD938X_DIGITAL_EFUSE_CTL, 0x2B}, + {WCD938X_DIGITAL_CDC_DMIC_RATE_1_2, 0x11}, + {WCD938X_DIGITAL_CDC_DMIC_RATE_3_4, 0x11}, + {WCD938X_DIGITAL_PDM_WD_CTL0, 0x00}, + {WCD938X_DIGITAL_PDM_WD_CTL1, 0x00}, + {WCD938X_DIGITAL_PDM_WD_CTL2, 0x00}, + {WCD938X_DIGITAL_INTR_MODE, 0x00}, + {WCD938X_DIGITAL_INTR_MASK_0, 0xFF}, + {WCD938X_DIGITAL_INTR_MASK_1, 0xFF}, + {WCD938X_DIGITAL_INTR_MASK_2, 0x3F}, + {WCD938X_DIGITAL_INTR_STATUS_0, 0x00}, + {WCD938X_DIGITAL_INTR_STATUS_1, 0x00}, + {WCD938X_DIGITAL_INTR_STATUS_2, 0x00}, + {WCD938X_DIGITAL_INTR_CLEAR_0, 0x00}, + {WCD938X_DIGITAL_INTR_CLEAR_1, 0x00}, + {WCD938X_DIGITAL_INTR_CLEAR_2, 0x00}, + {WCD938X_DIGITAL_INTR_LEVEL_0, 0x00}, + {WCD938X_DIGITAL_INTR_LEVEL_1, 0x00}, + {WCD938X_DIGITAL_INTR_LEVEL_2, 0x00}, + {WCD938X_DIGITAL_INTR_SET_0, 0x00}, + {WCD938X_DIGITAL_INTR_SET_1, 0x00}, + {WCD938X_DIGITAL_INTR_SET_2, 0x00}, + {WCD938X_DIGITAL_INTR_TEST_0, 0x00}, + {WCD938X_DIGITAL_INTR_TEST_1, 0x00}, + {WCD938X_DIGITAL_INTR_TEST_2, 0x00}, + {WCD938X_DIGITAL_TX_MODE_DBG_EN, 0x00}, + {WCD938X_DIGITAL_TX_MODE_DBG_0_1, 0x00}, + {WCD938X_DIGITAL_TX_MODE_DBG_2_3, 0x00}, + {WCD938X_DIGITAL_LB_IN_SEL_CTL, 0x00}, + {WCD938X_DIGITAL_LOOP_BACK_MODE, 0x00}, + {WCD938X_DIGITAL_SWR_DAC_TEST, 0x00}, + {WCD938X_DIGITAL_SWR_HM_TEST_RX_0, 0x40}, + {WCD938X_DIGITAL_SWR_HM_TEST_TX_0, 0x40}, + {WCD938X_DIGITAL_SWR_HM_TEST_RX_1, 0x00}, + {WCD938X_DIGITAL_SWR_HM_TEST_TX_1, 0x00}, + {WCD938X_DIGITAL_SWR_HM_TEST_TX_2, 0x00}, + {WCD938X_DIGITAL_SWR_HM_TEST_0, 0x00}, + {WCD938X_DIGITAL_SWR_HM_TEST_1, 0x00}, + {WCD938X_DIGITAL_PAD_CTL_SWR_0, 0x8F}, + {WCD938X_DIGITAL_PAD_CTL_SWR_1, 0x06}, + {WCD938X_DIGITAL_I2C_CTL, 0x00}, + {WCD938X_DIGITAL_CDC_TX_TANGGU_SW_MODE, 0x00}, + {WCD938X_DIGITAL_EFUSE_TEST_CTL_0, 0x00}, + {WCD938X_DIGITAL_EFUSE_TEST_CTL_1, 0x00}, + {WCD938X_DIGITAL_EFUSE_T_DATA_0, 0x00}, + {WCD938X_DIGITAL_EFUSE_T_DATA_1, 0x00}, + {WCD938X_DIGITAL_PAD_CTL_PDM_RX0, 0xF1}, + {WCD938X_DIGITAL_PAD_CTL_PDM_RX1, 0xF1}, + {WCD938X_DIGITAL_PAD_CTL_PDM_TX0, 0xF1}, + {WCD938X_DIGITAL_PAD_CTL_PDM_TX1, 0xF1}, + {WCD938X_DIGITAL_PAD_CTL_PDM_TX2, 0xF1}, + {WCD938X_DIGITAL_PAD_INP_DIS_0, 0x00}, + {WCD938X_DIGITAL_PAD_INP_DIS_1, 0x00}, + {WCD938X_DIGITAL_DRIVE_STRENGTH_0, 0x00}, + {WCD938X_DIGITAL_DRIVE_STRENGTH_1, 0x00}, + {WCD938X_DIGITAL_DRIVE_STRENGTH_2, 0x00}, + {WCD938X_DIGITAL_RX_DATA_EDGE_CTL, 0x1F}, + {WCD938X_DIGITAL_TX_DATA_EDGE_CTL, 0x80}, + {WCD938X_DIGITAL_GPIO_MODE, 0x00}, + {WCD938X_DIGITAL_PIN_CTL_OE, 0x00}, + {WCD938X_DIGITAL_PIN_CTL_DATA_0, 0x00}, + {WCD938X_DIGITAL_PIN_CTL_DATA_1, 0x00}, + {WCD938X_DIGITAL_PIN_STATUS_0, 0x00}, + {WCD938X_DIGITAL_PIN_STATUS_1, 0x00}, + {WCD938X_DIGITAL_DIG_DEBUG_CTL, 0x00}, + {WCD938X_DIGITAL_DIG_DEBUG_EN, 0x00}, + {WCD938X_DIGITAL_ANA_CSR_DBG_ADD, 0x00}, + {WCD938X_DIGITAL_ANA_CSR_DBG_CTL, 0x48}, + {WCD938X_DIGITAL_SSP_DBG, 0x00}, + {WCD938X_DIGITAL_MODE_STATUS_0, 0x00}, + {WCD938X_DIGITAL_MODE_STATUS_1, 0x00}, + {WCD938X_DIGITAL_SPARE_0, 0x00}, + {WCD938X_DIGITAL_SPARE_1, 0x00}, + {WCD938X_DIGITAL_SPARE_2, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_0, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_1, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_2, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_3, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_4, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_5, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_6, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_7, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_8, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_9, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_10, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_11, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_12, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_13, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_14, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_15, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_16, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_17, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_18, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_19, 0xFF}, + {WCD938X_DIGITAL_EFUSE_REG_20, 0x0E}, + {WCD938X_DIGITAL_EFUSE_REG_21, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_22, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_23, 0xF8}, + {WCD938X_DIGITAL_EFUSE_REG_24, 0x16}, + {WCD938X_DIGITAL_EFUSE_REG_25, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_26, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_27, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_28, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_29, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_30, 0x00}, + {WCD938X_DIGITAL_EFUSE_REG_31, 0x00}, + {WCD938X_DIGITAL_TX_REQ_FB_CTL_0, 0x88}, + {WCD938X_DIGITAL_TX_REQ_FB_CTL_1, 0x88}, + {WCD938X_DIGITAL_TX_REQ_FB_CTL_2, 0x88}, + {WCD938X_DIGITAL_TX_REQ_FB_CTL_3, 0x88}, + {WCD938X_DIGITAL_TX_REQ_FB_CTL_4, 0x88}, + {WCD938X_DIGITAL_DEM_BYPASS_DATA0, 0x55}, + {WCD938X_DIGITAL_DEM_BYPASS_DATA1, 0x55}, + {WCD938X_DIGITAL_DEM_BYPASS_DATA2, 0x55}, + {WCD938X_DIGITAL_DEM_BYPASS_DATA3, 0x01}, +}; + +static bool wcd938x_rdwr_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WCD938X_ANA_PAGE_REGISTER: + case WCD938X_ANA_BIAS: + case WCD938X_ANA_RX_SUPPLIES: + case WCD938X_ANA_HPH: + case WCD938X_ANA_EAR: + case WCD938X_ANA_EAR_COMPANDER_CTL: + case WCD938X_ANA_TX_CH1: + case WCD938X_ANA_TX_CH2: + case WCD938X_ANA_TX_CH3: + case WCD938X_ANA_TX_CH4: + case WCD938X_ANA_MICB1_MICB2_DSP_EN_LOGIC: + case WCD938X_ANA_MICB3_DSP_EN_LOGIC: + case WCD938X_ANA_MBHC_MECH: + case WCD938X_ANA_MBHC_ELECT: + case WCD938X_ANA_MBHC_ZDET: + case WCD938X_ANA_MBHC_BTN0: + case WCD938X_ANA_MBHC_BTN1: + case WCD938X_ANA_MBHC_BTN2: + case WCD938X_ANA_MBHC_BTN3: + case WCD938X_ANA_MBHC_BTN4: + case WCD938X_ANA_MBHC_BTN5: + case WCD938X_ANA_MBHC_BTN6: + case WCD938X_ANA_MBHC_BTN7: + case WCD938X_ANA_MICB1: + case WCD938X_ANA_MICB2: + case WCD938X_ANA_MICB2_RAMP: + case WCD938X_ANA_MICB3: + case WCD938X_ANA_MICB4: + case WCD938X_BIAS_CTL: + case WCD938X_BIAS_VBG_FINE_ADJ: + case WCD938X_LDOL_VDDCX_ADJUST: + case WCD938X_LDOL_DISABLE_LDOL: + case WCD938X_MBHC_CTL_CLK: + case WCD938X_MBHC_CTL_ANA: + case WCD938X_MBHC_CTL_SPARE_1: + case WCD938X_MBHC_CTL_SPARE_2: + case WCD938X_MBHC_CTL_BCS: + case WCD938X_MBHC_TEST_CTL: + case WCD938X_LDOH_MODE: + case WCD938X_LDOH_BIAS: + case WCD938X_LDOH_STB_LOADS: + case WCD938X_LDOH_SLOWRAMP: + case WCD938X_MICB1_TEST_CTL_1: + case WCD938X_MICB1_TEST_CTL_2: + case WCD938X_MICB1_TEST_CTL_3: + case WCD938X_MICB2_TEST_CTL_1: + case WCD938X_MICB2_TEST_CTL_2: + case WCD938X_MICB2_TEST_CTL_3: + case WCD938X_MICB3_TEST_CTL_1: + case WCD938X_MICB3_TEST_CTL_2: + case WCD938X_MICB3_TEST_CTL_3: + case WCD938X_MICB4_TEST_CTL_1: + case WCD938X_MICB4_TEST_CTL_2: + case WCD938X_MICB4_TEST_CTL_3: + case WCD938X_TX_COM_ADC_VCM: + case WCD938X_TX_COM_BIAS_ATEST: + case WCD938X_TX_COM_SPARE1: + case WCD938X_TX_COM_SPARE2: + case WCD938X_TX_COM_TXFE_DIV_CTL: + case WCD938X_TX_COM_TXFE_DIV_START: + case WCD938X_TX_COM_SPARE3: + case WCD938X_TX_COM_SPARE4: + case WCD938X_TX_1_2_TEST_EN: + case WCD938X_TX_1_2_ADC_IB: + case WCD938X_TX_1_2_ATEST_REFCTL: + case WCD938X_TX_1_2_TEST_CTL: + case WCD938X_TX_1_2_TEST_BLK_EN1: + case WCD938X_TX_1_2_TXFE1_CLKDIV: + case WCD938X_TX_3_4_TEST_EN: + case WCD938X_TX_3_4_ADC_IB: + case WCD938X_TX_3_4_ATEST_REFCTL: + case WCD938X_TX_3_4_TEST_CTL: + case WCD938X_TX_3_4_TEST_BLK_EN3: + case WCD938X_TX_3_4_TXFE3_CLKDIV: + case WCD938X_TX_3_4_TEST_BLK_EN2: + case WCD938X_TX_3_4_TXFE2_CLKDIV: + case WCD938X_TX_3_4_SPARE1: + case WCD938X_TX_3_4_TEST_BLK_EN4: + case WCD938X_TX_3_4_TXFE4_CLKDIV: + case WCD938X_TX_3_4_SPARE2: + case WCD938X_CLASSH_MODE_1: + case WCD938X_CLASSH_MODE_2: + case WCD938X_CLASSH_MODE_3: + case WCD938X_CLASSH_CTRL_VCL_1: + case WCD938X_CLASSH_CTRL_VCL_2: + case WCD938X_CLASSH_CTRL_CCL_1: + case WCD938X_CLASSH_CTRL_CCL_2: + case WCD938X_CLASSH_CTRL_CCL_3: + case WCD938X_CLASSH_CTRL_CCL_4: + case WCD938X_CLASSH_CTRL_CCL_5: + case WCD938X_CLASSH_BUCK_TMUX_A_D: + case WCD938X_CLASSH_BUCK_SW_DRV_CNTL: + case WCD938X_CLASSH_SPARE: + case WCD938X_FLYBACK_EN: + case WCD938X_FLYBACK_VNEG_CTRL_1: + case WCD938X_FLYBACK_VNEG_CTRL_2: + case WCD938X_FLYBACK_VNEG_CTRL_3: + case WCD938X_FLYBACK_VNEG_CTRL_4: + case WCD938X_FLYBACK_VNEG_CTRL_5: + case WCD938X_FLYBACK_VNEG_CTRL_6: + case WCD938X_FLYBACK_VNEG_CTRL_7: + case WCD938X_FLYBACK_VNEG_CTRL_8: + case WCD938X_FLYBACK_VNEG_CTRL_9: + case WCD938X_FLYBACK_VNEGDAC_CTRL_1: + case WCD938X_FLYBACK_VNEGDAC_CTRL_2: + case WCD938X_FLYBACK_VNEGDAC_CTRL_3: + case WCD938X_FLYBACK_CTRL_1: + case WCD938X_FLYBACK_TEST_CTL: + case WCD938X_RX_AUX_SW_CTL: + case WCD938X_RX_PA_AUX_IN_CONN: + case WCD938X_RX_TIMER_DIV: + case WCD938X_RX_OCP_CTL: + case WCD938X_RX_OCP_COUNT: + case WCD938X_RX_BIAS_EAR_DAC: + case WCD938X_RX_BIAS_EAR_AMP: + case WCD938X_RX_BIAS_HPH_LDO: + case WCD938X_RX_BIAS_HPH_PA: + case WCD938X_RX_BIAS_HPH_RDACBUFF_CNP2: + case WCD938X_RX_BIAS_HPH_RDAC_LDO: + case WCD938X_RX_BIAS_HPH_CNP1: + case WCD938X_RX_BIAS_HPH_LOWPOWER: + case WCD938X_RX_BIAS_AUX_DAC: + case WCD938X_RX_BIAS_AUX_AMP: + case WCD938X_RX_BIAS_VNEGDAC_BLEEDER: + case WCD938X_RX_BIAS_MISC: + case WCD938X_RX_BIAS_BUCK_RST: + case WCD938X_RX_BIAS_BUCK_VREF_ERRAMP: + case WCD938X_RX_BIAS_FLYB_ERRAMP: + case WCD938X_RX_BIAS_FLYB_BUFF: + case WCD938X_RX_BIAS_FLYB_MID_RST: + case WCD938X_HPH_CNP_EN: + case WCD938X_HPH_CNP_WG_CTL: + case WCD938X_HPH_CNP_WG_TIME: + case WCD938X_HPH_OCP_CTL: + case WCD938X_HPH_AUTO_CHOP: + case WCD938X_HPH_CHOP_CTL: + case WCD938X_HPH_PA_CTL1: + case WCD938X_HPH_PA_CTL2: + case WCD938X_HPH_L_EN: + case WCD938X_HPH_L_TEST: + case WCD938X_HPH_L_ATEST: + case WCD938X_HPH_R_EN: + case WCD938X_HPH_R_TEST: + case WCD938X_HPH_R_ATEST: + case WCD938X_HPH_RDAC_CLK_CTL1: + case WCD938X_HPH_RDAC_CLK_CTL2: + case WCD938X_HPH_RDAC_LDO_CTL: + case WCD938X_HPH_RDAC_CHOP_CLK_LP_CTL: + case WCD938X_HPH_REFBUFF_UHQA_CTL: + case WCD938X_HPH_REFBUFF_LP_CTL: + case WCD938X_HPH_L_DAC_CTL: + case WCD938X_HPH_R_DAC_CTL: + case WCD938X_HPH_SURGE_HPHLR_SURGE_COMP_SEL: + case WCD938X_HPH_SURGE_HPHLR_SURGE_EN: + case WCD938X_HPH_SURGE_HPHLR_SURGE_MISC1: + case WCD938X_EAR_EAR_EN_REG: + case WCD938X_EAR_EAR_PA_CON: + case WCD938X_EAR_EAR_SP_CON: + case WCD938X_EAR_EAR_DAC_CON: + case WCD938X_EAR_EAR_CNP_FSM_CON: + case WCD938X_EAR_TEST_CTL: + case WCD938X_ANA_NEW_PAGE_REGISTER: + case WCD938X_HPH_NEW_ANA_HPH2: + case WCD938X_HPH_NEW_ANA_HPH3: + case WCD938X_SLEEP_CTL: + case WCD938X_SLEEP_WATCHDOG_CTL: + case WCD938X_MBHC_NEW_ELECT_REM_CLAMP_CTL: + case WCD938X_MBHC_NEW_CTL_1: + case WCD938X_MBHC_NEW_CTL_2: + case WCD938X_MBHC_NEW_PLUG_DETECT_CTL: + case WCD938X_MBHC_NEW_ZDET_ANA_CTL: + case WCD938X_MBHC_NEW_ZDET_RAMP_CTL: + case WCD938X_TX_NEW_AMIC_MUX_CFG: + case WCD938X_AUX_AUXPA: + case WCD938X_LDORXTX_MODE: + case WCD938X_LDORXTX_CONFIG: + case WCD938X_DIE_CRACK_DIE_CRK_DET_EN: + case WCD938X_HPH_NEW_INT_RDAC_GAIN_CTL: + case WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L: + case WCD938X_HPH_NEW_INT_RDAC_VREF_CTL: + case WCD938X_HPH_NEW_INT_RDAC_OVERRIDE_CTL: + case WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R: + case WCD938X_HPH_NEW_INT_PA_MISC1: + case WCD938X_HPH_NEW_INT_PA_MISC2: + case WCD938X_HPH_NEW_INT_PA_RDAC_MISC: + case WCD938X_HPH_NEW_INT_HPH_TIMER1: + case WCD938X_HPH_NEW_INT_HPH_TIMER2: + case WCD938X_HPH_NEW_INT_HPH_TIMER3: + case WCD938X_HPH_NEW_INT_HPH_TIMER4: + case WCD938X_HPH_NEW_INT_PA_RDAC_MISC2: + case WCD938X_HPH_NEW_INT_PA_RDAC_MISC3: + case WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L_NEW: + case WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R_NEW: + case WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI: + case WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_ULP: + case WCD938X_RX_NEW_INT_HPH_RDAC_LDO_LP: + case WCD938X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL: + case WCD938X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL: + case WCD938X_MBHC_NEW_INT_MECH_DET_CURRENT: + case WCD938X_MBHC_NEW_INT_SPARE_2: + case WCD938X_EAR_INT_NEW_EAR_CHOPPER_CON: + case WCD938X_EAR_INT_NEW_CNP_VCM_CON1: + case WCD938X_EAR_INT_NEW_CNP_VCM_CON2: + case WCD938X_EAR_INT_NEW_EAR_DYNAMIC_BIAS: + case WCD938X_AUX_INT_EN_REG: + case WCD938X_AUX_INT_PA_CTRL: + case WCD938X_AUX_INT_SP_CTRL: + case WCD938X_AUX_INT_DAC_CTRL: + case WCD938X_AUX_INT_CLK_CTRL: + case WCD938X_AUX_INT_TEST_CTRL: + case WCD938X_AUX_INT_MISC: + case WCD938X_LDORXTX_INT_BIAS: + case WCD938X_LDORXTX_INT_STB_LOADS_DTEST: + case WCD938X_LDORXTX_INT_TEST0: + case WCD938X_LDORXTX_INT_STARTUP_TIMER: + case WCD938X_LDORXTX_INT_TEST1: + case WCD938X_SLEEP_INT_WATCHDOG_CTL_1: + case WCD938X_SLEEP_INT_WATCHDOG_CTL_2: + case WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT1: + case WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT2: + case WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L2: + case WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L1: + case WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L0: + case WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP1P2M: + case WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP0P6M: + case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L2L1: + case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L0: + case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_ULP: + case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L2L1: + case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L0: + case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_ULP: + case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_L2L1L0: + case WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_ULP: + case WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L2L1: + case WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L0ULP: + case WCD938X_TX_COM_NEW_INT_TXADC_INT_L2: + case WCD938X_TX_COM_NEW_INT_TXADC_INT_L1: + case WCD938X_TX_COM_NEW_INT_TXADC_INT_L0: + case WCD938X_TX_COM_NEW_INT_TXADC_INT_ULP: + case WCD938X_DIGITAL_PAGE_REGISTER: + case WCD938X_DIGITAL_SWR_TX_CLK_RATE: + case WCD938X_DIGITAL_CDC_RST_CTL: + case WCD938X_DIGITAL_TOP_CLK_CFG: + case WCD938X_DIGITAL_CDC_ANA_CLK_CTL: + case WCD938X_DIGITAL_CDC_DIG_CLK_CTL: + case WCD938X_DIGITAL_SWR_RST_EN: + case WCD938X_DIGITAL_CDC_PATH_MODE: + case WCD938X_DIGITAL_CDC_RX_RST: + case WCD938X_DIGITAL_CDC_RX0_CTL: + case WCD938X_DIGITAL_CDC_RX1_CTL: + case WCD938X_DIGITAL_CDC_RX2_CTL: + case WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1: + case WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3: + case WCD938X_DIGITAL_CDC_COMP_CTL_0: + case WCD938X_DIGITAL_CDC_ANA_TX_CLK_CTL: + case WCD938X_DIGITAL_CDC_HPH_DSM_A1_0: + case WCD938X_DIGITAL_CDC_HPH_DSM_A1_1: + case WCD938X_DIGITAL_CDC_HPH_DSM_A2_0: + case WCD938X_DIGITAL_CDC_HPH_DSM_A2_1: + case WCD938X_DIGITAL_CDC_HPH_DSM_A3_0: + case WCD938X_DIGITAL_CDC_HPH_DSM_A3_1: + case WCD938X_DIGITAL_CDC_HPH_DSM_A4_0: + case WCD938X_DIGITAL_CDC_HPH_DSM_A4_1: + case WCD938X_DIGITAL_CDC_HPH_DSM_A5_0: + case WCD938X_DIGITAL_CDC_HPH_DSM_A5_1: + case WCD938X_DIGITAL_CDC_HPH_DSM_A6_0: + case WCD938X_DIGITAL_CDC_HPH_DSM_A7_0: + case WCD938X_DIGITAL_CDC_HPH_DSM_C_0: + case WCD938X_DIGITAL_CDC_HPH_DSM_C_1: + case WCD938X_DIGITAL_CDC_HPH_DSM_C_2: + case WCD938X_DIGITAL_CDC_HPH_DSM_C_3: + case WCD938X_DIGITAL_CDC_HPH_DSM_R1: + case WCD938X_DIGITAL_CDC_HPH_DSM_R2: + case WCD938X_DIGITAL_CDC_HPH_DSM_R3: + case WCD938X_DIGITAL_CDC_HPH_DSM_R4: + case WCD938X_DIGITAL_CDC_HPH_DSM_R5: + case WCD938X_DIGITAL_CDC_HPH_DSM_R6: + case WCD938X_DIGITAL_CDC_HPH_DSM_R7: + case WCD938X_DIGITAL_CDC_AUX_DSM_A1_0: + case WCD938X_DIGITAL_CDC_AUX_DSM_A1_1: + case WCD938X_DIGITAL_CDC_AUX_DSM_A2_0: + case WCD938X_DIGITAL_CDC_AUX_DSM_A2_1: + case WCD938X_DIGITAL_CDC_AUX_DSM_A3_0: + case WCD938X_DIGITAL_CDC_AUX_DSM_A3_1: + case WCD938X_DIGITAL_CDC_AUX_DSM_A4_0: + case WCD938X_DIGITAL_CDC_AUX_DSM_A4_1: + case WCD938X_DIGITAL_CDC_AUX_DSM_A5_0: + case WCD938X_DIGITAL_CDC_AUX_DSM_A5_1: + case WCD938X_DIGITAL_CDC_AUX_DSM_A6_0: + case WCD938X_DIGITAL_CDC_AUX_DSM_A7_0: + case WCD938X_DIGITAL_CDC_AUX_DSM_C_0: + case WCD938X_DIGITAL_CDC_AUX_DSM_C_1: + case WCD938X_DIGITAL_CDC_AUX_DSM_C_2: + case WCD938X_DIGITAL_CDC_AUX_DSM_C_3: + case WCD938X_DIGITAL_CDC_AUX_DSM_R1: + case WCD938X_DIGITAL_CDC_AUX_DSM_R2: + case WCD938X_DIGITAL_CDC_AUX_DSM_R3: + case WCD938X_DIGITAL_CDC_AUX_DSM_R4: + case WCD938X_DIGITAL_CDC_AUX_DSM_R5: + case WCD938X_DIGITAL_CDC_AUX_DSM_R6: + case WCD938X_DIGITAL_CDC_AUX_DSM_R7: + case WCD938X_DIGITAL_CDC_HPH_GAIN_RX_0: + case WCD938X_DIGITAL_CDC_HPH_GAIN_RX_1: + case WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_0: + case WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_1: + case WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_2: + case WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_0: + case WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_1: + case WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_2: + case WCD938X_DIGITAL_CDC_HPH_GAIN_CTL: + case WCD938X_DIGITAL_CDC_AUX_GAIN_CTL: + case WCD938X_DIGITAL_CDC_EAR_PATH_CTL: + case WCD938X_DIGITAL_CDC_SWR_CLH: + case WCD938X_DIGITAL_SWR_CLH_BYP: + case WCD938X_DIGITAL_CDC_TX0_CTL: + case WCD938X_DIGITAL_CDC_TX1_CTL: + case WCD938X_DIGITAL_CDC_TX2_CTL: + case WCD938X_DIGITAL_CDC_TX_RST: + case WCD938X_DIGITAL_CDC_REQ_CTL: + case WCD938X_DIGITAL_CDC_RST: + case WCD938X_DIGITAL_CDC_AMIC_CTL: + case WCD938X_DIGITAL_CDC_DMIC_CTL: + case WCD938X_DIGITAL_CDC_DMIC1_CTL: + case WCD938X_DIGITAL_CDC_DMIC2_CTL: + case WCD938X_DIGITAL_CDC_DMIC3_CTL: + case WCD938X_DIGITAL_CDC_DMIC4_CTL: + case WCD938X_DIGITAL_EFUSE_PRG_CTL: + case WCD938X_DIGITAL_EFUSE_CTL: + case WCD938X_DIGITAL_CDC_DMIC_RATE_1_2: + case WCD938X_DIGITAL_CDC_DMIC_RATE_3_4: + case WCD938X_DIGITAL_PDM_WD_CTL0: + case WCD938X_DIGITAL_PDM_WD_CTL1: + case WCD938X_DIGITAL_PDM_WD_CTL2: + case WCD938X_DIGITAL_INTR_MODE: + case WCD938X_DIGITAL_INTR_MASK_0: + case WCD938X_DIGITAL_INTR_MASK_1: + case WCD938X_DIGITAL_INTR_MASK_2: + case WCD938X_DIGITAL_INTR_CLEAR_0: + case WCD938X_DIGITAL_INTR_CLEAR_1: + case WCD938X_DIGITAL_INTR_CLEAR_2: + case WCD938X_DIGITAL_INTR_LEVEL_0: + case WCD938X_DIGITAL_INTR_LEVEL_1: + case WCD938X_DIGITAL_INTR_LEVEL_2: + case WCD938X_DIGITAL_INTR_SET_0: + case WCD938X_DIGITAL_INTR_SET_1: + case WCD938X_DIGITAL_INTR_SET_2: + case WCD938X_DIGITAL_INTR_TEST_0: + case WCD938X_DIGITAL_INTR_TEST_1: + case WCD938X_DIGITAL_INTR_TEST_2: + case WCD938X_DIGITAL_TX_MODE_DBG_EN: + case WCD938X_DIGITAL_TX_MODE_DBG_0_1: + case WCD938X_DIGITAL_TX_MODE_DBG_2_3: + case WCD938X_DIGITAL_LB_IN_SEL_CTL: + case WCD938X_DIGITAL_LOOP_BACK_MODE: + case WCD938X_DIGITAL_SWR_DAC_TEST: + case WCD938X_DIGITAL_SWR_HM_TEST_RX_0: + case WCD938X_DIGITAL_SWR_HM_TEST_TX_0: + case WCD938X_DIGITAL_SWR_HM_TEST_RX_1: + case WCD938X_DIGITAL_SWR_HM_TEST_TX_1: + case WCD938X_DIGITAL_SWR_HM_TEST_TX_2: + case WCD938X_DIGITAL_PAD_CTL_SWR_0: + case WCD938X_DIGITAL_PAD_CTL_SWR_1: + case WCD938X_DIGITAL_I2C_CTL: + case WCD938X_DIGITAL_CDC_TX_TANGGU_SW_MODE: + case WCD938X_DIGITAL_EFUSE_TEST_CTL_0: + case WCD938X_DIGITAL_EFUSE_TEST_CTL_1: + case WCD938X_DIGITAL_PAD_CTL_PDM_RX0: + case WCD938X_DIGITAL_PAD_CTL_PDM_RX1: + case WCD938X_DIGITAL_PAD_CTL_PDM_TX0: + case WCD938X_DIGITAL_PAD_CTL_PDM_TX1: + case WCD938X_DIGITAL_PAD_CTL_PDM_TX2: + case WCD938X_DIGITAL_PAD_INP_DIS_0: + case WCD938X_DIGITAL_PAD_INP_DIS_1: + case WCD938X_DIGITAL_DRIVE_STRENGTH_0: + case WCD938X_DIGITAL_DRIVE_STRENGTH_1: + case WCD938X_DIGITAL_DRIVE_STRENGTH_2: + case WCD938X_DIGITAL_RX_DATA_EDGE_CTL: + case WCD938X_DIGITAL_TX_DATA_EDGE_CTL: + case WCD938X_DIGITAL_GPIO_MODE: + case WCD938X_DIGITAL_PIN_CTL_OE: + case WCD938X_DIGITAL_PIN_CTL_DATA_0: + case WCD938X_DIGITAL_PIN_CTL_DATA_1: + case WCD938X_DIGITAL_DIG_DEBUG_CTL: + case WCD938X_DIGITAL_DIG_DEBUG_EN: + case WCD938X_DIGITAL_ANA_CSR_DBG_ADD: + case WCD938X_DIGITAL_ANA_CSR_DBG_CTL: + case WCD938X_DIGITAL_SSP_DBG: + case WCD938X_DIGITAL_SPARE_0: + case WCD938X_DIGITAL_SPARE_1: + case WCD938X_DIGITAL_SPARE_2: + case WCD938X_DIGITAL_TX_REQ_FB_CTL_0: + case WCD938X_DIGITAL_TX_REQ_FB_CTL_1: + case WCD938X_DIGITAL_TX_REQ_FB_CTL_2: + case WCD938X_DIGITAL_TX_REQ_FB_CTL_3: + case WCD938X_DIGITAL_TX_REQ_FB_CTL_4: + case WCD938X_DIGITAL_DEM_BYPASS_DATA0: + case WCD938X_DIGITAL_DEM_BYPASS_DATA1: + case WCD938X_DIGITAL_DEM_BYPASS_DATA2: + case WCD938X_DIGITAL_DEM_BYPASS_DATA3: + return true; + } + + return false; +} + +static bool wcd938x_readonly_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case WCD938X_ANA_MBHC_RESULT_1: + case WCD938X_ANA_MBHC_RESULT_2: + case WCD938X_ANA_MBHC_RESULT_3: + case WCD938X_MBHC_MOISTURE_DET_FSM_STATUS: + case WCD938X_TX_1_2_SAR2_ERR: + case WCD938X_TX_1_2_SAR1_ERR: + case WCD938X_TX_3_4_SAR4_ERR: + case WCD938X_TX_3_4_SAR3_ERR: + case WCD938X_HPH_L_STATUS: + case WCD938X_HPH_R_STATUS: + case WCD938X_HPH_SURGE_HPHLR_SURGE_STATUS: + case WCD938X_EAR_STATUS_REG_1: + case WCD938X_EAR_STATUS_REG_2: + case WCD938X_MBHC_NEW_FSM_STATUS: + case WCD938X_MBHC_NEW_ADC_RESULT: + case WCD938X_DIE_CRACK_DIE_CRK_DET_OUT: + case WCD938X_AUX_INT_STATUS_REG: + case WCD938X_LDORXTX_INT_STATUS: + case WCD938X_DIGITAL_CHIP_ID0: + case WCD938X_DIGITAL_CHIP_ID1: + case WCD938X_DIGITAL_CHIP_ID2: + case WCD938X_DIGITAL_CHIP_ID3: + case WCD938X_DIGITAL_INTR_STATUS_0: + case WCD938X_DIGITAL_INTR_STATUS_1: + case WCD938X_DIGITAL_INTR_STATUS_2: + case WCD938X_DIGITAL_SWR_HM_TEST_0: + case WCD938X_DIGITAL_SWR_HM_TEST_1: + case WCD938X_DIGITAL_EFUSE_T_DATA_0: + case WCD938X_DIGITAL_EFUSE_T_DATA_1: + case WCD938X_DIGITAL_PIN_STATUS_0: + case WCD938X_DIGITAL_PIN_STATUS_1: + case WCD938X_DIGITAL_MODE_STATUS_0: + case WCD938X_DIGITAL_MODE_STATUS_1: + case WCD938X_DIGITAL_EFUSE_REG_0: + case WCD938X_DIGITAL_EFUSE_REG_1: + case WCD938X_DIGITAL_EFUSE_REG_2: + case WCD938X_DIGITAL_EFUSE_REG_3: + case WCD938X_DIGITAL_EFUSE_REG_4: + case WCD938X_DIGITAL_EFUSE_REG_5: + case WCD938X_DIGITAL_EFUSE_REG_6: + case WCD938X_DIGITAL_EFUSE_REG_7: + case WCD938X_DIGITAL_EFUSE_REG_8: + case WCD938X_DIGITAL_EFUSE_REG_9: + case WCD938X_DIGITAL_EFUSE_REG_10: + case WCD938X_DIGITAL_EFUSE_REG_11: + case WCD938X_DIGITAL_EFUSE_REG_12: + case WCD938X_DIGITAL_EFUSE_REG_13: + case WCD938X_DIGITAL_EFUSE_REG_14: + case WCD938X_DIGITAL_EFUSE_REG_15: + case WCD938X_DIGITAL_EFUSE_REG_16: + case WCD938X_DIGITAL_EFUSE_REG_17: + case WCD938X_DIGITAL_EFUSE_REG_18: + case WCD938X_DIGITAL_EFUSE_REG_19: + case WCD938X_DIGITAL_EFUSE_REG_20: + case WCD938X_DIGITAL_EFUSE_REG_21: + case WCD938X_DIGITAL_EFUSE_REG_22: + case WCD938X_DIGITAL_EFUSE_REG_23: + case WCD938X_DIGITAL_EFUSE_REG_24: + case WCD938X_DIGITAL_EFUSE_REG_25: + case WCD938X_DIGITAL_EFUSE_REG_26: + case WCD938X_DIGITAL_EFUSE_REG_27: + case WCD938X_DIGITAL_EFUSE_REG_28: + case WCD938X_DIGITAL_EFUSE_REG_29: + case WCD938X_DIGITAL_EFUSE_REG_30: + case WCD938X_DIGITAL_EFUSE_REG_31: + return true; + } + return false; +} + +static bool wcd938x_readable_register(struct device *dev, unsigned int reg) +{ + bool ret; + + ret = wcd938x_readonly_register(dev, reg); + if (!ret) + return wcd938x_rdwr_register(dev, reg); + + return ret; +} + +static bool wcd938x_writeable_register(struct device *dev, unsigned int reg) +{ + return wcd938x_rdwr_register(dev, reg); +} + +static bool wcd938x_volatile_register(struct device *dev, unsigned int reg) +{ + if (reg <= WCD938X_BASE_ADDRESS) + return 0; + + if (reg == WCD938X_DIGITAL_SWR_TX_CLK_RATE) + return true; + + if (wcd938x_readonly_register(dev, reg)) + return true; + + return false; +} + +struct regmap_config wcd938x_regmap_config = { + .name = "wcd938x_csr", + .reg_bits = 32, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = wcd938x_defaults, + .num_reg_defaults = ARRAY_SIZE(wcd938x_defaults), + .max_register = WCD938X_MAX_REGISTER, + .readable_reg = wcd938x_readable_register, + .writeable_reg = wcd938x_writeable_register, + .volatile_reg = wcd938x_volatile_register, + .can_multi_write = true, +}; +EXPORT_SYMBOL_GPL(wcd938x_regmap_config); + +static const struct regmap_irq wcd938x_irqs[WCD938X_NUM_IRQS] = { + REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_BUTTON_PRESS_DET, 0, 0x01), + REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_BUTTON_RELEASE_DET, 0, 0x02), + REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_ELECT_INS_REM_DET, 0, 0x04), + REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 0, 0x08), + REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_SW_DET, 0, 0x10), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHR_OCP_INT, 0, 0x20), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHR_CNP_INT, 0, 0x40), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHL_OCP_INT, 0, 0x80), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHL_CNP_INT, 1, 0x01), + REGMAP_IRQ_REG(WCD938X_IRQ_EAR_CNP_INT, 1, 0x02), + REGMAP_IRQ_REG(WCD938X_IRQ_EAR_SCD_INT, 1, 0x04), + REGMAP_IRQ_REG(WCD938X_IRQ_AUX_CNP_INT, 1, 0x08), + REGMAP_IRQ_REG(WCD938X_IRQ_AUX_SCD_INT, 1, 0x10), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHL_PDM_WD_INT, 1, 0x20), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHR_PDM_WD_INT, 1, 0x40), + REGMAP_IRQ_REG(WCD938X_IRQ_AUX_PDM_WD_INT, 1, 0x80), + REGMAP_IRQ_REG(WCD938X_IRQ_LDORT_SCD_INT, 2, 0x01), + REGMAP_IRQ_REG(WCD938X_IRQ_MBHC_MOISTURE_INT, 2, 0x02), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHL_SURGE_DET_INT, 2, 0x04), + REGMAP_IRQ_REG(WCD938X_IRQ_HPHR_SURGE_DET_INT, 2, 0x08), +}; + +static struct regmap_irq_chip wcd938x_regmap_irq_chip = { + .name = "wcd938x", + .irqs = wcd938x_irqs, + .num_irqs = ARRAY_SIZE(wcd938x_irqs), + .num_regs = 3, + .status_base = WCD938X_DIGITAL_INTR_STATUS_0, + .mask_base = WCD938X_DIGITAL_INTR_MASK_0, + .type_base = WCD938X_DIGITAL_INTR_LEVEL_0, + .ack_base = WCD938X_DIGITAL_INTR_CLEAR_0, + .use_ack = 1, + .runtime_pm = true, + .irq_drv_data = NULL, +}; + +static int wcd938x_io_init(struct wcd938x_priv *wcd938x) +{ + struct regmap *rm = wcd938x->regmap; + + regmap_update_bits(rm, WCD938X_SLEEP_CTL, 0x0E, 0x0E); + regmap_update_bits(rm, WCD938X_SLEEP_CTL, 0x80, 0x80); + /* 1 msec delay as per HW requirement */ + usleep_range(1000, 1010); + regmap_update_bits(rm, WCD938X_SLEEP_CTL, 0x40, 0x40); + /* 1 msec delay as per HW requirement */ + usleep_range(1000, 1010); + regmap_update_bits(rm, WCD938X_LDORXTX_CONFIG, 0x10, 0x00); + regmap_update_bits(rm, WCD938X_BIAS_VBG_FINE_ADJ, + 0xF0, 0x80); + regmap_update_bits(rm, WCD938X_ANA_BIAS, 0x80, 0x80); + regmap_update_bits(rm, WCD938X_ANA_BIAS, 0x40, 0x40); + /* 10 msec delay as per HW requirement */ + usleep_range(10000, 10010); + + regmap_update_bits(rm, WCD938X_ANA_BIAS, 0x40, 0x00); + regmap_update_bits(rm, WCD938X_HPH_NEW_INT_RDAC_GAIN_CTL, + 0xF0, 0x00); + regmap_update_bits(rm, WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L_NEW, + 0x1F, 0x15); + regmap_update_bits(rm, WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R_NEW, + 0x1F, 0x15); + regmap_update_bits(rm, WCD938X_HPH_REFBUFF_UHQA_CTL, + 0xC0, 0x80); + regmap_update_bits(rm, WCD938X_DIGITAL_CDC_DMIC_CTL, + 0x02, 0x02); + + regmap_update_bits(rm, WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_ULP, + 0xFF, 0x14); + regmap_update_bits(rm, WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_ULP, + 0x1F, 0x08); + + regmap_update_bits(rm, WCD938X_DIGITAL_TX_REQ_FB_CTL_0, 0xFF, 0x55); + regmap_update_bits(rm, WCD938X_DIGITAL_TX_REQ_FB_CTL_1, 0xFF, 0x44); + regmap_update_bits(rm, WCD938X_DIGITAL_TX_REQ_FB_CTL_2, 0xFF, 0x11); + regmap_update_bits(rm, WCD938X_DIGITAL_TX_REQ_FB_CTL_3, 0xFF, 0x00); + regmap_update_bits(rm, WCD938X_DIGITAL_TX_REQ_FB_CTL_4, 0xFF, 0x00); + + /* Set Noise Filter Resistor value */ + regmap_update_bits(rm, WCD938X_MICB1_TEST_CTL_1, 0xE0, 0xE0); + regmap_update_bits(rm, WCD938X_MICB2_TEST_CTL_1, 0xE0, 0xE0); + regmap_update_bits(rm, WCD938X_MICB3_TEST_CTL_1, 0xE0, 0xE0); + regmap_update_bits(rm, WCD938X_MICB4_TEST_CTL_1, 0xE0, 0xE0); + + regmap_update_bits(rm, WCD938X_TX_3_4_TEST_BLK_EN2, 0x01, 0x00); + regmap_update_bits(rm, WCD938X_HPH_SURGE_HPHLR_SURGE_EN, 0xC0, 0xC0); + + return 0; + +} + +static int wcd938x_get_micb_vout_ctl_val(u32 micb_mv) +{ + /* min micbias voltage is 1V and maximum is 2.85V */ + if (micb_mv < 1000 || micb_mv > 2850) + return -EINVAL; + + return (micb_mv - 1000) / 50; +} + +static int wcd938x_set_micbias_data(struct wcd938x_priv *wcd938x) +{ + int vout_ctl_1, vout_ctl_2, vout_ctl_3, vout_ctl_4; + + /* set micbias voltage */ + vout_ctl_1 = wcd938x_get_micb_vout_ctl_val(wcd938x->micb1_mv); + vout_ctl_2 = wcd938x_get_micb_vout_ctl_val(wcd938x->micb2_mv); + vout_ctl_3 = wcd938x_get_micb_vout_ctl_val(wcd938x->micb3_mv); + vout_ctl_4 = wcd938x_get_micb_vout_ctl_val(wcd938x->micb4_mv); + if (vout_ctl_1 < 0 || vout_ctl_2 < 0 || vout_ctl_3 < 0 || vout_ctl_4 < 0) + return -EINVAL; + + regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB1, + WCD938X_MICB_VOUT_MASK, vout_ctl_1); + regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB2, + WCD938X_MICB_VOUT_MASK, vout_ctl_2); + regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB3, + WCD938X_MICB_VOUT_MASK, vout_ctl_3); + regmap_update_bits(wcd938x->regmap, WCD938X_ANA_MICB4, + WCD938X_MICB_VOUT_MASK, vout_ctl_4); + + return 0; +} + +static irqreturn_t wcd938x_wd_handle_irq(int irq, void *data) +{ + return IRQ_HANDLED; +} + +static struct irq_chip wcd_irq_chip = { + .name = "WCD938x", +}; + +static int wcd_irq_chip_map(struct irq_domain *irqd, unsigned int virq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(virq, &wcd_irq_chip, handle_simple_irq); + irq_set_nested_thread(virq, 1); + irq_set_noprobe(virq); + + return 0; +} + +static const struct irq_domain_ops wcd_domain_ops = { + .map = wcd_irq_chip_map, +}; + +static int wcd938x_irq_init(struct wcd938x_priv *wcd, struct device *dev) +{ + + wcd->virq = irq_domain_add_linear(NULL, 1, &wcd_domain_ops, NULL); + if (!(wcd->virq)) { + dev_err(dev, "%s: Failed to add IRQ domain\n", __func__); + return -EINVAL; + } + + return devm_regmap_add_irq_chip(dev, wcd->regmap, + irq_create_mapping(wcd->virq, 0), + IRQF_ONESHOT, 0, &wcd938x_regmap_irq_chip, + &wcd->irq_chip); +} + +static int wcd938x_soc_codec_probe(struct snd_soc_component *component) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + struct device *dev = component->dev; + int ret, i; + + snd_soc_component_init_regmap(component, wcd938x->regmap); + + wcd938x->variant = snd_soc_component_read_field(component, + WCD938X_DIGITAL_EFUSE_REG_0, + WCD938X_ID_MASK); + + wcd938x->clsh_info = wcd_clsh_ctrl_alloc(component, WCD938X); + + wcd938x_io_init(wcd938x); + /* Set all interrupts as edge triggered */ + for (i = 0; i < wcd938x_regmap_irq_chip.num_regs; i++) { + regmap_write(wcd938x->regmap, + (WCD938X_DIGITAL_INTR_LEVEL_0 + i), 0); + } + + ret = wcd938x_irq_init(wcd938x, component->dev); + if (ret) { + dev_err(component->dev, "%s: IRQ init failed: %d\n", + __func__, ret); + return ret; + } + + wcd938x->hphr_pdm_wd_int = regmap_irq_get_virq(wcd938x->irq_chip, + WCD938X_IRQ_HPHR_PDM_WD_INT); + wcd938x->hphl_pdm_wd_int = regmap_irq_get_virq(wcd938x->irq_chip, + WCD938X_IRQ_HPHL_PDM_WD_INT); + wcd938x->aux_pdm_wd_int = regmap_irq_get_virq(wcd938x->irq_chip, + WCD938X_IRQ_AUX_PDM_WD_INT); + + /* Request for watchdog interrupt */ + ret = request_threaded_irq(wcd938x->hphr_pdm_wd_int, NULL, wcd938x_wd_handle_irq, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + "HPHR PDM WD INT", wcd938x); + if (ret) + dev_err(dev, "Failed to request HPHR WD interrupt (%d)\n", ret); + + ret = request_threaded_irq(wcd938x->hphl_pdm_wd_int, NULL, wcd938x_wd_handle_irq, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + "HPHL PDM WD INT", wcd938x); + if (ret) + dev_err(dev, "Failed to request HPHL WD interrupt (%d)\n", ret); + + ret = request_threaded_irq(wcd938x->aux_pdm_wd_int, NULL, wcd938x_wd_handle_irq, + IRQF_ONESHOT | IRQF_TRIGGER_RISING, + "AUX PDM WD INT", wcd938x); + if (ret) + dev_err(dev, "Failed to request Aux WD interrupt (%d)\n", ret); + + /* Disable watchdog interrupt for HPH and AUX */ + disable_irq_nosync(wcd938x->hphr_pdm_wd_int); + disable_irq_nosync(wcd938x->hphl_pdm_wd_int); + disable_irq_nosync(wcd938x->aux_pdm_wd_int); + + return ret; +} + +static const struct snd_soc_component_driver soc_codec_dev_wcd938x = { + .name = "wcd938x_codec", + .probe = wcd938x_soc_codec_probe, +}; + +static void wcd938x_dt_parse_micbias_info(struct device *dev, struct wcd938x_priv *wcd) +{ + struct device_node *np = dev->of_node; + u32 prop_val = 0; + int rc = 0; + + rc = of_property_read_u32(np, "qcom,micbias1-microvolt", &prop_val); + if (!rc) + wcd->micb1_mv = prop_val/1000; + else + dev_info(dev, "%s: Micbias1 DT property not found\n", __func__); + + rc = of_property_read_u32(np, "qcom,micbias2-microvolt", &prop_val); + if (!rc) + wcd->micb2_mv = prop_val/1000; + else + dev_info(dev, "%s: Micbias2 DT property not found\n", __func__); + + rc = of_property_read_u32(np, "qcom,micbias3-microvolt", &prop_val); + if (!rc) + wcd->micb3_mv = prop_val/1000; + else + dev_info(dev, "%s: Micbias3 DT property not found\n", __func__); + + rc = of_property_read_u32(np, "qcom,micbias4-microvolt", &prop_val); + if (!rc) + wcd->micb4_mv = prop_val/1000; + else + dev_info(dev, "%s: Micbias4 DT property not found\n", __func__); +} + +static int wcd938x_populate_dt_data(struct wcd938x_priv *wcd938x, struct device *dev) +{ + int ret; + + wcd938x->reset_gpio = of_get_named_gpio(dev->of_node, "reset-gpios", 0); + if (wcd938x->reset_gpio < 0) { + dev_err(dev, "Failed to get reset gpio: err = %d\n", + wcd938x->reset_gpio); + return wcd938x->reset_gpio; + } + + wcd938x->supplies[0].supply = "vdd-rxtx"; + wcd938x->supplies[1].supply = "vdd-io"; + wcd938x->supplies[2].supply = "vdd-buck"; + wcd938x->supplies[3].supply = "vdd-mic-bias"; + + ret = regulator_bulk_get(dev, WCD938X_MAX_SUPPLY, wcd938x->supplies); + if (ret) { + dev_err(dev, "Failed to get supplies: err = %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(WCD938X_MAX_SUPPLY, wcd938x->supplies); + if (ret) { + dev_err(dev, "Failed to enable supplies: err = %d\n", ret); + return ret; + } + + wcd938x_dt_parse_micbias_info(dev, wcd938x); + + return 0; +} + +static int wcd938x_reset(struct wcd938x_priv *wcd938x) +{ + gpio_direction_output(wcd938x->reset_gpio, 0); + /* 20us sleep required after pulling the reset gpio to LOW */ + usleep_range(20, 30); + gpio_set_value(wcd938x->reset_gpio, 1); + /* 20us sleep required after pulling the reset gpio to HIGH */ + usleep_range(20, 30); + + return 0; +} + +int wcd938x_handle_sdw_irq(struct wcd938x_sdw_priv *wcd) +{ + struct wcd938x_priv *wcd938x = wcd->wcd938x; + struct irq_domain *slave_irq = wcd938x->virq; + u32 sts1, sts2, sts3; + + do { + handle_nested_irq(irq_find_mapping(slave_irq, 0)); + regmap_read(wcd938x->regmap, WCD938X_DIGITAL_INTR_STATUS_0, &sts1); + regmap_read(wcd938x->regmap, WCD938X_DIGITAL_INTR_STATUS_1, &sts2); + regmap_read(wcd938x->regmap, WCD938X_DIGITAL_INTR_STATUS_2, &sts3); + + } while (sts1 || sts2 || sts3); + + return IRQ_HANDLED; +} +EXPORT_SYMBOL_GPL(wcd938x_handle_sdw_irq); + +static struct snd_soc_dai_ops wcd938x_sdw_dai_ops = { +}; + +static struct snd_soc_dai_driver wcd938x_dais[] = { + [0] = { + .name = "wcd938x-sdw-rx", + .playback = { + .stream_name = "WCD AIF1 Playback", + .rates = WCD938X_RATES_MASK | WCD938X_FRAC_RATES_MASK, + .formats = WCD938X_FORMATS_S16_S24_LE, + .rate_max = 192000, + .rate_min = 8000, + .channels_min = 1, + .channels_max = 2, + }, + .ops = &wcd938x_sdw_dai_ops, + }, + [1] = { + .name = "wcd938x-sdw-tx", + .capture = { + .stream_name = "WCD AIF1 Capture", + .rates = WCD938X_RATES_MASK, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rate_min = 8000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &wcd938x_sdw_dai_ops, + }, +}; + +static int wcd938x_bind(struct device *dev) +{ + struct wcd938x_priv *wcd938x = dev_get_drvdata(dev); + int ret; + + ret = component_bind_all(dev, wcd938x); + if (ret) { + dev_err(dev, "%s: Slave bind failed, ret = %d\n", + __func__, ret); + return ret; + } + + ret = wcd938x_set_micbias_data(wcd938x); + if (ret < 0) { + dev_err(dev, "%s: bad micbias pdata\n", __func__); + return ret; + } + + ret = snd_soc_register_component(dev, &soc_codec_dev_wcd938x, + wcd938x_dais, ARRAY_SIZE(wcd938x_dais)); + if (ret) + dev_err(dev, "%s: Codec registration failed\n", + __func__); + + return ret; + +} + +static void wcd938x_unbind(struct device *dev) +{ + struct wcd938x_priv *wcd938x = dev_get_drvdata(dev); + + snd_soc_unregister_component(dev); + component_unbind_all(dev, wcd938x); +} + +static const struct component_master_ops wcd938x_comp_ops = { + .bind = wcd938x_bind, + .unbind = wcd938x_unbind, +}; + +static int wcd938x_compare_of(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +static void wcd938x_release_of(struct device *dev, void *data) +{ + of_node_put(data); +} + +static int wcd938x_add_slave_components(struct wcd938x_priv *wcd938x, + struct device *dev, + struct component_match **matchptr) +{ + struct device_node *np; + + np = dev->of_node; + + wcd938x->rxnode = of_parse_phandle(np, "qcom,rx-device", 0); + if (!wcd938x->rxnode) { + dev_err(dev, "%s: Rx-device node not defined\n", __func__); + return -ENODEV; + } + + of_node_get(wcd938x->rxnode); + component_match_add_release(dev, matchptr, wcd938x_release_of, + wcd938x_compare_of, wcd938x->rxnode); + + wcd938x->txnode = of_parse_phandle(np, "qcom,tx-device", 0); + if (!wcd938x->txnode) { + dev_err(dev, "%s: Tx-device node not defined\n", __func__); + return -ENODEV; + } + of_node_get(wcd938x->txnode); + component_match_add_release(dev, matchptr, wcd938x_release_of, + wcd938x_compare_of, wcd938x->txnode); + return 0; +} + +static int wcd938x_probe(struct platform_device *pdev) +{ + struct component_match *match = NULL; + struct wcd938x_priv *wcd938x = NULL; + struct device *dev = &pdev->dev; + int ret; + + wcd938x = devm_kzalloc(dev, sizeof(struct wcd938x_priv), + GFP_KERNEL); + if (!wcd938x) + return -ENOMEM; + + dev_set_drvdata(dev, wcd938x); + + ret = wcd938x_populate_dt_data(wcd938x, dev); + if (ret) { + dev_err(dev, "%s: Fail to obtain platform data\n", __func__); + return -EINVAL; + } + + ret = wcd938x_add_slave_components(wcd938x, dev, &match); + if (ret) + return ret; + + wcd938x_reset(wcd938x); + + ret = component_master_add_with_match(dev, &wcd938x_comp_ops, match); + if (ret) + return ret; + + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_idle(dev); + + return ret; +} + +static int wcd938x_remove(struct platform_device *pdev) +{ + component_master_del(&pdev->dev, &wcd938x_comp_ops); + + return 0; +} + +static const struct of_device_id wcd938x_dt_match[] = { + { .compatible = "qcom,wcd9380-codec" }, + { .compatible = "qcom,wcd9385-codec" }, + {} +}; +MODULE_DEVICE_TABLE(of, wcd938x_dt_match); + +static struct platform_driver wcd938x_codec_driver = { + .probe = wcd938x_probe, + .remove = wcd938x_remove, + .driver = { + .name = "wcd938x_codec", + .of_match_table = of_match_ptr(wcd938x_dt_match), + .suppress_bind_attrs = true, + }, +}; + +module_platform_driver(wcd938x_codec_driver); +MODULE_DESCRIPTION("WCD938X Codec driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wcd938x.h b/sound/soc/codecs/wcd938x.h new file mode 100644 index 000000000000..efaa4dfc752a --- /dev/null +++ b/sound/soc/codecs/wcd938x.h @@ -0,0 +1,671 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __WCD938X_H__ +#define __WCD938X_H__ +#include <linux/soundwire/sdw.h> +#include <linux/soundwire/sdw_type.h> + +#define WCD938X_BASE_ADDRESS (0x3000) +#define WCD938X_ANA_PAGE_REGISTER (0x3000) +#define WCD938X_ANA_BIAS (0x3001) +#define WCD938X_ANA_RX_SUPPLIES (0x3008) +#define WCD938X_RX_BIAS_EN_MASK BIT(0) +#define WCD938X_REGULATOR_MODE_MASK BIT(1) +#define WCD938X_REGULATOR_MODE_CLASS_AB 1 +#define WCD938X_VNEG_EN_MASK BIT(6) +#define WCD938X_VPOS_EN_MASK BIT(7) +#define WCD938X_ANA_HPH (0x3009) +#define WCD938X_HPHR_REF_EN_MASK BIT(4) +#define WCD938X_HPHL_REF_EN_MASK BIT(5) +#define WCD938X_HPHR_EN_MASK BIT(6) +#define WCD938X_HPHL_EN_MASK BIT(7) +#define WCD938X_ANA_EAR (0x300A) +#define WCD938X_ANA_EAR_COMPANDER_CTL (0x300B) +#define WCD938X_GAIN_OVRD_REG_MASK BIT(7) +#define WCD938X_EAR_GAIN_MASK GENMASK(6, 2) +#define WCD938X_ANA_TX_CH1 (0x300E) +#define WCD938X_ANA_TX_CH2 (0x300F) +#define WCD938X_HPF1_INIT_MASK BIT(6) +#define WCD938X_HPF2_INIT_MASK BIT(5) +#define WCD938X_ANA_TX_CH3 (0x3010) +#define WCD938X_ANA_TX_CH4 (0x3011) +#define WCD938X_HPF3_INIT_MASK BIT(6) +#define WCD938X_HPF4_INIT_MASK BIT(5) +#define WCD938X_ANA_MICB1_MICB2_DSP_EN_LOGIC (0x3012) +#define WCD938X_ANA_MICB3_DSP_EN_LOGIC (0x3013) +#define WCD938X_ANA_MBHC_MECH (0x3014) +#define WCD938X_MBHC_L_DET_EN_MASK BIT(7) +#define WCD938X_MBHC_L_DET_EN BIT(7) +#define WCD938X_MBHC_GND_DET_EN_MASK BIT(6) +#define WCD938X_MBHC_MECH_DETECT_TYPE_MASK BIT(5) +#define WCD938X_MBHC_MECH_DETECT_TYPE_INS 1 +#define WCD938X_MBHC_HPHL_PLUG_TYPE_MASK BIT(4) +#define WCD938X_MBHC_HPHL_PLUG_TYPE_NO 1 +#define WCD938X_MBHC_GND_PLUG_TYPE_MASK BIT(3) +#define WCD938X_MBHC_GND_PLUG_TYPE_NO 1 +#define WCD938X_MBHC_HSL_PULLUP_COMP_EN BIT(2) +#define WCD938X_MBHC_HSG_PULLUP_COMP_EN BIT(1) +#define WCD938X_MBHC_HPHL_100K_TO_GND_EN BIT(0) + +#define WCD938X_ANA_MBHC_ELECT (0x3015) +#define WCD938X_ANA_MBHC_BD_ISRC_CTL_MASK GENMASK(6, 4) +#define WCD938X_ANA_MBHC_BD_ISRC_100UA GENMASK(5, 4) +#define WCD938X_ANA_MBHC_BD_ISRC_OFF 0 +#define WCD938X_ANA_MBHC_BIAS_EN_MASK BIT(0) +#define WCD938X_ANA_MBHC_BIAS_EN BIT(0) +#define WCD938X_ANA_MBHC_ZDET (0x3016) +#define WCD938X_ANA_MBHC_RESULT_1 (0x3017) +#define WCD938X_ANA_MBHC_RESULT_2 (0x3018) +#define WCD938X_ANA_MBHC_RESULT_3 (0x3019) +#define WCD938X_MBHC_BTN_RESULT_MASK GENMASK(2, 0) +#define WCD938X_ANA_MBHC_BTN0 (0x301A) +#define WCD938X_MBHC_BTN_VTH_MASK GENMASK(7, 2) +#define WCD938X_ANA_MBHC_BTN1 (0x301B) +#define WCD938X_ANA_MBHC_BTN2 (0x301C) +#define WCD938X_ANA_MBHC_BTN3 (0x301D) +#define WCD938X_ANA_MBHC_BTN4 (0x301E) +#define WCD938X_ANA_MBHC_BTN5 (0x301F) +#define WCD938X_VTH_MASK GENMASK(7, 2) +#define WCD938X_ANA_MBHC_BTN6 (0x3020) +#define WCD938X_ANA_MBHC_BTN7 (0x3021) +#define WCD938X_ANA_MICB1 (0x3022) +#define WCD938X_MICB_VOUT_MASK GENMASK(5, 0) +#define WCD938X_MICB_EN_MASK GENMASK(7, 6) +#define WCD938X_MICB_DISABLE 0 +#define WCD938X_MICB_ENABLE 1 +#define WCD938X_MICB_PULL_UP 2 +#define WCD938X_MICB_PULL_DOWN 3 +#define WCD938X_ANA_MICB2 (0x3023) +#define WCD938X_ANA_MICB2_ENABLE BIT(6) +#define WCD938X_ANA_MICB2_ENABLE_MASK GENMASK(7, 6) +#define WCD938X_ANA_MICB2_VOUT_MASK GENMASK(5, 0) +#define WCD938X_ANA_MICB2_RAMP (0x3024) +#define WCD938X_RAMP_EN_MASK BIT(7) +#define WCD938X_RAMP_SHIFT_CTRL_MASK GENMASK(4, 2) +#define WCD938X_ANA_MICB3 (0x3025) +#define WCD938X_ANA_MICB4 (0x3026) +#define WCD938X_BIAS_CTL (0x3028) +#define WCD938X_BIAS_VBG_FINE_ADJ (0x3029) +#define WCD938X_LDOL_VDDCX_ADJUST (0x3040) +#define WCD938X_LDOL_DISABLE_LDOL (0x3041) +#define WCD938X_MBHC_CTL_CLK (0x3056) +#define WCD938X_MBHC_CTL_ANA (0x3057) +#define WCD938X_MBHC_CTL_SPARE_1 (0x3058) +#define WCD938X_MBHC_CTL_SPARE_2 (0x3059) +#define WCD938X_MBHC_CTL_BCS (0x305A) +#define WCD938X_MBHC_MOISTURE_DET_FSM_STATUS (0x305B) +#define WCD938X_MBHC_TEST_CTL (0x305C) +#define WCD938X_LDOH_MODE (0x3067) +#define WCD938X_LDOH_EN_MASK BIT(7) +#define WCD938X_LDOH_BIAS (0x3068) +#define WCD938X_LDOH_STB_LOADS (0x3069) +#define WCD938X_LDOH_SLOWRAMP (0x306A) +#define WCD938X_MICB1_TEST_CTL_1 (0x306B) +#define WCD938X_MICB1_TEST_CTL_2 (0x306C) +#define WCD938X_MICB1_TEST_CTL_3 (0x306D) +#define WCD938X_MICB2_TEST_CTL_1 (0x306E) +#define WCD938X_MICB2_TEST_CTL_2 (0x306F) +#define WCD938X_MICB2_TEST_CTL_3 (0x3070) +#define WCD938X_MICB3_TEST_CTL_1 (0x3071) +#define WCD938X_MICB3_TEST_CTL_2 (0x3072) +#define WCD938X_MICB3_TEST_CTL_3 (0x3073) +#define WCD938X_MICB4_TEST_CTL_1 (0x3074) +#define WCD938X_MICB4_TEST_CTL_2 (0x3075) +#define WCD938X_MICB4_TEST_CTL_3 (0x3076) +#define WCD938X_TX_COM_ADC_VCM (0x3077) +#define WCD938X_TX_COM_BIAS_ATEST (0x3078) +#define WCD938X_TX_COM_SPARE1 (0x3079) +#define WCD938X_TX_COM_SPARE2 (0x307A) +#define WCD938X_TX_COM_TXFE_DIV_CTL (0x307B) +#define WCD938X_TX_COM_TXFE_DIV_START (0x307C) +#define WCD938X_TX_COM_SPARE3 (0x307D) +#define WCD938X_TX_COM_SPARE4 (0x307E) +#define WCD938X_TX_1_2_TEST_EN (0x307F) +#define WCD938X_TX_1_2_ADC_IB (0x3080) +#define WCD938X_TX_1_2_ATEST_REFCTL (0x3081) +#define WCD938X_TX_1_2_TEST_CTL (0x3082) +#define WCD938X_TX_1_2_TEST_BLK_EN1 (0x3083) +#define WCD938X_TX_1_2_TXFE1_CLKDIV (0x3084) +#define WCD938X_TX_1_2_SAR2_ERR (0x3085) +#define WCD938X_TX_1_2_SAR1_ERR (0x3086) +#define WCD938X_TX_3_4_TEST_EN (0x3087) +#define WCD938X_TX_3_4_ADC_IB (0x3088) +#define WCD938X_TX_3_4_ATEST_REFCTL (0x3089) +#define WCD938X_TX_3_4_TEST_CTL (0x308A) +#define WCD938X_TX_3_4_TEST_BLK_EN3 (0x308B) +#define WCD938X_TX_3_4_TXFE3_CLKDIV (0x308C) +#define WCD938X_TX_3_4_SAR4_ERR (0x308D) +#define WCD938X_TX_3_4_SAR3_ERR (0x308E) +#define WCD938X_TX_3_4_TEST_BLK_EN2 (0x308F) +#define WCD938X_TX_3_4_TXFE2_CLKDIV (0x3090) +#define WCD938X_TX_3_4_SPARE1 (0x3091) +#define WCD938X_TX_3_4_TEST_BLK_EN4 (0x3092) +#define WCD938X_TX_3_4_TXFE4_CLKDIV (0x3093) +#define WCD938X_TX_3_4_SPARE2 (0x3094) +#define WCD938X_CLASSH_MODE_1 (0x3097) +#define WCD938X_CLASSH_MODE_2 (0x3098) +#define WCD938X_CLASSH_MODE_3 (0x3099) +#define WCD938X_CLASSH_CTRL_VCL_1 (0x309A) +#define WCD938X_CLASSH_CTRL_VCL_2 (0x309B) +#define WCD938X_CLASSH_CTRL_CCL_1 (0x309C) +#define WCD938X_CLASSH_CTRL_CCL_2 (0x309D) +#define WCD938X_CLASSH_CTRL_CCL_3 (0x309E) +#define WCD938X_CLASSH_CTRL_CCL_4 (0x309F) +#define WCD938X_CLASSH_CTRL_CCL_5 (0x30A0) +#define WCD938X_CLASSH_BUCK_TMUX_A_D (0x30A1) +#define WCD938X_CLASSH_BUCK_SW_DRV_CNTL (0x30A2) +#define WCD938X_CLASSH_SPARE (0x30A3) +#define WCD938X_FLYBACK_EN (0x30A4) +#define WCD938X_EN_CUR_DET_MASK BIT(2) +#define WCD938X_FLYBACK_VNEG_CTRL_1 (0x30A5) +#define WCD938X_FLYBACK_VNEG_CTRL_2 (0x30A6) +#define WCD938X_FLYBACK_VNEG_CTRL_3 (0x30A7) +#define WCD938X_FLYBACK_VNEG_CTRL_4 (0x30A8) +#define WCD938X_FLYBACK_VNEG_CTRL_5 (0x30A9) +#define WCD938X_FLYBACK_VNEG_CTRL_6 (0x30AA) +#define WCD938X_FLYBACK_VNEG_CTRL_7 (0x30AB) +#define WCD938X_FLYBACK_VNEG_CTRL_8 (0x30AC) +#define WCD938X_FLYBACK_VNEG_CTRL_9 (0x30AD) +#define WCD938X_FLYBACK_VNEGDAC_CTRL_1 (0x30AE) +#define WCD938X_FLYBACK_VNEGDAC_CTRL_2 (0x30AF) +#define WCD938X_FLYBACK_VNEGDAC_CTRL_3 (0x30B0) +#define WCD938X_FLYBACK_CTRL_1 (0x30B1) +#define WCD938X_FLYBACK_TEST_CTL (0x30B2) +#define WCD938X_RX_AUX_SW_CTL (0x30B3) +#define WCD938X_RX_PA_AUX_IN_CONN (0x30B4) +#define WCD938X_RX_TIMER_DIV (0x30B5) +#define WCD938X_RX_OCP_CTL (0x30B6) +#define WCD938X_RX_OCP_COUNT (0x30B7) +#define WCD938X_RX_BIAS_EAR_DAC (0x30B8) +#define WCD938X_RX_BIAS_EAR_AMP (0x30B9) +#define WCD938X_RX_BIAS_HPH_LDO (0x30BA) +#define WCD938X_RX_BIAS_HPH_PA (0x30BB) +#define WCD938X_RX_BIAS_HPH_RDACBUFF_CNP2 (0x30BC) +#define WCD938X_RX_BIAS_HPH_RDAC_LDO (0x30BD) +#define WCD938X_RX_BIAS_HPH_CNP1 (0x30BE) +#define WCD938X_RX_BIAS_HPH_LOWPOWER (0x30BF) +#define WCD938X_RX_BIAS_AUX_DAC (0x30C0) +#define WCD938X_RX_BIAS_AUX_AMP (0x30C1) +#define WCD938X_RX_BIAS_VNEGDAC_BLEEDER (0x30C2) +#define WCD938X_RX_BIAS_MISC (0x30C3) +#define WCD938X_RX_BIAS_BUCK_RST (0x30C4) +#define WCD938X_RX_BIAS_BUCK_VREF_ERRAMP (0x30C5) +#define WCD938X_RX_BIAS_FLYB_ERRAMP (0x30C6) +#define WCD938X_RX_BIAS_FLYB_BUFF (0x30C7) +#define WCD938X_RX_BIAS_FLYB_MID_RST (0x30C8) +#define WCD938X_HPH_L_STATUS (0x30C9) +#define WCD938X_HPH_R_STATUS (0x30CA) +#define WCD938X_HPH_CNP_EN (0x30CB) +#define WCD938X_HPH_CNP_WG_CTL (0x30CC) +#define WCD938X_HPH_CNP_WG_TIME (0x30CD) +#define WCD938X_HPH_OCP_CTL (0x30CE) +#define WCD938X_HPH_AUTO_CHOP (0x30CF) +#define WCD938X_HPH_CHOP_CTL (0x30D0) +#define WCD938X_HPH_PA_CTL1 (0x30D1) +#define WCD938X_HPH_PA_CTL2 (0x30D2) +#define WCD938X_HPHPA_GND_R_MASK BIT(6) +#define WCD938X_HPHPA_GND_L_MASK BIT(4) +#define WCD938X_HPH_L_EN (0x30D3) +#define WCD938X_HPH_L_TEST (0x30D4) +#define WCD938X_HPH_L_ATEST (0x30D5) +#define WCD938X_HPH_R_EN (0x30D6) +#define WCD938X_GAIN_SRC_SEL_MASK BIT(5) +#define WCD938X_GAIN_SRC_SEL_REGISTER 1 +#define WCD938X_HPH_R_TEST (0x30D7) +#define WCD938X_HPH_R_ATEST (0x30D8) +#define WCD938X_HPHPA_GND_OVR_MASK BIT(1) +#define WCD938X_HPH_RDAC_CLK_CTL1 (0x30D9) +#define WCD938X_CHOP_CLK_EN_MASK BIT(7) +#define WCD938X_HPH_RDAC_CLK_CTL2 (0x30DA) +#define WCD938X_HPH_RDAC_LDO_CTL (0x30DB) +#define WCD938X_HPH_RDAC_CHOP_CLK_LP_CTL (0x30DC) +#define WCD938X_HPH_REFBUFF_UHQA_CTL (0x30DD) +#define WCD938X_HPH_REFBUFF_LP_CTL (0x30DE) +#define WCD938X_PREREF_FLIT_BYPASS_MASK BIT(0) +#define WCD938X_HPH_L_DAC_CTL (0x30DF) +#define WCD938X_HPH_R_DAC_CTL (0x30E0) +#define WCD938X_HPH_SURGE_HPHLR_SURGE_COMP_SEL (0x30E1) +#define WCD938X_HPH_SURGE_HPHLR_SURGE_EN (0x30E2) +#define WCD938X_HPH_SURGE_HPHLR_SURGE_MISC1 (0x30E3) +#define WCD938X_HPH_SURGE_HPHLR_SURGE_STATUS (0x30E4) +#define WCD938X_EAR_EAR_EN_REG (0x30E9) +#define WCD938X_EAR_EAR_PA_CON (0x30EA) +#define WCD938X_EAR_EAR_SP_CON (0x30EB) +#define WCD938X_EAR_EAR_DAC_CON (0x30EC) +#define WCD938X_DAC_SAMPLE_EDGE_SEL_MASK BIT(7) +#define WCD938X_EAR_EAR_CNP_FSM_CON (0x30ED) +#define WCD938X_EAR_TEST_CTL (0x30EE) +#define WCD938X_EAR_STATUS_REG_1 (0x30EF) +#define WCD938X_EAR_STATUS_REG_2 (0x30F0) +#define WCD938X_ANA_NEW_PAGE_REGISTER (0x3100) +#define WCD938X_HPH_NEW_ANA_HPH2 (0x3101) +#define WCD938X_HPH_NEW_ANA_HPH3 (0x3102) +#define WCD938X_SLEEP_CTL (0x3103) +#define WCD938X_SLEEP_WATCHDOG_CTL (0x3104) +#define WCD938X_MBHC_NEW_ELECT_REM_CLAMP_CTL (0x311F) +#define WCD938X_MBHC_NEW_CTL_1 (0x3120) +#define WCD938X_MBHC_CTL_RCO_EN_MASK BIT(7) +#define WCD938X_MBHC_CTL_RCO_EN BIT(7) +#define WCD938X_MBHC_BTN_DBNC_MASK GENMASK(1, 0) +#define WCD938X_MBHC_BTN_DBNC_T_16_MS 0x2 +#define WCD938X_MBHC_NEW_CTL_2 (0x3121) +#define WCD938X_M_RTH_CTL_MASK GENMASK(3, 2) +#define WCD938X_MBHC_HS_VREF_CTL_MASK GENMASK(1, 0) +#define WCD938X_MBHC_HS_VREF_1P5_V 0x1 +#define WCD938X_MBHC_NEW_PLUG_DETECT_CTL (0x3122) +#define WCD938X_MBHC_DBNC_TIMER_INSREM_DBNC_T_96_MS 0x6 + +#define WCD938X_MBHC_NEW_ZDET_ANA_CTL (0x3123) +#define WCD938X_ZDET_RANGE_CTL_MASK GENMASK(3, 0) +#define WCD938X_ZDET_MAXV_CTL_MASK GENMASK(6, 4) +#define WCD938X_MBHC_NEW_ZDET_RAMP_CTL (0x3124) +#define WCD938X_MBHC_NEW_FSM_STATUS (0x3125) +#define WCD938X_MBHC_NEW_ADC_RESULT (0x3126) +#define WCD938X_TX_NEW_AMIC_MUX_CFG (0x3127) +#define WCD938X_AUX_AUXPA (0x3128) +#define WCD938X_AUXPA_CLK_EN_MASK BIT(4) +#define WCD938X_LDORXTX_MODE (0x3129) +#define WCD938X_LDORXTX_CONFIG (0x312A) +#define WCD938X_DIE_CRACK_DIE_CRK_DET_EN (0x312C) +#define WCD938X_DIE_CRACK_DIE_CRK_DET_OUT (0x312D) +#define WCD938X_HPH_NEW_INT_RDAC_GAIN_CTL (0x3132) +#define WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L (0x3133) +#define WCD938X_HPH_NEW_INT_RDAC_VREF_CTL (0x3134) +#define WCD938X_HPH_NEW_INT_RDAC_OVERRIDE_CTL (0x3135) +#define WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R (0x3136) +#define WCD938X_HPH_RES_DIV_MASK GENMASK(4, 0) +#define WCD938X_HPH_NEW_INT_PA_MISC1 (0x3137) +#define WCD938X_HPH_NEW_INT_PA_MISC2 (0x3138) +#define WCD938X_HPH_NEW_INT_PA_RDAC_MISC (0x3139) +#define WCD938X_HPH_NEW_INT_HPH_TIMER1 (0x313A) +#define WCD938X_AUTOCHOP_TIMER_EN BIT(1) +#define WCD938X_HPH_NEW_INT_HPH_TIMER2 (0x313B) +#define WCD938X_HPH_NEW_INT_HPH_TIMER3 (0x313C) +#define WCD938X_HPH_NEW_INT_HPH_TIMER4 (0x313D) +#define WCD938X_HPH_NEW_INT_PA_RDAC_MISC2 (0x313E) +#define WCD938X_HPH_NEW_INT_PA_RDAC_MISC3 (0x313F) +#define WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L_NEW (0x3140) +#define WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R_NEW (0x3141) +#define WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_LOHIFI (0x3145) +#define WCD938X_RX_NEW_INT_HPH_RDAC_BIAS_ULP (0x3146) +#define WCD938X_RX_NEW_INT_HPH_RDAC_LDO_LP (0x3147) +#define WCD938X_MBHC_NEW_INT_MOISTURE_DET_DC_CTRL (0x31AF) +#define WCD938X_MBHC_NEW_INT_MOISTURE_DET_POLLING_CTRL (0x31B0) +#define WCD938X_MOISTURE_EN_POLLING_MASK BIT(2) +#define WCD938X_MBHC_NEW_INT_MECH_DET_CURRENT (0x31B1) +#define WCD938X_HSDET_PULLUP_C_MASK GENMASK(4, 0) +#define WCD938X_MBHC_NEW_INT_SPARE_2 (0x31B2) +#define WCD938X_EAR_INT_NEW_EAR_CHOPPER_CON (0x31B7) +#define WCD938X_EAR_INT_NEW_CNP_VCM_CON1 (0x31B8) +#define WCD938X_EAR_INT_NEW_CNP_VCM_CON2 (0x31B9) +#define WCD938X_EAR_INT_NEW_EAR_DYNAMIC_BIAS (0x31BA) +#define WCD938X_AUX_INT_EN_REG (0x31BD) +#define WCD938X_AUX_INT_PA_CTRL (0x31BE) +#define WCD938X_AUX_INT_SP_CTRL (0x31BF) +#define WCD938X_AUX_INT_DAC_CTRL (0x31C0) +#define WCD938X_AUX_INT_CLK_CTRL (0x31C1) +#define WCD938X_AUX_INT_TEST_CTRL (0x31C2) +#define WCD938X_AUX_INT_STATUS_REG (0x31C3) +#define WCD938X_AUX_INT_MISC (0x31C4) +#define WCD938X_LDORXTX_INT_BIAS (0x31C5) +#define WCD938X_LDORXTX_INT_STB_LOADS_DTEST (0x31C6) +#define WCD938X_LDORXTX_INT_TEST0 (0x31C7) +#define WCD938X_LDORXTX_INT_STARTUP_TIMER (0x31C8) +#define WCD938X_LDORXTX_INT_TEST1 (0x31C9) +#define WCD938X_LDORXTX_INT_STATUS (0x31CA) +#define WCD938X_SLEEP_INT_WATCHDOG_CTL_1 (0x31D0) +#define WCD938X_SLEEP_INT_WATCHDOG_CTL_2 (0x31D1) +#define WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT1 (0x31D3) +#define WCD938X_DIE_CRACK_INT_DIE_CRK_DET_INT2 (0x31D4) +#define WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L2 (0x31D5) +#define WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L1 (0x31D6) +#define WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_L0 (0x31D7) +#define WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP1P2M (0x31D8) +#define WCD938X_TX_COM_NEW_INT_TXFE_DIVSTOP_ULP0P6M (0x31D9) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L2L1 (0x31DA) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_L0 (0x31DB) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG1_ULP (0x31DC) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L2L1 (0x31DD) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_L0 (0x31DE) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_ULP (0x31DF) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_L2L1L0 (0x31E0) +#define WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2CASC_ULP (0x31E1) +#define WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L2L1 (0x31E2) +#define WCD938X_TX_COM_NEW_INT_TXADC_SCBIAS_L0ULP (0x31E3) +#define WCD938X_TX_COM_NEW_INT_TXADC_INT_L2 (0x31E4) +#define WCD938X_TX_COM_NEW_INT_TXADC_INT_L1 (0x31E5) +#define WCD938X_TX_COM_NEW_INT_TXADC_INT_L0 (0x31E6) +#define WCD938X_TX_COM_NEW_INT_TXADC_INT_ULP (0x31E7) +#define WCD938X_DIGITAL_PAGE_REGISTER (0x3400) +#define WCD938X_DIGITAL_CHIP_ID0 (0x3401) +#define WCD938X_DIGITAL_CHIP_ID1 (0x3402) +#define WCD938X_DIGITAL_CHIP_ID2 (0x3403) +#define WCD938X_DIGITAL_CHIP_ID3 (0x3404) +#define WCD938X_DIGITAL_SWR_TX_CLK_RATE (0x3405) +#define WCD938X_DIGITAL_CDC_RST_CTL (0x3406) +#define WCD938X_DIGITAL_TOP_CLK_CFG (0x3407) +#define WCD938X_DIGITAL_CDC_ANA_CLK_CTL (0x3408) +#define WCD938X_ANA_RX_CLK_EN_MASK BIT(0) +#define WCD938X_ANA_RX_DIV2_CLK_EN_MASK BIT(1) +#define WCD938X_ANA_RX_DIV4_CLK_EN_MASK BIT(2) +#define WCD938X_ANA_TX_CLK_EN_MASK BIT(3) +#define WCD938X_ANA_TX_DIV2_CLK_EN_MASK BIT(4) +#define WCD938X_ANA_TX_DIV4_CLK_EN_MASK BIT(5) +#define WCD938X_DIGITAL_CDC_DIG_CLK_CTL (0x3409) +#define WCD938X_TXD3_CLK_EN_MASK BIT(7) +#define WCD938X_TXD2_CLK_EN_MASK BIT(6) +#define WCD938X_TXD1_CLK_EN_MASK BIT(5) +#define WCD938X_TXD0_CLK_EN_MASK BIT(4) +#define WCD938X_TX_CLK_EN_MASK GENMASK(7, 4) +#define WCD938X_RXD2_CLK_EN_MASK BIT(2) +#define WCD938X_RXD1_CLK_EN_MASK BIT(1) +#define WCD938X_RXD0_CLK_EN_MASK BIT(0) +#define WCD938X_DIGITAL_SWR_RST_EN (0x340A) +#define WCD938X_DIGITAL_CDC_PATH_MODE (0x340B) +#define WCD938X_DIGITAL_CDC_RX_RST (0x340C) +#define WCD938X_DIGITAL_CDC_RX0_CTL (0x340D) +#define WCD938X_DEM_DITHER_ENABLE_MASK BIT(6) +#define WCD938X_DIGITAL_CDC_RX1_CTL (0x340E) +#define WCD938X_DIGITAL_CDC_RX2_CTL (0x340F) +#define WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1 (0x3410) +#define WCD938X_TXD0_MODE_MASK GENMASK(3, 0) +#define WCD938X_TXD1_MODE_MASK GENMASK(7, 4) +#define WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3 (0x3411) +#define WCD938X_TXD2_MODE_MASK GENMASK(3, 0) +#define WCD938X_TXD3_MODE_MASK GENMASK(7, 4) +#define WCD938X_DIGITAL_CDC_COMP_CTL_0 (0x3414) +#define WCD938X_HPHR_COMP_EN_MASK BIT(0) +#define WCD938X_HPHL_COMP_EN_MASK BIT(1) +#define WCD938X_DIGITAL_CDC_ANA_TX_CLK_CTL (0x3417) +#define WCD938X_TX_SC_CLK_EN_MASK BIT(0) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A1_0 (0x3418) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A1_1 (0x3419) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A2_0 (0x341A) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A2_1 (0x341B) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A3_0 (0x341C) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A3_1 (0x341D) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A4_0 (0x341E) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A4_1 (0x341F) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A5_0 (0x3420) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A5_1 (0x3421) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A6_0 (0x3422) +#define WCD938X_DIGITAL_CDC_HPH_DSM_A7_0 (0x3423) +#define WCD938X_DIGITAL_CDC_HPH_DSM_C_0 (0x3424) +#define WCD938X_DIGITAL_CDC_HPH_DSM_C_1 (0x3425) +#define WCD938X_DIGITAL_CDC_HPH_DSM_C_2 (0x3426) +#define WCD938X_DIGITAL_CDC_HPH_DSM_C_3 (0x3427) +#define WCD938X_DIGITAL_CDC_HPH_DSM_R1 (0x3428) +#define WCD938X_DIGITAL_CDC_HPH_DSM_R2 (0x3429) +#define WCD938X_DIGITAL_CDC_HPH_DSM_R3 (0x342A) +#define WCD938X_DIGITAL_CDC_HPH_DSM_R4 (0x342B) +#define WCD938X_DIGITAL_CDC_HPH_DSM_R5 (0x342C) +#define WCD938X_DIGITAL_CDC_HPH_DSM_R6 (0x342D) +#define WCD938X_DIGITAL_CDC_HPH_DSM_R7 (0x342E) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A1_0 (0x342F) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A1_1 (0x3430) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A2_0 (0x3431) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A2_1 (0x3432) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A3_0 (0x3433) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A3_1 (0x3434) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A4_0 (0x3435) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A4_1 (0x3436) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A5_0 (0x3437) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A5_1 (0x3438) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A6_0 (0x3439) +#define WCD938X_DIGITAL_CDC_AUX_DSM_A7_0 (0x343A) +#define WCD938X_DIGITAL_CDC_AUX_DSM_C_0 (0x343B) +#define WCD938X_DIGITAL_CDC_AUX_DSM_C_1 (0x343C) +#define WCD938X_DIGITAL_CDC_AUX_DSM_C_2 (0x343D) +#define WCD938X_DIGITAL_CDC_AUX_DSM_C_3 (0x343E) +#define WCD938X_DIGITAL_CDC_AUX_DSM_R1 (0x343F) +#define WCD938X_DIGITAL_CDC_AUX_DSM_R2 (0x3440) +#define WCD938X_DIGITAL_CDC_AUX_DSM_R3 (0x3441) +#define WCD938X_DIGITAL_CDC_AUX_DSM_R4 (0x3442) +#define WCD938X_DIGITAL_CDC_AUX_DSM_R5 (0x3443) +#define WCD938X_DIGITAL_CDC_AUX_DSM_R6 (0x3444) +#define WCD938X_DIGITAL_CDC_AUX_DSM_R7 (0x3445) +#define WCD938X_DIGITAL_CDC_HPH_GAIN_RX_0 (0x3446) +#define WCD938X_DIGITAL_CDC_HPH_GAIN_RX_1 (0x3447) +#define WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_0 (0x3448) +#define WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_1 (0x3449) +#define WCD938X_DIGITAL_CDC_HPH_GAIN_DSD_2 (0x344A) +#define WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_0 (0x344B) +#define WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_1 (0x344C) +#define WCD938X_DIGITAL_CDC_AUX_GAIN_DSD_2 (0x344D) +#define WCD938X_DIGITAL_CDC_HPH_GAIN_CTL (0x344E) +#define WCD938X_HPHL_RX_EN_MASK BIT(2) +#define WCD938X_HPHR_RX_EN_MASK BIT(3) +#define WCD938X_DIGITAL_CDC_AUX_GAIN_CTL (0x344F) +#define WCD938X_AUX_EN_MASK BIT(0) +#define WCD938X_DIGITAL_CDC_EAR_PATH_CTL (0x3450) +#define WCD938X_DIGITAL_CDC_SWR_CLH (0x3451) +#define WCD938X_DIGITAL_SWR_CLH_BYP (0x3452) +#define WCD938X_DIGITAL_CDC_TX0_CTL (0x3453) +#define WCD938X_DIGITAL_CDC_TX1_CTL (0x3454) +#define WCD938X_DIGITAL_CDC_TX2_CTL (0x3455) +#define WCD938X_DIGITAL_CDC_TX_RST (0x3456) +#define WCD938X_DIGITAL_CDC_REQ_CTL (0x3457) +#define WCD938X_FS_RATE_4P8_MASK BIT(1) +#define WCD938X_NO_NOTCH_MASK BIT(0) +#define WCD938X_DIGITAL_CDC_RST (0x3458) +#define WCD938X_DIGITAL_CDC_AMIC_CTL (0x345A) +#define WCD938X_AMIC1_IN_SEL_DMIC 0 +#define WCD938X_AMIC1_IN_SEL_AMIC 0 +#define WCD938X_AMIC1_IN_SEL_MASK BIT(0) +#define WCD938X_AMIC3_IN_SEL_MASK BIT(1) +#define WCD938X_AMIC4_IN_SEL_MASK BIT(2) +#define WCD938X_AMIC5_IN_SEL_MASK BIT(3) +#define WCD938X_DIGITAL_CDC_DMIC_CTL (0x345B) +#define WCD938X_DMIC_CLK_SCALING_EN_MASK GENMASK(2, 1) +#define WCD938X_DIGITAL_CDC_DMIC1_CTL (0x345C) +#define WCD938X_DMIC_CLK_EN_MASK BIT(3) +#define WCD938X_DIGITAL_CDC_DMIC2_CTL (0x345D) +#define WCD938X_DIGITAL_CDC_DMIC3_CTL (0x345E) +#define WCD938X_DIGITAL_CDC_DMIC4_CTL (0x345F) +#define WCD938X_DIGITAL_EFUSE_PRG_CTL (0x3460) +#define WCD938X_DIGITAL_EFUSE_CTL (0x3461) +#define WCD938X_DIGITAL_CDC_DMIC_RATE_1_2 (0x3462) +#define WCD938X_DIGITAL_CDC_DMIC_RATE_3_4 (0x3463) +#define WCD938X_DMIC1_RATE_MASK GENMASK(3, 0) +#define WCD938X_DMIC2_RATE_MASK GENMASK(7, 4) +#define WCD938X_DMIC3_RATE_MASK GENMASK(3, 0) +#define WCD938X_DMIC4_RATE_MASK GENMASK(7, 4) +#define WCD938X_DMIC4_RATE_2P4MHZ 3 + +#define WCD938X_DIGITAL_PDM_WD_CTL0 (0x3465) +#define WCD938X_PDM_WD_EN_MASK GENMASK(2, 0) +#define WCD938X_DIGITAL_PDM_WD_CTL1 (0x3466) +#define WCD938X_DIGITAL_PDM_WD_CTL2 (0x3467) +#define WCD938X_AUX_PDM_WD_EN_MASK GENMASK(2, 0) +#define WCD938X_DIGITAL_INTR_MODE (0x346A) +#define WCD938X_DIGITAL_INTR_MASK_0 (0x346B) +#define WCD938X_DIGITAL_INTR_MASK_1 (0x346C) +#define WCD938X_DIGITAL_INTR_MASK_2 (0x346D) +#define WCD938X_DIGITAL_INTR_STATUS_0 (0x346E) +#define WCD938X_DIGITAL_INTR_STATUS_1 (0x346F) +#define WCD938X_DIGITAL_INTR_STATUS_2 (0x3470) +#define WCD938X_DIGITAL_INTR_CLEAR_0 (0x3471) +#define WCD938X_DIGITAL_INTR_CLEAR_1 (0x3472) +#define WCD938X_DIGITAL_INTR_CLEAR_2 (0x3473) +#define WCD938X_DIGITAL_INTR_LEVEL_0 (0x3474) +#define WCD938X_DIGITAL_INTR_LEVEL_1 (0x3475) +#define WCD938X_DIGITAL_INTR_LEVEL_2 (0x3476) +#define WCD938X_DIGITAL_INTR_SET_0 (0x3477) +#define WCD938X_DIGITAL_INTR_SET_1 (0x3478) +#define WCD938X_DIGITAL_INTR_SET_2 (0x3479) +#define WCD938X_DIGITAL_INTR_TEST_0 (0x347A) +#define WCD938X_DIGITAL_INTR_TEST_1 (0x347B) +#define WCD938X_DIGITAL_INTR_TEST_2 (0x347C) +#define WCD938X_DIGITAL_TX_MODE_DBG_EN (0x347F) +#define WCD938X_DIGITAL_TX_MODE_DBG_0_1 (0x3480) +#define WCD938X_DIGITAL_TX_MODE_DBG_2_3 (0x3481) +#define WCD938X_DIGITAL_LB_IN_SEL_CTL (0x3482) +#define WCD938X_DIGITAL_LOOP_BACK_MODE (0x3483) +#define WCD938X_DIGITAL_SWR_DAC_TEST (0x3484) +#define WCD938X_DIGITAL_SWR_HM_TEST_RX_0 (0x3485) +#define WCD938X_DIGITAL_SWR_HM_TEST_TX_0 (0x3486) +#define WCD938X_DIGITAL_SWR_HM_TEST_RX_1 (0x3487) +#define WCD938X_DIGITAL_SWR_HM_TEST_TX_1 (0x3488) +#define WCD938X_DIGITAL_SWR_HM_TEST_TX_2 (0x3489) +#define WCD938X_DIGITAL_SWR_HM_TEST_0 (0x348A) +#define WCD938X_DIGITAL_SWR_HM_TEST_1 (0x348B) +#define WCD938X_DIGITAL_PAD_CTL_SWR_0 (0x348C) +#define WCD938X_DIGITAL_PAD_CTL_SWR_1 (0x348D) +#define WCD938X_DIGITAL_I2C_CTL (0x348E) +#define WCD938X_DIGITAL_CDC_TX_TANGGU_SW_MODE (0x348F) +#define WCD938X_DIGITAL_EFUSE_TEST_CTL_0 (0x3490) +#define WCD938X_DIGITAL_EFUSE_TEST_CTL_1 (0x3491) +#define WCD938X_DIGITAL_EFUSE_T_DATA_0 (0x3492) +#define WCD938X_DIGITAL_EFUSE_T_DATA_1 (0x3493) +#define WCD938X_DIGITAL_PAD_CTL_PDM_RX0 (0x3494) +#define WCD938X_DIGITAL_PAD_CTL_PDM_RX1 (0x3495) +#define WCD938X_DIGITAL_PAD_CTL_PDM_TX0 (0x3496) +#define WCD938X_DIGITAL_PAD_CTL_PDM_TX1 (0x3497) +#define WCD938X_DIGITAL_PAD_CTL_PDM_TX2 (0x3498) +#define WCD938X_DIGITAL_PAD_INP_DIS_0 (0x3499) +#define WCD938X_DIGITAL_PAD_INP_DIS_1 (0x349A) +#define WCD938X_DIGITAL_DRIVE_STRENGTH_0 (0x349B) +#define WCD938X_DIGITAL_DRIVE_STRENGTH_1 (0x349C) +#define WCD938X_DIGITAL_DRIVE_STRENGTH_2 (0x349D) +#define WCD938X_DIGITAL_RX_DATA_EDGE_CTL (0x349E) +#define WCD938X_DIGITAL_TX_DATA_EDGE_CTL (0x349F) +#define WCD938X_DIGITAL_GPIO_MODE (0x34A0) +#define WCD938X_DIGITAL_PIN_CTL_OE (0x34A1) +#define WCD938X_DIGITAL_PIN_CTL_DATA_0 (0x34A2) +#define WCD938X_DIGITAL_PIN_CTL_DATA_1 (0x34A3) +#define WCD938X_DIGITAL_PIN_STATUS_0 (0x34A4) +#define WCD938X_DIGITAL_PIN_STATUS_1 (0x34A5) +#define WCD938X_DIGITAL_DIG_DEBUG_CTL (0x34A6) +#define WCD938X_DIGITAL_DIG_DEBUG_EN (0x34A7) +#define WCD938X_DIGITAL_ANA_CSR_DBG_ADD (0x34A8) +#define WCD938X_DIGITAL_ANA_CSR_DBG_CTL (0x34A9) +#define WCD938X_DIGITAL_SSP_DBG (0x34AA) +#define WCD938X_DIGITAL_MODE_STATUS_0 (0x34AB) +#define WCD938X_DIGITAL_MODE_STATUS_1 (0x34AC) +#define WCD938X_DIGITAL_SPARE_0 (0x34AD) +#define WCD938X_DIGITAL_SPARE_1 (0x34AE) +#define WCD938X_DIGITAL_SPARE_2 (0x34AF) +#define WCD938X_DIGITAL_EFUSE_REG_0 (0x34B0) +#define WCD938X_ID_MASK GENMASK(4, 1) +#define WCD938X_DIGITAL_EFUSE_REG_1 (0x34B1) +#define WCD938X_DIGITAL_EFUSE_REG_2 (0x34B2) +#define WCD938X_DIGITAL_EFUSE_REG_3 (0x34B3) +#define WCD938X_DIGITAL_EFUSE_REG_4 (0x34B4) +#define WCD938X_DIGITAL_EFUSE_REG_5 (0x34B5) +#define WCD938X_DIGITAL_EFUSE_REG_6 (0x34B6) +#define WCD938X_DIGITAL_EFUSE_REG_7 (0x34B7) +#define WCD938X_DIGITAL_EFUSE_REG_8 (0x34B8) +#define WCD938X_DIGITAL_EFUSE_REG_9 (0x34B9) +#define WCD938X_DIGITAL_EFUSE_REG_10 (0x34BA) +#define WCD938X_DIGITAL_EFUSE_REG_11 (0x34BB) +#define WCD938X_DIGITAL_EFUSE_REG_12 (0x34BC) +#define WCD938X_DIGITAL_EFUSE_REG_13 (0x34BD) +#define WCD938X_DIGITAL_EFUSE_REG_14 (0x34BE) +#define WCD938X_DIGITAL_EFUSE_REG_15 (0x34BF) +#define WCD938X_DIGITAL_EFUSE_REG_16 (0x34C0) +#define WCD938X_DIGITAL_EFUSE_REG_17 (0x34C1) +#define WCD938X_DIGITAL_EFUSE_REG_18 (0x34C2) +#define WCD938X_DIGITAL_EFUSE_REG_19 (0x34C3) +#define WCD938X_DIGITAL_EFUSE_REG_20 (0x34C4) +#define WCD938X_DIGITAL_EFUSE_REG_21 (0x34C5) +#define WCD938X_DIGITAL_EFUSE_REG_22 (0x34C6) +#define WCD938X_DIGITAL_EFUSE_REG_23 (0x34C7) +#define WCD938X_DIGITAL_EFUSE_REG_24 (0x34C8) +#define WCD938X_DIGITAL_EFUSE_REG_25 (0x34C9) +#define WCD938X_DIGITAL_EFUSE_REG_26 (0x34CA) +#define WCD938X_DIGITAL_EFUSE_REG_27 (0x34CB) +#define WCD938X_DIGITAL_EFUSE_REG_28 (0x34CC) +#define WCD938X_DIGITAL_EFUSE_REG_29 (0x34CD) +#define WCD938X_DIGITAL_EFUSE_REG_30 (0x34CE) +#define WCD938X_DIGITAL_EFUSE_REG_31 (0x34CF) +#define WCD938X_DIGITAL_TX_REQ_FB_CTL_0 (0x34D0) +#define WCD938X_DIGITAL_TX_REQ_FB_CTL_1 (0x34D1) +#define WCD938X_DIGITAL_TX_REQ_FB_CTL_2 (0x34D2) +#define WCD938X_DIGITAL_TX_REQ_FB_CTL_3 (0x34D3) +#define WCD938X_DIGITAL_TX_REQ_FB_CTL_4 (0x34D4) +#define WCD938X_DIGITAL_DEM_BYPASS_DATA0 (0x34D5) +#define WCD938X_DIGITAL_DEM_BYPASS_DATA1 (0x34D6) +#define WCD938X_DIGITAL_DEM_BYPASS_DATA2 (0x34D7) +#define WCD938X_DIGITAL_DEM_BYPASS_DATA3 (0x34D8) +#define WCD938X_MAX_REGISTER (WCD938X_DIGITAL_DEM_BYPASS_DATA3) + +#define WCD938X_MAX_SWR_PORTS 5 +#define WCD938X_MAX_TX_SWR_PORTS 4 +#define WCD938X_MAX_SWR_CH_IDS 15 + +struct wcd938x_sdw_ch_info { + int port_num; + unsigned int ch_mask; +}; + +#define WCD_SDW_CH(id, pn, cmask) \ + [id] = { \ + .port_num = pn, \ + .ch_mask = cmask, \ + } + +enum wcd938x_tx_sdw_ports { + WCD938X_ADC_1_2_PORT = 1, + WCD938X_ADC_3_4_PORT, + /* DMIC0_0, DMIC0_1, DMIC1_0, DMIC1_1 */ + WCD938X_DMIC_0_3_MBHC_PORT, + WCD938X_DMIC_4_7_PORT, +}; + +enum wcd938x_tx_sdw_channels { + WCD938X_ADC1, + WCD938X_ADC2, + WCD938X_ADC3, + WCD938X_ADC4, + WCD938X_DMIC0, + WCD938X_DMIC1, + WCD938X_MBHC, + WCD938X_DMIC2, + WCD938X_DMIC3, + WCD938X_DMIC4, + WCD938X_DMIC5, + WCD938X_DMIC6, + WCD938X_DMIC7, +}; + +enum wcd938x_rx_sdw_ports { + WCD938X_HPH_PORT = 1, + WCD938X_CLSH_PORT, + WCD938X_COMP_PORT, + WCD938X_LO_PORT, + WCD938X_DSD_PORT, +}; + +enum wcd938x_rx_sdw_channels { + WCD938X_HPH_L, + WCD938X_HPH_R, + WCD938X_CLSH, + WCD938X_COMP_L, + WCD938X_COMP_R, + WCD938X_LO, + WCD938X_DSD_R, + WCD938X_DSD_L, +}; +enum { + WCD938X_SDW_DIR_RX, + WCD938X_SDW_DIR_TX, +}; + +struct wcd938x_priv; +struct wcd938x_sdw_priv { + struct sdw_slave *sdev; + struct sdw_stream_config sconfig; + struct sdw_stream_runtime *sruntime; + struct sdw_port_config port_config[WCD938X_MAX_SWR_PORTS]; + struct wcd938x_sdw_ch_info *ch_info; + bool port_enable[WCD938X_MAX_SWR_CH_IDS]; + int port_map[WCD938X_MAX_SWR_PORTS]; + int active_ports; + int num_ports; + bool is_tx; + struct wcd938x_priv *wcd938x; +}; + +extern struct regmap_config wcd938x_regmap_config; +int wcd938x_handle_sdw_irq(struct wcd938x_sdw_priv *priv); + +#endif /* __WCD938X_H__ */
On Tue, Jun 01, 2021 at 12:31:52PM +0100, Srinivas Kandagatla wrote:
This patch adds basic SoundWire codec driver to support for WCD938X TX and RX devices.
Signed-off-by: Srinivas Kandagatla srinivas.kandagatla@linaro.org
sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 +
It would have been nicer to add the Kconfig and Makefile changes last for the benefit of bisection.
On 08/06/2021 15:12, Mark Brown wrote:
On Tue, Jun 01, 2021 at 12:31:52PM +0100, Srinivas Kandagatla wrote:
This patch adds basic SoundWire codec driver to support for WCD938X TX and RX devices.
Signed-off-by: Srinivas Kandagatla srinivas.kandagatla@linaro.org
sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 +
It would have been nicer to add the Kconfig and Makefile changes last for the benefit of bisection.
I agree, will do that in next version.
--srini
Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC connected over SoundWire. This device has two SoundWire devices RX and TX respectively. This bindings is for those slave devices on WCD9380/WCD9385.
Signed-off-by: Srinivas Kandagatla srinivas.kandagatla@linaro.org Reviewed-by: Rob Herring robh@kernel.org --- .../bindings/sound/qcom,wcd938x-sdw.yaml | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml
diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml b/Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml new file mode 100644 index 000000000000..49a267b306f6 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,wcd938x-sdw.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/qcom,wcd938x-sdw.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Bindings for Qualcomm SoundWire Slave devices on WCD9380/WCD9385 + +maintainers: + - Srinivas Kandagatla srinivas.kandagatla@linaro.org + +description: | + Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC. + It has RX and TX Soundwire slave devices. This bindings is for the + slave devices. + +properties: + compatible: + const: sdw20217010d00 + + reg: + maxItems: 1 + + qcom,tx-port-mapping: + description: | + Specifies static port mapping between slave and master tx ports. + In the order of slave port index. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 4 + maxItems: 4 + + qcom,rx-port-mapping: + description: | + Specifies static port mapping between slave and master rx ports. + In the order of slave port index. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 5 + maxItems: 5 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + soundwire@3210000 { + #address-cells = <2>; + #size-cells = <0>; + reg = <0x03210000 0x2000>; + wcd938x_rx: codec@0,4 { + compatible = "sdw20217010d00"; + reg = <0 4>; + qcom,rx-port-mapping = <1 2 3 4 5>; + }; + }; + + soundwire@3230000 { + #address-cells = <2>; + #size-cells = <0>; + reg = <0x03230000 0x2000>; + wcd938x_tx: codec@0,3 { + compatible = "sdw20217010d00"; + reg = <0 3>; + qcom,tx-port-mapping = <2 3 4 5>; + }; + }; + +...
This patch adds support to SoundWire devices on WCD9380/WCD9385 Codec
Signed-off-by: Srinivas Kandagatla srinivas.kandagatla@linaro.org --- sound/soc/codecs/Kconfig | 9 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/wcd938x-sdw.c | 315 +++++++++++++++++++++++++++++++++ sound/soc/codecs/wcd938x.c | 82 +++++++++ sound/soc/codecs/wcd938x.h | 49 +++++ 5 files changed, 457 insertions(+) create mode 100644 sound/soc/codecs/wcd938x-sdw.c
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index f6ca59624e76..ab806a6057e0 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1548,6 +1548,15 @@ config SND_SOC_WCD934X config SND_SOC_WCD938X tristate
+config SND_SOC_WCD938X_SDW + tristate "WCD9380/WCD9385 Codec - SDW" + select SND_SOC_WCD938X + depends on SOUNDWIRE + select REGMAP_SOUNDWIRE + help + The WCD9380/9385 is a audio codec IC Integrated in + Qualcomm SoCs like SM8250. + config SND_SOC_WL1273 tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 444f60269b80..549f98f796ac 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -254,6 +254,7 @@ snd-soc-uda1380-objs := uda1380.o snd-soc-wcd9335-objs := wcd-clsh-v2.o wcd9335.o snd-soc-wcd934x-objs := wcd-clsh-v2.o wcd934x.o snd-soc-wcd938x-objs := wcd938x.o wcd-clsh-v2.o +snd-soc-wcd938x-sdw-objs := wcd938x-sdw.o snd-soc-wl1273-objs := wl1273.o snd-soc-wm-adsp-objs := wm_adsp.o snd-soc-wm0010-objs := wm0010.o @@ -578,6 +579,7 @@ obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_WCD9335) += snd-soc-wcd9335.o obj-$(CONFIG_SND_SOC_WCD934X) += snd-soc-wcd934x.o obj-$(CONFIG_SND_SOC_WCD938X) += snd-soc-wcd938x.o +obj-$(CONFIG_SND_SOC_WCD938X_SDW) += snd-soc-wcd938x-sdw.o obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o obj-$(CONFIG_SND_SOC_WM0010) += snd-soc-wm0010.o obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c new file mode 100644 index 000000000000..d82c40ec6898 --- /dev/null +++ b/sound/soc/codecs/wcd938x-sdw.c @@ -0,0 +1,315 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2021, Linaro Limited + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/component.h> +#include <sound/soc.h> +#include <linux/pm_runtime.h> +#include <linux/irqdomain.h> +#include <linux/of.h> +#include <linux/soundwire/sdw.h> +#include <linux/soundwire/sdw_type.h> +#include <linux/soundwire/sdw_registers.h> +#include <linux/regmap.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include "wcd938x.h" + +#define SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(m) (0xE0 + 0x10 * (m)) + +static struct wcd938x_sdw_ch_info wcd938x_sdw_rx_ch_info[] = { + WCD_SDW_CH(WCD938X_HPH_L, WCD938X_HPH_PORT, BIT(0)), + WCD_SDW_CH(WCD938X_HPH_R, WCD938X_HPH_PORT, BIT(1)), + WCD_SDW_CH(WCD938X_CLSH, WCD938X_CLSH_PORT, BIT(0)), + WCD_SDW_CH(WCD938X_COMP_L, WCD938X_COMP_PORT, BIT(0)), + WCD_SDW_CH(WCD938X_COMP_R, WCD938X_COMP_PORT, BIT(1)), + WCD_SDW_CH(WCD938X_LO, WCD938X_LO_PORT, BIT(0)), + WCD_SDW_CH(WCD938X_DSD_L, WCD938X_DSD_PORT, BIT(0)), + WCD_SDW_CH(WCD938X_DSD_R, WCD938X_DSD_PORT, BIT(1)), +}; + +static struct wcd938x_sdw_ch_info wcd938x_sdw_tx_ch_info[] = { + WCD_SDW_CH(WCD938X_ADC1, WCD938X_ADC_1_2_PORT, BIT(0)), + WCD_SDW_CH(WCD938X_ADC2, WCD938X_ADC_1_2_PORT, BIT(1)), + WCD_SDW_CH(WCD938X_ADC3, WCD938X_ADC_3_4_PORT, BIT(0)), + WCD_SDW_CH(WCD938X_ADC4, WCD938X_ADC_3_4_PORT, BIT(1)), + WCD_SDW_CH(WCD938X_DMIC0, WCD938X_DMIC_0_3_MBHC_PORT, BIT(0)), + WCD_SDW_CH(WCD938X_DMIC1, WCD938X_DMIC_0_3_MBHC_PORT, BIT(1)), + WCD_SDW_CH(WCD938X_MBHC, WCD938X_DMIC_0_3_MBHC_PORT, BIT(2)), + WCD_SDW_CH(WCD938X_DMIC2, WCD938X_DMIC_0_3_MBHC_PORT, BIT(2)), + WCD_SDW_CH(WCD938X_DMIC3, WCD938X_DMIC_0_3_MBHC_PORT, BIT(3)), + WCD_SDW_CH(WCD938X_DMIC4, WCD938X_DMIC_4_7_PORT, BIT(0)), + WCD_SDW_CH(WCD938X_DMIC5, WCD938X_DMIC_4_7_PORT, BIT(1)), + WCD_SDW_CH(WCD938X_DMIC6, WCD938X_DMIC_4_7_PORT, BIT(2)), + WCD_SDW_CH(WCD938X_DMIC7, WCD938X_DMIC_4_7_PORT, BIT(3)), +}; + +static struct sdw_dpn_prop wcd938x_dpn_prop[WCD938X_MAX_SWR_PORTS] = { + { + .num = 1, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 8, + .simple_ch_prep_sm = true, + }, { + .num = 2, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 4, + .simple_ch_prep_sm = true, + }, { + .num = 3, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 4, + .simple_ch_prep_sm = true, + }, { + .num = 4, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 4, + .simple_ch_prep_sm = true, + }, { + .num = 5, + .type = SDW_DPN_SIMPLE, + .min_ch = 1, + .max_ch = 4, + .simple_ch_prep_sm = true, + } +}; + +struct device *wcd938x_sdw_device_get(struct device_node *np) +{ + return bus_find_device_by_of_node(&sdw_bus_type, np); + +} +EXPORT_SYMBOL_GPL(wcd938x_sdw_device_get); + +int wcd938x_swr_get_current_bank(struct sdw_slave *sdev) +{ + int bank; + + bank = sdw_read(sdev, SDW_SCP_CTRL); + + return ((bank & 0x40) ? 1 : 0); +} +EXPORT_SYMBOL_GPL(wcd938x_swr_get_current_bank); + +int wcd938x_sdw_hw_params(struct wcd938x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct sdw_port_config port_config[WCD938X_MAX_SWR_PORTS]; + unsigned long ch_mask; + int i, j; + + wcd->sconfig.ch_count = 1; + wcd->active_ports = 0; + for (i = 0; i < WCD938X_MAX_SWR_PORTS; i++) { + ch_mask = wcd->port_config[i].ch_mask; + + if (!ch_mask) + continue; + + for_each_set_bit(j, &ch_mask, 4) + wcd->sconfig.ch_count++; + + port_config[wcd->active_ports] = wcd->port_config[i]; + wcd->active_ports++; + } + + wcd->sconfig.bps = 1; + wcd->sconfig.frame_rate = params_rate(params); + if (wcd->is_tx) + wcd->sconfig.direction = SDW_DATA_DIR_TX; + else + wcd->sconfig.direction = SDW_DATA_DIR_RX; + + wcd->sconfig.type = SDW_STREAM_PCM; + + return sdw_stream_add_slave(wcd->sdev, &wcd->sconfig, + &port_config[0], wcd->active_ports, + wcd->sruntime); +} +EXPORT_SYMBOL_GPL(wcd938x_sdw_hw_params); + +int wcd938x_sdw_free(struct wcd938x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + sdw_stream_remove_slave(wcd->sdev, wcd->sruntime); + + return 0; +} +EXPORT_SYMBOL_GPL(wcd938x_sdw_free); + +int wcd938x_sdw_set_sdw_stream(struct wcd938x_sdw_priv *wcd, + struct snd_soc_dai *dai, + void *stream, int direction) +{ + wcd->sruntime = stream; + + return 0; +} +EXPORT_SYMBOL_GPL(wcd938x_sdw_set_sdw_stream); + +static int wcd9380_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + return 0; +} + +static int wcd9380_bus_config(struct sdw_slave *slave, + struct sdw_bus_params *params) +{ + sdw_write(slave, SWRS_SCP_HOST_CLK_DIV2_CTL_BANK(params->next_bank), 0x01); + + return 0; +} + +static int wcd9380_interrupt_callback(struct sdw_slave *slave, + struct sdw_slave_intr_status *status) +{ + struct wcd938x_sdw_priv *wcd = dev_get_drvdata(&slave->dev); + + return wcd938x_handle_sdw_irq(wcd); +} + +static struct sdw_slave_ops wcd9380_slave_ops = { + .update_status = wcd9380_update_status, + .interrupt_callback = wcd9380_interrupt_callback, + .bus_config = wcd9380_bus_config, +}; + +static int wcd938x_sdw_component_bind(struct device *dev, + struct device *master, void *data) +{ + return 0; +} + +static void wcd938x_sdw_component_unbind(struct device *dev, + struct device *master, void *data) +{ +} + +static const struct component_ops wcd938x_sdw_component_ops = { + .bind = wcd938x_sdw_component_bind, + .unbind = wcd938x_sdw_component_unbind, +}; + +static int wcd9380_probe(struct sdw_slave *pdev, + const struct sdw_device_id *id) +{ + struct device *dev = &pdev->dev; + struct wcd938x_sdw_priv *wcd; + int ret; + + wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL); + if (!wcd) + return -ENOMEM; + + /** + * Port map index starts with 0, however the data port for this codec + * are from index 1 + */ + if (of_property_read_bool(dev->of_node, "qcom,tx-port-mapping")) { + wcd->is_tx = true; + ret = of_property_read_u32_array(dev->of_node, "qcom,tx-port-mapping", + &pdev->m_port_map[1], + WCD938X_MAX_TX_SWR_PORTS); + } else { + ret = of_property_read_u32_array(dev->of_node, "qcom,rx-port-mapping", + &pdev->m_port_map[1], + WCD938X_MAX_SWR_PORTS); + } + + if (ret < 0) + dev_info(dev, "Static Port mapping not specified\n"); + + wcd->sdev = pdev; + dev_set_drvdata(dev, wcd); + + pdev->prop.scp_int1_mask = SDW_SCP_INT1_IMPL_DEF | + SDW_SCP_INT1_BUS_CLASH | + SDW_SCP_INT1_PARITY; + pdev->prop.lane_control_support = true; + if (wcd->is_tx) { + struct regmap *rm; + + pdev->prop.source_ports = GENMASK(WCD938X_MAX_SWR_PORTS, 0); + pdev->prop.src_dpn_prop = wcd938x_dpn_prop; + wcd->ch_info = &wcd938x_sdw_tx_ch_info[0]; + pdev->prop.wake_capable = true; + + rm = devm_regmap_init_sdw(pdev, &wcd938x_regmap_config); + if (IS_ERR(rm)) + return PTR_ERR(rm); + } else { + pdev->prop.sink_ports = GENMASK(WCD938X_MAX_SWR_PORTS, 0); + pdev->prop.sink_dpn_prop = wcd938x_dpn_prop; + wcd->ch_info = &wcd938x_sdw_rx_ch_info[0]; + } + + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + return component_add(dev, &wcd938x_sdw_component_ops); +} + +static const struct sdw_device_id wcd9380_slave_id[] = { + SDW_SLAVE_ENTRY(0x0217, 0x10d, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, wcd9380_slave_id); + +static int __maybe_unused wcd938x_sdw_runtime_suspend(struct device *dev) +{ + struct regmap *regmap = dev_get_regmap(dev, NULL); + + if (regmap) { + regcache_cache_only(regmap, true); + regcache_mark_dirty(regmap); + } + return 0; +} + +static int __maybe_unused wcd938x_sdw_runtime_resume(struct device *dev) +{ + struct regmap *regmap = dev_get_regmap(dev, NULL); + + if (regmap) { + regcache_cache_only(regmap, false); + regcache_sync(regmap); + } + + pm_runtime_mark_last_busy(dev); + + return 0; +} + +static const struct dev_pm_ops wcd938x_sdw_pm_ops = { + SET_RUNTIME_PM_OPS(wcd938x_sdw_runtime_suspend, wcd938x_sdw_runtime_resume, NULL) +}; + + +static struct sdw_driver wcd9380_codec_driver = { + .probe = wcd9380_probe, + .ops = &wcd9380_slave_ops, + .id_table = wcd9380_slave_id, + .driver = { + .name = "wcd9380-codec", + .pm = &wcd938x_sdw_pm_ops, + } +}; +module_sdw_driver(wcd9380_codec_driver); + +MODULE_DESCRIPTION("WCD938X SDW codec driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index 6b8ee9971945..6400ff7347d4 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -1514,7 +1514,39 @@ int wcd938x_handle_sdw_irq(struct wcd938x_sdw_priv *wcd) } EXPORT_SYMBOL_GPL(wcd938x_handle_sdw_irq);
+static int wcd938x_codec_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct wcd938x_priv *wcd938x = dev_get_drvdata(dai->dev); + struct wcd938x_sdw_priv *wcd = wcd938x->sdw_priv[dai->id]; + + return wcd938x_sdw_hw_params(wcd, substream, params, dai); +} + +static int wcd938x_codec_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct wcd938x_priv *wcd938x = dev_get_drvdata(dai->dev); + struct wcd938x_sdw_priv *wcd = wcd938x->sdw_priv[dai->id]; + + return wcd938x_sdw_free(wcd, substream, dai); +} + +static int wcd938x_codec_set_sdw_stream(struct snd_soc_dai *dai, + void *stream, int direction) +{ + struct wcd938x_priv *wcd938x = dev_get_drvdata(dai->dev); + struct wcd938x_sdw_priv *wcd = wcd938x->sdw_priv[dai->id]; + + return wcd938x_sdw_set_sdw_stream(wcd, dai, stream, direction); + +} + static struct snd_soc_dai_ops wcd938x_sdw_dai_ops = { + .hw_params = wcd938x_codec_hw_params, + .hw_free = wcd938x_codec_free, + .set_sdw_stream = wcd938x_codec_set_sdw_stream, };
static struct snd_soc_dai_driver wcd938x_dais[] = { @@ -1558,6 +1590,53 @@ static int wcd938x_bind(struct device *dev) return ret; }
+ wcd938x->rxdev = wcd938x_sdw_device_get(wcd938x->rxnode); + if (!wcd938x->rxdev) { + dev_err(dev, "could not find slave with matching of node\n"); + return -EINVAL; + } + wcd938x->sdw_priv[AIF1_PB] = dev_get_drvdata(wcd938x->rxdev); + wcd938x->sdw_priv[AIF1_PB]->wcd938x = wcd938x; + + wcd938x->txdev = wcd938x_sdw_device_get(wcd938x->txnode); + if (!wcd938x->txdev) { + dev_err(dev, "could not find txslave with matching of node\n"); + return -EINVAL; + } + wcd938x->sdw_priv[AIF1_CAP] = dev_get_drvdata(wcd938x->txdev); + wcd938x->sdw_priv[AIF1_CAP]->wcd938x = wcd938x; + wcd938x->tx_sdw_dev = dev_to_sdw_dev(wcd938x->txdev); + if (!wcd938x->tx_sdw_dev) { + dev_err(dev, "could not get txslave with matching of dev\n"); + return -EINVAL; + } + + /* As TX is main CSR reg interface, which should not be suspended first. + * expicilty add the dependency link */ + if (!device_link_add(wcd938x->rxdev, wcd938x->txdev, DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME)) { + dev_err(dev, "could not devlink tx and rx\n"); + return -EINVAL; + } + + if (!device_link_add(dev, wcd938x->txdev, DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME)) { + dev_err(dev, "could not devlink wcd and tx\n"); + return -EINVAL; + } + + if (!device_link_add(dev, wcd938x->rxdev, DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME)) { + dev_err(dev, "could not devlink wcd and rx\n"); + return -EINVAL; + } + + wcd938x->regmap = dev_get_regmap(wcd938x->txdev, NULL); + if (!wcd938x->regmap) { + dev_err(dev, "%s: tx csr regmap not found\n", __func__); + return PTR_ERR(wcd938x->regmap); + } + ret = wcd938x_set_micbias_data(wcd938x); if (ret < 0) { dev_err(dev, "%s: bad micbias pdata\n", __func__); @@ -1578,6 +1657,9 @@ static void wcd938x_unbind(struct device *dev) { struct wcd938x_priv *wcd938x = dev_get_drvdata(dev);
+ device_link_remove(dev, wcd938x->txdev); + device_link_remove(dev, wcd938x->rxdev); + device_link_remove(wcd938x->rxdev, wcd938x->txdev); snd_soc_unregister_component(dev); component_unbind_all(dev, wcd938x); } diff --git a/sound/soc/codecs/wcd938x.h b/sound/soc/codecs/wcd938x.h index efaa4dfc752a..9db3ab6e47a6 100644 --- a/sound/soc/codecs/wcd938x.h +++ b/sound/soc/codecs/wcd938x.h @@ -668,4 +668,53 @@ struct wcd938x_sdw_priv { extern struct regmap_config wcd938x_regmap_config; int wcd938x_handle_sdw_irq(struct wcd938x_sdw_priv *priv);
+#if IS_ENABLED(CONFIG_SND_SOC_WCD938X_SDW) +int wcd938x_sdw_free(struct wcd938x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai); +int wcd938x_sdw_set_sdw_stream(struct wcd938x_sdw_priv *wcd, + struct snd_soc_dai *dai, + void *stream, int direction); +int wcd938x_sdw_hw_params(struct wcd938x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); + +struct device *wcd938x_sdw_device_get(struct device_node *np); +int wcd938x_swr_get_current_bank(struct sdw_slave *sdev); + +#else + +static inline int wcd938x_sdw_free(struct wcd938x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + return -EOPNOTSUPP; +} + +static inline int wcd938x_sdw_set_sdw_stream(struct wcd938x_sdw_priv *wcd, + struct snd_soc_dai *dai, + void *stream, int direction) +{ + return -EOPNOTSUPP; +} + +static inline int wcd938x_sdw_hw_params(struct wcd938x_sdw_priv *wcd, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + return -EOPNOTSUPP; +} + +static inline struct device *wcd938x_sdw_device_get(struct device_node *np) +{ + return NULL; +} + +static inline int wcd938x_swr_get_current_bank(struct sdw_slave *sdev) +{ + return 0; +} +#endif /* CONFIG_SND_SOC_WCD938X_SDW */ #endif /* __WCD938X_H__ */
This patch adds basic controls found in wcd938x codec.
Signed-off-by: Srinivas Kandagatla srinivas.kandagatla@linaro.org --- sound/soc/codecs/wcd938x.c | 409 +++++++++++++++++++++++++++++++++++++ 1 file changed, 409 insertions(+)
diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index 6400ff7347d4..510b1779adf0 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -74,6 +74,15 @@ #define WCD938X_MBHC_MOISTURE_RREF R_24_KOHM #define WCD_MBHC_HS_V_MAX 1600
+#define WCD938X_EAR_PA_GAIN_TLV(xname, reg, shift, max, invert, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ + SNDRV_CTL_ELEM_ACCESS_READWRITE,\ + .tlv.p = (tlv_array), \ + .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ + .put = wcd938x_ear_pa_put_gain, \ + .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } + enum { WCD9380 = 0, WCD9385 = 5, @@ -197,6 +206,10 @@ enum { MICB_DISABLE, };
+static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800); +static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(line_gain, 600, -3000); +static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(analog_gain, 0, 3000); + static const struct reg_default wcd938x_defaults[] = { {WCD938X_ANA_PAGE_REGISTER, 0x00}, {WCD938X_ANA_BIAS, 0x00}, @@ -1282,6 +1295,375 @@ static int wcd938x_io_init(struct wcd938x_priv *wcd938x)
}
+static int wcd938x_sdw_connect_port(struct wcd938x_sdw_ch_info *ch_info, + struct sdw_port_config *port_config, + u32 mstr_port_num, + u8 enable) +{ + u8 ch_mask, port_num; + + port_num = ch_info->port_num; + ch_mask = ch_info->ch_mask; + + port_config->num = port_num; + + if (enable) + port_config->ch_mask |= ch_mask; + else + port_config->ch_mask &= ~ch_mask; + + return 0; +} + +static int wcd938x_connect_port(struct wcd938x_sdw_priv *wcd, u8 ch_id, u8 enable) +{ + u8 port_num, mstr_port_num; + + port_num = wcd->ch_info[ch_id].port_num; + mstr_port_num = wcd->port_map[port_num - 1]; + + return wcd938x_sdw_connect_port(&wcd->ch_info[ch_id], + &wcd->port_config[port_num], + mstr_port_num, + enable); +} + +static int wcd938x_tx_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int path = e->shift_l; + + ucontrol->value.integer.value[0] = wcd938x->tx_mode[path]; + + return 0; +} + +static int wcd938x_tx_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int path = e->shift_l; + + wcd938x->tx_mode[path] = ucontrol->value.enumerated.item[0]; + + return 0; +} + +static int wcd938x_rx_hph_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wcd938x->hph_mode; + + return 0; +} + +static int wcd938x_rx_hph_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + wcd938x->hph_mode = ucontrol->value.enumerated.item[0]; + + return 0; +} + +static int wcd938x_ear_pa_put_gain(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + if (wcd938x->comp1_enable) { + dev_err(component->dev, "Can not set EAR PA Gain, compander1 is enabled\n"); + return -EINVAL; + } + + snd_soc_component_write_field(component, WCD938X_ANA_EAR_COMPANDER_CTL, + WCD938X_EAR_GAIN_MASK, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int wcd938x_get_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc; + bool hphr; + + mc = (struct soc_mixer_control *)(kcontrol->private_value); + hphr = mc->shift; + + if (hphr) + ucontrol->value.integer.value[0] = wcd938x->comp2_enable; + else + ucontrol->value.integer.value[0] = wcd938x->comp1_enable; + + return 0; +} + +static int wcd938x_set_compander(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + struct wcd938x_sdw_priv *wcd; + int value = ucontrol->value.integer.value[0]; + struct soc_mixer_control *mc; + bool hphr; + + mc = (struct soc_mixer_control *)(kcontrol->private_value); + hphr = mc->shift; + + wcd = wcd938x->sdw_priv[AIF1_PB]; + + if (hphr) + wcd938x->comp2_enable = value; + else + wcd938x->comp1_enable = value; + + if (value) + wcd938x_connect_port(wcd, mc->reg, true); + else + wcd938x_connect_port(wcd, mc->reg, false); + + return 0; +} + +static int wcd938x_ldoh_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wcd938x->ldoh; + + return 0; +} + +static int wcd938x_ldoh_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + wcd938x->ldoh = ucontrol->value.integer.value[0]; + + return 0; +} + +static int wcd938x_bcs_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = wcd938x->bcs_dis; + + return 0; +} + +static int wcd938x_bcs_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + wcd938x->bcs_dis = ucontrol->value.integer.value[0]; + + return 0; +} + +static const char * const tx_mode_mux_text_wcd9380[] = { + "ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP", +}; + +static const char * const tx_mode_mux_text[] = { + "ADC_INVALID", "ADC_HIFI", "ADC_LO_HIF", "ADC_NORMAL", "ADC_LP", + "ADC_ULP1", "ADC_ULP2", +}; + +static const char * const rx_hph_mode_mux_text_wcd9380[] = { + "CLS_H_INVALID", "CLS_H_INVALID_1", "CLS_H_LP", "CLS_AB", + "CLS_H_LOHIFI", "CLS_H_ULP", "CLS_H_INVALID_2", "CLS_AB_LP", + "CLS_AB_LOHIFI", +}; + +static const char * const rx_hph_mode_mux_text[] = { + "CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", "CLS_H_LOHIFI", + "CLS_H_ULP", "CLS_AB_HIFI", "CLS_AB_LP", "CLS_AB_LOHIFI", +}; + +static const struct soc_enum tx_mode_mux_enum_wcd9380[] = { + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tx_mode_mux_text_wcd9380), + tx_mode_mux_text_wcd9380), + SOC_ENUM_SINGLE(SND_SOC_NOPM, 1, ARRAY_SIZE(tx_mode_mux_text_wcd9380), + tx_mode_mux_text_wcd9380), + SOC_ENUM_SINGLE(SND_SOC_NOPM, 2, ARRAY_SIZE(tx_mode_mux_text_wcd9380), + tx_mode_mux_text_wcd9380), + SOC_ENUM_SINGLE(SND_SOC_NOPM, 3, ARRAY_SIZE(tx_mode_mux_text_wcd9380), + tx_mode_mux_text_wcd9380), +}; + +static const struct soc_enum tx_mode_mux_enum[] = { + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tx_mode_mux_text), + tx_mode_mux_text), + SOC_ENUM_SINGLE(SND_SOC_NOPM, 1, ARRAY_SIZE(tx_mode_mux_text), + tx_mode_mux_text), + SOC_ENUM_SINGLE(SND_SOC_NOPM, 2, ARRAY_SIZE(tx_mode_mux_text), + tx_mode_mux_text), + SOC_ENUM_SINGLE(SND_SOC_NOPM, 3, ARRAY_SIZE(tx_mode_mux_text), + tx_mode_mux_text), +}; + +static const struct soc_enum rx_hph_mode_mux_enum_wcd9380 = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text_wcd9380), + rx_hph_mode_mux_text_wcd9380); + +static const struct soc_enum rx_hph_mode_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), + rx_hph_mode_mux_text); + +static const struct snd_kcontrol_new wcd9380_snd_controls[] = { + SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum_wcd9380, + wcd938x_rx_hph_mode_get, wcd938x_rx_hph_mode_put), + SOC_ENUM_EXT("TX0 MODE", tx_mode_mux_enum_wcd9380[0], + wcd938x_tx_mode_get, wcd938x_tx_mode_put), + SOC_ENUM_EXT("TX1 MODE", tx_mode_mux_enum_wcd9380[1], + wcd938x_tx_mode_get, wcd938x_tx_mode_put), + SOC_ENUM_EXT("TX2 MODE", tx_mode_mux_enum_wcd9380[2], + wcd938x_tx_mode_get, wcd938x_tx_mode_put), + SOC_ENUM_EXT("TX3 MODE", tx_mode_mux_enum_wcd9380[3], + wcd938x_tx_mode_get, wcd938x_tx_mode_put), +}; + +static const struct snd_kcontrol_new wcd9385_snd_controls[] = { + SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum, + wcd938x_rx_hph_mode_get, wcd938x_rx_hph_mode_put), + SOC_ENUM_EXT("TX0 MODE", tx_mode_mux_enum[0], + wcd938x_tx_mode_get, wcd938x_tx_mode_put), + SOC_ENUM_EXT("TX1 MODE", tx_mode_mux_enum[1], + wcd938x_tx_mode_get, wcd938x_tx_mode_put), + SOC_ENUM_EXT("TX2 MODE", tx_mode_mux_enum[2], + wcd938x_tx_mode_get, wcd938x_tx_mode_put), + SOC_ENUM_EXT("TX3 MODE", tx_mode_mux_enum[3], + wcd938x_tx_mode_get, wcd938x_tx_mode_put), +}; + +static int wcd938x_get_swr_port(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(comp); + struct wcd938x_sdw_priv *wcd; + struct soc_mixer_control *mixer = (struct soc_mixer_control *)kcontrol->private_value; + int dai_id = mixer->shift; + int portidx = mixer->reg; + + wcd = wcd938x->sdw_priv[dai_id]; + + ucontrol->value.integer.value[0] = wcd->port_enable[portidx]; + + return 0; +} + +static int wcd938x_set_swr_port(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(comp); + struct wcd938x_sdw_priv *wcd; + struct soc_mixer_control *mixer = + (struct soc_mixer_control *)kcontrol->private_value; + int portidx = mixer->reg; + int dai_id = mixer->shift; + bool enable; + + wcd = wcd938x->sdw_priv[dai_id]; + + if (ucontrol->value.integer.value[0]) + enable = true; + else + enable = false; + + wcd->port_enable[portidx] = enable; + + wcd938x_connect_port(wcd, portidx, enable); + + return 0; + +} + +static const struct snd_kcontrol_new wcd938x_snd_controls[] = { + SOC_SINGLE_EXT("HPHL_COMP Switch", WCD938X_COMP_L, 0, 1, 0, + wcd938x_get_compander, wcd938x_set_compander), + SOC_SINGLE_EXT("HPHR_COMP Switch", WCD938X_COMP_R, 1, 1, 0, + wcd938x_get_compander, wcd938x_set_compander), + SOC_SINGLE_EXT("HPHL Switch", WCD938X_HPH_L, 0, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("HPHR Switch", WCD938X_HPH_R, 0, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("CLSH Switch", WCD938X_CLSH, 0, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("LO Switch", WCD938X_LO, 0, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("DSD_L Switch", WCD938X_DSD_L, 0, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("DSD_R Switch", WCD938X_DSD_R, 0, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_TLV("HPHL Volume", WCD938X_HPH_L_EN, 0, 0x18, 0, line_gain), + SOC_SINGLE_TLV("HPHR Volume", WCD938X_HPH_R_EN, 0, 0x18, 0, line_gain), + WCD938X_EAR_PA_GAIN_TLV("EAR_PA Volume", WCD938X_ANA_EAR_COMPANDER_CTL, + 2, 0x10, 0, ear_pa_gain), + SOC_SINGLE_EXT("ADC1 Switch", WCD938X_ADC1, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("ADC2 Switch", WCD938X_ADC2, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("ADC3 Switch", WCD938X_ADC3, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("ADC4 Switch", WCD938X_ADC4, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("DMIC0 Switch", WCD938X_DMIC0, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("DMIC1 Switch", WCD938X_DMIC1, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("MBHC Switch", WCD938X_MBHC, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("DMIC2 Switch", WCD938X_DMIC2, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("DMIC3 Switch", WCD938X_DMIC3, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("DMIC4 Switch", WCD938X_DMIC4, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("DMIC5 Switch", WCD938X_DMIC5, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("DMIC6 Switch", WCD938X_DMIC6, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("DMIC7 Switch", WCD938X_DMIC7, 1, 1, 0, + wcd938x_get_swr_port, wcd938x_set_swr_port), + SOC_SINGLE_EXT("LDOH Enable Switch", SND_SOC_NOPM, 0, 1, 0, + wcd938x_ldoh_get, wcd938x_ldoh_put), + SOC_SINGLE_EXT("ADC2_BCS Disable Switch", SND_SOC_NOPM, 0, 1, 0, + wcd938x_bcs_get, wcd938x_bcs_put), + + SOC_SINGLE_TLV("ADC1 Volume", WCD938X_ANA_TX_CH1, 0, 20, 0, analog_gain), + SOC_SINGLE_TLV("ADC2 Volume", WCD938X_ANA_TX_CH2, 0, 20, 0, analog_gain), + SOC_SINGLE_TLV("ADC3 Volume", WCD938X_ANA_TX_CH3, 0, 20, 0, analog_gain), + SOC_SINGLE_TLV("ADC4 Volume", WCD938X_ANA_TX_CH4, 0, 20, 0, analog_gain), +}; + static int wcd938x_get_micb_vout_ctl_val(u32 micb_mv) { /* min micbias voltage is 1V and maximum is 2.85V */ @@ -1412,12 +1794,39 @@ static int wcd938x_soc_codec_probe(struct snd_soc_component *component) disable_irq_nosync(wcd938x->hphl_pdm_wd_int); disable_irq_nosync(wcd938x->aux_pdm_wd_int);
+ switch (wcd938x->variant) { + case WCD9380: + ret = snd_soc_add_component_controls(component, wcd9380_snd_controls, + ARRAY_SIZE(wcd9380_snd_controls)); + if (ret < 0) { + dev_err(component->dev, + "%s: Failed to add snd ctrls for variant: %d\n", + __func__, wcd938x->variant); + goto err; + } + break; + case WCD9385: + ret = snd_soc_add_component_controls(component, wcd9385_snd_controls, + ARRAY_SIZE(wcd9385_snd_controls)); + if (ret < 0) { + dev_err(component->dev, + "%s: Failed to add snd ctrls for variant: %d\n", + __func__, wcd938x->variant); + goto err; + } + break; + default: + break; + } +err: return ret; }
static const struct snd_soc_component_driver soc_codec_dev_wcd938x = { .name = "wcd938x_codec", .probe = wcd938x_soc_codec_probe, + .controls = wcd938x_snd_controls, + .num_controls = ARRAY_SIZE(wcd938x_snd_controls), };
static void wcd938x_dt_parse_micbias_info(struct device *dev, struct wcd938x_priv *wcd)
On Tue, Jun 01, 2021 at 12:31:55PM +0100, Srinivas Kandagatla wrote:
+static int wcd938x_rx_hph_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
+{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
- wcd938x->hph_mode = ucontrol->value.enumerated.item[0];
- return 0;
+}
_put() should return true if it made a change, the same bug is present in a lot of other drivers too.
+static const struct snd_kcontrol_new wcd9380_snd_controls[] = {
- SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum_wcd9380,
wcd938x_rx_hph_mode_get, wcd938x_rx_hph_mode_put),
- SOC_ENUM_EXT("TX0 MODE", tx_mode_mux_enum_wcd9380[0],
wcd938x_tx_mode_get, wcd938x_tx_mode_put),
- SOC_ENUM_EXT("TX1 MODE", tx_mode_mux_enum_wcd9380[1],
wcd938x_tx_mode_get, wcd938x_tx_mode_put),
- SOC_ENUM_EXT("TX2 MODE", tx_mode_mux_enum_wcd9380[2],
wcd938x_tx_mode_get, wcd938x_tx_mode_put),
- SOC_ENUM_EXT("TX3 MODE", tx_mode_mux_enum_wcd9380[3],
wcd938x_tx_mode_get, wcd938x_tx_mode_put),
+};
Please don't use this pattern of indexing into arrays by absolute number, it's error prone and hard to read. Just declare static variables for the enums and reference them individually.
On 08/06/2021 14:59, Mark Brown wrote:
On Tue, Jun 01, 2021 at 12:31:55PM +0100, Srinivas Kandagatla wrote:
+static int wcd938x_rx_hph_mode_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
+{
- struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
- struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
- wcd938x->hph_mode = ucontrol->value.enumerated.item[0];
- return 0;
+}
_put() should return true if it made a change, the same bug is present in a lot of other drivers too.
Sure will fix this in next spin
+static const struct snd_kcontrol_new wcd9380_snd_controls[] = {
- SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum_wcd9380,
wcd938x_rx_hph_mode_get, wcd938x_rx_hph_mode_put),
- SOC_ENUM_EXT("TX0 MODE", tx_mode_mux_enum_wcd9380[0],
wcd938x_tx_mode_get, wcd938x_tx_mode_put),
- SOC_ENUM_EXT("TX1 MODE", tx_mode_mux_enum_wcd9380[1],
wcd938x_tx_mode_get, wcd938x_tx_mode_put),
- SOC_ENUM_EXT("TX2 MODE", tx_mode_mux_enum_wcd9380[2],
wcd938x_tx_mode_get, wcd938x_tx_mode_put),
- SOC_ENUM_EXT("TX3 MODE", tx_mode_mux_enum_wcd9380[3],
wcd938x_tx_mode_get, wcd938x_tx_mode_put),
+};
Please don't use this pattern of indexing into arrays by absolute number, it's error prone and hard to read. Just declare static variables for the enums and reference them individually.
I agree, will clean these instances in next version.
--srini
This patch adds required dapm widgets for playback.
Signed-off-by: Srinivas Kandagatla srinivas.kandagatla@linaro.org --- sound/soc/codecs/wcd938x.c | 687 +++++++++++++++++++++++++++++++++++++ 1 file changed, 687 insertions(+)
diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index 510b1779adf0..b33a12d788ca 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -1328,6 +1328,593 @@ static int wcd938x_connect_port(struct wcd938x_sdw_priv *wcd, u8 ch_id, u8 enabl enable); }
+static int wcd938x_codec_enable_rxclk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_RX_CLK_EN_MASK, 1); + snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, + WCD938X_RX_BIAS_EN_MASK, 1); + snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_RX0_CTL, + WCD938X_DEM_DITHER_ENABLE_MASK, 0); + snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_RX1_CTL, + WCD938X_DEM_DITHER_ENABLE_MASK, 0); + snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_RX2_CTL, + WCD938X_DEM_DITHER_ENABLE_MASK, 0); + snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_RX_DIV2_CLK_EN_MASK, 1); + snd_soc_component_write_field(component, WCD938X_AUX_AUXPA, + WCD938X_AUXPA_CLK_EN_MASK, 1); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, + WCD938X_VNEG_EN_MASK, 0); + snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, + WCD938X_VPOS_EN_MASK, 0); + snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, + WCD938X_RX_BIAS_EN_MASK, 0); + snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_RX_DIV2_CLK_EN_MASK, 0); + snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_RX_CLK_EN_MASK, 0); + break; + } + return 0; +} + +static int wcd938x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_RXD0_CLK_EN_MASK, 0x01); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, + WCD938X_HPHL_RX_EN_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_HPH_RDAC_CLK_CTL1, + WCD938X_CHOP_CLK_EN_MASK, 0); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_write_field(component, + WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_L, + WCD938X_HPH_RES_DIV_MASK, 0x02); + if (wcd938x->comp1_enable) { + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0, + WCD938X_HPHL_COMP_EN_MASK, 1); + /* 5msec compander delay as per HW requirement */ + if (!wcd938x->comp2_enable || (snd_soc_component_read(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0) & 0x01)) + usleep_range(5000, 5010); + snd_soc_component_write_field(component, WCD938X_HPH_NEW_INT_HPH_TIMER1, + WCD938X_AUTOCHOP_TIMER_EN, 0); + } else { + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0, + WCD938X_HPHL_COMP_EN_MASK, 0); + snd_soc_component_write_field(component, + WCD938X_HPH_L_EN, + WCD938X_GAIN_SRC_SEL_MASK, + WCD938X_GAIN_SRC_SEL_REGISTER); + + } + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_write_field(component, + WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R, + WCD938X_HPH_RES_DIV_MASK, 0x1); + break; + } + + return 0; +} + +static int wcd938x_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_RXD1_CLK_EN_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, + WCD938X_HPHR_RX_EN_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_HPH_RDAC_CLK_CTL1, + WCD938X_CHOP_CLK_EN_MASK, 0); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_component_write_field(component, + WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R, + WCD938X_HPH_RES_DIV_MASK, 0x02); + if (wcd938x->comp2_enable) { + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0, + WCD938X_HPHR_COMP_EN_MASK, 1); + /* 5msec compander delay as per HW requirement */ + if (!wcd938x->comp1_enable || + (snd_soc_component_read(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0) & 0x02)) + usleep_range(5000, 5010); + snd_soc_component_write_field(component, WCD938X_HPH_NEW_INT_HPH_TIMER1, + WCD938X_AUTOCHOP_TIMER_EN, 0); + } else { + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0, + WCD938X_HPHR_COMP_EN_MASK, 0); + snd_soc_component_write_field(component, + WCD938X_HPH_R_EN, + WCD938X_GAIN_SRC_SEL_MASK, + WCD938X_GAIN_SRC_SEL_REGISTER); + } + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_write_field(component, + WCD938X_HPH_NEW_INT_RDAC_HD2_CTL_R, + WCD938X_HPH_RES_DIV_MASK, 0x01); + break; + } + + return 0; +} + +static int wcd938x_codec_ear_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd938x->ear_rx_path = + snd_soc_component_read( + component, WCD938X_DIGITAL_CDC_EAR_PATH_CTL); + if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) { + snd_soc_component_write_field(component, + WCD938X_EAR_EAR_DAC_CON, + WCD938X_DAC_SAMPLE_EDGE_SEL_MASK, 0); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, + WCD938X_AUX_EN_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_RXD2_CLK_EN_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_ANA_EAR_COMPANDER_CTL, + WCD938X_GAIN_OVRD_REG_MASK, 1); + } else { + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, + WCD938X_HPHL_RX_EN_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_RXD0_CLK_EN_MASK, 1); + if (wcd938x->comp1_enable) + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0, + WCD938X_HPHL_COMP_EN_MASK, 1); + } + /* 5 msec delay as per HW requirement */ + usleep_range(5000, 5010); + if (wcd938x->flyback_cur_det_disable == 0) + snd_soc_component_write_field(component, WCD938X_FLYBACK_EN, + WCD938X_EN_CUR_DET_MASK, 0); + wcd938x->flyback_cur_det_disable++; + wcd_clsh_ctrl_set_state(wcd938x->clsh_info, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_EAR, + wcd938x->hph_mode); + break; + case SND_SOC_DAPM_POST_PMD: + if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) { + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, + WCD938X_AUX_EN_MASK, 0); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_RXD2_CLK_EN_MASK, 0); + } else { + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_HPH_GAIN_CTL, + WCD938X_HPHL_RX_EN_MASK, 0); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_RXD0_CLK_EN_MASK, 0); + if (wcd938x->comp1_enable) + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_COMP_CTL_0, + WCD938X_HPHL_COMP_EN_MASK, 0); + } + snd_soc_component_write_field(component, WCD938X_ANA_EAR_COMPANDER_CTL, + WCD938X_GAIN_OVRD_REG_MASK, 0); + snd_soc_component_write_field(component, + WCD938X_EAR_EAR_DAC_CON, + WCD938X_DAC_SAMPLE_EDGE_SEL_MASK, 1); + break; + }; + return 0; + +} + +static int wcd938x_codec_aux_dac_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_RX_DIV4_CLK_EN_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_RXD2_CLK_EN_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_AUX_GAIN_CTL, + WCD938X_AUX_EN_MASK, 1); + if (wcd938x->flyback_cur_det_disable == 0) + snd_soc_component_write_field(component, WCD938X_FLYBACK_EN, + WCD938X_EN_CUR_DET_MASK, 0); + wcd938x->flyback_cur_det_disable++; + wcd_clsh_ctrl_set_state(wcd938x->clsh_info, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_AUX, + wcd938x->hph_mode); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_RX_DIV4_CLK_EN_MASK, 0); + break; + }; + return ret; + +} + +static int wcd938x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd938x->hph_mode; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (wcd938x->ldoh) + snd_soc_component_write_field(component, WCD938X_LDOH_MODE, + WCD938X_LDOH_EN_MASK, 1); + wcd_clsh_ctrl_set_state(wcd938x->clsh_info, WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHR, hph_mode); + wcd_clsh_set_hph_mode(wcd938x->clsh_info, CLS_H_HIFI); + + if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || + hph_mode == CLS_H_ULP) { + snd_soc_component_write_field(component, + WCD938X_HPH_REFBUFF_LP_CTL, + WCD938X_PREREF_FLIT_BYPASS_MASK, 1); + } + snd_soc_component_write_field(component, WCD938X_ANA_HPH, + WCD938X_HPHR_REF_EN_MASK, 1); + wcd_clsh_set_hph_mode(wcd938x->clsh_info, hph_mode); + /* 100 usec delay as per HW requirement */ + usleep_range(100, 110); + set_bit(HPH_PA_DELAY, &wcd938x->status_mask); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_PDM_WD_CTL1, + WCD938X_PDM_WD_EN_MASK, 0x3); + break; + case SND_SOC_DAPM_POST_PMU: + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (test_bit(HPH_PA_DELAY, &wcd938x->status_mask)) { + if (!wcd938x->comp2_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + + if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || + hph_mode == CLS_H_ULP) + snd_soc_component_write_field(component, + WCD938X_HPH_REFBUFF_LP_CTL, + WCD938X_PREREF_FLIT_BYPASS_MASK, 0); + clear_bit(HPH_PA_DELAY, &wcd938x->status_mask); + } + snd_soc_component_write_field(component, WCD938X_HPH_NEW_INT_HPH_TIMER1, + WCD938X_AUTOCHOP_TIMER_EN, 1); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI || + hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) + snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, + WCD938X_REGULATOR_MODE_MASK, + WCD938X_REGULATOR_MODE_CLASS_AB); + enable_irq(wcd938x->hphr_pdm_wd_int); + break; + case SND_SOC_DAPM_PRE_PMD: + disable_irq_nosync(wcd938x->hphr_pdm_wd_int); + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (!wcd938x->comp2_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + snd_soc_component_write_field(component, WCD938X_ANA_HPH, + WCD938X_HPHR_EN_MASK, 0); + set_bit(HPH_PA_DELAY, &wcd938x->status_mask); + break; + case SND_SOC_DAPM_POST_PMD: + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (test_bit(HPH_PA_DELAY, &wcd938x->status_mask)) { + if (!wcd938x->comp2_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &wcd938x->status_mask); + } + snd_soc_component_write_field(component, WCD938X_ANA_HPH, + WCD938X_HPHR_REF_EN_MASK, 0); + snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL1, + WCD938X_PDM_WD_EN_MASK, 0); + wcd_clsh_ctrl_set_state(wcd938x->clsh_info, WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHR, hph_mode); + if (wcd938x->ldoh) + snd_soc_component_write_field(component, WCD938X_LDOH_MODE, + WCD938X_LDOH_EN_MASK, 0); + break; + }; + + return 0; +} + +static int wcd938x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd938x->hph_mode; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (wcd938x->ldoh) + snd_soc_component_write_field(component, WCD938X_LDOH_MODE, + WCD938X_LDOH_EN_MASK, 1); + wcd_clsh_ctrl_set_state(wcd938x->clsh_info, WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHL, hph_mode); + wcd_clsh_set_hph_mode(wcd938x->clsh_info, CLS_H_HIFI); + if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || + hph_mode == CLS_H_ULP) { + snd_soc_component_write_field(component, + WCD938X_HPH_REFBUFF_LP_CTL, + WCD938X_PREREF_FLIT_BYPASS_MASK, 1); + } + snd_soc_component_write_field(component, WCD938X_ANA_HPH, + WCD938X_HPHL_REF_EN_MASK, 1); + wcd_clsh_set_hph_mode(wcd938x->clsh_info, hph_mode); + /* 100 usec delay as per HW requirement */ + usleep_range(100, 110); + set_bit(HPH_PA_DELAY, &wcd938x->status_mask); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_PDM_WD_CTL0, + WCD938X_PDM_WD_EN_MASK, 0x3); + break; + case SND_SOC_DAPM_POST_PMU: + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (test_bit(HPH_PA_DELAY, &wcd938x->status_mask)) { + if (!wcd938x->comp1_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + if (hph_mode == CLS_H_LP || hph_mode == CLS_H_LOHIFI || + hph_mode == CLS_H_ULP) + snd_soc_component_write_field(component, + WCD938X_HPH_REFBUFF_LP_CTL, + WCD938X_PREREF_FLIT_BYPASS_MASK, 0); + clear_bit(HPH_PA_DELAY, &wcd938x->status_mask); + } + + snd_soc_component_write_field(component, WCD938X_HPH_NEW_INT_HPH_TIMER1, + WCD938X_AUTOCHOP_TIMER_EN, 1); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI || + hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) + snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, + WCD938X_REGULATOR_MODE_MASK, + WCD938X_REGULATOR_MODE_CLASS_AB); + enable_irq(wcd938x->hphl_pdm_wd_int); + break; + case SND_SOC_DAPM_PRE_PMD: + disable_irq_nosync(wcd938x->hphl_pdm_wd_int); + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (!wcd938x->comp1_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + snd_soc_component_write_field(component, WCD938X_ANA_HPH, + WCD938X_HPHL_EN_MASK, 0); + set_bit(HPH_PA_DELAY, &wcd938x->status_mask); + break; + case SND_SOC_DAPM_POST_PMD: + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (test_bit(HPH_PA_DELAY, &wcd938x->status_mask)) { + if (!wcd938x->comp1_enable) + usleep_range(21000, 21100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &wcd938x->status_mask); + } + snd_soc_component_write_field(component, WCD938X_ANA_HPH, + WCD938X_HPHL_REF_EN_MASK, 0); + snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL0, + WCD938X_PDM_WD_EN_MASK, 0); + wcd_clsh_ctrl_set_state(wcd938x->clsh_info, WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_HPHL, hph_mode); + if (wcd938x->ldoh) + snd_soc_component_write_field(component, WCD938X_LDOH_MODE, + WCD938X_LDOH_EN_MASK, 0); + break; + }; + + return 0; +} + +static int wcd938x_codec_enable_aux_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd938x->hph_mode; + int ret = 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL2, + WCD938X_AUX_PDM_WD_EN_MASK, 1); + break; + case SND_SOC_DAPM_POST_PMU: + /* 1 msec delay as per HW requirement */ + usleep_range(1000, 1010); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI || + hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) + snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, + WCD938X_REGULATOR_MODE_MASK, + WCD938X_REGULATOR_MODE_CLASS_AB); + enable_irq(wcd938x->aux_pdm_wd_int); + break; + case SND_SOC_DAPM_PRE_PMD: + disable_irq_nosync(wcd938x->aux_pdm_wd_int); + break; + case SND_SOC_DAPM_POST_PMD: + /* 1 msec delay as per HW requirement */ + usleep_range(1000, 1010); + snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL2, + WCD938X_AUX_PDM_WD_EN_MASK, 0); + wcd_clsh_ctrl_set_state(wcd938x->clsh_info, + WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_AUX, + hph_mode); + + wcd938x->flyback_cur_det_disable--; + if (wcd938x->flyback_cur_det_disable == 0) + snd_soc_component_write_field(component, WCD938X_FLYBACK_EN, + WCD938X_EN_CUR_DET_MASK, 1); + break; + }; + return ret; +} + +static int wcd938x_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int hph_mode = wcd938x->hph_mode; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* + * Enable watchdog interrupt for HPHL or AUX + * depending on mux value + */ + wcd938x->ear_rx_path = snd_soc_component_read(component, + WCD938X_DIGITAL_CDC_EAR_PATH_CTL); + if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) + snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL2, + WCD938X_AUX_PDM_WD_EN_MASK, 1); + else + snd_soc_component_write_field(component, + WCD938X_DIGITAL_PDM_WD_CTL0, + WCD938X_PDM_WD_EN_MASK, 0x3); + if (!wcd938x->comp1_enable) + snd_soc_component_write_field(component, + WCD938X_ANA_EAR_COMPANDER_CTL, + WCD938X_GAIN_OVRD_REG_MASK, 1); + + break; + case SND_SOC_DAPM_POST_PMU: + /* 6 msec delay as per HW requirement */ + usleep_range(6000, 6010); + if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI || + hph_mode == CLS_AB_LP || hph_mode == CLS_AB_LOHIFI) + snd_soc_component_write_field(component, WCD938X_ANA_RX_SUPPLIES, + WCD938X_REGULATOR_MODE_MASK, + WCD938X_REGULATOR_MODE_CLASS_AB); + if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) + enable_irq(wcd938x->aux_pdm_wd_int); + else + enable_irq(wcd938x->hphl_pdm_wd_int); + break; + case SND_SOC_DAPM_PRE_PMD: + if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) + disable_irq_nosync(wcd938x->aux_pdm_wd_int); + else + disable_irq_nosync(wcd938x->hphl_pdm_wd_int); + break; + case SND_SOC_DAPM_POST_PMD: + if (!wcd938x->comp1_enable) + snd_soc_component_write_field(component, WCD938X_ANA_EAR_COMPANDER_CTL, + WCD938X_GAIN_OVRD_REG_MASK, 0); + /* 7 msec delay as per HW requirement */ + usleep_range(7000, 7010); + if (wcd938x->ear_rx_path & EAR_RX_PATH_AUX) + snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL2, + WCD938X_AUX_PDM_WD_EN_MASK, 0); + else + snd_soc_component_write_field(component, WCD938X_DIGITAL_PDM_WD_CTL0, + WCD938X_PDM_WD_EN_MASK, 0); + + wcd_clsh_ctrl_set_state(wcd938x->clsh_info, WCD_CLSH_EVENT_POST_PA, + WCD_CLSH_STATE_EAR, hph_mode); + + wcd938x->flyback_cur_det_disable--; + if (wcd938x->flyback_cur_det_disable == 0) + snd_soc_component_write_field(component, WCD938X_FLYBACK_EN, + WCD938X_EN_CUR_DET_MASK, 1); + break; + }; + + return 0; +} + static int wcd938x_tx_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1506,6 +2093,10 @@ static const char * const rx_hph_mode_mux_text[] = { "CLS_H_ULP", "CLS_AB_HIFI", "CLS_AB_LP", "CLS_AB_LOHIFI", };
+static const char * const rdac3_mux_text[] = { + "RX1", "RX3" +}; + static const struct soc_enum tx_mode_mux_enum_wcd9380[] = { SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tx_mode_mux_text_wcd9380), tx_mode_mux_text_wcd9380), @@ -1536,6 +2127,29 @@ static const struct soc_enum rx_hph_mode_mux_enum = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), rx_hph_mode_mux_text);
+static const struct soc_enum rdac3_enum = + SOC_ENUM_SINGLE(WCD938X_DIGITAL_CDC_EAR_PATH_CTL, 0, + ARRAY_SIZE(rdac3_mux_text), rdac3_mux_text); + +static const struct snd_kcontrol_new ear_rdac_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new aux_rdac_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new hphl_rdac_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new hphr_rdac_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new rx_rdac3_mux = + SOC_DAPM_ENUM("RDAC3_MUX Mux", rdac3_enum); + static const struct snd_kcontrol_new wcd9380_snd_controls[] = { SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum_wcd9380, wcd938x_rx_hph_mode_get, wcd938x_rx_hph_mode_put), @@ -1664,6 +2278,77 @@ static const struct snd_kcontrol_new wcd938x_snd_controls[] = { SOC_SINGLE_TLV("ADC4 Volume", WCD938X_ANA_TX_CH4, 0, 20, 0, analog_gain), };
+static const struct snd_soc_dapm_widget wcd938x_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("IN1_HPHL"), + SND_SOC_DAPM_INPUT("IN2_HPHR"), + SND_SOC_DAPM_INPUT("IN3_AUX"), + + /*rx widgets*/ + SND_SOC_DAPM_PGA_E("EAR PGA", WCD938X_ANA_EAR, 7, 0, NULL, 0, + wcd938x_codec_enable_ear_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("AUX PGA", WCD938X_AUX_AUXPA, 7, 0, NULL, 0, + wcd938x_codec_enable_aux_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHL PGA", WCD938X_ANA_HPH, 7, 0, NULL, 0, + wcd938x_codec_enable_hphl_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("HPHR PGA", WCD938X_ANA_HPH, 6, 0, NULL, 0, + wcd938x_codec_enable_hphr_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_DAC_E("RDAC1", NULL, SND_SOC_NOPM, 0, 0, + wcd938x_codec_hphl_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RDAC2", NULL, SND_SOC_NOPM, 0, 0, + wcd938x_codec_hphr_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RDAC3", NULL, SND_SOC_NOPM, 0, 0, + wcd938x_codec_ear_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("RDAC4", NULL, SND_SOC_NOPM, 0, 0, + wcd938x_codec_aux_dac_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("RDAC3_MUX", SND_SOC_NOPM, 0, 0, &rx_rdac3_mux), + + SND_SOC_DAPM_SUPPLY("VDD_BUCK", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RXCLK", SND_SOC_NOPM, 0, 0, + wcd938x_codec_enable_rxclk, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY_S("CLS_H_PORT", 1, SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MIXER_E("RX1", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0), + SND_SOC_DAPM_MIXER_E("RX2", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0), + SND_SOC_DAPM_MIXER_E("RX3", SND_SOC_NOPM, 0, 0, NULL, 0, NULL, 0), + + /* rx mixer widgets*/ + SND_SOC_DAPM_MIXER("EAR_RDAC", SND_SOC_NOPM, 0, 0, + ear_rdac_switch, ARRAY_SIZE(ear_rdac_switch)), + SND_SOC_DAPM_MIXER("AUX_RDAC", SND_SOC_NOPM, 0, 0, + aux_rdac_switch, ARRAY_SIZE(aux_rdac_switch)), + SND_SOC_DAPM_MIXER("HPHL_RDAC", SND_SOC_NOPM, 0, 0, + hphl_rdac_switch, ARRAY_SIZE(hphl_rdac_switch)), + SND_SOC_DAPM_MIXER("HPHR_RDAC", SND_SOC_NOPM, 0, 0, + hphr_rdac_switch, ARRAY_SIZE(hphr_rdac_switch)), + + /*output widgets rx*/ + SND_SOC_DAPM_OUTPUT("EAR"), + SND_SOC_DAPM_OUTPUT("AUX"), + SND_SOC_DAPM_OUTPUT("HPHL"), + SND_SOC_DAPM_OUTPUT("HPHR"), +}; + static int wcd938x_get_micb_vout_ctl_val(u32 micb_mv) { /* min micbias voltage is 1V and maximum is 2.85V */ @@ -1827,6 +2512,8 @@ static const struct snd_soc_component_driver soc_codec_dev_wcd938x = { .probe = wcd938x_soc_codec_probe, .controls = wcd938x_snd_controls, .num_controls = ARRAY_SIZE(wcd938x_snd_controls), + .dapm_widgets = wcd938x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(wcd938x_dapm_widgets), };
static void wcd938x_dt_parse_micbias_info(struct device *dev, struct wcd938x_priv *wcd)
This patch adds required dapm widgets for capture path.
Signed-off-by: Srinivas Kandagatla srinivas.kandagatla@linaro.org --- sound/soc/codecs/wcd938x.c | 776 +++++++++++++++++++++++++++++++++++++ 1 file changed, 776 insertions(+)
diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index b33a12d788ca..d251ae35bd81 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -157,6 +157,16 @@ enum { NUM_CODEC_DAIS, };
+static u8 tx_mode_bit[] = { + [ADC_MODE_INVALID] = 0x00, + [ADC_MODE_HIFI] = 0x01, + [ADC_MODE_LO_HIF] = 0x02, + [ADC_MODE_NORMAL] = 0x04, + [ADC_MODE_LP] = 0x08, + [ADC_MODE_ULP1] = 0x10, + [ADC_MODE_ULP2] = 0x20, +}; + struct wcd938x_priv { struct sdw_slave *tx_sdw_dev; struct wcd938x_sdw_priv *sdw_priv[NUM_CODEC_DAIS]; @@ -1240,6 +1250,61 @@ static struct regmap_irq_chip wcd938x_regmap_irq_chip = { .irq_drv_data = NULL, };
+static int wcd938x_get_clk_rate(int mode) +{ + int rate; + + switch (mode) { + case ADC_MODE_ULP2: + rate = SWR_CLK_RATE_0P6MHZ; + break; + case ADC_MODE_ULP1: + rate = SWR_CLK_RATE_1P2MHZ; + break; + case ADC_MODE_LP: + rate = SWR_CLK_RATE_4P8MHZ; + break; + case ADC_MODE_NORMAL: + case ADC_MODE_LO_HIF: + case ADC_MODE_HIFI: + case ADC_MODE_INVALID: + default: + rate = SWR_CLK_RATE_9P6MHZ; + break; + } + + return rate; +} + +static int wcd938x_set_swr_clk_rate(struct snd_soc_component *component, int rate, int bank) +{ + u8 mask = (bank ? 0xF0 : 0x0F); + u8 val = 0; + + switch (rate) { + case SWR_CLK_RATE_0P6MHZ: + val = (bank ? 0x60 : 0x06); + break; + case SWR_CLK_RATE_1P2MHZ: + val = (bank ? 0x50 : 0x05); + break; + case SWR_CLK_RATE_2P4MHZ: + val = (bank ? 0x30 : 0x03); + break; + case SWR_CLK_RATE_4P8MHZ: + val = (bank ? 0x10 : 0x01); + break; + case SWR_CLK_RATE_9P6MHZ: + default: + val = 0x00; + break; + } + snd_soc_component_update_bits(component, WCD938X_DIGITAL_SWR_TX_CLK_RATE, + mask, val); + + return 0; +} + static int wcd938x_io_init(struct wcd938x_priv *wcd938x) { struct regmap *rm = wcd938x->regmap; @@ -1915,6 +1980,455 @@ static int wcd938x_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, return 0; }
+static int wcd938x_codec_enable_dmic(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + u16 dmic_clk_reg, dmic_clk_en_reg; + u8 dmic_sel_mask, dmic_clk_mask; + + switch (w->shift) { + case 0: + case 1: + dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_1_2; + dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC1_CTL; + dmic_clk_mask = WCD938X_DMIC1_RATE_MASK; + dmic_sel_mask = WCD938X_AMIC1_IN_SEL_MASK; + break; + case 2: + case 3: + dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_1_2; + dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC2_CTL; + dmic_clk_mask = WCD938X_DMIC2_RATE_MASK; + dmic_sel_mask = WCD938X_AMIC3_IN_SEL_MASK; + break; + case 4: + case 5: + dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_3_4; + dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC3_CTL; + dmic_clk_mask = WCD938X_DMIC3_RATE_MASK; + dmic_sel_mask = WCD938X_AMIC4_IN_SEL_MASK; + break; + case 6: + case 7: + dmic_clk_reg = WCD938X_DIGITAL_CDC_DMIC_RATE_3_4; + dmic_clk_en_reg = WCD938X_DIGITAL_CDC_DMIC4_CTL; + dmic_clk_mask = WCD938X_DMIC4_RATE_MASK; + dmic_sel_mask = WCD938X_AMIC5_IN_SEL_MASK; + break; + default: + dev_err(component->dev, "%s: Invalid DMIC Selection\n", + __func__); + return -EINVAL; + }; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_AMIC_CTL, + dmic_sel_mask, + WCD938X_AMIC1_IN_SEL_DMIC); + /* 250us sleep as per HW requirement */ + usleep_range(250, 260); + /* Setting DMIC clock rate to 2.4MHz */ + snd_soc_component_write_field(component, dmic_clk_reg, + dmic_clk_mask, + WCD938X_DMIC4_RATE_2P4MHZ); + snd_soc_component_write_field(component, dmic_clk_en_reg, + WCD938X_DMIC_CLK_EN_MASK, 1); + /* enable clock scaling */ + snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_DMIC_CTL, + WCD938X_DMIC_CLK_SCALING_EN_MASK, 0x3); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_AMIC_CTL, + dmic_sel_mask, WCD938X_AMIC1_IN_SEL_AMIC); + snd_soc_component_write_field(component, dmic_clk_en_reg, + WCD938X_DMIC_CLK_EN_MASK, 0); + break; + }; + return 0; +} + +static int wcd938x_tx_swr_ctrl(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int bank; + int rate; + + bank = (wcd938x_swr_get_current_bank(wcd938x->sdw_priv[AIF1_CAP]->sdev)) ? 0 : 1; + bank = bank ? 0 : 1; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (strnstr(w->name, "ADC", sizeof("ADC"))) { + int i = 0, mode = 0; + + if (test_bit(WCD_ADC1, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC1]]; + if (test_bit(WCD_ADC2, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC2]]; + if (test_bit(WCD_ADC3, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC3]]; + if (test_bit(WCD_ADC4, &wcd938x->status_mask)) + mode |= tx_mode_bit[wcd938x->tx_mode[WCD_ADC4]]; + + if (mode != 0) { + for (i = 0; i < ADC_MODE_ULP2; i++) { + if (mode & (1 << i)) { + i++; + break; + } + } + } + rate = wcd938x_get_clk_rate(i); + wcd938x_set_swr_clk_rate(component, rate, bank); + } + + if (strnstr(w->name, "ADC", sizeof("ADC"))) + /* Copy clk settings to active bank */ + wcd938x_set_swr_clk_rate(component, rate, !bank); + break; + case SND_SOC_DAPM_POST_PMD: + if (strnstr(w->name, "ADC", sizeof("ADC"))) { + rate = wcd938x_get_clk_rate(ADC_MODE_INVALID); + wcd938x_set_swr_clk_rate(component, rate, !bank); + wcd938x_set_swr_clk_rate(component, rate, bank); + } + break; + }; + + return 0; +} + +static int wcd938x_get_adc_mode(int val) +{ + int ret = 0; + + switch (val) { + case ADC_MODE_INVALID: + ret = ADC_MODE_VAL_NORMAL; + break; + case ADC_MODE_HIFI: + ret = ADC_MODE_VAL_HIFI; + break; + case ADC_MODE_LO_HIF: + ret = ADC_MODE_VAL_LO_HIF; + break; + case ADC_MODE_NORMAL: + ret = ADC_MODE_VAL_NORMAL; + break; + case ADC_MODE_LP: + ret = ADC_MODE_VAL_LP; + break; + case ADC_MODE_ULP1: + ret = ADC_MODE_VAL_ULP1; + break; + case ADC_MODE_ULP2: + ret = ADC_MODE_VAL_ULP2; + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int wcd938x_codec_enable_adc(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_TX_CLK_EN_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_TX_DIV2_CLK_EN_MASK, 1); + set_bit(w->shift, &wcd938x->status_mask); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_component_write_field(component, WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_TX_CLK_EN_MASK, 0); + clear_bit(w->shift, &wcd938x->status_mask); + break; + }; + + return 0; +} + +static void wcd938x_tx_channel_config(struct snd_soc_component *component, + int channel, int mode) +{ + int reg, mask; + + switch (channel) { + case 0: + reg = WCD938X_ANA_TX_CH2; + mask = WCD938X_HPF1_INIT_MASK; + break; + case 1: + reg = WCD938X_ANA_TX_CH2; + mask = WCD938X_HPF2_INIT_MASK; + break; + case 2: + reg = WCD938X_ANA_TX_CH4; + mask = WCD938X_HPF3_INIT_MASK; + break; + case 3: + reg = WCD938X_ANA_TX_CH4; + mask = WCD938X_HPF4_INIT_MASK; + break; + } + + snd_soc_component_write_field(component, reg, mask, mode); +} + +static int wcd938x_adc_enable_req(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int mode; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_REQ_CTL, + WCD938X_FS_RATE_4P8_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_REQ_CTL, + WCD938X_NO_NOTCH_MASK, 0); + wcd938x_tx_channel_config(component, w->shift, 1); + mode = wcd938x_get_adc_mode(wcd938x->tx_mode[w->shift]); + if (mode < 0) { + dev_info(component->dev, "Invalid ADC mode\n"); + return -EINVAL; + } + switch (w->shift) { + case 0: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, + WCD938X_TXD0_MODE_MASK, mode); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_TXD0_CLK_EN_MASK, 1); + break; + case 1: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, + WCD938X_TXD1_MODE_MASK, mode); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_TXD1_CLK_EN_MASK, 1); + break; + case 2: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, + WCD938X_TXD2_MODE_MASK, mode); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_TXD2_CLK_EN_MASK, 1); + break; + case 3: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, + WCD938X_TXD3_MODE_MASK, mode); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_TXD3_CLK_EN_MASK, 1); + break; + default: + break; + } + + wcd938x_tx_channel_config(component, w->shift, 0); + break; + case SND_SOC_DAPM_POST_PMD: + switch (w->shift) { + case 0: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, + WCD938X_TXD0_MODE_MASK, 0); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_TXD0_CLK_EN_MASK, 0); + break; + case 1: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_0_1, + WCD938X_TXD1_MODE_MASK, 0); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_TXD1_CLK_EN_MASK, 0); + break; + case 2: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, + WCD938X_TXD2_MODE_MASK, 0); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_TXD2_CLK_EN_MASK, 0); + break; + case 3: + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_TX_ANA_MODE_2_3, + WCD938X_TXD3_MODE_MASK, 0); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_TXD3_CLK_EN_MASK, 0); + break; + default: + break; + } + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_TX_DIV2_CLK_EN_MASK, 0); + break; + }; + + return 0; +} + +static int wcd938x_micbias_control(struct snd_soc_component *component, + int micb_num, int req, bool is_dapm) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + int micb_index = micb_num - 1; + u16 micb_reg; + + switch (micb_num) { + case MIC_BIAS_1: + micb_reg = WCD938X_ANA_MICB1; + break; + case MIC_BIAS_2: + micb_reg = WCD938X_ANA_MICB2; + break; + case MIC_BIAS_3: + micb_reg = WCD938X_ANA_MICB3; + break; + case MIC_BIAS_4: + micb_reg = WCD938X_ANA_MICB4; + break; + default: + dev_err(component->dev, "%s: Invalid micbias number: %d\n", + __func__, micb_num); + return -EINVAL; + }; + + switch (req) { + case MICB_PULLUP_ENABLE: + wcd938x->pullup_ref[micb_index]++; + if ((wcd938x->pullup_ref[micb_index] == 1) && + (wcd938x->micb_ref[micb_index] == 0)) + snd_soc_component_write_field(component, micb_reg, + WCD938X_MICB_EN_MASK, + WCD938X_MICB_PULL_UP); + break; + case MICB_PULLUP_DISABLE: + if (wcd938x->pullup_ref[micb_index] > 0) + wcd938x->pullup_ref[micb_index]--; + + if ((wcd938x->pullup_ref[micb_index] == 0) && + (wcd938x->micb_ref[micb_index] == 0)) + snd_soc_component_write_field(component, micb_reg, + WCD938X_MICB_EN_MASK, 0); + break; + case MICB_ENABLE: + wcd938x->micb_ref[micb_index]++; + if (wcd938x->micb_ref[micb_index] == 1) { + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_DIG_CLK_CTL, + WCD938X_TX_CLK_EN_MASK, 0xF); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_ANA_CLK_CTL, + WCD938X_ANA_TX_DIV2_CLK_EN_MASK, 1); + snd_soc_component_write_field(component, + WCD938X_DIGITAL_CDC_ANA_TX_CLK_CTL, + WCD938X_TX_SC_CLK_EN_MASK, 1); + + snd_soc_component_write_field(component, micb_reg, + WCD938X_MICB_EN_MASK, + WCD938X_MICB_ENABLE); + } + + break; + case MICB_DISABLE: + if (wcd938x->micb_ref[micb_index] > 0) + wcd938x->micb_ref[micb_index]--; + + if ((wcd938x->micb_ref[micb_index] == 0) && + (wcd938x->pullup_ref[micb_index] > 0)) + snd_soc_component_write_field(component, micb_reg, + WCD938X_MICB_EN_MASK, + WCD938X_MICB_PULL_UP); + else if ((wcd938x->micb_ref[micb_index] == 0) && + (wcd938x->pullup_ref[micb_index] == 0)) { + + snd_soc_component_write_field(component, micb_reg, + WCD938X_MICB_EN_MASK, 0); + } + break; + }; + + return 0; +} + +static int wcd938x_codec_enable_micbias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + int micb_num = w->shift; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd938x_micbias_control(component, micb_num, MICB_ENABLE, true); + break; + case SND_SOC_DAPM_POST_PMU: + /* 1 msec delay as per HW requirement */ + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + wcd938x_micbias_control(component, micb_num, MICB_DISABLE, true); + break; + }; + + return 0; +} + +static int wcd938x_codec_enable_micbias_pullup(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + int micb_num = w->shift; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wcd938x_micbias_control(component, micb_num, + MICB_PULLUP_ENABLE, true); + break; + case SND_SOC_DAPM_POST_PMU: + /* 1 msec delay as per HW requirement */ + usleep_range(1000, 1100); + break; + case SND_SOC_DAPM_POST_PMD: + wcd938x_micbias_control(component, micb_num, + MICB_PULLUP_DISABLE, true); + break; + }; + + return 0; +} + static int wcd938x_tx_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2093,10 +2607,30 @@ static const char * const rx_hph_mode_mux_text[] = { "CLS_H_ULP", "CLS_AB_HIFI", "CLS_AB_LP", "CLS_AB_LOHIFI", };
+static const char * const adc2_mux_text[] = { + "INP2", "INP3" +}; + +static const char * const adc3_mux_text[] = { + "INP4", "INP6" +}; + +static const char * const adc4_mux_text[] = { + "INP5", "INP7" +}; + static const char * const rdac3_mux_text[] = { "RX1", "RX3" };
+static const char * const hdr12_mux_text[] = { + "NO_HDR12", "HDR12" +}; + +static const char * const hdr34_mux_text[] = { + "NO_HDR34", "HDR34" +}; + static const struct soc_enum tx_mode_mux_enum_wcd9380[] = { SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tx_mode_mux_text_wcd9380), tx_mode_mux_text_wcd9380), @@ -2127,10 +2661,78 @@ static const struct soc_enum rx_hph_mode_mux_enum = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), rx_hph_mode_mux_text);
+static const struct soc_enum adc2_enum = + SOC_ENUM_SINGLE(WCD938X_TX_NEW_AMIC_MUX_CFG, 7, + ARRAY_SIZE(adc2_mux_text), adc2_mux_text); + +static const struct soc_enum adc3_enum = + SOC_ENUM_SINGLE(WCD938X_TX_NEW_AMIC_MUX_CFG, 6, + ARRAY_SIZE(adc3_mux_text), adc3_mux_text); + +static const struct soc_enum adc4_enum = + SOC_ENUM_SINGLE(WCD938X_TX_NEW_AMIC_MUX_CFG, 5, + ARRAY_SIZE(adc4_mux_text), adc4_mux_text); + +static const struct soc_enum hdr12_enum = + SOC_ENUM_SINGLE(WCD938X_TX_NEW_AMIC_MUX_CFG, 4, + ARRAY_SIZE(hdr12_mux_text), hdr12_mux_text); + +static const struct soc_enum hdr34_enum = + SOC_ENUM_SINGLE(WCD938X_TX_NEW_AMIC_MUX_CFG, 3, + ARRAY_SIZE(hdr34_mux_text), hdr34_mux_text); + static const struct soc_enum rdac3_enum = SOC_ENUM_SINGLE(WCD938X_DIGITAL_CDC_EAR_PATH_CTL, 0, ARRAY_SIZE(rdac3_mux_text), rdac3_mux_text);
+static const struct snd_kcontrol_new adc1_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new adc2_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new adc3_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new adc4_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic1_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic2_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic3_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic4_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic5_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic6_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic7_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + +static const struct snd_kcontrol_new dmic8_switch[] = { + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) +}; + static const struct snd_kcontrol_new ear_rdac_switch[] = { SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) }; @@ -2147,6 +2749,21 @@ static const struct snd_kcontrol_new hphr_rdac_switch[] = { SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0) };
+static const struct snd_kcontrol_new tx_adc2_mux = + SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum); + +static const struct snd_kcontrol_new tx_adc3_mux = + SOC_DAPM_ENUM("ADC3 MUX Mux", adc3_enum); + +static const struct snd_kcontrol_new tx_adc4_mux = + SOC_DAPM_ENUM("ADC4 MUX Mux", adc4_enum); + +static const struct snd_kcontrol_new tx_hdr12_mux = + SOC_DAPM_ENUM("HDR12 MUX Mux", hdr12_enum); + +static const struct snd_kcontrol_new tx_hdr34_mux = + SOC_DAPM_ENUM("HDR34 MUX Mux", hdr34_enum); + static const struct snd_kcontrol_new rx_rdac3_mux = SOC_DAPM_ENUM("RDAC3_MUX Mux", rdac3_enum);
@@ -2279,6 +2896,165 @@ static const struct snd_kcontrol_new wcd938x_snd_controls[] = { };
static const struct snd_soc_dapm_widget wcd938x_dapm_widgets[] = { + + /*input widgets*/ + SND_SOC_DAPM_INPUT("AMIC1"), + SND_SOC_DAPM_INPUT("AMIC2"), + SND_SOC_DAPM_INPUT("AMIC3"), + SND_SOC_DAPM_INPUT("AMIC4"), + SND_SOC_DAPM_INPUT("AMIC5"), + SND_SOC_DAPM_INPUT("AMIC6"), + SND_SOC_DAPM_INPUT("AMIC7"), + SND_SOC_DAPM_MIC("Analog Mic1", NULL), + SND_SOC_DAPM_MIC("Analog Mic2", NULL), + SND_SOC_DAPM_MIC("Analog Mic3", NULL), + SND_SOC_DAPM_MIC("Analog Mic4", NULL), + SND_SOC_DAPM_MIC("Analog Mic5", NULL), + + /*tx widgets*/ + SND_SOC_DAPM_ADC_E("ADC1", NULL, SND_SOC_NOPM, 0, 0, + wcd938x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC2", NULL, SND_SOC_NOPM, 1, 0, + wcd938x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC3", NULL, SND_SOC_NOPM, 2, 0, + wcd938x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC4", NULL, SND_SOC_NOPM, 3, 0, + wcd938x_codec_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 1, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 2, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 3, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 4, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 5, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC7", NULL, SND_SOC_NOPM, 6, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC8", NULL, SND_SOC_NOPM, 7, 0, + wcd938x_codec_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER_E("ADC1 REQ", SND_SOC_NOPM, 0, 0, + NULL, 0, wcd938x_adc_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC2 REQ", SND_SOC_NOPM, 1, 0, + NULL, 0, wcd938x_adc_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC3 REQ", SND_SOC_NOPM, 2, 0, + NULL, 0, wcd938x_adc_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC4 REQ", SND_SOC_NOPM, 3, 0, NULL, 0, + wcd938x_adc_enable_req, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, &tx_adc2_mux), + SND_SOC_DAPM_MUX("ADC3 MUX", SND_SOC_NOPM, 0, 0, &tx_adc3_mux), + SND_SOC_DAPM_MUX("ADC4 MUX", SND_SOC_NOPM, 0, 0, &tx_adc4_mux), + SND_SOC_DAPM_MUX("HDR12 MUX", SND_SOC_NOPM, 0, 0, &tx_hdr12_mux), + SND_SOC_DAPM_MUX("HDR34 MUX", SND_SOC_NOPM, 0, 0, &tx_hdr34_mux), + + /*tx mixers*/ + SND_SOC_DAPM_MIXER_E("ADC1_MIXER", SND_SOC_NOPM, 0, 0, adc1_switch, + ARRAY_SIZE(adc1_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC2_MIXER", SND_SOC_NOPM, 0, 0, adc2_switch, + ARRAY_SIZE(adc2_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC3_MIXER", SND_SOC_NOPM, 0, 0, adc3_switch, + ARRAY_SIZE(adc3_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("ADC4_MIXER", SND_SOC_NOPM, 0, 0, adc4_switch, + ARRAY_SIZE(adc4_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC1_MIXER", SND_SOC_NOPM, 0, 0, dmic1_switch, + ARRAY_SIZE(dmic1_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC2_MIXER", SND_SOC_NOPM, 0, 0, dmic2_switch, + ARRAY_SIZE(dmic2_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC3_MIXER", SND_SOC_NOPM, 0, 0, dmic3_switch, + ARRAY_SIZE(dmic3_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC4_MIXER", SND_SOC_NOPM, 0, 0, dmic4_switch, + ARRAY_SIZE(dmic4_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC5_MIXER", SND_SOC_NOPM, 0, 0, dmic5_switch, + ARRAY_SIZE(dmic5_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC6_MIXER", SND_SOC_NOPM, 0, 0, dmic6_switch, + ARRAY_SIZE(dmic6_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC7_MIXER", SND_SOC_NOPM, 0, 0, dmic7_switch, + ARRAY_SIZE(dmic7_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("DMIC8_MIXER", SND_SOC_NOPM, 0, 0, dmic8_switch, + ARRAY_SIZE(dmic8_switch), wcd938x_tx_swr_ctrl, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + /* micbias widgets*/ + SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0, + wcd938x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0, + wcd938x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0, + wcd938x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS4", SND_SOC_NOPM, MIC_BIAS_4, 0, + wcd938x_codec_enable_micbias, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + /* micbias pull up widgets*/ + SND_SOC_DAPM_SUPPLY("VA MIC BIAS1", SND_SOC_NOPM, MIC_BIAS_1, 0, + wcd938x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VA MIC BIAS2", SND_SOC_NOPM, MIC_BIAS_2, 0, + wcd938x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VA MIC BIAS3", SND_SOC_NOPM, MIC_BIAS_3, 0, + wcd938x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("VA MIC BIAS4", SND_SOC_NOPM, MIC_BIAS_4, 0, + wcd938x_codec_enable_micbias_pullup, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + /*output widgets tx*/ + SND_SOC_DAPM_OUTPUT("ADC1_OUTPUT"), + SND_SOC_DAPM_OUTPUT("ADC2_OUTPUT"), + SND_SOC_DAPM_OUTPUT("ADC3_OUTPUT"), + SND_SOC_DAPM_OUTPUT("ADC4_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC1_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC2_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC3_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC4_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC5_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC6_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC7_OUTPUT"), + SND_SOC_DAPM_OUTPUT("DMIC8_OUTPUT"), + SND_SOC_DAPM_INPUT("IN1_HPHL"), SND_SOC_DAPM_INPUT("IN2_HPHR"), SND_SOC_DAPM_INPUT("IN3_AUX"),
This patch adds audio routing for both playback and capture.
Signed-off-by: Srinivas Kandagatla srinivas.kandagatla@linaro.org --- sound/soc/codecs/wcd938x.c | 94 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+)
diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index d251ae35bd81..d659de0e3274 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -3123,6 +3123,98 @@ static const struct snd_soc_dapm_widget wcd938x_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("AUX"), SND_SOC_DAPM_OUTPUT("HPHL"), SND_SOC_DAPM_OUTPUT("HPHR"), + +}; + +static const struct snd_soc_dapm_route wcd938x_audio_map[] = { + {"ADC1_OUTPUT", NULL, "ADC1_MIXER"}, + {"ADC1_MIXER", "Switch", "ADC1 REQ"}, + {"ADC1 REQ", NULL, "ADC1"}, + {"ADC1", NULL, "AMIC1"}, + + {"ADC2_OUTPUT", NULL, "ADC2_MIXER"}, + {"ADC2_MIXER", "Switch", "ADC2 REQ"}, + {"ADC2 REQ", NULL, "ADC2"}, + {"ADC2", NULL, "HDR12 MUX"}, + {"HDR12 MUX", "NO_HDR12", "ADC2 MUX"}, + {"HDR12 MUX", "HDR12", "AMIC1"}, + {"ADC2 MUX", "INP3", "AMIC3"}, + {"ADC2 MUX", "INP2", "AMIC2"}, + + {"ADC3_OUTPUT", NULL, "ADC3_MIXER"}, + {"ADC3_MIXER", "Switch", "ADC3 REQ"}, + {"ADC3 REQ", NULL, "ADC3"}, + {"ADC3", NULL, "HDR34 MUX"}, + {"HDR34 MUX", "NO_HDR34", "ADC3 MUX"}, + {"HDR34 MUX", "HDR34", "AMIC5"}, + {"ADC3 MUX", "INP4", "AMIC4"}, + {"ADC3 MUX", "INP6", "AMIC6"}, + + {"ADC4_OUTPUT", NULL, "ADC4_MIXER"}, + {"ADC4_MIXER", "Switch", "ADC4 REQ"}, + {"ADC4 REQ", NULL, "ADC4"}, + {"ADC4", NULL, "ADC4 MUX"}, + {"ADC4 MUX", "INP5", "AMIC5"}, + {"ADC4 MUX", "INP7", "AMIC7"}, + + {"DMIC1_OUTPUT", NULL, "DMIC1_MIXER"}, + {"DMIC1_MIXER", "Switch", "DMIC1"}, + + {"DMIC2_OUTPUT", NULL, "DMIC2_MIXER"}, + {"DMIC2_MIXER", "Switch", "DMIC2"}, + + {"DMIC3_OUTPUT", NULL, "DMIC3_MIXER"}, + {"DMIC3_MIXER", "Switch", "DMIC3"}, + + {"DMIC4_OUTPUT", NULL, "DMIC4_MIXER"}, + {"DMIC4_MIXER", "Switch", "DMIC4"}, + + {"DMIC5_OUTPUT", NULL, "DMIC5_MIXER"}, + {"DMIC5_MIXER", "Switch", "DMIC5"}, + + {"DMIC6_OUTPUT", NULL, "DMIC6_MIXER"}, + {"DMIC6_MIXER", "Switch", "DMIC6"}, + + {"DMIC7_OUTPUT", NULL, "DMIC7_MIXER"}, + {"DMIC7_MIXER", "Switch", "DMIC7"}, + + {"DMIC8_OUTPUT", NULL, "DMIC8_MIXER"}, + {"DMIC8_MIXER", "Switch", "DMIC8"}, + + {"IN1_HPHL", NULL, "VDD_BUCK"}, + {"IN1_HPHL", NULL, "CLS_H_PORT"}, + + {"RX1", NULL, "IN1_HPHL"}, + {"RX1", NULL, "RXCLK"}, + {"RDAC1", NULL, "RX1"}, + {"HPHL_RDAC", "Switch", "RDAC1"}, + {"HPHL PGA", NULL, "HPHL_RDAC"}, + {"HPHL", NULL, "HPHL PGA"}, + + {"IN2_HPHR", NULL, "VDD_BUCK"}, + {"IN2_HPHR", NULL, "CLS_H_PORT"}, + {"RX2", NULL, "IN2_HPHR"}, + {"RDAC2", NULL, "RX2"}, + {"RX2", NULL, "RXCLK"}, + {"HPHR_RDAC", "Switch", "RDAC2"}, + {"HPHR PGA", NULL, "HPHR_RDAC"}, + {"HPHR", NULL, "HPHR PGA"}, + + {"IN3_AUX", NULL, "VDD_BUCK"}, + {"IN3_AUX", NULL, "CLS_H_PORT"}, + {"RX3", NULL, "IN3_AUX"}, + {"RDAC4", NULL, "RX3"}, + {"RX3", NULL, "RXCLK"}, + {"AUX_RDAC", "Switch", "RDAC4"}, + {"AUX PGA", NULL, "AUX_RDAC"}, + {"AUX", NULL, "AUX PGA"}, + + {"RDAC3_MUX", "RX3", "RX3"}, + {"RDAC3_MUX", "RX1", "RX1"}, + {"RDAC3", NULL, "RDAC3_MUX"}, + {"EAR_RDAC", "Switch", "RDAC3"}, + {"EAR PGA", NULL, "EAR_RDAC"}, + {"EAR", NULL, "EAR PGA"}, };
static int wcd938x_get_micb_vout_ctl_val(u32 micb_mv) @@ -3290,6 +3382,8 @@ static const struct snd_soc_component_driver soc_codec_dev_wcd938x = { .num_controls = ARRAY_SIZE(wcd938x_snd_controls), .dapm_widgets = wcd938x_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(wcd938x_dapm_widgets), + .dapm_routes = wcd938x_audio_map, + .num_dapm_routes = ARRAY_SIZE(wcd938x_audio_map), };
static void wcd938x_dt_parse_micbias_info(struct device *dev, struct wcd938x_priv *wcd)
On Tue, 1 Jun 2021 12:31:49 +0100, Srinivas Kandagatla wrote:
This patchset adds support for Qualcomm WCD938X codec.
Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC connected over SoundWire. This device has two SoundWire devices, RX and TX respectively supporting 4 x ADCs, ClassH, Ear, Aux PA, 2xHPH, 7 x TX diff inputs, 8 DMICs and MBHC.
[...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
Thanks!
[1/9] ASoC: dt-bindings: wcd938x: add bindings for wcd938x commit: 10ee3e07d32bede6cd007fb76150a1ccd0628852 [2/9] ASoC: codecs: wcd-clsh: add new version support commit: 19c5d1f6a0c39cf910c8d211ea40ff758bcb3f49 [3/9] ASoC: codecs: wcd938x: add basic driver commit: 8d78602aa87a3805902bed83157526fdc5b837d4 [4/9] ASoC: dt-bindings: wcd938x-sdw: add bindings for wcd938x-sdw commit: e02c65f3a7ce11ce522e805c78ed2f1da5d96975 [5/9] ASoC: codecs: wcd938x-sdw: add SoundWire driver commit: 16572522aece6a142d303a25f32544643f52c383 [6/9] ASoC: codecs: wcd938x: add basic controls commit: e8ba1e05bdc016700c85fad559a812c2e795442f [7/9] ASoC: codecs: wcd938x: add playback dapm widgets commit: 8da9db0cd6694c98f64b6ec413337ac834e05bb0 [8/9] ASoC: codecs: wcd938x: add capture dapm widgets commit: d5add08fcbce35faeeffa62d7e8f21fd979d8420 [9/9] ASoC: codecs: wcd938x: add audio routing (no commit info)
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
participants (2)
-
Mark Brown
-
Srinivas Kandagatla