ehci-atmel.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /*
  2. * Driver for EHCI UHP on Atmel chips
  3. *
  4. * Copyright (C) 2009 Atmel Corporation,
  5. * Nicolas Ferre <nicolas.ferre@atmel.com>
  6. *
  7. * Based on various ehci-*.c drivers
  8. *
  9. * This file is subject to the terms and conditions of the GNU General Public
  10. * License. See the file COPYING in the main directory of this archive for
  11. * more details.
  12. */
  13. #include <linux/clk.h>
  14. #include <linux/dma-mapping.h>
  15. #include <linux/io.h>
  16. #include <linux/kernel.h>
  17. #include <linux/module.h>
  18. #include <linux/of.h>
  19. #include <linux/of_platform.h>
  20. #include <linux/platform_device.h>
  21. #include <linux/usb.h>
  22. #include <linux/usb/hcd.h>
  23. #include "ehci.h"
  24. #define DRIVER_DESC "EHCI Atmel driver"
  25. static const char hcd_name[] = "ehci-atmel";
  26. static struct hc_driver __read_mostly ehci_atmel_hc_driver;
  27. /* interface and function clocks */
  28. static struct clk *iclk, *fclk;
  29. static int clocked;
  30. /*-------------------------------------------------------------------------*/
  31. static void atmel_start_clock(void)
  32. {
  33. clk_enable(iclk);
  34. clk_enable(fclk);
  35. clocked = 1;
  36. }
  37. static void atmel_stop_clock(void)
  38. {
  39. clk_disable(fclk);
  40. clk_disable(iclk);
  41. clocked = 0;
  42. }
  43. static void atmel_start_ehci(struct platform_device *pdev)
  44. {
  45. dev_dbg(&pdev->dev, "start\n");
  46. atmel_start_clock();
  47. }
  48. static void atmel_stop_ehci(struct platform_device *pdev)
  49. {
  50. dev_dbg(&pdev->dev, "stop\n");
  51. atmel_stop_clock();
  52. }
  53. /*-------------------------------------------------------------------------*/
  54. static u64 at91_ehci_dma_mask = DMA_BIT_MASK(32);
  55. static int ehci_atmel_drv_probe(struct platform_device *pdev)
  56. {
  57. struct usb_hcd *hcd;
  58. const struct hc_driver *driver = &ehci_atmel_hc_driver;
  59. struct resource *res;
  60. struct ehci_hcd *ehci;
  61. int irq;
  62. int retval;
  63. if (usb_disabled())
  64. return -ENODEV;
  65. pr_debug("Initializing Atmel-SoC USB Host Controller\n");
  66. irq = platform_get_irq(pdev, 0);
  67. if (irq <= 0) {
  68. dev_err(&pdev->dev,
  69. "Found HC with no IRQ. Check %s setup!\n",
  70. dev_name(&pdev->dev));
  71. retval = -ENODEV;
  72. goto fail_create_hcd;
  73. }
  74. /* Right now device-tree probed devices don't get dma_mask set.
  75. * Since shared usb code relies on it, set it here for now.
  76. * Once we have dma capability bindings this can go away.
  77. */
  78. if (!pdev->dev.dma_mask)
  79. pdev->dev.dma_mask = &at91_ehci_dma_mask;
  80. hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
  81. if (!hcd) {
  82. retval = -ENOMEM;
  83. goto fail_create_hcd;
  84. }
  85. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  86. if (!res) {
  87. dev_err(&pdev->dev,
  88. "Found HC with no register addr. Check %s setup!\n",
  89. dev_name(&pdev->dev));
  90. retval = -ENODEV;
  91. goto fail_request_resource;
  92. }
  93. hcd->rsrc_start = res->start;
  94. hcd->rsrc_len = resource_size(res);
  95. hcd->regs = devm_ioremap_resource(&pdev->dev, res);
  96. if (IS_ERR(hcd->regs)) {
  97. retval = PTR_ERR(hcd->regs);
  98. goto fail_request_resource;
  99. }
  100. iclk = devm_clk_get(&pdev->dev, "ehci_clk");
  101. if (IS_ERR(iclk)) {
  102. dev_err(&pdev->dev, "Error getting interface clock\n");
  103. retval = -ENOENT;
  104. goto fail_request_resource;
  105. }
  106. fclk = devm_clk_get(&pdev->dev, "uhpck");
  107. if (IS_ERR(fclk)) {
  108. dev_err(&pdev->dev, "Error getting function clock\n");
  109. retval = -ENOENT;
  110. goto fail_request_resource;
  111. }
  112. ehci = hcd_to_ehci(hcd);
  113. /* registers start at offset 0x0 */
  114. ehci->caps = hcd->regs;
  115. atmel_start_ehci(pdev);
  116. retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
  117. if (retval)
  118. goto fail_add_hcd;
  119. return retval;
  120. fail_add_hcd:
  121. atmel_stop_ehci(pdev);
  122. fail_request_resource:
  123. usb_put_hcd(hcd);
  124. fail_create_hcd:
  125. dev_err(&pdev->dev, "init %s fail, %d\n",
  126. dev_name(&pdev->dev), retval);
  127. return retval;
  128. }
  129. static int ehci_atmel_drv_remove(struct platform_device *pdev)
  130. {
  131. struct usb_hcd *hcd = platform_get_drvdata(pdev);
  132. usb_remove_hcd(hcd);
  133. usb_put_hcd(hcd);
  134. atmel_stop_ehci(pdev);
  135. fclk = iclk = NULL;
  136. return 0;
  137. }
  138. #ifdef CONFIG_OF
  139. static const struct of_device_id atmel_ehci_dt_ids[] = {
  140. { .compatible = "atmel,at91sam9g45-ehci" },
  141. { /* sentinel */ }
  142. };
  143. MODULE_DEVICE_TABLE(of, atmel_ehci_dt_ids);
  144. #endif
  145. static struct platform_driver ehci_atmel_driver = {
  146. .probe = ehci_atmel_drv_probe,
  147. .remove = ehci_atmel_drv_remove,
  148. .shutdown = usb_hcd_platform_shutdown,
  149. .driver = {
  150. .name = "atmel-ehci",
  151. .of_match_table = of_match_ptr(atmel_ehci_dt_ids),
  152. },
  153. };
  154. static int __init ehci_atmel_init(void)
  155. {
  156. if (usb_disabled())
  157. return -ENODEV;
  158. pr_info("%s: " DRIVER_DESC "\n", hcd_name);
  159. ehci_init_driver(&ehci_atmel_hc_driver, NULL);
  160. return platform_driver_register(&ehci_atmel_driver);
  161. }
  162. module_init(ehci_atmel_init);
  163. static void __exit ehci_atmel_cleanup(void)
  164. {
  165. platform_driver_unregister(&ehci_atmel_driver);
  166. }
  167. module_exit(ehci_atmel_cleanup);
  168. MODULE_DESCRIPTION(DRIVER_DESC);
  169. MODULE_ALIAS("platform:atmel-ehci");
  170. MODULE_AUTHOR("Nicolas Ferre");
  171. MODULE_LICENSE("GPL");