[PATCH v5 2/4] usb: typec: ucsi: Add support for message out data structure

Pooja Katiyar
2025-10-30T14:48:33Z

Add support for updating message out data structure for UCSI
ACPI interface for UCSI 2.1 and UCSI 3.0 commands such as
Set PDOs and LPM Firmware Update.

Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Pooja Katiyar <pooja.katiyar@intel.com>
---
Changelog v3:
- Added message_out fields to UCSI structure and updated sync_control
to perform write operation.
- Removed extra DSM Write call.

Changelog v2:
- Moved write_message_out operation to .sync_control.
- Updated ucsi_send_command to accept message_out data.

drivers/usb/typec/ucsi/ucsi.c | 14 ++++++++++++++
drivers/usb/typec/ucsi/ucsi.h | 2 ++
drivers/usb/typec/ucsi/ucsi_acpi.c | 16 ++++++++++++++++
3 files changed, 32 insertions(+)

diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c
index ee0c0d77e67d..ae199e5683cb 100644
--- a/drivers/usb/typec/ucsi/ucsi.c
+++ b/drivers/usb/typec/ucsi/ucsi.c
@@ -67,6 +67,20 @@ int ucsi_sync_control_common(struct ucsi *ucsi, u64 command, u32 *cci)

reinit_completion(&ucsi->complete);

+ if (ucsi->message_out_size > 0) {
+ if (!ucsi->ops->write_message_out) {
+ ucsi->message_out_size = 0;
+ ret = -EOPNOTSUPP;
+ goto out_clear_bit;
+ }
+
+ ret = ucsi->ops->write_message_out(ucsi, ucsi->message_out,
+ ucsi->message_out_size);
+ ucsi->message_out_size = 0;
+ if (ret)
+ goto out_clear_bit;
+ }
+
ret = ucsi->ops->async_control(ucsi, command);
if (ret)
goto out_clear_bit;
diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h
index 76343285be59..8c79e6699020 100644
--- a/drivers/usb/typec/ucsi/ucsi.h
+++ b/drivers/usb/typec/ucsi/ucsi.h
@@ -69,6 +69,7 @@ struct dentry;
* @read_cci: Read CCI register
* @poll_cci: Read CCI register while polling with notifications disabled
* @read_message_in: Read message data from UCSI
+ * @write_message_out: Write message data to UCSI
* @sync_control: Blocking control operation
* @async_control: Non-blocking control operation
* @update_altmodes: Squashes duplicate DP altmodes
@@ -84,6 +85,7 @@ struct ucsi_operations {
int (*read_cci)(struct ucsi *ucsi, u32 *cci);
int (*poll_cci)(struct ucsi *ucsi, u32 *cci);
int (*read_message_in)(struct ucsi *ucsi, void *val, size_t val_len);
+ int (*write_message_out)(struct ucsi *ucsi, void *data, size_t data_len);
int (*sync_control)(struct ucsi *ucsi, u64 command, u32 *cci);
int (*async_control)(struct ucsi *ucsi, u64 command);
bool (*update_altmodes)(struct ucsi *ucsi, u8 recipient,
diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c
index f1d1f6917b09..f9beeb835238 100644
--- a/drivers/usb/typec/ucsi/ucsi_acpi.c
+++ b/drivers/usb/typec/ucsi/ucsi_acpi.c
@@ -86,6 +86,21 @@ static int ucsi_acpi_read_message_in(struct ucsi *ucsi, void *val, size_t val_le
return 0;
}

+static int ucsi_acpi_write_message_out(struct ucsi *ucsi, void *data, size_t data_len)
+{
+ struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
+
+ if (!data || !data_len)
+ return -EINVAL;
+
+ if (ucsi->version <= UCSI_VERSION_1_2)
+ memcpy(ua->base + UCSI_MESSAGE_OUT, data, data_len);
+ else
+ memcpy(ua->base + UCSIv2_MESSAGE_OUT, data, data_len);
+
+ return 0;
+}
+
static int ucsi_acpi_async_control(struct ucsi *ucsi, u64 command)
{
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
@@ -101,6 +116,7 @@ static const struct ucsi_operations ucsi_acpi_ops = {
.read_cci = ucsi_acpi_read_cci,
.poll_cci = ucsi_acpi_poll_cci,
.read_message_in = ucsi_acpi_read_message_in,
+ .write_message_out = ucsi_acpi_write_message_out,
.sync_control = ucsi_sync_control_common,
.async_control = ucsi_acpi_async_control
};
--
2.43.0