exynos_hdmi_cecctrl.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /* drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c
  2. *
  3. * Copyright (c) 2009, 2014 Samsung Electronics
  4. * http://www.samsung.com/
  5. *
  6. * cec ftn file for Samsung TVOUT driver
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. */
  12. #include <linux/io.h>
  13. #include <linux/device.h>
  14. #include "exynos_hdmi_cec.h"
  15. #include "regs-cec.h"
  16. #define S5P_HDMI_FIN 24000000
  17. #define CEC_DIV_RATIO 320000
  18. #define CEC_MESSAGE_BROADCAST_MASK 0x0F
  19. #define CEC_MESSAGE_BROADCAST 0x0F
  20. #define CEC_FILTER_THRESHOLD 0x15
  21. void s5p_cec_set_divider(struct s5p_cec_dev *cec)
  22. {
  23. u32 div_ratio, div_val;
  24. unsigned int reg;
  25. div_ratio = S5P_HDMI_FIN / CEC_DIV_RATIO - 1;
  26. if (regmap_read(cec->pmu, EXYNOS_HDMI_PHY_CONTROL, &reg)) {
  27. dev_err(cec->dev, "failed to read phy control\n");
  28. return;
  29. }
  30. reg = (reg & ~(0x3FF << 16)) | (div_ratio << 16);
  31. if (regmap_write(cec->pmu, EXYNOS_HDMI_PHY_CONTROL, reg)) {
  32. dev_err(cec->dev, "failed to write phy control\n");
  33. return;
  34. }
  35. div_val = CEC_DIV_RATIO * 0.00005 - 1;
  36. writeb(0x0, cec->reg + S5P_CEC_DIVISOR_3);
  37. writeb(0x0, cec->reg + S5P_CEC_DIVISOR_2);
  38. writeb(0x0, cec->reg + S5P_CEC_DIVISOR_1);
  39. writeb(div_val, cec->reg + S5P_CEC_DIVISOR_0);
  40. }
  41. void s5p_cec_enable_rx(struct s5p_cec_dev *cec)
  42. {
  43. u8 reg;
  44. reg = readb(cec->reg + S5P_CEC_RX_CTRL);
  45. reg |= S5P_CEC_RX_CTRL_ENABLE;
  46. writeb(reg, cec->reg + S5P_CEC_RX_CTRL);
  47. }
  48. void s5p_cec_mask_rx_interrupts(struct s5p_cec_dev *cec)
  49. {
  50. u8 reg;
  51. reg = readb(cec->reg + S5P_CEC_IRQ_MASK);
  52. reg |= S5P_CEC_IRQ_RX_DONE;
  53. reg |= S5P_CEC_IRQ_RX_ERROR;
  54. writeb(reg, cec->reg + S5P_CEC_IRQ_MASK);
  55. }
  56. void s5p_cec_unmask_rx_interrupts(struct s5p_cec_dev *cec)
  57. {
  58. u8 reg;
  59. reg = readb(cec->reg + S5P_CEC_IRQ_MASK);
  60. reg &= ~S5P_CEC_IRQ_RX_DONE;
  61. reg &= ~S5P_CEC_IRQ_RX_ERROR;
  62. writeb(reg, cec->reg + S5P_CEC_IRQ_MASK);
  63. }
  64. void s5p_cec_mask_tx_interrupts(struct s5p_cec_dev *cec)
  65. {
  66. u8 reg;
  67. reg = readb(cec->reg + S5P_CEC_IRQ_MASK);
  68. reg |= S5P_CEC_IRQ_TX_DONE;
  69. reg |= S5P_CEC_IRQ_TX_ERROR;
  70. writeb(reg, cec->reg + S5P_CEC_IRQ_MASK);
  71. }
  72. void s5p_cec_unmask_tx_interrupts(struct s5p_cec_dev *cec)
  73. {
  74. u8 reg;
  75. reg = readb(cec->reg + S5P_CEC_IRQ_MASK);
  76. reg &= ~S5P_CEC_IRQ_TX_DONE;
  77. reg &= ~S5P_CEC_IRQ_TX_ERROR;
  78. writeb(reg, cec->reg + S5P_CEC_IRQ_MASK);
  79. }
  80. void s5p_cec_reset(struct s5p_cec_dev *cec)
  81. {
  82. u8 reg;
  83. writeb(S5P_CEC_RX_CTRL_RESET, cec->reg + S5P_CEC_RX_CTRL);
  84. writeb(S5P_CEC_TX_CTRL_RESET, cec->reg + S5P_CEC_TX_CTRL);
  85. reg = readb(cec->reg + 0xc4);
  86. reg &= ~0x1;
  87. writeb(reg, cec->reg + 0xc4);
  88. }
  89. void s5p_cec_tx_reset(struct s5p_cec_dev *cec)
  90. {
  91. writeb(S5P_CEC_TX_CTRL_RESET, cec->reg + S5P_CEC_TX_CTRL);
  92. }
  93. void s5p_cec_rx_reset(struct s5p_cec_dev *cec)
  94. {
  95. u8 reg;
  96. writeb(S5P_CEC_RX_CTRL_RESET, cec->reg + S5P_CEC_RX_CTRL);
  97. reg = readb(cec->reg + 0xc4);
  98. reg &= ~0x1;
  99. writeb(reg, cec->reg + 0xc4);
  100. }
  101. void s5p_cec_threshold(struct s5p_cec_dev *cec)
  102. {
  103. writeb(CEC_FILTER_THRESHOLD, cec->reg + S5P_CEC_RX_FILTER_TH);
  104. writeb(0, cec->reg + S5P_CEC_RX_FILTER_CTRL);
  105. }
  106. void s5p_cec_copy_packet(struct s5p_cec_dev *cec, char *data,
  107. size_t count, u8 retries)
  108. {
  109. int i = 0;
  110. u8 reg;
  111. while (i < count) {
  112. writeb(data[i], cec->reg + (S5P_CEC_TX_BUFF0 + (i * 4)));
  113. i++;
  114. }
  115. writeb(count, cec->reg + S5P_CEC_TX_BYTES);
  116. reg = readb(cec->reg + S5P_CEC_TX_CTRL);
  117. reg |= S5P_CEC_TX_CTRL_START;
  118. reg &= ~0x70;
  119. reg |= retries << 4;
  120. if ((data[0] & CEC_MESSAGE_BROADCAST_MASK) == CEC_MESSAGE_BROADCAST) {
  121. dev_dbg(cec->dev, "Broadcast");
  122. reg |= S5P_CEC_TX_CTRL_BCAST;
  123. } else {
  124. dev_dbg(cec->dev, "No Broadcast");
  125. reg &= ~S5P_CEC_TX_CTRL_BCAST;
  126. }
  127. writeb(reg, cec->reg + S5P_CEC_TX_CTRL);
  128. dev_dbg(cec->dev, "cec-tx: cec count (%zu): %*ph", count,
  129. (int)count, data);
  130. }
  131. void s5p_cec_set_addr(struct s5p_cec_dev *cec, u32 addr)
  132. {
  133. writeb(addr & 0x0F, cec->reg + S5P_CEC_LOGIC_ADDR);
  134. }
  135. u32 s5p_cec_get_status(struct s5p_cec_dev *cec)
  136. {
  137. u32 status = 0;
  138. status = readb(cec->reg + S5P_CEC_STATUS_0) & 0xf;
  139. status |= (readb(cec->reg + S5P_CEC_TX_STAT1) & 0xf) << 4;
  140. status |= readb(cec->reg + S5P_CEC_STATUS_1) << 8;
  141. status |= readb(cec->reg + S5P_CEC_STATUS_2) << 16;
  142. status |= readb(cec->reg + S5P_CEC_STATUS_3) << 24;
  143. dev_dbg(cec->dev, "status = 0x%x!\n", status);
  144. return status;
  145. }
  146. void s5p_clr_pending_tx(struct s5p_cec_dev *cec)
  147. {
  148. writeb(S5P_CEC_IRQ_TX_DONE | S5P_CEC_IRQ_TX_ERROR,
  149. cec->reg + S5P_CEC_IRQ_CLEAR);
  150. }
  151. void s5p_clr_pending_rx(struct s5p_cec_dev *cec)
  152. {
  153. writeb(S5P_CEC_IRQ_RX_DONE | S5P_CEC_IRQ_RX_ERROR,
  154. cec->reg + S5P_CEC_IRQ_CLEAR);
  155. }
  156. void s5p_cec_get_rx_buf(struct s5p_cec_dev *cec, u32 size, u8 *buffer)
  157. {
  158. u32 i = 0;
  159. char debug[40];
  160. while (i < size) {
  161. buffer[i] = readb(cec->reg + S5P_CEC_RX_BUFF0 + (i * 4));
  162. sprintf(debug + i * 2, "%02x ", buffer[i]);
  163. i++;
  164. }
  165. dev_dbg(cec->dev, "cec-rx: cec size(%d): %s", size, debug);
  166. }