[linux-yocto] [PATCH 08/65] sound: add atc260x sound driver

Jiang Lu lu.jiang at windriver.com
Wed Dec 21 01:16:09 PST 2016


From: wurui <wurui at actions-semi.com>

commit 7e4c4b402be5b73e78aebbd95aae6b0e34634155 from
https://github.com/xapp-le/kernel.git

Change-Id: Icc9349e8d47821633fe252d84631cd13a50caaa2
---
 arch/arm/mach-owl/include/mach/switch.h            |   53 +
 sound/Kconfig                                      |    9 +
 sound/core/pcm_lib.c                               |   25 +-
 sound/core/pcm_native.c                            |   90 +
 sound/soc/Kconfig                                  |    1 +
 sound/soc/Makefile                                 |    1 +
 sound/soc/atc260x/.gitignore                       |   24 +
 sound/soc/atc260x/Kconfig                          |   30 +
 sound/soc/atc260x/Makefile                         |   16 +
 .../atc260x/atc2603a-codec/atc2603a-audio-codec.c  | 1648 +++++++++++++++
 .../atc260x/atc2603a-codec/atc2603a-audio-regs.h   |  395 ++++
 .../atc260x/atc2603c-codec/atc2603c-audio-codec.c  | 2189 ++++++++++++++++++++
 .../atc260x/atc2603c-codec/atc2603c-audio-regs.h   |  244 +++
 sound/soc/atc260x/common-regs-owl.h                |  205 ++
 sound/soc/atc260x/dai-owl.c                        |  875 ++++++++
 sound/soc/atc260x/dmaengine-pcm-owl.c              |  438 ++++
 sound/soc/atc260x/hdmi-audio-owl.c                 |  814 ++++++++
 sound/soc/atc260x/link-owl.c                       |  642 ++++++
 sound/soc/atc260x/pcm-owl.c                        |  528 +++++
 sound/soc/atc260x/sndrv-owl.h                      |  101 +
 20 files changed, 8325 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm/mach-owl/include/mach/switch.h
 mode change 100644 => 100755 sound/Kconfig
 mode change 100644 => 100755 sound/core/pcm_lib.c
 mode change 100644 => 100755 sound/core/pcm_native.c
 mode change 100644 => 100755 sound/soc/Kconfig
 mode change 100644 => 100755 sound/soc/Makefile
 create mode 100755 sound/soc/atc260x/.gitignore
 create mode 100755 sound/soc/atc260x/Kconfig
 create mode 100755 sound/soc/atc260x/Makefile
 create mode 100755 sound/soc/atc260x/atc2603a-codec/atc2603a-audio-codec.c
 create mode 100755 sound/soc/atc260x/atc2603a-codec/atc2603a-audio-regs.h
 create mode 100755 sound/soc/atc260x/atc2603c-codec/atc2603c-audio-codec.c
 create mode 100755 sound/soc/atc260x/atc2603c-codec/atc2603c-audio-regs.h
 create mode 100755 sound/soc/atc260x/common-regs-owl.h
 create mode 100755 sound/soc/atc260x/dai-owl.c
 create mode 100755 sound/soc/atc260x/dmaengine-pcm-owl.c
 create mode 100755 sound/soc/atc260x/hdmi-audio-owl.c
 create mode 100755 sound/soc/atc260x/link-owl.c
 create mode 100755 sound/soc/atc260x/pcm-owl.c
 create mode 100755 sound/soc/atc260x/sndrv-owl.h

diff --git a/arch/arm/mach-owl/include/mach/switch.h b/arch/arm/mach-owl/include/mach/switch.h
new file mode 100644
index 0000000..3e4c748
--- /dev/null
+++ b/arch/arm/mach-owl/include/mach/switch.h
@@ -0,0 +1,53 @@
+/*
+ *  Switch class driver
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood at android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#ifndef __LINUX_SWITCH_H__
+#define __LINUX_SWITCH_H__
+
+struct switch_dev {
+	const char	*name;
+	struct device	*dev;
+	int		index;
+	int		state;
+
+	ssize_t	(*print_name)(struct switch_dev *sdev, char *buf);
+	ssize_t	(*print_state)(struct switch_dev *sdev, char *buf);
+};
+
+struct gpio_switch_platform_data {
+	const char *name;
+	unsigned 	gpio;
+
+	/* if NULL, switch_dev.name will be printed */
+	const char *name_on;
+	const char *name_off;
+	/* if NULL, "0" or "1" will be printed */
+	const char *state_on;
+	const char *state_off;
+};
+
+extern int switch_dev_register(struct switch_dev *sdev);
+extern void switch_dev_unregister(struct switch_dev *sdev);
+
+static inline int switch_get_state(struct switch_dev *sdev)
+{
+	return sdev->state;
+}
+
+extern void switch_set_state(struct switch_dev *sdev, int state);
+
+#endif /* __LINUX_SWITCH_H__ */
diff --git a/sound/Kconfig b/sound/Kconfig
old mode 100644
new mode 100755
index 5a240e0..062e7d1
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -134,3 +134,12 @@ config AC97_BUS
 	  sound subsystem and other function drivers completely unrelated to
 	  sound although they're sharing the AC97 bus. Concerned drivers
 	  should "select" this.
+	  
+config SND_UBUNTU
+	tristate "support for ubuntu."
+	help
+	  Say Y or M to ubuntu support.  This
+	  feature support ubuntu related.
+
+	  Many programs require this feature, so you should enable it
+	  unless you know what you're doing.
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
old mode 100644
new mode 100755
index 253a2da..7b9f3c8
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -1924,7 +1924,7 @@ static int wait_for_avail(struct snd_pcm_substream *substream,
 		}
 		wait_time = msecs_to_jiffies(wait_time * 1000);
 	}
-
+	wait_time = 50;
 	for (;;) {
 		if (signal_pending(current)) {
 			err = -ERESTARTSYS;
@@ -1999,8 +1999,17 @@ static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream,
 			return err;
 	} else {
 		char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
+#ifdef CONFIG_SND_UBUNTU
+        if(runtime->format == SNDRV_PCM_FORMAT_S16_LE){
+            memcpy(hwbuf, buf, frames_to_bytes(runtime, frames));
+        }else{
+		  if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames)))
+			return -EFAULT;
+		}	
+#else
 		if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames)))
 			return -EFAULT;
+#endif
 	}
 	return 0;
 }
@@ -2135,8 +2144,8 @@ snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const v
 	if (err < 0)
 		return err;
 	runtime = substream->runtime;
-	nonblock = !!(substream->f_flags & O_NONBLOCK);
-
+	//nonblock = !!(substream->f_flags & O_NONBLOCK);
+    nonblock = 0;
 	if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
 	    runtime->channels > 1)
 		return -EINVAL;
@@ -2221,8 +2230,18 @@ static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream,
 			return err;
 	} else {
 		char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
+#ifdef CONFIG_SND_UBUNTU
+        if(runtime->format == SNDRV_PCM_FORMAT_S16_LE){
+            memcpy(buf, hwbuf, frames_to_bytes(runtime, frames));
+        }else{
+            if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames)))
+                return -EFAULT;
+        }
+
+#else
 		if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames)))
 			return -EFAULT;
+#endif
 	}
 	return 0;
 }
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
old mode 100644
new mode 100755
index aa999e7..0801db3
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -2839,8 +2839,54 @@ static int snd_pcm_playback_ioctl1(struct file *file,
 			return -EFAULT;
 		if (copy_from_user(&xferi, _xferi, sizeof(xferi)))
 			return -EFAULT;
+#ifdef CONFIG_SND_UBUNTU
+        //when pcm data is 16bits
+        if(runtime->format == SNDRV_PCM_FORMAT_S16_LE){
+            unsigned int len, i;
+		    int *p = NULL;
+		    short *p_buf = NULL;
+            len = frames_to_bytes(runtime, xferi.frames);
+    	    p = kmalloc(2*len, GFP_KERNEL);
+    	    if (!p)
+        	    return -ENOMEM;
+    	    p_buf = kmalloc(len, GFP_KERNEL);
+    	    if (!p_buf)
+        	    return -ENOMEM;
+            if (copy_from_user((char *)p_buf, xferi.buf, len)){
+                printk(KERN_ERR"%s,%d\n", __func__, __LINE__);
+                return -EFAULT;
+            }
+            for(i=0; i<(len/2); i++) {
+                p[i] = ((int)p_buf[i]) << 16;
+            }
+            result = snd_pcm_lib_write(substream, p, 2*(xferi.frames));
+            if(result > 0){
+		    __put_user(result/2, &_xferi->result);
+            if((2*xferi.frames) != result){
+                   printk(KERN_ERR"%s,%d, frames:%ld, result:%ld\n", __func__, __LINE__,xferi.frames, result);
+                    __put_user(xferi.frames, &_xferi->result);
+                }
+            }
+            else
+                __put_user(result, &_xferi->result);
+		    if(NULL != p_buf){
+        	    kfree(p_buf);
+        	    p_buf = NULL;
+    	    }
+    	    if(NULL != p){
+        	    kfree(p);
+        	    p = NULL;
+    	    }
+        }else{
+            result = snd_pcm_lib_write(substream, xferi.buf, xferi.frames);
+		    __put_user(result, &_xferi->result);            
+        }
+		if(result < 0)
+			printk(KERN_ERR"%s,%d,result:%ld\n", __func__, __LINE__, result);
+#else
 		result = snd_pcm_lib_write(substream, xferi.buf, xferi.frames);
 		__put_user(result, &_xferi->result);
+#endif
 		return result < 0 ? result : 0;
 	}
 	case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
@@ -2919,8 +2965,51 @@ static int snd_pcm_capture_ioctl1(struct file *file,
 			return -EFAULT;
 		if (copy_from_user(&xferi, _xferi, sizeof(xferi)))
 			return -EFAULT;
+#ifdef CONFIG_SND_UBUNTU
+        //when pcm data is 16bits
+        if(runtime->format == SNDRV_PCM_FORMAT_S16_LE){
+            unsigned int len, i;
+            int *p = NULL;
+            short *p_buf = NULL;
+            len = frames_to_bytes(runtime, xferi.frames);
+            p = kmalloc(2*len, GFP_KERNEL);
+            if (!p)
+                return -ENOMEM;
+            p_buf = kmalloc(len, GFP_KERNEL);
+            if (!p_buf)
+                return -ENOMEM;
+            result = snd_pcm_lib_read(substream, p, 2*(xferi.frames));
+            __put_user(result/2, &_xferi->result);
+            for(i=0; i<(len/2); i++) {
+                p_buf[i] = (short)(p[i] >> 16);
+            }
+            if (copy_to_user(xferi.buf, (char *)p_buf, len)){
+                printk(KERN_ERR"%s,%d\n", __func__, __LINE__);
+                return -EFAULT;
+            }
+            if(NULL != p_buf){
+                kfree(p_buf);
+                p_buf = NULL;
+            }
+            if(NULL != p){
+                kfree(p);
+                p = NULL;
+            }
+
+            if(result < 0){
+                if(result == -EFAULT)
+                    printk(KERN_ERR"%s,%d,result:EFAULT\n", __func__, __LINE__);
+                else
+                    printk(KERN_ERR"%s,%d,result:%ld\n", __func__, __LINE__, result);
+              }
+        }else{
+            result = snd_pcm_lib_read(substream, xferi.buf, xferi.frames);
+            __put_user(result, &_xferi->result);
+        }
+#else
 		result = snd_pcm_lib_read(substream, xferi.buf, xferi.frames);
 		__put_user(result, &_xferi->result);
+#endif
 		return result < 0 ? result : 0;
 	}
 	case SNDRV_PCM_IOCTL_READN_FRAMES:
@@ -3513,6 +3602,7 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
 			return -ENXIO;
 		return snd_pcm_mmap_control(substream, file, area);
 	default:
+        printk(KERN_ERR"%s,default\n", __func__);
 		return snd_pcm_mmap_data(substream, file, area);
 	}
 	return 0;
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
old mode 100644
new mode 100755
index 3ba52da..9f93342
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -31,6 +31,7 @@ config SND_SOC_GENERIC_DMAENGINE_PCM
 	select SND_DMAENGINE_PCM
 
 # All the supported SoCs
+source "sound/soc/atc260x/Kconfig"
 source "sound/soc/adi/Kconfig"
 source "sound/soc/atmel/Kconfig"
 source "sound/soc/au1x/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
old mode 100644
new mode 100755
index 974ba70..d8d1f1c
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -12,6 +12,7 @@ endif
 obj-$(CONFIG_SND_SOC)	+= snd-soc-core.o
 obj-$(CONFIG_SND_SOC)	+= codecs/
 obj-$(CONFIG_SND_SOC)	+= generic/
+obj-$(CONFIG_SND_SOC)	+= atc260x/
 obj-$(CONFIG_SND_SOC)	+= adi/
 obj-$(CONFIG_SND_SOC)	+= atmel/
 obj-$(CONFIG_SND_SOC)	+= au1x/
diff --git a/sound/soc/atc260x/.gitignore b/sound/soc/atc260x/.gitignore
new file mode 100755
index 0000000..d12ccb3
--- /dev/null
+++ b/sound/soc/atc260x/.gitignore
@@ -0,0 +1,24 @@
+#
+# NOTE! Please use 'git ls-files -i --exclude-standard'
+# command after changing this file, to see if there are
+# any tracked files which get ignored after the change.
+#
+# Normal rules
+#
+*.o
+*.o.*
+*.ko
+*.ko.*
+*.mod.c
+*.order
+*.bak
+
+#
+# Top-level generic files
+#
+/Module.symvers
+
+#
+# git files that we don't want to ignore even it they are dot-files
+#
+!.gitignore
diff --git a/sound/soc/atc260x/Kconfig b/sound/soc/atc260x/Kconfig
new file mode 100755
index 0000000..e7b7df0
--- /dev/null
+++ b/sound/soc/atc260x/Kconfig
@@ -0,0 +1,30 @@
+config SND_SOC_OWL
+	tristate
+	depends on SND_SOC
+
+config SND_SOC_ATC2603A 
+	tristate
+	depends on SND_SOC_OWL
+
+config SND_SOC_ATC2603C 
+	tristate
+	depends on SND_SOC_OWL	
+
+config SND_SOC_HDMI_OWL
+	tristate
+	depends on SND_SOC_OWL
+
+config SND_SOC_DAI_OWL
+	tristate
+	depends on SND_SOC_OWL
+
+config SND_SOC_ALL_PMU_OWL
+	tristate "SoC Audio support for all pmus owl board"
+	select SND_SOC_OWL
+	select SND_SOC_HDMI_OWL
+	select SND_SOC_DAI_OWL
+	select SND_SOC_ATC2603A
+	select SND_SOC_ATC2603C
+	help
+	  Say Y if you want to add support for SoC audio on atc2603a-based
+	  ATM7059 board.	  
\ No newline at end of file
diff --git a/sound/soc/atc260x/Makefile b/sound/soc/atc260x/Makefile
new file mode 100755
index 0000000..bad9c2b
--- /dev/null
+++ b/sound/soc/atc260x/Makefile
@@ -0,0 +1,16 @@
+# AT91 Platform Support
+snd-soc-atc2603a-objs                            :=      atc2603a-codec/atc2603a-audio-codec.o
+snd-soc-atc2603c-objs                            :=      atc2603c-codec/atc2603c-audio-codec.o
+snd-soc-dai-owl-objs                        :=      dai-owl.o
+snd-soc-hdmi-owl-objs                       :=      hdmi-audio-owl.o
+snd-soc-pcm-owl-objs                        :=      pcm-owl.o dmaengine-pcm-owl.o
+snd-soc-link-owl-objs                       :=      link-owl.o
+
+obj-$(CONFIG_SND_SOC_OWL) += snd-soc-pcm-owl.o
+obj-$(CONFIG_SND_SOC_ATC2603A) += snd-soc-atc2603a.o 
+obj-$(CONFIG_SND_SOC_ATC2603C) += snd-soc-atc2603c.o 
+obj-$(CONFIG_SND_SOC_DAI_OWL) += snd-soc-dai-owl.o
+obj-$(CONFIG_SND_SOC_HDMI_OWL) += snd-soc-hdmi-owl.o
+
+# ATC2603A PMU Machine Support
+obj-$(CONFIG_SND_SOC_ALL_PMU_OWL) += snd-soc-link-owl.o
diff --git a/sound/soc/atc260x/atc2603a-codec/atc2603a-audio-codec.c b/sound/soc/atc260x/atc2603a-codec/atc2603a-audio-codec.c
new file mode 100755
index 0000000..f9336a4
--- /dev/null
+++ b/sound/soc/atc260x/atc2603a-codec/atc2603a-audio-codec.c
@@ -0,0 +1,1648 @@
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <linux/clk.h>			/* clk_enable */
+#include "../sndrv-owl.h"
+#include "atc2603a-audio-regs.h"
+#include "../common-regs-owl.h"
+#include <mach/clkname.h>
+#include <mach/module-owl.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+
+#include <linux/io.h>
+#include <linux/ioport.h>
+
+#include <linux/suspend.h>
+#include <linux/earlysuspend.h>
+
+#include <linux/mfd/atc260x/atc260x.h>
+
+
+static int direct_drive_disable;//0:ֱ\C7\FD\A3\AC 1:\B7\C7ֱ\C7\FD
+
+static const char *audio_device_node = "actions,atc2603a-audio";
+static const char *snd_earphone_output_mode = "earphone_output_mode";
+static const char *snd_mic_num = "mic_num";
+static const char *snd_mic0_gain = "mic0_gain";
+static const char *snd_speaker_gain = "speaker_gain";
+static const char *snd_earphone_gain = "earphone_gain";
+/*
+static const char *snd_speaker_volume = "speaker_volume";
+static const char *snd_earphone_volume = "earphone_volume";
+static const char *snd_earphone_detect_mode = "earphone_detect_mode";
+*/
+static const char *speaker_ctrl_name = "speaker_gpios";
+static int speaker_gpio_num;
+
+static audio_hw_cfg_t audio_hw_cfg;
+
+static int atc2603a_open_count;
+static unsigned int user_lock = 1;
+static volatile unsigned int hw_init_flag = false;
+static DEFINE_MUTEX(atc2603a_pa_down_lock);
+
+//20141013 yuchen: to check pmu ic type
+static int atc2603a_ictype = PMU_NOT_USED;
+
+struct reg_val {
+	int reg;
+	unsigned short val;
+	short delay; /* ms */
+};
+
+struct atc2603a_priv_data {
+	int mode;
+};
+static struct atc260x_dev *atc260x;
+struct snd_soc_codec *atc2603a_codec;
+
+#define   ATC2603A_AIF			0
+#define   REG_BASE				ATC2603A_AUDIO_IN_OUT_BASE
+
+#define   AUDIOINOUT_CTL		0x00
+#define   AUDIO_DEBUGOUTCTL 	0x01
+#define   DAC_FILTERCTL0		0x02
+#define   DAC_FILTERCTL1		0x03
+#define   DAC_DIGITALCTL		0x04
+#define   DAC_VOLUMECTL0		0x05
+#define   DAC_VOLUMECTL1		0x06
+#define   DAC_VOLUMECTL2		0x07
+#define   DAC_VOLUMECTL3		0x08
+#define   DAC_ANANLOG0			0x09
+#define   DAC_ANANLOG1			0x0a
+#define   DAC_ANANLOG2			0x0b
+#define   DAC_ANANLOG3			0x0c
+#define   DAC_ANANLOG4			0x0d
+#define   CLASSD_CTL0			0x0e
+#define   CLASSD_CTL1			0x0f
+#define   CLASSD_CTL2			0x10
+
+#define   ADC0_DIGITALCTL		0x11
+#define   ADC0_HPFCTL			0x12
+#define   ADC0_CTL				0x13
+#define   AGC0_CTL0				0x14
+#define   AGC0_CTL1				0x15
+#define   AGC0_CTL2				0x16
+#define   ADC_ANANLOG0			0x17
+#define   ADC_ANANLOG1			0x18
+#define   ADC1_DIGITALCTL		0x19
+#define   ADC1_CTL				0x1a
+#define   AGC1_CTL0				0x1b
+#define   AGC1_CTL1				0x1c
+#define   AGC1_CTL2				0x1d
+
+static const u16 atc2603a_reg[AGC1_CTL2 +1] = {
+	[AUDIOINOUT_CTL] = 0x00,
+	[AUDIO_DEBUGOUTCTL] = 0x00,
+	[DAC_FILTERCTL0] = 0x00,
+	[DAC_FILTERCTL1] = 0x00,
+	[DAC_DIGITALCTL] = 0x00,
+	[DAC_VOLUMECTL0] = 0xbebe,
+	[DAC_VOLUMECTL1] = 0xbebe,
+	[DAC_VOLUMECTL2] = 0xbebe,
+	[DAC_VOLUMECTL3] = 0xbebe,
+	[DAC_ANANLOG0] = 0x5355,
+	[DAC_ANANLOG1] = 0x0040,
+	[DAC_ANANLOG2] = 0x00,
+	[DAC_ANANLOG3] = 0x880b,
+	[DAC_ANANLOG4] = 0x00,
+	[CLASSD_CTL0] = 0x8000,
+	[CLASSD_CTL1] = 0x0450,
+	[CLASSD_CTL2] = 0x06d0,
+	[ADC0_DIGITALCTL] = 0x00,
+	[ADC0_HPFCTL] = 0x00,
+	[ADC0_CTL] = 0x0881,
+	[AGC0_CTL0] = 0x9933,
+	[AGC0_CTL1] = 0x051a,
+	[AGC0_CTL2] = 0x8c40,
+	[ADC_ANANLOG0] = 0x8269,
+	[ADC_ANANLOG1] = 0x8955,
+	[ADC1_DIGITALCTL] = 0x00,
+	[ADC1_CTL] = 0x00,
+	[AGC1_CTL0] = 0x9933,
+	[AGC1_CTL1] = 0x051a,
+	[AGC1_CTL2] = 0x8c40,
+};
+
+struct reg_val atc2603a_pa_up_list[] = {
+	{DAC_VOLUMECTL0, 0xbebe, 0},
+	{DAC_ANANLOG0, 0x00, 0},
+	{DAC_ANANLOG1, 0x00, 0},
+	{DAC_ANANLOG2, 0x00, 0},
+	{DAC_ANANLOG3, 0x00, 0},
+	{DAC_ANANLOG4, 0x00, 0},
+	{AUDIOINOUT_CTL, 0x02, 0},
+	{DAC_DIGITALCTL, 0x03, 0},
+	{DAC_ANANLOG4, 0x08c0, 0},
+	{DAC_ANANLOG0, 0x26b3, 0},
+	{DAC_ANANLOG3, 0x8b0b, 0},
+	{DAC_ANANLOG2, 0x07, 0},
+	{DAC_ANANLOG3, 0x8b0f, 100},
+	{DAC_ANANLOG2, 0x0f, 0},
+	{DAC_ANANLOG4, 0x88c0, 0},
+	{DAC_ANANLOG2, 0x1f, 600},
+	{DAC_ANANLOG2, 0x17, 0},
+};
+
+struct reg_val atc2603a_pa_down_list[] = {
+	{DAC_VOLUMECTL0, 0xbebe, 0},
+	{DAC_ANANLOG4, 0x08c0, 0},
+	{DAC_ANANLOG2, 0x1f, 0},
+	{DAC_ANANLOG2, 0x0f, 0},
+};
+
+struct asoc_codec_resource {
+    void __iomem    *base[MAX_RES_NUM];/*virtual base for every resource*/
+    void __iomem    *baseptr; /*pointer to every virtual base*/
+    struct clk      *clk;
+    int             irq;
+    unsigned int    setting;
+};
+
+
+/* 
+static void set_dai_reg_base(int num)
+{
+	codec_res.baseptr = codec_res.base[num];
+}
+
+static u32 snd_dai_readl(u32 reg)
+{
+	return readl(codec_res.baseptr + reg);
+}
+	 
+static void snd_dai_writel(u32 val, u32 reg)
+{
+	writel(val, codec_res.baseptr + reg);
+}
+*/
+
+/*
+static void snd_codec_writel_debug(unsigned int  val, unsigned int  reg)
+{
+	snd_dai_writel(val, reg);
+	snd_dbg("%s: reg[0x%x]=[0x%x][0x%x]\n"
+		, __func__, reg, val, snd_dai_readl(reg));
+}
+*/
+
+static int atc2603a_write_pmu(struct snd_soc_codec *codec, unsigned int reg,
+		unsigned int value)
+{
+	struct atc260x_dev *atc260x = snd_soc_codec_get_drvdata(codec);
+	int ret;
+	
+	ret = atc260x_reg_write(atc260x, reg, value);
+	if(ret < 0)
+	{
+		snd_err("atc2603a_write: reg = %#X, ret = %d \n", reg, ret);
+	}
+
+	snd_dbg("%s: reg[0x%x]=[0x%x][0x%x]\n"
+		, __func__, reg, value, atc260x_reg_read(atc260x, reg));
+
+	return ret;
+}
+static int atc2603a_read_pmu(struct snd_soc_codec *codec, unsigned int reg)
+{
+	struct atc260x_dev *atc260x = snd_soc_codec_get_drvdata(codec);
+	int ret;
+	
+	ret = atc260x_reg_read(atc260x, reg);
+	if(ret < 0)
+	{
+		snd_err("atc2603a_read: reg = %#X, ret = %d \n", reg, ret);
+	}
+
+	return ret;	
+}
+static int snd_soc_update_bits_pmu(struct snd_soc_codec *codec, unsigned short reg,
+				unsigned int mask, unsigned int value)
+{
+	bool change;
+	unsigned int old, new;
+	int ret;
+
+	{
+		ret = atc2603a_read_pmu(codec, reg);
+		if (ret < 0)
+			return ret;
+
+		old = ret;
+		new = (old & ~mask) | (value & mask);
+		change = old != new;
+		if (change)
+			ret = atc2603a_write_pmu(codec, reg, new);
+	}
+
+	if (ret < 0)
+		return ret;
+
+	return change;
+
+}
+
+
+static void ramp_undirect(unsigned int begv, unsigned int endv) {
+	unsigned int val = 0;
+	int count = 0;
+	
+	set_dai_reg_base(I2S_SPDIF_NUM);
+	while (endv < begv) {
+		count++;
+		if ((count & 0x7F) == 0) {
+			mdelay(1);
+		}
+		val = snd_dai_readl(I2S_FIFOCTL);
+		while ((val & (0x1 << 8)) != 0) {
+			val = snd_dai_readl(I2S_FIFOCTL);
+		};
+		snd_dai_writel(endv, I2STX_DAT);
+		endv -= 0x36000;
+	}
+	while (begv <= endv) {
+		count++;
+		if ((count & 0x7F) == 0) {
+			mdelay(1);
+		}
+		val = snd_dai_readl(I2S_FIFOCTL);
+		while ((val & (0x1 << 8)) != 0) {
+			val = snd_dai_readl(I2S_FIFOCTL);
+		};
+		snd_dai_writel(endv, I2STX_DAT);
+		endv -= 0x36000;
+	}
+}
+
+static int atc2603a_write(struct snd_soc_codec *codec, unsigned int reg,
+		unsigned int value)
+{
+	int ret = 0;
+
+	struct atc260x_dev *atc260x = snd_soc_codec_get_drvdata(codec);
+
+	ret = atc260x_reg_write(atc260x, reg + REG_BASE, value);
+	snd_dbg("%s: reg[0x%x]=[0x%x]\r\n", __func__, reg + REG_BASE, value);
+	if (ret < 0)
+		snd_err("atc2603a_write: reg = %#X, ret = %d failed\n",
+		reg, ret);
+
+	snd_dbg("%s: reg[0x%x]=[0x%x][0x%x]\n"
+		, __func__, reg, value, atc260x_reg_read(atc260x, reg + REG_BASE));
+
+	return ret;
+}
+
+static unsigned int atc2603a_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+	int ret = 0;
+
+	ret = atc260x_reg_read(atc260x, reg + REG_BASE);
+	snd_dbg("%s: reg[0x%x]\r\n", __func__, reg + REG_BASE);
+	if (ret < 0)
+	snd_err("atc2603a_read: reg = %#X, ret = %d failed\n", reg, ret);
+
+	return ret;
+}
+
+#define ADC0_GAIN_MAX	25
+
+static int atc2603a_adc_gain_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+	unsigned int val;
+	snd_soc_cache_sync(codec);
+	val = snd_soc_read(codec, mc->reg);
+	ucontrol->value.integer.value[0] =
+		((val & AGC_CTL0_AMP1GL_MSK) >> mc->shift);
+	ucontrol->value.integer.value[1] =
+		(val & AGC_CTL0_AMP1GR_MSK) >> mc->rshift;
+
+	return 0;
+}
+
+static int atc2603a_adc_gain_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+	unsigned int val, val1, val2;
+
+	val = snd_soc_read(codec, mc->reg);
+	val1 = ucontrol->value.integer.value[0];
+	val2 = val1;
+	val = val & (~AGC_CTL0_AMP1GL_MSK);
+	val = val & (~AGC_CTL0_AMP1GR_MSK);
+	val = val | (val1<< mc->shift);
+	val = val | (val2 << mc->rshift);
+
+	snd_soc_component_update_bits(component, mc->reg,
+	AGC_CTL0_AMP1GL_MSK | AGC_CTL0_AMP1GR_MSK,
+	val);
+
+	snd_soc_cache_sync(codec);
+
+	return 0;
+}
+
+static int atc2603a_mic_gain_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] =
+		audio_hw_cfg.mic0_gain[0];
+	ucontrol->value.integer.value[1] =
+		audio_hw_cfg.mic0_gain[1];
+
+	return 0;
+}
+
+static int atc2603a_earphone_gain_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] =
+		audio_hw_cfg.earphone_gain[0];
+	ucontrol->value.integer.value[1] =
+		audio_hw_cfg.earphone_gain[1];
+
+	return 0;
+}
+
+static int atc2603a_speaker_gain_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] =
+		audio_hw_cfg.speaker_gain[0];
+	ucontrol->value.integer.value[1] =
+		audio_hw_cfg.speaker_gain[1];
+
+	return 0;
+}
+
+static int atc2603a_speaker_volume_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] =
+		audio_hw_cfg.speaker_volume;
+
+	return 0;
+}
+
+static int atc2603a_earphone_volume_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] =
+		audio_hw_cfg.earphone_volume;
+
+	return 0;
+}
+
+static int atc2603a_mic_num_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] =
+		audio_hw_cfg.mic_num;
+
+	return 0;
+}
+
+const char *atc2603a_mic0_mode[] = {
+	"Differential", "Single ended"};
+
+static const SOC_ENUM_SINGLE_DECL(
+		atc2603a_mic0_mode_enum, ADC0_CTL,
+		ADC0_CTL_MIC0FDSE_SFT, atc2603a_mic0_mode);
+
+static const char *pa_output_swing[] = {
+	"Vpp2.4", "Vpp1.6"};
+
+static const SOC_ENUM_SINGLE_DECL(
+		pa_output_swing_enum, DAC_ANANLOG1,
+		DAC_ANALOG1_PASW_SFT, pa_output_swing);
+
+const struct snd_kcontrol_new atc2603a_snd_controls[] = {
+
+	SOC_DOUBLE_EXT_TLV("Dummy mic Gain",
+		0, 0, 1, 0xf, 0,
+		atc2603a_mic_gain_get,
+		NULL,
+		NULL),
+
+	SOC_DOUBLE_EXT_TLV("Dummy earphone gain",
+		0, 0, 1, 0xff, 0,
+		atc2603a_earphone_gain_get,
+		NULL,
+		NULL),
+
+	SOC_DOUBLE_EXT_TLV("Dummy speaker gain",
+		0, 0, 1, 0xff, 0,
+		atc2603a_speaker_gain_get,
+		NULL,
+		NULL),
+
+	SOC_SINGLE_EXT_TLV("Dummy speaker volume",
+		0, 0, 0x28, 0,
+		atc2603a_speaker_volume_get,
+		NULL,
+		NULL),
+
+	SOC_SINGLE_EXT_TLV("Dummy earphone volume",
+		0, 0, 0x28, 0,
+		atc2603a_earphone_volume_get,
+		NULL,
+		NULL),
+
+	SOC_SINGLE_EXT_TLV("Dummy mic num",
+		0, 0, 0x2, 0,
+		atc2603a_mic_num_get,
+		NULL,
+		NULL),
+
+	SOC_DOUBLE_EXT_TLV("Adc0 Gain",
+		AGC0_CTL0,
+		AGC0_CTL0_AMP1G0L_SFT,
+		AGC0_CTL0_AMP1G0R_SFT,
+		0xf,
+		0,
+		atc2603a_adc_gain_get,
+		atc2603a_adc_gain_put,
+		NULL),
+
+	SOC_SINGLE_TLV("AMP1 Gain boost Range select",
+		AGC0_CTL0,
+		AGC0_CTL0_AMP0GR1_SET,
+		0x7,
+		0,
+		NULL),
+
+	SOC_SINGLE_TLV("ADC0 Digital Gain control",
+		ADC0_DIGITALCTL,
+		ADC0_DIGITALCTL_ADGC0_SFT,
+		0xF,
+		0,
+		NULL),
+
+	SOC_DOUBLE_EXT_TLV("Adc1 Gain",
+		AGC1_CTL0,
+		AGC1_CTL0_AMP1G1L_SFT,
+		AGC1_CTL0_AMP1G1R_SFT,
+		0xf,
+		0,
+		atc2603a_adc_gain_get,
+		atc2603a_adc_gain_put,
+		NULL),
+		
+	SOC_ENUM("Mic0 Mode Mux", atc2603a_mic0_mode_enum),
+	
+	SOC_ENUM("PA Output Swing Mux", pa_output_swing_enum),
+	
+	SOC_SINGLE_TLV("DAC PA Volume",
+		DAC_ANANLOG1,
+		DAC_ANALOG1_VOLUME_SFT,
+		0x28,
+		0,
+		NULL),
+		
+	SOC_SINGLE("DAC FL FR PLAYBACK Switch",
+		DAC_ANANLOG1,
+		DAC_ANALOG1_DACFL_FRMUTE_SFT,
+		1,
+		0),
+		
+	SOC_SINGLE_TLV("DAC FL Gain",
+		DAC_VOLUMECTL0,
+		DAC_VOLUMECTL0_DACFL_VOLUME_SFT,
+		0xFF,
+		0,
+		NULL),
+		
+	SOC_SINGLE_TLV("DAC FR Gain",
+		DAC_VOLUMECTL0,
+		DAC_VOLUMECTL0_DACFR_VOLUME_SFT,
+		0xFF,
+		0,
+		NULL),
+		
+	SOC_SINGLE("DAC PA Switch",
+		DAC_ANANLOG4,
+		DAC_ANALOG4_PAEN_FR_FL_SFT,
+		1,
+		0),
+		
+	SOC_SINGLE("DAC PA OUTPUT Stage Switch",
+		DAC_ANANLOG4,
+		DAC_ANALOG4_PAOSEN_FR_FL_SFT,
+		1,
+		0),
+		
+	SOC_DOUBLE("DAC Digital FL FR Switch",
+		DAC_DIGITALCTL,
+		DAC_DIGITALCTL_DEFL_SFT,
+		DAC_DIGITALCTL_DEFR_SFT,
+		1,
+		0),
+
+	SOC_SINGLE("Internal Mic Power Switch", ADC0_CTL,
+		ADC0_CTL_VMICINEN_SFT,
+		1,
+		0),
+		
+	SOC_SINGLE("External Mic Power Switch",
+		ADC0_CTL,
+		ADC0_CTL_VMICEXEN_SFT,
+		1,
+		0),
+		
+	SOC_SINGLE_TLV("External MIC Power Voltage",
+		ADC0_CTL,
+		ADC0_CTL_VMICEXST_SFT,
+		0x3,
+		0,
+		NULL),
+		
+	SOC_SINGLE_TLV("Adc0 Digital Gain",
+		ADC0_DIGITALCTL,
+		6,
+		0xf, 0, NULL),
+		
+	SOC_SINGLE_TLV("Adc1 Digital Gain",
+		ADC1_DIGITALCTL,
+		2,
+		0xf, 0, NULL),
+};
+
+const char *atc2603a_adc0_src[] = {"MIC0", "FM", "AOUT MIXER"};
+
+static const SOC_ENUM_SINGLE_DECL(
+	atc2603a_adc0_enum, ADC0_CTL,
+	ADC0_CTL_ADCIS_SFT, atc2603a_adc0_src);
+
+
+const struct snd_kcontrol_new atc2603a_adc0_mux =
+SOC_DAPM_ENUM("ADC0 Source", atc2603a_adc0_enum);
+
+const struct snd_kcontrol_new atc2603a_dac_lr_mix[] = {
+	SOC_DAPM_SINGLE("FL FR Switch", DAC_ANANLOG1,
+			DAC_ANALOG1_DACFL_FRMUTE_SFT, 1, 0),
+	SOC_DAPM_SINGLE("MIC Switch", DAC_ANANLOG1,
+			DAC_ANALOG1_DACMICMUTE_SFT, 1, 0),
+	SOC_DAPM_SINGLE("FM Switch", DAC_ANANLOG1,
+			DAC_ANALOG1_DACFMMUTE_SFT, 1, 0),
+};
+
+static int atc2603a_mic0_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	unsigned int val;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		val = snd_soc_read(codec, ADC0_CTL);
+		/* single end or full differential */
+		if (val & ADC0_CTL_MIC0FDSE) {//if single end
+			snd_soc_update_bits_pmu(codec, ATC2603A_MFP_CTL1,
+					0x03 << 10, 0x03 << 10);//reserved?
+			snd_soc_update_bits_pmu(codec, ATC2603A_MFP_CTL1,
+					0x03 << 8, 0);//MICINL&MICINR
+		}
+		snd_soc_update_bits(codec, ADC1_CTL,
+				0x3 << 7, 0x3 << 7);//(VRDN output0 enable) | (VRDN output1 enable)
+		snd_soc_update_bits(codec, ADC0_HPFCTL,
+				0x3, 0x3);//(High Pass filter0 L enable) | (High Pass filter0 R enable)
+
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static void i2s_clk_disable(void)
+{
+}
+
+static int i2s_clk_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		i2s_clk_disable();
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget atc2603a_dapm_widgets[] = {
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("MICIN0LP"),
+	SND_SOC_DAPM_INPUT("MICIN0LN"),
+	SND_SOC_DAPM_INPUT("MICIN0RP"),
+	SND_SOC_DAPM_INPUT("MICIN0RN"),
+	SND_SOC_DAPM_INPUT("MICIN1LP"),
+	SND_SOC_DAPM_INPUT("MICIN1LN"),
+	SND_SOC_DAPM_INPUT("MICIN1RP"),
+	SND_SOC_DAPM_INPUT("MICIN1RN"),
+	SND_SOC_DAPM_INPUT("FMINL"),
+	SND_SOC_DAPM_INPUT("FMINR"),
+
+	SND_SOC_DAPM_SUPPLY("I2S_CLK", SND_SOC_NOPM,
+		0, 0, i2s_clk_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_PGA("MICIN0L", ADC0_CTL,
+		ADC0_CTL_MIC0LEN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("MICIN0R", ADC0_CTL,
+		ADC0_CTL_MIC0REN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("MICIN1L", ADC1_CTL,
+		ADC1_CTL_MIC1LEN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("MICIN1R", ADC1_CTL,
+		ADC1_CTL_MIC1REN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("FM L", ADC0_CTL,
+		ADC0_CTL_FMLEN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("FM R", ADC0_CTL,
+		ADC0_CTL_FMREN_SFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIC("MICIN0", atc2603a_mic0_event),
+	SND_SOC_DAPM_MIC("MICIN1", NULL),
+	SND_SOC_DAPM_MIC("FM", NULL),
+	/* ADC0 MUX */
+	SND_SOC_DAPM_MUX("ADC0 Mux", SND_SOC_NOPM, 0, 0,
+		&atc2603a_adc0_mux),
+	/* ADCS */
+	SND_SOC_DAPM_ADC("ADC0 L", NULL, ADC0_CTL,
+			ADC0_CTL_AD0LEN_SFT, 0),
+	SND_SOC_DAPM_ADC("ADC0 R", NULL, ADC0_CTL,
+			ADC0_CTL_AD0REN_SFT, 0),
+	SND_SOC_DAPM_ADC("ADC1 L", NULL, ADC1_CTL,
+			ADC1_CTL_AD1LEN_SFT, 0),
+	SND_SOC_DAPM_ADC("ADC1 R", NULL, ADC1_CTL,
+			ADC1_CTL_AD1REN_SFT, 0),
+	/* DAC Mixer */
+	SND_SOC_DAPM_MIXER("AOUT FL FR Mixer",
+			SND_SOC_NOPM, 0, 0,
+			atc2603a_dac_lr_mix,
+			ARRAY_SIZE(atc2603a_dac_lr_mix)),
+	SND_SOC_DAPM_DAC("DAC FL", NULL, DAC_ANANLOG4,
+		DAC_ANALOG4_DACEN_FL_SFT, 0),
+	SND_SOC_DAPM_DAC("DAC FR", NULL, DAC_ANANLOG4,
+		DAC_ANALOG4_DACEN_FR_SFT, 0),
+
+	SND_SOC_DAPM_AIF_IN("AIFRX", "AIF Playback", 0,
+			SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIFTX", "AIF Capture", 0,
+			SND_SOC_NOPM, 0, 0),
+
+	/* output lines */
+	SND_SOC_DAPM_OUTPUT("HP"),
+	SND_SOC_DAPM_OUTPUT("SP"),
+};
+
+static const struct snd_soc_dapm_route atc2603a_dapm_routes[] = {
+	{"MICIN0L", NULL, "MICIN0LP"},
+	{"MICIN0L", NULL, "MICIN0LN"},
+	{"MICIN0R", NULL, "MICIN0RP"},
+	{"MICIN0R", NULL, "MICIN0RN"},
+	{"MICIN1L", NULL, "MICIN1LP"},
+	{"MICIN1L", NULL, "MICIN1LN"},
+	{"MICIN1R", NULL, "MICIN1RP"},
+	{"MICIN1R", NULL, "MICIN1RN"},
+	{"FM L", NULL, "FMINL"},
+	{"FM R", NULL, "FMINR"},
+	{"MICIN0", NULL, "MICIN0L"},
+	{"MICIN0", NULL, "MICIN0R"},
+	{"MICIN1", NULL, "MICIN1L"},
+	{"MICIN1", NULL, "MICIN1R"},
+	{"FM", NULL, "FM L"},
+	{"FM", NULL, "FM R"},
+	{"ADC0 Mux", "MIC0", "MICIN0"},
+	{"ADC0 Mux", "FM", "FM"},
+	{"ADC0 Mux", "AOUT MIXER", "AOUT FL FR Mixer"},
+	{"ADC0 L", NULL, "ADC0 Mux"},
+	{"ADC0 R", NULL, "ADC0 Mux"},
+	{"AIFTX", NULL, "ADC0 L"},
+	{"AIFTX", NULL, "ADC0 R"},
+	{"AOUT FL FR Mixer", "FL FR Switch", "AIFRX"},
+	{"AOUT FL FR Mixer", "MIC Switch", "MICIN0"},
+	{"AOUT FL FR Mixer", "FM Switch", "FM"},
+	{"DAC FL", NULL, "AOUT FL FR Mixer"},
+	{"DAC FR", NULL, "AOUT FL FR Mixer"},
+	{"HP", NULL, "DAC FL"},
+	{"HP", NULL, "DAC FR"},
+	{"SP", NULL, "DAC FL"},
+	{"SP", NULL, "DAC FR"},
+};
+
+static void pa_up(struct snd_soc_codec *codec) {
+	/* DAC\B3\E4\B5\E7\B5ķ\BD\B7\A8:\B7\C7ֱ\C7\FD
+	a)	\CB\F9\D3\D0audio analog\BCĴ\E6\C6\F7\B6\BCд0\A3\AC\D6\F7\BF\D8TX\BA\CDTXFIFO\B6\BCʹ\C4ܡ\A3
+	b)	\CF\F2\D6\F7\BF\D8\C0\EF\C3\E6д\D7\EEСֵ\A3\A80x80000000\A3\A9
+	c)	\D6\F7\BFغ\CDatc2603aѡ\D4\F1N wireģʽ\A3\AC2.0 channelģʽ
+	d)	atc2603a\B5\C4DAC_D&A\B6\BCʹ\C4\DC
+	e)	PA BIAS EN \A3\ACPA EN\A3\ACLOOP2 EN\A3\ACatc2603_DAC_ANALOG1дȫ0
+	f)	Delay10ms
+	g)	DAC \BF\AAʼ\B7\C5ramp\CA\FD\BEݣ\A8\B4\D30X80000000\B5\BD0x7fffffff\A3\ACÿ\B8\F40x36000дһ\B4\CE
+	\A3\ACʹ\D3\C3mips\B2\E9ѯд5201\B5\C4I2S_TX FIFO\A3\A9,ͬʱ\BF\AA\C6\F4ramp connect
+	h)	\B5ȴ\FDԼ500 ms
+	i)	\BF\AA\C6\F4pa\CA\E4\B3\F6\BC\B6en\A3\AC\B6Ͽ\AAramp connect\A3\ACLOOP2 Disable\A1\A3
+	*/
+
+	set_dai_reg_base(I2S_SPDIF_NUM);
+	/* i2stx fifo en */
+	snd_dai_writel(snd_dai_readl(I2S_FIFOCTL) | 0x3, I2S_FIFOCTL);
+	/* i2s tx en */
+	snd_dai_writel(snd_dai_readl(I2S_CTL) | 0x3, I2S_CTL);
+	snd_soc_write(codec, DAC_VOLUMECTL0, 0xbebe);
+	snd_soc_write(codec, DAC_ANANLOG0, 0);
+	snd_soc_write(codec, DAC_ANANLOG1, 0);
+	snd_soc_write(codec, DAC_ANANLOG2, 0);
+	snd_soc_write(codec, DAC_ANANLOG3, 0);
+	snd_soc_write(codec, DAC_ANANLOG4, 0);
+
+
+	if (direct_drive_disable == 0) {
+		snd_dai_writel(0x1 << 31, I2STX_DAT);
+		snd_dai_writel(0x1 << 31, I2STX_DAT);
+	} else {
+		snd_dai_writel(0x7ffffe00, I2STX_DAT);
+		snd_dai_writel(0x7ffffe00, I2STX_DAT);
+	}
+
+	/* 2.0-Channel Mode */
+	snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x7 << 4), I2S_CTL);
+	/* I2S input en */
+	snd_soc_update_bits(codec, AUDIOINOUT_CTL, 0x01 << 1, 0x01 << 1);
+	/* FL&FR enable, dac_mute = 0(NOT MUTE) */
+	snd_soc_write(codec, DAC_DIGITALCTL, 0x3);
+	/* DAC analog FL&FR en, PA en, out stage disable */
+	snd_soc_write(codec, DAC_ANANLOG4, 0x08c0);
+	/* dac OPDA BIAS\C9\E8Ϊ100 */
+	snd_soc_write(codec, DAC_ANANLOG0, 0x26b3);
+	/*snd_soc_write(codec, DAC_ANANLOG3, 0x8b0b);
+	 dac pa bias en\A3\ACPA LOOP2 en */
+	snd_soc_write(codec, DAC_ANANLOG3, 0xab0b);
+
+
+	if (direct_drive_disable == 0) {
+		/* vro IQ biggest */
+		snd_soc_update_bits(codec, DAC_ANANLOG2, 0x07, 0x7);
+		snd_soc_update_bits(codec, DAC_ANANLOG3, 0x07, 0x7);
+	}
+
+	snd_dai_writel(((snd_dai_readl(I2S_CTL) & ~(0x3 << 11)) | (0x1 << 11)), I2S_CTL);
+	if (direct_drive_disable == 0) {
+		msleep(100);
+
+		/* antipop_VRO Resistant Connect */
+		snd_soc_update_bits(codec, DAC_ANANLOG2, 0x1 << 3, 0x1 << 3);
+		/* out stage en */
+		snd_soc_update_bits(codec, DAC_ANANLOG4, 0x1 << 15, 0x1 << 15);
+		/* DAC_OPVRO enable */
+		snd_soc_update_bits(codec, DAC_ANANLOG2, 0x1 << 4, 0x1 << 4);
+
+	} else {
+		msleep(100);
+		/* ramp Connect EN */
+		snd_soc_update_bits(codec, DAC_ANANLOG2, 0x3 << 9, 0x3 << 9);
+		ramp_undirect(0x80000000, 0x7ffffe00);
+	}
+	if (direct_drive_disable == 0) {
+		//INIT_DELAYED_WORK(&dwork_pa, pa_up_handler);
+		//schedule_delayed_work(&dwork_pa, msecs_to_jiffies(500));
+		msleep(500);//\B3\E4\B7\D6\C5\D4·\B7ŵ\E7
+		/* antipop_VRO Resistant disconnect */
+		snd_soc_update_bits(codec, DAC_ANANLOG2, 0x1 << 3, 0);
+
+	} else {
+
+		msleep(400);
+		snd_soc_update_bits(codec, DAC_ANANLOG4,
+			DAC_ANALOG4_PAOSEN_FR_FL, DAC_ANALOG4_PAOSEN_FR_FL);/* out stage en */
+		snd_soc_update_bits(codec, DAC_ANANLOG3,
+			DAC_ANALOG3_ATPLP2_FR_FL, 0);/* PA LOOP2 disable */
+		msleep(100);
+		snd_soc_update_bits(codec, DAC_ANANLOG2,
+			DAC_ANALOG2_ATP2CE, 0);/* ramp disconnect */
+	}
+
+	snd_dai_writel(0x0, I2STX_DAT);
+	snd_dai_writel(0x0, I2STX_DAT);
+	msleep(20);
+}
+static void atc2603a_pa_down(struct snd_soc_codec *codec)
+{
+	/* \B7\C7ֱ\C7\FDPA\CFµ\E7\B9\FD\B3\CC:
+	a)	\D2\F4\C1\BF\C9\E8Ϊ0
+	b)	PA \CA\E4\B3\F6\BC\B6disable\A3\ACLOOP2 EN, \B8\F4ֱ\B5\E7\C8\DDDischarge \BF\AA\C6\F4
+	c)	DAC \BF\AAʼ\B7\C5\D7\EEС\CA\FD\BE\DD,Delay \BA\F3\BF\AA\C6\F4ramp connect
+	d)	\B7\C5ramp\CA\FD\BE\DD,\B7\C5\CD\EA\BA\F3\B5ȴ\FDԼ600 ms
+	e)	\BCĴ\E6\C6\F7\B5\BDĬ\C8\CFֵ.
+	*/
+
+	if(hw_init_flag == true)
+	{
+		snd_soc_write(codec, DAC_VOLUMECTL0, 0xbebe);
+		snd_soc_update_bits(codec, DAC_ANANLOG4,
+				DAC_ANALOG4_PAOSEN_FR_FL, 0);//pa outout stage disable
+
+		if (direct_drive_disable == 0) {
+			snd_soc_update_bits(codec,
+				DAC_ANANLOG2, DAC_ANALOG2_DDATPR, DAC_ANALOG2_DDATPR);//connect the resistant
+			snd_soc_update_bits(codec,
+				DAC_ANANLOG2, DAC_ANALOG2_OPVROEN, 0);//disable
+		} else {
+			snd_soc_update_bits(codec, DAC_ANANLOG3,
+				DAC_ANALOG3_ATPLP2_FR_FL, DAC_ANALOG3_ATPLP2_FR_FL);/* PA LOOP2 en */
+			/* \B8\F4ֱ\B5\E7\C8\DDDischarge \BF\AA\C6\F4 */
+			snd_soc_update_bits(codec, DAC_ANANLOG2,
+			DAC_ANALOG2_PAVDC, DAC_ANALOG2_PAVDC);
+			snd_dai_writel(0x7ffffe00, I2STX_DAT);
+			snd_dai_writel(0x7ffffe00, I2STX_DAT);
+			msleep(100);
+
+			/*act_snd_writel(act_snd_readl(CO_DAC_ANALOG2) | (0x1 << 9),
+			CO_DAC_ANALOG2); ramp Connect EN */
+			snd_soc_update_bits(codec,
+				DAC_ANANLOG2, DAC_ANALOG2_ATP2CE, DAC_ANALOG2_ATP2CE);
+			ramp_undirect(0x80000000, 0x7ffffe00);
+			msleep(600);
+		}
+		snd_soc_write(codec, DAC_VOLUMECTL0, 0);
+		hw_init_flag = false;
+	}
+}
+
+void atc2603a_pa_up_all(struct snd_soc_codec *codec)
+{
+	int ret;
+
+	/* \B1\EAʶclassd\B5\C4״̬\CAǷ\F1\B1\BB\C9\E8\D6\C3Ϊ\B9̶\A8\B2\BB\D0\E8Ҫ\B8ı䣬ȱʡ\CA\C7TRUE */
+	static int classd_flag = 1;
+	struct clk *apll_clk;
+
+	module_clk_disable(MOD_ID_I2SRX);
+	module_clk_disable(MOD_ID_I2STX);
+	module_clk_enable(MOD_ID_I2SRX);
+	module_clk_enable(MOD_ID_I2STX);
+
+	/*for the fucked bug of motor shaking while startup,
+	because GPIOB(1) is mfp with I2S_LRCLK1*/
+	set_dai_reg_base(I2S_SPDIF_NUM);
+	snd_dai_writel(snd_dai_readl(GPIO_BOUTEN) | 2, GPIO_BOUTEN);
+
+	if(((snd_dai_readl(I2S_CTL) & 0x3) == 0x0)) {
+		/* disable i2s tx&rx */
+		snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x3 << 0), I2S_CTL);
+
+		/* avoid sound while reset fifo */
+		snd_soc_update_bits(codec,	DAC_ANANLOG1, 0x1 << 10, 0);
+
+		/* reset i2s rx&&tx fifo, avoid left & right channel wrong */
+		snd_dai_writel(snd_dai_readl(I2S_FIFOCTL) & ~(0x3 << 9) & ~0x3, I2S_FIFOCTL);
+		snd_dai_writel(snd_dai_readl(I2S_FIFOCTL) | (0x3 << 9) | 0x3, I2S_FIFOCTL);
+
+		/* this should before enable rx/tx, or after suspend, data may be corrupt */
+		snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x3 << 11),I2S_CTL);
+		snd_dai_writel(snd_dai_readl(I2S_CTL) | (0x1 << 11),I2S_CTL);
+		/* set i2s mode I2S_RX_ClkSel==1 */
+		snd_dai_writel(snd_dai_readl(I2S_CTL) | (0x1 << 10), I2S_CTL);
+
+		/* enable i2s rx/tx at the same time */
+		snd_dai_writel(snd_dai_readl(I2S_CTL) | 0x3, I2S_CTL);
+
+		apll_clk = clk_get(NULL, CLKNAME_AUDIOPLL);
+		clk_prepare(apll_clk);
+		clk_enable(apll_clk);
+
+		/* i2s rx 00: 2.0-Channel Mode */
+		snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x3 << 8), I2S_CTL);
+		snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x3 << 4), I2S_CTL);
+	}
+
+	/* enable i2s pad,i2s 4 wire pad all en */
+	/* EXTIRQ pad enable,ʹ\D6ж\CF\D0ź\C5\C4\DC\CB͵\BD\D6\F7\BF\D85201 */
+	snd_soc_update_bits_pmu(codec, ATC2603A_PAD_EN, 0x3901, 0x3901);
+
+	/* I2S: 2.0 Channel, SEL 4WIRE MODE */
+	snd_soc_update_bits(codec, AUDIOINOUT_CTL,0x1<<7, 0);
+	snd_soc_update_bits(codec, AUDIOINOUT_CTL, 0x3 << 5, 0x01 << 5);
+	snd_soc_update_bits(codec, AUDIOINOUT_CTL,0x1<<4, 0);
+	snd_soc_update_bits(codec, AUDIOINOUT_CTL,0x3<<2, 0);
+
+	/* bit5:2 I2S_DIN Multiplexing=I2S_Din,SEL 4WIRE MODE */
+	ret = snd_soc_update_bits_pmu(codec, ATC2603A_MFP_CTL0, 0x0f << 2, 0);//I2S,not GPIO
+
+	/* \B4\F2\BF\AA\C4ڲ\BF\B5Ļ\F9׼\C2˲\A8\C6\F7,\BC\F5С\B5\D7\D4룬\CC\E1\C9\FDaudio\D0\D4\C4\DC */
+	/*set_bdg_ctl();*/
+	/* for atc2603a those burn Efuse */
+	/* bit4:0 should not be changed, otherwise VREF isn't accurate */
+	ret = snd_soc_update_bits_pmu(codec, ATC2603A_PMU_BDG_CTL, 0x01 << 6, 0x01 << 6);
+	ret = snd_soc_update_bits_pmu(codec, ATC2603A_PMU_BDG_CTL, 0x01 << 5, 0);
+
+	pa_up(codec);
+
+	if (direct_drive_disable == 0) {
+		snd_soc_update_bits(codec, DAC_ANANLOG3,	0xa0f, 0xa0f);
+		snd_soc_update_bits(codec, DAC_ANANLOG2,	0x07, 0x3);
+		snd_soc_update_bits(codec, DAC_ANANLOG3,	0x07, 0x3);
+	}
+
+	if (classd_flag == 1) {
+		snd_soc_update_bits(codec, DAC_ANANLOG3, 0x1 << 9, 0x1 << 9);
+		snd_soc_update_bits(codec, DAC_ANANLOG2, 0x1 << 15, 0x1 << 15);
+		snd_soc_update_bits(codec, DAC_ANANLOG3, 0x1 << 13, 0x1 << 13);
+	}
+
+	//after pa_up, the regs status should be the same as outstandby?
+	snd_soc_update_bits(codec, DAC_ANANLOG1, DAC_ANALOG1_DACFL_FRMUTE, 0);//mute
+	snd_soc_update_bits(codec, AUDIOINOUT_CTL,	0x01 << 1, 0);//I2S input disable
+	snd_soc_update_bits(codec, DAC_ANANLOG1, DAC_ANALOG1_PASW, DAC_ANALOG1_PASW);//1.6v
+	snd_soc_update_bits(codec, DAC_FILTERCTL0, 0x03, 2);
+	snd_soc_update_bits(codec, DAC_ANANLOG1, 0x3f, 40);//
+	snd_soc_write(codec, DAC_VOLUMECTL0, 0xb5b5);//0//0xbebe
+
+	if (direct_drive_disable == 0) {
+	}
+	else {
+		snd_soc_write(codec, DAC_ANANLOG2, 0x8400);
+		snd_soc_write(codec, DAC_ANANLOG3, 0xaa0b);
+	}
+
+	snd_dai_writel(snd_dai_readl(I2S_CTL) & ~0x3, I2S_CTL);
+	snd_dai_writel(snd_dai_readl(I2S_FIFOCTL) & ~(0x3 << 9) & ~0x3, I2S_FIFOCTL);
+
+
+}
+EXPORT_SYMBOL_GPL(atc2603a_pa_up_all);
+
+static int atc2603a_audio_set_dai_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+
+	if (mute) {
+		snd_soc_update_bits(codec, DAC_ANANLOG1,
+			DAC_ANALOG1_DACFL_FRMUTE, 0);
+	} else {
+		snd_soc_update_bits(codec, DAC_ANANLOG1,
+			DAC_ANALOG1_DACFL_FRMUTE,
+			DAC_ANALOG1_DACFL_FRMUTE);
+	}
+
+	return 0;
+}
+static int atc2603a_audio_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	/* enable the atc2603a i2s input function */
+	struct snd_soc_codec *codec = dai->codec;
+
+	if(hw_init_flag == false) {
+		atc2603a_pa_up_all(codec);
+		hw_init_flag = true;
+	}
+	snd_soc_update_bits(codec, AUDIOINOUT_CTL, 0x03 << 5, 0x01 << 5);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (direct_drive_disable == 0) {
+
+		} else {
+			snd_soc_write(codec,	DAC_ANANLOG2,	0x8400);
+			snd_soc_write(codec,	DAC_ANANLOG3,	0xaa0b);
+		}
+
+		snd_soc_update_bits(codec,
+			AUDIOINOUT_CTL, 0x01 << 1, 0x01 << 1);
+		snd_soc_update_bits(codec,
+			DAC_ANANLOG4, 0x03 << 6, 0x03 << 6);
+	} else {
+			snd_soc_update_bits(codec,
+			ADC1_CTL, 0x3 << 7, 0x3 << 7);//VRDA0EN | VRDA1EN
+		snd_soc_update_bits(codec,
+			ADC0_HPFCTL, 0x3 << 0, 0x3 << 0);//adc0 hpf disable
+		snd_soc_update_bits(codec,
+			AUDIOINOUT_CTL, 0x01 << 8, 0x01 << 8);
+	}
+	atc2603a_open_count++;
+
+	return 0;
+}
+
+static int atc2603a_audio_hw_free(
+	struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	snd_dbg("atc2603a_audio_hw_free\n");
+	/* disable the atc2603a i2s input function */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		snd_soc_update_bits(codec,
+				AUDIOINOUT_CTL,
+				0x01 << 1, 0);
+	} else {
+		snd_soc_update_bits(codec,
+				AUDIOINOUT_CTL,
+				0x01 << 8, 0);
+	}
+	return 0;
+}
+
+static int atc2603a_audio_prepare(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	/* nothing should to do here now */
+	return 0;
+}
+
+static int atc2603a_audio_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = dai->codec;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+
+	snd_soc_update_bits(codec, DAC_FILTERCTL0, 0x03, 2);
+	/* we set the i2s 2 channel-mode by default */
+	snd_soc_update_bits(codec, AUDIOINOUT_CTL, 0x03 << 2, 0);
+
+	return 0;
+}
+
+static int atc2603a_audio_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	/* nothing should to do here now */
+	return 0;
+}
+
+static void atc2603a_power_down(struct snd_soc_codec *codec)
+{
+	atc2603a_pa_down(codec);
+}
+
+static int atc2603a_set_bias_level(struct snd_soc_codec *codec,
+		                        enum snd_soc_bias_level level)
+{
+#if 0
+	int ret;
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		snd_dbg("%s:  SND_SOC_BIAS_ON\n", __func__);
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		snd_dbg("%s:  SND_SOC_BIAS_PREPARE\n", __func__);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		#ifdef SND_SOC_BIAS_DEBUG
+		snd_dbg("%s:  SND_SOC_BIAS_STANDBY\n", __func__);
+		#endif
+
+		if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
+			codec->cache_only = false;
+			codec->cache_sync = 1;
+			ret = snd_soc_cache_sync(codec);
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_dbg("%s:  SND_SOC_BIAS_OFF\n", __func__);
+		break;
+
+	default:
+		break;
+	}
+
+	codec->dapm.bias_level = level;
+#endif
+	return 0;
+}
+
+static void reenable_audio_block(struct snd_soc_codec *codec)
+{
+	snd_soc_update_bits_pmu(codec,
+		ATC2603A_CMU_DEVRST, 0x01 << 4, 0);//audio block reset
+
+	snd_soc_update_bits_pmu(codec, ATC2603A_CMU_DEVRST,
+		0x01 << 10, 0x01 << 10);//SCLK to Audio Clock Enable Control
+	snd_soc_update_bits_pmu(codec,
+		ATC2603A_CMU_DEVRST, 0x01 << 4, 0x01 << 4);
+
+}
+
+static int atc2603a_probe(struct snd_soc_codec *codec)
+{
+	snd_dbg("atc2603a_probe!\n");
+	if (codec == NULL)
+		snd_dbg("NULL codec \r\n");
+
+	snd_dbg("codec->name = %s\r\n", codec->component.name);
+
+	atc2603a_codec = codec;
+
+	hw_init_flag = false;
+	reenable_audio_block(codec);
+
+	atc2603a_pa_up_all(codec);
+	hw_init_flag = true;
+
+
+	codec->dapm.bias_level = SND_SOC_BIAS_STANDBY;
+
+	return 0;
+}
+
+static int atc2603a_remove(struct snd_soc_codec *codec)
+{
+	atc2603a_pa_down(codec);
+	return 0;
+}
+
+static int atc2603a_suspend(struct snd_soc_codec *codec)
+{
+#if 0
+	atc2603a_power_down(codec);
+	atc2603a_set_bias_level(codec, SND_SOC_BIAS_OFF);
+#endif
+	return 0;
+}
+
+static int atc2603a_resume(struct snd_soc_codec *codec)
+{
+	reenable_audio_block(codec);
+#if 0
+	atc2603a_pa_up_all(codec);
+	hw_init_flag = true;
+#endif
+	atc2603a_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	return 0;
+}
+
+static void atc2603a_audio_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+#if 0
+	struct snd_soc_codec *codec = dai->codec;
+
+	atc2603a_power_down(codec);
+	atc2603a_set_bias_level(codec, SND_SOC_BIAS_OFF);
+#endif
+	return;
+}
+
+#define ATC2603A_RATES SNDRV_PCM_RATE_8000_192000
+#define ATC2603A_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+	SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+struct snd_soc_dai_ops atc2603a_aif_dai_ops = {
+	.shutdown = atc2603a_audio_shutdown,
+	.hw_params = atc2603a_audio_hw_params,
+	.hw_free = atc2603a_audio_hw_free,
+	.prepare = atc2603a_audio_prepare,
+	.set_fmt = atc2603a_audio_set_dai_fmt,
+	.set_sysclk = atc2603a_audio_set_dai_sysclk,
+	.digital_mute = atc2603a_audio_set_dai_digital_mute,
+};
+
+struct snd_soc_dai_driver codec_atc2603a_dai[] = {
+	{
+		.name = "atc2603a-dai",
+		.id = ATC2603A_AIF,
+		.playback = {
+			.stream_name = "AIF Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = ATC2603A_RATES,
+			.formats = ATC2603A_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF Capture",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = ATC2603A_RATES,
+			.formats = ATC2603A_FORMATS,
+		},
+		.ops = &atc2603a_aif_dai_ops,
+	},
+};
+
+static struct snd_soc_codec_driver soc_codec_atc2603a = {
+	.probe = atc2603a_probe,
+	.remove = atc2603a_remove,
+
+	.suspend = atc2603a_suspend,
+	.resume = atc2603a_resume,
+	//.set_bias_level = atc2603a_set_bias_level,
+	.idle_bias_off = true,
+
+	.reg_cache_size = (AGC1_CTL2 + 1),
+	.reg_word_size = sizeof(u16),
+	.reg_cache_default = atc2603a_reg,
+	.reg_cache_step = 1,
+
+	.controls = atc2603a_snd_controls,
+	.num_controls = ARRAY_SIZE(atc2603a_snd_controls),
+	.dapm_widgets = atc2603a_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(atc2603a_dapm_widgets),
+	.dapm_routes = atc2603a_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(atc2603a_dapm_routes),
+	.write = atc2603a_write,
+	.read = atc2603a_read,
+};
+
+static ssize_t error_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int cnt;
+
+	cnt = sprintf(buf, "%d\n(Note: 1: open, 0:close)\n", error_switch);
+	return cnt;
+}
+
+static ssize_t error_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int cnt, tmp;
+	cnt = sscanf(buf, "%d", &tmp);
+	switch (tmp) {
+	case 0:
+	case 1:
+		error_switch = tmp;
+		break;
+	default:
+		printk(KERN_ERR"invalid input\n");
+		break;
+	}
+	return count;
+}
+
+static ssize_t debug_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int cnt;
+
+	cnt = sprintf(buf, "%d\n(Note: 1: open, 0:close)\n", debug_switch);
+	return cnt;
+}
+
+static ssize_t debug_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	int cnt, tmp;
+	cnt = sscanf(buf, "%d", &tmp);
+	switch (tmp) {
+	case 0:
+	case 1:
+		debug_switch = tmp;
+		break;
+	default:
+		printk(KERN_INFO"invalid input\n");
+		break;
+	}
+	return count;
+}
+
+static struct device_attribute atc2603a_attr[] = {
+	__ATTR(error, S_IRUSR | S_IWUSR, error_show, error_store),
+	__ATTR(debug, S_IRUSR | S_IWUSR, debug_show, debug_store),
+};
+
+int atc2603a_audio_get_pmu_status(void)
+{
+	return atc2603a_ictype;
+}
+
+EXPORT_SYMBOL_GPL(atc2603a_audio_get_pmu_status);
+
+static int atc2603a_platform_probe(struct platform_device *pdev)
+{
+	int i;
+	int ret = 0;
+
+/*
+	dn = of_find_compatible_node(NULL, NULL, "actions,atm7039c-i2s");
+	if (!dn) {
+		snd_err("Fail to get device_node actions,atm7039c-i2s\r\n");
+		//goto of_get_failed;
+	}
+*/
+	
+	/*FIXME: what if error in second or third loop*/
+/*
+	for(i=0; i<2; i++) 
+	{
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		if (!res) {
+			snd_err("no memory resource i=%d\n", i);
+			return -ENODEV;
+		}
+
+		if (!devm_request_mem_region (&pdev->dev, res->start,
+					resource_size(res), "gl5203-audio-i2s")) {
+			snd_err("Unable to request register region\n");
+			return -EBUSY;
+		}
+
+		codec_res.base[i] = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+		if (codec_res.base[i] == NULL) {
+			snd_err("Unable to ioremap register region\n");
+			return -ENXIO;
+		}
+		
+		snd_err("it's ok %d\n", i);
+	}
+*/
+
+
+	for (i = 0; i < ARRAY_SIZE(atc2603a_attr); i++) {
+		snd_err("add file!\r\n");
+		ret = device_create_file(&pdev->dev, &atc2603a_attr[i]);
+	}
+
+	atc260x = dev_get_drvdata(pdev->dev.parent);
+	platform_set_drvdata(pdev, atc260x);
+
+	atc2603a_ictype = ATC260X_ICTYPE_2603A;
+
+	pdev->dev.init_name = "atc260x-audio";
+	snd_err("register codec\r\n");
+	return snd_soc_register_codec(&pdev->dev, &soc_codec_atc2603a,
+			codec_atc2603a_dai, ARRAY_SIZE(codec_atc2603a_dai));
+}
+
+static int atc2603a_platform_remove(struct platform_device *pdev)
+{
+	int i = 0;
+	struct device *dev;
+
+	dev = bus_find_device_by_name(&platform_bus_type, NULL, "atc260x-audio");
+	if (dev) {
+		for (i = 0; i < ARRAY_SIZE(atc2603a_attr); i++) {
+			snd_err("remove file!\r\n");
+			device_remove_file(dev, &atc2603a_attr[i]);
+		}
+	} else {
+		snd_err("Find platform device atc2603a-audio failed!\r\n");
+		return -ENODEV;
+	}
+
+	snd_soc_unregister_codec(&pdev->dev);
+	return 0;
+}
+
+static void atc2603a_platform_shutdown(struct platform_device *pdev)
+{
+	gpio_direction_output(speaker_gpio_num, 0);
+	snd_soc_write(atc2603a_codec, DAC_VOLUMECTL0, 0xBEBE);
+	snd_soc_write(atc2603a_codec, DAC_ANANLOG1, 0x0);
+	snd_soc_write(atc2603a_codec, DAC_ANANLOG3, 0x8B0B);
+	snd_soc_write(atc2603a_codec, DAC_ANANLOG4, 0x08C0);
+	snd_soc_write(atc2603a_codec, DAC_ANANLOG2, 0x0100);
+	snd_soc_update_bits(atc2603a_codec,
+			AUDIOINOUT_CTL,
+			0x01 << 1, 0);
+	atc2603a_power_down(atc2603a_codec);
+	return;
+}
+
+static const struct of_device_id atc2603a_audio_of_match[]= {
+	{.compatible = "actions,atc2603a-audio",},
+	{}
+};
+MODULE_DEVICE_TABLE(of, atc2603a_audio_of_match);
+
+static struct platform_driver atc2603a_platform_driver = {
+	.probe      = atc2603a_platform_probe,
+	.remove     = atc2603a_platform_remove,
+	.driver     = {
+		.name   = "atc2603a-audio",
+		.owner  = THIS_MODULE,
+		.of_match_table = atc2603a_audio_of_match,
+	},
+	.shutdown	= atc2603a_platform_shutdown,
+};
+
+static int atc2603a_get_cfg(void)
+{
+	u32 ret = 1;
+	struct device_node *dn;
+
+	dn = of_find_compatible_node(NULL, NULL, audio_device_node);
+	if (!dn) {
+		snd_err("Fail to get device_node\r\n");
+		goto of_get_failed;
+	}
+
+	ret = of_property_read_u32(dn, snd_earphone_output_mode,
+		&audio_hw_cfg.earphone_output_mode);
+	if (ret) {
+		snd_err("Fail to get snd_earphone_output_mode\r\n");
+		goto of_get_failed;
+	}
+
+	ret = of_property_read_u32(dn, snd_mic_num,
+		&audio_hw_cfg.mic_num);
+	if (ret) {
+		snd_err("Fail to get snd_mic_num\r\n");
+		goto of_get_failed;
+	}
+
+	ret = of_property_read_u32_array(dn, snd_mic0_gain,
+		audio_hw_cfg.mic0_gain, 2);
+	if (ret) {
+		snd_err("Fail to get snd_mic_gain\r\n");
+		goto of_get_failed;
+	}
+
+	ret = of_property_read_u32_array(dn, snd_speaker_gain,
+		audio_hw_cfg.speaker_gain, 2);
+	if (ret) {
+		snd_err("Fail to get snd_speaker_gain\r\n");
+		goto of_get_failed;
+	}
+
+	ret = of_property_read_u32_array(dn, snd_earphone_gain,
+		audio_hw_cfg.earphone_gain, 2);
+	if (ret) {
+		snd_err("Fail to get snd_earphone_gain\r\n");
+		goto of_get_failed;
+	}
+
+/*
+	ret = of_property_read_u32(dn, snd_speaker_volume,
+		&audio_hw_cfg.speaker_volume);
+	if (ret) {
+		snd_err("Fail to get snd_speaker_volume\r\n");
+		goto of_get_failed;
+	}
+
+	ret = of_property_read_u32(dn, snd_earphone_volume,
+		&audio_hw_cfg.earphone_volume);
+	if (ret) {
+		snd_err("Fail to get snd_earphone_volume\r\n");
+		goto of_get_failed;
+	}
+
+	ret = of_property_read_u32(dn, snd_earphone_detect_mode,
+		&audio_hw_cfg.earphone_detect_mode);
+	if (ret) {
+		snd_err("Fail to get snd_earphone_detect_mode\r\n");
+		goto of_get_failed;
+	}
+*/
+	audio_hw_cfg.speaker_volume = 0x28;
+	audio_hw_cfg.earphone_volume = 0x28;
+	audio_hw_cfg.earphone_detect_mode = 0;
+	
+
+	speaker_gpio_num = of_get_named_gpio_flags(dn, speaker_ctrl_name, 0, NULL);
+	if (speaker_gpio_num < 0) {
+		snd_err("get gpio[%s] fail\r\n", speaker_ctrl_name);
+	}
+
+	snd_err("Success to get device_node\r\n");
+	return 0;
+of_get_failed:
+	return ret;
+}
+
+static void atc2603a_dump_cfg(void)
+{
+#if 0
+	printk(KERN_ERR"earphone_detect_mode = %d\r\n",audio_hw_cfg.earphone_detect_mode);
+	printk(KERN_ERR"earphone_gain[0] = %d\r\n",audio_hw_cfg.earphone_gain[0]);
+	printk(KERN_ERR"earphone_gain[1] = %d\r\n",audio_hw_cfg.earphone_gain[1]);
+	printk(KERN_ERR"speaker_gain[0] = %d\r\n",audio_hw_cfg.speaker_gain[0]);
+	printk(KERN_ERR"speaker_gain[1] = %d\r\n",audio_hw_cfg.speaker_gain[1]);
+	printk(KERN_ERR"mic0_gain[0] = %d\r\n",audio_hw_cfg.mic0_gain[0]);
+	printk(KERN_ERR"mic0_gain[1] = %d\r\n",audio_hw_cfg.mic0_gain[1]);
+	printk(KERN_ERR"earphone_volume = %d\r\n",audio_hw_cfg.earphone_volume);
+	printk(KERN_ERR"speaker_volume = %d\r\n",audio_hw_cfg.speaker_volume);
+	printk(KERN_ERR"earphone_output_mode = %d\r\n",audio_hw_cfg.earphone_output_mode);
+	printk(KERN_ERR"mic_num = %d\r\n",audio_hw_cfg.mic_num);
+#endif
+}
+
+static int atc2603a_pa_down_notifier(struct notifier_block *notifier,
+				       unsigned long pm_event, void *v)
+{
+	mutex_lock(&atc2603a_pa_down_lock);
+
+	switch (pm_event) {
+
+		case PM_SUSPEND_PREPARE:
+			user_lock = 1;
+				snd_soc_update_bits(atc2603a_codec,
+				AUDIOINOUT_CTL,
+				0x01 << 1, 1);
+			atc2603a_power_down(atc2603a_codec);
+				snd_soc_update_bits(atc2603a_codec,
+				AUDIOINOUT_CTL,
+				0x01 << 1, 0);
+			break;
+
+		case PM_POST_SUSPEND:
+			user_lock = 0;
+			break;
+	}
+	mutex_unlock(&atc2603a_pa_down_lock);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block atc2603a_pa_down_nb = {
+	.notifier_call = atc2603a_pa_down_notifier,
+};
+
+static int __init atc2603a_init(void)
+{
+	u32 ret = 0;
+
+	printk("atc2603a_init\n");
+
+	ret = atc2603a_get_cfg();
+	if (ret){
+		snd_err("audio get cfg failed!\r\n");
+		goto audio_get_cfg_failed;
+	}
+
+	atc2603a_dump_cfg();
+
+	direct_drive_disable = audio_hw_cfg.earphone_output_mode;
+
+	ret = platform_driver_register(&atc2603a_platform_driver);
+	if(ret){
+		snd_err("platform_driver_register failed!\r\n");
+		goto platform_driver_register_failed;
+	}
+
+	//dev = bus_find_device_by_name(&platform_bus_type, NULL, "atc260x-audio");
+
+
+	register_pm_notifier(&atc2603a_pa_down_nb);
+
+	return 0;
+platform_driver_register_failed:
+audio_get_cfg_failed:
+	return ret;
+}
+
+static void __exit atc2603a_exit(void)
+{
+	platform_driver_unregister(&atc2603a_platform_driver);
+}
+
+module_init(atc2603a_init);
+module_exit(atc2603a_exit);
+
+
+MODULE_AUTHOR("sall.xie <sall.xie at actions-semi.com>");
+MODULE_DESCRIPTION("ATC2603A AUDIO module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/atc260x/atc2603a-codec/atc2603a-audio-regs.h b/sound/soc/atc260x/atc2603a-codec/atc2603a-audio-regs.h
new file mode 100755
index 0000000..7acf8f9
--- /dev/null
+++ b/sound/soc/atc260x/atc2603a-codec/atc2603a-audio-regs.h
@@ -0,0 +1,395 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2009 Actions Semi Inc.
+ */
+
+#ifndef __ATV5302_AUDIO_REGS_H__
+#define __ATV5302_AUDIO_REGS_H__
+
+/* AUDIOINOUT_CTL */
+#define AUDIOINOUT_CTL_INEN		(0x1 << 1)
+#define AUDIOINOUT_CTL_IMD(x)		(((x) & 0x3) << 2)
+#define AUDIOINOUT_CTL_LB		(0x1 << 4)
+#define AUDIOINOUT_CTL_IMS(x)		(((x) & 0x3) << 5)
+#define AUDIOINOUT_CTL_OMD		(0x1 << 7)
+#define AUDIOINOUT_CTL_OEN		(0x1 << 8)
+#define AUDIOINOUT_CTL_OCIEN		(0x1 << 9)
+#define AUDIOINOUT_CTL_OHSCIEN		(0x1 << 10)
+#define AUDIOINOUT_CTL_MDD		(0x1 << 11)
+#define AUDIOINOUT_CTL_EIDR		(0x1 << 12)
+
+/* DAC_FILTERCTL0 */
+#define DAC_FILTERCTL0_DOSRSFL_FR(x)	(((x) & 0x3) << 0)
+#define DAC_FILTERCTL0_DOSRSSW_C(x)	(((x) & 0x3) << 2)
+#define DAC_FILTERCTL0_DOSRSSL_SR(x)	(((x) & 0x3) << 4)
+#define DAC_FILTERCTL0_DOSRSSBL_SBR(x)	(((x) & 0x3) << 6)
+#define DAC_FILTERCTL0_DISRS		(0x1 << 8)
+#define DAC_FILTERCTL0_DEDFL_FR		(0x1 << 9)
+#define DAC_FILTERCTL0_DEDSW_C		(0x1 << 10)
+#define DAC_FILTERCTL0_DEDSL_SR		(0x1 << 11)
+#define DAC_FILTERCTL0_DEDSBL_SBR	(0x1 << 12)
+
+/* DAC_FILTERCTL1 */
+#define DAC_FILTERCTL1_DBWFL_FR(x)	(((x) & 0x3) << 0)
+#define DAC_FILTERCTL1_DBWSW_C(x)	(((x) & 0x3) << 2)
+#define DAC_FILTERCTL1_DBWSL_SR(x)	(((x) & 0x3) << 4)
+#define DAC_FILTERCTL1_DBWSBL_SBR(x)	(((x) & 0x3) << 6)
+
+/* DAC_DIGITALCTL */
+#define DAC_DIGITALCTL_DEFL		(0x1 << 0)
+#define DAC_DIGITALCTL_DEFL_SFT         (0)
+#define DAC_DIGITALCTL_DEFR		(0x1 << 1)
+#define DAC_DIGITALCTL_DEFR_SFT		(1)
+#define DAC_DIGITALCTL_DESW		(0x1 << 2)
+#define DAC_DIGITALCTL_DEC		(0x1 << 3)
+#define DAC_DIGITALCTL_DESL		(0x1 << 4)
+#define DAC_DIGITALCTL_DESR		(0x1 << 5)
+#define DAC_DIGITALCTL_DESBL		(0x1 << 6)
+#define DAC_DIGITALCTL_DESBR		(0x1 << 7)
+#define DAC_DIGITALCTL_DMFL		(0x1 << 8)
+#define DAC_DIGITALCTL_DMFR		(0x1 << 9)
+#define DAC_DIGITALCTL_DMSW		(0x1 << 10)
+#define DAC_DIGITALCTL_DMC		(0x1 << 11)
+#define DAC_DIGITALCTL_DMSL		(0x1 << 12)
+#define DAC_DIGITALCTL_DMSR		(0x1 << 13)
+#define DAC_DIGITALCTL_DMSBL		(0x1 << 14)
+#define DAC_DIGITALCTL_DMSBR		(0x1 << 15)
+
+/* DAC_VOLUMECTL0 */
+#define DAC_VOLUMECTL0_DACFL_VOLUME(x)	(((x) & 0xff) << 0)
+#define DAC_VOLUMECTL0_DACFL_VOLUME_SFT	(0)
+#define DAC_VOLUMECTL0_DACFR_VOLUME(x)	(((x) & 0xff) << 8)
+#define DAC_VOLUMECTL0_DACFR_VOLUME_SFT	(8)
+
+/* DAC_VOLUMECTL1 */
+#define DAC_VOLUMECTL1_DACSW_VOLUME(x)	(((x) & 0xff) << 0)
+#define DAC_VOLUMECTL1_DACC_VOLUME(x)	(((x) & 0xff) << 8)
+
+/* DAC_VOLUMECTL2 */
+#define DAC_VOLUMECTL2_DACSL_VOLUME(x)	(((x) & 0xff) << 0)
+#define DAC_VOLUMECTL2_DACSR_VOLUME(x)	(((x) & 0xff) << 8)
+
+/* DAC_VOLUMECTL3 */
+#define DAC_VOLUMECTL3_DACSBL_VOLUME(x)	(((x) & 0xff) << 0)
+#define DAC_VOLUMECTL3_DACSBR_VOLUME(x)	(((x) & 0xff) << 8)
+
+/* DAC_ANALOG0 */
+#define DAC_ANALOG0_OPGIB(x)		(((x) & 0x7) << 0)
+#define DAC_ANALOG0_KFEN		(0x1 << 3)
+#define DAC_ANALOG0_OPVBIB(x)		(((x) & 0x3) << 4)
+#define DAC_ANALOG0_OPDTSIB(x)		(((x) & 0x3) << 6)
+#define DAC_ANALOG0_OPDAIB(x)		(((x) & 0x7) << 8)
+#define DAC_ANALOG0_OPDAVB(x)		(((x) & 0x3) << 12)
+#define DAC_ANALOG0_PAIB(x)		(((x) & 0x3) << 14)
+
+/* DAC_ANALOG1 */
+#define DAC_ANALOG1_VOLUME(x)		(((x) & 0x3f) << 0)
+#define DAC_ANALOG1_VOLUME_SFT		(0)
+#define DAC_ANALOG1_PASW		(0x1 << 6)
+#define DAC_ANALOG1_PASW_SFT		(6)
+#define DAC_ANALOG1_ZERODT		(0x1 << 7)
+#define DAC_ANALOG1_PAIQ(x)		(((x) & 0x3) << 8)
+#define DAC_ANALOG1_DACFL_FRMUTE	(0x1 << 10)
+#define DAC_ANALOG1_DACFL_FRMUTE_SFT	(10)
+#define DAC_ANALOG1_DACSW_CMUTE		(0x1 << 11)
+#define DAC_ANALOG1_DACSL_SRMUTE	(0x1 << 12)
+#define DAC_ANALOG1_DACSBL_SBRMUTE	(0x1 << 13)
+#define DAC_ANALOG1_DACFMMUTE		(0x1 << 14)
+#define DAC_ANALOG1_DACFMMUTE_SFT	(14)
+#define DAC_ANALOG1_DACMICMUTE		(0x1 << 15)
+#define DAC_ANALOG1_DACMICMUTE_SFT	(15)
+
+/* DAC_ANALOG2 */
+#define DAC_ANALOG2_OPVROOSIB(x)	(((x) & 0x7) << 0)
+#define DAC_ANALOG2_DDATPR		(0x1 << 3)
+#define DAC_ANALOG2_OPVROEN		(0x1 << 4)
+#define DAC_ANALOG2_DDOVV		(0x1 << 5)
+#define DAC_ANALOG2_CLDMIX(x)		(((x) & 0x3) << 6)
+#define DAC_ANALOG2_PAVDC		(0x1 << 8)
+#define DAC_ANALOG2_ATP2CE		(0x1 << 9)
+#define DAC_ANALOG2_P2IB		(0x1 << 10)
+#define DAC_ANALOG2_DACI		(0x1 << 11)
+#define DAC_ANALOG2_ZERODETECT		(0x1 << 15)
+
+/* DAC_ANALOG3 */
+#define DAC_ANALOG3_OPVROIB(x)		(((x) & 0x7) << 0)
+#define DAC_ANALOG3_OPCM1IB(x)		(((x) & 0x3) << 3)
+#define DAC_ANALOG3_ATPLP2_SBR_SBL	(0x1 << 5)
+#define DAC_ANALOG3_ATPLP2_SR_SL	(0x1 << 6)
+#define DAC_ANALOG3_ATPLP2_SW_C		(0x1 << 7)
+#define DAC_ANALOG3_ATPLP2_FR_FL	(0x1 << 8)
+#define DAC_ANALOG3_BIASEN		(0x1 << 9)
+#define DAC_ANALOG3_EIDEN		(0x1 << 10)
+#define DAC_ANALOG3_VLCHD		(0x1 << 13)
+#define DAC_ANALOG3_OVLS		(0x1 << 14)
+#define DAC_ANALOG3_EIDS		(0x1 << 15)
+
+/* DAC_ANALOG4 */
+#define DAC_ANALOG4_DACEN_SBR		(0x1 << 0)
+#define DAC_ANALOG4_DACEN_SBL		(0x1 << 1)
+#define DAC_ANALOG4_DACEN_SR		(0x1 << 2)
+#define DAC_ANALOG4_DACEN_SL		(0x1 << 3)
+#define DAC_ANALOG4_DACEN_C		(0x1 << 4)
+#define DAC_ANALOG4_DACEN_SW		(0x1 << 5)
+#define DAC_ANALOG4_DACEN_FR		(0x1 << 6)
+#define DAC_ANALOG4_DACEN_FR_SFT	(6)
+#define DAC_ANALOG4_DACEN_FL		(0x1 << 7)
+#define DAC_ANALOG4_DACEN_FL_SFT	(7)
+#define DAC_ANALOG4_PAEN_SBR_SBL	(0x1 << 8)
+#define DAC_ANALOG4_PAEN_SR_SL		(0x1 << 9)
+#define DAC_ANALOG4_PAEN_SW_C		(0x1 << 10)
+#define DAC_ANALOG4_PAEN_FR_FL		(0x1 << 11)
+#define DAC_ANALOG4_PAEN_FR_FL_SFT	(11)
+#define DAC_ANALOG4_PAOSEN_SBR_SBL	(0x1 << 12)
+#define DAC_ANALOG4_PAOSEN_SR_SL	(0x1 << 13)
+#define DAC_ANALOG4_PAOSEN_SW_C		(0x1 << 14)
+#define DAC_ANALOG4_PAOSEN_FR_FL	(0x1 << 15)
+#define DAC_ANALOG4_PAOSEN_FR_FL_SFT	(15)
+
+/* CLASSD_CTL0 */
+#define CLASSD_CTL0_CLD1EN		(0x1 << 0)
+#define CLASSD_CTL0_CLD2EN		(0x1 << 1)
+#define CLASSD_CTL0_MUTE		(0x1 << 2)
+#define CLASSD_CTL0_PEN			(0x1 << 3)
+#define CLASSD_CTL0_FBEN		(0x1 << 4)
+#define CLASSD_CTL0_OTPEN		(0x1 << 5)
+#define CLASSD_CTL0_SCEN		(0x1 << 6)
+#define CLASSD_CTL0_SSEN		(0x1 << 7)
+#define CLASSD_CTL0_SABD		(0x1 << 8)
+#define CLASSD_CTL0_NCLPEN		(0x1 << 9)
+#define CLASSD_CTL0_DBGIN		(0x1 << 10)
+#define CLASSD_CTL0_GAIN		(0x1 << 11)
+#define CLASSD_CTL0_OTPR(x)		(((x) & 0x7) << 13)
+
+/* CLASSD_CTL1 */
+#define CLASSD_CTL1_IBREG(x)		(((x) & 0xf) << 0)
+#define CLASSD_CTL1_EDG(x)		(((x) & 0x3) << 4)
+#define CLASSD_CTL1_NCLPR(x)		(((x) & 0x3) << 6)
+#define CLASSD_CTL1_FSEN(x)		(((x) & 0x3) << 8)
+#define CLASSD_CTL1_SSR(x)		(((x) & 0x3) << 10)
+
+/* CLASSD_CTL2 */
+#define CLASSD_CTL2_VREC(x)		(((x) & 0x3) << 0)
+#define CLASSD_CTL2_RTIME(x)		(((x) & 0x7) << 6)
+#define CLASSD_CTL2_ATIME(x)		(((x) & 0x7) << 9)
+#define CLASSD_CTL2_SCWN1		(0x1 << 12)
+#define CLASSD_CTL2_OHWN1		(0x1 << 13)
+#define CLASSD_CTL2_SCWN2		(0x1 << 14)
+#define CLASSD_CTL2_OHWN2		(0x1 << 15)
+
+
+/* ADC0_DIGITALCTL */
+#define ADC0_DIGITALCTL_DMREN		(0x1 << 0)
+#define ADC0_DIGITALCTL_DMLEN		(0x1 << 1)
+#define ADC0_DIGITALCTL_DRFS		(0x1 << 2)
+#define ADC0_DIGITALCTL_VREN		(0x1 << 3)
+#define ADC0_DIGITALCTL_DCEN		(0x1 << 4)
+#define ADC0_DIGITALCTL_DCD			(0x1 << 5)
+#define ADC0_DIGITALCTL_ADGC0(x)	(((x) & 0xf) << 6)
+#define ADC0_DIGITALCTL_ADGC0_SFT	(6)
+#define ADC0_DIGITALCTL_AD0DEN		(0x1 << 10)
+#define ADC0_DIGITALCTL_AD0DLR		(0x1 << 11)
+
+/* ADC0_HPFCTL */
+#define ADC0_HPFCTL_HPF0REN		(0x1 << 0)
+#define ADC0_HPFCTL_HPF0LEN		(0x1 << 1)
+#define ADC0_HPFCTL_HPF0DW		(0x1 << 2)
+#define ADC0_HPFCTL_WNHPF0CUT(x)	(((x) & 0x7) << 3)
+#define ADC0_HPFCTL_SRSEL0(x)		(((x) & 0x3) << 6)
+
+/* ADC0_CTL */
+#define ADC0_CTL_ADCIS(x)		(((x) & 0x3) << 0)
+#define ADC0_CTL_ADCIS_SFT              (0)
+#define ADC0_CTL_AD0REN			(0x1 << 2)
+#define ADC0_CTL_AD0REN_SFT		(2)
+#define ADC0_CTL_AD0LEN			(0x1 << 3)
+#define ADC0_CTL_AD0LEN_SFT		(3)
+#define ADC0_CTL_MIC0FDSE		(0x1 << 4)
+#define ADC0_CTL_MIC0FDSE_SFT		(4)
+#define ADC0_CTL_MIC0REN		(0x1 << 5)
+#define ADC0_CTL_MIC0REN_SFT		(5)
+#define ADC0_CTL_MIC0LEN		(0x1 << 6)
+#define ADC0_CTL_MIC0LEN_SFT		(6)
+#define ADC0_CTL_VMICEXST(x)		(((x) & 0x3) << 7)
+#define ADC0_CTL_VMICEXST_SFT		(7)
+#define ADC0_CTL_VMICEXEN		(0x1 << 9)
+#define ADC0_CTL_VMICEXEN_SFT		(9)
+#define ADC0_CTL_FMGAIN(x)		(((x) & 0x7) << 10)
+#define ADC0_CTL_FMGAIN_SFT		(10)
+#define ADC0_CTL_FMREN			(0x1 << 13)
+#define ADC0_CTL_FMREN_SFT		(13)
+#define ADC0_CTL_FMLEN			(0x1 << 14)
+#define ADC0_CTL_FMLEN_SFT		(14)
+#define ADC0_CTL_VMICINEN		(0x1 << 15)
+#define ADC0_CTL_VMICINEN_SFT		(15)
+
+/* AGC0_CTL0 */
+#define AGC0_CTL0_AMP0GR1(x)		(((x) & 0x7) << 0)
+#define AGC0_CTL0_AMP0GR1_SET		(0)
+#define AGC0_CTL0_IMICSHD		(0x1 << 7)
+#define AGC0_CTL0_AMP1G0R(x)		(((x) & 0xf) << 8)
+#define AGC0_CTL0_AMP1G0R_SFT		(8)
+#define AGC0_CTL0_AMP1G0L(x)		(((x) & 0xf) << 12)
+#define AGC0_CTL0_AMP1G0L_SFT		(12)
+
+#define AGC_CTL0_AMP1GR1_MSK		(0x7 << 0)
+#define AGC_CTL0_AMP1GR_MSK		(0xf << 8)
+#define AGC_CTL0_AMP1GL_MSK		(0xf << 12)
+
+/* AGC0_CTL1 */
+#define AGC0_CTL1_RMSCY0(x)		(((x) & 0x3) << 0)
+#define AGC0_CTL1_CMR0(x)		(((x) & 0x3) << 2)
+#define AGC0_CTL1_DCYT0(x)		(((x) & 0x7) << 4)
+#define AGC0_CTL1_ATKT0(x)		(((x) & 0x7) << 7)
+#define AGC0_CTL1_NGT0(x)		(((x) & 0x7) << 10)
+#define AGC0_CTL1_RCTMEN0		(0x1 << 15)
+
+/* AGC0_CTL1 */
+#define AGC0_CTL2_AGC0REN		(0x1 << 0)
+#define AGC0_CTL2_AGC0LEN		(0x1 << 1)
+#define AGC0_CTL2_GREN0			(0x1 << 2)
+#define AGC0_CTL2_ZEROC0		(0x1 << 3)
+#define AGC0_CTL2_NGTEN0		(0x1 << 4)
+#define AGC0_CTL2_NGSLEN0		(0x1 << 5)
+#define AGC0_CTL2_RMSCEN0		(0x1 << 6)
+#define AGC0_CTL2_RMSINSEL0		(0x1 << 7)
+#define AGC0_CTL2_ADBEN			(0x1 << 8)
+#define AGC0_CTL2_MICAAEN		(0x1 << 9)
+#define AGC0_CTL2_NGTHSEL0(x)		(((x) & 0x7) << 10)
+#define AGC0_CTL2_TARGL0(x)		(((x) & 0x7) << 13)
+
+/* ADC_ANALOG0 */
+#define ADC_ANALOG0_VRDABC(x)		(((x) & 0x7) << 0)
+#define ADC_ANALOG0_OPBC23(x)		(((x) & 0x3) << 3)
+#define ADC_ANALOG0_OPBC1(x)		(((x) & 0x7) << 5)
+#define ADC_ANALOG0_IVSRMSTN(x)		(((x) & 0x7) << 13)
+
+/* ADC_ANALOG1 */
+#define ADC_ANALOG1_FMBC(x)		(((x) & 0x3) << 0)
+#define ADC_ANALOG1_FD1BUFBC(x)		(((x) & 0x3) << 2)
+#define ADC_ANALOG1_FD2BC(x)		(((x) & 0x3) << 4)
+#define ADC_ANALOG1_FD1BC(x)		(((x) & 0x3) << 6)
+#define ADC_ANALOG1_ADCBIAS		(0x1 << 10)
+#define ADC_ANALOG1_LPFBUFBC(x)		(((x) & 0x3) << 11)
+#define ADC_ANALOG1_LPFBC(x)		(((x) & 0x7) << 13)
+
+/* ADC1_DIGITALCTL */
+#define ADC1_DIGITALCTL_ADGC1(x)	(((x) & 0xf) << 2)
+#define ADC1_DIGITALCTL_HPF1REN		(0x1 << 6)
+#define ADC1_DIGITALCTL_HPF1LEN		(0x1 << 7)
+#define ADC1_DIGITALCTL_HPF1DW		(0x1 << 8)
+#define ADC1_DIGITALCTL_WNHPF1CUT(x)	(((x) & 0x7) << 9)
+#define ADC1_DIGITALCTL_SRSEL0(x)	(((x) & 0x3) << 12)
+#define ADC1_DIGITALCTL_AD1DEN		(0x1 << 14)
+#define ADC1_DIGITALCTL_AD1LR		(0x1 << 15)
+
+/* ADC1_CTL */
+#define ADC1_CTL_AD1REN			(0x1 << 0)
+#define ADC1_CTL_AD1REN_SFT		(0)
+#define ADC1_CTL_AD1LEN			(0x1 << 1)
+#define ADC1_CTL_AD1LEN_SFT		(1)
+#define ADC1_CTL_MIC1FDSE		(0x1 << 2)
+#define ADC1_CTL_MIC1REN		(0x1 << 3)
+#define ADC1_CTL_MIC1REN_SFT		(3)
+#define ADC1_CTL_MIC1LEN		(0x1 << 4)
+#define ADC1_CTL_MIC1LEN_SFT		(4)
+#define ADC1_CTL_VRDA1EN		(0x1 << 7)
+#define ADC1_CTL_VRDA0EN		(0x1 << 8)
+
+/* AGC1_CTL0 */
+#define AGC1_CTL0_AMP1GR1(x)		(((x) & 0x7) << 0)
+#define AGC1_CTL0_AMP1G1R(x)		(((x) & 0xf) << 8)
+#define AGC1_CTL0_AMP1G1R_SFT		(8)
+#define AGC1_CTL0_AMP1G1L(x)		(((x) & 0xf) << 12)
+#define AGC1_CTL0_AMP1G1L_SFT		(12)
+
+/* AGC1_CTL1 */
+#define AGC1_CTL1_RMSCY1(x)		(((x) & 0x3) << 0)
+#define AGC1_CTL1_CMR1(x)		(((x) & 0x3) << 2)
+#define AGC1_CTL1_DCYT1(x)		(((x) & 0x7) << 4)
+#define AGC1_CTL1_ATKT1(x)		(((x) & 0x7) << 7)
+#define AGC1_CTL1_NGT1(x)		(((x) & 0x7) << 10)
+#define AGC1_CTL1_RCTMEN1		(0x1 << 15)
+
+/* AGC1_CTL2 */
+#define AGC1_CTL2_AGC1REN		(0x1 << 0)
+#define AGC1_CTL2_AGC1LEN		(0x1 << 1)
+#define AGC1_CTL2_GREN1			(0x1 << 2)
+#define AGC1_CTL2_ZEROC1		(0x1 << 3)
+#define AGC1_CTL2_NGTEN1		(0x1 << 4)
+#define AGC1_CTL2_NGSLEN1		(0x1 << 5)
+#define AGC1_CTL2_RMSCEN1		(0x1 << 6)
+#define AGC1_CTL2_RMSINSEL1		(0x1 << 7)
+#define AGC1_CTL2_NGTHSEL1(x)		(((x) & 0x7) << 10)
+#define AGC1_CTL2_TARGL1(x)		(((x) & 0x7) << 13)
+
+/* I2S_CTL */
+#define I2S_CTL_I2STEN			(0x1 << 0)
+#define I2S_CTL_I2SREN			(0x1 << 1)
+#define I2S_CTL_I2STOWL			(0x1 << 2)
+#define I2S_CTL_I2STTDMRF		(0x1 << 3)
+#define I2S_CTL_I2STXM(x)		(((x) & 0x7) << 4)
+#define I2S_CTL_I2SRXM(x)		(((x) & 0x3) << 8)
+#define I2S_CTL_I2SRCS			(0x1 << 10)
+#define I2S_CTL_I2SPM(x)		(((x) & 0x3) << 11)
+
+/* I2S_FIFOCTL */
+#define I2S_FIFOCTL_I2STFR		(0x1 << 0)
+#define I2S_FIFOCTL_I2STFDEN		(0x1 << 1)
+#define I2S_FIFOCTL_I2STFIEN		(0x1 << 2)
+#define I2S_FIFOCTL_I2STFIP		(0x1 << 3)
+#define I2S_FIFOCTL_I2STFDCF(x)		(((x) & 0x7) << 4)
+#define I2S_FIFOCTL_I2STFDRF		(0x1 << 7)
+#define I2S_FIFOCTL_I2STFFF		(0x1 << 8)
+#define I2S_FIFOCTL_I2SRFR		(0x1 << 9)
+#define I2S_FIFOCTL_I2SRFDEN		(0x1 << 10)
+#define I2S_FIFOCTL_I2SRFIEN		(0x1 << 11)
+#define I2S_FIFOCTL_I2SRFIP		(0x1 << 12)
+#define I2S_FIFOCTL_I2SRFDCF(x)		(((x) & 0x3) << 13)
+#define I2S_FIFOCTL_I2STXKA		(0x1 << 15)
+#define I2S_FIFOCTL_I2SRFDRF		(0x1 << 16)
+#define I2S_FIFOCTL_I2SRFEF		(0x1 << 17)
+#define I2S_FIFOCTL_I2STFSS		(0x1 << 18)
+#define I2S_FIFOCTL_KMCMMI2ST(x)	(((x) & 0x3) << 19)
+
+/* SPDIF_HDMI_CTL */
+#define SPDIF_HDMI_CTL_SPDFR		(0x1 << 0)
+#define SPDIF_HDMI_CTL_HDMIFR		(0x1 << 1)
+#define SPDIF_HDMI_CTL_SPDFIP		(0x1 << 2)
+#define SPDIF_HDMI_CTL_SPDFFF		(0x1 << 3)
+#define SPDIF_HDMI_CTL_SPDFDEN		(0x1 << 4)
+#define SPDIF_HDMI_CTL_SPDFIEN		(0x1 << 5)
+#define SPDIF_HDMI_CTL_HDMFIP		(0x1 << 6)
+#define SPDIF_HDMI_CTL_HDMFFF		(0x1 << 7)
+#define SPDIF_HDMI_CTL_HDMFDEN		(0x1 << 8)
+#define SPDIF_HDMI_CTL_HDMFIEN		(0x1 << 9)
+#define SPDIF_HDMI_CTL_SPDEN		(0x1 << 10)
+#define SPDIF_HDMI_CTL_SPDKA		(0x1 << 11)
+#define SPDIF_HDMI_CTL_HDMKA		(0x1 << 12)
+#define SPDIF_HDMI_CTL_SPDFSS		(0x1 << 13)
+#define SPDIF_HDMI_CTL_HDMFSS		(0x1 << 14)
+#define SPDIF_HDMI_CTL_KMCMMHDM(x)	(((x) & 0x3) << 15)
+
+/* CMU_AUDIOPLL */
+#define CMU_AUDIOPLL_AUDIOPLLS		(0x1 << 0)
+#define CMU_AUDIOPLL_APEN		(0x1 << 4)
+#define CMU_AUDIOPLL_I2STX_CLK(x)	(((x) & 0xf) << 16)
+#define CMU_AUDIOPLL_I2SRX_CLK(x)	(((x) & 0xf) << 20)
+#define CMU_AUDIOPLL_HDMIA_CLK(x)	(((x) & 0xf) << 24)
+#define CMU_AUDIOPLL_SPDIF_CLK(x)	(((x) & 0xf) << 28)
+
+/* CMU_DEVCLKEN */
+#define CMU_DEVCLKEN0_I2STX		(0x1 << 20)
+#define CMU_DEVCLKEN0_I2SRX		(0x1 << 21)
+#define CMU_DEVCLKEN0_HDMIA		(0x1 << 22)
+#define CMU_DEVCLKEN0_SPDIF		(0x1 << 23)
+
+#define CMU_DEVRST0_AUDIO		(0x1 << 17)
+
+#define GL5302_DEVRST_AUDIO_CLK_EN	(0x1 << 10)
+#define GL5302_DEVRST_AUDIO_RST		(0x1 << 4)
+
+#endif  /* ifndef __ATV5302_AUDIO_REGS_H__ */
diff --git a/sound/soc/atc260x/atc2603c-codec/atc2603c-audio-codec.c b/sound/soc/atc260x/atc2603c-codec/atc2603c-audio-codec.c
new file mode 100755
index 0000000..e5f2a34
--- /dev/null
+++ b/sound/soc/atc260x/atc2603c-codec/atc2603c-audio-codec.c
@@ -0,0 +1,2189 @@
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <linux/clk.h>			/* clk_enable */
+#include "../sndrv-owl.h"
+#include "atc2603c-audio-regs.h"
+#include "../common-regs-owl.h"
+#include <mach/clkname.h>
+#include <mach/module-owl.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+
+#include <linux/io.h>
+#include <linux/ioport.h>
+
+#include <linux/suspend.h>
+#include <linux/earlysuspend.h>
+
+#include <linux/mfd/atc260x/atc260x.h>
+#include <linux/interrupt.h>
+#include <mach/switch.h>
+
+
+static int direct_drive_disable;
+
+static int adc_detect_mode; //0:earphone irq or gpio detect, 1: earphone adc detect
+
+static const char *audio_device_node = "actions,atc2603c-audio";
+static const char *snd_earphone_output_mode = "earphone_output_mode";
+static const char *snd_mic_num = "mic_num";
+static const char *snd_mic0_gain = "mic0_gain";
+static const char *snd_speaker_gain = "speaker_gain";
+static const char *snd_earphone_gain = "earphone_gain";
+static const char *speaker_ctrl_name = "speaker_en_gpios";
+static const char *earphone_detect_gpio = "earphone_detect_gpios";
+//20141202 new_code by yuchen: add new item in dts file to config mic mode differential or single end
+static const char *snd_mic_mode = "mic_mode";
+static const char *snd_earphone_detect_method = "earphone_detect_method";
+static const char *snd_adc_plugin_threshold = "adc_plugin_threshold";
+static const char *snd_adc_level = "adc_level";
+
+
+static int speaker_gpio_num;
+static int earphone_gpio_num;
+
+static enum of_gpio_flags speaker_gpio_level;
+static int speaker_gpio_active;
+
+static audio_hw_cfg_t audio_hw_cfg;
+
+static int atc2603c_open_count;
+static unsigned int user_lock = 1;
+static volatile unsigned int hw_init_flag = false;
+static DEFINE_MUTEX(atc2603c_pa_down_lock);
+
+//20141013 yuchen: to check pmu ic type
+static int atc2603c_ictype = PMU_NOT_USED;
+static int earphone_irq = -1;
+
+static int earphone_poll_ms = 50;
+
+
+struct reg_val {
+	int reg;
+	unsigned short val;
+	short delay; /* ms */
+};
+
+/*
+typedef struct ear_detect_dev {
+	struct cdev chrdev;
+	int dev_idx;
+	int irq;
+} ear_detect_dev_t;
+*/
+
+struct atc2603c_priv_data {
+	int mode;
+};
+static struct atc260x_dev *atc260x;
+struct snd_soc_codec *atc2603c_codec;
+
+static struct switch_dev headphone_sdev;
+
+#define   ATC2603C_AIF			0
+#define   REG_BASE				ATC2603C_AUDIO_OUT_BASE
+
+#define     AUDIOINOUT_CTL                                                    (0x0)
+#define     AUDIO_DEBUGOUTCTL                                                 (0x1)
+#define     DAC_DIGITALCTL                                                    (0x2)
+#define     DAC_VOLUMECTL0                                                    (0x3)
+#define     DAC_ANALOG0                                                       (0x4)
+#define     DAC_ANALOG1                                                       (0x5)
+#define     DAC_ANALOG2                                                       (0x6)
+#define     DAC_ANALOG3                                                       (0x7)
+
+//--------------Bits Location------------------------------------------//
+//--------------AUDIO_IN-------------------------------------------//
+
+
+//--------------Register Address---------------------------------------//
+
+#define     ADC_DIGITALCTL                                                    (0x8)
+#define     ADC_HPFCTL                                                        (0x9)
+#define     ADC_CTL                                                           (0xa)
+#define     AGC_CTL0                                                          (0xb)
+#define     AGC_CTL1                                                          (0xc)
+#define     AGC_CTL2                                                          (0xd)
+#define     ADC_ANALOG0                                                       (0xe)
+#define     ADC_ANALOG1                                                       (0xf)
+
+/*
+#define	ATC2603C_CMU_DEVRST		(ATC2603C_CMU_CONTROL_BASE+0x01) //0xc1
+#define	ATC2603C_PAD_EN			(ATC2603C_MFP_BASE+0x6)		//0xd6
+#define	ATC2603C_MFP_CTL		(ATC2603C_MFP_BASE+0x00)		//0xd0
+#define	ATC2603C_PMU_BDG_CTL		(ATC2603C_PMU_BASE+0x51)	//0x51
+*/
+
+static const u16 atc2603c_reg[ADC_ANALOG1+1] = {
+	[AUDIOINOUT_CTL] = 0x00,
+	[AUDIO_DEBUGOUTCTL] = 0x00,
+	[DAC_DIGITALCTL] = 0x03,
+	[DAC_VOLUMECTL0] = 0x00,
+	[DAC_ANALOG0] = 0x00,
+	[DAC_ANALOG1] = 0x00,
+	[DAC_ANALOG2] = 0x00,
+	[DAC_ANALOG3] = 0x00,
+	[ADC_DIGITALCTL] = 0x00,
+	[ADC_HPFCTL] = 0x00,
+	[ADC_CTL] = 0x00,
+	[AGC_CTL0] = 0x00,
+	[AGC_CTL1] = 0x00,
+	[AGC_CTL2] = 0x00,
+	[ADC_ANALOG0] = 0x00,
+	[ADC_ANALOG1] = 0x00,
+};
+
+/*
+struct reg_val atc2603c_pa_up_list[] = {
+	{DAC_VOLUMECTL0, 0xbebe, 0},
+	{DAC_ANALOG0, 0x00, 0},
+	{DAC_ANALOG1, 0x00, 0},
+	{DAC_ANALOG2, 0x00, 0},
+	{DAC_ANALOG3, 0x00, 0},
+	{DAC_ANALOG4, 0x00, 0},
+	{AUDIOINOUT_CTL, 0x02, 0},
+	{DAC_DIGITALCTL, 0x03, 0},
+	{DAC_ANALOG4, 0x08c0, 0},
+	{DAC_ANALOG0, 0x26b3, 0},
+	{DAC_ANALOG3, 0x8b0b, 0},
+	{DAC_ANALOG2, 0x07, 0},
+	{DAC_ANALOG3, 0x8b0f, 100},
+	{DAC_ANALOG2, 0x0f, 0},
+	{DAC_ANALOG4, 0x88c0, 0},
+	{DAC_ANALOG2, 0x1f, 600},
+	{DAC_ANALOG2, 0x17, 0},
+};
+
+struct reg_val atc2603c_pa_down_list[] = {
+	{DAC_VOLUMECTL0, 0xbebe, 0},
+	{DAC_ANALOG4, 0x08c0, 0},
+	{DAC_ANALOG2, 0x1f, 0},
+	{DAC_ANALOG2, 0x0f, 0},
+};
+*/
+
+struct asoc_codec_resource {
+    void __iomem    *base[MAX_RES_NUM];/*virtual base for every resource*/
+    void __iomem    *baseptr; /*pointer to every virtual base*/
+    struct clk      *clk;
+    int             irq;
+    unsigned int    setting;
+};
+
+//codec resources
+//static struct asoc_codec_resource codec_res;
+
+static int earphone_is_in_for_irq(void);
+static irqreturn_t earphone_detect_irq_handler(int irq, void *data);
+
+static struct delayed_work dwork_adc_detect;
+
+
+/* 
+static void set_dai_reg_base(int num)
+{
+	codec_res.baseptr = codec_res.base[num];
+}
+
+static u32 snd_dai_readl(u32 reg)
+{
+	return readl(codec_res.baseptr + reg);
+}
+	 
+static void snd_dai_writel(u32 val, u32 reg)
+{
+	writel(val, codec_res.baseptr + reg);
+}
+*/
+
+/*
+static void snd_codec_writel_debug(unsigned int  val, unsigned int  reg)
+{
+	snd_dai_writel(val, reg);
+	snd_dbg("%s: reg[0x%x]=[0x%x][0x%x]\n"
+		, __func__, reg, val, snd_dai_readl(reg));
+}
+*/
+
+static int atc2603c_write_pmu(struct snd_soc_codec *codec, unsigned int reg,
+		unsigned int value)
+{
+	struct atc260x_dev *atc260x = snd_soc_codec_get_drvdata(codec);
+	int ret;
+	
+	ret = atc260x_reg_write(atc260x, reg, value);
+	if(ret < 0)
+	{
+		snd_err("atc2603c_write: reg = %#X, ret = %d \n", reg, ret);
+	}
+
+//	snd_dbg("%s: reg[0x%x]=[0x%x][0x%x]\n"
+//		, __func__, reg, value, atc260x_reg_read(atc260x, reg));
+
+	return ret;
+}
+static int atc2603c_read_pmu(struct snd_soc_codec *codec, unsigned int reg)
+{
+	struct atc260x_dev *atc260x = snd_soc_codec_get_drvdata(codec);
+	int ret;
+	
+	ret = atc260x_reg_read(atc260x, reg);
+	if(ret < 0)
+	{
+		snd_err("atc2603c_read: reg = %#X, ret = %d \n", reg, ret);
+	}
+
+	return ret;	
+}
+
+
+static int snd_soc_update_bits_pmu(struct snd_soc_codec *codec, unsigned short reg,
+				unsigned int mask, unsigned int value)
+{
+	bool change;
+	unsigned int old, new;
+	int ret;
+
+	{
+		ret = atc2603c_read_pmu(codec, reg);
+		if (ret < 0)
+			return ret;
+
+		old = ret;
+		new = (old & ~mask) | (value & mask);
+		change = old != new;
+		if (change)
+			ret = atc2603c_write_pmu(codec, reg, new);
+	}
+
+	if (ret < 0)
+		return ret;
+
+	return change;
+
+}
+
+
+static void ramp_undirect(unsigned int begv, unsigned int endv) {
+	unsigned int val = 0;
+	int count = 0;
+	
+	set_dai_reg_base(I2S_SPDIF_NUM);
+	while (endv < begv) {
+		count++;
+		if ((count & 0x7F) == 0) {
+			mdelay(1);
+		}
+		val = snd_dai_readl(I2S_FIFOCTL);
+		while ((val & (0x1 << 8)) != 0) {
+			val = snd_dai_readl(I2S_FIFOCTL);
+		};
+		snd_dai_writel(endv, I2STX_DAT);
+		endv -= 0x36000;
+	}
+	while (begv <= endv) {
+		count++;
+		if ((count & 0x7F) == 0) {
+			mdelay(1);
+		}
+		val = snd_dai_readl(I2S_FIFOCTL);
+		while ((val & (0x1 << 8)) != 0) {
+			val = snd_dai_readl(I2S_FIFOCTL);
+		};
+		snd_dai_writel(endv, I2STX_DAT);
+		endv -= 0x36000;
+	}
+}
+
+static int atc2603c_write(struct snd_soc_codec *codec, unsigned int reg,
+		unsigned int value)
+{
+	int ret = 0;
+
+	struct atc260x_dev *atc260x = snd_soc_codec_get_drvdata(codec);
+/*
+	if (!snd_soc_codec_volatile_register(codec, reg) &&
+			(reg) < codec->driver->reg_cache_size &&
+			!codec->cache_bypass) {
+		ret = snd_soc_cache_write(codec, reg, value);
+		snd_dbg("%s: reg[0x%x]=[0x%x]\r\n", __func__, reg, value);
+		if (ret < 0)
+			return -1;
+	}
+
+	if (codec->cache_only) {
+		codec->cache_sync = 1;
+		return 0;
+	}
+*/
+
+	ret = atc260x_reg_write(atc260x, reg + REG_BASE, value);
+	//snd_err("%s: reg[0x%x]=[0x%x]\r\n", __FUNCTION__, reg + REG_BASE, value);
+	if (ret < 0)
+		snd_err("atc2603c_write: reg = %#X, ret = %d failed\n",
+		reg, ret);
+
+//	snd_dbg("%s: reg[0x%x]=[0x%x][0x%x]\n"
+//		, __func__, reg + REG_BASE, value, atc260x_reg_read(atc260x, reg + REG_BASE));
+
+	return ret;
+}
+
+static unsigned int atc2603c_read(struct snd_soc_codec *codec, unsigned int reg)
+{
+	int ret = 0;
+/*
+	if (!snd_soc_codec_volatile_register(codec, reg) &&
+			(reg) < codec->driver->reg_cache_size &&
+			!codec->cache_bypass) {
+		ret = snd_soc_cache_read(codec, reg, &val);
+		snd_dbg("%s: reg[0x%x]\r\n", __func__, reg);
+		if (ret < 0) {
+			snd_err("atc2603c_read: reg=%#X,ret=%d\n",
+				reg, ret);
+			return ret;
+		}
+		return val;
+	}
+*/
+	ret = atc260x_reg_read(atc260x, reg + REG_BASE);
+//	snd_dbg("%s: reg[0x%x]\r\n", __func__, reg + REG_BASE);
+	
+	if (ret < 0)
+	   snd_err("atc2603c_read: reg = %#X, ret = %d failed\n", reg, ret);
+
+	return ret;
+}
+
+#define ADC0_GAIN_MAX	25
+
+static int atc2603c_adc_gain_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+	unsigned int val;
+	//snd_soc_cache_sync(codec);
+	val = snd_soc_read(codec, mc->reg);
+	ucontrol->value.integer.value[0] =
+		((val & AGC_CTL0_AMP1GL_MSK) >> mc->shift);
+	ucontrol->value.integer.value[1] =
+		(val & AGC_CTL0_AMP1GR_MSK) >> mc->rshift;
+
+	return 0;
+}
+
+static int atc2603c_adc_gain_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
+	unsigned int val, val1, val2;
+
+	val = snd_soc_read(codec, mc->reg);
+	val1 = ucontrol->value.integer.value[0];
+	val2 = val1;
+	val = val & (~AGC_CTL0_AMP1GL_MSK);
+	val = val & (~AGC_CTL0_AMP1GR_MSK);
+	val = val | (val1<< mc->shift);
+	val = val | (val2 << mc->rshift);
+
+	snd_soc_component_update_bits(component, mc->reg,
+		AGC_CTL0_AMP1GL_MSK | AGC_CTL0_AMP1GR_MSK,
+		val);
+
+	return 0;
+}
+
+static int atc2603c_mic_gain_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] =
+		audio_hw_cfg.mic0_gain[0];
+	ucontrol->value.integer.value[1] =
+		audio_hw_cfg.mic0_gain[1];
+
+	return 0;
+}
+
+static int atc2603c_earphone_gain_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] =
+		audio_hw_cfg.earphone_gain[0];
+	ucontrol->value.integer.value[1] =
+		audio_hw_cfg.earphone_gain[1];
+
+	return 0;
+}
+
+static int atc2603c_speaker_gain_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] =
+		audio_hw_cfg.speaker_gain[0];
+	ucontrol->value.integer.value[1] =
+		audio_hw_cfg.speaker_gain[1];
+
+	return 0;
+}
+
+static int atc2603c_speaker_volume_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] =
+		audio_hw_cfg.speaker_volume;
+
+	return 0;
+}
+
+static int atc2603c_earphone_volume_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] =
+		audio_hw_cfg.earphone_volume;
+
+	return 0;
+}
+
+static int atc2603c_mic_num_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] =
+		audio_hw_cfg.mic_num;
+
+	return 0;
+}
+
+//20141202 by yuchen: new_code, get mic mode config from dts, 1 for differential, 2 for single end
+static int atc2603c_mic_mode_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	
+	ucontrol->value.integer.value[0] =
+		audio_hw_cfg.mic_mode;
+
+	return 0;	
+}
+
+static int atc2603c_earphone_detect_method_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	if(earphone_gpio_num < 0)
+	{
+		//no gpio, we use irq
+		ucontrol->value.integer.value[0] = 0;
+	}
+	else
+	{
+		//with gpio, we use gpio
+		ucontrol->value.integer.value[0] = 1;
+	}
+	return 0;	
+}
+
+
+
+const char *atc2603c_mic0_mode[] = {
+	"Differential", "Single ended"};
+
+static const SOC_ENUM_SINGLE_DECL(
+		atc2603c_mic0_mode_enum, ADC_CTL,
+		ADC_CTL_MIC0FDSE_SFT, atc2603c_mic0_mode);
+
+static const char *pa_output_swing[] = {
+	"Vpp2.4", "Vpp1.6"};
+
+static const SOC_ENUM_SINGLE_DECL(
+		pa_output_swing_enum, DAC_ANALOG1,
+		DAC_ANALOG1_PASW_SFT, pa_output_swing);
+
+const struct snd_kcontrol_new atc2603c_snd_controls[] = {
+
+	SOC_DOUBLE_EXT_TLV("Dummy mic Gain",
+		0, 0, 1, 0xf, 0,
+		atc2603c_mic_gain_get,
+		NULL,
+		NULL),
+
+	SOC_DOUBLE_EXT_TLV("Dummy earphone gain",
+		0, 0, 1, 0xff, 0,
+		atc2603c_earphone_gain_get,
+		NULL,
+		NULL),
+
+	SOC_DOUBLE_EXT_TLV("Dummy speaker gain",
+		0, 0, 1, 0xff, 0,
+		atc2603c_speaker_gain_get,
+		NULL,
+		NULL),
+
+	SOC_SINGLE_EXT_TLV("Dummy speaker volume",
+		0, 0, 0x28, 0,
+		atc2603c_speaker_volume_get,
+		NULL,
+		NULL),
+
+	SOC_SINGLE_EXT_TLV("Dummy earphone volume",
+		0, 0, 0x28, 0,
+		atc2603c_earphone_volume_get,
+		NULL,
+		NULL),
+
+	SOC_SINGLE_EXT_TLV("Dummy mic num",
+		0, 0, 0x2, 0,
+		atc2603c_mic_num_get,
+		NULL,
+		NULL),
+
+	SOC_DOUBLE_EXT_TLV("Adc0 Gain",
+		AGC_CTL0,
+		AGC_CTL0_AMP1G0L_SFT,
+		AGC_CTL0_AMP1G0R_SFT,
+		0xf,
+		0,
+		atc2603c_adc_gain_get,
+		atc2603c_adc_gain_put,
+		NULL),
+
+	SOC_SINGLE_TLV("AMP1 Gain boost Range select",
+		AGC_CTL0,
+		AGC_CTL0_AMP0GR1_SET,
+		0x7,
+		0,
+		NULL),
+		
+	SOC_SINGLE_TLV("ADC0 Digital Gain control",
+		ADC_DIGITALCTL,
+		ADC_DIGITALCTL_ADGC0_SFT,
+		0xF,
+		0,
+		NULL),	
+		
+	SOC_ENUM("Mic0 Mode Mux", atc2603c_mic0_mode_enum),
+	
+	SOC_SINGLE_EXT_TLV("Dummy mic mode",
+		0, 0, 1, 0,
+		atc2603c_mic_mode_get,
+		NULL,
+		NULL),
+
+	SOC_SINGLE_EXT_TLV("Dummy earphone detect method",
+		0, 0, 1, 0,
+		atc2603c_earphone_detect_method_get,
+		NULL,
+		NULL),
+		
+	
+	
+	SOC_ENUM("PA Output Swing Mux", pa_output_swing_enum),
+	
+	SOC_SINGLE_TLV("DAC PA Volume",
+		DAC_ANALOG1,
+		DAC_ANALOG1_VOLUME_SFT,
+		0x28,
+		0,
+		NULL),
+		
+	SOC_SINGLE("DAC FL FR PLAYBACK Switch",
+		DAC_ANALOG1,
+		DAC_ANALOG1_DACFL_FRMUTE_SFT,
+		1,
+		0),
+		
+	SOC_SINGLE_TLV("DAC FL Gain",
+		DAC_VOLUMECTL0,
+		DAC_VOLUMECTL0_DACFL_VOLUME_SFT,
+		0xFF,
+		0,
+		NULL),
+		
+	SOC_SINGLE_TLV("DAC FR Gain",
+		DAC_VOLUMECTL0,
+		DAC_VOLUMECTL0_DACFR_VOLUME_SFT,
+		0xFF,
+		0,
+		NULL),
+		
+	SOC_SINGLE("DAC PA Switch",
+		DAC_ANALOG3,
+		DAC_ANALOG3_PAEN_FR_FL_SFT,
+		1,
+		0),
+		
+	SOC_SINGLE("DAC PA OUTPUT Stage Switch",
+		DAC_ANALOG3,
+		DAC_ANALOG3_PAOSEN_FR_FL_SFT,
+		1,
+		0),
+		
+	SOC_DOUBLE("DAC Digital FL FR Switch",
+		DAC_DIGITALCTL,
+		DAC_DIGITALCTL_DEFL_SFT,
+		DAC_DIGITALCTL_DEFR_SFT,
+		1,
+		0),
+
+	SOC_SINGLE("Internal Mic Power Switch", 
+		AGC_CTL0,
+		AGC_CTL0_VMICINEN_SFT,
+		1,
+		0),
+		
+	SOC_SINGLE("External Mic Power Switch",
+		AGC_CTL0,
+		AGC_CTL0_VMICEXEN_SFT,
+		1,
+		0),
+		
+	SOC_SINGLE_TLV("External MIC Power Voltage",
+		AGC_CTL0,
+		AGC_CTL0_VMICEXST_SFT,
+		0x3,
+		0,
+		NULL),
+		
+	SOC_SINGLE_TLV("Adc0 Digital Gain",
+		ADC_DIGITALCTL,
+		ADC_DIGITALCTL_ADGC0_SFT,
+		0xf, 0, NULL),
+
+};
+#ifdef CONFIG_SND_UBUNTU
+static int atc2603c_playback_set_controls(struct snd_soc_codec *codec)
+{
+	snd_soc_update_bits(codec, DAC_ANALOG1, 0x3f << DAC_ANALOG1_VOLUME_SFT, 0x28 << DAC_ANALOG1_VOLUME_SFT);
+	snd_soc_update_bits(codec, DAC_VOLUMECTL0, 0xff << DAC_VOLUMECTL0_DACFL_VOLUME_SFT, 0xb5 << DAC_VOLUMECTL0_DACFL_VOLUME_SFT);
+	snd_soc_update_bits(codec, DAC_VOLUMECTL0, 0xff << DAC_VOLUMECTL0_DACFR_VOLUME_SFT, 0xb5 << DAC_VOLUMECTL0_DACFR_VOLUME_SFT);
+	snd_soc_update_bits(codec, DAC_ANALOG3, 0x1 << DAC_ANALOG3_PAEN_FR_FL_SFT, 0x01 << DAC_ANALOG3_PAEN_FR_FL_SFT);
+	snd_soc_update_bits(codec, DAC_ANALOG3, 0x1 << DAC_ANALOG3_PAOSEN_FR_FL_SFT, 0x01 << DAC_ANALOG3_PAOSEN_FR_FL_SFT);
+	snd_soc_update_bits(codec, DAC_DIGITALCTL, 0x03 << DAC_DIGITALCTL_DEFL_SFT, 0x03 << DAC_DIGITALCTL_DEFL_SFT);
+	snd_soc_update_bits(codec, DAC_ANALOG1, 0x01 << DAC_ANALOG1_PASW_SFT, 0x01 << DAC_ANALOG1_PASW_SFT);
+	snd_soc_update_bits(codec, DAC_ANALOG3, 0x03 << 0, 0x03);
+
+	return 0;
+}
+
+static int atc2603c_capture_set_controls(struct snd_soc_codec *codec)
+{
+	snd_soc_update_bits(codec, DAC_ANALOG1, 0x1 << DAC_ANALOG1_DACMICMUTE_SFT, 0x0 << DAC_ANALOG1_DACMICMUTE_SFT);
+	snd_soc_update_bits(codec, DAC_ANALOG1, 0x1 << DAC_ANALOG1_DACFMMUTE_SFT, 0x0 << DAC_ANALOG1_DACFMMUTE_SFT);
+	snd_soc_update_bits(codec, ADC_CTL, 0x3 << 6, 0x3 << 6);
+	snd_soc_update_bits(codec, ADC_CTL, 0x1f << 0, 0x12 << 0);
+
+	snd_soc_update_bits(codec, AGC_CTL0, 0xf << AGC_CTL0_AMP1G0L_SFT, 0x7 << AGC_CTL0_AMP1G0L_SFT);
+	snd_soc_update_bits(codec, AGC_CTL0, 0xf << AGC_CTL0_AMP1G0R_SFT, 0x7 << AGC_CTL0_AMP1G0R_SFT);
+	snd_soc_update_bits(codec, ADC_DIGITALCTL, 0xF << ADC_DIGITALCTL_ADGC0_SFT, 0x3 << ADC_DIGITALCTL_ADGC0_SFT);
+	snd_soc_update_bits(codec, AGC_CTL0, 0x7 << AGC_CTL0_AMP0GR1_SET, 0x07 << AGC_CTL0_AMP0GR1_SET);
+	snd_soc_update_bits(codec, AGC_CTL0, 0x1 << AGC_CTL0_VMICINEN_SFT, 0x1 << AGC_CTL0_VMICINEN_SFT);
+	snd_soc_update_bits(codec, AGC_CTL0, 0x1 << AGC_CTL0_VMICEXEN_SFT, 0x1 << AGC_CTL0_VMICEXEN_SFT);
+	snd_soc_update_bits(codec, AGC_CTL0, 0x3 << AGC_CTL0_VMICEXST_SFT, 0x1 << AGC_CTL0_VMICEXST_SFT);
+
+	if(audio_hw_cfg.mic_mode == 1){  //if differential.
+		snd_soc_update_bits(codec, ADC_CTL, 0x1 << ADC_CTL_MIC0FDSE_SFT, 0x0 << ADC_CTL_MIC0FDSE_SFT);
+		//FIXME no fd on 705a for now
+		snd_soc_update_bits_pmu(codec, ATC2603C_MFP_CTL,
+			0x3<<9 , 0x2<<9);//MICINL&MICINR
+		snd_soc_update_bits_pmu(codec, ATC2603C_MFP_CTL,
+			0x01 , 0x01);//MICINL&MICINR
+	}else{ //if single end. mic_mode=2
+		snd_soc_update_bits(codec, ADC_CTL, 0x1 << ADC_CTL_MIC0FDSE_SFT, 0x0 << ADC_CTL_MIC0FDSE_SFT);
+		snd_soc_update_bits_pmu(codec, ATC2603C_MFP_CTL,
+			0x03 , 0);//MICINL&MICINR
+	}
+
+	return 0;
+}
+#endif
+/*FIXME on input source selection */
+const char *atc2603c_adc0_src[] = {"None", "FM","MIC0", "FM MIC0", "PAOUT"};
+
+static const SOC_ENUM_SINGLE_DECL(
+	atc2603c_adc0_enum, ADC_CTL,
+	ADC_CTL_ATAD_MTA_FTA_SFT, atc2603c_adc0_src);
+
+const struct snd_kcontrol_new atc2603c_adc0_mux =
+SOC_DAPM_ENUM("ADC0 Source", atc2603c_adc0_enum);
+
+
+const struct snd_kcontrol_new atc2603c_dac_lr_mix[] = {
+	SOC_DAPM_SINGLE("FL FR Switch", DAC_ANALOG1,
+			DAC_ANALOG1_DACFL_FRMUTE_SFT, 1, 0),
+	SOC_DAPM_SINGLE("MIC Switch", DAC_ANALOG1,
+			DAC_ANALOG1_DACMICMUTE_SFT, 1, 0),
+	SOC_DAPM_SINGLE("FM Switch", DAC_ANALOG1,
+			DAC_ANALOG1_DACFMMUTE_SFT, 1, 0),
+};
+
+static int atc2603c_mic0_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+	unsigned int val;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		val = snd_soc_read(codec, ADC_CTL);
+		/* single end or full differential */
+		if (val & ADC_CTL_MIC0FDSE) {//if single end
+			snd_soc_update_bits_pmu(codec, ATC2603C_MFP_CTL,
+					0x03 , 0);//MICINL&MICINR
+		}
+		else
+		{
+			//FIXME no fd on 705a for now
+			snd_soc_update_bits_pmu(codec, ATC2603C_MFP_CTL,
+					0x3<<9 , 0x2<<9);//MICINL&MICINR
+			snd_soc_update_bits_pmu(codec, ATC2603C_MFP_CTL,
+					0x01 , 0x01);//MICINL&MICINR			
+			
+		}
+		//snd_soc_update_bits(codec, ADC1_CTL,
+		//		0x3 << 7, 0x3 << 7);//(VRDN output0 enable) | (VRDN output1 enable)
+		snd_soc_update_bits(codec, ADC_HPFCTL,
+				0x3, 0x3);//(High Pass filter0 L enable) | (High Pass filter0 R enable)
+
+		break;
+
+	case SND_SOC_DAPM_POST_PMD:
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static void i2s_clk_disable(void)
+{
+}
+
+static int i2s_clk_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		break;
+
+	case SND_SOC_DAPM_PRE_PMD:
+		i2s_clk_disable();
+		break;
+
+	default:
+		return 0;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget atc2603c_dapm_widgets[] = {
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("MICIN0LP"),
+	SND_SOC_DAPM_INPUT("MICIN0LN"),
+	SND_SOC_DAPM_INPUT("MICIN0RP"),
+	SND_SOC_DAPM_INPUT("MICIN0RN"),
+	SND_SOC_DAPM_INPUT("FMINL"),
+	SND_SOC_DAPM_INPUT("FMINR"),
+
+	SND_SOC_DAPM_SUPPLY("I2S_CLK", SND_SOC_NOPM,
+		0, 0, i2s_clk_event,
+		SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+//	SND_SOC_DAPM_PGA("MICIN0L", ADC_CTL,
+//		ADC_CTL_MIC0LEN_SFT, 0, NULL, 0),
+//	SND_SOC_DAPM_PGA("MICIN0R", ADC_CTL,
+//		ADC_CTL_MIC0REN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("FM L", ADC_CTL,
+		ADC_CTL_FMLEN_SFT, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("FM R", ADC_CTL,
+		ADC_CTL_FMREN_SFT, 0, NULL, 0),
+
+	SND_SOC_DAPM_MIC("MICIN0", atc2603c_mic0_event),
+	SND_SOC_DAPM_MIC("FM", NULL),
+	/* ADC0 MUX */
+	SND_SOC_DAPM_MUX("ADC0 Mux", SND_SOC_NOPM, 0, 0,
+		&atc2603c_adc0_mux),
+	/* ADCS */
+	SND_SOC_DAPM_ADC("ADC0 L", NULL, ADC_CTL,
+			ADC_CTL_AD0LEN_SFT, 0),
+	SND_SOC_DAPM_ADC("ADC0 R", NULL, ADC_CTL,
+			ADC_CTL_AD0REN_SFT, 0),
+	/* DAC Mixer */
+	SND_SOC_DAPM_MIXER("AOUT FL FR Mixer",
+			SND_SOC_NOPM, 0, 0,
+			atc2603c_dac_lr_mix,
+			ARRAY_SIZE(atc2603c_dac_lr_mix)),
+	SND_SOC_DAPM_DAC("DAC FL", NULL, DAC_ANALOG3,
+		DAC_ANALOG3_DACEN_FL_SFT, 0),
+	SND_SOC_DAPM_DAC("DAC FR", NULL, DAC_ANALOG3,
+		DAC_ANALOG3_DACEN_FR_SFT, 0),
+
+	SND_SOC_DAPM_AIF_IN("AIFRX", "AIF Playback", 0,
+			SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("AIFTX", "AIF Capture", 0,
+			SND_SOC_NOPM, 0, 0),
+
+	/* output lines */
+	SND_SOC_DAPM_OUTPUT("HP"),
+	SND_SOC_DAPM_OUTPUT("SP"),
+};
+
+static const struct snd_soc_dapm_route atc2603c_dapm_routes[] = {
+//	{"MICIN0L", NULL, "MICIN0LP"},
+//	{"MICIN0L", NULL, "MICIN0LN"},
+//	{"MICIN0R", NULL, "MICIN0RP"},
+//	{"MICIN0R", NULL, "MICIN0RN"},
+	{"FM L", NULL, "FMINL"},
+	{"FM R", NULL, "FMINR"},
+//	{"MICIN0", NULL, "MICIN0L"},
+//	{"MICIN0", NULL, "MICIN0R"},
+	{"FM", NULL, "FM L"},
+	{"FM", NULL, "FM R"},
+	{"ADC0 Mux", "MIC0", "MICIN0"},
+	{"ADC0 Mux", "FM", "FM"},
+	{"ADC0 Mux", "AOUT MIXER", "AOUT FL FR Mixer"},
+	{"ADC0 L", NULL, "ADC0 Mux"},
+	{"ADC0 R", NULL, "ADC0 Mux"},
+	{"AIFTX", NULL, "ADC0 L"},
+	{"AIFTX", NULL, "ADC0 R"},
+	{"AOUT FL FR Mixer", "FL FR Switch", "AIFRX"},
+	{"AOUT FL FR Mixer", "MIC Switch", "MICIN0"},
+	{"AOUT FL FR Mixer", "FM Switch", "FM"},
+	{"DAC FL", NULL, "AOUT FL FR Mixer"},
+	{"DAC FR", NULL, "AOUT FL FR Mixer"},
+	{"HP", NULL, "DAC FL"},
+	{"HP", NULL, "DAC FR"},
+	{"SP", NULL, "DAC FL"},
+	{"SP", NULL, "DAC FR"},
+};
+
+static void pa_up(struct snd_soc_codec *codec) {
+	/* DAC\B3\E4\B5\E7\B5ķ\BD\B7\A8:\B7\C7ֱ\C7\FD
+	a)	\CB\F9\D3\D0audio analog\BCĴ\E6\C6\F7\B6\BCд0\A3\AC\D6\F7\BF\D8TX\BA\CDTXFIFO\B6\BCʹ\C4ܡ\A3
+	b)	\CF\F2\D6\F7\BF\D8\C0\EF\C3\E6д\D7\EEСֵ\A3\A80x80000000\A3\A9
+	c)	\D6\F7\BFغ\CDatc2603cѡ\D4\F1N wireģʽ\A3\AC2.0 channelģʽ
+	d)	atc2603c\B5\C4DAC_D&A\B6\BCʹ\C4\DC
+	e)	PA BIAS EN \A3\ACPA EN\A3\ACLOOP2 EN\A3\ACatc2603c_DAC_ANALOG1дȫ0
+	f)	Delay10ms
+	g)	DAC \BF\AAʼ\B7\C5ramp\CA\FD\BEݣ\A8\B4\D30X80000000\B5\BD0x7fffffff\A3\ACÿ\B8\F40x36000дһ\B4\CE
+	\A3\ACʹ\D3\C3mips\B2\E9ѯд5201\B5\C4I2S_TX FIFO\A3\A9,ͬʱ\BF\AA\C6\F4ramp connect
+	h)	\B5ȴ\FDԼ500 ms
+	i)	\BF\AA\C6\F4pa\CA\E4\B3\F6\BC\B6en\A3\AC\B6Ͽ\AAramp connect\A3\ACLOOP2 Disable\A1\A3
+	*/
+
+	set_dai_reg_base(I2S_SPDIF_NUM);
+	/* i2stx fifo en */
+	snd_dai_writel(snd_dai_readl(I2S_FIFOCTL) | 0x3, I2S_FIFOCTL);
+	/* i2s tx en */
+	snd_dai_writel(snd_dai_readl(I2S_CTL) | 0x3, I2S_CTL);
+	snd_soc_write(codec, DAC_VOLUMECTL0, 0xbebe);
+	snd_soc_write(codec, DAC_ANALOG0, 0);
+	snd_soc_write(codec, DAC_ANALOG1, 0);
+	snd_soc_write(codec, DAC_ANALOG2, 0);
+	snd_soc_write(codec, DAC_ANALOG3, 0);
+
+	if (direct_drive_disable == 0) {
+		snd_dai_writel(0x1 << 31, I2STX_DAT);
+		snd_dai_writel(0x1 << 31, I2STX_DAT);
+	} else {
+		snd_dai_writel(0x7ffffe00, I2STX_DAT);
+		snd_dai_writel(0x7ffffe00, I2STX_DAT);
+	}
+
+	/* 2.0-Channel Mode */
+	snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x7 << 4), I2S_CTL);
+	
+	if (direct_drive_disable != 0) 
+	{	
+		/* I2S OUTPUT input ENABLE,SEL 4WIRE MODE,0x1a6:4 wire,tx 4.0,rx 5.1 */
+		/* I2S input en */
+		snd_soc_update_bits(codec, AUDIOINOUT_CTL, 0x01 << 1, 0x01 << 1);
+		/* I2S output en */
+		snd_soc_update_bits(codec, AUDIOINOUT_CTL, 0x03 << 5, 0x01 << 5);
+		/* I2S TX&RX MODE, SEL 4WIRE MODE*/
+		//snd_soc_update_bits(codec, AUDIOINOUT_CTL, 0x01 << 8, 0x01 << 8);
+		/* dac_2ch FL&FR enable */
+		snd_soc_update_bits(codec, DAC_DIGITALCTL, 0x3, 0x3);
+	}
+	/* da_a  EN,PA EN,all bias en */
+	snd_soc_write(codec, DAC_ANALOG3, 0x4b7);
+	/* DAC PA BIAS */
+	snd_soc_write(codec, DAC_ANALOG0, 0x26b3);
+	/* PA VOLUME=0 */
+	snd_soc_write(codec, DAC_ANALOG1, 0x0000);
+	/* */
+	snd_soc_write(codec, DAC_ANALOG2, 0x03);
+	
+	if (direct_drive_disable != 0) 
+	{	
+		/* da_a  EN,PA EN,OUTPSTAGE DIS,all bias en,loop2 en*/
+		snd_soc_write(codec, DAC_ANALOG3, 0x6b7);
+	}
+	else
+	{
+		/*PA EN,OUTPSTAGE en,all bias en,loop2en*/
+		snd_soc_write(codec, DAC_ANALOG3, 0x6bc);		
+	}
+
+	snd_dai_writel(((snd_dai_readl(I2S_CTL) & ~(0x3 << 11)) | (0x1 << 11)), I2S_CTL);
+	if (direct_drive_disable == 0) {
+		//direct mode
+		msleep(100);
+		/* antipop_VRO Resistant Connect */
+		snd_soc_write(codec, DAC_ANALOG2, 0x0b);
+		/* out stage en */
+		snd_soc_update_bits(codec, DAC_ANALOG2 , 0x1<<4, 0x1<<4);
+		/* DAC_OPVRO enable */
+		snd_soc_update_bits(codec, DAC_ANALOG2, 0x1<<3, 0);
+		//ramp_direct(0x80000000, 0x7ffffe00);
+	} else {
+		//non direct mode
+		msleep(100);
+		/* PA RAMP2 CONNECT */
+		snd_soc_update_bits(codec, DAC_ANALOG2 , 0x1<<4, 0x1<<4);
+		
+		ramp_undirect(0x80000000, 0x7ffffe00);
+	}
+	
+	if (direct_drive_disable != 0) 
+	{
+		//non direct mode
+		msleep(400);
+		/* out stage en */
+		/*EN,PA EN,OUTPSTAGE EN,all bias en,loop2 en*/
+		snd_soc_update_bits(codec, DAC_ANALOG3, 0x1<<3, 0x1<<3);
+		msleep(100);
+		
+		/*EN,PA EN,OUTPSTAGE EN,all bias en,loop2 DISABLE */
+		snd_soc_update_bits(codec, DAC_ANALOG3, 0x1<<9, 0);
+		/* ramp disconnect */
+		snd_soc_update_bits(codec, DAC_ANALOG2, 0x1<<9, 0);
+	}
+	
+	snd_dai_writel(0x0, I2STX_DAT);
+	snd_dai_writel(0x0, I2STX_DAT);
+	msleep(20);
+}
+
+
+static void atc2603c_pa_down(struct snd_soc_codec *codec)
+{
+	if(hw_init_flag == true)
+	{	
+        	if (direct_drive_disable == 0) {
+        		/* antipop_VRO Resistant Connect */
+        		snd_soc_update_bits(codec, DAC_ANALOG2, 0x3<<3, 0x3<<3);
+        		/* PA EN,OUTPSTAGE disen,all bias en,loop2 en */
+        		snd_soc_write(codec, DAC_ANALOG2, 0x6b4);
+        		/* bit3 vro antipop res connect,vro disen */
+        		snd_soc_update_bits(codec, DAC_ANALOG2, 0x1<<4, 0);
+        		/* bit3 vro antipop res disconnect,vro disen */
+        		snd_soc_update_bits(codec, DAC_ANALOG2, 0x1<<3, 0);
+        		
+        	} else {
+        		snd_dai_writel(snd_dai_readl(I2S_FIFOCTL) | 0x3, I2S_FIFOCTL);
+        		snd_dai_writel(snd_dai_readl(I2S_CTL) | 0x3, I2S_CTL);
+        		//act_snd_writel(act_snd_readl(CO_AUDIOINOUT_CTL) | (0x1 << 1), CO_AUDIOINOUT_CTL);
+        		
+        		snd_soc_write(codec, DAC_VOLUMECTL0, 0xbebe);
+        		
+        		/* PA LOOP2 en */
+        		snd_soc_update_bits(codec, DAC_ANALOG3, 0x1<<9, 0x1<<9);
+        		/* \B8\F4ֱ\B5\E7\C8\DDDischarge \BF\AA\C6\F4 */
+        		snd_soc_update_bits(codec, DAC_ANALOG2, 0x1<<8, 0x1<<8);
+        		
+        		snd_dai_writel(0x7ffffe00, I2STX_DAT);
+        		snd_dai_writel(0x7ffffe00, I2STX_DAT);
+        		msleep(300);
+        		
+        		/* ramp Connect EN */
+        		snd_soc_update_bits(codec, DAC_ANALOG2, 0x1 << 9, 0x1<<9);
+        		ramp_undirect(0x80000000, 0x7ffffe00);
+			msleep(600);
+        	}
+		snd_soc_write(codec, DAC_VOLUMECTL0, 0);
+		hw_init_flag = false;
+	}
+}
+
+static void atc2603c_adckeypad_config(struct snd_soc_codec *codec)
+{
+	//external mic power enable
+	snd_soc_update_bits(codec, AGC_CTL0, 0x1 << 6, 0x1 << 6); 
+	snd_soc_update_bits(codec, AGC_CTL0, 0x3 << 4, 0x3 << 4);
+	//printk("atc2603_ADC0_CTL:0x%x\n",act_snd_readl(atc2603_ADC0_CTL));
+	
+	//enable auxadc2
+	snd_soc_update_bits_pmu(codec, ATC2603C_PMU_AUXADC_CTL0, 0x1 << 12, 0x1 << 12);
+    
+	//GL5201_ADCKEY_INFO("open:AuxADC_CTL0 = 0x%x\n",act_snd_readl(atc2603_PMU_AuxADC_CTL0));                
+}
+
+static int detect_dep = 0;
+static int old_adc_state = SPEAKER_ON;
+static int now_adc_state = SPEAKER_ON;
+static int earphone_is_in_for_adc(void)
+{
+	int adc_val = 0;
+	
+	if(audio_hw_cfg.adc_level == 1)
+	{
+		
+		adc_val = 1024-atc2603c_read_pmu(atc2603c_codec, ATC2603C_PMU_AUXADC2);
+		//printk("direct 0x%x\n", adc_val);
+        	if(adc_val < audio_hw_cfg.adc_plugin_threshold)
+        	{
+        		return HEADSET_NO_MIC;
+        	}
+        	
+        	return SPEAKER_ON;
+	}
+	else
+	{
+		adc_val = atc2603c_read_pmu(atc2603c_codec, ATC2603C_PMU_AUXADC2);
+		//printk("undirect 0x%x\n", adc_val);
+        	if(adc_val < audio_hw_cfg.adc_plugin_threshold)
+        	{
+        		return HEADSET_NO_MIC;
+        	}
+        	
+        	return SPEAKER_ON;
+	}
+	
+	
+}
+
+
+static void adc_poll(struct work_struct *data) 
+{
+    	now_adc_state = earphone_is_in_for_adc();
+
+    	if(now_adc_state != old_adc_state)
+    	{
+    		if(detect_dep >= 4)
+    		{
+    			//state is stable
+    			detect_dep = 0;
+    		} 	
+    		else
+    		{
+    			//printk("detect_dep %d\n", detect_dep);
+    			detect_dep++;
+    			goto POLL_EXIT;
+    		}
+    	}
+    	else //now_state == old_state
+    	{
+    		if(detect_dep > 0)
+    		{
+    			//state is not stable yet
+    			detect_dep = 0;
+    		}
+    		
+    		goto POLL_EXIT;
+    	}
+    	
+    	        	
+        //we get here because state changed and stable	
+    	if (now_adc_state == HEADSET_NO_MIC) {
+            printk("sndrv: speaker off \n");
+        	/* 1:headset with mic;  2:headset without mic */
+            switch_set_state(&headphone_sdev, HEADSET_NO_MIC);
+                        
+        } 
+        else
+        {
+            printk("sndrv: speaker on state %d, old_state %d\n",now_adc_state, old_adc_state);
+            switch_set_state(&headphone_sdev, SPEAKER_ON);
+        }
+
+	old_adc_state = now_adc_state;        
+
+POLL_EXIT:	
+	schedule_delayed_work(&dwork_adc_detect, msecs_to_jiffies(earphone_poll_ms));
+}
+
+
+void atc2603c_pa_up_all(struct snd_soc_codec *codec)
+{
+	int ret;
+
+	/* \B1\EAʶclassd\B5\C4״̬\CAǷ\F1\B1\BB\C9\E8\D6\C3Ϊ\B9̶\A8\B2\BB\D0\E8Ҫ\B8ı䣬ȱʡ\CA\C7TRUE */
+	static int classd_flag = 1;
+	struct clk *apll_clk;
+
+	module_clk_disable(MOD_ID_I2SRX);
+	module_clk_disable(MOD_ID_I2STX);
+	module_clk_enable(MOD_ID_I2SRX);
+	module_clk_enable(MOD_ID_I2STX);
+
+	/*for the fucked bug of motor shaking while startup,
+	because GPIOB(1) is mfp with I2S_LRCLK1*/
+	set_dai_reg_base(I2S_SPDIF_NUM);
+	snd_dai_writel(snd_dai_readl(GPIO_BOUTEN) | 2, GPIO_BOUTEN);
+
+	if(((snd_dai_readl(I2S_CTL) & 0x3) == 0x0)) {
+		/* disable i2s tx&rx */
+		snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x3 << 0), I2S_CTL);
+
+		/* avoid sound while reset fifo */
+		snd_soc_update_bits(codec,DAC_ANALOG1, 0x1 << 10, 0);
+
+		/* reset i2s rx&&tx fifo, avoid left & right channel wrong */
+		snd_dai_writel(snd_dai_readl(I2S_FIFOCTL) & ~(0x3 << 9) & ~0x3, I2S_FIFOCTL);
+		snd_dai_writel(snd_dai_readl(I2S_FIFOCTL) | (0x3 << 9) | 0x3, I2S_FIFOCTL);
+
+		/* this should before enable rx/tx, or after suspend, data may be corrupt */
+		snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x3 << 11),I2S_CTL);
+		snd_dai_writel(snd_dai_readl(I2S_CTL) | (0x1 << 11),I2S_CTL);
+		/* set i2s mode I2S_RX_ClkSel==1 */
+		snd_dai_writel(snd_dai_readl(I2S_CTL) | (0x1 << 10), I2S_CTL);
+
+		/* enable i2s rx/tx at the same time */
+		snd_dai_writel(snd_dai_readl(I2S_CTL) | 0x3, I2S_CTL);
+
+		apll_clk = clk_get(NULL, CLKNAME_AUDIOPLL);
+		clk_prepare(apll_clk);
+		clk_enable(apll_clk);
+
+		/* i2s rx 00: 2.0-Channel Mode */
+		snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x3 << 8), I2S_CTL);
+		snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x3 << 4), I2S_CTL);
+	}
+
+    	/* EXTIRQ pad enable, ʹ\D6ж\CF\D0ź\C5\C4\DC\CB͵\BD\D6\F7\BF\D8 */
+    	snd_soc_update_bits_pmu(codec, ATC2603C_PAD_EN, 0x73, 0x73);
+    	/* I2S: 2.0 Channel, SEL 4WIRE MODE */
+    	snd_soc_update_bits(codec, AUDIOINOUT_CTL, 0x122, 0);
+
+    	snd_soc_update_bits(codec, AUDIOINOUT_CTL, 0x20, 0x20);
+    	
+    	//FIXME: it's default to differential here, how to config single end?
+	//snd_soc_update_bits_pmu(codec, ATC2603C_MFP_CTL, 0xf << 3, 0);
+	if(audio_hw_cfg.mic_mode == 1)
+	{
+		snd_soc_update_bits_pmu(codec, ATC2603C_MFP_CTL, 0x3<<9 , 0x2<<9);//MICINL&MICINR
+		snd_soc_update_bits_pmu(codec, ATC2603C_MFP_CTL, 0x01 , 0x01);//MICINL&MICINR			
+	}
+	else
+	{
+		snd_soc_update_bits_pmu(codec, ATC2603C_MFP_CTL, 0x3 , 0);//MICINL&MICINR		
+	}
+	
+
+	/* \B4\F2\BF\AA\C4ڲ\BF\B5Ļ\F9׼\C2˲\A8\C6\F7,\BC\F5С\B5\D7\D4룬\CC\E1\C9\FDaudio\D0\D4\C4\DC */
+	/*set_bdg_ctl();*/
+	/* for atc2603c those burn Efuse */
+	/* bit4:0 should not be changed, otherwise VREF isn't accurate */
+	ret = snd_soc_update_bits_pmu(codec, ATC2603C_PMU_BDG_CTL, 0x01 << 6, 0x01 << 6);
+	ret = snd_soc_update_bits_pmu(codec, ATC2603C_PMU_BDG_CTL, 0x01 << 5, 0);
+
+	pa_up(codec);
+
+	//snd_soc_update_bits(codec, DAC_DIGITALCTL, 0x3<<2, 0x3<<2);
+			
+	if (direct_drive_disable == 0)
+	{
+		snd_soc_update_bits(codec, DAC_ANALOG3, 0x1<<10, 0x1<<10);
+		snd_soc_update_bits(codec, DAC_ANALOG2, 0x7, 0x3);
+		snd_soc_update_bits(codec, DAC_ANALOG3, 0x7<<4, 0x3<<4);						
+	}
+			
+	if (classd_flag == 1) 
+	{
+		// DAC&PA Bias enable
+		snd_soc_update_bits(codec, DAC_ANALOG3, 0x1 << 10, 0x1 << 10);
+		// pa zero cross enable 
+		snd_soc_update_bits(codec, DAC_ANALOG2, 0x1 << 15, 0x1 << 15);
+		snd_soc_update_bits(codec, DAC_ANALOG3, 0x1 << 13, 0x1 << 13);
+	}
+
+
+	//after pa_up, the regs status should be the same as outstandby?
+	snd_soc_update_bits(codec, DAC_ANALOG1, DAC_ANALOG1_DACFL_FRMUTE, 0);//mute
+	snd_soc_update_bits(codec, AUDIOINOUT_CTL, 0x01 << 1, 0);//I2S input disable
+	snd_soc_update_bits(codec, DAC_ANALOG1, DAC_ANALOG1_PASW, DAC_ANALOG1_PASW);//1.6v
+	snd_soc_update_bits(codec, DAC_DIGITALCTL, 0x3<<4, 0x2<<4);
+	snd_soc_update_bits(codec, DAC_ANALOG1, 0x3f, 40);//
+	snd_soc_write(codec, DAC_VOLUMECTL0, 0xb5b5);//0//0xbebe
+
+/*
+	if (direct_drive_disable == 0) {
+	}
+	else {
+		snd_soc_write(codec, DAC_ANALOG2, 0x8400);
+		snd_soc_write(codec, DAC_ANALOG3, 0xaa0b);
+	}
+*/
+
+	snd_dai_writel(snd_dai_readl(I2S_CTL) & ~0x3, I2S_CTL);
+	snd_dai_writel(snd_dai_readl(I2S_FIFOCTL) & ~(0x3 << 9) & ~0x3, I2S_FIFOCTL);
+	
+	
+	//FIXME: for earphone irq detect and gpio detect compatibility
+	//we need these 2 bits always set to keep irq detect always enabled when no gpio detect available
+	//if we use dapm to control these 2 bits, irq detect cant always be enabled
+	//and if we dont use dapm and dont set these bits here, mic recording wont function 
+	//in gpio detect scenario.
+	//so we always set these 2 bits here and delete related dapm configs
+	//need to check any negative results
+        snd_soc_update_bits(codec, ADC_CTL, 0x1 << 6, 0x1 << 6);
+        snd_soc_update_bits(codec, ADC_CTL, 0x1 << 7, 0x1 << 7);
+	
+	//FIXME: set earphone irq detect
+	//enable pmu interupts mask for audio
+	//ret = snd_soc_update_bits_pmu(codec, ATC2603C_INTS_MSK, 0x1, 0x1);
+	//headset or earphone INOUT DECTECT IRQ enable
+	if((earphone_gpio_num < 0) && (adc_detect_mode == 0) && (earphone_irq != -1))	
+	{        	
+        	snd_soc_update_bits(codec, AUDIOINOUT_CTL, 0x1 << 10, 0x1 << 10);
+        	//  External MIC Power VMIC enabled
+        	//snd_soc_update_bits(codec, AGC_CTL0, 0x1 << 3, 0x1 << 3);
+        	snd_soc_update_bits(codec, AGC_CTL0, 0x1 << 6, 0x1 << 6);
+        	snd_soc_update_bits(codec, AGC_CTL0, 0x1 << 7, 0x1 << 7);
+        	
+        	snd_soc_update_bits(codec, ADC_ANALOG1, 0x1 << 8, 0x1 << 8);
+	}
+//	snd_soc_update_bits(codec, AUDIOINOUT_CTL, 0x1 << 2, 0);
+//	snd_soc_update_bits(codec, AUDIOINOUT_CTL, 0x1 << 3, 0);	
+}
+EXPORT_SYMBOL_GPL(atc2603c_pa_up_all);
+
+static int atc2603c_audio_set_dai_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+
+	if (mute) {
+		snd_soc_update_bits(codec, DAC_ANALOG1,
+			DAC_ANALOG1_DACFL_FRMUTE, 0);
+	} else {
+		snd_soc_update_bits(codec, DAC_ANALOG1,
+			DAC_ANALOG1_DACFL_FRMUTE,
+			DAC_ANALOG1_DACFL_FRMUTE);
+	}
+
+	return 0;
+}
+static int atc2603c_audio_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	/* enable the atc2603c i2s input function */
+	struct snd_soc_codec *codec = dai->codec;
+
+	//printk("atc2603c_audio_hw_params %d", hw_init_flag);
+	if(hw_init_flag == false) {
+		//printk("request IRQ %d!!!!", earphone_irq);
+				
+		//printk("atc2603c_pa_up_all %d!!!!", hw_init_flag);
+		atc2603c_pa_up_all(codec);
+		hw_init_flag = true;
+		
+	}
+	//snd_err("%s %d\n", __FILE__,__LINE__);
+	snd_soc_update_bits(codec, AUDIOINOUT_CTL, 0x03 << 5, 0x01 << 5);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+/*		
+		if (direct_drive_disable == 0) {
+
+		} else {
+			snd_soc_write(codec,	DAC_ANALOG2,	0x8400);
+			snd_soc_write(codec,	DAC_ANALOG3,	0xaa0b);
+		}
+*/
+		//snd_err("%s %d\n", __FILE__,__LINE__);
+		snd_soc_update_bits(codec,
+			AUDIOINOUT_CTL, 0x01 << 1, 0x01 << 1);
+		snd_soc_update_bits(codec,
+			DAC_ANALOG3, 0x03, 0x03);
+#ifdef CONFIG_SND_UBUNTU
+        atc2603c_playback_set_controls(codec);
+		audio_set_output_mode(substream, O_MODE_I2S);
+#endif
+	} else {
+		snd_soc_update_bits(codec,
+			ADC_HPFCTL, 0x3 << 0, 0x3 << 0);//adc0 hpf disable
+		//snd_err("%s %d\n", __FILE__,__LINE__);
+		snd_soc_update_bits(codec,
+			AUDIOINOUT_CTL, 0x01 << 8, 0x01 << 8);
+#ifdef CONFIG_SND_UBUNTU
+        atc2603c_capture_set_controls(codec);
+        if(params_channels(params) == 1){
+            snd_soc_update_bits(codec, ADC_CTL, 0x3 << 6, 0x2 << 6);
+            snd_soc_update_bits(codec, ADC_CTL, 0x3 << 3, 0x2 << 3);
+        }else{
+            snd_soc_update_bits(codec, ADC_CTL, 0x3 << 6, 0x3 << 6);
+            snd_soc_update_bits(codec, ADC_CTL, 0x3 << 3, 0x3 << 3);
+        }
+#endif
+	}
+	atc2603c_open_count++;
+
+	return 0;
+}
+
+static int atc2603c_audio_hw_free(
+	struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	snd_dbg("atc2603c_audio_hw_free\n");
+	/* disable the atc2603c i2s input function */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		//printk("SNDRV_PCM_STREAM_PLAYBACK\n");
+		snd_soc_update_bits(codec,
+				AUDIOINOUT_CTL,
+				0x01 << 1, 0);
+	} else {
+		//printk("SNDRV_PCM_STREAM_CAPTURE\n");
+		snd_soc_update_bits(codec,
+				AUDIOINOUT_CTL,
+				0x01 << 8, 0);
+	}
+
+    if(atc2603c_open_count > 0)
+        atc2603c_open_count--;
+	return 0;
+}
+
+static int atc2603c_audio_prepare(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	/* nothing should to do here now */
+	return 0;
+}
+
+static int atc2603c_audio_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = dai->codec;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, DAC_DIGITALCTL, 0x3<<4, 0x2<<4);
+	/* we set the i2s 2 channel-mode by default */
+	//snd_soc_update_bits(codec, AUDIOINOUT_CTL, 0x03 << 2, 0);
+
+	return 0;
+}
+
+static int atc2603c_audio_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	/* nothing should to do here now */
+	return 0;
+}
+
+static void atc2603c_power_down(struct snd_soc_codec *codec)
+{
+	atc2603c_pa_down(codec);
+}
+
+static int atc2603c_set_bias_level(struct snd_soc_codec *codec,
+		                        enum snd_soc_bias_level level)
+{
+#if 0
+	int ret;
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		snd_dbg("%s:  SND_SOC_BIAS_ON\n", __func__);
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		snd_dbg("%s:  SND_SOC_BIAS_PREPARE\n", __func__);
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		#ifdef SND_SOC_BIAS_DEBUG
+		snd_dbg("%s:  SND_SOC_BIAS_STANDBY\n", __func__);
+		#endif
+
+		if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
+			codec->cache_only = false;
+			codec->cache_sync = 1;
+			//ret = snd_soc_cache_sync(codec);
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_dbg("%s:  SND_SOC_BIAS_OFF\n", __func__);
+		break;
+
+	default:
+		break;
+	}
+
+	codec->dapm.bias_level = level;
+#endif
+	return 0;
+}
+
+static void reenable_audio_block(struct snd_soc_codec *codec)
+{
+	snd_soc_update_bits_pmu(codec,
+		ATC2603C_CMU_DEVRST, 0x1 << 4, 0);//audio block reset
+
+	snd_soc_update_bits_pmu(codec, ATC2603C_CMU_DEVRST,
+		0x1 << 10, 0x1 << 10);//SCLK to Audio Clock Enable Control
+	snd_soc_update_bits_pmu(codec,
+		ATC2603C_CMU_DEVRST, 0x1 << 4, 0x1 << 4);
+
+}
+
+static int atc2603c_probe(struct snd_soc_codec *codec)
+{
+	snd_dbg("atc2603c_probe!\n");
+	if (codec == NULL)
+		snd_dbg("NULL codec \r\n");
+
+	snd_dbg("codec->name = %s\r\n", codec->component.name);
+
+	atc2603c_codec = codec;
+
+	hw_init_flag = false;
+	reenable_audio_block(codec);
+
+	atc2603c_pa_up_all(codec);	
+	hw_init_flag = true;
+
+	if((earphone_gpio_num < 0) && (adc_detect_mode == 0) && (earphone_irq != -1))
+	{
+		int ret = devm_request_threaded_irq(codec->dev, earphone_irq, NULL,
+				earphone_detect_irq_handler, IRQF_TRIGGER_HIGH, "atc260x-audio",
+				NULL);
+
+		if(ret < 0)
+		{
+			snd_err("NO IRQ %d\n", ret);
+		}
+	}
+	
+	if(adc_detect_mode == 1)
+	{
+		//config adc detect 
+		atc2603c_adckeypad_config(codec);
+
+		old_adc_state = SPEAKER_ON;
+		now_adc_state = HEADSET_NO_MIC;
+		
+		INIT_DELAYED_WORK(&dwork_adc_detect, adc_poll);
+		schedule_delayed_work(&dwork_adc_detect, msecs_to_jiffies(500));
+	}
+
+	snd_soc_update_bits(codec, AUDIOINOUT_CTL, 0x1 << 2, 0);
+	snd_soc_update_bits(codec, AUDIOINOUT_CTL, 0x1 << 3, 0);	
+		
+	return 0;
+}
+
+static int atc2603c_remove(struct snd_soc_codec *codec)
+{
+	if (earphone_irq != -1)
+	{
+		free_irq(earphone_irq,codec->dev);
+		earphone_irq = -1;
+	}
+	
+	atc2603c_pa_down(codec);
+	
+	if(adc_detect_mode == 1)
+	{
+		cancel_delayed_work_sync(&dwork_adc_detect);	
+	}
+	return 0;
+}
+
+static int atc2603c_suspend(struct snd_soc_codec *codec)
+{
+	snd_err("atc2603c_suspend\n");
+    //atc2603c_store_regs();
+#ifdef CONFIG_SND_UBUNTU
+	atc2603c_power_down(codec);
+	atc2603c_set_bias_level(codec, SND_SOC_BIAS_OFF);
+#endif
+	if(adc_detect_mode == 1)
+	{
+		cancel_delayed_work_sync(&dwork_adc_detect);
+	}
+	return 0;
+}
+
+static int atc2603c_resume(struct snd_soc_codec *codec)
+{
+	int i;
+	snd_err("atc2603c_resume\n");	
+	printk("atc2603c_resume\n");
+	reenable_audio_block(codec);
+    
+#ifdef CONFIG_SND_UBUNTU
+	atc2603c_pa_up_all(codec);
+	hw_init_flag = true;
+#endif
+	//atc2603c_restore_regs();
+	//atc2603c_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	for(i=0;i<8;i++)
+	{
+		unsigned short reg_now;
+		reg_now = (unsigned short)atc260x_reg_read(atc260x, i + REG_BASE);
+                printk("[0xa%d]:0x%x\n",i, reg_now);
+	}
+
+	if(adc_detect_mode == 1)
+	{
+		schedule_delayed_work(&dwork_adc_detect, msecs_to_jiffies(500));
+		atc2603c_adckeypad_config(codec);	
+	}
+#ifdef CONFIG_SND_UBUNTU  //suspend/resume
+    if(atc2603c_open_count > 0){
+        atc2603c_playback_set_controls(codec);
+        snd_soc_update_bits(codec, AUDIOINOUT_CTL, 0x01 << 1, 0x01 << 1);
+    }
+#endif
+	return 0;
+}
+
+static void atc2603c_audio_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+#if 0
+	struct snd_soc_codec *codec = dai->codec;
+
+	atc2603c_power_down(codec);
+	atc2603c_set_bias_level(codec, SND_SOC_BIAS_OFF);
+#endif
+	return;
+}
+
+#define ATC2603C_RATES SNDRV_PCM_RATE_8000_192000
+#ifdef CONFIG_SND_UBUNTU
+#define ATC2603C_FORMATS (SNDRV_PCM_FMTBIT_S32_LE |\
+	SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)
+#else
+#define ATC2603C_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+	SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE)
+#endif
+
+struct snd_soc_dai_ops atc2603c_aif_dai_ops = {
+	.shutdown = atc2603c_audio_shutdown,
+	.hw_params = atc2603c_audio_hw_params,
+	.hw_free = atc2603c_audio_hw_free,
+	.prepare = atc2603c_audio_prepare,
+	.set_fmt = atc2603c_audio_set_dai_fmt,
+	.set_sysclk = atc2603c_audio_set_dai_sysclk,
+	.digital_mute = atc2603c_audio_set_dai_digital_mute,
+};
+
+struct snd_soc_dai_driver codec_atc2603c_dai[] = {
+	{
+		.name = "atc2603c-dai",
+		.id = ATC2603C_AIF,
+		.playback = {
+			.stream_name = "AIF Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = ATC2603C_RATES,
+			.formats = ATC2603C_FORMATS,
+		},
+		.capture = {
+			.stream_name = "AIF Capture",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = ATC2603C_RATES,
+			.formats = ATC2603C_FORMATS,
+		},
+		.ops = &atc2603c_aif_dai_ops,
+	},
+};
+
+static struct snd_soc_codec_driver soc_codec_atc2603c = {
+	.probe = atc2603c_probe,
+	.remove = atc2603c_remove,
+
+	.suspend = atc2603c_suspend,
+	.resume = atc2603c_resume,
+	//.set_bias_level = atc2603c_set_bias_level,
+	.idle_bias_off = true,
+
+	.reg_cache_size = (ADC_ANALOG1 + 1),
+	.reg_word_size = sizeof(u16),
+	.reg_cache_step = 1,
+
+	.controls = atc2603c_snd_controls,
+	.num_controls = ARRAY_SIZE(atc2603c_snd_controls),
+	.dapm_widgets = atc2603c_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(atc2603c_dapm_widgets),
+	.dapm_routes = atc2603c_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(atc2603c_dapm_routes),
+	.write = atc2603c_write,
+	.read = atc2603c_read,
+};
+
+static ssize_t error_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int cnt;
+
+	cnt = sprintf(buf, "%d\n(Note: 1: open, 0:close)\n", error_switch);
+	return cnt;
+}
+
+static ssize_t error_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int cnt, tmp;
+	cnt = sscanf(buf, "%d", &tmp);
+	switch (tmp) {
+	case 0:
+	case 1:
+		error_switch = tmp;
+		break;
+	default:
+		printk(KERN_ERR"invalid input\n");
+		break;
+	}
+	return count;
+}
+
+static ssize_t debug_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int cnt;
+
+	cnt = sprintf(buf, "%d\n(Note: 1: open, 0:close)\n", debug_switch);
+	return cnt;
+}
+
+static ssize_t debug_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	int cnt, tmp;
+	cnt = sscanf(buf, "%d", &tmp);
+	switch (tmp) {
+	case 0:
+	case 1:
+		debug_switch = tmp;
+		break;
+	default:
+		printk(KERN_INFO"invalid input\n");
+		break;
+	}
+	return count;
+}
+
+static struct device_attribute atc2603c_attr[] = {
+	__ATTR(error, S_IRUSR | S_IWUSR, error_show, error_store),
+	__ATTR(debug, S_IRUSR | S_IWUSR, debug_show, debug_store),
+};
+
+int atc2603c_audio_get_pmu_status(void)
+{
+	return atc2603c_ictype;
+}
+
+EXPORT_SYMBOL_GPL(atc2603c_audio_get_pmu_status);
+
+static int earphone_is_in_for_irq(void)
+{
+	int val = 0;
+	val = atc260x_reg_read(atc260x, ADC_ANALOG0+REG_BASE);
+	if((val & 0x1<<8) != 0)
+	{
+		return HEADSET_NO_MIC;
+	}
+	
+	val = atc260x_reg_read(atc260x, AGC_CTL1+REG_BASE);
+	if((val & 0x1<<13) != 0)
+	{
+		return HEADSET_MIC;
+	}
+	
+	return SPEAKER_ON;
+}
+
+static int old_state = -1;
+static irqreturn_t earphone_detect_irq_handler(int irq, void *data) 
+{
+    int state;
+
+    printk("earphone in/out\n");
+    state = earphone_is_in_for_irq();
+    
+    if (state == HEADSET_NO_MIC) {
+    	printk("sndrv: speaker off \n");
+    	/* 1:headset with mic;  2:headset without mic */
+        switch_set_state(&headphone_sdev, HEADSET_NO_MIC);
+        
+        atc260x_reg_write(atc260x,AUDIOINOUT_CTL+REG_BASE, atc260x_reg_read(atc260x, AUDIOINOUT_CTL+REG_BASE) | 0x1<<3);
+        atc260x_reg_write(atc260x,AUDIOINOUT_CTL+REG_BASE, atc260x_reg_read(atc260x, AUDIOINOUT_CTL+REG_BASE) & ~(0x1<<3));
+        
+    } 
+    else if (state == HEADSET_MIC)
+    {
+    	printk("sndrv: speaker off, mic in \n");
+    	/* 1:headset with mic;  2:headset without mic */
+        switch_set_state(&headphone_sdev, HEADSET_MIC);  
+        
+        atc260x_reg_write(atc260x,AUDIOINOUT_CTL+REG_BASE, atc260x_reg_read(atc260x, AUDIOINOUT_CTL+REG_BASE) | 0x1<<3);
+        atc260x_reg_write(atc260x,AUDIOINOUT_CTL+REG_BASE, atc260x_reg_read(atc260x, AUDIOINOUT_CTL+REG_BASE) & ~(0x1<<3));
+          	
+    }
+    else
+    {
+    	printk("sndrv: speaker on \n");
+        switch_set_state(&headphone_sdev, SPEAKER_ON);
+
+        atc260x_reg_write(atc260x,AUDIOINOUT_CTL+REG_BASE, atc260x_reg_read(atc260x, AUDIOINOUT_CTL+REG_BASE) | 0x1<<2);
+        atc260x_reg_write(atc260x,AUDIOINOUT_CTL+REG_BASE, atc260x_reg_read(atc260x, AUDIOINOUT_CTL+REG_BASE) & ~(0x1<<2));
+    }
+    
+    if(old_state == -1)
+    {
+    	old_state = state;
+    }
+    
+    return IRQ_HANDLED;
+}
+
+
+static int atc2603c_platform_probe(struct platform_device *pdev)
+{
+	int i;
+	int ret = 0;
+	
+	snd_err("atc2603c_platform_probe\r\n");
+
+/*
+	dn = of_find_compatible_node(NULL, NULL, "actions,atm7039c-i2s");
+	if (!dn) {
+		snd_err("Fail to get device_node actions,atm7039c-i2s\r\n");
+		//goto of_get_failed;
+	}
+*/
+	
+	/*FIXME: what if error in second or third loop*/
+/*
+	for(i=0; i<2; i++) 
+	{
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		if (!res) {
+			snd_err("no memory resource i=%d\n", i);
+			return -ENODEV;
+		}
+
+		if (!devm_request_mem_region (&pdev->dev, res->start,
+					resource_size(res), "gl5203-audio-i2s")) {
+			snd_err("Unable to request register region\n");
+			return -EBUSY;
+		}
+
+		codec_res.base[i] = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+		if (codec_res.base[i] == NULL) {
+			snd_err("Unable to ioremap register region\n");
+			return -ENXIO;
+		}
+		
+		snd_err("it's ok %d\n", i);
+	}
+*/
+	for (i = 0; i < ARRAY_SIZE(atc2603c_attr); i++) {
+		//snd_err("add file!\r\n");
+		ret = device_create_file(&pdev->dev, &atc2603c_attr[i]);
+	}
+
+
+	atc260x = dev_get_drvdata(pdev->dev.parent);
+	platform_set_drvdata(pdev, atc260x);
+
+	atc2603c_ictype = ATC260X_ICTYPE_2603C;
+	pdev->dev.init_name = "atc260x-audio";
+	
+	//we use VMICEXT to detect earphone
+	if((earphone_gpio_num<0)&&(adc_detect_mode == 0))
+	{
+		earphone_irq = platform_get_irq(pdev, 0); 
+		snd_err("what's my lucky draw %d\n", earphone_irq);
+	}	
+	
+	return snd_soc_register_codec(&pdev->dev, &soc_codec_atc2603c,
+			codec_atc2603c_dai, ARRAY_SIZE(codec_atc2603c_dai));
+}
+
+static int atc2603c_platform_remove(struct platform_device *pdev)
+{
+	int i = 0;
+	struct device *dev;
+
+	dev = bus_find_device_by_name(&platform_bus_type, NULL, "atc260x-audio");
+	if (dev) {
+		for (i = 0; i < ARRAY_SIZE(atc2603c_attr); i++) {
+			//snd_err("remove file!\r\n");
+			device_remove_file(dev, &atc2603c_attr[i]);
+		}
+	} else {
+		snd_err("Find platform device atc260x-audio failed!\r\n");
+		return -ENODEV;
+	}
+
+	snd_soc_unregister_codec(&pdev->dev);
+		
+	return 0;
+}
+
+static void atc2603c_platform_shutdown(struct platform_device *pdev)
+{	
+	gpio_direction_output(speaker_gpio_num, !speaker_gpio_active);
+/*
+	snd_soc_write(atc2603c_codec, DAC_VOLUMECTL0, 0xBEBE);
+	snd_soc_write(atc2603c_codec, DAC_ANALOG1, 0x0);
+	snd_soc_write(atc2603c_codec, DAC_ANALOG3, 0x8B0B);
+	snd_soc_write(atc2603c_codec, DAC_ANALOG4, 0x08C0);
+	snd_soc_write(atc2603c_codec, DAC_ANALOG2, 0x0100);
+	snd_soc_update_bits(atc2603c_codec,
+			AUDIOINOUT_CTL,
+			0x01 << 1, 0);
+*/
+	atc2603c_power_down(atc2603c_codec);
+	return;
+}
+
+static const struct of_device_id atc2603c_audio_of_match[]= {
+	{.compatible = "actions,atc2603c-audio",},
+	{}
+};
+MODULE_DEVICE_TABLE(of, atc2603c_audio_of_match);
+
+static struct platform_driver atc2603c_platform_driver = {
+	.probe      = atc2603c_platform_probe,
+	.remove     = atc2603c_platform_remove,
+	.driver     = {
+		.name   = "atc2603c-audio",
+		.owner  = THIS_MODULE,
+		.of_match_table = atc2603c_audio_of_match,
+	},
+	.shutdown	= atc2603c_platform_shutdown,
+};
+
+static int atc2603c_get_cfg(void)
+{
+	u32 ret = 1;
+	struct device_node *dn;
+
+	dn = of_find_compatible_node(NULL, NULL, audio_device_node);
+	if (!dn) {
+		snd_err("Fail to get device_node\r\n");
+		goto of_get_failed;
+	}
+
+	ret = of_property_read_u32(dn, snd_earphone_output_mode,
+		&audio_hw_cfg.earphone_output_mode);
+	if (ret) {
+		snd_err("Fail to get snd_earphone_output_mode\r\n");
+		goto of_get_failed;
+	}
+
+	ret = of_property_read_u32(dn, snd_mic_num,
+		&audio_hw_cfg.mic_num);
+	if (ret) {
+		snd_err("Fail to get snd_mic_num\r\n");
+		goto of_get_failed;
+	}
+
+	ret = of_property_read_u32_array(dn, snd_mic0_gain,
+		audio_hw_cfg.mic0_gain, 2);
+	if (ret) {
+		snd_err("Fail to get snd_mic_gain\r\n");
+		goto of_get_failed;
+	}
+
+	ret = of_property_read_u32_array(dn, snd_speaker_gain,
+		audio_hw_cfg.speaker_gain, 2);
+	if (ret) {
+		snd_err("Fail to get snd_speaker_gain\r\n");
+		goto of_get_failed;
+	}
+
+	ret = of_property_read_u32_array(dn, snd_earphone_gain,
+		audio_hw_cfg.earphone_gain, 2);
+	if (ret) {
+		snd_err("Fail to get snd_earphone_gain\r\n");
+		goto of_get_failed;
+	}
+
+/*
+	ret = of_property_read_u32(dn, snd_speaker_volume,
+		&audio_hw_cfg.speaker_volume);
+	if (ret) {
+		snd_err("Fail to get snd_speaker_volume\r\n");
+		goto of_get_failed;
+	}
+
+	ret = of_property_read_u32(dn, snd_earphone_volume,
+		&audio_hw_cfg.earphone_volume);
+	if (ret) {
+		snd_err("Fail to get snd_earphone_volume\r\n");
+		goto of_get_failed;
+	}
+
+	ret = of_property_read_u32(dn, snd_earphone_detect_mode,
+		&audio_hw_cfg.earphone_detect_mode);
+	if (ret) {
+		snd_err("Fail to get snd_earphone_detect_mode\r\n");
+		goto of_get_failed;
+	}
+*/
+	audio_hw_cfg.speaker_volume = 0x28;
+	audio_hw_cfg.earphone_volume = 0x28;
+	audio_hw_cfg.earphone_detect_mode = 0;
+
+	//20141202 change_code by yuchen : dont force fail on this one, there's a default value.
+	//default to differential
+	ret = of_property_read_u32(dn, snd_mic_mode,
+		&audio_hw_cfg.mic_mode);
+	if (ret) {
+		printk("fail get snd_mic_mode\r\n");
+		audio_hw_cfg.mic_mode = 1;
+		//goto of_get_failed;
+	}
+
+	//20150104 change_code by yuchen : add earphone detect method config
+	//0 for gpio, 1 for irq, 2 for adc
+	ret = of_property_read_u32(dn, snd_earphone_detect_method,
+		&audio_hw_cfg.earphone_detect_method);
+	if (ret) {
+		printk("fail get earphone_detect_method\r\n");
+		audio_hw_cfg.earphone_detect_method = 0;
+		//goto of_get_failed;
+	}
+	
+	if(audio_hw_cfg.earphone_detect_method == 2)
+	{
+		ret = of_property_read_u32(dn, snd_adc_plugin_threshold,
+			&audio_hw_cfg.adc_plugin_threshold);
+		if (ret) {
+			printk("fail get snd_adc_plugin_threshold\r\n");
+			audio_hw_cfg.adc_plugin_threshold = 900;
+			//goto of_get_failed;
+		}		
+	}			
+	
+	//fixme
+	ret = of_property_read_u32(dn, snd_adc_level,
+		&audio_hw_cfg.adc_level);
+	if (ret) {
+		printk("fail get adc level\r\n");
+		audio_hw_cfg.adc_level = 1;
+		//goto of_get_failed;
+	}		
+
+	speaker_gpio_num = of_get_named_gpio_flags(dn, speaker_ctrl_name, 0, &speaker_gpio_level);
+	if (speaker_gpio_num < 0) {
+		snd_err("get gpio[%s] fail\r\n", speaker_ctrl_name);
+	}
+	speaker_gpio_active = (speaker_gpio_level & OF_GPIO_ACTIVE_LOW);
+			
+	earphone_gpio_num = of_get_named_gpio_flags(dn, earphone_detect_gpio, 0, NULL);
+	if (earphone_gpio_num < 0) {
+		snd_dbg("no earphone detect gpio\r\n");
+	}
+	
+
+	return 0;
+of_get_failed:
+	return ret;
+}
+
+static void atc2603c_dump_cfg(void)
+{
+#if 0
+	printk(KERN_ERR"earphone_detect_mode = %d\r\n",audio_hw_cfg.earphone_detect_mode);
+	printk(KERN_ERR"earphone_gain[0] = %d\r\n",audio_hw_cfg.earphone_gain[0]);
+	printk(KERN_ERR"earphone_gain[1] = %d\r\n",audio_hw_cfg.earphone_gain[1]);
+	printk(KERN_ERR"speaker_gain[0] = %d\r\n",audio_hw_cfg.speaker_gain[0]);
+	printk(KERN_ERR"speaker_gain[1] = %d\r\n",audio_hw_cfg.speaker_gain[1]);
+	printk(KERN_ERR"mic0_gain[0] = %d\r\n",audio_hw_cfg.mic0_gain[0]);
+	printk(KERN_ERR"mic0_gain[1] = %d\r\n",audio_hw_cfg.mic0_gain[1]);
+	printk(KERN_ERR"earphone_volume = %d\r\n",audio_hw_cfg.earphone_volume);
+	printk(KERN_ERR"speaker_volume = %d\r\n",audio_hw_cfg.speaker_volume);
+	printk(KERN_ERR"earphone_output_mode = %d\r\n",audio_hw_cfg.earphone_output_mode);
+	printk(KERN_ERR"mic_num = %d\r\n",audio_hw_cfg.mic_num);
+#endif
+}
+
+static int atc2603c_pa_down_notifier(struct notifier_block *notifier,
+				       unsigned long pm_event, void *v)
+{
+	mutex_lock(&atc2603c_pa_down_lock);
+
+	switch (pm_event) {
+
+		case PM_SUSPEND_PREPARE:
+			user_lock = 1;
+			snd_soc_update_bits(atc2603c_codec,
+				AUDIOINOUT_CTL,
+				0x01 << 1, 0x01 << 1);
+			atc2603c_power_down(atc2603c_codec);
+			snd_soc_update_bits(atc2603c_codec,
+				AUDIOINOUT_CTL,
+				0x01 << 1, 0);
+			break;
+
+		case PM_POST_SUSPEND:
+			user_lock = 0;
+			break;
+	}
+	mutex_unlock(&atc2603c_pa_down_lock);
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block atc2603c_pa_down_nb = {
+	.notifier_call = atc2603c_pa_down_notifier,
+};
+
+static int dbgflag;
+
+
+static ssize_t dbgflag_show_file (struct device *dev, struct device_attribute *attr,
+        char *buf)
+{
+    return sprintf(buf, "%d\n", dbgflag);
+}
+
+static ssize_t dbgflag_store_file(struct device *dev, struct device_attribute *attr,
+        const char *buf, size_t count)
+{
+	char *endp;	
+	size_t size;
+	int flag = 0;
+
+	if (count > 0) {
+		flag = simple_strtoul(buf,&endp,0);
+		size = endp - buf;
+
+		if (*endp && (((*endp)==0x20)||((*endp)=='\n')||((*endp)=='\t')))	
+		    size++;
+
+		if (size != count)	
+		{
+			snd_err("%s %d %s, %d", __FUNCTION__, __LINE__, buf, flag);		
+			return -EINVAL;
+		}
+	}
+
+	snd_err("%s %d", __FUNCTION__, __LINE__);
+	dbgflag = flag;
+
+	return 0;
+}
+static DEVICE_ATTR(dbgflag, 0744, dbgflag_show_file, dbgflag_store_file);
+
+static int __init atc2603c_init(void)
+{
+	u32 ret = 0;
+
+	printk("atc2603c_init\n");
+
+	ret = atc2603c_get_cfg();
+	if (ret){
+		snd_err("audio get cfg failed!\r\n");
+		goto audio_get_cfg_failed;
+	}
+
+	atc2603c_dump_cfg();
+
+	direct_drive_disable = audio_hw_cfg.earphone_output_mode;
+	//snd_err("direct_drive_disable %d\n", direct_drive_disable);
+
+	ret = platform_driver_register(&atc2603c_platform_driver);
+	if(ret){
+		snd_err("platform_driver_register failed!\r\n");
+		goto platform_driver_register_failed;
+	}
+
+	//dev = bus_find_device_by_name(&platform_bus_type, NULL, "atc260x-audio");
+
+
+	register_pm_notifier(&atc2603c_pa_down_nb);
+
+	//20150103 change_code by yuchen: set adc_detect_mode by earphone detect method
+	if(audio_hw_cfg.earphone_detect_method == 2)
+	{
+		adc_detect_mode = 1;
+	}	
+	else
+	{
+		adc_detect_mode = 0;
+	}
+	
+	if((audio_hw_cfg.earphone_detect_method == 1) || (audio_hw_cfg.earphone_detect_method == 2))
+	{
+		headphone_sdev.name = "h2w";
+		ret = switch_dev_register(&headphone_sdev);
+		if (ret < 0) {
+			snd_err("failed to register switch dev for h2w\n");
+		}	
+		
+		dbgflag = 0;
+    		ret = device_create_file(headphone_sdev.dev, &dev_attr_dbgflag);
+    		if (ret)
+    		{
+    			snd_err("failed to device_create_file\n");
+        	}
+		
+			
+	}
+
+	return 0;
+platform_driver_register_failed:
+audio_get_cfg_failed:
+	return ret;
+}
+
+static void __exit atc2603c_exit(void)
+{
+	platform_driver_unregister(&atc2603c_platform_driver);
+	switch_dev_unregister(&headphone_sdev);
+}
+
+module_init(atc2603c_init);
+module_exit(atc2603c_exit);
+
+
+MODULE_AUTHOR("sall.xie <sall.xie at actions-semi.com>");
+MODULE_DESCRIPTION("ATC2603C AUDIO module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/atc260x/atc2603c-codec/atc2603c-audio-regs.h b/sound/soc/atc260x/atc2603c-codec/atc2603c-audio-regs.h
new file mode 100755
index 0000000..033bd37
--- /dev/null
+++ b/sound/soc/atc260x/atc2603c-codec/atc2603c-audio-regs.h
@@ -0,0 +1,244 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2009 Actions Semi Inc.
+ */
+
+#ifndef __ATC2603C_AUDIO_REGS_H__
+#define __ATC2603C_AUDIO_REGS_H__
+
+/* AUDIOINOUT_CTL */
+#define AUDIOINOUT_CTL_INEN		(0x1 << 1)
+#define AUDIOINOUT_CTL_LB		(0x1 << 4)
+#define AUDIOINOUT_CTL_IMS(x)		(((x) & 0x3) << 5)
+#define AUDIOINOUT_CTL_OMD		(0x1 << 7)
+#define AUDIOINOUT_CTL_OEN		(0x1 << 8)
+#define AUDIOINOUT_CTL_OCIEN		(0x1 << 9)
+#define AUDIOINOUT_CTL_OHSCIEN		(0x1 << 10)
+#define AUDIOINOUT_CTL_MDD		(0x1 << 11)
+#define AUDIOINOUT_CTL_EIDR		(0x1 << 12)
+
+/* DAC_DIGITALCTL */
+#define DAC_DIGITALCTL_DEFL		(0x1 << 0)
+#define DAC_DIGITALCTL_DEFL_SFT         (0)
+#define DAC_DIGITALCTL_DEFR		(0x1 << 1)
+#define DAC_DIGITALCTL_DEFR_SFT		(1)
+#define DAC_DIGITALCTL_DESW		(0x1 << 2)
+#define DAC_DIGITALCTL_DEC		(0x1 << 3)
+#define DAC_DIGITALCTL_DESL		(0x1 << 4)
+#define DAC_DIGITALCTL_DESR		(0x1 << 5)
+#define DAC_DIGITALCTL_DESBL		(0x1 << 6)
+#define DAC_DIGITALCTL_DESBR		(0x1 << 7)
+#define DAC_DIGITALCTL_DMFL		(0x1 << 8)
+#define DAC_DIGITALCTL_DMFR		(0x1 << 9)
+#define DAC_DIGITALCTL_DMSW		(0x1 << 10)
+#define DAC_DIGITALCTL_DMC		(0x1 << 11)
+#define DAC_DIGITALCTL_DMSL		(0x1 << 12)
+#define DAC_DIGITALCTL_DMSR		(0x1 << 13)
+#define DAC_DIGITALCTL_DMSBL		(0x1 << 14)
+#define DAC_DIGITALCTL_DMSBR		(0x1 << 15)
+
+/* DAC_VOLUMECTL0 */
+#define DAC_VOLUMECTL0_DACFL_VOLUME(x)	(((x) & 0xff) << 0)
+#define DAC_VOLUMECTL0_DACFL_VOLUME_SFT	(0)
+#define DAC_VOLUMECTL0_DACFR_VOLUME(x)	(((x) & 0xff) << 8)
+#define DAC_VOLUMECTL0_DACFR_VOLUME_SFT	(8)
+
+
+/* DAC_ANALOG0 */
+#define DAC_ANALOG0_OPGIB(x)		(((x) & 0x7) << 0)
+#define DAC_ANALOG0_KFEN		(0x1 << 3)
+#define DAC_ANALOG0_OPVBIB(x)		(((x) & 0x3) << 4)
+#define DAC_ANALOG0_OPDTSIB(x)		(((x) & 0x3) << 6)
+#define DAC_ANALOG0_OPDAIB(x)		(((x) & 0x7) << 8)
+#define DAC_ANALOG0_OPDAVB(x)		(((x) & 0x3) << 12)
+#define DAC_ANALOG0_PAIB(x)		(((x) & 0x3) << 14)
+
+/* DAC_ANALOG1 */
+#define DAC_ANALOG1_VOLUME(x)		(((x) & 0x3f) << 0)
+#define DAC_ANALOG1_VOLUME_SFT		(0)
+#define DAC_ANALOG1_PASW		(0x1 << 6)
+#define DAC_ANALOG1_PASW_SFT		(6)
+#define DAC_ANALOG1_ZERODT		(0x1 << 7)
+#define DAC_ANALOG1_PAIQ(x)		(((x) & 0x3) << 8)
+#define DAC_ANALOG1_DACFL_FRMUTE	(0x1 << 10)
+#define DAC_ANALOG1_DACFL_FRMUTE_SFT	(10)
+#define DAC_ANALOG1_DACSW_CMUTE		(0x1 << 11)
+#define DAC_ANALOG1_DACSL_SRMUTE	(0x1 << 12)
+#define DAC_ANALOG1_DACSBL_SBRMUTE	(0x1 << 13)
+#define DAC_ANALOG1_DACFMMUTE		(0x1 << 14)
+#define DAC_ANALOG1_DACFMMUTE_SFT	(14)
+#define DAC_ANALOG1_DACMICMUTE		(0x1 << 15)
+#define DAC_ANALOG1_DACMICMUTE_SFT	(15)
+
+/* DAC_ANALOG2 */
+#define DAC_ANALOG2_OPVROOSIB(x)	(((x) & 0x7) << 0)
+#define DAC_ANALOG2_DDATPR		(0x1 << 3)
+#define DAC_ANALOG2_OPVROEN		(0x1 << 4)
+#define DAC_ANALOG2_DDOVV		(0x1 << 5)
+#define DAC_ANALOG2_CLDMIX(x)		(((x) & 0x3) << 6)
+#define DAC_ANALOG2_PAVDC		(0x1 << 8)
+#define DAC_ANALOG2_ATP2CE		(0x1 << 9)
+#define DAC_ANALOG2_P2IB		(0x1 << 10)
+#define DAC_ANALOG2_DACI		(0x1 << 11)
+#define DAC_ANALOG2_ZERODETECT		(0x1 << 15)
+
+/* DAC_ANALOG3 */
+#define DAC_ANALOG3_DACEN_FR		(0x1)
+#define DAC_ANALOG3_DACEN_FR_SFT	(0)
+#define DAC_ANALOG3_DACEN_FL		(0x1 << 1)
+#define DAC_ANALOG3_DACEN_FL_SFT	(1)
+#define DAC_ANALOG3_PAEN_FR_FL		(0x1 << 2)
+#define DAC_ANALOG3_PAEN_FR_FL_SFT	(2)
+#define DAC_ANALOG3_PAOSEN_FR_FL	(0x1 << 3)
+#define DAC_ANALOG3_PAOSEN_FR_FL_SFT	(3)
+
+/*
+#define DAC_ANALOG3_OPVROIB(x)		(((x) & 0x7) << 0)
+#define DAC_ANALOG3_OPCM1IB(x)		(((x) & 0x3) << 3)
+#define DAC_ANALOG3_ATPLP2_SBR_SBL	(0x1 << 5)
+#define DAC_ANALOG3_ATPLP2_SR_SL	(0x1 << 6)
+#define DAC_ANALOG3_ATPLP2_SW_C		(0x1 << 7)
+#define DAC_ANALOG3_ATPLP2_FR_FL	(0x1 << 8)
+#define DAC_ANALOG3_BIASEN		(0x1 << 9)
+#define DAC_ANALOG3_EIDEN		(0x1 << 10)
+#define DAC_ANALOG3_VLCHD		(0x1 << 13)
+#define DAC_ANALOG3_OVLS		(0x1 << 14)
+#define DAC_ANALOG3_EIDS		(0x1 << 15)
+*/
+
+/* ADC_DIGITALCTL */
+#define ADC_DIGITALCTL_ADGC0		(((x) & 0xf) << 6)
+#define ADC_DIGITALCTL_ADGC0_SFT	(6)
+
+/* ADC0_HPFCTL */
+#define ADC0_HPFCTL_HPF0REN		(0x1 << 0)
+#define ADC0_HPFCTL_HPF0LEN		(0x1 << 1)
+#define ADC0_HPFCTL_HPF0DW		(0x1 << 2)
+#define ADC0_HPFCTL_WNHPF0CUT(x)	(((x) & 0x7) << 3)
+#define ADC0_HPFCTL_SRSEL0(x)		(((x) & 0x3) << 6)
+
+
+/* ADC_CTL */
+#define ADC_CTL_ATAD_MTA_FTA_SFT	(0)
+#define ADC_CTL_AD0REN			(0x1 << 3)
+#define ADC_CTL_AD0REN_SFT		(3)
+#define ADC_CTL_AD0LEN			(0x1 << 4)
+#define ADC_CTL_AD0LEN_SFT		(4)
+#define ADC_CTL_MIC0FDSE		(0x1 << 5)
+#define ADC_CTL_MIC0FDSE_SFT		(5)
+#define ADC_CTL_MIC0REN			(0x1 << 6)
+#define ADC_CTL_MIC0REN_SFT		(6)
+#define ADC_CTL_MIC0LEN			(0x1 << 7)
+#define ADC_CTL_MIC0LEN_SFT		(7)
+#define ADC_CTL_FMREN			(0x1 << 13)
+#define ADC_CTL_FMREN_SFT		(13)
+#define ADC_CTL_FMLEN			(0x1 << 14)
+#define ADC_CTL_FMLEN_SFT		(14)
+
+
+
+/* AGC_CTL0 */
+#define AGC_CTL0_AMP0GR1(x)		(((x) & 0x7) << 0)
+#define AGC_CTL0_AMP0GR1_SET		(0)
+#define AGC_CTL0_IMICSHD		(0x1 << 7)
+#define AGC_CTL0_AMP1G0R(x)		(((x) & 0xf) << 8)
+#define AGC_CTL0_AMP1G0R_SFT		(8)
+#define AGC_CTL0_AMP1G0L(x)		(((x) & 0xf) << 12)
+#define AGC_CTL0_AMP1G0L_SFT		(12)
+
+#define AGC_CTL0_AMP1GR1_MSK		(0x7 << 0)
+#define AGC_CTL0_AMP1GR_MSK		(0xf << 8)
+#define AGC_CTL0_AMP1GL_MSK		(0xf << 12)
+
+#define AGC_CTL0_VMICINEN		(0x1 << 3)
+#define AGC_CTL0_VMICINEN_SFT		(3)
+#define AGC_CTL0_VMICEXST		(((x) & 0x3) << 4)
+#define AGC_CTL0_VMICEXST_SFT		(4)
+#define AGC_CTL0_VMICEXEN		(0x1 << 6)
+#define AGC_CTL0_VMICEXEN_SFT		(6)
+
+/* ADC_ANALOG0 */
+#define ADC_ANALOG0_VRDABC(x)		(((x) & 0x7) << 0)
+#define ADC_ANALOG0_OPBC23(x)		(((x) & 0x3) << 3)
+#define ADC_ANALOG0_OPBC1(x)		(((x) & 0x7) << 5)
+#define ADC_ANALOG0_IVSRMSTN(x)		(((x) & 0x7) << 13)
+
+/* ADC_ANALOG1 */
+#define ADC_ANALOG1_FMBC(x)		(((x) & 0x3) << 0)
+#define ADC_ANALOG1_FD1BUFBC(x)		(((x) & 0x3) << 2)
+#define ADC_ANALOG1_FD2BC(x)		(((x) & 0x3) << 4)
+#define ADC_ANALOG1_FD1BC(x)		(((x) & 0x3) << 6)
+#define ADC_ANALOG1_ADCBIAS		(0x1 << 10)
+#define ADC_ANALOG1_LPFBUFBC(x)		(((x) & 0x3) << 11)
+#define ADC_ANALOG1_LPFBC(x)		(((x) & 0x7) << 13)
+
+/* I2S_CTL */
+#define I2S_CTL_I2STEN			(0x1 << 0)
+#define I2S_CTL_I2SREN			(0x1 << 1)
+#define I2S_CTL_I2STOWL			(0x1 << 2)
+#define I2S_CTL_I2STTDMRF		(0x1 << 3)
+#define I2S_CTL_I2STXM(x)		(((x) & 0x7) << 4)
+#define I2S_CTL_I2SRXM(x)		(((x) & 0x3) << 8)
+#define I2S_CTL_I2SRCS			(0x1 << 10)
+#define I2S_CTL_I2SPM(x)		(((x) & 0x3) << 11)
+
+/* I2S_FIFOCTL */
+#define I2S_FIFOCTL_I2STFR		(0x1 << 0)
+#define I2S_FIFOCTL_I2STFDEN		(0x1 << 1)
+#define I2S_FIFOCTL_I2STFIEN		(0x1 << 2)
+#define I2S_FIFOCTL_I2STFIP		(0x1 << 3)
+#define I2S_FIFOCTL_I2STFDCF(x)		(((x) & 0x7) << 4)
+#define I2S_FIFOCTL_I2STFDRF		(0x1 << 7)
+#define I2S_FIFOCTL_I2STFFF		(0x1 << 8)
+#define I2S_FIFOCTL_I2SRFR		(0x1 << 9)
+#define I2S_FIFOCTL_I2SRFDEN		(0x1 << 10)
+#define I2S_FIFOCTL_I2SRFIEN		(0x1 << 11)
+#define I2S_FIFOCTL_I2SRFIP		(0x1 << 12)
+#define I2S_FIFOCTL_I2SRFDCF(x)		(((x) & 0x3) << 13)
+#define I2S_FIFOCTL_I2STXKA		(0x1 << 15)
+#define I2S_FIFOCTL_I2SRFDRF		(0x1 << 16)
+#define I2S_FIFOCTL_I2SRFEF		(0x1 << 17)
+#define I2S_FIFOCTL_I2STFSS		(0x1 << 18)
+#define I2S_FIFOCTL_KMCMMI2ST(x)	(((x) & 0x3) << 19)
+
+/* SPDIF_HDMI_CTL */
+#define SPDIF_HDMI_CTL_SPDFR		(0x1 << 0)
+#define SPDIF_HDMI_CTL_HDMIFR		(0x1 << 1)
+#define SPDIF_HDMI_CTL_SPDFIP		(0x1 << 2)
+#define SPDIF_HDMI_CTL_SPDFFF		(0x1 << 3)
+#define SPDIF_HDMI_CTL_SPDFDEN		(0x1 << 4)
+#define SPDIF_HDMI_CTL_SPDFIEN		(0x1 << 5)
+#define SPDIF_HDMI_CTL_HDMFIP		(0x1 << 6)
+#define SPDIF_HDMI_CTL_HDMFFF		(0x1 << 7)
+#define SPDIF_HDMI_CTL_HDMFDEN		(0x1 << 8)
+#define SPDIF_HDMI_CTL_HDMFIEN		(0x1 << 9)
+#define SPDIF_HDMI_CTL_SPDEN		(0x1 << 10)
+#define SPDIF_HDMI_CTL_SPDKA		(0x1 << 11)
+#define SPDIF_HDMI_CTL_HDMKA		(0x1 << 12)
+#define SPDIF_HDMI_CTL_SPDFSS		(0x1 << 13)
+#define SPDIF_HDMI_CTL_HDMFSS		(0x1 << 14)
+#define SPDIF_HDMI_CTL_KMCMMHDM(x)	(((x) & 0x3) << 15)
+
+/* CMU_AUDIOPLL */
+#define CMU_AUDIOPLL_AUDIOPLLS		(0x1 << 0)
+#define CMU_AUDIOPLL_APEN		(0x1 << 4)
+#define CMU_AUDIOPLL_I2STX_CLK(x)	(((x) & 0xf) << 16)
+#define CMU_AUDIOPLL_I2SRX_CLK(x)	(((x) & 0xf) << 20)
+#define CMU_AUDIOPLL_HDMIA_CLK(x)	(((x) & 0xf) << 24)
+#define CMU_AUDIOPLL_SPDIF_CLK(x)	(((x) & 0xf) << 28)
+
+/* CMU_DEVCLKEN */
+#define CMU_DEVCLKEN0_I2STX		(0x1 << 20)
+#define CMU_DEVCLKEN0_I2SRX		(0x1 << 21)
+#define CMU_DEVCLKEN0_HDMIA		(0x1 << 22)
+#define CMU_DEVCLKEN0_SPDIF		(0x1 << 23)
+
+#define CMU_DEVRST0_AUDIO		(0x1 << 17)
+
+#define GL5302_DEVRST_AUDIO_CLK_EN	(0x1 << 10)
+#define GL5302_DEVRST_AUDIO_RST		(0x1 << 4)
+
+#endif  /* ifndef __ATC2603C_AUDIO_REGS_H__ */
diff --git a/sound/soc/atc260x/common-regs-owl.h b/sound/soc/atc260x/common-regs-owl.h
new file mode 100755
index 0000000..5668f3a
--- /dev/null
+++ b/sound/soc/atc260x/common-regs-owl.h
@@ -0,0 +1,205 @@
+/*
+ * reg-atm7059.h
+ *
+ */
+
+#ifndef __REG_5206_H__ 
+#define __REG_5206_H__
+
+/*I2S register definition*/
+#define I2S_SPDIF_BASE                              0xB0100000
+
+#define I2S_CTL                                     (0x0000)
+#define I2S_FIFOCTL                                 (0x0004)
+#define I2STX_DAT                                   (0x0008)
+#define I2SRX_DAT                                   (0x000c)
+#define SPDIF_HDMI_CTL                              (0x0010)
+#define SPDIF_DAT                                   (0x0014)
+#define SPDIF_CLSTAT                                (0x0018)
+#define SPDIF_CHSTAT                                (0x001c)
+#define HDMI_DAT                                    (0x0020)
+#define I2STX_DAT_DBG                               (0x0024)
+#define I2SRX_DAT_DBG                               (0x0028)
+#define I2STX_SPDIF_HDMI_CTL                        (0x002c)
+#define I2STX_SPDIF_HDMI_DAT                        (0x0030)
+
+/*GPIO MFP register definition*/
+#define GPIO_MFP_PWM_BASE                           0xB01B0000
+
+#define GPIO_AOUTEN                                 (0x0000)
+#define GPIO_AINEN                                  (0x0004)
+#define GPIO_ADAT                                   (0x0008)
+#define GPIO_BOUTEN                                 (0x000C)
+#define GPIO_BINEN                                  (0x0010)
+#define GPIO_BDAT                                   (0x0014)
+#define GPIO_COUTEN                                 (0x0018)
+#define GPIO_CINEN                                  (0x001C)
+#define GPIO_CDAT                                   (0x0020)
+#define GPIO_DOUTEN                                 (0x0024)
+#define GPIO_DINEN                                  (0x0028)
+#define GPIO_DDAT                                   (0x002C)
+#define GPIO_EOUTEN                                 (0x0030)
+#define GPIO_EINEN                                  (0x0034)
+#define GPIO_EDAT                                   (0x0038)
+#define MFP_CTL0                                    (0x0040)
+#define MFP_CTL1                                    (0x0044)
+#define MFP_CTL2                                    (0x0048)
+#define MFP_CTL3                                    (0x004C)
+#define PWM_CTL0                                    (0X50)
+#define PWM_CTL1                                    (0X54)
+#define PWM_CTL2                                    (0X58)
+#define PWM_CTL3                                    (0X5C)
+#define PAD_PULLCTL0                                (0x0060)
+#define PAD_PULLCTL1                                (0x0064)
+#define PAD_PULLCTL2                                (0x0068)
+#define PAD_ST0                                     (0x006C)
+#define PAD_ST1                                     (0x0070)
+#define PAD_CTL                                     (0x0074)
+#define SPEED_SENSOR_CTL                            (0x007C)
+#define PAD_DRV0                                    (0x0080)
+#define PAD_DRV1                                    (0x0084)
+#define PAD_DRV2                                    (0x0088)
+#define DEBUG_SEL                                   (0x0090)
+#define DEBUG_OEN0                                  (0x0094)
+#define DEBUG_OEN1                                  (0x0098)
+#define DEBUG_IEN0                                  (0x009C)
+#define DEBUG_IEN1                                  (0x00A0)
+#define MEM_MARGIN_CTRL0                            (0x00B0)
+#define MEM_MARGIN_CTRL1                            (0x00B4)
+#define BIST_START0                                 (0x00C0)
+#define BIST_START1                                 (0x00C4)
+#define BIST_DONE0                                  (0x00C8)
+#define BIST_DONE1                                  (0x00CC)
+#define BIST_FAIL0                                  (0x00D0)
+#define BIST_FAIL1                                  (0x00D4)
+#define INTC_EXTCTL                                 (0x0200)
+#define INTC_GPIOCTL                                (0x0204)
+#define INTC_GPIOA_PD                               (0x0208)
+#define INTC_GPIOA_MSK                              (0x020c)
+#define INTC_GPIOB_PD                               (0x0210)
+#define INTC_GPIOB_MSK                              (0x0214)
+#define INTC_GPIOC_PD                               (0x0218)
+#define INTC_GPIOC_MSK                              (0x021c)
+#define INTC_GPIOD_PD                               (0x0220)
+#define INTC_GPIOD_MSK                              (0x0224)
+#define INTC_GPIOE_PD                               (0x0228)
+#define INTC_GPIOE_MSK                              (0x022c)
+#define INTC_GPIOA_TYPE0                            (0x0230)
+#define INTC_GPIOA_TYPE1                            (0x0234)
+#define INTC_GPIOB_TYPE0                            (0x0238)
+#define INTC_GPIOB_TYPE1                            (0x023c)
+#define INTC_GPIOC_TYPE0                            (0x0240)
+#define INTC_GPIOC_TYPE1                            (0x0244)
+#define INTC_GPIOD_TYPE0                            (0x0248)
+#define INTC_GPIOD_TYPE1                            (0x024C)
+#define INTC_GPIOE_TYPE                             (0x0250)
+
+
+/* HDMI register definition*/
+#define     HDMIHW_REG_MEM_BASE                                               0xB02C0000
+
+#define     HDMI_VICTL                                                        (0x0000)
+#define     HDMI_VIVSYNC                                                      (0x0004)
+#define     HDMI_VIVHSYNC                                                     (0x0008)
+#define     HDMI_VIALSEOF                                                     (0x000C)
+#define     HDMI_VIALSEEF                                                     (0x0010)
+#define     HDMI_VIADLSE                                                      (0x0014)
+#define     HDMI_AIFRAMEC                                                     (0x0020)
+#define     HDMI_AICHSTABYTE0TO3                                              (0x0024)
+#define     HDMI_AICHSTABYTE4TO7                                              (0x0028)
+#define     HDMI_AICHSTABYTE8TO11                                             (0x002C)
+#define     HDMI_AICHSTABYTE12TO15                                            (0x0030)
+#define     HDMI_AICHSTABYTE16TO19                                            (0x0034)
+#define     HDMI_AICHSTABYTE20TO23                                            (0x0038)
+#define     HDMI_AICHSTASCN                                                   (0x003C)
+#define     HDMI_VR                                                           (0x0050)
+#define     HDMI_CR                                                           (0x0054)
+#define     HDMI_SCHCR                                                        (0x0058)
+#define     HDMI_ICR                                                          (0x005C)
+#define     HDMI_SCR                                                          (0x0060)
+#define     HDMI_LPCR                                                         (0x0064)
+#define     HDCP_CR                                                           (0x0068)
+#define     HDCP_SR                                                           (0x006C)
+#define     HDCP_ANLR                                                         (0x0070)
+#define     HDCP_ANMR                                                         (0x0074)
+#define     HDCP_ANILR                                                        (0x0078)
+#define     HDCP_ANIMR                                                        (0x007C)
+#define     HDCP_DPKLR                                                        (0x0080)
+#define     HDCP_DPKMR                                                        (0x0084)
+#define     HDCP_LIR                                                          (0x0088)
+#define     HDCP_SHACR                                                        (0x008C)
+#define     HDCP_SHADR                                                        (0x0090)
+#define     HDCP_ICR                                                          (0x0094)
+#define     HDCP_KMMR                                                         (0x0098)
+#define     HDCP_KMLR                                                         (0x009C)
+#define     HDCP_MILR                                                         (0x00A0)
+#define     HDCP_MIMR                                                         (0x00A4)
+#define     HDCP_KOWR                                                         (0x00A8)
+#define     HDCP_OWR                                                          (0x00AC)
+#define     TMDS_STR0                                                         (0x00B8)
+#define     TMDS_STR1                                                         (0x00BC)
+#define     TMDS_EODR0                                                        (0x00C0)
+#define     TMDS_EODR1                                                        (0x00C4)
+#define     HDMI_ASPCR                                                        (0x00D0)
+#define     HDMI_ACACR                                                        (0x00D4)
+#define     HDMI_ACRPCR                                                       (0x00D8)
+#define     HDMI_ACRPCTSR                                                     (0x00DC)
+#define     HDMI_ACRPPR                                                       (0x00E0)
+#define     HDMI_GCPCR                                                        (0x00E4)
+#define     HDMI_RPCR                                                         (0x00E8)
+#define     HDMI_RPRBDR                                                       (0x00EC)
+#define     HDMI_OPCR                                                         (0x00F0)
+#define     HDMI_DIPCCR                                                       (0x00F4)
+#define     HDMI_ORP6PH                                                       (0x00F8)
+#define     HDMI_ORSP6W0                                                      (0x00FC)
+#define     HDMI_ORSP6W1                                                      (0x0100)
+#define     HDMI_ORSP6W2                                                      (0x0104)
+#define     HDMI_ORSP6W3                                                      (0x0108)
+#define     HDMI_ORSP6W4                                                      (0x010C)
+#define     HDMI_ORSP6W5                                                      (0x0110)
+#define     HDMI_ORSP6W6                                                      (0x0114)
+#define     HDMI_ORSP6W7                                                      (0x0118)
+#define     HDMI_CECCR                                                        (0x011C)
+#define     HDMI_CECRTCR                                                      (0x0120)
+#define     HDMI_CECRXCR                                                      (0x0124)
+#define     HDMI_CECTXCR                                                      (0x0128)
+#define     HDMI_CECTXDR                                                      (0x012C)
+#define     HDMI_CECRXDR                                                      (0x0130)
+#define     HDMI_CECRXTCR                                                     (0x0134)
+#define     HDMI_CECTXTCR0                                                    (0x0138)
+#define     HDMI_CECTXTCR1                                                    (0x013C)
+#define     HDMI_CRCCR                                                        (0x0140)
+#define     HDMI_CRCDOR                                                       (0x0144)
+#define     HDMI_TX_1                                                         (0x0154)
+#define     HDMI_TX_2                                                         (0x0158)
+#define     CEC_DDC_HPD                                                       (0x015C)
+#define     MHL_PHYCTL1                                                       (0x0160)
+#define     MHL_PHYCTL2                                                       (0x0164)
+#define     MHL_PHYCTL3                                                       (0x0168)
+#define     MHL_CR                                                            (0x0180)
+#define     MHL_INTMSK                                                        (0x0184)
+#define     MHL_INTPD                                                         (0x0188)
+#define     MHL_INTSR                                                         (0x018c)
+#define     MSC_REQMSGR                                                       (0x0190)
+#define     MSC_REQRMSGR                                                      (0x0194)
+#define     MSC_RSPRMR                                                        (0x0198)
+#define     MSC_RSPRFIFO                                                      (0x019c)
+#define     MSC_RSPRRMR                                                       (0x01a0)
+#define     MHL_DDCCSR                                                        (0x01a4)
+#define     MHL_DDCPR                                                         (0x01a8)
+#define     CBUS_DCR0TO3                                                      (0x01b0)
+#define     CBUS_DCR4TO7                                                      (0x01b4)
+#define     CBUS_DCR8TOB                                                      (0x01b8)
+#define     CBUS_DCRCTOF                                                      (0x01bc)
+#define     CBUS_DEVINTR                                                      (0x01c0)
+#define     CBUS_DEVSR                                                        (0x01c4)
+#define     CBUS_SPR0TO3                                                      (0x01c8)
+#define     CBUS_SPR4TO7                                                      (0x01cc)
+#define     CBUS_SPR8TOB                                                      (0x01d0)
+#define     CBUS_SPRCTOF                                                      (0x01d4)
+#define     CBUS_VID                                                          (0x01d8)
+#define     CBUS_LLTCR                                                        (0x01e0)
+#define     CBUS_TLTCR                                                        (0x01e4)
+#define     MHL_DEBUG                                                         (0x1f0)
+
+#endif
diff --git a/sound/soc/atc260x/dai-owl.c b/sound/soc/atc260x/dai-owl.c
new file mode 100755
index 0000000..e10232f
--- /dev/null
+++ b/sound/soc/atc260x/dai-owl.c
@@ -0,0 +1,875 @@
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+
+#include <linux/clk.h>			/* clk_enable */
+#include <mach/clkname.h>
+#include <linux/cpufreq.h>
+#include <linux/io.h> 
+#include <linux/ioport.h>
+#include "sndrv-owl.h"
+#include "common-regs-owl.h"
+#include <mach/module-owl.h>
+
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+
+static int dai_clk_i2s_count;
+static int dai_clk_hdmi_count;
+static int dai_clk_spdif_count;
+static int dai_mode_i2s_count;
+static int dai_mode_hdmi_count;
+
+#ifdef CONFIG_SND_UBUNTU
+static int is_i2s_playback;
+static int is_i2s_record;
+#endif
+
+struct asoc_dai_resource {
+    void __iomem    *base[MAX_RES_NUM];/*virtual base for every resource*/
+    void __iomem    *baseptr; /*pointer to every virtual base*/
+    struct clk      *clk;
+    int             irq;
+    unsigned int    setting;
+};
+
+//dai resources
+static struct asoc_dai_resource dai_res;
+ 
+void set_dai_reg_base(int num)
+{
+	dai_res.baseptr = dai_res.base[num];
+}
+
+EXPORT_SYMBOL_GPL(set_dai_reg_base);
+
+u32 snd_dai_readl(u32 reg)
+{
+	return readl(dai_res.baseptr + reg);
+}
+
+EXPORT_SYMBOL_GPL(snd_dai_readl);
+	 
+void snd_dai_writel(u32 val, u32 reg)
+{
+	writel(val, dai_res.baseptr + reg);
+}
+
+EXPORT_SYMBOL_GPL(snd_dai_writel);
+
+
+
+static ssize_t error_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int cnt;
+
+	cnt = sprintf(buf, "%d\n(Note: 1: open, 0:close)\n", error_switch);
+	return cnt;
+}
+
+static ssize_t error_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int cnt, tmp;
+	cnt = sscanf(buf, "%d", &tmp);
+	switch (tmp) {
+	case 0:
+	case 1:
+		error_switch = tmp;
+		break;
+	default:
+		printk(KERN_ERR"invalid input\n");
+		break;
+	}
+	return count;
+}
+
+static ssize_t debug_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int cnt;
+
+	cnt = sprintf(buf, "%d\n(Note: 1: open, 0:close)\n", debug_switch);
+	return cnt;
+}
+
+static ssize_t debug_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	int cnt, tmp;
+	cnt = sscanf(buf, "%d", &tmp);
+	switch (tmp) {
+	case 0:
+	case 1:
+		debug_switch = tmp;
+		break;
+	default:
+		printk(KERN_INFO"invalid input\n");
+		break;
+	}
+	return count;
+}
+
+static struct device_attribute dai_attr[] = {
+	__ATTR(error, S_IRUSR | S_IWUSR, error_show, error_store),
+	__ATTR(debug, S_IRUSR | S_IWUSR, debug_show, debug_store),
+};
+
+/******************************************************************************/
+/*!
+ * \par  Description:
+ *    将采样率转换成矊 *¬件寄存器设置所需的索引值
+ * \param[in]    sample_rate  采样率
+ * \param[in]    mode 输入输出模
+ *式 (如果是spdif或者hdmi,index不同)
+ * \return       索引值
+ * \retval           -1 failed
+ * \ingroup      sndrv
+ *****************************************/
+static int get_sf_index(int sample_rate, int mode)
+{
+	int i = 0;
+	char fs = sample_rate / 1000;
+	// 44k 在基础上寄存器bit位基础上加16 
+	static fs_t fs_list[] = {
+		{ 384, { -1, 0} },
+		{ 352, { -1, 16} },
+		{ 192, { 0,  1} },
+		{ 176, { 16, 17} },
+		{ 96,  { 1,  3} },
+		{ 88,  { 17, 19} },
+		{ 64,  { 2, -1} },
+		{ 48,  { 3,  5} },
+		{ 44,  { 19, 21} },
+		{ 32,  { 4,  6} },
+		{ 24,  { 5, -1} },
+		{ 22,  {21, -1} },
+		{ 16,  { 6, -1} },
+		{ 12,  { 7, -1} },
+		{ 11,  {23, -1} },
+		{ 8,   { 8, -1} },
+		{ -1,  {-1, -1} }
+	};
+
+	while ((fs_list[i].sample_rate > 0) && (fs_list[i].sample_rate != fs))
+		i++;
+
+	if ((mode == O_MODE_HDMI) || (mode == O_MODE_SPDIF))
+		return fs_list[i].index[1];
+	else
+		return fs_list[i].index[0];
+}
+
+static int atm7059_dai_record_clk_set(int mode, int rate)
+{
+	struct clk *apll_clk;
+	unsigned long reg_val;
+	int sf_index, ret;
+
+	if (dai_clk_i2s_count > 0) {
+		dai_clk_i2s_count++;
+		return 0;
+	}
+	module_clk_enable(MOD_ID_I2SRX);
+	module_clk_enable(MOD_ID_I2STX);
+
+
+	sf_index = get_sf_index(rate, mode);
+	if (sf_index & 0x10)
+		reg_val = 45158400;
+	else
+		reg_val = 49152000;
+
+	apll_clk = clk_get(NULL, CLKNAME_AUDIOPLL);
+	clk_prepare(apll_clk);
+	ret = clk_set_rate(apll_clk, reg_val);
+	if (ret < 0) {
+		snd_dbg("audiopll set error!\n");
+		return ret;
+	}
+
+	apll_clk = clk_get(NULL, CLKNAME_I2STX_CLK);
+	ret = clk_set_rate(apll_clk, rate << 8);
+	if (ret) {
+		snd_dbg("i2stx clk rate set error!!\n");
+		return ret;
+	}
+	apll_clk = clk_get(NULL, CLKNAME_I2SRX_CLK);
+	ret = clk_set_rate(apll_clk, rate << 8);
+	if (ret) {
+		snd_dbg("i2srx clk rate set error!!\n");
+		return ret;
+	}
+	dai_clk_i2s_count++;
+
+	return 0;
+}
+
+static int atm7059_dai_clk_set(int mode, int rate)
+{
+	struct clk *apll_clk;
+	unsigned long reg_val;
+	int sf_index, ret;
+
+	module_clk_enable(MOD_ID_I2SRX);
+	module_clk_enable(MOD_ID_I2STX);
+
+	sf_index = get_sf_index(rate, mode);
+	if (sf_index & 0x10)
+		reg_val = 45158400;
+	else
+		reg_val = 49152000;
+
+	apll_clk = clk_get(NULL, CLKNAME_AUDIOPLL);
+	clk_prepare(apll_clk);
+	ret = clk_set_rate(apll_clk, reg_val);
+	if (ret < 0) {
+		snd_dbg("audiopll set error!\n");
+		return ret;
+	}
+
+	switch (mode) {
+	case O_MODE_I2S:
+	if (dai_clk_i2s_count == 0) {
+		apll_clk = clk_get(NULL, CLKNAME_I2STX_CLK);
+		ret = clk_set_rate(apll_clk, rate << 8);
+		if (ret) {
+			snd_dbg("i2stx clk rate set error!!\n");
+			return ret;
+		}
+		apll_clk = clk_get(NULL, CLKNAME_I2SRX_CLK);
+		ret = clk_set_rate(apll_clk, rate << 8);
+		if (ret) {
+			snd_dbg("i2srx clk rate set error!!\n");
+			return ret;
+		}
+	}
+	dai_clk_i2s_count++;
+	break;
+
+	case O_MODE_HDMI:
+	if (dai_clk_hdmi_count == 0) {
+		apll_clk = clk_get(NULL, CLKNAME_HDMIA_CLK);
+		ret = clk_set_rate(apll_clk, rate << 7);
+		if (ret) {
+			snd_dbg("hdmi clk rate set error!!\n");
+			return ret;
+		}
+	}
+	dai_clk_hdmi_count++;
+	break;
+
+	case O_MODE_SPDIF:
+	if (dai_clk_spdif_count == 0) {
+		apll_clk = clk_get(NULL, CLKNAME_SPDIF_CLK);
+		ret = clk_set_rate(apll_clk, rate << 7);
+		if (ret) {
+			snd_dbg("spdif clk rate set error!!\n");
+			return ret;
+		}
+	}
+	dai_clk_spdif_count++;
+	break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int atm7059_dai_record_clk_disable(void)
+{
+    if(dai_clk_i2s_count > 0)
+	{
+		dai_clk_i2s_count--;
+		return 0;
+	}
+
+	//module_clk_disable(MOD_ID_I2SRX);
+	//module_clk_disable(MOD_ID_I2STX);
+
+	return 0;
+}
+
+static int atm7059_dai_clk_disable(int mode)
+{
+	switch (mode) {
+	case O_MODE_I2S:
+	/* we disable the i2s_clk in another place */
+	/*
+	apll_clk = clk_get_sys(CLK_NAME_I2STX_CLK, NULL);
+	clk_disable(apll_clk);
+	apll_clk = clk_get_sys(CLK_NAME_I2SRX_CLK, NULL);
+	clk_disable(apll_clk);
+	*/
+	if(dai_clk_i2s_count > 0)
+		dai_clk_i2s_count--;
+	break;
+
+	case O_MODE_HDMI:
+    if(dai_clk_hdmi_count > 0)
+	    dai_clk_hdmi_count--;
+	break;
+
+	case O_MODE_SPDIF:
+    if(dai_clk_spdif_count > 0)    
+	dai_clk_spdif_count--;
+	break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+#if 0
+static int atm7059_i2s_4wire_config(struct atm7059_pcm_priv *pcm_priv,
+		struct snd_soc_dai *dai)
+{
+	int ret;
+
+	pcm_priv->pc = pinctrl_get(dai->dev);
+	if (IS_ERR(pcm_priv->pc) || (pcm_priv->pc == NULL)) {
+		snd_dbg("i2s pin control failed!\n");
+		return -EAGAIN;
+	}
+
+	pcm_priv->ps = pinctrl_lookup_state(pcm_priv->pc, "default");
+	if (IS_ERR(pcm_priv->ps) || (pcm_priv->ps == NULL)) {
+		snd_dbg("i2s pin state get failed!\n");
+		return -EAGAIN;
+	}
+
+	ret = pinctrl_select_state(pcm_priv->pc, pcm_priv->ps);
+	if (ret) {
+		snd_dbg("i2s pin state set failed!\n");
+		return -EAGAIN;
+	}
+
+	/*
+	 * set 4wire mode
+	snd_dai_writel(snd_dai_readl(PAD_CTL) | (0x1 << 1), PAD_CTL);
+	snd_dai_writel(snd_dai_readl(MFP_CTL0) & ~(0x1 << 2), MFP_CTL0);
+	snd_dai_writel(snd_dai_readl(MFP_CTL0) & ~(0x1 << 5), MFP_CTL0);
+	 */
+
+	/* disable i2s tx&rx */
+	snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x3 << 0), I2S_CTL);
+
+	/* reset i2s rx&&tx fifo, avoid left & right channel wrong */
+	snd_dai_writel(snd_dai_readl(I2S_FIFOCTL) & ~(0x3 << 9) & ~0x3, I2S_FIFOCTL);
+	snd_dai_writel(snd_dai_readl(I2S_FIFOCTL) | (0x3 << 9) | 0x3, I2S_FIFOCTL);
+
+	/* this should before enable rx/tx,
+	or after suspend, data may be corrupt */
+	snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x3 << 11), I2S_CTL);
+	snd_dai_writel(snd_dai_readl(I2S_CTL) | (0x1 << 11), I2S_CTL);
+	/* set i2s mode I2S_RX_ClkSel==1 */
+	snd_dai_writel(snd_dai_readl(I2S_CTL) | (0x1 << 10), I2S_CTL);
+
+	/* enable i2s rx/tx at the same time */
+	snd_dai_writel(snd_dai_readl(I2S_CTL) | 0x3, I2S_CTL);
+
+	/* i2s rx 00: 2.0-Channel Mode */
+	snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x3 << 8), I2S_CTL);
+	snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x7 << 4), I2S_CTL);
+
+	return 0;
+}
+#endif
+
+static int atm7059_dai_record_mode_set(struct atm7059_pcm_priv *pcm_priv,
+		struct snd_soc_dai *dai)
+{
+	/*ret = atm7059_i2s_4wire_config(pcm_priv, dai);*/
+	/*snd_dai_writel(snd_dai_readl(PAD_CTL) | (0x1 << 1), PAD_CTL);*/
+	if (dai_mode_i2s_count == 0) {
+//		set_dai_reg_base(GPIO_MFP_NUM);
+//		snd_dai_writel(snd_dai_readl(MFP_CTL0) & ~(0x1 << 2), MFP_CTL0);
+//		snd_dai_writel(snd_dai_readl(MFP_CTL0) & ~(0x3 << 3), MFP_CTL0);
+
+		/* disable i2s tx&rx */
+		set_dai_reg_base(I2S_SPDIF_NUM);
+		snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x3 << 0), I2S_CTL);
+
+		/* reset i2s rx&&tx fifo, avoid left & right channel wrong */
+		snd_dai_writel(snd_dai_readl(I2S_FIFOCTL)
+		& ~(0x3 << 9) & ~0x3, I2S_FIFOCTL);
+		snd_dai_writel(snd_dai_readl(I2S_FIFOCTL)
+			| (0x3 << 9) | 0x3, I2S_FIFOCTL);
+
+		/* this should before enable rx/tx,
+		or after suspend, data may be corrupt */
+		snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x3 << 11), I2S_CTL);
+		snd_dai_writel(snd_dai_readl(I2S_CTL) | (0x1 << 11), I2S_CTL);
+		/* set i2s mode I2S_RX_ClkSel==1 */
+		snd_dai_writel(snd_dai_readl(I2S_CTL) | (0x1 << 10), I2S_CTL);
+
+		/* enable i2s rx/tx at the same time */
+		snd_dai_writel(snd_dai_readl(I2S_CTL) | 0x3, I2S_CTL);
+
+		/* i2s rx 00: 2.0-Channel Mode */
+		snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x3 << 8), I2S_CTL);
+		snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x7 << 4), I2S_CTL);
+	}
+	dai_mode_i2s_count++;
+
+	return 0;
+}
+
+
+static int atm7059_dai_mode_set(struct atm7059_pcm_priv *pcm_priv,
+		struct snd_soc_dai *dai)
+{
+	int ret;
+
+	switch (pcm_priv->output_mode) {
+	case O_MODE_I2S:
+		/*ret = atm7059_i2s_4wire_config(pcm_priv, dai);*/
+		/*snd_dai_writel(snd_dai_readl(PAD_CTL) | (0x1 << 1), PAD_CTL);*/
+		if (dai_mode_i2s_count == 0) {
+//			set_dai_reg_base(GPIO_MFP_NUM);
+//			snd_dai_writel(snd_dai_readl(MFP_CTL0) & ~(0x1 << 2), MFP_CTL0);
+//			snd_dai_writel(snd_dai_readl(MFP_CTL0) & ~(0x3 << 3), MFP_CTL0);
+
+			/* disable i2s tx&rx */
+			set_dai_reg_base(I2S_SPDIF_NUM);
+			snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x3 << 0), I2S_CTL);
+
+			/* reset i2s rx&&tx fifo, avoid left & right channel wrong */
+			snd_dai_writel(snd_dai_readl(I2S_FIFOCTL)
+				& ~(0x3 << 9) & ~0x3, I2S_FIFOCTL);
+			snd_dai_writel(snd_dai_readl(I2S_FIFOCTL)
+				| (0x3 << 9) | 0x3, I2S_FIFOCTL);
+
+			/* this should before enable rx/tx,
+			or after suspend, data may be corrupt */
+			snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x3 << 11), I2S_CTL);
+			snd_dai_writel(snd_dai_readl(I2S_CTL) | (0x1 << 11), I2S_CTL);
+			/* set i2s mode I2S_RX_ClkSel==1 */
+			snd_dai_writel(snd_dai_readl(I2S_CTL) | (0x1 << 10), I2S_CTL);
+
+			/* enable i2s rx/tx at the same time */
+			snd_dai_writel(snd_dai_readl(I2S_CTL) | 0x3, I2S_CTL);
+
+			/* i2s rx 00: 2.0-Channel Mode */
+			snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x3 << 8), I2S_CTL);
+			snd_dai_writel(snd_dai_readl(I2S_CTL) & ~(0x7 << 4), I2S_CTL);
+		}
+		dai_mode_i2s_count++;
+		break;
+
+	case O_MODE_HDMI:
+		/* HDMI&SPDIF fifo reset */
+		if (dai_mode_hdmi_count == 0) {   
+            set_dai_reg_base(I2S_SPDIF_NUM);
+			snd_dai_writel(snd_dai_readl(SPDIF_HDMI_CTL) & ~0x3,
+				SPDIF_HDMI_CTL);
+			/* HDMI fifo enable,DRQ enable */
+			snd_dai_writel(snd_dai_readl(SPDIF_HDMI_CTL) |
+				0x102, SPDIF_HDMI_CTL);
+		}
+		dai_mode_hdmi_count++;
+		break;
+	case O_MODE_SPDIF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int atm7059_dai_record_mode_unset(void)
+{
+    if(dai_mode_i2s_count > 0)
+	    dai_mode_i2s_count--;
+	if (dai_mode_i2s_count == 0) {
+		set_dai_reg_base(I2S_SPDIF_NUM);
+		snd_dai_writel(snd_dai_readl(I2S_CTL) & ~0x3, I2S_CTL);
+		snd_dai_writel(snd_dai_readl(I2S_FIFOCTL) & ~0x3, I2S_FIFOCTL);
+		snd_dai_writel(snd_dai_readl(I2S_FIFOCTL) & ~(0x3 << 9), I2S_FIFOCTL);
+#ifdef CONFIG_SND_UBUNTU		
+		is_i2s_record = 0;
+#endif
+		/*pinctrl_put(pcm_priv->pc);*/
+	}
+	return 0;
+}
+
+static int atm7059_dai_mode_unset(struct atm7059_pcm_priv *pcm_priv)
+{
+	switch (pcm_priv->output_mode) {
+	case O_MODE_I2S:
+		if(dai_mode_i2s_count > 0)
+		dai_mode_i2s_count--;
+		if (dai_mode_i2s_count == 0) {
+			set_dai_reg_base(I2S_SPDIF_NUM);
+			snd_dai_writel(snd_dai_readl(I2S_CTL) & ~0x3, I2S_CTL);
+			snd_dai_writel(snd_dai_readl(I2S_FIFOCTL) & ~0x3, I2S_FIFOCTL);
+			snd_dai_writel(snd_dai_readl(I2S_FIFOCTL) & ~(0x3 << 9), I2S_FIFOCTL);
+			/*pinctrl_put(pcm_priv->pc);*/
+#ifdef CONFIG_SND_UBUNTU			
+			is_i2s_playback = 0;
+#endif
+		}
+		break;
+	case O_MODE_HDMI:
+		/* HDMI fifo disable */
+        if(dai_mode_hdmi_count > 0)
+		dai_mode_hdmi_count--;
+		if (dai_mode_hdmi_count == 0) {
+			set_dai_reg_base(I2S_SPDIF_NUM);
+			snd_dai_writel(snd_dai_readl(SPDIF_HDMI_CTL) & ~0x2, SPDIF_HDMI_CTL);
+		}
+		break;
+	case O_MODE_SPDIF:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int atm7059_dai_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_platform *platform = rtd->platform;
+	struct atm7059_pcm_priv *pcm_priv
+		= snd_soc_platform_get_drvdata(platform);
+
+#ifdef CONFIG_SND_UBUNTU		
+	if(((pcm_priv->output_mode == O_MODE_I2S)&&(is_i2s_playback == 1)) || 
+		(is_i2s_record == 1))
+	{
+		//snd_err("param setted\n");
+		return 0;
+	}	
+#endif
+
+//	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+//		//snd_err("playback hw param\n");
+//	}
+//	else
+//	{
+//		//snd_err("record hw param\n");
+//	}
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+        #ifdef CONFIG_SND_UBUNTU
+        printk(KERN_ERR"%s,SNDRV_PCM_FORMAT_S16_LE\n", __func__);
+        break;
+        #endif
+	case SNDRV_PCM_FORMAT_S32_LE:
+        #ifdef CONFIG_SND_UBUNTU
+        printk(KERN_ERR"%s,SNDRV_PCM_FORMAT_S32_LE\n", __func__);
+        #endif
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (SNDRV_PCM_STREAM_CAPTURE == substream->stream ) {
+		atm7059_dai_record_clk_set(pcm_priv->output_mode, params_rate(params));
+		atm7059_dai_record_mode_set(pcm_priv, dai);
+#ifdef CONFIG_SND_UBUNTU		
+		is_i2s_record = 1;
+#endif
+	}
+
+	if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream ) {
+		atm7059_dai_clk_set(pcm_priv->output_mode, params_rate(params));
+		atm7059_dai_mode_set(pcm_priv, dai);
+#ifdef CONFIG_SND_UBUNTU		
+		if(pcm_priv->output_mode == O_MODE_I2S)
+		{
+			is_i2s_playback = 1;
+		}
+#endif
+	}
+	return 0;
+}
+
+static int atm7059_dai_hw_free(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_platform *platform = rtd->platform;
+	struct atm7059_pcm_priv *pcm_priv =
+		snd_soc_platform_get_drvdata(platform);
+		
+		
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		//snd_err("playback free\n");
+	}
+	else
+	{
+		//snd_err("record free\n");
+	}
+#ifdef CONFIG_SND_UBUNTU	
+	if (SNDRV_PCM_STREAM_CAPTURE == substream->stream && is_i2s_playback == 0 )
+#else
+	if (SNDRV_PCM_STREAM_CAPTURE == substream->stream)
+#endif
+	{
+		atm7059_dai_record_clk_disable();
+		atm7059_dai_record_mode_unset();
+	}
+
+#ifdef CONFIG_SND_UBUNTU
+	if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream && is_i2s_record == 0 )
+#else
+	if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream)
+#endif
+	{
+		atm7059_dai_clk_disable(pcm_priv->output_mode);
+		atm7059_dai_mode_unset(pcm_priv);
+	}
+	
+
+	return 0;
+}
+
+struct snd_soc_dai_ops atm7059_dai_dai_ops = {
+	.hw_params = atm7059_dai_hw_params,
+	.hw_free = atm7059_dai_hw_free,
+};
+
+#ifdef CONFIG_SND_UBUNTU
+static u32 i2s_ctl_reg;
+static u32 i2s_fifoctl_reg;
+static u32 hdmi_ctl_reg;
+static int dai_regs_stored = -1;
+static int atm7059_dai_store_regs(void)
+{
+    set_dai_reg_base(I2S_SPDIF_NUM);
+
+	i2s_ctl_reg = snd_dai_readl(I2S_CTL);
+    i2s_fifoctl_reg = snd_dai_readl(I2S_FIFOCTL);
+    hdmi_ctl_reg = snd_dai_readl(SPDIF_HDMI_CTL);
+	dai_regs_stored = 1;
+	return 0;
+}
+
+static int atm7059_dai_restore_regs(void)
+{
+	if(dai_regs_stored < 0)
+	{
+		printk("no initial regs value yet\n");
+		return 0;
+	}
+	set_dai_reg_base(I2S_SPDIF_NUM);
+
+	snd_dai_writel(i2s_ctl_reg, I2S_CTL);
+	snd_dai_writel(i2s_fifoctl_reg, I2S_FIFOCTL);
+	snd_dai_writel(hdmi_ctl_reg, SPDIF_HDMI_CTL);	
+	dai_regs_stored = -1;
+
+	return 0;
+}
+
+static int atm7059_dai_suspend(struct snd_soc_dai *dai)
+{
+	return atm7059_dai_store_regs();
+}
+static int atm7059_dai_resume(struct snd_soc_dai *dai)
+{
+	return atm7059_dai_restore_regs();
+}
+#endif
+
+#define ATM7059_STEREO_CAPTURE_RATES SNDRV_PCM_RATE_8000_96000
+#define ATM7059_STEREO_PLAYBACK_RATES SNDRV_PCM_RATE_8000_192000
+#define ATM7059_FORMATS SNDRV_PCM_FMTBIT_S16_LE
+
+struct snd_soc_dai_driver atm7059_dai = {
+	.name = "gl5203-audio-i2s",
+	.id = ATM7059_AIF_I2S,
+	.playback = {
+		.stream_name = "atm7059 dai Playback",
+		.channels_min = 1,
+		.channels_max = 8,
+		.rates = ATM7059_STEREO_PLAYBACK_RATES,
+		#ifdef CONFIG_SND_UBUNTU
+		.formats = SNDRV_PCM_FMTBIT_S32_LE,
+		#else
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,		
+		#endif
+	},
+	.capture = {
+		.stream_name = "atm7059 dai Capture",
+		.channels_min = 1,
+		.channels_max = 4,
+		.rates = ATM7059_STEREO_CAPTURE_RATES,
+		#ifdef CONFIG_SND_UBUNTU
+		.formats = SNDRV_PCM_FMTBIT_S32_LE,
+		#else
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		#endif
+	},
+#ifdef CONFIG_SND_UBUNTU
+	.suspend = atm7059_dai_suspend,
+    .resume = atm7059_dai_resume,
+#endif
+	.ops = &atm7059_dai_dai_ops,
+};
+
+static const struct snd_soc_component_driver atm7059_component = {
+	.name		= "atm7059ac97c",
+};
+
+static const struct of_device_id owl_i2s_of_match[] = {
+	{.compatible = "actions,owl-audio-i2s",},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, owl_i2s_of_match);
+
+static int atm7059_dai_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int i;
+	int ret = 0;
+
+	struct device_node *dn;
+
+	dn = of_find_compatible_node(NULL, NULL, "actions,owl-audio-i2s");
+	if (!dn) {
+		snd_err("Fail to get device_node actions,owl-audio-i2s\r\n");
+		//goto of_get_failed;
+	}
+	
+	/*FIXME: what if error in second or third loop*/
+	//for(i=0; i<MAX_RES_NUM; i++) 
+	for(i=0; i<1; i++) 
+	{
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		if (!res) {
+			snd_err("no memory resource i=%d\n", i);
+			return -ENODEV;
+		}
+
+		if (!devm_request_mem_region (&pdev->dev, res->start,
+					resource_size(res), "owl-audio-i2s")) {
+			snd_err("Unable to request register region\n");
+			return -EBUSY;
+		}
+
+		dai_res.base[i] = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+		if (dai_res.base[i] == NULL) {
+			snd_err("Unable to ioremap register region\n");
+			return -ENXIO;
+		}
+		
+		snd_err("it's ok %d\n", i);
+	}
+
+
+	if (1)
+	{
+		for (i = 0; i < ARRAY_SIZE(dai_attr); i++) 
+		{
+			ret = device_create_file(&pdev->dev, &dai_attr[i]);
+			if (ret) {
+				snd_err("Add device file failed");
+				//goto device_create_file_failed;
+			}
+		}
+	}
+	else
+	{
+		snd_err("Find device failed");
+		//goto err_bus_find_device;	
+	}
+
+	
+	dev_warn(&pdev->dev, "atm7059_dai_probe\n");
+	//snd_err("dai probe fine\n");
+	
+	pdev->dev.init_name = "owl-audio-i2s";
+	
+	return snd_soc_register_component(&pdev->dev, &atm7059_component,
+					 &atm7059_dai, 1);
+
+}
+
+static int atm7059_dai_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_component(&pdev->dev);
+	return 0;
+}
+
+
+
+static struct platform_driver atm7059_dai_driver = {
+	.driver = {
+		.name = "owl-audio-i2s",
+		.owner = THIS_MODULE,
+		.of_match_table = owl_i2s_of_match,
+	},
+
+	.probe = atm7059_dai_probe,
+	.remove = atm7059_dai_remove,
+};
+
+//static struct platform_device *atm7059_dai_device;
+
+static int __init atm7059_dai_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&atm7059_dai_driver);
+	if (ret) {
+		snd_err(
+			"ASoC: Platform driver atm7059-dai register failed\n");
+		goto err_driver_register;
+	}
+
+
+	return 0;
+
+err_driver_register:
+	return ret;
+}
+
+static void __exit atm7059_dai_exit(void)
+{
+	int i = 0;
+	struct device *dev = NULL;
+
+    dev = bus_find_device_by_name(&platform_bus_type, NULL, "owl-audio-i2s");	
+
+	if (dev)
+	{
+		for (i = 0; i < ARRAY_SIZE(dai_attr); i++)
+		{
+			device_remove_file(dev, &dai_attr[i]);
+		}
+	}
+
+	platform_driver_unregister(&atm7059_dai_driver);
+	//platform_device_unregister(atm7059_dai_device);
+	//atm7059_dai_device = NULL;
+}
+
+module_init(atm7059_dai_init);
+module_exit(atm7059_dai_exit);
+
+
+/* Module information */
+MODULE_AUTHOR("sall.xie <sall.xie at actions-semi.com>");
+MODULE_DESCRIPTION("ATM7059 I2S Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/atc260x/dmaengine-pcm-owl.c b/sound/soc/atc260x/dmaengine-pcm-owl.c
new file mode 100755
index 0000000..bf3ecbb
--- /dev/null
+++ b/sound/soc/atc260x/dmaengine-pcm-owl.c
@@ -0,0 +1,438 @@
+/*
+ *  Copyright (C) 2012, Analog Devices Inc.
+ *	Author: Lars-Peter Clausen <lars at metafoo.de>
+ *
+ *  Based on:
+ *	imx-pcm-dma-mx2.c, Copyright 2009 Sascha Hauer <s.hauer at pengutronix.de>
+ *	mxs-pcm.c, Copyright (C) 2011 Freescale Semiconductor, Inc.
+ *	ep93xx-pcm.c, Copyright (C) 2006 Lennert Buytenhek <buytenh at wantstofly.org>
+ *		      Copyright (C) 2006 Applied Data Systems
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/dmaengine.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <sound/dmaengine_pcm.h>
+#include <mach/hdmac-owl.h>
+
+struct dmaengine_pcm_runtime_data {
+	struct dma_chan *dma_chan;
+	dma_cookie_t cookie;
+
+	unsigned int pos;
+	unsigned int startflag;
+};
+
+static inline struct dmaengine_pcm_runtime_data *substream_to_prtd(
+	const struct snd_pcm_substream *substream)
+{
+	return substream->runtime->private_data;
+}
+
+struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream)
+{
+	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+
+	return prtd->dma_chan;
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_get_chan);
+
+/**
+ * snd_hwparams_to_dma_slave_config - Convert hw_params to dma_slave_config
+ * @substream: PCM substream
+ * @params: hw_params
+ * @slave_config: DMA slave config
+ *
+ * This function can be used to initialize a dma_slave_config from a substream
+ * and hw_params in a dmaengine based PCM driver implementation.
+ */
+int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream,
+	const struct snd_pcm_hw_params *params,
+	struct dma_slave_config *slave_config)
+{
+	enum dma_slave_buswidth buswidth;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
+		break;
+	case SNDRV_PCM_FORMAT_S18_3LE:
+	case SNDRV_PCM_FORMAT_S20_3LE:
+	case SNDRV_PCM_FORMAT_S24_LE:
+	case SNDRV_PCM_FORMAT_S32_LE:
+		buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		slave_config->direction = DMA_MEM_TO_DEV;
+		slave_config->dst_addr_width = buswidth;
+	} else {
+		slave_config->direction = DMA_DEV_TO_MEM;
+		slave_config->src_addr_width = buswidth;
+	}
+
+	slave_config->device_fc = false;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hwparams_to_dma_slave_config);
+
+/**
+ * snd_dmaengine_pcm_set_config_from_dai_data() - Initializes a dma slave config
+ *  using DAI DMA data.
+ * @substream: PCM substream
+ * @dma_data: DAI DMA data
+ * @slave_config: DMA slave configuration
+ *
+ * Initializes the {dst,src}_addr, {dst,src}_maxburst, {dst,src}_addr_width and
+ * slave_id fields of the DMA slave config from the same fields of the DAI DMA
+ * data struct. The src and dst fields will be initialized depending on the
+ * direction of the substream. If the substream is a playback stream the dst
+ * fields will be initialized, if it is a capture stream the src fields will be
+ * initialized. The {dst,src}_addr_width field will only be initialized if the
+ * addr_width field of the DAI DMA data struct is not equal to
+ * DMA_SLAVE_BUSWIDTH_UNDEFINED.
+ */
+void snd_dmaengine_pcm_set_config_from_dai_data(
+	const struct snd_pcm_substream *substream,
+	const struct snd_dmaengine_dai_dma_data *dma_data,
+	struct dma_slave_config *slave_config)
+{
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		slave_config->dst_addr = dma_data->addr;
+		slave_config->dst_maxburst = dma_data->maxburst;
+		if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED)
+			slave_config->dst_addr_width = dma_data->addr_width;
+	} else {
+		slave_config->src_addr = dma_data->addr;
+		slave_config->src_maxburst = dma_data->maxburst;
+		if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED)
+			slave_config->src_addr_width = dma_data->addr_width;
+	}
+
+	slave_config->slave_id = dma_data->slave_id;
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_config_from_dai_data);
+
+static void dmaengine_pcm_dma_complete(void *arg)
+{
+	struct snd_pcm_substream *substream = arg;
+	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+
+	if (PCM_RUNTIME_CHECK(substream))
+		return;
+	if(prtd->startflag == 1)
+	{
+		if (SNDRV_PCM_STREAM_CAPTURE == substream->stream )
+		{
+			prtd->pos += snd_pcm_lib_period_bytes(substream);
+			if (prtd->pos >= snd_pcm_lib_buffer_bytes(substream))
+				prtd->pos = 0;
+		}
+		else if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
+			int prev_pos = prtd->pos;
+			int diff;
+			int this_interrupt_num;
+			int sum_periods = (snd_pcm_lib_buffer_bytes(substream)
+								/snd_pcm_lib_period_bytes(substream));
+			int remain_frame_cnt = read_remain_frame_cnt(prtd->dma_chan);
+			remain_frame_cnt = remain_frame_cnt%sum_periods;
+			prtd->pos = snd_pcm_lib_buffer_bytes(substream)
+						- (remain_frame_cnt*snd_pcm_lib_period_bytes(substream));
+			if (prtd->pos >= snd_pcm_lib_buffer_bytes(substream))
+				prtd->pos = 0;
+
+			diff = (prtd->pos - prev_pos);
+			if(diff>0)
+			{
+				this_interrupt_num = diff/snd_pcm_lib_period_bytes(substream);
+				if((this_interrupt_num != 1))
+					printk(KERN_ERR"[audio]:[%d]lost IRQ:num = %d\n",
+							__LINE__, this_interrupt_num);
+			}
+			else
+			{
+				this_interrupt_num = (diff + snd_pcm_lib_buffer_bytes(substream))
+					/snd_pcm_lib_period_bytes(substream);
+				if((this_interrupt_num != 1))
+					printk(KERN_ERR"[audio]:[%d]lost IRQ:num = %d\n",
+							__LINE__, this_interrupt_num);
+			}
+			//printk("1\n");
+		}
+
+		snd_pcm_period_elapsed(substream);
+	}
+	else
+	{
+	//printk(KERN_ERR"5,%d\n", prtd->startflag);
+	}
+}
+
+static int dmaengine_pcm_prepare_and_submit(struct snd_pcm_substream *substream)
+{
+	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+	struct dma_chan *chan = prtd->dma_chan;
+	struct dma_async_tx_descriptor *desc;
+	enum dma_transfer_direction direction;
+	unsigned long flags = DMA_CTRL_ACK;
+
+	direction = snd_pcm_substream_to_dma_direction(substream);
+
+	if (!substream->runtime->no_period_wakeup)
+		flags |= DMA_PREP_INTERRUPT;
+
+	prtd->pos = 0;
+	desc = dmaengine_prep_dma_cyclic(chan,
+		substream->runtime->dma_addr,
+		snd_pcm_lib_buffer_bytes(substream),
+		snd_pcm_lib_period_bytes(substream), direction, flags);
+
+	if (!desc)
+		return -ENOMEM;
+
+	desc->callback = dmaengine_pcm_dma_complete;
+	desc->callback_param = substream;
+	prtd->cookie = dmaengine_submit(desc);
+
+	return 0;
+}
+
+/**
+ * snd_dmaengine_pcm_trigger - dmaengine based PCM trigger implementation
+ * @substream: PCM substream
+ * @cmd: Trigger command
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ *
+ * This function can be used as the PCM trigger callback for dmaengine based PCM
+ * driver implementations.
+ */
+int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+	int ret;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		ret = dmaengine_pcm_prepare_and_submit(substream);
+		if (ret)
+			return ret;
+		dma_async_issue_pending(prtd->dma_chan);
+		prtd->startflag = 1;
+		break;
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+        #ifdef CONFIG_SND_UBUNTU
+		ret = dmaengine_pcm_prepare_and_submit(substream);
+		if (ret)
+			return ret;
+		dma_async_issue_pending(prtd->dma_chan);
+		prtd->startflag = 1;
+        #else
+		dmaengine_resume(prtd->dma_chan);
+        #endif
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+        #ifdef CONFIG_SND_UBUNTU
+		dmaengine_terminate_all(prtd->dma_chan);
+		prtd->startflag = 0;
+        #else
+		dmaengine_pause(prtd->dma_chan);
+        #endif
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		dmaengine_terminate_all(prtd->dma_chan);
+		prtd->startflag = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_trigger);
+
+/**
+ * snd_dmaengine_pcm_pointer_no_residue - dmaengine based PCM pointer implementation
+ * @substream: PCM substream
+ *
+ * This function is deprecated and should not be used by new drivers, as its
+ * results may be unreliable.
+ */
+snd_pcm_uframes_t snd_dmaengine_pcm_pointer_no_residue(struct snd_pcm_substream *substream)
+{
+	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+	return bytes_to_frames(substream->runtime, prtd->pos);
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer_no_residue);
+
+/**
+ * snd_dmaengine_pcm_pointer - dmaengine based PCM pointer implementation
+ * @substream: PCM substream
+ *
+ * This function can be used as the PCM pointer callback for dmaengine based PCM
+ * driver implementations.
+ */
+snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+
+	struct dma_tx_state state;
+	enum dma_status status;
+	unsigned int buf_size;
+	unsigned int pos = 0;
+
+	status = dmaengine_tx_status(prtd->dma_chan, prtd->cookie, &state);
+	if (status == DMA_IN_PROGRESS || status == DMA_PAUSED) {
+		buf_size = snd_pcm_lib_buffer_bytes(substream);
+		if (state.residue > 0 && state.residue <= buf_size)
+			pos = buf_size - state.residue;
+	}
+
+	return bytes_to_frames(substream->runtime, pos);
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer);
+
+/**
+ * snd_dmaengine_pcm_request_channel - Request channel for the dmaengine PCM
+ * @filter_fn: Filter function used to request the DMA channel
+ * @filter_data: Data passed to the DMA filter function
+ *
+ * Returns NULL or the requested DMA channel.
+ *
+ * This function request a DMA channel for usage with dmaengine PCM.
+ */
+struct dma_chan *snd_dmaengine_pcm_request_channel(dma_filter_fn filter_fn,
+	void *filter_data)
+{
+	dma_cap_mask_t mask;
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+	dma_cap_set(DMA_CYCLIC, mask);
+
+	return dma_request_channel(mask, filter_fn, filter_data);
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_request_channel);
+
+/**
+ * snd_dmaengine_pcm_open - Open a dmaengine based PCM substream
+ * @substream: PCM substream
+ * @chan: DMA channel to use for data transfers
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ *
+ * The function should usually be called from the pcm open callback. Note that
+ * this function will use private_data field of the substream's runtime. So it
+ * is not availabe to your pcm driver implementation.
+ */
+int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
+	struct dma_chan *chan)
+{
+	struct dmaengine_pcm_runtime_data *prtd;
+	int ret;
+
+	if (!chan)
+		return -ENXIO;
+
+	ret = snd_pcm_hw_constraint_integer(substream->runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		return ret;
+
+	prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
+	if (!prtd)
+		return -ENOMEM;
+
+	prtd->dma_chan = chan;
+
+	substream->runtime->private_data = prtd;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open);
+
+/**
+ * snd_dmaengine_pcm_open_request_chan - Open a dmaengine based PCM substream and request channel
+ * @substream: PCM substream
+ * @filter_fn: Filter function used to request the DMA channel
+ * @filter_data: Data passed to the DMA filter function
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ *
+ * This function will request a DMA channel using the passed filter function and
+ * data. The function should usually be called from the pcm open callback. Note
+ * that this function will use private_data field of the substream's runtime. So
+ * it is not availabe to your pcm driver implementation.
+ */
+int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream,
+	dma_filter_fn filter_fn, void *filter_data)
+{
+	return snd_dmaengine_pcm_open(substream,
+		    snd_dmaengine_pcm_request_channel(filter_fn, filter_data));
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan);
+
+/**
+ * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream
+ * @substream: PCM substream
+ */
+int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+	
+	kfree(prtd);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close);
+
+/**
+ * snd_dmaengine_pcm_release_chan_close - Close a dmaengine based PCM substream and release channel
+ * @substream: PCM substream
+ *
+ * Releases the DMA channel associated with the PCM substream.
+ */
+int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream)
+{
+	struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
+
+	if(prtd->dma_chan)
+	{
+		if(prtd->dma_chan->private)
+		{
+			//printk("sndrv: free\n");
+			kfree(prtd->dma_chan->private);
+		}
+		prtd->dma_chan->private = NULL;
+	}
+	
+	dma_release_channel(prtd->dma_chan);
+
+	return snd_dmaengine_pcm_close(substream);
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan);
+
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/atc260x/hdmi-audio-owl.c b/sound/soc/atc260x/hdmi-audio-owl.c
new file mode 100755
index 0000000..37119b3
--- /dev/null
+++ b/sound/soc/atc260x/hdmi-audio-owl.c
@@ -0,0 +1,814 @@
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h> 
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <linux/clk.h>			/* clk_enable */
+#include "sndrv-owl.h"
+#include <mach/module-owl.h>
+#include "common-regs-owl.h"
+
+#include <linux/io.h> 
+#include <linux/ioport.h>
+
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include <linux/of_device.h>
+
+#if defined(CONFIG_HAS_EARLYSUSPEND)&&defined(CONFIG_SND_UBUNTU)
+#include <linux/earlysuspend.h>
+	struct early_suspend early_suspend;
+    static int is_suspended = 0;
+#endif
+
+static int audio_clk_enable;
+
+#define Audio60958	1	/*1--IEC60958; 0--IEC61937*/
+#define HDMI_RAMPKT_AUDIO_SLOT	1
+#define HDMI_RAMPKT_PERIOD	1
+
+static int Speaker;			//Speaker Placement, stereo
+
+/* for register io remap
+struct asoc_hdmi_resource {
+    void __iomem    *base[MAX_RES_NUM];//virtual base for every resource
+    void __iomem    *baseptr; //pointer to every virtual base
+    struct clk      *clk;
+    int             irq;
+    unsigned int    setting;
+};
+
+static struct asoc_hdmi_resource hdmi_res;
+
+static void set_hdmi_reg_base(int num)
+{
+	hdmi_res.baseptr = hdmi_res.base[num];
+}
+
+static u32 snd_hdmi_readl(u32 reg)
+{
+	return readl(hdmi_res.baseptr + reg);
+}
+	 
+static void snd_hdmi_writel(u32 val, u32 reg)
+{
+	writel(val, hdmi_res.baseptr + reg);
+}
+*/
+#if defined(CONFIG_HAS_EARLYSUSPEND)&&defined(CONFIG_SND_UBUNTU)
+static void hdmi_audio_early_suspend(struct early_suspend *h)
+{
+    is_suspended = 1;
+}
+
+static void hdmi_audio_late_resume(struct early_suspend *h)
+{
+    is_suspended = 0;
+
+}
+#endif
+
+static ssize_t error_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int cnt;
+
+	cnt = sprintf(buf, "%d\n(Note: 1: open, 0:close)\n", error_switch);
+	return cnt;
+}
+
+static ssize_t error_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int cnt, tmp;
+	cnt = sscanf(buf, "%d", &tmp);
+	switch (tmp) {
+	case 0:
+	case 1:
+		error_switch = tmp;
+		break;
+	default:
+		printk(KERN_ERR"invalid input\n");
+		break;
+	}
+	return count;
+}
+
+static ssize_t debug_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int cnt;
+
+	cnt = sprintf(buf, "%d\n(Note: 1: open, 0:close)\n", debug_switch);
+	return cnt;
+}
+
+static ssize_t debug_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	int cnt, tmp;
+	cnt = sscanf(buf, "%d", &tmp);
+	switch (tmp) {
+	case 0:
+	case 1:
+		debug_switch = tmp;
+		break;
+	default:
+		printk(KERN_INFO"invalid input\n");
+		break;
+	}
+	return count;
+}
+
+static struct device_attribute hdmi_attr[] = {
+	__ATTR(error, S_IRUSR | S_IWUSR, error_show, error_store),
+	__ATTR(debug, S_IRUSR | S_IWUSR, debug_show, debug_store),
+};
+
+static int hdmi_EnableWriteRamPacket(void)
+{
+	int i;
+	//set_hdmi_reg_base(0);
+	hdmihw_write_reg(hdmihw_read_reg((u16)HDMI_OPCR) | (0x1 << 31), (u16)HDMI_OPCR);
+	while ((hdmihw_read_reg((u16)HDMI_OPCR) & (0x1 << 31)) != 0) {
+		for (i = 0; i < 10; i++)
+			;
+	}
+	return 0;
+}
+
+static int hdmi_SetRamPacket(unsigned no, unsigned char *pkt)
+{
+	unsigned char tpkt[36];
+	unsigned int *reg = (unsigned int *) tpkt;
+	unsigned int addr = 126 + no * 14;
+
+	if (no > 5)
+		return -EINVAL;
+
+	/**
+	 * according to change by genganan 2008-09-24
+	 */
+	/* Packet Header */
+	tpkt[0] = pkt[0];
+	tpkt[1] = pkt[1];
+	tpkt[2] = pkt[2];
+	tpkt[3] = 0;
+	/* Packet Word0 */
+	tpkt[4] = pkt[3];
+	tpkt[5] = pkt[4];
+	tpkt[6] = pkt[5];
+	tpkt[7] = pkt[6];
+	/* Packet Word1 */
+	tpkt[8] = pkt[7];
+	tpkt[9] = pkt[8];
+	tpkt[10] = pkt[9];
+	tpkt[11] = 0;
+	/* Packet Word2 */
+	tpkt[12] = pkt[10];
+	tpkt[13] = pkt[11];
+	tpkt[14] = pkt[12];
+	tpkt[15] = pkt[13];
+	/* Packet Word3 */
+	tpkt[16] = pkt[14];
+	tpkt[17] = pkt[15];
+	tpkt[18] = pkt[16];
+	tpkt[19] = 0;
+	/* Packet Word4 */
+	tpkt[20] = pkt[17];
+	tpkt[21] = pkt[18];
+	tpkt[22] = pkt[19];
+	tpkt[23] = pkt[20];
+	/* Packet Word5 */
+	tpkt[24] = pkt[21];
+	tpkt[25] = pkt[22];
+	tpkt[26] = pkt[23];
+	tpkt[27] = 0;
+	/* Packet Word6 */
+	tpkt[28] = pkt[24];
+	tpkt[29] = pkt[25];
+	tpkt[30] = pkt[26];
+	tpkt[31] = pkt[27];
+	/* Packet Word7 */
+	tpkt[32] = pkt[28];
+	tpkt[33] = pkt[29];
+	tpkt[34] = pkt[30];
+	tpkt[35] = 0;
+
+	/* write mode */
+	//set_hdmi_reg_base(0);
+	hdmihw_write_reg((1 << 8) | (((addr) & 0xFF) << 0), (u16)HDMI_OPCR);
+	hdmihw_write_reg(reg[0], (u16)HDMI_ORP6PH);
+	hdmihw_write_reg(reg[1], (u16)HDMI_ORSP6W0);
+	hdmihw_write_reg(reg[2], (u16)HDMI_ORSP6W1);
+	hdmihw_write_reg(reg[3], (u16)HDMI_ORSP6W2);
+	hdmihw_write_reg(reg[4], (u16)HDMI_ORSP6W3);
+	hdmihw_write_reg(reg[5], (u16)HDMI_ORSP6W4);
+	hdmihw_write_reg(reg[6], (u16)HDMI_ORSP6W5);
+	hdmihw_write_reg(reg[7], (u16)HDMI_ORSP6W6);
+	hdmihw_write_reg(reg[8], (u16)HDMI_ORSP6W7);
+
+	hdmi_EnableWriteRamPacket();
+
+	return 0;
+}
+
+static int hdmi_SetRamPacketPeriod(unsigned int no, int period)
+{
+	if (no > 5)
+		return -EINVAL;
+
+	if ((period > 0xf) || (period < 0))
+		return -EINVAL;
+
+	/* disable */
+	//set_hdmi_reg_base(0);
+	hdmihw_write_reg(hdmihw_read_reg((u16)HDMI_RPCR) & (unsigned int) (~(1 << no)),
+	(u16)HDMI_RPCR);
+	hdmihw_write_reg(hdmihw_read_reg((u16)HDMI_RPCR) &
+	(unsigned int) (~(0xf << (no * 4 + 8))),
+			(u16)HDMI_RPCR);
+
+	if (period != 0) {
+		/* enable and set period */
+		hdmihw_write_reg(hdmihw_read_reg((u16)HDMI_RPCR) |
+		(unsigned int) (period << (no * 4 + 8)),
+				(u16)HDMI_RPCR);
+		hdmihw_write_reg(hdmihw_read_reg((u16)HDMI_RPCR) | (unsigned int) (1 << no),
+		(u16)HDMI_RPCR);
+	}
+	return 0;
+}
+
+static int hdmi_gen_audio_infoframe(int audio_channel)
+{
+		unsigned char pkt[32];
+		unsigned int  checksum = 0;
+		int i;
+		memset(pkt, 0, 32);
+		/* header */
+		pkt[0] = 0x80 | 0x04;
+		pkt[1] = 1;
+		pkt[2] = 0x1f & 10;
+		pkt[3] = 0x00;
+		pkt[4] = audio_channel & 0x7;
+		pkt[5] = 0x0;
+		pkt[6] = 0x0;
+		pkt[7] = Speaker;
+		pkt[8] = (0x0 << 7) | (0x0 << 3);
+
+		/* count checksum */
+		for (i = 0; i < 31; i++)
+			checksum += pkt[i];
+
+		pkt[3] = (unsigned char)((~checksum + 1) & 0xff);
+    /* set to RAM Packet */
+		hdmi_SetRamPacket(HDMI_RAMPKT_AUDIO_SLOT, pkt);
+		hdmi_SetRamPacketPeriod(HDMI_RAMPKT_AUDIO_SLOT,
+		HDMI_RAMPKT_PERIOD);
+		return 0;
+}
+void set_hdmi_audio_interface(int channel, int samplerate)
+{
+	unsigned int tmp03;
+	unsigned int tmp47;
+	unsigned int CRP_N = 0;
+	unsigned int ASPCR = 0;
+	unsigned int ACACR = 0;
+
+	//改变音频相关参数时需要首先disable audio, 配置完成后enable
+	//snd_err("HDMI_ICR 0x%x", hdmihw_read_reg((u16)HDMI_ICR));
+	hdmihw_write_reg(hdmihw_read_reg((u16)HDMI_ICR) & ~(0x1 << 25), (u16)HDMI_ICR);
+	hdmihw_write_reg(hdmihw_read_reg((u16)HDMI_ACRPCR) | (0x1 << 31), (u16)HDMI_ACRPCR);
+	hdmihw_read_reg((u16)HDMI_ACRPCR); /*flush write buffer effect*/
+	
+	//set_hdmi_reg_base(0);
+	tmp03 = hdmihw_read_reg((u16)HDMI_AICHSTABYTE0TO3);
+	tmp03 &= (~(0xf << 24));
+
+	tmp47 = hdmihw_read_reg((u16)HDMI_AICHSTABYTE4TO7);
+	tmp47 &= (~(0xf << 4));
+	tmp47 |= 0xb;
+
+	switch (samplerate) {
+	/* 32000, 44100, 48000, 88200, 96000,
+	176400, 192000, 352.8kHz, 384kHz */
+	case 1:
+		tmp03 |= (0x3 << 24);
+		tmp47 |= (0xc << 4);
+		CRP_N = 4096;
+		break;
+
+	case 2:
+		tmp03 |= (0x0 << 24);
+		tmp47 |= (0xf << 4);
+		CRP_N = 6272;
+		break;
+
+	case 3:
+		tmp03 |= (0x2 << 24);
+		tmp47 |= (0xd << 4);
+		CRP_N = 6144;
+		break;
+
+	case 4:
+		tmp03 |= (0x8 << 24);
+		tmp47 |= (0x7 << 4);
+		CRP_N = 12544;
+		break;
+
+	case 5:
+		tmp03 |= (0xa << 24);
+		tmp47 |= (0x5 << 4);
+		CRP_N = 12288;
+		break;
+
+	case 6:
+		tmp03 |= (0xc << 24);
+		tmp47 |= (0x3 << 4);
+		CRP_N = 12288;
+		break;
+
+	case 7:
+		tmp03 |= (0xe << 24);
+		tmp47 |= (0x1 << 4);
+		CRP_N = 24576;
+		break;
+
+	case 8:
+		tmp03 |= (0x1 << 24);
+		CRP_N = 12544;
+		break;
+
+	case 9:
+		tmp03 |= (0x1 << 24);
+		CRP_N = 12288;
+		break;
+
+	default:
+		break;
+	}
+	hdmihw_write_reg(tmp03, (u16)HDMI_AICHSTABYTE0TO3);
+	hdmihw_write_reg(tmp47, (u16)HDMI_AICHSTABYTE4TO7);
+
+	hdmihw_write_reg(0x0, (u16)HDMI_AICHSTABYTE8TO11);
+	hdmihw_write_reg(0x0, (u16)HDMI_AICHSTABYTE12TO15);
+	hdmihw_write_reg(0x0, (u16)HDMI_AICHSTABYTE16TO19);
+	hdmihw_write_reg(0x0, (u16)HDMI_AICHSTABYTE20TO23);
+
+	switch (channel) {
+	case 2:
+		hdmihw_write_reg(0x20001, (u16)HDMI_AICHSTASCN);
+		break;
+
+	case 3:
+		hdmihw_write_reg(0x121, (u16)HDMI_AICHSTASCN);
+		break;
+
+	case 4:
+		hdmihw_write_reg(0x2121, (u16)HDMI_AICHSTASCN);
+		break;
+
+	case 5:
+		hdmihw_write_reg(0x12121, (u16)HDMI_AICHSTASCN);
+		break;
+
+	case 6:
+		hdmihw_write_reg(0x212121, (u16)HDMI_AICHSTASCN);
+		break;
+
+	case 7:
+		hdmihw_write_reg(0x1212121, (u16)HDMI_AICHSTASCN);
+		break;
+
+	case 8:
+		hdmihw_write_reg(0x21212121, (u16)HDMI_AICHSTASCN);
+		break;
+
+	default:
+		break;
+	}
+	/* TODO samplesize 16bit, 20bit */
+	/* 24 bit */
+	hdmihw_write_reg((hdmihw_read_reg((u16)HDMI_AICHSTABYTE4TO7) & ~0xf),
+	(u16)HDMI_AICHSTABYTE4TO7);
+	hdmihw_write_reg(hdmihw_read_reg((u16)HDMI_AICHSTABYTE4TO7) | 0xb, (u16)HDMI_AICHSTABYTE4TO7);
+	if (Audio60958 == 1) {
+		switch (channel) {
+		case 2:
+			ASPCR = 0x00000011;
+			ACACR = 0xfac688;
+			Speaker = 0x0;
+			break;
+
+		case 3:
+			ASPCR = 0x0002d713;
+			ACACR = 0x4008;
+			Speaker = 0x1;
+			break;
+
+		case 4:
+			ASPCR = 0x0003df1b;
+			ACACR = 0x4608;
+			Speaker = 0x3;
+			break;
+
+		case 5:
+			ASPCR = 0x0003df3b;
+			ACACR = 0x2c608;
+			Speaker = 0x7;
+			break;
+
+		case 6:
+			ASPCR = 0x0003df3f;
+			ACACR = 0x2c688;
+			Speaker = 0xb;
+			break;
+
+		case 7:
+			ASPCR = 0x0007ff7f;
+			ACACR = 0x1ac688;
+			Speaker = 0xf;
+			break;
+
+		case 8:
+			ASPCR = 0x0007ffff;
+			ACACR = 0xfac688;
+			Speaker = 0x13;
+			break;
+
+		default:
+			break;
+		}
+	} else {
+		ASPCR = 0x7f87c003;
+		ACACR = 0xfac688;
+
+		tmp03 = hdmihw_read_reg((u16)HDMI_AICHSTABYTE0TO3);
+		tmp03 |= 0x1;
+		hdmihw_write_reg(tmp03, (u16)HDMI_AICHSTABYTE0TO3);
+		hdmihw_write_reg(0x21, (u16)HDMI_AICHSTASCN);
+	}
+
+	/* enable Audio FIFO_FILL  disable wait cycle */
+	hdmihw_write_reg(hdmihw_read_reg((u16)HDMI_CR) | 0x50, (u16)HDMI_CR);
+
+	if (samplerate > 7)
+		ASPCR |= (0x1 << 31);
+
+	hdmihw_write_reg(ASPCR, (u16)HDMI_ASPCR);
+	hdmihw_write_reg(ACACR, (u16)HDMI_ACACR);
+    /*非压缩格式23~30位写0
+    * 如果针对压缩码流,
+    则HDMI_AICHSTABYTE0TO3的bit[1:0]=0x2(5005新加);
+    * 如果针对线性PCM码流,则HDMI_AICHSTABYTE0TO3
+    的bit[1:0]=0x0(同227A);
+    */
+		hdmihw_write_reg(hdmihw_read_reg((u16)HDMI_AICHSTABYTE0TO3) & ~0x3,
+		(u16)HDMI_AICHSTABYTE0TO3);
+
+    /* 如果针对压缩码流,则
+    HDMI_ASPCR的bit[30:23]=0xff(5005新加);
+     *  如果针对线性PCM码流,
+     则HDMI_ASPCR的bit[30:23]=0x0(同227A);
+     */
+		hdmihw_write_reg(hdmihw_read_reg((u16)HDMI_ASPCR) & ~(0xff << 23), (u16)HDMI_ASPCR);
+
+		hdmihw_write_reg(CRP_N | (0x1 << 31), (u16)HDMI_ACRPCR);
+		hdmi_gen_audio_infoframe(channel - 1);
+
+    /*****配置完音频相关参数后enable audio*/
+    /* enable CRP */
+		hdmihw_write_reg(hdmihw_read_reg((u16)HDMI_ACRPCR) & ~(0x1 << 31), (u16)HDMI_ACRPCR);
+
+    /* enable Audio Interface */
+		hdmihw_write_reg(hdmihw_read_reg((u16)HDMI_ICR) | (0x1 << 25), (u16)HDMI_ICR);
+}
+
+static int get_hdmi_audio_fs(int sample_rate)
+{
+	int AudioFS;
+	int fs = sample_rate / 1000;
+
+	/* for O_MODE_HDMI */
+	/* 32000, 44100, 48000, 88200, 96000, 176400,
+	192000, 352.8kHz, 384kHz */
+	switch (fs) {
+	case 32:
+		AudioFS = 1;
+		break;
+	case 44:
+		AudioFS = 2;
+		break;
+	case 48:
+		AudioFS = 3;
+		break;
+	case 88:
+		AudioFS = 4;
+		break;
+	case 96:
+		AudioFS = 5;
+		break;
+	case 176:
+		AudioFS = 6;
+		break;
+	case 192:
+		AudioFS = 7;
+		break;
+	case 352:
+		AudioFS = 8;
+		break;
+	case 384:
+		AudioFS = 9;
+		break;
+	default:
+		AudioFS = 2;
+		break;
+	}
+	return AudioFS;
+}
+
+static int hdmi_audio_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	int rate = params_rate(params);
+	int audio_fs = get_hdmi_audio_fs(rate);
+
+#if defined(CONFIG_HAS_EARLYSUSPEND)&&defined(CONFIG_SND_UBUNTU)
+    if(is_suspended == 1){
+        printk(KERN_ERR"system has suspended!\n");
+        return 0;
+    }
+#endif
+	if (audio_clk_enable == 0) {
+		module_clk_enable(MOD_ID_HDMIA);
+		audio_clk_enable = 1;
+	}
+	/* we set the hdmi audio channels stereo now*/
+	set_hdmi_audio_interface(2, audio_fs);
+	#ifdef CONFIG_SND_UBUNTU
+	audio_set_output_mode(substream, O_MODE_HDMI);
+	#endif
+	return 0;
+}
+static int hdmi_dai_hw_free(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+
+	if (audio_clk_enable == 1) {
+		module_clk_disable(MOD_ID_HDMIA);
+		audio_clk_enable = 0;
+	}
+
+	return 0;
+}
+
+static int hdmi_audio_prepare(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	/* nothing should to do here now */
+	return 0;
+}
+
+static int hdmi_audio_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	/* nothing should to do here now */
+	return 0;
+}
+
+static int hdmi_audio_set_dai_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	/* nothing should to do here now */
+	return 0;
+}
+
+#define atm7059_HDMI_RATES SNDRV_PCM_RATE_8000_192000
+#ifdef CONFIG_SND_UBUNTU
+#define atm7059_HDMI_FORMATS (SNDRV_PCM_FMTBIT_S32_LE \
+| SNDRV_PCM_FMTBIT_S20_3LE | \
+		SNDRV_PCM_FMTBIT_S24_LE)
+#else
+#define atm7059_HDMI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE \
+| SNDRV_PCM_FMTBIT_S20_3LE | \
+		SNDRV_PCM_FMTBIT_S24_LE)
+#endif
+
+struct snd_soc_dai_ops hdmi_aif_dai_ops = {
+	.hw_params = hdmi_audio_hw_params,
+	.prepare = hdmi_audio_prepare,
+	.set_fmt = hdmi_audio_set_dai_fmt,
+	.set_sysclk = hdmi_audio_set_dai_sysclk,
+	.hw_free = hdmi_dai_hw_free,
+};
+
+struct snd_soc_dai_driver codec_hdmi_dai[] = {
+	{
+		.name = "atm7059-hdmi-dai",
+		.id = ATM7059_AIF_HDMI,
+		.playback = {
+			.stream_name = "atm7059 hdmi Playback",
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = atm7059_HDMI_RATES,
+			.formats = atm7059_HDMI_FORMATS,
+		},
+		.ops = &hdmi_aif_dai_ops,
+	},
+};
+
+
+
+static int codec_hdmi_probe(struct snd_soc_codec *codec)
+{
+	/* nothing should to do here now */
+	snd_dbg("codec_hdmi_probe!\n");
+	return 0;
+}
+
+static int codec_hdmi_remove(struct snd_soc_codec *codec)
+{
+	/* nothing should to do here now */
+	return 0;
+}
+
+
+
+static struct snd_soc_codec_driver soc_codec_hdmi = {
+	.probe = codec_hdmi_probe,
+	.remove = codec_hdmi_remove,
+};
+
+static int atm7059_hdmi_probe(struct platform_device *pdev)
+{
+/*
+	struct resource *res;
+	int i;
+	int ret;
+
+	struct device_node *dn;
+
+	dn = of_find_compatible_node(NULL, NULL, "actions,gl5203-audio-hdmi");
+	if (!dn) {
+		snd_err("Fail to get device_node actions,atm7039c-hdmi\r\n");
+		//goto of_get_failed;
+	}
+	
+	for(i=0; i<1; i++) 
+	{
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		if (!res) {
+			snd_err("no memory resource\n");
+			return -ENODEV;
+		}
+
+		if (!devm_request_mem_region (&pdev->dev, res->start,
+					resource_size(res), "gl5203-audio-hdmi")) {
+			snd_err("Unable to request register region\n");
+			return -EBUSY;
+		}
+
+		hdmi_res.base[i] = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+		if (hdmi_res.base[i] == NULL) {
+			snd_err("Unable to ioremap register region\n");
+			return -ENXIO;
+		}
+	}
+
+	if (1)
+	{
+		for (i = 0; i < ARRAY_SIZE(hdmi_attr); i++) 
+		{
+			ret = device_create_file(&pdev->dev, &hdmi_attr[i]);
+			if (ret) {
+				snd_err("Add device file failed");
+				//goto device_create_file_failed;
+			}
+		}
+	}
+	else
+	{
+		snd_err("Find device failed");
+		//goto err_bus_find_device;	
+	}
+*/	
+#if defined(CONFIG_HAS_EARLYSUSPEND)&&defined(CONFIG_SND_UBUNTU)
+        early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+        //ts->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 1;
+        early_suspend.suspend = hdmi_audio_early_suspend;
+        early_suspend.resume = hdmi_audio_late_resume;
+        register_early_suspend(&early_suspend);
+#endif
+	
+	dev_warn(&pdev->dev,
+			"atm7059_hdmi_probe!!\n");
+						
+	return snd_soc_register_codec(&pdev->dev, &soc_codec_hdmi,
+			codec_hdmi_dai, ARRAY_SIZE(codec_hdmi_dai));
+}
+
+static int atm7059_hdmi_remove(struct platform_device *pdev)
+{
+#if defined(CONFIG_HAS_EARLYSUSPEND)&&defined(CONFIG_SND_UBUNTU)
+        unregister_early_suspend(&early_suspend);
+#endif
+	snd_soc_unregister_codec(&pdev->dev);
+	return 0;
+}
+
+static const struct of_device_id gl5203_hdmi_of_match[] = {
+	{.compatible = "actions,gl5203-audio-hdmi",},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, gl5203_hdmi_of_match);
+
+
+static struct platform_driver atm7059_hdmi_driver = {
+	.driver = {
+			.name = "atm7059-hdmi-audio",
+			.owner = THIS_MODULE,
+	},
+
+	.probe = atm7059_hdmi_probe,
+	.remove = atm7059_hdmi_remove,
+};
+ 
+static struct platform_device *atm7059_hdmi_device;
+static int __init atm7059_hdmi_init(void)
+{
+	int ret;
+	int i = 0;
+
+	atm7059_hdmi_device = platform_device_alloc("atm7059-hdmi-audio", -1);
+	if (!atm7059_hdmi_device) {
+		snd_err(
+				"ASoC: Platform device atm7059-hdmi-audio allocation failed\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = platform_device_add(atm7059_hdmi_device);
+	if (ret) {
+		snd_err(
+				"ASoC: Platform device atm7059-hdmi-audio add failed\n");
+		goto err_device_add;
+	}
+
+	ret = platform_driver_register(&atm7059_hdmi_driver);
+	if (ret) {
+		snd_err(
+				"ASoC: Platform driver atm7059-hdmi-audio register failed\n");
+		goto err_driver_register;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(hdmi_attr); i++) {
+		ret = device_create_file(
+			&atm7059_hdmi_device->dev, &hdmi_attr[i]);
+		if (ret) {
+			snd_err("Add device file failed");
+			goto device_create_file_failed;
+		}
+	}
+
+	return 0;
+
+device_create_file_failed:
+err_driver_register:
+	platform_device_unregister(atm7059_hdmi_device);
+
+err_device_add:
+	platform_device_put(atm7059_hdmi_device);
+	
+err:
+	return ret;
+}
+static void __exit atm7059_hdmi_exit(void)
+{
+	int i = 0;
+
+	for (i = 0; i < ARRAY_SIZE(hdmi_attr); i++) {
+		device_remove_file(&atm7059_hdmi_device->dev, &hdmi_attr[i]);
+	}
+
+	platform_driver_unregister(&atm7059_hdmi_driver);
+	platform_device_unregister(atm7059_hdmi_device);
+	atm7059_hdmi_device = NULL;
+}
+
+module_init(atm7059_hdmi_init);
+module_exit(atm7059_hdmi_exit);
+
+MODULE_AUTHOR("sall.xie <sall.xie at actions-semi.com>");
+MODULE_DESCRIPTION("atm7059 HDMI AUDIO module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/atc260x/link-owl.c b/sound/soc/atc260x/link-owl.c
new file mode 100755
index 0000000..3d8e1ea
--- /dev/null
+++ b/sound/soc/atc260x/link-owl.c
@@ -0,0 +1,642 @@
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <mach/switch.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include "sndrv-owl.h"
+
+#include <linux/mfd/atc260x/atc260x.h>
+
+extern int atc2603a_audio_get_pmu_status(void);
+extern int atc2603c_audio_get_pmu_status(void);
+
+
+
+#define SOUND_MAJOR		14
+#define SNDRV_MAJOR		SOUND_MAJOR
+#define SNDRV_NAME		"sound"
+
+const char *earphone_ctrl_link_name = "earphone_detect_gpios";
+const char *speaker_ctrl_link_name = "speaker_en_gpios";
+const char *audio_atc2603a_link_node = "actions,atc2603a-audio";
+const char *audio_atc2603c_link_node = "actions,atc2603c-audio";
+
+static int earphone_gpio_num = -1;
+enum of_gpio_flags earphone_gpio_level;
+static int speaker_gpio_num;
+static enum of_gpio_flags speaker_gpio_level;
+static int speaker_gpio_active;
+static int flag = 0;
+static bool speaker_exist=true;
+
+typedef struct {
+	struct switch_dev sdev;
+	struct delayed_work dwork;
+	struct workqueue_struct *wq;
+} headphone_dev_t;
+
+static headphone_dev_t headphone_sdev;
+
+static ssize_t error_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int cnt;
+
+	cnt = sprintf(buf, "%d\n(Note: 1: open, 0:close)\n", error_switch);
+	return cnt;
+}
+
+static ssize_t error_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int cnt, tmp;
+	cnt = sscanf(buf, "%d", &tmp);
+	switch (tmp) {
+	case 0:
+	case 1:
+		error_switch = tmp;
+		break;
+	default:
+		printk(KERN_ERR"invalid input\n");
+		break;
+	}
+	return count;
+}
+
+
+static ssize_t debug_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int cnt;
+
+	cnt = sprintf(buf, "%d\n(Note: 1: open, 0:close)\n", debug_switch);
+	return cnt;
+}
+
+static ssize_t debug_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	int cnt, tmp;
+	cnt = sscanf(buf, "%d", &tmp);
+	switch (tmp) {
+	case 0:
+	case 1:
+		debug_switch = tmp;
+		break;
+	default:
+		printk(KERN_INFO"invalid input\n");
+		break;
+	}
+	return count;
+}
+
+static struct device_attribute link_attr[] = {
+	__ATTR(error, S_IRUSR | S_IWUSR, error_show, error_store),
+	__ATTR(debug, S_IRUSR | S_IWUSR, debug_show, debug_store),
+};
+
+static void set_pa_onoff(int status)
+{
+	int ret;
+	if(speaker_exist){
+		if(status){
+			ret = gpio_direction_output(speaker_gpio_num, speaker_gpio_active);
+		}else{
+			ret = gpio_direction_output(speaker_gpio_num, !speaker_gpio_active);		
+		}	
+	
+	}
+
+}
+
+static int speaker_gpio_get(struct snd_kcontrol * kcontrol,
+	struct snd_ctl_elem_value * ucontrol)
+{
+
+	int state = 0;
+	if(speaker_exist) {
+	state = !!(gpio_get_value_cansleep(speaker_gpio_num));
+	ucontrol->value.bytes.data[0] = state;	
+	}
+	return 0;
+}
+static int speaker_gpio_put(struct snd_kcontrol * kcontrol,
+	struct snd_ctl_elem_value * ucontrol)
+{
+
+	int state = 0;
+	state = ucontrol->value.bytes.data[0];
+	set_pa_onoff(state);
+	return 0;
+}
+
+static const struct snd_kcontrol_new owl_outpa_controls[] = {
+	SOC_SINGLE_BOOL_EXT("speaker on off switch", 
+			0, speaker_gpio_get, speaker_gpio_put),
+};
+
+struct device_node *atm7059_audio_get_device_node(const char *name)
+{
+	struct device_node *dn;
+
+	dn = of_find_compatible_node(NULL, NULL, name);
+	if (!dn) {
+		snd_err("Fail to get device_node\r\n");
+		goto fail;
+	}
+
+	return dn;
+fail:
+	return NULL;
+}
+
+/*earphone gpio worked as a external interrupt */
+static int atm7059_audio_gpio_init(struct device_node *dn,
+			const char *name,enum of_gpio_flags *flags)
+{
+	int gpio;
+	int ret = 0;
+
+	if (!of_find_property(dn, name, NULL)) {
+		snd_err("find %s property fail\n", name);
+		goto fail;
+	}
+
+	gpio = of_get_named_gpio_flags(dn, name, 0, flags);
+	if (gpio < 0) {
+		snd_err("get gpio[%s] fail\r\n", name);
+		goto fail;
+	}
+
+	ret = gpio_request(gpio, name);
+	if (ret) {
+		snd_err("GPIO[%d] request failed\r\n", gpio);
+		goto fail;
+	}
+	return gpio;
+
+fail:
+	return -ENOMEM;
+}
+
+static int earphone_is_in(void)
+{
+	int state = 0;
+	if (earphone_gpio_num < 0)
+	{
+		//use irq to detect earphone
+	}
+	else
+	{
+		//use gpio to detect earphone
+		state = !!(gpio_get_value_cansleep(earphone_gpio_num));
+		state ^= earphone_gpio_level;
+	}
+	return state;
+}
+
+static void gl5203_earphone_monitor(struct work_struct *work)
+{
+	if (earphone_is_in())
+		switch_set_state(&headphone_sdev.sdev, SPEAKER_ON);
+	else
+		switch_set_state(&headphone_sdev.sdev, HEADSET_NO_MIC);
+
+	if(flag == 0)
+	queue_delayed_work(headphone_sdev.wq,
+		&headphone_sdev.dwork, msecs_to_jiffies(200));
+}
+
+static int atm7059_set_gpio_ear_detect(void)
+{
+	headphone_sdev.wq = create_singlethread_workqueue("earphone_detect_wq");
+    if ( !headphone_sdev.wq ) {
+        snd_err("Create workqueue failed");
+        goto create_workqueue_failed;
+    }
+
+	INIT_DELAYED_WORK(&headphone_sdev.dwork, gl5203_earphone_monitor);
+	queue_delayed_work(headphone_sdev.wq,
+		&headphone_sdev.dwork, msecs_to_jiffies(200));
+
+	return 0;
+create_workqueue_failed:
+	return -ENODEV;
+}
+
+static int atm7059_link_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;
+	int ret;
+	snd_dbg("###atm7059_link_hw_params\n");
+
+	/* set codec DAI configuration */
+	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops atm7059_link_ops = {
+	.hw_params = atm7059_link_hw_params,
+};
+
+/*
+ * Logic for a link as connected on a atm7059 board.
+ */
+static int atm7059_link_snd_init(struct snd_soc_pcm_runtime *rtd)
+{
+	snd_dbg("atm7059_link_init() called\n");
+
+	return 0;
+}
+
+static struct snd_soc_dai_link atm7059_atc2603a_link_dai[] = {
+	{
+		.name = "ATM7059 ATC2603A",
+		.stream_name = "ATC2603A PCM",
+		.cpu_dai_name = "owl-audio-i2s",
+		.codec_dai_name = "atc2603a-dai",
+		.init = atm7059_link_snd_init,
+		.platform_name = "atm7059-pcm-audio",
+		.codec_name = "atc260x-audio",
+		.ops = &atm7059_link_ops,
+	},
+
+	{
+		.name = "ATM7059 HDMI AUDIO",
+		.stream_name = "HDMI PCM",
+		.cpu_dai_name = "owl-audio-i2s",
+		.codec_dai_name = "atm7059-hdmi-dai",
+		.init = atm7059_link_snd_init,
+		.platform_name = "atm7059-pcm-audio",
+		.codec_name = "atm7059-hdmi-audio",
+		.ops = &atm7059_link_ops,
+	}
+};
+
+static struct snd_soc_dai_link atm7059_atc2603c_link_dai[] = {
+	{
+		.name = "ATM7059 ATC2603C",
+		.stream_name = "ATC2603C PCM",
+		.cpu_dai_name = "owl-audio-i2s",
+		.codec_dai_name = "atc2603c-dai",
+		.init = atm7059_link_snd_init,
+		.platform_name = "atm7059-pcm-audio",
+		.codec_name = "atc260x-audio",
+		.ops = &atm7059_link_ops,
+	},
+
+	{
+		.name = "ATM7059 HDMI AUDIO",
+		.stream_name = "HDMI PCM",
+		.cpu_dai_name = "owl-audio-i2s",
+		.codec_dai_name = "atm7059-hdmi-dai",
+		.init = atm7059_link_snd_init,
+		.platform_name = "atm7059-pcm-audio",
+		.codec_name = "atm7059-hdmi-audio",
+		.ops = &atm7059_link_ops,
+	}
+};
+
+
+static struct snd_soc_card snd_soc_atm7059_atc2603a_link = {
+	.name = "atm7059_link",
+	.owner = THIS_MODULE,
+	.dai_link = atm7059_atc2603a_link_dai,
+	.num_links = ARRAY_SIZE(atm7059_atc2603a_link_dai),
+	.controls = owl_outpa_controls,
+	.num_controls = ARRAY_SIZE(owl_outpa_controls),
+};
+
+static struct snd_soc_card snd_soc_atm7059_atc2603c_link = {
+	.name = "atm7059_link",
+	.owner = THIS_MODULE,
+	.dai_link = atm7059_atc2603c_link_dai,
+	.num_links = ARRAY_SIZE(atm7059_atc2603c_link_dai),
+	.controls = owl_outpa_controls,
+	.num_controls = ARRAY_SIZE(owl_outpa_controls),
+};
+
+
+static struct platform_device *atm7059_link_snd_device;
+/*
+static int compare_audio_device_name(struct device *dev, void *data)
+{
+	const char *name = (const char *)data;
+	char *device_name = dev_name(dev);
+	char *match_start = strrchr(device_name, '.');
+	
+	snd_err("device_name %s, match_start %x\n", device_name, match_start);
+	if(match_start==NULL)
+	{ 
+		if(strcmp(name, device_name)==0)
+		{
+			//got a match
+			return 1;
+		}	
+		else
+		{
+			return 0;
+		}
+	}
+	
+	if((int)(match_start-device_name+1) >= (int)strlen(device_name))
+	{
+		//should not happen but in case
+		return 0;
+	}
+	
+	snd_err("name %s to match %s\n", name, match_start+1);
+	if(strcmp(name, match_start+1)==0)
+	{
+		//got a match
+		return 1;
+	}
+	
+	return 0;
+}
+*/
+
+static int dbgflag;
+
+
+static ssize_t dbgflag_show_file (struct device *dev, struct device_attribute *attr,
+        char *buf)
+{
+    return sprintf(buf, "%d", dbgflag);
+}
+
+static ssize_t dbgflag_store_file(struct device *dev, struct device_attribute *attr,
+        const char *buf, size_t count)
+{
+	char *endp;	
+	size_t size;
+	int flag = 0;
+
+	if (count > 0) {
+
+		flag = simple_strtoul(buf,&endp,0);
+		size = endp - buf;
+
+		if (*endp && (((*endp)==0x20)||((*endp)=='\n')||((*endp)=='\t')))	
+			size++;	
+		if (size != count)	
+		{
+			snd_err("%s %d %s, %d", __FUNCTION__, __LINE__, buf, flag);		
+			return -EINVAL;
+		}
+	}
+
+	dbgflag = flag;
+
+	return 0;
+}
+
+static DEVICE_ATTR(dbgflag, S_IRUGO | S_IWUSR, dbgflag_show_file, dbgflag_store_file);
+
+//david add for i2s switch.
+static int i2s_switch_gpio_num = -1;
+enum of_gpio_flags i2s_switch_gpio_level;
+const char *i2s_switch_gpio_name = "i2s_switch_gpio";
+static int i2s_switch_gpio_active;
+
+static int __init atm7059_link_init(void)
+{
+	int i = 0;
+	int ret = 0;
+	struct device_node *dn = NULL;
+	int pmu_type;
+
+	snd_err("atm7059_link_init\n");
+
+	//20141013 yuchen: check pmu type to select correct codec param
+	pmu_type = atc2603a_audio_get_pmu_status();
+	if(pmu_type == ATC260X_ICTYPE_2603A)
+	{
+		dn = atm7059_audio_get_device_node(audio_atc2603a_link_node);
+		if (!dn)
+			goto no_device_node;
+	}
+	
+	if(pmu_type == PMU_NOT_USED)
+	{
+		pmu_type = atc2603c_audio_get_pmu_status();
+		if(pmu_type == ATC260X_ICTYPE_2603C)
+		{
+			dn = atm7059_audio_get_device_node(audio_atc2603c_link_node);
+			if (!dn)
+				goto no_device_node;			
+		}
+	}
+
+	if(pmu_type == PMU_NOT_USED)
+	{
+		snd_err("ASoC: No PMU type detected!\n");
+		goto no_device_node;
+	}
+
+	/*****************20151012 david add***************/ 
+	printk(KERN_ERR"%s,%d\n", __func__, __LINE__);
+	i2s_switch_gpio_num =
+	atm7059_audio_gpio_init(dn, i2s_switch_gpio_name, &i2s_switch_gpio_level);
+	if(i2s_switch_gpio_num > 0){
+		printk(KERN_ERR"%s,%d,num:%d\n", __func__, __LINE__, i2s_switch_gpio_num);
+		i2s_switch_gpio_active = (i2s_switch_gpio_level & OF_GPIO_ACTIVE_LOW); 
+	    	gpio_direction_output(i2s_switch_gpio_num, i2s_switch_gpio_active);
+	}
+	/*************************************************/
+
+
+	earphone_gpio_num =
+		atm7059_audio_gpio_init(dn, earphone_ctrl_link_name, &earphone_gpio_level);
+	if (earphone_gpio_num < 0)
+	{
+	}
+	else
+	{
+		gpio_direction_input(earphone_gpio_num);
+	}
+
+	speaker_gpio_num =
+		atm7059_audio_gpio_init(dn, speaker_ctrl_link_name, &speaker_gpio_level);
+	speaker_gpio_active = (speaker_gpio_level & OF_GPIO_ACTIVE_LOW);
+	if(speaker_gpio_num>0)
+		speaker_exist=true;
+  	else
+		speaker_exist=false;
+	if(speaker_exist)  
+	gpio_direction_output(speaker_gpio_num, !speaker_gpio_active);
+
+	if (earphone_gpio_num > 0)
+	{
+		ret = atm7059_set_gpio_ear_detect();
+		if(ret)
+			goto set_earphone_detect_failed;
+	}
+	else
+	{
+		switch(pmu_type)
+		{
+		case ATC260X_ICTYPE_2603A:
+			snd_err("CANT GET EARPHONE GPIO!!!\n");
+			break;
+		
+		case ATC260X_ICTYPE_2603C:
+			//atc2603c_set_irq_ear_detect();
+			snd_err("maybe using irq");
+			break;
+		default:
+			break;
+		}
+		
+	}
+
+	if (earphone_gpio_num > 0)
+	{
+		//FIXME: we register h2w in codec if using irq?
+		headphone_sdev.sdev.name = "h2w";
+		ret = switch_dev_register(&headphone_sdev.sdev);
+		if (ret < 0) {
+			snd_err("failed to register switch dev for "SNDRV_NAME"\n");
+			goto switch_dev_register_failed;
+		}
+		dbgflag = 0;
+    		ret = device_create_file(headphone_sdev.sdev.dev, &dev_attr_dbgflag);
+    		if (ret)
+    		{
+    			snd_err("failed to device_create_file\n");
+        	}
+		
+	}
+
+	atm7059_link_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!atm7059_link_snd_device) {
+		snd_err("ASoC: Platform device allocation failed\n");
+		ret = -ENOMEM;
+		goto platform_device_alloc_failed;
+	}
+
+	/* 2014.09.10 check the real device names*/
+
+	//20141013 yuchen: check pmu type to select correct codec param
+	switch(pmu_type)
+	{
+	case ATC260X_ICTYPE_2603A:
+		platform_set_drvdata(atm7059_link_snd_device,
+				&snd_soc_atm7059_atc2603a_link);
+		break;
+	
+	case ATC260X_ICTYPE_2603C:
+		platform_set_drvdata(atm7059_link_snd_device,
+				&snd_soc_atm7059_atc2603c_link);
+		break;
+	default:
+		break;
+	}
+
+	ret = platform_device_add(atm7059_link_snd_device);
+	if (ret) {
+		snd_err("ASoC: Platform device allocation failed\n");
+		goto platform_device_add_failed;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(link_attr); i++) {
+		ret = device_create_file(
+			&atm7059_link_snd_device->dev, &link_attr[i]);
+		if (ret) {
+			snd_err("Add device file failed");
+			goto device_create_file_failed;
+		}
+	}
+	
+
+	return 0;
+
+device_create_file_failed:
+	platform_device_del(atm7059_link_snd_device);
+platform_device_add_failed:
+	platform_device_put(atm7059_link_snd_device);
+platform_device_alloc_failed:
+	if (earphone_gpio_num > 0)
+	{
+		switch_dev_unregister(&headphone_sdev.sdev);
+	}
+switch_dev_register_failed:
+	if (earphone_gpio_num > 0)
+	{
+		destroy_workqueue(headphone_sdev.wq);
+	}
+set_earphone_detect_failed:
+	if(speaker_exist)
+	gpio_free(speaker_gpio_num);
+	if (earphone_gpio_num > 0)
+	{
+		gpio_free(earphone_gpio_num);
+	}
+no_device_node:
+	return ret;
+}
+
+static void __exit atm7059_link_exit(void)
+{
+	int i = 0;
+
+	for (i = 0; i < ARRAY_SIZE(link_attr); i++) {
+		device_remove_file(&atm7059_link_snd_device->dev, &link_attr[i]);
+	}
+	if (headphone_sdev.wq) {
+		flag = 1;
+		msleep(500);/*clear the queue,ensure no cpu write to it*/
+		flush_delayed_work(&headphone_sdev.dwork);
+		destroy_workqueue(headphone_sdev.wq);
+		headphone_sdev.wq = NULL;
+	}
+
+	if(earphone_gpio_num > 0)
+	{
+		gpio_free(earphone_gpio_num);
+		earphone_gpio_num = -1;
+		switch_dev_unregister(&headphone_sdev.sdev);
+	}
+	if(speaker_exist){
+		gpio_free(speaker_gpio_num);
+	}	
+	speaker_gpio_num = -1;
+
+    /*---------------david add-----------------------*/
+    if(i2s_switch_gpio_num > 0)
+    {
+		gpio_free(i2s_switch_gpio_num);
+		i2s_switch_gpio_num = -1;
+    }
+    /*----------------------------------------------*/
+
+	platform_device_unregister(atm7059_link_snd_device);
+}
+
+module_init(atm7059_link_init);
+module_exit(atm7059_link_exit);
+
+/* Module information */
+MODULE_AUTHOR("sall.xie <sall.xie at actions-semi.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/atc260x/pcm-owl.c b/sound/soc/atc260x/pcm-owl.c
new file mode 100755
index 0000000..2be508b
--- /dev/null
+++ b/sound/soc/atc260x/pcm-owl.c
@@ -0,0 +1,528 @@
+/*
+ * atm7059-pcm.c  --  ALSA PCM interface for the OMAP SoC
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula at bitmer.com>
+ *          Peter Ujfalusi <peter.ujfalusi at ti.com>
+ *
+ * This program 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 program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+#include <linux/dma-mapping.h>
+
+#include <mach/hardware.h>
+#include "sndrv-owl.h"
+
+static struct snd_pcm_hardware atm7059_playback_hw_info = {
+	.info			= SNDRV_PCM_INFO_MMAP |
+				  SNDRV_PCM_INFO_MMAP_VALID |
+				  SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				  SNDRV_PCM_INFO_RESUME,
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
+				  SNDRV_PCM_FMTBIT_S32_LE,
+	.rate_min		= 8000,
+	.rate_max		= 192000,
+	.channels_min		= 2,
+	.channels_max		= 8,
+	#ifdef CONFIG_SND_UBUNTU
+	.buffer_bytes_max	= 32 * 1024,
+	#else
+	.buffer_bytes_max	= 64 * 1024,
+	#endif
+	.period_bytes_min	= 256,
+	.period_bytes_max	= 32*1024,
+	.periods_min		= 2,
+	.periods_max		= 16,
+};
+
+static struct snd_pcm_hardware atm7059_capture_hw_info = {
+	.info			= SNDRV_PCM_INFO_MMAP |
+				  SNDRV_PCM_INFO_MMAP_VALID |
+				  SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_BLOCK_TRANSFER |
+				  SNDRV_PCM_INFO_RESUME,
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
+				  SNDRV_PCM_FMTBIT_S32_LE,
+	.rate_min		= 8000,
+	.rate_max		= 96000,
+	.channels_min		= 1,
+	.channels_max		= 4,
+	.buffer_bytes_max	= 64 * 1024,
+	.period_bytes_min	= 256,
+	.period_bytes_max	= 32*1024,
+	.periods_min		= 2,
+	.periods_max		= PAGE_SIZE / 16,
+};
+#ifdef CONFIG_SND_UBUNTU
+int audio_set_output_mode(struct snd_pcm_substream *substream, int value)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+    struct snd_soc_platform *platform = rtd->platform;
+    struct atm7059_pcm_priv *pcm_priv =
+        snd_soc_platform_get_drvdata(platform);
+	pcm_priv->output_mode = value;
+	return 0;
+}
+#endif
+static ssize_t error_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int cnt;
+
+	cnt = sprintf(buf, "%d\n(Note: 1: open, 0:close)\n", error_switch);
+	return cnt;
+}
+
+static ssize_t error_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	int cnt, tmp;
+	cnt = sscanf(buf, "%d", &tmp);
+	switch (tmp) {
+	case 0:
+	case 1:
+		error_switch = tmp;
+		break;
+	default:
+		printk(KERN_ERR"invalid input\n");
+		break;
+	}
+	return count;
+}
+
+
+static ssize_t debug_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	int cnt;
+
+	cnt = sprintf(buf, "%d\n(Note: 1: open, 0:close)\n", debug_switch);
+	return cnt;
+}
+
+static ssize_t debug_store(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	int cnt, tmp;
+	cnt = sscanf(buf, "%d", &tmp);
+	switch (tmp) {
+	case 0:
+	case 1:
+		debug_switch = tmp;
+		break;
+	default:
+		printk(KERN_INFO"invalid input\n");
+		break;
+	}
+	return count;
+}
+
+static struct device_attribute pcm_attr[] = {
+	__ATTR(error, S_IRUSR | S_IWUSR, error_show, error_store),
+	__ATTR(debug, S_IRUSR | S_IWUSR, debug_show, debug_store),
+};
+
+
+static const char *const audio_output_mode[]
+	= {"i2s", "hdmi", "spdif"};
+static const SOC_ENUM_SINGLE_DECL(audio_output_enum,
+	0, 0, audio_output_mode);
+
+static int audio_output_mode_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_platform *platform =
+		snd_kcontrol_chip(kcontrol);
+	struct atm7059_pcm_priv *pcm_priv =
+		snd_soc_platform_get_drvdata(platform);
+	ucontrol->value.integer.value[0] = pcm_priv->output_mode;
+	return 0;
+}
+
+static int audio_output_mode_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_platform *platform =
+		snd_kcontrol_chip(kcontrol);
+	struct atm7059_pcm_priv *pcm_priv =
+		snd_soc_platform_get_drvdata(platform);
+
+	pcm_priv->output_mode = ucontrol->value.integer.value[0];
+	return 0;
+}
+
+static const struct snd_kcontrol_new atm7059_pcm_controls[] = {
+	SOC_ENUM_EXT("audio output mode switch", audio_output_enum,
+			audio_output_mode_get, audio_output_mode_put),
+};
+
+/* this may get called several times by oss emulation */
+static int atm7059_pcm_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
+	//struct imx_pcm_dma_params *dma_params;
+	struct dma_slave_config slave_config;
+	int ret;
+
+	struct owl_dma_slave *atslave = (struct owl_dma_slave *)chan->private;
+	dma_addr_t dst_addr;
+	enum dma_slave_buswidth dst_addr_width;
+
+
+	//dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+	//direction, dst_addr_width or src_addr_width
+	ret = snd_hwparams_to_dma_slave_config(substream, params, &slave_config);
+	if (ret)
+		return ret;
+
+	slave_config.device_fc = false;
+
+	atslave->dma_dev = chan->device->dev;
+	atslave->trans_type = SLAVE;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		struct snd_soc_platform *platform = rtd->platform;
+		struct atm7059_pcm_priv *pcm_priv =
+			snd_soc_platform_get_drvdata(platform);
+
+		switch (pcm_priv->output_mode) {
+		case O_MODE_SPDIF:
+			atslave->mode = PRIORITY_SEVEN| SRC_INCR |
+			    DST_CONSTANT | SRC_DCU | DST_DEV | HDMIAUDIO | CRITICAL_BIT;
+			dst_addr = SPDIF_DAT;
+			break;
+		case O_MODE_HDMI:
+			atslave->mode = PRIORITY_SEVEN | SRC_INCR |
+			    DST_CONSTANT | SRC_DCU | DST_DEV | HDMIAUDIO | CRITICAL_BIT;
+			dst_addr = HDMI_DAT;
+			break;
+		case O_MODE_I2S:
+		default:
+			atslave->mode = PRIORITY_SEVEN | SRC_INCR |
+			    DST_CONSTANT | SRC_DCU | DST_DEV | I2S_T | CRITICAL_BIT;
+			dst_addr = I2STX_DAT;
+			break;
+		}
+
+		slave_config.dst_addr = dst_addr;
+
+		dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		slave_config.dst_addr_width = dst_addr_width;
+
+	} else {
+		atslave->mode = PRIORITY_SEVEN | SRC_CONSTANT |
+		    DST_INCR | DST_DCU | SRC_DEV | I2S_R | CRITICAL_BIT;
+
+		slave_config.src_addr = I2SRX_DAT;
+
+		slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	}
+
+	ret = dmaengine_slave_config(chan, &slave_config);
+	if (ret)
+		return ret;
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	/*
+	 * Set DMA transfer frame size equal to ALSA period size and frame
+	 * count as no. of ALSA periods. Then with DMA frame interrupt enabled,
+	 * we can transfer the whole ALSA buffer with single DMA transfer but
+	 * still can get an interrupt at each period bounary
+	 */
+
+	return 0;
+}
+
+static int atm7059_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	snd_pcm_set_runtime_buffer(substream, NULL);
+
+	return 0;
+}
+
+static int atm7059_pcm_prepare(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+static int atm7059_pcm_open(struct snd_pcm_substream *substream)
+{
+	int ret;
+	struct dma_chan *chan;
+	struct owl_dma_slave *atslave = kzalloc(sizeof(*atslave), GFP_KERNEL);
+	if (!atslave)
+		return -ENOMEM;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		snd_soc_set_runtime_hwparams(substream, &atm7059_playback_hw_info);
+	} else {
+		snd_soc_set_runtime_hwparams(substream, &atm7059_capture_hw_info);
+	}
+
+	//snd_pcm_hw_constraint_integer&&\B7\D6\C5\E4\D4\CB\D0\D0ʱ&&\C9\EA\C7\EBͨ\B5\C0
+	//ret = snd_dmaengine_pcm_open(substream, filter, dma_data);
+	ret = snd_dmaengine_pcm_open_request_chan(substream, NULL, NULL);
+	if (ret) {
+		return 0;
+	}
+
+	//snd_dmaengine_pcm_set_data(substream, dma_data);
+
+	chan = snd_dmaengine_pcm_get_chan(substream);
+	chan->private = (void *)atslave;
+	return 0;
+}
+
+static int atm7059_pcm_close(struct snd_pcm_substream *substream)
+{
+	//struct imx_dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
+	//\CAͷ\C5ͨ\B5\C0\A3\AC\CAͷ\C5\D4\CB\D0\D0ʱ
+	snd_dmaengine_pcm_close_release_chan(substream);
+	//printk("%s %d\n", __FUNCTION__, __LINE__);
+
+	//kfree(dma_data);
+
+	return 0;
+}
+
+static int atm7059_pcm_mmap(struct snd_pcm_substream *substream,
+	struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int ret= dma_mmap_coherent(substream->pcm->card->dev, vma,
+				                            runtime->dma_area,
+				                            runtime->dma_addr,
+				                            runtime->dma_bytes);
+	return ret;
+}
+
+static struct snd_pcm_ops atm7059_pcm_ops = {
+	.open		= atm7059_pcm_open,
+	.close		= atm7059_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= atm7059_pcm_hw_params,
+	.hw_free	= atm7059_pcm_hw_free,
+	.prepare	= atm7059_pcm_prepare,
+	.trigger	= snd_dmaengine_pcm_trigger,
+	.pointer	= snd_dmaengine_pcm_pointer_no_residue,
+	.mmap		= atm7059_pcm_mmap,
+};
+
+static u64 atm7059_pcm_dmamask = DMA_BIT_MASK(32);
+
+static int atm7059_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
+	int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size;
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		size = atm7059_playback_hw_info.buffer_bytes_max;
+	else
+		size = atm7059_capture_hw_info.buffer_bytes_max;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_coherent(pcm->card->dev, size,
+					   &buf->addr, GFP_KERNEL);
+	if (!buf->area)
+		return -ENOMEM;
+
+	buf->bytes = size;
+
+	return 0;
+}
+
+static void atm7059_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+
+		dma_free_coherent(pcm->card->dev, buf->bytes,
+				      buf->area, buf->addr);
+
+		buf->area = NULL;
+	}
+}
+
+static int atm7059_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_card *card = rtd->card->snd_card;
+	struct snd_pcm *pcm = rtd->pcm;
+	int ret = 0;
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &atm7059_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+		ret = atm7059_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret)
+			goto out;
+	}
+
+	if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+		ret = atm7059_pcm_preallocate_dma_buffer(pcm,
+			SNDRV_PCM_STREAM_CAPTURE);
+		if (ret)
+			goto out;
+	}
+
+out:
+	/* free preallocated buffers in case of error */
+	if (ret)
+		atm7059_pcm_free_dma_buffers(pcm);
+
+	return ret;
+}
+
+static struct snd_soc_platform_driver atm7059_soc_platform = {
+	.ops		= &atm7059_pcm_ops,
+	.pcm_new	= atm7059_pcm_new,
+	.pcm_free	= atm7059_pcm_free_dma_buffers,
+	.component_driver = {
+		.controls = atm7059_pcm_controls,
+		.num_controls = ARRAY_SIZE(atm7059_pcm_controls),
+	},
+};
+
+static int atm7059_pcm_probe(struct platform_device *pdev)
+{
+	dev_info(&pdev->dev,
+			"atm7059_pcm_probe!!\n");
+	pdev->dev.init_name = "atm7059-pcm-audio";
+	return snd_soc_register_platform(&pdev->dev,
+			&atm7059_soc_platform);
+}
+
+static int atm7059_pcm_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver atm7059_pcm_driver = {
+	.driver = {
+			.name = "atm7059-pcm-audio",
+			.owner = THIS_MODULE,
+	},
+
+	.probe = atm7059_pcm_probe,
+	.remove = atm7059_pcm_remove,
+};
+
+static struct platform_device *atm7059_pcm_device;
+static int __init atm7059_pcm_init(void)
+{
+	int ret;
+	int i = 0;
+	struct atm7059_pcm_priv *pcm_priv;
+
+	snd_dbg("atm7059_pcm_init!!\n");
+	atm7059_pcm_device = platform_device_alloc("atm7059-pcm-audio", -1);
+	if (!atm7059_pcm_device) {
+		snd_dbg(
+				"ASoC: Platform device atm7059-pcm-audio allocation failed\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = platform_device_add(atm7059_pcm_device);
+	if (ret) {
+		snd_dbg(
+				"ASoC: Platform device atm7059-pcm-audio add failed\n");
+		goto err_device_add;
+	}
+
+	pcm_priv = kzalloc(sizeof(struct atm7059_pcm_priv), GFP_KERNEL);
+	if (NULL == pcm_priv)
+		return -ENOMEM;
+	pcm_priv->output_mode = O_MODE_I2S;
+	platform_set_drvdata(atm7059_pcm_device, pcm_priv);
+
+	ret = platform_driver_register(&atm7059_pcm_driver);
+	if (ret) {
+		snd_dbg(
+				"ASoC: Platform driver atm7059-pcm-audio register failed\n");
+		goto err_driver_register;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(pcm_attr); i++) {
+		ret = device_create_file(
+			&atm7059_pcm_device->dev, &pcm_attr[i]);
+		if (ret) {
+			snd_err("Add device file failed");
+			goto device_create_file_failed;
+		}
+	}
+
+	return 0;
+
+device_create_file_failed:
+err_driver_register:
+	platform_device_unregister(atm7059_pcm_device);
+err_device_add:
+	platform_device_put(atm7059_pcm_device);
+err:
+	return ret;
+}
+static void __exit atm7059_pcm_exit(void)
+{
+	int i = 0;
+
+	for (i = 0; i < ARRAY_SIZE(pcm_attr); i++) {
+		device_remove_file(&atm7059_pcm_device->dev, &pcm_attr[i]);
+	}
+
+	platform_driver_unregister(&atm7059_pcm_driver);
+	platform_device_unregister(atm7059_pcm_device);
+	atm7059_pcm_device = NULL;
+}
+
+module_init(atm7059_pcm_init);
+module_exit(atm7059_pcm_exit);
+
+MODULE_AUTHOR("sall.xie <sall.xie at actions-semi.com>");
+MODULE_DESCRIPTION("ATM7059 PCM module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/atc260x/sndrv-owl.h b/sound/soc/atc260x/sndrv-owl.h
new file mode 100755
index 0000000..51a2077
--- /dev/null
+++ b/sound/soc/atc260x/sndrv-owl.h
@@ -0,0 +1,101 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2009 Actions Semi Inc.
+ */
+
+#ifndef __ATM7059_SNDRV_H__
+#define __ATM7059_SNDRV_H__
+#include <sound/pcm.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+#include <linux/atomic.h>
+#include <mach/hdmac-owl.h>
+#include <linux/dmaengine.h>
+#include <linux/pinctrl/consumer.h>
+
+#define PMU_NOT_USED	-1
+
+#define COMPILETEST 0
+
+#define ATM7059_AIF_I2S 0
+#define ATM7059_AIF_HDMI 0
+static int error_switch = 1;
+static int debug_switch = 1;
+
+#define SND_DEBUG
+#ifdef SND_DEBUG
+#define snd_err(fmt, args...) \
+	if (error_switch) \
+		printk(KERN_ERR"[SNDRV]:[%s] "fmt"\n", __func__, ##args)
+
+#define snd_dbg(fmt, args...) \
+	if (debug_switch) \
+		printk(KERN_DEBUG"[SNDRV]:[%s] "fmt"\n", __func__, ##args)
+#endif
+
+enum {
+	O_MODE_I2S,
+	O_MODE_HDMI,
+	O_MODE_SPDIF
+};
+
+enum {
+	SPEAKER_ON = 0,
+	HEADSET_MIC = 1,
+	HEADSET_NO_MIC = 2,
+};
+
+
+
+typedef struct {
+	short sample_rate;	/* 真实采样率除以1000 */
+	char index[2];		/* 对应硬件寄存器的索引值 */
+} fs_t;
+
+typedef struct {
+	unsigned int earphone_gpios;
+	unsigned int speaker_gpios;
+	unsigned int earphone_output_mode;
+	unsigned int mic_num;
+	unsigned int mic0_gain[2];
+	unsigned int speaker_gain[2];
+	unsigned int earphone_gain[2];
+	unsigned int speaker_volume;
+	unsigned int earphone_volume;
+	unsigned int earphone_detect_mode;
+	unsigned int mic_mode;
+	unsigned int earphone_detect_method;
+	unsigned int adc_plugin_threshold;
+	unsigned int adc_level;
+} audio_hw_cfg_t;
+
+//extern audio_hw_cfg_t audio_hw_cfg;
+
+struct atm7059_pcm_priv {
+	int output_mode;
+	struct pinctrl *pc;
+	struct pinctrl_state *ps;
+};
+
+enum{
+I2S_SPDIF_NUM = 0,
+GPIO_MFP_NUM,
+HDMI_NUM,
+MAX_RES_NUM
+};
+
+void set_dai_reg_base(int num);
+u32 snd_dai_readl(u32 reg);
+void snd_dai_writel(u32 val, u32 reg);
+
+extern void hdmihw_write_reg(u32 val, const u16 idx);
+extern int hdmihw_read_reg(const u16 idx);
+#ifdef CONFIG_SND_UBUNTU
+int audio_set_output_mode(struct snd_pcm_substream *substream, int value);
+#endif
+#endif /* ifndef __ATM7059_SNDRV_H__ */
-- 
2.7.4



More information about the linux-yocto mailing list