diff options
Diffstat (limited to 'drivers/platform/x86/lg-laptop.c')
-rw-r--r-- | drivers/platform/x86/lg-laptop.c | 107 |
1 files changed, 89 insertions, 18 deletions
diff --git a/drivers/platform/x86/lg-laptop.c b/drivers/platform/x86/lg-laptop.c index 20145b539335..3e520d5bca07 100644 --- a/drivers/platform/x86/lg-laptop.c +++ b/drivers/platform/x86/lg-laptop.c @@ -8,6 +8,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/acpi.h> +#include <linux/dmi.h> #include <linux/input.h> #include <linux/input/sparse-keymap.h> #include <linux/kernel.h> @@ -16,11 +17,12 @@ #include <linux/platform_device.h> #include <linux/types.h> -#define LED_DEVICE(_name, max) struct led_classdev _name = { \ +#define LED_DEVICE(_name, max, flag) struct led_classdev _name = { \ .name = __stringify(_name), \ .max_brightness = max, \ .brightness_set = _name##_set, \ .brightness_get = _name##_get, \ + .flags = flag, \ } MODULE_AUTHOR("Matan Ziv-Av"); @@ -69,9 +71,13 @@ static u32 inited; #define INIT_INPUT_ACPI 0x04 #define INIT_SPARSE_KEYMAP 0x80 +static int battery_limit_use_wmbb; +static struct led_classdev kbd_backlight; +static enum led_brightness get_kbd_backlight_level(void); + static const struct key_entry wmi_keymap[] = { {KE_KEY, 0x70, {KEY_F15} }, /* LG control panel (F1) */ - {KE_KEY, 0x74, {KEY_F13} }, /* Touchpad toggle (F5) */ + {KE_KEY, 0x74, {KEY_F21} }, /* Touchpad toggle (F5) */ {KE_KEY, 0xf020000, {KEY_F14} }, /* Read mode (F9) */ {KE_KEY, 0x10000000, {KEY_F16} },/* Keyboard backlight (F8) - pressing * this key both sends an event and @@ -214,10 +220,16 @@ static void wmi_notify(u32 value, void *context) int eventcode = obj->integer.value; struct key_entry *key; - key = - sparse_keymap_entry_from_scancode(wmi_input_dev, eventcode); - if (key && key->type == KE_KEY) - sparse_keymap_report_entry(wmi_input_dev, key, 1, true); + if (eventcode == 0x10000000) { + led_classdev_notify_brightness_hw_changed( + &kbd_backlight, get_kbd_backlight_level()); + } else { + key = sparse_keymap_entry_from_scancode( + wmi_input_dev, eventcode); + if (key && key->type == KE_KEY) + sparse_keymap_report_entry(wmi_input_dev, + key, 1, true); + } } pr_debug("Type: %i Eventcode: 0x%llx\n", obj->type, @@ -461,7 +473,10 @@ static ssize_t battery_care_limit_store(struct device *dev, if (value == 100 || value == 80) { union acpi_object *r; - r = lg_wmab(WM_BATT_LIMIT, WM_SET, value); + if (battery_limit_use_wmbb) + r = lg_wmbb(WMBB_BATT_LIMIT, WM_SET, value); + else + r = lg_wmab(WM_BATT_LIMIT, WM_SET, value); if (!r) return -EIO; @@ -479,16 +494,29 @@ static ssize_t battery_care_limit_show(struct device *dev, unsigned int status; union acpi_object *r; - r = lg_wmab(WM_BATT_LIMIT, WM_GET, 0); - if (!r) - return -EIO; + if (battery_limit_use_wmbb) { + r = lg_wmbb(WMBB_BATT_LIMIT, WM_GET, 0); + if (!r) + return -EIO; - if (r->type != ACPI_TYPE_INTEGER) { - kfree(r); - return -EIO; - } + if (r->type != ACPI_TYPE_BUFFER) { + kfree(r); + return -EIO; + } - status = r->integer.value; + status = r->buffer.pointer[0x10]; + } else { + r = lg_wmab(WM_BATT_LIMIT, WM_GET, 0); + if (!r) + return -EIO; + + if (r->type != ACPI_TYPE_INTEGER) { + kfree(r); + return -EIO; + } + + status = r->integer.value; + } kfree(r); if (status != 80 && status != 100) status = 0; @@ -529,7 +557,7 @@ static enum led_brightness tpad_led_get(struct led_classdev *cdev) return ggov(GOV_TLED) > 0 ? LED_ON : LED_OFF; } -static LED_DEVICE(tpad_led, 1); +static LED_DEVICE(tpad_led, 1, 0); static void kbd_backlight_set(struct led_classdev *cdev, enum led_brightness brightness) @@ -546,7 +574,7 @@ static void kbd_backlight_set(struct led_classdev *cdev, kfree(r); } -static enum led_brightness kbd_backlight_get(struct led_classdev *cdev) +static enum led_brightness get_kbd_backlight_level(void) { union acpi_object *r; int val; @@ -577,7 +605,12 @@ static enum led_brightness kbd_backlight_get(struct led_classdev *cdev) return val; } -static LED_DEVICE(kbd_backlight, 255); +static enum led_brightness kbd_backlight_get(struct led_classdev *cdev) +{ + return get_kbd_backlight_level(); +} + +static LED_DEVICE(kbd_backlight, 255, LED_BRIGHT_HW_CHANGED); static void wmi_input_destroy(void) { @@ -602,6 +635,8 @@ static struct platform_driver pf_driver = { static int acpi_add(struct acpi_device *device) { int ret; + const char *product; + int year = 2017; if (pf_device) return 0; @@ -619,6 +654,42 @@ static int acpi_add(struct acpi_device *device) pr_err("unable to register platform device\n"); goto out_platform_registered; } + product = dmi_get_system_info(DMI_PRODUCT_NAME); + if (strlen(product) > 4) + switch (product[4]) { + case '5': + case '6': + year = 2016; + break; + case '7': + year = 2017; + break; + case '8': + year = 2018; + break; + case '9': + year = 2019; + break; + case '0': + if (strlen(product) > 5) + switch (product[5]) { + case 'N': + year = 2020; + break; + case 'P': + year = 2021; + break; + default: + year = 2022; + } + break; + default: + year = 2019; + } + pr_info("product: %s year: %d\n", product, year); + + if (year >= 2019) + battery_limit_use_wmbb = 1; ret = sysfs_create_group(&pf_device->dev.kobj, &dev_attribute_group); if (ret) |