Re: [PATCH] Add IdeaPad quick_charge attribute to sysfs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

On 9/11/22 19:08, Barnabás Pőcze wrote:
> Hi
> 
> 
> 2022. szeptember 11., vasárnap 18:17 keltezéssel, Philipp Jungkamp írta:
>> 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
> 
> There is already an entry for this on the kernel bugzilla:
> https://bugzilla.kernel.org/show_bug.cgi?id=216176
> 
> I have two concerns: one, it adds a new driver specific attribute for a somewhat
> generic functionality;

Right this really needs a standardized API using the power_supply sysfs class, see:
https://bugzilla.kernel.org/show_bug.cgi?id=216176#c5

Please write an API proposal for this and submit it as discussed in the
linked comment,

Regards,

Hans



> two, Lenovo Vantage does not only check this single bit
> before allowing this mode to be enabled (as far as I can recall).
> 
> 
> Regards,
> Barnabás Pőcze
> 
> 
>>
>>  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
>>
> 




[Index of Archives]     [Linux Kernel Development]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux