c2k_sdio_platform.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. #include <mach/mt_c2k_sdio.h>
  2. #include <linux/interrupt.h>
  3. #include <linux/of_irq.h>
  4. #include <linux/of_address.h>
  5. static pm_callback_t via_sdio_pm_cb;
  6. static void *via_sdio_pm_data;
  7. void c2k_sdio_register_pm(pm_callback_t pm_cb, void *data)
  8. {
  9. pr_info("c2k_sdio_register_pm (0x%p, 0x%p)\n", pm_cb, data);
  10. /* register pm change callback */
  11. via_sdio_pm_cb = pm_cb;
  12. via_sdio_pm_data = data;
  13. }
  14. #ifndef C2K_USE_EINT
  15. #define C2K_USE_EINT
  16. #endif
  17. #ifdef C2K_USE_EINT
  18. static int c2k_sdio_eirq_num = 262;
  19. static sdio_irq_handler_t *c2k_sdio_eirq_handler;
  20. static void *c2k_sdio_eirq_data;
  21. /*static int interrupt_count_c2k;*/
  22. static atomic_t irq_installed;
  23. DEFINE_SPINLOCK(irq_en_lock);
  24. static int irq_enabled = 0;
  25. void c2k_sdio_enable_eirq(void)
  26. {
  27. unsigned long flags;
  28. spin_lock_irqsave(&irq_en_lock, flags);
  29. /*pr_info("[C2K] interrupt enable from %ps\n", __builtin_return_address(0));*/
  30. if (atomic_read(&irq_installed) && !irq_enabled) {
  31. enable_irq(c2k_sdio_eirq_num);
  32. irq_enabled = 1;
  33. }
  34. spin_unlock_irqrestore(&irq_en_lock, flags);
  35. }
  36. void c2k_sdio_disable_eirq(void)
  37. {
  38. unsigned long flags;
  39. spin_lock_irqsave(&irq_en_lock, flags);
  40. /*pr_info("[C2K] interrupt disable from %ps\n", __builtin_return_address(0));*/
  41. if (atomic_read(&irq_installed) && irq_enabled) {
  42. disable_irq_nosync(c2k_sdio_eirq_num);
  43. irq_enabled = 0;
  44. }
  45. spin_unlock_irqrestore(&irq_en_lock, flags);
  46. }
  47. static irqreturn_t c2k_sdio_eirq_handler_stub(int irq, void *data)
  48. {
  49. /*pr_info("[C2K] interrupt %d\n", interrupt_count_c2k++);*/
  50. if (atomic_read(&irq_installed) && c2k_sdio_eirq_handler)
  51. c2k_sdio_eirq_handler(c2k_sdio_eirq_data);
  52. return IRQ_HANDLED;
  53. }
  54. void c2k_sdio_request_eirq(sdio_irq_handler_t irq_handler, void *data)
  55. {
  56. pr_info("[C2K] request interrupt %d from %ps\n", c2k_sdio_eirq_num, __builtin_return_address(0));
  57. /*
  58. ret = request_irq(c2k_sdio_eirq_num, c2k_sdio_eirq_handler_stub, IRQF_TRIGGER_LOW, "C2K_CCCI", NULL);
  59. disable_irq(c2k_sdio_eirq_num);
  60. */
  61. c2k_sdio_eirq_handler = irq_handler;
  62. c2k_sdio_eirq_data = data;
  63. }
  64. void c2k_sdio_install_eirq(void)
  65. {
  66. int ret, irq_num;
  67. struct device_node *node = NULL;
  68. node = of_find_node_by_name(NULL, "c2k_sdio");
  69. if (node) {
  70. /* get IRQ ID */
  71. irq_num = irq_of_parse_and_map(node, 0);
  72. c2k_sdio_eirq_num = irq_num;
  73. } else {
  74. pr_err("c2k no device node\n");
  75. return;
  76. }
  77. atomic_set(&irq_installed, 1);
  78. pr_info("[C2K] interrupt install start from %ps, irq num = %d(%d)\n", __builtin_return_address(0),
  79. irq_num, c2k_sdio_eirq_num);
  80. ret = request_irq(irq_num, c2k_sdio_eirq_handler_stub, 0, "C2K_CCCI", NULL);
  81. pr_info("[C2K] interrupt install(%d) from %ps\n", ret, __builtin_return_address(0));
  82. if (!ret)
  83. disable_irq(c2k_sdio_eirq_num);
  84. else
  85. atomic_set(&irq_installed, 0);
  86. }
  87. void c2k_sdio_uninstall_eirq(void)
  88. {
  89. pr_info("[C2K] interrupt uninstall from %ps\n", __builtin_return_address(0));
  90. atomic_set(&irq_installed, 0);
  91. free_irq(c2k_sdio_eirq_num, NULL);
  92. }
  93. #else
  94. void c2k_sdio_install_eirq(void)
  95. {
  96. pr_info("[C2K] skip install: not eirq\n");
  97. }
  98. void c2k_sdio_uninstall_eirq(void)
  99. {
  100. pr_info("[C2K] skip uninstall: not eirq\n");
  101. }
  102. #endif
  103. void via_sdio_on(int sdio_port_num)
  104. {
  105. pm_message_t state = { .event = PM_EVENT_USER_RESUME };
  106. pr_info("via_sdio_on (%d)\n", sdio_port_num);
  107. /* 1. disable sdio eirq */
  108. /* 2. call sd callback */
  109. if (via_sdio_pm_cb)
  110. via_sdio_pm_cb(state, via_sdio_pm_data);
  111. else
  112. pr_warn("via_sdio_on no sd callback!!\n");
  113. }
  114. EXPORT_SYMBOL(via_sdio_on);
  115. void via_sdio_off(int sdio_port_num)
  116. {
  117. pm_message_t state = {.event = PM_EVENT_USER_SUSPEND};
  118. pr_info("via_sdio_off (%d)\n", sdio_port_num);
  119. /* 0. disable sdio eirq */
  120. #ifdef C2K_USE_EINT
  121. c2k_sdio_disable_eirq();
  122. #endif
  123. /* 1. call sd callback */
  124. if (via_sdio_pm_cb)
  125. via_sdio_pm_cb(state, via_sdio_pm_data);
  126. else
  127. pr_warn("via_sdio_off no sd callback!!\n");
  128. }
  129. EXPORT_SYMBOL(via_sdio_off);