diff mbox series

[v2,22/24] platform/x86: ideapad-laptop: add "always on USB charging" control support

Message ID 20210113182016.166049-23-pobrn@protonmail.com (mailing list archive)
State Changes Requested, archived
Headers show
Series platform/x86: ideapad-laptop: cleanup, keyboard backlight and "always on USB charging" control support, reenable touchpad control | expand

Commit Message

Barnabás Pőcze Jan. 13, 2021, 6:22 p.m. UTC
Certain models have a so-called "always on USB charging" feature, which
enables USB charging even when the computer is turned off or suspended,
and which may be controlled/queried using the SALS/HALS ACPI methods.
Expose this functionality via a new device attribute (usb_charging).
Tested on: Lenovo YOGA 520-14IKB 80X8

Signed-off-by: Barnabás Pőcze <pobrn@protonmail.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>

Comments

Andy Shevchenko Jan. 16, 2021, 8:09 p.m. UTC | #1
On Wed, Jan 13, 2021 at 8:24 PM Barnabás Pőcze <pobrn@protonmail.com> wrote:
>
> Certain models have a so-called "always on USB charging" feature, which
> enables USB charging even when the computer is turned off or suspended,
> and which may be controlled/queried using the SALS/HALS ACPI methods.
> Expose this functionality via a new device attribute (usb_charging).
> Tested on: Lenovo YOGA 520-14IKB 80X8

...

>  enum {
> -       HALS_KBD_BL_SUPPORT_BIT  = 4,
> -       HALS_KBD_BL_STATE_BIT    = 5,
> -       HALS_FNLOCK_SUPPORT_BIT  = 9,
> -       HALS_FNLOCK_STATE_BIT    = 10,
> -       HALS_HOTKEYS_PRIMARY_BIT = 11,
> +       HALS_KBD_BL_SUPPORT_BIT       = 4,
> +       HALS_KBD_BL_STATE_BIT         = 5,
> +       HALS_USB_CHARGING_SUPPORT_BIT = 6,
> +       HALS_USB_CHARGING_STATE_BIT   = 7,
> +       HALS_FNLOCK_SUPPORT_BIT       = 9,
> +       HALS_FNLOCK_STATE_BIT         = 10,
> +       HALS_HOTKEYS_PRIMARY_BIT      = 11,
>  };
>
>  enum {
> -       SALS_KBD_BL_ON  = 0x8,
> -       SALS_KBD_BL_OFF = 0x9,
> -       SALS_FNLOCK_ON  = 0xe,
> -       SALS_FNLOCK_OFF = 0xf,
> +       SALS_KBD_BL_ON        = 0x8,
> +       SALS_KBD_BL_OFF       = 0x9,
> +       SALS_USB_CHARGING_ON  = 0xa,
> +       SALS_USB_CHARGING_OFF = 0xb,
> +       SALS_FNLOCK_ON        = 0xe,
> +       SALS_FNLOCK_OFF       = 0xf,
>  };

Twice in the same series you reindented these. Please, indent them
correctly in the first place.
diff mbox series

Patch

diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index 7a0dbafe5dfc..da1c89b2e086 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -60,18 +60,22 @@  enum {
 };
 
 enum {
-	HALS_KBD_BL_SUPPORT_BIT  = 4,
-	HALS_KBD_BL_STATE_BIT    = 5,
-	HALS_FNLOCK_SUPPORT_BIT  = 9,
-	HALS_FNLOCK_STATE_BIT    = 10,
-	HALS_HOTKEYS_PRIMARY_BIT = 11,
+	HALS_KBD_BL_SUPPORT_BIT       = 4,
+	HALS_KBD_BL_STATE_BIT         = 5,
+	HALS_USB_CHARGING_SUPPORT_BIT = 6,
+	HALS_USB_CHARGING_STATE_BIT   = 7,
+	HALS_FNLOCK_SUPPORT_BIT       = 9,
+	HALS_FNLOCK_STATE_BIT         = 10,
+	HALS_HOTKEYS_PRIMARY_BIT      = 11,
 };
 
 enum {
-	SALS_KBD_BL_ON  = 0x8,
-	SALS_KBD_BL_OFF = 0x9,
-	SALS_FNLOCK_ON  = 0xe,
-	SALS_FNLOCK_OFF = 0xf,
+	SALS_KBD_BL_ON        = 0x8,
+	SALS_KBD_BL_OFF       = 0x9,
+	SALS_USB_CHARGING_ON  = 0xa,
+	SALS_USB_CHARGING_OFF = 0xb,
+	SALS_FNLOCK_ON        = 0xe,
+	SALS_FNLOCK_OFF       = 0xf,
 };
 
 enum {
@@ -122,7 +126,8 @@  struct ideapad_private {
 		     touchpad_ctrl_via_ec : 1,
 		     conservation_mode    : 1,
 		     fn_lock              : 1,
-		     kbd_bl               : 1;
+		     kbd_bl               : 1,
+		     usb_charging         : 1;
 	} features;
 	struct {
 		bool initialized;
@@ -585,12 +590,50 @@  static ssize_t fn_lock_store(struct device *dev,
 
 static DEVICE_ATTR_RW(fn_lock);
 
+static ssize_t usb_charging_show(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct ideapad_private *priv = dev_get_drvdata(dev);
+	unsigned long hals;
+	int err;
+
+	err = eval_hals(priv->adev->handle, &hals);
+	if (err)
+		return err;
+
+	return sysfs_emit(buf, "%u\n", test_bit(HALS_USB_CHARGING_STATE_BIT, &hals));
+}
+
+static ssize_t usb_charging_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct ideapad_private *priv = dev_get_drvdata(dev);
+	bool state;
+	int err;
+
+	err = kstrtobool(buf, &state);
+	if (err)
+		return err;
+
+	err = eval_sals(priv->adev->handle,
+			state ? SALS_USB_CHARGING_ON : SALS_USB_CHARGING_OFF);
+	if (err)
+		return err;
+
+	return count;
+}
+
+static DEVICE_ATTR_RW(usb_charging);
+
 static struct attribute *ideapad_attributes[] = {
 	&dev_attr_camera_power.attr,
 	&dev_attr_fan_mode.attr,
 	&dev_attr_touchpad.attr,
 	&dev_attr_conservation_mode.attr,
 	&dev_attr_fn_lock.attr,
+	&dev_attr_usb_charging.attr,
 	NULL
 };
 
@@ -613,6 +656,8 @@  static umode_t ideapad_is_visible(struct kobject *kobj,
 		supported = priv->features.conservation_mode;
 	else if (attr == &dev_attr_fn_lock.attr)
 		supported = priv->features.fn_lock;
+	else if (attr == &dev_attr_usb_charging.attr)
+		supported = priv->features.usb_charging;
 
 	return supported ? attr->mode : 0;
 }
@@ -1187,6 +1232,9 @@  static void ideapad_check_features(struct ideapad_private *priv)
 
 			if (test_bit(HALS_KBD_BL_SUPPORT_BIT, &val))
 				priv->features.kbd_bl = true;
+
+			if (test_bit(HALS_USB_CHARGING_SUPPORT_BIT, &val))
+				priv->features.usb_charging = true;
 		}
 	}
 }