Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Battery driver for One Laptop Per Child board.
0004  *
0005  *  Copyright © 2006-2010  David Woodhouse <dwmw2@infradead.org>
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    /* uint16_t,    *9.76/32,    mV   */
0023 #define EC_BAT_CURRENT  0x11    /* int16_t, *15.625/120, mA   */
0024 #define EC_BAT_ACR  0x12    /* int16_t, *6250/15,    µAh  */
0025 #define EC_BAT_TEMP 0x13    /* uint16_t,    *100/256,   °C  */
0026 #define EC_AMB_TEMP 0x14    /* uint16_t,    *100/256,   °C  */
0027 #define EC_BAT_STATUS   0x15    /* uint8_t, bitmask */
0028 #define EC_BAT_SOC  0x16    /* uint8_t, percentage */
0029 #define EC_BAT_SERIAL   0x17    /* uint8_t[6] */
0030 #define EC_BAT_EEPROM   0x18    /* uint8_t adr as input, uint8_t output */
0031 #define EC_BAT_ERRCODE  0x1f    /* uint8_t, bitmask */
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  *      Power
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 /* er,... */
0109             val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
0110     } else {
0111         /* Older EC didn't report charge/discharge bits */
0112         if (!(ec_byte & BAT_STAT_AC)) /* No AC means discharging */
0113             val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
0114         else if (ec_byte & BAT_STAT_FULL)
0115             val->intval = POWER_SUPPLY_STATUS_FULL;
0116         else /* Not _necessarily_ true but EC doesn't tell all yet */
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         /* Eep. We don't know this failure code */
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: /* Gold Peak */
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: /* Gold Peak, fall through */
0241         case 2: /* BYD */
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: /* Gold Peak */
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: /* Gold Peak */
0306             val->intval = 6400000;
0307             break;
0308         case 2: /* BYD */
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  *      Battery properties
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     /* Theoretically there's a race here -- the battery could be
0349        removed immediately after we check whether it's present, and
0350        then we query for some other property of the now-absent battery.
0351        It doesn't matter though -- the EC will return the last-known
0352        information, and it's as if we just ran that _little_ bit faster
0353        and managed to read it out before the battery went away. */
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 /* XO-1.5 does not have ambient temperature property */
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 /* EEPROM reading goes completely around the power_supply API, sadly */
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 /* Allow userspace to see the specific error value pulled from the EC */
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  *      Initialisation
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     /* See if the EC is already there and get the EC revision */
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         /* XO 1.75 */
0657         data->new_proto = true;
0658         data->little_endian = true;
0659     } else if (ecver > 0x44) {
0660         /* XO 1 or 1.5 with a new EC firmware. */
0661         data->new_proto = true;
0662     } else if (ecver < 0x44) {
0663         /*
0664          * We've seen a number of EC protocol changes; this driver
0665          * requires the latest EC protocol, supported by 0x44 and above.
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     /* Ignore the status. It doesn't actually matter */
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         /* XO-1.5 */
0688         olpc_bat_desc.properties = olpc_xo15_bat_props;
0689         olpc_bat_desc.num_properties = ARRAY_SIZE(olpc_xo15_bat_props);
0690     } else {
0691         /* XO-1 */
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");