drivers/usb/host/uhci-platform.c

Source file repositories/reference/linux-study-clean/drivers/usb/host/uhci-platform.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/host/uhci-platform.c
Extension
.c
Size
5638 bytes
Lines
215
Domain
Driver Families
Bucket
drivers/usb
Inferred role
Driver Families: implementation source
Status
source 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

if (of_property_read_u32(np, "#ports", &num_ports) == 0) {
			uhci->rh_numports = num_ports;
			dev_info(&pdev->dev,
				"Detected %d ports from device-tree\n",
				num_ports);
		}
		if (of_device_is_compatible(np, "aspeed,ast2400-uhci") ||
		    of_device_is_compatible(np, "aspeed,ast2500-uhci") ||
		    of_device_is_compatible(np, "aspeed,ast2600-uhci") ||
		    of_device_is_compatible(np, "aspeed,ast2700-uhci")) {
			uhci->is_aspeed = 1;
			dev_info(&pdev->dev,
				 "Enabled Aspeed implementation workarounds\n");
		}
	}

	/* Get and enable clock if any specified */
	uhci->clk = devm_clk_get_optional(&pdev->dev, NULL);
	if (IS_ERR(uhci->clk)) {
		ret = PTR_ERR(uhci->clk);
		goto err_rmr;
	}
	ret = clk_prepare_enable(uhci->clk);
	if (ret) {
		dev_err(&pdev->dev, "Error couldn't enable clock (%d)\n", ret);
		goto err_rmr;
	}

	uhci->rsts = devm_reset_control_array_get_optional_shared(&pdev->dev);
	if (IS_ERR(uhci->rsts)) {
		ret = PTR_ERR(uhci->rsts);
		goto err_clk;
	}
	ret = reset_control_deassert(uhci->rsts);
	if (ret)
		goto err_clk;

	ret = platform_get_irq(pdev, 0);
	if (ret < 0)
		goto err_reset;

	ret = usb_add_hcd(hcd, ret, IRQF_SHARED);
	if (ret)
		goto err_reset;

	device_wakeup_enable(hcd->self.controller);
	return 0;

err_reset:
	reset_control_assert(uhci->rsts);
err_clk:
	clk_disable_unprepare(uhci->clk);
err_rmr:
	usb_put_hcd(hcd);

	return ret;
}

static void uhci_hcd_platform_remove(struct platform_device *pdev)
{
	struct usb_hcd *hcd = platform_get_drvdata(pdev);
	struct uhci_hcd *uhci = hcd_to_uhci(hcd);

	reset_control_assert(uhci->rsts);
	clk_disable_unprepare(uhci->clk);
	usb_remove_hcd(hcd);
	usb_put_hcd(hcd);
}

/* Make sure the controller is quiescent and that we're not using it
 * any more.  This is mainly for the benefit of programs which, like kexec,
 * expect the hardware to be idle: not doing DMA or generating IRQs.
 *
 * This routine may be called in a damaged or failing kernel.  Hence we
 * do not acquire the spinlock before shutting down the controller.
 */
static void uhci_hcd_platform_shutdown(struct platform_device *op)
{
	struct usb_hcd *hcd = platform_get_drvdata(op);

	uhci_hc_died(hcd_to_uhci(hcd));
}

static const struct of_device_id platform_uhci_ids[] = {
	{ .compatible = "generic-uhci", },
	{ .compatible = "platform-uhci", },
	{ .compatible = "aspeed,ast2700-uhci", .data = (void *)1 },
	{}
};
MODULE_DEVICE_TABLE(of, platform_uhci_ids);

Annotation

Implementation Notes