linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 00/14] ASoC: Add support to WCD9335 Audio Codec
@ 2018-09-17  0:57 srinivas.kandagatla
  2018-09-17  0:57 ` [PATCH v4 01/14] ASoC: dt-bindings: update wcd9335 bindings srinivas.kandagatla
                   ` (13 more replies)
  0 siblings, 14 replies; 22+ messages in thread
From: srinivas.kandagatla @ 2018-09-17  0:57 UTC (permalink / raw)
  To: lee.jones, robh+dt, broonie
  Cc: mark.rutland, lgirdwood, bgoswami, devicetree, linux-kernel,
	vkoul, alsa-devel, Srinivas Kandagatla

From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

Thankyou for reviewing v3 patchset, here is v4 addressing comments from v3.

Qualcomm WCD9335 Codec is a standalone Hi-Fi audio codec IC.
It is integrated in multiple Qualcomm SoCs like: MSM8996, MSM8976,
and MSM8956 chipsets.

WCD9335 had multiple functional blocks, like: Soundwire controller,
interrupt mux, pin controller, Audio codec, MBHC, MAD(Mic activity Detection),
Ultrasonic proximity and pen detection, Battery-voltage monitoring and
Codec processing engine.

Currently this patchset has been only tested with SLIMbus interface due
to hardware avaiablity, but it can be easily made to work with both SLIMbus
and I2C/I2S.    

This patchset adds very basic playback and capture support witout much
fancy features. New features will be added once the basic support is in.
This patchset is tested on top of linux-next on DB820c for both playback
, capture paths and MBHC.

Some parts of the code has been inherited from Qualcomm andriod kernel,
so credits to various authors.

WCD9335 can be interfaced via I2S/I2C or SLIMbus. 

Here is my test branch incase someone want to try this out:
https://git.linaro.org/people/srinivas.kandagatla/linux.git/log/?h=wcd9335

Thanks,
Srini

Changes since v3 (https://lkml.org/lkml/2018/9/4/318/)
 - Updated mbhc dt bindings according to Robs Comments.
 - Added a cleanup patch to common up fixups.
 - Addressed various comments on mfd driver by Lee Jones.
 - Added acks on bindings and irq support.
 - fixed module loading

Srinivas Kandagatla (14):
  ASoC: dt-bindings: update wcd9335 bindings.
  mfd: wcd9335: add support to wcd9335 core
  mfd: wcd9335: add wcd irq support
  ASoC: wcd9335: add support to wcd9335 codec
  ASoC: wcd9335: add CLASS-H Controller support
  ASoC: wcd9335: add basic controls
  ASoC: wcd9335: add playback dapm widgets
  ASoC: wcd9335: add capture dapm widgets
  ASoC: wcd9335: add audio routings
  ASoC: dt-bindings: Add WCD9335 MBHC specific properties
  ASoC: wcd9335: add mbhc support
  ASoC: apq8096: add slim support
  ASoC: apq8096: add headset JACK support
  ASoC: qcom: common: move be_hw_fixup to common

 .../devicetree/bindings/sound/qcom,wcd9335.txt     |   30 +-
 drivers/mfd/Kconfig                                |   13 +
 drivers/mfd/Makefile                               |    4 +
 drivers/mfd/wcd9335-core.c                         |  394 ++
 include/linux/mfd/wcd9335/registers.h              |  640 +++
 include/linux/mfd/wcd9335/wcd9335.h                |   81 +
 sound/soc/codecs/Kconfig                           |    5 +
 sound/soc/codecs/Makefile                          |    2 +
 sound/soc/codecs/wcd-clsh-v2.c                     |  577 +++
 sound/soc/codecs/wcd-clsh-v2.h                     |   49 +
 sound/soc/codecs/wcd9335.c                         | 5241 ++++++++++++++++++++
 sound/soc/qcom/apq8096.c                           |  128 +-
 sound/soc/qcom/common.c                            |   17 +
 sound/soc/qcom/sdm845.c                            |   22 +-
 14 files changed, 7168 insertions(+), 35 deletions(-)
 create mode 100644 drivers/mfd/wcd9335-core.c
 create mode 100644 include/linux/mfd/wcd9335/registers.h
 create mode 100644 include/linux/mfd/wcd9335/wcd9335.h
 create mode 100644 sound/soc/codecs/wcd-clsh-v2.c
 create mode 100644 sound/soc/codecs/wcd-clsh-v2.h
 create mode 100644 sound/soc/codecs/wcd9335.c

-- 
2.9.3


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH v4 01/14] ASoC: dt-bindings: update wcd9335 bindings.
  2018-09-17  0:57 [PATCH v4 00/14] ASoC: Add support to WCD9335 Audio Codec srinivas.kandagatla
@ 2018-09-17  0:57 ` srinivas.kandagatla
  2018-09-17  0:57 ` [PATCH v4 02/14] mfd: wcd9335: add support to wcd9335 core srinivas.kandagatla
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: srinivas.kandagatla @ 2018-09-17  0:57 UTC (permalink / raw)
  To: lee.jones, robh+dt, broonie
  Cc: mark.rutland, lgirdwood, bgoswami, devicetree, linux-kernel,
	vkoul, alsa-devel, Srinivas Kandagatla

From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

This patch updates wcd9335 bindings with recommended properties.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Reviewed-by: Rob Herring <robh@kernel.org>
---
 Documentation/devicetree/bindings/sound/qcom,wcd9335.txt | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt b/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt
index 1d8d49e..5d6ea66 100644
--- a/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt
+++ b/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt
@@ -34,12 +34,12 @@ Required properties with SLIMbus Interface:
 	Definition: Interrupt names of WCD INTR1 and INTR2
 	Should be: "intr1", "intr2"
 
-- reset-gpio:
+- reset-gpios:
 	Usage: required
 	Value type: <String Array>
 	Definition: Reset gpio line
 
-- qcom,ifd:
+- slim-ifc-dev:
 	Usage: required
 	Value type: <phandle>
 	Definition: SLIM interface device
@@ -104,13 +104,13 @@ Required properties with SLIMbus Interface:
 	Value type: <u32>
 	Definition: Must be 1
 
-codec@1{
+audio-codec@1{
 	compatible = "slim217,1a0";
 	reg  = <1 0>;
 	interrupts = <&msmgpio 54 IRQ_TYPE_LEVEL_HIGH>;
 	interrupt-names = "intr2"
-	reset-gpio = <&msmgpio 64 0>;
-	qcom,ifd  = <&wc9335_ifd>;
+	reset-gpios = <&msmgpio 64 0>;
+	slim-ifc-dev  = <&wc9335_ifd>;
 	clock-names = "mclk", "native";
 	clocks = <&rpmcc RPM_SMD_DIV_CLK1>,
 		 <&rpmcc RPM_SMD_BB_CLK1>;
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v4 02/14] mfd: wcd9335: add support to wcd9335 core
  2018-09-17  0:57 [PATCH v4 00/14] ASoC: Add support to WCD9335 Audio Codec srinivas.kandagatla
  2018-09-17  0:57 ` [PATCH v4 01/14] ASoC: dt-bindings: update wcd9335 bindings srinivas.kandagatla
@ 2018-09-17  0:57 ` srinivas.kandagatla
  2018-10-24  7:07   ` Lee Jones
  2018-09-17  0:57 ` [PATCH v4 03/14] mfd: wcd9335: add wcd irq support srinivas.kandagatla
                   ` (11 subsequent siblings)
  13 siblings, 1 reply; 22+ messages in thread
From: srinivas.kandagatla @ 2018-09-17  0:57 UTC (permalink / raw)
  To: lee.jones, robh+dt, broonie
  Cc: mark.rutland, lgirdwood, bgoswami, devicetree, linux-kernel,
	vkoul, alsa-devel, Srinivas Kandagatla

From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

Qualcomm WCD9335 Codec is a standalone Hi-Fi audio codec IC,
It has mulitple blocks like Soundwire controller, codec,
Codec processing engine, ClassH controller, interrupt mux.
It supports both I2S/I2C and SLIMbus audio interfaces.

This patch adds support to SLIMbus audio interface.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Reviewed-by: Vinod Koul <vkoul@kernel.org>
---
 drivers/mfd/Kconfig                   |  13 +
 drivers/mfd/Makefile                  |   4 +
 drivers/mfd/wcd9335-core.c            | 316 +++++++++++++++++
 include/linux/mfd/wcd9335/registers.h | 640 ++++++++++++++++++++++++++++++++++
 include/linux/mfd/wcd9335/wcd9335.h   |  45 +++
 5 files changed, 1018 insertions(+)
 create mode 100644 drivers/mfd/wcd9335-core.c
 create mode 100644 include/linux/mfd/wcd9335/registers.h
 create mode 100644 include/linux/mfd/wcd9335/wcd9335.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 11841f4..a7bff87 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1807,6 +1807,19 @@ config MFD_WM97xx
 	  support for the WM97xx, in order to use the actual functionaltiy of
 	  the device other drivers must be enabled.
 
+config MFD_WCD9335_SLIM
+	tristate "Qualcomm WCD9335 with SLIMbus"
+	select MFD_CORE
+	select REGMAP_IRQ
+	select REGMAP_SLIMBUS
+	depends on SLIMBUS
+	help
+	  The WCD9335 is a standalone Hi-Fi audio CODEC IC, supports Qualcomm
+	  Technologies, Inc. (QTI) multimedia solutions, including the MSM8996,
+	  MSM8976, and MSM8956 chipsets. It has in-build Soundwire controller,
+	  interrupt mux. It supports both I2S/I2C and SLIMbus audio interfaces.
+	  This option selects SLIMbus audio interface.
+
 config MFD_STW481X
 	tristate "Support for ST Microelectronics STw481x"
 	depends on I2C && (ARCH_NOMADIK || COMPILE_TEST)
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 5856a94..9d0b98d 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -56,6 +56,10 @@ endif
 ifeq ($(CONFIG_MFD_CS47L24),y)
 obj-$(CONFIG_MFD_ARIZONA)	+= cs47l24-tables.o
 endif
+
+obj-$(CONFIG_MFD_WCD9335_SLIM)	+= wcd9335.o
+wcd9335-objs			:= wcd9335-core.o
+
 obj-$(CONFIG_MFD_WM8400)	+= wm8400-core.o
 wm831x-objs			:= wm831x-core.o wm831x-irq.o wm831x-otp.o
 wm831x-objs			+= wm831x-auxadc.o
diff --git a/drivers/mfd/wcd9335-core.c b/drivers/mfd/wcd9335-core.c
new file mode 100644
index 0000000..81ec0fc
--- /dev/null
+++ b/drivers/mfd/wcd9335-core.c
@@ -0,0 +1,316 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018, Linaro Limited
+
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/wcd9335/registers.h>
+#include <linux/mfd/wcd9335/wcd9335.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slimbus.h>
+
+#define WCD9335_SLIM_INTERFACE_DEVICE_INDEX	0
+
+static const struct mfd_cell wcd9335_devices[] = {
+	{ .name = "wcd9335-codec", },
+};
+
+static const struct regmap_range_cfg wcd9335_ranges[] = {
+	{
+		.name = "WCD9335",
+		.range_min =  0x0,
+		.range_max =  WCD9335_MAX_REGISTER,
+		.selector_reg = WCD9335_REG(0x0, 0),
+		.selector_mask = 0xff,
+		.selector_shift = 0,
+		.window_start = 0x0,
+		.window_len = 0x1000,
+	},
+};
+
+static bool wcd9335_is_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WCD9335_INTR_PIN1_STATUS0...WCD9335_INTR_PIN2_CLEAR3:
+	case WCD9335_ANA_MBHC_RESULT_3:
+	case WCD9335_ANA_MBHC_RESULT_2:
+	case WCD9335_ANA_MBHC_RESULT_1:
+	case WCD9335_ANA_MBHC_MECH:
+	case WCD9335_ANA_MBHC_ELECT:
+	case WCD9335_ANA_MBHC_ZDET:
+	case WCD9335_ANA_MICB2:
+	case WCD9335_ANA_RCO:
+	case WCD9335_ANA_BIAS:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static struct regmap_config wcd9335_regmap_config = {
+	.reg_bits = 16,
+	.val_bits = 8,
+	.cache_type = REGCACHE_RBTREE,
+	.max_register = WCD9335_MAX_REGISTER,
+	.can_multi_write = true,
+	.ranges = wcd9335_ranges,
+	.num_ranges = ARRAY_SIZE(wcd9335_ranges),
+	.volatile_reg = wcd9335_is_volatile_register,
+};
+
+static const struct regmap_range_cfg wcd9335_interface_ranges[] = {
+	{
+		.name = "WCD9335-Interface",
+		.range_min =  0x0,
+		.range_max = WCD9335_REG(0, 0x7ff),
+		.selector_reg = WCD9335_REG(0, 0x0),
+		.selector_mask = 0xff,
+		.selector_shift = 0,
+		.window_start = 0x0,
+		.window_len = 0x1000,
+	},
+};
+
+static struct regmap_config wcd9335_interface_regmap_config = {
+	.reg_bits = 16,
+	.val_bits = 8,
+	.can_multi_write = true,
+	.max_register = WCD9335_REG(0, 0x7FF),
+	.ranges = wcd9335_interface_ranges,
+	.num_ranges = ARRAY_SIZE(wcd9335_interface_ranges),
+};
+
+static struct wcd9335 *wcd_data;
+
+static int wcd9335_parse_resources(struct wcd9335 *ddata)
+{
+	struct device *dev = ddata->dev;
+	struct device_node *np = dev->of_node;
+	int ret;
+
+	ddata->reset_gpio = of_get_named_gpio(np,	"reset-gpios", 0);
+	if (ddata->reset_gpio < 0) {
+		dev_err(dev, "Reset GPIO missing from DT\n");
+		return ddata->reset_gpio;
+	}
+
+	ddata->mclk = devm_clk_get(dev, "mclk");
+	if (IS_ERR(ddata->mclk)) {
+		dev_err(dev, "mclk not found\n");
+		return PTR_ERR(ddata->mclk);
+	}
+
+	ddata->native_clk = devm_clk_get(dev, "slimbus");
+	if (IS_ERR(ddata->native_clk)) {
+		dev_err(dev, "slimbus clock not found\n");
+		return PTR_ERR(ddata->native_clk);
+	}
+
+	ddata->supplies[0].supply = "vdd-buck";
+	ddata->supplies[1].supply = "vdd-buck-sido";
+	ddata->supplies[2].supply = "vdd-tx";
+	ddata->supplies[3].supply = "vdd-rx";
+	ddata->supplies[4].supply = "vdd-io";
+
+	ret = regulator_bulk_get(dev, WCD9335_MAX_SUPPLY, ddata->supplies);
+	if (ret) {
+		dev_err(dev, "Failed to get supplies: err = %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int wcd9335_power_on_reset(struct wcd9335 *ddata)
+{
+	struct device *dev = ddata->dev;
+	int ret;
+
+	ret = regulator_bulk_enable(WCD9335_MAX_SUPPLY, ddata->supplies);
+	if (ret) {
+		dev_err(dev, "Failed to get supplies: err = %d\n", ret);
+		return ret;
+	}
+
+	/*
+	 * For WCD9335, it takes about 600us for the Vout_A and
+	 * Vout_D to be ready after BUCK_SIDO is powered up.
+	 * SYS_RST_N shouldn't be pulled high during this time
+	 * Toggle the reset line to make sure the reset pulse is
+	 * correctly applied
+	 */
+	usleep_range(600, 650);
+
+	gpio_direction_output(ddata->reset_gpio, 0);
+	msleep(20);
+	gpio_set_value(ddata->reset_gpio, 1);
+	msleep(20);
+
+	return 0;
+}
+
+static int wcd9335_bring_up(struct wcd9335 *ddata)
+{
+	struct regmap *rm = ddata->regmap;
+	int ver;
+
+	regmap_read(rm, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0, &ver);
+
+	if (ver == WCD9334_CHIP_ID_VER_V2_0) {
+		dev_info(ddata->dev, "WCD9335 CODEC version is v2.0\n");
+		ddata->version = WCD9335_VERSION_2_0;
+		regmap_write(rm, WCD9335_CODEC_RPM_RST_CTL,
+					WCD9335_CODEC_ANA_OUT_OF_RST);
+		regmap_write(rm, WCD9335_SIDO_SIDO_TEST_2, 0x00);
+		regmap_write(rm, WCD9335_SIDO_SIDO_CCL_8,
+					WCD9335_ANALOG_DEF_VALUE);
+		regmap_write(rm, WCD9335_BIAS_VBG_FINE_ADJ,
+					WCD9335_VBIAS_FINE_ADJ_DEF_VAL);
+		regmap_write(rm, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
+				WCD9335_HEADSWITCH_CONTROL_PWR_ON);
+		regmap_write(rm, WCD9335_CODEC_RPM_RST_CTL,
+					WCD9335_CODEC_ANA_OUT_OF_RST |
+					WCD9335_CODEC_DIG_OUT_OF_RST);
+	} else {
+		dev_err(ddata->dev, "WCD9335 CODEC version not supported\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int wcd9335_slim_status(struct slim_device *sdev,
+			       enum slim_device_status status)
+{
+	struct wcd9335 *ddata = dev_get_drvdata(&sdev->dev);
+	int ret;
+
+	if (ddata->regmap && ddata->interface_dev_regmap) {
+		switch (status) {
+		case SLIM_DEVICE_STATUS_UP:
+			ret = mfd_add_devices(ddata->dev, 0, wcd9335_devices,
+					ARRAY_SIZE(wcd9335_devices),
+					NULL, 0, NULL);
+			if (ret) {
+				dev_err(ddata->dev,
+					"Failed to add mfd devices: %d\n",
+					ret);
+				return ret;
+			}
+			break;
+		case SLIM_DEVICE_STATUS_DOWN:
+			mfd_remove_devices(ddata->dev);
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int wcd9335_slim_probe(struct slim_device *slim)
+{
+	struct device *dev = &slim->dev;
+	struct wcd9335 *ddata;
+	int ret;
+
+	if (!wcd_data) {
+		wcd_data = kzalloc(sizeof(*wcd_data), GFP_KERNEL);
+		if (!wcd_data)
+			return	-ENOMEM;
+	}
+
+	ddata = wcd_data;
+	dev_set_drvdata(dev, ddata);
+
+	/* Interface device */
+	if (slim->e_addr.dev_index == WCD9335_SLIM_INTERFACE_DEVICE_INDEX) {
+		if (slim_get_logical_addr(slim)) {
+			dev_err(dev, "Failed to get logical address\n");
+			return -EPROBE_DEFER;
+		}
+
+		ddata->slim_interface_dev = slim;
+		ddata->interface_dev_regmap = regmap_init_slimbus(slim,
+					  &wcd9335_interface_regmap_config);
+		if (IS_ERR(ddata->interface_dev_regmap)) {
+			ddata->slim_interface_dev = NULL;
+			dev_err(&slim->dev,
+				"Failed to allocate SLIM Interface regmap\n");
+			return PTR_ERR(ddata->interface_dev_regmap);
+		}
+
+		return 0;
+
+	}
+
+	ddata->regmap = regmap_init_slimbus(slim, &wcd9335_regmap_config);
+	if (IS_ERR(ddata->regmap)) {
+		dev_err(ddata->dev, "Failed to allocate SLIM regmap\n");
+		ddata->regmap = NULL;
+		return PTR_ERR(ddata->regmap);
+	}
+
+	ddata->dev = dev;
+	ddata->slim = slim;
+	ddata->intf_type = WCD9335_INTERFACE_TYPE_SLIMBUS;
+
+	ret = wcd9335_parse_resources(ddata);
+	if (ret) {
+		dev_err(dev, "Error parsing DT: %d\n", ret);
+		return ret;
+	}
+
+	ret = wcd9335_power_on_reset(ddata);
+	if (ret)
+		return ret;
+
+	if (slim_get_logical_addr(slim)) {
+		dev_err(dev, "Failed to get logical address\n");
+		return -EPROBE_DEFER;
+	}
+
+	ret = wcd9335_bring_up(ddata);
+	if (ret) {
+		dev_err(ddata->dev, "Failed to bringup WCD9335\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void wcd9335_slim_remove(struct slim_device *slim)
+{
+	if (slim->e_addr.dev_index != WCD9335_SLIM_INTERFACE_DEVICE_INDEX)
+		mfd_remove_devices(&slim->dev);
+
+	kfree(wcd_data);
+	wcd_data = NULL;
+}
+
+static const struct of_device_id wcd9335_device_id[]  = {
+	{ .compatible = "slim217,1a0" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, wcd9335_device_id);
+
+static struct slim_driver wcd9335_slim_driver = {
+	.driver = {
+		.name = "wcd9335-slim",
+		.of_match_table = of_match_ptr(wcd9335_device_id),
+	},
+	.probe = wcd9335_slim_probe,
+	.remove = wcd9335_slim_remove,
+	.device_status = wcd9335_slim_status,
+};
+
+module_slim_driver(wcd9335_slim_driver);
+MODULE_DESCRIPTION("WCD9335 slim driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mfd/wcd9335/registers.h b/include/linux/mfd/wcd9335/registers.h
new file mode 100644
index 0000000..24c02ad
--- /dev/null
+++ b/include/linux/mfd/wcd9335/registers.h
@@ -0,0 +1,640 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018, Linaro Limited */
+
+#ifndef _WCD9335_REGISTERS_H
+#define _WCD9335_REGISTERS_H
+
+/*
+ * WCD9335 register base can change according to the mode it works in
+ * in SLIMBUS mode the reg base starts from 0x800
+ * in i2s/i2c mode the reg base is 0x0
+ */
+#define WCD9335_REG(pg, r)	((pg << 12) | (r) | 0x800)
+#define WCD9335_REG_OFFSET(r)	(r & 0xFF)
+#define WCD9335_PAGE_OFFSET(r)	((r >> 12) & 0xFF)
+
+/* Page-0 Registers */
+#define WCD9335_PAGE0_PAGE_REGISTER		WCD9335_REG(0x00, 0x000)
+#define WCD9335_CODEC_RPM_CLK_GATE		WCD9335_REG(0x00, 0x002)
+#define WCD9335_CODEC_RPM_CLK_GATE_MCLK_GATE_MASK	GENMASK(1, 0)
+#define WCD9335_CODEC_RPM_CLK_MCLK_CFG		WCD9335_REG(0x00, 0x003)
+#define WCD9335_CODEC_RPM_CLK_MCLK_CFG_9P6MHZ	BIT(0)
+#define WCD9335_CODEC_RPM_CLK_MCLK_CFG_12P288MHZ	BIT(0)
+#define WCD9335_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK	GENMASK(1, 0)
+#define WCD9335_CODEC_RPM_RST_CTL		WCD9335_REG(0x00, 0x009)
+#define WCD9335_CODEC_ANA_RST			0
+#define WCD9335_CODEC_ANA_OUT_OF_RST		BIT(0)
+#define WCD9335_CODEC_DIG_RST			0
+#define WCD9335_CODEC_DIG_OUT_OF_RST		BIT(1)
+#define WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL	WCD9335_REG(0x00, 0x011)
+#define WCD9335_HEADSWITCH_CONTROL_PWR_ON	GENMASK(1, 0)
+#define WCD9335_HEADSWITCH_PWR_ON		BIT(0)
+#define WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0	WCD9335_REG(0x00, 0x021)
+#define WCD9334_CHIP_ID_VER_V2_0		BIT(0)
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_CTL	WCD9335_REG(0x00, 0x025)
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_SSTATE_MASK GENMASK(4, 1)
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_EN_MASK	BIT(0)
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_ENABLE	BIT(0)
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0	WCD9335_REG(0x00, 0x029)
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS	WCD9335_REG(0x00, 0x039)
+#define WCD9335_INTR_CFG			WCD9335_REG(0x00, 0x081)
+#define WCD9335_INTR_CLR_COMMIT			WCD9335_REG(0x00, 0x082)
+#define WCD9335_INTR_PIN1_MASK0			WCD9335_REG(0x00, 0x089)
+#define WCD9335_INTR_PIN1_MASK1			WCD9335_REG(0x00, 0x08a)
+#define WCD9335_INTR_PIN1_MASK2			WCD9335_REG(0x00, 0x08b)
+#define WCD9335_INTR_PIN1_MASK3			WCD9335_REG(0x00, 0x08c)
+#define WCD9335_INTR_PIN1_STATUS0		WCD9335_REG(0x00, 0x091)
+#define WCD9335_INTR_PIN1_STATUS1		WCD9335_REG(0x00, 0x092)
+#define WCD9335_INTR_PIN1_STATUS2		WCD9335_REG(0x00, 0x093)
+#define WCD9335_INTR_PIN1_STATUS3		WCD9335_REG(0x00, 0x094)
+#define WCD9335_INTR_PIN1_CLEAR0		WCD9335_REG(0x00, 0x099)
+#define WCD9335_INTR_PIN1_CLEAR1		WCD9335_REG(0x00, 0x09a)
+#define WCD9335_INTR_PIN1_CLEAR2		WCD9335_REG(0x00, 0x09b)
+#define WCD9335_INTR_PIN1_CLEAR3		WCD9335_REG(0x00, 0x09c)
+#define WCD9335_INTR_PIN2_MASK0			WCD9335_REG(0x00, 0x0a1)
+#define WCD9335_INTR_PIN2_MASK1			WCD9335_REG(0x00, 0x0a2)
+#define WCD9335_INTR_PIN2_MASK2			WCD9335_REG(0x00, 0x0a3)
+#define WCD9335_INTR_PIN2_MASK3			WCD9335_REG(0x00, 0x0a4)
+#define WCD9335_INTR_PIN2_STATUS0		WCD9335_REG(0x00, 0x0a9)
+#define WCD9335_INTR_PIN2_STATUS1		WCD9335_REG(0x00, 0x0aa)
+#define WCD9335_INTR_PIN2_STATUS2		WCD9335_REG(0x00, 0x0ab)
+#define WCD9335_INTR_PIN2_STATUS3		WCD9335_REG(0x00, 0x0ac)
+#define WCD9335_INTR_PIN2_CLEAR0		WCD9335_REG(0x00, 0x0b1)
+#define WCD9335_INTR_PIN2_CLEAR1		WCD9335_REG(0x00, 0x0b2)
+#define WCD9335_INTR_PIN2_CLEAR2		WCD9335_REG(0x00, 0x0b3)
+#define WCD9335_INTR_PIN2_CLEAR3		WCD9335_REG(0x00, 0x0b4)
+#define WCD9335_INTR_LEVEL0			WCD9335_REG(0x00, 0x0e1)
+#define WCD9335_INTR_LEVEL1			WCD9335_REG(0x00, 0x0e2)
+#define WCD9335_INTR_LEVEL2			WCD9335_REG(0x00, 0x0e3)
+#define WCD9335_INTR_LEVEL3			WCD9335_REG(0x00, 0x0e4)
+
+/* Page-1 Registers */
+#define WCD9335_CPE_FLL_USER_CTL_0		WCD9335_REG(0x01, 0x001)
+#define WCD9335_CPE_FLL_USER_CTL_1		WCD9335_REG(0x01, 0x002)
+#define WCD9335_CPE_FLL_USER_CTL_2		WCD9335_REG(0x01, 0x003)
+#define WCD9335_CPE_FLL_USER_CTL_3		WCD9335_REG(0x01, 0x004)
+#define WCD9335_CPE_FLL_USER_CTL_4		WCD9335_REG(0x01, 0x005)
+#define WCD9335_CPE_FLL_USER_CTL_5		WCD9335_REG(0x01, 0x006)
+#define WCD9335_CPE_FLL_USER_CTL_6		WCD9335_REG(0x01, 0x007)
+#define WCD9335_CPE_FLL_USER_CTL_7		WCD9335_REG(0x01, 0x008)
+#define WCD9335_CPE_FLL_USER_CTL_8		WCD9335_REG(0x01, 0x009)
+#define WCD9335_CPE_FLL_USER_CTL_9		WCD9335_REG(0x01, 0x00a)
+#define WCD9335_CPE_FLL_L_VAL_CTL_0		WCD9335_REG(0x01, 0x00b)
+#define WCD9335_CPE_FLL_L_VAL_CTL_1		WCD9335_REG(0x01, 0x00c)
+#define WCD9335_CPE_FLL_DSM_FRAC_CTL_0		WCD9335_REG(0x01, 0x00d)
+#define WCD9335_CPE_FLL_DSM_FRAC_CTL_1		WCD9335_REG(0x01, 0x00e)
+#define WCD9335_CPE_FLL_CONFIG_CTL_0		WCD9335_REG(0x01, 0x00f)
+#define WCD9335_CPE_FLL_CONFIG_CTL_1		WCD9335_REG(0x01, 0x010)
+#define WCD9335_CPE_FLL_CONFIG_CTL_2		WCD9335_REG(0x01, 0x011)
+#define WCD9335_CPE_FLL_CONFIG_CTL_3		WCD9335_REG(0x01, 0x012)
+#define WCD9335_CPE_FLL_CONFIG_CTL_4		WCD9335_REG(0x01, 0x013)
+#define WCD9335_CPE_FLL_TEST_CTL_0		WCD9335_REG(0x01, 0x014)
+#define WCD9335_CPE_FLL_TEST_CTL_1		WCD9335_REG(0x01, 0x015)
+#define WCD9335_CPE_FLL_TEST_CTL_2		WCD9335_REG(0x01, 0x016)
+#define WCD9335_CPE_FLL_TEST_CTL_3		WCD9335_REG(0x01, 0x017)
+#define WCD9335_CPE_FLL_TEST_CTL_4		WCD9335_REG(0x01, 0x018)
+#define WCD9335_CPE_FLL_TEST_CTL_5		WCD9335_REG(0x01, 0x019)
+#define WCD9335_CPE_FLL_TEST_CTL_6		WCD9335_REG(0x01, 0x01a)
+#define WCD9335_CPE_FLL_TEST_CTL_7		WCD9335_REG(0x01, 0x01b)
+#define WCD9335_CPE_FLL_FREQ_CTL_0		WCD9335_REG(0x01, 0x01c)
+#define WCD9335_CPE_FLL_FREQ_CTL_1		WCD9335_REG(0x01, 0x01d)
+#define WCD9335_CPE_FLL_FREQ_CTL_2		WCD9335_REG(0x01, 0x01e)
+#define WCD9335_CPE_FLL_FREQ_CTL_3		WCD9335_REG(0x01, 0x01f)
+#define WCD9335_CPE_FLL_SSC_CTL_0		WCD9335_REG(0x01, 0x020)
+#define WCD9335_CPE_FLL_SSC_CTL_1		WCD9335_REG(0x01, 0x021)
+#define WCD9335_CPE_FLL_SSC_CTL_2		WCD9335_REG(0x01, 0x022)
+#define WCD9335_CPE_FLL_SSC_CTL_3		WCD9335_REG(0x01, 0x023)
+#define WCD9335_CPE_FLL_FLL_MODE		WCD9335_REG(0x01, 0x024)
+#define WCD9335_CPE_FLL_STATUS_0		WCD9335_REG(0x01, 0x025)
+#define WCD9335_CPE_FLL_STATUS_1		WCD9335_REG(0x01, 0x026)
+#define WCD9335_CPE_FLL_STATUS_2		WCD9335_REG(0x01, 0x027)
+#define WCD9335_CPE_FLL_STATUS_3		WCD9335_REG(0x01, 0x028)
+#define WCD9335_I2S_FLL_USER_CTL_0		WCD9335_REG(0x01, 0x041)
+#define WCD9335_I2S_FLL_USER_CTL_1		WCD9335_REG(0x01, 0x042)
+#define WCD9335_I2S_FLL_USER_CTL_2		WCD9335_REG(0x01, 0x043)
+#define WCD9335_I2S_FLL_USER_CTL_3		WCD9335_REG(0x01, 0x044)
+#define WCD9335_I2S_FLL_USER_CTL_4		WCD9335_REG(0x01, 0x045)
+#define WCD9335_I2S_FLL_USER_CTL_5		WCD9335_REG(0x01, 0x046)
+#define WCD9335_I2S_FLL_USER_CTL_6		WCD9335_REG(0x01, 0x047)
+#define WCD9335_I2S_FLL_USER_CTL_7		WCD9335_REG(0x01, 0x048)
+#define WCD9335_I2S_FLL_USER_CTL_8		WCD9335_REG(0x01, 0x049)
+#define WCD9335_I2S_FLL_USER_CTL_9		WCD9335_REG(0x01, 0x04a)
+#define WCD9335_I2S_FLL_L_VAL_CTL_0		WCD9335_REG(0x01, 0x04b)
+#define WCD9335_I2S_FLL_L_VAL_CTL_1		WCD9335_REG(0x01, 0x04c)
+#define WCD9335_I2S_FLL_DSM_FRAC_CTL_0		WCD9335_REG(0x01, 0x04d)
+#define WCD9335_I2S_FLL_DSM_FRAC_CTL_1		WCD9335_REG(0x01, 0x04e)
+#define WCD9335_I2S_FLL_CONFIG_CTL_0		WCD9335_REG(0x01, 0x04f)
+#define WCD9335_I2S_FLL_CONFIG_CTL_1		WCD9335_REG(0x01, 0x050)
+#define WCD9335_I2S_FLL_CONFIG_CTL_2		WCD9335_REG(0x01, 0x051)
+#define WCD9335_I2S_FLL_CONFIG_CTL_3		WCD9335_REG(0x01, 0x052)
+#define WCD9335_I2S_FLL_CONFIG_CTL_4		WCD9335_REG(0x01, 0x053)
+#define WCD9335_I2S_FLL_TEST_CTL_0		WCD9335_REG(0x01, 0x054)
+#define WCD9335_I2S_FLL_TEST_CTL_1		WCD9335_REG(0x01, 0x055)
+#define WCD9335_I2S_FLL_TEST_CTL_2		WCD9335_REG(0x01, 0x056)
+#define WCD9335_I2S_FLL_TEST_CTL_3		WCD9335_REG(0x01, 0x057)
+#define WCD9335_I2S_FLL_TEST_CTL_4		WCD9335_REG(0x01, 0x058)
+#define WCD9335_I2S_FLL_TEST_CTL_5		WCD9335_REG(0x01, 0x059)
+#define WCD9335_I2S_FLL_TEST_CTL_6		WCD9335_REG(0x01, 0x05a)
+#define WCD9335_I2S_FLL_TEST_CTL_7		WCD9335_REG(0x01, 0x05b)
+#define WCD9335_I2S_FLL_FREQ_CTL_0		WCD9335_REG(0x01, 0x05c)
+#define WCD9335_I2S_FLL_FREQ_CTL_1		WCD9335_REG(0x01, 0x05d)
+#define WCD9335_I2S_FLL_FREQ_CTL_2		WCD9335_REG(0x01, 0x05e)
+#define WCD9335_I2S_FLL_FREQ_CTL_3		WCD9335_REG(0x01, 0x05f)
+#define WCD9335_I2S_FLL_SSC_CTL_0		WCD9335_REG(0x01, 0x060)
+#define WCD9335_I2S_FLL_SSC_CTL_1		WCD9335_REG(0x01, 0x061)
+#define WCD9335_I2S_FLL_SSC_CTL_2		WCD9335_REG(0x01, 0x062)
+#define WCD9335_I2S_FLL_SSC_CTL_3		WCD9335_REG(0x01, 0x063)
+#define WCD9335_I2S_FLL_FLL_MODE		WCD9335_REG(0x01, 0x064)
+#define WCD9335_I2S_FLL_STATUS_0		WCD9335_REG(0x01, 0x065)
+#define WCD9335_I2S_FLL_STATUS_1		WCD9335_REG(0x01, 0x066)
+#define WCD9335_I2S_FLL_STATUS_2		WCD9335_REG(0x01, 0x067)
+#define WCD9335_I2S_FLL_STATUS_3		WCD9335_REG(0x01, 0x068)
+#define WCD9335_SB_FLL_USER_CTL_0		WCD9335_REG(0x01, 0x081)
+#define WCD9335_SB_FLL_USER_CTL_1		WCD9335_REG(0x01, 0x082)
+#define WCD9335_SB_FLL_USER_CTL_2		WCD9335_REG(0x01, 0x083)
+#define WCD9335_SB_FLL_USER_CTL_3		WCD9335_REG(0x01, 0x084)
+#define WCD9335_SB_FLL_USER_CTL_4		WCD9335_REG(0x01, 0x085)
+#define WCD9335_SB_FLL_USER_CTL_5		WCD9335_REG(0x01, 0x086)
+#define WCD9335_SB_FLL_USER_CTL_6		WCD9335_REG(0x01, 0x087)
+#define WCD9335_SB_FLL_USER_CTL_7		WCD9335_REG(0x01, 0x088)
+#define WCD9335_SB_FLL_USER_CTL_8		WCD9335_REG(0x01, 0x089)
+#define WCD9335_SB_FLL_USER_CTL_9		WCD9335_REG(0x01, 0x08a)
+#define WCD9335_SB_FLL_L_VAL_CTL_0		WCD9335_REG(0x01, 0x08b)
+#define WCD9335_SB_FLL_L_VAL_CTL_1		WCD9335_REG(0x01, 0x08c)
+#define WCD9335_SB_FLL_DSM_FRAC_CTL_0		WCD9335_REG(0x01, 0x08d)
+#define WCD9335_SB_FLL_DSM_FRAC_CTL_1		WCD9335_REG(0x01, 0x08e)
+#define WCD9335_SB_FLL_CONFIG_CTL_0		WCD9335_REG(0x01, 0x08f)
+#define WCD9335_SB_FLL_CONFIG_CTL_1		WCD9335_REG(0x01, 0x090)
+#define WCD9335_SB_FLL_CONFIG_CTL_2		WCD9335_REG(0x01, 0x091)
+#define WCD9335_SB_FLL_CONFIG_CTL_3		WCD9335_REG(0x01, 0x092)
+#define WCD9335_SB_FLL_CONFIG_CTL_4		WCD9335_REG(0x01, 0x093)
+#define WCD9335_SB_FLL_TEST_CTL_0		WCD9335_REG(0x01, 0x094)
+#define WCD9335_SB_FLL_TEST_CTL_1		WCD9335_REG(0x01, 0x095)
+#define WCD9335_SB_FLL_TEST_CTL_2		WCD9335_REG(0x01, 0x096)
+#define WCD9335_SB_FLL_TEST_CTL_3		WCD9335_REG(0x01, 0x097)
+#define WCD9335_SB_FLL_TEST_CTL_4		WCD9335_REG(0x01, 0x098)
+#define WCD9335_SB_FLL_TEST_CTL_5		WCD9335_REG(0x01, 0x099)
+#define WCD9335_SB_FLL_TEST_CTL_6		WCD9335_REG(0x01, 0x09a)
+#define WCD9335_SB_FLL_TEST_CTL_7		WCD9335_REG(0x01, 0x09b)
+#define WCD9335_SB_FLL_FREQ_CTL_0		WCD9335_REG(0x01, 0x09c)
+#define WCD9335_SB_FLL_FREQ_CTL_1		WCD9335_REG(0x01, 0x09d)
+#define WCD9335_SB_FLL_FREQ_CTL_2		WCD9335_REG(0x01, 0x09e)
+#define WCD9335_SB_FLL_FREQ_CTL_3		WCD9335_REG(0x01, 0x09f)
+#define WCD9335_SB_FLL_SSC_CTL_0		WCD9335_REG(0x01, 0x0a0)
+#define WCD9335_SB_FLL_SSC_CTL_1		WCD9335_REG(0x01, 0x0a1)
+#define WCD9335_SB_FLL_SSC_CTL_2		WCD9335_REG(0x01, 0x0a2)
+#define WCD9335_SB_FLL_SSC_CTL_3		WCD9335_REG(0x01, 0x0a3)
+#define WCD9335_SB_FLL_FLL_MODE			WCD9335_REG(0x01, 0x0a4)
+#define WCD9335_SB_FLL_STATUS_0			WCD9335_REG(0x01, 0x0a5)
+#define WCD9335_SB_FLL_STATUS_1			WCD9335_REG(0x01, 0x0a6)
+#define WCD9335_SB_FLL_STATUS_2			WCD9335_REG(0x01, 0x0a7)
+#define WCD9335_SB_FLL_STATUS_3			WCD9335_REG(0x01, 0x0a8)
+
+/* Page-2 Registers */
+#define WCD9335_PAGE2_PAGE_REGISTER		WCD9335_REG(0x02, 0x000)
+#define WCD9335_CPE_SS_DMIC0_CTL		WCD9335_REG(0x02, 0x063)
+#define WCD9335_CPE_SS_DMIC1_CTL		WCD9335_REG(0x02, 0x064)
+#define WCD9335_CPE_SS_DMIC2_CTL		WCD9335_REG(0x02, 0x065)
+#define WCD9335_CPE_SS_DMIC_CFG			WCD9335_REG(0x02, 0x066)
+#define WCD9335_SOC_MAD_AUDIO_CTL_2		WCD9335_REG(0x02, 0x084)
+
+/* Page-6 Registers */
+#define WCD9335_PAGE6_PAGE_REGISTER		WCD9335_REG(0x06, 0x000)
+#define WCD9335_ANA_BIAS			WCD9335_REG(0x06, 0x001)
+#define WCD9335_ANA_BIAS_EN_MASK		BIT(7)
+#define WCD9335_ANA_BIAS_ENABLE			BIT(7)
+#define WCD9335_ANA_BIAS_DISABLE		0
+#define WCD9335_ANA_BIAS_PRECHRG_EN_MASK	BIT(6)
+#define WCD9335_ANA_BIAS_PRECHRG_ENABLE		BIT(6)
+#define WCD9335_ANA_BIAS_PRECHRG_DISABLE	0
+#define WCD9335_ANA_BIAS_PRECHRG_CTL_MODE	BIT(5)
+#define WCD9335_ANA_BIAS_PRECHRG_CTL_MODE_AUTO	BIT(5)
+#define WCD9335_ANA_BIAS_PRECHRG_CTL_MODE_MANUAL	0
+#define WCD9335_ANA_CLK_TOP			WCD9335_REG(0x06, 0x002)
+#define WCD9335_ANA_CLK_MCLK_EN_MASK		BIT(2)
+#define WCD9335_ANA_CLK_MCLK_ENABLE		BIT(2)
+#define WCD9335_ANA_CLK_MCLK_DISABLE		0
+#define WCD9335_ANA_CLK_MCLK_SRC_MASK		BIT(3)
+#define WCD9335_ANA_CLK_MCLK_SRC_RCO		BIT(3)
+#define WCD9335_ANA_CLK_MCLK_SRC_EXTERNAL	0
+#define WCD9335_ANA_CLK_EXT_CLKBUF_EN_MASK	BIT(7)
+#define WCD9335_ANA_CLK_EXT_CLKBUF_ENABLE	BIT(7)
+#define WCD9335_ANA_CLK_EXT_CLKBUF_DISABLE	0
+#define WCD9335_ANA_RCO				WCD9335_REG(0x06, 0x003)
+#define WCD9335_ANA_RCO_BG_EN_MASK		BIT(7)
+#define WCD9335_ANA_RCO_BG_ENABLE		BIT(7)
+#define WCD9335_ANA_BUCK_VOUT_D			WCD9335_REG(0x06, 0x005)
+#define WCD9335_ANA_BUCK_VOUT_MASK		GENMASK(7, 0)
+#define WCD9335_ANA_BUCK_CTL			WCD9335_REG(0x06, 0x006)
+#define WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_MASK	BIT(1)
+#define WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_EXT	BIT(1)
+#define WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_INT	0
+#define WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_MASK	BIT(2)
+#define WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_EXT	BIT(2)
+#define WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_INT	0
+#define WCD9335_ANA_BUCK_CTL_RAMP_START_MASK	BIT(7)
+#define WCD9335_ANA_BUCK_CTL_RAMP_START_ENABLE	BIT(7)
+#define WCD9335_ANA_BUCK_CTL_RAMP_START_DISABLE	0
+#define WCD9335_ANA_RX_SUPPLIES			WCD9335_REG(0x06, 0x008)
+#define WCD9335_ANA_RX_BIAS_ENABLE_MASK		BIT(0)
+#define WCD9335_ANA_RX_BIAS_ENABLE		BIT(0)
+#define WCD9335_ANA_RX_BIAS_DISABLE		0
+#define WCD9335_ANA_HPH				WCD9335_REG(0x06, 0x009)
+#define WCD9335_ANA_EAR				WCD9335_REG(0x06, 0x00a)
+#define WCD9335_ANA_LO_1_2			WCD9335_REG(0x06, 0x00b)
+#define WCD9335_ANA_LO_3_4			WCD9335_REG(0x06, 0x00c)
+#define WCD9335_ANA_AMIC1			WCD9335_REG(0x06, 0x00e)
+#define WCD9335_ANA_AMIC2			WCD9335_REG(0x06, 0x00f)
+#define WCD9335_ANA_AMIC3			WCD9335_REG(0x06, 0x010)
+#define WCD9335_ANA_AMIC4			WCD9335_REG(0x06, 0x011)
+#define WCD9335_ANA_AMIC5			WCD9335_REG(0x06, 0x012)
+#define WCD9335_ANA_AMIC6			WCD9335_REG(0x06, 0x013)
+#define WCD9335_ANA_MBHC_MECH			WCD9335_REG(0x06, 0x014)
+#define WCD9335_MBHC_L_DET_EN_MASK		BIT(7)
+#define WCD9335_MBHC_L_DET_EN			BIT(7)
+#define WCD9335_MBHC_GND_DET_EN_MASK		BIT(6)
+#define WCD9335_MBHC_MECH_DETECT_TYPE_MASK	BIT(5)
+#define WCD9335_MBHC_MECH_DETECT_TYPE_SHIFT	5
+#define WCD9335_MBHC_HPHL_PLUG_TYPE_MASK	BIT(4)
+#define WCD9335_MBHC_HPHL_PLUG_TYPE_NO		BIT(4)
+#define WCD9335_MBHC_GND_PLUG_TYPE_MASK		BIT(3)
+#define WCD9335_MBHC_GND_PLUG_TYPE_NO		BIT(3)
+#define WCD9335_MBHC_HSL_PULLUP_COMP_EN		BIT(2)
+#define WCD9335_MBHC_HPHL_100K_TO_GND_EN	BIT(0)
+
+#define WCD9335_ANA_MBHC_ELECT			WCD9335_REG(0x06, 0x015)
+#define WCD9335_ANA_MBHC_BD_ISRC_CTL_MASK	GENMASK(6, 4)
+#define WCD9335_ANA_MBHC_BD_ISRC_100UA		GENMASK(5, 4)
+#define WCD9335_ANA_MBHC_BD_ISRC_OFF		0
+#define WCD9335_ANA_MBHC_BIAS_EN_MASK		BIT(0)
+#define WCD9335_ANA_MBHC_BIAS_EN		BIT(0)
+#define WCD9335_ANA_MBHC_ZDET			WCD9335_REG(0x06, 0x016)
+#define WCD9335_ANA_MBHC_RESULT_1		WCD9335_REG(0x06, 0x017)
+#define WCD9335_ANA_MBHC_RESULT_2		WCD9335_REG(0x06, 0x018)
+#define WCD9335_ANA_MBHC_RESULT_3		WCD9335_REG(0x06, 0x019)
+#define WCD9335_MBHC_BTN_RESULT_MASK		GENMASK(2, 0)
+#define WCD9335_ANA_MBHC_BTN0			WCD9335_REG(0x06, 0x01a)
+#define WCD9335_ANA_MBHC_BTN1			WCD9335_REG(0x06, 0x01b)
+#define WCD9335_ANA_MBHC_BTN2			WCD9335_REG(0x06, 0x01c)
+#define WCD9335_ANA_MBHC_BTN3			WCD9335_REG(0x06, 0x01d)
+#define WCD9335_ANA_MBHC_BTN4			WCD9335_REG(0x06, 0x01e)
+#define WCD9335_ANA_MBHC_BTN5			WCD9335_REG(0x06, 0x01f)
+#define WCD9335_ANA_MBHC_BTN6			WCD9335_REG(0x06, 0x020)
+#define WCD9335_ANA_MBHC_BTN7			WCD9335_REG(0x06, 0x021)
+#define WCD9335_ANA_MICB1			WCD9335_REG(0x06, 0x022)
+#define WCD9335_ANA_MICB2			WCD9335_REG(0x06, 0x023)
+#define WCD9335_ANA_MICB2_ENABLE		BIT(6)
+#define WCD9335_ANA_MICB2_RAMP			WCD9335_REG(0x06, 0x024)
+#define WCD9335_ANA_MICB3			WCD9335_REG(0x06, 0x025)
+#define WCD9335_ANA_MICB4			WCD9335_REG(0x06, 0x026)
+#define WCD9335_ANA_VBADC			WCD9335_REG(0x06, 0x027)
+#define WCD9335_BIAS_VBG_FINE_ADJ		WCD9335_REG(0x06, 0x029)
+/*Precharge timecount 1P2Ms and 20Mv fine adjustment */
+#define WCD9335_VBIAS_FINE_ADJ_DEF_VAL		0x65
+#define WCD9335_RCO_CTRL_2			WCD9335_REG(0x06, 0x02f)
+#define WCD9335_SIDO_SIDO_CCL_2			WCD9335_REG(0x06, 0x042)
+#define WCD9335_SIDO_SIDO_CCL_4			WCD9335_REG(0x06, 0x044)
+#define WCD9335_SIDO_SIDO_CCL_8			WCD9335_REG(0x06, 0x048)
+#define WCD9335_VALLEY_COMP_PWC_C420FF		GENMASK(1, 0)
+/* comparator pulse of C420FF, bias current of 1P0UA, max current of 360MA */
+#define WCD9335_ANALOG_DEF_VALUE		0x6F
+#define WCD9335_SIDO_SIDO_CCL_10		WCD9335_REG(0x06, 0x04a)
+#define WCD9335_SIDO_SIDO_CCL_10_ICHARG_PWR_SEL_C320FF		0x2
+/* Comparator 1 and 2 Bias current at 1P0UA with start pulse width of C320FF */
+#define WCD9335_SIDO_SIDO_CCL_DEF_VALUE		0x6e
+#define WCD9335_SIDO_SIDO_TEST_2		WCD9335_REG(0x06, 0x055)
+#define WCD9335_MBHC_CTL_1			WCD9335_REG(0x06, 0x056)
+#define WCD9335_MBHC_BTN_DBNC_MASK		GENMASK(1, 0)
+#define WCD9335_MBHC_BTN_DBNC_T_16_MS		0x2
+#define WCD9335_MBHC_CTL_RCO_EN_MASK		BIT(7)
+#define WCD9335_MBHC_CTL_RCO_EN			BIT(7)
+
+#define WCD9335_MBHC_CTL_2			WCD9335_REG(0x06, 0x057)
+#define WCD9335_MBHC_HS_VREF_CTL_MASK		GENMASK(1, 0)
+#define WCD9335_MBHC_HS_VREF_1P5_V		0x1
+#define WCD9335_MBHC_PLUG_DETECT_CTL		WCD9335_REG(0x06, 0x058)
+#define WCD9335_MBHC_HSDET_PULLUP_CTL_MASK	GENMASK(7, 6)
+#define WCD9335_MBHC_HSDET_PULLUP_CTL_SHIFT	6
+#define WCD9335_MBHC_HSDET_PULLUP_CTL_1_2P0_UA	0x80
+#define WCD9335_MBHC_DBNC_TIMER_INSREM_DBNC_T_96_MS	0x6
+
+#define WCD9335_MBHC_ZDET_RAMP_CTL		WCD9335_REG(0x06, 0x05a)
+#define WCD9335_VBADC_IBIAS_FE			WCD9335_REG(0x06, 0x05e)
+#define WCD9335_FLYBACK_CTRL_1			WCD9335_REG(0x06, 0x0b1)
+#define WCD9335_RX_BIAS_HPH_PA			WCD9335_REG(0x06, 0x0bb)
+#define WCD9335_RX_BIAS_HPH_PA_AMP_5_UA_MASK	GENMASK(3, 0)
+#define WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2	WCD9335_REG(0x06, 0x0bc)
+#define WCD9335_RX_BIAS_HPH_RDAC_LDO		WCD9335_REG(0x06, 0x0bd)
+#define WCD9335_RX_BIAS_FLYB_BUFF		WCD9335_REG(0x06, 0x0c7)
+#define WCD9335_RX_BIAS_FLYB_VPOS_5_UA_MASK	GENMASK(3, 0)
+#define WCD9335_RX_BIAS_FLYB_I_0P0_UA		0
+#define WCD9335_RX_BIAS_FLYB_VNEG_5_UA_MASK	GENMASK(7, 4)
+#define WCD9335_RX_BIAS_FLYB_MID_RST		WCD9335_REG(0x06, 0x0c8)
+#define WCD9335_HPH_CNP_WG_CTL			WCD9335_REG(0x06, 0x0cc)
+#define WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK	GENMASK(2, 0)
+#define WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_500 0x2
+#define WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_1000 0x3
+#define WCD9335_HPH_OCP_CTL			WCD9335_REG(0x06, 0x0ce)
+#define WCD9335_HPH_AUTO_CHOP			WCD9335_REG(0x06, 0x0cf)
+#define WCD9335_HPH_AUTO_CHOP_MASK		BIT(5)
+#define WCD9335_HPH_AUTO_CHOP_FORCE_ENABLE		BIT(5)
+#define WCD9335_HPH_AUTO_CHOP_ENABLE_BY_CMPDR_GAIN		0
+#define WCD9335_HPH_PA_CTL1			WCD9335_REG(0x06, 0x0d1)
+#define WCD9335_HPH_PA_GM3_IB_SCALE_MASK		GENMASK(3, 1)
+#define WCD9335_HPH_PA_CTL2			WCD9335_REG(0x06, 0x0d2)
+#define WCD9335_HPH_PA_CTL2_FORCE_PSRREH_MASK	BIT(2)
+#define WCD9335_HPH_PA_CTL2_FORCE_PSRREH_ENABLE	BIT(2)
+#define WCD9335_HPH_PA_CTL2_FORCE_PSRREH_DISABLE 0
+#define WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK	BIT(3)
+#define WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_ENABLE	BIT(3)
+#define WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_DISABLE	0
+#define WCD9335_HPH_PA_CTL2_HPH_PSRR_ENH_MASK	BIT(5)
+#define WCD9335_HPH_PA_CTL2_HPH_PSRR_ENABLE	BIT(5)
+#define WCD9335_HPH_PA_CTL2_HPH_PSRR_DISABLE	0
+#define WCD9335_HPH_L_EN			WCD9335_REG(0x06, 0x0d3)
+#define WCD9335_HPH_CONST_SEL_L_MASK		GENMASK(7, 6)
+#define WCD9335_HPH_CONST_SEL_L_BYPASS		0
+#define WCD9335_HPH_CONST_SEL_L_LP_PATH		0x40
+#define WCD9335_HPH_CONST_SEL_L_HQ_PATH		0x80
+#define WCD9335_HPH_PA_GAIN_MASK		GENMASK(4, 0)
+#define WCD9335_HPH_GAIN_SRC_SEL_MASK		BIT(5)
+#define WCD9335_HPH_GAIN_SRC_SEL_COMPANDER	0
+#define WCD9335_HPH_GAIN_SRC_SEL_REGISTER	BIT(5)
+#define WCD9335_HPH_L_TEST			WCD9335_REG(0x06, 0x0d4)
+#define WCD9335_HPH_R_EN			WCD9335_REG(0x06, 0x0d6)
+#define WCD9335_HPH_R_TEST			WCD9335_REG(0x06, 0x0d7)
+#define WCD9335_HPH_R_ATEST			WCD9335_REG(0x06, 0x0d8)
+#define WCD9335_HPH_RDAC_LDO_CTL		WCD9335_REG(0x06, 0x0db)
+#define WCD9335_HPH_RDAC_N1P65_LD_OUTCTL_MASK	GENMASK(2, 0)
+#define WCD9335_HPH_RDAC_N1P65_LD_OUTCTL_V_N1P60	0x1
+#define WCD9335_HPH_RDAC_1P65_LD_OUTCTL_MASK	GENMASK(6, 4)
+#define WCD9335_HPH_RDAC_1P65_LD_OUTCTL_V_N1P60	0x10
+#define WCD9335_HPH_REFBUFF_LP_CTL		WCD9335_REG(0x06, 0x0de)
+#define WCD9335_HPH_L_DAC_CTL			WCD9335_REG(0x06, 0x0df)
+#define WCD9335_HPH_DAC_LDO_POWERMODE_MASK	BIT(0)
+#define WCD9335_HPH_DAC_LDO_POWERMODE_LOWPOWER	0
+#define WCD9335_HPH_DAC_LDO_POWERMODE_UHQA	BIT(0)
+#define WCD9335_HPH_DAC_LDO_UHQA_OV_MASK	BIT(1)
+#define WCD9335_HPH_DAC_LDO_UHQA_OV_ENABLE	BIT(1)
+#define WCD9335_HPH_DAC_LDO_UHQA_OV_DISABLE	0
+
+#define WCD9335_EAR_CMBUFF			WCD9335_REG(0x06, 0x0e2)
+#define WCD9335_DIFF_LO_LO2_COMPANDER		WCD9335_REG(0x06, 0x0ea)
+#define WCD9335_DIFF_LO_LO1_COMPANDER		WCD9335_REG(0x06, 0x0eb)
+#define WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ	WCD9335_REG(0x06, 0x0f1)
+#define WCD9335_DIFF_LO_COM_PA_FREQ		WCD9335_REG(0x06, 0x0f2)
+#define WCD9335_SE_LO_LO3_GAIN			WCD9335_REG(0x06, 0x0f8)
+#define WCD9335_SE_LO_LO3_CTRL			WCD9335_REG(0x06, 0x0f9)
+#define WCD9335_SE_LO_LO4_GAIN			WCD9335_REG(0x06, 0x0fa)
+
+/* Page-10 Registers */
+#define WCD9335_CDC_TX0_TX_PATH_CTL		WCD9335_REG(0x0a, 0x031)
+#define WCD9335_CDC_TX_PATH_CTL_PCM_RATE_MASK	GENMASK(3, 0)
+#define WCD9335_CDC_TX_PATH_CTL(dec)	WCD9335_REG(0xa, (0x31 + dec * 0x10))
+#define WCD9335_CDC_TX0_TX_PATH_CFG0		WCD9335_REG(0x0a, 0x032)
+#define WCD9335_CDC_TX_ADC_AMIC_DMIC_SEL_MASK	BIT(7)
+#define WCD9335_CDC_TX_ADC_DMIC_SEL		BIT(7)
+#define WCD9335_CDC_TX_ADC_AMIC_SEL		0
+#define WCD9335_CDC_TX0_TX_VOL_CTL		WCD9335_REG(0x0a, 0x034)
+#define WCD9335_CDC_TX0_TX_PATH_SEC2		WCD9335_REG(0x0a, 0x039)
+#define WCD9335_CDC_TX0_TX_PATH_SEC7		WCD9335_REG(0x0a, 0x03e)
+#define WCD9335_CDC_TX1_TX_PATH_CTL		WCD9335_REG(0x0a, 0x041)
+#define WCD9335_CDC_TX1_TX_PATH_CFG0		WCD9335_REG(0x0a, 0x042)
+#define WCD9335_CDC_TX2_TX_PATH_CTL		WCD9335_REG(0x0a, 0x051)
+#define WCD9335_CDC_TX2_TX_PATH_CFG0		WCD9335_REG(0x0a, 0x052)
+#define WCD9335_CDC_TX2_TX_VOL_CTL		WCD9335_REG(0x0a, 0x054)
+#define WCD9335_CDC_TX3_TX_PATH_CTL		WCD9335_REG(0x0a, 0x061)
+#define WCD9335_CDC_TX3_TX_PATH_CFG0		WCD9335_REG(0x0a, 0x062)
+#define WCD9335_CDC_TX3_TX_VOL_CTL		WCD9335_REG(0x0a, 0x064)
+#define WCD9335_CDC_TX4_TX_PATH_CTL		WCD9335_REG(0x0a, 0x071)
+#define WCD9335_CDC_TX4_TX_PATH_CFG0		WCD9335_REG(0x0a, 0x072)
+#define WCD9335_CDC_TX4_TX_VOL_CTL		WCD9335_REG(0x0a, 0x074)
+#define WCD9335_CDC_TX5_TX_PATH_CTL		WCD9335_REG(0x0a, 0x081)
+#define WCD9335_CDC_TX5_TX_PATH_CFG0		WCD9335_REG(0x0a, 0x082)
+#define WCD9335_CDC_TX5_TX_VOL_CTL		WCD9335_REG(0x0a, 0x084)
+#define WCD9335_CDC_TX6_TX_PATH_CTL		WCD9335_REG(0x0a, 0x091)
+#define WCD9335_CDC_TX6_TX_PATH_CFG0		WCD9335_REG(0x0a, 0x092)
+#define WCD9335_CDC_TX6_TX_VOL_CTL		WCD9335_REG(0x0a, 0x094)
+#define WCD9335_CDC_TX7_TX_PATH_CTL		WCD9335_REG(0x0a, 0x0a1)
+#define WCD9335_CDC_TX7_TX_PATH_CFG0		WCD9335_REG(0x0a, 0x0a2)
+#define WCD9335_CDC_TX7_TX_VOL_CTL		WCD9335_REG(0x0a, 0x0a4)
+#define WCD9335_CDC_TX8_TX_PATH_CTL		WCD9335_REG(0x0a, 0x0b1)
+#define WCD9335_CDC_TX8_TX_PATH_CFG0		WCD9335_REG(0x0a, 0x0b2)
+#define WCD9335_CDC_TX8_TX_VOL_CTL		WCD9335_REG(0x0a, 0x0b4)
+#define WCD9335_CDC_TX9_SPKR_PROT_PATH_CFG0	WCD9335_REG(0x0a, 0x0c3)
+#define WCD9335_CDC_TX10_SPKR_PROT_PATH_CFG0	WCD9335_REG(0x0a, 0x0c7)
+#define WCD9335_CDC_TX11_SPKR_PROT_PATH_CFG0	WCD9335_REG(0x0a, 0x0cb)
+#define WCD9335_CDC_TX12_SPKR_PROT_PATH_CFG0	WCD9335_REG(0x0a, 0x0cf)
+
+/* Page-11 Registers */
+#define WCD9335_PAGE11_PAGE_REGISTER		WCD9335_REG(0x0b, 0x000)
+#define WCD9335_CDC_COMPANDER1_CTL0		WCD9335_REG(0x0b, 0x001)
+#define WCD9335_CDC_COMPANDER1_CTL(c)	WCD9335_REG(0x0b, (0x001 + c * 0x8))
+#define WCD9335_CDC_COMPANDER_CLK_EN_MASK	BIT(0)
+#define WCD9335_CDC_COMPANDER_CLK_ENABLE	BIT(0)
+#define WCD9335_CDC_COMPANDER_CLK_DISABLE	0
+#define WCD9335_CDC_COMPANDER_SOFT_RST_MASK	BIT(1)
+#define WCD9335_CDC_COMPANDER_SOFT_RST_ENABLE	BIT(1)
+#define WCD9335_CDC_COMPANDER_SOFT_RST_DISABLE	0
+#define WCD9335_CDC_COMPANDER_HALT_MASK		BIT(2)
+#define WCD9335_CDC_COMPANDER_HALT		BIT(2)
+#define WCD9335_CDC_COMPANDER_NOHALT		0
+#define WCD9335_CDC_COMPANDER7_CTL3		WCD9335_REG(0x0b, 0x034)
+#define WCD9335_CDC_COMPANDER7_CTL7		WCD9335_REG(0x0b, 0x038)
+#define WCD9335_CDC_COMPANDER8_CTL3		WCD9335_REG(0x0b, 0x03c)
+#define WCD9335_CDC_COMPANDER8_CTL7		WCD9335_REG(0x0b, 0x040)
+#define WCD9335_CDC_RX0_RX_PATH_CTL		WCD9335_REG(0x0b, 0x041)
+#define WCD9335_CDC_RX_PGA_MUTE_EN_MASK		BIT(4)
+#define WCD9335_CDC_RX_PGA_MUTE_ENABLE		BIT(4)
+#define WCD9335_CDC_RX_PGA_MUTE_DISABLE		0
+#define WCD9335_CDC_RX_CLK_EN_MASK		BIT(5)
+#define WCD9335_CDC_RX_CLK_ENABLE		BIT(5)
+#define WCD9335_CDC_RX_CLK_DISABLE		0
+#define WCD9335_CDC_RX_RESET_MASK		BIT(6)
+#define WCD9335_CDC_RX_RESET_ENABLE		BIT(6)
+#define WCD9335_CDC_RX_RESET_DISABLE		0
+#define WCD9335_CDC_RX_PATH_CTL(rx)	WCD9335_REG(0x0b, (0x041 + rx * 0x14))
+#define WCD9335_CDC_RX0_RX_PATH_CFG0		WCD9335_REG(0x0b, 0x042)
+#define WCD9335_CDC_RX0_RX_PATH_CFG1		WCD9335_REG(0x0b, 0x043)
+#define WCD9335_CDC_RX0_RX_PATH_CFG2		WCD9335_REG(0x0b, 0x044)
+#define WCD9335_CDC_RX0_RX_VOL_CTL		WCD9335_REG(0x0b, 0x045)
+#define WCD9335_CDC_RX0_RX_PATH_MIX_CTL		WCD9335_REG(0x0b, 0x046)
+#define WCD9335_CDC_MIX_PCM_RATE_MASK		GENMASK(3, 0)
+#define WCD9335_CDC_RX_PATH_MIX_CTL(rx)	WCD9335_REG(0x0b, (0x46 + rx * 0x14))
+#define WCD9335_CDC_RX0_RX_PATH_MIX_CFG		WCD9335_REG(0x0b, 0x047)
+#define WCD9335_CDC_RX0_RX_VOL_MIX_CTL		WCD9335_REG(0x0b, 0x048)
+#define WCD9335_CDC_RX0_RX_PATH_SEC0		WCD9335_REG(0x0b, 0x049)
+#define WCD9335_CDC_RX0_RX_PATH_SEC7		WCD9335_REG(0x0b, 0x050)
+#define WCD9335_CDC_RX0_RX_PATH_MIX_SEC0	WCD9335_REG(0x0b, 0x051)
+#define WCD9335_CDC_RX1_RX_PATH_CTL		WCD9335_REG(0x0b, 0x055)
+#define WCD9335_CDC_RX1_RX_PATH_CFG0		WCD9335_REG(0x0b, 0x056)
+#define WCD9335_CDC_RX1_RX_PATH_CFG(c)	WCD9335_REG(0x0b, (0x056 + c * 0x14))
+#define WCD9335_CDC_RX_PATH_CFG_CMP_EN_MASK	BIT(1)
+#define WCD9335_CDC_RX_PATH_CFG_CMP_ENABLE	BIT(1)
+#define WCD9335_CDC_RX_PATH_CFG_CMP_DISABLE	0
+#define WCD9335_CDC_RX_PATH_CFG_HD2_EN_MASK	BIT(2)
+#define WCD9335_CDC_RX_PATH_CFG_HD2_ENABLE	BIT(2)
+#define WCD9335_CDC_RX_PATH_CFG_HD2_DISABLE	0
+#define WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_EN_MASK	BIT(3)
+#define WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_EN	BIT(3)
+#define WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_DISABLE	0
+#define WCD9335_CDC_RX1_RX_PATH_CFG2		WCD9335_REG(0x0b, 0x058)
+#define WCD9335_CDC_RX1_RX_VOL_CTL		WCD9335_REG(0x0b, 0x059)
+#define WCD9335_CDC_RX1_RX_PATH_MIX_CTL		WCD9335_REG(0x0b, 0x05a)
+#define WCD9335_CDC_RX1_RX_PATH_MIX_CFG		WCD9335_REG(0x0b, 0x05b)
+#define WCD9335_CDC_RX1_RX_VOL_MIX_CTL		WCD9335_REG(0x0b, 0x05c)
+#define WCD9335_CDC_RX1_RX_PATH_SEC0		WCD9335_REG(0x0b, 0x05d)
+#define WCD9335_CDC_RX1_RX_PATH_SEC3		WCD9335_REG(0x0b, 0x060)
+#define WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_MASK	GENMASK(1, 0)
+#define WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_2	0x1
+#define WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_1	0
+#define WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_MASK	GENMASK(5, 2)
+#define WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_0P2500	0x10
+#define WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_0P0000	0
+#define WCD9335_CDC_RX2_RX_PATH_CTL		WCD9335_REG(0x0b, 0x069)
+#define WCD9335_CDC_RX2_RX_PATH_CFG0		WCD9335_REG(0x0b, 0x06a)
+#define WCD9335_CDC_RX2_RX_PATH_CFG2		WCD9335_REG(0x0b, 0x06c)
+#define WCD9335_CDC_RX2_RX_VOL_CTL		WCD9335_REG(0x0b, 0x06d)
+#define WCD9335_CDC_RX2_RX_PATH_MIX_CTL		WCD9335_REG(0x0b, 0x06e)
+#define WCD9335_CDC_RX2_RX_PATH_MIX_CFG		WCD9335_REG(0x0b, 0x06f)
+#define WCD9335_CDC_RX2_RX_VOL_MIX_CTL		WCD9335_REG(0x0b, 0x070)
+#define WCD9335_CDC_RX2_RX_PATH_SEC0		WCD9335_REG(0x0b, 0x071)
+#define WCD9335_CDC_RX_PATH_DEM_INP_SEL_MASK	GENMASK(1, 0)
+#define WCD9335_CDC_RX2_RX_PATH_SEC3		WCD9335_REG(0x0b, 0x074)
+#define WCD9335_CDC_RX3_RX_PATH_CTL		WCD9335_REG(0x0b, 0x07d)
+#define WCD9335_CDC_RX3_RX_PATH_CFG0		WCD9335_REG(0x0b, 0x07e)
+#define WCD9335_CDC_RX3_RX_PATH_CFG2		WCD9335_REG(0x0b, 0x080)
+#define WCD9335_CDC_RX3_RX_VOL_CTL		WCD9335_REG(0x0b, 0x081)
+#define WCD9335_CDC_RX3_RX_PATH_MIX_CTL		WCD9335_REG(0x0b, 0x082)
+#define WCD9335_CDC_RX3_RX_PATH_MIX_CFG		WCD9335_REG(0x0b, 0x083)
+#define WCD9335_CDC_RX3_RX_VOL_MIX_CTL		WCD9335_REG(0x0b, 0x084)
+#define WCD9335_CDC_RX4_RX_PATH_CTL		WCD9335_REG(0x0b, 0x091)
+#define WCD9335_CDC_RX4_RX_PATH_CFG0		WCD9335_REG(0x0b, 0x092)
+#define WCD9335_CDC_RX4_RX_PATH_CFG2		WCD9335_REG(0x0b, 0x094)
+#define WCD9335_CDC_RX4_RX_VOL_CTL		WCD9335_REG(0x0b, 0x095)
+#define WCD9335_CDC_RX4_RX_PATH_MIX_CTL		WCD9335_REG(0x0b, 0x096)
+#define WCD9335_CDC_RX4_RX_PATH_MIX_CFG		WCD9335_REG(0x0b, 0x097)
+#define WCD9335_CDC_RX4_RX_VOL_MIX_CTL		WCD9335_REG(0x0b, 0x098)
+#define WCD9335_CDC_RX5_RX_PATH_CTL		WCD9335_REG(0x0b, 0x0a5)
+#define WCD9335_CDC_RX5_RX_PATH_CFG0		WCD9335_REG(0x0b, 0x0a6)
+#define WCD9335_CDC_RX5_RX_PATH_CFG2		WCD9335_REG(0x0b, 0x0a8)
+#define WCD9335_CDC_RX5_RX_VOL_CTL		WCD9335_REG(0x0b, 0x0a9)
+#define WCD9335_CDC_RX5_RX_PATH_MIX_CTL		WCD9335_REG(0x0b, 0x0aa)
+#define WCD9335_CDC_RX5_RX_PATH_MIX_CFG		WCD9335_REG(0x0b, 0x0ab)
+#define WCD9335_CDC_RX5_RX_VOL_MIX_CTL		WCD9335_REG(0x0b, 0x0ac)
+#define WCD9335_CDC_RX6_RX_PATH_CTL		WCD9335_REG(0x0b, 0x0b9)
+#define WCD9335_CDC_RX6_RX_PATH_CFG0		WCD9335_REG(0x0b, 0x0ba)
+#define WCD9335_CDC_RX6_RX_PATH_CFG2		WCD9335_REG(0x0b, 0x0bc)
+#define WCD9335_CDC_RX6_RX_VOL_CTL		WCD9335_REG(0x0b, 0x0bd)
+#define WCD9335_CDC_RX6_RX_PATH_MIX_CTL		WCD9335_REG(0x0b, 0x0be)
+#define WCD9335_CDC_RX6_RX_PATH_MIX_CFG		WCD9335_REG(0x0b, 0x0bf)
+#define WCD9335_CDC_RX6_RX_VOL_MIX_CTL		WCD9335_REG(0x0b, 0x0c0)
+#define WCD9335_CDC_RX7_RX_PATH_CTL		WCD9335_REG(0x0b, 0x0cd)
+#define WCD9335_CDC_RX7_RX_PATH_CFG0		WCD9335_REG(0x0b, 0x0ce)
+#define WCD9335_CDC_RX7_RX_PATH_CFG1		WCD9335_REG(0x0b, 0x0cf)
+#define WCD9335_CDC_RX7_RX_PATH_CFG2		WCD9335_REG(0x0b, 0x0d0)
+#define WCD9335_CDC_RX7_RX_VOL_CTL		WCD9335_REG(0x0b, 0x0d1)
+#define WCD9335_CDC_RX7_RX_PATH_MIX_CTL		WCD9335_REG(0x0b, 0x0d2)
+#define WCD9335_CDC_RX7_RX_PATH_MIX_CFG		WCD9335_REG(0x0b, 0x0d3)
+#define WCD9335_CDC_RX7_RX_VOL_MIX_CTL		WCD9335_REG(0x0b, 0x0d4)
+#define WCD9335_CDC_RX8_RX_PATH_CTL		WCD9335_REG(0x0b, 0x0e1)
+#define WCD9335_CDC_RX8_RX_PATH_CFG0		WCD9335_REG(0x0b, 0x0e2)
+#define WCD9335_CDC_RX8_RX_PATH_CFG1		WCD9335_REG(0x0b, 0x0e3)
+#define WCD9335_CDC_RX8_RX_PATH_CFG2		WCD9335_REG(0x0b, 0x0e4)
+#define WCD9335_CDC_RX8_RX_VOL_CTL		WCD9335_REG(0x0b, 0x0e5)
+#define WCD9335_CDC_RX8_RX_PATH_MIX_CTL		WCD9335_REG(0x0b, 0x0e6)
+#define WCD9335_CDC_RX8_RX_PATH_MIX_CFG		WCD9335_REG(0x0b, 0x0e7)
+#define WCD9335_CDC_RX8_RX_VOL_MIX_CTL		WCD9335_REG(0x0b, 0x0e8)
+
+/* Page-12 Registers */
+#define WCD9335_PAGE12_PAGE_REGISTER		WCD9335_REG(0x0c, 0x000)
+#define WCD9335_CDC_CLSH_K2_MSB			WCD9335_REG(0x0c, 0x00a)
+#define WCD9335_CDC_CLSH_K2_LSB			WCD9335_REG(0x0c, 0x00b)
+#define WCD9335_CDC_BOOST0_BOOST_CTL		WCD9335_REG(0x0c, 0x01a)
+#define WCD9335_CDC_BOOST0_BOOST_CFG1		WCD9335_REG(0x0c, 0x01b)
+#define WCD9335_CDC_BOOST0_BOOST_CFG2		WCD9335_REG(0x0c, 0x01c)
+#define WCD9335_CDC_BOOST1_BOOST_CTL		WCD9335_REG(0x0c, 0x022)
+#define WCD9335_CDC_BOOST1_BOOST_CFG1		WCD9335_REG(0x0c, 0x023)
+#define WCD9335_CDC_BOOST1_BOOST_CFG2		WCD9335_REG(0x0c, 0x024)
+
+/* Page-13 Registers */
+#define WCD9335_PAGE13_PAGE_REGISTER		WCD9335_REG(0x0d, 0x000)
+#define WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0	WCD9335_REG(0x0d, 0x001)
+#define WCD9335_CDC_RX_INP_MUX_RX_INT_CFG0(i) WCD9335_REG(0xd, (0x1 + i * 0x2))
+#define WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1	WCD9335_REG(0xd, 0x002)
+#define WCD9335_CDC_RX_INP_MUX_RX_INT_SEL_MASK	GENMASK(3, 0)
+#define WCD9335_CDC_RX_INP_MUX_RX_INT_CFG1(i) WCD9335_REG(0xd, (0x2 + i * 0x2))
+
+#define WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0	WCD9335_REG(0x0d, 0x003)
+#define WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1	WCD9335_REG(0x0d, 0x004)
+#define WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0	WCD9335_REG(0x0d, 0x005)
+#define WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1	WCD9335_REG(0x0d, 0x006)
+#define WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0	WCD9335_REG(0x0d, 0x007)
+#define WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1	WCD9335_REG(0x0d, 0x008)
+#define WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0	WCD9335_REG(0x0d, 0x009)
+#define WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1	WCD9335_REG(0x0d, 0x00a)
+#define WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0	WCD9335_REG(0x0d, 0x00b)
+#define WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1	WCD9335_REG(0x0d, 0x00c)
+#define WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0	WCD9335_REG(0x0d, 0x00d)
+#define WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1	WCD9335_REG(0x0d, 0x00e)
+#define WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0	WCD9335_REG(0x0d, 0x00f)
+#define WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1	WCD9335_REG(0x0d, 0x010)
+#define WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0	WCD9335_REG(0x0d, 0x011)
+#define WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1	WCD9335_REG(0x0d, 0x012)
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0	WCD9335_REG(0x0d, 0x01d)
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1	WCD9335_REG(0x0d, 0x01e)
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0	WCD9335_REG(0x0d, 0x01f)
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1	WCD9335_REG(0x0d, 0x020)
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0	WCD9335_REG(0x0d, 0x021)
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1	WCD9335_REG(0x0d, 0x022)
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0	WCD9335_REG(0x0d, 0x023)
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1	WCD9335_REG(0x0d, 0x024)
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0	WCD9335_REG(0x0d, 0x025)
+#define WCD9335_CDC_TX_INP_MUX_SEL_AMIC	0x1
+#define WCD9335_CDC_TX_INP_MUX_SEL_DMIC	0
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0	WCD9335_REG(0x0d, 0x026)
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0	WCD9335_REG(0x0d, 0x027)
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0	WCD9335_REG(0x0d, 0x028)
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0	WCD9335_REG(0x0d, 0x029)
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX10_CFG0	WCD9335_REG(0x0d, 0x02b)
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX11_CFG0	WCD9335_REG(0x0d, 0x02c)
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX12_CFG0	WCD9335_REG(0x0d, 0x02d)
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX13_CFG0	WCD9335_REG(0x0d, 0x02e)
+#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0	WCD9335_REG(0x0d, 0x03a)
+#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1	WCD9335_REG(0x0d, 0x03b)
+#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2	WCD9335_REG(0x0d, 0x03c)
+#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3	WCD9335_REG(0x0d, 0x03d)
+#define WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL	WCD9335_REG(0x0d, 0x041)
+#define WCD9335_CDC_CLK_RST_CTRL_MCLK_EN_MASK	BIT(0)
+#define WCD9335_CDC_CLK_RST_CTRL_MCLK_ENABLE	BIT(0)
+#define WCD9335_CDC_CLK_RST_CTRL_MCLK_DISABLE	0
+#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL	WCD9335_REG(0x0d, 0x042)
+#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_EN_MASK	BIT(0)
+#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_ENABLE	BIT(0)
+#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_DISABLE	0
+#define WCD9335_CDC_TOP_TOP_CFG1	WCD9335_REG(0x0d, 0x082)
+#define WCD9335_MAX_REGISTER	WCD9335_REG(0x80, 0x0FF)
+
+/* SLIMBUS Slave Registers */
+#define WCD9335_SLIM_PGD_PORT_INT_EN0	WCD9335_REG(0, 0x30)
+#define WCD9335_SLIM_PGD_PORT_INT_STATUS_RX_0	WCD9335_REG(0, 0x34)
+#define WCD9335_SLIM_PGD_PORT_INT_STATUS_RX_1	WCD9335_REG(0, 0x35)
+#define WCD9335_SLIM_PGD_PORT_INT_STATUS_TX_0	WCD9335_REG(0, 0x36)
+#define WCD9335_SLIM_PGD_PORT_INT_STATUS_TX_1	WCD9335_REG(0, 0x37)
+#define WCD9335_SLIM_PGD_PORT_INT_CLR_RX_0	WCD9335_REG(0, 0x38)
+#define WCD9335_SLIM_PGD_PORT_INT_CLR_RX_1	WCD9335_REG(0, 0x39)
+#define WCD9335_SLIM_PGD_PORT_INT_CLR_TX_0	WCD9335_REG(0, 0x3A)
+#define WCD9335_SLIM_PGD_PORT_INT_CLR_TX_1	WCD9335_REG(0, 0x3B)
+#define WCD9335_SLIM_PGD_PORT_INT_RX_SOURCE0	WCD9335_REG(0, 0x60)
+#define WCD9335_SLIM_PGD_PORT_INT_TX_SOURCE0	WCD9335_REG(0, 0x70)
+#define WCD9335_SLIM_PGD_RX_PORT_CFG(p)	WCD9335_REG(0, (0x30 + p))
+#define WCD9335_SLIM_PGD_PORT_CFG(p)	WCD9335_REG(0, (0x40 + p))
+#define WCD9335_SLIM_PGD_TX_PORT_CFG(p)	WCD9335_REG(0, (0x50 + p))
+#define WCD9335_SLIM_PGD_PORT_INT_SRC(p)	WCD9335_REG(0, (0x60 + p))
+#define WCD9335_SLIM_PGD_PORT_INT_STATUS(p)	WCD9335_REG(0, (0x80 + p))
+#define WCD9335_SLIM_PGD_TX_PORT_MULTI_CHNL_0(p) WCD9335_REG(0, (0x100 + 4 * p))
+/* ports range from 10-16 */
+#define WCD9335_SLIM_PGD_TX_PORT_MULTI_CHNL_1(p) WCD9335_REG(0, (0x101 + 4 * p))
+#define WCD9335_SLIM_PGD_RX_PORT_MULTI_CHNL_0(p) WCD9335_REG(0, (0x140 + 4 * p))
+
+#endif
diff --git a/include/linux/mfd/wcd9335/wcd9335.h b/include/linux/mfd/wcd9335/wcd9335.h
new file mode 100644
index 0000000..f5ccacf
--- /dev/null
+++ b/include/linux/mfd/wcd9335/wcd9335.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018, Linaro Limited */
+
+#ifndef __WCD9335_H__
+#define __WCD9335_H__
+
+#include <linux/slimbus.h>
+#include <linux/regulator/consumer.h>
+
+#define WCD9335_VERSION_2_0     2
+#define WCD9335_MAX_SUPPLY	5
+
+enum wcd_interface_type {
+	WCD9335_INTERFACE_TYPE_SLIMBUS = 1,
+	WCD9335_INTERFACE_TYPE_I2C,
+};
+
+/**
+ * struct wcd9335 - wcd9335 device handle.
+ * @version: Version of codec chip
+ * @reset_gpio: rest gpio
+ * @intf_type: Interface type, which can be SLIMBUS or I2C
+ * @dev: wcd9335 evice instance
+ * @mclk: MCLK clock handle.
+ * @slim: wcd9335 slim device handle.
+ * @slim_interface_dev: wcd9335 slim interface device handle
+ * @regmap: wcd9335 slim device regmap
+ * @interface_dev_regmap: wcd9335 interface device regmap.
+ * @supplies: voltage supplies required for wcd9335
+ */
+struct wcd9335 {
+	int version;
+	int reset_gpio;
+	enum wcd_interface_type intf_type;
+	struct device *dev;
+	struct clk *mclk;
+	struct clk *native_clk;
+	struct slim_device *slim;
+	struct slim_device *slim_interface_dev;
+	struct regmap *regmap;
+	struct regmap *interface_dev_regmap;
+	struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY];
+};
+
+#endif /* __WCD9335_H__ */
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v4 03/14] mfd: wcd9335: add wcd irq support
  2018-09-17  0:57 [PATCH v4 00/14] ASoC: Add support to WCD9335 Audio Codec srinivas.kandagatla
  2018-09-17  0:57 ` [PATCH v4 01/14] ASoC: dt-bindings: update wcd9335 bindings srinivas.kandagatla
  2018-09-17  0:57 ` [PATCH v4 02/14] mfd: wcd9335: add support to wcd9335 core srinivas.kandagatla
@ 2018-09-17  0:57 ` srinivas.kandagatla
  2018-09-17  0:57 ` [PATCH v4 04/14] ASoC: wcd9335: add support to wcd9335 codec srinivas.kandagatla
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: srinivas.kandagatla @ 2018-09-17  0:57 UTC (permalink / raw)
  To: lee.jones, robh+dt, broonie
  Cc: mark.rutland, lgirdwood, bgoswami, devicetree, linux-kernel,
	vkoul, alsa-devel, Srinivas Kandagatla

From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

WCD9335 supports two lines of irqs INTR1 and INTR2. Multiple interrupts
are muxed via these lines. INTR1 consists of all possible interrupt
sources like: Ear OCP, HPH OCP, MBHC, MAD, VBAT, and SVA. INTR2 is a
subset of first interrupt sources like MAD, VBAT, and SVA

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Reviewed-by: Vinod Koul <vkoul@kernel.org>
Acked-for-MFD-by: Lee Jones <lee.jones@linaro.org>
---
 drivers/mfd/wcd9335-core.c          | 78 +++++++++++++++++++++++++++++++++++++
 include/linux/mfd/wcd9335/wcd9335.h | 36 +++++++++++++++++
 2 files changed, 114 insertions(+)

diff --git a/drivers/mfd/wcd9335-core.c b/drivers/mfd/wcd9335-core.c
index 81ec0fc..f4266f5 100644
--- a/drivers/mfd/wcd9335-core.c
+++ b/drivers/mfd/wcd9335-core.c
@@ -3,6 +3,7 @@
 
 #include <linux/clk.h>
 #include <linux/gpio.h>
+#include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/wcd9335/registers.h>
@@ -10,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/of_gpio.h>
 #include <linux/of.h>
+#include <linux/of_irq.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
@@ -88,12 +90,71 @@ static struct regmap_config wcd9335_interface_regmap_config = {
 
 static struct wcd9335 *wcd_data;
 
+static const struct regmap_irq wcd9335_irqs[] = {
+	/* INTR_REG 0 */
+	REGMAP_IRQ_REG(WCD9335_IRQ_SLIMBUS, 0, BIT(0)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_FLL_LOCK_LOSS, 0, BIT(1)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_HPH_PA_OCPL_FAULT, 0, BIT(2)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_HPH_PA_OCPR_FAULT, 0, BIT(3)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_EAR_PA_OCP_FAULT, 0, BIT(4)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_HPH_PA_CNPL_COMPLETE, 0, BIT(5)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_HPH_PA_CNPR_COMPLETE, 0, BIT(6)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_EAR_PA_CNP_COMPLETE, 0, BIT(7)),
+	/* INTR_REG 1 */
+	REGMAP_IRQ_REG(WCD9335_IRQ_MBHC_SW_DET, 1, BIT(0)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_MBHC_ELECT_INS_REM_DET, 1, BIT(1)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_MBHC_BUTTON_PRESS_DET, 1, BIT(2)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET, 1, BIT(3)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET, 1, BIT(4)),
+	/* INTR_REG 2 */
+	REGMAP_IRQ_REG(WCD9335_IRQ_LINE_PA1_CNP_COMPLETE, 2, BIT(0)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_LINE_PA2_CNP_COMPLETE, 2, BIT(1)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_LINE_PA3_CNP_COMPLETE, 2, BIT(2)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_LINE_PA4_CNP_COMPLETE, 2, BIT(3)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_SOUNDWIRE, 2, BIT(4)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE, 2, BIT(5)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_RCO_ERROR, 2, BIT(6)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_SVA_ERROR, 2, BIT(7)),
+	/* INTR_REG 3 */
+	REGMAP_IRQ_REG(WCD9335_IRQ_MAD_AUDIO, 3, BIT(0)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_MAD_BEACON, 3, BIT(1)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_MAD_ULTRASOUND, 3, BIT(2)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_VBAT_ATTACK, 3, BIT(3)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_VBAT_RESTORE, 3, BIT(4)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_SVA_OUTBOX1, 3, BIT(5)),
+	REGMAP_IRQ_REG(WCD9335_IRQ_SVA_OUTBOX2, 3, BIT(6)),
+};
+
+static const struct regmap_irq_chip wcd9335_regmap_irq1_chip = {
+	.name = "wcd9335_pin1_irq",
+	.status_base = WCD9335_INTR_PIN1_STATUS0,
+	.mask_base = WCD9335_INTR_PIN1_MASK0,
+	.ack_base = WCD9335_INTR_PIN1_CLEAR0,
+	.type_base = WCD9335_INTR_LEVEL0,
+	.num_regs = 4,
+	.irqs = wcd9335_irqs,
+	.num_irqs = ARRAY_SIZE(wcd9335_irqs),
+};
+
 static int wcd9335_parse_resources(struct wcd9335 *ddata)
 {
 	struct device *dev = ddata->dev;
 	struct device_node *np = dev->of_node;
 	int ret;
 
+	/*
+	 * INTR1 consists of all possible interrupt sources Ear OCP,
+	 * HPH OCP, MBHC, MAD, VBAT, and SVA
+	 * INTR2 is a subset of first interrupt sources MAD, VBAT, and SVA
+	 */
+	ddata->irq = of_irq_get_byname(ddata->dev->of_node, "intr1");
+	if (ddata->irq < 0) {
+		if (ddata->irq != -EPROBE_DEFER)
+			dev_err(ddata->dev, "Unable to configure IRQ\n");
+
+		return ddata->irq;
+	}
+
 	ddata->reset_gpio = of_get_named_gpio(np,	"reset-gpios", 0);
 	if (ddata->reset_gpio < 0) {
 		dev_err(dev, "Reset GPIO missing from DT\n");
@@ -185,6 +246,19 @@ static int wcd9335_bring_up(struct wcd9335 *ddata)
 	return 0;
 }
 
+static int wcd9335_irq_init(struct wcd9335 *ddata)
+{
+	int ret;
+
+	ret = devm_regmap_add_irq_chip(ddata->dev, ddata->regmap, ddata->irq,
+				 IRQF_TRIGGER_HIGH, 0,
+				 &wcd9335_regmap_irq1_chip, &ddata->irq_data);
+	if (ret)
+		dev_err(ddata->dev, "Failed to register IRQ chip: %d\n", ret);
+
+	return ret;
+}
+
 static int wcd9335_slim_status(struct slim_device *sdev,
 			       enum slim_device_status status)
 {
@@ -283,6 +357,10 @@ static int wcd9335_slim_probe(struct slim_device *slim)
 		return ret;
 	}
 
+	ret = wcd9335_irq_init(ddata);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
diff --git a/include/linux/mfd/wcd9335/wcd9335.h b/include/linux/mfd/wcd9335/wcd9335.h
index f5ccacf..38e85e2 100644
--- a/include/linux/mfd/wcd9335/wcd9335.h
+++ b/include/linux/mfd/wcd9335/wcd9335.h
@@ -10,6 +10,38 @@
 #define WCD9335_VERSION_2_0     2
 #define WCD9335_MAX_SUPPLY	5
 
+#define	WCD9335_IRQ_SLIMBUS			0
+#define	WCD9335_IRQ_FLL_LOCK_LOSS		1
+#define	WCD9335_IRQ_HPH_PA_OCPL_FAULT		2
+#define	WCD9335_IRQ_HPH_PA_OCPR_FAULT		3
+#define	WCD9335_IRQ_EAR_PA_OCP_FAULT		4
+#define	WCD9335_IRQ_HPH_PA_CNPL_COMPLETE	5
+#define	WCD9335_IRQ_HPH_PA_CNPR_COMPLETE	6
+#define	WCD9335_IRQ_EAR_PA_CNP_COMPLETE		7
+#define	WCD9335_IRQ_MBHC_SW_DET			8
+#define	WCD9335_IRQ_MBHC_ELECT_INS_REM_DET	9
+#define	WCD9335_IRQ_MBHC_BUTTON_PRESS_DET	10
+#define	WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET	11
+#define	WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET	12
+#define	WCD9335_IRQ_RESERVED_0			13
+#define	WCD9335_IRQ_RESERVED_1			14
+#define	WCD9335_IRQ_RESERVED_2			15
+#define	WCD9335_IRQ_LINE_PA1_CNP_COMPLETE	16
+#define	WCD9335_IRQ_LINE_PA2_CNP_COMPLETE	17
+#define	WCD9335_IRQ_LINE_PA3_CNP_COMPLETE	18
+#define	WCD9335_IRQ_LINE_PA4_CNP_COMPLETE	19
+#define	WCD9335_IRQ_SOUNDWIRE			20
+#define	WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE	21
+#define	WCD9335_IRQ_RCO_ERROR			22
+#define	WCD9335_IRQ_SVA_ERROR			23
+#define	WCD9335_IRQ_MAD_AUDIO			24
+#define	WCD9335_IRQ_MAD_BEACON			25
+#define	WCD9335_IRQ_MAD_ULTRASOUND		26
+#define	WCD9335_IRQ_VBAT_ATTACK			27
+#define	WCD9335_IRQ_VBAT_RESTORE		28
+#define	WCD9335_IRQ_SVA_OUTBOX1			29
+#define	WCD9335_IRQ_SVA_OUTBOX2			30
+
 enum wcd_interface_type {
 	WCD9335_INTERFACE_TYPE_SLIMBUS = 1,
 	WCD9335_INTERFACE_TYPE_I2C,
@@ -18,6 +50,7 @@ enum wcd_interface_type {
 /**
  * struct wcd9335 - wcd9335 device handle.
  * @version: Version of codec chip
+ * @irq: interrupt number
  * @reset_gpio: rest gpio
  * @intf_type: Interface type, which can be SLIMBUS or I2C
  * @dev: wcd9335 evice instance
@@ -26,10 +59,12 @@ enum wcd_interface_type {
  * @slim_interface_dev: wcd9335 slim interface device handle
  * @regmap: wcd9335 slim device regmap
  * @interface_dev_regmap: wcd9335 interface device regmap.
+ * @irq_data: IRQ chip data.
  * @supplies: voltage supplies required for wcd9335
  */
 struct wcd9335 {
 	int version;
+	int irq;
 	int reset_gpio;
 	enum wcd_interface_type intf_type;
 	struct device *dev;
@@ -39,6 +74,7 @@ struct wcd9335 {
 	struct slim_device *slim_interface_dev;
 	struct regmap *regmap;
 	struct regmap *interface_dev_regmap;
+	struct regmap_irq_chip_data *irq_data;
 	struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY];
 };
 
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v4 04/14] ASoC: wcd9335: add support to wcd9335 codec
  2018-09-17  0:57 [PATCH v4 00/14] ASoC: Add support to WCD9335 Audio Codec srinivas.kandagatla
                   ` (2 preceding siblings ...)
  2018-09-17  0:57 ` [PATCH v4 03/14] mfd: wcd9335: add wcd irq support srinivas.kandagatla
@ 2018-09-17  0:57 ` srinivas.kandagatla
  2018-09-17  0:57 ` [PATCH v4 05/14] ASoC: wcd9335: add CLASS-H Controller support srinivas.kandagatla
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: srinivas.kandagatla @ 2018-09-17  0:57 UTC (permalink / raw)
  To: lee.jones, robh+dt, broonie
  Cc: mark.rutland, lgirdwood, bgoswami, devicetree, linux-kernel,
	vkoul, alsa-devel, Srinivas Kandagatla

From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

Qualcomm WCD9335 Codec is a standalone Hi-Fi audio codec IC,
It supports both I2S/I2C and SLIMbus audio interfaces.
On slimbus interface it supports two data lanes; 16 Tx ports
and 8 Rx ports. It has Seven DACs and nine dedicated interpolators,
Seven (six audio ADCs, and one VBAT ADC), Multibutton headset
control (MBHC), Active noise cancellation and Sidetone paths
and processing.

This patchset adds very basic support for playback and capture
via the 9 interpolators and ADC respectively.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Reviewed-by: Vinod Koul <vkoul@kernel.org>
---
 sound/soc/codecs/Kconfig   |    5 +
 sound/soc/codecs/Makefile  |    2 +
 sound/soc/codecs/wcd9335.c | 1177 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1184 insertions(+)
 create mode 100644 sound/soc/codecs/wcd9335.c

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index efb095d..2e8b59a 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -1066,6 +1066,11 @@ config SND_SOC_UDA1380
         tristate
 	depends on I2C
 
+config SND_SOC_WCD9335
+	tristate "WCD9335 Codec"
+	depends on MFD_WCD9335_SLIM
+        tristate
+
 config SND_SOC_WL1273
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 7ae7c85..01410b6 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -192,6 +192,7 @@ snd-soc-twl4030-objs := twl4030.o
 snd-soc-twl6040-objs := twl6040.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
+snd-soc-wcd9335-objs := wcd9335.o
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm-adsp-objs := wm_adsp.o
 snd-soc-wm0010-objs := wm0010.o
@@ -451,6 +452,7 @@ obj-$(CONFIG_SND_SOC_TWL4030)	+= snd-soc-twl4030.o
 obj-$(CONFIG_SND_SOC_TWL6040)	+= snd-soc-twl6040.o
 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_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/wcd9335.c b/sound/soc/codecs/wcd9335.c
new file mode 100644
index 0000000..764c844
--- /dev/null
+++ b/sound/soc/codecs/wcd9335.c
@@ -0,0 +1,1177 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+// Copyright (c) 2017-2018, Linaro Limited
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/regulator/consumer.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/slimbus.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/info.h>
+#include <linux/mfd/wcd9335/wcd9335.h>
+#include <linux/mfd/wcd9335/registers.h>
+
+#define WCD9335_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 WCD9335_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100)
+#define WCD9335_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \
+				  SNDRV_PCM_FMTBIT_S24_LE)
+
+/* slave port water mark level
+ *   (0: 6bytes, 1: 9bytes, 2: 12 bytes, 3: 15 bytes)
+ */
+#define SLAVE_PORT_WATER_MARK_6BYTES  0
+#define SLAVE_PORT_WATER_MARK_9BYTES  1
+#define SLAVE_PORT_WATER_MARK_12BYTES 2
+#define SLAVE_PORT_WATER_MARK_15BYTES 3
+#define SLAVE_PORT_WATER_MARK_SHIFT 1
+#define SLAVE_PORT_ENABLE           1
+#define SLAVE_PORT_DISABLE          0
+#define WCD9335_SLIM_WATER_MARK_VAL \
+	((SLAVE_PORT_WATER_MARK_12BYTES << SLAVE_PORT_WATER_MARK_SHIFT) | \
+	 (SLAVE_PORT_ENABLE))
+
+#define WCD9335_SLIM_NUM_PORT_REG 3
+#define WCD9335_SLIM_PGD_PORT_INT_TX_EN0 (WCD9335_SLIM_PGD_PORT_INT_EN0 + 2)
+
+#define WCD9335_MCLK_CLK_12P288MHZ	12288000
+#define WCD9335_MCLK_CLK_9P6MHZ		9600000
+
+#define WCD9335_SLIM_CLOSE_TIMEOUT 1000
+#define WCD9335_SLIM_IRQ_OVERFLOW (1 << 0)
+#define WCD9335_SLIM_IRQ_UNDERFLOW (1 << 1)
+#define WCD9335_SLIM_IRQ_PORT_CLOSED (1 << 2)
+
+#define WCD9335_NUM_INTERPOLATORS 9
+#define WCD9335_RX_START	16
+#define WCD9335_SLIM_CH_START 128
+
+#define WCD9335_SLIM_RX_CH(p) \
+	{.port = p + WCD9335_RX_START, .shift = p,}
+
+/* vout step value */
+#define WCD9335_CALCULATE_VOUT_D(req_mv) (((req_mv - 650) * 10) / 25)
+
+enum {
+	WCD9335_RX0 = 0,
+	WCD9335_RX1,
+	WCD9335_RX2,
+	WCD9335_RX3,
+	WCD9335_RX4,
+	WCD9335_RX5,
+	WCD9335_RX6,
+	WCD9335_RX7,
+	WCD9335_RX8,
+	WCD9335_RX9,
+	WCD9335_RX10,
+	WCD9335_RX11,
+	WCD9335_RX12,
+	WCD9335_RX_MAX,
+};
+
+enum {
+	SIDO_SOURCE_INTERNAL = 0,
+	SIDO_SOURCE_RCO_BG,
+};
+
+enum wcd9335_sido_voltage {
+	SIDO_VOLTAGE_SVS_MV = 950,
+	SIDO_VOLTAGE_NOMINAL_MV = 1100,
+};
+
+enum {
+	AIF1_PB = 0,
+	AIF1_CAP,
+	AIF2_PB,
+	AIF2_CAP,
+	AIF3_PB,
+	AIF3_CAP,
+	AIF4_PB,
+	NUM_CODEC_DAIS,
+};
+
+enum {
+	INTn_2_INP_SEL_ZERO = 0,
+	INTn_2_INP_SEL_RX0,
+	INTn_2_INP_SEL_RX1,
+	INTn_2_INP_SEL_RX2,
+	INTn_2_INP_SEL_RX3,
+	INTn_2_INP_SEL_RX4,
+	INTn_2_INP_SEL_RX5,
+	INTn_2_INP_SEL_RX6,
+	INTn_2_INP_SEL_RX7,
+	INTn_2_INP_SEL_PROXIMITY,
+};
+
+enum {
+	INTn_1_MIX_INP_SEL_ZERO = 0,
+	INTn_1_MIX_INP_SEL_DEC0,
+	INTn_1_MIX_INP_SEL_DEC1,
+	INTn_1_MIX_INP_SEL_IIR0,
+	INTn_1_MIX_INP_SEL_IIR1,
+	INTn_1_MIX_INP_SEL_RX0,
+	INTn_1_MIX_INP_SEL_RX1,
+	INTn_1_MIX_INP_SEL_RX2,
+	INTn_1_MIX_INP_SEL_RX3,
+	INTn_1_MIX_INP_SEL_RX4,
+	INTn_1_MIX_INP_SEL_RX5,
+	INTn_1_MIX_INP_SEL_RX6,
+	INTn_1_MIX_INP_SEL_RX7,
+
+};
+
+enum wcd_clock_type {
+	WCD_CLK_OFF,
+	WCD_CLK_RCO,
+	WCD_CLK_MCLK,
+};
+
+struct wcd9335_slim_ch {
+	u32 ch_num;
+	u16 port;
+	u16 shift;
+	struct list_head list;
+};
+
+struct wcd_slim_codec_dai_data {
+	struct list_head slim_ch_list;
+	struct slim_stream_config sconfig;
+	struct slim_stream_runtime *sruntime;
+};
+
+struct wcd9335_codec {
+	struct device *dev;
+	struct clk *mclk;
+	struct clk *native_clk;
+	u32 mclk_rate;
+	u8 intf_type;
+	u8 version;
+
+	struct slim_device *slim;
+	struct slim_device *slim_interface_dev;
+	struct regmap *regmap;
+	struct regmap *if_regmap;
+	struct regmap_irq_chip_data *irq_data;
+
+	struct wcd9335_slim_ch rx_chs[WCD9335_RX_MAX];
+	u32 num_rx_port;
+
+	int sido_input_src;
+	enum wcd9335_sido_voltage sido_voltage;
+
+	struct wcd_slim_codec_dai_data dai[NUM_CODEC_DAIS];
+	struct snd_soc_component *component;
+
+	int master_bias_users;
+	int clk_mclk_users;
+	int clk_rco_users;
+	int sido_ccl_cnt;
+	enum wcd_clock_type clk_type;
+
+	u32 hph_mode;
+};
+
+struct wcd9335_irq {
+	int irq;
+	irqreturn_t (*handler)(int irq, void *data);
+	char *name;
+};
+
+static const struct wcd9335_slim_ch wcd9335_rx_chs[WCD9335_RX_MAX] = {
+	WCD9335_SLIM_RX_CH(0),	 /* 16 */
+	WCD9335_SLIM_RX_CH(1),	 /* 17 */
+	WCD9335_SLIM_RX_CH(2),
+	WCD9335_SLIM_RX_CH(3),
+	WCD9335_SLIM_RX_CH(4),
+	WCD9335_SLIM_RX_CH(5),
+	WCD9335_SLIM_RX_CH(6),
+	WCD9335_SLIM_RX_CH(7),
+	WCD9335_SLIM_RX_CH(8),
+	WCD9335_SLIM_RX_CH(9),
+	WCD9335_SLIM_RX_CH(10),
+	WCD9335_SLIM_RX_CH(11),
+	WCD9335_SLIM_RX_CH(12),
+};
+
+struct interp_sample_rate {
+	int rate;
+	int rate_val;
+};
+
+static struct interp_sample_rate int_mix_rate_val[] = {
+	{48000, 0x4},	/* 48K */
+	{96000, 0x5},	/* 96K */
+	{192000, 0x6},	/* 192K */
+};
+
+static struct interp_sample_rate int_prim_rate_val[] = {
+	{8000, 0x0},	/* 8K */
+	{16000, 0x1},	/* 16K */
+	{24000, -EINVAL},/* 24K */
+	{32000, 0x3},	/* 32K */
+	{48000, 0x4},	/* 48K */
+	{96000, 0x5},	/* 96K */
+	{192000, 0x6},	/* 192K */
+	{384000, 0x7},	/* 384K */
+	{44100, 0x8}, /* 44.1K */
+};
+
+struct wcd9335_reg_mask_val {
+	u16 reg;
+	u8 mask;
+	u8 val;
+};
+
+static const struct wcd9335_reg_mask_val wcd9335_codec_reg_init[] = {
+	/* Rbuckfly/R_EAR(32) */
+	{WCD9335_CDC_CLSH_K2_MSB, 0x0F, 0x00},
+	{WCD9335_CDC_CLSH_K2_LSB, 0xFF, 0x60},
+	{WCD9335_CPE_SS_DMIC_CFG, 0x80, 0x00},
+	{WCD9335_CDC_BOOST0_BOOST_CTL, 0x70, 0x50},
+	{WCD9335_CDC_BOOST1_BOOST_CTL, 0x70, 0x50},
+	{WCD9335_CDC_RX7_RX_PATH_CFG1, 0x08, 0x08},
+	{WCD9335_CDC_RX8_RX_PATH_CFG1, 0x08, 0x08},
+	{WCD9335_ANA_LO_1_2, 0x3C, 0X3C},
+	{WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ, 0x70, 0x00},
+	{WCD9335_DIFF_LO_COM_PA_FREQ, 0x70, 0x40},
+	{WCD9335_SOC_MAD_AUDIO_CTL_2, 0x03, 0x03},
+	{WCD9335_CDC_TOP_TOP_CFG1, 0x02, 0x02},
+	{WCD9335_CDC_TOP_TOP_CFG1, 0x01, 0x01},
+	{WCD9335_EAR_CMBUFF, 0x08, 0x00},
+	{WCD9335_CDC_TX9_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_TX10_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_TX11_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_TX12_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_COMPANDER7_CTL3, 0x80, 0x80},
+	{WCD9335_CDC_COMPANDER8_CTL3, 0x80, 0x80},
+	{WCD9335_CDC_COMPANDER7_CTL7, 0x01, 0x01},
+	{WCD9335_CDC_COMPANDER8_CTL7, 0x01, 0x01},
+	{WCD9335_CDC_RX0_RX_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_RX1_RX_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_RX2_RX_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_RX3_RX_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_RX4_RX_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_RX5_RX_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_RX6_RX_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_RX7_RX_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_RX8_RX_PATH_CFG0, 0x01, 0x01},
+	{WCD9335_CDC_RX0_RX_PATH_MIX_CFG, 0x01, 0x01},
+	{WCD9335_CDC_RX1_RX_PATH_MIX_CFG, 0x01, 0x01},
+	{WCD9335_CDC_RX2_RX_PATH_MIX_CFG, 0x01, 0x01},
+	{WCD9335_CDC_RX3_RX_PATH_MIX_CFG, 0x01, 0x01},
+	{WCD9335_CDC_RX4_RX_PATH_MIX_CFG, 0x01, 0x01},
+	{WCD9335_CDC_RX5_RX_PATH_MIX_CFG, 0x01, 0x01},
+	{WCD9335_CDC_RX6_RX_PATH_MIX_CFG, 0x01, 0x01},
+	{WCD9335_CDC_RX7_RX_PATH_MIX_CFG, 0x01, 0x01},
+	{WCD9335_CDC_RX8_RX_PATH_MIX_CFG, 0x01, 0x01},
+	{WCD9335_VBADC_IBIAS_FE, 0x0C, 0x08},
+	{WCD9335_RCO_CTRL_2, 0x0F, 0x08},
+	{WCD9335_RX_BIAS_FLYB_MID_RST, 0xF0, 0x10},
+	{WCD9335_FLYBACK_CTRL_1, 0x20, 0x20},
+	{WCD9335_HPH_OCP_CTL, 0xFF, 0x5A},
+	{WCD9335_HPH_L_TEST, 0x01, 0x01},
+	{WCD9335_HPH_R_TEST, 0x01, 0x01},
+	{WCD9335_CDC_BOOST0_BOOST_CFG1, 0x3F, 0x12},
+	{WCD9335_CDC_BOOST0_BOOST_CFG2, 0x1C, 0x08},
+	{WCD9335_CDC_COMPANDER7_CTL7, 0x1E, 0x18},
+	{WCD9335_CDC_BOOST1_BOOST_CFG1, 0x3F, 0x12},
+	{WCD9335_CDC_BOOST1_BOOST_CFG2, 0x1C, 0x08},
+	{WCD9335_CDC_COMPANDER8_CTL7, 0x1E, 0x18},
+	{WCD9335_CDC_TX0_TX_PATH_SEC7, 0xFF, 0x45},
+	{WCD9335_CDC_RX0_RX_PATH_SEC0, 0xFC, 0xF4},
+	{WCD9335_HPH_REFBUFF_LP_CTL, 0x08, 0x08},
+	{WCD9335_HPH_REFBUFF_LP_CTL, 0x06, 0x02},
+};
+
+static int wcd9335_set_mix_interpolator_rate(struct snd_soc_dai *dai,
+					     int rate_val,
+					     u32 rate)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wcd9335_codec *wcd = dev_get_drvdata(component->dev);
+	struct wcd9335_slim_ch *ch;
+	int val, j;
+
+	list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) {
+		for (j = 0; j < WCD9335_NUM_INTERPOLATORS; j++) {
+			val = snd_soc_component_read32(component,
+					WCD9335_CDC_RX_INP_MUX_RX_INT_CFG1(j)) &
+					WCD9335_CDC_RX_INP_MUX_RX_INT_SEL_MASK;
+
+			if (val == (ch->shift + INTn_2_INP_SEL_RX0))
+				snd_soc_component_update_bits(component,
+						WCD9335_CDC_RX_PATH_MIX_CTL(j),
+						WCD9335_CDC_MIX_PCM_RATE_MASK,
+						rate_val);
+		}
+	}
+
+	return 0;
+}
+
+static int wcd9335_set_prim_interpolator_rate(struct snd_soc_dai *dai,
+					      u8 rate_val,
+					      u32 rate)
+{
+	struct snd_soc_component *comp = dai->component;
+	struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev);
+	struct wcd9335_slim_ch *ch;
+	u8 cfg0, cfg1, inp0_sel, inp1_sel, inp2_sel;
+	int inp, j;
+
+	list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) {
+		inp = ch->shift + INTn_1_MIX_INP_SEL_RX0;
+		/*
+		 * Loop through all interpolator MUX inputs and find out
+		 * to which interpolator input, the slim rx port
+		 * is connected
+		 */
+		for (j = 0; j < WCD9335_NUM_INTERPOLATORS; j++) {
+			cfg0 = snd_soc_component_read32(comp,
+					WCD9335_CDC_RX_INP_MUX_RX_INT_CFG0(j));
+			cfg1 = snd_soc_component_read32(comp,
+					WCD9335_CDC_RX_INP_MUX_RX_INT_CFG1(j));
+
+			inp0_sel = cfg0 &
+				 WCD9335_CDC_RX_INP_MUX_RX_INT_SEL_MASK;
+			inp1_sel = (cfg0 >> 4) &
+				 WCD9335_CDC_RX_INP_MUX_RX_INT_SEL_MASK;
+			inp2_sel = (cfg1 >> 4) &
+				 WCD9335_CDC_RX_INP_MUX_RX_INT_SEL_MASK;
+
+			if ((inp0_sel == inp) ||  (inp1_sel == inp) ||
+			    (inp2_sel == inp)) {
+				/* rate is in Hz */
+				if ((j == 0) && (rate == 44100))
+					dev_info(wcd->dev,
+						"Cannot set 44.1KHz on INT0\n");
+				else
+					snd_soc_component_update_bits(comp,
+						WCD9335_CDC_RX_PATH_CTL(j),
+						WCD9335_CDC_MIX_PCM_RATE_MASK,
+						rate_val);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int wcd9335_set_interpolator_rate(struct snd_soc_dai *dai, u32 rate)
+{
+	int i;
+
+	/* set mixing path rate */
+	for (i = 0; i < ARRAY_SIZE(int_mix_rate_val); i++) {
+		if (rate == int_mix_rate_val[i].rate) {
+			wcd9335_set_mix_interpolator_rate(dai,
+					int_mix_rate_val[i].rate_val, rate);
+			break;
+		}
+	}
+
+	/* set primary path sample rate */
+	for (i = 0; i < ARRAY_SIZE(int_prim_rate_val); i++) {
+		if (rate == int_prim_rate_val[i].rate) {
+			wcd9335_set_prim_interpolator_rate(dai,
+					int_prim_rate_val[i].rate_val, rate);
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int wcd9335_slim_set_hw_params(struct wcd9335_codec *wcd,
+				 struct wcd_slim_codec_dai_data *dai_data,
+				 int direction)
+{
+	struct list_head *slim_ch_list = &dai_data->slim_ch_list;
+	struct slim_stream_config *cfg = &dai_data->sconfig;
+	struct wcd9335_slim_ch *ch;
+	u16 payload = 0;
+	int ret, i;
+
+	cfg->ch_count = 0;
+	cfg->direction = direction;
+	cfg->port_mask = 0;
+
+	/* Configure slave interface device */
+	list_for_each_entry(ch, slim_ch_list, list) {
+		cfg->ch_count++;
+		payload |= 1 << ch->shift;
+		cfg->port_mask |= BIT(ch->port);
+	}
+
+	cfg->chs = kcalloc(cfg->ch_count, sizeof(unsigned int), GFP_KERNEL);
+	if (!cfg->chs)
+		return -ENOMEM;
+
+	i = 0;
+	list_for_each_entry(ch, slim_ch_list, list) {
+		cfg->chs[i++] = ch->ch_num;
+		if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+			/* write to interface device */
+			ret = regmap_write(wcd->if_regmap,
+				WCD9335_SLIM_PGD_RX_PORT_MULTI_CHNL_0(ch->port),
+				payload);
+
+			if (ret < 0)
+				goto err;
+
+			/* configure the slave port for water mark and enable*/
+			ret = regmap_write(wcd->if_regmap,
+					WCD9335_SLIM_PGD_RX_PORT_CFG(ch->port),
+					WCD9335_SLIM_WATER_MARK_VAL);
+			if (ret < 0)
+				goto err;
+		}
+	}
+
+	dai_data->sruntime = slim_stream_allocate(wcd->slim, "WCD9335-SLIM");
+	slim_stream_prepare(dai_data->sruntime, cfg);
+
+	return 0;
+
+err:
+	dev_err(wcd->dev, "Error Setting slim hw params\n");
+	kfree(cfg->chs);
+	cfg->chs = NULL;
+
+	return ret;
+}
+
+static int wcd9335_hw_params(struct snd_pcm_substream *substream,
+			   struct snd_pcm_hw_params *params,
+			   struct snd_soc_dai *dai)
+{
+	struct wcd9335_codec *wcd;
+	int ret;
+
+	wcd = snd_soc_component_get_drvdata(dai->component);
+
+	switch (substream->stream) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		ret = wcd9335_set_interpolator_rate(dai, params_rate(params));
+		if (ret) {
+			dev_err(wcd->dev, "cannot set sample rate: %u\n",
+				params_rate(params));
+			return ret;
+		}
+		switch (params_width(params)) {
+		case 16 ... 24:
+			wcd->dai[dai->id].sconfig.bps = params_width(params);
+			break;
+		default:
+			dev_err(wcd->dev, "%s: Invalid format 0x%x\n",
+				__func__, params_width(params));
+			return -EINVAL;
+		}
+		break;
+	default:
+		dev_err(wcd->dev, "Invalid stream type %d\n",
+			substream->stream);
+		return -EINVAL;
+	};
+
+	wcd->dai[dai->id].sconfig.rate = params_rate(params);
+	wcd9335_slim_set_hw_params(wcd, &wcd->dai[dai->id], substream->stream);
+
+	return 0;
+}
+
+static int wcd9335_prepare(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *dai)
+{
+	struct wcd_slim_codec_dai_data *dai_data;
+	struct wcd9335_codec *wcd;
+
+	wcd = snd_soc_component_get_drvdata(dai->component);
+	dai_data = &wcd->dai[dai->id];
+	slim_stream_enable(dai_data->sruntime);
+
+	return 0;
+}
+
+static int wcd9335_set_channel_map(struct snd_soc_dai *dai,
+				   unsigned int tx_num, unsigned int *tx_slot,
+				   unsigned int rx_num, unsigned int *rx_slot)
+{
+	struct wcd9335_codec *wcd;
+	int i;
+
+	wcd = snd_soc_component_get_drvdata(dai->component);
+
+	if (!tx_slot || !rx_slot) {
+		dev_err(wcd->dev, "Invalid tx_slot=%p, rx_slot=%p\n",
+			tx_slot, rx_slot);
+		return -EINVAL;
+	}
+
+	if (wcd->rx_chs) {
+		wcd->num_rx_port = rx_num;
+		for (i = 0; i < rx_num; i++) {
+			wcd->rx_chs[i].ch_num = rx_slot[i];
+			INIT_LIST_HEAD(&wcd->rx_chs[i].list);
+		}
+	}
+
+	return 0;
+}
+
+static int wcd9335_get_channel_map(struct snd_soc_dai *dai,
+				   unsigned int *tx_num, unsigned int *tx_slot,
+				   unsigned int *rx_num, unsigned int *rx_slot)
+{
+	struct wcd9335_slim_ch *ch;
+	struct wcd9335_codec *wcd;
+	int i = 0;
+
+	wcd = snd_soc_component_get_drvdata(dai->component);
+
+	switch (dai->id) {
+	case AIF1_PB:
+	case AIF2_PB:
+	case AIF3_PB:
+	case AIF4_PB:
+		if (!rx_slot || !rx_num) {
+			dev_err(wcd->dev, "Invalid rx_slot %p or rx_num %p\n",
+				rx_slot, rx_num);
+			return -EINVAL;
+		}
+
+		list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list)
+			rx_slot[i++] = ch->ch_num;
+
+		*rx_num = i;
+		break;
+	default:
+		dev_err(wcd->dev, "Invalid DAI ID %x\n", dai->id);
+		break;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops wcd9335_dai_ops = {
+	.hw_params = wcd9335_hw_params,
+	.prepare = wcd9335_prepare,
+	.set_channel_map = wcd9335_set_channel_map,
+	.get_channel_map = wcd9335_get_channel_map,
+};
+
+static struct snd_soc_dai_driver wcd9335_slim_dais[] = {
+	[0] = {
+		.name = "wcd9335_rx1",
+		.id = AIF1_PB,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK,
+			.formats = WCD9335_FORMATS_S16_S24_LE,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &wcd9335_dai_ops,
+	},
+	[1] = {
+		.name = "wcd9335_tx1",
+		.id = AIF1_CAP,
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.rates = WCD9335_RATES_MASK,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rate_min = 8000,
+			.rate_max = 192000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &wcd9335_dai_ops,
+	},
+	[2] = {
+		.name = "wcd9335_rx2",
+		.id = AIF2_PB,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK,
+			.formats = WCD9335_FORMATS_S16_S24_LE,
+			.rate_min = 8000,
+			.rate_max = 192000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &wcd9335_dai_ops,
+	},
+	[3] = {
+		.name = "wcd9335_tx2",
+		.id = AIF2_CAP,
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.rates = WCD9335_RATES_MASK,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rate_min = 8000,
+			.rate_max = 192000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &wcd9335_dai_ops,
+	},
+	[4] = {
+		.name = "wcd9335_rx3",
+		.id = AIF3_PB,
+		.playback = {
+			.stream_name = "AIF3 Playback",
+			.rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK,
+			.formats = WCD9335_FORMATS_S16_S24_LE,
+			.rate_min = 8000,
+			.rate_max = 192000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &wcd9335_dai_ops,
+	},
+	[5] = {
+		.name = "wcd9335_tx3",
+		.id = AIF3_CAP,
+		.capture = {
+			.stream_name = "AIF3 Capture",
+			.rates = WCD9335_RATES_MASK,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rate_min = 8000,
+			.rate_max = 192000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &wcd9335_dai_ops,
+	},
+	[6] = {
+		.name = "wcd9335_rx4",
+		.id = AIF4_PB,
+		.playback = {
+			.stream_name = "AIF4 Playback",
+			.rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK,
+			.formats = WCD9335_FORMATS_S16_S24_LE,
+			.rate_min = 8000,
+			.rate_max = 192000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &wcd9335_dai_ops,
+	},
+};
+
+static irqreturn_t wcd9335_slimbus_irq(int irq, void *data)
+{
+	struct wcd9335_codec *wcd = data;
+	unsigned long status = 0;
+	int i, j, port_id;
+	unsigned int val, int_val = 0;
+	bool tx;
+	unsigned short reg = 0;
+
+	for (i = WCD9335_SLIM_PGD_PORT_INT_STATUS_RX_0, j = 0;
+	     i <= WCD9335_SLIM_PGD_PORT_INT_STATUS_TX_1; i++, j++) {
+		regmap_read(wcd->if_regmap, i, &val);
+		status |= ((u32)val << (8 * j));
+	}
+
+	for_each_set_bit(j, &status, 32) {
+		tx = (j >= 16 ? true : false);
+		port_id = (tx ? j - 16 : j);
+		regmap_read(wcd->if_regmap,
+				WCD9335_SLIM_PGD_PORT_INT_RX_SOURCE0 + j, &val);
+		if (val) {
+			if (!tx)
+				reg = WCD9335_SLIM_PGD_PORT_INT_EN0 +
+					(port_id / 8);
+			else
+				reg = WCD9335_SLIM_PGD_PORT_INT_TX_EN0 +
+					(port_id / 8);
+			regmap_read(
+				wcd->if_regmap, reg, &int_val);
+			/*
+			 * Ignore interrupts for ports for which the
+			 * interrupts are not specifically enabled.
+			 */
+			if (!(int_val & (1 << (port_id % 8))))
+				continue;
+		}
+		if (val & WCD9335_SLIM_IRQ_OVERFLOW)
+			dev_err_ratelimited(wcd->dev,
+			   "%s: overflow error on %s port %d, value %x\n",
+			   __func__, (tx ? "TX" : "RX"), port_id, val);
+		if (val & WCD9335_SLIM_IRQ_UNDERFLOW)
+			dev_err_ratelimited(wcd->dev,
+			   "%s: underflow error on %s port %d, value %x\n",
+			   __func__, (tx ? "TX" : "RX"), port_id, val);
+		if ((val & WCD9335_SLIM_IRQ_OVERFLOW) ||
+			(val & WCD9335_SLIM_IRQ_UNDERFLOW)) {
+			if (!tx)
+				reg = WCD9335_SLIM_PGD_PORT_INT_EN0 +
+					(port_id / 8);
+			else
+				reg = WCD9335_SLIM_PGD_PORT_INT_TX_EN0 +
+					(port_id / 8);
+			regmap_read(
+				wcd->if_regmap, reg, &int_val);
+			if (int_val & (1 << (port_id % 8))) {
+				int_val = int_val ^ (1 << (port_id % 8));
+				regmap_write(wcd->if_regmap,
+					reg, int_val);
+			}
+		}
+
+		regmap_write(wcd->if_regmap,
+				WCD9335_SLIM_PGD_PORT_INT_CLR_RX_0 + (j / 8),
+				BIT(j % 8));
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct wcd9335_irq wcd9335_irqs[] = {
+	{
+		.irq = WCD9335_IRQ_SLIMBUS,
+		.handler = wcd9335_slimbus_irq,
+		.name = "SLIM Slave",
+	},
+};
+
+static int wcd9335_setup_irqs(struct wcd9335_codec *wcd)
+{
+	int irq, ret, i;
+
+	for (i = 0; i < ARRAY_SIZE(wcd9335_irqs); i++) {
+		irq = regmap_irq_get_virq(wcd->irq_data, wcd9335_irqs[i].irq);
+		if (irq < 0) {
+			dev_err(wcd->dev, "Failed to get %s\n",
+					wcd9335_irqs[i].name);
+			return irq;
+		}
+
+		ret = devm_request_threaded_irq(wcd->dev, irq, NULL,
+						wcd9335_irqs[i].handler,
+						IRQF_TRIGGER_RISING,
+						wcd9335_irqs[i].name, wcd);
+		if (ret) {
+			dev_err(wcd->dev, "Failed to request %s\n",
+					wcd9335_irqs[i].name);
+			return ret;
+		}
+	}
+
+	/* enable interrupts on all slave ports */
+	for (i = 0; i < WCD9335_SLIM_NUM_PORT_REG; i++)
+		regmap_write(wcd->if_regmap, WCD9335_SLIM_PGD_PORT_INT_EN0 + i,
+			     0xFF);
+
+	return ret;
+}
+
+static void wcd9335_cdc_sido_ccl_enable(struct wcd9335_codec *wcd,
+					bool ccl_flag)
+{
+	struct snd_soc_component *comp = wcd->component;
+
+	if (ccl_flag) {
+		if (++wcd->sido_ccl_cnt == 1)
+			snd_soc_component_write(comp, WCD9335_SIDO_SIDO_CCL_10,
+					WCD9335_SIDO_SIDO_CCL_DEF_VALUE);
+	} else {
+		if (wcd->sido_ccl_cnt == 0) {
+			dev_err(wcd->dev, "sido_ccl already disabled\n");
+			return;
+		}
+		if (--wcd->sido_ccl_cnt == 0)
+			snd_soc_component_write(comp, WCD9335_SIDO_SIDO_CCL_10,
+				WCD9335_SIDO_SIDO_CCL_10_ICHARG_PWR_SEL_C320FF);
+	}
+}
+
+static int wcd9335_enable_master_bias(struct wcd9335_codec *wcd)
+{
+	wcd->master_bias_users++;
+	if (wcd->master_bias_users == 1) {
+		regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS,
+					WCD9335_ANA_BIAS_EN_MASK,
+					WCD9335_ANA_BIAS_ENABLE);
+		regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS,
+					WCD9335_ANA_BIAS_PRECHRG_EN_MASK,
+					WCD9335_ANA_BIAS_PRECHRG_ENABLE);
+		/*
+		 * 1ms delay is required after pre-charge is enabled
+		 * as per HW requirement
+		 */
+		usleep_range(1000, 1100);
+		regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS,
+					WCD9335_ANA_BIAS_PRECHRG_EN_MASK,
+					WCD9335_ANA_BIAS_PRECHRG_DISABLE);
+		regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS,
+				WCD9335_ANA_BIAS_PRECHRG_CTL_MODE,
+				WCD9335_ANA_BIAS_PRECHRG_CTL_MODE_MANUAL);
+	}
+
+	return 0;
+}
+
+static int wcd9335_enable_mclk(struct wcd9335_codec *wcd)
+{
+	/* Enable mclk requires master bias to be enabled first */
+	if (wcd->master_bias_users <= 0)
+		return -EINVAL;
+
+	if (((wcd->clk_mclk_users == 0) && (wcd->clk_type == WCD_CLK_MCLK)) ||
+	    ((wcd->clk_mclk_users > 0) && (wcd->clk_type != WCD_CLK_MCLK))) {
+		dev_err(wcd->dev, "Error enabling MCLK, clk_type: %d\n",
+			wcd->clk_type);
+		return -EINVAL;
+	}
+
+	if (++wcd->clk_mclk_users == 1) {
+		regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP,
+					WCD9335_ANA_CLK_EXT_CLKBUF_EN_MASK,
+					WCD9335_ANA_CLK_EXT_CLKBUF_ENABLE);
+		regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP,
+					WCD9335_ANA_CLK_MCLK_SRC_MASK,
+					WCD9335_ANA_CLK_MCLK_SRC_EXTERNAL);
+		regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP,
+					WCD9335_ANA_CLK_MCLK_EN_MASK,
+					WCD9335_ANA_CLK_MCLK_ENABLE);
+		regmap_update_bits(wcd->regmap,
+				   WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL,
+				   WCD9335_CDC_CLK_RST_CTRL_FS_CNT_EN_MASK,
+				   WCD9335_CDC_CLK_RST_CTRL_FS_CNT_ENABLE);
+		regmap_update_bits(wcd->regmap,
+				   WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL,
+				   WCD9335_CDC_CLK_RST_CTRL_MCLK_EN_MASK,
+				   WCD9335_CDC_CLK_RST_CTRL_MCLK_ENABLE);
+		/*
+		 * 10us sleep is required after clock is enabled
+		 * as per HW requirement
+		 */
+		usleep_range(10, 15);
+	}
+
+	wcd->clk_type = WCD_CLK_MCLK;
+
+	return 0;
+}
+
+static int wcd9335_disable_mclk(struct wcd9335_codec *wcd)
+{
+	if (wcd->clk_mclk_users <= 0)
+		return -EINVAL;
+
+	if (--wcd->clk_mclk_users == 0) {
+		if (wcd->clk_rco_users > 0) {
+			/* MCLK to RCO switch */
+			regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP,
+					WCD9335_ANA_CLK_MCLK_SRC_MASK,
+					WCD9335_ANA_CLK_MCLK_SRC_RCO);
+			wcd->clk_type = WCD_CLK_RCO;
+		} else {
+			regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP,
+					WCD9335_ANA_CLK_MCLK_EN_MASK,
+					WCD9335_ANA_CLK_MCLK_DISABLE);
+			wcd->clk_type = WCD_CLK_OFF;
+		}
+
+		regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP,
+					WCD9335_ANA_CLK_EXT_CLKBUF_EN_MASK,
+					WCD9335_ANA_CLK_EXT_CLKBUF_DISABLE);
+	}
+
+	return 0;
+}
+
+static int wcd9335_disable_master_bias(struct wcd9335_codec *wcd)
+{
+	if (wcd->master_bias_users <= 0)
+		return -EINVAL;
+
+	wcd->master_bias_users--;
+	if (wcd->master_bias_users == 0) {
+		regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS,
+				WCD9335_ANA_BIAS_EN_MASK,
+				WCD9335_ANA_BIAS_DISABLE);
+		regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS,
+				WCD9335_ANA_BIAS_PRECHRG_CTL_MODE,
+				WCD9335_ANA_BIAS_PRECHRG_CTL_MODE_MANUAL);
+	}
+	return 0;
+}
+
+static int wcd9335_cdc_req_mclk_enable(struct wcd9335_codec *wcd,
+				     bool enable)
+{
+	int ret = 0;
+
+	if (enable) {
+		wcd9335_cdc_sido_ccl_enable(wcd, true);
+		ret = clk_prepare_enable(wcd->mclk);
+		if (ret) {
+			dev_err(wcd->dev, "%s: ext clk enable failed\n",
+				__func__);
+			goto err;
+		}
+		/* get BG */
+		wcd9335_enable_master_bias(wcd);
+		/* get MCLK */
+		wcd9335_enable_mclk(wcd);
+
+	} else {
+		/* put MCLK */
+		wcd9335_disable_mclk(wcd);
+		/* put BG */
+		wcd9335_disable_master_bias(wcd);
+		clk_disable_unprepare(wcd->mclk);
+		wcd9335_cdc_sido_ccl_enable(wcd, false);
+	}
+err:
+	return ret;
+}
+
+static void wcd9335_codec_apply_sido_voltage(struct wcd9335_codec *wcd,
+					     enum wcd9335_sido_voltage req_mv)
+{
+	struct snd_soc_component *comp = wcd->component;
+	int vout_d_val;
+
+	if (req_mv == wcd->sido_voltage)
+		return;
+
+	/* compute the vout_d step value */
+	vout_d_val = WCD9335_CALCULATE_VOUT_D(req_mv) &
+			WCD9335_ANA_BUCK_VOUT_MASK;
+	snd_soc_component_write(comp, WCD9335_ANA_BUCK_VOUT_D, vout_d_val);
+	snd_soc_component_update_bits(comp, WCD9335_ANA_BUCK_CTL,
+				WCD9335_ANA_BUCK_CTL_RAMP_START_MASK,
+				WCD9335_ANA_BUCK_CTL_RAMP_START_ENABLE);
+
+	/* 1 msec sleep required after SIDO Vout_D voltage change */
+	usleep_range(1000, 1100);
+	wcd->sido_voltage = req_mv;
+	snd_soc_component_update_bits(comp, WCD9335_ANA_BUCK_CTL,
+				WCD9335_ANA_BUCK_CTL_RAMP_START_MASK,
+				WCD9335_ANA_BUCK_CTL_RAMP_START_DISABLE);
+}
+
+static int wcd9335_codec_update_sido_voltage(struct wcd9335_codec *wcd,
+					     enum wcd9335_sido_voltage req_mv)
+{
+	int ret = 0;
+
+	/* enable mclk before setting SIDO voltage */
+	ret = wcd9335_cdc_req_mclk_enable(wcd, true);
+	if (ret) {
+		dev_err(wcd->dev, "Ext clk enable failed\n");
+		goto err;
+	}
+
+	wcd9335_codec_apply_sido_voltage(wcd, req_mv);
+	wcd9335_cdc_req_mclk_enable(wcd, false);
+
+err:
+	return ret;
+}
+
+static int _wcd9335_codec_enable_mclk(struct snd_soc_component *component,
+				      int enable)
+{
+	struct wcd9335_codec *wcd = dev_get_drvdata(component->dev);
+	int ret;
+
+	if (enable) {
+		ret = wcd9335_cdc_req_mclk_enable(wcd, true);
+		if (ret)
+			return ret;
+
+		wcd9335_codec_apply_sido_voltage(wcd,
+				SIDO_VOLTAGE_NOMINAL_MV);
+	} else {
+		wcd9335_codec_update_sido_voltage(wcd,
+					wcd->sido_voltage);
+		wcd9335_cdc_req_mclk_enable(wcd, false);
+	}
+
+	return 0;
+}
+
+static void wcd9335_enable_sido_buck(struct snd_soc_component *component)
+{
+	struct wcd9335_codec *wcd = dev_get_drvdata(component->dev);
+
+	snd_soc_component_update_bits(component, WCD9335_ANA_RCO,
+					WCD9335_ANA_RCO_BG_EN_MASK,
+					WCD9335_ANA_RCO_BG_ENABLE);
+	snd_soc_component_update_bits(component, WCD9335_ANA_BUCK_CTL,
+					WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_MASK,
+					WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_EXT);
+	/* 100us sleep needed after IREF settings */
+	usleep_range(100, 110);
+	snd_soc_component_update_bits(component, WCD9335_ANA_BUCK_CTL,
+					WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_MASK,
+					WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_EXT);
+	/* 100us sleep needed after VREF settings */
+	usleep_range(100, 110);
+	wcd->sido_input_src = SIDO_SOURCE_RCO_BG;
+}
+
+static int wcd9335_enable_efuse_sensing(struct snd_soc_component *comp)
+{
+	_wcd9335_codec_enable_mclk(comp, true);
+	snd_soc_component_update_bits(comp,
+				WCD9335_CHIP_TIER_CTRL_EFUSE_CTL,
+				WCD9335_CHIP_TIER_CTRL_EFUSE_EN_MASK,
+				WCD9335_CHIP_TIER_CTRL_EFUSE_ENABLE);
+	/*
+	 * 5ms sleep required after enabling efuse control
+	 * before checking the status.
+	 */
+	usleep_range(5000, 5500);
+
+	if (!(snd_soc_component_read32(comp,
+					WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS) &
+					WCD9335_CHIP_TIER_CTRL_EFUSE_EN_MASK))
+		WARN(1, "%s: Efuse sense is not complete\n", __func__);
+
+	wcd9335_enable_sido_buck(comp);
+	_wcd9335_codec_enable_mclk(comp, false);
+
+	return 0;
+}
+
+static void wcd9335_codec_init(struct snd_soc_component *component)
+{
+	struct wcd9335_codec *wcd = dev_get_drvdata(component->dev);
+	int i;
+
+	/* ungate MCLK and set clk rate */
+	regmap_update_bits(wcd->regmap, WCD9335_CODEC_RPM_CLK_GATE,
+				WCD9335_CODEC_RPM_CLK_GATE_MCLK_GATE_MASK, 0);
+
+	regmap_update_bits(wcd->regmap, WCD9335_CODEC_RPM_CLK_MCLK_CFG,
+				WCD9335_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK,
+				WCD9335_CODEC_RPM_CLK_MCLK_CFG_9P6MHZ);
+
+	for (i = 0; i < ARRAY_SIZE(wcd9335_codec_reg_init); i++)
+		snd_soc_component_update_bits(component,
+					wcd9335_codec_reg_init[i].reg,
+					wcd9335_codec_reg_init[i].mask,
+					wcd9335_codec_reg_init[i].val);
+
+	wcd9335_enable_efuse_sensing(component);
+}
+
+static int wcd9335_codec_probe(struct snd_soc_component *component)
+{
+	struct wcd9335_codec *wcd = dev_get_drvdata(component->dev);
+	int i;
+
+	snd_soc_component_init_regmap(component, wcd->regmap);
+	wcd->component = component;
+
+	wcd9335_codec_init(component);
+
+	for (i = 0; i < NUM_CODEC_DAIS; i++)
+		INIT_LIST_HEAD(&wcd->dai[i].slim_ch_list);
+
+	return wcd9335_setup_irqs(wcd);
+}
+
+static void wcd9335_codec_remove(struct snd_soc_component *comp)
+{
+	struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev);
+
+	free_irq(regmap_irq_get_virq(wcd->irq_data, WCD9335_IRQ_SLIMBUS), wcd);
+}
+
+static int wcd9335_codec_set_sysclk(struct snd_soc_component *comp,
+				    int clk_id, int source,
+				    unsigned int freq, int dir)
+{
+	struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev);
+
+	wcd->mclk_rate = freq;
+
+	if (wcd->mclk_rate == WCD9335_MCLK_CLK_12P288MHZ)
+		snd_soc_component_update_bits(comp,
+				WCD9335_CODEC_RPM_CLK_MCLK_CFG,
+				WCD9335_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK,
+				WCD9335_CODEC_RPM_CLK_MCLK_CFG_12P288MHZ);
+	else if (wcd->mclk_rate == WCD9335_MCLK_CLK_9P6MHZ)
+		snd_soc_component_update_bits(comp,
+				WCD9335_CODEC_RPM_CLK_MCLK_CFG,
+				WCD9335_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK,
+				WCD9335_CODEC_RPM_CLK_MCLK_CFG_9P6MHZ);
+
+	return clk_set_rate(wcd->mclk, freq);
+}
+
+static const struct snd_soc_component_driver wcd9335_component_drv = {
+	.probe = wcd9335_codec_probe,
+	.remove = wcd9335_codec_remove,
+	.set_sysclk = wcd9335_codec_set_sysclk,
+};
+
+static int wcd9335_probe(struct platform_device *pdev)
+{
+	struct wcd9335 *pdata = dev_get_drvdata(pdev->dev.parent);
+	struct device *dev = &pdev->dev;
+	struct wcd9335_codec *wcd;
+
+	wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL);
+	if (!wcd)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev, wcd);
+
+	memcpy(wcd->rx_chs, wcd9335_rx_chs, sizeof(wcd9335_rx_chs));
+
+	wcd->regmap = pdata->regmap;
+	wcd->if_regmap = pdata->interface_dev_regmap;
+	wcd->slim = pdata->slim;
+	wcd->slim_interface_dev = pdata->slim_interface_dev;
+	wcd->irq_data = pdata->irq_data;
+	wcd->version = pdata->version;
+	wcd->intf_type = pdata->intf_type;
+	wcd->dev = dev;
+	wcd->mclk = pdata->mclk;
+	wcd->native_clk = pdata->native_clk;
+	wcd->sido_input_src = SIDO_SOURCE_INTERNAL;
+	wcd->sido_voltage = SIDO_VOLTAGE_NOMINAL_MV;
+
+	return devm_snd_soc_register_component(dev, &wcd9335_component_drv,
+					       wcd9335_slim_dais,
+					       ARRAY_SIZE(wcd9335_slim_dais));
+}
+
+static const struct platform_device_id wcd9335_driver_ids[] = {
+	{ .name = "wcd9335-codec", },
+	{},
+};
+MODULE_DEVICE_TABLE(platform, wcd9335_driver_ids);
+
+static struct platform_driver wcd9335_codec_driver = {
+	.probe = wcd9335_probe,
+	.id_table = wcd9335_driver_ids,
+	.driver = {
+		.name = "wcd9335-codec",
+	},
+};
+module_platform_driver(wcd9335_codec_driver);
+MODULE_DESCRIPTION("WCD9335 Codec driver");
+MODULE_LICENSE("GPL v2");
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v4 05/14] ASoC: wcd9335: add CLASS-H Controller support
  2018-09-17  0:57 [PATCH v4 00/14] ASoC: Add support to WCD9335 Audio Codec srinivas.kandagatla
                   ` (3 preceding siblings ...)
  2018-09-17  0:57 ` [PATCH v4 04/14] ASoC: wcd9335: add support to wcd9335 codec srinivas.kandagatla
@ 2018-09-17  0:57 ` srinivas.kandagatla
  2018-09-17  0:57 ` [PATCH v4 06/14] ASoC: wcd9335: add basic controls srinivas.kandagatla
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: srinivas.kandagatla @ 2018-09-17  0:57 UTC (permalink / raw)
  To: lee.jones, robh+dt, broonie
  Cc: mark.rutland, lgirdwood, bgoswami, devicetree, linux-kernel,
	vkoul, alsa-devel, Srinivas Kandagatla

From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

CLASS-H controller/Amplifier is common accorss Qualcomm WCD codec series.
This patchset adds basic CLASS-H controller apis for WCD codecs after
wcd9335 to use.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Reviewed-by: Vinod Koul <vkoul@kernel.org>
---
 sound/soc/codecs/Makefile      |   2 +-
 sound/soc/codecs/wcd-clsh-v2.c | 577 +++++++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/wcd-clsh-v2.h |  49 ++++
 sound/soc/codecs/wcd9335.c     |  10 +
 4 files changed, 637 insertions(+), 1 deletion(-)
 create mode 100644 sound/soc/codecs/wcd-clsh-v2.c
 create mode 100644 sound/soc/codecs/wcd-clsh-v2.h

diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 01410b6..847a2e5 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -192,7 +192,7 @@ snd-soc-twl4030-objs := twl4030.o
 snd-soc-twl6040-objs := twl6040.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
-snd-soc-wcd9335-objs := wcd9335.o
+snd-soc-wcd9335-objs := wcd-clsh-v2.o wcd9335.o
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm-adsp-objs := wm_adsp.o
 snd-soc-wm0010-objs := wm0010.o
diff --git a/sound/soc/codecs/wcd-clsh-v2.c b/sound/soc/codecs/wcd-clsh-v2.c
new file mode 100644
index 0000000..d5124bd
--- /dev/null
+++ b/sound/soc/codecs/wcd-clsh-v2.c
@@ -0,0 +1,577 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+// Copyright (c) 2017-2018, Linaro Limited
+
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/mfd/wcd9335/wcd9335.h>
+#include <linux/mfd/wcd9335/registers.h>
+#include "wcd-clsh-v2.h"
+
+struct wcd_clsh_ctrl {
+	int state;
+	int mode;
+	int flyback_users;
+	int buck_users;
+	int clsh_users;
+	int codec_version;
+	struct snd_soc_component *comp;
+};
+
+/* Class-H registers for codecs from and above WCD9335 */
+#define WCD9XXX_A_CDC_RX0_RX_PATH_CFG0			WCD9335_REG(0xB, 0x42)
+#define WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK		BIT(6)
+#define WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE		BIT(6)
+#define WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE		0
+#define WCD9XXX_A_CDC_RX1_RX_PATH_CFG0			WCD9335_REG(0xB, 0x56)
+#define WCD9XXX_A_CDC_RX2_RX_PATH_CFG0			WCD9335_REG(0xB, 0x6A)
+#define WCD9XXX_A_CDC_CLSH_K1_MSB			WCD9335_REG(0xC, 0x08)
+#define WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK		GENMASK(3, 0)
+#define WCD9XXX_A_CDC_CLSH_K1_LSB			WCD9335_REG(0xC, 0x09)
+#define WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK		GENMASK(7, 0)
+#define WCD9XXX_A_ANA_RX_SUPPLIES			WCD9335_REG(0x6, 0x08)
+#define WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK		BIT(1)
+#define WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H		0
+#define WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_AB		BIT(1)
+#define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK		BIT(2)
+#define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_UHQA		BIT(2)
+#define WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_DEFAULT		0
+#define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK		BIT(3)
+#define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_UHQA		BIT(3)
+#define WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT		0
+#define WCD9XXX_A_ANA_RX_VNEG_EN_MASK			BIT(6)
+#define WCD9XXX_A_ANA_RX_VNEG_EN_SHIFT			6
+#define WCD9XXX_A_ANA_RX_VNEG_ENABLE			BIT(6)
+#define WCD9XXX_A_ANA_RX_VNEG_DISABLE			0
+#define WCD9XXX_A_ANA_RX_VPOS_EN_MASK			BIT(7)
+#define WCD9XXX_A_ANA_RX_VPOS_EN_SHIFT			7
+#define WCD9XXX_A_ANA_RX_VPOS_ENABLE			BIT(7)
+#define WCD9XXX_A_ANA_RX_VPOS_DISABLE			0
+#define WCD9XXX_A_ANA_HPH				WCD9335_REG(0x6, 0x09)
+#define WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK		GENMASK(3, 2)
+#define WCD9XXX_A_ANA_HPH_PWR_LEVEL_UHQA		0x08
+#define WCD9XXX_A_ANA_HPH_PWR_LEVEL_LP			0x04
+#define WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL		0x0
+#define WCD9XXX_A_CDC_CLSH_CRC				WCD9335_REG(0xC, 0x01)
+#define WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK		BIT(0)
+#define WCD9XXX_A_CDC_CLSH_CRC_CLK_ENABLE		BIT(0)
+#define WCD9XXX_A_CDC_CLSH_CRC_CLK_DISABLE		0
+#define WCD9XXX_FLYBACK_EN				WCD9335_REG(0x6, 0xA4)
+#define WCD9XXX_FLYBACK_EN_DELAY_SEL_MASK		GENMASK(6, 5)
+#define WCD9XXX_FLYBACK_EN_DELAY_26P25_US		0x40
+#define WCD9XXX_FLYBACK_EN_RESET_BY_EXT_MASK		BIT(4)
+#define WCD9XXX_FLYBACK_EN_PWDN_WITHOUT_DELAY		BIT(4)
+#define WCD9XXX_FLYBACK_EN_PWDN_WITH_DELAY			0
+#define WCD9XXX_RX_BIAS_FLYB_BUFF			WCD9335_REG(0x6, 0xC7)
+#define WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK		GENMASK(7, 4)
+#define WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK		GENMASK(0, 3)
+#define WCD9XXX_HPH_L_EN				WCD9335_REG(0x6, 0xD3)
+#define WCD9XXX_HPH_CONST_SEL_L_MASK			GENMASK(7, 3)
+#define WCD9XXX_HPH_CONST_SEL_BYPASS			0
+#define WCD9XXX_HPH_CONST_SEL_LP_PATH			0x40
+#define WCD9XXX_HPH_CONST_SEL_HQ_PATH			0x80
+#define WCD9XXX_HPH_R_EN				WCD9335_REG(0x6, 0xD6)
+#define WCD9XXX_HPH_REFBUFF_UHQA_CTL			WCD9335_REG(0x6, 0xDD)
+#define WCD9XXX_HPH_REFBUFF_UHQA_GAIN_MASK		GENMASK(2, 0)
+#define WCD9XXX_CLASSH_CTRL_VCL_2                       WCD9335_REG(0x6, 0x9B)
+#define WCD9XXX_CLASSH_CTRL_VCL_2_VREF_FILT_1_MASK	GENMASK(5, 4)
+#define WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_50KOHM	0x20
+#define WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_0KOHM	0x0
+#define WCD9XXX_CDC_RX1_RX_PATH_CTL			WCD9335_REG(0xB, 0x55)
+#define WCD9XXX_CDC_RX2_RX_PATH_CTL			WCD9335_REG(0xB, 0x69)
+#define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_CONTROL		WCD9335_REG(0xD, 0x41)
+#define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_EN_MASK		BIT(0)
+#define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_11P3_EN_MASK	BIT(1)
+#define WCD9XXX_CLASSH_CTRL_CCL_1                       WCD9335_REG(0x6, 0x9C)
+#define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_MASK	GENMASK(7, 4)
+#define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA	0x50
+#define WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA	0x30
+
+#define CLSH_REQ_ENABLE		true
+#define CLSH_REQ_DISABLE	false
+#define WCD_USLEEP_RANGE	50
+
+enum {
+	DAC_GAIN_0DB = 0,
+	DAC_GAIN_0P2DB,
+	DAC_GAIN_0P4DB,
+	DAC_GAIN_0P6DB,
+	DAC_GAIN_0P8DB,
+	DAC_GAIN_M0P2DB,
+	DAC_GAIN_M0P4DB,
+	DAC_GAIN_M0P6DB,
+};
+
+static inline void wcd_enable_clsh_block(struct wcd_clsh_ctrl *ctrl,
+					 bool enable)
+{
+	struct snd_soc_component *comp = ctrl->comp;
+
+	if ((enable && ++ctrl->clsh_users == 1) ||
+	    (!enable && --ctrl->clsh_users == 0))
+		snd_soc_component_update_bits(comp, WCD9XXX_A_CDC_CLSH_CRC,
+				      WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK,
+				      enable);
+	if (ctrl->clsh_users < 0)
+		ctrl->clsh_users = 0;
+}
+
+static inline bool wcd_clsh_enable_status(struct snd_soc_component *comp)
+{
+	return snd_soc_component_read32(comp, WCD9XXX_A_CDC_CLSH_CRC) &
+					WCD9XXX_A_CDC_CLSH_CRC_CLK_EN_MASK;
+}
+
+static inline void wcd_clsh_set_buck_mode(struct snd_soc_component *comp,
+					  int mode)
+{
+	/* set to HIFI */
+	if (mode == CLS_H_HIFI)
+		snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
+					WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK,
+					WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_UHQA);
+	else
+		snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
+					WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_MASK,
+					WCD9XXX_A_ANA_RX_VPOS_PWR_LVL_DEFAULT);
+}
+
+static inline void wcd_clsh_set_flyback_mode(struct snd_soc_component *comp,
+					     int mode)
+{
+	/* set to HIFI */
+	if (mode == CLS_H_HIFI)
+		snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
+					WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK,
+					WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_UHQA);
+	else
+		snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
+					WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_MASK,
+					WCD9XXX_A_ANA_RX_VNEG_PWR_LVL_DEFAULT);
+}
+
+static void wcd_clsh_buck_ctrl(struct wcd_clsh_ctrl *ctrl,
+			       int mode,
+			       bool enable)
+{
+	struct snd_soc_component *comp = ctrl->comp;
+
+	/* enable/disable buck */
+	if ((enable && (++ctrl->buck_users == 1)) ||
+	   (!enable && (--ctrl->buck_users == 0)))
+		snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
+				WCD9XXX_A_ANA_RX_VPOS_EN_MASK,
+				enable << WCD9XXX_A_ANA_RX_VPOS_EN_SHIFT);
+	/*
+	 * 500us sleep is required after buck enable/disable
+	 * 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)
+{
+	struct snd_soc_component *comp = ctrl->comp;
+
+	/* enable/disable flyback */
+	if ((enable && (++ctrl->flyback_users == 1)) ||
+	   (!enable && (--ctrl->flyback_users == 0))) {
+		snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
+				WCD9XXX_A_ANA_RX_VNEG_EN_MASK,
+				enable << WCD9XXX_A_ANA_RX_VNEG_EN_SHIFT);
+		/* 100usec delay is needed as per HW requirement */
+		usleep_range(100, 110);
+	}
+	/*
+	 * 500us sleep is required after flyback enable/disable
+	 * as per HW requirement
+	 */
+	usleep_range(500, 500 + WCD_USLEEP_RANGE);
+}
+
+static void wcd_clsh_set_gain_path(struct wcd_clsh_ctrl *ctrl, int mode)
+{
+	struct snd_soc_component *comp = ctrl->comp;
+	int val = 0;
+
+	switch (mode) {
+	case CLS_H_NORMAL:
+	case CLS_AB:
+		val = WCD9XXX_HPH_CONST_SEL_BYPASS;
+		break;
+	case CLS_H_HIFI:
+		val = WCD9XXX_HPH_CONST_SEL_HQ_PATH;
+		break;
+	case CLS_H_LP:
+		val = WCD9XXX_HPH_CONST_SEL_LP_PATH;
+		break;
+	};
+
+	snd_soc_component_update_bits(comp, WCD9XXX_HPH_L_EN,
+					WCD9XXX_HPH_CONST_SEL_L_MASK,
+					val);
+
+	snd_soc_component_update_bits(comp, WCD9XXX_HPH_R_EN,
+					WCD9XXX_HPH_CONST_SEL_L_MASK,
+					val);
+}
+
+static void wcd_clsh_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;
+
+	res_val = WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_0KOHM;
+	switch (mode) {
+	case CLS_H_NORMAL:
+		res_val = WCD9XXX_CLASSH_CTRL_VCL_VREF_FILT_R_50KOHM;
+		val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL;
+		gain = DAC_GAIN_0DB;
+		ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA;
+		break;
+	case CLS_AB:
+		val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_NORMAL;
+		gain = DAC_GAIN_0DB;
+		ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA;
+		break;
+	case CLS_H_HIFI:
+		val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_UHQA;
+		gain = DAC_GAIN_M0P2DB;
+		ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_50MA;
+		break;
+	case CLS_H_LP:
+		val = WCD9XXX_A_ANA_HPH_PWR_LEVEL_LP;
+		ipeak = WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_30MA;
+		break;
+	};
+
+	snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_HPH,
+					WCD9XXX_A_ANA_HPH_PWR_LEVEL_MASK, val);
+	snd_soc_component_update_bits(comp, WCD9XXX_CLASSH_CTRL_VCL_2,
+				WCD9XXX_CLASSH_CTRL_VCL_2_VREF_FILT_1_MASK,
+				res_val);
+	if (mode != CLS_H_LP)
+		snd_soc_component_update_bits(comp,
+					WCD9XXX_HPH_REFBUFF_UHQA_CTL,
+					WCD9XXX_HPH_REFBUFF_UHQA_GAIN_MASK,
+					gain);
+	snd_soc_component_update_bits(comp, WCD9XXX_CLASSH_CTRL_CCL_1,
+				WCD9XXX_CLASSH_CTRL_CCL_1_DELTA_IPEAK_MASK,
+				ipeak);
+}
+
+static void wcd_clsh_set_flyback_current(struct snd_soc_component *comp,
+					 int mode)
+{
+
+	snd_soc_component_update_bits(comp, WCD9XXX_RX_BIAS_FLYB_BUFF,
+				WCD9XXX_RX_BIAS_FLYB_VPOS_5_UA_MASK, 0x0A);
+	snd_soc_component_update_bits(comp, WCD9XXX_RX_BIAS_FLYB_BUFF,
+				WCD9XXX_RX_BIAS_FLYB_VNEG_5_UA_MASK, 0x0A);
+	/* Sleep needed to avoid click and pop as per HW requirement */
+	usleep_range(100, 110);
+}
+
+static void wcd_clsh_set_buck_regulator_mode(struct snd_soc_component *comp,
+					     int mode)
+{
+	if (mode == CLS_AB)
+		snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
+					WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK,
+					WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_AB);
+	else
+		snd_soc_component_update_bits(comp, WCD9XXX_A_ANA_RX_SUPPLIES,
+					WCD9XXX_A_ANA_RX_REGULATOR_MODE_MASK,
+					WCD9XXX_A_ANA_RX_REGULATOR_MODE_CLS_H);
+}
+
+static void wcd_clsh_state_lo(struct wcd_clsh_ctrl *ctrl, int req_state,
+			      bool is_enable, int mode)
+{
+	struct snd_soc_component *comp = ctrl->comp;
+
+	if (mode != CLS_AB) {
+		dev_err(comp->dev, "%s: LO cannot be in this mode: %d\n",
+			__func__, mode);
+		return;
+	}
+
+	if (is_enable) {
+		wcd_clsh_set_buck_regulator_mode(comp, mode);
+		wcd_clsh_set_buck_mode(comp, mode);
+		wcd_clsh_set_flyback_mode(comp, mode);
+		wcd_clsh_flyback_ctrl(ctrl, mode, true);
+		wcd_clsh_set_flyback_current(comp, mode);
+		wcd_clsh_buck_ctrl(ctrl, mode, true);
+	} else {
+		wcd_clsh_buck_ctrl(ctrl, mode, false);
+		wcd_clsh_flyback_ctrl(ctrl, mode, false);
+		wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL);
+		wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL);
+		wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL);
+	}
+}
+
+static void wcd_clsh_state_hph_r(struct wcd_clsh_ctrl *ctrl, int req_state,
+				 bool is_enable, int mode)
+{
+	struct snd_soc_component *comp = ctrl->comp;
+
+	if (mode == CLS_H_NORMAL) {
+		dev_err(comp->dev, "%s: Normal mode not applicable for hph_r\n",
+			__func__);
+		return;
+	}
+
+	if (is_enable) {
+		if (mode != CLS_AB) {
+			wcd_enable_clsh_block(ctrl, true);
+			/*
+			 * These K1 values depend on the Headphone Impedance
+			 * For now it is assumed to be 16 ohm
+			 */
+			snd_soc_component_update_bits(comp,
+					WCD9XXX_A_CDC_CLSH_K1_MSB,
+					WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK,
+					0x00);
+			snd_soc_component_update_bits(comp,
+					WCD9XXX_A_CDC_CLSH_K1_LSB,
+					WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK,
+					0xC0);
+			snd_soc_component_update_bits(comp,
+					    WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
+					    WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
+					    WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE);
+		}
+		wcd_clsh_set_buck_regulator_mode(comp, mode);
+		wcd_clsh_set_flyback_mode(comp, mode);
+		wcd_clsh_flyback_ctrl(ctrl, mode, true);
+		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_set_gain_path(ctrl, mode);
+	} else {
+		wcd_clsh_set_hph_mode(comp, CLS_H_NORMAL);
+
+		if (mode != CLS_AB) {
+			snd_soc_component_update_bits(comp,
+					    WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
+					    WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
+					    WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE);
+			wcd_enable_clsh_block(ctrl, false);
+		}
+		/* buck and flyback set to default mode and disable */
+		wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false);
+		wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false);
+		wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL);
+		wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL);
+		wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL);
+	}
+}
+
+static void wcd_clsh_state_hph_l(struct wcd_clsh_ctrl *ctrl, int req_state,
+				 bool is_enable, int mode)
+{
+	struct snd_soc_component *comp = ctrl->comp;
+
+	if (mode == CLS_H_NORMAL) {
+		dev_err(comp->dev, "%s: Normal mode not applicable for hph_l\n",
+			__func__);
+		return;
+	}
+
+	if (is_enable) {
+		if (mode != CLS_AB) {
+			wcd_enable_clsh_block(ctrl, true);
+			/*
+			 * These K1 values depend on the Headphone Impedance
+			 * For now it is assumed to be 16 ohm
+			 */
+			snd_soc_component_update_bits(comp,
+					WCD9XXX_A_CDC_CLSH_K1_MSB,
+					WCD9XXX_A_CDC_CLSH_K1_MSB_COEF_MASK,
+					0x00);
+			snd_soc_component_update_bits(comp,
+					WCD9XXX_A_CDC_CLSH_K1_LSB,
+					WCD9XXX_A_CDC_CLSH_K1_LSB_COEF_MASK,
+					0xC0);
+			snd_soc_component_update_bits(comp,
+					    WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
+					    WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
+					    WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE);
+		}
+		wcd_clsh_set_buck_regulator_mode(comp, mode);
+		wcd_clsh_set_flyback_mode(comp, mode);
+		wcd_clsh_flyback_ctrl(ctrl, mode, true);
+		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_set_gain_path(ctrl, mode);
+	} else {
+		wcd_clsh_set_hph_mode(comp, CLS_H_NORMAL);
+
+		if (mode != CLS_AB) {
+			snd_soc_component_update_bits(comp,
+					    WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
+					    WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
+					    WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE);
+			wcd_enable_clsh_block(ctrl, false);
+		}
+		/* set buck and flyback to Default Mode */
+		wcd_clsh_buck_ctrl(ctrl, CLS_H_NORMAL, false);
+		wcd_clsh_flyback_ctrl(ctrl, CLS_H_NORMAL, false);
+		wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL);
+		wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL);
+		wcd_clsh_set_buck_regulator_mode(comp, CLS_H_NORMAL);
+	}
+}
+
+static void wcd_clsh_state_ear(struct wcd_clsh_ctrl *ctrl, int req_state,
+			       bool is_enable, int mode)
+{
+	struct snd_soc_component *comp = ctrl->comp;
+
+	if (mode != CLS_H_NORMAL) {
+		dev_err(comp->dev, "%s: mode: %d cannot be used for EAR\n",
+			__func__, mode);
+		return;
+	}
+
+	if (is_enable) {
+		wcd_enable_clsh_block(ctrl, true);
+		snd_soc_component_update_bits(comp,
+					WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+					WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
+					WCD9XXX_A_CDC_RX_PATH_CLSH_ENABLE);
+		wcd_clsh_set_buck_mode(comp, mode);
+		wcd_clsh_set_flyback_mode(comp, mode);
+		wcd_clsh_flyback_ctrl(ctrl, mode, true);
+		wcd_clsh_set_flyback_current(comp, mode);
+		wcd_clsh_buck_ctrl(ctrl, mode, true);
+	} else {
+		snd_soc_component_update_bits(comp,
+					WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+					WCD9XXX_A_CDC_RX_PATH_CLSH_EN_MASK,
+					WCD9XXX_A_CDC_RX_PATH_CLSH_DISABLE);
+		wcd_enable_clsh_block(ctrl, false);
+		wcd_clsh_buck_ctrl(ctrl, mode, false);
+		wcd_clsh_flyback_ctrl(ctrl, mode, false);
+		wcd_clsh_set_flyback_mode(comp, CLS_H_NORMAL);
+		wcd_clsh_set_buck_mode(comp, CLS_H_NORMAL);
+	}
+}
+
+static int _wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl, int req_state,
+				    bool is_enable, int mode)
+{
+	switch (req_state) {
+	case WCD_CLSH_STATE_EAR:
+		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);
+		break;
+	case WCD_CLSH_STATE_HPHR:
+		wcd_clsh_state_hph_r(ctrl, req_state, is_enable, mode);
+		break;
+		break;
+	case WCD_CLSH_STATE_LO:
+		wcd_clsh_state_lo(ctrl, req_state, is_enable, mode);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * Function: wcd_clsh_is_state_valid
+ * Params: state
+ * Description:
+ * Provides information on valid states of Class H configuration
+ */
+static bool wcd_clsh_is_state_valid(int state)
+{
+	switch (state) {
+	case WCD_CLSH_STATE_IDLE:
+	case WCD_CLSH_STATE_EAR:
+	case WCD_CLSH_STATE_HPHL:
+	case WCD_CLSH_STATE_HPHR:
+	case WCD_CLSH_STATE_LO:
+		return true;
+	default:
+		return false;
+	};
+}
+
+/*
+ * Function: wcd_clsh_fsm
+ * Params: ctrl, req_state, req_type, clsh_event
+ * Description:
+ * This function handles PRE DAC and POST DAC conditions of different devices
+ * and updates class H configuration of different combination of devices
+ * based on validity of their states. ctrl will contain current
+ * class h state information
+ */
+int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl,
+			    enum wcd_clsh_event clsh_event,
+			    int nstate,
+			    enum wcd_clsh_mode mode)
+{
+	struct snd_soc_component *comp = ctrl->comp;
+
+	if (nstate == ctrl->state)
+		return 0;
+
+	if (!wcd_clsh_is_state_valid(nstate)) {
+		dev_err(comp->dev, "Class-H not a valid new state:\n");
+		return -EINVAL;
+	}
+
+	switch (clsh_event) {
+	case WCD_CLSH_EVENT_PRE_DAC:
+		_wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_ENABLE, mode);
+		break;
+	case WCD_CLSH_EVENT_POST_PA:
+		_wcd_clsh_ctrl_set_state(ctrl, nstate, CLSH_REQ_DISABLE, mode);
+		break;
+	};
+
+	ctrl->state = nstate;
+	ctrl->mode = mode;
+
+	return 0;
+}
+
+int wcd_clsh_ctrl_get_state(struct wcd_clsh_ctrl *ctrl)
+{
+	return ctrl->state;
+}
+
+struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc(struct snd_soc_component *comp,
+					  int version)
+{
+	struct wcd_clsh_ctrl *ctrl;
+
+	ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
+	if (!ctrl)
+		return ERR_PTR(-ENOMEM);
+
+	ctrl->state = WCD_CLSH_STATE_IDLE;
+	ctrl->comp = comp;
+
+	return ctrl;
+}
+
+void wcd_clsh_ctrl_free(struct wcd_clsh_ctrl *ctrl)
+{
+	kfree(ctrl);
+}
diff --git a/sound/soc/codecs/wcd-clsh-v2.h b/sound/soc/codecs/wcd-clsh-v2.h
new file mode 100644
index 0000000..a902f98
--- /dev/null
+++ b/sound/soc/codecs/wcd-clsh-v2.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _WCD_CLSH_V2_H_
+#define _WCD_CLSH_V2_H_
+#include <sound/soc.h>
+
+enum wcd_clsh_event {
+	WCD_CLSH_EVENT_PRE_DAC = 1,
+	WCD_CLSH_EVENT_POST_PA,
+};
+
+/*
+ * Basic states for Class H state machine.
+ * represented as a bit mask within a u8 data type
+ * bit 0: EAR mode
+ * bit 1: HPH Left mode
+ * bit 2: HPH Right mode
+ * bit 3: Lineout mode
+ */
+#define	WCD_CLSH_STATE_IDLE	0
+#define	WCD_CLSH_STATE_EAR	BIT(0)
+#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_MAX	4
+#define NUM_CLSH_STATES_V2	BIT(WCD_CLSH_STATE_MAX)
+
+enum wcd_clsh_mode {
+	CLS_H_NORMAL = 0, /* Class-H Default */
+	CLS_H_HIFI, /* Class-H HiFi */
+	CLS_H_LP, /* Class-H Low Power */
+	CLS_AB, /* Class-AB */
+	CLS_H_LOHIFI, /* LoHIFI */
+	CLS_NONE, /* None of the above modes */
+};
+
+struct wcd_clsh_ctrl;
+
+extern struct wcd_clsh_ctrl *wcd_clsh_ctrl_alloc(
+				struct snd_soc_component *component,
+				int version);
+extern void wcd_clsh_ctrl_free(struct wcd_clsh_ctrl *ctrl);
+extern int wcd_clsh_ctrl_get_state(struct wcd_clsh_ctrl *ctrl);
+extern int wcd_clsh_ctrl_set_state(struct wcd_clsh_ctrl *ctrl,
+				   enum wcd_clsh_event event,
+				   int state,
+				   enum wcd_clsh_mode mode);
+
+#endif /* _WCD_CLSH_V2_H_ */
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 764c844..98e1860 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -20,6 +20,7 @@
 #include <sound/info.h>
 #include <linux/mfd/wcd9335/wcd9335.h>
 #include <linux/mfd/wcd9335/registers.h>
+#include "wcd-clsh-v2.h"
 
 #define WCD9335_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
 			    SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
@@ -180,6 +181,7 @@ struct wcd9335_codec {
 	int sido_ccl_cnt;
 	enum wcd_clock_type clk_type;
 
+	struct wcd_clsh_ctrl *clsh_ctrl;
 	u32 hph_mode;
 };
 
@@ -1082,6 +1084,13 @@ static int wcd9335_codec_probe(struct snd_soc_component *component)
 	int i;
 
 	snd_soc_component_init_regmap(component, wcd->regmap);
+	/* Class-H Init*/
+	wcd->clsh_ctrl = wcd_clsh_ctrl_alloc(component, wcd->version);
+	if (IS_ERR(wcd->clsh_ctrl))
+		return PTR_ERR(wcd->clsh_ctrl);
+
+	/* Default HPH Mode to Class-H HiFi */
+	wcd->hph_mode = CLS_H_HIFI;
 	wcd->component = component;
 
 	wcd9335_codec_init(component);
@@ -1096,6 +1105,7 @@ static void wcd9335_codec_remove(struct snd_soc_component *comp)
 {
 	struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev);
 
+	wcd_clsh_ctrl_free(wcd->clsh_ctrl);
 	free_irq(regmap_irq_get_virq(wcd->irq_data, WCD9335_IRQ_SLIMBUS), wcd);
 }
 
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v4 06/14] ASoC: wcd9335: add basic controls
  2018-09-17  0:57 [PATCH v4 00/14] ASoC: Add support to WCD9335 Audio Codec srinivas.kandagatla
                   ` (4 preceding siblings ...)
  2018-09-17  0:57 ` [PATCH v4 05/14] ASoC: wcd9335: add CLASS-H Controller support srinivas.kandagatla
@ 2018-09-17  0:57 ` srinivas.kandagatla
  2018-09-17  0:57 ` [PATCH v4 07/14] ASoC: wcd9335: add playback dapm widgets srinivas.kandagatla
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: srinivas.kandagatla @ 2018-09-17  0:57 UTC (permalink / raw)
  To: lee.jones, robh+dt, broonie
  Cc: mark.rutland, lgirdwood, bgoswami, devicetree, linux-kernel,
	vkoul, alsa-devel, Srinivas Kandagatla

From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

This patch adds basic controls found in wcd9335 codec.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Reviewed-by: Vinod Koul <vkoul@kernel.org>
---
 sound/soc/codecs/wcd9335.c | 358 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 358 insertions(+)

diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 98e1860..a5cd663 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -104,6 +104,18 @@ enum {
 };
 
 enum {
+	COMPANDER_1, /* HPH_L */
+	COMPANDER_2, /* HPH_R */
+	COMPANDER_3, /* LO1_DIFF */
+	COMPANDER_4, /* LO2_DIFF */
+	COMPANDER_5, /* LO3_SE */
+	COMPANDER_6, /* LO4_SE */
+	COMPANDER_7, /* SWR SPK CH1 */
+	COMPANDER_8, /* SWR SPK CH2 */
+	COMPANDER_MAX,
+};
+
+enum {
 	INTn_2_INP_SEL_ZERO = 0,
 	INTn_2_INP_SEL_RX0,
 	INTn_2_INP_SEL_RX1,
@@ -183,6 +195,7 @@ struct wcd9335_codec {
 
 	struct wcd_clsh_ctrl *clsh_ctrl;
 	u32 hph_mode;
+	int comp_enabled[COMPANDER_MAX];
 };
 
 struct wcd9335_irq {
@@ -297,6 +310,118 @@ static const struct wcd9335_reg_mask_val wcd9335_codec_reg_init[] = {
 	{WCD9335_HPH_REFBUFF_LP_CTL, 0x06, 0x02},
 };
 
+/* Cutoff frequency for high pass filter */
+static const char * const cf_text[] = {
+	"CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ"
+};
+
+static const char * const rx_cf_text[] = {
+	"CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ",
+	"CF_NEG_3DB_0P48HZ"
+};
+
+static const char * const wcd9335_ear_pa_gain_text[] = {
+	"G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB",
+	"G_0_DB", "G_M2P5_DB", "UNDEFINED", "G_M12_DB"
+};
+
+static const char * const rx_hph_mode_mux_text[] = {
+	"CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", "CLS_H_LOHIFI"
+};
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
+static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+
+static const struct soc_enum wcd9335_ear_pa_gain_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wcd9335_ear_pa_gain_text),
+			wcd9335_ear_pa_gain_text);
+
+static const struct soc_enum cf_dec0_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX0_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX1_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec2_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX2_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec3_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX3_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec4_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX4_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec5_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX5_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec6_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX6_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec7_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX7_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_dec8_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX8_TX_PATH_CFG0, 5, 3, cf_text);
+
+static const struct soc_enum cf_int0_1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX0_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int0_2_enum, WCD9335_CDC_RX0_RX_PATH_MIX_CFG, 2,
+		     rx_cf_text);
+
+static const struct soc_enum cf_int1_1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX1_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int1_2_enum, WCD9335_CDC_RX1_RX_PATH_MIX_CFG, 2,
+		     rx_cf_text);
+
+static const struct soc_enum cf_int2_1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX2_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int2_2_enum, WCD9335_CDC_RX2_RX_PATH_MIX_CFG, 2,
+		     rx_cf_text);
+
+static const struct soc_enum cf_int3_1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX3_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int3_2_enum, WCD9335_CDC_RX3_RX_PATH_MIX_CFG, 2,
+		     rx_cf_text);
+
+static const struct soc_enum cf_int4_1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX4_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int4_2_enum, WCD9335_CDC_RX4_RX_PATH_MIX_CFG, 2,
+		     rx_cf_text);
+
+static const struct soc_enum cf_int5_1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX5_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int5_2_enum, WCD9335_CDC_RX5_RX_PATH_MIX_CFG, 2,
+		     rx_cf_text);
+
+static const struct soc_enum cf_int6_1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX6_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int6_2_enum, WCD9335_CDC_RX6_RX_PATH_MIX_CFG, 2,
+		     rx_cf_text);
+
+static const struct soc_enum cf_int7_1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX7_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int7_2_enum, WCD9335_CDC_RX7_RX_PATH_MIX_CFG, 2,
+		     rx_cf_text);
+
+static const struct soc_enum cf_int8_1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX8_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int8_2_enum, WCD9335_CDC_RX8_RX_PATH_MIX_CFG, 2,
+		     rx_cf_text);
+
+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 int wcd9335_set_mix_interpolator_rate(struct snd_soc_dai *dai,
 					     int rate_val,
 					     u32 rate)
@@ -675,6 +800,237 @@ static struct snd_soc_dai_driver wcd9335_slim_dais[] = {
 	},
 };
 
+static int wcd9335_get_compander(struct snd_kcontrol *kc,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kc);
+	int comp = ((struct soc_mixer_control *)kc->private_value)->shift;
+	struct wcd9335_codec *wcd = dev_get_drvdata(component->dev);
+
+	ucontrol->value.integer.value[0] = wcd->comp_enabled[comp];
+	return 0;
+}
+
+static int wcd9335_set_compander(struct snd_kcontrol *kc,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kc);
+	struct wcd9335_codec *wcd = dev_get_drvdata(component->dev);
+	int comp = ((struct soc_mixer_control *) kc->private_value)->shift;
+	int value = ucontrol->value.integer.value[0];
+	int sel;
+
+	wcd->comp_enabled[comp] = value;
+	sel = value ? WCD9335_HPH_GAIN_SRC_SEL_COMPANDER :
+		WCD9335_HPH_GAIN_SRC_SEL_REGISTER;
+
+	/* Any specific register configuration for compander */
+	switch (comp) {
+	case COMPANDER_1:
+		/* Set Gain Source Select based on compander enable/disable */
+		snd_soc_component_update_bits(component, WCD9335_HPH_L_EN,
+				      WCD9335_HPH_GAIN_SRC_SEL_MASK, sel);
+		break;
+	case COMPANDER_2:
+		snd_soc_component_update_bits(component, WCD9335_HPH_R_EN,
+				      WCD9335_HPH_GAIN_SRC_SEL_MASK, sel);
+		break;
+	case COMPANDER_5:
+		snd_soc_component_update_bits(component, WCD9335_SE_LO_LO3_GAIN,
+				      WCD9335_HPH_GAIN_SRC_SEL_MASK, sel);
+		break;
+	case COMPANDER_6:
+		snd_soc_component_update_bits(component, WCD9335_SE_LO_LO4_GAIN,
+				      WCD9335_HPH_GAIN_SRC_SEL_MASK, sel);
+		break;
+	default:
+		break;
+	};
+
+	return 0;
+}
+
+static int wcd9335_rx_hph_mode_get(struct snd_kcontrol *kc,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kc);
+	struct wcd9335_codec *wcd = dev_get_drvdata(component->dev);
+
+	ucontrol->value.enumerated.item[0] = wcd->hph_mode;
+
+	return 0;
+}
+
+static int wcd9335_rx_hph_mode_put(struct snd_kcontrol *kc,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kc);
+	struct wcd9335_codec *wcd = dev_get_drvdata(component->dev);
+	u32 mode_val;
+
+	mode_val = ucontrol->value.enumerated.item[0];
+
+	if (mode_val == 0) {
+		dev_err(wcd->dev, "Invalid HPH Mode, default to ClSH HiFi\n");
+		mode_val = CLS_H_HIFI;
+	}
+	wcd->hph_mode = mode_val;
+
+	return 0;
+}
+
+static int wcd9335_ear_pa_gain_get(struct snd_kcontrol *kc,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kc);
+	int ear_pa_gain;
+
+	ear_pa_gain = snd_soc_component_read32(component, WCD9335_ANA_EAR);
+	ear_pa_gain = (ear_pa_gain & 0x70) >> 4;
+	ucontrol->value.enumerated.item[0] = ear_pa_gain;
+
+	return 0;
+}
+
+static int wcd9335_ear_pa_gain_put(struct snd_kcontrol *kc,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_soc_kcontrol_component(kc);
+	u8 ear_pa_gain;
+
+	ear_pa_gain =  ucontrol->value.enumerated.item[0] << 4;
+	snd_soc_component_update_bits(component, WCD9335_ANA_EAR,
+					0x70, ear_pa_gain);
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new wcd9335_snd_controls[] = {
+	/* -84dB min - 40dB max */
+	SOC_SINGLE_SX_TLV("RX0 Digital Volume", WCD9335_CDC_RX0_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX1 Digital Volume", WCD9335_CDC_RX1_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX2 Digital Volume", WCD9335_CDC_RX2_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX3 Digital Volume", WCD9335_CDC_RX3_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX4 Digital Volume", WCD9335_CDC_RX4_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX5 Digital Volume", WCD9335_CDC_RX5_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX6 Digital Volume", WCD9335_CDC_RX6_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX7 Digital Volume", WCD9335_CDC_RX7_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX8 Digital Volume", WCD9335_CDC_RX8_RX_VOL_CTL,
+		0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX0 Mix Digital Volume",
+			  WCD9335_CDC_RX0_RX_VOL_MIX_CTL,
+			  0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX1 Mix Digital Volume",
+			  WCD9335_CDC_RX1_RX_VOL_MIX_CTL,
+			  0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX2 Mix Digital Volume",
+			  WCD9335_CDC_RX2_RX_VOL_MIX_CTL,
+			  0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX3 Mix Digital Volume",
+			  WCD9335_CDC_RX3_RX_VOL_MIX_CTL,
+			  0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX4 Mix Digital Volume",
+			  WCD9335_CDC_RX4_RX_VOL_MIX_CTL,
+			  0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX5 Mix Digital Volume",
+			  WCD9335_CDC_RX5_RX_VOL_MIX_CTL,
+			  0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX6 Mix Digital Volume",
+			  WCD9335_CDC_RX6_RX_VOL_MIX_CTL,
+			  0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX7 Mix Digital Volume",
+			  WCD9335_CDC_RX7_RX_VOL_MIX_CTL,
+			  0, -84, 40, digital_gain),
+	SOC_SINGLE_SX_TLV("RX8 Mix Digital Volume",
+			  WCD9335_CDC_RX8_RX_VOL_MIX_CTL,
+			  0, -84, 40, digital_gain),
+	SOC_ENUM("RX INT0_1 HPF cut off", cf_int0_1_enum),
+	SOC_ENUM("RX INT0_2 HPF cut off", cf_int0_2_enum),
+	SOC_ENUM("RX INT1_1 HPF cut off", cf_int1_1_enum),
+	SOC_ENUM("RX INT1_2 HPF cut off", cf_int1_2_enum),
+	SOC_ENUM("RX INT2_1 HPF cut off", cf_int2_1_enum),
+	SOC_ENUM("RX INT2_2 HPF cut off", cf_int2_2_enum),
+	SOC_ENUM("RX INT3_1 HPF cut off", cf_int3_1_enum),
+	SOC_ENUM("RX INT3_2 HPF cut off", cf_int3_2_enum),
+	SOC_ENUM("RX INT4_1 HPF cut off", cf_int4_1_enum),
+	SOC_ENUM("RX INT4_2 HPF cut off", cf_int4_2_enum),
+	SOC_ENUM("RX INT5_1 HPF cut off", cf_int5_1_enum),
+	SOC_ENUM("RX INT5_2 HPF cut off", cf_int5_2_enum),
+	SOC_ENUM("RX INT6_1 HPF cut off", cf_int6_1_enum),
+	SOC_ENUM("RX INT6_2 HPF cut off", cf_int6_2_enum),
+	SOC_ENUM("RX INT7_1 HPF cut off", cf_int7_1_enum),
+	SOC_ENUM("RX INT7_2 HPF cut off", cf_int7_2_enum),
+	SOC_ENUM("RX INT8_1 HPF cut off", cf_int8_1_enum),
+	SOC_ENUM("RX INT8_2 HPF cut off", cf_int8_2_enum),
+	SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0,
+		       wcd9335_get_compander, wcd9335_set_compander),
+	SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0,
+		       wcd9335_get_compander, wcd9335_set_compander),
+	SOC_SINGLE_EXT("COMP3 Switch", SND_SOC_NOPM, COMPANDER_3, 1, 0,
+		       wcd9335_get_compander, wcd9335_set_compander),
+	SOC_SINGLE_EXT("COMP4 Switch", SND_SOC_NOPM, COMPANDER_4, 1, 0,
+		       wcd9335_get_compander, wcd9335_set_compander),
+	SOC_SINGLE_EXT("COMP5 Switch", SND_SOC_NOPM, COMPANDER_5, 1, 0,
+		       wcd9335_get_compander, wcd9335_set_compander),
+	SOC_SINGLE_EXT("COMP6 Switch", SND_SOC_NOPM, COMPANDER_6, 1, 0,
+		       wcd9335_get_compander, wcd9335_set_compander),
+	SOC_SINGLE_EXT("COMP7 Switch", SND_SOC_NOPM, COMPANDER_7, 1, 0,
+		       wcd9335_get_compander, wcd9335_set_compander),
+	SOC_SINGLE_EXT("COMP8 Switch", SND_SOC_NOPM, COMPANDER_8, 1, 0,
+		       wcd9335_get_compander, wcd9335_set_compander),
+	SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum,
+		       wcd9335_rx_hph_mode_get, wcd9335_rx_hph_mode_put),
+
+	/* Gain Controls */
+	SOC_ENUM_EXT("EAR PA Gain", wcd9335_ear_pa_gain_enum,
+		wcd9335_ear_pa_gain_get, wcd9335_ear_pa_gain_put),
+
+	SOC_SINGLE_TLV("HPHL Volume", WCD9335_HPH_L_EN, 0, 20, 1,
+		line_gain),
+	SOC_SINGLE_TLV("HPHR Volume", WCD9335_HPH_R_EN, 0, 20, 1,
+		line_gain),
+	SOC_SINGLE_TLV("LINEOUT1 Volume", WCD9335_DIFF_LO_LO1_COMPANDER,
+			3, 16, 1, line_gain),
+	SOC_SINGLE_TLV("LINEOUT2 Volume", WCD9335_DIFF_LO_LO2_COMPANDER,
+			3, 16, 1, line_gain),
+	SOC_SINGLE_TLV("LINEOUT3 Volume", WCD9335_SE_LO_LO3_GAIN, 0, 20, 1,
+			line_gain),
+	SOC_SINGLE_TLV("LINEOUT4 Volume", WCD9335_SE_LO_LO4_GAIN, 0, 20, 1,
+			line_gain),
+
+	SOC_SINGLE_TLV("ADC1 Volume", WCD9335_ANA_AMIC1, 0, 20, 0,
+			analog_gain),
+	SOC_SINGLE_TLV("ADC2 Volume", WCD9335_ANA_AMIC2, 0, 20, 0,
+			analog_gain),
+	SOC_SINGLE_TLV("ADC3 Volume", WCD9335_ANA_AMIC3, 0, 20, 0,
+			analog_gain),
+	SOC_SINGLE_TLV("ADC4 Volume", WCD9335_ANA_AMIC4, 0, 20, 0,
+			analog_gain),
+	SOC_SINGLE_TLV("ADC5 Volume", WCD9335_ANA_AMIC5, 0, 20, 0,
+			analog_gain),
+	SOC_SINGLE_TLV("ADC6 Volume", WCD9335_ANA_AMIC6, 0, 20, 0,
+			analog_gain),
+
+	SOC_ENUM("TX0 HPF cut off", cf_dec0_enum),
+	SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
+	SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
+	SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
+	SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
+	SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
+	SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
+	SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
+	SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
+};
+
 static irqreturn_t wcd9335_slimbus_irq(int irq, void *data)
 {
 	struct wcd9335_codec *wcd = data;
@@ -1135,6 +1491,8 @@ static const struct snd_soc_component_driver wcd9335_component_drv = {
 	.probe = wcd9335_codec_probe,
 	.remove = wcd9335_codec_remove,
 	.set_sysclk = wcd9335_codec_set_sysclk,
+	.controls = wcd9335_snd_controls,
+	.num_controls = ARRAY_SIZE(wcd9335_snd_controls),
 };
 
 static int wcd9335_probe(struct platform_device *pdev)
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v4 07/14] ASoC: wcd9335: add playback dapm widgets
  2018-09-17  0:57 [PATCH v4 00/14] ASoC: Add support to WCD9335 Audio Codec srinivas.kandagatla
                   ` (5 preceding siblings ...)
  2018-09-17  0:57 ` [PATCH v4 06/14] ASoC: wcd9335: add basic controls srinivas.kandagatla
@ 2018-09-17  0:57 ` srinivas.kandagatla
  2018-09-17  0:57 ` [PATCH v4 08/14] ASoC: wcd9335: add capture " srinivas.kandagatla
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: srinivas.kandagatla @ 2018-09-17  0:57 UTC (permalink / raw)
  To: lee.jones, robh+dt, broonie
  Cc: mark.rutland, lgirdwood, bgoswami, devicetree, linux-kernel,
	vkoul, alsa-devel, Srinivas Kandagatla

From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

This patch adds required dapm widgets for playback.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Reviewed-by: Vinod Koul <vkoul@kernel.org>
---
 sound/soc/codecs/wcd9335.c | 1796 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1796 insertions(+)

diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index a5cd663..9732675 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -145,6 +145,18 @@ enum {
 
 };
 
+enum {
+	INTERP_EAR = 0,
+	INTERP_HPHL,
+	INTERP_HPHR,
+	INTERP_LO1,
+	INTERP_LO2,
+	INTERP_LO3,
+	INTERP_LO4,
+	INTERP_SPKR1,
+	INTERP_SPKR2,
+};
+
 enum wcd_clock_type {
 	WCD_CLK_OFF,
 	WCD_CLK_RCO,
@@ -195,7 +207,14 @@ struct wcd9335_codec {
 
 	struct wcd_clsh_ctrl *clsh_ctrl;
 	u32 hph_mode;
+	int prim_int_users[WCD9335_NUM_INTERPOLATORS];
+
 	int comp_enabled[COMPANDER_MAX];
+
+	unsigned int rx_port_value;
+	int hph_l_gain;
+	int hph_r_gain;
+	u32 rx_bias_count;
 };
 
 struct wcd9335_irq {
@@ -325,10 +344,69 @@ static const char * const wcd9335_ear_pa_gain_text[] = {
 	"G_0_DB", "G_M2P5_DB", "UNDEFINED", "G_M12_DB"
 };
 
+static const char * const rx_int0_7_mix_mux_text[] = {
+	"ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5",
+	"RX6", "RX7", "PROXIMITY"
+};
+
+static const char * const rx_int_mix_mux_text[] = {
+	"ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5",
+	"RX6", "RX7"
+};
+
+static const char * const rx_prim_mix_text[] = {
+	"ZERO", "DEC0", "DEC1", "IIR0", "IIR1", "RX0", "RX1", "RX2",
+	"RX3", "RX4", "RX5", "RX6", "RX7"
+};
+
+static const char * const rx_int_dem_inp_mux_text[] = {
+	"NORMAL_DSM_OUT", "CLSH_DSM_OUT",
+};
+
+static const char * const rx_int0_interp_mux_text[] = {
+	"ZERO", "RX INT0 MIX2",
+};
+
+static const char * const rx_int1_interp_mux_text[] = {
+	"ZERO", "RX INT1 MIX2",
+};
+
+static const char * const rx_int2_interp_mux_text[] = {
+	"ZERO", "RX INT2 MIX2",
+};
+
+static const char * const rx_int3_interp_mux_text[] = {
+	"ZERO", "RX INT3 MIX2",
+};
+
+static const char * const rx_int4_interp_mux_text[] = {
+	"ZERO", "RX INT4 MIX2",
+};
+
+static const char * const rx_int5_interp_mux_text[] = {
+	"ZERO", "RX INT5 MIX2",
+};
+
+static const char * const rx_int6_interp_mux_text[] = {
+	"ZERO", "RX INT6 MIX2",
+};
+
+static const char * const rx_int7_interp_mux_text[] = {
+	"ZERO", "RX INT7 MIX2",
+};
+
+static const char * const rx_int8_interp_mux_text[] = {
+	"ZERO", "RX INT8 SEC MIX"
+};
+
 static const char * const rx_hph_mode_mux_text[] = {
 	"CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", "CLS_H_LOHIFI"
 };
 
+static const char *const slim_rx_mux_text[] = {
+	"ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB",
+};
+
 static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
 static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
 static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
@@ -422,6 +500,455 @@ 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 slim_rx_mux_enum =
+	SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
+
+static const struct soc_enum rx_int0_2_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1, 0, 10,
+			rx_int0_7_mix_mux_text);
+
+static const struct soc_enum rx_int1_2_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1, 0, 9,
+			rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int2_2_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1, 0, 9,
+			rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int3_2_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1, 0, 9,
+			rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int4_2_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1, 0, 9,
+			rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int5_2_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1, 0, 9,
+			rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int6_2_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1, 0, 9,
+			rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int7_2_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1, 0, 10,
+			rx_int0_7_mix_mux_text);
+
+static const struct soc_enum rx_int8_2_mux_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1, 0, 9,
+			rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int0_1_mix_inp0_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0, 0, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int0_1_mix_inp1_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int0_1_mix_inp2_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int1_1_mix_inp0_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0, 0, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int1_1_mix_inp1_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int1_1_mix_inp2_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int2_1_mix_inp0_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0, 0, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int2_1_mix_inp1_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int2_1_mix_inp2_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int3_1_mix_inp0_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0, 0, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int3_1_mix_inp1_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int3_1_mix_inp2_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int4_1_mix_inp0_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0, 0, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int4_1_mix_inp1_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int4_1_mix_inp2_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int5_1_mix_inp0_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0, 0, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int5_1_mix_inp1_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int5_1_mix_inp2_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int6_1_mix_inp0_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0, 0, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int6_1_mix_inp1_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int6_1_mix_inp2_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int7_1_mix_inp0_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0, 0, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int7_1_mix_inp1_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int7_1_mix_inp2_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int8_1_mix_inp0_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0, 0, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int8_1_mix_inp1_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int8_1_mix_inp2_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1, 4, 13,
+			rx_prim_mix_text);
+
+static const struct soc_enum rx_int0_dem_inp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX0_RX_PATH_SEC0, 0,
+			ARRAY_SIZE(rx_int_dem_inp_mux_text),
+			rx_int_dem_inp_mux_text);
+
+static const struct soc_enum rx_int1_dem_inp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX1_RX_PATH_SEC0, 0,
+			ARRAY_SIZE(rx_int_dem_inp_mux_text),
+			rx_int_dem_inp_mux_text);
+
+static const struct soc_enum rx_int2_dem_inp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX2_RX_PATH_SEC0, 0,
+			ARRAY_SIZE(rx_int_dem_inp_mux_text),
+			rx_int_dem_inp_mux_text);
+
+static const struct soc_enum rx_int0_interp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX0_RX_PATH_CTL, 5, 2,
+			rx_int0_interp_mux_text);
+
+static const struct soc_enum rx_int1_interp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX1_RX_PATH_CTL, 5, 2,
+			rx_int1_interp_mux_text);
+
+static const struct soc_enum rx_int2_interp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX2_RX_PATH_CTL, 5, 2,
+			rx_int2_interp_mux_text);
+
+static const struct soc_enum rx_int3_interp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX3_RX_PATH_CTL, 5, 2,
+			rx_int3_interp_mux_text);
+
+static const struct soc_enum rx_int4_interp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX4_RX_PATH_CTL, 5, 2,
+			rx_int4_interp_mux_text);
+
+static const struct soc_enum rx_int5_interp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX5_RX_PATH_CTL, 5, 2,
+			rx_int5_interp_mux_text);
+
+static const struct soc_enum rx_int6_interp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX6_RX_PATH_CTL, 5, 2,
+			rx_int6_interp_mux_text);
+
+static const struct soc_enum rx_int7_interp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX7_RX_PATH_CTL, 5, 2,
+			rx_int7_interp_mux_text);
+
+static const struct soc_enum rx_int8_interp_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_RX8_RX_PATH_CTL, 5, 2,
+			rx_int8_interp_mux_text);
+
+static const struct snd_kcontrol_new rx_int0_2_mux =
+	SOC_DAPM_ENUM("RX INT0_2 MUX Mux", rx_int0_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int1_2_mux =
+	SOC_DAPM_ENUM("RX INT1_2 MUX Mux", rx_int1_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int2_2_mux =
+	SOC_DAPM_ENUM("RX INT2_2 MUX Mux", rx_int2_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int3_2_mux =
+	SOC_DAPM_ENUM("RX INT3_2 MUX Mux", rx_int3_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int4_2_mux =
+	SOC_DAPM_ENUM("RX INT4_2 MUX Mux", rx_int4_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int5_2_mux =
+	SOC_DAPM_ENUM("RX INT5_2 MUX Mux", rx_int5_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int6_2_mux =
+	SOC_DAPM_ENUM("RX INT6_2 MUX Mux", rx_int6_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int7_2_mux =
+	SOC_DAPM_ENUM("RX INT7_2 MUX Mux", rx_int7_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int8_2_mux =
+	SOC_DAPM_ENUM("RX INT8_2 MUX Mux", rx_int8_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int0_1_mix_inp0_mux =
+	SOC_DAPM_ENUM("RX INT0_1 MIX1 INP0 Mux", rx_int0_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int0_1_mix_inp1_mux =
+	SOC_DAPM_ENUM("RX INT0_1 MIX1 INP1 Mux", rx_int0_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int0_1_mix_inp2_mux =
+	SOC_DAPM_ENUM("RX INT0_1 MIX1 INP2 Mux", rx_int0_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int1_1_mix_inp0_mux =
+	SOC_DAPM_ENUM("RX INT1_1 MIX1 INP0 Mux", rx_int1_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int1_1_mix_inp1_mux =
+	SOC_DAPM_ENUM("RX INT1_1 MIX1 INP1 Mux", rx_int1_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int1_1_mix_inp2_mux =
+	SOC_DAPM_ENUM("RX INT1_1 MIX1 INP2 Mux", rx_int1_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int2_1_mix_inp0_mux =
+	SOC_DAPM_ENUM("RX INT2_1 MIX1 INP0 Mux", rx_int2_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int2_1_mix_inp1_mux =
+	SOC_DAPM_ENUM("RX INT2_1 MIX1 INP1 Mux", rx_int2_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int2_1_mix_inp2_mux =
+	SOC_DAPM_ENUM("RX INT2_1 MIX1 INP2 Mux", rx_int2_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int3_1_mix_inp0_mux =
+	SOC_DAPM_ENUM("RX INT3_1 MIX1 INP0 Mux", rx_int3_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int3_1_mix_inp1_mux =
+	SOC_DAPM_ENUM("RX INT3_1 MIX1 INP1 Mux", rx_int3_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int3_1_mix_inp2_mux =
+	SOC_DAPM_ENUM("RX INT3_1 MIX1 INP2 Mux", rx_int3_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int4_1_mix_inp0_mux =
+	SOC_DAPM_ENUM("RX INT4_1 MIX1 INP0 Mux", rx_int4_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int4_1_mix_inp1_mux =
+	SOC_DAPM_ENUM("RX INT4_1 MIX1 INP1 Mux", rx_int4_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int4_1_mix_inp2_mux =
+	SOC_DAPM_ENUM("RX INT4_1 MIX1 INP2 Mux", rx_int4_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int5_1_mix_inp0_mux =
+	SOC_DAPM_ENUM("RX INT5_1 MIX1 INP0 Mux", rx_int5_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int5_1_mix_inp1_mux =
+	SOC_DAPM_ENUM("RX INT5_1 MIX1 INP1 Mux", rx_int5_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int5_1_mix_inp2_mux =
+	SOC_DAPM_ENUM("RX INT5_1 MIX1 INP2 Mux", rx_int5_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int6_1_mix_inp0_mux =
+	SOC_DAPM_ENUM("RX INT6_1 MIX1 INP0 Mux", rx_int6_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int6_1_mix_inp1_mux =
+	SOC_DAPM_ENUM("RX INT6_1 MIX1 INP1 Mux", rx_int6_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int6_1_mix_inp2_mux =
+	SOC_DAPM_ENUM("RX INT6_1 MIX1 INP2 Mux", rx_int6_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int7_1_mix_inp0_mux =
+	SOC_DAPM_ENUM("RX INT7_1 MIX1 INP0 Mux", rx_int7_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int7_1_mix_inp1_mux =
+	SOC_DAPM_ENUM("RX INT7_1 MIX1 INP1 Mux", rx_int7_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int7_1_mix_inp2_mux =
+	SOC_DAPM_ENUM("RX INT7_1 MIX1 INP2 Mux", rx_int7_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int8_1_mix_inp0_mux =
+	SOC_DAPM_ENUM("RX INT8_1 MIX1 INP0 Mux", rx_int8_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int8_1_mix_inp1_mux =
+	SOC_DAPM_ENUM("RX INT8_1 MIX1 INP1 Mux", rx_int8_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int8_1_mix_inp2_mux =
+	SOC_DAPM_ENUM("RX INT8_1 MIX1 INP2 Mux", rx_int8_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int0_interp_mux =
+	SOC_DAPM_ENUM("RX INT0 INTERP Mux", rx_int0_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int1_interp_mux =
+	SOC_DAPM_ENUM("RX INT1 INTERP Mux", rx_int1_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int2_interp_mux =
+	SOC_DAPM_ENUM("RX INT2 INTERP Mux", rx_int2_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int3_interp_mux =
+	SOC_DAPM_ENUM("RX INT3 INTERP Mux", rx_int3_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int4_interp_mux =
+	SOC_DAPM_ENUM("RX INT4 INTERP Mux", rx_int4_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int5_interp_mux =
+	SOC_DAPM_ENUM("RX INT5 INTERP Mux", rx_int5_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int6_interp_mux =
+	SOC_DAPM_ENUM("RX INT6 INTERP Mux", rx_int6_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int7_interp_mux =
+	SOC_DAPM_ENUM("RX INT7 INTERP Mux", rx_int7_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int8_interp_mux =
+	SOC_DAPM_ENUM("RX INT8 INTERP Mux", rx_int8_interp_mux_enum);
+
+static int slim_rx_mux_get(struct snd_kcontrol *kc,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc);
+	struct wcd9335_codec *wcd = dev_get_drvdata(dapm->dev);
+
+	ucontrol->value.enumerated.item[0] = wcd->rx_port_value;
+
+	return 0;
+}
+
+static int slim_rx_mux_put(struct snd_kcontrol *kc,
+			   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kc);
+	struct wcd9335_codec *wcd = dev_get_drvdata(w->dapm->dev);
+	struct soc_enum *e = (struct soc_enum *)kc->private_value;
+	struct snd_soc_dapm_update *update = NULL;
+	u32 port_id = w->shift;
+
+	wcd->rx_port_value = ucontrol->value.enumerated.item[0];
+
+	switch (wcd->rx_port_value) {
+	case 0:
+		list_del_init(&wcd->rx_chs[port_id].list);
+		break;
+	case 1:
+		list_add_tail(&wcd->rx_chs[port_id].list,
+			      &wcd->dai[AIF1_PB].slim_ch_list);
+		break;
+	case 2:
+		list_add_tail(&wcd->rx_chs[port_id].list,
+			      &wcd->dai[AIF2_PB].slim_ch_list);
+		break;
+	case 3:
+		list_add_tail(&wcd->rx_chs[port_id].list,
+			      &wcd->dai[AIF3_PB].slim_ch_list);
+		break;
+	case 4:
+		list_add_tail(&wcd->rx_chs[port_id].list,
+			      &wcd->dai[AIF4_PB].slim_ch_list);
+		break;
+	default:
+		dev_err(wcd->dev, "Unknown AIF %d\n", wcd->rx_port_value);
+		goto err;
+	}
+
+	snd_soc_dapm_mux_update_power(w->dapm, kc, wcd->rx_port_value,
+				      e, update);
+
+	return 0;
+err:
+	return -EINVAL;
+}
+
+static const struct snd_kcontrol_new slim_rx_mux[WCD9335_RX_MAX] = {
+	SOC_DAPM_ENUM_EXT("SLIM RX0 Mux", slim_rx_mux_enum,
+			  slim_rx_mux_get, slim_rx_mux_put),
+	SOC_DAPM_ENUM_EXT("SLIM RX1 Mux", slim_rx_mux_enum,
+			  slim_rx_mux_get, slim_rx_mux_put),
+	SOC_DAPM_ENUM_EXT("SLIM RX2 Mux", slim_rx_mux_enum,
+			  slim_rx_mux_get, slim_rx_mux_put),
+	SOC_DAPM_ENUM_EXT("SLIM RX3 Mux", slim_rx_mux_enum,
+			  slim_rx_mux_get, slim_rx_mux_put),
+	SOC_DAPM_ENUM_EXT("SLIM RX4 Mux", slim_rx_mux_enum,
+			  slim_rx_mux_get, slim_rx_mux_put),
+	SOC_DAPM_ENUM_EXT("SLIM RX5 Mux", slim_rx_mux_enum,
+			  slim_rx_mux_get, slim_rx_mux_put),
+	SOC_DAPM_ENUM_EXT("SLIM RX6 Mux", slim_rx_mux_enum,
+			  slim_rx_mux_get, slim_rx_mux_put),
+	SOC_DAPM_ENUM_EXT("SLIM RX7 Mux", slim_rx_mux_enum,
+			  slim_rx_mux_get, slim_rx_mux_put),
+};
+
+static int wcd9335_int_dem_inp_mux_put(struct snd_kcontrol *kc,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_enum *e = (struct soc_enum *)kc->private_value;
+	struct snd_soc_component *component;
+	int reg, val;
+
+	component = snd_soc_dapm_kcontrol_component(kc);
+	val = ucontrol->value.enumerated.item[0];
+
+	if (e->reg == WCD9335_CDC_RX0_RX_PATH_SEC0)
+		reg = WCD9335_CDC_RX0_RX_PATH_CFG0;
+	else if (e->reg == WCD9335_CDC_RX1_RX_PATH_SEC0)
+		reg = WCD9335_CDC_RX1_RX_PATH_CFG0;
+	else if (e->reg == WCD9335_CDC_RX2_RX_PATH_SEC0)
+		reg = WCD9335_CDC_RX2_RX_PATH_CFG0;
+	else
+		return -EINVAL;
+
+	/* Set Look Ahead Delay */
+	snd_soc_component_update_bits(component, reg,
+				WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_EN_MASK,
+				val ? WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_EN : 0);
+	/* Set DEM INP Select */
+	return snd_soc_dapm_put_enum_double(kc, ucontrol);
+}
+
+static const struct snd_kcontrol_new rx_int0_dem_inp_mux =
+	SOC_DAPM_ENUM_EXT("RX INT0 DEM MUX Mux", rx_int0_dem_inp_mux_enum,
+			  snd_soc_dapm_get_enum_double,
+			  wcd9335_int_dem_inp_mux_put);
+
+static const struct snd_kcontrol_new rx_int1_dem_inp_mux =
+	SOC_DAPM_ENUM_EXT("RX INT1 DEM MUX Mux", rx_int1_dem_inp_mux_enum,
+			  snd_soc_dapm_get_enum_double,
+			  wcd9335_int_dem_inp_mux_put);
+
+static const struct snd_kcontrol_new rx_int2_dem_inp_mux =
+	SOC_DAPM_ENUM_EXT("RX INT2 DEM MUX Mux", rx_int2_dem_inp_mux_enum,
+			  snd_soc_dapm_get_enum_double,
+			  wcd9335_int_dem_inp_mux_put);
+
 static int wcd9335_set_mix_interpolator_rate(struct snd_soc_dai *dai,
 					     int rate_val,
 					     u32 rate)
@@ -1031,6 +1558,988 @@ static const struct snd_kcontrol_new wcd9335_snd_controls[] = {
 	SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
 };
 
+static void wcd9335_codec_enable_int_port(struct wcd_slim_codec_dai_data *dai,
+					struct snd_soc_component *component)
+{
+	int port_num = 0;
+	unsigned short reg = 0;
+	unsigned int val = 0;
+	struct wcd9335_codec *wcd = dev_get_drvdata(component->dev);
+	struct wcd9335_slim_ch *ch;
+
+	list_for_each_entry(ch, &dai->slim_ch_list, list) {
+		if (ch->port >= WCD9335_RX_START) {
+			port_num = ch->port - WCD9335_RX_START;
+			reg = WCD9335_SLIM_PGD_PORT_INT_EN0 + (port_num / 8);
+		} else {
+			port_num = ch->port;
+			reg = WCD9335_SLIM_PGD_PORT_INT_TX_EN0 + (port_num / 8);
+		}
+
+		regmap_read(wcd->if_regmap, reg, &val);
+		if (!(val & BIT(port_num % 8)))
+			regmap_write(wcd->if_regmap, reg,
+					val | BIT(port_num % 8));
+	}
+}
+
+static int wcd9335_codec_enable_slim(struct snd_soc_dapm_widget *w,
+				       struct snd_kcontrol *kc,
+				       int event)
+{
+	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+	struct wcd9335_codec *wcd = snd_soc_component_get_drvdata(comp);
+	struct wcd_slim_codec_dai_data *dai = &wcd->dai[w->shift];
+	int ret = 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		wcd9335_codec_enable_int_port(dai, comp);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		slim_stream_unprepare(dai->sruntime);
+		slim_stream_disable(dai->sruntime);
+		kfree(dai->sconfig.chs);
+
+		break;
+	}
+
+	return ret;
+}
+
+static int wcd9335_codec_enable_mix_path(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kc, int event)
+{
+	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+	u16 gain_reg;
+	int offset_val = 0;
+	int val = 0;
+
+	switch (w->reg) {
+	case WCD9335_CDC_RX0_RX_PATH_MIX_CTL:
+		gain_reg = WCD9335_CDC_RX0_RX_VOL_MIX_CTL;
+		break;
+	case WCD9335_CDC_RX1_RX_PATH_MIX_CTL:
+		gain_reg = WCD9335_CDC_RX1_RX_VOL_MIX_CTL;
+		break;
+	case WCD9335_CDC_RX2_RX_PATH_MIX_CTL:
+		gain_reg = WCD9335_CDC_RX2_RX_VOL_MIX_CTL;
+		break;
+	case WCD9335_CDC_RX3_RX_PATH_MIX_CTL:
+		gain_reg = WCD9335_CDC_RX3_RX_VOL_MIX_CTL;
+		break;
+	case WCD9335_CDC_RX4_RX_PATH_MIX_CTL:
+		gain_reg = WCD9335_CDC_RX4_RX_VOL_MIX_CTL;
+		break;
+	case WCD9335_CDC_RX5_RX_PATH_MIX_CTL:
+		gain_reg = WCD9335_CDC_RX5_RX_VOL_MIX_CTL;
+		break;
+	case WCD9335_CDC_RX6_RX_PATH_MIX_CTL:
+		gain_reg = WCD9335_CDC_RX6_RX_VOL_MIX_CTL;
+		break;
+	case WCD9335_CDC_RX7_RX_PATH_MIX_CTL:
+		gain_reg = WCD9335_CDC_RX7_RX_VOL_MIX_CTL;
+		break;
+	case WCD9335_CDC_RX8_RX_PATH_MIX_CTL:
+		gain_reg = WCD9335_CDC_RX8_RX_VOL_MIX_CTL;
+		break;
+	default:
+		dev_err(comp->dev, "%s: No gain register avail for %s\n",
+			__func__, w->name);
+		return 0;
+	};
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		val = snd_soc_component_read32(comp, gain_reg);
+		val += offset_val;
+		snd_soc_component_write(comp, gain_reg, val);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		break;
+	};
+
+	return 0;
+}
+
+static u16 wcd9335_interp_get_primary_reg(u16 reg, u16 *ind)
+{
+	u16 prim_int_reg = WCD9335_CDC_RX0_RX_PATH_CTL;
+
+	switch (reg) {
+	case WCD9335_CDC_RX0_RX_PATH_CTL:
+	case WCD9335_CDC_RX0_RX_PATH_MIX_CTL:
+		prim_int_reg = WCD9335_CDC_RX0_RX_PATH_CTL;
+		*ind = 0;
+		break;
+	case WCD9335_CDC_RX1_RX_PATH_CTL:
+	case WCD9335_CDC_RX1_RX_PATH_MIX_CTL:
+		prim_int_reg = WCD9335_CDC_RX1_RX_PATH_CTL;
+		*ind = 1;
+		break;
+	case WCD9335_CDC_RX2_RX_PATH_CTL:
+	case WCD9335_CDC_RX2_RX_PATH_MIX_CTL:
+		prim_int_reg = WCD9335_CDC_RX2_RX_PATH_CTL;
+		*ind = 2;
+		break;
+	case WCD9335_CDC_RX3_RX_PATH_CTL:
+	case WCD9335_CDC_RX3_RX_PATH_MIX_CTL:
+		prim_int_reg = WCD9335_CDC_RX3_RX_PATH_CTL;
+		*ind = 3;
+		break;
+	case WCD9335_CDC_RX4_RX_PATH_CTL:
+	case WCD9335_CDC_RX4_RX_PATH_MIX_CTL:
+		prim_int_reg = WCD9335_CDC_RX4_RX_PATH_CTL;
+		*ind = 4;
+		break;
+	case WCD9335_CDC_RX5_RX_PATH_CTL:
+	case WCD9335_CDC_RX5_RX_PATH_MIX_CTL:
+		prim_int_reg = WCD9335_CDC_RX5_RX_PATH_CTL;
+		*ind = 5;
+		break;
+	case WCD9335_CDC_RX6_RX_PATH_CTL:
+	case WCD9335_CDC_RX6_RX_PATH_MIX_CTL:
+		prim_int_reg = WCD9335_CDC_RX6_RX_PATH_CTL;
+		*ind = 6;
+		break;
+	case WCD9335_CDC_RX7_RX_PATH_CTL:
+	case WCD9335_CDC_RX7_RX_PATH_MIX_CTL:
+		prim_int_reg = WCD9335_CDC_RX7_RX_PATH_CTL;
+		*ind = 7;
+		break;
+	case WCD9335_CDC_RX8_RX_PATH_CTL:
+	case WCD9335_CDC_RX8_RX_PATH_MIX_CTL:
+		prim_int_reg = WCD9335_CDC_RX8_RX_PATH_CTL;
+		*ind = 8;
+		break;
+	};
+
+	return prim_int_reg;
+}
+
+static void wcd9335_codec_hd2_control(struct snd_soc_component *component,
+				    u16 prim_int_reg, int event)
+{
+	u16 hd2_scale_reg;
+	u16 hd2_enable_reg = 0;
+
+	if (prim_int_reg == WCD9335_CDC_RX1_RX_PATH_CTL) {
+		hd2_scale_reg = WCD9335_CDC_RX1_RX_PATH_SEC3;
+		hd2_enable_reg = WCD9335_CDC_RX1_RX_PATH_CFG0;
+	}
+	if (prim_int_reg == WCD9335_CDC_RX2_RX_PATH_CTL) {
+		hd2_scale_reg = WCD9335_CDC_RX2_RX_PATH_SEC3;
+		hd2_enable_reg = WCD9335_CDC_RX2_RX_PATH_CFG0;
+	}
+
+	if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) {
+		snd_soc_component_update_bits(component, hd2_scale_reg,
+				WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_MASK,
+				WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_0P2500);
+		snd_soc_component_update_bits(component, hd2_scale_reg,
+				WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_MASK,
+				WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_2);
+		snd_soc_component_update_bits(component, hd2_enable_reg,
+				WCD9335_CDC_RX_PATH_CFG_HD2_EN_MASK,
+				WCD9335_CDC_RX_PATH_CFG_HD2_ENABLE);
+	}
+
+	if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_component_update_bits(component, hd2_enable_reg,
+					WCD9335_CDC_RX_PATH_CFG_HD2_EN_MASK,
+					WCD9335_CDC_RX_PATH_CFG_HD2_DISABLE);
+		snd_soc_component_update_bits(component, hd2_scale_reg,
+					WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_MASK,
+					WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_1);
+		snd_soc_component_update_bits(component, hd2_scale_reg,
+				WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_MASK,
+				WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_0P0000);
+	}
+}
+
+static int wcd9335_codec_enable_prim_interpolator(
+						struct snd_soc_component *comp,
+						u16 reg, int event)
+{
+	struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev);
+	u16 ind = 0;
+	int prim_int_reg = wcd9335_interp_get_primary_reg(reg, &ind);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd->prim_int_users[ind]++;
+		if (wcd->prim_int_users[ind] == 1) {
+			snd_soc_component_update_bits(comp, prim_int_reg,
+					WCD9335_CDC_RX_PGA_MUTE_EN_MASK,
+					WCD9335_CDC_RX_PGA_MUTE_ENABLE);
+			wcd9335_codec_hd2_control(comp, prim_int_reg, event);
+			snd_soc_component_update_bits(comp, prim_int_reg,
+					WCD9335_CDC_RX_CLK_EN_MASK,
+					WCD9335_CDC_RX_CLK_ENABLE);
+		}
+
+		if ((reg != prim_int_reg) &&
+			((snd_soc_component_read32(comp, prim_int_reg)) &
+			 WCD9335_CDC_RX_PGA_MUTE_EN_MASK))
+			snd_soc_component_update_bits(comp, reg,
+						WCD9335_CDC_RX_PGA_MUTE_EN_MASK,
+						WCD9335_CDC_RX_PGA_MUTE_ENABLE);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd->prim_int_users[ind]--;
+		if (wcd->prim_int_users[ind] == 0) {
+			snd_soc_component_update_bits(comp, prim_int_reg,
+					WCD9335_CDC_RX_CLK_EN_MASK,
+					WCD9335_CDC_RX_CLK_DISABLE);
+			snd_soc_component_update_bits(comp, prim_int_reg,
+					WCD9335_CDC_RX_RESET_MASK,
+					WCD9335_CDC_RX_RESET_ENABLE);
+			snd_soc_component_update_bits(comp, prim_int_reg,
+					WCD9335_CDC_RX_RESET_MASK,
+					WCD9335_CDC_RX_RESET_DISABLE);
+			wcd9335_codec_hd2_control(comp, prim_int_reg, event);
+		}
+		break;
+	};
+
+	return 0;
+}
+
+static int wcd9335_config_compander(struct snd_soc_component *component,
+				    int interp_n, int event)
+{
+	struct wcd9335_codec *wcd = dev_get_drvdata(component->dev);
+	int comp;
+	u16 comp_ctl0_reg, rx_path_cfg0_reg;
+
+	/* EAR does not have compander */
+	if (!interp_n)
+		return 0;
+
+	comp = interp_n - 1;
+	if (!wcd->comp_enabled[comp])
+		return 0;
+
+	comp_ctl0_reg = WCD9335_CDC_COMPANDER1_CTL(comp);
+	rx_path_cfg0_reg = WCD9335_CDC_RX1_RX_PATH_CFG(comp);
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		/* Enable Compander Clock */
+		snd_soc_component_update_bits(component, comp_ctl0_reg,
+					WCD9335_CDC_COMPANDER_CLK_EN_MASK,
+					WCD9335_CDC_COMPANDER_CLK_ENABLE);
+		/* Reset comander */
+		snd_soc_component_update_bits(component, comp_ctl0_reg,
+					WCD9335_CDC_COMPANDER_SOFT_RST_MASK,
+					WCD9335_CDC_COMPANDER_SOFT_RST_ENABLE);
+		snd_soc_component_update_bits(component, comp_ctl0_reg,
+				WCD9335_CDC_COMPANDER_SOFT_RST_MASK,
+				WCD9335_CDC_COMPANDER_SOFT_RST_DISABLE);
+		/* Enables DRE in this path */
+		snd_soc_component_update_bits(component, rx_path_cfg0_reg,
+					WCD9335_CDC_RX_PATH_CFG_CMP_EN_MASK,
+					WCD9335_CDC_RX_PATH_CFG_CMP_ENABLE);
+	}
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_component_update_bits(component, comp_ctl0_reg,
+					WCD9335_CDC_COMPANDER_HALT_MASK,
+					WCD9335_CDC_COMPANDER_HALT);
+		snd_soc_component_update_bits(component, rx_path_cfg0_reg,
+					WCD9335_CDC_RX_PATH_CFG_CMP_EN_MASK,
+					WCD9335_CDC_RX_PATH_CFG_CMP_DISABLE);
+
+		snd_soc_component_update_bits(component, comp_ctl0_reg,
+					WCD9335_CDC_COMPANDER_SOFT_RST_MASK,
+					WCD9335_CDC_COMPANDER_SOFT_RST_ENABLE);
+		snd_soc_component_update_bits(component, comp_ctl0_reg,
+				WCD9335_CDC_COMPANDER_SOFT_RST_MASK,
+				WCD9335_CDC_COMPANDER_SOFT_RST_DISABLE);
+		snd_soc_component_update_bits(component, comp_ctl0_reg,
+					WCD9335_CDC_COMPANDER_CLK_EN_MASK,
+					WCD9335_CDC_COMPANDER_CLK_DISABLE);
+		snd_soc_component_update_bits(component, comp_ctl0_reg,
+					WCD9335_CDC_COMPANDER_HALT_MASK,
+					WCD9335_CDC_COMPANDER_NOHALT);
+	}
+
+	return 0;
+}
+
+static int wcd9335_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kc, int event)
+{
+	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+	u16 gain_reg;
+	u16 reg;
+	int val;
+	int offset_val = 0;
+
+	if (!(strcmp(w->name, "RX INT0 INTERP"))) {
+		reg = WCD9335_CDC_RX0_RX_PATH_CTL;
+		gain_reg = WCD9335_CDC_RX0_RX_VOL_CTL;
+	} else if (!(strcmp(w->name, "RX INT1 INTERP"))) {
+		reg = WCD9335_CDC_RX1_RX_PATH_CTL;
+		gain_reg = WCD9335_CDC_RX1_RX_VOL_CTL;
+	} else if (!(strcmp(w->name, "RX INT2 INTERP"))) {
+		reg = WCD9335_CDC_RX2_RX_PATH_CTL;
+		gain_reg = WCD9335_CDC_RX2_RX_VOL_CTL;
+	} else if (!(strcmp(w->name, "RX INT3 INTERP"))) {
+		reg = WCD9335_CDC_RX3_RX_PATH_CTL;
+		gain_reg = WCD9335_CDC_RX3_RX_VOL_CTL;
+	} else if (!(strcmp(w->name, "RX INT4 INTERP"))) {
+		reg = WCD9335_CDC_RX4_RX_PATH_CTL;
+		gain_reg = WCD9335_CDC_RX4_RX_VOL_CTL;
+	} else if (!(strcmp(w->name, "RX INT5 INTERP"))) {
+		reg = WCD9335_CDC_RX5_RX_PATH_CTL;
+		gain_reg = WCD9335_CDC_RX5_RX_VOL_CTL;
+	} else if (!(strcmp(w->name, "RX INT6 INTERP"))) {
+		reg = WCD9335_CDC_RX6_RX_PATH_CTL;
+		gain_reg = WCD9335_CDC_RX6_RX_VOL_CTL;
+	} else if (!(strcmp(w->name, "RX INT7 INTERP"))) {
+		reg = WCD9335_CDC_RX7_RX_PATH_CTL;
+		gain_reg = WCD9335_CDC_RX7_RX_VOL_CTL;
+	} else if (!(strcmp(w->name, "RX INT8 INTERP"))) {
+		reg = WCD9335_CDC_RX8_RX_PATH_CTL;
+		gain_reg = WCD9335_CDC_RX8_RX_VOL_CTL;
+	} else {
+		dev_err(comp->dev, "%s: Interpolator reg not found\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Reset if needed */
+		wcd9335_codec_enable_prim_interpolator(comp, reg, event);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		wcd9335_config_compander(comp, w->shift, event);
+		val = snd_soc_component_read32(comp, gain_reg);
+		val += offset_val;
+		snd_soc_component_write(comp, gain_reg, val);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd9335_config_compander(comp, w->shift, event);
+		wcd9335_codec_enable_prim_interpolator(comp, reg, event);
+		break;
+	};
+
+	return 0;
+}
+
+static void wcd9335_codec_hph_mode_gain_opt(struct snd_soc_component *component,
+					    u8 gain)
+{
+	struct wcd9335_codec *wcd = dev_get_drvdata(component->dev);
+	u8 hph_l_en, hph_r_en;
+	u8 l_val, r_val;
+	u8 hph_pa_status;
+	bool is_hphl_pa, is_hphr_pa;
+
+	hph_pa_status = snd_soc_component_read32(component, WCD9335_ANA_HPH);
+	is_hphl_pa = hph_pa_status >> 7;
+	is_hphr_pa = (hph_pa_status & 0x40) >> 6;
+
+	hph_l_en = snd_soc_component_read32(component, WCD9335_HPH_L_EN);
+	hph_r_en = snd_soc_component_read32(component, WCD9335_HPH_R_EN);
+
+	l_val = (hph_l_en & 0xC0) | 0x20 | gain;
+	r_val = (hph_r_en & 0xC0) | 0x20 | gain;
+
+	/*
+	 * Set HPH_L & HPH_R gain source selection to REGISTER
+	 * for better click and pop only if corresponding PAs are
+	 * not enabled. Also cache the values of the HPHL/R
+	 * PA gains to be applied after PAs are enabled
+	 */
+	if ((l_val != hph_l_en) && !is_hphl_pa) {
+		snd_soc_component_write(component, WCD9335_HPH_L_EN, l_val);
+		wcd->hph_l_gain = hph_l_en & 0x1F;
+	}
+
+	if ((r_val != hph_r_en) && !is_hphr_pa) {
+		snd_soc_component_write(component, WCD9335_HPH_R_EN, r_val);
+		wcd->hph_r_gain = hph_r_en & 0x1F;
+	}
+}
+
+static void wcd9335_codec_hph_lohifi_config(struct snd_soc_component *comp,
+					  int event)
+{
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		snd_soc_component_update_bits(comp, WCD9335_RX_BIAS_HPH_PA,
+					WCD9335_RX_BIAS_HPH_PA_AMP_5_UA_MASK,
+					0x06);
+		snd_soc_component_update_bits(comp,
+					WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2,
+					0xF0, 0x40);
+		snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL,
+				WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK,
+				WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_1000);
+		snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2,
+				WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK,
+				WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_ENABLE);
+		snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL1,
+				WCD9335_HPH_PA_GM3_IB_SCALE_MASK,
+				0x0C);
+		wcd9335_codec_hph_mode_gain_opt(comp, 0x11);
+	}
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2,
+			WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK,
+			WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_DISABLE);
+		snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL,
+				WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK,
+				WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_500);
+		snd_soc_component_write(comp, WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2,
+					0x8A);
+		snd_soc_component_update_bits(comp, WCD9335_RX_BIAS_HPH_PA,
+					WCD9335_RX_BIAS_HPH_PA_AMP_5_UA_MASK,
+					0x0A);
+	}
+}
+
+static void wcd9335_codec_hph_lp_config(struct snd_soc_component *comp,
+				      int event)
+{
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL1,
+				WCD9335_HPH_PA_GM3_IB_SCALE_MASK,
+				0x0C);
+		wcd9335_codec_hph_mode_gain_opt(comp, 0x10);
+		snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL,
+				WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK,
+				WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_1000);
+		snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2,
+			WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK,
+			WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_ENABLE);
+		snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2,
+				WCD9335_HPH_PA_CTL2_FORCE_PSRREH_MASK,
+				WCD9335_HPH_PA_CTL2_FORCE_PSRREH_ENABLE);
+		snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2,
+				WCD9335_HPH_PA_CTL2_HPH_PSRR_ENH_MASK,
+				WCD9335_HPH_PA_CTL2_HPH_PSRR_ENABLE);
+		snd_soc_component_update_bits(comp, WCD9335_HPH_RDAC_LDO_CTL,
+				WCD9335_HPH_RDAC_N1P65_LD_OUTCTL_MASK,
+				WCD9335_HPH_RDAC_N1P65_LD_OUTCTL_V_N1P60);
+		snd_soc_component_update_bits(comp, WCD9335_HPH_RDAC_LDO_CTL,
+				WCD9335_HPH_RDAC_1P65_LD_OUTCTL_MASK,
+				WCD9335_HPH_RDAC_1P65_LD_OUTCTL_V_N1P60);
+		snd_soc_component_update_bits(comp,
+				WCD9335_RX_BIAS_HPH_RDAC_LDO, 0x0F, 0x01);
+		snd_soc_component_update_bits(comp,
+				WCD9335_RX_BIAS_HPH_RDAC_LDO, 0xF0, 0x10);
+	}
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_component_write(comp, WCD9335_RX_BIAS_HPH_RDAC_LDO,
+					0x88);
+		snd_soc_component_write(comp, WCD9335_HPH_RDAC_LDO_CTL,
+					0x33);
+		snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2,
+				WCD9335_HPH_PA_CTL2_HPH_PSRR_ENH_MASK,
+				WCD9335_HPH_PA_CTL2_HPH_PSRR_DISABLE);
+		snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2,
+				WCD9335_HPH_PA_CTL2_FORCE_PSRREH_MASK,
+				WCD9335_HPH_PA_CTL2_FORCE_PSRREH_DISABLE);
+		snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2,
+				WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK,
+				WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_DISABLE);
+		snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL,
+				WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK,
+				WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_500);
+		snd_soc_component_update_bits(comp, WCD9335_HPH_R_EN,
+				WCD9335_HPH_CONST_SEL_L_MASK,
+				WCD9335_HPH_CONST_SEL_L_HQ_PATH);
+		snd_soc_component_update_bits(comp, WCD9335_HPH_L_EN,
+				WCD9335_HPH_CONST_SEL_L_MASK,
+				WCD9335_HPH_CONST_SEL_L_HQ_PATH);
+	}
+}
+
+static void wcd9335_codec_hph_hifi_config(struct snd_soc_component *comp,
+					int event)
+{
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL,
+				WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK,
+				WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_1000);
+		snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2,
+				WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK,
+				WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_ENABLE);
+		snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL1,
+				WCD9335_HPH_PA_GM3_IB_SCALE_MASK,
+				0x0C);
+		wcd9335_codec_hph_mode_gain_opt(comp, 0x11);
+	}
+
+	if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		snd_soc_component_update_bits(comp, WCD9335_HPH_PA_CTL2,
+			WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK,
+			WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_DISABLE);
+		snd_soc_component_update_bits(comp, WCD9335_HPH_CNP_WG_CTL,
+				WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK,
+				WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_500);
+	}
+}
+
+static void wcd9335_codec_hph_mode_config(struct snd_soc_component *component,
+					  int event, int mode)
+{
+	switch (mode) {
+	case CLS_H_LP:
+		wcd9335_codec_hph_lp_config(component, event);
+		break;
+	case CLS_H_LOHIFI:
+		wcd9335_codec_hph_lohifi_config(component, event);
+		break;
+	case CLS_H_HIFI:
+		wcd9335_codec_hph_hifi_config(component, event);
+		break;
+	}
+}
+
+static int wcd9335_codec_hphl_dac_event(struct snd_soc_dapm_widget *w,
+					struct snd_kcontrol *kc,
+					int event)
+{
+	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+	struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev);
+	int hph_mode = wcd->hph_mode;
+	u8 dem_inp;
+	int ret = 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Read DEM INP Select */
+		dem_inp = snd_soc_component_read32(comp,
+				WCD9335_CDC_RX1_RX_PATH_SEC0) & 0x03;
+		if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) ||
+				(hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) {
+			dev_err(comp->dev, "Incorrect DEM Input\n");
+			return -EINVAL;
+		}
+		wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_PRE_DAC,
+					WCD_CLSH_STATE_HPHL,
+					((hph_mode == CLS_H_LOHIFI) ?
+					 CLS_H_HIFI : hph_mode));
+
+		wcd9335_codec_hph_mode_config(comp, event, hph_mode);
+
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		usleep_range(1000, 1100);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* 1000us required as per HW requirement */
+		usleep_range(1000, 1100);
+
+		if (!(wcd_clsh_ctrl_get_state(wcd->clsh_ctrl) &
+				WCD_CLSH_STATE_HPHR))
+			wcd9335_codec_hph_mode_config(comp, event, hph_mode);
+
+		wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA,
+				WCD_CLSH_STATE_HPHL,
+				((hph_mode == CLS_H_LOHIFI) ?
+				 CLS_H_HIFI : hph_mode));
+		break;
+	};
+
+	return ret;
+}
+
+static int wcd9335_codec_lineout_dac_event(struct snd_soc_dapm_widget *w,
+					   struct snd_kcontrol *kc, int event)
+{
+	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+	struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_PRE_DAC,
+					WCD_CLSH_STATE_LO, CLS_AB);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA,
+					WCD_CLSH_STATE_LO, CLS_AB);
+		break;
+	}
+
+	return 0;
+}
+
+static int wcd9335_codec_ear_dac_event(struct snd_soc_dapm_widget *w,
+				       struct snd_kcontrol *kc, int event)
+{
+	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+	struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev);
+	int ret = 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_PRE_DAC,
+					WCD_CLSH_STATE_EAR, CLS_H_NORMAL);
+
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA,
+					WCD_CLSH_STATE_EAR, CLS_H_NORMAL);
+		break;
+	};
+
+	return ret;
+}
+
+static void wcd9335_codec_hph_post_pa_config(struct wcd9335_codec *wcd,
+					     int mode, int event)
+{
+	u8 scale_val = 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		switch (mode) {
+		case CLS_H_HIFI:
+			scale_val = 0x3;
+			break;
+		case CLS_H_LOHIFI:
+			scale_val = 0x1;
+			break;
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		scale_val = 0x6;
+		break;
+	}
+
+	if (scale_val)
+		snd_soc_component_update_bits(wcd->component,
+					WCD9335_HPH_PA_CTL1,
+					WCD9335_HPH_PA_GM3_IB_SCALE_MASK,
+					scale_val << 1);
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		if (wcd->comp_enabled[COMPANDER_1] ||
+		    wcd->comp_enabled[COMPANDER_2]) {
+			/* GAIN Source Selection */
+			snd_soc_component_update_bits(wcd->component,
+					WCD9335_HPH_L_EN,
+					WCD9335_HPH_GAIN_SRC_SEL_MASK,
+					WCD9335_HPH_GAIN_SRC_SEL_COMPANDER);
+			snd_soc_component_update_bits(wcd->component,
+					WCD9335_HPH_R_EN,
+					WCD9335_HPH_GAIN_SRC_SEL_MASK,
+					WCD9335_HPH_GAIN_SRC_SEL_COMPANDER);
+			snd_soc_component_update_bits(wcd->component,
+					WCD9335_HPH_AUTO_CHOP,
+					WCD9335_HPH_AUTO_CHOP_MASK,
+					WCD9335_HPH_AUTO_CHOP_FORCE_ENABLE);
+		}
+		snd_soc_component_update_bits(wcd->component,
+						WCD9335_HPH_L_EN,
+						WCD9335_HPH_PA_GAIN_MASK,
+						wcd->hph_l_gain);
+		snd_soc_component_update_bits(wcd->component,
+						WCD9335_HPH_R_EN,
+						WCD9335_HPH_PA_GAIN_MASK,
+						wcd->hph_r_gain);
+	}
+
+	if (SND_SOC_DAPM_EVENT_OFF(event))
+		snd_soc_component_update_bits(wcd->component,
+				WCD9335_HPH_AUTO_CHOP,
+				WCD9335_HPH_AUTO_CHOP_MASK,
+				WCD9335_HPH_AUTO_CHOP_ENABLE_BY_CMPDR_GAIN);
+}
+
+static int wcd9335_codec_hphr_dac_event(struct snd_soc_dapm_widget *w,
+				      struct snd_kcontrol *kc,
+				      int event)
+{
+	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+	struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev);
+	int hph_mode = wcd->hph_mode;
+	u8 dem_inp;
+	int ret = 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+
+		/* Read DEM INP Select */
+		dem_inp = snd_soc_component_read32(comp,
+				WCD9335_CDC_RX2_RX_PATH_SEC0) &
+				WCD9335_CDC_RX_PATH_DEM_INP_SEL_MASK;
+		if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) ||
+		     (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) {
+			dev_err(comp->dev, "DEM Input not set correctly, hph_mode: %d\n",
+				hph_mode);
+			return -EINVAL;
+		}
+
+		wcd_clsh_ctrl_set_state(wcd->clsh_ctrl,
+			     WCD_CLSH_EVENT_PRE_DAC,
+			     WCD_CLSH_STATE_HPHR,
+			     ((hph_mode == CLS_H_LOHIFI) ?
+			       CLS_H_HIFI : hph_mode));
+
+		wcd9335_codec_hph_mode_config(comp, event, hph_mode);
+
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* 1000us required as per HW requirement */
+		usleep_range(1000, 1100);
+
+		if (!(wcd_clsh_ctrl_get_state(wcd->clsh_ctrl) &
+					WCD_CLSH_STATE_HPHL))
+			wcd9335_codec_hph_mode_config(comp, event, hph_mode);
+
+		wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA,
+			     WCD_CLSH_STATE_HPHR, ((hph_mode == CLS_H_LOHIFI) ?
+						CLS_H_HIFI : hph_mode));
+		break;
+	};
+
+	return ret;
+}
+
+static int wcd9335_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
+				      struct snd_kcontrol *kc,
+				      int event)
+{
+	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+	struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev);
+	int hph_mode = wcd->hph_mode;
+	int ret = 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/*
+		 * 7ms sleep is required after PA is enabled as per
+		 * HW requirement
+		 */
+		usleep_range(7000, 7100);
+
+		wcd9335_codec_hph_post_pa_config(wcd, hph_mode, event);
+		snd_soc_component_update_bits(comp,
+					WCD9335_CDC_RX1_RX_PATH_CTL,
+					WCD9335_CDC_RX_PGA_MUTE_EN_MASK,
+					WCD9335_CDC_RX_PGA_MUTE_DISABLE);
+
+		/* Remove mix path mute if it is enabled */
+		if ((snd_soc_component_read32(comp,
+					WCD9335_CDC_RX1_RX_PATH_MIX_CTL)) &
+					WCD9335_CDC_RX_PGA_MUTE_EN_MASK)
+			snd_soc_component_update_bits(comp,
+					    WCD9335_CDC_RX1_RX_PATH_MIX_CTL,
+					    WCD9335_CDC_RX_PGA_MUTE_EN_MASK,
+					    WCD9335_CDC_RX_PGA_MUTE_DISABLE);
+
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		wcd9335_codec_hph_post_pa_config(wcd, hph_mode, event);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* 5ms sleep is required after PA is disabled as per
+		 * HW requirement
+		 */
+		usleep_range(5000, 5500);
+		break;
+	};
+
+	return ret;
+}
+
+static int wcd9335_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w,
+					 struct snd_kcontrol *kc,
+					 int event)
+{
+	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+	int vol_reg = 0, mix_vol_reg = 0;
+	int ret = 0;
+
+	if (w->reg == WCD9335_ANA_LO_1_2) {
+		if (w->shift == 7) {
+			vol_reg = WCD9335_CDC_RX3_RX_PATH_CTL;
+			mix_vol_reg = WCD9335_CDC_RX3_RX_PATH_MIX_CTL;
+		} else if (w->shift == 6) {
+			vol_reg = WCD9335_CDC_RX4_RX_PATH_CTL;
+			mix_vol_reg = WCD9335_CDC_RX4_RX_PATH_MIX_CTL;
+		}
+	} else if (w->reg == WCD9335_ANA_LO_3_4) {
+		if (w->shift == 7) {
+			vol_reg = WCD9335_CDC_RX5_RX_PATH_CTL;
+			mix_vol_reg = WCD9335_CDC_RX5_RX_PATH_MIX_CTL;
+		} else if (w->shift == 6) {
+			vol_reg = WCD9335_CDC_RX6_RX_PATH_CTL;
+			mix_vol_reg = WCD9335_CDC_RX6_RX_PATH_MIX_CTL;
+		}
+	} else {
+		dev_err(comp->dev, "Error enabling lineout PA\n");
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* 5ms sleep is required after PA is enabled as per
+		 * HW requirement
+		 */
+		usleep_range(5000, 5500);
+		snd_soc_component_update_bits(comp, vol_reg,
+					WCD9335_CDC_RX_PGA_MUTE_EN_MASK,
+					WCD9335_CDC_RX_PGA_MUTE_DISABLE);
+
+		/* Remove mix path mute if it is enabled */
+		if ((snd_soc_component_read32(comp, mix_vol_reg)) &
+					WCD9335_CDC_RX_PGA_MUTE_EN_MASK)
+			snd_soc_component_update_bits(comp,  mix_vol_reg,
+					WCD9335_CDC_RX_PGA_MUTE_EN_MASK,
+					WCD9335_CDC_RX_PGA_MUTE_DISABLE);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* 5ms sleep is required after PA is disabled as per
+		 * HW requirement
+		 */
+		usleep_range(5000, 5500);
+		break;
+	};
+
+	return ret;
+}
+
+static void wcd9335_codec_init_flyback(struct snd_soc_component *component)
+{
+	snd_soc_component_update_bits(component, WCD9335_HPH_L_EN,
+					WCD9335_HPH_CONST_SEL_L_MASK,
+					WCD9335_HPH_CONST_SEL_L_BYPASS);
+	snd_soc_component_update_bits(component, WCD9335_HPH_R_EN,
+					WCD9335_HPH_CONST_SEL_L_MASK,
+					WCD9335_HPH_CONST_SEL_L_BYPASS);
+	snd_soc_component_update_bits(component, WCD9335_RX_BIAS_FLYB_BUFF,
+					WCD9335_RX_BIAS_FLYB_VPOS_5_UA_MASK,
+					WCD9335_RX_BIAS_FLYB_I_0P0_UA);
+	snd_soc_component_update_bits(component, WCD9335_RX_BIAS_FLYB_BUFF,
+					WCD9335_RX_BIAS_FLYB_VNEG_5_UA_MASK,
+					WCD9335_RX_BIAS_FLYB_I_0P0_UA);
+}
+
+static int wcd9335_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kc, int event)
+{
+	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+	struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd->rx_bias_count++;
+		if (wcd->rx_bias_count == 1) {
+			wcd9335_codec_init_flyback(comp);
+			snd_soc_component_update_bits(comp,
+						WCD9335_ANA_RX_SUPPLIES,
+						WCD9335_ANA_RX_BIAS_ENABLE_MASK,
+						WCD9335_ANA_RX_BIAS_ENABLE);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd->rx_bias_count--;
+		if (!wcd->rx_bias_count)
+			snd_soc_component_update_bits(comp,
+					WCD9335_ANA_RX_SUPPLIES,
+					WCD9335_ANA_RX_BIAS_ENABLE_MASK,
+					WCD9335_ANA_RX_BIAS_DISABLE);
+		break;
+	};
+
+	return 0;
+}
+
+static int wcd9335_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
+					struct snd_kcontrol *kc, int event)
+{
+	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+	struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev);
+	int hph_mode = wcd->hph_mode;
+	int ret = 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/*
+		 * 7ms sleep is required after PA is enabled as per
+		 * HW requirement
+		 */
+		usleep_range(7000, 7100);
+		wcd9335_codec_hph_post_pa_config(wcd, hph_mode, event);
+		snd_soc_component_update_bits(comp,
+					WCD9335_CDC_RX2_RX_PATH_CTL,
+					WCD9335_CDC_RX_PGA_MUTE_EN_MASK,
+					WCD9335_CDC_RX_PGA_MUTE_DISABLE);
+		/* Remove mix path mute if it is enabled */
+		if ((snd_soc_component_read32(comp,
+					WCD9335_CDC_RX2_RX_PATH_MIX_CTL)) &
+					WCD9335_CDC_RX_PGA_MUTE_EN_MASK)
+			snd_soc_component_update_bits(comp,
+					WCD9335_CDC_RX2_RX_PATH_MIX_CTL,
+					WCD9335_CDC_RX_PGA_MUTE_EN_MASK,
+					WCD9335_CDC_RX_PGA_MUTE_DISABLE);
+
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		wcd9335_codec_hph_post_pa_config(wcd, hph_mode, event);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* 5ms sleep is required after PA is disabled as per
+		 * HW requirement
+		 */
+		usleep_range(5000, 5500);
+		break;
+	};
+
+	return ret;
+}
+
+static int wcd9335_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
+				       struct snd_kcontrol *kc, int event)
+{
+	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+	int ret = 0;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* 5ms sleep is required after PA is enabled as per
+		 * HW requirement
+		 */
+		usleep_range(5000, 5500);
+		snd_soc_component_update_bits(comp,
+					WCD9335_CDC_RX0_RX_PATH_CTL,
+					WCD9335_CDC_RX_PGA_MUTE_EN_MASK,
+					WCD9335_CDC_RX_PGA_MUTE_DISABLE);
+		/* Remove mix path mute if it is enabled */
+		if ((snd_soc_component_read32(comp,
+					WCD9335_CDC_RX0_RX_PATH_MIX_CTL)) &
+					WCD9335_CDC_RX_PGA_MUTE_EN_MASK)
+			snd_soc_component_update_bits(comp,
+					WCD9335_CDC_RX0_RX_PATH_MIX_CTL,
+					WCD9335_CDC_RX_PGA_MUTE_EN_MASK,
+					WCD9335_CDC_RX_PGA_MUTE_DISABLE);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		/* 5ms sleep is required after PA is disabled as per
+		 * HW requirement
+		 */
+		usleep_range(5000, 5500);
+
+		break;
+	};
+
+	return ret;
+}
+
 static irqreturn_t wcd9335_slimbus_irq(int irq, void *data)
 {
 	struct wcd9335_codec *wcd = data;
@@ -1368,6 +2877,291 @@ static int _wcd9335_codec_enable_mclk(struct snd_soc_component *component,
 	return 0;
 }
 
+static int wcd9335_codec_enable_mclk(struct snd_soc_dapm_widget *w,
+				     struct snd_kcontrol *kc, int event)
+{
+	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		return _wcd9335_codec_enable_mclk(comp, true);
+	case SND_SOC_DAPM_POST_PMD:
+		return _wcd9335_codec_enable_mclk(comp, false);
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget wcd9335_dapm_widgets[] = {
+	/* TODO SPK1 & SPK2 OUT*/
+	SND_SOC_DAPM_OUTPUT("EAR"),
+	SND_SOC_DAPM_OUTPUT("HPHL"),
+	SND_SOC_DAPM_OUTPUT("HPHR"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT3"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT4"),
+	SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
+				AIF1_PB, 0, wcd9335_codec_enable_slim,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN_E("AIF2 PB", "AIF2 Playback", 0, SND_SOC_NOPM,
+				AIF2_PB, 0, wcd9335_codec_enable_slim,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN_E("AIF3 PB", "AIF3 Playback", 0, SND_SOC_NOPM,
+				AIF3_PB, 0, wcd9335_codec_enable_slim,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_AIF_IN_E("AIF4 PB", "AIF4 Playback", 0, SND_SOC_NOPM,
+				AIF4_PB, 0, wcd9335_codec_enable_slim,
+				SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX("SLIM RX0 MUX", SND_SOC_NOPM, WCD9335_RX0, 0,
+				&slim_rx_mux[WCD9335_RX0]),
+	SND_SOC_DAPM_MUX("SLIM RX1 MUX", SND_SOC_NOPM, WCD9335_RX1, 0,
+				&slim_rx_mux[WCD9335_RX1]),
+	SND_SOC_DAPM_MUX("SLIM RX2 MUX", SND_SOC_NOPM, WCD9335_RX2, 0,
+				&slim_rx_mux[WCD9335_RX2]),
+	SND_SOC_DAPM_MUX("SLIM RX3 MUX", SND_SOC_NOPM, WCD9335_RX3, 0,
+				&slim_rx_mux[WCD9335_RX3]),
+	SND_SOC_DAPM_MUX("SLIM RX4 MUX", SND_SOC_NOPM, WCD9335_RX4, 0,
+				&slim_rx_mux[WCD9335_RX4]),
+	SND_SOC_DAPM_MUX("SLIM RX5 MUX", SND_SOC_NOPM, WCD9335_RX5, 0,
+				&slim_rx_mux[WCD9335_RX5]),
+	SND_SOC_DAPM_MUX("SLIM RX6 MUX", SND_SOC_NOPM, WCD9335_RX6, 0,
+				&slim_rx_mux[WCD9335_RX6]),
+	SND_SOC_DAPM_MUX("SLIM RX7 MUX", SND_SOC_NOPM, WCD9335_RX7, 0,
+				&slim_rx_mux[WCD9335_RX7]),
+	SND_SOC_DAPM_MIXER("SLIM RX0", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM RX6", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("SLIM RX7", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MUX_E("RX INT0_2 MUX", WCD9335_CDC_RX0_RX_PATH_MIX_CTL,
+			5, 0, &rx_int0_2_mux, wcd9335_codec_enable_mix_path,
+			SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MUX_E("RX INT1_2 MUX", WCD9335_CDC_RX1_RX_PATH_MIX_CTL,
+			5, 0, &rx_int1_2_mux, wcd9335_codec_enable_mix_path,
+			SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MUX_E("RX INT2_2 MUX", WCD9335_CDC_RX2_RX_PATH_MIX_CTL,
+			5, 0, &rx_int2_2_mux, wcd9335_codec_enable_mix_path,
+			SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MUX_E("RX INT3_2 MUX", WCD9335_CDC_RX3_RX_PATH_MIX_CTL,
+			5, 0, &rx_int3_2_mux, wcd9335_codec_enable_mix_path,
+			SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MUX_E("RX INT4_2 MUX", WCD9335_CDC_RX4_RX_PATH_MIX_CTL,
+			5, 0, &rx_int4_2_mux, wcd9335_codec_enable_mix_path,
+			SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MUX_E("RX INT5_2 MUX", WCD9335_CDC_RX5_RX_PATH_MIX_CTL,
+			5, 0, &rx_int5_2_mux, wcd9335_codec_enable_mix_path,
+			SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MUX_E("RX INT6_2 MUX", WCD9335_CDC_RX6_RX_PATH_MIX_CTL,
+			5, 0, &rx_int6_2_mux, wcd9335_codec_enable_mix_path,
+			SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MUX_E("RX INT7_2 MUX", WCD9335_CDC_RX7_RX_PATH_MIX_CTL,
+			5, 0, &rx_int7_2_mux, wcd9335_codec_enable_mix_path,
+			SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MUX_E("RX INT8_2 MUX", WCD9335_CDC_RX8_RX_PATH_MIX_CTL,
+			5, 0, &rx_int8_2_mux, wcd9335_codec_enable_mix_path,
+			SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+		&rx_int0_1_mix_inp0_mux),
+	SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_int0_1_mix_inp1_mux),
+	SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_int0_1_mix_inp2_mux),
+	SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+		&rx_int1_1_mix_inp0_mux),
+	SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_int1_1_mix_inp1_mux),
+	SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_int1_1_mix_inp2_mux),
+	SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+		&rx_int2_1_mix_inp0_mux),
+	SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_int2_1_mix_inp1_mux),
+	SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_int2_1_mix_inp2_mux),
+	SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+		&rx_int3_1_mix_inp0_mux),
+	SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_int3_1_mix_inp1_mux),
+	SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_int3_1_mix_inp2_mux),
+	SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+		&rx_int4_1_mix_inp0_mux),
+	SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_int4_1_mix_inp1_mux),
+	SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_int4_1_mix_inp2_mux),
+	SND_SOC_DAPM_MUX("RX INT5_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+		&rx_int5_1_mix_inp0_mux),
+	SND_SOC_DAPM_MUX("RX INT5_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_int5_1_mix_inp1_mux),
+	SND_SOC_DAPM_MUX("RX INT5_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_int5_1_mix_inp2_mux),
+	SND_SOC_DAPM_MUX("RX INT6_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+		&rx_int6_1_mix_inp0_mux),
+	SND_SOC_DAPM_MUX("RX INT6_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_int6_1_mix_inp1_mux),
+	SND_SOC_DAPM_MUX("RX INT6_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_int6_1_mix_inp2_mux),
+	SND_SOC_DAPM_MUX("RX INT7_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+		&rx_int7_1_mix_inp0_mux),
+	SND_SOC_DAPM_MUX("RX INT7_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_int7_1_mix_inp1_mux),
+	SND_SOC_DAPM_MUX("RX INT7_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_int7_1_mix_inp2_mux),
+	SND_SOC_DAPM_MUX("RX INT8_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+		&rx_int8_1_mix_inp0_mux),
+	SND_SOC_DAPM_MUX("RX INT8_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+		&rx_int8_1_mix_inp1_mux),
+	SND_SOC_DAPM_MUX("RX INT8_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+		&rx_int8_1_mix_inp2_mux),
+
+	SND_SOC_DAPM_MIXER("RX INT0_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT1_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT2_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT2 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT3_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT3 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT4_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT4 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT5_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT5 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT6_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT6 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT7_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT7 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT8_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT8 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIXER("RX INT0 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT1 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT2 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT3 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT4 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT5 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT6 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT7 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+	SND_SOC_DAPM_MIXER("RX INT8 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_MUX("RX INT0 DEM MUX", SND_SOC_NOPM, 0, 0,
+		&rx_int0_dem_inp_mux),
+	SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0,
+		&rx_int1_dem_inp_mux),
+	SND_SOC_DAPM_MUX("RX INT2 DEM MUX", SND_SOC_NOPM, 0, 0,
+		&rx_int2_dem_inp_mux),
+
+	SND_SOC_DAPM_MUX_E("RX INT0 INTERP", SND_SOC_NOPM,
+		INTERP_EAR, 0, &rx_int0_interp_mux,
+		wcd9335_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT1 INTERP", SND_SOC_NOPM,
+		INTERP_HPHL, 0, &rx_int1_interp_mux,
+		wcd9335_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT2 INTERP", SND_SOC_NOPM,
+		INTERP_HPHR, 0, &rx_int2_interp_mux,
+		wcd9335_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT3 INTERP", SND_SOC_NOPM,
+		INTERP_LO1, 0, &rx_int3_interp_mux,
+		wcd9335_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT4 INTERP", SND_SOC_NOPM,
+		INTERP_LO2, 0, &rx_int4_interp_mux,
+		wcd9335_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT5 INTERP", SND_SOC_NOPM,
+		INTERP_LO3, 0, &rx_int5_interp_mux,
+		wcd9335_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT6 INTERP", SND_SOC_NOPM,
+		INTERP_LO4, 0, &rx_int6_interp_mux,
+		wcd9335_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT7 INTERP", SND_SOC_NOPM,
+		INTERP_SPKR1, 0, &rx_int7_interp_mux,
+		wcd9335_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_MUX_E("RX INT8 INTERP", SND_SOC_NOPM,
+		INTERP_SPKR2, 0, &rx_int8_interp_mux,
+		wcd9335_codec_enable_interpolator,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_DAC_E("RX INT0 DAC", NULL, SND_SOC_NOPM,
+		0, 0, wcd9335_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("RX INT1 DAC", NULL, WCD9335_ANA_HPH,
+		5, 0, wcd9335_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("RX INT2 DAC", NULL, WCD9335_ANA_HPH,
+		4, 0, wcd9335_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("RX INT3 DAC", NULL, SND_SOC_NOPM,
+		0, 0, wcd9335_codec_lineout_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_DAC_E("RX INT4 DAC", NULL, SND_SOC_NOPM,
+		0, 0, wcd9335_codec_lineout_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_DAC_E("RX INT5 DAC", NULL, SND_SOC_NOPM,
+		0, 0, wcd9335_codec_lineout_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_DAC_E("RX INT6 DAC", NULL, SND_SOC_NOPM,
+		0, 0, wcd9335_codec_lineout_dac_event,
+		SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("HPHL PA", WCD9335_ANA_HPH, 7, 0, NULL, 0,
+			   wcd9335_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 PA", WCD9335_ANA_HPH, 6, 0, NULL, 0,
+			   wcd9335_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_PGA_E("EAR PA", WCD9335_ANA_EAR, 7, 0, NULL, 0,
+			   wcd9335_codec_enable_ear_pa,
+			   SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LINEOUT1 PA", WCD9335_ANA_LO_1_2, 7, 0, NULL, 0,
+			   wcd9335_codec_enable_lineout_pa,
+			   SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LINEOUT2 PA", WCD9335_ANA_LO_1_2, 6, 0, NULL, 0,
+			   wcd9335_codec_enable_lineout_pa,
+			   SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LINEOUT3 PA", WCD9335_ANA_LO_3_4, 7, 0, NULL, 0,
+			   wcd9335_codec_enable_lineout_pa,
+			   SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("LINEOUT4 PA", WCD9335_ANA_LO_3_4, 6, 0, NULL, 0,
+			   wcd9335_codec_enable_lineout_pa,
+			   SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
+		wcd9335_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SUPPLY("MCLK",  SND_SOC_NOPM, 0, 0,
+		wcd9335_codec_enable_mclk, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+};
+
 static void wcd9335_enable_sido_buck(struct snd_soc_component *component)
 {
 	struct wcd9335_codec *wcd = dev_get_drvdata(component->dev);
@@ -1493,6 +3287,8 @@ static const struct snd_soc_component_driver wcd9335_component_drv = {
 	.set_sysclk = wcd9335_codec_set_sysclk,
 	.controls = wcd9335_snd_controls,
 	.num_controls = ARRAY_SIZE(wcd9335_snd_controls),
+	.dapm_widgets = wcd9335_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wcd9335_dapm_widgets),
 };
 
 static int wcd9335_probe(struct platform_device *pdev)
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v4 08/14] ASoC: wcd9335: add capture dapm widgets
  2018-09-17  0:57 [PATCH v4 00/14] ASoC: Add support to WCD9335 Audio Codec srinivas.kandagatla
                   ` (6 preceding siblings ...)
  2018-09-17  0:57 ` [PATCH v4 07/14] ASoC: wcd9335: add playback dapm widgets srinivas.kandagatla
@ 2018-09-17  0:57 ` srinivas.kandagatla
  2018-09-17  0:57 ` [PATCH v4 09/14] ASoC: wcd9335: add audio routings srinivas.kandagatla
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: srinivas.kandagatla @ 2018-09-17  0:57 UTC (permalink / raw)
  To: lee.jones, robh+dt, broonie
  Cc: mark.rutland, lgirdwood, bgoswami, devicetree, linux-kernel,
	vkoul, alsa-devel, Srinivas Kandagatla

From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

This patch adds required dapm widgets for capture path.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Reviewed-by: Vinod Koul <vkoul@kernel.org>
---
 sound/soc/codecs/wcd9335.c | 1449 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 1448 insertions(+), 1 deletion(-)

diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 9732675..86a15b1 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -58,10 +58,43 @@
 #define WCD9335_NUM_INTERPOLATORS 9
 #define WCD9335_RX_START	16
 #define WCD9335_SLIM_CH_START 128
+#define WCD9335_MAX_MICBIAS 4
+#define WCD9335_MAX_VALID_ADC_MUX  13
+#define WCD9335_INVALID_ADC_MUX 9
+
+#define  TX_HPF_CUT_OFF_FREQ_MASK	0x60
+#define  CF_MIN_3DB_4HZ			0x0
+#define  CF_MIN_3DB_75HZ		0x1
+#define  CF_MIN_3DB_150HZ		0x2
+#define WCD9335_DMIC_CLK_DIV_2  0x0
+#define WCD9335_DMIC_CLK_DIV_3  0x1
+#define WCD9335_DMIC_CLK_DIV_4  0x2
+#define WCD9335_DMIC_CLK_DIV_6  0x3
+#define WCD9335_DMIC_CLK_DIV_8  0x4
+#define WCD9335_DMIC_CLK_DIV_16  0x5
+#define WCD9335_DMIC_CLK_DRIVE_DEFAULT 0x02
+#define WCD9335_AMIC_PWR_LEVEL_LP 0
+#define WCD9335_AMIC_PWR_LEVEL_DEFAULT 1
+#define WCD9335_AMIC_PWR_LEVEL_HP 2
+#define WCD9335_AMIC_PWR_LVL_MASK 0x60
+#define WCD9335_AMIC_PWR_LVL_SHIFT 0x5
+
+#define WCD9335_DEC_PWR_LVL_MASK 0x06
+#define WCD9335_DEC_PWR_LVL_LP 0x02
+#define WCD9335_DEC_PWR_LVL_HP 0x04
+#define WCD9335_DEC_PWR_LVL_DF 0x00
+
+#define  TX_HPF_CUT_OFF_FREQ_MASK	0x60
+#define  CF_MIN_3DB_4HZ			0x0
+#define  CF_MIN_3DB_75HZ		0x1
+#define  CF_MIN_3DB_150HZ		0x2
 
 #define WCD9335_SLIM_RX_CH(p) \
 	{.port = p + WCD9335_RX_START, .shift = p,}
 
+#define WCD9335_SLIM_TX_CH(p) \
+	{.port = p, .shift = p,}
+
 /* vout step value */
 #define WCD9335_CALCULATE_VOUT_D(req_mv) (((req_mv - 650) * 10) / 25)
 
@@ -83,6 +116,26 @@ enum {
 };
 
 enum {
+	WCD9335_TX0 = 0,
+	WCD9335_TX1,
+	WCD9335_TX2,
+	WCD9335_TX3,
+	WCD9335_TX4,
+	WCD9335_TX5,
+	WCD9335_TX6,
+	WCD9335_TX7,
+	WCD9335_TX8,
+	WCD9335_TX9,
+	WCD9335_TX10,
+	WCD9335_TX11,
+	WCD9335_TX12,
+	WCD9335_TX13,
+	WCD9335_TX14,
+	WCD9335_TX15,
+	WCD9335_TX_MAX,
+};
+
+enum {
 	SIDO_SOURCE_INTERNAL = 0,
 	SIDO_SOURCE_RCO_BG,
 };
@@ -163,6 +216,20 @@ enum wcd_clock_type {
 	WCD_CLK_MCLK,
 };
 
+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,
+};
+
 struct wcd9335_slim_ch {
 	u32 ch_num;
 	u16 port;
@@ -191,7 +258,9 @@ struct wcd9335_codec {
 	struct regmap_irq_chip_data *irq_data;
 
 	struct wcd9335_slim_ch rx_chs[WCD9335_RX_MAX];
+	struct wcd9335_slim_ch tx_chs[WCD9335_TX_MAX];
 	u32 num_rx_port;
+	u32 num_tx_port;
 
 	int sido_input_src;
 	enum wcd9335_sido_voltage sido_voltage;
@@ -212,9 +281,22 @@ struct wcd9335_codec {
 	int comp_enabled[COMPANDER_MAX];
 
 	unsigned int rx_port_value;
+	unsigned int tx_port_value;
 	int hph_l_gain;
 	int hph_r_gain;
 	u32 rx_bias_count;
+
+	/*TX*/
+	int micb_ref[WCD9335_MAX_MICBIAS];
+	int pullup_ref[WCD9335_MAX_MICBIAS];
+
+	int dmic_0_1_clk_cnt;
+	int dmic_2_3_clk_cnt;
+	int dmic_4_5_clk_cnt;
+	int dmic_sample_rate;
+	int mad_dmic_sample_rate;
+
+	int native_clk_users;
 };
 
 struct wcd9335_irq {
@@ -223,6 +305,25 @@ struct wcd9335_irq {
 	char *name;
 };
 
+static const struct wcd9335_slim_ch wcd9335_tx_chs[WCD9335_TX_MAX] = {
+	WCD9335_SLIM_TX_CH(0),
+	WCD9335_SLIM_TX_CH(1),
+	WCD9335_SLIM_TX_CH(2),
+	WCD9335_SLIM_TX_CH(3),
+	WCD9335_SLIM_TX_CH(4),
+	WCD9335_SLIM_TX_CH(5),
+	WCD9335_SLIM_TX_CH(6),
+	WCD9335_SLIM_TX_CH(7),
+	WCD9335_SLIM_TX_CH(8),
+	WCD9335_SLIM_TX_CH(9),
+	WCD9335_SLIM_TX_CH(10),
+	WCD9335_SLIM_TX_CH(11),
+	WCD9335_SLIM_TX_CH(12),
+	WCD9335_SLIM_TX_CH(13),
+	WCD9335_SLIM_TX_CH(14),
+	WCD9335_SLIM_TX_CH(15),
+};
+
 static const struct wcd9335_slim_ch wcd9335_rx_chs[WCD9335_RX_MAX] = {
 	WCD9335_SLIM_RX_CH(0),	 /* 16 */
 	WCD9335_SLIM_RX_CH(1),	 /* 17 */
@@ -407,6 +508,59 @@ static const char *const slim_rx_mux_text[] = {
 	"ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB",
 };
 
+static const char * const adc_mux_text[] = {
+	"DMIC", "AMIC", "ANC_FB_TUNE1", "ANC_FB_TUNE2"
+};
+
+static const char * const dmic_mux_text[] = {
+	"ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5",
+	"SMIC0", "SMIC1", "SMIC2", "SMIC3"
+};
+
+static const char * const dmic_mux_alt_text[] = {
+	"ZERO", "DMIC0", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5",
+};
+
+static const char * const amic_mux_text[] = {
+	"ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6"
+};
+
+static const char * const sb_tx0_mux_text[] = {
+	"ZERO", "RX_MIX_TX0", "DEC0", "DEC0_192"
+};
+
+static const char * const sb_tx1_mux_text[] = {
+	"ZERO", "RX_MIX_TX1", "DEC1", "DEC1_192"
+};
+
+static const char * const sb_tx2_mux_text[] = {
+	"ZERO", "RX_MIX_TX2", "DEC2", "DEC2_192"
+};
+
+static const char * const sb_tx3_mux_text[] = {
+	"ZERO", "RX_MIX_TX3", "DEC3", "DEC3_192"
+};
+
+static const char * const sb_tx4_mux_text[] = {
+	"ZERO", "RX_MIX_TX4", "DEC4", "DEC4_192"
+};
+
+static const char * const sb_tx5_mux_text[] = {
+	"ZERO", "RX_MIX_TX5", "DEC5", "DEC5_192"
+};
+
+static const char * const sb_tx6_mux_text[] = {
+	"ZERO", "RX_MIX_TX6", "DEC6", "DEC6_192"
+};
+
+static const char * const sb_tx7_mux_text[] = {
+	"ZERO", "RX_MIX_TX7", "DEC7", "DEC7_192"
+};
+
+static const char * const sb_tx8_mux_text[] = {
+	"ZERO", "RX_MIX_TX8", "DEC8", "DEC8_192"
+};
+
 static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
 static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
 static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
@@ -698,6 +852,150 @@ static const struct soc_enum rx_int8_interp_mux_enum =
 	SOC_ENUM_SINGLE(WCD9335_CDC_RX8_RX_PATH_CTL, 5, 2,
 			rx_int8_interp_mux_text);
 
+static const struct soc_enum tx_adc_mux0_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1, 0, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_adc_mux1_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1, 0, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_adc_mux2_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1, 0, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_adc_mux3_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1, 0, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_adc_mux4_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 6, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_adc_mux5_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 6, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_adc_mux6_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 6, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_adc_mux7_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 6, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_adc_mux8_chain_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 6, 4,
+			adc_mux_text);
+
+static const struct soc_enum tx_dmic_mux0_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 3, 11,
+			dmic_mux_text);
+
+static const struct soc_enum tx_dmic_mux1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 3, 11,
+			dmic_mux_text);
+
+static const struct soc_enum tx_dmic_mux2_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 3, 11,
+			dmic_mux_text);
+
+static const struct soc_enum tx_dmic_mux3_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 3, 11,
+			dmic_mux_text);
+
+static const struct soc_enum tx_dmic_mux4_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 3, 7,
+			dmic_mux_alt_text);
+
+static const struct soc_enum tx_dmic_mux5_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 3, 7,
+			dmic_mux_alt_text);
+
+static const struct soc_enum tx_dmic_mux6_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 3, 7,
+			dmic_mux_alt_text);
+
+static const struct soc_enum tx_dmic_mux7_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 3, 7,
+			dmic_mux_alt_text);
+
+static const struct soc_enum tx_dmic_mux8_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 3, 7,
+			dmic_mux_alt_text);
+
+static const struct soc_enum tx_amic_mux0_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum tx_amic_mux1_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum tx_amic_mux2_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum tx_amic_mux3_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum tx_amic_mux4_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum tx_amic_mux5_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum tx_amic_mux6_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum tx_amic_mux7_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum tx_amic_mux8_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0, 0, 7,
+			amic_mux_text);
+
+static const struct soc_enum sb_tx0_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 0, 4,
+			sb_tx0_mux_text);
+
+static const struct soc_enum sb_tx1_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 2, 4,
+			sb_tx1_mux_text);
+
+static const struct soc_enum sb_tx2_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 4, 4,
+			sb_tx2_mux_text);
+
+static const struct soc_enum sb_tx3_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0, 6, 4,
+			sb_tx3_mux_text);
+
+static const struct soc_enum sb_tx4_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 0, 4,
+			sb_tx4_mux_text);
+
+static const struct soc_enum sb_tx5_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 2, 4,
+			sb_tx5_mux_text);
+
+static const struct soc_enum sb_tx6_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 4, 4,
+			sb_tx6_mux_text);
+
+static const struct soc_enum sb_tx7_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1, 6, 4,
+			sb_tx7_mux_text);
+
+static const struct soc_enum sb_tx8_mux_enum =
+	SOC_ENUM_SINGLE(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2, 0, 4,
+			sb_tx8_mux_text);
+
 static const struct snd_kcontrol_new rx_int0_2_mux =
 	SOC_DAPM_ENUM("RX INT0_2 MUX Mux", rx_int0_2_mux_chain_enum);
 
@@ -833,6 +1131,87 @@ static const struct snd_kcontrol_new rx_int7_interp_mux =
 static const struct snd_kcontrol_new rx_int8_interp_mux =
 	SOC_DAPM_ENUM("RX INT8 INTERP Mux", rx_int8_interp_mux_enum);
 
+static const struct snd_kcontrol_new tx_dmic_mux0 =
+	SOC_DAPM_ENUM("DMIC MUX0 Mux", tx_dmic_mux0_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux1 =
+	SOC_DAPM_ENUM("DMIC MUX1 Mux", tx_dmic_mux1_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux2 =
+	SOC_DAPM_ENUM("DMIC MUX2 Mux", tx_dmic_mux2_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux3 =
+	SOC_DAPM_ENUM("DMIC MUX3 Mux", tx_dmic_mux3_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux4 =
+	SOC_DAPM_ENUM("DMIC MUX4 Mux", tx_dmic_mux4_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux5 =
+	SOC_DAPM_ENUM("DMIC MUX5 Mux", tx_dmic_mux5_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux6 =
+	SOC_DAPM_ENUM("DMIC MUX6 Mux", tx_dmic_mux6_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux7 =
+	SOC_DAPM_ENUM("DMIC MUX7 Mux", tx_dmic_mux7_enum);
+
+static const struct snd_kcontrol_new tx_dmic_mux8 =
+	SOC_DAPM_ENUM("DMIC MUX8 Mux", tx_dmic_mux8_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux0 =
+	SOC_DAPM_ENUM("AMIC MUX0 Mux", tx_amic_mux0_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux1 =
+	SOC_DAPM_ENUM("AMIC MUX1 Mux", tx_amic_mux1_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux2 =
+	SOC_DAPM_ENUM("AMIC MUX2 Mux", tx_amic_mux2_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux3 =
+	SOC_DAPM_ENUM("AMIC MUX3 Mux", tx_amic_mux3_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux4 =
+	SOC_DAPM_ENUM("AMIC MUX4 Mux", tx_amic_mux4_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux5 =
+	SOC_DAPM_ENUM("AMIC MUX5 Mux", tx_amic_mux5_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux6 =
+	SOC_DAPM_ENUM("AMIC MUX6 Mux", tx_amic_mux6_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux7 =
+	SOC_DAPM_ENUM("AMIC MUX7 Mux", tx_amic_mux7_enum);
+
+static const struct snd_kcontrol_new tx_amic_mux8 =
+	SOC_DAPM_ENUM("AMIC MUX8 Mux", tx_amic_mux8_enum);
+
+static const struct snd_kcontrol_new sb_tx0_mux =
+	SOC_DAPM_ENUM("SLIM TX0 MUX Mux", sb_tx0_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx1_mux =
+	SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx2_mux =
+	SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx3_mux =
+	SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx4_mux =
+	SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx5_mux =
+	SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx6_mux =
+	SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx7_mux =
+	SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx8_mux =
+	SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
+
 static int slim_rx_mux_get(struct snd_kcontrol *kc,
 			   struct snd_ctl_elem_value *ucontrol)
 {
@@ -888,6 +1267,55 @@ static int slim_rx_mux_put(struct snd_kcontrol *kc,
 	return -EINVAL;
 }
 
+static int slim_tx_mixer_get(struct snd_kcontrol *kc,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc);
+	struct wcd9335_codec *wcd = dev_get_drvdata(dapm->dev);
+
+	ucontrol->value.integer.value[0] = wcd->tx_port_value;
+
+	return 0;
+}
+
+static int slim_tx_mixer_put(struct snd_kcontrol *kc,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+
+	struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kc);
+	struct wcd9335_codec *wcd = dev_get_drvdata(widget->dapm->dev);
+	struct snd_soc_dapm_update *update = NULL;
+	struct soc_mixer_control *mixer =
+			(struct soc_mixer_control *)kc->private_value;
+	int enable = ucontrol->value.integer.value[0];
+	int dai_id = widget->shift;
+	int port_id = mixer->shift;
+
+	switch (dai_id) {
+	case AIF1_CAP:
+	case AIF2_CAP:
+	case AIF3_CAP:
+		/* only add to the list if value not set */
+		if (enable && !(wcd->tx_port_value & BIT(port_id))) {
+			wcd->tx_port_value |= BIT(port_id);
+			list_add_tail(&wcd->tx_chs[port_id].list,
+					&wcd->dai[dai_id].slim_ch_list);
+		} else if (!enable && (wcd->tx_port_value & BIT(port_id))) {
+			wcd->tx_port_value &= ~BIT(port_id);
+			list_del_init(&wcd->tx_chs[port_id].list);
+		}
+		break;
+	default:
+		dev_err(wcd->dev, "Unknown AIF %d\n", dai_id);
+		return -EINVAL;
+	}
+
+	snd_soc_dapm_mixer_update_power(widget->dapm, kc, enable, update);
+
+	return 0;
+}
+
 static const struct snd_kcontrol_new slim_rx_mux[WCD9335_RX_MAX] = {
 	SOC_DAPM_ENUM_EXT("SLIM RX0 Mux", slim_rx_mux_enum,
 			  slim_rx_mux_get, slim_rx_mux_put),
@@ -907,6 +1335,136 @@ static const struct snd_kcontrol_new slim_rx_mux[WCD9335_RX_MAX] = {
 			  slim_rx_mux_get, slim_rx_mux_put),
 };
 
+static const struct snd_kcontrol_new aif1_cap_mixer[] = {
+	SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD9335_TX0, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD9335_TX1, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD9335_TX2, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD9335_TX3, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD9335_TX4, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD9335_TX5, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD9335_TX6, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD9335_TX7, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD9335_TX8, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, WCD9335_TX9, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, WCD9335_TX10, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, WCD9335_TX11, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD9335_TX13, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new aif2_cap_mixer[] = {
+	SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD9335_TX0, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD9335_TX1, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD9335_TX2, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD9335_TX3, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD9335_TX4, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD9335_TX5, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD9335_TX6, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD9335_TX7, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD9335_TX8, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, WCD9335_TX9, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, WCD9335_TX10, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX11", SND_SOC_NOPM, WCD9335_TX11, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX13", SND_SOC_NOPM, WCD9335_TX13, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+};
+
+static const struct snd_kcontrol_new aif3_cap_mixer[] = {
+	SOC_SINGLE_EXT("SLIM TX0", SND_SOC_NOPM, WCD9335_TX0, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, WCD9335_TX1, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, WCD9335_TX2, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, WCD9335_TX3, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, WCD9335_TX4, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, WCD9335_TX5, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, WCD9335_TX6, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, WCD9335_TX7, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+	SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, WCD9335_TX8, 1, 0,
+			slim_tx_mixer_get, slim_tx_mixer_put),
+};
+
+static int wcd9335_put_dec_enum(struct snd_kcontrol *kc,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc);
+	struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+	struct soc_enum *e = (struct soc_enum *)kc->private_value;
+	unsigned int val, reg, sel;
+
+	val = ucontrol->value.enumerated.item[0];
+
+	switch (e->reg) {
+	case WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1:
+		reg = WCD9335_CDC_TX0_TX_PATH_CFG0;
+		break;
+	case WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1:
+		reg = WCD9335_CDC_TX1_TX_PATH_CFG0;
+		break;
+	case WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1:
+		reg = WCD9335_CDC_TX2_TX_PATH_CFG0;
+		break;
+	case WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1:
+		reg = WCD9335_CDC_TX3_TX_PATH_CFG0;
+		break;
+	case WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0:
+		reg = WCD9335_CDC_TX4_TX_PATH_CFG0;
+		break;
+	case WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0:
+		reg = WCD9335_CDC_TX5_TX_PATH_CFG0;
+		break;
+	case WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0:
+		reg = WCD9335_CDC_TX6_TX_PATH_CFG0;
+		break;
+	case WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0:
+		reg = WCD9335_CDC_TX7_TX_PATH_CFG0;
+		break;
+	case WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0:
+		reg = WCD9335_CDC_TX8_TX_PATH_CFG0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* AMIC: 0, DMIC: 1 */
+	sel = val ? WCD9335_CDC_TX_ADC_AMIC_SEL : WCD9335_CDC_TX_ADC_DMIC_SEL;
+	snd_soc_component_update_bits(component, reg,
+				      WCD9335_CDC_TX_ADC_AMIC_DMIC_SEL_MASK,
+				      sel);
+
+	return snd_soc_dapm_put_enum_double(kc, ucontrol);
+}
+
 static int wcd9335_int_dem_inp_mux_put(struct snd_kcontrol *kc,
 				 struct snd_ctl_elem_value *ucontrol)
 {
@@ -949,6 +1507,51 @@ static const struct snd_kcontrol_new rx_int2_dem_inp_mux =
 			  snd_soc_dapm_get_enum_double,
 			  wcd9335_int_dem_inp_mux_put);
 
+static const struct snd_kcontrol_new tx_adc_mux0 =
+	SOC_DAPM_ENUM_EXT("ADC MUX0 Mux", tx_adc_mux0_chain_enum,
+			  snd_soc_dapm_get_enum_double,
+			  wcd9335_put_dec_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux1 =
+	SOC_DAPM_ENUM_EXT("ADC MUX1 Mux", tx_adc_mux1_chain_enum,
+			  snd_soc_dapm_get_enum_double,
+			  wcd9335_put_dec_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux2 =
+	SOC_DAPM_ENUM_EXT("ADC MUX2 Mux", tx_adc_mux2_chain_enum,
+			  snd_soc_dapm_get_enum_double,
+			  wcd9335_put_dec_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux3 =
+	SOC_DAPM_ENUM_EXT("ADC MUX3 Mux", tx_adc_mux3_chain_enum,
+			  snd_soc_dapm_get_enum_double,
+			  wcd9335_put_dec_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux4 =
+	SOC_DAPM_ENUM_EXT("ADC MUX4 Mux", tx_adc_mux4_chain_enum,
+			  snd_soc_dapm_get_enum_double,
+			  wcd9335_put_dec_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux5 =
+	SOC_DAPM_ENUM_EXT("ADC MUX5 Mux", tx_adc_mux5_chain_enum,
+			  snd_soc_dapm_get_enum_double,
+			  wcd9335_put_dec_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux6 =
+	SOC_DAPM_ENUM_EXT("ADC MUX6 Mux", tx_adc_mux6_chain_enum,
+			  snd_soc_dapm_get_enum_double,
+			  wcd9335_put_dec_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux7 =
+	SOC_DAPM_ENUM_EXT("ADC MUX7 Mux", tx_adc_mux7_chain_enum,
+			  snd_soc_dapm_get_enum_double,
+			  wcd9335_put_dec_enum);
+
+static const struct snd_kcontrol_new tx_adc_mux8 =
+	SOC_DAPM_ENUM_EXT("ADC MUX8 Mux", tx_adc_mux8_chain_enum,
+			  snd_soc_dapm_get_enum_double,
+			  wcd9335_put_dec_enum);
+
 static int wcd9335_set_mix_interpolator_rate(struct snd_soc_dai *dai,
 					     int rate_val,
 					     u32 rate)
@@ -1091,6 +1694,27 @@ static int wcd9335_slim_set_hw_params(struct wcd9335_codec *wcd,
 					WCD9335_SLIM_WATER_MARK_VAL);
 			if (ret < 0)
 				goto err;
+		} else {
+			ret = regmap_write(wcd->if_regmap,
+				WCD9335_SLIM_PGD_TX_PORT_MULTI_CHNL_0(ch->port),
+				payload & 0x00FF);
+			if (ret < 0)
+				goto err;
+
+			/* ports 8,9 */
+			ret = regmap_write(wcd->if_regmap,
+				WCD9335_SLIM_PGD_TX_PORT_MULTI_CHNL_1(ch->port),
+				(payload & 0xFF00)>>8);
+			if (ret < 0)
+				goto err;
+
+			/* configure the slave port for water mark and enable*/
+			ret = regmap_write(wcd->if_regmap,
+					WCD9335_SLIM_PGD_TX_PORT_CFG(ch->port),
+					WCD9335_SLIM_WATER_MARK_VAL);
+
+			if (ret < 0)
+				goto err;
 		}
 	}
 
@@ -1107,12 +1731,91 @@ static int wcd9335_slim_set_hw_params(struct wcd9335_codec *wcd,
 	return ret;
 }
 
+static int wcd9335_set_decimator_rate(struct snd_soc_dai *dai,
+				      u8 rate_val, u32 rate)
+{
+	struct snd_soc_component *comp = dai->component;
+	struct wcd9335_codec *wcd = snd_soc_component_get_drvdata(comp);
+	u8 shift = 0, shift_val = 0, tx_mux_sel;
+	struct wcd9335_slim_ch *ch;
+	int tx_port, tx_port_reg;
+	int decimator = -1;
+
+	list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) {
+		tx_port = ch->port;
+		if ((tx_port == 12) || (tx_port >= 14)) {
+			dev_err(wcd->dev, "Invalid SLIM TX%u port DAI ID:%d\n",
+				tx_port, dai->id);
+			return -EINVAL;
+		}
+		/* Find the SB TX MUX input - which decimator is connected */
+		if (tx_port < 4) {
+			tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0;
+			shift = (tx_port << 1);
+			shift_val = 0x03;
+		} else if ((tx_port >= 4) && (tx_port < 8)) {
+			tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1;
+			shift = ((tx_port - 4) << 1);
+			shift_val = 0x03;
+		} else if ((tx_port >= 8) && (tx_port < 11)) {
+			tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2;
+			shift = ((tx_port - 8) << 1);
+			shift_val = 0x03;
+		} else if (tx_port == 11) {
+			tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3;
+			shift = 0;
+			shift_val = 0x0F;
+		} else if (tx_port == 13) {
+			tx_port_reg = WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3;
+			shift = 4;
+			shift_val = 0x03;
+		} else {
+			return -EINVAL;
+		}
+
+		tx_mux_sel = snd_soc_component_read32(comp, tx_port_reg) &
+						      (shift_val << shift);
+
+		tx_mux_sel = tx_mux_sel >> shift;
+		if (tx_port <= 8) {
+			if ((tx_mux_sel == 0x2) || (tx_mux_sel == 0x3))
+				decimator = tx_port;
+		} else if (tx_port <= 10) {
+			if ((tx_mux_sel == 0x1) || (tx_mux_sel == 0x2))
+				decimator = ((tx_port == 9) ? 7 : 6);
+		} else if (tx_port == 11) {
+			if ((tx_mux_sel >= 1) && (tx_mux_sel < 7))
+				decimator = tx_mux_sel - 1;
+		} else if (tx_port == 13) {
+			if ((tx_mux_sel == 0x1) || (tx_mux_sel == 0x2))
+				decimator = 5;
+		}
+
+		if (decimator >= 0) {
+			snd_soc_component_update_bits(comp,
+					WCD9335_CDC_TX_PATH_CTL(decimator),
+					WCD9335_CDC_TX_PATH_CTL_PCM_RATE_MASK,
+					rate_val);
+		} else if ((tx_port <= 8) && (tx_mux_sel == 0x01)) {
+			/* Check if the TX Mux input is RX MIX TXn */
+			dev_err(wcd->dev, "RX_MIX_TX%u going to SLIM TX%u\n",
+				tx_port, tx_port);
+		} else {
+			dev_err(wcd->dev, "ERROR: Invalid decimator: %d\n",
+				decimator);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int wcd9335_hw_params(struct snd_pcm_substream *substream,
 			   struct snd_pcm_hw_params *params,
 			   struct snd_soc_dai *dai)
 {
 	struct wcd9335_codec *wcd;
-	int ret;
+	int ret, tx_fs_rate = 0;
 
 	wcd = snd_soc_component_get_drvdata(dai->component);
 
@@ -1134,6 +1837,53 @@ static int wcd9335_hw_params(struct snd_pcm_substream *substream,
 			return -EINVAL;
 		}
 		break;
+
+	case SNDRV_PCM_STREAM_CAPTURE:
+		switch (params_rate(params)) {
+		case 8000:
+			tx_fs_rate = 0;
+			break;
+		case 16000:
+			tx_fs_rate = 1;
+			break;
+		case 32000:
+			tx_fs_rate = 3;
+			break;
+		case 48000:
+			tx_fs_rate = 4;
+			break;
+		case 96000:
+			tx_fs_rate = 5;
+			break;
+		case 192000:
+			tx_fs_rate = 6;
+			break;
+		case 384000:
+			tx_fs_rate = 7;
+			break;
+		default:
+			dev_err(wcd->dev, "%s: Invalid TX sample rate: %d\n",
+				__func__, params_rate(params));
+			return -EINVAL;
+
+		};
+
+		ret = wcd9335_set_decimator_rate(dai, tx_fs_rate,
+						params_rate(params));
+		if (ret < 0) {
+			dev_err(wcd->dev, "Cannot set TX Decimator rate\n");
+			return ret;
+		}
+		switch (params_width(params)) {
+		case 16 ... 32:
+			wcd->dai[dai->id].sconfig.bps = params_width(params);
+			break;
+		default:
+			dev_err(wcd->dev, "%s: Invalid format 0x%x\n",
+				__func__, params_width(params));
+			return -EINVAL;
+		};
+		break;
 	default:
 		dev_err(wcd->dev, "Invalid stream type %d\n",
 			substream->stream);
@@ -1182,6 +1932,14 @@ static int wcd9335_set_channel_map(struct snd_soc_dai *dai,
 		}
 	}
 
+	if (wcd->tx_chs) {
+		wcd->num_tx_port = tx_num;
+		for (i = 0; i < tx_num; i++) {
+			wcd->tx_chs[i].ch_num = tx_slot[i];
+			INIT_LIST_HEAD(&wcd->tx_chs[i].list);
+		}
+	}
+
 	return 0;
 }
 
@@ -1211,6 +1969,19 @@ static int wcd9335_get_channel_map(struct snd_soc_dai *dai,
 
 		*rx_num = i;
 		break;
+	case AIF1_CAP:
+	case AIF2_CAP:
+	case AIF3_CAP:
+		if (!tx_slot || !tx_num) {
+			dev_err(wcd->dev, "Invalid tx_slot %p or tx_num %p\n",
+				tx_slot, tx_num);
+			return -EINVAL;
+		}
+		list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list)
+			tx_slot[i++] = ch->ch_num;
+
+		*tx_num = i;
+		break;
 	default:
 		dev_err(wcd->dev, "Invalid DAI ID %x\n", dai->id);
 		break;
@@ -1558,6 +2329,496 @@ static const struct snd_kcontrol_new wcd9335_snd_controls[] = {
 	SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
 };
 
+static int wcd9335_micbias_control(struct snd_soc_component *component,
+				   int micb_num, int req, bool is_dapm)
+{
+	struct wcd9335_codec *wcd = snd_soc_component_get_drvdata(component);
+	int micb_index = micb_num - 1;
+	u16 micb_reg;
+
+	if ((micb_index < 0) || (micb_index > WCD9335_MAX_MICBIAS - 1)) {
+		dev_err(wcd->dev, "Invalid micbias index, micb_ind:%d\n",
+			micb_index);
+		return -EINVAL;
+	}
+
+	switch (micb_num) {
+	case MIC_BIAS_1:
+		micb_reg = WCD9335_ANA_MICB1;
+		break;
+	case MIC_BIAS_2:
+		micb_reg = WCD9335_ANA_MICB2;
+		break;
+	case MIC_BIAS_3:
+		micb_reg = WCD9335_ANA_MICB3;
+		break;
+	case MIC_BIAS_4:
+		micb_reg = WCD9335_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:
+		wcd->pullup_ref[micb_index]++;
+		if ((wcd->pullup_ref[micb_index] == 1) &&
+		    (wcd->micb_ref[micb_index] == 0))
+			snd_soc_component_update_bits(component, micb_reg,
+							0xC0, 0x80);
+		break;
+	case MICB_PULLUP_DISABLE:
+		wcd->pullup_ref[micb_index]--;
+		if ((wcd->pullup_ref[micb_index] == 0) &&
+		    (wcd->micb_ref[micb_index] == 0))
+			snd_soc_component_update_bits(component, micb_reg,
+							0xC0, 0x00);
+		break;
+	case MICB_ENABLE:
+		wcd->micb_ref[micb_index]++;
+		if (wcd->micb_ref[micb_index] == 1)
+			snd_soc_component_update_bits(component, micb_reg,
+							0xC0, 0x40);
+		break;
+	case MICB_DISABLE:
+		wcd->micb_ref[micb_index]--;
+		if ((wcd->micb_ref[micb_index] == 0) &&
+		    (wcd->pullup_ref[micb_index] > 0))
+			snd_soc_component_update_bits(component, micb_reg,
+							0xC0, 0x80);
+		else if ((wcd->micb_ref[micb_index] == 0) &&
+			 (wcd->pullup_ref[micb_index] == 0)) {
+			snd_soc_component_update_bits(component, micb_reg,
+							0xC0, 0x00);
+		}
+		break;
+	};
+
+	return 0;
+}
+
+static int __wcd9335_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+					int event)
+{
+	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+	int micb_num;
+
+	if (strnstr(w->name, "MIC BIAS1", sizeof("MIC BIAS1")))
+		micb_num = MIC_BIAS_1;
+	else if (strnstr(w->name, "MIC BIAS2", sizeof("MIC BIAS2")))
+		micb_num = MIC_BIAS_2;
+	else if (strnstr(w->name, "MIC BIAS3", sizeof("MIC BIAS3")))
+		micb_num = MIC_BIAS_3;
+	else if (strnstr(w->name, "MIC BIAS4", sizeof("MIC BIAS4")))
+		micb_num = MIC_BIAS_4;
+	else
+		return -EINVAL;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/*
+		 * MIC BIAS can also be requested by MBHC,
+		 * so use ref count to handle micbias pullup
+		 * and enable requests
+		 */
+		wcd9335_micbias_control(comp, micb_num, MICB_ENABLE, true);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/* wait for cnp time */
+		usleep_range(1000, 1100);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		wcd9335_micbias_control(comp, micb_num, MICB_DISABLE, true);
+		break;
+	};
+
+	return 0;
+}
+
+static int wcd9335_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kc, int event)
+{
+	return __wcd9335_codec_enable_micbias(w, event);
+}
+
+static void wcd9335_codec_set_tx_hold(struct snd_soc_component *comp,
+				      u16 amic_reg, bool set)
+{
+	u8 mask = 0x20;
+	u8 val;
+
+	if (amic_reg == WCD9335_ANA_AMIC1 || amic_reg == WCD9335_ANA_AMIC3 ||
+	    amic_reg == WCD9335_ANA_AMIC5)
+		mask = 0x40;
+
+	val = set ? mask : 0x00;
+
+	switch (amic_reg) {
+	case WCD9335_ANA_AMIC1:
+	case WCD9335_ANA_AMIC2:
+		snd_soc_component_update_bits(comp, WCD9335_ANA_AMIC2, mask,
+						val);
+		break;
+	case WCD9335_ANA_AMIC3:
+	case WCD9335_ANA_AMIC4:
+		snd_soc_component_update_bits(comp, WCD9335_ANA_AMIC4, mask,
+						val);
+		break;
+	case WCD9335_ANA_AMIC5:
+	case WCD9335_ANA_AMIC6:
+		snd_soc_component_update_bits(comp, WCD9335_ANA_AMIC6, mask,
+						val);
+		break;
+	default:
+		dev_err(comp->dev, "%s: invalid amic: %d\n",
+			__func__, amic_reg);
+		break;
+	}
+}
+
+static int wcd9335_codec_enable_adc(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kc, int event)
+{
+	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		wcd9335_codec_set_tx_hold(comp, w->reg, true);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int wcd9335_codec_find_amic_input(struct snd_soc_component *comp,
+					 int adc_mux_n)
+{
+	int mux_sel, reg, mreg;
+
+	if (adc_mux_n < 0 || adc_mux_n > WCD9335_MAX_VALID_ADC_MUX ||
+	    adc_mux_n == WCD9335_INVALID_ADC_MUX)
+		return 0;
+
+	/* Check whether adc mux input is AMIC or DMIC */
+	if (adc_mux_n < 4) {
+		reg = WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1 + 2 * adc_mux_n;
+		mreg = WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + 2 * adc_mux_n;
+		mux_sel = snd_soc_component_read32(comp, reg) & 0x3;
+	} else {
+		reg = WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0 + adc_mux_n - 4;
+		mreg = reg;
+		mux_sel = snd_soc_component_read32(comp, reg) >> 6;
+	}
+
+	if (mux_sel != WCD9335_CDC_TX_INP_MUX_SEL_AMIC)
+		return 0;
+
+	return snd_soc_component_read32(comp, mreg) & 0x07;
+}
+
+static u16 wcd9335_codec_get_amic_pwlvl_reg(struct snd_soc_component *comp,
+					    int amic)
+{
+	u16 pwr_level_reg = 0;
+
+	switch (amic) {
+	case 1:
+	case 2:
+		pwr_level_reg = WCD9335_ANA_AMIC1;
+		break;
+
+	case 3:
+	case 4:
+		pwr_level_reg = WCD9335_ANA_AMIC3;
+		break;
+
+	case 5:
+	case 6:
+		pwr_level_reg = WCD9335_ANA_AMIC5;
+		break;
+	default:
+		dev_err(comp->dev, "invalid amic: %d\n", amic);
+		break;
+	}
+
+	return pwr_level_reg;
+}
+
+static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kc, int event)
+{
+	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+	unsigned int decimator;
+	char *dec_adc_mux_name = NULL;
+	char *widget_name = NULL;
+	char *wname;
+	int ret = 0, amic_n;
+	u16 tx_vol_ctl_reg, pwr_level_reg = 0, dec_cfg_reg, hpf_gate_reg;
+	u16 tx_gain_ctl_reg;
+	char *dec;
+	u8 hpf_coff_freq;
+
+	widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+	if (!widget_name)
+		return -ENOMEM;
+
+	wname = widget_name;
+	dec_adc_mux_name = strsep(&widget_name, " ");
+	if (!dec_adc_mux_name) {
+		dev_err(comp->dev, "%s: Invalid decimator = %s\n",
+			__func__, w->name);
+		ret =  -EINVAL;
+		goto out;
+	}
+	dec_adc_mux_name = widget_name;
+
+	dec = strpbrk(dec_adc_mux_name, "012345678");
+	if (!dec) {
+		dev_err(comp->dev, "%s: decimator index not found\n",
+			__func__);
+		ret =  -EINVAL;
+		goto out;
+	}
+
+	ret = kstrtouint(dec, 10, &decimator);
+	if (ret < 0) {
+		dev_err(comp->dev, "%s: Invalid decimator = %s\n",
+			__func__, wname);
+		ret =  -EINVAL;
+		goto out;
+	}
+
+	tx_vol_ctl_reg = WCD9335_CDC_TX0_TX_PATH_CTL + 16 * decimator;
+	hpf_gate_reg = WCD9335_CDC_TX0_TX_PATH_SEC2 + 16 * decimator;
+	dec_cfg_reg = WCD9335_CDC_TX0_TX_PATH_CFG0 + 16 * decimator;
+	tx_gain_ctl_reg = WCD9335_CDC_TX0_TX_VOL_CTL + 16 * decimator;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		amic_n = wcd9335_codec_find_amic_input(comp, decimator);
+		if (amic_n)
+			pwr_level_reg = wcd9335_codec_get_amic_pwlvl_reg(comp,
+								       amic_n);
+
+		if (pwr_level_reg) {
+			switch ((snd_soc_component_read32(comp, pwr_level_reg) &
+					      WCD9335_AMIC_PWR_LVL_MASK) >>
+					      WCD9335_AMIC_PWR_LVL_SHIFT) {
+			case WCD9335_AMIC_PWR_LEVEL_LP:
+				snd_soc_component_update_bits(comp, dec_cfg_reg,
+						    WCD9335_DEC_PWR_LVL_MASK,
+						    WCD9335_DEC_PWR_LVL_LP);
+				break;
+
+			case WCD9335_AMIC_PWR_LEVEL_HP:
+				snd_soc_component_update_bits(comp, dec_cfg_reg,
+						    WCD9335_DEC_PWR_LVL_MASK,
+						    WCD9335_DEC_PWR_LVL_HP);
+				break;
+			case WCD9335_AMIC_PWR_LEVEL_DEFAULT:
+			default:
+				snd_soc_component_update_bits(comp, dec_cfg_reg,
+						    WCD9335_DEC_PWR_LVL_MASK,
+						    WCD9335_DEC_PWR_LVL_DF);
+				break;
+			}
+		}
+		hpf_coff_freq = (snd_soc_component_read32(comp, dec_cfg_reg) &
+				   TX_HPF_CUT_OFF_FREQ_MASK) >> 5;
+
+		if (hpf_coff_freq != CF_MIN_3DB_150HZ)
+			snd_soc_component_update_bits(comp, dec_cfg_reg,
+					    TX_HPF_CUT_OFF_FREQ_MASK,
+					    CF_MIN_3DB_150HZ << 5);
+		/* Enable TX PGA Mute */
+		snd_soc_component_update_bits(comp, tx_vol_ctl_reg,
+						0x10, 0x10);
+		/* Enable APC */
+		snd_soc_component_update_bits(comp, dec_cfg_reg, 0x08, 0x08);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_component_update_bits(comp, hpf_gate_reg, 0x01, 0x00);
+
+		if (decimator == 0) {
+			snd_soc_component_write(comp,
+					WCD9335_MBHC_ZDET_RAMP_CTL, 0x83);
+			snd_soc_component_write(comp,
+					WCD9335_MBHC_ZDET_RAMP_CTL, 0xA3);
+			snd_soc_component_write(comp,
+					WCD9335_MBHC_ZDET_RAMP_CTL, 0x83);
+			snd_soc_component_write(comp,
+					WCD9335_MBHC_ZDET_RAMP_CTL, 0x03);
+		}
+
+		snd_soc_component_update_bits(comp, hpf_gate_reg,
+						0x01, 0x01);
+		snd_soc_component_update_bits(comp, tx_vol_ctl_reg,
+						0x10, 0x00);
+		snd_soc_component_write(comp, tx_gain_ctl_reg,
+			      snd_soc_component_read32(comp, tx_gain_ctl_reg));
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		hpf_coff_freq = (snd_soc_component_read32(comp, dec_cfg_reg) &
+				   TX_HPF_CUT_OFF_FREQ_MASK) >> 5;
+		snd_soc_component_update_bits(comp, tx_vol_ctl_reg, 0x10, 0x10);
+		snd_soc_component_update_bits(comp, dec_cfg_reg, 0x08, 0x00);
+			if (hpf_coff_freq != CF_MIN_3DB_150HZ) {
+				snd_soc_component_update_bits(comp, dec_cfg_reg,
+						    TX_HPF_CUT_OFF_FREQ_MASK,
+						    hpf_coff_freq << 5);
+			}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_component_update_bits(comp, tx_vol_ctl_reg, 0x10, 0x00);
+		break;
+	};
+out:
+	kfree(wname);
+	return ret;
+}
+
+static u8 wcd9335_get_dmic_clk_val(struct snd_soc_component *component,
+				 u32 mclk_rate, u32 dmic_clk_rate)
+{
+	u32 div_factor;
+	u8 dmic_ctl_val;
+
+	dev_err(component->dev,
+		"%s: mclk_rate = %d, dmic_sample_rate = %d\n",
+		__func__, mclk_rate, dmic_clk_rate);
+
+	/* Default value to return in case of error */
+	if (mclk_rate == WCD9335_MCLK_CLK_9P6MHZ)
+		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_2;
+	else
+		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_3;
+
+	if (dmic_clk_rate == 0) {
+		dev_err(component->dev,
+			"%s: dmic_sample_rate cannot be 0\n",
+			__func__);
+		goto done;
+	}
+
+	div_factor = mclk_rate / dmic_clk_rate;
+	switch (div_factor) {
+	case 2:
+		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_2;
+		break;
+	case 3:
+		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_3;
+		break;
+	case 4:
+		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_4;
+		break;
+	case 6:
+		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_6;
+		break;
+	case 8:
+		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_8;
+		break;
+	case 16:
+		dmic_ctl_val = WCD9335_DMIC_CLK_DIV_16;
+		break;
+	default:
+		dev_err(component->dev,
+			"%s: Invalid div_factor %u, clk_rate(%u), dmic_rate(%u)\n",
+			__func__, div_factor, mclk_rate, dmic_clk_rate);
+		break;
+	}
+
+done:
+	return dmic_ctl_val;
+}
+
+static int wcd9335_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kc, int event)
+{
+	struct snd_soc_component *comp = snd_soc_dapm_to_component(w->dapm);
+	struct wcd9335_codec *wcd = snd_soc_component_get_drvdata(comp);
+	u8  dmic_clk_en = 0x01;
+	u16 dmic_clk_reg;
+	s32 *dmic_clk_cnt;
+	u8 dmic_rate_val, dmic_rate_shift = 1;
+	unsigned int dmic;
+	int ret;
+	char *wname;
+
+	wname = strpbrk(w->name, "012345");
+	if (!wname) {
+		dev_err(comp->dev, "%s: widget not found\n", __func__);
+		return -EINVAL;
+	}
+
+	ret = kstrtouint(wname, 10, &dmic);
+	if (ret < 0) {
+		dev_err(comp->dev, "%s: Invalid DMIC line on the codec\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	switch (dmic) {
+	case 0:
+	case 1:
+		dmic_clk_cnt = &(wcd->dmic_0_1_clk_cnt);
+		dmic_clk_reg = WCD9335_CPE_SS_DMIC0_CTL;
+		break;
+	case 2:
+	case 3:
+		dmic_clk_cnt = &(wcd->dmic_2_3_clk_cnt);
+		dmic_clk_reg = WCD9335_CPE_SS_DMIC1_CTL;
+		break;
+	case 4:
+	case 5:
+		dmic_clk_cnt = &(wcd->dmic_4_5_clk_cnt);
+		dmic_clk_reg = WCD9335_CPE_SS_DMIC2_CTL;
+		break;
+	default:
+		dev_err(comp->dev, "%s: Invalid DMIC Selection\n",
+			__func__);
+		return -EINVAL;
+	};
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		dmic_rate_val =
+			wcd9335_get_dmic_clk_val(comp,
+					wcd->mclk_rate,
+					wcd->dmic_sample_rate);
+
+		(*dmic_clk_cnt)++;
+		if (*dmic_clk_cnt == 1) {
+			snd_soc_component_update_bits(comp, dmic_clk_reg,
+				0x07 << dmic_rate_shift,
+				dmic_rate_val << dmic_rate_shift);
+			snd_soc_component_update_bits(comp, dmic_clk_reg,
+					dmic_clk_en, dmic_clk_en);
+		}
+
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		dmic_rate_val =
+			wcd9335_get_dmic_clk_val(comp,
+					wcd->mclk_rate,
+					wcd->mad_dmic_sample_rate);
+		(*dmic_clk_cnt)--;
+		if (*dmic_clk_cnt  == 0) {
+			snd_soc_component_update_bits(comp, dmic_clk_reg,
+					dmic_clk_en, 0);
+			snd_soc_component_update_bits(comp, dmic_clk_reg,
+				0x07 << dmic_rate_shift,
+				dmic_rate_val << dmic_rate_shift);
+		}
+		break;
+	};
+
+	return 0;
+}
+
 static void wcd9335_codec_enable_int_port(struct wcd_slim_codec_dai_data *dai,
 					struct snd_soc_component *component)
 {
@@ -3160,6 +4421,191 @@ static const struct snd_soc_dapm_widget wcd9335_dapm_widgets[] = {
 		wcd9335_codec_enable_mclk, SND_SOC_DAPM_PRE_PMU |
 		SND_SOC_DAPM_POST_PMD),
 
+	/* TX */
+	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_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
+		AIF1_CAP, 0, wcd9335_codec_enable_slim,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_AIF_OUT_E("AIF2 CAP", "AIF2 Capture", 0, SND_SOC_NOPM,
+		AIF2_CAP, 0, wcd9335_codec_enable_slim,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_AIF_OUT_E("AIF3 CAP", "AIF3 Capture", 0, SND_SOC_NOPM,
+		AIF3_CAP, 0, wcd9335_codec_enable_slim,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SUPPLY("MIC BIAS1", SND_SOC_NOPM, 0, 0,
+			       wcd9335_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, 0, 0,
+			       wcd9335_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, 0, 0,
+			       wcd9335_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, 0, 0,
+			       wcd9335_codec_enable_micbias,
+			       SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("ADC1", NULL, WCD9335_ANA_AMIC1, 7, 0,
+			   wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_ADC_E("ADC2", NULL, WCD9335_ANA_AMIC2, 7, 0,
+			   wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_ADC_E("ADC3", NULL, WCD9335_ANA_AMIC3, 7, 0,
+			   wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_ADC_E("ADC4", NULL, WCD9335_ANA_AMIC4, 7, 0,
+			   wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_ADC_E("ADC5", NULL, WCD9335_ANA_AMIC5, 7, 0,
+			   wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU),
+	SND_SOC_DAPM_ADC_E("ADC6", NULL, WCD9335_ANA_AMIC6, 7, 0,
+			   wcd9335_codec_enable_adc, SND_SOC_DAPM_PRE_PMU),
+
+	/* Digital Mic Inputs */
+	SND_SOC_DAPM_ADC_E("DMIC0", NULL, SND_SOC_NOPM, 0, 0,
+		wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+		wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
+		wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
+		wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
+		wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
+		wcd9335_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+		SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX("DMIC MUX0", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux0),
+	SND_SOC_DAPM_MUX("DMIC MUX1", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux1),
+	SND_SOC_DAPM_MUX("DMIC MUX2", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux2),
+	SND_SOC_DAPM_MUX("DMIC MUX3", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux3),
+	SND_SOC_DAPM_MUX("DMIC MUX4", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux4),
+	SND_SOC_DAPM_MUX("DMIC MUX5", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux5),
+	SND_SOC_DAPM_MUX("DMIC MUX6", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux6),
+	SND_SOC_DAPM_MUX("DMIC MUX7", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux7),
+	SND_SOC_DAPM_MUX("DMIC MUX8", SND_SOC_NOPM, 0, 0,
+		&tx_dmic_mux8),
+
+	SND_SOC_DAPM_MUX("AMIC MUX0", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux0),
+	SND_SOC_DAPM_MUX("AMIC MUX1", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux1),
+	SND_SOC_DAPM_MUX("AMIC MUX2", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux2),
+	SND_SOC_DAPM_MUX("AMIC MUX3", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux3),
+	SND_SOC_DAPM_MUX("AMIC MUX4", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux4),
+	SND_SOC_DAPM_MUX("AMIC MUX5", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux5),
+	SND_SOC_DAPM_MUX("AMIC MUX6", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux6),
+	SND_SOC_DAPM_MUX("AMIC MUX7", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux7),
+	SND_SOC_DAPM_MUX("AMIC MUX8", SND_SOC_NOPM, 0, 0,
+		&tx_amic_mux8),
+
+	SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
+		aif1_cap_mixer, ARRAY_SIZE(aif1_cap_mixer)),
+
+	SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0,
+		aif2_cap_mixer, ARRAY_SIZE(aif2_cap_mixer)),
+
+	SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0,
+		aif3_cap_mixer, ARRAY_SIZE(aif3_cap_mixer)),
+
+	SND_SOC_DAPM_MUX("SLIM TX0 MUX", SND_SOC_NOPM, WCD9335_TX0, 0,
+		&sb_tx0_mux),
+	SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, WCD9335_TX1, 0,
+		&sb_tx1_mux),
+	SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, WCD9335_TX2, 0,
+		&sb_tx2_mux),
+	SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, WCD9335_TX3, 0,
+		&sb_tx3_mux),
+	SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, WCD9335_TX4, 0,
+		&sb_tx4_mux),
+	SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, WCD9335_TX5, 0,
+		&sb_tx5_mux),
+	SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, WCD9335_TX6, 0,
+		&sb_tx6_mux),
+	SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, WCD9335_TX7, 0,
+		&sb_tx7_mux),
+	SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, WCD9335_TX8, 0,
+		&sb_tx8_mux),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX0", WCD9335_CDC_TX0_TX_PATH_CTL, 5, 0,
+			   &tx_adc_mux0, wcd9335_codec_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX1", WCD9335_CDC_TX1_TX_PATH_CTL, 5, 0,
+			   &tx_adc_mux1, wcd9335_codec_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX2", WCD9335_CDC_TX2_TX_PATH_CTL, 5, 0,
+			   &tx_adc_mux2, wcd9335_codec_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX3", WCD9335_CDC_TX3_TX_PATH_CTL, 5, 0,
+			   &tx_adc_mux3, wcd9335_codec_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX4", WCD9335_CDC_TX4_TX_PATH_CTL, 5, 0,
+			   &tx_adc_mux4, wcd9335_codec_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX5", WCD9335_CDC_TX5_TX_PATH_CTL, 5, 0,
+			   &tx_adc_mux5, wcd9335_codec_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX6", WCD9335_CDC_TX6_TX_PATH_CTL, 5, 0,
+			   &tx_adc_mux6, wcd9335_codec_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX7", WCD9335_CDC_TX7_TX_PATH_CTL, 5, 0,
+			   &tx_adc_mux7, wcd9335_codec_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MUX_E("ADC MUX8", WCD9335_CDC_TX8_TX_PATH_CTL, 5, 0,
+			   &tx_adc_mux8, wcd9335_codec_enable_dec,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 };
 
 static void wcd9335_enable_sido_buck(struct snd_soc_component *component)
@@ -3304,6 +4750,7 @@ static int wcd9335_probe(struct platform_device *pdev)
 	dev_set_drvdata(dev, wcd);
 
 	memcpy(wcd->rx_chs, wcd9335_rx_chs, sizeof(wcd9335_rx_chs));
+	memcpy(wcd->tx_chs, wcd9335_tx_chs, sizeof(wcd9335_tx_chs));
 
 	wcd->regmap = pdata->regmap;
 	wcd->if_regmap = pdata->interface_dev_regmap;
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v4 09/14] ASoC: wcd9335: add audio routings
  2018-09-17  0:57 [PATCH v4 00/14] ASoC: Add support to WCD9335 Audio Codec srinivas.kandagatla
                   ` (7 preceding siblings ...)
  2018-09-17  0:57 ` [PATCH v4 08/14] ASoC: wcd9335: add capture " srinivas.kandagatla
@ 2018-09-17  0:57 ` srinivas.kandagatla
  2018-09-17  0:57 ` [PATCH v4 10/14] ASoC: dt-bindings: Add WCD9335 MBHC specific properties srinivas.kandagatla
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 22+ messages in thread
From: srinivas.kandagatla @ 2018-09-17  0:57 UTC (permalink / raw)
  To: lee.jones, robh+dt, broonie
  Cc: mark.rutland, lgirdwood, bgoswami, devicetree, linux-kernel,
	vkoul, alsa-devel, Srinivas Kandagatla

From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

This patch adds audio routing for both playback and capture.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Reviewed-by: Vinod Koul <vkoul@kernel.org>
---
 sound/soc/codecs/wcd9335.c | 189 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 189 insertions(+)

diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 86a15b1..efbb698 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -98,6 +98,67 @@
 /* vout step value */
 #define WCD9335_CALCULATE_VOUT_D(req_mv) (((req_mv - 650) * 10) / 25)
 
+#define WCD9335_INTERPOLATOR_PATH(id)			\
+	{"RX INT" #id "_1 MIX1 INP0", "RX0", "SLIM RX0"},	\
+	{"RX INT" #id "_1 MIX1 INP0", "RX1", "SLIM RX1"},	\
+	{"RX INT" #id "_1 MIX1 INP0", "RX2", "SLIM RX2"},	\
+	{"RX INT" #id "_1 MIX1 INP0", "RX3", "SLIM RX3"},	\
+	{"RX INT" #id "_1 MIX1 INP0", "RX4", "SLIM RX4"},	\
+	{"RX INT" #id "_1 MIX1 INP0", "RX5", "SLIM RX5"},	\
+	{"RX INT" #id "_1 MIX1 INP0", "RX6", "SLIM RX6"},	\
+	{"RX INT" #id "_1 MIX1 INP0", "RX7", "SLIM RX7"},	\
+	{"RX INT" #id "_1 MIX1 INP1", "RX0", "SLIM RX0"},	\
+	{"RX INT" #id "_1 MIX1 INP1", "RX1", "SLIM RX1"},	\
+	{"RX INT" #id "_1 MIX1 INP1", "RX2", "SLIM RX2"},	\
+	{"RX INT" #id "_1 MIX1 INP1", "RX3", "SLIM RX3"},	\
+	{"RX INT" #id "_1 MIX1 INP1", "RX4", "SLIM RX4"},	\
+	{"RX INT" #id "_1 MIX1 INP1", "RX5", "SLIM RX5"},	\
+	{"RX INT" #id "_1 MIX1 INP1", "RX6", "SLIM RX6"},	\
+	{"RX INT" #id "_1 MIX1 INP1", "RX7", "SLIM RX7"},	\
+	{"RX INT" #id "_1 MIX1 INP2", "RX0", "SLIM RX0"},	\
+	{"RX INT" #id "_1 MIX1 INP2", "RX1", "SLIM RX1"},	\
+	{"RX INT" #id "_1 MIX1 INP2", "RX2", "SLIM RX2"},	\
+	{"RX INT" #id "_1 MIX1 INP2", "RX3", "SLIM RX3"},	\
+	{"RX INT" #id "_1 MIX1 INP2", "RX4", "SLIM RX4"},	\
+	{"RX INT" #id "_1 MIX1 INP2", "RX5", "SLIM RX5"},	\
+	{"RX INT" #id "_1 MIX1 INP2", "RX6", "SLIM RX6"},	\
+	{"RX INT" #id "_1 MIX1 INP2", "RX7", "SLIM RX7"},	\
+	{"RX INT" #id "_2 MUX", "RX0", "SLIM RX0"},	\
+	{"RX INT" #id "_2 MUX", "RX1", "SLIM RX1"},	\
+	{"RX INT" #id "_2 MUX", "RX2", "SLIM RX2"},	\
+	{"RX INT" #id "_2 MUX", "RX3", "SLIM RX3"},	\
+	{"RX INT" #id "_2 MUX", "RX4", "SLIM RX4"},	\
+	{"RX INT" #id "_2 MUX", "RX5", "SLIM RX5"},	\
+	{"RX INT" #id "_2 MUX", "RX6", "SLIM RX6"},	\
+	{"RX INT" #id "_2 MUX", "RX7", "SLIM RX7"},	\
+	{"RX INT" #id "_1 MIX1", NULL, "RX INT" #id "_1 MIX1 INP0"},	\
+	{"RX INT" #id "_1 MIX1", NULL, "RX INT" #id "_1 MIX1 INP1"},	\
+	{"RX INT" #id "_1 MIX1", NULL, "RX INT" #id "_1 MIX1 INP2"},	\
+	{"RX INT" #id " SEC MIX", NULL, "RX INT" #id "_2 MUX"},		\
+	{"RX INT" #id " SEC MIX", NULL, "RX INT" #id "_1 MIX1"},	\
+	{"RX INT" #id " MIX2", NULL, "RX INT" #id " SEC MIX"},		\
+	{"RX INT" #id " INTERP", NULL, "RX INT" #id " MIX2"}
+
+#define WCD9335_ADC_MUX_PATH(id)			\
+	{"AIF1_CAP Mixer", "SLIM TX" #id, "SLIM TX" #id " MUX"}, \
+	{"AIF2_CAP Mixer", "SLIM TX" #id, "SLIM TX" #id " MUX"}, \
+	{"AIF3_CAP Mixer", "SLIM TX" #id, "SLIM TX" #id " MUX"}, \
+	{"SLIM TX" #id " MUX", "DEC" #id, "ADC MUX" #id}, \
+	{"ADC MUX" #id, "DMIC", "DMIC MUX" #id},	\
+	{"ADC MUX" #id, "AMIC", "AMIC MUX" #id},	\
+	{"DMIC MUX" #id, "DMIC0", "DMIC0"},		\
+	{"DMIC MUX" #id, "DMIC1", "DMIC1"},		\
+	{"DMIC MUX" #id, "DMIC2", "DMIC2"},		\
+	{"DMIC MUX" #id, "DMIC3", "DMIC3"},		\
+	{"DMIC MUX" #id, "DMIC4", "DMIC4"},		\
+	{"DMIC MUX" #id, "DMIC5", "DMIC5"},		\
+	{"AMIC MUX" #id, "ADC1", "ADC1"},		\
+	{"AMIC MUX" #id, "ADC2", "ADC2"},		\
+	{"AMIC MUX" #id, "ADC3", "ADC3"},		\
+	{"AMIC MUX" #id, "ADC4", "ADC4"},		\
+	{"AMIC MUX" #id, "ADC5", "ADC5"},		\
+	{"AMIC MUX" #id, "ADC6", "ADC6"}
+
 enum {
 	WCD9335_RX0 = 0,
 	WCD9335_RX1,
@@ -2329,6 +2390,132 @@ static const struct snd_kcontrol_new wcd9335_snd_controls[] = {
 	SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
 };
 
+static const struct snd_soc_dapm_route wcd9335_audio_map[] = {
+	{"SLIM RX0 MUX", "AIF1_PB", "AIF1 PB"},
+	{"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
+	{"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"},
+	{"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"},
+	{"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"},
+	{"SLIM RX5 MUX", "AIF1_PB", "AIF1 PB"},
+	{"SLIM RX6 MUX", "AIF1_PB", "AIF1 PB"},
+	{"SLIM RX7 MUX", "AIF1_PB", "AIF1 PB"},
+
+	{"SLIM RX0 MUX", "AIF2_PB", "AIF2 PB"},
+	{"SLIM RX1 MUX", "AIF2_PB", "AIF2 PB"},
+	{"SLIM RX2 MUX", "AIF2_PB", "AIF2 PB"},
+	{"SLIM RX3 MUX", "AIF2_PB", "AIF2 PB"},
+	{"SLIM RX4 MUX", "AIF2_PB", "AIF2 PB"},
+	{"SLIM RX5 MUX", "AIF2_PB", "AIF2 PB"},
+	{"SLIM RX6 MUX", "AIF2_PB", "AIF2 PB"},
+	{"SLIM RX7 MUX", "AIF2_PB", "AIF2 PB"},
+
+	{"SLIM RX0 MUX", "AIF3_PB", "AIF3 PB"},
+	{"SLIM RX1 MUX", "AIF3_PB", "AIF3 PB"},
+	{"SLIM RX2 MUX", "AIF3_PB", "AIF3 PB"},
+	{"SLIM RX3 MUX", "AIF3_PB", "AIF3 PB"},
+	{"SLIM RX4 MUX", "AIF3_PB", "AIF3 PB"},
+	{"SLIM RX5 MUX", "AIF3_PB", "AIF3 PB"},
+	{"SLIM RX6 MUX", "AIF3_PB", "AIF3 PB"},
+	{"SLIM RX7 MUX", "AIF3_PB", "AIF3 PB"},
+
+	{"SLIM RX0 MUX", "AIF4_PB", "AIF4 PB"},
+	{"SLIM RX1 MUX", "AIF4_PB", "AIF4 PB"},
+	{"SLIM RX2 MUX", "AIF4_PB", "AIF4 PB"},
+	{"SLIM RX3 MUX", "AIF4_PB", "AIF4 PB"},
+	{"SLIM RX4 MUX", "AIF4_PB", "AIF4 PB"},
+	{"SLIM RX5 MUX", "AIF4_PB", "AIF4 PB"},
+	{"SLIM RX6 MUX", "AIF4_PB", "AIF4 PB"},
+	{"SLIM RX7 MUX", "AIF4_PB", "AIF4 PB"},
+
+	{"SLIM RX0", NULL, "SLIM RX0 MUX"},
+	{"SLIM RX1", NULL, "SLIM RX1 MUX"},
+	{"SLIM RX2", NULL, "SLIM RX2 MUX"},
+	{"SLIM RX3", NULL, "SLIM RX3 MUX"},
+	{"SLIM RX4", NULL, "SLIM RX4 MUX"},
+	{"SLIM RX5", NULL, "SLIM RX5 MUX"},
+	{"SLIM RX6", NULL, "SLIM RX6 MUX"},
+	{"SLIM RX7", NULL, "SLIM RX7 MUX"},
+
+	WCD9335_INTERPOLATOR_PATH(0),
+	WCD9335_INTERPOLATOR_PATH(1),
+	WCD9335_INTERPOLATOR_PATH(2),
+	WCD9335_INTERPOLATOR_PATH(3),
+	WCD9335_INTERPOLATOR_PATH(4),
+	WCD9335_INTERPOLATOR_PATH(5),
+	WCD9335_INTERPOLATOR_PATH(6),
+	WCD9335_INTERPOLATOR_PATH(7),
+	WCD9335_INTERPOLATOR_PATH(8),
+
+	/* EAR PA */
+	{"RX INT0 DEM MUX", "CLSH_DSM_OUT", "RX INT0 INTERP"},
+	{"RX INT0 DAC", NULL, "RX INT0 DEM MUX"},
+	{"RX INT0 DAC", NULL, "RX_BIAS"},
+	{"EAR PA", NULL, "RX INT0 DAC"},
+	{"EAR", NULL, "EAR PA"},
+
+	/* HPHL */
+	{"RX INT1 DEM MUX", "CLSH_DSM_OUT", "RX INT1 INTERP"},
+	{"RX INT1 DAC", NULL, "RX INT1 DEM MUX"},
+	{"RX INT1 DAC", NULL, "RX_BIAS"},
+	{"HPHL PA", NULL, "RX INT1 DAC"},
+	{"HPHL", NULL, "HPHL PA"},
+
+	/* HPHR */
+	{"RX INT2 DEM MUX", "CLSH_DSM_OUT", "RX INT2 INTERP"},
+	{"RX INT2 DAC", NULL, "RX INT2 DEM MUX"},
+	{"RX INT2 DAC", NULL, "RX_BIAS"},
+	{"HPHR PA", NULL, "RX INT2 DAC"},
+	{"HPHR", NULL, "HPHR PA"},
+
+	/* LINEOUT1 */
+	{"RX INT3 DAC", NULL, "RX INT3 INTERP"},
+	{"RX INT3 DAC", NULL, "RX_BIAS"},
+	{"LINEOUT1 PA", NULL, "RX INT3 DAC"},
+	{"LINEOUT1", NULL, "LINEOUT1 PA"},
+
+	/* LINEOUT2 */
+	{"RX INT4 DAC", NULL, "RX INT4 INTERP"},
+	{"RX INT4 DAC", NULL, "RX_BIAS"},
+	{"LINEOUT2 PA", NULL, "RX INT4 DAC"},
+	{"LINEOUT2", NULL, "LINEOUT2 PA"},
+
+	/* LINEOUT3 */
+	{"RX INT5 DAC", NULL, "RX INT5 INTERP"},
+	{"RX INT5 DAC", NULL, "RX_BIAS"},
+	{"LINEOUT3 PA", NULL, "RX INT5 DAC"},
+	{"LINEOUT3", NULL, "LINEOUT3 PA"},
+
+	/* LINEOUT4 */
+	{"RX INT6 DAC", NULL, "RX INT6 INTERP"},
+	{"RX INT6 DAC", NULL, "RX_BIAS"},
+	{"LINEOUT4 PA", NULL, "RX INT6 DAC"},
+	{"LINEOUT4", NULL, "LINEOUT4 PA"},
+
+	/* SLIMBUS Connections */
+	{"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
+	{"AIF2 CAP", NULL, "AIF2_CAP Mixer"},
+	{"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
+
+	/* ADC Mux */
+	WCD9335_ADC_MUX_PATH(0),
+	WCD9335_ADC_MUX_PATH(1),
+	WCD9335_ADC_MUX_PATH(2),
+	WCD9335_ADC_MUX_PATH(3),
+	WCD9335_ADC_MUX_PATH(4),
+	WCD9335_ADC_MUX_PATH(5),
+	WCD9335_ADC_MUX_PATH(6),
+	WCD9335_ADC_MUX_PATH(7),
+	WCD9335_ADC_MUX_PATH(8),
+
+	/* ADC Connections */
+	{"ADC1", NULL, "AMIC1"},
+	{"ADC2", NULL, "AMIC2"},
+	{"ADC3", NULL, "AMIC3"},
+	{"ADC4", NULL, "AMIC4"},
+	{"ADC5", NULL, "AMIC5"},
+	{"ADC6", NULL, "AMIC6"},
+};
+
 static int wcd9335_micbias_control(struct snd_soc_component *component,
 				   int micb_num, int req, bool is_dapm)
 {
@@ -4735,6 +4922,8 @@ static const struct snd_soc_component_driver wcd9335_component_drv = {
 	.num_controls = ARRAY_SIZE(wcd9335_snd_controls),
 	.dapm_widgets = wcd9335_dapm_widgets,
 	.num_dapm_widgets = ARRAY_SIZE(wcd9335_dapm_widgets),
+	.dapm_routes = wcd9335_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(wcd9335_audio_map),
 };
 
 static int wcd9335_probe(struct platform_device *pdev)
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v4 10/14] ASoC: dt-bindings: Add WCD9335 MBHC specific properties
  2018-09-17  0:57 [PATCH v4 00/14] ASoC: Add support to WCD9335 Audio Codec srinivas.kandagatla
                   ` (8 preceding siblings ...)
  2018-09-17  0:57 ` [PATCH v4 09/14] ASoC: wcd9335: add audio routings srinivas.kandagatla
@ 2018-09-17  0:57 ` srinivas.kandagatla
  2018-09-26  9:27   ` Banajit Goswami
  2018-09-17  0:57 ` [PATCH v4 11/14] ASoC: wcd9335: add mbhc support srinivas.kandagatla
                   ` (3 subsequent siblings)
  13 siblings, 1 reply; 22+ messages in thread
From: srinivas.kandagatla @ 2018-09-17  0:57 UTC (permalink / raw)
  To: lee.jones, robh+dt, broonie
  Cc: mark.rutland, lgirdwood, bgoswami, devicetree, linux-kernel,
	vkoul, alsa-devel, Srinivas Kandagatla

From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

This patch add new bindings required to support MBHC
(Multi Button Headset Control) block in the codec.
This block is used for jack insert/removal detection,
headset type detection and 8 button press/release events.

All these properties are very much specific to board.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 .../devicetree/bindings/sound/qcom,wcd9335.txt       | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt b/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt
index 5d6ea66..a95a8b4 100644
--- a/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt
+++ b/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt
@@ -55,6 +55,26 @@ Required properties with SLIMbus Interface:
 	Value type: <string>
 	Definition: Must contain "mclk", "mclk2" and "slimbus" strings.
 
+- qcom,mbhc-vthreshold-millivolt:
+	Usage: Optional, only required if headset button support required.
+	Value type: <u32 array>
+	Definition: Must contain an array of 8 threshold voltages in mV for
+		 8 buttons detection on headset.
+
+- qcom,hphl-jack-type-normally-open:
+	Usage: Optional, only required if headset button support required.
+	Value type: <boolean>
+	Definition: present if hphl pin on jack is a NO (Normally Open).
+		If not specified, then its assumed that hphl pin on jack
+		is NC (Normally Closed).
+
+- qcom,gnd-jack-type-normally-open:
+	Usage: Optional, only required if headset button support required.
+	Value type: <boolean>
+	Definition: present if gnd pin on jack is NO (Normally Open).
+		 If not specified, then its assumed that gnd pin on
+		 jack is NC  (Normally Closed).
+
 - vdd-buck-supply:
 	Usage: required
 	Value type: <phandle>
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v4 11/14] ASoC: wcd9335: add mbhc support
  2018-09-17  0:57 [PATCH v4 00/14] ASoC: Add support to WCD9335 Audio Codec srinivas.kandagatla
                   ` (9 preceding siblings ...)
  2018-09-17  0:57 ` [PATCH v4 10/14] ASoC: dt-bindings: Add WCD9335 MBHC specific properties srinivas.kandagatla
@ 2018-09-17  0:57 ` srinivas.kandagatla
  2018-09-26  9:31   ` Banajit Goswami
  2018-09-17  0:57 ` [PATCH v4 12/14] ASoC: apq8096: add slim support srinivas.kandagatla
                   ` (2 subsequent siblings)
  13 siblings, 1 reply; 22+ messages in thread
From: srinivas.kandagatla @ 2018-09-17  0:57 UTC (permalink / raw)
  To: lee.jones, robh+dt, broonie
  Cc: mark.rutland, lgirdwood, bgoswami, devicetree, linux-kernel,
	vkoul, alsa-devel, Srinivas Kandagatla

From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/codecs/wcd9335.c | 268 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 266 insertions(+), 2 deletions(-)

diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index efbb698..6c95cff 100644
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -11,6 +11,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/clk.h>
 #include <linux/delay.h>
+#include <sound/jack.h>
 #include <linux/kernel.h>
 #include <linux/slimbus.h>
 #include <sound/soc.h>
@@ -89,12 +90,18 @@
 #define  CF_MIN_3DB_75HZ		0x1
 #define  CF_MIN_3DB_150HZ		0x2
 
+#define WCD9335_MBHC_MAX_BUTTONS	(8)
+
 #define WCD9335_SLIM_RX_CH(p) \
 	{.port = p + WCD9335_RX_START, .shift = p,}
 
 #define WCD9335_SLIM_TX_CH(p) \
 	{.port = p, .shift = p,}
 
+static int btn_mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+	       SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_BTN_4;
+static int hs_jack_mask = SND_JACK_HEADPHONE | SND_JACK_HEADSET;
+
 /* vout step value */
 #define WCD9335_CALCULATE_VOUT_D(req_mv) (((req_mv - 650) * 10) / 25)
 
@@ -323,6 +330,16 @@ struct wcd9335_codec {
 	u32 num_rx_port;
 	u32 num_tx_port;
 
+	struct snd_soc_jack *jack;
+	bool hphl_jack_type_normally_open;
+	bool gnd_jack_type_normally_open;
+	bool	mbhc_btn_enabled;
+	int	mbhc_btn0_released;
+	bool	detect_accessory_type;
+	int	accessory_type;
+	/* Voltage threshold for button detection */
+	u32 vref_btn[WCD9335_MBHC_MAX_BUTTONS];
+
 	int sido_input_src;
 	enum wcd9335_sido_voltage sido_voltage;
 
@@ -2829,7 +2846,6 @@ static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w,
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		snd_soc_component_update_bits(comp, hpf_gate_reg, 0x01, 0x00);
-
 		if (decimator == 0) {
 			snd_soc_component_write(comp,
 					WCD9335_MBHC_ZDET_RAMP_CTL, 0x83);
@@ -2840,7 +2856,6 @@ static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w,
 			snd_soc_component_write(comp,
 					WCD9335_MBHC_ZDET_RAMP_CTL, 0x03);
 		}
-
 		snd_soc_component_update_bits(comp, hpf_gate_reg,
 						0x01, 0x01);
 		snd_soc_component_update_bits(comp, tx_vol_ctl_reg,
@@ -3988,6 +4003,131 @@ static int wcd9335_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
 	return ret;
 }
 
+static irqreturn_t wcd9335_mbhc_sw_irq(int irq, void *data)
+{
+	struct wcd9335_codec *wcd = data;
+	struct snd_soc_component *component = wcd->component;
+	bool ins = false;
+
+	if (snd_soc_component_read32(component, WCD9335_ANA_MBHC_MECH) &
+			WCD9335_MBHC_MECH_DETECT_TYPE_MASK)
+		ins = true;
+
+	/* Set the detection type appropriately */
+	snd_soc_component_update_bits(component, WCD9335_ANA_MBHC_MECH,
+			    WCD9335_MBHC_MECH_DETECT_TYPE_MASK,
+			    (!ins << WCD9335_MBHC_MECH_DETECT_TYPE_SHIFT));
+
+	if (ins) { /* hs insertion */
+		u32 btndet_curr_src;
+
+		/*
+		 * If no micbias is enabled, then enable 100uA internal
+		 * current source for Button detection
+		 */
+		if (snd_soc_component_read32(component, WCD9335_ANA_MICB2) &
+						WCD9335_ANA_MICB2_ENABLE)
+			btndet_curr_src = WCD9335_ANA_MBHC_BD_ISRC_OFF;
+		else
+			btndet_curr_src = WCD9335_ANA_MBHC_BD_ISRC_100UA;
+
+		snd_soc_component_update_bits(component,
+					WCD9335_ANA_MBHC_ELECT,
+					WCD9335_ANA_MBHC_BD_ISRC_CTL_MASK,
+					btndet_curr_src);
+
+		/*
+		 * if only a btn0 press event is receive just before
+		 * insert event then its a 3 pole headphone else if
+		 * both press and release event received then its
+		 * a headset.
+		 */
+		if (wcd->mbhc_btn0_released) {
+			snd_soc_jack_report(wcd->jack,
+					    SND_JACK_HEADSET, hs_jack_mask);
+			wcd->accessory_type = SND_JACK_HEADSET;
+		} else {
+			snd_soc_jack_report(wcd->jack,
+					    SND_JACK_HEADPHONE, hs_jack_mask);
+			wcd->accessory_type = SND_JACK_HEADPHONE;
+		}
+
+		wcd->detect_accessory_type = false;
+
+	} else { /* removal */
+		snd_soc_jack_report(wcd->jack, 0, hs_jack_mask);
+		wcd->detect_accessory_type = true;
+		wcd->mbhc_btn0_released = false;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t wcd9335_mbhc_btn_press_irq(int irq, void *data)
+{
+	struct wcd9335_codec *wcd = data;
+	struct snd_soc_component *comp = wcd->component;
+	u32 btn_result, result;
+
+	/* do not handle any button events for headset without buttons */
+	if (wcd->accessory_type == SND_JACK_HEADPHONE)
+		return IRQ_HANDLED;
+
+	result = snd_soc_component_read32(comp, WCD9335_ANA_MBHC_RESULT_3);
+	btn_result = result & WCD9335_MBHC_BTN_RESULT_MASK;
+
+	switch (btn_result) {
+	case 0xf:
+		snd_soc_jack_report(wcd->jack, SND_JACK_BTN_4, btn_mask);
+		break;
+	case 0x4:
+		snd_soc_jack_report(wcd->jack, SND_JACK_BTN_4, btn_mask);
+		break;
+	case 0x3:
+		snd_soc_jack_report(wcd->jack, SND_JACK_BTN_3, btn_mask);
+		break;
+	case 0x2:
+		snd_soc_jack_report(wcd->jack, SND_JACK_BTN_2, btn_mask);
+		break;
+	case 0x1:
+		snd_soc_jack_report(wcd->jack, SND_JACK_BTN_1, btn_mask);
+		break;
+	case 0x0:
+		/* handle BTN_0 specially for type detection */
+		if (!wcd->detect_accessory_type)
+			snd_soc_jack_report(wcd->jack,
+					    SND_JACK_BTN_0, btn_mask);
+		break;
+	default:
+		dev_err(comp->dev,
+			"Unexpected button press result (%x)", btn_result);
+		break;
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t wcd9335_mbhc_bt_rel_irq(int irq, void *data)
+{
+	struct wcd9335_codec *wcd = data;
+
+
+	if (wcd->detect_accessory_type) {
+		u32 result = snd_soc_component_read32(wcd->component,
+						WCD9335_ANA_MBHC_RESULT_3);
+
+		/* check if its BTN0 thats released */
+		if (!(result & WCD9335_MBHC_BTN_RESULT_MASK))
+			wcd->mbhc_btn0_released = true;
+
+	} else {
+		if (wcd->accessory_type != SND_JACK_HEADPHONE)
+			snd_soc_jack_report(wcd->jack, 0, btn_mask);
+	}
+
+	return IRQ_HANDLED;
+}
+
 static irqreturn_t wcd9335_slimbus_irq(int irq, void *data)
 {
 	struct wcd9335_codec *wcd = data;
@@ -4057,11 +4197,95 @@ static irqreturn_t wcd9335_slimbus_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static void wcd9335_program_btn_threshold(struct wcd9335_codec *wcd)
+{
+	int i, vth;
+
+	for (i = 0; i < WCD9335_MBHC_MAX_BUTTONS; i++) {
+		vth = ((wcd->vref_btn[i] * 2) / 25) & 0x3F;
+		snd_soc_component_update_bits(wcd->component,
+					WCD9335_ANA_MBHC_BTN0 + i,
+					0xFC, vth << 2);
+	}
+}
+
+static void wcd9335_mbhc_initialise(struct wcd9335_codec *wcd)
+{
+	struct snd_soc_component *comp = wcd->component;
+	u32 plug_type = 0;
+
+	snd_soc_component_update_bits(comp, WCD9335_MBHC_PLUG_DETECT_CTL,
+			WCD9335_MBHC_HSDET_PULLUP_CTL_MASK,
+			WCD9335_MBHC_HSDET_PULLUP_CTL_1_2P0_UA);
+
+	if (wcd->hphl_jack_type_normally_open)
+		plug_type |= WCD9335_MBHC_HPHL_PLUG_TYPE_NO;
+
+	if (wcd->gnd_jack_type_normally_open)
+		plug_type |= WCD9335_MBHC_GND_PLUG_TYPE_NO;
+
+	snd_soc_component_write(wcd->component, WCD9335_ANA_MBHC_MECH,
+			plug_type |
+			WCD9335_MBHC_L_DET_EN |
+			WCD9335_MBHC_HSL_PULLUP_COMP_EN |
+			WCD9335_MBHC_HPHL_100K_TO_GND_EN);
+
+	/* Insertion debounce set to 96ms */
+	snd_soc_component_write(wcd->component,
+			WCD9335_MBHC_PLUG_DETECT_CTL,
+			WCD9335_MBHC_DBNC_TIMER_INSREM_DBNC_T_96_MS|
+			WCD9335_MBHC_HSDET_PULLUP_CTL_1_2P0_UA);
+	/* Button Debounce set to 16ms */
+	snd_soc_component_update_bits(wcd->component, WCD9335_MBHC_CTL_1,
+			WCD9335_MBHC_BTN_DBNC_MASK,
+			WCD9335_MBHC_BTN_DBNC_T_16_MS);
+
+	/* enable bias distribution control */
+	snd_soc_component_update_bits(comp, WCD9335_ANA_MBHC_ELECT,
+				WCD9335_ANA_MBHC_BIAS_EN_MASK,
+				WCD9335_ANA_MBHC_BIAS_EN);
+
+	snd_soc_component_update_bits(wcd->component,
+				WCD9335_ANA_MBHC_ELECT,
+				WCD9335_ANA_MBHC_BD_ISRC_CTL_MASK,
+				WCD9335_ANA_MBHC_BD_ISRC_100UA);
+
+	/* enable MBHC clock */
+	snd_soc_component_update_bits(wcd->component, WCD9335_MBHC_CTL_1,
+			WCD9335_MBHC_CTL_RCO_EN_MASK,
+			WCD9335_MBHC_CTL_RCO_EN);
+
+	snd_soc_component_update_bits(wcd->component, WCD9335_MBHC_CTL_2,
+			WCD9335_MBHC_HS_VREF_CTL_MASK,
+			WCD9335_MBHC_HS_VREF_1P5_V);
+
+	/* program HS_VREF value */
+	wcd9335_program_btn_threshold(wcd);
+	/* Start FSM */
+	snd_soc_component_update_bits(wcd->component, WCD9335_ANA_MBHC_ELECT,
+			BIT(7), BIT(7));
+
+	wcd->mbhc_btn0_released = false;
+	wcd->detect_accessory_type = true;
+}
+
 static struct wcd9335_irq wcd9335_irqs[] = {
 	{
 		.irq = WCD9335_IRQ_SLIMBUS,
 		.handler = wcd9335_slimbus_irq,
 		.name = "SLIM Slave",
+	}, {
+		.irq = WCD9335_IRQ_MBHC_SW_DET,
+		.handler = wcd9335_mbhc_sw_irq,
+		.name = "Headset Mech Insert Removal",
+	}, {
+		.irq = WCD9335_IRQ_MBHC_BUTTON_PRESS_DET,
+		.handler = wcd9335_mbhc_btn_press_irq,
+		.name = "Headset Button Press",
+	}, {
+		.irq = WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET,
+		.handler = wcd9335_mbhc_bt_rel_irq,
+		.name = "Headset Button Release",
 	},
 };
 
@@ -4859,6 +5083,7 @@ static void wcd9335_codec_init(struct snd_soc_component *component)
 					wcd9335_codec_reg_init[i].val);
 
 	wcd9335_enable_efuse_sensing(component);
+	wcd9335_mbhc_initialise(wcd);
 }
 
 static int wcd9335_codec_probe(struct snd_soc_component *component)
@@ -4914,10 +5139,21 @@ static int wcd9335_codec_set_sysclk(struct snd_soc_component *comp,
 	return clk_set_rate(wcd->mclk, freq);
 }
 
+static int wcd9335_codec_set_jack(struct snd_soc_component *comp,
+				  struct snd_soc_jack *jack, void *data)
+{
+	struct wcd9335_codec *wcd = dev_get_drvdata(comp->dev);
+
+	wcd->jack = jack;
+
+	return 0;
+}
+
 static const struct snd_soc_component_driver wcd9335_component_drv = {
 	.probe = wcd9335_codec_probe,
 	.remove = wcd9335_codec_remove,
 	.set_sysclk = wcd9335_codec_set_sysclk,
+	.set_jack = wcd9335_codec_set_jack,
 	.controls = wcd9335_snd_controls,
 	.num_controls = ARRAY_SIZE(wcd9335_snd_controls),
 	.dapm_widgets = wcd9335_dapm_widgets,
@@ -4926,6 +5162,33 @@ static const struct snd_soc_component_driver wcd9335_component_drv = {
 	.num_dapm_routes = ARRAY_SIZE(wcd9335_audio_map),
 };
 
+static void of_parse_mbhc_data(struct device *dev, struct wcd9335_codec *wcd)
+{
+	int rval;
+
+	if (of_property_read_bool(dev->of_node,
+				  "qcom,hphl-jack-type-normally-open"))
+		wcd->hphl_jack_type_normally_open = true;
+	else
+		wcd->hphl_jack_type_normally_open = false;
+
+	if (of_property_read_bool(dev->of_node,
+				  "qcom,gnd-jack-type-normally-open"))
+		wcd->gnd_jack_type_normally_open = true;
+	else
+		wcd->gnd_jack_type_normally_open = false;
+
+	wcd->mbhc_btn_enabled = true;
+	rval = of_property_read_u32_array(dev->of_node,
+					  "qcom,mbhc-vthreshold",
+					  &wcd->vref_btn[0],
+					  WCD9335_MBHC_MAX_BUTTONS);
+	if (rval < 0) {
+		wcd->mbhc_btn_enabled = false;
+		dev_err(dev, "MBHC btn detection disabled\n");
+	}
+}
+
 static int wcd9335_probe(struct platform_device *pdev)
 {
 	struct wcd9335 *pdata = dev_get_drvdata(pdev->dev.parent);
@@ -4937,6 +5200,7 @@ static int wcd9335_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	dev_set_drvdata(dev, wcd);
+	of_parse_mbhc_data(pdev->dev.parent, wcd);
 
 	memcpy(wcd->rx_chs, wcd9335_rx_chs, sizeof(wcd9335_rx_chs));
 	memcpy(wcd->tx_chs, wcd9335_tx_chs, sizeof(wcd9335_tx_chs));
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v4 12/14] ASoC: apq8096: add slim support
  2018-09-17  0:57 [PATCH v4 00/14] ASoC: Add support to WCD9335 Audio Codec srinivas.kandagatla
                   ` (10 preceding siblings ...)
  2018-09-17  0:57 ` [PATCH v4 11/14] ASoC: wcd9335: add mbhc support srinivas.kandagatla
@ 2018-09-17  0:57 ` srinivas.kandagatla
  2018-09-17  0:57 ` [PATCH v4 13/14] ASoC: apq8096: add headset JACK support srinivas.kandagatla
  2018-09-17  0:57 ` [PATCH v4 14/14] ASoC: qcom: common: move be_hw_fixup to common srinivas.kandagatla
  13 siblings, 0 replies; 22+ messages in thread
From: srinivas.kandagatla @ 2018-09-17  0:57 UTC (permalink / raw)
  To: lee.jones, robh+dt, broonie
  Cc: mark.rutland, lgirdwood, bgoswami, devicetree, linux-kernel,
	vkoul, alsa-devel, Srinivas Kandagatla

From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/apq8096.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 71 insertions(+), 1 deletion(-)

diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c
index 1543e85..66a28c2 100644
--- a/sound/soc/qcom/apq8096.c
+++ b/sound/soc/qcom/apq8096.c
@@ -9,6 +9,10 @@
 #include <sound/pcm.h>
 #include "common.h"
 
+#define SLIM_MAX_TX_PORTS 16
+#define SLIM_MAX_RX_PORTS 16
+#define WCD9335_DEFAULT_MCLK_RATE	9600000
+
 static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 				      struct snd_pcm_hw_params *params)
 {
@@ -23,14 +27,80 @@ static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 	return 0;
 }
 
+static int msm_snd_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_card *card = rtd->card;
+	u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+	u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
+	int ret = 0;
+
+	ret = snd_soc_dai_get_channel_map(codec_dai,
+				&tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+	if (ret != 0 && ret != -ENOTSUPP) {
+		dev_err(card->dev, "failed to get codec chan map : %d\n", ret);
+		goto end;
+	} else if (ret == -ENOTSUPP) {
+		return 0;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
+						  rx_ch_cnt, rx_ch);
+	else
+		ret = snd_soc_dai_set_channel_map(cpu_dai, tx_ch_cnt, tx_ch,
+						  0, NULL);
+	if (ret != 0 && ret != -ENOTSUPP)
+		dev_err(card->dev, "Failed to set cpu chan map : %d\n", ret);
+	else if (ret == -ENOTSUPP)
+		ret = 0;
+end:
+	return ret;
+}
+
+static struct snd_soc_ops apq8096_ops = {
+	.hw_params = msm_snd_hw_params,
+};
+
+static int apq8096_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+	/*
+	 * Codec SLIMBUS configuration
+	 * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13
+	 * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
+	 * TX14, TX15, TX16
+	 */
+	unsigned int rx_ch[SLIM_MAX_RX_PORTS] = {144, 145, 146, 147, 148, 149,
+					150, 151, 152, 153, 154, 155, 156};
+	unsigned int tx_ch[SLIM_MAX_TX_PORTS] = {128, 129, 130, 131, 132, 133,
+					    134, 135, 136, 137, 138, 139,
+					    140, 141, 142, 143};
+
+	snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+					tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+
+	snd_soc_dai_set_sysclk(codec_dai, 0, WCD9335_DEFAULT_MCLK_RATE,
+				SNDRV_PCM_STREAM_PLAYBACK);
+
+	return 0;
+}
+
 static void apq8096_add_be_ops(struct snd_soc_card *card)
 {
 	struct snd_soc_dai_link *link = card->dai_link;
 	int i, num_links = card->num_links;
 
 	for (i = 0; i < num_links; i++) {
-		if (link->no_pcm == 1)
+		if (link->no_pcm == 1) {
 			link->be_hw_params_fixup = apq8096_be_hw_params_fixup;
+			link->init = apq8096_init;
+			link->ops = &apq8096_ops;
+		}
 		link++;
 	}
 }
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v4 13/14] ASoC: apq8096: add headset JACK support
  2018-09-17  0:57 [PATCH v4 00/14] ASoC: Add support to WCD9335 Audio Codec srinivas.kandagatla
                   ` (11 preceding siblings ...)
  2018-09-17  0:57 ` [PATCH v4 12/14] ASoC: apq8096: add slim support srinivas.kandagatla
@ 2018-09-17  0:57 ` srinivas.kandagatla
  2018-09-17  0:57 ` [PATCH v4 14/14] ASoC: qcom: common: move be_hw_fixup to common srinivas.kandagatla
  13 siblings, 0 replies; 22+ messages in thread
From: srinivas.kandagatla @ 2018-09-17  0:57 UTC (permalink / raw)
  To: lee.jones, robh+dt, broonie
  Cc: mark.rutland, lgirdwood, bgoswami, devicetree, linux-kernel,
	vkoul, alsa-devel, Srinivas Kandagatla

From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/apq8096.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c
index 66a28c2..daad43f 100644
--- a/sound/soc/qcom/apq8096.c
+++ b/sound/soc/qcom/apq8096.c
@@ -5,14 +5,21 @@
 #include <linux/platform_device.h>
 #include <linux/of_device.h>
 #include <sound/soc.h>
+#include <sound/jack.h>
 #include <sound/soc-dapm.h>
 #include <sound/pcm.h>
+#include <uapi/linux/input-event-codes.h>
 #include "common.h"
 
 #define SLIM_MAX_TX_PORTS 16
 #define SLIM_MAX_RX_PORTS 16
 #define WCD9335_DEFAULT_MCLK_RATE	9600000
 
+struct apq8096_card_data {
+	struct snd_soc_jack jack;
+	bool jack_setup;
+};
+
 static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 				      struct snd_pcm_hw_params *params)
 {
@@ -68,6 +75,7 @@ static struct snd_soc_ops apq8096_ops = {
 static int apq8096_init(struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct apq8096_card_data *data = snd_soc_card_get_drvdata(rtd->card);
 
 	/*
 	 * Codec SLIMBUS configuration
@@ -80,6 +88,8 @@ static int apq8096_init(struct snd_soc_pcm_runtime *rtd)
 	unsigned int tx_ch[SLIM_MAX_TX_PORTS] = {128, 129, 130, 131, 132, 133,
 					    134, 135, 136, 137, 138, 139,
 					    140, 141, 142, 143};
+	struct snd_soc_card *card = rtd->card;
+	int rval;
 
 	snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
 					tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
@@ -87,6 +97,38 @@ static int apq8096_init(struct snd_soc_pcm_runtime *rtd)
 	snd_soc_dai_set_sysclk(codec_dai, 0, WCD9335_DEFAULT_MCLK_RATE,
 				SNDRV_PCM_STREAM_PLAYBACK);
 
+	if (!data->jack_setup) {
+		struct snd_jack *jack;
+
+		rval = snd_soc_card_jack_new(card, "Headset Jack",
+					     SND_JACK_HEADSET |
+					     SND_JACK_HEADPHONE |
+					     SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+					     SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+					     SND_JACK_BTN_4,
+					     &data->jack, NULL, 0);
+
+		if (rval < 0) {
+			dev_err(card->dev, "Unable to add Headphone Jack\n");
+			return rval;
+		}
+
+		jack = data->jack.jack;
+
+		snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+		snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+		snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+		snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+		data->jack_setup = true;
+	}
+
+	rval = snd_soc_component_set_jack(codec_dai->component,
+					 &data->jack, NULL);
+	if (rval != 0 && rval != -ENOTSUPP) {
+		dev_warn(card->dev, "Failed to set jack: %d\n", rval);
+		return rval;
+	}
+
 	return 0;
 }
 
@@ -107,6 +149,7 @@ static void apq8096_add_be_ops(struct snd_soc_card *card)
 
 static int apq8096_platform_probe(struct platform_device *pdev)
 {
+	struct apq8096_card_data *data;
 	struct snd_soc_card *card;
 	struct device *dev = &pdev->dev;
 	int ret;
@@ -115,8 +158,15 @@ static int apq8096_platform_probe(struct platform_device *pdev)
 	if (!card)
 		return -ENOMEM;
 
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		kfree(card);
+		return -ENOMEM;
+	}
+
 	card->dev = dev;
 	dev_set_drvdata(dev, card);
+	snd_soc_card_set_drvdata(card, data);
 	ret = qcom_snd_parse_of(card);
 	if (ret) {
 		dev_err(dev, "Error parsing OF data\n");
@@ -134,16 +184,19 @@ static int apq8096_platform_probe(struct platform_device *pdev)
 	kfree(card->dai_link);
 err:
 	kfree(card);
+	kfree(data);
 	return ret;
 }
 
 static int apq8096_platform_remove(struct platform_device *pdev)
 {
 	struct snd_soc_card *card = dev_get_drvdata(&pdev->dev);
+	struct apq8096_card_data *data = snd_soc_card_get_drvdata(card);
 
 	snd_soc_unregister_card(card);
 	kfree(card->dai_link);
 	kfree(card);
+	kfree(data);
 
 	return 0;
 }
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH v4 14/14] ASoC: qcom: common: move be_hw_fixup to common
  2018-09-17  0:57 [PATCH v4 00/14] ASoC: Add support to WCD9335 Audio Codec srinivas.kandagatla
                   ` (12 preceding siblings ...)
  2018-09-17  0:57 ` [PATCH v4 13/14] ASoC: apq8096: add headset JACK support srinivas.kandagatla
@ 2018-09-17  0:57 ` srinivas.kandagatla
  2018-09-19  5:49   ` [alsa-devel] " Rohit Kumar
  13 siblings, 1 reply; 22+ messages in thread
From: srinivas.kandagatla @ 2018-09-17  0:57 UTC (permalink / raw)
  To: lee.jones, robh+dt, broonie
  Cc: mark.rutland, lgirdwood, bgoswami, devicetree, linux-kernel,
	vkoul, alsa-devel, Srinivas Kandagatla

From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

be_hw_fixup for qdsp is common across mutiple qcom machine drivers,
so move it to common file and remove the redundant code.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/apq8096.c | 15 ---------------
 sound/soc/qcom/common.c  | 17 +++++++++++++++++
 sound/soc/qcom/sdm845.c  | 22 ++--------------------
 3 files changed, 19 insertions(+), 35 deletions(-)

diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c
index daad43f..9cb26aee 100644
--- a/sound/soc/qcom/apq8096.c
+++ b/sound/soc/qcom/apq8096.c
@@ -20,20 +20,6 @@ struct apq8096_card_data {
 	bool jack_setup;
 };
 
-static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
-				      struct snd_pcm_hw_params *params)
-{
-	struct snd_interval *rate = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_RATE);
-	struct snd_interval *channels = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_CHANNELS);
-
-	rate->min = rate->max = 48000;
-	channels->min = channels->max = 2;
-
-	return 0;
-}
-
 static int msm_snd_hw_params(struct snd_pcm_substream *substream,
 			     struct snd_pcm_hw_params *params)
 {
@@ -139,7 +125,6 @@ static void apq8096_add_be_ops(struct snd_soc_card *card)
 
 	for (i = 0; i < num_links; i++) {
 		if (link->no_pcm == 1) {
-			link->be_hw_params_fixup = apq8096_be_hw_params_fixup;
 			link->init = apq8096_init;
 			link->ops = &apq8096_ops;
 		}
diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
index eb1b9da..ce8e759 100644
--- a/sound/soc/qcom/common.c
+++ b/sound/soc/qcom/common.c
@@ -3,8 +3,24 @@
 // Copyright (c) 2018, The Linux Foundation. All rights reserved.
 
 #include <linux/module.h>
+#include <sound/pcm_params.h>
 #include "common.h"
 
+static int qcom_snd_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+				       struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = 2;
+	params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
+
+	return 0;
+}
+
 int qcom_snd_parse_of(struct snd_soc_card *card)
 {
 	struct device_node *np;
@@ -79,6 +95,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
 			}
 			link->no_pcm = 1;
 			link->ignore_pmdown_time = 1;
+			link->be_hw_params_fixup = qcom_snd_be_hw_params_fixup;
 		} else {
 			link->platform_of_node = link->cpu_of_node;
 			link->codec_dai_name = "snd-soc-dummy-dai";
diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c
index 2a781d8..87e150c 100644
--- a/sound/soc/qcom/sdm845.c
+++ b/sound/soc/qcom/sdm845.c
@@ -11,7 +11,6 @@
 #include "common.h"
 #include "qdsp6/q6afe.h"
 
-#define DEFAULT_SAMPLE_RATE_48K		48000
 #define DEFAULT_MCLK_RATE		24576000
 #define DEFAULT_BCLK_RATE		12288000
 
@@ -177,32 +176,15 @@ static struct snd_soc_ops sdm845_be_ops = {
 	.shutdown = sdm845_snd_shutdown,
 };
 
-static int sdm845_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
-				struct snd_pcm_hw_params *params)
-{
-	struct snd_interval *rate = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_RATE);
-	struct snd_interval *channels = hw_param_interval(params,
-					SNDRV_PCM_HW_PARAM_CHANNELS);
-	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
-
-	rate->min = rate->max = DEFAULT_SAMPLE_RATE_48K;
-	channels->min = channels->max = 2;
-	snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
-
-	return 0;
-}
-
 static void sdm845_add_be_ops(struct snd_soc_card *card)
 {
 	struct snd_soc_dai_link *link = card->dai_link;
 	int i, num_links = card->num_links;
 
 	for (i = 0; i < num_links; i++) {
-		if (link->no_pcm == 1) {
+		if (link->no_pcm == 1)
 			link->ops = &sdm845_be_ops;
-			link->be_hw_params_fixup = sdm845_be_hw_params_fixup;
-		}
+
 		link++;
 	}
 }
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [alsa-devel] [PATCH v4 14/14] ASoC: qcom: common: move be_hw_fixup to common
  2018-09-17  0:57 ` [PATCH v4 14/14] ASoC: qcom: common: move be_hw_fixup to common srinivas.kandagatla
@ 2018-09-19  5:49   ` Rohit Kumar
  2018-09-26 10:56     ` Srinivas Kandagatla
  0 siblings, 1 reply; 22+ messages in thread
From: Rohit Kumar @ 2018-09-19  5:49 UTC (permalink / raw)
  To: srinivas.kandagatla, lee.jones, robh+dt, broonie
  Cc: mark.rutland, devicetree, alsa-devel, bgoswami, lgirdwood,
	linux-kernel, vkoul

Hello Srinivas,


We will add support for vi feedback usecase in sdm845 machine driver 
where we have to support 4 channel tx data for a particular backend. We 
should probably keep be_hw_params_fixup in respective machine driver for 
now to support such requirement.


Thanks,

Rohit


On 9/17/2018 6:27 AM, srinivas.kandagatla@linaro.org wrote:
> From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>
> be_hw_fixup for qdsp is common across mutiple qcom machine drivers,
> so move it to common file and remove the redundant code.
>
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---
>   sound/soc/qcom/apq8096.c | 15 ---------------
>   sound/soc/qcom/common.c  | 17 +++++++++++++++++
>   sound/soc/qcom/sdm845.c  | 22 ++--------------------
>   3 files changed, 19 insertions(+), 35 deletions(-)
>
> diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c
> index daad43f..9cb26aee 100644
> --- a/sound/soc/qcom/apq8096.c
> +++ b/sound/soc/qcom/apq8096.c
> @@ -20,20 +20,6 @@ struct apq8096_card_data {
>   	bool jack_setup;
>   };
>   
> -static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
> -				      struct snd_pcm_hw_params *params)
> -{
> -	struct snd_interval *rate = hw_param_interval(params,
> -					SNDRV_PCM_HW_PARAM_RATE);
> -	struct snd_interval *channels = hw_param_interval(params,
> -					SNDRV_PCM_HW_PARAM_CHANNELS);
> -
> -	rate->min = rate->max = 48000;
> -	channels->min = channels->max = 2;
> -
> -	return 0;
> -}
> -
>   static int msm_snd_hw_params(struct snd_pcm_substream *substream,
>   			     struct snd_pcm_hw_params *params)
>   {
> @@ -139,7 +125,6 @@ static void apq8096_add_be_ops(struct snd_soc_card *card)
>   
>   	for (i = 0; i < num_links; i++) {
>   		if (link->no_pcm == 1) {
> -			link->be_hw_params_fixup = apq8096_be_hw_params_fixup;
>   			link->init = apq8096_init;
>   			link->ops = &apq8096_ops;
>   		}
> diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
> index eb1b9da..ce8e759 100644
> --- a/sound/soc/qcom/common.c
> +++ b/sound/soc/qcom/common.c
> @@ -3,8 +3,24 @@
>   // Copyright (c) 2018, The Linux Foundation. All rights reserved.
>   
>   #include <linux/module.h>
> +#include <sound/pcm_params.h>
>   #include "common.h"
>   
> +static int qcom_snd_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
> +				       struct snd_pcm_hw_params *params)
> +{
> +	struct snd_interval *rate = hw_param_interval(params,
> +					SNDRV_PCM_HW_PARAM_RATE);
> +	struct snd_interval *channels = hw_param_interval(params,
> +					SNDRV_PCM_HW_PARAM_CHANNELS);
> +
> +	rate->min = rate->max = 48000;
> +	channels->min = channels->max = 2;
> +	params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
> +
> +	return 0;
> +}
> +
>   int qcom_snd_parse_of(struct snd_soc_card *card)
>   {
>   	struct device_node *np;
> @@ -79,6 +95,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
>   			}
>   			link->no_pcm = 1;
>   			link->ignore_pmdown_time = 1;
> +			link->be_hw_params_fixup = qcom_snd_be_hw_params_fixup;
>   		} else {
>   			link->platform_of_node = link->cpu_of_node;
>   			link->codec_dai_name = "snd-soc-dummy-dai";
> diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c
> index 2a781d8..87e150c 100644
> --- a/sound/soc/qcom/sdm845.c
> +++ b/sound/soc/qcom/sdm845.c
> @@ -11,7 +11,6 @@
>   #include "common.h"
>   #include "qdsp6/q6afe.h"
>   
> -#define DEFAULT_SAMPLE_RATE_48K		48000
>   #define DEFAULT_MCLK_RATE		24576000
>   #define DEFAULT_BCLK_RATE		12288000
>   
> @@ -177,32 +176,15 @@ static struct snd_soc_ops sdm845_be_ops = {
>   	.shutdown = sdm845_snd_shutdown,
>   };
>   
> -static int sdm845_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
> -				struct snd_pcm_hw_params *params)
> -{
> -	struct snd_interval *rate = hw_param_interval(params,
> -					SNDRV_PCM_HW_PARAM_RATE);
> -	struct snd_interval *channels = hw_param_interval(params,
> -					SNDRV_PCM_HW_PARAM_CHANNELS);
> -	struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
> -
> -	rate->min = rate->max = DEFAULT_SAMPLE_RATE_48K;
> -	channels->min = channels->max = 2;
> -	snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
> -
> -	return 0;
> -}
> -
>   static void sdm845_add_be_ops(struct snd_soc_card *card)
>   {
>   	struct snd_soc_dai_link *link = card->dai_link;
>   	int i, num_links = card->num_links;
>   
>   	for (i = 0; i < num_links; i++) {
> -		if (link->no_pcm == 1) {
> +		if (link->no_pcm == 1)
>   			link->ops = &sdm845_be_ops;
> -			link->be_hw_params_fixup = sdm845_be_hw_params_fixup;
> -		}
> +
>   		link++;
>   	}
>   }


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v4 10/14] ASoC: dt-bindings: Add WCD9335 MBHC specific properties
  2018-09-17  0:57 ` [PATCH v4 10/14] ASoC: dt-bindings: Add WCD9335 MBHC specific properties srinivas.kandagatla
@ 2018-09-26  9:27   ` Banajit Goswami
  0 siblings, 0 replies; 22+ messages in thread
From: Banajit Goswami @ 2018-09-26  9:27 UTC (permalink / raw)
  To: srinivas.kandagatla, lee.jones, robh+dt, broonie
  Cc: mark.rutland, lgirdwood, devicetree, linux-kernel, vkoul, alsa-devel



On 9/16/2018 5:57 PM, srinivas.kandagatla@linaro.org wrote:
> From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>
> This patch add new bindings required to support MBHC
> (Multi Button Headset Control) block in the codec.
> This block is used for jack insert/removal detection,
> headset type detection and 8 button press/release events.
>
> All these properties are very much specific to board.
>
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---
>   .../devicetree/bindings/sound/qcom,wcd9335.txt       | 20 ++++++++++++++++++++
>   1 file changed, 20 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt b/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt
> index 5d6ea66..a95a8b4 100644
> --- a/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt
> +++ b/Documentation/devicetree/bindings/sound/qcom,wcd9335.txt
> @@ -55,6 +55,26 @@ Required properties with SLIMbus Interface:

> +- qcom,hphl-jack-type-normally-open:
> +	Usage: Optional, only required if headset button support required.
...only required if headset insertion/removal support required

> +	Value type: <boolean>
> +	Definition: present if hphl pin on jack is a NO (Normally Open).
> +		If not specified, then its assumed that hphl pin on jack
> +		is NC (Normally Closed).
> +
> +- qcom,gnd-jack-type-normally-open:
> +	Usage: Optional, only required if headset button support required.
...only required if headset insertion/removal support required.

> +	Value type: <boolean>
> +	Definition: present if gnd pin on jack is NO (Normally Open).
> +		 If not specified, then its assumed that gnd pin on
> +		 jack is NC  (Normally Closed).
Ground pin  may not be present on most of the headset jacks. So we 
cannot assume the type is NC if not specified in the device tree.

> +
>   - vdd-buck-supply:
>   	Usage: required
>   	Value type: <phandle>

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v4 11/14] ASoC: wcd9335: add mbhc support
  2018-09-17  0:57 ` [PATCH v4 11/14] ASoC: wcd9335: add mbhc support srinivas.kandagatla
@ 2018-09-26  9:31   ` Banajit Goswami
  2018-09-26 10:56     ` Srinivas Kandagatla
  0 siblings, 1 reply; 22+ messages in thread
From: Banajit Goswami @ 2018-09-26  9:31 UTC (permalink / raw)
  To: srinivas.kandagatla, lee.jones, robh+dt, broonie
  Cc: mark.rutland, lgirdwood, devicetree, linux-kernel, vkoul, alsa-devel



On 9/16/2018 5:57 PM, srinivas.kandagatla@linaro.org wrote:
> From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---
>   sound/soc/codecs/wcd9335.c | 268 ++++++++++++++++++++++++++++++++++++++++++++-
>   1 file changed, 266 insertions(+), 2 deletions(-)
>
> diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
> index efbb698..6c95cff 100644
> --- a/sound/soc/codecs/wcd9335.c
> +++ b/sound/soc/codecs/wcd9335.c

> @@ -89,12 +90,18 @@
>   #define  CF_MIN_3DB_75HZ		0x1
>   #define  CF_MIN_3DB_150HZ		0x2
>   
> +#define WCD9335_MBHC_MAX_BUTTONS	(8)
Though MBHC HW supports button detection up to 8, we are only supporting 
4 buttons in SW, right ?

> +
>   #define WCD9335_SLIM_RX_CH(p) \
>   	{.port = p + WCD9335_RX_START, .shift = p,}
>   
>   #define WCD9335_SLIM_TX_CH(p) \
>   	{.port = p, .shift = p,}

> @@ -3988,6 +4003,131 @@ static int wcd9335_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
>   	return ret;
>   }
>   
> +static irqreturn_t wcd9335_mbhc_sw_irq(int irq, void *data)
Are we supporting only headset and headphone detection for now ? 
Extension cable and electrical detection will be supported later ?
And how about cases for slow insertion scenarios ?

> +{
> +	struct wcd9335_codec *wcd = data;
>

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v4 11/14] ASoC: wcd9335: add mbhc support
  2018-09-26  9:31   ` Banajit Goswami
@ 2018-09-26 10:56     ` Srinivas Kandagatla
  0 siblings, 0 replies; 22+ messages in thread
From: Srinivas Kandagatla @ 2018-09-26 10:56 UTC (permalink / raw)
  To: Banajit Goswami, lee.jones, robh+dt, broonie
  Cc: mark.rutland, lgirdwood, devicetree, linux-kernel, vkoul, alsa-devel



On 26/09/18 10:31, Banajit Goswami wrote:
>> +static irqreturn_t wcd9335_mbhc_sw_irq(int irq, void *data)
> Are we supporting only headset and headphone detection for now ? 
> Extension cable and electrical detection will be supported later ?
> And how about cases for slow insertion scenarios ?
> 
I can not test extension cable and Other features like electrical 
detection will be added in future if we need it!

--srini
>> +{
>> +    struct wcd9335_codec *wcd = data;

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [alsa-devel] [PATCH v4 14/14] ASoC: qcom: common: move be_hw_fixup to common
  2018-09-19  5:49   ` [alsa-devel] " Rohit Kumar
@ 2018-09-26 10:56     ` Srinivas Kandagatla
  0 siblings, 0 replies; 22+ messages in thread
From: Srinivas Kandagatla @ 2018-09-26 10:56 UTC (permalink / raw)
  To: Rohit Kumar, lee.jones, robh+dt, broonie
  Cc: mark.rutland, devicetree, alsa-devel, bgoswami, lgirdwood,
	linux-kernel, vkoul



On 19/09/18 06:49, Rohit Kumar wrote:
> Hello Srinivas,
> 
> 
> We will add support for vi feedback usecase in sdm845 machine driver 
> where we have to support 4 channel tx data for a particular backend. We 
> should probably keep be_hw_params_fixup in respective machine driver for 
> now to support such requirement.
> 
I agree, we can drop this patch!

thanks,
srini
> 
> Thanks,
> 
> Rohit
> 
> 
> On 9/17/2018 6:27 AM, srinivas.kandagatla@linaro.org wrote:
>> From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>>
>> be_hw_fixup for qdsp is common across mutiple qcom machine drivers,
>> so move it to common file and remove the redundant code.
>>
>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
>> ---
>>   sound/soc/qcom/apq8096.c | 15 ---------------
>>   sound/soc/qcom/common.c  | 17 +++++++++++++++++
>>   sound/soc/qcom/sdm845.c  | 22 ++--------------------
>>   3 files changed, 19 insertions(+), 35 deletions(-)
>>
>> diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c
>> index daad43f..9cb26aee 100644
>> --- a/sound/soc/qcom/apq8096.c
>> +++ b/sound/soc/qcom/apq8096.c
>> @@ -20,20 +20,6 @@ struct apq8096_card_data {
>>       bool jack_setup;
>>   };
>> -static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
>> -                      struct snd_pcm_hw_params *params)
>> -{
>> -    struct snd_interval *rate = hw_param_interval(params,
>> -                    SNDRV_PCM_HW_PARAM_RATE);
>> -    struct snd_interval *channels = hw_param_interval(params,
>> -                    SNDRV_PCM_HW_PARAM_CHANNELS);
>> -
>> -    rate->min = rate->max = 48000;
>> -    channels->min = channels->max = 2;
>> -
>> -    return 0;
>> -}
>> -
>>   static int msm_snd_hw_params(struct snd_pcm_substream *substream,
>>                    struct snd_pcm_hw_params *params)
>>   {
>> @@ -139,7 +125,6 @@ static void apq8096_add_be_ops(struct snd_soc_card 
>> *card)
>>       for (i = 0; i < num_links; i++) {
>>           if (link->no_pcm == 1) {
>> -            link->be_hw_params_fixup = apq8096_be_hw_params_fixup;
>>               link->init = apq8096_init;
>>               link->ops = &apq8096_ops;
>>           }
>> diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
>> index eb1b9da..ce8e759 100644
>> --- a/sound/soc/qcom/common.c
>> +++ b/sound/soc/qcom/common.c
>> @@ -3,8 +3,24 @@
>>   // Copyright (c) 2018, The Linux Foundation. All rights reserved.
>>   #include <linux/module.h>
>> +#include <sound/pcm_params.h>
>>   #include "common.h"
>> +static int qcom_snd_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
>> +                       struct snd_pcm_hw_params *params)
>> +{
>> +    struct snd_interval *rate = hw_param_interval(params,
>> +                    SNDRV_PCM_HW_PARAM_RATE);
>> +    struct snd_interval *channels = hw_param_interval(params,
>> +                    SNDRV_PCM_HW_PARAM_CHANNELS);
>> +
>> +    rate->min = rate->max = 48000;
>> +    channels->min = channels->max = 2;
>> +    params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
>> +
>> +    return 0;
>> +}
>> +
>>   int qcom_snd_parse_of(struct snd_soc_card *card)
>>   {
>>       struct device_node *np;
>> @@ -79,6 +95,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
>>               }
>>               link->no_pcm = 1;
>>               link->ignore_pmdown_time = 1;
>> +            link->be_hw_params_fixup = qcom_snd_be_hw_params_fixup;
>>           } else {
>>               link->platform_of_node = link->cpu_of_node;
>>               link->codec_dai_name = "snd-soc-dummy-dai";
>> diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c
>> index 2a781d8..87e150c 100644
>> --- a/sound/soc/qcom/sdm845.c
>> +++ b/sound/soc/qcom/sdm845.c
>> @@ -11,7 +11,6 @@
>>   #include "common.h"
>>   #include "qdsp6/q6afe.h"
>> -#define DEFAULT_SAMPLE_RATE_48K        48000
>>   #define DEFAULT_MCLK_RATE        24576000
>>   #define DEFAULT_BCLK_RATE        12288000
>> @@ -177,32 +176,15 @@ static struct snd_soc_ops sdm845_be_ops = {
>>       .shutdown = sdm845_snd_shutdown,
>>   };
>> -static int sdm845_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
>> -                struct snd_pcm_hw_params *params)
>> -{
>> -    struct snd_interval *rate = hw_param_interval(params,
>> -                    SNDRV_PCM_HW_PARAM_RATE);
>> -    struct snd_interval *channels = hw_param_interval(params,
>> -                    SNDRV_PCM_HW_PARAM_CHANNELS);
>> -    struct snd_mask *fmt = hw_param_mask(params, 
>> SNDRV_PCM_HW_PARAM_FORMAT);
>> -
>> -    rate->min = rate->max = DEFAULT_SAMPLE_RATE_48K;
>> -    channels->min = channels->max = 2;
>> -    snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE);
>> -
>> -    return 0;
>> -}
>> -
>>   static void sdm845_add_be_ops(struct snd_soc_card *card)
>>   {
>>       struct snd_soc_dai_link *link = card->dai_link;
>>       int i, num_links = card->num_links;
>>       for (i = 0; i < num_links; i++) {
>> -        if (link->no_pcm == 1) {
>> +        if (link->no_pcm == 1)
>>               link->ops = &sdm845_be_ops;
>> -            link->be_hw_params_fixup = sdm845_be_hw_params_fixup;
>> -        }
>> +
>>           link++;
>>       }
>>   }
> 

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v4 02/14] mfd: wcd9335: add support to wcd9335 core
  2018-09-17  0:57 ` [PATCH v4 02/14] mfd: wcd9335: add support to wcd9335 core srinivas.kandagatla
@ 2018-10-24  7:07   ` Lee Jones
  2018-10-24 10:50     ` Srinivas Kandagatla
  0 siblings, 1 reply; 22+ messages in thread
From: Lee Jones @ 2018-10-24  7:07 UTC (permalink / raw)
  To: srinivas.kandagatla
  Cc: robh+dt, broonie, mark.rutland, lgirdwood, bgoswami, devicetree,
	linux-kernel, vkoul, alsa-devel

On Sun, 16 Sep 2018, srinivas.kandagatla@linaro.org wrote:

> From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> 
> Qualcomm WCD9335 Codec is a standalone Hi-Fi audio codec IC,
> It has mulitple blocks like Soundwire controller, codec,
> Codec processing engine, ClassH controller, interrupt mux.
> It supports both I2S/I2C and SLIMbus audio interfaces.
> 
> This patch adds support to SLIMbus audio interface.
> 
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> Reviewed-by: Vinod Koul <vkoul@kernel.org>
> ---
>  drivers/mfd/Kconfig                   |  13 +
>  drivers/mfd/Makefile                  |   4 +
>  drivers/mfd/wcd9335-core.c            | 316 +++++++++++++++++
>  include/linux/mfd/wcd9335/registers.h | 640 ++++++++++++++++++++++++++++++++++
>  include/linux/mfd/wcd9335/wcd9335.h   |  45 +++
>  5 files changed, 1018 insertions(+)
>  create mode 100644 drivers/mfd/wcd9335-core.c
>  create mode 100644 include/linux/mfd/wcd9335/registers.h
>  create mode 100644 include/linux/mfd/wcd9335/wcd9335.h
> 
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 11841f4..a7bff87 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -1807,6 +1807,19 @@ config MFD_WM97xx
>  	  support for the WM97xx, in order to use the actual functionaltiy of
>  	  the device other drivers must be enabled.
>  
> +config MFD_WCD9335_SLIM
> +	tristate "Qualcomm WCD9335 with SLIMbus"
> +	select MFD_CORE
> +	select REGMAP_IRQ
> +	select REGMAP_SLIMBUS
> +	depends on SLIMBUS
> +	help
> +	  The WCD9335 is a standalone Hi-Fi audio CODEC IC, supports Qualcomm
> +	  Technologies, Inc. (QTI) multimedia solutions, including the MSM8996,
> +	  MSM8976, and MSM8956 chipsets. It has in-build Soundwire controller,
> +	  interrupt mux. It supports both I2S/I2C and SLIMbus audio interfaces.
> +	  This option selects SLIMbus audio interface.
> +
>  config MFD_STW481X
>  	tristate "Support for ST Microelectronics STw481x"
>  	depends on I2C && (ARCH_NOMADIK || COMPILE_TEST)
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 5856a94..9d0b98d 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -56,6 +56,10 @@ endif
>  ifeq ($(CONFIG_MFD_CS47L24),y)
>  obj-$(CONFIG_MFD_ARIZONA)	+= cs47l24-tables.o
>  endif
> +
> +obj-$(CONFIG_MFD_WCD9335_SLIM)	+= wcd9335.o
> +wcd9335-objs			:= wcd9335-core.o
> +
>  obj-$(CONFIG_MFD_WM8400)	+= wm8400-core.o
>  wm831x-objs			:= wm831x-core.o wm831x-irq.o wm831x-otp.o
>  wm831x-objs			+= wm831x-auxadc.o
> diff --git a/drivers/mfd/wcd9335-core.c b/drivers/mfd/wcd9335-core.c
> new file mode 100644
> index 0000000..81ec0fc
> --- /dev/null
> +++ b/drivers/mfd/wcd9335-core.c
> @@ -0,0 +1,316 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (c) 2018, Linaro Limited
> +
> +#include <linux/clk.h>
> +#include <linux/gpio.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/core.h>
> +#include <linux/mfd/wcd9335/registers.h>
> +#include <linux/mfd/wcd9335/wcd9335.h>
> +#include <linux/module.h>
> +#include <linux/of_gpio.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +#include <linux/slimbus.h>
> +
> +#define WCD9335_SLIM_INTERFACE_DEVICE_INDEX	0
> +
> +static const struct mfd_cell wcd9335_devices[] = {
> +	{ .name = "wcd9335-codec", },
> +};

Any news on other devices?

> +static const struct regmap_range_cfg wcd9335_ranges[] = {
> +	{
> +		.name = "WCD9335",
> +		.range_min =  0x0,
> +		.range_max =  WCD9335_MAX_REGISTER,
> +		.selector_reg = WCD9335_REG(0x0, 0),
> +		.selector_mask = 0xff,
> +		.selector_shift = 0,
> +		.window_start = 0x0,
> +		.window_len = 0x1000,
> +	},
> +};
> +
> +static bool wcd9335_is_volatile_register(struct device *dev, unsigned int reg)
> +{
> +	switch (reg) {
> +	case WCD9335_INTR_PIN1_STATUS0...WCD9335_INTR_PIN2_CLEAR3:
> +	case WCD9335_ANA_MBHC_RESULT_3:
> +	case WCD9335_ANA_MBHC_RESULT_2:
> +	case WCD9335_ANA_MBHC_RESULT_1:
> +	case WCD9335_ANA_MBHC_MECH:
> +	case WCD9335_ANA_MBHC_ELECT:
> +	case WCD9335_ANA_MBHC_ZDET:
> +	case WCD9335_ANA_MICB2:
> +	case WCD9335_ANA_RCO:
> +	case WCD9335_ANA_BIAS:
> +		return true;
> +	default:
> +		return false;
> +	}
> +}
> +
> +static struct regmap_config wcd9335_regmap_config = {
> +	.reg_bits = 16,
> +	.val_bits = 8,
> +	.cache_type = REGCACHE_RBTREE,
> +	.max_register = WCD9335_MAX_REGISTER,
> +	.can_multi_write = true,
> +	.ranges = wcd9335_ranges,
> +	.num_ranges = ARRAY_SIZE(wcd9335_ranges),
> +	.volatile_reg = wcd9335_is_volatile_register,
> +};
> +
> +static const struct regmap_range_cfg wcd9335_interface_ranges[] = {
> +	{
> +		.name = "WCD9335-Interface",
> +		.range_min =  0x0,
> +		.range_max = WCD9335_REG(0, 0x7ff),
> +		.selector_reg = WCD9335_REG(0, 0x0),
> +		.selector_mask = 0xff,
> +		.selector_shift = 0,
> +		.window_start = 0x0,
> +		.window_len = 0x1000,
> +	},
> +};
> +
> +static struct regmap_config wcd9335_interface_regmap_config = {
> +	.reg_bits = 16,
> +	.val_bits = 8,
> +	.can_multi_write = true,
> +	.max_register = WCD9335_REG(0, 0x7FF),
> +	.ranges = wcd9335_interface_ranges,
> +	.num_ranges = ARRAY_SIZE(wcd9335_interface_ranges),
> +};
> +
> +static struct wcd9335 *wcd_data;

This does not need to be global.

Please move it into .probe().

> +static int wcd9335_parse_resources(struct wcd9335 *ddata)
> +{
> +	struct device *dev = ddata->dev;
> +	struct device_node *np = dev->of_node;
> +	int ret;
> +
> +	ddata->reset_gpio = of_get_named_gpio(np,	"reset-gpios", 0);

Odd whitespace issue.

> +	if (ddata->reset_gpio < 0) {
> +		dev_err(dev, "Reset GPIO missing from DT\n");

I'm not sure you have to be that specific.  Especially when below you
simply say that the clock is missing.  I think "Reset GPIO not found"
is suitable.

> +		return ddata->reset_gpio;
> +	}
> +
> +	ddata->mclk = devm_clk_get(dev, "mclk");
> +	if (IS_ERR(ddata->mclk)) {
> +		dev_err(dev, "mclk not found\n");
> +		return PTR_ERR(ddata->mclk);
> +	}
> +
> +	ddata->native_clk = devm_clk_get(dev, "slimbus");
> +	if (IS_ERR(ddata->native_clk)) {
> +		dev_err(dev, "slimbus clock not found\n");
> +		return PTR_ERR(ddata->native_clk);
> +	}
> +
> +	ddata->supplies[0].supply = "vdd-buck";
> +	ddata->supplies[1].supply = "vdd-buck-sido";
> +	ddata->supplies[2].supply = "vdd-tx";
> +	ddata->supplies[3].supply = "vdd-rx";
> +	ddata->supplies[4].supply = "vdd-io";
> +
> +	ret = regulator_bulk_get(dev, WCD9335_MAX_SUPPLY, ddata->supplies);
> +	if (ret) {
> +		dev_err(dev, "Failed to get supplies: err = %d\n", ret);

Remove the 'err'.  It's pretty ugly.

		dev_err(dev, "Failed to get supplies: %d\n", ret);

> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int wcd9335_power_on_reset(struct wcd9335 *ddata)
> +{
> +	struct device *dev = ddata->dev;
> +	int ret;
> +
> +	ret = regulator_bulk_enable(WCD9335_MAX_SUPPLY, ddata->supplies);
> +	if (ret) {
> +		dev_err(dev, "Failed to get supplies: err = %d\n", ret);
> +		return ret;
> +	}
> +
> +	/*
> +	 * For WCD9335, it takes about 600us for the Vout_A and
> +	 * Vout_D to be ready after BUCK_SIDO is powered up.
> +	 * SYS_RST_N shouldn't be pulled high during this time
> +	 * Toggle the reset line to make sure the reset pulse is
> +	 * correctly applied
> +	 */
> +	usleep_range(600, 650);
> +
> +	gpio_direction_output(ddata->reset_gpio, 0);
> +	msleep(20);
> +	gpio_set_value(ddata->reset_gpio, 1);
> +	msleep(20);
> +
> +	return 0;
> +}
> +
> +static int wcd9335_bring_up(struct wcd9335 *ddata)
> +{
> +	struct regmap *rm = ddata->regmap;
> +	int ver;
> +
> +	regmap_read(rm, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0, &ver);
> +
> +	if (ver == WCD9334_CHIP_ID_VER_V2_0) {
> +		dev_info(ddata->dev, "WCD9335 CODEC version is v2.0\n");

How much do you really want to see this on the boot log?

> +		ddata->version = WCD9335_VERSION_2_0;
> +		regmap_write(rm, WCD9335_CODEC_RPM_RST_CTL,
> +					WCD9335_CODEC_ANA_OUT_OF_RST);
> +		regmap_write(rm, WCD9335_SIDO_SIDO_TEST_2, 0x00);
> +		regmap_write(rm, WCD9335_SIDO_SIDO_CCL_8,
> +					WCD9335_ANALOG_DEF_VALUE);
> +		regmap_write(rm, WCD9335_BIAS_VBG_FINE_ADJ,
> +					WCD9335_VBIAS_FINE_ADJ_DEF_VAL);
> +		regmap_write(rm, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
> +				WCD9335_HEADSWITCH_CONTROL_PWR_ON);
> +		regmap_write(rm, WCD9335_CODEC_RPM_RST_CTL,
> +					WCD9335_CODEC_ANA_OUT_OF_RST |
> +					WCD9335_CODEC_DIG_OUT_OF_RST);
> +	} else {
> +		dev_err(ddata->dev, "WCD9335 CODEC version not supported\n");

I think you should print out the failed version.

> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int wcd9335_slim_status(struct slim_device *sdev,
> +			       enum slim_device_status status)
> +{
> +	struct wcd9335 *ddata = dev_get_drvdata(&sdev->dev);
> +	int ret;
> +
> +	if (ddata->regmap && ddata->interface_dev_regmap) {
> +		switch (status) {
> +		case SLIM_DEVICE_STATUS_UP:
> +			ret = mfd_add_devices(ddata->dev, 0, wcd9335_devices,
> +					ARRAY_SIZE(wcd9335_devices),
> +					NULL, 0, NULL);
> +			if (ret) {
> +				dev_err(ddata->dev,
> +					"Failed to add mfd devices: %d\n",
> +					ret);
> +				return ret;
> +			}
> +			break;
> +		case SLIM_DEVICE_STATUS_DOWN:
> +			mfd_remove_devices(ddata->dev);
> +			break;
> +		default:
> +			return -EINVAL;
> +		}
> +	}

This is all quite horrible.  Why do you want to bind/unbind the device
every time you power up/down the device?

> +	return 0;
> +}
> +
> +static int wcd9335_slim_probe(struct slim_device *slim)
> +{
> +	struct device *dev = &slim->dev;
> +	struct wcd9335 *ddata;
> +	int ret;
> +
> +	if (!wcd_data) {
> +		wcd_data = kzalloc(sizeof(*wcd_data), GFP_KERNEL);

devm_*?

> +		if (!wcd_data)
> +			return	-ENOMEM;
> +	}
> +
> +	ddata = wcd_data;
> +	dev_set_drvdata(dev, ddata);
> +
> +	/* Interface device */
> +	if (slim->e_addr.dev_index == WCD9335_SLIM_INTERFACE_DEVICE_INDEX) {
> +		if (slim_get_logical_addr(slim)) {
> +			dev_err(dev, "Failed to get logical address\n");
> +			return -EPROBE_DEFER;
> +		}
> +
> +		ddata->slim_interface_dev = slim;

If you set this below the next if (), you don't need to NULLify it in
the error path.

> +		ddata->interface_dev_regmap = regmap_init_slimbus(slim,
> +					  &wcd9335_interface_regmap_config);
> +		if (IS_ERR(ddata->interface_dev_regmap)) {
> +			ddata->slim_interface_dev = NULL;
> +			dev_err(&slim->dev,
> +				"Failed to allocate SLIM Interface regmap\n");
> +			return PTR_ERR(ddata->interface_dev_regmap);
> +		}
> +
> +		return 0;
> +
> +	}
> +
> +	ddata->regmap = regmap_init_slimbus(slim, &wcd9335_regmap_config);
> +	if (IS_ERR(ddata->regmap)) {
> +		dev_err(ddata->dev, "Failed to allocate SLIM regmap\n");
> +		ddata->regmap = NULL;

If you're returning an error, why do you need to NULLify this?

> +		return PTR_ERR(ddata->regmap);
> +	}
> +
> +	ddata->dev = dev;
> +	ddata->slim = slim;
> +	ddata->intf_type = WCD9335_INTERFACE_TYPE_SLIMBUS;
> +
> +	ret = wcd9335_parse_resources(ddata);
> +	if (ret) {
> +		dev_err(dev, "Error parsing DT: %d\n", ret);

If you have suitable specific error messages in
wcd9335_parse_resources(), you don't need another one.

> +		return ret;
> +	}
> +
> +	ret = wcd9335_power_on_reset(ddata);
> +	if (ret)
> +		return ret;
> +
> +	if (slim_get_logical_addr(slim)) {
> +		dev_err(dev, "Failed to get logical address\n");
> +		return -EPROBE_DEFER;

Unless you use devm_*, you'll need to clean-up first.

> +	}
> +
> +	ret = wcd9335_bring_up(ddata);
> +	if (ret) {
> +		dev_err(ddata->dev, "Failed to bringup WCD9335\n");

If you have suitable specific error messages in wcd9335_bring_up(),
you don't need another one.

> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static void wcd9335_slim_remove(struct slim_device *slim)
> +{
> +	if (slim->e_addr.dev_index != WCD9335_SLIM_INTERFACE_DEVICE_INDEX)
> +		mfd_remove_devices(&slim->dev);

devm_*?

Then you can remove this function.

> +	kfree(wcd_data);
> +	wcd_data = NULL;
> +}
> +
> +static const struct of_device_id wcd9335_device_id[]  = {
> +	{ .compatible = "slim217,1a0" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, wcd9335_device_id);
> +
> +static struct slim_driver wcd9335_slim_driver = {
> +	.driver = {
> +		.name = "wcd9335-slim",
> +		.of_match_table = of_match_ptr(wcd9335_device_id),
> +	},
> +	.probe = wcd9335_slim_probe,
> +	.remove = wcd9335_slim_remove,
> +	.device_status = wcd9335_slim_status,
> +};
> +
> +module_slim_driver(wcd9335_slim_driver);
> +MODULE_DESCRIPTION("WCD9335 slim driver");
> +MODULE_LICENSE("GPL v2");

AUTHOR?

> diff --git a/include/linux/mfd/wcd9335/registers.h b/include/linux/mfd/wcd9335/registers.h
> new file mode 100644
> index 0000000..24c02ad
> --- /dev/null
> +++ b/include/linux/mfd/wcd9335/registers.h
> @@ -0,0 +1,640 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (c) 2018, Linaro Limited */
> +
> +#ifndef _WCD9335_REGISTERS_H
> +#define _WCD9335_REGISTERS_H
> +
> +/*
> + * WCD9335 register base can change according to the mode it works in
> + * in SLIMBUS mode the reg base starts from 0x800
> + * in i2s/i2c mode the reg base is 0x0
> + */
> +#define WCD9335_REG(pg, r)	((pg << 12) | (r) | 0x800)
> +#define WCD9335_REG_OFFSET(r)	(r & 0xFF)
> +#define WCD9335_PAGE_OFFSET(r)	((r >> 12) & 0xFF)
> +
> +/* Page-0 Registers */
> +#define WCD9335_PAGE0_PAGE_REGISTER		WCD9335_REG(0x00, 0x000)
> +#define WCD9335_CODEC_RPM_CLK_GATE		WCD9335_REG(0x00, 0x002)
> +#define WCD9335_CODEC_RPM_CLK_GATE_MCLK_GATE_MASK	GENMASK(1, 0)
> +#define WCD9335_CODEC_RPM_CLK_MCLK_CFG		WCD9335_REG(0x00, 0x003)
> +#define WCD9335_CODEC_RPM_CLK_MCLK_CFG_9P6MHZ	BIT(0)
> +#define WCD9335_CODEC_RPM_CLK_MCLK_CFG_12P288MHZ	BIT(0)
> +#define WCD9335_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK	GENMASK(1, 0)
> +#define WCD9335_CODEC_RPM_RST_CTL		WCD9335_REG(0x00, 0x009)
> +#define WCD9335_CODEC_ANA_RST			0
> +#define WCD9335_CODEC_ANA_OUT_OF_RST		BIT(0)
> +#define WCD9335_CODEC_DIG_RST			0
> +#define WCD9335_CODEC_DIG_OUT_OF_RST		BIT(1)
> +#define WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL	WCD9335_REG(0x00, 0x011)
> +#define WCD9335_HEADSWITCH_CONTROL_PWR_ON	GENMASK(1, 0)
> +#define WCD9335_HEADSWITCH_PWR_ON		BIT(0)
> +#define WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0	WCD9335_REG(0x00, 0x021)
> +#define WCD9334_CHIP_ID_VER_V2_0		BIT(0)
> +#define WCD9335_CHIP_TIER_CTRL_EFUSE_CTL	WCD9335_REG(0x00, 0x025)
> +#define WCD9335_CHIP_TIER_CTRL_EFUSE_SSTATE_MASK GENMASK(4, 1)
> +#define WCD9335_CHIP_TIER_CTRL_EFUSE_EN_MASK	BIT(0)
> +#define WCD9335_CHIP_TIER_CTRL_EFUSE_ENABLE	BIT(0)
> +#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0	WCD9335_REG(0x00, 0x029)
> +#define WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS	WCD9335_REG(0x00, 0x039)
> +#define WCD9335_INTR_CFG			WCD9335_REG(0x00, 0x081)
> +#define WCD9335_INTR_CLR_COMMIT			WCD9335_REG(0x00, 0x082)
> +#define WCD9335_INTR_PIN1_MASK0			WCD9335_REG(0x00, 0x089)
> +#define WCD9335_INTR_PIN1_MASK1			WCD9335_REG(0x00, 0x08a)
> +#define WCD9335_INTR_PIN1_MASK2			WCD9335_REG(0x00, 0x08b)
> +#define WCD9335_INTR_PIN1_MASK3			WCD9335_REG(0x00, 0x08c)
> +#define WCD9335_INTR_PIN1_STATUS0		WCD9335_REG(0x00, 0x091)
> +#define WCD9335_INTR_PIN1_STATUS1		WCD9335_REG(0x00, 0x092)
> +#define WCD9335_INTR_PIN1_STATUS2		WCD9335_REG(0x00, 0x093)
> +#define WCD9335_INTR_PIN1_STATUS3		WCD9335_REG(0x00, 0x094)
> +#define WCD9335_INTR_PIN1_CLEAR0		WCD9335_REG(0x00, 0x099)
> +#define WCD9335_INTR_PIN1_CLEAR1		WCD9335_REG(0x00, 0x09a)
> +#define WCD9335_INTR_PIN1_CLEAR2		WCD9335_REG(0x00, 0x09b)
> +#define WCD9335_INTR_PIN1_CLEAR3		WCD9335_REG(0x00, 0x09c)
> +#define WCD9335_INTR_PIN2_MASK0			WCD9335_REG(0x00, 0x0a1)
> +#define WCD9335_INTR_PIN2_MASK1			WCD9335_REG(0x00, 0x0a2)
> +#define WCD9335_INTR_PIN2_MASK2			WCD9335_REG(0x00, 0x0a3)
> +#define WCD9335_INTR_PIN2_MASK3			WCD9335_REG(0x00, 0x0a4)
> +#define WCD9335_INTR_PIN2_STATUS0		WCD9335_REG(0x00, 0x0a9)
> +#define WCD9335_INTR_PIN2_STATUS1		WCD9335_REG(0x00, 0x0aa)
> +#define WCD9335_INTR_PIN2_STATUS2		WCD9335_REG(0x00, 0x0ab)
> +#define WCD9335_INTR_PIN2_STATUS3		WCD9335_REG(0x00, 0x0ac)
> +#define WCD9335_INTR_PIN2_CLEAR0		WCD9335_REG(0x00, 0x0b1)
> +#define WCD9335_INTR_PIN2_CLEAR1		WCD9335_REG(0x00, 0x0b2)
> +#define WCD9335_INTR_PIN2_CLEAR2		WCD9335_REG(0x00, 0x0b3)
> +#define WCD9335_INTR_PIN2_CLEAR3		WCD9335_REG(0x00, 0x0b4)
> +#define WCD9335_INTR_LEVEL0			WCD9335_REG(0x00, 0x0e1)
> +#define WCD9335_INTR_LEVEL1			WCD9335_REG(0x00, 0x0e2)
> +#define WCD9335_INTR_LEVEL2			WCD9335_REG(0x00, 0x0e3)
> +#define WCD9335_INTR_LEVEL3			WCD9335_REG(0x00, 0x0e4)
> +
> +/* Page-1 Registers */
> +#define WCD9335_CPE_FLL_USER_CTL_0		WCD9335_REG(0x01, 0x001)
> +#define WCD9335_CPE_FLL_USER_CTL_1		WCD9335_REG(0x01, 0x002)
> +#define WCD9335_CPE_FLL_USER_CTL_2		WCD9335_REG(0x01, 0x003)
> +#define WCD9335_CPE_FLL_USER_CTL_3		WCD9335_REG(0x01, 0x004)
> +#define WCD9335_CPE_FLL_USER_CTL_4		WCD9335_REG(0x01, 0x005)
> +#define WCD9335_CPE_FLL_USER_CTL_5		WCD9335_REG(0x01, 0x006)
> +#define WCD9335_CPE_FLL_USER_CTL_6		WCD9335_REG(0x01, 0x007)
> +#define WCD9335_CPE_FLL_USER_CTL_7		WCD9335_REG(0x01, 0x008)
> +#define WCD9335_CPE_FLL_USER_CTL_8		WCD9335_REG(0x01, 0x009)
> +#define WCD9335_CPE_FLL_USER_CTL_9		WCD9335_REG(0x01, 0x00a)
> +#define WCD9335_CPE_FLL_L_VAL_CTL_0		WCD9335_REG(0x01, 0x00b)
> +#define WCD9335_CPE_FLL_L_VAL_CTL_1		WCD9335_REG(0x01, 0x00c)
> +#define WCD9335_CPE_FLL_DSM_FRAC_CTL_0		WCD9335_REG(0x01, 0x00d)
> +#define WCD9335_CPE_FLL_DSM_FRAC_CTL_1		WCD9335_REG(0x01, 0x00e)
> +#define WCD9335_CPE_FLL_CONFIG_CTL_0		WCD9335_REG(0x01, 0x00f)
> +#define WCD9335_CPE_FLL_CONFIG_CTL_1		WCD9335_REG(0x01, 0x010)
> +#define WCD9335_CPE_FLL_CONFIG_CTL_2		WCD9335_REG(0x01, 0x011)
> +#define WCD9335_CPE_FLL_CONFIG_CTL_3		WCD9335_REG(0x01, 0x012)
> +#define WCD9335_CPE_FLL_CONFIG_CTL_4		WCD9335_REG(0x01, 0x013)
> +#define WCD9335_CPE_FLL_TEST_CTL_0		WCD9335_REG(0x01, 0x014)
> +#define WCD9335_CPE_FLL_TEST_CTL_1		WCD9335_REG(0x01, 0x015)
> +#define WCD9335_CPE_FLL_TEST_CTL_2		WCD9335_REG(0x01, 0x016)
> +#define WCD9335_CPE_FLL_TEST_CTL_3		WCD9335_REG(0x01, 0x017)
> +#define WCD9335_CPE_FLL_TEST_CTL_4		WCD9335_REG(0x01, 0x018)
> +#define WCD9335_CPE_FLL_TEST_CTL_5		WCD9335_REG(0x01, 0x019)
> +#define WCD9335_CPE_FLL_TEST_CTL_6		WCD9335_REG(0x01, 0x01a)
> +#define WCD9335_CPE_FLL_TEST_CTL_7		WCD9335_REG(0x01, 0x01b)
> +#define WCD9335_CPE_FLL_FREQ_CTL_0		WCD9335_REG(0x01, 0x01c)
> +#define WCD9335_CPE_FLL_FREQ_CTL_1		WCD9335_REG(0x01, 0x01d)
> +#define WCD9335_CPE_FLL_FREQ_CTL_2		WCD9335_REG(0x01, 0x01e)
> +#define WCD9335_CPE_FLL_FREQ_CTL_3		WCD9335_REG(0x01, 0x01f)
> +#define WCD9335_CPE_FLL_SSC_CTL_0		WCD9335_REG(0x01, 0x020)
> +#define WCD9335_CPE_FLL_SSC_CTL_1		WCD9335_REG(0x01, 0x021)
> +#define WCD9335_CPE_FLL_SSC_CTL_2		WCD9335_REG(0x01, 0x022)
> +#define WCD9335_CPE_FLL_SSC_CTL_3		WCD9335_REG(0x01, 0x023)
> +#define WCD9335_CPE_FLL_FLL_MODE		WCD9335_REG(0x01, 0x024)
> +#define WCD9335_CPE_FLL_STATUS_0		WCD9335_REG(0x01, 0x025)
> +#define WCD9335_CPE_FLL_STATUS_1		WCD9335_REG(0x01, 0x026)
> +#define WCD9335_CPE_FLL_STATUS_2		WCD9335_REG(0x01, 0x027)
> +#define WCD9335_CPE_FLL_STATUS_3		WCD9335_REG(0x01, 0x028)
> +#define WCD9335_I2S_FLL_USER_CTL_0		WCD9335_REG(0x01, 0x041)
> +#define WCD9335_I2S_FLL_USER_CTL_1		WCD9335_REG(0x01, 0x042)
> +#define WCD9335_I2S_FLL_USER_CTL_2		WCD9335_REG(0x01, 0x043)
> +#define WCD9335_I2S_FLL_USER_CTL_3		WCD9335_REG(0x01, 0x044)
> +#define WCD9335_I2S_FLL_USER_CTL_4		WCD9335_REG(0x01, 0x045)
> +#define WCD9335_I2S_FLL_USER_CTL_5		WCD9335_REG(0x01, 0x046)
> +#define WCD9335_I2S_FLL_USER_CTL_6		WCD9335_REG(0x01, 0x047)
> +#define WCD9335_I2S_FLL_USER_CTL_7		WCD9335_REG(0x01, 0x048)
> +#define WCD9335_I2S_FLL_USER_CTL_8		WCD9335_REG(0x01, 0x049)
> +#define WCD9335_I2S_FLL_USER_CTL_9		WCD9335_REG(0x01, 0x04a)
> +#define WCD9335_I2S_FLL_L_VAL_CTL_0		WCD9335_REG(0x01, 0x04b)
> +#define WCD9335_I2S_FLL_L_VAL_CTL_1		WCD9335_REG(0x01, 0x04c)
> +#define WCD9335_I2S_FLL_DSM_FRAC_CTL_0		WCD9335_REG(0x01, 0x04d)
> +#define WCD9335_I2S_FLL_DSM_FRAC_CTL_1		WCD9335_REG(0x01, 0x04e)
> +#define WCD9335_I2S_FLL_CONFIG_CTL_0		WCD9335_REG(0x01, 0x04f)
> +#define WCD9335_I2S_FLL_CONFIG_CTL_1		WCD9335_REG(0x01, 0x050)
> +#define WCD9335_I2S_FLL_CONFIG_CTL_2		WCD9335_REG(0x01, 0x051)
> +#define WCD9335_I2S_FLL_CONFIG_CTL_3		WCD9335_REG(0x01, 0x052)
> +#define WCD9335_I2S_FLL_CONFIG_CTL_4		WCD9335_REG(0x01, 0x053)
> +#define WCD9335_I2S_FLL_TEST_CTL_0		WCD9335_REG(0x01, 0x054)
> +#define WCD9335_I2S_FLL_TEST_CTL_1		WCD9335_REG(0x01, 0x055)
> +#define WCD9335_I2S_FLL_TEST_CTL_2		WCD9335_REG(0x01, 0x056)
> +#define WCD9335_I2S_FLL_TEST_CTL_3		WCD9335_REG(0x01, 0x057)
> +#define WCD9335_I2S_FLL_TEST_CTL_4		WCD9335_REG(0x01, 0x058)
> +#define WCD9335_I2S_FLL_TEST_CTL_5		WCD9335_REG(0x01, 0x059)
> +#define WCD9335_I2S_FLL_TEST_CTL_6		WCD9335_REG(0x01, 0x05a)
> +#define WCD9335_I2S_FLL_TEST_CTL_7		WCD9335_REG(0x01, 0x05b)
> +#define WCD9335_I2S_FLL_FREQ_CTL_0		WCD9335_REG(0x01, 0x05c)
> +#define WCD9335_I2S_FLL_FREQ_CTL_1		WCD9335_REG(0x01, 0x05d)
> +#define WCD9335_I2S_FLL_FREQ_CTL_2		WCD9335_REG(0x01, 0x05e)
> +#define WCD9335_I2S_FLL_FREQ_CTL_3		WCD9335_REG(0x01, 0x05f)
> +#define WCD9335_I2S_FLL_SSC_CTL_0		WCD9335_REG(0x01, 0x060)
> +#define WCD9335_I2S_FLL_SSC_CTL_1		WCD9335_REG(0x01, 0x061)
> +#define WCD9335_I2S_FLL_SSC_CTL_2		WCD9335_REG(0x01, 0x062)
> +#define WCD9335_I2S_FLL_SSC_CTL_3		WCD9335_REG(0x01, 0x063)
> +#define WCD9335_I2S_FLL_FLL_MODE		WCD9335_REG(0x01, 0x064)
> +#define WCD9335_I2S_FLL_STATUS_0		WCD9335_REG(0x01, 0x065)
> +#define WCD9335_I2S_FLL_STATUS_1		WCD9335_REG(0x01, 0x066)
> +#define WCD9335_I2S_FLL_STATUS_2		WCD9335_REG(0x01, 0x067)
> +#define WCD9335_I2S_FLL_STATUS_3		WCD9335_REG(0x01, 0x068)
> +#define WCD9335_SB_FLL_USER_CTL_0		WCD9335_REG(0x01, 0x081)
> +#define WCD9335_SB_FLL_USER_CTL_1		WCD9335_REG(0x01, 0x082)
> +#define WCD9335_SB_FLL_USER_CTL_2		WCD9335_REG(0x01, 0x083)
> +#define WCD9335_SB_FLL_USER_CTL_3		WCD9335_REG(0x01, 0x084)
> +#define WCD9335_SB_FLL_USER_CTL_4		WCD9335_REG(0x01, 0x085)
> +#define WCD9335_SB_FLL_USER_CTL_5		WCD9335_REG(0x01, 0x086)
> +#define WCD9335_SB_FLL_USER_CTL_6		WCD9335_REG(0x01, 0x087)
> +#define WCD9335_SB_FLL_USER_CTL_7		WCD9335_REG(0x01, 0x088)
> +#define WCD9335_SB_FLL_USER_CTL_8		WCD9335_REG(0x01, 0x089)
> +#define WCD9335_SB_FLL_USER_CTL_9		WCD9335_REG(0x01, 0x08a)
> +#define WCD9335_SB_FLL_L_VAL_CTL_0		WCD9335_REG(0x01, 0x08b)
> +#define WCD9335_SB_FLL_L_VAL_CTL_1		WCD9335_REG(0x01, 0x08c)
> +#define WCD9335_SB_FLL_DSM_FRAC_CTL_0		WCD9335_REG(0x01, 0x08d)
> +#define WCD9335_SB_FLL_DSM_FRAC_CTL_1		WCD9335_REG(0x01, 0x08e)
> +#define WCD9335_SB_FLL_CONFIG_CTL_0		WCD9335_REG(0x01, 0x08f)
> +#define WCD9335_SB_FLL_CONFIG_CTL_1		WCD9335_REG(0x01, 0x090)
> +#define WCD9335_SB_FLL_CONFIG_CTL_2		WCD9335_REG(0x01, 0x091)
> +#define WCD9335_SB_FLL_CONFIG_CTL_3		WCD9335_REG(0x01, 0x092)
> +#define WCD9335_SB_FLL_CONFIG_CTL_4		WCD9335_REG(0x01, 0x093)
> +#define WCD9335_SB_FLL_TEST_CTL_0		WCD9335_REG(0x01, 0x094)
> +#define WCD9335_SB_FLL_TEST_CTL_1		WCD9335_REG(0x01, 0x095)
> +#define WCD9335_SB_FLL_TEST_CTL_2		WCD9335_REG(0x01, 0x096)
> +#define WCD9335_SB_FLL_TEST_CTL_3		WCD9335_REG(0x01, 0x097)
> +#define WCD9335_SB_FLL_TEST_CTL_4		WCD9335_REG(0x01, 0x098)
> +#define WCD9335_SB_FLL_TEST_CTL_5		WCD9335_REG(0x01, 0x099)
> +#define WCD9335_SB_FLL_TEST_CTL_6		WCD9335_REG(0x01, 0x09a)
> +#define WCD9335_SB_FLL_TEST_CTL_7		WCD9335_REG(0x01, 0x09b)
> +#define WCD9335_SB_FLL_FREQ_CTL_0		WCD9335_REG(0x01, 0x09c)
> +#define WCD9335_SB_FLL_FREQ_CTL_1		WCD9335_REG(0x01, 0x09d)
> +#define WCD9335_SB_FLL_FREQ_CTL_2		WCD9335_REG(0x01, 0x09e)
> +#define WCD9335_SB_FLL_FREQ_CTL_3		WCD9335_REG(0x01, 0x09f)
> +#define WCD9335_SB_FLL_SSC_CTL_0		WCD9335_REG(0x01, 0x0a0)
> +#define WCD9335_SB_FLL_SSC_CTL_1		WCD9335_REG(0x01, 0x0a1)
> +#define WCD9335_SB_FLL_SSC_CTL_2		WCD9335_REG(0x01, 0x0a2)
> +#define WCD9335_SB_FLL_SSC_CTL_3		WCD9335_REG(0x01, 0x0a3)
> +#define WCD9335_SB_FLL_FLL_MODE			WCD9335_REG(0x01, 0x0a4)
> +#define WCD9335_SB_FLL_STATUS_0			WCD9335_REG(0x01, 0x0a5)
> +#define WCD9335_SB_FLL_STATUS_1			WCD9335_REG(0x01, 0x0a6)
> +#define WCD9335_SB_FLL_STATUS_2			WCD9335_REG(0x01, 0x0a7)
> +#define WCD9335_SB_FLL_STATUS_3			WCD9335_REG(0x01, 0x0a8)
> +
> +/* Page-2 Registers */
> +#define WCD9335_PAGE2_PAGE_REGISTER		WCD9335_REG(0x02, 0x000)
> +#define WCD9335_CPE_SS_DMIC0_CTL		WCD9335_REG(0x02, 0x063)
> +#define WCD9335_CPE_SS_DMIC1_CTL		WCD9335_REG(0x02, 0x064)
> +#define WCD9335_CPE_SS_DMIC2_CTL		WCD9335_REG(0x02, 0x065)
> +#define WCD9335_CPE_SS_DMIC_CFG			WCD9335_REG(0x02, 0x066)
> +#define WCD9335_SOC_MAD_AUDIO_CTL_2		WCD9335_REG(0x02, 0x084)
> +
> +/* Page-6 Registers */
> +#define WCD9335_PAGE6_PAGE_REGISTER		WCD9335_REG(0x06, 0x000)
> +#define WCD9335_ANA_BIAS			WCD9335_REG(0x06, 0x001)
> +#define WCD9335_ANA_BIAS_EN_MASK		BIT(7)
> +#define WCD9335_ANA_BIAS_ENABLE			BIT(7)
> +#define WCD9335_ANA_BIAS_DISABLE		0
> +#define WCD9335_ANA_BIAS_PRECHRG_EN_MASK	BIT(6)
> +#define WCD9335_ANA_BIAS_PRECHRG_ENABLE		BIT(6)
> +#define WCD9335_ANA_BIAS_PRECHRG_DISABLE	0
> +#define WCD9335_ANA_BIAS_PRECHRG_CTL_MODE	BIT(5)
> +#define WCD9335_ANA_BIAS_PRECHRG_CTL_MODE_AUTO	BIT(5)
> +#define WCD9335_ANA_BIAS_PRECHRG_CTL_MODE_MANUAL	0
> +#define WCD9335_ANA_CLK_TOP			WCD9335_REG(0x06, 0x002)
> +#define WCD9335_ANA_CLK_MCLK_EN_MASK		BIT(2)
> +#define WCD9335_ANA_CLK_MCLK_ENABLE		BIT(2)
> +#define WCD9335_ANA_CLK_MCLK_DISABLE		0
> +#define WCD9335_ANA_CLK_MCLK_SRC_MASK		BIT(3)
> +#define WCD9335_ANA_CLK_MCLK_SRC_RCO		BIT(3)
> +#define WCD9335_ANA_CLK_MCLK_SRC_EXTERNAL	0
> +#define WCD9335_ANA_CLK_EXT_CLKBUF_EN_MASK	BIT(7)
> +#define WCD9335_ANA_CLK_EXT_CLKBUF_ENABLE	BIT(7)
> +#define WCD9335_ANA_CLK_EXT_CLKBUF_DISABLE	0
> +#define WCD9335_ANA_RCO				WCD9335_REG(0x06, 0x003)
> +#define WCD9335_ANA_RCO_BG_EN_MASK		BIT(7)
> +#define WCD9335_ANA_RCO_BG_ENABLE		BIT(7)
> +#define WCD9335_ANA_BUCK_VOUT_D			WCD9335_REG(0x06, 0x005)
> +#define WCD9335_ANA_BUCK_VOUT_MASK		GENMASK(7, 0)
> +#define WCD9335_ANA_BUCK_CTL			WCD9335_REG(0x06, 0x006)
> +#define WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_MASK	BIT(1)
> +#define WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_EXT	BIT(1)
> +#define WCD9335_ANA_BUCK_CTL_VOUT_D_IREF_INT	0
> +#define WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_MASK	BIT(2)
> +#define WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_EXT	BIT(2)
> +#define WCD9335_ANA_BUCK_CTL_VOUT_D_VREF_INT	0
> +#define WCD9335_ANA_BUCK_CTL_RAMP_START_MASK	BIT(7)
> +#define WCD9335_ANA_BUCK_CTL_RAMP_START_ENABLE	BIT(7)
> +#define WCD9335_ANA_BUCK_CTL_RAMP_START_DISABLE	0
> +#define WCD9335_ANA_RX_SUPPLIES			WCD9335_REG(0x06, 0x008)
> +#define WCD9335_ANA_RX_BIAS_ENABLE_MASK		BIT(0)
> +#define WCD9335_ANA_RX_BIAS_ENABLE		BIT(0)
> +#define WCD9335_ANA_RX_BIAS_DISABLE		0
> +#define WCD9335_ANA_HPH				WCD9335_REG(0x06, 0x009)
> +#define WCD9335_ANA_EAR				WCD9335_REG(0x06, 0x00a)
> +#define WCD9335_ANA_LO_1_2			WCD9335_REG(0x06, 0x00b)
> +#define WCD9335_ANA_LO_3_4			WCD9335_REG(0x06, 0x00c)
> +#define WCD9335_ANA_AMIC1			WCD9335_REG(0x06, 0x00e)
> +#define WCD9335_ANA_AMIC2			WCD9335_REG(0x06, 0x00f)
> +#define WCD9335_ANA_AMIC3			WCD9335_REG(0x06, 0x010)
> +#define WCD9335_ANA_AMIC4			WCD9335_REG(0x06, 0x011)
> +#define WCD9335_ANA_AMIC5			WCD9335_REG(0x06, 0x012)
> +#define WCD9335_ANA_AMIC6			WCD9335_REG(0x06, 0x013)
> +#define WCD9335_ANA_MBHC_MECH			WCD9335_REG(0x06, 0x014)
> +#define WCD9335_MBHC_L_DET_EN_MASK		BIT(7)
> +#define WCD9335_MBHC_L_DET_EN			BIT(7)
> +#define WCD9335_MBHC_GND_DET_EN_MASK		BIT(6)
> +#define WCD9335_MBHC_MECH_DETECT_TYPE_MASK	BIT(5)
> +#define WCD9335_MBHC_MECH_DETECT_TYPE_SHIFT	5
> +#define WCD9335_MBHC_HPHL_PLUG_TYPE_MASK	BIT(4)
> +#define WCD9335_MBHC_HPHL_PLUG_TYPE_NO		BIT(4)
> +#define WCD9335_MBHC_GND_PLUG_TYPE_MASK		BIT(3)
> +#define WCD9335_MBHC_GND_PLUG_TYPE_NO		BIT(3)
> +#define WCD9335_MBHC_HSL_PULLUP_COMP_EN		BIT(2)
> +#define WCD9335_MBHC_HPHL_100K_TO_GND_EN	BIT(0)
> +
> +#define WCD9335_ANA_MBHC_ELECT			WCD9335_REG(0x06, 0x015)
> +#define WCD9335_ANA_MBHC_BD_ISRC_CTL_MASK	GENMASK(6, 4)
> +#define WCD9335_ANA_MBHC_BD_ISRC_100UA		GENMASK(5, 4)
> +#define WCD9335_ANA_MBHC_BD_ISRC_OFF		0
> +#define WCD9335_ANA_MBHC_BIAS_EN_MASK		BIT(0)
> +#define WCD9335_ANA_MBHC_BIAS_EN		BIT(0)
> +#define WCD9335_ANA_MBHC_ZDET			WCD9335_REG(0x06, 0x016)
> +#define WCD9335_ANA_MBHC_RESULT_1		WCD9335_REG(0x06, 0x017)
> +#define WCD9335_ANA_MBHC_RESULT_2		WCD9335_REG(0x06, 0x018)
> +#define WCD9335_ANA_MBHC_RESULT_3		WCD9335_REG(0x06, 0x019)
> +#define WCD9335_MBHC_BTN_RESULT_MASK		GENMASK(2, 0)
> +#define WCD9335_ANA_MBHC_BTN0			WCD9335_REG(0x06, 0x01a)
> +#define WCD9335_ANA_MBHC_BTN1			WCD9335_REG(0x06, 0x01b)
> +#define WCD9335_ANA_MBHC_BTN2			WCD9335_REG(0x06, 0x01c)
> +#define WCD9335_ANA_MBHC_BTN3			WCD9335_REG(0x06, 0x01d)
> +#define WCD9335_ANA_MBHC_BTN4			WCD9335_REG(0x06, 0x01e)
> +#define WCD9335_ANA_MBHC_BTN5			WCD9335_REG(0x06, 0x01f)
> +#define WCD9335_ANA_MBHC_BTN6			WCD9335_REG(0x06, 0x020)
> +#define WCD9335_ANA_MBHC_BTN7			WCD9335_REG(0x06, 0x021)
> +#define WCD9335_ANA_MICB1			WCD9335_REG(0x06, 0x022)
> +#define WCD9335_ANA_MICB2			WCD9335_REG(0x06, 0x023)
> +#define WCD9335_ANA_MICB2_ENABLE		BIT(6)
> +#define WCD9335_ANA_MICB2_RAMP			WCD9335_REG(0x06, 0x024)
> +#define WCD9335_ANA_MICB3			WCD9335_REG(0x06, 0x025)
> +#define WCD9335_ANA_MICB4			WCD9335_REG(0x06, 0x026)
> +#define WCD9335_ANA_VBADC			WCD9335_REG(0x06, 0x027)
> +#define WCD9335_BIAS_VBG_FINE_ADJ		WCD9335_REG(0x06, 0x029)
> +/*Precharge timecount 1P2Ms and 20Mv fine adjustment */
> +#define WCD9335_VBIAS_FINE_ADJ_DEF_VAL		0x65
> +#define WCD9335_RCO_CTRL_2			WCD9335_REG(0x06, 0x02f)
> +#define WCD9335_SIDO_SIDO_CCL_2			WCD9335_REG(0x06, 0x042)
> +#define WCD9335_SIDO_SIDO_CCL_4			WCD9335_REG(0x06, 0x044)
> +#define WCD9335_SIDO_SIDO_CCL_8			WCD9335_REG(0x06, 0x048)
> +#define WCD9335_VALLEY_COMP_PWC_C420FF		GENMASK(1, 0)
> +/* comparator pulse of C420FF, bias current of 1P0UA, max current of 360MA */
> +#define WCD9335_ANALOG_DEF_VALUE		0x6F
> +#define WCD9335_SIDO_SIDO_CCL_10		WCD9335_REG(0x06, 0x04a)
> +#define WCD9335_SIDO_SIDO_CCL_10_ICHARG_PWR_SEL_C320FF		0x2
> +/* Comparator 1 and 2 Bias current at 1P0UA with start pulse width of C320FF */
> +#define WCD9335_SIDO_SIDO_CCL_DEF_VALUE		0x6e
> +#define WCD9335_SIDO_SIDO_TEST_2		WCD9335_REG(0x06, 0x055)
> +#define WCD9335_MBHC_CTL_1			WCD9335_REG(0x06, 0x056)
> +#define WCD9335_MBHC_BTN_DBNC_MASK		GENMASK(1, 0)
> +#define WCD9335_MBHC_BTN_DBNC_T_16_MS		0x2
> +#define WCD9335_MBHC_CTL_RCO_EN_MASK		BIT(7)
> +#define WCD9335_MBHC_CTL_RCO_EN			BIT(7)
> +
> +#define WCD9335_MBHC_CTL_2			WCD9335_REG(0x06, 0x057)
> +#define WCD9335_MBHC_HS_VREF_CTL_MASK		GENMASK(1, 0)
> +#define WCD9335_MBHC_HS_VREF_1P5_V		0x1
> +#define WCD9335_MBHC_PLUG_DETECT_CTL		WCD9335_REG(0x06, 0x058)
> +#define WCD9335_MBHC_HSDET_PULLUP_CTL_MASK	GENMASK(7, 6)
> +#define WCD9335_MBHC_HSDET_PULLUP_CTL_SHIFT	6
> +#define WCD9335_MBHC_HSDET_PULLUP_CTL_1_2P0_UA	0x80
> +#define WCD9335_MBHC_DBNC_TIMER_INSREM_DBNC_T_96_MS	0x6
> +
> +#define WCD9335_MBHC_ZDET_RAMP_CTL		WCD9335_REG(0x06, 0x05a)
> +#define WCD9335_VBADC_IBIAS_FE			WCD9335_REG(0x06, 0x05e)
> +#define WCD9335_FLYBACK_CTRL_1			WCD9335_REG(0x06, 0x0b1)
> +#define WCD9335_RX_BIAS_HPH_PA			WCD9335_REG(0x06, 0x0bb)
> +#define WCD9335_RX_BIAS_HPH_PA_AMP_5_UA_MASK	GENMASK(3, 0)
> +#define WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2	WCD9335_REG(0x06, 0x0bc)
> +#define WCD9335_RX_BIAS_HPH_RDAC_LDO		WCD9335_REG(0x06, 0x0bd)
> +#define WCD9335_RX_BIAS_FLYB_BUFF		WCD9335_REG(0x06, 0x0c7)
> +#define WCD9335_RX_BIAS_FLYB_VPOS_5_UA_MASK	GENMASK(3, 0)
> +#define WCD9335_RX_BIAS_FLYB_I_0P0_UA		0
> +#define WCD9335_RX_BIAS_FLYB_VNEG_5_UA_MASK	GENMASK(7, 4)
> +#define WCD9335_RX_BIAS_FLYB_MID_RST		WCD9335_REG(0x06, 0x0c8)
> +#define WCD9335_HPH_CNP_WG_CTL			WCD9335_REG(0x06, 0x0cc)
> +#define WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_MASK	GENMASK(2, 0)
> +#define WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_500 0x2
> +#define WCD9335_HPH_CNP_WG_CTL_CURR_LDIV_RATIO_1000 0x3
> +#define WCD9335_HPH_OCP_CTL			WCD9335_REG(0x06, 0x0ce)
> +#define WCD9335_HPH_AUTO_CHOP			WCD9335_REG(0x06, 0x0cf)
> +#define WCD9335_HPH_AUTO_CHOP_MASK		BIT(5)
> +#define WCD9335_HPH_AUTO_CHOP_FORCE_ENABLE		BIT(5)
> +#define WCD9335_HPH_AUTO_CHOP_ENABLE_BY_CMPDR_GAIN		0
> +#define WCD9335_HPH_PA_CTL1			WCD9335_REG(0x06, 0x0d1)
> +#define WCD9335_HPH_PA_GM3_IB_SCALE_MASK		GENMASK(3, 1)
> +#define WCD9335_HPH_PA_CTL2			WCD9335_REG(0x06, 0x0d2)
> +#define WCD9335_HPH_PA_CTL2_FORCE_PSRREH_MASK	BIT(2)
> +#define WCD9335_HPH_PA_CTL2_FORCE_PSRREH_ENABLE	BIT(2)
> +#define WCD9335_HPH_PA_CTL2_FORCE_PSRREH_DISABLE 0
> +#define WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_MASK	BIT(3)
> +#define WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_ENABLE	BIT(3)
> +#define WCD9335_HPH_PA_CTL2_FORCE_IQCTRL_DISABLE	0
> +#define WCD9335_HPH_PA_CTL2_HPH_PSRR_ENH_MASK	BIT(5)
> +#define WCD9335_HPH_PA_CTL2_HPH_PSRR_ENABLE	BIT(5)
> +#define WCD9335_HPH_PA_CTL2_HPH_PSRR_DISABLE	0
> +#define WCD9335_HPH_L_EN			WCD9335_REG(0x06, 0x0d3)
> +#define WCD9335_HPH_CONST_SEL_L_MASK		GENMASK(7, 6)
> +#define WCD9335_HPH_CONST_SEL_L_BYPASS		0
> +#define WCD9335_HPH_CONST_SEL_L_LP_PATH		0x40
> +#define WCD9335_HPH_CONST_SEL_L_HQ_PATH		0x80
> +#define WCD9335_HPH_PA_GAIN_MASK		GENMASK(4, 0)
> +#define WCD9335_HPH_GAIN_SRC_SEL_MASK		BIT(5)
> +#define WCD9335_HPH_GAIN_SRC_SEL_COMPANDER	0
> +#define WCD9335_HPH_GAIN_SRC_SEL_REGISTER	BIT(5)
> +#define WCD9335_HPH_L_TEST			WCD9335_REG(0x06, 0x0d4)
> +#define WCD9335_HPH_R_EN			WCD9335_REG(0x06, 0x0d6)
> +#define WCD9335_HPH_R_TEST			WCD9335_REG(0x06, 0x0d7)
> +#define WCD9335_HPH_R_ATEST			WCD9335_REG(0x06, 0x0d8)
> +#define WCD9335_HPH_RDAC_LDO_CTL		WCD9335_REG(0x06, 0x0db)
> +#define WCD9335_HPH_RDAC_N1P65_LD_OUTCTL_MASK	GENMASK(2, 0)
> +#define WCD9335_HPH_RDAC_N1P65_LD_OUTCTL_V_N1P60	0x1
> +#define WCD9335_HPH_RDAC_1P65_LD_OUTCTL_MASK	GENMASK(6, 4)
> +#define WCD9335_HPH_RDAC_1P65_LD_OUTCTL_V_N1P60	0x10
> +#define WCD9335_HPH_REFBUFF_LP_CTL		WCD9335_REG(0x06, 0x0de)
> +#define WCD9335_HPH_L_DAC_CTL			WCD9335_REG(0x06, 0x0df)
> +#define WCD9335_HPH_DAC_LDO_POWERMODE_MASK	BIT(0)
> +#define WCD9335_HPH_DAC_LDO_POWERMODE_LOWPOWER	0
> +#define WCD9335_HPH_DAC_LDO_POWERMODE_UHQA	BIT(0)
> +#define WCD9335_HPH_DAC_LDO_UHQA_OV_MASK	BIT(1)
> +#define WCD9335_HPH_DAC_LDO_UHQA_OV_ENABLE	BIT(1)
> +#define WCD9335_HPH_DAC_LDO_UHQA_OV_DISABLE	0
> +
> +#define WCD9335_EAR_CMBUFF			WCD9335_REG(0x06, 0x0e2)
> +#define WCD9335_DIFF_LO_LO2_COMPANDER		WCD9335_REG(0x06, 0x0ea)
> +#define WCD9335_DIFF_LO_LO1_COMPANDER		WCD9335_REG(0x06, 0x0eb)
> +#define WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ	WCD9335_REG(0x06, 0x0f1)
> +#define WCD9335_DIFF_LO_COM_PA_FREQ		WCD9335_REG(0x06, 0x0f2)
> +#define WCD9335_SE_LO_LO3_GAIN			WCD9335_REG(0x06, 0x0f8)
> +#define WCD9335_SE_LO_LO3_CTRL			WCD9335_REG(0x06, 0x0f9)
> +#define WCD9335_SE_LO_LO4_GAIN			WCD9335_REG(0x06, 0x0fa)
> +
> +/* Page-10 Registers */
> +#define WCD9335_CDC_TX0_TX_PATH_CTL		WCD9335_REG(0x0a, 0x031)
> +#define WCD9335_CDC_TX_PATH_CTL_PCM_RATE_MASK	GENMASK(3, 0)
> +#define WCD9335_CDC_TX_PATH_CTL(dec)	WCD9335_REG(0xa, (0x31 + dec * 0x10))
> +#define WCD9335_CDC_TX0_TX_PATH_CFG0		WCD9335_REG(0x0a, 0x032)
> +#define WCD9335_CDC_TX_ADC_AMIC_DMIC_SEL_MASK	BIT(7)
> +#define WCD9335_CDC_TX_ADC_DMIC_SEL		BIT(7)
> +#define WCD9335_CDC_TX_ADC_AMIC_SEL		0
> +#define WCD9335_CDC_TX0_TX_VOL_CTL		WCD9335_REG(0x0a, 0x034)
> +#define WCD9335_CDC_TX0_TX_PATH_SEC2		WCD9335_REG(0x0a, 0x039)
> +#define WCD9335_CDC_TX0_TX_PATH_SEC7		WCD9335_REG(0x0a, 0x03e)
> +#define WCD9335_CDC_TX1_TX_PATH_CTL		WCD9335_REG(0x0a, 0x041)
> +#define WCD9335_CDC_TX1_TX_PATH_CFG0		WCD9335_REG(0x0a, 0x042)
> +#define WCD9335_CDC_TX2_TX_PATH_CTL		WCD9335_REG(0x0a, 0x051)
> +#define WCD9335_CDC_TX2_TX_PATH_CFG0		WCD9335_REG(0x0a, 0x052)
> +#define WCD9335_CDC_TX2_TX_VOL_CTL		WCD9335_REG(0x0a, 0x054)
> +#define WCD9335_CDC_TX3_TX_PATH_CTL		WCD9335_REG(0x0a, 0x061)
> +#define WCD9335_CDC_TX3_TX_PATH_CFG0		WCD9335_REG(0x0a, 0x062)
> +#define WCD9335_CDC_TX3_TX_VOL_CTL		WCD9335_REG(0x0a, 0x064)
> +#define WCD9335_CDC_TX4_TX_PATH_CTL		WCD9335_REG(0x0a, 0x071)
> +#define WCD9335_CDC_TX4_TX_PATH_CFG0		WCD9335_REG(0x0a, 0x072)
> +#define WCD9335_CDC_TX4_TX_VOL_CTL		WCD9335_REG(0x0a, 0x074)
> +#define WCD9335_CDC_TX5_TX_PATH_CTL		WCD9335_REG(0x0a, 0x081)
> +#define WCD9335_CDC_TX5_TX_PATH_CFG0		WCD9335_REG(0x0a, 0x082)
> +#define WCD9335_CDC_TX5_TX_VOL_CTL		WCD9335_REG(0x0a, 0x084)
> +#define WCD9335_CDC_TX6_TX_PATH_CTL		WCD9335_REG(0x0a, 0x091)
> +#define WCD9335_CDC_TX6_TX_PATH_CFG0		WCD9335_REG(0x0a, 0x092)
> +#define WCD9335_CDC_TX6_TX_VOL_CTL		WCD9335_REG(0x0a, 0x094)
> +#define WCD9335_CDC_TX7_TX_PATH_CTL		WCD9335_REG(0x0a, 0x0a1)
> +#define WCD9335_CDC_TX7_TX_PATH_CFG0		WCD9335_REG(0x0a, 0x0a2)
> +#define WCD9335_CDC_TX7_TX_VOL_CTL		WCD9335_REG(0x0a, 0x0a4)
> +#define WCD9335_CDC_TX8_TX_PATH_CTL		WCD9335_REG(0x0a, 0x0b1)
> +#define WCD9335_CDC_TX8_TX_PATH_CFG0		WCD9335_REG(0x0a, 0x0b2)
> +#define WCD9335_CDC_TX8_TX_VOL_CTL		WCD9335_REG(0x0a, 0x0b4)
> +#define WCD9335_CDC_TX9_SPKR_PROT_PATH_CFG0	WCD9335_REG(0x0a, 0x0c3)
> +#define WCD9335_CDC_TX10_SPKR_PROT_PATH_CFG0	WCD9335_REG(0x0a, 0x0c7)
> +#define WCD9335_CDC_TX11_SPKR_PROT_PATH_CFG0	WCD9335_REG(0x0a, 0x0cb)
> +#define WCD9335_CDC_TX12_SPKR_PROT_PATH_CFG0	WCD9335_REG(0x0a, 0x0cf)
> +
> +/* Page-11 Registers */
> +#define WCD9335_PAGE11_PAGE_REGISTER		WCD9335_REG(0x0b, 0x000)
> +#define WCD9335_CDC_COMPANDER1_CTL0		WCD9335_REG(0x0b, 0x001)
> +#define WCD9335_CDC_COMPANDER1_CTL(c)	WCD9335_REG(0x0b, (0x001 + c * 0x8))
> +#define WCD9335_CDC_COMPANDER_CLK_EN_MASK	BIT(0)
> +#define WCD9335_CDC_COMPANDER_CLK_ENABLE	BIT(0)
> +#define WCD9335_CDC_COMPANDER_CLK_DISABLE	0
> +#define WCD9335_CDC_COMPANDER_SOFT_RST_MASK	BIT(1)
> +#define WCD9335_CDC_COMPANDER_SOFT_RST_ENABLE	BIT(1)
> +#define WCD9335_CDC_COMPANDER_SOFT_RST_DISABLE	0
> +#define WCD9335_CDC_COMPANDER_HALT_MASK		BIT(2)
> +#define WCD9335_CDC_COMPANDER_HALT		BIT(2)
> +#define WCD9335_CDC_COMPANDER_NOHALT		0
> +#define WCD9335_CDC_COMPANDER7_CTL3		WCD9335_REG(0x0b, 0x034)
> +#define WCD9335_CDC_COMPANDER7_CTL7		WCD9335_REG(0x0b, 0x038)
> +#define WCD9335_CDC_COMPANDER8_CTL3		WCD9335_REG(0x0b, 0x03c)
> +#define WCD9335_CDC_COMPANDER8_CTL7		WCD9335_REG(0x0b, 0x040)
> +#define WCD9335_CDC_RX0_RX_PATH_CTL		WCD9335_REG(0x0b, 0x041)
> +#define WCD9335_CDC_RX_PGA_MUTE_EN_MASK		BIT(4)
> +#define WCD9335_CDC_RX_PGA_MUTE_ENABLE		BIT(4)
> +#define WCD9335_CDC_RX_PGA_MUTE_DISABLE		0
> +#define WCD9335_CDC_RX_CLK_EN_MASK		BIT(5)
> +#define WCD9335_CDC_RX_CLK_ENABLE		BIT(5)
> +#define WCD9335_CDC_RX_CLK_DISABLE		0
> +#define WCD9335_CDC_RX_RESET_MASK		BIT(6)
> +#define WCD9335_CDC_RX_RESET_ENABLE		BIT(6)
> +#define WCD9335_CDC_RX_RESET_DISABLE		0
> +#define WCD9335_CDC_RX_PATH_CTL(rx)	WCD9335_REG(0x0b, (0x041 + rx * 0x14))
> +#define WCD9335_CDC_RX0_RX_PATH_CFG0		WCD9335_REG(0x0b, 0x042)
> +#define WCD9335_CDC_RX0_RX_PATH_CFG1		WCD9335_REG(0x0b, 0x043)
> +#define WCD9335_CDC_RX0_RX_PATH_CFG2		WCD9335_REG(0x0b, 0x044)
> +#define WCD9335_CDC_RX0_RX_VOL_CTL		WCD9335_REG(0x0b, 0x045)
> +#define WCD9335_CDC_RX0_RX_PATH_MIX_CTL		WCD9335_REG(0x0b, 0x046)
> +#define WCD9335_CDC_MIX_PCM_RATE_MASK		GENMASK(3, 0)
> +#define WCD9335_CDC_RX_PATH_MIX_CTL(rx)	WCD9335_REG(0x0b, (0x46 + rx * 0x14))
> +#define WCD9335_CDC_RX0_RX_PATH_MIX_CFG		WCD9335_REG(0x0b, 0x047)
> +#define WCD9335_CDC_RX0_RX_VOL_MIX_CTL		WCD9335_REG(0x0b, 0x048)
> +#define WCD9335_CDC_RX0_RX_PATH_SEC0		WCD9335_REG(0x0b, 0x049)
> +#define WCD9335_CDC_RX0_RX_PATH_SEC7		WCD9335_REG(0x0b, 0x050)
> +#define WCD9335_CDC_RX0_RX_PATH_MIX_SEC0	WCD9335_REG(0x0b, 0x051)
> +#define WCD9335_CDC_RX1_RX_PATH_CTL		WCD9335_REG(0x0b, 0x055)
> +#define WCD9335_CDC_RX1_RX_PATH_CFG0		WCD9335_REG(0x0b, 0x056)
> +#define WCD9335_CDC_RX1_RX_PATH_CFG(c)	WCD9335_REG(0x0b, (0x056 + c * 0x14))
> +#define WCD9335_CDC_RX_PATH_CFG_CMP_EN_MASK	BIT(1)
> +#define WCD9335_CDC_RX_PATH_CFG_CMP_ENABLE	BIT(1)
> +#define WCD9335_CDC_RX_PATH_CFG_CMP_DISABLE	0
> +#define WCD9335_CDC_RX_PATH_CFG_HD2_EN_MASK	BIT(2)
> +#define WCD9335_CDC_RX_PATH_CFG_HD2_ENABLE	BIT(2)
> +#define WCD9335_CDC_RX_PATH_CFG_HD2_DISABLE	0
> +#define WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_EN_MASK	BIT(3)
> +#define WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_EN	BIT(3)
> +#define WCD9335_CDC_RX_PATH_CFG0_DLY_ZN_DISABLE	0
> +#define WCD9335_CDC_RX1_RX_PATH_CFG2		WCD9335_REG(0x0b, 0x058)
> +#define WCD9335_CDC_RX1_RX_VOL_CTL		WCD9335_REG(0x0b, 0x059)
> +#define WCD9335_CDC_RX1_RX_PATH_MIX_CTL		WCD9335_REG(0x0b, 0x05a)
> +#define WCD9335_CDC_RX1_RX_PATH_MIX_CFG		WCD9335_REG(0x0b, 0x05b)
> +#define WCD9335_CDC_RX1_RX_VOL_MIX_CTL		WCD9335_REG(0x0b, 0x05c)
> +#define WCD9335_CDC_RX1_RX_PATH_SEC0		WCD9335_REG(0x0b, 0x05d)
> +#define WCD9335_CDC_RX1_RX_PATH_SEC3		WCD9335_REG(0x0b, 0x060)
> +#define WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_MASK	GENMASK(1, 0)
> +#define WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_2	0x1
> +#define WCD9335_CDC_RX_PATH_SEC_HD2_SCALE_1	0
> +#define WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_MASK	GENMASK(5, 2)
> +#define WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_0P2500	0x10
> +#define WCD9335_CDC_RX_PATH_SEC_HD2_ALPHA_0P0000	0
> +#define WCD9335_CDC_RX2_RX_PATH_CTL		WCD9335_REG(0x0b, 0x069)
> +#define WCD9335_CDC_RX2_RX_PATH_CFG0		WCD9335_REG(0x0b, 0x06a)
> +#define WCD9335_CDC_RX2_RX_PATH_CFG2		WCD9335_REG(0x0b, 0x06c)
> +#define WCD9335_CDC_RX2_RX_VOL_CTL		WCD9335_REG(0x0b, 0x06d)
> +#define WCD9335_CDC_RX2_RX_PATH_MIX_CTL		WCD9335_REG(0x0b, 0x06e)
> +#define WCD9335_CDC_RX2_RX_PATH_MIX_CFG		WCD9335_REG(0x0b, 0x06f)
> +#define WCD9335_CDC_RX2_RX_VOL_MIX_CTL		WCD9335_REG(0x0b, 0x070)
> +#define WCD9335_CDC_RX2_RX_PATH_SEC0		WCD9335_REG(0x0b, 0x071)
> +#define WCD9335_CDC_RX_PATH_DEM_INP_SEL_MASK	GENMASK(1, 0)
> +#define WCD9335_CDC_RX2_RX_PATH_SEC3		WCD9335_REG(0x0b, 0x074)
> +#define WCD9335_CDC_RX3_RX_PATH_CTL		WCD9335_REG(0x0b, 0x07d)
> +#define WCD9335_CDC_RX3_RX_PATH_CFG0		WCD9335_REG(0x0b, 0x07e)
> +#define WCD9335_CDC_RX3_RX_PATH_CFG2		WCD9335_REG(0x0b, 0x080)
> +#define WCD9335_CDC_RX3_RX_VOL_CTL		WCD9335_REG(0x0b, 0x081)
> +#define WCD9335_CDC_RX3_RX_PATH_MIX_CTL		WCD9335_REG(0x0b, 0x082)
> +#define WCD9335_CDC_RX3_RX_PATH_MIX_CFG		WCD9335_REG(0x0b, 0x083)
> +#define WCD9335_CDC_RX3_RX_VOL_MIX_CTL		WCD9335_REG(0x0b, 0x084)
> +#define WCD9335_CDC_RX4_RX_PATH_CTL		WCD9335_REG(0x0b, 0x091)
> +#define WCD9335_CDC_RX4_RX_PATH_CFG0		WCD9335_REG(0x0b, 0x092)
> +#define WCD9335_CDC_RX4_RX_PATH_CFG2		WCD9335_REG(0x0b, 0x094)
> +#define WCD9335_CDC_RX4_RX_VOL_CTL		WCD9335_REG(0x0b, 0x095)
> +#define WCD9335_CDC_RX4_RX_PATH_MIX_CTL		WCD9335_REG(0x0b, 0x096)
> +#define WCD9335_CDC_RX4_RX_PATH_MIX_CFG		WCD9335_REG(0x0b, 0x097)
> +#define WCD9335_CDC_RX4_RX_VOL_MIX_CTL		WCD9335_REG(0x0b, 0x098)
> +#define WCD9335_CDC_RX5_RX_PATH_CTL		WCD9335_REG(0x0b, 0x0a5)
> +#define WCD9335_CDC_RX5_RX_PATH_CFG0		WCD9335_REG(0x0b, 0x0a6)
> +#define WCD9335_CDC_RX5_RX_PATH_CFG2		WCD9335_REG(0x0b, 0x0a8)
> +#define WCD9335_CDC_RX5_RX_VOL_CTL		WCD9335_REG(0x0b, 0x0a9)
> +#define WCD9335_CDC_RX5_RX_PATH_MIX_CTL		WCD9335_REG(0x0b, 0x0aa)
> +#define WCD9335_CDC_RX5_RX_PATH_MIX_CFG		WCD9335_REG(0x0b, 0x0ab)
> +#define WCD9335_CDC_RX5_RX_VOL_MIX_CTL		WCD9335_REG(0x0b, 0x0ac)
> +#define WCD9335_CDC_RX6_RX_PATH_CTL		WCD9335_REG(0x0b, 0x0b9)
> +#define WCD9335_CDC_RX6_RX_PATH_CFG0		WCD9335_REG(0x0b, 0x0ba)
> +#define WCD9335_CDC_RX6_RX_PATH_CFG2		WCD9335_REG(0x0b, 0x0bc)
> +#define WCD9335_CDC_RX6_RX_VOL_CTL		WCD9335_REG(0x0b, 0x0bd)
> +#define WCD9335_CDC_RX6_RX_PATH_MIX_CTL		WCD9335_REG(0x0b, 0x0be)
> +#define WCD9335_CDC_RX6_RX_PATH_MIX_CFG		WCD9335_REG(0x0b, 0x0bf)
> +#define WCD9335_CDC_RX6_RX_VOL_MIX_CTL		WCD9335_REG(0x0b, 0x0c0)
> +#define WCD9335_CDC_RX7_RX_PATH_CTL		WCD9335_REG(0x0b, 0x0cd)
> +#define WCD9335_CDC_RX7_RX_PATH_CFG0		WCD9335_REG(0x0b, 0x0ce)
> +#define WCD9335_CDC_RX7_RX_PATH_CFG1		WCD9335_REG(0x0b, 0x0cf)
> +#define WCD9335_CDC_RX7_RX_PATH_CFG2		WCD9335_REG(0x0b, 0x0d0)
> +#define WCD9335_CDC_RX7_RX_VOL_CTL		WCD9335_REG(0x0b, 0x0d1)
> +#define WCD9335_CDC_RX7_RX_PATH_MIX_CTL		WCD9335_REG(0x0b, 0x0d2)
> +#define WCD9335_CDC_RX7_RX_PATH_MIX_CFG		WCD9335_REG(0x0b, 0x0d3)
> +#define WCD9335_CDC_RX7_RX_VOL_MIX_CTL		WCD9335_REG(0x0b, 0x0d4)
> +#define WCD9335_CDC_RX8_RX_PATH_CTL		WCD9335_REG(0x0b, 0x0e1)
> +#define WCD9335_CDC_RX8_RX_PATH_CFG0		WCD9335_REG(0x0b, 0x0e2)
> +#define WCD9335_CDC_RX8_RX_PATH_CFG1		WCD9335_REG(0x0b, 0x0e3)
> +#define WCD9335_CDC_RX8_RX_PATH_CFG2		WCD9335_REG(0x0b, 0x0e4)
> +#define WCD9335_CDC_RX8_RX_VOL_CTL		WCD9335_REG(0x0b, 0x0e5)
> +#define WCD9335_CDC_RX8_RX_PATH_MIX_CTL		WCD9335_REG(0x0b, 0x0e6)
> +#define WCD9335_CDC_RX8_RX_PATH_MIX_CFG		WCD9335_REG(0x0b, 0x0e7)
> +#define WCD9335_CDC_RX8_RX_VOL_MIX_CTL		WCD9335_REG(0x0b, 0x0e8)
> +
> +/* Page-12 Registers */
> +#define WCD9335_PAGE12_PAGE_REGISTER		WCD9335_REG(0x0c, 0x000)
> +#define WCD9335_CDC_CLSH_K2_MSB			WCD9335_REG(0x0c, 0x00a)
> +#define WCD9335_CDC_CLSH_K2_LSB			WCD9335_REG(0x0c, 0x00b)
> +#define WCD9335_CDC_BOOST0_BOOST_CTL		WCD9335_REG(0x0c, 0x01a)
> +#define WCD9335_CDC_BOOST0_BOOST_CFG1		WCD9335_REG(0x0c, 0x01b)
> +#define WCD9335_CDC_BOOST0_BOOST_CFG2		WCD9335_REG(0x0c, 0x01c)
> +#define WCD9335_CDC_BOOST1_BOOST_CTL		WCD9335_REG(0x0c, 0x022)
> +#define WCD9335_CDC_BOOST1_BOOST_CFG1		WCD9335_REG(0x0c, 0x023)
> +#define WCD9335_CDC_BOOST1_BOOST_CFG2		WCD9335_REG(0x0c, 0x024)
> +
> +/* Page-13 Registers */
> +#define WCD9335_PAGE13_PAGE_REGISTER		WCD9335_REG(0x0d, 0x000)
> +#define WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0	WCD9335_REG(0x0d, 0x001)
> +#define WCD9335_CDC_RX_INP_MUX_RX_INT_CFG0(i) WCD9335_REG(0xd, (0x1 + i * 0x2))
> +#define WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1	WCD9335_REG(0xd, 0x002)
> +#define WCD9335_CDC_RX_INP_MUX_RX_INT_SEL_MASK	GENMASK(3, 0)
> +#define WCD9335_CDC_RX_INP_MUX_RX_INT_CFG1(i) WCD9335_REG(0xd, (0x2 + i * 0x2))
> +
> +#define WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0	WCD9335_REG(0x0d, 0x003)
> +#define WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1	WCD9335_REG(0x0d, 0x004)
> +#define WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0	WCD9335_REG(0x0d, 0x005)
> +#define WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1	WCD9335_REG(0x0d, 0x006)
> +#define WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0	WCD9335_REG(0x0d, 0x007)
> +#define WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1	WCD9335_REG(0x0d, 0x008)
> +#define WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0	WCD9335_REG(0x0d, 0x009)
> +#define WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1	WCD9335_REG(0x0d, 0x00a)
> +#define WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0	WCD9335_REG(0x0d, 0x00b)
> +#define WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1	WCD9335_REG(0x0d, 0x00c)
> +#define WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0	WCD9335_REG(0x0d, 0x00d)
> +#define WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1	WCD9335_REG(0x0d, 0x00e)
> +#define WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0	WCD9335_REG(0x0d, 0x00f)
> +#define WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1	WCD9335_REG(0x0d, 0x010)
> +#define WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0	WCD9335_REG(0x0d, 0x011)
> +#define WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1	WCD9335_REG(0x0d, 0x012)
> +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0	WCD9335_REG(0x0d, 0x01d)
> +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1	WCD9335_REG(0x0d, 0x01e)
> +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0	WCD9335_REG(0x0d, 0x01f)
> +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1	WCD9335_REG(0x0d, 0x020)
> +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0	WCD9335_REG(0x0d, 0x021)
> +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1	WCD9335_REG(0x0d, 0x022)
> +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0	WCD9335_REG(0x0d, 0x023)
> +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1	WCD9335_REG(0x0d, 0x024)
> +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0	WCD9335_REG(0x0d, 0x025)
> +#define WCD9335_CDC_TX_INP_MUX_SEL_AMIC	0x1
> +#define WCD9335_CDC_TX_INP_MUX_SEL_DMIC	0
> +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0	WCD9335_REG(0x0d, 0x026)
> +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0	WCD9335_REG(0x0d, 0x027)
> +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0	WCD9335_REG(0x0d, 0x028)
> +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0	WCD9335_REG(0x0d, 0x029)
> +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX10_CFG0	WCD9335_REG(0x0d, 0x02b)
> +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX11_CFG0	WCD9335_REG(0x0d, 0x02c)
> +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX12_CFG0	WCD9335_REG(0x0d, 0x02d)
> +#define WCD9335_CDC_TX_INP_MUX_ADC_MUX13_CFG0	WCD9335_REG(0x0d, 0x02e)
> +#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0	WCD9335_REG(0x0d, 0x03a)
> +#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1	WCD9335_REG(0x0d, 0x03b)
> +#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2	WCD9335_REG(0x0d, 0x03c)
> +#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3	WCD9335_REG(0x0d, 0x03d)
> +#define WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL	WCD9335_REG(0x0d, 0x041)
> +#define WCD9335_CDC_CLK_RST_CTRL_MCLK_EN_MASK	BIT(0)
> +#define WCD9335_CDC_CLK_RST_CTRL_MCLK_ENABLE	BIT(0)
> +#define WCD9335_CDC_CLK_RST_CTRL_MCLK_DISABLE	0
> +#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL	WCD9335_REG(0x0d, 0x042)
> +#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_EN_MASK	BIT(0)
> +#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_ENABLE	BIT(0)
> +#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_DISABLE	0
> +#define WCD9335_CDC_TOP_TOP_CFG1	WCD9335_REG(0x0d, 0x082)
> +#define WCD9335_MAX_REGISTER	WCD9335_REG(0x80, 0x0FF)
> +
> +/* SLIMBUS Slave Registers */
> +#define WCD9335_SLIM_PGD_PORT_INT_EN0	WCD9335_REG(0, 0x30)
> +#define WCD9335_SLIM_PGD_PORT_INT_STATUS_RX_0	WCD9335_REG(0, 0x34)
> +#define WCD9335_SLIM_PGD_PORT_INT_STATUS_RX_1	WCD9335_REG(0, 0x35)
> +#define WCD9335_SLIM_PGD_PORT_INT_STATUS_TX_0	WCD9335_REG(0, 0x36)
> +#define WCD9335_SLIM_PGD_PORT_INT_STATUS_TX_1	WCD9335_REG(0, 0x37)
> +#define WCD9335_SLIM_PGD_PORT_INT_CLR_RX_0	WCD9335_REG(0, 0x38)
> +#define WCD9335_SLIM_PGD_PORT_INT_CLR_RX_1	WCD9335_REG(0, 0x39)
> +#define WCD9335_SLIM_PGD_PORT_INT_CLR_TX_0	WCD9335_REG(0, 0x3A)
> +#define WCD9335_SLIM_PGD_PORT_INT_CLR_TX_1	WCD9335_REG(0, 0x3B)
> +#define WCD9335_SLIM_PGD_PORT_INT_RX_SOURCE0	WCD9335_REG(0, 0x60)
> +#define WCD9335_SLIM_PGD_PORT_INT_TX_SOURCE0	WCD9335_REG(0, 0x70)
> +#define WCD9335_SLIM_PGD_RX_PORT_CFG(p)	WCD9335_REG(0, (0x30 + p))
> +#define WCD9335_SLIM_PGD_PORT_CFG(p)	WCD9335_REG(0, (0x40 + p))
> +#define WCD9335_SLIM_PGD_TX_PORT_CFG(p)	WCD9335_REG(0, (0x50 + p))
> +#define WCD9335_SLIM_PGD_PORT_INT_SRC(p)	WCD9335_REG(0, (0x60 + p))
> +#define WCD9335_SLIM_PGD_PORT_INT_STATUS(p)	WCD9335_REG(0, (0x80 + p))
> +#define WCD9335_SLIM_PGD_TX_PORT_MULTI_CHNL_0(p) WCD9335_REG(0, (0x100 + 4 * p))
> +/* ports range from 10-16 */
> +#define WCD9335_SLIM_PGD_TX_PORT_MULTI_CHNL_1(p) WCD9335_REG(0, (0x101 + 4 * p))
> +#define WCD9335_SLIM_PGD_RX_PORT_MULTI_CHNL_0(p) WCD9335_REG(0, (0x140 + 4 * p))
> +
> +#endif
> diff --git a/include/linux/mfd/wcd9335/wcd9335.h b/include/linux/mfd/wcd9335/wcd9335.h
> new file mode 100644
> index 0000000..f5ccacf
> --- /dev/null
> +++ b/include/linux/mfd/wcd9335/wcd9335.h
> @@ -0,0 +1,45 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (c) 2018, Linaro Limited */
> +
> +#ifndef __WCD9335_H__
> +#define __WCD9335_H__
> +
> +#include <linux/slimbus.h>
> +#include <linux/regulator/consumer.h>
> +
> +#define WCD9335_VERSION_2_0     2
> +#define WCD9335_MAX_SUPPLY	5
> +
> +enum wcd_interface_type {
> +	WCD9335_INTERFACE_TYPE_SLIMBUS = 1,
> +	WCD9335_INTERFACE_TYPE_I2C,
> +};
> +
> +/**
> + * struct wcd9335 - wcd9335 device handle.
> + * @version: Version of codec chip
> + * @reset_gpio: rest gpio

"Reset GPIO"

> + * @intf_type: Interface type, which can be SLIMBUS or I2C
> + * @dev: wcd9335 evice instance

Did you spell-check this?

> + * @mclk: MCLK clock handle.

Full stop or no full stop, choose one.

> + * @slim: wcd9335 slim device handle.

WCD9335

> + * @slim_interface_dev: wcd9335 slim interface device handle

What's the difference between slim and slim_interface_dev?

Why do you need 2 struct slim_device *'s?

> + * @regmap: wcd9335 slim device regmap
> + * @interface_dev_regmap: wcd9335 interface device regmap.
> + * @supplies: voltage supplies required for wcd9335
> + */
> +struct wcd9335 {
> +	int version;
> +	int reset_gpio;
> +	enum wcd_interface_type intf_type;
> +	struct device *dev;
> +	struct clk *mclk;
> +	struct clk *native_clk;
> +	struct slim_device *slim;
> +	struct slim_device *slim_interface_dev;
> +	struct regmap *regmap;
> +	struct regmap *interface_dev_regmap;
> +	struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY];
> +};
> +
> +#endif /* __WCD9335_H__ */

-- 
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH v4 02/14] mfd: wcd9335: add support to wcd9335 core
  2018-10-24  7:07   ` Lee Jones
@ 2018-10-24 10:50     ` Srinivas Kandagatla
  0 siblings, 0 replies; 22+ messages in thread
From: Srinivas Kandagatla @ 2018-10-24 10:50 UTC (permalink / raw)
  To: Lee Jones
  Cc: robh+dt, broonie, mark.rutland, lgirdwood, bgoswami, devicetree,
	linux-kernel, vkoul, alsa-devel



On 24/10/18 08:07, Lee Jones wrote:
>> +#define WCD9335_SLIM_INTERFACE_DEVICE_INDEX	0
>> +
>> +static const struct mfd_cell wcd9335_devices[] = {
>> +	{ .name = "wcd9335-codec", },
>> +};
> Any news on other devices?
> 
We are totally limited with hardware to test other devices on this 
codec. Given the fact that no one is actively working on adding support 
to other devices ATM.
Also IRC discussions with you suggested that I should move this driver 
to codecs for now and when a new device support comes up we can move it 
back to mfd.

Regarding other comments, I will make sure that address them if the code 
is still there after moving to codecs.

thanks,
srini

>> +static const struct regmap_range_cfg wcd9335_ranges[] = {
>> +	{
>> +		.name = "WCD9335",
>> +		.range_min =  0x0,
>> +		.range_max =  WCD9335_MAX_REGISTER,
>> +		.selector_reg = WCD9335_REG(0x0, 0),
>> +		.selector_mask = 0xff,
>> +		.selector_shift = 0,
>> +		.window_start = 0x0,
>> +		.window_len = 0x1000,
>> +	},
>> +};

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2018-10-24 10:50 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-17  0:57 [PATCH v4 00/14] ASoC: Add support to WCD9335 Audio Codec srinivas.kandagatla
2018-09-17  0:57 ` [PATCH v4 01/14] ASoC: dt-bindings: update wcd9335 bindings srinivas.kandagatla
2018-09-17  0:57 ` [PATCH v4 02/14] mfd: wcd9335: add support to wcd9335 core srinivas.kandagatla
2018-10-24  7:07   ` Lee Jones
2018-10-24 10:50     ` Srinivas Kandagatla
2018-09-17  0:57 ` [PATCH v4 03/14] mfd: wcd9335: add wcd irq support srinivas.kandagatla
2018-09-17  0:57 ` [PATCH v4 04/14] ASoC: wcd9335: add support to wcd9335 codec srinivas.kandagatla
2018-09-17  0:57 ` [PATCH v4 05/14] ASoC: wcd9335: add CLASS-H Controller support srinivas.kandagatla
2018-09-17  0:57 ` [PATCH v4 06/14] ASoC: wcd9335: add basic controls srinivas.kandagatla
2018-09-17  0:57 ` [PATCH v4 07/14] ASoC: wcd9335: add playback dapm widgets srinivas.kandagatla
2018-09-17  0:57 ` [PATCH v4 08/14] ASoC: wcd9335: add capture " srinivas.kandagatla
2018-09-17  0:57 ` [PATCH v4 09/14] ASoC: wcd9335: add audio routings srinivas.kandagatla
2018-09-17  0:57 ` [PATCH v4 10/14] ASoC: dt-bindings: Add WCD9335 MBHC specific properties srinivas.kandagatla
2018-09-26  9:27   ` Banajit Goswami
2018-09-17  0:57 ` [PATCH v4 11/14] ASoC: wcd9335: add mbhc support srinivas.kandagatla
2018-09-26  9:31   ` Banajit Goswami
2018-09-26 10:56     ` Srinivas Kandagatla
2018-09-17  0:57 ` [PATCH v4 12/14] ASoC: apq8096: add slim support srinivas.kandagatla
2018-09-17  0:57 ` [PATCH v4 13/14] ASoC: apq8096: add headset JACK support srinivas.kandagatla
2018-09-17  0:57 ` [PATCH v4 14/14] ASoC: qcom: common: move be_hw_fixup to common srinivas.kandagatla
2018-09-19  5:49   ` [alsa-devel] " Rohit Kumar
2018-09-26 10:56     ` Srinivas Kandagatla

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).