Re: [PATCH 2/2] platform/x86: Battery charge mode in toshiba_acpi

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

 



Hi,

On 8/21/22 22:08, Arvid Norlander wrote:
> Unlike for example ThinkPads where this control is granular here it is
> just off/on. When off it charges to 100%. When on it charges to about 80%.
> 
> Controlling this setting is done via HCI register 0x00ba. Setting to value
> 1 will result in limiting the charing to 80% of the battery capacity,
> while setting it to 0 will allow charging to 100%.
> 
> Reading the current state is a bit weird, and needs a 1 set in the last
> position of the query for whatever reason. In addition, the read may
> return 0x8d20 (Data not available) rarely, so a retry mechanism is needed.
> 
> According to the Windows program used to control the feature the setting
> will not take effect until the battery has been discharged to around 50%.
> However, in my testing it takes effect as soon as the charge drops below
> 80%. On Windows Toshiba branded this feature as "Eco charging".
> 
> Signed-off-by: Arvid Norlander <lkml@xxxxxxxxx>

As mentioned in my reply to the cover-letter it would be better IMHO
to use the standard /sys/class/power_supply/BAT*/charge_control_end_threshold
sysfs attribute for this functionality.

Regards,

Hans


> ---
>  drivers/platform/x86/toshiba_acpi.c | 110 ++++++++++++++++++++++++++++
>  1 file changed, 110 insertions(+)
> 
> diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
> index 6cc617b2940e..2e13f241538a 100644
> --- a/drivers/platform/x86/toshiba_acpi.c
> +++ b/drivers/platform/x86/toshiba_acpi.c
> @@ -112,6 +112,7 @@ MODULE_LICENSE("GPL");
>  #define HCI_KBD_ILLUMINATION		0x0095
>  #define HCI_ECO_MODE			0x0097
>  #define HCI_ACCELEROMETER2		0x00a6
> +#define HCI_BATTERY_CHARGE_MODE		0x00ba
>  #define HCI_SYSTEM_INFO			0xc000
>  #define SCI_PANEL_POWER_ON		0x010d
>  #define SCI_ILLUMINATION		0x014e
> @@ -201,6 +202,7 @@ struct toshiba_acpi_dev {
>  	unsigned int usb_three_supported:1;
>  	unsigned int wwan_supported:1;
>  	unsigned int cooling_method_supported:1;
> +	unsigned int battery_charge_mode_supported:1;
>  	unsigned int sysfs_created:1;
>  	unsigned int special_functions;
>  
> @@ -1285,6 +1287,69 @@ static int toshiba_cooling_method_set(struct toshiba_acpi_dev *dev, u32 state)
>  	return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
>  }
>  
> +/* Battery charge control */
> +static void toshiba_battery_charge_mode_available(struct toshiba_acpi_dev *dev)
> +{
> +	u32 in[TCI_WORDS] = { HCI_GET, HCI_BATTERY_CHARGE_MODE, 0, 0, 0, 0 };
> +	u32 out[TCI_WORDS];
> +	acpi_status status;
> +
> +	dev->battery_charge_mode_supported = 0;
> +
> +	status = tci_raw(dev, in, out);
> +	if (ACPI_FAILURE(status)) {
> +		pr_err("ACPI call to get Battery Charge Mode failed\n");
> +		return;
> +	}
> +
> +	if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2)
> +		return;
> +
> +	dev->battery_charge_mode_supported = 1;
> +}
> +
> +static int toshiba_battery_charge_mode_get(struct toshiba_acpi_dev *dev, u32 *state)
> +{
> +	u32 in[TCI_WORDS] = { HCI_GET, HCI_BATTERY_CHARGE_MODE, 0, 0, 0, 0x1 };
> +	u32 out[TCI_WORDS];
> +	int retries = 3;
> +
> +	do {
> +		acpi_status status = tci_raw(dev, in, out);
> +
> +		if (ACPI_FAILURE(status))
> +			pr_err("ACPI call to get Battery Charge Mode failed\n");
> +		switch (out[0]) {
> +		case TOS_SUCCESS:
> +		case TOS_SUCCESS2:
> +			*state = out[2];
> +			return 0;
> +		case TOS_NOT_SUPPORTED:
> +			return -ENODEV;
> +		case TOS_DATA_NOT_AVAILABLE:
> +			retries--;
> +			break;
> +		default:
> +			return -EIO;
> +		}
> +	} while (retries);
> +
> +	return -EIO;
> +}
> +
> +static int toshiba_battery_charge_mode_set(struct toshiba_acpi_dev *dev, u32 state)
> +{
> +	u32 result = hci_write(dev, HCI_BATTERY_CHARGE_MODE, state);
> +
> +	if (result == TOS_FAILURE)
> +		pr_err("ACPI call to set Battery Charge Mode failed\n");
> +
> +	if (result == TOS_NOT_SUPPORTED)
> +		return -ENODEV;
> +
> +	return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
> +}
> +
>  /* Transflective Backlight */
>  static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status)
>  {
> @@ -2334,6 +2399,44 @@ static ssize_t cooling_method_store(struct device *dev,
>  }
>  static DEVICE_ATTR_RW(cooling_method);
>  
> +static ssize_t battery_charge_mode_show(struct device *dev,
> +					   struct device_attribute *attr,
> +					   char *buf)
> +{
> +	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
> +	int state;
> +	int ret;
> +
> +	ret = toshiba_battery_charge_mode_get(toshiba, &state);
> +	if (ret < 0)
> +		return ret;
> +
> +	return sprintf(buf, "%d\n", state);
> +}
> +
> +static ssize_t battery_charge_mode_store(struct device *dev,
> +					    struct device_attribute *attr,
> +					    const char *buf, size_t count)
> +{
> +	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
> +	int state;
> +	int ret;
> +
> +	ret = kstrtoint(buf, 0, &state);
> +	if (ret)
> +		return ret;
> +
> +	if (state != 0 && state != 1)
> +		return -EINVAL;
> +
> +	ret = toshiba_battery_charge_mode_set(toshiba, state);
> +	if (ret)
> +		return ret;
> +
> +	return count;
> +}
> +static DEVICE_ATTR_RW(battery_charge_mode);
> +
>  static struct attribute *toshiba_attributes[] = {
>  	&dev_attr_version.attr,
>  	&dev_attr_fan.attr,
> @@ -2350,6 +2453,7 @@ static struct attribute *toshiba_attributes[] = {
>  	&dev_attr_panel_power_on.attr,
>  	&dev_attr_usb_three.attr,
>  	&dev_attr_cooling_method.attr,
> +	&dev_attr_battery_charge_mode.attr,
>  	NULL,
>  };
>  
> @@ -2384,6 +2488,8 @@ static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
>  		exists = (drv->usb_three_supported) ? true : false;
>  	else if (attr == &dev_attr_cooling_method.attr)
>  		exists = (drv->cooling_method_supported) ? true : false;
> +	else if (attr == &dev_attr_battery_charge_mode.attr)
> +		exists = (drv->battery_charge_mode_supported) ? true : false;
>  
>  	return exists ? attr->mode : 0;
>  }
> @@ -2959,6 +3065,8 @@ static void print_supported_features(struct toshiba_acpi_dev *dev)
>  		pr_cont(" wwan");
>  	if (dev->cooling_method_supported)
>  		pr_cont(" cooling-method");
> +	if (dev->battery_charge_mode_supported)
> +		pr_cont(" battery-charge-mode");
>  
>  	pr_cont("\n");
>  }
> @@ -3166,6 +3274,8 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
>  
>  	toshiba_cooling_method_available(dev);
>  
> +	toshiba_battery_charge_mode_available(dev);
> +
>  	print_supported_features(dev);
>  
>  	ret = sysfs_create_group(&dev->acpi_dev->dev.kobj,




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

  Powered by Linux