2 * EHCI HCD (Host Controller Driver) for USB.
4 * (C) Copyright 2006-2007 Stefan Roese <sr@denx.de>, DENX Software Engineering
6 * Bus Glue for PPC On-Chip EHCI driver
7 * Tested on AMCC 440EPx
9 * Based on "ehci-au1xxx.c" by K.Boge <karsten.boge@amd.com>
11 * This file is licenced under the GPL.
14 #include <linux/platform_device.h>
16 extern int usb_disabled(void);
18 /* called during probe() after chip reset completes */
19 static int ehci_ppc_soc_setup(struct usb_hcd
*hcd
)
21 struct ehci_hcd
*ehci
= hcd_to_ehci(hcd
);
24 retval
= ehci_halt(ehci
);
28 retval
= ehci_init(hcd
);
33 return ehci_reset(ehci
);
37 * usb_ehci_ppc_soc_probe - initialize PPC-SoC-based HCDs
38 * Context: !in_interrupt()
40 * Allocates basic resources for this USB host controller, and
41 * then invokes the start() method for the HCD associated with it
42 * through the hotplug entry's driver_data.
45 int usb_ehci_ppc_soc_probe(const struct hc_driver
*driver
,
46 struct usb_hcd
**hcd_out
,
47 struct platform_device
*dev
)
51 struct ehci_hcd
*ehci
;
53 if (dev
->resource
[1].flags
!= IORESOURCE_IRQ
) {
54 pr_debug("resource[1] is not IORESOURCE_IRQ");
57 hcd
= usb_create_hcd(driver
, &dev
->dev
, "PPC-SOC EHCI");
60 hcd
->rsrc_start
= dev
->resource
[0].start
;
61 hcd
->rsrc_len
= dev
->resource
[0].end
- dev
->resource
[0].start
+ 1;
63 if (!request_mem_region(hcd
->rsrc_start
, hcd
->rsrc_len
, hcd_name
)) {
64 pr_debug("request_mem_region failed");
69 hcd
->regs
= ioremap(hcd
->rsrc_start
, hcd
->rsrc_len
);
71 pr_debug("ioremap failed");
76 ehci
= hcd_to_ehci(hcd
);
77 ehci
->big_endian_mmio
= 1;
78 ehci
->big_endian_desc
= 1;
79 ehci
->caps
= hcd
->regs
;
80 ehci
->regs
= hcd
->regs
+ HC_LENGTH(ehci_readl(ehci
, &ehci
->caps
->hc_capbase
));
82 /* cache this readonly data; minimize chip reads */
83 ehci
->hcs_params
= ehci_readl(ehci
, &ehci
->caps
->hcs_params
);
85 #if defined(CONFIG_440EPX)
87 * 440EPx Errata USBH_3
88 * Fix: Enable Break Memory Transfer (BMT) in INSNREG3
90 out_be32((void *)((ulong
)(&ehci
->regs
->command
) + 0x8c), (1 << 0));
91 ehci_dbg(ehci
, "Break Memory Transfer (BMT) has beed enabled!\n");
94 retval
= usb_add_hcd(hcd
, dev
->resource
[1].start
, IRQF_DISABLED
);
100 release_mem_region(hcd
->rsrc_start
, hcd
->rsrc_len
);
106 /* may be called without controller electrically present */
107 /* may be called with controller, bus, and devices active */
110 * usb_ehci_hcd_ppc_soc_remove - shutdown processing for PPC-SoC-based HCDs
111 * @dev: USB Host Controller being removed
112 * Context: !in_interrupt()
114 * Reverses the effect of usb_ehci_hcd_ppc_soc_probe(), first invoking
115 * the HCD's stop() method. It is always called from a thread
116 * context, normally "rmmod", "apmd", or something similar.
119 void usb_ehci_ppc_soc_remove(struct usb_hcd
*hcd
, struct platform_device
*dev
)
123 release_mem_region(hcd
->rsrc_start
, hcd
->rsrc_len
);
127 static const struct hc_driver ehci_ppc_soc_hc_driver
= {
128 .description
= hcd_name
,
129 .product_desc
= "PPC-SOC EHCI",
130 .hcd_priv_size
= sizeof(struct ehci_hcd
),
133 * generic hardware linkage
136 .flags
= HCD_MEMORY
| HCD_USB2
,
139 * basic lifecycle operations
141 .reset
= ehci_ppc_soc_setup
,
144 .shutdown
= ehci_shutdown
,
147 * managing i/o requests and associated device resources
149 .urb_enqueue
= ehci_urb_enqueue
,
150 .urb_dequeue
= ehci_urb_dequeue
,
151 .endpoint_disable
= ehci_endpoint_disable
,
156 .get_frame_number
= ehci_get_frame
,
161 .hub_status_data
= ehci_hub_status_data
,
162 .hub_control
= ehci_hub_control
,
163 .bus_suspend
= ehci_bus_suspend
,
164 .bus_resume
= ehci_bus_resume
,
165 .relinquish_port
= ehci_relinquish_port
,
166 .port_handed_over
= ehci_port_handed_over
,
169 static int ehci_hcd_ppc_soc_drv_probe(struct platform_device
*pdev
)
171 struct usb_hcd
*hcd
= NULL
;
174 pr_debug("In ehci_hcd_ppc_soc_drv_probe\n");
179 /* FIXME we only want one one probe() not two */
180 ret
= usb_ehci_ppc_soc_probe(&ehci_ppc_soc_hc_driver
, &hcd
, pdev
);
184 static int ehci_hcd_ppc_soc_drv_remove(struct platform_device
*pdev
)
186 struct usb_hcd
*hcd
= platform_get_drvdata(pdev
);
188 /* FIXME we only want one one remove() not two */
189 usb_ehci_ppc_soc_remove(hcd
, pdev
);
193 MODULE_ALIAS("platform:ppc-soc-ehci");
194 static struct platform_driver ehci_ppc_soc_driver
= {
195 .probe
= ehci_hcd_ppc_soc_drv_probe
,
196 .remove
= ehci_hcd_ppc_soc_drv_remove
,
197 .shutdown
= usb_hcd_platform_shutdown
,
199 .name
= "ppc-soc-ehci",