Reading UCSI_VERSION is a special case as there is no notification that syncs the data into host memory. Read UCSI_VERSION only once during initialization and provide it as a parameter to ucsi_register(). Signed-off-by: Christian A. Ehrhardt <lk@xxxxxxx> --- drivers/usb/typec/ucsi/ucsi.c | 13 ++++--------- drivers/usb/typec/ucsi/ucsi.h | 2 +- drivers/usb/typec/ucsi/ucsi_acpi.c | 8 +++++++- drivers/usb/typec/ucsi/ucsi_ccg.c | 12 ++++++++++-- drivers/usb/typec/ucsi/ucsi_glink.c | 11 ++++++++++- drivers/usb/typec/ucsi/ucsi_stm32g0.c | 26 ++++++++++++++++++++++---- 6 files changed, 54 insertions(+), 18 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index ae105383e69e..eb630447ba80 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -1581,18 +1581,13 @@ EXPORT_SYMBOL_GPL(ucsi_destroy); /** * ucsi_register - Register UCSI interface * @ucsi: UCSI instance + * @version: The revision of the UCSI spec */ -int ucsi_register(struct ucsi *ucsi) +int ucsi_register(struct ucsi *ucsi, u16 version) { - int ret; - - ret = ucsi->ops->read(ucsi, UCSI_VERSION, &ucsi->version, - sizeof(ucsi->version)); - if (ret) - return ret; - - if (!ucsi->version) + if (!version) return -ENODEV; + ucsi->version = version; /* * Version format is JJ.M.N (JJ = Major version, M = Minor version, diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index 7e35ffbe0a6f..100e16b49814 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -77,7 +77,7 @@ struct ucsi_operations { struct ucsi *ucsi_create(struct device *dev, const struct ucsi_operations *ops); void ucsi_destroy(struct ucsi *ucsi); -int ucsi_register(struct ucsi *ucsi); +int ucsi_register(struct ucsi *ucsi, u16 version); void ucsi_unregister(struct ucsi *ucsi); void *ucsi_get_drvdata(struct ucsi *ucsi); void ucsi_set_drvdata(struct ucsi *ucsi, void *data); diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c index 928eacbeb21a..710ddfc03ed0 100644 --- a/drivers/usb/typec/ucsi/ucsi_acpi.c +++ b/drivers/usb/typec/ucsi/ucsi_acpi.c @@ -226,6 +226,7 @@ static int ucsi_acpi_probe(struct platform_device *pdev) const struct dmi_system_id *id; struct ucsi_acpi *ua; struct resource *res; + u16 version; acpi_status status; int ret; @@ -272,7 +273,12 @@ static int ucsi_acpi_probe(struct platform_device *pdev) return -ENODEV; } - ret = ucsi_register(ua->ucsi); + ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ); + if (ret) + return ret; + version = le16_to_cpu(*(__le16 *)(ua->base + UCSI_VERSION)); + + ret = ucsi_register(ua->ucsi, version); if (ret) { acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), ACPI_DEVICE_NOTIFY, diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index 709295948c65..d47f5e31c98a 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -1356,7 +1356,7 @@ static int ccg_restart(struct ucsi_ccg *uc) return status; } - status = ucsi_register(uc->ucsi); + status = ucsi_register(uc->ucsi, uc->ucsi->version); if (status) { dev_err(uc->dev, "failed to register the interface\n"); return status; @@ -1422,6 +1422,7 @@ static int ucsi_ccg_probe(struct i2c_client *client) struct ucsi_ccg *uc; const char *fw_name; int status; + __le16 version; uc = devm_kzalloc(dev, sizeof(*uc), GFP_KERNEL); if (!uc) @@ -1477,7 +1478,14 @@ static int ucsi_ccg_probe(struct i2c_client *client) goto out_ucsi_destroy; } - status = ucsi_register(uc->ucsi); + status = ccg_read(uc, CCGX_RAB_UCSI_DATA_BLOCK(UCSI_VERSION), + (u8 *)&version, sizeof(version)); + if (status < 0) { + dev_err(uc->dev, "cannot read UCSI version - %d\n", status); + return status; + } + + status = ucsi_register(uc->ucsi, le16_to_cpu(version)); if (status) goto out_free_irq; diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c index 0a0d08467c56..7a0b28536abd 100644 --- a/drivers/usb/typec/ucsi/ucsi_glink.c +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -255,8 +255,17 @@ static void pmic_glink_ucsi_notify(struct work_struct *work) static void pmic_glink_ucsi_register(struct work_struct *work) { struct pmic_glink_ucsi *ucsi = container_of(work, struct pmic_glink_ucsi, register_work); + __le16 version; + int ret; + + ret = pmic_glink_ucsi_read(ucsi->ucsi, UCSI_VERSION, &version, + sizeof(version)); + if (ret < 0) { + dev_err(ucsi->dev, "cannot read version: %d\n", ret); + return; + } - ucsi_register(ucsi->ucsi); + ucsi_register(ucsi->ucsi, le16_to_cpu(version)); } static void pmic_glink_ucsi_callback(const void *data, size_t len, void *priv) diff --git a/drivers/usb/typec/ucsi/ucsi_stm32g0.c b/drivers/usb/typec/ucsi/ucsi_stm32g0.c index 93d7806681cf..112692c7a158 100644 --- a/drivers/usb/typec/ucsi/ucsi_stm32g0.c +++ b/drivers/usb/typec/ucsi/ucsi_stm32g0.c @@ -325,10 +325,10 @@ static int ucsi_stm32g0_fw_rcv(struct ucsi *ucsi, void *data, size_t len) return ucsi_stm32g0_bl_rcv_woack(ucsi, data, len); } -/* UCSI ops */ -static int ucsi_stm32g0_read(struct ucsi *ucsi, unsigned int offset, void *val, size_t len) +static int ucsi_stm32g0_read_from_hw(struct ucsi_stm32g0 *g0, + unsigned int offset, + void *val, size_t len) { - struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); struct i2c_client *client = g0->client; u8 reg = offset; struct i2c_msg msg[] = { @@ -357,6 +357,15 @@ static int ucsi_stm32g0_read(struct ucsi *ucsi, unsigned int offset, void *val, return 0; } +/* UCSI ops */ +static int ucsi_stm32g0_read(struct ucsi *ucsi, unsigned int offset, + void *val, size_t len) +{ + struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); + + return ucsi_stm32g0_read_from_hw(g0, offset, val, len); +} + static int ucsi_stm32g0_async_write(struct ucsi *ucsi, unsigned int offset, const void *val, size_t len) { @@ -445,6 +454,7 @@ static int ucsi_stm32g0_register(struct ucsi *ucsi) { struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); struct i2c_client *client = g0->client; + __le16 version; int ret; /* Request alert interrupt */ @@ -455,7 +465,15 @@ static int ucsi_stm32g0_register(struct ucsi *ucsi) return ret; } - ret = ucsi_register(ucsi); + ret = ucsi_stm32g0_read_from_hw(g0, UCSI_VERSION, &version, + sizeof(version)); + if (ret) { + dev_err(g0->dev, "failed to read version number: %d\n", ret); + free_irq(client->irq, g0); + return ret; + } + + ret = ucsi_register(ucsi, le16_to_cpu(version)); if (ret) { dev_err_probe(g0->dev, ret, "ucsi_register failed\n"); free_irq(client->irq, g0); -- 2.40.1