summaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorArvid Norlander <lkml@vorpal.se>2022-09-02 20:00:35 +0200
committerHans de Goede <hdegoede@redhat.com>2022-09-09 21:58:16 +0200
commit89655fbb396aff20bd5247fa6b13a689e2f10f9c (patch)
tree4ff387f530c3682b42cca22139d7d1680ec5fea2 /drivers/platform
parentc727ba4cd95a12d8e43b02963d3ba4daddbd100c (diff)
downloadlinux-89655fbb396aff20bd5247fa6b13a689e2f10f9c.tar.bz2
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: Arvid Norlander <lkml@vorpal.se> Link: https://lore.kernel.org/r/20220902180037.1728546-2-lkml@vorpal.se Reviewed-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/toshiba_acpi.c69
1 files changed, 69 insertions, 0 deletions
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 7fd9d97c9b3b..b55e6e17f723 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -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 @@ iio_error:
toshiba_cooling_method_available(dev);
+ toshiba_battery_charge_mode_available(dev);
+
print_supported_features(dev);
ret = sysfs_create_group(&dev->acpi_dev->dev.kobj,