simtec-usb.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. // SPDX-License-Identifier: GPL-2.0
  2. //
  3. // Copyright 2004-2005 Simtec Electronics
  4. // Ben Dooks <[email protected]>
  5. //
  6. // http://www.simtec.co.uk/products/EB2410ITX/
  7. //
  8. // Simtec BAST and Thorcom VR1000 USB port support functions
  9. #define DEBUG
  10. #include <linux/kernel.h>
  11. #include <linux/types.h>
  12. #include <linux/interrupt.h>
  13. #include <linux/list.h>
  14. #include <linux/gpio.h>
  15. #include <linux/timer.h>
  16. #include <linux/init.h>
  17. #include <linux/device.h>
  18. #include <linux/io.h>
  19. #include <asm/mach/arch.h>
  20. #include <asm/mach/map.h>
  21. #include <asm/mach/irq.h>
  22. #include "gpio-samsung.h"
  23. #include "irqs.h"
  24. #include <asm/irq.h>
  25. #include <linux/platform_data/usb-ohci-s3c2410.h>
  26. #include "devs.h"
  27. #include "bast.h"
  28. #include "simtec.h"
  29. /* control power and monitor over-current events on various Simtec
  30. * designed boards.
  31. */
  32. static unsigned int power_state[2];
  33. static void
  34. usb_simtec_powercontrol(int port, int to)
  35. {
  36. pr_debug("usb_simtec_powercontrol(%d,%d)\n", port, to);
  37. power_state[port] = to;
  38. if (power_state[0] && power_state[1])
  39. gpio_set_value(S3C2410_GPB(4), 0);
  40. else
  41. gpio_set_value(S3C2410_GPB(4), 1);
  42. }
  43. static irqreturn_t
  44. usb_simtec_ocirq(int irq, void *pw)
  45. {
  46. struct s3c2410_hcd_info *info = pw;
  47. if (gpio_get_value(S3C2410_GPG(10)) == 0) {
  48. pr_debug("usb_simtec: over-current irq (oc detected)\n");
  49. s3c2410_usb_report_oc(info, 3);
  50. } else {
  51. pr_debug("usb_simtec: over-current irq (oc cleared)\n");
  52. s3c2410_usb_report_oc(info, 0);
  53. }
  54. return IRQ_HANDLED;
  55. }
  56. static void usb_simtec_enableoc(struct s3c2410_hcd_info *info, int on)
  57. {
  58. int ret;
  59. if (on) {
  60. ret = request_irq(BAST_IRQ_USBOC, usb_simtec_ocirq,
  61. IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
  62. "USB Over-current", info);
  63. if (ret != 0) {
  64. printk(KERN_ERR "failed to request usb oc irq\n");
  65. }
  66. } else {
  67. free_irq(BAST_IRQ_USBOC, info);
  68. }
  69. }
  70. static struct s3c2410_hcd_info usb_simtec_info __initdata = {
  71. .port[0] = {
  72. .flags = S3C_HCDFLG_USED
  73. },
  74. .port[1] = {
  75. .flags = S3C_HCDFLG_USED
  76. },
  77. .power_control = usb_simtec_powercontrol,
  78. .enable_oc = usb_simtec_enableoc,
  79. };
  80. int __init usb_simtec_init(void)
  81. {
  82. int ret;
  83. printk("USB Power Control, Copyright 2004 Simtec Electronics\n");
  84. ret = gpio_request(S3C2410_GPB(4), "USB power control");
  85. if (ret < 0) {
  86. pr_err("%s: failed to get GPB4\n", __func__);
  87. return ret;
  88. }
  89. ret = gpio_request(S3C2410_GPG(10), "USB overcurrent");
  90. if (ret < 0) {
  91. pr_err("%s: failed to get GPG10\n", __func__);
  92. gpio_free(S3C2410_GPB(4));
  93. return ret;
  94. }
  95. /* turn power on */
  96. gpio_direction_output(S3C2410_GPB(4), 1);
  97. gpio_direction_input(S3C2410_GPG(10));
  98. s3c_ohci_set_platdata(&usb_simtec_info);
  99. return 0;
  100. }