Lines Matching +full:i2c +full:- +full:hdmi
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.com>
8 #include <linux/i2c.h>
25 static int fifo_transfer(struct sun4i_hdmi *hdmi, u8 *buf, int len, bool read) in fifo_transfer() argument
41 (hdmi->variant->ddc_fifo_thres_incl ? 0 : 1); in fifo_transfer()
50 if (regmap_field_read_poll_timeout(hdmi->field_ddc_int_status, reg, in fifo_transfer()
53 return -ETIMEDOUT; in fifo_transfer()
56 return -EIO; in fifo_transfer()
59 ioread8_rep(hdmi->base + hdmi->variant->ddc_fifo_reg, buf, len); in fifo_transfer()
61 iowrite8_rep(hdmi->base + hdmi->variant->ddc_fifo_reg, buf, len); in fifo_transfer()
64 regmap_field_force_write(hdmi->field_ddc_int_status, in fifo_transfer()
70 static int xfer_msg(struct sun4i_hdmi *hdmi, struct i2c_msg *msg) in xfer_msg() argument
76 if (hdmi->variant->ddc_fifo_has_dir) { in xfer_msg()
77 reg = readl(hdmi->base + SUN4I_HDMI_DDC_CTRL_REG); in xfer_msg()
79 reg |= (msg->flags & I2C_M_RD) ? in xfer_msg()
82 writel(reg, hdmi->base + SUN4I_HDMI_DDC_CTRL_REG); in xfer_msg()
86 regmap_field_write(hdmi->field_ddc_addr_reg, 0); in xfer_msg()
88 /* Set I2C address */ in xfer_msg()
89 regmap_field_write(hdmi->field_ddc_slave_addr, msg->addr); in xfer_msg()
97 regmap_field_write(hdmi->field_ddc_fifo_tx_thres, in xfer_msg()
98 hdmi->variant->ddc_fifo_thres_incl ? 0 : 1); in xfer_msg()
99 regmap_field_write(hdmi->field_ddc_fifo_rx_thres, RX_THRESHOLD); in xfer_msg()
100 regmap_field_write(hdmi->field_ddc_fifo_clear, 1); in xfer_msg()
101 if (regmap_field_read_poll_timeout(hdmi->field_ddc_fifo_clear, in xfer_msg()
103 return -EIO; in xfer_msg()
106 regmap_field_write(hdmi->field_ddc_byte_count, msg->len); in xfer_msg()
109 regmap_field_write(hdmi->field_ddc_cmd, in xfer_msg()
110 msg->flags & I2C_M_RD ? in xfer_msg()
115 regmap_field_force_write(hdmi->field_ddc_int_status, in xfer_msg()
121 regmap_field_write(hdmi->field_ddc_start, 1); in xfer_msg()
124 for (i = 0; i < msg->len; i += len) { in xfer_msg()
125 len = fifo_transfer(hdmi, msg->buf + i, msg->len - i, in xfer_msg()
126 msg->flags & I2C_M_RD); in xfer_msg()
132 if (regmap_field_read_poll_timeout(hdmi->field_ddc_start, in xfer_msg()
134 return -EIO; in xfer_msg()
137 regmap_field_read(hdmi->field_ddc_int_status, ®); in xfer_msg()
140 return -EIO; in xfer_msg()
149 struct sun4i_hdmi *hdmi = i2c_get_adapdata(adap); in sun4i_hdmi_i2c_xfer() local
155 return -EINVAL; in sun4i_hdmi_i2c_xfer()
157 return -EINVAL; in sun4i_hdmi_i2c_xfer()
161 clk_prepare_enable(hdmi->ddc_clk); in sun4i_hdmi_i2c_xfer()
162 clk_set_rate(hdmi->ddc_clk, 100000); in sun4i_hdmi_i2c_xfer()
164 /* Reset I2C controller */ in sun4i_hdmi_i2c_xfer()
165 regmap_field_write(hdmi->field_ddc_en, 1); in sun4i_hdmi_i2c_xfer()
166 regmap_field_write(hdmi->field_ddc_reset, 1); in sun4i_hdmi_i2c_xfer()
167 if (regmap_field_read_poll_timeout(hdmi->field_ddc_reset, in sun4i_hdmi_i2c_xfer()
169 clk_disable_unprepare(hdmi->ddc_clk); in sun4i_hdmi_i2c_xfer()
170 return -EIO; in sun4i_hdmi_i2c_xfer()
173 regmap_field_write(hdmi->field_ddc_sck_en, 1); in sun4i_hdmi_i2c_xfer()
174 regmap_field_write(hdmi->field_ddc_sda_en, 1); in sun4i_hdmi_i2c_xfer()
177 err = xfer_msg(hdmi, &msgs[i]); in sun4i_hdmi_i2c_xfer()
184 clk_disable_unprepare(hdmi->ddc_clk); in sun4i_hdmi_i2c_xfer()
198 static int sun4i_hdmi_init_regmap_fields(struct sun4i_hdmi *hdmi) in sun4i_hdmi_init_regmap_fields() argument
200 hdmi->field_ddc_en = in sun4i_hdmi_init_regmap_fields()
201 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, in sun4i_hdmi_init_regmap_fields()
202 hdmi->variant->field_ddc_en); in sun4i_hdmi_init_regmap_fields()
203 if (IS_ERR(hdmi->field_ddc_en)) in sun4i_hdmi_init_regmap_fields()
204 return PTR_ERR(hdmi->field_ddc_en); in sun4i_hdmi_init_regmap_fields()
206 hdmi->field_ddc_start = in sun4i_hdmi_init_regmap_fields()
207 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, in sun4i_hdmi_init_regmap_fields()
208 hdmi->variant->field_ddc_start); in sun4i_hdmi_init_regmap_fields()
209 if (IS_ERR(hdmi->field_ddc_start)) in sun4i_hdmi_init_regmap_fields()
210 return PTR_ERR(hdmi->field_ddc_start); in sun4i_hdmi_init_regmap_fields()
212 hdmi->field_ddc_reset = in sun4i_hdmi_init_regmap_fields()
213 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, in sun4i_hdmi_init_regmap_fields()
214 hdmi->variant->field_ddc_reset); in sun4i_hdmi_init_regmap_fields()
215 if (IS_ERR(hdmi->field_ddc_reset)) in sun4i_hdmi_init_regmap_fields()
216 return PTR_ERR(hdmi->field_ddc_reset); in sun4i_hdmi_init_regmap_fields()
218 hdmi->field_ddc_addr_reg = in sun4i_hdmi_init_regmap_fields()
219 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, in sun4i_hdmi_init_regmap_fields()
220 hdmi->variant->field_ddc_addr_reg); in sun4i_hdmi_init_regmap_fields()
221 if (IS_ERR(hdmi->field_ddc_addr_reg)) in sun4i_hdmi_init_regmap_fields()
222 return PTR_ERR(hdmi->field_ddc_addr_reg); in sun4i_hdmi_init_regmap_fields()
224 hdmi->field_ddc_slave_addr = in sun4i_hdmi_init_regmap_fields()
225 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, in sun4i_hdmi_init_regmap_fields()
226 hdmi->variant->field_ddc_slave_addr); in sun4i_hdmi_init_regmap_fields()
227 if (IS_ERR(hdmi->field_ddc_slave_addr)) in sun4i_hdmi_init_regmap_fields()
228 return PTR_ERR(hdmi->field_ddc_slave_addr); in sun4i_hdmi_init_regmap_fields()
230 hdmi->field_ddc_int_mask = in sun4i_hdmi_init_regmap_fields()
231 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, in sun4i_hdmi_init_regmap_fields()
232 hdmi->variant->field_ddc_int_mask); in sun4i_hdmi_init_regmap_fields()
233 if (IS_ERR(hdmi->field_ddc_int_mask)) in sun4i_hdmi_init_regmap_fields()
234 return PTR_ERR(hdmi->field_ddc_int_mask); in sun4i_hdmi_init_regmap_fields()
236 hdmi->field_ddc_int_status = in sun4i_hdmi_init_regmap_fields()
237 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, in sun4i_hdmi_init_regmap_fields()
238 hdmi->variant->field_ddc_int_status); in sun4i_hdmi_init_regmap_fields()
239 if (IS_ERR(hdmi->field_ddc_int_status)) in sun4i_hdmi_init_regmap_fields()
240 return PTR_ERR(hdmi->field_ddc_int_status); in sun4i_hdmi_init_regmap_fields()
242 hdmi->field_ddc_fifo_clear = in sun4i_hdmi_init_regmap_fields()
243 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, in sun4i_hdmi_init_regmap_fields()
244 hdmi->variant->field_ddc_fifo_clear); in sun4i_hdmi_init_regmap_fields()
245 if (IS_ERR(hdmi->field_ddc_fifo_clear)) in sun4i_hdmi_init_regmap_fields()
246 return PTR_ERR(hdmi->field_ddc_fifo_clear); in sun4i_hdmi_init_regmap_fields()
248 hdmi->field_ddc_fifo_rx_thres = in sun4i_hdmi_init_regmap_fields()
249 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, in sun4i_hdmi_init_regmap_fields()
250 hdmi->variant->field_ddc_fifo_rx_thres); in sun4i_hdmi_init_regmap_fields()
251 if (IS_ERR(hdmi->field_ddc_fifo_rx_thres)) in sun4i_hdmi_init_regmap_fields()
252 return PTR_ERR(hdmi->field_ddc_fifo_rx_thres); in sun4i_hdmi_init_regmap_fields()
254 hdmi->field_ddc_fifo_tx_thres = in sun4i_hdmi_init_regmap_fields()
255 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, in sun4i_hdmi_init_regmap_fields()
256 hdmi->variant->field_ddc_fifo_tx_thres); in sun4i_hdmi_init_regmap_fields()
257 if (IS_ERR(hdmi->field_ddc_fifo_tx_thres)) in sun4i_hdmi_init_regmap_fields()
258 return PTR_ERR(hdmi->field_ddc_fifo_tx_thres); in sun4i_hdmi_init_regmap_fields()
260 hdmi->field_ddc_byte_count = in sun4i_hdmi_init_regmap_fields()
261 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, in sun4i_hdmi_init_regmap_fields()
262 hdmi->variant->field_ddc_byte_count); in sun4i_hdmi_init_regmap_fields()
263 if (IS_ERR(hdmi->field_ddc_byte_count)) in sun4i_hdmi_init_regmap_fields()
264 return PTR_ERR(hdmi->field_ddc_byte_count); in sun4i_hdmi_init_regmap_fields()
266 hdmi->field_ddc_cmd = in sun4i_hdmi_init_regmap_fields()
267 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, in sun4i_hdmi_init_regmap_fields()
268 hdmi->variant->field_ddc_cmd); in sun4i_hdmi_init_regmap_fields()
269 if (IS_ERR(hdmi->field_ddc_cmd)) in sun4i_hdmi_init_regmap_fields()
270 return PTR_ERR(hdmi->field_ddc_cmd); in sun4i_hdmi_init_regmap_fields()
272 hdmi->field_ddc_sda_en = in sun4i_hdmi_init_regmap_fields()
273 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, in sun4i_hdmi_init_regmap_fields()
274 hdmi->variant->field_ddc_sda_en); in sun4i_hdmi_init_regmap_fields()
275 if (IS_ERR(hdmi->field_ddc_sda_en)) in sun4i_hdmi_init_regmap_fields()
276 return PTR_ERR(hdmi->field_ddc_sda_en); in sun4i_hdmi_init_regmap_fields()
278 hdmi->field_ddc_sck_en = in sun4i_hdmi_init_regmap_fields()
279 devm_regmap_field_alloc(hdmi->dev, hdmi->regmap, in sun4i_hdmi_init_regmap_fields()
280 hdmi->variant->field_ddc_sck_en); in sun4i_hdmi_init_regmap_fields()
281 if (IS_ERR(hdmi->field_ddc_sck_en)) in sun4i_hdmi_init_regmap_fields()
282 return PTR_ERR(hdmi->field_ddc_sck_en); in sun4i_hdmi_init_regmap_fields()
287 int sun4i_hdmi_i2c_create(struct device *dev, struct sun4i_hdmi *hdmi) in sun4i_hdmi_i2c_create() argument
292 ret = sun4i_ddc_create(hdmi, hdmi->ddc_parent_clk); in sun4i_hdmi_i2c_create()
296 ret = sun4i_hdmi_init_regmap_fields(hdmi); in sun4i_hdmi_i2c_create()
302 return -ENOMEM; in sun4i_hdmi_i2c_create()
304 adap->owner = THIS_MODULE; in sun4i_hdmi_i2c_create()
305 adap->algo = &sun4i_hdmi_i2c_algorithm; in sun4i_hdmi_i2c_create()
306 strscpy(adap->name, "sun4i_hdmi_i2c adapter", sizeof(adap->name)); in sun4i_hdmi_i2c_create()
307 i2c_set_adapdata(adap, hdmi); in sun4i_hdmi_i2c_create()
313 hdmi->i2c = adap; in sun4i_hdmi_i2c_create()