1 // SPDX-License-Identifier: GPL-2.0-only
3 * Battery driver for One Laptop Per Child board.
5 * Copyright © 2006-2010 David Woodhouse <dwmw2@infradead.org>
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/mod_devicetable.h>
11 #include <linux/types.h>
12 #include <linux/err.h>
13 #include <linux/device.h>
15 #include <linux/platform_device.h>
16 #include <linux/power_supply.h>
17 #include <linux/jiffies.h>
18 #include <linux/sched.h>
19 #include <linux/olpc-ec.h>
22 #define EC_BAT_VOLTAGE 0x10 /* uint16_t, *9.76/32, mV */
23 #define EC_BAT_CURRENT 0x11 /* int16_t, *15.625/120, mA */
24 #define EC_BAT_ACR 0x12 /* int16_t, *6250/15, µAh */
25 #define EC_BAT_TEMP 0x13 /* uint16_t, *100/256, °C */
26 #define EC_AMB_TEMP 0x14 /* uint16_t, *100/256, °C */
27 #define EC_BAT_STATUS 0x15 /* uint8_t, bitmask */
28 #define EC_BAT_SOC 0x16 /* uint8_t, percentage */
29 #define EC_BAT_SERIAL 0x17 /* uint8_t[6] */
30 #define EC_BAT_EEPROM 0x18 /* uint8_t adr as input, uint8_t output */
31 #define EC_BAT_ERRCODE 0x1f /* uint8_t, bitmask */
33 #define BAT_STAT_PRESENT 0x01
34 #define BAT_STAT_FULL 0x02
35 #define BAT_STAT_LOW 0x04
36 #define BAT_STAT_DESTROY 0x08
37 #define BAT_STAT_AC 0x10
38 #define BAT_STAT_CHARGING 0x20
39 #define BAT_STAT_DISCHARGING 0x40
40 #define BAT_STAT_TRICKLE 0x80
42 #define BAT_ERR_INFOFAIL 0x02
43 #define BAT_ERR_OVERVOLTAGE 0x04
44 #define BAT_ERR_OVERTEMP 0x05
45 #define BAT_ERR_GAUGESTOP 0x06
46 #define BAT_ERR_OUT_OF_CONTROL 0x07
47 #define BAT_ERR_ID_FAIL 0x09
48 #define BAT_ERR_ACR_FAIL 0x10
50 #define BAT_ADDR_MFR_TYPE 0x5F
52 struct olpc_battery_data
{
53 struct power_supply
*olpc_ac
;
54 struct power_supply
*olpc_bat
;
60 /*********************************************************************
62 *********************************************************************/
64 static int olpc_ac_get_prop(struct power_supply
*psy
,
65 enum power_supply_property psp
,
66 union power_supply_propval
*val
)
72 case POWER_SUPPLY_PROP_ONLINE
:
73 ret
= olpc_ec_cmd(EC_BAT_STATUS
, NULL
, 0, &status
, 1);
77 val
->intval
= !!(status
& BAT_STAT_AC
);
86 static enum power_supply_property olpc_ac_props
[] = {
87 POWER_SUPPLY_PROP_ONLINE
,
90 static const struct power_supply_desc olpc_ac_desc
= {
92 .type
= POWER_SUPPLY_TYPE_MAINS
,
93 .properties
= olpc_ac_props
,
94 .num_properties
= ARRAY_SIZE(olpc_ac_props
),
95 .get_property
= olpc_ac_get_prop
,
98 static int olpc_bat_get_status(struct olpc_battery_data
*data
,
99 union power_supply_propval
*val
, uint8_t ec_byte
)
101 if (data
->new_proto
) {
102 if (ec_byte
& (BAT_STAT_CHARGING
| BAT_STAT_TRICKLE
))
103 val
->intval
= POWER_SUPPLY_STATUS_CHARGING
;
104 else if (ec_byte
& BAT_STAT_DISCHARGING
)
105 val
->intval
= POWER_SUPPLY_STATUS_DISCHARGING
;
106 else if (ec_byte
& BAT_STAT_FULL
)
107 val
->intval
= POWER_SUPPLY_STATUS_FULL
;
109 val
->intval
= POWER_SUPPLY_STATUS_NOT_CHARGING
;
111 /* Older EC didn't report charge/discharge bits */
112 if (!(ec_byte
& BAT_STAT_AC
)) /* No AC means discharging */
113 val
->intval
= POWER_SUPPLY_STATUS_DISCHARGING
;
114 else if (ec_byte
& BAT_STAT_FULL
)
115 val
->intval
= POWER_SUPPLY_STATUS_FULL
;
116 else /* Not _necessarily_ true but EC doesn't tell all yet */
117 val
->intval
= POWER_SUPPLY_STATUS_CHARGING
;
123 static int olpc_bat_get_health(union power_supply_propval
*val
)
128 ret
= olpc_ec_cmd(EC_BAT_ERRCODE
, NULL
, 0, &ec_byte
, 1);
134 val
->intval
= POWER_SUPPLY_HEALTH_GOOD
;
137 case BAT_ERR_OVERTEMP
:
138 val
->intval
= POWER_SUPPLY_HEALTH_OVERHEAT
;
141 case BAT_ERR_OVERVOLTAGE
:
142 val
->intval
= POWER_SUPPLY_HEALTH_OVERVOLTAGE
;
145 case BAT_ERR_INFOFAIL
:
146 case BAT_ERR_OUT_OF_CONTROL
:
147 case BAT_ERR_ID_FAIL
:
148 case BAT_ERR_ACR_FAIL
:
149 val
->intval
= POWER_SUPPLY_HEALTH_UNSPEC_FAILURE
;
153 /* Eep. We don't know this failure code */
160 static int olpc_bat_get_mfr(union power_supply_propval
*val
)
165 ec_byte
= BAT_ADDR_MFR_TYPE
;
166 ret
= olpc_ec_cmd(EC_BAT_EEPROM
, &ec_byte
, 1, &ec_byte
, 1);
170 switch (ec_byte
>> 4) {
172 val
->strval
= "Gold Peak";
178 val
->strval
= "Unknown";
185 static int olpc_bat_get_tech(union power_supply_propval
*val
)
190 ec_byte
= BAT_ADDR_MFR_TYPE
;
191 ret
= olpc_ec_cmd(EC_BAT_EEPROM
, &ec_byte
, 1, &ec_byte
, 1);
195 switch (ec_byte
& 0xf) {
197 val
->intval
= POWER_SUPPLY_TECHNOLOGY_NiMH
;
200 val
->intval
= POWER_SUPPLY_TECHNOLOGY_LiFe
;
203 val
->intval
= POWER_SUPPLY_TECHNOLOGY_UNKNOWN
;
210 static int olpc_bat_get_charge_full_design(union power_supply_propval
*val
)
213 union power_supply_propval tech
;
216 ret
= olpc_bat_get_tech(&tech
);
220 ec_byte
= BAT_ADDR_MFR_TYPE
;
221 ret
= olpc_ec_cmd(EC_BAT_EEPROM
, &ec_byte
, 1, &ec_byte
, 1);
227 switch (tech
.intval
) {
228 case POWER_SUPPLY_TECHNOLOGY_NiMH
:
230 case 1: /* Gold Peak */
231 val
->intval
= 3000000*.8;
238 case POWER_SUPPLY_TECHNOLOGY_LiFe
:
240 case 1: /* Gold Peak, fall through */
242 val
->intval
= 2800000;
256 static int olpc_bat_get_charge_now(union power_supply_propval
*val
)
259 union power_supply_propval full
;
262 ret
= olpc_ec_cmd(EC_BAT_SOC
, NULL
, 0, &soc
, 1);
266 ret
= olpc_bat_get_charge_full_design(&full
);
270 val
->intval
= soc
* (full
.intval
/ 100);
274 static int olpc_bat_get_voltage_max_design(union power_supply_propval
*val
)
277 union power_supply_propval tech
;
281 ret
= olpc_bat_get_tech(&tech
);
285 ec_byte
= BAT_ADDR_MFR_TYPE
;
286 ret
= olpc_ec_cmd(EC_BAT_EEPROM
, &ec_byte
, 1, &ec_byte
, 1);
292 switch (tech
.intval
) {
293 case POWER_SUPPLY_TECHNOLOGY_NiMH
:
295 case 1: /* Gold Peak */
296 val
->intval
= 6000000;
303 case POWER_SUPPLY_TECHNOLOGY_LiFe
:
305 case 1: /* Gold Peak */
306 val
->intval
= 6400000;
309 val
->intval
= 6500000;
323 static u16
ecword_to_cpu(struct olpc_battery_data
*data
, u16 ec_word
)
325 if (data
->little_endian
)
326 return le16_to_cpu((__force __le16
)ec_word
);
328 return be16_to_cpu((__force __be16
)ec_word
);
331 /*********************************************************************
333 *********************************************************************/
334 static int olpc_bat_get_property(struct power_supply
*psy
,
335 enum power_supply_property psp
,
336 union power_supply_propval
*val
)
338 struct olpc_battery_data
*data
= power_supply_get_drvdata(psy
);
344 ret
= olpc_ec_cmd(EC_BAT_STATUS
, NULL
, 0, &ec_byte
, 1);
348 /* Theoretically there's a race here -- the battery could be
349 removed immediately after we check whether it's present, and
350 then we query for some other property of the now-absent battery.
351 It doesn't matter though -- the EC will return the last-known
352 information, and it's as if we just ran that _little_ bit faster
353 and managed to read it out before the battery went away. */
354 if (!(ec_byte
& (BAT_STAT_PRESENT
| BAT_STAT_TRICKLE
)) &&
355 psp
!= POWER_SUPPLY_PROP_PRESENT
)
359 case POWER_SUPPLY_PROP_STATUS
:
360 ret
= olpc_bat_get_status(data
, val
, ec_byte
);
364 case POWER_SUPPLY_PROP_CHARGE_TYPE
:
365 if (ec_byte
& BAT_STAT_TRICKLE
)
366 val
->intval
= POWER_SUPPLY_CHARGE_TYPE_TRICKLE
;
367 else if (ec_byte
& BAT_STAT_CHARGING
)
368 val
->intval
= POWER_SUPPLY_CHARGE_TYPE_FAST
;
370 val
->intval
= POWER_SUPPLY_CHARGE_TYPE_NONE
;
372 case POWER_SUPPLY_PROP_PRESENT
:
373 val
->intval
= !!(ec_byte
& (BAT_STAT_PRESENT
|
377 case POWER_SUPPLY_PROP_HEALTH
:
378 if (ec_byte
& BAT_STAT_DESTROY
)
379 val
->intval
= POWER_SUPPLY_HEALTH_DEAD
;
381 ret
= olpc_bat_get_health(val
);
387 case POWER_SUPPLY_PROP_MANUFACTURER
:
388 ret
= olpc_bat_get_mfr(val
);
392 case POWER_SUPPLY_PROP_TECHNOLOGY
:
393 ret
= olpc_bat_get_tech(val
);
397 case POWER_SUPPLY_PROP_VOLTAGE_AVG
:
398 case POWER_SUPPLY_PROP_VOLTAGE_NOW
:
399 ret
= olpc_ec_cmd(EC_BAT_VOLTAGE
, NULL
, 0, (void *)&ec_word
, 2);
403 val
->intval
= ecword_to_cpu(data
, ec_word
) * 9760L / 32;
405 case POWER_SUPPLY_PROP_CURRENT_AVG
:
406 case POWER_SUPPLY_PROP_CURRENT_NOW
:
407 ret
= olpc_ec_cmd(EC_BAT_CURRENT
, NULL
, 0, (void *)&ec_word
, 2);
411 val
->intval
= ecword_to_cpu(data
, ec_word
) * 15625L / 120;
413 case POWER_SUPPLY_PROP_CAPACITY
:
414 ret
= olpc_ec_cmd(EC_BAT_SOC
, NULL
, 0, &ec_byte
, 1);
417 val
->intval
= ec_byte
;
419 case POWER_SUPPLY_PROP_CAPACITY_LEVEL
:
420 if (ec_byte
& BAT_STAT_FULL
)
421 val
->intval
= POWER_SUPPLY_CAPACITY_LEVEL_FULL
;
422 else if (ec_byte
& BAT_STAT_LOW
)
423 val
->intval
= POWER_SUPPLY_CAPACITY_LEVEL_LOW
;
425 val
->intval
= POWER_SUPPLY_CAPACITY_LEVEL_NORMAL
;
427 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN
:
428 ret
= olpc_bat_get_charge_full_design(val
);
432 case POWER_SUPPLY_PROP_CHARGE_NOW
:
433 ret
= olpc_bat_get_charge_now(val
);
437 case POWER_SUPPLY_PROP_TEMP
:
438 ret
= olpc_ec_cmd(EC_BAT_TEMP
, NULL
, 0, (void *)&ec_word
, 2);
442 val
->intval
= ecword_to_cpu(data
, ec_word
) * 10 / 256;
444 case POWER_SUPPLY_PROP_TEMP_AMBIENT
:
445 ret
= olpc_ec_cmd(EC_AMB_TEMP
, NULL
, 0, (void *)&ec_word
, 2);
449 val
->intval
= (int)ecword_to_cpu(data
, ec_word
) * 10 / 256;
451 case POWER_SUPPLY_PROP_CHARGE_COUNTER
:
452 ret
= olpc_ec_cmd(EC_BAT_ACR
, NULL
, 0, (void *)&ec_word
, 2);
456 val
->intval
= ecword_to_cpu(data
, ec_word
) * 6250 / 15;
458 case POWER_SUPPLY_PROP_SERIAL_NUMBER
:
459 ret
= olpc_ec_cmd(EC_BAT_SERIAL
, NULL
, 0, (void *)&ser_buf
, 8);
463 sprintf(data
->bat_serial
, "%016llx", (long long)be64_to_cpu(ser_buf
));
464 val
->strval
= data
->bat_serial
;
466 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN
:
467 ret
= olpc_bat_get_voltage_max_design(val
);
479 static enum power_supply_property olpc_xo1_bat_props
[] = {
480 POWER_SUPPLY_PROP_STATUS
,
481 POWER_SUPPLY_PROP_CHARGE_TYPE
,
482 POWER_SUPPLY_PROP_PRESENT
,
483 POWER_SUPPLY_PROP_HEALTH
,
484 POWER_SUPPLY_PROP_TECHNOLOGY
,
485 POWER_SUPPLY_PROP_VOLTAGE_AVG
,
486 POWER_SUPPLY_PROP_VOLTAGE_NOW
,
487 POWER_SUPPLY_PROP_CURRENT_AVG
,
488 POWER_SUPPLY_PROP_CURRENT_NOW
,
489 POWER_SUPPLY_PROP_CAPACITY
,
490 POWER_SUPPLY_PROP_CAPACITY_LEVEL
,
491 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN
,
492 POWER_SUPPLY_PROP_CHARGE_NOW
,
493 POWER_SUPPLY_PROP_TEMP
,
494 POWER_SUPPLY_PROP_TEMP_AMBIENT
,
495 POWER_SUPPLY_PROP_MANUFACTURER
,
496 POWER_SUPPLY_PROP_SERIAL_NUMBER
,
497 POWER_SUPPLY_PROP_CHARGE_COUNTER
,
498 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN
,
501 /* XO-1.5 does not have ambient temperature property */
502 static enum power_supply_property olpc_xo15_bat_props
[] = {
503 POWER_SUPPLY_PROP_STATUS
,
504 POWER_SUPPLY_PROP_CHARGE_TYPE
,
505 POWER_SUPPLY_PROP_PRESENT
,
506 POWER_SUPPLY_PROP_HEALTH
,
507 POWER_SUPPLY_PROP_TECHNOLOGY
,
508 POWER_SUPPLY_PROP_VOLTAGE_AVG
,
509 POWER_SUPPLY_PROP_VOLTAGE_NOW
,
510 POWER_SUPPLY_PROP_CURRENT_AVG
,
511 POWER_SUPPLY_PROP_CURRENT_NOW
,
512 POWER_SUPPLY_PROP_CAPACITY
,
513 POWER_SUPPLY_PROP_CAPACITY_LEVEL
,
514 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN
,
515 POWER_SUPPLY_PROP_CHARGE_NOW
,
516 POWER_SUPPLY_PROP_TEMP
,
517 POWER_SUPPLY_PROP_MANUFACTURER
,
518 POWER_SUPPLY_PROP_SERIAL_NUMBER
,
519 POWER_SUPPLY_PROP_CHARGE_COUNTER
,
520 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN
,
523 /* EEPROM reading goes completely around the power_supply API, sadly */
525 #define EEPROM_START 0x20
526 #define EEPROM_END 0x80
527 #define EEPROM_SIZE (EEPROM_END - EEPROM_START)
529 static ssize_t
olpc_bat_eeprom_read(struct file
*filp
, struct kobject
*kobj
,
530 struct bin_attribute
*attr
, char *buf
, loff_t off
, size_t count
)
536 for (i
= 0; i
< count
; i
++) {
537 ec_byte
= EEPROM_START
+ off
+ i
;
538 ret
= olpc_ec_cmd(EC_BAT_EEPROM
, &ec_byte
, 1, &buf
[i
], 1);
540 pr_err("olpc-battery: "
541 "EC_BAT_EEPROM cmd @ 0x%x failed - %d!\n",
550 static struct bin_attribute olpc_bat_eeprom
= {
556 .read
= olpc_bat_eeprom_read
,
559 /* Allow userspace to see the specific error value pulled from the EC */
561 static ssize_t
olpc_bat_error_read(struct device
*dev
,
562 struct device_attribute
*attr
, char *buf
)
567 ret
= olpc_ec_cmd(EC_BAT_ERRCODE
, NULL
, 0, &ec_byte
, 1);
571 return sprintf(buf
, "%d\n", ec_byte
);
574 static struct device_attribute olpc_bat_error
= {
579 .show
= olpc_bat_error_read
,
582 static struct attribute
*olpc_bat_sysfs_attrs
[] = {
583 &olpc_bat_error
.attr
,
587 static struct bin_attribute
*olpc_bat_sysfs_bin_attrs
[] = {
592 static const struct attribute_group olpc_bat_sysfs_group
= {
593 .attrs
= olpc_bat_sysfs_attrs
,
594 .bin_attrs
= olpc_bat_sysfs_bin_attrs
,
598 static const struct attribute_group
*olpc_bat_sysfs_groups
[] = {
599 &olpc_bat_sysfs_group
,
603 /*********************************************************************
605 *********************************************************************/
607 static struct power_supply_desc olpc_bat_desc
= {
608 .name
= "olpc_battery",
609 .get_property
= olpc_bat_get_property
,
613 static int olpc_battery_suspend(struct platform_device
*pdev
,
616 struct olpc_battery_data
*data
= platform_get_drvdata(pdev
);
618 if (device_may_wakeup(&data
->olpc_ac
->dev
))
619 olpc_ec_wakeup_set(EC_SCI_SRC_ACPWR
);
621 olpc_ec_wakeup_clear(EC_SCI_SRC_ACPWR
);
623 if (device_may_wakeup(&data
->olpc_bat
->dev
))
624 olpc_ec_wakeup_set(EC_SCI_SRC_BATTERY
| EC_SCI_SRC_BATSOC
625 | EC_SCI_SRC_BATERR
);
627 olpc_ec_wakeup_clear(EC_SCI_SRC_BATTERY
| EC_SCI_SRC_BATSOC
628 | EC_SCI_SRC_BATERR
);
633 static int olpc_battery_probe(struct platform_device
*pdev
)
635 struct power_supply_config bat_psy_cfg
= {};
636 struct power_supply_config ac_psy_cfg
= {};
637 struct olpc_battery_data
*data
;
642 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
645 platform_set_drvdata(pdev
, data
);
647 /* See if the EC is already there and get the EC revision */
648 ret
= olpc_ec_cmd(EC_FIRMWARE_REV
, NULL
, 0, &ecver
, 1);
652 if (of_find_compatible_node(NULL
, NULL
, "olpc,xo1.75-ec")) {
654 data
->new_proto
= true;
655 data
->little_endian
= true;
656 } else if (ecver
> 0x44) {
657 /* XO 1 or 1.5 with a new EC firmware. */
658 data
->new_proto
= true;
659 } else if (ecver
< 0x44) {
661 * We've seen a number of EC protocol changes; this driver
662 * requires the latest EC protocol, supported by 0x44 and above.
664 printk(KERN_NOTICE
"OLPC EC version 0x%02x too old for "
665 "battery driver.\n", ecver
);
669 ret
= olpc_ec_cmd(EC_BAT_STATUS
, NULL
, 0, &status
, 1);
673 /* Ignore the status. It doesn't actually matter */
675 ac_psy_cfg
.of_node
= pdev
->dev
.of_node
;
676 ac_psy_cfg
.drv_data
= data
;
678 data
->olpc_ac
= devm_power_supply_register(&pdev
->dev
, &olpc_ac_desc
,
680 if (IS_ERR(data
->olpc_ac
))
681 return PTR_ERR(data
->olpc_ac
);
683 if (of_device_is_compatible(pdev
->dev
.of_node
, "olpc,xo1.5-battery")) {
685 olpc_bat_desc
.properties
= olpc_xo15_bat_props
;
686 olpc_bat_desc
.num_properties
= ARRAY_SIZE(olpc_xo15_bat_props
);
689 olpc_bat_desc
.properties
= olpc_xo1_bat_props
;
690 olpc_bat_desc
.num_properties
= ARRAY_SIZE(olpc_xo1_bat_props
);
693 bat_psy_cfg
.of_node
= pdev
->dev
.of_node
;
694 bat_psy_cfg
.drv_data
= data
;
695 bat_psy_cfg
.attr_grp
= olpc_bat_sysfs_groups
;
697 data
->olpc_bat
= devm_power_supply_register(&pdev
->dev
, &olpc_bat_desc
,
699 if (IS_ERR(data
->olpc_bat
))
700 return PTR_ERR(data
->olpc_bat
);
702 if (olpc_ec_wakeup_available()) {
703 device_set_wakeup_capable(&data
->olpc_ac
->dev
, true);
704 device_set_wakeup_capable(&data
->olpc_bat
->dev
, true);
710 static const struct of_device_id olpc_battery_ids
[] = {
711 { .compatible
= "olpc,xo1-battery" },
712 { .compatible
= "olpc,xo1.5-battery" },
715 MODULE_DEVICE_TABLE(of
, olpc_battery_ids
);
717 static struct platform_driver olpc_battery_driver
= {
719 .name
= "olpc-battery",
720 .of_match_table
= olpc_battery_ids
,
722 .probe
= olpc_battery_probe
,
723 .suspend
= olpc_battery_suspend
,
726 module_platform_driver(olpc_battery_driver
);
728 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
729 MODULE_LICENSE("GPL");
730 MODULE_DESCRIPTION("Battery driver for One Laptop Per Child 'XO' machine");