Devicetree
 help / color / mirror / Atom feed
* [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