All of lore.kernel.org
 help / color / mirror / Atom feed
From: Philipp Jungkamp <p.jungkamp@gmx.net>
To: Ike Panhc <ike.pan@canonical.com>,
	Hans de Goede <hdegoede@redhat.com>,
	Mark Gross <markgross@kernel.org>
Cc: platform-driver-x86@vger.kernel.org,
	Philipp Jungkamp <p.jungkamp@gmx.net>
Subject: [PATCH] Add IdeaPad quick_charge attribute to sysfs
Date: Sun, 11 Sep 2022 18:17:18 +0200	[thread overview]
Message-ID: <20220911161718.24284-1-p.jungkamp@gmx.net> (raw)

More recent IdeaPads allow USB-C quick-charging to be controlled via
ACPI. This seems to be mutually exclusive with the ACPI conservation
mode.

Expose a readable and writable 'quick_charge' sysfs attribute next when
support is indicated in ACPI.
---
I deduced the indicator bits from their names in the DSDT (QCHO and
QCHX). I don't have an IdeaPad except mine on hand and can't check
whether these are indeed the intended uses or their behaviour on other
IdeaPads. I can confirm that a change in the quick_charge toggle is
visible in Lenovo Vantage when dual booting into Windows 11.

Greetings,
Philipp Jungkamp

 drivers/platform/x86/ideapad-laptop.c | 64 ++++++++++++++++++++++++++-
 1 file changed, 62 insertions(+), 2 deletions(-)

diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index abd0c81d62c4..dea35779264a 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -54,12 +54,16 @@ enum {
 };

 enum {
-	GBMD_CONSERVATION_STATE_BIT = 5,
+	GBMD_QUICK_CHARGE_STATE_BIT   = 2,
+	GBMD_CONSERVATION_STATE_BIT   = 5,
+	GBMD_QUICK_CHARGE_SUPPORT_BIT = 17,
 };

 enum {
 	SBMC_CONSERVATION_ON  = 3,
 	SBMC_CONSERVATION_OFF = 5,
+	SBMC_QUICK_CHARGE_ON  = 7,
+	SBMC_QUICK_CHARGE_OFF = 8,
 };

 enum {
@@ -140,6 +144,7 @@ struct ideapad_private {
 		bool kbd_bl               : 1;
 		bool touchpad_ctrl_via_ec : 1;
 		bool usb_charging         : 1;
+		bool quick_charge         : 1;
 	} features;
 	struct {
 		bool initialized;
@@ -482,6 +487,12 @@ static ssize_t conservation_mode_store(struct device *dev,
 	if (err)
 		return err;

+	if (priv->features.quick_charge && state) {
+		err = exec_sbmc(priv->adev->handle, SBMC_QUICK_CHARGE_OFF);
+		if (err)
+			return err;
+	}
+
 	err = exec_sbmc(priv->adev->handle, state ? SBMC_CONSERVATION_ON : SBMC_CONSERVATION_OFF);
 	if (err)
 		return err;
@@ -491,6 +502,48 @@ static ssize_t conservation_mode_store(struct device *dev,

 static DEVICE_ATTR_RW(conservation_mode);

+static ssize_t quick_charge_show(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct ideapad_private *priv = dev_get_drvdata(dev);
+	unsigned long result;
+	int err;
+
+	err = eval_gbmd(priv->adev->handle, &result);
+	if (err)
+		return err;
+
+	return sysfs_emit(buf, "%d\n", !!test_bit(GBMD_QUICK_CHARGE_STATE_BIT, &result));
+}
+
+static ssize_t quick_charge_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;
+
+	if (priv->features.conservation_mode && state) {
+		err = exec_sbmc(priv->adev->handle, SBMC_CONSERVATION_OFF);
+		if (err)
+			return err;
+	}
+
+	err = exec_sbmc(priv->adev->handle, state ? SBMC_QUICK_CHARGE_ON : SBMC_QUICK_CHARGE_OFF);
+	if (err)
+		return err;
+
+	return count;
+}
+
+static DEVICE_ATTR_RW(quick_charge);
+
 static ssize_t fan_mode_show(struct device *dev,
 			     struct device_attribute *attr,
 			     char *buf)
@@ -641,6 +694,7 @@ static DEVICE_ATTR_RW(usb_charging);
 static struct attribute *ideapad_attributes[] = {
 	&dev_attr_camera_power.attr,
 	&dev_attr_conservation_mode.attr,
+	&dev_attr_quick_charge.attr,
 	&dev_attr_fan_mode.attr,
 	&dev_attr_fn_lock.attr,
 	&dev_attr_touchpad.attr,
@@ -660,6 +714,8 @@ static umode_t ideapad_is_visible(struct kobject *kobj,
 		supported = test_bit(CFG_CAP_CAM_BIT, &priv->cfg);
 	else if (attr == &dev_attr_conservation_mode.attr)
 		supported = priv->features.conservation_mode;
+	else if (attr == &dev_attr_quick_charge.attr)
+		supported = priv->features.quick_charge;
 	else if (attr == &dev_attr_fan_mode.attr)
 		supported = priv->features.fan_mode;
 	else if (attr == &dev_attr_fn_lock.attr)
@@ -1546,9 +1602,13 @@ static void ideapad_check_features(struct ideapad_private *priv)
 	if (!read_ec_data(handle, VPCCMD_R_FAN, &val))
 		priv->features.fan_mode = true;

-	if (acpi_has_method(handle, "GBMD") && acpi_has_method(handle, "SBMC"))
+	if (acpi_has_method(handle, "GBMD") && acpi_has_method(handle, "SBMC")) {
 		priv->features.conservation_mode = true;

+		if (!eval_gbmd(handle,&val) && test_bit(GBMD_QUICK_CHARGE_SUPPORT_BIT, &val))
+			priv->features.quick_charge = true;
+	}
+
 	if (acpi_has_method(handle, "DYTC"))
 		priv->features.dytc = true;

--
2.37.3


             reply	other threads:[~2022-09-11 16:17 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-09-11 16:17 Philipp Jungkamp [this message]
2022-09-11 18:08 ` [PATCH] Add IdeaPad quick_charge attribute to sysfs Barnabás Pőcze
2022-09-19  9:08   ` Hans de Goede

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220911161718.24284-1-p.jungkamp@gmx.net \
    --to=p.jungkamp@gmx.net \
    --cc=hdegoede@redhat.com \
    --cc=ike.pan@canonical.com \
    --cc=markgross@kernel.org \
    --cc=platform-driver-x86@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.