• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/usb/host/
1/*
2 * Sonics Silicon Backplane
3 * Broadcom USB-core OHCI driver
4 *
5 * Copyright 2007 Michael Buesch <mb@bu3sch.de>
6 *
7 * Derived from the OHCI-PCI driver
8 * Copyright 1999 Roman Weissgaerber
9 * Copyright 2000-2002 David Brownell
10 * Copyright 1999 Linus Torvalds
11 * Copyright 1999 Gregory P. Smith
12 *
13 * Derived from the USBcore related parts of Broadcom-SB
14 * Copyright 2005 Broadcom Corporation
15 *
16 * Licensed under the GNU/GPL. See COPYING for details.
17 */
18#include <linux/ssb/ssb.h>
19
20
21#define SSB_OHCI_TMSLOW_HOSTMODE	(1 << 29)
22
23struct ssb_ohci_device {
24	struct ohci_hcd ohci; /* _must_ be at the beginning. */
25
26	u32 enable_flags;
27};
28
29static inline
30struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd)
31{
32	return (struct ssb_ohci_device *)(hcd->hcd_priv);
33}
34
35
36static int ssb_ohci_reset(struct usb_hcd *hcd)
37{
38	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
39	struct ohci_hcd *ohci = &ohcidev->ohci;
40	int err;
41
42	ohci_hcd_init(ohci);
43	err = ohci_init(ohci);
44
45	return err;
46}
47
48static int ssb_ohci_start(struct usb_hcd *hcd)
49{
50	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
51	struct ohci_hcd *ohci = &ohcidev->ohci;
52	int err;
53
54	err = ohci_run(ohci);
55	if (err < 0) {
56		ohci_err(ohci, "can't start\n");
57		ohci_stop(hcd);
58	}
59
60	return err;
61}
62
63static const struct hc_driver ssb_ohci_hc_driver = {
64	.description		= "ssb-usb-ohci",
65	.product_desc		= "SSB OHCI Controller",
66	.hcd_priv_size		= sizeof(struct ssb_ohci_device),
67
68	.irq			= ohci_irq,
69	.flags			= HCD_MEMORY | HCD_USB11,
70
71	.reset			= ssb_ohci_reset,
72	.start			= ssb_ohci_start,
73	.stop			= ohci_stop,
74	.shutdown		= ohci_shutdown,
75
76	.urb_enqueue		= ohci_urb_enqueue,
77	.urb_dequeue		= ohci_urb_dequeue,
78	.endpoint_disable	= ohci_endpoint_disable,
79
80	.get_frame_number	= ohci_get_frame,
81
82	.hub_status_data	= ohci_hub_status_data,
83	.hub_control		= ohci_hub_control,
84#ifdef	CONFIG_PM
85	.bus_suspend		= ohci_bus_suspend,
86	.bus_resume		= ohci_bus_resume,
87#endif
88
89	.start_port_reset	= ohci_start_port_reset,
90};
91
92static void ssb_ohci_detach(struct ssb_device *dev)
93{
94	struct usb_hcd *hcd = ssb_get_drvdata(dev);
95
96	if (hcd->driver->shutdown)
97		hcd->driver->shutdown(hcd);
98	usb_remove_hcd(hcd);
99	iounmap(hcd->regs);
100	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
101	usb_put_hcd(hcd);
102	ssb_device_disable(dev, 0);
103}
104
105static int ssb_ohci_attach(struct ssb_device *dev)
106{
107	struct ssb_ohci_device *ohcidev;
108	struct usb_hcd *hcd;
109	int err = -ENOMEM;
110	u32 tmp, flags = 0;
111
112	if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
113	    dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
114		return -EOPNOTSUPP;
115
116	if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) {
117		/* Put the device into host-mode. */
118		flags |= SSB_OHCI_TMSLOW_HOSTMODE;
119		ssb_device_enable(dev, flags);
120	} else if (dev->id.coreid == SSB_DEV_USB20_HOST) {
121		/*
122		 * USB 2.0 special considerations:
123		 *
124		 * In addition to the standard SSB reset sequence, the Host
125		 * Control Register must be programmed to bring the USB core
126		 * and various phy components out of reset.
127		 */
128		ssb_device_enable(dev, 0);
129		ssb_write32(dev, 0x200, 0x7ff);
130
131		/* Change Flush control reg */
132		tmp = ssb_read32(dev, 0x400);
133		tmp &= ~8;
134		ssb_write32(dev, 0x400, tmp);
135		tmp = ssb_read32(dev, 0x400);
136
137		/* Change Shim control reg */
138		tmp = ssb_read32(dev, 0x304);
139		tmp &= ~0x100;
140		ssb_write32(dev, 0x304, tmp);
141		tmp = ssb_read32(dev, 0x304);
142
143		udelay(1);
144
145		if (dev->id.revision == 2 && dev->bus->chip_id == 0x5354) {
146			/* Change syn01 reg */
147			tmp = 0x00fe00fe;
148			ssb_write32(dev, 0x894, tmp);
149
150			/* Change syn03 reg */
151			tmp = ssb_read32(dev, 0x89c);
152			tmp |= 0x1;
153			ssb_write32(dev, 0x89c, tmp);
154		}
155	} else
156		ssb_device_enable(dev, 0);
157
158	hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
159			dev_name(dev->dev));
160	if (!hcd)
161		goto err_dev_disable;
162	ohcidev = hcd_to_ssb_ohci(hcd);
163	ohcidev->enable_flags = flags;
164
165	tmp = ssb_read32(dev, SSB_ADMATCH0);
166	hcd->rsrc_start = ssb_admatch_base(tmp);
167	hcd->rsrc_len = ssb_admatch_size(tmp);
168	hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
169	if (!hcd->regs)
170		goto err_put_hcd;
171	err = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED);
172	if (err)
173		goto err_iounmap;
174
175	ssb_set_drvdata(dev, hcd);
176
177	return err;
178
179err_iounmap:
180	iounmap(hcd->regs);
181err_put_hcd:
182	usb_put_hcd(hcd);
183err_dev_disable:
184	ssb_device_disable(dev, flags);
185	return err;
186}
187
188static int ssb_ohci_probe(struct ssb_device *dev,
189		const struct ssb_device_id *id)
190{
191	int err;
192	u16 chipid_top;
193
194	/* USBcores are only connected on embedded devices. */
195	chipid_top = (dev->bus->chip_id & 0xFF00);
196	if (chipid_top != 0x4700 && chipid_top != 0x5300)
197		return -ENODEV;
198
199	/* TODO: Probably need checks here; is the core connected? */
200
201	if (usb_disabled())
202		return -ENODEV;
203
204	/* We currently always attach SSB_DEV_USB11_HOSTDEV
205	 * as HOST OHCI. If we want to attach it as Client device,
206	 * we must branch here and call into the (yet to
207	 * be written) Client mode driver. Same for remove(). */
208
209	err = ssb_ohci_attach(dev);
210
211	return err;
212}
213
214static void ssb_ohci_remove(struct ssb_device *dev)
215{
216	ssb_ohci_detach(dev);
217}
218
219#ifdef CONFIG_PM
220
221static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state)
222{
223	ssb_device_disable(dev, 0);
224
225	return 0;
226}
227
228static int ssb_ohci_resume(struct ssb_device *dev)
229{
230	struct usb_hcd *hcd = ssb_get_drvdata(dev);
231	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
232
233	ssb_device_enable(dev, ohcidev->enable_flags);
234
235	ohci_finish_controller_resume(hcd);
236	return 0;
237}
238
239#else /* !CONFIG_PM */
240#define ssb_ohci_suspend	NULL
241#define ssb_ohci_resume	NULL
242#endif /* CONFIG_PM */
243
244static const struct ssb_device_id ssb_ohci_table[] = {
245	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
246	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
247	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
248	SSB_DEVTABLE_END
249};
250MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
251
252static struct ssb_driver ssb_ohci_driver = {
253	.name		= KBUILD_MODNAME,
254	.id_table	= ssb_ohci_table,
255	.probe		= ssb_ohci_probe,
256	.remove		= ssb_ohci_remove,
257	.suspend	= ssb_ohci_suspend,
258	.resume		= ssb_ohci_resume,
259};
260