blob: 83f3a40db538ab14e6145c23fbde0a38df66a45f [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,
92
93 /*
94 * managing i/o requests and associated device resources
95 */
96 .urb_enqueue = ohci_urb_enqueue,
97 .urb_dequeue = ohci_urb_dequeue,
98 .endpoint_disable = ohci_endpoint_disable,
99
100 /*
101 * scheduling support
102 */
103 .get_frame_number = ohci_get_frame,
104
105 /*
106 * root hub support
107 */
108 .hub_status_data = ohci_hub_status_data,
109 .hub_control = ohci_hub_control,
110#ifdef CONFIG_PM
111 .bus_suspend = ohci_bus_suspend,
112 .bus_resume = ohci_bus_resume,
113#endif
114 .start_port_reset = ohci_start_port_reset,
115};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
Russell Kingae99ddb2012-01-26 13:25:47 +0000117static int sa1111_start_hc(struct sa1111_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118{
119 unsigned int usb_rst = 0;
Russell Kingae99ddb2012-01-26 13:25:47 +0000120 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
Russell King3f878db2012-01-26 10:39:57 +0000122 dev_dbg(&dev->dev, "starting SA-1111 OHCI USB Controller\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 if (machine_is_xp860() ||
125 machine_has_neponset() ||
126 machine_is_pfs168() ||
127 machine_is_badge4())
128 usb_rst = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW;
129
130 /*
131 * Configure the power sense and control lines. Place the USB
132 * host controller in reset.
133 */
134 sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
Russell King22135362012-01-16 11:37:03 +0000135 dev->mapbase + USB_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
137 /*
138 * Now, carefully enable the USB clock, and take
139 * the USB host controller out of reset.
140 */
Russell Kingae99ddb2012-01-26 13:25:47 +0000141 ret = sa1111_enable_device(dev);
142 if (ret == 0) {
143 udelay(11);
Russell King22135362012-01-16 11:37:03 +0000144 sa1111_writel(usb_rst, dev->mapbase + USB_RESET);
Russell Kingae99ddb2012-01-26 13:25:47 +0000145 }
146
147 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148}
149
150static void sa1111_stop_hc(struct sa1111_dev *dev)
151{
152 unsigned int usb_rst;
Russell King9cb0f812012-01-26 10:37:46 +0000153
Russell King3f878db2012-01-26 10:39:57 +0000154 dev_dbg(&dev->dev, "stopping SA-1111 OHCI USB Controller\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
156 /*
157 * Put the USB host controller into reset.
158 */
Russell King22135362012-01-16 11:37:03 +0000159 usb_rst = sa1111_readl(dev->mapbase + USB_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
Russell King22135362012-01-16 11:37:03 +0000161 dev->mapbase + USB_RESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162
163 /*
164 * Stop the USB clock.
165 */
166 sa1111_disable_device(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167}
168
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169/**
Russell King132db992012-01-26 10:52:34 +0000170 * ohci_hcd_sa1111_probe - initialize SA-1111-based HCDs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 *
172 * Allocates basic resources for this USB host controller, and
Russell King132db992012-01-26 10:52:34 +0000173 * then invokes the start() method for the HCD associated with it.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 */
Russell King132db992012-01-26 10:52:34 +0000175static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176{
177 struct usb_hcd *hcd;
Russell King132db992012-01-26 10:52:34 +0000178 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
Russell King132db992012-01-26 10:52:34 +0000180 if (usb_disabled())
181 return -ENODEV;
182
183 hcd = usb_create_hcd(&ohci_sa1111_hc_driver, &dev->dev, "sa1111");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 if (!hcd)
185 return -ENOMEM;
Russell King9cb0f812012-01-26 10:37:46 +0000186
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 hcd->rsrc_start = dev->res.start;
Joe Perches28f65c112011-06-09 09:13:32 -0700188 hcd->rsrc_len = resource_size(&dev->res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
190 if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
191 dbg("request_mem_region failed");
Russell King132db992012-01-26 10:52:34 +0000192 ret = -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 goto err1;
194 }
Russell King9cb0f812012-01-26 10:37:46 +0000195
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 hcd->regs = dev->mapbase;
197
Russell Kingae99ddb2012-01-26 13:25:47 +0000198 ret = sa1111_start_hc(dev);
199 if (ret)
200 goto err2;
201
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 ohci_hcd_init(hcd_to_ohci(hcd));
203
Russell King132db992012-01-26 10:52:34 +0000204 ret = usb_add_hcd(hcd, dev->irq[1], 0);
205 if (ret == 0)
206 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
208 sa1111_stop_hc(dev);
Russell Kingae99ddb2012-01-26 13:25:47 +0000209 err2:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
211 err1:
212 usb_put_hcd(hcd);
Russell King132db992012-01-26 10:52:34 +0000213 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214}
215
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216/**
Russell King132db992012-01-26 10:52:34 +0000217 * ohci_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 * @dev: USB Host Controller being removed
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 *
Russell King132db992012-01-26 10:52:34 +0000220 * Reverses the effect of ohci_hcd_sa1111_probe(), first invoking
221 * the HCD's stop() method.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 */
Russell King132db992012-01-26 10:52:34 +0000223static int ohci_hcd_sa1111_remove(struct sa1111_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224{
Russell King132db992012-01-26 10:52:34 +0000225 struct usb_hcd *hcd = sa1111_get_drvdata(dev);
226
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 usb_remove_hcd(hcd);
228 sa1111_stop_hc(dev);
229 release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
230 usb_put_hcd(hcd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 return 0;
233}
234
235static struct sa1111_driver ohci_hcd_sa1111_driver = {
236 .drv = {
237 .name = "sa1111-ohci",
Russell King1ebcd762012-01-26 11:19:48 +0000238 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 },
240 .devid = SA1111_DEVID_USB,
Russell King132db992012-01-26 10:52:34 +0000241 .probe = ohci_hcd_sa1111_probe,
242 .remove = ohci_hcd_sa1111_remove,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243};