^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * ehci-omap.c - driver for USBHOST on OMAP3/4 processors
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Bus Glue for the EHCI controllers in OMAP3/4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Tested on several OMAP3 boards, and OMAP4 Pandaboard
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Copyright (C) 2007-2013 Texas Instruments, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Author: Vikram Pandita <vikram.pandita@ti.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Author: Anand Gadiyar <gadiyar@ti.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Author: Keshava Munegowda <keshava_mgowda@ti.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * Author: Roger Quadros <rogerq@ti.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Copyright (C) 2009 Nokia Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * Contact: Felipe Balbi <felipe.balbi@nokia.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * Based on "ehci-fsl.c" and "ehci-au1xxx.c" ehci glue layers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/usb/ulpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/pm_runtime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/usb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/usb/hcd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/dma-mapping.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include "ehci.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/platform_data/usb-omap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /* EHCI Register Set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define EHCI_INSNREG04 (0xA0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define EHCI_INSNREG04_DISABLE_UNSUSPEND (1 << 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define EHCI_INSNREG05_ULPI (0xA4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define EHCI_INSNREG05_ULPI_CONTROL_SHIFT 31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define EHCI_INSNREG05_ULPI_PORTSEL_SHIFT 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define EHCI_INSNREG05_ULPI_OPSEL_SHIFT 22
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define EHCI_INSNREG05_ULPI_REGADD_SHIFT 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define EHCI_INSNREG05_ULPI_WRDATA_SHIFT 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define DRIVER_DESC "OMAP-EHCI Host Controller driver"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) static const char hcd_name[] = "ehci-omap";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) /*-------------------------------------------------------------------------*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct omap_hcd {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct usb_phy *phy[OMAP3_HS_USB_PORTS]; /* one PHY for each port */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) int nports;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static inline void ehci_write(void __iomem *base, u32 reg, u32 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) __raw_writel(val, base + reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static inline u32 ehci_read(void __iomem *base, u32 reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return __raw_readl(base + reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /* configure so an HC device and id are always provided */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) /* always called with process context; sleeping is OK */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static struct hc_driver __read_mostly ehci_omap_hc_driver;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static const struct ehci_driver_overrides ehci_omap_overrides __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) .extra_priv_size = sizeof(struct omap_hcd),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * ehci_hcd_omap_probe - initialize TI-based HCDs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * @pdev: Pointer to this platform device's information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * Allocates basic resources for this USB host controller, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * then invokes the start() method for the HCD associated with it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * through the hotplug entry's driver_data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) static int ehci_hcd_omap_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) struct usbhs_omap_platform_data *pdata = dev_get_platdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct usb_hcd *hcd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) void __iomem *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) struct omap_hcd *omap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (usb_disabled())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) if (!dev->parent) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) dev_err(dev, "Missing parent device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) /* For DT boot, get platform data from parent. i.e. usbhshost */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (dev->of_node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) pdata = dev_get_platdata(dev->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) dev->platform_data = pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (!pdata) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) dev_err(dev, "Missing platform data\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) irq = platform_get_irq(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (irq < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) regs = devm_ioremap_resource(dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (IS_ERR(regs))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) return PTR_ERR(regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * Right now device-tree probed devices don't get dma_mask set.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * Since shared usb code relies on it, set it here for now.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * Once we have dma capability bindings this can go away.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) hcd = usb_create_hcd(&ehci_omap_hc_driver, dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) dev_name(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (!hcd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) dev_err(dev, "Failed to create HCD\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) hcd->rsrc_start = res->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) hcd->rsrc_len = resource_size(res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) hcd->regs = regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) hcd_to_ehci(hcd)->caps = regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) omap = (struct omap_hcd *)hcd_to_ehci(hcd)->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) omap->nports = pdata->nports;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) platform_set_drvdata(pdev, hcd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) /* get the PHY devices if needed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) for (i = 0 ; i < omap->nports ; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) struct usb_phy *phy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) /* get the PHY device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) phy = devm_usb_get_phy_by_phandle(dev, "phys", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (IS_ERR(phy)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) ret = PTR_ERR(phy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if (ret == -ENODEV) { /* no PHY */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) phy = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) if (ret != -EPROBE_DEFER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) dev_err(dev, "Can't get PHY for port %d: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) i, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) goto err_phy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) omap->phy[i] = phy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (pdata->port_mode[i] == OMAP_EHCI_PORT_MODE_PHY) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) usb_phy_init(omap->phy[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) /* bring PHY out of suspend */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) usb_phy_set_suspend(omap->phy[i], 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) pm_runtime_enable(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) pm_runtime_get_sync(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * An undocumented "feature" in the OMAP3 EHCI controller,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * causes suspended ports to be taken out of suspend when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) * the USBCMD.Run/Stop bit is cleared (for example when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * we do ehci_bus_suspend).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * This breaks suspend-resume if the root-hub is allowed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * to suspend. Writing 1 to this undocumented register bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) * disables this feature and restores normal behavior.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) ehci_write(regs, EHCI_INSNREG04,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) EHCI_INSNREG04_DISABLE_UNSUSPEND);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) dev_err(dev, "failed to add hcd with err %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) goto err_pm_runtime;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) device_wakeup_enable(hcd->self.controller);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) * Bring PHYs out of reset for non PHY modes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) * Even though HSIC mode is a PHY-less mode, the reset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) * line exists between the chips and can be modelled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) * as a PHY device for reset control.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) for (i = 0; i < omap->nports; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (!omap->phy[i] ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) pdata->port_mode[i] == OMAP_EHCI_PORT_MODE_PHY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) usb_phy_init(omap->phy[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) /* bring PHY out of suspend */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) usb_phy_set_suspend(omap->phy[i], 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) err_pm_runtime:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) pm_runtime_put_sync(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) pm_runtime_disable(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) err_phy:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) for (i = 0; i < omap->nports; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (omap->phy[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) usb_phy_shutdown(omap->phy[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) usb_put_hcd(hcd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) * ehci_hcd_omap_remove - shutdown processing for EHCI HCDs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) * @pdev: USB Host Controller being removed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) * Reverses the effect of usb_ehci_hcd_omap_probe(), first invoking
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) * the HCD's stop() method. It is always called from a thread
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) * context, normally "rmmod", "apmd", or something similar.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) static int ehci_hcd_omap_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) struct usb_hcd *hcd = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) struct omap_hcd *omap = (struct omap_hcd *)hcd_to_ehci(hcd)->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) usb_remove_hcd(hcd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) for (i = 0; i < omap->nports; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) if (omap->phy[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) usb_phy_shutdown(omap->phy[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) usb_put_hcd(hcd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) pm_runtime_put_sync(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) pm_runtime_disable(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) static const struct of_device_id omap_ehci_dt_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) { .compatible = "ti,ehci-omap" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) MODULE_DEVICE_TABLE(of, omap_ehci_dt_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) static struct platform_driver ehci_hcd_omap_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) .probe = ehci_hcd_omap_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) .remove = ehci_hcd_omap_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) .shutdown = usb_hcd_platform_shutdown,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) /*.suspend = ehci_hcd_omap_suspend, */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) /*.resume = ehci_hcd_omap_resume, */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) .name = hcd_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) .of_match_table = omap_ehci_dt_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) /*-------------------------------------------------------------------------*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) static int __init ehci_omap_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) if (usb_disabled())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) pr_info("%s: " DRIVER_DESC "\n", hcd_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) ehci_init_driver(&ehci_omap_hc_driver, &ehci_omap_overrides);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) return platform_driver_register(&ehci_hcd_omap_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) module_init(ehci_omap_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) static void __exit ehci_omap_cleanup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) platform_driver_unregister(&ehci_hcd_omap_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) module_exit(ehci_omap_cleanup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) MODULE_ALIAS("platform:ehci-omap");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) MODULE_AUTHOR("Texas Instruments, Inc.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) MODULE_AUTHOR("Felipe Balbi <felipe.balbi@nokia.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) MODULE_DESCRIPTION(DRIVER_DESC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) MODULE_LICENSE("GPL");