From 25f12141e2be96e904239d963e25818b8854e72f Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 26 Nov 2007 00:25:45 +0300 Subject: [BATTERY] Every file should include the headers containing the prototypes for its global functions. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Anton Vorontsov --- drivers/power/power_supply_leds.c | 2 ++ drivers/power/power_supply_sysfs.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/power/power_supply_leds.c b/drivers/power/power_supply_leds.c index 7f8f3590b02..80ca28840b1 100644 --- a/drivers/power/power_supply_leds.c +++ b/drivers/power/power_supply_leds.c @@ -12,6 +12,8 @@ #include +#include "power_supply.h" + /* Battery specific LEDs triggers. */ static void power_supply_update_bat_leds(struct power_supply *psy) diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index 249f61bae63..e8ad1fd0f09 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -14,6 +14,8 @@ #include #include +#include "power_supply.h" + /* * This is because the name "current" breaks the device attr macro. * The "current" word resolves to "(get_current())" so instead of -- cgit v1.2.3-70-g09d2 From 4d24473c435c7c3ad7b43e43b70cdb16aba25443 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sat, 17 Nov 2007 19:55:58 +0900 Subject: [BATTERY] power_supply_leds: use kasprintf Use kasprintf instead of kmalloc()-strcpy()-strcat(). Cc: Anton Vorontsov Cc: David Woodhouse Signed-off-by: Akinobu Mita Signed-off-by: Anton Vorontsov --- drivers/power/power_supply_leds.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/drivers/power/power_supply_leds.c b/drivers/power/power_supply_leds.c index 80ca28840b1..fa3034f85c3 100644 --- a/drivers/power/power_supply_leds.c +++ b/drivers/power/power_supply_leds.c @@ -10,6 +10,7 @@ * You may use this code as per GPL version 2 */ +#include #include #include "power_supply.h" @@ -48,28 +49,20 @@ 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); + psy->charging_full_trig_name = kasprintf(GFP_KERNEL, + "%s-charging-or-full", psy->name); if (!psy->charging_full_trig_name) goto charging_full_failed; - psy->charging_trig_name = kmalloc(strlen(psy->name) + - sizeof("-charging"), GFP_KERNEL); + psy->charging_trig_name = kasprintf(GFP_KERNEL, + "%s-charging", psy->name); if (!psy->charging_trig_name) goto charging_failed; - psy->full_trig_name = kmalloc(strlen(psy->name) + - sizeof("-full"), GFP_KERNEL); + psy->full_trig_name = kasprintf(GFP_KERNEL, "%s-full", psy->name); 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_simple(psy->charging_trig_name, @@ -120,14 +113,10 @@ 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); + psy->online_trig_name = kasprintf(GFP_KERNEL, "%s-online", psy->name); 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; -- cgit v1.2.3-70-g09d2 From 8efe444038a205e79b38b7ad03878824901849a8 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Wed, 12 Dec 2007 14:12:56 -0500 Subject: power: remove POWER_SUPPLY_PROP_CAPACITY_LEVEL The CAPACITY_LEVEL stuff defines various levels of charge; however, what is the difference between them? What differentiates between HIGH and NORMAL, LOW and CRITICAL, etc? As it appears that these are fairly arbitrary, we end up making such policy decisions in the kernel (or in hardware). This is the sort of decision that should be made in userspace, not in the kernel. If the hardware does not support _CAPACITY and it cannot be easily calculated, then perhaps the driver should register a custom CAPACITY_LEVEL attribute; however, userspace should not become accustomed to looking for such a thing, and we should certainly not encourage drivers to provide CAPACITY_LEVEL stubs. The following removes support for POWER_SUPPLY_PROP_CAPACITY_LEVEL. The OLPC battery driver is the only driver making use of this, so it's removed from there as well. Signed-off-by: Andres Salomon Signed-off-by: David Woodhouse --- Documentation/power_supply_class.txt | 2 -- drivers/power/olpc_battery.c | 9 --------- drivers/power/power_supply_sysfs.c | 6 ------ include/linux/power_supply.h | 10 ---------- 4 files changed, 27 deletions(-) diff --git a/Documentation/power_supply_class.txt b/Documentation/power_supply_class.txt index 9758cf433c0..a032c316b3b 100644 --- a/Documentation/power_supply_class.txt +++ b/Documentation/power_supply_class.txt @@ -100,8 +100,6 @@ age)". I.e. these attributes represents real thresholds, not design values. ENERGY_FULL, ENERGY_EMPTY - same as above but for energy. CAPACITY - capacity in percents. -CAPACITY_LEVEL - capacity level. This corresponds to -POWER_SUPPLY_CAPACITY_LEVEL_*. TEMP - temperature of the power supply. TEMP_AMBIENT - ambient temperature. diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index c998e68d060..af7a231092a 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c @@ -226,14 +226,6 @@ static int olpc_bat_get_property(struct power_supply *psy, return ret; val->intval = ec_byte; break; - case POWER_SUPPLY_PROP_CAPACITY_LEVEL: - if (ec_byte & BAT_STAT_FULL) - val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL; - else if (ec_byte & BAT_STAT_LOW) - val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW; - else - val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; - break; case POWER_SUPPLY_PROP_TEMP: ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2); if (ret) @@ -265,7 +257,6 @@ static enum power_supply_property olpc_bat_props[] = { 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, POWER_SUPPLY_PROP_MANUFACTURER, diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index e8ad1fd0f09..7a2163fa61c 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -50,9 +50,6 @@ static ssize_t power_supply_show_property(struct device *dev, static char *technology_text[] = { "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd" }; - 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; @@ -73,9 +70,6 @@ static ssize_t power_supply_show_property(struct device *dev, 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); diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 606c0957997..358b38d09fe 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -56,15 +56,6 @@ enum { POWER_SUPPLY_TECHNOLOGY_NiCd, }; -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, @@ -91,7 +82,6 @@ enum power_supply_property { 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, -- cgit v1.2.3-70-g09d2 From 839dc9f105c0d856f9a0be48fb3bd0982ff5df5b Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Wed, 12 Dec 2007 14:12:59 -0500 Subject: power: fix incorrect unregistration in power_supply_create_attrs error path In power_supply_create_attrs(), we create static attributes as referenced by power_supply_static_attrs[i]. After that, if we fail, we unregister via power_supply_static_attrs[psy->properties[i]]. This is incorrect, as psy->properties has absolutely no bearing on static attribs. This patch fixes it to unregister the correct attrib. Another line which was unnecessarily line wrapped is also unwrapped. Signed-off-by: Andres Salomon Signed-off-by: David Woodhouse --- drivers/power/power_supply_sysfs.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index 7a2163fa61c..bab591ba785 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -155,8 +155,7 @@ dynamics_failed: &power_supply_attrs[psy->properties[j]]); statics_failed: while (i--) - device_remove_file(psy->dev, - &power_supply_static_attrs[psy->properties[i]]); + device_remove_file(psy->dev, &power_supply_static_attrs[i]); succeed: return rc; } @@ -166,8 +165,7 @@ 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]); + device_remove_file(psy->dev, &power_supply_static_attrs[i]); for (i = 0; i < psy->num_properties; i++) device_remove_file(psy->dev, -- cgit v1.2.3-70-g09d2 From 9ef45106261e802f9d80bf0bc652124b42b1f344 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 7 Jan 2008 04:12:39 +0300 Subject: pda_power: only register available psu Currently pda-power adds both ac and usb power supply units. This patch fixes it so that psu are added only if they are enabled. Signed-off-by: Dmitry Baryshkov Signed-off-by: Anton Vorontsov --- drivers/power/pda_power.c | 80 ++++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c index c058f285be1..d98622f9f31 100644 --- a/drivers/power/pda_power.c +++ b/drivers/power/pda_power.c @@ -168,66 +168,74 @@ static int pda_power_probe(struct platform_device *pdev) 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; - } + if (pdata->is_ac_online) { + 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 ac_supply_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 (ac_irq) { - ret = request_irq(ac_irq->start, power_changed_isr, - get_irq_flags(ac_irq), ac_irq->name, - &pda_power_supplies[0]); + if (pdata->is_usb_online) { + ret = power_supply_register(&pdev->dev, &pda_power_supplies[1]); if (ret) { - dev_err(dev, "request ac irq failed\n"); - goto ac_irq_failed; + dev_err(dev, "failed to register %s power supply\n", + pda_power_supplies[1].name); + goto usb_supply_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; + 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; + return 0; usb_irq_failed: - if (ac_irq) + if (pdata->is_usb_online) + power_supply_unregister(&pda_power_supplies[1]); +usb_supply_failed: + if (pdata->is_ac_online && 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: + if (pdata->is_ac_online) + power_supply_unregister(&pda_power_supplies[0]); +ac_supply_failed: noirqs: wrongid: -success: return ret; } static int pda_power_remove(struct platform_device *pdev) { - if (usb_irq) + if (pdata->is_usb_online && usb_irq) free_irq(usb_irq->start, &pda_power_supplies[1]); - if (ac_irq) + if (pdata->is_ac_online && 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]); + if (pdata->is_usb_online) + power_supply_unregister(&pda_power_supplies[1]); + if (pdata->is_ac_online) + power_supply_unregister(&pda_power_supplies[0]); return 0; } -- cgit v1.2.3-70-g09d2 From c7cc930f9a5c26385a08cd7dc28cb5e3ed186d72 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 7 Jan 2008 04:12:41 +0300 Subject: power_supply: add few more values and props Add LiMn (one of the most common for small non-rechargable batteries) battery technology and voltage_min/_max properties support. Signed-off-by: Dmitry Baryshkov Signed-off-by: Anton Vorontsov --- Documentation/power_supply_class.txt | 4 ++++ drivers/power/power_supply_sysfs.c | 5 ++++- include/linux/power_supply.h | 3 +++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Documentation/power_supply_class.txt b/Documentation/power_supply_class.txt index a032c316b3b..a8686e5a685 100644 --- a/Documentation/power_supply_class.txt +++ b/Documentation/power_supply_class.txt @@ -87,6 +87,10 @@ batteries use voltage for very approximated calculation of capacity. Battery driver also can use this attribute just to inform userspace about maximal and minimal voltage thresholds of a given battery. +VOLTAGE_MAX, VOLTAGE_MIN - same as _DESIGN voltage values except that +these ones should be used if hardware could only guess (measure and +retain) the thresholds of a given power supply. + CHARGE_FULL_DESIGN, CHARGE_EMPTY_DESIGN - design charge values, when battery considered full/empty. diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index bab591ba785..d4824840c5b 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c @@ -48,7 +48,8 @@ static ssize_t power_supply_show_property(struct device *dev, "Unspecified failure" }; static char *technology_text[] = { - "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd" + "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd", + "LiMn" }; ssize_t ret; struct power_supply *psy = dev_get_drvdata(dev); @@ -84,6 +85,8 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(present), POWER_SUPPLY_ATTR(online), POWER_SUPPLY_ATTR(technology), + POWER_SUPPLY_ATTR(voltage_max), + POWER_SUPPLY_ATTR(voltage_min), POWER_SUPPLY_ATTR(voltage_max_design), POWER_SUPPLY_ATTR(voltage_min_design), POWER_SUPPLY_ATTR(voltage_now), diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 358b38d09fe..5cbf3e37101 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -54,6 +54,7 @@ enum { POWER_SUPPLY_TECHNOLOGY_LIPO, POWER_SUPPLY_TECHNOLOGY_LiFe, POWER_SUPPLY_TECHNOLOGY_NiCd, + POWER_SUPPLY_TECHNOLOGY_LiMn, }; enum power_supply_property { @@ -63,6 +64,8 @@ enum power_supply_property { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_VOLTAGE_MAX, + POWER_SUPPLY_PROP_VOLTAGE_MIN, POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, POWER_SUPPLY_PROP_VOLTAGE_NOW, -- cgit v1.2.3-70-g09d2 From 8f8e9b387e07cbb96f10936cc455229d7aff4790 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 13 Jan 2008 02:35:43 +0300 Subject: pda_power: add suspend/resume support Add suspend/resume/wakeup support for pda_power. Signed-off-by: Dmitry Baryshkov Signed-off-by: Anton Vorontsov --- drivers/power/pda_power.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c index d98622f9f31..35dc25973f3 100644 --- a/drivers/power/pda_power.c +++ b/drivers/power/pda_power.c @@ -207,6 +207,8 @@ static int pda_power_probe(struct platform_device *pdev) } } + device_init_wakeup(&pdev->dev, 1); + return 0; usb_irq_failed: @@ -239,12 +241,43 @@ static int pda_power_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int pda_power_suspend(struct platform_device *pdev, pm_message_t state) +{ + if (device_may_wakeup(&pdev->dev)) { + if (ac_irq) + enable_irq_wake(ac_irq->start); + if (usb_irq) + enable_irq_wake(usb_irq->start); + } + + return 0; +} + +static int pda_power_resume(struct platform_device *pdev) +{ + if (device_may_wakeup(&pdev->dev)) { + if (usb_irq) + disable_irq_wake(usb_irq->start); + if (ac_irq) + disable_irq_wake(ac_irq->start); + } + + return 0; +} +#else +#define pda_power_suspend NULL +#define pda_power_resume NULL +#endif /* CONFIG_PM */ + static struct platform_driver pda_power_pdrv = { .driver = { .name = "pda-power", }, .probe = pda_power_probe, .remove = pda_power_remove, + .suspend = pda_power_suspend, + .resume = pda_power_resume, }; static int __init pda_power_init(void) -- cgit v1.2.3-70-g09d2 From dffd28a13a439e672c735d3fc87844d28cbacc65 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sun, 13 Jan 2008 02:39:16 +0300 Subject: apm_power: support using VOLTAGE_* properties for apm calculations It's pretty dummy, but useful for batteries for which we can only get voltages. Signed-off-by: Dmitry Baryshkov Signed-off-by: Anton Vorontsov --- drivers/power/apm_power.c | 91 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 70 insertions(+), 21 deletions(-) diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c index 7e29b90a4f6..a832a9a05c6 100644 --- a/drivers/power/apm_power.c +++ b/drivers/power/apm_power.c @@ -13,7 +13,7 @@ #include #include -static DEFINE_MUTEX(apm_mutex); + #define PSY_PROP(psy, prop, val) psy->get_property(psy, \ POWER_SUPPLY_PROP_##prop, val) @@ -22,8 +22,15 @@ static DEFINE_MUTEX(apm_mutex); #define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val) +static DEFINE_MUTEX(apm_mutex); static struct power_supply *main_battery; +enum apm_source { + SOURCE_ENERGY, + SOURCE_CHARGE, + SOURCE_VOLTAGE, +}; + struct find_bat_param { struct power_supply *main; struct power_supply *bat; @@ -107,7 +114,7 @@ static void find_main_battery(void) } } -static int calculate_time(int status, int using_charge) +static int do_calculate_time(int status, enum apm_source source) { union power_supply_propval full; union power_supply_propval empty; @@ -126,20 +133,34 @@ static int calculate_time(int status, int using_charge) return -1; } - if (using_charge) { + switch (source) { + case SOURCE_CHARGE: full_prop = POWER_SUPPLY_PROP_CHARGE_FULL; full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN; empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; cur_avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG; cur_now_prop = POWER_SUPPLY_PROP_CHARGE_NOW; - } else { + break; + case SOURCE_ENERGY: full_prop = POWER_SUPPLY_PROP_ENERGY_FULL; full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN; empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY; empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; cur_avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG; cur_now_prop = POWER_SUPPLY_PROP_ENERGY_NOW; + break; + case SOURCE_VOLTAGE: + full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX; + full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN; + empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN; + empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN; + cur_avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG; + cur_now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW; + break; + default: + printk(KERN_ERR "Unsupported source: %d\n", source); + return -1; } if (_MPSY_PROP(full_prop, &full)) { @@ -166,7 +187,26 @@ static int calculate_time(int status, int using_charge) return -((cur.intval - empty.intval) * 60L) / I.intval; } -static int calculate_capacity(int using_charge) +static int calculate_time(int status) +{ + int time; + + time = do_calculate_time(status, SOURCE_ENERGY); + if (time != -1) + return time; + + time = do_calculate_time(status, SOURCE_CHARGE); + if (time != -1) + return time; + + time = do_calculate_time(status, SOURCE_VOLTAGE); + if (time != -1) + return time; + + return -1; +} + +static int calculate_capacity(enum apm_source source) { enum power_supply_property full_prop, empty_prop; enum power_supply_property full_design_prop, empty_design_prop; @@ -174,20 +214,33 @@ static int calculate_capacity(int using_charge) union power_supply_propval empty, full, cur; int ret; - if (using_charge) { + switch (source) { + case SOURCE_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 { + break; + case SOURCE_ENERGY: 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; + case SOURCE_VOLTAGE: + full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX; + empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN; + full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN; + empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN; + now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW; + avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG; + break; + default: + printk(KERN_ERR "Unsupported source: %d\n", source); + return -1; } if (_MPSY_PROP(full_prop, &full)) { @@ -254,10 +307,12 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info) info->battery_life = capacity.intval; } else { /* try calculate using energy */ - info->battery_life = calculate_capacity(0); + info->battery_life = calculate_capacity(SOURCE_ENERGY); /* if failed try calculate using charge instead */ if (info->battery_life == -1) - info->battery_life = calculate_capacity(1); + info->battery_life = calculate_capacity(SOURCE_CHARGE); + if (info->battery_life == -1) + info->battery_life = calculate_capacity(SOURCE_VOLTAGE); } /* charging status */ @@ -280,22 +335,16 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info) if (status.intval == POWER_SUPPLY_STATUS_CHARGING) { if (!MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full) || - !MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full)) { + !MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full)) info->time = time_to_full.intval / 60; - } else { - info->time = calculate_time(status.intval, 0); - if (info->time == -1) - info->time = calculate_time(status.intval, 1); - } + else + info->time = calculate_time(status.intval); } else { if (!MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty) || - !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty)) { + !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty)) info->time = time_to_empty.intval / 60; - } else { - info->time = calculate_time(status.intval, 0); - if (info->time == -1) - info->time = calculate_time(status.intval, 1); - } + else + info->time = calculate_time(status.intval); } mutex_unlock(&apm_mutex); -- cgit v1.2.3-70-g09d2 From bfde2662ae8c7f0054990e59456718761a352651 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Sun, 13 Jan 2008 02:39:17 +0300 Subject: pda_power: various cleanups - handle spurious interrupts correctly; - get rid of pda_power_supplies array, use two variables instead; - factor out psy_changed() function, it will be used for polling. Signed-off-by: Anton Vorontsov --- drivers/power/pda_power.c | 147 +++++++++++++++++++++++++++++----------------- 1 file changed, 92 insertions(+), 55 deletions(-) diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c index 35dc25973f3..d6c6dbc20e2 100644 --- a/drivers/power/pda_power.c +++ b/drivers/power/pda_power.c @@ -33,6 +33,16 @@ static struct resource *ac_irq, *usb_irq; static struct timer_list charger_timer; static struct timer_list supply_timer; +enum { + PDA_PSY_OFFLINE = 0, + PDA_PSY_ONLINE = 1, + PDA_PSY_TO_CHANGE, +}; +static int new_ac_status = -1; +static int new_usb_status = -1; +static int ac_status = -1; +static int usb_status = -1; + static int pda_power_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) @@ -61,36 +71,44 @@ static char *pda_power_supplied_to[] = { "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 struct power_supply pda_psy_ac = { + .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, +}; + +static struct power_supply pda_psy_usb = { + .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_status(void) +{ + if (pdata->is_ac_online) + new_ac_status = !!pdata->is_ac_online(); + + if (pdata->is_usb_online) + new_usb_status = !!pdata->is_usb_online(); +} + static void update_charger(void) { if (!pdata->set_charge) return; - if (pdata->is_ac_online && pdata->is_ac_online()) { + if (new_ac_status > 0) { dev_dbg(dev, "charger on (AC)\n"); pdata->set_charge(PDA_POWER_CHARGE_AC); - } else if (pdata->is_usb_online && pdata->is_usb_online()) { + } else if (new_usb_status > 0) { dev_dbg(dev, "charger on (USB)\n"); pdata->set_charge(PDA_POWER_CHARGE_USB); } else { @@ -99,31 +117,53 @@ static void update_charger(void) } } -static void supply_timer_func(unsigned long power_supply_ptr) +static void supply_timer_func(unsigned long unused) { - void *power_supply = (void *)power_supply_ptr; + if (ac_status == PDA_PSY_TO_CHANGE) { + ac_status = new_ac_status; + power_supply_changed(&pda_psy_ac); + } - power_supply_changed(power_supply); + if (usb_status == PDA_PSY_TO_CHANGE) { + usb_status = new_usb_status; + power_supply_changed(&pda_psy_usb); + } } -static void charger_timer_func(unsigned long power_supply_ptr) +static void psy_changed(void) { update_charger(); - /* Okay, charger set. Now wait a bit before notifying supplicants, - * charge power should stabilize. */ - supply_timer.data = power_supply_ptr; + /* + * Okay, charger set. Now wait a bit before notifying supplicants, + * charge power should stabilize. + */ mod_timer(&supply_timer, jiffies + msecs_to_jiffies(pdata->wait_for_charger)); } +static void charger_timer_func(unsigned long unused) +{ + update_status(); + psy_changed(); +} + static irqreturn_t power_changed_isr(int irq, void *power_supply) { - /* Wait a bit before reading ac/usb line status and setting charger, - * because ac/usb status readings may lag from irq. */ - charger_timer.data = (unsigned long)power_supply; + if (power_supply == &pda_psy_ac) + ac_status = PDA_PSY_TO_CHANGE; + else if (power_supply == &pda_psy_usb) + usb_status = PDA_PSY_TO_CHANGE; + else + return IRQ_NONE; + + /* + * Wait a bit before reading ac/usb line status and setting charger, + * because ac/usb status readings may lag from irq. + */ mod_timer(&charger_timer, jiffies + msecs_to_jiffies(pdata->wait_for_status)); + return IRQ_HANDLED; } @@ -142,6 +182,7 @@ static int pda_power_probe(struct platform_device *pdev) pdata = pdev->dev.platform_data; + update_status(); update_charger(); if (!pdata->wait_for_status) @@ -155,31 +196,26 @@ static int pda_power_probe(struct platform_device *pdev) 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; + pda_psy_ac.supplied_to = pdata->supplied_to; + pda_psy_ac.num_supplicants = pdata->num_supplicants; + pda_psy_usb.supplied_to = pdata->supplied_to; + pda_psy_usb.num_supplicants = pdata->num_supplicants; } if (pdata->is_ac_online) { - ret = power_supply_register(&pdev->dev, &pda_power_supplies[0]); + ret = power_supply_register(&pdev->dev, &pda_psy_ac); if (ret) { dev_err(dev, "failed to register %s power supply\n", - pda_power_supplies[0].name); + pda_psy_ac.name); goto ac_supply_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]); + &pda_psy_ac); if (ret) { dev_err(dev, "request ac irq failed\n"); goto ac_irq_failed; @@ -188,18 +224,17 @@ static int pda_power_probe(struct platform_device *pdev) } if (pdata->is_usb_online) { - ret = power_supply_register(&pdev->dev, &pda_power_supplies[1]); + ret = power_supply_register(&pdev->dev, &pda_psy_usb); if (ret) { dev_err(dev, "failed to register %s power supply\n", - pda_power_supplies[1].name); + pda_psy_usb.name); goto usb_supply_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]); + usb_irq->name, &pda_psy_usb); if (ret) { dev_err(dev, "request usb irq failed\n"); goto usb_irq_failed; @@ -213,15 +248,14 @@ static int pda_power_probe(struct platform_device *pdev) usb_irq_failed: if (pdata->is_usb_online) - power_supply_unregister(&pda_power_supplies[1]); + power_supply_unregister(&pda_psy_usb); usb_supply_failed: if (pdata->is_ac_online && ac_irq) - free_irq(ac_irq->start, &pda_power_supplies[0]); + free_irq(ac_irq->start, &pda_psy_ac); ac_irq_failed: if (pdata->is_ac_online) - power_supply_unregister(&pda_power_supplies[0]); + power_supply_unregister(&pda_psy_ac); ac_supply_failed: -noirqs: wrongid: return ret; } @@ -229,15 +263,18 @@ wrongid: static int pda_power_remove(struct platform_device *pdev) { if (pdata->is_usb_online && usb_irq) - free_irq(usb_irq->start, &pda_power_supplies[1]); + free_irq(usb_irq->start, &pda_psy_usb); if (pdata->is_ac_online && ac_irq) - free_irq(ac_irq->start, &pda_power_supplies[0]); + free_irq(ac_irq->start, &pda_psy_ac); + del_timer_sync(&charger_timer); del_timer_sync(&supply_timer); + if (pdata->is_usb_online) - power_supply_unregister(&pda_power_supplies[1]); + power_supply_unregister(&pda_psy_usb); if (pdata->is_ac_online) - power_supply_unregister(&pda_power_supplies[0]); + power_supply_unregister(&pda_psy_ac); + return 0; } -- cgit v1.2.3-70-g09d2 From c3caebad7427f62fe77621bae1bd1da0e56a130d Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Sun, 13 Jan 2008 02:44:20 +0300 Subject: pda_power: implement polling Signed-off-by: Anton Vorontsov --- drivers/power/pda_power.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- include/linux/pda_power.h | 1 + 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c index d6c6dbc20e2..c8aa55b81fd 100644 --- a/drivers/power/pda_power.c +++ b/drivers/power/pda_power.c @@ -32,6 +32,8 @@ 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 struct timer_list polling_timer; +static int polling; enum { PDA_PSY_OFFLINE = 0, @@ -167,6 +169,31 @@ static irqreturn_t power_changed_isr(int irq, void *power_supply) return IRQ_HANDLED; } +static void polling_timer_func(unsigned long unused) +{ + int changed = 0; + + dev_dbg(dev, "polling...\n"); + + update_status(); + + if (!ac_irq && new_ac_status != ac_status) { + ac_status = PDA_PSY_TO_CHANGE; + changed = 1; + } + + if (!usb_irq && new_usb_status != usb_status) { + usb_status = PDA_PSY_TO_CHANGE; + changed = 1; + } + + if (changed) + psy_changed(); + + mod_timer(&polling_timer, + jiffies + msecs_to_jiffies(pdata->polling_interval)); +} + static int pda_power_probe(struct platform_device *pdev) { int ret = 0; @@ -191,6 +218,9 @@ static int pda_power_probe(struct platform_device *pdev) if (!pdata->wait_for_charger) pdata->wait_for_charger = 500; + if (!pdata->polling_interval) + pdata->polling_interval = 2000; + setup_timer(&charger_timer, charger_timer_func, 0); setup_timer(&supply_timer, supply_timer_func, 0); @@ -220,6 +250,8 @@ static int pda_power_probe(struct platform_device *pdev) dev_err(dev, "request ac irq failed\n"); goto ac_irq_failed; } + } else { + polling = 1; } } @@ -239,10 +271,20 @@ static int pda_power_probe(struct platform_device *pdev) dev_err(dev, "request usb irq failed\n"); goto usb_irq_failed; } + } else { + polling = 1; } } - device_init_wakeup(&pdev->dev, 1); + if (polling) { + dev_dbg(dev, "will poll for status\n"); + setup_timer(&polling_timer, polling_timer_func, 0); + mod_timer(&polling_timer, + jiffies + msecs_to_jiffies(pdata->polling_interval)); + } + + if (ac_irq || usb_irq) + device_init_wakeup(&pdev->dev, 1); return 0; @@ -267,6 +309,8 @@ static int pda_power_remove(struct platform_device *pdev) if (pdata->is_ac_online && ac_irq) free_irq(ac_irq->start, &pda_psy_ac); + if (polling) + del_timer_sync(&polling_timer); del_timer_sync(&charger_timer); del_timer_sync(&supply_timer); diff --git a/include/linux/pda_power.h b/include/linux/pda_power.h index 1375f15797e..225beb13680 100644 --- a/include/linux/pda_power.h +++ b/include/linux/pda_power.h @@ -26,6 +26,7 @@ struct pda_power_pdata { unsigned int wait_for_status; /* msecs, default is 500 */ unsigned int wait_for_charger; /* msecs, default is 500 */ + unsigned int polling_interval; /* msecs, default is 2000 */ }; #endif /* __PDA_POWER_H__ */ -- cgit v1.2.3-70-g09d2 From ae4bb152901e406074ae2a205e1c42941a46bbaf Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Sun, 13 Jan 2008 02:44:54 +0300 Subject: MAINTAINERS: remove kernel-discuss@handhelds.org list kernel-discuss at handhelds.org is down for months, and nobody knows why. So remove it for now. Signed-off-by: Anton Vorontsov --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 91082e60d28..61787801244 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3053,7 +3053,6 @@ M: cbou@mail.ru P: David Woodhouse M: dwmw2@infradead.org L: linux-kernel@vger.kernel.org -L: kernel-discuss@handhelds.org T: git git.infradead.org/battery-2.6.git S: Maintained -- cgit v1.2.3-70-g09d2 From e91926e9ea9073d8ce95b74602e8c2d775f5a793 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Sun, 13 Jan 2008 02:44:54 +0300 Subject: apm_power: check I.intval for zero value, we use it as the divisor Signed-off-by: Anton Vorontsov --- drivers/power/apm_power.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c index a832a9a05c6..a4892275659 100644 --- a/drivers/power/apm_power.c +++ b/drivers/power/apm_power.c @@ -133,6 +133,9 @@ static int do_calculate_time(int status, enum apm_source source) return -1; } + if (!I.intval) + return 0; + switch (source) { case SOURCE_CHARGE: full_prop = POWER_SUPPLY_PROP_CHARGE_FULL; -- cgit v1.2.3-70-g09d2