Index: linux-2.6.23/drivers/input/touchscreen/Kconfig
===================================================================
--- linux-2.6.23.orig/drivers/input/touchscreen/Kconfig	2008-02-13 01:12:29.000000000 +0000
+++ linux-2.6.23/drivers/input/touchscreen/Kconfig	2008-02-13 01:13:20.000000000 +0000
@@ -54,6 +54,12 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called corgi_ts.
 
+config TOUCHSCREEN_ZYLONITE
+	tristate "Zylonite touchscreen driver"
+	default y
+	help
+	  Say Y here for the Zylonite touchscreen driver
+
 config TOUCHSCREEN_FUJITSU
 	tristate "Fujitsu serial touchscreen"
 	select SERIO
Index: linux-2.6.23/drivers/input/touchscreen/Makefile
===================================================================
--- linux-2.6.23.orig/drivers/input/touchscreen/Makefile	2008-02-13 01:12:29.000000000 +0000
+++ linux-2.6.23/drivers/input/touchscreen/Makefile	2008-02-13 01:13:38.000000000 +0000
@@ -19,3 +19,4 @@
 obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)	+= touchwin.o
 obj-$(CONFIG_TOUCHSCREEN_UCB1400)	+= ucb1400_ts.o
 obj-$(CONFIG_TOUCHSCREEN_TSC2101)	+= tsc2101_ts.o
+obj-$(CONFIG_TOUCHSCREEN_ZYLONITE)	+= zylonite-ts.o
Index: linux-2.6.23/drivers/input/touchscreen/zylonite-ts.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.23/drivers/input/touchscreen/zylonite-ts.c	2008-02-13 16:19:15.000000000 +0000
@@ -0,0 +1,1517 @@
+/*
+ *  drivers/input/touchscreen/mhn_audio_touch.c.
+ *
+ *  Author:	bridge.wu@marvell.com
+ *  Created:	Nov 17, 2006
+ *  Copyright:	Marvell Corporation.
+ *
+ *  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.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+
+#include <asm/semaphore.h>
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/mfp.h>
+//#include <asm/arch/ipmc.h>
+#include <linux/suspend.h>
+#include <linux/spinlock.h>
+
+//#include <asm/arch/codec/acodec.h>
+//#include <asm/arch/mhn_audio_plat.h>
+
+#define OSCC               __REG(0x41350000)  /* Oscillator Configuration Register */
+#define AC97_DIV	__REG(0x41340014)
+
+#define ALSA_ZY_CARD_DEBUG
+#undef ALSA_ZY_CARD_DEBUG
+
+#define WM_9713_ID  0x4C13 /* this should be the 7E register value */
+
+#ifdef ALSA_ZY_CARD_DEBUG
+#define dbg(format, arg...) printk(KERN_DEBUG format, ##arg)
+#else
+#define dbg(format, arg...)
+#endif
+
+#define DEBUG
+#undef DEBUG
+#ifdef DEBUG
+unsigned int start_time;
+unsigned int end_time;
+unsigned int time;
+#define PRINT_TIME() do {\
+        time = ((end_time > start_time))?\
+                (end_time - start_time)*100/325:\
+                (0xffffffff - start_time + end_time)*100/325;\
+        printk("\n%s:%dus\n", __FUNCTION__, time);\
+} while(0)
+#endif
+
+
+
+
+/* 9713 specific
+ *	Register Name			Index
+ */
+#define RESET				0X00
+#define SPEAKER_VOLUME 			0X02
+#define HEADPHONE_VOLUME		0X04
+#define OUT3_OUT4_VOLUME  		0X06
+#define MONOVOL_MONOINPGA_ROUTE		0X08
+#define LINE_IN_PGA_VOL_ROUTE		0X0A
+#define DAC_PGA_VOL_ROUTE		0X0C
+#define MIC_PGA_VOLUME			0X0E
+#define MIC_ROUTING			0X10
+#define REC_PGA_VOL			0X12
+#define REC_ROUTE_MUX_SEL		0X14
+#define PCBEEP_VOL_ROUTE		0X16
+#define VXDAC_VOLUME_ROUTE		0X18
+#define AUX_DAC_VOL_ROUTE		0X1A
+#define OUTPUT_PGA_MUX			0X1C
+#define DAC_3D_CTRL_INV_MUX_SEL		0X1E
+#define DAC_TONE_CTRL			0X20
+#define MIC_BIAS			0X22
+#define OUTPUT_VOL_MAPPING_JACK		0X24
+#define POWERDOWN_CTRL_STAT		0X26
+#define EXTENDED_AUD_ID			0X28
+#define EXTENDED_AUD_STAT_CTRL  	0X2A
+#define AUDIO_DAC_RATE			0X2C
+#define AUX_DAC_RATE			0X2E
+#define AUDIO_ADC_RATE			0X32
+#define PCM_CODEC_CTRL			0X36
+#define SPDIF_CTRL			0X3A
+#define POWER_DOWN_1			0X3C
+#define POWER_DOWN_2			0X3E
+#define GENERAL_PURPOSE_WM_13		0X40
+#define FAST_POWERUP_CTRL		0X42
+#define MCLK_PLL_CTRL_1			0X44
+#define MCLK_PLL_CTRL_2			0X46
+#define GPIO_PIN_CFG			0X4C
+#define GPIO_PIN_POL_TYPE		0X4E
+#define GPIO_PIN_STICKY 		0X50
+#define GPIO_PIN_WAKEUP			0X52
+#define GPIO_PIN_STATUS			0X54
+#define GPIO_PIN_SHARING		0X56
+#define GPIO_PULL_UP_DOWN_CTRL		0X58
+#define ADD_FUNC_1         		0X5A
+#define ADD_FUNC_2        		0X5C
+#define ALC_CTRL         		0X60
+#define ALC_NOISE_GATE_CTRL		0X62
+#define AUX_DAC_INPUT_CTRL 		0X64
+#define TEST_REG_1 			0X68
+#define TEST_REG_2 			0X6A
+#define TEST_REG_3 			0X6C
+#define TEST_REG_4 			0X6E
+#define DIGITIZER_1_WM13	    	0x74
+#define DIGITIZER_2_WM13	    	0x76
+#define DIGITIZER_3_WM13	    	0x78
+#define DIGITIZER_READ_BACK	    	0x7a
+#define VENDOR_ID1	  		0x7c
+#define VENDOR_ID2	  		0x7e
+
+#define ZY_TOUCH_SAMPLE_X 1
+#define ZY_TOUCH_SAMPLE_Y 2
+
+#define ZY_EVENT_TYPE_NONE			0
+#define ZY_EVENT_TYPE_PDN			1
+
+
+typedef enum _zy_acodec_error_t {
+    ZY_ACODEC_SUCCESS = 0,    /* successful completion of a function */
+    ZY_ACODEC_GENERAL_SW_ERR, /* null pointer to registers or other software error */
+    ZY_ACODEC_CONTROLLER_INTERFACE_TIMEOUT, /* time-out for waiting for respponse */
+    ZY_ACODEC_SAMPLERATE_NOT_SUPPORTED, /* the sample rate is not supported either in controller or codec */
+    ZY_ACODEC_FEATURE_NO_SUPPORTED, /* this codec feature is not supported  */
+    ZY_ACODEC_GENERAL_HW_ERR ,/* other hardware error besides time out */
+    ZY_ACODEC_ROUTE_NO_SUPPORTED, /* the codec can not set the route required */
+    ZY_ACODEC_SLEEP /* the codec is sleep */
+} zy_acodec_error_t;
+
+typedef unsigned int zy_acodec_device_id_t;
+
+typedef enum _codec_state {
+	ZY_CODEC_SLEEP  = 0,
+	ZY_CODEC_WAKEUP = 1
+} acodec_state_t;
+
+typedef enum {
+       ZY_FM = 0,
+       ZY_MIC1 = 1,
+       ZY_MIC2 = 2,
+       ZY_SPEAKER =3,
+       ZY_HEADSET =4,
+       ZY_HANDSET =5,
+} vol_port_type_t;
+
+typedef struct _context_t {
+	int  use_count; 		/* probe/remove and suspend/resume usage count, sync among multiple devices */
+	zy_acodec_device_id_t acodec_id;/* - an ID that uniquely identifies the codec to be used */
+	unsigned long init_number; 	/* used by driver to track whether it is inited or not */
+
+	void *p_voice_reg;       	/* pointer to Monahans registers that has PCM interface to codec */
+	void *p_hifi_reg;        	/* pointer to Monahans registers that has hifi interface to codec */
+	void *p_ctrl_reg;        	/* pointer to Monahans registers that has control interface to codec */
+	int  *p_ost_regs;		/* needed for time out */
+	void *p_save_memory;        	/* pointer to a memory region to save context while suspend */
+    	void *p_zy_scenario;        	/* pointer to the scenario data structure  */
+    	long u_max_read_write_time_out_ms;/* input the max time to wait in milliseconds before giving up on a read or write operation */
+	long u_max_setup_time_out_ms;	/* input the maximum time in milliseconds to wait during initial setup of the ACODEC controller and codec */
+
+	/* member functions these pointers must be set by */
+	zy_acodec_error_t (* g_pfn_codec_specific_init)      (struct _context_t *p_device_context);
+	zy_acodec_error_t (* g_pfn_codec_specific_dinit)    (struct _context_t *p_device_context);
+	zy_acodec_error_t (* g_pfn_acodec_read)             (struct _context_t *p_dev_context, unsigned short reg_addr, unsigned short *p_reg_value);
+	zy_acodec_error_t (* g_pfn_acodec_write)            (struct _context_t *p_dev_context, unsigned short reg_addr, unsigned short reg_value);
+
+	/* add for route */
+	zy_acodec_error_t (* g_pfn_set_route)           (struct _context_t *p_device_context, unsigned short * rout_map ,unsigned short* current_map);
+	/* add for sleep the codec */
+	zy_acodec_error_t (* g_pfn_sleep_codec)           (struct _context_t *p_device_context);
+	/* add for Wake up the codec */
+	zy_acodec_error_t (* g_pfn_wake_codec)           (struct _context_t *p_device_context);
+	/* add for get codec state */
+	zy_acodec_error_t (* g_pfn_get_state)           (struct _context_t *p_device_context, acodec_state_t *p_state);
+	/* add for volume */
+	zy_acodec_error_t (* g_pfn_get_vol)(struct _context_t *p_device_context, vol_port_type_t port,  unsigned short *gain_in_db);
+	zy_acodec_error_t (* g_pfn_set_vol)(struct _context_t *p_device_context, vol_port_type_t port,  unsigned short gain_in_db);
+
+        void (* g_pfn_get_event)(struct _context_t *p_device_context, unsigned char * event_type);
+        void (* g_pfn_event_ack)(struct _context_t *p_device_context, unsigned char event_type);
+        zy_acodec_error_t (* g_pfn_enable_touch)(struct _context_t *p_device_context);
+        zy_acodec_error_t (* g_pfn_disable_touch)(struct _context_t *p_device_context);
+} zy_acocec_context_t, *p_zy_acocec_context_t;
+
+
+
+
+
+static p_zy_acocec_context_t p_zy_codec_ctxt = NULL;
+
+#include <linux/input.h>
+//#include <asm/arch/codec/wm9713.h>
+
+#define PEN_DOWN 		1
+#define PEN_UP			0
+#define TS_SAMPLE_INTERVAL 	1
+
+typedef struct {
+	struct input_dev *idev;
+	struct timer_list *timer;
+	int  use_count;
+} codec_zy_ts_t;
+
+codec_zy_ts_t codec_zy_ts;
+
+static struct input_dev *codec_zy_ts_input;
+
+#ifdef CONFIG_PM
+static volatile int touch_suspend = 0 ;
+#endif
+
+#define ZY_AC97_CODEC_REGS_NUM        0x40
+
+typedef struct
+{  //   Register symbol     // Usage
+    volatile unsigned long pocr;           // PCM Out Control Register
+    volatile unsigned long picr;           // PCM In Control Register
+    volatile unsigned long mccr;           // Mic In Control Register
+    volatile unsigned long gcr;            // Global Control Register
+    volatile unsigned long posr;           // PCM Out Status Register
+    volatile unsigned long pisr;           // PCM In Status Register
+    volatile unsigned long mcsr;           // Mic In Status Register
+    volatile unsigned long gsr;            // Global Status Register
+    volatile unsigned long car;            // CODEC Access Register
+    volatile unsigned long pcscr;          // PCM Surround Out Control
+    volatile unsigned long pcssr;          // PCM Surround Out Status
+    volatile unsigned long pcsdr;          // PCM Surround Out Data
+    volatile unsigned long pcclcr;         // PCM Center/LFE Out Control
+    volatile unsigned long pcclsr;         // PCM Center/LFE Out Status
+    volatile unsigned long pccldr;         // PCM Center/LFE Out Data
+    volatile unsigned long reserved1;       //
+    volatile unsigned long pcdr;           // PCM FIFO Data Register
+    volatile unsigned long reserved2 [0x7];      // 0x4050-0044 through 0x4050-005C
+    volatile unsigned long mcdr;           // Mic-in FIFO Data Register
+    volatile unsigned long reserved3 [0x27];   // 0x4050-0064 through 0x4050-00FC
+    volatile unsigned long mocr;           // MODEM Out Control Register
+    volatile unsigned long reserved4;
+    volatile unsigned long micr;           // MODEM In Control Register
+    volatile unsigned long reserved5;
+    volatile unsigned long mosr;           // MODEM Out Status Register
+    volatile unsigned long reserved6;
+    volatile unsigned long misr;           // MODEM In Status Register
+    volatile unsigned long reserved7 [0x9];      // 0x4050-011C through 0x4050-013C
+    volatile unsigned long modr;           // MODEM FIFO Data Register
+    volatile unsigned long reserved8 [0x2F];   // 0x4050-0144 through 0x4050-01FC
+                            // Primary Audio CODEC registers access
+    volatile unsigned long codec_regs_primary_aud   [ZY_AC97_CODEC_REGS_NUM];
+                            // Secondary ID 01 Audio CODEC registers access
+    volatile unsigned long codec_regs_secondary_aud [ZY_AC97_CODEC_REGS_NUM];
+                            // Primary MODEM CODEC registers access
+    volatile unsigned long codec_regs_primary_mdm   [ZY_AC97_CODEC_REGS_NUM];
+                            // Secondary ID 01 MODEM CODEC registers access
+    volatile unsigned long codec_regs_secondary_mdm [ZY_AC97_CODEC_REGS_NUM];
+                            // Secondary ID 10 MODEM CODEC registers access
+    volatile unsigned long codec_regs_third_mdm [ZY_AC97_CODEC_REGS_NUM];
+                            // Secondary ID 11 MODEM CODEC registers access
+    volatile unsigned long codec_regs_fouth_mdm [ZY_AC97_CODEC_REGS_NUM];
+                            // Secondary ID 10 Audio CODEC registers access
+    volatile unsigned long codec_regs_third_aud [ZY_AC97_CODEC_REGS_NUM];
+                            // Secondary ID 11 Audio CODEC registers access
+    volatile unsigned long codec_regs_fouth_aud [ZY_AC97_CODEC_REGS_NUM];
+}  zy_ac97_acodec_t, *p_zy_ac97acodec_t ;
+
+
+/* Constants for the Global Control Register and Global Status Register */
+
+// AC97 Global Control Register bit mask constants
+
+#define ZY_AC97_GCR_GIE_MSK          (1u << 0 )
+#define ZY_AC97_GCR_COLD_RESET_MSK   (1u << 1 )
+#define ZY_AC97_GCR_WARM_RESET_MSK   (1u << 2 )
+#define ZY_AC97_GCR_LINK_OFF_MSK     (1u << 3 )
+#define ZY_AC97_GCR_PCRSM_IEN_MSK    (1u << 4 )
+#define ZY_AC97_GCR_SCRSM_IEN_MSK    (1u << 5 )
+#define ZY_AC97_GCR_PCRDY_IEN_MSK    (1u << 8 )
+#define ZY_AC97_GCR_SCRDY_IEN_MSK    (1u << 9 )
+#define ZY_AC97_GCR_SDONE_IE_MSK     (1u << 18)
+#define ZY_AC97_GCR_CDONE_IE_MSK     (1u << 19)
+#define ZY_AC97_GCR_nDMAEN_MSK       (1u << 24)
+#define ZY_AC97_GCR_CLKBPB_MSK       (1u << 31)
+#define ZY_AC97_GCR_FRCRST_MSK       (1u << 30)
+// Global Status Register bit mask constants
+
+#define ZY_AC97_GSR_GSCI_MSK       (1u << 0 )
+#define ZY_AC97_GSR_MIINT_MSK      (1u << 1 )
+#define ZY_AC97_GSR_MOINT_MSK      (1u << 2 )
+#define ZY_AC97_GSR_ACOFFD_MSK     (1u << 3 )
+#define ZY_AC97_GSR_PIINT_MSK      (1u << 5 )
+#define ZY_AC97_GSR_POINT_MSK      (1u << 6 )
+#define ZY_AC97_GSR_MINT_MSK       (1u << 7 )
+#define ZY_AC97_GSR_PCRDY_MSK      (1u << 8 )
+#define ZY_AC97_GSR_SCRDY_MSK      (1u << 9 )
+#define ZY_AC97_GSR_PCRSM_MSK      (1u << 10)
+#define ZY_AC97_GSR_SCRSM_MSK      (1u << 11)
+#define ZY_AC97_GSR_SLT12_BITS_MSK (7u << 12)
+#define ZY_AC97_GSR_RCS_ERR_MSK    (1u << 15)
+#define ZY_AC97_GSR_SDONE_MSK      (1u << 18)
+#define ZY_AC97_GSR_CDONE_MSK      (1u << 19)
+
+
+// Bit mask and values for CAIP bit in car register.
+#define ZY_AC97_CAR_CAIP_MSK       (0x1<<0)
+#define ZY_AC97_CAR_CAIP_LOCKED    (0x1<<0)
+#define ZY_AC97_CAR_CAIP_CLEAR     (0<<0)
+
+/* Constants for FIFO status reporting and control */
+
+// One bit location is used to report FIFO error conditions and clear
+//  interrupts on those conditions in the various non-global status registers.
+
+// ZY_AC97_FIFOSTAT_FIFOE is used in:
+                                                // posr
+                                                // pisr
+                                                // mcsr
+                                                // mosr
+                                                // misr
+
+#define ZY_AC97_FIFOSTAT_FIFOE  (1u << 4)
+#define ZY_AC97_FIFOSTAT_EOC	  (1u << 3)
+#define ZY_AC97_FIFOSTAT_FSR	  (1u << 2)
+
+// A different bit location is used to enable or disable interrupts based on
+//  FIFO error conditions in the various non-global control registers.
+
+// ZY_AC97_FIFOCTRL_FEIE is used in:
+                                                // pocr
+                                                // picr
+                                                // mccr
+                                                // mocr
+                                                // micr
+
+#define ZY_AC97_FIFOCTRL_FEIE  (1u << 3)
+#define ZY_AC97_FIFOCTRL_FSRIE (1u << 1)
+
+/*
+*******************************************************************************
+    AC'97 Codec Registers Location and Bit Definition
+*******************************************************************************
+*/
+
+/* */
+
+    // Includes symbolic values for certain proprietary register asssignments
+    //   in AC'97 devices that might be used with ZY_AC97.
+
+    // Valid for subset of R 2.1 specification.
+    // Leading "e" in comment means it is an "expanded" register definition as
+    //  found in one or more of the Appendices A-D of the R 2.1 specification.
+    //  Appendix identifier will immediately follow the "e", such as "eA"
+    // R/O indicates read-only
+    // Registers not supported by the assumed controller will be commented out.
+
+#define    ZY_AC97_CR_RESET_ID             0x00  // RESET CODEC TO DEFAULT, get ID info
+#define    ZY_AC97_CR_MASTER_VOLUME        0x02  // LINE OUT VOLUME
+#define    ZY_AC97_CR_HEADPHONE_VOLUME     0x04  //
+#define    ZY_AC97_CR_MASTER_VOLUME_MONO   0x06  //
+#define    ZY_AC97_CR_MASTER_TONE_R_L      0x08  //
+#define    ZY_AC97_CR_PC_BEEP_VOLUME       0x0A  //
+#define    ZY_AC97_CR_PHONE_VOLUME         0x0C  //
+#define    ZY_AC97_CR_MIC_VOLUME           0x0E  //   micrOPHONE VOLUME/ AGC
+#define    ZY_AC97_CR_LINE_IN_VOLUME       0x10  //   LINE IN VOLUME
+#define    ZY_AC97_CR_CD_VOLUME            0x12  //
+#define    ZY_AC97_CR_VIDEO_VOLUME         0x14  //
+#define    ZY_AC97_CR_AUX_VOLUME           0x16  //
+#define    ZY_AC97_CR_PCM_OUT_VOLUME       0x18  //
+#define    ZY_AC97_CR_RECORD_SELECT        0x1A  //   SELECT LINE IN OR micrOPHONE
+#define    ZY_AC97_CR_RECORD_GAIN          0x1C  //
+#define    ZY_AC97_CR_RECORD_GAIN_MIC      0x1E  //
+#define    ZY_AC97_CR_GENERAL_PURPOSE      0x20  //
+#define    ZY_AC97_CR_CONTROL_3D           0x22  //
+#define    ZY_AC97_CR_POWERDOWN_CTRL_STAT  0x26  //   POWER MANAGEMENT
+#define    ZY_AC97_CR_E_AUDIO_ID           0x28  // eA Extended audio sprt info, R/O
+#define    ZY_AC97_CR_E_AUDIO_CTRL_STAT    0x2A  // eA Extended audio stat + control
+
+//
+// Audio Sample Rate Control Registers, 0x2C - 0x34
+//
+                                           // eA PCM Front DAC rate control
+#define    ZY_AC97_CR_E_ASR_PCM_FRNT_DAC_RT 0x2C  //  (output slots 3, 4, 6)
+#define    ZY_AC97_CR_E_ASR_PCM_LR_ADC_RT   0x32  // eA PCM L+R ADC rate control (3+4)
+#define    ZY_AC97_CR_E_ASR_MIC_ADC_RT      0x34  // eA PCM Mic ADC rate control (5)
+
+
+#define    ZY_AC97_CR_E_MDM_GPIO_PIN_STAT     0x54
+//
+// 5Ah-7Ah: Vendor Reserved
+//
+//
+// 7Ch-7Eh: Vendor ID registers.  Optional but standardized for Plug'n'Play
+//
+#define    ZY_AC97_CR_VENDOR_ID1         0x7C
+#define    ZY_AC97_CR_VENDOR_ID2         0x7E
+
+#define    ZY_AC97_CR_MAX               ZY_AC97_CR_VENDOR_ID2
+
+#define    ZY_AC97_CR_END_OF_LIST       (ZY_AC97_CR_MAX +  2)
+
+
+
+/* Other Constants */
+
+// For accessing the Codec mixer registers, each increment of one 32-bit word
+//  in processor space increments the addressed mixer register by two.
+// This does not cause any ambiguities because only even mixer register
+//  addresses are currently supported (AC '97 spec, R 2.2)
+#define ZY_AC97_CODEC_REGS_PER_WORD   	2
+
+/* Default timeout and holdtime settings */
+
+// timeout in reading and writing codec registers through AC link
+#define ZY_AC97_RW_TIMEOUT_DEF		200	//unit is us
+
+// timeout in waiting for codec's ready signal during setup process
+#define ZY_AC97_SETUP_TIMEOUT_DEF		500	//unit is us
+
+// timeout in waiting for locking the link successfully
+#define ZY_AC97_LOCK_TIMEOUT_DEF   		300	//unit is us
+
+// timeout in shutting down the link
+#define ZY_AC97_LINKOFF_TIMEOUT_DEF   	500	//unit is us
+
+// holdtime for keeping nReset signal active(low) in AC link
+#define ZY_AC97_COLD_HOLDTIME			100	//unit is us
+
+/*
+*******************************************************************************
+  ZY AC97 data structure used in function interface
+*******************************************************************************
+*/
+
+typedef struct
+{
+    unsigned long pocr;           // PCM Out Control Register
+    unsigned long picr;           // PCM In Control Register
+    unsigned long mccr;           // Mic In Control Register
+    unsigned long gcr;            // Global Control Register
+    unsigned long pcscr;          // PCM Surround Out Control
+    unsigned long pcclcr;         // PCM Center/LFE Out Control
+    unsigned long mocr;           // MODEM Out Control Register
+    unsigned long micr;           // MODEM In Control Register
+}zy_ac97_save_context_t;
+
+
+#define AC97_SAVE_CONTEXT_SIZE (sizeof(zy_ac97_save_context_t))
+
+static int zy_ac97_acodec_link_lock(p_zy_ac97acodec_t p_ac97_reg)
+{
+	int		status = 1;
+	volatile unsigned long	car_tmp;
+
+	car_tmp = p_ac97_reg->car;
+	if (car_tmp & ZY_AC97_CAR_CAIP_MSK)	/*  "1" in CAIP bit means lock failed. */
+	{
+		status = 0;
+	}
+	return (status);
+}
+
+
+zy_acodec_error_t zy_ac97_acodec_write (zy_acocec_context_t *p_dev_context, unsigned short offset, unsigned short data)
+{
+	zy_acodec_error_t	status = ZY_ACODEC_SUCCESS;
+	int			got_link;
+	unsigned long		time_remaining;
+	volatile unsigned long *	p_codec_reg;
+	p_zy_ac97acodec_t p_ac97_reg = (p_zy_ac97acodec_t)(p_dev_context->p_ctrl_reg);
+	unsigned long max_rw_time_out_us = (p_dev_context->u_max_read_write_time_out_ms) * 1000;
+
+
+	if(offset == ZY_AC97_CR_E_MDM_GPIO_PIN_STAT)
+	{/* it is a special register and sent out on slot 12 */
+		p_codec_reg = &(p_ac97_reg->codec_regs_primary_mdm[0]);
+		p_codec_reg += offset / ZY_AC97_CODEC_REGS_PER_WORD;
+		/*  The data will be sent out on slot 12. */
+		*p_codec_reg = (unsigned long)data;
+		goto done;
+	}
+
+	/*  Point to specified register within area mapped to target codec regs */
+	p_codec_reg = &(p_ac97_reg->codec_regs_primary_aud[0]);
+	p_codec_reg += offset / ZY_AC97_CODEC_REGS_PER_WORD;
+
+
+	/* Lock the ACLINK */
+	time_remaining = ZY_AC97_LOCK_TIMEOUT_DEF;
+	do
+	{
+		got_link = zy_ac97_acodec_link_lock(p_ac97_reg);
+		if (0 == got_link)	/*  1 usec is a long time.  Skip delay if possible. */
+		{
+			udelay(1);
+		}
+	}		/*  Wait while time remaining and ACLINK not available */
+	while (time_remaining-- && (0 == got_link));
+
+	if (0 == got_link)	/*  Didn't get the ACLINK */
+	{
+		status = ZY_ACODEC_CONTROLLER_INTERFACE_TIMEOUT;
+		printk(KERN_ERR "AC97 Write Link Timeout\n");
+	}
+	else	/*  We got the link. Perform the write operation and don't wait. */
+	{
+		/*  First, clear old write status indication CDONE by writing a ONE to that bit. */
+		p_ac97_reg->gsr = ZY_AC97_GSR_CDONE_MSK;
+
+		*p_codec_reg = (unsigned long)data;	   /*  Now the write! */
+
+		/* Wait until write cycle is complete. There should be a way
+		 * to do this speculatively at the beginning of the procedure.
+		 * Need to discover it. Too inefficient to always wait.
+		 */
+
+		time_remaining = max_rw_time_out_us;
+		do
+		{
+			udelay(1);
+		}	 /*  Wait while time remaining and command I/O still incomplete. */
+		while ( (time_remaining--) && !(p_ac97_reg->gsr & ZY_AC97_GSR_CDONE_MSK));
+		if (!(p_ac97_reg->gsr & ZY_AC97_GSR_CDONE_MSK))
+		{
+			status = ZY_ACODEC_CONTROLLER_INTERFACE_TIMEOUT;
+			p_ac97_reg->car = ZY_AC97_CAR_CAIP_CLEAR;
+		}
+	}  /*  Got AC link */
+
+done:
+	return(status);
+} /*  Ac97CtrlCodecWrite() */
+
+#define CKENA		__REG(0x4134000C)	/* A Clock Enable Register */
+#define CKENB		__REG(0x41340010)
+
+zy_acodec_error_t zy_ac97_acodec_read  (zy_acocec_context_t *p_dev_context, unsigned short offset,  unsigned short *pdata)
+{
+	zy_acodec_error_t	status = ZY_ACODEC_SUCCESS;
+	int			got_link;
+	unsigned long		time_remaining;
+	volatile unsigned long *	p_codec_reg;
+	p_zy_ac97acodec_t p_ac97_reg = (p_zy_ac97acodec_t)(p_dev_context->p_ctrl_reg);
+	unsigned long max_rw_time_out_us = (p_dev_context->u_max_read_write_time_out_ms) * 1000;
+
+	/*  Point to specified register within area mapped to target codec regs */
+	p_codec_reg = &(p_ac97_reg->codec_regs_primary_aud[0]);
+	p_codec_reg += offset / ZY_AC97_CODEC_REGS_PER_WORD;
+
+	/* Lock the ACLINK */
+	time_remaining = ZY_AC97_LOCK_TIMEOUT_DEF;
+	do
+	{
+		got_link = zy_ac97_acodec_link_lock(p_ac97_reg);
+		if (0 == got_link)	/*  1 usec is a long time.  Skip delay if possible. */
+		{
+			udelay(1);
+		}
+	}		/*  Wait while time remaining and ACLINK not available */
+	while (time_remaining-- && (0 == got_link));
+
+	if (0 == got_link)	/*  Didn't get the ACLINK */
+	{
+		status = ZY_ACODEC_CONTROLLER_INTERFACE_TIMEOUT;
+		printk(KERN_ERR "AC97 Read Link Timeout\n");
+	}
+	else	/*  We got the link. Perform the write operation and don't wait. */
+	{
+		 /*  First, clear old read status indications. */
+		p_ac97_reg->gsr = ZY_AC97_GSR_SDONE_MSK | ZY_AC97_GSR_RCS_ERR_MSK;
+
+		*pdata = (unsigned short)(*p_codec_reg); /*  This is THE DUMMY READ. */
+
+		 /*  Wait for read I/O with codec to complete before doing real read. */
+		time_remaining = max_rw_time_out_us;
+		do
+		{
+			udelay(1);
+		}   /*  Wait while time remaining and read I/O still incomplete */
+		while( (time_remaining--) && (!(p_ac97_reg->gsr & ZY_AC97_GSR_SDONE_MSK)) );
+
+		if ((p_ac97_reg->gsr & ZY_AC97_GSR_SDONE_MSK) && (!(p_ac97_reg->gsr & ZY_AC97_GSR_RCS_ERR_MSK)) )
+		{
+			if (p_ac97_reg->gsr & ZY_AC97_GSR_RCS_ERR_MSK)
+			{/* timeout indicated by RCS bit */
+				status = ZY_ACODEC_CONTROLLER_INTERFACE_TIMEOUT;
+			}
+			/*  succeed in reading. clear status bits first. */
+			p_ac97_reg->gsr = ZY_AC97_GSR_SDONE_MSK | ZY_AC97_GSR_RCS_ERR_MSK;
+			*pdata = (unsigned short)(*p_codec_reg);	/*  THE REAL READ. */
+			if (*pdata == 0xffff)
+			{/* timeout indicated by returned value */
+				status = ZY_ACODEC_CONTROLLER_INTERFACE_TIMEOUT;
+			}
+			/* check later: is second waiting really needed? */
+	 		time_remaining = max_rw_time_out_us;
+			do
+			{
+				udelay(1);
+  			}   /*  Wait while time remaining and read I/O still incomplete */
+			while( (time_remaining--) && (!(p_ac97_reg->gsr & ZY_AC97_GSR_SDONE_MSK)) );
+			//printk(KERN_ERR "AC97 Read Result %d\n", (p_ac97_reg->gsr & ZY_AC97_GSR_SDONE_MSK) );
+		}
+		else	/*  failed */
+		{
+			status = ZY_ACODEC_CONTROLLER_INTERFACE_TIMEOUT;
+			p_ac97_reg->car = ZY_AC97_CAR_CAIP_CLEAR;
+			//printk(KERN_ERR "AC97 Read Link Timeout2 %x %x %x\n", CKENA, OSCC, CKENB);
+		} /*  else  (OK to do real read) */
+
+	} /*  else  (We got the link.  Perform the read operations.) */
+
+	return (status);
+}
+
+
+
+zy_acodec_error_t zy_acodec_get_adc_sample(zy_acocec_context_t *p_device_context, unsigned short *p_sample_data, unsigned short adc_type, int *p_pen_down)
+{
+	zy_acodec_error_t	status = ZY_ACODEC_SUCCESS;
+	unsigned short value;
+	unsigned long wait;
+
+	if (adc_type == ZY_TOUCH_SAMPLE_X)
+	{
+		value = 0x202;
+	}
+	else
+	{/* Y sample */
+		value = 0x204;
+	}
+
+	status = zy_ac97_acodec_write(p_device_context, DIGITIZER_1_WM13, value);
+
+	wait = 0;
+	do
+	{
+		status = zy_ac97_acodec_read(p_device_context, DIGITIZER_1_WM13, &value);
+		if ( !(value & 0x200 ) )
+		{
+			break;
+		}
+	}while ( 100 > wait++ );
+
+	status = zy_ac97_acodec_read(p_device_context, DIGITIZER_READ_BACK, &value);
+	if (value & 0x8000)
+	{/* means pen down */
+		*p_pen_down = 1;
+	}
+	else
+	{
+		*p_pen_down = 0;
+	}
+	*p_sample_data = value & 0xfff;
+
+	return status;
+}
+
+
+
+/*
+ * add a touch event
+ */
+static int codec_zy_ts_evt_add(codec_zy_ts_t* ts, u16 pressure, u16 x, u16 y)
+{
+        /* add event and remove adc src bits */
+        static u16 pre_press = 0;
+
+        input_report_abs(ts->idev, ABS_X, x & 0xfff);
+        input_report_abs(ts->idev, ABS_Y, y & 0xfff);
+        if (pressure == pre_press){
+                pressure--;
+        }
+        pre_press = pressure;
+        input_report_abs(ts->idev, ABS_PRESSURE, pressure & 0xfff);
+	input_sync(ts->idev);
+#ifdef CONFIG_IPM
+	ipm_event_notify(IPM_EVENT_UI, IPM_EVENT_DEVICE_TSI, NULL, 0);
+#endif
+        return 0;
+}
+
+/*
+ * add a pen up event
+ */
+static void codec_zy_ts_evt_release(codec_zy_ts_t* ts)
+{
+	input_report_abs(ts->idev, ABS_PRESSURE, 0);
+	input_sync(ts->idev);
+
+#ifdef CONFIG_IPM
+	ipm_event_notify(IPM_EVENT_UI, IPM_EVENT_DEVICE_TSI, NULL, 0);
+#endif
+	p_zy_codec_ctxt->g_pfn_event_ack(p_zy_codec_ctxt,ZY_EVENT_TYPE_PDN);
+}
+
+/*
+ * Kill the touchscreen thread and stop
+ * the touch digitiser.
+ */
+static void codec_zy_ts_input_close(struct input_dev *idev)
+{
+	codec_zy_ts_t *ts = (codec_zy_ts_t *) &codec_zy_ts;
+
+#ifdef CONFIG_PM
+	if(touch_suspend){
+		pr_info("touch is suspended!\n");
+		return -1;
+	}
+#endif
+	dbg("close ts input!\n");
+	if (--ts->use_count == 0) {
+		del_timer(ts->timer);
+		if (ts->timer != NULL)
+			kfree(ts->timer);
+		p_zy_codec_ctxt->g_pfn_disable_touch(p_zy_codec_ctxt);
+	}
+}
+
+/*
+ * Sample the touchscreen
+ */
+int ac97_poll_touch(codec_zy_ts_t *ts)
+{
+	unsigned short x=0, y=0;
+	int if_down= 0;
+	zy_acodec_error_t status = ZY_ACODEC_SUCCESS;
+
+#ifdef DEBUG
+        start_time = OSCR;
+#endif
+
+	/* get x value */
+	status = zy_acodec_get_adc_sample(p_zy_codec_ctxt, &x, ZY_TOUCH_SAMPLE_X, &if_down);
+	if (ZY_ACODEC_SUCCESS != status ){
+		return -EIO;
+	}
+	dbg("x:0x%x\n", x);
+
+	/* the pen is up */
+	if (1 != if_down){
+		return PEN_UP;
+	}
+
+	/* get y vaule */
+	status = zy_acodec_get_adc_sample(p_zy_codec_ctxt, &y, ZY_TOUCH_SAMPLE_Y, &if_down);
+	if (ZY_ACODEC_SUCCESS != status ){
+		return -EIO;
+	}
+	dbg("y:0x%x\n",y);
+
+	/* the pen is up */
+	if (1 != if_down){
+		return PEN_UP;
+	}
+
+	/* the pen is down, can not get the pressure value,
+	 * so if pen is down, give the max pressure value
+	 */
+	codec_zy_ts_evt_add(ts,0xfff, x, y);
+
+#ifdef DEBUG
+        end_time = OSCR;
+        PRINT_TIME();
+#endif
+
+	return PEN_DOWN;
+}
+
+static void touch_timer_handler(unsigned long unused)
+{
+	int event;
+	codec_zy_ts_t *ts = &codec_zy_ts;
+
+	event = ac97_poll_touch(ts);
+
+	if (event == PEN_DOWN) {
+		dbg("pen down!\n");
+		ts->timer->expires = jiffies + TS_SAMPLE_INTERVAL;
+		add_timer(ts->timer);
+	} else if(event == PEN_UP) {
+		dbg("pen up!\n");
+		codec_zy_ts_evt_release(ts);
+	} else if(event == -EIO) {
+		printk(KERN_ERR "Access touch interface error!\n");
+	}
+	return;
+}
+
+static zy_acodec_error_t  zy_ac97_acodec_cold_reset(zy_acocec_context_t * p_ac97_ctxt)
+{
+	zy_acodec_error_t	status = ZY_ACODEC_SUCCESS;
+	p_zy_ac97acodec_t p_ac97 = (p_zy_ac97acodec_t)(p_ac97_ctxt->p_ctrl_reg);
+	int		 pri_codec_ready;
+	unsigned long		time_remaining;
+
+	p_ac97->gcr = 0;
+	p_ac97->gcr |= ZY_AC97_GCR_CLKBPB_MSK;
+	/*  Hold reset active for a minimum time */
+	udelay(ZY_AC97_COLD_HOLDTIME);
+	p_ac97->gcr &= ~ZY_AC97_GCR_CLKBPB_MSK;
+
+	/*  Deactivate cold reset condition */
+	p_ac97->gcr |= (ZY_AC97_GCR_COLD_RESET_MSK | ZY_AC97_GCR_WARM_RESET_MSK);
+
+
+	pri_codec_ready = 0;
+	time_remaining = (p_ac97_ctxt->u_max_setup_time_out_ms) * 10;
+	do
+	{
+		udelay(1);
+		if (p_ac97->gsr & ZY_AC97_GSR_PCRDY_MSK)
+			pri_codec_ready = 1;
+	}
+	while (time_remaining-- && (pri_codec_ready == 0));
+
+	/*  Timeout status if some of the devices weren't ready. */
+	if (pri_codec_ready == 0)
+	{
+		status = ZY_ACODEC_CONTROLLER_INTERFACE_TIMEOUT;
+	}
+
+	return (status);
+}
+
+
+zy_acodec_error_t  zy_ac97_acodec_init(zy_acocec_context_t *p_ac97_ctxt)
+{
+	zy_acodec_error_t	status ;
+
+	status = zy_ac97_acodec_cold_reset(p_ac97_ctxt);
+
+	return (status);
+}
+
+
+/*
+ * Start the touchscreen thread and
+ * the touch digitiser.
+ */
+static int codec_zy_ts_input_open(struct input_dev *idev)
+{
+	codec_zy_ts_t *ts = (codec_zy_ts_t *) &codec_zy_ts;
+
+#ifdef CONFIG_PM
+	if(touch_suspend){
+		pr_info("touch is suspended!\n");
+		return -1;
+	}
+#endif
+
+	if (ts->use_count++ > 0)
+		return 0;
+
+	dbg("Touch is opened. Use count: %d\n", ts->use_count);
+	ts->idev = idev;
+	ts->timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
+	if (!ts->timer) {
+		printk(KERN_ERR "Alloc memory error for timer!\n");
+		return -ENOMEM;
+	}
+
+	init_timer(ts->timer);
+	ts->timer->function = touch_timer_handler;
+	ts->timer->data = 0;
+	p_zy_codec_ctxt->g_pfn_enable_touch(p_zy_codec_ctxt);
+
+	return 0;
+}
+
+/*
+ * initilze the pxa touch screen
+ */
+static int alsa_ts_init( void )
+{
+	codec_zy_ts_t* ts = &codec_zy_ts;
+
+	memset(ts, 0, sizeof(codec_zy_ts_t));
+
+	codec_zy_ts_input = input_allocate_device();
+	if (!codec_zy_ts_input)
+		return -ENOMEM;
+
+
+	/* tell input system what we events we accept and register */
+	codec_zy_ts_input->name = "codec zy touchscreen";
+	codec_zy_ts_input->open = codec_zy_ts_input_open;
+	codec_zy_ts_input->close = codec_zy_ts_input_close;
+	__set_bit(EV_ABS, codec_zy_ts_input->evbit);
+	__set_bit(ABS_X, codec_zy_ts_input->absbit);
+	__set_bit(ABS_Y, codec_zy_ts_input->absbit);
+	__set_bit(ABS_PRESSURE, codec_zy_ts_input->absbit);
+	input_register_device(codec_zy_ts_input);
+
+	return 0;
+}
+
+static irqreturn_t pxa_touch_irq(int irq, void *dev)
+{
+	unsigned char event_type;
+
+	//printk(KERN_ERR "%s: enter codec event handler\n", __FUNCTION__);
+
+	dbg("%s: enter codec event handler\n", __FUNCTION__);
+	p_zy_codec_ctxt->g_pfn_get_event(p_zy_codec_ctxt, &event_type);
+	switch (event_type) {
+		case ZY_EVENT_TYPE_PDN:
+		{
+			codec_zy_ts_t *ts = &codec_zy_ts;
+			/*if the touch is not open need not acknowledge the event*/
+			if (ts->use_count <= 0)
+				break;
+			ts->timer->expires = jiffies + TS_SAMPLE_INTERVAL;
+			add_timer(ts->timer);
+			break;
+		}
+		default:
+			printk("unsupported codec event:0x%x\n", event_type);
+	}
+
+	return IRQ_HANDLED;
+}
+
+
+
+
+
+
+
+
+
+static mfp_cfg_t extra_cfg[] = {
+	MFP_CFG_X(GPIO17, AF3, DS03X, PULL_LOW),
+	MFP_CFG_X(GPIO25, AF0, DS01X, PULL_LOW),
+};
+
+#define ARRAY_AND_SIZE(x)	(x), ARRAY_SIZE(x)
+
+extern void dump_mfp(void);
+
+zy_acodec_error_t	zy_ac97_acodec_mfp_init(zy_acocec_context_t *p_device_context)
+{
+	unsigned short codec_id;
+
+	//mhn_mfp_set_afds(MFP_RSVD_AC97_SDATA_IN_0, MFP_AF0, MFP_DS03X);
+	//enable_ac97_pins();
+	zy_ac97_acodec_init(p_device_context);
+    	if (zy_ac97_acodec_read(p_device_context, 0x0, &codec_id)){
+
+		/*
+		 * there is a bug on MonahansL/MonhansPL PC card: AC97_SDATA_IN is not connected to CODEC
+		 * ECO 72: Connect PWM_0(MFP_RSVD_AC97_SDATA_IN_0) to CODEC as AC97_SDATA_IN
+		 */
+
+		//mhn_mfp_set_afds(MFP_RSVD_AC97_SDATA_IN_0, MFP_RSVD_AC97_SDATA_IN_0_AF, MFP_DS03X);
+		//mhn_mfp_set_afds(MFP_AC97_SDATA_IN_0, MFP_AF0, MFP_DS01X);
+
+		gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO17), 0);
+		pxa3xx_mfp_config(ARRAY_AND_SIZE(extra_cfg));
+		gpio_direction_input(mfp_to_gpio(MFP_PIN_GPIO25));
+	}
+
+
+	return ZY_ACODEC_SUCCESS;
+}
+
+#define ZY_AC97_WM9713_GPIO_PIN_PDN ( 0x1 << 13 )  /* Pen down */
+
+/*power enable bit in 3ch and 3eh */
+/*3ch */
+#define ZY_AC97_9713_PWR_PADCPD   ( 0x1 << 15 )
+#define ZY_AC97_9713_PWR_VMID     ( 0x1 << 14 )
+#define ZY_AC97_9713_PWR_TSHUT    ( 0x1 << 13 )
+#define ZY_AC97_9713_PWR_VXDAC    ( 0x1 << 12 )
+#define ZY_AC97_9713_PWR_AUXDAC   ( 0x1 << 11 )
+#define ZY_AC97_9713_PWR_MBIAS    ( 0x1 << 10 )
+#define ZY_AC97_9713_PWR_PLL      ( 0x1 << 9 )
+#define ZY_AC97_9713_PWR_DACL     ( 0x1 << 7 )
+#define ZY_AC97_9713_PWR_DACR     ( 0x1 << 6 )
+#define ZY_AC97_9713_PWR_ADCL     ( 0x1 << 5 )
+#define ZY_AC97_9713_PWR_ADCR     ( 0x1 << 4 )
+#define ZY_AC97_9713_PWR_HPLX     ( 0x1 << 3 )
+#define ZY_AC97_9713_PWR_HPRX     ( 0x1 << 2 )
+#define ZY_AC97_9713_PWR_SPKX     ( 0x1 << 1 )
+#define ZY_AC97_9713_PWR_MX       ( 0x1 << 0 )
+
+/*3EH */
+#define ZY_AC97_9713_PWR_MCD      ( 0x1 << 15 )
+#define ZY_AC97_9713_PWR_MICBIAS  ( 0x1 << 14 )
+#define ZY_AC97_9713_PWR_MONO     ( 0x1 << 13 )
+#define ZY_AC97_9713_PWR_OUT4     ( 0x1 << 12 )
+#define ZY_AC97_9713_PWR_OUT3     ( 0x1 << 11 )
+#define ZY_AC97_9713_PWR_HPL      ( 0x1 << 10 )
+#define ZY_AC97_9713_PWR_HPR      ( 0x1 << 9 )
+#define ZY_AC97_9713_PWR_SPKL     ( 0x1 << 8 )
+#define ZY_AC97_9713_PWR_SPKR     ( 0x1 << 7 )
+#define ZY_AC97_9713_PWR_LL       ( 0x1 << 6 )
+#define ZY_AC97_9713_PWR_LR       ( 0x1 << 5 )
+#define ZY_AC97_9713_PWR_MOIN     ( 0x1 << 4 )
+#define ZY_AC97_9713_PWR_MA       ( 0x1 << 3 )
+#define ZY_AC97_9713_PWR_MB       ( 0x1 << 2 )
+#define ZY_AC97_9713_PWR_MPA      ( 0x1 << 1 )
+#define ZY_AC97_9713_PWR_MPB      ( 0x1 << 0 )
+
+
+void zy_wm9713_get_event(zy_acocec_context_t *p_device_context, unsigned char * event_type)
+{
+	unsigned short event_state = 0;
+	zy_ac97_acodec_read(p_device_context, GPIO_PIN_STATUS, &event_state);
+	if(event_state & ZY_AC97_WM9713_GPIO_PIN_PDN){
+		*event_type = ZY_EVENT_TYPE_PDN;
+		return;
+	}
+	return;
+}
+
+void zy_wm9713_event_ack(zy_acocec_context_t *p_device_context, unsigned char event_type)
+{
+	unsigned short event_state = 0;
+	zy_ac97_acodec_read(p_device_context, GPIO_PIN_STATUS, &event_state);
+	if( event_type == ZY_EVENT_TYPE_PDN){
+		zy_ac97_acodec_write(p_device_context,
+					GPIO_PIN_STATUS,
+					(event_state & (~ZY_AC97_WM9713_GPIO_PIN_PDN)));
+	}
+
+	zy_ac97_acodec_read(p_device_context, GPIO_PIN_STATUS, &event_state);
+	return;
+}
+
+static void * p_saved_memory = NULL;
+static void * p_zy_scenario = NULL;
+static p_zy_acocec_context_t p_zy_ctxt = NULL;
+
+#define WM9713_SAVE_REGISTER_NO (64-11)
+typedef struct {
+    unsigned short wm9713RegisterContext [WM9713_SAVE_REGISTER_NO + 1]; /* Fixed (data misalignment error) */
+}ZY_9713_CONTEXT_SAVE_T;
+
+
+/**
+ * alsa_prepare_for_zy - create and initialize the p_zy_acocec_context_t
+ * 				   open the clock of data link
+ * @p_p_zy_ctxt: return the data structure p_zy_acocec_context_t
+ * return: 0 success ; -ENOMEM
+ **/
+int alsa_prepare_for_zy(p_zy_acocec_context_t * p_p_zy_ctxt)
+{
+	if (p_zy_ctxt) {
+		p_zy_ctxt->use_count++;
+		*p_p_zy_ctxt = p_zy_ctxt;
+		return 0;
+	}
+
+	p_zy_ctxt = kzalloc(sizeof(zy_acocec_context_t), GFP_KERNEL);
+	if (!p_zy_ctxt)
+		return -ENOMEM;
+
+	/* enable CLK_POUT as CODEC clock input */
+	OSCC |= 0x800;
+
+	p_saved_memory = kzalloc(sizeof(ZY_9713_CONTEXT_SAVE_T) +
+				sizeof(zy_ac97_save_context_t), GFP_KERNEL);
+	if (NULL == p_saved_memory) {
+		if (p_zy_ctxt)
+			kfree(p_zy_ctxt);
+		return -ENOMEM;
+	}
+
+	p_zy_ctxt->acodec_id = (zy_acodec_device_id_t) (WM_9713_ID);
+	p_zy_ctxt->use_count++;
+	/*
+	p_zy_ctxt->pMfpRegBase = (unsigned long) (MFP_BASE);
+	p_zy_ctxt->pMfpRmDb = ZY_MFP_RM_DATABASE;
+	p_zy_ctxt->p_ost_regs = OST_BASE;
+	*/
+	p_zy_ctxt->p_voice_reg = NULL;
+	p_zy_ctxt->p_hifi_reg = (void *) (&POCR);
+	p_zy_ctxt->p_ctrl_reg = (void *) (&POCR);
+	p_zy_ctxt->u_max_read_write_time_out_ms = ZY_AC97_RW_TIMEOUT_DEF;
+	p_zy_ctxt->u_max_setup_time_out_ms = ZY_AC97_SETUP_TIMEOUT_DEF;
+	p_zy_ctxt->p_save_memory = p_saved_memory;
+	p_zy_ctxt->p_zy_scenario = p_zy_scenario;
+//	pxa_set_cken(24, 1);
+	CKENA |= (1 << 24);
+	AC97_DIV = 1625<<12 | 128;
+#ifdef DEBUG_ALSA_ZY
+	debug_pac97ctxt = p_zy_ctxt;
+	misc_register(&audio_dev);
+#endif
+
+	(*p_p_zy_ctxt) = p_zy_ctxt;
+
+	return 0;
+}
+
+
+/* this is platform specific */
+/* do later: not to enable recording route and playback route in this function,
+ * leave it to driver to call other function
+ */
+zy_acodec_error_t zy_wm9713_specific_init (zy_acocec_context_t *p_device_context)
+{
+
+	unsigned short value;
+
+	/* this assumes that the aclink is initialized wait some time and then
+	 * do a warm reset to enabled the ACLINK, required for wm9713
+	 * (not wm9712 or ucb1400)
+	 */
+
+	/* pay attention: whether the workaround is still needed? */
+	p_zy_ac97acodec_t p_ac97_reg = (p_zy_ac97acodec_t)(p_device_context->p_ctrl_reg);
+
+	p_ac97_reg->gcr |= ZY_AC97_GCR_WARM_RESET_MSK;
+
+	mdelay(5);
+
+	/* power on all the necessary unit */
+	zy_ac97_acodec_write(p_device_context,POWERDOWN_CTRL_STAT, 0x000);	/*26*/
+	/* open left headphone mixer */
+	/* open right headphone mixer */
+	/* open right/left dac */
+	/* open right/left adc */
+	/* open temperature sensor */
+	/* enable reference generator */
+	zy_ac97_acodec_write(p_device_context,POWER_DOWN_1, 0xda00);		/*3c */
+	/* open microphone bias */
+	/* open HPL output PGA */
+	/* open HPR output PGA */
+	/* open mic PGA MA */
+	/* open mic pre-amp MPA */
+	/* if here we enable SPKL and SPKR PGA, then Touch screen will doesn't work */
+	zy_ac97_acodec_write(p_device_context,POWER_DOWN_2,0xb9f5);   /*3e */
+
+	/* recording route and microphone input */
+	/* microphone selection, now fixed to MIC1 input and mic bias output */
+	/* MIC1 only, MICBIAS enable */
+	zy_ac97_acodec_write (p_device_context, MIC_BIAS, 0xC440);	/*0x22h*/
+
+	/* mic pga setting to mixer (side tone) */
+	/* comment the below code to make MICA/B play back volume gain + 0db */
+	/* zy_ac97_acodec_write (p_device_context, MIC_PGA_VOLUME, 0x0000); */	/*0x0eh*/
+
+	/* recording side tone and ADC boost, now fixed to default (14h) */
+	/* recording volume  0dB */
+	zy_ac97_acodec_write(p_device_context, REC_PGA_VOL, 0x0); /*12*/
+
+	/* hifi playback route and output mixer	 */
+	/* by default, fixed to enable headphone only */
+
+	/* comment the below code to make SPEAKER default MUTE */
+	zy_ac97_acodec_write (p_device_context, SPEAKER_VOLUME, 0x0);		/*02*/
+
+	/* comment the below code to make OUT3_OUT4 default MUTE */
+	/* zy_ac97_acodec_write (p_device_context, OUT3_OUT4_VOLUME, 0x8000); */	/*06*/
+
+	/* remove all  the mute bit  volume gain + 0db  */
+	zy_ac97_acodec_write(p_device_context, HEADPHONE_VOLUME, 0x0);	/*04*/
+
+	/* DAC route */
+	/* open DAC to headphone mixer path */
+	/* left DAC gain +0db */
+	/* right DAC gain +0db */
+	zy_ac97_acodec_write(p_device_context, DAC_PGA_VOL_ROUTE,0x0808);	/*0c*/
+
+	/* out3 configure, invert to HPMIXR */
+	/* zy_ac97_acodec_write(p_device_context,DAC_3D_CTRL_INV_MUX_SEL, 0x8000); */	/*1e*/
+
+	/* output control */
+	 /* select HPMIXR HPMIXL out */
+	 /* other out are all VIM */
+	zy_ac97_acodec_write(p_device_context,OUTPUT_PGA_MUX, 0x9BA8);		/*1c*/
+
+	/* set sample rates */
+	/* enable variable rate conversion */
+	zy_ac97_acodec_write(p_device_context, EXTENDED_AUD_STAT_CTRL , 0x1); /*2a*/
+	/*  DAC 44kHZ */
+	zy_ac97_acodec_write(p_device_context,AUDIO_DAC_RATE,0xac44); /*2c*/
+	/*  ADC 16KHZ */
+	zy_ac97_acodec_write(p_device_context,AUDIO_ADC_RATE,0x3E80); /*32*/
+
+	/* clock scheme, use external clock, it is 24MHZ from MCLK_A */
+
+
+	zy_ac97_acodec_read(p_device_context, MCLK_PLL_CTRL_1, &value);
+	zy_ac97_acodec_write(p_device_context, MCLK_PLL_CTRL_1, value | 0x2);
+
+	return ZY_ACODEC_SUCCESS;
+}
+
+zy_acodec_error_t zy_wm9713_specific_deinit (zy_acocec_context_t *p_device_context)
+{/* do later: shut down all power */
+	unsigned short value = 0;
+
+	/* close the power of all units */
+	zy_ac97_acodec_write(p_device_context, POWER_DOWN_1, 0xffff);
+	zy_ac97_acodec_write(p_device_context, POWER_DOWN_2, 0xffff);
+	zy_ac97_acodec_read(p_device_context, POWER_DOWN_1, &value);
+ 	value &= ~(ZY_AC97_9713_PWR_MBIAS);
+	zy_ac97_acodec_write(p_device_context, POWER_DOWN_1, value);
+
+	return ZY_ACODEC_SUCCESS;
+}
+
+zy_acodec_error_t zy_acodec_set_pen_down_interrupt(zy_acocec_context_t *p_device_context, int enable)
+{/* disable/enable pen down interrupt in the codec. This function is not implemented for Wm9713 */
+	/* because the pen down detection could not be disabled in codec */
+	return ZY_ACODEC_SUCCESS;
+}
+
+zy_acodec_error_t zy_wm9713_enable_touch(zy_acocec_context_t *p_device_context)
+{/* enable touch functionality in the codec */
+	zy_acodec_error_t	status = ZY_ACODEC_SUCCESS;
+	unsigned short value;
+
+	/* power setting */
+	status = zy_ac97_acodec_read(p_device_context, POWER_DOWN_1, &value);
+	value &= ~(ZY_AC97_9713_PWR_PADCPD);
+	status = zy_ac97_acodec_write(p_device_context, POWER_DOWN_1, value);
+
+	/* basic touch setting	 */
+	status = zy_ac97_acodec_write(p_device_context, DIGITIZER_3_WM13, 0xc008);
+	status = zy_ac97_acodec_write(p_device_context, DIGITIZER_2_WM13, 0x6);
+
+
+	/* 9713 powerdown virtual gpio setting (polarity, sticky, wakeup) */
+	/* 9713 gpio 2(pin45) route to IRQ */
+	/*  Notes: Can use defaults for IRQ polarity, PENDOWN polarity in IRQ, */
+	/*   sticky for PENDOWN in IRQ and wakeup for PENDOWN.	 */
+	status = zy_ac97_acodec_read(p_device_context, GPIO_PIN_CFG, &value);
+	value &= ~(0x4);
+	status = zy_ac97_acodec_write(p_device_context, GPIO_PIN_CFG, value);
+
+	status = zy_ac97_acodec_read(p_device_context, GPIO_PIN_SHARING, &value);
+	value &= ~(0x4);
+	status = zy_ac97_acodec_write(p_device_context, GPIO_PIN_SHARING, value);
+
+	status = zy_ac97_acodec_read(p_device_context, GPIO_PIN_WAKEUP, &value);
+	value |= (0x2000);
+	status = zy_ac97_acodec_write(p_device_context, GPIO_PIN_WAKEUP, value);
+
+	status = zy_ac97_acodec_read(p_device_context, GPIO_PIN_STICKY, &value);
+	value |= (0x2000);
+	status = zy_ac97_acodec_write(p_device_context, GPIO_PIN_STICKY, value);
+
+	return status;
+}
+
+zy_acodec_error_t zy_wm9713_disable_touch(zy_acocec_context_t *p_device_context)
+{/* disable touch functionality in the codec */
+	zy_acodec_error_t	status = ZY_ACODEC_SUCCESS;
+	unsigned short value;
+
+	/* power setting */
+	status = zy_ac97_acodec_read(p_device_context, POWER_DOWN_1, &value);
+	value |= (ZY_AC97_9713_PWR_PADCPD);
+	status = zy_ac97_acodec_write(p_device_context, POWER_DOWN_1, value);
+
+	return status;
+}
+zy_acodec_error_t	zy_ac97_acodec_mfp_deinit(zy_acocec_context_t *p_device_context)
+{/* do later: free all MFP resources. */
+    return ZY_ACODEC_SUCCESS;
+}
+
+static zy_acodec_error_t  zy_ac97_acodec_shut_down_aclink(p_zy_ac97acodec_t p_ac97_reg, int * p_ost_regs)
+{
+	zy_acodec_error_t	status = ZY_ACODEC_SUCCESS;
+	unsigned long time_remaining = ZY_AC97_LINKOFF_TIMEOUT_DEF;
+
+	p_ac97_reg->gcr |= ZY_AC97_GCR_LINK_OFF_MSK;
+	p_ac97_reg->gcr |= ZY_AC97_GCR_CLKBPB_MSK;
+
+	while (!(p_ac97_reg->gsr & ZY_AC97_GSR_ACOFFD_MSK))
+	{
+		time_remaining --;
+		if (0 == time_remaining)
+		{
+			status = ZY_ACODEC_CONTROLLER_INTERFACE_TIMEOUT;
+			break;
+		}
+		udelay(1);
+	}
+	p_ac97_reg->gcr |= ZY_AC97_GCR_FRCRST_MSK;
+	/* check later: any delay needed */
+	p_ac97_reg->gcr &= ~ZY_AC97_GCR_FRCRST_MSK;
+	p_ac97_reg->gcr &= ~ZY_AC97_GCR_CLKBPB_MSK;
+
+	return(status);
+}
+
+
+zy_acodec_error_t  zy_ac97_acodec_deinit(zy_acocec_context_t * p_ac97_ctxt)
+{
+	zy_acodec_error_t	status ;
+
+	status = zy_ac97_acodec_shut_down_aclink((p_zy_ac97acodec_t)(p_ac97_ctxt->p_ctrl_reg), p_ac97_ctxt->p_ost_regs);
+
+	return (status);
+}
+
+zy_acodec_error_t zy_acodec_deinit(zy_acocec_context_t *p_device_context)
+{
+	/* power down codec by codec specific power down function */
+	if (p_device_context->g_pfn_codec_specific_dinit)
+	{
+		p_device_context->g_pfn_codec_specific_dinit(p_device_context);
+	}
+	/* call bus deinit function */
+	zy_ac97_acodec_deinit(p_device_context);
+	/* restore MFP, set GPIO to suitable value */
+	zy_ac97_acodec_mfp_deinit(p_device_context);
+
+	return ZY_ACODEC_SUCCESS;
+}
+
+void alsa_zy_codec_put(p_zy_acocec_context_t p_acodectxt)
+{
+
+	zy_acodec_deinit(p_acodectxt);
+	//pxa_set_cken(24, 0);
+	CKENA &= ~(1 << 24);
+
+	if(p_acodectxt->p_save_memory){
+		kfree(p_saved_memory);
+	}
+	if(p_acodectxt->p_zy_scenario){
+		kfree(p_zy_scenario);
+	}
+}
+
+
+zy_acodec_error_t zy_acodec_init(zy_acocec_context_t *p_device_context, int hw_init)
+{
+	/* set codec specific functions
+	 * set mfp for Zylonite platform
+	 * call bus init function (AC97, I2S, I2C, SSP)
+	 * call specific init of codec
+	 */
+	zy_acodec_error_t retval = ZY_ACODEC_SUCCESS;
+
+	if (p_device_context->acodec_id != WM_9713_ID)
+	{/* on Zylonite, it is Wolfson 9713 codec only */
+		return ZY_ACODEC_GENERAL_SW_ERR;
+	}
+
+	if (1 == hw_init)
+	{
+		zy_ac97_acodec_mfp_init(p_device_context);
+		zy_ac97_acodec_init(p_device_context);  /* codec init common to ac97 */
+	}
+
+	/* wm9713-specific functions */
+	(p_device_context->g_pfn_codec_specific_init)	= zy_wm9713_specific_init;
+	(p_device_context->g_pfn_codec_specific_dinit)  = zy_wm9713_specific_deinit;
+	(p_device_context->g_pfn_acodec_read)		= zy_ac97_acodec_read;
+	(p_device_context->g_pfn_acodec_write)		= zy_ac97_acodec_write;
+
+	(p_device_context->g_pfn_event_ack)    = zy_wm9713_event_ack;
+	(p_device_context->g_pfn_get_event)    = zy_wm9713_get_event;
+	(p_device_context->g_pfn_disable_touch)        = zy_wm9713_disable_touch;
+	(p_device_context->g_pfn_enable_touch) = zy_wm9713_enable_touch;
+
+	if (1 == hw_init)
+	{
+		retval = p_device_context->g_pfn_codec_specific_init(p_device_context);
+	}
+
+	return retval;
+}
+
+static int __devinit touch_codec_zy_probe(struct platform_device *dev)
+{
+	int ret = 0;
+	struct snd_card *card = NULL;
+	zy_acodec_error_t status;
+
+	/* will increase codec context use count */
+	ret = alsa_prepare_for_zy(&p_zy_codec_ctxt);
+	if (ret)
+		goto err;
+
+	/* codec specific initialization, audio will do it either */
+	if (1 == p_zy_codec_ctxt->use_count) {
+		status = zy_acodec_init(p_zy_codec_ctxt, 1);
+		if (ZY_ACODEC_SUCCESS != status) {
+			printk(KERN_ERR "initialize codec error\n");
+			ret = -EIO;
+			goto err;
+		}
+
+	/* power down the units of the acodec, sleep the acodec, zy_acodec_init()
+	 * will open all the units' power of the codec while ALSA need all the codec
+	 * units power down and the codec should sleep if it can.
+	 * So on the zylonite platform we call below function to power down and sleep
+	 * wm9713 codec.
+	 */
+	p_zy_codec_ctxt->g_pfn_codec_specific_dinit(p_zy_codec_ctxt);
+
+	}
+
+	alsa_ts_init();
+
+	//mhn_mfp_set_afds(MFP_AC97_INT_N_GPIO,0,0);
+	//mhn_gpio_set_direction(MFP_AC97_INT_N_GPIO, GPIO_DIR_IN);
+	//mhn_gpio_clear_edge_detect_status(MFP_AC97_INT_N_GPIO);
+	gpio_direction_input(mfp_to_gpio(MFP_PIN_GPIO26));
+	ret = request_irq(IRQ_GPIO(mfp_to_gpio(MFP_PIN_GPIO26)),
+			pxa_touch_irq, IRQF_TRIGGER_RISING,
+			"wm9713 touch event interrupt", NULL);
+	if (ret) {
+		printk(KERN_ERR "Request IRQ for touch failed (%d).\n", ret);
+		goto err;
+	}
+
+	return 0;
+err:
+	if (p_zy_codec_ctxt && (!--p_zy_codec_ctxt->use_count)) {
+		zy_acodec_deinit(p_zy_codec_ctxt);
+		//pxa_set_cken(24, 0);
+		CKENA &= ~(1 << 24);
+		kfree(p_zy_codec_ctxt);
+		p_zy_codec_ctxt = NULL;
+	}
+
+	if (card)
+		snd_card_free(card);
+
+	return ret;
+}
+
+static int __devexit touch_codec_zy_remove(struct platform_device *dev)
+{
+	struct snd_card *card = platform_get_drvdata(dev);
+
+	input_unregister_device(codec_zy_ts_input);
+
+	if (p_zy_codec_ctxt && (!--p_zy_codec_ctxt->use_count)) {
+		alsa_zy_codec_put(p_zy_codec_ctxt);
+		kfree(p_zy_codec_ctxt);
+		p_zy_codec_ctxt = NULL;
+	}
+
+	if (card) {
+		snd_card_free(card);
+		platform_set_drvdata(dev, NULL);
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int touch_codec_zy_suspend(struct platform_device *_dev, pm_message_t state, u32 level)
+{
+	int ret=0;
+	
+	if (level == SUSPEND_DISABLE) {
+		ret = audio_codec_zy_do_suspend(NULL, SNDRV_CTL_POWER_D3cold, p_zy_codec_ctxt);
+		touch_suspend = 1;
+	}
+	return ret;
+}
+
+static int touch_codec_zy_resume(struct platform_device *_dev, u32 level)
+{
+	int ret = 0;
+	
+	if (level == RESUME_ENABLE) {
+		ret = audio_codec_zy_do_resume(NULL, SNDRV_CTL_POWER_D0, p_zy_codec_ctxt);
+		touch_suspend = 0;
+	}
+	return ret;
+}
+#else
+#define touch_codec_zy_suspend	NULL
+#define touch_codec_zy_resume	NULL
+#endif
+
+static struct platform_driver touch_codec_zy_driver = {
+	.probe 	= 	touch_codec_zy_probe,
+	.remove = 	__devexit_p(touch_codec_zy_remove),
+	.suspend= 	touch_codec_zy_suspend,
+	.resume = 	touch_codec_zy_resume,
+	.driver = {
+		.name 	= 	"pxa2xx-touch",
+	},
+};
+
+static int __init touch_codec_zy_init(void)
+{
+	return platform_driver_register(&touch_codec_zy_driver);
+}
+
+static void __exit touch_code_zy_exit(void)
+{
+	platform_driver_unregister(&touch_codec_zy_driver);
+}
+module_init(touch_codec_zy_init);
+module_exit(touch_code_zy_exit);
+
+EXPORT_SYMBOL(p_zy_codec_ctxt);
+
+MODULE_AUTHOR("bridge.wu@marvell.com");
+MODULE_DESCRIPTION("zylonite audio touch codec driver on ALSA");
+MODULE_LICENSE("GPL");
+
