/* * linux/drivers/power/palmtx_battery.c * * Battery measurement code for Palm T|X Handheld computer * * based on tosa_battery.c * * Copyright (C) 2008 Marek Vasut * * 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 static DEFINE_MUTEX(bat_lock); static struct work_struct bat_work; struct mutex work_lock; int bat_status = POWER_SUPPLY_STATUS_DISCHARGING; static unsigned long palmtx_read_bat(struct power_supply *bat_ps) { return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data, WM97XX_AUX_ID3) * 1000 / 414; } static unsigned long palmtx_read_temp(struct power_supply *bat_ps) { return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data, WM97XX_AUX_ID2); } static int palmtx_bat_get_property(struct power_supply *bat_ps, enum power_supply_property psp, union power_supply_propval *val) { switch (psp) { case POWER_SUPPLY_PROP_STATUS: val->intval = bat_status; break; case POWER_SUPPLY_PROP_TECHNOLOGY: val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO; break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: val->intval = palmtx_read_bat(bat_ps); break; case POWER_SUPPLY_PROP_VOLTAGE_MAX: case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: val->intval = PALMTX_BAT_MAX_VOLTAGE; break; case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: val->intval = PALMTX_BAT_MIN_VOLTAGE; break; case POWER_SUPPLY_PROP_TEMP: val->intval = palmtx_read_temp(bat_ps); break; case POWER_SUPPLY_PROP_PRESENT: val->intval = 1; break; default: return -EINVAL; } return 0; } static void palmtx_bat_external_power_changed(struct power_supply *bat_ps) { schedule_work(&bat_work); } static char *status_text[] = { [POWER_SUPPLY_STATUS_UNKNOWN] = "Unknown", [POWER_SUPPLY_STATUS_CHARGING] = "Charging", [POWER_SUPPLY_STATUS_DISCHARGING] = "Discharging", }; static void palmtx_bat_update(struct power_supply *bat_ps) { int old_status = bat_status; mutex_lock(&work_lock); bat_status = gpio_get_value(GPIO_NR_PALMTX_POWER_DETECT) ? POWER_SUPPLY_STATUS_CHARGING : POWER_SUPPLY_STATUS_DISCHARGING; if (old_status != bat_status) { pr_debug("%s %s -> %s\n", bat_ps->name, status_text[old_status], status_text[bat_status]); power_supply_changed(bat_ps); } mutex_unlock(&work_lock); } static enum power_supply_property palmtx_bat_main_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_TECHNOLOGY, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_VOLTAGE_MAX, POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_PRESENT, }; struct power_supply bat_ps = { .name = "main-battery", .type = POWER_SUPPLY_TYPE_BATTERY, .properties = palmtx_bat_main_props, .num_properties = ARRAY_SIZE(palmtx_bat_main_props), .get_property = palmtx_bat_get_property, .external_power_changed = palmtx_bat_external_power_changed, .use_for_apm = 1, }; static void palmtx_bat_work(struct work_struct *work) { palmtx_bat_update(&bat_ps); } #ifdef CONFIG_PM static int palmtx_bat_suspend(struct platform_device *dev, pm_message_t state) { flush_scheduled_work(); return 0; } static int palmtx_bat_resume(struct platform_device *dev) { schedule_work(&bat_work); return 0; } #else #define palmtx_bat_suspend NULL #define palmtx_bat_resume NULL #endif static int __devinit palmtx_bat_probe(struct platform_device *dev) { int ret = 0; if (!machine_is_palmtx()) return -ENODEV; mutex_init(&work_lock); INIT_WORK(&bat_work, palmtx_bat_work); ret = power_supply_register(&dev->dev, &bat_ps); if (!ret) schedule_work(&bat_work); return ret; } static int __devexit palmtx_bat_remove(struct platform_device *dev) { power_supply_unregister(&bat_ps); return 0; } static struct platform_driver palmtx_bat_driver = { .driver.name = "wm97xx-battery", .driver.owner = THIS_MODULE, .probe = palmtx_bat_probe, .remove = __devexit_p(palmtx_bat_remove), .suspend = palmtx_bat_suspend, .resume = palmtx_bat_resume, }; static int __init palmtx_bat_init(void) { return platform_driver_register(&palmtx_bat_driver); } static void __exit palmtx_bat_exit(void) { platform_driver_unregister(&palmtx_bat_driver); } module_init(palmtx_bat_init); module_exit(palmtx_bat_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Marek Vasut "); MODULE_DESCRIPTION("Palm T|X battery driver");