ehci-pmcmsp.c 8.6 KB

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