1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2014 MediaTek Inc.
4 * Author: Jie Qiu <jie.qiu@mediatek.com>
7 #include <linux/delay.h>
9 #include <linux/interrupt.h>
10 #include <linux/mod_devicetable.h>
11 #include <linux/platform_device.h>
15 #define TR_CONFIG 0x00
16 #define CLEAR_CEC_IRQ BIT(15)
18 #define CEC_CKGEN 0x04
19 #define CEC_32K_PDN BIT(19)
23 #define HDMI_PORD BIT(25)
24 #define HDMI_HTPLG BIT(24)
25 #define HDMI_PORD_INT_EN BIT(9)
26 #define HDMI_HTPLG_INT_EN BIT(8)
28 #define RX_GEN_WD 0x58
29 #define HDMI_PORD_INT_32K_STATUS BIT(26)
30 #define RX_RISC_INT_32K_STATUS BIT(25)
31 #define HDMI_HTPLG_INT_32K_STATUS BIT(24)
32 #define HDMI_PORD_INT_32K_CLR BIT(18)
33 #define RX_INT_32K_CLR BIT(17)
34 #define HDMI_HTPLG_INT_32K_CLR BIT(16)
35 #define HDMI_PORD_INT_32K_STA_MASK BIT(10)
36 #define RX_RISC_INT_32K_STA_MASK BIT(9)
37 #define HDMI_HTPLG_INT_32K_STA_MASK BIT(8)
38 #define HDMI_PORD_INT_32K_EN BIT(2)
39 #define RX_INT_32K_EN BIT(1)
40 #define HDMI_HTPLG_INT_32K_EN BIT(0)
42 #define NORMAL_INT_CTRL 0x5C
43 #define HDMI_HTPLG_INT_STA BIT(0)
44 #define HDMI_PORD_INT_STA BIT(1)
45 #define HDMI_HTPLG_INT_CLR BIT(16)
46 #define HDMI_PORD_INT_CLR BIT(17)
47 #define HDMI_FULL_INT_CLR BIT(20)
54 void (*hpd_event
)(bool hpd
, struct device
*dev
);
55 struct device
*hdmi_dev
;
59 static void mtk_cec_clear_bits(struct mtk_cec
*cec
, unsigned int offset
,
62 void __iomem
*reg
= cec
->regs
+ offset
;
70 static void mtk_cec_set_bits(struct mtk_cec
*cec
, unsigned int offset
,
73 void __iomem
*reg
= cec
->regs
+ offset
;
81 static void mtk_cec_mask(struct mtk_cec
*cec
, unsigned int offset
,
82 unsigned int val
, unsigned int mask
)
84 u32 tmp
= readl(cec
->regs
+ offset
) & ~mask
;
87 writel(val
, cec
->regs
+ offset
);
90 void mtk_cec_set_hpd_event(struct device
*dev
,
91 void (*hpd_event
)(bool hpd
, struct device
*dev
),
92 struct device
*hdmi_dev
)
94 struct mtk_cec
*cec
= dev_get_drvdata(dev
);
97 spin_lock_irqsave(&cec
->lock
, flags
);
98 cec
->hdmi_dev
= hdmi_dev
;
99 cec
->hpd_event
= hpd_event
;
100 spin_unlock_irqrestore(&cec
->lock
, flags
);
103 bool mtk_cec_hpd_high(struct device
*dev
)
105 struct mtk_cec
*cec
= dev_get_drvdata(dev
);
108 status
= readl(cec
->regs
+ RX_EVENT
);
110 return (status
& (HDMI_PORD
| HDMI_HTPLG
)) == (HDMI_PORD
| HDMI_HTPLG
);
113 static void mtk_cec_htplg_irq_init(struct mtk_cec
*cec
)
115 mtk_cec_mask(cec
, CEC_CKGEN
, 0 | CEC_32K_PDN
, PDN
| CEC_32K_PDN
);
116 mtk_cec_set_bits(cec
, RX_GEN_WD
, HDMI_PORD_INT_32K_CLR
|
117 RX_INT_32K_CLR
| HDMI_HTPLG_INT_32K_CLR
);
118 mtk_cec_mask(cec
, RX_GEN_WD
, 0, HDMI_PORD_INT_32K_CLR
| RX_INT_32K_CLR
|
119 HDMI_HTPLG_INT_32K_CLR
| HDMI_PORD_INT_32K_EN
|
120 RX_INT_32K_EN
| HDMI_HTPLG_INT_32K_EN
);
123 static void mtk_cec_htplg_irq_enable(struct mtk_cec
*cec
)
125 mtk_cec_set_bits(cec
, RX_EVENT
, HDMI_PORD_INT_EN
| HDMI_HTPLG_INT_EN
);
128 static void mtk_cec_htplg_irq_disable(struct mtk_cec
*cec
)
130 mtk_cec_clear_bits(cec
, RX_EVENT
, HDMI_PORD_INT_EN
| HDMI_HTPLG_INT_EN
);
133 static void mtk_cec_clear_htplg_irq(struct mtk_cec
*cec
)
135 mtk_cec_set_bits(cec
, TR_CONFIG
, CLEAR_CEC_IRQ
);
136 mtk_cec_set_bits(cec
, NORMAL_INT_CTRL
, HDMI_HTPLG_INT_CLR
|
137 HDMI_PORD_INT_CLR
| HDMI_FULL_INT_CLR
);
138 mtk_cec_set_bits(cec
, RX_GEN_WD
, HDMI_PORD_INT_32K_CLR
|
139 RX_INT_32K_CLR
| HDMI_HTPLG_INT_32K_CLR
);
141 mtk_cec_clear_bits(cec
, NORMAL_INT_CTRL
, HDMI_HTPLG_INT_CLR
|
142 HDMI_PORD_INT_CLR
| HDMI_FULL_INT_CLR
);
143 mtk_cec_clear_bits(cec
, TR_CONFIG
, CLEAR_CEC_IRQ
);
144 mtk_cec_clear_bits(cec
, RX_GEN_WD
, HDMI_PORD_INT_32K_CLR
|
145 RX_INT_32K_CLR
| HDMI_HTPLG_INT_32K_CLR
);
148 static void mtk_cec_hpd_event(struct mtk_cec
*cec
, bool hpd
)
150 void (*hpd_event
)(bool hpd
, struct device
*dev
);
151 struct device
*hdmi_dev
;
154 spin_lock_irqsave(&cec
->lock
, flags
);
155 hpd_event
= cec
->hpd_event
;
156 hdmi_dev
= cec
->hdmi_dev
;
157 spin_unlock_irqrestore(&cec
->lock
, flags
);
160 hpd_event(hpd
, hdmi_dev
);
163 static irqreturn_t
mtk_cec_htplg_isr_thread(int irq
, void *arg
)
165 struct device
*dev
= arg
;
166 struct mtk_cec
*cec
= dev_get_drvdata(dev
);
169 mtk_cec_clear_htplg_irq(cec
);
170 hpd
= mtk_cec_hpd_high(dev
);
172 if (cec
->hpd
!= hpd
) {
173 dev_dbg(dev
, "hotplug event! cur hpd = %d, hpd = %d\n",
176 mtk_cec_hpd_event(cec
, hpd
);
181 static int mtk_cec_probe(struct platform_device
*pdev
)
183 struct device
*dev
= &pdev
->dev
;
185 struct resource
*res
;
188 cec
= devm_kzalloc(dev
, sizeof(*cec
), GFP_KERNEL
);
192 platform_set_drvdata(pdev
, cec
);
193 spin_lock_init(&cec
->lock
);
195 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
196 cec
->regs
= devm_ioremap_resource(dev
, res
);
197 if (IS_ERR(cec
->regs
)) {
198 ret
= PTR_ERR(cec
->regs
);
199 dev_err(dev
, "Failed to ioremap cec: %d\n", ret
);
203 cec
->clk
= devm_clk_get(dev
, NULL
);
204 if (IS_ERR(cec
->clk
)) {
205 ret
= PTR_ERR(cec
->clk
);
206 dev_err(dev
, "Failed to get cec clock: %d\n", ret
);
210 cec
->irq
= platform_get_irq(pdev
, 0);
212 dev_err(dev
, "Failed to get cec irq: %d\n", cec
->irq
);
216 ret
= devm_request_threaded_irq(dev
, cec
->irq
, NULL
,
217 mtk_cec_htplg_isr_thread
,
218 IRQF_SHARED
| IRQF_TRIGGER_LOW
|
219 IRQF_ONESHOT
, "hdmi hpd", dev
);
221 dev_err(dev
, "Failed to register cec irq: %d\n", ret
);
225 ret
= clk_prepare_enable(cec
->clk
);
227 dev_err(dev
, "Failed to enable cec clock: %d\n", ret
);
231 mtk_cec_htplg_irq_init(cec
);
232 mtk_cec_htplg_irq_enable(cec
);
237 static int mtk_cec_remove(struct platform_device
*pdev
)
239 struct mtk_cec
*cec
= platform_get_drvdata(pdev
);
241 mtk_cec_htplg_irq_disable(cec
);
242 clk_disable_unprepare(cec
->clk
);
246 static const struct of_device_id mtk_cec_of_ids
[] = {
247 { .compatible
= "mediatek,mt8173-cec", },
251 struct platform_driver mtk_cec_driver
= {
252 .probe
= mtk_cec_probe
,
253 .remove
= mtk_cec_remove
,
255 .name
= "mediatek-cec",
256 .of_match_table
= mtk_cec_of_ids
,