add rk616 codec driver
author陈金泉 <chenjq@rock-chips.com>
Thu, 18 Apr 2013 02:42:32 +0000 (10:42 +0800)
committer陈金泉 <chenjq@rock-chips.com>
Thu, 18 Apr 2013 02:42:32 +0000 (10:42 +0800)
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/rk616_codec.c [new file with mode: 0755]
sound/soc/codecs/rk616_codec.h [new file with mode: 0755]
sound/soc/rk29/Kconfig
sound/soc/rk29/Makefile
sound/soc/rk29/rk_rk616.c [new file with mode: 0755]

index 6619b8fb555434561909c6fdbbc2b50bda9a23bc..3889aff2bd7f682f84f76ec4371bd3b46d6015ee 100755 (executable)
@@ -87,6 +87,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_RT5639 if I2C
        select SND_SOC_RT5616 if I2C
        select SND_SOC_RK610 if I2C
+       select SND_SOC_RK616 if I2C
        select SND_SOC_WM8903 if I2C
        select SND_SOC_WM8904 if I2C
        select SND_SOC_WM8915 if I2C
@@ -437,6 +438,10 @@ config SND_SOC_RK610
        tristate
        depends on MFD_RK610
 
+config SND_SOC_RK616
+       tristate
+       depends on MFD_RK616
+
 # Amp
 config SND_SOC_LM4857
        tristate
index a03da1769aa4b7bae94614e549056dde598715a0..62292a90224e59420c6c8128f5fec49c8da8a20d 100755 (executable)
@@ -93,6 +93,7 @@ snd-soc-wm-hubs-objs := wm_hubs.o
 snd-soc-rk1000-objs := rk1000_codec.o
 snd-soc-jz4740-codec-objs := jz4740.o
 snd-soc-rk610-objs := rk610_codec.o
+snd-soc-rk616-objs := rk616_codec.o
 snd-soc-rt5640-objs := rt5640.o rt5640-dsp.o rt5640_ioctl.o rt56xx_ioctl.o
 snd-soc-rt3261-objs := rt3261.o rt3261-dsp.o rt3261_ioctl.o rt_codec_ioctl.o
 snd-soc-rt3224-objs := rt3261.o rt3261_ioctl.o rt_codec_ioctl.o
@@ -204,6 +205,7 @@ obj-$(CONFIG_SND_SOC_WM9713)        += snd-soc-wm9713.o
 obj-$(CONFIG_SND_SOC_WM_HUBS)  += snd-soc-wm-hubs.o
 obj-$(CONFIG_SND_SOC_RK1000)   += snd-soc-rk1000.o
 obj-$(CONFIG_SND_SOC_RK610)    += snd-soc-rk610.o
+obj-$(CONFIG_SND_SOC_RK616)    += snd-soc-rk616.o
 obj-$(CONFIG_SND_SOC_RK2928)   += snd-soc-rk2928.o
 
 # Amp
diff --git a/sound/soc/codecs/rk616_codec.c b/sound/soc/codecs/rk616_codec.c
new file mode 100755 (executable)
index 0000000..99f49f9
--- /dev/null
@@ -0,0 +1,1766 @@
+/*
+ * rk616.c  --  RK616 CODEC ALSA SoC audio driver
+ *
+ * Copyright 2013 Rockship
+ * Author: chenjq <chenjq@rock-chips.com>
+ */
+
+#define DEBUG //for log
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <linux/gpio.h>
+#include <linux/mfd/rk616.h>
+#include "rk616_codec.h"
+#include <mach/board.h>
+
+
+#define RK616_FOR_MID
+
+#define RK616_REG_RW /* for debug */
+#define RK616_PROC
+#ifdef RK616_PROC
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/vmalloc.h>
+#endif
+
+#ifdef CONFIG_RK_HEADSET_DET
+#include "../../../drivers/headset_observe/rk_headset.h"
+#endif
+
+struct rk616_codec_priv {
+       struct snd_soc_codec *codec;
+
+       unsigned int stereo_sysclk;
+       unsigned int rate;
+#ifdef RK616_FOR_MID
+       int playback_active;
+       int capture_active;
+#endif
+       int spk_ctr_status;
+       int spk_ctr_pin;
+       int spk_ctr_on;
+       int spk_ctr_off;
+};
+
+static struct rk616_codec_priv *rk616_priv = NULL;
+
+static const unsigned int rk616_reg_defaults[RK616_PGAR_AGC_CTL5 + 1] = {
+       [RK616_RESET] = 0x0003,
+       [RK616_ADC_INT_CTL1] = 0x0050,
+       [RK616_ADC_INT_CTL2] = 0x000e,
+       [RK616_DAC_INT_CTL1] = 0x0050,
+       [RK616_DAC_INT_CTL2] = 0x001c,
+       [RK616_PGA_AGC_CTL] = 0x000c,
+       [RK616_PWR_ADD1] = 0x007c,
+       [RK616_BST_CTL] = 0x0099,
+       [RK616_DIFFIN_CTL] = 0x0024,
+       [RK616_MIXINL_CTL] = 0x001f,
+       [RK616_MIXINL_VOL1] = 0x0024,
+       [RK616_MIXINL_VOL2] = 0x0004,
+       [RK616_MIXINR_CTL] = 0x003f,
+       [RK616_MIXINR_VOL1] = 0x0024,
+       [RK616_MIXINR_VOL2] = 0x0024,
+       [RK616_PGAL_CTL] = 0x00cc,
+       [RK616_PGAR_CTL] = 0x00cc,
+       [RK616_PWR_ADD2] = 0x00ff,
+       [RK616_DAC_CTL] = 0x003f,
+       [RK616_LINEMIX_CTL] = 0x001f,
+       [RK616_MUXHP_HPMIX_CTL] = 0x003c,
+       [RK616_HPMIX_CTL] = 0x00ff,
+       [RK616_HPMIX_VOL1] = 0x0000,
+       [RK616_HPMIX_VOL2] = 0x0000,
+       [RK616_LINEOUT1_CTL] = 0x0060,
+       [RK616_LINEOUT2_CTL] = 0x0060,
+       [RK616_SPKL_CTL] = 0x00e0,
+       [RK616_SPKR_CTL] = 0x00e0,
+       [RK616_HPL_CTL] = 0x00e0,
+       [RK616_HPR_CTL] = 0x00e0,
+       [RK616_MICBIAS_CTL] = 0x00ff,
+       [RK616_MICKEY_DET_CTL] = 0x0028,
+       [RK616_PWR_ADD3] = 0x000f,
+       [RK616_ADC_CTL] = 0x0036,
+       [RK616_PGAL_AGC_CTL1] = 0x001f,
+       [RK616_PGAL_AGC_CTL2] = 0x0025,
+       [RK616_PGAL_AGC_CTL3] = 0x0041,
+       [RK616_PGAL_AGC_CTL4] = 0x002c,
+       [RK616_PGAL_ASR_CTL] = 0x0000,
+       [RK616_PGAL_AGC_MAX_H] = 0x0026,
+       [RK616_PGAL_AGC_MAX_L] = 0x0040,
+       [RK616_PGAL_AGC_MIN_H] = 0x0036,
+       [RK616_PGAL_AGC_MIN_L] = 0x0020,
+       [RK616_PGAL_AGC_CTL5] = 0x0038,
+       [RK616_PGAR_AGC_CTL1] = 0x001f,
+       [RK616_PGAR_AGC_CTL2] = 0x0025,
+       [RK616_PGAR_AGC_CTL3] = 0x0041,
+       [RK616_PGAR_AGC_CTL4] = 0x002c,
+       [RK616_PGAR_ASR_CTL] = 0x0000,
+       [RK616_PGAR_AGC_MAX_H] = 0x0026,
+       [RK616_PGAR_AGC_MAX_L] = 0x0040,
+       [RK616_PGAR_AGC_MIN_H] = 0x0036,
+       [RK616_PGAR_AGC_MIN_L] = 0x0020,
+       [RK616_PGAR_AGC_CTL5] = 0x0038,
+};
+
+static struct rk616_reg_val_typ rk616_mfd_reg_defaults[] = {
+       {CRU_CODEC_DIV, 0x00000000},
+       {CRU_IO_CON0, (I2S1_OUT_EN | I2S0_OUT_EN | I2S1_PD_DISABLE | I2S0_PD_DISABLE) | 
+               ((I2S1_OUT_EN | I2S0_OUT_EN | I2S1_PD_DISABLE | I2S0_PD_DISABLE) << 16)},
+       {CRU_IO_CON1, (I2S1_SI_EN | I2S0_SI_EN) | ((I2S1_SI_EN | I2S0_SI_EN) << 16)},
+};
+
+static struct rk616_reg_val_typ rk616_mfd_reg_cache[] = {
+       {CRU_CODEC_DIV, 0x00000000},
+       {CRU_IO_CON0, (I2S1_OUT_EN | I2S0_OUT_EN | I2S1_PD_DISABLE | I2S0_PD_DISABLE) | 
+               ((I2S1_OUT_EN | I2S0_OUT_EN | I2S1_PD_DISABLE | I2S0_PD_DISABLE) << 16)},
+       {CRU_IO_CON1, (I2S1_SI_EN | I2S0_SI_EN) | ((I2S1_SI_EN | I2S0_SI_EN) << 16)},
+};
+
+#define RK616_MFD_REG_LEN ARRAY_SIZE(rk616_mfd_reg_cache)
+
+static int rk616_mfd_register(unsigned int reg)
+{
+       int i;
+
+       for (i = 0; i < RK616_MFD_REG_LEN; i++) {
+               if (rk616_mfd_reg_cache[i].reg == reg)
+                       return 1;
+       }
+
+       return 0;
+}
+
+//writeable mask bit 16~31
+static int rk616_mfd_mask_register(unsigned int reg)
+{
+       switch (reg) {
+       case CRU_IO_CON0:
+       case CRU_IO_CON1:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static int rk616_volatile_register(struct snd_soc_codec *codec, unsigned int reg)
+{
+       switch (reg) {
+       case RK616_RESET:
+       case RK616_MICKEY_DET_CTL:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static int rk616_codec_register(struct snd_soc_codec *codec, unsigned int reg)
+{
+       switch (reg) {
+       case RK616_RESET:
+       case RK616_ADC_INT_CTL1 :
+       case RK616_ADC_INT_CTL2 :
+       case RK616_DAC_INT_CTL1:
+       case RK616_DAC_INT_CTL2:
+       case RK616_PGA_AGC_CTL:
+       case RK616_PWR_ADD1:
+       case RK616_BST_CTL:
+       case RK616_DIFFIN_CTL:
+       case RK616_MIXINL_CTL:
+       case RK616_MIXINL_VOL1:
+       case RK616_MIXINL_VOL2:
+       case RK616_MIXINR_CTL:
+       case RK616_MIXINR_VOL1:
+       case RK616_MIXINR_VOL2:
+       case RK616_PGAL_CTL:
+       case RK616_PGAR_CTL     :
+       case RK616_PWR_ADD2:
+       case RK616_DAC_CTL:
+       case RK616_LINEMIX_CTL:
+       case RK616_MUXHP_HPMIX_CTL:
+       case RK616_HPMIX_CTL:
+       case RK616_HPMIX_VOL1:
+       case RK616_HPMIX_VOL2:
+       case RK616_LINEOUT1_CTL:
+       case RK616_LINEOUT2_CTL:
+       case RK616_SPKL_CTL:
+       case RK616_SPKR_CTL:
+       case RK616_HPL_CTL:
+       case RK616_HPR_CTL:
+       case RK616_MICBIAS_CTL:
+       case RK616_MICKEY_DET_CTL:
+       case RK616_PWR_ADD3:
+       case RK616_ADC_CTL:
+       case RK616_PGAL_AGC_CTL1:
+       case RK616_PGAL_AGC_CTL2:
+       case RK616_PGAL_AGC_CTL3:
+       case RK616_PGAL_AGC_CTL4:
+       case RK616_PGAL_ASR_CTL:
+       case RK616_PGAL_AGC_MAX_H:
+       case RK616_PGAL_AGC_MAX_L:
+       case RK616_PGAL_AGC_MIN_H:
+       case RK616_PGAL_AGC_MIN_L:
+       case RK616_PGAL_AGC_CTL5:
+       case RK616_PGAR_AGC_CTL1:
+       case RK616_PGAR_AGC_CTL2:
+       case RK616_PGAR_AGC_CTL3:
+       case RK616_PGAR_AGC_CTL4:
+       case RK616_PGAR_ASR_CTL:
+       case RK616_PGAR_AGC_MAX_H:
+       case RK616_PGAR_AGC_MAX_L:
+       case RK616_PGAR_AGC_MIN_H:
+       case RK616_PGAR_AGC_MIN_L:
+       case RK616_PGAR_AGC_CTL5:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static inline unsigned int rk616_read_reg_cache(struct snd_soc_codec *codec,
+       unsigned int reg)
+{
+       unsigned int *cache = codec->reg_cache;
+       int i;
+
+       if (rk616_codec_register(codec, reg))
+               return  cache[reg];
+
+       if (rk616_mfd_register(reg)) {
+               for (i = 0; i < RK616_MFD_REG_LEN; i++) {
+                       if (rk616_mfd_reg_cache[i].reg == reg)
+                               return rk616_mfd_reg_cache[i].value;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static inline void rk616_write_reg_cache(struct snd_soc_codec *codec,
+       unsigned int reg, unsigned int value)
+{
+       unsigned int *cache = codec->reg_cache;
+       int i;
+
+       if (rk616_codec_register(codec, reg)) {
+               cache[reg] = value;
+               return;
+       }
+
+       if (rk616_mfd_register(reg)) {
+               for (i = 0; i < RK616_MFD_REG_LEN; i++) {
+                       if (rk616_mfd_reg_cache[i].reg == reg) {
+                               rk616_mfd_reg_cache[i].value = value;
+                               return;
+                       }
+               }
+       }
+}
+
+static unsigned int rk616_codec_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+       unsigned int value;
+       struct mfd_rk616 *rk616 = snd_soc_codec_get_drvdata(codec);
+
+       if (!rk616)
+               return -EINVAL;
+
+       if (rk616_volatile_register(codec, reg) == 0) {
+               value = rk616_read_reg_cache(codec, reg);
+       } else {
+               if (rk616->read_dev(rk616, reg, &value) < 0) {
+                       dev_err(codec->dev, "%s reg = 0x%x failed\n", __func__, reg);
+                       return -EIO;
+               }
+       }
+
+       dev_dbg(codec->dev, "%s reg = %x, val= %x\n", __func__, reg, value);
+       return value;
+}
+
+static int rk616_codec_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value)
+{
+       struct mfd_rk616 *rk616 = snd_soc_codec_get_drvdata(codec);
+
+       if (!rk616)
+               return -EINVAL;
+
+       if (rk616_mfd_mask_register(reg))
+               value = ((0xffff0000 & rk616_read_reg_cache(codec, reg)) | (value & 0x0000ffff));
+
+       if (rk616->write_dev(rk616, reg, &value) < 0) {
+               dev_err(codec->dev, "%s reg = 0x%x failed\n", __func__, reg);
+               return -EIO;
+       }
+
+       rk616_write_reg_cache(codec, reg, value);
+
+       dev_dbg(codec->dev, "%s reg=0x%x, val=0x%x\n", __func__, reg, value);
+       return 0;
+}
+
+static int rk616_hw_write(const struct i2c_client *client, const char *buf, int count)
+{
+       struct snd_soc_codec *codec = rk616_priv->codec;
+       unsigned int reg, value;
+       int ret = -1;
+
+       if (!rk616_priv & !rk616_priv->codec)
+               return -EINVAL;
+
+       if (count == 3) {
+               reg = (unsigned int)buf[0];
+               value = (buf[1] & 0xff00) | (0x00ff & buf[2]);
+               ret = rk616_codec_write(codec, reg, value);
+       } else {
+               dev_err(codec->dev, "%s i2c len error\n", __func__);
+       }
+
+       return (ret == 0) ? count : ret;
+}
+
+static int rk616_reset(struct snd_soc_codec *codec)
+{
+       int ret;
+
+       ret = snd_soc_write(codec, RK616_RESET, 0);
+       if (ret >= 0) {
+               memcpy(codec->reg_cache, rk616_reg_defaults,
+                      sizeof(rk616_reg_defaults));
+               memcpy(rk616_mfd_reg_cache, rk616_mfd_reg_defaults,
+                      sizeof(rk616_mfd_reg_defaults));
+       }
+
+       return ret;
+}
+
+#ifdef RK616_FOR_MID
+static struct rk616_reg_val_typ init_list[] = {
+
+};
+
+#define RK616_INIT_REG_LEN ARRAY_SIZE(init_list)
+
+static int rk616_reg_init(struct snd_soc_codec *codec)
+{
+       int i;
+
+       for (i = 0; i < RK616_INIT_REG_LEN; i++)
+               snd_soc_write(codec, init_list[i].reg, init_list[i].value);
+
+       return 0;
+}
+#endif
+
+int rk616_headset_mic_detect(bool headset_status)
+{
+       struct snd_soc_codec *codec = rk616_priv->codec;
+
+       dev_dbg(codec->dev, "%s::%d\n", __FUNCTION__, __LINE__);
+
+       if (!rk616_priv & !rk616_priv->codec)
+               return -EINVAL;
+
+       if (headset_status) {
+
+       } else {// headset is out, disable MIC2 Bias
+               dev_dbg(codec->dev, "headset is out,disable Mic2 Bias\n");
+       }
+       return 0;
+}
+EXPORT_SYMBOL(rk616_headset_mic_detect);
+
+void codec_set_spk(bool on)
+{
+       struct snd_soc_codec *codec = rk616_priv->codec;
+
+       dev_dbg(codec->dev, "%s:: %s\n", __func__, on?"enable spk":"disable spk");
+
+       if (!rk616_priv & !rk616_priv->codec)
+               return;
+
+       if (on) {
+#ifdef RK616_FOR_MID
+               snd_soc_update_bits(codec, RK616_SPKL_CTL,
+                       RK616_MUTE, 0);
+               snd_soc_update_bits(codec, RK616_SPKR_CTL,
+                       RK616_MUTE, 0);
+               snd_soc_update_bits(codec, RK616_HPL_CTL,
+                       RK616_MUTE, 0);
+               snd_soc_update_bits(codec, RK616_HPR_CTL,
+                       RK616_MUTE, 0);
+#else
+               snd_soc_dapm_enable_pin(&codec->dapm, "Headphone Jack");
+               snd_soc_dapm_enable_pin(&codec->dapm, "Ext Spk");
+#endif
+       } else {
+#ifdef RK616_FOR_MID
+               snd_soc_update_bits(codec, RK616_SPKL_CTL,
+                       RK616_MUTE, RK616_MUTE);
+               snd_soc_update_bits(codec, RK616_SPKR_CTL,
+                       RK616_MUTE, RK616_MUTE);
+               snd_soc_update_bits(codec, RK616_HPL_CTL,
+                       RK616_MUTE, RK616_MUTE);
+               snd_soc_update_bits(codec, RK616_HPR_CTL,
+                       RK616_MUTE, RK616_MUTE);
+#else
+               snd_soc_dapm_disable_pin(&codec->dapm, "Headphone Jack");
+               snd_soc_dapm_disable_pin(&codec->dapm, "Ext Spk");
+#endif
+       }
+       snd_soc_dapm_sync(&codec->dapm);
+}
+EXPORT_SYMBOL_GPL(codec_set_spk);
+
+static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -3900, 150, 0);
+static const DECLARE_TLV_DB_SCALE(pga_vol_tlv, -1800, 150, 0);
+static const DECLARE_TLV_DB_SCALE(bst_vol_tlv, 0, 2000, 0);
+static const DECLARE_TLV_DB_SCALE(mix_vol_tlv, -1200, 300, 0);
+static const DECLARE_TLV_DB_SCALE(pga_agc_max_vol_tlv, -1350, 600, 0);
+static const DECLARE_TLV_DB_SCALE(pga_agc_min_vol_tlv, -1800, 600, 0);
+
+static const char *rk616_input_mode[] = {"Differential", "Single-Ended"}; 
+
+static const char *rk616_micbias_ratio[] = {"1.0 Vref", "1.1 Vref",
+               "1.2 Vref", "1.3 Vref", "1.4 Vref", "1.5 Vref", "1.6 Vref", "1.7 Vref",};
+
+static const char *rk616_dis_en_sel[] = {"Disable", "Enable"};
+
+static const char *rk616_mickey_range[] = {"100uA", "300uA",
+               "500uA", "700uA", "900uA", "1100uA", "1300uA", "1500uA"};
+
+static const char *rk616_pga_gain_control[] = {"Normal", "AGC"};
+
+static const char *rk616_pga_agc_way[] = {"Normal", "Jack"};
+
+static const char *rk616_pga_agc_hold_time[] = {"0ms", "2ms",
+               "4ms", "8ms", "16ms", "32ms", "64ms", "128ms", "256ms", "512ms", "1s"};
+
+static const char *rk616_pga_agc_ramp_up_time[] = {"500us", "1ms", "2ms",
+               "4ms", "8ms", "16ms", "32ms", "64ms", "128ms", "256ms", "512ms"};
+
+static const char *rk616_pga_agc_ramp_down_time[] = {"Normal:125us Jack:32us",
+               "Normal:250us Jack:64us", "Normal:500us Jack:125us", "Normal:1ms Jack:250us",
+               "Normal:2ms Jack:500us", "Normal:4ms Jack:1ms", "Normal:8ms Jack:2ms",
+               "Normal:16ms Jack:4ms", "Normal:32ms Jack:8ms", "Normal:64ms Jack:16ms",
+               "Normal:128ms Jack:32ms"};
+
+static const char *rk616_pga_agc_mode[] = {"Normal", "Limiter"};
+
+static const char *rk616_pga_agc_recovery_mode[] = {"Right Now", "After AGC to Limiter"};
+
+static const char *rk616_pga_agc_noise_gate_threhold[] = {"-39dB", "-45dB", "-51dB",
+               "-57dB", "-63dB", "-69dB", "-75dB", "-81dB"};
+
+static const char *rk616_pga_agc_update_gain[] = {"Right Now", "After 1st Zero Cross"};
+
+static const char *rk616_pga_agc_approximate_sample_rate[] = {"48KHz", "32KHz",
+               "24KHz", "16KHz", "12KHz", "8KHz"};
+
+static const struct soc_enum rk616_bst_enum[] = {
+SOC_ENUM_SINGLE(RK616_BST_CTL, RK616_BSTL_MODE_SFT, 2, rk616_input_mode),
+SOC_ENUM_SINGLE(RK616_BST_CTL, RK616_BSTR_MODE_SFT, 2, rk616_input_mode),
+};
+
+static const struct soc_enum rk616_diffin_enum =
+       SOC_ENUM_SINGLE(RK616_DIFFIN_CTL, RK616_DIFFIN_MODE_SFT, 2, rk616_input_mode);
+
+static const struct soc_enum rk616_micbias_enum[] = {
+SOC_ENUM_SINGLE(RK616_MICBIAS_CTL, RK616_MICBIAS1_V_SFT, 8, rk616_micbias_ratio),
+SOC_ENUM_SINGLE(RK616_MICBIAS_CTL, RK616_MICBIAS2_V_SFT, 8, rk616_micbias_ratio),
+};
+
+static const struct soc_enum rk616_mickey_enum[] = {
+SOC_ENUM_SINGLE(RK616_MICKEY_DET_CTL, RK616_MK1_DET_SFT, 2, rk616_dis_en_sel),
+SOC_ENUM_SINGLE(RK616_MICKEY_DET_CTL, RK616_MK2_DET_SFT, 2, rk616_dis_en_sel),
+SOC_ENUM_SINGLE(RK616_MICKEY_DET_CTL, RK616_MK1_DET_I_SFT, 8, rk616_mickey_range),
+SOC_ENUM_SINGLE(RK616_MICKEY_DET_CTL, RK616_MK2_DET_I_SFT, 8, rk616_mickey_range),
+};
+
+static const struct soc_enum rk616_agcl_enum[] = {
+SOC_ENUM_SINGLE(RK616_PGA_AGC_CTL, RK616_PGAL_AGC_EN_SFT, 2, rk616_pga_gain_control),/*0*/
+SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL1, RK616_PGA_AGC_WAY_SFT, 2, rk616_pga_agc_way),/*1*/
+SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL1, RK616_PGA_AGC_HOLD_T_SFT, 11, rk616_pga_agc_hold_time),/*2*/
+SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL2, RK616_PGA_AGC_GRU_T_SFT, 11, rk616_pga_agc_ramp_up_time),/*3*/
+SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL2, RK616_PGA_AGC_GRD_T_SFT, 11, rk616_pga_agc_ramp_down_time),/*4*/
+SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL3, RK616_PGA_AGC_MODE_SFT, 2, rk616_pga_agc_mode),/*5*/
+SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL3, RK616_PGA_AGC_ZO_SFT, 2, rk616_dis_en_sel),/*6*/
+SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL3, RK616_PGA_AGC_REC_MODE_SFT, 2, rk616_pga_agc_recovery_mode),/*7*/
+SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL3, RK616_PGA_AGC_FAST_D_SFT, 2, rk616_dis_en_sel),/*8*/
+SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL3, RK616_PGA_AGC_NG_SFT, 2, rk616_dis_en_sel),/*9*/
+SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL3, RK616_PGA_AGC_NG_THR_SFT, 8, rk616_pga_agc_noise_gate_threhold),/*10*/
+SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL4, RK616_PGA_AGC_ZO_MODE_SFT, 2, rk616_pga_agc_update_gain),/*11*/
+SOC_ENUM_SINGLE(RK616_PGAL_ASR_CTL, RK616_PGA_SLOW_CLK_SFT, 2, rk616_dis_en_sel),/*12*/
+SOC_ENUM_SINGLE(RK616_PGAL_ASR_CTL, RK616_PGA_ASR_SFT, 6, rk616_pga_agc_approximate_sample_rate),/*13*/
+SOC_ENUM_SINGLE(RK616_PGAL_AGC_CTL5, RK616_PGA_AGC_SFT, 2, rk616_dis_en_sel),/*14*/
+};
+
+static const struct soc_enum rk616_agcr_enum[] = {
+SOC_ENUM_SINGLE(RK616_PGA_AGC_CTL, RK616_PGAR_AGC_EN_SFT, 2, rk616_pga_gain_control),/*0*/
+SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL1, RK616_PGA_AGC_WAY_SFT, 2, rk616_pga_agc_way),/*1*/
+SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL1, RK616_PGA_AGC_HOLD_T_SFT, 11, rk616_pga_agc_hold_time),/*2*/
+SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL2, RK616_PGA_AGC_GRU_T_SFT, 11, rk616_pga_agc_ramp_up_time),/*3*/
+SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL2, RK616_PGA_AGC_GRD_T_SFT, 11, rk616_pga_agc_ramp_down_time),/*4*/
+SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL3, RK616_PGA_AGC_MODE_SFT, 2, rk616_pga_agc_mode),/*5*/
+SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL3, RK616_PGA_AGC_ZO_SFT, 2, rk616_dis_en_sel),/*6*/
+SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL3, RK616_PGA_AGC_REC_MODE_SFT, 2, rk616_pga_agc_recovery_mode),/*7*/
+SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL3, RK616_PGA_AGC_FAST_D_SFT, 2, rk616_dis_en_sel),/*8*/
+SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL3, RK616_PGA_AGC_NG_SFT, 2, rk616_dis_en_sel),/*9*/
+SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL3, RK616_PGA_AGC_NG_THR_SFT, 8, rk616_pga_agc_noise_gate_threhold),/*10*/
+SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL4, RK616_PGA_AGC_ZO_MODE_SFT, 2, rk616_pga_agc_update_gain),/*11*/
+SOC_ENUM_SINGLE(RK616_PGAR_ASR_CTL, RK616_PGA_SLOW_CLK_SFT, 2, rk616_dis_en_sel),/*12*/
+SOC_ENUM_SINGLE(RK616_PGAR_ASR_CTL, RK616_PGA_ASR_SFT, 6, rk616_pga_agc_approximate_sample_rate),/*13*/
+SOC_ENUM_SINGLE(RK616_PGAR_AGC_CTL5, RK616_PGA_AGC_SFT, 2, rk616_dis_en_sel),/*14*/
+};
+
+#ifdef RK616_REG_RW
+#define REGVAL_MAX 0xffff
+static unsigned int regctl_addr = 0x08;
+
+static int rk616_regctl_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = REGVAL_MAX;
+       return 0;
+}
+
+static int rk616_regctl_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       ucontrol->value.integer.value[0] = regctl_addr;
+       ucontrol->value.integer.value[1] = snd_soc_read(codec, regctl_addr);
+       return 0;
+}
+
+static int rk616_regctl_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int reg = ucontrol->value.integer.value[0];
+       unsigned int value = ucontrol->value.integer.value[0];
+
+       if (rk616_codec_register(codec, reg) ||
+               rk616_mfd_register(reg)) {
+               regctl_addr = reg;
+               if (value <= REGVAL_MAX)
+                       snd_soc_write(codec, regctl_addr, value);
+       }
+
+       return 0;
+}
+#endif
+
+static const struct snd_kcontrol_new rk616_snd_controls[] = {
+
+       SOC_SINGLE("I2S0 schmitt input Switch", CRU_IO_CON1,
+                               3, 1, 0),
+       SOC_SINGLE("I2S1 schmitt input Switch", CRU_IO_CON1,
+                               4, 1, 0),
+       SOC_SINGLE("I2S0 output Switch", CRU_IO_CON0,
+                               12, 1, 0),
+       SOC_SINGLE("I2S1 output Switch", CRU_IO_CON0,
+                               13, 1, 0),
+
+       SOC_DOUBLE_R_TLV("SPKOUT Playback Volume", RK616_SPKL_CTL,
+               RK616_SPKR_CTL, RK616_VOL_SFT, 31, 0, out_vol_tlv),
+       SOC_DOUBLE_R("SPKOUT Playback Switch", RK616_SPKL_CTL,
+               RK616_SPKR_CTL, RK616_MUTE_SFT, 1, 1),
+
+       SOC_DOUBLE_R_TLV("HPOUT Playback Volume", RK616_HPL_CTL,
+               RK616_HPR_CTL, RK616_VOL_SFT, 31, 0, out_vol_tlv),
+       SOC_DOUBLE_R("HPOUT Playback Switch", RK616_HPL_CTL,
+               RK616_HPR_CTL, RK616_MUTE_SFT, 1, 1),
+
+       SOC_SINGLE_TLV("LINEOUT1 Playback Volume", RK616_LINEOUT1_CTL,
+               RK616_LINEOUT_VOL_SFT, 31, 0, out_vol_tlv),
+       SOC_SINGLE("LINEOUT1 Playback Switch", RK616_LINEOUT1_CTL,
+               RK616_LINEOUT_MUTE_SFT, 1, 1),
+       SOC_SINGLE_TLV("LINEOUT2 Playback Volume", RK616_LINEOUT2_CTL,
+               RK616_LINEOUT_VOL_SFT, 31, 0, out_vol_tlv),
+       SOC_SINGLE("LINEOUT2 Playback Switch", RK616_LINEOUT2_CTL,
+               RK616_LINEOUT_MUTE_SFT, 1, 1),
+
+       SOC_SINGLE_TLV("PGAL Capture Volume", RK616_PGAL_CTL,
+               RK616_PGA_VOL_SFT, 31, 0, pga_vol_tlv),//0x0a bit 5 is 0
+       SOC_SINGLE("PGAL Capture Switch", RK616_PGAL_CTL,
+               RK616_PGA_MUTE_SFT, 1, 1),
+       SOC_SINGLE_TLV("PGAR Capture Volume", RK616_PGAR_CTL,
+               RK616_PGA_VOL_SFT, 31, 0, pga_vol_tlv),//0x0a bit 4 is 0
+       SOC_SINGLE("PGAR Capture Switch", RK616_PGAR_CTL,
+               RK616_PGA_MUTE_SFT, 1, 1),
+
+       SOC_SINGLE_TLV("DIFFIN Capture Volume", RK616_DIFFIN_CTL,
+               RK616_DIFFIN_GAIN_SFT, 1, 0, bst_vol_tlv),
+       SOC_SINGLE("DIFFIN Capture Switch", RK616_DIFFIN_CTL,
+               RK616_DIFFIN_MUTE_SFT, 1, 1),
+
+       SOC_SINGLE_TLV("BST_L Capture Volume", RK616_BST_CTL,
+               RK616_BSTL_GAIN_SFT, 1, 0, bst_vol_tlv),
+       SOC_SINGLE("BST_L Capture Switch", RK616_BST_CTL,
+               RK616_BSTL_MUTE_SFT, 1, 1),
+       SOC_SINGLE_TLV("BST_R Capture Volume", RK616_BST_CTL,
+               RK616_BSTR_GAIN_SFT, 1, 0, bst_vol_tlv),
+       SOC_SINGLE("BST_R Capture Switch", RK616_BST_CTL,
+               RK616_BSTR_MUTE_SFT, 1, 1),
+
+       SOC_ENUM("BST_L Mode",  rk616_bst_enum[0]),
+       SOC_ENUM("BST_R Mode",  rk616_bst_enum[1]),
+       SOC_ENUM("DIFFIN Mode",  rk616_diffin_enum),
+
+
+       SOC_SINGLE_TLV("MUXMIC to MIXINL Volume", RK616_MIXINL_VOL1,
+               RK616_MIL_F_MUX_VOL_SFT, 7, 0, mix_vol_tlv),
+       SOC_SINGLE_TLV("IN1P to MIXINL Volume", RK616_MIXINL_VOL1,
+               RK616_MIL_F_IN1P_VOL_SFT, 7, 0, mix_vol_tlv),
+       SOC_SINGLE_TLV("IN3L to MIXINL Volume", RK616_MIXINL_VOL2,
+               RK616_MIL_F_IN3L_VOL_SFT, 7, 0, mix_vol_tlv),
+
+       SOC_SINGLE_TLV("MIXINR MUX to MIXINR Volume", RK616_MIXINR_VOL1,
+               RK616_MIR_F_MIRM_VOL_SFT, 7, 0, mix_vol_tlv),
+       SOC_SINGLE_TLV("IN3R to MIXINR Volume", RK616_MIXINR_VOL1,
+               RK616_MIR_F_IN3R_VOL_SFT, 7, 0, mix_vol_tlv),
+       SOC_SINGLE_TLV("MIC2N to MIXINR Volume", RK616_MIXINR_VOL2,
+               RK616_MIR_F_MIC2N_VOL_SFT, 7, 0, mix_vol_tlv),
+       SOC_SINGLE_TLV("IN1P to MIXINR Volume", RK616_MIXINR_VOL2,
+               RK616_MIR_F_IN1P_VOL_SFT, 7, 0, mix_vol_tlv),
+
+       SOC_SINGLE("MIXINL Switch", RK616_MIXINL_CTL,
+               RK616_MIL_MUTE_SFT, 1, 1),
+       SOC_SINGLE("MIXINR Switch", RK616_MIXINR_CTL,
+               RK616_MIR_MUTE_SFT, 1, 1),
+
+       SOC_SINGLE_TLV("IN1P to HPMIXL Volume", RK616_HPMIX_VOL1,
+               RK616_HML_F_IN1P_VOL_SFT, 7, 0, mix_vol_tlv),
+       SOC_SINGLE_TLV("HPMIX MUX to HPMIXL Volume", RK616_HPMIX_VOL2,
+               RK616_HML_F_HMM_VOL_SFT, 7, 0, mix_vol_tlv),
+       SOC_SINGLE_TLV("HPMIX MUX to MIXINR Volume", RK616_HPMIX_VOL2,
+               RK616_HMR_F_HMM_VOL_SFT, 7, 0, mix_vol_tlv),
+
+       SOC_ENUM("Micbias1 Voltage",  rk616_micbias_enum[0]),
+       SOC_ENUM("Micbias2 Voltage ",  rk616_micbias_enum[1]),
+
+       SOC_ENUM("MIC1 Key Detection Enable",  rk616_mickey_enum[0]),
+       SOC_ENUM("MIC2 Key Detection Enable",  rk616_mickey_enum[1]),
+       SOC_ENUM("MIC1 Key Range",  rk616_mickey_enum[2]),
+       SOC_ENUM("MIC2 Key Range",  rk616_mickey_enum[3]),
+
+
+       SOC_ENUM("PGAL Gain Control",  rk616_agcl_enum[0]),
+       SOC_ENUM("PGAL AGC Way",  rk616_agcl_enum[1]),
+       SOC_ENUM("PGAL AGC Hold Time",  rk616_agcl_enum[2]),
+       SOC_ENUM("PGAL AGC Ramp Up Time",  rk616_agcl_enum[3]),
+       SOC_ENUM("PGAL AGC Ramp Down Time",  rk616_agcl_enum[4]),
+       SOC_ENUM("PGAL AGC Mode",  rk616_agcl_enum[5]),
+       SOC_ENUM("PGAL AGC Gain Update Zero Enable",  rk616_agcl_enum[6]),
+       SOC_ENUM("PGAL AGC Gain Recovery LPGA VOL",  rk616_agcl_enum[7]),
+       SOC_ENUM("PGAL AGC Fast Decrement Enable",  rk616_agcl_enum[8]),
+       SOC_ENUM("PGAL AGC Noise Gate Enable",  rk616_agcl_enum[9]),
+       SOC_ENUM("PGAL AGC Noise Gate Threhold",  rk616_agcl_enum[10]),
+       SOC_ENUM("PGAL AGC Upate Gain",  rk616_agcl_enum[11]),
+       SOC_ENUM("PGAL AGC Slow Clock Enable",  rk616_agcl_enum[12]),
+       SOC_ENUM("PGAL AGC Approximate Sample Rate",  rk616_agcl_enum[13]),
+       SOC_ENUM("PGAL AGC Enable",  rk616_agcl_enum[14]),
+
+       SOC_SINGLE_TLV("PGAL AGC Volume", RK616_PGAL_AGC_CTL4,
+               RK616_PGA_AGC_VOL_SFT, 31, 0, pga_vol_tlv),//AGC disable and 0x0a bit 5 is 1
+
+       SOC_SINGLE("PGAL AGC Max Level High 8 Bits", RK616_PGAL_AGC_MAX_H,
+               0, 255, 0),
+       SOC_SINGLE("PGAL AGC Max Level Low 8 Bits", RK616_PGAL_AGC_MAX_L,
+               0, 255, 0),
+       SOC_SINGLE("PGAL AGC Min Level High 8 Bits", RK616_PGAL_AGC_MIN_H,
+               0, 255, 0),
+       SOC_SINGLE("PGAL AGC Min Level Low 8 Bits", RK616_PGAL_AGC_MIN_L,
+               0, 255, 0),
+
+       SOC_SINGLE_TLV("PGAL AGC Max Gain", RK616_PGAL_AGC_CTL5,
+               RK616_PGA_AGC_MAX_G_SFT, 7, 0, pga_agc_max_vol_tlv),//AGC enable and 0x0a bit 5 is 1
+       SOC_SINGLE_TLV("PGAL AGC Min Gain", RK616_PGAL_AGC_CTL5,
+               RK616_PGA_AGC_MIN_G_SFT, 7, 0, pga_agc_min_vol_tlv),//AGC enable and 0x0a bit 5 is 1
+
+       SOC_ENUM("PGAR Gain Control",  rk616_agcr_enum[0]),
+       SOC_ENUM("PGAR AGC Way",  rk616_agcr_enum[1]),
+       SOC_ENUM("PGAR AGC Hold Time",  rk616_agcr_enum[2]),
+       SOC_ENUM("PGAR AGC Ramp Up Time",  rk616_agcr_enum[3]),
+       SOC_ENUM("PGAR AGC Ramp Down Time",  rk616_agcr_enum[4]),
+       SOC_ENUM("PGAR AGC Mode",  rk616_agcr_enum[5]),
+       SOC_ENUM("PGAR AGC Gain Update Zero Enable",  rk616_agcr_enum[6]),
+       SOC_ENUM("PGAR AGC Gain Recovery LPGA VOL",  rk616_agcr_enum[7]),
+       SOC_ENUM("PGAR AGC Fast Decrement Enable",  rk616_agcr_enum[8]),
+       SOC_ENUM("PGAR AGC Noise Gate Enable",  rk616_agcr_enum[9]),
+       SOC_ENUM("PGAR AGC Noise Gate Threhold",  rk616_agcr_enum[10]),
+       SOC_ENUM("PGAR AGC Upate Gain",  rk616_agcr_enum[11]),
+       SOC_ENUM("PGAR AGC Slow Clock Enable",  rk616_agcr_enum[12]),
+       SOC_ENUM("PGAR AGC Approximate Sample Rate",  rk616_agcr_enum[13]),
+       SOC_ENUM("PGAR AGC Enable",  rk616_agcr_enum[14]),
+
+       SOC_SINGLE_TLV("PGAR AGC Volume", RK616_PGAR_AGC_CTL4,
+               RK616_PGA_AGC_VOL_SFT, 31, 0, pga_vol_tlv),//AGC disable and 0x0a bit 4 is 1
+
+       SOC_SINGLE("PGAR AGC Max Level High 8 Bits", RK616_PGAR_AGC_MAX_H,
+               0, 255, 0),
+       SOC_SINGLE("PGAR AGC Max Level Low 8 Bits", RK616_PGAR_AGC_MAX_L,
+               0, 255, 0),
+       SOC_SINGLE("PGAR AGC Min Level High 8 Bits", RK616_PGAR_AGC_MIN_H,
+               0, 255, 0),
+       SOC_SINGLE("PGAR AGC Min Level Low 8 Bits", RK616_PGAR_AGC_MIN_L,
+               0, 255, 0),
+
+       SOC_SINGLE_TLV("PGAR AGC Max Gain", RK616_PGAR_AGC_CTL5,
+               RK616_PGA_AGC_MAX_G_SFT, 7, 0, pga_agc_max_vol_tlv),//AGC enable and 0x06 bit 4 is 1
+       SOC_SINGLE_TLV("PGAR AGC Min Gain", RK616_PGAR_AGC_CTL5,
+               RK616_PGA_AGC_MIN_G_SFT, 7, 0, pga_agc_min_vol_tlv),//AGC enable and 0x06 bit 4 is 1
+
+#ifdef RK616_REG_RW
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Register Control",
+               .info = rk616_regctl_info,
+               .get = rk616_regctl_get,
+               .put = rk616_regctl_put,
+       },
+#endif
+};
+
+static int rk616_dacl_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_update_bits(codec, RK616_DAC_CTL,
+                       RK616_DACL_PWRD | RK616_DACL_CLK_PWRD, 0);
+               break;
+
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, RK616_DAC_CTL,
+                       RK616_DACL_PWRD | RK616_DACL_CLK_PWRD,
+                       RK616_DACL_PWRD | RK616_DACL_CLK_PWRD);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int rk616_dacr_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_update_bits(codec, RK616_DAC_CTL,
+                       RK616_DACR_PWRD | RK616_DACR_CLK_PWRD, 0);
+               break;
+
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, RK616_DAC_CTL,
+                       RK616_DACR_PWRD | RK616_DACR_CLK_PWRD,
+                       RK616_DACR_PWRD | RK616_DACR_CLK_PWRD);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int rk616_adcl_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_update_bits(codec, RK616_ADC_CTL,
+                       RK616_ADCL_CLK_PWRD | RK616_ADCL_PWRD, 0);
+               break;
+
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, RK616_ADC_CTL,
+                       RK616_ADCL_CLK_PWRD | RK616_ADCL_PWRD,
+                       RK616_ADCL_CLK_PWRD | RK616_ADCL_PWRD);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+static int rk616_adcr_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               snd_soc_update_bits(codec, RK616_ADC_CTL,
+                       RK616_ADCR_CLK_PWRD | RK616_ADCR_PWRD, 0);
+               break;
+
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_update_bits(codec, RK616_ADC_CTL,
+                       RK616_ADCR_CLK_PWRD | RK616_ADCR_PWRD,
+                       RK616_ADCR_CLK_PWRD | RK616_ADCR_PWRD);
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 0;
+}
+
+/* Mixin */
+static const struct snd_kcontrol_new rk616_mixinl[] = {
+       SOC_DAPM_SINGLE("IN3L Switch", RK616_MIXINL_CTL,
+                               RK616_MIL_F_IN3L_SFT, 1, 1),
+       SOC_DAPM_SINGLE("IN1P Switch", RK616_MIXINL_CTL,
+                               RK616_MIL_F_IN1P_SFT, 1, 1),
+       SOC_DAPM_SINGLE("MUXMIC Switch", RK616_MIXINL_CTL,
+                               RK616_MIL_F_MUX_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rk616_mixinr[] = {
+       SOC_DAPM_SINGLE("MIC2N Switch", RK616_MIXINR_CTL,
+                               RK616_MIR_F_MIC2N_SFT, 1, 1),
+       SOC_DAPM_SINGLE("IN1P Switch", RK616_MIXINL_CTL,
+                               RK616_MIR_F_IN1P_SFT, 1, 1),
+       SOC_DAPM_SINGLE("IN3R Switch", RK616_MIXINL_CTL,
+                               RK616_MIR_F_IN3R_SFT, 1, 1),
+       SOC_DAPM_SINGLE("MIXINR Mux Switch", RK616_MIXINL_CTL,
+                               RK616_MIR_F_MIRM_SFT, 1, 1),
+};
+
+/* Linemix */
+static const struct snd_kcontrol_new rk616_linemix[] = {
+       SOC_DAPM_SINGLE("PGAR Switch", RK616_LINEMIX_CTL,
+                               RK616_LM_F_PGAR_SFT, 1, 1),
+       SOC_DAPM_SINGLE("PGAL Switch", RK616_LINEMIX_CTL,
+                               RK616_LM_F_PGAL_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DACR Switch", RK616_LINEMIX_CTL,
+                               RK616_LM_F_DACR_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DACL Switch", RK616_LINEMIX_CTL,
+                               RK616_LM_F_DACL_SFT, 1, 1),
+};
+
+/* HPmix */
+static const struct snd_kcontrol_new rk616_hpmixl[] = {
+       SOC_DAPM_SINGLE("HPMix Mux Switch", RK616_HPMIX_CTL,
+                               RK616_HML_F_HMM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("IN1P Switch", RK616_HPMIX_CTL,
+                               RK616_HML_F_IN1P_SFT, 1, 1),
+       SOC_DAPM_SINGLE("PGAL Switch", RK616_HPMIX_CTL,
+                               RK616_HML_F_PGAL_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DACL Switch", RK616_HPMIX_CTL,
+                               RK616_HML_F_DACL_SFT, 1, 1),
+};
+
+static const struct snd_kcontrol_new rk616_hpmixr[] = {
+       SOC_DAPM_SINGLE("HPMix Mux Switch", RK616_HPMIX_CTL,
+                               RK616_HMR_F_HMM_SFT, 1, 1),
+       SOC_DAPM_SINGLE("PGAR Switch", RK616_HPMIX_CTL,
+                               RK616_HMR_F_PGAR_SFT, 1, 1),
+       SOC_DAPM_SINGLE("PGAL Switch", RK616_HPMIX_CTL,
+                               RK616_HMR_F_PGAL_SFT, 1, 1),
+       SOC_DAPM_SINGLE("DACR Switch", RK616_HPMIX_CTL,
+                               RK616_HMR_F_DACR_SFT, 1, 1),
+};
+
+/* HP MUX */
+static const char *hpl_sel[] = {"HPMIXL", "DACL"};
+
+static const struct soc_enum hpl_sel_enum =
+       SOC_ENUM_SINGLE(RK616_MUXHP_HPMIX_CTL, RK616_MHL_F_SFT,
+                       ARRAY_SIZE(hpl_sel), hpl_sel);
+
+static const struct snd_kcontrol_new hpl_sel_mux =
+       SOC_DAPM_ENUM("HPL select Mux", hpl_sel_enum);
+
+static const char *hpr_sel[] = {"HPMIXR", "DACR"};
+
+static const struct soc_enum hpr_sel_enum =
+       SOC_ENUM_SINGLE(RK616_MUXHP_HPMIX_CTL, RK616_MHR_F_SFT,
+                       ARRAY_SIZE(hpr_sel), hpr_sel);
+
+static const struct snd_kcontrol_new hpr_sel_mux =
+       SOC_DAPM_ENUM("HPR select Mux", hpr_sel_enum);
+
+/* MIC MUX */
+static const char *mic_sel[] = {"BSTL", "BSTR"};
+
+static const struct soc_enum mic_sel_enum =
+       SOC_ENUM_SINGLE(RK616_MIXINL_CTL, RK616_MM_F_SFT,
+                       ARRAY_SIZE(mic_sel), mic_sel);
+
+static const struct snd_kcontrol_new mic_sel_mux =
+       SOC_DAPM_ENUM("Mic select Mux", mic_sel_enum);
+
+/* MIXINR MUX */
+static const char *mixinr_sel[] = {"DIFFIN", "IN1N"};
+
+static const struct soc_enum mixinr_sel_enum =
+       SOC_ENUM_SINGLE(RK616_DIFFIN_CTL, RK616_MIRM_F_SFT,
+                       ARRAY_SIZE(mixinr_sel), mixinr_sel);
+
+static const struct snd_kcontrol_new mixinr_sel_mux =
+       SOC_DAPM_ENUM("Mixinr select Mux", mixinr_sel_enum);
+
+/* HPMIX MUX */
+static const char *hpmix_sel[] = {"DIFFIN", "IN1N"};
+
+static const struct soc_enum hpmix_sel_enum =
+       SOC_ENUM_SINGLE(RK616_DIFFIN_CTL, RK616_HMM_F_SFT,
+                       ARRAY_SIZE(hpmix_sel), hpmix_sel);
+
+static const struct snd_kcontrol_new hpmix_sel_mux =
+       SOC_DAPM_ENUM("HPMix select Mux", hpmix_sel_enum);
+
+
+static const struct snd_soc_dapm_widget rk616_dapm_widgets[] = {
+       /* supply */
+       SND_SOC_DAPM_SUPPLY("I2S0 Interface", CRU_IO_CON0,
+                               3, 1, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("I2S1 Interface", CRU_IO_CON0,
+                               4, 1, NULL, 0),
+
+       /* microphone bias */
+       SND_SOC_DAPM_MICBIAS("Mic1 Bias", RK616_MICBIAS_CTL,
+                                       RK616_MICBIAS1_PWRD_SFT, 1),
+       SND_SOC_DAPM_MICBIAS("Mic2 Bias", RK616_MICBIAS_CTL,
+                                       RK616_MICBIAS2_PWRD_SFT, 1),
+
+       /* DACs */
+       SND_SOC_DAPM_SUPPLY("DAC", RK616_PWR_ADD2,
+                               RK616_DAC_PWRD_SFT, 1, NULL, 0),
+       SND_SOC_DAPM_ADC_E("DAC L", NULL, SND_SOC_NOPM,
+               0, 0, rk616_dacl_event,
+               SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_ADC_E("DAC R", NULL, SND_SOC_NOPM,
+               0, 0, rk616_dacr_event,
+               SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+
+       /* ADCs */
+       SND_SOC_DAPM_SUPPLY("ADC", RK616_PWR_ADD1,
+                               RK616_ADC_PWRD_SFT, 1, NULL, 0),
+       SND_SOC_DAPM_ADC_E("ADC L", NULL, SND_SOC_NOPM,
+               0, 0, rk616_adcl_event,
+               SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_ADC_E("ADC R", NULL, SND_SOC_NOPM,
+               0, 0, rk616_adcr_event,
+               SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+
+       /* PGA */
+       SND_SOC_DAPM_PGA("BSTL", RK616_BST_CTL,
+               RK616_BSTL_PWRD_SFT, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("BSTR", RK616_BST_CTL,
+               RK616_BSTR_PWRD_SFT, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("DIFFIN", RK616_DIFFIN_CTL,
+               RK616_DIFFIN_PWRD, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("PGAL", RK616_PGAL_CTL,
+               RK616_PGA_PWRD, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("PGAR", RK616_PGAR_CTL,
+               RK616_PGA_PWRD, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("SPKL", RK616_SPKL_CTL,
+               RK616_PWRD_SFT, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("SPKR", RK616_SPKR_CTL,
+               RK616_PWRD_SFT, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("HPL", RK616_HPL_CTL,
+               RK616_PWRD_SFT, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("HPR", RK616_HPR_CTL,
+               RK616_PWRD_SFT, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("LINE1", RK616_LINEOUT1_CTL,
+               RK616_LINEOUT_PWRD, 1, NULL, 0),
+       SND_SOC_DAPM_PGA("LINE2", RK616_LINEOUT2_CTL,
+               RK616_LINEOUT_PWRD, 1, NULL, 0),
+
+       /* MIXER */
+       SND_SOC_DAPM_MIXER("MIXINL", RK616_MIXINL_CTL,
+               RK616_MIL_PWRD_SFT, 1, rk616_mixinl,
+               ARRAY_SIZE(rk616_mixinl)),
+       SND_SOC_DAPM_MIXER("MIXINR", RK616_MIXINR_CTL,
+               RK616_MIR_PWRD_SFT, 1, rk616_mixinr,
+               ARRAY_SIZE(rk616_mixinr)),
+       SND_SOC_DAPM_MIXER("LINEMIX", RK616_LINEMIX_CTL,
+               RK616_LM_PWRD_SFT, 1, rk616_linemix,
+               ARRAY_SIZE(rk616_linemix)),
+       SND_SOC_DAPM_MIXER("HPMIXL", RK616_MUXHP_HPMIX_CTL,
+               RK616_HML_PWRD_SFT, 1, rk616_hpmixl,
+               ARRAY_SIZE(rk616_hpmixl)),
+       SND_SOC_DAPM_MIXER("HPMIXR", RK616_MUXHP_HPMIX_CTL,
+               RK616_HMR_PWRD_SFT, 1, rk616_hpmixr,
+               ARRAY_SIZE(rk616_hpmixr)),
+
+       /* MUX */
+       SND_SOC_DAPM_MUX("HPL Mux", SND_SOC_NOPM, 0, 0,
+                               &hpl_sel_mux),
+       SND_SOC_DAPM_MUX("HPR Mux", SND_SOC_NOPM, 0, 0,
+                               &hpr_sel_mux),
+       SND_SOC_DAPM_MUX("Mic Mux", SND_SOC_NOPM, 0, 0,
+                               &mic_sel_mux),
+       SND_SOC_DAPM_MUX("MIXINR Mux", SND_SOC_NOPM, 0, 0,
+                               &mixinr_sel_mux),
+       SND_SOC_DAPM_MUX("HPMix Mux", SND_SOC_NOPM, 0, 0,
+                               &hpmix_sel_mux),
+
+       /* Audio Interface */
+       SND_SOC_DAPM_AIF_IN("I2S0 DAC", "HIFI Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("I2S0 ADC", "HIFI Capture", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_IN("I2S1 DAC", "VOICE Playback", 0, SND_SOC_NOPM, 0, 0),
+       SND_SOC_DAPM_AIF_OUT("I2S1 ADC", "VOICE Capture", 0, SND_SOC_NOPM, 0, 0),
+
+       /* Input */
+       SND_SOC_DAPM_INPUT("IN3L"),
+       SND_SOC_DAPM_INPUT("IN3R"),
+       SND_SOC_DAPM_INPUT("IN1P"),
+       SND_SOC_DAPM_INPUT("IN1N"),
+       SND_SOC_DAPM_INPUT("MIC2P"),
+       SND_SOC_DAPM_INPUT("MIC2N"),
+       SND_SOC_DAPM_INPUT("MIC1P"),
+       SND_SOC_DAPM_INPUT("MIC1N"),
+
+       /* Output */
+       SND_SOC_DAPM_OUTPUT("SPKOUTL"),
+       SND_SOC_DAPM_OUTPUT("SPKOUTR"),
+       SND_SOC_DAPM_OUTPUT("HPOUTL"),
+       SND_SOC_DAPM_OUTPUT("HPOUTR"),
+       SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+       SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+};
+
+static const struct snd_soc_dapm_route rk616_dapm_routes[] = {
+       {"I2S0 DAC", NULL, "I2S0 Interface"},
+       {"I2S0 ADC", NULL, "I2S0 Interface"},
+       {"I2S1 DAC", NULL, "I2S1Interface"},
+       {"I2S1 ADC", NULL, "I2S1Interface"},
+
+       /* Input */
+       {"DIFFIN", NULL, "IN1P"},
+       {"DIFFIN", NULL, "IN1N"},
+
+       {"BSTR", NULL, "MIC2P"},
+       {"BSTR", NULL, "MIC2N"},
+
+       {"BSTL", NULL, "MIC1P"},
+       {"BSTL", NULL, "MIC1N"},
+
+       {"HPMix Mux", "DIFFIN", "DIFFIN"},
+       {"HPMix Mux", "IN1N", "IN1N"},
+
+       {"MIXINR Mux", "DIFFIN", "DIFFIN"},
+       {"MIXINR Mux", "IN1N", "IN1N"},
+
+       {"Mic Mux", "BSTR", "BSTR"},
+       {"Mic Mux", "BSTL", "BSTL"},
+
+       {"MIXINR", "MIC2N Switch", "MIC2N"},
+       {"MIXINR", "IN1P Switch", "IN1P"},
+       {"MIXINR", "IN3R Switch", "IN3R"},
+       {"MIXINR", "MIXINR Mux Switch", "MIXINR Mux"},
+
+       {"MIXINL", "IN3L Switch", "IN3L"},
+       {"MIXINL", "IN1P Switch", "IN1P"},
+       {"MIXINL", "MUXMIC Switch", "Mic Mux"},
+
+       {"PGAR", NULL, "MIXINR"},
+       {"PGAL", NULL, "MIXINL"},
+
+       {"ADCR", NULL, "PGAR"},
+       {"ADCL", NULL, "PGAL"},
+
+       {"ADC", NULL, "ADCR"},
+       {"ADC", NULL, "ADCL"},
+
+       {"I2S0 ADC", NULL, "ADC"},
+       {"I2S1 ADC", NULL, "ADC"},
+
+       /* Output */
+       {"DAC", NULL, "I2S0 DAC"},
+       {"DAC", NULL, "I2S1 DAC"},
+
+       {"DACR", NULL, "DAC"},
+       {"DACL", NULL, "DAC"},
+
+       {"LINEMIX", "PGAR Switch", "PGAR"},
+       {"LINEMIX", "PGAL Switch", "PGAL"},
+       {"LINEMIX", "DACR Switch", "DACR"},
+       {"LINEMIX", "DACL Mux Switch", "DACL"},
+
+       {"HPMIXR", "HPMix Mux Switch", "HPMix Mux"},
+       {"HPMIXR", "PGAR Switch", "PGAR"},
+       {"HPMIXR", "PGAL Switch", "PGAL"},
+       {"HPMIXR", "DACR Switch", "DACR"},
+
+       {"HPMIXL", "HPMix Mux Switch", "HPMix Mux"},
+       {"HPMIXL", "IN1P Switch", "PGAR"},
+       {"HPMIXL", "PGAL Switch", "PGAL"},
+       {"HPMIXL", "DACL Switch", "DACL"},
+
+       {"HPR Mux", "DACR", "DACR"},
+       {"HPR Mux", "HPMIXR", "HPMIXR"},
+
+       {"HPL Mux", "DACL", "DACL"},
+       {"HPL Mux", "HPMIXL", "HPMIXR"},
+
+       {"LINE1", NULL, "LINEMIX"},
+       {"LINE2", NULL, "LINEMIX"},
+
+       {"SPKR", NULL, "HPR Mux"},
+       {"SPKL", NULL, "HPL Mux"},
+
+       {"HPR", NULL, "HPR Mux"},
+       {"HPL", NULL, "HPL Mux"},
+
+       {"LINEOUT1", NULL, "LINE1"},
+       {"LINEOUT2", NULL, "LINE2"},
+
+       {"SPKOUTR", NULL, "SPKR"},
+       {"SPKOUTL", NULL, "SPKL"},
+
+       {"HPOUTR", NULL, "HPR"},
+       {"HPOUTL", NULL, "HPL"},
+
+};
+
+static int rk616_set_bias_level(struct snd_soc_codec *codec,
+                                enum snd_soc_bias_level level)
+{
+       switch (level) {
+       case SND_SOC_BIAS_ON:
+               break;
+
+       case SND_SOC_BIAS_PREPARE:
+               snd_soc_update_bits(codec, RK616_MICBIAS_CTL,
+                       RK616_MICBIAS1_PWRD | RK616_MICBIAS2_PWRD, 0);
+               break;
+
+       case SND_SOC_BIAS_STANDBY:
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+                       /* set power */
+                       snd_soc_update_bits(codec, RK616_PWR_ADD1, 
+                               RK616_DIFFIN_MIR_PGAR_RLPWRD | RK616_MIC1_MIC2_MIL_PGAL_RLPWRD |
+                               RK616_ADCL_RLPWRD | RK616_ADCR_RLPWRD, 
+                               RK616_DIFFIN_MIR_PGAR_RLPWRD | RK616_MIC1_MIC2_MIL_PGAL_RLPWRD |
+                               RK616_ADCL_RLPWRD | RK616_ADCR_RLPWRD);
+
+                       snd_soc_update_bits(codec, RK616_PWR_ADD2, 
+                               RK616_HPL_HPR_PWRD | RK616_DACL_SPKL_RLPWRD |
+                               RK616_DACR_SPKR_RLPWRD | RK616_LM_LO_RLPWRD |
+                               RK616_HM_RLPWRD, 
+                               RK616_DACL_SPKL_RLPWRD | RK616_DACR_SPKR_RLPWRD |
+                               RK616_LM_LO_RLPWRD | RK616_HM_RLPWRD);
+
+                       snd_soc_update_bits(codec, RK616_PWR_ADD3, 
+                               RK616_ADCL_ZO_PWRD | RK616_ADCR_ZO_PWRD |
+                               RK616_DACL_ZO_PWRD | RK616_DACR_ZO_PWRD , 
+                               RK616_ADCL_ZO_PWRD | RK616_ADCR_ZO_PWRD |
+                               RK616_DACL_ZO_PWRD | RK616_DACR_ZO_PWRD );
+
+                       snd_soc_write(codec, RK616_MICBIAS_CTL,
+                               RK616_MICBIAS1_PWRD | RK616_MICBIAS2_PWRD |
+                               RK616_MICBIAS1_V_1_7 | RK616_MICBIAS2_V_1_7);
+               }
+               break;
+
+       case SND_SOC_BIAS_OFF:
+               snd_soc_write(codec, RK616_PWR_ADD1, 0xffff);
+               snd_soc_write(codec, RK616_PWR_ADD2, 0xffff);
+               snd_soc_write(codec, RK616_PWR_ADD3, 0xffff);
+               snd_soc_update_bits(codec, RK616_MICBIAS_CTL,
+                       RK616_MICBIAS1_PWRD | RK616_MICBIAS2_PWRD,
+                       RK616_MICBIAS1_PWRD | RK616_MICBIAS2_PWRD);
+               break;
+       }
+
+       codec->dapm.bias_level = level;
+
+       return 0;
+}
+
+static int rk616_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+                                int clk_id, unsigned int freq, int dir)
+{
+       struct rk616_codec_priv *rk616 = rk616_priv;
+
+       if (!rk616)
+               return -EINVAL;
+
+       rk616->stereo_sysclk = freq;
+
+       return 0;
+}
+
+static int rk616_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                             unsigned int fmt)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       unsigned int adc_aif1 = 0, adc_aif2 = 0, dac_aif1 = 0, dac_aif2 = 0;
+
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               adc_aif2 |= RK616_I2S_MODE_SLV;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               adc_aif2 |= RK616_I2S_MODE_MST;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_DSP_A:
+               adc_aif1 |= RK616_ADC_DF_PCM;
+               dac_aif1 |= RK616_DAC_DF_PCM;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               adc_aif1 |= RK616_ADC_DF_I2S;
+               dac_aif1 |= RK616_DAC_DF_I2S;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               adc_aif1 |= RK616_ADC_DF_RJ;
+               dac_aif1 |= RK616_DAC_DF_RJ;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               adc_aif1 |= RK616_ADC_DF_LJ;
+               dac_aif1 |= RK616_DAC_DF_LJ;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_NF:
+               adc_aif1 |= RK616_ALRCK_POL_DIS;
+               adc_aif2 |= RK616_ABCLK_POL_DIS;
+               dac_aif1 |= RK616_DLRCK_POL_DIS;
+               dac_aif2 |= RK616_DBCLK_POL_DIS;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               adc_aif1 |= RK616_ALRCK_POL_EN;
+               adc_aif2 |= RK616_ABCLK_POL_EN;
+               dac_aif1 |= RK616_DLRCK_POL_EN;
+               dac_aif2 |= RK616_DBCLK_POL_EN;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               adc_aif1 |= RK616_ALRCK_POL_DIS;
+               adc_aif2 |= RK616_ABCLK_POL_EN;
+               dac_aif1 |= RK616_DLRCK_POL_DIS;
+               dac_aif2 |= RK616_DBCLK_POL_EN;
+               break;
+       case SND_SOC_DAIFMT_NB_IF:
+               adc_aif1 |= RK616_ALRCK_POL_EN;
+               adc_aif2 |= RK616_ABCLK_POL_DIS;
+               dac_aif1 |= RK616_DLRCK_POL_EN;
+               dac_aif2 |= RK616_DBCLK_POL_DIS;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_update_bits(codec, RK616_ADC_INT_CTL1,
+                       RK616_ALRCK_POL_MASK | RK616_ADC_DF_MASK, adc_aif1);
+       snd_soc_update_bits(codec, RK616_ADC_INT_CTL2,
+                       RK616_ABCLK_POL_MASK | RK616_I2S_MODE_MASK, adc_aif2);
+       snd_soc_update_bits(codec, RK616_DAC_INT_CTL1,
+                       RK616_DLRCK_POL_MASK | RK616_DAC_DF_MASK, dac_aif1);
+       snd_soc_update_bits(codec, RK616_DAC_INT_CTL2,
+                       RK616_DBCLK_POL_MASK, dac_aif2);
+
+       return 0;
+}
+
+static int rk616_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec *codec =rtd->codec;
+       struct rk616_codec_priv *rk616 = rk616_priv;
+       unsigned int rate = params_rate(params);
+       unsigned int div;
+       unsigned int adc_aif1 = 0, adc_aif2  = 0, dac_aif1 = 0, dac_aif2  = 0;
+       u32 mfd_aif1 = 0, mfd_aif2 = 0;
+
+       if (!rk616)
+               return -EINVAL;
+
+       if (rk616->stereo_sysclk % rate > 0) {
+               dev_err(codec->dev, "need PLL");
+               return -EINVAL;
+       }
+
+       div = (rk616->stereo_sysclk / rate) - 1;
+
+       dev_dbg(codec->dev, "MCLK = %dHz, sample rate = %dHz, div = %d\n",
+               rk616->stereo_sysclk, rate, div);
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               adc_aif1 |= RK616_ADC_VWL_16;
+               adc_aif2 |= RK616_ADC_WL_16;
+               dac_aif1 |= RK616_DAC_VWL_16;
+               dac_aif2 |= RK616_DAC_WL_16;
+               break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               adc_aif1 |= RK616_ADC_VWL_20;
+               adc_aif2 |= RK616_ADC_WL_20;
+               dac_aif1 |= RK616_DAC_VWL_20;
+               dac_aif2 |= RK616_DAC_WL_20;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               adc_aif1 |= RK616_ADC_VWL_24;
+               adc_aif2 |= RK616_ADC_WL_24;
+               dac_aif1 |= RK616_DAC_VWL_24;
+               dac_aif2 |= RK616_DAC_WL_24;
+               break;
+       case SNDRV_PCM_FORMAT_S32_LE:
+               adc_aif1 |= RK616_ADC_VWL_32;
+               adc_aif2 |= RK616_ADC_WL_32;
+               dac_aif1 |= RK616_DAC_VWL_32;
+               dac_aif2 |= RK616_DAC_WL_32;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       switch (params_channels(params)) {
+       case RK616_MONO:
+               adc_aif1 |= RK616_I2S_TYPE_MONO;
+               break;
+       case RK616_STEREO:
+               adc_aif1 |= RK616_I2S_TYPE_STEREO;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       adc_aif1 |= RK616_ADC_SWAP_DIS;
+       adc_aif2 |= RK616_ADC_RST_DIS;
+       dac_aif1 |= RK616_DAC_SWAP_DIS;
+       dac_aif2 |= RK616_DAC_RST_DIS;
+
+       rk616->rate = rate;
+
+       snd_soc_write(codec, CRU_CODEC_DIV, div);//(lrclk = mclk / div + 1)
+
+       snd_soc_update_bits(codec, RK616_ADC_INT_CTL1,
+                        RK616_ADC_VWL_MASK | RK616_ADC_SWAP_MASK |
+                        RK616_I2S_TYPE_MASK, adc_aif1);
+       snd_soc_update_bits(codec, RK616_ADC_INT_CTL2,
+                       RK616_ADC_WL_MASK | RK616_ADC_RST_MASK, adc_aif2);
+       snd_soc_update_bits(codec, RK616_DAC_INT_CTL1,
+                        RK616_DAC_VWL_MASK | RK616_DAC_SWAP_MASK, dac_aif1);
+       snd_soc_update_bits(codec, RK616_DAC_INT_CTL2,
+                       RK616_DAC_WL_MASK | RK616_DAC_RST_MASK, dac_aif2);
+
+       switch (dai->id) {
+       case RK616_HIFI:
+               mfd_aif1 |= (I2S0_OUT_EN | I2S1_PD_DISABLE) |
+                       ((I2S1_OUT_EN | I2S0_OUT_EN |
+                       I2S1_PD_DISABLE | I2S0_PD_DISABLE) << 16);
+               mfd_aif2 |= I2S0_SI_EN | ((I2S1_SI_EN | I2S0_SI_EN) << 16);
+               break;
+       case RK616_VOICE:
+               mfd_aif1 |= (I2S1_OUT_EN | I2S0_PD_DISABLE) |
+                       ((I2S1_OUT_EN | I2S0_OUT_EN |
+                       I2S1_PD_DISABLE | I2S0_PD_DISABLE) << 16);
+               mfd_aif2 |= I2S1_SI_EN | ((I2S1_SI_EN | I2S0_SI_EN) << 16);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       snd_soc_write(codec, CRU_IO_CON0, mfd_aif1);
+       snd_soc_write(codec, CRU_IO_CON1, mfd_aif2);
+
+       return 0;
+}
+
+#ifdef RK616_FOR_MID
+static int rk616_trigger(struct snd_pcm_substream *substream,
+                         int cmd,
+                         struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_codec *codec = rtd->codec;
+       struct rk616_codec_priv *rk616 = rk616_priv;
+       bool playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+       bool is_codec_running = rk616->playback_active > 0 || rk616->capture_active > 0;
+
+       if (!rk616)
+               return -EINVAL;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (playback)
+                       rk616->playback_active++;
+               else
+                       rk616->capture_active++;
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (playback)
+                       rk616->playback_active--;
+               else
+                       rk616->capture_active--;
+               break;
+
+       default:
+               return 0;
+               break;
+       }
+
+       if (rk616->playback_active > 0 || rk616->capture_active > 0){
+               if (is_codec_running == false) {
+                       rk616_reg_init(codec);
+               }
+       } else {
+               if (is_codec_running == true) {
+                       rk616_reset(codec);
+               }
+       }
+
+       return 0;
+}
+#endif
+
+#define RK616_PLAYBACK_RATES (SNDRV_PCM_RATE_8000 |\
+                             SNDRV_PCM_RATE_16000 |    \
+                             SNDRV_PCM_RATE_32000 |    \
+                             SNDRV_PCM_RATE_44100 |    \
+                             SNDRV_PCM_RATE_48000 |    \
+                             SNDRV_PCM_RATE_96000)
+
+#define RK616_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\
+                             SNDRV_PCM_RATE_16000 |    \
+                             SNDRV_PCM_RATE_32000 |    \
+                             SNDRV_PCM_RATE_44100 |    \
+                             SNDRV_PCM_RATE_48000 |    \
+                             SNDRV_PCM_RATE_96000)
+
+#define RK616_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+                       SNDRV_PCM_FMTBIT_S20_3LE |\
+                       SNDRV_PCM_FMTBIT_S24_LE |\
+                       SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops rk616_dai_ops = {
+       .hw_params      = rk616_hw_params,
+       .set_fmt        = rk616_set_dai_fmt,
+       .set_sysclk     = rk616_set_dai_sysclk,
+#ifdef RK616_FOR_MID
+       .trigger = rk616_trigger,
+#endif
+};
+
+static struct snd_soc_dai_driver rk616_dai[] = {
+       {
+               .name = "rk616-hifi",
+               .id = RK616_HIFI,
+               .playback = {
+                       .stream_name = "HiFi Playback",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = RK616_PLAYBACK_RATES,
+                       .formats = RK616_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "HiFi Capture",
+                       .channels_min = 2,
+                       .channels_max = 2,
+                       .rates = RK616_CAPTURE_RATES,
+                       .formats = RK616_FORMATS,
+               },
+               .ops = &rk616_dai_ops,
+       },
+       {
+               .name = "rk616-voice",
+               .id = RK616_VOICE,
+               .playback = {
+                       .stream_name = "Voice Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RK616_PLAYBACK_RATES,
+                       .formats = RK616_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "Voice Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = RK616_CAPTURE_RATES,
+                       .formats = RK616_FORMATS,
+               },
+               .ops = &rk616_dai_ops,
+       },
+
+};
+
+static int rk616_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+       rk616_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+       return 0;
+}
+
+static int rk616_resume(struct snd_soc_codec *codec)
+{
+       rk616_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+       return 0;
+}
+
+#ifdef RK616_PROC      
+static int rk616_proc_init(void);
+#endif
+
+static int rk616_probe(struct snd_soc_codec *codec)
+{
+       struct rk616_codec_priv *rk616;
+       int ret;
+       unsigned int val;
+
+       rk616 = kzalloc(sizeof(struct rk616_codec_priv), GFP_KERNEL);
+       if (rk616 == NULL)
+               return -ENOMEM;
+
+       rk616->codec = codec;
+
+#ifdef RK616_FOR_MID
+       rk616->playback_active = 0;
+       rk616->capture_active = 0;
+#endif
+
+       rk616_priv = rk616;
+
+       ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               goto err__;
+       }
+
+       codec->hw_read = rk616_codec_read;
+       codec->hw_write = (hw_write_t)rk616_hw_write;
+       codec->read = rk616_codec_read;
+       codec->write = rk616_codec_write;
+
+       val = snd_soc_read(codec, RK616_RESET);
+       if (val != rk616_reg_defaults[RK616_RESET]) {
+               dev_err(codec->dev,
+                       "Device register 0: %x is not a 0x0003\n", val);
+               ret = -ENODEV;
+               goto err__;
+       }
+
+       rk616_reset(codec);
+
+       rk616_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+#ifdef RK616_PROC
+       rk616_proc_init();
+#endif
+
+       snd_soc_add_controls(codec, rk616_snd_controls,
+                               ARRAY_SIZE(rk616_snd_controls));
+
+err__:
+       kfree(rk616);
+
+       return ret;
+}
+
+/* power down chip */
+static int rk616_remove(struct snd_soc_codec *codec)
+{
+       rk616_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_rk616 = {
+       .probe =        rk616_probe,
+       .remove =       rk616_remove,
+       .suspend =      rk616_suspend,
+       .resume =       rk616_resume,
+       .set_bias_level = rk616_set_bias_level,
+       .reg_cache_size = ARRAY_SIZE(rk616_reg_defaults),
+       .reg_word_size = sizeof(unsigned int),
+       .reg_cache_default = rk616_reg_defaults,
+       .volatile_register = rk616_volatile_register,
+       //.seq_notifier = wm8903_seq_notifier,
+       .dapm_widgets = rk616_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(rk616_dapm_widgets),
+       .dapm_routes = rk616_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(rk616_dapm_routes),
+};
+
+static __devinit int rk616_platform_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                       &soc_codec_dev_rk616, rk616_dai, ARRAY_SIZE(rk616_dai));
+}
+
+static __devexit int rk616_platform_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver rk616_codec_driver = {
+       .driver = {
+                  .name = "rk616-codec",
+                  .owner = THIS_MODULE,
+                  },
+       .probe = rk616_platform_probe,
+       .remove = __devexit_p(rk616_platform_remove),
+};
+
+
+static __init int rk616_modinit(void)
+{
+       return platform_driver_register(&rk616_codec_driver);
+}
+module_init(rk616_modinit);
+
+static __exit void rk616_exit(void)
+{
+       platform_driver_unregister(&rk616_codec_driver);
+}
+module_exit(rk616_exit);
+
+#ifdef RK616_PROC
+static ssize_t rk616_proc_write(struct file *file, const char __user *buffer,
+                          unsigned long len, void *data)
+{
+       struct snd_soc_codec *codec = rk616_priv->codec;
+       char *cookie_pot, *p, debug_write_read = 0;
+       int reg, value;
+
+       if (!rk616_priv & !rk616_priv->codec)
+               return -EINVAL;
+
+       cookie_pot = (char *)vmalloc( len );
+       if (!cookie_pot) {
+               return -ENOMEM;
+       } else {
+               if (copy_from_user( cookie_pot, buffer, len )) 
+                       return -EFAULT;
+       }
+
+       switch(cookie_pot[0]) {
+       case 'd':
+       case 'D':
+               debug_write_read ++;
+               debug_write_read %= 2;
+               if (debug_write_read != 0)
+                       printk("Debug read and write reg on\n");
+               else    
+                       printk("Debug read and write reg off\n");       
+               break;  
+       case 'r':
+       case 'R':
+               printk("Read reg debug\n");             
+               if (cookie_pot[1] ==':') {
+                       debug_write_read = 1;
+                       strsep(&cookie_pot,":");
+                       while ((p = strsep(&cookie_pot, ","))) {
+                               reg = simple_strtol(p, NULL, 16);
+                               value = snd_soc_read(codec, reg);
+                               printk("rk616_read:0x%04x = 0x%04x\n", reg, value);
+                       }
+                       debug_write_read = 0;
+                       printk("\n");
+               } else {
+                       printk("Error Read reg debug.\n");
+                       printk("For example: echo r:22,23,24,25>rk616_ts\n");
+               }
+               break;
+       case 'w':
+       case 'W':
+               printk("Write reg debug\n");            
+               if (cookie_pot[1] ==':') {
+                       debug_write_read = 1;
+                       strsep(&cookie_pot, ":");
+                       while ((p = strsep(&cookie_pot, "="))) {
+                               reg = simple_strtol(p, NULL, 16);
+                               p=strsep(&cookie_pot, ",");
+                               value = simple_strtol(p, NULL, 16);
+                               snd_soc_write(codec, reg, value);
+                               printk("rk616_write:0x%04x = 0x%04x\n", reg, value);
+                       }
+                       debug_write_read = 0;
+                       printk("\n");
+               } else {
+                       printk("Error Write reg debug.\n");
+                       printk("For example: w:22=0,23=0,24=0,25=0>rk616_ts\n");
+               }
+               break;  
+       case 'a':
+               printk("Dump reg \n");          
+
+               for (reg = 0; reg < 0x6e; reg += 2) {
+                       value = snd_soc_read(codec, reg);
+                       printk("rk616_read : 0x%04x = 0x%04x\n", reg, value);
+               }
+               break;
+       default:
+               printk("Help for rk616_ts .\n-->The Cmd list: \n");
+               printk("-->'d&&D' Open or Off the debug\n");
+               printk("-->'r&&R' Read reg debug,Example: echo 'r:22,23,24,25'>rk616_ts\n");
+               printk("-->'w&&W' Write reg debug,Example: echo 'w:22=0,23=0,24=0,25=0'>rk616_ts\n");
+               break;
+       }
+
+       return len;
+}
+
+static const struct file_operations rk616_proc_fops = {
+       .owner          = THIS_MODULE,
+};
+
+static int rk616_proc_init(void)
+{
+       struct proc_dir_entry *rk616_proc_entry;
+
+       rk616_proc_entry = create_proc_entry("driver/rk616_ts", 0777, NULL);
+
+       if(rk616_proc_entry != NULL) {
+               rk616_proc_entry->write_proc = rk616_proc_write;
+               return 0;
+       } else {
+               printk("create proc error !\n");
+               return -1;
+       }
+}
+#endif
+
+MODULE_DESCRIPTION("ASoC RK616 driver");
+MODULE_AUTHOR("chenjq <chenjq@rock-chips.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/rk616_codec.h b/sound/soc/codecs/rk616_codec.h
new file mode 100755 (executable)
index 0000000..704caea
--- /dev/null
@@ -0,0 +1,737 @@
+/*
+ * rk616.h  --  RK616 CODEC ALSA SoC audio driver
+ *
+ * Copyright 2013 Rockship
+ * Author: chenjq <chenjq@rock-chips.com>
+ *
+ */
+
+#ifndef __RK616_CODEC_H__
+#define __RK616_CODEC_H__
+
+#define RK616_CODEC_BASE                       0x0800
+
+#define RK616_RESET                            (RK616_CODEC_BASE + 0x00)
+#define RK616_ADC_INT_CTL1                     (RK616_CODEC_BASE + 0x08)
+#define RK616_ADC_INT_CTL2                     (RK616_CODEC_BASE + 0x0c)
+#define RK616_DAC_INT_CTL1                     (RK616_CODEC_BASE + 0x10)
+#define RK616_DAC_INT_CTL2                     (RK616_CODEC_BASE + 0x14)
+#define RK616_PGA_AGC_CTL                      (RK616_CODEC_BASE + 0x28)
+#define RK616_PWR_ADD1                         (RK616_CODEC_BASE + 0x3c)
+#define RK616_BST_CTL                          (RK616_CODEC_BASE + 0x40)
+#define RK616_DIFFIN_CTL                       (RK616_CODEC_BASE + 0x44)
+#define RK616_MIXINL_CTL                       (RK616_CODEC_BASE + 0x48)
+#define RK616_MIXINL_VOL1                      (RK616_CODEC_BASE + 0x4c)
+#define RK616_MIXINL_VOL2                      (RK616_CODEC_BASE + 0x50)
+#define RK616_MIXINR_CTL                       (RK616_CODEC_BASE + 0x54)
+#define RK616_MIXINR_VOL1                      (RK616_CODEC_BASE + 0x58)
+#define RK616_MIXINR_VOL2                      (RK616_CODEC_BASE + 0x5c)
+#define RK616_PGAL_CTL                         (RK616_CODEC_BASE + 0x60)
+#define RK616_PGAR_CTL                         (RK616_CODEC_BASE + 0x64)
+#define RK616_PWR_ADD2                         (RK616_CODEC_BASE + 0x68)
+#define RK616_DAC_CTL                          (RK616_CODEC_BASE + 0x6c)
+#define RK616_LINEMIX_CTL                      (RK616_CODEC_BASE + 0x70)
+#define RK616_MUXHP_HPMIX_CTL                  (RK616_CODEC_BASE + 0x74)
+#define RK616_HPMIX_CTL                                (RK616_CODEC_BASE + 0x78)
+#define RK616_HPMIX_VOL1                       (RK616_CODEC_BASE + 0x7c)
+#define RK616_HPMIX_VOL2                       (RK616_CODEC_BASE + 0x80)
+#define RK616_LINEOUT1_CTL                     (RK616_CODEC_BASE + 0x84)
+#define RK616_LINEOUT2_CTL                     (RK616_CODEC_BASE + 0x88)
+#define RK616_SPKL_CTL                         (RK616_CODEC_BASE + 0x8c)
+#define RK616_SPKR_CTL                         (RK616_CODEC_BASE + 0x90)
+#define RK616_HPL_CTL                          (RK616_CODEC_BASE + 0x94)
+#define RK616_HPR_CTL                          (RK616_CODEC_BASE + 0x98)
+#define RK616_MICBIAS_CTL                      (RK616_CODEC_BASE + 0x9c)
+#define RK616_MICKEY_DET_CTL                   (RK616_CODEC_BASE + 0xa0)
+#define RK616_PWR_ADD3                         (RK616_CODEC_BASE + 0xa4)
+#define RK616_ADC_CTL                          (RK616_CODEC_BASE + 0xa8)
+#define RK616_PGAL_AGC_CTL1                    (RK616_CODEC_BASE + 0xc0)
+#define RK616_PGAL_AGC_CTL2                    (RK616_CODEC_BASE + 0xc4)
+#define RK616_PGAL_AGC_CTL3                    (RK616_CODEC_BASE + 0xc8)
+#define RK616_PGAL_AGC_CTL4                    (RK616_CODEC_BASE + 0xcc)
+#define RK616_PGAL_ASR_CTL                     (RK616_CODEC_BASE + 0xd0)
+#define RK616_PGAL_AGC_MAX_H                   (RK616_CODEC_BASE + 0xd4)
+#define RK616_PGAL_AGC_MAX_L                   (RK616_CODEC_BASE + 0xd8)
+#define RK616_PGAL_AGC_MIN_H                   (RK616_CODEC_BASE + 0xdc)
+#define RK616_PGAL_AGC_MIN_L                   (RK616_CODEC_BASE + 0xe0)
+#define RK616_PGAL_AGC_CTL5                    (RK616_CODEC_BASE + 0xe4)
+#define RK616_PGAR_AGC_CTL1                    (RK616_CODEC_BASE + 0x100)
+#define RK616_PGAR_AGC_CTL2                    (RK616_CODEC_BASE + 0x104)
+#define RK616_PGAR_AGC_CTL3                    (RK616_CODEC_BASE + 0x108)
+#define RK616_PGAR_AGC_CTL4                    (RK616_CODEC_BASE + 0x10c)
+#define RK616_PGAR_ASR_CTL                     (RK616_CODEC_BASE + 0x110)
+#define RK616_PGAR_AGC_MAX_H                   (RK616_CODEC_BASE + 0x114)
+#define RK616_PGAR_AGC_MAX_L                   (RK616_CODEC_BASE + 0x118)
+#define RK616_PGAR_AGC_MIN_H                   (RK616_CODEC_BASE + 0x11c)
+#define RK616_PGAR_AGC_MIN_L                   (RK616_CODEC_BASE + 0x120)
+#define RK616_PGAR_AGC_CTL5                    (RK616_CODEC_BASE + 0x124)
+
+/* global definition (0x8c 0x90 0x94 0x98) */
+#define RK616_PWRD                             (0x1 << 7)
+#define RK616_PWRD_SFT                         7
+
+#define RK616_INIT_MASK                                (0x1 << 6)//? INIT
+#define RK616_INIT_SFT                         6
+#define RK616_INIT_RN                          (0x1 << 6)
+#define RK616_INIT_AFT                         (0x0 << 6)
+
+#define RK616_MUTE                             (0x1 << 5)
+#define RK616_MUTE_SFT                         5
+
+#define RK616_VOL_MASK                         0x1f
+#define RK616_VOL_SFT                          0
+
+/* ADC Interface Control 1 (0x08) */
+#define RK616_ALRCK_POL_MASK                   (0x1 << 7)
+#define RK616_ALRCK_POL_SFT                    7
+#define RK616_ALRCK_POL_EN                     (0x1 << 7)
+#define RK616_ALRCK_POL_DIS                    (0x0 << 7)
+
+#define RK616_ADC_VWL_MASK                     (0x3 << 5)
+#define RK616_ADC_VWL_SFT                      5
+#define RK616_ADC_VWL_32                       (0x3 << 5)
+#define RK616_ADC_VWL_24                       (0x2 << 5)
+#define RK616_ADC_VWL_20                       (0x1 << 5)
+#define RK616_ADC_VWL_16                       (0x0 << 5)
+
+#define RK616_ADC_DF_MASK                      (0x3 << 3)
+#define RK616_ADC_DF_SFT                       3
+#define RK616_ADC_DF_PCM                       (0x3 << 3)
+#define RK616_ADC_DF_I2S                       (0x2 << 3)
+#define RK616_ADC_DF_LJ                                (0x1 << 3)
+#define RK616_ADC_DF_RJ                                (0x0 << 3)
+
+#define RK616_ADC_SWAP_MASK                    (0x1 << 1)
+#define RK616_ADC_SWAP_SFT                     1
+#define RK616_ADC_SWAP_EN                      (0x1 << 1)
+#define RK616_ADC_SWAP_DIS                     (0x0 << 1)
+
+#define RK616_I2S_TYPE_MASK                    0x1
+#define RK616_I2S_TYPE_SFT                     0
+#define RK616_I2S_TYPE_STEREO                  0x1
+#define RK616_I2S_TYPE_MONO                    0x0
+
+/* ADC Interface Control 2 (0x0c) */
+#define RK616_I2S_MODE_MASK                    (0x1 << 4)
+#define RK616_I2S_MODE_SFT                     4
+#define RK616_I2S_MODE_MST                     (0x1 << 4)
+#define RK616_I2S_MODE_SLV                     (0x0 << 4)
+
+#define RK616_ADC_WL_MASK                      (0x3 << 2)
+#define RK616_ADC_WL_SFT                       2
+#define RK616_ADC_WL_32                                (0x3 << 2)
+#define RK616_ADC_WL_24                                (0x2 << 2)
+#define RK616_ADC_WL_20                                (0x1 << 2)
+#define RK616_ADC_WL_16                                (0x0 << 2)
+
+#define RK616_ADC_RST_MASK                     (0x1 << 1)
+#define RK616_ADC_RST_SFT                      1
+#define RK616_ADC_RST_EN                       (0x1 << 1)
+#define RK616_ADC_RST_DIS                      (0x0 << 1)
+
+#define RK616_ABCLK_POL_MASK                   0x1
+#define RK616_ABCLK_POL_SFT                    0
+#define RK616_ABCLK_POL_EN                     0x1
+#define RK616_ABCLK_POL_DIS                    0x0
+
+/* DAC Interface Control 1 (0x10) */
+#define RK616_DLRCK_POL_MASK                   (0x1 << 7)
+#define RK616_DLRCK_POL_SFT                    7
+#define RK616_DLRCK_POL_EN                     (0x1 << 7)
+#define RK616_DLRCK_POL_DIS                    (0x0 << 7)
+
+#define RK616_DAC_VWL_MASK                     (0x3 << 5)
+#define RK616_DAC_VWL_SFT                      5
+#define RK616_DAC_VWL_32                       (0x3 << 5)
+#define RK616_DAC_VWL_24                       (0x2 << 5)
+#define RK616_DAC_VWL_20                       (0x1 << 5)
+#define RK616_DAC_VWL_16                       (0x0 << 5)
+
+#define RK616_DAC_DF_MASK                      (0x3 << 3)
+#define RK616_DAC_DF_SFT                       3
+#define RK616_DAC_DF_PCM                       (0x3 << 3)
+#define RK616_DAC_DF_I2S                       (0x2 << 3)
+#define RK616_DAC_DF_LJ                                (0x1 << 3)
+#define RK616_DAC_DF_RJ                                (0x0 << 3)
+
+#define RK616_DAC_SWAP_MASK                    (0x1 << 2)
+#define RK616_DAC_SWAP_SFT                     2
+#define RK616_DAC_SWAP_EN                      (0x1 << 2)
+#define RK616_DAC_SWAP_DIS                     (0x0 << 2)
+
+/* DAC Interface Control 2 (0x14) */
+#define RK616_DAC_WL_MASK                      (0x3 << 2)
+#define RK616_DAC_WL_SFT                       2
+#define RK616_DAC_WL_32                                (0x3 << 2)
+#define RK616_DAC_WL_24                                (0x2 << 2)
+#define RK616_DAC_WL_20                                (0x1 << 2)
+#define RK616_DAC_WL_16                                (0x0 << 2)
+
+#define RK616_DAC_RST_MASK                     (0x1 << 1)
+#define RK616_DAC_RST_SFT                      1
+#define RK616_DAC_RST_EN                       (0x1 << 1)
+#define RK616_DAC_RST_DIS                      (0x0 << 1)
+
+#define RK616_DBCLK_POL_MASK                   0x1
+#define RK616_DBCLK_POL_SFT                    0
+#define RK616_DBCLK_POL_EN                     0x1
+#define RK616_DBCLK_POL_DIS                    0x0
+
+/* PGA AGC Enable (0x28) */
+#define RK616_PGAL_AGC_EN_MASK                 (0x1 << 5)
+#define RK616_PGAL_AGC_EN_SFT                  5
+#define RK616_PGAL_AGC_EN                      (0x1 << 5)
+#define RK616_PGAL_AGC_DIS                     (0x0 << 5)
+
+#define RK616_PGAR_AGC_EN_MASK                 (0x1 << 4)
+#define RK616_PGAR_AGC_EN_SFT                  4
+#define RK616_PGAR_AGC_EN                      (0x1 << 4)
+#define RK616_PGAR_AGC_DIS                     (0x0 << 4)
+
+/* Power Management Addition 1 (0x3c) */
+#define RK616_ADC_PWRD                         (0x1 << 6)
+#define RK616_ADC_PWRD_SFT                     6
+
+#define RK616_DIFFIN_MIR_PGAR_RLPWRD           (0x1 << 5)
+#define RK616_DIFFIN_MIR_PGAR_RLPWRD_SFT               5
+
+#define RK616_MIC1_MIC2_MIL_PGAL_RLPWRD                (0x1 << 4)
+#define RK616_MIC1_MIC2_MIL_PGAL_RLPWRD_SFT    4
+
+#define RK616_ADCL_RLPWRD                      (0x1 << 3)
+#define RK616_ADCL_RLPWRD_SFT                  3
+
+#define RK616_ADCR_RLPWRD                      (0x1 << 2)
+#define RK616_ADCR_RLPWRD_SFT                  2
+
+/* BST Control (0x40) */
+#define RK616_BSTL_PWRD                                (0x1 << 7)
+#define RK616_BSTL_PWRD_SFT                    7
+
+#define RK616_BSTL_MODE_MASK                   (0x1 << 6)
+#define RK616_BSTL_MODE_SFT                    6
+#define RK616_BSTL_MODE_SE                     (0x1 << 6)
+#define RK616_BSTL_MODE_DIFF                   (0x0 << 6)
+
+#define RK616_BSTL_GAIN_MASK                   (0x1 << 5)
+#define RK616_BSTL_GAIN_SFT                    5
+#define RK616_BSTL_GAIN_20DB                   (0x1 << 5)
+#define RK616_BSTL_GAIN_0DB                    (0x0 << 5)
+
+#define RK616_BSTL_MUTE                                (0x1 << 4)
+#define RK616_BSTL_MUTE_SFT                    4
+
+#define RK616_BSTR_PWRD                                (0x1 << 3)
+#define RK616_BSTR_PWRD_SFT                    3
+
+#define RK616_BSTR_MODE_MASK                   (0x1 << 2)
+#define RK616_BSTR_MODE_SFT                    2
+#define RK616_BSTR_MODE_SE                     (0x1 << 2)
+#define RK616_BSTR_MODE_DIFF                   (0x0 << 2)
+
+#define RK616_BSTR_GAIN_MASK                   (0x1 << 1)
+#define RK616_BSTR_GAIN_SFT                    1
+#define RK616_BSTR_GAIN_20DB                   (0x1 << 1)
+#define RK616_BSTR_GAIN_0DB                    (0x0 << 1)
+
+#define RK616_BSTR_MUTE                                0x1
+#define RK616_BSTR_MUTE_SFT                    0
+
+/* DIFFIN Control (0x44) */
+#define RK616_DIFFIN_PWRD                      (0x1 << 5)
+#define RK616_DIFFIN_PWRD_SFT                  5
+
+#define RK616_DIFFIN_MODE_MASK                 (0x1 << 4)
+#define RK616_DIFFIN_MODE_SFT                  4
+#define RK616_DIFFIN_MODE_SE                   (0x1 << 4)
+#define RK616_DIFFIN_MODE_DIFF                 (0x0 << 4)
+
+#define RK616_DIFFIN_GAIN_MASK                 (0x1 << 3)
+#define RK616_DIFFIN_GAIN_SFT                  3
+#define RK616_DIFFIN_GAIN_20DB                 (0x1 << 3)
+#define RK616_DIFFIN_GAIN_0DB                  (0x0 << 3)
+
+#define RK616_DIFFIN_MUTE                      (0x1 << 2)
+#define RK616_DIFFIN_MUTE_SFT                  2
+
+#define RK616_MIRM_F_MASK                      (0x1 << 1)
+#define RK616_MIRM_F_SFT                       1
+#define RK616_MIRM_F_IN1N                      (0x1 << 1)
+#define RK616_MIRM_F_DIFFIN                    (0x0 << 1)
+
+#define RK616_HMM_F_MASK                       0x1
+#define RK616_HMM_F_SFT                                0
+#define RK616_HMM_F_IN1N                       0x1
+#define RK616_HMM_F_DIFFIN                     0x0
+
+
+/* BSTR MUXMIC MIXINL Control (0x48) */
+#define RK616_SE_BSTR_F_MASK                   (0x1 << 6)
+#define RK616_SE_BSTR_F_SFT                    6
+#define RK616_SE_BSTR_F_MIN2P                  (0x1 << 6)
+#define RK616_SE_BSTR_F_MIN2N                  (0x0 << 6)
+
+#define RK616_MM_F_MASK                                (0x1 << 5)
+#define RK616_MM_F_SFT                         5
+#define RK616_MM_F_BSTR                                (0x1 << 5)
+#define RK616_MM_F_BSTL                                (0x0 << 5)
+
+#define RK616_MIL_PWRD                         (0x1 << 4)
+#define RK616_MIL_PWRD_SFT                     4
+
+#define RK616_MIL_MUTE                         (0x1 << 3)
+#define RK616_MIL_MUTE_SFT                     3
+
+#define RK616_MIL_F_IN3L                       (0x1 << 2)
+#define RK616_MIL_F_IN3L_SFT                   2
+
+#define RK616_MIL_F_IN1P                       (0x1 << 1)
+#define RK616_MIL_F_IN1P_SFT                   1
+
+#define RK616_MIL_F_MUX                                (0x1 << 0)
+#define RK616_MIL_F_MUX_SFT                    0
+
+/* MIXINL volume 1 (0x4c) */
+#define RK616_MIL_F_MUX_VOL_MASK               (0x7 << 3)
+#define RK616_MIL_F_MUX_VOL_SFT                        3
+
+#define RK616_MIL_F_IN1P_VOL_MASK              0x7
+#define RK616_MIL_F_IN1P_VOL_SFT               0
+
+/* MIXINL volume 2 (0x50) */
+#define RK616_MIL_F_IN3L_VOL_MASK              0x7
+#define RK616_MIL_F_IN3L_VOL_SFT               0
+
+/* MIXINR Control (0x54) */
+#define RK616_MIR_PWRD                         (0x1 << 5)
+#define RK616_MIR_PWRD_SFT                     5
+
+#define RK616_MIR_MUTE                         (0x1 << 4)
+#define RK616_MIR_MUTE_SFT                     4
+
+#define RK616_MIR_F_MIC2N                      (0x1 << 3)
+#define RK616_MIR_F_MIC2N_SFT                  3
+
+#define RK616_MIR_F_IN1P                       (0x1 << 2)
+#define RK616_MIR_F_IN1P_SFT                   2
+
+#define RK616_MIR_F_IN3R                       (0x1 << 1)
+#define RK616_MIR_F_IN3R_SFT                   1
+
+#define RK616_MIR_F_MIRM                       0x1
+#define RK616_MIR_F_MIRM_SFT                   0
+
+/* MIXINR volume 1 (0x58) */
+#define RK616_MIR_F_MIRM_VOL_MASK              (0x7 << 3)
+#define RK616_MIR_F_MIRM_VOL_SFT               3
+
+#define RK616_MIR_F_IN3R_VOL_MASK              0x7
+#define RK616_MIR_F_IN3R_VOL_SFT               0
+
+/* MIXINR volume 2 (0x5c) */
+#define RK616_MIR_F_MIC2N_VOL_MASK             (0x7 << 3)
+#define RK616_MIR_F_MIC2N_VOL_SFT              3
+
+#define RK616_MIR_F_IN1P_VOL_MASK              0x7
+#define RK616_MIR_F_IN1P_VOL_SFT               0
+
+/* PGA Control (0x60 0x64) */
+#define RK616_PGA_PWRD                         (0x1 << 7)
+#define RK616_PGA_PWRD_SFT                     7
+
+#define RK616_PGA_MUTE                         (0x1 << 6)
+#define RK616_PGA_MUTE_SFT                     6
+
+#define RK616_PGA_VOL_MASK                     (0x1f << 0)
+#define RK616_PGA_VOL_SFT                      0
+
+
+/* Power Management Addition 2 (0x68) */
+#define RK616_HPL_HPR_PWRD                     (0x1 << 7)
+#define RK616_HPL_HPR_PWRD_SFT                 7
+
+#define RK616_DAC_PWRD                         (0x1 << 6)//? Interface or not
+#define RK616_DAC_PWRD_SFT                     6
+
+#define RK616_DACL_RLPWRD                      (0x1 << 5)
+#define RK616_DACL_RLPWRD_SFT                  5
+
+#define RK616_DACL_SPKL_RLPWRD                 (0x1 << 4)
+#define RK616_DACL_SPKL_RLPWRD_SFT             4
+
+#define RK616_DACR_RLPWRD                      (0x1 << 3)
+#define RK616_DACR_RLPWRD_SFT                  3
+
+#define RK616_DACR_SPKR_RLPWRD                 (0x1 << 2)//? BIT 3 BIT 6 BIT 2
+#define RK616_DACR_SPKR_RLPWRD_SFT             2
+
+#define RK616_LM_LO_RLPWRD                     (0x1 << 1)
+#define RK616_LM_LO_RLPWRD_SFT                 1
+
+#define RK616_HM_RLPWRD                                0x1
+#define RK616_HM_RLPWRD_SFT                    0
+
+/* DAC Control (0x6c) */
+#define RK616_DACL_INIT_MASK                   (0x1 << 5)//? INIT?
+#define RK616_DACL_INIT_SFT                    5
+#define RK616_DACL_INIT_RN                     (0x1 << 5)
+#define RK616_DACL_INIT_AFT                    (0x0 << 5)
+
+#define RK616_DACR_INIT_MASK                   (0x1 << 4)//? INIT?
+#define RK616_DACR_INIT_SFT                    4
+#define RK616_DACR_INIT_RN                     (0x1 << 4)
+#define RK616_DACR_INIT_AFT                    (0x0 << 4)
+
+#define RK616_DACL_PWRD                                (0x1 << 3)
+#define RK616_DACL_PWRD_SFT                    3
+
+#define RK616_DACR_PWRD                                (0x1 << 2)
+#define RK616_DACR_PWRD_SFT                    2
+
+#define RK616_DACR_CLK_PWRD                    (0x1 << 1)
+#define RK616_DACR_CLK_PWRD_SFT                        1
+
+#define RK616_DACL_CLK_PWRD                    0x1
+#define RK616_DACL_CLK_PWRD_SFT                        0
+
+/* Linemix Control (0x70) */
+#define RK616_LM_PWRD                          (0x1 << 4)
+#define RK616_LM_PWRD_SFT                      4
+
+#define RK616_LM_F_PGAR                                (0x1 << 3)
+#define RK616_LM_F_PGAR_SFT                    3
+
+#define RK616_LM_F_PGAL                                (0x1 << 2)
+#define RK616_LM_F_PGAL_SFT                    2
+
+#define RK616_LM_F_DACR                                (0x1 << 1)
+#define RK616_LM_F_DACR_SFT                    1
+
+#define RK616_LM_F_DACL                                0x1
+#define RK616_LM_F_DACL_SFT                    0
+
+/* MUXHP HPMIX Control (0x74) */
+#define RK616_HML_PWRD                         (0x1 << 5)
+#define RK616_HML_PWRD_SFT                     5
+
+#define RK616_HML_INIT_MASK                    (0x1 << 4)//? INIT?
+#define RK616_HML_INIT_SFT                     4
+#define RK616_HML_INIT_RN                      (0x1 << 4)
+#define RK616_HML_INIT_AFT                     (0x0 << 4)
+
+#define RK616_HMR_PWRD                         (0x1 << 3)
+#define RK616_HMR_PWRD_SFT                     3
+
+#define RK616_HMR_INIT_MASK                    (0x1 << 2)//? INIT?
+#define RK616_HMR_INIT_SFT                     2
+#define RK616_HMR_INIT_RN                      (0x1 << 2)
+#define RK616_HMR_INIT_AFT                     (0x0 << 2)
+
+#define RK616_MHL_F_MASK                       (0x1 << 1)
+#define RK616_MHL_F_SFT                                1
+#define RK616_MHL_F_DACL                       (0x1 << 1)
+#define RK616_MHL_F_HPMIXL                     (0x0 << 1)
+
+#define RK616_MHR_F_MASK                       0x1
+#define RK616_MHR_F_SFT                                0
+#define RK616_MHR_F_DACR                       0x1
+#define RK616_MHR_F_HPMIXR                     0x0
+
+/* HPMIX Control (0x78) */
+#define RK616_HML_F_HMM                                (0x1 << 7)
+#define RK616_HML_F_HMM_SFT                    7
+
+#define RK616_HML_F_IN1P                       (0x1 << 6)
+#define RK616_HML_F_IN1P_SFT                   6
+
+#define RK616_HML_F_PGAL                       (0x1 << 5)
+#define RK616_HML_F_PGAL_SFT                   5
+
+#define RK616_HML_F_DACL                       (0x1 << 4)
+#define RK616_HML_F_DACL_SFT                   4
+
+#define RK616_HMR_F_HMM                                (0x1 << 3)
+#define RK616_HMR_F_HMM_SFT                    3
+
+#define RK616_HMR_F_PGAR                       (0x1 << 2)
+#define RK616_HMR_F_PGAR_SFT                   2
+
+#define RK616_HMR_F_PGAL                       (0x1 << 1)
+#define RK616_HMR_F_PGAL_SFT                   1
+
+#define RK616_HMR_F_DACR                       0x1
+#define RK616_HMR_F_DACR_SFT                   0
+
+/* HPMIX Volume Control 1 (0x7c) */
+#define RK616_HML_F_IN1P_VOL_MASK              0x7
+#define RK616_HML_F_IN1P_VOL_SFT               0
+
+/* HPMIX Volume Control 2 (0x80) */
+#define RK616_HML_F_HMM_VOL_MASK               (0x7 << 3)
+#define RK616_HML_F_HMM_VOL_SFT                        3
+
+#define RK616_HMR_F_HMM_VOL_MASK               0x7
+#define RK616_HMR_F_HMM_VOL_SFT                        0
+
+/* Lineout1 Control (0x84 0x88) */
+#define RK616_LINEOUT_PWRD                     (0x1 << 6)
+#define RK616_LINEOUT_PWRD_SFT                 6
+
+#define RK616_LINEOUT_MUTE                     (0x1 << 5)
+#define RK616_LINEOUT_MUTE_SFT                 5
+
+#define RK616_LINEOUT_VOL_MASK                 0x1f
+#define RK616_LINEOUT_VOL_SFT                  0
+
+/* Micbias Control 1 (0x9c) */
+#define RK616_MICBIAS1_PWRD                    (0x1 << 7)
+#define RK616_MICBIAS1_PWRD_SFT                        7
+
+#define RK616_MICBIAS2_PWRD                    (0x1 << 6)
+#define RK616_MICBIAS2_PWRD_SFT                        6
+
+#define RK616_MICBIAS1_V_MASK                  (0x7 << 3)
+#define RK616_MICBIAS1_V_SFT                   3
+#define RK616_MICBIAS1_V_1_7                   (0x7 << 3)
+#define RK616_MICBIAS1_V_1_6                   (0x6 << 3)
+#define RK616_MICBIAS1_V_1_5                   (0x5 << 3)
+#define RK616_MICBIAS1_V_1_4                   (0x4 << 3)
+#define RK616_MICBIAS1_V_1_3                   (0x3 << 3)
+#define RK616_MICBIAS1_V_1_2                   (0x2 << 3)
+#define RK616_MICBIAS1_V_1_1                   (0x1 << 3)
+#define RK616_MICBIAS1_V_1_0                   (0x0 << 3)
+
+#define RK616_MICBIAS2_V_MASK                  0x7
+#define RK616_MICBIAS2_V_SFT                   0
+#define RK616_MICBIAS2_V_1_7                   0x7
+#define RK616_MICBIAS2_V_1_6                   0x6
+#define RK616_MICBIAS2_V_1_5                   0x5
+#define RK616_MICBIAS2_V_1_4                   0x4
+#define RK616_MICBIAS2_V_1_3                   0x3
+#define RK616_MICBIAS2_V_1_2                   0x2
+#define RK616_MICBIAS2_V_1_1                   0x1
+#define RK616_MICBIAS2_V_1_0                   0x0
+
+/* MIC Key Detection Control (0xa0) */
+#define RK616_MK1_DET_MASK                     (0x1 << 7)
+#define RK616_MK1_DET_SFT                      7
+#define RK616_MK1_EN                           (0x1 << 7)
+#define RK616_MK1_DIS                          (0x0 << 7)
+
+#define RK616_MK2_DET_MASK                     (0x1 << 6)
+#define RK616_MK2_DET_SFT                      6
+#define RK616_MK2_EN                           (0x1 << 6)
+#define RK616_MK2_DIS                          (0x0 << 6)
+
+#define RK616_MK1_DET_I_MASK                   (0x7 << 3)
+#define RK616_MK1_DET_I_SFT                    3
+#define RK616_MK1_DET_I_1500                   (0x7 << 3)
+#define RK616_MK1_DET_I_1300                   (0x6 << 3)
+#define RK616_MK1_DET_I_1100                   (0x5 << 3)
+#define RK616_MK1_DET_I_900                    (0x4 << 3)
+#define RK616_MK1_DET_I_700                    (0x3 << 3)
+#define RK616_MK1_DET_I_500                    (0x2 << 3)
+#define RK616_MK1_DET_I_300                    (0x1 << 3)
+#define RK616_MK1_DET_I_100                    (0x0 << 3)
+
+#define RK616_MK2_DET_I_MASK                   0x7
+#define RK616_MK2_DET_I_SFT                    0
+#define RK616_MK2_DET_I_1500                   0x7
+#define RK616_MK2_DET_I_1300                   0x6
+#define RK616_MK2_DET_I_1100                   0x5
+#define RK616_MK2_DET_I_900                    0x4
+#define RK616_MK2_DET_I_700                    0x3
+#define RK616_MK2_DET_I_500                    0x2
+#define RK616_MK2_DET_I_300                    0x1
+#define RK616_MK2_DET_I_100                    0x0
+
+/* Power Management Addition 3 (0xa4) */
+#define RK616_ADCL_ZO_PWRD                     (0x1 << 3)
+#define RK616_ADCL_ZO_PWRD_SFT                 3
+
+#define RK616_ADCR_ZO_PWRD                     (0x1 << 2)
+#define RK616_ADCR_ZO_PWRD_SFT                 2
+
+#define RK616_DACL_ZO_PWRD                     (0x1 << 1)
+#define RK616_DACL_ZO_PWRD_SFT                 1
+
+#define RK616_DACR_ZO_PWRD                     0x1
+#define RK616_DACR_ZO_PWRD_SFT                 0
+
+/* ADC control (0xa8) */
+#define RK616_ADCL_CLK_PWRD                    (0x1 << 5)//?set to 1
+#define RK616_ADCL_CLK_PWRD_SFT                        5
+
+#define RK616_ADCL_PWRD                                (0x1 << 4)
+#define RK616_ADCL_PWRD_SFT                    4
+
+#define RK616_ADCL_RST_MASK                    (0x1 << 3)//? 0x0c same
+#define RK616_ADCL_RST_SFT                     3
+#define RK616_ADCL_RST_EN                      (0x1 << 3)//? 1 clear 0 work means
+#define RK616_ADCL_RST_DIS                     (0x0 << 3)
+
+#define RK616_ADCR_CLK_PWRD                    (0x1 << 2)
+#define RK616_ADCR_CLK_PWRD_SFT                        2
+
+#define RK616_ADCR_PWRD                                (0x1 << 1)
+#define RK616_ADCR_PWRD_SFT                    1
+
+#define RK616_ADCR_RST_MASK                    0x1//? 0x0c same
+#define RK616_ADCR_RST_SFT                     0
+#define RK616_ADCR_RST_EN                      0x1//? 1 clear 0 work means
+#define RK616_ADCR_RST_DIS                     0x0
+
+/* PGA AGC control 1 (0xc0 0x110) */
+#define RK616_PGA_AGC_WAY_MASK                 (0x1 << 4)
+#define RK616_PGA_AGC_WAY_SFT                  4
+#define RK616_PGA_AGC_WAY_JACK                 (0x1 << 4)
+#define RK616_PGA_AGC_WAY_NOR                  (0x0 << 4)
+
+#define RK616_PGA_AGC_HOLD_T_MASK              0xf
+#define RK616_PGA_AGC_HOLD_T_SFT               0
+#define RK616_PGA_AGC_HOLD_T_1024              0xa
+#define RK616_PGA_AGC_HOLD_T_512               0x9
+#define RK616_PGA_AGC_HOLD_T_256               0x8
+#define RK616_PGA_AGC_HOLD_T_128               0x7
+#define RK616_PGA_AGC_HOLD_T_64                        0x6
+#define RK616_PGA_AGC_HOLD_T_32                        0x5
+#define RK616_PGA_AGC_HOLD_T_16                        0x4
+#define RK616_PGA_AGC_HOLD_T_8                 0x3
+#define RK616_PGA_AGC_HOLD_T_4                 0x2
+#define RK616_PGA_AGC_HOLD_T_2                 0x1
+#define RK616_PGA_AGC_HOLD_T_0                 0x0
+
+/* PGA AGC control 2 (0xc4 0x104) */
+#define RK616_PGA_AGC_GRU_T_MASK               (0xf << 4)
+#define RK616_PGA_AGC_GRU_T_SFT                        4
+#define RK616_PGA_AGC_GRU_T_512                        (0xa << 4)
+#define RK616_PGA_AGC_GRU_T_256                        (0x9 << 4)
+#define RK616_PGA_AGC_GRU_T_128                        (0x8 << 4)
+#define RK616_PGA_AGC_GRU_T_64                 (0x7 << 4)
+#define RK616_PGA_AGC_GRU_T_32                 (0x6 << 4)
+#define RK616_PGA_AGC_GRU_T_16                 (0x5 << 4)
+#define RK616_PGA_AGC_GRU_T_8                  (0x4 << 4)
+#define RK616_PGA_AGC_GRU_T_4                  (0x3 << 4)
+#define RK616_PGA_AGC_GRU_T_2                  (0x2 << 4)
+#define RK616_PGA_AGC_GRU_T_1                  (0x1 << 4)
+#define RK616_PGA_AGC_GRU_T_0_5                        (0x0 << 4)
+
+#define RK616_PGA_AGC_GRD_T_MASK               0xf
+#define RK616_PGA_AGC_GRD_T_SFT                        0
+#define RK616_PGA_AGC_GRD_T_128_32             0xa
+#define RK616_PGA_AGC_GRD_T_64_16              0x9
+#define RK616_PGA_AGC_GRD_T_32_8               0x8
+#define RK616_PGA_AGC_GRD_T_16_4               0x7
+#define RK616_PGA_AGC_GRD_T_8_2                        0x6
+#define RK616_PGA_AGC_GRD_T_4_1                        0x5
+#define RK616_PGA_AGC_GRD_T_2_0_512            0x4
+#define RK616_PGA_AGC_GRD_T_1_0_256            0x3
+#define RK616_PGA_AGC_GRD_T_0_500_128          0x2
+#define RK616_PGA_AGC_GRD_T_0_250_64           0x1
+#define RK616_PGA_AGC_GRD_T_0_125_32           0x0
+
+/* PGA AGC control 3 (0xc8 0x108) */
+#define RK616_PGA_AGC_MODE_MASK                        (0x1 << 7)
+#define RK616_PGA_AGC_MODE_SFT                 7
+#define RK616_PGA_AGC_MODE_LIMIT               (0x1 << 7)
+#define RK616_PGA_AGC_MODE_NOR                 (0x0 << 7)
+
+#define RK616_PGA_AGC_ZO_MASK                  (0x1 << 6)
+#define RK616_PGA_AGC_ZO_SFT                   6
+#define RK616_PGA_AGC_ZO_EN                    (0x1 << 6)
+#define RK616_PGA_AGC_ZO_DIS                   (0x0 << 6)
+
+#define RK616_PGA_AGC_REC_MODE_MASK            (0x1 << 5)
+#define RK616_PGA_AGC_REC_MODE_SFT             5
+#define RK616_PGA_AGC_REC_MODE_AC              (0x1 << 5)
+#define RK616_PGA_AGC_REC_MODE_RN              (0x0 << 5)
+
+#define RK616_PGA_AGC_FAST_D_MASK              (0x1 << 4)
+#define RK616_PGA_AGC_FAST_D_SFT               4
+#define RK616_PGA_AGC_FAST_D_EN                        (0x1 << 4)
+#define RK616_PGA_AGC_FAST_D_DIS               (0x0 << 4)
+
+#define RK616_PGA_AGC_NG_MASK                  (0x1 << 3)
+#define RK616_PGA_AGC_NG_SFT                   3
+#define RK616_PGA_AGC_NG_EN                    (0x1 << 3)
+#define RK616_PGA_AGC_NG_DIS                   (0x0 << 3)
+
+#define RK616_PGA_AGC_NG_THR_MASK              0x7
+#define RK616_PGA_AGC_NG_THR_SFT               0
+#define RK616_PGA_AGC_NG_THR_N81DB             0x7
+#define RK616_PGA_AGC_NG_THR_N75DB             0x6
+#define RK616_PGA_AGC_NG_THR_N69DB             0x5
+#define RK616_PGA_AGC_NG_THR_N63DB             0x4
+#define RK616_PGA_AGC_NG_THR_N57DB             0x3
+#define RK616_PGA_AGC_NG_THR_N51DB             0x2
+#define RK616_PGA_AGC_NG_THR_N45DB             0x1
+#define RK616_PGA_AGC_NG_THR_N39DB             0x0
+
+/* PGA AGC Control 4 (0xcc 0x10c) */
+#define RK616_PGA_AGC_ZO_MODE_MASK             (0x1 << 5)
+#define RK616_PGA_AGC_ZO_MODE_SFT              5
+#define RK616_PGA_AGC_ZO_MODE_UWRC             (0x1 << 5)
+#define RK616_PGA_AGC_ZO_MODE_UARC             (0x0 << 5)
+
+#define RK616_PGA_AGC_VOL_MASK                 0x1f
+#define RK616_PGA_AGC_VOL_SFT                  0
+
+/* PGA ASR Control (0xd0 0x110) */
+#define RK616_PGA_SLOW_CLK_MASK                        (0x1 << 3)
+#define RK616_PGA_SLOW_CLK_SFT                 3
+#define RK616_PGA_SLOW_CLK_EN                  (0x1 << 3)
+#define RK616_PGA_SLOW_CLK_DIS                 (0x0 << 3)
+
+#define RK616_PGA_ASR_MASK                     0x7
+#define RK616_PGA_ASR_SFT                      0
+#define RK616_PGA_ASR_8KHz                     0x5
+#define RK616_PGA_ASR_12KHz                    0x4
+#define RK616_PGA_ASR_16KHz                    0x3
+#define RK616_PGA_ASR_24KHz                    0x2
+#define RK616_PGA_ASR_32KHz                    0x1
+#define RK616_PGA_ASR_48KHz                    0x0
+
+/* PGA AGC Control 5 (0xe4 0x124) */
+#define RK616_PGA_AGC_MASK                     (0x1 << 6)
+#define RK616_PGA_AGC_SFT                      6
+#define RK616_PGA_AGC_EN                       (0x1 << 6)
+#define RK616_PGA_AGC_DIS                      (0x0 << 6)
+
+#define RK616_PGA_AGC_MAX_G_MASK               (0x7 << 3)
+#define RK616_PGA_AGC_MAX_G_SFT                        3
+#define RK616_PGA_AGC_MAX_G_28_5DB             (0x7 << 3)
+#define RK616_PGA_AGC_MAX_G_22_5DB             (0x6 << 3)
+#define RK616_PGA_AGC_MAX_G_16_5DB             (0x5 << 3)
+#define RK616_PGA_AGC_MAX_G_10_5DB             (0x4 << 3)
+#define RK616_PGA_AGC_MAX_G_4_5DB              (0x3 << 3)
+#define RK616_PGA_AGC_MAX_G_N1_5DB             (0x2 << 3)
+#define RK616_PGA_AGC_MAX_G_N7_5DB             (0x1 << 3)
+#define RK616_PGA_AGC_MAX_G_N13_5DB            (0x0 << 3)
+
+#define RK616_PGA_AGC_MIN_G_MASK               0x7
+#define RK616_PGA_AGC_MIN_G_SFT                        0
+#define RK616_PGA_AGC_MIN_G_24DB               0x7
+#define RK616_PGA_AGC_MIN_G_18DB               0x6
+#define RK616_PGA_AGC_MIN_G_12DB               0x5
+#define RK616_PGA_AGC_MIN_G_6DB                        0x4
+#define RK616_PGA_AGC_MIN_G_0DB                        0x3
+#define RK616_PGA_AGC_MIN_G_N6DB               0x2
+#define RK616_PGA_AGC_MIN_G_N12DB              0x1
+#define RK616_PGA_AGC_MIN_G_N18DB              0x0
+
+enum {
+       RK616_HIFI,
+       RK616_VOICE,
+};
+
+enum {
+       RK616_MONO = 1,
+       RK616_STEREO,
+};
+
+struct rk616_reg_val_typ {
+       unsigned int reg;
+       unsigned int  value;
+};
+
+#endif //__RK616_CODEC_H__
index de090e13bda4ab4a924b83826595c3fef836bfc1..d44586c90cc382cfc281cc80c6471aa339580d85 100755 (executable)
@@ -251,6 +251,15 @@ config SND_RK29_SOC_RK610
          Say Y if you want to add support for SoC audio on rockchip
          with the RK610(JETTA).
 
+config SND_RK29_SOC_RK616
+       tristate "SoC I2S Audio support for rockchip - RK616"
+       depends on SND_RK29_SOC
+       select SND_RK29_SOC_I2S
+       select SND_SOC_RK616
+       help
+         Say Y if you want to add support for SoC audio on rockchip
+         with the RK616(JETTA).
+
 config SND_RK_SOC_RK2928
        tristate "SoC I2S Audio support for rockchip - RK2928"
        depends on SND_RK29_SOC && ARCH_RK2928
index aa29e347a3c07b280bf63672ef842c103c27db2e..cfd5e3bbc1a2486d333b25b3ff0b8b4cd58bf1e4 100755 (executable)
@@ -29,6 +29,7 @@ snd-soc-rk1000-objs := rk29_rk1000codec.o
 snd-soc-wm8994-objs := rk29_wm8994.o
 snd-soc-hdmi-objs := rk29_hdmi.o
 snd-soc-rk610-objs := rk29_jetta_codec.o
+snd-soc-rk616-objs := rk_rk616.o
 snd-soc-aic3262-objs := rk29_aic3262.o
 snd-soc-rk2928-objs := rk2928-card.o
 snd-soc-es8323-objs := rk29_es8323.o
@@ -51,5 +52,6 @@ obj-$(CONFIG_SND_RK29_SOC_AIC3111) += snd-soc-aic3111.o
 obj-$(CONFIG_SND_RK29_SOC_AIC3262) += snd-soc-aic3262.o
 obj-$(CONFIG_SND_RK29_SOC_HDMI) += snd-soc-hdmi.o
 obj-$(CONFIG_SND_RK29_SOC_RK610) += snd-soc-rk610.o
+obj-$(CONFIG_SND_RK29_SOC_RK616) += snd-soc-rk616.o
 obj-$(CONFIG_SND_RK_SOC_RK2928) += snd-soc-rk2928.o
 obj-$(CONFIG_SND_RK29_SOC_ES8323) += snd-soc-es8323.o
diff --git a/sound/soc/rk29/rk_rk616.c b/sound/soc/rk29/rk_rk616.c
new file mode 100755 (executable)
index 0000000..49ae8e1
--- /dev/null
@@ -0,0 +1,286 @@
+/*\r
+ * rk_rk616.c  --  SoC audio for rockchip\r
+ *\r
+ * Driver for rockchip rk616 audio\r
+ *\r
+ *  This program is free software; you can redistribute  it and/or modify it\r
+ *  under  the terms of  the GNU General  Public License as published by the\r
+ *  Free Software Foundation;  either version 2 of the  License, or (at your\r
+ *  option) any later version.\r
+ *\r
+ *\r
+ */\r
+\r
+#include <linux/module.h>\r
+#include <linux/device.h>\r
+#include <sound/core.h>\r
+#include <sound/pcm.h>\r
+#include <sound/soc.h>\r
+#include <sound/soc-dapm.h>\r
+#include <asm/io.h>\r
+#include <mach/hardware.h>\r
+#include "../codecs/rk616_codec.h"\r
+#include "rk29_pcm.h"\r
+#include "rk29_i2s.h"\r
+\r
+#if 1\r
+#define        DBG(x...)       printk(KERN_INFO x)\r
+#else\r
+#define        DBG(x...)\r
+#endif\r
+\r
+static const struct snd_soc_dapm_widget rk_dapm_widgets[] = {\r
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),\r
+       SND_SOC_DAPM_MIC("Headset Jack", NULL), \r
+       SND_SOC_DAPM_SPK("Ext Spk", NULL),\r
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),\r
+};\r
+\r
+static const struct snd_soc_dapm_route rk_audio_map[]={\r
+\r
+       /* Mic Jack --> MIC_IN*/\r
+       {"Mic1 Bias", NULL, "Mic Jack"},\r
+       {"MIC1", NULL, "Mic1 Bias"},\r
+       \r
+       // HP MIC\r
+       {"Mic1 Bias", NULL, "Headset Jack"},\r
+       {"MIC3", NULL, "Mic1 Bias"},\r
+\r
+       {"Ext Spk", NULL, "SPOLP"},\r
+       {"Ext Spk", NULL, "SPOLN"},\r
+       {"Ext Spk", NULL, "SPORP"},\r
+       {"Ext Spk", NULL, "SPORN"},\r
+\r
+       {"Headphone Jack", NULL, "HPOL"},\r
+       {"Headphone Jack", NULL, "HPOR"},\r
+} ;\r
+\r
+static const struct snd_kcontrol_new rk_controls[] = {\r
+       SOC_DAPM_PIN_SWITCH("Mic Jack"),\r
+       SOC_DAPM_PIN_SWITCH("Headset Jack"),\r
+       SOC_DAPM_PIN_SWITCH("Ext Spk"),\r
+       SOC_DAPM_PIN_SWITCH("Headphone Jack"),\r
+};\r
+\r
+static int rk616_init(struct snd_soc_pcm_runtime *rtd)\r
+{\r
+       struct snd_soc_codec *codec = rtd->codec;\r
+       struct snd_soc_dapm_context *dapm = &codec->dapm;\r
+\r
+       DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);\r
+\r
+       snd_soc_add_controls(codec, rk_controls,\r
+                       ARRAY_SIZE(rk_controls));\r
+\r
+       /* Add specific widgets */\r
+       snd_soc_dapm_new_controls(dapm, rk_dapm_widgets,\r
+                                 ARRAY_SIZE(rk_dapm_widgets));\r
+       /* Set up specific audio path audio_mapnects */\r
+       snd_soc_dapm_add_routes(dapm, rk_audio_map, ARRAY_SIZE(rk_audio_map));\r
+\r
+       snd_soc_dapm_enable_pin(dapm, "Mic Jack");\r
+       snd_soc_dapm_enable_pin(dapm, "Headset Jack");\r
+       snd_soc_dapm_enable_pin(dapm, "Ext Spk");\r
+       snd_soc_dapm_enable_pin(dapm, "Headphone Jack");\r
+\r
+       snd_soc_dapm_sync(dapm);\r
+\r
+       return 0;\r
+}\r
+\r
+static int rk_hifi_hw_params(struct snd_pcm_substream *substream,\r
+       struct snd_pcm_hw_params *params)\r
+{\r
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;\r
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;\r
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;\r
+       unsigned int pll_out = 0;\r
+       int ret;\r
+\r
+       DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);\r
+                \r
+       /* set codec DAI configuration */\r
+       #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) \r
+\r
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |\r
+                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);\r
+       #endif  \r
+       #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) \r
+\r
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |\r
+                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM ); \r
+       #endif\r
+       if (ret < 0)\r
+               return ret; \r
+\r
+       /* set cpu DAI configuration */\r
+       #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) \r
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |\r
+                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);\r
+       #endif  \r
+       #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) \r
+       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |\r
+                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); \r
+       #endif          \r
+       if (ret < 0)\r
+               return ret;\r
+\r
+       switch(params_rate(params)) {\r
+               case 8000:\r
+               case 16000:\r
+               case 24000:\r
+               case 32000:\r
+               case 48000:\r
+                       pll_out = 12288000;\r
+                       break;\r
+               case 11025:\r
+               case 22050:\r
+               case 44100:\r
+                       pll_out = 11289600;\r
+                       break;\r
+               default:\r
+                       DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));\r
+                       return -EINVAL;\r
+                       break;\r
+       }\r
+\r
+       DBG("Enter:%s, %d, rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));\r
+\r
+       /*Set the system clk for codec*/\r
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN);\r
+       if (ret < 0) {\r
+               DBG("rk_hifi_hw_params:failed to set the sysclk for codec side\n"); \r
+               return ret;\r
+       }\r
+\r
+       snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);\r
+       snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1);\r
+       snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);\r
+\r
+       DBG("Enter:%s, %d, pll_out/4/params_rate(params) = %d \n", __FUNCTION__, __LINE__, (pll_out/4)/params_rate(params));\r
\r
+       return 0;\r
+}\r
+\r
+static int rk_voice_hw_params(struct snd_pcm_substream *substream,\r
+       struct snd_pcm_hw_params *params)\r
+{\r
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;\r
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;\r
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;\r
+       unsigned int pll_out = 0;\r
+       int ret;\r
+\r
+       DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);    \r
+       \r
+       /* set codec DAI configuration */\r
+       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A |\r
+                               SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS);\r
+\r
+       switch(params_rate(params)) {\r
+               case 8000:\r
+               case 16000:\r
+               case 24000:\r
+               case 32000:\r
+               case 48000:\r
+                       pll_out = 12288000;\r
+                       break;\r
+               case 11025:\r
+               case 22050:\r
+               case 44100:\r
+                       pll_out = 11289600;\r
+                       break;\r
+               default:\r
+                       DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));\r
+                       return -EINVAL;\r
+                       break;\r
+       }\r
+\r
+       //snd_soc_dai_set_pll(codec_dai, RT5625_PLL_MCLK_TO_VSYSCLK, 0, pll_out, 24576000);\r
+\r
+       /*Set the system clk for codec*/\r
+       ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN);\r
+\r
+       if (ret < 0) {\r
+               printk("rk_voice_hw_params:failed to set the sysclk for codec side\n"); \r
+               return ret;\r
+       }\r
+\r
+       ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);\r
\r
+       return 0;\r
+}\r
+\r
+static struct snd_soc_ops rk616_hifi_ops = {\r
+       .hw_params = rk_hifi_hw_params,\r
+};\r
+\r
+static struct snd_soc_ops rk616_voice_ops = {\r
+       .hw_params = rk_voice_hw_params,\r
+};\r
+\r
+static struct snd_soc_dai_link rk_dai[] = {\r
+       {\r
+               .name = "RK616 I2S1",\r
+               .stream_name = "RK616 PCM",\r
+               .codec_name = "rk616 codec.0-0050",\r
+               .platform_name = "rockchip-audio",\r
+               .cpu_dai_name = "rk29_i2s.0",\r
+               .codec_dai_name = "rk616-hifi",\r
+               .init = rk616_init,\r
+               .ops = &rk616_hifi_ops,\r
+       },\r
+       {\r
+               .name = "RK616 I2S2",\r
+               .stream_name = "RK616 PCM",\r
+               .codec_name = "rtk616.0-001f",\r
+               .platform_name = "rockchip-audio",\r
+               .cpu_dai_name = "rk29_i2s.0",\r
+               .codec_dai_name = "rk616-voice",\r
+               .ops = &rk616_voice_ops,\r
+       },\r
+};\r
+\r
+static struct snd_soc_card snd_soc_card_rk = {\r
+       .name = "RK_RK616",\r
+       .dai_link = rk_dai,\r
+       .num_links = 2,\r
+};\r
+\r
+static struct platform_device *rk_snd_device;\r
+\r
+static int __init audio_card_init(void)\r
+{\r
+       int ret =0;\r
+\r
+       DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);\r
+\r
+       rk_snd_device = platform_device_alloc("soc-audio", -1);\r
+       if (!rk_snd_device) {\r
+                 printk("platform device allocation failed\n");\r
+                 return -ENOMEM;\r
+       }\r
+\r
+       platform_set_drvdata(rk_snd_device, &snd_soc_card_rk);\r
+       ret = platform_device_add(rk_snd_device);\r
+       if (ret) {\r
+               printk("platform device add failed\n");\r
+\r
+               platform_device_put(rk_snd_device);\r
+               return ret;\r
+       }\r
+\r
+        return ret;\r
+}\r
+\r
+static void __exit audio_card_exit(void)\r
+{\r
+       platform_device_unregister(rk_snd_device);\r
+}\r
+\r
+module_init(audio_card_init);\r
+module_exit(audio_card_exit);\r
+/* Module information */\r
+MODULE_AUTHOR("rockchip");\r
+MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");\r
+MODULE_LICENSE("GPL");\r