usb: typec: ucsi: ccg: enable runtime pm support
authorAjay Gupta <ajayg@nvidia.com>
Fri, 7 Jun 2019 16:34:21 +0000 (09:34 -0700)
committerWolfram Sang <wsa@the-dreams.de>
Fri, 7 Jun 2019 22:09:20 +0000 (00:09 +0200)
The change enables runtime pm support to UCSI CCG driver.
Added ucsi_resume() function to enable notification after
system reusme. Exported both ucsi_resume() and ucsi_send_command()
symbols in ucsi.c for modular build.

Signed-off-by: Ajay Gupta <ajayg@nvidia.com>
Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
drivers/usb/typec/ucsi/ucsi.c
drivers/usb/typec/ucsi/ucsi.h
drivers/usb/typec/ucsi/ucsi_ccg.c

index 7850b85..ba288b9 100644 (file)
@@ -206,7 +206,17 @@ int ucsi_send_command(struct ucsi *ucsi, struct ucsi_control *ctrl,
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(ucsi_send_command);
 
+int ucsi_resume(struct ucsi *ucsi)
+{
+       struct ucsi_control ctrl;
+
+       /* Restore UCSI notification enable mask after system resume */
+       UCSI_CMD_SET_NTFY_ENABLE(ctrl, UCSI_ENABLE_NTFY_ALL);
+       return ucsi_send_command(ucsi, &ctrl, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(ucsi_resume);
 /* -------------------------------------------------------------------------- */
 
 void ucsi_altmode_update_active(struct ucsi_connector *con)
index 1e2981a..de87d0b 100644 (file)
@@ -430,6 +430,7 @@ int ucsi_send_command(struct ucsi *ucsi, struct ucsi_control *ctrl,
                      void *retval, size_t size);
 
 void ucsi_altmode_update_active(struct ucsi_connector *con);
+int ucsi_resume(struct ucsi *ucsi);
 
 #if IS_ENABLED(CONFIG_TYPEC_DP_ALTMODE)
 struct typec_altmode *
index 9d46aa9..b15bc6c 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
 
 #include <asm/unaligned.h>
 #include "ucsi.h"
@@ -210,6 +212,7 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
        if (quirks && quirks->max_read_len)
                max_read_len = quirks->max_read_len;
 
+       pm_runtime_get_sync(uc->dev);
        while (rem_len > 0) {
                msgs[1].buf = &data[len - rem_len];
                rlen = min_t(u16, rem_len, max_read_len);
@@ -218,12 +221,14 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
                status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
                if (status < 0) {
                        dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+                       pm_runtime_put_sync(uc->dev);
                        return status;
                }
                rab += rlen;
                rem_len -= rlen;
        }
 
+       pm_runtime_put_sync(uc->dev);
        return 0;
 }
 
@@ -249,13 +254,16 @@ static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
        msgs[0].len = len + sizeof(rab);
        msgs[0].buf = buf;
 
+       pm_runtime_get_sync(uc->dev);
        status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
        if (status < 0) {
                dev_err(uc->dev, "i2c_transfer failed %d\n", status);
+               pm_runtime_put_sync(uc->dev);
                kfree(buf);
                return status;
        }
 
+       pm_runtime_put_sync(uc->dev);
        kfree(buf);
        return 0;
 }
@@ -1134,6 +1142,10 @@ static int ucsi_ccg_probe(struct i2c_client *client,
        if (status)
                dev_err(uc->dev, "cannot create sysfs group: %d\n", status);
 
+       pm_runtime_set_active(uc->dev);
+       pm_runtime_enable(uc->dev);
+       pm_runtime_idle(uc->dev);
+
        return 0;
 }
 
@@ -1143,6 +1155,7 @@ static int ucsi_ccg_remove(struct i2c_client *client)
 
        cancel_work_sync(&uc->work);
        ucsi_unregister_ppm(uc->ucsi);
+       pm_runtime_disable(uc->dev);
        free_irq(uc->irq, uc);
        sysfs_remove_group(&uc->dev->kobj, &ucsi_ccg_attr_group);
 
@@ -1155,9 +1168,34 @@ static const struct i2c_device_id ucsi_ccg_device_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, ucsi_ccg_device_id);
 
+static int ucsi_ccg_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct ucsi_ccg *uc = i2c_get_clientdata(client);
+
+       return ucsi_resume(uc->ucsi);
+}
+
+static int ucsi_ccg_runtime_suspend(struct device *dev)
+{
+       return 0;
+}
+
+static int ucsi_ccg_runtime_resume(struct device *dev)
+{
+       return 0;
+}
+
+static const struct dev_pm_ops ucsi_ccg_pm = {
+       .resume = ucsi_ccg_resume,
+       .runtime_suspend = ucsi_ccg_runtime_suspend,
+       .runtime_resume = ucsi_ccg_runtime_resume,
+};
+
 static struct i2c_driver ucsi_ccg_driver = {
        .driver = {
                .name = "ucsi_ccg",
+               .pm = &ucsi_ccg_pm,
        },
        .probe = ucsi_ccg_probe,
        .remove = ucsi_ccg_remove,