Re: [PATCH v2 1/2] ASoC: codec: Inno codec driver for RK3036 SoC

2015-11-06 Thread Mark Brown
On Fri, Nov 06, 2015 at 04:15:37PM +0800, Shunqian Zheng wrote:
> On 2015年11月06日 00:13, Mark Brown wrote:
> >On Thu, Nov 05, 2015 at 05:53:13PM +0800, Shunqian Zheng wrote:

> >This looks like a simple boolean control rather than an enum - it looks
> >like it's just turning antipop on and off.

> It is a boolean control, but it takes 2 bits -- the value of "on" is b10 and
> b01 for "off".
> So I try to use VALUE_ENUM.

The presentation of the control to userspace needs to be a Switch, this
is probably going to need you to code something custom.


signature.asc
Description: PGP signature


Re: [PATCH v2 1/2] ASoC: codec: Inno codec driver for RK3036 SoC

2015-11-06 Thread Shunqian Zheng

Mark,

On 2015年11月06日 00:13, Mark Brown wrote:

On Thu, Nov 05, 2015 at 05:53:13PM +0800, Shunqian Zheng wrote:

This is basically all good, a few very minor comments below but nothing
that should take any time to fix.


+static const char *rk3036_codec_antipop_text[] = {"none", "work"};
+static const unsigned int rk3036_codec_antipop_values[] = {0x1, 0x2};
+
+static SOC_VALUE_ENUM_DOUBLE_DECL(rk3036_codec_antipop_enum, INNO_R09,
+   INNO_R09_HPL_ANITPOP_SHIFT, INNO_R09_HPR_ANITPOP_SHIFT, 0x3,
+   rk3036_codec_antipop_text, rk3036_codec_antipop_values);

This looks like a simple boolean control rather than an enum - it looks
like it's just turning antipop on and off.
It is a boolean control, but it takes 2 bits -- the value of "on" is b10 
and b01 for "off".

So I try to use VALUE_ENUM.




+   SOC_DOUBLE_R_RANGE_TLV("Headphone Volume", INNO_R07, INNO_R08,
+   INNO_HP_GAIN_SHIFT, INNO_HP_GAIN_N39DB,
+   INNO_HP_GAIN_0DB, 0, rk3036_codec_hp_tlv),
+   SOC_DOUBLE("Zero Cross Detect", INNO_R06, INNO_R06_VOUTL_CZ_SHIFT,
+   INNO_R06_VOUTR_CZ_SHIFT, 1, 0),

This should be "Zero Cross Switch".

Make change in V3.



+   SOC_DOUBLE("HP Mute", INNO_R09, INNO_R09_HPL_MUTE_SHIFT,
+   INNO_R09_HPR_MUTE_SHIFT, 1, 1),

This should be "Headphone Switch".

Make change in V3.



+static int rk3036_codec_add_widgets(struct snd_soc_codec *codec)
+{
+   struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+
+   snd_soc_add_codec_controls(codec, rk3036_codec_dapm_controls,
+   ARRAY_SIZE(rk3036_codec_dapm_controls));
+
+   snd_soc_dapm_new_controls(dapm, rk3036_codec_dapm_widgets,
+   ARRAY_SIZE(rk3036_codec_dapm_widgets));
+
+   snd_soc_dapm_add_routes(dapm, rk3036_codec_dapm_routes,
+   ARRAY_SIZE(rk3036_codec_dapm_routes));

Just point at the tables from the driver structure and let the core do
the initialisation for you.

Make change in V3.



+static int rk3036_codec_set_bias_level(struct snd_soc_codec *codec,
+  enum snd_soc_bias_level level)
+{
+   switch (level) {
+   case SND_SOC_BIAS_STANDBY:
+   /* set a big current for capacitor charging. */
+   snd_soc_write(codec, INNO_R10, INNO_R10_MAX_CUR);
+   /* start precharge */
+   snd_soc_write(codec, INNO_R06, INNO_R06_DAC_PRECHARGE);

Do we not need to wait for this to ramp?

The datasheet didn't give the delay value. It works in my tests.

Thank you,
Shunqian


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2 1/2] ASoC: codec: Inno codec driver for RK3036 SoC

2015-11-06 Thread Shunqian Zheng

LABBE,


On 2015年11月05日 20:47, LABBE Corentin wrote:

On Thu, Nov 05, 2015 at 05:53:13PM +0800, Shunqian Zheng wrote:

From: ZhengShunQian 

RK3036 SoC integrated with an Inno audio codec.
This driver implements the functions of it.

There is not need a special machine driver, since the
simple-card machine driver works perfect in this case.

Signed-off-by: ZhengShunQian 
---
  sound/soc/codecs/Kconfig   |   4 +
  sound/soc/codecs/Makefile  |   2 +
  sound/soc/codecs/inno_rk3036.c | 455 +
  sound/soc/codecs/inno_rk3036.h | 120 +++
  4 files changed, 581 insertions(+)
  create mode 100644 sound/soc/codecs/inno_rk3036.c
  create mode 100644 sound/soc/codecs/inno_rk3036.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index cfdafc4..89d789e 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -67,6 +67,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ES8328_I2C if I2C
select SND_SOC_GTM601
select SND_SOC_ICS43432
+   select SND_SOC_INNO_RK3036
select SND_SOC_ISABELLE if I2C
select SND_SOC_JZ4740_CODEC
select SND_SOC_LM4857 if I2C
@@ -471,6 +472,9 @@ config SND_SOC_GTM601
  config SND_SOC_ICS43432
tristate
  
+config SND_SOC_INNO_RK3036

+   tristate "Inno codec driver for RK3036 SoC"
+
  config SND_SOC_ISABELLE
  tristate
  
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile

index f632fc4..2f6bc6c 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -60,6 +60,7 @@ snd-soc-es8328-i2c-objs := es8328-i2c.o
  snd-soc-es8328-spi-objs := es8328-spi.o
  snd-soc-gtm601-objs := gtm601.o
  snd-soc-ics43432-objs := ics43432.o
+snd-soc-inno-rk3036-objs := inno_rk3036.o
  snd-soc-isabelle-objs := isabelle.o
  snd-soc-jz4740-codec-objs := jz4740.o
  snd-soc-l3-objs := l3.o
@@ -255,6 +256,7 @@ obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
  obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
  obj-$(CONFIG_SND_SOC_GTM601)+= snd-soc-gtm601.o
  obj-$(CONFIG_SND_SOC_ICS43432)+= snd-soc-ics43432.o
+obj-$(CONFIG_SND_SOC_INNO_RK3036)  += snd-soc-inno-rk3036.o
  obj-$(CONFIG_SND_SOC_ISABELLE)+= snd-soc-isabelle.o
  obj-$(CONFIG_SND_SOC_JZ4740_CODEC)+= snd-soc-jz4740-codec.o
  obj-$(CONFIG_SND_SOC_L3)  += snd-soc-l3.o
diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c
new file mode 100644
index 000..ce68f02
--- /dev/null
+++ b/sound/soc/codecs/inno_rk3036.c
@@ -0,0 +1,455 @@
+/*
+ * Driver of Inno codec for rk3036 by Rockchip Inc.
+ *
+ * Author: Rockchip Inc.
+ * Author: Zheng ShunQian
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "inno_rk3036.h"
+
+struct rk3036_codec_priv {
+   void __iomem *base;
+   struct clk *pclk;
+   struct regmap *regmap;
+   struct device *dev;
+};
+
+static const DECLARE_TLV_DB_MINMAX(rk3036_codec_hp_tlv, -39, 0);
+
+static const char *rk3036_codec_antipop_text[] = {"none", "work"};
+static const unsigned int rk3036_codec_antipop_values[] = {0x1, 0x2};
+
+static SOC_VALUE_ENUM_DOUBLE_DECL(rk3036_codec_antipop_enum, INNO_R09,
+   INNO_R09_HPL_ANITPOP_SHIFT, INNO_R09_HPR_ANITPOP_SHIFT, 0x3,
+   rk3036_codec_antipop_text, rk3036_codec_antipop_values);
+
+static const struct snd_kcontrol_new rk3036_codec_dapm_controls[] = {
+   SOC_DOUBLE_R_RANGE_TLV("Headphone Volume", INNO_R07, INNO_R08,
+   INNO_HP_GAIN_SHIFT, INNO_HP_GAIN_N39DB,
+   INNO_HP_GAIN_0DB, 0, rk3036_codec_hp_tlv),
+   SOC_DOUBLE("Zero Cross Detect", INNO_R06, INNO_R06_VOUTL_CZ_SHIFT,
+   INNO_R06_VOUTR_CZ_SHIFT, 1, 0),
+   SOC_DOUBLE("HP Mute", INNO_R09, INNO_R09_HPL_MUTE_SHIFT,
+   INNO_R09_HPR_MUTE_SHIFT, 1, 1),
+   SOC_ENUM("Anti-pop", rk3036_codec_antipop_enum),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpl_mixer_controls[] = {
+   SOC_DAPM_SINGLE("DAC Left Out Switch", INNO_R09,
+   INNO_R09_DACL_SWITCH_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpr_mixer_controls[] = {
+   SOC_DAPM_SINGLE("DAC Right Out Switch", INNO_R09,
+   INNO_R09_DACR_SWITCH_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpl_switch_controls[] = {
+   SOC_DAPM_SINGLE("HP Left Out Switch", INNO_R05,
+   INNO_R05_HPL_WORK_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpr_switch_controls[] = {
+   SOC_DAPM_SINGLE("HP Right Out Switch", INNO_R05,
+   INNO_R05_HPR_WORK_SHIFT, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget rk3036_codec_dapm_widgets[] = {
+   SND_SOC_DAPM_SUPPLY_S("DAC PWR", 1, INNO_R06,
+ INNO_R06_DAC_EN_SHIFT, 0, NULL, 0

Re: [PATCH v2 1/2] ASoC: codec: Inno codec driver for RK3036 SoC

2015-11-05 Thread Mark Brown
On Thu, Nov 05, 2015 at 05:53:13PM +0800, Shunqian Zheng wrote:

This is basically all good, a few very minor comments below but nothing
that should take any time to fix.

> +static const char *rk3036_codec_antipop_text[] = {"none", "work"};
> +static const unsigned int rk3036_codec_antipop_values[] = {0x1, 0x2};
> +
> +static SOC_VALUE_ENUM_DOUBLE_DECL(rk3036_codec_antipop_enum, INNO_R09,
> + INNO_R09_HPL_ANITPOP_SHIFT, INNO_R09_HPR_ANITPOP_SHIFT, 0x3,
> + rk3036_codec_antipop_text, rk3036_codec_antipop_values);

This looks like a simple boolean control rather than an enum - it looks
like it's just turning antipop on and off.

> + SOC_DOUBLE_R_RANGE_TLV("Headphone Volume", INNO_R07, INNO_R08,
> + INNO_HP_GAIN_SHIFT, INNO_HP_GAIN_N39DB,
> + INNO_HP_GAIN_0DB, 0, rk3036_codec_hp_tlv),
> + SOC_DOUBLE("Zero Cross Detect", INNO_R06, INNO_R06_VOUTL_CZ_SHIFT,
> + INNO_R06_VOUTR_CZ_SHIFT, 1, 0),

This should be "Zero Cross Switch".

> + SOC_DOUBLE("HP Mute", INNO_R09, INNO_R09_HPL_MUTE_SHIFT,
> + INNO_R09_HPR_MUTE_SHIFT, 1, 1),

This should be "Headphone Switch".

> +static int rk3036_codec_add_widgets(struct snd_soc_codec *codec)
> +{
> + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
> +
> + snd_soc_add_codec_controls(codec, rk3036_codec_dapm_controls,
> + ARRAY_SIZE(rk3036_codec_dapm_controls));
> +
> + snd_soc_dapm_new_controls(dapm, rk3036_codec_dapm_widgets,
> + ARRAY_SIZE(rk3036_codec_dapm_widgets));
> +
> + snd_soc_dapm_add_routes(dapm, rk3036_codec_dapm_routes,
> + ARRAY_SIZE(rk3036_codec_dapm_routes));

Just point at the tables from the driver structure and let the core do
the initialisation for you.

> +static int rk3036_codec_set_bias_level(struct snd_soc_codec *codec,
> +enum snd_soc_bias_level level)
> +{
> + switch (level) {
> + case SND_SOC_BIAS_STANDBY:
> + /* set a big current for capacitor charging. */
> + snd_soc_write(codec, INNO_R10, INNO_R10_MAX_CUR);
> + /* start precharge */
> + snd_soc_write(codec, INNO_R06, INNO_R06_DAC_PRECHARGE);

Do we not need to wait for this to ramp?


signature.asc
Description: PGP signature


Re: [PATCH v2 1/2] ASoC: codec: Inno codec driver for RK3036 SoC

2015-11-05 Thread LABBE Corentin
On Thu, Nov 05, 2015 at 05:53:13PM +0800, Shunqian Zheng wrote:
> From: ZhengShunQian 
> 
> RK3036 SoC integrated with an Inno audio codec.
> This driver implements the functions of it.
> 
> There is not need a special machine driver, since the
> simple-card machine driver works perfect in this case.
> 
> Signed-off-by: ZhengShunQian 
> ---
>  sound/soc/codecs/Kconfig   |   4 +
>  sound/soc/codecs/Makefile  |   2 +
>  sound/soc/codecs/inno_rk3036.c | 455 
> +
>  sound/soc/codecs/inno_rk3036.h | 120 +++
>  4 files changed, 581 insertions(+)
>  create mode 100644 sound/soc/codecs/inno_rk3036.c
>  create mode 100644 sound/soc/codecs/inno_rk3036.h
> 
> diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
> index cfdafc4..89d789e 100644
> --- a/sound/soc/codecs/Kconfig
> +++ b/sound/soc/codecs/Kconfig
> @@ -67,6 +67,7 @@ config SND_SOC_ALL_CODECS
>   select SND_SOC_ES8328_I2C if I2C
>   select SND_SOC_GTM601
>   select SND_SOC_ICS43432
> + select SND_SOC_INNO_RK3036
>   select SND_SOC_ISABELLE if I2C
>   select SND_SOC_JZ4740_CODEC
>   select SND_SOC_LM4857 if I2C
> @@ -471,6 +472,9 @@ config SND_SOC_GTM601
>  config SND_SOC_ICS43432
>   tristate
>  
> +config SND_SOC_INNO_RK3036
> + tristate "Inno codec driver for RK3036 SoC"
> +
>  config SND_SOC_ISABELLE
>  tristate
>  
> diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
> index f632fc4..2f6bc6c 100644
> --- a/sound/soc/codecs/Makefile
> +++ b/sound/soc/codecs/Makefile
> @@ -60,6 +60,7 @@ snd-soc-es8328-i2c-objs := es8328-i2c.o
>  snd-soc-es8328-spi-objs := es8328-spi.o
>  snd-soc-gtm601-objs := gtm601.o
>  snd-soc-ics43432-objs := ics43432.o
> +snd-soc-inno-rk3036-objs := inno_rk3036.o
>  snd-soc-isabelle-objs := isabelle.o
>  snd-soc-jz4740-codec-objs := jz4740.o
>  snd-soc-l3-objs := l3.o
> @@ -255,6 +256,7 @@ obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
>  obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
>  obj-$(CONFIG_SND_SOC_GTM601)+= snd-soc-gtm601.o
>  obj-$(CONFIG_SND_SOC_ICS43432)   += snd-soc-ics43432.o
> +obj-$(CONFIG_SND_SOC_INNO_RK3036)+= snd-soc-inno-rk3036.o
>  obj-$(CONFIG_SND_SOC_ISABELLE)   += snd-soc-isabelle.o
>  obj-$(CONFIG_SND_SOC_JZ4740_CODEC)   += snd-soc-jz4740-codec.o
>  obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
> diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c
> new file mode 100644
> index 000..ce68f02
> --- /dev/null
> +++ b/sound/soc/codecs/inno_rk3036.c
> @@ -0,0 +1,455 @@
> +/*
> + * Driver of Inno codec for rk3036 by Rockchip Inc.
> + *
> + * Author: Rockchip Inc.
> + * Author: Zheng ShunQian
> + */
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#include "inno_rk3036.h"
> +
> +struct rk3036_codec_priv {
> + void __iomem *base;
> + struct clk *pclk;
> + struct regmap *regmap;
> + struct device *dev;
> +};
> +
> +static const DECLARE_TLV_DB_MINMAX(rk3036_codec_hp_tlv, -39, 0);
> +
> +static const char *rk3036_codec_antipop_text[] = {"none", "work"};
> +static const unsigned int rk3036_codec_antipop_values[] = {0x1, 0x2};
> +
> +static SOC_VALUE_ENUM_DOUBLE_DECL(rk3036_codec_antipop_enum, INNO_R09,
> + INNO_R09_HPL_ANITPOP_SHIFT, INNO_R09_HPR_ANITPOP_SHIFT, 0x3,
> + rk3036_codec_antipop_text, rk3036_codec_antipop_values);
> +
> +static const struct snd_kcontrol_new rk3036_codec_dapm_controls[] = {
> + SOC_DOUBLE_R_RANGE_TLV("Headphone Volume", INNO_R07, INNO_R08,
> + INNO_HP_GAIN_SHIFT, INNO_HP_GAIN_N39DB,
> + INNO_HP_GAIN_0DB, 0, rk3036_codec_hp_tlv),
> + SOC_DOUBLE("Zero Cross Detect", INNO_R06, INNO_R06_VOUTL_CZ_SHIFT,
> + INNO_R06_VOUTR_CZ_SHIFT, 1, 0),
> + SOC_DOUBLE("HP Mute", INNO_R09, INNO_R09_HPL_MUTE_SHIFT,
> + INNO_R09_HPR_MUTE_SHIFT, 1, 1),
> + SOC_ENUM("Anti-pop", rk3036_codec_antipop_enum),
> +};
> +
> +static const struct snd_kcontrol_new rk3036_codec_hpl_mixer_controls[] = {
> + SOC_DAPM_SINGLE("DAC Left Out Switch", INNO_R09,
> + INNO_R09_DACL_SWITCH_SHIFT, 1, 0),
> +};
> +
> +static const struct snd_kcontrol_new rk3036_codec_hpr_mixer_controls[] = {
> + SOC_DAPM_SINGLE("DAC Right Out Switch", INNO_R09,
> + INNO_R09_DACR_SWITCH_SHIFT, 1, 0),
> +};
> +
> +static const struct snd_kcontrol_new rk3036_codec_hpl_switch_controls[] = {
> + SOC_DAPM_SINGLE("HP Left Out Switch", INNO_R05,
> + INNO_R05_HPL_WORK_SHIFT, 1, 0),
> +};
> +
> +static const struct snd_kcontrol_new rk3036_codec_hpr_switch_controls[] = {
> + SOC_DAPM_SINGLE("HP Right Out Switch", INNO_R05,
> + INNO_R05_HPR_WORK_SHIFT, 1, 0),
> +};
> +
> +static const struct snd_soc_dapm_widget rk3036_codec_dap

[PATCH v2 1/2] ASoC: codec: Inno codec driver for RK3036 SoC

2015-11-05 Thread Shunqian Zheng
From: ZhengShunQian 

RK3036 SoC integrated with an Inno audio codec.
This driver implements the functions of it.

There is not need a special machine driver, since the
simple-card machine driver works perfect in this case.

Signed-off-by: ZhengShunQian 
---
 sound/soc/codecs/Kconfig   |   4 +
 sound/soc/codecs/Makefile  |   2 +
 sound/soc/codecs/inno_rk3036.c | 455 +
 sound/soc/codecs/inno_rk3036.h | 120 +++
 4 files changed, 581 insertions(+)
 create mode 100644 sound/soc/codecs/inno_rk3036.c
 create mode 100644 sound/soc/codecs/inno_rk3036.h

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index cfdafc4..89d789e 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -67,6 +67,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ES8328_I2C if I2C
select SND_SOC_GTM601
select SND_SOC_ICS43432
+   select SND_SOC_INNO_RK3036
select SND_SOC_ISABELLE if I2C
select SND_SOC_JZ4740_CODEC
select SND_SOC_LM4857 if I2C
@@ -471,6 +472,9 @@ config SND_SOC_GTM601
 config SND_SOC_ICS43432
tristate
 
+config SND_SOC_INNO_RK3036
+   tristate "Inno codec driver for RK3036 SoC"
+
 config SND_SOC_ISABELLE
 tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index f632fc4..2f6bc6c 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -60,6 +60,7 @@ snd-soc-es8328-i2c-objs := es8328-i2c.o
 snd-soc-es8328-spi-objs := es8328-spi.o
 snd-soc-gtm601-objs := gtm601.o
 snd-soc-ics43432-objs := ics43432.o
+snd-soc-inno-rk3036-objs := inno_rk3036.o
 snd-soc-isabelle-objs := isabelle.o
 snd-soc-jz4740-codec-objs := jz4740.o
 snd-soc-l3-objs := l3.o
@@ -255,6 +256,7 @@ obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o
 obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o
 obj-$(CONFIG_SND_SOC_GTM601)+= snd-soc-gtm601.o
 obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o
+obj-$(CONFIG_SND_SOC_INNO_RK3036)  += snd-soc-inno-rk3036.o
 obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_L3)   += snd-soc-l3.o
diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c
new file mode 100644
index 000..ce68f02
--- /dev/null
+++ b/sound/soc/codecs/inno_rk3036.c
@@ -0,0 +1,455 @@
+/*
+ * Driver of Inno codec for rk3036 by Rockchip Inc.
+ *
+ * Author: Rockchip Inc.
+ * Author: Zheng ShunQian
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "inno_rk3036.h"
+
+struct rk3036_codec_priv {
+   void __iomem *base;
+   struct clk *pclk;
+   struct regmap *regmap;
+   struct device *dev;
+};
+
+static const DECLARE_TLV_DB_MINMAX(rk3036_codec_hp_tlv, -39, 0);
+
+static const char *rk3036_codec_antipop_text[] = {"none", "work"};
+static const unsigned int rk3036_codec_antipop_values[] = {0x1, 0x2};
+
+static SOC_VALUE_ENUM_DOUBLE_DECL(rk3036_codec_antipop_enum, INNO_R09,
+   INNO_R09_HPL_ANITPOP_SHIFT, INNO_R09_HPR_ANITPOP_SHIFT, 0x3,
+   rk3036_codec_antipop_text, rk3036_codec_antipop_values);
+
+static const struct snd_kcontrol_new rk3036_codec_dapm_controls[] = {
+   SOC_DOUBLE_R_RANGE_TLV("Headphone Volume", INNO_R07, INNO_R08,
+   INNO_HP_GAIN_SHIFT, INNO_HP_GAIN_N39DB,
+   INNO_HP_GAIN_0DB, 0, rk3036_codec_hp_tlv),
+   SOC_DOUBLE("Zero Cross Detect", INNO_R06, INNO_R06_VOUTL_CZ_SHIFT,
+   INNO_R06_VOUTR_CZ_SHIFT, 1, 0),
+   SOC_DOUBLE("HP Mute", INNO_R09, INNO_R09_HPL_MUTE_SHIFT,
+   INNO_R09_HPR_MUTE_SHIFT, 1, 1),
+   SOC_ENUM("Anti-pop", rk3036_codec_antipop_enum),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpl_mixer_controls[] = {
+   SOC_DAPM_SINGLE("DAC Left Out Switch", INNO_R09,
+   INNO_R09_DACL_SWITCH_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpr_mixer_controls[] = {
+   SOC_DAPM_SINGLE("DAC Right Out Switch", INNO_R09,
+   INNO_R09_DACR_SWITCH_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpl_switch_controls[] = {
+   SOC_DAPM_SINGLE("HP Left Out Switch", INNO_R05,
+   INNO_R05_HPL_WORK_SHIFT, 1, 0),
+};
+
+static const struct snd_kcontrol_new rk3036_codec_hpr_switch_controls[] = {
+   SOC_DAPM_SINGLE("HP Right Out Switch", INNO_R05,
+   INNO_R05_HPR_WORK_SHIFT, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget rk3036_codec_dapm_widgets[] = {
+   SND_SOC_DAPM_SUPPLY_S("DAC PWR", 1, INNO_R06,
+ INNO_R06_DAC_EN_SHIFT, 0, NULL, 0),
+   SND_SOC_DAPM_SUPPLY_S("DACL VREF", 2, INNO_R04,
+ INNO_R04_DACL_VREF_SHIFT, 0, NULL, 0),
+   SND_SOC_DAPM_SUPPLY_S(