adm5120-drv.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /*
  2. * ADM5120 HCD (Host Controller Driver) for USB
  3. *
  4. * Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org>
  5. *
  6. * This file was derived from: drivers/usb/host/ohci-au1xxx.c
  7. * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
  8. * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
  9. * (C) Copyright 2002 Hewlett-Packard Company
  10. *
  11. * Written by Christopher Hoover <ch@hpl.hp.com>
  12. * Based on fragments of previous driver by Russell King et al.
  13. *
  14. * Modified for LH7A404 from ahcd-sa1111.c
  15. * by Durgesh Pattamatta <pattamattad@sharpsec.com>
  16. * Modified for AMD Alchemy Au1xxx
  17. * by Matt Porter <mporter@kernel.crashing.org>
  18. *
  19. * This program is free software; you can redistribute it and/or modify it
  20. * under the terms of the GNU General Public License version 2 as published
  21. * by the Free Software Foundation.
  22. *
  23. */
  24. #include <linux/platform_device.h>
  25. #include <linux/signal.h>
  26. #include <asm/bootinfo.h>
  27. #include <asm/mach-adm5120/adm5120_defs.h>
  28. #ifdef DEBUG
  29. #define HCD_DBG(f, a...) printk(KERN_DEBUG "%s: " f, hcd_name, ## a)
  30. #else
  31. #define HCD_DBG(f, a...) do {} while (0)
  32. #endif
  33. #define HCD_ERR(f, a...) printk(KERN_ERR "%s: " f, hcd_name, ## a)
  34. #define HCD_INFO(f, a...) printk(KERN_INFO "%s: " f, hcd_name, ## a)
  35. /*-------------------------------------------------------------------------*/
  36. static int admhc_adm5120_probe(const struct hc_driver *driver,
  37. struct platform_device *dev)
  38. {
  39. int retval;
  40. struct usb_hcd *hcd;
  41. int irq;
  42. struct resource *regs;
  43. /* sanity checks */
  44. regs = platform_get_resource(dev, IORESOURCE_MEM, 0);
  45. if (!regs) {
  46. HCD_DBG("no IOMEM resource found\n");
  47. return -ENODEV;
  48. }
  49. irq = platform_get_irq(dev, 0);
  50. if (irq < 0) {
  51. HCD_DBG("no IRQ resource found\n");
  52. return -ENODEV;
  53. }
  54. hcd = usb_create_hcd(driver, &dev->dev, "ADM5120");
  55. if (!hcd)
  56. return -ENOMEM;
  57. hcd->rsrc_start = regs->start;
  58. hcd->rsrc_len = regs->end - regs->start + 1;
  59. if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
  60. HCD_DBG("request_mem_region failed\n");
  61. retval = -EBUSY;
  62. goto err_dev;
  63. }
  64. hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
  65. if (!hcd->regs) {
  66. HCD_DBG("ioremap failed\n");
  67. retval = -ENOMEM;
  68. goto err_mem;
  69. }
  70. admhc_hcd_init(hcd_to_admhcd(hcd));
  71. retval = usb_add_hcd(hcd, irq, 0);
  72. if (retval)
  73. goto err_io;
  74. return 0;
  75. err_io:
  76. iounmap(hcd->regs);
  77. err_mem:
  78. release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
  79. err_dev:
  80. usb_put_hcd(hcd);
  81. return retval;
  82. }
  83. /* may be called without controller electrically present */
  84. /* may be called with controller, bus, and devices active */
  85. static void admhc_adm5120_remove(struct usb_hcd *hcd,
  86. struct platform_device *dev)
  87. {
  88. usb_remove_hcd(hcd);
  89. iounmap(hcd->regs);
  90. release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
  91. usb_put_hcd(hcd);
  92. }
  93. static int admhc_adm5120_start(struct usb_hcd *hcd)
  94. {
  95. struct admhcd *ahcd = hcd_to_admhcd(hcd);
  96. int ret;
  97. ret = admhc_init(ahcd);
  98. if (ret < 0) {
  99. HCD_ERR("unable to init %s\n", hcd->self.bus_name);
  100. goto err;
  101. }
  102. ret = admhc_run(ahcd);
  103. if (ret < 0) {
  104. HCD_ERR("unable to run %s\n", hcd->self.bus_name);
  105. goto err_stop;
  106. }
  107. return 0;
  108. err_stop:
  109. admhc_stop(hcd);
  110. err:
  111. return ret;
  112. }
  113. static const struct hc_driver adm5120_hc_driver = {
  114. .description = hcd_name,
  115. .product_desc = "ADM5120 built-in USB 1.1 Host Controller",
  116. .hcd_priv_size = sizeof(struct admhcd),
  117. /*
  118. * generic hardware linkage
  119. */
  120. .irq = admhc_irq,
  121. .flags = HCD_USB11 | HCD_MEMORY,
  122. /*
  123. * basic lifecycle operations
  124. */
  125. .start = admhc_adm5120_start,
  126. .stop = admhc_stop,
  127. .shutdown = admhc_shutdown,
  128. /*
  129. * managing i/o requests and associated device resources
  130. */
  131. .urb_enqueue = admhc_urb_enqueue,
  132. .urb_dequeue = admhc_urb_dequeue,
  133. .endpoint_disable = admhc_endpoint_disable,
  134. /*
  135. * scheduling support
  136. */
  137. .get_frame_number = admhc_get_frame_number,
  138. /*
  139. * root hub support
  140. */
  141. .hub_status_data = admhc_hub_status_data,
  142. .hub_control = admhc_hub_control,
  143. #ifdef CONFIG_PM
  144. .bus_suspend = admhc_bus_suspend,
  145. .bus_resume = admhc_bus_resume,
  146. #endif
  147. .start_port_reset = admhc_start_port_reset,
  148. };
  149. static int usb_hcd_adm5120_probe(struct platform_device *pdev)
  150. {
  151. int ret;
  152. ret = admhc_adm5120_probe(&adm5120_hc_driver, pdev);
  153. return ret;
  154. }
  155. static int usb_hcd_adm5120_remove(struct platform_device *pdev)
  156. {
  157. struct usb_hcd *hcd = platform_get_drvdata(pdev);
  158. admhc_adm5120_remove(hcd, pdev);
  159. return 0;
  160. }
  161. #ifdef CONFIG_PM
  162. /* TODO */
  163. static int usb_hcd_adm5120_suspend(struct platform_device *dev)
  164. {
  165. struct usb_hcd *hcd = platform_get_drvdata(dev);
  166. return 0;
  167. }
  168. static int usb_hcd_adm5120_resume(struct platform_device *dev)
  169. {
  170. struct usb_hcd *hcd = platform_get_drvdata(dev);
  171. return 0;
  172. }
  173. #else
  174. #define usb_hcd_adm5120_suspend NULL
  175. #define usb_hcd_adm5120_resume NULL
  176. #endif /* CONFIG_PM */
  177. static struct platform_driver usb_hcd_adm5120_driver = {
  178. .probe = usb_hcd_adm5120_probe,
  179. .remove = usb_hcd_adm5120_remove,
  180. .shutdown = usb_hcd_platform_shutdown,
  181. .suspend = usb_hcd_adm5120_suspend,
  182. .resume = usb_hcd_adm5120_resume,
  183. .driver = {
  184. .name = "adm5120-hcd",
  185. .owner = THIS_MODULE,
  186. },
  187. };