From f0c3f25b04e29e8791112634ee556cd7141bce30 Mon Sep 17 00:00:00 2001
From: =?utf8?q?=E9=99=88=E9=87=91=E6=B3=89?= <chenjq@rock-chips.com>
Date: Wed, 30 Nov 2011 11:42:08 +0800
Subject: [PATCH] add tlv320aic3111 codec driver

---
 sound/soc/codecs/Kconfig         |    4 +
 sound/soc/codecs/Makefile        |    2 +
 sound/soc/codecs/tlv320aic3111.c | 1925 ++++++++++++++++++++++++++++++
 sound/soc/codecs/tlv320aic3111.h |  621 ++++++++++
 sound/soc/rk29/Kconfig           |   13 +-
 sound/soc/rk29/Makefile          |    2 +
 sound/soc/rk29/rk29_aic3111.c    |  219 ++++
 7 files changed, 2784 insertions(+), 2 deletions(-)
 create mode 100644 sound/soc/codecs/tlv320aic3111.c
 create mode 100644 sound/soc/codecs/tlv320aic3111.h
 create mode 100644 sound/soc/rk29/rk29_aic3111.c

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 9dfeb311759f..95da908c85f9 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -50,6 +50,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_TLV320AIC3X if I2C
 	select SND_SOC_TPA6130A2 if I2C
 	select SND_SOC_TLV320DAC33 if I2C
+	select SND_SOC_TLV320AIC3111 if I2C
 	select SND_SOC_TWL4030 if TWL4030_CORE
 	select SND_SOC_TWL6040 if TWL4030_CORE
 	select SND_SOC_UDA134X
@@ -242,6 +243,9 @@ config SND_SOC_TLV320AIC3X
 config SND_SOC_TLV320DAC33
 	tristate
 
+config SND_SOC_TLV320AIC3111
+	tristate
+
 config SND_SOC_TWL4030
 	select TWL4030_CODEC
 	tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index b5c69a02e817..e9d88b2d3ba5 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -33,6 +33,7 @@ snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
+snd-soc-tlv320aic3111-objs := tlv320aic3111.o
 snd-soc-tlv320dac33-objs := tlv320dac33.o
 snd-soc-twl4030-objs := twl4030.o
 snd-soc-twl6040-objs := twl6040.o
@@ -130,6 +131,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC23)	+= snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)	+= snd-soc-tlv320aic26.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3X)	+= snd-soc-tlv320aic3x.o
 obj-$(CONFIG_SND_SOC_TVL320AIC32X4)     += snd-soc-tlv320aic32x4.o
+obj-$(CONFIG_SND_SOC_TLV320AIC3111)	+= snd-soc-tlv320aic3111.o
 obj-$(CONFIG_SND_SOC_TLV320DAC33)	+= snd-soc-tlv320dac33.o
 obj-$(CONFIG_SND_SOC_TWL4030)	+= snd-soc-twl4030.o
 obj-$(CONFIG_SND_SOC_TWL6040)	+= snd-soc-twl6040.o
diff --git a/sound/soc/codecs/tlv320aic3111.c b/sound/soc/codecs/tlv320aic3111.c
new file mode 100644
index 000000000000..b065f0f446d4
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic3111.c
@@ -0,0 +1,1925 @@
+/*
+ * linux/sound/soc/codecs/tlv320aic3111.c
+ *
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * Rev 0.1   ASoC driver support    Mistral         14-04-2010
+ * 
+ * Rev 0.2   Updated based Review Comments Mistral      29-06-2010 
+ *
+ * Rev 0.3   Updated for Codec Family Compatibility     12-07-2010
+ */
+
+/*
+ ***************************************************************************** 
+ * Include Files
+ ***************************************************************************** 
+ */
+#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/cdev.h>
+
+#include <linux/proc_fs.h>
+#include <linux/seq_file.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 <mach/gpio.h>
+#include "tlv320aic3111.h"
+
+#if 0
+#define AIC3111_DEBUG
+#define	AIC_DBG(x...)	printk(KERN_INFO x)
+#else
+#define	AIC_DBG(x...)	do { } while (0)
+#endif
+
+#define HP_DET_PIN 		RK29_PIN6_PA0
+//#define AIC3111_DEBUG
+/* codec status */
+#define AIC3110_IS_SHUTDOWN	0
+#define AIC3110_IS_CAPTURE_ON	1
+#define AIC3110_IS_PLAYBACK_ON	2
+#define AIC3110_IS_INITPOWER_ON	4
+
+/* work type */
+#define AIC3110_POWERDOWN_NULL	0
+#define AIC3110_POWERDOWN_PLAYBACK	1
+#define AIC3110_POWERDOWN_CAPTURE	2
+#define AIC3110_POWERDOWN_PLAYBACK_CAPTURE	3
+#define JACK_DET_ADLOOP         msecs_to_jiffies(200)
+
+//#define AIC3111_DEBUG
+#define SPK 1
+#define HP 0
+static int aic3111_power_speaker (bool on);
+struct speaker_data {
+     struct timer_list timer;
+     struct semaphore sem;
+};
+enum 
+{
+	POWER_STATE_OFF = 0,
+	POWER_STATE_ON,
+
+	POWER_STATE_SW_HP = 0,
+	POWER_STATE_SW_SPK,
+}; 
+
+static void aic3111_work(struct work_struct *work);
+
+static struct workqueue_struct *aic3111_workq;
+static DECLARE_DELAYED_WORK(delayed_work, aic3111_work);
+static int aic3111_current_status = AIC3110_IS_SHUTDOWN, aic3111_work_type = AIC3110_POWERDOWN_NULL;
+static bool isHSin = true, isSetHW = false;
+int old_status = SPK;
+/*
+ ***************************************************************************** 
+ * Global Variables
+ ***************************************************************************** 
+ */
+/* Used to maintain the Register Access control*/
+static u8 aic3111_reg_ctl;
+
+static struct snd_soc_codec *aic3111_codec;
+struct aic3111_priv *aic3111_privdata;
+struct i2c_client *aic3111_i2c;
+
+  /* add a timer for checkout HP or SPK*/
+static struct timer_list aic3111_timer;
+
+/*Used to delay work hpdet switch irq handle*/
+struct delayed_work aic3111_hpdet_work;
+
+#ifdef CONFIG_MINI_DSP
+extern int aic3111_minidsp_program (struct snd_soc_codec *codec);
+extern void aic3111_add_minidsp_controls (struct snd_soc_codec *codec);
+#endif
+
+/*
+ *	AIC3111 register cache
+ *	We are caching the registers here.
+ *	NOTE: In AIC3111, there are 61 pages of 128 registers supported.
+ * 	The following table contains the page0, page1 and page2 registers values.
+ */
+
+#ifdef AIC3111_CODEC_SUPPORT
+static const u8 aic31xx_reg[AIC31xx_CACHEREGNUM] = {
+/* Page 0 Registers */
+/* 0  */ 0x00, 0x00, 0x12, 0x00, 0x00, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x01, 0x00, 0x80, 0x80,
+/* 10 */ 0x08, 0x00, 0x01, 0x01, 0x80, 0x80, 0x04, 0x00, 0x01, 0x00, 0x00,
+  0x00, 0x01, 0x00, 0x00, 0x00,
+/* 20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x55, 0x55, 0x00, 0x00,
+  0x00, 0x01, 0x01, 0x00, 0x14,
+/* 40 */ 0x0c, 0x00, 0x00, 0x00, 0x6f, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xee, 0x10, 0xd8, 0x7e, 0xe3,
+/* 50 */ 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 70 */ 0x00, 0x00, 0x10, 0x32, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x12, 0x02,
+/* Page 1 Registers */
+/* 0 */ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x80, 0x80, 0x00, 0x00, 0x00,
+/* 40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 70 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+#elif defined(AIC3110_CODEC_SUPPORT)
+/**************** AIC3110 REG CACHE ******************/
+static const u8 aic31xx_reg[AIC31xx_CACHEREGNUM] = {
+/* Page 0 Registers */
+0x00, 0x00, 0x01, 0x56, 0x00, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x80, 0x80, 
+0x08, 0x00, 0x01, 0x01, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x02, 0x32, 0x12, 0x03, 0x02, 0x02, 0x11, 0x10, 0x00, 0x01, 0x04, 0x00, 0x14, 
+0x0c, 0x00, 0x00, 0x00, 0x0f, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0x10, 0xd8, 0x7e, 0xe3, 
+0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+/* Page 1 Registers */
+0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 
+0x06, 0x3e, 0x00, 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x02, 0x02, 0x00, 0x00, 0x20, 0x86, 0x00, 0x80, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+}; /**************************** End of AIC3110 REG CAHE ******************/
+
+#elif defined(AIC3100_CODEC_SUPPORT)
+/******************************* AIC3100 REG CACHE ***********************/
+static const u8 aic31xx_reg[AIC31xx_CACHEREGNUM] = {
+/* Page 0 Registers */
+/* 0  */ 0x00, 0x00, 0x12, 0x00, 0x00, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x01, 0x00, 0x80, 0x00,
+/* 10 */ 0x00, 0x00, 0x01, 0x01, 0x80, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+  0x00, 0x01, 0x00, 0x00, 0x00,
+/* 20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x55, 0x55, 0x00, 0x00,
+  0x00, 0x01, 0x01, 0x00, 0x14,
+/* 40 */ 0x0c, 0x00, 0x00, 0x00, 0x6f, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xee, 0x10, 0xd8, 0x7e, 0xe3,
+/* 50 */ 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 70 */ 0x00, 0x00, 0x10, 0x32, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x12, 0x02,
+/* Page 1 Registers */
+/* 0 */ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x80, 0x80, 0x00, 0x00, 0x00,
+/* 40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 70 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+}; /**************************** End of AIC3100 REG CACHE ******************/
+
+#else /*#ifdef AIC3120_CODEC_SUPPORT */
+static const u8 aic31xx_reg[AIC31xx_CACHEREGNUM] = {
+/* Page 0 Registers */
+/* 0  */ 0x00, 0x00, 0x12, 0x00, 0x00, 0x11, 0x04, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x01, 0x00, 0x80, 0x80,
+/* 10 */ 0x08, 0x00, 0x01, 0x01, 0x80, 0x80, 0x04, 0x00, 0x01, 0x00, 0x00,
+  0x00, 0x01, 0x00, 0x00, 0x00,
+/* 20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x55, 0x55, 0x00, 0x00,
+  0x00, 0x01, 0x01, 0x00, 0x14,
+/* 40 */ 0x0c, 0x00, 0x00, 0x00, 0x6f, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0xee, 0x10, 0xd8, 0x7e, 0xe3,
+/* 50 */ 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 70 */ 0x00, 0x00, 0x10, 0x32, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x12, 0x02,
+/* Page 1 Registers */
+/* 0 */ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x80, 0x80, 0x00, 0x00, 0x00,
+/* 40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+/* 70 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+#endif
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_change_page
+ * Purpose  : This function is to switch between page 0 and page 1.
+ *            
+ *----------------------------------------------------------------------------
+ */
+static int aic3111_change_page (struct snd_soc_codec *codec, u8 new_page)
+{
+	struct aic3111_priv *aic3111 = aic3111_privdata;
+	u8 data[2];
+
+	if (new_page == 2 || new_page > 8) {
+		printk("ERROR::codec do not have page %d !!!!!!\n", new_page);
+		return -1;
+	}
+
+	data[0] = 0;
+	data[1] = new_page;
+	aic3111->page_no = new_page;
+
+	if (codec->hw_write (codec->control_data, data, 2) != 2)
+	{
+		printk ("Error in changing page to %d \n", new_page);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_write_reg_cache
+ * Purpose  : This function is to write aic3111 register cache
+ *            
+ *----------------------------------------------------------------------------
+ */
+static inline void aic3111_write_reg_cache (struct snd_soc_codec *codec, u16 reg, u8 value)
+{
+	u8 *cache = codec->reg_cache;
+
+	if (reg >= AIC31xx_CACHEREGNUM)
+	{
+		return;
+	}
+
+	cache[reg] = value;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_read
+ * Purpose  : This function is to read the aic3111 register space.
+ *            
+ *----------------------------------------------------------------------------
+ */
+static unsigned int aic3111_read (struct snd_soc_codec *codec, unsigned int reg)
+{
+	struct aic3111_priv *aic3111 = aic3111_privdata;
+	u8 value;
+	u8 page = reg / 128;
+
+	if (page == 2 || page > 8) {
+		printk("aic3111_read::Error page, there's not page %d in codec tlv320aic3111 !!!\n", page);
+		return -1;
+	}
+
+	reg = reg % 128;
+
+	if (aic3111->page_no != page)
+	{
+		aic3111_change_page (codec, page);
+	}
+
+	i2c_master_send (codec->control_data, (char *) &reg, 1);
+	i2c_master_recv (codec->control_data, &value, 1);
+
+	return value;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_write
+ * Purpose  : This function is to write to the aic3111 register space.
+ *            
+ *----------------------------------------------------------------------------
+ */
+static int aic3111_write (struct snd_soc_codec *codec, unsigned int reg, unsigned int value)
+{
+	struct aic3111_priv *aic3111 = aic3111_privdata;
+	u8 data[2];
+	u8 page;
+        //printk("enter %s!!!!!!\n",__FUNCTION__);
+	//printk("RK29_PIN6_PB6 =%d!!!!!!\n",gpio_get_value(RK29_PIN6_PB6));
+	page = reg / 128;
+ 	data[AIC3111_REG_OFFSET_INDEX] = reg % 128;
+
+	if (page == 2 || page > 9) {
+		printk("aic3111_write::Error page, there's not page %d in codec tlv320aic3111 !!!\n", page);
+		return -1;
+	}
+
+	if (aic3111->page_no != page)
+	{
+		aic3111_change_page (codec, page);
+	}
+
+	/* data is
+	*   D15..D8 aic3111 register offset
+	*   D7...D0 register data
+	*/
+	data[AIC3111_REG_DATA_INDEX] = value & AIC3111_8BITS_MASK;
+#if defined(EN_REG_CACHE)
+	if ((page == 0) || (page == 1))
+	{
+		aic3111_write_reg_cache (codec, reg, value);
+	}
+#endif
+	if (codec->hw_write (codec->control_data, data, 2) != 2)
+	{
+		printk ("Error in i2c write\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int aic3111_print_register_cache (struct platform_device *pdev)
+{
+	struct snd_soc_codec *codec = aic3111_codec;
+	u8 *cache = codec->reg_cache;
+	int reg;
+
+	printk ("\n========3110 reg========\n");
+	for (reg = 0; reg < codec->reg_size; reg++) 
+	{
+		if (reg == 0) printk ("Page 0\n");
+		if (reg == 128) printk ("\nPage 1\n");
+		if (reg%16 == 0 && reg != 0 && reg != 128) printk ("\n");
+		printk("0x%02x, ",aic3111_read(codec,reg));
+	}
+	printk ("\n========3110 cache========\n");
+	for (reg = 0; reg < codec->reg_size; reg++) 
+	{
+		if (reg == 0) printk ("Page 0\n");
+		if (reg == 128) printk ("\nPage 1\n");
+		if (reg%16 == 0 && reg != 0 && reg != 128) printk ("\n");
+		printk ("0x%02x, ",cache[reg]);
+	}
+	printk ("\n==========================\n");
+	return 0;
+}
+
+static void aic3111_soft_reset (void)
+{
+	struct snd_soc_codec *codec = aic3111_codec;
+
+	AIC_DBG("CODEC::%s\n",__FUNCTION__);
+
+	//aic3111_write (codec, 1, 0x01);
+	aic3111_write (codec, 63, 0x00);
+	gpio_set_value(RK29_PIN6_PB5, GPIO_LOW);
+	msleep(10);
+	aic3111_write (aic3111_codec, (68), 0x01); //disable DRC
+	aic3111_write (aic3111_codec, (128 + 31), 0xc4);
+	aic3111_write (aic3111_codec, (128 + 36), 0x28); //Left Analog Vol to HPL
+	aic3111_write (aic3111_codec, (128 + 37), 0x28); //Right Analog Vol to HPL
+	aic3111_write (aic3111_codec, (128 + 40), 0x4f); //HPL driver PGA
+	aic3111_write (aic3111_codec, (128 + 41), 0x4f); //HPR driver PGA
+	aic3111_power_speaker(POWER_STATE_OFF);	
+	mdelay (20);
+	aic3111_write (codec, 1, 0x00);
+
+	memcpy(codec->reg_cache, aic31xx_reg,
+	       sizeof(aic31xx_reg));
+
+	isSetHW = false;
+
+	return;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_set_bias_level
+ * Purpose  : This function is to get triggered when dapm events occurs.
+ *            
+ *----------------------------------------------------------------------------
+ */
+static int aic3111_set_bias_level(struct snd_soc_codec *codec,
+			enum snd_soc_bias_level level)
+{
+	struct aic3111_priv *aic3111 = aic3111_privdata;
+	u8 value;
+
+	if (isSetHW)
+		return 0;
+
+	AIC_DBG ("CODEC::%s>>>>>>level:%d>>>>master:%d\n", __FUNCTION__, level, aic3111->master);
+
+  	switch (level) {
+    	 /* full On */
+	case SND_SOC_BIAS_ON:
+      	/* all power is driven by DAPM system */
+      		if (aic3111->master)
+		{
+	 		 /* Switch on PLL */
+	 		value = aic3111_read(codec, CLK_REG_2);
+	 		aic3111_write(codec, CLK_REG_2, (value | ENABLE_PLL));
+
+	  		/* Switch on NDAC Divider */
+	  		value = aic3111_read(codec, NDAC_CLK_REG);
+	  		aic3111_write(codec, NDAC_CLK_REG, value | ENABLE_NDAC);
+
+	  		/* Switch on MDAC Divider */
+	  		value = aic3111_read(codec, MDAC_CLK_REG);
+	 		aic3111_write(codec, MDAC_CLK_REG, value | ENABLE_MDAC);
+
+	  		/* Switch on NADC Divider */
+	  		value = aic3111_read(codec, NADC_CLK_REG);
+	  		aic3111_write(codec, NADC_CLK_REG, value | ENABLE_MDAC);
+
+	 		/* Switch on MADC Divider */
+	 		value = aic3111_read(codec, MADC_CLK_REG);
+	  		aic3111_write(codec, MADC_CLK_REG, value | ENABLE_MDAC);
+
+	 		/* Switch on BCLK_N Divider */
+	 		value = aic3111_read(codec, BCLK_N_VAL);
+	  		aic3111_write(codec, BCLK_N_VAL, value | ENABLE_BCLK);
+		} else {
+	  		/* Switch on PLL */
+	  		value = aic3111_read(codec, CLK_REG_2);
+	 		aic3111_write(codec, CLK_REG_2, (value | ENABLE_PLL));
+
+	  		/* Switch on NDAC Divider */
+	  		value = aic3111_read(codec, NDAC_CLK_REG);
+	  		aic3111_write(codec, NDAC_CLK_REG, value | ENABLE_NDAC);
+
+	  		/* Switch on MDAC Divider */
+	  		value = aic3111_read(codec, MDAC_CLK_REG);
+	  		aic3111_write(codec, MDAC_CLK_REG, value | ENABLE_MDAC);
+
+	  		/* Switch on NADC Divider */
+	  		value = aic3111_read(codec, NADC_CLK_REG);
+	  		aic3111_write(codec, NADC_CLK_REG, value | ENABLE_MDAC);
+
+	  		/* Switch on MADC Divider */
+	  		value = aic3111_read(codec, MADC_CLK_REG);
+	  		aic3111_write(codec, MADC_CLK_REG, value | ENABLE_MDAC);
+
+	  		/* Switch on BCLK_N Divider */
+	  		value = aic3111_read(codec, BCLK_N_VAL);
+	  		aic3111_write(codec, BCLK_N_VAL, value | ENABLE_BCLK);
+		}
+		break;
+
+	/* partial On */
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	/* Off, with power */
+	case SND_SOC_BIAS_STANDBY:
+		/*
+		 * all power is driven by DAPM system,
+		 * so output power is safe if bypass was set
+		 */
+		if (aic3111->master)
+		{
+			/* Switch off PLL */
+			value = aic3111_read(codec, CLK_REG_2);
+			aic3111_write(codec, CLK_REG_2, (value & ~ENABLE_PLL));
+
+			/* Switch off NDAC Divider */
+			value = aic3111_read(codec, NDAC_CLK_REG);
+			aic3111_write(codec, NDAC_CLK_REG, value & ~ENABLE_NDAC);
+
+			/* Switch off MDAC Divider */
+			value = aic3111_read(codec, MDAC_CLK_REG);
+			aic3111_write(codec, MDAC_CLK_REG, value & ~ENABLE_MDAC);
+
+			/* Switch off NADC Divider */
+			value = aic3111_read(codec, NADC_CLK_REG);
+			aic3111_write(codec, NADC_CLK_REG, value & ~ENABLE_NDAC);
+
+			/* Switch off MADC Divider */
+			value = aic3111_read(codec, MADC_CLK_REG);
+			aic3111_write(codec, MADC_CLK_REG, value & ~ENABLE_MDAC);
+			value = aic3111_read(codec, BCLK_N_VAL);
+
+			/* Switch off BCLK_N Divider */
+			aic3111_write(codec, BCLK_N_VAL, value & ~ENABLE_BCLK);
+		}
+		break;
+
+	/* Off, without power */
+	case SND_SOC_BIAS_OFF:
+		/* force all power off */
+		break;
+	}
+	codec->dapm.bias_level = level;
+	return 0;
+}
+
+/* the structure contains the different values for mclk */
+static const struct aic3111_rate_divs aic3111_divs[] = {
+/* 
+ * mclk, rate, p_val, pll_j, pll_d, dosr, ndac, mdac, aosr, nadc, madc, blck_N, 
+ * codec_speficic_initializations 
+ */
+  /* 8k rate */
+  {12000000, 8000, 1, 7, 6800, 768,  5, 3, 128, 5, 18, 24},
+  //{12288000, 8000, 1, 7, 8643, 768,  5, 3, 128, 5, 18, 24},
+  {24000000, 8000, 2, 7, 6800, 768, 15, 1,  64, 45, 4, 24},
+  /* 11.025k rate */
+  {12000000, 11025, 1, 7, 5264, 512,  8, 2, 128,  8, 8, 16},
+  {24000000, 11025, 2, 7, 5264, 512, 16, 1,  64, 32, 4, 16},
+  /* 16k rate */
+  {12000000, 16000, 1, 7, 6800, 384,  5, 3, 128,  5, 9, 12},
+  {24000000, 16000, 2, 7, 6800, 384, 15, 1,  64, 18, 5, 12},
+  /* 22.05k rate */
+  {12000000, 22050, 1, 7, 5264, 256,  4, 4, 128,  4, 8, 8},
+  {24000000, 22050, 2, 7, 5264, 256, 16, 1,  64, 16, 4, 8},
+  /* 32k rate */
+  {12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6},
+  {24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7,  6, 6},
+  /* 44.1k rate */
+  {12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
+  {11289600, 44100, 1, 8,    0, 128, 4, 4, 128, 4, 4, 4},
+  {24000000, 44100, 2, 7, 5264, 128, 8, 2,  64, 8, 4, 4},
+  /* 48k rate */
+  {12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4},
+  {24000000, 48000, 2, 8, 1920, 128, 8, 2,  64, 8, 4, 4},
+  /*96k rate */
+  {12000000, 96000, 1, 8, 1920, 64, 2, 8, 64, 2, 8, 2},
+  {24000000, 96000, 2, 8, 1920, 64, 4, 4, 64, 8, 2, 2},
+  /*192k */
+  {12000000, 192000, 1, 8, 1920, 32, 2, 8, 32, 2, 8, 1},
+  {24000000, 192000, 2, 8, 1920, 32, 4, 4, 32, 4, 4, 1},
+};
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_get_divs
+ * Purpose  : This function is to get required divisor from the "aic3111_divs"
+ *            table.
+ *            
+ *----------------------------------------------------------------------------
+ */
+static inline int aic3111_get_divs (int mclk, int rate)
+{
+	int i;
+
+	AIC_DBG("Enter::%s\n",__FUNCTION__);
+
+	for (i = 0; i < ARRAY_SIZE (aic3111_divs); i++)
+	{
+		if ((aic3111_divs[i].rate == rate) && (aic3111_divs[i].mclk == mclk))
+		{
+			return i;
+		}
+	}
+
+	printk ("Master clock and sample rate is not supported\n");
+	return -EINVAL;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_hw_params
+ * Purpose  : This function is to set the hardware parameters for AIC3111.
+ *            The functions set the sample rate and audio serial data word 
+ *            length.
+ *            
+ *----------------------------------------------------------------------------
+ */
+static int aic3111_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params,
+                       struct snd_soc_dai *codec_dai)
+{
+	struct snd_soc_codec *codec = aic3111_codec;
+	struct aic3111_priv *aic3111 = aic3111_privdata;
+	int i;
+	u8 data;
+
+	if (isSetHW)
+		return 0;
+
+	AIC_DBG("CODEC::%s\n", __FUNCTION__);
+
+	aic3111_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	i = aic3111_get_divs(aic3111->sysclk, params_rate (params));
+
+	if (i < 0) {
+		printk ("sampling rate not supported\n");
+		return i;
+	}
+
+	/* We will fix R value to 1 and will make P & J=K.D as varialble */
+
+	/* Setting P & R values */
+	aic3111_write(codec, CLK_REG_2, ((aic3111_divs[i].p_val << 4) | 0x01));
+
+	/* J value */
+	aic3111_write(codec, CLK_REG_3, aic3111_divs[i].pll_j);
+
+	/* MSB & LSB for D value */
+	aic3111_write(codec, CLK_REG_4, (aic3111_divs[i].pll_d >> 8));
+	aic3111_write(codec, CLK_REG_5, (aic3111_divs[i].pll_d & AIC3111_8BITS_MASK));
+
+	/* NDAC divider value */
+	aic3111_write(codec, NDAC_CLK_REG, aic3111_divs[i].ndac);
+
+	/* MDAC divider value */
+	aic3111_write(codec, MDAC_CLK_REG, aic3111_divs[i].mdac);
+
+	/* DOSR MSB & LSB values */
+	aic3111_write(codec, DAC_OSR_MSB, aic3111_divs[i].dosr >> 8);
+	aic3111_write(codec, DAC_OSR_LSB, aic3111_divs[i].dosr & AIC3111_8BITS_MASK);
+
+	/* NADC divider value */
+	aic3111_write(codec, NADC_CLK_REG, aic3111_divs[i].nadc);
+
+	/* MADC divider value */
+	aic3111_write(codec, MADC_CLK_REG, aic3111_divs[i].madc);
+
+	/* AOSR value */
+	aic3111_write(codec, ADC_OSR_REG, aic3111_divs[i].aosr);
+
+	/* BCLK N divider */
+	aic3111_write(codec, BCLK_N_VAL, aic3111_divs[i].blck_N);
+
+	aic3111_set_bias_level(codec, SND_SOC_BIAS_ON);
+
+	data = aic3111_read(codec, INTERFACE_SET_REG_1);
+
+	data = data & ~(3 << 4);
+
+	switch (params_format (params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		data |= (AIC3111_WORD_LEN_20BITS << DATA_LEN_SHIFT);
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		data |= (AIC3111_WORD_LEN_24BITS << DATA_LEN_SHIFT);
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		data |= (AIC3111_WORD_LEN_32BITS << DATA_LEN_SHIFT);
+		break;
+	}
+
+	aic3111_write(codec, INTERFACE_SET_REG_1, data);
+
+	return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_mute
+ * Purpose  : This function is to mute or unmute the left and right DAC
+ *            
+ *----------------------------------------------------------------------------
+ */
+static int aic3111_mute (struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u8 dac_reg;
+
+	AIC_DBG ("CODEC::%s>>>>mute:%d\n", __FUNCTION__, mute);
+
+	dac_reg = aic3111_read (codec, DAC_MUTE_CTRL_REG) & ~MUTE_ON;
+	if (mute)
+		;//aic3111_write (codec, DAC_MUTE_CTRL_REG, dac_reg | MUTE_ON);
+	else {
+		//aic3111_write (codec, DAC_MUTE_CTRL_REG, dac_reg);
+		isSetHW = true;
+	}
+
+	return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_set_dai_sysclk
+ * Purpose  : This function is to set the DAI system clock
+ *            
+ *----------------------------------------------------------------------------
+ */
+static int aic3111_set_dai_sysclk (struct snd_soc_dai *codec_dai,
+			int clk_id, unsigned int freq, int dir)
+{
+	struct aic3111_priv *aic3111 = aic3111_privdata;
+
+	if (isSetHW)
+		return 0;
+
+	AIC_DBG("Enter %s and line %d\n",__FUNCTION__,__LINE__);
+
+	switch (freq) {
+	case AIC3111_FREQ_11289600:
+	case AIC3111_FREQ_12000000:
+	case AIC3111_FREQ_24000000:
+		aic3111->sysclk = freq;
+		return 0;
+	}
+
+	printk ("Invalid frequency to set DAI system clock\n");
+	return -EINVAL;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_set_dai_fmt
+ * Purpose  : This function is to set the DAI format
+ *            
+ *----------------------------------------------------------------------------
+ */
+static int aic3111_set_dai_fmt (struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct aic3111_priv *aic3111 = aic3111_privdata;
+	u8 iface_reg;
+
+	if (isSetHW)
+		return 0;
+
+	AIC_DBG("Enter %s and line %d\n",__FUNCTION__,__LINE__);
+
+	iface_reg = aic3111_read (codec, INTERFACE_SET_REG_1);
+	iface_reg = iface_reg & ~(3 << 6 | 3 << 2);   //set I2S mode BCLK and WCLK is input
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		aic3111->master = 1;
+		iface_reg |= BIT_CLK_MASTER | WORD_CLK_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		aic3111->master = 0;
+		iface_reg &= ~(BIT_CLK_MASTER | WORD_CLK_MASTER);
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		aic3111->master = 0;
+		iface_reg |= BIT_CLK_MASTER;
+		iface_reg &= ~(WORD_CLK_MASTER);
+		break;
+	default:
+		printk ("Invalid DAI master/slave interface\n");
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		iface_reg |= (AIC3111_DSP_MODE << AUDIO_MODE_SHIFT);
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		iface_reg |= (AIC3111_RIGHT_JUSTIFIED_MODE << AUDIO_MODE_SHIFT);
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface_reg |= (AIC3111_LEFT_JUSTIFIED_MODE << AUDIO_MODE_SHIFT);
+		break;
+	default:
+		printk ("Invalid DAI interface format\n");
+		return -EINVAL;
+	}
+
+	aic3111_write (codec, INTERFACE_SET_REG_1, iface_reg);
+
+	return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_power_headphone
+ * Purpose  : 
+ * parameter: on = 1: power up;	
+ *            on = 0: power dn;	
+ * xjq@rock-chips.com     
+ *----------------------------------------------------------------------------
+ */
+static int aic3111_power_headphone (bool on)
+{
+	struct snd_soc_codec *codec = aic3111_codec;
+
+	AIC_DBG("Enter %s and line %d\n",__FUNCTION__,__LINE__);
+
+	if (on == POWER_STATE_ON) {
+		aic3111_write (codec, (63), 0xd4);
+//		aic3111_write(codec, (128 + 35), 0x88);
+		aic3111_write (codec, (68), 0x01); //disable DRC
+		aic3111_write (codec, (128 + 31), 0xc4);
+		aic3111_write (codec, (128 + 44), 0x00);
+		aic3111_write (codec, (128 + 36), 0x28); //Left Analog Vol to HPL
+		aic3111_write (codec, (128 + 37), 0x28); //Right Analog Vol to HPL
+//		aic3111_write (codec, (128 + 40), 0x06); //HPL driver PGA
+//		aic3111_write (codec, (128 + 41), 0x06); //HPR driver PGA
+		aic3111_write (codec, (128 + 40), 0x4f); //HPL driver PGA
+		aic3111_write (codec, (128 + 41), 0x4f); //HPR driver PGA
+
+	} else if (on == POWER_STATE_OFF) {
+
+		aic3111_write (codec, (128 + 31), 0x00);
+		aic3111_write (codec, (128 + 44), 0x00);
+		aic3111_write (codec, (128 + 36), 0xff);
+		aic3111_write (codec, (128 + 37), 0xff);
+		aic3111_write (codec, (128 + 40), 0x02);
+		aic3111_write (codec, (128 + 41), 0x02);
+	}
+
+	return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_power_speaker
+ * Purpose  : 
+ * parameter: on = 1: power up;	
+ *            on = 0: power dn;	
+ * xjq@rock-chips.com     
+ *----------------------------------------------------------------------------
+ */
+static int aic3111_power_speaker (bool on)
+{
+	struct snd_soc_codec *codec = aic3111_codec;
+
+	AIC_DBG("Enter %s and line %d\n",__FUNCTION__,__LINE__);
+
+	if (on == POWER_STATE_ON) {
+#if 0
+//		aic3111_write(codec, (128 + 32), 0x86);
+		aic3111_write(codec, (128 + 32), 0xc6);
+		aic3111_write(codec, (128 + 30), 0x00);  
+//		aic3111_write(codec, (128 + 38), 0x08); //set left speaker analog gain to -4.88db
+		aic3111_write(codec, (128 + 38), 0x16); //set left speaker analog gain to -4.88db
+		aic3111_write(codec, (128 + 39), 0x16); //Right Analog Vol to SPR
+//		aic3111_write(codec, (128 + 38), 0x7f); //set left speaker analog gain to -4.88db
+//		aic3111_write(codec, (128 + 39), 0x7f); //Right Analog Vol to SPR
+		aic3111_write(codec, (128 + 42), 0x1d); //set left speaker driver gain to 12db
+		aic3111_write(codec, (128 + 43), 0x1d); //bit3-4 output stage gain
+//		aic3111_write(codec, (128 + 43), 0x00); //bit3-4 output stage gain
+		aic3111_write(codec, (37), 0x98);
+
+#if 1		/* DRC */
+		aic3111_write(codec, (60), 0x02); //select PRB_P2
+		aic3111_write(codec, (68), 0x61); //enable left and right DRC, set DRC threshold to -3db, set DRC hystersis to 1db
+		aic3111_write(codec, (69), 0x00); //set hold time disable
+		aic3111_write(codec, (70), 0x5D); //set attack time to 0.125db per sample period and decay time to 0.000488db per sample
+#endif
+#endif
+#if 1
+		aic3111_write(codec, (63), 0xfc);
+		aic3111_write(codec, (128 + 32), 0xc6);
+		aic3111_write(codec, (128 + 30), 0x00);
+		aic3111_write(codec, (128 + 39), 0x08); //set left speaker analog gain to -4.88db
+		aic3111_write(codec, (128 + 38), 0x08); //Right Analog Vol to SPR
+		aic3111_write(codec, (128 + 43), 0x0D); //set left speaker driver gain to 12db
+		aic3111_write(codec, (128 + 42), 0x0D); //bit3-4 output stage gain
+		aic3111_write(codec, (37), 0x99);
+
+#if 1		/* DRC */
+		aic3111_write(codec, (60), 0x02); //select PRB_P2
+		aic3111_write(codec, (68), 0x61); //enable left and right DRC, set DRC threshold to -3db, set DRC hystersis to 1db
+		aic3111_write(codec, (69), 0x00); //set hold time disable
+		aic3111_write(codec, (70), 0x5D); //set attack time to 0.125db per sample period and decay time to 0.000488db per sample
+#endif
+#endif
+	} else if (on == POWER_STATE_OFF) {
+
+		aic3111_write(codec, (68), 0x01); //disable DRC
+		aic3111_write(codec, (128 + 32), 0x06);
+		aic3111_write(codec, (128 + 30), 0x00);
+		aic3111_write(codec, (128 + 38), 0xff);
+		aic3111_write(codec, (128 + 39), 0xff);
+		aic3111_write(codec, (128 + 42), 0x00);
+		aic3111_write(codec, (128 + 43), 0x00);
+		aic3111_write(codec, (37), 0x00);
+	}
+
+	return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_HS_switch
+ * Purpose  : This function is to initialise the AIC3111 driver
+ *            In PLAYBACK, switch between HP and SPK app.	
+ * parameter: on = 1: SPK power up & HP  power dn;	
+ *            on = 0: HP  power up & SPK power dn;		
+ * xjq@rock-chips.com     
+ *----------------------------------------------------------------------------
+ */
+static int aic3111_HS_switch (bool on)
+{
+	AIC_DBG("enter %s and line %d\n",__FUNCTION__,__LINE__);
+
+	if (POWER_STATE_SW_SPK == on) {
+
+		//aic3111_power_headphone (POWER_STATE_OFF);
+		aic3111_power_speaker (POWER_STATE_ON);
+	} else if (POWER_STATE_SW_HP == on) {
+
+		aic3111_power_speaker (POWER_STATE_OFF);
+		//aic3111_power_headphone (POWER_STATE_ON);
+
+		//aic3111_power_speaker (POWER_STATE_ON);
+		//aic3111_power_headphone (POWER_STATE_OFF);
+	}
+
+	return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_SPK_HS_powerdown
+ * Purpose  : This function is to power down HP and SPK.			
+ * xjq@rock-chips.com
+ *----------------------------------------------------------------------------
+ */
+static int aic3111_SPK_HS_powerdown (void)
+{
+	AIC_DBG("enter %s and line %d\n",__FUNCTION__,__LINE__);
+
+	//aic3111_power_headphone (POWER_STATE_OFF);
+	aic3111_power_speaker (POWER_STATE_OFF);
+//	aic3111_power_speaker (POWER_STATE_ON);
+
+	return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_power_init
+ * Purpose  : pll clock setting
+ * parameter: on = 1: power up;	
+ *            on = 0: power dn;	
+ * xjq@rock-chips.com     
+ *----------------------------------------------------------------------------
+ */
+static void aic3111_power_init (void)
+{
+	struct snd_soc_codec *codec = aic3111_codec;
+
+	AIC_DBG("enter %s and line %d\n",__FUNCTION__,__LINE__);
+
+	if (!(aic3111_current_status & AIC3110_IS_INITPOWER_ON)) {
+
+		AIC_DBG ("CODEC::%s\n", __FUNCTION__);
+
+		aic3111_write(codec, (128 + 46), 0x0b);
+		aic3111_write(codec, (128 + 35), 0x44);
+		aic3111_write(codec,  (4), 0x03);
+		aic3111_write(codec, (29), 0x01);
+		aic3111_write(codec, (48), 0xC0);
+		aic3111_write(codec, (51), 0x14);
+		aic3111_write(codec, (67), 0x82);
+
+		aic3111_current_status |= AIC3110_IS_INITPOWER_ON;
+	}
+
+	return;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_power_playback
+ * Purpose  : 
+ * parameter: on = 1: power up;	
+ *            on = 0: power dn;	
+ * xjq@rock-chips.com     
+ *----------------------------------------------------------------------------
+ */
+static int aic3111_power_playback (bool on)
+{
+	struct snd_soc_codec *codec = aic3111_codec;
+
+	AIC_DBG ("CODEC::%s>>>>>>%d\n", __FUNCTION__, on);
+	gpio_set_value(RK29_PIN6_PB5, GPIO_LOW);
+	aic3111_power_init();
+
+	if ((on == POWER_STATE_ON) &&
+	    !(aic3111_current_status & AIC3110_IS_PLAYBACK_ON)) {
+//	if(1){
+		//gpio_set_value(RK29_PIN6_PB5, GPIO_HIGH);
+
+		/****open HPL and HPR*******/
+		//aic3111_write(codec, (63), 0xfc);
+		msleep(10);
+		aic3111_write(codec, (65), 0x00); //LDAC VOL
+		aic3111_write(codec, (66), 0x00); //RDAC VOL
+		aic3111_write (aic3111_codec, (63), 0xd4);
+//		aic3111_write(codec, (128 + 35), 0x88);
+
+		//aic3111_write (aic3111_codec, (68), 0x01); //disable DRC
+		//aic3111_write (aic3111_codec, (128 + 31), 0xc4);
+		aic3111_write (aic3111_codec, (128 + 44), 0x00);
+		//aic3111_write (aic3111_codec, (128 + 36), 0x28); //Left Analog Vol to HPL
+		//aic3111_write (aic3111_codec, (128 + 37), 0x28); //Right Analog Vol to HPL
+		aic3111_write (codec, (128 + 40), 0x06); //HPL driver PGA
+		aic3111_write (codec, (128 + 41), 0x06); //HPR driver PGA
+		//aic3111_write (aic3111_codec, (128 + 40), 0x4f); //HPL driver PGA
+		//aic3111_write (aic3111_codec, (128 + 41), 0x4f); //HPR driver PGA
+		//printk("HP INIT~~~~~~~~~~~~~~~~~~~~~~~~~`\n");
+		/***************************/		
+		
+		aic3111_HS_switch(isHSin);
+
+		aic3111_write(codec, (65), 0x10); //LDAC VOL to +8db
+		aic3111_write(codec, (66), 0x10); //RDAC VOL to +8db
+		msleep(10);
+		aic3111_write(codec, (64), 0x00);
+		
+		aic3111_current_status |= AIC3110_IS_PLAYBACK_ON;
+
+	} else if ((on == POWER_STATE_OFF) &&
+	           (aic3111_current_status & AIC3110_IS_PLAYBACK_ON)) {
+
+		aic3111_write(codec, (68), 0x01); //disable DRC
+		aic3111_write(codec, (64), 0x0c);
+		aic3111_write(codec, (63), 0x00);
+		aic3111_write(codec, (65), 0x00); //LDAC VOL
+		aic3111_write(codec, (66), 0x00); //RDAC VOL
+
+		aic3111_SPK_HS_powerdown();
+
+		aic3111_current_status &= ~AIC3110_IS_PLAYBACK_ON;
+	}
+	//mdelay(800);
+	gpio_set_value(RK29_PIN6_PB5, GPIO_HIGH);
+
+	return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_power_capture
+ * Purpose  : 
+ * parameter: on = 1: power up;	
+ *            on = 0: power dn;	
+ * xjq@rock-chips.com     
+ *----------------------------------------------------------------------------
+ */
+static int aic3111_power_capture (bool on)
+{
+	struct snd_soc_codec *codec = aic3111_codec;
+
+	AIC_DBG ("CODEC::%s>>>>>>%d\n", __FUNCTION__, on);
+
+	aic3111_power_init();
+
+	if ((on == POWER_STATE_ON) &&
+	    !(aic3111_current_status & AIC3110_IS_CAPTURE_ON)) {
+		aic3111_write(codec, (64), 0x0c);
+		msleep(10);
+
+		aic3111_write(codec, (61), 0x0b);
+		aic3111_write(codec, (128 + 47), 0x00); //MIC PGA 0x80:0dB  0x14:10dB  0x28:20dB  0x3c:30dB 0x77:59dB
+		aic3111_write(codec, (128 + 48), 0x80); //MIC1LP\MIC1LM RIN = 10.
+		aic3111_write(codec, (128 + 49), 0x20);
+		aic3111_write(codec, (82), 0x00); //D7=0:0: ADC channel not muted
+		aic3111_write(codec, (83), 0x1A); //ADC Digital Volume 0 dB
+		aic3111_write(codec, (81), 0x80); //D7=1:ADC channel is powered up.
+
+#if 1
+		/*configure register to creat a filter 20~3.5kHz*/
+
+		aic3111_write(codec, (128*4 + 14), 0x7f);
+		aic3111_write(codec, (128*4 + 15), 0x00);
+		aic3111_write(codec, (128*4 + 16), 0xc0);
+		aic3111_write(codec, (128*4 + 17), 0x18);
+		aic3111_write(codec, (128*4 + 18), 0x00);
+
+		aic3111_write(codec, (128*4 + 19), 0x00);
+		aic3111_write(codec, (128*4 + 20), 0x3f);
+		aic3111_write(codec, (128*4 + 21), 0x00);
+		aic3111_write(codec, (128*4 + 22), 0x00);
+		aic3111_write(codec, (128*4 + 23), 0x00);
+
+		aic3111_write(codec, (128*4 + 24), 0x05);
+		aic3111_write(codec, (128*4 + 25), 0xd2);
+		aic3111_write(codec, (128*4 + 26), 0x05);
+		aic3111_write(codec, (128*4 + 27), 0xd2);
+		aic3111_write(codec, (128*4 + 28), 0x05);
+
+		aic3111_write(codec, (128*4 + 29), 0xd2);
+		aic3111_write(codec, (128*4 + 30), 0x53);
+		aic3111_write(codec, (128*4 + 31), 0xff);
+		aic3111_write(codec, (128*4 + 32), 0xc0);
+		aic3111_write(codec, (128*4 + 33), 0xb5);
+#endif
+		msleep(10);
+		aic3111_write(codec, (64), 0x00);
+		aic3111_current_status |= AIC3110_IS_CAPTURE_ON;
+
+	} else if ((on == POWER_STATE_OFF) &&
+	           (aic3111_current_status & AIC3110_IS_CAPTURE_ON)) {
+
+		aic3111_write(codec, (61), 0x00);
+		aic3111_write(codec, (128 + 47), 0x00); //MIC PGA AOL
+		aic3111_write(codec, (128 + 48), 0x00);
+		aic3111_write(codec, (128 + 50), 0x00);
+		aic3111_write(codec, (81), 0x00);
+		aic3111_write(codec, (82), 0x80);
+		aic3111_write(codec, (83), 0x00); //ADC VOL
+		aic3111_write(codec, (86), 0x00);
+
+		aic3111_current_status &= ~AIC3110_IS_CAPTURE_ON;
+	}
+
+	return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_powerdown
+ * Purpose  : This function is to power down codec.
+ *            
+ *----------------------------------------------------------------------------
+ */
+static void aic3111_powerdown (void)
+{
+	AIC_DBG ("CODEC::%s\n", __FUNCTION__);
+
+	if (aic3111_current_status != AIC3110_IS_SHUTDOWN) {
+		aic3111_soft_reset();//sai
+		aic3111_current_status = AIC3110_IS_SHUTDOWN;
+	}
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_work
+ * Purpose  : This function is to respond to HPDET handle.
+ *            
+ *----------------------------------------------------------------------------
+ */
+static void aic3111_work (struct work_struct *work)
+{
+	AIC_DBG("Enter %s and line %d\n",__FUNCTION__,__LINE__);
+
+	switch (aic3111_work_type) {
+	case AIC3110_POWERDOWN_NULL:
+		break;
+	case AIC3110_POWERDOWN_PLAYBACK:
+		aic3111_power_playback(POWER_STATE_OFF);
+		break;
+	case AIC3110_POWERDOWN_CAPTURE:
+		aic3111_power_capture(POWER_STATE_OFF);
+		break;
+	case AIC3110_POWERDOWN_PLAYBACK_CAPTURE:
+		aic3111_powerdown();//sai
+		break;
+	default:
+		break;
+	}
+
+	aic3111_work_type = AIC3110_POWERDOWN_NULL;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_startup
+ * Purpose  : This function is to start up codec.
+ *            
+ *----------------------------------------------------------------------------
+ */
+static int aic3111_startup (struct snd_pcm_substream *substream,
+			  struct snd_soc_dai *dai)
+{
+/*
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = aic3111_codec;
+*/
+
+	AIC_DBG ("CODEC::%s----substream->stream:%s \n", __FUNCTION__,
+		   substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "PLAYBACK":"CAPTURE");
+
+	cancel_delayed_work_sync(&delayed_work);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+
+		aic3111_power_playback(POWER_STATE_ON);
+
+	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+
+		aic3111_power_capture(POWER_STATE_ON);
+	}
+
+	return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_startup
+ * Purpose  : This function is to shut down codec.
+ *            
+ *----------------------------------------------------------------------------
+ */
+static void aic3111_shutdown (struct snd_pcm_substream *substream,
+			    struct snd_soc_dai *dai)
+{
+	struct snd_soc_dai *codec_dai = dai;
+
+	AIC_DBG ("CODEC::%s----substream->stream:%s \n", __FUNCTION__,
+		   substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "PLAYBACK":"CAPTURE");
+
+	if (!codec_dai->capture_active && !codec_dai->playback_active) {
+
+		cancel_delayed_work_sync(&delayed_work);
+
+		/* If codec is already shutdown, return */
+		if (aic3111_current_status == AIC3110_IS_SHUTDOWN)
+			return;
+
+		AIC_DBG ("CODEC::Is going to power down aic3111\n");
+
+		aic3111_work_type = AIC3110_POWERDOWN_PLAYBACK_CAPTURE;
+
+		/* If codec is useless, queue work to close it */
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			queue_delayed_work(aic3111_workq, &delayed_work,
+				msecs_to_jiffies(1000));
+		}
+		else {
+			queue_delayed_work(aic3111_workq, &delayed_work,
+				msecs_to_jiffies(3000));
+		}
+	} 
+	else if (codec_dai->capture_active && !codec_dai->playback_active) {
+
+		cancel_delayed_work_sync(&delayed_work);
+
+		aic3111_work_type = AIC3110_POWERDOWN_PLAYBACK;
+
+		/* Turn off playback and keep record on */
+		queue_delayed_work(aic3111_workq, &delayed_work,
+			msecs_to_jiffies(1000));
+	} 
+	else if (!codec_dai->capture_active && codec_dai->playback_active) {
+
+		cancel_delayed_work_sync(&delayed_work);
+
+		aic3111_work_type = AIC3110_POWERDOWN_CAPTURE;
+
+		/* Turn off record and keep playback on */
+		queue_delayed_work(aic3111_workq, &delayed_work,
+			msecs_to_jiffies(3000));
+	}
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_trigger
+ * Purpose  : This function is to respond to playback trigger.
+ *            
+ *----------------------------------------------------------------------------
+ */
+static int aic3111_trigger(struct snd_pcm_substream *substream,
+			  int status,
+			  struct snd_soc_dai *dai)
+{
+	struct snd_soc_dai *codec_dai = dai;
+
+	if(status == 0)
+	{
+		gpio_set_value(RK29_PIN6_PB5, GPIO_LOW);
+		mdelay(10);
+	}
+
+	AIC_DBG ("CODEC::%s----status = %d substream->stream:%s \n", __FUNCTION__, status,
+		   substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "PLAYBACK":"CAPTURE");	
+
+	if (status == 1 || status == 0) {
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			codec_dai->playback_active = status;
+		} else {
+			codec_dai->capture_active = status;
+		}
+	}
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops aic3111_dai_ops = {
+	.hw_params = aic3111_hw_params,
+	.digital_mute = aic3111_mute,
+	.set_sysclk = aic3111_set_dai_sysclk,
+	.set_fmt = aic3111_set_dai_fmt,
+	.startup	= aic3111_startup,
+	.shutdown	= aic3111_shutdown,
+	.trigger	= aic3111_trigger,
+};
+
+static struct snd_soc_dai_driver aic3111_dai[] = {
+	{
+		.name = "AIC3111 HiFi",
+		.playback = {
+			.stream_name = "HiFi Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = AIC3111_RATES,
+			.formats = AIC3111_FORMATS,
+		},
+		.capture = {
+			.stream_name = "HiFi Capture",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = AIC3111_RATES,
+			.formats = AIC3111_FORMATS,
+	 	},
+		.ops = &aic3111_dai_ops,
+	},
+};
+
+#ifdef AIC3111_DEBUG
+static struct class *aic3111_debug_class = NULL;
+static int reg_128_39 = 12, reg_128_43 = 0;
+static int i=52;j=1,k=0;
+static int CheckCommand(const char __user *buffer)
+{
+	switch(*buffer) {
+	case '1':
+		if (*(buffer + 1) == '+') {
+			if (reg_128_39 < 12) {
+				if (reg_128_39 % 2 == 0)
+					printk("write reg 128 + 39 vol + : %ddB -> -%d.5dB\n", (reg_128_39 - 12) / 2, (11 - reg_128_39) / 2);
+				else
+					printk("write reg 128 + 39 vol + : -%d.5dB -> %ddB\n", (12 - reg_128_39) / 2, (reg_128_39 - 11) / 2);
+				reg_128_39++;
+				aic3111_write(aic3111_codec, (128 + 39), 0x04 + (12 - reg_128_39));
+			} else {
+				printk("128 + 39 max vol 0dB\n");
+			}
+		} else if (*(buffer + 1) == '-') {
+			if (reg_128_39 > 0) {
+				if (reg_128_39 % 2 == 0)
+					printk("write reg 128 + 39 vol - : %ddB -> -%d.5dB\n", (reg_128_39 - 12) / 2, (13 - reg_128_39) / 2);
+				else
+					printk("write reg 128 + 39 vol - : -%d.5dB -> %ddB\n", (12 - reg_128_39) / 2, (reg_128_39 - 13) / 2);
+				reg_128_39--;
+				aic3111_write(aic3111_codec, (128 + 39), 0x08 + (12 - reg_128_39));
+			} else {
+				printk("128 + 39 min vol -6dB\n");
+			}
+		}
+		break;
+	case '2':
+		if (*(buffer + 1) == '+') {
+			if (reg_128_43 < 2) {
+				printk("write reg 128 + 43 vol + : %ddB -> %ddB\n", (reg_128_43) * 6, (reg_128_43 + 1) * 6);
+				reg_128_43++;
+				aic3111_write(aic3111_codec, (128 + 43), 0x04 + ((reg_128_43 + 1) << 3));
+			} else {
+				printk("128 + 43 max vol 12dB\n");
+			}
+		} else if (*(buffer + 1) == '-') {
+			if (reg_128_43 > 0) {
+				printk("write reg 128 + 43 vol - : %ddB -> %ddB\n", (reg_128_43) * 6, (reg_128_43 - 1) * 6);
+				reg_128_43--;
+				aic3111_write(aic3111_codec, (128 + 43), 0x04 + ((reg_128_43 + 1) << 3));
+			} else {
+				printk("128 + 43 min vol 0dB\n");
+			}
+		}
+		break;
+	case 'o':
+		aic3111_write(aic3111_codec, (128 + 39), 0x08 + (12 - reg_128_39));
+		aic3111_write(aic3111_codec, (128 + 43), 0x04 + ((reg_128_43 + 1) << 3));
+	case 'l':
+		if (reg_128_39 % 2 == 0)
+			printk("reg 128 + 43 vol : %ddB  reg 128 + 39 vol : %ddB\n", (reg_128_43) * 6, (reg_128_39 - 12) / 2);
+		else
+			printk("reg 128 + 43 vol : %ddB  reg 128 + 39 vol : -%d.5dB\n", (reg_128_43) * 6, (12 - reg_128_39) / 2);
+		break;
+	case 's':
+		aic3111_power_speaker (POWER_STATE_ON);
+		break;
+
+	case 'h':
+		aic3111_power_headphone (POWER_STATE_ON);
+		break;
+
+	case 'q':
+		aic3111_power_speaker (POWER_STATE_OFF);
+		break;
+	
+	case 'w':
+		aic3111_power_headphone (POWER_STATE_OFF);
+		break;
+
+	case 'a':
+		i--;
+		gpio_set_value(RK29_PIN6_PB5, GPIO_HIGH);
+		//printk("reg[128+39]=0x%x\n",aic3111_read(aic3111_codec,(128 + 39)));
+		printk("-db add\n");
+		break;
+	case 'r':
+		i++;
+		gpio_set_value(RK29_PIN6_PB5, GPIO_LOW);
+		//printk("reg[128+39]=0x%x\n",aic3111_read(aic3111_codec,(128 + 39)));
+		printk("-db down\n");
+		break;
+	case 't':
+		
+		printk("PB5 = %d\n",gpio_get_value(RK29_PIN6_PB5));
+		break;
+
+	case 'z':
+		j++;
+		aic3111_write(aic3111_codec, (66), j);
+		printk("DAC db add\n");
+		printk("reg[66]=0x%x\n",aic3111_read(aic3111_codec,66));
+		break;
+	case 'x':
+		j--;
+		aic3111_write(aic3111_codec, (66), j);
+		printk("DAC db down\n");
+		printk("reg[66]=0x%x\n",aic3111_read(aic3111_codec,66));
+		break;
+
+	case 'c':
+		j--;
+		aic3111_write(aic3111_codec, (63), 0xfc);
+		printk("reg[63]=0x%x\n",aic3111_read(aic3111_codec,66));
+		break;
+
+	case 'n':
+		k++;
+		if(k==1)
+		{
+		aic3111_write(aic3111_codec, (128 + 40), 0x0e);
+		aic3111_write(aic3111_codec, (128 + 41), 0x0e);
+		printk("HPR and HPL 1 DB\n",k);
+		}
+		if(k==2)
+		{
+		aic3111_write(aic3111_codec, (128 + 40), 0x1e);
+		aic3111_write(aic3111_codec, (128 + 40), 0x1e);
+		printk("HPR and HPL 3 DB\n",k);
+		}
+		if(k==3)
+		{
+		aic3111_write(aic3111_codec, (128 + 40), 0x2e);
+		aic3111_write(aic3111_codec, (128 + 40), 0x2e);
+		printk("HPR and HPL 5 DB\n",k);
+		}
+		break;
+
+	case 'm':
+		k--;
+		if(k==1)
+		{
+		aic3111_write(aic3111_codec, (128 + 40), 0x0e);
+		aic3111_write(aic3111_codec, (128 + 41), 0x0e);
+		printk("HPR and HPL 1 DB\n",k);
+		}
+		if(k==2)
+		{
+		aic3111_write(aic3111_codec, (128 + 40), 0x1e);
+		aic3111_write(aic3111_codec, (128 + 40), 0x1e);
+		printk("HPR and HPL 3 DB\n",k);
+		}
+		if(k==3)
+		{
+		aic3111_write(aic3111_codec, (128 + 40), 0x2e);
+		aic3111_write(aic3111_codec, (128 + 40), 0x2e);
+		printk("HPR and HPL 5 DB\n",k);
+		}
+		break;
+
+
+	default:
+		printk("Please press '1' '2' 'o' 'l' !\n");
+		break;
+	}
+	return 0;
+}
+
+static int aic3111_proc_write(struct file *file, const char __user *buffer,
+			   unsigned long count, void *data)
+{
+	if (CheckCommand(buffer) != 0) {
+		printk("Write proc error !\n");
+		return -1;
+	}
+
+	return sizeof(buffer);
+}
+static const struct file_operations aic3111_proc_fops = {
+	.owner		= THIS_MODULE,
+	.write		= aic3111_proc_write,
+};
+
+static int aic3111_proc_init(void) {
+
+	struct proc_dir_entry *aic3111_proc_entry;
+        //printk("!!!!!!!!!!!!!!!!!!!!\n");
+	aic3111_proc_entry = create_proc_entry("driver/aic3111_ts", 0777, NULL);
+
+	if (aic3111_proc_entry != NULL) {
+
+		aic3111_proc_entry->write_proc = aic3111_proc_write;
+
+		return -1;
+	}else {
+		printk("create proc error !\n");
+	}
+
+	return 0;
+}
+#endif
+
+struct delayed_work aic3111_speaker_delayed_work;
+int speakeronoff;
+
+static void  aic3111_speaker_delayed_work_func(struct work_struct  *work)
+{
+	struct snd_soc_codec *codec = aic3111_codec;
+
+	if (aic3111_current_status & AIC3110_IS_PLAYBACK_ON){
+		if(speakeronoff) {
+
+			 //aic3111_write(codec, (128 + 32), 0xc6);
+			//printk("reg 128+32 = %x\n"aic3111_read(codec, (128 + 32)));
+			isHSin = 0;
+			//gpio_set_value(RK29_PIN6_PB5, GPIO_LOW);
+			aic3111_power_speaker(POWER_STATE_OFF);
+			gpio_set_value(RK29_PIN6_PB5, GPIO_HIGH);
+			//aic3111_power_headphone(POWER_STATE_ON);
+			//aic3111_write(codec, (128 + 35), 0x88);
+			printk("now hp sound\n");
+		} else {
+
+			//aic3111_power_speaker(POWER_STATE_ON);
+
+			isHSin = 1;
+			//aic3111_power_headphone(POWER_STATE_OFF);
+			gpio_set_value(RK29_PIN6_PB5, GPIO_LOW);
+			aic3111_power_speaker(POWER_STATE_ON);
+			aic3111_write(codec, (128 + 35), 0x44);
+			aic3111_write(codec, (63), 0xfc);
+			printk("now spk sound\n");
+
+		}
+	}    
+        //printk("----------------------------mma7660_work_func------------------------\n");
+    
+}
+
+/**for check hp or spk****/
+static int speaker_timer(unsigned long _data)
+{
+	struct speaker_data *spk = (struct speaker_data *)_data;
+	int new_status;
+
+	if (gpio_get_value(RK29_PIN6_PB6) == 0) {
+		new_status = HP;
+		isHSin = 0;
+		//printk("hp now\n");
+		if(old_status != new_status)
+		{
+			old_status = new_status;
+			// printk("new_status = %d,old_status = %d\n",new_status,old_status);
+			old_status = new_status;
+
+			schedule_delayed_work(&aic3111_speaker_delayed_work,msecs_to_jiffies(30));
+			speakeronoff=1;
+			//printk("HS RUN!!!!!!!!!!\n");
+		}
+	}
+
+	if (gpio_get_value(RK29_PIN6_PB6) == 1) {
+		new_status = SPK;
+		isHSin = 1;
+		//printk("speak now\n");
+		if(old_status != new_status)
+		{
+			old_status = new_status;
+			printk("new_status = %d,old_status = %d\n",new_status,old_status);
+			old_status = new_status;
+
+			schedule_delayed_work(&aic3111_speaker_delayed_work,msecs_to_jiffies(30));
+			speakeronoff=0;
+			//printk("HS RUN!!!!!!!!!!\n");
+		}
+	}
+
+	mod_timer(&spk->timer, jiffies + msecs_to_jiffies(200));
+
+	return 0;
+}
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_probe
+ * Purpose  : This is first driver function called by the SoC core driver.
+ *            
+ *----------------------------------------------------------------------------
+ */
+static int aic3111_probe (struct snd_soc_codec *codec)
+{
+	int ret = 0;//, flags, hp_det_irq;
+
+	codec->hw_write = (hw_write_t) i2c_master_send;
+	codec->control_data = aic3111_i2c;
+	aic3111_codec = codec;
+
+#if 1
+	gpio_set_value(RK29_PIN6_PB6,1);
+	struct speaker_data *spk;
+
+	spk = kzalloc(sizeof(struct speaker_data), GFP_KERNEL);
+	if (spk == NULL) {
+		printk("Allocate Memory Failed!\n");
+		ret = -ENOMEM;
+		//goto exit_gpio_free;
+	}
+
+	setup_timer(&spk->timer, speaker_timer, (unsigned long)spk);
+	mod_timer(&spk->timer, jiffies + JACK_DET_ADLOOP);
+	INIT_DELAYED_WORK(&aic3111_speaker_delayed_work, aic3111_speaker_delayed_work_func);
+
+/*********************/
+	//pio_set_value(RK29_PIN6_PB5, GPIO_LOW);
+	//aic3111_power_speaker(POWER_STATE_OFF);
+	//aic3111_power_headphone(POWER_STATE_ON);
+#endif
+
+	aic3111_workq = create_freezable_workqueue("aic3111");
+	if (aic3111_workq == NULL) {
+		return -ENOMEM;
+	}
+
+/*	INIT_DELAYED_WORK (&aic3111_hpdet_work, aic3111_hpdet_work_handle);
+	if (gpio_request (HP_DET_PIN, "hp_det")) {      
+		gpio_free (HP_DET_PIN);   
+		printk ("CODEC::tlv3110 hp det  pin request error\n");       
+	}	
+	else {
+		gpio_direction_input (HP_DET_PIN);
+		gpio_pull_updown (HP_DET_PIN, PullDisable);
+		hp_det_irq = gpio_to_irq (HP_DET_PIN);
+		isHSin = gpio_get_value (HP_DET_PIN);
+		
+		flags = isHSin ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
+		ret = request_irq (hp_det_irq, aic3111_hpdet_isr, flags, "hpdet", codec);
+		if (ret < 0) {
+			printk ("CODEC::request hp_det_irq error\n");
+		}
+	}
+*/
+	/* Just Reset codec */
+	aic3111_soft_reset();
+	gpio_set_value(RK29_PIN6_PB5, GPIO_LOW);
+	msleep(10);
+	aic3111_write (aic3111_codec, (68), 0x01); //disable DRC
+	aic3111_write (aic3111_codec, (128 + 31), 0xc4);
+	aic3111_write (aic3111_codec, (128 + 36), 0x28); //Left Analog Vol to HPL
+	aic3111_write (aic3111_codec, (128 + 37), 0x28); //Right Analog Vol to HPL
+	aic3111_write (aic3111_codec, (128 + 40), 0x4f); //HPL driver PGA
+	aic3111_write (aic3111_codec, (128 + 41), 0x4f); //HPR driver PGA
+
+#ifdef AIC3111_DEBUG
+	aic3111_proc_init();
+#endif
+
+	aic3111_set_bias_level (codec, SND_SOC_BIAS_STANDBY);
+
+	return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_remove
+ * Purpose  : to remove aic3111 soc device 
+ *            
+ *----------------------------------------------------------------------------
+ */
+static int aic3111_remove (struct snd_soc_codec *codec)
+{
+	AIC_DBG ("CODEC::%s\n", __FUNCTION__);
+
+	/* Disable HPDET irq */
+	//disable_irq_nosync (HP_DET_PIN);
+
+	/* power down chip */
+	aic3111_set_bias_level (codec, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_suspend
+ * Purpose  : This function is to suspend the AIC3111 driver.
+ *            
+ *----------------------------------------------------------------------------
+ */
+static int aic3111_suspend (struct snd_soc_codec *codec, pm_message_t state)
+{
+
+	AIC_DBG ("CODEC::%s\n", __FUNCTION__);
+
+	aic3111_set_bias_level (codec, SND_SOC_BIAS_STANDBY);
+
+	aic3111_soft_reset();//sai
+
+	return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * Function : aic3111_resume
+ * Purpose  : This function is to resume the AIC3111 driver
+ *            
+ *----------------------------------------------------------------------------
+ */
+static int aic3111_resume (struct snd_soc_codec *codec)
+{
+	//isHSin = gpio_get_value(HP_DET_PIN);
+	aic3111_set_bias_level (codec, SND_SOC_BIAS_STANDBY);
+	//aic3111_set_bias_level(codec, codec->suspend_bias_level);
+
+	return 0;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * @struct  snd_soc_codec_device |
+ *          This structure is soc audio codec device sturecute which pointer
+ *          to basic functions aic3111_probe(), aic3111_remove(),  
+ *          aic3111_suspend() and aic3111_resume()
+ *----------------------------------------------------------------------------
+ */
+static struct snd_soc_codec_driver soc_codec_dev_aic3111 = {
+	.probe = aic3111_probe,
+	.remove = aic3111_remove,
+	.suspend = aic3111_suspend,
+	.resume = aic3111_resume,
+	.set_bias_level = aic3111_set_bias_level,
+	.reg_cache_size = ARRAY_SIZE(aic31xx_reg),
+	.reg_word_size = sizeof(u16),
+	.reg_cache_default = aic31xx_reg,
+	.reg_cache_step = 1,
+};
+
+static const struct i2c_device_id tlv320aic3111_i2c_id[] = {
+	{ "aic3111", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tlv320aic3111_i2c_id);
+
+static int tlv320aic3111_i2c_probe(struct i2c_client *i2c,
+		    const struct i2c_device_id *id)
+{
+	struct aic3111_priv *aic3111;
+	int ret;
+
+	aic3111 = kzalloc(sizeof(struct aic3111_priv), GFP_KERNEL);
+	if (NULL == aic3111)
+		return -ENOMEM;
+
+	aic3111_i2c = i2c;
+
+	i2c_set_clientdata(i2c, aic3111);
+
+	aic3111_privdata = aic3111;
+
+	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_aic3111,
+			aic3111_dai, ARRAY_SIZE(aic3111_dai));
+	if (ret < 0)
+		kfree(aic3111);
+
+	return ret;
+}
+
+static __devexit int tlv320aic3111_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	kfree(i2c_get_clientdata(client));
+	return 0;
+}
+
+struct i2c_driver tlv320aic3111_i2c_driver = {
+	.driver = {
+		.name = "AIC3111",
+		.owner = THIS_MODULE,
+	},
+	.probe = tlv320aic3111_i2c_probe,
+	.remove   = __devexit_p(tlv320aic3111_i2c_remove),
+	.id_table = tlv320aic3111_i2c_id,
+};
+
+static int __init tlv320aic3111_init (void)
+{
+	return i2c_add_driver(&tlv320aic3111_i2c_driver);
+}
+
+static void __exit tlv320aic3111_exit (void)
+{
+	i2c_del_driver(&tlv320aic3111_i2c_driver);
+}
+
+module_init (tlv320aic3111_init);
+module_exit (tlv320aic3111_exit);
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+static int proc_3110_reg_show (struct seq_file *s, void *v)
+{
+	struct snd_soc_codec *codec = aic3111_codec;
+	int reg;
+	u8 *cache = codec->reg_cache;
+
+	seq_printf (s, "========3110register========\n");
+	for (reg = 0; reg < 256; reg++) {
+		if (reg == 0) seq_printf (s, "Page 0\n");
+		if (reg == 128) seq_printf (s, "\nPage 1\n");
+		if (reg%8 == 0 && reg != 0 && reg != 128) seq_printf (s, "\n");
+		seq_printf (s, "[%d]0x%02x, ",reg,aic3111_read (codec, reg));
+	}
+	seq_printf (s, "\n========3110cache========\n");
+	for (reg = 0; reg < codec->reg_size; reg++) {
+		if (reg == 0) seq_printf (s, "Page 0\n");
+		if (reg == 128) seq_printf (s, "\nPage 1\n");
+		if (reg%16 == 0 && reg != 0 && reg != 128) seq_printf (s, "\n");
+		seq_printf (s, "0x%02x, ",cache[reg]);
+	}
+	printk ("\n==========================\n");
+	return 0;
+}
+
+static int proc_3110_reg_open (struct inode *inode, struct file *file)
+{
+	return single_open (file, proc_3110_reg_show, NULL);
+}
+
+static const struct file_operations proc_3110_reg_fops = {
+	.open		= proc_3110_reg_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int __init codec_proc_init (void)
+{
+	proc_create ("aic3110_register", 0, NULL, &proc_3110_reg_fops);
+
+	return 0;
+}
+late_initcall (codec_proc_init);
+#endif /* CONFIG_PROC_FS */
+
+MODULE_DESCRIPTION (" ASoC TLV320AIC3111 codec driver ");
+MODULE_AUTHOR (" Jaz B John <jazbjohn@mistralsolutions.com> ");
+MODULE_LICENSE ("GPL");
+
diff --git a/sound/soc/codecs/tlv320aic3111.h b/sound/soc/codecs/tlv320aic3111.h
new file mode 100644
index 000000000000..7b5b17092db7
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic3111.h
@@ -0,0 +1,621 @@
+/*
+ * linux/sound/soc/codecs/tlv320aic3111.h
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * History:
+ *
+ * Rev 0.1   ASoC driver support    Mistral         14-04-2010
+ * 
+ * Rev 0.2   Updated based Review Comments Mistral      29-06-2010 
+ * 
+ * Rev 0.3   Updated for Codec Family Compatibility     12-07-2010
+ */
+
+#ifndef _TLV320AIC3111_H
+#define _TLV320AIC3111_H
+
+/* #define AUDIO_NAME "aic3111"
+#define AIC3111_VERSION "0.1"
+*/
+
+
+/*
+ ******************AIC31xx CODEC SUPPORT ***************** 
+ * THE CURRENT CODE-BASE SUPPORTS BUILDING of the CODEC 
+ * DRIVER FOR AIC3111, AIC3110, AIC3100 and AIC3120.
+ * PLEASE NOTE THAT FOR EACH OF THE ABOVE CODECS, the 
+ * Linux Developer needs to enable a particular flag in 
+ * this header file before performing a build of the
+ * Audio Codec Driver.
+ *********************************************************
+*/
+
+//#define AIC3111_CODEC_SUPPORT
+#define AIC3110_CODEC_SUPPORT
+//#define AIC3100_CODEC_SUPPORT
+//#define AIC3120_CODEC_SUPPORT		
+
+/* NOTE THAT AIC3110 and AIC3100 do not support miniDSP */
+#ifdef AIC3110_CODEC_SUPPORT
+#undef CONFIG_MINI_DSP
+
+#define AUDIO_NAME "aic3110"
+#define AIC3111_VERSION "0.1"
+
+#endif
+
+#ifdef AIC3100_CODEC_SUPPORT
+#undef CONFIG_MINI_DSP
+
+#define AUDIO_NAME "aic3100"
+#define AIC3111_VERSION "0.1"
+
+#endif
+
+#ifdef AIC3120_CODEC_SUPPORT
+#undef CONFIG_MINI_DSP
+
+#define AUDIO_NAME "aic3120"
+#define AIC3111_VERSION "0.1"
+
+#endif
+
+/* The user has a choice to enable or disable miniDSP code
+ * when building for AIC3111 Codec.
+ */
+#ifdef AIC3111_CODEC_SUPPORT
+/* Macro enables or disables support for miniDSP in the driver */
+//#define CONFIG_MINI_DSP
+#undef CONFIG_MINI_DSP
+
+#define AUDIO_NAME "aic3111"
+#define AIC3111_VERSION "0.1"
+
+#endif
+
+
+/* Enable slave / master mode for codec */
+//#define AIC3111_MCBSP_SLAVE
+#undef AIC3111_MCBSP_SLAVE
+
+/* Enable register caching on write */
+#define EN_REG_CACHE
+
+/* Enable headset detection */
+#define HEADSET_DETECTION
+
+/* AIC3111 supported sample rate are 8k to 192k */
+#define AIC3111_RATES	SNDRV_PCM_RATE_8000_192000
+
+/* AIC3111 supports the word formats 16bits, 20bits, 24bits and 32 bits */
+#define AIC3111_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+			 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+#define AIC3111_FREQ_12000000 12000000
+#define AIC3111_FREQ_24000000 24000000
+#define AIC3111_FREQ_11289600 11289600
+
+/* AIC3111 register space */
+#define AIC31xx_CACHEREGNUM	384
+
+/* Audio data word length = 16-bits (default setting) */
+#define AIC3111_WORD_LEN_16BITS		0x00
+#define AIC3111_WORD_LEN_20BITS		0x01
+#define AIC3111_WORD_LEN_24BITS		0x02
+#define AIC3111_WORD_LEN_32BITS		0x03
+#define	DATA_LEN_SHIFT			    4
+
+/* sink: name of target widget */
+#define AIC3111_WIDGET_NAME			    0
+/* control: mixer control name */
+#define AIC3111_CONTROL_NAME			1
+/* source: name of source name */
+#define AIC3111_SOURCE_NAME			    2
+
+/* D15..D8 aic3111 register offset */
+#define AIC3111_REG_OFFSET_INDEX        0
+/* D7...D0 register data */
+#define AIC3111_REG_DATA_INDEX          1
+
+/* Serial data bus uses I2S mode (Default mode) */
+#define AIC3111_I2S_MODE				0x00
+#define AIC3111_DSP_MODE				0x01
+#define AIC3111_RIGHT_JUSTIFIED_MODE	0x02
+#define AIC3111_LEFT_JUSTIFIED_MODE		0x03
+#define AUDIO_MODE_SHIFT			    6
+
+/* number of codec specific register for configuration */
+#define NO_FEATURE_REGS			        2
+
+/* 8 bit mask value */
+#define AIC3111_8BITS_MASK		0xFF
+
+#ifndef AIC3120_CODEC_SUPPORT	/* for AIC3111, AIC3110 and AIC3100 */
+/* ****************** Page 0 Registers **************************************/
+#define	PAGE_SELECT			    0
+#define	RESET				    1
+#define	CLK_REG_1			    4
+#define	CLK_REG_2			    5
+#define	CLK_REG_3			    6
+#define	CLK_REG_4			    7
+#define	CLK_REG_5			    8
+#define	NDAC_CLK_REG			11
+#define	MDAC_CLK_REG			12
+#define DAC_OSR_MSB			    13
+#define DAC_OSR_LSB			    14
+#define	NADC_CLK_REG			18
+#define	MADC_CLK_REG			19
+#define ADC_OSR_REG			    20
+#define CLK_MUX_REG			    25
+#define CLK_MVAL_REG			26
+#define INTERFACE_SET_REG_1		27
+#define DATA_SLOT_OFFSET		28
+#define INTERFACE_SET_REG_2		29
+#define BCLK_N_VAL			    30
+#define INTERFACE_SET_REG_3		31
+#define INTERFACE_SET_REG_4		32
+#define INTERFACE_SET_REG_5		33
+#define I2C_BUS_COND			34
+
+#define INTL_CRTL_REG_1			48
+#define INTL_CRTL_REG_2			49
+#define GPIO_CRTL_REG_1			51
+
+#define DAC_PRB_SEL_REG			60
+#define ADC_PRB_SEL_REG			61
+#define DAC_CHN_REG			    63
+#define DAC_MUTE_CTRL_REG		64
+#define LDAC_VOL			    65
+#define RDAC_VOL			    66
+
+#define HEADSET_DETECT			67
+
+#define DRC_CTL_REG_1			68
+#define DRC_CTL_REG_2			69
+#define DRC_CTL_REG_3			70
+
+#define LEFT_BEEP_GEN			71
+#define RIGHT_BEEP_GEN			72
+#define BEEP_LENGTH_MSB			73
+#define BEEP_LENGTH_MID			74
+#define BEEP_LENGTH_LSB			75
+#define BEEP_SINX_MSB			76
+#define BEEP_SINX_LSB			77
+#define BEEP_COSX_MSB			78
+#define BEEP_COSX_LSB			79
+
+
+#define ADC_DIG_MIC			    81
+#define	ADC_FGA				    82
+#define	ADC_CGA				    83
+
+#define AGC_CTRL_1			    86
+#define AGC_CTRL_2			    87
+#define AGC_CTRL_3			    88
+#define AGC_CTRL_4			    89
+#define AGC_CTRL_5			    90
+#define AGC_CTRL_6			    91
+#define AGC_CTRL_7			    92
+#define AGC_CTRL_8			    93
+
+#define ADC_DC_1			    102
+#define ADC_DC_2			    103
+#define PIN_VOL_CTRL			116
+#define PIN_VOL_GAIN			117
+
+
+/******************** Page 1 Registers **************************************/
+#define PAGE_1				    128
+#define HEADPHONE_DRIVER		(PAGE_1 + 31)
+#define CLASSD_SPEAKER_AMP		(PAGE_1 + 32)
+#define HP_POP_CTRL			    (PAGE_1 + 33)
+#define PGA_RAMP_CTRL			(PAGE_1 + 34)
+#define DAC_MIX_CTRL			(PAGE_1 + 35)
+#define L_ANLOG_VOL_2_HPL		(PAGE_1 + 36)
+#define R_ANLOG_VOL_2_HPR		(PAGE_1 + 37)
+#define L_ANLOG_VOL_2_SPL		(PAGE_1 + 38)
+#define R_ANLOG_VOL_2_SPR		(PAGE_1 + 39)
+#define HPL_DRIVER			    (PAGE_1 + 40)
+#define HPR_DRIVER			    (PAGE_1 + 41)
+#define SPL_DRIVER			    (PAGE_1 + 42)
+#define SPR_DRIVER			    (PAGE_1 + 43)
+#define HP_DRIVER_CTRL			(PAGE_1 + 44)
+#define MICBIAS_CTRL			(PAGE_1 + 46)
+#define MIC_PGA				    (PAGE_1 + 47)
+#define MIC_GAIN			    (PAGE_1 + 48)
+#define ADC_IP_SEL			    (PAGE_1 + 49)
+#define CM_SET	         		(PAGE_1 + 50)
+
+#define L_MICPGA_P			    (PAGE_1 + 52)
+#define L_MICPGA_N			    (PAGE_1 + 54)
+#define R_MICPGA_P			    (PAGE_1 + 55)
+#define R_MICPGA_N			    (PAGE_1 + 57)
+
+/****************************************************************************/
+/****************************************************************************/
+#define BIT7		(1 << 7)
+#define BIT6		(1 << 6)
+#define BIT5		(1 << 5)
+#define BIT4		(1 << 4)
+#define	BIT3		(1 << 3)
+#define BIT2		(1 << 2)
+#define BIT1		(1 << 1)
+#define BIT0		(1 << 0)
+
+#define HP_UNMUTE			    BIT2
+#define HPL_UNMUTE			    BIT3
+#define ENABLE_DAC_CHN			(BIT6 | BIT7)
+#define ENABLE_ADC_CHN			(BIT6 | BIT7)
+#define BCLK_DIR_CTRL			(BIT2 | BIT3)
+#define CODEC_CLKIN_MASK		0x03
+#define MCLK_2_CODEC_CLKIN		0x00
+#define CODEC_MUX_VALUE			0X03
+/*Bclk_in selection*/
+#define BDIV_CLKIN_MASK			0x03
+#define	DAC_MOD_CLK_2_BDIV_CLKIN 	BIT0
+#define SOFT_RESET			    0x01
+#define PAGE0				    0x00
+#define PAGE1				    0x01
+#define BIT_CLK_MASTER			BIT3
+#define WORD_CLK_MASTER			BIT2
+#define	HIGH_PLL 			    BIT6
+#define ENABLE_PLL			    BIT7
+#define ENABLE_NDAC			    BIT7
+#define ENABLE_MDAC			    BIT7
+#define ENABLE_NADC			    BIT7
+#define ENABLE_MADC			    BIT7
+#define ENABLE_BCLK			    BIT7
+#define LDAC_2_LCHN			    BIT4
+#define RDAC_2_RCHN			    BIT2
+#define RDAC_2_RAMP			    BIT2
+#define LDAC_2_LAMP			    BIT6
+#define LDAC_CHNL_2_HPL			BIT3
+#define RDAC_CHNL_2_HPR			BIT3
+#define SOFT_STEP_2WCLK			BIT0
+#define MUTE_ON				    0x00
+#define DEFAULT_VOL			    0x0
+//#define DEFAULT_VOL			    0xAf
+#define DISABLE_ANALOG			BIT3
+#define LDAC_2_HPL_ROUTEON		BIT3
+#define RDAC_2_HPR_ROUTEON		BIT3
+#define LINEIN_L_2_LMICPGA_10K		BIT6
+#define LINEIN_L_2_LMICPGA_20K		BIT7
+#define LINEIN_L_2_LMICPGA_40K		(0x3 << 6)
+#define LINEIN_R_2_RMICPGA_10K		BIT6
+#define LINEIN_R_2_RMICPGA_20K		BIT7
+#define LINEIN_R_2_RMICPGA_40K		(0x3 << 6)
+
+
+/****************************************************************************
+ * DAPM widget related #defines
+ ***************************************************************************
+ */
+#define LMUTE_ENUM		    0
+#define RMUTE_ENUM		    1
+#define DACEXTRA_ENUM		2
+#define DACCONTROL_ENUM		3
+#define SOFTSTEP_ENUM		4
+#define BEEP_ENUM		    5
+#define MICBIAS_ENUM		6
+#define DACLEFTIP_ENUM		7
+#define DACRIGHTIP_ENUM		8
+#define VOLTAGE_ENUM		9
+#define HSET_ENUM		    10
+#define DRC_ENUM		    11
+#define MIC1LP_ENUM		    12
+#define MIC1RP_ENUM		    13
+#define MIC1LM_ENUM		    14
+#define MIC_ENUM		    15
+#define CM_ENUM			    16
+#define MIC1LMM_ENUM		17
+#define MIC1_ENUM		    18
+#define MIC2_ENUM		    19
+#define MIC3_ENUM		    20
+#define ADCMUTE_ENUM		21
+#endif
+
+#ifdef AIC3120_CODEC_SUPPORT	/*for AIC3120 */
+	/* ****************** Page 0 Registers **************************************/
+	#define	PAGE_SELECT			    0
+	#define	RESET				    1
+	#define	CLK_REG_1			    4
+	#define	CLK_REG_2			    5
+	#define	CLK_REG_3			    6
+	#define	CLK_REG_4			    7
+	#define	CLK_REG_5			    8
+	#define	NDAC_CLK_REG			11
+	#define	MDAC_CLK_REG			12
+	#define DAC_OSR_MSB			    13
+	#define DAC_OSR_LSB			    14
+	#define	NADC_CLK_REG			18
+	#define	MADC_CLK_REG			19
+	#define ADC_OSR_REG			    20
+	#define CLK_MUX_REG			    25
+	#define CLK_MVAL_REG			26
+	#define INTERFACE_SET_REG_1		27
+	#define DATA_SLOT_OFFSET		28
+	#define INTERFACE_SET_REG_2		29
+	#define BCLK_N_VAL			    30
+	#define INTERFACE_SET_REG_3		31
+	#define INTERFACE_SET_REG_4		32
+	#define INTERFACE_SET_REG_5		33
+	#define I2C_BUS_COND			34
+
+	#define INTL_CRTL_REG_1			48
+	#define INTL_CRTL_REG_2			49
+	#define GPIO_CRTL_REG_1			51
+
+	#define DAC_PRB_SEL_REG			60
+	#define ADC_PRB_SEL_REG			61
+	#define DAC_CHN_REG			    63
+	#define DAC_MUTE_CTRL_REG		64
+	#define LDAC_VOL			    65	/*Mistral: AIC3120 has mono dac...renamed from LDAC_VOL to DAC_VOL.*/
+	#define DAC_VOL				65	/*Mistral:..DUAL definition for compatibility*/
+	/*Mistral: 3120 is mono..RDAC_VOL is reserved..register removed*/
+
+	#define HEADSET_DETECT			67
+
+	#define DRC_CTL_REG_1			68
+	#define DRC_CTL_REG_2			69
+	#define DRC_CTL_REG_3			70
+
+	/* 3120 does not have beep generation circuits...So removed beep related registers*/
+
+	#define ADC_DIG_MIC			    81
+	#define	ADC_FGA				    82
+	#define	ADC_CGA				    83
+
+	#define AGC_CTRL_1			    86
+	#define AGC_CTRL_2			    87
+	#define AGC_CTRL_3			    88
+	#define AGC_CTRL_4			    89
+	#define AGC_CTRL_5			    90
+	#define AGC_CTRL_6			    91
+	#define AGC_CTRL_7			    92
+	#define AGC_CTRL_8			    93
+
+	#define ADC_DC_1			    102
+	#define ADC_DC_2			    103
+	#define PIN_VOL_CTRL			116
+	#define PIN_VOL_GAIN			117
+
+
+	/******************** Page 1 Registers **************************************/
+	#define PAGE_1				    128
+	#define HEADPHONE_DRIVER		(PAGE_1 + 31)
+	#define CLASSD_SPEAKER_AMP		(PAGE_1 + 32)
+	#define HP_POP_CTRL			    (PAGE_1 + 33)
+	#define PGA_RAMP_CTRL			(PAGE_1 + 34)
+	#define DAC_MIX_CTRL			(PAGE_1 + 35)
+	#define L_ANLOG_VOL_2_HPL		(PAGE_1 + 36)
+	#define ANALOG_HPOUT_VOL		(PAGE_1 + 36)
+	/*Mistral:	3120 DAC is mono.. R_ANALOG_VOL_2_HPR register is removed*/
+	#define L_ANLOG_VOL_2_SPL		(PAGE_1 + 38)
+	#define ANALOG_CDOUT_VOL		(PAGE_1 + 38)	/*Mistral: Dual definition for compatibility*/
+	/*Mistral:	3120 DAC is mono.. R_ANALOG_VOL_2_SPR register is removed*/
+	#define HPL_DRIVER			(PAGE_1 + 40)	/*Mistral: kept for compatibility*/
+	#define HP_DRIVER			(PAGE_1 + 40)	/*Mistral: Dual definition for compatibility*/
+	#define HPOUT_DRIVER			(PAGE_1 + 40)	/*Mistral: Triple definition for compatibility*/ 
+	/*Mistral:	3120 DAC is mono.. HPR_DRIVER register is removed*/
+	#define SPL_DRIVER			(PAGE_1 + 42)	/*Mistral: kept for compatibility*/
+	#define SP_DRIVER			(PAGE_1 + 42)	/*Mistral: Dual Definition for compatibility*/
+	#define CD_OUT_DRIVER			(PAGE_1 + 42)	/*Mistral: Triple definition for compatibility*/
+	/*Mistral:	3120 DAC is mono.. HPR_DRIVER register is removed*/
+	#define HP_DRIVER_CTRL			(PAGE_1 + 44)
+	#define MICBIAS_CTRL			(PAGE_1 + 46)
+	#define MIC_PGA				    (PAGE_1 + 47)
+	#define MIC_GAIN			    (PAGE_1 + 48)
+	#define ADC_IP_SEL			    (PAGE_1 + 49)
+	#define CM_SET	         		(PAGE_1 + 50)
+
+	#define L_MICPGA_P			    (PAGE_1 + 52)
+	#define L_MICPGA_N			    (PAGE_1 + 54)
+	#define R_MICPGA_P			    (PAGE_1 + 55)
+	#define R_MICPGA_N			    (PAGE_1 + 57)
+
+	/****************************************************************************/
+	/****************************************************************************/
+	#define BIT7		(1 << 7)
+	#define BIT6		(1 << 6)
+	#define BIT5		(1 << 5)
+	#define BIT4		(1 << 4)
+	#define	BIT3		(1 << 3)
+	#define BIT2		(1 << 2)
+	#define BIT1		(1 << 1)
+	#define BIT0		(1 << 0)
+
+	#define HP_UNMUTE			    BIT2	/*Mistral: Kept for compatibility*/
+	#define HPL_UNMUTE			    BIT3
+	#define ENABLE_DAC_CHN			 BIT7	/*Mistral reg [0][63] only right DAC is present*/
+	#define ENABLE_ADC_CHN			(BIT6 | BIT7)
+	#define BCLK_DIR_CTRL			(BIT2 | BIT3)
+	#define CODEC_CLKIN_MASK		0x03
+	#define MCLK_2_CODEC_CLKIN		0x00
+	#define CODEC_MUX_VALUE			0X03
+	/*Bclk_in selection*/
+	#define BDIV_CLKIN_MASK			0x03
+	#define	DAC_MOD_CLK_2_BDIV_CLKIN 	BIT0
+	#define SOFT_RESET			    0x01
+	#define PAGE0				    0x00
+	#define PAGE1				    0x01
+	#define BIT_CLK_MASTER			BIT3
+	#define WORD_CLK_MASTER			BIT2
+	#define	HIGH_PLL 			BIT6
+	#define ENABLE_PLL			BIT7
+	#define ENABLE_NDAC			BIT7
+	#define ENABLE_MDAC			BIT7
+	#define ENABLE_NADC			BIT7
+	#define ENABLE_MADC			BIT7
+	#define ENABLE_BCLK			BIT7
+	#define LDAC_2_LCHN			BIT4
+	/*Mistral: RDAC_2_LCHN...Removed as its reserved*/
+	#define RDAC_2_RAMP			BIT2	/*Mistral: kept for compatibility*/
+	#define LDAC_2_LAMP			BIT6
+	#define LDAC_CHNL_2_HPL			BIT3
+	#define SOFT_STEP_2WCLK			BIT0
+	#define MUTE_ON				    0x00
+	#define DEFAULT_VOL			    0x0
+	#define DISABLE_ANALOG			BIT3
+	#define LDAC_2_HPL_ROUTEON		BIT3
+	/*#define RDAC_2_HPR_ROUTEON		BIT3*/	/*Mistral: NOT present in AIC3120*/
+	#define LINEIN_L_2_LMICPGA_10K		BIT6
+	#define LINEIN_L_2_LMICPGA_20K		BIT7
+	#define LINEIN_L_2_LMICPGA_40K		(0x3 << 6)
+	#define LINEIN_R_2_RMICPGA_10K		BIT6
+	#define LINEIN_R_2_RMICPGA_20K		BIT7
+	#define LINEIN_R_2_RMICPGA_40K		(0x3 << 6)
+
+
+	/****************************************************************************
+	 * DAPM widget related #defines
+	 ***************************************************************************
+	 */
+	#define LMUTE_ENUM		    0
+	/*#define RMUTE_ENUM		    1*/	/*Mistral: NOT Present in AIC3120*/
+	#define DACEXTRA_ENUM		2
+	#define DACCONTROL_ENUM		3
+	#define SOFTSTEP_ENUM		4
+	/*#define BEEP_ENUM		    5*/	/*Mistral: not present in AIC3120*/
+	#define MICBIAS_ENUM		6
+	#define DACLEFTIP_ENUM		7
+	#define DACRIGHTIP_ENUM		8
+	#define VOLTAGE_ENUM		9
+	#define HSET_ENUM		    10
+	#define DRC_ENUM		    11
+	#define MIC1LP_ENUM		    12
+	#define MIC1RP_ENUM		    13
+	#define MIC1LM_ENUM		    14
+	#define MIC_ENUM		    15
+	#define CM_ENUM			    16
+	#define MIC1LMM_ENUM		17
+	#define MIC1_ENUM		    18
+	#define MIC2_ENUM		    19
+	#define MIC3_ENUM		    20
+	#define ADCMUTE_ENUM		21
+#endif
+
+
+/***************************************************************************** 
+ * Structures Definitions
+ ***************************************************************************** 
+ */
+/*
+ *----------------------------------------------------------------------------
+ * @struct  aic3111_setup_data |
+ *          i2c specific data setup for AIC3111.
+ * @field   unsigned short |i2c_address |
+ *          Unsigned short for i2c address.
+ *----------------------------------------------------------------------------
+ */
+struct aic3111_setup_data
+{
+  unsigned short i2c_address;
+};
+
+/*
+ *----------------------------------------------------------------------------
+ * @struct  aic3111_priv |
+ *          AIC3111 priviate data structure to set the system clock, mode and
+ *          page number. 
+ * @field   u32 | sysclk |
+ *          system clock
+ * @field   s32 | master |
+ *          master/slave mode setting for AIC3111
+ * @field   u8 | page_no |
+ *          page number. Here, page 0 and page 1 are used.
+ *----------------------------------------------------------------------------
+ */
+struct aic3111_priv
+{
+  u32 sysclk;
+  s32 master;
+  u8 page_no;
+};
+
+/*
+ *----------------------------------------------------------------------------
+ * @struct  aic3111_configs |
+ *          AIC3111 initialization data which has register offset and register 
+ *          value.
+ * @field   u16 | reg_offset |
+ *          AIC3111 Register offsets required for initialization..
+ * @field   u8 | reg_val |
+ *          value to set the AIC3111 register to initialize the AIC3111.
+ *----------------------------------------------------------------------------
+ */
+struct aic3111_configs
+{
+  u16 reg_offset;
+  u8 reg_val;
+};
+
+/*
+ *----------------------------------------------------------------------------
+ * @struct  aic3111_rate_divs |
+ *          Setting up the values to get different freqencies 
+ *          
+ * @field   u32 | mclk |
+ *          Master clock 
+ * @field   u32 | rate |
+ *          sample rate
+ * @field   u8 | p_val |
+ *          value of p in PLL
+ * @field   u32 | pll_j |
+ *          value for pll_j
+ * @field   u32 | pll_d |
+ *          value for pll_d
+ * @field   u32 | dosr |
+ *          value to store dosr
+ * @field   u32 | ndac |
+ *          value for ndac
+ * @field   u32 | mdac |
+ *          value for mdac
+ * @field   u32 | aosr |
+ *          value for aosr
+ * @field   u32 | nadc |
+ *          value for nadc
+ * @field   u32 | madc |
+ *          value for madc
+ * @field   u32 | blck_N |
+ *          value for block N
+ * @field   u32 | aic3111_configs |
+ *          configurations for aic3111 register value
+ *----------------------------------------------------------------------------
+ */
+struct aic3111_rate_divs
+{
+  u32 mclk;
+  u32 rate;
+  u8 p_val;
+  u8 pll_j;
+  u16 pll_d;
+  u16 dosr;
+  u8 ndac;
+  u8 mdac;
+  u8 aosr;
+  u8 nadc;
+  u8 madc;
+  u8 blck_N;
+  struct aic3111_configs codec_specific_regs[NO_FEATURE_REGS];
+};
+
+/*
+ *----------------------------------------------------------------------------
+ * @struct  snd_soc_codec_dai |
+ *          It is SoC Codec DAI structure which has DAI capabilities viz., 
+ *          playback and capture, DAI runtime information viz. state of DAI 
+ *			and pop wait state, and DAI private data. 
+ *----------------------------------------------------------------------------
+ */
+extern struct snd_soc_dai tlv320aic3111_dai;
+
+#endif /* _TLV320AIC3111_H */
diff --git a/sound/soc/rk29/Kconfig b/sound/soc/rk29/Kconfig
index 9474a30ea572..d2772c079bb1 100755
--- a/sound/soc/rk29/Kconfig
+++ b/sound/soc/rk29/Kconfig
@@ -95,7 +95,16 @@ config SND_RK29_SOC_CS42L52
 	help
 	  Say Y if you want to add support for SoC audio on rockchip
 	  with the CS42L52.
-	  
+
+config SND_RK29_SOC_AIC3111
+	tristate "SoC I2S Audio support for rockchip - AIC3111"
+	depends on SND_RK29_SOC && I2C_RK29
+	select SND_RK29_SOC_I2S
+	select SND_SOC_TLV320AIC3111
+	help
+	  Say Y if you want to add support for SoC audio on rockchip
+	  with the AIC3111.
+  
 config SND_RK29_SOC_RK1000
 	tristate "SoC I2S Audio support for rockchip - RK1000"
 	depends on SND_RK29_SOC && RK1000_CONTROL && I2C_RK29
@@ -105,7 +114,7 @@ config SND_RK29_SOC_RK1000
 	  Say Y if you want to add support for SoC audio on rockchip
 	  with the RK1000.	 
 	   
-if SND_RK29_SOC_WM8988 || SND_RK29_SOC_RK1000 || SND_RK29_SOC_WM8994 || SND_RK29_SOC_WM8900 || SND_RK29_SOC_RT5621 || SND_RK29_SOC_RT5631 || SND_RK29_SOC_RT5625 || SND_RK29_SOC_CS42L52
+if SND_RK29_SOC_WM8988 || SND_RK29_SOC_RK1000 || SND_RK29_SOC_WM8994 || SND_RK29_SOC_WM8900 || SND_RK29_SOC_RT5621 || SND_RK29_SOC_RT5631 || SND_RK29_SOC_RT5625 || SND_RK29_SOC_CS42L52 || SND_RK29_SOC_AIC3111
 choice
   prompt "Set i2s type"
 	config SND_RK29_CODEC_SOC_MASTER
diff --git a/sound/soc/rk29/Makefile b/sound/soc/rk29/Makefile
index cc0c09b0b40d..3092da30c1e5 100644
--- a/sound/soc/rk29/Makefile
+++ b/sound/soc/rk29/Makefile
@@ -11,6 +11,7 @@ snd-soc-rt5621-objs := rk29_rt5621.o
 snd-soc-rt5631-objs := rk29_rt5631.o
 snd-soc-rt5625-objs := rk29_rt5625.o
 snd-soc-cs42l52-objs := rk29_cs42l52.o
+snd-soc-aic3111-objs := rk29_aic3111.o
 snd-soc-wm8988-objs := rk29_wm8988.o
 snd-soc-rk1000-objs := rk29_rk1000codec.o
 snd-soc-wm8994-objs := rk29_wm8994.o
@@ -23,3 +24,4 @@ obj-$(CONFIG_SND_RK29_SOC_RT5631) += snd-soc-rt5631.o
 obj-$(CONFIG_SND_RK29_SOC_RT5625) += snd-soc-rt5625.o
 obj-$(CONFIG_SND_RK29_SOC_RK1000) += snd-soc-rk1000.o
 obj-$(CONFIG_SND_RK29_SOC_CS42L52) += snd-soc-cs42l52.o
+obj-$(CONFIG_SND_RK29_SOC_AIC3111) += snd-soc-aic3111.o
diff --git a/sound/soc/rk29/rk29_aic3111.c b/sound/soc/rk29/rk29_aic3111.c
new file mode 100644
index 000000000000..68311b117077
--- /dev/null
+++ b/sound/soc/rk29/rk29_aic3111.c
@@ -0,0 +1,219 @@
+/*
+ * rk29_tlv320dac3100.c  --  SoC audio for rockchip
+ *
+ * Driver for rockchip tlv320aic3100 audio
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/io.h>
+#include <mach/hardware.h>
+#include <mach/rk29_iomap.h>
+#include <mach/gpio.h>
+#include "../codecs/tlv320aic3111.h"
+#include "rk29_pcm.h"
+#include "rk29_i2s.h"
+
+#if 0
+#define	AIC_DBG(x...)	printk(KERN_INFO x)
+#else
+#define	AIC_DBG(x...)	do { } while (0)
+#endif
+
+#ifdef CODECHPDET
+	#define HP_DET_PIN 		RK29_PIN6_PA0
+#endif
+
+
+
+static int rk29_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	unsigned int pll_out = 0; 
+	int ret;
+
+	AIC_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+
+	/*by Vincent Hsiung for EQ Vol Change*/
+	#define HW_PARAMS_FLAG_EQVOL_ON 0x21
+	#define HW_PARAMS_FLAG_EQVOL_OFF 0x22
+	if ((params->flags == HW_PARAMS_FLAG_EQVOL_ON)||(params->flags == HW_PARAMS_FLAG_EQVOL_OFF))
+	{
+		ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai);
+		AIC_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+	}
+	else
+	{   
+		/* set codec DAI configuration */
+		#if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) 
+			ret = snd_soc_dai_set_fmt(codec_dai, 
+							SND_SOC_DAIFMT_I2S |
+							SND_SOC_DAIFMT_NB_NF | 
+							SND_SOC_DAIFMT_CBS_CFS);
+		#endif
+
+		#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 
+				ret = snd_soc_dai_set_fmt(codec_dai, 
+							SND_SOC_DAIFMT_I2S |
+							SND_SOC_DAIFMT_NB_NF |
+							SND_SOC_DAIFMT_CBM_CFM ); 
+		#endif
+
+		if (ret < 0)
+			return ret; 
+
+		/* set cpu DAI configuration */
+		#if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) 
+				ret = snd_soc_dai_set_fmt(cpu_dai, 
+							SND_SOC_DAIFMT_I2S |
+							SND_SOC_DAIFMT_NB_NF | 
+							SND_SOC_DAIFMT_CBM_CFM);
+		#endif
+		
+		#if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 
+				ret = snd_soc_dai_set_fmt(cpu_dai, 
+							SND_SOC_DAIFMT_I2S |
+							SND_SOC_DAIFMT_NB_NF | 
+							SND_SOC_DAIFMT_CBS_CFS);	
+		#endif
+
+		if (ret < 0)
+			return ret;
+	}
+
+	switch(params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 24000:
+	case 32000:
+	case 48000:
+			pll_out = 12288000;
+			break;
+	case 11025:
+	case 22050:
+	case 44100:
+			pll_out = 11289600;
+			break;
+	default:
+			printk("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
+			return -EINVAL;
+			break;
+	}
+	AIC_DBG("Enter:%s, %d, rate=%d, pll_out = %d\n",__FUNCTION__,__LINE__,params_rate(params), pll_out);
+	//pll_out = 12000000;
+	snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
+	snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN);
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget dac3100_dapm_widgets[] = {
+/*	SND_SOC_DAPM_LINE("Audio Out", NULL),
+	SND_SOC_DAPM_LINE("Line in", NULL),
+	SND_SOC_DAPM_MIC("Micn", NULL),
+	SND_SOC_DAPM_MIC("Micp", NULL),*/
+};
+
+static const struct snd_soc_dapm_route audio_map[]= {
+/*	{"Audio Out", NULL, "HPL"},
+	{"Audio Out", NULL, "HPR"},
+	{"Line in", NULL, "RINPUT1"},
+	{"Line in", NULL, "LINPUT1"},
+	{"Micn", NULL, "RINPUT2"},
+	{"Micp", NULL, "LINPUT2"},*/
+};
+
+/*
+ * Logic for a tlv320dac3100 as connected on a rockchip board.
+ */
+static int rk29_aic3111_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	AIC_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+
+	/* Add specific widgets */
+	snd_soc_dapm_new_controls(dapm, dac3100_dapm_widgets,
+				  ARRAY_SIZE(dac3100_dapm_widgets));
+
+	/* Set up specific audio path audio_mapnects */
+	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
+		AIC_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+	snd_soc_dapm_nc_pin(dapm, "HPL");
+		AIC_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+	snd_soc_dapm_nc_pin(dapm, "HPR");
+		AIC_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+	snd_soc_dapm_sync(dapm);
+		AIC_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+	return 0;
+}
+
+static struct snd_soc_ops rk29_ops = {
+	  .hw_params = rk29_hw_params,
+};
+
+static struct snd_soc_dai_link rk29_dai = {
+	.name = "AIC3111",
+	.stream_name = "AIC3111 PCM",
+	.codec_name = "AIC3111.0-0018",
+	.platform_name = "rockchip-audio",
+	.cpu_dai_name = "rk29_i2s.0",
+	.codec_dai_name = "AIC3111 HiFi",
+	.init = rk29_aic3111_init,
+	.ops = &rk29_ops,
+};
+
+static struct snd_soc_card snd_soc_card_rk29 = {
+	.name = "RK29_AIC3111",
+	.dai_link = &rk29_dai,
+	.num_links = 1,
+};
+
+static struct platform_device *rk29_snd_device;
+
+static int __init audio_card_init(void)
+{
+	int ret =0;
+
+        AIC_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
+	rk29_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!rk29_snd_device) {
+		  AIC_DBG("platform device allocation failed\n");
+		  ret = -ENOMEM;
+		  return ret;
+	}
+	platform_set_drvdata(rk29_snd_device, &snd_soc_card_rk29);
+	ret = platform_device_add(rk29_snd_device);
+	if (ret) {
+	        AIC_DBG("platform device add failed\n");
+	        platform_device_put(rk29_snd_device);
+	}
+	return ret;
+}
+
+static void __exit audio_card_exit(void)
+{
+	platform_device_unregister(rk29_snd_device);
+}
+
+module_init(audio_card_init);
+module_exit(audio_card_exit);
+/* Module information */
+MODULE_AUTHOR("rockchip");
+MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
+MODULE_LICENSE("GPL");
-- 
2.34.1