12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2f0a3dd33SJonathan Liu /*
3f0a3dd33SJonathan Liu  * Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.com>
4f0a3dd33SJonathan Liu  * Copyright (C) 2017 Jonathan Liu <net147@gmail.com>
5f0a3dd33SJonathan Liu  */
6f0a3dd33SJonathan Liu 
7f0a3dd33SJonathan Liu #include <linux/clk.h>
8f0a3dd33SJonathan Liu #include <linux/i2c.h>
9f0a3dd33SJonathan Liu #include <linux/iopoll.h>
10f0a3dd33SJonathan Liu 
11f0a3dd33SJonathan Liu #include "sun4i_hdmi.h"
12f0a3dd33SJonathan Liu 
13f0a3dd33SJonathan Liu #define SUN4I_HDMI_DDC_INT_STATUS_ERROR_MASK ( \
14f0a3dd33SJonathan Liu 	SUN4I_HDMI_DDC_INT_STATUS_ILLEGAL_FIFO_OPERATION | \
15f0a3dd33SJonathan Liu 	SUN4I_HDMI_DDC_INT_STATUS_DDC_RX_FIFO_UNDERFLOW | \
16f0a3dd33SJonathan Liu 	SUN4I_HDMI_DDC_INT_STATUS_DDC_TX_FIFO_OVERFLOW | \
17f0a3dd33SJonathan Liu 	SUN4I_HDMI_DDC_INT_STATUS_ARBITRATION_ERROR | \
18f0a3dd33SJonathan Liu 	SUN4I_HDMI_DDC_INT_STATUS_ACK_ERROR | \
19f0a3dd33SJonathan Liu 	SUN4I_HDMI_DDC_INT_STATUS_BUS_ERROR \
20f0a3dd33SJonathan Liu )
21f0a3dd33SJonathan Liu 
22f0a3dd33SJonathan Liu /* FIFO request bit is set when FIFO level is above RX_THRESHOLD during read */
23f0a3dd33SJonathan Liu #define RX_THRESHOLD SUN4I_HDMI_DDC_FIFO_CTRL_RX_THRES_MAX
24f0a3dd33SJonathan Liu 
fifo_transfer(struct sun4i_hdmi * hdmi,u8 * buf,int len,bool read)25f0a3dd33SJonathan Liu static int fifo_transfer(struct sun4i_hdmi *hdmi, u8 *buf, int len, bool read)
26f0a3dd33SJonathan Liu {
27f0a3dd33SJonathan Liu 	/*
28f0a3dd33SJonathan Liu 	 * 1 byte takes 9 clock cycles (8 bits + 1 ACK) = 90 us for 100 kHz
29f0a3dd33SJonathan Liu 	 * clock. As clock rate is fixed, just round it up to 100 us.
30f0a3dd33SJonathan Liu 	 */
31f0a3dd33SJonathan Liu 	const unsigned long byte_time_ns = 100;
32f0a3dd33SJonathan Liu 	const u32 mask = SUN4I_HDMI_DDC_INT_STATUS_ERROR_MASK |
33f0a3dd33SJonathan Liu 			 SUN4I_HDMI_DDC_INT_STATUS_FIFO_REQUEST |
34f0a3dd33SJonathan Liu 			 SUN4I_HDMI_DDC_INT_STATUS_TRANSFER_COMPLETE;
35f0a3dd33SJonathan Liu 	u32 reg;
36939d749aSChen-Yu Tsai 	/*
37939d749aSChen-Yu Tsai 	 * If threshold is inclusive, then the FIFO may only have
38939d749aSChen-Yu Tsai 	 * RX_THRESHOLD number of bytes, instead of RX_THRESHOLD + 1.
39939d749aSChen-Yu Tsai 	 */
40939d749aSChen-Yu Tsai 	int read_len = RX_THRESHOLD +
41939d749aSChen-Yu Tsai 		(hdmi->variant->ddc_fifo_thres_incl ? 0 : 1);
42f0a3dd33SJonathan Liu 
43939d749aSChen-Yu Tsai 	/*
44939d749aSChen-Yu Tsai 	 * Limit transfer length by FIFO threshold or FIFO size.
45939d749aSChen-Yu Tsai 	 * For TX the threshold is for an empty FIFO.
46939d749aSChen-Yu Tsai 	 */
47939d749aSChen-Yu Tsai 	len = min_t(int, len, read ? read_len : SUN4I_HDMI_DDC_FIFO_SIZE);
48f0a3dd33SJonathan Liu 
49f0a3dd33SJonathan Liu 	/* Wait until error, FIFO request bit set or transfer complete */
50939d749aSChen-Yu Tsai 	if (regmap_field_read_poll_timeout(hdmi->field_ddc_int_status, reg,
51939d749aSChen-Yu Tsai 					   reg & mask, len * byte_time_ns,
52939d749aSChen-Yu Tsai 					   100000))
53f0a3dd33SJonathan Liu 		return -ETIMEDOUT;
54f0a3dd33SJonathan Liu 
55f0a3dd33SJonathan Liu 	if (reg & SUN4I_HDMI_DDC_INT_STATUS_ERROR_MASK)
56f0a3dd33SJonathan Liu 		return -EIO;
57f0a3dd33SJonathan Liu 
58f0a3dd33SJonathan Liu 	if (read)
59adfda0bbSSamuel Holland 		ioread8_rep(hdmi->base + hdmi->variant->ddc_fifo_reg, buf, len);
60f0a3dd33SJonathan Liu 	else
61adfda0bbSSamuel Holland 		iowrite8_rep(hdmi->base + hdmi->variant->ddc_fifo_reg, buf, len);
62f0a3dd33SJonathan Liu 
63939d749aSChen-Yu Tsai 	/* Clear FIFO request bit by forcing a write to that bit */
64939d749aSChen-Yu Tsai 	regmap_field_force_write(hdmi->field_ddc_int_status,
65939d749aSChen-Yu Tsai 				 SUN4I_HDMI_DDC_INT_STATUS_FIFO_REQUEST);
66f0a3dd33SJonathan Liu 
67f0a3dd33SJonathan Liu 	return len;
68f0a3dd33SJonathan Liu }
69f0a3dd33SJonathan Liu 
xfer_msg(struct sun4i_hdmi * hdmi,struct i2c_msg * msg)70f0a3dd33SJonathan Liu static int xfer_msg(struct sun4i_hdmi *hdmi, struct i2c_msg *msg)
71f0a3dd33SJonathan Liu {
72f0a3dd33SJonathan Liu 	int i, len;
73f0a3dd33SJonathan Liu 	u32 reg;
74f0a3dd33SJonathan Liu 
75f0a3dd33SJonathan Liu 	/* Set FIFO direction */
76939d749aSChen-Yu Tsai 	if (hdmi->variant->ddc_fifo_has_dir) {
77f0a3dd33SJonathan Liu 		reg = readl(hdmi->base + SUN4I_HDMI_DDC_CTRL_REG);
78f0a3dd33SJonathan Liu 		reg &= ~SUN4I_HDMI_DDC_CTRL_FIFO_DIR_MASK;
79f0a3dd33SJonathan Liu 		reg |= (msg->flags & I2C_M_RD) ?
80f0a3dd33SJonathan Liu 		       SUN4I_HDMI_DDC_CTRL_FIFO_DIR_READ :
81f0a3dd33SJonathan Liu 		       SUN4I_HDMI_DDC_CTRL_FIFO_DIR_WRITE;
82f0a3dd33SJonathan Liu 		writel(reg, hdmi->base + SUN4I_HDMI_DDC_CTRL_REG);
83939d749aSChen-Yu Tsai 	}
84939d749aSChen-Yu Tsai 
85939d749aSChen-Yu Tsai 	/* Clear address register (not cleared by soft reset) */
86939d749aSChen-Yu Tsai 	regmap_field_write(hdmi->field_ddc_addr_reg, 0);
87f0a3dd33SJonathan Liu 
88f0a3dd33SJonathan Liu 	/* Set I2C address */
89939d749aSChen-Yu Tsai 	regmap_field_write(hdmi->field_ddc_slave_addr, msg->addr);
90f0a3dd33SJonathan Liu 
91939d749aSChen-Yu Tsai 	/*
92939d749aSChen-Yu Tsai 	 * Set FIFO RX/TX thresholds and clear FIFO
93939d749aSChen-Yu Tsai 	 *
94939d749aSChen-Yu Tsai 	 * If threshold is inclusive, we can set the TX threshold to
95939d749aSChen-Yu Tsai 	 * 0 instead of 1.
96939d749aSChen-Yu Tsai 	 */
97939d749aSChen-Yu Tsai 	regmap_field_write(hdmi->field_ddc_fifo_tx_thres,
98939d749aSChen-Yu Tsai 			   hdmi->variant->ddc_fifo_thres_incl ? 0 : 1);
99939d749aSChen-Yu Tsai 	regmap_field_write(hdmi->field_ddc_fifo_rx_thres, RX_THRESHOLD);
100939d749aSChen-Yu Tsai 	regmap_field_write(hdmi->field_ddc_fifo_clear, 1);
101939d749aSChen-Yu Tsai 	if (regmap_field_read_poll_timeout(hdmi->field_ddc_fifo_clear,
102939d749aSChen-Yu Tsai 					   reg, !reg, 100, 2000))
103f0a3dd33SJonathan Liu 		return -EIO;
104f0a3dd33SJonathan Liu 
105f0a3dd33SJonathan Liu 	/* Set transfer length */
106939d749aSChen-Yu Tsai 	regmap_field_write(hdmi->field_ddc_byte_count, msg->len);
107f0a3dd33SJonathan Liu 
108f0a3dd33SJonathan Liu 	/* Set command */
109939d749aSChen-Yu Tsai 	regmap_field_write(hdmi->field_ddc_cmd,
110939d749aSChen-Yu Tsai 			   msg->flags & I2C_M_RD ?
111f0a3dd33SJonathan Liu 			   SUN4I_HDMI_DDC_CMD_IMPLICIT_READ :
112939d749aSChen-Yu Tsai 			   SUN4I_HDMI_DDC_CMD_IMPLICIT_WRITE);
113f0a3dd33SJonathan Liu 
114939d749aSChen-Yu Tsai 	/* Clear interrupt status bits by forcing a write */
115939d749aSChen-Yu Tsai 	regmap_field_force_write(hdmi->field_ddc_int_status,
116939d749aSChen-Yu Tsai 				 SUN4I_HDMI_DDC_INT_STATUS_ERROR_MASK |
117f0a3dd33SJonathan Liu 				 SUN4I_HDMI_DDC_INT_STATUS_FIFO_REQUEST |
118939d749aSChen-Yu Tsai 				 SUN4I_HDMI_DDC_INT_STATUS_TRANSFER_COMPLETE);
119f0a3dd33SJonathan Liu 
120f0a3dd33SJonathan Liu 	/* Start command */
121939d749aSChen-Yu Tsai 	regmap_field_write(hdmi->field_ddc_start, 1);
122f0a3dd33SJonathan Liu 
123f0a3dd33SJonathan Liu 	/* Transfer bytes */
124f0a3dd33SJonathan Liu 	for (i = 0; i < msg->len; i += len) {
125f0a3dd33SJonathan Liu 		len = fifo_transfer(hdmi, msg->buf + i, msg->len - i,
126f0a3dd33SJonathan Liu 				    msg->flags & I2C_M_RD);
127f0a3dd33SJonathan Liu 		if (len <= 0)
128f0a3dd33SJonathan Liu 			return len;
129f0a3dd33SJonathan Liu 	}
130f0a3dd33SJonathan Liu 
131f0a3dd33SJonathan Liu 	/* Wait for command to finish */
132939d749aSChen-Yu Tsai 	if (regmap_field_read_poll_timeout(hdmi->field_ddc_start,
133939d749aSChen-Yu Tsai 					   reg, !reg, 100, 100000))
134f0a3dd33SJonathan Liu 		return -EIO;
135f0a3dd33SJonathan Liu 
136f0a3dd33SJonathan Liu 	/* Check for errors */
137939d749aSChen-Yu Tsai 	regmap_field_read(hdmi->field_ddc_int_status, &reg);
138f0a3dd33SJonathan Liu 	if ((reg & SUN4I_HDMI_DDC_INT_STATUS_ERROR_MASK) ||
139f0a3dd33SJonathan Liu 	    !(reg & SUN4I_HDMI_DDC_INT_STATUS_TRANSFER_COMPLETE)) {
140f0a3dd33SJonathan Liu 		return -EIO;
141f0a3dd33SJonathan Liu 	}
142f0a3dd33SJonathan Liu 
143f0a3dd33SJonathan Liu 	return 0;
144f0a3dd33SJonathan Liu }
145f0a3dd33SJonathan Liu 
sun4i_hdmi_i2c_xfer(struct i2c_adapter * adap,struct i2c_msg * msgs,int num)146f0a3dd33SJonathan Liu static int sun4i_hdmi_i2c_xfer(struct i2c_adapter *adap,
147f0a3dd33SJonathan Liu 			       struct i2c_msg *msgs, int num)
148f0a3dd33SJonathan Liu {
149f0a3dd33SJonathan Liu 	struct sun4i_hdmi *hdmi = i2c_get_adapdata(adap);
150f0a3dd33SJonathan Liu 	u32 reg;
151f0a3dd33SJonathan Liu 	int err, i, ret = num;
152f0a3dd33SJonathan Liu 
153f0a3dd33SJonathan Liu 	for (i = 0; i < num; i++) {
154f0a3dd33SJonathan Liu 		if (!msgs[i].len)
155f0a3dd33SJonathan Liu 			return -EINVAL;
156f0a3dd33SJonathan Liu 		if (msgs[i].len > SUN4I_HDMI_DDC_BYTE_COUNT_MAX)
157f0a3dd33SJonathan Liu 			return -EINVAL;
158f0a3dd33SJonathan Liu 	}
159f0a3dd33SJonathan Liu 
160939d749aSChen-Yu Tsai 	/* DDC clock needs to be enabled for the module to work */
161f0a3dd33SJonathan Liu 	clk_prepare_enable(hdmi->ddc_clk);
162f0a3dd33SJonathan Liu 	clk_set_rate(hdmi->ddc_clk, 100000);
163f0a3dd33SJonathan Liu 
164939d749aSChen-Yu Tsai 	/* Reset I2C controller */
165939d749aSChen-Yu Tsai 	regmap_field_write(hdmi->field_ddc_en, 1);
166939d749aSChen-Yu Tsai 	regmap_field_write(hdmi->field_ddc_reset, 1);
167939d749aSChen-Yu Tsai 	if (regmap_field_read_poll_timeout(hdmi->field_ddc_reset,
168939d749aSChen-Yu Tsai 					   reg, !reg, 100, 2000)) {
169939d749aSChen-Yu Tsai 		clk_disable_unprepare(hdmi->ddc_clk);
170939d749aSChen-Yu Tsai 		return -EIO;
171939d749aSChen-Yu Tsai 	}
172939d749aSChen-Yu Tsai 
173939d749aSChen-Yu Tsai 	regmap_field_write(hdmi->field_ddc_sck_en, 1);
174939d749aSChen-Yu Tsai 	regmap_field_write(hdmi->field_ddc_sda_en, 1);
175939d749aSChen-Yu Tsai 
176f0a3dd33SJonathan Liu 	for (i = 0; i < num; i++) {
177f0a3dd33SJonathan Liu 		err = xfer_msg(hdmi, &msgs[i]);
178f0a3dd33SJonathan Liu 		if (err) {
179f0a3dd33SJonathan Liu 			ret = err;
180f0a3dd33SJonathan Liu 			break;
181f0a3dd33SJonathan Liu 		}
182f0a3dd33SJonathan Liu 	}
183f0a3dd33SJonathan Liu 
184f0a3dd33SJonathan Liu 	clk_disable_unprepare(hdmi->ddc_clk);
185f0a3dd33SJonathan Liu 	return ret;
186f0a3dd33SJonathan Liu }
187f0a3dd33SJonathan Liu 
sun4i_hdmi_i2c_func(struct i2c_adapter * adap)188f0a3dd33SJonathan Liu static u32 sun4i_hdmi_i2c_func(struct i2c_adapter *adap)
189f0a3dd33SJonathan Liu {
190f0a3dd33SJonathan Liu 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
191f0a3dd33SJonathan Liu }
192f0a3dd33SJonathan Liu 
193f0a3dd33SJonathan Liu static const struct i2c_algorithm sun4i_hdmi_i2c_algorithm = {
194f0a3dd33SJonathan Liu 	.master_xfer	= sun4i_hdmi_i2c_xfer,
195f0a3dd33SJonathan Liu 	.functionality	= sun4i_hdmi_i2c_func,
196f0a3dd33SJonathan Liu };
197f0a3dd33SJonathan Liu 
sun4i_hdmi_init_regmap_fields(struct sun4i_hdmi * hdmi)198939d749aSChen-Yu Tsai static int sun4i_hdmi_init_regmap_fields(struct sun4i_hdmi *hdmi)
199939d749aSChen-Yu Tsai {
200939d749aSChen-Yu Tsai 	hdmi->field_ddc_en =
201939d749aSChen-Yu Tsai 		devm_regmap_field_alloc(hdmi->dev, hdmi->regmap,
202939d749aSChen-Yu Tsai 					hdmi->variant->field_ddc_en);
203939d749aSChen-Yu Tsai 	if (IS_ERR(hdmi->field_ddc_en))
204939d749aSChen-Yu Tsai 		return PTR_ERR(hdmi->field_ddc_en);
205939d749aSChen-Yu Tsai 
206939d749aSChen-Yu Tsai 	hdmi->field_ddc_start =
207939d749aSChen-Yu Tsai 		devm_regmap_field_alloc(hdmi->dev, hdmi->regmap,
208939d749aSChen-Yu Tsai 					hdmi->variant->field_ddc_start);
209939d749aSChen-Yu Tsai 	if (IS_ERR(hdmi->field_ddc_start))
210939d749aSChen-Yu Tsai 		return PTR_ERR(hdmi->field_ddc_start);
211939d749aSChen-Yu Tsai 
212939d749aSChen-Yu Tsai 	hdmi->field_ddc_reset =
213939d749aSChen-Yu Tsai 		devm_regmap_field_alloc(hdmi->dev, hdmi->regmap,
214939d749aSChen-Yu Tsai 					hdmi->variant->field_ddc_reset);
215939d749aSChen-Yu Tsai 	if (IS_ERR(hdmi->field_ddc_reset))
216939d749aSChen-Yu Tsai 		return PTR_ERR(hdmi->field_ddc_reset);
217939d749aSChen-Yu Tsai 
218939d749aSChen-Yu Tsai 	hdmi->field_ddc_addr_reg =
219939d749aSChen-Yu Tsai 		devm_regmap_field_alloc(hdmi->dev, hdmi->regmap,
220939d749aSChen-Yu Tsai 					hdmi->variant->field_ddc_addr_reg);
221939d749aSChen-Yu Tsai 	if (IS_ERR(hdmi->field_ddc_addr_reg))
222939d749aSChen-Yu Tsai 		return PTR_ERR(hdmi->field_ddc_addr_reg);
223939d749aSChen-Yu Tsai 
224939d749aSChen-Yu Tsai 	hdmi->field_ddc_slave_addr =
225939d749aSChen-Yu Tsai 		devm_regmap_field_alloc(hdmi->dev, hdmi->regmap,
226939d749aSChen-Yu Tsai 					hdmi->variant->field_ddc_slave_addr);
227939d749aSChen-Yu Tsai 	if (IS_ERR(hdmi->field_ddc_slave_addr))
228939d749aSChen-Yu Tsai 		return PTR_ERR(hdmi->field_ddc_slave_addr);
229939d749aSChen-Yu Tsai 
230939d749aSChen-Yu Tsai 	hdmi->field_ddc_int_mask =
231939d749aSChen-Yu Tsai 		devm_regmap_field_alloc(hdmi->dev, hdmi->regmap,
232939d749aSChen-Yu Tsai 					hdmi->variant->field_ddc_int_mask);
233939d749aSChen-Yu Tsai 	if (IS_ERR(hdmi->field_ddc_int_mask))
234939d749aSChen-Yu Tsai 		return PTR_ERR(hdmi->field_ddc_int_mask);
235939d749aSChen-Yu Tsai 
236939d749aSChen-Yu Tsai 	hdmi->field_ddc_int_status =
237939d749aSChen-Yu Tsai 		devm_regmap_field_alloc(hdmi->dev, hdmi->regmap,
238939d749aSChen-Yu Tsai 					hdmi->variant->field_ddc_int_status);
239939d749aSChen-Yu Tsai 	if (IS_ERR(hdmi->field_ddc_int_status))
240939d749aSChen-Yu Tsai 		return PTR_ERR(hdmi->field_ddc_int_status);
241939d749aSChen-Yu Tsai 
242939d749aSChen-Yu Tsai 	hdmi->field_ddc_fifo_clear =
243939d749aSChen-Yu Tsai 		devm_regmap_field_alloc(hdmi->dev, hdmi->regmap,
244939d749aSChen-Yu Tsai 					hdmi->variant->field_ddc_fifo_clear);
245939d749aSChen-Yu Tsai 	if (IS_ERR(hdmi->field_ddc_fifo_clear))
246939d749aSChen-Yu Tsai 		return PTR_ERR(hdmi->field_ddc_fifo_clear);
247939d749aSChen-Yu Tsai 
248939d749aSChen-Yu Tsai 	hdmi->field_ddc_fifo_rx_thres =
249939d749aSChen-Yu Tsai 		devm_regmap_field_alloc(hdmi->dev, hdmi->regmap,
250939d749aSChen-Yu Tsai 					hdmi->variant->field_ddc_fifo_rx_thres);
251939d749aSChen-Yu Tsai 	if (IS_ERR(hdmi->field_ddc_fifo_rx_thres))
252939d749aSChen-Yu Tsai 		return PTR_ERR(hdmi->field_ddc_fifo_rx_thres);
253939d749aSChen-Yu Tsai 
254939d749aSChen-Yu Tsai 	hdmi->field_ddc_fifo_tx_thres =
255939d749aSChen-Yu Tsai 		devm_regmap_field_alloc(hdmi->dev, hdmi->regmap,
256939d749aSChen-Yu Tsai 					hdmi->variant->field_ddc_fifo_tx_thres);
257939d749aSChen-Yu Tsai 	if (IS_ERR(hdmi->field_ddc_fifo_tx_thres))
258939d749aSChen-Yu Tsai 		return PTR_ERR(hdmi->field_ddc_fifo_tx_thres);
259939d749aSChen-Yu Tsai 
260939d749aSChen-Yu Tsai 	hdmi->field_ddc_byte_count =
261939d749aSChen-Yu Tsai 		devm_regmap_field_alloc(hdmi->dev, hdmi->regmap,
262939d749aSChen-Yu Tsai 					hdmi->variant->field_ddc_byte_count);
263939d749aSChen-Yu Tsai 	if (IS_ERR(hdmi->field_ddc_byte_count))
264939d749aSChen-Yu Tsai 		return PTR_ERR(hdmi->field_ddc_byte_count);
265939d749aSChen-Yu Tsai 
266939d749aSChen-Yu Tsai 	hdmi->field_ddc_cmd =
267939d749aSChen-Yu Tsai 		devm_regmap_field_alloc(hdmi->dev, hdmi->regmap,
268939d749aSChen-Yu Tsai 					hdmi->variant->field_ddc_cmd);
269939d749aSChen-Yu Tsai 	if (IS_ERR(hdmi->field_ddc_cmd))
270939d749aSChen-Yu Tsai 		return PTR_ERR(hdmi->field_ddc_cmd);
271939d749aSChen-Yu Tsai 
272939d749aSChen-Yu Tsai 	hdmi->field_ddc_sda_en =
273939d749aSChen-Yu Tsai 		devm_regmap_field_alloc(hdmi->dev, hdmi->regmap,
274939d749aSChen-Yu Tsai 					hdmi->variant->field_ddc_sda_en);
275939d749aSChen-Yu Tsai 	if (IS_ERR(hdmi->field_ddc_sda_en))
276939d749aSChen-Yu Tsai 		return PTR_ERR(hdmi->field_ddc_sda_en);
277939d749aSChen-Yu Tsai 
278939d749aSChen-Yu Tsai 	hdmi->field_ddc_sck_en =
279939d749aSChen-Yu Tsai 		devm_regmap_field_alloc(hdmi->dev, hdmi->regmap,
280939d749aSChen-Yu Tsai 					hdmi->variant->field_ddc_sck_en);
281939d749aSChen-Yu Tsai 	if (IS_ERR(hdmi->field_ddc_sck_en))
282939d749aSChen-Yu Tsai 		return PTR_ERR(hdmi->field_ddc_sck_en);
283939d749aSChen-Yu Tsai 
284939d749aSChen-Yu Tsai 	return 0;
285939d749aSChen-Yu Tsai }
286939d749aSChen-Yu Tsai 
sun4i_hdmi_i2c_create(struct device * dev,struct sun4i_hdmi * hdmi)287f0a3dd33SJonathan Liu int sun4i_hdmi_i2c_create(struct device *dev, struct sun4i_hdmi *hdmi)
288f0a3dd33SJonathan Liu {
289f0a3dd33SJonathan Liu 	struct i2c_adapter *adap;
290f0a3dd33SJonathan Liu 	int ret = 0;
291f0a3dd33SJonathan Liu 
292939d749aSChen-Yu Tsai 	ret = sun4i_ddc_create(hdmi, hdmi->ddc_parent_clk);
293939d749aSChen-Yu Tsai 	if (ret)
294939d749aSChen-Yu Tsai 		return ret;
295939d749aSChen-Yu Tsai 
296939d749aSChen-Yu Tsai 	ret = sun4i_hdmi_init_regmap_fields(hdmi);
297f0a3dd33SJonathan Liu 	if (ret)
298f0a3dd33SJonathan Liu 		return ret;
299f0a3dd33SJonathan Liu 
300f0a3dd33SJonathan Liu 	adap = devm_kzalloc(dev, sizeof(*adap), GFP_KERNEL);
301f0a3dd33SJonathan Liu 	if (!adap)
302f0a3dd33SJonathan Liu 		return -ENOMEM;
303f0a3dd33SJonathan Liu 
304f0a3dd33SJonathan Liu 	adap->owner = THIS_MODULE;
305f0a3dd33SJonathan Liu 	adap->class = I2C_CLASS_DDC;
306f0a3dd33SJonathan Liu 	adap->algo = &sun4i_hdmi_i2c_algorithm;
307*83602576SAzeem Shaikh 	strscpy(adap->name, "sun4i_hdmi_i2c adapter", sizeof(adap->name));
308f0a3dd33SJonathan Liu 	i2c_set_adapdata(adap, hdmi);
309f0a3dd33SJonathan Liu 
310f0a3dd33SJonathan Liu 	ret = i2c_add_adapter(adap);
311f0a3dd33SJonathan Liu 	if (ret)
312f0a3dd33SJonathan Liu 		return ret;
313f0a3dd33SJonathan Liu 
314f0a3dd33SJonathan Liu 	hdmi->i2c = adap;
315f0a3dd33SJonathan Liu 
316f0a3dd33SJonathan Liu 	return ret;
317f0a3dd33SJonathan Liu }
318