aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power')
-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
5 files changed, 292 insertions, 139 deletions
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,