/** * ehci_hcd_omap_probe - initialize TI-based HCDs * @pdev: Pointer to this platform device's information * * Allocates basic resources for this USB host controller, and * then invokes the start() method for the HCD associated with it * through the hotplug entry's driver_data.
*/ staticint ehci_hcd_omap_probe(struct platform_device *pdev)
{ struct device *dev = &pdev->dev; struct usbhs_omap_platform_data *pdata = dev_get_platdata(dev); struct resource *res; struct usb_hcd *hcd; void __iomem *regs; int ret; int irq; int i; struct omap_hcd *omap;
if (usb_disabled()) return -ENODEV;
if (!dev->parent) {
dev_err(dev, "Missing parent device\n"); return -ENODEV;
}
/* For DT boot, get platform data from parent. i.e. usbhshost */ if (dev->of_node) {
pdata = dev_get_platdata(dev->parent);
dev->platform_data = pdata;
}
if (!pdata) {
dev_err(dev, "Missing platform data\n"); return -ENODEV;
}
irq = platform_get_irq(pdev, 0); if (irq < 0) return irq;
regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(regs)) return PTR_ERR(regs);
/* * Right now device-tree probed devices don't get dma_mask set. * Since shared usb code relies on it, set it here for now. * Once we have dma capability bindings this can go away.
*/
ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); if (ret) return ret;
ret = -ENODEV;
hcd = usb_create_hcd(&ehci_omap_hc_driver, dev,
dev_name(dev)); if (!hcd) {
dev_err(dev, "Failed to create HCD\n"); return -ENOMEM;
}
/* get the PHY devices if needed */ for (i = 0 ; i < omap->nports ; i++) { struct usb_phy *phy;
/* get the PHY device */
phy = devm_usb_get_phy_by_phandle(dev, "phys", i); if (IS_ERR(phy)) {
ret = PTR_ERR(phy); if (ret == -ENODEV) { /* no PHY */
phy = NULL; continue;
}
if (ret != -EPROBE_DEFER)
dev_err(dev, "Can't get PHY for port %d: %d\n",
i, ret); goto err_phy;
}
omap->phy[i] = phy;
if (pdata->port_mode[i] == OMAP_EHCI_PORT_MODE_PHY) {
usb_phy_init(omap->phy[i]); /* bring PHY out of suspend */
usb_phy_set_suspend(omap->phy[i], 0);
}
}
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
/* * An undocumented "feature" in the OMAP3 EHCI controller, * causes suspended ports to be taken out of suspend when * the USBCMD.Run/Stop bit is cleared (for example when * we do ehci_bus_suspend). * This breaks suspend-resume if the root-hub is allowed * to suspend. Writing 1 to this undocumented register bit * disables this feature and restores normal behavior.
*/
ehci_write(regs, EHCI_INSNREG04,
EHCI_INSNREG04_DISABLE_UNSUSPEND);
ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret) {
dev_err(dev, "failed to add hcd with err %d\n", ret); goto err_pm_runtime;
}
device_wakeup_enable(hcd->self.controller);
/* * Bring PHYs out of reset for non PHY modes. * Even though HSIC mode is a PHY-less mode, the reset * line exists between the chips and can be modelled * as a PHY device for reset control.
*/ for (i = 0; i < omap->nports; i++) { if (!omap->phy[i] ||
pdata->port_mode[i] == OMAP_EHCI_PORT_MODE_PHY) continue;
usb_phy_init(omap->phy[i]); /* bring PHY out of suspend */
usb_phy_set_suspend(omap->phy[i], 0);
}
err_phy: for (i = 0; i < omap->nports; i++) { if (omap->phy[i])
usb_phy_shutdown(omap->phy[i]);
}
usb_put_hcd(hcd);
return ret;
}
/** * ehci_hcd_omap_remove - shutdown processing for EHCI HCDs * @pdev: USB Host Controller being removed * * Reverses the effect of usb_ehci_hcd_omap_probe(), first invoking * the HCD's stop() method. It is always called from a thread * context, normally "rmmod", "apmd", or something similar.
*/ staticvoid ehci_hcd_omap_remove(struct platform_device *pdev)
{ struct device *dev = &pdev->dev; struct usb_hcd *hcd = dev_get_drvdata(dev); struct omap_hcd *omap = (struct omap_hcd *)hcd_to_ehci(hcd)->priv; int i;
usb_remove_hcd(hcd);
for (i = 0; i < omap->nports; i++) { if (omap->phy[i])
usb_phy_shutdown(omap->phy[i]);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.