Unverified Commit a918e291 authored by Mark Brown's avatar Mark Brown
Browse files

Merge series "ASoC: codecs: add wcd938x support" from Srinivas Kandagatla...

Merge series "ASoC: codecs: add wcd938x support" from Srinivas Kandagatla <srinivas.kandagatla@linaro.org>:

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 v8:
 - moved Kconfig and Makefile changes to last patch as suggested by Mark
 - removed array of enums and used static entries instead. Suggested by Mark
 - return true if put succeeds, Suggested by Mark
 - removed some unneeded semi-colons in switch

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 and Kconfig

 .../bindings/sound/qcom,wcd938x-sdw.yaml      |   70 +
 .../bindings/sound/qcom,wcd938x.yaml          |  146 +
 sound/soc/codecs/Kconfig                      |   14 +
 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                    | 3753 +++++++++++++++++
 sound/soc/codecs/wcd938x.h                    |  720 ++++
 9 files changed, 5376 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

--
2.21.0
parents 03c0cbd9 04544222
Loading
Loading
Loading
Loading
+70 −0
Original line number Diff line number Diff line
# 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>;
        };
    };

...
+146 −0
Original line number Diff line number Diff line
# 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>;
        };
    };

...
+14 −0
Original line number Diff line number Diff line
@@ -234,6 +234,8 @@ config SND_SOC_ALL_CODECS
	imply SND_SOC_UDA1380
	imply SND_SOC_WCD9335
	imply SND_SOC_WCD934X
	imply SND_SOC_WCD937X
	imply SND_SOC_WCD938X
	imply SND_SOC_LPASS_RX_MACRO
	imply SND_SOC_LPASS_TX_MACRO
	imply SND_SOC_WL1273
@@ -1554,6 +1556,18 @@ 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_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

+4 −0
Original line number Diff line number Diff line
@@ -255,6 +255,8 @@ snd-soc-uda1380-objs := uda1380.o
snd-soc-wcd-mbhc-objs := wcd-mbhc-v2.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
@@ -580,6 +582,8 @@ obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
obj-$(CONFIG_SND_SOC_WCD_MBHC)	+= snd-soc-wcd-mbhc.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
+338 −10
Original line number Diff line number Diff line
@@ -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,17 +784,31 @@ static int _wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, int req_state,
{
	switch (req_state) {
	case WCD_CLSH_STATE_EAR:
		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:
		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:
		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:
		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;
}
Loading