Skip to content

Commit f67213c

Browse files
Nagarjuna Kristamthierryreding
authored andcommitted
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 <[email protected]> Acked-by: Kishon Vijay Abraham I <[email protected]> [[email protected]: rebase onto Greg's usb-next branch] Signed-off-by: Thierry Reding <[email protected]>
1 parent ca9e742 commit f67213c

File tree

3 files changed

+76
-0
lines changed

3 files changed

+76
-0
lines changed

drivers/phy/tegra/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
config PHY_TEGRA_XUSB
33
tristate "NVIDIA Tegra XUSB pad controller driver"
44
depends on ARCH_TEGRA
5+
select USB_CONN_GPIO
56
help
67
Choose this option if you have an NVIDIA Tegra SoC.
78

drivers/phy/tegra/xusb.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,11 @@ static int tegra_xusb_port_init(struct tegra_xusb_port *port,
541541

542542
static void tegra_xusb_port_unregister(struct tegra_xusb_port *port)
543543
{
544+
if (!IS_ERR_OR_NULL(port->usb_role_sw)) {
545+
of_platform_depopulate(&port->dev);
546+
usb_role_switch_unregister(port->usb_role_sw);
547+
}
548+
544549
device_unregister(&port->dev);
545550
}
546551

@@ -551,11 +556,64 @@ static const char *const modes[] = {
551556
[USB_DR_MODE_OTG] = "otg",
552557
};
553558

559+
static const char * const usb_roles[] = {
560+
[USB_ROLE_NONE] = "none",
561+
[USB_ROLE_HOST] = "host",
562+
[USB_ROLE_DEVICE] = "device",
563+
};
564+
565+
static int tegra_xusb_role_sw_set(struct usb_role_switch *sw,
566+
enum usb_role role)
567+
{
568+
struct tegra_xusb_port *port = usb_role_switch_get_drvdata(sw);
569+
570+
dev_dbg(&port->dev, "%s(): role %s\n", __func__, usb_roles[role]);
571+
572+
return 0;
573+
}
574+
575+
static int tegra_xusb_setup_usb_role_switch(struct tegra_xusb_port *port)
576+
{
577+
struct usb_role_switch_desc role_sx_desc = {
578+
.fwnode = dev_fwnode(&port->dev),
579+
.set = tegra_xusb_role_sw_set,
580+
};
581+
int err = 0;
582+
583+
/*
584+
* USB role switch driver needs parent driver owner info. This is a
585+
* suboptimal solution. TODO: Need to revisit this in a follow-up patch
586+
* where an optimal solution is possible with changes to USB role
587+
* switch driver.
588+
*/
589+
port->dev.driver = devm_kzalloc(&port->dev,
590+
sizeof(struct device_driver),
591+
GFP_KERNEL);
592+
port->dev.driver->owner = THIS_MODULE;
593+
594+
port->usb_role_sw = usb_role_switch_register(&port->dev,
595+
&role_sx_desc);
596+
if (IS_ERR(port->usb_role_sw)) {
597+
err = PTR_ERR(port->usb_role_sw);
598+
dev_err(&port->dev, "failed to register USB role switch: %d",
599+
err);
600+
return err;
601+
}
602+
603+
usb_role_switch_set_drvdata(port->usb_role_sw, port);
604+
605+
/* populate connector entry */
606+
of_platform_populate(port->dev.of_node, NULL, NULL, &port->dev);
607+
608+
return err;
609+
}
610+
554611
static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2)
555612
{
556613
struct tegra_xusb_port *port = &usb2->base;
557614
struct device_node *np = port->dev.of_node;
558615
const char *mode;
616+
int err;
559617

560618
usb2->internal = of_property_read_bool(np, "nvidia,internal");
561619

@@ -572,6 +630,20 @@ static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2)
572630
usb2->mode = USB_DR_MODE_HOST;
573631
}
574632

633+
/* usb-role-switch property is mandatory for OTG/Peripheral modes */
634+
if (usb2->mode == USB_DR_MODE_PERIPHERAL ||
635+
usb2->mode == USB_DR_MODE_OTG) {
636+
if (of_property_read_bool(np, "usb-role-switch")) {
637+
err = tegra_xusb_setup_usb_role_switch(port);
638+
if (err < 0)
639+
return err;
640+
} else {
641+
dev_err(&port->dev, "usb-role-switch not found for %s mode",
642+
modes[usb2->mode]);
643+
return -EINVAL;
644+
}
645+
}
646+
575647
usb2->supply = devm_regulator_get(&port->dev, "vbus");
576648
return PTR_ERR_OR_ZERO(usb2->supply);
577649
}

drivers/phy/tegra/xusb.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/workqueue.h>
1313

1414
#include <linux/usb/otg.h>
15+
#include <linux/usb/role.h>
1516

1617
/* legacy entry points for backwards-compatibility */
1718
int tegra_xusb_padctl_legacy_probe(struct platform_device *pdev);
@@ -266,6 +267,8 @@ struct tegra_xusb_port {
266267
struct list_head list;
267268
struct device dev;
268269

270+
struct usb_role_switch *usb_role_sw;
271+
269272
const struct tegra_xusb_port_ops *ops;
270273
};
271274

0 commit comments

Comments
 (0)