0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/mod_devicetable.h>
0011 #include <linux/types.h>
0012 #include <linux/err.h>
0013 #include <linux/device.h>
0014 #include <linux/of.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/power_supply.h>
0017 #include <linux/jiffies.h>
0018 #include <linux/sched.h>
0019 #include <linux/olpc-ec.h>
0020
0021
0022 #define EC_BAT_VOLTAGE 0x10
0023 #define EC_BAT_CURRENT 0x11
0024 #define EC_BAT_ACR 0x12
0025 #define EC_BAT_TEMP 0x13
0026 #define EC_AMB_TEMP 0x14
0027 #define EC_BAT_STATUS 0x15
0028 #define EC_BAT_SOC 0x16
0029 #define EC_BAT_SERIAL 0x17
0030 #define EC_BAT_EEPROM 0x18
0031 #define EC_BAT_ERRCODE 0x1f
0032
0033 #define BAT_STAT_PRESENT 0x01
0034 #define BAT_STAT_FULL 0x02
0035 #define BAT_STAT_LOW 0x04
0036 #define BAT_STAT_DESTROY 0x08
0037 #define BAT_STAT_AC 0x10
0038 #define BAT_STAT_CHARGING 0x20
0039 #define BAT_STAT_DISCHARGING 0x40
0040 #define BAT_STAT_TRICKLE 0x80
0041
0042 #define BAT_ERR_INFOFAIL 0x02
0043 #define BAT_ERR_OVERVOLTAGE 0x04
0044 #define BAT_ERR_OVERTEMP 0x05
0045 #define BAT_ERR_GAUGESTOP 0x06
0046 #define BAT_ERR_OUT_OF_CONTROL 0x07
0047 #define BAT_ERR_ID_FAIL 0x09
0048 #define BAT_ERR_ACR_FAIL 0x10
0049
0050 #define BAT_ADDR_MFR_TYPE 0x5F
0051
0052 struct olpc_battery_data {
0053 struct power_supply *olpc_ac;
0054 struct power_supply *olpc_bat;
0055 char bat_serial[17];
0056 bool new_proto;
0057 bool little_endian;
0058 };
0059
0060
0061
0062
0063
0064 static int olpc_ac_get_prop(struct power_supply *psy,
0065 enum power_supply_property psp,
0066 union power_supply_propval *val)
0067 {
0068 int ret = 0;
0069 uint8_t status;
0070
0071 switch (psp) {
0072 case POWER_SUPPLY_PROP_ONLINE:
0073 ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &status, 1);
0074 if (ret)
0075 return ret;
0076
0077 val->intval = !!(status & BAT_STAT_AC);
0078 break;
0079 default:
0080 ret = -EINVAL;
0081 break;
0082 }
0083 return ret;
0084 }
0085
0086 static enum power_supply_property olpc_ac_props[] = {
0087 POWER_SUPPLY_PROP_ONLINE,
0088 };
0089
0090 static const struct power_supply_desc olpc_ac_desc = {
0091 .name = "olpc_ac",
0092 .type = POWER_SUPPLY_TYPE_MAINS,
0093 .properties = olpc_ac_props,
0094 .num_properties = ARRAY_SIZE(olpc_ac_props),
0095 .get_property = olpc_ac_get_prop,
0096 };
0097
0098 static int olpc_bat_get_status(struct olpc_battery_data *data,
0099 union power_supply_propval *val, uint8_t ec_byte)
0100 {
0101 if (data->new_proto) {
0102 if (ec_byte & (BAT_STAT_CHARGING | BAT_STAT_TRICKLE))
0103 val->intval = POWER_SUPPLY_STATUS_CHARGING;
0104 else if (ec_byte & BAT_STAT_DISCHARGING)
0105 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
0106 else if (ec_byte & BAT_STAT_FULL)
0107 val->intval = POWER_SUPPLY_STATUS_FULL;
0108 else
0109 val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
0110 } else {
0111
0112 if (!(ec_byte & BAT_STAT_AC))
0113 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
0114 else if (ec_byte & BAT_STAT_FULL)
0115 val->intval = POWER_SUPPLY_STATUS_FULL;
0116 else
0117 val->intval = POWER_SUPPLY_STATUS_CHARGING;
0118 }
0119
0120 return 0;
0121 }
0122
0123 static int olpc_bat_get_health(union power_supply_propval *val)
0124 {
0125 uint8_t ec_byte;
0126 int ret;
0127
0128 ret = olpc_ec_cmd(EC_BAT_ERRCODE, NULL, 0, &ec_byte, 1);
0129 if (ret)
0130 return ret;
0131
0132 switch (ec_byte) {
0133 case 0:
0134 val->intval = POWER_SUPPLY_HEALTH_GOOD;
0135 break;
0136
0137 case BAT_ERR_OVERTEMP:
0138 val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
0139 break;
0140
0141 case BAT_ERR_OVERVOLTAGE:
0142 val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
0143 break;
0144
0145 case BAT_ERR_INFOFAIL:
0146 case BAT_ERR_OUT_OF_CONTROL:
0147 case BAT_ERR_ID_FAIL:
0148 case BAT_ERR_ACR_FAIL:
0149 val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
0150 break;
0151
0152 default:
0153
0154 ret = -EIO;
0155 }
0156
0157 return ret;
0158 }
0159
0160 static int olpc_bat_get_mfr(union power_supply_propval *val)
0161 {
0162 uint8_t ec_byte;
0163 int ret;
0164
0165 ec_byte = BAT_ADDR_MFR_TYPE;
0166 ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
0167 if (ret)
0168 return ret;
0169
0170 switch (ec_byte >> 4) {
0171 case 1:
0172 val->strval = "Gold Peak";
0173 break;
0174 case 2:
0175 val->strval = "BYD";
0176 break;
0177 default:
0178 val->strval = "Unknown";
0179 break;
0180 }
0181
0182 return ret;
0183 }
0184
0185 static int olpc_bat_get_tech(union power_supply_propval *val)
0186 {
0187 uint8_t ec_byte;
0188 int ret;
0189
0190 ec_byte = BAT_ADDR_MFR_TYPE;
0191 ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
0192 if (ret)
0193 return ret;
0194
0195 switch (ec_byte & 0xf) {
0196 case 1:
0197 val->intval = POWER_SUPPLY_TECHNOLOGY_NiMH;
0198 break;
0199 case 2:
0200 val->intval = POWER_SUPPLY_TECHNOLOGY_LiFe;
0201 break;
0202 default:
0203 val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
0204 break;
0205 }
0206
0207 return ret;
0208 }
0209
0210 static int olpc_bat_get_charge_full_design(union power_supply_propval *val)
0211 {
0212 uint8_t ec_byte;
0213 union power_supply_propval tech;
0214 int ret, mfr;
0215
0216 ret = olpc_bat_get_tech(&tech);
0217 if (ret)
0218 return ret;
0219
0220 ec_byte = BAT_ADDR_MFR_TYPE;
0221 ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
0222 if (ret)
0223 return ret;
0224
0225 mfr = ec_byte >> 4;
0226
0227 switch (tech.intval) {
0228 case POWER_SUPPLY_TECHNOLOGY_NiMH:
0229 switch (mfr) {
0230 case 1:
0231 val->intval = 3000000*.8;
0232 break;
0233 default:
0234 return -EIO;
0235 }
0236 break;
0237
0238 case POWER_SUPPLY_TECHNOLOGY_LiFe:
0239 switch (mfr) {
0240 case 1:
0241 case 2:
0242 val->intval = 2800000;
0243 break;
0244 default:
0245 return -EIO;
0246 }
0247 break;
0248
0249 default:
0250 return -EIO;
0251 }
0252
0253 return ret;
0254 }
0255
0256 static int olpc_bat_get_charge_now(union power_supply_propval *val)
0257 {
0258 uint8_t soc;
0259 union power_supply_propval full;
0260 int ret;
0261
0262 ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &soc, 1);
0263 if (ret)
0264 return ret;
0265
0266 ret = olpc_bat_get_charge_full_design(&full);
0267 if (ret)
0268 return ret;
0269
0270 val->intval = soc * (full.intval / 100);
0271 return 0;
0272 }
0273
0274 static int olpc_bat_get_voltage_max_design(union power_supply_propval *val)
0275 {
0276 uint8_t ec_byte;
0277 union power_supply_propval tech;
0278 int mfr;
0279 int ret;
0280
0281 ret = olpc_bat_get_tech(&tech);
0282 if (ret)
0283 return ret;
0284
0285 ec_byte = BAT_ADDR_MFR_TYPE;
0286 ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
0287 if (ret)
0288 return ret;
0289
0290 mfr = ec_byte >> 4;
0291
0292 switch (tech.intval) {
0293 case POWER_SUPPLY_TECHNOLOGY_NiMH:
0294 switch (mfr) {
0295 case 1:
0296 val->intval = 6000000;
0297 break;
0298 default:
0299 return -EIO;
0300 }
0301 break;
0302
0303 case POWER_SUPPLY_TECHNOLOGY_LiFe:
0304 switch (mfr) {
0305 case 1:
0306 val->intval = 6400000;
0307 break;
0308 case 2:
0309 val->intval = 6500000;
0310 break;
0311 default:
0312 return -EIO;
0313 }
0314 break;
0315
0316 default:
0317 return -EIO;
0318 }
0319
0320 return ret;
0321 }
0322
0323 static u16 ecword_to_cpu(struct olpc_battery_data *data, u16 ec_word)
0324 {
0325 if (data->little_endian)
0326 return le16_to_cpu((__force __le16)ec_word);
0327 else
0328 return be16_to_cpu((__force __be16)ec_word);
0329 }
0330
0331
0332
0333
0334 static int olpc_bat_get_property(struct power_supply *psy,
0335 enum power_supply_property psp,
0336 union power_supply_propval *val)
0337 {
0338 struct olpc_battery_data *data = power_supply_get_drvdata(psy);
0339 int ret = 0;
0340 u16 ec_word;
0341 uint8_t ec_byte;
0342 __be64 ser_buf;
0343
0344 ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &ec_byte, 1);
0345 if (ret)
0346 return ret;
0347
0348
0349
0350
0351
0352
0353
0354 if (!(ec_byte & (BAT_STAT_PRESENT | BAT_STAT_TRICKLE)) &&
0355 psp != POWER_SUPPLY_PROP_PRESENT)
0356 return -ENODEV;
0357
0358 switch (psp) {
0359 case POWER_SUPPLY_PROP_STATUS:
0360 ret = olpc_bat_get_status(data, val, ec_byte);
0361 if (ret)
0362 return ret;
0363 break;
0364 case POWER_SUPPLY_PROP_CHARGE_TYPE:
0365 if (ec_byte & BAT_STAT_TRICKLE)
0366 val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
0367 else if (ec_byte & BAT_STAT_CHARGING)
0368 val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
0369 else
0370 val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
0371 break;
0372 case POWER_SUPPLY_PROP_PRESENT:
0373 val->intval = !!(ec_byte & (BAT_STAT_PRESENT |
0374 BAT_STAT_TRICKLE));
0375 break;
0376
0377 case POWER_SUPPLY_PROP_HEALTH:
0378 if (ec_byte & BAT_STAT_DESTROY)
0379 val->intval = POWER_SUPPLY_HEALTH_DEAD;
0380 else {
0381 ret = olpc_bat_get_health(val);
0382 if (ret)
0383 return ret;
0384 }
0385 break;
0386
0387 case POWER_SUPPLY_PROP_MANUFACTURER:
0388 ret = olpc_bat_get_mfr(val);
0389 if (ret)
0390 return ret;
0391 break;
0392 case POWER_SUPPLY_PROP_TECHNOLOGY:
0393 ret = olpc_bat_get_tech(val);
0394 if (ret)
0395 return ret;
0396 break;
0397 case POWER_SUPPLY_PROP_VOLTAGE_AVG:
0398 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
0399 ret = olpc_ec_cmd(EC_BAT_VOLTAGE, NULL, 0, (void *)&ec_word, 2);
0400 if (ret)
0401 return ret;
0402
0403 val->intval = ecword_to_cpu(data, ec_word) * 9760L / 32;
0404 break;
0405 case POWER_SUPPLY_PROP_CURRENT_AVG:
0406 case POWER_SUPPLY_PROP_CURRENT_NOW:
0407 ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2);
0408 if (ret)
0409 return ret;
0410
0411 val->intval = ecword_to_cpu(data, ec_word) * 15625L / 120;
0412 break;
0413 case POWER_SUPPLY_PROP_CAPACITY:
0414 ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &ec_byte, 1);
0415 if (ret)
0416 return ret;
0417 val->intval = ec_byte;
0418 break;
0419 case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
0420 if (ec_byte & BAT_STAT_FULL)
0421 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
0422 else if (ec_byte & BAT_STAT_LOW)
0423 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
0424 else
0425 val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
0426 break;
0427 case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
0428 ret = olpc_bat_get_charge_full_design(val);
0429 if (ret)
0430 return ret;
0431 break;
0432 case POWER_SUPPLY_PROP_CHARGE_NOW:
0433 ret = olpc_bat_get_charge_now(val);
0434 if (ret)
0435 return ret;
0436 break;
0437 case POWER_SUPPLY_PROP_TEMP:
0438 ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);
0439 if (ret)
0440 return ret;
0441
0442 val->intval = ecword_to_cpu(data, ec_word) * 10 / 256;
0443 break;
0444 case POWER_SUPPLY_PROP_TEMP_AMBIENT:
0445 ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2);
0446 if (ret)
0447 return ret;
0448
0449 val->intval = (int)ecword_to_cpu(data, ec_word) * 10 / 256;
0450 break;
0451 case POWER_SUPPLY_PROP_CHARGE_COUNTER:
0452 ret = olpc_ec_cmd(EC_BAT_ACR, NULL, 0, (void *)&ec_word, 2);
0453 if (ret)
0454 return ret;
0455
0456 val->intval = ecword_to_cpu(data, ec_word) * 6250 / 15;
0457 break;
0458 case POWER_SUPPLY_PROP_SERIAL_NUMBER:
0459 ret = olpc_ec_cmd(EC_BAT_SERIAL, NULL, 0, (void *)&ser_buf, 8);
0460 if (ret)
0461 return ret;
0462
0463 sprintf(data->bat_serial, "%016llx", (long long)be64_to_cpu(ser_buf));
0464 val->strval = data->bat_serial;
0465 break;
0466 case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
0467 ret = olpc_bat_get_voltage_max_design(val);
0468 if (ret)
0469 return ret;
0470 break;
0471 default:
0472 ret = -EINVAL;
0473 break;
0474 }
0475
0476 return ret;
0477 }
0478
0479 static enum power_supply_property olpc_xo1_bat_props[] = {
0480 POWER_SUPPLY_PROP_STATUS,
0481 POWER_SUPPLY_PROP_CHARGE_TYPE,
0482 POWER_SUPPLY_PROP_PRESENT,
0483 POWER_SUPPLY_PROP_HEALTH,
0484 POWER_SUPPLY_PROP_TECHNOLOGY,
0485 POWER_SUPPLY_PROP_VOLTAGE_AVG,
0486 POWER_SUPPLY_PROP_VOLTAGE_NOW,
0487 POWER_SUPPLY_PROP_CURRENT_AVG,
0488 POWER_SUPPLY_PROP_CURRENT_NOW,
0489 POWER_SUPPLY_PROP_CAPACITY,
0490 POWER_SUPPLY_PROP_CAPACITY_LEVEL,
0491 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
0492 POWER_SUPPLY_PROP_CHARGE_NOW,
0493 POWER_SUPPLY_PROP_TEMP,
0494 POWER_SUPPLY_PROP_TEMP_AMBIENT,
0495 POWER_SUPPLY_PROP_MANUFACTURER,
0496 POWER_SUPPLY_PROP_SERIAL_NUMBER,
0497 POWER_SUPPLY_PROP_CHARGE_COUNTER,
0498 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
0499 };
0500
0501
0502 static enum power_supply_property olpc_xo15_bat_props[] = {
0503 POWER_SUPPLY_PROP_STATUS,
0504 POWER_SUPPLY_PROP_CHARGE_TYPE,
0505 POWER_SUPPLY_PROP_PRESENT,
0506 POWER_SUPPLY_PROP_HEALTH,
0507 POWER_SUPPLY_PROP_TECHNOLOGY,
0508 POWER_SUPPLY_PROP_VOLTAGE_AVG,
0509 POWER_SUPPLY_PROP_VOLTAGE_NOW,
0510 POWER_SUPPLY_PROP_CURRENT_AVG,
0511 POWER_SUPPLY_PROP_CURRENT_NOW,
0512 POWER_SUPPLY_PROP_CAPACITY,
0513 POWER_SUPPLY_PROP_CAPACITY_LEVEL,
0514 POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
0515 POWER_SUPPLY_PROP_CHARGE_NOW,
0516 POWER_SUPPLY_PROP_TEMP,
0517 POWER_SUPPLY_PROP_MANUFACTURER,
0518 POWER_SUPPLY_PROP_SERIAL_NUMBER,
0519 POWER_SUPPLY_PROP_CHARGE_COUNTER,
0520 POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
0521 };
0522
0523
0524
0525 #define EEPROM_START 0x20
0526 #define EEPROM_END 0x80
0527 #define EEPROM_SIZE (EEPROM_END - EEPROM_START)
0528
0529 static ssize_t olpc_bat_eeprom_read(struct file *filp, struct kobject *kobj,
0530 struct bin_attribute *attr, char *buf, loff_t off, size_t count)
0531 {
0532 uint8_t ec_byte;
0533 int ret;
0534 int i;
0535
0536 for (i = 0; i < count; i++) {
0537 ec_byte = EEPROM_START + off + i;
0538 ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &buf[i], 1);
0539 if (ret) {
0540 pr_err("olpc-battery: "
0541 "EC_BAT_EEPROM cmd @ 0x%x failed - %d!\n",
0542 ec_byte, ret);
0543 return -EIO;
0544 }
0545 }
0546
0547 return count;
0548 }
0549
0550 static struct bin_attribute olpc_bat_eeprom = {
0551 .attr = {
0552 .name = "eeprom",
0553 .mode = S_IRUGO,
0554 },
0555 .size = EEPROM_SIZE,
0556 .read = olpc_bat_eeprom_read,
0557 };
0558
0559
0560
0561 static ssize_t olpc_bat_error_read(struct device *dev,
0562 struct device_attribute *attr, char *buf)
0563 {
0564 uint8_t ec_byte;
0565 ssize_t ret;
0566
0567 ret = olpc_ec_cmd(EC_BAT_ERRCODE, NULL, 0, &ec_byte, 1);
0568 if (ret < 0)
0569 return ret;
0570
0571 return sprintf(buf, "%d\n", ec_byte);
0572 }
0573
0574 static struct device_attribute olpc_bat_error = {
0575 .attr = {
0576 .name = "error",
0577 .mode = S_IRUGO,
0578 },
0579 .show = olpc_bat_error_read,
0580 };
0581
0582 static struct attribute *olpc_bat_sysfs_attrs[] = {
0583 &olpc_bat_error.attr,
0584 NULL
0585 };
0586
0587 static struct bin_attribute *olpc_bat_sysfs_bin_attrs[] = {
0588 &olpc_bat_eeprom,
0589 NULL
0590 };
0591
0592 static const struct attribute_group olpc_bat_sysfs_group = {
0593 .attrs = olpc_bat_sysfs_attrs,
0594 .bin_attrs = olpc_bat_sysfs_bin_attrs,
0595
0596 };
0597
0598 static const struct attribute_group *olpc_bat_sysfs_groups[] = {
0599 &olpc_bat_sysfs_group,
0600 NULL
0601 };
0602
0603
0604
0605
0606
0607 static struct power_supply_desc olpc_bat_desc = {
0608 .name = "olpc_battery",
0609 .get_property = olpc_bat_get_property,
0610 .use_for_apm = 1,
0611 };
0612
0613 static int olpc_battery_suspend(struct platform_device *pdev,
0614 pm_message_t state)
0615 {
0616 struct olpc_battery_data *data = platform_get_drvdata(pdev);
0617
0618 if (device_may_wakeup(&data->olpc_ac->dev))
0619 olpc_ec_wakeup_set(EC_SCI_SRC_ACPWR);
0620 else
0621 olpc_ec_wakeup_clear(EC_SCI_SRC_ACPWR);
0622
0623 if (device_may_wakeup(&data->olpc_bat->dev))
0624 olpc_ec_wakeup_set(EC_SCI_SRC_BATTERY | EC_SCI_SRC_BATSOC
0625 | EC_SCI_SRC_BATERR);
0626 else
0627 olpc_ec_wakeup_clear(EC_SCI_SRC_BATTERY | EC_SCI_SRC_BATSOC
0628 | EC_SCI_SRC_BATERR);
0629
0630 return 0;
0631 }
0632
0633 static int olpc_battery_probe(struct platform_device *pdev)
0634 {
0635 struct power_supply_config bat_psy_cfg = {};
0636 struct power_supply_config ac_psy_cfg = {};
0637 struct olpc_battery_data *data;
0638 struct device_node *np;
0639 uint8_t status;
0640 uint8_t ecver;
0641 int ret;
0642
0643 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
0644 if (!data)
0645 return -ENOMEM;
0646 platform_set_drvdata(pdev, data);
0647
0648
0649 ret = olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0, &ecver, 1);
0650 if (ret)
0651 return ret;
0652
0653 np = of_find_compatible_node(NULL, NULL, "olpc,xo1.75-ec");
0654 if (np) {
0655 of_node_put(np);
0656
0657 data->new_proto = true;
0658 data->little_endian = true;
0659 } else if (ecver > 0x44) {
0660
0661 data->new_proto = true;
0662 } else if (ecver < 0x44) {
0663
0664
0665
0666
0667 printk(KERN_NOTICE "OLPC EC version 0x%02x too old for "
0668 "battery driver.\n", ecver);
0669 return -ENXIO;
0670 }
0671
0672 ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &status, 1);
0673 if (ret)
0674 return ret;
0675
0676
0677
0678 ac_psy_cfg.of_node = pdev->dev.of_node;
0679 ac_psy_cfg.drv_data = data;
0680
0681 data->olpc_ac = devm_power_supply_register(&pdev->dev, &olpc_ac_desc,
0682 &ac_psy_cfg);
0683 if (IS_ERR(data->olpc_ac))
0684 return PTR_ERR(data->olpc_ac);
0685
0686 if (of_device_is_compatible(pdev->dev.of_node, "olpc,xo1.5-battery")) {
0687
0688 olpc_bat_desc.properties = olpc_xo15_bat_props;
0689 olpc_bat_desc.num_properties = ARRAY_SIZE(olpc_xo15_bat_props);
0690 } else {
0691
0692 olpc_bat_desc.properties = olpc_xo1_bat_props;
0693 olpc_bat_desc.num_properties = ARRAY_SIZE(olpc_xo1_bat_props);
0694 }
0695
0696 bat_psy_cfg.of_node = pdev->dev.of_node;
0697 bat_psy_cfg.drv_data = data;
0698 bat_psy_cfg.attr_grp = olpc_bat_sysfs_groups;
0699
0700 data->olpc_bat = devm_power_supply_register(&pdev->dev, &olpc_bat_desc,
0701 &bat_psy_cfg);
0702 if (IS_ERR(data->olpc_bat))
0703 return PTR_ERR(data->olpc_bat);
0704
0705 if (olpc_ec_wakeup_available()) {
0706 device_set_wakeup_capable(&data->olpc_ac->dev, true);
0707 device_set_wakeup_capable(&data->olpc_bat->dev, true);
0708 }
0709
0710 return 0;
0711 }
0712
0713 static const struct of_device_id olpc_battery_ids[] = {
0714 { .compatible = "olpc,xo1-battery" },
0715 { .compatible = "olpc,xo1.5-battery" },
0716 {}
0717 };
0718 MODULE_DEVICE_TABLE(of, olpc_battery_ids);
0719
0720 static struct platform_driver olpc_battery_driver = {
0721 .driver = {
0722 .name = "olpc-battery",
0723 .of_match_table = olpc_battery_ids,
0724 },
0725 .probe = olpc_battery_probe,
0726 .suspend = olpc_battery_suspend,
0727 };
0728
0729 module_platform_driver(olpc_battery_driver);
0730
0731 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
0732 MODULE_LICENSE("GPL");
0733 MODULE_DESCRIPTION("Battery driver for One Laptop Per Child 'XO' machine");