Lines Matching +full:ddc +full:- +full:i2c +full:- +full:bus

1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd.
6 * Author: Algea Cao <algea.cao@rock-chips.com>
11 #include <linux/i2c.h>
28 #include <sound/hdmi-codec.h>
30 #include "dw-hdmi-qp.h"
55 struct dw_hdmi_qp_i2c *i2c; member
68 regmap_write(hdmi->regm, offset, val); in dw_hdmi_qp_write()
75 regmap_read(hdmi->regm, offset, &val); in dw_hdmi_qp_read()
83 regmap_update_bits(hdmi->regm, reg, mask, data); in dw_hdmi_qp_mod()
89 struct dw_hdmi_qp_i2c *i2c = hdmi->i2c; in dw_hdmi_qp_i2c_read() local
92 if (!i2c->is_regaddr) { in dw_hdmi_qp_i2c_read()
93 dev_dbg(hdmi->dev, "set read register address to 0\n"); in dw_hdmi_qp_i2c_read()
94 i2c->slave_reg = 0x00; in dw_hdmi_qp_i2c_read()
95 i2c->is_regaddr = true; in dw_hdmi_qp_i2c_read()
98 while (length--) { in dw_hdmi_qp_i2c_read()
99 reinit_completion(&i2c->cmp); in dw_hdmi_qp_i2c_read()
101 dw_hdmi_qp_mod(hdmi, i2c->slave_reg++ << 12, I2CM_ADDR, in dw_hdmi_qp_i2c_read()
104 if (i2c->is_segment) in dw_hdmi_qp_i2c_read()
111 stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); in dw_hdmi_qp_i2c_read()
113 dev_err(hdmi->dev, "i2c read timed out\n"); in dw_hdmi_qp_i2c_read()
115 return -EAGAIN; in dw_hdmi_qp_i2c_read()
118 /* Check for error condition on the bus */ in dw_hdmi_qp_i2c_read()
119 if (i2c->stat & I2CM_NACK_RCVD_IRQ) { in dw_hdmi_qp_i2c_read()
120 dev_err(hdmi->dev, "i2c read error\n"); in dw_hdmi_qp_i2c_read()
122 return -EIO; in dw_hdmi_qp_i2c_read()
129 i2c->is_segment = false; in dw_hdmi_qp_i2c_read()
137 struct dw_hdmi_qp_i2c *i2c = hdmi->i2c; in dw_hdmi_qp_i2c_write() local
140 if (!i2c->is_regaddr) { in dw_hdmi_qp_i2c_write()
142 i2c->slave_reg = buf[0]; in dw_hdmi_qp_i2c_write()
143 length--; in dw_hdmi_qp_i2c_write()
145 i2c->is_regaddr = true; in dw_hdmi_qp_i2c_write()
148 while (length--) { in dw_hdmi_qp_i2c_write()
149 reinit_completion(&i2c->cmp); in dw_hdmi_qp_i2c_write()
152 dw_hdmi_qp_mod(hdmi, i2c->slave_reg++ << 12, I2CM_ADDR, in dw_hdmi_qp_i2c_write()
157 stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); in dw_hdmi_qp_i2c_write()
159 dev_err(hdmi->dev, "i2c write time out!\n"); in dw_hdmi_qp_i2c_write()
161 return -EAGAIN; in dw_hdmi_qp_i2c_write()
164 /* Check for error condition on the bus */ in dw_hdmi_qp_i2c_write()
165 if (i2c->stat & I2CM_NACK_RCVD_IRQ) { in dw_hdmi_qp_i2c_write()
166 dev_err(hdmi->dev, "i2c write nack!\n"); in dw_hdmi_qp_i2c_write()
168 return -EIO; in dw_hdmi_qp_i2c_write()
181 struct dw_hdmi_qp_i2c *i2c = hdmi->i2c; in dw_hdmi_qp_i2c_xfer() local
187 * The internal I2C controller does not support the multi-byte in dw_hdmi_qp_i2c_xfer()
188 * read and write operations needed for DDC/CI. in dw_hdmi_qp_i2c_xfer()
189 * FIXME: Blacklist the DDC/CI address until we filter out in dw_hdmi_qp_i2c_xfer()
190 * unsupported I2C operations. in dw_hdmi_qp_i2c_xfer()
192 return -EOPNOTSUPP; in dw_hdmi_qp_i2c_xfer()
196 dev_err(hdmi->dev, in dw_hdmi_qp_i2c_xfer()
199 return -EOPNOTSUPP; in dw_hdmi_qp_i2c_xfer()
203 guard(mutex)(&i2c->lock); in dw_hdmi_qp_i2c_xfer()
210 /* Set slave device address taken from the first I2C message */ in dw_hdmi_qp_i2c_xfer()
217 i2c->is_regaddr = false; in dw_hdmi_qp_i2c_xfer()
219 /* Set segment pointer for I2C extended read mode operation */ in dw_hdmi_qp_i2c_xfer()
220 i2c->is_segment = false; in dw_hdmi_qp_i2c_xfer()
224 i2c->is_segment = true; in dw_hdmi_qp_i2c_xfer()
263 struct dw_hdmi_qp_i2c *i2c; in dw_hdmi_qp_i2c_adapter() local
267 i2c = devm_kzalloc(hdmi->dev, sizeof(*i2c), GFP_KERNEL); in dw_hdmi_qp_i2c_adapter()
268 if (!i2c) in dw_hdmi_qp_i2c_adapter()
269 return ERR_PTR(-ENOMEM); in dw_hdmi_qp_i2c_adapter()
271 mutex_init(&i2c->lock); in dw_hdmi_qp_i2c_adapter()
272 init_completion(&i2c->cmp); in dw_hdmi_qp_i2c_adapter()
274 adap = &i2c->adap; in dw_hdmi_qp_i2c_adapter()
275 adap->owner = THIS_MODULE; in dw_hdmi_qp_i2c_adapter()
276 adap->dev.parent = hdmi->dev; in dw_hdmi_qp_i2c_adapter()
277 adap->algo = &dw_hdmi_qp_algorithm; in dw_hdmi_qp_i2c_adapter()
278 strscpy(adap->name, "DesignWare HDMI QP", sizeof(adap->name)); in dw_hdmi_qp_i2c_adapter()
282 ret = devm_i2c_add_adapter(hdmi->dev, adap); in dw_hdmi_qp_i2c_adapter()
284 dev_warn(hdmi->dev, "cannot add %s I2C adapter\n", adap->name); in dw_hdmi_qp_i2c_adapter()
285 devm_kfree(hdmi->dev, i2c); in dw_hdmi_qp_i2c_adapter()
289 hdmi->i2c = i2c; in dw_hdmi_qp_i2c_adapter()
290 dev_info(hdmi->dev, "registered %s I2C bus driver\n", adap->name); in dw_hdmi_qp_i2c_adapter()
301 dev_err(hdmi->dev, "failed to configure avi infoframe\n"); in dw_hdmi_qp_config_avi_infoframe()
302 return -EINVAL; in dw_hdmi_qp_config_avi_infoframe()
338 dev_err(hdmi->dev, "failed to configure drm infoframe\n"); in dw_hdmi_qp_config_drm_infoframe()
339 return -EINVAL; in dw_hdmi_qp_config_drm_infoframe()
367 struct dw_hdmi_qp *hdmi = bridge->driver_private; in dw_hdmi_qp_bridge_atomic_enable()
368 struct drm_atomic_state *state = old_state->base.state; in dw_hdmi_qp_bridge_atomic_enable()
373 connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); in dw_hdmi_qp_bridge_atomic_enable()
381 if (connector->display_info.is_hdmi) { in dw_hdmi_qp_bridge_atomic_enable()
382 dev_dbg(hdmi->dev, "%s mode=HDMI rate=%llu\n", in dw_hdmi_qp_bridge_atomic_enable()
383 __func__, conn_state->hdmi.tmds_char_rate); in dw_hdmi_qp_bridge_atomic_enable()
386 dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__); in dw_hdmi_qp_bridge_atomic_enable()
390 hdmi->phy.ops->init(hdmi, hdmi->phy.data); in dw_hdmi_qp_bridge_atomic_enable()
401 struct dw_hdmi_qp *hdmi = bridge->driver_private; in dw_hdmi_qp_bridge_atomic_disable()
403 hdmi->phy.ops->disable(hdmi, hdmi->phy.data); in dw_hdmi_qp_bridge_atomic_disable()
409 struct dw_hdmi_qp *hdmi = bridge->driver_private; in dw_hdmi_qp_bridge_detect()
411 return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); in dw_hdmi_qp_bridge_detect()
418 struct dw_hdmi_qp *hdmi = bridge->driver_private; in dw_hdmi_qp_bridge_edid_read()
421 drm_edid = drm_edid_read_ddc(connector, bridge->ddc); in dw_hdmi_qp_bridge_edid_read()
423 dev_dbg(hdmi->dev, "failed to get edid\n"); in dw_hdmi_qp_bridge_edid_read()
433 struct dw_hdmi_qp *hdmi = bridge->driver_private; in dw_hdmi_qp_bridge_tmds_char_rate_valid()
436 dev_dbg(hdmi->dev, "Unsupported TMDS char rate: %lld\n", rate); in dw_hdmi_qp_bridge_tmds_char_rate_valid()
446 struct dw_hdmi_qp *hdmi = bridge->driver_private; in dw_hdmi_qp_bridge_clear_infoframe()
459 dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type); in dw_hdmi_qp_bridge_clear_infoframe()
469 struct dw_hdmi_qp *hdmi = bridge->driver_private; in dw_hdmi_qp_bridge_write_infoframe()
481 dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type); in dw_hdmi_qp_bridge_write_infoframe()
502 struct dw_hdmi_qp_i2c *i2c = hdmi->i2c; in dw_hdmi_qp_main_hardirq() local
507 i2c->stat = stat & (I2CM_OP_DONE_IRQ | I2CM_READ_REQUEST_IRQ | in dw_hdmi_qp_main_hardirq()
510 if (i2c->stat) { in dw_hdmi_qp_main_hardirq()
511 dw_hdmi_qp_write(hdmi, i2c->stat, MAINUNIT_1_INT_CLEAR); in dw_hdmi_qp_main_hardirq()
512 complete(&i2c->cmp); in dw_hdmi_qp_main_hardirq()
545 if (hdmi->phy.ops->setup_hpd) in dw_hdmi_qp_init_hw()
546 hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data); in dw_hdmi_qp_init_hw()
553 struct device *dev = &pdev->dev; in dw_hdmi_qp_bind()
558 if (!plat_data->phy_ops || !plat_data->phy_ops->init || in dw_hdmi_qp_bind()
559 !plat_data->phy_ops->disable || !plat_data->phy_ops->read_hpd) { in dw_hdmi_qp_bind()
561 return ERR_PTR(-ENODEV); in dw_hdmi_qp_bind()
566 return ERR_PTR(-ENOMEM); in dw_hdmi_qp_bind()
568 hdmi->dev = dev; in dw_hdmi_qp_bind()
574 hdmi->regm = devm_regmap_init_mmio(dev, regs, &dw_hdmi_qp_regmap_config); in dw_hdmi_qp_bind()
575 if (IS_ERR(hdmi->regm)) { in dw_hdmi_qp_bind()
577 return ERR_CAST(hdmi->regm); in dw_hdmi_qp_bind()
580 hdmi->phy.ops = plat_data->phy_ops; in dw_hdmi_qp_bind()
581 hdmi->phy.data = plat_data->phy_data; in dw_hdmi_qp_bind()
585 ret = devm_request_threaded_irq(dev, plat_data->main_irq, in dw_hdmi_qp_bind()
591 hdmi->bridge.driver_private = hdmi; in dw_hdmi_qp_bind()
592 hdmi->bridge.funcs = &dw_hdmi_qp_bridge_funcs; in dw_hdmi_qp_bind()
593 hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT | in dw_hdmi_qp_bind()
597 hdmi->bridge.of_node = pdev->dev.of_node; in dw_hdmi_qp_bind()
598 hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; in dw_hdmi_qp_bind()
599 hdmi->bridge.vendor = "Synopsys"; in dw_hdmi_qp_bind()
600 hdmi->bridge.product = "DW HDMI QP TX"; in dw_hdmi_qp_bind()
602 hdmi->bridge.ddc = dw_hdmi_qp_i2c_adapter(hdmi); in dw_hdmi_qp_bind()
603 if (IS_ERR(hdmi->bridge.ddc)) in dw_hdmi_qp_bind()
604 return ERR_CAST(hdmi->bridge.ddc); in dw_hdmi_qp_bind()
606 ret = devm_drm_bridge_add(dev, &hdmi->bridge); in dw_hdmi_qp_bind()
610 ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL, in dw_hdmi_qp_bind()
625 MODULE_AUTHOR("Algea Cao <algea.cao@rock-chips.com>");