On Mon, Nov 04, 2019 at 05:24:29PM +0300, Heikki Krogerus wrote: > Replacing the old "cmd" and "sync" callbacks with an > implementation of struct ucsi_operations. The ACPI > notification (interrupt) handler will from now on read the > CCI (Command Status and Connector Change Indication) > register, and call ucsi_connector_change() function and/or > complete pending command completions based on it. > > Signed-off-by: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx> FTR, my request for better (non-)iomem documentation isn't really that important. Reviewed-by: Guenter Roeck <linux@xxxxxxxxxxxx> > --- > drivers/usb/typec/ucsi/ucsi_acpi.c | 91 +++++++++++++++++++++++------- > 1 file changed, 72 insertions(+), 19 deletions(-) > > diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c > index a18112a83fae..3f1786170098 100644 > --- a/drivers/usb/typec/ucsi/ucsi_acpi.c > +++ b/drivers/usb/typec/ucsi/ucsi_acpi.c > @@ -19,7 +19,9 @@ > struct ucsi_acpi { > struct device *dev; > struct ucsi *ucsi; > - struct ucsi_ppm ppm; > + void __iomem *base; > + struct completion complete; > + unsigned long flags; > guid_t guid; > }; > > @@ -39,27 +41,73 @@ static int ucsi_acpi_dsm(struct ucsi_acpi *ua, int func) > return 0; > } > > -static int ucsi_acpi_cmd(struct ucsi_ppm *ppm, struct ucsi_control *ctrl) > +static int ucsi_acpi_read(struct ucsi *ucsi, unsigned int offset, > + void *val, size_t val_len) > { > - struct ucsi_acpi *ua = container_of(ppm, struct ucsi_acpi, ppm); > + struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); > + int ret; > + > + ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ); > + if (ret) > + return ret; > + > + memcpy(val, (const void __force *)(ua->base + offset), val_len); > + > + return 0; > +} > + > +static int ucsi_acpi_async_write(struct ucsi *ucsi, unsigned int offset, > + const void *val, size_t val_len) > +{ > + struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); > > - ppm->data->ctrl.raw_cmd = ctrl->raw_cmd; > + memcpy((void __force *)(ua->base + offset), val, val_len); > > return ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_WRITE); > } > > -static int ucsi_acpi_sync(struct ucsi_ppm *ppm) > +static int ucsi_acpi_sync_write(struct ucsi *ucsi, unsigned int offset, > + const void *val, size_t val_len) > { > - struct ucsi_acpi *ua = container_of(ppm, struct ucsi_acpi, ppm); > + struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); > + int ret; > + > + set_bit(COMMAND_PENDING, &ua->flags); > + > + ret = ucsi_acpi_async_write(ucsi, offset, val, val_len); > + if (ret) > + goto out_clear_bit; > > - return ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ); > + if (!wait_for_completion_timeout(&ua->complete, msecs_to_jiffies(5000))) > + ret = -ETIMEDOUT; > + > +out_clear_bit: > + clear_bit(COMMAND_PENDING, &ua->flags); > + > + return ret; > } > > +static const struct ucsi_operations ucsi_acpi_ops = { > + .read = ucsi_acpi_read, > + .sync_write = ucsi_acpi_sync_write, > + .async_write = ucsi_acpi_async_write > +}; > + > static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data) > { > struct ucsi_acpi *ua = data; > + u32 cci; > + int ret; > + > + ret = ucsi_acpi_read(ua->ucsi, UCSI_CCI, &cci, sizeof(cci)); > + if (ret) > + return; > > - ucsi_notify(ua->ucsi); > + if (test_bit(COMMAND_PENDING, &ua->flags) && > + cci & (UCSI_CCI_ACK_COMPLETE | UCSI_CCI_COMMAND_COMPLETE)) > + complete(&ua->complete); > + else if (UCSI_CCI_CONNECTOR(cci)) > + ucsi_connector_change(ua->ucsi, UCSI_CCI_CONNECTOR(cci)); > } > > static int ucsi_acpi_probe(struct platform_device *pdev) > @@ -90,35 +138,39 @@ static int ucsi_acpi_probe(struct platform_device *pdev) > * it can not be requested here, and we can not use > * devm_ioremap_resource(). > */ > - ua->ppm.data = devm_ioremap(&pdev->dev, res->start, resource_size(res)); > - if (!ua->ppm.data) > + ua->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); > + if (!ua->base) > return -ENOMEM; > > - if (!ua->ppm.data->version) > - return -ENODEV; > - > ret = guid_parse(UCSI_DSM_UUID, &ua->guid); > if (ret) > return ret; > > - ua->ppm.cmd = ucsi_acpi_cmd; > - ua->ppm.sync = ucsi_acpi_sync; > + init_completion(&ua->complete); > ua->dev = &pdev->dev; > > + ua->ucsi = ucsi_create(&pdev->dev, &ucsi_acpi_ops); > + if (IS_ERR(ua->ucsi)) > + return PTR_ERR(ua->ucsi); > + > + ucsi_set_drvdata(ua->ucsi, ua); > + > status = acpi_install_notify_handler(ACPI_HANDLE(&pdev->dev), > ACPI_DEVICE_NOTIFY, > ucsi_acpi_notify, ua); > if (ACPI_FAILURE(status)) { > dev_err(&pdev->dev, "failed to install notify handler\n"); > + ucsi_destroy(ua->ucsi); > return -ENODEV; > } > > - ua->ucsi = ucsi_register_ppm(&pdev->dev, &ua->ppm); > - if (IS_ERR(ua->ucsi)) { > + ret = ucsi_register(ua->ucsi); > + if (ret) { > acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), > ACPI_DEVICE_NOTIFY, > ucsi_acpi_notify); > - return PTR_ERR(ua->ucsi); > + ucsi_destroy(ua->ucsi); > + return ret; > } > > platform_set_drvdata(pdev, ua); > @@ -130,7 +182,8 @@ static int ucsi_acpi_remove(struct platform_device *pdev) > { > struct ucsi_acpi *ua = platform_get_drvdata(pdev); > > - ucsi_unregister_ppm(ua->ucsi); > + ucsi_unregister(ua->ucsi); > + ucsi_destroy(ua->ucsi); > > acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), ACPI_DEVICE_NOTIFY, > ucsi_acpi_notify);