summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/platform/x86/Kconfig1
-rw-r--r--drivers/platform/x86/toshiba_acpi.c96
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: