Lines Matching +full:i2s +full:- +full:transmitter +full:- +full:1

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>
29 #include <sound/hdmi-codec.h>
31 #include "dw-hdmi-qp.h"
43 * slow so we pre-compute values we expect to see.
153 regmap_write(hdmi->regm, offset, val); in dw_hdmi_qp_write()
160 regmap_read(hdmi->regm, offset, &val); in dw_hdmi_qp_read()
168 regmap_update_bits(hdmi->regm, reg, mask, data); in dw_hdmi_qp_mod()
209 return -ENOENT; in dw_hdmi_qp_match_tmds_n_table()
213 return tmds_n->n_32k; in dw_hdmi_qp_match_tmds_n_table()
217 return (freq / 44100) * tmds_n->n_44k1; in dw_hdmi_qp_match_tmds_n_table()
221 return (freq / 48000) * tmds_n->n_48k; in dw_hdmi_qp_match_tmds_n_table()
223 return -ENOENT; in dw_hdmi_qp_match_tmds_n_table()
255 (diff == best_diff && abs(n - ideal_n) < best_n_distance)) { in dw_hdmi_qp_compute_n()
258 best_n_distance = abs(best_n - ideal_n); in dw_hdmi_qp_compute_n()
265 if (best_diff == 0 && (abs(n - ideal_n) > best_n_distance)) in dw_hdmi_qp_compute_n()
280 dev_warn(hdmi->dev, "Rate %lu missing; compute N dynamically\n", in dw_hdmi_qp_find_n()
304 return tmds_cts->cts_32k; in dw_hdmi_qp_find_cts()
308 return tmds_cts->cts_44k1; in dw_hdmi_qp_find_cts()
312 return tmds_cts->cts_48k; in dw_hdmi_qp_find_cts()
314 return -ENOENT; in dw_hdmi_qp_find_cts()
335 /* Select I2S interface as the audio source */ in dw_hdmi_qp_set_audio_interface()
338 /* Enable the active i2s lanes */ in dw_hdmi_qp_set_audio_interface()
339 switch (hparms->channels) { in dw_hdmi_qp_set_audio_interface()
347 conf0 |= I2S_LINES_EN(1); in dw_hdmi_qp_set_audio_interface()
357 * Enable bpcuv generated internally for L-PCM, or received in dw_hdmi_qp_set_audio_interface()
360 switch (fmt->bit_fmt) { in dw_hdmi_qp_set_audio_interface()
362 conf0 = (hparms->channels == 8) ? AUD_HBR : AUD_ASP; in dw_hdmi_qp_set_audio_interface()
382 * used when the I2S audio interface, General Purpose Audio (GPA),
393 * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | in dw_hdmi_qp_set_channel_status()
399 * CS5: | | CGMS-A | in dw_hdmi_qp_set_channel_status()
403 * b: linear PCM identification: 0 for lpcm, 1 for nlpcm in dw_hdmi_qp_set_channel_status()
417 dw_hdmi_qp_write(hdmi, channel_status[0] | (channel_status[1] << 8), in dw_hdmi_qp_set_channel_status()
420 regmap_bulk_write(hdmi->regm, AUDPKT_CHSTATUS_OVR1, &channel_status[3], 1); in dw_hdmi_qp_set_channel_status()
448 if (hdmi->tmds_char_rate) in dw_hdmi_qp_audio_enable()
462 if (!hdmi->tmds_char_rate) in dw_hdmi_qp_audio_prepare()
463 return -ENODEV; in dw_hdmi_qp_audio_prepare()
465 if (fmt->bit_clk_provider | fmt->frame_clk_provider) { in dw_hdmi_qp_audio_prepare()
466 dev_err(hdmi->dev, "unsupported clock settings\n"); in dw_hdmi_qp_audio_prepare()
467 return -EINVAL; in dw_hdmi_qp_audio_prepare()
470 if (fmt->bit_fmt == SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE) in dw_hdmi_qp_audio_prepare()
474 dw_hdmi_qp_set_sample_rate(hdmi, hdmi->tmds_char_rate, hparms->sample_rate); in dw_hdmi_qp_audio_prepare()
475 dw_hdmi_qp_set_channel_status(hdmi, hparms->iec.status, ref2stream); in dw_hdmi_qp_audio_prepare()
476 drm_atomic_helper_connector_hdmi_update_audio_infoframe(connector, &hparms->cea); in dw_hdmi_qp_audio_prepare()
507 if (hdmi->tmds_char_rate) in dw_hdmi_qp_audio_disable()
514 struct dw_hdmi_qp_i2c *i2c = hdmi->i2c; in dw_hdmi_qp_i2c_read()
517 if (!i2c->is_regaddr) { in dw_hdmi_qp_i2c_read()
518 dev_dbg(hdmi->dev, "set read register address to 0\n"); in dw_hdmi_qp_i2c_read()
519 i2c->slave_reg = 0x00; in dw_hdmi_qp_i2c_read()
520 i2c->is_regaddr = true; in dw_hdmi_qp_i2c_read()
523 while (length--) { in dw_hdmi_qp_i2c_read()
524 reinit_completion(&i2c->cmp); in dw_hdmi_qp_i2c_read()
526 dw_hdmi_qp_mod(hdmi, i2c->slave_reg++ << 12, I2CM_ADDR, in dw_hdmi_qp_i2c_read()
529 if (i2c->is_segment) in dw_hdmi_qp_i2c_read()
536 stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); in dw_hdmi_qp_i2c_read()
538 dev_err(hdmi->dev, "i2c read timed out\n"); in dw_hdmi_qp_i2c_read()
540 return -EAGAIN; in dw_hdmi_qp_i2c_read()
544 if (i2c->stat & I2CM_NACK_RCVD_IRQ) { in dw_hdmi_qp_i2c_read()
545 dev_err(hdmi->dev, "i2c read error\n"); in dw_hdmi_qp_i2c_read()
547 return -EIO; in dw_hdmi_qp_i2c_read()
554 i2c->is_segment = false; in dw_hdmi_qp_i2c_read()
562 struct dw_hdmi_qp_i2c *i2c = hdmi->i2c; in dw_hdmi_qp_i2c_write()
565 if (!i2c->is_regaddr) { in dw_hdmi_qp_i2c_write()
567 i2c->slave_reg = buf[0]; in dw_hdmi_qp_i2c_write()
568 length--; in dw_hdmi_qp_i2c_write()
570 i2c->is_regaddr = true; in dw_hdmi_qp_i2c_write()
573 while (length--) { in dw_hdmi_qp_i2c_write()
574 reinit_completion(&i2c->cmp); in dw_hdmi_qp_i2c_write()
577 dw_hdmi_qp_mod(hdmi, i2c->slave_reg++ << 12, I2CM_ADDR, in dw_hdmi_qp_i2c_write()
582 stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10); in dw_hdmi_qp_i2c_write()
584 dev_err(hdmi->dev, "i2c write time out!\n"); in dw_hdmi_qp_i2c_write()
586 return -EAGAIN; in dw_hdmi_qp_i2c_write()
590 if (i2c->stat & I2CM_NACK_RCVD_IRQ) { in dw_hdmi_qp_i2c_write()
591 dev_err(hdmi->dev, "i2c write nack!\n"); in dw_hdmi_qp_i2c_write()
593 return -EIO; in dw_hdmi_qp_i2c_write()
606 struct dw_hdmi_qp_i2c *i2c = hdmi->i2c; in dw_hdmi_qp_i2c_xfer()
612 * The internal I2C controller does not support the multi-byte in dw_hdmi_qp_i2c_xfer()
617 return -EOPNOTSUPP; in dw_hdmi_qp_i2c_xfer()
621 dev_err(hdmi->dev, in dw_hdmi_qp_i2c_xfer()
623 i + 1, num); in dw_hdmi_qp_i2c_xfer()
624 return -EOPNOTSUPP; in dw_hdmi_qp_i2c_xfer()
628 guard(mutex)(&i2c->lock); in dw_hdmi_qp_i2c_xfer()
636 if (addr == DDC_SEGMENT_ADDR && msgs[0].len == 1) in dw_hdmi_qp_i2c_xfer()
642 i2c->is_regaddr = false; in dw_hdmi_qp_i2c_xfer()
645 i2c->is_segment = false; in dw_hdmi_qp_i2c_xfer()
648 if (msgs[i].addr == DDC_SEGMENT_ADDR && msgs[i].len == 1) { in dw_hdmi_qp_i2c_xfer()
649 i2c->is_segment = true; in dw_hdmi_qp_i2c_xfer()
692 i2c = devm_kzalloc(hdmi->dev, sizeof(*i2c), GFP_KERNEL); in dw_hdmi_qp_i2c_adapter()
694 return ERR_PTR(-ENOMEM); in dw_hdmi_qp_i2c_adapter()
696 mutex_init(&i2c->lock); in dw_hdmi_qp_i2c_adapter()
697 init_completion(&i2c->cmp); in dw_hdmi_qp_i2c_adapter()
699 adap = &i2c->adap; in dw_hdmi_qp_i2c_adapter()
700 adap->owner = THIS_MODULE; in dw_hdmi_qp_i2c_adapter()
701 adap->dev.parent = hdmi->dev; in dw_hdmi_qp_i2c_adapter()
702 adap->algo = &dw_hdmi_qp_algorithm; in dw_hdmi_qp_i2c_adapter()
703 strscpy(adap->name, "DesignWare HDMI QP", sizeof(adap->name)); in dw_hdmi_qp_i2c_adapter()
707 ret = devm_i2c_add_adapter(hdmi->dev, adap); in dw_hdmi_qp_i2c_adapter()
709 dev_warn(hdmi->dev, "cannot add %s I2C adapter\n", adap->name); in dw_hdmi_qp_i2c_adapter()
710 devm_kfree(hdmi->dev, i2c); in dw_hdmi_qp_i2c_adapter()
714 hdmi->i2c = i2c; in dw_hdmi_qp_i2c_adapter()
715 dev_info(hdmi->dev, "registered %s I2C bus driver\n", adap->name); in dw_hdmi_qp_i2c_adapter()
726 dev_err(hdmi->dev, "failed to configure avi infoframe\n"); in dw_hdmi_qp_config_avi_infoframe()
727 return -EINVAL; in dw_hdmi_qp_config_avi_infoframe()
734 val = buffer[1] << 8 | buffer[2] << 16; in dw_hdmi_qp_config_avi_infoframe()
763 dev_err(hdmi->dev, "failed to configure drm infoframe\n"); in dw_hdmi_qp_config_drm_infoframe()
764 return -EINVAL; in dw_hdmi_qp_config_drm_infoframe()
769 val = buffer[1] << 8 | buffer[2] << 16; in dw_hdmi_qp_config_drm_infoframe()
818 regmap_bulk_write(hdmi->regm, PKT_AUDI_CONTENTS0, &header_bytes, 1); in dw_hdmi_qp_config_audio_infoframe()
819 regmap_bulk_write(hdmi->regm, PKT_AUDI_CONTENTS1, &buffer[3], 1); in dw_hdmi_qp_config_audio_infoframe()
820 regmap_bulk_write(hdmi->regm, PKT_AUDI_CONTENTS2, &buffer[4], 1); in dw_hdmi_qp_config_audio_infoframe()
837 struct dw_hdmi_qp *hdmi = bridge->driver_private; in dw_hdmi_qp_bridge_atomic_enable()
842 connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder); in dw_hdmi_qp_bridge_atomic_enable()
850 if (connector->display_info.is_hdmi) { in dw_hdmi_qp_bridge_atomic_enable()
851 dev_dbg(hdmi->dev, "%s mode=HDMI rate=%llu\n", in dw_hdmi_qp_bridge_atomic_enable()
852 __func__, conn_state->hdmi.tmds_char_rate); in dw_hdmi_qp_bridge_atomic_enable()
854 hdmi->tmds_char_rate = conn_state->hdmi.tmds_char_rate; in dw_hdmi_qp_bridge_atomic_enable()
856 dev_dbg(hdmi->dev, "%s mode=DVI\n", __func__); in dw_hdmi_qp_bridge_atomic_enable()
860 hdmi->phy.ops->init(hdmi, hdmi->phy.data); in dw_hdmi_qp_bridge_atomic_enable()
871 struct dw_hdmi_qp *hdmi = bridge->driver_private; in dw_hdmi_qp_bridge_atomic_disable()
873 hdmi->tmds_char_rate = 0; in dw_hdmi_qp_bridge_atomic_disable()
875 hdmi->phy.ops->disable(hdmi, hdmi->phy.data); in dw_hdmi_qp_bridge_atomic_disable()
881 struct dw_hdmi_qp *hdmi = bridge->driver_private; in dw_hdmi_qp_bridge_detect()
883 return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); in dw_hdmi_qp_bridge_detect()
890 struct dw_hdmi_qp *hdmi = bridge->driver_private; in dw_hdmi_qp_bridge_edid_read()
893 drm_edid = drm_edid_read_ddc(connector, bridge->ddc); in dw_hdmi_qp_bridge_edid_read()
895 dev_dbg(hdmi->dev, "failed to get edid\n"); in dw_hdmi_qp_bridge_edid_read()
905 struct dw_hdmi_qp *hdmi = bridge->driver_private; in dw_hdmi_qp_bridge_tmds_char_rate_valid()
908 dev_dbg(hdmi->dev, "Unsupported TMDS char rate: %lld\n", rate); in dw_hdmi_qp_bridge_tmds_char_rate_valid()
918 struct dw_hdmi_qp *hdmi = bridge->driver_private; in dw_hdmi_qp_bridge_clear_infoframe()
938 dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type); in dw_hdmi_qp_bridge_clear_infoframe()
948 struct dw_hdmi_qp *hdmi = bridge->driver_private; in dw_hdmi_qp_bridge_write_infoframe()
963 dev_dbg(hdmi->dev, "Unsupported infoframe type %x\n", type); in dw_hdmi_qp_bridge_write_infoframe()
987 struct dw_hdmi_qp_i2c *i2c = hdmi->i2c; in dw_hdmi_qp_main_hardirq()
992 i2c->stat = stat & (I2CM_OP_DONE_IRQ | I2CM_READ_REQUEST_IRQ | in dw_hdmi_qp_main_hardirq()
995 if (i2c->stat) { in dw_hdmi_qp_main_hardirq()
996 dw_hdmi_qp_write(hdmi, i2c->stat, MAINUNIT_1_INT_CLEAR); in dw_hdmi_qp_main_hardirq()
997 complete(&i2c->cmp); in dw_hdmi_qp_main_hardirq()
1030 if (hdmi->phy.ops->setup_hpd) in dw_hdmi_qp_init_hw()
1031 hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data); in dw_hdmi_qp_init_hw()
1038 struct device *dev = &pdev->dev; in dw_hdmi_qp_bind()
1043 if (!plat_data->phy_ops || !plat_data->phy_ops->init || in dw_hdmi_qp_bind()
1044 !plat_data->phy_ops->disable || !plat_data->phy_ops->read_hpd) { in dw_hdmi_qp_bind()
1046 return ERR_PTR(-ENODEV); in dw_hdmi_qp_bind()
1054 hdmi->dev = dev; in dw_hdmi_qp_bind()
1060 hdmi->regm = devm_regmap_init_mmio(dev, regs, &dw_hdmi_qp_regmap_config); in dw_hdmi_qp_bind()
1061 if (IS_ERR(hdmi->regm)) { in dw_hdmi_qp_bind()
1063 return ERR_CAST(hdmi->regm); in dw_hdmi_qp_bind()
1066 hdmi->phy.ops = plat_data->phy_ops; in dw_hdmi_qp_bind()
1067 hdmi->phy.data = plat_data->phy_data; in dw_hdmi_qp_bind()
1071 ret = devm_request_threaded_irq(dev, plat_data->main_irq, in dw_hdmi_qp_bind()
1077 hdmi->bridge.driver_private = hdmi; in dw_hdmi_qp_bind()
1078 hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT | in dw_hdmi_qp_bind()
1083 hdmi->bridge.of_node = pdev->dev.of_node; in dw_hdmi_qp_bind()
1084 hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA; in dw_hdmi_qp_bind()
1085 hdmi->bridge.vendor = "Synopsys"; in dw_hdmi_qp_bind()
1086 hdmi->bridge.product = "DW HDMI QP TX"; in dw_hdmi_qp_bind()
1088 hdmi->bridge.ddc = dw_hdmi_qp_i2c_adapter(hdmi); in dw_hdmi_qp_bind()
1089 if (IS_ERR(hdmi->bridge.ddc)) in dw_hdmi_qp_bind()
1090 return ERR_CAST(hdmi->bridge.ddc); in dw_hdmi_qp_bind()
1092 hdmi->bridge.hdmi_audio_max_i2s_playback_channels = 8; in dw_hdmi_qp_bind()
1093 hdmi->bridge.hdmi_audio_dev = dev; in dw_hdmi_qp_bind()
1094 hdmi->bridge.hdmi_audio_dai_port = 1; in dw_hdmi_qp_bind()
1096 ret = devm_drm_bridge_add(dev, &hdmi->bridge); in dw_hdmi_qp_bind()
1100 ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL, in dw_hdmi_qp_bind()
1115 MODULE_AUTHOR("Algea Cao <algea.cao@rock-chips.com>");
1117 MODULE_DESCRIPTION("DW HDMI QP transmitter library");