summaryrefslogtreecommitdiff
path: root/drivers/usb/host/ohci-pxa27x.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ohci-pxa27x.c')
-rw-r--r--drivers/usb/host/ohci-pxa27x.c258
1 files changed, 141 insertions, 117 deletions
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 9b7435f..93371a2 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -19,27 +19,15 @@
* This file is licenced under the GPL.
*/
-#include <linux/clk.h>
#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
+#include <mach/hardware.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>
#include <linux/platform_data/usb-pxa3xx-ulpi.h>
-#include <linux/platform_device.h>
-#include <linux/signal.h>
-#include <linux/usb.h>
-#include <linux/usb/hcd.h>
-#include <linux/usb/otg.h>
-
-#include <mach/hardware.h>
-
-#include "ohci.h"
-
-#define DRIVER_DESC "OHCI PXA27x/PXA3x driver"
/*
* UHC: USB Host Controller (OHCI-like) register definitions
@@ -113,16 +101,16 @@
#define PXA_UHC_MAX_PORTNUM 3
-static const char hcd_name[] = "ohci-pxa27x";
-
-static struct hc_driver __read_mostly ohci_pxa27x_hc_driver;
-
struct pxa27x_ohci {
+ /* must be 1st member here for hcd_to_ohci() to work */
+ struct ohci_hcd ohci;
+
+ struct device *dev;
struct clk *clk;
void __iomem *mmio_base;
};
-#define to_pxa27x_ohci(hcd) (struct pxa27x_ohci *)(hcd_to_ohci(hcd)->priv)
+#define to_pxa27x_ohci(hcd) (struct pxa27x_ohci *)hcd_to_ohci(hcd)
/*
PMM_NPS_MODE -- PMM Non-power switching mode
@@ -134,10 +122,10 @@ struct pxa27x_ohci {
PMM_PERPORT_MODE -- PMM per port switching mode
Ports are powered individually.
*/
-static int pxa27x_ohci_select_pmm(struct pxa27x_ohci *pxa_ohci, int mode)
+static int pxa27x_ohci_select_pmm(struct pxa27x_ohci *ohci, int mode)
{
- uint32_t uhcrhda = __raw_readl(pxa_ohci->mmio_base + UHCRHDA);
- uint32_t uhcrhdb = __raw_readl(pxa_ohci->mmio_base + UHCRHDB);
+ uint32_t uhcrhda = __raw_readl(ohci->mmio_base + UHCRHDA);
+ uint32_t uhcrhdb = __raw_readl(ohci->mmio_base + UHCRHDB);
switch (mode) {
case PMM_NPS_MODE:
@@ -161,18 +149,20 @@ static int pxa27x_ohci_select_pmm(struct pxa27x_ohci *pxa_ohci, int mode)
uhcrhda |= RH_A_NPS;
}
- __raw_writel(uhcrhda, pxa_ohci->mmio_base + UHCRHDA);
- __raw_writel(uhcrhdb, pxa_ohci->mmio_base + UHCRHDB);
+ __raw_writel(uhcrhda, ohci->mmio_base + UHCRHDA);
+ __raw_writel(uhcrhdb, ohci->mmio_base + UHCRHDB);
return 0;
}
+extern int usb_disabled(void);
+
/*-------------------------------------------------------------------------*/
-static inline void pxa27x_setup_hc(struct pxa27x_ohci *pxa_ohci,
+static inline void pxa27x_setup_hc(struct pxa27x_ohci *ohci,
struct pxaohci_platform_data *inf)
{
- uint32_t uhchr = __raw_readl(pxa_ohci->mmio_base + UHCHR);
- uint32_t uhcrhda = __raw_readl(pxa_ohci->mmio_base + UHCRHDA);
+ uint32_t uhchr = __raw_readl(ohci->mmio_base + UHCHR);
+ uint32_t uhcrhda = __raw_readl(ohci->mmio_base + UHCRHDA);
if (inf->flags & ENABLE_PORT1)
uhchr &= ~UHCHR_SSEP1;
@@ -204,17 +194,17 @@ static inline void pxa27x_setup_hc(struct pxa27x_ohci *pxa_ohci,
uhcrhda |= UHCRHDA_POTPGT(inf->power_on_delay / 2);
}
- __raw_writel(uhchr, pxa_ohci->mmio_base + UHCHR);
- __raw_writel(uhcrhda, pxa_ohci->mmio_base + UHCRHDA);
+ __raw_writel(uhchr, ohci->mmio_base + UHCHR);
+ __raw_writel(uhcrhda, ohci->mmio_base + UHCRHDA);
}
-static inline void pxa27x_reset_hc(struct pxa27x_ohci *pxa_ohci)
+static inline void pxa27x_reset_hc(struct pxa27x_ohci *ohci)
{
- uint32_t uhchr = __raw_readl(pxa_ohci->mmio_base + UHCHR);
+ uint32_t uhchr = __raw_readl(ohci->mmio_base + UHCHR);
- __raw_writel(uhchr | UHCHR_FHR, pxa_ohci->mmio_base + UHCHR);
+ __raw_writel(uhchr | UHCHR_FHR, ohci->mmio_base + UHCHR);
udelay(11);
- __raw_writel(uhchr & ~UHCHR_FHR, pxa_ohci->mmio_base + UHCHR);
+ __raw_writel(uhchr & ~UHCHR_FHR, ohci->mmio_base + UHCHR);
}
#ifdef CONFIG_PXA27x
@@ -223,26 +213,25 @@ extern void pxa27x_clear_otgph(void);
#define pxa27x_clear_otgph() do {} while (0)
#endif
-static int pxa27x_start_hc(struct pxa27x_ohci *pxa_ohci, struct device *dev)
+static int pxa27x_start_hc(struct pxa27x_ohci *ohci, struct device *dev)
{
int retval = 0;
struct pxaohci_platform_data *inf;
uint32_t uhchr;
- struct usb_hcd *hcd = dev_get_drvdata(dev);
inf = dev_get_platdata(dev);
- clk_prepare_enable(pxa_ohci->clk);
+ clk_prepare_enable(ohci->clk);
- pxa27x_reset_hc(pxa_ohci);
+ pxa27x_reset_hc(ohci);
- uhchr = __raw_readl(pxa_ohci->mmio_base + UHCHR) | UHCHR_FSBIR;
- __raw_writel(uhchr, pxa_ohci->mmio_base + UHCHR);
+ uhchr = __raw_readl(ohci->mmio_base + UHCHR) | UHCHR_FSBIR;
+ __raw_writel(uhchr, ohci->mmio_base + UHCHR);
- while (__raw_readl(pxa_ohci->mmio_base + UHCHR) & UHCHR_FSBIR)
+ while (__raw_readl(ohci->mmio_base + UHCHR) & UHCHR_FSBIR)
cpu_relax();
- pxa27x_setup_hc(pxa_ohci, inf);
+ pxa27x_setup_hc(ohci, inf);
if (inf->init)
retval = inf->init(dev);
@@ -251,39 +240,38 @@ static int pxa27x_start_hc(struct pxa27x_ohci *pxa_ohci, struct device *dev)
return retval;
if (cpu_is_pxa3xx())
- pxa3xx_u2d_start_hc(&hcd->self);
+ pxa3xx_u2d_start_hc(&ohci_to_hcd(&ohci->ohci)->self);
- uhchr = __raw_readl(pxa_ohci->mmio_base + UHCHR) & ~UHCHR_SSE;
- __raw_writel(uhchr, pxa_ohci->mmio_base + UHCHR);
- __raw_writel(UHCHIE_UPRIE | UHCHIE_RWIE, pxa_ohci->mmio_base + UHCHIE);
+ uhchr = __raw_readl(ohci->mmio_base + UHCHR) & ~UHCHR_SSE;
+ __raw_writel(uhchr, ohci->mmio_base + UHCHR);
+ __raw_writel(UHCHIE_UPRIE | UHCHIE_RWIE, ohci->mmio_base + UHCHIE);
/* Clear any OTG Pin Hold */
pxa27x_clear_otgph();
return 0;
}
-static void pxa27x_stop_hc(struct pxa27x_ohci *pxa_ohci, struct device *dev)
+static void pxa27x_stop_hc(struct pxa27x_ohci *ohci, struct device *dev)
{
struct pxaohci_platform_data *inf;
- struct usb_hcd *hcd = dev_get_drvdata(dev);
uint32_t uhccoms;
inf = dev_get_platdata(dev);
if (cpu_is_pxa3xx())
- pxa3xx_u2d_stop_hc(&hcd->self);
+ pxa3xx_u2d_stop_hc(&ohci_to_hcd(&ohci->ohci)->self);
if (inf->exit)
inf->exit(dev);
- pxa27x_reset_hc(pxa_ohci);
+ pxa27x_reset_hc(ohci);
/* Host Controller Reset */
- uhccoms = __raw_readl(pxa_ohci->mmio_base + UHCCOMS) | 0x01;
- __raw_writel(uhccoms, pxa_ohci->mmio_base + UHCCOMS);
+ uhccoms = __raw_readl(ohci->mmio_base + UHCCOMS) | 0x01;
+ __raw_writel(uhccoms, ohci->mmio_base + UHCCOMS);
udelay(10);
- clk_disable_unprepare(pxa_ohci->clk);
+ clk_disable_unprepare(ohci->clk);
}
#ifdef CONFIG_OF
@@ -299,7 +287,6 @@ static int ohci_pxa_of_init(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
struct pxaohci_platform_data *pdata;
u32 tmp;
- int ret;
if (!np)
return 0;
@@ -308,9 +295,10 @@ static int ohci_pxa_of_init(struct platform_device *pdev)
* 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(&pdev->dev, DMA_BIT_MASK(32));
- if (ret)
- return ret;
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+ if (!pdev->dev.coherent_dma_mask)
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
@@ -368,8 +356,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
int retval, irq;
struct usb_hcd *hcd;
struct pxaohci_platform_data *inf;
- struct pxa27x_ohci *pxa_ohci;
- struct ohci_hcd *ohci;
+ struct pxa27x_ohci *ohci;
struct resource *r;
struct clk *usb_clk;
@@ -422,31 +409,29 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
}
/* initialize "struct pxa27x_ohci" */
- pxa_ohci = to_pxa27x_ohci(hcd);
- pxa_ohci->clk = usb_clk;
- pxa_ohci->mmio_base = (void __iomem *)hcd->regs;
+ ohci = (struct pxa27x_ohci *)hcd_to_ohci(hcd);
+ ohci->dev = &pdev->dev;
+ ohci->clk = usb_clk;
+ ohci->mmio_base = (void __iomem *)hcd->regs;
- retval = pxa27x_start_hc(pxa_ohci, &pdev->dev);
- if (retval < 0) {
+ if ((retval = pxa27x_start_hc(ohci, &pdev->dev)) < 0) {
pr_debug("pxa27x_start_hc failed");
goto err3;
}
/* Select Power Management Mode */
- pxa27x_ohci_select_pmm(pxa_ohci, inf->port_mode);
+ pxa27x_ohci_select_pmm(ohci, inf->port_mode);
if (inf->power_budget)
hcd->power_budget = inf->power_budget;
- /* The value of NDP in roothub_a is incorrect on this hardware */
- ohci = hcd_to_ohci(hcd);
- ohci->num_ports = 3;
+ ohci_hcd_init(hcd_to_ohci(hcd));
retval = usb_add_hcd(hcd, irq, 0);
if (retval == 0)
return retval;
- pxa27x_stop_hc(pxa_ohci, &pdev->dev);
+ pxa27x_stop_hc(ohci, &pdev->dev);
err3:
iounmap(hcd->regs);
err2:
@@ -474,18 +459,88 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
*/
void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *pdev)
{
- struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd);
+ struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd);
usb_remove_hcd(hcd);
- pxa27x_stop_hc(pxa_ohci, &pdev->dev);
+ pxa27x_stop_hc(ohci, &pdev->dev);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
- clk_put(pxa_ohci->clk);
usb_put_hcd(hcd);
+ clk_put(ohci->clk);
}
/*-------------------------------------------------------------------------*/
+static int
+ohci_pxa27x_start (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int ret;
+
+ ohci_dbg (ohci, "ohci_pxa27x_start, ohci:%p", ohci);
+
+ /* The value of NDP in roothub_a is incorrect on this hardware */
+ ohci->num_ports = 3;
+
+ if ((ret = ohci_init(ohci)) < 0)
+ return ret;
+
+ if ((ret = ohci_run (ohci)) < 0) {
+ dev_err(hcd->self.controller, "can't start %s",
+ hcd->self.bus_name);
+ ohci_stop (hcd);
+ return ret;
+ }
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_pxa27x_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "PXA27x OHCI",
+ .hcd_priv_size = sizeof(struct pxa27x_ohci),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ /*
+ * basic lifecycle operations
+ */
+ .start = ohci_pxa27x_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ohci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+#ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+#endif
+ .start_port_reset = ohci_start_port_reset,
+};
+
+/*-------------------------------------------------------------------------*/
+
static int ohci_hcd_pxa27x_drv_probe(struct platform_device *pdev)
{
pr_debug ("In ohci_hcd_pxa27x_drv_probe");
@@ -508,42 +563,32 @@ static int ohci_hcd_pxa27x_drv_remove(struct platform_device *pdev)
static int ohci_hcd_pxa27x_drv_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
- struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd);
- struct ohci_hcd *ohci = hcd_to_ohci(hcd);
- bool do_wakeup = device_may_wakeup(dev);
- int ret;
-
+ struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd);
- if (time_before(jiffies, ohci->next_statechange))
+ if (time_before(jiffies, ohci->ohci.next_statechange))
msleep(5);
- ohci->next_statechange = jiffies;
+ ohci->ohci.next_statechange = jiffies;
- ret = ohci_suspend(hcd, do_wakeup);
- if (ret)
- return ret;
-
- pxa27x_stop_hc(pxa_ohci, dev);
- return ret;
+ pxa27x_stop_hc(ohci, dev);
+ return 0;
}
static int ohci_hcd_pxa27x_drv_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
- struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd);
+ struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd);
struct pxaohci_platform_data *inf = dev_get_platdata(dev);
- struct ohci_hcd *ohci = hcd_to_ohci(hcd);
int status;
- if (time_before(jiffies, ohci->next_statechange))
+ if (time_before(jiffies, ohci->ohci.next_statechange))
msleep(5);
- ohci->next_statechange = jiffies;
+ ohci->ohci.next_statechange = jiffies;
- status = pxa27x_start_hc(pxa_ohci, dev);
- if (status < 0)
+ if ((status = pxa27x_start_hc(ohci, dev)) < 0)
return status;
/* Select Power Management Mode */
- pxa27x_ohci_select_pmm(pxa_ohci, inf->port_mode);
+ pxa27x_ohci_select_pmm(ohci, inf->port_mode);
ohci_resume(hcd, false);
return 0;
@@ -555,6 +600,9 @@ static const struct dev_pm_ops ohci_hcd_pxa27x_pm_ops = {
};
#endif
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:pxa27x-ohci");
+
static struct platform_driver ohci_hcd_pxa27x_driver = {
.probe = ohci_hcd_pxa27x_drv_probe,
.remove = ohci_hcd_pxa27x_drv_remove,
@@ -569,27 +617,3 @@ static struct platform_driver ohci_hcd_pxa27x_driver = {
},
};
-static const struct ohci_driver_overrides pxa27x_overrides __initconst = {
- .extra_priv_size = sizeof(struct pxa27x_ohci),
-};
-
-static int __init ohci_pxa27x_init(void)
-{
- if (usb_disabled())
- return -ENODEV;
-
- pr_info("%s: " DRIVER_DESC "\n", hcd_name);
- ohci_init_driver(&ohci_pxa27x_hc_driver, &pxa27x_overrides);
- return platform_driver_register(&ohci_hcd_pxa27x_driver);
-}
-module_init(ohci_pxa27x_init);
-
-static void __exit ohci_pxa27x_cleanup(void)
-{
- platform_driver_unregister(&ohci_hcd_pxa27x_driver);
-}
-module_exit(ohci_pxa27x_cleanup);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:pxa27x-ohci");