Exemple #1
0
static ssize_t ec_debugfs_cmd_write(struct file *file, const char __user *buf,
				    size_t size, loff_t *ppos)
{
	int i, m;
	unsigned char ec_cmd[EC_MAX_CMD_ARGS];
	unsigned int ec_cmd_int[EC_MAX_CMD_ARGS];
	char cmdbuf[64];
	int ec_cmd_bytes;

	mutex_lock(&ec_debugfs_cmd_lock);

	size = simple_write_to_buffer(cmdbuf, sizeof(cmdbuf), ppos, buf, size);

	m = sscanf(cmdbuf, "%x:%u %x %x %x %x %x", &ec_cmd_int[0],
		   &ec_debugfs_resp_bytes,
		   &ec_cmd_int[1], &ec_cmd_int[2], &ec_cmd_int[3],
		   &ec_cmd_int[4], &ec_cmd_int[5]);
	if (m < 2 || ec_debugfs_resp_bytes > EC_MAX_CMD_REPLY) {
		/* reset to prevent overflow on read */
		ec_debugfs_resp_bytes = 0;

		printk(KERN_DEBUG "olpc-ec: bad ec cmd:  "
		       "cmd:response-count [arg1 [arg2 ...]]\n");
		size = -EINVAL;
		goto out;
	}

	/* convert scanf'd ints to char */
	ec_cmd_bytes = m - 2;
	for (i = 0; i <= ec_cmd_bytes; i++)
		ec_cmd[i] = ec_cmd_int[i];

	printk(KERN_DEBUG "olpc-ec: debugfs cmd 0x%02x with %d args "
	       "%02x %02x %02x %02x %02x, want %d returns\n",
	       ec_cmd[0], ec_cmd_bytes, ec_cmd[1], ec_cmd[2], ec_cmd[3],
	       ec_cmd[4], ec_cmd[5], ec_debugfs_resp_bytes);

	olpc_ec_cmd(ec_cmd[0], (ec_cmd_bytes == 0) ? NULL : &ec_cmd[1],
		    ec_cmd_bytes, ec_debugfs_resp, ec_debugfs_resp_bytes);

	printk(KERN_DEBUG "olpc-ec: response "
	       "%02x %02x %02x %02x %02x %02x %02x %02x (%d bytes expected)\n",
	       ec_debugfs_resp[0], ec_debugfs_resp[1], ec_debugfs_resp[2],
	       ec_debugfs_resp[3], ec_debugfs_resp[4], ec_debugfs_resp[5],
	       ec_debugfs_resp[6], ec_debugfs_resp[7], ec_debugfs_resp_bytes);

out:
	mutex_unlock(&ec_debugfs_cmd_lock);
	return size;
}
Exemple #2
0
static int __init olpc_init(void)
{
	unsigned char *romsig;

	/* The ioremap check is dangerous; limit what we run it on */
	if (!is_geode() || geode_has_vsa2())
		return 0;

	spin_lock_init(&ec_lock);

	romsig = ioremap(0xffffffc0, 16);
	if (!romsig)
		return 0;

	if (strncmp(romsig, "CL1   Q", 7))
		goto unmap;
	if (strncmp(romsig+6, romsig+13, 3)) {
		printk(KERN_INFO "OLPC BIOS signature looks invalid.  "
				"Assuming not OLPC\n");
		goto unmap;
	}

	printk(KERN_INFO "OLPC board with OpenFirmware %.16s\n", romsig);
	olpc_platform_info.flags |= OLPC_F_PRESENT;

	/* get the platform revision */
	platform_detect();

	/* assume B1 and above models always have a DCON */
	if (olpc_board_at_least(olpc_board(0xb1)))
		olpc_platform_info.flags |= OLPC_F_DCON;

	/* get the EC revision */
	olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0,
			(unsigned char *) &olpc_platform_info.ecver, 1);

	/* check to see if the VSA exists */
	if (geode_has_vsa2())
		olpc_platform_info.flags |= OLPC_F_VSA;

	printk(KERN_INFO "OLPC board revision %s%X (EC=%x)\n",
			((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "",
			olpc_platform_info.boardrev >> 4,
			olpc_platform_info.ecver);

unmap:
	iounmap(romsig);
	return 0;
}
Exemple #3
0
static int olpc_bat_get_voltage_max_design(union power_supply_propval *val)
{
	uint8_t ec_byte;
	union power_supply_propval tech;
	int mfr;
	int ret;

	ret = olpc_bat_get_tech(&tech);
	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;

	mfr = ec_byte >> 4;

	switch (tech.intval) {
	case POWER_SUPPLY_TECHNOLOGY_NiMH:
		switch (mfr) {
		case 1: /* Gold Peak */
			val->intval = 6000000;
			break;
		default:
			return -EIO;
		}
		break;

	case POWER_SUPPLY_TECHNOLOGY_LiFe:
		switch (mfr) {
		case 1: /* Gold Peak */
			val->intval = 6400000;
			break;
		case 2: /* BYD */
			val->intval = 6500000;
			break;
		default:
			return -EIO;
		}
		break;

	default:
		return -EIO;
	}

	return ret;
}
Exemple #4
0
static int __maybe_unused olpc_xo175_ec_resume(struct device *dev)
{
	u8 x = 0;

	/*
	 * The resume hint is only needed if no other commands are
	 * being sent during resume. all it does is tell the EC
	 * the SoC is definitely awake.
	 */
	olpc_ec_cmd(CMD_SUSPEND_HINT, &x, 1, NULL, 0);

	/* Enable all EC events while we're awake */
	olpc_xo175_ec_set_event_mask(EC_ALL_EVENTS);

	return 0;
}
Exemple #5
0
static int olpc_bat_get_charge_now(union power_supply_propval *val)
{
	uint8_t soc;
	union power_supply_propval full;
	int ret;

	ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &soc, 1);
	if (ret)
		return ret;

	ret = olpc_bat_get_charge_full_design(&full);
	if (ret)
		return ret;

	val->intval = soc * (full.intval / 100);
	return 0;
}
Exemple #6
0
static int __init olpc_init(void)
{
	int r = 0;

	if (!olpc_ofw_present() || !platform_detect())
		return 0;

	spin_lock_init(&ec_lock);

	/* assume B1 and above models always have a DCON */
	if (olpc_board_at_least(olpc_board(0xb1)))
		olpc_platform_info.flags |= OLPC_F_DCON;

	/* get the EC revision */
	olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0,
			(unsigned char *) &olpc_platform_info.ecver, 1);

#ifdef CONFIG_PCI_OLPC
	/* If the VSA exists let it emulate PCI, if not emulate in kernel.
	 * XO-1 only. */
	if (olpc_platform_info.boardrev < olpc_board_pre(0xd0) &&
			!cs5535_has_vsa2())
		x86_init.pci.arch_init = pci_olpc_init;
#endif
	/* EC version 0x5f adds support for wide SCI mask */
	if (olpc_platform_info.ecver >= 0x5f)
		olpc_platform_info.flags |= OLPC_F_EC_WIDE_SCI;

	printk(KERN_INFO "OLPC board revision %s%X (EC=%x)\n",
			((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "",
			olpc_platform_info.boardrev >> 4,
			olpc_platform_info.ecver);

	if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) { /* XO-1 */
		r = add_xo1_platform_devices();
		if (r)
			return r;
	}

	register_syscore_ops(&olpc_syscore_ops);
	setup_debugfs();

	return 0;
}
Exemple #7
0
static ssize_t olpc_bat_eeprom_read(struct file *filp, struct kobject *kobj,
		struct bin_attribute *attr, char *buf, loff_t off, size_t count)
{
	uint8_t ec_byte;
	int ret;
	int i;

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

	return count;
}
Exemple #8
0
static int __init olpc_bat_init(void)
{
    int ret = 0;
    uint8_t status;

    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);
        return -ENXIO;
    }

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

    /* Ignore the status. It doesn't actually matter */

    bat_pdev = platform_device_register_simple("olpc-battery", 0, NULL, 0);
    if (IS_ERR(bat_pdev))
        return PTR_ERR(bat_pdev);

    ret = power_supply_register(&bat_pdev->dev, &olpc_ac);
    if (ret)
        goto ac_failed;

    olpc_bat.name = bat_pdev->name;

    ret = power_supply_register(&bat_pdev->dev, &olpc_bat);
    if (ret)
        goto battery_failed;

    goto success;

battery_failed:
    power_supply_unregister(&olpc_ac);
ac_failed:
    platform_device_unregister(bat_pdev);
success:
    return ret;
}
Exemple #9
0
static int olpc_ac_get_prop(struct power_supply *psy,
			    enum power_supply_property psp,
			    union power_supply_propval *val)
{
	int ret = 0;
	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;
	}
	return ret;
}
Exemple #10
0
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)
		return ret;

	switch (ec_byte & 0xf) {
	case 1:
		val->intval = POWER_SUPPLY_TECHNOLOGY_NiMH;
		break;
	case 2:
		val->intval = POWER_SUPPLY_TECHNOLOGY_LiFe;
		break;
	default:
		val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
		break;
	}

	return ret;
}
Exemple #11
0
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)
		return ret;

	switch (ec_byte >> 4) {
	case 1:
		val->strval = "Gold Peak";
		break;
	case 2:
		val->strval = "BYD";
		break;
	default:
		val->strval = "Unknown";
		break;
	}

	return ret;
}
Exemple #12
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;

	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 */
		ret = -EIO;
	}

	return ret;
}
Exemple #13
0
static int olpc_battery_probe(struct platform_device *pdev)
{
	struct power_supply_config bat_psy_cfg = {};
	struct power_supply_config ac_psy_cfg = {};
	struct olpc_battery_data *data;
	uint8_t status;
	uint8_t ecver;
	int ret;

	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
	if (!data)
		return -ENOMEM;
	platform_set_drvdata(pdev, data);

	/* See if the EC is already there and get the EC revision */
	ret = olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0, &ecver, 1);
	if (ret)
		return ret;

	if (of_find_compatible_node(NULL, NULL, "olpc,xo1.75-ec")) {
		/* XO 1.75 */
		data->new_proto = true;
		data->little_endian = true;
	} else if (ecver > 0x44) {
		/* XO 1 or 1.5 with a new EC firmware. */
		data->new_proto = true;
	} else if (ecver < 0x44) {
		/*
		 * We've seen a number of EC protocol changes; this driver
		 * requires the latest EC protocol, supported by 0x44 and above.
		 */
		printk(KERN_NOTICE "OLPC EC version 0x%02x too old for "
			"battery driver.\n", ecver);
		return -ENXIO;
	}

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

	/* Ignore the status. It doesn't actually matter */

	ac_psy_cfg.of_node = pdev->dev.of_node;
	ac_psy_cfg.drv_data = data;

	data->olpc_ac = devm_power_supply_register(&pdev->dev, &olpc_ac_desc,
								&ac_psy_cfg);
	if (IS_ERR(data->olpc_ac))
		return PTR_ERR(data->olpc_ac);

	if (of_device_is_compatible(pdev->dev.of_node, "olpc,xo1.5-battery")) {
		/* XO-1.5 */
		olpc_bat_desc.properties = olpc_xo15_bat_props;
		olpc_bat_desc.num_properties = ARRAY_SIZE(olpc_xo15_bat_props);
	} else {
		/* XO-1 */
		olpc_bat_desc.properties = olpc_xo1_bat_props;
		olpc_bat_desc.num_properties = ARRAY_SIZE(olpc_xo1_bat_props);
	}

	bat_psy_cfg.of_node = pdev->dev.of_node;
	bat_psy_cfg.drv_data = data;
	bat_psy_cfg.attr_grp = olpc_bat_sysfs_groups;

	data->olpc_bat = devm_power_supply_register(&pdev->dev, &olpc_bat_desc,
								&bat_psy_cfg);
	if (IS_ERR(data->olpc_bat))
		return PTR_ERR(data->olpc_bat);

	if (olpc_ec_wakeup_available()) {
		device_set_wakeup_capable(&data->olpc_ac->dev, true);
		device_set_wakeup_capable(&data->olpc_bat->dev, true);
	}

	return 0;
}
Exemple #14
0
static int __init olpc_bat_init(void)
{
	int ret = 0;
	uint8_t status;

	if (!olpc_platform_info.ecver)
		return -ENXIO;

	/*
	 * 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;
	}

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

	/* Ignore the status. It doesn't actually matter */

	bat_pdev = platform_device_register_simple("olpc-battery", 0, NULL, 0);
	if (IS_ERR(bat_pdev))
		return PTR_ERR(bat_pdev);

	ret = power_supply_register(&bat_pdev->dev, &olpc_ac);
	if (ret)
		goto ac_failed;

	olpc_bat.name = bat_pdev->name;
	if (olpc_board_at_least(olpc_board_pre(0xd0))) { /* XO-1.5 */
		olpc_bat.properties = olpc_xo15_bat_props;
		olpc_bat.num_properties = ARRAY_SIZE(olpc_xo15_bat_props);
	} else { /* XO-1 */
		olpc_bat.properties = olpc_xo1_bat_props;
		olpc_bat.num_properties = ARRAY_SIZE(olpc_xo1_bat_props);
	}

	ret = power_supply_register(&bat_pdev->dev, &olpc_bat);
	if (ret)
		goto battery_failed;

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

	ret = device_create_file(olpc_bat.dev, &olpc_bat_error);
	if (ret)
		goto error_failed;

	goto success;

error_failed:
	device_remove_bin_file(olpc_bat.dev, &olpc_bat_eeprom);
eeprom_failed:
	power_supply_unregister(&olpc_bat);
battery_failed:
	power_supply_unregister(&olpc_ac);
ac_failed:
	platform_device_unregister(bat_pdev);
success:
	return ret;
}
Exemple #15
0
/*********************************************************************
 *		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;
	__be16 ec_word;
	uint8_t ec_byte;
	__be64 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 | BAT_STAT_TRICKLE)) &&
			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_CHARGE_TYPE:
		if (ec_byte & BAT_STAT_TRICKLE)
			val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
		else if (ec_byte & BAT_STAT_CHARGING)
			val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
		else
			val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
		break;
	case POWER_SUPPLY_PROP_PRESENT:
		val->intval = !!(ec_byte & (BAT_STAT_PRESENT |
					    BAT_STAT_TRICKLE));
		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:
	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
		ret = olpc_ec_cmd(EC_BAT_VOLTAGE, NULL, 0, (void *)&ec_word, 2);
		if (ret)
			return ret;

		val->intval = (s16)be16_to_cpu(ec_word) * 9760L / 32;
		break;
	case POWER_SUPPLY_PROP_CURRENT_AVG:
	case POWER_SUPPLY_PROP_CURRENT_NOW:
		ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2);
		if (ret)
			return ret;

		val->intval = (s16)be16_to_cpu(ec_word) * 15625L / 120;
		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;
		break;
	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
		if (ec_byte & BAT_STAT_FULL)
			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
		else if (ec_byte & BAT_STAT_LOW)
			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
		else
			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
		break;
	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
		ret = olpc_bat_get_charge_full_design(val);
		if (ret)
			return ret;
		break;
	case POWER_SUPPLY_PROP_CHARGE_NOW:
		ret = olpc_bat_get_charge_now(val);
		if (ret)
			return ret;
		break;
	case POWER_SUPPLY_PROP_TEMP:
		ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);
		if (ret)
			return ret;

		val->intval = (s16)be16_to_cpu(ec_word) * 100 / 256;
		break;
	case POWER_SUPPLY_PROP_TEMP_AMBIENT:
		ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2);
		if (ret)
			return ret;

		val->intval = (int)be16_to_cpu(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;

		val->intval = (s16)be16_to_cpu(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;
	}

	return ret;
}
Exemple #16
0
static int olpc_battery_probe(struct platform_device *pdev)
{
	int ret;
	uint8_t status;

	/*
	 * 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;
	}

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

	/* Ignore the status. It doesn't actually matter */

	olpc_ac = power_supply_register(&pdev->dev, &olpc_ac_desc, NULL);
	if (IS_ERR(olpc_ac))
		return PTR_ERR(olpc_ac);

	if (olpc_board_at_least(olpc_board_pre(0xd0))) { /* XO-1.5 */
		olpc_bat_desc.properties = olpc_xo15_bat_props;
		olpc_bat_desc.num_properties = ARRAY_SIZE(olpc_xo15_bat_props);
	} else { /* XO-1 */
		olpc_bat_desc.properties = olpc_xo1_bat_props;
		olpc_bat_desc.num_properties = ARRAY_SIZE(olpc_xo1_bat_props);
	}

	olpc_bat = power_supply_register(&pdev->dev, &olpc_bat_desc, NULL);
	if (IS_ERR(olpc_bat)) {
		ret = PTR_ERR(olpc_bat);
		goto battery_failed;
	}

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

	ret = device_create_file(&olpc_bat->dev, &olpc_bat_error);
	if (ret)
		goto error_failed;

	if (olpc_ec_wakeup_available()) {
		device_set_wakeup_capable(&olpc_ac->dev, true);
		device_set_wakeup_capable(&olpc_bat->dev, true);
	}

	return 0;

error_failed:
	device_remove_bin_file(&olpc_bat->dev, &olpc_bat_eeprom);
eeprom_failed:
	power_supply_unregister(olpc_bat);
battery_failed:
	power_supply_unregister(olpc_ac);
	return ret;
}
Exemple #17
0
/*********************************************************************
 *        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;

    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;

    case POWER_SUPPLY_PROP_MANUFACTURER:
        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 >> 4) {
        case 1:
            val->strval = "Gold Peak";
            break;
        case 2:
            val->strval = "BYD";
            break;
        default:
            val->strval = "Unknown";
            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;
            break;
        case 2:
            val->intval = POWER_SUPPLY_TECHNOLOGY_LiFe;
            break;
        default:
            val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
            break;
        }
        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;

        ec_word = be16_to_cpu(ec_word);
        val->intval = ec_word * 15625L / 120;
        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;
        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;
        break;
    case POWER_SUPPLY_PROP_TEMP_AMBIENT:
        ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2);
        if (ret)
            return ret;

        ec_word = be16_to_cpu(ec_word);
        val->intval = ec_word * 100 / 256;
        break;
    default:
        ret = -EINVAL;
        break;
    }

    return ret;
}
static void if_usb_reset_olpc_card(struct lbs_private *priv)
{
	printk(KERN_CRIT "Resetting OLPC wireless via EC...\n");
	olpc_ec_cmd(0x25, NULL, 0, NULL, 0);
}
Exemple #19
0
static int olpc_bat_get_property(struct power_supply *psy,
				 enum power_supply_property psp,
				 union power_supply_propval *val)
{
	int ret = 0;
	__be16 ec_word;
	uint8_t ec_byte;
	__be64 ser_buf;

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

	
	if (!(ec_byte & (BAT_STAT_PRESENT | BAT_STAT_TRICKLE)) &&
			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_CHARGE_TYPE:
		if (ec_byte & BAT_STAT_TRICKLE)
			val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
		else if (ec_byte & BAT_STAT_CHARGING)
			val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
		else
			val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
		break;
	case POWER_SUPPLY_PROP_PRESENT:
		val->intval = !!(ec_byte & (BAT_STAT_PRESENT |
					    BAT_STAT_TRICKLE));
		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);
		if (ret)
			return ret;

		val->intval = (int)be16_to_cpu(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;

		val->intval = (int)be16_to_cpu(ec_word) * 15625L / 120;
		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;
		break;
	case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
		if (ec_byte & BAT_STAT_FULL)
			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
		else if (ec_byte & BAT_STAT_LOW)
			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
		else
			val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
		break;
	case POWER_SUPPLY_PROP_TEMP:
		ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);
		if (ret)
			return ret;

		val->intval = (int)be16_to_cpu(ec_word) * 100 / 256;
		break;
	case POWER_SUPPLY_PROP_TEMP_AMBIENT:
		ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2);
		if (ret)
			return ret;

		val->intval = (int)be16_to_cpu(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;

		val->intval = (int)be16_to_cpu(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;
	}

	return ret;
}