aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-02-01 23:13:05 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2008-02-01 23:13:05 -0500
commitae9458d6a0956aa21cb49e1251e35a8d4dacbe6e (patch)
tree98c162c79113bc2bd748a3ad5b6fb5ba66139751
parent63e9b66e29357dd12e8b1d3ebf7036e7591f81e3 (diff)
parente91926e9ea9073d8ce95b74602e8c2d775f5a793 (diff)
Merge git://git.infradead.org/battery-2.6
* git://git.infradead.org/battery-2.6: apm_power: check I.intval for zero value, we use it as the divisor MAINTAINERS: remove kernel-discuss@handhelds.org list pda_power: implement polling pda_power: various cleanups apm_power: support using VOLTAGE_* properties for apm calculations pda_power: add suspend/resume support power_supply: add few more values and props pda_power: only register available psu power: fix incorrect unregistration in power_supply_create_attrs error path power: remove POWER_SUPPLY_PROP_CAPACITY_LEVEL [BATTERY] power_supply_leds: use kasprintf [BATTERY] Every file should include the headers containing the prototypes for its global functions.
-rw-r--r--Documentation/power_supply_class.txt6
-rw-r--r--MAINTAINERS1
-rw-r--r--drivers/power/apm_power.c94
-rw-r--r--drivers/power/olpc_battery.c9
-rw-r--r--drivers/power/pda_power.c282
-rw-r--r--drivers/power/power_supply_leds.c27
-rw-r--r--drivers/power/power_supply_sysfs.c19
-rw-r--r--include/linux/pda_power.h1
-rw-r--r--include/linux/power_supply.h13
9 files changed, 300 insertions, 152 deletions
diff --git a/Documentation/power_supply_class.txt b/Documentation/power_supply_class.txt
index 9758cf433c06..a8686e5a6857 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.
87Battery driver also can use this attribute just to inform userspace 87Battery driver also can use this attribute just to inform userspace
88about maximal and minimal voltage thresholds of a given battery. 88about maximal and minimal voltage thresholds of a given battery.
89 89
90VOLTAGE_MAX, VOLTAGE_MIN - same as _DESIGN voltage values except that
91these ones should be used if hardware could only guess (measure and
92retain) the thresholds of a given power supply.
93
90CHARGE_FULL_DESIGN, CHARGE_EMPTY_DESIGN - design charge values, when 94CHARGE_FULL_DESIGN, CHARGE_EMPTY_DESIGN - design charge values, when
91battery considered full/empty. 95battery considered full/empty.
92 96
@@ -100,8 +104,6 @@ age)". I.e. these attributes represents real thresholds, not design values.
100ENERGY_FULL, ENERGY_EMPTY - same as above but for energy. 104ENERGY_FULL, ENERGY_EMPTY - same as above but for energy.
101 105
102CAPACITY - capacity in percents. 106CAPACITY - capacity in percents.
103CAPACITY_LEVEL - capacity level. This corresponds to
104POWER_SUPPLY_CAPACITY_LEVEL_*.
105 107
106TEMP - temperature of the power supply. 108TEMP - temperature of the power supply.
107TEMP_AMBIENT - ambient temperature. 109TEMP_AMBIENT - ambient temperature.
diff --git a/MAINTAINERS b/MAINTAINERS
index 6cae13718925..58b16038baea 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3053,7 +3053,6 @@ M: cbou@mail.ru
3053P: David Woodhouse 3053P: David Woodhouse
3054M: dwmw2@infradead.org 3054M: dwmw2@infradead.org
3055L: linux-kernel@vger.kernel.org 3055L: linux-kernel@vger.kernel.org
3056L: kernel-discuss@handhelds.org
3057T: git git.infradead.org/battery-2.6.git 3056T: git git.infradead.org/battery-2.6.git
3058S: Maintained 3057S: Maintained
3059 3058
diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c
index 7e29b90a4f63..a4892275659d 100644
--- a/drivers/power/apm_power.c
+++ b/drivers/power/apm_power.c
@@ -13,7 +13,7 @@
13#include <linux/power_supply.h> 13#include <linux/power_supply.h>
14#include <linux/apm-emulation.h> 14#include <linux/apm-emulation.h>
15 15
16static DEFINE_MUTEX(apm_mutex); 16
17#define PSY_PROP(psy, prop, val) psy->get_property(psy, \ 17#define PSY_PROP(psy, prop, val) psy->get_property(psy, \
18 POWER_SUPPLY_PROP_##prop, val) 18 POWER_SUPPLY_PROP_##prop, val)
19 19
@@ -22,8 +22,15 @@ static DEFINE_MUTEX(apm_mutex);
22 22
23#define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val) 23#define MPSY_PROP(prop, val) _MPSY_PROP(POWER_SUPPLY_PROP_##prop, val)
24 24
25static DEFINE_MUTEX(apm_mutex);
25static struct power_supply *main_battery; 26static struct power_supply *main_battery;
26 27
28enum apm_source {
29 SOURCE_ENERGY,
30 SOURCE_CHARGE,
31 SOURCE_VOLTAGE,
32};
33
27struct find_bat_param { 34struct find_bat_param {
28 struct power_supply *main; 35 struct power_supply *main;
29 struct power_supply *bat; 36 struct power_supply *bat;
@@ -107,7 +114,7 @@ static void find_main_battery(void)
107 } 114 }
108} 115}
109 116
110static int calculate_time(int status, int using_charge) 117static int do_calculate_time(int status, enum apm_source source)
111{ 118{
112 union power_supply_propval full; 119 union power_supply_propval full;
113 union power_supply_propval empty; 120 union power_supply_propval empty;
@@ -126,20 +133,37 @@ static int calculate_time(int status, int using_charge)
126 return -1; 133 return -1;
127 } 134 }
128 135
129 if (using_charge) { 136 if (!I.intval)
137 return 0;
138
139 switch (source) {
140 case SOURCE_CHARGE:
130 full_prop = POWER_SUPPLY_PROP_CHARGE_FULL; 141 full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
131 full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN; 142 full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
132 empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; 143 empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
133 empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; 144 empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
134 cur_avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG; 145 cur_avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
135 cur_now_prop = POWER_SUPPLY_PROP_CHARGE_NOW; 146 cur_now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
136 } else { 147 break;
148 case SOURCE_ENERGY:
137 full_prop = POWER_SUPPLY_PROP_ENERGY_FULL; 149 full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
138 full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN; 150 full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
139 empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY; 151 empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
140 empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; 152 empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
141 cur_avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG; 153 cur_avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
142 cur_now_prop = POWER_SUPPLY_PROP_ENERGY_NOW; 154 cur_now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
155 break;
156 case SOURCE_VOLTAGE:
157 full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX;
158 full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN;
159 empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN;
160 empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN;
161 cur_avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG;
162 cur_now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW;
163 break;
164 default:
165 printk(KERN_ERR "Unsupported source: %d\n", source);
166 return -1;
143 } 167 }
144 168
145 if (_MPSY_PROP(full_prop, &full)) { 169 if (_MPSY_PROP(full_prop, &full)) {
@@ -166,7 +190,26 @@ static int calculate_time(int status, int using_charge)
166 return -((cur.intval - empty.intval) * 60L) / I.intval; 190 return -((cur.intval - empty.intval) * 60L) / I.intval;
167} 191}
168 192
169static int calculate_capacity(int using_charge) 193static int calculate_time(int status)
194{
195 int time;
196
197 time = do_calculate_time(status, SOURCE_ENERGY);
198 if (time != -1)
199 return time;
200
201 time = do_calculate_time(status, SOURCE_CHARGE);
202 if (time != -1)
203 return time;
204
205 time = do_calculate_time(status, SOURCE_VOLTAGE);
206 if (time != -1)
207 return time;
208
209 return -1;
210}
211
212static int calculate_capacity(enum apm_source source)
170{ 213{
171 enum power_supply_property full_prop, empty_prop; 214 enum power_supply_property full_prop, empty_prop;
172 enum power_supply_property full_design_prop, empty_design_prop; 215 enum power_supply_property full_design_prop, empty_design_prop;
@@ -174,20 +217,33 @@ static int calculate_capacity(int using_charge)
174 union power_supply_propval empty, full, cur; 217 union power_supply_propval empty, full, cur;
175 int ret; 218 int ret;
176 219
177 if (using_charge) { 220 switch (source) {
221 case SOURCE_CHARGE:
178 full_prop = POWER_SUPPLY_PROP_CHARGE_FULL; 222 full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
179 empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY; 223 empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
180 full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN; 224 full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
181 empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN; 225 empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN;
182 now_prop = POWER_SUPPLY_PROP_CHARGE_NOW; 226 now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
183 avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG; 227 avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
184 } else { 228 break;
229 case SOURCE_ENERGY:
185 full_prop = POWER_SUPPLY_PROP_ENERGY_FULL; 230 full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
186 empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY; 231 empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
187 full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN; 232 full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
188 empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN; 233 empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN;
189 now_prop = POWER_SUPPLY_PROP_ENERGY_NOW; 234 now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
190 avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG; 235 avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
236 case SOURCE_VOLTAGE:
237 full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX;
238 empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN;
239 full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN;
240 empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN;
241 now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW;
242 avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG;
243 break;
244 default:
245 printk(KERN_ERR "Unsupported source: %d\n", source);
246 return -1;
191 } 247 }
192 248
193 if (_MPSY_PROP(full_prop, &full)) { 249 if (_MPSY_PROP(full_prop, &full)) {
@@ -254,10 +310,12 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
254 info->battery_life = capacity.intval; 310 info->battery_life = capacity.intval;
255 } else { 311 } else {
256 /* try calculate using energy */ 312 /* try calculate using energy */
257 info->battery_life = calculate_capacity(0); 313 info->battery_life = calculate_capacity(SOURCE_ENERGY);
258 /* if failed try calculate using charge instead */ 314 /* if failed try calculate using charge instead */
259 if (info->battery_life == -1) 315 if (info->battery_life == -1)
260 info->battery_life = calculate_capacity(1); 316 info->battery_life = calculate_capacity(SOURCE_CHARGE);
317 if (info->battery_life == -1)
318 info->battery_life = calculate_capacity(SOURCE_VOLTAGE);
261 } 319 }
262 320
263 /* charging status */ 321 /* charging status */
@@ -280,22 +338,16 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
280 338
281 if (status.intval == POWER_SUPPLY_STATUS_CHARGING) { 339 if (status.intval == POWER_SUPPLY_STATUS_CHARGING) {
282 if (!MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full) || 340 if (!MPSY_PROP(TIME_TO_FULL_AVG, &time_to_full) ||
283 !MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full)) { 341 !MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full))
284 info->time = time_to_full.intval / 60; 342 info->time = time_to_full.intval / 60;
285 } else { 343 else
286 info->time = calculate_time(status.intval, 0); 344 info->time = calculate_time(status.intval);
287 if (info->time == -1)
288 info->time = calculate_time(status.intval, 1);
289 }
290 } else { 345 } else {
291 if (!MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty) || 346 if (!MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty) ||
292 !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty)) { 347 !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty))
293 info->time = time_to_empty.intval / 60; 348 info->time = time_to_empty.intval / 60;
294 } else { 349 else
295 info->time = calculate_time(status.intval, 0); 350 info->time = calculate_time(status.intval);
296 if (info->time == -1)
297 info->time = calculate_time(status.intval, 1);
298 }
299 } 351 }
300 352
301 mutex_unlock(&apm_mutex); 353 mutex_unlock(&apm_mutex);
diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c
index c998e68d060f..af7a231092a4 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,
226 return ret; 226 return ret;
227 val->intval = ec_byte; 227 val->intval = ec_byte;
228 break; 228 break;
229 case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
230 if (ec_byte & BAT_STAT_FULL)
231 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
232 else if (ec_byte & BAT_STAT_LOW)
233 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
234 else
235 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
236 break;
237 case POWER_SUPPLY_PROP_TEMP: 229 case POWER_SUPPLY_PROP_TEMP:
238 ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2); 230 ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);
239 if (ret) 231 if (ret)
@@ -265,7 +257,6 @@ static enum power_supply_property olpc_bat_props[] = {
265 POWER_SUPPLY_PROP_VOLTAGE_AVG, 257 POWER_SUPPLY_PROP_VOLTAGE_AVG,
266 POWER_SUPPLY_PROP_CURRENT_AVG, 258 POWER_SUPPLY_PROP_CURRENT_AVG,
267 POWER_SUPPLY_PROP_CAPACITY, 259 POWER_SUPPLY_PROP_CAPACITY,
268 POWER_SUPPLY_PROP_CAPACITY_LEVEL,
269 POWER_SUPPLY_PROP_TEMP, 260 POWER_SUPPLY_PROP_TEMP,
270 POWER_SUPPLY_PROP_TEMP_AMBIENT, 261 POWER_SUPPLY_PROP_TEMP_AMBIENT,
271 POWER_SUPPLY_PROP_MANUFACTURER, 262 POWER_SUPPLY_PROP_MANUFACTURER,
diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c
index c058f285be1a..c8aa55b81fd8 100644
--- a/drivers/power/pda_power.c
+++ b/drivers/power/pda_power.c
@@ -32,6 +32,18 @@ static struct pda_power_pdata *pdata;
32static struct resource *ac_irq, *usb_irq; 32static struct resource *ac_irq, *usb_irq;
33static struct timer_list charger_timer; 33static struct timer_list charger_timer;
34static struct timer_list supply_timer; 34static struct timer_list supply_timer;
35static struct timer_list polling_timer;
36static int polling;
37
38enum {
39 PDA_PSY_OFFLINE = 0,
40 PDA_PSY_ONLINE = 1,
41 PDA_PSY_TO_CHANGE,
42};
43static int new_ac_status = -1;
44static int new_usb_status = -1;
45static int ac_status = -1;
46static int usb_status = -1;
35 47
36static int pda_power_get_property(struct power_supply *psy, 48static int pda_power_get_property(struct power_supply *psy,
37 enum power_supply_property psp, 49 enum power_supply_property psp,
@@ -61,36 +73,44 @@ static char *pda_power_supplied_to[] = {
61 "backup-battery", 73 "backup-battery",
62}; 74};
63 75
64static struct power_supply pda_power_supplies[] = { 76static struct power_supply pda_psy_ac = {
65 { 77 .name = "ac",
66 .name = "ac", 78 .type = POWER_SUPPLY_TYPE_MAINS,
67 .type = POWER_SUPPLY_TYPE_MAINS, 79 .supplied_to = pda_power_supplied_to,
68 .supplied_to = pda_power_supplied_to, 80 .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
69 .num_supplicants = ARRAY_SIZE(pda_power_supplied_to), 81 .properties = pda_power_props,
70 .properties = pda_power_props, 82 .num_properties = ARRAY_SIZE(pda_power_props),
71 .num_properties = ARRAY_SIZE(pda_power_props), 83 .get_property = pda_power_get_property,
72 .get_property = pda_power_get_property,
73 },
74 {
75 .name = "usb",
76 .type = POWER_SUPPLY_TYPE_USB,
77 .supplied_to = pda_power_supplied_to,
78 .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
79 .properties = pda_power_props,
80 .num_properties = ARRAY_SIZE(pda_power_props),
81 .get_property = pda_power_get_property,
82 },
83}; 84};
84 85
86static struct power_supply pda_psy_usb = {
87 .name = "usb",
88 .type = POWER_SUPPLY_TYPE_USB,
89 .supplied_to = pda_power_supplied_to,
90 .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
91 .properties = pda_power_props,
92 .num_properties = ARRAY_SIZE(pda_power_props),
93 .get_property = pda_power_get_property,
94};
95
96static void update_status(void)
97{
98 if (pdata->is_ac_online)
99 new_ac_status = !!pdata->is_ac_online();
100
101 if (pdata->is_usb_online)
102 new_usb_status = !!pdata->is_usb_online();
103}
104
85static void update_charger(void) 105static void update_charger(void)
86{ 106{
87 if (!pdata->set_charge) 107 if (!pdata->set_charge)
88 return; 108 return;
89 109
90 if (pdata->is_ac_online && pdata->is_ac_online()) { 110 if (new_ac_status > 0) {
91 dev_dbg(dev, "charger on (AC)\n"); 111 dev_dbg(dev, "charger on (AC)\n");
92 pdata->set_charge(PDA_POWER_CHARGE_AC); 112 pdata->set_charge(PDA_POWER_CHARGE_AC);
93 } else if (pdata->is_usb_online && pdata->is_usb_online()) { 113 } else if (new_usb_status > 0) {
94 dev_dbg(dev, "charger on (USB)\n"); 114 dev_dbg(dev, "charger on (USB)\n");
95 pdata->set_charge(PDA_POWER_CHARGE_USB); 115 pdata->set_charge(PDA_POWER_CHARGE_USB);
96 } else { 116 } else {
@@ -99,34 +119,81 @@ static void update_charger(void)
99 } 119 }
100} 120}
101 121
102static void supply_timer_func(unsigned long power_supply_ptr) 122static void supply_timer_func(unsigned long unused)
103{ 123{
104 void *power_supply = (void *)power_supply_ptr; 124 if (ac_status == PDA_PSY_TO_CHANGE) {
125 ac_status = new_ac_status;
126 power_supply_changed(&pda_psy_ac);
127 }
105 128
106 power_supply_changed(power_supply); 129 if (usb_status == PDA_PSY_TO_CHANGE) {
130 usb_status = new_usb_status;
131 power_supply_changed(&pda_psy_usb);
132 }
107} 133}
108 134
109static void charger_timer_func(unsigned long power_supply_ptr) 135static void psy_changed(void)
110{ 136{
111 update_charger(); 137 update_charger();
112 138
113 /* Okay, charger set. Now wait a bit before notifying supplicants, 139 /*
114 * charge power should stabilize. */ 140 * Okay, charger set. Now wait a bit before notifying supplicants,
115 supply_timer.data = power_supply_ptr; 141 * charge power should stabilize.
142 */
116 mod_timer(&supply_timer, 143 mod_timer(&supply_timer,
117 jiffies + msecs_to_jiffies(pdata->wait_for_charger)); 144 jiffies + msecs_to_jiffies(pdata->wait_for_charger));
118} 145}
119 146
147static void charger_timer_func(unsigned long unused)
148{
149 update_status();
150 psy_changed();
151}
152
120static irqreturn_t power_changed_isr(int irq, void *power_supply) 153static irqreturn_t power_changed_isr(int irq, void *power_supply)
121{ 154{
122 /* Wait a bit before reading ac/usb line status and setting charger, 155 if (power_supply == &pda_psy_ac)
123 * because ac/usb status readings may lag from irq. */ 156 ac_status = PDA_PSY_TO_CHANGE;
124 charger_timer.data = (unsigned long)power_supply; 157 else if (power_supply == &pda_psy_usb)
158 usb_status = PDA_PSY_TO_CHANGE;
159 else
160 return IRQ_NONE;
161
162 /*
163 * Wait a bit before reading ac/usb line status and setting charger,
164 * because ac/usb status readings may lag from irq.
165 */
125 mod_timer(&charger_timer, 166 mod_timer(&charger_timer,
126 jiffies + msecs_to_jiffies(pdata->wait_for_status)); 167 jiffies + msecs_to_jiffies(pdata->wait_for_status));
168
127 return IRQ_HANDLED; 169 return IRQ_HANDLED;
128} 170}
129 171
172static void polling_timer_func(unsigned long unused)
173{
174 int changed = 0;
175
176 dev_dbg(dev, "polling...\n");
177
178 update_status();
179
180 if (!ac_irq && new_ac_status != ac_status) {
181 ac_status = PDA_PSY_TO_CHANGE;
182 changed = 1;
183 }
184
185 if (!usb_irq && new_usb_status != usb_status) {
186 usb_status = PDA_PSY_TO_CHANGE;
187 changed = 1;
188 }
189
190 if (changed)
191 psy_changed();
192
193 mod_timer(&polling_timer,
194 jiffies + msecs_to_jiffies(pdata->polling_interval));
195}
196
130static int pda_power_probe(struct platform_device *pdev) 197static int pda_power_probe(struct platform_device *pdev)
131{ 198{
132 int ret = 0; 199 int ret = 0;
@@ -142,6 +209,7 @@ static int pda_power_probe(struct platform_device *pdev)
142 209
143 pdata = pdev->dev.platform_data; 210 pdata = pdev->dev.platform_data;
144 211
212 update_status();
145 update_charger(); 213 update_charger();
146 214
147 if (!pdata->wait_for_status) 215 if (!pdata->wait_for_status)
@@ -150,86 +218,138 @@ static int pda_power_probe(struct platform_device *pdev)
150 if (!pdata->wait_for_charger) 218 if (!pdata->wait_for_charger)
151 pdata->wait_for_charger = 500; 219 pdata->wait_for_charger = 500;
152 220
221 if (!pdata->polling_interval)
222 pdata->polling_interval = 2000;
223
153 setup_timer(&charger_timer, charger_timer_func, 0); 224 setup_timer(&charger_timer, charger_timer_func, 0);
154 setup_timer(&supply_timer, supply_timer_func, 0); 225 setup_timer(&supply_timer, supply_timer_func, 0);
155 226
156 ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac"); 227 ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac");
157 usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb"); 228 usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb");
158 if (!ac_irq && !usb_irq) {
159 dev_err(dev, "no ac/usb irq specified\n");
160 ret = -ENODEV;
161 goto noirqs;
162 }
163 229
164 if (pdata->supplied_to) { 230 if (pdata->supplied_to) {
165 pda_power_supplies[0].supplied_to = pdata->supplied_to; 231 pda_psy_ac.supplied_to = pdata->supplied_to;
166 pda_power_supplies[1].supplied_to = pdata->supplied_to; 232 pda_psy_ac.num_supplicants = pdata->num_supplicants;
167 pda_power_supplies[0].num_supplicants = pdata->num_supplicants; 233 pda_psy_usb.supplied_to = pdata->supplied_to;
168 pda_power_supplies[1].num_supplicants = pdata->num_supplicants; 234 pda_psy_usb.num_supplicants = pdata->num_supplicants;
169 } 235 }
170 236
171 ret = power_supply_register(&pdev->dev, &pda_power_supplies[0]); 237 if (pdata->is_ac_online) {
172 if (ret) { 238 ret = power_supply_register(&pdev->dev, &pda_psy_ac);
173 dev_err(dev, "failed to register %s power supply\n", 239 if (ret) {
174 pda_power_supplies[0].name); 240 dev_err(dev, "failed to register %s power supply\n",
175 goto supply0_failed; 241 pda_psy_ac.name);
176 } 242 goto ac_supply_failed;
243 }
177 244
178 ret = power_supply_register(&pdev->dev, &pda_power_supplies[1]); 245 if (ac_irq) {
179 if (ret) { 246 ret = request_irq(ac_irq->start, power_changed_isr,
180 dev_err(dev, "failed to register %s power supply\n", 247 get_irq_flags(ac_irq), ac_irq->name,
181 pda_power_supplies[1].name); 248 &pda_psy_ac);
182 goto supply1_failed; 249 if (ret) {
250 dev_err(dev, "request ac irq failed\n");
251 goto ac_irq_failed;
252 }
253 } else {
254 polling = 1;
255 }
183 } 256 }
184 257
185 if (ac_irq) { 258 if (pdata->is_usb_online) {
186 ret = request_irq(ac_irq->start, power_changed_isr, 259 ret = power_supply_register(&pdev->dev, &pda_psy_usb);
187 get_irq_flags(ac_irq), ac_irq->name,
188 &pda_power_supplies[0]);
189 if (ret) { 260 if (ret) {
190 dev_err(dev, "request ac irq failed\n"); 261 dev_err(dev, "failed to register %s power supply\n",
191 goto ac_irq_failed; 262 pda_psy_usb.name);
263 goto usb_supply_failed;
192 } 264 }
193 }
194 265
195 if (usb_irq) { 266 if (usb_irq) {
196 ret = request_irq(usb_irq->start, power_changed_isr, 267 ret = request_irq(usb_irq->start, power_changed_isr,
197 get_irq_flags(usb_irq), usb_irq->name, 268 get_irq_flags(usb_irq),
198 &pda_power_supplies[1]); 269 usb_irq->name, &pda_psy_usb);
199 if (ret) { 270 if (ret) {
200 dev_err(dev, "request usb irq failed\n"); 271 dev_err(dev, "request usb irq failed\n");
201 goto usb_irq_failed; 272 goto usb_irq_failed;
273 }
274 } else {
275 polling = 1;
202 } 276 }
203 } 277 }
204 278
205 goto success; 279 if (polling) {
280 dev_dbg(dev, "will poll for status\n");
281 setup_timer(&polling_timer, polling_timer_func, 0);
282 mod_timer(&polling_timer,
283 jiffies + msecs_to_jiffies(pdata->polling_interval));
284 }
285
286 if (ac_irq || usb_irq)
287 device_init_wakeup(&pdev->dev, 1);
288
289 return 0;
206 290
207usb_irq_failed: 291usb_irq_failed:
208 if (ac_irq) 292 if (pdata->is_usb_online)
209 free_irq(ac_irq->start, &pda_power_supplies[0]); 293 power_supply_unregister(&pda_psy_usb);
294usb_supply_failed:
295 if (pdata->is_ac_online && ac_irq)
296 free_irq(ac_irq->start, &pda_psy_ac);
210ac_irq_failed: 297ac_irq_failed:
211 power_supply_unregister(&pda_power_supplies[1]); 298 if (pdata->is_ac_online)
212supply1_failed: 299 power_supply_unregister(&pda_psy_ac);
213 power_supply_unregister(&pda_power_supplies[0]); 300ac_supply_failed:
214supply0_failed:
215noirqs:
216wrongid: 301wrongid:
217success:
218 return ret; 302 return ret;
219} 303}
220 304
221static int pda_power_remove(struct platform_device *pdev) 305static int pda_power_remove(struct platform_device *pdev)
222{ 306{
223 if (usb_irq) 307 if (pdata->is_usb_online && usb_irq)
224 free_irq(usb_irq->start, &pda_power_supplies[1]); 308 free_irq(usb_irq->start, &pda_psy_usb);
225 if (ac_irq) 309 if (pdata->is_ac_online && ac_irq)
226 free_irq(ac_irq->start, &pda_power_supplies[0]); 310 free_irq(ac_irq->start, &pda_psy_ac);
311
312 if (polling)
313 del_timer_sync(&polling_timer);
227 del_timer_sync(&charger_timer); 314 del_timer_sync(&charger_timer);
228 del_timer_sync(&supply_timer); 315 del_timer_sync(&supply_timer);
229 power_supply_unregister(&pda_power_supplies[1]); 316
230 power_supply_unregister(&pda_power_supplies[0]); 317 if (pdata->is_usb_online)
318 power_supply_unregister(&pda_psy_usb);
319 if (pdata->is_ac_online)
320 power_supply_unregister(&pda_psy_ac);
321
322 return 0;
323}
324
325#ifdef CONFIG_PM
326static int pda_power_suspend(struct platform_device *pdev, pm_message_t state)
327{
328 if (device_may_wakeup(&pdev->dev)) {
329 if (ac_irq)
330 enable_irq_wake(ac_irq->start);
331 if (usb_irq)
332 enable_irq_wake(usb_irq->start);
333 }
334
335 return 0;
336}
337
338static int pda_power_resume(struct platform_device *pdev)
339{
340 if (device_may_wakeup(&pdev->dev)) {
341 if (usb_irq)
342 disable_irq_wake(usb_irq->start);
343 if (ac_irq)
344 disable_irq_wake(ac_irq->start);
345 }
346
231 return 0; 347 return 0;
232} 348}
349#else
350#define pda_power_suspend NULL
351#define pda_power_resume NULL
352#endif /* CONFIG_PM */
233 353
234static struct platform_driver pda_power_pdrv = { 354static struct platform_driver pda_power_pdrv = {
235 .driver = { 355 .driver = {
@@ -237,6 +357,8 @@ static struct platform_driver pda_power_pdrv = {
237 }, 357 },
238 .probe = pda_power_probe, 358 .probe = pda_power_probe,
239 .remove = pda_power_remove, 359 .remove = pda_power_remove,
360 .suspend = pda_power_suspend,
361 .resume = pda_power_resume,
240}; 362};
241 363
242static int __init pda_power_init(void) 364static int __init pda_power_init(void)
diff --git a/drivers/power/power_supply_leds.c b/drivers/power/power_supply_leds.c
index 7f8f3590b02e..fa3034f85c38 100644
--- a/drivers/power/power_supply_leds.c
+++ b/drivers/power/power_supply_leds.c
@@ -10,8 +10,11 @@
10 * You may use this code as per GPL version 2 10 * You may use this code as per GPL version 2
11 */ 11 */
12 12
13#include <linux/kernel.h>
13#include <linux/power_supply.h> 14#include <linux/power_supply.h>
14 15
16#include "power_supply.h"
17
15/* Battery specific LEDs triggers. */ 18/* Battery specific LEDs triggers. */
16 19
17static void power_supply_update_bat_leds(struct power_supply *psy) 20static void power_supply_update_bat_leds(struct power_supply *psy)
@@ -46,28 +49,20 @@ static int power_supply_create_bat_triggers(struct power_supply *psy)
46{ 49{
47 int rc = 0; 50 int rc = 0;
48 51
49 psy->charging_full_trig_name = kmalloc(strlen(psy->name) + 52 psy->charging_full_trig_name = kasprintf(GFP_KERNEL,
50 sizeof("-charging-or-full"), GFP_KERNEL); 53 "%s-charging-or-full", psy->name);
51 if (!psy->charging_full_trig_name) 54 if (!psy->charging_full_trig_name)
52 goto charging_full_failed; 55 goto charging_full_failed;
53 56
54 psy->charging_trig_name = kmalloc(strlen(psy->name) + 57 psy->charging_trig_name = kasprintf(GFP_KERNEL,
55 sizeof("-charging"), GFP_KERNEL); 58 "%s-charging", psy->name);
56 if (!psy->charging_trig_name) 59 if (!psy->charging_trig_name)
57 goto charging_failed; 60 goto charging_failed;
58 61
59 psy->full_trig_name = kmalloc(strlen(psy->name) + 62 psy->full_trig_name = kasprintf(GFP_KERNEL, "%s-full", psy->name);
60 sizeof("-full"), GFP_KERNEL);
61 if (!psy->full_trig_name) 63 if (!psy->full_trig_name)
62 goto full_failed; 64 goto full_failed;
63 65
64 strcpy(psy->charging_full_trig_name, psy->name);
65 strcat(psy->charging_full_trig_name, "-charging-or-full");
66 strcpy(psy->charging_trig_name, psy->name);
67 strcat(psy->charging_trig_name, "-charging");
68 strcpy(psy->full_trig_name, psy->name);
69 strcat(psy->full_trig_name, "-full");
70
71 led_trigger_register_simple(psy->charging_full_trig_name, 66 led_trigger_register_simple(psy->charging_full_trig_name,
72 &psy->charging_full_trig); 67 &psy->charging_full_trig);
73 led_trigger_register_simple(psy->charging_trig_name, 68 led_trigger_register_simple(psy->charging_trig_name,
@@ -118,14 +113,10 @@ static int power_supply_create_gen_triggers(struct power_supply *psy)
118{ 113{
119 int rc = 0; 114 int rc = 0;
120 115
121 psy->online_trig_name = kmalloc(strlen(psy->name) + sizeof("-online"), 116 psy->online_trig_name = kasprintf(GFP_KERNEL, "%s-online", psy->name);
122 GFP_KERNEL);
123 if (!psy->online_trig_name) 117 if (!psy->online_trig_name)
124 goto online_failed; 118 goto online_failed;
125 119
126 strcpy(psy->online_trig_name, psy->name);
127 strcat(psy->online_trig_name, "-online");
128
129 led_trigger_register_simple(psy->online_trig_name, &psy->online_trig); 120 led_trigger_register_simple(psy->online_trig_name, &psy->online_trig);
130 121
131 goto success; 122 goto success;
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 249f61bae639..d4824840c5bf 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -14,6 +14,8 @@
14#include <linux/ctype.h> 14#include <linux/ctype.h>
15#include <linux/power_supply.h> 15#include <linux/power_supply.h>
16 16
17#include "power_supply.h"
18
17/* 19/*
18 * This is because the name "current" breaks the device attr macro. 20 * This is because the name "current" breaks the device attr macro.
19 * The "current" word resolves to "(get_current())" so instead of 21 * The "current" word resolves to "(get_current())" so instead of
@@ -46,10 +48,8 @@ static ssize_t power_supply_show_property(struct device *dev,
46 "Unspecified failure" 48 "Unspecified failure"
47 }; 49 };
48 static char *technology_text[] = { 50 static char *technology_text[] = {
49 "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd" 51 "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd",
50 }; 52 "LiMn"
51 static char *capacity_level_text[] = {
52 "Unknown", "Critical", "Low", "Normal", "High", "Full"
53 }; 53 };
54 ssize_t ret; 54 ssize_t ret;
55 struct power_supply *psy = dev_get_drvdata(dev); 55 struct power_supply *psy = dev_get_drvdata(dev);
@@ -71,9 +71,6 @@ static ssize_t power_supply_show_property(struct device *dev,
71 return sprintf(buf, "%s\n", health_text[value.intval]); 71 return sprintf(buf, "%s\n", health_text[value.intval]);
72 else if (off == POWER_SUPPLY_PROP_TECHNOLOGY) 72 else if (off == POWER_SUPPLY_PROP_TECHNOLOGY)
73 return sprintf(buf, "%s\n", technology_text[value.intval]); 73 return sprintf(buf, "%s\n", technology_text[value.intval]);
74 else if (off == POWER_SUPPLY_PROP_CAPACITY_LEVEL)
75 return sprintf(buf, "%s\n",
76 capacity_level_text[value.intval]);
77 else if (off >= POWER_SUPPLY_PROP_MODEL_NAME) 74 else if (off >= POWER_SUPPLY_PROP_MODEL_NAME)
78 return sprintf(buf, "%s\n", value.strval); 75 return sprintf(buf, "%s\n", value.strval);
79 76
@@ -88,6 +85,8 @@ static struct device_attribute power_supply_attrs[] = {
88 POWER_SUPPLY_ATTR(present), 85 POWER_SUPPLY_ATTR(present),
89 POWER_SUPPLY_ATTR(online), 86 POWER_SUPPLY_ATTR(online),
90 POWER_SUPPLY_ATTR(technology), 87 POWER_SUPPLY_ATTR(technology),
88 POWER_SUPPLY_ATTR(voltage_max),
89 POWER_SUPPLY_ATTR(voltage_min),
91 POWER_SUPPLY_ATTR(voltage_max_design), 90 POWER_SUPPLY_ATTR(voltage_max_design),
92 POWER_SUPPLY_ATTR(voltage_min_design), 91 POWER_SUPPLY_ATTR(voltage_min_design),
93 POWER_SUPPLY_ATTR(voltage_now), 92 POWER_SUPPLY_ATTR(voltage_now),
@@ -159,8 +158,7 @@ dynamics_failed:
159 &power_supply_attrs[psy->properties[j]]); 158 &power_supply_attrs[psy->properties[j]]);
160statics_failed: 159statics_failed:
161 while (i--) 160 while (i--)
162 device_remove_file(psy->dev, 161 device_remove_file(psy->dev, &power_supply_static_attrs[i]);
163 &power_supply_static_attrs[psy->properties[i]]);
164succeed: 162succeed:
165 return rc; 163 return rc;
166} 164}
@@ -170,8 +168,7 @@ void power_supply_remove_attrs(struct power_supply *psy)
170 int i; 168 int i;
171 169
172 for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++) 170 for (i = 0; i < ARRAY_SIZE(power_supply_static_attrs); i++)
173 device_remove_file(psy->dev, 171 device_remove_file(psy->dev, &power_supply_static_attrs[i]);
174 &power_supply_static_attrs[i]);
175 172
176 for (i = 0; i < psy->num_properties; i++) 173 for (i = 0; i < psy->num_properties; i++)
177 device_remove_file(psy->dev, 174 device_remove_file(psy->dev,
diff --git a/include/linux/pda_power.h b/include/linux/pda_power.h
index 1375f15797e7..225beb136807 100644
--- a/include/linux/pda_power.h
+++ b/include/linux/pda_power.h
@@ -26,6 +26,7 @@ struct pda_power_pdata {
26 26
27 unsigned int wait_for_status; /* msecs, default is 500 */ 27 unsigned int wait_for_status; /* msecs, default is 500 */
28 unsigned int wait_for_charger; /* msecs, default is 500 */ 28 unsigned int wait_for_charger; /* msecs, default is 500 */
29 unsigned int polling_interval; /* msecs, default is 2000 */
29}; 30};
30 31
31#endif /* __PDA_POWER_H__ */ 32#endif /* __PDA_POWER_H__ */
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 606c0957997f..5cbf3e371012 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -54,15 +54,7 @@ enum {
54 POWER_SUPPLY_TECHNOLOGY_LIPO, 54 POWER_SUPPLY_TECHNOLOGY_LIPO,
55 POWER_SUPPLY_TECHNOLOGY_LiFe, 55 POWER_SUPPLY_TECHNOLOGY_LiFe,
56 POWER_SUPPLY_TECHNOLOGY_NiCd, 56 POWER_SUPPLY_TECHNOLOGY_NiCd,
57}; 57 POWER_SUPPLY_TECHNOLOGY_LiMn,
58
59enum {
60 POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN = 0,
61 POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL,
62 POWER_SUPPLY_CAPACITY_LEVEL_LOW,
63 POWER_SUPPLY_CAPACITY_LEVEL_NORMAL,
64 POWER_SUPPLY_CAPACITY_LEVEL_HIGH,
65 POWER_SUPPLY_CAPACITY_LEVEL_FULL,
66}; 58};
67 59
68enum power_supply_property { 60enum power_supply_property {
@@ -72,6 +64,8 @@ enum power_supply_property {
72 POWER_SUPPLY_PROP_PRESENT, 64 POWER_SUPPLY_PROP_PRESENT,
73 POWER_SUPPLY_PROP_ONLINE, 65 POWER_SUPPLY_PROP_ONLINE,
74 POWER_SUPPLY_PROP_TECHNOLOGY, 66 POWER_SUPPLY_PROP_TECHNOLOGY,
67 POWER_SUPPLY_PROP_VOLTAGE_MAX,
68 POWER_SUPPLY_PROP_VOLTAGE_MIN,
75 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 69 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
76 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, 70 POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
77 POWER_SUPPLY_PROP_VOLTAGE_NOW, 71 POWER_SUPPLY_PROP_VOLTAGE_NOW,
@@ -91,7 +85,6 @@ enum power_supply_property {
91 POWER_SUPPLY_PROP_ENERGY_NOW, 85 POWER_SUPPLY_PROP_ENERGY_NOW,
92 POWER_SUPPLY_PROP_ENERGY_AVG, 86 POWER_SUPPLY_PROP_ENERGY_AVG,
93 POWER_SUPPLY_PROP_CAPACITY, /* in percents! */ 87 POWER_SUPPLY_PROP_CAPACITY, /* in percents! */
94 POWER_SUPPLY_PROP_CAPACITY_LEVEL,
95 POWER_SUPPLY_PROP_TEMP, 88 POWER_SUPPLY_PROP_TEMP,
96 POWER_SUPPLY_PROP_TEMP_AMBIENT, 89 POWER_SUPPLY_PROP_TEMP_AMBIENT,
97 POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 90 POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,