Commit 8983bfd5 authored by Matan Ziv-Av's avatar Matan Ziv-Av Committed by Hans de Goede
Browse files

platform/x86: lg-laptop: Support for battery charge limit on newer models



Add support for the difference between various models:

- Use dmi to detect laptop model.
- 2019 and newer models use _wmbb method to set battery charge limit.

Signed-off-by: default avatarMatan Ziv-Av <matan@svgalib.org>
Link: https://lore.kernel.org/r/bd6922a412e50c2dcfb7ce24fc8687f577181d65.1629291912.git.matan@svgalib.org


Reviewed-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
parent dcfbd31e
Loading
Loading
Loading
Loading
+66 −9
Original line number Diff line number Diff line
@@ -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>
@@ -69,6 +70,8 @@ static u32 inited;
#define INIT_INPUT_ACPI         0x04
#define INIT_SPARSE_KEYMAP      0x80

static int battery_limit_use_wmbb;

static const struct key_entry wmi_keymap[] = {
	{KE_KEY, 0x70, {KEY_F15} },	 /* LG control panel (F1) */
	{KE_KEY, 0x74, {KEY_F13} },	 /* Touchpad toggle (F5) */
@@ -461,6 +464,9 @@ static ssize_t battery_care_limit_store(struct device *dev,
	if (value == 100 || value == 80) {
		union acpi_object *r;

		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,6 +485,18 @@ static ssize_t battery_care_limit_show(struct device *dev,
	unsigned int status;
	union acpi_object *r;

	if (battery_limit_use_wmbb) {
		r = lg_wmbb(WMBB_BATT_LIMIT, WM_GET, 0);
		if (!r)
			return -EIO;

		if (r->type != ACPI_TYPE_BUFFER) {
			kfree(r);
			return -EIO;
		}

		status = r->buffer.pointer[0x10];
	} else {
		r = lg_wmab(WM_BATT_LIMIT, WM_GET, 0);
		if (!r)
			return -EIO;
@@ -489,6 +507,7 @@ static ssize_t battery_care_limit_show(struct device *dev,
		}

		status = r->integer.value;
	}
	kfree(r);
	if (status != 80 && status != 100)
		status = 0;
@@ -602,6 +621,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 +640,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)