Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b14f7fb5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* git://git.infradead.org/battery-2.6:
  power_supply: Sharp SL-6000 (tosa) batteries support
  power_supply: fix up CHARGE_COUNTER output to be more precise
  power_supply: add CHARGE_COUNTER property and olpc_battery support for it
  power_supply: bump EC version check that we refuse to run with in olpc_battery
  power_supply: cleanup of the OLPC battery driver
  power_supply: add eeprom dump file to olpc_battery's sysfs
  power_supply: Support serial number in olpc_battery
parents 00e9028a 9fec6060
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -101,6 +101,10 @@ of charge when battery became full/empty". It also could mean "value of
charge when battery considered full/empty at given conditions (temperature,
age)". I.e. these attributes represents real thresholds, not design values.

CHARGE_COUNTER - the current charge counter (in µAh).  This could easily
be negative; there is no empty or full value.  It is only useful for
relative, time-based measurements.

ENERGY_FULL, ENERGY_EMPTY - same as above but for energy.

CAPACITY - capacity in percents.
+7 −0
Original line number Diff line number Diff line
@@ -49,6 +49,13 @@ config BATTERY_OLPC
	help
	  Say Y to enable support for the battery on the OLPC laptop.

config BATTERY_TOSA
	tristate "Sharp SL-6000 (tosa) battery"
	depends on MACH_TOSA && MFD_TC6393XB
	help
	  Say Y to enable support for the battery on the Sharp Zaurus
	  SL-6000 (tosa) models.

config BATTERY_PALMTX
	tristate "Palm T|X battery"
	depends on MACH_PALMTX
+1 −0
Original line number Diff line number Diff line
@@ -20,4 +20,5 @@ obj-$(CONFIG_APM_POWER) += apm_power.o
obj-$(CONFIG_BATTERY_DS2760)	+= ds2760_battery.o
obj-$(CONFIG_BATTERY_PMU)	+= pmu_battery.o
obj-$(CONFIG_BATTERY_OLPC)	+= olpc_battery.o
obj-$(CONFIG_BATTERY_TOSA)	+= tosa_battery.o
obj-$(CONFIG_BATTERY_PALMTX)	+= palmtx_battery.o
+197 −76
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@

#define EC_BAT_VOLTAGE	0x10	/* uint16_t,	*9.76/32,    mV   */
#define EC_BAT_CURRENT	0x11	/* int16_t,	*15.625/120, mA   */
#define EC_BAT_ACR	0x12
#define EC_BAT_ACR	0x12	/* int16_t,	*6250/15,    µAh  */
#define EC_BAT_TEMP	0x13	/* uint16_t,	*100/256,   °C  */
#define EC_AMB_TEMP	0x14	/* uint16_t,	*100/256,   °C  */
#define EC_BAT_STATUS	0x15	/* uint8_t,	bitmask */
@@ -84,32 +84,10 @@ static struct power_supply olpc_ac = {
	.get_property = olpc_ac_get_prop,
};

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

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

	/* 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;
static char bat_serial[17]; /* Ick */

	switch (psp) {
	case POWER_SUPPLY_PROP_STATUS:
static int olpc_bat_get_status(union power_supply_propval *val, uint8_t ec_byte)
{
	if (olpc_platform_info.ecver > 0x44) {
		if (ec_byte & BAT_STAT_CHARGING)
			val->intval = POWER_SUPPLY_STATUS_CHARGING;
@@ -127,16 +105,16 @@ static int olpc_bat_get_property(struct power_supply *psy,
			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 {
	return 0;
}

static int olpc_bat_get_health(union power_supply_propval *val)
{
	uint8_t ec_byte;
	int ret;

	ret = olpc_ec_cmd(EC_BAT_ERRCODE, NULL, 0, &ec_byte, 1);
	if (ret)
		return ret;
@@ -163,12 +141,17 @@ static int olpc_bat_get_property(struct power_supply *psy,

	default:
		/* Eep. We don't know this failure code */
				return -EIO;
		ret = -EIO;
	}

	return ret;
}
		break;

	case POWER_SUPPLY_PROP_MANUFACTURER:
static int olpc_bat_get_mfr(union power_supply_propval *val)
{
	uint8_t ec_byte;
	int ret;

	ec_byte = BAT_ADDR_MFR_TYPE;
	ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
	if (ret)
@@ -185,8 +168,15 @@ static int olpc_bat_get_property(struct power_supply *psy,
		val->strval = "Unknown";
		break;
	}
		break;
	case POWER_SUPPLY_PROP_TECHNOLOGY:

	return ret;
}

static int olpc_bat_get_tech(union power_supply_propval *val)
{
	uint8_t ec_byte;
	int ret;

	ec_byte = BAT_ADDR_MFR_TYPE;
	ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1, &ec_byte, 1);
	if (ret)
@@ -203,6 +193,64 @@ static int olpc_bat_get_property(struct power_supply *psy,
		val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
		break;
	}

	return ret;
}

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

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

	/* 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:
		ret = olpc_bat_get_status(val, ec_byte);
		if (ret)
			return ret;
		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_bat_get_health(val);
			if (ret)
				return ret;
		}
		break;

	case POWER_SUPPLY_PROP_MANUFACTURER:
		ret = olpc_bat_get_mfr(val);
		if (ret)
			return ret;
		break;
	case POWER_SUPPLY_PROP_TECHNOLOGY:
		ret = olpc_bat_get_tech(val);
		if (ret)
			return ret;
		break;
	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
		ret = olpc_ec_cmd(EC_BAT_VOLTAGE, NULL, 0, (void *)&ec_word, 2);
@@ -241,6 +289,22 @@ static int olpc_bat_get_property(struct power_supply *psy,
		ec_word = be16_to_cpu(ec_word);
		val->intval = ec_word * 100 / 256;
		break;
	case POWER_SUPPLY_PROP_CHARGE_COUNTER:
		ret = olpc_ec_cmd(EC_BAT_ACR, NULL, 0, (void *)&ec_word, 2);
		if (ret)
			return ret;

		ec_word = be16_to_cpu(ec_word);
		val->intval = ec_word * 6250 / 15;
		break;
	case POWER_SUPPLY_PROP_SERIAL_NUMBER:
		ret = olpc_ec_cmd(EC_BAT_SERIAL, NULL, 0, (void *)&ser_buf, 8);
		if (ret)
			return ret;

		sprintf(bat_serial, "%016llx", (long long)be64_to_cpu(ser_buf));
		val->strval = bat_serial;
		break;
	default:
		ret = -EINVAL;
		break;
@@ -260,6 +324,50 @@ static enum power_supply_property olpc_bat_props[] = {
	POWER_SUPPLY_PROP_TEMP,
	POWER_SUPPLY_PROP_TEMP_AMBIENT,
	POWER_SUPPLY_PROP_MANUFACTURER,
	POWER_SUPPLY_PROP_SERIAL_NUMBER,
	POWER_SUPPLY_PROP_CHARGE_COUNTER,
};

/* EEPROM reading goes completely around the power_supply API, sadly */

#define EEPROM_START	0x20
#define EEPROM_END	0x80
#define EEPROM_SIZE	(EEPROM_END - EEPROM_START)

static ssize_t olpc_bat_eeprom_read(struct kobject *kobj,
		struct bin_attribute *attr, char *buf, loff_t off, size_t count)
{
	uint8_t ec_byte;
	int ret, end;

	if (off >= EEPROM_SIZE)
		return 0;
	if (off + count > EEPROM_SIZE)
		count = EEPROM_SIZE - off;

	end = EEPROM_START + off + count;
	for (ec_byte = EEPROM_START + off; ec_byte < end; ec_byte++) {
		ret = olpc_ec_cmd(EC_BAT_EEPROM, &ec_byte, 1,
				&buf[ec_byte - EEPROM_START], 1);
		if (ret) {
			printk(KERN_ERR "olpc-battery:  EC command "
					"EC_BAT_EEPROM @ 0x%x failed -"
					" %d!\n", ec_byte, ret);
			return -EIO;
		}
	}

	return count;
}

static struct bin_attribute olpc_bat_eeprom = {
	.attr = {
		.name = "eeprom",
		.mode = S_IRUGO,
		.owner = THIS_MODULE,
	},
	.size = 0,
	.read = olpc_bat_eeprom_read,
};

/*********************************************************************
@@ -290,8 +398,14 @@ static int __init olpc_bat_init(void)

	if (!olpc_platform_info.ecver)
		return -ENXIO;
	if (olpc_platform_info.ecver < 0x43) {
		printk(KERN_NOTICE "OLPC EC version 0x%02x too old for battery driver.\n", olpc_platform_info.ecver);

	/*
	 * We've seen a number of EC protocol changes; this driver requires
	 * the latest EC protocol, supported by 0x44 and above.
	 */
	if (olpc_platform_info.ecver < 0x44) {
		printk(KERN_NOTICE "OLPC EC version 0x%02x too old for "
			"battery driver.\n", olpc_platform_info.ecver);
		return -ENXIO;
	}

@@ -315,8 +429,14 @@ static int __init olpc_bat_init(void)
	if (ret)
		goto battery_failed;

	ret = device_create_bin_file(olpc_bat.dev, &olpc_bat_eeprom);
	if (ret)
		goto eeprom_failed;

	goto success;

eeprom_failed:
	power_supply_unregister(&olpc_bat);
battery_failed:
	power_supply_unregister(&olpc_ac);
ac_failed:
@@ -327,6 +447,7 @@ static int __init olpc_bat_init(void)

static void __exit olpc_bat_exit(void)
{
	device_remove_bin_file(olpc_bat.dev, &olpc_bat_eeprom);
	power_supply_unregister(&olpc_bat);
	power_supply_unregister(&olpc_ac);
	platform_device_unregister(bat_pdev);
+1 −0
Original line number Diff line number Diff line
@@ -99,6 +99,7 @@ static struct device_attribute power_supply_attrs[] = {
	POWER_SUPPLY_ATTR(charge_empty),
	POWER_SUPPLY_ATTR(charge_now),
	POWER_SUPPLY_ATTR(charge_avg),
	POWER_SUPPLY_ATTR(charge_counter),
	POWER_SUPPLY_ATTR(energy_full_design),
	POWER_SUPPLY_ATTR(energy_empty_design),
	POWER_SUPPLY_ATTR(energy_full),
Loading