From f170c05e3e08aa2068601db369078bb83dc5e7e7 Mon Sep 17 00:00:00 2001 From: Waqar Hameed Date: Tue, 1 Sep 2026 21:35:07 +0200 Subject: 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`. Signed-off-by: Waqar Hameed Link: https://patch.msgid.link/5b6d1d588c8aaf237c45638c29a2ff23f0a07f34.1788290289.git.waqar.hameed@axis.com Signed-off-by: Sebastian Reichel --- include/linux/power_supply.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index e749d2189335..fcd05f4a8883 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 { -- cgit v1.2.3 From 4fe4d3dc5c20c62789c718946bdb4f72a7cf363d Mon Sep 17 00:00:00 2001 From: Waqar Hameed Date: Tue, 1 Sep 2026 21:35:08 +0200 Subject: power: supply: Add sysfs entry for system load control 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 Link: https://patch.msgid.link/d86f528de9a058091f806d9676639239cfeaf805.1788290289.git.waqar.hameed@axis.com Signed-off-by: Sebastian Reichel --- 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(+) (limited to 'include/linux') diff --git a/Documentation/ABI/testing/sysfs-class-power b/Documentation/ABI/testing/sysfs-class-power index 98b389845d1e..2cf3f53a652b 100644 --- a/Documentation/ABI/testing/sysfs-class-power +++ b/Documentation/ABI/testing/sysfs-class-power @@ -594,6 +594,31 @@ Description: Valid values: 0 - 100 (percent) +What: /sys/class/power_supply//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//input_current_limit diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 9d6b24856c8b..b0f524d152cf 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 fcd05f4a8883..f6cbeffda653 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; -- cgit v1.2.3 From abe09806ef8b76f47e6248c82abc1d1623e9f985 Mon Sep 17 00:00:00 2001 From: Henrik Grimler Date: Tue, 18 Aug 2026 11:48:22 +0200 Subject: power: supply: bq27xxx: add support for bq27z746 bq27z746 is similar to bq27z561, but has additional battery protection logic. The standard register map is a subset of the one found in bq27z561. There are some more differences among the ManufacturerAccess registers, but the ManufacturerAccess registers are currently not handled by the driver in any way. Therefore use the same regs and props for bq27z746 and bq27z561. Signed-off-by: Henrik Grimler Acked-by: Andrew Davis Link: https://patch.msgid.link/20260818-bq27z746-v2-3-0371e206665f@axis.com Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery.c | 6 ++++++ drivers/power/supply/bq27xxx_battery_i2c.c | 2 ++ include/linux/power/bq27xxx_battery.h | 1 + 3 files changed, 9 insertions(+) (limited to 'include/linux') diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index cd30993b8a89..17f5b58609be 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -37,6 +37,7 @@ * https://www.ti.com/product/bq27441-g1 * https://www.ti.com/product/bq27621-g1 * https://www.ti.com/product/bq27z561 + * https://www.ti.com/product/bq27z746 * https://www.ti.com/product/bq28z610 * https://www.ti.com/product/bq34z100-g1 * https://www.ti.com/product/bq78z100 @@ -502,6 +503,7 @@ static u8 [BQ27XXX_REG_AP] = 0x22, BQ27XXX_DM_REG_ROWS, }, +#define bq27z746_regs bq27z561_regs bq28z610_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, @@ -837,6 +839,8 @@ static enum power_supply_property bq27z561_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; +#define bq27z746_props bq27z561_props + static enum power_supply_property bq28z610_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, @@ -995,6 +999,7 @@ static struct bq27xxx_dm_reg bq27621_dm_regs[] = { #endif #define bq27z561_dm_regs NULL +#define bq27z746_dm_regs NULL #define bq28z610_dm_regs NULL #define bq34z100_dm_regs NULL #define bq78z100_dm_regs NULL @@ -1053,6 +1058,7 @@ static struct { [BQ27441] = BQ27XXX_DATA(bq27441, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), [BQ27621] = BQ27XXX_DATA(bq27621, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), [BQ27Z561] = BQ27XXX_DATA(bq27z561, 0 , BQ27Z561_O_BITS), + [BQ27Z746] = BQ27XXX_DATA(bq27z746, 0 , BQ27Z561_O_BITS), [BQ28Z610] = BQ27XXX_DATA(bq28z610, 0 , BQ27Z561_O_BITS), [BQ34Z100] = BQ27XXX_DATA(bq34z100, 0 , BQ27XXX_O_OTDC | BQ27XXX_O_SOC_SI | \ BQ27XXX_O_HAS_CI | BQ27XXX_O_MUL_CHEM), diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c index c4e7a9521d08..2a6b4534cb28 100644 --- a/drivers/power/supply/bq27xxx_battery_i2c.c +++ b/drivers/power/supply/bq27xxx_battery_i2c.c @@ -253,6 +253,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = { { .name = "bq27441", .driver_data = BQ27441 }, { .name = "bq27621", .driver_data = BQ27621 }, { .name = "bq27z561", .driver_data = BQ27Z561 }, + { .name = "bq27z746", .driver_data = BQ27Z746 }, { .name = "bq28z610", .driver_data = BQ28Z610 }, { .name = "bq34z100", .driver_data = BQ34Z100 }, { .name = "bq78z100", .driver_data = BQ78Z100 }, @@ -290,6 +291,7 @@ static const struct of_device_id bq27xxx_battery_i2c_of_match_table[] = { { .compatible = "ti,bq27441" }, { .compatible = "ti,bq27621" }, { .compatible = "ti,bq27z561" }, + { .compatible = "ti,bq27z746" }, { .compatible = "ti,bq28z610" }, { .compatible = "ti,bq34z100" }, { .compatible = "ti,bq78z100" }, diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h index d56e1276aafe..0b833c4bb583 100644 --- a/include/linux/power/bq27xxx_battery.h +++ b/include/linux/power/bq27xxx_battery.h @@ -33,6 +33,7 @@ enum bq27xxx_chip { BQ27441, BQ27621, BQ27Z561, + BQ27Z746, BQ28Z610, BQ34Z100, BQ78Z100, -- cgit v1.2.3 From 5d32ee3bff8bc943095d04e801e1b45f1c695753 Mon Sep 17 00:00:00 2001 From: Alexey Charkov Date: Fri, 2 Oct 2026 16:02:55 +0400 Subject: power: supply: bq27xxx: add support for BQ28Z620 Match the BQ28Z620 under its own chip ID so that code touching its relocated data flash can tell it apart from the BQ28Z610. Reuse the BQ28Z610 register map and properties, as the standard commands the driver reads are unchanged. Keep the 10 mW scaling of AveragePower() even though the BQ28Z620 TRM lists it in mW: readings on hardware match V * I only in 10 mW units. Signed-off-by: Alexey Charkov Link: https://patch.msgid.link/20261002-bq28z620-v1-2-bdcc10d42519@flipper.net Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery.c | 6 ++++++ drivers/power/supply/bq27xxx_battery_i2c.c | 2 ++ include/linux/power/bq27xxx_battery.h | 1 + 3 files changed, 9 insertions(+) (limited to 'include/linux') diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 17f5b58609be..09272249b4f7 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -39,6 +39,7 @@ * https://www.ti.com/product/bq27z561 * https://www.ti.com/product/bq27z746 * https://www.ti.com/product/bq28z610 + * https://www.ti.com/product/bq28z620 * https://www.ti.com/product/bq34z100-g1 * https://www.ti.com/product/bq78z100 */ @@ -525,6 +526,7 @@ static u8 [BQ27XXX_REG_AP] = 0x22, BQ27XXX_DM_REG_ROWS, }, +#define bq28z620_regs bq28z610_regs bq34z100_regs[BQ27XXX_REG_MAX] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x0c, @@ -861,6 +863,8 @@ static enum power_supply_property bq28z610_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; +#define bq28z620_props bq28z610_props + static enum power_supply_property bq34z100_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, @@ -1001,6 +1005,7 @@ static struct bq27xxx_dm_reg bq27621_dm_regs[] = { #define bq27z561_dm_regs NULL #define bq27z746_dm_regs NULL #define bq28z610_dm_regs NULL +#define bq28z620_dm_regs NULL #define bq34z100_dm_regs NULL #define bq78z100_dm_regs NULL @@ -1060,6 +1065,7 @@ static struct { [BQ27Z561] = BQ27XXX_DATA(bq27z561, 0 , BQ27Z561_O_BITS), [BQ27Z746] = BQ27XXX_DATA(bq27z746, 0 , BQ27Z561_O_BITS), [BQ28Z610] = BQ27XXX_DATA(bq28z610, 0 , BQ27Z561_O_BITS), + [BQ28Z620] = BQ27XXX_DATA(bq28z620, 0 , BQ27Z561_O_BITS), [BQ34Z100] = BQ27XXX_DATA(bq34z100, 0 , BQ27XXX_O_OTDC | BQ27XXX_O_SOC_SI | \ BQ27XXX_O_HAS_CI | BQ27XXX_O_MUL_CHEM), [BQ78Z100] = BQ27XXX_DATA(bq78z100, 0 , BQ27Z561_O_BITS), diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c index 2a6b4534cb28..715ce8b6e401 100644 --- a/drivers/power/supply/bq27xxx_battery_i2c.c +++ b/drivers/power/supply/bq27xxx_battery_i2c.c @@ -255,6 +255,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = { { .name = "bq27z561", .driver_data = BQ27Z561 }, { .name = "bq27z746", .driver_data = BQ27Z746 }, { .name = "bq28z610", .driver_data = BQ28Z610 }, + { .name = "bq28z620", .driver_data = BQ28Z620 }, { .name = "bq34z100", .driver_data = BQ34Z100 }, { .name = "bq78z100", .driver_data = BQ78Z100 }, { } @@ -293,6 +294,7 @@ static const struct of_device_id bq27xxx_battery_i2c_of_match_table[] = { { .compatible = "ti,bq27z561" }, { .compatible = "ti,bq27z746" }, { .compatible = "ti,bq28z610" }, + { .compatible = "ti,bq28z620" }, { .compatible = "ti,bq34z100" }, { .compatible = "ti,bq78z100" }, {}, diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h index 0b833c4bb583..731ea837aac3 100644 --- a/include/linux/power/bq27xxx_battery.h +++ b/include/linux/power/bq27xxx_battery.h @@ -35,6 +35,7 @@ enum bq27xxx_chip { BQ27Z561, BQ27Z746, BQ28Z610, + BQ28Z620, BQ34Z100, BQ78Z100, }; -- cgit v1.2.3