1 /*
2  * PMC MSP EHCI (Host Controller Driver) for USB.
3  *
4  * (C) Copyright 2006-2010 PMC-Sierra Inc
5  *
6  * This file is subject to the terms and conditions of the GNU General Public
7  * License.  See the file "COPYING" in the main directory of this archive
8  * for more details.
9  *
10  */
11 
12 /* includes */
13 #include <linux/platform_device.h>
14 #include <linux/gpio.h>
15 #include <linux/usb.h>
16 #include <msp_usb.h>
17 
18 /* stream disable*/
19 #define USB_CTRL_MODE_STREAM_DISABLE	0x10
20 
21 /* threshold */
22 #define USB_CTRL_FIFO_THRESH		0x00300000
23 
24 /* register offset for usb_mode */
25 #define USB_EHCI_REG_USB_MODE		0x68
26 
27 /* register offset for usb fifo */
28 #define USB_EHCI_REG_USB_FIFO		0x24
29 
30 /* register offset for usb status */
31 #define USB_EHCI_REG_USB_STATUS		0x44
32 
33 /* serial/parallel transceiver */
34 #define USB_EHCI_REG_BIT_STAT_STS	(1<<29)
35 
36 /* TWI USB0 host device pin */
37 #define MSP_PIN_USB0_HOST_DEV		49
38 
39 /* TWI USB1 host device pin */
40 #define MSP_PIN_USB1_HOST_DEV		50
41 
42 
usb_hcd_tdi_set_mode(struct ehci_hcd * ehci)43 static void usb_hcd_tdi_set_mode(struct ehci_hcd *ehci)
44 {
45 	u8 *base;
46 	u8 *statreg;
47 	u8 *fiforeg;
48 	u32 val;
49 	struct ehci_regs *reg_base = ehci->regs;
50 
51 	/* get register base */
52 	base = (u8 *)reg_base + USB_EHCI_REG_USB_MODE;
53 	statreg = (u8 *)reg_base + USB_EHCI_REG_USB_STATUS;
54 	fiforeg = (u8 *)reg_base + USB_EHCI_REG_USB_FIFO;
55 
56 	/* Disable controller mode stream */
57 	val = ehci_readl(ehci, (u32 *)base);
58 	ehci_writel(ehci, (val | USB_CTRL_MODE_STREAM_DISABLE),
59 			(u32 *)base);
60 
61 	/* clear STS to select parallel transceiver interface */
62 	val = ehci_readl(ehci, (u32 *)statreg);
63 	val = val & ~USB_EHCI_REG_BIT_STAT_STS;
64 	ehci_writel(ehci, val, (u32 *)statreg);
65 
66 	/* write to set the proper fifo threshold */
67 	ehci_writel(ehci, USB_CTRL_FIFO_THRESH, (u32 *)fiforeg);
68 
69 	/* set TWI GPIO USB_HOST_DEV pin high */
70 	gpio_direction_output(MSP_PIN_USB0_HOST_DEV, 1);
71 #ifdef CONFIG_MSP_HAS_DUAL_USB
72 	gpio_direction_output(MSP_PIN_USB1_HOST_DEV, 1);
73 #endif
74 }
75 
76 /* called during probe() after chip reset completes */
ehci_msp_setup(struct usb_hcd * hcd)77 static int ehci_msp_setup(struct usb_hcd *hcd)
78 {
79 	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);
80 	int			retval;
81 	ehci->big_endian_mmio = 1;
82 	ehci->big_endian_desc = 1;
83 
84 	ehci->caps = hcd->regs;
85 	ehci->regs = hcd->regs +
86 			HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
87 	dbg_hcs_params(ehci, "reset");
88 	dbg_hcc_params(ehci, "reset");
89 
90 	/* cache this readonly data; minimize chip reads */
91 	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
92 	hcd->has_tt = 1;
93 
94 	retval = ehci_halt(ehci);
95 	if (retval)
96 		return retval;
97 
98 	ehci_reset(ehci);
99 
100 	/* data structure init */
101 	retval = ehci_init(hcd);
102 	if (retval)
103 		return retval;
104 
105 	usb_hcd_tdi_set_mode(ehci);
106 	ehci_port_power(ehci, 0);
107 
108 	return retval;
109 }
110 
111 
112 /* configure so an HC device and id are always provided
113  * always called with process context; sleeping is OK
114  */
115 
usb_hcd_msp_map_regs(struct mspusb_device * dev)116 static int usb_hcd_msp_map_regs(struct mspusb_device *dev)
117 {
118 	struct resource *res;
119 	struct platform_device *pdev = &dev->dev;
120 	u32 res_len;
121 	int retval;
122 
123 	/* MAB register space */
124 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
125 	if (res == NULL)
126 		return -ENOMEM;
127 	res_len = res->end - res->start + 1;
128 	if (!request_mem_region(res->start, res_len, "mab regs"))
129 		return -EBUSY;
130 
131 	dev->mab_regs = ioremap_nocache(res->start, res_len);
132 	if (dev->mab_regs == NULL) {
133 		retval = -ENOMEM;
134 		goto err1;
135 	}
136 
137 	/* MSP USB register space */
138 	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
139 	if (res == NULL) {
140 		retval = -ENOMEM;
141 		goto err2;
142 	}
143 	res_len = res->end - res->start + 1;
144 	if (!request_mem_region(res->start, res_len, "usbid regs")) {
145 		retval = -EBUSY;
146 		goto err2;
147 	}
148 	dev->usbid_regs = ioremap_nocache(res->start, res_len);
149 	if (dev->usbid_regs == NULL) {
150 		retval = -ENOMEM;
151 		goto err3;
152 	}
153 
154 	return 0;
155 err3:
156 	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
157 	res_len = res->end - res->start + 1;
158 	release_mem_region(res->start, res_len);
159 err2:
160 	iounmap(dev->mab_regs);
161 err1:
162 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
163 	res_len = res->end - res->start + 1;
164 	release_mem_region(res->start, res_len);
165 	dev_err(&pdev->dev, "Failed to map non-EHCI regs.\n");
166 	return retval;
167 }
168 
169 /**
170  * usb_hcd_msp_probe - initialize PMC MSP-based HCDs
171  * Context: !in_interrupt()
172  *
173  * Allocates basic resources for this USB host controller, and
174  * then invokes the start() method for the HCD associated with it
175  * through the hotplug entry's driver_data.
176  *
177  */
usb_hcd_msp_probe(const struct hc_driver * driver,struct platform_device * dev)178 int usb_hcd_msp_probe(const struct hc_driver *driver,
179 			  struct platform_device *dev)
180 {
181 	int retval;
182 	struct usb_hcd *hcd;
183 	struct resource *res;
184 	struct ehci_hcd		*ehci ;
185 
186 	hcd = usb_create_hcd(driver, &dev->dev, "pmcmsp");
187 	if (!hcd)
188 		return -ENOMEM;
189 
190 	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
191 	if (res == NULL) {
192 		pr_debug("No IOMEM resource info for %s.\n", dev->name);
193 		retval = -ENOMEM;
194 		goto err1;
195 	}
196 	hcd->rsrc_start = res->start;
197 	hcd->rsrc_len = res->end - res->start + 1;
198 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, dev->name)) {
199 		retval = -EBUSY;
200 		goto err1;
201 	}
202 	hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
203 	if (!hcd->regs) {
204 		pr_debug("ioremap failed");
205 		retval = -ENOMEM;
206 		goto err2;
207 	}
208 
209 	res = platform_get_resource(dev, IORESOURCE_IRQ, 0);
210 	if (res == NULL) {
211 		dev_err(&dev->dev, "No IRQ resource info for %s.\n", dev->name);
212 		retval = -ENOMEM;
213 		goto err3;
214 	}
215 
216 	/* Map non-EHCI register spaces */
217 	retval = usb_hcd_msp_map_regs(to_mspusb_device(dev));
218 	if (retval != 0)
219 		goto err3;
220 
221 	ehci = hcd_to_ehci(hcd);
222 	ehci->big_endian_mmio = 1;
223 	ehci->big_endian_desc = 1;
224 
225 
226 	retval = usb_add_hcd(hcd, res->start, IRQF_SHARED);
227 	if (retval == 0)
228 		return 0;
229 
230 	usb_remove_hcd(hcd);
231 err3:
232 	iounmap(hcd->regs);
233 err2:
234 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
235 err1:
236 	usb_put_hcd(hcd);
237 
238 	return retval;
239 }
240 
241 
242 
243 /**
244  * usb_hcd_msp_remove - shutdown processing for PMC MSP-based HCDs
245  * @dev: USB Host Controller being removed
246  * Context: !in_interrupt()
247  *
248  * Reverses the effect of usb_hcd_msp_probe(), first invoking
249  * the HCD's stop() method.  It is always called from a thread
250  * context, normally "rmmod", "apmd", or something similar.
251  *
252  * may be called without controller electrically present
253  * may be called with controller, bus, and devices active
254  */
usb_hcd_msp_remove(struct usb_hcd * hcd,struct platform_device * dev)255 void usb_hcd_msp_remove(struct usb_hcd *hcd, struct platform_device *dev)
256 {
257 	usb_remove_hcd(hcd);
258 	iounmap(hcd->regs);
259 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
260 	usb_put_hcd(hcd);
261 }
262 
263 #ifdef CONFIG_MSP_HAS_DUAL_USB
264 /*
265  * Wrapper around the main ehci_irq.  Since both USB host controllers are
266  * sharing the same IRQ, need to first determine whether we're the intended
267  * recipient of this interrupt.
268  */
ehci_msp_irq(struct usb_hcd * hcd)269 static irqreturn_t ehci_msp_irq(struct usb_hcd *hcd)
270 {
271 	u32 int_src;
272 	struct device *dev = hcd->self.controller;
273 	struct platform_device *pdev;
274 	struct mspusb_device *mdev;
275 	struct ehci_hcd	*ehci = hcd_to_ehci(hcd);
276 	/* need to reverse-map a couple of containers to get our device */
277 	pdev = to_platform_device(dev);
278 	mdev = to_mspusb_device(pdev);
279 
280 	/* Check to see if this interrupt is for this host controller */
281 	int_src = ehci_readl(ehci, &mdev->mab_regs->int_stat);
282 	if (int_src & (1 << pdev->id))
283 		return ehci_irq(hcd);
284 
285 	/* Not for this device */
286 	return IRQ_NONE;
287 }
288 #endif /* DUAL_USB */
289 
290 static const struct hc_driver ehci_msp_hc_driver = {
291 	.description =		hcd_name,
292 	.product_desc =		"PMC MSP EHCI",
293 	.hcd_priv_size =	sizeof(struct ehci_hcd),
294 
295 	/*
296 	 * generic hardware linkage
297 	 */
298 #ifdef CONFIG_MSP_HAS_DUAL_USB
299 	.irq =			ehci_msp_irq,
300 #else
301 	.irq =			ehci_irq,
302 #endif
303 	.flags =		HCD_MEMORY | HCD_USB2,
304 
305 	/*
306 	 * basic lifecycle operations
307 	 */
308 	.reset =		ehci_msp_setup,
309 	.start =		ehci_run,
310 	.shutdown		= ehci_shutdown,
311 	.start			= ehci_run,
312 	.stop			= ehci_stop,
313 
314 	/*
315 	 * managing i/o requests and associated device resources
316 	 */
317 	.urb_enqueue		= ehci_urb_enqueue,
318 	.urb_dequeue		= ehci_urb_dequeue,
319 	.endpoint_disable	= ehci_endpoint_disable,
320 	.endpoint_reset		= ehci_endpoint_reset,
321 
322 	/*
323 	 * scheduling support
324 	 */
325 	.get_frame_number	= ehci_get_frame,
326 
327 	/*
328 	 * root hub support
329 	 */
330 	.hub_status_data	= ehci_hub_status_data,
331 	.hub_control		= ehci_hub_control,
332 	.bus_suspend		= ehci_bus_suspend,
333 	.bus_resume		= ehci_bus_resume,
334 	.relinquish_port	= ehci_relinquish_port,
335 	.port_handed_over	= ehci_port_handed_over,
336 
337 	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,
338 };
339 
ehci_hcd_msp_drv_probe(struct platform_device * pdev)340 static int ehci_hcd_msp_drv_probe(struct platform_device *pdev)
341 {
342 	int ret;
343 
344 	pr_debug("In ehci_hcd_msp_drv_probe");
345 
346 	if (usb_disabled())
347 		return -ENODEV;
348 
349 	gpio_request(MSP_PIN_USB0_HOST_DEV, "USB0_HOST_DEV_GPIO");
350 #ifdef CONFIG_MSP_HAS_DUAL_USB
351 	gpio_request(MSP_PIN_USB1_HOST_DEV, "USB1_HOST_DEV_GPIO");
352 #endif
353 
354 	ret = usb_hcd_msp_probe(&ehci_msp_hc_driver, pdev);
355 
356 	return ret;
357 }
358 
ehci_hcd_msp_drv_remove(struct platform_device * pdev)359 static int ehci_hcd_msp_drv_remove(struct platform_device *pdev)
360 {
361 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
362 
363 	usb_hcd_msp_remove(hcd, pdev);
364 
365 	/* free TWI GPIO USB_HOST_DEV pin */
366 	gpio_free(MSP_PIN_USB0_HOST_DEV);
367 #ifdef CONFIG_MSP_HAS_DUAL_USB
368 	gpio_free(MSP_PIN_USB1_HOST_DEV);
369 #endif
370 
371 	return 0;
372 }
373 
374 MODULE_ALIAS("pmcmsp-ehci");
375 
376 static struct platform_driver ehci_hcd_msp_driver = {
377 	.probe		= ehci_hcd_msp_drv_probe,
378 	.remove		= ehci_hcd_msp_drv_remove,
379 	.driver		= {
380 		.name	= "pmcmsp-ehci",
381 		.owner	= THIS_MODULE,
382 	},
383 };
384