/* * Battery driver for iPAQ blueangel * * Copyright 2007 Anton Vorontsov * Copyright 2005 SDG Systems, LLC * Copyright 2005 Aric D. Blumer * Copyright 2005 Phil Blundell * * 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. * * History: * 2007/02/14 Anton Vorontsov Use ds2760_battery driver, cleanup */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DRIVER_NAME "blueangel_power" #define POWER_NONE 0 #define POWER_AC 1 #define POWER_USB 2 extern struct platform_device blueangel_asic3; static struct ds2760_device_info ds2760_di; static int supply_status; static unsigned int ac_irq, usb_irq; struct timer_list isr_timer; DEFINE_LED_TRIGGER(charging_trig); DEFINE_LED_TRIGGER(chargefull_trig); static void blueangel_update_leds(const struct ds2760_device_info *di) { if (supply_status) { if (di->charge_status == BATTERY_STATUS_FULL) { led_trigger_event(chargefull_trig, LED_FULL); led_trigger_event(charging_trig, LED_OFF); return; } else if (di->charge_status == BATTERY_STATUS_CHARGING) { led_trigger_event(chargefull_trig, LED_OFF); led_trigger_event(charging_trig, LED_FULL); return; } } led_trigger_event(chargefull_trig, LED_OFF); led_trigger_event(charging_trig, LED_OFF); return; } static void blueangel_supply_changed(void) { /* if (supply_status & POWER_AC) { // If we're on AC, it doesn't matter if we're on USB or not, // use AC only SET_blueangel_GPIO_N(CHARGE_EN, 1); SET_blueangel_GPIO(USB_CHARGE_RATE, 0); } else if (supply_status & POWER_USB) { // We're not on AC, but we are on USB, so charge with that SET_blueangel_GPIO(USB_CHARGE_RATE, 1); SET_blueangel_GPIO_N(CHARGE_EN, 1); } else { // We're not on AC or USB, don't charge SET_blueangel_GPIO_N(CHARGE_EN, 0); SET_blueangel_GPIO(USB_CHARGE_RATE, 0); } */ return; } static int blueangel_update_supply_status(void) { unsigned int val; int ac_in, usb_in; val = asic3_get_gpio_status_d( &blueangel_asic3.dev ); ac_in = (val & (1<charge_status == BATTERY_STATUS_UNKNOWN) { /* ds2760_battery is about to suspend or resume. On suspend * we should turn off leds, and on resume we should update * supply status. */ int old_status = supply_status; blueangel_update_supply_status(); if (old_status != supply_status) blueangel_isr_timer_func(0); } blueangel_update_leds(di); return; } void blueangel_null_release(struct device *dev) { return; /* current platform_device api is weird */ } static struct ds2760_device_info ds2760_di = { .battery_info = { .name = "blueangel_primary", .id = "main", .main_battery = 1, .max_voltage = 3700, .min_voltage = 0, .max_current = 1490, .min_current = -1490, .min_charge = 0, }, .is_charge_power_supplied = blueangel_update_supply_status, .charge_callback = blueangel_charge_callback, }; static struct platform_device ds2760_pdev = { .name = "ds2760-battery", .dev = { .platform_data = &ds2760_di, .release = blueangel_null_release, }, }; static struct battery_adc_platform_data blueangel_backup_batt_params = { .battery_info = { .name = "blueangel_backup", .id = "backup", .max_voltage = 1400, .min_voltage = 1000, .max_current = 500, .min_current = 0, .min_charge = 0, .max_charge = 100, }, .voltage_pin = "ads7846-ssp:vaux", }; static struct platform_device blueangel_backup_batt = { .name = "adc-battery", .id = -1, .dev = { .platform_data = &blueangel_backup_batt_params, } }; static int blueangel_battery_init (void) { int ret; setup_timer(&isr_timer, blueangel_isr_timer_func, 1); ac_irq = asic3_irq_base(&blueangel_asic3.dev) + ASIC3_GPIOD_IRQ_BASE + GPIOD_AC_CHARGER_N; ret = request_irq (ac_irq, blueangel_attach_isr, IRQF_DISABLED, "blueangel AC Detect", NULL); if (ret) goto ac_irq_failed; usb_irq = asic3_irq_base(&blueangel_asic3.dev) + ASIC3_GPIOC_IRQ_BASE + GPIOC_USB_PUEN; ret = request_irq (usb_irq, blueangel_attach_isr, IRQF_DISABLED, "blueangel USB Detect", NULL); if (ret) goto usb_irq_failed; ret = platform_device_register(&ds2760_pdev); if (ret) goto platform_device_failed; ret = platform_device_register(&blueangel_backup_batt); /* Not being able to register backup battery is not fatal */ if (ret) printk(KERN_ERR DRIVER_NAME ": Could not register backup battery: err=%d\n", ret); led_trigger_register_simple("blueangel-chargefull", &chargefull_trig); led_trigger_register_hwtimer("blueangel-charging", &charging_trig); blueangel_isr_timer_func(0); goto success; platform_device_failed: printk (KERN_ERR "%s: failed to register device\n", __FUNCTION__); free_irq(usb_irq, NULL); usb_irq_failed: printk (KERN_ERR "%s: unable to grab USB in IRQ\n", __FUNCTION__); free_irq(ac_irq, NULL); ac_irq_failed: printk (KERN_ERR "%s: unable to grab AC in IRQ\n", __FUNCTION__); success: return ret; } static void blueangel_battery_exit(void) { led_trigger_unregister_simple(chargefull_trig); led_trigger_unregister_hwtimer(charging_trig); free_irq(ac_irq, NULL); free_irq(usb_irq, NULL); del_timer_sync(&isr_timer); platform_device_unregister(&ds2760_pdev); platform_device_unregister(&blueangel_backup_batt); return; } module_init(blueangel_battery_init); module_exit(blueangel_battery_exit); MODULE_LICENSE("GPL");