Merge branch 'bkl-removal' into next
[pandora-kernel.git] / arch / arm / common / sharpsl_pm.c
1 /*
2  * Battery and Power Management code for the Sharp SL-C7xx and SL-Cxx00
3  * series of PDAs
4  *
5  * Copyright (c) 2004-2005 Richard Purdie
6  *
7  * Based on code written by Sharp for 2.4 kernels
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  *
13  */
14
15 #undef DEBUG
16
17 #include <linux/module.h>
18 #include <linux/timer.h>
19 #include <linux/init.h>
20 #include <linux/kernel.h>
21 #include <linux/apm_bios.h>
22 #include <linux/delay.h>
23 #include <linux/interrupt.h>
24 #include <linux/platform_device.h>
25 #include <linux/leds.h>
26 #include <linux/apm-emulation.h>
27 #include <linux/suspend.h>
28
29 #include <asm/hardware.h>
30 #include <asm/mach-types.h>
31 #include <asm/irq.h>
32 #include <asm/arch/pm.h>
33 #include <asm/arch/pxa-regs.h>
34 #include <asm/arch/pxa2xx-regs.h>
35 #include <asm/arch/sharpsl.h>
36 #include <asm/hardware/sharpsl_pm.h>
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 static int sharpsl_off_charge_battery(void);
59 static int sharpsl_check_battery_temp(void);
60 static int sharpsl_check_battery_voltage(void);
61 static int sharpsl_ac_check(void);
62 static int sharpsl_fatal_check(void);
63 static int sharpsl_average_value(int ad);
64 static void sharpsl_average_clear(void);
65 static void sharpsl_charge_toggle(struct work_struct *private_);
66 static void sharpsl_battery_thread(struct work_struct *private_);
67
68
69 /*
70  * Variables
71  */
72 struct sharpsl_pm_status sharpsl_pm;
73 DECLARE_DELAYED_WORK(toggle_charger, sharpsl_charge_toggle);
74 DECLARE_DELAYED_WORK(sharpsl_bat, sharpsl_battery_thread);
75 DEFINE_LED_TRIGGER(sharpsl_charge_led_trigger);
76
77
78 static int get_percentage(int voltage)
79 {
80         int i = sharpsl_pm.machinfo->bat_levels - 1;
81         int bl_status = sharpsl_pm.machinfo->backlight_get_status ? sharpsl_pm.machinfo->backlight_get_status() : 0;
82         struct battery_thresh *thresh;
83
84         if (sharpsl_pm.charge_mode == CHRG_ON)
85                 thresh = bl_status ? sharpsl_pm.machinfo->bat_levels_acin_bl : sharpsl_pm.machinfo->bat_levels_acin;
86         else
87                 thresh = bl_status ? sharpsl_pm.machinfo->bat_levels_noac_bl : sharpsl_pm.machinfo->bat_levels_noac;
88
89         while (i > 0 && (voltage > thresh[i].voltage))
90                 i--;
91
92         return thresh[i].percentage;
93 }
94
95 static int get_apm_status(int voltage)
96 {
97         int low_thresh, high_thresh;
98
99         if (sharpsl_pm.charge_mode == CHRG_ON) {
100                 high_thresh = sharpsl_pm.machinfo->status_high_acin;
101                 low_thresh = sharpsl_pm.machinfo->status_low_acin;
102         } else {
103                 high_thresh = sharpsl_pm.machinfo->status_high_noac;
104                 low_thresh = sharpsl_pm.machinfo->status_low_noac;
105         }
106
107         if (voltage >= high_thresh)
108                 return APM_BATTERY_STATUS_HIGH;
109         if (voltage >= low_thresh)
110                 return APM_BATTERY_STATUS_LOW;
111         return APM_BATTERY_STATUS_CRITICAL;
112 }
113
114 void sharpsl_battery_kick(void)
115 {
116         schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(125));
117 }
118 EXPORT_SYMBOL(sharpsl_battery_kick);
119
120
121 static void sharpsl_battery_thread(struct work_struct *private_)
122 {
123         int voltage, percent, apm_status, i = 0;
124
125         if (!sharpsl_pm.machinfo)
126                 return;
127
128         sharpsl_pm.battstat.ac_status = (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN) ? APM_AC_ONLINE : APM_AC_OFFLINE);
129
130         /* Corgi cannot confirm when battery fully charged so periodically kick! */
131         if (!sharpsl_pm.machinfo->batfull_irq && (sharpsl_pm.charge_mode == CHRG_ON)
132                         && time_after(jiffies, sharpsl_pm.charge_start_time +  SHARPSL_CHARGE_ON_TIME_INTERVAL))
133                 schedule_delayed_work(&toggle_charger, 0);
134
135         while(1) {
136                 voltage = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
137
138                 if (voltage > 0) break;
139                 if (i++ > 5) {
140                         voltage = sharpsl_pm.machinfo->bat_levels_noac[0].voltage;
141                         dev_warn(sharpsl_pm.dev, "Warning: Cannot read main battery!\n");
142                         break;
143                 }
144         }
145
146         voltage = sharpsl_average_value(voltage);
147         apm_status = get_apm_status(voltage);
148         percent = get_percentage(voltage);
149
150         /* At low battery voltages, the voltage has a tendency to start
151            creeping back up so we try to avoid this here */
152         if ((sharpsl_pm.battstat.ac_status == APM_AC_ONLINE) || (apm_status == APM_BATTERY_STATUS_HIGH) ||  percent <= sharpsl_pm.battstat.mainbat_percent) {
153                 sharpsl_pm.battstat.mainbat_voltage = voltage;
154                 sharpsl_pm.battstat.mainbat_status = apm_status;
155                 sharpsl_pm.battstat.mainbat_percent = percent;
156         }
157
158         dev_dbg(sharpsl_pm.dev, "Battery: voltage: %d, status: %d, percentage: %d, time: %ld\n", voltage,
159                         sharpsl_pm.battstat.mainbat_status, sharpsl_pm.battstat.mainbat_percent, jiffies);
160
161 #ifdef CONFIG_BACKLIGHT_CORGI
162         /* If battery is low. limit backlight intensity to save power. */
163         if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE)
164                         && ((sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_LOW) ||
165                         (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL))) {
166                 if (!(sharpsl_pm.flags & SHARPSL_BL_LIMIT)) {
167                         sharpsl_pm.machinfo->backlight_limit(1);
168                         sharpsl_pm.flags |= SHARPSL_BL_LIMIT;
169                 }
170         } else if (sharpsl_pm.flags & SHARPSL_BL_LIMIT) {
171                 sharpsl_pm.machinfo->backlight_limit(0);
172                 sharpsl_pm.flags &= ~SHARPSL_BL_LIMIT;
173         }
174 #endif
175
176         /* Suspend if critical battery level */
177         if ((sharpsl_pm.battstat.ac_status != APM_AC_ONLINE)
178                         && (sharpsl_pm.battstat.mainbat_status == APM_BATTERY_STATUS_CRITICAL)
179                         && !(sharpsl_pm.flags & SHARPSL_APM_QUEUED)) {
180                 sharpsl_pm.flags |= SHARPSL_APM_QUEUED;
181                 dev_err(sharpsl_pm.dev, "Fatal Off\n");
182                 apm_queue_event(APM_CRITICAL_SUSPEND);
183         }
184
185         schedule_delayed_work(&sharpsl_bat, SHARPSL_BATCHK_TIME);
186 }
187
188 void sharpsl_pm_led(int val)
189 {
190         if (val == SHARPSL_LED_ERROR) {
191                 dev_err(sharpsl_pm.dev, "Charging Error!\n");
192         } else if (val == SHARPSL_LED_ON) {
193                 dev_dbg(sharpsl_pm.dev, "Charge LED On\n");
194                 led_trigger_event(sharpsl_charge_led_trigger, LED_FULL);
195         } else {
196                 dev_dbg(sharpsl_pm.dev, "Charge LED Off\n");
197                 led_trigger_event(sharpsl_charge_led_trigger, LED_OFF);
198         }
199 }
200
201 static void sharpsl_charge_on(void)
202 {
203         dev_dbg(sharpsl_pm.dev, "Turning Charger On\n");
204
205         sharpsl_pm.full_count = 0;
206         sharpsl_pm.charge_mode = CHRG_ON;
207         schedule_delayed_work(&toggle_charger, msecs_to_jiffies(250));
208         schedule_delayed_work(&sharpsl_bat, msecs_to_jiffies(500));
209 }
210
211 static void sharpsl_charge_off(void)
212 {
213         dev_dbg(sharpsl_pm.dev, "Turning Charger Off\n");
214
215         sharpsl_pm.machinfo->charge(0);
216         sharpsl_pm_led(SHARPSL_LED_OFF);
217         sharpsl_pm.charge_mode = CHRG_OFF;
218
219         schedule_delayed_work(&sharpsl_bat, 0);
220 }
221
222 static void sharpsl_charge_error(void)
223 {
224         sharpsl_pm_led(SHARPSL_LED_ERROR);
225         sharpsl_pm.machinfo->charge(0);
226         sharpsl_pm.charge_mode = CHRG_ERROR;
227 }
228
229 static void sharpsl_charge_toggle(struct work_struct *private_)
230 {
231         dev_dbg(sharpsl_pm.dev, "Toogling Charger at time: %lx\n", jiffies);
232
233         if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) {
234                 sharpsl_charge_off();
235                 return;
236         } else if ((sharpsl_check_battery_temp() < 0) || (sharpsl_ac_check() < 0)) {
237                 sharpsl_charge_error();
238                 return;
239         }
240
241         sharpsl_pm_led(SHARPSL_LED_ON);
242         sharpsl_pm.machinfo->charge(0);
243         mdelay(SHARPSL_CHARGE_WAIT_TIME);
244         sharpsl_pm.machinfo->charge(1);
245
246         sharpsl_pm.charge_start_time = jiffies;
247 }
248
249 static void sharpsl_ac_timer(unsigned long data)
250 {
251         int acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN);
252
253         dev_dbg(sharpsl_pm.dev, "AC Status: %d\n",acin);
254
255         sharpsl_average_clear();
256         if (acin && (sharpsl_pm.charge_mode != CHRG_ON))
257                 sharpsl_charge_on();
258         else if (sharpsl_pm.charge_mode == CHRG_ON)
259                 sharpsl_charge_off();
260
261         schedule_delayed_work(&sharpsl_bat, 0);
262 }
263
264
265 irqreturn_t sharpsl_ac_isr(int irq, void *dev_id)
266 {
267         /* Delay the event slightly to debounce */
268         /* Must be a smaller delay than the chrg_full_isr below */
269         mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250));
270
271         return IRQ_HANDLED;
272 }
273
274 static void sharpsl_chrg_full_timer(unsigned long data)
275 {
276         dev_dbg(sharpsl_pm.dev, "Charge Full at time: %lx\n", jiffies);
277
278         sharpsl_pm.full_count++;
279
280         if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN)) {
281                 dev_dbg(sharpsl_pm.dev, "Charge Full: AC removed - stop charging!\n");
282                 if (sharpsl_pm.charge_mode == CHRG_ON)
283                         sharpsl_charge_off();
284         } else if (sharpsl_pm.full_count < 2) {
285                 dev_dbg(sharpsl_pm.dev, "Charge Full: Count too low\n");
286                 schedule_delayed_work(&toggle_charger, 0);
287         } else if (time_after(jiffies, sharpsl_pm.charge_start_time + SHARPSL_CHARGE_FINISH_TIME)) {
288                 dev_dbg(sharpsl_pm.dev, "Charge Full: Interrupt generated too slowly - retry.\n");
289                 schedule_delayed_work(&toggle_charger, 0);
290         } else {
291                 sharpsl_charge_off();
292                 sharpsl_pm.charge_mode = CHRG_DONE;
293                 dev_dbg(sharpsl_pm.dev, "Charge Full: Charging Finished\n");
294         }
295 }
296
297 /* Charging Finished Interrupt (Not present on Corgi) */
298 /* Can trigger at the same time as an AC status change so
299    delay until after that has been processed */
300 irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id)
301 {
302         if (sharpsl_pm.flags & SHARPSL_SUSPENDED)
303                 return IRQ_HANDLED;
304
305         /* delay until after any ac interrupt */
306         mod_timer(&sharpsl_pm.chrg_full_timer, jiffies + msecs_to_jiffies(500));
307
308         return IRQ_HANDLED;
309 }
310
311 irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id)
312 {
313         int is_fatal = 0;
314
315         if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) {
316                 dev_err(sharpsl_pm.dev, "Battery now Unlocked! Suspending.\n");
317                 is_fatal = 1;
318         }
319
320         if (!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_FATAL)) {
321                 dev_err(sharpsl_pm.dev, "Fatal Batt Error! Suspending.\n");
322                 is_fatal = 1;
323         }
324
325         if (!(sharpsl_pm.flags & SHARPSL_APM_QUEUED) && is_fatal) {
326                 sharpsl_pm.flags |= SHARPSL_APM_QUEUED;
327                 apm_queue_event(APM_CRITICAL_SUSPEND);
328         }
329
330         return IRQ_HANDLED;
331 }
332
333 /*
334  * Maintain an average of the last 10 readings
335  */
336 #define SHARPSL_CNV_VALUE_NUM    10
337 static int sharpsl_ad_index;
338
339 static void sharpsl_average_clear(void)
340 {
341         sharpsl_ad_index = 0;
342 }
343
344 static int sharpsl_average_value(int ad)
345 {
346         int i, ad_val = 0;
347         static int sharpsl_ad[SHARPSL_CNV_VALUE_NUM+1];
348
349         if (sharpsl_pm.battstat.mainbat_status != APM_BATTERY_STATUS_HIGH) {
350                 sharpsl_ad_index = 0;
351                 return ad;
352         }
353
354         sharpsl_ad[sharpsl_ad_index] = ad;
355         sharpsl_ad_index++;
356         if (sharpsl_ad_index >= SHARPSL_CNV_VALUE_NUM) {
357                 for (i=0; i < (SHARPSL_CNV_VALUE_NUM-1); i++)
358                         sharpsl_ad[i] = sharpsl_ad[i+1];
359                 sharpsl_ad_index = SHARPSL_CNV_VALUE_NUM - 1;
360         }
361         for (i=0; i < sharpsl_ad_index; i++)
362                 ad_val += sharpsl_ad[i];
363
364         return (ad_val / sharpsl_ad_index);
365 }
366
367 /*
368  * Take an array of 5 integers, remove the maximum and minimum values
369  * and return the average.
370  */
371 static int get_select_val(int *val)
372 {
373         int i, j, k, temp, sum = 0;
374
375         /* Find MAX val */
376         temp = val[0];
377         j=0;
378         for (i=1; i<5; i++) {
379                 if (temp < val[i]) {
380                         temp = val[i];
381                         j = i;
382                 }
383         }
384
385         /* Find MIN val */
386         temp = val[4];
387         k=4;
388         for (i=3; i>=0; i--) {
389                 if (temp > val[i]) {
390                         temp = val[i];
391                         k = i;
392                 }
393         }
394
395         for (i=0; i<5; i++)
396                 if (i != j && i != k )
397                         sum += val[i];
398
399         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]);
400
401         return (sum/3);
402 }
403
404 static int sharpsl_check_battery_temp(void)
405 {
406         int val, i, buff[5];
407
408         /* Check battery temperature */
409         for (i=0; i<5; i++) {
410                 mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);
411                 sharpsl_pm.machinfo->measure_temp(1);
412                 mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP);
413                 buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_TEMP);
414                 sharpsl_pm.machinfo->measure_temp(0);
415         }
416
417         val = get_select_val(buff);
418
419         dev_dbg(sharpsl_pm.dev, "Temperature: %d\n", val);
420         if (val > sharpsl_pm.machinfo->charge_on_temp) {
421                 printk(KERN_WARNING "Not charging: temperature out of limits.\n");
422                 return -1;
423         }
424
425         return 0;
426 }
427
428 static int sharpsl_check_battery_voltage(void)
429 {
430         int val, i, buff[5];
431
432         /* disable charge, enable discharge */
433         sharpsl_pm.machinfo->charge(0);
434         sharpsl_pm.machinfo->discharge(1);
435         mdelay(SHARPSL_WAIT_DISCHARGE_ON);
436
437         if (sharpsl_pm.machinfo->discharge1)
438                 sharpsl_pm.machinfo->discharge1(1);
439
440         /* Check battery voltage */
441         for (i=0; i<5; i++) {
442                 buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
443                 mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
444         }
445
446         if (sharpsl_pm.machinfo->discharge1)
447                 sharpsl_pm.machinfo->discharge1(0);
448
449         sharpsl_pm.machinfo->discharge(0);
450
451         val = get_select_val(buff);
452         dev_dbg(sharpsl_pm.dev, "Battery Voltage: %d\n", val);
453
454         if (val < sharpsl_pm.machinfo->charge_on_volt)
455                 return -1;
456
457         return 0;
458 }
459
460 static int sharpsl_ac_check(void)
461 {
462         int temp, i, buff[5];
463
464         for (i=0; i<5; i++) {
465                 buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_ACIN_VOLT);
466                 mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_ACIN);
467         }
468
469         temp = get_select_val(buff);
470         dev_dbg(sharpsl_pm.dev, "AC Voltage: %d\n",temp);
471
472         if ((temp > sharpsl_pm.machinfo->charge_acin_high) || (temp < sharpsl_pm.machinfo->charge_acin_low)) {
473                 dev_err(sharpsl_pm.dev, "Error: AC check failed.\n");
474                 return -1;
475         }
476
477         return 0;
478 }
479
480 #ifdef CONFIG_PM
481 static int sharpsl_pm_suspend(struct platform_device *pdev, pm_message_t state)
482 {
483         sharpsl_pm.flags |= SHARPSL_SUSPENDED;
484         flush_scheduled_work();
485
486         if (sharpsl_pm.charge_mode == CHRG_ON)
487                 sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG;
488         else
489                 sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG;
490
491         return 0;
492 }
493
494 static int sharpsl_pm_resume(struct platform_device *pdev)
495 {
496         /* Clear the reset source indicators as they break the bootloader upon reboot */
497         RCSR = 0x0f;
498         sharpsl_average_clear();
499         sharpsl_pm.flags &= ~SHARPSL_APM_QUEUED;
500         sharpsl_pm.flags &= ~SHARPSL_SUSPENDED;
501
502         return 0;
503 }
504
505 static void corgi_goto_sleep(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state)
506 {
507         dev_dbg(sharpsl_pm.dev, "Time is: %08x\n",RCNR);
508
509         dev_dbg(sharpsl_pm.dev, "Offline Charge Activate = %d\n",sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG);
510         /* not charging and AC-IN! */
511
512         if ((sharpsl_pm.flags & SHARPSL_DO_OFFLINE_CHRG) && (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN))) {
513                 dev_dbg(sharpsl_pm.dev, "Activating Offline Charger...\n");
514                 sharpsl_pm.charge_mode = CHRG_OFF;
515                 sharpsl_pm.flags &= ~SHARPSL_DO_OFFLINE_CHRG;
516                 sharpsl_off_charge_battery();
517         }
518
519         sharpsl_pm.machinfo->presuspend();
520
521         PEDR = 0xffffffff; /* clear it */
522
523         sharpsl_pm.flags &= ~SHARPSL_ALARM_ACTIVE;
524         if ((sharpsl_pm.charge_mode == CHRG_ON) && ((alarm_enable && ((alarm_time - RCNR) > (SHARPSL_BATCHK_TIME_SUSPEND + 30))) || !alarm_enable)) {
525                 RTSR &= RTSR_ALE;
526                 RTAR = RCNR + SHARPSL_BATCHK_TIME_SUSPEND;
527                 dev_dbg(sharpsl_pm.dev, "Charging alarm at: %08x\n",RTAR);
528                 sharpsl_pm.flags |= SHARPSL_ALARM_ACTIVE;
529         } else if (alarm_enable) {
530                 RTSR &= RTSR_ALE;
531                 RTAR = alarm_time;
532                 dev_dbg(sharpsl_pm.dev, "User alarm at: %08x\n",RTAR);
533         } else {
534                 dev_dbg(sharpsl_pm.dev, "No alarms set.\n");
535         }
536
537         pxa_pm_enter(state);
538
539         sharpsl_pm.machinfo->postsuspend();
540
541         dev_dbg(sharpsl_pm.dev, "Corgi woken up from suspend: %08x\n",PEDR);
542 }
543
544 static int corgi_enter_suspend(unsigned long alarm_time, unsigned int alarm_enable, suspend_state_t state)
545 {
546         if (!sharpsl_pm.machinfo->should_wakeup(!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE) && alarm_enable) )
547         {
548                 if (!(sharpsl_pm.flags & SHARPSL_ALARM_ACTIVE)) {
549                         dev_dbg(sharpsl_pm.dev, "No user triggered wakeup events and not charging. Strange. Suspend.\n");
550                         corgi_goto_sleep(alarm_time, alarm_enable, state);
551                         return 1;
552                 }
553                 if(sharpsl_off_charge_battery()) {
554                         dev_dbg(sharpsl_pm.dev, "Charging. Suspend...\n");
555                         corgi_goto_sleep(alarm_time, alarm_enable, state);
556                         return 1;
557                 }
558                 dev_dbg(sharpsl_pm.dev, "User triggered wakeup in offline charger.\n");
559         }
560
561         if ((!sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_LOCK)) || (sharpsl_fatal_check() < 0) )
562         {
563                 dev_err(sharpsl_pm.dev, "Fatal condition. Suspend.\n");
564                 corgi_goto_sleep(alarm_time, alarm_enable, state);
565                 return 1;
566         }
567
568         return 0;
569 }
570
571 static int corgi_pxa_pm_enter(suspend_state_t state)
572 {
573         unsigned long alarm_time = RTAR;
574         unsigned int alarm_status = ((RTSR & RTSR_ALE) != 0);
575
576         dev_dbg(sharpsl_pm.dev, "SharpSL suspending for first time.\n");
577
578         corgi_goto_sleep(alarm_time, alarm_status, state);
579
580         while (corgi_enter_suspend(alarm_time,alarm_status,state))
581                 {}
582
583         if (sharpsl_pm.machinfo->earlyresume)
584                 sharpsl_pm.machinfo->earlyresume();
585
586         dev_dbg(sharpsl_pm.dev, "SharpSL resuming...\n");
587
588         return 0;
589 }
590 #endif
591
592
593 /*
594  * Check for fatal battery errors
595  * Fatal returns -1
596  */
597 static int sharpsl_fatal_check(void)
598 {
599         int buff[5], temp, i, acin;
600
601         dev_dbg(sharpsl_pm.dev, "sharpsl_fatal_check entered\n");
602
603         /* Check AC-Adapter */
604         acin = sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_ACIN);
605
606         if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) {
607                 sharpsl_pm.machinfo->charge(0);
608                 udelay(100);
609                 sharpsl_pm.machinfo->discharge(1);      /* enable discharge */
610                 mdelay(SHARPSL_WAIT_DISCHARGE_ON);
611         }
612
613         if (sharpsl_pm.machinfo->discharge1)
614                 sharpsl_pm.machinfo->discharge1(1);
615
616         /* Check battery : check inserting battery ? */
617         for (i=0; i<5; i++) {
618                 buff[i] = sharpsl_pm.machinfo->read_devdata(SHARPSL_BATT_VOLT);
619                 mdelay(SHARPSL_CHECK_BATTERY_WAIT_TIME_VOLT);
620         }
621
622         if (sharpsl_pm.machinfo->discharge1)
623                 sharpsl_pm.machinfo->discharge1(0);
624
625         if (acin && (sharpsl_pm.charge_mode == CHRG_ON)) {
626                 udelay(100);
627                 sharpsl_pm.machinfo->charge(1);
628                 sharpsl_pm.machinfo->discharge(0);
629         }
630
631         temp = get_select_val(buff);
632         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));
633
634         if ((acin && (temp < sharpsl_pm.machinfo->fatal_acin_volt)) ||
635                         (!acin && (temp < sharpsl_pm.machinfo->fatal_noacin_volt)))
636                 return -1;
637         return 0;
638 }
639
640 static int sharpsl_off_charge_error(void)
641 {
642         dev_err(sharpsl_pm.dev, "Offline Charger: Error occurred.\n");
643         sharpsl_pm.machinfo->charge(0);
644         sharpsl_pm_led(SHARPSL_LED_ERROR);
645         sharpsl_pm.charge_mode = CHRG_ERROR;
646         return 1;
647 }
648
649 /*
650  * Charging Control while suspended
651  * Return 1 - go straight to sleep
652  * Return 0 - sleep or wakeup depending on other factors
653  */
654 static int sharpsl_off_charge_battery(void)
655 {
656         int time;
657
658         dev_dbg(sharpsl_pm.dev, "Charge Mode: %d\n", sharpsl_pm.charge_mode);
659
660         if (sharpsl_pm.charge_mode == CHRG_OFF) {
661                 dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 1\n");
662
663                 /* AC Check */
664                 if ((sharpsl_ac_check() < 0) || (sharpsl_check_battery_temp() < 0))
665                         return sharpsl_off_charge_error();
666
667                 /* Start Charging */
668                 sharpsl_pm_led(SHARPSL_LED_ON);
669                 sharpsl_pm.machinfo->charge(0);
670                 mdelay(SHARPSL_CHARGE_WAIT_TIME);
671                 sharpsl_pm.machinfo->charge(1);
672
673                 sharpsl_pm.charge_mode = CHRG_ON;
674                 sharpsl_pm.full_count = 0;
675
676                 return 1;
677         } else if (sharpsl_pm.charge_mode != CHRG_ON) {
678                 return 1;
679         }
680
681         if (sharpsl_pm.full_count == 0) {
682                 int time;
683
684                 dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 2\n");
685
686                 if ((sharpsl_check_battery_temp() < 0) || (sharpsl_check_battery_voltage() < 0))
687                         return sharpsl_off_charge_error();
688
689                 sharpsl_pm.machinfo->charge(0);
690                 mdelay(SHARPSL_CHARGE_WAIT_TIME);
691                 sharpsl_pm.machinfo->charge(1);
692                 sharpsl_pm.charge_mode = CHRG_ON;
693
694                 mdelay(SHARPSL_CHARGE_CO_CHECK_TIME);
695
696                 time = RCNR;
697                 while(1) {
698                         /* Check if any wakeup event had occurred */
699                         if (sharpsl_pm.machinfo->charger_wakeup() != 0)
700                                 return 0;
701                         /* Check for timeout */
702                         if ((RCNR - time) > SHARPSL_WAIT_CO_TIME)
703                                 return 1;
704                         if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_CHRGFULL)) {
705                                 dev_dbg(sharpsl_pm.dev, "Offline Charger: Charge full occurred. Retrying to check\n");
706                                 sharpsl_pm.full_count++;
707                                 sharpsl_pm.machinfo->charge(0);
708                                 mdelay(SHARPSL_CHARGE_WAIT_TIME);
709                                 sharpsl_pm.machinfo->charge(1);
710                                 return 1;
711                         }
712                 }
713         }
714
715         dev_dbg(sharpsl_pm.dev, "Offline Charger: Step 3\n");
716
717         mdelay(SHARPSL_CHARGE_CO_CHECK_TIME);
718
719         time = RCNR;
720         while(1) {
721                 /* Check if any wakeup event had occurred */
722                 if (sharpsl_pm.machinfo->charger_wakeup() != 0)
723                         return 0;
724                 /* Check for timeout */
725                 if ((RCNR-time) > SHARPSL_WAIT_CO_TIME) {
726                         if (sharpsl_pm.full_count > SHARPSL_CHARGE_RETRY_CNT) {
727                                 dev_dbg(sharpsl_pm.dev, "Offline Charger: Not charged sufficiently. Retrying.\n");
728                                 sharpsl_pm.full_count = 0;
729                         }
730                         sharpsl_pm.full_count++;
731                         return 1;
732                 }
733                 if (sharpsl_pm.machinfo->read_devdata(SHARPSL_STATUS_CHRGFULL)) {
734                         dev_dbg(sharpsl_pm.dev, "Offline Charger: Charging complete.\n");
735                         sharpsl_pm_led(SHARPSL_LED_OFF);
736                         sharpsl_pm.machinfo->charge(0);
737                         sharpsl_pm.charge_mode = CHRG_DONE;
738                         return 1;
739                 }
740         }
741 }
742
743
744 static ssize_t battery_percentage_show(struct device *dev, struct device_attribute *attr, char *buf)
745 {
746         return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_percent);
747 }
748
749 static ssize_t battery_voltage_show(struct device *dev, struct device_attribute *attr, char *buf)
750 {
751         return sprintf(buf, "%d\n",sharpsl_pm.battstat.mainbat_voltage);
752 }
753
754 static DEVICE_ATTR(battery_percentage, 0444, battery_percentage_show, NULL);
755 static DEVICE_ATTR(battery_voltage, 0444, battery_voltage_show, NULL);
756
757 extern void (*apm_get_power_status)(struct apm_power_info *);
758
759 static void sharpsl_apm_get_power_status(struct apm_power_info *info)
760 {
761         info->ac_line_status = sharpsl_pm.battstat.ac_status;
762
763         if (sharpsl_pm.charge_mode == CHRG_ON)
764                 info->battery_status = APM_BATTERY_STATUS_CHARGING;
765         else
766                 info->battery_status = sharpsl_pm.battstat.mainbat_status;
767
768         info->battery_flag = (1 << info->battery_status);
769         info->battery_life = sharpsl_pm.battstat.mainbat_percent;
770 }
771
772 static struct platform_suspend_ops sharpsl_pm_ops = {
773         .enter          = corgi_pxa_pm_enter,
774         .valid          = suspend_valid_only_mem,
775 };
776
777 static int __init sharpsl_pm_probe(struct platform_device *pdev)
778 {
779         int ret;
780
781         if (!pdev->dev.platform_data)
782                 return -EINVAL;
783
784         sharpsl_pm.dev = &pdev->dev;
785         sharpsl_pm.machinfo = pdev->dev.platform_data;
786         sharpsl_pm.charge_mode = CHRG_OFF;
787         sharpsl_pm.flags = 0;
788
789         init_timer(&sharpsl_pm.ac_timer);
790         sharpsl_pm.ac_timer.function = sharpsl_ac_timer;
791
792         init_timer(&sharpsl_pm.chrg_full_timer);
793         sharpsl_pm.chrg_full_timer.function = sharpsl_chrg_full_timer;
794
795         led_trigger_register_simple("sharpsl-charge", &sharpsl_charge_led_trigger);
796
797         sharpsl_pm.machinfo->init();
798
799         ret = device_create_file(&pdev->dev, &dev_attr_battery_percentage);
800         ret |= device_create_file(&pdev->dev, &dev_attr_battery_voltage);
801         if (ret != 0)
802                 dev_warn(&pdev->dev, "Failed to register attributes (%d)\n", ret);
803
804         apm_get_power_status = sharpsl_apm_get_power_status;
805
806         suspend_set_ops(&sharpsl_pm_ops);
807
808         mod_timer(&sharpsl_pm.ac_timer, jiffies + msecs_to_jiffies(250));
809
810         return 0;
811 }
812
813 static int sharpsl_pm_remove(struct platform_device *pdev)
814 {
815         suspend_set_ops(NULL);
816
817         device_remove_file(&pdev->dev, &dev_attr_battery_percentage);
818         device_remove_file(&pdev->dev, &dev_attr_battery_voltage);
819
820         led_trigger_unregister_simple(sharpsl_charge_led_trigger);
821
822         sharpsl_pm.machinfo->exit();
823
824         del_timer_sync(&sharpsl_pm.chrg_full_timer);
825         del_timer_sync(&sharpsl_pm.ac_timer);
826
827         return 0;
828 }
829
830 static struct platform_driver sharpsl_pm_driver = {
831         .probe          = sharpsl_pm_probe,
832         .remove         = sharpsl_pm_remove,
833         .suspend        = sharpsl_pm_suspend,
834         .resume         = sharpsl_pm_resume,
835         .driver         = {
836                 .name           = "sharpsl-pm",
837         },
838 };
839
840 static int __devinit sharpsl_pm_init(void)
841 {
842         return platform_driver_register(&sharpsl_pm_driver);
843 }
844
845 static void sharpsl_pm_exit(void)
846 {
847         platform_driver_unregister(&sharpsl_pm_driver);
848 }
849
850 late_initcall(sharpsl_pm_init);
851 module_exit(sharpsl_pm_exit);