From: <mar...@us...> - 2007-03-19 20:32:34
|
Revision: 924 http://svn.sourceforge.net/hackndev/?rev=924&view=rev Author: marex_z71 Date: 2007-03-19 13:19:05 -0700 (Mon, 19 Mar 2007) Log Message: ----------- PalmLD: Battery driver and TESTING new powermanagement !!! USE AT YOUR 0WN RISK, IT CAN HANG YOUR DEVICE !!! Modified Paths: -------------- linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/Kconfig linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/Makefile linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/palmld.c linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/palmld_ide.c linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/palmld_pm.c linux4palm/linux/trunk/include/asm-arm/arch-pxa/palmld-gpio.h Added Paths: ----------- linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/palmld_battery.c linux4palm/linux/trunk/include/asm-arm/arch-pxa/palmld-init.h Removed Paths: ------------- linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/palmld_ac97.c Modified: linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/Kconfig =================================================================== --- linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/Kconfig 2007-03-18 19:56:23 UTC (rev 923) +++ linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/Kconfig 2007-03-19 20:19:05 UTC (rev 924) @@ -21,3 +21,20 @@ config PALMLD_IDE tristate "Palm LifeDrive IDE driver" depends on MACH_XSCALE_PALMLD + +config PALMLD_BATTERY + tristate "Palm LifeDrive Battery support" + select TOUCHSCREEN_WM97XX + depends on MACH_XSCALE_PALMLD + default m + help + Enable support for PalmOne LifeDrive battery to APM. + ATM use it only as module, otherwise it hangs. + +config PALMLD_PM + tristate "Palm LifeDrive Power Management support" + depends on MACH_XSCALE_PALMLD + default y if MACH_XSCALE_PALMLD + help + Enable support for suspend/resume the PalmOne LifeDrive PDA. + \ No newline at end of file Modified: linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/Makefile =================================================================== --- linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/Makefile 2007-03-18 19:56:23 UTC (rev 923) +++ linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/Makefile 2007-03-19 20:19:05 UTC (rev 924) @@ -6,5 +6,6 @@ obj-$(CONFIG_PALMLD_PCMCIA) += palmld_pcmcia.o obj-$(CONFIG_PALMLD_USB) += palmld_usb.o obj-$(CONFIG_PALMLD_IDE) += palmld_ide.o -obj-$(CONFIG_PM) += palmld_pm.o +obj-$(CONFIG_PALMLD_PM) += palmld_pm.o +obj-$(CONFIG_PALMLD_BATTERY) += palmld_battery.o Modified: linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/palmld.c =================================================================== --- linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/palmld.c 2007-03-18 19:56:23 UTC (rev 923) +++ linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/palmld.c 2007-03-19 20:19:05 UTC (rev 924) @@ -234,6 +234,18 @@ }; +/******************** + * Power Management * + ********************/ + +struct platform_device palmld_pm = { + .name = "palmld-pm", + .id = -1, + .dev = { + .platform_data = NULL, + }, +}; + /********************************************************* * IDE *********************************************************/ @@ -246,7 +258,7 @@ static struct platform_device *devices[] __initdata = { &palmld_kbd, &palmld_ac97, &palmld_ide, &palmld_backlight, - &palmldled_device, + &palmldled_device, &palmld_pm, }; /********************************************************* @@ -325,13 +337,6 @@ static void __init palmld_init(void) { - - -#ifdef CONFIG_PM - extern struct pxa_ll_pm_ops palmld_ll_pm_ops; - pxa_pm_set_ll_ops(&palmld_ll_pm_ops); -#endif - set_pxa_fb_info( &palmld_lcd_screen ); pxa_set_mci_info( &palmld_mci_platform_data ); platform_add_devices( devices, ARRAY_SIZE(devices) ); Deleted: linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/palmld_ac97.c =================================================================== --- linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/palmld_ac97.c 2007-03-18 19:56:23 UTC (rev 923) +++ linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/palmld_ac97.c 2007-03-19 20:19:05 UTC (rev 924) @@ -1,544 +0,0 @@ -/* - * linux/arch/arm/mach-pxa/palmld/palmld-ts.c - * - * Touchscreen/battery driver for Palm LifeDrive's WM9712 AC97 codec. - * - * Author: Alex Osborne <bob...@gm...> - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/input.h> -#include <linux/device.h> -#include <linux/workqueue.h> -#include <linux/battery.h> - -#include <asm/delay.h> -#include <asm/arch/hardware.h> -#include <asm/arch/pxa-regs.h> -#include <asm/arch/irqs.h> -#include <asm/arch/palmld-gpio.h> -#include <asm/arch/palmld-ac97.h> - -#include <asm/mach-types.h> -#include <asm/mach/arch.h> -#include <asm/mach/map.h> - -#include <sound/driver.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/initval.h> -#include <sound/ac97_codec.h> - - -#define palmld_ac97_WORK_QUEUE_NAME "palmld_ac97.c" - -#define GET_GPIO(gpio) \ - (GPLR(gpio) & GPIO_bit(gpio)) - -#define X_AXIS_MAX 3630 -#define X_AXIS_MIN 200 -#define Y_AXIS_MAX 3880 -#define Y_AXIS_MIN 160 -#define PRESSURE_MIN 0 -#define PRESSURE_MAX 300 - -#define GPIO_DEBUG - -static spinlock_t palmld_ac97_lock = SPIN_LOCK_UNLOCKED; - -static struct workqueue_struct *palmld_ac97_workqueue; -static struct work_struct palmld_ac97_irq_task; -struct input_dev *palmld_ac97_input; -struct device *palmld_ac97_dev; - -static u64 battery_update_jiffies_64 = 0; -static int battery_voltage; - -DECLARE_MUTEX(battery_update_mutex); - -/* - * ac97 codec - */ - -void wm97xx_gpio_func(ac97_t *ac97, int gpio, int func) -{ - int GEn; - GEn = ac97->bus->ops->read(ac97, 0x56); - if(func) - GEn |= gpio; - else - GEn &= ~gpio; - ac97->bus->ops->write(ac97, 0x56, GEn); -} - -void wm97xx_gpio_mode(ac97_t *ac97, int gpio, int config, int polarity, - int sticky, int wakeup) -{ - int GCn, GPn, GSn, GWn; - GCn = ac97->bus->ops->read(ac97, 0x4c); - GPn = ac97->bus->ops->read(ac97, 0x4e); - GSn = ac97->bus->ops->read(ac97, 0x50); - GWn = ac97->bus->ops->read(ac97, 0x52); - - if(config) - GCn |= gpio; - else - GCn &= ~gpio; - - if(polarity) - GPn |= gpio; - else - GPn &= ~gpio; - - if(sticky) - GSn |= gpio; - else - GSn &= ~gpio; - - if(wakeup) - GWn |= gpio; - else - GWn &= ~gpio; - - ac97->bus->ops->write(ac97, 0x4c, GCn); - ac97->bus->ops->write(ac97, 0x4e, GPn); - ac97->bus->ops->write(ac97, 0x50, GSn); - ac97->bus->ops->write(ac97, 0x52, GWn); -} - -void wm97xx_set_digitiser_power(struct device *dev, int value) -{ - ac97_t *ac97 = dev->platform_data; - u16 d2; - - d2 = ac97->bus->ops->read(ac97, AC97_WM97XX_DIGITISER2); - d2 |= value; - ac97->bus->ops->write(ac97, AC97_WM97XX_DIGITISER2, d2); -} - -/* - * This is a hack that waits until the ac97 bus is free. I was unable to find - * a more appropriate way of doing this, but it seems to work. If we don't use - * this, then the driver will eventually conflict with another driver's use - * of AC97 (probably audio) and will lockup. - */ -void wait_for_ac97(void) -{ - int timeout=1000; - - while (CAR & CAR_CAIP) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/100); - set_current_state(TASK_RUNNING); - if(!timeout--) { - printk("palmld_ac97_pendown: CAR_CAIP timeout\n"); - return; - } - } - CAR &= ~CAR_CAIP; - -} - -static int palmld_ac97_take_reading(struct device *dev, int adcsel) -{ - ac97_t *ac97 = dev->platform_data; - int timeout=100; - u16 r76, r7a; - - r76 = ac97->bus->ops->read(ac97, 0x76); - r76 &= ~WM97XX_ADCSEL_MASK; /* clear ADCSEL */ - r76 |= adcsel; /* set ADCSEL */ - r76 &= ~(1<<11); /* COO = 0 (single measurement) */ - r76 &= ~(1<<10); /* CTC = 0 (polling mode) */ - r76 |= (1<<15); /* start reading */ - ac97->bus->ops->write(ac97, 0x76, r76); - - do { - if(!(timeout--)) { - printk("palmld_ac97_pendown: timed out waiting for poll to complete.\n"); - return 0; - } - //udelay(1); - r76 = ac97->bus->ops->read(ac97, 0x76); - } while(!(r76 & (1<<15))); - printk("Poll complete loops=%d\n", 100-timeout); - - r7a = ac97->bus->ops->read(ac97, 0x7a); - return r7a; -} - - - -/* - * battery - */ - -void update_data(int force) -{ - u16 reading; - - if(!force && (battery_update_jiffies_64 + HZ > jiffies_64)) { - return; - } - - if(down_trylock(&battery_update_mutex)) { - return; - } - - - spin_lock(&palmld_ac97_lock); - wait_for_ac97(); - - #ifdef GPIO_DEBUG - ac97_t *ac97 = palmld_ac97_dev->platform_data; - - // invert and univert the gpio a few times while watching - // the PXA's gpios to see if we can spot a connection ;) - printk("%x %x %x\n", GPLR0, GPLR1, GPLR2); - - reading = ac97->bus->ops->read(ac97, 0x58); - ac97->bus->ops->write(ac97, 0x58, reading | 1); - udelay(10); - printk("%x %x %x %x\n", GPLR0, GPLR1, GPLR2, GPLR3); - - reading = ac97->bus->ops->read(ac97, 0x58); - ac97->bus->ops->write(ac97, 0x58, reading & (~1)); - udelay(10); - printk("%x %x %x %x\n", GPLR0, GPLR1, GPLR2, GPLR3); - - - #else - wm97xx_set_digitiser_power(palmld_ac97_dev, WM97XX_PRP_DET_DIG); - reading = palmld_ac97_take_reading(palmld_ac97_dev, WM97XX_ADCSEL_BMON); - wm97xx_set_digitiser_power(palmld_ac97_dev, WM97XX_PRP_DET); - - #endif - - spin_unlock(&palmld_ac97_lock); - battery_voltage = reading & 0xfff; - printk("Battery: %d\n", battery_voltage); - - battery_update_jiffies_64 = jiffies_64; - up(&battery_update_mutex); -} - -int get_min_voltage(struct battery *b) -{ - return 0; -} -int get_min_charge(struct battery *b) -{ - return 0; -} -int get_max_voltage(struct battery *b) -{ - return 4750; /* mV */ -} -int get_max_charge(struct battery *b) -{ - return 1; -} -int get_voltage(struct battery *b) -{ - update_data(0); - return battery_voltage; -} -int get_charge(struct battery *b) -{ - return 0; -} -int get_status(struct battery *b) -{ - return 0; //power_status == POWER_NONE? 0: 1; -} - -static struct battery palmld_battery = { - .name = "palmld-ac97", - .id = "battery0", - .get_min_voltage = get_min_voltage, - .get_min_current = NULL, - .get_min_charge = get_min_charge, - .get_max_voltage = get_max_voltage, - .get_max_current = NULL, - .get_max_charge = get_max_charge, - .get_temp = NULL, - .get_voltage = get_voltage, - .get_current = NULL, - .get_charge = get_charge, - .get_status = get_status, -}; - -static void -battery_class_release(struct class_device *dev) -{ -} - -static void -battery_class_class_release(struct class *class) -{ -} - - -/* - * touchscreen - */ - -static void palmld_ac97_pendown(struct device *dev) -{ - ac97_t *ac97 = dev->platform_data; - int xread, yread, pressure; - int pendown=0, valid_coords=0; - - - - /* - * shut off the pen detect interrupt until pen goes up, otherwise the WM9712 - * will keep on interrupting us and we'll never be able to get any work - * done. - */ - spin_lock(&palmld_ac97_lock); - wait_for_ac97(); - wm97xx_gpio_mode(ac97, WM97XX_GPIO_13, WM97XX_GPIO_IN, - WM97XX_GPIO_POL_HIGH, WM97XX_GPIO_NOTSTICKY, WM97XX_GPIO_NOWAKE); - spin_unlock(&palmld_ac97_lock); - - - /* take readings until the pen goes up */ - do { - spin_lock(&palmld_ac97_lock); - wait_for_ac97(); - - /* power up digitiser */ - wm97xx_set_digitiser_power(dev, WM97XX_PRP_DET_DIG); - - /* take readings */ - xread = palmld_ac97_take_reading(dev, WM97XX_ADCSEL_X); - yread = palmld_ac97_take_reading(dev, WM97XX_ADCSEL_Y); - pressure = palmld_ac97_take_reading(dev, WM97XX_ADCSEL_PRES); - - /* power down digitiser to conserve power */ - wm97xx_set_digitiser_power(dev, WM97XX_PRP_DET); - - printk("(%d,%d) = %d\n", xread&0xfff, yread&0xfff, pressure&0xfff); - - pendown = pressure & (1<<15); - valid_coords = (xread & 0xfff) && (yread & 0xfff) && (pressure & 0xfff); - - /* - * with light pressure reading is exteremely inaccurate so only report - * it when there is heavy pressure - */ - if( (!pendown) || (pressure & 0xfff) < 100 ) { - - /* valid coordinates? */ - if(valid_coords) { - input_report_abs(palmld_ac97_input, ABS_X, xread & 0xfff); - input_report_abs(palmld_ac97_input, ABS_Y, yread & 0xfff); - input_report_abs(palmld_ac97_input, ABS_PRESSURE, pressure & 0xfff); - } - - if(valid_coords || !pendown) { - input_report_key(palmld_ac97_input, BTN_TOUCH, pendown); - } - input_sync(palmld_ac97_input); - } - - spin_unlock(&palmld_ac97_lock); - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/100); - set_current_state(TASK_RUNNING); - } while(pressure & (1<<15)); - - /* re-enable pen detect interrupt */ - spin_lock(&palmld_ac97_lock); - wait_for_ac97(); - wm97xx_gpio_mode(ac97, WM97XX_GPIO_13, WM97XX_GPIO_IN, - WM97XX_GPIO_POL_HIGH, WM97XX_GPIO_STICKY, WM97XX_GPIO_WAKE); - spin_unlock(&palmld_ac97_lock); - - printk("exit\n"); -} - -static void palmld_ac97_irq_work(void *data) -{ - int change = 0; - struct device *dev = data; - ac97_t *ac97 = dev->platform_data; - u16 levels; - - - //while(GET_GPIO(27)) { /* while interrupt still there */ - - spin_lock(&palmld_ac97_lock); - wait_for_ac97(); - levels = ac97->bus->ops->read(ac97, 0x54); - spin_unlock(&palmld_ac97_lock); - - printk("int %x\n", levels); - - - if(levels & WM97XX_GPIO_13) { - printk("Pen down detected %x\n", levels); - levels &= ~WM97XX_GPIO_13; - //wm9712_initiate_measurement(ac97); - palmld_ac97_pendown(dev); - change++; - } - - spin_lock(&palmld_ac97_lock); - wait_for_ac97(); - ac97->bus->ops->write(ac97, 0x54, levels); - spin_unlock(&palmld_ac97_lock); - //} - - -} - -static irqreturn_t palmld_ac97_irq_handler(int irq, void *dev_id, struct pt_regs *regs) -{ - /* - * we can't use ac97 from within the interrupt handler, so schedule a task - * to do the actual handling. - */ - queue_work(palmld_ac97_workqueue, &palmld_ac97_irq_task); - - return IRQ_HANDLED; -} - -static int __init palmld_ac97_probe(struct device *dev) -{ - int err; - ac97_t *ac97 = dev->platform_data; - u16 d2; - - if(!machine_is_xscale_palmld()) - return -ENODEV; - printk("palmld_ac97_probe\n"); - - /* for use by bettery level monitor */ - palmld_ac97_dev = dev; - - /* setup work queue */ - palmld_ac97_workqueue = create_workqueue(palmld_ac97_WORK_QUEUE_NAME); - INIT_WORK(&palmld_ac97_irq_task, palmld_ac97_irq_work, dev); - - - set_irq_type(IRQ_GPIO_PALMLD_WM9712_IRQ, IRQT_RISING); - err = request_irq(IRQ_GPIO_PALMLD_WM9712_IRQ, palmld_ac97_irq_handler, - SA_INTERRUPT, "WM9712 IRQ", dev); - - if(err) { - printk(KERN_ERR "palmld_ac97_probe: cannot request pen down IRQ\n"); - return -1; - } - - spin_lock(&palmld_ac97_lock); - - printk("x\n"); - - /* reset levels */ - ac97->bus->ops->write(ac97, 0x54, 0); - printk("y\n"); - - /* disable digitiser to save power, enable pen-down detect */ - d2 = ac97->bus->ops->read(ac97, AC97_WM97XX_DIGITISER2); - d2 |= WM97XX_PRP_DET; - ac97->bus->ops->write(ac97, AC97_WM97XX_DIGITISER2, d2); - - - /* enable interrupts on codec's gpio 2 (connected to cpu gpio 27) */ - wm97xx_gpio_mode(ac97, WM97XX_GPIO_2, WM97XX_GPIO_IN, - WM97XX_GPIO_POL_HIGH, WM97XX_GPIO_NOTSTICKY, WM97XX_GPIO_NOWAKE); - wm97xx_gpio_func(ac97, WM97XX_GPIO_2, 0); - - /* enable pen detect interrupt */ - wm97xx_gpio_mode(ac97, WM97XX_GPIO_13, WM97XX_GPIO_IN, - WM97XX_GPIO_POL_HIGH, WM97XX_GPIO_STICKY, WM97XX_GPIO_WAKE); - - /* enable ada detect interrupt */ - /* - wm97xx_gpio_mode(ac97, WM97XX_GPIO_12, WM97XX_GPIO_IN, - WM97XX_GPIO_POL_HIGH, WM97XX_GPIO_NOTSTICKY, WM97XX_GPIO_NOWAKE); - */ - - /* turn off irq gpio inverting */ - ac97->bus->ops->write(ac97, 0x58, ac97->bus->ops->read(ac97, 0x58)&~1); - - - /* turn on the digitiser and pen down detector */ - d2 = ac97->bus->ops->read(ac97, AC97_WM97XX_DIGITISER2); - d2 |= WM97XX_PRP_DETW; - ac97->bus->ops->write(ac97, AC97_WM97XX_DIGITISER2, d2); - printk("probe\n"); - - spin_unlock(&palmld_ac97_lock); - - /* setup the input device */ - palmld_ac97_input = input_allocate_device(); - palmld_ac97_input->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); - palmld_ac97_input->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); - input_set_abs_params(palmld_ac97_input, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0); - input_set_abs_params(palmld_ac97_input, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0); - input_set_abs_params(palmld_ac97_input, ABS_PRESSURE, PRESSURE_MIN, PRESSURE_MAX, 0, 0); - - palmld_ac97_input->name = "Palm LifeDrive touchscreen"; - palmld_ac97_input->dev = dev; - palmld_ac97_input->id.bustype = BUS_HOST; - input_register_device(palmld_ac97_input); - - /* register battery */ - if(battery_class_register(&palmld_battery)) { - printk(KERN_ERR "palmld_ac97_probe: Could not register battery " - "class\n"); - } else { - palmld_battery.class_dev.class->release = battery_class_release; - palmld_battery.class_dev.class->class_release = battery_class_class_release; - } - - return 0; -} - -static int __exit palmld_ac97_remove (struct device *dev) -{ - ac97_t *ac97 = dev->platform_data; - printk("x: %x\n", ac97->bus->ops->read(ac97, AC97_WM97XX_DIGITISER2)); - input_unregister_device(palmld_ac97_input); - free_irq(IRQ_GPIO_PALMLD_WM9712_IRQ, dev); - return 0; -} - -static struct device_driver palmld_ac97_driver = { - .name = "WM9711,WM9712", - .bus = &ac97_bus_type, - .probe = palmld_ac97_probe, - .remove = palmld_ac97_remove, -#ifdef CONFIG_PM - .suspend = NULL, - .resume = NULL, -#endif -}; - -static int __init palmld_ac97_init(void) -{ - if(!machine_is_xscale_palmld()) - return -ENODEV; - - - return driver_register(&palmld_ac97_driver); -} - -static void __exit palmld_ac97_exit(void) -{ - driver_unregister(&palmld_ac97_driver); -} - -module_init(palmld_ac97_init); -module_exit(palmld_ac97_exit); - -MODULE_AUTHOR ("Alex Osborne <bob...@gm...>"); -MODULE_DESCRIPTION ("WM9712 AC97 codec support for Palm LifeDrive"); -MODULE_LICENSE ("GPL"); Added: linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/palmld_battery.c =================================================================== --- linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/palmld_battery.c (rev 0) +++ linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/palmld_battery.c 2007-03-19 20:19:05 UTC (rev 924) @@ -0,0 +1,236 @@ +/************************************************************************ + * linux/arch/arm/mach-pxa/palmld/palmld_battery.c * + * * + * Touchscreen/battery driver for WM9712 AC97 codec * + * Authros: Jan Herman <2h...@se...> * + * Sergey Lapin <sl...@ha...> * + * Changes for PalmLD: Marek Vasut <mar...@gm...> * + * * + ************************************************************************/ + + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/input.h> +#include <linux/device.h> +#include <linux/workqueue.h> +#include <linux/battery.h> + +#include <asm/apm.h> +#include <asm/delay.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/arch/hardware.h> +#include <asm/arch/pxa-regs.h> +#include <asm/arch/irqs.h> + +#include <sound/driver.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/initval.h> +#include <linux/wm97xx.h> +#include <asm/arch/palmld-gpio.h> +#include <asm/arch/palmld-init.h> + + +struct palmld_battery_dev +{ + struct wm97xx * wm; + int battery_registered; + int current_voltage; + int previous_voltage; + u32 last_battery_update; +}; + +struct palmld_battery_dev bat; + +#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) +/* original APM hook */ +static void (*apm_get_power_status_orig)(struct apm_power_info *info); +#endif + +int palmld_battery_min_voltage(struct battery *b) +{ + return PALMLD_BAT_MIN_VOLTAGE; +} + + +int palmld_battery_max_voltage(struct battery *b) +{ + return PALMLD_BAT_MAX_VOLTAGE; /* mV */ +} + +/* + This formula is based on battery life of my battery 1100mAh. Original battery in Zire72 is Li-On 920mAh + V_batt = ADCSEL_BMON * 1,889 + 767,8 [mV] +*/ + +int palmld_battery_get_voltage(struct battery *b) +{ + if (bat.battery_registered){ + bat.previous_voltage = bat.current_voltage; + bat.current_voltage = wm97xx_read_aux_adc(bat.wm, WM97XX_AUX_ID3); + bat.last_battery_update = jiffies; + return bat.current_voltage * 1889/1000 + 7678/10; + } + else{ + printk("palmld_battery: cannot get voltage -> battery driver unregistered\n"); + return 0; + } +} + + +int palmld_battery_get_status(struct battery *b) +{ + int ac_connected = GET_PALMLD_GPIO(POWER_DETECT); + int usb_connected = !GET_PALMLD_GPIO(USB_DETECT); + + if (bat.current_voltage <= 0) + return BATTERY_STATUS_UNKNOWN; + + if (ac_connected || usb_connected){ + if ( ( bat.current_voltage > bat.previous_voltage ) || (bat.current_voltage <= PALMLD_BAT_MAX_VOLTAGE) ) + return BATTERY_STATUS_CHARGING; + return BATTERY_STATUS_NOT_CHARGING; + } + else + return BATTERY_STATUS_DISCHARGING; +} + +struct battery palmld_battery = { + .name = "palmld_battery", + .id = "battery0", + .get_min_voltage = palmld_battery_min_voltage, + .get_max_voltage = palmld_battery_max_voltage, + .get_voltage = palmld_battery_get_voltage, + .get_status = palmld_battery_get_status, +}; + +static int palmld_wm97xx_probe(struct device *dev) +{ + struct wm97xx *wm = dev->driver_data; + bat.wm = wm; + return 0; +} + +static int palmld_wm97xx_remove(struct device *dev) +{ + return 0; +} + +static void +palmld_wm97xx_shutdown(struct device *dev) +{ +#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) + apm_get_power_status = apm_get_power_status_orig; +#endif +} + +static int +palmld_wm97xx_suspend(struct device *dev, pm_message_t state) +{ + return 0; +} + +static int +palmld_wm97xx_resume(struct device *dev) +{ + return 0; +} + + +static struct device_driver palmld_wm97xx_driver = { + .name = "wm97xx-touchscreen", + .bus = &wm97xx_bus_type, + .owner = THIS_MODULE, + .probe = palmld_wm97xx_probe, + .remove = palmld_wm97xx_remove, + .suspend = palmld_wm97xx_suspend, + .resume = palmld_wm97xx_resume, + .shutdown = palmld_wm97xx_shutdown +}; + +#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) + +/* APM status query callback implementation */ +static void palmld_apm_get_power_status(struct apm_power_info *info) +{ + int min, max, curr, percent; + + curr = palmld_battery_get_voltage(&palmld_battery); + min = palmld_battery_min_voltage(&palmld_battery); + max = palmld_battery_max_voltage(&palmld_battery); + + curr = curr - min; + if (curr < 0) curr = 0; + max = max - min; + + percent = curr*100/max; + + info->battery_life = percent; + + info->ac_line_status = (GET_PALMLD_GPIO(POWER_DETECT) + ? APM_AC_ONLINE : APM_AC_OFFLINE); + + if (info->ac_line_status) { + info->battery_status = APM_BATTERY_STATUS_CHARGING; + } else { + if (percent > 50) + info->battery_status = APM_BATTERY_STATUS_HIGH; + else if (percent < 5) + info->battery_status = APM_BATTERY_STATUS_CRITICAL; + else + info->battery_status = APM_BATTERY_STATUS_LOW; + } + + info->time = percent * PALMLD_MAX_LIFE_MINS/100; + info->units = APM_UNITS_MINS; +} +#endif +static int __init palmld_wm97xx_init(void) +{ +#ifndef MODULE + int ret; +#endif + + /* register battery to APM layer */ + bat.battery_registered = 0; + + if(battery_class_register(&palmld_battery)) { + printk(KERN_ERR "palmld_ac97_probe: could not register battery class\n"); + } + else { + bat.battery_registered = 1; + printk("Battery registered\n"); + } +#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) + apm_get_power_status_orig = apm_get_power_status; + apm_get_power_status = palmld_apm_get_power_status; +#endif +#ifndef MODULE + /* If we're in kernel, we could accidentally be run before wm97xx + and thus have panic */ + if((ret = bus_register(&wm97xx_bus_type)) < 0) + return ret; +#endif + return driver_register(&palmld_wm97xx_driver); +} + +static void __exit palmld_wm97xx_exit(void) +{ +/* TODO - recover APM callback to original state */ + battery_class_unregister(&palmld_battery); + driver_unregister(&palmld_wm97xx_driver); +} + +module_init(palmld_wm97xx_init); +module_exit(palmld_wm97xx_exit); + +/* Module information */ +MODULE_AUTHOR("Sergey Lapin <sl...@ha...> Jan Herman <2h...@se...>"); +MODULE_DESCRIPTION("wm97xx battery driver"); +MODULE_LICENSE("GPL"); Modified: linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/palmld_ide.c =================================================================== --- linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/palmld_ide.c 2007-03-18 19:56:23 UTC (rev 923) +++ linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/palmld_ide.c 2007-03-19 20:19:05 UTC (rev 924) @@ -67,6 +67,8 @@ .bus = &platform_bus_type, .probe = palmld_ide_probe, .remove = palmld_ide_remove, + .suspend= NULL, + .resume = NULL, }; static int __init palmld_ide_init(void) Modified: linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/palmld_pm.c =================================================================== --- linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/palmld_pm.c 2007-03-18 19:56:23 UTC (rev 923) +++ linux4palm/linux/trunk/arch/arm/mach-pxa/palmld/palmld_pm.c 2007-03-19 20:19:05 UTC (rev 924) @@ -1,87 +1,185 @@ +/************************************************************************ + * PalmOne LifeDrive suspend/resume support * + * * + * Author: Jan Herman <2h...@se...> * + * Sergey Lapin <sla...@gm...> * + * Modification for Palm LifeDrive: Marek Vasut <mar...@gm...> * + * * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License version 2 as * + * published by the Free Software Foundation. * + * * + ************************************************************************/ + #include <linux/kernel.h> #include <linux/device.h> #include <linux/pm.h> +#include <linux/fb.h> +#include <linux/platform_device.h> +#include <asm/mach-types.h> +#include <asm/hardware.h> +#include <asm/arch/pm.h> #include <asm/arch/pxa-pm_ll.h> #include <asm/arch/hardware.h> #include <asm/arch/pxa-regs.h> -static u32 *addr_a0200000; -static u32 *addr_a0200004; -static u32 *addr_a0200008; -static u32 save_a0200000; -static u32 save_a0200004; -static u32 save_a0200008; +#include <asm/arch/palmld-gpio.h> +#include <asm/arch/pxa27x_keyboard.h> -static void palmld_pxa_ll_pm_suspend(unsigned long resume_addr) +#define KPASMKP(col) (col/2==0 ? KPASMKP0 : col/2==1 ? KPASMKP1 : col/2==2 ? KPASMKP2 : KPASMKP3) +#define KPASMKPx_MKC(row, col) (1 << (row + 16*(col%2))) + +struct pm_save_data { + int brightness; + u32 rcnr; +}; - /* wake up on */ - PWER |= PWER_GPIO12; - //PFER |= PWER_RTC; - PRER |= PWER_GPIO12; - - /* USB, in theory this can even wake us from deep sleep */ - PWER |= PWER_GPIO3; - PFER |= PWER_GPIO3; - PRER |= PWER_GPIO3; - - /* disable GPIO reset, palm bootloader will hang us */ - //PCFR |= PCFR_GPR_EN | PCFR_OPDE; - PCFR &= PCFR_GPR_EN; - - /* as set by POS */ - /*PGSR0 = 0x00020000; - PGSR1 = 0x00000000; - PGSR2 = 0x01004000; - PGSR3 = 0x00421380; - - PGSR2 |= (1<<30); - PGSR3 |= (1<<7) | (1<<8) | (1<<9); +static struct pm_save_data pm_save_data; - PSLR = 0xff400000; - */ - //PKWR |= GPIO_bit(0) | GPIO_bit(12) | GPIO_bit(3) | (1<<17); - //PKSR = 0xffffffff; // clear +#ifdef CONFIG_PM +static int palmld_suspend(struct device *dev, pm_message_t state) +{ + /* Wake-Up on RTC event, etc. */ + PWER |= PWER_RTC | PWER_WEP1; + /* Wake-Up on powerbutton */ + PWER |= PWER_GPIO12; + PRER |= PWER_GPIO12; - /* - addr_a0200000 = phys_to_virt(0xa0200000); - addr_a0200004 = phys_to_virt(0xa0200004); - addr_a0200008 = phys_to_virt(0xa0200008); + /* USB, in theory this can even wake us from deep sleep */ +// PWER |= PWER_GPIO3; +// PFER |= PWER_GPIO3; +// PRER |= PWER_GPIO3; - save_a0200000 = *addr_a0200000; - save_a0200004 = *addr_a0200004; - save_a0200008 = *addr_a0200008; - */ - /* - c: e3a00121 mov r0, #1073741832 ; 0x40000008 - 10: e280060f add r0, r0, #15728640 ; 0xf00000 - 14: e590f000 ldr pc, [r0] - */ - - /* - *addr_a0200000 = 0xe3a00121; // mov r0, #0x40000008 - *addr_a0200004 = 0xe280060f; // add r0, r0, #0xf00000 - *addr_a0200008 = 0xe590f000; // ldr pc, [r0] - */ + /* Wakeup by keyboard :) */ +// PKWR = 0xe0001; - PSPR = 0; /* should cause Palm bootloader to allow us to reboot */ + /* Enabled Deep-Sleep mode */ + PCFR |= PCFR_DS; + + /* Low power mode */ + PCFR |= PCFR_OPDE; + + + /* 3.6.8.1 */ + while(!(OSCC & OSCC_OOK)) + {} + + /* disable GPIO reset, palm bootloader will hang us */ + //PCFR |= PCFR_GPR_EN | PCFR_OPDE; + PCFR &= PCFR_GPR_EN; + + return 0; +} + +static int palmld_resume(struct device *dev) +{ + /* Disabled Deep-Sleep mode ?? */ + PCFR &= PCFR_DS; + + /* Re-enable GPIO reset */ + PCFR |= PCFR_GPR_EN; /* !! DO NOT REMOVE !! THIS IS NECCESARY FOR ENABLE PALM RESET !! */ + + + /* Here are all of special to resume PalmOne LifeDrive */ + + /* Turn on LCD power */ +// SET_PALMZ72_GPIO(LCD_POWER,1); + /* Turn on USB power */ +// SET_PALMZ72_GPIO(USB_POWER,1); + + return 0; +} +#else +#define palmld_suspend NULL +#define palmld_resume NULL +#endif + +static void palmld_pxa_ll_pm_suspend(unsigned long resume_addr) +{ + /* For future */ return; } static void palmld_pxa_ll_pm_resume(void) { - /* - *addr_a0200000 = save_a0200000; - *addr_a0200004 = save_a0200004; - *addr_a0200008 = save_a0200008; - */ - - /* re-enable GPIO reset */ - PCFR |= PCFR_GPR_EN; + /* For future */ } struct pxa_ll_pm_ops palmld_ll_pm_ops = { - .suspend = palmld_pxa_ll_pm_suspend, - .resume = palmld_pxa_ll_pm_resume, + .suspend = palmld_pxa_ll_pm_suspend, + .resume = palmld_pxa_ll_pm_resume, }; + +static int (*pxa_pm_enter_orig)(suspend_state_t state); + +static int lifedrive_enter_suspend(suspend_state_t state) +{ + /* Here we should implement wakeup conditions + If we have none, just return 1 to continue + sleeping */ + int data = 0; + + /* Do not suspend on active keypress */ + pxa_pm_enter_orig(state); + + printk(KERN_NOTICE "Returning from sleep due to GPIOs 100-102 or 13\n"); + printk(KERN_NOTICE "RCNR = %u pm_save_data.rcnr = %u\n", RCNR, pm_save_data.rcnr); + printk(KERN_NOTICE "Keys pressed: %d\n", data); + pm_save_data.rcnr = 0; + return 0; +} +static int lifedrive_pxa_pm_enter(suspend_state_t state) +{ + pm_save_data.rcnr = 0; + pxa_pm_enter_orig(state); + while (lifedrive_enter_suspend(state)) + {} + return 0; +} + + +static struct pm_ops lifedrive_pm_ops = { + .pm_disk_mode = PM_DISK_FIRMWARE, + .prepare = pxa_pm_prepare, + .enter = lifedrive_pxa_pm_enter, + .finish = pxa_pm_finish, +}; + +extern struct pm_ops pxa_pm_ops; + +static int palmld_pm_probe(struct device *dev) +{ + printk(KERN_NOTICE "PalmOne LifeDrive power management driver registered\n"); + return 0; +} + +struct device_driver palmld_pm_driver = { + .name = "palmld-pm", + .bus = &platform_bus_type, + .probe = palmld_pm_probe, + .suspend = palmld_suspend, + .resume = palmld_resume, +}; + +static int __init palmld_pm_init(void) +{ +pxa_pm_enter_orig=pxa_pm_ops.enter; + pxa_pm_ops.enter = pxa_pm_enter_orig; + return driver_register(&palmld_pm_driver); +} + +static void __exit palmld_pm_exit(void) +{ + pxa_pm_ops.enter = pxa_pm_enter_orig; + driver_unregister(&palmld_pm_driver); +} + +module_init(palmld_pm_init); +module_exit(palmld_pm_exit); + +MODULE_AUTHOR("Jan Herman <2h...@se...>, Sergey Lapin <sla...@gm...>"); +MODULE_DESCRIPTION("PalmOne LifeDrive power management driver"); +MODULE_LICENSE("GPL"); Modified: linux4palm/linux/trunk/include/asm-arm/arch-pxa/palmld-gpio.h =================================================================== --- linux4palm/linux/trunk/include/asm-arm/arch-pxa/palmld-gpio.h 2007-03-18 19:56:23 UTC (rev 923) +++ linux4palm/linux/trunk/include/asm-arm/arch-pxa/palmld-gpio.h 2007-03-19 20:19:05 UTC (rev 924) @@ -41,6 +41,8 @@ #define GPIO_NR_PALMLD_ORANGE_LED 94 #define GPIO_NR_PALMLD_IDE_IRQ 95 +#define GPIO_NR_PALMLD_LCD_POWER 96 + #define GPIO_NR_PALMLD_KP_MKIN3 97 /* rotate-display, center, left */ #define GPIO_NR_PALMLD_IDE_RESET 98 Added: linux4palm/linux/trunk/include/asm-arm/arch-pxa/palmld-init.h =================================================================== --- linux4palm/linux/trunk/include/asm-arm/arch-pxa/palmld-init.h (rev 0) +++ linux4palm/linux/trunk/include/asm-arm/arch-pxa/palmld-init.h 2007-03-19 20:19:05 UTC (rev 924) @@ -0,0 +1,34 @@ +/* + * palmld-init.h + * + * Init values for PalmOne LifeDrive Handheld Computer + * + * Author: Marek Vasut <mar...@gm...> + * + * + * 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. + * + * + * + */ + +#ifndef _INCLUDE_PALMLD_INIT_H_ + +#define _INCLUDE_PALMLD_INIT_H_ + + +// BATTERY + +#define PALMLD_BAT_MAX_VOLTAGE 4000 // 4.00V current voltage at max charge as from PalmOS +#define PALMLD_BAT_MIN_VOLTAGE 3600 // 3.60V critical voltage as from Zlauncher +#define PALMLD_BAT_MAX_CURRENT 0 // unknokn +#define PALMLD_BAT_MIN_CURRENT 0 // unknown +#define PALMLD_BAT_MAX_CHARGE 1 // unknown +#define PALMLD_BAT_MIN_CHARGE 1 // unknown +#define PALMLD_BAT_MEASURE_DELAY (HZ * 1) +#define PALMLD_MAX_LIFE_MINS 240 // my LifeDrive on-life in minutes + + +#endif This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |