734 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Battery driver for One Laptop Per Child board.4 *5 * Copyright © 2006-2010 David Woodhouse <dwmw2@infradead.org>6 */7 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>14#include <linux/of.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>20 21 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 */32 33#define BAT_STAT_PRESENT 0x0134#define BAT_STAT_FULL 0x0235#define BAT_STAT_LOW 0x0436#define BAT_STAT_DESTROY 0x0837#define BAT_STAT_AC 0x1038#define BAT_STAT_CHARGING 0x2039#define BAT_STAT_DISCHARGING 0x4040#define BAT_STAT_TRICKLE 0x8041 42#define BAT_ERR_INFOFAIL 0x0243#define BAT_ERR_OVERVOLTAGE 0x0444#define BAT_ERR_OVERTEMP 0x0545#define BAT_ERR_GAUGESTOP 0x0646#define BAT_ERR_OUT_OF_CONTROL 0x0747#define BAT_ERR_ID_FAIL 0x0948#define BAT_ERR_ACR_FAIL 0x1049 50#define BAT_ADDR_MFR_TYPE 0x5F51 52struct olpc_battery_data {53 struct power_supply *olpc_ac;54 struct power_supply *olpc_bat;55 char bat_serial[17];56 bool new_proto;57 bool little_endian;58};59 60/*********************************************************************61 * Power62 *********************************************************************/63 64static int olpc_ac_get_prop(struct power_supply *psy,65 enum power_supply_property psp,66 union power_supply_propval *val)67{68 int ret = 0;69 uint8_t status;70 71 switch (psp) {72 case POWER_SUPPLY_PROP_ONLINE:73 ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &status, 1);74 if (ret)75 return ret;76 77 val->intval = !!(status & BAT_STAT_AC);78 break;79 default:80 ret = -EINVAL;81 break;82 }83 return ret;84}85 86static enum power_supply_property olpc_ac_props[] = {87 POWER_SUPPLY_PROP_ONLINE,88};89 90static const struct power_supply_desc olpc_ac_desc = {91 .name = "olpc_ac",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,96};97 98static int olpc_bat_get_status(struct olpc_battery_data *data,99 union power_supply_propval *val, uint8_t ec_byte)100{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;108 else /* er,... */109 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;110 } else {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;118 }119 120 return 0;121}122 123static int olpc_bat_get_health(union power_supply_propval *val)124{125 uint8_t ec_byte;126 int ret;127 128 ret = olpc_ec_cmd(EC_BAT_ERRCODE, NULL, 0, &ec_byte, 1);129 if (ret)130 return ret;131 132 switch (ec_byte) {133 case 0:134 val->intval = POWER_SUPPLY_HEALTH_GOOD;135 break;136 137 case BAT_ERR_OVERTEMP:138 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;139 break;140 141 case BAT_ERR_OVERVOLTAGE:142 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;143 break;144 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;150 break;151 152 default:153 /* Eep. We don't know this failure code */154 ret = -EIO;155 }156 157 return ret;158}159 160static int olpc_bat_get_mfr(union power_supply_propval *val)161{162 uint8_t ec_byte;163 int ret;164 165 ec_byte = BAT_ADDR_MFR_TYPE;166 ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);167 if (ret)168 return ret;169 170 switch (ec_byte >> 4) {171 case 1:172 val->strval = "Gold Peak";173 break;174 case 2:175 val->strval = "BYD";176 break;177 default:178 val->strval = "Unknown";179 break;180 }181 182 return ret;183}184 185static int olpc_bat_get_tech(union power_supply_propval *val)186{187 uint8_t ec_byte;188 int ret;189 190 ec_byte = BAT_ADDR_MFR_TYPE;191 ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);192 if (ret)193 return ret;194 195 switch (ec_byte & 0xf) {196 case 1:197 val->intval = POWER_SUPPLY_TECHNOLOGY_NiMH;198 break;199 case 2:200 val->intval = POWER_SUPPLY_TECHNOLOGY_LiFe;201 break;202 default:203 val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;204 break;205 }206 207 return ret;208}209 210static int olpc_bat_get_charge_full_design(union power_supply_propval *val)211{212 uint8_t ec_byte;213 union power_supply_propval tech;214 int ret, mfr;215 216 ret = olpc_bat_get_tech(&tech);217 if (ret)218 return ret;219 220 ec_byte = BAT_ADDR_MFR_TYPE;221 ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);222 if (ret)223 return ret;224 225 mfr = ec_byte >> 4;226 227 switch (tech.intval) {228 case POWER_SUPPLY_TECHNOLOGY_NiMH:229 switch (mfr) {230 case 1: /* Gold Peak */231 val->intval = 3000000*.8;232 break;233 default:234 return -EIO;235 }236 break;237 238 case POWER_SUPPLY_TECHNOLOGY_LiFe:239 switch (mfr) {240 case 1: /* Gold Peak, fall through */241 case 2: /* BYD */242 val->intval = 2800000;243 break;244 default:245 return -EIO;246 }247 break;248 249 default:250 return -EIO;251 }252 253 return ret;254}255 256static int olpc_bat_get_charge_now(union power_supply_propval *val)257{258 uint8_t soc;259 union power_supply_propval full;260 int ret;261 262 ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &soc, 1);263 if (ret)264 return ret;265 266 ret = olpc_bat_get_charge_full_design(&full);267 if (ret)268 return ret;269 270 val->intval = soc * (full.intval / 100);271 return 0;272}273 274static int olpc_bat_get_voltage_max_design(union power_supply_propval *val)275{276 uint8_t ec_byte;277 union power_supply_propval tech;278 int mfr;279 int ret;280 281 ret = olpc_bat_get_tech(&tech);282 if (ret)283 return ret;284 285 ec_byte = BAT_ADDR_MFR_TYPE;286 ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);287 if (ret)288 return ret;289 290 mfr = ec_byte >> 4;291 292 switch (tech.intval) {293 case POWER_SUPPLY_TECHNOLOGY_NiMH:294 switch (mfr) {295 case 1: /* Gold Peak */296 val->intval = 6000000;297 break;298 default:299 return -EIO;300 }301 break;302 303 case POWER_SUPPLY_TECHNOLOGY_LiFe:304 switch (mfr) {305 case 1: /* Gold Peak */306 val->intval = 6400000;307 break;308 case 2: /* BYD */309 val->intval = 6500000;310 break;311 default:312 return -EIO;313 }314 break;315 316 default:317 return -EIO;318 }319 320 return ret;321}322 323static u16 ecword_to_cpu(struct olpc_battery_data *data, u16 ec_word)324{325 if (data->little_endian)326 return le16_to_cpu((__force __le16)ec_word);327 else328 return be16_to_cpu((__force __be16)ec_word);329}330 331/*********************************************************************332 * Battery properties333 *********************************************************************/334static int olpc_bat_get_property(struct power_supply *psy,335 enum power_supply_property psp,336 union power_supply_propval *val)337{338 struct olpc_battery_data *data = power_supply_get_drvdata(psy);339 int ret = 0;340 u16 ec_word;341 uint8_t ec_byte;342 __be64 ser_buf;343 344 ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &ec_byte, 1);345 if (ret)346 return ret;347 348 /* Theoretically there's a race here -- the battery could be349 removed immediately after we check whether it's present, and350 then we query for some other property of the now-absent battery.351 It doesn't matter though -- the EC will return the last-known352 information, and it's as if we just ran that _little_ bit faster353 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)356 return -ENODEV;357 358 switch (psp) {359 case POWER_SUPPLY_PROP_STATUS:360 ret = olpc_bat_get_status(data, val, ec_byte);361 if (ret)362 return ret;363 break;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;369 else370 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;371 break;372 case POWER_SUPPLY_PROP_PRESENT:373 val->intval = !!(ec_byte & (BAT_STAT_PRESENT |374 BAT_STAT_TRICKLE));375 break;376 377 case POWER_SUPPLY_PROP_HEALTH:378 if (ec_byte & BAT_STAT_DESTROY)379 val->intval = POWER_SUPPLY_HEALTH_DEAD;380 else {381 ret = olpc_bat_get_health(val);382 if (ret)383 return ret;384 }385 break;386 387 case POWER_SUPPLY_PROP_MANUFACTURER:388 ret = olpc_bat_get_mfr(val);389 if (ret)390 return ret;391 break;392 case POWER_SUPPLY_PROP_TECHNOLOGY:393 ret = olpc_bat_get_tech(val);394 if (ret)395 return ret;396 break;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);400 if (ret)401 return ret;402 403 val->intval = ecword_to_cpu(data, ec_word) * 9760L / 32;404 break;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);408 if (ret)409 return ret;410 411 val->intval = ecword_to_cpu(data, ec_word) * 15625L / 120;412 break;413 case POWER_SUPPLY_PROP_CAPACITY:414 ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &ec_byte, 1);415 if (ret)416 return ret;417 val->intval = ec_byte;418 break;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;424 else425 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;426 break;427 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:428 ret = olpc_bat_get_charge_full_design(val);429 if (ret)430 return ret;431 break;432 case POWER_SUPPLY_PROP_CHARGE_NOW:433 ret = olpc_bat_get_charge_now(val);434 if (ret)435 return ret;436 break;437 case POWER_SUPPLY_PROP_TEMP:438 ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);439 if (ret)440 return ret;441 442 val->intval = ecword_to_cpu(data, ec_word) * 10 / 256;443 break;444 case POWER_SUPPLY_PROP_TEMP_AMBIENT:445 ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2);446 if (ret)447 return ret;448 449 val->intval = (int)ecword_to_cpu(data, ec_word) * 10 / 256;450 break;451 case POWER_SUPPLY_PROP_CHARGE_COUNTER:452 ret = olpc_ec_cmd(EC_BAT_ACR, NULL, 0, (void *)&ec_word, 2);453 if (ret)454 return ret;455 456 val->intval = ecword_to_cpu(data, ec_word) * 6250 / 15;457 break;458 case POWER_SUPPLY_PROP_SERIAL_NUMBER:459 ret = olpc_ec_cmd(EC_BAT_SERIAL, NULL, 0, (void *)&ser_buf, 8);460 if (ret)461 return ret;462 463 sprintf(data->bat_serial, "%016llx", (long long)be64_to_cpu(ser_buf));464 val->strval = data->bat_serial;465 break;466 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:467 ret = olpc_bat_get_voltage_max_design(val);468 if (ret)469 return ret;470 break;471 default:472 ret = -EINVAL;473 break;474 }475 476 return ret;477}478 479static 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,499};500 501/* XO-1.5 does not have ambient temperature property */502static 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,521};522 523/* EEPROM reading goes completely around the power_supply API, sadly */524 525#define EEPROM_START 0x20526#define EEPROM_END 0x80527#define EEPROM_SIZE (EEPROM_END - EEPROM_START)528 529static 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)531{532 uint8_t ec_byte;533 int ret;534 int i;535 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);539 if (ret) {540 pr_err("olpc-battery: "541 "EC_BAT_EEPROM cmd @ 0x%x failed - %d!\n",542 ec_byte, ret);543 return -EIO;544 }545 }546 547 return count;548}549 550static struct bin_attribute olpc_bat_eeprom = {551 .attr = {552 .name = "eeprom",553 .mode = S_IRUGO,554 },555 .size = EEPROM_SIZE,556 .read = olpc_bat_eeprom_read,557};558 559/* Allow userspace to see the specific error value pulled from the EC */560 561static ssize_t olpc_bat_error_read(struct device *dev,562 struct device_attribute *attr, char *buf)563{564 uint8_t ec_byte;565 ssize_t ret;566 567 ret = olpc_ec_cmd(EC_BAT_ERRCODE, NULL, 0, &ec_byte, 1);568 if (ret < 0)569 return ret;570 571 return sysfs_emit(buf, "%d\n", ec_byte);572}573 574static struct device_attribute olpc_bat_error = {575 .attr = {576 .name = "error",577 .mode = S_IRUGO,578 },579 .show = olpc_bat_error_read,580};581 582static struct attribute *olpc_bat_sysfs_attrs[] = {583 &olpc_bat_error.attr,584 NULL585};586 587static struct bin_attribute *olpc_bat_sysfs_bin_attrs[] = {588 &olpc_bat_eeprom,589 NULL590};591 592static const struct attribute_group olpc_bat_sysfs_group = {593 .attrs = olpc_bat_sysfs_attrs,594 .bin_attrs = olpc_bat_sysfs_bin_attrs,595 596};597 598static const struct attribute_group *olpc_bat_sysfs_groups[] = {599 &olpc_bat_sysfs_group,600 NULL601};602 603/*********************************************************************604 * Initialisation605 *********************************************************************/606 607static struct power_supply_desc olpc_bat_desc = {608 .name = "olpc_battery",609 .get_property = olpc_bat_get_property,610 .use_for_apm = 1,611};612 613static int olpc_battery_suspend(struct platform_device *pdev,614 pm_message_t state)615{616 struct olpc_battery_data *data = platform_get_drvdata(pdev);617 618 if (device_may_wakeup(&data->olpc_ac->dev))619 olpc_ec_wakeup_set(EC_SCI_SRC_ACPWR);620 else621 olpc_ec_wakeup_clear(EC_SCI_SRC_ACPWR);622 623 if (device_may_wakeup(&data->olpc_bat->dev))624 olpc_ec_wakeup_set(EC_SCI_SRC_BATTERY | EC_SCI_SRC_BATSOC625 | EC_SCI_SRC_BATERR);626 else627 olpc_ec_wakeup_clear(EC_SCI_SRC_BATTERY | EC_SCI_SRC_BATSOC628 | EC_SCI_SRC_BATERR);629 630 return 0;631}632 633static int olpc_battery_probe(struct platform_device *pdev)634{635 struct power_supply_config bat_psy_cfg = {};636 struct power_supply_config ac_psy_cfg = {};637 struct olpc_battery_data *data;638 struct device_node *np;639 uint8_t status;640 uint8_t ecver;641 int ret;642 643 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);644 if (!data)645 return -ENOMEM;646 platform_set_drvdata(pdev, data);647 648 /* See if the EC is already there and get the EC revision */649 ret = olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0, &ecver, 1);650 if (ret)651 return ret;652 653 np = of_find_compatible_node(NULL, NULL, "olpc,xo1.75-ec");654 if (np) {655 of_node_put(np);656 /* XO 1.75 */657 data->new_proto = true;658 data->little_endian = true;659 } else if (ecver > 0x44) {660 /* XO 1 or 1.5 with a new EC firmware. */661 data->new_proto = true;662 } else if (ecver < 0x44) {663 /*664 * We've seen a number of EC protocol changes; this driver665 * requires the latest EC protocol, supported by 0x44 and above.666 */667 printk(KERN_NOTICE "OLPC EC version 0x%02x too old for "668 "battery driver.\n", ecver);669 return -ENXIO;670 }671 672 ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &status, 1);673 if (ret)674 return ret;675 676 /* Ignore the status. It doesn't actually matter */677 678 ac_psy_cfg.of_node = pdev->dev.of_node;679 ac_psy_cfg.drv_data = data;680 681 data->olpc_ac = devm_power_supply_register(&pdev->dev, &olpc_ac_desc,682 &ac_psy_cfg);683 if (IS_ERR(data->olpc_ac))684 return PTR_ERR(data->olpc_ac);685 686 if (of_device_is_compatible(pdev->dev.of_node, "olpc,xo1.5-battery")) {687 /* XO-1.5 */688 olpc_bat_desc.properties = olpc_xo15_bat_props;689 olpc_bat_desc.num_properties = ARRAY_SIZE(olpc_xo15_bat_props);690 } else {691 /* XO-1 */692 olpc_bat_desc.properties = olpc_xo1_bat_props;693 olpc_bat_desc.num_properties = ARRAY_SIZE(olpc_xo1_bat_props);694 }695 696 bat_psy_cfg.of_node = pdev->dev.of_node;697 bat_psy_cfg.drv_data = data;698 bat_psy_cfg.attr_grp = olpc_bat_sysfs_groups;699 700 data->olpc_bat = devm_power_supply_register(&pdev->dev, &olpc_bat_desc,701 &bat_psy_cfg);702 if (IS_ERR(data->olpc_bat))703 return PTR_ERR(data->olpc_bat);704 705 if (olpc_ec_wakeup_available()) {706 device_set_wakeup_capable(&data->olpc_ac->dev, true);707 device_set_wakeup_capable(&data->olpc_bat->dev, true);708 }709 710 return 0;711}712 713static const struct of_device_id olpc_battery_ids[] = {714 { .compatible = "olpc,xo1-battery" },715 { .compatible = "olpc,xo1.5-battery" },716 {}717};718MODULE_DEVICE_TABLE(of, olpc_battery_ids);719 720static struct platform_driver olpc_battery_driver = {721 .driver = {722 .name = "olpc-battery",723 .of_match_table = olpc_battery_ids,724 },725 .probe = olpc_battery_probe,726 .suspend = olpc_battery_suspend,727};728 729module_platform_driver(olpc_battery_driver);730 731MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");732MODULE_LICENSE("GPL");733MODULE_DESCRIPTION("Battery driver for One Laptop Per Child 'XO' machine");734