mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] usb: typec: tcpm: Support native battery energy properties in battery AMS
@ 2026-08-20 21:17 Amit Sunil Dhamne via B4 Relay
  2026-08-24 11:27 ` Heikki Krogerus
  0 siblings, 1 reply; 2+ messages in thread
From: Amit Sunil Dhamne via B4 Relay @ 2026-08-20 21:17 UTC (permalink / raw)
  To: Badhri Jagan Sridharan, Heikki Krogerus, Greg Kroah-Hartman
  Cc: linux-usb, linux-kernel, RD Babiera, Kyle Tso, Sebastian Reichel,
	Amit Sunil Dhamne

From: Amit Sunil Dhamne <amitsd@google.com>

Some fuel gauges report battery telemetry in energy rather than charge.
Add support for querying native energy properties for Battery Status and
Battery Capabilities AMS, falling back to calculating energy from charge
and average voltage when primary properties are not supported.

+---------+--------------------+----------------------------------+
| Sr. No. | Primary            | Fallback                         |
+---------+--------------------+----------------------------------+
| 1       | ENERGY_NOW         | CHARGE_NOW + VOLTAGE_AVG         |
| 2       | ENERGY_FULL_DESIGN | CHARGE_FULL_DESIGN + VOLTAGE_AVG |
| 3       | ENERGY_FULL        | CHARGE_FULL + VOLTAGE_AVG        |
+---------+--------------------+----------------------------------+
Note: All properties above are to be prefixed with POWER_SUPPLY_PROP_.

Closes: https://lore.kernel.org/all/amVJ1u67qHENBQ5l@venus/
Suggested-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Assisted-by: Gemini:gemini-3.1-pro
Signed-off-by: Amit Sunil Dhamne <amitsd@google.com>
Reviewed-by: Badhri Jagan Sridharan <badhri@google.com>
---
 drivers/usb/typec/tcpm/tcpm.c | 57 +++++++++++++++++++++++++++----------------
 1 file changed, 36 insertions(+), 21 deletions(-)

diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index a8cd1959c426..0d7dc0b51c87 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -410,6 +410,9 @@ struct pd_timings {
 /* Convert microwatt to watt */
 #define UW_TO_W(pow)				(div_u64((pow), 1000000))
 
+/* Convert micro-Watt-hours to USB PD energy (increments of 0.1Wh) */
+#define UWH_TO_PD_ENERGY(energy)		(UW_TO_W((u64)(energy) * 10))
+
 /*
  * As per USB PD Spec Rev 3.18 (Sec. 6.5.13.11), the number of fixed batteries
  * that a port can be queried is restricted to 4.
@@ -1580,8 +1583,7 @@ static u16 tcpm_charge_to_energy(int charge, int voltage)
 {
 	u64 energy = div_u64((u64)charge * voltage, 1000000);
 
-	/* Battery telemetry is reported in increments of 0.1Wh */
-	return (u16)UW_TO_W(energy * 10);
+	return UWH_TO_PD_ENERGY(energy);
 }
 
 static int tcpm_pd_send_batt_status(struct tcpm_port *port)
@@ -1612,16 +1614,17 @@ static int tcpm_pd_send_batt_status(struct tcpm_port *port)
 	else
 		batt_present = val.intval > 0;
 
-	ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_CHARGE_NOW,
-					&val);
+	ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_ENERGY_NOW, &val);
 	if (!ret) {
-		charge_now = val.intval;
-		ret = power_supply_get_property(batt,
-						POWER_SUPPLY_PROP_VOLTAGE_AVG,
-						&val);
-		if (!ret)
-			present_charge = tcpm_charge_to_energy(charge_now,
-							       val.intval);
+		present_charge = UWH_TO_PD_ENERGY(val.intval);
+	} else {
+		ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_CHARGE_NOW, &val);
+		if (!ret) {
+			charge_now = val.intval;
+			ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_VOLTAGE_AVG, &val);
+			if (!ret)
+				present_charge = tcpm_charge_to_energy(charge_now, val.intval);
+		}
 	}
 
 	ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_STATUS, &val);
@@ -1678,19 +1681,31 @@ static int tcpm_pd_send_batt_cap(struct tcpm_port *port)
 
 	invalid_ref = false;
 	batt = port->fixed_batt[batt_id];
-	ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_VOLTAGE_AVG,
-					&val);
-	if (!ret) {
-		vol = val.intval;
-		ret = power_supply_get_property(batt,
-						POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
-						&val);
+
+	ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, &val);
+	if (!ret)
+		design_cap = UWH_TO_PD_ENERGY(val.intval);
+
+	ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_ENERGY_FULL, &val);
+	if (!ret)
+		charge_cap = UWH_TO_PD_ENERGY(val.intval);
+
+	if (design_cap != BATTERY_PROPERTY_UNKNOWN && charge_cap != BATTERY_PROPERTY_UNKNOWN)
+		goto send_cap;
+
+	ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_VOLTAGE_AVG, &val);
+	if (ret)
+		goto send_cap;
+
+	vol = val.intval;
+	if (design_cap == BATTERY_PROPERTY_UNKNOWN) {
+		ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, &val);
 		if (!ret)
 			design_cap = tcpm_charge_to_energy(val.intval, vol);
+	}
 
-		ret = power_supply_get_property(batt,
-						POWER_SUPPLY_PROP_CHARGE_FULL,
-						&val);
+	if (charge_cap == BATTERY_PROPERTY_UNKNOWN) {
+		ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_CHARGE_FULL, &val);
 		if (!ret)
 			charge_cap = tcpm_charge_to_energy(val.intval, vol);
 	}

---
base-commit: e1e6e541c5c9cf548e9fdc35fc26808c82074440
change-id: 20260820-tcpm-energy-props-upstream-a493353f0054

Best regards,
-- 
Amit Sunil Dhamne <amitsd@google.com>



^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] usb: typec: tcpm: Support native battery energy properties in battery AMS
  2026-08-20 21:17 [PATCH] usb: typec: tcpm: Support native battery energy properties in battery AMS Amit Sunil Dhamne via B4 Relay
@ 2026-08-24 11:27 ` Heikki Krogerus
  0 siblings, 0 replies; 2+ messages in thread
From: Heikki Krogerus @ 2026-08-24 11:27 UTC (permalink / raw)
  To: amitsd
  Cc: Badhri Jagan Sridharan, Greg Kroah-Hartman, linux-usb,
	linux-kernel, RD Babiera, Kyle Tso, Sebastian Reichel

On Thu, Aug 20, 2026 at 09:17:58PM +0000, Amit Sunil Dhamne via B4 Relay wrote:
> From: Amit Sunil Dhamne <amitsd@google.com>
> 
> Some fuel gauges report battery telemetry in energy rather than charge.
> Add support for querying native energy properties for Battery Status and
> Battery Capabilities AMS, falling back to calculating energy from charge
> and average voltage when primary properties are not supported.
> 
> +---------+--------------------+----------------------------------+
> | Sr. No. | Primary            | Fallback                         |
> +---------+--------------------+----------------------------------+
> | 1       | ENERGY_NOW         | CHARGE_NOW + VOLTAGE_AVG         |
> | 2       | ENERGY_FULL_DESIGN | CHARGE_FULL_DESIGN + VOLTAGE_AVG |
> | 3       | ENERGY_FULL        | CHARGE_FULL + VOLTAGE_AVG        |
> +---------+--------------------+----------------------------------+
> Note: All properties above are to be prefixed with POWER_SUPPLY_PROP_.
> 
> Closes: https://lore.kernel.org/all/amVJ1u67qHENBQ5l@venus/
> Suggested-by: Sebastian Reichel <sebastian.reichel@collabora.com>
> Assisted-by: Gemini:gemini-3.1-pro
> Signed-off-by: Amit Sunil Dhamne <amitsd@google.com>
> Reviewed-by: Badhri Jagan Sridharan <badhri@google.com>

Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>

> ---
>  drivers/usb/typec/tcpm/tcpm.c | 57 +++++++++++++++++++++++++++----------------
>  1 file changed, 36 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
> index a8cd1959c426..0d7dc0b51c87 100644
> --- a/drivers/usb/typec/tcpm/tcpm.c
> +++ b/drivers/usb/typec/tcpm/tcpm.c
> @@ -410,6 +410,9 @@ struct pd_timings {
>  /* Convert microwatt to watt */
>  #define UW_TO_W(pow)				(div_u64((pow), 1000000))
>  
> +/* Convert micro-Watt-hours to USB PD energy (increments of 0.1Wh) */
> +#define UWH_TO_PD_ENERGY(energy)		(UW_TO_W((u64)(energy) * 10))
> +
>  /*
>   * As per USB PD Spec Rev 3.18 (Sec. 6.5.13.11), the number of fixed batteries
>   * that a port can be queried is restricted to 4.
> @@ -1580,8 +1583,7 @@ static u16 tcpm_charge_to_energy(int charge, int voltage)
>  {
>  	u64 energy = div_u64((u64)charge * voltage, 1000000);
>  
> -	/* Battery telemetry is reported in increments of 0.1Wh */
> -	return (u16)UW_TO_W(energy * 10);
> +	return UWH_TO_PD_ENERGY(energy);
>  }
>  
>  static int tcpm_pd_send_batt_status(struct tcpm_port *port)
> @@ -1612,16 +1614,17 @@ static int tcpm_pd_send_batt_status(struct tcpm_port *port)
>  	else
>  		batt_present = val.intval > 0;
>  
> -	ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_CHARGE_NOW,
> -					&val);
> +	ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_ENERGY_NOW, &val);
>  	if (!ret) {
> -		charge_now = val.intval;
> -		ret = power_supply_get_property(batt,
> -						POWER_SUPPLY_PROP_VOLTAGE_AVG,
> -						&val);
> -		if (!ret)
> -			present_charge = tcpm_charge_to_energy(charge_now,
> -							       val.intval);
> +		present_charge = UWH_TO_PD_ENERGY(val.intval);
> +	} else {
> +		ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_CHARGE_NOW, &val);
> +		if (!ret) {
> +			charge_now = val.intval;
> +			ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_VOLTAGE_AVG, &val);
> +			if (!ret)
> +				present_charge = tcpm_charge_to_energy(charge_now, val.intval);
> +		}
>  	}
>  
>  	ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_STATUS, &val);
> @@ -1678,19 +1681,31 @@ static int tcpm_pd_send_batt_cap(struct tcpm_port *port)
>  
>  	invalid_ref = false;
>  	batt = port->fixed_batt[batt_id];
> -	ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_VOLTAGE_AVG,
> -					&val);
> -	if (!ret) {
> -		vol = val.intval;
> -		ret = power_supply_get_property(batt,
> -						POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
> -						&val);
> +
> +	ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, &val);
> +	if (!ret)
> +		design_cap = UWH_TO_PD_ENERGY(val.intval);
> +
> +	ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_ENERGY_FULL, &val);
> +	if (!ret)
> +		charge_cap = UWH_TO_PD_ENERGY(val.intval);
> +
> +	if (design_cap != BATTERY_PROPERTY_UNKNOWN && charge_cap != BATTERY_PROPERTY_UNKNOWN)
> +		goto send_cap;
> +
> +	ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_VOLTAGE_AVG, &val);
> +	if (ret)
> +		goto send_cap;
> +
> +	vol = val.intval;
> +	if (design_cap == BATTERY_PROPERTY_UNKNOWN) {
> +		ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, &val);
>  		if (!ret)
>  			design_cap = tcpm_charge_to_energy(val.intval, vol);
> +	}
>  
> -		ret = power_supply_get_property(batt,
> -						POWER_SUPPLY_PROP_CHARGE_FULL,
> -						&val);
> +	if (charge_cap == BATTERY_PROPERTY_UNKNOWN) {
> +		ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_CHARGE_FULL, &val);
>  		if (!ret)
>  			charge_cap = tcpm_charge_to_energy(val.intval, vol);
>  	}
> 
> ---
> base-commit: e1e6e541c5c9cf548e9fdc35fc26808c82074440
> change-id: 20260820-tcpm-energy-props-upstream-a493353f0054
> 
> Best regards,
> -- 
> Amit Sunil Dhamne <amitsd@google.com>
> 

-- 
heikki

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-08-24 11:27 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-20 21:17 [PATCH] usb: typec: tcpm: Support native battery energy properties in battery AMS Amit Sunil Dhamne via B4 Relay
2026-08-24 11:27 ` Heikki Krogerus

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®