From patchwork Wed Mar 12 23:42:01 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amit Sunil Dhamne via B4 Relay X-Patchwork-Id: 873050 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5B7521E5B7D; Wed, 12 Mar 2025 23:43:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741823000; cv=none; b=LH+x9hLLYli8CgMCmMbmHZUZ8f6Z2l38zRfeZ8Zn/CLq/u89KCHxdCzaS7oxKCIpg+jrQy5fVNNz5mOtAx+4WtF+YX019urNgfl+LnrGkkzSslnxFY7E3BWmOsxJ8g9mmlasxjNXwZsDNT5703XNt/IZgl3NpofZz+IVonnUJ3g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741823000; c=relaxed/simple; bh=oNHEqFnHlfFcftIEwL+ZSyzQY3I5krbjajiCBWj4zhM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=HO1CKS+6sS31O8utfcVgQyF/jZ74M+OEYMOM7LypqJQ4/7NeSfBQlV2kkB5mnPvUZtobkmNP+UJmqH6kPDcqIV1TpU0IlelqADCvTRsFzTCedWwBbCfFxKvt8XK1ns5ram1nmaobwbNZ2tW22vSgwh/KGA/29E5NGIyTqV3gMU4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=bDl7urbm; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="bDl7urbm" Received: by smtp.kernel.org (Postfix) with ESMTPS id CBD70C4CEEB; Wed, 12 Mar 2025 23:43:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1741822999; bh=oNHEqFnHlfFcftIEwL+ZSyzQY3I5krbjajiCBWj4zhM=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=bDl7urbmpwbzxmuEqxaqwGE8H7Lq9MZCpqwL6sro/WrWsitPY1b4+TDe8t8N2N+OO io4R5xzQ9gB+WhwgmhkXD6XyjM+ShWV1GG1Q9Zlj5XBkbKv2FdYLxCHg3oBLRnoayS YiV2jP3oFIUls2OqzQNC6K9N+nldd9+226Tm8SCLEPvcKWbAZKZFMPZQXCHTaqvzQL MSw+tzCrit9SVgy67O/AQCAhs7GPQdQLYcQHv0b9sZfxeR60M3BjMLW0DNRng/UUoL VGgOdqqdqvHjw4/4FjasCZBevllr2yRg6qQm/8pyjfMVrigpSykgUKvsiL556y69Iu n6pv1PgQ6g0Cw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id B66CFC35FF1; Wed, 12 Mar 2025 23:43:19 +0000 (UTC) From: Amit Sunil Dhamne via B4 Relay Date: Wed, 12 Mar 2025 16:42:01 -0700 Subject: [PATCH 1/5] dt-bindings: connector: add fixed-batteries property Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250312-batt_ops-v1-1-88e0bb3129fd@google.com> References: <20250312-batt_ops-v1-0-88e0bb3129fd@google.com> In-Reply-To: <20250312-batt_ops-v1-0-88e0bb3129fd@google.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Greg Kroah-Hartman , Badhri Jagan Sridharan , Sebastian Reichel , Heikki Krogerus , "Rafael J. Wysocki" , Len Brown , Pavel Machek Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org, linux-pm@vger.kernel.org, RD Babiera , Kyle Tso , Amit Sunil Dhamne X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1741822998; l=2148; i=amitsd@google.com; s=20241031; h=from:subject:message-id; bh=lqB7hbM4siiws9pIh8thUf/I8+c5fiz+QxbzSuLaKTI=; b=hsUx8+UVc88upFK9cm+h8BLvCbfLdOUWzajlTp2MMm6mhFBleKWb8+HpA/plfvmMQYjbZ68zu p4UeoLFlbZaDKPMCwtoPQDgTMN7r+riaPZLxj73hm2hWzkwoq23N1HT X-Developer-Key: i=amitsd@google.com; a=ed25519; pk=wD+XZSST4dmnNZf62/lqJpLm7fiyT8iv462zmQ3H6bI= X-Endpoint-Received: by B4 Relay for amitsd@google.com/20241031 with auth_id=262 X-Original-From: Amit Sunil Dhamne Reply-To: amitsd@google.com From: Amit Sunil Dhamne Add a new "fixed-batteries" DT property to connector class. This property is populated with nodes associated with battery type power supplies powering the USB PD connector. This is needed by the Type-C Port Manager (TCPM) to query psy properties which are used to feed Battery_Status & Battery_Capacity AMS. Signed-off-by: Amit Sunil Dhamne --- Documentation/devicetree/bindings/connector/usb-connector.yaml | 8 ++++++++ Documentation/devicetree/bindings/usb/maxim,max33359.yaml | 1 + 2 files changed, 9 insertions(+) diff --git a/Documentation/devicetree/bindings/connector/usb-connector.yaml b/Documentation/devicetree/bindings/connector/usb-connector.yaml index 11e40d225b9f3a0d0aeea7bf764f1c00a719d615..5e15bc060f5a2cfce842f83de738f1e8bae3ce2d 100644 --- a/Documentation/devicetree/bindings/connector/usb-connector.yaml +++ b/Documentation/devicetree/bindings/connector/usb-connector.yaml @@ -300,6 +300,14 @@ properties: $ref: /schemas/types.yaml#/definitions/uint8-array maxItems: 4 + fixed-batteries: + description: Contains references to nodes associated with battery type power + supplies powering the USB PD device. These batteries are fixed type and + not hot swappable. + minItems: 1 + maxItems: 4 + $ref: /schemas/types.yaml#/definitions/phandle-array + dependencies: sink-vdos-v1: [ sink-vdos ] sink-vdos: [ sink-vdos-v1 ] diff --git a/Documentation/devicetree/bindings/usb/maxim,max33359.yaml b/Documentation/devicetree/bindings/usb/maxim,max33359.yaml index 3de4dc40b79192b60443421b557bd2fb18683bf7..66c99f0131f074f1c08e31d7481f555647e3b2f8 100644 --- a/Documentation/devicetree/bindings/usb/maxim,max33359.yaml +++ b/Documentation/devicetree/bindings/usb/maxim,max33359.yaml @@ -75,6 +75,7 @@ examples: PDO_FIXED(9000, 2000, 0)>; sink-bc12-completion-time-ms = <500>; pd-revision = /bits/ 8 <0x03 0x01 0x01 0x08>; + fixed-batteries = <&batt1 &batt2>; }; }; }; From patchwork Wed Mar 12 23:42:03 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amit Sunil Dhamne via B4 Relay X-Patchwork-Id: 873049 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 80C301F0E48; Wed, 12 Mar 2025 23:43:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741823000; cv=none; b=kRd6Fmc1jJLyQbi2sWlKG1utbfvC8MwpjWWwR7Cp12VIKdFAm2js033tnZRJozvTZTZnx6/DPibc6MChvvICFvuhm+85xix32nMMcHx7yzirUEO94nq7INM0eLfuVJE6tr7qrp1buijJFJxyrAorCG5/ehBXj5Q05ASBvd45tMg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741823000; c=relaxed/simple; bh=afE7iqHaEzszgRWnZVNiYr+rdCf5/b897AXjXV5srUU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=N92rPpKvcui5lEkS9I5cEwqzNSwEp3G0l0Pto3v3zyETwkL0WnvIT7ls2S44RlxbglRUBdrnQoHBjuT/EIDDWs1y6jYCpY19x7Tep+pDWELKDuAenM8uTMucHMtA6a/X06oaNBgZprbuggmeWGZGyVlHp83m5hMQWk2tnFhsC2U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=tFHqe11m; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="tFHqe11m" Received: by smtp.kernel.org (Postfix) with ESMTPS id 04ADAC4CEF2; Wed, 12 Mar 2025 23:43:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1741823000; bh=afE7iqHaEzszgRWnZVNiYr+rdCf5/b897AXjXV5srUU=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=tFHqe11mwcv1xnMg4dOaVKHIuTTIJozwQZXOtN8Mz8zcjBgLHLrFdhAA7qV68QysQ szIBs/LTI8cd7NJyBaz++N+XGqq1hCIfp2zoU7QsUvCcIhgflnsYc4mcF7dnxbQUDW B0YQE0GeLLPIHW0V6DqVyzvv7vN5gwEACxIxkswWMhdBkGq2m+dNX7wBxKDWxXxSpP xitnvNhOc3rMu2nT7YPcWGUFO7RDoWP2CO0a/fVcOf8xImh7wZWYvTilq3ee8JQrh+ fvl1b8fpihb+wO/797m+MclQQnJxsh4jSHMZMbUXXEE0vq5cgDE+nJJpSJni8nzTcp 11N+yc6OUVHXg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id EC8ADC28B2E; Wed, 12 Mar 2025 23:43:19 +0000 (UTC) From: Amit Sunil Dhamne via B4 Relay Date: Wed, 12 Mar 2025 16:42:03 -0700 Subject: [PATCH 3/5] usb: typec: tcpm: Add support for Battery Status response message Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250312-batt_ops-v1-3-88e0bb3129fd@google.com> References: <20250312-batt_ops-v1-0-88e0bb3129fd@google.com> In-Reply-To: <20250312-batt_ops-v1-0-88e0bb3129fd@google.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Greg Kroah-Hartman , Badhri Jagan Sridharan , Sebastian Reichel , Heikki Krogerus , "Rafael J. Wysocki" , Len Brown , Pavel Machek Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org, linux-pm@vger.kernel.org, RD Babiera , Kyle Tso , Amit Sunil Dhamne X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1741822998; l=9539; i=amitsd@google.com; s=20241031; h=from:subject:message-id; bh=R3bHGGUWI+arh8+QWnfjJz8sHg4WRzXg+q2l4c+Ptkk=; b=NyUSf7Rjfz8NXScDvzgLTUDmO3O9pDM+TSPJAY/fzhxq4HQkzEELnqGT+oYq+in9Awv+7e3uN PdJFIhBht5dD/Jz2IWokHjh4id8+7pCUmd2ELwbuaID/cBAv5KFUMwy X-Developer-Key: i=amitsd@google.com; a=ed25519; pk=wD+XZSST4dmnNZf62/lqJpLm7fiyT8iv462zmQ3H6bI= X-Endpoint-Received: by B4 Relay for amitsd@google.com/20241031 with auth_id=262 X-Original-From: Amit Sunil Dhamne Reply-To: amitsd@google.com From: Amit Sunil Dhamne Add support for responding to Get_Battery_Status (extended) request with a Battery_Status (data) msg. The requester shall request the status of an individual battery by providing an index in Get_Battery_Status. In case of failure to identify battery, the responder shall reply with an appropriate message indicating so. Battery status support is only provided for fixed batteries indexed from 0 - 3. Support for Battery_Status 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 Reviewed-by: Kyle Tso Reviewed-by: Badhri Jagan Sridharan --- drivers/usb/typec/tcpm/tcpm.c | 127 +++++++++++++++++++++++++++++++++++++++++- include/linux/usb/pd.h | 34 +++++++++++ 2 files changed, 159 insertions(+), 2 deletions(-) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 6bf1a22c785aff6b1ad77a20d85e22580527f5b1..2d0dcb998608e25c308159873c6b10e178e0a7a1 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -228,6 +228,7 @@ enum pd_msg_request { PD_MSG_DATA_SINK_CAP, PD_MSG_DATA_SOURCE_CAP, PD_MSG_DATA_REV, + PD_MSG_DATA_BATT_STATUS }; enum adev_actions { @@ -332,6 +333,15 @@ struct pd_timings { u32 snk_bc12_cmpletion_time; }; +/* + * As per USB PD Spec Rev 3.18 (Sec. 6.5.13.11), a sink can have a maximum + * of 4 fixed batteries indexed [0, 3]. + */ +#define MAX_NUM_FIXED_BATT 4 + +/* Convert microwatt to watt */ +#define UWH_TO_WH(pow) ((pow) / 1000000) + struct tcpm_port { struct device *dev; @@ -580,6 +590,15 @@ struct tcpm_port { /* Indicates maximum (revision, version) supported */ struct pd_revision_info pd_rev; + + struct power_supply *fixed_batt[MAX_NUM_FIXED_BATT]; + u8 fixed_batt_cnt; + + /* + * Variable used to store battery_ref from the Get_Battery_Status + * request to process Battery_Status messages. + */ + u8 batt_request; #ifdef CONFIG_DEBUG_FS struct dentry *dentry; struct mutex logbuffer_lock; /* log buffer access lock */ @@ -1339,6 +1358,62 @@ static int tcpm_pd_send_sink_caps(struct tcpm_port *port) return tcpm_pd_transmit(port, TCPC_TX_SOP, &msg); } +#define BATTERY_PROPERTY_UNKNOWN 0xffff + +static int tcpm_pd_send_batt_status(struct tcpm_port *port) +{ + struct pd_message msg; + struct power_supply *batt; + u32 bsdo; + u32 batt_id = port->batt_request; + union power_supply_propval val; + int ret; + bool batt_present = false; + u8 charging_status = BSDO_BATTERY_INFO_RSVD; + u16 present_charge = BATTERY_PROPERTY_UNKNOWN; + + memset(&msg, 0, sizeof(msg)); + if (batt_id < MAX_NUM_FIXED_BATT && port->fixed_batt[batt_id]) { + batt_present = true; + batt = port->fixed_batt[batt_id]; + ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_ENERGY_NOW, &val); + /* Battery Present Charge is reported in increments of 0.1WH */ + if (!ret) + present_charge = (u16)(UWH_TO_WH(val.intval) * 10); + + ret = power_supply_get_property(batt, POWER_SUPPLY_PROP_STATUS, + &val); + if (!ret) { + switch (val.intval) { + case POWER_SUPPLY_STATUS_CHARGING: + case POWER_SUPPLY_STATUS_FULL: + charging_status = BSDO_BATTERY_INFO_CHARGING; + break; + case POWER_SUPPLY_STATUS_DISCHARGING: + charging_status = BSDO_BATTERY_INFO_DISCHARGING; + break; + case POWER_SUPPLY_STATUS_NOT_CHARGING: + charging_status = BSDO_BATTERY_INFO_IDLE; + break; + default: + charging_status = BSDO_BATTERY_INFO_RSVD; + break; + } + } + } + + bsdo = BSDO(present_charge, batt_present ? charging_status : 0, + batt_present, !batt_present); + msg.payload[0] = cpu_to_le32(bsdo); + msg.header = PD_HEADER_LE(PD_DATA_BATT_STATUS, + port->pwr_role, + port->data_role, + port->negotiated_rev, + port->message_id, + 1); + 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) { @@ -3597,6 +3672,7 @@ static void tcpm_pd_ext_msg_request(struct tcpm_port *port, { enum pd_ext_msg_type type = pd_header_type_le(msg->header); unsigned int data_size = pd_ext_header_data_size_le(msg->ext_msg.header); + const struct pd_chunked_ext_message_data *ext_msg = &msg->ext_msg; /* stopping VDM state machine if interrupted by other Messages */ if (tcpm_vdm_ams(port)) { @@ -3605,7 +3681,7 @@ static void tcpm_pd_ext_msg_request(struct tcpm_port *port, mod_vdm_delayed_work(port, 0); } - if (!(le16_to_cpu(msg->ext_msg.header) & PD_EXT_HDR_CHUNKED)) { + if (!(le16_to_cpu(ext_msg->header) & PD_EXT_HDR_CHUNKED)) { tcpm_pd_handle_msg(port, PD_MSG_CTRL_NOT_SUPP, NONE_AMS); tcpm_log(port, "Unchunked extended messages unsupported"); return; @@ -3630,9 +3706,13 @@ static void tcpm_pd_ext_msg_request(struct tcpm_port *port, NONE_AMS, 0); } break; + case PD_EXT_GET_BATT_STATUS: + port->batt_request = ext_msg->data[0]; + 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: - case PD_EXT_GET_BATT_STATUS: case PD_EXT_BATT_CAP: case PD_EXT_GET_MANUFACTURER_INFO: case PD_EXT_MANUFACTURER_INFO: @@ -3833,6 +3913,14 @@ static bool tcpm_send_queued_message(struct tcpm_port *port) ret); tcpm_ams_finish(port); break; + case PD_MSG_DATA_BATT_STATUS: + ret = tcpm_pd_send_batt_status(port); + if (ret) + tcpm_log(port, + "Failed to send battery status ret=%d", + ret); + tcpm_ams_finish(port); + break; default: break; } @@ -7164,6 +7252,35 @@ static void tcpm_fw_get_timings(struct tcpm_port *port, struct fwnode_handle *fw port->timings.snk_bc12_cmpletion_time = val; } +static void tcpm_fw_get_batt(struct tcpm_port *port, struct fwnode_handle *fwnode) +{ + int i, ret; + enum power_supply_type psy_type; + + ret = power_supply_get_by_fwnode_reference_array(fwnode, + "fixed-batteries", + port->fixed_batt, + MAX_NUM_FIXED_BATT); + if (ret < 0) { + tcpm_log(port, + "Unable to parse or find batteries property, ret=%d", + ret); + return; + } + + port->fixed_batt_cnt = ret; + for (i = 0; i < port->fixed_batt_cnt; i++) { + if (!port->fixed_batt[i]) + continue; + + psy_type = port->fixed_batt[i]->desc->type; + if (psy_type != POWER_SUPPLY_TYPE_BATTERY) + tcpm_log(port, + "Wrong power supply type (%u) at idx:%d. Should be battery type.", + psy_type, i); + } +} + static int tcpm_fw_get_caps(struct tcpm_port *port, struct fwnode_handle *fwnode) { struct fwnode_handle *capabilities, *child, *caps = NULL; @@ -7746,6 +7863,7 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) tcpm_fw_get_timings(port, tcpc->fwnode); tcpm_fw_get_pd_revision(port, tcpc->fwnode); + tcpm_fw_get_batt(port, tcpc->fwnode); port->try_role = port->typec_caps.prefer_role; @@ -7827,6 +7945,11 @@ void tcpm_unregister_port(struct tcpm_port *port) hrtimer_cancel(&port->vdm_state_machine_timer); hrtimer_cancel(&port->state_machine_timer); + for (i = 0; i < port->fixed_batt_cnt; i++) { + if (port->fixed_batt[i]) + power_supply_put(port->fixed_batt[i]); + } + tcpm_reset_port(port); tcpm_port_unregister_pd(port); diff --git a/include/linux/usb/pd.h b/include/linux/usb/pd.h index 3068c3084eb6176d7d9184c3959a4110282a9fa0..299e7c20127cd5b7dcdae4f24468df4b34b072b5 100644 --- a/include/linux/usb/pd.h +++ b/include/linux/usb/pd.h @@ -553,4 +553,38 @@ void usb_power_delivery_unlink_device(struct usb_power_delivery *pd, struct devi #endif /* CONFIG_TYPEC */ +/* Battery Status Data Object */ +#define BSDO_PRESENT_CAPACITY_SHIFT 16 +#define BSDO_PRESENT_CAPACITY_MASK GENMASK(31, 16) +#define BSDO_CHG_STATUS_SHIFT 10 +#define BSDO_CHG_STATUS_MASK GENMASK(11, 10) +#define BSDO_BATTERY_PRESENT BIT(9) +#define BSDO_INVALID_BATTERY_REFERENCE BIT(8) + +/* + * Battery Charge Status: Battery Charging Status Values as defined in + * "USB PD Spec Rev3.1 Ver1.8", "Table 6-46 Battery Status Data Object (BSDO)". + */ +#define BSDO_BATTERY_INFO_CHARGING 0x1 +#define BSDO_BATTERY_INFO_DISCHARGING 0x2 +#define BSDO_BATTERY_INFO_IDLE 0x3 +#define BSDO_BATTERY_INFO_RSVD 0x4 + +/** + * BSDO() - Pack data into Battery Status Data Object format + * @batt_charge: Battery's present state of charge in 0.1WH increment + * @chg_status: Battery charge status + * @batt_present: When set, this indicates battery is present/attached. + * Otherwise: + * - Non hot-swappable battery: Indicates absence of battery + * - Hot-swappable battery: Indicates battery is unattached + * @invalid_ref: Set when invalid battery reference is made in + * Get_Battery_Status request, else 0 + */ +#define BSDO(batt_charge, chg_status, batt_present, invalid_ref) \ + ((((batt_charge) << BSDO_PRESENT_CAPACITY_SHIFT) & BSDO_PRESENT_CAPACITY_MASK) | \ + (((chg_status) << BSDO_CHG_STATUS_SHIFT) & BSDO_CHG_STATUS_MASK) | \ + ((batt_present) ? BSDO_BATTERY_PRESENT : 0) | \ + ((invalid_ref) ? BSDO_INVALID_BATTERY_REFERENCE : 0)) + #endif /* __LINUX_USB_PD_H */ From patchwork Wed Mar 12 23:42:05 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amit Sunil Dhamne via B4 Relay X-Patchwork-Id: 873048 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BE3C41F2C3B; Wed, 12 Mar 2025 23:43:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741823000; cv=none; b=Lmvo9oXxWq5qzaKE14wfVzr8aqzzcwNJyeYHnzBmTFiyy7MV+F7UlFPCnJ0qDqqVwvX3Tfm53iLIv+M9RVRTlJr4JeWNsEvhC6BA7mlcxYsZ4UUETBCQ4TxJ2yZkYckNc7fEzOOgmDw30jHmwZZR3YKBnOViHA7FyVH59PdUWe4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741823000; c=relaxed/simple; bh=2bA2EGf65pJlOWExavnBkLXzvsRgKvhpp4DQILDFGmQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Dp0YxoTQV6Y0HHndDonJymS7kzwrT3y0qAkENW7Oj66PkR9/K8oMxjSfHoDvoeau+aYXm5GlVgFtvg0s6vq4mbgG/lDaw3qwAHMxVpK6vs+nw9nz4ZKstqwZCFdilBGlM18PfI/L6xe5AddSpBM4PEhADPEPH2xqBMvAWG/JskU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Ucxyt6vW; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Ucxyt6vW" Received: by smtp.kernel.org (Postfix) with ESMTPS id 3C41FC4CEFD; Wed, 12 Mar 2025 23:43:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1741823000; bh=2bA2EGf65pJlOWExavnBkLXzvsRgKvhpp4DQILDFGmQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=Ucxyt6vWdpKB4cnlLzoyXSYw+g8pzq87rPj6iZ35bnmPlIgM5RlsW1DA0M9/oYQEZ gPdQpSXGGOF8fYIWymBxH1SR2iMTyfijwoBBsBdlSQlayKFQsCYBwEUFwE7JmO1HG/ 7xV0xxoMgPtzq5lTgZcHRWjRWj4zka6LuRN3ieLz2R16foYOMHjdxm0kRFJmY3U0dt /4uBs+e77ehKC8wuWQzW37T2pPiYm6VDIP3MtbUJ4AZ34xhmPqfy5jtehh+HnnTf+P 8bFs/QKnHG4fguPyVgSSzfJZIJ6+eQP3w+k9VMACHfD34a/hpjQAmR5SM+MVeaAoyf GhEiaF3/Dicdw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 313A3C28B2E; Wed, 12 Mar 2025 23:43:20 +0000 (UTC) From: Amit Sunil Dhamne via B4 Relay Date: Wed, 12 Mar 2025 16:42:05 -0700 Subject: [PATCH 5/5] usb: typec: tcpm: Add support for Battery Cap response message Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20250312-batt_ops-v1-5-88e0bb3129fd@google.com> References: <20250312-batt_ops-v1-0-88e0bb3129fd@google.com> In-Reply-To: <20250312-batt_ops-v1-0-88e0bb3129fd@google.com> To: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Greg Kroah-Hartman , Badhri Jagan Sridharan , Sebastian Reichel , Heikki Krogerus , "Rafael J. Wysocki" , Len Brown , Pavel Machek Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org, linux-pm@vger.kernel.org, RD Babiera , Kyle Tso , Amit Sunil Dhamne X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1741822998; l=6790; i=amitsd@google.com; s=20241031; h=from:subject:message-id; bh=0Lu/D0Fl96RaaPPHoSMV9B9kZVmVEN77JVQOeODSfIQ=; b=0K5DuxJ6366+M06TTECI+vhtR57ZydL0Iv3549e6hZtapSUyxuhzcxvc+QaXrwK1A5/bO7GST /e7NHyWB5MDBGNdUJuyW7btkH5QC4ZLmfvBpXkJEvlUQ4RVHhtMWv54 X-Developer-Key: i=amitsd@google.com; a=ed25519; pk=wD+XZSST4dmnNZf62/lqJpLm7fiyT8iv462zmQ3H6bI= X-Endpoint-Received: by B4 Relay for amitsd@google.com/20241031 with auth_id=262 X-Original-From: Amit Sunil Dhamne Reply-To: amitsd@google.com From: Amit Sunil Dhamne 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 Reviewed-by: Kyle Tso Reviewed-by: Badhri Jagan Sridharan --- 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 2d0dcb998608e25c308159873c6b10e178e0a7a1..22a5a0d463c8738d2160cbe9472207b8053f99b8 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 { @@ -595,8 +596,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; + 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 299e7c20127cd5b7dcdae4f24468df4b34b072b5..791f58b7d1de6c4093fcf38b298e7051ebb6e98c 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