2 * Battery driver for One Laptop Per Child board.
4 * Copyright © 2006-2010 David Woodhouse <dwmw2@infradead.org>
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.
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>
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 */
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
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
52 #define BAT_ADDR_MFR_TYPE 0x5F
54 /*********************************************************************
56 *********************************************************************/
58 static int olpc_ac_get_prop(struct power_supply
*psy
,
59 enum power_supply_property psp
,
60 union power_supply_propval
*val
)
66 case POWER_SUPPLY_PROP_ONLINE
:
67 ret
= olpc_ec_cmd(EC_BAT_STATUS
, NULL
, 0, &status
, 1);
71 val
->intval
= !!(status
& BAT_STAT_AC
);
80 static enum power_supply_property olpc_ac_props
[] = {
81 POWER_SUPPLY_PROP_ONLINE
,
84 static const struct power_supply_desc olpc_ac_desc
= {
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
,
92 static struct power_supply
*olpc_ac
;
94 static char bat_serial
[17]; /* Ick */
96 static int olpc_bat_get_status(union power_supply_propval
*val
, uint8_t ec_byte
)
98 if (olpc_platform_info
.ecver
> 0x44) {
99 if (ec_byte
& (BAT_STAT_CHARGING
| BAT_STAT_TRICKLE
))
100 val
->intval
= POWER_SUPPLY_STATUS_CHARGING
;
101 else if (ec_byte
& BAT_STAT_DISCHARGING
)
102 val
->intval
= POWER_SUPPLY_STATUS_DISCHARGING
;
103 else if (ec_byte
& BAT_STAT_FULL
)
104 val
->intval
= POWER_SUPPLY_STATUS_FULL
;
106 val
->intval
= POWER_SUPPLY_STATUS_NOT_CHARGING
;
108 /* Older EC didn't report charge/discharge bits */
109 if (!(ec_byte
& BAT_STAT_AC
)) /* No AC means discharging */
110 val
->intval
= POWER_SUPPLY_STATUS_DISCHARGING
;
111 else if (ec_byte
& BAT_STAT_FULL
)
112 val
->intval
= POWER_SUPPLY_STATUS_FULL
;
113 else /* Not _necessarily_ true but EC doesn't tell all yet */
114 val
->intval
= POWER_SUPPLY_STATUS_CHARGING
;
120 static int olpc_bat_get_health(union power_supply_propval
*val
)
125 ret
= olpc_ec_cmd(EC_BAT_ERRCODE
, NULL
, 0, &ec_byte
, 1);
131 val
->intval
= POWER_SUPPLY_HEALTH_GOOD
;
134 case BAT_ERR_OVERTEMP
:
135 val
->intval
= POWER_SUPPLY_HEALTH_OVERHEAT
;
138 case BAT_ERR_OVERVOLTAGE
:
139 val
->intval
= POWER_SUPPLY_HEALTH_OVERVOLTAGE
;
142 case BAT_ERR_INFOFAIL
:
143 case BAT_ERR_OUT_OF_CONTROL
:
144 case BAT_ERR_ID_FAIL
:
145 case BAT_ERR_ACR_FAIL
:
146 val
->intval
= POWER_SUPPLY_HEALTH_UNSPEC_FAILURE
;
150 /* Eep. We don't know this failure code */
157 static int olpc_bat_get_mfr(union power_supply_propval
*val
)
162 ec_byte
= BAT_ADDR_MFR_TYPE
;
163 ret
= olpc_ec_cmd(EC_BAT_EEPROM
, &ec_byte
, 1, &ec_byte
, 1);
167 switch (ec_byte
>> 4) {
169 val
->strval
= "Gold Peak";
175 val
->strval
= "Unknown";
182 static int olpc_bat_get_tech(union power_supply_propval
*val
)
187 ec_byte
= BAT_ADDR_MFR_TYPE
;
188 ret
= olpc_ec_cmd(EC_BAT_EEPROM
, &ec_byte
, 1, &ec_byte
, 1);
192 switch (ec_byte
& 0xf) {
194 val
->intval
= POWER_SUPPLY_TECHNOLOGY_NiMH
;
197 val
->intval
= POWER_SUPPLY_TECHNOLOGY_LiFe
;
200 val
->intval
= POWER_SUPPLY_TECHNOLOGY_UNKNOWN
;
207 static int olpc_bat_get_charge_full_design(union power_supply_propval
*val
)
210 union power_supply_propval tech
;
213 ret
= olpc_bat_get_tech(&tech
);
217 ec_byte
= BAT_ADDR_MFR_TYPE
;
218 ret
= olpc_ec_cmd(EC_BAT_EEPROM
, &ec_byte
, 1, &ec_byte
, 1);
224 switch (tech
.intval
) {
225 case POWER_SUPPLY_TECHNOLOGY_NiMH
:
227 case 1: /* Gold Peak */
228 val
->intval
= 3000000*.8;
235 case POWER_SUPPLY_TECHNOLOGY_LiFe
:
237 case 1: /* Gold Peak, fall through */
239 val
->intval
= 2800000;
253 static int olpc_bat_get_charge_now(union power_supply_propval
*val
)
256 union power_supply_propval full
;
259 ret
= olpc_ec_cmd(EC_BAT_SOC
, NULL
, 0, &soc
, 1);
263 ret
= olpc_bat_get_charge_full_design(&full
);
267 val
->intval
= soc
* (full
.intval
/ 100);
271 static int olpc_bat_get_voltage_max_design(union power_supply_propval
*val
)
274 union power_supply_propval tech
;
278 ret
= olpc_bat_get_tech(&tech
);
282 ec_byte
= BAT_ADDR_MFR_TYPE
;
283 ret
= olpc_ec_cmd(EC_BAT_EEPROM
, &ec_byte
, 1, &ec_byte
, 1);
289 switch (tech
.intval
) {
290 case POWER_SUPPLY_TECHNOLOGY_NiMH
:
292 case 1: /* Gold Peak */
293 val
->intval
= 6000000;
300 case POWER_SUPPLY_TECHNOLOGY_LiFe
:
302 case 1: /* Gold Peak */
303 val
->intval
= 6400000;
306 val
->intval
= 6500000;
320 /*********************************************************************
322 *********************************************************************/
323 static int olpc_bat_get_property(struct power_supply
*psy
,
324 enum power_supply_property psp
,
325 union power_supply_propval
*val
)
332 ret
= olpc_ec_cmd(EC_BAT_STATUS
, NULL
, 0, &ec_byte
, 1);
336 /* Theoretically there's a race here -- the battery could be
337 removed immediately after we check whether it's present, and
338 then we query for some other property of the now-absent battery.
339 It doesn't matter though -- the EC will return the last-known
340 information, and it's as if we just ran that _little_ bit faster
341 and managed to read it out before the battery went away. */
342 if (!(ec_byte
& (BAT_STAT_PRESENT
| BAT_STAT_TRICKLE
)) &&
343 psp
!= POWER_SUPPLY_PROP_PRESENT
)
347 case POWER_SUPPLY_PROP_STATUS
:
348 ret
= olpc_bat_get_status(val
, ec_byte
);
352 case POWER_SUPPLY_PROP_CHARGE_TYPE
:
353 if (ec_byte
& BAT_STAT_TRICKLE
)
354 val
->intval
= POWER_SUPPLY_CHARGE_TYPE_TRICKLE
;
355 else if (ec_byte
& BAT_STAT_CHARGING
)
356 val
->intval
= POWER_SUPPLY_CHARGE_TYPE_FAST
;
358 val
->intval
= POWER_SUPPLY_CHARGE_TYPE_NONE
;
360 case POWER_SUPPLY_PROP_PRESENT
:
361 val
->intval
= !!(ec_byte
& (BAT_STAT_PRESENT
|
365 case POWER_SUPPLY_PROP_HEALTH
:
366 if (ec_byte
& BAT_STAT_DESTROY
)
367 val
->intval
= POWER_SUPPLY_HEALTH_DEAD
;
369 ret
= olpc_bat_get_health(val
);
375 case POWER_SUPPLY_PROP_MANUFACTURER
:
376 ret
= olpc_bat_get_mfr(val
);
380 case POWER_SUPPLY_PROP_TECHNOLOGY
:
381 ret
= olpc_bat_get_tech(val
);
385 case POWER_SUPPLY_PROP_VOLTAGE_AVG
:
386 case POWER_SUPPLY_PROP_VOLTAGE_NOW
:
387 ret
= olpc_ec_cmd(EC_BAT_VOLTAGE
, NULL
, 0, (void *)&ec_word
, 2);
391 val
->intval
= (s16
)be16_to_cpu(ec_word
) * 9760L / 32;
393 case POWER_SUPPLY_PROP_CURRENT_AVG
:
394 case POWER_SUPPLY_PROP_CURRENT_NOW
:
395 ret
= olpc_ec_cmd(EC_BAT_CURRENT
, NULL
, 0, (void *)&ec_word
, 2);
399 val
->intval
= (s16
)be16_to_cpu(ec_word
) * 15625L / 120;
401 case POWER_SUPPLY_PROP_CAPACITY
:
402 ret
= olpc_ec_cmd(EC_BAT_SOC
, NULL
, 0, &ec_byte
, 1);
405 val
->intval
= ec_byte
;
407 case POWER_SUPPLY_PROP_CAPACITY_LEVEL
:
408 if (ec_byte
& BAT_STAT_FULL
)
409 val
->intval
= POWER_SUPPLY_CAPACITY_LEVEL_FULL
;
410 else if (ec_byte
& BAT_STAT_LOW
)
411 val
->intval
= POWER_SUPPLY_CAPACITY_LEVEL_LOW
;
413 val
->intval
= POWER_SUPPLY_CAPACITY_LEVEL_NORMAL
;
415 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN
:
416 ret
= olpc_bat_get_charge_full_design(val
);
420 case POWER_SUPPLY_PROP_CHARGE_NOW
:
421 ret
= olpc_bat_get_charge_now(val
);
425 case POWER_SUPPLY_PROP_TEMP
:
426 ret
= olpc_ec_cmd(EC_BAT_TEMP
, NULL
, 0, (void *)&ec_word
, 2);
430 val
->intval
= (s16
)be16_to_cpu(ec_word
) * 100 / 256;
432 case POWER_SUPPLY_PROP_TEMP_AMBIENT
:
433 ret
= olpc_ec_cmd(EC_AMB_TEMP
, NULL
, 0, (void *)&ec_word
, 2);
437 val
->intval
= (int)be16_to_cpu(ec_word
) * 100 / 256;
439 case POWER_SUPPLY_PROP_CHARGE_COUNTER
:
440 ret
= olpc_ec_cmd(EC_BAT_ACR
, NULL
, 0, (void *)&ec_word
, 2);
444 val
->intval
= (s16
)be16_to_cpu(ec_word
) * 6250 / 15;
446 case POWER_SUPPLY_PROP_SERIAL_NUMBER
:
447 ret
= olpc_ec_cmd(EC_BAT_SERIAL
, NULL
, 0, (void *)&ser_buf
, 8);
451 sprintf(bat_serial
, "%016llx", (long long)be64_to_cpu(ser_buf
));
452 val
->strval
= bat_serial
;
454 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN
:
455 ret
= olpc_bat_get_voltage_max_design(val
);
467 static enum power_supply_property olpc_xo1_bat_props
[] = {
468 POWER_SUPPLY_PROP_STATUS
,
469 POWER_SUPPLY_PROP_CHARGE_TYPE
,
470 POWER_SUPPLY_PROP_PRESENT
,
471 POWER_SUPPLY_PROP_HEALTH
,
472 POWER_SUPPLY_PROP_TECHNOLOGY
,
473 POWER_SUPPLY_PROP_VOLTAGE_AVG
,
474 POWER_SUPPLY_PROP_VOLTAGE_NOW
,
475 POWER_SUPPLY_PROP_CURRENT_AVG
,
476 POWER_SUPPLY_PROP_CURRENT_NOW
,
477 POWER_SUPPLY_PROP_CAPACITY
,
478 POWER_SUPPLY_PROP_CAPACITY_LEVEL
,
479 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN
,
480 POWER_SUPPLY_PROP_CHARGE_NOW
,
481 POWER_SUPPLY_PROP_TEMP
,
482 POWER_SUPPLY_PROP_TEMP_AMBIENT
,
483 POWER_SUPPLY_PROP_MANUFACTURER
,
484 POWER_SUPPLY_PROP_SERIAL_NUMBER
,
485 POWER_SUPPLY_PROP_CHARGE_COUNTER
,
486 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN
,
489 /* XO-1.5 does not have ambient temperature property */
490 static enum power_supply_property olpc_xo15_bat_props
[] = {
491 POWER_SUPPLY_PROP_STATUS
,
492 POWER_SUPPLY_PROP_CHARGE_TYPE
,
493 POWER_SUPPLY_PROP_PRESENT
,
494 POWER_SUPPLY_PROP_HEALTH
,
495 POWER_SUPPLY_PROP_TECHNOLOGY
,
496 POWER_SUPPLY_PROP_VOLTAGE_AVG
,
497 POWER_SUPPLY_PROP_VOLTAGE_NOW
,
498 POWER_SUPPLY_PROP_CURRENT_AVG
,
499 POWER_SUPPLY_PROP_CURRENT_NOW
,
500 POWER_SUPPLY_PROP_CAPACITY
,
501 POWER_SUPPLY_PROP_CAPACITY_LEVEL
,
502 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN
,
503 POWER_SUPPLY_PROP_CHARGE_NOW
,
504 POWER_SUPPLY_PROP_TEMP
,
505 POWER_SUPPLY_PROP_MANUFACTURER
,
506 POWER_SUPPLY_PROP_SERIAL_NUMBER
,
507 POWER_SUPPLY_PROP_CHARGE_COUNTER
,
508 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN
,
511 /* EEPROM reading goes completely around the power_supply API, sadly */
513 #define EEPROM_START 0x20
514 #define EEPROM_END 0x80
515 #define EEPROM_SIZE (EEPROM_END - EEPROM_START)
517 static ssize_t
olpc_bat_eeprom_read(struct file
*filp
, struct kobject
*kobj
,
518 struct bin_attribute
*attr
, char *buf
, loff_t off
, size_t count
)
524 for (i
= 0; i
< count
; i
++) {
525 ec_byte
= EEPROM_START
+ off
+ i
;
526 ret
= olpc_ec_cmd(EC_BAT_EEPROM
, &ec_byte
, 1, &buf
[i
], 1);
528 pr_err("olpc-battery: "
529 "EC_BAT_EEPROM cmd @ 0x%x failed - %d!\n",
538 static struct bin_attribute olpc_bat_eeprom
= {
544 .read
= olpc_bat_eeprom_read
,
547 /* Allow userspace to see the specific error value pulled from the EC */
549 static ssize_t
olpc_bat_error_read(struct device
*dev
,
550 struct device_attribute
*attr
, char *buf
)
555 ret
= olpc_ec_cmd(EC_BAT_ERRCODE
, NULL
, 0, &ec_byte
, 1);
559 return sprintf(buf
, "%d\n", ec_byte
);
562 static struct device_attribute olpc_bat_error
= {
567 .show
= olpc_bat_error_read
,
570 /*********************************************************************
572 *********************************************************************/
574 static struct power_supply_desc olpc_bat_desc
= {
575 .name
= "olpc-battery",
576 .get_property
= olpc_bat_get_property
,
580 static struct power_supply
*olpc_bat
;
582 static int olpc_battery_suspend(struct platform_device
*pdev
,
585 if (device_may_wakeup(&olpc_ac
->dev
))
586 olpc_ec_wakeup_set(EC_SCI_SRC_ACPWR
);
588 olpc_ec_wakeup_clear(EC_SCI_SRC_ACPWR
);
590 if (device_may_wakeup(&olpc_bat
->dev
))
591 olpc_ec_wakeup_set(EC_SCI_SRC_BATTERY
| EC_SCI_SRC_BATSOC
592 | EC_SCI_SRC_BATERR
);
594 olpc_ec_wakeup_clear(EC_SCI_SRC_BATTERY
| EC_SCI_SRC_BATSOC
595 | EC_SCI_SRC_BATERR
);
600 static int olpc_battery_probe(struct platform_device
*pdev
)
606 * We've seen a number of EC protocol changes; this driver requires
607 * the latest EC protocol, supported by 0x44 and above.
609 if (olpc_platform_info
.ecver
< 0x44) {
610 printk(KERN_NOTICE
"OLPC EC version 0x%02x too old for "
611 "battery driver.\n", olpc_platform_info
.ecver
);
615 ret
= olpc_ec_cmd(EC_BAT_STATUS
, NULL
, 0, &status
, 1);
619 /* Ignore the status. It doesn't actually matter */
621 olpc_ac
= power_supply_register(&pdev
->dev
, &olpc_ac_desc
, NULL
);
623 return PTR_ERR(olpc_ac
);
625 if (olpc_board_at_least(olpc_board_pre(0xd0))) { /* XO-1.5 */
626 olpc_bat_desc
.properties
= olpc_xo15_bat_props
;
627 olpc_bat_desc
.num_properties
= ARRAY_SIZE(olpc_xo15_bat_props
);
629 olpc_bat_desc
.properties
= olpc_xo1_bat_props
;
630 olpc_bat_desc
.num_properties
= ARRAY_SIZE(olpc_xo1_bat_props
);
633 olpc_bat
= power_supply_register(&pdev
->dev
, &olpc_bat_desc
, NULL
);
634 if (IS_ERR(olpc_bat
)) {
635 ret
= PTR_ERR(olpc_bat
);
639 ret
= device_create_bin_file(&olpc_bat
->dev
, &olpc_bat_eeprom
);
643 ret
= device_create_file(&olpc_bat
->dev
, &olpc_bat_error
);
647 if (olpc_ec_wakeup_available()) {
648 device_set_wakeup_capable(&olpc_ac
->dev
, true);
649 device_set_wakeup_capable(&olpc_bat
->dev
, true);
655 device_remove_bin_file(&olpc_bat
->dev
, &olpc_bat_eeprom
);
657 power_supply_unregister(olpc_bat
);
659 power_supply_unregister(olpc_ac
);
663 static int olpc_battery_remove(struct platform_device
*pdev
)
665 device_remove_file(&olpc_bat
->dev
, &olpc_bat_error
);
666 device_remove_bin_file(&olpc_bat
->dev
, &olpc_bat_eeprom
);
667 power_supply_unregister(olpc_bat
);
668 power_supply_unregister(olpc_ac
);
672 static const struct of_device_id olpc_battery_ids
[] = {
673 { .compatible
= "olpc,xo1-battery" },
676 MODULE_DEVICE_TABLE(of
, olpc_battery_ids
);
678 static struct platform_driver olpc_battery_driver
= {
680 .name
= "olpc-battery",
681 .of_match_table
= olpc_battery_ids
,
683 .probe
= olpc_battery_probe
,
684 .remove
= olpc_battery_remove
,
685 .suspend
= olpc_battery_suspend
,
688 module_platform_driver(olpc_battery_driver
);
690 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
691 MODULE_LICENSE("GPL");
692 MODULE_DESCRIPTION("Battery driver for One Laptop Per Child 'XO' machine");