drivers/phy/tegra/xusb.c

Source file repositories/reference/linux-study-clean/drivers/phy/tegra/xusb.c

File Facts

System
Linux kernel
Corpus path
drivers/phy/tegra/xusb.c
Extension
.c
Size
36243 bytes
Lines
1552
Domain
Driver Families
Bucket
drivers/phy
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

sizeof(struct device_driver),
					GFP_KERNEL);
	if (!port->dev.driver)
		return -ENOMEM;

	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;
	}

	INIT_WORK(&port->usb_phy_work, tegra_xusb_usb_phy_work);
	usb_role_switch_set_drvdata(port->usb_role_sw, port);

	port->usb_phy.otg = devm_kzalloc(&port->dev, sizeof(struct usb_otg),
					 GFP_KERNEL);
	if (!port->usb_phy.otg)
		return -ENOMEM;

	lane = tegra_xusb_find_lane(port->padctl, "usb2", port->index);
	if (IS_ERR(lane))
		return PTR_ERR(lane);

	/*
	 * Assign phy dev to usb-phy dev. Host/device drivers can use phy
	 * reference to retrieve usb-phy details.
	 */
	port->usb_phy.dev = &lane->pad->lanes[port->index]->dev;
	port->usb_phy.dev->driver = port->dev.driver;
	port->usb_phy.otg->usb_phy = &port->usb_phy;
	port->usb_phy.otg->set_peripheral = tegra_xusb_set_peripheral;
	port->usb_phy.otg->set_host = tegra_xusb_set_host;

	err = usb_add_phy_dev(&port->usb_phy);
	if (err < 0) {
		dev_err(&port->dev, "Failed to add USB PHY: %d\n", err);
		return err;
	}

	/* populate connector entry */
	of_platform_populate(port->dev.of_node, NULL, NULL, &port->dev);

	return err;
}

static void tegra_xusb_parse_usb_role_default_mode(struct tegra_xusb_port *port)
{
	enum usb_role role = USB_ROLE_NONE;
	enum usb_dr_mode mode = usb_get_role_switch_default_mode(&port->dev);

	if (mode == USB_DR_MODE_HOST)
		role = USB_ROLE_HOST;
	else if (mode == USB_DR_MODE_PERIPHERAL)
		role = USB_ROLE_DEVICE;

	if (role != USB_ROLE_NONE) {
		usb_role_switch_set_role(port->usb_role_sw, role);
		dev_dbg(&port->dev, "usb role default mode is %s", modes[mode]);
	}
}

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");

	if (!of_property_read_string(np, "mode", &mode)) {
		int err = match_string(modes, ARRAY_SIZE(modes), mode);
		if (err < 0) {
			dev_err(&port->dev, "invalid value %s for \"mode\"\n",
				mode);
			usb2->mode = USB_DR_MODE_UNKNOWN;
		} else {
			usb2->mode = err;
		}
	} else {
		usb2->mode = USB_DR_MODE_HOST;
	}

	/* usb-role-switch property is mandatory for OTG/Peripheral modes */
	if (usb2->mode == USB_DR_MODE_PERIPHERAL ||

Annotation

Implementation Notes