ehci-pmcmsp.c 8.6 KB

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