All of lore.kernel.org
 help / color / mirror / Atom feed
From: Heikki Krogerus <heikki.krogerus@linux.intel.com>
To: amitsd@google.com
Cc: Badhri Jagan Sridharan <badhri@google.com>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org,
	Kyle Tso <kyletso@google.com>, RD Babiera <rdbabiera@google.com>
Subject: Re: [PATCH] usb: typec: tcpm: Add support for Battery Cap response message
Date: Thu, 16 Jul 2026 11:47:37 +0300	[thread overview]
Message-ID: <aliaqQzLVVRyBhFO@kuha> (raw)
In-Reply-To: <20260714-batt-caps-upstream-v1-1-c86f0a7fbbda@google.com>

On Tue, Jul 14, 2026 at 11:06:47PM +0000, Amit Sunil Dhamne via B4 Relay wrote:
> From: Amit Sunil Dhamne <amitsd@google.com>
> 
> Add support for responding to Get_Battery_Cap (extended) request with a
> a Battery_Capabilities (extended) msg. The requester will request
> Battery Cap for a specific battery using an index in Get_Battery_Cap. In
> case of failure to identify battery, TCPM shall reply with an
> appropriate message indicating so.
> 
> As the Battery Cap Data Block size is 9 Bytes (lesser than
> MaxExtendedMsgChunkLen of 26B), only a single chunk is required to
> complete the AMS.
> 
> Support for Battery_Capabilities message is required for sinks that
> contain battery as specified in USB PD Rev3.1 v1.8
> ("Applicability of Data Messages" section).
> 
> 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>

> ---
> This patch depends on the series [1].
> 
> [1] https://lore.kernel.org/all/20260714-batt-status-v5-0-9de4aa900b69@google.com/
> ---
>  drivers/usb/typec/tcpm/tcpm.c | 108 +++++++++++++++++++++++++++++++++++++-----
>  include/linux/usb/pd.h        |  22 +++++++++
>  2 files changed, 117 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
> index cd33ee131ebd..393266dd55f8 100644
> --- a/drivers/usb/typec/tcpm/tcpm.c
> +++ b/drivers/usb/typec/tcpm/tcpm.c
> @@ -234,7 +234,8 @@ enum pd_msg_request {
>  	PD_MSG_DATA_SOURCE_CAP,
>  	PD_MSG_DATA_REV,
>  	PD_MSG_EXT_SINK_CAP_EXT,
> -	PD_MSG_DATA_BATT_STATUS
> +	PD_MSG_DATA_BATT_STATUS,
> +	PD_MSG_EXT_BATT_CAP,
>  };
>  
>  enum adev_actions {
> @@ -1559,6 +1560,14 @@ static int tcpm_pd_send_sink_cap_ext(struct tcpm_port *port)
>  	return tcpm_pd_transmit(port, TCPC_TX_SOP, &msg);
>  }
>  
> +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);
> +}
> +
>  static int tcpm_pd_send_batt_status(struct tcpm_port *port)
>  {
>  	u16 present_charge = BATTERY_PROPERTY_UNKNOWN;
> @@ -1569,7 +1578,6 @@ static int tcpm_pd_send_batt_status(struct tcpm_port *port)
>  	u8 charging_status = 0;
>  	struct pd_message msg;
>  	int ret, charge_now;
> -	u64 energy_now;
>  	u32 bsdo;
>  
>  	tcpm_get_fixed_batt(port);
> @@ -1595,16 +1603,9 @@ static int tcpm_pd_send_batt_status(struct tcpm_port *port)
>  		ret = power_supply_get_property(batt,
>  						POWER_SUPPLY_PROP_VOLTAGE_AVG,
>  						&val);
> -		if (!ret) {
> -			energy_now = div_u64((u64)charge_now * val.intval,
> -					     1000000);
> -
> -			/*
> -			 * Battery Present Charge is reported in
> -			 * increments of 0.1WH.
> -			 */
> -			present_charge = (u16)UW_TO_W(energy_now * 10);
> -		}
> +		if (!ret)
> +			present_charge = tcpm_charge_to_energy(charge_now,
> +							       val.intval);
>  	}
>  
>  	ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_STATUS, &val);
> @@ -1640,6 +1641,71 @@ static int tcpm_pd_send_batt_status(struct tcpm_port *port)
>  	return tcpm_pd_transmit(port, TCPC_TX_SOP, &msg);
>  }
>  
> +static int tcpm_pd_send_batt_cap(struct tcpm_port *port)
> +{
> +	u16 design_cap = BATTERY_PROPERTY_UNKNOWN;
> +	u16 charge_cap = BATTERY_PROPERTY_UNKNOWN;
> +	u32 batt_id = port->batt_request_id;
> +	union power_supply_propval val;
> +	struct batt_cap_ext_msg bcdb;
> +	struct power_supply *batt;
> +	bool invalid_ref = true;
> +	struct pd_message msg;
> +	u8 data_obj_cnt;
> +	int ret, vol;
> +
> +	tcpm_get_fixed_batt(port);
> +	memset(&msg, 0, sizeof(msg));
> +
> +	if (batt_id >= port->fixed_batt_cnt || batt_id >= MAX_NUM_FIXED_BATT)
> +		goto send_cap;
> +
> +	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);
> +		if (!ret)
> +			design_cap = tcpm_charge_to_energy(val.intval, vol);
> +
> +		ret = power_supply_get_property(batt,
> +						POWER_SUPPLY_PROP_CHARGE_FULL,
> +						&val);
> +		if (!ret)
> +			charge_cap = tcpm_charge_to_energy(val.intval, vol);
> +	}
> +
> +send_cap:
> +
> +	/*
> +	 * As per the USB PD Rev3.1 v1.8 spec, if a battery VID (assigned by the
> +	 * USB-IF) does not exist or an invalid battery reference is made by the
> +	 * requestor, then set the VID field to 0xffff. If the VID field is
> +	 * 0xffff, set the PID field to 0.
> +	 */
> +	bcdb.vid = BATTERY_PROPERTY_UNKNOWN;
> +	bcdb.pid = 0;
> +	bcdb.batt_design_cap = cpu_to_le16(design_cap);
> +	bcdb.batt_last_chg_cap = cpu_to_le16(charge_cap);
> +	bcdb.batt_type = invalid_ref ? BATT_CAP_BATT_TYPE_INVALID_REF : 0;
> +	memcpy(msg.ext_msg.data, &bcdb, sizeof(bcdb));
> +	msg.ext_msg.header = PD_EXT_HDR_LE(sizeof(bcdb),
> +					   0, /* Denotes if request chunk */
> +					   0, /* Chunk number */
> +					   1  /* Chunked */);
> +
> +	data_obj_cnt = count_chunked_data_objs(sizeof(bcdb));
> +	msg.header = PD_HEADER_EXT_LE(PD_EXT_BATT_CAP, port->pwr_role,
> +				      port->data_role, port->negotiated_rev,
> +				      port->message_id, data_obj_cnt);
> +
> +	return tcpm_pd_transmit(port, TCPC_TX_SOP, &msg);
> +}
> +
>  static void mod_tcpm_delayed_work(struct tcpm_port *port, unsigned int delay_ms)
>  {
>  	if (delay_ms) {
> @@ -4041,8 +4107,16 @@ static void tcpm_pd_ext_msg_request(struct tcpm_port *port,
>  			tcpm_set_state(port, SOFT_RESET_SEND, 0);
>  		}
>  		break;
> -	case PD_EXT_SOURCE_CAP_EXT:
>  	case PD_EXT_GET_BATT_CAP:
> +		if (data_size >= 1) {
> +			port->batt_request_id = ext_msg->data[0];
> +			tcpm_pd_handle_msg(port, PD_MSG_EXT_BATT_CAP,
> +					   GETTING_BATTERY_CAPABILITIES);
> +		} else {
> +			tcpm_set_state(port, SOFT_RESET_SEND, 0);
> +		}
> +		break;
> +	case PD_EXT_SOURCE_CAP_EXT:
>  	case PD_EXT_BATT_CAP:
>  	case PD_EXT_GET_MANUFACTURER_INFO:
>  	case PD_EXT_MANUFACTURER_INFO:
> @@ -4261,6 +4335,14 @@ static bool tcpm_send_queued_message(struct tcpm_port *port)
>  					 ret);
>  			tcpm_ams_finish(port);
>  			break;
> +		case PD_MSG_EXT_BATT_CAP:
> +			ret = tcpm_pd_send_batt_cap(port);
> +			if (ret)
> +				tcpm_log(port,
> +					 "Failed to send battery cap ret=%d",
> +					 ret);
> +			tcpm_ams_finish(port);
> +			break;
>  		default:
>  			break;
>  		}
> diff --git a/include/linux/usb/pd.h b/include/linux/usb/pd.h
> index afb9c2c65588..10ff4af7dedc 100644
> --- a/include/linux/usb/pd.h
> +++ b/include/linux/usb/pd.h
> @@ -106,6 +106,9 @@ enum pd_ext_msg_type {
>  #define PD_HEADER_LE(type, pwr, data, rev, id, cnt) \
>  	cpu_to_le16(PD_HEADER((type), (pwr), (data), (rev), (id), (cnt), (0)))
>  
> +#define PD_HEADER_EXT_LE(type, pwr, data, rev, id, cnt) \
> +	cpu_to_le16(PD_HEADER((type), (pwr), (data), (rev), (id), (cnt), (1)))
> +
>  static inline unsigned int pd_header_cnt(u16 header)
>  {
>  	return (header >> PD_HEADER_CNT_SHIFT) & PD_HEADER_CNT_MASK;
> @@ -219,6 +222,25 @@ static inline u8 count_chunked_data_objs(u32 size)
>  	return ((size / 4) + (size % 4 ? 1 : 0));
>  }
>  
> +/**
> + * batt_cap_ext_msg - Battery capability extended PD message
> + * @vid: Battery Vendor ID (assigned by USB-IF)
> + * @pid: Battery Product ID (assigned by battery or device vendor)
> + * @batt_design_cap: Battery design capacity in 0.1Wh
> + * @batt_last_chg_cap: Battery last full charge capacity in 0.1Wh
> + * @batt_type: Battery Type. bit0 when set indicates invalid battery reference.
> + *             Rest of the bits are reserved.
> + */
> +struct batt_cap_ext_msg {
> +	__le16 vid;
> +	__le16 pid;
> +	__le16 batt_design_cap;
> +	__le16 batt_last_chg_cap;
> +	u8 batt_type;
> +} __packed;
> +
> +#define BATT_CAP_BATT_TYPE_INVALID_REF BIT(0)
> +
>  /* Sink Caps Extended Data Block Version */
>  #define SKEDB_VER_1_0				1
>  
> 
> ---
> base-commit: 0e35b9b6ec0ffcc5e23cbdec09f5c622ad532b53
> change-id: 20260714-batt-caps-upstream-57f2cbe8eed3
> prerequisite-change-id: 20260501-batt-status-16b6761c0bb1:v5
> prerequisite-patch-id: 39dd78a0bb18e681fcd8efb01b6879dbeb881a3a
> prerequisite-patch-id: 621fa71ad856f4b3246ec480ab17f8089b082932
> 
> Best regards,
> -- 
> Amit Sunil Dhamne <amitsd@google.com>
> 

-- 
heikki

      reply	other threads:[~2026-07-16  8:47 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-14 23:06 [PATCH] usb: typec: tcpm: Add support for Battery Cap response message Amit Sunil Dhamne via B4 Relay
2026-07-14 23:06 ` Amit Sunil Dhamne
2026-07-16  8:47 ` Heikki Krogerus [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aliaqQzLVVRyBhFO@kuha \
    --to=heikki.krogerus@linux.intel.com \
    --cc=amitsd@google.com \
    --cc=badhri@google.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=kyletso@google.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=rdbabiera@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.