From a7d62d2e454c0ef4b398cbc3e32577aa46ea99b8 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Sun, 20 Jan 2008 16:48:44 +0000 Subject: linux-rp-2.6.23: Clean up and drop unused or now unneeded patches --- .../linux-rp-2.6.23/mmcsd_no_scr_check-r2.patch | 29 - packages/linux/linux-rp-2.6.23/pda-power.patch | 3373 -------------------- packages/linux/linux-rp-2.6.23/vt_ioctl_race.patch | 46 - .../linux/linux-rp-2.6.23/w100fb-unused-var.patch | 17 - packages/linux/linux-rp_2.6.23.bb | 35 +- 5 files changed, 17 insertions(+), 3483 deletions(-) delete mode 100644 packages/linux/linux-rp-2.6.23/mmcsd_no_scr_check-r2.patch delete mode 100644 packages/linux/linux-rp-2.6.23/pda-power.patch delete mode 100644 packages/linux/linux-rp-2.6.23/vt_ioctl_race.patch delete mode 100644 packages/linux/linux-rp-2.6.23/w100fb-unused-var.patch (limited to 'packages/linux') diff --git a/packages/linux/linux-rp-2.6.23/mmcsd_no_scr_check-r2.patch b/packages/linux/linux-rp-2.6.23/mmcsd_no_scr_check-r2.patch deleted file mode 100644 index ac2245f088..0000000000 --- a/packages/linux/linux-rp-2.6.23/mmcsd_no_scr_check-r2.patch +++ /dev/null @@ -1,29 +0,0 @@ ---- - drivers/mmc/core/sd.c | 11 ++++++----- - 1 file changed, 6 insertions(+), 5 deletions(-) - -Index: linux-2.6.23/drivers/mmc/core/sd.c -=================================================================== ---- linux-2.6.23.orig/drivers/mmc/core/sd.c 2007-10-17 11:33:26.000000000 +0200 -+++ linux-2.6.23/drivers/mmc/core/sd.c 2007-10-17 11:33:49.000000000 +0200 -@@ -173,14 +173,15 @@ - - scr_struct = UNSTUFF_BITS(resp, 60, 4); - if (scr_struct != 0) { -- printk(KERN_ERR "%s: unrecognised SCR structure version %d\n", -+ printk(KERN_WARNING "%s: unrecognised SCR structure version %d\n", - mmc_hostname(card->host), scr_struct); -- return -EINVAL; -+ scr->sda_vsn = 0; -+ scr->bus_widths = 0; -+ } else { -+ scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4); -+ scr->bus_widths = UNSTUFF_BITS(resp, 48, 4); - } - -- scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4); -- scr->bus_widths = UNSTUFF_BITS(resp, 48, 4); -- - return 0; - } - diff --git a/packages/linux/linux-rp-2.6.23/pda-power.patch b/packages/linux/linux-rp-2.6.23/pda-power.patch deleted file mode 100644 index face2f4ef2..0000000000 --- a/packages/linux/linux-rp-2.6.23/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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#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 -+ * Copyright (c) 2007 Eugeny Boger -+ * -+ * Author: Eugeny Boger -+ * -+ * 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 -+#include -+#include -+ -+#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 "); -+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 -+ * February 2007 -+ * -+ * Matt Reimer -+ * April 2004, 2005, 2007 -+ * -+ * Szabolcs Gyurko -+ * September 2004 -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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 , " -+ "Matt Reimer , " -+ "Anton Vorontsov "); -+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 -+ * -+ */ -+ -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include -+#include -+ -+#include -+ -+#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 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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 "); -+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 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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 "); -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 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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_p