ehci-pmcmsp.c 7.5 KB

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