1549 lines
51 KiB
Diff
1549 lines
51 KiB
Diff
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");
|
|
+
|