Commit 89655fbb authored by Arvid Norlander's avatar Arvid Norlander Committed by Hans de Goede
Browse files

platform/x86: Battery charge mode in toshiba_acpi (internals)



This commit adds the internal functions to control the Toshiba laptop.

Unlike for example ThinkPads where this control is granular here it is
just off/on. When off it charges to 100%. When on it charges to about 80%.

Controlling this setting is done via HCI register 0x00ba. Setting to value
1 will result in limiting the charing to 80% of the battery capacity,
while setting it to 0 will allow charging to 100%.

Reading the current state is a bit weird, and needs a 1 set in the last
position of the query for whatever reason. In addition, the read may
return 0x8d20 (Data not available) rarely, so a retry mechanism is needed.

According to the Windows program used to control the feature the setting
will not take effect until the battery has been discharged to around 50%.
However, in my testing it takes effect as soon as the charge drops below
80%. On Windows Toshiba branded this feature as "Eco charging".

Signed-off-by: default avatarArvid Norlander <lkml@vorpal.se>
Link: https://lore.kernel.org/r/20220902180037.1728546-2-lkml@vorpal.se


Reviewed-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
parent c727ba4c
Loading
Loading
Loading
Loading
+69 −0
Original line number Diff line number Diff line
@@ -114,6 +114,7 @@ MODULE_LICENSE("GPL");
#define HCI_KBD_ILLUMINATION		0x0095
#define HCI_ECO_MODE			0x0097
#define HCI_ACCELEROMETER2		0x00a6
#define HCI_BATTERY_CHARGE_MODE		0x00ba
#define HCI_SYSTEM_INFO			0xc000
#define SCI_PANEL_POWER_ON		0x010d
#define SCI_ILLUMINATION		0x014e
@@ -207,6 +208,7 @@ struct toshiba_acpi_dev {
	unsigned int usb_three_supported:1;
	unsigned int wwan_supported:1;
	unsigned int cooling_method_supported:1;
	unsigned int battery_charge_mode_supported:1;
	unsigned int sysfs_created:1;
	unsigned int special_functions;

@@ -1283,6 +1285,69 @@ static int toshiba_cooling_method_set(struct toshiba_acpi_dev *dev, u32 state)
	return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
}

/* Battery charge control */
static void toshiba_battery_charge_mode_available(struct toshiba_acpi_dev *dev)
{
	u32 in[TCI_WORDS] = { HCI_GET, HCI_BATTERY_CHARGE_MODE, 0, 0, 0, 0 };
	u32 out[TCI_WORDS];
	acpi_status status;

	dev->battery_charge_mode_supported = 0;

	status = tci_raw(dev, in, out);
	if (ACPI_FAILURE(status)) {
		pr_err("ACPI call to get Battery Charge Mode failed\n");
		return;
	}

	if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2)
		return;

	dev->battery_charge_mode_supported = 1;
}

static int toshiba_battery_charge_mode_get(struct toshiba_acpi_dev *dev, u32 *state)
{
	u32 in[TCI_WORDS] = { HCI_GET, HCI_BATTERY_CHARGE_MODE, 0, 0, 0, 0x1 };
	u32 out[TCI_WORDS];
	int retries = 3;

	do {
		acpi_status status = tci_raw(dev, in, out);

		if (ACPI_FAILURE(status))
			pr_err("ACPI call to get Battery Charge Mode failed\n");
		switch (out[0]) {
		case TOS_SUCCESS:
		case TOS_SUCCESS2:
			*state = out[2];
			return 0;
		case TOS_NOT_SUPPORTED:
			return -ENODEV;
		case TOS_DATA_NOT_AVAILABLE:
			retries--;
			break;
		default:
			return -EIO;
		}
	} while (retries);

	return -EIO;
}

static int toshiba_battery_charge_mode_set(struct toshiba_acpi_dev *dev, u32 state)
{
	u32 result = hci_write(dev, HCI_BATTERY_CHARGE_MODE, state);

	if (result == TOS_FAILURE)
		pr_err("ACPI call to set Battery Charge Mode failed\n");

	if (result == TOS_NOT_SUPPORTED)
		return -ENODEV;

	return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
}

/* Transflective Backlight */
static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status)
{
@@ -3022,6 +3087,8 @@ static void print_supported_features(struct toshiba_acpi_dev *dev)
		pr_cont(" wwan");
	if (dev->cooling_method_supported)
		pr_cont(" cooling-method");
	if (dev->battery_charge_mode_supported)
		pr_cont(" battery-charge-mode");

	pr_cont("\n");
}
@@ -3249,6 +3316,8 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)

	toshiba_cooling_method_available(dev);

	toshiba_battery_charge_mode_available(dev);

	print_supported_features(dev);

	ret = sysfs_create_group(&dev->acpi_dev->dev.kobj,