diff mbox series

[2/6] ASoC: wcd934x: add support to wcd9340/wcd9341 codec

Message ID 20190702080920.22623-3-srinivas.kandagatla@linaro.org
State New
Headers show
Series ASoC: Add support to WCD9340/WCD9341 codec | expand

Commit Message

Srinivas Kandagatla July 2, 2019, 8:09 a.m. UTC
Qualcomm WCD9340/WCD9341 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 Five DACs and seven dedicated interpolators,
Seven (six audio ADCs, and one VBAT ADC), Multibutton headset
control (MBHC), Active noise cancellation, Sidetone paths,
MAD (mic activity detection) and codec processing engine.
It supports Class-H differential earpiece out and stereo single
ended headphones out.
This codec also has integrated SoundWire controller.

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

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

---
 sound/soc/codecs/Kconfig   |   10 +
 sound/soc/codecs/Makefile  |    2 +
 sound/soc/codecs/wcd934x.c | 2068 ++++++++++++++++++++++++++++++++++++
 sound/soc/codecs/wcd934x.h |  426 ++++++++
 4 files changed, 2506 insertions(+)
 create mode 100644 sound/soc/codecs/wcd934x.c
 create mode 100644 sound/soc/codecs/wcd934x.h

-- 
2.21.0

Comments

Mark Brown July 2, 2019, 2:44 p.m. UTC | #1
On Tue, Jul 02, 2019 at 09:09:16AM +0100, Srinivas Kandagatla wrote:

> +#define WCD_VERSION_WCD9341_1_1     5

> +#define WCD_IS_1_0(wcd) \

> +	((wcd->type == WCD934X) ? \

> +	 ((wcd->version == WCD_VERSION_1_0 || \

> +	   wcd->version == WCD_VERSION_WCD9340_1_0 || \

> +	   wcd->version == WCD_VERSION_WCD9341_1_0) ? 1 : 0) : 0)


Eew.  If you really need these make them functions and write
normal code with switch statements rather than abusing the
ternery operator like this, it's really not terribly readable.

> +static void wcd934x_update_reg_defaults(struct wcd934x_codec *wcd)

> +{

> +	struct regmap *rm = wcd->regmap;

> +

> +	regmap_update_bits(rm, WCD934X_BIAS_VBG_FINE_ADJ, 0xFF, 0x75);

> +	regmap_update_bits(rm, WCD934X_CODEC_CPR_SVS_CX_VDD, 0xFF, 0x7C);


What's all this stuff doing?  Should you be uing a regmap patch?

> +static int wcd934x_disable_master_bias(struct wcd934x_codec *data)

> +{

> +	if (data->master_bias_users <= 0)

> +		return 0;

> +

> +	data->master_bias_users--;


There's an awful lot of these refcounted things - are you sure
none of them could be supply widgets?

> +static void wcd934x_get_version(struct wcd934x_codec *wcd)

> +{

> +	int val1, val2, version, ret;

> +	struct regmap *regmap;

> +	u16 id_minor;

> +	u32 version_mask = 0;

> +

> +	regmap = wcd->regmap;

> +	version = 0;

> +

> +	ret = regmap_bulk_read(regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0,

> +			       (u8 *)&id_minor, sizeof(u16));

> +

> +	if (ret)

> +		return;


No error reporting at all?

> +	regmap_read(regmap, WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT14, &val1);

> +	regmap_read(regmap, WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT15, &val2);

> +

> +	dev_info(wcd->dev, "%s: chip version :0x%x 0x:%x\n",

> +		 __func__, val1, val2);


We don't report id_minor as part of the version?  Also the format
string there just seems mangled and not even internally
consistent.

> +	version_mask |= (!!((u8)val1 & 0x80)) << DSD_DISABLED_MASK;

> +	version_mask |= (!!((u8)val2 & 0x01)) << SLNQ_DISABLED_MASK;

> +

> +	switch (version_mask) {

> +	case DSD_DISABLED | SLNQ_DISABLED:

> +		if (id_minor == 0)

> +			version = WCD_VERSION_WCD9340_1_0;

> +		else if (id_minor == 0x01)

> +			version = WCD_VERSION_WCD9340_1_1;


This looks like you're trying to write a switch statement on the
minor version...

> +static void wcd934x_update_cpr_defaults(struct wcd934x_codec *data)

> +{

> +	int i;

> +

> +	__wcd934x_cdc_mclk_enable(data, true);

> +

> +	wcd934x_set_sido_input_src(data, SIDO_SOURCE_RCO_BG);

> +	regmap_write(data->regmap, WCD934X_CODEC_CPR_SVS2_MIN_CX_VDD, 0x2C);

> +	regmap_update_bits(data->regmap, WCD934X_CODEC_RPM_CLK_GATE,

> +			   0x10, 0x00);

> +

> +	for (i = 0; i < ARRAY_SIZE(cpr_defaults); i++) {

> +		regmap_bulk_write(data->regmap,

> +				  WCD934X_CODEC_CPR_WR_DATA_0,

> +				(u8 *)&cpr_defaults[i].wr_data, 4);

> +		regmap_bulk_write(data->regmap,

> +				  WCD934X_CODEC_CPR_WR_ADDR_0,

> +				(u8 *)&cpr_defaults[i].wr_addr, 4);


What is "cpr" and should you be using a regmap patch here?  Why
is this not with the other default updates?  You've got loads of
random undocumented sequences like this all through the driver,
are they patches or are they things that should be controllable
by the user?

> +		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;

> +		}


This looks like a switch statement, and it's not clear if there's
missing error handling.

> +static int wcd934x_get_micbias_val(struct device *dev, const char *micbias)

> +{

> +	int mv;

> +

> +	if (of_property_read_u32(dev->of_node, micbias, &mv))

> +		mv = WCD934X_DEF_MICBIAS_MV;

> +

> +	if (mv < 1000 || mv > 2850)

> +		mv = WCD934X_DEF_MICBIAS_MV;


This silently ignores errors, that's not good - people might
think they successfully configured their DT when they haven't.

> +	for_each_set_bit(j, &status, 32) {

> +		tx = (j >= 16 ? true : false);

> +		port_id = (tx ? j - 16 : j);


Please write normal conditional statements to improve legibility.

> +			/*

> +			 * Ignore interrupts for ports for which the

> +			 * interrupts are not specifically enabled.

> +			 */

> +			if (!(int_val & (1 << (port_id % 8))))

> +				continue;


Is this expected to happen?

> +	return of_platform_populate(wcd->dev->of_node, NULL, NULL, wcd->dev);


Why are we doing this?

> +{

> +	struct device *dev = wcd->dev;

> +	struct device_node *np = dev->of_node;

> +	int ret;

> +	/*

> +	 * INTR1 consists of all possible interrupt sources Ear OCP,


Missing blank line.

> +	 * HPH OCP, MBHC, MAD, VBAT, and SVA

> +	 * INTR2 is a subset of first interrupt sources MAD, VBAT, and SVA

> +	 */

> +	wcd->irq = of_irq_get_byname(wcd->dev->of_node, "intr1");

> +	if (wcd->irq < 0) {

> +		if (wcd->irq != -EPROBE_DEFER)

> +			dev_err(wcd->dev, "Unable to configure IRQ\n");


It's helpful to print what the error code was, it can help people
debug things.

> +	wcd->reset_gpio = of_get_named_gpio(np,	"reset-gpios", 0);

> +	if (wcd->reset_gpio < 0) {

> +		dev_err(dev, "Reset gpio missing in DT\n");

> +		return wcd->reset_gpio;

> +	}


devm_gpiod_get()

> +static int wcd934x_bring_up(struct wcd934x_codec *wcd)

> +{

> +	struct regmap *wcd_regmap = wcd->regmap;

> +	u16 id_minor, id_major;

> +	int ret;


> +	dev_info(wcd->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n",

> +		 __func__, id_major, id_minor);

> +


What was with the other verison parsing and printing code?
Srinivas Kandagatla July 2, 2019, 4:37 p.m. UTC | #2
Thanks Mark for taking time to review this patch.

On 02/07/2019 15:44, Mark Brown wrote:
> On Tue, Jul 02, 2019 at 09:09:16AM +0100, Srinivas Kandagatla wrote:

> 

>> +#define WCD_VERSION_WCD9341_1_1     5

>> +#define WCD_IS_1_0(wcd) \

>> +	((wcd->type == WCD934X) ? \

>> +	 ((wcd->version == WCD_VERSION_1_0 || \

>> +	   wcd->version == WCD_VERSION_WCD9340_1_0 || \

>> +	   wcd->version == WCD_VERSION_WCD9341_1_0) ? 1 : 0) : 0)

> 

> Eew.  If you really need these make them functions and write

> normal code with switch statements rather than abusing the

> ternery operator like this, it's really not terribly readable.

> 

I agree, will fix this and such use of ternary operators in the code.

>> +static void wcd934x_update_reg_defaults(struct wcd934x_codec *wcd)

>> +{

>> +	struct regmap *rm = wcd->regmap;

>> +

>> +	regmap_update_bits(rm, WCD934X_BIAS_VBG_FINE_ADJ, 0xFF, 0x75);

>> +	regmap_update_bits(rm, WCD934X_CODEC_CPR_SVS_CX_VDD, 0xFF, 0x7C);

> 

> What's all this stuff doing?  Should you be uing a regmap patch?

> 

I will try that in next version.
>> +static int wcd934x_disable_master_bias(struct wcd934x_codec *data)

>> +{

>> +	if (data->master_bias_users <= 0)

>> +		return 0;

>> +

>> +	data->master_bias_users--;

> 

> There's an awful lot of these refcounted things - are you sure

> none of them could be supply widgets?

I did not like it either, will remove them as this might be redundant. 
"MCLK" is already a supply widget.
> 

>> +static void wcd934x_get_version(struct wcd934x_codec *wcd)

>> +{

>> +	int val1, val2, version, ret;

>> +	struct regmap *regmap;

>> +	u16 id_minor;

>> +	u32 version_mask = 0;

>> +

>> +	regmap = wcd->regmap;

>> +	version = 0;

>> +

>> +	ret = regmap_bulk_read(regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0,

>> +			       (u8 *)&id_minor, sizeof(u16));

>> +

>> +	if (ret)

>> +		return;

> 

> No error reporting at all?

I agree, will fix this in next version.
> 

>> +	regmap_read(regmap, WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT14, &val1);

>> +	regmap_read(regmap, WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT15, &val2);

>> +

>> +	dev_info(wcd->dev, "%s: chip version :0x%x 0x:%x\n",

>> +		 __func__, val1, val2);

> 

> We don't report id_minor as part of the version?  Also the format

> string there just seems mangled and not even internally

> consistent.


> 

>> +	version_mask |= (!!((u8)val1 & 0x80)) << DSD_DISABLED_MASK;

>> +	version_mask |= (!!((u8)val2 & 0x01)) << SLNQ_DISABLED_MASK;

>> +

>> +	switch (version_mask) {

>> +	case DSD_DISABLED | SLNQ_DISABLED:

>> +		if (id_minor == 0)

>> +			version = WCD_VERSION_WCD9340_1_0;

>> +		else if (id_minor == 0x01)

>> +			version = WCD_VERSION_WCD9340_1_1;

> 

> This looks like you're trying to write a switch statement on the

> minor version...

> 

Will move to switch and any such occurrences.

>> +static void wcd934x_update_cpr_defaults(struct wcd934x_codec *data)

>> +{

>> +	int i;

>> +

>> +	__wcd934x_cdc_mclk_enable(data, true);

>> +

>> +	wcd934x_set_sido_input_src(data, SIDO_SOURCE_RCO_BG);

>> +	regmap_write(data->regmap, WCD934X_CODEC_CPR_SVS2_MIN_CX_VDD, 0x2C);

>> +	regmap_update_bits(data->regmap, WCD934X_CODEC_RPM_CLK_GATE,

>> +			   0x10, 0x00);

>> +

>> +	for (i = 0; i < ARRAY_SIZE(cpr_defaults); i++) {

>> +		regmap_bulk_write(data->regmap,

>> +				  WCD934X_CODEC_CPR_WR_DATA_0,

>> +				(u8 *)&cpr_defaults[i].wr_data, 4);

>> +		regmap_bulk_write(data->regmap,

>> +				  WCD934X_CODEC_CPR_WR_ADDR_0,

>> +				(u8 *)&cpr_defaults[i].wr_addr, 4);

> 

> What is "cpr" and should you be using a regmap patch here?  Why

> is this not with the other default updates?  You've got loads of

> random undocumented sequences like this all through the driver,

> are they patches or are they things that should be controllable

> by the user?

It makes sense to have a single default map here, I will do the in next 
version. And regarding user controllable, I will go thru the list once 
again in detail and remove user controllable registers.
> 

> 

>> +static int wcd934x_get_micbias_val(struct device *dev, const char *micbias)

>> +{

>> +	int mv;

>> +

>> +	if (of_property_read_u32(dev->of_node, micbias, &mv))

>> +		mv = WCD934X_DEF_MICBIAS_MV;

>> +

>> +	if (mv < 1000 || mv > 2850)

>> +		mv = WCD934X_DEF_MICBIAS_MV;


> 

>> +	return of_platform_populate(wcd->dev->of_node, NULL, NULL, wcd->dev);

> 

> Why are we doing this?


I will not be using MFD in this instance as most of the resources like 
interrupts, pins, clks, SoundWire are modeled as proper drivers with 
their respective subsystems.

This gives a advantage of reusing those drivers like SoundWire, pinctrl 
on other Qualcomm IPs as well!
Also I did not wanted to have a custom functions or hooks in the 
drivers, so platform bus made much sense for me to use here, which can 
take care of bringing up and tearing down the devices with proper parent 
child relationship.
This will instantiate all the child devices like pinctrl, SoundWire 
Controller and so on.

> 

>> +{

>> +	struct device *dev = wcd->dev;

>> +	struct device_node *np = dev->of_node;

>> +	int ret;

>> +	/*

>> +	 * INTR1 consists of all possible interrupt sources Ear OCP,

> 

> Missing blank line.

> 

Yes, I will fix such instances in the driver in next version.

>> +	 * HPH OCP, MBHC, MAD, VBAT, and SVA

>> +	 * INTR2 is a subset of first interrupt sources MAD, VBAT, and SVA

>> +	 */

>> +	wcd->irq = of_irq_get_byname(wcd->dev->of_node, "intr1");

>> +	if (wcd->irq < 0) {

>> +		if (wcd->irq != -EPROBE_DEFER)

>> +			dev_err(wcd->dev, "Unable to configure IRQ\n");

> 

> It's helpful to print what the error code was, it can help people

> debug things.

I agree!
> 

>> +	wcd->reset_gpio = of_get_named_gpio(np,	"reset-gpios", 0);

>> +	if (wcd->reset_gpio < 0) {

>> +		dev_err(dev, "Reset gpio missing in DT\n");

>> +		return wcd->reset_gpio;

>> +	}

> 

> devm_gpiod_get()

Make sense!

> 

>> +static int wcd934x_bring_up(struct wcd934x_codec *wcd)

>> +{

>> +	struct regmap *wcd_regmap = wcd->regmap;

>> +	u16 id_minor, id_major;

>> +	int ret;

> 

>> +	dev_info(wcd->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n",

>> +		 __func__, id_major, id_minor);

>> +

> 

> What was with the other verison parsing and printing code?

I will fix this in next version with single place to print the version 
number.


Thanks,
srini
>
Mark Brown July 2, 2019, 4:57 p.m. UTC | #3
On Tue, Jul 02, 2019 at 05:37:01PM +0100, Srinivas Kandagatla wrote:
> On 02/07/2019 15:44, Mark Brown wrote:

> > On Tue, Jul 02, 2019 at 09:09:16AM +0100, Srinivas Kandagatla wrote:


> > > +	for (i = 0; i < ARRAY_SIZE(cpr_defaults); i++) {

> > > +		regmap_bulk_write(data->regmap,

> > > +				  WCD934X_CODEC_CPR_WR_DATA_0,

> > > +				(u8 *)&cpr_defaults[i].wr_data, 4);

> > > +		regmap_bulk_write(data->regmap,

> > > +				  WCD934X_CODEC_CPR_WR_ADDR_0,

> > > +				(u8 *)&cpr_defaults[i].wr_addr, 4);


> > What is "cpr" and should you be using a regmap patch here?  Why

> > is this not with the other default updates?  You've got loads of

> > random undocumented sequences like this all through the driver,

> > are they patches or are they things that should be controllable

> > by the user?


> It makes sense to have a single default map here, I will do the in next

> version. And regarding user controllable, I will go thru the list once

> again in detail and remove user controllable registers.


What is a "default map"?  In terms of user controllable stuff
it's not just a question of if things are currently user
controllable but also if they should be user controllable.

> > > +	return of_platform_populate(wcd->dev->of_node, NULL, NULL, wcd->dev);


> > Why are we doing this?


> I will not be using MFD in this instance as most of the resources like

> interrupts, pins, clks, SoundWire are modeled as proper drivers with

> their respective subsystems.


This is a driver for a single device, you should be able to
instantiate things without requiring binding through DT (and
hence support non-DT systems such as those using ACPI).

> This gives a advantage of reusing those drivers like SoundWire, pinctrl

> on other Qualcomm IPs as well!

> Also I did not wanted to have a custom functions or hooks in the

> drivers, so platform bus made much sense for me to use here, which can

> take care of bringing up and tearing down the devices with proper parent

> child relationship.

> This will instantiate all the child devices like pinctrl, SoundWire

> Controller and so on.


Just create platform devices like normal...
Srinivas Kandagatla July 3, 2019, 8:49 a.m. UTC | #4
On 02/07/2019 17:57, Mark Brown wrote:
> On Tue, Jul 02, 2019 at 05:37:01PM +0100, Srinivas Kandagatla wrote:

>> On 02/07/2019 15:44, Mark Brown wrote:

>>> On Tue, Jul 02, 2019 at 09:09:16AM +0100, Srinivas Kandagatla wrote:

> 

>>>> +	for (i = 0; i < ARRAY_SIZE(cpr_defaults); i++) {

>>>> +		regmap_bulk_write(data->regmap,

>>>> +				  WCD934X_CODEC_CPR_WR_DATA_0,

>>>> +				(u8 *)&cpr_defaults[i].wr_data, 4);

>>>> +		regmap_bulk_write(data->regmap,

>>>> +				  WCD934X_CODEC_CPR_WR_ADDR_0,

>>>> +				(u8 *)&cpr_defaults[i].wr_addr, 4);

> 

>>> What is "cpr" and should you be using a regmap patch here?  Why

>>> is this not with the other default updates?  You've got loads of

>>> random undocumented sequences like this all through the driver,

>>> are they patches or are they things that should be controllable

>>> by the user?

> 

>> It makes sense to have a single default map here, I will do the in next

>> version. And regarding user controllable, I will go thru the list once

>> again in detail and remove user controllable registers.

> 

> What is a "default map"?  In terms of user controllable stuff

> it's not just a question of if things are currently user

> controllable but also if they should be user controllable.


I meant default updates here. These magic values and list came from 
downstream android code, so I will have to audit them before I can say 
that it will be useful for them to be exposed to user.
Most of things that made sense to provide a user control for the 
usecases of playback/capture/sidetone/speakers are already exposed via 
mixer controls.
> 

>>>> +	return of_platform_populate(wcd->dev->of_node, NULL, NULL, wcd->dev);

> 

>>> Why are we doing this?

> 

>> I will not be using MFD in this instance as most of the resources like

>> interrupts, pins, clks, SoundWire are modeled as proper drivers with

>> their respective subsystems.

> 

> This is a driver for a single device, you should be able to

> instantiate things without requiring binding through DT (and

> hence support non-DT systems such as those using ACPI).


My view point atleast from hw side was that Codec is Parent which is 
encompassing these different blocks and bus interface. DT representation 
clearly showed that relationship between the parent and child devices.
Binding it through DT will make sure that resources are ready before 
they are instantiated.

All the child devices also have some machine/board specific properties 
and dependency on resources from parent like regmap, clks, and bus.

In ACPI case, am not 100% sure how these will be represented inline with 
hw representation.

Are you suggesting to use MFD here?

> 

>> This gives a advantage of reusing those drivers like SoundWire, pinctrl

>> on other Qualcomm IPs as well!

>> Also I did not wanted to have a custom functions or hooks in the

>> drivers, so platform bus made much sense for me to use here, which can

>> take care of bringing up and tearing down the devices with proper parent

>> child relationship.

>> This will instantiate all the child devices like pinctrl, SoundWire

>> Controller and so on.

> 

> Just create platform devices like normal...

These are already modeled as platform devices, except the fact that 
these are children of Codec device.

thanks,
srini
>
Mark Brown July 3, 2019, 11:52 a.m. UTC | #5
On Wed, Jul 03, 2019 at 09:49:37AM +0100, Srinivas Kandagatla wrote:
> On 02/07/2019 17:57, Mark Brown wrote:


> > This is a driver for a single device, you should be able to

> > instantiate things without requiring binding through DT (and

> > hence support non-DT systems such as those using ACPI).


> My view point atleast from hw side was that Codec is Parent which is

> encompassing these different blocks and bus interface. DT representation

> clearly showed that relationship between the parent and child devices.

> Binding it through DT will make sure that resources are ready before

> they are instantiated.


> All the child devices also have some machine/board specific properties

> and dependency on resources from parent like regmap, clks, and bus.


> In ACPI case, am not 100% sure how these will be represented inline with

> hw representation.


> Are you suggesting to use MFD here?


I'm saying that you should be using a MFD here like all the other
CODECs with multiple functions and that you shouldn't have
compatible strings in DT for the subfunctions since you already
know they'll be there simply from enumerating the chip as a whole
and how exactly they are divided up is a function of how Linux
currently has subsystems, not of the hardware.

> > > This will instantiate all the child devices like pinctrl, SoundWire

> > > Controller and so on.


> > Just create platform devices like normal...


> These are already modeled as platform devices, except the fact that

> these are children of Codec device.


No, you've got them as DT nodes.
Srinivas Kandagatla July 3, 2019, 12:06 p.m. UTC | #6
On 03/07/2019 12:52, Mark Brown wrote:
> On Wed, Jul 03, 2019 at 09:49:37AM +0100, Srinivas Kandagatla wrote:

>> On 02/07/2019 17:57, Mark Brown wrote:

> 

>>> This is a driver for a single device, you should be able to

>>> instantiate things without requiring binding through DT (and

>>> hence support non-DT systems such as those using ACPI).

> 

>> My view point atleast from hw side was that Codec is Parent which is

>> encompassing these different blocks and bus interface. DT representation

>> clearly showed that relationship between the parent and child devices.

>> Binding it through DT will make sure that resources are ready before

>> they are instantiated.

> 

>> All the child devices also have some machine/board specific properties

>> and dependency on resources from parent like regmap, clks, and bus.

> 

>> In ACPI case, am not 100% sure how these will be represented inline with

>> hw representation.

> 

>> Are you suggesting to use MFD here?

> 

> I'm saying that you should be using a MFD here like all the other

> CODECs with multiple functions and that you shouldn't have

> compatible strings in DT for the subfunctions since you already

> know they'll be there simply from enumerating the chip as a whole

> and how exactly they are divided up is a function of how Linux

> currently has subsystems, not of the hardware.

> 

Got it!, thanks for the input, I will change that in v2.



--srin
diff mbox series

Patch

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 9f89a5346299..efe02f498e48 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -200,6 +200,7 @@  config SND_SOC_ALL_CODECS
 	select SND_SOC_UDA134X
 	select SND_SOC_UDA1380 if I2C
 	select SND_SOC_WCD9335 if SLIMBUS
+	select SND_SOC_WCD934X if SLIMBUS
 	select SND_SOC_WL1273 if MFD_WL1273_CORE
 	select SND_SOC_WM0010 if SPI_MASTER
 	select SND_SOC_WM1250_EV1 if I2C
@@ -1212,6 +1213,15 @@  config SND_SOC_WCD9335
 	  Qualcomm Technologies, Inc. (QTI) multimedia solutions,
 	  including the MSM8996, MSM8976, and MSM8956 chipsets.
 
+config SND_SOC_WCD934X
+	tristate "WCD9340/WCD9341 Codec"
+	depends on SLIMBUS
+	select REGMAP_SLIMBUS
+	select REGMAP_IRQ
+	help
+	  The WCD9340/9341 is a audio codec IC Integrated in
+	  Qualcomm SoCs like SDM845.
+
 config SND_SOC_WL1273
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 5b4bb8cf4325..f595f1dcd68a 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -213,6 +213,7 @@  snd-soc-twl6040-objs := twl6040.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wcd9335-objs := wcd-clsh-v2.o wcd9335.o
+snd-soc-wcd934x-objs := wcd-clsh-v2.o wcd934x.o
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm-adsp-objs := wm_adsp.o
 snd-soc-wm0010-objs := wm0010.o
@@ -493,6 +494,7 @@  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_WCD934X)	+= snd-soc-wcd934x.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/wcd934x.c b/sound/soc/codecs/wcd934x.c
new file mode 100644
index 000000000000..98ec7ab396fc
--- /dev/null
+++ b/sound/soc/codecs/wcd934x.c
@@ -0,0 +1,2068 @@ 
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019, Linaro Limited
+
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of_clk.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/slimbus.h>
+#include <linux/kernel.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include "wcd934x.h"
+#include "wcd-clsh-v2.h"
+
+#define WCD934X_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 WCD934X_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\
+				 SNDRV_PCM_RATE_176400)
+#define WCD934X_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 WCD934X_SLIM_WATER_MARK_VAL \
+	((SLAVE_PORT_WATER_MARK_12BYTES << SLAVE_PORT_WATER_MARK_SHIFT) | \
+	 (SLAVE_PORT_ENABLE))
+
+#define WCD934X_SLIM_NUM_PORT_REG 3
+#define WCD934X_SLIM_PGD_PORT_INT_TX_EN0 (WCD934X_SLIM_PGD_PORT_INT_EN0 + 2)
+#define WCD934X_SLIM_IRQ_OVERFLOW BIT(0)
+#define WCD934X_SLIM_IRQ_UNDERFLOW BIT(1)
+#define WCD934X_SLIM_IRQ_PORT_CLOSED BIT(2)
+
+#define WCD934X_MCLK_CLK_12P288MHZ	12288000
+#define WCD934X_MCLK_CLK_9P6MHZ		9600000
+
+/* Only valid for 9.6 MHz mclk */
+#define WCD9XXX_DMIC_SAMPLE_RATE_2P4MHZ 2400000
+#define WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ 4800000
+
+/* Only valid for 12.288 MHz mclk */
+#define WCD9XXX_DMIC_SAMPLE_RATE_4P096MHZ 4096000
+
+#define WCD934X_DMIC_CLK_DIV_2  0x0
+#define WCD934X_DMIC_CLK_DIV_3  0x1
+#define WCD934X_DMIC_CLK_DIV_4  0x2
+#define WCD934X_DMIC_CLK_DIV_6  0x3
+#define WCD934X_DMIC_CLK_DIV_8  0x4
+#define WCD934X_DMIC_CLK_DIV_16  0x5
+#define WCD934X_DMIC_CLK_DRIVE_DEFAULT 0x02
+
+#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 WCD934X_RX_START	16
+#define WCD934X_NUM_INTERPOLATORS 9
+#define WCD934X_RX_PATH_CTL_OFFSET 20
+#define WCD934X_MAX_VALID_ADC_MUX  13
+#define WCD934X_INVALID_ADC_MUX 9
+
+#define WCD934X_SLIM_RX_CH(p) \
+	{.port = p + WCD934X_RX_START, .shift = p,}
+
+#define WCD934X_SLIM_TX_CH(p) \
+	{.port = p, .shift = p,}
+
+/* Feature masks to distinguish codec version */
+#define DSD_DISABLED_MASK   0
+#define SLNQ_DISABLED_MASK  1
+
+#define DSD_DISABLED   BIT(DSD_DISABLED_MASK)
+#define SLNQ_DISABLED  BIT(SLNQ_DISABLED_MASK)
+
+/* As fine version info cannot be retrieved before wcd probe.
+ * Define three coarse versions for possible future use before wcd probe.
+ */
+#define WCD_VERSION_1_0             0
+#define WCD_VERSION_1_1             1
+#define WCD_VERSION_WCD9340_1_0     2
+#define WCD_VERSION_WCD9341_1_0     3
+#define WCD_VERSION_WCD9340_1_1     4
+#define WCD_VERSION_WCD9341_1_1     5
+#define WCD_IS_1_0(wcd) \
+	((wcd->type == WCD934X) ? \
+	 ((wcd->version == WCD_VERSION_1_0 || \
+	   wcd->version == WCD_VERSION_WCD9340_1_0 || \
+	   wcd->version == WCD_VERSION_WCD9341_1_0) ? 1 : 0) : 0)
+#define WCD_IS_1_1(wcd) \
+	((wcd->type == WCD934X) ? \
+	 ((wcd->version == WCD_VERSION_1_1 || \
+	   wcd->version == WCD_VERSION_WCD9340_1_1 || \
+	   wcd->version == WCD_VERSION_WCD9341_1_1) ? 1 : 0) : 0)
+#define WCD_IS_WCD9340_1_0(wcd) \
+	((wcd->type == WCD934X) ? \
+	 ((wcd->version == WCD_VERSION_WCD9340_1_0) ? 1 : 0) : 0)
+#define WCD_IS_WCD9341_1_0(wcd) \
+	((wcd->type == WCD934X) ? \
+	 ((wcd->version == WCD_VERSION_WCD9341_1_0) ? 1 : 0) : 0)
+#define WCD_IS_WCD9340_1_1(wcd) \
+	((wcd->type == WCD934X) ? \
+	 ((wcd->version == WCD_VERSION_WCD9340_1_1) ? 1 : 0) : 0)
+#define WCD_IS_WCD9341_1_1(wcd) \
+	((wcd->type == WCD934X) ? \
+	 ((wcd->version == WCD_VERSION_WCD9341_1_1) ? 1 : 0) : 0)
+
+#define WCD934X_AMIC_PWR_LEVEL_LP 0
+#define WCD934X_AMIC_PWR_LEVEL_DEFAULT 1
+#define WCD934X_AMIC_PWR_LEVEL_HP 2
+#define WCD934X_AMIC_PWR_LEVEL_HYBRID 3
+#define WCD934X_AMIC_PWR_LVL_MASK 0x60
+#define WCD934X_AMIC_PWR_LVL_SHIFT 0x5
+
+#define WCD934X_DEC_PWR_LVL_MASK 0x06
+#define WCD934X_DEC_PWR_LVL_LP 0x02
+#define WCD934X_DEC_PWR_LVL_HP 0x04
+#define WCD934X_DEC_PWR_LVL_DF 0x00
+#define WCD934X_DEC_PWR_LVL_HYBRID WCD934X_DEC_PWR_LVL_DF
+
+#define WCD934X_MAX_MICBIAS 4
+#define WCD934X_DEF_MICBIAS_MV	1800
+#define WCD934X_MAX_MICBIAS_MV	2850
+
+enum {
+	SIDO_SOURCE_INTERNAL,
+	SIDO_SOURCE_RCO_BG,
+};
+
+enum {
+	INTERP_EAR = 0,
+	INTERP_HPHL,
+	INTERP_HPHR,
+	INTERP_LO1,
+	INTERP_LO2,
+	INTERP_LO3_NA, /* LO3 not avalible in Tavil */
+	INTERP_LO4_NA,
+	INTERP_SPKR1, /*INT7 WSA Speakers via soundwire */
+	INTERP_SPKR2, /*INT8 WSA Speakers via soundwire */
+	INTERP_MAX,
+};
+
+enum {
+	WCD934X_RX0 = 0,
+	WCD934X_RX1,
+	WCD934X_RX2,
+	WCD934X_RX3,
+	WCD934X_RX4,
+	WCD934X_RX5,
+	WCD934X_RX6,
+	WCD934X_RX7,
+	WCD934X_RX8,
+	WCD934X_RX9,
+	WCD934X_RX10,
+	WCD934X_RX11,
+	WCD934X_RX12,
+	WCD934X_RX_MAX,
+};
+
+enum {
+	WCD934X_TX0 = 0,
+	WCD934X_TX1,
+	WCD934X_TX2,
+	WCD934X_TX3,
+	WCD934X_TX4,
+	WCD934X_TX5,
+	WCD934X_TX6,
+	WCD934X_TX7,
+	WCD934X_TX8,
+	WCD934X_TX9,
+	WCD934X_TX10,
+	WCD934X_TX11,
+	WCD934X_TX12,
+	WCD934X_TX13,
+	WCD934X_TX14,
+	WCD934X_TX15,
+	WCD934X_TX_MAX,
+};
+
+struct wcd934x_reg_mask_val {
+	u16 reg;
+	u8 mask;
+	u8 val;
+};
+
+struct wcd934x_slim_ch {
+	u32 ch_num;
+	u16 port;
+	u16 shift;
+	struct list_head list;
+};
+
+static const struct wcd934x_slim_ch wcd934x_tx_chs[WCD934X_TX_MAX] = {
+	WCD934X_SLIM_TX_CH(0),
+	WCD934X_SLIM_TX_CH(1),
+	WCD934X_SLIM_TX_CH(2),
+	WCD934X_SLIM_TX_CH(3),
+	WCD934X_SLIM_TX_CH(4),
+	WCD934X_SLIM_TX_CH(5),
+	WCD934X_SLIM_TX_CH(6),
+	WCD934X_SLIM_TX_CH(7),
+	WCD934X_SLIM_TX_CH(8),
+	WCD934X_SLIM_TX_CH(9),
+	WCD934X_SLIM_TX_CH(10),
+	WCD934X_SLIM_TX_CH(11),
+	WCD934X_SLIM_TX_CH(12),
+	WCD934X_SLIM_TX_CH(13),
+	WCD934X_SLIM_TX_CH(14),
+	WCD934X_SLIM_TX_CH(15),
+};
+
+static const struct wcd934x_slim_ch wcd934x_rx_chs[WCD934X_RX_MAX] = {
+	WCD934X_SLIM_RX_CH(0),	 /* 16 */
+	WCD934X_SLIM_RX_CH(1),	 /* 17 */
+	WCD934X_SLIM_RX_CH(2),
+	WCD934X_SLIM_RX_CH(3),
+	WCD934X_SLIM_RX_CH(4),
+	WCD934X_SLIM_RX_CH(5),
+	WCD934X_SLIM_RX_CH(6),
+	WCD934X_SLIM_RX_CH(7),
+	WCD934X_SLIM_RX_CH(8),
+	WCD934X_SLIM_RX_CH(9),
+	WCD934X_SLIM_RX_CH(10),
+	WCD934X_SLIM_RX_CH(11),
+	WCD934X_SLIM_RX_CH(12),
+};
+
+enum {
+	AIF1_PB = 0,
+	AIF1_CAP,
+	AIF2_PB,
+	AIF2_CAP,
+	AIF3_PB,
+	AIF3_CAP,
+	AIF4_PB,
+	AIF4_VIFEED,
+	AIF4_MAD_TX,
+	NUM_CODEC_DAIS,
+};
+
+enum {
+	INTn_1_INP_SEL_ZERO = 0,
+	INTn_1_INP_SEL_DEC0,
+	INTn_1_INP_SEL_DEC1,
+	INTn_1_INP_SEL_IIR0,
+	INTn_1_INP_SEL_IIR1,
+	INTn_1_INP_SEL_RX0,
+	INTn_1_INP_SEL_RX1,
+	INTn_1_INP_SEL_RX2,
+	INTn_1_INP_SEL_RX3,
+	INTn_1_INP_SEL_RX4,
+	INTn_1_INP_SEL_RX5,
+	INTn_1_INP_SEL_RX6,
+	INTn_1_INP_SEL_RX7,
+};
+
+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 {
+	INTERP_MAIN_PATH,
+	INTERP_MIX_PATH,
+};
+
+struct interp_sample_rate {
+	int sample_rate;
+	int rate_val;
+};
+
+static struct interp_sample_rate sr_val_tbl[] = {
+	{8000, 0x0},
+	{16000, 0x1},
+	{32000, 0x3},
+	{48000, 0x4},
+	{96000, 0x5},
+	{192000, 0x6},
+	{384000, 0x7},
+	{44100, 0x9},
+	{88200, 0xA},
+	{176400, 0xB},
+	{352800, 0xC},
+};
+
+struct wcd_slim_codec_dai_data {
+	struct list_head slim_ch_list;
+	struct slim_stream_config sconfig;
+	struct slim_stream_runtime *sruntime;
+};
+
+#define WCD934X_MAX_SUPPLY	5
+struct wcd934x_codec {
+	struct device *dev;
+	struct clk_hw hw;
+	struct clk *extclk;
+	int clk_mclk_users;
+	int master_bias_users;
+	int rate;
+	int irq;
+	int reset_gpio;
+	struct regmap *regmap;
+	struct regmap *if_regmap;
+	struct regmap_irq_chip_data *irq_data;
+
+	struct slim_device *slim;
+	struct slim_device *slim_ifc_dev;
+	struct wcd934x_slim_ch rx_chs[WCD934X_RX_MAX];
+	struct wcd934x_slim_ch tx_chs[WCD934X_TX_MAX];
+	struct regulator_bulk_data supplies[WCD934X_MAX_SUPPLY];
+	u32 num_rx_port;
+	u32 num_tx_port;
+	struct snd_soc_component *component;
+	struct wcd_slim_codec_dai_data dai[NUM_CODEC_DAIS];
+	struct wcd_clsh_ctrl *clsh_ctrl;
+	u32 hph_mode;
+	u32 rx_bias_count;
+	u32 version;
+	int main_clk_users[WCD934X_NUM_INTERPOLATORS];
+	unsigned int rx_port_value;
+	unsigned int tx_port_value;
+
+	/*TX*/
+	int micb_ref[WCD934X_MAX_MICBIAS];
+	int pullup_ref[WCD934X_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 power_active_ref;
+	int cur_power_state;
+	int sido_input_src;
+	int clk_type;
+};
+
+#define to_wcd934x_codec(_hw) container_of(_hw, struct wcd934x_codec, hw)
+
+enum wcd_clock_type {
+	WCD_CLK_OFF,
+	WCD_CLK_RCO,
+	WCD_CLK_MCLK,
+};
+
+enum codec_power_states {
+	WCD_REGION_POWER_COLLAPSE_REMOVE,
+	WCD_REGION_POWER_COLLAPSE_BEGIN,
+	WCD_REGION_POWER_DOWN,
+};
+
+static void wcd934x_update_reg_defaults(struct wcd934x_codec *wcd)
+{
+	struct regmap *rm = wcd->regmap;
+
+	regmap_update_bits(rm, WCD934X_BIAS_VBG_FINE_ADJ, 0xFF, 0x75);
+	regmap_update_bits(rm, WCD934X_CODEC_CPR_SVS_CX_VDD, 0xFF, 0x7C);
+	regmap_update_bits(rm, WCD934X_CODEC_CPR_SVS2_CX_VDD, 0xFF, 0x58);
+	regmap_update_bits(rm, WCD934X_CDC_RX0_RX_PATH_DSMDEM_CTL, 0x01, 0x01);
+	regmap_update_bits(rm, WCD934X_CDC_RX1_RX_PATH_DSMDEM_CTL, 0x01, 0x01);
+	regmap_update_bits(rm, WCD934X_CDC_RX2_RX_PATH_DSMDEM_CTL, 0x01, 0x01);
+	regmap_update_bits(rm, WCD934X_CDC_RX3_RX_PATH_DSMDEM_CTL, 0x01, 0x01);
+	regmap_update_bits(rm, WCD934X_CDC_RX4_RX_PATH_DSMDEM_CTL, 0x01, 0x01);
+	regmap_update_bits(rm, WCD934X_CDC_RX7_RX_PATH_DSMDEM_CTL, 0x01, 0x01);
+	regmap_update_bits(rm, WCD934X_CDC_RX8_RX_PATH_DSMDEM_CTL, 0x01, 0x01);
+	regmap_update_bits(rm, WCD934X_CDC_COMPANDER8_CTL7, 0x1E, 0x18);
+	regmap_update_bits(rm, WCD934X_CDC_COMPANDER7_CTL7, 0x1E, 0x18);
+	regmap_update_bits(rm, WCD934X_CDC_RX0_RX_PATH_SEC0, 0x08, 0x0);
+	regmap_update_bits(rm, WCD934X_CDC_CLSH_DECAY_CTRL, 0x03, 0x0);
+	regmap_update_bits(rm, WCD934X_MICB1_TEST_CTL_2, 0x07, 0x01);
+	regmap_update_bits(rm, WCD934X_CDC_BOOST0_BOOST_CFG1, 0x3F, 0x12);
+	regmap_update_bits(rm, WCD934X_CDC_BOOST0_BOOST_CFG2, 0x1C, 0x08);
+	regmap_update_bits(rm, WCD934X_CDC_BOOST1_BOOST_CFG1, 0x3F, 0x12);
+	regmap_update_bits(rm, WCD934X_CDC_BOOST1_BOOST_CFG2, 0x1C, 0x08);
+	regmap_update_bits(rm, WCD934X_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD,
+			   0x1F, 0x09);
+	regmap_update_bits(rm, WCD934X_CDC_TX0_TX_PATH_CFG1, 0x01, 0x00);
+	regmap_update_bits(rm, WCD934X_CDC_TX1_TX_PATH_CFG1, 0x01, 0x00);
+	regmap_update_bits(rm, WCD934X_CDC_TX2_TX_PATH_CFG1, 0x01, 0x00);
+	regmap_update_bits(rm, WCD934X_CDC_TX3_TX_PATH_CFG1, 0x01, 0x00);
+	regmap_update_bits(rm, WCD934X_CDC_TX4_TX_PATH_CFG1, 0x01, 0x00);
+	regmap_update_bits(rm, WCD934X_CDC_TX5_TX_PATH_CFG1, 0x01, 0x00);
+	regmap_update_bits(rm, WCD934X_CDC_TX6_TX_PATH_CFG1, 0x01, 0x00);
+	regmap_update_bits(rm, WCD934X_CDC_TX7_TX_PATH_CFG1, 0x01, 0x00);
+	regmap_update_bits(rm, WCD934X_CDC_TX8_TX_PATH_CFG1, 0x01, 0x00);
+	regmap_update_bits(rm, WCD934X_RX_OCP_CTL, 0x0F, 0x02);
+	regmap_update_bits(rm, WCD934X_HPH_OCP_CTL, 0xFF, 0x3A);
+	regmap_update_bits(rm, WCD934X_HPH_L_TEST, 0x01, 0x01);
+	regmap_update_bits(rm, WCD934X_HPH_R_TEST, 0x01, 0x01);
+	regmap_update_bits(rm, WCD934X_CPE_FLL_CONFIG_CTL_2, 0xFF, 0x20);
+	regmap_update_bits(rm, WCD934X_MBHC_NEW_CTL_2, 0x0C, 0x00);
+}
+
+static int wcd934x_dig_core_remove_power_collapse(struct wcd934x_codec *data)
+{
+	data->power_active_ref++;
+	if (data->power_active_ref == 1 &&
+	    data->cur_power_state == WCD_REGION_POWER_DOWN) {
+		regmap_write(data->regmap,
+			     WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x05);
+		regmap_write(data->regmap,
+			     WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x07);
+		regmap_update_bits(data->regmap,
+				   WCD934X_CODEC_RPM_RST_CTL, 0x02, 0x00);
+		regmap_update_bits(data->regmap,
+				   WCD934X_CODEC_RPM_RST_CTL, 0x02, 0x02);
+		regmap_write(data->regmap,
+			     WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x03);
+
+		data->cur_power_state = WCD_REGION_POWER_COLLAPSE_REMOVE;
+	}
+	return 0;
+}
+
+static void wcd934x_codec_power_gate_digital_core(struct wcd934x_codec *data)
+{
+	data->power_active_ref--;
+
+	if (data->power_active_ref > 0) {
+		data->cur_power_state = WCD_REGION_POWER_COLLAPSE_BEGIN;
+		regmap_update_bits(data->regmap,
+			   WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x04, 0x04);
+		regmap_update_bits(data->regmap,
+			   WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x01, 0x00);
+		regmap_update_bits(data->regmap,
+			   WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x02, 0x00);
+		data->cur_power_state = WCD_REGION_POWER_DOWN;
+	}
+}
+
+static int wcd934x_enable_master_bias(struct wcd934x_codec *data)
+{
+	if (++data->master_bias_users != 1)
+		return 0;
+
+	regmap_update_bits(data->regmap, WCD934X_ANA_BIAS,   0x80, 0x80);
+	regmap_update_bits(data->regmap, WCD934X_ANA_BIAS,   0x40, 0x40);
+	/*
+	 * 1ms delay is required after pre-charge is enabled
+	 * as per HW requirement
+	 */
+	usleep_range(1000, 1100);
+	regmap_update_bits(data->regmap, WCD934X_ANA_BIAS, 0x40, 0x00);
+	regmap_update_bits(data->regmap,  WCD934X_ANA_BIAS, 0x20, 0x00);
+
+	return 0;
+}
+
+static int wcd934x_disable_master_bias(struct wcd934x_codec *data)
+{
+	if (data->master_bias_users <= 0)
+		return 0;
+
+	data->master_bias_users--;
+
+	if (data->master_bias_users == 0) {
+		regmap_update_bits(data->regmap, WCD934X_ANA_BIAS,
+				   0x80, 0x00);
+		regmap_update_bits(data->regmap,
+				   WCD934X_ANA_BIAS, 0x20, 0x00);
+	}
+
+	return 0;
+}
+
+static int wcd934x_enable_clk_mclk(struct wcd934x_codec *data)
+{
+	if (++data->clk_mclk_users == 1) {
+		/*
+		 * In data clock contrl register is changed
+		 * to CLK_SYS_MCLK_PRG
+		 */
+		regmap_update_bits(data->regmap, WCD934X_CLK_SYS_MCLK_PRG,
+				   0x80, 0x80);
+		regmap_update_bits(data->regmap, WCD934X_CLK_SYS_MCLK_PRG,
+				   0x30, 0x10);
+		regmap_update_bits(data->regmap, WCD934X_CLK_SYS_MCLK_PRG,
+				   0x02, 0x00);
+		regmap_update_bits(data->regmap, WCD934X_CLK_SYS_MCLK_PRG,
+				   0x01, 0x01);
+		regmap_update_bits(data->regmap, WCD934X_CLK_SYS_MCLK_PRG,
+				   0x02, 0x00);
+		regmap_update_bits(data->regmap,
+				   WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL,
+				   0x01, 0x01);
+		regmap_update_bits(data->regmap,
+				   WCD934X_CDC_CLK_RST_CTRL_MCLK_CONTROL,
+				   0x01, 0x01);
+		regmap_update_bits(data->regmap,
+				   WCD934X_CDC_CLK_RST_CTRL_MCLK_CONTROL,
+				   0x01, 0x01);
+		regmap_update_bits(data->regmap, WCD934X_CODEC_RPM_CLK_GATE,
+				   0x03, 0x00);
+		/*
+		 * 10us sleep is required after clock is enabled
+		 * as per HW requirement
+		 */
+		usleep_range(10, 15);
+	}
+
+	data->clk_type = WCD_CLK_MCLK;
+
+	return 0;
+}
+
+static void wcd934x_set_sido_input_src(struct wcd934x_codec *data,
+				       int sido_src)
+{
+	if (sido_src == data->sido_input_src)
+		return;
+
+	if (sido_src == SIDO_SOURCE_INTERNAL) {
+		regmap_update_bits(data->regmap, WCD934X_ANA_BUCK_CTL,
+				   0x04, 0x00);
+		usleep_range(100, 110);
+		regmap_update_bits(data->regmap, WCD934X_ANA_BUCK_CTL,
+				   0x03, 0x00);
+		usleep_range(100, 110);
+		regmap_update_bits(data->regmap, WCD934X_ANA_RCO,
+				   0x80, 0x00);
+		usleep_range(100, 110);
+	} else if (sido_src == SIDO_SOURCE_RCO_BG) {
+		regmap_update_bits(data->regmap, WCD934X_ANA_RCO,
+				   0x80, 0x80);
+		usleep_range(100, 110);
+		regmap_update_bits(data->regmap, WCD934X_ANA_BUCK_CTL,
+				   0x02, 0x02);
+		usleep_range(100, 110);
+		regmap_update_bits(data->regmap, WCD934X_ANA_BUCK_CTL,
+				   0x01, 0x01);
+		usleep_range(100, 110);
+		regmap_update_bits(data->regmap, WCD934X_ANA_BUCK_CTL,
+				   0x04, 0x04);
+		usleep_range(100, 110);
+	}
+	data->sido_input_src = sido_src;
+}
+
+static int wcd934x_disable_clk_mclk(struct wcd934x_codec *data)
+{
+	if (--data->clk_mclk_users == 0) {
+		regmap_update_bits(data->regmap,
+				   WCD934X_CLK_SYS_MCLK_PRG, 0x81, 0x00);
+		data->clk_type = WCD_CLK_OFF;
+		wcd934x_set_sido_input_src(data, SIDO_SOURCE_INTERNAL);
+	}
+
+	return 0;
+}
+
+static int wcd934x_cdc_req_mclk_enable(struct wcd934x_codec *data,
+				       bool enable)
+{
+	int ret = 0;
+
+	if (enable) {
+		ret = clk_prepare_enable(data->extclk);
+		if (ret) {
+			dev_err(data->dev, "%s: ext clk enable failed\n",
+				__func__);
+			goto done;
+		}
+		wcd934x_enable_master_bias(data);
+		wcd934x_enable_clk_mclk(data);
+	} else {
+		wcd934x_disable_clk_mclk(data);
+		wcd934x_disable_master_bias(data);
+		clk_disable_unprepare(data->extclk);
+	}
+
+done:
+	return ret;
+}
+
+static int __wcd934x_cdc_mclk_enable(struct wcd934x_codec *wcd,
+				     bool enable)
+{
+	int ret = 0;
+
+	if (enable) {
+		wcd934x_dig_core_remove_power_collapse(wcd);
+		ret = wcd934x_cdc_req_mclk_enable(wcd, true);
+		if (ret)
+			goto done;
+	} else {
+		int val;
+
+		regmap_read(wcd->regmap, WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL,
+			    &val);
+
+		/* Don't disable clock if the soundwire/others using it.*/
+		if (val & 0x1)
+			return 0;
+
+		wcd934x_cdc_req_mclk_enable(wcd, false);
+		wcd934x_codec_power_gate_digital_core(wcd);
+	}
+
+done:
+	return ret;
+}
+
+static void wcd934x_get_version(struct wcd934x_codec *wcd)
+{
+	int val1, val2, version, ret;
+	struct regmap *regmap;
+	u16 id_minor;
+	u32 version_mask = 0;
+
+	regmap = wcd->regmap;
+	version = 0;
+
+	ret = regmap_bulk_read(regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0,
+			       (u8 *)&id_minor, sizeof(u16));
+
+	if (ret)
+		return;
+
+	regmap_read(regmap, WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT14, &val1);
+	regmap_read(regmap, WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT15, &val2);
+
+	dev_info(wcd->dev, "%s: chip version :0x%x 0x:%x\n",
+		 __func__, val1, val2);
+
+	version_mask |= (!!((u8)val1 & 0x80)) << DSD_DISABLED_MASK;
+	version_mask |= (!!((u8)val2 & 0x01)) << SLNQ_DISABLED_MASK;
+
+	switch (version_mask) {
+	case DSD_DISABLED | SLNQ_DISABLED:
+		if (id_minor == 0)
+			version = WCD_VERSION_WCD9340_1_0;
+		else if (id_minor == 0x01)
+			version = WCD_VERSION_WCD9340_1_1;
+		break;
+	case SLNQ_DISABLED:
+		if (id_minor == 0)
+			version = WCD_VERSION_WCD9341_1_0;
+		else if (id_minor == 0x01)
+			version = WCD_VERSION_WCD9341_1_1;
+		break;
+	}
+
+	wcd->version = version;
+}
+
+static void wcd934x_enable_efuse_sensing(struct wcd934x_codec *data)
+{
+	int rc, val;
+
+	__wcd934x_cdc_mclk_enable(data, true);
+
+	regmap_update_bits(data->regmap,
+			   WCD934X_CHIP_TIER_CTRL_EFUSE_CTL, 0x1E, 0x10);
+	regmap_update_bits(data->regmap,
+			   WCD934X_CHIP_TIER_CTRL_EFUSE_CTL, 0x01, 0x01);
+	/*
+	 * 5ms sleep required after enabling efuse control
+	 * before checking the status.
+	 */
+	usleep_range(5000, 5500);
+	wcd934x_set_sido_input_src(data, SIDO_SOURCE_RCO_BG);
+
+	rc = regmap_read(data->regmap,
+			 WCD934X_CHIP_TIER_CTRL_EFUSE_STATUS, &val);
+	if (rc || (!(val & 0x01)))
+		WARN(1, "%s: Efuse sense is not complete val=%x, ret=%d\n",
+		     __func__, val, rc);
+
+	__wcd934x_cdc_mclk_enable(data, false);
+}
+
+struct wcd934x_cpr_reg_defaults {
+	int wr_data;
+	int wr_addr;
+};
+
+static const struct wcd934x_cpr_reg_defaults cpr_defaults[] = {
+	{ 0x00000820, 0x00000094 },
+	{ 0x00000fC0, 0x00000048 },
+	{ 0x0000f000, 0x00000044 },
+	{ 0x0000bb80, 0xC0000178 },
+	{ 0x00000000, 0x00000160 },
+	{ 0x10854522, 0x00000060 },
+	{ 0x10854509, 0x00000064 },
+	{ 0x108544dd, 0x00000068 },
+	{ 0x108544ad, 0x0000006C },
+	{ 0x0000077E, 0x00000070 },
+	{ 0x000007da, 0x00000074 },
+	{ 0x00000000, 0x00000078 },
+	{ 0x00000000, 0x0000007C },
+	{ 0x00042029, 0x00000080 },
+	{ 0x4002002A, 0x00000090 },
+	{ 0x4002002B, 0x00000090 },
+};
+
+static void wcd934x_update_cpr_defaults(struct wcd934x_codec *data)
+{
+	int i;
+
+	__wcd934x_cdc_mclk_enable(data, true);
+
+	wcd934x_set_sido_input_src(data, SIDO_SOURCE_RCO_BG);
+	regmap_write(data->regmap, WCD934X_CODEC_CPR_SVS2_MIN_CX_VDD, 0x2C);
+	regmap_update_bits(data->regmap, WCD934X_CODEC_RPM_CLK_GATE,
+			   0x10, 0x00);
+
+	for (i = 0; i < ARRAY_SIZE(cpr_defaults); i++) {
+		regmap_bulk_write(data->regmap,
+				  WCD934X_CODEC_CPR_WR_DATA_0,
+				(u8 *)&cpr_defaults[i].wr_data, 4);
+		regmap_bulk_write(data->regmap,
+				  WCD934X_CODEC_CPR_WR_ADDR_0,
+				(u8 *)&cpr_defaults[i].wr_addr, 4);
+	}
+
+	__wcd934x_cdc_mclk_enable(data, false);
+}
+
+static int wcd934x_swrm_clock(struct wcd934x_codec *data, bool enable)
+{
+	if (enable) {
+		regmap_update_bits(data->regmap,
+				   WCD934X_TEST_DEBUG_NPL_DLY_TEST_1,
+				   0x10, 0x00);
+		__wcd934x_cdc_mclk_enable(data, true);
+		regmap_update_bits(data->regmap,
+				   WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL,
+				   0x01, 0x01);
+	} else {
+		regmap_update_bits(data->regmap,
+				   WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL,
+				   0x01, 0x00);
+		__wcd934x_cdc_mclk_enable(data, false);
+		regmap_update_bits(data->regmap,
+				   WCD934X_TEST_DEBUG_NPL_DLY_TEST_1,
+				   0x10, 0x10);
+	}
+
+	return 0;
+}
+
+static const struct wcd934x_reg_mask_val wcd934x_codec_reg_init_1_1_val[] = {
+	{WCD934X_CDC_COMPANDER1_CTL7, 0x1E, 0x06},
+	{WCD934X_CDC_COMPANDER2_CTL7, 0x1E, 0x06},
+	{WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0xFF, 0x84},
+	{WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0xFF, 0x84},
+	{WCD934X_CDC_RX3_RX_PATH_SEC0, 0xFC, 0xF4},
+	{WCD934X_CDC_RX4_RX_PATH_SEC0, 0xFC, 0xF4},
+};
+
+static const struct wcd934x_reg_mask_val wcd934x_codec_reg_init_common_val[] = {
+	{WCD934X_CDC_CLSH_K2_MSB, 0x0F, 0x00},
+	{WCD934X_CDC_CLSH_K2_LSB, 0xFF, 0x60},
+	{WCD934X_CPE_SS_DMIC_CFG, 0x80, 0x00},
+	{WCD934X_CDC_BOOST0_BOOST_CTL, 0x7C, 0x58},
+	{WCD934X_CDC_BOOST1_BOOST_CTL, 0x7C, 0x58},
+	{WCD934X_CDC_RX7_RX_PATH_CFG1, 0x08, 0x08},
+	{WCD934X_CDC_RX8_RX_PATH_CFG1, 0x08, 0x08},
+	{WCD934X_CDC_TOP_TOP_CFG1, 0x02, 0x02},
+	{WCD934X_CDC_TOP_TOP_CFG1, 0x01, 0x01},
+	{WCD934X_CDC_TX9_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{WCD934X_CDC_TX10_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{WCD934X_CDC_TX11_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{WCD934X_CDC_TX12_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+	{WCD934X_DATA_HUB_SB_TX11_INP_CFG, 0x01, 0x01},
+	{WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL, 0x01, 0x01},
+	{WCD934X_CDC_COMPANDER7_CTL3, 0x80, 0x80},
+	{WCD934X_CDC_COMPANDER8_CTL3, 0x80, 0x80},
+	{WCD934X_CDC_COMPANDER7_CTL7, 0x01, 0x01},
+	{WCD934X_CDC_COMPANDER8_CTL7, 0x01, 0x01},
+	{WCD934X_CODEC_RPM_CLK_GATE, 0x08, 0x00},
+	{WCD934X_TLMM_DMIC3_CLK_PINCFG, 0xFF, 0x0a},
+	{WCD934X_TLMM_DMIC3_DATA_PINCFG, 0xFF, 0x0a},
+	{WCD934X_CPE_SS_SVA_CFG, 0x60, 0x00},
+	{WCD934X_CPE_SS_CPAR_CFG, 0x10, 0x10},
+	{WCD934X_MICB1_TEST_CTL_1, 0xff, 0xfa},
+	{WCD934X_MICB2_TEST_CTL_1, 0xff, 0xfa},
+	{WCD934X_MICB3_TEST_CTL_1, 0xff, 0xfa},
+	{WCD934X_MICB4_TEST_CTL_1, 0xff, 0xfa},
+};
+
+static const struct wcd934x_reg_mask_val wcd934x_codec_mclk2_1_1_defaults[] = {
+	{WCD934X_CLK_SYS_MCLK2_PRG1, 0x60, 0x20},
+};
+
+static void wcd934x_mclk2_reg_defaults(struct wcd934x_codec *data)
+{
+	u32 i;
+
+	for (i = 0; i < ARRAY_SIZE(wcd934x_codec_mclk2_1_1_defaults); i++)
+		regmap_update_bits(data->regmap,
+				   wcd934x_codec_mclk2_1_1_defaults[i].reg,
+				    wcd934x_codec_mclk2_1_1_defaults[i].mask,
+				    wcd934x_codec_mclk2_1_1_defaults[i].val);
+}
+
+static void wcd934x_codec_init_reg(struct wcd934x_codec *data)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wcd934x_codec_reg_init_common_val); i++)
+		regmap_update_bits(data->regmap,
+				   wcd934x_codec_reg_init_common_val[i].reg,
+				    wcd934x_codec_reg_init_common_val[i].mask,
+				    wcd934x_codec_reg_init_common_val[i].val);
+
+	for (i = 0; i < ARRAY_SIZE(wcd934x_codec_reg_init_1_1_val); i++)
+		regmap_update_bits(data->regmap,
+				   wcd934x_codec_reg_init_1_1_val[i].reg,
+				   wcd934x_codec_reg_init_1_1_val[i].mask,
+				   wcd934x_codec_reg_init_1_1_val[i].val);
+}
+
+static int wcd934x_set_prim_interpolator_rate(struct snd_soc_dai *dai,
+					      u8 rate_val,
+					      u32 rate)
+{
+	struct snd_soc_component *comp = dai->component;
+	struct wcd934x_codec *wcd = dev_get_drvdata(comp->dev);
+	struct wcd934x_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_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 < WCD934X_NUM_INTERPOLATORS; j++) {
+			/* Interpolators 5 and 6 are not aviliable in Tavil */
+			if (j == INTERP_LO3_NA || j == INTERP_LO4_NA)
+				continue;
+
+			cfg0 = snd_soc_component_read32(comp,
+					WCD934X_CDC_RX_INP_MUX_RX_INT_CFG0(j));
+			cfg1 = snd_soc_component_read32(comp,
+					WCD934X_CDC_RX_INP_MUX_RX_INT_CFG1(j));
+
+			inp0_sel = cfg0 &
+				 WCD934X_CDC_RX_INP_MUX_RX_INT_SEL_MASK;
+			inp1_sel = (cfg0 >> 4) &
+				 WCD934X_CDC_RX_INP_MUX_RX_INT_SEL_MASK;
+			inp2_sel = (cfg1 >> 4) &
+				 WCD934X_CDC_RX_INP_MUX_RX_INT_SEL_MASK;
+
+			if ((inp0_sel == inp) ||  (inp1_sel == inp) ||
+			    (inp2_sel == inp)) {
+				/* rate is in Hz */
+				/*
+				 * Ear and speaker primary path does not support
+				 * native sample rates
+				 */
+				if ((j == INTERP_EAR || j == INTERP_SPKR1 ||
+				     j == INTERP_SPKR2) && rate == 44100)
+					dev_err(wcd->dev,
+						"Cannot set 44.1KHz on INT%d\n",
+						j);
+				else
+					snd_soc_component_update_bits(comp,
+					      WCD934X_CDC_RX_PATH_CTL(j),
+					      WCD934X_CDC_MIX_PCM_RATE_MASK,
+					      rate_val);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int wcd934x_set_mix_interpolator_rate(struct snd_soc_dai *dai,
+					     int rate_val,
+					     u32 rate)
+{
+	struct snd_soc_component *component = dai->component;
+	struct wcd934x_codec *wcd = dev_get_drvdata(component->dev);
+	struct wcd934x_slim_ch *ch;
+	int val, j;
+
+	list_for_each_entry(ch, &wcd->dai[dai->id].slim_ch_list, list) {
+		for (j = 0; j < WCD934X_NUM_INTERPOLATORS; j++) {
+			/* Interpolators 5 and 6 are not aviliable in Tavil */
+			if (j == INTERP_LO3_NA || j == INTERP_LO4_NA)
+				continue;
+			val = snd_soc_component_read32(component,
+					WCD934X_CDC_RX_INP_MUX_RX_INT_CFG1(j)) &
+					WCD934X_CDC_RX_INP_MUX_RX_INT_SEL_MASK;
+
+			if (val == (ch->shift + INTn_2_INP_SEL_RX0)) {
+				/*
+				 * Ear mix path supports only 48, 96, 192,
+				 * 384KHz only
+				 */
+				if ((j == INTERP_EAR) &&
+				    (rate_val < 0x4 ||
+				     rate_val > 0x7)) {
+					dev_err(component->dev,
+						"Invalid rate for AIF_PB DAI(%d)\n",
+						dai->id);
+					return -EINVAL;
+				}
+
+				snd_soc_component_update_bits(component,
+					      WCD934X_CDC_RX_PATH_MIX_CTL(j),
+					      WCD934X_CDC_MIX_PCM_RATE_MASK,
+					      rate_val);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int wcd934x_set_interpolator_rate(struct snd_soc_dai *dai,
+					 u32 sample_rate)
+{
+	int rate_val = 0;
+	int i, ret;
+
+	for (i = 0; i < ARRAY_SIZE(sr_val_tbl); i++) {
+		if (sample_rate == sr_val_tbl[i].sample_rate) {
+			rate_val = sr_val_tbl[i].rate_val;
+			break;
+		}
+	}
+	if ((i == ARRAY_SIZE(sr_val_tbl)) || (rate_val < 0)) {
+		pr_err("%s: Unsupported sample rate: %d\n",
+		       __func__, sample_rate);
+		return -EINVAL;
+	}
+
+	ret = wcd934x_set_prim_interpolator_rate(dai, (u8)rate_val,
+						 sample_rate);
+	if (ret)
+		return ret;
+	ret = wcd934x_set_mix_interpolator_rate(dai, (u8)rate_val,
+						sample_rate);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+static int wcd934x_set_decimator_rate(struct snd_soc_dai *dai,
+				      u8 rate_val, u32 rate)
+{
+	struct snd_soc_component *comp = dai->component;
+	struct wcd934x_codec *wcd = snd_soc_component_get_drvdata(comp);
+	u8 shift = 0, shift_val = 0, tx_mux_sel;
+	struct wcd934x_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 = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0;
+			shift = (tx_port << 1);
+			shift_val = 0x03;
+		} else if ((tx_port >= 4) && (tx_port < 8)) {
+			tx_port_reg = WCD934X_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 = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2;
+			shift = ((tx_port - 8) << 1);
+			shift_val = 0x03;
+		} else if (tx_port == 11) {
+			tx_port_reg = WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3;
+			shift = 0;
+			shift_val = 0x0F;
+		} else if (tx_port == 13) {
+			tx_port_reg = WCD934X_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,
+				      WCD934X_CDC_TX_PATH_CTL(decimator),
+				      WCD934X_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 wcd934x_slim_set_hw_params(struct wcd934x_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 wcd934x_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,
+			   WCD934X_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,
+					WCD934X_SLIM_PGD_RX_PORT_CFG(ch->port),
+					WCD934X_SLIM_WATER_MARK_VAL);
+			if (ret < 0)
+				goto err;
+		} else {
+			ret = regmap_write(wcd->if_regmap,
+				WCD934X_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,
+				WCD934X_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,
+					WCD934X_SLIM_PGD_TX_PORT_CFG(ch->port),
+					WCD934X_SLIM_WATER_MARK_VAL);
+
+			if (ret < 0)
+				goto err;
+		}
+	}
+
+	dai_data->sruntime = slim_stream_allocate(wcd->slim, "WCD934x-SLIM");
+
+	return 0;
+
+err:
+	dev_err(wcd->dev, "Error Setting slim hw params\n");
+	kfree(cfg->chs);
+	cfg->chs = NULL;
+
+	return ret;
+}
+
+static int wcd934x_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct wcd934x_codec *wcd;
+	int ret, tx_fs_rate = 0;
+
+	wcd = snd_soc_component_get_drvdata(dai->component);
+
+	switch (substream->stream) {
+	case SNDRV_PCM_STREAM_PLAYBACK:
+		ret = wcd934x_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;
+
+	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 = wcd934x_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);
+		return -EINVAL;
+	};
+
+	wcd->dai[dai->id].sconfig.rate = params_rate(params);
+	wcd934x_slim_set_hw_params(wcd, &wcd->dai[dai->id], substream->stream);
+
+	return 0;
+}
+
+static int wcd934x_trigger(struct snd_pcm_substream *substream, int cmd,
+			   struct snd_soc_dai *dai)
+{
+	struct wcd_slim_codec_dai_data *dai_data;
+	struct wcd934x_codec *wcd;
+	struct slim_stream_config *cfg;
+
+	wcd = snd_soc_component_get_drvdata(dai->component);
+
+	dai_data = &wcd->dai[dai->id];
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		cfg = &dai_data->sconfig;
+		slim_stream_prepare(dai_data->sruntime, cfg);
+		slim_stream_enable(dai_data->sruntime);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		slim_stream_unprepare(dai_data->sruntime);
+		slim_stream_disable(dai_data->sruntime);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int wcd934x_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 wcd934x_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);
+		}
+	}
+
+	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;
+}
+
+static int wcd934x_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 wcd934x_slim_ch *ch;
+	struct wcd934x_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;
+	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;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops wcd934x_dai_ops = {
+	.hw_params = wcd934x_hw_params,
+	.trigger = wcd934x_trigger,
+	.set_channel_map = wcd934x_set_channel_map,
+	.get_channel_map = wcd934x_get_channel_map,
+};
+
+static struct snd_soc_dai_driver wcd934x_slim_dais[] = {
+	[0] = {
+		.name = "wcd934x_rx1",
+		.id = AIF1_PB,
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.rates = WCD934X_RATES_MASK | WCD934X_FRAC_RATES_MASK,
+			.formats = WCD934X_FORMATS_S16_S24_LE,
+			.rate_max = 192000,
+			.rate_min = 8000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &wcd934x_dai_ops,
+	},
+	[1] = {
+		.name = "wcd934x_tx1",
+		.id = AIF1_CAP,
+		.capture = {
+			.stream_name = "AIF1 Capture",
+			.rates = WCD934X_RATES_MASK,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rate_min = 8000,
+			.rate_max = 192000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &wcd934x_dai_ops,
+	},
+	[2] = {
+		.name = "wcd934x_rx2",
+		.id = AIF2_PB,
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.rates = WCD934X_RATES_MASK | WCD934X_FRAC_RATES_MASK,
+			.formats = WCD934X_FORMATS_S16_S24_LE,
+			.rate_min = 8000,
+			.rate_max = 192000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &wcd934x_dai_ops,
+	},
+	[3] = {
+		.name = "wcd934x_tx2",
+		.id = AIF2_CAP,
+		.capture = {
+			.stream_name = "AIF2 Capture",
+			.rates = WCD934X_RATES_MASK,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rate_min = 8000,
+			.rate_max = 192000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &wcd934x_dai_ops,
+	},
+	[4] = {
+		.name = "wcd934x_rx3",
+		.id = AIF3_PB,
+		.playback = {
+			.stream_name = "AIF3 Playback",
+			.rates = WCD934X_RATES_MASK | WCD934X_FRAC_RATES_MASK,
+			.formats = WCD934X_FORMATS_S16_S24_LE,
+			.rate_min = 8000,
+			.rate_max = 192000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &wcd934x_dai_ops,
+	},
+	[5] = {
+		.name = "wcd934x_tx3",
+		.id = AIF3_CAP,
+		.capture = {
+			.stream_name = "AIF3 Capture",
+			.rates = WCD934X_RATES_MASK,
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+			.rate_min = 8000,
+			.rate_max = 192000,
+			.channels_min = 1,
+			.channels_max = 4,
+		},
+		.ops = &wcd934x_dai_ops,
+	},
+	[6] = {
+		.name = "wcd934x_rx4",
+		.id = AIF4_PB,
+		.playback = {
+			.stream_name = "AIF4 Playback",
+			.rates = WCD934X_RATES_MASK | WCD934X_FRAC_RATES_MASK,
+			.formats = WCD934X_FORMATS_S16_S24_LE,
+			.rate_min = 8000,
+			.rate_max = 192000,
+			.channels_min = 1,
+			.channels_max = 2,
+		},
+		.ops = &wcd934x_dai_ops,
+	},
+};
+
+static int swclk_gate_enable(struct clk_hw *hw)
+{
+	return wcd934x_swrm_clock(to_wcd934x_codec(hw), true);
+}
+
+static void swclk_gate_disable(struct clk_hw *hw)
+{
+	wcd934x_swrm_clock(to_wcd934x_codec(hw), false);
+}
+
+static int swclk_gate_is_enabled(struct clk_hw *hw)
+{
+	struct wcd934x_codec *wcd = to_wcd934x_codec(hw);
+	int ret, val;
+
+	regmap_read(wcd->regmap, WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL, &val);
+	ret = val & 0x01;
+
+	return ret;
+}
+
+static unsigned long swclk_recalc_rate(struct clk_hw *hw,
+				       unsigned long parent_rate)
+{
+	return parent_rate / 2;
+}
+
+static const struct clk_ops swclk_gate_ops = {
+	.prepare = swclk_gate_enable,
+	.unprepare = swclk_gate_disable,
+	.is_enabled = swclk_gate_is_enabled,
+	.recalc_rate = swclk_recalc_rate,
+
+};
+
+static struct clk *wcd934x_register_mclk_output(struct wcd934x_codec *wcd)
+{
+	struct clk *parent = wcd->extclk;
+	struct device *dev = wcd->dev;
+	struct device_node *np = dev->of_node;
+	const char *parent_clk_name = NULL;
+	const char *clk_name = "mclk";
+	struct clk_hw *hw;
+	struct clk_init_data init;
+	int ret;
+
+	wcd->extclk = parent;
+
+	if (of_property_read_u32(np, "clock-frequency", &wcd->rate))
+		return NULL;
+
+	parent_clk_name = __clk_get_name(parent);
+
+	of_property_read_string(np, "clock-output-names", &clk_name);
+
+	init.name = clk_name;
+	init.ops = &swclk_gate_ops;
+	init.flags = 0;
+	init.parent_names = &parent_clk_name;
+	init.num_parents = 1;
+	wcd->hw.init = &init;
+
+	hw = &wcd->hw;
+	ret = clk_hw_register(wcd->dev, hw);
+	if (ret)
+		return ERR_PTR(ret);
+
+	of_clk_add_provider(np, of_clk_src_simple_get, hw->clk);
+
+	return NULL;
+}
+
+static int wcd934x_get_micbias_val(struct device *dev, const char *micbias)
+{
+	int mv;
+
+	if (of_property_read_u32(dev->of_node, micbias, &mv))
+		mv = WCD934X_DEF_MICBIAS_MV;
+
+	if (mv < 1000 || mv > 2850)
+		mv = WCD934X_DEF_MICBIAS_MV;
+
+	return (mv - 1000) / 50;
+}
+
+static int wcd934x_init_dmic(struct snd_soc_component *comp)
+{
+	int vout_ctl_1, vout_ctl_2, vout_ctl_3, vout_ctl_4;
+	struct wcd934x_codec *wcd = dev_get_drvdata(comp->dev);
+	u32 def_dmic_rate, dmic_clk_drv;
+
+	vout_ctl_1 = wcd934x_get_micbias_val(comp->dev, "qcom,mibias1-lvl");
+	vout_ctl_2 = wcd934x_get_micbias_val(comp->dev, "qcom,mibias2-lvl");
+	vout_ctl_3 = wcd934x_get_micbias_val(comp->dev, "qcom,mibias3-lvl");
+	vout_ctl_4 = wcd934x_get_micbias_val(comp->dev, "qcom,mibias4-lvl");
+
+	snd_soc_component_update_bits(comp, WCD934X_ANA_MICB1,
+				      WCD934X_MICB_VAL_MASK, vout_ctl_1);
+	snd_soc_component_update_bits(comp, WCD934X_ANA_MICB2,
+				      WCD934X_MICB_VAL_MASK, vout_ctl_2);
+	snd_soc_component_update_bits(comp, WCD934X_ANA_MICB3,
+				      WCD934X_MICB_VAL_MASK, vout_ctl_3);
+	snd_soc_component_update_bits(comp, WCD934X_ANA_MICB4,
+				      WCD934X_MICB_VAL_MASK, vout_ctl_4);
+
+	if (wcd->rate == WCD934X_MCLK_CLK_9P6MHZ)
+		def_dmic_rate = WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ;
+	else
+		def_dmic_rate = WCD9XXX_DMIC_SAMPLE_RATE_4P096MHZ;
+
+	wcd->dmic_sample_rate = def_dmic_rate;
+
+	dmic_clk_drv = 0;
+	snd_soc_component_update_bits(comp, WCD934X_TEST_DEBUG_PAD_DRVCTL_0,
+				      0x0C, dmic_clk_drv << 2);
+
+	return 0;
+}
+
+static int wcd934x_comp_init(struct snd_soc_component *component)
+{
+	struct wcd934x_codec *wcd = dev_get_drvdata(component->dev);
+
+	wcd934x_update_reg_defaults(wcd);
+	wcd934x_enable_efuse_sensing(wcd);
+	wcd934x_get_version(wcd);
+	wcd934x_update_cpr_defaults(wcd);
+	wcd934x_dig_core_remove_power_collapse(wcd);
+	wcd934x_codec_init_reg(wcd);
+	return 0;
+}
+
+static irqreturn_t wcd934x_slim_irq_handler(int irq, void *data)
+{
+	struct wcd934x_codec *wcd = data;
+	unsigned long status = 0;
+	int i, j, port_id;
+	unsigned int val, int_val = 0;
+	irqreturn_t ret = IRQ_NONE;
+	bool tx;
+	unsigned short reg = 0;
+
+	for (i = WCD934X_SLIM_PGD_PORT_INT_STATUS_RX_0, j = 0;
+	     i <= WCD934X_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,
+			    WCD934X_SLIM_PGD_PORT_INT_RX_SOURCE0 + j, &val);
+		if (val) {
+			if (!tx)
+				reg = WCD934X_SLIM_PGD_PORT_INT_EN0 +
+					(port_id / 8);
+			else
+				reg = WCD934X_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 & WCD934X_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 & WCD934X_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 & WCD934X_SLIM_IRQ_OVERFLOW) ||
+		    (val & WCD934X_SLIM_IRQ_UNDERFLOW)) {
+			if (!tx)
+				reg = WCD934X_SLIM_PGD_PORT_INT_EN0 +
+					(port_id / 8);
+			else
+				reg = WCD934X_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);
+			}
+		}
+
+		if (val & WCD934X_SLIM_IRQ_PORT_CLOSED)
+			dev_err_ratelimited(wcd->dev,
+					    "%s: Port Closed %s port %d, value %x\n",
+			   __func__, (tx ? "TX" : "RX"), port_id, val);
+
+		regmap_write(wcd->if_regmap,
+			     WCD934X_SLIM_PGD_PORT_INT_CLR_RX_0 + (j / 8),
+				BIT(j % 8));
+		ret = IRQ_HANDLED;
+	}
+
+	return ret;
+}
+
+static int wcd934x_comp_probe(struct snd_soc_component *component)
+{
+	struct wcd934x_codec *wcd = dev_get_drvdata(component->dev);
+	int i;
+
+	snd_soc_component_init_regmap(component, wcd->regmap);
+	wcd->component = component;
+
+	/* 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 Low HiFi */
+	wcd->hph_mode = CLS_H_LOHIFI;
+
+	wcd934x_comp_init(component);
+
+	for (i = 0; i < NUM_CODEC_DAIS; i++)
+		INIT_LIST_HEAD(&wcd->dai[i].slim_ch_list);
+
+	wcd934x_mclk2_reg_defaults(wcd);
+	wcd934x_init_dmic(component);
+	return 0;
+}
+
+static void wcd934x_comp_remove(struct snd_soc_component *comp)
+{
+	struct wcd934x_codec *wcd = dev_get_drvdata(comp->dev);
+
+	wcd_clsh_ctrl_free(wcd->clsh_ctrl);
+}
+
+static int wcd934x_comp_set_sysclk(struct snd_soc_component *comp,
+				   int clk_id, int source,
+				    unsigned int freq, int dir)
+{
+	struct wcd934x_codec *wcd = dev_get_drvdata(comp->dev);
+	int val = WCD934X_CODEC_RPM_CLK_MCLK_CFG_9P6MHZ;
+
+	wcd->rate = freq;
+
+	if (wcd->rate == WCD934X_MCLK_CLK_12P288MHZ)
+		val = WCD934X_CODEC_RPM_CLK_MCLK_CFG_12P288MHZ;
+
+	snd_soc_component_update_bits(comp, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
+				      WCD934X_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK,
+				      val);
+
+	return clk_set_rate(wcd->extclk, freq);
+}
+
+static const struct snd_soc_component_driver wcd934x_component_drv = {
+	.probe = wcd934x_comp_probe,
+	.remove = wcd934x_comp_remove,
+	.set_sysclk = wcd934x_comp_set_sysclk,
+};
+
+static int wcd934x_codec_probe(struct wcd934x_codec *wcd)
+{
+	struct device *dev = wcd->dev;
+	int ret, irq;
+
+	irq = regmap_irq_get_virq(wcd->irq_data, WCD934X_IRQ_SLIMBUS);
+	if (irq < 0) {
+		dev_err(wcd->dev, "Failed to get SLIM IRQ\n");
+		return irq;
+	}
+
+	wcd->cur_power_state = WCD_REGION_POWER_COLLAPSE_REMOVE;
+
+	/* set default rate 9P6MHz */
+	regmap_update_bits(wcd->regmap, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
+			   WCD934X_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK,
+			   WCD934X_CODEC_RPM_CLK_MCLK_CFG_9P6MHZ);
+	memcpy(wcd->rx_chs, wcd934x_rx_chs, sizeof(wcd934x_rx_chs));
+	memcpy(wcd->tx_chs, wcd934x_tx_chs, sizeof(wcd934x_tx_chs));
+
+	ret = devm_request_threaded_irq(dev, irq, NULL,
+					wcd934x_slim_irq_handler,
+					IRQF_TRIGGER_RISING,
+					"slim", wcd);
+	if (ret) {
+		dev_err(dev, "Failed to request slimbus irq\n");
+		return ret;
+	}
+	wcd934x_register_mclk_output(wcd);
+	of_property_read_u32(dev->of_node, "qcom,dmic-sample-rate",
+			     &wcd->dmic_sample_rate);
+	ret = devm_snd_soc_register_component(dev, &wcd934x_component_drv,
+					      wcd934x_slim_dais,
+					      ARRAY_SIZE(wcd934x_slim_dais));
+
+	return of_platform_populate(wcd->dev->of_node, NULL, NULL, wcd->dev);
+}
+
+static const struct regmap_range_cfg wcd934x_ranges[] = {
+	{	.name = "WCD934X",
+		.range_min =  0x0,
+		.range_max =  0xffff,
+		.selector_reg = 0x800,
+		.selector_mask = 0xff,
+		.selector_shift = 0,
+		.window_start = 0x800,
+		.window_len = 0x100,
+	},
+};
+
+static bool wcd934x_is_volatile_register(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case WCD934X_INTR_PIN1_STATUS0...WCD934X_INTR_PIN2_CLEAR3:
+	case WCD934X_SWR_AHB_BRIDGE_RD_DATA_0 ... WCD934X_SWR_AHB_BRIDGE_RD_DATA_3:
+	case WCD934X_SWR_AHB_BRIDGE_ACCESS_STATUS:
+	case WCD934X_ANA_MBHC_RESULT_3:
+	case WCD934X_ANA_MBHC_RESULT_2:
+	case WCD934X_ANA_MBHC_RESULT_1:
+	case WCD934X_ANA_MBHC_MECH:
+	case WCD934X_ANA_MBHC_ELECT:
+	case WCD934X_ANA_MBHC_ZDET:
+	case WCD934X_ANA_MICB2:
+	case WCD934X_ANA_RCO:
+	case WCD934X_ANA_BIAS:
+		return true;
+	default:
+		return false;
+	}
+
+};
+
+static const struct regmap_range_cfg wcd934x_ifc_ranges[] = {
+	{
+		.name = "WCD9335-IFC-DEV",
+		.range_min =  0x0,
+		.range_max = 0xffff,
+		.selector_reg = 0x800,
+		.selector_mask = 0xfff,
+		.selector_shift = 0,
+		.window_start = 0x800,
+		.window_len = 0x400,
+	},
+};
+
+static struct regmap_config wcd934x_ifc_regmap_config = {
+	.reg_bits = 16,
+	.val_bits = 8,
+	.max_register = 0xffff,
+	.ranges = wcd934x_ifc_ranges,
+	.num_ranges = ARRAY_SIZE(wcd934x_ifc_ranges),
+};
+
+static struct regmap_config wcd934x_regmap_config = {
+	.reg_bits = 16,
+	.val_bits = 8,
+	.cache_type = REGCACHE_RBTREE,
+	.max_register = 0xffff,
+	.can_multi_write = true,
+	.ranges = wcd934x_ranges,
+	.num_ranges = ARRAY_SIZE(wcd934x_ranges),
+	.volatile_reg = wcd934x_is_volatile_register,
+};
+
+static int wcd934x_parse_resources(struct wcd934x_codec *wcd)
+{
+	struct device *dev = wcd->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
+	 */
+	wcd->irq = of_irq_get_byname(wcd->dev->of_node, "intr1");
+	if (wcd->irq < 0) {
+		if (wcd->irq != -EPROBE_DEFER)
+			dev_err(wcd->dev, "Unable to configure IRQ\n");
+
+		return wcd->irq;
+	}
+
+	wcd->reset_gpio = of_get_named_gpio(np,	"reset-gpios", 0);
+	if (wcd->reset_gpio < 0) {
+		dev_err(dev, "Reset gpio missing in DT\n");
+		return wcd->reset_gpio;
+	}
+
+	wcd->extclk = devm_clk_get(dev, "extclk");
+	if (IS_ERR(wcd->extclk)) {
+		dev_err(dev, "extclk not found\n");
+		return PTR_ERR(wcd->extclk);
+	}
+
+	wcd->supplies[0].supply = "vdd-buck";
+	wcd->supplies[1].supply = "vdd-buck-sido";
+	wcd->supplies[2].supply = "vdd-tx";
+	wcd->supplies[3].supply = "vdd-rx";
+	wcd->supplies[4].supply = "vdd-io";
+
+	ret = regulator_bulk_get(dev, WCD934X_MAX_SUPPLY, wcd->supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to get supplies: err = %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int wcd934x_power_on_reset(struct wcd934x_codec *wcd)
+{
+	struct device *dev = wcd->dev;
+	int ret;
+
+	ret = regulator_bulk_enable(WCD934X_MAX_SUPPLY, wcd->supplies);
+	if (ret != 0) {
+		dev_err(dev, "Failed to get supplies: err = %d\n", ret);
+		return ret;
+	}
+
+	/*
+	 * For WCD934X, 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
+	 */
+	usleep_range(600, 650);
+	gpio_direction_output(wcd->reset_gpio, 0);
+	msleep(20);
+	gpio_set_value(wcd->reset_gpio, 1);
+	msleep(20);
+
+	return 0;
+}
+
+static int wcd934x_slim_probe(struct slim_device *slim)
+{
+	struct device *dev = &slim->dev;
+	struct wcd934x_codec *wcd;
+	int ret = 0;
+
+	wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL);
+	if (!wcd)
+		return	-ENOMEM;
+
+	wcd->dev = dev;
+	ret = wcd934x_parse_resources(wcd);
+	if (ret) {
+		dev_err(dev, "Error parsing DT (%d)\n", ret);
+		return ret;
+	}
+
+	ret = wcd934x_power_on_reset(wcd);
+	if (ret) {
+		dev_err(dev, "Error Powering\n");
+		return ret;
+	}
+
+	dev_set_drvdata(dev, wcd);
+	wcd->slim = slim;
+
+	return 0;
+}
+
+static int wcd934x_bring_up(struct wcd934x_codec *wcd)
+{
+	struct regmap *wcd_regmap = wcd->regmap;
+	u16 id_minor, id_major;
+	int ret;
+
+	ret = regmap_bulk_read(wcd_regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0,
+			      (u8 *)&id_minor, sizeof(u16));
+	if (ret)
+		return -EINVAL;
+
+	ret = regmap_bulk_read(wcd_regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE2,
+			      (u8 *)&id_major, sizeof(u16));
+	if (ret)
+		return -EINVAL;
+
+	dev_info(wcd->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n",
+		 __func__, id_major, id_minor);
+
+	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x01);
+	regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_A_STARTUP, 0x19);
+	regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_D_STARTUP, 0x15);
+	/* Add 1msec delay for VOUT to settle */
+	usleep_range(1000, 1100);
+	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5);
+	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7);
+	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x3);
+	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x7);
+	regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
+
+	return 0;
+
+}
+
+static const struct regmap_irq wcd934x_irqs[] = {
+	/* INTR_REG 0 */
+	[WCD934X_IRQ_SLIMBUS] = {
+		.reg_offset = 0,
+		.mask = BIT(0),
+		.type = {
+			.type_reg_offset = 0,
+			.types_supported = IRQ_TYPE_EDGE_BOTH,
+			.type_reg_mask  = BIT(0),
+			.type_level_low_val = BIT(0),
+			.type_level_high_val = BIT(0),
+			.type_falling_val = 0,
+			.type_rising_val = 0,
+		},
+	},
+	[WCD934X_IRQ_SOUNDWIRE] = {
+		.reg_offset = 2,
+		.mask = BIT(4),
+		.type = {
+			.type_reg_offset = 2,
+			.types_supported = IRQ_TYPE_EDGE_BOTH,
+			.type_reg_mask  = BIT(4),
+		},
+	},
+};
+
+static const struct regmap_irq_chip wcd934x_regmap_irq_chip = {
+	.name = "wcd934x_irq",
+	.status_base = WCD934X_INTR_PIN1_STATUS0,
+	.mask_base = WCD934X_INTR_PIN1_MASK0,
+	.ack_base = WCD934X_INTR_PIN1_CLEAR0,
+	.type_base = WCD934X_INTR_LEVEL0,
+	.num_type_reg = 4,
+	.type_in_mask = false,
+	.num_regs = 4,
+	.irqs = wcd934x_irqs,
+	.num_irqs = ARRAY_SIZE(wcd934x_irqs),
+};
+
+static int wcd934x_slim_status(struct slim_device *sdev,
+				 enum slim_device_status status)
+{
+	struct device *dev = &sdev->dev;
+	struct device_node *ifc_dev_np;
+	struct wcd934x_codec *wcd;
+	int ret;
+
+	wcd = dev_get_drvdata(dev);
+
+	switch (status) {
+	case SLIM_DEVICE_STATUS_UP:
+		ifc_dev_np = of_parse_phandle(dev->of_node, "slim-ifc-dev", 0);
+		if (!ifc_dev_np) {
+			dev_err(dev, "No Interface device found\n");
+			return -EINVAL;
+		}
+		wcd->slim = sdev;
+		wcd->slim_ifc_dev = of_slim_get_device(sdev->ctrl, ifc_dev_np);
+		if (!wcd->slim_ifc_dev) {
+			dev_err(dev, "Unable to get SLIM Interface device\n");
+			return -EINVAL;
+		}
+
+		slim_get_logical_addr(wcd->slim_ifc_dev);
+		wcd->regmap = regmap_init_slimbus(sdev, &wcd934x_regmap_config);
+		if (IS_ERR(wcd->regmap)) {
+			dev_err(dev, "Failed to allocate slim register map\n");
+			return PTR_ERR(wcd->regmap);
+		}
+
+		wcd->if_regmap = regmap_init_slimbus(wcd->slim_ifc_dev,
+					  &wcd934x_ifc_regmap_config);
+		if (IS_ERR(wcd->if_regmap)) {
+			dev_err(dev, "Failed to allocate ifc register map\n");
+			return PTR_ERR(wcd->if_regmap);
+		}
+
+		ret = wcd934x_bring_up(wcd);
+		if (ret) {
+			dev_err(dev, "Failed to bringup WCD934X\n");
+			return ret;
+		}
+
+		ret = devm_regmap_add_irq_chip(wcd->dev, wcd->regmap,
+					       wcd->irq,
+					       IRQF_TRIGGER_HIGH, 0,
+					       &wcd934x_regmap_irq_chip,
+					       &wcd->irq_data);
+		if (ret) {
+			dev_err(wcd->dev, "Failed to register IRQ chip: %d\n",
+				ret);
+			return ret;
+		}
+
+		return wcd934x_codec_probe(wcd);
+	case SLIM_DEVICE_STATUS_DOWN:
+		of_platform_depopulate(wcd->dev);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct slim_device_id wcd934x_slim_id[] = {
+	{SLIM_MANF_ID_QCOM, SLIM_PROD_CODE_WCD9340, 0x1, 0x0},
+	{}
+};
+
+static struct slim_driver wcd934x_slim_driver = {
+	.driver = {
+		.name = "wcd934x-slim",
+	},
+	.probe = wcd934x_slim_probe,
+	.device_status = wcd934x_slim_status,
+	.id_table = wcd934x_slim_id,
+};
+
+module_slim_driver(wcd934x_slim_driver);
+MODULE_DESCRIPTION("WCD934x codec driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("slim:217:250:*");
diff --git a/sound/soc/codecs/wcd934x.h b/sound/soc/codecs/wcd934x.h
new file mode 100644
index 000000000000..b191699c6646
--- /dev/null
+++ b/sound/soc/codecs/wcd934x.h
@@ -0,0 +1,426 @@ 
+#ifndef _WCD934X_REGISTERS_H
+#define _WCD934X_REGISTERS_H
+
+#define WCD934X_CODEC_RPM_CLK_GATE				0x0002
+#define WCD934X_CODEC_RPM_CLK_MCLK_CFG				0x0003
+#define WCD934X_CODEC_RPM_CLK_MCLK_CFG_9P6MHZ			BIT(0)
+#define WCD934X_CODEC_RPM_CLK_MCLK_CFG_12P288MHZ		BIT(1)
+#define WCD934X_CODEC_RPM_CLK_MCLK_CFG_MCLK_MASK		GENMASK(1, 0)
+#define WCD934X_CODEC_RPM_RST_CTL				0x0009
+#define WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL			0x0011
+#define WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0			0x0021
+#define WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE2			0x0023
+#define WCD934X_CHIP_TIER_CTRL_EFUSE_CTL			0x0025
+#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT14			0x0037
+#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT15			0x0038
+#define WCD934X_CHIP_TIER_CTRL_EFUSE_STATUS			0x0039
+#define WCD934X_DATA_HUB_SB_TX10_INP_CFG			0x006b
+#define WCD934X_DATA_HUB_SB_TX11_INP_CFG			0x006c
+#define WCD934X_DATA_HUB_SB_TX13_INP_CFG			0x006e
+#define WCD934X_CPE_FLL_CONFIG_CTL_2				0x0111
+#define WCD934X_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD		0x0213
+#define WCD934X_CPE_SS_SVA_CFG					0x0214
+#define WCD934X_CPE_SS_DMIC0_CTL				0x0218
+#define WCD934X_CPE_SS_DMIC1_CTL				0x0219
+#define WCD934X_CPE_SS_DMIC2_CTL				0x021a
+#define WCD934X_CPE_SS_DMIC_CFG					0x021b
+#define WCD934X_CPE_SS_DMIC_CFG					0x021b
+#define WCD934X_CPE_SS_CPAR_CFG					0x021c
+#define WCD934X_INTR_PIN1_MASK0					0x0409
+#define WCD934X_INTR_PIN1_STATUS0				0x0411
+#define WCD934X_INTR_PIN1_CLEAR0				0x0419
+#define WCD934X_INTR_PIN2_CLEAR3				0x0434
+#define WCD934X_INTR_LEVEL0					0x0461
+/* INTR_REG 0 */
+#define	WCD934X_IRQ_SLIMBUS			0
+#define	WCD934X_IRQ_MISC			1
+#define	WCD934X_IRQ_HPH_PA_OCPL_FAULT		2
+#define	WCD934X_IRQ_HPH_PA_OCPR_FAULT		3
+#define	WCD934X_IRQ_EAR_PA_OCP_FAULT		4
+#define	WCD934X_IRQ_HPH_PA_CNPL_COMPLETE	5
+#define	WCD934X_IRQ_HPH_PA_CNPR_COMPLETE	6
+#define	WCD934X_IRQ_EAR_PA_CNP_COMPLETE		7
+/* INTR_REG 1 */
+#define	WCD934X_IRQ_MBHC_SW_DET			8
+#define	WCD934X_IRQ_MBHC_ELECT_INS_REM_DET	9
+#define	WCD934X_IRQ_MBHC_BUTTON_PRESS_DET	10
+#define	WCD934X_IRQ_MBHC_BUTTON_RELEASE_DET	11
+#define	WCD934X_IRQ_MBHC_ELECT_INS_REM_LEG_DET	12
+#define	WCD934X_IRQ_RESERVED_0			13
+#define	WCD934X_IRQ_RESERVED_1			14
+#define	WCD934X_IRQ_RESERVED_2			15
+/* INTR_REG 2 */
+#define	WCD934X_IRQ_LINE_PA1_CNP_COMPLETE	16
+#define	WCD934X_IRQ_LINE_PA2_CNP_COMPLETE	17
+#define	WCD934X_IRQ_SLNQ_ANALOG_ERROR		18
+#define	WCD934X_IRQ_RESERVED_3			19
+#define	WCD934X_IRQ_SOUNDWIRE			20
+#define	WCD934X_IRQ_VDD_DIG_RAMP_COMPLETE	21
+#define	WCD934X_IRQ_RCO_ERROR			22
+#define	WCD934X_IRQ_CPE_ERROR			23
+/* INTR_REG 3 */
+#define	WCD934X_IRQ_MAD_AUDIO			24
+#define	WCD934X_IRQ_MAD_BEACON			25
+#define	WCD934X_IRQ_MAD_ULTRASOUND		26
+#define	WCD934X_IRQ_VBAT_ATTACK			27
+#define	WCD934X_IRQ_VBAT_RESTORE		28
+#define	WCD934X_IRQ_CPE1_INTR			29
+#define	WCD934X_IRQ_RESERVED_4			30
+#define	WCD934X_IRQ_SLNQ_DIGITAL		31
+#define WCD934X_NUM_IRQS			32
+#define WCD934X_ANA_BIAS					0x0601
+#define WCD934X_ANA_RCO						0x0603
+#define WCD934X_ANA_BUCK_CTL					0x0606
+#define WCD934X_ANA_RX_SUPPLIES					0x0608
+#define WCD934X_ANA_HPH						0x0609
+#define WCD934X_ANA_EAR						0x060a
+#define WCD934X_ANA_LO_1_2					0x060b
+#define WCD934X_ANA_AMIC1					0x060e
+#define WCD934X_ANA_AMIC2					0x060f
+#define WCD934X_ANA_AMIC3					0x0610
+#define WCD934X_ANA_AMIC4					0x0611
+#define WCD934X_ANA_MBHC_MECH					0x0614
+#define WCD934X_ANA_MBHC_ELECT					0x0615
+#define WCD934X_ANA_MBHC_ZDET					0x0616
+#define WCD934X_ANA_MBHC_RESULT_1				0x0617
+#define WCD934X_ANA_MBHC_RESULT_2				0x0618
+#define WCD934X_ANA_MBHC_RESULT_3				0x0619
+#define WCD934X_ANA_MICB1					0x0622
+#define WCD934X_MICB_VAL_MASK					GENMASK(5, 0)
+#define WCD934X_ANA_MICB2					0x0623
+#define WCD934X_ANA_MICB3					0x0625
+#define WCD934X_ANA_MICB4					0x0626
+#define WCD934X_BIAS_VBG_FINE_ADJ				0x0629
+#define WCD934X_MICB1_TEST_CTL_1				0x066b
+#define WCD934X_MICB1_TEST_CTL_2				0x066c
+#define WCD934X_MICB2_TEST_CTL_1				0x066e
+#define WCD934X_MICB3_TEST_CTL_1				0x0671
+#define WCD934X_MICB4_TEST_CTL_1				0x0674
+#define WCD934X_CLASSH_MODE_1					0x0697
+#define WCD934X_CLASSH_MODE_2					0x0698
+#define WCD934X_CLASSH_MODE_3					0x0699
+#define WCD934X_CLASSH_CTRL_VCL_1				0x069a
+#define WCD934X_CLASSH_CTRL_VCL_2				0x069b
+#define WCD934X_CLASSH_CTRL_CCL_1				0x069c
+#define WCD934X_CLASSH_CTRL_CCL_2				0x069d
+#define WCD934X_CLASSH_CTRL_CCL_3				0x069e
+#define WCD934X_CLASSH_CTRL_CCL_4				0x069f
+#define WCD934X_CLASSH_CTRL_CCL_5				0x06a0
+#define WCD934X_CLASSH_BUCK_TMUX_A_D				0x06a1
+#define WCD934X_CLASSH_BUCK_SW_DRV_CNTL				0x06a2
+#define WCD934X_RX_OCP_CTL					0x06b6
+#define WCD934X_RX_OCP_COUNT					0x06b7
+#define WCD934X_HPH_CNP_EN					0x06cb
+#define WCD934X_HPH_CNP_WG_CTL					0x06cc
+#define WCD934X_HPH_OCP_CTL					0x06ce
+#define WCD934X_HPH_L_EN					0x06d3
+#define WCD934X_HPH_GAIN_SRC_SEL_MASK				BIT(5)
+#define WCD934X_HPH_GAIN_SRC_SEL_COMPANDER			0
+#define WCD934X_HPH_GAIN_SRC_SEL_REGISTER			BIT(5)
+#define WCD934X_HPH_L_TEST					0x06d4
+#define WCD934X_HPH_R_EN					0x06d6
+#define WCD934X_HPH_R_TEST					0x06d7
+#define WCD934X_DIFF_LO_LO2_COMPANDER				0x06ea
+#define WCD934X_DIFF_LO_LO1_COMPANDER				0x06eb
+#define WCD934X_CLK_SYS_MCLK_PRG				0x0711
+#define WCD934X_CLK_SYS_MCLK2_PRG1				0x0712
+#define WCD934X_CLK_SYS_MCLK2_PRG2				0x0713
+#define WCD934X_SIDO_NEW_VOUT_A_STARTUP				0x071b
+#define WCD934X_SIDO_NEW_VOUT_D_STARTUP				0x071c
+#define WCD934X_SIDO_NEW_VOUT_D_FREQ1				0x071d
+#define WCD934X_SIDO_NEW_VOUT_D_FREQ2				0x071e
+#define WCD934X_MBHC_NEW_CTL_2					0x0721
+#define WCD934X_TX_NEW_AMIC_4_5_SEL				0x0727
+#define WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_L			0x0733
+#define WCD934X_HPH_NEW_INT_RDAC_OVERRIDE_CTL			0x0735
+#define WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_R			0x0736
+#define WCD934X_HPH_NEW_INT_HPH_TIMER1				0x073a
+#define WCD934X_CDC_TX0_TX_PATH_CTL				0x0a31
+#define WCD934X_CDC_TX_PATH_CTL_PCM_RATE_MASK			GENMASK(3, 0)
+#define WCD934X_CDC_TX_PATH_CTL(dec)				(0xa31 + dec * 0x10)
+#define WCD934X_CDC_TX0_TX_PATH_CFG0				0x0a32
+#define WCD934X_CDC_TX0_TX_PATH_CFG1				0x0a33
+#define WCD934X_CDC_TX0_TX_VOL_CTL				0x0a34
+#define WCD934X_CDC_TX0_TX_PATH_192_CTL				0x0a35
+#define WCD934X_CDC_TX0_TX_PATH_192_CFG				0x0a36
+#define WCD934X_CDC_TX0_TX_PATH_SEC2				0x0a39
+#define WCD934X_CDC_TX1_TX_PATH_CTL				0x0a41
+#define WCD934X_CDC_TX1_TX_PATH_CFG0				0x0a42
+#define WCD934X_CDC_TX1_TX_PATH_CFG1				0x0a43
+#define WCD934X_CDC_TX1_TX_VOL_CTL				0x0a44
+#define WCD934X_CDC_TX2_TX_PATH_CTL				0x0a51
+#define WCD934X_CDC_TX2_TX_PATH_CFG0				0x0a52
+#define WCD934X_CDC_TX2_TX_PATH_CFG1				0x0a53
+#define WCD934X_CDC_TX2_TX_VOL_CTL				0x0a54
+#define WCD934X_CDC_TX3_TX_PATH_CTL				0x0a61
+#define WCD934X_CDC_TX3_TX_PATH_CFG0				0x0a62
+#define WCD934X_CDC_TX3_TX_PATH_CFG1				0x0a63
+#define WCD934X_CDC_TX3_TX_VOL_CTL				0x0a64
+#define WCD934X_CDC_TX3_TX_PATH_192_CTL				0x0a65
+#define WCD934X_CDC_TX3_TX_PATH_192_CFG				0x0a66
+#define WCD934X_CDC_TX4_TX_PATH_CTL				0x0a71
+#define WCD934X_CDC_TX4_TX_PATH_CFG0				0x0a72
+#define WCD934X_CDC_TX4_TX_PATH_CFG1				0x0a73
+#define WCD934X_CDC_TX4_TX_VOL_CTL				0x0a74
+#define WCD934X_CDC_TX4_TX_PATH_192_CTL				0x0a75
+#define WCD934X_CDC_TX4_TX_PATH_192_CFG				0x0a76
+#define WCD934X_CDC_TX5_TX_PATH_CTL				0x0a81
+#define WCD934X_CDC_TX5_TX_PATH_CFG0				0x0a82
+#define WCD934X_CDC_TX5_TX_PATH_CFG1				0x0a83
+#define WCD934X_CDC_TX5_TX_VOL_CTL				0x0a84
+#define WCD934X_CDC_TX5_TX_PATH_192_CTL				0x0a85
+#define WCD934X_CDC_TX5_TX_PATH_192_CFG				0x0a86
+#define WCD934X_CDC_TX6_TX_PATH_CTL				0x0a91
+#define WCD934X_CDC_TX6_TX_PATH_CFG0				0x0a92
+#define WCD934X_CDC_TX6_TX_PATH_CFG1				0x0a93
+#define WCD934X_CDC_TX6_TX_VOL_CTL				0x0a94
+#define WCD934X_CDC_TX6_TX_PATH_192_CTL				0x0a95
+#define WCD934X_CDC_TX6_TX_PATH_192_CFG				0x0a96
+#define WCD934X_CDC_TX7_TX_PATH_CTL				0x0aa1
+#define WCD934X_CDC_TX7_TX_PATH_CFG0				0x0aa2
+#define WCD934X_CDC_TX7_TX_PATH_CFG1				0x0aa3
+#define WCD934X_CDC_TX7_TX_VOL_CTL				0x0aa4
+#define WCD934X_CDC_TX7_TX_PATH_192_CTL				0x0aa5
+#define WCD934X_CDC_TX7_TX_PATH_192_CFG				0x0aa6
+#define WCD934X_CDC_TX8_TX_PATH_CTL				0x0ab1
+#define WCD934X_CDC_TX8_TX_PATH_CFG0				0x0ab2
+#define WCD934X_CDC_TX8_TX_PATH_CFG1				0x0ab3
+#define WCD934X_CDC_TX8_TX_VOL_CTL				0x0ab4
+#define WCD934X_CDC_TX8_TX_PATH_192_CTL				0x0ab5
+#define WCD934X_CDC_TX8_TX_PATH_192_CFG				0x0ab6
+#define WCD934X_CDC_TX9_SPKR_PROT_PATH_CFG0			0x0ac3
+#define WCD934X_CDC_TX10_SPKR_PROT_PATH_CFG0			0x0ac7
+#define WCD934X_CDC_TX11_SPKR_PROT_PATH_CFG0			0x0acb
+#define WCD934X_CDC_TX12_SPKR_PROT_PATH_CFG0			0x0acf
+#define WCD934X_CDC_COMPANDER1_CTL0				0x0b01
+#define WCD934X_CDC_COMPANDER1_CTL7				0x0b08
+#define WCD934X_CDC_COMPANDER2_CTL7				0x0b10
+#define WCD934X_CDC_COMPANDER7_CTL3				0x0b34
+#define WCD934X_CDC_COMPANDER7_CTL7				0x0b38
+#define WCD934X_CDC_COMPANDER8_CTL3				0x0b3c
+#define WCD934X_CDC_COMPANDER8_CTL7				0x0b40
+#define WCD934X_CDC_RX0_RX_PATH_CTL				0x0b41
+#define WCD934X_CDC_RX_PGA_MUTE_EN_MASK				BIT(4)
+#define WCD934X_CDC_RX_PGA_MUTE_ENABLE				BIT(4)
+#define WCD934X_CDC_RX_PGA_MUTE_DISABLE				0
+#define WCD934X_CDC_RX_PATH_CTL(rx)				(0xb41 + rx * 0x14)
+#define WCD934X_CDC_MIX_PCM_RATE_MASK				GENMASK(3, 0)
+#define WCD934X_CDC_RX0_RX_PATH_CFG0				0x0b42
+#define WCD934X_CDC_RX0_RX_PATH_CFG1				0x0b43
+#define WCD934X_CDC_RX0_RX_PATH_CFG2				0x0b44
+#define WCD934X_CDC_RX0_RX_VOL_CTL				0x0b45
+#define WCD934X_CDC_RX0_RX_PATH_MIX_CTL				0x0b46
+#define WCD934X_CDC_RX_PATH_MIX_CTL(rx)				(0xb46 + rx * 0x14)
+#define WCD934X_CDC_RX0_RX_PATH_MIX_CFG				0x0b47
+#define WCD934X_CDC_RX0_RX_VOL_MIX_CTL				0x0b48
+#define WCD934X_CDC_RX0_RX_PATH_SEC0				0x0b49
+#define WCD934X_CDC_RX0_RX_PATH_DSMDEM_CTL			0x0b53
+#define WCD934X_CDC_RX1_RX_PATH_CTL				0x0b55
+#define WCD934X_CDC_RX1_RX_PATH_CFG0				0x0b56
+#define WCD934X_CDC_RX1_RX_PATH_CFG2				0x0b58
+#define WCD934X_CDC_RX1_RX_VOL_CTL				0x0b59
+#define WCD934X_CDC_RX1_RX_PATH_MIX_CTL				0x0b5a
+#define WCD934X_CDC_RX1_RX_PATH_MIX_CFG				0x0b5b
+#define WCD934X_CDC_RX1_RX_VOL_MIX_CTL				0x0b5c
+#define WCD934X_CDC_RX1_RX_PATH_SEC0				0x0b5d
+#define WCD934X_CDC_RX1_RX_PATH_SEC3				0x0b60
+#define WCD934X_CDC_RX_PATH_SEC_HD2_ALPHA_MASK			GENMASK(5, 2)
+#define WCD934X_CDC_RX_PATH_SEC_HD2_ALPHA_0P3125		0x14
+#define WCD934X_CDC_RX_PATH_SEC_HD2_ALPHA_0P0000		0
+#define WCD934X_CDC_RX1_RX_PATH_DSMDEM_CTL			0x0b67
+#define WCD934X_CDC_RX2_RX_PATH_CTL				0x0b69
+#define WCD934X_CDC_RX2_RX_PATH_CFG0				0x0b6a
+#define WCD934X_CDC_RX_PATH_CFG_HD2_EN_MASK			BIT(2)
+#define WCD934X_CDC_RX_PATH_CFG_HD2_ENABLE			BIT(2)
+#define WCD934X_CDC_RX_PATH_CFG_HD2_DISABLE			0
+#define WCD934X_CDC_RX2_RX_PATH_CFG2				0x0b6c
+#define WCD934X_CDC_RX2_RX_VOL_CTL				0x0b6d
+#define WCD934X_CDC_RX2_RX_PATH_MIX_CTL				0x0b6e
+#define WCD934X_CDC_RX2_RX_PATH_MIX_CFG				0x0b6f
+#define WCD934X_CDC_RX2_RX_VOL_MIX_CTL				0x0b70
+#define WCD934X_CDC_RX2_RX_PATH_SEC0				0x0b71
+#define WCD934X_CDC_RX2_RX_PATH_SEC3				0x0b74
+#define WCD934X_CDC_RX2_RX_PATH_DSMDEM_CTL			0x0b7b
+#define WCD934X_CDC_RX3_RX_PATH_CTL				0x0b7d
+#define WCD934X_CDC_RX3_RX_PATH_CFG2				0x0b80
+#define WCD934X_CDC_RX3_RX_VOL_CTL				0x0b81
+#define WCD934X_CDC_RX3_RX_PATH_MIX_CTL				0x0b82
+#define WCD934X_CDC_RX3_RX_PATH_MIX_CFG				0x0b83
+#define WCD934X_CDC_RX3_RX_VOL_MIX_CTL				0x0b84
+#define WCD934X_CDC_RX3_RX_PATH_SEC0				0x0b85
+#define WCD934X_CDC_RX3_RX_PATH_DSMDEM_CTL			0x0b8f
+#define WCD934X_CDC_RX4_RX_PATH_CTL				0x0b91
+#define WCD934X_CDC_RX4_RX_PATH_CFG2				0x0b94
+#define WCD934X_CDC_RX4_RX_VOL_CTL				0x0b95
+#define WCD934X_CDC_RX4_RX_PATH_MIX_CTL				0x0b96
+#define WCD934X_CDC_RX4_RX_PATH_MIX_CFG				0x0b97
+#define WCD934X_CDC_RX4_RX_VOL_MIX_CTL				0x0b98
+#define WCD934X_CDC_RX4_RX_PATH_SEC0				0x0b99
+#define WCD934X_CDC_RX4_RX_PATH_DSMDEM_CTL			0x0ba3
+#define WCD934X_CDC_RX7_RX_PATH_CTL				0x0bcd
+#define WCD934X_CDC_RX7_RX_PATH_CFG1				0x0bcf
+#define WCD934X_CDC_RX7_RX_PATH_CFG2				0x0bd0
+#define WCD934X_CDC_RX7_RX_VOL_CTL				0x0bd1
+#define WCD934X_CDC_RX7_RX_PATH_MIX_CTL				0x0bd2
+#define WCD934X_CDC_RX7_RX_PATH_MIX_CFG				0x0bd3
+#define WCD934X_CDC_RX7_RX_VOL_MIX_CTL				0x0bd4
+#define WCD934X_CDC_RX7_RX_PATH_SEC1				0x0bd6
+#define WCD934X_CDC_RX7_RX_PATH_MIX_SEC0			0x0bdd
+#define WCD934X_CDC_RX7_RX_PATH_DSMDEM_CTL			0x0bdf
+#define WCD934X_CDC_RX8_RX_PATH_CTL				0x0be1
+#define WCD934X_CDC_RX8_RX_PATH_CFG1				0x0be3
+#define WCD934X_CDC_RX8_RX_PATH_CFG2				0x0be4
+#define WCD934X_CDC_RX8_RX_VOL_CTL				0x0be5
+#define WCD934X_CDC_RX8_RX_PATH_MIX_CTL				0x0be6
+#define WCD934X_CDC_RX8_RX_PATH_MIX_CFG				0x0be7
+#define WCD934X_CDC_RX8_RX_VOL_MIX_CTL				0x0be8
+#define WCD934X_CDC_RX8_RX_PATH_SEC1				0x0bea
+#define WCD934X_CDC_RX8_RX_PATH_MIX_SEC0			0x0bf1
+#define WCD934X_CDC_RX8_RX_PATH_DSMDEM_CTL			0x0bf3
+
+#define WCD934X_CDC_CLSH_DECAY_CTRL				0x0c03
+#define WCD934X_CDC_CLSH_K2_MSB					0x0c0a
+#define WCD934X_CDC_CLSH_K2_LSB					0x0c0b
+#define WCD934X_CDC_CLSH_TEST0					0x0c0f
+#define WCD934X_CDC_BOOST0_BOOST_PATH_CTL			0x0c19
+#define WCD934X_CDC_BOOST0_BOOST_CTL				0x0c1a
+#define WCD934X_CDC_BOOST0_BOOST_CFG1				0x0c1b
+#define WCD934X_CDC_BOOST0_BOOST_CFG2				0x0c1c
+#define WCD934X_CDC_BOOST1_BOOST_PATH_CTL			0x0c21
+#define WCD934X_CDC_BOOST1_BOOST_CTL				0x0c22
+#define WCD934X_CDC_BOOST1_BOOST_CFG1				0x0c23
+#define WCD934X_CDC_BOOST1_BOOST_CFG2				0x0c24
+#define WCD934X_SWR_AHB_BRIDGE_RD_DATA_0			0x0c91
+#define WCD934X_SWR_AHB_BRIDGE_RD_DATA_3			0x0c94
+#define WCD934X_SWR_AHB_BRIDGE_ACCESS_STATUS			0x0c96
+#define WCD934X_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL		0x0cb5
+#define WCD934X_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL		0x0cb9
+#define WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG0			0x0d01
+#define WCD934X_CDC_RX_INP_MUX_RX_INT_CFG0(i)		(0xd01 + i * 0x2)
+#define WCD934X_CDC_RX_INP_MUX_RX_INT_SEL_MASK			GENMASK(3, 0)
+#define WCD934X_CDC_RX_INP_MUX_RX_INT0_CFG1			0x0d02
+#define WCD934X_CDC_RX_INP_MUX_RX_INT_CFG1(i)		(0xd02 + i * 0x2)
+#define WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG0			0x0d03
+#define WCD934X_CDC_RX_INP_MUX_RX_INT1_CFG1			0x0d04
+#define WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG0			0x0d05
+#define WCD934X_CDC_RX_INP_MUX_RX_INT2_CFG1			0x0d06
+#define WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG0			0x0d07
+#define WCD934X_CDC_RX_INP_MUX_RX_INT3_CFG1			0x0d08
+#define WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG0			0x0d09
+#define WCD934X_CDC_RX_INP_MUX_RX_INT4_CFG1			0x0d0a
+#define WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG0			0x0d0f
+#define WCD934X_CDC_RX_INP_MUX_RX_INT7_CFG1			0x0d10
+#define WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG0			0x0d11
+#define WCD934X_CDC_RX_INP_MUX_RX_INT8_CFG1			0x0d12
+#define WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG0			0x0d13
+#define WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG1			0x0d14
+#define WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG2			0x0d15
+#define WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG3			0x0d16
+#define WCD934X_CDC_RX_INP_MUX_RX_MIX_CFG4			0x0d17
+#define WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0		0x0d18
+#define WCD934X_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1		0x0d19
+#define WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0			0x0d1d
+#define WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG1			0x0d1e
+#define WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG0			0x0d1f
+#define WCD934X_CDC_TX_INP_MUX_ADC_MUX1_CFG1			0x0d20
+#define WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG0			0x0d21
+#define WCD934X_CDC_TX_INP_MUX_ADC_MUX2_CFG1			0x0d22
+#define WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG0			0x0d23
+#define WCD934X_CDC_TX_INP_MUX_ADC_MUX3_CFG1			0x0d25
+#define WCD934X_CDC_TX_INP_MUX_ADC_MUX4_CFG0			0x0d26
+#define WCD934X_CDC_TX_INP_MUX_ADC_MUX5_CFG0			0x0d27
+#define WCD934X_CDC_TX_INP_MUX_ADC_MUX6_CFG0			0x0d28
+#define WCD934X_CDC_TX_INP_MUX_ADC_MUX7_CFG0			0x0d29
+#define WCD934X_CDC_TX_INP_MUX_ADC_MUX8_CFG0			0x0d2a
+#define WCD934X_CDC_TX_INP_MUX_ADC_MUX10_CFG0			0x0d2b
+#define WCD934X_CDC_TX_INP_MUX_ADC_MUX11_CFG0			0x0d2c
+#define WCD934X_CDC_TX_INP_MUX_ADC_MUX12_CFG0			0x0d2d
+#define WCD934X_CDC_TX_INP_MUX_ADC_MUX13_CFG0			0x0d2e
+#define WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0		0x0d31
+#define WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1		0x0d32
+#define WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2		0x0d33
+#define WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3		0x0d34
+#define WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0		0x0d35
+#define WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1		0x0d36
+#define WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2		0x0d37
+#define WCD934X_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3		0x0d38
+#define WCD934X_CDC_IF_ROUTER_TX_MUX_CFG0			0x0d3a
+#define WCD934X_CDC_IF_ROUTER_TX_MUX_CFG1			0x0d3b
+#define WCD934X_CDC_IF_ROUTER_TX_MUX_CFG2			0x0d3c
+#define WCD934X_CDC_IF_ROUTER_TX_MUX_CFG3			0x0d3d
+#define WCD934X_CDC_CLK_RST_CTRL_MCLK_CONTROL			0x0d41
+#define WCD934X_CDC_CLK_RST_CTRL_FS_CNT_CONTROL			0x0d42
+#define WCD934X_CDC_CLK_RST_CTRL_SWR_CONTROL			0x0d43
+#define WCD934X_CDC_CLK_RST_CTRL_DSD_CONTROL			0x0d44
+#define WCD934X_CDC_CLK_RST_CTRL_ASRC_SHARE_CONTROL		0x0d45
+#define WCD934X_CDC_CLK_RST_CTRL_GFM_CONTROL			0x0d46
+#define WCD934X_CDC_SIDETONE_IIR0_IIR_PATH_CTL			0x0d55
+#define WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL		0x0d56
+#define WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL		0x0d57
+#define WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL		0x0d58
+#define WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL		0x0d59
+#define WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B5_CTL		0x0d5a
+#define WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B6_CTL		0x0d5b
+#define WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B7_CTL		0x0d5c
+#define WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_B8_CTL		0x0d5d
+#define WCD934X_CDC_SIDETONE_IIR0_IIR_CTL			0x0d5e
+#define WCD934X_CDC_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL		0x0d5f
+#define WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL		0x0d60
+#define WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL		0x0d61
+#define WCD934X_CDC_SIDETONE_IIR1_IIR_PATH_CTL			0x0d65
+#define WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL		0x0d66
+#define WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL		0x0d67
+#define WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL		0x0d68
+#define WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL		0x0d69
+#define WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B5_CTL		0x0d6a
+#define WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B6_CTL		0x0d6b
+#define WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B7_CTL		0x0d6c
+#define WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B8_CTL		0x0d6d
+#define WCD934X_CDC_SIDETONE_IIR1_IIR_CTL			0x0d6e
+#define WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL		0x0d6f
+#define WCD934X_CDC_SIDETONE_IIR1_IIR_COEF_B1_CTL		0x0d70
+#define WCD934X_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL		0x0d71
+#define WCD934X_CDC_TOP_TOP_CFG1				0x0d82
+#define WCD934X_CDC_TOP_TOP_CFG7				0x0d88
+#define WCD934X_CDC_TOP_HPHL_COMP_LUT				0x0d8b
+#define WCD934X_CDC_TOP_HPHR_COMP_LUT				0x0d90
+#define WCD934X_CODEC_CPR_WR_DATA_0				0x5001
+#define WCD934X_CODEC_CPR_WR_ADDR_0				0x5005
+#define WCD934X_CODEC_CPR_SVS_CX_VDD				0x5022
+#define WCD934X_CODEC_CPR_SVS2_CX_VDD				0x5023
+#define WCD934X_CODEC_CPR_SVS2_MIN_CX_VDD			0x5027
+#define WCD934X_TLMM_DMIC1_CLK_PINCFG				0x8015
+#define WCD934X_TLMM_DMIC1_DATA_PINCFG				0x8016
+#define WCD934X_TLMM_DMIC2_CLK_PINCFG				0x8017
+#define WCD934X_TLMM_DMIC2_DATA_PINCFG				0x8018
+#define WCD934X_TLMM_DMIC3_CLK_PINCFG				0x8019
+#define WCD934X_TLMM_DMIC3_DATA_PINCFG				0x801a
+#define WCD934X_TEST_DEBUG_PAD_DRVCTL_0				0x803b
+#define WCD934X_TEST_DEBUG_NPL_DLY_TEST_1			0x803e
+
+/* SLIMBUS Slave Registers */
+#define WCD934X_SLIM_PGD_PORT_INT_EN0				0x30
+#define WCD934X_SLIM_PGD_PORT_INT_STATUS_RX_0			0x34
+#define WCD934X_SLIM_PGD_PORT_INT_STATUS_RX_1			0x35
+#define WCD934X_SLIM_PGD_PORT_INT_STATUS_TX_0			0x36
+#define WCD934X_SLIM_PGD_PORT_INT_STATUS_TX_1			0x37
+#define WCD934X_SLIM_PGD_PORT_INT_CLR_RX_0			0x38
+#define WCD934X_SLIM_PGD_PORT_INT_CLR_RX_1			0x39
+#define WCD934X_SLIM_PGD_PORT_INT_CLR_TX_0			0x3A
+#define WCD934X_SLIM_PGD_PORT_INT_CLR_TX_1			0x3B
+#define WCD934X_SLIM_PGD_PORT_INT_RX_SOURCE0			0x60
+#define WCD934X_SLIM_PGD_PORT_INT_TX_SOURCE0			0x70
+#define WCD934X_SLIM_PGD_RX_PORT_CFG(p)				(0x30 + p)
+#define WCD934X_SLIM_PGD_PORT_CFG(p)				(0x40 + p)
+#define WCD934X_SLIM_PGD_TX_PORT_CFG(p)				(0x50 + p)
+#define WCD934X_SLIM_PGD_PORT_INT_SRC(p)			(0x60 + p)
+#define WCD934X_SLIM_PGD_PORT_INT_STATUS(p)			(0x80 + p)
+#define WCD934X_SLIM_PGD_TX_PORT_MULTI_CHNL_0(p)		(0x100 + 4 * p)
+/* ports range from 10-16 */
+#define WCD934X_SLIM_PGD_TX_PORT_MULTI_CHNL_1(p)		(0x101 + 4 * p)
+#define WCD934X_SLIM_PGD_RX_PORT_MULTI_CHNL_0(p)		(0x140 + 4 * p)
+
+#define SLIM_MANF_ID_QCOM			0x217
+#define SLIM_PROD_CODE_WCD9340			0x250
+
+#endif