aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/host/ehci-ppc-of.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ehci-ppc-of.c')
-rw-r--r--drivers/usb/host/ehci-ppc-of.c144
1 files changed, 73 insertions, 71 deletions
diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c
index ee305b1f99f..547924796d2 100644
--- a/drivers/usb/host/ehci-ppc-of.c
+++ b/drivers/usb/host/ehci-ppc-of.c
@@ -12,29 +12,14 @@
* This file is licenced under the GPL.
*/
+#include <linux/err.h>
#include <linux/signal.h>
#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/of_platform.h>
-/* called during probe() after chip reset completes */
-static int ehci_ppc_of_setup(struct usb_hcd *hcd)
-{
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- int retval;
-
- retval = ehci_halt(ehci);
- if (retval)
- return retval;
-
- retval = ehci_init(hcd);
- if (retval)
- return retval;
-
- ehci->sbrn = 0x20;
- return ehci_reset(ehci);
-}
-
static const struct hc_driver ehci_ppc_of_hc_driver = {
.description = hcd_name,
@@ -45,12 +30,12 @@ static const struct hc_driver ehci_ppc_of_hc_driver = {
* generic hardware linkage
*/
.irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
+ .flags = HCD_MEMORY | HCD_USB2 | HCD_BH,
/*
* basic lifecycle operations
*/
- .reset = ehci_ppc_of_setup,
+ .reset = ehci_setup,
.start = ehci_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,
@@ -61,6 +46,7 @@ static const struct hc_driver ehci_ppc_of_hc_driver = {
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
/*
* scheduling support
@@ -76,6 +62,10 @@ static const struct hc_driver ehci_ppc_of_hc_driver = {
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
#endif
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
@@ -84,7 +74,7 @@ static const struct hc_driver ehci_ppc_of_hc_driver = {
* Fix: Enable Break Memory Transfer (BMT) in INSNREG3
*/
#define PPC440EPX_EHCI0_INSREG_BMT (0x1 << 0)
-static int __devinit
+static int
ppc44x_enable_bmt(struct device_node *dn)
{
__iomem u32 *insreg_virt;
@@ -100,16 +90,17 @@ ppc44x_enable_bmt(struct device_node *dn)
}
-static int __devinit
-ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
+static int ehci_hcd_ppc_of_probe(struct platform_device *op)
{
- struct device_node *dn = op->node;
+ struct device_node *dn = op->dev.of_node;
struct usb_hcd *hcd;
- struct ehci_hcd *ehci;
+ struct ehci_hcd *ehci = NULL;
struct resource res;
int irq;
int rv;
+ struct device_node *np;
+
if (usb_disabled())
return -ENODEV;
@@ -124,29 +115,39 @@ ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
return -ENOMEM;
hcd->rsrc_start = res.start;
- hcd->rsrc_len = res.end - res.start + 1;
-
- if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
- printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
- rv = -EBUSY;
- goto err_rmr;
- }
+ hcd->rsrc_len = resource_size(&res);
irq = irq_of_parse_and_map(dn, 0);
if (irq == NO_IRQ) {
- printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+ dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n",
+ __FILE__);
rv = -EBUSY;
goto err_irq;
}
- hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
- if (!hcd->regs) {
- printk(KERN_ERR __FILE__ ": ioremap failed\n");
- rv = -ENOMEM;
+ hcd->regs = devm_ioremap_resource(&op->dev, &res);
+ if (IS_ERR(hcd->regs)) {
+ rv = PTR_ERR(hcd->regs);
goto err_ioremap;
}
ehci = hcd_to_ehci(hcd);
+ np = of_find_compatible_node(NULL, NULL, "ibm,usb-ohci-440epx");
+ if (np != NULL) {
+ /* claim we really affected by usb23 erratum */
+ if (!of_address_to_resource(np, 0, &res))
+ ehci->ohci_hcctrl_reg =
+ devm_ioremap(&op->dev,
+ res.start + OHCI_HCCTRL_OFFSET,
+ OHCI_HCCTRL_LEN);
+ else
+ pr_debug("%s: no ohci offset in fdt\n", __FILE__);
+ if (!ehci->ohci_hcctrl_reg) {
+ pr_debug("%s: ioremap for ohci hcctrl failed\n", __FILE__);
+ } else {
+ ehci->has_amcc_usb23 = 1;
+ }
+ }
if (of_get_property(dn, "big-endian", NULL)) {
ehci->big_endian_mmio = 1;
@@ -158,11 +159,6 @@ ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
ehci->big_endian_desc = 1;
ehci->caps = hcd->regs;
- ehci->regs = hcd->regs +
- HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
-
- /* cache this readonly data; minimize chip reads */
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
if (of_device_is_compatible(dn, "ibm,usb-ehci-440epx")) {
rv = ppc44x_enable_bmt(dn);
@@ -171,52 +167,59 @@ ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
}
rv = usb_add_hcd(hcd, irq, 0);
- if (rv == 0)
- return 0;
+ if (rv)
+ goto err_ioremap;
+
+ device_wakeup_enable(hcd->self.controller);
+ return 0;
- iounmap(hcd->regs);
err_ioremap:
irq_dispose_mapping(irq);
err_irq:
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err_rmr:
usb_put_hcd(hcd);
return rv;
}
-static int ehci_hcd_ppc_of_remove(struct of_device *op)
+static int ehci_hcd_ppc_of_remove(struct platform_device *op)
{
- struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
- dev_set_drvdata(&op->dev, NULL);
+ struct usb_hcd *hcd = platform_get_drvdata(op);
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+ struct device_node *np;
+ struct resource res;
dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
usb_remove_hcd(hcd);
- iounmap(hcd->regs);
irq_dispose_mapping(hcd->irq);
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ /* use request_mem_region to test if the ohci driver is loaded. if so
+ * ensure the ohci core is operational.
+ */
+ if (ehci->has_amcc_usb23) {
+ np = of_find_compatible_node(NULL, NULL, "ibm,usb-ohci-440epx");
+ if (np != NULL) {
+ if (!of_address_to_resource(np, 0, &res))
+ if (!request_mem_region(res.start,
+ 0x4, hcd_name))
+ set_ohci_hcfs(ehci, 1);
+ else
+ release_mem_region(res.start, 0x4);
+ else
+ pr_debug("%s: no ohci offset in fdt\n", __FILE__);
+ of_node_put(np);
+ }
+ }
usb_put_hcd(hcd);
return 0;
}
-static int ehci_hcd_ppc_of_shutdown(struct of_device *op)
-{
- struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
-
- if (hcd->driver->shutdown)
- hcd->driver->shutdown(hcd);
-
- return 0;
-}
-
-
-static struct of_device_id ehci_hcd_ppc_of_match[] = {
+static const struct of_device_id ehci_hcd_ppc_of_match[] = {
{
.compatible = "usb-ehci",
},
@@ -225,14 +228,13 @@ static struct of_device_id ehci_hcd_ppc_of_match[] = {
MODULE_DEVICE_TABLE(of, ehci_hcd_ppc_of_match);
-static struct of_platform_driver ehci_hcd_ppc_of_driver = {
- .name = "ppc-of-ehci",
- .match_table = ehci_hcd_ppc_of_match,
+static struct platform_driver ehci_hcd_ppc_of_driver = {
.probe = ehci_hcd_ppc_of_probe,
.remove = ehci_hcd_ppc_of_remove,
- .shutdown = ehci_hcd_ppc_of_shutdown,
- .driver = {
- .name = "ppc-of-ehci",
- .owner = THIS_MODULE,
+ .shutdown = usb_hcd_platform_shutdown,
+ .driver = {
+ .name = "ppc-of-ehci",
+ .owner = THIS_MODULE,
+ .of_match_table = ehci_hcd_ppc_of_match,
},
};