switch_it6633.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. #include "drv_types.h"
  2. #include <linux/sched.h>
  3. #include <linux/workqueue.h>
  4. #include <drv_debug.h>
  5. #include "hdmi_processing.h"
  6. #include "hdmi_switch.h"
  7. #include "hdmi_hpd.h"
  8. #include "gpioi2c.h"
  9. #include "hdmi_time.h"
  10. #define bSwitchDBG ((*(UINT32*)DBGCONFIG2ADDR)&DBGCFG_CECSWITCH)
  11. #ifdef __KERNEL__
  12. #ifndef CONFIG_SUPPORT_DEBUG_MESSAGE
  13. #define switchdbg(fmt,args...)
  14. #else
  15. #define switchdbg(fmt,args...) printk(bSwitchDBG?("[HS] " fmt):"", ## args)
  16. #endif
  17. #endif
  18. static struct timer_list hpd_timer;
  19. static struct work_struct hpd_wq;
  20. static UINT8 it6633_readi2c(UINT8 addr)
  21. {
  22. UINT8 val = 0;
  23. hdmi_i2c_read(addr, &val, 1);
  24. return val;
  25. }
  26. static void it6633_writei2c(UINT8 addr, UINT8 val)
  27. {
  28. hdmi_i2c_write(addr, &val, 1);
  29. }
  30. static void hpd_timer_schedule(struct timer_list *, UINT32);
  31. static BOOL bToggle = false;
  32. static BOOL bSignalCheck = false;
  33. static UINT32 hpd_status = 0;
  34. static UINT8 sw_port = 0xff;
  35. static void apply_switch_hpd(UINT32 hpd)
  36. {
  37. UINT8 byte;
  38. byte = it6633_readi2c(0x29);
  39. byte &= 0xc1;
  40. byte |= ((hpd & 0x1) << 3);
  41. byte |= ((hpd & 0x2) << 1);
  42. byte |= ((hpd & 0x4) >> 1);
  43. switchdbg("%s byte 0x%02x\n", __FUNCTION__, byte);
  44. it6633_writei2c(0x29, byte);
  45. }
  46. static void toggle_hpd(UINT8 port)
  47. {
  48. UINT8 byte;
  49. switchdbg("%s port %s\n", __FUNCTION__,
  50. port == 0 ? "A" :
  51. port == 1 ? "B" :
  52. port == 2 ? "C" : "X"
  53. );
  54. byte = it6633_readi2c(0x29);
  55. byte &= (~(1 << (3 - (unsigned char)port)));
  56. it6633_writei2c(0x29, byte);
  57. it6633_writei2c(0x04, 0x00);
  58. byte = it6633_readi2c(0x29);
  59. byte &= 0xcf;
  60. byte |= 0x20;
  61. it6633_writei2c(0x29, byte);
  62. switchdbg("delay 500 ms\n");
  63. HDMI_DelayMs(500);
  64. byte &= 0xcf;
  65. it6633_writei2c(0x29, byte);
  66. byte = 0xB0 | ((unsigned char)port << 2) | (unsigned char)port;
  67. it6633_writei2c(0x06, byte);
  68. }
  69. static void check_hpd(void *dummy)
  70. {
  71. UINT8 diff_hpd_status = 0;
  72. UINT8 local_hpd_status = 0;
  73. local_hpd_status = it6633_readi2c(0x24) & 0x7;
  74. diff_hpd_status = local_hpd_status ^ hpd_status;
  75. hpd_status = local_hpd_status;
  76. if (bToggle || diff_hpd_status)
  77. {
  78. apply_switch_hpd(hpd_status);
  79. switchdbg("sw_port 0x%02x diff_hpd_status 0x%02x\n",
  80. sw_port, diff_hpd_status);
  81. if (sw_port != 0xff &&
  82. (diff_hpd_status & hpd_status & (1 << sw_port)))
  83. {
  84. switchdbg("delay 20 ms\n");
  85. HDMI_DelayMs(20);
  86. bToggle = true;
  87. }
  88. else
  89. {
  90. hdmi_hpd_update();
  91. }
  92. }
  93. if (bToggle && sw_port != 0xff)
  94. {
  95. toggle_hpd(sw_port);
  96. bToggle = false;
  97. hdmi_hpd_update();
  98. }
  99. if (bSignalCheck)
  100. {
  101. bSignalCheck = false;
  102. hdmi_signal_check_start();
  103. }
  104. }
  105. static void HPD_TIMER(void* dummy)
  106. {
  107. /* Schedule working queue to check hpd now */
  108. schedule_work(&hpd_wq);
  109. /* Check hpd periodically */
  110. hpd_timer_schedule(&hpd_timer, 50);
  111. }
  112. static void hpd_timer_schedule(struct timer_list *timer, UINT32 ten_ms)
  113. {
  114. del_timer(timer);
  115. timer->expires = jiffies + (HZ / 100) * ten_ms; // 10ms per unit
  116. timer->data = (UINT32)NULL;
  117. timer->function = (void (*)(ULONG))HPD_TIMER;
  118. add_timer(timer);
  119. }
  120. UINT32 hdmi_switch_hpd_status(void)
  121. {
  122. /* Return switch hpd status */
  123. // bit[0] - A port
  124. // bit[1] - B port
  125. // bit[2] - C port
  126. return hpd_status;
  127. }
  128. void hdmi_switch_disable(void)
  129. {
  130. switchdbg("%s\n", __FUNCTION__);
  131. it6633_writei2c(0x04, 0x08);
  132. }
  133. void hdmi_switch_enable(INT8 port)
  134. {
  135. switchdbg("%s port %s\n", __FUNCTION__,
  136. port == 0 ? "A" :
  137. port == 1 ? "B" :
  138. port == 2 ? "C" : "unknown");
  139. if (port < 0)
  140. {
  141. sw_port = 0xff;
  142. return;
  143. }
  144. port &= 0x3;
  145. sw_port = (unsigned char)port;
  146. bToggle = true;
  147. bSignalCheck = true;
  148. hpd_timer_schedule(&hpd_timer, 0);
  149. }
  150. void hdmi_switch_init(void)
  151. {
  152. switchdbg("%s\n", __FUNCTION__);
  153. /* Setup i2c mode, device id, and address length */
  154. hdmi_i2c_setup(USE_HW_I2C_SLAVE, 0x94, 1);
  155. it6633_writei2c(0x04, 0x08);
  156. /* Init DDC 5V status */
  157. hpd_status = 0;
  158. bToggle = false;
  159. /* Schedule timer to check hpd periodically */
  160. INIT_WORK(&hpd_wq, (work_func_t)check_hpd);
  161. init_timer(&hpd_timer);
  162. /* Schedule the 2 seconds timer,
  163. it will be rescheduled when current
  164. hdmi switch source is selected */
  165. hpd_timer_schedule(&hpd_timer, 200);
  166. /* Notice hdmi driver the current hpd status */
  167. }
  168. void hdmi_switch_power(BOOL bPwr)
  169. {
  170. switchdbg("%s(%s)\n", __FUNCTION__, bPwr ? "on" : "off");
  171. }