This is the core patch adding EZX support to the kernel Index: linux-2.6.16.5-a/arch/arm/boot/compressed/head-xscale.S =================================================================== --- linux-2.6.16.5-a.orig/arch/arm/boot/compressed/head-xscale.S 2006-05-04 17:06:50.000000000 +0200 +++ linux-2.6.16.5-a/arch/arm/boot/compressed/head-xscale.S 2006-05-04 17:07:04.000000000 +0200 @@ -54,3 +54,6 @@ str r1, [r0, #0x18] #endif +#ifdef CONFIG_ARCH_EZX + mov r7, #MACH_TYPE_EZX +#endif Index: linux-2.6.16.5-a/arch/arm/boot/compressed/head.S =================================================================== --- linux-2.6.16.5-a.orig/arch/arm/boot/compressed/head.S 2006-05-04 17:06:50.000000000 +0200 +++ linux-2.6.16.5-a/arch/arm/boot/compressed/head.S 2006-05-04 17:07:04.000000000 +0200 @@ -10,6 +10,7 @@ #include #include +#define DEBUG /* * Debugging stuff * @@ -111,6 +112,11 @@ mov r0, r0 .endr + inituart r10, r11 + + mov r1, #0x300 @ mach_id 0x363 is official EZX + orr r1, r1, #0x63 @ bootloader JUMP doesn't set r1 + b 1f .word 0x016f2818 @ Magic numbers to help the loader .word start @ absolute load/run zImage address @@ -137,6 +143,10 @@ teqp pc, #0x0c000003 @ turn off interrupts #endif + addruart r11 + mov r10, #'d' + senduart r10, r11 + /* * Note that some cache flushing and other stuff may * be needed here - is there an Angel SWI call for this? Index: linux-2.6.16.5-a/arch/arm/kernel/apm.c =================================================================== --- linux-2.6.16.5-a.orig/arch/arm/kernel/apm.c 2006-05-04 17:06:50.000000000 +0200 +++ linux-2.6.16.5-a/arch/arm/kernel/apm.c 2006-05-04 17:07:04.000000000 +0200 @@ -605,3 +605,7 @@ wake_up_interruptible(&kapmd_wait); } EXPORT_SYMBOL(apm_queue_event); + +void pm_do_poweroff(void) +{ /* FIXME */ +} Index: linux-2.6.16.5-a/arch/arm/mach-pxa/Kconfig =================================================================== --- linux-2.6.16.5-a.orig/arch/arm/mach-pxa/Kconfig 2006-05-04 17:06:50.000000000 +0200 +++ linux-2.6.16.5-a/arch/arm/mach-pxa/Kconfig 2006-05-04 17:07:29.000000000 +0200 @@ -1,5 +1,8 @@ if ARCH_PXA +config PXA_EZX + bool + menu "Intel PXA2xx Implementations" choice @@ -30,6 +33,18 @@ SL-C3000 (Spitz), SL-C3100 (Borzoi) or SL-C6000x (Tosa) handheld computer. +config PXA_EZX_E680 + bool "Motorola E680 GSM Phone" + select PXA27x + select IWMMXT + select PXA_EZX + +config PXA_EZX_A780 + bool "Motorola A780 GSM Phone" + select PXA27x + select IWMMXT + select PXA_EZX + endchoice if PXA_SHARPSL Index: linux-2.6.16.5-a/arch/arm/mach-pxa/Makefile =================================================================== --- linux-2.6.16.5-a.orig/arch/arm/mach-pxa/Makefile 2006-05-04 17:06:55.000000000 +0200 +++ linux-2.6.16.5-a/arch/arm/mach-pxa/Makefile 2006-05-04 17:07:04.000000000 +0200 @@ -5,7 +5,7 @@ # Common support (must be linked before board specific support) obj-y += generic.o irq.o dma.o time.o obj-$(CONFIG_PXA25x) += pxa25x.o -obj-$(CONFIG_PXA27x) += pxa27x.o +obj-$(CONFIG_PXA27x) += pxa27x.o sram.o # Specific board support obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o @@ -16,6 +16,7 @@ obj-$(CONFIG_MACH_AKITA) += akita-ioexp.o obj-$(CONFIG_MACH_POODLE) += poodle.o obj-$(CONFIG_MACH_TOSA) += tosa.o +obj-$(CONFIG_PXA_EZX) += ezx.o # Support for blinky lights led-y := leds.o Index: linux-2.6.16.5-a/arch/arm/mach-pxa/ezx-compat.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/arch/arm/mach-pxa/ezx-compat.c 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,24 @@ + +int set_GPIO_IRQ_edge(int irq, int type) +{ + int mytype; + + switch (type) { + case GPIO_FALLING_EDGE: + mytype = IRQT_FALLING; + break; + case GPIO_RISING_EDGE: + mytype = IRQT_RISING; + break; + case GPIO_BOTH_EDGES: + mytype = IRQT_BOTHEDGE; + break; + default: + return -EINVAL; + break; + } + + return set_irq_type(irq, mytype); +} + + Index: linux-2.6.16.5-a/arch/arm/mach-pxa/ezx.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/arch/arm/mach-pxa/ezx.c 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,567 @@ +/* + * linux/arch/arm/mach-ezx/a780.c + * + * Support for the Motorola Ezx A780 Development Platform. + * + * Author: Zhuang Xiaofan + * Created: Nov 25, 2003 + * Copyright: Motorola Inc. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "generic.h" +#include +#include + +#include "../../../drivers/misc/ezx/ezx-emu.h" + +#define FIRST_STEP 2 +#define LAST_STEP 3 +#define BP_RDY_TIMEOUT 0x000c0000 + +extern void usb_send_readurb(void); +extern void pm_do_poweroff(void); + + +/* check power down condition */ +inline void check_power_off(void) +{ + if (!(GPIO_is_high(GPIO_BB_WDI2))) { +#ifdef CONFIG_PM + pm_do_poweroff(); +#endif + } +} + +/* OHCI Controller */ + +static int ezx_ohci_init(struct device *dev) +{ + /* for A780 support (connected with Neptune) */ + pxa_gpio_mode(GPIO30_USB_P3_2); /* GPIO30 - USB_P3_2/ICL_TXENB */ + pxa_gpio_mode(GPIO31_USB_P3_6); /* GPIO31 - USB_P3_6/ICL_VPOUT */ + pxa_gpio_mode(GPIO90_USB_P3_5); /* GPIO90 - USB_P3_5/ICL_VPIN */ + pxa_gpio_mode(GPIO91_USB_P3_1); /* GPIO91 - USB_P3_1/ICL_XRXD */ + pxa_gpio_mode(GPIO56_USB_P3_4); /* GPIO56 - USB_P3_4/ICL_VMOUT */ + pxa_gpio_mode(GPIO113_USB_P3_3);/* GPIO113 - USB_P3_3/ICL_VMIN */ + UP3OCR = 0x00000002; + + UHCHR = UHCHR & ~(UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE); + + return 0; +} + +static struct pxaohci_platform_data ezx_ohci_platform_data = { + .port_mode = PMM_NPS_MODE, + .init = ezx_ohci_init, +}; + +/* MMC/SD Device */ + +static struct pxamci_platform_data ezx_mci_platform_data; + +static int ezx_mci_init(struct device *dev, + irqreturn_t (*ezx_detect_int)(int, void *, struct pt_regs *), + void *data) +{ + int err; + printk("%s entered\n", __FUNCTION__); + + /* Setup GPIO for PXA27x MMC/SD controller */ + pxa_gpio_mode(GPIO32_MMCCLK_MD); + pxa_gpio_mode(GPIO112_MMCCMD_MD); + pxa_gpio_mode(GPIO92_MMCDAT0_MD); + pxa_gpio_mode(GPIO109_MMCDAT1_MD); + pxa_gpio_mode(GPIO110_MMCDAT2_MD); + pxa_gpio_mode(GPIO111_MMCDAT3_MD); + + SSP_PCAP_MMCSD_poweron(); + + ezx_mci_platform_data.detect_delay = msecs_to_jiffies(250); + + err = request_irq(0x49, ezx_detect_int, SA_INTERRUPT, + "MMC card detect", data); + if (err) { + printk(KERN_ERR "ezx_mci_detect: MMC/SD: can't request " + "MMC card detect IRQ\n"); + return -1; + } + + set_GPIO_IRQ_edge(0x0b, GPIO_BOTH_EDGES); + + return 0; +} + +static int ezx_mci_get_ro(struct device *dev) +{ + printk("%s entered\n", __FUNCTION__); + return (GPLR3 & 0x800); + // return GPIO_is_high(96+4); + /* this is only e680, i guess */ +} + +static void ezx_mci_setpower(struct device *dev, unsigned int vdd) +{ + printk("%s entered\n", __FUNCTION__); + /* FIXME: implement this */ + SSP_PCAP_MMCSD_poweron(); +} + +static void ezx_mci_exit(struct device *dev, void *data) +{ + printk("%s entered\n", __FUNCTION__); + SSP_PCAP_MMCSD_poweroff(); + free_irq(0x49, data); +} + +static struct pxamci_platform_data ezx_mci_platform_data = { + .ocr_mask = MMC_VDD_27_28, //|MMC_VDD_32_33|MMC_VDD_33_34, + .init = ezx_mci_init, + .get_ro = ezx_mci_get_ro, + .setpower = ezx_mci_setpower, + .exit = ezx_mci_exit, +}; + +/* USB Device Controller */ + +static int udc_connected_status; + +static void ezx_udc_command(int cmd) +{ + switch (cmd) { + case PXA2XX_UDC_CMD_DISCONNECT: + printk(KERN_NOTICE "USB cmd disconnect\n"); + pcap_switch_off_usb(); + udc_connected_status = 0; + break; + case PXA2XX_UDC_CMD_CONNECT: + printk(KERN_NOTICE "USB cmd connect\n"); + pcap_switch_on_usb(); + udc_connected_status = 1; + break; + } +} + +static int ezx_udc_is_connected(void) +{ + return udc_connected_status; +} + +static struct pxa2xx_udc_mach_info ezx_udc_info __initdata = { + .udc_is_connected = ezx_udc_is_connected, + .udc_command = ezx_udc_command, +}; + +/* pxafb */ + +#define BKLIGHT_PRESCALE 2 +#define BKLIGHT_PERIOD 49 +#define DEFAULT_DUTYCYCLE 25 +#define MAX_DUTYCYCLE (BKLIGHT_PERIOD+1) +#define MIN_DUTYCYCLE 0 + +static void pxafb_backlight_power(int on) +{ + if (on) { + CKEN |= CKEN0_PWM0; + PWM_CTRL0 = BKLIGHT_PRESCALE; + PWM_PERVAL0 = BKLIGHT_PERIOD; + PWM_PWDUTY0 = DEFAULT_DUTYCYCLE; + + GPDR0 |= 0x00010000; //PWM0 is GPIO16 + pxa_gpio_mode(GPIO16_PWM0_MD); + } else { +#if 0 + PWM_PWDUTY0 = 0; + GAFR0_U &= +#endif + } +} + +//#define mdelay(x) udelay((x)*1000) + +static void pxafb_lcd_power(int on) +{ + if (on) { + mdelay(1); + GPSR3 = 0x00100000; + mdelay(10); + GPCR3 = 0x00100000; + GPDR3 |= 0x00100000; + } else { +#if 0 + GPSR3 = 0x00100000; + PGSR3 |= 0x00100000; + mdelay(41); +#endif + } +} + +static struct pxafb_mach_info ezx_fb_info __initdata = { + .pixclock = 150000, + .xres = 240, + .yres = 320, + .bpp = 16, + + .hsync_len = 10, + .left_margin = 20, + .right_margin = 10, + + .vsync_len = 2, + .upper_margin = 3, + .lower_margin = 2, + + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + + .lccr0 = 0x002008F8, + .lccr3 = 0x0430FF09, + + .pxafb_backlight_power = &pxafb_backlight_power, + .pxafb_lcd_power = &pxafb_lcd_power, +}; + + +/* backlight */ +/* keyboard */ +/* touch screen */ + +/* SSP device */ + +struct platform_device ezx_ssp_pcap_device = { + .name = "ezx-ssp-pcap", + .dev = { + //.parent = , + }, + .id = -1, +}; + + +static int step = FIRST_STEP; +void handshake(void) +{ + /* step 1: check MCU_INT_SW or BP_RDY is low (now it is checked in apboot) */ + if (step == 1) { + int timeout = BP_RDY_TIMEOUT; + + /* config MCU_INT_SW, BP_RDY as input */ + GPDR(GPIO_MCU_INT_SW) &= ~GPIO_bit(GPIO_MCU_INT_SW); + GPDR(GPIO_BP_RDY) &= ~GPIO_bit(GPIO_BP_RDY); + + while ( timeout -- ) { + if ( (!(GPIO_is_high(GPIO_MCU_INT_SW))) + || (!(GPIO_is_high(GPIO_BP_RDY))) ) { + step ++; + break; + } + + check_power_off(); + } + } + + /* step 2: wait BP_RDY is low */ + if (step == 2) { + if (!(GPIO_is_high(GPIO_BP_RDY))) { + + /* config MCU_INT_SW as output */ + pxa_gpio_mode(GPIO_MCU_INT_SW | GPIO_OUT); + clr_GPIO(GPIO_MCU_INT_SW); + + step ++; + } + } + + /* step 3: wait BP_RDY is high */ + if (step == 3) { + if (GPIO_is_high(GPIO_BP_RDY)) { + step ++; + //FIXME delay_bklight(); + set_GPIO(GPIO_MCU_INT_SW); + } + } +} + +#ifdef CONFIG_APM +static unsigned long idle_limit = 0; +int pm_handle_irq(int irq) +{ + + //FIXME: extern unsigned long idle_limit; + //FIXME: extern int can_idle, can_sleep; + static unsigned long tmp_jiffy; /* for temporary store of jiffies */ + + /* + * if idle_limit is zero, never enter idle. + * if not OS timer, reset idle timer count + */ + if (idle_limit == 0) { + tmp_jiffy = jiffies; + return irq; + } +#if 0 + if (irq != IRQ_OST0) { + tmp_jiffy = jiffies; + can_idle = 0; + can_sleep = 0; + } else if (jiffies > tmp_jiffy + idle_limit) { + + /* + * I think this is enough to prevent from reentering here + * due to jiffies will be stoped + */ + tmp_jiffy = jiffies; + + /* if pm idle timer expired, queue event */ + apm_queue_event(KRNL_PROC_INACT); + can_idle = 1; + } +#endif + + return irq; +} + +irqreturn_t bp_wdi_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + apm_queue_event(KRNL_BP_WDI); + return IRQ_HANDLED; +} + +static struct irqaction bp_wdi_irq = { + .name = "BP wdi", + .handler = &bp_wdi_intr, +}; +#endif + +int handshake_pass(void) +{ + return (step > LAST_STEP); +} + +static irqreturn_t bp_rdy_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + static int usbipc_ready = 0; + + if (!usbipc_ready) { + handshake(); + if (handshake_pass()) { + disable_irq(IRQ_GPIO(GPIO_BB_WDI2)); + + /* set bp_rdy handle for usb ipc */ + set_GPIO_IRQ_edge(GPIO_BP_RDY, GPIO_FALLING_EDGE); + usbipc_ready = 1; + } + } else + // FIXME usb_send_readurb(); + {} + + return IRQ_HANDLED; +} + +static struct irqaction bp_rdy_irq = { + .name = "BP rdy", + .handler = bp_rdy_intr, +}; + +static irqreturn_t bp_wdi2_intr(int irq, void *dev_id, struct pt_regs *regs) +{ +#ifdef CONFIG_PM + pm_do_poweroff(); +#endif + return IRQ_HANDLED; +} + +static struct irqaction bp_wdi2_irq = { + .name = "BP wdi2", + .handler = bp_wdi2_intr, +}; + + +static struct resource ezx_bp_resources[] = { + [0] = { + .start = GPIO_BP_RDY, + .end = GPIO_BP_RDY, + .flags = IORESOURCE_IRQ, + }, + [1] = { + .start = GPIO_BB_WDI2, + .end = GPIO_BB_WDI2, + .flags = IORESOURCE_IRQ, + }, +#ifdef CONFIG_APM + [2] = { + .start = GPIO_BB_WDI, + .end = GPIO_BB_WDI, + .flags = IORESOURCE_IRQ, + }, +#endif +}; + +static struct platform_device ezx_bp_device = { + .name = "ezx-bp", + .dev = { + //.parent = + //.platform_data = + }, + .id = -1, + .num_resources = ARRAY_SIZE(ezx_bp_resources), + .resource = ezx_bp_resources, +}; + +static void __init ezx_init_gpio_irq(void) +{ +#ifdef CONFIG_APM + set_GPIO_IRQ_edge(GPIO_BB_WDI, GPIO_FALLING_EDGE); + setup_irq(IRQ_GPIO(GPIO_BB_WDI), &bp_wdi_irq); +#endif + set_GPIO_IRQ_edge(GPIO_BP_RDY, GPIO_BOTH_EDGES); + setup_irq(IRQ_GPIO(GPIO_BP_RDY), &bp_rdy_irq); + + set_GPIO_IRQ_edge(GPIO_BB_WDI2, GPIO_FALLING_EDGE); + setup_irq(IRQ_GPIO(GPIO_BB_WDI2), &bp_wdi2_irq); +} + +static void __init a780_init_irq(void) +{ + pxa_init_irq(); + + /* init ezx specfic gpio irq */ + ezx_init_gpio_irq(); + + check_power_off(); + handshake(); + if (handshake_pass()) { + disable_irq(IRQ_GPIO(GPIO_BP_RDY)); + disable_irq(IRQ_GPIO(GPIO_BB_WDI2)); + } +} + +static struct platform_device *devices[] __initdata = { + &ezx_bp_device, + &ezx_ssp_pcap_device, +}; + +static void __init +fixup_a780(struct machine_desc *desc, struct tag *tag, + char **cmdline, struct meminfo *mi) +{ + screen_info.orig_video_cols = 30; + screen_info.orig_video_lines = 80; +} + +static void __init a780_init(void) +{ + CKEN = CKEN9_OSTIMER | CKEN22_MEMC | CKEN5_STUART; + + /* set BB_RESET PIN out put high */ + pxa_gpio_mode(GPIO_BB_RESET|GPIO_OUT); + set_GPIO(GPIO_BB_RESET); + + pxa_gpio_mode(GPIO_ICL_FFRXD_MD); + pxa_gpio_mode(GPIO_ICL_FFTXD_MD); + pxa_gpio_mode(GPIO_ICL_FFCTS_MD); + pxa_gpio_mode(GPIO_ICL_FFRTS_MD); + + pxa_gpio_mode(GPIO42_BTRXD_MD); + pxa_gpio_mode(GPIO43_BTTXD_MD); + pxa_gpio_mode(GPIO44_BTCTS_MD); + pxa_gpio_mode(GPIO45_BTRTS_MD); + + /* clear EMU MUX1/MUX2 (low) to close the audio path to EMU */ + pxa_gpio_mode(GPIO_EMU_MUX1|GPIO_OUT); + clr_GPIO(GPIO_EMU_MUX1); + pxa_gpio_mode(GPIO_EMU_MUX2|GPIO_OUT); + clr_GPIO(GPIO_EMU_MUX2); + +#if defined(CONFIG_ARCH_EZX_E680) + pxa_gpio_mode(GPIO46_STRXD_MD); + pxa_gpio_mode(GPIO47_STTXD_MD); + + /* setup sleep mode values */ + PWER = 0xc000f803; // disable usb 0xdc00f803; + PFER = 0x0000f803; + PRER = 0x00001802; + // keypad wakeup (PKWR,PGSR3) should be in keypad.c + PGSR0 = 0x00000010; + PGSR1 = 0x02800000; + PGSR2 = 0x00040000; + PGSR3 = 0x00000000; + PCFR = PCFR_DC_EN | PCFR_FS | PCFR_FP | PCFR_OPDE; + PSLR = 0x05800f00; + +#elif defined(CONFIG_ARCH_EZX_A780) + + /* Standard UART */ + pxa_gpio_mode(GPIO46_STRXD_MD); + pxa_gpio_mode(GPIO47_STTXD_MD); + + /* setup sleep mode values */ + PWER = 0xc0007803; // disable usb, GPIO15 NC + PFER = 0x00007803; + PRER = 0x00001802; + // keypad wakeup (PKWR,PGSR3) should be in keypad.c + PGSR0 = 0x00000010; + PGSR1 = 0x02800000; + PGSR2 = 0x00040000; + PGSR3 = 0x00000008; + PCFR = PCFR_DC_EN | PCFR_FS | PCFR_FP | PCFR_OPDE; + PSLR = 0x05800f00; + +#endif + set_pxa_fb_info(&ezx_fb_info); + pxa_set_udc_info(&ezx_udc_info); + pxa_set_mci_info(&ezx_mci_platform_data); + pxa_set_ohci_info(&ezx_ohci_platform_data); + + ssp_pcap_init(); + + /* try to configure USB connector as FFUART */ + emu_switch_to(EMU_SWITCH_TO_UART); + + platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +MACHINE_START(EZX, "Motorola Ezx Platform") + /* Maintainer: Harald Welte */ + .phys_ram = 0xa0000000, + .phys_io = 0x40000000, + .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, + .boot_params = 0xa0000100, + .fixup = fixup_a780, + .map_io = pxa_map_io, + .init_irq = a780_init_irq, + .timer = &pxa_timer, + .init_machine = a780_init, +MACHINE_END Index: linux-2.6.16.5-a/arch/arm/mach-pxa/irq.c =================================================================== --- linux-2.6.16.5-a.orig/arch/arm/mach-pxa/irq.c 2006-05-04 17:06:50.000000000 +0200 +++ linux-2.6.16.5-a/arch/arm/mach-pxa/irq.c 2006-05-04 17:07:04.000000000 +0200 @@ -25,6 +25,8 @@ #include "generic.h" +#include "ezx-compat.c" + /* * This is for peripheral IRQs internal to the PXA chip. */ Index: linux-2.6.16.5-a/arch/arm/mach-pxa/sram.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/arch/arm/mach-pxa/sram.c 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,104 @@ +/* + * linux/arch/arm/mach-wmmx/sram.c + * + * Bulverde Internal Memory stuff + * + * Created: Sep 05, 2003 + * Copyright: MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define SRAM_MEM_VIRT io_p2v(SRAM_MEM_PHYS) + +#define SRAM_DELAY_STANDBY_TIME 255 + +static spinlock_t sram_spinlock; +static volatile int sram_locked = 0; + +static int __init sram_init (void) { + /* Enable clock */ + pxa_set_cken(CKEN20_IM, 1); + + /* All the banks are + * - Automatic wakeup enabled + * - Enter Stand-by after 255 ms + */ + IMPMCR = IMPMCR_PC3_AUTO_MODE | + IMPMCR_PC2_AUTO_MODE | + IMPMCR_PC1_AUTO_MODE | + IMPMCR_PC0_AUTO_MODE | + IMPMCR_AW3 | IMPMCR_AW2 | + IMPMCR_AW1 | IMPMCR_AW0 | + SRAM_DELAY_STANDBY_TIME; + + return 0; +} + +int sram_access_obtain(unsigned long *pmem, unsigned long *psize) { + + int flags; + + spin_lock_irqsave(&sram_spinlock, flags); + + if (sram_locked != 0) { + spin_unlock_irqrestore(&sram_spinlock, flags); + return -EAGAIN; + } + + sram_locked = 1; + + spin_unlock_irqrestore(&sram_spinlock, flags); + + *pmem = SRAM_MEM_VIRT; + *psize = SRAM_SIZE; + + return 0; +} + +int sram_access_release(unsigned long *pmem, unsigned long *psize) +{ + if ((*pmem != SRAM_MEM_VIRT) || + (*psize != SRAM_SIZE)){ + return -EINVAL; + } + + *pmem = 0; + *psize = 0; + + sram_locked = 0; + + return 0; +} + +EXPORT_SYMBOL(sram_access_obtain); +EXPORT_SYMBOL(sram_access_release); + +__initcall(sram_init); + Index: linux-2.6.16.5-a/arch/arm/mm/init.c =================================================================== --- linux-2.6.16.5-a.orig/arch/arm/mm/init.c 2006-05-04 17:06:50.000000000 +0200 +++ linux-2.6.16.5-a/arch/arm/mm/init.c 2006-05-04 17:07:04.000000000 +0200 @@ -230,6 +230,10 @@ #endif if (res_size) reserve_bootmem_node(pgdat, PHYS_OFFSET, res_size); +#ifdef CONFIG_ARCH_EZX + /* reserve the first page memory for exiting sleep and user off */ + reserve_bootmem_node(pgdat, PHYS_OFFSET, PAGE_SIZE); +#endif } void __init build_mem_type_table(void); Index: linux-2.6.16.5-a/include/asm-arm/arch-pxa/debug-macro.S =================================================================== --- linux-2.6.16.5-a.orig/include/asm-arm/arch-pxa/debug-macro.S 2006-05-04 17:06:50.000000000 +0200 +++ linux-2.6.16.5-a/include/asm-arm/arch-pxa/debug-macro.S 2006-05-04 17:07:04.000000000 +0200 @@ -14,15 +14,59 @@ #include "hardware.h" .macro addruart,rx - mrc p15, 0, \rx, c1, c0 - tst \rx, #1 @ MMU enabled? - moveq \rx, #0x40000000 @ physical - movne \rx, #io_p2v(0x40000000) @ virtual - orr \rx, \rx, #0x00100000 +@ mrc p15, 0, \rx, c1, c0 +@ tst \rx, #1 @ MMU enabled? + mov \rx, #0x40000000 @ physical +@ moveq \rx, #0x40000000 @ physical +@ movne \rx, #io_p2v(0x40000000) @ virtual + orr \rx, \rx, #0x00700000 + .endm + + .macro inituart,rd,rx + ldr \rd, =0x41300004 @ CKEN + ldr \rx, [\rd] + orr \rx, \rx, #0x20 + str \rx, [\rd] + + ldr \rd, =0x40E0005C + ldr \rx, [\rd] + bic \rx, \rx, #0xF0000000 @ clear GPIO46/47 config + orr \rx, \rx, #0x60000000 @ set GPIO46: AF2, GPIO47: AF1 + str \rx, [\rd] + ldr \rd, =0x40E00010 + ldr \rx, [\rd] + bic \rx, \rx, #0x0000c000 @ clear GPIO46/47 direction + orr \rx, \rx, #0x00008000 @ set GPIO 47 out, 46 in + str \rx, [\rd] + + addruart \rd + mov \rx, #0x83 @ DLAB = 1 + strb \rx, [\rd, #0x0c] + + mov \rx, #0x08 @ Divisor 8 => 115200 bps + strb \rx, [\rd, #0x00] + + mov \rx, #0x00 + strb \rx, [\rd, #0x04] @ Divisor high = 0 + + mov \rx, #0x03 + strb \rx, [\rd, #0x0c] @ DLAB = 0, n81 + + mov \rx, #0x00 + strb \rx, [\rd, #0x10] @ MCR = 0 + + mov \rx, #0x00 + strb \rx, [\rd, #0x28] @ disable autobaud + + mov \rx, #0x40 + strb \rx, [\rd, #0x04] @ IER UUE (UART Enable) .endm .macro senduart,rd,rx - str \rd, [\rx, #0] +1000: ldr r12, [\rx, #0x14] + tst r12, #(1 << 6) + beq 1000b + strb \rd, [\rx, #0] .endm .macro busyuart,rd,rx Index: linux-2.6.16.5-a/include/asm-arm/arch-pxa/ezx-compat.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/include/asm-arm/arch-pxa/ezx-compat.h 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,14 @@ +#ifndef _EZX_COMPAT_H +#define _EZX_COMPAT_H + +#define GPIO_is_high(x) (GPLR(x) & GPIO_bit(x)) +#define set_GPIO(x) (GPSR(x) = GPIO_bit(x)) +#define clr_GPIO(x) (GPCR(x) = GPIO_bit(x)) + +#define GPIO_FALLING_EDGE 1 +#define GPIO_RISING_EDGE 2 +#define GPIO_BOTH_EDGES 3 + +extern int set_GPIO_IRQ_edge(int irq, int type); + +#endif Index: linux-2.6.16.5-a/include/asm-arm/arch-pxa/ezx.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/include/asm-arm/arch-pxa/ezx.h 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,221 @@ +/* + * linux/include/asm-arm/arch-pxa/ezx.h + * + * Specific macro defines for Motorola Ezx Development Platform + * + * Author: Zhuang Xiaofan + * Created: Nov 25, 2003 + * Copyright: Motorola Inc. + * + * 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. + */ + +/* support E680 p3 and ealier PCB */ +//#define E680_P3_AND_EARLY + +/* + * Flags in memory for sleep use + */ +#define FLAG_ADDR PHYS_OFFSET +#define RESUME_ADDR (PHYS_OFFSET + 4) +#define BPSIG_ADDR (PHYS_OFFSET + 8) + +#define USER_OFF_FLAG 0x5a5a5a5a +#define SLEEP_FLAG 0x6b6b6b6b +#define OFF_FLAG 0x7c7c7c7c +#define REFLASH_FLAG 0x0C1D2E3F +#define PASS_THRU_FLAG 0x12345678 + +#define WDI_FLAG 0xbb00dead +#define NO_FLAG 0xaa00dead + +/* + * GPIO control pin, have to change when hardware lock down + */ + +#ifdef E680_P3_AND_EARLY + +/* shakehand with BP's PIN */ +#define GPIO_BP_RDY 0 /* BP_RDY */ +#define GPIO_BB_WDI 13 /* BB_WDI */ +#define GPIO_BB_WDI2 3 /* BB_WDI2 */ +#define GPIO_BB_RESET 57 /* BB_RESET */ +#define GPIO_MCU_INT_SW 115 /* MCU_INT_SW */ +#define GPIO_TC_MM_EN 89 /* TC_MM_EN */ + +/* control PCAP direct PIN */ +#define GPIO_WDI_AP 4 /* WDI_AP */ +#define GPIO_SYS_RESTART 55 /* restart PCAP power */ +#define GPIO_AP_STANDBY 28 /* make pcap enter standby mode */ + +/* communicate with PCAP's PIN */ +#define GPIO_PCAP_SEC_INT 1 /* PCAP interrupt PIN to AP */ +#define GPIO_SPI_CLK 23 /* PCAP SPI port clock */ +#define GPIO_SPI_CE 24 /* PCAP SPI port SSPFRM */ +#define GPIO_SPI_MOSI 25 /* PCAP SPI port SSPTXD */ +#define GPIO_SPI_MISO 26 /* PCAP SPI port SSPRXD */ + +/* blue tooth control PIN */ +#define GPIO_BT_WAKEUP 2 /* AP wake up bluetooth module */ +#define GPIO_BT_HOSTWAKE 14 /* bluetooth module wake up Ap module */ +#define GPIO_BT_RESET 56 /* AP reset bluetooth module */ + +/* control LCD high - OFF low -- ON */ +#define GPIO_LCD_OFF 116 /* control LCD */ + +/* FFUART PIN */ +#define GPIO_ICL_FFRXD_MD (34 | GPIO_ALT_FN_1_IN) +#define GPIO_ICL_FFCTS_MD (35 | GPIO_ALT_FN_1_IN) +#define GPIO_ICL_FFTXD_MD (39 | GPIO_ALT_FN_2_OUT) +#define GPIO_ICL_FFRTS_MD (41 | GPIO_ALT_FN_2_OUT) + +#elif defined(A780_P1_AND_EARLY) + +/* shakehand with BP's PIN */ +#define GPIO_BP_RDY 0 /* BP_RDY */ +#define GPIO_BB_WDI 13 /* BB_WDI */ +#define GPIO_BB_WDI2 3 /* BB_WDI2 */ +#define GPIO_BB_RESET 82 /* BB_RESET */ +#define GPIO_MCU_INT_SW 57 /* MCU_INT_SW */ +#define GPIO_TC_MM_EN 89 /* TC_MM_EN */ + +/* control PCAP direct PIN */ +#define GPIO_WDI_AP 4 /* WDI_AP */ +#define GPIO_SYS_RESTART 55 /* restart PCAP power */ +#define GPIO_AP_STANDBY 28 /* make pcap enter standby mode */ + +/* communicate with PCAP's PIN */ +#define GPIO_PCAP_SEC_INT 1 /* PCAP interrupt PIN to AP */ +#define GPIO_SPI_CLK 29 /* PCAP SPI port clock */ +#define GPIO_SPI_CE 24 /* PCAP SPI port SSPFRM */ +#define GPIO_SPI_MOSI 25 /* PCAP SPI port SSPTXD */ +#define GPIO_SPI_MISO 26 /* PCAP SPI port SSPRXD */ + +/* blue tooth control PIN */ +#define GPIO_BT_WAKEUP 2 /* AP wake up bluetooth module */ +#define GPIO_BT_HOSTWAKE 14 /* bluetooth module wake up Ap module */ +#define GPIO_BT_RESET 56 /* AP reset bluetooth module */ + +/* control LCD high - OFF low -- ON */ +#define GPIO_LCD_OFF 116 /* control LCD */ + +/* FFUART PIN */ +#define GPIO_ICL_FFRXD_MD (53 | GPIO_ALT_FN_1_IN) +#define GPIO_ICL_FFCTS_MD (35 | GPIO_ALT_FN_1_IN) +#define GPIO_ICL_FFTXD_MD (39 | GPIO_ALT_FN_2_OUT) +#define GPIO_ICL_FFRTS_MD (41 | GPIO_ALT_FN_2_OUT) + +#else + +/* shakehand with BP's PIN */ +#define GPIO_BP_RDY 0 /* BP_RDY */ +#define GPIO_BB_WDI 13 /* BB_WDI */ +#define GPIO_BB_WDI2 3 /* BB_WDI2 */ +#define GPIO_BB_RESET 82 /* BB_RESET */ +#define GPIO_MCU_INT_SW 57 /* MCU_INT_SW */ +#define GPIO_TC_MM_EN 99 /* TC_MM_EN */ + +/* control PCAP direct PIN */ +#define GPIO_WDI_AP 4 /* WDI_AP */ +#define GPIO_SYS_RESTART 55 /* restart PCAP power */ +//#define GPIO_AP_STANDBY 28 /* make pcap enter standby mode */ + +/* communicate with PCAP's PIN */ +#define GPIO_PCAP_SEC_INT 1 /* PCAP interrupt PIN to AP */ +#define GPIO_SPI_CLK 29 /* PCAP SPI port clock */ +#define GPIO_SPI_CE 24 /* PCAP SPI port SSPFRM */ +#define GPIO_SPI_MOSI 25 /* PCAP SPI port SSPTXD */ +#define GPIO_SPI_MISO 26 /* PCAP SPI port SSPRXD */ + +/* blue tooth control PIN */ +#define GPIO_BT_WAKEUP 28 /* AP wake up bluetooth module */ +#define GPIO_BT_HOSTWAKE 14 /* AP wake up bluetooth module */ +#define GPIO_BT_RESET 48 /* AP reset bluetooth module */ + +/* control LCD high - OFF low -- ON */ +#define GPIO_LCD_OFF 116 /* control LCD */ + +/* FFUART PIN */ +#define GPIO_ICL_FFRXD_MD (53 | GPIO_ALT_FN_1_IN) +#define GPIO_ICL_FFCTS_MD (35 | GPIO_ALT_FN_1_IN) +#define GPIO_ICL_FFTXD_MD (39 | GPIO_ALT_FN_2_OUT) +#define GPIO_ICL_FFRTS_MD (41 | GPIO_ALT_FN_2_OUT) + +#endif +/* + * ezx platform, wake up source edge detect bit + */ +#define PEDR_INT_SEC 1 + +#define GPIO_FLIP_PIN 12 +/*E680 screen lock button*/ + +#define GPIO_LOCK_SCREEN_PIN GPIO_FLIP_PIN + +/* MMC interface */ +#define GPIO_MMC_DETECT 11 +#define GPIO_MMC_CLK 32 +#define GPIO_MMC_DATA0 92 +#define GPIO_MMC_WP 107 +#define GPIO_MMC_DATA1 109 +#define GPIO_MMC_DATA2 110 +#define GPIO_MMC_DATA3 111 +#define GPIO_MMC_CMD 112 + +/* interface function */ +#define GPIO_MMC_CLK_MD (GPIO_MMC_CLK | GPIO_ALT_FN_2_OUT) +#define GPIO_MMC_DATA0_MD (GPIO_MMC_DATA0 | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT) +#define GPIO_MMC_DATA1_MD (GPIO_MMC_DATA1 | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT) +#define GPIO_MMC_DATA2_MD (GPIO_MMC_DATA2 | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT) +#define GPIO_MMC_DATA3_MD (GPIO_MMC_DATA3 | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT) + +#define GPIO_MMC_CMD_MD (GPIO_MMC_CMD | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT) + +/* EMU GPIO 119 ---MUX2 120 --- MUX1 */ +#define GPIO_EMU_MUX1 120 +#define GPIO_EMU_MUX2 119 +#define GPIO_SNP_INT_CTL 86 +#define GPIO_SNP_INT_IN 87 + + +/* audio related pins */ +#define AP_13MHZ_OUTPUT_PIN 9 + +#ifdef CONFIG_ARCH_EZX_E680 +#define GPIO_VA_SEL_BUL 79 +#define GPIO_FLT_SEL_BUL 80 /* out filter select pin */ +#define GPIO_MIDI_RESET 78 /* GPIO used by MIDI chipset */ +#define GPIO_MIDI_CS 33 +#define GPIO_MIDI_IRQ 15 +#define GPIO_MIDI_NPWE 49 +#define GPIO_MIDI_RDY 18 +#endif + +#ifdef CONFIG_ARCH_EZX_A780 +#define GPIO_HW_ATTENUATE_A780 96 /* hw noise attenuation be used or bypassed, for receiver or louderspeaker mode */ +#endif + + +/* bp status pin */ +#define GPIO_BP_STATE 41 + +/* define usb related pin */ +#define GPIO34_TXENB 34 +#define GPIO35_XRXD 35 +#define GPIO36_VMOUT 36 +#define GPIO39_VPOUT 39 +#define GPIO40_VPIN 40 +#define GPIO53_VMIN 53 + +/* USB client 6 pin defination */ +#define GPIO34_TXENB_MD (GPIO34_TXENB | GPIO_ALT_FN_1_OUT) +#define GPIO35_XRXD_MD (GPIO35_XRXD | GPIO_ALT_FN_2_IN ) +#define GPIO36_VMOUT_MD (GPIO36_VMOUT | GPIO_ALT_FN_1_OUT) +#define GPIO39_VPOUT_MD (GPIO39_VPOUT | GPIO_ALT_FN_1_OUT) +#define GPIO40_VPIN_MD (GPIO40_VPIN | GPIO_ALT_FN_3_IN ) +#define GPIO53_VMIN_MD (GPIO53_VMIN | GPIO_ALT_FN_2_IN ) + +#define GPIO53_FFRXD_MD (53 | GPIO_ALT_FN_1_IN) + Index: linux-2.6.16.5-a/include/asm-arm/arch-pxa/hardware.h =================================================================== --- linux-2.6.16.5-a.orig/include/asm-arm/arch-pxa/hardware.h 2006-05-04 17:06:50.000000000 +0200 +++ linux-2.6.16.5-a/include/asm-arm/arch-pxa/hardware.h 2006-05-04 17:07:04.000000000 +0200 @@ -62,6 +62,7 @@ #ifndef __ASSEMBLY__ +#include /* * Handy routine to set GPIO alternate functions */ Index: linux-2.6.16.5-a/include/asm-arm/arch-pxa/pxa-regs.h =================================================================== --- linux-2.6.16.5-a.orig/include/asm-arm/arch-pxa/pxa-regs.h 2006-05-04 17:06:50.000000000 +0200 +++ linux-2.6.16.5-a/include/asm-arm/arch-pxa/pxa-regs.h 2006-05-04 17:07:04.000000000 +0200 @@ -856,6 +856,8 @@ #define UP2OCR_HXOE (1 << 17) /* Host Port 2 Transceiver Output Enable */ #define UP2OCR_SEOS (1 << 24) /* Single-Ended Output Select */ +#define UP3OCR __REG(0x40600024) /* USB Port 3 Output Control register */ + #define UDCCSN(x) __REG2(0x40600100, (x) << 2) #define UDCCSR0 __REG(0x40600100) /* UDC Control/Status register - Endpoint 0 */ #define UDCCSR0_SA (1 << 7) /* Setup Active */ @@ -1259,6 +1261,7 @@ #define GPIO33_nCS_5 33 /* chip select 5 */ #define GPIO34_FFRXD 34 /* FFUART receive */ #define GPIO34_MMCCS0 34 /* MMC Chip Select 0 */ +#define GPIO34_USB_P2_2 34 /* USB Port2 Pin 2 */ #define GPIO35_FFCTS 35 /* FFUART Clear to send */ #define GPIO36_FFDCD 36 /* FFUART Data carrier detect */ #define GPIO37_FFDSR 37 /* FFUART data set ready */ @@ -1382,22 +1385,29 @@ #define GPIO29_SDATA_IN_AC97_MD (29 | GPIO_ALT_FN_1_IN) #define GPIO29_SDATA_IN_I2S_MD (29 | GPIO_ALT_FN_2_IN) #define GPIO30_SDATA_OUT_AC97_MD (30 | GPIO_ALT_FN_2_OUT) +#define GPIO30_USB_P3_2 (30 | GPIO_ALT_FN_3_OUT) #define GPIO30_SDATA_OUT_I2S_MD (30 | GPIO_ALT_FN_1_OUT) #define GPIO31_SYNC_I2S_MD (31 | GPIO_ALT_FN_1_OUT) #define GPIO31_SYNC_AC97_MD (31 | GPIO_ALT_FN_2_OUT) +#define GPIO31_USB_P3_6 (31 | GPIO_ALT_FN_3_OUT) #define GPIO32_SDATA_IN1_AC97_MD (32 | GPIO_ALT_FN_1_IN) #define GPIO32_SYSCLK_I2S_MD (32 | GPIO_ALT_FN_1_OUT) #define GPIO32_MMCCLK_MD ( 32 | GPIO_ALT_FN_2_OUT) #define GPIO33_nCS_5_MD (33 | GPIO_ALT_FN_2_OUT) #define GPIO34_FFRXD_MD (34 | GPIO_ALT_FN_1_IN) +#define GPIO34_USB_P2_2_MD (34 | GPIO_ALT_FN_1_OUT) #define GPIO34_MMCCS0_MD (34 | GPIO_ALT_FN_2_OUT) #define GPIO35_FFCTS_MD (35 | GPIO_ALT_FN_1_IN) +#define GPIO35_USB_P2_1_MD (35 | GPIO_ALT_FN_2_IN) #define GPIO36_FFDCD_MD (36 | GPIO_ALT_FN_1_IN) +#define GPIO36_USB_P2_4_MD (36 | GPIO_ALT_FN_1_OUT) #define GPIO37_FFDSR_MD (37 | GPIO_ALT_FN_1_IN) #define GPIO38_FFRI_MD (38 | GPIO_ALT_FN_1_IN) #define GPIO39_MMCCS1_MD (39 | GPIO_ALT_FN_1_OUT) #define GPIO39_FFTXD_MD (39 | GPIO_ALT_FN_2_OUT) +#define GPIO39_USB_P2_6_MD (39 | GPIO_ALT_FN_1_OUT) #define GPIO40_FFDTR_MD (40 | GPIO_ALT_FN_2_OUT) +#define GPIO40_USB_P2_5_MD (40 | GPIO_ALT_FN_3_IN) #define GPIO41_FFRTS_MD (41 | GPIO_ALT_FN_2_OUT) #define GPIO42_BTRXD_MD (42 | GPIO_ALT_FN_1_IN) #define GPIO42_HWRXD_MD (42 | GPIO_ALT_FN_3_IN) @@ -1422,13 +1432,16 @@ #define GPIO51_HWRTS_MD (51 | GPIO_ALT_FN_1_OUT) #define GPIO51_nPIOW_MD (51 | GPIO_ALT_FN_2_OUT) #define GPIO52_nPCE_1_MD (52 | GPIO_ALT_FN_2_OUT) -#define GPIO53_nPCE_2_MD (53 | GPIO_ALT_FN_2_OUT) #define GPIO53_MMCCLK_MD (53 | GPIO_ALT_FN_1_OUT) +#define GPIO53_nPCE_2_MD (53 | GPIO_ALT_FN_2_OUT) +#define GPIO53_FFRXD_MD (53 | GPIO_ALT_FN_1_IN) +#define GPIO53_USB_P2_3_MD (53 | GPIO_ALT_FN_2_IN) #define GPIO54_MMCCLK_MD (54 | GPIO_ALT_FN_1_OUT) #define GPIO54_nPCE_2_MD (54 | GPIO_ALT_FN_2_OUT) #define GPIO54_pSKTSEL_MD (54 | GPIO_ALT_FN_2_OUT) #define GPIO55_nPREG_MD (55 | GPIO_ALT_FN_2_OUT) #define GPIO56_nPWAIT_MD (56 | GPIO_ALT_FN_1_IN) +#define GPIO56_USB_P3_4 (56 | GPIO_ALT_FN_1_OUT) #define GPIO57_nIOIS16_MD (57 | GPIO_ALT_FN_1_IN) #define GPIO58_LDD_0_MD (58 | GPIO_ALT_FN_2_OUT) #define GPIO59_LDD_1_MD (59 | GPIO_ALT_FN_2_OUT) @@ -1471,6 +1484,8 @@ #define GPIO84_NSSP_TX (84 | GPIO_ALT_FN_1_OUT) #define GPIO84_NSSP_RX (84 | GPIO_ALT_FN_2_IN) #define GPIO85_nPCE_1_MD (85 | GPIO_ALT_FN_1_OUT) +#define GPIO90_USB_P3_5 (90 | GPIO_ALT_FN_2_IN) +#define GPIO91_USB_P3_1 (91 | GPIO_ALT_FN_2_IN) #define GPIO92_MMCDAT0_MD (92 | GPIO_ALT_FN_1_OUT) #define GPIO104_pSKTSEL_MD (104 | GPIO_ALT_FN_1_OUT) #define GPIO109_MMCDAT1_MD (109 | GPIO_ALT_FN_1_OUT) @@ -1481,6 +1496,7 @@ #define GPIO112_MMCCMD_MD (112 | GPIO_ALT_FN_1_OUT) #define GPIO113_I2S_SYSCLK_MD (113 | GPIO_ALT_FN_1_OUT) #define GPIO113_AC97_RESET_N_MD (113 | GPIO_ALT_FN_2_OUT) +#define GPIO113_USB_P3_3 (113 | GPIO_ALT_FN_3_IN) #define GPIO117_I2CSCL_MD (117 | GPIO_ALT_FN_1_OUT) #define GPIO118_I2CSDA_MD (118 | GPIO_ALT_FN_1_IN) @@ -1496,6 +1512,7 @@ #define PFER __REG(0x40F00014) /* Power Manager GPIO Falling-Edge Detect Enable Register */ #define PEDR __REG(0x40F00018) /* Power Manager GPIO Edge Detect Status Register */ #define PCFR __REG(0x40F0001C) /* Power Manager General Configuration Register */ +#define PGSR(x) (__REG(0x40F00020 + ((unsigned long)(x)/32 * 4))) #define PGSR0 __REG(0x40F00020) /* Power Manager GPIO Sleep State Register for GP[31-0] */ #define PGSR1 __REG(0x40F00024) /* Power Manager GPIO Sleep State Register for GP[63-32] */ #define PGSR2 __REG(0x40F00028) /* Power Manager GPIO Sleep State Register for GP[84-64] */ Index: linux-2.6.16.5-a/include/asm-arm/arch-pxa/uncompress.h =================================================================== --- linux-2.6.16.5-a.orig/include/asm-arm/arch-pxa/uncompress.h 2006-05-04 17:06:50.000000000 +0200 +++ linux-2.6.16.5-a/include/asm-arm/arch-pxa/uncompress.h 2006-05-04 17:07:04.000000000 +0200 @@ -14,12 +14,12 @@ #define STUART ((volatile unsigned long *)0x40700000) #define HWUART ((volatile unsigned long *)0x41600000) -#define UART FFUART +#define UART STUART static __inline__ void putc(char c) { - while (!(UART[5] & 0x20)); + while (!(UART[5] & 0x40)); UART[0] = c; } Index: linux-2.6.16.5-a/drivers/misc/ezx/ssp_pcap.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/misc/ezx/ssp_pcap.h 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,673 @@ +/* (c) Copyright Motorola Beijing 2002 all rights reserved. + + Project Name : EZX + Project No. : + Title : + File Name : + Description : + + ************** REVISION HISTORY ********************************************** + Date Author Reference + ======== ========== ========================== + 2002-07-01 weiqiang lin create +*/ +#ifndef SSP_PCAP_H +#define SSP_PCAP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SSP_vibrate_start_command() SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_EN); \ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_EN) + +#define SSP_vibrate_stop_command() SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_EN); \ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_EN) + +#define SSP_PCAP_REGISTER_VALUE_LENGTH 16 + +#define SSP_PCAP_REGISTER_WRITE_OP_BIT 0x80000000 +#define SSP_PCAP_REGISTER_READ_OP_BIT 0x00000000 + +#define SSP_PCAP_REGISTER_VALUE_UP_WORD_MASK 0xffff0000 +#define SSP_PCAP_REGISTER_VALUE_DOWN_WORD_MASK 0x0000ffff + +#define SSP_PCAP_REGISTER_VALUE_MASK 0x01ffffff +#define SSP_PCAP_REGISTER_VALUE_MASK 0x01ffffff +#define SSP_PCAP_REGISTER_ADDRESS_MASK 0x7c000000 +#define SSP_PCAP_REGISTER_ADDRESS_SHIFT 26 +#define SSP_PCAP_REGISTER_NUMBER 32 + +#define SSP_PCAP_ADC_START_VALUE_SET_MASK 0xfffffc00 +#define SSP_PCAP_ADC_START_VALUE 0x000001dd + + +#define SSP_PCAP_PHONE_CDC_CLOCK_MASK 0x000001c0 +#define SSP_PCAP_STEREO_SAMPLE_RATE_MASK 0x00000f00 +#define SSP_PCAP_STEREO_BCLK_TIME_SLOT_MASK 0x00018000 +#define SSP_PCAP_STEREO_CLOCK_MASK 0x0000001c +#define SSP_PCAP_DIGITAL_AUDIO_MODE_MASK 0x00006000 +#define SSP_PCAP_TOUCH_PANEL_POSITION_DETECT_MODE_MASK 0x000e0000 +#define SSP_PCAP_MONO_PGA_MASK 0x00180000 + +#define SSP_PCAP_VIBRATOR_VOLTAGE_LEVEL_MASK 0x00300000 + +#define SSP_PCAP_AUDIO_IN_GAIN_MASK 0x0000001f +#define SSP_PCAP_AUDIO_IN_GAIN_SHIFT 0 +#define SSP_PCAP_AUDIO_OUT_GAIN_MASK 0x0001e000 +#define SSP_PCAP_AUDIO_OUT_GAIN_SHIFT 13 + + +#define SSP_PCAP_ADD1_VALUE_MASK 0x000003ff +#define SSP_PCAP_ADD1_VALUE_SHIFT 0 +#define SSP_PCAP_ADD2_VALUE_MASK 0x000ffc00 +#define SSP_PCAP_ADD2_VALUE_SHIFT 10 + + +#define PCAP_AUDIO_IN_GAIN_MAX_VALUE 31 +#define PCAP_AUDIO_OUT_GAIN_MAX_VALUE 15 + +#define PCAP_CLEAR_INTERRUPT_REGISTER 0x00141fdf +#define PCAP_MASK_ALL_INTERRUPT 0x0013ffff + +#define SSP_PCAP_TS_KEEPER_TIMER 100 /* 1 second */ +#define START_ADC_DELAY_TIMER 1991 /* 540 us */ + +#define SSP_SEND_PM_ALART_INTERVAL 1000 *HZ/1000 /* 1 second */ +#define SSP_SEND_MSG_USB_ACCESSORY_INFO_DEBOUNCE 200 *HZ/1000 /* 200ms */ + +struct ssp_interrupt_info +{ + u32 type; + u32 status; + void* privdata; +}; + +#ifndef U8 +#define U8 unsigned char +#endif + +#ifndef U32 +#define U32 unsigned long +#endif + +#ifndef U16 +#define U16 unsigned short +#endif + +#ifndef P_U16 +#define P_U16 U16* +#endif + +#ifndef P_U32 +#define P_U32 U32* +#endif + +#define SSP_SELECT_BUFFER (volatile unsigned long *)(0xf4000000) + +#define SSP_SR_RNE 0x00000008 +#define SSP_PCAP_BASE 0x00001000 +/************************ STRUCTURES, ENUMS, AND TYPEDEFS **************************/ +typedef enum accessoryStatus +{ + ACCESSORY_DEVICE_STATUS_DETACHED = 0, + ACCESSORY_DEVICE_STATUS_ATTACHED , + ACCESSORY_DEVICE_STATUS_UNKNOW =0x000000ff +}ACCESSORY_DEVICE_STATUS; + +typedef enum accessoryType +{ + ACCESSORY_DEVICE_NONE = 0, + ACCESSORY_DEVICE_SERIAL_PORT , + ACCESSORY_DEVICE_USB_PORT , + ACCESSORY_DEVICE_UNKNOW =0x000000ff +}ACCESSORY_TYPE; + +typedef enum pcapReturnStatus +{ + SSP_PCAP_SUCCESS = 0, + SSP_PCAP_ERROR_REGISTER = SSP_PCAP_BASE+1, + SSP_PCAP_ERROR_VALUE = SSP_PCAP_BASE+2, + + SSP_PCAP_NOT_RUN = SSP_PCAP_BASE+0xff +}SSP_PCAP_STATUS; + +typedef enum pcapPortType +{ + SSP_PCAP_SERIAL_PORT = 0x00000000, + SSP_PCAP_LOW_USB_PORT = 0x00000001, + SSP_PCAP_HIGH_USB_PORT = 0x00000002, + SSP_PCAP_UNKNOW_PORT = 0x000000ff +}SSP_PCAP_PORT_TYPE; + +typedef enum pcapInitDriverType +{ + SSP_PCAP_TS_OPEN = 0x00000000, + SSP_PCAP_AUDIO_OPEN = 0x00000001, + SSP_PCAP_UNKNOW_DRIVER_OPEN = 0x000000ff +}SSP_PCAP_INIT_DRIVER_TYPE; + + +typedef enum pcapReturnBitStatus +{ + SSP_PCAP_BIT_ZERO = 0x00000000, + SSP_PCAP_BIT_ONE = 0x00000001, + SSP_PCAP_BIT_ERROR = 0xff000000 +}SSP_PCAP_BIT_STATUS; + +typedef enum pcapCDCClkType +{ + PCAP_CDC_CLK_IN_13M0 = 0x00000000, + PCAP_CDC_CLK_IN_15M36 = 0x00000040, + PCAP_CDC_CLK_IN_16M8 = 0x00000080, + PCAP_CDC_CLK_IN_19M44 = 0x000000c0, + PCAP_CDC_CLK_IN_26M0 = 0x00000100 +}PHONE_CDC_CLOCK_TYPE; + +typedef enum pcapST_SR +{ + PCAP_ST_SAMPLE_RATE_8K = 0x00000000, + PCAP_ST_SAMPLE_RATE_11K = 0x00000100, + PCAP_ST_SAMPLE_RATE_12K = 0x00000200, + PCAP_ST_SAMPLE_RATE_16K = 0x00000300, + PCAP_ST_SAMPLE_RATE_22K = 0x00000400, + PCAP_ST_SAMPLE_RATE_24K = 0x00000500, + PCAP_ST_SAMPLE_RATE_32K = 0x00000600, + PCAP_ST_SAMPLE_RATE_44K = 0x00000700, + PCAP_ST_SAMPLE_RATE_48K = 0x00000800 +}ST_SAMPLE_RATE_TYPE; + +typedef enum pcapST_BCLK +{ + PCAP_ST_BCLK_SLOT_16 = 0x00000000, + PCAP_ST_BCLK_SLOT_8 = 0x00008000, + PCAP_ST_BCLK_SLOT_4 = 0x00010000, + PCAP_ST_BCLK_SLOT_2 = 0x00018000, +}ST_BCLK_TIME_SLOT_TYPE; + +typedef enum pcapST_CLK +{ + PCAP_ST_CLK_PLL_CLK_IN_13M0 = 0x00000000, + PCAP_ST_CLK_PLL_CLK_IN_15M36 = 0x00000004, + PCAP_ST_CLK_PLL_CLK_IN_16M8 = 0x00000008, + PCAP_ST_CLK_PLL_CLK_IN_19M44 = 0x0000000c, + PCAP_ST_CLK_PLL_CLK_IN_26M0 = 0x00000010, + PCAP_ST_CLK_PLL_CLK_IN_EXT_MCLK = 0x00000014, + PCAP_ST_CLK_PLL_CLK_IN_FSYNC = 0x00000018, + PCAP_ST_CLK_PLL_CLK_IN_BITCLK = 0x0000001c +}ST_CLK_TYPE; + +typedef enum pcapDigitalAudioInterfaceMode +{ + PCAP_DIGITAL_AUDIO_INTERFACE_NORMAL = 0x00000000, + PCAP_DIGITAL_AUDIO_INTERFACE_NETWORK = 0x00002000, + PCAP_DIGITAL_AUDIO_INTERFACE_I2S = 0x00004000 +}DIG_AUD_MODE_TYPE; + +typedef enum pcapMono +{ + PCAP_MONO_PGA_R_L_STEREO = 0x00000000, + PCAP_MONO_PGA_RL = 0x00080000, + PCAP_MONO_PGA_RL_3DB = 0x00100000, + PCAP_MONO_PGA_RL_6DB = 0x00180000 +}MONO_TYPE; + +typedef enum pcapVibratorVoltageLevel +{ + PCAP_VIBRATOR_VOLTAGE_LEVEL0 = 0x00000000, + PCAP_VIBRATOR_VOLTAGE_LEVEL1 = 0x00100000, + PCAP_VIBRATOR_VOLTAGE_LEVEL2 = 0x00200000, + PCAP_VIBRATOR_VOLTAGE_LEVEL3 = 0x00300000 +}VibratorVoltageLevel_TYPE; + +typedef enum pcapTouchScreenMode +{ + PCAP_TS_POSITION_X_MEASUREMENT = 0x00000000, + PCAP_TS_POSITION_XY_MEASUREMENT = 0x00020000, + PCAP_TS_PRESSURE_MEASUREMENT = 0x00040000, + PCAP_TS_PLATE_X_MEASUREMENT = 0x00060000, + PCAP_TS_PLATE_Y_MEASUREMENT = 0x00080000, + PCAP_TS_STANDBY_MODE = 0x000a0000, + PCAP_TS_NONTS_MODE = 0x000c0000 +}TOUCH_SCREEN_DETECT_TYPE; + +typedef enum pcapADJRegister +{ + SSP_PCAP_ADJ_ISR_REGISTER = 0x00, + SSP_PCAP_ADJ_MSR_REGISTER = 0x01, + SSP_PCAP_ADJ_PSTAT_REGISTER = 0x02, + SSP_PCAP_ADJ_VREG2_REGISTER = 0x06, + SSP_PCAP_ADJ_AUX_VREG_REGISTER = 0x07, + SSP_PCAP_ADJ_BATT_DAC_REGISTER = 0x08, + SSP_PCAP_ADJ_ADC1_REGISTER = 0x09, + SSP_PCAP_ADJ_ADC2_REGISTER = 0x0a, + SSP_PCAP_ADJ_AUD_CODEC_REGISTER = 0x0b, + SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER = 0x0c, + SSP_PCAP_ADJ_ST_DAC_REGISTER = 0x0d, + SSP_PCAP_ADJ_BUSCTRL_REGISTER = 0x14, + SSP_PCAP_ADJ_PERIPH_REGISTER = 0x15, + SSP_PCAP_ADJ_LOWPWR_CTRL_REGISTER = 0x18, + SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER = 0x1a, + SSP_PCAP_ADJ_GP_REG_REGISTER = 0x1b +}SSP_PCAP_SECONDARY_PROCESSOR_REGISTER; + +typedef enum pcapADJBit_SetType +{ + SSP_PCAP_ADJ_BIT_ISR_ADCDONEI = 0x00000001, + SSP_PCAP_ADJ_BIT_ISR_TSI = 0x00000002, + SSP_PCAP_ADJ_BIT_ISR_1HZI = 0x00000004, + SSP_PCAP_ADJ_BIT_ISR_WHI = 0x00000008, + SSP_PCAP_ADJ_BIT_ISR_WLI = 0x00000010, + SSP_PCAP_ADJ_BIT_ISR_TODAI = 0x00000020, + SSP_PCAP_ADJ_BIT_ISR_USB4VI = 0x00000040, + SSP_PCAP_ADJ_BIT_ISR_ONOFFI = 0x00000080, + SSP_PCAP_ADJ_BIT_ISR_ONOFF2I = 0x00000100, + SSP_PCAP_ADJ_BIT_ISR_USB1VI = 0x00000200, + SSP_PCAP_ADJ_BIT_ISR_MOBPORTI = 0x00000400, + SSP_PCAP_ADJ_BIT_ISR_MB2I = 0x00000800, + SSP_PCAP_ADJ_BIT_ISR_A1I = 0x00001000, + SSP_PCAP_ADJ_BIT_ISR_STI = 0x00002000, + SSP_PCAP_ADJ_BIT_ISR_PCI = 0x00004000, + SSP_PCAP_ADJ_BIT_ISR_WARMI = 0x00008000, + SSP_PCAP_ADJ_BIT_ISR_EOLI = 0x00010000, + SSP_PCAP_ADJ_BIT_ISR_CLKI = 0x00020000, + SSP_PCAP_ADJ_BIT_ISR_SYS_RSTI = 0x00040000, + SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I = 0x00100000, + SSP_PCAP_ADJ_BIT_ISR_SOFT_RESETI = 0x00200000, + SSP_PCAP_ADJ_BIT_ISR_MNEXBI = 0x00400000, + + SSP_PCAP_ADJ_BIT_MSR_ADCDONEM = 0x04000001, + SSP_PCAP_ADJ_BIT_MSR_TSM = 0x04000002, + SSP_PCAP_ADJ_BIT_MSR_1HZM = 0x04000004, + SSP_PCAP_ADJ_BIT_MSR_WHM = 0x04000008, + SSP_PCAP_ADJ_BIT_MSR_WLM = 0x04000010, + SSP_PCAP_ADJ_BIT_MSR_TODAM = 0x04000020, + SSP_PCAP_ADJ_BIT_MSR_USB4VM = 0x04000040, + SSP_PCAP_ADJ_BIT_MSR_ONOFFM = 0x04000080, + SSP_PCAP_ADJ_BIT_MSR_ONOFF2M = 0x04000100, + SSP_PCAP_ADJ_BIT_MSR_USB1VM = 0x04000200, + SSP_PCAP_ADJ_BIT_MSR_MOBPORTM = 0x04000400, + SSP_PCAP_ADJ_BIT_MSR_MB2M = 0x04000800, + SSP_PCAP_ADJ_BIT_MSR_A1M = 0x04001000, + SSP_PCAP_ADJ_BIT_MSR_STM = 0x04002000, + SSP_PCAP_ADJ_BIT_MSR_PCM = 0x04004000, + SSP_PCAP_ADJ_BIT_MSR_WARMM = 0x04008000, + SSP_PCAP_ADJ_BIT_MSR_EOLM = 0x04010000, + SSP_PCAP_ADJ_BIT_MSR_CLKM = 0x04020000, + SSP_PCAP_ADJ_BIT_MSR_SYS_RSTM = 0x04040000, + SSP_PCAP_ADJ_BIT_MSR_ADCDONE2M = 0x04100000, + SSP_PCAP_ADJ_BIT_MSR_SOFT_RESETM = 0x04200000, + SSP_PCAP_ADJ_BIT_MSR_MNEXBM = 0x04400000, + + SSP_PCAP_ADJ_BIT_PSTAT_USBDET_4V = 0x08000040, + SSP_PCAP_ADJ_BIT_PSTAT_ONOFFSNS = 0x08000080, + SSP_PCAP_ADJ_BIT_PSTAT_ONOFFSNS2 = 0x08000100, + SSP_PCAP_ADJ_BIT_PSTAT_USBDET_1V = 0x08000200, + SSP_PCAP_ADJ_BIT_PSTAT_MOBSENSB = 0x08000400, + SSP_PCAP_ADJ_BIT_PSTAT_MB2SNS = 0x08000800, + SSP_PCAP_ADJ_BIT_PSTAT_A1SNS = 0x08001000, + SSP_PCAP_ADJ_BIT_PSTAT_MSTB = 0x08002000, + SSP_PCAP_ADJ_BIT_PSTAT_EOL_STAT = 0x08010000, + SSP_PCAP_ADJ_BIT_PSTAT_CLK_STAT = 0x08020000, + SSP_PCAP_ADJ_BIT_PSTAT_SYS_RST = 0x08040000, + SSP_PCAP_ADJ_BIT_PSTAT_BATTFBSNS = 0x08080000, + SSP_PCAP_ADJ_BIT_PSTAT_BATT_DET_IN_SNS = 0x08200000, + SSP_PCAP_ADJ_BIT_PSTAT_MNEXBSNS = 0x08400000, + SSP_PCAP_ADJ_BIT_PSTAT_WARM_SYS_RST = 0x08800000, + + SSP_PCAP_ADJ_BIT_VREG2_V1_STBY = 0x18000001, + SSP_PCAP_ADJ_BIT_VREG2_V2_STBY = 0x18000002, + SSP_PCAP_ADJ_BIT_VREG2_V3_STBY = 0x18000004, + SSP_PCAP_ADJ_BIT_VREG2_V4_STBY = 0x18000008, + SSP_PCAP_ADJ_BIT_VREG2_V5_STBY = 0x18000010, + SSP_PCAP_ADJ_BIT_VREG2_V6_STBY = 0x18000020, + SSP_PCAP_ADJ_BIT_VREG2_V7_STBY = 0x18000040, + SSP_PCAP_ADJ_BIT_VREG2_V8_STBY = 0x18000080, + SSP_PCAP_ADJ_BIT_VREG2_V9_STBY = 0x18000100, + SSP_PCAP_ADJ_BIT_VREG2_V10_STBY = 0x18000200, + SSP_PCAP_ADJ_BIT_VREG2_V1_LOWPWR = 0x18000400, + SSP_PCAP_ADJ_BIT_VREG2_V2_LOWPWR = 0x18000800, + SSP_PCAP_ADJ_BIT_VREG2_V3_LOWPWR = 0x18001000, + SSP_PCAP_ADJ_BIT_VREG2_V4_LOWPWR = 0x18002000, + SSP_PCAP_ADJ_BIT_VREG2_V5_LOWPWR = 0x18004000, + SSP_PCAP_ADJ_BIT_VREG2_V6_LOWPWR = 0x18008000, + SSP_PCAP_ADJ_BIT_VREG2_V7_LOWPWR = 0x18010000, + SSP_PCAP_ADJ_BIT_VREG2_V8_LOWPWR = 0x18020000, + SSP_PCAP_ADJ_BIT_VREG2_V9_LOWPWR = 0x18040000, + SSP_PCAP_ADJ_BIT_VREG2_V10_LOWPWR = 0x18080000, + + SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX1_EN = 0x1c000002, + SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX1_0 = 0x1c000004, + SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX1_1 = 0x1c000008, + SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN = 0x1c000010, + SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_0 = 0x1c000020, + SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_1 = 0x1c000040, + SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_EN = 0x1c000080, + SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_0 = 0x1c000100, + SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_1 = 0x1c000200, + SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_2 = 0x1c000400, + SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX3_3 = 0x1c000800, + SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX4_EN = 0x1c001000, + SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX4_0 = 0x1c002000, + SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX4_1 = 0x1c004000, + SSP_PCAP_ADJ_BIT_AUX_VREG_VSIM2_EN = 0x1c010000, + SSP_PCAP_ADJ_BIT_AUX_VREG_VSIM_EN = 0x1c020000, + SSP_PCAP_ADJ_BIT_AUX_VREG_VSIM_0 = 0x1c040000, + SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_EN = 0x1c080000, + SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_0 = 0x1c100000, + SSP_PCAP_ADJ_BIT_AUX_VREG_V_VIB_1 = 0x1c200000, + SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX1_STBY = 0x1c400000, + SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX1_LOWPWR = 0x1c800000, + SSP_PCAP_ADJ_BIT_AUX_VREG_SW3_STBY = 0x1d000000, + + SSP_PCAP_ADJ_BIT_BATT_DAC_DAC0 = 0x20000001, + SSP_PCAP_ADJ_BIT_BATT_DAC_DAC1 = 0x20000002, + SSP_PCAP_ADJ_BIT_BATT_DAC_DAC2 = 0x20000004, + SSP_PCAP_ADJ_BIT_BATT_DAC_DAC3 = 0x20000008, + SSP_PCAP_ADJ_BIT_BATT_DAC_DAC4 = 0x20000010, + SSP_PCAP_ADJ_BIT_BATT_DAC_DAC5 = 0x20000020, + SSP_PCAP_ADJ_BIT_BATT_DAC_DAC6 = 0x20000040, + SSP_PCAP_ADJ_BIT_BATT_DAC_DAC7 = 0x20000080, + SSP_PCAP_ADJ_BIT_BATT_DAC_B_FDBK = 0x20000100, + SSP_PCAP_ADJ_BIT_BATT_DAC_EXT_ISENSE = 0x20000200, + SSP_PCAP_ADJ_BIT_BATT_DAC_V_COIN0 = 0x20000400, + SSP_PCAP_ADJ_BIT_BATT_DAC_V_COIN1 = 0x20000800, + SSP_PCAP_ADJ_BIT_BATT_DAC_V_COIN2 = 0x20001000, + SSP_PCAP_ADJ_BIT_BATT_DAC_V_COIN3 = 0x20002000, + SSP_PCAP_ADJ_BIT_BATT_DAC_I_COIN = 0x20004000, + SSP_PCAP_ADJ_BIT_BATT_DAC_COIN_CH_EN = 0x20008000, + SSP_PCAP_ADJ_BIT_BATT_DAC_EOL_SEL0 = 0x20020000, + SSP_PCAP_ADJ_BIT_BATT_DAC_EOL_SEL1 = 0x20040000, + SSP_PCAP_ADJ_BIT_BATT_DAC_EOL_SEL2 = 0x20080000, + SSP_PCAP_ADJ_BIT_BATT_DAC_EOL_CMP_EN = 0x20100000, + SSP_PCAP_ADJ_BIT_BATT_DAC_BATT_DET_EN = 0x20200000, + SSP_PCAP_ADJ_BIT_BATT_DAC_THERMBIAS_CTRL = 0x20400000, + + SSP_PCAP_ADJ_BIT_ADC1_ADEN = 0x24000001, + SSP_PCAP_ADJ_BIT_ADC1_RAND = 0x24000002, + SSP_PCAP_ADJ_BIT_ADC1_AD_SEL1 = 0x24000004, + SSP_PCAP_ADJ_BIT_ADC1_AD_SEL2 = 0x24000008, + SSP_PCAP_ADJ_BIT_ADC1_ADA10 = 0x24000010, + SSP_PCAP_ADJ_BIT_ADC1_ADA11 = 0x24000020, + SSP_PCAP_ADJ_BIT_ADC1_ADA12 = 0x24000040, + SSP_PCAP_ADJ_BIT_ADC1_ADA20 = 0x24000080, + SSP_PCAP_ADJ_BIT_ADC1_ADA21 = 0x24000100, + SSP_PCAP_ADJ_BIT_ADC1_ADA22 = 0x24000200, + SSP_PCAP_ADJ_BIT_ADC1_ATO0 = 0x24000400, + SSP_PCAP_ADJ_BIT_ADC1_ATO1 = 0x24000800, + SSP_PCAP_ADJ_BIT_ADC1_ATO2 = 0x24001000, + SSP_PCAP_ADJ_BIT_ADC1_ATO3 = 0x24002000, + SSP_PCAP_ADJ_BIT_ADC1_ATOX = 0x24004000, + SSP_PCAP_ADJ_BIT_ADC1_MTR1 = 0x24008000, + SSP_PCAP_ADJ_BIT_ADC1_MTR2 = 0x24010000, + SSP_PCAP_ADJ_BIT_ADC1_TS_M0 = 0x24020000, + SSP_PCAP_ADJ_BIT_ADC1_TS_M1 = 0x24040000, + SSP_PCAP_ADJ_BIT_ADC1_TS_M2 = 0x24080000, + SSP_PCAP_ADJ_BIT_ADC1_TS_REF_LOWPWR = 0x24100000, + SSP_PCAP_ADJ_BIT_ADC1_TS_REFENB = 0x24200000, + SSP_PCAP_ADJ_BIT_ADC1_BATT_I_POLARITY = 0x24400000, + SSP_PCAP_ADJ_BIT_ADC1_BATT_I_ADC = 0x24800000, + + SSP_PCAP_ADJ_BIT_ADC2_ADD10 = 0x28000001, + SSP_PCAP_ADJ_BIT_ADC2_ADD11 = 0x28000002, + SSP_PCAP_ADJ_BIT_ADC2_ADD12 = 0x28000004, + SSP_PCAP_ADJ_BIT_ADC2_ADD13 = 0x28000008, + SSP_PCAP_ADJ_BIT_ADC2_ADD14 = 0x28000010, + SSP_PCAP_ADJ_BIT_ADC2_ADD15 = 0x28000020, + SSP_PCAP_ADJ_BIT_ADC2_ADD16 = 0x28000040, + SSP_PCAP_ADJ_BIT_ADC2_ADD17 = 0x28000080, + SSP_PCAP_ADJ_BIT_ADC2_ADD18 = 0x28000100, + SSP_PCAP_ADJ_BIT_ADC2_ADD19 = 0x28000200, + SSP_PCAP_ADJ_BIT_ADC2_ADD20 = 0x28000400, + SSP_PCAP_ADJ_BIT_ADC2_ADD21 = 0x28000800, + SSP_PCAP_ADJ_BIT_ADC2_ADD22 = 0x28001000, + SSP_PCAP_ADJ_BIT_ADC2_ADD23 = 0x28002000, + SSP_PCAP_ADJ_BIT_ADC2_ADD24 = 0x28004000, + SSP_PCAP_ADJ_BIT_ADC2_ADD25 = 0x28008000, + SSP_PCAP_ADJ_BIT_ADC2_ADD26 = 0x28010000, + SSP_PCAP_ADJ_BIT_ADC2_ADD27 = 0x28020000, + SSP_PCAP_ADJ_BIT_ADC2_ADD28 = 0x28040000, + SSP_PCAP_ADJ_BIT_ADC2_ADD29 = 0x28080000, + SSP_PCAP_ADJ_BIT_ADC2_ADINC1 = 0x28100000, + SSP_PCAP_ADJ_BIT_ADC2_ADINC2 = 0x28200000, + SSP_PCAP_ADJ_BIT_ADC2_ASC = 0x28400000, + + SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDIHPF = 0x2c000001, + SSP_PCAP_ADJ_BIT_AUD_CODEC_SMB = 0x2c000002, + SSP_PCAP_ADJ_BIT_AUD_CODEC_AUDOHPF = 0x2c000004, + SSP_PCAP_ADJ_BIT_AUD_CODEC_CD_TS = 0x2c000008, + SSP_PCAP_ADJ_BIT_AUD_CODEC_DLM = 0x2c000010, + SSP_PCAP_ADJ_BIT_AUD_CODEC_ADITH = 0x2c000020, + SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK0 = 0x2c000040, + SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK1 = 0x2c000080, + SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK2 = 0x2c000100, + SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_INV = 0x2c000200, + SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_INV = 0x2c000400, + SSP_PCAP_ADJ_BIT_AUD_CODEC_DF_RESET = 0x2c000800, + SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_EN = 0x2c001000, + SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_CLK_EN = 0x2c002000, + SSP_PCAP_ADJ_BIT_AUD_CODEC_FS_8K_16K = 0x2c004000, + SSP_PCAP_ADJ_BIT_AUD_CODEC_DIG_AUD_IN = 0x2c008000, + SSP_PCAP_ADJ_BIT_AUD_CODEC_CLK_IN_SEL = 0x2c010000, + SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2_MUX = 0x2c020000, + SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG0 = 0x2c040000, + SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG1 = 0x2c080000, + SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG2 = 0x2c100000, + SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG3 = 0x2c200000, + SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG4 = 0x2c400000, + SSP_PCAP_ADJ_BIT_AUD_CODEC_MIC2IG_PRI_ADJ = 0x2c800000, + SSP_PCAP_ADJ_BIT_AUD_CODEC_CDC_PRI_ADJ = 0x2c200000, + + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1_EN = 0x30000001, + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A2_EN = 0x30000002, + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A4_EN = 0x30000010, + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ARIGHT_EN = 0x30000020, + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ALEFT_EN = 0x30000040, + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CD_BYP = 0x30000080, + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_CDC_SW = 0x30000100, + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_ST_DAC_SW = 0x30000200, + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW = 0x30000400, + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_R_EN = 0x30000800, + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_L_EN = 0x30001000, + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_AUDOG0 = 0x30002000, + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_AUDOG1 = 0x30004000, + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_AUDOG2 = 0x30008000, + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_AUDOG3 = 0x30010000, + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_A1CTRL = 0x30020000, + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_MONO0 = 0x30080000, + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_MONO1 = 0x30100000, + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_AUDOG_PRI_ADJ = 0x30200000, + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_MONO_PRI_ADJ = 0x30400000, + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_RX_PRI_ADJ0 = 0x30800000, + SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_RX_PRI_ADJ1 = 0x31000000, + + SSP_PCAP_ADJ_BIT_ST_DAC_SMB_ST_DAC = 0x34000001, + SSP_PCAP_ADJ_BIT_ST_DAC_STDET_EN = 0x34000002, + SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK0 = 0x34000004, + SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK1 = 0x34000008, + SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK2 = 0x34000010, + SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_EN = 0x34000020, + SSP_PCAP_ADJ_BIT_ST_DAC_DF_RESET_ST_DAC = 0x34000040, + SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_EN = 0x34000080, + SSP_PCAP_ADJ_BIT_ST_DAC_SR0 = 0x34000100, + SSP_PCAP_ADJ_BIT_ST_DAC_SR1 = 0x34000200, + SSP_PCAP_ADJ_BIT_ST_DAC_SR2 = 0x34000400, + SSP_PCAP_ADJ_BIT_ST_DAC_SR3 = 0x34000800, + SSP_PCAP_ADJ_BIT_ST_DAC_DIG_AUD_IN_ST_DAC = 0x34001000, + SSP_PCAP_ADJ_BIT_ST_DAC_DIG_AUD_FS0 = 0x34002000, + SSP_PCAP_ADJ_BIT_ST_DAC_DIG_AUD_FS1 = 0x34004000, + SSP_PCAP_ADJ_BIT_ST_DAC_BCLK0 = 0x34008000, + SSP_PCAP_ADJ_BIT_ST_DAC_BCLK1 = 0x34010000, + SSP_PCAP_ADJ_BIT_ST_DAC_ST_CLK_INV = 0x34020000, + SSP_PCAP_ADJ_BIT_ST_DAC_ST_FS_INV = 0x34040000, + SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_CLK_IN_SEL = 0x34080000, + SSP_PCAP_ADJ_BIT_ST_DAC_ST_DAC_PRI_ADJ = 0x35000000, + + SSP_PCAP_ADJ_BIT_BUSCTRL_FSENB = 0x50000001, + SSP_PCAP_ADJ_BIT_BUSCTRL_USB_SUSPEND = 0x50000002, + SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PU = 0x50000004, + SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PD = 0x50000008, + SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN = 0x50000010, + SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PS = 0x50000020, + SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_MSTR_EN = 0x50000040, + SSP_PCAP_ADJ_BIT_BUSCTRL_VBUS_PD_ENB = 0x50000080, + SSP_PCAP_ADJ_BIT_BUSCTRL_CURRLIM = 0x50000100, + SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB = 0x50000200, + SSP_PCAP_ADJ_BIT_BUSCTRL_RS232_DIR = 0x50000400, + SSP_PCAP_ADJ_BIT_BUSCTRL_SE0_CONN = 0x50000800, + SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PDM = 0x50001000, + SSP_PCAP_ADJ_BIT_BUSCTRL_BUS_PRI_ADJ = 0x51000000, + + SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL0 = 0x54000001, + SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL1 = 0x54000002, + SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL2 = 0x54000004, + SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL3 = 0x54000008, + SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL4 = 0x54000010, + SSP_PCAP_ADJ_BIT_PERIPH_LEDR_EN = 0x54000020, + SSP_PCAP_ADJ_BIT_PERIPH_LEDG_EN = 0x54000040, + SSP_PCAP_ADJ_BIT_PERIPH_LEDR_CTRL0 = 0x54000080, + SSP_PCAP_ADJ_BIT_PERIPH_LEDR_CTRL1 = 0x54000100, + SSP_PCAP_ADJ_BIT_PERIPH_LEDR_CTRL2 = 0x54000200, + SSP_PCAP_ADJ_BIT_PERIPH_LEDR_CTRL3 = 0x54000400, + SSP_PCAP_ADJ_BIT_PERIPH_LEDG_CTRL0 = 0x54000800, + SSP_PCAP_ADJ_BIT_PERIPH_LEDG_CTRL1 = 0x54001000, + SSP_PCAP_ADJ_BIT_PERIPH_LEDG_CTRL2 = 0x54002000, + SSP_PCAP_ADJ_BIT_PERIPH_LEDG_CTRL3 = 0x54004000, + SSP_PCAP_ADJ_BIT_PERIPH_LEDR_I0 = 0x54008000, + SSP_PCAP_ADJ_BIT_PERIPH_LEDR_I1 = 0x54010000, + SSP_PCAP_ADJ_BIT_PERIPH_LEDG_I0 = 0x54020000, + SSP_PCAP_ADJ_BIT_PERIPH_LEDG_I1 = 0x54040000, + SSP_PCAP_ADJ_BIT_PERIPH_SKIP = 0x54080000, + SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL0 = 0x54100000, + SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL1 = 0x54200000, + SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL2 = 0x54400000, + SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL3 = 0x54800000, + SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL4 = 0x55000000, + + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX2_STBY = 0x60000001, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX2_LOWPWR = 0x60000002, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX3_STBY = 0x60000004, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX3_LOWPWR = 0x60000008, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX4_STBY = 0x60000010, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VAUX4_LOWPWR = 0x60000020, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VSIM_LOWPWR = 0x60000040, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VSIM2_LOWPWR = 0x60000080, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE00 = 0x60000100, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE01 = 0x60000200, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE10 = 0x60000400, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW1_MODE11 = 0x60000800, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW10_DVS = 0x60001000, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW11_DVS = 0x60002000, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW12_DVS = 0x60004000, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW13_DVS = 0x60008000, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW2_MODE00 = 0x60010000, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW2_MODE01 = 0x60020000, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW2_MODE10 = 0x60040000, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW2_MODE11 = 0x60080000, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW20_DVS = 0x60100000, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW21_DVS = 0x60200000, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW22_DVS = 0x60400000, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_SW23_DVS = 0x60800000, + SSP_PCAP_ADJ_BIT_LOWPWR_CTRL_VC_STBY = 0x61000000, + + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG0 = 0x68000001, + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG1 = 0x68000002, + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG2 = 0x68000004, + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG3 = 0x68000008, + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG4 = 0x68000010, + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_EN = 0x68000020, + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A3_MUX = 0x68000040, + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_EN = 0x68000080, + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A5_MUX = 0x68000100, + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_EXT_MIC_MUX = 0x68000200, + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON2 = 0x68000400, + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_MB_ON1 = 0x68000800, + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A1ID_TX = 0x68001000, + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A1_CONFIG = 0x68002000, + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AHS_CONFIG = 0x68004000, + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_A2_CONFIG = 0x68008000, + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_LOWPWR = 0x68080000, + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIO_STBY = 0x68100000, + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_V2_EN_2 = 0x68200000, + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_AUDIG_PRI_ADJ = 0x68400000, + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_TX_PRI_ADJ0 = 0x68800000, + SSP_PCAP_ADJ_BIT_TX_AUD_AMPS_TX_PRI_ADJ1 = 0x69000000, + + SSP_PCAP_ADJ_BIT_SYS_RST_CLR = 0x6c000001, + SSP_PCAP_ADJ_BIT_SYS_RST_MODE0 = 0x6c000002, + SSP_PCAP_ADJ_BIT_SYS_RST_MODE1 = 0x6c000004, + SSP_PCAP_ADJ_BIT_SYS_VFLASH_0 = 0x6c000008, + SSP_PCAP_ADJ_BIT_SYS_VFLASH_1 = 0x6c000010, + SSP_PCAP_ADJ_BIT_SYS_MID_SELECT = 0x6c000020, + SSP_PCAP_ADJ_BIT_SYS_MID_FET = 0x6c000040, + SSP_PCAP_ADJ_BIT_SYS_MAIN_LOW = 0x6c000080, + SSP_PCAP_ADJ_BIT_SYS_BATTFB_DIS = 0x6c000100, + SSP_PCAP_ADJ_BIT_SYS_GP_REG9 = 0x6c000200, + SSP_PCAP_ADJ_BIT_SYS_GP_REG10 = 0x6c000400, + SSP_PCAP_ADJ_BIT_SYS_GP_REG11 = 0x6c000800, + SSP_PCAP_ADJ_BIT_SYS_GP_REG12 = 0x6c001000, + SSP_PCAP_ADJ_BIT_SYS_GP_REG13 = 0x6c002000, + SSP_PCAP_ADJ_BIT_SYS_GP_REG14 = 0x6c004000, + SSP_PCAP_ADJ_BIT_SYS_GP_REG15 = 0x6c008000, + SSP_PCAP_ADJ_BIT_SYS_GP_REG16 = 0x6c010000, + SSP_PCAP_ADJ_BIT_SYS_GP_REG17 = 0x6c020000, + SSP_PCAP_ADJ_BIT_SYS_GP_REG18 = 0x6c040000, + SSP_PCAP_ADJ_BIT_SYS_GP_REG19 = 0x6c080000, + SSP_PCAP_ADJ_BIT_SYS_GP_REG20 = 0x6c100000, + SSP_PCAP_ADJ_BIT_SYS_GP_REG21 = 0x6c200000, + SSP_PCAP_ADJ_BIT_SYS_GP_REG22 = 0x6c400000, + SSP_PCAP_ADJ_BIT_SYS_GP_REG23 = 0x6c800000, + SSP_PCAP_ADJ_BIT_SYS_GP_REG24 = 0x6d000000 + +}SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE; + +/************************ FUNCTION PROTOTYPES **************************************/ +extern void ssp_pcap_init(void); +extern void ssp_pcap_release(void); + +extern void ssp_pcap_open(SSP_PCAP_INIT_DRIVER_TYPE portType); +extern void ssp_pcap_close(void); + +extern void ssp_pcap_intoSleep_callBack(void); +extern void ssp_pcap_wakeUp_callBack(void); + + +extern SSP_PCAP_STATUS SSP_PCAP_write_data_to_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER ssp_pcap_register,U32 ssp_pcap_register_value); +extern SSP_PCAP_STATUS SSP_PCAP_read_data_from_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER ssp_pcap_register,P_U32 p_ssp_pcap_register_value); + +extern SSP_PCAP_STATUS SSP_PCAP_bit_set(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; +extern SSP_PCAP_STATUS SSP_PCAP_bit_clean(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; +extern SSP_PCAP_BIT_STATUS SSP_PCAP_get_bit_from_buffer(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; +extern SSP_PCAP_BIT_STATUS SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; +extern U32 SSP_PCAP_get_register_value_from_buffer(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER ssp_pcap_register ) ; + +extern SSP_PCAP_STATUS SSP_PCAP_TSI_mode_set(TOUCH_SCREEN_DETECT_TYPE mode_Type ); +extern SSP_PCAP_STATUS SSP_PCAP_TSI_start_XY_read(void); +extern SSP_PCAP_STATUS SSP_PCAP_TSI_get_XY_value(P_U16 p_x,P_U16 p_y); +extern SSP_PCAP_STATUS SSP_PCAP_CDC_CLK_set(PHONE_CDC_CLOCK_TYPE clkType); + +extern SSP_PCAP_STATUS SSP_PCAP_CDC_SR_set(ST_SAMPLE_RATE_TYPE srType); +extern SSP_PCAP_STATUS SSP_PCAP_BCLK_set(ST_BCLK_TIME_SLOT_TYPE bclkType); +extern SSP_PCAP_STATUS SSP_PCAP_STCLK_set(ST_CLK_TYPE stClkType); +extern SSP_PCAP_STATUS SSP_PCAP_DIG_AUD_FS_set(DIG_AUD_MODE_TYPE fsType); +extern SSP_PCAP_STATUS SSP_PCAP_AUDIG_set(U32 audioInGain); +extern SSP_PCAP_STATUS SSP_PCAP_MONO_set(MONO_TYPE monoType); +extern SSP_PCAP_STATUS SSP_PCAP_AUDOG_set(U32 audioOutGain); + +extern SSP_PCAP_STATUS SSP_PCAP_V_VIB_level_set(VibratorVoltageLevel_TYPE VIBLevelType); +extern SSP_PCAP_STATUS SSP_PCAP_configure_USB_UART_transeiver(SSP_PCAP_PORT_TYPE portType); +extern SSP_PCAP_BIT_STATUS SSP_PCAP_get_audio_in_status(void); + +/* for log */ +extern void pcap_log_add_pure_data(u8* pData,u32 len); +extern void pcap_log_add_data(u8* pData,u32 len); + +/* screen lock on/off handler */ +extern void ssp_pcap_screenlock_lock(u32 data); +extern void ssp_pcap_screenlock_unlock(u32 data); + +#ifdef __cplusplus +} +#endif + +#endif Index: linux-2.6.16.5-a/drivers/misc/ezx/ssp_pcap_main.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/misc/ezx/ssp_pcap_main.c 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,2568 @@ +/* (c) Copyright Motorola 2002, All rights reserved. + Motorola Confidential Proprietary + Contains confidential proprietary information of Motorola, Inc. + Reverse engineering is prohibited. + The copyright notice does not imply publication. + + Project Name : EZX + Project No. : + Title : + File Name : + Description : + + ************** REVISION HISTORY ********************************************** + Date Author Reference + ======== ========== ========================== + 2002-07-02 weiqiang lin create + 2004-02-09 weiqiang lin update PM for Bulverde OS libdd74345. + 2004-04-13 weiqiang lin update accessory usb attach and detach + 2004-04-27 weiqiang lin send the USB accessory detach/attach information to PM + 2004-05-11 weiqiang lin after sleep TC_MM_EN will be high else will be low + 2004-06-24 Cheng Xuefeng remove the SSP_PCAP_configure_USB_UART_transeiver() + 2004-08-19 weiqiang lin after sleep set SW1 output 1.3V and low power mode and when headset button press/release, send an event to PM + 2004-08-31 weiqiang lin remove the headset button press/release event to PM. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#include "ssp_pcap.h" +//#define SSP_PCAP_OPERATE_WITH_SPI + +static u32 ssp_pcap_operate_pin_with_inverter; +static u32 ssp_pcap_rxd_pin_with_inverter; +//#define SSP_PCAP_OPERATE_DEBUG_INFORNMATION + +#ifdef _DEBUG_BOARD +#define SSP_PCAP_DEBUG_BOARD +#endif + +/* 0 -- unlock 1- lock */ +static u32 ssp_pcap_screenlock_status; +static struct timer_list ssp_pcap_screenlock_timer; +static void ssp_pcap_screenlock_lockhandler(u32 data); + +static struct timer_list ssp_start_adc_timer; +static struct timer_list ssp_tsi_timer; +static struct timer_list ssp_usb_accessory_debounce_timer; + +static U32 ssp_pcap_status = 0; +static U32 ssp_pcap_registerValue[SSP_PCAP_REGISTER_NUMBER] = {0}; + +SSP_PCAP_BIT_STATUS SSP_PCAP_get_audio_in_status(void); +SSP_PCAP_STATUS SSP_PCAP_write_data_to_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER ssp_pcap_register,U32 ssp_pcap_register_value); +SSP_PCAP_STATUS SSP_PCAP_read_data_from_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER ssp_pcap_register,P_U32 p_ssp_pcap_register_value); + +SSP_PCAP_STATUS SSP_PCAP_bit_set(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; +SSP_PCAP_STATUS SSP_PCAP_bit_clean(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; +SSP_PCAP_BIT_STATUS SSP_PCAP_get_bit_from_buffer(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; +SSP_PCAP_BIT_STATUS SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE ssp_pcap_bit ) ; +U32 SSP_PCAP_get_register_value_from_buffer(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER ssp_pcap_register ) ; + +#ifdef SSP_PCAP_OPERATE_WITH_SPI +static wait_queue_head_t ssp_pcap_send_wait; +static U32 ssp_pcap_readValue; +static void ssp_interrupt_routine(int irq, void *dev_id, struct pt_regs *regs ); +void ssp_put_intoData(U32 pcapValue); +#endif + +static spinlock_t pcapoperation_lock = SPIN_LOCK_UNLOCKED; +static void ssp_pcap_interrupt_routine(int irq, void *dev_id, struct pt_regs *regs ); +//static U32 ssp_pcapRegisterReadOut = 0; + +//static void usb_hardware_switch(void); + +//static struct timer_list usb_switch_timer; + +void ssp_pcap_init(void); +void ssp_pcap_release(void); +void ssp_pcap_clear_int(void); +void ssp_pcap_intoSleepCallBack(void); +void ssp_pcap_wakeUpCallBack(void); + +extern int usb_gpio_init(void); +extern int stop_usb(void); +static void ssp_tsi_keeper(u32 data); +static void ssp_usb_accessory_debounce_handler(u32 data); + +extern void ezx_ts_dataReadok_interrupt(int irq,void* dev_id, struct pt_regs *regs); +extern void ezx_ts_touch_interrupt(int irq,void* dev_id, struct pt_regs *regs); +void (*headjack_change_interrupt_routine)(int ch,void *dev_id,struct pt_regs *regs); +void (*mic_change_interrupt_routine)(int ch,void *dev_id,struct pt_regs *regs); +//extern u8 pxafb_ezx_getLCD_status(void); + +int (*cable_hotplug_attach)(ACCESSORY_DEVICE_STATUS status); +static struct ssp_interrupt_info sspUsbAccessoryInfo; + +void SSP_PCAP_MMCSD_poweroff(void) +{ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN); +} +EXPORT_SYMBOL(SSP_PCAP_MMCSD_poweroff); + +void SSP_PCAP_MMCSD_poweron(void) +{ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_AUX_VREG_VAUX2_EN); +} +EXPORT_SYMBOL(SSP_PCAP_MMCSD_poweron); + +static void accessory_bus_detect_handler(ACCESSORY_TYPE type,ACCESSORY_DEVICE_STATUS status,void* privdata ) +{ + sspUsbAccessoryInfo.type = (u32)type; + sspUsbAccessoryInfo.status = (u32)status; + sspUsbAccessoryInfo.privdata = privdata; + del_timer(&ssp_usb_accessory_debounce_timer); + ssp_usb_accessory_debounce_timer.data = ( unsigned long ) &sspUsbAccessoryInfo; + /* 2 seconds protect timer */ + ssp_usb_accessory_debounce_timer.expires = jiffies + SSP_SEND_MSG_USB_ACCESSORY_INFO_DEBOUNCE; + add_timer(&ssp_usb_accessory_debounce_timer); + return; +} + +static void ssp_usb_accessory_debounce_handler(u32 data) +{ + struct ssp_interrupt_info * pMyInfo; + ACCESSORY_TYPE type; + ACCESSORY_DEVICE_STATUS status; + + pMyInfo = (struct ssp_interrupt_info *)data; + type = ( ACCESSORY_TYPE) pMyInfo->type; + status = ( ACCESSORY_DEVICE_STATUS) pMyInfo->status; + + switch(type) + { + case ACCESSORY_DEVICE_USB_PORT: + if (cable_hotplug_attach) + (*cable_hotplug_attach)(status); + switch(status) + { + case ACCESSORY_DEVICE_STATUS_DETACHED: + apm_queue_event(KRNL_ACCS_DETACH); + break; + case ACCESSORY_DEVICE_STATUS_ATTACHED: + apm_queue_event(KRNL_ACCS_ATTACH); + break; + default: + break; + } + break; + default: + break; + } + return; +} + +/*--------------------------------------------------------------------------- + DESCRIPTION: log system stored in buffer. it can output via FFUART. also you can change a little to other output mode. + + INPUTS: none. + + + OUTPUTS: none. + + + IMPORTANT NOTES: the macro PCAP_LOG_FFUART_OUT is a switch. + it is auto-output to FFUART every PCAP_LOG_OUTPUT_TIMER seconds + + +---------------------------------------------------------------------------*/ +/* record log system by linwq */ +//#define PCAP_LOG_FFUART_OUT + +#ifdef PCAP_LOG_FFUART_OUT +static struct timer_list pcap_outlog_timer; + +#define PCAP_LOG_OUTPUT_TIMER 60 +#define PCAP_LOG_RECORD_LENGTH 50000 + +unsigned char pcap_log_data[PCAP_LOG_RECORD_LENGTH]; + +u8* pcap_log_now_address = pcap_log_data; +#define PCAP_LOG_START_ADDRESS pcap_log_data +#define PCAP_LOG_END_ADDRESS pcap_log_data + PCAP_LOG_RECORD_LENGTH +u32 pcap_log_len = 0; + +void pcap_log_add_pure_data(u8* pData,u32 len) +{ + u32 i; + if ((pData ==NULL)|| len == 0) + return; + for(i = 0;i= PCAP_LOG_RECORD_LENGTH) + pcap_log_len = PCAP_LOG_RECORD_LENGTH; + } + return; +} + +void pcap_log_add_data(u8* pData,u32 len) +{ + u32 i; + u8 temp[20]; + if ((pData ==NULL)|| len == 0) + return; + sprintf(temp,"\n <%d MS>",(int)(OSCR/3686)); + for(i = 0;i<(u32)strlen(temp);i++) + { + *pcap_log_now_address ++ = temp[i]; + if( PCAP_LOG_END_ADDRESS == pcap_log_now_address ) + pcap_log_now_address = PCAP_LOG_START_ADDRESS; + pcap_log_len++; + if(pcap_log_len >= PCAP_LOG_RECORD_LENGTH) + pcap_log_len = PCAP_LOG_RECORD_LENGTH; + } + + for(i = 0;i= PCAP_LOG_RECORD_LENGTH) + pcap_log_len = PCAP_LOG_RECORD_LENGTH; + } + return; +} + +static void pcap_log_output_from_ffuart(void) +{ + u32 i; + u32 ssp_ffuart_dll,ssp_ffuart_dlh; + u8 ssp_ffuart_cken = 1,ssp_ffuart_en = 1; + if(0 == pcap_log_len) + return; + + /* if cable in NOT UART cable, should return */ + printk("\n *********log out ************* \n <%d jiffies>log:",(int)jiffies); + local_irq_disable(); + if(!(CKEN&CKEN6_FFUART)) + { + ssp_ffuart_cken = 0; + CKEN |= CKEN6_FFUART; + pcap_log_add_data("FFUART CLK not ENABLE!",strlen("FFUART CLK not ENABLE!")); + } + + FFLCR = (FFLCR&0xff)|0x80; + ssp_ffuart_dll = FFDLL&0xff; + ssp_ffuart_dlh = FFDLH&0xff; + FFLCR = FFLCR&0x7f; + + if((0x08 !=ssp_ffuart_dll)||(0x00 != ssp_ffuart_dlh)) + { + FFLCR = 0x83; + FFDLL = 0x08; + FFDLH = 0; + FFLCR = 0x03; + } + + if(!(FFIER&0x00000040)) + { + ssp_ffuart_en = 0; + FFIER |= 0x00000040; + pcap_log_add_data("FFUART model not ENABLE!",strlen("FFUART model not ENABLE!")); + } + + for(i=0;ilog:",(int)jiffies); + local_irq_disable(); + if(!(CKEN&CKEN5_STUART)) + { + ssp_stuart_cken = 0; + CKEN |= CKEN5_STUART; + pcap_log_add_data("STUART CLK not ENABLE!",strlen("STUART CLK not ENABLE!")); + } + + STLCR = (STLCR&0xff)|0x80; + ssp_stuart_dll = STDLL&0xff; + ssp_stuart_dlh = STDLH&0xff; + STLCR &= 0x7f; + + if((0x08 !=ssp_stuart_dll)||(0x00 != ssp_stuart_dlh)) + { + STLCR = 0x83; + STDLL = 0x08; + STDLH = 0; + STLCR = 0x03; + } + + if(!(STIER&0x00000040)) + { + ssp_stuart_en = 0; + STIER |= 0x00000040; + pcap_log_add_data("STUART model not ENABLE!",strlen("STUART model not ENABLE!")); + }ACCESSORY_DEVICE_STATUS + + for(i=0;i>SSP_PCAP_ADD2_VALUE_SHIFT); + } + SSP_PCAP_TSI_mode_set(PCAP_TS_STANDBY_MODE); + return ret; +} + +/*--------------------------------------------------------------------------- + DESCRIPTION: + + INPUTS: + + + OUTPUTS: + + + IMPORTANT NOTES: + + +---------------------------------------------------------------------------*/ + +SSP_PCAP_STATUS SSP_PCAP_CDC_CLK_set(PHONE_CDC_CLOCK_TYPE clkType) +{ + U32 tempValue; + tempValue = ssp_pcap_registerValue[SSP_PCAP_ADJ_AUD_CODEC_REGISTER]&(~SSP_PCAP_PHONE_CDC_CLOCK_MASK); + tempValue = tempValue|clkType; + return SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUD_CODEC_REGISTER,tempValue); +} + +/*--------------------------------------------------------------------------- + DESCRIPTION: + + INPUTS: + + + OUTPUTS: + + + IMPORTANT NOTES: + + +---------------------------------------------------------------------------*/ +SSP_PCAP_STATUS SSP_PCAP_V_VIB_level_set(VibratorVoltageLevel_TYPE VIBLevelType) +{ + U32 tempValue; + tempValue = ssp_pcap_registerValue[SSP_PCAP_ADJ_AUX_VREG_REGISTER]&(~SSP_PCAP_VIBRATOR_VOLTAGE_LEVEL_MASK); + tempValue = tempValue|VIBLevelType; + return SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_AUX_VREG_REGISTER,tempValue); +} + +/*--------------------------------------------------------------------------- + DESCRIPTION: + + INPUTS: + + + OUTPUTS: + + + IMPORTANT NOTES: + + +---------------------------------------------------------------------------*/ +SSP_PCAP_STATUS SSP_PCAP_CDC_SR_set(ST_SAMPLE_RATE_TYPE srType) +{ + U32 tempValue; + tempValue = ssp_pcap_registerValue[SSP_PCAP_ADJ_ST_DAC_REGISTER]&(~SSP_PCAP_STEREO_SAMPLE_RATE_MASK); + tempValue = tempValue|srType; + return SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_ST_DAC_REGISTER,tempValue); +} + +/*--------------------------------------------------------------------------- + DESCRIPTION: + + INPUTS: + + + OUTPUTS: + + + IMPORTANT NOTES: + + +---------------------------------------------------------------------------*/ +SSP_PCAP_STATUS SSP_PCAP_BCLK_set(ST_BCLK_TIME_SLOT_TYPE bclkType) +{ + U32 tempValue; + tempValue = ssp_pcap_registerValue[SSP_PCAP_ADJ_ST_DAC_REGISTER]&(~SSP_PCAP_STEREO_BCLK_TIME_SLOT_MASK); + tempValue = tempValue|bclkType; + return SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_ST_DAC_REGISTER,tempValue); +} + +/*--------------------------------------------------------------------------- + DESCRIPTION: + + INPUTS: + + + OUTPUTS: + + + IMPORTANT NOTES: + + +---------------------------------------------------------------------------*/ +SSP_PCAP_STATUS SSP_PCAP_STCLK_set(ST_CLK_TYPE stClkType) +{ + U32 tempValue; + tempValue = ssp_pcap_registerValue[SSP_PCAP_ADJ_ST_DAC_REGISTER]&(~SSP_PCAP_STEREO_CLOCK_MASK); + tempValue = tempValue|stClkType; + return SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_ST_DAC_REGISTER,tempValue); +} + +/*--------------------------------------------------------------------------- + DESCRIPTION: + + INPUTS: + + + OUTPUTS: + + + IMPORTANT NOTES: + + +---------------------------------------------------------------------------*/ +SSP_PCAP_STATUS SSP_PCAP_DIG_AUD_FS_set(DIG_AUD_MODE_TYPE fsType) +{ + U32 tempValue; + tempValue = ssp_pcap_registerValue[SSP_PCAP_ADJ_ST_DAC_REGISTER]&(~SSP_PCAP_DIGITAL_AUDIO_MODE_MASK); + tempValue = tempValue|fsType; + return SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_ST_DAC_REGISTER,tempValue); +} + +/*--------------------------------------------------------------------------- + DESCRIPTION: + + INPUTS: + + + OUTPUTS: + + + IMPORTANT NOTES: + + +---------------------------------------------------------------------------*/ +SSP_PCAP_STATUS SSP_PCAP_AUDIG_set(U32 audioInGain) +{ + U32 tempValue; + if (audioInGain > PCAP_AUDIO_IN_GAIN_MAX_VALUE) + return SSP_PCAP_ERROR_VALUE; + tempValue = ssp_pcap_registerValue[SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER]&(~SSP_PCAP_AUDIO_IN_GAIN_MASK); + + /* shoulb be better like this tempValue |= audioInGain < PCAP_AUDIO_OUT_GAIN_MAX_VALUE) + return SSP_PCAP_ERROR_VALUE; + tempValue = ssp_pcap_registerValue[SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER]&(~SSP_PCAP_AUDIO_OUT_GAIN_MASK); + tempValue |= audioOutGain <SSP_SEND_PM_ALART_INTERVAL) + { + ssp_pcap_last_jiffies = (u32) jiffies; + apm_queue_event(KRNL_TOUCHSCREEN); + } + return; +} + +static void ssp_pcap_interrupt_routine(int irq, void *dev_id, struct pt_regs *regs ) +{ + u32 pcap_repeat_num; + U32 tempValue; + u32 tempClearInterrupt; +#ifdef PCAP_LOG_FFUART_OUT + u8 temp[100]; + pcap_log_add_data("SSP interrupt by GPIO.",strlen("\n SSP interrupt by GPIO.")); +#endif + +#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION + printk( "\n ************************ \n SSP interrupt by GPIO. "); +#endif + /* should care the return value */ + pcap_repeat_num = 0; +intRepeat: + SSP_PCAP_read_data_from_PCAP( SSP_PCAP_ADJ_ISR_REGISTER,&tempValue); + tempClearInterrupt = tempValue&(SSP_PCAP_ADJ_BIT_ISR_MB2I|SSP_PCAP_ADJ_BIT_ISR_STI|SSP_PCAP_ADJ_BIT_ISR_A1I|SSP_PCAP_ADJ_BIT_ISR_USB1VI|SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I|SSP_PCAP_ADJ_BIT_ISR_TSI|SSP_PCAP_ADJ_BIT_ISR_USB4VI); + + /* send the data to ISR register to clear the interrupt flag */ + SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_ISR_REGISTER,tempClearInterrupt); + +#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION + printk("\n w17202 TSI = 0x%x ",tempClearInterrupt); +#endif + if(SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I&tempValue) + { + if(SSP_PCAP_BIT_ZERO == SSP_PCAP_get_bit_from_buffer(SSP_PCAP_ADJ_BIT_MSR_ADCDONE2M)) + { + /* call read XY callback function */ +#ifdef PCAP_LOG_FFUART_OUT + pcap_log_add_data("SSP ADC interrupt need handle.",strlen("SSP ADC interrupt need handle.")); +#endif +#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION + printk( "\n ************************** \n SSP ADC interrupt need handle." ); +#endif + ssp_pcap_ts_send_pMmessage(); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_ADC1_ADEN); + /* 2 seconds protect timer */ + /* better used it after linux 2.4.17 */ + mod_timer(&ssp_tsi_timer,jiffies + SSP_PCAP_TS_KEEPER_TIMER); + ezx_ts_dataReadok_interrupt(0,NULL,NULL); + } + else + { +#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION + printk( "\n ************************** \n SSP ADC interrupt should be discarded." ); +#endif + } + } + + if(SSP_PCAP_ADJ_BIT_ISR_TSI&tempValue) + { + if(SSP_PCAP_BIT_ZERO == SSP_PCAP_get_bit_from_buffer(SSP_PCAP_ADJ_BIT_MSR_TSM)) + { +#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION + printk( "\n ************************* \n SSP TSI need handle."); +#endif +#ifdef PCAP_LOG_FFUART_OUT + pcap_log_add_data("SSP TSI need handle.",strlen("SSP TSI need handle.")); +#endif + ssp_pcap_ts_send_pMmessage(); + //if ( pxafb_ezx_getLCD_status() ) + if (1) + { + /* call touch panel callbcak function */ + SSP_PCAP_bit_set( SSP_PCAP_ADJ_BIT_MSR_TSM); + /* 2 seconds protect timer */ + /* better used it after linux 2.4.17 */ + mod_timer(&ssp_tsi_timer,jiffies + SSP_PCAP_TS_KEEPER_TIMER);; + ezx_ts_touch_interrupt(0,NULL,NULL); + } + } + else + { +#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION + printk( "\n************************* \n SSP TSI should be discarded."); +#endif +#ifdef PCAP_LOG_FFUART_OUT + pcap_log_add_data("SSP TSI need not handle.",strlen("SSP TSI need not handle.")); +#endif + } + } + + + if(SSP_PCAP_ADJ_BIT_ISR_USB4VI&tempValue) + { + if(SSP_PCAP_BIT_ZERO == SSP_PCAP_get_bit_from_buffer(SSP_PCAP_ADJ_BIT_MSR_USB4VM)) + { + if(SSP_PCAP_BIT_ONE == SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_USBDET_4V)) + { + /* maybe we can support low speed USB how to do??? */ +#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION + printk( "\n************************* \n SSP USB4VI need handle."); +#endif +#ifdef PCAP_LOG_FFUART_OUT + pcap_log_add_data("SSP USB4VI need handle.",strlen("SSP USB4VI need handle.")); +#endif + accessory_bus_detect_handler(ACCESSORY_DEVICE_USB_PORT,ACCESSORY_DEVICE_STATUS_ATTACHED,NULL); + } + else + { +#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION + printk( "\n ************************* \n SSP USB4VI low need NOT handle same as USB1VI low."); +#endif + } + } + else + { +#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION + printk( "\n************************* \n SSP USB4VI should be discarded."); +#endif + } + } + + if(SSP_PCAP_ADJ_BIT_ISR_USB1VI&tempValue) + { + if(SSP_PCAP_BIT_ZERO == SSP_PCAP_get_bit_from_buffer(SSP_PCAP_ADJ_BIT_MSR_USB1VM)) + { + if(SSP_PCAP_BIT_ONE == SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_USBDET_1V)) + { +#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION + printk( "\n************************* \n SSP USB_VBUS greater than 1V!"); +#endif + } + else + { +#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION + printk( "\n************************* \n SSP USB_VBUS less than 1V! need handle."); +#endif + accessory_bus_detect_handler(ACCESSORY_DEVICE_USB_PORT,ACCESSORY_DEVICE_STATUS_DETACHED,NULL); + } + } + else + { +#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION + printk( "\n************************* \n SSP USB1VI should be discarded."); +#endif + } + } + + + if(SSP_PCAP_ADJ_BIT_ISR_A1I&tempValue) + { + if(SSP_PCAP_BIT_ZERO == SSP_PCAP_get_bit_from_buffer(SSP_PCAP_ADJ_BIT_MSR_A1M)) + { +#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION + printk( "\n A1_INT insert/remove case, need to handle. ISR =%x ",tempValue ); +#endif +#ifdef PCAP_LOG_FFUART_OUT + sprintf(temp,"A1_INT insert/remove case, need to handle. ISR =%x ",tempValue ); + pcap_log_add_data(temp,strlen(temp)); +#endif + /* earpiece insert/remove need handler */ + if (headjack_change_interrupt_routine) + (*headjack_change_interrupt_routine)(0,NULL,NULL); + } + else + { +#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION + printk( "\n A1_INT should be discarded." ); +#endif + } + } + + if(SSP_PCAP_ADJ_BIT_ISR_MB2I&tempValue) + { + if(SSP_PCAP_BIT_ZERO == SSP_PCAP_get_bit_from_buffer(SSP_PCAP_ADJ_BIT_MSR_MB2M)) + { +#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION + printk( "\n MIC insert/remove case, need to handle! ISR =%x ",tempValue ); +#endif +#ifdef PCAP_LOG_FFUART_OUT + sprintf(temp,"MIC insert/remove case, need to handle! ISR =%x ",tempValue ); + pcap_log_add_data(temp,strlen(temp)); +#endif + //queue_apm_event(KRNL_KEYPAD,NULL); + /* mic insert/remove or answer/end call handler */ + if (mic_change_interrupt_routine) + (*mic_change_interrupt_routine)(0,NULL,NULL); + } + else + { +#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION + printk( "\n************************* \n SSP MB2I should be discarded."); +#endif + } + } + if(GPLR0&0x00000002) + { + /* this case is a very critical case. */ +#ifdef PCAP_LOG_FFUART_OUT + pcap_log_add_data("repeat pcap int!",strlen("repeat pcap int!")); +#endif + if(pcap_repeat_num<10) + { + pcap_repeat_num++; + goto intRepeat; + } + else + { +#ifdef PCAP_LOG_FFUART_OUT + pcap_log_add_data("repeat pcap exceed 10 times!",strlen("repeat pcap exceed 10 times!")); +#endif + } + } + return; +} + +/*--------------------------------------------------------------------------- + DESCRIPTION: + + INPUTS: + + + OUTPUTS: + + + IMPORTANT NOTES: + + +---------------------------------------------------------------------------*/ + +#ifdef SSP_PCAP_OPERATE_WITH_SPI + +void ssp_put_intoData(U32 pcapValue) +{ +#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION + char string[100]; +#endif + U32 tempFirstByte; + U32 tempSecondByte; + tempFirstByte = (pcapValue&SSP_PCAP_REGISTER_VALUE_UP_WORD_MASK)>>SSP_PCAP_REGISTER_VALUE_LENGTH; + tempSecondByte = (pcapValue&SSP_PCAP_REGISTER_VALUE_DOWN_WORD_MASK); + /* disable all interrupt or disable the SSP (zero to SSE) */ + local_irq_disable(); + SSDR = tempFirstByte ; + SSDR = tempSecondByte ; + local_irq_enable(); +#ifdef SSP_PCAP_OPERATE_DEBUG_INFORNMATION + printk("\n ssp put dat \n"); + sprintf( string,"\n fisrt part =%8x second part =%8x \n",tempFirstByte,tempSecondByte); + printk(string); +#endif + return; +} + +#endif + +/*--------------------------------------------------------------------------- + DESCRIPTION: + + INPUTS: + + + OUTPUTS: + + + IMPORTANT NOTES: + + +---------------------------------------------------------------------------*/ +SSP_PCAP_STATUS SSP_PCAP_write_data_to_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER sspPcapRegister,U32 registerValue) +{ + u32 pcapTempValue ; + unsigned long flags; + /* prevent the process schedule out and mask the PCAP's interrupt handler */ + //ICMR &= ~(1<<(GPIO1_RST+PXA_IRQ_SKIP)); + save_flags(flags); + local_irq_disable(); + spin_lock(&pcapoperation_lock); + + if(!test_and_set_bit(0,&ssp_pcap_status)) + { + switch(sspPcapRegister) + { +#ifdef SSP_PCAP_DEBUG_BOARD + case 3: + case 22: +#endif + case SSP_PCAP_ADJ_ISR_REGISTER: + case SSP_PCAP_ADJ_MSR_REGISTER: + case SSP_PCAP_ADJ_PSTAT_REGISTER: + case SSP_PCAP_ADJ_VREG2_REGISTER: + case SSP_PCAP_ADJ_AUX_VREG_REGISTER: + case SSP_PCAP_ADJ_BATT_DAC_REGISTER: + case SSP_PCAP_ADJ_ADC1_REGISTER: + case SSP_PCAP_ADJ_ADC2_REGISTER: + case SSP_PCAP_ADJ_AUD_CODEC_REGISTER: + case SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER: + case SSP_PCAP_ADJ_ST_DAC_REGISTER: + case SSP_PCAP_ADJ_BUSCTRL_REGISTER: + case SSP_PCAP_ADJ_PERIPH_REGISTER: + case SSP_PCAP_ADJ_LOWPWR_CTRL_REGISTER: + case SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER: + case SSP_PCAP_ADJ_GP_REG_REGISTER: + ssp_pcap_registerValue[sspPcapRegister] = registerValue&SSP_PCAP_REGISTER_VALUE_MASK; + pcapTempValue = SSP_PCAP_REGISTER_WRITE_OP_BIT|(sspPcapRegister<>SSP_PCAP_REGISTER_ADDRESS_SHIFT; + + switch(sspPcapRegister) + { + case SSP_PCAP_ADJ_ISR_REGISTER: + ssp_pcap_registerValue[sspPcapRegister] = 0; +#ifdef SSP_PCAP_DEBUG_BOARD + case 22: +#endif + case SSP_PCAP_ADJ_MSR_REGISTER: + case SSP_PCAP_ADJ_PSTAT_REGISTER: + case SSP_PCAP_ADJ_VREG2_REGISTER: + case SSP_PCAP_ADJ_AUX_VREG_REGISTER: + case SSP_PCAP_ADJ_BATT_DAC_REGISTER: + case SSP_PCAP_ADJ_ADC1_REGISTER: + case SSP_PCAP_ADJ_ADC2_REGISTER: + case SSP_PCAP_ADJ_AUD_CODEC_REGISTER: + case SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER: + case SSP_PCAP_ADJ_ST_DAC_REGISTER: + case SSP_PCAP_ADJ_BUSCTRL_REGISTER: + case SSP_PCAP_ADJ_PERIPH_REGISTER: + case SSP_PCAP_ADJ_LOWPWR_CTRL_REGISTER: + case SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER: + case SSP_PCAP_ADJ_GP_REG_REGISTER: + + sspPcapRegisterBitValue = (sspPcapBit&SSP_PCAP_REGISTER_VALUE_MASK); + ssp_pcap_registerValue[sspPcapRegister] |= sspPcapRegisterBitValue; + /* should care the return value */ + ret =SSP_PCAP_write_data_to_PCAP(sspPcapRegister,ssp_pcap_registerValue[sspPcapRegister]); + return SSP_PCAP_SUCCESS; + break; + default: + return SSP_PCAP_ERROR_REGISTER; + break; + } + return SSP_PCAP_SUCCESS; +} + +/*--------------------------------------------------------------------------- + DESCRIPTION: + + INPUTS: + + + OUTPUTS: + + + IMPORTANT NOTES: + + +---------------------------------------------------------------------------*/ +SSP_PCAP_STATUS SSP_PCAP_bit_clean(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE sspPcapBit ) +{ + U32 sspPcapRegisterBitValue; + SSP_PCAP_STATUS ret; + U8 sspPcapRegister = (sspPcapBit&SSP_PCAP_REGISTER_ADDRESS_MASK)>>SSP_PCAP_REGISTER_ADDRESS_SHIFT; + + switch(sspPcapRegister) + { + case SSP_PCAP_ADJ_ISR_REGISTER: + ssp_pcap_registerValue[sspPcapRegister] = 0; + case SSP_PCAP_ADJ_MSR_REGISTER: + case SSP_PCAP_ADJ_PSTAT_REGISTER: + case SSP_PCAP_ADJ_VREG2_REGISTER: + case SSP_PCAP_ADJ_AUX_VREG_REGISTER: + case SSP_PCAP_ADJ_BATT_DAC_REGISTER: + case SSP_PCAP_ADJ_ADC1_REGISTER: + case SSP_PCAP_ADJ_ADC2_REGISTER: + case SSP_PCAP_ADJ_AUD_CODEC_REGISTER: + case SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER: + case SSP_PCAP_ADJ_ST_DAC_REGISTER: + case SSP_PCAP_ADJ_BUSCTRL_REGISTER: + case SSP_PCAP_ADJ_PERIPH_REGISTER: + case SSP_PCAP_ADJ_LOWPWR_CTRL_REGISTER: + case SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER: + case SSP_PCAP_ADJ_GP_REG_REGISTER: + sspPcapRegisterBitValue = (sspPcapBit&SSP_PCAP_REGISTER_VALUE_MASK); + ssp_pcap_registerValue[sspPcapRegister] &= ~sspPcapRegisterBitValue; + /* should care the return value */ + ret =SSP_PCAP_write_data_to_PCAP(sspPcapRegister,ssp_pcap_registerValue[sspPcapRegister]); + return SSP_PCAP_SUCCESS; + break; + default: + return SSP_PCAP_ERROR_REGISTER; + break; + } + return SSP_PCAP_SUCCESS; +} + +/*--------------------------------------------------------------------------- + DESCRIPTION: + + INPUTS: + + + OUTPUTS: + + + IMPORTANT NOTES: + + +---------------------------------------------------------------------------*/ +SSP_PCAP_BIT_STATUS SSP_PCAP_get_bit_from_buffer(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE sspPcapBit ) +{ + U32 sspPcapRegisterBitValue; + U8 sspPcapRegister = (sspPcapBit&SSP_PCAP_REGISTER_ADDRESS_MASK)>>SSP_PCAP_REGISTER_ADDRESS_SHIFT; + switch(sspPcapRegister) + { + case SSP_PCAP_ADJ_ISR_REGISTER: + case SSP_PCAP_ADJ_MSR_REGISTER: + case SSP_PCAP_ADJ_PSTAT_REGISTER: + case SSP_PCAP_ADJ_VREG2_REGISTER: + case SSP_PCAP_ADJ_AUX_VREG_REGISTER: + case SSP_PCAP_ADJ_BATT_DAC_REGISTER: + case SSP_PCAP_ADJ_ADC1_REGISTER: + case SSP_PCAP_ADJ_ADC2_REGISTER: + case SSP_PCAP_ADJ_AUD_CODEC_REGISTER: + case SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER: + case SSP_PCAP_ADJ_ST_DAC_REGISTER: + case SSP_PCAP_ADJ_BUSCTRL_REGISTER: + case SSP_PCAP_ADJ_PERIPH_REGISTER: + case SSP_PCAP_ADJ_LOWPWR_CTRL_REGISTER: + case SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER: + case SSP_PCAP_ADJ_GP_REG_REGISTER: + sspPcapRegisterBitValue = (sspPcapBit&SSP_PCAP_REGISTER_VALUE_MASK); + sspPcapRegisterBitValue &= ssp_pcap_registerValue[sspPcapRegister]; + if(sspPcapRegisterBitValue) + { + return SSP_PCAP_BIT_ONE; + } + else + { + return SSP_PCAP_BIT_ZERO; + } + break; + default: + return SSP_PCAP_BIT_ERROR; + break; + } + return SSP_PCAP_BIT_ERROR; +} + +/*--------------------------------------------------------------------------- + DESCRIPTION: + + INPUTS: + + + OUTPUTS: + + + IMPORTANT NOTES: + + +---------------------------------------------------------------------------*/ +SSP_PCAP_BIT_STATUS SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER_BIT_TYPE sspPcapBit ) +{ + U32 sspPcapTempRegisterValue; + U32 sspPcapRegisterBitValue; + SSP_PCAP_STATUS ret; + U8 sspPcapRegister = (sspPcapBit&SSP_PCAP_REGISTER_ADDRESS_MASK)>>SSP_PCAP_REGISTER_ADDRESS_SHIFT; + + switch(sspPcapRegister) + { + case SSP_PCAP_ADJ_ISR_REGISTER: + case SSP_PCAP_ADJ_MSR_REGISTER: + case SSP_PCAP_ADJ_PSTAT_REGISTER: + case SSP_PCAP_ADJ_VREG2_REGISTER: + case SSP_PCAP_ADJ_AUX_VREG_REGISTER: + case SSP_PCAP_ADJ_BATT_DAC_REGISTER: + case SSP_PCAP_ADJ_ADC1_REGISTER: + case SSP_PCAP_ADJ_ADC2_REGISTER: + case SSP_PCAP_ADJ_AUD_CODEC_REGISTER: + case SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER: + case SSP_PCAP_ADJ_ST_DAC_REGISTER: + case SSP_PCAP_ADJ_BUSCTRL_REGISTER: + case SSP_PCAP_ADJ_PERIPH_REGISTER: + case SSP_PCAP_ADJ_LOWPWR_CTRL_REGISTER: + case SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER: + case SSP_PCAP_ADJ_GP_REG_REGISTER: + sspPcapRegisterBitValue = (sspPcapBit&SSP_PCAP_REGISTER_VALUE_MASK); + /* should care the return value */ + ret = SSP_PCAP_read_data_from_PCAP(sspPcapRegister,&sspPcapTempRegisterValue); + sspPcapRegisterBitValue &= sspPcapTempRegisterValue; + if(sspPcapRegisterBitValue) + { + return SSP_PCAP_BIT_ONE; + } + else + { + return SSP_PCAP_BIT_ZERO; + } + break; + default: + return SSP_PCAP_BIT_ERROR; + break; + } + return SSP_PCAP_BIT_ERROR; +} +/*--------------------------------------------------------------------------- + DESCRIPTION: + + INPUTS: + + + OUTPUTS: + + + IMPORTANT NOTES: + + +---------------------------------------------------------------------------*/ +U32 SSP_PCAP_get_register_value_from_buffer(SSP_PCAP_SECONDARY_PROCESSOR_REGISTER sspPcapRegister ) +{ + switch(sspPcapRegister) + { + case SSP_PCAP_ADJ_ISR_REGISTER: + case SSP_PCAP_ADJ_MSR_REGISTER: + case SSP_PCAP_ADJ_PSTAT_REGISTER: + case SSP_PCAP_ADJ_VREG2_REGISTER: + case SSP_PCAP_ADJ_AUX_VREG_REGISTER: + case SSP_PCAP_ADJ_BATT_DAC_REGISTER: + case SSP_PCAP_ADJ_ADC1_REGISTER: + case SSP_PCAP_ADJ_ADC2_REGISTER: + case SSP_PCAP_ADJ_AUD_CODEC_REGISTER: + case SSP_PCAP_ADJ_AUD_RX_AMPS_REGISTER: + case SSP_PCAP_ADJ_ST_DAC_REGISTER: + case SSP_PCAP_ADJ_BUSCTRL_REGISTER: + case SSP_PCAP_ADJ_PERIPH_REGISTER: + case SSP_PCAP_ADJ_LOWPWR_CTRL_REGISTER: + case SSP_PCAP_ADJ_TX_AUD_AMPS_REGISTER: + case SSP_PCAP_ADJ_GP_REG_REGISTER: + return ssp_pcap_registerValue[sspPcapRegister]; + break; + default: + return SSP_PCAP_ERROR_REGISTER; + break; + } +} +#ifdef __cplusplus +} +#endif Index: linux-2.6.16.5-a/drivers/char/Kconfig =================================================================== --- linux-2.6.16.5-a.orig/drivers/char/Kconfig 2006-05-04 17:06:50.000000000 +0200 +++ linux-2.6.16.5-a/drivers/char/Kconfig 2006-05-04 17:07:04.000000000 +0200 @@ -1007,6 +1007,16 @@ The mmtimer device allows direct userspace access to the Altix system timer. +config LINUX_LED + tristate "LED support" + +config PXA_E680_LED + tristate "E680 LED suppory" + depends on LINUX_LED + +config BULVERDE_SRAM_DEV + tristate "BULVERDE Internal SRAM char device" + source "drivers/char/tpm/Kconfig" config TELCLOCK Index: linux-2.6.16.5-a/drivers/char/Makefile =================================================================== --- linux-2.6.16.5-a.orig/drivers/char/Makefile 2006-05-04 17:06:50.000000000 +0200 +++ linux-2.6.16.5-a/drivers/char/Makefile 2006-05-04 17:07:04.000000000 +0200 @@ -95,6 +95,14 @@ obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o obj-$(CONFIG_TCG_TPM) += tpm/ + +obj-$(CONFIG_LINUX_LED) += led.o +obj-$(CONFIG_PXA_E680_LED) += led_pxa_e680.o + +obj-$(CONFIG_MAINSTONE_KEYPAD) += mstone_keypad.o +obj-$(CONFIG_BULVERDE_SRAM_DEV) += sram.o + + # Files generated that shall be removed upon make clean clean-files := consolemap_deftbl.c defkeymap.c qtronixmap.c Index: linux-2.6.16.5-a/drivers/char/gpio_test.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/char/gpio_test.c 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,216 @@ +/* + * linux/drivers/char/gpio_test.c + * + * Support for the Motorola Ezx A780 Development Platform. + * + * Author: Jay Jia + * Created: April 25, 2004 + * Copyright: Motorola Inc. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../misc/ssp_pcap.h" + + +#define SUCCESS 0 +#define DEVICE_NAME "gpio_test" +#define GPIO_TEST_IOCTL_CMD_OPS_MASK 0x000F +#define GPIO_TEST_IOCTL_CMD_VAL_MASK 0x0080 +#define GPIO_TEST_IOCTL_CMD_NUM_MASK 0xFF00 +#define GPIO_TEST_IOCTL_CMD_VAL_SHIFT 7 +#define GPIO_TEST_IOCTL_CMD_NUM_SHIFT 8 + +static int Major=127; +static unsigned char pcap_usb_ps = 0; +static unsigned char pcap_vusb_en = 0; +static unsigned char pcap_ov_test_on = 0; + +static int gpio_test_open(struct inode *inode,struct file *file) +{ + MOD_INC_USE_COUNT; + return SUCCESS; +} + +static int gpio_test_release(struct inode *inode,struct file *file) + +{ + MOD_DEC_USE_COUNT; + return SUCCESS; +} + + +/******************************************************************************* +Function Name: gpio_test_ioctl + +Parameter: + The ioctl() accept a 2-byte command : cmd + Use this param as follows: + + bit 0 - 3: operation type. + 0x01, gpio read + 0x02, gpio write + 0x03, gpio config + 0x04, PCAP test + bit 4 -6: + reserved. keep ZERO + bit 7: + For gpio, write/config value. + For Over voltage test, + 0, ON + 1, OFF + bit 8 - 15: + For gpio, it is gpio pin number + For PCAP test, + 0x01, Over voltage test. + others, reserved. + +Return Value: + For Over voltage test, + return 0 for success. + return 1 for error. +*******************************************************************************/ +static int gpio_test_ioctl(struct inode *inode,struct file *file,unsigned short cmd,unsigned long arg) +{ + int num, val, ops, ret; + + ret = 0; + num = (cmd & GPIO_TEST_IOCTL_CMD_NUM_MASK) >> GPIO_TEST_IOCTL_CMD_NUM_SHIFT; + val = cmd & GPIO_TEST_IOCTL_CMD_VAL_MASK; + ops = cmd & GPIO_TEST_IOCTL_CMD_OPS_MASK; + + if(ops == 1)/*read gpio*/ + { +// set_GPIO_mode(num); +// GPDR(num) &= ~GPIO_bit(num); + ret = GPLR(num) & GPIO_bit(num); +// printk("in GPIO kernel read function, num = %d and ret = %d\n",num,ret); + return (ret == 0) ? 0:1; + } + + if(ops == 2)/*write gpio*/ + { +// set_GPIO_mode(num); +// GPDR(num) |= GPIO_bit(num); + if( val ) + GPSR(num) = GPIO_bit(num); + else + GPCR(num) = GPIO_bit(num); + return 2; + } + + if(ops == 3)/*set gpio*/ + { + set_GPIO_mode(num); + if( val ) + GPDR(num) |= GPIO_bit(num); + else + GPDR(num) &= ~GPIO_bit(num); + return 3; + } + + if(ops == 4)/* PCAP test */ + { + printk("PCAP test, cmd = 0x%x.\n", cmd); + val = val >> GPIO_TEST_IOCTL_CMD_VAL_SHIFT; + switch(num) + { + case 1: /* Over Voltage test */ + if(val == 0) /* ON */ + { + printk("Over Voltage test ON.\n"); + /* backup USB_PS and VUSB_EN */ + pcap_ov_test_on = 1; + pcap_usb_ps = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PS); + pcap_vusb_en = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); + /* USB_PS = 0, PCAP USB powered by VUSB_IN */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PS); + /* VUSB_EN = 1, USB tranceiver enabled */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); + /* USB 1V INT mask */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_MSR_USB1VM); + /* USB 4V INT mask */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_MSR_USB4VM); + ret = 0; + } + else if(val == 1) /* OFF */ + { + printk("Over Voltage test OFF.\n"); + if(pcap_ov_test_on != 1) + { + ret = 1; /* return error */ + break; + } + /* restore USB_PS and VUSB_EN */ + if(pcap_usb_ps) + { + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PS); + } + else + { + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PS); + } + if(pcap_vusb_en) + { + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); + } + else + { + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); + } + pcap_ov_test_on = 0; + /* USB 1V INT unmask */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_USB1VI); /* clear 1V INT status */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_MSR_USB1VM); + /* USB 4V INT unmask */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_USB4VI); /* clear 4V INT status */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_MSR_USB4VM); + ret = 0; + } + else /* Unrecongized command */ + { + ret = 1; + } + break; + default: + ret = 1; + } + return ret; + } /* end of PCAP test */ +} + +static struct file_operations gpio_test_fops={ + ioctl: gpio_test_ioctl, + open: gpio_test_open, + release:gpio_test_release, +}; + +int gpio_test_init_module() +{ + register_chrdev(Major, DEVICE_NAME, &gpio_test_fops); + return 0; +} + +void gpio_test_cleanup_module() +{ + unregister_chrdev(Major,DEVICE_NAME); +} + +module_init(gpio_test_init_module); +module_exit(gpio_test_cleanup_module); +MODULE_AUTHOR("Jay Jia"); +MODULE_LICENSE("GPL"); Index: linux-2.6.16.5-a/drivers/char/led.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/char/led.c 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,318 @@ +/* + * Device driver for controlling LEDs. See linux/led.h for info on + * how to use this. + * + * This currently only supports mono and bicolor LEDs, but support for + * fancier LEDs (scrolling text or numeric LEDs, for instance) could + * easily be added. + * + * Corey Minyard + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VERSION "1.0" + +/* A lock that is held when manipulating LED info. */ +static spinlock_t led_lock = SPIN_LOCK_UNLOCKED; + +/* A linked list of all the LEDs registered. */ +static struct led_reg_info *leds; + +/* Register a new LED with the driver. */ +int register_led_info(struct led_reg_info *info) +{ + struct led_reg_info *led; + int rv = 0; + + spin_lock(&led_lock); + info->next = NULL; + led = leds; + if (led == NULL) + { + leds = info; + } + else + { + while (led->next != NULL) + { + if (strcmp(led->info->name, info->info->name) == 0) + { + /* Registering a duplicate. */ + rv = -1; + goto out; + } + led = led->next; + } + led->next = info; + } + MOD_INC_USE_COUNT; + +out: + spin_unlock(&led_lock); + + return rv; +} + +/* Unregister an LED from the driver. */ +int unregister_led_info(struct led_reg_info *info) +{ + int rv = -1; + struct led_reg_info *led; + + if (info == NULL) + { + return -1; + } + + spin_lock(&led_lock); + led = leds; + if (led == info) + { + MOD_DEC_USE_COUNT; + leds = leds->next; + } + else + { + while (led->next != NULL) + { + if (led->next == info) + { + MOD_DEC_USE_COUNT; + led->next = info->next; + rv = 0; + goto out; + } + led = led->next; + } + } +out: + spin_unlock(&led_lock); + return rv; +} + +/* Return the number of LEDs registered. */ +static int count_leds(void) +{ + struct led_reg_info *led; + int count = 0; + + spin_lock(&led_lock); + led = leds; + while (led != NULL) + { + count = count + 1; + led = led->next; + } + spin_unlock(&led_lock); + + return count; +} + +/* Find an LED by its number. Must be called with the led spin lock + held. */ +static struct led_reg_info *get_led_by_num(int num) +{ + struct led_reg_info *led; + int count = num; + + led = leds; + while (led != NULL) + { + if (count == 0) + { + led->info->led_num = num; + return led; + } + count = count - 1; + led = led->next; + } + + return NULL; +} + +/* Find an LED by its name. Must be called with the led spin lock + held. */ +static struct led_reg_info *get_led_by_name(char *name) +{ + struct led_reg_info *led; + int count = 0; + + led = leds; + while (led != NULL) + { + if (strcmp(name, led->info->name) == 0) + { + led->info->led_num = count; + return led; + } + count++; + led = led->next; + } + + return NULL; +} + +/* The IOCTL handler for the LED driver. */ +static int led_ioctl(struct inode *inode, + struct file *file, + unsigned int cmd, + unsigned long arg) +{ + int i; + struct led_reg_info *led; + struct led_info info; + struct led_op op; + + switch(cmd) + { + case LEDIOC_GETCOUNT: + return count_leds(); + + case LEDIOC_GETINFO_BY_NUM: + case LEDIOC_GETINFO_BY_NAME: + i = copy_from_user(&info, (void*)arg, sizeof(info)); + if (i) + { + return -EFAULT; + } + + spin_lock(&led_lock); + if (cmd == LEDIOC_GETINFO_BY_NUM) + led = get_led_by_num(info.led_num); + else + led = get_led_by_name(info.name); + if (led == NULL) + { + spin_unlock(&led_lock); + return -EINVAL; + } + + info.type = led->info->type; + info.led_num = led->info->led_num; + strcpy(info.name, led->info->name); + info.info = led->info->info; + i = copy_to_user((void *)arg, &info, sizeof(info)); + + spin_unlock(&led_lock); + + if (i) + { + return -EFAULT; + } + return 0; + + case LEDIOC_OP: + i = copy_from_user(&op, (void*)arg, sizeof(op)); + if (i) + { + return -EFAULT; + } + + spin_lock(&led_lock); + led = get_led_by_name(op.name); + if (led == NULL) + { + spin_unlock(&led_lock); + return -EINVAL; + } + + i = led->handle_led_op(led, &op); + if (!i) + { + i = copy_to_user((void *)arg, &op, sizeof(op)); + if (i) + { + i = -EFAULT; + } + } + spin_unlock(&led_lock); + + return i; + + default: + return -ENOIOCTLCMD; + } +} + +/* Not much to do for opening. */ +static int led_open(struct inode *inode, struct file *file) +{ + switch(MINOR(inode->i_rdev)) + { + case LED_MINOR: + return 0; + + default: + return -ENODEV; + } +} + +/* Closing is really easy. */ +static int led_close(struct inode *inode, struct file *file) +{ + return 0; +} + + +static struct file_operations led_fops = { + owner: THIS_MODULE, + llseek: NULL, + read: NULL, + write: NULL, + ioctl: led_ioctl, + open: led_open, + release: led_close, +}; + +static struct miscdevice led_miscdev= +{ + LED_MINOR, + "led", + &led_fops +}; + + +/* Remove the LED driver. */ +static void __exit led_exit(void) +{ + misc_deregister(&led_miscdev); +} + +/* Set up the LED device driver. */ +static int __init led_init(void) +{ + int ret; + + printk("generic LED driver: v%s Corey Minyard (minyard@mvista.com)\n", + VERSION); + + leds = NULL; + ret = misc_register(&led_miscdev); + if (ret) { + printk(KERN_ERR "led: can't misc_register on minor=%d\n", + LED_MINOR); + return -1; + } + return 0; +} + +module_init(led_init); +module_exit(led_exit); + +EXPORT_SYMBOL(register_led_info); +EXPORT_SYMBOL(unregister_led_info); + +MODULE_LICENSE("GPL"); Index: linux-2.6.16.5-a/drivers/char/led_pxa_e680.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/char/led_pxa_e680.c 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,596 @@ +/*-------------------------------------------------------------------------------------------- +// Module Name: led_pxa_e680.c +// +// General Description: This is the driver for E680 LED. +//--------------------------------------------------------------------------------------------- +// Motorola Confidential Proprietary +// (c) Copyright Motorola 2003-2004, All Rights Reserved +// +// +// Revision History: +// Modification Tracking +// Author (core ID) Date Number Description of Changes +// ------------------------- ------------ ---------- ---------------------------- +// Liu weijie (A19553) 11/01/2003 LIBdd43835 Init create +// Wang Jamshid(a5036c) 04/29/2004 LIBee01180 fix bug,register pm call back +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../misc/ssp_pcap.h" + +#ifdef CONFIG_E680_P4A +#define IND_CNTL_R_BUL 79 +#define IND_CNTL_G_BUL 18 +#else +#define IND_CNTL_R_BUL 46 +#define IND_CNTL_G_BUL 47 +#endif + +#define SSP_PCAP_LED_MASK 0x000fffe0 +#define SSP_PCAP_LED_SHIFT 5 + +#define VERSION "1.0" + +//#define DEBUG_LED_DRIVER + +#ifdef DEBUG_LED_DRIVER +#define PRINTK(s...) printk(s) +#else +#define PRINTK(s...) +#endif +typedef struct +{ + unsigned char ind_GPIO_red; /*Indicator Red control GPIO 79: 0 active, 1 disactive*/ + unsigned char ind_GPIO_green; /*Indicator Green control GPIO 18: 0 active, 1 disactive*/ + unsigned char pcap_LEDR_en; /*pcap LEDR_EN bit value: 1 =Red LED(&Green) + sink circuit enabled*/ + unsigned char pcap_LEDG_en; /*pcap LEDG_EN bit value:1 =Green(->Blue)LED + sink circuit enabled*/ + unsigned char pcap_LEDR_CTRL; /* 4bits Sets the timing for the red(&Green) LED + sink circuit*/ + unsigned char pcap_LEDG_CTRL; /* 4bits Sets the timing for the GREEN (->Blue) LED + sink circuit*/ + unsigned char pcap_LEDR_I; /* 2 bits 00 3mA,01 4mA, 10 5mA, 11 9mA */ + /* sets the pulsed current level for LEDR*/ + unsigned char pcap_LEDG_I; + unsigned char pcap_SKIP_on; /*1=The ON timing sequence defined by LEDx_CTRL + is executed on every other cycle*/ +}PCAP2_LED_REGISTER_VALUE; + +const PCAP2_LED_REGISTER_VALUE led_register_value [LED_BOTTOM_STATE +1 ]= +{ + {0x1,0x1, 0x0,0x0, 0x0,0x0, 0x0,0x0,0x0}, /*LED_OFF*/ + + /*Always On*/ + {0x0,0x1, 0x1,0x0, 0xc,0x0, 0x1,0x0,0x0}, /*LED_RED_ALWAYS_ON,skip off*/ + {0x1,0x0, 0x1,0x0, 0xc,0x0, 0x1,0x0,0x0}, /*LED_GREEN_ALWAYS_ON*/ + {0x1,0x1, 0x0,0x1, 0x0,0xc, 0x0,0x0,0x0}, /*LED_BLUE_ALWAYS_ON*/ + {0x0,0x1, 0x1,0x1, 0xc,0xc, 0x1,0x0,0x0}, /*LED_LIGHT_RED_ALWAYS_ON*/ + {0x0,0x0, 0x1,0x0, 0xc,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_ALWAYS_ON*/ + {0x1,0x0, 0x1,0x1, 0xc,0xc, 0x1,0x0,0x0}, /*LED_LIGHT_BLUE_ALWAYS_ON*/ + {0x0,0x0, 0x1,0x1, 0xc,0xc, 0x1,0x0,0x0}, /*LED_WHITE_ALWAYS_ON*/ + + /* RED 5 mA current Skip OFF*/ + {0x0,0x1, 0x1,0x0, 0x1,0x0, 0x1,0x0,0x0}, /*LED_RED_01_ON_19_OFF,skip off*/ + {0x0,0x1, 0x1,0x0, 0x2,0x0, 0x1,0x0,0x0}, /*LED_RED_02_ON_18_OFF*/ + {0x0,0x1, 0x1,0x0, 0x3,0x0, 0x1,0x0,0x0}, /*LED_RED_05_ON_15_OFF*/ + {0x0,0x1, 0x1,0x0, 0x4,0x0, 0x1,0x0,0x0}, /*LED_RED_025_ON_075_OFF*/ + {0x0,0x1, 0x1,0x0, 0x5,0x0, 0x1,0x0,0x0}, /*LED_RED_025_ON_175_OFF*/ + {0x0,0x1, 0x1,0x0, 0x6,0x0, 0x1,0x0,0x0}, /*LED_RED_005_ON_195_OFF*/ + {0x0,0x1, 0x1,0x0, 0x7,0x0, 0x1,0x0,0x0}, /*LED_RED_05_ON_05_OFF*/ + {0x0,0x1, 0x1,0x0, 0x8,0x0, 0x1,0x0,0x0}, /*LED_RED_05_OFF_05_ON*/ + {0x0,0x1, 0x1,0x0, 0x9,0x0, 0x1,0x0,0x0}, /*LED_RED_0125_ON_05_OFF_0075_ON_15_OFF*/ + {0x0,0x1, 0x1,0x0, 0xa,0x0, 0x1,0x0,0x0}, /*LED_RED_0125_ON_2075_OFF*/ + {0x0,0x1, 0x1,0x0, 0xb,0x0, 0x1,0x0,0x0}, /*LED_RED_0625_OFF_0075_ON_15_OFF*/ + + /* RED Skip ON*/ + {0x0,0x1, 0x1,0x0, 0x1,0x0, 0x1,0x0,0x1}, /*LED_RED_01_ON_19_OFF,skip On*/ + {0x0,0x1, 0x1,0x0, 0x2,0x0, 0x1,0x0,0x1}, /*LED_RED_02_ON_18_OFF*/ + {0x0,0x1, 0x1,0x0, 0x3,0x0, 0x1,0x0,0x1}, /*LED_RED_05_ON_15_OFF*/ + {0x0,0x1, 0x1,0x0, 0x4,0x0, 0x1,0x0,0x1}, /*LED_RED_025_ON_075_OFF*/ + {0x0,0x1, 0x1,0x0, 0x5,0x0, 0x1,0x0,0x1}, /*LED_RED_025_ON_175_OFF*/ + {0x0,0x1, 0x1,0x0, 0x6,0x0, 0x1,0x0,0x1}, /*LED_RED_005_ON_195_OFF*/ + {0x0,0x1, 0x1,0x0, 0x7,0x0, 0x1,0x0,0x1}, /*LED_RED_05_ON_05_OFF*/ + {0x0,0x1, 0x1,0x0, 0x8,0x0, 0x1,0x0,0x1}, /*LED_RED_05_OFF_05_ON*/ + {0x0,0x1, 0x1,0x0, 0x9,0x0, 0x1,0x0,0x1}, /*LED_RED_0125_ON_05_OFF_0075_ON_15_OFF*/ + {0x0,0x1, 0x1,0x0, 0xa,0x0, 0x1,0x0,0x1}, /*LED_RED_0125_ON_2075_OFF*/ + {0x0,0x1, 0x1,0x0, 0xb,0x0, 0x1,0x0,0x1}, /*LED_RED_0625_OFF_0075_ON_15_OFF*/ + + /*GREEN Skip OFF*/ + {0x1,0x0, 0x1,0x0, 0x1,0x0, 0x1,0x0,0x0}, /*LED_GREEN_01_ON_19_OFF,skip off*/ + {0x1,0x0, 0x1,0x0, 0x2,0x0, 0x1,0x0,0x0}, /*LED_GREEN_02_ON_18_OFF*/ + {0x1,0x0, 0x1,0x0, 0x3,0x0, 0x1,0x0,0x0}, /*LED_GREEN_05_ON_15_OFF*/ + {0x1,0x0, 0x1,0x0, 0x4,0x0, 0x1,0x0,0x0}, /*LED_GREEN_025_ON_075_OFF*/ + {0x1,0x0, 0x1,0x0, 0x5,0x0, 0x1,0x0,0x0}, /*LED_GREEN_025_ON_175_OFF*/ + {0x1,0x0, 0x1,0x0, 0x6,0x0, 0x1,0x0,0x0}, /*LED_GREEN_005_ON_195_OFF*/ + {0x1,0x0, 0x1,0x0, 0x7,0x0, 0x1,0x0,0x0}, /*LED_GREEN_05_ON_05_OFF*/ + {0x1,0x0, 0x1,0x0, 0x8,0x0, 0x1,0x0,0x0}, /*LED_GREEN_05_OFF_05_ON*/ + {0x1,0x0, 0x1,0x0, 0x9,0x0, 0x1,0x0,0x0}, /*LED_GREEN_0125_ON_05_OFF_0075_ON_15_OFF*/ + {0x1,0x0, 0x1,0x0, 0xa,0x0, 0x1,0x0,0x0}, /*LED_GREEN_0125_ON_2075_OFF*/ + {0x1,0x0, 0x1,0x0, 0xb,0x0, 0x1,0x0,0x0}, /*LED_GREEN_0625_OFF_0075_ON_15_OFF*/ + + /*GREEN Skip ON*/ + {0x1,0x0, 0x1,0x0, 0x1,0x0, 0x1,0x0,0x1}, /*LED_GREEN_01_ON_19_OFF,skip On*/ + {0x1,0x0, 0x1,0x0, 0x2,0x0, 0x1,0x0,0x1}, /*LED_GREEN_02_ON_18_OFF*/ + {0x1,0x0, 0x1,0x0, 0x3,0x0, 0x1,0x0,0x1}, /*LED_GREEN_05_ON_15_OFF*/ + {0x1,0x0, 0x1,0x0, 0x4,0x0, 0x1,0x0,0x1}, /*LED_GREEN_025_ON_075_OFF*/ + {0x1,0x0, 0x1,0x0, 0x5,0x0, 0x1,0x0,0x1}, /*LED_GREEN_025_ON_175_OFF*/ + {0x1,0x0, 0x1,0x0, 0x6,0x0, 0x1,0x0,0x1}, /*LED_GREEN_005_ON_195_OFF*/ + {0x1,0x0, 0x1,0x0, 0x7,0x0, 0x1,0x0,0x1}, /*LED_GREEN_05_ON_05_OFF*/ + {0x1,0x0, 0x1,0x0, 0x8,0x0, 0x1,0x0,0x1}, /*LED_GREEN_05_OFF_05_ON*/ + {0x1,0x0, 0x1,0x0, 0x9,0x0, 0x1,0x0,0x1}, /*LED_GREEN_0125_ON_05_OFF_0075_ON_15_OFF*/ + {0x1,0x0, 0x1,0x0, 0xa,0x0, 0x1,0x0,0x1}, /*LED_GREEN_0125_ON_2075_OFF*/ + {0x1,0x0, 0x1,0x0, 0xb,0x0, 0x1,0x0,0x1}, /*LED_GREEN_0625_OFF_0075_ON_15_OFF*/ + + /*BLUE 5 mA Current Skip OFF*/ + {0x1,0x1, 0x0,0x1, 0x0,0x1, 0x0,0x0,0x0}, /*LED_BLUE_01_ON_19_OFF,skip off*/ + {0x1,0x1, 0x0,0x1, 0x0,0x2, 0x0,0x0,0x0}, /*LED_BLUE_02_ON_18_OFF*/ + {0x1,0x1, 0x0,0x1, 0x0,0x3, 0x0,0x0,0x0}, /*LED_BLUE_05_ON_15_OFF*/ + {0x1,0x1, 0x0,0x1, 0x0,0x4, 0x0,0x0,0x0}, /*LED_BLUE_025_ON_075_OFF*/ + {0x1,0x1, 0x0,0x1, 0x0,0x5, 0x0,0x0,0x0}, /*LED_BLUE_025_ON_175_OFF*/ + {0x1,0x1, 0x0,0x1, 0x0,0x6, 0x0,0x0,0x0}, /*LED_BLUE_005_ON_195_OFF*/ + {0x1,0x1, 0x0,0x1, 0x0,0x7, 0x0,0x0,0x0}, /*LED_BLUE_05_ON_05_OFF*/ + {0x1,0x1, 0x0,0x1, 0x0,0x8, 0x0,0x0,0x0}, /*LED_BLUE_05_OFF_05_ON*/ + {0x1,0x1, 0x0,0x1, 0x0,0x9, 0x0,0x0,0x0}, /*LED_BLUE_0125_ON_05_OFF_0075_ON_15_OFF*/ + {0x1,0x1, 0x0,0x1, 0x0,0xa, 0x0,0x0,0x0}, /*LED_BLUE_0125_ON_2075_OFF*/ + {0x1,0x1, 0x0,0x1, 0x0,0xb, 0x0,0x0,0x0}, /*LED_BLUE_0625_OFF_0075_ON_15_OFF*/ + + /*BLUE 5 mA Current Skip On*/ + {0x1,0x1, 0x0,0x1, 0x0,0x1, 0x0,0x0,0x1}, /*LED_BLUE_01_ON_19_OFF,skip On*/ + {0x1,0x1, 0x0,0x1, 0x0,0x2, 0x0,0x0,0x1}, /*LED_BLUE_02_ON_18_OFF*/ + {0x1,0x1, 0x0,0x1, 0x0,0x3, 0x0,0x0,0x1}, /*LED_BLUE_05_ON_15_OFF*/ + {0x1,0x1, 0x0,0x1, 0x0,0x4, 0x0,0x0,0x1}, /*LED_BLUE_025_ON_075_OFF*/ + {0x1,0x1, 0x0,0x1, 0x0,0x5, 0x0,0x0,0x1}, /*LED_BLUE_025_ON_175_OFF*/ + {0x1,0x1, 0x0,0x1, 0x0,0x6, 0x0,0x0,0x1}, /*LED_BLUE_005_ON_195_OFF*/ + {0x1,0x1, 0x0,0x1, 0x0,0x7, 0x0,0x0,0x1}, /*LED_BLUE_05_ON_05_OFF*/ + {0x1,0x1, 0x0,0x1, 0x0,0x8, 0x0,0x0,0x1}, /*LED_BLUE_05_OFF_05_ON*/ + {0x1,0x1, 0x0,0x1, 0x0,0x9, 0x0,0x0,0x1}, /*LED_BLUE_0125_ON_05_OFF_0075_ON_15_OFF*/ + {0x1,0x1, 0x0,0x1, 0x0,0xa, 0x0,0x0,0x1}, /*LED_BLUE_0125_ON_2075_OFF*/ + {0x1,0x1, 0x0,0x1, 0x0,0xb, 0x0,0x0,0x1}, /*LED_BLUE_0625_OFF_0075_ON_15_OFF*/ + + /*ORANGE 5 mA Current Skip OFF*/ + {0x0,0x0, 0x1,0x0, 0x1,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_01_ON_19_OFF,skip off*/ + {0x0,0x0, 0x1,0x0, 0x2,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_02_ON_18_OFF*/ + {0x0,0x0, 0x1,0x0, 0x3,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_05_ON_15_OFF*/ + {0x0,0x0, 0x1,0x0, 0x4,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_025_ON_075_OFF*/ + {0x0,0x0, 0x1,0x0, 0x5,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_025_ON_175_OFF*/ + {0x0,0x0, 0x1,0x0, 0x6,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_005_ON_195_OFF*/ + {0x0,0x0, 0x1,0x0, 0x7,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_05_ON_05_OFF*/ + {0x0,0x0, 0x1,0x0, 0x8,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_05_OFF_05_ON*/ + {0x0,0x0, 0x1,0x0, 0x9,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_0125_ON_05_OFF_0075_ON_15_OFF*/ + {0x0,0x0, 0x1,0x0, 0xa,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_0125_ON_2075_OFF*/ + {0x0,0x0, 0x1,0x0, 0xb,0x0, 0x1,0x0,0x0}, /*LED_ORANGE_0625_OFF_0075_ON_15_OFF*/ + + /*ORANGE 5 mA current Skip On*/ + {0x0,0x0, 0x1,0x0, 0x1,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_01_ON_19_OFF,skip On*/ + {0x0,0x0, 0x1,0x0, 0x2,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_02_ON_18_OFF*/ + {0x0,0x0, 0x1,0x0, 0x3,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_05_ON_15_OFF*/ + {0x0,0x0, 0x1,0x0, 0x4,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_025_ON_075_OFF*/ + {0x0,0x0, 0x1,0x0, 0x5,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_025_ON_175_OFF*/ + {0x0,0x0, 0x1,0x0, 0x6,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_005_ON_195_OFF*/ + {0x0,0x0, 0x1,0x0, 0x7,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_05_ON_05_OFF*/ + {0x0,0x0, 0x1,0x0, 0x8,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_05_OFF_05_ON*/ + {0x0,0x0, 0x1,0x0, 0x9,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_0125_ON_05_OFF_0075_ON_15_OFF*/ + {0x0,0x0, 0x1,0x0, 0xa,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_0125_ON_2075_OFF*/ + {0x0,0x0, 0x1,0x0, 0xb,0x0, 0x1,0x0,0x1}, /*LED_ORANGE_0625_OFF_0075_ON_15_OFF*/ + + /*LED_RED_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF*/ + {0x0,0x1, 0x1,0x1, 0xa,0xb, 0x1,0x0,0x0}, + /*LED_GREEN_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF*/ + {0x1,0x0, 0x1,0x1, 0xa,0xb, 0x1,0x0,0x0}, + /*LED_ORANGE_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF*/ + {0x0,0x0, 0x1,0x1, 0xa,0xb, 0x1,0x0,0x0}, + + /*LED_RED_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF_SKIP*/ + {0x0,0x1, 0x1,0x1, 0xa,0xb, 0x1,0x0,0x1}, + /*LED_GREEN_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF_SKIP*/ + {0x1,0x0, 0x1,0x1, 0xa,0xb, 0x1,0x0,0x1}, + /*LED_ORANGE_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF_SKIP*/ + {0x0,0x0, 0x1,0x1, 0xa,0xb, 0x1,0x0,0x1}, + + {0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +#ifdef DEBUG_LED_DRIVER +char LED_Name[LED_BOTTOM_STATE +1][100]= +{ + "LED_OFF", + + "LED_RED_ALWAYS_ON", + "LED_GREEN_ALWAYS_ON", + "LED_BLUE_ALWAYS_ON", + "LED_LIGHT_RED_ALWAYS_ON", + "LED_ORANGE_ALWAYS_ON", + "LED_LIGHT_BLUE_ALWAYS_ON", + "LED_WHITE_ALWAYS_ON", + + "LED_RED_01_ON_19_OFF", + "LED_RED_02_ON_18_OFF", + "LED_RED_05_ON_15_OFF", + "LED_RED_025_ON_075_OFF", + "LED_RED_025_ON_175_OFF", + "LED_RED_005_ON_195_OFF", + "LED_RED_05_ON_05_OFF", + "LED_RED_05_OFF_05_ON", + "LED_RED_0125_ON_05_OFF_0075_ON_15_OFF", + "LED_RED_0125_ON_2075_OFF", + "LED_RED_0625_OFF_0075_ON_15_OFF", + + "LED_RED_01_ON_19_OFF_SKIP", + "LED_RED_02_ON_18_OFF_SKIP", + "LED_RED_05_ON_15_OFF_SKIP", + "LED_RED_025_ON_075_OFF_SKIP", + "LED_RED_025_ON_175_OFF_SKIP", + "LED_RED_005_ON_195_OFF_SKIP", + "LED_RED_05_ON_05_OFF_SKIP", + "LED_RED_05_OFF_05_ON_SKIP", + "LED_RED_0125_ON_05_OFF_0075_ON_15_OFF_SKIP", + "LED_RED_0125_ON_2075_OFF_SKIP", + "LED_RED_0625_OFF_0075_ON_15_OFF_SKIP", + + "LED_GREEN_01_ON_19_OFF", + "LED_GREEN_02_ON_18_OFF", + "LED_GREEN_05_ON_15_OFF", + "LED_GREEN_025_ON_075_OFF", + "LED_GREEN_025_ON_175_OFF", + "LED_GREEN_005_ON_195_OFF", + "LED_GREEN_05_ON_05_OFF", + "LED_GREEN_05_OFF_05_ON", + "LED_GREEN_0125_ON_05_OFF_0075_ON_15_OFF", + "LED_GREEN_0125_ON_2075_OFF", + "LED_GREEN_0625_OFF_0075_ON_15_OFF", + + "LED_GREEN_01_ON_19_OFF_SKIP", + "LED_GREEN_02_ON_18_OFF_SKIP", + "LED_GREEN_05_ON_15_OFF_SKIP", + "LED_GREEN_025_ON_075_OFF_SKIP", + "LED_GREEN_025_ON_175_OFF_SKIP", + "LED_GREEN_005_ON_195_OFF_SKIP", + "LED_GREEN_05_ON_05_OFF_SKIP", + "LED_GREEN_05_OFF_05_ON_SKIP", + "LED_GREEN_0125_ON_05_OFF_0075_ON_15_OFF_SKIP", + "LED_GREEN_0125_ON_2075_OFF_SKIP", + "LED_GREEN_0625_OFF_0075_ON_15_OFF_SKIP", + + "LED_BLUE_01_ON_19_OFF", + "LED_BLUE_02_ON_18_OFF", + "LED_BLUE_05_ON_15_OFF", + "LED_BLUE_025_ON_075_OFF", + "LED_BLUE_025_ON_175_OFF", + "LED_BLUE_005_ON_195_OFF", + "LED_BLUE_05_ON_05_OFF", + "LED_BLUE_05_OFF_05_ON", + "LED_BLUE_0125_ON_05_OFF_0075_ON_15_OFF", + "LED_BLUE_0125_ON_2075_OFF", + "LED_BLUE_0625_OFF_0075_ON_15_OFF", + + "LED_BLUE_01_ON_19_OFF_SKIP", + "LED_BLUE_02_ON_18_OFF_SKIP", + "LED_BLUE_05_ON_15_OFF_SKIP", + "LED_BLUE_025_ON_075_OFF_SKIP", + "LED_BLUE_025_ON_175_OFF_SKIP", + "LED_BLUE_005_ON_195_OFF_SKIP", + "LED_BLUE_05_ON_05_OFF_SKIP", + "LED_BLUE_05_OFF_05_ON_SKIP", + "LED_BLUE_0125_ON_05_OFF_0075_ON_15_OFF_SKIP", + "LED_BLUE_0125_ON_2075_OFF_SKIP", + "LED_BLUE_0625_OFF_0075_ON_15_OFF_SKIP", + + "LED_ORANGE_01_ON_19_OFF", + "LED_ORANGE_02_ON_18_OFF", + "LED_ORANGE_05_ON_15_OFF", + "LED_ORANGE_025_ON_075_OFF", + "LED_ORANGE_025_ON_175_OFF", + "LED_ORANGE_005_ON_195_OFF", + "LED_ORANGE_05_ON_05_OFF", + "LED_ORANGE_05_OFF_05_ON", + "LED_ORANGE_0125_ON_05_OFF_0075_ON_15_OFF", + "LED_ORANGE_0125_ON_2075_OFF", + "LED_ORANGE_0625_OFF_0075_ON_15_OFF", + + "LED_ORANGE_01_ON_19_OFF_SKIP", + "LED_ORANGE_02_ON_18_OFF_SKIP", + "LED_ORANGE_05_ON_15_OFF_SKIP", + "LED_ORANGE_025_ON_075_OFF_SKIP", + "LED_ORANGE_025_ON_175_OFF_SKIP", + "LED_ORANGE_005_ON_195_OFF_SKIP", + "LED_ORANGE_05_ON_05_OFF_SKIP", + "LED_ORANGE_05_OFF_05_ON_SKIP", + "LED_ORANGE_0125_ON_05_OFF_0075_ON_15_OFF_SKIP", + "LED_ORANGE_0125_ON_2075_OFF_SKIP", + "LED_ORANGE_0625_OFF_0075_ON_15_OFF_SKIP", + + "LED_RED_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF", + "LED_GREEN_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF", + "LED_ORANGE_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF", + + + "LED_RED_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF_SKIP", + "LED_GREEN_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF_SKIP", + "LED_ORANGE_0125_ON_2075_OFF_BLUE_0625_OFF_0075_ON_15_OFF_SKIP", + "" +}; /* LED Name*/ +#endif +/* These are the control structures for the LEDs. */ +static struct led_info info1; +static struct led_reg_info led1; +static int old_state ; +static unsigned int old_tempValue; +static struct pm_dev *led_pxa_pm_dev; +/*--------------------------------------------------------------------------- +DESCRIPTION: Set LED state. +INPUTS: int state LED light mode. +OUTPUTS: int 0, succesee else return error no. +IMPORTANT NOTES: +To prevent RED to GREEN phase timing issues, the RED and Green LED bit codes should be written +simultaneously. Additionally, changing the timing of one or both drivers should be accomplished by first writing a +zero to each bit location, followed by a write to both locations with the desired bits. + +---------------------------------------------------------------------------*/ +int PXA_E680_LED_set(int state) +{ + unsigned char ledr_en,ledg_en,ledr_ctrl,ledg_ctrl,ledr_i,ledg_i,skip; + unsigned int tempValue, value =0; + + if ( state >= LED_BOTTOM_STATE) + { + PRINTK("Driver:LED The State is invalid.\n"); + return 1; + } + else if ( old_state == state) + { + PRINTK("Driver:LED Same to previous State %s.\n",LED_Name[state]); + return 0; /*Donn't need change the LED state.*/ + } + /*First Disable LED.*/ + if(SSP_PCAP_read_data_from_PCAP(SSP_PCAP_ADJ_PERIPH_REGISTER,&tempValue)!= + SSP_PCAP_SUCCESS) + { + PRINTK("Driver:LED PCAP Read Failed.\n"); + return 1; + } + tempValue &= (~SSP_PCAP_LED_MASK); + if(SSP_PCAP_write_data_to_PCAP(SSP_PCAP_ADJ_PERIPH_REGISTER,tempValue)!=SSP_PCAP_SUCCESS) + { + PRINTK("Driver:LED PCAP Write Failed (Clear Data).\n"); + return 1; + } + + /*Set GPIO as general I/O and as output*/ + set_GPIO_mode(IND_CNTL_R_BUL | GPIO_OUT); + set_GPIO_mode(IND_CNTL_G_BUL | GPIO_OUT); + + if (led_register_value[state].ind_GPIO_red && led_register_value[state].ind_GPIO_green) + { + /*Disable Red & Green signal*/ + set_GPIO(IND_CNTL_R_BUL); /*IND_CNTL_R_BUL Low active*/ + PGSR(IND_CNTL_R_BUL) = PGSR(IND_CNTL_R_BUL) | GPIO_bit(IND_CNTL_R_BUL); + + clr_GPIO(IND_CNTL_G_BUL); /*IND_CNTL_G_BUL High active*/ + PGSR(IND_CNTL_G_BUL) = PGSR(IND_CNTL_G_BUL) & (~GPIO_bit(IND_CNTL_G_BUL)); + + PRINTK("GPIO Green Disable, Red Disable!\n"); + }else if ( (!led_register_value[state].ind_GPIO_red) && + led_register_value[state].ind_GPIO_green) + { + /*Green Disable, Red Enable*/ + clr_GPIO(IND_CNTL_R_BUL); + PGSR(IND_CNTL_R_BUL) = PGSR(IND_CNTL_R_BUL) & (~GPIO_bit(IND_CNTL_R_BUL)); + + clr_GPIO(IND_CNTL_G_BUL); + PGSR(IND_CNTL_G_BUL) = PGSR(IND_CNTL_G_BUL) & (~GPIO_bit(IND_CNTL_G_BUL)); + + PRINTK("GPIO Green Disable, Red Enable!\n"); + }else if ( led_register_value[state].ind_GPIO_red && + !led_register_value[state].ind_GPIO_green) + { + /*Red Disable, Green Enable*/ + set_GPIO(IND_CNTL_R_BUL); + PGSR(IND_CNTL_R_BUL) = PGSR(IND_CNTL_R_BUL) | GPIO_bit(IND_CNTL_R_BUL); + + set_GPIO(IND_CNTL_G_BUL); + PGSR(IND_CNTL_G_BUL) = PGSR(IND_CNTL_G_BUL) | GPIO_bit(IND_CNTL_G_BUL); + PRINTK("GPIO Red Disable, Green Enable"); + }else + { + /*Red & Green enable*/ + clr_GPIO(IND_CNTL_R_BUL); + PGSR(IND_CNTL_R_BUL) = PGSR(IND_CNTL_R_BUL) & (~GPIO_bit(IND_CNTL_R_BUL)); + + set_GPIO(IND_CNTL_G_BUL); + PGSR(IND_CNTL_G_BUL) = PGSR(IND_CNTL_G_BUL) | GPIO_bit(IND_CNTL_G_BUL); + PRINTK("GPIO Red & Green enable!\n"); + } + PRINTK("Driver:--IND_CNTL_G_BUL:%x IND_CNTL_R_BUL:%x\n",GPIO_is_high(IND_CNTL_G_BUL), + GPIO_is_high(IND_CNTL_R_BUL)); + /* Write PCAP Peripheral Control Register*/ + ledr_en = led_register_value[state].pcap_LEDR_en & 0x1; + ledg_en = led_register_value[state].pcap_LEDG_en & 0x1; + ledr_ctrl = led_register_value[state].pcap_LEDR_CTRL & 0xf; + ledg_ctrl = led_register_value[state].pcap_LEDG_CTRL & 0xf; + ledr_i = led_register_value[state].pcap_LEDR_I & 0x3; + ledg_i = led_register_value[state].pcap_LEDG_I & 0x3; + skip = led_register_value[state].pcap_SKIP_on & 0x1; + + value = ( ledr_en | (ledg_en <<1) | (ledr_ctrl <<2) | (ledg_ctrl <<6) | + (ledr_i << 10) | (ledg_i <<12) | (skip <<14) ) & 0x7fff; + tempValue |= (value <op) + { + case SET_LED: + if ( PXA_E680_LED_set(op->op_info.bicolor.color) == 0) + return 0; + else + return -EINVAL; + default: + PRINTK("LED:Error CMD.\n"); + return -EINVAL; + } +} + +/** + * PXA_E680_LED_exit: + * + * Remove the LEDs from the LED driver + */ + +static void __exit PXA_E680_LED_exit(void) +{ + pm_unregister(led_pxa_pm_dev); + unregister_led_info(&led1); +} + +/** + * PXA_E680_LED_init + * + * Register the LEDs with the LED driver. + */ + +static int __init PXA_E680_LED_init(void) +{ + info1.type = LED_TYPE_BICOLOR; + strcpy(info1.name, LED_E680_NAME); + led1.info = &info1; + led1.data = (void *) 0; + led1.handle_led_op = handle_led_op; + register_led_info(&led1); + + old_state = LED_OFF; + old_tempValue = 0; + led_pxa_pm_dev = pm_register(PM_UNKNOWN_DEV, PM_SYS_UNKNOWN, PXA_E680_LED_retore_PGSR); + + /*Set GPIO as general IO and as Output*/ + set_GPIO_mode(IND_CNTL_R_BUL | GPIO_OUT); + set_GPIO_mode(IND_CNTL_G_BUL | GPIO_OUT); + + set_GPIO(IND_CNTL_R_BUL); + PGSR(IND_CNTL_R_BUL) = PGSR(IND_CNTL_R_BUL) | GPIO_bit(IND_CNTL_R_BUL); + + clr_GPIO(IND_CNTL_G_BUL); + PGSR(IND_CNTL_G_BUL) = PGSR(IND_CNTL_G_BUL) & (~GPIO_bit(IND_CNTL_G_BUL)); + PRINTK("PCAP2 LED driver: v%s E680\n", VERSION); + return 0; +} + +module_init(PXA_E680_LED_init); +module_exit(PXA_E680_LED_exit); +MODULE_LICENSE("GPL"); Index: linux-2.6.16.5-a/drivers/char/mstone_keypad.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/char/mstone_keypad.c 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,581 @@ +/* + * linux/driver/char/mstone_keypad.c + * Keypad driver for Intel Mainstone development board + * + * Copyright (C) 2003, Intel Corporation (yu.tang@intel.com) + * Copyright 2003 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * source@mvista.com + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Direct-KEY scan-code for Mainstone-I Board */ +#define ROTARY_DEFAULT 0x7F +#define NO_KEY 0xFF +#define SCAN_CODE_SCROLL_UP 0xA +#define SCAN_CODE_SCROLL_DOWN 0xB +#define SCAN_CODE_ACTION 0xC + +DECLARE_MUTEX(kpdrv_mutex); +static struct kpe_queue kpe_queue; +static int kpdrv_refcount = 0; + +//#define DEBUG 1 +#if DEBUG +static unsigned int mstone_keypad_dbg = 1; +#else +#define mstone_keypad_dbg 0 +#endif + +#ifdef CONFIG_DPM +#include + +static int pxakpd_suspend(struct device *dev, u32 state, u32 level); +static int pxakpd_resume(struct device *dev, u32 level); +static int pxakpd_scale(struct bus_op_point *op, u32 level); + +static struct device_driver pxakpd_driver_ldm = { + name: "pxa-kpd", + devclass: NULL, + probe: NULL, + suspend: pxakpd_suspend, + resume: pxakpd_resume, + scale: pxakpd_scale, + remove: NULL, + constraints: NULL, +}; + +static struct device pxakpd_device_ldm = { + name: "PXA Keypad", + bus_id: "pxakpd", + driver: NULL, + power_state: DPM_POWER_ON, +}; + +static void +pxakpd_ldm_register(void) +{ + extern void pxaopb_driver_register(struct device_driver *driver); + extern void pxaopb_device_register(struct device *device); + + pxaopb_driver_register(&pxakpd_driver_ldm); + pxaopb_device_register(&pxakpd_device_ldm); +} + +static void +pxakpd_ldm_unregister(void) +{ + extern void pxaopb_driver_unregister(struct device_driver *driver); + extern void pxaopb_device_unregister(struct device *device); + + pxaopb_device_unregister(&pxakpd_device_ldm); + pxaopb_driver_unregister(&pxakpd_driver_ldm); +} + +static int +pxakpd_resume(struct device *dev, u32 level) +{ + if (mstone_keypad_dbg) + printk("+++: in pxakpd_resume()\n"); + + switch (level) { + case RESUME_POWER_ON: + /* enable direct and matrix interrupts */ + KPC |= (KPC_DIE | KPC_MIE); + + /* enable clock to keypad */ + CKEN |= CKEN19_KEYPAD; + { + struct kp_event kpe; + unsigned char c; + + kpe.flags |= (KP_DIRECT | KP_MATRIX ); + c = get_scancode(&kpe); + if (c != NO_KEY) { + /* Insert it into key event list. */ + kpq_put(&kpe); + } + else { + /* We are not woke by key press. */ + } + } + break; + } + + return 0; +} + +static int +pxakpd_suspend(struct device *dev, u32 state, u32 level) +{ + if (mstone_keypad_dbg) + printk("+++: in pxakpd_suspend()\n"); + + switch (level) { + case SUSPEND_POWER_DOWN: + /* disable clock to keypad */ + CKEN &= ~CKEN19_KEYPAD; + + /* disable direct and matrix interrupts */ + KPC &= ~(KPC_DIE | KPC_MIE); + break; + } + + return 0; +} + +static int +pxakpd_scale(struct bus_op_point *op, u32 level) +{ + printk("+++: in pxakpd_scale()\n"); + + return 0; +} +#endif /* CONFIG_DPM */ + +/* Init kpe queue */ +static void kpq_init(void) +{ + kpe_queue.head = kpe_queue.tail = kpe_queue.len = 0; + kpe_queue.spinlock = SPIN_LOCK_UNLOCKED; + init_waitqueue_head(&kpe_queue.waitq); +} + +static int kpq_empty(void) +{ + int flags, empty; + + spin_lock_irqsave(&kpe_queue.spinlock,flags); + empty = kpe_queue.len ? 0 : 1; + spin_unlock_irqrestore(&kpe_queue.spinlock, flags); + + return empty; +} + +static int kpq_get(struct kp_event *kpe) +{ + int flags, err = 0; + + spin_lock_irqsave(&kpe_queue.spinlock, flags); + if (kpe_queue.head == kpe_queue.tail) { + printk(KERN_ERR "keypad: empty event queue, looks bad\n"); + err = -EAGAIN; + goto out; + } + memcpy(kpe, kpe_queue.kpes + kpe_queue.tail, sizeof(struct kp_event)); + kpe_queue.len--; + kpe_queue.tail = (kpe_queue.tail + 1) % MAX_KPES; + out: + spin_unlock_irqrestore(&kpe_queue.spinlock, flags); + return err; +} + +static void kpq_put(struct kp_event *kpe) +{ + int flags; + + spin_lock_irqsave(&kpe_queue.spinlock, flags); + memcpy(kpe_queue.kpes + kpe_queue.head, kpe, sizeof(struct kp_event)); + kpe_queue.len++; + if (kpe_queue.len == MAX_KPES) { + printk(KERN_ERR "keypad: events are comes too fast, will discard next\n"); + kpe_queue.len--; + goto out; + } + kpe_queue.head = (kpe_queue.head + 1) % MAX_KPES; + out: + spin_unlock_irqrestore(&kpe_queue.spinlock, flags); + /* Wake up the waiting processes */ + wake_up_interruptible(&kpe_queue.waitq); +} + +static int kp_direct_scan(struct kp_event *kpe) +{ + kpe->flags |= KP_DIRECT; + kpe->direct = KPDK; + kpe->rotary = KPREC; + return 0; +} + +static int kp_matrix_scan(struct kp_event *kpe) +{ + KPC |= KPC_AS; + while (KPAS &KPAS_SO); + + kpe->flags |= KP_MATRIX; + kpe->matrix[0] = KPAS; + kpe->matrix[1] = KPASMKP0; + kpe->matrix[2] = KPASMKP1; + kpe->matrix[3] = KPASMKP2; + kpe->matrix[4] = KPASMKP3; + + KPC &= ~KPC_AS; + + return 0; +} + +/* Interrupt kandler for keypad */ +static void kp_interrupt(int irq, void *ptr, struct pt_regs *regs) +{ + struct kp_event kpe = {0}; + int flags; + unsigned long kpc_val; + + printk("+++: kp_interrupt()\n"); + + spin_lock_irqsave(&kpe_queue.spinlock,flags); + + /* ACK interrupt */ + kpc_val = KPC; + kpe.jiffies = jiffies; + + /* Direct interrupt */ + if (kpc_val & KPC_DI) + kp_direct_scan(&kpe); + + /* Matrix interrupt */ + if (kpc_val & KPC_MI) + kp_matrix_scan(&kpe); + + spin_unlock_irqrestore(&kpe_queue.spinlock, flags); + + if (((kpe.flags & KP_DIRECT) || (kpe.flags & KP_MATRIX)) && kpdrv_refcount) + kpq_put(&kpe); +} + +/* Wait for keypad event, must be in task-context */ +int kp_wait(struct kp_event *kpe, signed int timeout) +{ + int n, err = 0; + + while(1) { + if (!kpq_empty()) { + n = kpq_get(kpe); + if (n < 0) + continue; + break; + } + + /* No event available ? */ + if (!timeout) { + err = -EAGAIN; + break; + } + + if (timeout > 0) { + /* Wait for timeout */ + timeout = interruptible_sleep_on_timeout(&kpe_queue.waitq, timeout); + continue; + } + else{ + /* Wait for kpevent/signal */ + while(1) { + interruptible_sleep_on(&kpe_queue.waitq); + if (kpq_empty() && !signal_pending(current)) + continue; + break; + } + + if (signal_pending(current)) { + err = -EINTR; + break; + } + } + } + return err; +} + +/* Poll for keypad event */ +unsigned int kp_poll(struct file *file, poll_table *wait) +{ + poll_wait(file, &kpe_queue.waitq, wait); + return kpq_empty() ? 0 : POLLIN | POLLRDNORM; +} + +static unsigned char get_scancode(struct kp_event *kpe) +{ + static unsigned int curr, prev = ROTARY_DEFAULT; + unsigned int c; + + c = NO_KEY; + + if (kpe->flags & KP_DIRECT) { + + curr = kpe->rotary & 0xFF; + + if (kpe->rotary & KPREC_OF0) { + KPREC &= ~KPREC_OF0; + KPREC |= ROTARY_DEFAULT; + prev = ROTARY_DEFAULT; + c = SCAN_CODE_SCROLL_UP; + } + else if (kpe->rotary & KPREC_UF0) { + KPREC &= ~KPREC_UF0; + KPREC |= ROTARY_DEFAULT; + prev = ROTARY_DEFAULT; + c = SCAN_CODE_SCROLL_DOWN; + } + else if (curr > prev) { + c = SCAN_CODE_SCROLL_UP; + prev = curr; + } + else if (curr < prev) { + c = SCAN_CODE_SCROLL_DOWN; + prev = curr; + } + else if (kpe->direct & KPDK_DK2) { + c = SCAN_CODE_ACTION; + prev = curr; + } + } + + if (kpe->flags & KP_MATRIX) { + unsigned int count = (kpe->matrix[0] >> 26) & 0x1f; + + c = kpe->matrix[0] & 0xff; + + /* Key up */ + if (!count) c |= 0x80; + } + + return c; +} + +static ssize_t kpdrv_read(struct file * filp, char * buf, + size_t count, loff_t *ppos) +{ + struct kp_event kpe; + int err,left,timeout; + unsigned char c; + + timeout = 0; + left = count; + do { + err = kp_wait(&kpe, timeout); + if (err) { + if ( left != count ) return (count-left); + + if (filp->f_flags & O_NONBLOCK) return err; + + if (timeout) return err; + + timeout = -1; + continue; + } + /* Parse if direct/matrix flags are set*/ + if ( (kpe.flags & KP_DIRECT) || (kpe.flags & KP_MATRIX) ) { + c = get_scancode(&kpe); + if (c != NO_KEY) { + put_user(c, buf++); + left --; + } + } + } while (left); + return (count-left); +} + +static int kpdrv_ioctl(struct inode *ip, struct file *fp, + unsigned int cmd, unsigned long arg) +{ + int interval = KPKDI & 0xffff; + int ign = (KPC & KPC_IMKP); + + switch(cmd) { + case KPIOGET_INTERVAL: + if (copy_to_user((void*)arg, &interval, sizeof(int))) + return -EFAULT; + break; + case KPIOGET_IGNMULTI: + if (copy_to_user((void*)arg, &ign, sizeof(int))) + return -EFAULT; + break; + case KPIOSET_INTERVAL: + if (copy_from_user(&interval, (void*)arg, sizeof(int))) + return -EFAULT; + + /* FIXME : sighting #34833, Matrix Key interval should be >10ms */ + if ( (interval & 0xff) < 10) return -EINVAL; + + KPKDI &= ~0xffff; + KPKDI |= (interval & 0xffff); + break; + case KPIOSET_IGNMULTI: + if (copy_from_user(&ign, (void*)arg, sizeof(int))) + return -EFAULT; + + if (ign) + KPC |= KPC_IMKP; + else + KPC &= ~KPC_IMKP; + + break; + + default: + /* Unknown command */ + return -EINVAL; + } + return 0; +} + +static unsigned int kpdrv_poll(struct file *filp, poll_table * wait) { + return kp_poll(filp, wait); +} + +static int kpdrv_open(struct inode *inode, struct file *filp) +{ + down(&kpdrv_mutex); + if (!kpdrv_refcount) + kpq_init(); + kpdrv_refcount++; + up(&kpdrv_mutex); + return 0; +} + +static int kpdrv_close(struct inode *inode, struct file *filp) +{ + down(&kpdrv_mutex); + kpdrv_refcount--; + up(&kpdrv_mutex); + + return 0; +} + +static struct file_operations kpdrv_fops = { + owner: THIS_MODULE, + open: kpdrv_open, + release: kpdrv_close, + read: kpdrv_read, + ioctl: kpdrv_ioctl, + poll: kpdrv_poll, +}; + + +static struct miscdevice keypad_miscdevice = { + minor: MISC_DYNAMIC_MINOR, + name: "keypad", + fops: &kpdrv_fops +}; + +static int __init kpdrv_init(void) +{ + int err; + + /* Setup gpio */ + set_GPIO_mode(93 | GPIO_ALT_FN_1_IN); + set_GPIO_mode(94 | GPIO_ALT_FN_1_IN); + set_GPIO_mode(95 | GPIO_ALT_FN_1_IN); + set_GPIO_mode(96 | GPIO_ALT_FN_1_IN); + set_GPIO_mode(97 | GPIO_ALT_FN_1_IN); + set_GPIO_mode(98 | GPIO_ALT_FN_1_IN); + set_GPIO_mode(99 | GPIO_ALT_FN_1_IN); + + set_GPIO_mode(100 | GPIO_ALT_FN_1_IN); + set_GPIO_mode(101 | GPIO_ALT_FN_1_IN); + set_GPIO_mode(102 | GPIO_ALT_FN_1_IN); + + set_GPIO_mode(103 | GPIO_ALT_FN_2_OUT); + set_GPIO_mode(104 | GPIO_ALT_FN_2_OUT); + set_GPIO_mode(105 | GPIO_ALT_FN_2_OUT); + set_GPIO_mode(106 | GPIO_ALT_FN_2_OUT); + set_GPIO_mode(107 | GPIO_ALT_FN_2_OUT); + set_GPIO_mode(108 | GPIO_ALT_FN_2_OUT); + + /* Set keypad control register */ + KPC = (KPC_ASACT | (3<<26) | (4<<23)| + KPC_ME | (2<<6) | KPC_DEE0 | KPC_DE | + KPC_MS_ALL | KPC_MIE | KPC_DIE | KPC_IMKP); + + /* Set debouce time seperately for Matrix/Direct. */ + KPKDI= 0x010A; + + /* Set scroll wheel value to mid-point value */ + KPREC= 0x7F; + + /* Enable unit clock */ + CKEN |= CKEN19_KEYPAD; + + /* Request keypad IRQ */ + err = request_irq(IRQ_KEYPAD, kp_interrupt, 0, "keypad", NULL); + if (err) { + printk (KERN_CRIT "can't register IRQ%d for keypad, error %d\n", + IRQ_KEYPAD, err); + /* Disable clock unit */ + CKEN &= ~CKEN19_KEYPAD; + return -ENODEV; + } + + /* Register driver as miscdev */ + err = misc_register(&keypad_miscdevice); + if (err) + printk(KERN_ERR "can't register keypad misc device, error %d\n", err); + else + printk(KERN_INFO "Intel Mainstone Keypad driver registered with minor %d\n", + keypad_miscdevice.minor); + +#ifdef CONFIG_DPM + pxakpd_ldm_register(); +#endif /* CONFIG_DPM */ + + return err; +} + +static void __exit kpdrv_exit(void) +{ +#ifdef CONFIG_DPM + pxakpd_ldm_unregister(); +#endif /* CONFIG_DPM */ + + /* Disable clock unit */ + CKEN &= ~CKEN19_KEYPAD; + + /* Free keypad IRQ */ + free_irq(IRQ_KEYPAD, NULL); + + /* Unregister keypad device */ + misc_deregister(&keypad_miscdevice); +} + +module_init(kpdrv_init); +module_exit(kpdrv_exit); + +MODULE_AUTHOR("Yu Tang , source@mvista.com"); +MODULE_DESCRIPTION("Intel Mainstone KEYPAD driver"); +MODULE_LICENSE("GPL"); Index: linux-2.6.16.5-a/drivers/char/n_tty.c =================================================================== --- linux-2.6.16.5-a.orig/drivers/char/n_tty.c 2006-05-04 17:06:50.000000000 +0200 +++ linux-2.6.16.5-a/drivers/char/n_tty.c 2006-05-04 17:07:04.000000000 +0200 @@ -60,6 +60,12 @@ #define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */ #define TTY_THRESHOLD_UNTHROTTLE 128 +#if defined(CONFIG_ARCH_EZX) && 0 +extern int btuart_flip_flow_ctl; +extern void rs_flip_unthrottle(struct tty_struct *tty); +#endif + + static inline unsigned char *alloc_buf(void) { gfp_t prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; @@ -957,6 +963,11 @@ n_tty_set_room(tty); +#if defined (CONFIG_ARCH_EZX) && 0 + if (tty && tth->driver.btuart) + rs_flip_unthrottle(tty); +#endif + if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) { kill_fasync(&tty->fasync, SIGIO, POLL_IN); if (waitqueue_active(&tty->read_wait)) Index: linux-2.6.16.5-a/drivers/char/sram.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/char/sram.c 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,194 @@ +/* + * linux/drivers/char/sram.c + * + * Bulverde Internal Memory character device driver + * + * Created: Sep 05, 2003 + * Copyright: MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +static unsigned long sram_base = 0; +static unsigned long sram_size = 0; + +extern int sram_access_obtain(unsigned long *pmem, unsigned long *psize); +extern int sram_access_release(unsigned long *pmem, unsigned long *psize); + +/* + * This funcion reads the SRAM memory. + * The f_pos points to the SRAM memory location. + */ +static ssize_t sram_read(struct file * file, char * buf, + size_t count, loff_t *ppos) { + unsigned long p = *ppos; + ssize_t read; + + if (p >= sram_size) + return 0; + + if (count > sram_size - p) + count = sram_size - p; + + read = 0; + + if (copy_to_user(buf, (char *)(sram_base + p), count)) + return -EFAULT; + + read += count; + *ppos += read; + + return read; +} + +static ssize_t sram_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) { + unsigned long p = *ppos; + ssize_t written; + + if (p >= sram_size) + return 0; + + if (count > sram_size - p) + count = sram_size - p; + + written = 0; + + if (copy_from_user((char *)(sram_base + p), buf, count)) + return -EFAULT; + + written += count; + *ppos += written; + + return written; +} + +static int sram_mmap(struct file * file, struct vm_area_struct * vma) { + + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + + if (((file->f_flags & O_WRONLY) != 0) || + ((file->f_flags & O_RDWR) != 0)) { + vma->vm_page_prot = (pgprot_t)PAGE_SHARED; + } else { + vma->vm_page_prot = (pgprot_t)PAGE_READONLY; + } + + /* Do not cache SRAM memory if O_SYNC flag is set */ + if ((file->f_flags & O_SYNC) != 0) { + pgprot_val(vma->vm_page_prot) &= ~L_PTE_CACHEABLE; + } + + /* Don't try to swap out physical pages.. */ + vma->vm_flags |= VM_RESERVED | VM_LOCKED; + + if (remap_page_range(vma->vm_start, SRAM_MEM_PHYS + offset, + vma->vm_end - vma->vm_start, vma->vm_page_prot)) { + return -EAGAIN; + } + + return 0; +} + + +static loff_t sram_lseek(struct file * file, loff_t offset, int orig) { + + switch (orig) { + case 0: + file->f_pos = offset; + break; + case 1: + file->f_pos += offset; + break; + case 2: + file->f_pos = SRAM_SIZE + offset; + break; + default: + return -EINVAL; + } + + if (file->f_pos < 0) { + file->f_pos = 0; + } else if (file->f_pos > SRAM_SIZE) { + file->f_pos = SRAM_SIZE; + } + + return file->f_pos; +} + +static int sram_open(struct inode * inode, struct file * filp) { + return sram_access_obtain(&sram_base, &sram_size); +} + +static int sram_release(struct inode * inode, struct file * filp) { + return sram_access_release(&sram_base, &sram_size); +} + + +static struct file_operations sram_fops = { + llseek: sram_lseek, + read: sram_read, + write: sram_write, + mmap: sram_mmap, + open: sram_open, + release: sram_release, +}; + +static struct miscdevice sram_misc = { + minor : MISC_DYNAMIC_MINOR, + name : "misc/sram", + fops : &sram_fops, +}; + +static int __init sram_chr_init(void) { + if (misc_register(&sram_misc) != 0) + { + printk(KERN_ERR "Cannot register device /dev/%s\n", + sram_misc.name); + return -EFAULT; + } + + return 0; +} + +static void __exit sram_chr_exit(void) { + misc_deregister(&sram_misc); +} + +module_init(sram_chr_init) +module_exit(sram_chr_exit) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("MontaVista Software Inc."); Index: linux-2.6.16.5-a/drivers/char/tty_io.c =================================================================== --- linux-2.6.16.5-a.orig/drivers/char/tty_io.c 2006-05-04 17:06:50.000000000 +0200 +++ linux-2.6.16.5-a/drivers/char/tty_io.c 2006-05-04 17:07:04.000000000 +0200 @@ -2772,6 +2772,14 @@ goto out; } spin_lock_irqsave(&tty->buf.lock, flags); +#if defined(CONFIG_EZX_A780) || defined(CONFIG_ARCH_EZX_E680) + if (tty && tty->driver.btuart && + ((N_TTY_BUF_SIZE - tty->read_cnt - 2) < (512 + 128))) { + schedule_delayed_work(&tty->flip.work, 1); + return; + } +#endif + while((tbuf = tty->buf.head) != NULL) { while ((count = tbuf->commit - tbuf->read) != 0) { char_buf = tbuf->char_buf_ptr + tbuf->read; Index: linux-2.6.16.5-a/drivers/misc/Kconfig =================================================================== --- linux-2.6.16.5-a.orig/drivers/misc/Kconfig 2006-05-04 17:06:50.000000000 +0200 +++ linux-2.6.16.5-a/drivers/misc/Kconfig 2006-05-04 17:07:04.000000000 +0200 @@ -30,3 +30,4 @@ endmenu +source "drivers/misc/ezx/Kconfig" Index: linux-2.6.16.5-a/drivers/misc/Makefile =================================================================== --- linux-2.6.16.5-a.orig/drivers/misc/Makefile 2006-05-04 17:06:50.000000000 +0200 +++ linux-2.6.16.5-a/drivers/misc/Makefile 2006-05-04 17:07:04.000000000 +0200 @@ -5,3 +5,4 @@ obj-$(CONFIG_IBM_ASM) += ibmasm/ obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ +obj-$(CONFIG_PXA_EZX) += ezx/ Index: linux-2.6.16.5-a/drivers/misc/ezx/Kconfig =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/misc/ezx/Kconfig 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,20 @@ +# +# Misc strange devices +# + +menu "Motorola EZX devices" + +config KEYPAD_A780 + tristate "Device driver for Motorola A780 keypad" + +config KEYPAD_E680 + tristate "Device driver for Motorola E680 keypad" + +config KEYLIGHT_A780 + tristate "Device driver for Motorola A780 keylight" + +config FMRADIO_E680 + tristate "Device driver for Motorola E680 FM Radio" + +endmenu + Index: linux-2.6.16.5-a/drivers/misc/ezx/Makefile =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/misc/ezx/Makefile 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,13 @@ + +obj-$(CONFIG_PXA_EZX) += ssp_pcap_main.o ezx-ts.o ezx-button.o ezx-emu.o + +# obj-$(CONFIG_EZX) += keypad.o keypad-panasonic.o keypad-e398.o + +obj-$(CONFIG_KEYPAD_A780) += keypad.o +obj-$(CONFIG_KEYPAD_E680) += keypad.o +obj-$(CONFIG_KEYLIGHT_A780) += keylight.o +obj-$(CONFIG_FMRADIO_E680) += fmradio.o + +obj-$(CONFIG_PANIC_LOG) += log.o +obj-$(CONFIG_ARCH_EZX) += ezx_log.o + Index: linux-2.6.16.5-a/drivers/misc/ezx/ezx-button.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/misc/ezx/ezx-button.c 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,476 @@ +/* + * linux/drivers/char/ezx-button.c --- button driver on ezx + * + * Support for the Motorola Ezx A780 Development Platform. + * + * Author: Zhou Qiong, Jay Jia + * Created: Dec 16, 2003 + * Copyright: Motorola Inc. + * + * 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. + * + * Jin Lihong(w20076) Mar.15,2004,LIBdd86574 headset judgement condition reverse + * Jin Lihong(w20076) Apr.13,2004,LIBdd96876 reorganise file header + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "ssp_pcap.h" +#include "ezx-button.h" + +#define DEBUG +#ifdef CONFIG_PM +static struct pm_dev *pm_dev; +#endif + +#define FULL(queue) ((queue.head+1==queue.tail)||(queue.head+1-NR_BUTTONS==queue.tail)) + +struct button_queue{ + unsigned short button_buffer[NR_BUTTONS]; + unsigned int head; + unsigned int tail; +}; + +static struct timer_list lockscreen_timer; +static struct timer_list answer_timer; + +static DECLARE_WAIT_QUEUE_HEAD(button_wait_queue); /* Used for blocking read */ +static struct button_queue buttonevent; + +static int answer_flag=0; +int lockscreen_flag=0; + +static int first_open=0; +static int before_emu=0; +static int before_charge_500mA=0; +static int before_charge_0mA=0; + +void usb_cable_event_handler(unsigned short cable_event) +{ + if(!FULL(buttonevent)) + { + buttonevent.button_buffer[buttonevent.head] = cable_event; + buttonevent.head = (buttonevent.head+1)%(NR_BUTTONS); + wake_up_interruptible(&button_wait_queue); + printk("usb cable event = %d\n", cable_event); + } +} + +static int button_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) +{ + int data, ret; + + switch(cmd){ +/* +*/ + case BUTTON_GET_HEADSETSTATUS: + data = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_A1SNS); + if(data) + ret = HEADSET_IN; + else + ret = HEADSET_OUT; + return put_user(ret, (int *)arg); +/* +*/ + case BUTTON_GET_FLIPSTATUS: + data = GPLR(GPIO_FLIP_PIN) & GPIO_bit(GPIO_FLIP_PIN); + if(!data) + ret = FLIP_OFF; + else + ret = FLIP_ON; + lockscreen_flag = ret; + return put_user(ret, (int *)arg); + default: + return -EINVAL; + } + return 0; +} + +static unsigned int button_poll(struct file *file, poll_table *wait) +{ + poll_wait(file, &button_wait_queue, wait); + if(buttonevent.head != buttonevent.tail) + return POLLIN | POLLRDNORM; + return 0; +} +/* + * This function is called when a user space program attempts to read + * /dev/button. It puts the device to sleep on the wait queue until + * irq handler writes some data to the buffer and flushes + * the queue, at which point it writes the data out to the device and + * returns the number of characters it has written. This function is + * reentrant, so that many processes can be attempting to read from the + * device at any one time. + */ + +static int button_read (struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + int retval = 0; + + if (buttonevent.head == buttonevent.tail) + { + add_wait_queue(&button_wait_queue, &wait); + current->state = TASK_INTERRUPTIBLE; + + while (buttonevent.head == buttonevent.tail) + { + if (file->f_flags & O_NONBLOCK) + { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) + { + retval = -ERESTARTSYS; + break; + } + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&button_wait_queue, &wait); + } + + if (retval) + return retval; + + while ((buttonevent.head != buttonevent.tail) && (retval + sizeof(unsigned short)) <= count) + { + if (copy_to_user(buffer+retval, buttonevent.button_buffer+buttonevent.tail, sizeof(unsigned short))) + return -EFAULT; + buttonevent.tail = (buttonevent.tail+1)%(NR_BUTTONS); + retval += sizeof(unsigned short); + } + + return retval; +} + +static void scan_lockscreen_button(unsigned long parameters) +{ + unsigned long data; + int bdelay = BUTTON_INTERVAL; + +#ifdef DEBUG + printk("enter scan_lockscreen_button\n"); +#endif + data = GPLR(GPIO_FLIP_PIN); + if(!(data & GPIO_bit(GPIO_FLIP_PIN))) // lockscreen - 0 + { + lockscreen_flag = 0; + if(!FULL(buttonevent)) + { + buttonevent.button_buffer[buttonevent.head] = FLIP | KEYDOWN; + buttonevent.head = (buttonevent.head+1)%(NR_BUTTONS); +#ifdef CONFIG_KEYPAD_E680 + ssp_pcap_screenlock_lock(0); +#endif + wake_up_interruptible(&button_wait_queue); +#ifdef CONFIG_APM + apm_queue_event(KRNL_FLIP_OFF); +#endif + +#ifdef DEBUG + printk("LockScreen keydown\n"); +#endif + } + } + else // lockscreen - 1 + { + lockscreen_flag = 1; + if(!FULL(buttonevent)) + { + buttonevent.button_buffer[buttonevent.head] = FLIP | KEYUP; + buttonevent.head = (buttonevent.head+1)%(NR_BUTTONS); +#ifdef CONFIG_KEYPAD_E680 + ssp_pcap_screenlock_unlock(0); +#endif + wake_up_interruptible(&button_wait_queue); +#ifdef CONFIG_APM + apm_queue_event(KRNL_FLIP_ON); +#endif + +#ifdef DEBUG + printk("LockScreen keyup\n"); +#endif + } + } +} + +static void scan_answer_button(unsigned long parameters) +{ + int ssp_pcap_bit_status; + int bdelay = BUTTON_INTERVAL; + +#ifdef DEBUG + printk("enter scan_answer_button\n"); +#endif + /* read pcap register to check if headjack is in */ +// ssp_pcap_bit_status = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_A1SNS); +// if( ssp_pcap_bit_status != 0 ) /* headjack is in */ + { + ssp_pcap_bit_status = SSP_PCAP_get_bit_from_PCAP(SSP_PCAP_ADJ_BIT_PSTAT_MB2SNS); + if(ssp_pcap_bit_status == 0) // keydown + { + answer_flag ++; + if((!FULL(buttonevent))&&((answer_flag==1)||((answer_flag%NR_REPEAT)==0))) + { + buttonevent.button_buffer[buttonevent.head] = ANSWER | KEYDOWN; + buttonevent.head = (buttonevent.head+1)%(NR_BUTTONS); + wake_up_interruptible(&button_wait_queue); +#ifdef DEBUG + printk("answer keydown\n"); +#endif + } + answer_timer.expires = (jiffies + bdelay); + add_timer (&answer_timer); + } + else if(answer_flag) // keyup + { + del_timer(&answer_timer); + answer_flag = 0; + if(!FULL(buttonevent)) + { + buttonevent.button_buffer[buttonevent.head] = ANSWER | KEYUP; + buttonevent.head = (buttonevent.head+1)%(NR_BUTTONS); + wake_up_interruptible(&button_wait_queue); +#ifdef DEBUG + printk("answer keyup\n"); +#endif + } + } + } +} + +static void lockscreen_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + int bdelay = 10; /* The delay, in jiffies */ + + del_timer (&lockscreen_timer); + lockscreen_timer.expires = (jiffies + bdelay); + add_timer (&lockscreen_timer); +} + +void answer_button_handler(int irq, void *dev_id, struct pt_regs *regs) +{ +#if 0 + int bdelay = BUTTON_DELAY; /* The delay, in jiffies */ + + del_timer (&answer_timer); + answer_timer.expires = (jiffies + bdelay); + add_timer (&answer_timer); + printk("answer_button_handler\n"); +#endif + scan_answer_button(0); +} + +void headset_in_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + if(!FULL(buttonevent)) + { + buttonevent.button_buffer[buttonevent.head] = HEADSET_INT | KEYDOWN; + buttonevent.head = (buttonevent.head+1)%(NR_BUTTONS); + wake_up_interruptible(&button_wait_queue); + printk("headset button insert\n"); + answer_flag = 0; + } +} + + +void headset_out_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + if(!FULL(buttonevent)) + { + buttonevent.button_buffer[buttonevent.head] = HEADSET_INT | KEYUP; + buttonevent.head = (buttonevent.head+1)%(NR_BUTTONS); + wake_up_interruptible(&button_wait_queue); + printk("headset button remove\n"); + answer_flag = 0; + } +} + +#ifdef CONFIG_PM +static int button_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) +{ + switch(req) + { + case PM_SUSPEND: + break; + + case PM_RESUME: + break; + } + return 0; +} +#endif + +static int count=0; +static int button_release(struct inode * inode, struct file * file) +{ + int i; + + count --; + if(count) + { + return -EBUSY; + } + + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_MB2I); /* clear interrupt */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_MSR_MB2M); /* mask interrupt */ + + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_ISR_A1I); /* clear interrupt */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_MSR_A1M); /* mask interrupt */ + + // init gpio12 input, +// GPDR(GPIO_LOCK_SCREEN_PIN) &= 0xFFFFEFFF; + GPDR(GPIO_FLIP_PIN) &= ~(GPIO_bit(GPIO_FLIP_PIN)); + del_timer (&lockscreen_timer); + del_timer (&answer_timer); + free_irq(IRQ_GPIO(GPIO_FLIP_PIN), NULL); + + for(i=0; i + +/* Various defines: */ +#define BUTTON_DELAY 1 /* How many jiffies to wait */ +#define BUTTON_INTERVAL 10 /* How many jiffies to interval */ +#define VERSION "0.1" /* Driver version number */ +#define BUTTON_MINOR 158 /* Major 10, Minor 158, /dev/button */ + +/* single button */ +#define FLIP 0x80 +#define ANSWER 0x81 +#define HEADSET_INT 0x82 +#define EMU_CHARGER_500mA 0x83 +#define EMU_USB 0x84 +#define EMU_CHARGER_0 0x85 + +#define NR_BUTTONS 256 + +#define BUTTON_IOCTL_BASE 0xde +#define BUTTON_GET_FLIPSTATUS _IOR(BUTTON_IOCTL_BASE, 1,int) +#define BUTTON_GET_HEADSETSTATUS _IOR(BUTTON_IOCTL_BASE, 2,int) +#define BUTTON_GET_EMU_CABLE _IOR(BUTTON_IOCTL_BASE, 3,int) +#define BUTTON_GET_EMU_CHARGER _IOR(BUTTON_IOCTL_BASE, 4,int) +#define BUTTON_USB_CABLE_IN _IOR(BUTTON_IOCTL_BASE, 5,int) +#define BUTTON_USB_CABLE_OUT _IOR(BUTTON_IOCTL_BASE, 6,int) +#define BUTTON_CHARGER_CAP _IOR(BUTTON_IOCTL_BASE, 7,int) +#define BUTTON_USB_DEV_TYPE _IOR(BUTTON_IOCTL_BASE, 8,int) +#define NR_REPEAT 5 +#define FLIP_ON 1 +#define FLIP_OFF 0 +#define HEADSET_IN 0 +#define HEADSET_OUT 1 +#define EMU_CABLE_BEFORE 1 +#define EMU_CHARGE_500mA_BEFORE 1 +#define EMU_CHARGE_0mA_BEFORE 2 + +#define KEYDOWN 0x8000 +#define KEYUP 0x0000 +//#define LOCKSCREEN 0x84 +#define LOCKSCREEN FLIP +//# define BUTTON_GET_LOCKSCREENSTATUS _IOR(BUTTON_IOCTL_BASE, 3,int) +# define BUTTON_GET_LOCKSCREENSTATUS BUTTON_GET_FLIPSTATUS +//#define LOCKSCREEN_ON 1 +#define LOCKSCREEN_ON FLIP_OFF +//#define LOCKSCREEN_OFF 0 +#define LOCKSCREEN_OFF FLIP_ON + +#ifndef u16 +#define u16 unsigned short +#endif +/* usb cable event */ +#define USB_CABLE_IN 0xa0 +#define USB_CABLE_OUT 0xa1 +#define USB_CABLE_500mA 0xa2 +#define USB_CABLE_0mA 0xa3 +#define NETMONITOR_CABLE 0xa4 +#define MODEM_CABLE 0xa5 +#define APLOG_CABLE 0xa6 +#define CFG11_CABLE 0xa7 +#define DSPLOG_CABLE 0xa8 +#define USBNET_CABLE 0xa9 +#define PST_CABLE 0xaa +#define MASSSTORAGE_CABLE 0xab +#define UNKNOWN_CABLE 0xff +/*add function*/ +extern void answer_button_handler(int irq, void *dev_id, struct pt_regs *regs); +extern void headset_in_handler(int irq, void *dev_id, struct pt_regs *regs); +extern void headset_out_handler(int irq, void *dev_id, struct pt_regs *regs); +/* +extern void emu_charger_500mA_handler(void); +extern void emu_usb_in_handler(void); +extern void emu_usb_out_handler(void); +extern void emu_charger_0(void); +*/ +extern void usb_cable_event_handler(unsigned short cable_event); Index: linux-2.6.16.5-a/drivers/misc/ezx/ezx-emu.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/misc/ezx/ezx-emu.c 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,1185 @@ +#ifdef EMU_PIHF_FEATURE +/* + * linux/drivers/misc/ezx-emu.c --- EMU driver on ezx + * + * Support for the Motorola Ezx A780 Development Platform. + * + * Author: Cheng Xuefeng + * Created: April 30, 2004 + * Copyright: Motorola Inc. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "ssp_pcap.h" +#include "ezx-emu.h" + +#include +#include + +#define DEBUG +#ifdef CONFIG_PM +static struct pm_dev *pm_dev; +#endif + +#ifdef EMU_INTERFACE_DEBUG +#define EMU_DBG(fmt,args...) printk("EMU:"fmt,##args); +#else +#define EMU_DBG(fmt,args...) +#endif + +EXPORT_SYMBOL(emu_switch_to); + +extern void emu_switch_to(T_EMU_SWITCH_TO to); + +#define EMU_YES (1) +#define EMU_NO (0) + +/* 1ms */ +#define EMU_PIHF_DPLUS_INIT_INTERVAL (1) + +static int emu_is_int = EMU_NO; +static int emu_is_wait = EMU_NO; + +typedef enum{ + EMU_USB = 0, + EMU_SPD, + EMU_PIHF, /*EMU_PIHF is a subset of EMU_SPD*/ + EMU_EIHF +} T_EMU_CURRENT_DEVICE; + +typedef enum{ + EMU_MODE_UART =0, + EMU_MODE_USB, + EMU_MODE_AUDIO_MONO, + EMU_MODE_AUDIO_STEREO +} T_EMU_MODE; + +static T_EMU_CURRENT_DEVICE emu_current_device = EMU_USB; +static T_EMU_MODE emu_current_mode = EMU_MODE_USB; + +static DECLARE_WAIT_QUEUE_HEAD(emu_wait_queue); /* Used for blocking read */ + +static int emucount=0; + + +static void emu_handle_int(int irq,void *dev,struct pt_regs *regs); + +/* This will be export to other modules. For other feature, developer should + * add related T_EMU_SWITCH_TO type as requriement. + */ +void emu_switch_to(T_EMU_SWITCH_TO to) +{ + switch(to) + { + case EMU_SWITCH_TO_NO_DEV: + EMU_DBG("emu_switch_to:EMU_SWITCH_TO_NO_DEV\n"); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PU); + + /* Disable the PCAP transceiver both for USB and RS232 */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB); + + /* Set the Bulverde GPIO */ + pxa_gpio_mode(GPIO34_USB_P2_2_MD); + set_GPIO(GPIO34_TXENB); + pxa_gpio_mode(GPIO35_USB_P2_1_MD); + pxa_gpio_mode(GPIO36_USB_P2_4_MD); + pxa_gpio_mode(GPIO39_USB_P2_6_MD); //pxa_gpio_mode(GPIO39_VPOUT | GPIO_IN); + pxa_gpio_mode(GPIO40_USB_P2_5_MD); + pxa_gpio_mode(GPIO53_USB_P2_3_MD); + break; + case EMU_SWITCH_TO_UART: + + /* set the PCAP as UART mode */ + /*SSP_PCAP_configure_USB_UART_transeiver(SSP_PCAP_SERIAL_PORT);*/ + if(SSP_PCAP_SUCCESS == SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN)) + { + EMU_DBG("Before SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB clean\n"); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB); + } + else + { + return; + } + + /* This must be set. */ + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232_DIR); + EMU_DBG("emu_switch_to:EMU_SWITCH_TO_UART:set txd high\n"); + set_GPIO(GPIO39_FFTXD); + + /* set other USB related GPIO direcction to IN first */ + pxa_gpio_mode(GPIO34_USB_P2_2_MD); + set_GPIO(GPIO34_TXENB); + pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); + pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); + pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); + + /* Init UART related GPIO */ + pxa_gpio_mode(GPIO39_FFTXD_MD); + pxa_gpio_mode(GPIO53_FFRXD_MD); + CKEN |= CKEN6_FFUART; + + /* set the MUX1/2 to data mode */ + clr_GPIO(GPIO_EMU_MUX1); + clr_GPIO(GPIO_EMU_MUX2); + + emu_current_mode = EMU_MODE_UART; + break; + case EMU_SWITCH_TO_USB: + EMU_DBG("emu_switch_to:EMU_SWITCH_TO_USB\n"); + /* set the 6 USB related GPIOs as USB function*/ + pxa_gpio_mode(GPIO34_USB_P2_2_MD); + pxa_gpio_mode(GPIO35_USB_P2_1_MD); + pxa_gpio_mode(GPIO36_USB_P2_4_MD); + pxa_gpio_mode(GPIO39_USB_P2_6_MD); + pxa_gpio_mode(GPIO40_USB_P2_5_MD); + pxa_gpio_mode(GPIO53_USB_P2_3_MD); + UP2OCR = 0x02000000; + + /* set the PCAP as UART mode */ + /*SSP_PCAP_configure_USB_UART_transeiver(SSP_PCAP_HIGH_USB_PORT);*/ + if(SSP_PCAP_SUCCESS == SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB)) + { + if(SSP_PCAP_SUCCESS == SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_FSENB)) + { + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); + } + } + + /* set the MUX1/2 to data mode */ + clr_GPIO(GPIO_EMU_MUX1); + clr_GPIO(GPIO_EMU_MUX2); + + emu_current_mode = EMU_MODE_USB; + break; + case EMU_SWITCH_TO_AUDIO_MONO: + /* This will not change the PCAP audio related + * register. Just change the MUX1/2. Switching + * the audio path is controlled by other driver. + */ + EMU_DBG("emu_switch_to:EMU_SWITCH_TO_AUDIO_MONO\n"); + + clr_GPIO(GPIO39_VPOUT); + mdelay(1); + pxa_gpio_mode(GPIO34_TXENB | GPIO_OUT); + set_GPIO(GPIO34_TXENB); + pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); + pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); + pxa_gpio_mode(GPIO39_VPOUT | GPIO_IN); + pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); + pxa_gpio_mode(GPIO53_VMIN | GPIO_IN); + + /* set the MUX1/2 to mono mode */ + set_GPIO(GPIO_EMU_MUX1); + clr_GPIO(GPIO_EMU_MUX2); + + emu_current_mode = EMU_MODE_AUDIO_MONO; + break; + case EMU_SWITCH_TO_AUDIO_STEREO: + /* This will not change the PCAP audio related + * register. Just change the MUX1/2. Switching + * the audio path is controlled by other driver. + */ + EMU_DBG("emu_switch_to:EMU_SWITCH_TO_AUDIO_STEREO\n"); + clr_GPIO(GPIO39_VPOUT); + pxa_gpio_mode(GPIO34_USB_P2_@ | GPIO_IN); + pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); + pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); + pxa_gpio_mode(GPIO39_VPOUT | GPIO_IN); + pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); + pxa_gpio_mode(GPIO53_VMIN | GPIO_IN); + + /* set the MUX1/2 to stereo mode */ + set_GPIO(GPIO_EMU_MUX1); + set_GPIO(GPIO_EMU_MUX2); + emu_current_mode = EMU_MODE_AUDIO_STEREO; + break; + default: + break; + } + return; +} + + +static int emu_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) +{ + int ret; + long val; + + switch(cmd){ + + /* Switch the MUX1/2 and set the GPIOs */ + case EMU_SW_TO_UART: + EMU_DBG("emu_ioctl:EMU_SW_TO_UART:before change\n"); + emu_switch_to(EMU_SWITCH_TO_UART); + break; + + case EMU_SW_TO_USB: + EMU_DBG("emu_ioctl:EMU_SW_TO_USB:before change\n"); + emu_switch_to(EMU_SWITCH_TO_USB); + break; + + case EMU_SW_TO_AUDIO_MONO: + EMU_DBG("emu_ioctl:EMU_SW_TO_AUDIO_MONO:before change\n"); + emu_switch_to(EMU_SWITCH_TO_AUDIO_MONO); + break; + + case EMU_SW_TO_AUDIO_STEREO: + EMU_DBG("emu_ioctl:EMU_SW_TO_AUDIO_STEREO: not support...\n"); + emu_switch_to(EMU_SWITCH_TO_AUDIO_STEREO); + break; + + case EMU_SMART_SPD_INIT: + + EMU_DBG("emu_ioctl:EMU_SPD_INIT\n"); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PU); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PD); + mdelay(EMU_PIHF_DPLUS_INIT_INTERVAL); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PD); + + /* init to UART mode */ + emu_switch_to(EMU_SWITCH_TO_UART); + + EMU_DBG("emu_ioctl:set GPIO 86\n"); + /* For SNP_INT_CTL, the inactive state is low. + * That means the ID line is high. + */ + pxa_gpio_mode(GPIO_SNP_INT_CTL|GPIO_OUT); + clr_GPIO(GPIO_SNP_INT_CTL); + + EMU_DBG("emu_ioctl:before request_irq()\n"); + + udelay(10); + + set_GPIO_IRQ_edge(GPIO_SNP_INT_IN,GPIO_FALLING_EDGE|GPIO_RISING_EDGE); + + if (request_irq(IRQ_GPIO(GPIO_SNP_INT_IN),emu_handle_int, + SA_INTERRUPT|SA_SAMPLE_RANDOM, + "EMU SNP interrupt",(void*)1) + ) + { + printk(KERN_WARNING"can't get EMU snp_int irq\n"); + return -EIO; + } + + emu_current_device = EMU_SPD; + break; + + /* EMU PIHF */ + case EMU_PIHF_INIT: + EMU_DBG("%s,%s:EMU_PIHF_INIT",__FILE__,__FUNCTION__); + + /* init to UART mode */ + emu_switch_to(EMU_SWITCH_TO_UART); + + emu_current_device = EMU_PIHF; + break; + case EMU_PIHF_SNP_INT_CTL: + EMU_DBG("emu_ioctl:got the SNP_INT_CTL...\n"); + /* For SNP_INT_CTL, the inactive state is low. + * That means the ID line is high. + */ + ret = get_user(val,(long *)arg); + if (ret) + return ret; + disable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); + set_GPIO(GPIO_SNP_INT_CTL); + mdelay(val); + clr_GPIO(GPIO_SNP_INT_CTL); + enable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); + break; + + case EMU_PIHF_ID_LOW: + EMU_DBG("emu_ioctl:EMU_PIHF_ID_LOW\n"); + disable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); + set_GPIO(GPIO_SNP_INT_CTL); + enable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); + break; + + case EMU_PIHF_ID_HIGH: + EMU_DBG("emu_ioctl:EMU_PIHF_ID_HIGH\n"); + disable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); + clr_GPIO(GPIO_SNP_INT_CTL); + enable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); + break; + + /* EMU EIHF */ + case EMU_EIHF_INIT: + emu_current_device = EMU_EIHF; + break; + + case EMU_EIHF_MUTE: + clr_GPIO(GPIO_SNP_INT_CTL); + break; + + case EMU_EIHF_UNMUTE: + set_GPIO(GPIO_SNP_INT_CTL); + break; + + default: + return -EINVAL; + } + return 0; +} + +static unsigned int emu_poll(struct file *file, poll_table *wait) +{ + if (emu_is_int == EMU_NO) + { + EMU_DBG("%s,%s:emu_is_int is NO\n",__FILE__,__FUNCTION__); + emu_is_wait = EMU_YES; + poll_wait(file, &emu_wait_queue, wait); + } + else + { + EMU_DBG("%s,%s:emu_is_int is YES\n",__FILE__,__FUNCTION__); + emu_is_int = EMU_NO; + } + return POLLIN | POLLRDNORM; +} +/* + * This function is called when a user space program attempts to read + * /dev/emu. It puts the device to sleep on the wait queue until + * irq handler writes some data to the buffer and flushes + * the queue, at which point it writes the data out to the device and + * returns the number of characters it has written. This function is + * reentrant, so that many processes can be attempting to read from the + * device at any one time. + */ + +static int emu_read (struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + int retval = 0; + + EMU_DBG("%s,%s:enter ...\n",__FILE__,__FUNCTION__); + if (EMU_NO == emu_is_int) + { + EMU_DBG("%s,%s:emu_is_int is NO\n",__FILE__,__FUNCTION__); + add_wait_queue(&emu_wait_queue, &wait); + current->state = TASK_INTERRUPTIBLE; + + while (EMU_NO == emu_is_int) + { + if (file->f_flags & O_NONBLOCK) + { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) + { + retval = -ERESTARTSYS; + break; + } + emu_is_wait = EMU_YES; + EMU_DBG("%s,%s:before schedule()\n",__FILE__,__FUNCTION__); + schedule(); + } + current->state = TASK_RUNNING; + EMU_DBG("%s,%s:after wake up\n",__FILE__,__FUNCTION__); + remove_wait_queue(&emu_wait_queue, &wait); + } + + return retval; +} + +#ifdef CONFIG_PM +static int emu_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) +{ + EMU_DBG("emu_pm_callback\n"); + switch(req) + { + case PM_SUSPEND: + EMU_DBG("emu_pm_callback:PM_SUSPEND\n"); + /* Disable the PCAP transceiver both for USB and RS232 */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB); + + /* Set the Bulverde GPIO */ + pxa_gpio_mode(GPIO34_TXENB | GPIO_OUT); + set_GPIO(GPIO34_TXENB); + PGSR(GPIO34_TXENB)|=GPIO_bit(GPIO34_TXENB); + pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); + pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); + pxa_gpio_mode(GPIO39_VPOUT | GPIO_IN); + pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); + pxa_gpio_mode(GPIO53_VMIN | GPIO_IN); + break; + + case PM_RESUME: + + if ( emucount != 0) + { + switch ( emu_current_device) + { + case EMU_PIHF: + + EMU_DBG("emu_pm_callback:EMU_PIHF\n"); + disable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); + clr_GPIO(GPIO_SNP_INT_CTL); + enable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); + + switch(emu_current_mode) + { + case EMU_MODE_UART: + emu_switch_to(EMU_SWITCH_TO_UART); + break; + case EMU_MODE_USB: + emu_switch_to(EMU_SWITCH_TO_USB); + break; + case EMU_MODE_AUDIO_MONO: + emu_switch_to(EMU_SWITCH_TO_AUDIO_MONO); + break; + case EMU_MODE_AUDIO_STEREO: + emu_switch_to(EMU_SWITCH_TO_AUDIO_STEREO); + break; + default: + break; + } + break; + case EMU_EIHF: + /* Should not come here since the EIHF must have the charger. */ + break; + case EMU_USB: + emu_switch_to(EMU_SWITCH_TO_USB); + break; + default: + break; + } + } + break; + } + return 0; +} +#endif + +static int emu_release(struct inode * inode, struct file * file) +{ + int i; + + if ( emucount > 0) + emucount --; + + if(emucount) + { + return -EBUSY; + } + + if ( EMU_PIHF == emu_current_device) + free_irq(IRQ_GPIO(GPIO_SNP_INT_IN),NULL); + + EMU_DBG("emu_release:freed irq...%d\n",IRQ_GPIO(87)); + +#ifdef CONFIG_PM + pm_unregister(pm_dev); +#endif +#ifdef DEBUG + EMU_DBG("emu_release:emu device released\n"); +#endif + + return 0; +} + +static void emu_handle_int(int irq,void *dev,struct pt_regs *regs) +{ + EMU_DBG("%s,%s:got the interrupt...\n",__FILE__,__FUNCTION__); + if ( EMU_YES == emu_is_wait ) + { + EMU_DBG("%s,%s:emu_is_wait is YES...\n",__FILE__,__FUNCTION__); + wake_up_interruptible(&emu_wait_queue); + emu_is_wait = EMU_NO; + } + else + { + EMU_DBG("%s,%s:emu_is_wait is NO...\n",__FILE__,__FUNCTION__); + emu_is_int = EMU_YES; + } + EMU_DBG("emu_handle_int:after wake up...\n"); +} + +static int emu_open(struct inode * inode, struct file * file) +{ + int i, data; + int ret; + + /* emucount could only be 1 or 0 */ + if(emucount) + { + return -EBUSY; + } + emucount ++; + +#ifdef CONFIG_PM + pm_dev = pm_register(PM_SYS_DEV, 0, emu_pm_callback); +#endif + EMU_DBG("emu_open:emu device opened\n"); + return 0; +} + +/* add emu_ioctl to check flip status */ +static struct file_operations emu_fops = { + owner: THIS_MODULE, + open: emu_open, + release: emu_release, + read: emu_read, + poll: emu_poll, + ioctl: emu_ioctl, +}; + +/* + * This structure is the misc device structure, which specifies the minor + * device number (165 in this case), the name of the device (for /proc/misc), + * and the address of the above file operations structure. + */ + +static struct miscdevice emu_misc_device = { + EMU_MINOR, + "emu", + &emu_fops, +}; + +/* + * This function is called to initialise the driver, either from misc.c at + * bootup if the driver is compiled into the kernel, or from init_module + * below at module insert time. It attempts to register the device node + * and the IRQ and fails with a warning message if either fails, though + * neither ever should because the device number and IRQ are unique to + * this driver. + */ + +static int __init emu_init(void) +{ + pxa_gpio_mode(GPIO_SNP_INT_IN | GPIO_IN); + pxa_gpio_mode(GPIO_EMU_MUX1 | GPIO_OUT); + pxa_gpio_mode(GPIO_EMU_MUX2 | GPIO_OUT); + + if (misc_register (&emu_misc_device)) { + EMU_DBG (KERN_WARNING "emu: Couldn't register device 10, " + "%d.\n", EMU_MINOR); + return -EBUSY; + } +} + +static void __exit emu_exit (void) +{ + misc_deregister(&emu_misc_device); +} + + +module_init(emu_init); +module_exit(emu_exit); +#else /* EMU_PIHF_FEATURE */ + +/* + * linux/drivers/misc/ezx-emu.c --- EMU driver on ezx + * + * Support for the Motorola Ezx A780 Development Platform. + * + * Author: Cheng Xuefeng + * Created: April 30, 2004 + * Copyright: Motorola Inc. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "ssp_pcap.h" +#include "ezx-emu.h" + +#include +#include + +#define DEBUG +#ifdef CONFIG_PM +static struct pm_dev *pm_dev; +#endif + +#ifdef EMU_INTERFACE_DEBUG +#define EMU_DBG(fmt,args...) printk("EMU:"fmt,##args); +#else +#define EMU_DBG(fmt,args...) +#endif + +EXPORT_SYMBOL(emu_switch_to); + +extern void emu_switch_to(T_EMU_SWITCH_TO to); + +#define EMU_YES (0) +#define EMU_NO (1) + +/* 1ms */ +#define EMU_PIHF_DPLUS_INIT_INTERVAL (1) + +static int emu_is_int = EMU_NO; +static int emu_is_wait = EMU_NO; + +typedef enum{ + EMU_USB = 0, + EMU_PIHF, + EMU_EIHF +} T_EMU_CURRENT_DEVICE; + +typedef enum{ + EMU_MODE_UART =0, + EMU_MODE_USB, + EMU_MODE_AUDIO_MONO, + EMU_MODE_AUDIO_STEREO +} T_EMU_MODE; + +static T_EMU_CURRENT_DEVICE emu_current_device = EMU_USB; +static T_EMU_MODE emu_current_mode = EMU_MODE_USB; + +static DECLARE_WAIT_QUEUE_HEAD(emu_wait_queue); /* Used for blocking read */ + +static int emucount=0; + + +static void emu_handle_int(int irq,void *dev,struct pt_regs *regs); + +/* This will be export to other modules. For other feature, developer should + * add related T_EMU_SWITCH_TO type as requriement. + */ +void emu_switch_to(T_EMU_SWITCH_TO to) +{ + switch(to) + { + case EMU_SWITCH_TO_NO_DEV: + EMU_DBG("emu_switch_to:EMU_SWITCH_TO_NO_DEV\n"); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PU); + + /* Disable the PCAP transceiver both for USB and RS232 */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB); + + /* Set the Bulverde GPIO */ + pxa_gpio_mode(GPIO34_TXENB | GPIO_OUT); + set_GPIO(GPIO34_TXENB); + pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); + pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); + pxa_gpio_mode(GPIO39_VPOUT | GPIO_IN); + pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); + pxa_gpio_mode(GPIO53_VMIN | GPIO_IN); + break; + case EMU_SWITCH_TO_UART: + EMU_DBG("emu_switch_to:EMU_SWITCH_TO_UART\n"); + /* set other USB related GPIO direcction to IN first */ + set_GPIO(GPIO39_VPOUT); + + pxa_gpio_mode(GPIO34_TXENB | GPIO_IN); + pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); + pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); + pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); + + /* Init UART related GPIO */ + pxa_gpio_mode(GPIO39_FFTXD_MD); + pxa_gpio_mode(GPIO53_FFRXD_MD); + CKEN |= CKEN6_FFUART; + EMU_DBG("emu_switch_to:EMU_SWITCH_TO_UART:set txd high\n"); + + /* set the PCAP as UART mode */ + /*SSP_PCAP_configure_USB_UART_transeiver(SSP_PCAP_SERIAL_PORT);*/ + if(SSP_PCAP_SUCCESS == SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN)) + { + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB); + } + else + { + return; + } + + /* set the MUX1/2 to data mode */ + clr_GPIO(GPIO_EMU_MUX1); + clr_GPIO(GPIO_EMU_MUX2); + + emu_current_mode = EMU_MODE_UART; + break; + case EMU_SWITCH_TO_USB: + EMU_DBG("emu_switch_to:EMU_SWITCH_TO_USB\n"); + /* set the 6 USB related GPIOs as USB function*/ + pxa_gpio_mode(GPIO34_USB_P2_2_MD); + pxa_gpio_mode(GPIO35_XRXD_MD); + pxa_gpio_mode(GPIO36_VMOUT_MD); + pxa_gpio_mode(GPIO39_VPOUT_MD); + pxa_gpio_mode(GPIO40_VPIN_MD); + pxa_gpio_mode(GPIO53_VMIN_MD); + UP2OCR = 0x02000000; + + /* set the PCAP as UART mode */ + /*SSP_PCAP_configure_USB_UART_transeiver(SSP_PCAP_HIGH_USB_PORT);*/ + if(SSP_PCAP_SUCCESS == SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB)) + { + if(SSP_PCAP_SUCCESS == SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_FSENB)) + { + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); + } + } + + /* set the MUX1/2 to data mode */ + clr_GPIO(GPIO_EMU_MUX1); + clr_GPIO(GPIO_EMU_MUX2); + + emu_current_mode = EMU_MODE_USB; + break; + case EMU_SWITCH_TO_AUDIO_MONO: + /* This will not change the PCAP audio related + * register. Just change the MUX1/2. Switching + * the audio path is controlled by other driver. + */ + EMU_DBG("emu_switch_to:EMU_SWITCH_TO_AUDIO_MONO\n"); + + clr_GPIO(GPIO39_VPOUT); + mdelay(1); + pxa_gpio_mode(GPIO34_TXENB | GPIO_OUT); + set_GPIO(GPIO34_TXENB); + pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); + pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); + pxa_gpio_mode(GPIO39_VPOUT | GPIO_IN); + pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); + pxa_gpio_mode(GPIO53_VMIN | GPIO_IN); + + /* set the MUX1/2 to mono mode */ + set_GPIO(GPIO_EMU_MUX1); + clr_GPIO(GPIO_EMU_MUX2); + + emu_current_mode = EMU_MODE_AUDIO_MONO; + break; + case EMU_SWITCH_TO_AUDIO_STEREO: + /* This will not change the PCAP audio related + * register. Just change the MUX1/2. Switching + * the audio path is controlled by other driver. + */ + EMU_DBG("emu_switch_to:EMU_SWITCH_TO_AUDIO_STEREO\n"); + clr_GPIO(GPIO39_VPOUT); + pxa_gpio_mode(GPIO34_TXENB | GPIO_OUT); + set_GPIO(GPIO34_TXENB); + pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); + pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); + pxa_gpio_mode(GPIO39_VPOUT | GPIO_IN); + pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); + pxa_gpio_mode(GPIO53_VMIN | GPIO_IN); + + /* set the MUX1/2 to stereo mode */ + set_GPIO(GPIO_EMU_MUX1); + set_GPIO(GPIO_EMU_MUX2); + emu_current_mode = EMU_MODE_AUDIO_STEREO; + break; + default: + break; + } + return; +} + + +static int emu_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) +{ + int ret; + long val; + + switch(cmd){ + + /* Switch the MUX1/2 and set the GPIOs */ + case EMU_SW_TO_UART: + EMU_DBG("emu_ioctl:EMU_SW_TO_UART:before change\n"); + emu_switch_to(EMU_SWITCH_TO_UART); + break; + + case EMU_SW_TO_USB: + EMU_DBG("emu_ioctl:EMU_SW_TO_USB:before change\n"); + emu_switch_to(EMU_SWITCH_TO_USB); + break; + + case EMU_SW_TO_AUDIO_MONO: + EMU_DBG("emu_ioctl:EMU_SW_TO_AUDIO_MONO:before change\n"); + emu_switch_to(EMU_SWITCH_TO_AUDIO_MONO); + break; + + case EMU_SW_TO_AUDIO_STEREO: + EMU_DBG("emu_ioctl:EMU_SW_TO_AUDIO_STEREO: not support...\n"); + emu_switch_to(EMU_SWITCH_TO_AUDIO_STEREO); + break; + + /* EMU PIHF */ + case EMU_PIHF_INIT: + EMU_DBG("%s,%s:EMU_PIHF_INIT",__FILE__,__FUNCTION__); + + /* init to UART mode */ + emu_switch_to(EMU_SWITCH_TO_UART); + + EMU_DBG("emu_ioctl:set GPIO 86\n"); + /* For SNP_INT_CTL, the inactive state is low. + * That means the ID line is high. + */ + pxa_gpio_mode(GPIO_SNP_INT_CTL|GPIO_OUT); + clr_GPIO(GPIO_SNP_INT_CTL); + + EMU_DBG("emu_ioctl:before request_irq()\n"); + + udelay(10); + + set_GPIO_IRQ_edge(GPIO_SNP_INT_IN,GPIO_FALLING_EDGE|GPIO_RISING_EDGE); + +#if 0 + if(GPLR(GPIO_SNP_INT_IN) & GPIO_bit(GPIO_SNP_INT_IN)) + { + EMU_DBG("emu_ioctl:87 is high\n"); + } + else + { + EMU_DBG("emu_ioctl:87 is low\n"); + } +#endif + + if (request_irq(IRQ_GPIO(GPIO_SNP_INT_IN),emu_handle_int, + SA_INTERRUPT|SA_SAMPLE_RANDOM, + "EMU SNP interrupt",(void*)1) + ) + { + printk(KERN_WARNING"can't get EMU snp_int irq\n"); + return -EIO; + } + + emu_current_device = EMU_PIHF; + break; + case EMU_PIHF_SNP_INT_CTL: + EMU_DBG("emu_ioctl:got the SNP_INT_CTL...\n"); + /* For SNP_INT_CTL, the inactive state is low. + * That means the ID line is high. + */ + ret = get_user(val,(long *)arg); + if (ret) + return ret; + disable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); + set_GPIO(GPIO_SNP_INT_CTL); + mdelay(val); + clr_GPIO(GPIO_SNP_INT_CTL); + enable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); + break; + + case EMU_PIHF_ID_LOW: + EMU_DBG("emu_ioctl:EMU_PIHF_ID_LOW\n"); + disable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); + set_GPIO(GPIO_SNP_INT_CTL); + enable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); + break; + + case EMU_PIHF_ID_HIGH: + EMU_DBG("emu_ioctl:EMU_PIHF_ID_HIGH\n"); + disable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); + clr_GPIO(GPIO_SNP_INT_CTL); + enable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); + break; + + case EMU_PIHF_INIT_DPLUS_CTL: + EMU_DBG("emu_ioctl:EMU_PIHF_INIT_DPLUS_CTL\n"); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PU); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PD); + mdelay(EMU_PIHF_DPLUS_INIT_INTERVAL); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_USB_PD); + break; + + /* EMU EIHF */ + case EMU_EIHF_INIT: + emu_current_device = EMU_EIHF; + break; + + case EMU_EIHF_MUTE: + clr_GPIO(GPIO_SNP_INT_CTL); + break; + + case EMU_EIHF_UNMUTE: + set_GPIO(GPIO_SNP_INT_CTL); + break; + + default: + return -EINVAL; + } + return 0; +} + +static unsigned int emu_poll(struct file *file, poll_table *wait) +{ + if (emu_is_int == EMU_NO) + { + emu_is_wait = EMU_YES; + poll_wait(file, &emu_wait_queue, wait); + } + else + { + emu_is_int = EMU_NO; + } + return POLLIN | POLLRDNORM; +} +/* + * This function is called when a user space program attempts to read + * /dev/emu. It puts the device to sleep on the wait queue until + * irq handler writes some data to the buffer and flushes + * the queue, at which point it writes the data out to the device and + * returns the number of characters it has written. This function is + * reentrant, so that many processes can be attempting to read from the + * device at any one time. + */ + +static int emu_read (struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + int retval = 0; + + if (EMU_NO == emu_is_int) + { + add_wait_queue(&emu_wait_queue, &wait); + current->state = TASK_INTERRUPTIBLE; + + while (EMU_NO == emu_is_int) + { + if (file->f_flags & O_NONBLOCK) + { + retval = -EAGAIN; + break; + } + if (signal_pending(current)) + { + retval = -ERESTARTSYS; + break; + } + emu_is_wait = EMU_YES; + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&emu_wait_queue, &wait); + } + + return retval; +} + +#ifdef CONFIG_PM +static int emu_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) +{ + EMU_DBG("emu_pm_callback\n"); + switch(req) + { + case PM_SUSPEND: + EMU_DBG("emu_pm_callback:PM_SUSPEND\n"); + /* Disable the PCAP transceiver both for USB and RS232 */ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_BUSCTRL_VUSB_EN); + SSP_PCAP_bit_set(SSP_PCAP_ADJ_BIT_BUSCTRL_RS232ENB); + + /* Set the Bulverde GPIO */ + pxa_gpio_mode(GPIO34_TXENB | GPIO_OUT); + set_GPIO(GPIO34_TXENB); + PGSR(GPIO34_TXENB)|=GPIO_bit(GPIO34_TXENB); + pxa_gpio_mode(GPIO35_XRXD | GPIO_IN); + pxa_gpio_mode(GPIO36_VMOUT | GPIO_IN); + pxa_gpio_mode(GPIO39_VPOUT | GPIO_IN); + pxa_gpio_mode(GPIO40_VPIN | GPIO_IN); + pxa_gpio_mode(GPIO53_VMIN | GPIO_IN); + break; + + case PM_RESUME: + + if ( emucount != 0) + { + switch ( emu_current_device) + { + case EMU_PIHF: + + EMU_DBG("emu_pm_callback:EMU_PIHF\n"); + disable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); + clr_GPIO(GPIO_SNP_INT_CTL); + enable_irq(IRQ_GPIO(GPIO_SNP_INT_IN)); + + switch(emu_current_mode) + { + case EMU_MODE_UART: + emu_switch_to(EMU_SWITCH_TO_UART); + break; + case EMU_MODE_USB: + emu_switch_to(EMU_SWITCH_TO_USB); + break; + case EMU_MODE_AUDIO_MONO: + emu_switch_to(EMU_SWITCH_TO_AUDIO_MONO); + break; + case EMU_MODE_AUDIO_STEREO: + emu_switch_to(EMU_SWITCH_TO_AUDIO_STEREO); + break; + default: + break; + } + break; + case EMU_EIHF: + /* Should not come here since the EIHF must have the charger. */ + break; + case EMU_USB: + emu_switch_to(EMU_SWITCH_TO_USB); + break; + default: + break; + } + } + break; + } + return 0; +} +#endif + +static int emu_release(struct inode * inode, struct file * file) +{ + int i; + + if ( emucount > 0) + emucount --; + + if(emucount) + { + return -EBUSY; + } + + if ( EMU_PIHF == emu_current_device) + free_irq(IRQ_GPIO(GPIO_SNP_INT_IN),NULL); + + EMU_DBG("emu_release:freed irq...%d\n",IRQ_GPIO(87)); + +#ifdef CONFIG_PM + pm_unregister(pm_dev); +#endif +#ifdef DEBUG + EMU_DBG("emu_release:emu device released\n"); +#endif + + return 0; +} + +static void emu_handle_int(int irq,void *dev,struct pt_regs *regs) +{ + EMU_DBG("emu_handle_int:got the interrupt...\n"); + if ( EMU_YES == emu_is_wait ) + { + wake_up_interruptible(&emu_wait_queue); + emu_is_wait = EMU_NO; + } + else + { + emu_is_int = EMU_YES; + } + EMU_DBG("emu_handle_int:after wake up...\n"); +} + +static int emu_open(struct inode * inode, struct file * file) +{ + int i, data; + int ret; + + /* emucount could only be 1 or 0 */ + if(emucount) + { + return -EBUSY; + } + emucount ++; + +#ifdef CONFIG_PM + pm_dev = pm_register(PM_SYS_DEV, 0, emu_pm_callback); +#endif + EMU_DBG("emu_open:emu device opened\n"); + return 0; +} + +/* add emu_ioctl to check flip status */ +static struct file_operations emu_fops = { + owner: THIS_MODULE, + open: emu_open, + release: emu_release, + read: emu_read, + poll: emu_poll, + ioctl: emu_ioctl, +}; + +/* + * This structure is the misc device structure, which specifies the minor + * device number (165 in this case), the name of the device (for /proc/misc), + * and the address of the above file operations structure. + */ + +static struct miscdevice emu_misc_device = { + EMU_MINOR, + "emu", + &emu_fops, +}; + +/* + * This function is called to initialise the driver, either from misc.c at + * bootup if the driver is compiled into the kernel, or from init_module + * below at module insert time. It attempts to register the device node + * and the IRQ and fails with a warning message if either fails, though + * neither ever should because the device number and IRQ are unique to + * this driver. + */ + +static int __init emu_init(void) +{ + pxa_gpio_mode(GPIO_SNP_INT_IN | GPIO_IN); + + if (misc_register (&emu_misc_device)) { + EMU_DBG (KERN_WARNING "emu: Couldn't register device 10, " + "%d.\n", EMU_MINOR); + return -EBUSY; + } +} + +static void __exit emu_exit (void) +{ + misc_deregister(&emu_misc_device); +} + + +module_init(emu_init); +module_exit(emu_exit); +#endif /* EMU_PIHF_FEATURE */ Index: linux-2.6.16.5-a/drivers/misc/ezx/ezx-emu.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/misc/ezx/ezx-emu.h 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,93 @@ +#ifdef EMU_PIHF_FEATURE +/* + * linux/drivers/emu/ezx-emu.h + * author: Cheng Xuefeng + * company: Motorola Inc. + * date: 30/4/2004 + */ +#include + +/* Various defines: */ +#define VERSION "0.1" /* Driver version number */ +#define EMU_MINOR 250 /* Major 10, Minor 250, /dev/emu */ + +/* single button */ + +#define EMU_IOCTL_BASE 0xdf + +/* Switch the Mux1/2 and set the GPIOs */ +#define EMU_SW_TO_UART _IO(EMU_IOCTL_BASE, 1) +#define EMU_SW_TO_USB _IO(EMU_IOCTL_BASE, 2) +#define EMU_SW_TO_AUDIO_MONO _IO(EMU_IOCTL_BASE, 3) +#define EMU_SW_TO_AUDIO_STEREO _IO(EMU_IOCTL_BASE, 4) +#define EMU_SMART_SPD_INIT _IO(EMU_IOCTL_BASE, 5) + +/* EMU PIHF */ +#define EMU_PIHF_INIT _IOW(EMU_IOCTL_BASE, 21,int) +/*#define EMU_PIHF_GET_STATUS _IOR(EMU_IOCTL_BASE, 12,int)*/ +#define EMU_PIHF_SNP_INT_CTL _IOR(EMU_IOCTL_BASE, 23,int) +#define EMU_PIHF_ID_LOW _IO(EMU_IOCTL_BASE, 24) +#define EMU_PIHF_ID_HIGH _IO(EMU_IOCTL_BASE, 25) + +/* EMU EIHF */ +#define EMU_EIHF_INIT _IOW(EMU_IOCTL_BASE, 31,int) +#define EMU_EIHF_MUTE _IO(EMU_IOCTL_BASE, 32) +#define EMU_EIHF_UNMUTE _IO(EMU_IOCTL_BASE, 33) + +typedef enum{ + EMU_SWITCH_TO_UART = 0, + EMU_SWITCH_TO_USB, + EMU_SWITCH_TO_AUDIO_MONO, + EMU_SWITCH_TO_AUDIO_STEREO, + EMU_SWITCH_TO_NO_DEV +} T_EMU_SWITCH_TO; + +void emu_switch_to(T_EMU_SWITCH_TO to); + +#else /* EMU_PIHF_FEATURE */ + +/* + * linux/drivers/emu/ezx-emu.h + * author: Cheng Xuefeng + * company: Motorola Inc. + * date: 30/4/2004 + */ +#include + +/* Various defines: */ +#define VERSION "0.1" /* Driver version number */ +#define EMU_MINOR 250 /* Major 10, Minor 250, /dev/emu */ + +/* single button */ + +#define EMU_IOCTL_BASE 0xdf + +/* Switch the Mux1/2 and set the GPIOs */ +#define EMU_SW_TO_UART _IO(EMU_IOCTL_BASE, 1) +#define EMU_SW_TO_USB _IO(EMU_IOCTL_BASE, 2) +#define EMU_SW_TO_AUDIO_MONO _IO(EMU_IOCTL_BASE, 3) +#define EMU_SW_TO_AUDIO_STEREO _IO(EMU_IOCTL_BASE, 4) + +/* EMU PIHF */ +#define EMU_PIHF_INIT _IOW(EMU_IOCTL_BASE, 21,int) +/*#define EMU_PIHF_GET_STATUS _IOR(EMU_IOCTL_BASE, 12,int)*/ +#define EMU_PIHF_SNP_INT_CTL _IOR(EMU_IOCTL_BASE, 23,int) +#define EMU_PIHF_ID_LOW _IO(EMU_IOCTL_BASE, 24) +#define EMU_PIHF_ID_HIGH _IO(EMU_IOCTL_BASE, 25) +#define EMU_PIHF_INIT_DPLUS_CTL _IO(EMU_IOCTL_BASE, 26) + +/* EMU EIHF */ +#define EMU_EIHF_INIT _IOW(EMU_IOCTL_BASE, 31,int) +#define EMU_EIHF_MUTE _IO(EMU_IOCTL_BASE, 32) +#define EMU_EIHF_UNMUTE _IO(EMU_IOCTL_BASE, 33) + +typedef enum{ + EMU_SWITCH_TO_UART = 0, + EMU_SWITCH_TO_USB, + EMU_SWITCH_TO_AUDIO_MONO, + EMU_SWITCH_TO_AUDIO_STEREO, + EMU_SWITCH_TO_NO_DEV +} T_EMU_SWITCH_TO; + +void emu_switch_to(T_EMU_SWITCH_TO to); +#endif /* EMU_PIHF_FEATURE */ Index: linux-2.6.16.5-a/drivers/misc/ezx/ezx-log.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/misc/ezx/ezx-log.c 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,183 @@ +/* + * Kernel panic log interface for Linux on A760(XScale PXA262). + * + * Copyright (c) 2000 Motorola + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * 0.01 2003-07-01 zxf + * - initial release + */ + +#include +#include +#include +#include + +#include +#include + +#include "log.h" + +#define A760_LOG_NAME "A760" +#define A760_LOG_START 0x01fc0000 +#define A760_LOG_SIZE 0x00020000 + +#define E680_LOG_NAME "E680" +#define E680_LOG_START 0x01fc0000 +#define E680_LOG_SIZE 0x00020000 + +#define A780_LOG_NAME "A780" +#define A780_LOG_START 0x01fc0000 +#define A780_LOG_SIZE 0x00020000 + +#ifdef CONFIG_ARCH_EZX_E680 +#define LOG_NAME E680_LOG_NAME +#define LOG_START E680_LOG_START +#define LOG_SIZE E680_LOG_SIZE +#elif CONFIG_ARCH_EZX_A780 +#define LOG_NAME A780_LOG_NAME +#define LOG_START A780_LOG_START +#define LOG_SIZE A780_LOG_SIZE +#else +#define LOG_NAME A760_LOG_NAME +#define LOG_START A760_LOG_START +#define LOG_SIZE A760_LOG_SIZE +#endif + +static ssize_t log_read(const char *buf, size_t count, loff_t *ppos); +static ssize_t log_write(const char *buf, size_t count); + +static struct log_area flash_log = { + name: LOG_NAME, //"A760", + start: LOG_START, // LOGO_ADDR is 0x01fc0000 + size: LOG_SIZE, + write: log_write, + read: log_read, +}; + +/* + * Here the read implementation should not impact mtd device. + * Most part of the read function is coming from mtdchar.c + */ +#define MAX_KMALLOC_SIZE 0x20000 +static ssize_t log_read(const char *buf, size_t count, loff_t *ppos) +{ + struct mtd_info *mtd; + size_t retlen=0; + size_t total_retlen=0; + int ret=0; + int len; + char *kbuf; + + mtd = get_mtd_device(NULL, 3); + if (!mtd) + return -ENODEV; + + while (count) { + if (count > MAX_KMALLOC_SIZE) + len = MAX_KMALLOC_SIZE; + else + len = count; + + kbuf=kmalloc(len,GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + + ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf); + if (!ret) { + *ppos += retlen; + if (copy_to_user(buf, kbuf, retlen)) { + kfree(kbuf); + return -EFAULT; + } + else + total_retlen += retlen; + + count -= retlen; + buf += retlen; + } + else { + kfree(kbuf); + return ret; + } + + kfree(kbuf); + } + + return total_retlen; +} + +static ssize_t log_write(const char *buf, size_t count) +{ + int i; + ssize_t ret; + void *area; + unsigned short *buffer; + volatile unsigned short *ptr; + + //printk(KERN_EMERG "****** panic time: %d ******\n", OSCR); + + area = __ioremap(flash_log.start, flash_log.size, 0); + if (!area) + return -ENOMEM; + + ptr = (unsigned short *)area; + ret = count; + +#define EZX_A760 +#ifdef EZX_A760 + /* wait state ready */ + *ptr = 0x70; + while (!((*ptr) & 0x80)); + + /* unlock the block */ + *ptr = 0x60; *ptr = 0xd0; + while (!((*ptr) & 0x80)); + + /* erase the block */ + *ptr = 0x20; *ptr = 0xd0; + while (!((*ptr) & 0x80)); + +#elif EZX_BVD + // bvd platform + // same as A760 +#endif + + /* program the block */ + if(count > flash_log.size) + count = flash_log.size; + count = count / sizeof(unsigned short); /* it doesn't matter to lose a little data */ + buffer = (unsigned short *)buf; + for (i = 0; i < count; i++, ptr++) { + *ptr = 0x40; + *ptr = *buffer++; + while (!((*ptr) & 0x80)); + } + + //printk(KERN_EMERG "****** panic time: %d ******\n", OSCR); + __iounmap(area); + return ret; +} + + +static int __init ezxlog_init(void) +{ + return log_register(&flash_log); +} + +static void __exit ezxlog_exit(void) +{ + log_unregister(&flash_log); +} + +module_init(ezxlog_init); +module_exit(ezxlog_exit); + +MODULE_AUTHOR("zxf "); +MODULE_DESCRIPTION("A760 Kernel panic log interface"); +MODULE_LICENSE("GPL"); +EXPORT_NO_SYMBOLS; Index: linux-2.6.16.5-a/drivers/misc/ezx/ezx-ts.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/misc/ezx/ezx-ts.c 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,910 @@ +/* + * linux/drivers/char/ezx-ts.c + * + * Copyright (C) 2002 Lili Jiang, All Rights Reserved. + * + * + * June, 2002 Lili Jiang, create + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "ezx-ts.h" +#include "ssp_pcap.h" + +#define DEBUG 0 /*change it when formal release*/ +#if DEBUG +# define TS_DPRINTK(s...) printk(s) +#else +# define TS_DPRINTK(s...) +#endif + +/* + * This structure is nonsense - millisecs is not very useful + * since the field size is too small. Also, we SHOULD NOT + * be exposing jiffies to user space directly. + */ +struct ts_event { + u16 pressure; + u16 x; + u16 y; + u16 pad; +// struct timeval stamp; +}; + +static struct timer_list ezx_ts_penup_timer; + +static struct irqaction ezx_ts_custom_timer_irq = { + name: "ezx_ts_custom_timer", +}; + +static u8 bSetPenupTimer = 0; +static u8 bFirstPen = 0; +//static unsigned long penCurJiffies = 0; +static unsigned int penSampleCount = 0; +static u32 tspenSampleCount = 0; +static u32 tsDiscardDataCount = 0; + +typedef enum +{ + PRESSURE, + COORDINATE +}EZX_TS_READ_STATE; + +EZX_TS_READ_STATE ezx_ts_read_state = PRESSURE; + +#define TS_NR_EVENTS 128 +/*250 //pay attention to that haed and tail is defined as u8*/ + +#define TS_EDGE_MIN_LIMIT (0) /* 10 */ +#define TS_EDGE_MAX_LIMIT (1023) + +/* jiffies : 10ms, pen shake 50ms????? */ +//#define EZX_TS_READ_MIN_SPACE 10 /*100//5*/ +//#define EZX_TS_PENUP_TIMEOUT_MS 8 + +#define EZX_TS_PENSAMPLE_TIMEOUT_MS 2 + //8,6 +//#define EZX_TS_HWR_TIMEOUT_MS 2 + +#define QT_ONEPEN_SAMPLES_NUM 1 + //3,5 +//#define HWR_ONEPEN_SAMPLES_NUM 1 + +#define CUSTOM_ONEPEN_SAMPLES_NUM 1 +#define EZX_TS_CUSTOM_TIMEOUT_MS 12 + //15ms +#define X_DIFF 85 +#define Y_DIFF 75 +#define MIN_X_HOLD 5 +#define MIN_Y_HOLD 4 +#define SAMPLE_COUNT_NOT_JUMPER 20 + +typedef enum +{ + EZX_PEN_NORMAL, + EZX_PEN_CUSTOM +}EZX_TS_PEN_STYLE; + +static EZX_TS_PEN_STYLE gPenStyle = EZX_PEN_NORMAL; +static u8 gPenSamplesNum = QT_ONEPEN_SAMPLES_NUM; +//static u32 gHwrTimer = EZX_TS_HWR_TIMEOUT_MS; +static u32 gCustomTimer = EZX_TS_CUSTOM_TIMEOUT_MS; +static u8 getPenUp = 0; + +struct ezx_ts_info { + /*struct ucb1x00 *ucb;*/ + struct fasync_struct *fasync; + wait_queue_head_t read_wait; + + /* + struct semaphore irq_wait; + struct semaphore sem; + struct completion init_exit; + struct task_struct *rtask; + */ + u16 x_cur; /*store the current pen value read from ADC*/ + u16 y_cur; /*store the current pen value read from ADC */ + u16 cur_pressure; + u16 x_pre; + u16 y_pre; + u8 evt_head; + u8 evt_tail; + struct ts_event events[TS_NR_EVENTS]; /* buffer for store pen data*/ +/* + int restart:1; + int adcsync:1; + +#ifdef CONFIG_PM + struct pm_dev *pmdev; +#endif +*/ +}; + +static struct ezx_ts_info ezxts; + +#define EZX_TS_SHAKE_SAMPLES 3 +static u8 ezx_ts_shake_samples_count = 0; +static struct ts_event ezx_ts_shake_samples[EZX_TS_SHAKE_SAMPLES]; + +static int ezx_ts_init(void); +static void ezx_ts_exit(void); +static int ezx_ts_open(struct inode *inode, struct file * filp); +static int ezx_ts_release(struct inode *inode, struct file *filp); +static ssize_t ezx_ts_read(struct file* filp, char* buffer, size_t count, loff_t *ppos); +static unsigned int ezx_ts_poll(struct file* filp, struct poll_table_struct * wait); +static int ezx_ts_fasync(int fd, struct file* filp, int mode); + +/* internal function */ +static void ezx_ts_init_penEvent(void); +static void ezx_ts_pen_touch_handler(void); +static void ezx_ts_penup_timeout(unsigned long data); +static void ezx_ts_set_timer(struct timer_list *timer, void (*timer_timeout)(unsigned long), signed long timeout); +static void ezx_ts_check_pen_samples(void); +static void ezx_ts_evt_add(u16 pressure, u16 x, u16 y); +static struct ts_event ezx_ts_get_onedata(void); + +/* for setup ezx ts self timer,begin */ +static void ezx_ts_custom_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + TS_DPRINTK("ezx_ts_custom_timer_interrupt entered.jiffies: %d\n@@@\n", jiffies); + SSP_PCAP_TSI_mode_set(PCAP_TS_POSITION_XY_MEASUREMENT); + SSP_PCAP_TSI_start_XY_read(); + + /* clear this timer */ + OIER &= ~OIER_E3; + OSSR = OSSR_M3; /* Clear match on timer 2 */ +} + +static void ezx_ts_custom_setup_timer() +{ + ezx_ts_custom_timer_irq.handler = ezx_ts_custom_timer_interrupt; + setup_irq(IRQ_OST3, &ezx_ts_custom_timer_irq); +} + + +static void ezx_ts_custom_timer_start(void) +{ + OIER |= OIER_E3; + //OSMR2 = OSCR + sleep_limit * LATCH; //OSCR: 0x40A00010 + OSMR3 = OSCR + (gCustomTimer * HZ * LATCH) /1000; +} + +static void ezx_ts_custom_timer_stop(void) +{ + OIER &= ~OIER_E3; + OSSR = OSSR_M3; /* Clear match on timer 2 */ +} + +/* for setup ezx ts self timer, end */ + + +static void ezx_ts_init_penEvent(void) +{ + int i; + + ezxts.x_cur = 0; + ezxts.y_cur = 0; + ezxts.x_pre = 0; + ezxts.y_pre = 0; + ezxts.cur_pressure = PEN_UP; + + for (i = 0; i < TS_NR_EVENTS; i++) + { + ezxts.events[i].pressure=(u16)0; + ezxts.events[i].x=(u16)0; + ezxts.events[i].y=(u16)0; + ezxts.events[i].pad=(u16)0; + } + ezxts.evt_head = 0; + ezxts.evt_tail = 0; + + gPenStyle = EZX_PEN_NORMAL; + gPenSamplesNum = QT_ONEPEN_SAMPLES_NUM; + //gHwrTimer = EZX_TS_HWR_TIMEOUT_MS; + gCustomTimer = EZX_TS_CUSTOM_TIMEOUT_MS; +} + + +static void ezx_ts_pen_touch_handler(void) +{ + SSP_PCAP_TSI_mode_set(PCAP_TS_PRESSURE_MEASUREMENT); + SSP_PCAP_TSI_start_XY_read(); + ezx_ts_read_state = PRESSURE; + ezxts.x_pre = 0; + ezxts.y_pre = 0; + + TS_DPRINTK("ezx_ts pen touch handler done.\n"); +} + +static void ezx_ts_penup_timeout(unsigned long data) +{ + TS_DPRINTK("@@@\nIn pen drag! jiffies: %d\n@@@\n", jiffies); + bSetPenupTimer = 0; + SSP_PCAP_TSI_mode_set(PCAP_TS_POSITION_XY_MEASUREMENT); + SSP_PCAP_TSI_start_XY_read(); +} + +static void ezx_ts_check_pen_samples(void) +{ + if ( (ezx_ts_read_state == COORDINATE) && (penSampleCount != 0 ) ) + { + int k; + if (penSampleCount < gPenSamplesNum) + { + for ( k = 0; k < (gPenSamplesNum - penSampleCount); k++) + { + ezx_ts_evt_add(PEN_DOWN, ezxts.x_cur, ezxts.y_cur); + TS_DPRINTK("ezx_ts_add_additional_samples: %d\n", k); + } + } + TS_DPRINTK("ezx_ts_evt_add: PEN_UP\n"); + //ezx_ts_evt_add(PEN_UP, 0, 0); + } + + if (bSetPenupTimer) + { + del_timer(&ezx_ts_penup_timer); + bSetPenupTimer = 0; + TS_DPRINTK("^^^^Delete penup timer1.\n"); + } + penSampleCount = 0; +} + +static void ezx_ts_set_timer(struct timer_list *timer, void (*timer_timeout)(unsigned long), + signed long timeout) +{ + init_timer(timer); + timer->expires = timeout + jiffies; + timer->data = (unsigned long) current; + timer->function = timer_timeout; + + add_timer(timer); + //TS_DPRINTK("ezx_ts set timer done.\n"); +} + +static void ezx_ts_evt_add(u16 pressure, u16 x, u16 y) +{ + int next_head; + int last_head; + /* if pen_up, then copy pressure=0, last_evt.x y to current evt*/ + + next_head = ezxts.evt_head + 1; + if (next_head == TS_NR_EVENTS) + { + next_head = 0; + } + + last_head = ezxts.evt_head - 1; + if (last_head == -1) + { + last_head = TS_NR_EVENTS - 1; + } + +/* if (next_head != ezxts.evt_tail)*/ + //{ + if ( pressure == PEN_DOWN) + { +/* if ( (penSampleCount >1) && ((penCurJiffies + EZX_TS_READ_MIN_SPACE) < jiffies)) + { + // see two ~ four data or just ignore the data except the first one???? + return; + } + else*/ + //{ + ezxts.events[ezxts.evt_head].pressure = pressure; + ezxts.events[ezxts.evt_head].x = x; + ezxts.events[ezxts.evt_head].y = y; + TS_DPRINTK("ezx_store: x: %d, y :%d, pressure: 0x%x\n", x, y, pressure); + //} + } + else + { + ezxts.events[ezxts.evt_head].pressure = pressure; + ezxts.events[ezxts.evt_head].x = ezxts.events[last_head].x; + ezxts.events[ezxts.evt_head].y = ezxts.events[last_head].y; + TS_DPRINTK("ezx_store: PEN_UP\n"); + } + //} +// do_gettimeofday(&(ezxts.events[ezxts.evt_head].stamp)); + ezxts.evt_head = next_head; + + if (ezxts.evt_head == ezxts.evt_tail) + { + if ( ++ezxts.evt_tail == TS_NR_EVENTS ) + ezxts.evt_tail = 0; + } + + if (ezxts.fasync) + kill_fasync(&ezxts.fasync, SIGIO, POLL_IN); + wake_up_interruptible(&ezxts.read_wait); +} + +static struct ts_event ezx_ts_get_onedata(void) +{ + int cur = ezxts.evt_tail; + + if (++ezxts.evt_tail == TS_NR_EVENTS) + ezxts.evt_tail = 0; + + return ezxts.events[cur]; +} + +/***************************************************************************** + * FUNCTION NAME : ezx_ts_open() + * + * INPUTS: + * + * OUTPUTS: pen info from ts event structure + * + * VALUE RETURNED: none + * + * DESCRIPTION: + * i) Increase this device module used count. + * ii) Initialize a buffer for store data read from touch screen interface. + * iii) Initialize touch screen interface hardware. + * iv) Setup touch screen wait queue. +***************************************************************************** + */ +static int ezx_ts_open(struct inode *inode, struct file * filp) +{ + struct ezx_ts_info *ts = &ezxts; + +/* ssp_pcap_init(); // change to _start_kernel + ssp_pcap_open(); */ + ssp_pcap_open(SSP_PCAP_TS_OPEN); + SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_MSR_TSM); + + ezx_ts_init_penEvent(); + filp->private_data = ts; + + + TS_DPRINTK("ezx touch screen driver opened\n"); + return 0; +} + +/* Decrease this device module used count. */ +static int ezx_ts_release(struct inode *inode, struct file *filp) +{ + ezx_ts_init_penEvent(); + ezx_ts_fasync(-1, filp, 0); + + TS_DPRINTK("ezx touch screen driver closed\n"); + return 0; +} + +/***************************************************************************** + * FUNCTION NAME : ezx_ts_read + * + * INPUTS: + * + * OUTPUTS: pen info from ts event structure + * + * VALUE RETURNED: none + * + * DESCRIPTION: + * This is used for UI app to call. + * If device is opened by nonblock mode then copy available data from the ts event buffer + * to user buffer and return the actual read data count, if device is opened by block mode + * and no data available then sleep until the required data count be read completed. + * + * CAUTIONS: + * + * + ***************************************************************************** + */ +static ssize_t ezx_ts_read(struct file* filp, char* buffer, size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + + struct ezx_ts_info *ts = filp->private_data; + char *ptr = buffer; + int err = 0; + struct ts_event evt; + + add_wait_queue(&ts->read_wait, &wait); + while (count >= sizeof(struct ts_event)) + { + err = -ERESTARTSYS; + if (signal_pending(current)) + break; + if ((ts)->evt_head != (ts)->evt_tail) + { + evt = ezx_ts_get_onedata(); /*evt_tail pos changed in this func*/ + err = copy_to_user(ptr, &evt, sizeof(struct ts_event)); + + if (err) + break; + //printk("ezx_ts_read: x:%d, y:%d, pressure:0x%x\n", evt.x, evt.y, evt.pressure); + ptr += sizeof(struct ts_event); + count -= sizeof(struct ts_event); + continue; + } + + set_current_state(TASK_INTERRUPTIBLE); + err = -EAGAIN; + if (filp->f_flags & O_NONBLOCK) + break; + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&(ts->read_wait), &wait); + + return ptr == buffer ? err : ptr - buffer; + +} + +/* +This function is used in nonblock mode to determine whether it can read data from touch screen +device without blocking. +Call poll_wait to wait until read operation status changed then return POLLIN (flag of device can be +read without blocking) | POLLRDNORM (flag of data is available) bit mask if there is readable data +now. +*/ + +static unsigned int ezx_ts_poll(struct file* filp, struct poll_table_struct * wait) +{ + struct ezx_ts_info *ts = filp->private_data; + int ret = 0; + + if ( ts != NULL) + { + TS_DPRINTK("ezx_ts_poll.\n"); + poll_wait(filp, &ts->read_wait, wait); + if (ts->evt_head != ts->evt_tail) + { + TS_DPRINTK("ezx_ts_poll: ts->evt_head != ts->evt_tail\n"); + ret = POLLIN | POLLRDNORM; + } + } + + return ret; +} + +/* Setup fasync queue for touch screen device. */ + +static int ezx_ts_fasync(int fd, struct file* filp, int mode) +{ + struct ezx_ts_info *ts = filp->private_data; + + if ( ts != NULL) + { + TS_DPRINTK("ezx_ts_fasync.\n"); + return fasync_helper(fd, filp, mode, &ts->fasync); + } + else return 0; +} + +static int +ezx_ts_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) +{ + int res = 0; + + TS_DPRINTK("ezx_ts_ioctl: arg is %d\n", arg); + switch (cmd) { +/* + case SETTONORMAL: + TS_DPRINTK("ezx_ts_ioctl_test: This is SETTONORMAL.\n"); + gPenStyle = EZX_PEN_NORMAL; + gPenSamplesNum = QT_ONEPEN_SAMPLES_NUM; + //gHwrTimer = EZX_TS_HWR_TIMEOUT_MS; + gCustomTimer = EZX_TS_CUSTOM_TIMEOUT_MS; + break; + + case SETTOHWR: + TS_DPRINTK("ezx_ts_ioctl_test: This is SETTOHWR.\n"); + gPenStyle = EZX_PEN_HWR; + gPenSamplesNum = HWR_ONEPEN_SAMPLES_NUM; + if ( (arg > 0 ) && (arg < 100) ) + { + gHwrTimer = arg; + TS_DPRINTK("ezx_ts_ioctl_test: gHwrTimer is %d.\n", gHwrTimer); + } + break; + + case SETTOCUSTOM: + TS_DPRINTK("ezx_ts_ioctl_test: This is SETTOCUSTOM.\n"); + gPenStyle = EZX_PEN_CUSTOM; + gPenSamplesNum = CUSTOM_ONEPEN_SAMPLES_NUM; + if ( (arg > 0 ) && (arg < 100) ) + { + gCustomTimer = arg; + TS_DPRINTK("ezx_ts_ioctl_test: gCustomTimer is %d.\n", gCustomTimer); + } + break; + case GETPENSTYLE: + TS_DPRINTK("ezx_ts_ioctl_test: This is GETPENSTYLE.\n"); + put_user(gPenStyle, (u32*)arg); + break; + default: + res = -EINVAL; +*/ + } + + return res; +} + +/***************************************************************************** + * FUNCTION NAME : ezx_ts_touch_interrupt + * + * INPUTS: + * + * + * OUTPUTS: + * + * + * VALUE RETURNED: + * + * + * DESCRIPTION: + * This is touch screen touch interrupt service routine called by PCAP module when touch screen + * interrupt happened. First eliminate shake signal to get stable touch screen press information. + * Then write instruction to PCAP register to read ADC conversion value of pressed spot x,y coordinate + * and return. + * + * CAUTIONS: + * + * + * + ***************************************************************************** + */ +void ezx_ts_touch_interrupt(int irq, void* dev_id, struct pt_regs *regs) +{ + TS_DPRINTK("ezx_ts_touch_irq happened.\n"); + ezx_ts_shake_samples_count = 0; + //TS_DPRINTK("ezx_ts_touch_irq excuted.\n"); + ezx_ts_check_pen_samples(); + ezx_ts_pen_touch_handler(); + +} + +/***************************************************************************** + * FUNCTION NAME : ezx_ts_dataReadok_interrupt + * + * INPUTS: call PCAP API to read x,y + * + * OUTPUTS: Store the pen info to ts event structure + * + * VALUE RETURNED: none + * + * DESCRIPTION: + * This is called by PCAP module to deal with the touch screen press raw information read from ADC + * when ADC data conversion finished. It performs write the data to ts event buffer for user to + * read out. + * + * CAUTIONS: Consider pen shake + * + * + ***************************************************************************** + */ +void ezx_ts_dataReadok_interrupt(int irq, void* dev_id, struct pt_regs *regs) +{ + static u16 pressure; + u16 x; + u16 y; + U16 tempx,tempy; + + if (SSP_PCAP_TSI_get_XY_value(&x, &y) != SSP_PCAP_SUCCESS) + { + return; + } + /* convert x,y???? */ + // TS_DPRINTK( "ezx_ts_get_XY_value: x:%d, y:%d\n",x, y); + /* TS_DPRINTK( "\nezx_ts before convert: x:%d, y:%d\n",x, y);*/ + + if ( ezx_ts_read_state == PRESSURE) + { + if (( y >= TS_EDGE_MAX_LIMIT ) || (y <= TS_EDGE_MIN_LIMIT)) + { + TS_DPRINTK("ezx_ts_datareadok_irq: PEN_UP.\n"); + pressure = PEN_UP; + ezxts.cur_pressure = PEN_UP; + + /*ezx_ts_check_pen_samples();*/ + if ( getPenUp == 0 ) + { + ezx_ts_evt_add( pressure, 0, 0); + } + SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_MSR_TSM); + return; + } + else + { + TS_DPRINTK("ezx_ts_datareadok_irq: PEN_DOWN.\n"); + getPenUp = 0; + pressure = PEN_DOWN; + ezxts.cur_pressure = PEN_DOWN; + tspenSampleCount = 0; + ezxts.x_pre = 0; + ezxts.y_pre = 0; + bFirstPen = 1 ; + SSP_PCAP_TSI_mode_set(PCAP_TS_POSITION_XY_MEASUREMENT); + SSP_PCAP_TSI_start_XY_read(); + ezx_ts_read_state = COORDINATE; + + //TS_DPRINTK("ezx_ts_datareadok_irq: Begin read XY.\n"); + return; + } + } + else if ( ezx_ts_read_state == COORDINATE) + {/* + u8 count; + + count = 0; + while ( (( x <= TS_EDGE_MIN_LIMIT)||( x >= TS_EDGE_MAX_LIMIT) || + ( y <= TS_EDGE_MIN_LIMIT)||( y >= TS_EDGE_MAX_LIMIT)) + && (count++ < 15) ) + { + SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_MSR_TSM); + SSP_PCAP_TSI_mode_set(PCAP_TS_POSITION_XY_MEASUREMENT); + SSP_PCAP_TSI_start_XY_read(); + } + */ + if ( ( x <= TS_EDGE_MIN_LIMIT)||( x >= TS_EDGE_MAX_LIMIT) || + ( y <= TS_EDGE_MIN_LIMIT)||( y >= TS_EDGE_MAX_LIMIT) ) + { /* regard it as PEN_UP */ + pressure = PEN_UP; + ezxts.cur_pressure = PEN_UP; + x = 0; + y = 0; + tspenSampleCount = 0; + SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_MSR_TSM); + /*del_timer(&ezx_ts_read_timer);*/ + ezx_ts_check_pen_samples(); + ezx_ts_evt_add( pressure, 0, 0); + /* SSP_PCAP_bit_clean( SSP_PCAP_ADJ_BIT_MSR_TSM);*/ + ezx_ts_read_state = PRESSURE; + getPenUp = 1; + TS_DPRINTK( "ezx_ts Invalid x,y position: PEN_UP?\n"); + return; + } + getPenUp = 0; + penSampleCount++; + //TS_DPRINTK("ezx_ts_datareadok_irq: Begin store XY %d.\n", penSampleCount); + + if ( gPenStyle == EZX_PEN_CUSTOM ) + { + if ( ((ezxts.x_pre == 0) && (ezxts.y_pre == 0)) + || ( (ezxts.x_pre != 0) && (ezxts.y_pre != 0) + &&(!((abs(ezxts.x_pre - x) > X_DIFF) || (abs(ezxts.y_pre - y) > Y_DIFF))) ) + ) + { + //TS_DPRINTK("ezx_ts_datareadok_irq: diff <= XY_DIFF.\n"); + + ezxts.x_pre = x; + ezxts.y_pre = y; + + TS_DPRINTK("ezx_ts_datareadok_irq:x_pre=%d,y_pre=%d\n", ezxts.x_pre, ezxts.y_pre); + ezxts.x_cur = x; + ezxts.y_cur = y; + ezx_ts_evt_add(pressure, ezxts.x_cur, ezxts.y_cur); + //printk("ezx_ts_datareadok_irq_custom add pressure0x%x,x_cur%d,y_cur%d\n",pressure,ezxts.x_cur,ezxts.y_cur); + ezx_ts_custom_timer_start(); + } + else + { + //TS_DPRINTK("ezx_ts_datareadok_irq: DIFF > XY_DIFF\n"); + SSP_PCAP_TSI_mode_set(PCAP_TS_POSITION_XY_MEASUREMENT); + SSP_PCAP_TSI_start_XY_read(); + TS_DPRINTK("ezx_ts_datareadok_irq:x_pre=%d,y_pre=%d, x=%d,y=%d\n", ezxts.x_pre, ezxts.y_pre,x,y); + } + + + /* + if ( ezx_ts_shake_samples_count < EZX_TS_SHAKE_SAMPLES ) + { + ezx_ts_shake_samples[ezx_ts_shake_samples_count].x = x; + ezx_ts_shake_samples[ezx_ts_shake_samples_count].y = y; + ezx_ts_shake_samples[ezx_ts_shake_samples_count++].pressure = PEN_DOWN; + SSP_PCAP_TSI_mode_set(PCAP_TS_POSITION_XY_MEASUREMENT); + SSP_PCAP_TSI_start_XY_read(); + TS_DPRINTK("ezx_ts_read_shake_samples%d:x=%d,y=%d\n", ezx_ts_shake_samples_count,x,y); + } + if (ezx_ts_shake_samples_count >= EZX_TS_SHAKE_SAMPLES) + { + if ( (abs(ezx_ts_shake_samples[0].x - ezx_ts_shake_samples[1].x) > X_DIFF) || + (abs(ezx_ts_shake_samples[0].y - ezx_ts_shake_samples[1].y) > Y_DIFF) || + (abs(ezx_ts_shake_samples[1].x - ezx_ts_shake_samples[2].x) > X_DIFF) || + (abs(ezx_ts_shake_samples[1].y - ezx_ts_shake_samples[2].y) > Y_DIFF) + ) + { + // throw these data and re-read + ezx_ts_shake_samples_count = 0; + } + else //save to ts_event queue + { + ezxts.x_pre = ezxts.x_cur; + ezxts.y_pre = ezxts.y_cur; + TS_DPRINTK("ezx_ts_datareadok_irq:x_pre=%d,y_pre=%d\n", ezxts.x_pre, ezxts.y_pre); + ezxts.x_cur = (ezx_ts_shake_samples[0].x + ezx_ts_shake_samples[1].x + ezx_ts_shake_samples[2].x) / 3; + ezxts.y_cur = (ezx_ts_shake_samples[0].y + ezx_ts_shake_samples[1].y + ezx_ts_shake_samples[2].y) / 3;; + ezx_ts_shake_samples_count = 0; + ezx_ts_evt_add(pressure, ezxts.x_cur, ezxts.y_cur); + } + ezx_ts_custom_timer_start(); + } + */ + } + else + { + /* ezxts.x_pre and ezxts.y_pre store the last position */ + tspenSampleCount ++; + if(1 == tspenSampleCount) + { + ezxts.x_cur = x; + ezxts.y_cur = y; + if( 0 == bSetPenupTimer ) + { + SSP_PCAP_TSI_mode_set(PCAP_TS_POSITION_XY_MEASUREMENT); + SSP_PCAP_TSI_start_XY_read(); + } + } + else if (2 == tspenSampleCount) + { + tspenSampleCount = 0; + + tempx = (ezxts.x_cur > x? ezxts.x_cur - x:x - ezxts.x_cur); + tempy = (ezxts.y_cur > y? ezxts.y_cur - y:y - ezxts.y_cur); + if(tempx <= X_DIFF && tempy <= Y_DIFF ) + { + x = (x+ezxts.x_cur)/2; + y = (y+ezxts.y_cur)/2; + if( 1 == bFirstPen) + { + bFirstPen = 0; + ezxts.x_pre = x; + ezxts.y_pre = y; + } + tempx = ( ezxts.x_pre > x? ezxts.x_pre -x:x - ezxts.x_pre); + tempy = ( ezxts.y_pre > y? ezxts.y_pre -y:y - ezxts.y_pre); + if(tempx <= X_DIFF && tempy <= Y_DIFF ) + { + tsDiscardDataCount = 0; + if(tempx > MIN_X_HOLD || tempy > MIN_Y_HOLD) + { + ezxts.x_pre = x; + ezxts.y_pre = y; + } + ezx_ts_evt_add(pressure, ezxts.x_pre, ezxts.y_pre); + if ( bSetPenupTimer == 0 ) + { + ezx_ts_set_timer(&ezx_ts_penup_timer, ezx_ts_penup_timeout, + EZX_TS_PENSAMPLE_TIMEOUT_MS); + TS_DPRINTK("ezx_ts_datareadok_irq: set timer pen sample\n"); + bSetPenupTimer = 1; + } + } + else + { + + tsDiscardDataCount ++; + if(tsDiscardDataCount > SAMPLE_COUNT_NOT_JUMPER) + { + tsDiscardDataCount = 0; + ezxts.x_pre = x; + ezxts.y_pre = y; + ezx_ts_evt_add(pressure, ezxts.x_pre, ezxts.y_pre); + if ( bSetPenupTimer == 0 ) + { + ezx_ts_set_timer(&ezx_ts_penup_timer, ezx_ts_penup_timeout, + EZX_TS_PENSAMPLE_TIMEOUT_MS); + TS_DPRINTK("ezx_ts_datareadok_irq: set timer pen sample\n"); + bSetPenupTimer = 1; + } + } + else if( 0 == bSetPenupTimer ) + { + SSP_PCAP_TSI_mode_set(PCAP_TS_POSITION_XY_MEASUREMENT); + SSP_PCAP_TSI_start_XY_read(); + } + } + } + else + { + if( 0 == bSetPenupTimer ) + { + SSP_PCAP_TSI_mode_set(PCAP_TS_POSITION_XY_MEASUREMENT); + SSP_PCAP_TSI_start_XY_read(); + } + } + } + else /* discard the case */ + { + tspenSampleCount = 0; + if( 0 == bSetPenupTimer ) + { + SSP_PCAP_TSI_mode_set(PCAP_TS_POSITION_XY_MEASUREMENT); + SSP_PCAP_TSI_start_XY_read(); + } + } + } + /*if (penSampleCount >= gPenSamplesNum) + { + penSampleCount = 0; + }*/ + //TS_DPRINTK("ezx_ts_datareadok_irq: read XY finished.\n"); + } + +} + + +static struct file_operations ezx_ts_fops = { + .owner = THIS_MODULE, + .read = ezx_ts_read, + .poll = ezx_ts_poll, + .open = ezx_ts_open, + .release = ezx_ts_release, + .fasync = ezx_ts_fasync, + .ioctl = ezx_ts_ioctl, +}; + +/* + * miscdevice structure for misc driver registration. + */ +static struct miscdevice ezx_ts_dev = +{ + .minor = EZX_TS_MINOR_ID, + .name = "ezx_ts", + .fops = &ezx_ts_fops, +}; + +/*Register touch screen device in misc devices.*/ +static int ezx_ts_init(void) +{ + int ret; + + init_waitqueue_head(&ezxts.read_wait); + ret = misc_register(&ezx_ts_dev); + + if (ret<0) + { + printk("ezx_ts_dev: failed to registering the device\n"); + } + ezx_ts_custom_setup_timer(); + + TS_DPRINTK("ezx_ts_init done.\n"); + return ret; +} + +/*Unregister touch screen device.*/ +static void ezx_ts_exit(void) +{ + + if (bSetPenupTimer) + { + del_timer(&ezx_ts_penup_timer); + bSetPenupTimer = 0; + } + + ezx_ts_custom_timer_stop(); + + misc_deregister(&ezx_ts_dev); + + TS_DPRINTK("ezx touch screen driver removed\n"); +} + +module_init(ezx_ts_init); +module_exit(ezx_ts_exit); + +MODULE_DESCRIPTION("ezx touchscreen driver"); +MODULE_LICENSE("GPL"); Index: linux-2.6.16.5-a/drivers/misc/ezx/ezx-ts.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/misc/ezx/ezx-ts.h 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,22 @@ +/* + * linux/drivers/char/ezx-ts.c + * + * Copyright (C) 2002 Lili Jiang, All Rights Reserved. + * + * + * June, 2002 Lili Jiang, create + */ + +#ifndef _EZXTS_H +#define _EZXTS_H + +#define EZX_TS_MINOR_ID 14 + +#define PEN_UP 0 +#define PEN_DOWN 0xffff + +/* extern functio nfor PCAP */ +void ezx_ts_touch_interrupt(int irq, void* dev_id, struct pt_regs *regs); +void ezx_ts_dataReadok_interrupt(int irq, void* dev_id, struct pt_regs *regs); + +#endif //_EZXTS_H Index: linux-2.6.16.5-a/drivers/misc/ezx/fmradio.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/misc/ezx/fmradio.c 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,249 @@ +/* + * linux/drivers/i2c/fmradio.c + * + * Support for the Motorola Ezx A780 Development Platform. + * + * Author: Jay Jia + * Created: Nov 25, 2003 + * Copyright: Motorola Inc. + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../../../sound/oss/ezx-common.h" +#include "fmradio.h" + +#define I2C_FMRADIO 0x81 + +static int fmradio_adapter_attach(struct i2c_adapter *adap); +static int fmradio_detach(struct i2c_client *client); +static int fmradio_client_register(struct i2c_client *client); +static int fmradio_client_unregister(struct i2c_client *client); +/* ----------------------------------------------------------------------- */ +static struct i2c_driver driver = { + .owner = THIS_MODULE, + .name = "fmradio driver", + .id = I2C_FMRADIO, + //.flags = I2C_DF_DUMMY, + .attach_adapter = fmradio_adapter_attach, + .detach_client = fmradio_detach, +}; + +static struct i2c_adapter fmradio_adapter = { + .owner = THIS_MODULE, + .name = "fmradio adapter", + .id = I2C_FMRADIO, + .client_register = fmradio_client_register, + .client_unregister = fmradio_client_unregister, +}; + +static struct i2c_client client_template = { + .name = "(unset)", + .adapter = &fmradio_adapter, +}; + +struct i2c_client *fmradio_client; + +static int fmradio_open(struct inode *inode, struct file *file) +{ + if( audioonflag & (DSP16_DEVICE|PHONE_DEVICE) ){ +#ifdef EZX_OSS_DEBUG + printk(EZXOSS_DEBUG "E680 open FM EBUSY because 0x%X device is using the sound hardware.\n",audioonflag ); +#endif + return -EBUSY; + } + + + poweron_mixer(FM_DEVICE); + //MOD_INC_USE_COUNT; + + return 0; +} + +static int fmradio_close(struct inode * inode, struct file *file) +{ + unsigned int flags; + unsigned char standby[5] = {0x2a, 0x48, 0xa1, 0xdf, 0x40}; + + //MOD_DEC_USE_COUNT; + //e680_boomer_path_tmp_mono_lineout (); //mute boomer + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_AUD_RX_AMPS_PGA_IN_SW); + + local_irq_save(flags); + enable_irq(IRQ_I2C); + //write standby command + i2c_master_send (fmradio_client, standby, 5); + local_irq_restore(flags); + shutdown_mixer(FM_DEVICE); + + return 0; +} + + +static int fmradio_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + return mixer_ioctl(inode, file, cmd, arg); +} + +static ssize_t fmradio_read(struct file *file, char *buf, size_t count, loff_t *ptr) +{ + char *tmp; + int ret; + unsigned int flags; + + /* copy user space data to kernel space. */ + tmp = kmalloc(count,GFP_KERNEL); + if (tmp==NULL) + return -ENOMEM; + local_irq_save(flags); + enable_irq(IRQ_I2C); + ret = i2c_master_recv(fmradio_client,tmp,count); + local_irq_restore(flags); + if (ret >= 0) + copy_to_user(buf,tmp,count); + kfree(tmp); + return ret; +} +static ssize_t fmradio_write(struct file *file, const char *buf, size_t count, loff_t *ptr) +{ + int ret; + char *tmp; +// char data[4]={0x18,0x7d,0xbd,0xcd}; +// char freq[5]={0x2e,0x56,0x41,0x11,0x40}; +// unsigned char s[5]={0, 0, 0, 0, 0}; + +// mixer_write(data,4); +// i2c_master_send(fmradio_client,freq,5); +// printk("fmradio test code\n"); +// mdelay(300); +// i2c_master_recv(fmradio_client, s, 5); +// printk("s0=%02x s1=%02x s2=%02x s3=%02x s4=%02x \n",s[0],s[1],s[2],s[3],s[4]); + + unsigned int flags; + /* copy user space data to kernel space. */ + tmp = kmalloc(count,GFP_KERNEL); + if (tmp==NULL) + return -ENOMEM; + if (copy_from_user(tmp,buf,count)) { + kfree(tmp); + return -EFAULT; + } + local_irq_save(flags); + enable_irq(IRQ_I2C); + ret = i2c_master_send(fmradio_client,tmp,count); + local_irq_restore(flags); + kfree(tmp); + return ret; +} + +static int fmradio_client_register(struct i2c_client *client) +{ + + return 0; +} + +static int fmradio_client_unregister(struct i2c_client *client) +{ + + return 0; +} +/* ----------------------------------------------------------------------- */ +static struct file_operations fmradio_fops = { + read: fmradio_read, + write: fmradio_write, + ioctl: fmradio_ioctl, + open: fmradio_open, + release: fmradio_close, +}; + +static struct miscdevice fmradio_misc_device = { + FMRADIO_MINOR, + FMRADIO_NAME, + &fmradio_fops, +}; + +/* ----------------------------------------------------------------------- */ + +static int fmradio_adapter_attach(struct i2c_adapter *adap) +{ + if(! (fmradio_client = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) + return -ENOMEM; + memcpy(fmradio_client,&client_template,sizeof(struct i2c_client)); + fmradio_client->adapter = adap; + + fmradio_client->addr = 0x60; + + printk("adapter %s\n",adap->name); + i2c_attach_client(fmradio_client); + + return 0; +} + +static int fmradio_detach(struct i2c_client *client) +{ + i2c_detach_client(fmradio_client); + return 0; +} +/* ----------------------------------------------------------------------- */ + +static int fmradio_init_module(void) +{ + int res; + + res = i2c_add_driver(&driver); + if( res < 0 ) + { + printk("error in add fmradio i2c driver\n"); + return res; + } + + if (misc_register (&fmradio_misc_device)) + { + printk(KERN_ERR "Couldn't register fmradio driver\n"); + return -EIO; + } + return 0; +} + +static void fmradio_cleanup_module(void) +{ + i2c_del_driver(&driver); + misc_deregister(&fmradio_misc_device); +} + +module_init(fmradio_init_module); +module_exit(fmradio_cleanup_module); +MODULE_AUTHOR("Jay Jia"); +MODULE_LICENSE("GPL"); Index: linux-2.6.16.5-a/drivers/misc/ezx/fmradio.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/misc/ezx/fmradio.h 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,7 @@ +#ifndef __FMRADIO_H +#define __FMRADIO_H + +#define FMRADIO_NAME "fmradio" +#define FMRADIO_MINOR 198 + +#endif Index: linux-2.6.16.5-a/drivers/misc/ezx/keylight.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/misc/ezx/keylight.c 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,236 @@ +/* + * linux/drivers/misc/keylight.c --- key backlight driver on ezx + * + * Support for the Motorola Ezx A780 Development Platform. + * + * Author: Jay Jia + * Created: Feb 16, 2004 + * Copyright: Motorola Inc. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "keylight.h" +#include "ssp_pcap.h" +#include + +static int keylight_open_cnt = 0; +static int main_current_brightness = 0xf; +static int aux_current_brightness = 0x1f; + +MODULE_LICENSE("GPL"); + +#ifdef CONFIG_PM +static struct pm_dev *pm_dev; +#endif + +static int keylight_open(struct inode *inode,struct file *file) +{ + keylight_open_cnt++; + + return 0; +} + +static int keylight_close(struct inode *inode,struct file *file) +{ + keylight_open_cnt--; + + if ( keylight_open_cnt == 0 ) + { + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL0); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL1); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL2); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL3); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL4); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL0); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL1); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL2); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL3); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL4); + } + + return 0; +} + +static void keylight_main_turn_off(void) +{ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL0); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL1); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL2); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL3); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL_CTRL4); +} + +static void keylight_aux_turn_off(void) +{ + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL0); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL1); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL2); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL3); + SSP_PCAP_bit_clean(SSP_PCAP_ADJ_BIT_PERIPH_BL2_CTRL4); +} + +static void keylight_main_turn_on(void) +{ + int i,count; + + for( i=0; i<5; i++) + { + count = 1< +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "keypad.h" +#include +#include "asm/arch/ezx.h" + +#ifdef CONFIG_PM +static struct pm_dev *pm_dev; +static struct pm_dev *keypadI_pm_dev; +static int kpc_res,kpkdi_res; +static int GPIO_TC_MM_STATE = 1; +extern unsigned char pxafb_ezx_getLCD_status(void); +#endif +/* + * This is the number of microseconds we wait before checking to see if any + * keys have been released. + */ +#define RDELAY 200 + +#define KEYBUF_EMPTY() (keybuf_start == keybuf_end) +#define KEYBUF_FULL() ( ((keybuf_end+1)%KEYBUF_SIZE) == keybuf_start) +#define KEYBUF_INC(x) ((x) = (((x)+1) % KEYBUF_SIZE)) + +static int keypad_open (struct inode *, struct file *); +static int keypad_close (struct inode *, struct file *); +static int keypad_ioctl (struct inode *, struct file *, + unsigned int, unsigned long); +static unsigned int keypad_poll (struct file *, poll_table *); +static ssize_t keypad_read (struct file *, char *, size_t, loff_t *); + +static int keypadB_open (struct inode *, struct file *); +static int keypadB_close (struct inode *, struct file *); +static int keypadB_ioctl (struct inode *, struct file *, + unsigned int, unsigned long); +static unsigned int keypadB_poll (struct file *, poll_table *); + +static int keypadI_open(struct inode *, struct file *); +static int keypadI_close(struct inode *, struct file *); +static int keypadI_ioctl (struct inode *, struct file *, + unsigned int, unsigned long); + +static void kp_interrupt (int, void *, struct pt_regs *); +#ifdef USE_RELEASE_TIMER +static void release_timer_went_off (unsigned long); +static void do_scan(void); +#endif +static void autorepeat_timer_went_off (unsigned long); + +static int add_to_keybuf (unsigned short); +static int add_events (unsigned long *, unsigned long *); +static int insert_event (unsigned short); +static unsigned short get_from_keybuf (void); +static void scan_to_bitmap + (unsigned long, unsigned long, unsigned long, unsigned long *); +static inline void set_bitmap_to_zero(unsigned long b[]); +static inline void copy_bitmap(unsigned long dest[], unsigned long source[]); +static inline void turn_on_bit(unsigned long map[], int); +static inline void turn_off_bit(unsigned long map[], int); +static inline int any_keys_down (unsigned long *); + +/* + * keybuf is a circular buffer to hold keypad events. + * keybuf_start is the index of the first event. + * keybuf_end is one more than the index of the last event. + * The buffer is empty when keybuf_start == keybuf_end. + * We only use KEYBUF_SIZE-1 entries in the buffer so we can tell + * when it's full without needing another variable to tell us. + * The buffer is full when (keybuf_end+1)%KEYBUF_SIZE == keybuf_start. + */ +static unsigned short keybuf[KEYBUF_SIZE]; +static int keybuf_start = 0; +static int keybuf_end = 0; + +static DECLARE_WAIT_QUEUE_HEAD(keypad_wait); +static spinlock_t keypad_lock = SPIN_LOCK_UNLOCKED; + +static int reading_opens = 0; +static int bitmap_opens = 0; + +/* previous bitmap of keys down */ +static unsigned long oldkeybitmap[NUM_WORDS_IN_BITMAP]; +/* current bitmap of keys down */ +static unsigned long keybitmap[NUM_WORDS_IN_BITMAP]; +/* last bitmap read by ioctl */ +static unsigned long lastioctlbitmap[NUM_WORDS_IN_BITMAP]; + +static unsigned long kpas = 0; /* last value of kpas */ +static unsigned long kpasmkp0 = 0; /* last value of kpasmkp0 */ +static unsigned long kpasmkp1 = 0; /* last value of kpasmkp1 */ +static unsigned long kpasmkp2 = 0; /* last value of kpasamkp2*/ +static unsigned long kpdk = 0; /* last value of kpdk */ + +#ifdef USE_RELEASE_TIMER +static struct timer_list key_release_timer; +static int key_release_interval = RDELAY * HZ/1000; +#endif + +static int do_autorepeat = 1; +static long jiffies_to_first_repeat = 30; +static long jiffies_to_next_repeat = 30; +static struct timer_list autorepeat_timer; + +extern int lockscreen_flag; + +static int +keypad_open(struct inode *inode, struct file *file) +{ +#ifdef KDEBUG + printk(KERN_DEBUG "keypad_open\n"); +#endif + spin_lock(keypad_lock); + if (reading_opens > 0) + { + spin_unlock(keypad_lock); + return -EBUSY; + } + reading_opens++; + spin_unlock(keypad_lock); + + return 0; +} + +static int +keypadB_open(struct inode *inode, struct file *file) +{ +#ifdef KDEBUG + printk(KERN_DEBUG "keypadB_open\n"); +#endif + spin_lock(keypad_lock); + if (bitmap_opens > 0) + { + spin_unlock(keypad_lock); + return -EBUSY; + } + bitmap_opens++; + /* + * poll returns when lastioctlbitmap is different from keybitmap. + * we set lastioctlbitmap to keybitmap here so that a poll right + * after an open returns when the bitmap is different from when + * the open was done, not when the bitmap is different from the + * last time some other process read it + */ + copy_bitmap(lastioctlbitmap, keybitmap); + spin_unlock(keypad_lock); + + return 0; +} + +#if defined(CONFIG_KEYPAD_E680) +#ifdef CONFIG_PM +static int keypadI_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) +{ + switch(req) + { + case PM_SUSPEND: + break; + case PM_RESUME: + GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); + if(GPIO_TC_MM_STATE == 1) + GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); + else + GPCR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); + break; + default: + break; + } + return 0; +} +#endif +#endif + +static int +keypadI_open(struct inode *inode, struct file *file) +{ +#ifdef KDEBUG + printk(KERN_DEBUG "keypadI_open\n"); +#endif +#if defined(CONFIG_KEYPAD_E680) + pxa_gpio_mode(GPIO_TC_MM_EN); + GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); + GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); +#endif + + return 0; +} + +static int +keypad_close(struct inode * inode, struct file *file) +{ +#ifdef KDEBUG + printk(KERN_DEBUG " keypad_close\n"); +#endif + /* + * this decrement of reading_opens doesn't have to be protected because + * it can only be executed to close the single open of /dev/keypad + */ + reading_opens--; + return 0; +} + +static int +keypadB_close(struct inode * inode, struct file *file) +{ +#ifdef KDEBUG + printk(KERN_DEBUG " keypadB_close\n"); +#endif + /* + * this decrement of bitmap_opens doesn't have to be protected because + * it can only be executed to close the single open of /dev/keypadB + */ + bitmap_opens--; + return 0; +} + +static int +keypadI_close(struct inode * inode, struct file *file) +{ +#ifdef KDEBUG + printk(KERN_DEBUG " keypadI_close\n"); +#endif +#if defined(CONFIG_KEYPAD_E680) + pxa_gpio_mode(GPIO_TC_MM_EN); + GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); + GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); +#endif + + return 0; +} + +/** + * Add the specified event to the key buffer. + * This should be called with keypad_lock locked. + */ +static int +add_to_keybuf (unsigned short event) +{ + if (KEYBUF_FULL()) + { + return -ENOMEM; + } + + keybuf[keybuf_end] = event; + KEYBUF_INC (keybuf_end); + +#if CONFIG_APM + queue_apm_event(KRNL_KEYPAD, NULL); +#endif + printk("add keypad event = %x\n", event); + return 0; +} + +/* + * code[c*8+r] is the key code for the key that's down when there's a 1 + * in column c, row r of the scan registers. + */ + +#if defined(CONFIG_KEYPAD_V700) +int +scanbit_to_keycode[] = { + /* col 0 */ + KEYPAD_UP, KEYPAD_DOWN, KEYPAD_LEFT, KEYPAD_RIGHT, + KEYPAD_POUND, KEYPAD_0, KEYPAD_9, KEYPAD_NONE, + /* col 1 */ + KEYPAD_2, KEYPAD_4, KEYPAD_6, KEYPAD_8, + KEYPAD_7, KEYPAD_SLEFT, KEYPAD_SRIGHT, KEYPAD_NONE, + /* col 2 */ + KEYPAD_MENU, KEYPAD_1, KEYPAD_3, KEYPAD_5, + KEYPAD_STAR, KEYPAD_VOLUP, KEYPAD_VOLDOWN, KEYPAD_NONE, + /* col 3 */ + KEYPAD_CAMERA, KEYPAD_CLEAR, KEYPAD_CARRIER, KEYPAD_ACTIVATE, + KEYPAD_SEND, KEYPAD_SMART, KEYPAD_VAVR, KEYPAD_NONE +}; + +/* end CONFIG_KEYPAD_V700 */ +#elif defined(CONFIG_E680_P4A) +int +scanbit_to_keycode[] = { + /* col 0 */ + KEYPAD_UP, KEYPAD_DOWN, KEYPAD_LEFT, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 1 */ + KEYPAD_RIGHT, KEYPAD_CENTER, KEYPAD_HOME, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 2 */ + KEYPAD_GAME_R, KEYPAD_NONE, KEYPAD_GAME_L, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 3 */ + KEYPAD_A, KEYPAD_B, KEYPAD_NONE, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, +}; + +/* end CONFIG_E680_P4A */ +#elif defined(CONFIG_KEYPAD_E680) +int +scanbit_to_keycode[] = { + /* col 0 */ + KEYPAD_UP, KEYPAD_DOWN, KEYPAD_NONE, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 1 */ + KEYPAD_RIGHT, KEYPAD_LEFT, KEYPAD_NONE, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 2 */ + KEYPAD_NONE, KEYPAD_GAME_R, KEYPAD_NONE, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 3 */ + KEYPAD_HOME, KEYPAD_GAME_L, KEYPAD_CENTER, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + +}; +/*end CONFIG_KEYPAD_E680 */ +#elif defined(CONFIG_KEYPAD_A780) +int +scanbit_to_keycode[] = { + /* col 0 */ + KEYPAD_OK, KEYPAD_1, KEYPAD_4, KEYPAD_7, + KEYPAD_STAR, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 1 */ + KEYPAD_MENU, KEYPAD_2, KEYPAD_5, KEYPAD_8, + KEYPAD_0, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 2 */ + KEYPAD_CANCEL, KEYPAD_3, KEYPAD_6, KEYPAD_9, + KEYPAD_POUND, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 3 */ + KEYPAD_JOG_UP, KEYPAD_JOG_MIDDLE, KEYPAD_PTT, KEYPAD_HOME, + KEYPAD_JOG_DOWN, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 4 */ + KEYPAD_UP, KEYPAD_CENTER, KEYPAD_LEFT, KEYPAD_RIGHT, + KEYPAD_DOWN, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, +}; +#endif + +/* + * Decode the specified scan register values into the bitmap pointed + * to by the last argument. The bitmap will contain a 1 + * for each key that's down. + * + * Only the 1st two of the four scan registers are used. + */ +static void +scan_to_bitmap(unsigned long kpas, unsigned long kpasmkp0, + unsigned long kpasmkp1, unsigned long bitmap[]) +{ + int row, col; + int bitnum; + unsigned long scanmap; +#if defined(CONFIG_KEYPAD_A780) + int keep; +#endif + + set_bitmap_to_zero (bitmap); + + if ((kpas & KPAS_MUKP) == MUKP_NO_KEYS) + { + return; + } + + if ((kpas & KPAS_MUKP) == MUKP_ONE_KEY) + { + row = (kpas & KPAS_RP) >> 4; + col = kpas & KPAS_CP; + turn_on_bit (bitmap, scanbit_to_keycode[col*8 + row]); + return; + } + + /* reach here if multiple keys */ + scanmap = (kpasmkp0 & 0x7f) | ((kpasmkp0 & 0x7f0000) >> 8) | + ((kpasmkp1 & 0x7f) << 16) | ((kpasmkp1 & 0x7f0000) << 8); + while ((bitnum = ffs(scanmap)) != 0) + { + /* + * ffs returns bit numbers starting with 1, so subtract 1 to index + * into scanbit_to_keycode[] + */ + turn_on_bit (bitmap, scanbit_to_keycode[bitnum-1]); + scanmap &= ~(1<<(bitnum-1)); + } +#if defined(CONFIG_KEYPAD_A780) + kpasmkp2 = KPASMKP2; + printk("kpasmkp0 = 0x\n", kpasmkp0); + printk("kpasmkp1 = 0x\n", kpasmkp1); + printk("kpasmkp2 = 0x\n", kpasmkp2); + if( (kpasmkp2 != 1) || (kpasmkp2 != 2) | (kpasmkp2 != 4) | (kpasmkp2 != 8) | (kpasmkp2 != 16) ) + return; + while ((bitnum = ffs(kpasmkp2)) !=0) + { + turn_on_bit (bitmap, scanbit_to_keycode[32+bitnum-1]); + kpasmkp2 &= ~(1<<(bitnum-1)); + } +#endif +} + +/* + * Add events indicated by the difference between the last scan (oldbitmap) + * and this one (newbitmap) to the input buffer. + * Return nonzero right away if any of the events can't be added. + * A zero return means all the events were added. + * This should be called with keypad_lock locked. + */ +static int +add_events (unsigned long *oldbitmap, unsigned long *newbitmap) +{ + unsigned long tmpmap, onebitmap; + int bitnum, i, ret; + + /* generate events for keys that were down before and are up now */ + for (i=NUM_WORDS_IN_BITMAP-1;i>=0;i--) + { + tmpmap = oldbitmap[i]; + while ((bitnum = ffs(tmpmap)) != 0) + { + onebitmap = 1<<(bitnum-1); + if ((newbitmap[i] & onebitmap) == 0) + { + ret = add_to_keybuf(bitnum + (32*(NUM_WORDS_IN_BITMAP-1-i) | KEYUP)); + if (ret < 0) + { + return ret; + } + } + tmpmap &= ~onebitmap; + } + } + /* generate events for down keys that were up before */ + for (i=NUM_WORDS_IN_BITMAP-1;i>=0;i--) + { + tmpmap = newbitmap[i]; + while ((bitnum = ffs(tmpmap)) != 0) + { + onebitmap = 1<<(bitnum-1); + if ((oldbitmap[i] & onebitmap) == 0) + { + ret = add_to_keybuf + (bitnum + (32*(NUM_WORDS_IN_BITMAP-1-i) | KEYDOWN)); + if (ret < 0) + { + return ret; + } + } + tmpmap &= ~onebitmap; + } + } + return 0; +} + +/* + * do the INSERT_EVENT ioctl + */ +static int +insert_event (unsigned short event) +{ + unsigned long flags; + int ret; + + if (KEYCODE(event) > KEYPAD_MAXCODE) + { + printk(KERN_WARNING " inserted key code %d too big\n", + KEYCODE(event)); + return -EINVAL; + } + spin_lock_irqsave(&keypad_lock, flags); + if (KEY_IS_DOWN(event)) + { + turn_on_bit(keybitmap, KEYCODE(event)); + } + else + { + turn_off_bit (keybitmap, event); + } + if ((ret = add_to_keybuf(event)) < 0) + { + spin_unlock_irqrestore(&keypad_lock,flags); + return ret; + } + spin_unlock_irqrestore(&keypad_lock, flags); + wake_up_interruptible (&keypad_wait); + return 0; +} + +static int +keypad_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int interval; /* debounce interval */ + int imkp; /* Ignore Multiple Key Press bit */ + struct autorepeatinfo ar; /* autorepeat information */ + +#ifdef KDEBUG + printk (KERN_DEBUG "keypad_ioctl: 0x%x\n", cmd); +#endif + switch (cmd) + { + case KEYPAD_IOC_INSERT_EVENT: + return insert_event ((unsigned short)arg); + break; + case KEYPAD_IOC_GET_DEBOUNCE_INTERVAL: + interval = KPKDI & KPKDI_BITS; + return put_user(interval, (unsigned long *)arg); + break; + case KEYPAD_IOC_SET_DEBOUNCE_INTERVAL: + interval = (unsigned short)arg; + if (interval > KPKDI_BITS) + { + return -EINVAL; + } + KPKDI &= ~KPKDI_BITS; + KPKDI |= interval; + break; + case KEYPAD_IOC_GET_IMKP_SETTING: + imkp = ((KPC & KPC_IMKP) == KPC_IMKP); + return put_user(imkp, (unsigned char *)arg); + break; + case KEYPAD_IOC_SET_IMKP_SETTING: + imkp = (unsigned char)arg; + if (imkp) + { + KPC |= KPC_IMKP; + } + else + { + KPC &= ~KPC_IMKP; + } + break; + case KEYPAD_IOC_SET_AUTOREPEAT: + if (copy_from_user (&ar, (void *)arg, + sizeof(struct autorepeatinfo)) != 0) + { + return -EFAULT; + } + do_autorepeat = ar.r_repeat; + /* times are specified in milliseconds; convert to jiffies */ + jiffies_to_first_repeat = ar.r_time_to_first_repeat * HZ/1000; + jiffies_to_next_repeat = ar.r_time_between_repeats * HZ/1000; + break; + default: + return -ENOTTY; + } + return 0; +} + +static int +keypadB_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned long flags; + int ret; + +#ifdef KDEBUG + printk (KERN_DEBUG "keypadB_ioctl: 0x%x\n", cmd); +#endif + if (cmd == KEYPAD_IOC_INSERT_EVENT) + { + return insert_event ((unsigned short)arg); + } + else if (cmd == KEYPAD_IOC_GETBITMAP) + { + spin_lock_irqsave(&keypad_lock, flags); + ret = copy_to_user ((void *)arg, keybitmap, + NUM_WORDS_IN_BITMAP * sizeof(unsigned long)); + copy_bitmap (lastioctlbitmap, keybitmap); + spin_unlock_irqrestore(&keypad_lock, flags); + return (ret != 0) ? -EFAULT : 0; + } + else + { + return -ENOTTY; + } +} + +static int +keypadI_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned long flags; + int ret; + +#ifdef KDEBUG + printk (KERN_DEBUG "keypadI_ioctl: 0x%x\n", cmd); +#endif +#if defined(CONFIG_KEYPAD_E680) + if( cmd == KEYPADI_TURN_ON_LED ) + { + GPCR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); + GPIO_TC_MM_STATE = 0; + PGSR3 &= ~GPIO_bit(GPIO_TC_MM_EN); + return 0; + } + if( cmd == KEYPADI_TURN_OFF_LED ) + { + GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); + GPIO_TC_MM_STATE = 1; + PGSR3 |= GPIO_bit(GPIO_TC_MM_EN); + return 0; + } +#endif + + if (cmd == KEYPAD_IOC_INSERT_EVENT) + { + return insert_event ((unsigned short)arg); + } + else if (cmd == KEYPAD_IOC_GETBITMAP) + { + spin_lock_irqsave(&keypad_lock, flags); + ret = copy_to_user ((void *)arg, keybitmap, + NUM_WORDS_IN_BITMAP * sizeof(unsigned long)); + copy_bitmap (lastioctlbitmap, keybitmap); + spin_unlock_irqrestore(&keypad_lock, flags); + return (ret != 0) ? -EFAULT : 0; + } + else + { + return -ENOTTY; + } +} + +static unsigned int +keypad_poll( struct file *file, poll_table * wait ) +{ +#ifdef KDEBUG + printk(KERN_DEBUG " keypad_poll\n"); +#endif + poll_wait(file, &keypad_wait, wait); + + if (!KEYBUF_EMPTY()) + { + return (POLLIN | POLLRDNORM); + } + return 0; +} + +static unsigned int +keypadB_poll( struct file *file, poll_table * wait ) +{ + int i; + +#ifdef KDEBUG + printk(KERN_DEBUG " keypadB_poll\n"); +#endif + poll_wait(file, &keypad_wait, wait); + + for (i=0; i < NUM_WORDS_IN_BITMAP; i++) + { + if (lastioctlbitmap[i] != keybitmap[i]) + { + return (POLLIN | POLLRDNORM); + } + } + return 0; +} + +static unsigned short +get_from_keybuf(void) +{ + unsigned short event; + unsigned long flags; + + spin_lock_irqsave(&keypad_lock, flags); + event = keybuf[keybuf_start]; + KEYBUF_INC (keybuf_start); + spin_unlock_irqrestore(&keypad_lock, flags); + return event; +} + +static ssize_t +keypad_read(struct file *file, char *buf, size_t count, loff_t *ptr) +{ + int i, ret; + unsigned short event; + +#ifdef KDEBUG + printk(KERN_DEBUG " keypad_read\n"); +#endif + /* Can't seek (pread) on this device */ + if (ptr != &file->f_pos) + { + return -ESPIPE; + } + + if (count == 0) + { + return 0; + } + + if (KEYBUF_EMPTY()) + { + /* buffer is empty */ + /* if not blocking return */ + if (file->f_flags & O_NONBLOCK) + { + return -EAGAIN; + } + /* blocking, so wait for input */ + ret = wait_event_interruptible(keypad_wait, !KEYBUF_EMPTY()); + if (ret) + { + return ret; + } + } + + i = 0; + /* copy events until we have what the user asked for or we run out */ + while ((i+1 < count) && !KEYBUF_EMPTY()) + { + event = get_from_keybuf(); + if ((ret = put_user(event, (unsigned short *)buf)) != 0) + { + return ret; + } + buf += EVENTSIZE; + i += EVENTSIZE; + } + return i; +} + +#ifdef CONFIG_PM +static int button_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) +{ + int pksr; + + pksr = PKSR; + PKSR = 0xfffff; + switch(req) + { + case PM_SUSPEND: + kpc_res = KPC; + kpkdi_res = KPKDI; + set_bitmap_to_zero (oldkeybitmap); + set_bitmap_to_zero (keybitmap); + set_bitmap_to_zero (lastioctlbitmap); + kpas = 0; + kpasmkp0 = 0; + kpasmkp1 = 0; + kpasmkp2 = 0; + kpdk = 0; + break; + case PM_RESUME: + KPC = kpc_res; + KPKDI = kpkdi_res; +#if CONFIG_APM +#if defined(CONFIG_E680_P4A) + if (pksr & 0xe4400) /*93 97 100 101 102 key is pressed (switch on) */ + { + queue_apm_event(KRNL_KEYPAD, NULL); + if (pksr & 0x400) + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } +#endif +#if defined(CONFIG_KEYPAD_E680) + if (pksr & 0xee400) /*93 96 97 98 190 101 102 key is pressed */ + { + queue_apm_event(KRNL_KEYPAD, NULL); + if (pksr & 0x400) + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + if (pksr & 0x2000) + turn_on_bit (keybitmap, KEYPAD_A); + if (pksr & 0x8000) + turn_on_bit (keybitmap, KEYPAD_B); + } +#endif +#if defined(CONFIG_KEYPAD_A780) + printk("pksr = %x\n",pksr); + if (pksr & 0xec400) /* 93 97 98 100 101 102 key is pressed */ + { + queue_apm_event(KRNL_KEYPAD, NULL); + if (pksr & 0x400) + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } +#endif +#endif + + break; + } + return 0; +} +#endif + +/* for /dev/keypad */ +static struct file_operations +keypad_fops = { + read: keypad_read, + llseek: no_llseek, + poll: keypad_poll, + ioctl: keypad_ioctl, + open: keypad_open, + release: keypad_close, +}; + +static struct miscdevice +keypad_misc_device = { + KEYPAD_MINOR, + KEYPAD_NAME, + &keypad_fops, +}; + +/* + * for /dev/keypadB. + * read() isn't defined here. calls to read() will return -1 with EINVAL. + */ +static struct file_operations +keypadB_fops = { + llseek: no_llseek, + poll: keypadB_poll, + ioctl: keypadB_ioctl, + open: keypadB_open, + release: keypadB_close, +}; + +static struct miscdevice +keypadB_misc_device = { + KEYPAD_BITMAP_MINOR, + KEYPAD_BITMAP_NAME, + &keypadB_fops, +}; + +/* + * for /dev/keypadI. + * read() isn't defined here. calls to read() will return -1 with EINVAL. + */ +static struct file_operations +keypadI_fops = { + llseek: no_llseek, + ioctl: keypadI_ioctl, + open: keypadI_open, + release: keypadI_close, +}; + +static struct miscdevice +keypadI_misc_device = { + KEYPAD_INSERT_MINOR, + KEYPAD_INSERT_NAME, + &keypadI_fops, +}; + +#ifdef CONFIG_PANIC_LOG +static u32 panic_bug_used =0; +#endif + +/* Interrupt Handler for KEYPAD */ +static void +kp_interrupt(int irq, void *ptr, struct pt_regs *regs) +{ + unsigned long flags; + unsigned long kpc_val; + +#ifdef USE_RELEASE_TIMER + del_timer (&key_release_timer); +#endif + del_timer (&autorepeat_timer); + spin_lock_irqsave(&keypad_lock,flags); + + /* ack interrupt */ + kpc_val = KPC; + + /* matrix interrupt */ + if (kpc_val & KPC_MI) + { +/* + * The Intel driver turned on KPC_AS here. It doesn't seem that we + * would need to do that, because getting an interrupt means that + * a scan was just done. For now, I've commented out the setting + * and clearing of this bit. + KPC |= KPC_AS; + */ + while (KPAS & KPAS_SO) + { + /* Wait for the Scan On bit to go off before */ + /* reading the scan registers. */ + NULL; + }; + + kpas = KPAS; + kpasmkp0 = KPASMKP0; + kpasmkp1 = KPASMKP1; + kpasmkp2 = KPASMKP2; + + } + + /* direct interrupt */ + if (kpc_val & KPC_DI) + { + kpdk = KPDK; + /* + * reading the register turns off the "key pressed since last read" + * bit if it was on, so we turn it off + */ + kpdk &= ~KPDK_DKP; + } + + copy_bitmap (oldkeybitmap, keybitmap); + scan_to_bitmap (kpas, kpasmkp0, kpasmkp1, keybitmap); +#if defined(CONFIG_E680_P4A) + if (kpdk & KPDK_DK0) /* VR key is pressed */ + { + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } + if (kpdk & KPDK_DK4) + { + turn_on_bit (keybitmap, KEYPAD_POWER); + } + /* power key is connected to GPIO97 as GPIO input */ +#elif defined(CONFIG_KEYPAD_E680) + if (kpdk & KPDK_DK0) /* VR key is pressed */ + { + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } + if (kpdk & KPDK_DK4) + { + turn_on_bit (keybitmap, KEYPAD_POWER); + } + /* power key is connected to GPIO97 as GPIO input */ + if (kpdk & KPDK_DK3) + { + turn_on_bit (keybitmap, KEYPAD_A); + } + if (kpdk & KPDK_DK5) + { + turn_on_bit (keybitmap, KEYPAD_B); + } + +#elif defined(CONFIG_KEYPAD_A780) + if (kpdk & KPDK_DK0) /* voice/camera key is pressed */ + { + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } +#endif + +#ifdef CONFIG_PANIC_LOG + if ((kpdk & KPDK_DK0)&&(kpasmkp1& 0x00020000)) + { + if(0 == panic_bug_used) + { + panic_bug_used = 1; + BUG(); + } + } +#endif + + (void) add_events (oldkeybitmap, keybitmap); + + /* If any keys are down, set a timer to check for key release */ + /* and one for autorepeat if that's on. */ + if (any_keys_down (keybitmap)) + { +#ifdef USE_RELEASE_TIMER + key_release_timer.expires = (jiffies + key_release_interval); + add_timer (&key_release_timer); +#endif + if (do_autorepeat) + { + autorepeat_timer.expires = (jiffies + jiffies_to_first_repeat); + add_timer (&autorepeat_timer); + } + } + + spin_unlock_irqrestore(&keypad_lock, flags); + wake_up_interruptible (&keypad_wait); + printk("keypad interrupt occurred\n"); +} + +#ifdef USE_RELEASE_TIMER +/* + * This is called when the key release timer goes off. That's the + * only time it should be called. Check for changes in what keys + * are down. + */ +static void +release_timer_went_off(unsigned long unused) +{ + unsigned long flags; + + spin_lock_irqsave(&keypad_lock,flags); + do_scan(); + /* If any keys are still down, set the timer going again. */ + if (any_keys_down (keybitmap)) + { + mod_timer (&key_release_timer, jiffies + key_release_interval); + } + else + { + del_timer (&autorepeat_timer); + } + spin_unlock_irqrestore(&keypad_lock, flags); +} +#endif + +/* + * This is called when the autorepeat timer goes off. + */ +static void +autorepeat_timer_went_off(unsigned long unused) +{ + int i, bitnum; + unsigned long tmp; + unsigned long flags; + + spin_lock_irqsave(&keypad_lock,flags); + if (!any_keys_down (keybitmap)) + { + spin_unlock_irqrestore(&keypad_lock, flags); + return; + } + for (i=0;i */ + pxa_gpio_mode(97 | GPIO_ALT_FN_1_IN); /* KP_MKIN<3> */ + pxa_gpio_mode(98 | GPIO_ALT_FN_1_IN); /* KP_MKIN<4> */ + pxa_gpio_mode(99 | GPIO_ALT_FN_1_IN); /* KP_MKIN<5> */ + pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ + pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ + pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ + pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ + pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ + pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ + pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ +#elif defined(CONFIG_E680_P4A) + pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); /* KP_DKIN<0>, VR Key */ + pxa_gpio_mode(97 | GPIO_ALT_FN_1_IN); /* KP_DKIN<4>, power key */ + pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ + pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ + pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ + pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ + pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ + pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ + pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ +#elif defined(CONFIG_KEYPAD_E680) + pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); /* KP_DKIN<0>, VR Key */ + pxa_gpio_mode(96 | GPIO_ALT_FN_1_IN); /* KP_DKIN<3>, GAME_A */ + pxa_gpio_mode(97 | GPIO_ALT_FN_1_IN); /* KP_DKIN<4>, power key */ + pxa_gpio_mode(98 | GPIO_ALT_FN_1_IN); /* KP_DKIN<5>, GAME_B */ + pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ + pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ + pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ + pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ + pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ + pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ + pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ + pxa_gpio_mode(GPIO_TC_MM_EN); + GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); + GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); + PGSR3 |= GPIO_bit(GPIO_TC_MM_EN); +#elif defined (CONFIG_KEYPAD_A780) + pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); /* KP_DKIN<0>, voice_rec */ + pxa_gpio_mode(97 | GPIO_ALT_FN_3_IN); /* KP_MKIN<3> */ + pxa_gpio_mode(98 | GPIO_ALT_FN_3_IN); /* KP_MKIN<4> */ + pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ + pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ + pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ + pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ + pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ + pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ + pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ + pxa_gpio_mode(107 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<4> */ +#elif defined(CONFIG_KEYPAD_MAINSTONE) + /* from Intel driver */ + pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); + pxa_gpio_mode(94 | GPIO_ALT_FN_1_IN); + pxa_gpio_mode(95 | GPIO_ALT_FN_1_IN); + pxa_gpio_mode(98 | GPIO_ALT_FN_1_IN); + pxa_gpio_mode(99 | GPIO_ALT_FN_1_IN); + pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ + pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ + pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ + pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ + pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ + pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ + pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ +#endif + + /* set keypad control register */ + KPC = (KPC_ASACT | /* automatic scan on activity */ + KPC_ME | KPC_DE | /* matrix and direct keypad enabled */ +#if defined (CONFIG_KEYPAD_V700) + (3<<23) | /* 4 columns */ + (6<<26) | /* 7 rows */ +#elif defined(CONFIG_E680_P4A) + (3<<23) | /* 4 columns */ + (2<<26) | /* 3 rows */ + (4<<6) | /* 4# direct key */ +#elif defined(CONFIG_KEYPAD_E680) + (5<<23) | /* 4 columns */ + (4<<26) | /* 3 rows */ + (5<<6) | /* 5# direct keys */ +#elif defined(CONFIG_KEYPAD_A780) + (4<<23) | /* 5 columns */ + (4<<26) | /* 5 rows */ + (0<<6) | /* 1# direct keys */ +#endif + KPC_MS7_0); /* scan all columns */ + + CKEN |= CKEN19_KEYPAD; + + err = request_irq (IRQ_KEYPAD, kp_interrupt, 0, "Keypad", NULL); + if (err) + { + printk (KERN_CRIT "can't register IRQ%d for keypad, error %d\n", + IRQ_KEYPAD, err); + CKEN &= ~CKEN19_KEYPAD; + return -ENODEV; + } + + if (misc_register (&keypad_misc_device)) + { + printk(KERN_ERR "Couldn't register keypad driver\n"); + return -EIO; + } + if (misc_register (&keypadB_misc_device)) + { + printk(KERN_ERR "Couldn't register keypadB driver\n"); + misc_deregister(&keypad_misc_device); + return -EIO; + } + if (misc_register (&keypadI_misc_device)) + { + printk(KERN_ERR "Couldn't register keypadI driver\n"); + misc_deregister(&keypad_misc_device); + misc_deregister(&keypadB_misc_device); + return -EIO; + } + +#ifdef USE_RELEASE_TIMER + init_timer (&key_release_timer); + key_release_timer.function = release_timer_went_off; +#endif + init_timer (&autorepeat_timer); + autorepeat_timer.function = autorepeat_timer_went_off; + + /* + * we want the phone to be able to tell the status of the screen + * lock switch at power-up time + */ + kpdk = KPDK; /* read direct key register */ + /* + * reading the register turns off the "key pressed since last read" bit + * if it was on, so we turn it off + */ + kpdk &= ~KPDK_DKP; +#if defined(CONFIG_E680_P4A) + if (kpdk & KPDK_DK0) /* VR key is pressed (switch on) */ + { + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } + if (kpdk & KPDK_DK4) /* Power key is pressed (switch on) */ + { + turn_on_bit (keybitmap, KEYPAD_POWER); + } +#elif defined(CONFIG_KEYPAD_E680) + if (kpdk & KPDK_DK0) /* VR key is pressed (switch on) */ + { + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } + if (kpdk & KPDK_DK4) /* Power key is pressed (switch on) */ + { + turn_on_bit (keybitmap, KEYPAD_POWER); + } + if (kpdk & KPDK_DK3) /* GAME_A key is pressed (switch on) */ + { + turn_on_bit (keybitmap, KEYPAD_A); + } + if (kpdk & KPDK_DK5) /* GAME_B key is pressed (switch on) */ + { + turn_on_bit (keybitmap, KEYPAD_B); + } +#elif defined(CONFIG_KEYPAD_A780) + if (kpdk & KPDK_DK0) /* voice/camera key is pressed */ + { + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } +#endif + +#ifdef CONFIG_PM + pm_dev = pm_register(PM_SYS_DEV, 0, button_pm_callback); +#if defined(CONFIG_E680_P4A) +/*93,97,100,101,102*/ + PKWR = 0xe4400; +/*103 104 105 106*/ + PGSR3 |= 0x780; +#endif +#if defined(CONFIG_KEYPAD_E680) +/*93,96,97,98,100,101,102*/ + PKWR = 0xee400; +/*103 104 105 106*/ + PGSR3 |= 0x780; +#endif +#if defined(CONFIG_KEYPAD_A780) +/*93,97,98,100,101,102*/ + PKWR = 0xec400; +/*103 104 105 106 107*/ + PGSR3 |= 0xf80; +#endif +#endif + +#if defined(CONFIG_KEYPAD_E680) +#ifdef CONFIG_PM + keypadI_pm_dev = pm_register(PM_SYS_DEV, 0, keypadI_pm_callback); + PGSR3 |= 0x8; +#endif +#endif + + KPC |= (KPC_DIE | KPC_MIE); + KPKDI = 0x40; + return 0; +} + +static void +__exit keypad_exit(void) +{ +#ifdef KDEBUG + printk(KERN_DEBUG " keypad_exit\n"); +#endif + misc_deregister(&keypad_misc_device); + misc_deregister(&keypadB_misc_device); + misc_deregister(&keypadI_misc_device); + +#ifdef CONFIG_PM + pm_unregister(pm_dev); +#endif + +#if defined(CONFIG_KEYPAD_E680) +#ifdef CONFIG_PM + pm_unregister(keypadI_pm_dev); +#endif +#endif + + CKEN &= ~CKEN19_KEYPAD; +} + +module_init (keypad_init); +module_exit (keypad_exit); Index: linux-2.6.16.5-a/drivers/misc/ezx/keypad-panasonic.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/misc/ezx/keypad-panasonic.c 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,1569 @@ +/* + * linux/drivers/char/keypad.c + * + * (c) Copyright Motorola 2003, All rights reserved. + */ + +/* + * This driver is for three devices: /dev/keypad, /dev/keypadB and + * /dev/keypadI. + * /dev/keypad would be used for reading the key event buffer. + * It can be opened by one process at a time. + * /dev/keypadB would be used for ioctl(KEYPAD_IOC_GETBITMAP). + * It can be opened by one process at a time. + * /dev/keypadI would be used for ioctl(KEYPAD_IOC_INSERT_EVENT). + * It can be opened any number of times simultaneously. + * + * The bulverde specification is ambiguous about when interrupts happen + * for released keys. We were told by Intel that we won't + * get interrupts for released keys except in the case when multiple + * keys were down and they've all been released. So we implemented + * a timer to poll for changes in key states. + * + * The E680 P2 hardware gives us interrupts when any key is released, + * whether it was the only key down or not, and whether it's the last + * of multiple keys to be released or not. We don't know whether this + * behavior will continue in future hardware releases, so the release + * timer is still in the code, #ifdef'd with USE_RELEASE_TIMER. On the + * P2 hardware, the code works with or without USE_RELEASE_TIMER defined. + * If the release interrupts are always going to happen, we can remove + * the #ifdef'd code. + * + * With the P2 hardware, the power key bit in the KPDK register is always + * on. We don't know if this is correct behavior or not, but in any case + * it certainly causes trouble to have that key autorepeating indefinitely, + * or to be checking indefinitely for the key to be released (if we're doing + * release polling). + * + * For now, any_keys_down() returns 0 if the power key is the only one down. + * . At interrupt time, if the power key is the only one down we don't + * set the autorepeat timer or release timer. + * . When the release timer goes off, if the power key is the only one + * still down we don't set the timer again. + * . When the autorepeat timer goes off, if the power key is the only + * one down we don't generate any events. + * In autorepeat_timer_went_off, if there are non-power keys down, while we're + * looking through the whole bitmap of keys down we ignore the power key. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "keypad.h" +#include +#include "asm/arch/ezx.h" +#include + +#ifdef CONFIG_PM +static struct pm_dev *pm_dev; +static struct pm_dev *keypadI_pm_dev; +static int kpc_res,kpkdi_res; +static int GPIO_TC_MM_STATE = 1; +extern unsigned char pxafb_ezx_getLCD_status(void); +#endif +/* + * This is the number of microseconds we wait before checking to see if any + * keys have been released. + */ +#define RDELAY 200 + +#define KEYBUF_EMPTY() (keybuf_start == keybuf_end) +#define KEYBUF_FULL() ( ((keybuf_end+1)%KEYBUF_SIZE) == keybuf_start) +#define KEYBUF_INC(x) ((x) = (((x)+1) % KEYBUF_SIZE)) + +static int keypad_open (struct inode *, struct file *); +static int keypad_close (struct inode *, struct file *); +static int keypad_ioctl (struct inode *, struct file *, + unsigned int, unsigned long); +static unsigned int keypad_poll (struct file *, poll_table *); +static ssize_t keypad_read (struct file *, char *, size_t, loff_t *); + +static int keypadB_open (struct inode *, struct file *); +static int keypadB_close (struct inode *, struct file *); +static int keypadB_ioctl (struct inode *, struct file *, + unsigned int, unsigned long); +static unsigned int keypadB_poll (struct file *, poll_table *); + +static int keypadI_open(struct inode *, struct file *); +static int keypadI_close(struct inode *, struct file *); +static int keypadI_ioctl (struct inode *, struct file *, + unsigned int, unsigned long); + +static void kp_interrupt (int, void *, struct pt_regs *); +#ifdef USE_RELEASE_TIMER +static void release_timer_went_off (unsigned long); +static void do_scan(void); +#endif +static void autorepeat_timer_went_off (unsigned long); + +static int add_to_keybuf (unsigned short); +static int add_events (unsigned long *, unsigned long *); +static int insert_event (unsigned short); +static unsigned short get_from_keybuf (void); +static void scan_to_bitmap + (unsigned long, unsigned long, unsigned long, unsigned long *); +static inline void set_bitmap_to_zero(unsigned long b[]); +static inline void copy_bitmap(unsigned long dest[], unsigned long source[]); +static inline void turn_on_bit(unsigned long map[], int); +static inline void turn_off_bit(unsigned long map[], int); +static inline int any_keys_down (unsigned long *); + +/* + * keybuf is a circular buffer to hold keypad events. + * keybuf_start is the index of the first event. + * keybuf_end is one more than the index of the last event. + * The buffer is empty when keybuf_start == keybuf_end. + * We only use KEYBUF_SIZE-1 entries in the buffer so we can tell + * when it's full without needing another variable to tell us. + * The buffer is full when (keybuf_end+1)%KEYBUF_SIZE == keybuf_start. + */ +static unsigned short keybuf[KEYBUF_SIZE]; +static int keybuf_start = 0; +static int keybuf_end = 0; + +static DECLARE_WAIT_QUEUE_HEAD(keypad_wait); +static spinlock_t keypad_lock = SPIN_LOCK_UNLOCKED; + +static int reading_opens = 0; +static int bitmap_opens = 0; + +/* previous bitmap of keys down */ +static unsigned long oldkeybitmap[NUM_WORDS_IN_BITMAP]; +/* current bitmap of keys down */ +static unsigned long keybitmap[NUM_WORDS_IN_BITMAP]; +/* last bitmap read by ioctl */ +static unsigned long lastioctlbitmap[NUM_WORDS_IN_BITMAP]; + +static unsigned long kpas = 0; /* last value of kpas */ +static unsigned long kpasmkp0 = 0; /* last value of kpasmkp0 */ +static unsigned long kpasmkp1 = 0; /* last value of kpasmkp1 */ +static unsigned long kpasmkp2 = 0; /* last value of kpasmkp2 */ +static unsigned long kpdk = 0; /* last value of kpdk */ + +#ifdef USE_RELEASE_TIMER +static struct timer_list key_release_timer; +static int key_release_interval = RDELAY * HZ/1000; +#endif + +static int do_autorepeat = 1; +static long jiffies_to_first_repeat = 30; +static long jiffies_to_next_repeat = 30; +static struct timer_list autorepeat_timer; + +extern int lockscreen_flag; + +static int +keypad_open(struct inode *inode, struct file *file) +{ +#ifdef KDEBUG + printk(KERN_DEBUG "keypad_open\n"); +#endif + spin_lock(keypad_lock); + if (reading_opens > 0) + { + spin_unlock(keypad_lock); + return -EBUSY; + } + reading_opens++; + spin_unlock(keypad_lock); + + return 0; +} + +static int +keypadB_open(struct inode *inode, struct file *file) +{ +#ifdef KDEBUG + printk(KERN_DEBUG "keypadB_open\n"); +#endif + spin_lock(keypad_lock); + if (bitmap_opens > 0) + { + spin_unlock(keypad_lock); + return -EBUSY; + } + bitmap_opens++; + /* + * poll returns when lastioctlbitmap is different from keybitmap. + * we set lastioctlbitmap to keybitmap here so that a poll right + * after an open returns when the bitmap is different from when + * the open was done, not when the bitmap is different from the + * last time some other process read it + */ + copy_bitmap(lastioctlbitmap, keybitmap); + spin_unlock(keypad_lock); + + return 0; +} + +#if defined(CONFIG_KEYPAD_E680) +#ifdef CONFIG_PM +static int keypadI_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) +{ + switch(req) + { + case PM_SUSPEND: + break; + case PM_RESUME: + GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); + if(GPIO_TC_MM_STATE == 1) + GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); + else + GPCR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); + break; + default: + break; + } + return 0; +} +#endif +#endif + +static int +keypadI_open(struct inode *inode, struct file *file) +{ +#ifdef KDEBUG + printk(KERN_DEBUG "keypadI_open\n"); +#endif +#if defined(CONFIG_KEYPAD_E680) + pxa_gpio_mode(GPIO_TC_MM_EN); + GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); + GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); +#endif + + return 0; +} + +static int +keypad_close(struct inode * inode, struct file *file) +{ +#ifdef KDEBUG + printk(KERN_DEBUG " keypad_close\n"); +#endif + /* + * this decrement of reading_opens doesn't have to be protected because + * it can only be executed to close the single open of /dev/keypad + */ + reading_opens--; + return 0; +} + +static int +keypadB_close(struct inode * inode, struct file *file) +{ +#ifdef KDEBUG + printk(KERN_DEBUG " keypadB_close\n"); +#endif + /* + * this decrement of bitmap_opens doesn't have to be protected because + * it can only be executed to close the single open of /dev/keypadB + */ + bitmap_opens--; + return 0; +} + +static int +keypadI_close(struct inode * inode, struct file *file) +{ +#ifdef KDEBUG + printk(KERN_DEBUG " keypadI_close\n"); +#endif +#if defined(CONFIG_KEYPAD_E680) + pxa_gpio_mode(GPIO_TC_MM_EN); + GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); + GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); +#endif + + return 0; +} + +/** + * Add the specified event to the key buffer. + * This should be called with keypad_lock locked. + */ +static int +add_to_keybuf (unsigned short event) +{ + if (KEYBUF_FULL()) + { + return -ENOMEM; + } + keybuf[keybuf_end] = event; + KEYBUF_INC (keybuf_end); + +#if CONFIG_APM + queue_apm_event(KRNL_KEYPAD, NULL); +#endif + printk("add keypad event = %x\n", event); + return 0; +} + +/* + * code[c*8+r] is the key code for the key that's down when there's a 1 + * in column c, row r of the scan registers. + */ + +#if defined(CONFIG_KEYPAD_V700) +int +scanbit_to_keycode[] = { + /* col 0 */ + KEYPAD_UP, KEYPAD_DOWN, KEYPAD_LEFT, KEYPAD_RIGHT, + KEYPAD_POUND, KEYPAD_0, KEYPAD_9, KEYPAD_NONE, + /* col 1 */ + KEYPAD_2, KEYPAD_4, KEYPAD_6, KEYPAD_8, + KEYPAD_7, KEYPAD_SLEFT, KEYPAD_SRIGHT, KEYPAD_NONE, + /* col 2 */ + KEYPAD_MENU, KEYPAD_1, KEYPAD_3, KEYPAD_5, + KEYPAD_STAR, KEYPAD_VOLUP, KEYPAD_VOLDOWN, KEYPAD_NONE, + /* col 3 */ + KEYPAD_CAMERA, KEYPAD_CLEAR, KEYPAD_CARRIER, KEYPAD_ACTIVATE, + KEYPAD_SEND, KEYPAD_SMART, KEYPAD_VAVR, KEYPAD_NONE +}; + +/* end CONFIG_KEYPAD_V700 */ +#elif defined(CONFIG_E680_P4A) +int +scanbit_to_keycode[] = { + /* col 0 */ + KEYPAD_UP, KEYPAD_DOWN, KEYPAD_LEFT, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 1 */ + KEYPAD_RIGHT, KEYPAD_CENTER, KEYPAD_HOME, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 2 */ + KEYPAD_GAME_R, KEYPAD_NONE, KEYPAD_GAME_L, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 3 */ + KEYPAD_A, KEYPAD_B, KEYPAD_NONE, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, +}; + +/* end CONFIG_E680_P4A */ +#elif defined(CONFIG_KEYPAD_E680) +int +scanbit_to_keycode[] = { + /* col 0 */ + KEYPAD_UP, KEYPAD_DOWN, KEYPAD_NONE, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 1 */ + KEYPAD_RIGHT, KEYPAD_LEFT, KEYPAD_NONE, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 2 */ + KEYPAD_NONE, KEYPAD_GAME_R, KEYPAD_NONE, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 3 */ + KEYPAD_HOME, KEYPAD_GAME_L, KEYPAD_CENTER, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + +}; +/*end CONFIG_KEYPAD_E680 */ +#elif defined(CONFIG_KEYPAD_A780) +int +scanbit_to_keycode[] = { + /* col 0 */ + KEYPAD_OK, KEYPAD_1, KEYPAD_4, KEYPAD_7, + KEYPAD_STAR, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 1 */ + KEYPAD_MENU, KEYPAD_2, KEYPAD_5, KEYPAD_8, + KEYPAD_0, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 2 */ + KEYPAD_CANCEL, KEYPAD_3, KEYPAD_6, KEYPAD_9, + KEYPAD_POUND, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 3 */ + KEYPAD_JOG_UP, KEYPAD_JOG_MIDDLE, KEYPAD_PTT, KEYPAD_NONE, + KEYPAD_JOG_DOWN, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 4 */ + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_HOME, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, +}; +#endif + +/* + * Decode the specified scan register values into the bitmap pointed + * to by the last argument. The bitmap will contain a 1 + * for each key that's down. + * + * Only the 1st two of the four scan registers are used. + */ +static void +scan_to_bitmap(unsigned long kpas, unsigned long kpasmkp0, + unsigned long kpasmkp1, unsigned long bitmap[]) +{ + int row, col; + int bitnum; + unsigned long scanmap; + + set_bitmap_to_zero (bitmap); + + if ((kpas & KPAS_MUKP) == MUKP_NO_KEYS) + { + return; + } + + if ((kpas & KPAS_MUKP) == MUKP_ONE_KEY) + { + row = (kpas & KPAS_RP) >> 4; + col = kpas & KPAS_CP; +#if defined(CONFIG_KEYPAD_A780) + if( !((row == 3)&&(col == 3)) ) + { +#endif + turn_on_bit (bitmap, scanbit_to_keycode[col*8 + row]); +#if defined(CONFIG_KEYPAD_A780) + } +#endif + + return; + } + + /* reach here if multiple keys */ + scanmap = (kpasmkp0 & 0x7f) | ((kpasmkp0 & 0x7f0000) >> 8) | + ((kpasmkp1 & 0x7f) << 16) | ((kpasmkp1 & 0x7f0000) << 8); + while ((bitnum = ffs(scanmap)) != 0) + { + /* + * ffs returns bit numbers starting with 1, so subtract 1 to index + * into scanbit_to_keycode[] + */ + turn_on_bit (bitmap, scanbit_to_keycode[bitnum-1]); + scanmap &= ~(1<<(bitnum-1)); + } +#if defined(CONFIG_KEYPAD_A780) + kpasmkp2 = KPASMKP2; + kpasmkp2 &= 0x8; + while ((bitnum = ffs(kpasmkp2)) !=0) + { + turn_on_bit (bitmap, scanbit_to_keycode[32+bitnum-1]); + kpasmkp2 &= ~(1<<(bitnum-1)); + } +#endif +} + +/* + * Add events indicated by the difference between the last scan (oldbitmap) + * and this one (newbitmap) to the input buffer. + * Return nonzero right away if any of the events can't be added. + * A zero return means all the events were added. + * This should be called with keypad_lock locked. + */ +static int +add_events (unsigned long *oldbitmap, unsigned long *newbitmap) +{ + unsigned long tmpmap, onebitmap; + int bitnum, i, ret; + + /* generate events for keys that were down before and are up now */ + for (i=NUM_WORDS_IN_BITMAP-1;i>=0;i--) + { + tmpmap = oldbitmap[i]; + while ((bitnum = ffs(tmpmap)) != 0) + { + onebitmap = 1<<(bitnum-1); + if ((newbitmap[i] & onebitmap) == 0) + { + ret = add_to_keybuf(bitnum + (32*(NUM_WORDS_IN_BITMAP-1-i) | KEYUP)); + if (ret < 0) + { + return ret; + } + } + tmpmap &= ~onebitmap; + } + } + /* generate events for down keys that were up before */ + for (i=NUM_WORDS_IN_BITMAP-1;i>=0;i--) + { + tmpmap = newbitmap[i]; + while ((bitnum = ffs(tmpmap)) != 0) + { + onebitmap = 1<<(bitnum-1); + if ((oldbitmap[i] & onebitmap) == 0) + { + ret = add_to_keybuf + (bitnum + (32*(NUM_WORDS_IN_BITMAP-1-i) | KEYDOWN)); + if (ret < 0) + { + return ret; + } + } + tmpmap &= ~onebitmap; + } + } + return 0; +} + +/* + * do the INSERT_EVENT ioctl + */ +static int +insert_event (unsigned short event) +{ + unsigned long flags; + int ret; + + if (KEYCODE(event) > KEYPAD_MAXCODE) + { + printk(KERN_WARNING " inserted key code %d too big\n", + KEYCODE(event)); + return -EINVAL; + } + spin_lock_irqsave(&keypad_lock, flags); + if (KEY_IS_DOWN(event)) + { + turn_on_bit(keybitmap, KEYCODE(event)); + } + else + { + turn_off_bit (keybitmap, event); + } + if ((ret = add_to_keybuf(event)) < 0) + { + spin_unlock_irqrestore(&keypad_lock,flags); + return ret; + } + spin_unlock_irqrestore(&keypad_lock, flags); + wake_up_interruptible (&keypad_wait); + return 0; +} + +static int +keypad_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int interval; /* debounce interval */ + int imkp; /* Ignore Multiple Key Press bit */ + struct autorepeatinfo ar; /* autorepeat information */ + +#ifdef KDEBUG + printk (KERN_DEBUG "keypad_ioctl: 0x%x\n", cmd); +#endif + switch (cmd) + { + case KEYPAD_IOC_INSERT_EVENT: + return insert_event ((unsigned short)arg); + break; + case KEYPAD_IOC_GET_DEBOUNCE_INTERVAL: + interval = KPKDI & KPKDI_BITS; + return put_user(interval, (unsigned long *)arg); + break; + case KEYPAD_IOC_SET_DEBOUNCE_INTERVAL: + interval = (unsigned short)arg; + if (interval > KPKDI_BITS) + { + return -EINVAL; + } + KPKDI &= ~KPKDI_BITS; + KPKDI |= interval; + break; + case KEYPAD_IOC_GET_IMKP_SETTING: + imkp = ((KPC & KPC_IMKP) == KPC_IMKP); + return put_user(imkp, (unsigned char *)arg); + break; + case KEYPAD_IOC_SET_IMKP_SETTING: + imkp = (unsigned char)arg; + if (imkp) + { + KPC |= KPC_IMKP; + } + else + { + KPC &= ~KPC_IMKP; + } + break; + case KEYPAD_IOC_SET_AUTOREPEAT: + if (copy_from_user (&ar, (void *)arg, + sizeof(struct autorepeatinfo)) != 0) + { + return -EFAULT; + } + do_autorepeat = ar.r_repeat; + /* times are specified in milliseconds; convert to jiffies */ + jiffies_to_first_repeat = ar.r_time_to_first_repeat * HZ/1000; + jiffies_to_next_repeat = ar.r_time_between_repeats * HZ/1000; + break; + default: + return -ENOTTY; + } + return 0; +} + +static int +keypadB_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned long flags; + int ret; + +#ifdef KDEBUG + printk (KERN_DEBUG "keypadB_ioctl: 0x%x\n", cmd); +#endif + if (cmd == KEYPAD_IOC_INSERT_EVENT) + { + return insert_event ((unsigned short)arg); + } + else if (cmd == KEYPAD_IOC_GETBITMAP) + { + spin_lock_irqsave(&keypad_lock, flags); + ret = copy_to_user ((void *)arg, keybitmap, + NUM_WORDS_IN_BITMAP * sizeof(unsigned long)); + copy_bitmap (lastioctlbitmap, keybitmap); + spin_unlock_irqrestore(&keypad_lock, flags); + return (ret != 0) ? -EFAULT : 0; + } + else + { + return -ENOTTY; + } +} + +static int +keypadI_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned long flags; + int ret; + +#ifdef KDEBUG + printk (KERN_DEBUG "keypadI_ioctl: 0x%x\n", cmd); +#endif +#if defined(CONFIG_KEYPAD_E680) + if( cmd == KEYPADI_TURN_ON_LED ) + { + GPCR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); + GPIO_TC_MM_STATE = 0; + PGSR3 &= ~GPIO_bit(GPIO_TC_MM_EN); + return 0; + } + if( cmd == KEYPADI_TURN_OFF_LED ) + { + GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); + GPIO_TC_MM_STATE = 1; + PGSR3 |= GPIO_bit(GPIO_TC_MM_EN); + return 0; + } +#endif + + if (cmd == KEYPAD_IOC_INSERT_EVENT) + { + return insert_event ((unsigned short)arg); + } + else if (cmd == KEYPAD_IOC_GETBITMAP) + { + spin_lock_irqsave(&keypad_lock, flags); + ret = copy_to_user ((void *)arg, keybitmap, + NUM_WORDS_IN_BITMAP * sizeof(unsigned long)); + copy_bitmap (lastioctlbitmap, keybitmap); + spin_unlock_irqrestore(&keypad_lock, flags); + return (ret != 0) ? -EFAULT : 0; + } + else + { + return -ENOTTY; + } +} + +static unsigned int +keypad_poll( struct file *file, poll_table * wait ) +{ +#ifdef KDEBUG + printk(KERN_DEBUG " keypad_poll\n"); +#endif + poll_wait(file, &keypad_wait, wait); + + if (!KEYBUF_EMPTY()) + { + return (POLLIN | POLLRDNORM); + } + return 0; +} + +static unsigned int +keypadB_poll( struct file *file, poll_table * wait ) +{ + int i; + +#ifdef KDEBUG + printk(KERN_DEBUG " keypadB_poll\n"); +#endif + poll_wait(file, &keypad_wait, wait); + + for (i=0; i < NUM_WORDS_IN_BITMAP; i++) + { + if (lastioctlbitmap[i] != keybitmap[i]) + { + return (POLLIN | POLLRDNORM); + } + } + return 0; +} + +static unsigned short +get_from_keybuf(void) +{ + unsigned short event; + unsigned long flags; + + spin_lock_irqsave(&keypad_lock, flags); + event = keybuf[keybuf_start]; + KEYBUF_INC (keybuf_start); + spin_unlock_irqrestore(&keypad_lock, flags); + return event; +} + +static ssize_t +keypad_read(struct file *file, char *buf, size_t count, loff_t *ptr) +{ + int i, ret; + unsigned short event; + +#ifdef KDEBUG + printk(KERN_DEBUG " keypad_read\n"); +#endif + /* Can't seek (pread) on this device */ + if (ptr != &file->f_pos) + { + return -ESPIPE; + } + + if (count == 0) + { + return 0; + } + + if (KEYBUF_EMPTY()) + { + /* buffer is empty */ + /* if not blocking return */ + if (file->f_flags & O_NONBLOCK) + { + return -EAGAIN; + } + /* blocking, so wait for input */ + ret = wait_event_interruptible(keypad_wait, !KEYBUF_EMPTY()); + if (ret) + { + return ret; + } + } + + i = 0; + /* copy events until we have what the user asked for or we run out */ + while ((i+1 < count) && !KEYBUF_EMPTY()) + { + event = get_from_keybuf(); + if ((ret = put_user(event, (unsigned short *)buf)) != 0) + { + return ret; + } + buf += EVENTSIZE; + i += EVENTSIZE; + } + return i; +} + +#ifdef CONFIG_PM +static int button_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) +{ + int pksr; + + pksr = PKSR; + PKSR = 0xfffff; + switch(req) + { + case PM_SUSPEND: + kpc_res = KPC; + kpkdi_res = KPKDI; + set_bitmap_to_zero (oldkeybitmap); + set_bitmap_to_zero (keybitmap); + set_bitmap_to_zero (lastioctlbitmap); + kpas = 0; + kpasmkp0 = 0; + kpasmkp1 = 0; + kpasmkp2 = 0; + kpdk = 0; + break; + case PM_RESUME: + KPC = kpc_res; + KPKDI = kpkdi_res; +#if CONFIG_APM +#if defined(CONFIG_E680_P4A) + if (pksr & 0xe4400) /*93 97 100 101 102 key is pressed (switch on) */ + { + queue_apm_event(KRNL_KEYPAD, NULL); + if (pksr & 0x400) + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } +#endif +#if defined(CONFIG_KEYPAD_E680) + if (pksr & 0xee400) /*93 96 97 98 190 101 102 key is pressed */ + { + queue_apm_event(KRNL_KEYPAD, NULL); + if (pksr & 0x400) + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + if (pksr & 0x2000) + turn_on_bit (keybitmap, KEYPAD_A); + if (pksr & 0x8000) + turn_on_bit (keybitmap, KEYPAD_B); + } +#endif +#if defined(CONFIG_KEYPAD_A780) + printk("pksr = %x\n",pksr); + if (pksr & 0xec400) /* 93 97 98 100 101 102 key is pressed */ + { + queue_apm_event(KRNL_KEYPAD, NULL); + if (pksr & 0x400) + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } +#endif +#endif + + break; + } + return 0; +} +#endif + +/* for /dev/keypad */ +static struct file_operations +keypad_fops = { + read: keypad_read, + llseek: no_llseek, + poll: keypad_poll, + ioctl: keypad_ioctl, + open: keypad_open, + release: keypad_close, +}; + +static struct miscdevice +keypad_misc_device = { + KEYPAD_MINOR, + KEYPAD_NAME, + &keypad_fops, +}; + +/* + * for /dev/keypadB. + * read() isn't defined here. calls to read() will return -1 with EINVAL. + */ +static struct file_operations +keypadB_fops = { + llseek: no_llseek, + poll: keypadB_poll, + ioctl: keypadB_ioctl, + open: keypadB_open, + release: keypadB_close, +}; + +static struct miscdevice +keypadB_misc_device = { + KEYPAD_BITMAP_MINOR, + KEYPAD_BITMAP_NAME, + &keypadB_fops, +}; + +/* + * for /dev/keypadI. + * read() isn't defined here. calls to read() will return -1 with EINVAL. + */ +static struct file_operations +keypadI_fops = { + llseek: no_llseek, + ioctl: keypadI_ioctl, + open: keypadI_open, + release: keypadI_close, +}; + +static struct miscdevice +keypadI_misc_device = { + KEYPAD_INSERT_MINOR, + KEYPAD_INSERT_NAME, + &keypadI_fops, +}; + +#ifdef CONFIG_PANIC_LOG +static u32 panic_bug_used =0; +static int panic_key = 0; +#endif + +/* Interrupt Handler for KEYPAD */ +static void +kp_interrupt(int irq, void *ptr, struct pt_regs *regs) +{ + unsigned long flags; + unsigned long kpc_val; + +#ifdef USE_RELEASE_TIMER + del_timer (&key_release_timer); +#endif + del_timer (&autorepeat_timer); + spin_lock_irqsave(&keypad_lock,flags); + + /* ack interrupt */ + kpc_val = KPC; + + /* matrix interrupt */ + if (kpc_val & KPC_MI) + { +/* + * The Intel driver turned on KPC_AS here. It doesn't seem that we + * would need to do that, because getting an interrupt means that + * a scan was just done. For now, I've commented out the setting + * and clearing of this bit. + KPC |= KPC_AS; + */ + while (KPAS & KPAS_SO) + { + /* Wait for the Scan On bit to go off before */ + /* reading the scan registers. */ + NULL; + }; + + kpas = KPAS; + kpasmkp0 = KPASMKP0; + kpasmkp1 = KPASMKP1; + kpasmkp2 = KPASMKP2; + + } + + /* direct interrupt */ + if (kpc_val & KPC_DI) + { + kpdk = KPDK; + /* + * reading the register turns off the "key pressed since last read" + * bit if it was on, so we turn it off + */ + kpdk &= ~KPDK_DKP; + } + + copy_bitmap (oldkeybitmap, keybitmap); +#if defined(CONFIG_E680_P4A) + if (kpdk & KPDK_DK0) /* VR key is pressed */ + { + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } + if (kpdk & KPDK_DK4) + { + turn_on_bit (keybitmap, KEYPAD_POWER); + } + /* power key is connected to GPIO97 as GPIO input */ +#elif defined(CONFIG_KEYPAD_E680) + scan_to_bitmap (kpas, kpasmkp0, kpasmkp1, keybitmap); + if (kpdk & KPDK_DK0) /* VR key is pressed */ + { + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } + if (kpdk & KPDK_DK4) + { + turn_on_bit (keybitmap, KEYPAD_POWER); + } + /* power key is connected to GPIO97 as GPIO input */ + if (kpdk & KPDK_DK3) + { + turn_on_bit (keybitmap, KEYPAD_A); + } + if (kpdk & KPDK_DK5) + { + turn_on_bit (keybitmap, KEYPAD_B); + } + +#elif defined(CONFIG_KEYPAD_A780) +#ifdef CONFIG_PANIC_LOG + panic_key = 0; +#endif + scan_to_bitmap (kpas, kpasmkp0, kpasmkp1 & 0xfff7ffff, keybitmap); + if (kpdk & KPDK_DK0) /* voice/camera key is pressed */ + { +#ifdef CONFIG_PANIC_LOG + panic_key = 1; +#endif + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } +#endif +#if defined(CONFIG_KEYPAD_A780) + kpasmkp2 = KPASMKP2; + if ( (kpasmkp2 & 0x17) || (kpasmkp1 & 0x80000) ) + { + if( kpasmkp2 == 0x5 && kpasmkp1 == 0x80000 ) + { + printk("Jay Up key pressed\n"); + turn_on_bit(keybitmap, KEYPAD_UP); + } + else + { + if( kpasmkp2 == 0x14 && kpasmkp1 == 0x80000) + { + printk("Jay Right key pressed\n"); + turn_on_bit(keybitmap, KEYPAD_RIGHT); + } + else + { + if( kpasmkp2 == 0x12 && kpasmkp1 == 0x80000) + { + printk("Jay Down key pressed\n"); + turn_on_bit(keybitmap, KEYPAD_DOWN); + } + else + { + if( kpasmkp2 == 0x3 && kpasmkp1 == 0x80000) + { + printk("Jay Left key pressed\n"); + turn_on_bit(keybitmap, KEYPAD_LEFT); + } + else + { + if( kpasmkp1 == 0x80000 && (kpasmkp2 & 0x17) == 0) + + { + printk("Jay Center key pressed\n"); + turn_on_bit(keybitmap, KEYPAD_CENTER); + } + } + } + } + } + } +#endif + + + (void) add_events (oldkeybitmap, keybitmap); + + /* If any keys are down, set a timer to check for key release */ + /* and one for autorepeat if that's on. */ + if (any_keys_down (keybitmap)) + { +#ifdef USE_RELEASE_TIMER + key_release_timer.expires = (jiffies + key_release_interval); + add_timer (&key_release_timer); +#endif + if (do_autorepeat) + { + autorepeat_timer.expires = (jiffies + jiffies_to_first_repeat); + add_timer (&autorepeat_timer); + } + } + + spin_unlock_irqrestore(&keypad_lock, flags); + wake_up_interruptible (&keypad_wait); + printk("keypad interrupt occurred\n"); +} + +#ifdef USE_RELEASE_TIMER +/* + * This is called when the key release timer goes off. That's the + * only time it should be called. Check for changes in what keys + * are down. + */ +static void +release_timer_went_off(unsigned long unused) +{ + unsigned long flags; + + spin_lock_irqsave(&keypad_lock,flags); + do_scan(); + /* If any keys are still down, set the timer going again. */ + if (any_keys_down (keybitmap)) + { + mod_timer (&key_release_timer, jiffies + key_release_interval); + } + else + { + del_timer (&autorepeat_timer); + } + spin_unlock_irqrestore(&keypad_lock, flags); +} +#endif + +/* + * This is called when the autorepeat timer goes off. + */ +static void +autorepeat_timer_went_off(unsigned long unused) +{ + int i, bitnum; + unsigned long tmp; + unsigned long flags; + +#ifdef CONFIG_PANIC_LOG + int temp_key; + if( panic_key == 1 ) + { + kpc_res = KPC; + /* Initiate a manual scan */ + KPC &= ~(KPC_AS | KPC_ASACT | KPC_MIE | KPC_MS0 | KPC_MS1 | KPC_MS2 | KPC_MS3 | KPC_MS4 | KPC_MS5 | KPC_MS6 | KPC_MS7); + /* reading the scan registers. */ + KPC |= 0x10000; + mdelay(0x64); + temp_key = KPMK & 0xff; +// KPC |= (KPC_ASACT | KPC_MS0 | KPC_MS1 | KPC_MS2 | KPC_MS3 | KPC_MS4 | KPC_MS5 | KPC_MS6 | KPC_MS7); + KPC = kpc_res; + + printk("temp_key = %x\n", temp_key); + + if ( temp_key == 0x2 ) + { + if(0 == panic_bug_used) + { + panic_bug_used = 1; + BUG(); + } + } + } +#endif + + spin_lock_irqsave(&keypad_lock,flags); + if (!any_keys_down (keybitmap)) + { + spin_unlock_irqrestore(&keypad_lock, flags); + return; + } + for (i=0;i */ + pxa_gpio_mode(97 | GPIO_ALT_FN_1_IN); /* KP_MKIN<3> */ + pxa_gpio_mode(98 | GPIO_ALT_FN_1_IN); /* KP_MKIN<4> */ + pxa_gpio_mode(99 | GPIO_ALT_FN_1_IN); /* KP_MKIN<5> */ + pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ + pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ + pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ + pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ + pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ + pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ + pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ +#elif defined(CONFIG_E680_P4A) + pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); /* KP_DKIN<0>, VR Key */ + pxa_gpio_mode(97 | GPIO_ALT_FN_1_IN); /* KP_DKIN<4>, power key */ + pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ + pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ + pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ + pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ + pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ + pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ + pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ +#elif defined(CONFIG_KEYPAD_E680) + pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); /* KP_DKIN<0>, VR Key */ + pxa_gpio_mode(96 | GPIO_ALT_FN_1_IN); /* KP_DKIN<3>, GAME_A */ + pxa_gpio_mode(97 | GPIO_ALT_FN_1_IN); /* KP_DKIN<4>, power key */ + pxa_gpio_mode(98 | GPIO_ALT_FN_1_IN); /* KP_DKIN<5>, GAME_B */ + pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ + pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ + pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ + pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ + pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ + pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ + pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ + pxa_gpio_mode(GPIO_TC_MM_EN); + GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); + GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); + PGSR3 |= GPIO_bit(GPIO_TC_MM_EN); +#elif defined(CONFIG_KEYPAD_A780) + pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); /* KP_DKIN<0>, voice_rec */ + pxa_gpio_mode(97 | GPIO_ALT_FN_3_IN); /* KP_MKIN<3> */ + pxa_gpio_mode(98 | GPIO_ALT_FN_3_IN); /* KP_MKIN<4> */ + pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ + pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ + pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ + pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ + pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ + pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ + pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ + pxa_gpio_mode(107 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<4> */ +#elif defined(CONFIG_KEYPAD_MAINSTONE) + /* from Intel driver */ + pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); + pxa_gpio_mode(94 | GPIO_ALT_FN_1_IN); + pxa_gpio_mode(95 | GPIO_ALT_FN_1_IN); + pxa_gpio_mode(98 | GPIO_ALT_FN_1_IN); + pxa_gpio_mode(99 | GPIO_ALT_FN_1_IN); + pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ + pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ + pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ + pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ + pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ + pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ + pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ +#endif + + /* set keypad control register */ + KPC = (KPC_ASACT | /* automatic scan on activity */ + KPC_ME | KPC_DE | /* matrix and direct keypad enabled */ +#if defined(CONFIG_KEYPAD_V700) + (3<<23) | /* 4 columns */ + (6<<26) | /* 7 rows */ +#elif defined(CONFIG_E680_P4A) + (3<<23) | /* 4 columns */ + (2<<26) | /* 3 rows */ + (4<<6) | /* 4# direct key */ +#elif defined(CONFIG_KEYPAD_E680) + (5<<23) | /* 4 columns */ + (4<<26) | /* 3 rows */ + (5<<6) | /* 5# direct keys */ +#elif defined(CONFIG_KEYPAD_A780) + KPC_IMKP | + (4<<23) | /* 5 columns */ + (4<<26) | /* 5 rows */ + (0<<6) | /* 1# direct keys */ +#endif + KPC_MS7_0); /* scan all columns */ + + CKEN |= CKEN19_KEYPAD; + + err = request_irq (IRQ_KEYPAD, kp_interrupt, 0, "Keypad", NULL); + if (err) + { + printk (KERN_CRIT "can't register IRQ%d for keypad, error %d\n", + IRQ_KEYPAD, err); + CKEN &= ~CKEN19_KEYPAD; + return -ENODEV; + } + + if (misc_register (&keypad_misc_device)) + { + printk(KERN_ERR "Couldn't register keypad driver\n"); + return -EIO; + } + if (misc_register (&keypadB_misc_device)) + { + printk(KERN_ERR "Couldn't register keypadB driver\n"); + misc_deregister(&keypad_misc_device); + return -EIO; + } + if (misc_register (&keypadI_misc_device)) + { + printk(KERN_ERR "Couldn't register keypadI driver\n"); + misc_deregister(&keypad_misc_device); + misc_deregister(&keypadB_misc_device); + return -EIO; + } + +#ifdef USE_RELEASE_TIMER + init_timer (&key_release_timer); + key_release_timer.function = release_timer_went_off; +#endif + init_timer (&autorepeat_timer); + autorepeat_timer.function = autorepeat_timer_went_off; + + /* + * we want the phone to be able to tell the status of the screen + * lock switch at power-up time + */ + kpdk = KPDK; /* read direct key register */ + /* + * reading the register turns off the "key pressed since last read" bit + * if it was on, so we turn it off + */ + kpdk &= ~KPDK_DKP; +#if defined(CONFIG_E680_P4A) + if (kpdk & KPDK_DK0) /* VR key is pressed (switch on) */ + { + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } + if (kpdk & KPDK_DK4) /* Power key is pressed (switch on) */ + { + turn_on_bit (keybitmap, KEYPAD_POWER); + } +#elif defined(CONFIG_KEYPAD_E680) + if (kpdk & KPDK_DK0) /* VR key is pressed (switch on) */ + { + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } + if (kpdk & KPDK_DK4) /* Power key is pressed (switch on) */ + { + turn_on_bit (keybitmap, KEYPAD_POWER); + } + if (kpdk & KPDK_DK3) /* GAME_A key is pressed (switch on) */ + { + turn_on_bit (keybitmap, KEYPAD_A); + } + if (kpdk & KPDK_DK5) /* GAME_B key is pressed (switch on) */ + { + turn_on_bit (keybitmap, KEYPAD_B); + } +#elif defined(CONFIG_KEYPAD_A780) + if (kpdk & KPDK_DK0) /* voice/camera key is pressed */ + { + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } +#endif + +#ifdef CONFIG_PM + pm_dev = pm_register(PM_SYS_DEV, 0, button_pm_callback); +#if defined(CONFIG_E680_P4A) +/*93,97,100,101,102*/ + PKWR = 0xe4400; +/*103 104 105 106*/ + PGSR3 |= 0x780; +#endif +#if defined(CONFIG_KEYPAD_E680) +/*93,96,97,98,100,101,102*/ + PKWR = 0xee400; +/*103 104 105 106*/ + PGSR3 |= 0x780; +#endif +#if defined(CONFIG_KEYPAD_A780) +/*93,97,98,100,101,102*/ + PKWR = 0xec400; +/*103 104 105 106 107*/ + PGSR3 |= 0xf80; +#endif +#endif + +#if defined(CONFIG_KEYPAD_E680) +#ifdef CONFIG_PM + keypadI_pm_dev = pm_register(PM_SYS_DEV, 0, keypadI_pm_callback); + PGSR3 |= 0x8; +#endif +#endif + + KPC |= (KPC_DIE | KPC_MIE); + KPKDI = 0x40; + return 0; + +} + +static void +__exit keypad_exit(void) +{ +#ifdef KDEBUG + printk(KERN_DEBUG " keypad_exit\n"); +#endif + misc_deregister(&keypad_misc_device); + misc_deregister(&keypadB_misc_device); + misc_deregister(&keypadI_misc_device); + +#ifdef CONFIG_PM + pm_unregister(pm_dev); +#endif + +#if defined(CONFIG_KEYPAD_E680) +#ifdef CONFIG_PM + pm_unregister(keypadI_pm_dev); +#endif +#endif + + CKEN &= ~CKEN19_KEYPAD; +} + +module_init (keypad_init); +module_exit (keypad_exit); Index: linux-2.6.16.5-a/drivers/misc/ezx/keypad.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/misc/ezx/keypad.c 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,1499 @@ +/* + * linux/drivers/char/keypad.c + * + * (c) Copyright Motorola 2003, All rights reserved. + */ + +/* + * This driver is for three devices: /dev/keypad, /dev/keypadB and + * /dev/keypadI. + * /dev/keypad would be used for reading the key event buffer. + * It can be opened by one process at a time. + * /dev/keypadB would be used for ioctl(KEYPAD_IOC_GETBITMAP). + * It can be opened by one process at a time. + * /dev/keypadI would be used for ioctl(KEYPAD_IOC_INSERT_EVENT). + * It can be opened any number of times simultaneously. + * + * The bulverde specification is ambiguous about when interrupts happen + * for released keys. We were told by Intel that we won't + * get interrupts for released keys except in the case when multiple + * keys were down and they've all been released. So we implemented + * a timer to poll for changes in key states. + * + * The E680 P2 hardware gives us interrupts when any key is released, + * whether it was the only key down or not, and whether it's the last + * of multiple keys to be released or not. We don't know whether this + * behavior will continue in future hardware releases, so the release + * timer is still in the code, #ifdef'd with USE_RELEASE_TIMER. On the + * P2 hardware, the code works with or without USE_RELEASE_TIMER defined. + * If the release interrupts are always going to happen, we can remove + * the #ifdef'd code. + * + * With the P2 hardware, the power key bit in the KPDK register is always + * on. We don't know if this is correct behavior or not, but in any case + * it certainly causes trouble to have that key autorepeating indefinitely, + * or to be checking indefinitely for the key to be released (if we're doing + * release polling). + * + * For now, any_keys_down() returns 0 if the power key is the only one down. + * . At interrupt time, if the power key is the only one down we don't + * set the autorepeat timer or release timer. + * . When the release timer goes off, if the power key is the only one + * still down we don't set the timer again. + * . When the autorepeat timer goes off, if the power key is the only + * one down we don't generate any events. + * In autorepeat_timer_went_off, if there are non-power keys down, while we're + * looking through the whole bitmap of keys down we ignore the power key. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "keypad.h" +#include +#include + +#include + +#ifdef CONFIG_PM +static struct pm_dev *pm_dev; +static struct pm_dev *keypadI_pm_dev; +static int kpc_res,kpkdi_res; +#endif +static int GPIO_TC_MM_STATE = 1; +/* + * This is the number of microseconds we wait before checking to see if any + * keys have been released. + */ +#define RDELAY 200 + +#define KEYBUF_EMPTY() (keybuf_start == keybuf_end) +#define KEYBUF_FULL() ( ((keybuf_end+1)%KEYBUF_SIZE) == keybuf_start) +#define KEYBUF_INC(x) ((x) = (((x)+1) % KEYBUF_SIZE)) + +static int keypad_open (struct inode *, struct file *); +static int keypad_close (struct inode *, struct file *); +static int keypad_ioctl (struct inode *, struct file *, + unsigned int, unsigned long); +static unsigned int keypad_poll (struct file *, poll_table *); +static ssize_t keypad_read (struct file *, char *, size_t, loff_t *); + +static int keypadB_open (struct inode *, struct file *); +static int keypadB_close (struct inode *, struct file *); +static int keypadB_ioctl (struct inode *, struct file *, + unsigned int, unsigned long); +static unsigned int keypadB_poll (struct file *, poll_table *); + +static int keypadI_open(struct inode *, struct file *); +static int keypadI_close(struct inode *, struct file *); +static int keypadI_ioctl (struct inode *, struct file *, + unsigned int, unsigned long); + +static irqreturn_t kp_interrupt (int, void *, struct pt_regs *); +#ifdef USE_RELEASE_TIMER +static void release_timer_went_off (unsigned long); +static void do_scan(void); +#endif +static void autorepeat_timer_went_off (unsigned long); + +static int add_to_keybuf (unsigned short); +static int add_events (unsigned long *, unsigned long *); +static int insert_event (unsigned short); +static unsigned short get_from_keybuf (void); +static void scan_to_bitmap + (unsigned long, unsigned long, unsigned long, unsigned long *); +static inline void set_bitmap_to_zero(unsigned long b[]); +static inline void copy_bitmap(unsigned long dest[], unsigned long source[]); +static inline void turn_on_bit(unsigned long map[], int); +static inline void turn_off_bit(unsigned long map[], int); +static inline int any_keys_down (unsigned long *); + +/* + * keybuf is a circular buffer to hold keypad events. + * keybuf_start is the index of the first event. + * keybuf_end is one more than the index of the last event. + * The buffer is empty when keybuf_start == keybuf_end. + * We only use KEYBUF_SIZE-1 entries in the buffer so we can tell + * when it's full without needing another variable to tell us. + * The buffer is full when (keybuf_end+1)%KEYBUF_SIZE == keybuf_start. + */ +static unsigned short keybuf[KEYBUF_SIZE]; +static int keybuf_start = 0; +static int keybuf_end = 0; + +static DECLARE_WAIT_QUEUE_HEAD(keypad_wait); +static spinlock_t keypad_lock = SPIN_LOCK_UNLOCKED; + +static int reading_opens = 0; +static int bitmap_opens = 0; + +/* previous bitmap of keys down */ +static unsigned long oldkeybitmap[NUM_WORDS_IN_BITMAP]; +/* current bitmap of keys down */ +static unsigned long keybitmap[NUM_WORDS_IN_BITMAP]; +/* last bitmap read by ioctl */ +static unsigned long lastioctlbitmap[NUM_WORDS_IN_BITMAP]; + +static unsigned long kpas = 0; /* last value of kpas */ +static unsigned long kpasmkp0 = 0; /* last value of kpasmkp0 */ +static unsigned long kpasmkp1 = 0; /* last value of kpasmkp1 */ +static unsigned long kpasmkp2 = 0; /* last value of kpasamkp2*/ +static unsigned long kpdk = 0; /* last value of kpdk */ + +#ifdef USE_RELEASE_TIMER +static struct timer_list key_release_timer; +static int key_release_interval = RDELAY * HZ/1000; +#endif + +static int do_autorepeat = 1; +static long jiffies_to_first_repeat = 30; +static long jiffies_to_next_repeat = 30; +static struct timer_list autorepeat_timer; + +extern int lockscreen_flag; + +static int +keypad_open(struct inode *inode, struct file *file) +{ +#ifdef KDEBUG + printk(KERN_DEBUG "keypad_open\n"); +#endif + spin_lock(keypad_lock); + if (reading_opens > 0) + { + spin_unlock(keypad_lock); + return -EBUSY; + } + reading_opens++; + spin_unlock(keypad_lock); + + return 0; +} + +static int +keypadB_open(struct inode *inode, struct file *file) +{ +#ifdef KDEBUG + printk(KERN_DEBUG "keypadB_open\n"); +#endif + spin_lock(keypad_lock); + if (bitmap_opens > 0) + { + spin_unlock(keypad_lock); + return -EBUSY; + } + bitmap_opens++; + /* + * poll returns when lastioctlbitmap is different from keybitmap. + * we set lastioctlbitmap to keybitmap here so that a poll right + * after an open returns when the bitmap is different from when + * the open was done, not when the bitmap is different from the + * last time some other process read it + */ + copy_bitmap(lastioctlbitmap, keybitmap); + spin_unlock(keypad_lock); + + return 0; +} + +#if defined(CONFIG_KEYPAD_E680) +#ifdef CONFIG_PM +static int keypadI_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) +{ + switch(req) + { + case PM_SUSPEND: + break; + case PM_RESUME: + GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); + if(GPIO_TC_MM_STATE == 1) + GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); + else + GPCR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); + break; + default: + break; + } + return 0; +} +#endif +#endif + +static int +keypadI_open(struct inode *inode, struct file *file) +{ +#ifdef KDEBUG + printk(KERN_DEBUG "keypadI_open\n"); +#endif +#if defined(CONFIG_KEYPAD_E680) + pxa_gpio_mode(GPIO_TC_MM_EN); + GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); + GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); +#endif + + return 0; +} + +static int +keypad_close(struct inode * inode, struct file *file) +{ +#ifdef KDEBUG + printk(KERN_DEBUG " keypad_close\n"); +#endif + /* + * this decrement of reading_opens doesn't have to be protected because + * it can only be executed to close the single open of /dev/keypad + */ + reading_opens--; + return 0; +} + +static int +keypadB_close(struct inode * inode, struct file *file) +{ +#ifdef KDEBUG + printk(KERN_DEBUG " keypadB_close\n"); +#endif + /* + * this decrement of bitmap_opens doesn't have to be protected because + * it can only be executed to close the single open of /dev/keypadB + */ + bitmap_opens--; + return 0; +} + +static int +keypadI_close(struct inode * inode, struct file *file) +{ +#ifdef KDEBUG + printk(KERN_DEBUG " keypadI_close\n"); +#endif +#if defined(CONFIG_KEYPAD_E680) + pxa_gpio_mode(GPIO_TC_MM_EN); + GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); + GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); +#endif + + return 0; +} + +/** + * Add the specified event to the key buffer. + * This should be called with keypad_lock locked. + */ +static int +add_to_keybuf (unsigned short event) +{ + if (KEYBUF_FULL()) + { + return -ENOMEM; + } + + keybuf[keybuf_end] = event; + KEYBUF_INC (keybuf_end); + +#ifdef CONFIG_APM + apm_queue_event(KRNL_KEYPAD, NULL); +#endif + //printk("add keypad event = %x\n", event); + return 0; +} + +/* + * code[c*8+r] is the key code for the key that's down when there's a 1 + * in column c, row r of the scan registers. + */ + +#if defined(CONFIG_KEYPAD_V700) +int +scanbit_to_keycode[] = { + /* col 0 */ + KEYPAD_UP, KEYPAD_DOWN, KEYPAD_LEFT, KEYPAD_RIGHT, + KEYPAD_POUND, KEYPAD_0, KEYPAD_9, KEYPAD_NONE, + /* col 1 */ + KEYPAD_2, KEYPAD_4, KEYPAD_6, KEYPAD_8, + KEYPAD_7, KEYPAD_SLEFT, KEYPAD_SRIGHT, KEYPAD_NONE, + /* col 2 */ + KEYPAD_MENU, KEYPAD_1, KEYPAD_3, KEYPAD_5, + KEYPAD_STAR, KEYPAD_VOLUP, KEYPAD_VOLDOWN, KEYPAD_NONE, + /* col 3 */ + KEYPAD_CAMERA, KEYPAD_CLEAR, KEYPAD_CARRIER, KEYPAD_ACTIVATE, + KEYPAD_SEND, KEYPAD_SMART, KEYPAD_VAVR, KEYPAD_NONE +}; + +/* end CONFIG_KEYPAD_V700 */ +#elif defined(CONFIG_E680_P4A) +int +scanbit_to_keycode[] = { + /* col 0 */ + KEYPAD_UP, KEYPAD_DOWN, KEYPAD_LEFT, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 1 */ + KEYPAD_RIGHT, KEYPAD_CENTER, KEYPAD_HOME, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 2 */ + KEYPAD_GAME_R, KEYPAD_NONE, KEYPAD_GAME_L, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 3 */ + KEYPAD_A, KEYPAD_B, KEYPAD_NONE, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, +}; + +/* end CONFIG_E680_P4A */ +#elif defined(CONFIG_KEYPAD_E680) +int +scanbit_to_keycode[] = { + /* col 0 */ + KEYPAD_UP, KEYPAD_DOWN, KEYPAD_NONE, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 1 */ + KEYPAD_RIGHT, KEYPAD_LEFT, KEYPAD_NONE, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 2 */ + KEYPAD_NONE, KEYPAD_GAME_R, KEYPAD_NONE, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 3 */ + KEYPAD_HOME, KEYPAD_GAME_L, KEYPAD_CENTER, KEYPAD_NONE, + KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + +}; +/*end CONFIG_KEYPAD_E680 */ +#elif defined(CONFIG_KEYPAD_A780) +int +scanbit_to_keycode[] = { + /* col 0 */ + KEYPAD_OK, KEYPAD_1, KEYPAD_4, KEYPAD_7, + KEYPAD_STAR, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 1 */ + KEYPAD_MENU, KEYPAD_2, KEYPAD_5, KEYPAD_8, + KEYPAD_0, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 2 */ + KEYPAD_CANCEL, KEYPAD_3, KEYPAD_6, KEYPAD_9, + KEYPAD_POUND, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 3 */ + KEYPAD_JOG_UP, KEYPAD_JOG_MIDDLE, KEYPAD_JOG_DOWN, KEYPAD_LEFT, + KEYPAD_DOWN, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, + /* col 4 */ + KEYPAD_CENTER, KEYPAD_HOME, KEYPAD_PTT, KEYPAD_UP, + KEYPAD_RIGHT, KEYPAD_NONE, KEYPAD_NONE, KEYPAD_NONE, +}; +#endif + +/* + * Decode the specified scan register values into the bitmap pointed + * to by the last argument. The bitmap will contain a 1 + * for each key that's down. + * + * Only the 1st two of the four scan registers are used. + */ +static void +scan_to_bitmap(unsigned long kpas, unsigned long kpasmkp0, + unsigned long kpasmkp1, unsigned long bitmap[]) +{ + int row, col; + int bitnum; + unsigned long scanmap; +#if defined(CONFIG_KEYPAD_A780) + int keep; +#endif + + set_bitmap_to_zero (bitmap); + + if ((kpas & KPAS_MUKP) == MUKP_NO_KEYS) + { + return; + } + + if ((kpas & KPAS_MUKP) == MUKP_ONE_KEY) + { + row = (kpas & KPAS_RP) >> 4; + col = kpas & KPAS_CP; + turn_on_bit (bitmap, scanbit_to_keycode[col*8 + row]); + return; + } + + /* reach here if multiple keys */ + scanmap = (kpasmkp0 & 0x7f) | ((kpasmkp0 & 0x7f0000) >> 8) | + ((kpasmkp1 & 0x7f) << 16) | ((kpasmkp1 & 0x7f0000) << 8); + while ((bitnum = ffs(scanmap)) != 0) + { + /* + * ffs returns bit numbers starting with 1, so subtract 1 to index + * into scanbit_to_keycode[] + */ + turn_on_bit (bitmap, scanbit_to_keycode[bitnum-1]); + scanmap &= ~(1<<(bitnum-1)); + } +#if defined(CONFIG_KEYPAD_A780) + kpasmkp2 = KPASMKP2; + if ((kpasmkp1 & 0x180000) || (kpasmkp2 & 0x18)) + keep = 1; + else + keep = 0; + if ( keep ) + kpasmkp2 &= 0xfffffffe; + while ((bitnum = ffs(kpasmkp2)) !=0) + { + turn_on_bit (bitmap, scanbit_to_keycode[32+bitnum-1]); + kpasmkp2 &= ~(1<<(bitnum-1)); + } +#endif +} + +/* + * Add events indicated by the difference between the last scan (oldbitmap) + * and this one (newbitmap) to the input buffer. + * Return nonzero right away if any of the events can't be added. + * A zero return means all the events were added. + * This should be called with keypad_lock locked. + */ +static int +add_events (unsigned long *oldbitmap, unsigned long *newbitmap) +{ + unsigned long tmpmap, onebitmap; + int bitnum, i, ret; + + /* generate events for keys that were down before and are up now */ + for (i=NUM_WORDS_IN_BITMAP-1;i>=0;i--) + { + tmpmap = oldbitmap[i]; + while ((bitnum = ffs(tmpmap)) != 0) + { + onebitmap = 1<<(bitnum-1); + if ((newbitmap[i] & onebitmap) == 0) + { + ret = add_to_keybuf(bitnum + (32*(NUM_WORDS_IN_BITMAP-1-i) | KEYUP)); + if (ret < 0) + { + return ret; + } + } + tmpmap &= ~onebitmap; + } + } + /* generate events for down keys that were up before */ + for (i=NUM_WORDS_IN_BITMAP-1;i>=0;i--) + { + tmpmap = newbitmap[i]; + while ((bitnum = ffs(tmpmap)) != 0) + { + onebitmap = 1<<(bitnum-1); + if ((oldbitmap[i] & onebitmap) == 0) + { + ret = add_to_keybuf + (bitnum + (32*(NUM_WORDS_IN_BITMAP-1-i) | KEYDOWN)); + if (ret < 0) + { + return ret; + } + } + tmpmap &= ~onebitmap; + } + } + return 0; +} + +/* + * do the INSERT_EVENT ioctl + */ +static int +insert_event (unsigned short event) +{ + unsigned long flags; + int ret; + + if (KEYCODE(event) > KEYPAD_MAXCODE) + { + printk(KERN_WARNING " inserted key code %d too big\n", + KEYCODE(event)); + return -EINVAL; + } + spin_lock_irqsave(&keypad_lock, flags); + if (KEY_IS_DOWN(event)) + { + turn_on_bit(keybitmap, KEYCODE(event)); + } + else + { + turn_off_bit (keybitmap, event); + } + if ((ret = add_to_keybuf(event)) < 0) + { + spin_unlock_irqrestore(&keypad_lock,flags); + return ret; + } + spin_unlock_irqrestore(&keypad_lock, flags); + wake_up_interruptible (&keypad_wait); + return 0; +} + +static int +keypad_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int interval; /* debounce interval */ + int imkp; /* Ignore Multiple Key Press bit */ + struct autorepeatinfo ar; /* autorepeat information */ + +#ifdef KDEBUG + printk (KERN_DEBUG "keypad_ioctl: 0x%x\n", cmd); +#endif + switch (cmd) + { + case KEYPAD_IOC_INSERT_EVENT: + return insert_event ((unsigned short)arg); + break; + case KEYPAD_IOC_GET_DEBOUNCE_INTERVAL: + interval = KPKDI & KPKDI_BITS; + return put_user(interval, (unsigned long *)arg); + break; + case KEYPAD_IOC_SET_DEBOUNCE_INTERVAL: + interval = (unsigned short)arg; + if (interval > KPKDI_BITS) + { + return -EINVAL; + } + KPKDI &= ~KPKDI_BITS; + KPKDI |= interval; + break; + case KEYPAD_IOC_GET_IMKP_SETTING: + imkp = ((KPC & KPC_IMKP) == KPC_IMKP); + return put_user(imkp, (unsigned char *)arg); + break; + case KEYPAD_IOC_SET_IMKP_SETTING: + imkp = (unsigned char)arg; + if (imkp) + { + KPC |= KPC_IMKP; + } + else + { + KPC &= ~KPC_IMKP; + } + break; + case KEYPAD_IOC_SET_AUTOREPEAT: + if (copy_from_user (&ar, (void *)arg, + sizeof(struct autorepeatinfo)) != 0) + { + return -EFAULT; + } + do_autorepeat = ar.r_repeat; + /* times are specified in milliseconds; convert to jiffies */ + jiffies_to_first_repeat = ar.r_time_to_first_repeat * HZ/1000; + jiffies_to_next_repeat = ar.r_time_between_repeats * HZ/1000; + break; + default: + return -ENOTTY; + } + return 0; +} + +static int +keypadB_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned long flags; + int ret; + +#ifdef KDEBUG + printk (KERN_DEBUG "keypadB_ioctl: 0x%x\n", cmd); +#endif + if (cmd == KEYPAD_IOC_INSERT_EVENT) + { + return insert_event ((unsigned short)arg); + } + else if (cmd == KEYPAD_IOC_GETBITMAP) + { + spin_lock_irqsave(&keypad_lock, flags); + ret = copy_to_user ((void *)arg, keybitmap, + NUM_WORDS_IN_BITMAP * sizeof(unsigned long)); + copy_bitmap (lastioctlbitmap, keybitmap); + spin_unlock_irqrestore(&keypad_lock, flags); + return (ret != 0) ? -EFAULT : 0; + } + else + { + return -ENOTTY; + } +} + +static int +keypadI_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned long flags; + int ret; + +#ifdef KDEBUG + printk (KERN_DEBUG "keypadI_ioctl: 0x%x\n", cmd); +#endif +#if defined(CONFIG_KEYPAD_E680) + if( cmd == KEYPADI_TURN_ON_LED ) + { + GPCR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); + GPIO_TC_MM_STATE = 0; + PGSR3 &= ~GPIO_bit(GPIO_TC_MM_EN); + return 0; + } + if( cmd == KEYPADI_TURN_OFF_LED ) + { + GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); + GPIO_TC_MM_STATE = 1; + PGSR3 |= GPIO_bit(GPIO_TC_MM_EN); + return 0; + } +#endif + + if (cmd == KEYPAD_IOC_INSERT_EVENT) + { + return insert_event ((unsigned short)arg); + } + else if (cmd == KEYPAD_IOC_GETBITMAP) + { + spin_lock_irqsave(&keypad_lock, flags); + ret = copy_to_user ((void *)arg, keybitmap, + NUM_WORDS_IN_BITMAP * sizeof(unsigned long)); + copy_bitmap (lastioctlbitmap, keybitmap); + spin_unlock_irqrestore(&keypad_lock, flags); + return (ret != 0) ? -EFAULT : 0; + } + else + { + return -ENOTTY; + } +} + +static unsigned int +keypad_poll( struct file *file, poll_table * wait ) +{ +#ifdef KDEBUG + printk(KERN_DEBUG " keypad_poll\n"); +#endif + poll_wait(file, &keypad_wait, wait); + + if (!KEYBUF_EMPTY()) + { + return (POLLIN | POLLRDNORM); + } + return 0; +} + +static unsigned int +keypadB_poll( struct file *file, poll_table * wait ) +{ + int i; + +#ifdef KDEBUG + printk(KERN_DEBUG " keypadB_poll\n"); +#endif + poll_wait(file, &keypad_wait, wait); + + for (i=0; i < NUM_WORDS_IN_BITMAP; i++) + { + if (lastioctlbitmap[i] != keybitmap[i]) + { + return (POLLIN | POLLRDNORM); + } + } + return 0; +} + +static unsigned short +get_from_keybuf(void) +{ + unsigned short event; + unsigned long flags; + + spin_lock_irqsave(&keypad_lock, flags); + event = keybuf[keybuf_start]; + KEYBUF_INC (keybuf_start); + spin_unlock_irqrestore(&keypad_lock, flags); + return event; +} + +static ssize_t +keypad_read(struct file *file, char *buf, size_t count, loff_t *ptr) +{ + int i, ret; + unsigned short event; + +#ifdef KDEBUG + printk(KERN_DEBUG " keypad_read\n"); +#endif + /* Can't seek (pread) on this device */ + if (ptr != &file->f_pos) + { + return -ESPIPE; + } + + if (count == 0) + { + return 0; + } + + if (KEYBUF_EMPTY()) + { + /* buffer is empty */ + /* if not blocking return */ + if (file->f_flags & O_NONBLOCK) + { + return -EAGAIN; + } + /* blocking, so wait for input */ + ret = wait_event_interruptible(keypad_wait, !KEYBUF_EMPTY()); + if (ret) + { + return ret; + } + } + + i = 0; + /* copy events until we have what the user asked for or we run out */ + while ((i+1 < count) && !KEYBUF_EMPTY()) + { + event = get_from_keybuf(); + if ((ret = put_user(event, (unsigned short *)buf)) != 0) + { + return ret; + } + buf += EVENTSIZE; + i += EVENTSIZE; + } + return i; +} + +#ifdef CONFIG_PM +static int button_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) +{ + int pksr; + + pksr = PKSR; + PKSR = 0xfffff; + switch(req) + { + case PM_SUSPEND: + kpc_res = KPC; + kpkdi_res = KPKDI; + set_bitmap_to_zero (oldkeybitmap); + set_bitmap_to_zero (keybitmap); + set_bitmap_to_zero (lastioctlbitmap); + kpas = 0; + kpasmkp0 = 0; + kpasmkp1 = 0; + kpasmkp2 = 0; + kpdk = 0; + break; + case PM_RESUME: + KPC = kpc_res; + KPKDI = kpkdi_res; +#ifdef CONFIG_APM +#if defined(CONFIG_E680_P4A) + if (pksr & 0xe4400) /*93 97 100 101 102 key is pressed (switch on) */ + { + apm_queue_event(KRNL_KEYPAD); + if (pksr & 0x400) + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } +#endif +#if defined(CONFIG_KEYPAD_E680) + if (pksr & 0xee400) /*93 96 97 98 190 101 102 key is pressed */ + { + apm_queue_event(KRNL_KEYPAD); + if (pksr & 0x400) + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + if (pksr & 0x2000) + turn_on_bit (keybitmap, KEYPAD_A); + if (pksr & 0x8000) + turn_on_bit (keybitmap, KEYPAD_B); + } +#endif +#if defined(CONFIG_KEYPAD_A780) + printk("pksr = %x\n",pksr); + if (pksr & 0xec400) /* 93 97 98 100 101 102 key is pressed */ + { + apm_queue_event(KRNL_KEYPAD); + if (pksr & 0x400) + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } +#endif +#endif + + break; + } + return 0; +} +#endif + +/* for /dev/keypad */ +static struct file_operations +keypad_fops = { + read: keypad_read, + llseek: no_llseek, + poll: keypad_poll, + ioctl: keypad_ioctl, + open: keypad_open, + release: keypad_close, +}; + +static struct miscdevice +keypad_misc_device = { + KEYPAD_MINOR, + KEYPAD_NAME, + &keypad_fops, +}; + +/* + * for /dev/keypadB. + * read() isn't defined here. calls to read() will return -1 with EINVAL. + */ +static struct file_operations +keypadB_fops = { + llseek: no_llseek, + poll: keypadB_poll, + ioctl: keypadB_ioctl, + open: keypadB_open, + release: keypadB_close, +}; + +static struct miscdevice +keypadB_misc_device = { + KEYPAD_BITMAP_MINOR, + KEYPAD_BITMAP_NAME, + &keypadB_fops, +}; + +/* + * for /dev/keypadI. + * read() isn't defined here. calls to read() will return -1 with EINVAL. + */ +static struct file_operations +keypadI_fops = { + llseek: no_llseek, + ioctl: keypadI_ioctl, + open: keypadI_open, + release: keypadI_close, +}; + +static struct miscdevice +keypadI_misc_device = { + KEYPAD_INSERT_MINOR, + KEYPAD_INSERT_NAME, + &keypadI_fops, +}; + +#ifdef CONFIG_PANIC_LOG +static u32 panic_bug_used =0; +#endif + +/* Interrupt Handler for KEYPAD */ +static irqreturn_t +kp_interrupt(int irq, void *ptr, struct pt_regs *regs) +{ + unsigned long flags; + unsigned long kpc_val; + +#ifdef USE_RELEASE_TIMER + del_timer (&key_release_timer); +#endif + del_timer (&autorepeat_timer); + spin_lock_irqsave(&keypad_lock,flags); + + /* ack interrupt */ + kpc_val = KPC; + + /* matrix interrupt */ + if (kpc_val & KPC_MI) + { +/* + * The Intel driver turned on KPC_AS here. It doesn't seem that we + * would need to do that, because getting an interrupt means that + * a scan was just done. For now, I've commented out the setting + * and clearing of this bit. + KPC |= KPC_AS; + */ + while (KPAS & KPAS_SO) + { + /* Wait for the Scan On bit to go off before */ + /* reading the scan registers. */ + NULL; + }; + + kpas = KPAS; + kpasmkp0 = KPASMKP0; + kpasmkp1 = KPASMKP1; + kpasmkp2 = KPASMKP2; + + } + + /* direct interrupt */ + if (kpc_val & KPC_DI) + { + kpdk = KPDK; + /* + * reading the register turns off the "key pressed since last read" + * bit if it was on, so we turn it off + */ + kpdk &= ~KPDK_DKP; + } +#ifdef CONFIG_PANIC_LOG + if ((kpdk & KPDK_DK0)&&(kpasmkp1& 0x00020000)) + { + if(0 == panic_bug_used) + { + panic_bug_used = 1; + BUG(); + } + } +#endif + copy_bitmap (oldkeybitmap, keybitmap); + scan_to_bitmap (kpas, kpasmkp0, kpasmkp1, keybitmap); +#if defined(CONFIG_E680_P4A) + if (kpdk & KPDK_DK0) /* VR key is pressed */ + { + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } + if (kpdk & KPDK_DK4) + { + turn_on_bit (keybitmap, KEYPAD_POWER); + } + /* power key is connected to GPIO97 as GPIO input */ +#elif defined(CONFIG_KEYPAD_E680) + if (kpdk & KPDK_DK0) /* VR key is pressed */ + { + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } + if (kpdk & KPDK_DK4) + { + turn_on_bit (keybitmap, KEYPAD_POWER); + } + /* power key is connected to GPIO97 as GPIO input */ + if (kpdk & KPDK_DK3) + { + turn_on_bit (keybitmap, KEYPAD_A); + } + if (kpdk & KPDK_DK5) + { + turn_on_bit (keybitmap, KEYPAD_B); + } + +#elif defined(CONFIG_KEYPAD_A780) + if (kpdk & KPDK_DK0) /* voice/camera key is pressed */ + { + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } +#endif + + (void) add_events (oldkeybitmap, keybitmap); + + /* If any keys are down, set a timer to check for key release */ + /* and one for autorepeat if that's on. */ + if (any_keys_down (keybitmap)) + { +#ifdef USE_RELEASE_TIMER + key_release_timer.expires = (jiffies + key_release_interval); + add_timer (&key_release_timer); +#endif + if (do_autorepeat) + { + autorepeat_timer.expires = (jiffies + jiffies_to_first_repeat); + add_timer (&autorepeat_timer); + } + } + + spin_unlock_irqrestore(&keypad_lock, flags); + wake_up_interruptible (&keypad_wait); + //printk("keypad interrupt occurred\n"); + return IRQ_HANDLED; +} + +#ifdef USE_RELEASE_TIMER +/* + * This is called when the key release timer goes off. That's the + * only time it should be called. Check for changes in what keys + * are down. + */ +static void +release_timer_went_off(unsigned long unused) +{ + unsigned long flags; + + spin_lock_irqsave(&keypad_lock,flags); + do_scan(); + /* If any keys are still down, set the timer going again. */ + if (any_keys_down (keybitmap)) + { + mod_timer (&key_release_timer, jiffies + key_release_interval); + } + else + { + del_timer (&autorepeat_timer); + } + spin_unlock_irqrestore(&keypad_lock, flags); +} +#endif + +/* + * This is called when the autorepeat timer goes off. + */ +static void +autorepeat_timer_went_off(unsigned long unused) +{ + int i, bitnum; + unsigned long tmp; + unsigned long flags; + + spin_lock_irqsave(&keypad_lock,flags); + if (!any_keys_down (keybitmap)) + { + spin_unlock_irqrestore(&keypad_lock, flags); + return; + } + for (i=0;i */ + pxa_gpio_mode(97 | GPIO_ALT_FN_1_IN); /* KP_MKIN<3> */ + pxa_gpio_mode(98 | GPIO_ALT_FN_1_IN); /* KP_MKIN<4> */ + pxa_gpio_mode(99 | GPIO_ALT_FN_1_IN); /* KP_MKIN<5> */ + pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ + pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ + pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ + pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ + pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ + pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ + pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ +#elif defined(CONFIG_E680_P4A) + pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); /* KP_DKIN<0>, VR Key */ + pxa_gpio_mode(97 | GPIO_ALT_FN_1_IN); /* KP_DKIN<4>, power key */ + pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ + pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ + pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ + pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ + pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ + pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ + pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ +#elif defined(CONFIG_KEYPAD_E680) + pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); /* KP_DKIN<0>, VR Key */ + pxa_gpio_mode(96 | GPIO_ALT_FN_1_IN); /* KP_DKIN<3>, GAME_A */ + pxa_gpio_mode(97 | GPIO_ALT_FN_1_IN); /* KP_DKIN<4>, power key */ + pxa_gpio_mode(98 | GPIO_ALT_FN_1_IN); /* KP_DKIN<5>, GAME_B */ + pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ + pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ + pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ + pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ + pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ + pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ + pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ + pxa_gpio_mode(GPIO_TC_MM_EN); + GPDR(GPIO_TC_MM_EN) |= GPIO_bit(GPIO_TC_MM_EN); + GPSR(GPIO_TC_MM_EN) = GPIO_bit(GPIO_TC_MM_EN); + PGSR3 |= GPIO_bit(GPIO_TC_MM_EN); +#elif defined (CONFIG_KEYPAD_A780) + pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); /* KP_DKIN<0>, voice_rec */ + pxa_gpio_mode(97 | GPIO_ALT_FN_3_IN); /* KP_MKIN<3> */ + pxa_gpio_mode(98 | GPIO_ALT_FN_3_IN); /* KP_MKIN<4> */ + pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ + pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ + pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ + pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ + pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ + pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ + pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ + pxa_gpio_mode(107 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<4> */ +#elif defined(CONFIG_KEYPAD_MAINSTONE) + /* from Intel driver */ + pxa_gpio_mode(93 | GPIO_ALT_FN_1_IN); + pxa_gpio_mode(94 | GPIO_ALT_FN_1_IN); + pxa_gpio_mode(95 | GPIO_ALT_FN_1_IN); + pxa_gpio_mode(98 | GPIO_ALT_FN_1_IN); + pxa_gpio_mode(99 | GPIO_ALT_FN_1_IN); + pxa_gpio_mode(100 | GPIO_ALT_FN_1_IN); /* KP_MKIN<0> */ + pxa_gpio_mode(101 | GPIO_ALT_FN_1_IN); /* KP_MKIN<1> */ + pxa_gpio_mode(102 | GPIO_ALT_FN_1_IN); /* KP_MKIN<2> */ + pxa_gpio_mode(103 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<0> */ + pxa_gpio_mode(104 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<1> */ + pxa_gpio_mode(105 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<2> */ + pxa_gpio_mode(106 | GPIO_ALT_FN_2_OUT); /* KP_MKOUT<3> */ +#endif + + /* set keypad control register */ + KPC = (KPC_ASACT | /* automatic scan on activity */ + KPC_ME | KPC_DE | /* matrix and direct keypad enabled */ +#if defined (CONFIG_KEYPAD_V700) + (3<<23) | /* 4 columns */ + (6<<26) | /* 7 rows */ +#elif defined(CONFIG_E680_P4A) + (3<<23) | /* 4 columns */ + (2<<26) | /* 3 rows */ + (4<<6) | /* 4# direct key */ +#elif defined(CONFIG_KEYPAD_E680) + (5<<23) | /* 4 columns */ + (4<<26) | /* 3 rows */ + (5<<6) | /* 5# direct keys */ +#elif defined(CONFIG_KEYPAD_A780) + (4<<23) | /* 5 columns */ + (4<<26) | /* 5 rows */ + (0<<6) | /* 1# direct keys */ +#endif + KPC_MS_ALL); /* scan all columns */ + + CKEN |= CKEN19_KEYPAD; + + err = request_irq (IRQ_KEYPAD, kp_interrupt, 0, "Keypad", NULL); + if (err) + { + printk (KERN_CRIT "can't register IRQ%d for keypad, error %d\n", + IRQ_KEYPAD, err); + CKEN &= ~CKEN19_KEYPAD; + return -ENODEV; + } + + if (misc_register (&keypad_misc_device)) + { + printk(KERN_ERR "Couldn't register keypad driver\n"); + return -EIO; + } + if (misc_register (&keypadB_misc_device)) + { + printk(KERN_ERR "Couldn't register keypadB driver\n"); + misc_deregister(&keypad_misc_device); + return -EIO; + } + if (misc_register (&keypadI_misc_device)) + { + printk(KERN_ERR "Couldn't register keypadI driver\n"); + misc_deregister(&keypad_misc_device); + misc_deregister(&keypadB_misc_device); + return -EIO; + } + +#ifdef USE_RELEASE_TIMER + init_timer (&key_release_timer); + key_release_timer.function = release_timer_went_off; +#endif + init_timer (&autorepeat_timer); + autorepeat_timer.function = autorepeat_timer_went_off; + + /* + * we want the phone to be able to tell the status of the screen + * lock switch at power-up time + */ + kpdk = KPDK; /* read direct key register */ + /* + * reading the register turns off the "key pressed since last read" bit + * if it was on, so we turn it off + */ + kpdk &= ~KPDK_DKP; +#if defined(CONFIG_E680_P4A) + if (kpdk & KPDK_DK0) /* VR key is pressed (switch on) */ + { + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } + if (kpdk & KPDK_DK4) /* Power key is pressed (switch on) */ + { + turn_on_bit (keybitmap, KEYPAD_POWER); + } +#elif defined(CONFIG_KEYPAD_E680) + if (kpdk & KPDK_DK0) /* VR key is pressed (switch on) */ + { + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } + if (kpdk & KPDK_DK4) /* Power key is pressed (switch on) */ + { + turn_on_bit (keybitmap, KEYPAD_POWER); + } + if (kpdk & KPDK_DK3) /* GAME_A key is pressed (switch on) */ + { + turn_on_bit (keybitmap, KEYPAD_A); + } + if (kpdk & KPDK_DK5) /* GAME_B key is pressed (switch on) */ + { + turn_on_bit (keybitmap, KEYPAD_B); + } +#elif defined(CONFIG_KEYPAD_A780) + if (kpdk & KPDK_DK0) /* voice/camera key is pressed */ + { + turn_on_bit (keybitmap, KEYPAD_CAMERA_VOICE); + } +#endif + +#ifdef CONFIG_PM + pm_dev = pm_register(PM_SYS_DEV, 0, button_pm_callback); +#if defined(CONFIG_E680_P4A) +/*93,97,100,101,102*/ + PKWR = 0xe4400; +/*103 104 105 106*/ + PGSR3 |= 0x780; +#endif +#if defined(CONFIG_KEYPAD_E680) +/*93,96,97,98,100,101,102*/ + PKWR = 0xee400; +/*103 104 105 106*/ + PGSR3 |= 0x780; +#endif +#if defined(CONFIG_KEYPAD_A780) +/*93,97,98,100,101,102*/ + PKWR = 0xec400; +/*103 104 105 106 107*/ + PGSR3 |= 0xf80; +#endif +#endif + +#if defined(CONFIG_KEYPAD_E680) +#ifdef CONFIG_PM + keypadI_pm_dev = pm_register(PM_SYS_DEV, 0, keypadI_pm_callback); + PGSR3 |= 0x8; +#endif +#endif + + KPC |= (KPC_DIE | KPC_MIE); + KPKDI = 0x40; + return 0; +} + +static void +__exit keypad_exit(void) +{ +#ifdef KDEBUG + printk(KERN_DEBUG " keypad_exit\n"); +#endif + misc_deregister(&keypad_misc_device); + misc_deregister(&keypadB_misc_device); + misc_deregister(&keypadI_misc_device); + +#ifdef CONFIG_PM + pm_unregister(pm_dev); +#endif + +#if defined(CONFIG_KEYPAD_E680) +#ifdef CONFIG_PM + pm_unregister(keypadI_pm_dev); +#endif +#endif + + CKEN &= ~CKEN19_KEYPAD; +} + +module_init (keypad_init); +module_exit (keypad_exit); Index: linux-2.6.16.5-a/drivers/misc/ezx/keypad.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/misc/ezx/keypad.h 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,104 @@ +#ifndef __DRIVER_CHAR_KEYPAD_H +#define __DRIVER_CHAR_KEYPAD_H + +/* + * linux/drivers/char/keypad.h + * + * (c) Copyright Motorola 2003, All rights reserved. + */ + +#include +#include + +/** + * /dev/keypad is the main keypad device. Opening this device provides access + * for read(), ioctl() and poll()/select(). Only one process at a time + * can open this device. + */ +#define KEYPAD_NAME "keypad" +#define KEYPAD_MINOR 0xf0 /* 240 */ + +/** + * /dev/keypadB can be opened for ioctl() and poll()/select(). + * Only one process at a time can open this device. + */ +#define KEYPAD_BITMAP_NAME "keypadB" +#define KEYPAD_BITMAP_MINOR 0xf1 /* 241 */ + +/** + * /dev/keypadI can be opened for ioctl(INSERT_EVENT). + * Any number of devices can open this simultaneously. + */ +#define KEYPAD_INSERT_NAME "keypadI" +#define KEYPAD_INSERT_MINOR 0xf2 /* 242 */ + +/* + * KEYBUF_SIZE must be a power of 2 to avoid performance-destroying + * integer divisions in the compiled code. + * Each keypad event is a short, so a buffer n bytes long can hold + * n/2 keypad events. + */ +#define KEYBUF_SIZE 256 + +#if 0 +#define KPC __REG(0x41500000) /* control register */ +#define KPDK __REG(0x41500008) /* direct key register */ +#define KPAS __REG(0x41500020) /* automatic scan register */ +#define KPASMKP0 __REG(0x41500028) /* auto scan multiple key press reg 0 */ +#define KPASMKP1 __REG(0x41500030) /* auto scan multiple key press reg 1 */ +#define KPKDI __REG(0x41500048) /* debounce interval register */ + +#define KPC_RSRVD0 0x80000000 /* reserved */ +#define KPC_AS 0x40000000 /* automatic scan */ +#define KPC_ASACT 0x20000000 /* automatic scan on activity */ +#define KPC_MKRN 0x1c000000 /* number of matrix keypad rows - 1 */ +#define KPC_MKCN 0x03800000 /* number of matrix keypad columns - 1 */ +#define KPC_MI 0x00400000 /* matrix interrupt, reset when read */ +#define KPC_IMKP 0x00200000 /* ignore multiple key press */ +#define KPC_MS7_0 0x001fe000 /* MS7-MS0 assert to scan columns */ +#define KPC_MS7 0x00100000 /* MS7 assert to scan column */ +#define KPC_MS6 0x00080000 /* MS6 assert to scan column */ +#define KPC_MS5 0x00040000 /* MS5 assert to scan column */ +#define KPC_MS4 0x00020000 /* MS4 assert to scan column */ +#define KPC_MS3 0x00010000 /* MS3 assert to scan column */ +#define KPC_MS2 0x00008000 /* MS2 assert to scan column */ +#define KPC_MS1 0x00004000 /* MS1 assert to scan column */ +#define KPC_MS0 0x00002000 /* MS0 assert to scan column */ +#define KPC_ME 0x00001000 /* matrix keypad enable */ +#define KPC_MIE 0x00000800 /* matrix interrupt enable */ +#define KPC_RSRVD1 0x00000600 /* reserved */ +#define KPC_DKN 0x000001c0 /* number of direct keys - 1 */ +#define KPC_DI 0x00000020 /* direct interrupt bit, reset when read */ +#define KPC_RSRVD2 0x00000010 /* reserved */ +#define KPC_REE1 0x00000008 /* rotary encoder 1 enable */ +#define KPC_REE0 0x00000004 /* rotary encoder 0 enable */ +#define KPC_DE 0x00000002 /* direct keypad enable */ +#define KPC_DIE 0x00000001 /* direct keypad interrupt enable */ + +#define KPC_7rows 0x18000000 /* 6 in KPC_MKRN */ +#define KPC_4cols 0x01800000 /* 3 in KPC_MKCN */ +/* + * bits in Direct Key register + */ +#define KPDK_DKP (0x1 << 31) /* on if direct key pressed since last read */ +#define KPDK_DK7 (0x1 << 7) +#define KPDK_DK6 (0x1 << 6) +#define KPDK_DK5 (0x1 << 5) +#define KPDK_DK4 (0x1 << 4) +#define KPDK_DK3 (0x1 << 3) +#define KPDK_DK2 (0x1 << 2) +#define KPDK_DK1 (0x1 << 1) +#define KPDK_DK0 (0x1 << 0) + + +#endif + +#define KPKDI_BITS 0xff /* bits in KPKDI register for debounce interval */ +#define KPAS_MUKP 0x7c000000 /* KPAS bits 30-26 */ +#define MUKP_NO_KEYS 0x00000000 /* value of MUKP if no keys are down */ +#define MUKP_ONE_KEY 0x04000000 /* value of MUKP if one key is down */ +#define KPAS_SO 0x80000000 /* scan on bit */ +#define KPAS_RP 0x000000f0 /* row of single key */ +#define KPAS_CP 0x0000000f /* column of single key */ + +#endif /* __DRIVER_CHAR_KEYPAD_H */ Index: linux-2.6.16.5-a/drivers/misc/ezx/log.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/misc/ezx/log.c 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,287 @@ +/* + * Kernel panic log interface for Linux. + * + * Copyright (c) 2000 Motorola + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * 0.01 2003-07-01 zxf + * - initial release + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" + +#include +#include "../video/pxafb.h" + +#define LOGDRV_MINOR 188 + +static struct log_area *log = NULL; +struct log_cmdline log_cmdline; + +static int __init log_setup(char *str) +{ + struct log_cmdline *c; + + c = &log_cmdline; + memcpy(c->name, str, sizeof(c->name)); + + return 1; +} + +__setup("paniclog=", log_setup); + +void panic_trig(const char *str, struct pt_regs *regs, int err) +{ + if (log) + die(str, regs, err); +} +EXPORT_SYMBOL(panic_trig); + +int log_register(struct log_area *log_f) +{ + if (strcmp(log_cmdline.name, log_f->name) == 0) + log = log_f; + return 0; +} + +int log_unregister(struct log_area *log_f) +{ + log = NULL; + return 0; +} + +static loff_t logdrv_lseek(struct file *file, loff_t offset, int orig) +{ + switch (orig) { + case 0: + /* SEEK_SET */ + file->f_pos = offset; + break; + case 1: + /* SEEK_CUR */ + file->f_pos += offset; + break; + case 2: + /* SEEK_END */ + file->f_pos = log->size + offset; + break; + default: + return -EINVAL; + } + + if (file->f_pos < 0) + file->f_pos = 0; + else if (file->f_pos >= log->size) + file->f_pos = log->size - 1; + + return file->f_pos; +} + +static int logdrv_open(struct inode *inode, struct file *file) +{ + if (!log) { + printk("Not register mechine specific log structure!\n"); + return -ENODEV; + } + + return 0; +} + +static int logdrv_close(struct inode *inode, struct file *file) +{ + return 0; +} + +static ssize_t logdrv_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + + if (count < 0) + return -EINVAL; + + if (count > log->size - p) + count = log->size - p; + if (log->read) + return log->read(buf, count, ppos); + + if (copy_to_user((void *)buf, (void *)(log->start + *ppos), count)) + return -EFAULT; + + *ppos += count; + return count; +} + +static struct file_operations logdrv_fops = { + owner: THIS_MODULE, + llseek: logdrv_lseek, + read: logdrv_read, + open: logdrv_open, + release: logdrv_close, +}; + +static struct miscdevice logdrv_miscdev = { + LOGDRV_MINOR, + "log drv", + &logdrv_fops +}; + +extern void logbuf_info(char **st, unsigned long *cnt); +extern struct pxafb_info *pxafbi; +extern int get_irq_list(char *buf); + +extern atomic_t vm_committed_space; +void dump_proc_meminfo(void) +{ + struct sysinfo i; + char buf[1024]; + int len; + int pg_size, committed; + +#define K(x) ((x) << (PAGE_SHIFT - 10)) +#define B(x) ((unsigned long long)(x) << PAGE_SHIFT) + + si_meminfo(&i); + si_swapinfo(&i); + + pg_size = atomic_read(&page_cache_size) - i.bufferram ; + committed = atomic_read(&vm_committed_space); + + len = sprintf(buf, " total: used: free: shared: buffers: cached:\n" + "Mem: %8Lu %8Lu %8Lu %8Lu %8Lu %8Lu\n" + "Swap: %8Lu %8Lu %8Lu\n", + B(i.totalram), B(i.totalram-i.freeram), B(i.freeram), + B(i.sharedram), B(i.bufferram), + B(pg_size), B(i.totalswap), + B(i.totalswap-i.freeswap), B(i.freeswap)); + + len += sprintf(buf+len, + "MemTotal: %8lu kB\n" + "MemFree: %8lu kB\n" + "MemShared: %8lu kB\n" + "Buffers: %8lu kB\n" + "Cached: %8lu kB\n" + "SwapCached: %8lu kB\n" + "Active: %8u kB\n" + "Inactive: %8u kB\n" + "HighTotal: %8lu kB\n" + "HighFree: %8lu kB\n" + "LowTotal: %8lu kB\n" + "LowFree: %8lu kB\n" + "SwapTotal: %8lu kB\n" + "SwapFree: %8lu kB\n" + "Committed_AS: %8u kB\n", + K(i.totalram), + K(i.freeram), + K(i.sharedram), + K(i.bufferram), + K(pg_size - swapper_space.nrpages), + K(swapper_space.nrpages), + K(nr_active_pages), + K(nr_inactive_pages), + K(i.totalhigh), + K(i.freehigh), + K(i.totalram-i.totalhigh), + K(i.freeram-i.freehigh), + K(i.totalswap), + K(i.freeswap), + K(committed)); + + printk(KERN_EMERG " [meminfo] len 0x%x\n %s\n", len, buf); +} + +int panic_log_notify(struct notifier_block *self, unsigned long code, void *unused) +{ + unsigned long count; + char *start; + + printk(KERN_EMERG "****** panic time: %d ******\n", OSCR); //RCNR); + + if(pxafbi) + { + int i; + unsigned long *p; + printk(KERN_EMERG " pxafbi->map_cpu: 0x%x, size 0x%x\n", pxafbi->map_cpu, pxafbi->map_size); + p = (unsigned long)(pxafbi->map_cpu); + for(i=0; i<(pxafbi->map_size/sizeof(unsigned long)); i++) + *p++ = 0x0; + printk(KERN_EMERG "****** panic time: %d ******\n", OSCR); + } + + if(1) + { + // cat /proc/interrupts + char buf[1024]; + int len; + + len = get_irq_list(buf); + printk(KERN_EMERG " [interrupts] len 0x%x\n", len); + printk(KERN_EMERG "%s\n", buf); + } + + if(1) + { + // cat /proc/meminfo + dump_proc_meminfo(); + } + + /* Below 2 lines will overwrite useful information if log_buf is not large enough */ + printk(KERN_EMERG "****** show task state when panic *******\n"); + show_state(); + + /* get syslog buf info: start position, number of chars */ + logbuf_info(&start, &count); + + /* write information to log area */ + if (log && log->write) + log->write(start, count); + + printk(KERN_EMERG "OK, Now we exit panic log function!\n"); + + return NOTIFY_DONE; +} + +static struct notifier_block panic_log_nb = { + panic_log_notify, + NULL, + 0 +}; + +extern struct notifier_block *panic_notifier_list; +static int __init log_init(void) +{ + misc_register(&logdrv_miscdev); + return notifier_chain_register(&panic_notifier_list, &panic_log_nb); +} + +static void __exit log_exit(void) +{ + notifier_chain_unregister(&panic_notifier_list, &panic_log_nb); + misc_deregister(&logdrv_miscdev); +} + +module_init(log_init); +module_exit(log_exit); + +EXPORT_SYMBOL(log_register); +EXPORT_SYMBOL(log_unregister); + +MODULE_AUTHOR("zxf "); +MODULE_DESCRIPTION("Kernel panic log interface"); +MODULE_LICENSE("GPL"); + Index: linux-2.6.16.5-a/drivers/misc/ezx/log.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/drivers/misc/ezx/log.h 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,35 @@ +/* + * Kernel panic log interface for Linux on A760(XScale PXA262). + * + * Copyright (c) 2000 Motorola + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * 0.01 2003-07-01 zxf + * - initial release + */ + +#ifndef _PANIC_LOG_H_ +#define _PANIC_LOG_H_ + +#include + +struct log_area { + char name[8]; + unsigned long start; + unsigned long size; + ssize_t (*write) (const char *buf, size_t count); + ssize_t (*read) (const char *buf, size_t count, loff_t *ppos); +}; + +struct log_cmdline { + char name[8]; +}; + +extern int log_register(struct log_area *log_f); +extern int log_unregister(struct log_area *log_f); + +#endif /* _PANIC_LOG_H_ */ Index: linux-2.6.16.5-a/include/linux/keypad.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/include/linux/keypad.h 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,137 @@ +#ifndef __LINUX_KEYPAD_H +#define __LINUX_KEYPAD_H + +/* + * include/linux/keypad.h + * + * (c) Copyright Motorola 2003, All rights reserved. + */ + +#include + +#define KEYDOWN 0x8000 +#define KEYUP 0x0000 + +#define EVENTSIZE sizeof(short) +#define KEY_IS_DOWN(x) ((x) & KEYDOWN) +#define KEYCODE(x) ((x) & 0x7fff) + +struct autorepeatinfo { + int r_repeat; /* 1 to do autorepeat, 0 to not do it */ + int r_time_to_first_repeat; /* time to first repeat in milliseconds */ + int r_time_between_repeats; /* time between repeats in milliseconds */ +}; + +#define KEYPAD_IOCTL_BASE 'k' + +/* + * return the bitmap of keys currently down. + * The bitmap is an array of NUM_WORDS_IN_BITMAP unsigned long words. + * We count the bits starting with 1 in the rightmost position in + * the rightmost (highest-indexed) word. If NUM_WORDS_IN_BITMAP is two, + * the bitmap looks like this: + * 0 1 + * ---------------------------------------------------- + * | 64 63 ........... 34 33 | 32 31 ............. 2 1 | + * ---------------------------------------------------- + * Bit n corresponds to key code n. + */ + +#define KEYPAD_IOC_GETBITMAP _IOR(KEYPAD_IOCTL_BASE,1,unsigned long *) +#define NUM_WORDS_IN_BITMAP 2 + +/** + * put the specified event on the keypad's input queue and update the bitmap. + * The exact event as specified will be returned by read() when it + * reaches the front of the queue. A key press event consists of + * the key code or'd with KEYDOWN. A key release event consists of + * just the key code. + */ +#define KEYPAD_IOC_INSERT_EVENT _IOW(KEYPAD_IOCTL_BASE,2,unsigned short) + +/** + * have the driver interpret the specified scan register values as + * if it had gotten an interrupt. The passed-in argument is a pointer + * to three consecutive 32-bit words in this order: KPAS, KPASMKP0, KPASMKP1. + */ +#define KEYPAD_IOC_INSERTKEYSCAN _IOW(KEYPAD_IOCTL_BASE,3,unsigned long *) + +/* get the hardware debounce interval (in milliseconds) */ +#define KEYPAD_IOC_GET_DEBOUNCE_INTERVAL \ + _IOR(KEYPAD_IOCTL_BASE,4,unsigned short *) + +/* set the hardware debounce interval (in milliseconds) */ +#define KEYPAD_IOC_SET_DEBOUNCE_INTERVAL \ + _IOW(KEYPAD_IOCTL_BASE,4,unsigned short) + +/* get "Ignore Multiple Key Press" bit; 1 means they are ignored */ +#define KEYPAD_IOC_GET_IMKP_SETTING _IOR(KEYPAD_IOCTL_BASE,5,unsigned char *) + +/* set "Ignore Multiple Key Press" bit; 1 means they will be ignored */ +#define KEYPAD_IOC_SET_IMKP_SETTING _IOW(KEYPAD_IOCTL_BASE,5,unsigned char) + +/* + * specify what to do about autorepeat on held keys + * the 3rd argument is a pointer to a struct autorepeat + */ +#define KEYPAD_IOC_SET_AUTOREPEAT _IOW(KEYPAD_IOCTL_BASE,6,unsigned long *) + +#define KEYPADI_TURN_ON_LED 1 +#define KEYPADI_TURN_OFF_LED 0 +/* + * the constant KEY_k is both the code for key k in an event returned by + * read() and the bit position for key k in the bitmap returned by + * ioctl(KEYPAD_IOC_GETBITMAP). + */ +#define KEYPAD_NONE 0 + +#define KEYPAD_0 1 +#define KEYPAD_1 2 +#define KEYPAD_2 3 +#define KEYPAD_3 4 +#define KEYPAD_4 5 +#define KEYPAD_5 6 +#define KEYPAD_6 7 +#define KEYPAD_7 8 +#define KEYPAD_8 9 +#define KEYPAD_9 10 + +#define KEYPAD_UP 11 +#define KEYPAD_DOWN 12 +#define KEYPAD_LEFT 13 +#define KEYPAD_RIGHT 14 +#define KEYPAD_POUND 15 +#define KEYPAD_STAR 16 +#define KEYPAD_MENU 17 +#define KEYPAD_SLEFT 18 +#define KEYPAD_SRIGHT 19 +#define KEYPAD_VOLUP 20 +#define KEYPAD_VOLDOWN 21 +#define KEYPAD_CAMERA 22 +#define KEYPAD_CLEAR 23 +#define KEYPAD_CARRIER 24 +#define KEYPAD_ACTIVATE 25 +#define KEYPAD_SEND 26 +#define KEYPAD_SMART 27 +#define KEYPAD_VAVR 28 + +#define KEYPAD_CENTER 29 +#define KEYPAD_HOME 30 +#define KEYPAD_A 31 +#define KEYPAD_B 32 +#define KEYPAD_GAME_R 33 +#define KEYPAD_GAME_L 34 +#define KEYPAD_CAMERA_VOICE 35 +//#define KEYPAD_SCREEN_LOCK 36 +#define KEYPAD_POWER 37 + +#define KEYPAD_OK 38 +#define KEYPAD_CANCEL 39 +#define KEYPAD_PTT 40 +#define KEYPAD_JOG_UP 41 +#define KEYPAD_JOG_MIDDLE 42 +#define KEYPAD_JOG_DOWN 43 + +#define KEYPAD_MAXCODE 43 + +#endif /* __LINUX_KEYPAD_H */ Index: linux-2.6.16.5-a/include/linux/wrapper.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16.5-a/include/linux/wrapper.h 2006-05-04 17:07:04.000000000 +0200 @@ -0,0 +1,7 @@ +#ifndef _WRAPPER_H_ +#define _WRAPPER_H_ + +#define mem_map_reserve(p) set_bit(PG_reserved, &((p)->flags)) +#define mem_map_unreserve(p) clear_bit(PG_reserved, &((p)->flags)) + +#endif /* _WRAPPER_H_ */ Index: linux-2.6.16.5-a/include/linux/apm_bios.h =================================================================== --- linux-2.6.16.5-a.orig/include/linux/apm_bios.h 2006-05-04 17:06:50.000000000 +0200 +++ linux-2.6.16.5-a/include/linux/apm_bios.h 2006-05-04 17:07:04.000000000 +0200 @@ -208,6 +208,31 @@ #define APM_CAP_RESUME_SUSPEND_PCMCIA 0x0080 /* Resume on PCMCIA Ring */ /* + * kernel event definitions for our ezx platform + */ +enum +{ + KRNL_ACCS_ATTACH, + KRNL_ACCS_DETACH, + KRNL_BLUETOOTH, + KRNL_TOUCHSCREEN, + KRNL_KEYPAD, + KRNL_RTC, + KRNL_FLIP_ON, + KRNL_FLIP_OFF, + KRNL_VOICE_REC, + KRNL_ICL, + KRNL_BP, + KRNL_BP_WDI, + KRNL_PROC_INACT, + KRNL_IDLE_TIMEOUT, + KRNL_SCREEN_LOCK, + KRNL_SCREEN_UNLOCK +}; + + + +/* * ioctl operations */ #include