Root/drivers/power/olpc_battery.c

1/*
2 * Battery driver for One Laptop Per Child board.
3 *
4 * Copyright © 2006-2010 David Woodhouse <dwmw2@infradead.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/types.h>
14#include <linux/err.h>
15#include <linux/device.h>
16#include <linux/platform_device.h>
17#include <linux/power_supply.h>
18#include <linux/jiffies.h>
19#include <linux/sched.h>
20#include <linux/olpc-ec.h>
21#include <asm/olpc.h>
22
23
24#define EC_BAT_VOLTAGE 0x10 /* uint16_t, *9.76/32, mV */
25#define EC_BAT_CURRENT 0x11 /* int16_t, *15.625/120, mA */
26#define EC_BAT_ACR 0x12 /* int16_t, *6250/15, µAh */
27#define EC_BAT_TEMP 0x13 /* uint16_t, *100/256, °C */
28#define EC_AMB_TEMP 0x14 /* uint16_t, *100/256, °C */
29#define EC_BAT_STATUS 0x15 /* uint8_t, bitmask */
30#define EC_BAT_SOC 0x16 /* uint8_t, percentage */
31#define EC_BAT_SERIAL 0x17 /* uint8_t[6] */
32#define EC_BAT_EEPROM 0x18 /* uint8_t adr as input, uint8_t output */
33#define EC_BAT_ERRCODE 0x1f /* uint8_t, bitmask */
34
35#define BAT_STAT_PRESENT 0x01
36#define BAT_STAT_FULL 0x02
37#define BAT_STAT_LOW 0x04
38#define BAT_STAT_DESTROY 0x08
39#define BAT_STAT_AC 0x10
40#define BAT_STAT_CHARGING 0x20
41#define BAT_STAT_DISCHARGING 0x40
42#define BAT_STAT_TRICKLE 0x80
43
44#define BAT_ERR_INFOFAIL 0x02
45#define BAT_ERR_OVERVOLTAGE 0x04
46#define BAT_ERR_OVERTEMP 0x05
47#define BAT_ERR_GAUGESTOP 0x06
48#define BAT_ERR_OUT_OF_CONTROL 0x07
49#define BAT_ERR_ID_FAIL 0x09
50#define BAT_ERR_ACR_FAIL 0x10
51
52#define BAT_ADDR_MFR_TYPE 0x5F
53
54/*********************************************************************
55 * Power
56 *********************************************************************/
57
58static int olpc_ac_get_prop(struct power_supply *psy,
59                enum power_supply_property psp,
60                union power_supply_propval *val)
61{
62    int ret = 0;
63    uint8_t status;
64
65    switch (psp) {
66    case POWER_SUPPLY_PROP_ONLINE:
67        ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &status, 1);
68        if (ret)
69            return ret;
70
71        val->intval = !!(status & BAT_STAT_AC);
72        break;
73    default:
74        ret = -EINVAL;
75        break;
76    }
77    return ret;
78}
79
80static enum power_supply_property olpc_ac_props[] = {
81    POWER_SUPPLY_PROP_ONLINE,
82};
83
84static struct power_supply olpc_ac = {
85    .name = "olpc-ac",
86    .type = POWER_SUPPLY_TYPE_MAINS,
87    .properties = olpc_ac_props,
88    .num_properties = ARRAY_SIZE(olpc_ac_props),
89    .get_property = olpc_ac_get_prop,
90};
91
92static char bat_serial[17]; /* Ick */
93
94static int olpc_bat_get_status(union power_supply_propval *val, uint8_t ec_byte)
95{
96    if (olpc_platform_info.ecver > 0x44) {
97        if (ec_byte & (BAT_STAT_CHARGING | BAT_STAT_TRICKLE))
98            val->intval = POWER_SUPPLY_STATUS_CHARGING;
99        else if (ec_byte & BAT_STAT_DISCHARGING)
100            val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
101        else if (ec_byte & BAT_STAT_FULL)
102            val->intval = POWER_SUPPLY_STATUS_FULL;
103        else /* er,... */
104            val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
105    } else {
106        /* Older EC didn't report charge/discharge bits */
107        if (!(ec_byte & BAT_STAT_AC)) /* No AC means discharging */
108            val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
109        else if (ec_byte & BAT_STAT_FULL)
110            val->intval = POWER_SUPPLY_STATUS_FULL;
111        else /* Not _necessarily_ true but EC doesn't tell all yet */
112            val->intval = POWER_SUPPLY_STATUS_CHARGING;
113    }
114
115    return 0;
116}
117
118static int olpc_bat_get_health(union power_supply_propval *val)
119{
120    uint8_t ec_byte;
121    int ret;
122
123    ret = olpc_ec_cmd(EC_BAT_ERRCODE, NULL, 0, &ec_byte, 1);
124    if (ret)
125        return ret;
126
127    switch (ec_byte) {
128    case 0:
129        val->intval = POWER_SUPPLY_HEALTH_GOOD;
130        break;
131
132    case BAT_ERR_OVERTEMP:
133        val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
134        break;
135
136    case BAT_ERR_OVERVOLTAGE:
137        val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
138        break;
139
140    case BAT_ERR_INFOFAIL:
141    case BAT_ERR_OUT_OF_CONTROL:
142    case BAT_ERR_ID_FAIL:
143    case BAT_ERR_ACR_FAIL:
144        val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
145        break;
146
147    default:
148        /* Eep. We don't know this failure code */
149        ret = -EIO;
150    }
151
152    return ret;
153}
154
155static int olpc_bat_get_mfr(union power_supply_propval *val)
156{
157    uint8_t ec_byte;
158    int ret;
159
160    ec_byte = BAT_ADDR_MFR_TYPE;
161    ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
162    if (ret)
163        return ret;
164
165    switch (ec_byte >> 4) {
166    case 1:
167        val->strval = "Gold Peak";
168        break;
169    case 2:
170        val->strval = "BYD";
171        break;
172    default:
173        val->strval = "Unknown";
174        break;
175    }
176
177    return ret;
178}
179
180static int olpc_bat_get_tech(union power_supply_propval *val)
181{
182    uint8_t ec_byte;
183    int ret;
184
185    ec_byte = BAT_ADDR_MFR_TYPE;
186    ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
187    if (ret)
188        return ret;
189
190    switch (ec_byte & 0xf) {
191    case 1:
192        val->intval = POWER_SUPPLY_TECHNOLOGY_NiMH;
193        break;
194    case 2:
195        val->intval = POWER_SUPPLY_TECHNOLOGY_LiFe;
196        break;
197    default:
198        val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
199        break;
200    }
201
202    return ret;
203}
204
205static int olpc_bat_get_charge_full_design(union power_supply_propval *val)
206{
207    uint8_t ec_byte;
208    union power_supply_propval tech;
209    int ret, mfr;
210
211    ret = olpc_bat_get_tech(&tech);
212    if (ret)
213        return ret;
214
215    ec_byte = BAT_ADDR_MFR_TYPE;
216    ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
217    if (ret)
218        return ret;
219
220    mfr = ec_byte >> 4;
221
222    switch (tech.intval) {
223    case POWER_SUPPLY_TECHNOLOGY_NiMH:
224        switch (mfr) {
225        case 1: /* Gold Peak */
226            val->intval = 3000000*.8;
227            break;
228        default:
229            return -EIO;
230        }
231        break;
232
233    case POWER_SUPPLY_TECHNOLOGY_LiFe:
234        switch (mfr) {
235        case 1: /* Gold Peak, fall through */
236        case 2: /* BYD */
237            val->intval = 2800000;
238            break;
239        default:
240            return -EIO;
241        }
242        break;
243
244    default:
245        return -EIO;
246    }
247
248    return ret;
249}
250
251static int olpc_bat_get_charge_now(union power_supply_propval *val)
252{
253    uint8_t soc;
254    union power_supply_propval full;
255    int ret;
256
257    ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &soc, 1);
258    if (ret)
259        return ret;
260
261    ret = olpc_bat_get_charge_full_design(&full);
262    if (ret)
263        return ret;
264
265    val->intval = soc * (full.intval / 100);
266    return 0;
267}
268
269static int olpc_bat_get_voltage_max_design(union power_supply_propval *val)
270{
271    uint8_t ec_byte;
272    union power_supply_propval tech;
273    int mfr;
274    int ret;
275
276    ret = olpc_bat_get_tech(&tech);
277    if (ret)
278        return ret;
279
280    ec_byte = BAT_ADDR_MFR_TYPE;
281    ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
282    if (ret)
283        return ret;
284
285    mfr = ec_byte >> 4;
286
287    switch (tech.intval) {
288    case POWER_SUPPLY_TECHNOLOGY_NiMH:
289        switch (mfr) {
290        case 1: /* Gold Peak */
291            val->intval = 6000000;
292            break;
293        default:
294            return -EIO;
295        }
296        break;
297
298    case POWER_SUPPLY_TECHNOLOGY_LiFe:
299        switch (mfr) {
300        case 1: /* Gold Peak */
301            val->intval = 6400000;
302            break;
303        case 2: /* BYD */
304            val->intval = 6500000;
305            break;
306        default:
307            return -EIO;
308        }
309        break;
310
311    default:
312        return -EIO;
313    }
314
315    return ret;
316}
317
318/*********************************************************************
319 * Battery properties
320 *********************************************************************/
321static int olpc_bat_get_property(struct power_supply *psy,
322                 enum power_supply_property psp,
323                 union power_supply_propval *val)
324{
325    int ret = 0;
326    __be16 ec_word;
327    uint8_t ec_byte;
328    __be64 ser_buf;
329
330    ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &ec_byte, 1);
331    if (ret)
332        return ret;
333
334    /* Theoretically there's a race here -- the battery could be
335       removed immediately after we check whether it's present, and
336       then we query for some other property of the now-absent battery.
337       It doesn't matter though -- the EC will return the last-known
338       information, and it's as if we just ran that _little_ bit faster
339       and managed to read it out before the battery went away. */
340    if (!(ec_byte & (BAT_STAT_PRESENT | BAT_STAT_TRICKLE)) &&
341            psp != POWER_SUPPLY_PROP_PRESENT)
342        return -ENODEV;
343
344    switch (psp) {
345    case POWER_SUPPLY_PROP_STATUS:
346        ret = olpc_bat_get_status(val, ec_byte);
347        if (ret)
348            return ret;
349        break;
350    case POWER_SUPPLY_PROP_CHARGE_TYPE:
351        if (ec_byte & BAT_STAT_TRICKLE)
352            val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
353        else if (ec_byte & BAT_STAT_CHARGING)
354            val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
355        else
356            val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
357        break;
358    case POWER_SUPPLY_PROP_PRESENT:
359        val->intval = !!(ec_byte & (BAT_STAT_PRESENT |
360                        BAT_STAT_TRICKLE));
361        break;
362
363    case POWER_SUPPLY_PROP_HEALTH:
364        if (ec_byte & BAT_STAT_DESTROY)
365            val->intval = POWER_SUPPLY_HEALTH_DEAD;
366        else {
367            ret = olpc_bat_get_health(val);
368            if (ret)
369                return ret;
370        }
371        break;
372
373    case POWER_SUPPLY_PROP_MANUFACTURER:
374        ret = olpc_bat_get_mfr(val);
375        if (ret)
376            return ret;
377        break;
378    case POWER_SUPPLY_PROP_TECHNOLOGY:
379        ret = olpc_bat_get_tech(val);
380        if (ret)
381            return ret;
382        break;
383    case POWER_SUPPLY_PROP_VOLTAGE_AVG:
384    case POWER_SUPPLY_PROP_VOLTAGE_NOW:
385        ret = olpc_ec_cmd(EC_BAT_VOLTAGE, NULL, 0, (void *)&ec_word, 2);
386        if (ret)
387            return ret;
388
389        val->intval = (s16)be16_to_cpu(ec_word) * 9760L / 32;
390        break;
391    case POWER_SUPPLY_PROP_CURRENT_AVG:
392    case POWER_SUPPLY_PROP_CURRENT_NOW:
393        ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2);
394        if (ret)
395            return ret;
396
397        val->intval = (s16)be16_to_cpu(ec_word) * 15625L / 120;
398        break;
399    case POWER_SUPPLY_PROP_CAPACITY:
400        ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &ec_byte, 1);
401        if (ret)
402            return ret;
403        val->intval = ec_byte;
404        break;
405    case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
406        if (ec_byte & BAT_STAT_FULL)
407            val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
408        else if (ec_byte & BAT_STAT_LOW)
409            val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
410        else
411            val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
412        break;
413    case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
414        ret = olpc_bat_get_charge_full_design(val);
415        if (ret)
416            return ret;
417        break;
418    case POWER_SUPPLY_PROP_CHARGE_NOW:
419        ret = olpc_bat_get_charge_now(val);
420        if (ret)
421            return ret;
422        break;
423    case POWER_SUPPLY_PROP_TEMP:
424        ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);
425        if (ret)
426            return ret;
427
428        val->intval = (s16)be16_to_cpu(ec_word) * 100 / 256;
429        break;
430    case POWER_SUPPLY_PROP_TEMP_AMBIENT:
431        ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2);
432        if (ret)
433            return ret;
434
435        val->intval = (int)be16_to_cpu(ec_word) * 100 / 256;
436        break;
437    case POWER_SUPPLY_PROP_CHARGE_COUNTER:
438        ret = olpc_ec_cmd(EC_BAT_ACR, NULL, 0, (void *)&ec_word, 2);
439        if (ret)
440            return ret;
441
442        val->intval = (s16)be16_to_cpu(ec_word) * 6250 / 15;
443        break;
444    case POWER_SUPPLY_PROP_SERIAL_NUMBER:
445        ret = olpc_ec_cmd(EC_BAT_SERIAL, NULL, 0, (void *)&ser_buf, 8);
446        if (ret)
447            return ret;
448
449        sprintf(bat_serial, "%016llx", (long long)be64_to_cpu(ser_buf));
450        val->strval = bat_serial;
451        break;
452    case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
453        ret = olpc_bat_get_voltage_max_design(val);
454        if (ret)
455            return ret;
456        break;
457    default:
458        ret = -EINVAL;
459        break;
460    }
461
462    return ret;
463}
464
465static enum power_supply_property olpc_xo1_bat_props[] = {
466    POWER_SUPPLY_PROP_STATUS,
467    POWER_SUPPLY_PROP_CHARGE_TYPE,
468    POWER_SUPPLY_PROP_PRESENT,
469    POWER_SUPPLY_PROP_HEALTH,
470    POWER_SUPPLY_PROP_TECHNOLOGY,
471    POWER_SUPPLY_PROP_VOLTAGE_AVG,
472    POWER_SUPPLY_PROP_VOLTAGE_NOW,
473    POWER_SUPPLY_PROP_CURRENT_AVG,
474    POWER_SUPPLY_PROP_CURRENT_NOW,
475    POWER_SUPPLY_PROP_CAPACITY,
476    POWER_SUPPLY_PROP_CAPACITY_LEVEL,
477    POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
478    POWER_SUPPLY_PROP_CHARGE_NOW,
479    POWER_SUPPLY_PROP_TEMP,
480    POWER_SUPPLY_PROP_TEMP_AMBIENT,
481    POWER_SUPPLY_PROP_MANUFACTURER,
482    POWER_SUPPLY_PROP_SERIAL_NUMBER,
483    POWER_SUPPLY_PROP_CHARGE_COUNTER,
484    POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
485};
486
487/* XO-1.5 does not have ambient temperature property */
488static enum power_supply_property olpc_xo15_bat_props[] = {
489    POWER_SUPPLY_PROP_STATUS,
490    POWER_SUPPLY_PROP_CHARGE_TYPE,
491    POWER_SUPPLY_PROP_PRESENT,
492    POWER_SUPPLY_PROP_HEALTH,
493    POWER_SUPPLY_PROP_TECHNOLOGY,
494    POWER_SUPPLY_PROP_VOLTAGE_AVG,
495    POWER_SUPPLY_PROP_VOLTAGE_NOW,
496    POWER_SUPPLY_PROP_CURRENT_AVG,
497    POWER_SUPPLY_PROP_CURRENT_NOW,
498    POWER_SUPPLY_PROP_CAPACITY,
499    POWER_SUPPLY_PROP_CAPACITY_LEVEL,
500    POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
501    POWER_SUPPLY_PROP_CHARGE_NOW,
502    POWER_SUPPLY_PROP_TEMP,
503    POWER_SUPPLY_PROP_MANUFACTURER,
504    POWER_SUPPLY_PROP_SERIAL_NUMBER,
505    POWER_SUPPLY_PROP_CHARGE_COUNTER,
506    POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
507};
508
509/* EEPROM reading goes completely around the power_supply API, sadly */
510
511#define EEPROM_START 0x20
512#define EEPROM_END 0x80
513#define EEPROM_SIZE (EEPROM_END - EEPROM_START)
514
515static ssize_t olpc_bat_eeprom_read(struct file *filp, struct kobject *kobj,
516        struct bin_attribute *attr, char *buf, loff_t off, size_t count)
517{
518    uint8_t ec_byte;
519    int ret;
520    int i;
521
522    if (off >= EEPROM_SIZE)
523        return 0;
524    if (off + count > EEPROM_SIZE)
525        count = EEPROM_SIZE - off;
526
527    for (i = 0; i < count; i++) {
528        ec_byte = EEPROM_START + off + i;
529        ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &buf[i], 1);
530        if (ret) {
531            pr_err("olpc-battery: "
532                   "EC_BAT_EEPROM cmd @ 0x%x failed - %d!\n",
533                   ec_byte, ret);
534            return -EIO;
535        }
536    }
537
538    return count;
539}
540
541static struct bin_attribute olpc_bat_eeprom = {
542    .attr = {
543        .name = "eeprom",
544        .mode = S_IRUGO,
545    },
546    .size = 0,
547    .read = olpc_bat_eeprom_read,
548};
549
550/* Allow userspace to see the specific error value pulled from the EC */
551
552static ssize_t olpc_bat_error_read(struct device *dev,
553        struct device_attribute *attr, char *buf)
554{
555    uint8_t ec_byte;
556    ssize_t ret;
557
558    ret = olpc_ec_cmd(EC_BAT_ERRCODE, NULL, 0, &ec_byte, 1);
559    if (ret < 0)
560        return ret;
561
562    return sprintf(buf, "%d\n", ec_byte);
563}
564
565static struct device_attribute olpc_bat_error = {
566    .attr = {
567        .name = "error",
568        .mode = S_IRUGO,
569    },
570    .show = olpc_bat_error_read,
571};
572
573/*********************************************************************
574 * Initialisation
575 *********************************************************************/
576
577static struct power_supply olpc_bat = {
578    .name = "olpc-battery",
579    .get_property = olpc_bat_get_property,
580    .use_for_apm = 1,
581};
582
583static int olpc_battery_suspend(struct platform_device *pdev,
584                pm_message_t state)
585{
586    if (device_may_wakeup(olpc_ac.dev))
587        olpc_ec_wakeup_set(EC_SCI_SRC_ACPWR);
588    else
589        olpc_ec_wakeup_clear(EC_SCI_SRC_ACPWR);
590
591    if (device_may_wakeup(olpc_bat.dev))
592        olpc_ec_wakeup_set(EC_SCI_SRC_BATTERY | EC_SCI_SRC_BATSOC
593                   | EC_SCI_SRC_BATERR);
594    else
595        olpc_ec_wakeup_clear(EC_SCI_SRC_BATTERY | EC_SCI_SRC_BATSOC
596                     | EC_SCI_SRC_BATERR);
597
598    return 0;
599}
600
601static int __devinit olpc_battery_probe(struct platform_device *pdev)
602{
603    int ret;
604    uint8_t status;
605
606    /*
607     * We've seen a number of EC protocol changes; this driver requires
608     * the latest EC protocol, supported by 0x44 and above.
609     */
610    if (olpc_platform_info.ecver < 0x44) {
611        printk(KERN_NOTICE "OLPC EC version 0x%02x too old for "
612            "battery driver.\n", olpc_platform_info.ecver);
613        return -ENXIO;
614    }
615
616    ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &status, 1);
617    if (ret)
618        return ret;
619
620    /* Ignore the status. It doesn't actually matter */
621
622    ret = power_supply_register(&pdev->dev, &olpc_ac);
623    if (ret)
624        return ret;
625
626    if (olpc_board_at_least(olpc_board_pre(0xd0))) { /* XO-1.5 */
627        olpc_bat.properties = olpc_xo15_bat_props;
628        olpc_bat.num_properties = ARRAY_SIZE(olpc_xo15_bat_props);
629    } else { /* XO-1 */
630        olpc_bat.properties = olpc_xo1_bat_props;
631        olpc_bat.num_properties = ARRAY_SIZE(olpc_xo1_bat_props);
632    }
633
634    ret = power_supply_register(&pdev->dev, &olpc_bat);
635    if (ret)
636        goto battery_failed;
637
638    ret = device_create_bin_file(olpc_bat.dev, &olpc_bat_eeprom);
639    if (ret)
640        goto eeprom_failed;
641
642    ret = device_create_file(olpc_bat.dev, &olpc_bat_error);
643    if (ret)
644        goto error_failed;
645
646    if (olpc_ec_wakeup_available()) {
647        device_set_wakeup_capable(olpc_ac.dev, true);
648        device_set_wakeup_capable(olpc_bat.dev, true);
649    }
650
651    return 0;
652
653error_failed:
654    device_remove_bin_file(olpc_bat.dev, &olpc_bat_eeprom);
655eeprom_failed:
656    power_supply_unregister(&olpc_bat);
657battery_failed:
658    power_supply_unregister(&olpc_ac);
659    return ret;
660}
661
662static int __devexit olpc_battery_remove(struct platform_device *pdev)
663{
664    device_remove_file(olpc_bat.dev, &olpc_bat_error);
665    device_remove_bin_file(olpc_bat.dev, &olpc_bat_eeprom);
666    power_supply_unregister(&olpc_bat);
667    power_supply_unregister(&olpc_ac);
668    return 0;
669}
670
671static const struct of_device_id olpc_battery_ids[] __devinitconst = {
672    { .compatible = "olpc,xo1-battery" },
673    {}
674};
675MODULE_DEVICE_TABLE(of, olpc_battery_ids);
676
677static struct platform_driver olpc_battery_driver = {
678    .driver = {
679        .name = "olpc-battery",
680        .owner = THIS_MODULE,
681        .of_match_table = olpc_battery_ids,
682    },
683    .probe = olpc_battery_probe,
684    .remove = __devexit_p(olpc_battery_remove),
685    .suspend = olpc_battery_suspend,
686};
687
688module_platform_driver(olpc_battery_driver);
689
690MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
691MODULE_LICENSE("GPL");
692MODULE_DESCRIPTION("Battery driver for One Laptop Per Child 'XO' machine");
693

Archive Download this file



interactive