ohci-jz4740.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /*
  2. * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms of the GNU General Public License as published by the
  6. * Free Software Foundation; either version 2 of the License, or (at your
  7. * option) any later version.
  8. *
  9. * You should have received a copy of the GNU General Public License along
  10. * with this program; if not, write to the Free Software Foundation, Inc.,
  11. * 675 Mass Ave, Cambridge, MA 02139, USA.
  12. *
  13. */
  14. #include <linux/platform_device.h>
  15. #include <linux/clk.h>
  16. #include <linux/regulator/consumer.h>
  17. struct jz4740_ohci_hcd {
  18. struct ohci_hcd ohci_hcd;
  19. struct regulator *vbus;
  20. bool vbus_enabled;
  21. struct clk *clk;
  22. };
  23. static inline struct jz4740_ohci_hcd *hcd_to_jz4740_hcd(struct usb_hcd *hcd)
  24. {
  25. return (struct jz4740_ohci_hcd *)(hcd->hcd_priv);
  26. }
  27. static inline struct usb_hcd *jz4740_hcd_to_hcd(struct jz4740_ohci_hcd *jz4740_ohci)
  28. {
  29. return container_of((void *)jz4740_ohci, struct usb_hcd, hcd_priv);
  30. }
  31. static int ohci_jz4740_start(struct usb_hcd *hcd)
  32. {
  33. struct ohci_hcd *ohci = hcd_to_ohci(hcd);
  34. int ret;
  35. ret = ohci_init(ohci);
  36. if (ret < 0)
  37. return ret;
  38. ohci->num_ports = 1;
  39. ret = ohci_run(ohci);
  40. if (ret < 0) {
  41. dev_err(hcd->self.controller, "Can not start %s",
  42. hcd->self.bus_name);
  43. ohci_stop(hcd);
  44. return ret;
  45. }
  46. return 0;
  47. }
  48. static int ohci_jz4740_set_vbus_power(struct jz4740_ohci_hcd *jz4740_ohci,
  49. bool enabled)
  50. {
  51. int ret = 0;
  52. if (!jz4740_ohci->vbus)
  53. return 0;
  54. if (enabled && !jz4740_ohci->vbus_enabled) {
  55. ret = regulator_enable(jz4740_ohci->vbus);
  56. if (ret)
  57. dev_err(jz4740_hcd_to_hcd(jz4740_ohci)->self.controller,
  58. "Could not power vbus\n");
  59. } else if (!enabled && jz4740_ohci->vbus_enabled) {
  60. ret = regulator_disable(jz4740_ohci->vbus);
  61. }
  62. if (ret == 0)
  63. jz4740_ohci->vbus_enabled = enabled;
  64. return ret;
  65. }
  66. static int ohci_jz4740_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
  67. u16 wIndex, char *buf, u16 wLength)
  68. {
  69. struct jz4740_ohci_hcd *jz4740_ohci = hcd_to_jz4740_hcd(hcd);
  70. int ret;
  71. switch (typeReq) {
  72. case SetHubFeature:
  73. if (wValue == USB_PORT_FEAT_POWER)
  74. ret = ohci_jz4740_set_vbus_power(jz4740_ohci, true);
  75. break;
  76. case ClearHubFeature:
  77. if (wValue == USB_PORT_FEAT_POWER)
  78. ret = ohci_jz4740_set_vbus_power(jz4740_ohci, false);
  79. break;
  80. }
  81. if (ret)
  82. return ret;
  83. return ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
  84. }
  85. static const struct hc_driver ohci_jz4740_hc_driver = {
  86. .description = hcd_name,
  87. .product_desc = "JZ4740 OHCI",
  88. .hcd_priv_size = sizeof(struct jz4740_ohci_hcd),
  89. /*
  90. * generic hardware linkage
  91. */
  92. .irq = ohci_irq,
  93. .flags = HCD_USB11 | HCD_MEMORY,
  94. /*
  95. * basic lifecycle operations
  96. */
  97. .start = ohci_jz4740_start,
  98. .stop = ohci_stop,
  99. .shutdown = ohci_shutdown,
  100. /*
  101. * managing i/o requests and associated device resources
  102. */
  103. .urb_enqueue = ohci_urb_enqueue,
  104. .urb_dequeue = ohci_urb_dequeue,
  105. .endpoint_disable = ohci_endpoint_disable,
  106. /*
  107. * scheduling support
  108. */
  109. .get_frame_number = ohci_get_frame,
  110. /*
  111. * root hub support
  112. */
  113. .hub_status_data = ohci_hub_status_data,
  114. .hub_control = ohci_jz4740_hub_control,
  115. #ifdef CONFIG_PM
  116. .bus_suspend = ohci_bus_suspend,
  117. .bus_resume = ohci_bus_resume,
  118. #endif
  119. .start_port_reset = ohci_start_port_reset,
  120. };
  121. static __devinit int jz4740_ohci_probe(struct platform_device *pdev)
  122. {
  123. int ret;
  124. struct usb_hcd *hcd;
  125. struct jz4740_ohci_hcd *jz4740_ohci;
  126. struct resource *res;
  127. int irq;
  128. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  129. if (!res) {
  130. dev_err(&pdev->dev, "Failed to get platform resource\n");
  131. return -ENOENT;
  132. }
  133. irq = platform_get_irq(pdev, 0);
  134. if (irq < 0) {
  135. dev_err(&pdev->dev, "Failed to get platform irq\n");
  136. return irq;
  137. }
  138. hcd = usb_create_hcd(&ohci_jz4740_hc_driver, &pdev->dev, "jz4740");
  139. if (!hcd) {
  140. dev_err(&pdev->dev, "Failed to create hcd.\n");
  141. return -ENOMEM;
  142. }
  143. jz4740_ohci = hcd_to_jz4740_hcd(hcd);
  144. res = request_mem_region(res->start, resource_size(res), hcd_name);
  145. if (!res) {
  146. dev_err(&pdev->dev, "Failed to request mem region.\n");
  147. ret = -EBUSY;
  148. goto err_free;
  149. }
  150. hcd->rsrc_start = res->start;
  151. hcd->rsrc_len = resource_size(res);
  152. hcd->regs = ioremap(res->start, resource_size(res));
  153. if (!hcd->regs) {
  154. dev_err(&pdev->dev, "Failed to ioremap registers.\n");
  155. ret = -EBUSY;
  156. goto err_release_mem;
  157. }
  158. jz4740_ohci->clk = clk_get(&pdev->dev, "uhc");
  159. if (IS_ERR(jz4740_ohci->clk)) {
  160. ret = PTR_ERR(jz4740_ohci->clk);
  161. dev_err(&pdev->dev, "Failed to get clock: %d\n", ret);
  162. goto err_iounmap;
  163. }
  164. jz4740_ohci->vbus = regulator_get(&pdev->dev, "vbus");
  165. if (IS_ERR(jz4740_ohci->vbus))
  166. jz4740_ohci->vbus = NULL;
  167. clk_set_rate(jz4740_ohci->clk, 48000000);
  168. clk_enable(jz4740_ohci->clk);
  169. if (jz4740_ohci->vbus)
  170. ohci_jz4740_set_vbus_power(jz4740_ohci, true);
  171. platform_set_drvdata(pdev, hcd);
  172. ohci_hcd_init(hcd_to_ohci(hcd));
  173. ret = usb_add_hcd(hcd, irq, 0);
  174. if (ret) {
  175. dev_err(&pdev->dev, "Failed to add hcd: %d\n", ret);
  176. goto err_disable;
  177. }
  178. return 0;
  179. err_disable:
  180. platform_set_drvdata(pdev, NULL);
  181. if (jz4740_ohci->vbus) {
  182. regulator_disable(jz4740_ohci->vbus);
  183. regulator_put(jz4740_ohci->vbus);
  184. }
  185. clk_disable(jz4740_ohci->clk);
  186. clk_put(jz4740_ohci->clk);
  187. err_iounmap:
  188. iounmap(hcd->regs);
  189. err_release_mem:
  190. release_mem_region(res->start, resource_size(res));
  191. err_free:
  192. usb_put_hcd(hcd);
  193. return ret;
  194. }
  195. static __devexit int jz4740_ohci_remove(struct platform_device *pdev)
  196. {
  197. struct usb_hcd *hcd = platform_get_drvdata(pdev);
  198. struct jz4740_ohci_hcd *jz4740_ohci = hcd_to_jz4740_hcd(hcd);
  199. usb_remove_hcd(hcd);
  200. platform_set_drvdata(pdev, NULL);
  201. if (jz4740_ohci->vbus) {
  202. regulator_disable(jz4740_ohci->vbus);
  203. regulator_put(jz4740_ohci->vbus);
  204. }
  205. clk_disable(jz4740_ohci->clk);
  206. clk_put(jz4740_ohci->clk);
  207. iounmap(hcd->regs);
  208. release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
  209. usb_put_hcd(hcd);
  210. return 0;
  211. }
  212. static struct platform_driver ohci_hcd_jz4740_driver = {
  213. .probe = jz4740_ohci_probe,
  214. .remove = __devexit_p(jz4740_ohci_remove),
  215. .driver = {
  216. .name = "jz4740-ohci",
  217. .owner = THIS_MODULE,
  218. },
  219. };
  220. MODULE_ALIAS("platform:jz4740-ohci");