diff options
-rw-r--r-- | drivers/platform/x86/Kconfig | 1 | ||||
-rw-r--r-- | drivers/platform/x86/toshiba_acpi.c | 96 |
2 files changed, 97 insertions, 0 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index daefe57c7b86..f5312f51de19 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -791,6 +791,7 @@ config SAMSUNG_Q10 config ACPI_TOSHIBA tristate "Toshiba Laptop Extras" depends on ACPI + depends on ACPI_BATTERY depends on ACPI_WMI select LEDS_CLASS select NEW_LEDS diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index b55e6e17f723..1b3357a4207a 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -45,6 +45,7 @@ #include <linux/hwmon.h> #include <linux/iio/iio.h> #include <linux/toshiba.h> +#include <acpi/battery.h> #include <acpi/video.h> MODULE_AUTHOR("John Belmonte"); @@ -3045,6 +3046,91 @@ static const struct hwmon_chip_info toshiba_acpi_hwmon_chip_info = { }; #endif +/* ACPI battery hooking */ +static ssize_t charge_control_end_threshold_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + u32 state; + int status; + + if (toshiba_acpi == NULL) { + pr_err("Toshiba ACPI object invalid\n"); + return -ENODEV; + } + + status = toshiba_battery_charge_mode_get(toshiba_acpi, &state); + + if (status != 0) + return status; + + if (state == 1) + return sprintf(buf, "80\n"); + else + return sprintf(buf, "100\n"); +} + +static ssize_t charge_control_end_threshold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + u32 value; + int rval; + + if (toshiba_acpi == NULL) { + pr_err("Toshiba ACPI object invalid\n"); + return -ENODEV; + } + + rval = kstrtou32(buf, 10, &value); + if (rval) + return rval; + + if (value < 1 || value > 100) + return -EINVAL; + rval = toshiba_battery_charge_mode_set(toshiba_acpi, + (value < 90) ? 1 : 0); + if (rval < 0) + return rval; + else + return count; +} + +static DEVICE_ATTR_RW(charge_control_end_threshold); + +static struct attribute *toshiba_acpi_battery_attrs[] = { + &dev_attr_charge_control_end_threshold.attr, + NULL, +}; + +ATTRIBUTE_GROUPS(toshiba_acpi_battery); + +static int toshiba_acpi_battery_add(struct power_supply *battery) +{ + if (toshiba_acpi == NULL) { + pr_err("Init order issue\n"); + return -ENODEV; + } + if (!toshiba_acpi->battery_charge_mode_supported) + return -ENODEV; + if (device_add_groups(&battery->dev, toshiba_acpi_battery_groups)) + return -ENODEV; + return 0; +} + +static int toshiba_acpi_battery_remove(struct power_supply *battery) +{ + device_remove_groups(&battery->dev, toshiba_acpi_battery_groups); + return 0; +} + +static struct acpi_battery_hook battery_hook = { + .add_battery = toshiba_acpi_battery_add, + .remove_battery = toshiba_acpi_battery_remove, + .name = "Toshiba Battery Extension", +}; + static void print_supported_features(struct toshiba_acpi_dev *dev) { pr_info("Supported laptop features:"); @@ -3134,6 +3220,9 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev) rfkill_destroy(dev->wwan_rfk); } + if (dev->battery_charge_mode_supported) + battery_hook_unregister(&battery_hook); + if (toshiba_acpi) toshiba_acpi = NULL; @@ -3332,6 +3421,13 @@ iio_error: toshiba_acpi = dev; + /* + * As the battery hook relies on the static variable toshiba_acpi being + * set, this must be done after toshiba_acpi is assigned. + */ + if (dev->battery_charge_mode_supported) + battery_hook_register(&battery_hook); + return 0; error: |