mtk_cec.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /*
  2. * Copyright (c) 2014 MediaTek Inc.
  3. * Author: Jie Qiu <jie.qiu@mediatek.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #include <linux/clk.h>
  15. #include <linux/delay.h>
  16. #include <linux/io.h>
  17. #include <linux/interrupt.h>
  18. #include <linux/mod_devicetable.h>
  19. #include <linux/platform_device.h>
  20. #include "mtk_cec.h"
  21. #define TR_CONFIG 0x00
  22. #define CLEAR_CEC_IRQ BIT(15)
  23. #define CEC_CKGEN 0x04
  24. #define CEC_32K_PDN BIT(19)
  25. #define PDN BIT(16)
  26. #define RX_EVENT 0x54
  27. #define HDMI_PORD BIT(25)
  28. #define HDMI_HTPLG BIT(24)
  29. #define HDMI_PORD_INT_EN BIT(9)
  30. #define HDMI_HTPLG_INT_EN BIT(8)
  31. #define RX_GEN_WD 0x58
  32. #define HDMI_PORD_INT_32K_STATUS BIT(26)
  33. #define RX_RISC_INT_32K_STATUS BIT(25)
  34. #define HDMI_HTPLG_INT_32K_STATUS BIT(24)
  35. #define HDMI_PORD_INT_32K_CLR BIT(18)
  36. #define RX_INT_32K_CLR BIT(17)
  37. #define HDMI_HTPLG_INT_32K_CLR BIT(16)
  38. #define HDMI_PORD_INT_32K_STA_MASK BIT(10)
  39. #define RX_RISC_INT_32K_STA_MASK BIT(9)
  40. #define HDMI_HTPLG_INT_32K_STA_MASK BIT(8)
  41. #define HDMI_PORD_INT_32K_EN BIT(2)
  42. #define RX_INT_32K_EN BIT(1)
  43. #define HDMI_HTPLG_INT_32K_EN BIT(0)
  44. #define NORMAL_INT_CTRL 0x5C
  45. #define HDMI_HTPLG_INT_STA BIT(0)
  46. #define HDMI_PORD_INT_STA BIT(1)
  47. #define HDMI_HTPLG_INT_CLR BIT(16)
  48. #define HDMI_PORD_INT_CLR BIT(17)
  49. #define HDMI_FULL_INT_CLR BIT(20)
  50. struct mtk_cec {
  51. void __iomem *regs;
  52. struct clk *clk;
  53. int irq;
  54. bool hpd;
  55. void (*hpd_event)(bool hpd, struct device *dev);
  56. struct device *hdmi_dev;
  57. spinlock_t lock;
  58. };
  59. static void mtk_cec_clear_bits(struct mtk_cec *cec, unsigned int offset,
  60. unsigned int bits)
  61. {
  62. void __iomem *reg = cec->regs + offset;
  63. u32 tmp;
  64. tmp = readl(reg);
  65. tmp &= ~bits;
  66. writel(tmp, reg);
  67. }
  68. static void mtk_cec_set_bits(struct mtk_cec *cec, unsigned int offset,
  69. unsigned int bits)
  70. {
  71. void __iomem *reg = cec->regs + offset;
  72. u32 tmp;
  73. tmp = readl(reg);
  74. tmp |= bits;
  75. writel(tmp, reg);
  76. }
  77. static void mtk_cec_mask(struct mtk_cec *cec, unsigned int offset,
  78. unsigned int val, unsigned int mask)
  79. {
  80. u32 tmp = readl(cec->regs + offset) & ~mask;
  81. tmp |= val & mask;
  82. writel(val, cec->regs + offset);
  83. }
  84. void mtk_cec_set_hpd_event(struct device *dev,
  85. void (*hpd_event)(bool hpd, struct device *dev),
  86. struct device *hdmi_dev)
  87. {
  88. struct mtk_cec *cec = dev_get_drvdata(dev);
  89. unsigned long flags;
  90. spin_lock_irqsave(&cec->lock, flags);
  91. cec->hdmi_dev = hdmi_dev;
  92. cec->hpd_event = hpd_event;
  93. spin_unlock_irqrestore(&cec->lock, flags);
  94. }
  95. bool mtk_cec_hpd_high(struct device *dev)
  96. {
  97. struct mtk_cec *cec = dev_get_drvdata(dev);
  98. unsigned int status;
  99. status = readl(cec->regs + RX_EVENT);
  100. return (status & (HDMI_PORD | HDMI_HTPLG)) == (HDMI_PORD | HDMI_HTPLG);
  101. }
  102. static void mtk_cec_htplg_irq_init(struct mtk_cec *cec)
  103. {
  104. mtk_cec_mask(cec, CEC_CKGEN, 0 | CEC_32K_PDN, PDN | CEC_32K_PDN);
  105. mtk_cec_set_bits(cec, RX_GEN_WD, HDMI_PORD_INT_32K_CLR |
  106. RX_INT_32K_CLR | HDMI_HTPLG_INT_32K_CLR);
  107. mtk_cec_mask(cec, RX_GEN_WD, 0, HDMI_PORD_INT_32K_CLR | RX_INT_32K_CLR |
  108. HDMI_HTPLG_INT_32K_CLR | HDMI_PORD_INT_32K_EN |
  109. RX_INT_32K_EN | HDMI_HTPLG_INT_32K_EN);
  110. }
  111. static void mtk_cec_htplg_irq_enable(struct mtk_cec *cec)
  112. {
  113. mtk_cec_set_bits(cec, RX_EVENT, HDMI_PORD_INT_EN | HDMI_HTPLG_INT_EN);
  114. }
  115. static void mtk_cec_htplg_irq_disable(struct mtk_cec *cec)
  116. {
  117. mtk_cec_clear_bits(cec, RX_EVENT, HDMI_PORD_INT_EN | HDMI_HTPLG_INT_EN);
  118. }
  119. static void mtk_cec_clear_htplg_irq(struct mtk_cec *cec)
  120. {
  121. mtk_cec_set_bits(cec, TR_CONFIG, CLEAR_CEC_IRQ);
  122. mtk_cec_set_bits(cec, NORMAL_INT_CTRL, HDMI_HTPLG_INT_CLR |
  123. HDMI_PORD_INT_CLR | HDMI_FULL_INT_CLR);
  124. mtk_cec_set_bits(cec, RX_GEN_WD, HDMI_PORD_INT_32K_CLR |
  125. RX_INT_32K_CLR | HDMI_HTPLG_INT_32K_CLR);
  126. usleep_range(5, 10);
  127. mtk_cec_clear_bits(cec, NORMAL_INT_CTRL, HDMI_HTPLG_INT_CLR |
  128. HDMI_PORD_INT_CLR | HDMI_FULL_INT_CLR);
  129. mtk_cec_clear_bits(cec, TR_CONFIG, CLEAR_CEC_IRQ);
  130. mtk_cec_clear_bits(cec, RX_GEN_WD, HDMI_PORD_INT_32K_CLR |
  131. RX_INT_32K_CLR | HDMI_HTPLG_INT_32K_CLR);
  132. }
  133. static void mtk_cec_hpd_event(struct mtk_cec *cec, bool hpd)
  134. {
  135. void (*hpd_event)(bool hpd, struct device *dev);
  136. struct device *hdmi_dev;
  137. unsigned long flags;
  138. spin_lock_irqsave(&cec->lock, flags);
  139. hpd_event = cec->hpd_event;
  140. hdmi_dev = cec->hdmi_dev;
  141. spin_unlock_irqrestore(&cec->lock, flags);
  142. if (hpd_event)
  143. hpd_event(hpd, hdmi_dev);
  144. }
  145. static irqreturn_t mtk_cec_htplg_isr_thread(int irq, void *arg)
  146. {
  147. struct device *dev = arg;
  148. struct mtk_cec *cec = dev_get_drvdata(dev);
  149. bool hpd;
  150. mtk_cec_clear_htplg_irq(cec);
  151. hpd = mtk_cec_hpd_high(dev);
  152. if (cec->hpd != hpd) {
  153. dev_dbg(dev, "hotplug event! cur hpd = %d, hpd = %d\n",
  154. cec->hpd, hpd);
  155. cec->hpd = hpd;
  156. mtk_cec_hpd_event(cec, hpd);
  157. }
  158. return IRQ_HANDLED;
  159. }
  160. static int mtk_cec_probe(struct platform_device *pdev)
  161. {
  162. struct device *dev = &pdev->dev;
  163. struct mtk_cec *cec;
  164. struct resource *res;
  165. int ret;
  166. cec = devm_kzalloc(dev, sizeof(*cec), GFP_KERNEL);
  167. if (!cec)
  168. return -ENOMEM;
  169. platform_set_drvdata(pdev, cec);
  170. spin_lock_init(&cec->lock);
  171. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  172. cec->regs = devm_ioremap_resource(dev, res);
  173. if (IS_ERR(cec->regs)) {
  174. ret = PTR_ERR(cec->regs);
  175. dev_err(dev, "Failed to ioremap cec: %d\n", ret);
  176. return ret;
  177. }
  178. cec->clk = devm_clk_get(dev, NULL);
  179. if (IS_ERR(cec->clk)) {
  180. ret = PTR_ERR(cec->clk);
  181. dev_err(dev, "Failed to get cec clock: %d\n", ret);
  182. return ret;
  183. }
  184. cec->irq = platform_get_irq(pdev, 0);
  185. if (cec->irq < 0) {
  186. dev_err(dev, "Failed to get cec irq: %d\n", cec->irq);
  187. return cec->irq;
  188. }
  189. ret = devm_request_threaded_irq(dev, cec->irq, NULL,
  190. mtk_cec_htplg_isr_thread,
  191. IRQF_SHARED | IRQF_TRIGGER_LOW |
  192. IRQF_ONESHOT, "hdmi hpd", dev);
  193. if (ret) {
  194. dev_err(dev, "Failed to register cec irq: %d\n", ret);
  195. return ret;
  196. }
  197. ret = clk_prepare_enable(cec->clk);
  198. if (ret) {
  199. dev_err(dev, "Failed to enable cec clock: %d\n", ret);
  200. return ret;
  201. }
  202. mtk_cec_htplg_irq_init(cec);
  203. mtk_cec_htplg_irq_enable(cec);
  204. return 0;
  205. }
  206. static int mtk_cec_remove(struct platform_device *pdev)
  207. {
  208. struct mtk_cec *cec = platform_get_drvdata(pdev);
  209. mtk_cec_htplg_irq_disable(cec);
  210. clk_disable_unprepare(cec->clk);
  211. return 0;
  212. }
  213. static const struct of_device_id mtk_cec_of_ids[] = {
  214. { .compatible = "mediatek,mt8173-cec", },
  215. {}
  216. };
  217. struct platform_driver mtk_cec_driver = {
  218. .probe = mtk_cec_probe,
  219. .remove = mtk_cec_remove,
  220. .driver = {
  221. .name = "mediatek-cec",
  222. .of_match_table = mtk_cec_of_ids,
  223. },
  224. };