|
@@ -27,8 +27,9 @@
|
|
|
#include <linux/spinlock.h>
|
|
|
#include <linux/gpio.h>
|
|
|
#include <plat/usb.h>
|
|
|
+#include <linux/pm_runtime.h>
|
|
|
|
|
|
-#define USBHS_DRIVER_NAME "usbhs-omap"
|
|
|
+#define USBHS_DRIVER_NAME "usbhs_omap"
|
|
|
#define OMAP_EHCI_DEVICE "ehci-omap"
|
|
|
#define OMAP_OHCI_DEVICE "ohci-omap3"
|
|
|
|
|
@@ -147,9 +148,6 @@
|
|
|
|
|
|
|
|
|
struct usbhs_hcd_omap {
|
|
|
- struct clk *usbhost_ick;
|
|
|
- struct clk *usbhost_hs_fck;
|
|
|
- struct clk *usbhost_fs_fck;
|
|
|
struct clk *xclk60mhsp1_ck;
|
|
|
struct clk *xclk60mhsp2_ck;
|
|
|
struct clk *utmi_p1_fck;
|
|
@@ -159,8 +157,7 @@ struct usbhs_hcd_omap {
|
|
|
struct clk *usbhost_p2_fck;
|
|
|
struct clk *usbtll_p2_fck;
|
|
|
struct clk *init_60m_fclk;
|
|
|
- struct clk *usbtll_fck;
|
|
|
- struct clk *usbtll_ick;
|
|
|
+ struct clk *ehci_logic_fck;
|
|
|
|
|
|
void __iomem *uhh_base;
|
|
|
void __iomem *tll_base;
|
|
@@ -169,7 +166,6 @@ struct usbhs_hcd_omap {
|
|
|
|
|
|
u32 usbhs_rev;
|
|
|
spinlock_t lock;
|
|
|
- int count;
|
|
|
};
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
@@ -319,269 +315,6 @@ err_end:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * usbhs_omap_probe - initialize TI-based HCDs
|
|
|
- *
|
|
|
- * Allocates basic resources for this USB host controller.
|
|
|
- */
|
|
|
-static int __devinit usbhs_omap_probe(struct platform_device *pdev)
|
|
|
-{
|
|
|
- struct device *dev = &pdev->dev;
|
|
|
- struct usbhs_omap_platform_data *pdata = dev->platform_data;
|
|
|
- struct usbhs_hcd_omap *omap;
|
|
|
- struct resource *res;
|
|
|
- int ret = 0;
|
|
|
- int i;
|
|
|
-
|
|
|
- if (!pdata) {
|
|
|
- dev_err(dev, "Missing platform data\n");
|
|
|
- ret = -ENOMEM;
|
|
|
- goto end_probe;
|
|
|
- }
|
|
|
-
|
|
|
- omap = kzalloc(sizeof(*omap), GFP_KERNEL);
|
|
|
- if (!omap) {
|
|
|
- dev_err(dev, "Memory allocation failed\n");
|
|
|
- ret = -ENOMEM;
|
|
|
- goto end_probe;
|
|
|
- }
|
|
|
-
|
|
|
- spin_lock_init(&omap->lock);
|
|
|
-
|
|
|
- for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
|
|
|
- omap->platdata.port_mode[i] = pdata->port_mode[i];
|
|
|
-
|
|
|
- omap->platdata.ehci_data = pdata->ehci_data;
|
|
|
- omap->platdata.ohci_data = pdata->ohci_data;
|
|
|
-
|
|
|
- omap->usbhost_ick = clk_get(dev, "usbhost_ick");
|
|
|
- if (IS_ERR(omap->usbhost_ick)) {
|
|
|
- ret = PTR_ERR(omap->usbhost_ick);
|
|
|
- dev_err(dev, "usbhost_ick failed error:%d\n", ret);
|
|
|
- goto err_end;
|
|
|
- }
|
|
|
-
|
|
|
- omap->usbhost_hs_fck = clk_get(dev, "hs_fck");
|
|
|
- if (IS_ERR(omap->usbhost_hs_fck)) {
|
|
|
- ret = PTR_ERR(omap->usbhost_hs_fck);
|
|
|
- dev_err(dev, "usbhost_hs_fck failed error:%d\n", ret);
|
|
|
- goto err_usbhost_ick;
|
|
|
- }
|
|
|
-
|
|
|
- omap->usbhost_fs_fck = clk_get(dev, "fs_fck");
|
|
|
- if (IS_ERR(omap->usbhost_fs_fck)) {
|
|
|
- ret = PTR_ERR(omap->usbhost_fs_fck);
|
|
|
- dev_err(dev, "usbhost_fs_fck failed error:%d\n", ret);
|
|
|
- goto err_usbhost_hs_fck;
|
|
|
- }
|
|
|
-
|
|
|
- omap->usbtll_fck = clk_get(dev, "usbtll_fck");
|
|
|
- if (IS_ERR(omap->usbtll_fck)) {
|
|
|
- ret = PTR_ERR(omap->usbtll_fck);
|
|
|
- dev_err(dev, "usbtll_fck failed error:%d\n", ret);
|
|
|
- goto err_usbhost_fs_fck;
|
|
|
- }
|
|
|
-
|
|
|
- omap->usbtll_ick = clk_get(dev, "usbtll_ick");
|
|
|
- if (IS_ERR(omap->usbtll_ick)) {
|
|
|
- ret = PTR_ERR(omap->usbtll_ick);
|
|
|
- dev_err(dev, "usbtll_ick failed error:%d\n", ret);
|
|
|
- goto err_usbtll_fck;
|
|
|
- }
|
|
|
-
|
|
|
- omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
|
|
|
- if (IS_ERR(omap->utmi_p1_fck)) {
|
|
|
- ret = PTR_ERR(omap->utmi_p1_fck);
|
|
|
- dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
|
|
|
- goto err_usbtll_ick;
|
|
|
- }
|
|
|
-
|
|
|
- omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
|
|
|
- if (IS_ERR(omap->xclk60mhsp1_ck)) {
|
|
|
- ret = PTR_ERR(omap->xclk60mhsp1_ck);
|
|
|
- dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret);
|
|
|
- goto err_utmi_p1_fck;
|
|
|
- }
|
|
|
-
|
|
|
- omap->utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk");
|
|
|
- if (IS_ERR(omap->utmi_p2_fck)) {
|
|
|
- ret = PTR_ERR(omap->utmi_p2_fck);
|
|
|
- dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
|
|
|
- goto err_xclk60mhsp1_ck;
|
|
|
- }
|
|
|
-
|
|
|
- omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck");
|
|
|
- if (IS_ERR(omap->xclk60mhsp2_ck)) {
|
|
|
- ret = PTR_ERR(omap->xclk60mhsp2_ck);
|
|
|
- dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret);
|
|
|
- goto err_utmi_p2_fck;
|
|
|
- }
|
|
|
-
|
|
|
- omap->usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk");
|
|
|
- if (IS_ERR(omap->usbhost_p1_fck)) {
|
|
|
- ret = PTR_ERR(omap->usbhost_p1_fck);
|
|
|
- dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret);
|
|
|
- goto err_xclk60mhsp2_ck;
|
|
|
- }
|
|
|
-
|
|
|
- omap->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk");
|
|
|
- if (IS_ERR(omap->usbtll_p1_fck)) {
|
|
|
- ret = PTR_ERR(omap->usbtll_p1_fck);
|
|
|
- dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret);
|
|
|
- goto err_usbhost_p1_fck;
|
|
|
- }
|
|
|
-
|
|
|
- omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk");
|
|
|
- if (IS_ERR(omap->usbhost_p2_fck)) {
|
|
|
- ret = PTR_ERR(omap->usbhost_p2_fck);
|
|
|
- dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret);
|
|
|
- goto err_usbtll_p1_fck;
|
|
|
- }
|
|
|
-
|
|
|
- omap->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk");
|
|
|
- if (IS_ERR(omap->usbtll_p2_fck)) {
|
|
|
- ret = PTR_ERR(omap->usbtll_p2_fck);
|
|
|
- dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret);
|
|
|
- goto err_usbhost_p2_fck;
|
|
|
- }
|
|
|
-
|
|
|
- omap->init_60m_fclk = clk_get(dev, "init_60m_fclk");
|
|
|
- if (IS_ERR(omap->init_60m_fclk)) {
|
|
|
- ret = PTR_ERR(omap->init_60m_fclk);
|
|
|
- dev_err(dev, "init_60m_fclk failed error:%d\n", ret);
|
|
|
- goto err_usbtll_p2_fck;
|
|
|
- }
|
|
|
-
|
|
|
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh");
|
|
|
- if (!res) {
|
|
|
- dev_err(dev, "UHH EHCI get resource failed\n");
|
|
|
- ret = -ENODEV;
|
|
|
- goto err_init_60m_fclk;
|
|
|
- }
|
|
|
-
|
|
|
- omap->uhh_base = ioremap(res->start, resource_size(res));
|
|
|
- if (!omap->uhh_base) {
|
|
|
- dev_err(dev, "UHH ioremap failed\n");
|
|
|
- ret = -ENOMEM;
|
|
|
- goto err_init_60m_fclk;
|
|
|
- }
|
|
|
-
|
|
|
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tll");
|
|
|
- if (!res) {
|
|
|
- dev_err(dev, "UHH EHCI get resource failed\n");
|
|
|
- ret = -ENODEV;
|
|
|
- goto err_tll;
|
|
|
- }
|
|
|
-
|
|
|
- omap->tll_base = ioremap(res->start, resource_size(res));
|
|
|
- if (!omap->tll_base) {
|
|
|
- dev_err(dev, "TLL ioremap failed\n");
|
|
|
- ret = -ENOMEM;
|
|
|
- goto err_tll;
|
|
|
- }
|
|
|
-
|
|
|
- platform_set_drvdata(pdev, omap);
|
|
|
-
|
|
|
- ret = omap_usbhs_alloc_children(pdev);
|
|
|
- if (ret) {
|
|
|
- dev_err(dev, "omap_usbhs_alloc_children failed\n");
|
|
|
- goto err_alloc;
|
|
|
- }
|
|
|
-
|
|
|
- goto end_probe;
|
|
|
-
|
|
|
-err_alloc:
|
|
|
- iounmap(omap->tll_base);
|
|
|
-
|
|
|
-err_tll:
|
|
|
- iounmap(omap->uhh_base);
|
|
|
-
|
|
|
-err_init_60m_fclk:
|
|
|
- clk_put(omap->init_60m_fclk);
|
|
|
-
|
|
|
-err_usbtll_p2_fck:
|
|
|
- clk_put(omap->usbtll_p2_fck);
|
|
|
-
|
|
|
-err_usbhost_p2_fck:
|
|
|
- clk_put(omap->usbhost_p2_fck);
|
|
|
-
|
|
|
-err_usbtll_p1_fck:
|
|
|
- clk_put(omap->usbtll_p1_fck);
|
|
|
-
|
|
|
-err_usbhost_p1_fck:
|
|
|
- clk_put(omap->usbhost_p1_fck);
|
|
|
-
|
|
|
-err_xclk60mhsp2_ck:
|
|
|
- clk_put(omap->xclk60mhsp2_ck);
|
|
|
-
|
|
|
-err_utmi_p2_fck:
|
|
|
- clk_put(omap->utmi_p2_fck);
|
|
|
-
|
|
|
-err_xclk60mhsp1_ck:
|
|
|
- clk_put(omap->xclk60mhsp1_ck);
|
|
|
-
|
|
|
-err_utmi_p1_fck:
|
|
|
- clk_put(omap->utmi_p1_fck);
|
|
|
-
|
|
|
-err_usbtll_ick:
|
|
|
- clk_put(omap->usbtll_ick);
|
|
|
-
|
|
|
-err_usbtll_fck:
|
|
|
- clk_put(omap->usbtll_fck);
|
|
|
-
|
|
|
-err_usbhost_fs_fck:
|
|
|
- clk_put(omap->usbhost_fs_fck);
|
|
|
-
|
|
|
-err_usbhost_hs_fck:
|
|
|
- clk_put(omap->usbhost_hs_fck);
|
|
|
-
|
|
|
-err_usbhost_ick:
|
|
|
- clk_put(omap->usbhost_ick);
|
|
|
-
|
|
|
-err_end:
|
|
|
- kfree(omap);
|
|
|
-
|
|
|
-end_probe:
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs
|
|
|
- * @pdev: USB Host Controller being removed
|
|
|
- *
|
|
|
- * Reverses the effect of usbhs_omap_probe().
|
|
|
- */
|
|
|
-static int __devexit usbhs_omap_remove(struct platform_device *pdev)
|
|
|
-{
|
|
|
- struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev);
|
|
|
-
|
|
|
- if (omap->count != 0) {
|
|
|
- dev_err(&pdev->dev,
|
|
|
- "Either EHCI or OHCI is still using usbhs core\n");
|
|
|
- return -EBUSY;
|
|
|
- }
|
|
|
-
|
|
|
- iounmap(omap->tll_base);
|
|
|
- iounmap(omap->uhh_base);
|
|
|
- clk_put(omap->init_60m_fclk);
|
|
|
- clk_put(omap->usbtll_p2_fck);
|
|
|
- clk_put(omap->usbhost_p2_fck);
|
|
|
- clk_put(omap->usbtll_p1_fck);
|
|
|
- clk_put(omap->usbhost_p1_fck);
|
|
|
- clk_put(omap->xclk60mhsp2_ck);
|
|
|
- clk_put(omap->utmi_p2_fck);
|
|
|
- clk_put(omap->xclk60mhsp1_ck);
|
|
|
- clk_put(omap->utmi_p1_fck);
|
|
|
- clk_put(omap->usbtll_ick);
|
|
|
- clk_put(omap->usbtll_fck);
|
|
|
- clk_put(omap->usbhost_fs_fck);
|
|
|
- clk_put(omap->usbhost_hs_fck);
|
|
|
- clk_put(omap->usbhost_ick);
|
|
|
- kfree(omap);
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
static bool is_ohci_port(enum usbhs_omap_port_mode pmode)
|
|
|
{
|
|
|
switch (pmode) {
|
|
@@ -689,30 +422,85 @@ static void usbhs_omap_tll_init(struct device *dev, u8 tll_channel_count)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static int usbhs_enable(struct device *dev)
|
|
|
+static int usbhs_runtime_resume(struct device *dev)
|
|
|
{
|
|
|
struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
|
|
|
struct usbhs_omap_platform_data *pdata = &omap->platdata;
|
|
|
- unsigned long flags = 0;
|
|
|
- int ret = 0;
|
|
|
- unsigned long timeout;
|
|
|
- unsigned reg;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ dev_dbg(dev, "usbhs_runtime_resume\n");
|
|
|
|
|
|
- dev_dbg(dev, "starting TI HSUSB Controller\n");
|
|
|
if (!pdata) {
|
|
|
dev_dbg(dev, "missing platform_data\n");
|
|
|
return -ENODEV;
|
|
|
}
|
|
|
|
|
|
spin_lock_irqsave(&omap->lock, flags);
|
|
|
- if (omap->count > 0)
|
|
|
- goto end_count;
|
|
|
|
|
|
- clk_enable(omap->usbhost_ick);
|
|
|
- clk_enable(omap->usbhost_hs_fck);
|
|
|
- clk_enable(omap->usbhost_fs_fck);
|
|
|
- clk_enable(omap->usbtll_fck);
|
|
|
- clk_enable(omap->usbtll_ick);
|
|
|
+ if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck))
|
|
|
+ clk_enable(omap->ehci_logic_fck);
|
|
|
+
|
|
|
+ if (is_ehci_tll_mode(pdata->port_mode[0])) {
|
|
|
+ clk_enable(omap->usbhost_p1_fck);
|
|
|
+ clk_enable(omap->usbtll_p1_fck);
|
|
|
+ }
|
|
|
+ if (is_ehci_tll_mode(pdata->port_mode[1])) {
|
|
|
+ clk_enable(omap->usbhost_p2_fck);
|
|
|
+ clk_enable(omap->usbtll_p2_fck);
|
|
|
+ }
|
|
|
+ clk_enable(omap->utmi_p1_fck);
|
|
|
+ clk_enable(omap->utmi_p2_fck);
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(&omap->lock, flags);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int usbhs_runtime_suspend(struct device *dev)
|
|
|
+{
|
|
|
+ struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
|
|
|
+ struct usbhs_omap_platform_data *pdata = &omap->platdata;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ dev_dbg(dev, "usbhs_runtime_suspend\n");
|
|
|
+
|
|
|
+ if (!pdata) {
|
|
|
+ dev_dbg(dev, "missing platform_data\n");
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
+ spin_lock_irqsave(&omap->lock, flags);
|
|
|
+
|
|
|
+ if (is_ehci_tll_mode(pdata->port_mode[0])) {
|
|
|
+ clk_disable(omap->usbhost_p1_fck);
|
|
|
+ clk_disable(omap->usbtll_p1_fck);
|
|
|
+ }
|
|
|
+ if (is_ehci_tll_mode(pdata->port_mode[1])) {
|
|
|
+ clk_disable(omap->usbhost_p2_fck);
|
|
|
+ clk_disable(omap->usbtll_p2_fck);
|
|
|
+ }
|
|
|
+ clk_disable(omap->utmi_p2_fck);
|
|
|
+ clk_disable(omap->utmi_p1_fck);
|
|
|
+
|
|
|
+ if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck))
|
|
|
+ clk_disable(omap->ehci_logic_fck);
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(&omap->lock, flags);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void omap_usbhs_init(struct device *dev)
|
|
|
+{
|
|
|
+ struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
|
|
|
+ struct usbhs_omap_platform_data *pdata = &omap->platdata;
|
|
|
+ unsigned long flags;
|
|
|
+ unsigned reg;
|
|
|
+
|
|
|
+ dev_dbg(dev, "starting TI HSUSB Controller\n");
|
|
|
+
|
|
|
+ pm_runtime_get_sync(dev);
|
|
|
+ spin_lock_irqsave(&omap->lock, flags);
|
|
|
|
|
|
if (pdata->ehci_data->phy_reset) {
|
|
|
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) {
|
|
@@ -736,50 +524,6 @@ static int usbhs_enable(struct device *dev)
|
|
|
omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
|
|
|
dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev);
|
|
|
|
|
|
- /* perform TLL soft reset, and wait until reset is complete */
|
|
|
- usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
|
|
|
- OMAP_USBTLL_SYSCONFIG_SOFTRESET);
|
|
|
-
|
|
|
- /* Wait for TLL reset to complete */
|
|
|
- timeout = jiffies + msecs_to_jiffies(1000);
|
|
|
- while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
|
|
|
- & OMAP_USBTLL_SYSSTATUS_RESETDONE)) {
|
|
|
- cpu_relax();
|
|
|
-
|
|
|
- if (time_after(jiffies, timeout)) {
|
|
|
- dev_dbg(dev, "operation timed out\n");
|
|
|
- ret = -EINVAL;
|
|
|
- goto err_tll;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- dev_dbg(dev, "TLL RESET DONE\n");
|
|
|
-
|
|
|
- /* (1<<3) = no idle mode only for initial debugging */
|
|
|
- usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
|
|
|
- OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
|
|
|
- OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
|
|
|
- OMAP_USBTLL_SYSCONFIG_AUTOIDLE);
|
|
|
-
|
|
|
- /* Put UHH in NoIdle/NoStandby mode */
|
|
|
- reg = usbhs_read(omap->uhh_base, OMAP_UHH_SYSCONFIG);
|
|
|
- if (is_omap_usbhs_rev1(omap)) {
|
|
|
- reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP
|
|
|
- | OMAP_UHH_SYSCONFIG_SIDLEMODE
|
|
|
- | OMAP_UHH_SYSCONFIG_CACTIVITY
|
|
|
- | OMAP_UHH_SYSCONFIG_MIDLEMODE);
|
|
|
- reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE;
|
|
|
-
|
|
|
-
|
|
|
- } else if (is_omap_usbhs_rev2(omap)) {
|
|
|
- reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR;
|
|
|
- reg |= OMAP4_UHH_SYSCONFIG_NOIDLE;
|
|
|
- reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR;
|
|
|
- reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY;
|
|
|
- }
|
|
|
-
|
|
|
- usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);
|
|
|
-
|
|
|
reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
|
|
|
/* setup ULPI bypass and burst configurations */
|
|
|
reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
|
|
@@ -825,49 +569,6 @@ static int usbhs_enable(struct device *dev)
|
|
|
reg &= ~OMAP4_P1_MODE_CLEAR;
|
|
|
reg &= ~OMAP4_P2_MODE_CLEAR;
|
|
|
|
|
|
- if (is_ehci_phy_mode(pdata->port_mode[0])) {
|
|
|
- ret = clk_set_parent(omap->utmi_p1_fck,
|
|
|
- omap->xclk60mhsp1_ck);
|
|
|
- if (ret != 0) {
|
|
|
- dev_err(dev, "xclk60mhsp1_ck set parent"
|
|
|
- "failed error:%d\n", ret);
|
|
|
- goto err_tll;
|
|
|
- }
|
|
|
- } else if (is_ehci_tll_mode(pdata->port_mode[0])) {
|
|
|
- ret = clk_set_parent(omap->utmi_p1_fck,
|
|
|
- omap->init_60m_fclk);
|
|
|
- if (ret != 0) {
|
|
|
- dev_err(dev, "init_60m_fclk set parent"
|
|
|
- "failed error:%d\n", ret);
|
|
|
- goto err_tll;
|
|
|
- }
|
|
|
- clk_enable(omap->usbhost_p1_fck);
|
|
|
- clk_enable(omap->usbtll_p1_fck);
|
|
|
- }
|
|
|
-
|
|
|
- if (is_ehci_phy_mode(pdata->port_mode[1])) {
|
|
|
- ret = clk_set_parent(omap->utmi_p2_fck,
|
|
|
- omap->xclk60mhsp2_ck);
|
|
|
- if (ret != 0) {
|
|
|
- dev_err(dev, "xclk60mhsp1_ck set parent"
|
|
|
- "failed error:%d\n", ret);
|
|
|
- goto err_tll;
|
|
|
- }
|
|
|
- } else if (is_ehci_tll_mode(pdata->port_mode[1])) {
|
|
|
- ret = clk_set_parent(omap->utmi_p2_fck,
|
|
|
- omap->init_60m_fclk);
|
|
|
- if (ret != 0) {
|
|
|
- dev_err(dev, "init_60m_fclk set parent"
|
|
|
- "failed error:%d\n", ret);
|
|
|
- goto err_tll;
|
|
|
- }
|
|
|
- clk_enable(omap->usbhost_p2_fck);
|
|
|
- clk_enable(omap->usbtll_p2_fck);
|
|
|
- }
|
|
|
-
|
|
|
- clk_enable(omap->utmi_p1_fck);
|
|
|
- clk_enable(omap->utmi_p2_fck);
|
|
|
-
|
|
|
if (is_ehci_tll_mode(pdata->port_mode[0]) ||
|
|
|
(is_ohci_port(pdata->port_mode[0])))
|
|
|
reg |= OMAP4_P1_MODE_TLL;
|
|
@@ -913,12 +614,15 @@ static int usbhs_enable(struct device *dev)
|
|
|
(pdata->ehci_data->reset_gpio_port[1], 1);
|
|
|
}
|
|
|
|
|
|
-end_count:
|
|
|
- omap->count++;
|
|
|
spin_unlock_irqrestore(&omap->lock, flags);
|
|
|
- return 0;
|
|
|
+ pm_runtime_put_sync(dev);
|
|
|
+}
|
|
|
+
|
|
|
+static void omap_usbhs_deinit(struct device *dev)
|
|
|
+{
|
|
|
+ struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
|
|
|
+ struct usbhs_omap_platform_data *pdata = &omap->platdata;
|
|
|
|
|
|
-err_tll:
|
|
|
if (pdata->ehci_data->phy_reset) {
|
|
|
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
|
|
|
gpio_free(pdata->ehci_data->reset_gpio_port[0]);
|
|
@@ -926,123 +630,272 @@ err_tll:
|
|
|
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
|
|
|
gpio_free(pdata->ehci_data->reset_gpio_port[1]);
|
|
|
}
|
|
|
-
|
|
|
- clk_disable(omap->usbtll_ick);
|
|
|
- clk_disable(omap->usbtll_fck);
|
|
|
- clk_disable(omap->usbhost_fs_fck);
|
|
|
- clk_disable(omap->usbhost_hs_fck);
|
|
|
- clk_disable(omap->usbhost_ick);
|
|
|
- spin_unlock_irqrestore(&omap->lock, flags);
|
|
|
- return ret;
|
|
|
}
|
|
|
|
|
|
-static void usbhs_disable(struct device *dev)
|
|
|
+
|
|
|
+/**
|
|
|
+ * usbhs_omap_probe - initialize TI-based HCDs
|
|
|
+ *
|
|
|
+ * Allocates basic resources for this USB host controller.
|
|
|
+ */
|
|
|
+static int __devinit usbhs_omap_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
- struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
|
|
|
- struct usbhs_omap_platform_data *pdata = &omap->platdata;
|
|
|
- unsigned long flags = 0;
|
|
|
- unsigned long timeout;
|
|
|
+ struct device *dev = &pdev->dev;
|
|
|
+ struct usbhs_omap_platform_data *pdata = dev->platform_data;
|
|
|
+ struct usbhs_hcd_omap *omap;
|
|
|
+ struct resource *res;
|
|
|
+ int ret = 0;
|
|
|
+ int i;
|
|
|
|
|
|
- dev_dbg(dev, "stopping TI HSUSB Controller\n");
|
|
|
+ if (!pdata) {
|
|
|
+ dev_err(dev, "Missing platform data\n");
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto end_probe;
|
|
|
+ }
|
|
|
|
|
|
- spin_lock_irqsave(&omap->lock, flags);
|
|
|
+ omap = kzalloc(sizeof(*omap), GFP_KERNEL);
|
|
|
+ if (!omap) {
|
|
|
+ dev_err(dev, "Memory allocation failed\n");
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto end_probe;
|
|
|
+ }
|
|
|
|
|
|
- if (omap->count == 0)
|
|
|
- goto end_disble;
|
|
|
+ spin_lock_init(&omap->lock);
|
|
|
|
|
|
- omap->count--;
|
|
|
+ for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
|
|
|
+ omap->platdata.port_mode[i] = pdata->port_mode[i];
|
|
|
+
|
|
|
+ omap->platdata.ehci_data = pdata->ehci_data;
|
|
|
+ omap->platdata.ohci_data = pdata->ohci_data;
|
|
|
|
|
|
- if (omap->count != 0)
|
|
|
- goto end_disble;
|
|
|
+ pm_runtime_enable(dev);
|
|
|
|
|
|
- /* Reset OMAP modules for insmod/rmmod to work */
|
|
|
- usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG,
|
|
|
- is_omap_usbhs_rev2(omap) ?
|
|
|
- OMAP4_UHH_SYSCONFIG_SOFTRESET :
|
|
|
- OMAP_UHH_SYSCONFIG_SOFTRESET);
|
|
|
|
|
|
- timeout = jiffies + msecs_to_jiffies(100);
|
|
|
- while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS)
|
|
|
- & (1 << 0))) {
|
|
|
- cpu_relax();
|
|
|
+ for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
|
|
|
+ if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) ||
|
|
|
+ is_ehci_hsic_mode(i)) {
|
|
|
+ omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck");
|
|
|
+ if (IS_ERR(omap->ehci_logic_fck)) {
|
|
|
+ ret = PTR_ERR(omap->ehci_logic_fck);
|
|
|
+ dev_warn(dev, "ehci_logic_fck failed:%d\n",
|
|
|
+ ret);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
- if (time_after(jiffies, timeout))
|
|
|
- dev_dbg(dev, "operation timed out\n");
|
|
|
+ omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
|
|
|
+ if (IS_ERR(omap->utmi_p1_fck)) {
|
|
|
+ ret = PTR_ERR(omap->utmi_p1_fck);
|
|
|
+ dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
|
|
|
+ goto err_end;
|
|
|
}
|
|
|
|
|
|
- while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS)
|
|
|
- & (1 << 1))) {
|
|
|
- cpu_relax();
|
|
|
+ omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
|
|
|
+ if (IS_ERR(omap->xclk60mhsp1_ck)) {
|
|
|
+ ret = PTR_ERR(omap->xclk60mhsp1_ck);
|
|
|
+ dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret);
|
|
|
+ goto err_utmi_p1_fck;
|
|
|
+ }
|
|
|
|
|
|
- if (time_after(jiffies, timeout))
|
|
|
- dev_dbg(dev, "operation timed out\n");
|
|
|
+ omap->utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk");
|
|
|
+ if (IS_ERR(omap->utmi_p2_fck)) {
|
|
|
+ ret = PTR_ERR(omap->utmi_p2_fck);
|
|
|
+ dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
|
|
|
+ goto err_xclk60mhsp1_ck;
|
|
|
}
|
|
|
|
|
|
- while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS)
|
|
|
- & (1 << 2))) {
|
|
|
- cpu_relax();
|
|
|
+ omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck");
|
|
|
+ if (IS_ERR(omap->xclk60mhsp2_ck)) {
|
|
|
+ ret = PTR_ERR(omap->xclk60mhsp2_ck);
|
|
|
+ dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret);
|
|
|
+ goto err_utmi_p2_fck;
|
|
|
+ }
|
|
|
|
|
|
- if (time_after(jiffies, timeout))
|
|
|
- dev_dbg(dev, "operation timed out\n");
|
|
|
+ omap->usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk");
|
|
|
+ if (IS_ERR(omap->usbhost_p1_fck)) {
|
|
|
+ ret = PTR_ERR(omap->usbhost_p1_fck);
|
|
|
+ dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret);
|
|
|
+ goto err_xclk60mhsp2_ck;
|
|
|
}
|
|
|
|
|
|
- usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, (1 << 1));
|
|
|
+ omap->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk");
|
|
|
+ if (IS_ERR(omap->usbtll_p1_fck)) {
|
|
|
+ ret = PTR_ERR(omap->usbtll_p1_fck);
|
|
|
+ dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret);
|
|
|
+ goto err_usbhost_p1_fck;
|
|
|
+ }
|
|
|
|
|
|
- while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
|
|
|
- & (1 << 0))) {
|
|
|
- cpu_relax();
|
|
|
+ omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk");
|
|
|
+ if (IS_ERR(omap->usbhost_p2_fck)) {
|
|
|
+ ret = PTR_ERR(omap->usbhost_p2_fck);
|
|
|
+ dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret);
|
|
|
+ goto err_usbtll_p1_fck;
|
|
|
+ }
|
|
|
|
|
|
- if (time_after(jiffies, timeout))
|
|
|
- dev_dbg(dev, "operation timed out\n");
|
|
|
+ omap->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk");
|
|
|
+ if (IS_ERR(omap->usbtll_p2_fck)) {
|
|
|
+ ret = PTR_ERR(omap->usbtll_p2_fck);
|
|
|
+ dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret);
|
|
|
+ goto err_usbhost_p2_fck;
|
|
|
}
|
|
|
|
|
|
- if (is_omap_usbhs_rev2(omap)) {
|
|
|
- if (is_ehci_tll_mode(pdata->port_mode[0]))
|
|
|
- clk_disable(omap->usbtll_p1_fck);
|
|
|
- if (is_ehci_tll_mode(pdata->port_mode[1]))
|
|
|
- clk_disable(omap->usbtll_p2_fck);
|
|
|
- clk_disable(omap->utmi_p2_fck);
|
|
|
- clk_disable(omap->utmi_p1_fck);
|
|
|
+ omap->init_60m_fclk = clk_get(dev, "init_60m_fclk");
|
|
|
+ if (IS_ERR(omap->init_60m_fclk)) {
|
|
|
+ ret = PTR_ERR(omap->init_60m_fclk);
|
|
|
+ dev_err(dev, "init_60m_fclk failed error:%d\n", ret);
|
|
|
+ goto err_usbtll_p2_fck;
|
|
|
}
|
|
|
|
|
|
- clk_disable(omap->usbtll_ick);
|
|
|
- clk_disable(omap->usbtll_fck);
|
|
|
- clk_disable(omap->usbhost_fs_fck);
|
|
|
- clk_disable(omap->usbhost_hs_fck);
|
|
|
- clk_disable(omap->usbhost_ick);
|
|
|
+ if (is_ehci_phy_mode(pdata->port_mode[0])) {
|
|
|
+ /* for OMAP3 , the clk set paretn fails */
|
|
|
+ ret = clk_set_parent(omap->utmi_p1_fck,
|
|
|
+ omap->xclk60mhsp1_ck);
|
|
|
+ if (ret != 0)
|
|
|
+ dev_err(dev, "xclk60mhsp1_ck set parent"
|
|
|
+ "failed error:%d\n", ret);
|
|
|
+ } else if (is_ehci_tll_mode(pdata->port_mode[0])) {
|
|
|
+ ret = clk_set_parent(omap->utmi_p1_fck,
|
|
|
+ omap->init_60m_fclk);
|
|
|
+ if (ret != 0)
|
|
|
+ dev_err(dev, "init_60m_fclk set parent"
|
|
|
+ "failed error:%d\n", ret);
|
|
|
+ }
|
|
|
|
|
|
- /* The gpio_free migh sleep; so unlock the spinlock */
|
|
|
- spin_unlock_irqrestore(&omap->lock, flags);
|
|
|
+ if (is_ehci_phy_mode(pdata->port_mode[1])) {
|
|
|
+ ret = clk_set_parent(omap->utmi_p2_fck,
|
|
|
+ omap->xclk60mhsp2_ck);
|
|
|
+ if (ret != 0)
|
|
|
+ dev_err(dev, "xclk60mhsp2_ck set parent"
|
|
|
+ "failed error:%d\n", ret);
|
|
|
+ } else if (is_ehci_tll_mode(pdata->port_mode[1])) {
|
|
|
+ ret = clk_set_parent(omap->utmi_p2_fck,
|
|
|
+ omap->init_60m_fclk);
|
|
|
+ if (ret != 0)
|
|
|
+ dev_err(dev, "init_60m_fclk set parent"
|
|
|
+ "failed error:%d\n", ret);
|
|
|
+ }
|
|
|
|
|
|
- if (pdata->ehci_data->phy_reset) {
|
|
|
- if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
|
|
|
- gpio_free(pdata->ehci_data->reset_gpio_port[0]);
|
|
|
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh");
|
|
|
+ if (!res) {
|
|
|
+ dev_err(dev, "UHH EHCI get resource failed\n");
|
|
|
+ ret = -ENODEV;
|
|
|
+ goto err_init_60m_fclk;
|
|
|
+ }
|
|
|
|
|
|
- if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
|
|
|
- gpio_free(pdata->ehci_data->reset_gpio_port[1]);
|
|
|
+ omap->uhh_base = ioremap(res->start, resource_size(res));
|
|
|
+ if (!omap->uhh_base) {
|
|
|
+ dev_err(dev, "UHH ioremap failed\n");
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto err_init_60m_fclk;
|
|
|
}
|
|
|
- return;
|
|
|
|
|
|
-end_disble:
|
|
|
- spin_unlock_irqrestore(&omap->lock, flags);
|
|
|
-}
|
|
|
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tll");
|
|
|
+ if (!res) {
|
|
|
+ dev_err(dev, "UHH EHCI get resource failed\n");
|
|
|
+ ret = -ENODEV;
|
|
|
+ goto err_tll;
|
|
|
+ }
|
|
|
|
|
|
-int omap_usbhs_enable(struct device *dev)
|
|
|
-{
|
|
|
- return usbhs_enable(dev->parent);
|
|
|
+ omap->tll_base = ioremap(res->start, resource_size(res));
|
|
|
+ if (!omap->tll_base) {
|
|
|
+ dev_err(dev, "TLL ioremap failed\n");
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto err_tll;
|
|
|
+ }
|
|
|
+
|
|
|
+ platform_set_drvdata(pdev, omap);
|
|
|
+
|
|
|
+ ret = omap_usbhs_alloc_children(pdev);
|
|
|
+ if (ret) {
|
|
|
+ dev_err(dev, "omap_usbhs_alloc_children failed\n");
|
|
|
+ goto err_alloc;
|
|
|
+ }
|
|
|
+
|
|
|
+ omap_usbhs_init(dev);
|
|
|
+
|
|
|
+ goto end_probe;
|
|
|
+
|
|
|
+err_alloc:
|
|
|
+ iounmap(omap->tll_base);
|
|
|
+
|
|
|
+err_tll:
|
|
|
+ iounmap(omap->uhh_base);
|
|
|
+
|
|
|
+err_init_60m_fclk:
|
|
|
+ clk_put(omap->init_60m_fclk);
|
|
|
+
|
|
|
+err_usbtll_p2_fck:
|
|
|
+ clk_put(omap->usbtll_p2_fck);
|
|
|
+
|
|
|
+err_usbhost_p2_fck:
|
|
|
+ clk_put(omap->usbhost_p2_fck);
|
|
|
+
|
|
|
+err_usbtll_p1_fck:
|
|
|
+ clk_put(omap->usbtll_p1_fck);
|
|
|
+
|
|
|
+err_usbhost_p1_fck:
|
|
|
+ clk_put(omap->usbhost_p1_fck);
|
|
|
+
|
|
|
+err_xclk60mhsp2_ck:
|
|
|
+ clk_put(omap->xclk60mhsp2_ck);
|
|
|
+
|
|
|
+err_utmi_p2_fck:
|
|
|
+ clk_put(omap->utmi_p2_fck);
|
|
|
+
|
|
|
+err_xclk60mhsp1_ck:
|
|
|
+ clk_put(omap->xclk60mhsp1_ck);
|
|
|
+
|
|
|
+err_utmi_p1_fck:
|
|
|
+ clk_put(omap->utmi_p1_fck);
|
|
|
+
|
|
|
+err_end:
|
|
|
+ clk_put(omap->ehci_logic_fck);
|
|
|
+ pm_runtime_disable(dev);
|
|
|
+ kfree(omap);
|
|
|
+
|
|
|
+end_probe:
|
|
|
+ return ret;
|
|
|
}
|
|
|
-EXPORT_SYMBOL_GPL(omap_usbhs_enable);
|
|
|
|
|
|
-void omap_usbhs_disable(struct device *dev)
|
|
|
+/**
|
|
|
+ * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs
|
|
|
+ * @pdev: USB Host Controller being removed
|
|
|
+ *
|
|
|
+ * Reverses the effect of usbhs_omap_probe().
|
|
|
+ */
|
|
|
+static int __devexit usbhs_omap_remove(struct platform_device *pdev)
|
|
|
{
|
|
|
- usbhs_disable(dev->parent);
|
|
|
+ struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev);
|
|
|
+
|
|
|
+ omap_usbhs_deinit(&pdev->dev);
|
|
|
+ iounmap(omap->tll_base);
|
|
|
+ iounmap(omap->uhh_base);
|
|
|
+ clk_put(omap->init_60m_fclk);
|
|
|
+ clk_put(omap->usbtll_p2_fck);
|
|
|
+ clk_put(omap->usbhost_p2_fck);
|
|
|
+ clk_put(omap->usbtll_p1_fck);
|
|
|
+ clk_put(omap->usbhost_p1_fck);
|
|
|
+ clk_put(omap->xclk60mhsp2_ck);
|
|
|
+ clk_put(omap->utmi_p2_fck);
|
|
|
+ clk_put(omap->xclk60mhsp1_ck);
|
|
|
+ clk_put(omap->utmi_p1_fck);
|
|
|
+ clk_put(omap->ehci_logic_fck);
|
|
|
+ pm_runtime_disable(&pdev->dev);
|
|
|
+ kfree(omap);
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
-EXPORT_SYMBOL_GPL(omap_usbhs_disable);
|
|
|
+
|
|
|
+static const struct dev_pm_ops usbhsomap_dev_pm_ops = {
|
|
|
+ .runtime_suspend = usbhs_runtime_suspend,
|
|
|
+ .runtime_resume = usbhs_runtime_resume,
|
|
|
+};
|
|
|
|
|
|
static struct platform_driver usbhs_omap_driver = {
|
|
|
.driver = {
|
|
|
.name = (char *)usbhs_driver_name,
|
|
|
.owner = THIS_MODULE,
|
|
|
+ .pm = &usbhsomap_dev_pm_ops,
|
|
|
},
|
|
|
.remove = __exit_p(usbhs_omap_remove),
|
|
|
};
|