blob: 95c3f0fb48d3c9d79b2020dec51f12ba3a1acbc9 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * OHCI HCD (Host Controller Driver) for USB.
3 *
4 * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
5 * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
6 * (C) Copyright 2002 Hewlett-Packard Company
David Brownelldd9048a2006-12-05 03:18:31 -08007 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * SA1111 Bus Glue
9 *
10 * Written by Christopher Hoover <ch@hpl.hp.com>
Uwe Kleine-Königac310bb2008-07-10 17:30:46 -070011 * Based on fragments of previous driver by Russell King et al.
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 *
13 * This file is licenced under the GPL.
14 */
David Brownelldd9048a2006-12-05 03:18:31 -080015
Russell Kinga09e64f2008-08-05 16:14:15 +010016#include <mach/hardware.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <asm/mach-types.h>
Russell Kinga09e64f2008-08-05 16:14:15 +010018#include <mach/assabet.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <asm/hardware/sa1111.h>
20
21#ifndef CONFIG_SA1111
22#error "This file is SA-1111 bus glue. CONFIG_SA1111 must be defined."
23#endif
24
Russell King22135362012-01-16 11:37:03 +000025#define USB_STATUS 0x0118
26#define USB_RESET 0x011c
27#define USB_IRQTEST 0x0120
28
29#define USB_RESET_FORCEIFRESET (1 << 0)
30#define USB_RESET_FORCEHCRESET (1 << 1)
31#define USB_RESET_CLKGENRESET (1 << 2)
32#define USB_RESET_SIMSCALEDOWN (1 << 3)
33#define USB_RESET_USBINTTEST (1 << 4)
34#define USB_RESET_SLEEPSTBYEN (1 << 5)
35#define USB_RESET_PWRSENSELOW (1 << 6)
36#define USB_RESET_PWRCTRLLOW (1 << 7)
37
38#define USB_STATUS_IRQHCIRMTWKUP (1 << 7)
39#define USB_STATUS_IRQHCIBUFFACC (1 << 8)
40#define USB_STATUS_NIRQHCIM (1 << 9)
41#define USB_STATUS_NHCIMFCLR (1 << 10)
42#define USB_STATUS_USBPWRSENSE (1 << 11)
43
Russell King132db992012-01-26 10:52:34 +000044#if 0
45static void dump_hci_status(struct usb_hcd *hcd, const char *label)
46{
47 unsigned long status = sa1111_readl(hcd->regs + USB_STATUS);
48
49 dbg("%s USB_STATUS = { %s%s%s%s%s}", label,
50 ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""),
51 ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""),
52 ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "),
53 ((status & USB_STATUS_NHCIMFCLR) ? "" : "HCIMFCLR "),
54 ((status & USB_STATUS_USBPWRSENSE) ? "USBPWRSENSE " : ""));
55}
56#endif
57
58static int __devinit ohci_sa1111_start(struct usb_hcd *hcd)
59{
60 struct ohci_hcd *ohci = hcd_to_ohci(hcd);
61 int ret;
62
63 ret = ohci_init(ohci);
64 if (ret < 0)
65 return ret;
66
67 ret = ohci_run(ohci);
68 if (ret < 0) {
69 err("can't start %s", hcd->self.bus_name);
70 ohci_stop(hcd);
71 return ret;
72 }
73 return 0;
74}
75
76static const struct hc_driver ohci_sa1111_hc_driver = {
77 .description = hcd_name,
78 .product_desc = "SA-1111 OHCI",
79 .hcd_priv_size = sizeof(struct ohci_hcd),
80
81 /*
82 * generic hardware linkage
83 */
84 .irq = ohci_irq,
85 .flags = HCD_USB11 | HCD_MEMORY,
86
87 /*
88 * basic lifecycle operations
89 */
90 .start = ohci_sa1111_start,
91 .stop = ohci_stop,
Russell King846a7042012-01-26 11:10:20 +000092 .shutdown = ohci_shutdown,
Russell King132db992012-01-26 10:52:34 +000093
94 /*
95 * managing i/o requests and associated device resources
96 */
97 .urb_enqueue = ohci_urb_enqueue,
98 .urb_dequeue = ohci_urb_dequeue,
99 .endpoint_disable = ohci_endpoint_disable,
100
101 /*
102 * scheduling support
103 */
104 .get_frame_number = ohci_get_frame,
105
106 /*
107 * root hub support
108 */
109 .hub_status_data = ohci_hub_status_data,
110 .hub_control = ohci_hub_control,
111#ifdef CONFIG_PM
112 .bus_suspend = ohci_bus_suspend,
113 .bus_resume = ohci_bus_resume,
114#endif
115 .start_port_reset = ohci_start_port_reset,
116};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117
Russell Kingae99ddb2012-01-26 13:25:47 +0000118static int sa1111_start_hc(struct sa1111_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119{
120 unsigned int usb_rst = 0;
Russell Kingae99ddb2012-01-26 13:25:47 +0000121 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
Russell King3f878db2012-01-26 10:39:57 +0000123 dev_dbg(&dev->dev, "starting SA-1111 OHCI USB Controller\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 if (machine_is_xp860() ||
126 machine_has_neponset() ||
127 machine_is_pfs168() ||
128 machine_is_badge4())
129 usb_rst = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW;
130
131 /*
132 * Configure the power sense and control lines. Place the USB
133 * host controller in reset.
134 */
135 sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
Russell King22135362012-01-16 11:37:03 +0000136 dev->mapbase + USB_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137
138 /*
139 * Now, carefully enable the USB clock, and take
140 * the USB host controller out of reset.
141 */
Russell Kingae99ddb2012-01-26 13:25:47 +0000142 ret = sa1111_enable_device(dev);
143 if (ret == 0) {
144 udelay(11);
Russell King22135362012-01-16 11:37:03 +0000145 sa1111_writel(usb_rst, dev->mapbase + USB_RESET);
Russell Kingae99ddb2012-01-26 13:25:47 +0000146 }
147
148 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149}
150
151static void sa1111_stop_hc(struct sa1111_dev *dev)
152{
153 unsigned int usb_rst;
Russell King9cb0f812012-01-26 10:37:46 +0000154
Russell King3f878db2012-01-26 10:39:57 +0000155 dev_dbg(&dev->dev, "stopping SA-1111 OHCI USB Controller\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
157 /*
158 * Put the USB host controller into reset.
159 */
Russell King22135362012-01-16 11:37:03 +0000160 usb_rst = sa1111_readl(dev->mapbase + USB_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
Russell King22135362012-01-16 11:37:03 +0000162 dev->mapbase + USB_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
164 /*
165 * Stop the USB clock.
166 */
167 sa1111_disable_device(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168}
169
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170/**
Russell King132db992012-01-26 10:52:34 +0000171 * ohci_hcd_sa1111_probe - initialize SA-1111-based HCDs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 *
173 * Allocates basic resources for this USB host controller, and
Russell King132db992012-01-26 10:52:34 +0000174 * then invokes the start() method for the HCD associated with it.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 */
Russell King132db992012-01-26 10:52:34 +0000176static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177{
178 struct usb_hcd *hcd;
Russell King132db992012-01-26 10:52:34 +0000179 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
Russell King132db992012-01-26 10:52:34 +0000181 if (usb_disabled())
182 return -ENODEV;
183
184 hcd = usb_create_hcd(&ohci_sa1111_hc_driver, &dev->dev, "sa1111");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 if (!hcd)
186 return -ENOMEM;
Russell King9cb0f812012-01-26 10:37:46 +0000187
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 hcd->rsrc_start = dev->res.start;
Joe Perches28f65c112011-06-09 09:13:32 -0700189 hcd->rsrc_len = resource_size(&dev->res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
191 if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
192 dbg("request_mem_region failed");
Russell King132db992012-01-26 10:52:34 +0000193 ret = -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 goto err1;
195 }
Russell King9cb0f812012-01-26 10:37:46 +0000196
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 hcd->regs = dev->mapbase;
198
Russell Kingae99ddb2012-01-26 13:25:47 +0000199 ret = sa1111_start_hc(dev);
200 if (ret)
201 goto err2;
202
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 ohci_hcd_init(hcd_to_ohci(hcd));
204
Russell King132db992012-01-26 10:52:34 +0000205 ret = usb_add_hcd(hcd, dev->irq[1], 0);
206 if (ret == 0)
207 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
209 sa1111_stop_hc(dev);
Russell Kingae99ddb2012-01-26 13:25:47 +0000210 err2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
212 err1:
213 usb_put_hcd(hcd);
Russell King132db992012-01-26 10:52:34 +0000214 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215}
216
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217/**
Russell King132db992012-01-26 10:52:34 +0000218 * ohci_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 * @dev: USB Host Controller being removed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 *
Russell King132db992012-01-26 10:52:34 +0000221 * Reverses the effect of ohci_hcd_sa1111_probe(), first invoking
222 * the HCD's stop() method.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 */
Russell King132db992012-01-26 10:52:34 +0000224static int ohci_hcd_sa1111_remove(struct sa1111_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225{
Russell King132db992012-01-26 10:52:34 +0000226 struct usb_hcd *hcd = sa1111_get_drvdata(dev);
227
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 usb_remove_hcd(hcd);
229 sa1111_stop_hc(dev);
230 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
231 usb_put_hcd(hcd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 return 0;
234}
235
Russell King846a7042012-01-26 11:10:20 +0000236static void ohci_hcd_sa1111_shutdown(struct sa1111_dev *dev)
237{
238 struct usb_hcd *hcd = sa1111_get_drvdata(dev);
239
240 if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
241 hcd->driver->shutdown(hcd);
242 sa1111_stop_hc(dev);
243 }
244}
245
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246static struct sa1111_driver ohci_hcd_sa1111_driver = {
247 .drv = {
248 .name = "sa1111-ohci",
Russell King1ebcd762012-01-26 11:19:48 +0000249 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 },
251 .devid = SA1111_DEVID_USB,
Russell King132db992012-01-26 10:52:34 +0000252 .probe = ohci_hcd_sa1111_probe,
253 .remove = ohci_hcd_sa1111_remove,
Russell King846a7042012-01-26 11:10:20 +0000254 .shutdown = ohci_hcd_sa1111_shutdown,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255};