summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Chen <peter.chen@nxp.com>2019-01-14 16:46:18 +0800
committerDong Aisheng <aisheng.dong@nxp.com>2019-11-25 15:56:17 +0800
commit86f778d41662602d08245eb854fb260f8d5d3bc0 (patch)
tree8cab07fc0a15960fdfc3da136af3bf83a6912ed6
parente4cf49447137cffa30d60fa27ff6cc09e95853b9 (diff)
MLK-20754 usb: cdns3: add role switch sys entry
It is an experimental feature, and tested by internal team for Carplay feature. Signed-off-by: Peter Chen <peter.chen@nxp.com> (cherry picked from commit 270c1ea5168763a03f79c4f9ecadb2cd18dc08f9)
-rw-r--r--Documentation/ABI/testing/sysfs-platform-cadence-usb39
-rw-r--r--drivers/usb/cdns3/core.c62
2 files changed, 67 insertions, 4 deletions
diff --git a/Documentation/ABI/testing/sysfs-platform-cadence-usb3 b/Documentation/ABI/testing/sysfs-platform-cadence-usb3
new file mode 100644
index 000000000000..c969518dcc30
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-cadence-usb3
@@ -0,0 +1,9 @@
+What: /sys/bus/platform/devices/5b110000.usb3/role
+Date: Jan 2019
+Contact: Peter Chen <peter.chen@nxp.com>
+Description:
+ It returns string "gadget", "host" and "none" when read it,
+ it indicates current controller role.
+
+ It will do role switch when write "gadget" or "host" to it.
+ Only controller at dual-role configuration supports writing.
diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c
index b8a183f03af7..063678b6b577 100644
--- a/drivers/usb/cdns3/core.c
+++ b/drivers/usb/cdns3/core.c
@@ -499,6 +499,54 @@ static int cdns3_register_extcon(struct cdns3 *cdns)
return 0;
}
+static ssize_t cdns3_role_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cdns3 *cdns = dev_get_drvdata(dev);
+
+ if (cdns->role != CDNS3_ROLE_END)
+ return sprintf(buf, "%s\n", cdns3_role(cdns)->name);
+ else
+ return sprintf(buf, "%s\n", "none");
+}
+
+static ssize_t cdns3_role_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t n)
+{
+ struct cdns3 *cdns = dev_get_drvdata(dev);
+ enum cdns3_roles role;
+ int ret;
+
+ if (!(cdns->roles[CDNS3_ROLE_HOST] && cdns->roles[CDNS3_ROLE_GADGET])) {
+ dev_warn(dev, "Current configuration is not dual-role, quit\n");
+ return -EPERM;
+ }
+
+ for (role = CDNS3_ROLE_HOST; role <= CDNS3_ROLE_GADGET; role++)
+ if (!strncmp(buf, cdns->roles[role]->name,
+ strlen(cdns->roles[role]->name)))
+ break;
+
+ if (role == cdns->role)
+ return -EINVAL;
+
+ disable_irq(cdns->irq);
+ ret = cdns3_do_role_switch(cdns, role);
+ enable_irq(cdns->irq);
+
+ return (ret == 0) ? n : ret;
+}
+static DEVICE_ATTR(role, 0644, cdns3_role_show, cdns3_role_store);
+
+static struct attribute *cdns3_attrs[] = {
+ &dev_attr_role.attr,
+ NULL,
+};
+
+static const struct attribute_group cdns3_attr_group = {
+ .attrs = cdns3_attrs,
+};
+
/**
* cdns3_probe - probe for cdns3 core device
* @pdev: Pointer to cdns3 core platform device
@@ -613,6 +661,10 @@ static int cdns3_probe(struct platform_device *pdev)
if (ret)
goto err4;
+ ret = sysfs_create_group(&dev->kobj, &cdns3_attr_group);
+ if (ret)
+ goto err4;
+
device_set_wakeup_capable(dev, true);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
@@ -648,13 +700,15 @@ err1:
static int cdns3_remove(struct platform_device *pdev)
{
struct cdns3 *cdns = platform_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
- pm_runtime_get_sync(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
- pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_get_sync(dev);
+ pm_runtime_disable(dev);
+ pm_runtime_put_noidle(dev);
+ sysfs_remove_group(&dev->kobj, &cdns3_attr_group);
cdns3_remove_roles(cdns);
usb_phy_shutdown(cdns->usbphy);
- cdns3_disable_unprepare_clks(&pdev->dev);
+ cdns3_disable_unprepare_clks(dev);
return 0;
}