Linux Power Management development
 help / color / mirror / Atom feed
* [PATCH v2 0/8] Add sysfs entry for system load control
@ 2026-09-01 19:35 Waqar Hameed
  2026-09-01 19:35 ` [PATCH v2 1/8] power: supply: Pack power_supply_desc to eliminate holes Waqar Hameed
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: Waqar Hameed @ 2026-09-01 19:35 UTC (permalink / raw)
  To: Sebastian Reichel; +Cc: kernel, linux-pm, linux-kernel

During discussions of the development of a new driver [1], it was
concluded that a new `sysfs` ABI for controlling the connection from
power to system load is wanted. This patchset introduces this.

There are already several drivers that are controlling this, but with
their own custom `sysfs` entries. The drivers in this patchset were find
with a simple `grep` for `bat\s?fet` (there might be more?), and then
converted to use this new `sysfs` ABI. The old custom ABIs are left
untouched of course, for backward compatibility.

[1] https://lore.kernel.org/lkml/cover.1772201049.git.waqar.hameed@axis.com/

Changes in v2:

* Drop already merged patches (picked up by Sebastian in v1).
* Pack `struct power_supply_desc` so that an extra member doesn't
  increase the size unnecessarily too much.
* Use `power_supply_show_enum_with_available()` for
  `POWER_SUPPLY_LOAD_SWITCH`.
* Drop commit for selftest since properties using
  `power_supply_show_enum_with_available()` don't have any helper test
  functions. Should we add this (in a separate patch set)? I'll others
  decide if it's worth the churn...
* Add implementation for bq25630.

Link to v1: https://lore.kernel.org/lkml/cover.1782683551.git.waqar.hameed@axis.com/

Waqar Hameed (8):
  power: supply: Pack power_supply_desc to eliminate holes
  power: supply: Add sysfs entry for system load control
  power: supply: ltc4162-l: Use POWER_SUPPLY_PROP_LOAD_SWITCH
  power: supply: rt9471: Use POWER_SUPPLY_PROP_LOAD_SWITCH
  power: supply: rt9467: Use POWER_SUPPLY_PROP_LOAD_SWITCH
  power: supply: bq24257: Use POWER_SUPPLY_PROP_LOAD_SWITCH
  power: supply: bq24190: Use POWER_SUPPLY_PROP_LOAD_SWITCH
  power: supply: bq25630: Add support for BATFET control

 Documentation/ABI/testing/sysfs-class-power   | 25 ++++++
 .../ABI/testing/sysfs-class-power-ltc4162l    |  2 +
 .../ABI/testing/sysfs-class-power-rt9467      |  2 +
 .../ABI/testing/sysfs-class-power-rt9471      |  2 +
 drivers/power/supply/bq24190_charger.c        | 62 ++++++++++++++
 drivers/power/supply/bq24257_charger.c        | 43 +++++++++-
 drivers/power/supply/bq25630_charger.c        | 84 +++++++++++++++++++
 drivers/power/supply/ltc4162-l-charger.c      | 56 +++++++++++--
 drivers/power/supply/power_supply_sysfs.c     | 17 ++++
 drivers/power/supply/rt9467-charger.c         | 54 ++++++++++--
 drivers/power/supply/rt9471.c                 | 54 ++++++++++--
 include/linux/power_supply.h                  | 18 +++-
 12 files changed, 397 insertions(+), 22 deletions(-)


base-commit: 73e3f0710014fe6d4ed98cfc02292f6121db7558
-- 
2.43.0


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v2 1/8] power: supply: Pack power_supply_desc to eliminate holes
  2026-09-01 19:35 [PATCH v2 0/8] Add sysfs entry for system load control Waqar Hameed
@ 2026-09-01 19:35 ` Waqar Hameed
  2026-09-01 19:35 ` [PATCH v2 3/8] power: supply: ltc4162-l: Use POWER_SUPPLY_PROP_LOAD_SWITCH Waqar Hameed
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Waqar Hameed @ 2026-09-01 19:35 UTC (permalink / raw)
  To: Sebastian Reichel; +Cc: kernel, linux-pm, linux-kernel

`pahole` reports that there are two holes in `struct power_supply_desc`:

  struct power_supply_desc {
          const char  *              name;                 /*     0     4 */
          enum power_supply_type     type;                 /*     4     4 */
          u8                         charge_behaviours;    /*     8     1 */

          /* XXX 3 bytes hole, try to pack */

          u32                        charge_types;         /*    12     4 */
          u32                        usb_types;            /*    16     4 */
          const enum power_supply_property  * properties;  /*    20     4 */
          size_t                     num_properties;       /*    24     4 */
          int                        (*get_property)(...); /*    28     4 */
          int                        (*set_property)(...); /*    32     4 */
          int                        (*property_is_writeable)(...);  /*    36     4 */
          void                       (*external_power_changed)(...); /*    40     4 */
          int                        (*init)(struct power_supply *); /*    44     4 */
          bool                       no_thermal;           /*    48     1 */

          /* XXX 3 bytes hole, try to pack */

          int                        use_for_apm;          /*    52     4 */

          /* size: 56, cachelines: 1, members: 14 */
          /* sum members: 50, holes: 2, sum holes: 6 */
          /* last cacheline: 56 bytes */
  };

This can be optimized by moving `u8 charge_behaviours` to the end and
swapping `int use_for_apm` with `bool no_thermal`:

  struct power_supply_desc {
          const char  *              name;                 /*     0     4 */
          enum power_supply_type     type;                 /*     4     4 */
          u32                        charge_types;         /*     8     4 */
          u32                        usb_types;            /*    12     4 */
          const enum power_supply_property  * properties;  /*    16     4 */
          size_t                     num_properties;       /*    20     4 */
          int                        (*get_property)(...); /*    24     4 */
          int                        (*set_property)(...); /*    28     4 */
          int                        (*property_is_writeable)(...);  /*    32     4 */
          void                       (*external_power_changed)(...); /*    36     4 */
          int                        (*init)(struct power_supply *); /*    40     4 */
          int                        use_for_apm;          /*    44     4 */
          bool                       no_thermal;           /*    48     1 */
          u8                         charge_behaviours;    /*    49     1 */

          /* size: 52, cachelines: 1, members: 14 */
          /* padding: 2 */
          /* last cacheline: 52 bytes */
  };

Do this in order to save 4 bytes. This will also help when adding new
members in the future to this `struct`.

Signed-off-by: Waqar Hameed <waqar.hameed@axis.com>
---
 include/linux/power_supply.h | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index e749d21893352..fcd05f4a88833 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -259,7 +259,6 @@ struct power_supply_config {
 struct power_supply_desc {
 	const char *name;
 	enum power_supply_type type;
-	u8 charge_behaviours;
 	u32 charge_types;
 	u32 usb_types;
 	const enum power_supply_property *properties;
@@ -295,14 +294,17 @@ struct power_supply_desc {
 	 */
 	int (*init)(struct power_supply *psy);
 
+	/* For APM emulation, think legacy userspace. */
+	int use_for_apm;
+
 	/*
 	 * Set if thermal zone should not be created for this power supply.
 	 * For example for virtual supplies forwarding calls to actual
 	 * sensors or other supplies.
 	 */
 	bool no_thermal;
-	/* For APM emulation, think legacy userspace. */
-	int use_for_apm;
+
+	u8 charge_behaviours;
 };
 
 struct power_supply_ext {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 3/8] power: supply: ltc4162-l: Use POWER_SUPPLY_PROP_LOAD_SWITCH
  2026-09-01 19:35 [PATCH v2 0/8] Add sysfs entry for system load control Waqar Hameed
  2026-09-01 19:35 ` [PATCH v2 1/8] power: supply: Pack power_supply_desc to eliminate holes Waqar Hameed
@ 2026-09-01 19:35 ` Waqar Hameed
  2026-09-01 19:35 ` [PATCH v2 2/8] power: supply: Add sysfs entry for system load control Waqar Hameed
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Waqar Hameed @ 2026-09-01 19:35 UTC (permalink / raw)
  To: Sebastian Reichel; +Cc: kernel, linux-pm, linux-kernel

The framework supports controlling system load with
`POWER_SUPPLY_PROP_LOAD_SWITCH`. Use this to select ship mode, but keep
old custom `sysfs` ABI for backward compatibility. However, add a note
in ABI documentation that one should prefer the property `load_switch`
instead.

Signed-off-by: Waqar Hameed <waqar.hameed@axis.com>
---
 .../ABI/testing/sysfs-class-power-ltc4162l    |  2 +
 drivers/power/supply/ltc4162-l-charger.c      | 56 +++++++++++++++++--
 2 files changed, 52 insertions(+), 6 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-class-power-ltc4162l b/Documentation/ABI/testing/sysfs-class-power-ltc4162l
index ba30db93052bf..ad46ad834af05 100644
--- a/Documentation/ABI/testing/sysfs-class-power-ltc4162l
+++ b/Documentation/ABI/testing/sysfs-class-power-ltc4162l
@@ -77,6 +77,8 @@ Description:
 		The ship mode, when armed, activates once the input voltage
 		drops below 1V.
 
+		Note: use /sys/class/power_supply/ltc4162-l/load_switch instead.
+
 		Access: Read, Write
 
 		Valid values: 0 (disable) or 1 (enable)
diff --git a/drivers/power/supply/ltc4162-l-charger.c b/drivers/power/supply/ltc4162-l-charger.c
index 5c09e0368e6f0..01b0511da9aee 100644
--- a/drivers/power/supply/ltc4162-l-charger.c
+++ b/drivers/power/supply/ltc4162-l-charger.c
@@ -755,6 +755,41 @@ static int ltc4162l_set_term_current(struct ltc4162l_info *info,
 				  BIT(2), BIT(2));
 }
 
+static int ltc4162l_get_ship_mode(struct ltc4162l_info *info,
+				  union power_supply_propval *val)
+{
+	unsigned int regval;
+	int ret;
+
+	ret = regmap_read(info->regmap, LTC4162L_ARM_SHIP_MODE, &regval);
+	if (ret < 0)
+		return ret;
+
+	val->intval = regval == LTC4162L_ARM_SHIP_MODE_MAGIC ?
+			      POWER_SUPPLY_LOAD_SWITCH_SHIP :
+			      POWER_SUPPLY_LOAD_SWITCH_ON;
+
+	return 0;
+}
+
+static int ltc4162l_set_ship_mode(struct ltc4162l_info *info, int value)
+{
+	unsigned int regval;
+
+	switch (value) {
+	case POWER_SUPPLY_LOAD_SWITCH_ON:
+		regval = 0;
+		break;
+	case POWER_SUPPLY_LOAD_SWITCH_SHIP:
+		regval = LTC4162L_ARM_SHIP_MODE_MAGIC;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return regmap_write(info->regmap, LTC4162L_ARM_SHIP_MODE, regval);
+}
+
 /* Custom properties */
 static const char * const ltc4162l_charge_status_name[] = {
 	"ilim_reg_active", /* 32 */
@@ -890,15 +925,15 @@ static ssize_t arm_ship_mode_show(struct device *dev,
 {
 	struct power_supply *psy = to_power_supply(dev);
 	struct ltc4162l_info *info = power_supply_get_drvdata(psy);
-	unsigned int regval;
+	union power_supply_propval val;
 	int ret;
 
-	ret = regmap_read(info->regmap, LTC4162L_ARM_SHIP_MODE, &regval);
-	if (ret)
+	ret = ltc4162l_get_ship_mode(info, &val);
+	if (ret < 0)
 		return ret;
 
 	return sysfs_emit(buf, "%u\n",
-		regval == LTC4162L_ARM_SHIP_MODE_MAGIC ? 1 : 0);
+			  val.intval == POWER_SUPPLY_LOAD_SWITCH_SHIP ? 1 : 0);
 }
 
 static ssize_t arm_ship_mode_store(struct device *dev,
@@ -915,8 +950,9 @@ static ssize_t arm_ship_mode_store(struct device *dev,
 	if (ret < 0)
 		return ret;
 
-	ret = regmap_write(info->regmap, LTC4162L_ARM_SHIP_MODE,
-				value ? LTC4162L_ARM_SHIP_MODE_MAGIC : 0);
+	ret = ltc4162l_set_ship_mode(info,
+				     value ? POWER_SUPPLY_LOAD_SWITCH_SHIP :
+					     POWER_SUPPLY_LOAD_SWITCH_ON);
 	if (ret < 0)
 		return ret;
 
@@ -981,6 +1017,8 @@ static int ltc4162l_get_property(struct power_supply *psy,
 		return chip_info->get_die_temp(info, val);
 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
 		return ltc4162l_get_term_current(info, val);
+	case POWER_SUPPLY_PROP_LOAD_SWITCH:
+		return ltc4162l_get_ship_mode(info, val);
 	default:
 		return -EINVAL;
 	}
@@ -1003,6 +1041,8 @@ static int ltc4162l_set_property(struct power_supply *psy,
 		return ltc4162l_set_iin_limit(info, val->intval);
 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
 		return ltc4162l_set_term_current(info, val->intval);
+	case POWER_SUPPLY_PROP_LOAD_SWITCH:
+		return ltc4162l_set_ship_mode(info, val->intval);
 	default:
 		return -EINVAL;
 	}
@@ -1016,6 +1056,7 @@ static int ltc4162l_property_is_writeable(struct power_supply *psy,
 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
+	case POWER_SUPPLY_PROP_LOAD_SWITCH:
 		return 1;
 	default:
 		return 0;
@@ -1037,10 +1078,13 @@ static enum power_supply_property ltc4162l_properties[] = {
 	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
 	POWER_SUPPLY_PROP_TEMP,
 	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
+	POWER_SUPPLY_PROP_LOAD_SWITCH,
 };
 
 static const struct power_supply_desc ltc4162l_desc = {
 	.type		= POWER_SUPPLY_TYPE_MAINS,
+	.load_switches	= BIT(POWER_SUPPLY_LOAD_SWITCH_ON) |
+			  BIT(POWER_SUPPLY_LOAD_SWITCH_SHIP),
 	.properties	= ltc4162l_properties,
 	.num_properties	= ARRAY_SIZE(ltc4162l_properties),
 	.get_property	= ltc4162l_get_property,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 2/8] power: supply: Add sysfs entry for system load control
  2026-09-01 19:35 [PATCH v2 0/8] Add sysfs entry for system load control Waqar Hameed
  2026-09-01 19:35 ` [PATCH v2 1/8] power: supply: Pack power_supply_desc to eliminate holes Waqar Hameed
  2026-09-01 19:35 ` [PATCH v2 3/8] power: supply: ltc4162-l: Use POWER_SUPPLY_PROP_LOAD_SWITCH Waqar Hameed
@ 2026-09-01 19:35 ` Waqar Hameed
  2026-09-01 19:35 ` [PATCH v2 5/8] power: supply: rt9467: Use POWER_SUPPLY_PROP_LOAD_SWITCH Waqar Hameed
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Waqar Hameed @ 2026-09-01 19:35 UTC (permalink / raw)
  To: Sebastian Reichel; +Cc: kernel, linux-pm, linux-kernel

There are devices that can control the connection from power to system
load. For example, with a field-effect transistor between a battery and
the system load (BATFET). Drivers for these devices are currently
enrolling their own custom `sysfs` property to control this.

In order to unify this, add a new `sysfs` entry for controlling such
switch and corresponding `power_supply_property` with `enum` values. The
obvious states are "on" and "off", i.e. there is a connection or not,
respectively. However, many devices can also enter special modes such as
"low-power", "shipping" or "deep sleep".

Since the members in `struct power_supply_desc` already are ordered,
adding `load_switches` only increases the size with 4 bytes, as can be
seen from `pahole`:

  struct power_supply_desc {
          const char  *              name;                 /*     0     4 */
          enum power_supply_type     type;                 /*     4     4 */
          u32                        charge_types;         /*     8     4 */
          u32                        usb_types;            /*    12     4 */
          u32                        load_switches;        /*    16     4 */
          const enum power_supply_property  * properties;  /*    20     4 */
          size_t                     num_properties;       /*    24     4 */
          int                        (*get_property)(...); /*    28     4 */
          int                        (*set_property)(...); /*    32     4 */
          int                        (*property_is_writeable)(...);  /*    36     4 */
          void                       (*external_power_changed)(...); /*    40     4 */
          int                        (*init)(struct power_supply *); /*    44     4 */
          int                        use_for_apm;          /*    48     4 */
          bool                       no_thermal;           /*    52     1 */
          u8                         charge_behaviours;    /*    53     1 */

          /* size: 56, cachelines: 1, members: 15 */
          /* padding: 2 */
          /* last cacheline: 56 bytes */
  };

Signed-off-by: Waqar Hameed <waqar.hameed@axis.com>
---
 Documentation/ABI/testing/sysfs-class-power | 25 +++++++++++++++++++++
 drivers/power/supply/power_supply_sysfs.c   | 17 ++++++++++++++
 include/linux/power_supply.h                | 10 +++++++++
 3 files changed, 52 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-class-power b/Documentation/ABI/testing/sysfs-class-power
index 5641f1fd5fd6f..93f2398125d88 100644
--- a/Documentation/ABI/testing/sysfs-class-power
+++ b/Documentation/ABI/testing/sysfs-class-power
@@ -590,6 +590,31 @@ Description:
 
 		Valid values: 0 - 100 (percent)
 
+What:		/sys/class/power_supply/<supply_name>/load_switch
+Date:		June 2026
+Contact:	linux-pm@vger.kernel.org
+Description:
+		Devices can control the connection from power to system load.
+		For example, with a field-effect transistor between a battery
+		and the system load (BATFET). This entry controls such switch.
+		The obvious states are "on" and "off", i.e. there is a
+		connection or not, respectively. However, many devices can also
+		enter special modes such as "low-power", "shipping" or "deep
+		sleep". In these modes the switch is usually off and the
+		quiescent current quite low.
+
+		Access: Read, Write
+
+		Valid values:
+
+		============= ==================================
+		"Unknown" (0) Unknown mode.
+		"On"      (1) Power is connected to the load.
+		"Off"     (2) Power is disconnected to the load.
+		"Standby" (3) Low-power mode.
+		"Ship"    (4) Ship mode.
+		============= ==================================
+
 **USB Properties**
 
 What:		/sys/class/power_supply/<supply_name>/input_current_limit
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 9d6b24856c8b0..b0f524d152cf6 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -152,6 +152,14 @@ static const char * const POWER_SUPPLY_CHARGE_BEHAVIOUR_TEXT[] = {
 	[POWER_SUPPLY_CHARGE_BEHAVIOUR_FORCE_DISCHARGE]		= "force-discharge",
 };
 
+static const char *const POWER_SUPPLY_LOAD_SWITCH_TEXT[] = {
+	[POWER_SUPPLY_LOAD_SWITCH_UNKNOWN] = "Unknown",
+	[POWER_SUPPLY_LOAD_SWITCH_ON]	   = "On",
+	[POWER_SUPPLY_LOAD_SWITCH_OFF]	   = "Off",
+	[POWER_SUPPLY_LOAD_SWITCH_STANDBY] = "Standby",
+	[POWER_SUPPLY_LOAD_SWITCH_SHIP]	   = "Ship",
+};
+
 static struct power_supply_attr power_supply_attrs[] __ro_after_init = {
 	/* Properties of type `int' */
 	POWER_SUPPLY_ENUM_ATTR(STATUS),
@@ -231,6 +239,7 @@ static struct power_supply_attr power_supply_attrs[] __ro_after_init = {
 	POWER_SUPPLY_ATTR(MANUFACTURE_DAY),
 	POWER_SUPPLY_ATTR(INTERNAL_RESISTANCE),
 	POWER_SUPPLY_ATTR(STATE_OF_HEALTH),
+	POWER_SUPPLY_ENUM_ATTR(LOAD_SWITCH),
 	/* Properties of type `const char *' */
 	POWER_SUPPLY_ATTR(MODEL_NAME),
 	POWER_SUPPLY_ATTR(MANUFACTURER),
@@ -400,6 +409,14 @@ static ssize_t power_supply_format_property(struct device *dev,
 		ret = power_supply_show_charge_types(dev, psy,
 						     value.intval, buf);
 		break;
+	case POWER_SUPPLY_PROP_LOAD_SWITCH:
+		if (uevent) /* no possible values in uevents */
+			goto default_format;
+		ret = power_supply_show_enum_with_available(
+			dev, POWER_SUPPLY_LOAD_SWITCH_TEXT,
+			ARRAY_SIZE(POWER_SUPPLY_LOAD_SWITCH_TEXT),
+			psy->desc->load_switches, value.intval, buf);
+		break;
 	case POWER_SUPPLY_PROP_MODEL_NAME ... POWER_SUPPLY_PROP_SERIAL_NUMBER:
 		ret = sysfs_emit(buf, "%s\n", value.strval);
 		break;
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index fcd05f4a88833..f6cbeffda6534 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -104,6 +104,14 @@ enum {
 	POWER_SUPPLY_SCOPE_DEVICE,
 };
 
+enum {
+	POWER_SUPPLY_LOAD_SWITCH_UNKNOWN = 0,
+	POWER_SUPPLY_LOAD_SWITCH_ON,
+	POWER_SUPPLY_LOAD_SWITCH_OFF,
+	POWER_SUPPLY_LOAD_SWITCH_STANDBY,
+	POWER_SUPPLY_LOAD_SWITCH_SHIP,
+};
+
 enum power_supply_property {
 	/* Properties of type `int' */
 	POWER_SUPPLY_PROP_STATUS = 0,
@@ -182,6 +190,7 @@ enum power_supply_property {
 	POWER_SUPPLY_PROP_MANUFACTURE_DAY,
 	POWER_SUPPLY_PROP_INTERNAL_RESISTANCE,
 	POWER_SUPPLY_PROP_STATE_OF_HEALTH,
+	POWER_SUPPLY_PROP_LOAD_SWITCH,
 	/* Properties of type `const char *' */
 	POWER_SUPPLY_PROP_MODEL_NAME,
 	POWER_SUPPLY_PROP_MANUFACTURER,
@@ -261,6 +270,7 @@ struct power_supply_desc {
 	enum power_supply_type type;
 	u32 charge_types;
 	u32 usb_types;
+	u32 load_switches;
 	const enum power_supply_property *properties;
 	size_t num_properties;
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 4/8] power: supply: rt9471: Use POWER_SUPPLY_PROP_LOAD_SWITCH
  2026-09-01 19:35 [PATCH v2 0/8] Add sysfs entry for system load control Waqar Hameed
                   ` (4 preceding siblings ...)
  2026-09-01 19:35 ` [PATCH v2 6/8] power: supply: bq24257: " Waqar Hameed
@ 2026-09-01 19:35 ` Waqar Hameed
  2026-09-01 19:35 ` [PATCH v2 8/8] power: supply: bq25630: Add support for BATFET control Waqar Hameed
  2026-09-01 19:35 ` [PATCH v2 7/8] power: supply: bq24190: Use POWER_SUPPLY_PROP_LOAD_SWITCH Waqar Hameed
  7 siblings, 0 replies; 9+ messages in thread
From: Waqar Hameed @ 2026-09-01 19:35 UTC (permalink / raw)
  To: Sebastian Reichel; +Cc: kernel, linux-pm, linux-kernel

The framework supports controlling system load with
`POWER_SUPPLY_PROP_LOAD_SWITCH`. Use this to control the BATFET, but
keep old custom `sysfs` ABI for backward compatibility. However, add a
note in ABI documentation that one should prefer the property
`load_switch` instead.

Signed-off-by: Waqar Hameed <waqar.hameed@axis.com>
---
 .../ABI/testing/sysfs-class-power-rt9471      |  2 +
 drivers/power/supply/rt9471.c                 | 54 ++++++++++++++++---
 2 files changed, 50 insertions(+), 6 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-class-power-rt9471 b/Documentation/ABI/testing/sysfs-class-power-rt9471
index 0a390ee5ac21c..90cf94c1cbf6b 100644
--- a/Documentation/ABI/testing/sysfs-class-power-rt9471
+++ b/Documentation/ABI/testing/sysfs-class-power-rt9471
@@ -11,6 +11,8 @@ Description:
 		mode. 'Disable' also can help to leave it, but it's more like to abort
 		the action before the device really enter shipping mode.
 
+		Note: use /sys/class/power_supply/rt9471-*/load_switch instead.
+
 		Access: Read, Write
 		Valid values:
 		- 1: enabled
diff --git a/drivers/power/supply/rt9471.c b/drivers/power/supply/rt9471.c
index b67f5abaa9938..b16d39a774dd4 100644
--- a/drivers/power/supply/rt9471.c
+++ b/drivers/power/supply/rt9471.c
@@ -265,6 +265,39 @@ static int rt9471_get_ieoc(struct rt9471_chip *chip, int *microamp)
 	return rt9471_get_value_by_field_range(chip, F_IEOC_CHG, RT9471_RANGE_IEOC, microamp);
 }
 
+static int rt9471_set_batfet(struct rt9471_chip *chip, int val)
+{
+	unsigned int regval;
+
+	switch (val) {
+	case POWER_SUPPLY_LOAD_SWITCH_ON:
+		regval = 0;
+		break;
+	case POWER_SUPPLY_LOAD_SWITCH_OFF:
+		regval = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return regmap_field_write(chip->rm_fields[F_BATFET_DIS], regval);
+}
+
+static int rt9471_get_batfet(struct rt9471_chip *chip, int *val)
+{
+	unsigned int regval;
+	int ret;
+
+	ret = regmap_field_read(chip->rm_fields[F_BATFET_DIS], &regval);
+	if (ret < 0)
+		return ret;
+
+	*val = regval ? POWER_SUPPLY_LOAD_SWITCH_OFF :
+			POWER_SUPPLY_LOAD_SWITCH_ON;
+
+	return 0;
+}
+
 static int rt9471_get_status(struct rt9471_chip *chip, int *status)
 {
 	unsigned int ic_stat;
@@ -342,6 +375,7 @@ static enum power_supply_property rt9471_charger_properties[] = {
 	POWER_SUPPLY_PROP_USB_TYPE,
 	POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
 	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
+	POWER_SUPPLY_PROP_LOAD_SWITCH,
 	POWER_SUPPLY_PROP_MODEL_NAME,
 	POWER_SUPPLY_PROP_MANUFACTURER,
 };
@@ -358,6 +392,7 @@ static int rt9471_charger_property_is_writeable(struct power_supply *psy,
 	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
 	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
+	case POWER_SUPPLY_PROP_LOAD_SWITCH:
 		return 1;
 	default:
 		return 0;
@@ -393,6 +428,8 @@ static int rt9471_charger_set_property(struct power_supply *psy,
 			chip, F_IPRE_CHG, RT9471_RANGE_IPRE, val->intval);
 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
 		return rt9471_set_ieoc(chip, val->intval);
+	case POWER_SUPPLY_PROP_LOAD_SWITCH:
+		return rt9471_set_batfet(chip, val->intval);
 	default:
 		return -EINVAL;
 	}
@@ -439,6 +476,8 @@ static int rt9471_charger_get_property(struct power_supply *psy,
 			chip, F_IPRE_CHG, RT9471_RANGE_IPRE, &val->intval);
 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
 		return rt9471_get_ieoc(chip, &val->intval);
+	case POWER_SUPPLY_PROP_LOAD_SWITCH:
+		return rt9471_get_batfet(chip, &val->intval);
 	case POWER_SUPPLY_PROP_MODEL_NAME:
 		val->strval = rt9471_model;
 		return 0;
@@ -649,14 +688,14 @@ static ssize_t sysoff_enable_show(struct device *dev,
 				  struct device_attribute *attr, char *buf)
 {
 	struct rt9471_chip *chip = psy_device_to_chip(dev);
-	unsigned int sysoff_enable;
+	unsigned int val;
 	int ret;
 
-	ret = regmap_field_read(chip->rm_fields[F_BATFET_DIS], &sysoff_enable);
-	if (ret)
+	ret = rt9471_get_batfet(chip, &val);
+	if (ret < 0)
 		return ret;
 
-	return sysfs_emit(buf, "%d\n", sysoff_enable);
+	return sysfs_emit(buf, "%d\n", val == POWER_SUPPLY_LOAD_SWITCH_OFF);
 }
 
 static ssize_t sysoff_enable_store(struct device *dev,
@@ -671,8 +710,9 @@ static ssize_t sysoff_enable_store(struct device *dev,
 	if (ret)
 		return ret;
 
-	ret = regmap_field_write(chip->rm_fields[F_BATFET_DIS], !!tmp);
-	if (ret)
+	ret = rt9471_set_batfet(chip, tmp ? POWER_SUPPLY_LOAD_SWITCH_OFF :
+					    POWER_SUPPLY_LOAD_SWITCH_ON);
+	if (ret < 0)
 		return ret;
 
 	return count;
@@ -744,6 +784,8 @@ static int rt9471_register_psy(struct rt9471_chip *chip)
 			  BIT(POWER_SUPPLY_USB_TYPE_DCP) |
 			  BIT(POWER_SUPPLY_USB_TYPE_APPLE_BRICK_ID) |
 			  BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN);
+	desc->load_switches = BIT(POWER_SUPPLY_LOAD_SWITCH_ON) |
+			      BIT(POWER_SUPPLY_LOAD_SWITCH_OFF);
 	desc->properties = rt9471_charger_properties;
 	desc->num_properties = ARRAY_SIZE(rt9471_charger_properties);
 	desc->get_property = rt9471_charger_get_property;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 5/8] power: supply: rt9467: Use POWER_SUPPLY_PROP_LOAD_SWITCH
  2026-09-01 19:35 [PATCH v2 0/8] Add sysfs entry for system load control Waqar Hameed
                   ` (2 preceding siblings ...)
  2026-09-01 19:35 ` [PATCH v2 2/8] power: supply: Add sysfs entry for system load control Waqar Hameed
@ 2026-09-01 19:35 ` Waqar Hameed
  2026-09-01 19:35 ` [PATCH v2 6/8] power: supply: bq24257: " Waqar Hameed
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Waqar Hameed @ 2026-09-01 19:35 UTC (permalink / raw)
  To: Sebastian Reichel; +Cc: kernel, linux-pm, linux-kernel

The framework supports controlling system load with
`POWER_SUPPLY_PROP_LOAD_SWITCH`. Use this to control the BATFET, but
keep old custom `sysfs` ABI for backward compatibility. However, add a
note in ABI documentation that one should prefer the property
`load_switch` instead.

Signed-off-by: Waqar Hameed <waqar.hameed@axis.com>
---
 .../ABI/testing/sysfs-class-power-rt9467      |  2 +
 drivers/power/supply/rt9467-charger.c         | 54 ++++++++++++++++---
 2 files changed, 50 insertions(+), 6 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-class-power-rt9467 b/Documentation/ABI/testing/sysfs-class-power-rt9467
index 619b7c45d145d..bfbfd78ec1c19 100644
--- a/Documentation/ABI/testing/sysfs-class-power-rt9467
+++ b/Documentation/ABI/testing/sysfs-class-power-rt9467
@@ -13,6 +13,8 @@ Description:
 		'Disable' also can help to leave it, but it's more like to
 		abort the action before the device really enter shipping mode.
 
+		Note: use /sys/class/power_supply/rt9467-*/load_switch instead.
+
 		Access: Read, Write
 		Valid values:
 		- 1: enabled
diff --git a/drivers/power/supply/rt9467-charger.c b/drivers/power/supply/rt9467-charger.c
index a9a83b263e187..f0d10f44b1090 100644
--- a/drivers/power/supply/rt9467-charger.c
+++ b/drivers/power/supply/rt9467-charger.c
@@ -633,6 +633,39 @@ static int rt9467_psy_set_ieoc(struct rt9467_chg_data *data, int microamp)
 	return ret;
 }
 
+static int rt9467_set_batfet(struct rt9467_chg_data *data, int val)
+{
+	unsigned int regval;
+
+	switch (val) {
+	case POWER_SUPPLY_LOAD_SWITCH_ON:
+		regval = 0;
+		break;
+	case POWER_SUPPLY_LOAD_SWITCH_OFF:
+		regval = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return regmap_field_write(data->rm_field[F_SHIP_MODE], regval);
+}
+
+static int rt9467_get_batfet(struct rt9467_chg_data *data, int *val)
+{
+	unsigned int regval;
+	int ret;
+
+	ret = regmap_field_read(data->rm_field[F_SHIP_MODE], &regval);
+	if (ret < 0)
+		return ret;
+
+	*val = regval ? POWER_SUPPLY_LOAD_SWITCH_OFF :
+			POWER_SUPPLY_LOAD_SWITCH_ON;
+
+	return 0;
+}
+
 static const enum power_supply_property rt9467_chg_properties[] = {
 	POWER_SUPPLY_PROP_STATUS,
 	POWER_SUPPLY_PROP_ONLINE,
@@ -648,6 +681,7 @@ static const enum power_supply_property rt9467_chg_properties[] = {
 	POWER_SUPPLY_PROP_USB_TYPE,
 	POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
 	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
+	POWER_SUPPLY_PROP_LOAD_SWITCH,
 };
 
 static int rt9467_psy_get_property(struct power_supply *psy,
@@ -711,6 +745,8 @@ static int rt9467_psy_get_property(struct power_supply *psy,
 		val->intval = data->ieoc_ua;
 		mutex_unlock(&data->ichg_ieoc_lock);
 		return 0;
+	case POWER_SUPPLY_PROP_LOAD_SWITCH:
+		return rt9467_get_batfet(data, &val->intval);
 	default:
 		return -ENODATA;
 	}
@@ -747,6 +783,8 @@ static int rt9467_psy_set_property(struct power_supply *psy,
 						    RT9467_RANGE_IPREC, val->intval);
 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
 		return rt9467_psy_set_ieoc(data, val->intval);
+	case POWER_SUPPLY_PROP_LOAD_SWITCH:
+		return rt9467_set_batfet(data, val->intval);
 	default:
 		return -EINVAL;
 	}
@@ -764,6 +802,7 @@ static int rt9467_chg_prop_is_writeable(struct power_supply *psy,
 	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
 	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
+	case POWER_SUPPLY_PROP_LOAD_SWITCH:
 		return 1;
 	default:
 		return 0;
@@ -777,6 +816,8 @@ static const struct power_supply_desc rt9467_chg_psy_desc = {
 		     BIT(POWER_SUPPLY_USB_TYPE_CDP) |
 		     BIT(POWER_SUPPLY_USB_TYPE_DCP) |
 		     BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN),
+	.load_switches = BIT(POWER_SUPPLY_LOAD_SWITCH_ON) |
+			 BIT(POWER_SUPPLY_LOAD_SWITCH_OFF),
 	.properties = rt9467_chg_properties,
 	.num_properties = ARRAY_SIZE(rt9467_chg_properties),
 	.property_is_writeable = rt9467_chg_prop_is_writeable,
@@ -793,14 +834,14 @@ static ssize_t sysoff_enable_show(struct device *dev,
 				  struct device_attribute *attr, char *buf)
 {
 	struct rt9467_chg_data *data = psy_device_to_chip(dev);
-	unsigned int sysoff_enable;
+	int val;
 	int ret;
 
-	ret = regmap_field_read(data->rm_field[F_SHIP_MODE], &sysoff_enable);
-	if (ret)
+	ret = rt9467_get_batfet(data, &val);
+	if (ret < 0)
 		return ret;
 
-	return sysfs_emit(buf, "%d\n", sysoff_enable);
+	return sysfs_emit(buf, "%d\n", val == POWER_SUPPLY_LOAD_SWITCH_OFF);
 }
 
 static ssize_t sysoff_enable_store(struct device *dev,
@@ -815,8 +856,9 @@ static ssize_t sysoff_enable_store(struct device *dev,
 	if (ret)
 		return ret;
 
-	ret = regmap_field_write(data->rm_field[F_SHIP_MODE], !!tmp);
-	if (ret)
+	ret = rt9467_set_batfet(data, tmp ? POWER_SUPPLY_LOAD_SWITCH_OFF :
+					    POWER_SUPPLY_LOAD_SWITCH_ON);
+	if (ret < 0)
 		return ret;
 
 	return count;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 6/8] power: supply: bq24257: Use POWER_SUPPLY_PROP_LOAD_SWITCH
  2026-09-01 19:35 [PATCH v2 0/8] Add sysfs entry for system load control Waqar Hameed
                   ` (3 preceding siblings ...)
  2026-09-01 19:35 ` [PATCH v2 5/8] power: supply: rt9467: Use POWER_SUPPLY_PROP_LOAD_SWITCH Waqar Hameed
@ 2026-09-01 19:35 ` Waqar Hameed
  2026-09-01 19:35 ` [PATCH v2 4/8] power: supply: rt9471: " Waqar Hameed
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Waqar Hameed @ 2026-09-01 19:35 UTC (permalink / raw)
  To: Sebastian Reichel; +Cc: kernel, linux-pm, linux-kernel

The framework supports controlling system load with
`POWER_SUPPLY_PROP_LOAD_SWITCH`. Use this to control `SYSOFF`, but keep
old custom `sysfs` ABI for backward compatibility.

Signed-off-by: Waqar Hameed <waqar.hameed@axis.com>
---
 drivers/power/supply/bq24257_charger.c | 43 +++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)

diff --git a/drivers/power/supply/bq24257_charger.c b/drivers/power/supply/bq24257_charger.c
index 944a7aa6f187d..8eea7d0395ce0 100644
--- a/drivers/power/supply/bq24257_charger.c
+++ b/drivers/power/supply/bq24257_charger.c
@@ -295,6 +295,40 @@ static int bq24257_set_input_current_limit(struct bq24257_device *bq,
 						    BQ24257_IILIMIT_MAP_SIZE));
 }
 
+static int bq24257_get_sys_switch(struct bq24257_device *bq,
+				  union power_supply_propval *val)
+{
+	int ret;
+
+	ret = bq24257_field_read(bq, F_SYSOFF);
+	if (ret < 0)
+		return ret;
+
+	val->intval = ret ? POWER_SUPPLY_LOAD_SWITCH_OFF :
+			    POWER_SUPPLY_LOAD_SWITCH_ON;
+
+	return 0;
+}
+
+static int bq24257_set_sys_switch(struct bq24257_device *bq,
+				  const union power_supply_propval *val)
+{
+	u8 regval;
+
+	switch (val->intval) {
+	case POWER_SUPPLY_LOAD_SWITCH_ON:
+		regval = 0;
+		break;
+	case POWER_SUPPLY_LOAD_SWITCH_OFF:
+		regval = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return bq24257_field_write(bq, F_SYSOFF, regval);
+}
+
 static int bq24257_power_supply_get_property(struct power_supply *psy,
 					     enum power_supply_property psp,
 					     union power_supply_propval *val)
@@ -381,7 +415,8 @@ static int bq24257_power_supply_get_property(struct power_supply *psy,
 
 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
 		return bq24257_get_input_current_limit(bq, val);
-
+	case POWER_SUPPLY_PROP_LOAD_SWITCH:
+		return bq24257_get_sys_switch(bq, val);
 	default:
 		return -EINVAL;
 	}
@@ -398,6 +433,8 @@ static int bq24257_power_supply_set_property(struct power_supply *psy,
 	switch (prop) {
 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
 		return bq24257_set_input_current_limit(bq, val);
+	case POWER_SUPPLY_PROP_LOAD_SWITCH:
+		return bq24257_set_sys_switch(bq, val);
 	default:
 		return -EINVAL;
 	}
@@ -408,6 +445,7 @@ static int bq24257_power_supply_property_is_writeable(struct power_supply *psy,
 {
 	switch (psp) {
 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+	case POWER_SUPPLY_PROP_LOAD_SWITCH:
 		return true;
 	default:
 		return false;
@@ -740,6 +778,7 @@ static enum power_supply_property bq24257_power_supply_props[] = {
 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
 	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
 	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+	POWER_SUPPLY_PROP_LOAD_SWITCH,
 };
 
 static char *bq24257_charger_supplied_to[] = {
@@ -749,6 +788,8 @@ static char *bq24257_charger_supplied_to[] = {
 static const struct power_supply_desc bq24257_power_supply_desc = {
 	.name = "bq24257-charger",
 	.type = POWER_SUPPLY_TYPE_USB,
+	.load_switches = BIT(POWER_SUPPLY_LOAD_SWITCH_ON) |
+			 BIT(POWER_SUPPLY_LOAD_SWITCH_OFF),
 	.properties = bq24257_power_supply_props,
 	.num_properties = ARRAY_SIZE(bq24257_power_supply_props),
 	.get_property = bq24257_power_supply_get_property,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 7/8] power: supply: bq24190: Use POWER_SUPPLY_PROP_LOAD_SWITCH
  2026-09-01 19:35 [PATCH v2 0/8] Add sysfs entry for system load control Waqar Hameed
                   ` (6 preceding siblings ...)
  2026-09-01 19:35 ` [PATCH v2 8/8] power: supply: bq25630: Add support for BATFET control Waqar Hameed
@ 2026-09-01 19:35 ` Waqar Hameed
  7 siblings, 0 replies; 9+ messages in thread
From: Waqar Hameed @ 2026-09-01 19:35 UTC (permalink / raw)
  To: Sebastian Reichel; +Cc: kernel, linux-pm, linux-kernel

The `online`-property has historically been (ab)used for controlling the
BATFET in this driver. The framework supports controlling system load
with `POWER_SUPPLY_PROP_LOAD_SWITCH`. Use this to control the BATFET,
but keep the support for `online` in order to have ABI backward
compatibility.

Moreover, don't bother with converting the `online`-functions to use the
new `charger_get/set_batfet_ctrl()` to keep the code more readable. It's
already quite messy, e.g. `charge_set_online()` calls
`battery_set_online()`.

Signed-off-by: Waqar Hameed <waqar.hameed@axis.com>
---
 drivers/power/supply/bq24190_charger.c | 62 ++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c
index 4bea6fd83c36f..d67bf25ec6ec1 100644
--- a/drivers/power/supply/bq24190_charger.c
+++ b/drivers/power/supply/bq24190_charger.c
@@ -1294,6 +1294,58 @@ static int bq24190_charger_set_iinlimit(struct bq24190_dev_info *bdi,
 			ARRAY_SIZE(bq24190_isc_iinlim_values), val->intval);
 }
 
+static int bq24190_charger_get_batfet_ctrl(struct bq24190_dev_info *bdi,
+					   union power_supply_propval *val)
+{
+	u8 regval;
+	int ret;
+
+	ret = bq24190_read_mask(bdi, BQ24190_REG_MOC,
+				BQ24190_REG_MOC_BATFET_DISABLE_MASK,
+				BQ24190_REG_MOC_BATFET_DISABLE_SHIFT,
+				&regval);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Datasheet defines shipping mode as BATFET off _and_ the watchdog
+	 * disabled. Since the watchdog is disabled during the whole lifetime
+	 * (from probe), shipping mode is the only "off" state that can be
+	 * achievable.
+	 */
+	val->intval = regval ? POWER_SUPPLY_LOAD_SWITCH_SHIP :
+			       POWER_SUPPLY_LOAD_SWITCH_ON;
+	return 0;
+}
+
+static int
+bq24190_charger_set_batfet_ctrl(struct bq24190_dev_info *bdi,
+				const union power_supply_propval *val)
+{
+	u8 regval;
+
+	/*
+	 * Datasheet defines shipping mode as BATFET off _and_ the watchdog
+	 * disabled. Since the watchdog is disabled during the whole lifetime
+	 * (from probe), shipping mode is the only "off" state that can be
+	 * achievable.
+	 */
+	switch (val->intval) {
+	case POWER_SUPPLY_LOAD_SWITCH_ON:
+		regval = 0;
+		break;
+	case POWER_SUPPLY_LOAD_SWITCH_SHIP:
+		regval = 1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return bq24190_write_mask(bdi, BQ24190_REG_MOC,
+				  BQ24190_REG_MOC_BATFET_DISABLE_MASK,
+				  BQ24190_REG_MOC_BATFET_DISABLE_SHIFT, regval);
+}
+
 static int bq24190_charger_get_property(struct power_supply *psy,
 		enum power_supply_property psp, union power_supply_propval *val)
 {
@@ -1350,6 +1402,9 @@ static int bq24190_charger_get_property(struct power_supply *psy,
 		val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
 		ret = 0;
 		break;
+	case POWER_SUPPLY_PROP_LOAD_SWITCH:
+		ret = bq24190_charger_get_batfet_ctrl(bdi, val);
+		break;
 	case POWER_SUPPLY_PROP_MODEL_NAME:
 		val->strval = bdi->model_name;
 		ret = 0;
@@ -1400,6 +1455,9 @@ static int bq24190_charger_set_property(struct power_supply *psy,
 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
 		ret = bq24190_charger_set_iinlimit(bdi, val);
 		break;
+	case POWER_SUPPLY_PROP_LOAD_SWITCH:
+		ret = bq24190_charger_set_batfet_ctrl(bdi, val);
+		break;
 	default:
 		ret = -EINVAL;
 	}
@@ -1420,6 +1478,7 @@ static int bq24190_charger_property_is_writeable(struct power_supply *psy,
 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
 	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+	case POWER_SUPPLY_PROP_LOAD_SWITCH:
 		return 1;
 	default:
 		return 0;
@@ -1480,6 +1539,7 @@ static enum power_supply_property bq24190_charger_properties[] = {
 	POWER_SUPPLY_PROP_SCOPE,
 	POWER_SUPPLY_PROP_MODEL_NAME,
 	POWER_SUPPLY_PROP_MANUFACTURER,
+	POWER_SUPPLY_PROP_LOAD_SWITCH,
 };
 
 static char *bq24190_charger_supplied_to[] = {
@@ -1498,6 +1558,8 @@ static const struct power_supply_desc bq24190_charger_desc = {
 	.charge_types		= BIT(POWER_SUPPLY_CHARGE_TYPE_NONE)    |
 				  BIT(POWER_SUPPLY_CHARGE_TYPE_TRICKLE) |
 				  BIT(POWER_SUPPLY_CHARGE_TYPE_FAST),
+	.load_switches		= BIT(POWER_SUPPLY_LOAD_SWITCH_ON) |
+				  BIT(POWER_SUPPLY_LOAD_SWITCH_SHIP),
 };
 
 /* Battery power supply property routines */
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v2 8/8] power: supply: bq25630: Add support for BATFET control
  2026-09-01 19:35 [PATCH v2 0/8] Add sysfs entry for system load control Waqar Hameed
                   ` (5 preceding siblings ...)
  2026-09-01 19:35 ` [PATCH v2 4/8] power: supply: rt9471: " Waqar Hameed
@ 2026-09-01 19:35 ` Waqar Hameed
  2026-09-01 19:35 ` [PATCH v2 7/8] power: supply: bq24190: Use POWER_SUPPLY_PROP_LOAD_SWITCH Waqar Hameed
  7 siblings, 0 replies; 9+ messages in thread
From: Waqar Hameed @ 2026-09-01 19:35 UTC (permalink / raw)
  To: Sebastian Reichel; +Cc: kernel, linux-pm, linux-kernel

The framework supports controlling system load with
`POWER_SUPPLY_PROP_LOAD_SWITCH`. Use this to select between the
different supported BATFET control modes.

Signed-off-by: Waqar Hameed <waqar.hameed@axis.com>
---
 drivers/power/supply/bq25630_charger.c | 84 ++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)

diff --git a/drivers/power/supply/bq25630_charger.c b/drivers/power/supply/bq25630_charger.c
index 200f74f8eab61..bf54ff557a40f 100644
--- a/drivers/power/supply/bq25630_charger.c
+++ b/drivers/power/supply/bq25630_charger.c
@@ -112,6 +112,12 @@
 #define BQ25630_ITERM_MAX 1000000
 #define BQ25630_ITERM_STEP 10000
 
+/* BATFET control modes. */
+#define BQ25630_BATFET_CTRL_IDLE	0x00
+#define BQ25630_BATFET_CTRL_SHUTDOWN	0x01
+#define BQ25630_BATFET_CTRL_SHIP	0x02
+#define BQ25630_BATFET_CTRL_STANDBY	0x03
+
 /* Charge types. */
 #define BQ25630_CHG_STAT_NOT_CHARGING	0x00
 #define BQ25630_CHG_STAT_TRICKLE_CHARGE 0x01
@@ -587,6 +593,71 @@ static int bq25630_read_vbus(struct bq25630_data *data, int *val)
 	return 0;
 }
 
+static int bq25630_read_batfet_ctrl(struct bq25630_data *data, int *val)
+{
+	unsigned int regval;
+	int ret;
+
+	ret = regmap_field_read(data->regfields[BQ25630_REGF_BATFET_CTRL],
+				&regval);
+	if (ret) {
+		dev_err(data->dev, "Could not read BATFET control (%d)\n", ret);
+		return ret;
+	}
+
+	switch (regval) {
+	case BQ25630_BATFET_CTRL_IDLE:
+		*val = POWER_SUPPLY_LOAD_SWITCH_ON;
+		break;
+	case BQ25630_BATFET_CTRL_SHUTDOWN:
+		*val = POWER_SUPPLY_LOAD_SWITCH_OFF;
+		break;
+	case BQ25630_BATFET_CTRL_SHIP:
+		*val = POWER_SUPPLY_LOAD_SWITCH_SHIP;
+		break;
+	case BQ25630_BATFET_CTRL_STANDBY:
+		*val = POWER_SUPPLY_LOAD_SWITCH_STANDBY;
+		break;
+	default:
+		*val = POWER_SUPPLY_LOAD_SWITCH_UNKNOWN;
+	}
+
+	return 0;
+}
+
+static int bq25630_write_batfet_ctrl(struct bq25630_data *data, int val)
+{
+	unsigned int regval;
+	int ret;
+
+	switch (val) {
+	case POWER_SUPPLY_LOAD_SWITCH_ON:
+		regval = BQ25630_BATFET_CTRL_IDLE;
+		break;
+	case POWER_SUPPLY_LOAD_SWITCH_OFF:
+		regval = BQ25630_BATFET_CTRL_SHUTDOWN;
+		break;
+	case POWER_SUPPLY_LOAD_SWITCH_SHIP:
+		regval = BQ25630_BATFET_CTRL_SHIP;
+		break;
+	case POWER_SUPPLY_LOAD_SWITCH_STANDBY:
+		regval = BQ25630_BATFET_CTRL_STANDBY;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = regmap_field_write(data->regfields[BQ25630_REGF_BATFET_CTRL],
+				 regval);
+	if (ret) {
+		dev_err(data->dev, "Could not write BATFET control (%d)\n",
+			ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 static int bq25630_get_status(struct bq25630_data *data, int *val)
 {
 	unsigned int regval;
@@ -845,6 +916,9 @@ static int bq25630_charger_get_property(struct power_supply *psy,
 					 BQ25630_ITERM_MIN_REGVAL,
 					 &val->intval);
 		break;
+	case POWER_SUPPLY_PROP_LOAD_SWITCH:
+		ret = bq25630_read_batfet_ctrl(data, &val->intval);
+		break;
 	case POWER_SUPPLY_PROP_MODEL_NAME:
 		val->strval = "BQ25630";
 		break;
@@ -913,6 +987,9 @@ static int bq25630_charger_set_property(struct power_supply *psy,
 					  BQ25630_ITERM_MIN_REGVAL,
 					  val->intval);
 		break;
+	case POWER_SUPPLY_PROP_LOAD_SWITCH:
+		ret = bq25630_write_batfet_ctrl(data, val->intval);
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -932,6 +1009,7 @@ static int bq25630_charger_property_is_writeable(struct power_supply *psy,
 	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
 	case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
 	case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
+	case POWER_SUPPLY_PROP_LOAD_SWITCH:
 		return true;
 	default:
 		return false;
@@ -954,6 +1032,7 @@ static const enum power_supply_property bq25630_charger_properties[] = {
 	POWER_SUPPLY_PROP_USB_TYPE,
 	POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
 	POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
+	POWER_SUPPLY_PROP_LOAD_SWITCH,
 	POWER_SUPPLY_PROP_MODEL_NAME,
 	POWER_SUPPLY_PROP_MANUFACTURER,
 };
@@ -972,6 +1051,11 @@ static const struct power_supply_desc bq25630_charger_psy_desc = {
 		     BIT(POWER_SUPPLY_USB_TYPE_DCP) |
 		     BIT(POWER_SUPPLY_USB_TYPE_CDP) |
 		     BIT(POWER_SUPPLY_USB_TYPE_C),
+	.load_switches = BIT(POWER_SUPPLY_LOAD_SWITCH_UNKNOWN) |
+			 BIT(POWER_SUPPLY_LOAD_SWITCH_ON) |
+			 BIT(POWER_SUPPLY_LOAD_SWITCH_OFF) |
+			 BIT(POWER_SUPPLY_LOAD_SWITCH_STANDBY) |
+			 BIT(POWER_SUPPLY_LOAD_SWITCH_SHIP),
 	.properties = bq25630_charger_properties,
 	.num_properties = ARRAY_SIZE(bq25630_charger_properties),
 	.get_property = bq25630_charger_get_property,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-09-01 19:35 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-01 19:35 [PATCH v2 0/8] Add sysfs entry for system load control Waqar Hameed
2026-09-01 19:35 ` [PATCH v2 1/8] power: supply: Pack power_supply_desc to eliminate holes Waqar Hameed
2026-09-01 19:35 ` [PATCH v2 3/8] power: supply: ltc4162-l: Use POWER_SUPPLY_PROP_LOAD_SWITCH Waqar Hameed
2026-09-01 19:35 ` [PATCH v2 2/8] power: supply: Add sysfs entry for system load control Waqar Hameed
2026-09-01 19:35 ` [PATCH v2 5/8] power: supply: rt9467: Use POWER_SUPPLY_PROP_LOAD_SWITCH Waqar Hameed
2026-09-01 19:35 ` [PATCH v2 6/8] power: supply: bq24257: " Waqar Hameed
2026-09-01 19:35 ` [PATCH v2 4/8] power: supply: rt9471: " Waqar Hameed
2026-09-01 19:35 ` [PATCH v2 8/8] power: supply: bq25630: Add support for BATFET control Waqar Hameed
2026-09-01 19:35 ` [PATCH v2 7/8] power: supply: bq24190: Use POWER_SUPPLY_PROP_LOAD_SWITCH Waqar Hameed

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox