2 * Copyright (c) 2014 MediaTek Inc.
3 * Author: Jie Qiu <jie.qiu@mediatek.com>
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.
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.
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/i2c.h>
17 #include <linux/time.h>
18 #include <linux/delay.h>
19 #include <linux/errno.h>
20 #include <linux/err.h>
21 #include <linux/platform_device.h>
22 #include <linux/clk.h>
23 #include <linux/slab.h>
25 #include <linux/iopoll.h>
26 #include <linux/of_address.h>
27 #include <linux/of_irq.h>
28 #include <linux/of_platform.h>
30 #define SIF1_CLOK (288)
31 #define DDC_DDCMCTL0 (0x0)
32 #define DDCM_ODRAIN BIT(31)
33 #define DDCM_CLK_DIV_OFFSET (16)
34 #define DDCM_CLK_DIV_MASK (0xfff << 16)
35 #define DDCM_CS_STATUS BIT(4)
36 #define DDCM_SCL_STATE BIT(3)
37 #define DDCM_SDA_STATE BIT(2)
38 #define DDCM_SM0EN BIT(1)
39 #define DDCM_SCL_STRECH BIT(0)
40 #define DDC_DDCMCTL1 (0x4)
41 #define DDCM_ACK_OFFSET (16)
42 #define DDCM_ACK_MASK (0xff << 16)
43 #define DDCM_PGLEN_OFFSET (8)
44 #define DDCM_PGLEN_MASK (0x7 << 8)
45 #define DDCM_SIF_MODE_OFFSET (4)
46 #define DDCM_SIF_MODE_MASK (0x7 << 4)
47 #define DDCM_START (0x1)
48 #define DDCM_WRITE_DATA (0x2)
49 #define DDCM_STOP (0x3)
50 #define DDCM_READ_DATA_NO_ACK (0x4)
51 #define DDCM_READ_DATA_ACK (0x5)
52 #define DDCM_TRI BIT(0)
53 #define DDC_DDCMD0 (0x8)
54 #define DDCM_DATA3 (0xff << 24)
55 #define DDCM_DATA2 (0xff << 16)
56 #define DDCM_DATA1 (0xff << 8)
57 #define DDCM_DATA0 (0xff << 0)
58 #define DDC_DDCMD1 (0xc)
59 #define DDCM_DATA7 (0xff << 24)
60 #define DDCM_DATA6 (0xff << 16)
61 #define DDCM_DATA5 (0xff << 8)
62 #define DDCM_DATA4 (0xff << 0)
65 struct i2c_adapter adap
;
70 static inline void sif_set_bit(struct mtk_hdmi_ddc
*ddc
, unsigned int offset
,
73 writel(readl(ddc
->regs
+ offset
) | val
, ddc
->regs
+ offset
);
76 static inline void sif_clr_bit(struct mtk_hdmi_ddc
*ddc
, unsigned int offset
,
79 writel(readl(ddc
->regs
+ offset
) & ~val
, ddc
->regs
+ offset
);
82 static inline bool sif_bit_is_set(struct mtk_hdmi_ddc
*ddc
, unsigned int offset
,
85 return (readl(ddc
->regs
+ offset
) & val
) == val
;
88 static inline void sif_write_mask(struct mtk_hdmi_ddc
*ddc
, unsigned int offset
,
89 unsigned int mask
, unsigned int shift
,
94 tmp
= readl(ddc
->regs
+ offset
);
96 tmp
|= (val
<< shift
) & mask
;
97 writel(tmp
, ddc
->regs
+ offset
);
100 static inline unsigned int sif_read_mask(struct mtk_hdmi_ddc
*ddc
,
101 unsigned int offset
, unsigned int mask
,
104 return (readl(ddc
->regs
+ offset
) & mask
) >> shift
;
107 static void ddcm_trigger_mode(struct mtk_hdmi_ddc
*ddc
, int mode
)
111 sif_write_mask(ddc
, DDC_DDCMCTL1
, DDCM_SIF_MODE_MASK
,
112 DDCM_SIF_MODE_OFFSET
, mode
);
113 sif_set_bit(ddc
, DDC_DDCMCTL1
, DDCM_TRI
);
114 readl_poll_timeout(ddc
->regs
+ DDC_DDCMCTL1
, val
,
115 (val
& DDCM_TRI
) != DDCM_TRI
, 4, 20000);
118 static int mtk_hdmi_ddc_read_msg(struct mtk_hdmi_ddc
*ddc
, struct i2c_msg
*msg
)
120 struct device
*dev
= ddc
->adap
.dev
.parent
;
121 u32 remain_count
, ack_count
, ack_final
, read_count
, temp_count
;
126 ddcm_trigger_mode(ddc
, DDCM_START
);
127 sif_write_mask(ddc
, DDC_DDCMD0
, 0xff, 0, (msg
->addr
<< 1) | 0x01);
128 sif_write_mask(ddc
, DDC_DDCMCTL1
, DDCM_PGLEN_MASK
, DDCM_PGLEN_OFFSET
,
130 ddcm_trigger_mode(ddc
, DDCM_WRITE_DATA
);
131 ack
= sif_read_mask(ddc
, DDC_DDCMCTL1
, DDCM_ACK_MASK
, DDCM_ACK_OFFSET
);
132 dev_dbg(dev
, "ack = 0x%x\n", ack
);
134 dev_err(dev
, "i2c ack err!\n");
138 remain_count
= msg
->len
;
139 ack_count
= (msg
->len
- 1) / 8;
142 while (remain_count
> 0) {
148 read_count
= remain_count
;
152 sif_write_mask(ddc
, DDC_DDCMCTL1
, DDCM_PGLEN_MASK
,
153 DDCM_PGLEN_OFFSET
, read_count
- 1);
154 ddcm_trigger_mode(ddc
, (ack_final
== 1) ?
155 DDCM_READ_DATA_NO_ACK
:
158 ack
= sif_read_mask(ddc
, DDC_DDCMCTL1
, DDCM_ACK_MASK
,
161 while (((ack
& (1 << temp_count
)) != 0) && (temp_count
< 8))
163 if (((ack_final
== 1) && (temp_count
!= (read_count
- 1))) ||
164 ((ack_final
== 0) && (temp_count
!= read_count
))) {
165 dev_err(dev
, "Address NACK! ACK(0x%x)\n", ack
);
169 for (i
= read_count
; i
>= 1; i
--) {
181 msg
->buf
[index
+ i
- 1] = sif_read_mask(ddc
, offset
,
186 remain_count
-= read_count
;
193 static int mtk_hdmi_ddc_write_msg(struct mtk_hdmi_ddc
*ddc
, struct i2c_msg
*msg
)
195 struct device
*dev
= ddc
->adap
.dev
.parent
;
198 ddcm_trigger_mode(ddc
, DDCM_START
);
199 sif_write_mask(ddc
, DDC_DDCMD0
, DDCM_DATA0
, 0, msg
->addr
<< 1);
200 sif_write_mask(ddc
, DDC_DDCMD0
, DDCM_DATA1
, 8, msg
->buf
[0]);
201 sif_write_mask(ddc
, DDC_DDCMCTL1
, DDCM_PGLEN_MASK
, DDCM_PGLEN_OFFSET
,
203 ddcm_trigger_mode(ddc
, DDCM_WRITE_DATA
);
205 ack
= sif_read_mask(ddc
, DDC_DDCMCTL1
, DDCM_ACK_MASK
, DDCM_ACK_OFFSET
);
206 dev_dbg(dev
, "ack = %d\n", ack
);
209 dev_err(dev
, "i2c ack err!\n");
216 static int mtk_hdmi_ddc_xfer(struct i2c_adapter
*adapter
,
217 struct i2c_msg
*msgs
, int num
)
219 struct mtk_hdmi_ddc
*ddc
= adapter
->algo_data
;
220 struct device
*dev
= adapter
->dev
.parent
;
225 dev_err(dev
, "invalid arguments\n");
229 sif_set_bit(ddc
, DDC_DDCMCTL0
, DDCM_SCL_STRECH
);
230 sif_set_bit(ddc
, DDC_DDCMCTL0
, DDCM_SM0EN
);
231 sif_clr_bit(ddc
, DDC_DDCMCTL0
, DDCM_ODRAIN
);
233 if (sif_bit_is_set(ddc
, DDC_DDCMCTL1
, DDCM_TRI
)) {
234 dev_err(dev
, "ddc line is busy!\n");
238 sif_write_mask(ddc
, DDC_DDCMCTL0
, DDCM_CLK_DIV_MASK
,
239 DDCM_CLK_DIV_OFFSET
, SIF1_CLOK
);
241 for (i
= 0; i
< num
; i
++) {
242 struct i2c_msg
*msg
= &msgs
[i
];
244 dev_dbg(dev
, "i2c msg, adr:0x%x, flags:%d, len :0x%x\n",
245 msg
->addr
, msg
->flags
, msg
->len
);
247 if (msg
->flags
& I2C_M_RD
)
248 ret
= mtk_hdmi_ddc_read_msg(ddc
, msg
);
250 ret
= mtk_hdmi_ddc_write_msg(ddc
, msg
);
255 ddcm_trigger_mode(ddc
, DDCM_STOP
);
260 ddcm_trigger_mode(ddc
, DDCM_STOP
);
261 dev_err(dev
, "ddc failed!\n");
265 static u32
mtk_hdmi_ddc_func(struct i2c_adapter
*adapter
)
267 return I2C_FUNC_I2C
| I2C_FUNC_SMBUS_EMUL
;
270 static const struct i2c_algorithm mtk_hdmi_ddc_algorithm
= {
271 .master_xfer
= mtk_hdmi_ddc_xfer
,
272 .functionality
= mtk_hdmi_ddc_func
,
275 static int mtk_hdmi_ddc_probe(struct platform_device
*pdev
)
277 struct device
*dev
= &pdev
->dev
;
278 struct mtk_hdmi_ddc
*ddc
;
279 struct resource
*mem
;
282 ddc
= devm_kzalloc(dev
, sizeof(struct mtk_hdmi_ddc
), GFP_KERNEL
);
286 ddc
->clk
= devm_clk_get(dev
, "ddc-i2c");
287 if (IS_ERR(ddc
->clk
)) {
288 dev_err(dev
, "get ddc_clk failed: %p ,\n", ddc
->clk
);
289 return PTR_ERR(ddc
->clk
);
292 mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
293 ddc
->regs
= devm_ioremap_resource(&pdev
->dev
, mem
);
294 if (IS_ERR(ddc
->regs
))
295 return PTR_ERR(ddc
->regs
);
297 ret
= clk_prepare_enable(ddc
->clk
);
299 dev_err(dev
, "enable ddc clk failed!\n");
303 strlcpy(ddc
->adap
.name
, "mediatek-hdmi-ddc", sizeof(ddc
->adap
.name
));
304 ddc
->adap
.owner
= THIS_MODULE
;
305 ddc
->adap
.class = I2C_CLASS_DDC
;
306 ddc
->adap
.algo
= &mtk_hdmi_ddc_algorithm
;
307 ddc
->adap
.retries
= 3;
308 ddc
->adap
.dev
.of_node
= dev
->of_node
;
309 ddc
->adap
.algo_data
= ddc
;
310 ddc
->adap
.dev
.parent
= &pdev
->dev
;
312 ret
= i2c_add_adapter(&ddc
->adap
);
314 dev_err(dev
, "failed to add bus to i2c core\n");
315 goto err_clk_disable
;
318 platform_set_drvdata(pdev
, ddc
);
320 dev_dbg(dev
, "ddc->adap: %p\n", &ddc
->adap
);
321 dev_dbg(dev
, "ddc->clk: %p\n", ddc
->clk
);
322 dev_dbg(dev
, "physical adr: %pa, end: %pa\n", &mem
->start
,
328 clk_disable_unprepare(ddc
->clk
);
332 static int mtk_hdmi_ddc_remove(struct platform_device
*pdev
)
334 struct mtk_hdmi_ddc
*ddc
= platform_get_drvdata(pdev
);
336 i2c_del_adapter(&ddc
->adap
);
337 clk_disable_unprepare(ddc
->clk
);
342 static const struct of_device_id mtk_hdmi_ddc_match
[] = {
343 { .compatible
= "mediatek,mt8173-hdmi-ddc", },
347 struct platform_driver mtk_hdmi_ddc_driver
= {
348 .probe
= mtk_hdmi_ddc_probe
,
349 .remove
= mtk_hdmi_ddc_remove
,
351 .name
= "mediatek-hdmi-ddc",
352 .of_match_table
= mtk_hdmi_ddc_match
,
356 MODULE_AUTHOR("Jie Qiu <jie.qiu@mediatek.com>");
357 MODULE_DESCRIPTION("MediaTek HDMI DDC Driver");
358 MODULE_LICENSE("GPL v2");