diff options
Diffstat (limited to 'arch/arm/mach-pxa/sharpsl_pm.c')
-rw-r--r-- | arch/arm/mach-pxa/sharpsl_pm.c | 863 |
1 files changed, 847 insertions, 16 deletions
diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c index 16b4ec67e3b6..2546c066cd6e 100644 --- a/arch/arm/mach-pxa/sharpsl_pm.c +++ b/arch/arm/mach-pxa/sharpsl_pm.c | |||
@@ -15,20 +15,69 @@ | |||
15 | #undef DEBUG | 15 | #undef DEBUG |
16 | 16 | ||
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/init.h> | ||
19 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
20 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
21 | #include <linux/irq.h> | ||
22 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
23 | #include <linux/apm-emulation.h> | 21 | #include <linux/apm-emulation.h> |
22 | #include <linux/timer.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/leds.h> | ||
25 | #include <linux/suspend.h> | ||
26 | #include <linux/gpio.h> | ||
24 | 27 | ||
25 | #include <mach/hardware.h> | ||
26 | #include <asm/mach-types.h> | 28 | #include <asm/mach-types.h> |
27 | #include <mach/pm.h> | 29 | #include <mach/pm.h> |
30 | #include <mach/pxa2xx-regs.h> | ||
28 | #include <mach/pxa2xx-gpio.h> | 31 | #include <mach/pxa2xx-gpio.h> |
32 | #include <mach/regs-rtc.h> | ||
29 | #include <mach/sharpsl.h> | 33 | #include <mach/sharpsl.h> |
34 | #include <mach/sharpsl_pm.h> | ||
35 | |||
30 | #include "sharpsl.h" | 36 | #include "sharpsl.h" |
31 | 37 | ||
38 | /* | ||
39 | * Constants | ||
40 | */ | ||
41 | #define SHARPSL_CHARGE_ON_TIME_INTERVAL (msecs_to_jiffies(1*60*1000)) /* 1 min */ | ||
42 | #define SHARPSL_CHARGE_FINISH_TIME (msecs_to_jiffies(10*60*1000)) /* 10 min */ | ||
43 | #define SHARPSL_BATCHK_TIME (msecs_to_jiffies(15*1000)) /* 15 sec */ | ||
44 | #define SHARPSL_BATCHK_TIME_SUSPEND (60*10) /* 10 min */ | ||
45 | |||
46 | #define SHARPSL_WAIT_CO_TIME 15 /* 15 sec */ | ||
47 | #define SHARPSL_WAIT_DISCHARGE_ON 100 /* 100 msec */ | ||
48 | #define SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP 10 /* 10 msec */ | ||
49 | #define SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT 10 /* 10 msec */ | ||
50 | #define SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN 10 /* 10 msec */ | ||
51 | #define SHARPSL_CHARGE_WAIT_TIME 15 /* 15 msec */ | ||
52 | #define SHARPSL_CHARGE_CO_CHECK_TIME 5 /* 5 msec */ | ||
53 | #define SHARPSL_CHARGE_RETRY_CNT 1 /* eqv. 10 min */ | ||
54 | |||
55 | /* | ||
56 | * Prototypes | ||
57 | */ | ||
58 | #ifdef CONFIG_PM | ||
59 | static int sharpsl_off_charge_battery(void); | ||
60 | static int sharpsl_check_battery_voltage(void); | ||
61 | static int sharpsl_fatal_check(void); | ||
62 | #endif | ||
63 | static int sharpsl_check_battery_temp(void); | ||
64 | static int sharpsl_ac_check(void); | ||
65 | static int sharpsl_average_value(int ad); | ||
66 | static void sharpsl_average_clear(void); | ||
67 | static void sharpsl_charge_toggle(struct work_struct *private_); | ||
68 | static void sharpsl_battery_thread(struct work_struct *private_); | ||
69 | |||
70 | |||
71 | /* | ||
72 | * Variables | ||
73 | */ | ||
74 | struct sharpsl_pm_status sharpsl_pm; | ||
75 | static DECLARE_DELAYED_WORK(toggle_charger, sharpsl_charge_toggle); | ||
76 | static DECLARE_DELAYED_WORK(sharpsl_bat, sharpsl_battery_thread); | ||
77 | DEFINE_LED_TRIGGER(sharpsl_charge_led_trigger); | ||
78 | |||
79 | |||
80 | |||
32 | struct battery_thresh spitz_battery_levels_acin[] = { | 81 | struct battery_thresh spitz_battery_levels_acin[] = { |
33 | { 213, 100}, | 82 | { 213, 100}, |
34 | { 212, 98}, | 83 | { 212, 98}, |
@@ -144,42 +193,789 @@ int sharpsl_pm_pxa_read_max1111(int channel) | |||
144 | #endif | 193 | #endif |
145 | } | 194 | } |
146 | 195 | ||
147 | void sharpsl_pm_pxa_init(void) | 196 | static int get_percentage(int voltage) |
197 | { | ||
198 | int i = sharpsl_pm.machinfo->bat_levels - 1; | ||
199 | int bl_status = sharpsl_pm.machinfo->backlight_get_status ? sharpsl_pm.machinfo->backlight_get_status() : 0; | ||
200 | struct battery_thresh *thresh; | ||
201 | |||
202 | if (sharpsl_pm.charge_mode == CHRG_ON) | ||
203 | thresh = bl_status ? sharpsl_pm.machinfo->bat_levels_acin_bl : sharpsl_pm.machinfo->bat_levels_acin; | ||
204 | else | ||
205 | thresh = bl_status ? sharpsl_pm.machinfo->bat_levels_noac_bl : sharpsl_pm.machinfo->bat_levels_noac; | ||
206 | |||
207 | while (i > 0 && (voltage > thresh[i].voltage)) | ||
208 | i--; | ||
209 | |||
210 | return thresh[i].percentage; | ||
211 | } | ||
212 | |||
213 | static int get_apm_status(int voltage) | ||
214 | { | ||
215 | int low_thresh, high_thresh; | ||
216 | |||
217 | if (sharpsl_pm.charge_mode == CHRG_ON) { | ||
218 | high_thresh = sharpsl_pm.machinfo->status_high_acin; | ||
219 | low_thresh = sharpsl_pm.machinfo->status_low_acin; | ||
220 | } else { | ||
221 | high_thresh = sharpsl_pm.machinfo->status_high_noac; | ||
222 | low_thresh = sharpsl_pm.machinfo->status_low_noac; | ||
223 | } | ||
224 | |||
225 | if (voltage >= high_thresh) | ||
226 | return APM_BATTERY_STATUS_HIGH; | ||
227 | if (voltage >= low_thresh) | ||
228 | return APM_BATTERY_STATUS_LOW; | ||
229 | return APM_BATTERY_STATUS_CRITICAL; | ||
230 | } | ||
231 | |||
232 | void sharpsl_battery_kick(void) | ||
233 | { | ||
234 | schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(125)); | ||
235 | } | ||
236 | EXPORT_SYMBOL(sharpsl_battery_kick); | ||
237 | |||
238 | |||
239 | static void sharpsl_battery_thread(struct work_struct *private_) | ||
240 | { | ||
241 | int voltage, percent, apm_status, i = 0; | ||
242 | |||
243 | if (!sharpsl_pm.machinfo) | ||
244 | return; | ||
245 | |||
246 | sharpsl_pm.battstat.ac_status = (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN) ? APM_AC_ONLINE : APM_AC_OFFLINE); | ||
247 | |||
248 | /* Corgi cannot confirm when battery fully charged so periodically kick! */ | ||
249 | if (!sharpsl_pm.machinfo->batfull_irq && (sharpsl_pm.charge_mode == CHRG_ON) | ||
250 | && time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_ON_TIME_INTERVAL)) | ||
251 | schedule_delayed_work(&toggle_charger, 0); | ||
252 | |||
253 | while(1) { | ||
254 | voltage = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT); | ||
255 | |||
256 | if (voltage > 0) break; | ||
257 | if (i++ > 5) { | ||
258 | voltage = sharpsl_pm.machinfo->bat_levels_noac[0].voltage; | ||
259 | dev_warn(sharpsl_pm.dev, "Warning: Cannot read main battery!\n"); | ||
260 | break; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | voltage = sharpsl_average_value(voltage); | ||
265 | apm_status = get_apm_status(voltage); | ||
266 | percent = get_percentage(voltage); | ||
267 | |||
268 | /* At low battery voltages, the voltage has a tendency to start | ||
269 | creeping back up so we try to avoid this here */ | ||
270 | if ((sharpsl_pm.battstat.ac_status == APM_AC_ONLINE) || (apm_status == APM_BATTERY_STATUS_HIGH) || percent <= sharpsl_pm.battstat.mainbat_percent) { | ||
271 | sharpsl_pm.battstat.mainbat_voltage = voltage; | ||
272 | sharpsl_pm.battstat.mainbat_status = apm_status; | ||
273 | sharpsl_pm.battstat.mainbat_percent = percent; | ||
274 | } | ||
275 | |||
276 | dev_dbg(sharpsl_pm.dev, "Battery: voltage: %d, status: %d, percentage: %d, time: %ld\n", voltage, | ||
277 | sharpsl_pm.battstat.mainbat_status, sharpsl_pm.battstat.mainbat_percent, jiffies); | ||
278 | |||
279 | #ifdef CONFIG_BACKLIGHT_CORGI | ||
280 | /* If battery is low. limit backlight intensity to save power. */ | ||
281 | if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE) | ||
282 | && ((sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_LOW) || | ||
283 | (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL))) { | ||
284 | if (!(sharpsl_pm.flags & SHARPSL_BL_LIMIT)) { | ||
285 | sharpsl_pm.machinfo->backlight_limit(1); | ||
286 | sharpsl_pm.flags |= SHARPSL_BL_LIMIT; | ||
287 | } | ||
288 | } else if (sharpsl_pm.flags & SHARPSL_BL_LIMIT) { | ||
289 | sharpsl_pm.machinfo->backlight_limit(0); | ||
290 | sharpsl_pm.flags &= ~SHARPSL_BL_LIMIT; | ||
291 | } | ||
292 | #endif | ||
293 | |||
294 | /* Suspend if critical battery level */ | ||
295 | if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE) | ||
296 | && (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL) | ||
297 | && !(sharpsl_pm.flags & SHARPSL_APM_QUEUED)) { | ||
298 | sharpsl_pm.flags |= SHARPSL_APM_QUEUED; | ||
299 | dev_err(sharpsl_pm.dev, "Fatal Off\n"); | ||
300 | apm_queue_event(APM_CRITICAL_SUSPEND); | ||
301 | } | ||
302 | |||
303 | schedule_delayed_work(&sharpsl_bat, SHARPSL_BATCHK_TIME); | ||
304 | } | ||
305 | |||
306 | void sharpsl_pm_led(int val) | ||
307 | { | ||
308 | if (val == SHARPSL_LED_ERROR) { | ||
309 | dev_err(sharpsl_pm.dev, "Charging Error!\n"); | ||
310 | } else if (val == SHARPSL_LED_ON) { | ||
311 | dev_dbg(sharpsl_pm.dev, "Charge LED On\n"); | ||
312 | led_trigger_event(sharpsl_charge_led_trigger, LED_FULL); | ||
313 | } else { | ||
314 | dev_dbg(sharpsl_pm.dev, "Charge LED Off\n"); | ||
315 | led_trigger_event(sharpsl_charge_led_trigger, LED_OFF); | ||
316 | } | ||
317 | } | ||
318 | |||
319 | static void sharpsl_charge_on(void) | ||
320 | { | ||
321 | dev_dbg(sharpsl_pm.dev, "Turning Charger On\n"); | ||
322 | |||
323 | sharpsl_pm.full_count = 0; | ||
324 | sharpsl_pm.charge_mode = CHRG_ON; | ||
325 | schedule_delayed_work(&toggle_charger, msecs_to_jiffies(250)); | ||
326 | schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(500)); | ||
327 | } | ||
328 | |||
329 | static void sharpsl_charge_off(void) | ||
330 | { | ||
331 | dev_dbg(sharpsl_pm.dev, "Turning Charger Off\n"); | ||
332 | |||
333 | sharpsl_pm.machinfo->charge(0); | ||
334 | sharpsl_pm_led(SHARPSL_LED_OFF); | ||
335 | sharpsl_pm.charge_mode = CHRG_OFF; | ||
336 | |||
337 | schedule_delayed_work(&sharpsl_bat, 0); | ||
338 | } | ||
339 | |||
340 | static void sharpsl_charge_error(void) | ||
148 | { | 341 | { |
149 | pxa_gpio_mode(sharpsl_pm.machinfo->gpio_acin | GPIO_IN); | 342 | sharpsl_pm_led(SHARPSL_LED_ERROR); |
150 | pxa_gpio_mode(sharpsl_pm.machinfo->gpio_batfull | GPIO_IN); | 343 | sharpsl_pm.machinfo->charge(0); |
151 | pxa_gpio_mode(sharpsl_pm.machinfo->gpio_batlock | GPIO_IN); | 344 | sharpsl_pm.charge_mode = CHRG_ERROR; |
345 | } | ||
346 | |||
347 | static void sharpsl_charge_toggle(struct work_struct *private_) | ||
348 | { | ||
349 | dev_dbg(sharpsl_pm.dev, "Toogling Charger at time: %lx\n", jiffies); | ||
350 | |||
351 | if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) { | ||
352 | sharpsl_charge_off(); | ||
353 | return; | ||
354 | } else if ((sharpsl_check_battery_temp() < 0) || (sharpsl_ac_check() < 0)) { | ||
355 | sharpsl_charge_error(); | ||
356 | return; | ||
357 | } | ||
358 | |||
359 | sharpsl_pm_led(SHARPSL_LED_ON); | ||
360 | sharpsl_pm.machinfo->charge(0); | ||
361 | mdelay(SHARPSL_CHARGE_WAIT_TIME); | ||
362 | sharpsl_pm.machinfo->charge(1); | ||
363 | |||
364 | sharpsl_pm.charge_start_time = jiffies; | ||
365 | } | ||
366 | |||
367 | static void sharpsl_ac_timer(unsigned long data) | ||
368 | { | ||
369 | int acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN); | ||
370 | |||
371 | dev_dbg(sharpsl_pm.dev, "AC Status: %d\n",acin); | ||
372 | |||
373 | sharpsl_average_clear(); | ||
374 | if (acin && (sharpsl_pm.charge_mode != CHRG_ON)) | ||
375 | sharpsl_charge_on(); | ||
376 | else if (sharpsl_pm.charge_mode == CHRG_ON) | ||
377 | sharpsl_charge_off(); | ||
378 | |||
379 | schedule_delayed_work(&sharpsl_bat, 0); | ||
380 | } | ||
381 | |||
382 | |||
383 | static irqreturn_t sharpsl_ac_isr(int irq, void *dev_id) | ||
384 | { | ||
385 | /* Delay the event slightly to debounce */ | ||
386 | /* Must be a smaller delay than the chrg_full_isr below */ | ||
387 | mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250)); | ||
388 | |||
389 | return IRQ_HANDLED; | ||
390 | } | ||
391 | |||
392 | static void sharpsl_chrg_full_timer(unsigned long data) | ||
393 | { | ||
394 | dev_dbg(sharpsl_pm.dev, "Charge Full at time: %lx\n", jiffies); | ||
395 | |||
396 | sharpsl_pm.full_count++; | ||
397 | |||
398 | if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) { | ||
399 | dev_dbg(sharpsl_pm.dev, "Charge Full: AC removed - stop charging!\n"); | ||
400 | if (sharpsl_pm.charge_mode == CHRG_ON) | ||
401 | sharpsl_charge_off(); | ||
402 | } else if (sharpsl_pm.full_count < 2) { | ||
403 | dev_dbg(sharpsl_pm.dev, "Charge Full: Count too low\n"); | ||
404 | schedule_delayed_work(&toggle_charger, 0); | ||
405 | } else if (time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_FINISH_TIME)) { | ||
406 | dev_dbg(sharpsl_pm.dev, "Charge Full: Interrupt generated too slowly - retry.\n"); | ||
407 | schedule_delayed_work(&toggle_charger, 0); | ||
408 | } else { | ||
409 | sharpsl_charge_off(); | ||
410 | sharpsl_pm.charge_mode = CHRG_DONE; | ||
411 | dev_dbg(sharpsl_pm.dev, "Charge Full: Charging Finished\n"); | ||
412 | } | ||
413 | } | ||
414 | |||
415 | /* Charging Finished Interrupt (Not present on Corgi) */ | ||
416 | /* Can trigger at the same time as an AC status change so | ||
417 | delay until after that has been processed */ | ||
418 | static irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id) | ||
419 | { | ||
420 | if (sharpsl_pm.flags & SHARPSL_SUSPENDED) | ||
421 | return IRQ_HANDLED; | ||
422 | |||
423 | /* delay until after any ac interrupt */ | ||
424 | mod_timer(&sharpsl_pm.chrg_full_timer, jiffies + msecs_to_jiffies(500)); | ||
425 | |||
426 | return IRQ_HANDLED; | ||
427 | } | ||
428 | |||
429 | static irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id) | ||
430 | { | ||
431 | int is_fatal = 0; | ||
432 | |||
433 | if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) { | ||
434 | dev_err(sharpsl_pm.dev, "Battery now Unlocked! Suspending.\n"); | ||
435 | is_fatal = 1; | ||
436 | } | ||
437 | |||
438 | if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_FATAL)) { | ||
439 | dev_err(sharpsl_pm.dev, "Fatal Batt Error! Suspending.\n"); | ||
440 | is_fatal = 1; | ||
441 | } | ||
442 | |||
443 | if (!(sharpsl_pm.flags & SHARPSL_APM_QUEUED) && is_fatal) { | ||
444 | sharpsl_pm.flags |= SHARPSL_APM_QUEUED; | ||
445 | apm_queue_event(APM_CRITICAL_SUSPEND); | ||
446 | } | ||
447 | |||
448 | return IRQ_HANDLED; | ||
449 | } | ||
450 | |||
451 | /* | ||
452 | * Maintain an average of the last 10 readings | ||
453 | */ | ||
454 | #define SHARPSL_CNV_VALUE_NUM 10 | ||
455 | static int sharpsl_ad_index; | ||
456 | |||
457 | static void sharpsl_average_clear(void) | ||
458 | { | ||
459 | sharpsl_ad_index = 0; | ||
460 | } | ||
461 | |||
462 | static int sharpsl_average_value(int ad) | ||
463 | { | ||
464 | int i, ad_val = 0; | ||
465 | static int sharpsl_ad[SHARPSL_CNV_VALUE_NUM+1]; | ||
466 | |||
467 | if (sharpsl_pm.battstat.mainbat_status != APM_BATTERY_STATUS_HIGH) { | ||
468 | sharpsl_ad_index = 0; | ||
469 | return ad; | ||
470 | } | ||
471 | |||
472 | sharpsl_ad[sharpsl_ad_index] = ad; | ||
473 | sharpsl_ad_index++; | ||
474 | if (sharpsl_ad_index >= SHARPSL_CNV_VALUE_NUM) { | ||
475 | for (i=0; i < (SHARPSL_CNV_VALUE_NUM-1); i++) | ||
476 | sharpsl_ad[i] = sharpsl_ad[i+1]; | ||
477 | sharpsl_ad_index = SHARPSL_CNV_VALUE_NUM - 1; | ||
478 | } | ||
479 | for (i=0; i < sharpsl_ad_index; i++) | ||
480 | ad_val += sharpsl_ad[i]; | ||
481 | |||
482 | return (ad_val / sharpsl_ad_index); | ||
483 | } | ||
484 | |||
485 | /* | ||
486 | * Take an array of 5 integers, remove the maximum and minimum values | ||
487 | * and return the average. | ||
488 | */ | ||
489 | static int get_select_val(int *val) | ||
490 | { | ||
491 | int i, j, k, temp, sum = 0; | ||
492 | |||
493 | /* Find MAX val */ | ||
494 | temp = val[0]; | ||
495 | j=0; | ||
496 | for (i=1; i<5; i++) { | ||
497 | if (temp < val[i]) { | ||
498 | temp = val[i]; | ||
499 | j = i; | ||
500 | } | ||
501 | } | ||
502 | |||
503 | /* Find MIN val */ | ||
504 | temp = val[4]; | ||
505 | k=4; | ||
506 | for (i=3; i>=0; i--) { | ||
507 | if (temp > val[i]) { | ||
508 | temp = val[i]; | ||
509 | k = i; | ||
510 | } | ||
511 | } | ||
512 | |||
513 | for (i=0; i<5; i++) | ||
514 | if (i != j && i != k ) | ||
515 | sum += val[i]; | ||
516 | |||
517 | dev_dbg(sharpsl_pm.dev, "Average: %d from values: %d, %d, %d, %d, %d\n", sum/3, val[0], val[1], val[2], val[3], val[4]); | ||
518 | |||
519 | return (sum/3); | ||
520 | } | ||
521 | |||
522 | static int sharpsl_check_battery_temp(void) | ||
523 | { | ||
524 | int val, i, buff[5]; | ||
525 | |||
526 | /* Check battery temperature */ | ||
527 | for (i=0; i<5; i++) { | ||
528 | mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP); | ||
529 | sharpsl_pm.machinfo->measure_temp(1); | ||
530 | mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP); | ||
531 | buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_TEMP); | ||
532 | sharpsl_pm.machinfo->measure_temp(0); | ||
533 | } | ||
534 | |||
535 | val = get_select_val(buff); | ||
536 | |||
537 | dev_dbg(sharpsl_pm.dev, "Temperature: %d\n", val); | ||
538 | if (val > sharpsl_pm.machinfo->charge_on_temp) { | ||
539 | printk(KERN_WARNING "Not charging: temperature out of limits.\n"); | ||
540 | return -1; | ||
541 | } | ||
542 | |||
543 | return 0; | ||
544 | } | ||
545 | |||
546 | #ifdef CONFIG_PM | ||
547 | static int sharpsl_check_battery_voltage(void) | ||
548 | { | ||
549 | int val, i, buff[5]; | ||
550 | |||
551 | /* disable charge, enable discharge */ | ||
552 | sharpsl_pm.machinfo->charge(0); | ||
553 | sharpsl_pm.machinfo->discharge(1); | ||
554 | mdelay(SHARPSL_WAIT_DISCHARGE_ON); | ||
555 | |||
556 | if (sharpsl_pm.machinfo->discharge1) | ||
557 | sharpsl_pm.machinfo->discharge1(1); | ||
558 | |||
559 | /* Check battery voltage */ | ||
560 | for (i=0; i<5; i++) { | ||
561 | buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT); | ||
562 | mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT); | ||
563 | } | ||
564 | |||
565 | if (sharpsl_pm.machinfo->discharge1) | ||
566 | sharpsl_pm.machinfo->discharge1(0); | ||
567 | |||
568 | sharpsl_pm.machinfo->discharge(0); | ||
569 | |||
570 | val = get_select_val(buff); | ||
571 | dev_dbg(sharpsl_pm.dev, "Battery Voltage: %d\n", val); | ||
572 | |||
573 | if (val < sharpsl_pm.machinfo->charge_on_volt) | ||
574 | return -1; | ||
575 | |||
576 | return 0; | ||
577 | } | ||
578 | #endif | ||
579 | |||
580 | static int sharpsl_ac_check(void) | ||
581 | { | ||
582 | int temp, i, buff[5]; | ||
583 | |||
584 | for (i=0; i<5; i++) { | ||
585 | buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_ACIN_VOLT); | ||
586 | mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN); | ||
587 | } | ||
588 | |||
589 | temp = get_select_val(buff); | ||
590 | dev_dbg(sharpsl_pm.dev, "AC Voltage: %d\n",temp); | ||
591 | |||
592 | if ((temp > sharpsl_pm.machinfo->charge_acin_high) || (temp < sharpsl_pm.machinfo->charge_acin_low)) { | ||
593 | dev_err(sharpsl_pm.dev, "Error: AC check failed.\n"); | ||
594 | return -1; | ||
595 | } | ||
596 | |||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | #ifdef CONFIG_PM | ||
601 | static int sharpsl_pm_suspend(struct platform_device *pdev, pm_message_t state) | ||
602 | { | ||
603 | sharpsl_pm.flags |= SHARPSL_SUSPENDED; | ||
604 | flush_scheduled_work(); | ||
605 | |||
606 | if (sharpsl_pm.charge_mode == CHRG_ON) | ||
607 | sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG; | ||
608 | else | ||
609 | sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG; | ||
610 | |||
611 | return 0; | ||
612 | } | ||
613 | |||
614 | static int sharpsl_pm_resume(struct platform_device *pdev) | ||
615 | { | ||
616 | /* Clear the reset source indicators as they break the bootloader upon reboot */ | ||
617 | RCSR = 0x0f; | ||
618 | sharpsl_average_clear(); | ||
619 | sharpsl_pm.flags &= ~SHARPSL_APM_QUEUED; | ||
620 | sharpsl_pm.flags &= ~SHARPSL_SUSPENDED; | ||
621 | |||
622 | return 0; | ||
623 | } | ||
624 | |||
625 | static void corgi_goto_sleep(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state) | ||
626 | { | ||
627 | dev_dbg(sharpsl_pm.dev, "Time is: %08x\n",RCNR); | ||
628 | |||
629 | dev_dbg(sharpsl_pm.dev, "Offline Charge Activate = %d\n",sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG); | ||
630 | /* not charging and AC-IN! */ | ||
631 | |||
632 | if ((sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG) && (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN))) { | ||
633 | dev_dbg(sharpsl_pm.dev, "Activating Offline Charger...\n"); | ||
634 | sharpsl_pm.charge_mode = CHRG_OFF; | ||
635 | sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG; | ||
636 | sharpsl_off_charge_battery(); | ||
637 | } | ||
638 | |||
639 | sharpsl_pm.machinfo->presuspend(); | ||
640 | |||
641 | PEDR = 0xffffffff; /* clear it */ | ||
642 | |||
643 | sharpsl_pm.flags &= ~SHARPSL_ALARM_ACTIVE; | ||
644 | if ((sharpsl_pm.charge_mode == CHRG_ON) && ((alarm_enable && ((alarm_time - RCNR) > (SHARPSL_BATCHK_TIME_SUSPEND + 30))) || !alarm_enable)) { | ||
645 | RTSR &= RTSR_ALE; | ||
646 | RTAR = RCNR + SHARPSL_BATCHK_TIME_SUSPEND; | ||
647 | dev_dbg(sharpsl_pm.dev, "Charging alarm at: %08x\n",RTAR); | ||
648 | sharpsl_pm.flags |= SHARPSL_ALARM_ACTIVE; | ||
649 | } else if (alarm_enable) { | ||
650 | RTSR &= RTSR_ALE; | ||
651 | RTAR = alarm_time; | ||
652 | dev_dbg(sharpsl_pm.dev, "User alarm at: %08x\n",RTAR); | ||
653 | } else { | ||
654 | dev_dbg(sharpsl_pm.dev, "No alarms set.\n"); | ||
655 | } | ||
656 | |||
657 | pxa_pm_enter(state); | ||
658 | |||
659 | sharpsl_pm.machinfo->postsuspend(); | ||
660 | |||
661 | dev_dbg(sharpsl_pm.dev, "Corgi woken up from suspend: %08x\n",PEDR); | ||
662 | } | ||
663 | |||
664 | static int corgi_enter_suspend(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state) | ||
665 | { | ||
666 | if (!sharpsl_pm.machinfo->should_wakeup(!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE) && alarm_enable) ) | ||
667 | { | ||
668 | if (!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE)) { | ||
669 | dev_dbg(sharpsl_pm.dev, "No user triggered wakeup events and not charging. Strange. Suspend.\n"); | ||
670 | corgi_goto_sleep(alarm_time, alarm_enable, state); | ||
671 | return 1; | ||
672 | } | ||
673 | if(sharpsl_off_charge_battery()) { | ||
674 | dev_dbg(sharpsl_pm.dev, "Charging. Suspend...\n"); | ||
675 | corgi_goto_sleep(alarm_time, alarm_enable, state); | ||
676 | return 1; | ||
677 | } | ||
678 | dev_dbg(sharpsl_pm.dev, "User triggered wakeup in offline charger.\n"); | ||
679 | } | ||
680 | |||
681 | if ((!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) || (sharpsl_fatal_check() < 0) ) | ||
682 | { | ||
683 | dev_err(sharpsl_pm.dev, "Fatal condition. Suspend.\n"); | ||
684 | corgi_goto_sleep(alarm_time, alarm_enable, state); | ||
685 | return 1; | ||
686 | } | ||
687 | |||
688 | return 0; | ||
689 | } | ||
690 | |||
691 | static int corgi_pxa_pm_enter(suspend_state_t state) | ||
692 | { | ||
693 | unsigned long alarm_time = RTAR; | ||
694 | unsigned int alarm_status = ((RTSR & RTSR_ALE) != 0); | ||
695 | |||
696 | dev_dbg(sharpsl_pm.dev, "SharpSL suspending for first time.\n"); | ||
697 | |||
698 | corgi_goto_sleep(alarm_time, alarm_status, state); | ||
699 | |||
700 | while (corgi_enter_suspend(alarm_time,alarm_status,state)) | ||
701 | {} | ||
702 | |||
703 | if (sharpsl_pm.machinfo->earlyresume) | ||
704 | sharpsl_pm.machinfo->earlyresume(); | ||
705 | |||
706 | dev_dbg(sharpsl_pm.dev, "SharpSL resuming...\n"); | ||
707 | |||
708 | return 0; | ||
709 | } | ||
710 | |||
711 | /* | ||
712 | * Check for fatal battery errors | ||
713 | * Fatal returns -1 | ||
714 | */ | ||
715 | static int sharpsl_fatal_check(void) | ||
716 | { | ||
717 | int buff[5], temp, i, acin; | ||
718 | |||
719 | dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check entered\n"); | ||
720 | |||
721 | /* Check AC-Adapter */ | ||
722 | acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN); | ||
723 | |||
724 | if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) { | ||
725 | sharpsl_pm.machinfo->charge(0); | ||
726 | udelay(100); | ||
727 | sharpsl_pm.machinfo->discharge(1); /* enable discharge */ | ||
728 | mdelay(SHARPSL_WAIT_DISCHARGE_ON); | ||
729 | } | ||
730 | |||
731 | if (sharpsl_pm.machinfo->discharge1) | ||
732 | sharpsl_pm.machinfo->discharge1(1); | ||
733 | |||
734 | /* Check battery : check inserting battery ? */ | ||
735 | for (i=0; i<5; i++) { | ||
736 | buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT); | ||
737 | mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT); | ||
738 | } | ||
739 | |||
740 | if (sharpsl_pm.machinfo->discharge1) | ||
741 | sharpsl_pm.machinfo->discharge1(0); | ||
742 | |||
743 | if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) { | ||
744 | udelay(100); | ||
745 | sharpsl_pm.machinfo->charge(1); | ||
746 | sharpsl_pm.machinfo->discharge(0); | ||
747 | } | ||
748 | |||
749 | temp = get_select_val(buff); | ||
750 | dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check: acin: %d, discharge voltage: %d, no discharge: %ld\n", acin, temp, sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT)); | ||
751 | |||
752 | if ((acin && (temp < sharpsl_pm.machinfo->fatal_acin_volt)) || | ||
753 | (!acin && (temp < sharpsl_pm.machinfo->fatal_noacin_volt))) | ||
754 | return -1; | ||
755 | return 0; | ||
756 | } | ||
757 | |||
758 | static int sharpsl_off_charge_error(void) | ||
759 | { | ||
760 | dev_err(sharpsl_pm.dev, "Offline Charger: Error occurred.\n"); | ||
761 | sharpsl_pm.machinfo->charge(0); | ||
762 | sharpsl_pm_led(SHARPSL_LED_ERROR); | ||
763 | sharpsl_pm.charge_mode = CHRG_ERROR; | ||
764 | return 1; | ||
765 | } | ||
766 | |||
767 | /* | ||
768 | * Charging Control while suspended | ||
769 | * Return 1 - go straight to sleep | ||
770 | * Return 0 - sleep or wakeup depending on other factors | ||
771 | */ | ||
772 | static int sharpsl_off_charge_battery(void) | ||
773 | { | ||
774 | int time; | ||
775 | |||
776 | dev_dbg(sharpsl_pm.dev, "Charge Mode: %d\n", sharpsl_pm.charge_mode); | ||
777 | |||
778 | if (sharpsl_pm.charge_mode == CHRG_OFF) { | ||
779 | dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 1\n"); | ||
780 | |||
781 | /* AC Check */ | ||
782 | if ((sharpsl_ac_check() < 0) || (sharpsl_check_battery_temp() < 0)) | ||
783 | return sharpsl_off_charge_error(); | ||
784 | |||
785 | /* Start Charging */ | ||
786 | sharpsl_pm_led(SHARPSL_LED_ON); | ||
787 | sharpsl_pm.machinfo->charge(0); | ||
788 | mdelay(SHARPSL_CHARGE_WAIT_TIME); | ||
789 | sharpsl_pm.machinfo->charge(1); | ||
790 | |||
791 | sharpsl_pm.charge_mode = CHRG_ON; | ||
792 | sharpsl_pm.full_count = 0; | ||
793 | |||
794 | return 1; | ||
795 | } else if (sharpsl_pm.charge_mode != CHRG_ON) { | ||
796 | return 1; | ||
797 | } | ||
798 | |||
799 | if (sharpsl_pm.full_count == 0) { | ||
800 | int time; | ||
801 | |||
802 | dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 2\n"); | ||
803 | |||
804 | if ((sharpsl_check_battery_temp() < 0) || (sharpsl_check_battery_voltage() < 0)) | ||
805 | return sharpsl_off_charge_error(); | ||
806 | |||
807 | sharpsl_pm.machinfo->charge(0); | ||
808 | mdelay(SHARPSL_CHARGE_WAIT_TIME); | ||
809 | sharpsl_pm.machinfo->charge(1); | ||
810 | sharpsl_pm.charge_mode = CHRG_ON; | ||
811 | |||
812 | mdelay(SHARPSL_CHARGE_CO_CHECK_TIME); | ||
813 | |||
814 | time = RCNR; | ||
815 | while(1) { | ||
816 | /* Check if any wakeup event had occurred */ | ||
817 | if (sharpsl_pm.machinfo->charger_wakeup() != 0) | ||
818 | return 0; | ||
819 | /* Check for timeout */ | ||
820 | if ((RCNR - time) > SHARPSL_WAIT_CO_TIME) | ||
821 | return 1; | ||
822 | if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_CHRGFULL)) { | ||
823 | dev_dbg(sharpsl_pm.dev, "Offline Charger: Charge full occurred. Retrying to check\n"); | ||
824 | sharpsl_pm.full_count++; | ||
825 | sharpsl_pm.machinfo->charge(0); | ||
826 | mdelay(SHARPSL_CHARGE_WAIT_TIME); | ||
827 | sharpsl_pm.machinfo->charge(1); | ||
828 | return 1; | ||
829 | } | ||
830 | } | ||
831 | } | ||
832 | |||
833 | dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 3\n"); | ||
834 | |||
835 | mdelay(SHARPSL_CHARGE_CO_CHECK_TIME); | ||
836 | |||
837 | time = RCNR; | ||
838 | while(1) { | ||
839 | /* Check if any wakeup event had occurred */ | ||
840 | if (sharpsl_pm.machinfo->charger_wakeup() != 0) | ||
841 | return 0; | ||
842 | /* Check for timeout */ | ||
843 | if ((RCNR-time) > SHARPSL_WAIT_CO_TIME) { | ||
844 | if (sharpsl_pm.full_count > SHARPSL_CHARGE_RETRY_CNT) { | ||
845 | dev_dbg(sharpsl_pm.dev, "Offline Charger: Not charged sufficiently. Retrying.\n"); | ||
846 | sharpsl_pm.full_count = 0; | ||
847 | } | ||
848 | sharpsl_pm.full_count++; | ||
849 | return 1; | ||
850 | } | ||
851 | if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_CHRGFULL)) { | ||
852 | dev_dbg(sharpsl_pm.dev, "Offline Charger: Charging complete.\n"); | ||
853 | sharpsl_pm_led(SHARPSL_LED_OFF); | ||
854 | sharpsl_pm.machinfo->charge(0); | ||
855 | sharpsl_pm.charge_mode = CHRG_DONE; | ||
856 | return 1; | ||
857 | } | ||
858 | } | ||
859 | } | ||
860 | #else | ||
861 | #define sharpsl_pm_suspend NULL | ||
862 | #define sharpsl_pm_resume NULL | ||
863 | #endif | ||
864 | |||
865 | static ssize_t battery_percentage_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
866 | { | ||
867 | return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_percent); | ||
868 | } | ||
869 | |||
870 | static ssize_t battery_voltage_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
871 | { | ||
872 | return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_voltage); | ||
873 | } | ||
874 | |||
875 | static DEVICE_ATTR(battery_percentage, 0444, battery_percentage_show, NULL); | ||
876 | static DEVICE_ATTR(battery_voltage, 0444, battery_voltage_show, NULL); | ||
877 | |||
878 | extern void (*apm_get_power_status)(struct apm_power_info *); | ||
879 | |||
880 | static void sharpsl_apm_get_power_status(struct apm_power_info *info) | ||
881 | { | ||
882 | info->ac_line_status = sharpsl_pm.battstat.ac_status; | ||
883 | |||
884 | if (sharpsl_pm.charge_mode == CHRG_ON) | ||
885 | info->battery_status = APM_BATTERY_STATUS_CHARGING; | ||
886 | else | ||
887 | info->battery_status = sharpsl_pm.battstat.mainbat_status; | ||
888 | |||
889 | info->battery_flag = (1 << info->battery_status); | ||
890 | info->battery_life = sharpsl_pm.battstat.mainbat_percent; | ||
891 | } | ||
892 | |||
893 | #ifdef CONFIG_PM | ||
894 | static struct platform_suspend_ops sharpsl_pm_ops = { | ||
895 | .prepare = pxa_pm_prepare, | ||
896 | .finish = pxa_pm_finish, | ||
897 | .enter = corgi_pxa_pm_enter, | ||
898 | .valid = suspend_valid_only_mem, | ||
899 | }; | ||
900 | #endif | ||
901 | |||
902 | static int __init sharpsl_pm_probe(struct platform_device *pdev) | ||
903 | { | ||
904 | int ret; | ||
905 | |||
906 | if (!pdev->dev.platform_data) | ||
907 | return -EINVAL; | ||
908 | |||
909 | sharpsl_pm.dev = &pdev->dev; | ||
910 | sharpsl_pm.machinfo = pdev->dev.platform_data; | ||
911 | sharpsl_pm.charge_mode = CHRG_OFF; | ||
912 | sharpsl_pm.flags = 0; | ||
913 | |||
914 | init_timer(&sharpsl_pm.ac_timer); | ||
915 | sharpsl_pm.ac_timer.function = sharpsl_ac_timer; | ||
916 | |||
917 | init_timer(&sharpsl_pm.chrg_full_timer); | ||
918 | sharpsl_pm.chrg_full_timer.function = sharpsl_chrg_full_timer; | ||
919 | |||
920 | led_trigger_register_simple("sharpsl-charge", &sharpsl_charge_led_trigger); | ||
921 | |||
922 | sharpsl_pm.machinfo->init(); | ||
923 | |||
924 | gpio_request(sharpsl_pm.machinfo->gpio_acin, "AC IN"); | ||
925 | gpio_direction_input(sharpsl_pm.machinfo->gpio_acin); | ||
926 | gpio_request(sharpsl_pm.machinfo->gpio_batfull, "Battery Full"); | ||
927 | gpio_direction_input(sharpsl_pm.machinfo->gpio_batfull); | ||
928 | gpio_request(sharpsl_pm.machinfo->gpio_batlock, "Battery Lock"); | ||
929 | gpio_direction_input(sharpsl_pm.machinfo->gpio_batlock); | ||
152 | 930 | ||
153 | /* Register interrupt handlers */ | 931 | /* Register interrupt handlers */ |
154 | if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr, IRQF_DISABLED, "AC Input Detect", sharpsl_ac_isr)) { | 932 | if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr, IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "AC Input Detect", sharpsl_ac_isr)) { |
155 | dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin)); | 933 | dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin)); |
156 | } | 934 | } |
157 | else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin),IRQ_TYPE_EDGE_BOTH); | ||
158 | 935 | ||
159 | if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr, IRQF_DISABLED, "Battery Cover", sharpsl_fatal_isr)) { | 936 | if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr, IRQF_DISABLED | IRQF_TRIGGER_FALLING, "Battery Cover", sharpsl_fatal_isr)) { |
160 | dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock)); | 937 | dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock)); |
161 | } | 938 | } |
162 | else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock),IRQ_TYPE_EDGE_FALLING); | ||
163 | 939 | ||
164 | if (sharpsl_pm.machinfo->gpio_fatal) { | 940 | if (sharpsl_pm.machinfo->gpio_fatal) { |
165 | if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal), sharpsl_fatal_isr, IRQF_DISABLED, "Fatal Battery", sharpsl_fatal_isr)) { | 941 | if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal), sharpsl_fatal_isr, IRQF_DISABLED | IRQF_TRIGGER_FALLING, "Fatal Battery", sharpsl_fatal_isr)) { |
166 | dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal)); | 942 | dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal)); |
167 | } | 943 | } |
168 | else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_fatal),IRQ_TYPE_EDGE_FALLING); | ||
169 | } | 944 | } |
170 | 945 | ||
171 | if (sharpsl_pm.machinfo->batfull_irq) | 946 | if (sharpsl_pm.machinfo->batfull_irq) |
172 | { | 947 | { |
173 | /* Register interrupt handler. */ | 948 | /* Register interrupt handler. */ |
174 | if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull), sharpsl_chrg_full_isr, IRQF_DISABLED, "CO", sharpsl_chrg_full_isr)) { | 949 | if (request_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull), sharpsl_chrg_full_isr, IRQF_DISABLED | IRQF_TRIGGER_RISING, "CO", sharpsl_chrg_full_isr)) { |
175 | dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull)); | 950 | dev_err(sharpsl_pm.dev, "Could not get irq %d.\n", IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull)); |
176 | } | 951 | } |
177 | else set_irq_type(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull),IRQ_TYPE_EDGE_RISING); | ||
178 | } | 952 | } |
953 | |||
954 | ret = device_create_file(&pdev->dev, &dev_attr_battery_percentage); | ||
955 | ret |= device_create_file(&pdev->dev, &dev_attr_battery_voltage); | ||
956 | if (ret != 0) | ||
957 | dev_warn(&pdev->dev, "Failed to register attributes (%d)\n", ret); | ||
958 | |||
959 | apm_get_power_status = sharpsl_apm_get_power_status; | ||
960 | |||
961 | #ifdef CONFIG_PM | ||
962 | suspend_set_ops(&sharpsl_pm_ops); | ||
963 | #endif | ||
964 | |||
965 | mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250)); | ||
966 | |||
967 | return 0; | ||
179 | } | 968 | } |
180 | 969 | ||
181 | void sharpsl_pm_pxa_remove(void) | 970 | static int sharpsl_pm_remove(struct platform_device *pdev) |
182 | { | 971 | { |
972 | suspend_set_ops(NULL); | ||
973 | |||
974 | device_remove_file(&pdev->dev, &dev_attr_battery_percentage); | ||
975 | device_remove_file(&pdev->dev, &dev_attr_battery_voltage); | ||
976 | |||
977 | led_trigger_unregister_simple(sharpsl_charge_led_trigger); | ||
978 | |||
183 | free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr); | 979 | free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_acin), sharpsl_ac_isr); |
184 | free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr); | 980 | free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batlock), sharpsl_fatal_isr); |
185 | 981 | ||
@@ -188,4 +984,39 @@ void sharpsl_pm_pxa_remove(void) | |||
188 | 984 | ||
189 | if (sharpsl_pm.machinfo->batfull_irq) | 985 | if (sharpsl_pm.machinfo->batfull_irq) |
190 | free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull), sharpsl_chrg_full_isr); | 986 | free_irq(IRQ_GPIO(sharpsl_pm.machinfo->gpio_batfull), sharpsl_chrg_full_isr); |
987 | |||
988 | gpio_free(sharpsl_pm.machinfo->gpio_batlock); | ||
989 | gpio_free(sharpsl_pm.machinfo->gpio_batfull); | ||
990 | gpio_free(sharpsl_pm.machinfo->gpio_acin); | ||
991 | |||
992 | if (sharpsl_pm.machinfo->exit) | ||
993 | sharpsl_pm.machinfo->exit(); | ||
994 | |||
995 | del_timer_sync(&sharpsl_pm.chrg_full_timer); | ||
996 | del_timer_sync(&sharpsl_pm.ac_timer); | ||
997 | |||
998 | return 0; | ||
191 | } | 999 | } |
1000 | |||
1001 | static struct platform_driver sharpsl_pm_driver = { | ||
1002 | .probe = sharpsl_pm_probe, | ||
1003 | .remove = sharpsl_pm_remove, | ||
1004 | .suspend = sharpsl_pm_suspend, | ||
1005 | .resume = sharpsl_pm_resume, | ||
1006 | .driver = { | ||
1007 | .name = "sharpsl-pm", | ||
1008 | }, | ||
1009 | }; | ||
1010 | |||
1011 | static int __devinit sharpsl_pm_init(void) | ||
1012 | { | ||
1013 | return platform_driver_register(&sharpsl_pm_driver); | ||
1014 | } | ||
1015 | |||
1016 | static void sharpsl_pm_exit(void) | ||
1017 | { | ||
1018 | platform_driver_unregister(&sharpsl_pm_driver); | ||
1019 | } | ||
1020 | |||
1021 | late_initcall(sharpsl_pm_init); | ||
1022 | module_exit(sharpsl_pm_exit); | ||