Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1/*
  2 * Sonics Silicon Backplane
  3 * Broadcom USB-core OHCI driver
  4 *
  5 * Copyright 2007 Michael Buesch <m@bues.ch>
  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		/* Work around for 5354 failures */
146		if (dev->id.revision == 2 && dev->bus->chip_id == 0x5354) {
147			/* Change syn01 reg */
148			tmp = 0x00fe00fe;
149			ssb_write32(dev, 0x894, tmp);
150
151			/* Change syn03 reg */
152			tmp = ssb_read32(dev, 0x89c);
153			tmp |= 0x1;
154			ssb_write32(dev, 0x89c, tmp);
155		}
156	} else
157		ssb_device_enable(dev, 0);
158
159	hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
160			dev_name(dev->dev));
161	if (!hcd)
162		goto err_dev_disable;
163	ohcidev = hcd_to_ssb_ohci(hcd);
164	ohcidev->enable_flags = flags;
165
166	tmp = ssb_read32(dev, SSB_ADMATCH0);
167	hcd->rsrc_start = ssb_admatch_base(tmp);
168	hcd->rsrc_len = ssb_admatch_size(tmp);
169	hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
170	if (!hcd->regs)
171		goto err_put_hcd;
172	err = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED);
173	if (err)
174		goto err_iounmap;
175
176	ssb_set_drvdata(dev, hcd);
177
178	return err;
179
180err_iounmap:
181	iounmap(hcd->regs);
182err_put_hcd:
183	usb_put_hcd(hcd);
184err_dev_disable:
185	ssb_device_disable(dev, flags);
186	return err;
187}
188
189static int ssb_ohci_probe(struct ssb_device *dev,
190		const struct ssb_device_id *id)
191{
192	int err;
193	u16 chipid_top;
194
195	/* USBcores are only connected on embedded devices. */
196	chipid_top = (dev->bus->chip_id & 0xFF00);
197	if (chipid_top != 0x4700 && chipid_top != 0x5300)
198		return -ENODEV;
199
200	/* TODO: Probably need checks here; is the core connected? */
201
202	if (usb_disabled())
203		return -ENODEV;
204
205	/* We currently always attach SSB_DEV_USB11_HOSTDEV
206	 * as HOST OHCI. If we want to attach it as Client device,
207	 * we must branch here and call into the (yet to
208	 * be written) Client mode driver. Same for remove(). */
209
210	err = ssb_ohci_attach(dev);
211
212	return err;
213}
214
215static void ssb_ohci_remove(struct ssb_device *dev)
216{
217	ssb_ohci_detach(dev);
218}
219
220#ifdef CONFIG_PM
221
222static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state)
223{
224	ssb_device_disable(dev, 0);
225
226	return 0;
227}
228
229static int ssb_ohci_resume(struct ssb_device *dev)
230{
231	struct usb_hcd *hcd = ssb_get_drvdata(dev);
232	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
233
234	ssb_device_enable(dev, ohcidev->enable_flags);
235
236	ohci_finish_controller_resume(hcd);
237	return 0;
238}
239
240#else /* !CONFIG_PM */
241#define ssb_ohci_suspend	NULL
242#define ssb_ohci_resume	NULL
243#endif /* CONFIG_PM */
244
245static const struct ssb_device_id ssb_ohci_table[] = {
246	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
247	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
248	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
249	SSB_DEVTABLE_END
250};
251MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
252
253static struct ssb_driver ssb_ohci_driver = {
254	.name		= KBUILD_MODNAME,
255	.id_table	= ssb_ohci_table,
256	.probe		= ssb_ohci_probe,
257	.remove		= ssb_ohci_remove,
258	.suspend	= ssb_ohci_suspend,
259	.resume		= ssb_ohci_resume,
260};