Index: linux-2.6.23/arch/arm/mach-pxa/ezx.c =================================================================== --- linux-2.6.23.orig/arch/arm/mach-pxa/ezx.c 2007-10-23 12:03:55.000000000 +0200 +++ linux-2.6.23/arch/arm/mach-pxa/ezx.c 2007-10-23 13:21:24.000000000 +0200 @@ -86,8 +86,40 @@ .init = ezx_ohci_init, }; +/* BP */ +static struct resource ezxbp_resources[] = { + [0] = { + .start = IRQ_GPIO(GPIO_BP_RDY), + .end = IRQ_GPIO(GPIO_BP_RDY), + .flags = IORESOURCE_IRQ, + }, + [1] = { + .start = IRQ_GPIO(GPIO_BB_WDI2), + .end = IRQ_GPIO(GPIO_BB_WDI2), + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = IRQ_GPIO(GPIO_BB_WDI), + .end = IRQ_GPIO(GPIO_BB_WDI), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device ezxbp_device = { + .name = "ezx-bp", + .dev = { + //.parent = + //.platform_data = + }, + .id = -1, + .num_resources = ARRAY_SIZE(ezxbp_resources), + .resource = ezxbp_resources, +}; + + static struct platform_device *devices[] __initdata = { + &ezxbp_device, }; static int __init ezx_init(void) Index: linux-2.6.23/arch/arm/mach-pxa/Kconfig =================================================================== --- linux-2.6.23.orig/arch/arm/mach-pxa/Kconfig 2007-10-23 12:03:55.000000000 +0200 +++ linux-2.6.23/arch/arm/mach-pxa/Kconfig 2007-10-23 13:21:23.000000000 +0200 @@ -106,6 +106,9 @@ endchoice +config EZX_BP + bool "BP Control code for EZX Platform" + endif endmenu Index: linux-2.6.23/arch/arm/mach-pxa/ezx-bp.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.23/arch/arm/mach-pxa/ezx-bp.c 2007-10-23 13:22:01.000000000 +0200 @@ -0,0 +1,264 @@ +/* + * BP handshake code for Motorola EZX phones + * + * Copyright (c) 2007 Daniel Ribeiro + * + * Based on Motorola's a780.c Copyright (c) 2003-2005 Motorola + * + * 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 + +/* BP Handshake */ +#define FIRST_STEP 2 +#define LAST_STEP 3 +#define BP_RDY_TIMEOUT 0x000c0000 + +#if 1 +#define DEBUGP(x, args ...) printk(x, ##args) +#else +#define DEBUGP(x, args ...) +#endif + +extern void usb_send_readurb(void); + +struct bp { + int irq_wdi; + int irq_wdi2; + int irq_rdy; +}; + +/* check power down condition */ +static inline void check_power_off(void) +{ + if (pxa_gpio_get_value(GPIO_BB_WDI2) == 0) { + DEBUGP("BP request poweroff!\n"); + /* + * It is correct to power off here, the following line is + * commented out because e680 lowers WDI2 when BP is in + * flash mode, otherwise WDI2 is used to detect low + * battery. You can safely uncomment this line if you are + * using this kernel with BP in normal mode. + */ +#ifndef CONFIG_PXA_EZX_E680 + pm_power_off(); +#endif + } +} + +static int step = FIRST_STEP; + +inline int bp_handshake_passed(void) +{ + return (step > LAST_STEP); +} +EXPORT_SYMBOL(bp_handshake_passed); + +void handshake(void) +{ + /* step 1: check MCU_INT_SW or BP_RDY is low (now it is checked in apboot) */ + DEBUGP("bp handshake entered!\n"); + if (step == 1) { + int timeout = BP_RDY_TIMEOUT; + + /* config MCU_INT_SW, BP_RDY as input */ + pxa_gpio_mode(GPIO_MCU_INT_SW | GPIO_IN); + pxa_gpio_mode(GPIO_BP_RDY | GPIO_IN); + + while (timeout--) { + if (pxa_gpio_get_value(GPIO_MCU_INT_SW) == 0 + || pxa_gpio_get_value(GPIO_BP_RDY) == 0) { + step ++; + break; + } + + check_power_off(); + } + DEBUGP("ezx-bp: handshake step 1\n"); + } + + /* step 2: wait BP_RDY is low */ + if (step == 2) { + if (pxa_gpio_get_value(GPIO_BP_RDY) == 0) { + /* config MCU_INT_SW as output */ + pxa_gpio_mode(GPIO_MCU_INT_SW | GPIO_OUT); + pxa_gpio_set_value(GPIO_MCU_INT_SW, 0); + + step ++; + DEBUGP("ezx-bp: handshake step 2\n"); + } + } + + /* step 3: wait BP_RDY is high */ + else if (step == 3) { + if (pxa_gpio_get_value(GPIO_BP_RDY)) { + step ++; + //FIXME delay_bklight(); + pxa_gpio_set_value(GPIO_MCU_INT_SW, 1); + printk(KERN_NOTICE "ezx-bp: handshake passed\n"); + } + } +} + +irqreturn_t bp_wdi_handler(int irq, void *dev_id) +{ + DEBUGP("BP Lowered WDI line. This is not good :(\n"); + /* + * this means that BP is not responsive. + * we could try to reset BP and then handshake again + * but i doubt its possible to bring it up again. + */ + return IRQ_HANDLED; +} + +static irqreturn_t bp_rdy_handler(int irq, void *dev_id) +{ + struct bp *bp = dev_id; + DEBUGP("BP rdy irq\n"); + if (!bp_handshake_passed()) { + handshake(); + if (bp_handshake_passed()) { + /* FIXME: (test) try to not disable irq_wdi2 and drain battery */ + disable_irq(bp->irq_wdi2); + + /* set bp_rdy handle for usb ipc */ + set_irq_type(bp->irq_rdy, IRQT_FALLING); + } + } +#ifdef CONFIG_TS0710_MUX_USB + else usb_send_readurb(); +#endif + return IRQ_HANDLED; +} + +/* BP request for poweroff */ +static irqreturn_t bp_wdi2_handler(int irq, void *dev_id) +{ + DEBUGP("BP request poweroff!\n"); + /* same case as check_power_off() */ +#ifndef CONFIG_PXA_EZX_E680 + pm_power_off(); +#endif + return IRQ_HANDLED; +} + +static int __init ezxbp_probe(struct platform_device *dev) +{ + int ret; + struct bp *bp; + + bp = kzalloc(sizeof(*bp), GFP_KERNEL); + if (!bp) + return -ENOMEM; + + bp->irq_rdy = platform_get_irq(dev, 0); + if(bp->irq_rdy < 0) { + ret = bp->irq_rdy; + goto fail; + } + + bp->irq_wdi2 = platform_get_irq(dev, 1); + if(bp->irq_wdi2 < 0) { + ret = bp->irq_wdi2; + goto fail; + } + + bp->irq_wdi = platform_get_irq(dev, 2); + if(bp->irq_wdi < 0) { + ret = bp->irq_wdi; + goto fail; + } + + set_irq_type(bp->irq_wdi, IRQT_FALLING); + request_irq(bp->irq_wdi, bp_wdi_handler, IRQF_DISABLED, + "bp wdi", bp); + + set_irq_type(bp->irq_rdy, IRQT_BOTHEDGE); + request_irq(bp->irq_rdy, bp_rdy_handler, IRQF_DISABLED, + "bp rdy", bp); + + set_irq_type(bp->irq_wdi2, IRQT_FALLING); + request_irq(bp->irq_wdi2, bp_wdi2_handler, IRQF_DISABLED, + "bp wdi2", bp); + + /* turn on BP */ + pxa_gpio_mode(GPIO_BB_RESET|GPIO_OUT); + pxa_gpio_set_value(GPIO_BB_RESET, 1); + + check_power_off(); + handshake(); + + return 0; +fail: + kfree(bp); + return ret; +} + +static int ezxbp_remove(struct platform_device *dev) +{ + struct bp *bp = platform_get_drvdata(dev); + + free_irq(bp->irq_wdi, bp); + free_irq(bp->irq_wdi2, bp); + free_irq(bp->irq_rdy, bp); + kfree(bp); + + return 0; +} + +static int ezxbp_suspend(struct platform_device *dev, pm_message_t state) +{ + DEBUGP("bp suspend!\n"); +// pxa_gpio_set_value(GPIO_MCU_INT_SW, 0); + return 0; +} + +static int ezxbp_resume(struct platform_device *dev) +{ + DEBUGP("bp resume!\n"); +// pxa_gpio_set_value(GPIO_MCU_INT_SW, 1); + return 0; +} +static struct platform_driver ezxbp_driver = { + .probe = ezxbp_probe, + .remove = ezxbp_remove, +#warning FIXME: missing suspend/resume support + .suspend = ezxbp_suspend, + .resume = ezxbp_resume, + .driver = { + .name = "ezx-bp", + .owner = THIS_MODULE, + }, +}; + +int __init ezxbp_init(void) +{ + return platform_driver_register(&ezxbp_driver); +} + +void ezxbp_fini(void) +{ + return platform_driver_unregister(&ezxbp_driver); +} + +module_init(ezxbp_init); +module_exit(ezxbp_fini); + +MODULE_DESCRIPTION("Motorola BP Control driver"); +MODULE_AUTHOR("Daniel Ribeiro "); +MODULE_LICENSE("GPL"); + Index: linux-2.6.23/arch/arm/mach-pxa/Makefile =================================================================== --- linux-2.6.23.orig/arch/arm/mach-pxa/Makefile 2007-10-23 12:03:55.000000000 +0200 +++ linux-2.6.23/arch/arm/mach-pxa/Makefile 2007-10-23 13:21:23.000000000 +0200 @@ -25,6 +25,7 @@ obj-$(CONFIG_PXA_EZX_E2) += ezx-e2.o obj-$(CONFIG_PXA_EZX_A1200) += ezx-a1200.o obj-$(CONFIG_PXA_EZX_E6) += ezx-e6.o +obj-$(CONFIG_EZX_BP) += ezx-bp.o # Support for blinky lights led-y := leds.o