diff options
author | Michael Lauer <mickey@vanille-media.de> | 2008-07-17 00:06:49 +0000 |
---|---|---|
committer | Michael Lauer <mickey@vanille-media.de> | 2008-07-17 00:06:49 +0000 |
commit | e5a07e89eee07991812965e5de9855524326046d (patch) | |
tree | af0292e04acbd90cec81e21a5c10b76731ed7bba /packages/linux/linux-rp-2.6.26/zylonite_touch-r0.patch | |
parent | af568c07872e91924a320060b9b651ad23efc67c (diff) | |
parent | ce10c417ad24f7d9d1db3e63a076d56ac9143252 (diff) |
merge of '4c6f4640a8b948badde77deaaebbfc2c9959ecae'
and 'e5e5a9814f67f07864e0b56012257f49ace89669'
Diffstat (limited to 'packages/linux/linux-rp-2.6.26/zylonite_touch-r0.patch')
-rw-r--r-- | packages/linux/linux-rp-2.6.26/zylonite_touch-r0.patch | 1548 |
1 files changed, 1548 insertions, 0 deletions
diff --git a/packages/linux/linux-rp-2.6.26/zylonite_touch-r0.patch b/packages/linux/linux-rp-2.6.26/zylonite_touch-r0.patch new file mode 100644 index 0000000000..1c00696051 --- /dev/null +++ b/packages/linux/linux-rp-2.6.26/zylonite_touch-r0.patch @@ -0,0 +1,1548 @@ +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"); ++ |