[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <g5w3ydcvtxwvcu5armmnt4v6y6wsymt7rothnvaesdql6kdscz@rhkxzx3y47iv>
Date: Mon, 23 Jun 2025 23:51:13 +0200
From: Sebastian Reichel <sebastian.reichel@...labora.com>
To: amitsd@...gle.com
Cc: Rob Herring <robh@...nel.org>,
Krzysztof Kozlowski <krzk+dt@...nel.org>, Conor Dooley <conor+dt@...nel.org>,
Greg Kroah-Hartman <gregkh@...uxfoundation.org>, Badhri Jagan Sridharan <badhri@...gle.com>,
Heikki Krogerus <heikki.krogerus@...ux.intel.com>, "Rafael J. Wysocki" <rafael@...nel.org>,
Len Brown <len.brown@...el.com>, Pavel Machek <pavel@...nel.org>, Kyle Tso <kyletso@...gle.com>,
devicetree@...r.kernel.org, linux-kernel@...r.kernel.org, linux-usb@...r.kernel.org,
linux-pm@...r.kernel.org
Subject: Re: [PATCH v2 5/5] usb: typec: tcpm: Add support for Battery Cap
response message
Hi,
On Wed, May 07, 2025 at 06:00:26PM -0700, Amit Sunil Dhamne via B4 Relay wrote:
> From: Amit Sunil Dhamne <amitsd@...gle.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.
>
> Support has been added only for fixed batteries and not hot swappable
> ones.
>
> 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@...gle.com>
> Reviewed-by: Badhri Jagan Sridharan <badhri@...gle.com>
> Reviewed-by: Kyle Tso <kyletso@...gle.com>
> ---
> drivers/usb/typec/tcpm/tcpm.c | 96 +++++++++++++++++++++++++++++++++++++++++--
> include/linux/usb/pd.h | 31 ++++++++++++++
> 2 files changed, 123 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
> index 98df0c7ce00e43f6c95ab49237a414e1b4413369..4731126fbf19a50178be0cf8867b3fe08595724c 100644
> --- a/drivers/usb/typec/tcpm/tcpm.c
> +++ b/drivers/usb/typec/tcpm/tcpm.c
> @@ -228,7 +228,8 @@ enum pd_msg_request {
> PD_MSG_DATA_SINK_CAP,
> PD_MSG_DATA_SOURCE_CAP,
> PD_MSG_DATA_REV,
> - PD_MSG_DATA_BATT_STATUS
> + PD_MSG_DATA_BATT_STATUS,
> + PD_MSG_EXT_BATT_CAP,
> };
>
> enum adev_actions {
> @@ -597,8 +598,8 @@ struct tcpm_port {
> u8 fixed_batt_cnt;
>
> /*
> - * Variable used to store battery_ref from the Get_Battery_Status
> - * request to process Battery_Status messages.
> + * Variable used to store battery_ref from the Get_Battery_Status &
> + * Get_Battery_Caps request to process Battery_Status messages.
> */
> u8 batt_request;
> #ifdef CONFIG_DEBUG_FS
> @@ -1414,6 +1415,81 @@ 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)
> +{
> + struct pd_message msg;
> + struct power_supply *batt;
> + struct batt_cap_ext_msg bcdb;
> + u32 batt_id = port->batt_request;
> + int ret;
> + union power_supply_propval val;
> + bool batt_present = false;
> + u16 batt_design_cap = BATTERY_PROPERTY_UNKNOWN;
> + u16 batt_charge_cap = BATTERY_PROPERTY_UNKNOWN;
> + u8 data_obj_cnt;
> + /*
> + * As per USB PD Rev3.1 v1.8, if battery reference is incorrect,
> + * then set the VID field to 0xffff.
> + * If VID field is set to 0xffff, always set the PID field to
> + * 0x0000.
> + */
> + u16 vid = BATTERY_PROPERTY_UNKNOWN;
> + u16 pid = 0x0;
> +
> + memset(&msg, 0, sizeof(msg));
> +
> + if (batt_id < MAX_NUM_FIXED_BATT && port->fixed_batt[batt_id]) {
> + batt_present = true;
This should also handle POWER_SUPPLY_PROP_PRESENT.
Greetings,
-- Sebastian
> + batt = port->fixed_batt[batt_id];
> + ret = power_supply_get_property(batt,
> + POWER_SUPPLY_PROP_USBIF_VENDOR_ID,
> + &val);
> + if (!ret)
> + vid = val.intval;
> +
> + if (vid != BATTERY_PROPERTY_UNKNOWN) {
> + ret = power_supply_get_property(batt,
> + POWER_SUPPLY_PROP_USBIF_PRODUCT_ID,
> + &val);
> + if (!ret)
> + pid = val.intval;
> + }
> +
> + ret = power_supply_get_property(batt,
> + POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
> + &val);
> + if (!ret)
> + batt_design_cap = (u16)UWH_TO_WH(val.intval * 10);
> +
> + ret = power_supply_get_property(batt,
> + POWER_SUPPLY_PROP_ENERGY_FULL,
> + &val);
> + if (!ret)
> + batt_charge_cap = (u16)UWH_TO_WH(val.intval * 10);
> + }
> +
> + bcdb.vid = cpu_to_le16(vid);
> + bcdb.pid = cpu_to_le16(pid);
> + bcdb.batt_design_cap = cpu_to_le16(batt_design_cap);
> + bcdb.batt_last_chg_cap = cpu_to_le16(batt_charge_cap);
> + bcdb.batt_type = !batt_present ? 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 = cpu_to_le16(PD_HEADER(PD_EXT_BATT_CAP,
> + port->pwr_role,
> + port->data_role,
> + port->negotiated_rev,
> + port->message_id,
> + data_obj_cnt,
> + 1 /* Denotes if ext header */));
> + 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) {
> @@ -3711,8 +3787,12 @@ static void tcpm_pd_ext_msg_request(struct tcpm_port *port,
> tcpm_pd_handle_msg(port, PD_MSG_DATA_BATT_STATUS,
> GETTING_BATTERY_STATUS);
> break;
> - case PD_EXT_SOURCE_CAP_EXT:
> case PD_EXT_GET_BATT_CAP:
> + port->batt_request = ext_msg->data[0];
> + tcpm_pd_handle_msg(port, PD_MSG_EXT_BATT_CAP,
> + GETTING_BATTERY_CAPABILITIES);
> + break;
> + case PD_EXT_SOURCE_CAP_EXT:
> case PD_EXT_BATT_CAP:
> case PD_EXT_GET_MANUFACTURER_INFO:
> case PD_EXT_MANUFACTURER_INFO:
> @@ -3921,6 +4001,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 4efa7bfd9863915dfc8048da264116d9b05a447b..c89594177da57f4398b75c89c1991b4937614a70 100644
> --- a/include/linux/usb/pd.h
> +++ b/include/linux/usb/pd.h
> @@ -204,6 +204,37 @@ struct pd_message {
> };
> } __packed;
>
> +/*
> + * count_chunked_data_objs: Helper to calculate number of Data Objects on a 4
> + * byte boundary.
> + * @size: Size of data block for extended message. Should *not* include extended
> + * header size.
> + */
> +static inline u8 count_chunked_data_objs(u32 size)
> +{
> + size += offsetof(struct pd_chunked_ext_message_data, data);
> + 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)
> +
> /* PDO: Power Data Object */
> #define PDO_MAX_OBJECTS 7
>
>
> --
> 2.49.0.987.g0cc8ee98dc-goog
>
>
Download attachment "signature.asc" of type "application/pgp-signature" (834 bytes)
Powered by blists - more mailing lists