add tlv320aic3111 codec driver
author陈金泉 <chenjq@rock-chips.com>
Wed, 30 Nov 2011 03:42:08 +0000 (11:42 +0800)
committer陈金泉 <chenjq@rock-chips.com>
Wed, 30 Nov 2011 03:42:08 +0000 (11:42 +0800)
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/tlv320aic3111.c [new file with mode: 0644]
sound/soc/codecs/tlv320aic3111.h [new file with mode: 0644]
sound/soc/rk29/Kconfig
sound/soc/rk29/Makefile
sound/soc/rk29/rk29_aic3111.c [new file with mode: 0644]

index 9dfeb311759f634520b068d5c444b24274219481..95da908c85f956c40a4fb13b3a6e45d9638e80b4 100644 (file)
@@ -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
index b5c69a02e817578f477c5330314c1e2d1cd6c309..e9d88b2d3ba53d5dbf81c4a2660ee5b08a6672f0 100644 (file)
@@ -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 (file)
index 0000000..b065f0f
--- /dev/null
@@ -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 (file)
index 0000000..7b5b170
--- /dev/null
@@ -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 */
index 9474a30ea572fac100511a68ad051a16cf54bacb..d2772c079bb10045c1a83966622d1b54a2e4f49a 100755 (executable)
@@ -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
index cc0c09b0b40d4a350612a80bca0794fc51d5ba54..3092da30c1e5ebdcac3cc08bd3a1a6fd87e629d1 100644 (file)
@@ -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 (file)
index 0000000..68311b1
--- /dev/null
@@ -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");