phy: tegra: xusb: Add usb-role-switch support
If usb-role-switch property is present in USB 2 port, register usb-role-switch to receive usb role changes. Signed-off-by: Nagarjuna Kristam <nkristam@nvidia.com> Acked-by: Kishon Vijay Abraham I <kishon@ti.com> [treding@nvidia.com: rebase onto Greg's usb-next branch] Signed-off-by: Thierry Reding <treding@nvidia.com>
This commit is contained in:
parent
ca9e742b5c
commit
f67213cee2
@ -2,6 +2,7 @@
|
||||
config PHY_TEGRA_XUSB
|
||||
tristate "NVIDIA Tegra XUSB pad controller driver"
|
||||
depends on ARCH_TEGRA
|
||||
select USB_CONN_GPIO
|
||||
help
|
||||
Choose this option if you have an NVIDIA Tegra SoC.
|
||||
|
||||
|
@ -541,6 +541,11 @@ unregister:
|
||||
|
||||
static void tegra_xusb_port_unregister(struct tegra_xusb_port *port)
|
||||
{
|
||||
if (!IS_ERR_OR_NULL(port->usb_role_sw)) {
|
||||
of_platform_depopulate(&port->dev);
|
||||
usb_role_switch_unregister(port->usb_role_sw);
|
||||
}
|
||||
|
||||
device_unregister(&port->dev);
|
||||
}
|
||||
|
||||
@ -551,11 +556,64 @@ static const char *const modes[] = {
|
||||
[USB_DR_MODE_OTG] = "otg",
|
||||
};
|
||||
|
||||
static const char * const usb_roles[] = {
|
||||
[USB_ROLE_NONE] = "none",
|
||||
[USB_ROLE_HOST] = "host",
|
||||
[USB_ROLE_DEVICE] = "device",
|
||||
};
|
||||
|
||||
static int tegra_xusb_role_sw_set(struct usb_role_switch *sw,
|
||||
enum usb_role role)
|
||||
{
|
||||
struct tegra_xusb_port *port = usb_role_switch_get_drvdata(sw);
|
||||
|
||||
dev_dbg(&port->dev, "%s(): role %s\n", __func__, usb_roles[role]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_xusb_setup_usb_role_switch(struct tegra_xusb_port *port)
|
||||
{
|
||||
struct usb_role_switch_desc role_sx_desc = {
|
||||
.fwnode = dev_fwnode(&port->dev),
|
||||
.set = tegra_xusb_role_sw_set,
|
||||
};
|
||||
int err = 0;
|
||||
|
||||
/*
|
||||
* USB role switch driver needs parent driver owner info. This is a
|
||||
* suboptimal solution. TODO: Need to revisit this in a follow-up patch
|
||||
* where an optimal solution is possible with changes to USB role
|
||||
* switch driver.
|
||||
*/
|
||||
port->dev.driver = devm_kzalloc(&port->dev,
|
||||
sizeof(struct device_driver),
|
||||
GFP_KERNEL);
|
||||
port->dev.driver->owner = THIS_MODULE;
|
||||
|
||||
port->usb_role_sw = usb_role_switch_register(&port->dev,
|
||||
&role_sx_desc);
|
||||
if (IS_ERR(port->usb_role_sw)) {
|
||||
err = PTR_ERR(port->usb_role_sw);
|
||||
dev_err(&port->dev, "failed to register USB role switch: %d",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
usb_role_switch_set_drvdata(port->usb_role_sw, port);
|
||||
|
||||
/* populate connector entry */
|
||||
of_platform_populate(port->dev.of_node, NULL, NULL, &port->dev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2)
|
||||
{
|
||||
struct tegra_xusb_port *port = &usb2->base;
|
||||
struct device_node *np = port->dev.of_node;
|
||||
const char *mode;
|
||||
int err;
|
||||
|
||||
usb2->internal = of_property_read_bool(np, "nvidia,internal");
|
||||
|
||||
@ -572,6 +630,20 @@ static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2)
|
||||
usb2->mode = USB_DR_MODE_HOST;
|
||||
}
|
||||
|
||||
/* usb-role-switch property is mandatory for OTG/Peripheral modes */
|
||||
if (usb2->mode == USB_DR_MODE_PERIPHERAL ||
|
||||
usb2->mode == USB_DR_MODE_OTG) {
|
||||
if (of_property_read_bool(np, "usb-role-switch")) {
|
||||
err = tegra_xusb_setup_usb_role_switch(port);
|
||||
if (err < 0)
|
||||
return err;
|
||||
} else {
|
||||
dev_err(&port->dev, "usb-role-switch not found for %s mode",
|
||||
modes[usb2->mode]);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
usb2->supply = devm_regulator_get(&port->dev, "vbus");
|
||||
return PTR_ERR_OR_ZERO(usb2->supply);
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/usb/role.h>
|
||||
|
||||
/* legacy entry points for backwards-compatibility */
|
||||
int tegra_xusb_padctl_legacy_probe(struct platform_device *pdev);
|
||||
@ -266,6 +267,8 @@ struct tegra_xusb_port {
|
||||
struct list_head list;
|
||||
struct device dev;
|
||||
|
||||
struct usb_role_switch *usb_role_sw;
|
||||
|
||||
const struct tegra_xusb_port_ops *ops;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user