~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to arch/arm/mach-pxa/sharpsl_pm.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

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