* [PATCH 0/3] power: supply: battery: Allow separate charging limits vs. discharging
@ 2026-11-09 9:41 Alexey Charkov
2026-11-09 9:41 ` [PATCH 1/3] dt-bindings: power: supply: battery: Add a charging temperature range Alexey Charkov
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Alexey Charkov @ 2026-11-09 9:41 UTC (permalink / raw)
To: Sebastian Reichel, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-pm, devicetree, linux-kernel, Alexey Charkov
Some batteries specify different operating temperature ranges when
charging vs. when discharging, e.g. charge at 0C to 45C, but discharge
at up to -20C to 60C. Current DT bindings and power supply core don't
allow that, so extend them with additional properties so that a separate
limit could be programmed for when a charger should cut voltage going into
the battery vs. when the system itself should shut down.
Additionally, allow the DT to specify voltage/current limits to be applied
when the battery is being charged in the "alert" band (either high or low
temperature, which often requires derating especially at the low end).
Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
Alexey Charkov (3):
dt-bindings: power: supply: battery: Add a charging temperature range
power: supply: core: Read the charging temperature range and alert settings
power: supply: samsung-sdi-battery: Set the charging temperature range
.../devicetree/bindings/power/supply/battery.yaml | 45 +++++++++++++++++++++-
drivers/power/supply/power_supply_core.c | 16 ++++++++
drivers/power/supply/samsung-sdi-battery.c | 12 ++++++
include/linux/power_supply.h | 16 ++++++--
4 files changed, 83 insertions(+), 6 deletions(-)
---
base-commit: ddfe51b0a0f5dc9e415cc2c8ad8db17532dd426b
change-id: 20261109-battery-charge-temp-range-37fc54d4e3a3
Best regards,
--
Alexey Charkov <alchark@flipper.net>
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/3] dt-bindings: power: supply: battery: Add a charging temperature range
2026-11-09 9:41 [PATCH 0/3] power: supply: battery: Allow separate charging limits vs. discharging Alexey Charkov
@ 2026-11-09 9:41 ` Alexey Charkov
2026-11-09 9:41 ` [PATCH 2/3] power: supply: core: Read the charging temperature range and alert settings Alexey Charkov
2026-11-09 9:41 ` [PATCH 3/3] power: supply: samsung-sdi-battery: Set the charging temperature range Alexey Charkov
2 siblings, 0 replies; 5+ messages in thread
From: Alexey Charkov @ 2026-11-09 9:41 UTC (permalink / raw)
To: Sebastian Reichel, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-pm, devicetree, linux-kernel, Alexey Charkov
Describe batteries rated for separate charging and discharging
temperature ranges, such as 0-45C for charging and -20-60C for
discharging, often with a reduced charge current near the ends of the
charging range: operating-range-celsius holds a single range, and
existing users read it both as the limit for any use of the battery and
as the limit for charging.
Add charge-temp-range-celsius for the charging range, falling back to
operating-range-celsius when absent, and state that
operating-range-celsius covers discharging. Add the charge current and
voltage to use between alert-celsius and the charging range limits, to
describe a reduced charge rate near those limits and none beyond them.
A missing half of an alert charge current and voltage pair falls back to
the matching constant-charge-* setting. alert-celsius is expected to fully
fall inside charge-temp-range-celsius, but when it does not,
charge-temp-range-celsius takes precedence to ensure no charge occurs
outside the allowed range.
Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
.../devicetree/bindings/power/supply/battery.yaml | 45 +++++++++++++++++++++-
1 file changed, 43 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/power/supply/battery.yaml b/Documentation/devicetree/bindings/power/supply/battery.yaml
index 9575ee1491bb..d2f2ed9a01fe 100644
--- a/Documentation/devicetree/bindings/power/supply/battery.yaml
+++ b/Documentation/devicetree/bindings/power/supply/battery.yaml
@@ -111,11 +111,21 @@ properties:
for each of the battery capacity lookup table.
operating-range-celsius:
- description: operating temperature range of a battery
+ description: operating temperature range of a battery, in which it can be
+ discharged. Charging may be further restricted by
+ charge-temp-range-celsius.
items:
- description: minimum temperature at which battery can operate
- description: maximum temperature at which battery can operate
+ charge-temp-range-celsius:
+ description: temperature range in which the battery can be charged, within
+ operating-range-celsius. If absent, the battery can be charged in all of
+ operating-range-celsius. Outside this range the battery is not charged.
+ items:
+ - description: minimum temperature at which battery can be charged
+ - description: maximum temperature at which battery can be charged
+
ambient-celsius:
description: safe range of ambient temperature
items:
@@ -123,11 +133,39 @@ properties:
- description: alert when ambient temperature is higher than this value
alert-celsius:
- description: safe range of battery temperature
+ description: safe range of battery temperature. Where a limit of this
+ range lies within charge-temp-range-celsius, the battery is charged
+ between the two limits with the alert-low-temp-charge-* or
+ alert-high-temp-charge-* settings. Each of those that is absent falls
+ back to the corresponding constant-charge-* setting.
items:
- description: alert when battery temperature is lower than this value
- description: alert when battery temperature is higher than this value
+ alert-low-temp-charge-current-microamp:
+ description: charge current in place of
+ constant-charge-current-max-microamp, while the battery temperature is
+ between the lower limits of charge-temp-range-celsius and alert-celsius
+ minimum: 1
+
+ alert-low-temp-charge-voltage-microvolt:
+ description: charge voltage in place of
+ constant-charge-voltage-max-microvolt, while the battery temperature is
+ between the lower limits of charge-temp-range-celsius and alert-celsius
+ minimum: 1
+
+ alert-high-temp-charge-current-microamp:
+ description: charge current in place of
+ constant-charge-current-max-microamp, while the battery temperature is
+ between the upper limits of alert-celsius and charge-temp-range-celsius
+ minimum: 1
+
+ alert-high-temp-charge-voltage-microvolt:
+ description: charge voltage in place of
+ constant-charge-voltage-max-microvolt, while the battery temperature is
+ between the upper limits of alert-celsius and charge-temp-range-celsius
+ minimum: 1
+
# The volt-drop* -properties describe voltage-drop for a battery, described
# as VDROP in:
# https://patentimages.storage.googleapis.com/6c/f5/17/c1d901c220f6a9/US20150032394A1.pdf
@@ -200,8 +238,11 @@ examples:
ocv-capacity-table-2 = <4250000 100>, <4200000 95>, <4185000 90>;
resistance-temp-table = <20 100>, <10 90>, <0 80>, <(-10) 60>;
operating-range-celsius = <(-30) 50>;
+ charge-temp-range-celsius = <0 45>;
ambient-celsius = <(-5) 50>;
alert-celsius = <0 40>;
+ alert-high-temp-charge-current-microamp = <450000>;
+ alert-high-temp-charge-voltage-microvolt = <4100000>;
};
charger@11 {
--
2.56.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/3] power: supply: core: Read the charging temperature range and alert settings
2026-11-09 9:41 [PATCH 0/3] power: supply: battery: Allow separate charging limits vs. discharging Alexey Charkov
2026-11-09 9:41 ` [PATCH 1/3] dt-bindings: power: supply: battery: Add a charging temperature range Alexey Charkov
@ 2026-11-09 9:41 ` Alexey Charkov
2026-11-10 23:24 ` sashiko-bot
2026-11-09 9:41 ` [PATCH 3/3] power: supply: samsung-sdi-battery: Set the charging temperature range Alexey Charkov
2 siblings, 1 reply; 5+ messages in thread
From: Alexey Charkov @ 2026-11-09 9:41 UTC (permalink / raw)
To: Sebastian Reichel, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-pm, devicetree, linux-kernel, Alexey Charkov
Read charge-temp-range-celsius into new temp_charge_min and
temp_charge_max fields, falling back to the operating range when it is
absent, so that a charger can stop charging outside a narrower range
while the battery stays in use. Read the alert-*-temp-charge-*
properties into the existing alert_*_temp_charge_* fields, which no
firmware description could set before, and document them as applying
between the alert and charging limits.
Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
drivers/power/supply/power_supply_core.c | 16 ++++++++++++++++
include/linux/power_supply.h | 16 ++++++++++++----
2 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
index de15314ef954..3bfc4fb8687e 100644
--- a/drivers/power/supply/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
@@ -855,6 +855,14 @@ int power_supply_get_battery_info(struct power_supply *psy,
&info->constant_charge_voltage_max_uv);
fwnode_property_read_u32(fwnode, "factory-internal-resistance-micro-ohms",
&info->factory_internal_resistance_uohm);
+ fwnode_property_read_u32(fwnode, "alert-low-temp-charge-current-microamp",
+ &info->alert_low_temp_charge_current_ua);
+ fwnode_property_read_u32(fwnode, "alert-low-temp-charge-voltage-microvolt",
+ &info->alert_low_temp_charge_voltage_uv);
+ fwnode_property_read_u32(fwnode, "alert-high-temp-charge-current-microamp",
+ &info->alert_high_temp_charge_current_ua);
+ fwnode_property_read_u32(fwnode, "alert-high-temp-charge-voltage-microvolt",
+ &info->alert_high_temp_charge_voltage_uv);
if (!fwnode_property_read_u32_array(fwnode, "ambient-celsius",
min_max, ARRAY_SIZE(min_max))) {
@@ -871,6 +879,14 @@ int power_supply_get_battery_info(struct power_supply *psy,
info->temp_min = min_max[0];
info->temp_max = min_max[1];
}
+ if (!fwnode_property_read_u32_array(fwnode, "charge-temp-range-celsius",
+ min_max, ARRAY_SIZE(min_max))) {
+ info->temp_charge_min = min_max[0];
+ info->temp_charge_max = min_max[1];
+ } else {
+ info->temp_charge_min = info->temp_min;
+ info->temp_charge_max = info->temp_max;
+ }
len = fwnode_property_count_u32(fwnode, "ocv-capacity-celsius");
if (len < 0 && len != -EINVAL) {
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index cce61137aef4..246fba40ea78 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -559,15 +559,15 @@ struct power_supply_maintenance_charge_table {
* maintenance_charge.
* @alert_low_temp_charge_current_ua: The charging current to use if the battery
* enters low alert temperature, i.e. if the internal temperature is between
- * temp_alert_min and temp_min. No matter the charging phase, this
+ * temp_charge_min and temp_alert_min. No matter the charging phase, this
* and alert_high_temp_charge_voltage_uv will be applied.
* @alert_low_temp_charge_voltage_uv: Same as alert_low_temp_charge_current_ua,
* but for the charging voltage.
* @alert_high_temp_charge_current_ua: The charging current to use if the
* battery enters high alert temperature, i.e. if the internal temperature is
- * between temp_alert_max and temp_max. No matter the charging phase, this
- * and alert_high_temp_charge_voltage_uv will be applied, usually lowering
- * the charging current as an evasive manouver.
+ * between temp_alert_max and temp_charge_max. No matter the charging phase,
+ * this and alert_high_temp_charge_voltage_uv will be applied, usually
+ * lowering the charging current as an evasive manouver.
* @alert_high_temp_charge_voltage_uv: Same as
* alert_high_temp_charge_current_ua, but for the charging voltage.
* @factory_internal_resistance_uohm: the internal resistance of the battery
@@ -603,6 +603,12 @@ struct power_supply_maintenance_charge_table {
* @temp_max: the battery will go outside of operating conditions when
* the internal temperature goes above this temperature in degrees Celsius.
* Normally this means the system should shut down.
+ * @temp_charge_min: the battery must not be charged when the internal
+ * temperature is below this temperature in degrees Celsius. Defaults to
+ * temp_min.
+ * @temp_charge_max: the battery must not be charged when the internal
+ * temperature is above this temperature in degrees Celsius. Defaults to
+ * temp_max.
* @ocv_table: for each entry in ocv_temp there is a corresponding entry in
* ocv_table and a size for each entry in ocv_table_size. These arrays
* determine the capacity in percent in relation to the voltage in microvolts
@@ -826,6 +832,8 @@ struct power_supply_battery_info {
int temp_alert_max;
int temp_min;
int temp_max;
+ int temp_charge_min;
+ int temp_charge_max;
const struct power_supply_battery_ocv_table *ocv_table[POWER_SUPPLY_OCV_TEMP_MAX];
int ocv_table_size[POWER_SUPPLY_OCV_TEMP_MAX];
const struct power_supply_resistance_temp_table *resist_table;
--
2.56.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/3] power: supply: samsung-sdi-battery: Set the charging temperature range
2026-11-09 9:41 [PATCH 0/3] power: supply: battery: Allow separate charging limits vs. discharging Alexey Charkov
2026-11-09 9:41 ` [PATCH 1/3] dt-bindings: power: supply: battery: Add a charging temperature range Alexey Charkov
2026-11-09 9:41 ` [PATCH 2/3] power: supply: core: Read the charging temperature range and alert settings Alexey Charkov
@ 2026-11-09 9:41 ` Alexey Charkov
2 siblings, 0 replies; 5+ messages in thread
From: Alexey Charkov @ 2026-11-09 9:41 UTC (permalink / raw)
To: Sebastian Reichel, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: linux-pm, devicetree, linux-kernel, Alexey Charkov
Give each battery a charging range equal to its operating range, as the
firmware parsing does when charge-temp-range-celsius is absent, since
these static descriptions skip that parsing: keep their behaviour
unchanged.
Leave any correction of these limits to a separate change, but note
that they follow the charge-block thresholds of the matching vendor
kernels, which count in tenths of a degree: the -50C and -30C lower
limits look like a unit slip in the original import, as -50 there
means -5C.
Signed-off-by: Alexey Charkov <alchark@flipper.net>
---
drivers/power/supply/samsung-sdi-battery.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/power/supply/samsung-sdi-battery.c b/drivers/power/supply/samsung-sdi-battery.c
index 33565002ee27..da283735df3b 100644
--- a/drivers/power/supply/samsung-sdi-battery.c
+++ b/drivers/power/supply/samsung-sdi-battery.c
@@ -659,6 +659,8 @@ static struct samsung_sdi_battery samsung_sdi_batteries[] = {
.temp_alert_min = 0,
.temp_alert_max = 40,
.temp_max = 60,
+ .temp_charge_min = -50,
+ .temp_charge_max = 60,
.resist_table = samsung_temp2res,
.resist_table_size = ARRAY_SIZE(samsung_temp2res),
/* If you have tables for more temperatures, add them */
@@ -703,6 +705,8 @@ static struct samsung_sdi_battery samsung_sdi_batteries[] = {
.temp_alert_min = 0,
.temp_alert_max = 40,
.temp_max = 47,
+ .temp_charge_min = -30,
+ .temp_charge_max = 47,
.resist_table = samsung_temp2res,
.resist_table_size = ARRAY_SIZE(samsung_temp2res),
/* If you have tables for more temperatures, add them */
@@ -747,6 +751,8 @@ static struct samsung_sdi_battery samsung_sdi_batteries[] = {
.temp_alert_min = 0,
.temp_alert_max = 43,
.temp_max = 49,
+ .temp_charge_min = -50,
+ .temp_charge_max = 49,
.resist_table = samsung_temp2res,
.resist_table_size = ARRAY_SIZE(samsung_temp2res),
/* If you have tables for more temperatures, add them */
@@ -790,6 +796,8 @@ static struct samsung_sdi_battery samsung_sdi_batteries[] = {
.temp_alert_min = 0,
.temp_alert_max = 40,
.temp_max = 60,
+ .temp_charge_min = -50,
+ .temp_charge_max = 60,
.resist_table = samsung_temp2res,
.resist_table_size = ARRAY_SIZE(samsung_temp2res),
/* If you have tables for more temperatures, add them */
@@ -835,6 +843,8 @@ static struct samsung_sdi_battery samsung_sdi_batteries[] = {
.temp_alert_min = 0,
.temp_alert_max = 40,
.temp_max = 60,
+ .temp_charge_min = -5,
+ .temp_charge_max = 60,
.resist_table = samsung_temp2res,
.resist_table_size = ARRAY_SIZE(samsung_temp2res),
/* If you have tables for more temperatures, add them */
@@ -879,6 +889,8 @@ static struct samsung_sdi_battery samsung_sdi_batteries[] = {
.temp_alert_min = 0,
.temp_alert_max = 40,
.temp_max = 60,
+ .temp_charge_min = -5,
+ .temp_charge_max = 60,
.resist_table = samsung_temp2res,
.resist_table_size = ARRAY_SIZE(samsung_temp2res),
/* If you have tables for more temperatures, add them */
--
2.56.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 2/3] power: supply: core: Read the charging temperature range and alert settings
2026-11-09 9:41 ` [PATCH 2/3] power: supply: core: Read the charging temperature range and alert settings Alexey Charkov
@ 2026-11-10 23:24 ` sashiko-bot
0 siblings, 0 replies; 5+ messages in thread
From: sashiko-bot @ 2026-11-10 23:24 UTC (permalink / raw)
To: Alexey Charkov; +Cc: devicetree, robh, conor+dt
Thank you for your contribution! Sashiko AI review found no new issues
in this patch, but noticed 1 related pre-existing issue it does not
introduce:
- [High] power: supply: core: out-of-bounds read in
power_supply_ocv2cap_simple() [1]
--
commit adb164988f0d04b6bb830ddbcbc6a92311698583
Author: Alexey Charkov <alchark@flipper.net>
power: supply: core: Read the charging temperature range and alert settings
This commit reads the charge-temp-range-celsius and alert-*-temp-charge-*
firmware properties into struct power_supply_battery_info, falling back to
the operating temperature range when charge-temp-range-celsius is absent.
> diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
> index de15314ef9549..3bfc4fb8687ef 100644
> --- a/drivers/power/supply/power_supply_core.c
> +++ b/drivers/power/supply/power_supply_core.c
> @@ -855,6 +855,14 @@ int power_supply_get_battery_info(struct power_supply *psy,
> &info->constant_charge_voltage_max_uv);
> fwnode_property_read_u32(fwnode, "factory-internal-resistance-micro-ohms",
> &info->factory_internal_resistance_uohm);
> + fwnode_property_read_u32(fwnode, "alert-low-temp-charge-current-microamp",
> + &info->alert_low_temp_charge_current_ua);
> + fwnode_property_read_u32(fwnode, "alert-low-temp-charge-voltage-microvolt",
> + &info->alert_low_temp_charge_voltage_uv);
> + fwnode_property_read_u32(fwnode, "alert-high-temp-charge-current-microamp",
> + &info->alert_high_temp_charge_current_ua);
> + fwnode_property_read_u32(fwnode, "alert-high-temp-charge-voltage-microvolt",
> + &info->alert_high_temp_charge_voltage_uv);
>
> if (!fwnode_property_read_u32_array(fwnode, "ambient-celsius",
> min_max, ARRAY_SIZE(min_max))) {
> @@ -871,6 +879,14 @@ int power_supply_get_battery_info(struct power_supply *psy,
> info->temp_min = min_max[0];
> info->temp_max = min_max[1];
> }
> + if (!fwnode_property_read_u32_array(fwnode, "charge-temp-range-celsius",
> + min_max, ARRAY_SIZE(min_max))) {
> + info->temp_charge_min = min_max[0];
> + info->temp_charge_max = min_max[1];
> + } else {
> + info->temp_charge_min = info->temp_min;
> + info->temp_charge_max = info->temp_max;
> + }
>
> len = fwnode_property_count_u32(fwnode, "ocv-capacity-celsius");
> if (len < 0 && len != -EINVAL) {
[Severity: High]
This problem wasn't introduced by this patch, but can an empty
ocv-capacity-table-N property in power_supply_get_battery_info() [1]
cause an out-of-bounds read in power_supply_ocv2cap_simple()?
drivers/power/supply/power_supply_core.c:power_supply_get_battery_info() {
...
proplen = fwnode_property_count_u32(fwnode, propname);
if (proplen < 0 || proplen % 2 != 0) {
dev_err(&psy->dev, "failed to get %s\n", propname);
power_supply_put_battery_info(psy, info);
err = -EINVAL;
goto out_put_node;
}
...
tab_len = proplen / 2;
info->ocv_table_size[index] = tab_len;
info->ocv_table[index] = table =
devm_kcalloc(&psy->dev, tab_len, sizeof(*table), GFP_KERNEL);
...
}
When ocv-capacity-table-N is present but empty,
fwnode_property_count_u32() returns 0, which passes the proplen < 0 ||
proplen % 2 != 0 check. devm_kcalloc() then returns ZERO_SIZE_PTR with
ocv_table_size[index] set to 0, and power_supply_ocv2cap_simple() later
dereferences table[0], crashing the kernel. Rejecting proplen <= 0 (similar
to resistance-temp-table below) would avoid this.
[1] https://sashiko.dev/#/bug/linux-4a0a5d5f-629d-4b0d-b4be-07415bcb018e
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261109-battery-charge-temp-range-v1-0-a967abd8b80c@flipper.net?part=2
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-11-10 23:24 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-09 9:41 [PATCH 0/3] power: supply: battery: Allow separate charging limits vs. discharging Alexey Charkov
2026-11-09 9:41 ` [PATCH 1/3] dt-bindings: power: supply: battery: Add a charging temperature range Alexey Charkov
2026-11-09 9:41 ` [PATCH 2/3] power: supply: core: Read the charging temperature range and alert settings Alexey Charkov
2026-11-10 23:24 ` sashiko-bot
2026-11-09 9:41 ` [PATCH 3/3] power: supply: samsung-sdi-battery: Set the charging temperature range Alexey Charkov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox