usb: typec: ucsi: acpi: Move to the new API
authorHeikki Krogerus <heikki.krogerus@linux.intel.com>
Mon, 4 Nov 2019 14:24:29 +0000 (17:24 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 4 Nov 2019 20:53:11 +0000 (21:53 +0100)
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@linux.intel.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Link: https://lore.kernel.org/r/20191104142435.29960-13-heikki.krogerus@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/typec/ucsi/ucsi_acpi.c

index a18112a..3f17861 100644 (file)
@@ -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);