Commit 400cffd5 authored by Thomas Weißschuh's avatar Thomas Weißschuh Committed by Hans de Goede
Browse files

platform/x86: thinkpad_acpi: support inhibit-charge



This adds support for the inhibit-charge charge_behaviour through the
embedded controller of ThinkPads.

Co-developed-by: default avatarThomas Koch <linrunner@gmx.net>
Signed-off-by: default avatarThomas Koch <linrunner@gmx.net>
Co-developed-by: default avatarNicolò Piazzalunga <nicolopiazzalunga@gmail.com>
Signed-off-by: default avatarNicolò Piazzalunga <nicolopiazzalunga@gmail.com>
Signed-off-by: default avatarThomas Weißschuh <linux@weissschuh.net>
Acked-by: default avatarSebastian Reichel <sebastian.reichel@collabora.com>
Link: https://lore.kernel.org/r/20211123232704.25394-5-linux@weissschuh.net


Reviewed-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
parent b55d416d
Loading
Loading
Loading
Loading
+62 −2
Original line number Original line Diff line number Diff line
@@ -9216,6 +9216,8 @@ static struct ibm_struct mute_led_driver_data = {
#define SET_STOP	"BCSS"
#define SET_STOP	"BCSS"
#define GET_DISCHARGE	"BDSG"
#define GET_DISCHARGE	"BDSG"
#define SET_DISCHARGE	"BDSS"
#define SET_DISCHARGE	"BDSS"
#define GET_INHIBIT	"BICG"
#define SET_INHIBIT	"BICS"


enum {
enum {
	BAT_ANY = 0,
	BAT_ANY = 0,
@@ -9233,6 +9235,7 @@ enum {
	THRESHOLD_START,
	THRESHOLD_START,
	THRESHOLD_STOP,
	THRESHOLD_STOP,
	FORCE_DISCHARGE,
	FORCE_DISCHARGE,
	INHIBIT_CHARGE,
};
};


struct tpacpi_battery_data {
struct tpacpi_battery_data {
@@ -9304,6 +9307,12 @@ static int tpacpi_battery_get(int what, int battery, int *ret)
		/* The force discharge status is in bit 0 */
		/* The force discharge status is in bit 0 */
		*ret = *ret & 0x01;
		*ret = *ret & 0x01;
		return 0;
		return 0;
	case INHIBIT_CHARGE:
		if ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_INHIBIT, ret, battery))
			return -ENODEV;
		/* The inhibit charge status is in bit 0 */
		*ret = *ret & 0x01;
		return 0;
	default:
	default:
		pr_crit("wrong parameter: %d", what);
		pr_crit("wrong parameter: %d", what);
		return -EINVAL;
		return -EINVAL;
@@ -9342,6 +9351,22 @@ static int tpacpi_battery_set(int what, int battery, int value)
			return -ENODEV;
			return -ENODEV;
		}
		}
		return 0;
		return 0;
	case INHIBIT_CHARGE:
		/* When setting inhibit charge, we set a default value of
		 * always breaking on AC detach and the effective time is set to
		 * be permanent.
		 * The battery ID is in bits 4-5, 2 bits,
		 * the effective time is in bits 8-23, 2 bytes.
		 * A time of FFFF indicates forever.
		 */
		param = value;
		param |= battery << 4;
		param |= 0xFFFF << 8;
		if (ACPI_FAILURE(tpacpi_battery_acpi_eval(SET_INHIBIT, &ret, param))) {
			pr_err("failed to set inhibit charge on %d", battery);
			return -ENODEV;
		}
		return 0;
	default:
	default:
		pr_crit("wrong parameter: %d", what);
		pr_crit("wrong parameter: %d", what);
		return -EINVAL;
		return -EINVAL;
@@ -9389,6 +9414,8 @@ static int tpacpi_battery_probe(int battery)
	 * 4) Check for support
	 * 4) Check for support
	 * 5) Get the current force discharge status
	 * 5) Get the current force discharge status
	 * 6) Check for support
	 * 6) Check for support
	 * 7) Get the current inhibit charge status
	 * 8) Check for support
	 */
	 */
	if (acpi_has_method(hkey_handle, GET_START)) {
	if (acpi_has_method(hkey_handle, GET_START)) {
		if ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_START, &ret, battery)) {
		if ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_START, &ret, battery)) {
@@ -9435,6 +9462,16 @@ static int tpacpi_battery_probe(int battery)
			battery_info.batteries[battery].charge_behaviours |=
			battery_info.batteries[battery].charge_behaviours |=
				BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE);
				BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE);
	}
	}
	if (acpi_has_method(hkey_handle, GET_INHIBIT)) {
		if (ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_INHIBIT, &ret, battery))) {
			pr_err("Error probing battery inhibit charge; %d\n", battery);
			return -ENODEV;
		}
		/* Support is marked in bit 5 */
		if (ret & BIT(5))
			battery_info.batteries[battery].charge_behaviours |=
				BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE);
	}


	battery_info.batteries[battery].charge_behaviours |=
	battery_info.batteries[battery].charge_behaviours |=
		BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO);
		BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO);
@@ -9593,10 +9630,22 @@ static ssize_t charge_behaviour_show(struct device *dev,
	if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE)) {
	if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE)) {
		if (tpacpi_battery_get(FORCE_DISCHARGE, battery, &ret))
		if (tpacpi_battery_get(FORCE_DISCHARGE, battery, &ret))
			return -ENODEV;
			return -ENODEV;
		if (ret)
		if (ret) {
			active = POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE;
			active = POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE;
			goto out;
		}
	}

	if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE)) {
		if (tpacpi_battery_get(INHIBIT_CHARGE, battery, &ret))
			return -ENODEV;
		if (ret) {
			active = POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE;
			goto out;
		}
	}
	}


out:
	return power_supply_charge_behaviour_show(dev, available, active, buf);
	return power_supply_charge_behaviour_show(dev, available, active, buf);
}
}


@@ -9633,11 +9682,22 @@ static ssize_t charge_behaviour_store(struct device *dev,
	case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO:
	case POWER_SUPPLY_CHARGE_BEHAVIOUR_AUTO:
		if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE))
		if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE))
			ret = tpacpi_battery_set_validate(FORCE_DISCHARGE, battery, 0);
			ret = tpacpi_battery_set_validate(FORCE_DISCHARGE, battery, 0);
		if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE))
			ret = min(ret, tpacpi_battery_set_validate(INHIBIT_CHARGE, battery, 0));
		if (ret < 0)
		if (ret < 0)
			return ret;
			return ret;
		break;
		break;
	case POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE:
	case POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE:
		ret = tpacpi_battery_set_validate(FORCE_DISCHARGE, battery, 1);
		if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE))
			ret = tpacpi_battery_set_validate(INHIBIT_CHARGE, battery, 0);
		ret = min(ret, tpacpi_battery_set_validate(FORCE_DISCHARGE, battery, 1));
		if (ret < 0)
			return ret;
		break;
	case POWER_SUPPLY_CHARGE_BEHAVIOUR_INHIBIT_CHARGE:
		if (available & BIT(POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE))
			ret = tpacpi_battery_set_validate(FORCE_DISCHARGE, battery, 0);
		ret = min(ret, tpacpi_battery_set_validate(INHIBIT_CHARGE, battery, 1));
		if (ret < 0)
		if (ret < 0)
			return ret;
			return ret;
		break;
		break;