diff options
Diffstat (limited to 'meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/pda-power.patch')
-rw-r--r-- | meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/pda-power.patch | 3373 |
1 files changed, 0 insertions, 3373 deletions
diff --git a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/pda-power.patch b/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/pda-power.patch deleted file mode 100644 index face2f4ef..000000000 --- a/meta/packages/linux/linux-rp-2.6.23+2.6.24-rc0+git/pda-power.patch +++ /dev/null @@ -1,3373 +0,0 @@ ---- - arch/arm/Kconfig | 2 - drivers/Kconfig | 2 - drivers/Makefile | 1 - drivers/power/Kconfig | 70 +++++ - drivers/power/Makefile | 28 ++ - drivers/power/adc_battery.c | 278 +++++++++++++++++++++ - drivers/power/apm_power.c | 247 +++++++++++++++++++ - drivers/power/ds2760_battery.c | 475 +++++++++++++++++++++++++++++++++++++ - drivers/power/micro_battery.c | 257 ++++++++++++++++++++ - drivers/power/olpc_battery.c | 302 +++++++++++++++++++++++ - drivers/power/pda_power.c | 263 ++++++++++++++++++++ - drivers/power/pmu_battery.c | 215 ++++++++++++++++ - drivers/power/power_supply.h | 42 +++ - drivers/power/power_supply_core.c | 168 +++++++++++++ - drivers/power/power_supply_leds.c | 188 ++++++++++++++ - drivers/power/power_supply_sysfs.c | 289 ++++++++++++++++++++++ - drivers/power/simpad-battery.c | 242 ++++++++++++++++++ - include/linux/power_supply.h | 175 +++++++++++++ - 18 files changed, 3244 insertions(+) - -Index: linux-2.6.22/drivers/power/adc_battery.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.22/drivers/power/adc_battery.c 2007-08-23 12:26:28.000000000 +0200 -@@ -0,0 +1,278 @@ -+/* -+ * Copyright (c) 2007 Paul Sokolovsky -+ * -+ * 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. -+ * -+ */ -+ -+//#define DEBUG -+ -+#include <linux/module.h> -+#include <linux/interrupt.h> -+#include <linux/pm.h> -+#include <linux/delay.h> -+#include <linux/workqueue.h> -+#include <linux/platform_device.h> -+#include <linux/power_supply.h> -+#include <linux/adc.h> -+#include <linux/adc_battery.h> -+ -+#include <asm/irq.h> -+ -+#define PIN_NO_VOLT 0 -+#define PIN_NO_CURR 1 -+#define PIN_NO_TEMP 2 -+ -+struct battery_adc_priv { -+ struct power_supply batt_cdev; -+ -+ struct battery_adc_platform_data *pdata; -+ -+ struct adc_request req; -+ struct adc_sense pins[3]; -+ struct adc_sense last_good_pins[3]; -+ -+ struct workqueue_struct *wq; -+ struct delayed_work work; -+}; -+ -+/* -+ * Battery properties -+ */ -+ -+static int adc_battery_get_property(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ struct battery_adc_priv* drvdata = (struct battery_adc_priv*)psy; -+ int voltage; -+ -+ switch (psp) { -+ case POWER_SUPPLY_PROP_STATUS: -+ val->intval = drvdata->pdata->charge_status; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: -+ val->intval = drvdata->pdata->battery_info.voltage_max_design; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: -+ val->intval = drvdata->pdata->battery_info.voltage_min_design; -+ break; -+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: -+ val->intval = drvdata->pdata->battery_info.charge_full_design; -+ break; -+ case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN: -+ val->intval = drvdata->pdata->battery_info.charge_empty_design; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_NOW: -+ val->intval = drvdata->last_good_pins[PIN_NO_VOLT].value * drvdata->pdata->voltage_mult; -+ break; -+ case POWER_SUPPLY_PROP_CURRENT_NOW: -+ val->intval = drvdata->last_good_pins[PIN_NO_CURR].value * drvdata->pdata->current_mult; -+ break; -+ case POWER_SUPPLY_PROP_CHARGE_NOW: -+ /* We do calculations in mX, not uX, because todo it in uX we should use "long long"s, -+ * which is a mess (need to use do_div) when you need divide operation). */ -+ voltage = drvdata->last_good_pins[PIN_NO_VOLT].value * drvdata->pdata->voltage_mult; -+ val->intval = ((voltage/1000 - drvdata->pdata->battery_info.voltage_min_design/1000) * -+ (drvdata->pdata->battery_info.charge_full_design/1000 - -+ drvdata->pdata->battery_info.charge_empty_design/1000)) / -+ (drvdata->pdata->battery_info.voltage_max_design/1000 - -+ drvdata->pdata->battery_info.voltage_min_design/1000); -+ val->intval *= 1000; /* convert final result to uX */ -+ break; -+ case POWER_SUPPLY_PROP_TEMP: -+ val->intval = drvdata->last_good_pins[PIN_NO_TEMP].value * drvdata->pdata->temperature_mult / 1000; -+ break; -+ default: -+ return -EINVAL; -+ }; -+ return 0; -+} -+ -+/* -+ * Driver body -+ */ -+ -+static void adc_battery_query(struct battery_adc_priv *drvdata) -+{ -+ struct battery_adc_platform_data *pdata = drvdata->pdata; -+ int powered, charging; -+ -+ adc_request_sample(&drvdata->req); -+ -+ powered = power_supply_am_i_supplied(&drvdata->batt_cdev); -+ charging = pdata->is_charging ? pdata->is_charging() : -1; -+ -+ if (powered && charging) -+ pdata->charge_status = POWER_SUPPLY_STATUS_CHARGING; -+ else if (powered && !charging && charging != -1) -+ pdata->charge_status = POWER_SUPPLY_STATUS_FULL; -+ else -+ pdata->charge_status = POWER_SUPPLY_STATUS_DISCHARGING; -+ -+ /* Throw away invalid samples, this may happen soon after resume for example. */ -+ if (drvdata->pins[PIN_NO_VOLT].value > 0) { -+ memcpy(drvdata->last_good_pins, drvdata->pins, sizeof(drvdata->pins)); -+#ifdef DEBUG -+ printk("%d %d %d\n", drvdata->pins[PIN_NO_VOLT].value, -+ drvdata->pins[PIN_NO_CURR].value, -+ drvdata->pins[PIN_NO_TEMP].value); -+#endif -+ } -+} -+ -+static void adc_battery_charge_power_changed(struct power_supply *bat) -+{ -+ struct battery_adc_priv *drvdata = (struct battery_adc_priv*)bat; -+ cancel_delayed_work(&drvdata->work); -+ queue_delayed_work(drvdata->wq, &drvdata->work, 0); -+} -+ -+static void adc_battery_work_func(struct work_struct *work) -+{ -+ struct delayed_work *delayed_work = container_of(work, struct delayed_work, work); -+ struct battery_adc_priv *drvdata = container_of(delayed_work, struct battery_adc_priv, work); -+ -+ adc_battery_query(drvdata); -+ power_supply_changed(&drvdata->batt_cdev); -+ -+ queue_delayed_work(drvdata->wq, &drvdata->work, (5000 * HZ) / 1000); -+} -+ -+static int adc_battery_probe(struct platform_device *pdev) -+{ -+ int retval; -+ struct battery_adc_platform_data *pdata = pdev->dev.platform_data; -+ struct battery_adc_priv *drvdata; -+ int i, j; -+ enum power_supply_property props[] = { -+ POWER_SUPPLY_PROP_STATUS, -+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, -+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, -+ POWER_SUPPLY_PROP_VOLTAGE_NOW, -+ POWER_SUPPLY_PROP_CURRENT_NOW, -+ POWER_SUPPLY_PROP_CHARGE_NOW, -+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, -+ POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN, -+ POWER_SUPPLY_PROP_TEMP, -+ }; -+ -+ // Initialize ts data structure. -+ drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); -+ if (!drvdata) -+ return -ENOMEM; -+ -+ drvdata->batt_cdev.name = pdata->battery_info.name; -+ drvdata->batt_cdev.use_for_apm = pdata->battery_info.use_for_apm; -+ drvdata->batt_cdev.num_properties = ARRAY_SIZE(props); -+ drvdata->batt_cdev.get_property = adc_battery_get_property; -+ drvdata->batt_cdev.external_power_changed = -+ adc_battery_charge_power_changed; -+ -+ if (!pdata->voltage_pin) { -+ drvdata->batt_cdev.num_properties--; -+ props[3] = -1; -+ } -+ if (!pdata->current_pin) { -+ drvdata->batt_cdev.num_properties--; -+ props[4] = -1; -+ } -+ if (!pdata->temperature_pin) { -+ drvdata->batt_cdev.num_properties--; -+ props[8] = -1; -+ } -+ -+ drvdata->batt_cdev.properties = kmalloc( -+ sizeof(*drvdata->batt_cdev.properties) * -+ drvdata->batt_cdev.num_properties, GFP_KERNEL); -+ if (!drvdata->batt_cdev.properties) -+ return -ENOMEM; -+ -+ j = 0; -+ for (i = 0; i < ARRAY_SIZE(props); i++) { -+ if (props[i] == -1) -+ continue; -+ drvdata->batt_cdev.properties[j++] = props[i]; -+ } -+ -+ retval = power_supply_register(&pdev->dev, &drvdata->batt_cdev); -+ if (retval) { -+ printk("adc-battery: Error registering battery classdev"); -+ return retval; -+ } -+ -+ drvdata->req.senses = drvdata->pins; -+ drvdata->req.num_senses = ARRAY_SIZE(drvdata->pins); -+ drvdata->pins[PIN_NO_VOLT].name = pdata->voltage_pin; -+ drvdata->pins[PIN_NO_CURR].name = pdata->current_pin; -+ drvdata->pins[PIN_NO_TEMP].name = pdata->temperature_pin; -+ -+ adc_request_register(&drvdata->req); -+ -+ /* Here we assume raw values in mV */ -+ if (!pdata->voltage_mult) -+ pdata->voltage_mult = 1000; -+ /* Here we assume raw values in mA */ -+ if (!pdata->current_mult) -+ pdata->current_mult = 1000; -+ /* Here we assume raw values in 1/10 C */ -+ if (!pdata->temperature_mult) -+ pdata->temperature_mult = 1000; -+ -+ drvdata->pdata = pdata; -+ pdata->drvdata = drvdata; /* Seems ugly, we need better solution */ -+ -+ platform_set_drvdata(pdev, drvdata); -+ -+ // Load initial values ASAP -+ adc_battery_query(drvdata); -+ -+ // Still schedule next sampling soon -+ INIT_DELAYED_WORK(&drvdata->work, adc_battery_work_func); -+ drvdata->wq = create_workqueue(pdev->dev.bus_id); -+ if (!drvdata->wq) -+ return -ESRCH; -+ -+ queue_delayed_work(drvdata->wq, &drvdata->work, (5000 * HZ) / 1000); -+ -+ return retval; -+} -+ -+static int adc_battery_remove(struct platform_device *pdev) -+{ -+ struct battery_adc_priv *drvdata = platform_get_drvdata(pdev); -+ cancel_delayed_work(&drvdata->work); -+ destroy_workqueue(drvdata->wq); -+ power_supply_unregister(&drvdata->batt_cdev); -+ adc_request_unregister(&drvdata->req); -+ kfree(drvdata->batt_cdev.properties); -+ return 0; -+} -+ -+static struct platform_driver adc_battery_driver = { -+ .driver = { -+ .name = "adc-battery", -+ }, -+ .probe = adc_battery_probe, -+ .remove = adc_battery_remove, -+}; -+ -+static int __init adc_battery_init(void) -+{ -+ return platform_driver_register(&adc_battery_driver); -+} -+ -+static void __exit adc_battery_exit(void) -+{ -+ platform_driver_unregister(&adc_battery_driver); -+} -+ -+module_init(adc_battery_init) -+module_exit(adc_battery_exit) -+ -+MODULE_AUTHOR("Paul Sokolovsky"); -+MODULE_DESCRIPTION("Battery driver for ADC device"); -+MODULE_LICENSE("GPL"); -Index: linux-2.6.22/drivers/power/apm_power.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.22/drivers/power/apm_power.c 2007-08-23 12:13:52.000000000 +0200 -@@ -0,0 +1,247 @@ -+/* -+ * Copyright (c) 2007 Anton Vorontsov <cbou@mail.ru> -+ * Copyright (c) 2007 Eugeny Boger <eugenyboger@dgap.mipt.ru> -+ * -+ * Author: Eugeny Boger <eugenyboger@dgap.mipt.ru> -+ * -+ * Use consistent with the GNU GPL is permitted, -+ * provided that this copyright notice is -+ * preserved in its entirety in all copies and derived works. -+ */ -+ -+#include <linux/module.h> -+#include <linux/power_supply.h> -+#include <linux/apm-emulation.h> -+ -+#define PSY_PROP(psy, prop, val) psy->get_property(psy, \ -+ POWER_SUPPLY_PROP_##prop, val) -+ -+#define _MPSY_PROP(prop, val) main_battery->get_property(main_battery, \ -+ prop, val) -+ -+#define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val) -+ -+static struct power_supply *main_battery; -+ -+static void find_main_battery(void) -+{ -+ struct device *dev; -+ struct power_supply *bat, *batm; -+ union power_supply_propval full; -+ int max_charge = 0; -+ -+ main_battery = NULL; -+ batm = NULL; -+ list_for_each_entry(dev, &power_supply_class->devices, node) { -+ bat = dev_get_drvdata(dev); -+ /* If none of battery devices cantains 'use_for_apm' flag, -+ choice one with maximum design charge */ -+ if (!PSY_PROP(bat, CHARGE_FULL_DESIGN, &full)) { -+ if (full.intval > max_charge) { -+ batm = bat; -+ max_charge = full.intval; -+ } -+ } -+ -+ if (bat->use_for_apm) -+ main_battery = bat; -+ } -+ if (!main_battery) -+ main_battery = batm; -+ -+ return; -+} -+ -+static int calculate_time(int status) -+{ -+ union power_supply_propval charge_full, charge_empty; -+ union power_supply_propval charge, I; -+ -+ if (MPSY_PROP(CHARGE_FULL, &charge_full)) { -+ /* if battery can't report this property, use design value */ -+ if (MPSY_PROP(CHARGE_FULL_DESIGN, &charge_full)) -+ return -1; -+ } -+ -+ if (MPSY_PROP(CHARGE_EMPTY, &charge_empty)) { -+ /* if battery can't report this property, use design value */ -+ if (MPSY_PROP(CHARGE_EMPTY_DESIGN, &charge_empty)) -+ charge_empty.intval = 0; -+ } -+ -+ if (MPSY_PROP(CHARGE_AVG, &charge)) { -+ /* if battery can't report average value, use momentary */ -+ if (MPSY_PROP(CHARGE_NOW, &charge)) -+ return -1; -+ } -+ -+ if (MPSY_PROP(CURRENT_AVG, &I)) { -+ /* if battery can't report average value, use momentary */ -+ if (MPSY_PROP(CURRENT_NOW, &I)) -+ return -1; -+ } -+ -+ if (I.intval == 0) -+ return 0; -+ else if (status == POWER_SUPPLY_STATUS_CHARGING) -+ return ((charge.intval - charge_full.intval) * 60L) / -+ I.intval; -+ else -+ return -((charge.intval - charge_empty.intval) * 60L) / -+ I.intval; -+} -+ -+static int calculate_capacity(int using_charge) -+{ -+ enum power_supply_property full_prop, empty_prop; -+ enum power_supply_property full_design_prop, empty_design_prop; -+ enum power_supply_property now_prop, avg_prop; -+ union power_supply_propval empty, full, cur; -+ int ret; -+ -+ if (using_charge) { -+ full_prop = POWER_SUPPLY_PROP_CHARGE_FULL; -+ empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; -+ full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN; -+ empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN; -+ now_prop = POWER_SUPPLY_PROP_CHARGE_NOW; -+ avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG; -+ } -+ else { -+ full_prop = POWER_SUPPLY_PROP_ENERGY_FULL; -+ empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY; -+ full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN; -+ empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN; -+ now_prop = POWER_SUPPLY_PROP_ENERGY_NOW; -+ avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG; -+ } -+ -+ if (_MPSY_PROP(full_prop, &full)) { -+ /* if battery can't report this property, use design value */ -+ if (_MPSY_PROP(full_design_prop, &full)) -+ return -1; -+ } -+ -+ if (_MPSY_PROP(avg_prop, &cur)) { -+ /* if battery can't report average value, use momentary */ -+ if (_MPSY_PROP(now_prop, &cur)) -+ return -1; -+ } -+ -+ if (_MPSY_PROP(empty_prop, &empty)) { -+ /* if battery can't report this property, use design value */ -+ if (_MPSY_PROP(empty_design_prop, &empty)) -+ empty.intval = 0; -+ } -+ -+ if (full.intval - empty.intval) -+ ret = ((cur.intval - empty.intval) * 100L) / -+ (full.intval - empty.intval); -+ else -+ return -1; -+ -+ if (ret > 100) -+ return 100; -+ else if (ret < 0) -+ return 0; -+ -+ return ret; -+} -+ -+static void apm_battery_apm_get_power_status(struct apm_power_info *info) -+{ -+ union power_supply_propval status; -+ union power_supply_propval capacity, time_to_full, time_to_empty; -+ -+ down(&power_supply_class->sem); -+ find_main_battery(); -+ if (!main_battery) { -+ up(&power_supply_class->sem); -+ return; -+ } -+ -+ /* status */ -+ -+ if (MPSY_PROP(STATUS, &status)) -+ status.intval = POWER_SUPPLY_STATUS_UNKNOWN; -+ -+ /* ac line status */ -+ -+ if ((status.intval == POWER_SUPPLY_STATUS_CHARGING) || -+ (status.intval == POWER_SUPPLY_STATUS_NOT_CHARGING) || -+ (status.intval == POWER_SUPPLY_STATUS_FULL)) -+ info->ac_line_status = APM_AC_ONLINE; -+ else -+ info->ac_line_status = APM_AC_OFFLINE; -+ -+ /* battery life (i.e. capacity, in percents) */ -+ -+ if (MPSY_PROP(CAPACITY, &capacity) == 0) -+ info->battery_life = capacity.intval; -+ else { -+ /* try calculate using energy */ -+ info->battery_life = calculate_capacity(0); -+ /* if failed try calculate using charge instead */ -+ if (info->battery_life == -1) -+ info->battery_life = calculate_capacity(1); -+ } -+ -+ /* charging status */ -+ -+ if (status.intval == POWER_SUPPLY_STATUS_CHARGING) -+ info->battery_status = APM_BATTERY_STATUS_CHARGING; -+ else { -+ if (info->battery_life > 50) -+ info->battery_status = APM_BATTERY_STATUS_HIGH; -+ else if (info->battery_life > 5) -+ info->battery_status = APM_BATTERY_STATUS_LOW; -+ else -+ info->battery_status = APM_BATTERY_STATUS_CRITICAL; -+ } -+ info->battery_flag = info->battery_status; -+ -+ /* time */ -+ -+ info->units = APM_UNITS_MINS; -+ -+ if (status.intval == POWER_SUPPLY_STATUS_CHARGING) { -+ if (MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full)) { -+ if (MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full)) -+ info->time = calculate_time(status.intval); -+ else -+ info->time = time_to_full.intval / 60; -+ } -+ } -+ else { -+ if (MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty)) { -+ if (MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty)) -+ info->time = calculate_time(status.intval); -+ else -+ info->time = time_to_empty.intval / 60; -+ } -+ } -+ -+ up(&power_supply_class->sem); -+ return; -+} -+ -+static int __init apm_battery_init(void) -+{ -+ printk(KERN_INFO "APM Battery Driver\n"); -+ -+ apm_get_power_status = apm_battery_apm_get_power_status; -+ return 0; -+} -+ -+static void __exit apm_battery_exit(void) -+{ -+ apm_get_power_status = NULL; -+ return; -+} -+ -+module_init(apm_battery_init); -+module_exit(apm_battery_exit); -+ -+MODULE_AUTHOR("Eugeny Boger <eugenyboger@dgap.mipt.ru>"); -+MODULE_DESCRIPTION("APM emulation driver for battery monitoring class"); -+MODULE_LICENSE("GPL"); -Index: linux-2.6.22/drivers/power/ds2760_battery.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.22/drivers/power/ds2760_battery.c 2007-08-23 12:13:52.000000000 +0200 -@@ -0,0 +1,475 @@ -+/* -+ * Driver for batteries with DS2760 chips inside. -+ * -+ * Copyright (c) 2007 Anton Vorontsov -+ * 2004-2007 Matt Reimer -+ * 2004 Szabolcs Gyurko -+ * -+ * Use consistent with the GNU GPL is permitted, -+ * provided that this copyright notice is -+ * preserved in its entirety in all copies and derived works. -+ * -+ * Author: Anton Vorontsov <cbou@mail.ru> -+ * February 2007 -+ * -+ * Matt Reimer <mreimer@vpop.net> -+ * April 2004, 2005, 2007 -+ * -+ * Szabolcs Gyurko <szabolcs.gyurko@tlt.hu> -+ * September 2004 -+ */ -+ -+#include <linux/module.h> -+#include <linux/param.h> -+#include <linux/jiffies.h> -+#include <linux/workqueue.h> -+#include <linux/pm.h> -+#include <linux/platform_device.h> -+#include <linux/power_supply.h> -+ -+#include "../w1/w1.h" -+#include "../w1/slaves/w1_ds2760.h" -+ -+struct ds2760_device_info { -+ struct device *dev; -+ -+ /* DS2760 data, valid after calling ds2760_battery_read_status() */ -+ unsigned long update_time; /* jiffies when data read */ -+ char raw[DS2760_DATA_SIZE]; /* raw DS2760 data */ -+ int voltage_raw; /* units of 4.88 mV */ -+ int voltage_uV; /* units of uV */ -+ int current_raw; /* units of 0.625 mA */ -+ int current_uA; /* units of uA */ -+ int accum_current_raw; /* units of 0.25 mAh */ -+ int accum_current_uAh; /* units of uAh */ -+ int temp_raw; /* units of 0.125 C */ -+ int temp_C; /* units of 0.1 C */ -+ int rated_capacity; /* units of uAh */ -+ int rem_capacity; /* percentage */ -+ int full_active_uAh; /* units of uAh */ -+ int empty_uAh; /* units of uAh */ -+ int life_sec; /* units of seconds */ -+ int charge_status; /* POWER_SUPPLY_STATUS_* */ -+ -+ int full_counter; -+ struct power_supply bat; -+ struct device *w1_dev; -+ struct workqueue_struct *monitor_wqueue; -+ struct delayed_work monitor_work; -+}; -+ -+static unsigned int cache_time = 1000; -+module_param(cache_time, uint, 0644); -+MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); -+ -+/* Some batteries have their rated capacity stored a N * 10 mAh, while -+ * others use an index into this table. */ -+static int rated_capacities[] = { -+ 0, -+ 920, /* Samsung */ -+ 920, /* BYD */ -+ 920, /* Lishen */ -+ 920, /* NEC */ -+ 1440, /* Samsung */ -+ 1440, /* BYD */ -+ 1440, /* Lishen */ -+ 1440, /* NEC */ -+ 2880, /* Samsung */ -+ 2880, /* BYD */ -+ 2880, /* Lishen */ -+ 2880 /* NEC */ -+}; -+ -+/* array is level at temps 0C, 10C, 20C, 30C, 40C -+ * temp is in Celsius */ -+static int battery_interpolate(int array[], int temp) -+{ -+ int index, dt; -+ -+ if (temp <= 0) -+ return array[0]; -+ if (temp >= 40) -+ return array[4]; -+ -+ index = temp / 10; -+ dt = temp % 10; -+ -+ return array[index] + (((array[index + 1] - array[index]) * dt) / 10); -+} -+ -+static int ds2760_battery_read_status(struct ds2760_device_info *di) -+{ -+ int ret, i, start, count, scale[5]; -+ -+ if (di->update_time && time_before(jiffies, di->update_time + -+ msecs_to_jiffies(cache_time))) -+ return 0; -+ -+ /* The first time we read the entire contents of SRAM/EEPROM, -+ * but after that we just read the interesting bits that change. */ -+ if (di->update_time == 0) { -+ start = 0; -+ count = DS2760_DATA_SIZE; -+ } -+ else { -+ start = DS2760_VOLTAGE_MSB; -+ count = DS2760_TEMP_LSB - start + 1; -+ } -+ -+ ret = w1_ds2760_read(di->w1_dev, di->raw + start, start, count); -+ if (ret != count) { -+ dev_warn(di->dev, "call to w1_ds2760_read failed (0x%p)\n", -+ di->w1_dev); -+ return 1; -+ } -+ -+ di->update_time = jiffies; -+ -+ /* DS2760 reports voltage in units of 4.88mV, but the battery class -+ * reports in units of uV, so convert by multiplying by 4880. */ -+ di->voltage_raw = (di->raw[DS2760_VOLTAGE_MSB] << 3) | -+ (di->raw[DS2760_VOLTAGE_LSB] >> 5); -+ di->voltage_uV = di->voltage_raw * 4880; -+ -+ /* DS2760 reports current in signed units of 0.625mA, but the battery -+ * class reports in units of uA, so convert by multiplying by 625. */ -+ di->current_raw = -+ (((signed char)di->raw[DS2760_CURRENT_MSB]) << 5) | -+ (di->raw[DS2760_CURRENT_LSB] >> 3); -+ di->current_uA = di->current_raw * 625; -+ -+ /* DS2760 reports accumulated current in signed units of 0.25mAh. */ -+ di->accum_current_raw = -+ (((signed char)di->raw[DS2760_CURRENT_ACCUM_MSB]) << 8) | -+ di->raw[DS2760_CURRENT_ACCUM_LSB]; -+ di->accum_current_uAh = di->accum_current_raw * 250; -+ -+ /* DS2760 reports temperature in signed units of 0.125C, but the -+ * battery class reports in units of 1/10 C, so we convert by -+ * multiplying by .125 * 10 = 1.25. */ -+ di->temp_raw = (((signed char)di->raw[DS2760_TEMP_MSB]) << 3) | -+ (di->raw[DS2760_TEMP_LSB] >> 5); -+ di->temp_C = di->temp_raw + (di->temp_raw / 4); -+ -+ /* At least some battery monitors (e.g. HP iPAQ) store the battery's -+ * maximum rated capacity. */ -+ if (di->raw[DS2760_RATED_CAPACITY] < ARRAY_SIZE(rated_capacities)) -+ di->rated_capacity = rated_capacities[ -+ (unsigned int)di->raw[DS2760_RATED_CAPACITY]]; -+ else -+ di->rated_capacity = di->raw[DS2760_RATED_CAPACITY] * 10; -+ -+ di->rated_capacity *= 1000; /* convert to uAh */ -+ -+ /* Calculate the full level at the present temperature. */ -+ di->full_active_uAh = di->raw[DS2760_ACTIVE_FULL] << 8 | -+ di->raw[DS2760_ACTIVE_FULL + 1]; -+ -+ scale[0] = di->raw[DS2760_ACTIVE_FULL] << 8 | -+ di->raw[DS2760_ACTIVE_FULL + 1]; -+ for (i = 1; i < 5; i++) -+ scale[i] = scale[i - 1] + di->raw[DS2760_ACTIVE_FULL + 2 + i]; -+ -+ di->full_active_uAh = battery_interpolate(scale, di->temp_C / 10); -+ di->full_active_uAh *= 1000; /* convert to uAh */ -+ -+ /* Calculate the empty level at the present temperature. */ -+ scale[4] = di->raw[DS2760_ACTIVE_EMPTY + 4]; -+ for (i = 3; i >= 0; i--) -+ scale[i] = scale[i + 1] + di->raw[DS2760_ACTIVE_EMPTY + i]; -+ -+ di->empty_uAh = battery_interpolate(scale, di->temp_C / 10); -+ di->empty_uAh *= 1000; /* convert to uAh */ -+ -+ /* From Maxim Application Note 131: remaining capacity = -+ * ((ICA - Empty Value) / (Full Value - Empty Value)) x 100% */ -+ di->rem_capacity = ((di->accum_current_uAh - di->empty_uAh) * 100L) / -+ (di->full_active_uAh - di->empty_uAh); -+ -+ if (di->rem_capacity < 0) -+ di->rem_capacity = 0; -+ if (di->rem_capacity > 100) -+ di->rem_capacity = 100; -+ -+ if (di->current_uA) -+ di->life_sec = -((di->accum_current_uAh - di->empty_uAh) * -+ 3600L) / di->current_uA; -+ else -+ di->life_sec = 0; -+ -+ return 0; -+} -+ -+static void ds2760_battery_update_status(struct ds2760_device_info *di) -+{ -+ int old_charge_status = di->charge_status; -+ -+ ds2760_battery_read_status(di); -+ -+ if (di->charge_status == POWER_SUPPLY_STATUS_UNKNOWN) -+ di->full_counter = 0; -+ -+ if (power_supply_am_i_supplied(&di->bat)) { -+ if (di->current_uA > 10000) { -+ di->charge_status = POWER_SUPPLY_STATUS_CHARGING; -+ di->full_counter = 0; -+ } -+ else if (di->current_uA < -5000) { -+ if (di->charge_status != POWER_SUPPLY_STATUS_NOT_CHARGING) -+ dev_notice(di->dev, "not enough power to " -+ "charge\n"); -+ di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING; -+ di->full_counter = 0; -+ } -+ else if (di->current_uA < 10000 && -+ di->charge_status != POWER_SUPPLY_STATUS_FULL) { -+ -+ /* Don't consider the battery to be full unless -+ * we've seen the current < 10 mA at least two -+ * consecutive times. */ -+ -+ di->full_counter++; -+ -+ if (di->full_counter < 2) -+ di->charge_status = POWER_SUPPLY_STATUS_CHARGING; -+ else { -+ unsigned char acr[2]; -+ int acr_val; -+ -+ /* acr is in units of 0.25 mAh */ -+ acr_val = di->full_active_uAh * 4L / 1000; -+ -+ acr[0] = acr_val >> 8; -+ acr[1] = acr_val & 0xff; -+ -+ if (w1_ds2760_write(di->w1_dev, acr, -+ DS2760_CURRENT_ACCUM_MSB, 2) < 2) -+ dev_warn(di->dev, -+ "ACR reset failed\n"); -+ -+ di->charge_status = POWER_SUPPLY_STATUS_FULL; -+ } -+ } -+ } -+ else { -+ di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING; -+ di->full_counter = 0; -+ } -+ -+ if (di->charge_status != old_charge_status) -+ power_supply_changed(&di->bat); -+ -+ return; -+} -+ -+static void ds2760_battery_work(struct work_struct *work) -+{ -+ struct ds2760_device_info *di = container_of(work, -+ struct ds2760_device_info, monitor_work.work); -+ const int interval = HZ * 60; -+ -+ dev_dbg(di->dev, "%s\n", __FUNCTION__); -+ -+ ds2760_battery_update_status(di); -+ queue_delayed_work(di->monitor_wqueue, &di->monitor_work, interval); -+ -+ return; -+} -+ -+#define to_ds2760_device_info(x) container_of((x), struct ds2760_device_info, \ -+ bat); -+ -+static void ds2760_battery_external_power_changed(struct power_supply *psy) -+{ -+ struct ds2760_device_info *di = to_ds2760_device_info(psy); -+ -+ dev_dbg(di->dev, "%s\n", __FUNCTION__); -+ -+ cancel_delayed_work(&di->monitor_work); -+ queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ/10); -+ -+ return; -+} -+ -+static int ds2760_battery_get_property(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ struct ds2760_device_info *di = to_ds2760_device_info(psy); -+ -+ switch (psp) { -+ case POWER_SUPPLY_PROP_STATUS: -+ val->intval = di->charge_status; -+ return 0; -+ default: -+ break; -+ } -+ -+ ds2760_battery_read_status(di); -+ -+ switch (psp) { -+ case POWER_SUPPLY_PROP_VOLTAGE_NOW: -+ val->intval = di->voltage_uV; -+ break; -+ case POWER_SUPPLY_PROP_CURRENT_NOW: -+ val->intval = di->current_uA; -+ break; -+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: -+ val->intval = di->rated_capacity; -+ break; -+ case POWER_SUPPLY_PROP_CHARGE_FULL: -+ val->intval = di->full_active_uAh; -+ break; -+ case POWER_SUPPLY_PROP_CHARGE_EMPTY: -+ val->intval = di->empty_uAh; -+ break; -+ case POWER_SUPPLY_PROP_CHARGE_NOW: -+ val->intval = di->accum_current_uAh; -+ break; -+ case POWER_SUPPLY_PROP_TEMP: -+ val->intval = di->temp_C; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static enum power_supply_property ds2760_battery_props[] = { -+ POWER_SUPPLY_PROP_STATUS, -+ POWER_SUPPLY_PROP_VOLTAGE_NOW, -+ POWER_SUPPLY_PROP_CURRENT_NOW, -+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, -+ POWER_SUPPLY_PROP_CHARGE_FULL, -+ POWER_SUPPLY_PROP_CHARGE_EMPTY, -+ POWER_SUPPLY_PROP_CHARGE_NOW, -+ POWER_SUPPLY_PROP_TEMP, -+}; -+ -+static int ds2760_battery_probe(struct platform_device *pdev) -+{ -+ int retval = 0; -+ struct ds2760_device_info *di; -+ struct ds2760_platform_data *pdata; -+ -+ di = kzalloc(sizeof(*di), GFP_KERNEL); -+ if (!di) { -+ retval = -ENOMEM; -+ goto di_alloc_failed; -+ } -+ -+ platform_set_drvdata(pdev, di); -+ -+ pdata = pdev->dev.platform_data; -+ di->dev = &pdev->dev; -+ di->w1_dev = pdev->dev.parent; -+ di->bat.name = pdev->dev.bus_id; -+ di->bat.type = POWER_SUPPLY_TYPE_BATTERY; -+ di->bat.properties = ds2760_battery_props; -+ di->bat.num_properties = ARRAY_SIZE(ds2760_battery_props); -+ di->bat.get_property = ds2760_battery_get_property; -+ di->bat.external_power_changed = -+ ds2760_battery_external_power_changed; -+ di->bat.use_for_apm = 1; -+ -+ di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; -+ -+ retval = power_supply_register(&pdev->dev, &di->bat); -+ if (retval) { -+ dev_err(di->dev, "failed to register battery"); -+ goto batt_failed; -+ } -+ -+ INIT_DELAYED_WORK(&di->monitor_work, ds2760_battery_work); -+ di->monitor_wqueue = create_singlethread_workqueue(pdev->dev.bus_id); -+ if (!di->monitor_wqueue) { -+ retval = -ESRCH; -+ goto workqueue_failed; -+ } -+ queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ * 1); -+ -+ goto success; -+ -+workqueue_failed: -+ power_supply_unregister(&di->bat); -+batt_failed: -+ kfree(di); -+di_alloc_failed: -+success: -+ return retval; -+} -+ -+static int ds2760_battery_remove(struct platform_device *pdev) -+{ -+ struct ds2760_device_info *di = platform_get_drvdata(pdev); -+ -+ cancel_rearming_delayed_workqueue(di->monitor_wqueue, -+ &di->monitor_work); -+ destroy_workqueue(di->monitor_wqueue); -+ power_supply_unregister(&di->bat); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+ -+static int ds2760_battery_suspend(struct platform_device *pdev, -+ pm_message_t state) -+{ -+ struct ds2760_device_info *di = platform_get_drvdata(pdev); -+ -+ di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; -+ -+ return 0; -+} -+ -+static int ds2760_battery_resume(struct platform_device *pdev) -+{ -+ struct ds2760_device_info *di = platform_get_drvdata(pdev); -+ -+ di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN; -+ power_supply_changed(&di->bat); -+ -+ cancel_delayed_work(&di->monitor_work); -+ queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ); -+ -+ return 0; -+} -+ -+#else -+ -+#define ds2760_battery_suspend NULL -+#define ds2760_battery_resume NULL -+ -+#endif /* CONFIG_PM */ -+ -+static struct platform_driver ds2760_battery_driver = { -+ .driver = { -+ .name = "ds2760-battery", -+ }, -+ .probe = ds2760_battery_probe, -+ .remove = ds2760_battery_remove, -+ .suspend = ds2760_battery_suspend, -+ .resume = ds2760_battery_resume, -+}; -+ -+static int __init ds2760_battery_init(void) -+{ -+ return platform_driver_register(&ds2760_battery_driver); -+} -+ -+static void __exit ds2760_battery_exit(void) -+{ -+ platform_driver_unregister(&ds2760_battery_driver); -+ return; -+} -+ -+module_init(ds2760_battery_init); -+module_exit(ds2760_battery_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, " -+ "Matt Reimer <mreimer@vpop.net>, " -+ "Anton Vorontsov <cbou@mail.ru>"); -+MODULE_DESCRIPTION("ds2760 battery driver"); -Index: linux-2.6.22/drivers/power/Kconfig -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.22/drivers/power/Kconfig 2007-08-23 12:13:52.000000000 +0200 -@@ -0,0 +1,70 @@ -+menuconfig POWER_SUPPLY -+ tristate "Power supply class support" -+ help -+ Say Y here to enable power supply class support. This allows -+ power supply (batteries, AC, USB) monitoring by userspace -+ via sysfs and uevent (if available) and/or APM kernel interface -+ (if selected below). -+ -+if POWER_SUPPLY -+ -+config POWER_SUPPLY_DEBUG -+ bool "Power supply debug" -+ help -+ Say Y here to enable debugging messages for power supply class -+ and drivers. -+ -+config PDA_POWER -+ tristate "Generic PDA/phone power driver" -+ help -+ Say Y here to enable generic power driver for PDAs and phones with -+ one or two external power supplies (AC/USB) connected to main and -+ backup batteries, and optional builtin charger. -+ -+config APM_POWER -+ tristate "APM emulation for class batteries" -+ depends on APM_EMULATION -+ help -+ Say Y here to enable support APM status emulation using -+ battery class devices. -+ -+config BATTERY_DS2760 -+ tristate "DS2760 battery driver (HP iPAQ & others)" -+ select W1 -+ select W1_SLAVE_DS2760 -+ help -+ Say Y here to enable support for batteries with ds2760 chip. -+ -+config BATTERY_PMU -+ tristate "Apple PMU battery" -+ depends on ADB_PMU -+ help -+ Say Y here to expose battery information on Apple machines -+ through the generic battery class. -+ -+config BATTERY_OLPC -+ tristate "One Laptop Per Child battery" -+ depends on X86_32 -+ help -+ Say Y to enable support for the battery on the OLPC laptop. -+ -+# drivers below are not in battery2-2.6 tree -+ -+config ADC_BATTERY -+ tristate "Generic ADC battery driver" -+ depends on ADC && POWER_SUPPLY -+ help -+ Say Y here to enable support for battery monitoring using generic ADC device. -+ -+config IPAQ_MICRO_BATTERY -+ tristate "HP iPAQ Micro ASIC battery driver" -+ depends on IPAQ_MICRO && POWER_SUPPLY -+ help -+ Choose this option if you want to monitor battery status on -+ Compaq/HP iPAQ h3100 h3600 -+ -+config MCP_UCB1x00_SIMPAD_BATTERY -+ tristate "SIMpad Battery Reading Support" -+ depends on MCP_UCB1x00 && POWER_SUPPLY -+ -+endif # POWER_SUPPLY -Index: linux-2.6.22/drivers/power/Makefile -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.22/drivers/power/Makefile 2007-08-23 12:13:52.000000000 +0200 -@@ -0,0 +1,28 @@ -+power_supply-objs := power_supply_core.o -+ -+ifeq ($(CONFIG_SYSFS),y) -+power_supply-objs += power_supply_sysfs.o -+endif -+ -+ifeq ($(CONFIG_LEDS_TRIGGERS),y) -+power_supply-objs += power_supply_leds.o -+endif -+ -+ifeq ($(CONFIG_POWER_SUPPLY_DEBUG),y) -+EXTRA_CFLAGS += -DDEBUG -+endif -+ -+obj-$(CONFIG_POWER_SUPPLY) += power_supply.o -+ -+obj-$(CONFIG_PDA_POWER) += pda_power.o -+obj-$(CONFIG_APM_POWER) += apm_power.o -+ -+obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o -+obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o -+obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o -+ -+# drivers below are not in battery2-2.6 tree -+ -+obj-$(CONFIG_ADC_BATTERY) += adc_battery.o -+obj-$(CONFIG_IPAQ_MICRO_BATTERY) += micro_battery.o -+obj-$(CONFIG_MCP_UCB1x00_SIMPAD_BATTERY) += simpad-battery.o -Index: linux-2.6.22/drivers/power/micro_battery.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.22/drivers/power/micro_battery.c 2007-08-23 12:25:20.000000000 +0200 -@@ -0,0 +1,257 @@ -+/* -+ * 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. -+ * -+ * h3600 atmel micro companion support, battery subdevice -+ * based on previous kernel 2.4 version -+ * Author : Alessandro Gardich <gremlin@gremlin.it> -+ * -+ */ -+ -+ -+#include <linux/module.h> -+#include <linux/version.h> -+ -+#include <linux/init.h> -+#include <linux/fs.h> -+#include <linux/interrupt.h> -+#include <linux/sched.h> -+#include <linux/pm.h> -+#include <linux/sysctl.h> -+#include <linux/proc_fs.h> -+#include <linux/delay.h> -+#include <linux/device.h> -+#include <linux/power_supply.h> -+#include <linux/platform_device.h> -+#include <linux/timer.h> -+ -+#include <asm/arch/hardware.h> -+ -+#include <asm/arch/h3600.h> -+#include <asm/arch/SA-1100.h> -+ -+#include <asm/hardware/micro.h> -+ -+#define BATT_PERIOD 10*HZ -+ -+#define H3600_BATT_STATUS_HIGH 0x01 -+#define H3600_BATT_STATUS_LOW 0x02 -+#define H3600_BATT_STATUS_CRITICAL 0x04 -+#define H3600_BATT_STATUS_CHARGING 0x08 -+#define H3600_BATT_STATUS_CHARGEMAIN 0x10 -+#define H3600_BATT_STATUS_DEAD 0x20 /* Battery will not charge */ -+#define H3600_BATT_STATUS_NOTINSTALLED 0x20 /* For expansion pack batteries */ -+#define H3600_BATT_STATUS_FULL 0x40 /* Battery fully charged (and connected to AC) */ -+#define H3600_BATT_STATUS_NOBATTERY 0x80 -+#define H3600_BATT_STATUS_UNKNOWN 0xff -+ -+ -+//static struct power_supply_dev *micro_battery; -+ -+static micro_private_t *p_micro; -+ -+struct timer_list batt_timer; -+ -+struct { -+ int ac; -+ int update_time; -+ int chemistry; -+ int voltage; -+ int temperature; -+ int flag; -+} micro_battery; -+ -+static void micro_battery_receive (int len, unsigned char *data) { -+ if (0) { -+ printk(KERN_ERR "h3600_battery - AC = %02x\n", data[0]); -+ printk(KERN_ERR "h3600_battery - BAT1 chemistry = %02x\n", data[1]); -+ printk(KERN_ERR "h3600_battery - BAT1 voltage = %d %02x%02x\n", (data[3]<<8)+data[2], data[2], data[3]); -+ printk(KERN_ERR "h3600_battery - BAT1 status = %02x\n", data[4]); -+ } -+ -+ micro_battery.ac = data[0]; -+ micro_battery.chemistry = data[1]; -+ micro_battery.voltage = ((((unsigned short)data[3]<<8)+data[2]) * 5000L ) * 1000 / 1024; -+ micro_battery.flag = data[4]; -+ -+ if (len == 9) { -+ if (0) { -+ printk(KERN_ERR "h3600_battery - BAT2 chemistry = %02x\n", data[5]); -+ printk(KERN_ERR "h3600_battery - BAT2 voltage = %d %02x%02x\n", (data[7]<<8)+data[6], data[6], data[7]); -+ printk(KERN_ERR "h3600_battery - BAT2 status = %02x\n", data[8]); -+ } -+ } -+} -+ -+static void micro_temperature_receive (int len, unsigned char *data) { -+ micro_battery.temperature = ((unsigned short)data[1]<<8)+data[0]; -+} -+ -+void h3600_battery_read_status(unsigned long data) { -+ -+ if (++data % 2) -+ h3600_micro_tx_msg(0x09,0,NULL); -+ else -+ h3600_micro_tx_msg(0x06,0,NULL); -+ -+ batt_timer.expires += BATT_PERIOD; -+ batt_timer.data = data; -+ -+ add_timer(&batt_timer); -+} -+ -+int get_capacity(struct power_supply *b) { -+ switch (micro_battery.flag) { -+ case H3600_BATT_STATUS_HIGH : return 100; break; -+ case H3600_BATT_STATUS_LOW : return 50; break; -+ case H3600_BATT_STATUS_CRITICAL : return 5; break; -+ default: break; -+ } -+ return 0; -+} -+ -+int get_status(struct power_supply *b) { -+ -+ if (micro_battery.flag == H3600_BATT_STATUS_UNKNOWN) -+ return POWER_SUPPLY_STATUS_UNKNOWN; -+ -+ if (micro_battery.flag & H3600_BATT_STATUS_FULL) -+ return POWER_SUPPLY_STATUS_FULL; -+ -+ if ((micro_battery.flag & H3600_BATT_STATUS_CHARGING) || -+ (micro_battery.flag & H3600_BATT_STATUS_CHARGEMAIN)) -+ return POWER_SUPPLY_STATUS_CHARGING; -+ -+ return POWER_SUPPLY_STATUS_DISCHARGING; -+} -+ -+static int micro_batt_get_property(struct power_supply *b, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ switch (psp) { -+ case POWER_SUPPLY_PROP_STATUS: -+ val->intval = get_status(b); -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: -+ val->intval = 4700000; -+ break; -+ case POWER_SUPPLY_PROP_CAPACITY: -+ val->intval = get_capacity(b); -+ break; -+ case POWER_SUPPLY_PROP_TEMP: -+ val->intval = micro_battery.temperature; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_NOW: -+ val->intval = micro_battery.voltage; -+ break; -+ default: -+ return -EINVAL; -+ }; -+ -+ return 0; -+} -+ -+static enum power_supply_property micro_batt_props[] = { -+ POWER_SUPPLY_PROP_STATUS, -+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, -+ POWER_SUPPLY_PROP_CAPACITY, -+ POWER_SUPPLY_PROP_TEMP, -+ POWER_SUPPLY_PROP_VOLTAGE_NOW, -+}; -+ -+static struct power_supply h3600_battery = { -+ .name = "main-battery", -+ .properties = micro_batt_props, -+ .num_properties = ARRAY_SIZE(micro_batt_props), -+ .get_property = micro_batt_get_property, -+ .use_for_apm = 1, -+}; -+ -+static int micro_batt_probe (struct platform_device *pdev) -+{ -+ if (1) printk(KERN_ERR "micro battery probe : begin\n"); -+ -+ power_supply_register(&pdev->dev, &h3600_battery); -+ -+ { /*--- callback ---*/ -+ p_micro = platform_get_drvdata(pdev); -+ spin_lock(p_micro->lock); -+ p_micro->h_batt = micro_battery_receive; -+ p_micro->h_temp = micro_temperature_receive; -+ spin_unlock(p_micro->lock); -+ } -+ -+ { /*--- timer ---*/ -+ init_timer(&batt_timer); -+ batt_timer.expires = jiffies + BATT_PERIOD; -+ batt_timer.data = 0; -+ batt_timer.function = h3600_battery_read_status; -+ -+ add_timer(&batt_timer); -+ } -+ -+ if (1) printk(KERN_ERR "micro battery probe : end\n"); -+ return 0; -+} -+ -+static int micro_batt_remove (struct platform_device *pdev) -+{ -+ power_supply_unregister(&h3600_battery); -+ { /*--- callback ---*/ -+ init_timer(&batt_timer); -+ p_micro->h_batt = NULL; -+ p_micro->h_temp = NULL; -+ spin_unlock(p_micro->lock); -+ } -+ { /*--- timer ---*/ -+ del_timer_sync(&batt_timer); -+ } -+ return 0; -+} -+ -+static int micro_batt_suspend ( struct platform_device *pdev, pm_message_t state) -+{ -+ { /*--- timer ---*/ -+ del_timer(&batt_timer); -+ } -+ return 0; -+} -+ -+static int micro_batt_resume ( struct platform_device *pdev) -+{ -+ { /*--- timer ---*/ -+ add_timer(&batt_timer); -+ } -+ return 0; -+} -+ -+struct platform_driver micro_batt_device_driver = { -+ .driver = { -+ .name = "h3600-micro-battery", -+ }, -+ .probe = micro_batt_probe, -+ .remove = micro_batt_remove, -+ .suspend = micro_batt_suspend, -+ .resume = micro_batt_resume, -+}; -+ -+static int micro_batt_init (void) -+{ -+ return platform_driver_register(µ_batt_device_driver); -+} -+ -+static void micro_batt_cleanup (void) -+{ -+ platform_driver_unregister (µ_batt_device_driver); -+} -+ -+module_init (micro_batt_init); -+module_exit (micro_batt_cleanup); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("gremlin.it"); -+MODULE_DESCRIPTION("driver for iPAQ Atmel micro battery"); -+ -+ -Index: linux-2.6.22/drivers/power/olpc_battery.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.22/drivers/power/olpc_battery.c 2007-08-23 12:13:52.000000000 +0200 -@@ -0,0 +1,302 @@ -+/* -+ * Battery driver for One Laptop Per Child board. -+ * -+ * Copyright © 2006 David Woodhouse <dwmw2@infradead.org> -+ * -+ * 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/module.h> -+#include <linux/err.h> -+#include <linux/platform_device.h> -+#include <linux/power_supply.h> -+#include <linux/jiffies.h> -+#include <linux/sched.h> -+#include <asm/io.h> -+ -+#define wBAT_VOLTAGE 0xf900 /* *9.76/32, mV */ -+#define wBAT_CURRENT 0xf902 /* *15.625/120, mA */ -+#define wBAT_TEMP 0xf906 /* *256/1000, °C */ -+#define wAMB_TEMP 0xf908 /* *256/1000, °C */ -+#define SOC 0xf910 /* percentage */ -+#define sMBAT_STATUS 0xfaa4 -+#define sBAT_PRESENT 1 -+#define sBAT_FULL 2 -+#define sBAT_DESTROY 4 /* what is this exactly? */ -+#define sBAT_LOW 32 -+#define sBAT_DISCHG 64 -+#define sMCHARGE_STATUS 0xfaa5 -+#define sBAT_CHARGE 1 -+#define sBAT_OVERTEMP 4 -+#define sBAT_NiMH 8 -+#define sPOWER_FLAG 0xfa40 -+#define ADAPTER_IN 1 -+ -+/********************************************************************* -+ * EC locking and access -+ *********************************************************************/ -+ -+static int lock_ec(void) -+{ -+ unsigned long timeo = jiffies + HZ / 20; -+ -+ while (1) { -+ unsigned char lock = inb(0x6c) & 0x80; -+ if (!lock) -+ return 0; -+ if (time_after(jiffies, timeo)) { -+ printk(KERN_ERR "olpc_battery: failed to lock EC for " -+ "battery access\n"); -+ return 1; -+ } -+ yield(); -+ } -+} -+ -+static void unlock_ec(void) -+{ -+ outb(0xff, 0x6c); -+ return; -+} -+ -+static unsigned char read_ec_byte(unsigned short adr) -+{ -+ outb(adr >> 8, 0x381); -+ outb(adr, 0x382); -+ return inb(0x383); -+} -+ -+static unsigned short read_ec_word(unsigned short adr) -+{ -+ return (read_ec_byte(adr) << 8) | read_ec_byte(adr + 1); -+} -+ -+/********************************************************************* -+ * Power -+ *********************************************************************/ -+ -+static int olpc_ac_get_prop(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ int ret = 0; -+ -+ if (lock_ec()) -+ return -EIO; -+ -+ switch (psp) { -+ case POWER_SUPPLY_PROP_ONLINE: -+ if (!(read_ec_byte(sMBAT_STATUS) & sBAT_PRESENT)) { -+ ret = -ENODEV; -+ goto out; -+ } -+ val->intval = !!(read_ec_byte(sPOWER_FLAG) & ADAPTER_IN); -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+out: -+ unlock_ec(); -+ return ret; -+} -+ -+static enum power_supply_property olpc_ac_props[] = { -+ POWER_SUPPLY_PROP_ONLINE, -+}; -+ -+static struct power_supply olpc_ac = { -+ .name = "olpc-ac", -+ .type = POWER_SUPPLY_TYPE_MAINS, -+ .properties = olpc_ac_props, -+ .num_properties = ARRAY_SIZE(olpc_ac_props), -+ .get_property = olpc_ac_get_prop, -+}; -+ -+/********************************************************************* -+ * Battery properties -+ *********************************************************************/ -+ -+static int olpc_bat_get_property(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ int ret = 0; -+ -+ if (lock_ec()) -+ return -EIO; -+ -+ switch (psp) { -+ case POWER_SUPPLY_PROP_STATUS: -+ { -+ int status = POWER_SUPPLY_STATUS_UNKNOWN; -+ -+ val->intval = read_ec_byte(sMBAT_STATUS); -+ -+ if (!(val->intval & sBAT_PRESENT)) { -+ ret = -ENODEV; -+ goto out; -+ } -+ -+ if (val->intval & sBAT_DISCHG) -+ status = POWER_SUPPLY_STATUS_DISCHARGING; -+ else if (val->intval & sBAT_FULL) -+ status = POWER_SUPPLY_STATUS_FULL; -+ -+ val->intval = read_ec_byte(sMCHARGE_STATUS); -+ if (val->intval & sBAT_CHARGE) -+ status = POWER_SUPPLY_STATUS_CHARGING; -+ -+ val->intval = status; -+ break; -+ } -+ case POWER_SUPPLY_PROP_PRESENT: -+ val->intval = !!(read_ec_byte(sMBAT_STATUS) & sBAT_PRESENT); -+ break; -+ case POWER_SUPPLY_PROP_HEALTH: -+ val->intval = read_ec_byte(sMCHARGE_STATUS); -+ if (val->intval & sBAT_OVERTEMP) -+ val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; -+ else -+ val->intval = POWER_SUPPLY_HEALTH_GOOD; -+ break; -+ case POWER_SUPPLY_PROP_TECHNOLOGY: -+ val->intval = read_ec_byte(sMCHARGE_STATUS); -+ if (val->intval & sBAT_NiMH) -+ val->intval = POWER_SUPPLY_TECHNOLOGY_NIMH; -+ else -+ val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN; -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_AVG: -+ val->intval = read_ec_byte(wBAT_VOLTAGE) * 9760L / 32; -+ break; -+ case POWER_SUPPLY_PROP_CURRENT_AVG: -+ val->intval = read_ec_byte(wBAT_CURRENT) * 15625L / 120; -+ break; -+ case POWER_SUPPLY_PROP_CAPACITY: -+ val->intval = read_ec_byte(SOC); -+ break; -+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL: -+ val->intval = read_ec_byte(sMBAT_STATUS); -+ if (val->intval & sBAT_FULL) -+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL; -+ else if (val->intval & sBAT_LOW) -+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW; -+ else -+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; -+ break; -+ case POWER_SUPPLY_PROP_TEMP: -+ val->intval = read_ec_byte(wBAT_TEMP) * 256 / 100; -+ break; -+ case POWER_SUPPLY_PROP_TEMP_AMBIENT: -+ val->intval = read_ec_byte(wAMB_TEMP) * 256 / 100; -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ -+out: -+ unlock_ec(); -+ return ret; -+} -+ -+static enum power_supply_property olpc_bat_props[] = { -+ POWER_SUPPLY_PROP_STATUS, -+ POWER_SUPPLY_PROP_PRESENT, -+ POWER_SUPPLY_PROP_HEALTH, -+ POWER_SUPPLY_PROP_TECHNOLOGY, -+ POWER_SUPPLY_PROP_VOLTAGE_AVG, -+ POWER_SUPPLY_PROP_CURRENT_AVG, -+ POWER_SUPPLY_PROP_CAPACITY, -+ POWER_SUPPLY_PROP_CAPACITY_LEVEL, -+ POWER_SUPPLY_PROP_TEMP, -+ POWER_SUPPLY_PROP_TEMP_AMBIENT, -+}; -+ -+/********************************************************************* -+ * Initialisation -+ *********************************************************************/ -+ -+static struct platform_device *bat_pdev; -+ -+static struct power_supply olpc_bat = { -+ .properties = olpc_bat_props, -+ .num_properties = ARRAY_SIZE(olpc_bat_props), -+ .get_property = olpc_bat_get_property, -+ .use_for_apm = 1, -+}; -+ -+static int __init olpc_bat_init(void) -+{ -+ int ret = 0; -+ unsigned short tmp; -+ -+ if (!request_region(0x380, 4, "olpc-battery")) { -+ ret = -EIO; -+ goto region_failed; -+ } -+ -+ if (lock_ec()) { -+ ret = -EIO; -+ goto lock_failed; -+ } -+ -+ tmp = read_ec_word(0xfe92); -+ unlock_ec(); -+ -+ if (tmp != 0x380) { -+ /* Doesn't look like OLPC EC */ -+ ret = -ENODEV; -+ goto not_olpc_ec; -+ } -+ -+ bat_pdev = platform_device_register_simple("olpc-battery", 0, NULL, 0); -+ if (IS_ERR(bat_pdev)) { -+ ret = PTR_ERR(bat_pdev); -+ goto pdev_failed; -+ } -+ -+ ret = power_supply_register(&bat_pdev->dev, &olpc_ac); -+ if (ret) -+ goto ac_failed; -+ -+ olpc_bat.name = bat_pdev->name; -+ -+ ret = power_supply_register(&bat_pdev->dev, &olpc_bat); -+ if (ret) -+ goto battery_failed; -+ -+ goto success; -+ -+battery_failed: -+ power_supply_unregister(&olpc_ac); -+ac_failed: -+ platform_device_unregister(bat_pdev); -+pdev_failed: -+not_olpc_ec: -+lock_failed: -+ release_region(0x380, 4); -+region_failed: -+success: -+ return ret; -+} -+ -+static void __exit olpc_bat_exit(void) -+{ -+ power_supply_unregister(&olpc_bat); -+ power_supply_unregister(&olpc_ac); -+ platform_device_unregister(bat_pdev); -+ release_region(0x380, 4); -+ return; -+} -+ -+module_init(olpc_bat_init); -+module_exit(olpc_bat_exit); -+ -+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("Battery driver for One Laptop Per Child " -+ "($100 laptop) board."); -Index: linux-2.6.22/drivers/power/pda_power.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.22/drivers/power/pda_power.c 2007-08-23 12:13:52.000000000 +0200 -@@ -0,0 +1,263 @@ -+/* -+ * Common power driver for PDAs and phones with one or two external -+ * power supplies (AC/USB) connected to main and backup batteries, -+ * and optional builtin charger. -+ * -+ * Copyright 2007 Anton Vorontsov <cbou@mail.ru> -+ * -+ * 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/module.h> -+#include <linux/platform_device.h> -+#include <linux/interrupt.h> -+#include <linux/power_supply.h> -+#include <linux/pda_power.h> -+#include <linux/timer.h> -+#include <linux/jiffies.h> -+ -+static inline unsigned int get_irq_flags(struct resource *res) -+{ -+ unsigned int flags = IRQF_DISABLED | IRQF_SHARED; -+ -+ flags |= res->flags & IRQF_TRIGGER_MASK; -+ -+ return flags; -+} -+ -+static struct device *dev; -+static struct pda_power_pdata *pdata; -+static struct resource *ac_irq, *usb_irq; -+static struct timer_list charger_timer; -+static struct timer_list supply_timer; -+ -+static int pda_power_get_property(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ switch (psp) { -+ case POWER_SUPPLY_PROP_ONLINE: -+ if (psy->type == POWER_SUPPLY_TYPE_MAINS) -+ val->intval = pdata->is_ac_online ? -+ pdata->is_ac_online() : 0; -+ else -+ val->intval = pdata->is_usb_online ? -+ pdata->is_usb_online() : 0; -+ break; -+ default: -+ return -EINVAL; -+ } -+ return 0; -+} -+ -+static enum power_supply_property pda_power_props[] = { -+ POWER_SUPPLY_PROP_ONLINE, -+}; -+ -+static char *pda_power_supplied_to[] = { -+ "main-battery", -+ "backup-battery", -+}; -+ -+static struct power_supply pda_power_supplies[] = { -+ { -+ .name = "ac", -+ .type = POWER_SUPPLY_TYPE_MAINS, -+ .supplied_to = pda_power_supplied_to, -+ .num_supplicants = ARRAY_SIZE(pda_power_supplied_to), -+ .properties = pda_power_props, -+ .num_properties = ARRAY_SIZE(pda_power_props), -+ .get_property = pda_power_get_property, -+ }, -+ { -+ .name = "usb", -+ .type = POWER_SUPPLY_TYPE_USB, -+ .supplied_to = pda_power_supplied_to, -+ .num_supplicants = ARRAY_SIZE(pda_power_supplied_to), -+ .properties = pda_power_props, -+ .num_properties = ARRAY_SIZE(pda_power_props), -+ .get_property = pda_power_get_property, -+ }, -+}; -+ -+static void update_charger(void) -+{ -+ if (!pdata->set_charge) -+ return; -+ -+ if (pdata->is_ac_online && pdata->is_ac_online()) { -+ dev_dbg(dev, "charger on (AC)\n"); -+ pdata->set_charge(PDA_POWER_CHARGE_AC); -+ } -+ else if (pdata->is_usb_online && pdata->is_usb_online()) { -+ dev_dbg(dev, "charger on (USB)\n"); -+ pdata->set_charge(PDA_POWER_CHARGE_USB); -+ } -+ else { -+ dev_dbg(dev, "charger off\n"); -+ pdata->set_charge(0); -+ } -+ -+ return; -+} -+ -+static void supply_timer_func(unsigned long irq) -+{ -+ if (ac_irq && irq == ac_irq->start) -+ power_supply_changed(&pda_power_supplies[0]); -+ else if (usb_irq && irq == usb_irq->start) -+ power_supply_changed(&pda_power_supplies[1]); -+ return; -+} -+ -+static void charger_timer_func(unsigned long irq) -+{ -+ update_charger(); -+ -+ /* Okay, charger set. Now wait a bit before notifying supplicants, -+ * charge power should stabilize. */ -+ supply_timer.data = irq; -+ mod_timer(&supply_timer, -+ jiffies + msecs_to_jiffies(pdata->wait_for_charger)); -+ return; -+} -+ -+static irqreturn_t power_changed_isr(int irq, void *unused) -+{ -+ /* Wait a bit before reading ac/usb line status and setting charger, -+ * because ac/usb status readings may lag from irq. */ -+ charger_timer.data = irq; -+ mod_timer(&charger_timer, -+ jiffies + msecs_to_jiffies(pdata->wait_for_status)); -+ return IRQ_HANDLED; -+} -+ -+static int pda_power_probe(struct platform_device *pdev) -+{ -+ int ret = 0; -+ -+ dev = &pdev->dev; -+ -+ if (pdev->id != -1) { -+ dev_err(dev, "it's meaningless to register several " -+ "pda_powers, use id = -1\n"); -+ ret = -EINVAL; -+ goto wrongid; -+ } -+ -+ pdata = pdev->dev.platform_data; -+ -+ update_charger(); -+ -+ if (!pdata->wait_for_status) -+ pdata->wait_for_status = 500; -+ -+ if (!pdata->wait_for_charger) -+ pdata->wait_for_charger = 500; -+ -+ setup_timer(&charger_timer, charger_timer_func, 0); -+ setup_timer(&supply_timer, supply_timer_func, 0); -+ -+ ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac"); -+ usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb"); -+ if (!ac_irq && !usb_irq) { -+ dev_err(dev, "no ac/usb irq specified\n"); -+ ret = -ENODEV; -+ goto noirqs; -+ } -+ -+ if (pdata->supplied_to) { -+ pda_power_supplies[0].supplied_to = pdata->supplied_to; -+ pda_power_supplies[1].supplied_to = pdata->supplied_to; -+ pda_power_supplies[0].num_supplicants = pdata->num_supplicants; -+ pda_power_supplies[1].num_supplicants = pdata->num_supplicants; -+ } -+ -+ ret = power_supply_register(&pdev->dev, &pda_power_supplies[0]); -+ if (ret) { -+ dev_err(dev, "failed to register %s power supply\n", -+ pda_power_supplies[0].name); -+ goto supply0_failed; -+ } -+ -+ ret = power_supply_register(&pdev->dev, &pda_power_supplies[1]); -+ if (ret) { -+ dev_err(dev, "failed to register %s power supply\n", -+ pda_power_supplies[1].name); -+ goto supply1_failed; -+ } -+ -+ if (ac_irq) { -+ ret = request_irq(ac_irq->start, power_changed_isr, -+ get_irq_flags(ac_irq), ac_irq->name, -+ &pda_power_supplies[0]); -+ if (ret) { -+ dev_err(dev, "request ac irq failed\n"); -+ goto ac_irq_failed; -+ } -+ } -+ -+ if (usb_irq) { -+ ret = request_irq(usb_irq->start, power_changed_isr, -+ get_irq_flags(usb_irq), usb_irq->name, -+ &pda_power_supplies[1]); -+ if (ret) { -+ dev_err(dev, "request usb irq failed\n"); -+ goto usb_irq_failed; -+ } -+ } -+ -+ goto success; -+ -+usb_irq_failed: -+ if (ac_irq) -+ free_irq(ac_irq->start, &pda_power_supplies[0]); -+ac_irq_failed: -+ power_supply_unregister(&pda_power_supplies[1]); -+supply1_failed: -+ power_supply_unregister(&pda_power_supplies[0]); -+supply0_failed: -+noirqs: -+wrongid: -+success: -+ return ret; -+} -+ -+static int pda_power_remove(struct platform_device *pdev) -+{ -+ if (usb_irq) -+ free_irq(usb_irq->start, &pda_power_supplies[1]); -+ if (ac_irq) -+ free_irq(ac_irq->start, &pda_power_supplies[0]); -+ del_timer_sync(&charger_timer); -+ del_timer_sync(&supply_timer); -+ power_supply_unregister(&pda_power_supplies[1]); -+ power_supply_unregister(&pda_power_supplies[0]); -+ return 0; -+} -+ -+static struct platform_driver pda_power_pdrv = { -+ .driver = { -+ .name = "pda-power", -+ }, -+ .probe = pda_power_probe, -+ .remove = pda_power_remove, -+}; -+ -+static int __init pda_power_init(void) -+{ -+ return platform_driver_register(&pda_power_pdrv); -+} -+ -+static void __exit pda_power_exit(void) -+{ -+ platform_driver_unregister(&pda_power_pdrv); -+ return; -+} -+ -+module_init(pda_power_init); -+module_exit(pda_power_exit); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>"); -Index: linux-2.6.22/drivers/power/pmu_battery.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.22/drivers/power/pmu_battery.c 2007-08-23 12:13:52.000000000 +0200 -@@ -0,0 +1,215 @@ -+/* -+ * Battery class driver for Apple PMU -+ * -+ * Copyright © 2006 David Woodhouse <dwmw2@infradead.org> -+ * -+ * 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/module.h> -+#include <linux/platform_device.h> -+#include <linux/err.h> -+#include <linux/power_supply.h> -+#include <linux/adb.h> -+#include <linux/pmu.h> -+ -+static struct pmu_battery_dev { -+ struct power_supply bat; -+ struct pmu_battery_info *pbi; -+ char name[16]; -+ int propval; -+} *pbats[PMU_MAX_BATTERIES]; -+ -+#define to_pmu_battery_dev(x) container_of(x, struct pmu_battery_dev, bat) -+ -+/********************************************************************* -+ * Power -+ *********************************************************************/ -+ -+static int pmu_get_ac_prop(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ switch (psp) { -+ case POWER_SUPPLY_PROP_ONLINE: -+ val->intval = (!!(pmu_power_flags & PMU_PWR_AC_PRESENT)) || -+ (pmu_battery_count == 0); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static enum power_supply_property pmu_ac_props[] = { -+ POWER_SUPPLY_PROP_ONLINE, -+}; -+ -+static struct power_supply pmu_ac = { -+ .name = "pmu-ac", -+ .type = POWER_SUPPLY_TYPE_MAINS, -+ .properties = pmu_ac_props, -+ .num_properties = ARRAY_SIZE(pmu_ac_props), -+ .get_property = pmu_get_ac_prop, -+}; -+ -+/********************************************************************* -+ * Battery properties -+ *********************************************************************/ -+ -+static char *pmu_batt_types[] = { -+ "Smart", "Comet", "Hooper", "Unknown" -+}; -+ -+static char *pmu_bat_get_model_name(struct pmu_battery_info *pbi) -+{ -+ switch (pbi->flags & PMU_BATT_TYPE_MASK) { -+ case PMU_BATT_TYPE_SMART: -+ return pmu_batt_types[0]; -+ case PMU_BATT_TYPE_COMET: -+ return pmu_batt_types[1]; -+ case PMU_BATT_TYPE_HOOPER: -+ return pmu_batt_types[2]; -+ default: break; -+ } -+ return pmu_batt_types[3]; -+} -+ -+static int pmu_bat_get_property(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val) -+{ -+ struct pmu_battery_dev *pbat = to_pmu_battery_dev(psy); -+ struct pmu_battery_info *pbi = pbat->pbi; -+ -+ switch (psp) { -+ case POWER_SUPPLY_PROP_STATUS: -+ if (pbi->flags & PMU_BATT_CHARGING) -+ val->intval = POWER_SUPPLY_STATUS_CHARGING; -+ else -+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING; -+ break; -+ case POWER_SUPPLY_PROP_PRESENT: -+ val->intval = !!(pbi->flags & PMU_BATT_PRESENT); -+ break; -+ case POWER_SUPPLY_PROP_MODEL_NAME: -+ val->strval = pmu_bat_get_model_name(pbi); -+ break; -+ case POWER_SUPPLY_PROP_ENERGY_AVG: -+ val->intval = pbi->charge * 1000; /* mWh -> µWh */ -+ break; -+ case POWER_SUPPLY_PROP_ENERGY_FULL: -+ val->intval = pbi->max_charge * 1000; /* mWh -> µWh */ -+ break; -+ case POWER_SUPPLY_PROP_CURRENT_AVG: -+ val->intval = pbi->amperage * 1000; /* mA -> µA */ -+ break; -+ case POWER_SUPPLY_PROP_VOLTAGE_AVG: -+ val->intval = pbi->voltage * 1000; /* mV -> µV */ -+ break; -+ case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: -+ val->intval = pbi->time_remaining; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static enum power_supply_property pmu_bat_props[] = { -+ POWER_SUPPLY_PROP_STATUS, -+ POWER_SUPPLY_PROP_PRESENT, -+ POWER_SUPPLY_PROP_MODEL_NAME, -+ POWER_SUPPLY_PROP_ENERGY_AVG, -+ POWER_SUPPLY_PROP_ENERGY_FULL, -+ POWER_SUPPLY_PROP_CURRENT_AVG, -+ POWER_SUPPLY_PROP_VOLTAGE_AVG, -+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, -+}; -+ -+/********************************************************************* -+ * Initialisation -+ *********************************************************************/ -+ -+static struct platform_device *bat_pdev; -+ -+static int __init pmu_bat_init(void) -+{ -+ int ret; -+ int i; -+ -+ bat_pdev = platform_device_register_simple("pmu-battery", -+ 0, NULL, 0); -+ if (IS_ERR(bat_pdev)) { -+ ret = PTR_ERR(bat_pdev); -+ goto pdev_register_failed; -+ } -+ -+ ret = power_supply_register(&bat_pdev->dev, &pmu_ac); -+ if (ret) -+ goto ac_register_failed; -+ -+ for (i = 0; i < pmu_battery_count; i++) { -+ struct pmu_battery_dev *pbat = kzalloc(sizeof(*pbat), -+ GFP_KERNEL); -+ if (!pbat) -+ break; -+ -+ sprintf(pbat->name, "PMU battery %d", i); -+ pbat->bat.name = pbat->name; -+ pbat->bat.properties = pmu_bat_props; -+ pbat->bat.num_properties = ARRAY_SIZE(pmu_bat_props); -+ pbat->bat.get_property = pmu_bat_get_property; -+ pbat->pbi = &pmu_batteries[i]; -+ -+ ret = power_supply_register(&bat_pdev->dev, &pbat->bat); -+ if (ret) { -+ kfree(pbat); -+ goto battery_register_failed; -+ } -+ pbats[i] = pbat; -+ } -+ -+ goto success; -+ -+battery_register_failed: -+ while (i--) { -+ if (!pbats[i]) -+ continue; -+ power_supply_unregister(&pbats[i]->bat); -+ kfree(pbats[i]); -+ } -+ power_supply_unregister(&pmu_ac); -+ac_register_failed: -+ platform_device_unregister(bat_pdev); -+pdev_register_failed: -+success: -+ return ret; -+} -+ -+static void __exit pmu_bat_exit(void) -+{ -+ int i; -+ -+ for (i = 0; i < PMU_MAX_BATTERIES; i++) { -+ if (!pbats[i]) -+ continue; -+ power_supply_unregister(&pbats[i]->bat); -+ kfree(pbats[i]); -+ } -+ power_supply_unregister(&pmu_ac); -+ platform_device_unregister(bat_pdev); -+ -+ return; -+} -+ -+module_init(pmu_bat_init); -+module_exit(pmu_bat_exit); -+ -+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("PMU battery driver"); -Index: linux-2.6.22/drivers/power/power_supply_core.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.22/drivers/power/power_supply_core.c 2007-08-23 12:13:52.000000000 +0200 -@@ -0,0 +1,168 @@ -+/* -+ * Universal power supply monitor class -+ * -+ * Copyright (c) 2007 Anton Vorontsov <cbou@mail.ru> -+ * Copyright (c) 2004 Szabolcs Gyurko -+ * Copyright (c) 2003 Ian Molton <spyro@f2s.com> -+ * -+ * Modified: 2004, Oct Szabolcs Gyurko -+ * -+ * You may use this code as per GPL version 2 -+ */ -+ -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/init.h> -+#include <linux/device.h> -+#include <linux/err.h> -+#include <linux/power_supply.h> -+#include "power_supply.h" -+ -+struct class *power_supply_class; -+ -+static void power_supply_changed_work(struct work_struct *work) -+{ -+ struct power_supply *psy = container_of(work, struct power_supply, -+ changed_work); -+ int i; -+ -+ dev_dbg(psy->dev, "%s\n", __FUNCTION__); -+ -+ for (i = 0; i < psy->num_supplicants; i++) { -+ struct device *dev; -+ -+ down(&power_supply_class->sem); -+ list_for_each_entry(dev, &power_supply_class->devices, node) { -+ struct power_supply *pst = dev_get_drvdata(dev); -+ -+ if (!strcmp(psy->supplied_to[i], pst->name)) { -+ if (pst->external_power_changed) -+ pst->external_power_changed(pst); -+ } -+ } -+ up(&power_supply_class->sem); -+ } -+ -+ power_supply_update_leds(psy); -+ -+ kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE); -+ -+ return; -+} -+ -+void power_supply_changed(struct power_supply *psy) -+{ -+ dev_dbg(psy->dev, "%s\n", __FUNCTION__); -+ -+ schedule_work(&psy->changed_work); -+ -+ return; -+} -+ -+int power_supply_am_i_supplied(struct power_supply *psy) -+{ -+ union power_supply_propval ret = {0,}; -+ struct device *dev; -+ -+ down(&power_supply_class->sem); -+ list_for_each_entry(dev, &power_supply_class->devices, node) { -+ struct power_supply *epsy = dev_get_drvdata(dev); -+ int i; -+ -+ for (i = 0; i < epsy->num_supplicants; i++) { -+ if (!strcmp(epsy->supplied_to[i], psy->name)) { -+ if (epsy->get_property(epsy, -+ POWER_SUPPLY_PROP_ONLINE, &ret)) -+ continue; -+ if (ret.intval) -+ goto out; -+ } -+ } -+ } -+out: -+ up(&power_supply_class->sem); -+ -+ dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, ret.intval); -+ -+ return ret.intval; -+} -+ -+int power_supply_register(struct device *parent, struct power_supply *psy) -+{ -+ int rc = 0; -+ -+ psy->dev = device_create(power_supply_class, parent, 0, -+ "%s", psy->name); -+ if (IS_ERR(psy->dev)) { -+ rc = PTR_ERR(psy->dev); -+ goto dev_create_failed; -+ } -+ -+ dev_set_drvdata(psy->dev, psy); -+ -+ INIT_WORK(&psy->changed_work, power_supply_changed_work); -+ -+ rc = power_supply_create_attrs(psy); -+ if (rc) -+ goto create_attrs_failed; -+ -+ rc = power_supply_create_triggers(psy); -+ if (rc) -+ goto create_triggers_failed; -+ -+ power_supply_changed(psy); -+ -+ goto success; -+ -+create_triggers_failed: -+ power_supply_remove_attrs(psy); -+create_attrs_failed: -+ device_unregister(psy->dev); -+dev_create_failed: -+success: -+ return rc; -+} -+ -+void power_supply_unregister(struct power_supply *psy) -+{ -+ flush_scheduled_work(); -+ power_supply_remove_triggers(psy); -+ power_supply_remove_attrs(psy); -+ device_unregister(psy->dev); -+ return; -+} -+ -+static int __init power_supply_class_init(void) -+{ -+ power_supply_class = class_create(THIS_MODULE, "power_supply"); -+ -+ if (IS_ERR(power_supply_class)) -+ return PTR_ERR(power_supply_class); -+ -+ power_supply_class->dev_uevent = power_supply_uevent; -+ -+ return 0; -+} -+ -+static void __exit power_supply_class_exit(void) -+{ -+ class_destroy(power_supply_class); -+ return; -+} -+ -+EXPORT_SYMBOL_GPL(power_supply_changed); -+EXPORT_SYMBOL_GPL(power_supply_am_i_supplied); -+EXPORT_SYMBOL_GPL(power_supply_register); -+EXPORT_SYMBOL_GPL(power_supply_unregister); -+ -+/* exported for the APM Power driver, APM emulation */ -+EXPORT_SYMBOL_GPL(power_supply_class); -+ -+subsys_initcall(power_supply_class_init); -+module_exit(power_supply_class_exit); -+ -+MODULE_DESCRIPTION("Universal power supply monitor class"); -+MODULE_AUTHOR("Ian Molton <spyro@f2s.com>, " -+ "Szabolcs Gyurko, " -+ "Anton Vorontsov <cbou@mail.ru>"); -+MODULE_LICENSE("GPL"); -Index: linux-2.6.22/drivers/power/power_supply.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.22/drivers/power/power_supply.h 2007-08-23 12:13:52.000000000 +0200 -@@ -0,0 +1,42 @@ -+/* -+ * Functions private to power supply class -+ * -+ * Copyright (c) 2007 Anton Vorontsov <cbou@mail.ru> -+ * Copyright (c) 2004 Szabolcs Gyurko -+ * Copyright (c) 2003 Ian Molton <spyro@f2s.com> -+ * -+ * Modified: 2004, Oct Szabolcs Gyurko -+ * -+ * You may use this code as per GPL version 2 -+ */ -+ -+#ifdef CONFIG_SYSFS -+ -+extern int power_supply_create_attrs(struct power_supply *psy); -+extern void power_supply_remove_attrs(struct power_supply *psy); -+extern int power_supply_uevent(struct device *dev, char **envp, int num_envp, -+ char *buffer, int buffer_size); -+ -+#else -+ -+static inline int power_supply_create_attrs(struct power_supply *psy) -+{ return 0; } -+static inline void power_supply_remove_attrs(struct power_supply *psy) {} -+#define power_supply_uevent NULL -+ -+#endif /* CONFIG_SYSFS */ -+ -+#ifdef CONFIG_LEDS_TRIGGERS -+ -+extern void power_supply_update_leds(struct power_supply *psy); -+extern int power_supply_create_triggers(struct power_supply *psy); -+extern void power_supply_remove_triggers(struct power_supply *psy); -+ -+#else -+ -+static inline void power_supply_update_leds(struct power_supply *psy) {} -+static inline int power_supply_create_triggers(struct power_supply *psy) -+{ return 0; } -+static inline void power_supply_remove_triggers(struct power_supply *psy) {} -+ -+#endif /* CONFIG_LEDS_TRIGGERS */ -Index: linux-2.6.22/drivers/power/power_supply_leds.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.22/drivers/power/power_supply_leds.c 2007-08-23 12:13:52.000000000 +0200 -@@ -0,0 +1,188 @@ -+/* -+ * LEDs triggers for power supply class -+ * -+ * Copyright (c) 2007 Anton Vorontsov <cbou@mail.ru> -+ * Copyright (c) 2004 Szabolcs Gyurko -+ * Copyright (c) 2003 Ian Molton <spyro@f2s.com> -+ * -+ * Modified: 2004, Oct Szabolcs Gyurko -+ * -+ * You may use this code as per GPL version 2 -+ */ -+ -+#include <linux/power_supply.h> -+ -+/* If we have hwtimer trigger, then use it to blink charging LED */ -+ -+#if defined(CONFIG_LEDS_TRIGGER_HWTIMER) || \ -+ (defined(CONFIG_BATTERY_MODULE) && \ -+ defined(CONFIG_LEDS_TRIGGER_HWTIMER_MODULE)) -+ #define led_trigger_register_charging led_trigger_register_hwtimer -+ #define led_trigger_unregister_charging led_trigger_unregister_hwtimer -+#else -+ #define led_trigger_register_charging led_trigger_register_simple -+ #define led_trigger_unregister_charging led_trigger_unregister_simple -+#endif -+ -+/* Battery specific LEDs triggers. */ -+ -+static void power_supply_update_bat_leds(struct power_supply *psy) -+{ -+ union power_supply_propval status; -+ -+ if (psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &status)) -+ return; -+ -+ dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, status.intval); -+ -+ switch(status.intval) { -+ case POWER_SUPPLY_STATUS_FULL: -+ led_trigger_event(psy->charging_full_trig, LED_FULL); -+ led_trigger_event(psy->charging_trig, LED_OFF); -+ led_trigger_event(psy->full_trig, LED_FULL); -+ break; -+ case POWER_SUPPLY_STATUS_CHARGING: -+ led_trigger_event(psy->charging_full_trig, LED_FULL); -+ led_trigger_event(psy->charging_trig, LED_FULL); -+ led_trigger_event(psy->full_trig, LED_OFF); -+ break; -+ default: -+ led_trigger_event(psy->charging_full_trig, LED_OFF); -+ led_trigger_event(psy->charging_trig, LED_OFF); -+ led_trigger_event(psy->full_trig, LED_OFF); -+ break; -+ } -+ -+ return; -+} -+ -+static int power_supply_create_bat_triggers(struct power_supply *psy) -+{ -+ int rc = 0; -+ -+ psy->charging_full_trig_name = kmalloc(strlen(psy->name) + -+ sizeof("-charging-or-full"), GFP_KERNEL); -+ if (!psy->charging_full_trig_name) -+ goto charging_full_failed; -+ -+ psy->charging_trig_name = kmalloc(strlen(psy->name) + -+ sizeof("-charging"), GFP_KERNEL); -+ if (!psy->charging_trig_name) -+ goto charging_failed; -+ -+ psy->full_trig_name = kmalloc(strlen(psy->name) + -+ sizeof("-full"), GFP_KERNEL); -+ if (!psy->full_trig_name) -+ goto full_failed; -+ -+ strcpy(psy->charging_full_trig_name, psy->name); -+ strcat(psy->charging_full_trig_name, "-charging-or-full"); -+ strcpy(psy->charging_trig_name, psy->name); -+ strcat(psy->charging_trig_name, "-charging"); -+ strcpy(psy->full_trig_name, psy->name); -+ strcat(psy->full_trig_name, "-full"); -+ -+ led_trigger_register_simple(psy->charging_full_trig_name, -+ &psy->charging_full_trig); -+ led_trigger_register_charging(psy->charging_trig_name, -+ &psy->charging_trig); -+ led_trigger_register_simple(psy->full_trig_name, -+ &psy->full_trig); -+ -+ goto success; -+ -+full_failed: -+ kfree(psy->charging_trig_name); -+charging_failed: -+ kfree(psy->charging_full_trig_name); -+charging_full_failed: -+ rc = -ENOMEM; -+success: -+ return rc; -+} -+ -+static void power_supply_remove_bat_triggers(struct power_supply *psy) -+{ -+ led_trigger_unregister_simple(psy->charging_full_trig); -+ led_trigger_unregister_charging(psy->charging_trig); -+ led_trigger_unregister_simple(psy->full_trig); -+ kfree(psy->full_trig_name); -+ kfree(psy->charging_trig_name); -+ kfree(psy->charging_full_trig_name); -+ return; -+} -+ -+/* Generated power specific LEDs triggers. */ -+ -+static void power_supply_update_gen_leds(struct power_supply *psy) -+{ -+ union power_supply_propval online; -+ -+ if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online)) -+ return; -+ -+ dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, online.intval); -+ -+ if (online.intval) -+ led_trigger_event(psy->online_trig, LED_FULL); -+ else -+ led_trigger_event(psy->online_trig, LED_OFF); -+ -+ return; -+} -+ -+static int power_supply_create_gen_triggers(struct power_supply *psy) -+{ -+ int rc = 0; -+ -+ psy->online_trig_name = kmalloc(strlen(psy->name) + sizeof("-online"), -+ GFP_KERNEL); -+ if (!psy->online_trig_name) -+ goto online_failed; -+ -+ strcpy(psy->online_trig_name, psy->name); -+ strcat(psy->online_trig_name, "-online"); -+ -+ led_trigger_register_simple(psy->online_trig_name, &psy->online_trig); -+ -+ goto success; -+ -+online_failed: -+ rc = -ENOMEM; -+success: -+ return rc; -+} -+ -+static void power_supply_remove_gen_triggers(struct power_supply *psy) -+{ -+ led_trigger_unregister_simple(psy->online_trig); -+ kfree(psy->online_trig_name); -+ return; -+} -+ -+/* Choice what triggers to create&update. */ -+ -+void power_supply_update_leds(struct power_supply *psy) -+{ -+ if (psy->type == POWER_SUPPLY_TYPE_BATTERY) -+ power_supply_update_bat_leds(psy); -+ else -+ power_supply_update_gen_leds(psy); -+ return; -+} -+ -+int power_supply_create_triggers(struct power_supply *psy) -+{ -+ if (psy->type == POWER_SUPPLY_TYPE_BATTERY) -+ return power_supply_create_bat_triggers(psy); -+ return power_supply_create_gen_triggers(psy); -+} -+ -+void power_supply_remove_triggers(struct power_supply *psy) -+{ -+ if (psy->type == POWER_SUPPLY_TYPE_BATTERY) -+ power_supply_remove_bat_triggers(psy); -+ else -+ power_supply_remove_gen_triggers(psy); -+ return; -+} -Index: linux-2.6.22/drivers/power/power_supply_sysfs.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.22/drivers/power/power_supply_sysfs.c 2007-08-23 12:13:52.000000000 +0200 -@@ -0,0 +1,289 @@ -+/* -+ * Sysfs interface for the universal power supply monitor class -+ * -+ * Copyright © 2007 David Woodhouse <dwmw2@infradead.org> -+ * Copyright (c) 2007 Anton Vorontsov <cbou@mail.ru> -+ * Copyright (c) 2004 Szabolcs Gyurko -+ * Copyright (c) 2003 Ian Molton <spyro@f2s.com> -+ * -+ * Modified: 2004, Oct Szabolcs Gyurko -+ * -+ * You may use this code as per GPL version 2 -+ */ -+ -+#include <linux/ctype.h> -+#include <linux/power_supply.h> -+ -+/* -+ * This is because the name "current" breaks the device attr macro. -+ * The "current" word resolvs to "(get_current())" so instead of -+ * "current" "(get_current())" appears in the sysfs. -+ * -+ * The source of this definition is the device.h which calls __ATTR -+ * macro in sysfs.h which calls the __stringify macro. -+ * -+ * Only modification that the name is not tried to be resolved -+ * (as a macro let's say). -+ */ -+ -+#define POWER_SUPPLY_ATTR(_name) \ -+{ \ -+ .attr = { .name = #_name, .mode = 0444, .owner = THIS_MODULE }, \ -+ .show = power_supply_show_property, \ -+ .store = NULL, \ -+} -+ -+static struct device_attribute power_supply_attrs[]; -+ -+static ssize_t power_supply_show_property(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) { -+ static char *status_text[] = { -+ "Unknown", "Charging", "Discharging", "Not charging", "Full" -+ }; -+ static char *health_text[] = { -+ "Unknown", "Good", "Overheat", "Dead" -+ }; -+ static char *technology_text[] = { -+ "Unknown", "NiMH", "Li-ion", "Li-poly" -+ }; -+ static char *capacity_level_text[] = { -+ "Unknown", "Critical", "Low", "Normal", "High", "Full" -+ }; -+ ssize_t ret; -+ struct power_supply *psy = dev_get_drvdata(dev); -+ const ptrdiff_t off = attr - power_supply_attrs; -+ union power_supply_propval value; -+ -+ ret = psy->get_property(psy, off, &value); -+ -+ if (ret < 0) { -+ dev_err(dev, "driver failed to report `%s' property\n", -+ attr->attr.name); -+ return ret; -+ } -+ -+ if (off == POWER_SUPPLY_PROP_STATUS) -+ return sprintf(buf, "%s\n", status_text[value.intval]); -+ else if (off == POWER_SUPPLY_PROP_HEALTH) -+ return sprintf(buf, "%s\n", health_text[value.intval]); -+ else if (off == POWER_SUPPLY_PROP_TECHNOLOGY) -+ return sprintf(buf, "%s\n", technology_text[value.intval]); -+ else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL) -+ return sprintf(buf, "%s\n", -+ capacity_level_text[value.intval]); -+ else if (off == POWER_SUPPLY_PROP_MODEL_NAME) -+ return sprintf(buf, "%s\n", value.strval); -+ -+ return sprintf(buf, "%d\n", value.intval); -+} -+ -+/* Must be in the same order as POWER_SUPPLY_PROP_* */ -+static struct device_attribute power_supply_attrs[] = { -+ /* Properties of type `int' */ -+ POWER_SUPPLY_ATTR(status), -+ POWER_SUPPLY_ATTR(health), -+ POWER_SUPPLY_ATTR(present), -+ POWER_SUPPLY_ATTR(online), -+ POWER_SUPPLY_ATTR(technology), -+ POWER_SUPPLY_ATTR(voltage_max_design), -+ POWER_SUPPLY_ATTR(voltage_min_design), -+ POWER_SUPPLY_ATTR(voltage_now), -+ POWER_SUPPLY_ATTR(voltage_avg), -+ POWER_SUPPLY_ATTR(current_now), -+ POWER_SUPPLY_ATTR(current_avg), -+ POWER_SUPPLY_ATTR(charge_full_design), -+ POWER_SUPPLY_ATTR(charge_empty_design), -+ POWER_SUPPLY_ATTR(charge_full), -+ POWER_SUPPLY_ATTR(charge_empty), -+ POWER_SUPPLY_ATTR(charge_now), -+ POWER_SUPPLY_ATTR(charge_avg), -+ POWER_SUPPLY_ATTR(energy_full_design), -+ POWER_SUPPLY_ATTR(energy_empty_design), -+ POWER_SUPPLY_ATTR(energy_full), -+ POWER_SUPPLY_ATTR(energy_empty), -+ POWER_SUPPLY_ATTR(energy_now), -+ POWER_SUPPLY_ATTR(energy_avg), -+ POWER_SUPPLY_ATTR(capacity), -+ POWER_SUPPLY_ATTR(capacity_level), -+ POWER_SUPPLY_ATTR(temp), -+ POWER_SUPPLY_ATTR(temp_ambient), -+ POWER_SUPPLY_ATTR(time_to_empty_now), -+ POWER_SUPPLY_ATTR(time_to_empty_avg), -+ POWER_SUPPLY_ATTR(time_to_full_now), -+ POWER_SUPPLY_ATTR(time_to_full_avg), -+ /* Properties of type `const char *' */ -+ POWER_SUPPLY_ATTR(model_name), -+}; -+ -+static ssize_t power_supply_show_static_attrs(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) { -+ static char *type_text[] = { "Battery", "UPS", "Mains", "USB" }; -+ struct power_supply *psy = dev_get_drvdata(dev); -+ -+ return sprintf(buf, "%s\n", type_text[psy->type]); -+} -+ -+static struct device_attribute power_supply_static_attrs[] = { -+ __ATTR(type, 0444, power_supply_show_static_attrs, NULL), -+}; -+ -+int power_supply_create_attrs(struct power_supply *psy) -+{ -+ int rc = 0; -+ int i, j; -+ -+ for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++) { -+ rc = device_create_file(psy->dev, -+ &power_supply_static_attrs[i]); -+ if (rc) -+ goto statics_failed; -+ } -+ -+ for (j = 0; j < psy->num_properties; j++) { -+ rc = device_create_file(psy->dev, -+ &power_supply_attrs[psy->properties[j]]); -+ if (rc) -+ goto dynamics_failed; -+ } -+ -+ goto succeed; -+ -+dynamics_failed: -+ while (j--) -+ device_remove_file(psy->dev, -+ &power_supply_attrs[psy->properties[j]]); -+statics_failed: -+ while (i--) -+ device_remove_file(psy->dev, -+ &power_supply_static_attrs[psy->properties[i]]); -+succeed: -+ return rc; -+} -+ -+void power_supply_remove_attrs(struct power_supply *psy) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++) -+ device_remove_file(psy->dev, -+ &power_supply_static_attrs[i]); -+ -+ for (i = 0; i < psy->num_properties; i++) -+ device_remove_file(psy->dev, -+ &power_supply_attrs[psy->properties[i]]); -+ -+ return; -+} -+ -+static char *kstruprdup(const char *str, gfp_t gfp) -+{ -+ char *ret, *ustr; -+ -+ ustr = ret = kmalloc(strlen(str) + 1, gfp); -+ -+ if (!ret) -+ return NULL; -+ -+ while (*str) -+ *ustr++ = toupper(*str++); -+ -+ *ustr = 0; -+ -+ return ret; -+} -+ -+int power_supply_uevent(struct device *dev, char **envp, int num_envp, -+ char *buffer, int buffer_size) -+{ -+ struct power_supply *psy = dev_get_drvdata(dev); -+ int i = 0, length = 0, ret = 0, j; -+ char *prop_buf; -+ char *attrname; -+ -+ dev_dbg(dev, "uevent\n"); -+ -+ if (!psy) { -+ dev_dbg(dev, "No power supply yet\n"); -+ return ret; -+ } -+ -+ dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name); -+ -+ ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, -+ &length, "POWER_SUPPLY_NAME=%s", psy->name); -+ if (ret) -+ return ret; -+ -+ prop_buf = (char *)get_zeroed_page(GFP_KERNEL); -+ if (!prop_buf) -+ return -ENOMEM; -+ -+ for (j = 0; j < ARRAY_SIZE(power_supply_static_attrs); j++) { -+ struct device_attribute *attr; -+ char *line; -+ -+ attr = &power_supply_static_attrs[j]; -+ -+ ret = power_supply_show_static_attrs(dev, attr, prop_buf); -+ if (ret < 0) -+ goto out; -+ -+ line = strchr(prop_buf, '\n'); -+ if (line) -+ *line = 0; -+ -+ attrname = kstruprdup(attr->attr.name, GFP_KERNEL); -+ if (!attrname) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf); -+ -+ ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, -+ &length, "POWER_SUPPLY_%s=%s", -+ attrname, prop_buf); -+ kfree(attrname); -+ if (ret) -+ goto out; -+ } -+ -+ dev_dbg(dev, "%zd dynamic props\n", psy->num_properties); -+ -+ for (j = 0; j < psy->num_properties; j++) { -+ struct device_attribute *attr; -+ char *line; -+ -+ attr = &power_supply_attrs[psy->properties[j]]; -+ -+ ret = power_supply_show_property(dev, attr, prop_buf); -+ if (ret < 0) -+ goto out; -+ -+ line = strchr(prop_buf, '\n'); -+ if (line) -+ *line = 0; -+ -+ attrname = kstruprdup(attr->attr.name, GFP_KERNEL); -+ if (!attrname) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf); -+ -+ ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, -+ &length, "POWER_SUPPLY_%s=%s", -+ attrname, prop_buf); -+ kfree(attrname); -+ if (ret) -+ goto out; -+ } -+ -+out: -+ free_page((unsigned long)prop_buf); -+ -+ return ret; -+} -Index: linux-2.6.22/drivers/power/simpad-battery.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.22/drivers/power/simpad-battery.c 2007-08-23 12:13:52.000000000 +0200 -@@ -0,0 +1,242 @@ -+/* -+ * linux/drivers/misc/simpad-battery.c -+ * -+ * Copyright (C) 2005 Holger Hans Peter Freyther -+ * Copyright (C) 2001 Juergen Messerer -+ * -+ * 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. -+ * -+ * Read the Battery Level through the UCB1x00 chip. T-Sinuspad is -+ * unsupported for now. -+ * -+ */ -+ -+#include <linux/battery.h> -+#include <asm/dma.h> -+#include "ucb1x00.h" -+ -+ -+/* -+ * Conversion from AD -> mV -+ * 7.5V = 1023 7.3313mV/Digit -+ * -+ * 400 Units == 9.7V -+ * a = ADC value -+ * 21 = ADC error -+ * 12600 = Divident to get 2*7.3242 -+ * 860 = Divider to get 2*7.3242 -+ * 170 = Voltagedrop over -+ */ -+#define CALIBRATE_BATTERY(a) ((((a + 21)*12600)/860) + 170) -+ -+/* -+ * We have two types of batteries a small and a large one -+ * To get the right value we to distinguish between those two -+ * 450 Units == 15 V -+ */ -+#define CALIBRATE_SUPPLY(a) (((a) * 1500) / 45) -+#define MIN_SUPPLY 12000 /* Less then 12V means no powersupply */ -+ -+/* -+ * Charging Current -+ * if value is >= 50 then charging is on -+ */ -+#define CALIBRATE_CHARGING(a) (((a)* 1000)/(152/4))) -+ -+struct simpad_battery_t { -+ struct battery battery; -+ struct ucb1x00* ucb; -+ -+ /* -+ * Variables for the values to one time support -+ * T-Sinuspad as well -+ */ -+ int min_voltage; -+ int min_current; -+ int min_charge; -+ -+ int max_voltage; -+ int max_current; -+ int max_charge; -+ -+ int min_supply; -+ int charging_led_label; -+ int charging_max_label; -+ int batt_full; -+ int batt_low; -+ int batt_critical; -+ int batt_empty; -+}; -+ -+static int simpad_get_min_voltage(struct battery* _battery ) -+{ -+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery; -+ return battery->min_voltage; -+} -+ -+static int simpad_get_min_current(struct battery* _battery) -+{ -+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery; -+ return battery->min_current; -+} -+ -+static int simpad_get_min_charge(struct battery* _battery) -+{ -+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery; -+ return battery->min_charge; -+} -+ -+static int simpad_get_max_voltage(struct battery* _battery) -+{ -+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery; -+ return battery->max_voltage; -+} -+ -+static int simpad_get_max_current(struct battery* _battery) -+{ -+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery; -+ return battery->max_current; -+} -+ -+static int simpad_get_max_charge(struct battery* _battery) -+{ -+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery; -+ return battery->max_charge; -+} -+ -+static int simpad_get_temp(struct battery* _battery) -+{ -+ return 0; -+} -+ -+static int simpad_get_voltage(struct battery* _battery) -+{ -+ int val; -+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery; -+ -+ -+ ucb1x00_adc_enable(battery->ucb); -+ val = ucb1x00_adc_read(battery->ucb, UCB_ADC_INP_AD1, UCB_NOSYNC); -+ ucb1x00_adc_disable(battery->ucb); -+ -+ return CALIBRATE_BATTERY(val); -+} -+ -+static int simpad_get_current(struct battery* _battery) -+{ -+ int val; -+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery; -+ -+ ucb1x00_adc_enable(battery->ucb); -+ val = ucb1x00_adc_read(battery->ucb, UCB_ADC_INP_AD3, UCB_NOSYNC); -+ ucb1x00_adc_disable(battery->ucb); -+ -+ return val; -+} -+ -+static int simpad_get_charge(struct battery* _battery) -+{ -+ int val; -+ struct simpad_battery_t* battery = (struct simpad_battery_t*)_battery; -+ -+ ucb1x00_adc_enable(battery->ucb); -+ val = ucb1x00_adc_read(battery->ucb, UCB_ADC_INP_AD2, UCB_NOSYNC); -+ ucb1x00_adc_disable(battery->ucb); -+ -+ return CALIBRATE_SUPPLY(val); -+ -+} -+ -+static int simpad_get_status(struct battery* _battery) -+{ -+ struct simpad_battery_t* battery = (struct simpad_battery_t*)(_battery); -+ int vcharger = simpad_get_voltage(_battery); -+ int icharger = simpad_get_current(_battery); -+ -+ int status = BATTERY_STATUS_UNKNOWN; -+ if(icharger > battery->charging_led_label) -+ status = BATTERY_STATUS_CHARGING; -+ else if(vcharger > battery->min_supply) -+ status = BATTERY_STATUS_NOT_CHARGING; -+ else -+ status = BATTERY_STATUS_DISCHARGING; -+ -+ return status; -+} -+ -+static struct simpad_battery_t simpad_battery = { -+ .battery = { -+ .get_min_voltage = simpad_get_min_voltage, -+ .get_min_current = simpad_get_min_current, -+ .get_min_charge = simpad_get_min_charge, -+ .get_max_voltage = simpad_get_max_voltage, -+ .get_max_current = simpad_get_max_current, -+ .get_max_charge = simpad_get_max_charge, -+ .get_temp = simpad_get_temp, -+ .get_voltage = simpad_get_voltage, -+ .get_current = simpad_get_current, -+ .get_charge = simpad_get_charge, -+ .get_status = simpad_get_status, -+ }, -+ .min_voltage = 0, -+ .min_current = 0, -+ .min_charge = 0, -+ .max_voltage = 0, -+ .max_current = 0, -+ .max_charge = 0, -+ -+ .min_supply = 1200, -+ .charging_led_label = 18, -+ .charging_max_label = 265, -+ .batt_full = 8300, -+ .batt_low = 7300, -+ .batt_critical = 6800, -+ .batt_empty = 6500, -+}; -+ -+ -+ -+/* -+ * UCB glue code -+ */ -+static int ucb1x00_battery_add(struct class_device *dev) -+{ -+ struct ucb1x00 *ucb = classdev_to_ucb1x00(dev); -+ simpad_battery.ucb = ucb; -+ -+ battery_class_register(&simpad_battery.battery); -+ -+ return 0; -+} -+ -+static void ucb1x00_battery_remove(struct class_device *dev) -+{ -+ return battery_class_unregister(&simpad_battery.battery); -+} -+ -+ -+static struct ucb1x00_class_interface ucb1x00_battery_interface = { -+ .interface = { -+ .add = ucb1x00_battery_add, -+ .remove = ucb1x00_battery_remove, -+ }, -+}; -+ -+ -+static int __init battery_register(void) -+{ -+ return ucb1x00_register_interface(&ucb1x00_battery_interface); -+} -+ -+static void __exit battery_unregister(void) -+{ -+ ucb1x00_unregister_interface(&ucb1x00_battery_interface); -+} -+ -+module_init(battery_register); -+module_exit(battery_unregister); -+ -+MODULE_AUTHOR("Holger Hans Peter Freyther"); -+MODULE_LICENSE("GPL"); -Index: linux-2.6.22/arch/arm/Kconfig -=================================================================== ---- linux-2.6.22.orig/arch/arm/Kconfig 2007-08-23 12:17:42.000000000 +0200 -+++ linux-2.6.22/arch/arm/Kconfig 2007-08-23 12:22:28.000000000 +0200 -@@ -1016,6 +1016,8 @@ - - source "drivers/w1/Kconfig" - -+source "drivers/power/Kconfig" -+ - source "drivers/hwmon/Kconfig" - - #source "drivers/l3/Kconfig" -Index: linux-2.6.22/drivers/Kconfig -=================================================================== ---- linux-2.6.22.orig/drivers/Kconfig 2007-08-23 12:21:27.000000000 +0200 -+++ linux-2.6.22/drivers/Kconfig 2007-08-23 12:22:03.000000000 +0200 -@@ -54,6 +54,8 @@ - - source "drivers/w1/Kconfig" - -+source "drivers/power/Kconfig" -+ - source "drivers/hwmon/Kconfig" - - source "drivers/mfd/Kconfig" -Index: linux-2.6.22/drivers/Makefile -=================================================================== ---- linux-2.6.22.orig/drivers/Makefile 2007-08-23 12:33:58.000000000 +0200 -+++ linux-2.6.22/drivers/Makefile 2007-08-23 12:34:34.000000000 +0200 -@@ -61,6 +61,7 @@ - obj-$(CONFIG_RTC_LIB) += rtc/ - obj-y += i2c/ - obj-$(CONFIG_W1) += w1/ -+obj-$(CONFIG_POWER_SUPPLY) += power/ - obj-$(CONFIG_HWMON) += hwmon/ - obj-$(CONFIG_PHONE) += telephony/ - obj-$(CONFIG_MD) += md/ -Index: linux-2.6.22/include/linux/power_supply.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.22/include/linux/power_supply.h 2007-08-23 12:37:10.000000000 +0200 -@@ -0,0 +1,175 @@ -+/* -+ * Universal power supply monitor class -+ * -+ * Copyright (c) 2007 Anton Vorontsov <cbou@mail.ru> -+ * Copyright (c) 2004 Szabolcs Gyurko -+ * Copyright (c) 2003 Ian Molton <spyro@f2s.com> -+ * -+ * Modified: 2004, Oct Szabolcs Gyurko -+ * -+ * You may use this code as per GPL version 2 -+ */ -+ -+#ifndef __LINUX_POWER_SUPPLY_H__ -+#define __LINUX_POWER_SUPPLY_H__ -+ -+#include <linux/device.h> -+#include <linux/workqueue.h> -+#include <linux/leds.h> -+ -+/* -+ * All voltages, currents, charges, energies, time and temperatures in uV, -+ * uA, uAh, uWh, seconds and tenths of degree Celsius unless otherwise -+ * stated. It's driver's job to convert its raw values to units in which -+ * this class operates. -+ */ -+ -+/* -+ * For systems where the charger determines the maximum battery capacity -+ * the min and max fields should be used to present these values to user -+ * space. Unused/unknown fields will not appear in sysfs. -+ */ -+ -+enum { -+ POWER_SUPPLY_STATUS_UNKNOWN = 0, -+ POWER_SUPPLY_STATUS_CHARGING, -+ POWER_SUPPLY_STATUS_DISCHARGING, -+ POWER_SUPPLY_STATUS_NOT_CHARGING, -+ POWER_SUPPLY_STATUS_FULL, -+}; -+ -+enum { -+ POWER_SUPPLY_HEALTH_UNKNOWN = 0, -+ POWER_SUPPLY_HEALTH_GOOD, -+ POWER_SUPPLY_HEALTH_OVERHEAT, -+ POWER_SUPPLY_HEALTH_DEAD, -+}; -+ -+enum { -+ POWER_SUPPLY_TECHNOLOGY_UNKNOWN = 0, -+ POWER_SUPPLY_TECHNOLOGY_NIMH, -+ POWER_SUPPLY_TECHNOLOGY_LION, -+ POWER_SUPPLY_TECHNOLOGY_LIPO, -+}; -+ -+enum { -+ POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN = 0, -+ POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL, -+ POWER_SUPPLY_CAPACITY_LEVEL_LOW, -+ POWER_SUPPLY_CAPACITY_LEVEL_NORMAL, -+ POWER_SUPPLY_CAPACITY_LEVEL_HIGH, -+ POWER_SUPPLY_CAPACITY_LEVEL_FULL, -+}; -+ -+enum power_supply_property { -+ /* Properties of type `int' */ -+ POWER_SUPPLY_PROP_STATUS = 0, -+ POWER_SUPPLY_PROP_HEALTH, -+ POWER_SUPPLY_PROP_PRESENT, -+ POWER_SUPPLY_PROP_ONLINE, -+ POWER_SUPPLY_PROP_TECHNOLOGY, -+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, -+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, -+ POWER_SUPPLY_PROP_VOLTAGE_NOW, -+ POWER_SUPPLY_PROP_VOLTAGE_AVG, -+ POWER_SUPPLY_PROP_CURRENT_NOW, -+ POWER_SUPPLY_PROP_CURRENT_AVG, -+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, -+ POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN, -+ POWER_SUPPLY_PROP_CHARGE_FULL, -+ POWER_SUPPLY_PROP_CHARGE_EMPTY, -+ POWER_SUPPLY_PROP_CHARGE_NOW, -+ POWER_SUPPLY_PROP_CHARGE_AVG, -+ POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, -+ POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN, -+ POWER_SUPPLY_PROP_ENERGY_FULL, -+ POWER_SUPPLY_PROP_ENERGY_EMPTY, -+ POWER_SUPPLY_PROP_ENERGY_NOW, -+ POWER_SUPPLY_PROP_ENERGY_AVG, -+ POWER_SUPPLY_PROP_CAPACITY, /* in percents! */ -+ POWER_SUPPLY_PROP_CAPACITY_LEVEL, -+ POWER_SUPPLY_PROP_TEMP, -+ POWER_SUPPLY_PROP_TEMP_AMBIENT, -+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, -+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, -+ POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, -+ POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, -+ /* Properties of type `const char *' */ -+ POWER_SUPPLY_PROP_MODEL_NAME, -+}; -+ -+enum power_supply_type { -+ POWER_SUPPLY_TYPE_BATTERY = 0, -+ POWER_SUPPLY_TYPE_UPS, -+ POWER_SUPPLY_TYPE_MAINS, -+ POWER_SUPPLY_TYPE_USB, -+}; -+ -+union power_supply_propval { -+ int intval; -+ const char *strval; -+}; -+ -+struct power_supply { -+ const char *name; -+ enum power_supply_type type; -+ enum power_supply_property *properties; -+ size_t num_properties; -+ -+ char **supplied_to; -+ size_t num_supplicants; -+ -+ int (*get_property)(struct power_supply *psy, -+ enum power_supply_property psp, -+ union power_supply_propval *val); -+ void (*external_power_changed)(struct power_supply *psy); -+ -+ /* For APM emulation, think legacy userspace. */ -+ int use_for_apm; -+ -+ /* private */ -+ struct device *dev; -+ struct work_struct changed_work; -+ -+#ifdef CONFIG_LEDS_TRIGGERS -+ struct led_trigger *charging_full_trig; -+ char *charging_full_trig_name; -+ struct led_trigger *charging_trig; -+ char *charging_trig_name; -+ struct led_trigger *full_trig; -+ char *full_trig_name; -+ struct led_trigger *online_trig; -+ char *online_trig_name; -+#endif -+}; -+ -+/* -+ * This is recommended structure to specify static power supply parameters. -+ * Generic one, parametrizable for different power supplies. Power supply -+ * class itself does not use it, but that's what implementing most platform -+ * drivers, should try reuse for consistency. -+ */ -+ -+struct power_supply_info { -+ const char *name; -+ int technology; -+ int voltage_max_design; -+ int voltage_min_design; -+ int charge_full_design; -+ int charge_empty_design; -+ int energy_full_design; -+ int energy_empty_design; -+ int use_for_apm; -+}; -+ -+extern void power_supply_changed(struct power_supply *psy); -+extern int power_supply_am_i_supplied(struct power_supply *psy); -+ -+extern int power_supply_register(struct device *parent, -+ struct power_supply *psy); -+extern void power_supply_unregister(struct power_supply *psy); -+ -+/* For APM emulation, think legacy userspace. */ -+extern struct class *power_supply_class; -+ -+#endif /* __LINUX_POWER_SUPPLY_H__ */ |