Skip to contentSkip to conversation

Add sysfs entry for system load control

PATCH Applied Waqar Hameed 2 participants 10 messages Sep 1 – Sep 9 Power supply

lore
Share & tools
lore
#0 lore raw

v2 cover Add sysfs entry for system load control

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/[email protected]/

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/[email protected]/

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

Signature · 1 line
2.43.0
#1 lore raw

PATCH v2 1/8 power: supply: Pack power_supply_desc to eliminate holes

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.

---
 include/linux/power_supply.h | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
include/linux/power_supply.h +5 -3
index e749d21893352..fcd05f4a88833 100644
@@ -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 {
Signature · 1 line
2.43.0
#2 lore raw

PATCH v2 2/8 power: supply: Add sysfs entry for system load control

In reply to Waqar Hameed

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 */

};

---
 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(+)
Documentation/ABI/testing/sysfs-class-power +25 -0
index 5641f1fd5fd6f..93f2398125d88 100644
@@ -590,6 +590,31 @@ Description:
 
 		Valid values: 0 - 100 (percent)
 
+What:		/sys/class/power_supply/<supply_name>/load_switch
+Date:		June 2026
+Contact:	[email protected]
+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
drivers/power/supply/power_supply_sysfs.c +17 -0
index 9d6b24856c8b0..b0f524d152cf6 100644
@@ -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;
include/linux/power_supply.h +10 -0
index fcd05f4a88833..f6cbeffda6534 100644
@@ -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;
 
Signature · 1 line
2.43.0
#3 lore raw

PATCH v2 3/8 power: supply: ltc4162-l: Use POWER_SUPPLY_PROP_LOAD_SWITCH

In reply to Waqar Hameed

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.

---
 .../ABI/testing/sysfs-class-power-ltc4162l    |  2 +
 drivers/power/supply/ltc4162-l-charger.c      | 56 +++++++++++++++++--
 2 files changed, 52 insertions(+), 6 deletions(-)
Documentation/ABI/testing/sysfs-class-power-ltc4162l +2 -0
index ba30db93052bf..ad46ad834af05 100644
@@ -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)
drivers/power/supply/ltc4162-l-charger.c +50 -6

107 lines not on this page · raw message

Signature · 1 line
2.43.0
#4 lore raw

PATCH v2 4/8 power: supply: rt9471: Use POWER_SUPPLY_PROP_LOAD_SWITCH

In reply to Waqar Hameed

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.

---
 .../ABI/testing/sysfs-class-power-rt9471      |  2 +
 drivers/power/supply/rt9471.c                 | 54 ++++++++++++++++---
 2 files changed, 50 insertions(+), 6 deletions(-)
Documentation/ABI/testing/sysfs-class-power-rt9471 +2 -0
index 0a390ee5ac21c..90cf94c1cbf6b 100644
@@ -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
drivers/power/supply/rt9471.c +48 -6

106 lines not on this page · raw message

Signature · 1 line
2.43.0
#5 lore raw

PATCH v2 5/8 power: supply: rt9467: Use POWER_SUPPLY_PROP_LOAD_SWITCH

In reply to Waqar Hameed

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.

---
 .../ABI/testing/sysfs-class-power-rt9467      |  2 +
 drivers/power/supply/rt9467-charger.c         | 54 ++++++++++++++++---
 2 files changed, 50 insertions(+), 6 deletions(-)
Documentation/ABI/testing/sysfs-class-power-rt9467 +2 -0
index 619b7c45d145d..bfbfd78ec1c19 100644
@@ -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
drivers/power/supply/rt9467-charger.c +48 -6

106 lines not on this page · raw message

Signature · 1 line
2.43.0
#6 lore raw

PATCH v2 6/8 power: supply: bq24257: Use POWER_SUPPLY_PROP_LOAD_SWITCH

In reply to Waqar Hameed

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.

---
 drivers/power/supply/bq24257_charger.c | 43 +++++++++++++++++++++++++-
 1 file changed, 42 insertions(+), 1 deletion(-)
drivers/power/supply/bq24257_charger.c +42 -1
index 944a7aa6f187d..8eea7d0395ce0 100644
@@ -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,
Signature · 1 line
2.43.0
#7 lore raw

PATCH v2 7/8 power: supply: bq24190: Use POWER_SUPPLY_PROP_LOAD_SWITCH

In reply to Waqar Hameed

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().

---
 drivers/power/supply/bq24190_charger.c | 62 ++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)
drivers/power/supply/bq24190_charger.c +62 -0
index 4bea6fd83c36f..d67bf25ec6ec1 100644
@@ -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 */
Signature · 1 line
2.43.0
#8 lore raw

PATCH v2 8/8 power: supply: bq25630: Add support for BATFET control

In reply to Waqar Hameed

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

---
 drivers/power/supply/bq25630_charger.c | 84 ++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)
drivers/power/supply/bq25630_charger.c +84 -0
index 200f74f8eab61..bf54ff557a40f 100644
@@ -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,
Signature · 1 line
2.43.0
#9 lore raw
In reply to Waqar Hameed
Quoted 11 lines · Waqar Hameed

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.

[...]

Applied, thanks!

[1/8] power: supply: Pack power_supply_desc to eliminate holes

      commit: 1948a667e2b9e2628a73f7b594bc2461b3062471
[2/8] power: supply: Add sysfs entry for system load control
      commit: eb16583b98416ea8472a48356e5eeeecbd7ab2e2
[3/8] power: supply: ltc4162-l: Use POWER_SUPPLY_PROP_LOAD_SWITCH
      commit: 63ca332b361df73d0f69ebf20a325e8f014d8982
[4/8] power: supply: rt9471: Use POWER_SUPPLY_PROP_LOAD_SWITCH
      commit: 63c85b1ae2f602d7865964e078b35b24196409f7
[5/8] power: supply: rt9467: Use POWER_SUPPLY_PROP_LOAD_SWITCH
      commit: 22baf7437615b94a4dad8288b14ae8815761d70d
[6/8] power: supply: bq24257: Use POWER_SUPPLY_PROP_LOAD_SWITCH
      commit: f7259dbf1e73f759c4a0c972a402bec3f6756b28
[7/8] power: supply: bq24190: Use POWER_SUPPLY_PROP_LOAD_SWITCH
      commit: 22d3111d524958c849e8105a8201ef40bd86c1ff
[8/8] power: supply: bq25630: Add support for BATFET control
      commit: 800ab4aa3ebc56333d65d158aa61bae56f9b79ec

Best regards,

Signature · 1 line
Sebastian Reichel <[email protected]>