* [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, ®val);
+ 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, ®val);
- 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], ®val);
+ 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], ®val);
+ 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,
+ ®val);
+ 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],
+ ®val);
+ 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