Signed-off-by: Andres Salomon
---
drivers/power/olpc_battery.c | 413 +++++++++++++++++++++++++----------------
1 files changed, 252 insertions(+), 161 deletions(-)

diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c
index af7a231..419aca2 100644
--- a/drivers/power/olpc_battery.c
+++ b/drivers/power/olpc_battery.c
@@ -50,216 +50,309 @@
* Power
************************************************** *******************/

-static int olpc_ac_get_prop(struct power_supply *psy,
- enum power_supply_property psp,
- union power_supply_propval *val)
+static ssize_t olpc_ac_is_online(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- int ret = 0;
+ int ret;
uint8_t status;

- switch (psp) {
- case POWER_SUPPLY_PROP_ONLINE:
- ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &status, 1);
- if (ret)
- return ret;
-
- val->intval = !!(status & BAT_STAT_AC);
- break;
- default:
- ret = -EINVAL;
- break;
- }
+ ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &status, 1);
+ if (!ret)
+ sprintf(buf, "%d\n", !!(status & BAT_STAT_AC));
return ret;
}

-static enum power_supply_property olpc_ac_props[] = {
- POWER_SUPPLY_PROP_ONLINE,
+static struct device_attribute olpc_ac_props[] = {
+ POWER_SUPPLY_ONLINE(olpc_ac_is_online),
+ POWER_SUPPLY_END
};

static struct power_supply olpc_ac = {
.name = "olpc-ac",
.type = POWER_SUPPLY_TYPE_MAINS,
- .properties = olpc_ac_props,
- .num_properties = ARRAY_SIZE(olpc_ac_props),
- .get_property = olpc_ac_get_prop,
+ .props = (struct device_attribute **) &olpc_ac_props,
};

/************************************************** *******************
* Battery properties
************************************************** *******************/
-static int olpc_bat_get_property(struct power_supply *psy,
- enum power_supply_property psp,
- union power_supply_propval *val)
+static ssize_t olpc_bat_get_status(uint8_t *status)
{
- int ret = 0;
- int16_t ec_word;
- uint8_t ec_byte;
+ int ret;

- ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &ec_byte, 1);
+ ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, status, 1);
if (ret)
return ret;

+ if (!(*status & BAT_STAT_PRESENT))
+ ret = -ENODEV;
+
/* Theoretically there's a race here -- the battery could be
removed immediately after we check whether it's present, and
then we query for some other property of the now-absent battery.
It doesn't matter though -- the EC will return the last-known
information, and it's as if we just ran that _little_ bit faster
and managed to read it out before the battery went away. */
- if (!(ec_byte & BAT_STAT_PRESENT) && psp != POWER_SUPPLY_PROP_PRESENT)
- return -ENODEV;
-
- switch (psp) {
- case POWER_SUPPLY_PROP_STATUS:
- if (olpc_platform_info.ecver > 0x44) {
- if (ec_byte & BAT_STAT_CHARGING)
- val->intval = POWER_SUPPLY_STATUS_CHARGING;
- else if (ec_byte & BAT_STAT_DISCHARGING)
- val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
- else if (ec_byte & BAT_STAT_FULL)
- val->intval = POWER_SUPPLY_STATUS_FULL;
- else /* er,... */
- val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
- } else {
- /* Older EC didn't report charge/discharge bits */
- if (!(ec_byte & BAT_STAT_AC)) /* No AC means discharging */
- val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
- else if (ec_byte & BAT_STAT_FULL)
- val->intval = POWER_SUPPLY_STATUS_FULL;
- else /* Not _necessarily_ true but EC doesn't tell all yet */
- val->intval = POWER_SUPPLY_STATUS_CHARGING;
- break;
- }
- case POWER_SUPPLY_PROP_PRESENT:
- val->intval = !!(ec_byte & BAT_STAT_PRESENT);
- break;

- case POWER_SUPPLY_PROP_HEALTH:
- if (ec_byte & BAT_STAT_DESTROY)
- val->intval = POWER_SUPPLY_HEALTH_DEAD;
- else {
- ret = olpc_ec_cmd(EC_BAT_ERRCODE, NULL, 0, &ec_byte, 1);
- if (ret)
- return ret;
-
- switch (ec_byte) {
- case 0:
- val->intval = POWER_SUPPLY_HEALTH_GOOD;
- break;
-
- case BAT_ERR_OVERTEMP:
- val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
- break;
-
- case BAT_ERR_OVERVOLTAGE:
- val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
- break;
-
- case BAT_ERR_INFOFAIL:
- case BAT_ERR_OUT_OF_CONTROL:
- case BAT_ERR_ID_FAIL:
- case BAT_ERR_ACR_FAIL:
- val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
- break;
-
- default:
- /* Eep. We don't know this failure code */
- return -EIO;
- }
- }
- break;
+ return ret;
+}

- case POWER_SUPPLY_PROP_MANUFACTURER:
- ec_byte = BAT_ADDR_MFR_TYPE;
- ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
+static ssize_t olpc_bat_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ uint8_t ec_byte;
+
+ ret = olpc_bat_get_status(&ec_byte);
+ if (ret)
+ return ret;
+
+ if (olpc_platform_info.ecver > 0x44) {
+ if (ec_byte & BAT_STAT_CHARGING)
+ ret = POWER_SUPPLY_STATUS_CHARGING;
+ else if (ec_byte & BAT_STAT_DISCHARGING)
+ ret = POWER_SUPPLY_STATUS_DISCHARGING;
+ else if (ec_byte & BAT_STAT_FULL)
+ ret = POWER_SUPPLY_STATUS_FULL;
+ else /* er,... */
+ ret = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ } else {
+ /* Older EC didn't report charge/discharge bits */
+ if (!(ec_byte & BAT_STAT_AC)) /* No AC means discharging */
+ ret = POWER_SUPPLY_STATUS_DISCHARGING;
+ else if (ec_byte & BAT_STAT_FULL)
+ ret = POWER_SUPPLY_STATUS_FULL;
+ else /* Not _necessarily_ true but EC doesn't tell all yet */
+ ret = POWER_SUPPLY_STATUS_CHARGING;
+ }
+
+ return power_supply_status_str(ret, buf);
+}
+
+static ssize_t olpc_bat_present(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ uint8_t ec_byte;
+
+ ret = olpc_bat_get_status(&ec_byte);
+ if (ret && ret != -ENODEV)
+ return ret;
+
+ return sprintf(buf, "%d\n", !!(ec_byte & BAT_STAT_PRESENT));
+}
+
+static ssize_t olpc_bat_health(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ uint8_t ec_byte;
+
+ ret = olpc_bat_get_status(&ec_byte);
+ if (ret)
+ return ret;
+
+ if (ec_byte & BAT_STAT_DESTROY)
+ ret = POWER_SUPPLY_HEALTH_DEAD;
+ else {
+ ret = olpc_ec_cmd(EC_BAT_ERRCODE, NULL, 0, &ec_byte, 1);
if (ret)
return ret;

- switch (ec_byte >> 4) {
- case 1:
- val->strval = "Gold Peak";
+ switch (ec_byte) {
+ case 0:
+ ret = POWER_SUPPLY_HEALTH_GOOD;
break;
- case 2:
- val->strval = "BYD";
- break;
- default:
- val->strval = "Unknown";
+
+ case BAT_ERR_OVERTEMP:
+ ret = POWER_SUPPLY_HEALTH_OVERHEAT;
break;
- }
- break;
- case POWER_SUPPLY_PROP_TECHNOLOGY:
- ec_byte = BAT_ADDR_MFR_TYPE;
- ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
- if (ret)
- return ret;

- switch (ec_byte & 0xf) {
- case 1:
- val->intval = POWER_SUPPLY_TECHNOLOGY_NiMH;
+ case BAT_ERR_OVERVOLTAGE:
+ ret = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
break;
- case 2:
- val->intval = POWER_SUPPLY_TECHNOLOGY_LiFe;
+
+ case BAT_ERR_INFOFAIL:
+ case BAT_ERR_OUT_OF_CONTROL:
+ case BAT_ERR_ID_FAIL:
+ case BAT_ERR_ACR_FAIL:
+ ret = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
break;
+
default:
- val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
- break;
+ /* Eep. We don't know this failure code */
+ return -EIO;
}
- break;
- case POWER_SUPPLY_PROP_VOLTAGE_AVG:
- ret = olpc_ec_cmd(EC_BAT_VOLTAGE, NULL, 0, (void *)&ec_word, 2);
- if (ret)
- return ret;
+ }

- ec_word = be16_to_cpu(ec_word);
- val->intval = ec_word * 9760L / 32;
- break;
- case POWER_SUPPLY_PROP_CURRENT_AVG:
- ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2);
- if (ret)
- return ret;
+ return power_supply_health_str(ret, buf);
+}
+
+static ssize_t olpc_bat_manufacturer(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ uint8_t ec_byte;
+
+ ret = olpc_bat_get_status(&ec_byte);
+ if (ret)
+ return ret;
+
+ ec_byte = BAT_ADDR_MFR_TYPE;
+ ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
+ if (ret)
+ return ret;

- ec_word = be16_to_cpu(ec_word);
- val->intval = ec_word * 15625L / 120;
+ switch (ec_byte >> 4) {
+ case 1:
+ strcpy(buf, "Gold Peak");
break;
- case POWER_SUPPLY_PROP_CAPACITY:
- ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &ec_byte, 1);
- if (ret)
- return ret;
- val->intval = ec_byte;
+ case 2:
+ strcpy(buf, "BYD");
break;
- case POWER_SUPPLY_PROP_TEMP:
- ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);
- if (ret)
- return ret;
- ec_word = be16_to_cpu(ec_word);
- val->intval = ec_word * 100 / 256;
+ default:
+ strcpy(buf, "Unknown");
break;
- case POWER_SUPPLY_PROP_TEMP_AMBIENT:
- ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2);
- if (ret)
- return ret;
+ }
+
+ return ret;
+}
+
+static ssize_t olpc_bat_technology(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ uint8_t ec_byte;

- ec_word = be16_to_cpu(ec_word);
- val->intval = ec_word * 100 / 256;
+ ret = olpc_bat_get_status(&ec_byte);
+ if (ret)
+ return ret;
+
+ ec_byte = BAT_ADDR_MFR_TYPE;
+ ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
+ if (ret)
+ return ret;
+
+ switch (ec_byte & 0xf) {
+ case 1:
+ ret = POWER_SUPPLY_TECHNOLOGY_NiMH;
+ break;
+ case 2:
+ ret = POWER_SUPPLY_TECHNOLOGY_LiFe;
break;
default:
- ret = -EINVAL;
+ ret = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
break;
}

- return ret;
+ return power_supply_technology_str(ret, buf);
+}
+
+static ssize_t olpc_bat_voltage_avg(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ uint8_t ec_byte;
+ uint16_t ec_word;
+
+ ret = olpc_bat_get_status(&ec_byte);
+ if (ret)
+ return ret;
+
+ ret = olpc_ec_cmd(EC_BAT_VOLTAGE, NULL, 0, (void *) &ec_word, 2);
+ if (ret)
+ return ret;
+
+ ec_word = be16_to_cpu(ec_word);
+ return sprintf(buf, "%d\n", ec_word * 9760L / 32);
+}
+
+static ssize_t olpc_bat_current_avg(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ uint8_t ec_byte;
+ uint16_t ec_word;
+
+ ret = olpc_bat_get_status(&ec_byte);
+ if (ret)
+ return ret;
+
+ ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *) &ec_word, 2);
+ if (ret)
+ return ret;
+
+ ec_word = be16_to_cpu(ec_word);
+ return sprintf(buf, "%d\n", ec_word * 15625L / 120);
+}
+
+static ssize_t olpc_bat_capacity(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ uint8_t ec_byte;
+
+ ret = olpc_bat_get_status(&ec_byte);
+ if (ret)
+ return ret;
+
+ ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &ec_byte, 1);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%d\n", ec_byte);
+}
+
+static ssize_t olpc_bat_temp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ uint8_t ec_byte;
+ uint16_t ec_word;
+
+ ret = olpc_bat_get_status(&ec_byte);
+ if (ret)
+ return ret;
+
+ ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *) &ec_word, 2);
+ if (ret)
+ return ret;
+
+ ec_word = be16_to_cpu(ec_word);
+ return sprintf(buf, "%d\n", ec_word * 100 / 256);
+}
+
+static ssize_t olpc_bat_temp_ambient(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ uint8_t ec_byte;
+ uint16_t ec_word;
+
+ ret = olpc_bat_get_status(&ec_byte);
+ if (ret)
+ return ret;
+
+ ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2);
+ if (ret)
+ return ret;
+
+ ec_word = be16_to_cpu(ec_word);
+ return sprintf(buf, "%d\n", ec_word * 100 / 256);
}

-static enum power_supply_property olpc_bat_props[] = {
- POWER_SUPPLY_PROP_STATUS,
- POWER_SUPPLY_PROP_PRESENT,
- POWER_SUPPLY_PROP_HEALTH,
- POWER_SUPPLY_PROP_TECHNOLOGY,
- POWER_SUPPLY_PROP_VOLTAGE_AVG,
- POWER_SUPPLY_PROP_CURRENT_AVG,
- POWER_SUPPLY_PROP_CAPACITY,
- POWER_SUPPLY_PROP_TEMP,
- POWER_SUPPLY_PROP_TEMP_AMBIENT,
- POWER_SUPPLY_PROP_MANUFACTURER,
+static struct device_attribute olpc_bat_props[] = {
+ POWER_SUPPLY_STATUS(olpc_bat_status),
+ POWER_SUPPLY_PRESENT(olpc_bat_present),
+ POWER_SUPPLY_HEALTH(olpc_bat_health),
+ POWER_SUPPLY_TECHNOLOGY(olpc_bat_technology),
+ POWER_SUPPLY_VOLT_AVG(olpc_bat_voltage_avg),
+ POWER_SUPPLY_CURR_AVG(olpc_bat_current_avg),
+ POWER_SUPPLY_CAPACITY(olpc_bat_capacity),
+ POWER_SUPPLY_TEMP(olpc_bat_temp),
+ POWER_SUPPLY_TEMP_AMB(olpc_bat_temp_ambient),
+ POWER_SUPPLY_MFR(olpc_bat_manufacturer),
+ POWER_SUPPLY_END
};

/************************************************** *******************
@@ -269,9 +362,7 @@ static enum power_supply_property olpc_bat_props[] = {
static struct platform_device *bat_pdev;

static struct power_supply olpc_bat = {
- .properties = olpc_bat_props,
- .num_properties = ARRAY_SIZE(olpc_bat_props),
- .get_property = olpc_bat_get_property,
+ .props = (struct device_attribute **) &olpc_bat_props,
.use_for_apm = 1,
};

--
1.5.3.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/