While LT9611UXC is a DSI-to-HDMI bridge, it implements all HDMI-related
functions internally, in the firmware, thus it doesn't make sense to
implement DRM_BRIDGE_OP_HDMI. However it is possible to implement
DRM_BRIDGE_OP_HDMI_AUDIO, streamlining HDMI audio plumbing (which
includes plugged notifications and ELD handling).

Implement corresponding callbacks and trigger EDID read /
drm_connector_hdmi_audio_plugged_notify() from the hpd_notify callback.

Signed-off-by: Dmitry Baryshkov <dmitry.barysh...@oss.qualcomm.com>
---
 drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 125 +++++++++++------------------
 1 file changed, 49 insertions(+), 76 deletions(-)

diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c 
b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
index 
38fb8776c0f441ae433c60a7680aaa6501a8956e..11aab07d88df646a54fea287030a183eb823b26d
 100644
--- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
+++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
@@ -17,8 +17,6 @@
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 
-#include <sound/hdmi-codec.h>
-
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_bridge.h>
 #include <drm/drm_edid.h>
@@ -27,6 +25,8 @@
 #include <drm/drm_print.h>
 #include <drm/drm_probe_helper.h>
 
+#include <drm/display/drm_hdmi_audio_helper.h>
+
 #define EDID_BLOCK_SIZE        128
 #define EDID_NUM_BLOCKS        2
 
@@ -48,7 +48,6 @@ struct lt9611uxc {
        struct device_node *dsi1_node;
        struct mipi_dsi_device *dsi0;
        struct mipi_dsi_device *dsi1;
-       struct platform_device *audio_pdev;
 
        struct gpio_desc *reset_gpio;
        struct gpio_desc *enable_gpio;
@@ -429,12 +428,52 @@ static const struct drm_edid 
*lt9611uxc_bridge_edid_read(struct drm_bridge *brid
        return drm_edid_read_custom(connector, lt9611uxc_get_edid_block, 
lt9611uxc);
 }
 
+static void lt9611uxc_bridge_hpd_notify(struct drm_bridge *bridge,
+                                       struct drm_connector *connector,
+                                       enum drm_connector_status status)
+{
+       const struct drm_edid *drm_edid;
+
+       if (status == connector_status_disconnected) {
+               drm_connector_hdmi_audio_plugged_notify(connector, false);
+               drm_edid_connector_update(connector, NULL);
+               return;
+       }
+
+       drm_edid = lt9611uxc_bridge_edid_read(bridge, connector);
+       drm_edid_connector_update(connector, drm_edid);
+       drm_edid_free(drm_edid);
+
+       if (status == connector_status_connected)
+               drm_connector_hdmi_audio_plugged_notify(connector, true);
+}
+
+static int lt9611uxc_hdmi_audio_prepare(struct drm_bridge *bridge,
+                                       struct drm_connector *connector,
+                                       struct hdmi_codec_daifmt *fmt,
+                                       struct hdmi_codec_params *hparms)
+{
+       /*
+        * LT9611UXC will automatically detect rate and sample size, so no need
+        * to setup anything here.
+        */
+       return 0;
+}
+
+static void lt9611uxc_hdmi_audio_shutdown(struct drm_bridge *bridge,
+                                         struct drm_connector *connector)
+{
+}
+
 static const struct drm_bridge_funcs lt9611uxc_bridge_funcs = {
        .attach = lt9611uxc_bridge_attach,
        .mode_valid = lt9611uxc_bridge_mode_valid,
        .mode_set = lt9611uxc_bridge_mode_set,
        .detect = lt9611uxc_bridge_detect,
        .edid_read = lt9611uxc_bridge_edid_read,
+       .hpd_notify = lt9611uxc_bridge_hpd_notify,
+       .hdmi_audio_prepare = lt9611uxc_hdmi_audio_prepare,
+       .hdmi_audio_shutdown = lt9611uxc_hdmi_audio_shutdown,
 };
 
 static int lt9611uxc_parse_dt(struct device *dev,
@@ -508,73 +547,6 @@ static int lt9611uxc_read_version(struct lt9611uxc 
*lt9611uxc)
        return ret < 0 ? ret : rev;
 }
 
-static int lt9611uxc_hdmi_hw_params(struct device *dev, void *data,
-                                   struct hdmi_codec_daifmt *fmt,
-                                   struct hdmi_codec_params *hparms)
-{
-       /*
-        * LT9611UXC will automatically detect rate and sample size, so no need
-        * to setup anything here.
-        */
-       return 0;
-}
-
-static void lt9611uxc_audio_shutdown(struct device *dev, void *data)
-{
-}
-
-static int lt9611uxc_hdmi_i2s_get_dai_id(struct snd_soc_component *component,
-                                        struct device_node *endpoint,
-                                        void *data)
-{
-       struct of_endpoint of_ep;
-       int ret;
-
-       ret = of_graph_parse_endpoint(endpoint, &of_ep);
-       if (ret < 0)
-               return ret;
-
-       /*
-        * HDMI sound should be located as reg = <2>
-        * Then, it is sound port 0
-        */
-       if (of_ep.port == 2)
-               return 0;
-
-       return -EINVAL;
-}
-
-static const struct hdmi_codec_ops lt9611uxc_codec_ops = {
-       .hw_params      = lt9611uxc_hdmi_hw_params,
-       .audio_shutdown = lt9611uxc_audio_shutdown,
-       .get_dai_id     = lt9611uxc_hdmi_i2s_get_dai_id,
-};
-
-static int lt9611uxc_audio_init(struct device *dev, struct lt9611uxc 
*lt9611uxc)
-{
-       struct hdmi_codec_pdata codec_data = {
-               .ops = &lt9611uxc_codec_ops,
-               .max_i2s_channels = 2,
-               .i2s = 1,
-               .data = lt9611uxc,
-       };
-
-       lt9611uxc->audio_pdev =
-               platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
-                                             PLATFORM_DEVID_AUTO,
-                                             &codec_data, sizeof(codec_data));
-
-       return PTR_ERR_OR_ZERO(lt9611uxc->audio_pdev);
-}
-
-static void lt9611uxc_audio_exit(struct lt9611uxc *lt9611uxc)
-{
-       if (lt9611uxc->audio_pdev) {
-               platform_device_unregister(lt9611uxc->audio_pdev);
-               lt9611uxc->audio_pdev = NULL;
-       }
-}
-
 #define LT9611UXC_FW_PAGE_SIZE 32
 static void lt9611uxc_firmware_write_page(struct lt9611uxc *lt9611uxc, u16 
addr, const u8 *buf)
 {
@@ -858,11 +830,17 @@ static int lt9611uxc_probe(struct i2c_client *client)
        i2c_set_clientdata(client, lt9611uxc);
 
        lt9611uxc->bridge.of_node = client->dev.of_node;
-       lt9611uxc->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID;
+       lt9611uxc->bridge.ops = DRM_BRIDGE_OP_DETECT |
+               DRM_BRIDGE_OP_EDID |
+               DRM_BRIDGE_OP_HDMI_AUDIO;
        if (lt9611uxc->hpd_supported)
                lt9611uxc->bridge.ops |= DRM_BRIDGE_OP_HPD;
        lt9611uxc->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
 
+       lt9611uxc->bridge.hdmi_audio_dev = dev;
+       lt9611uxc->bridge.hdmi_audio_max_i2s_playback_channels = 2;
+       lt9611uxc->bridge.hdmi_audio_dai_port = 2;
+
        drm_bridge_add(&lt9611uxc->bridge);
 
        /* Attach primary DSI */
@@ -881,10 +859,6 @@ static int lt9611uxc_probe(struct i2c_client *client)
                }
        }
 
-       ret = lt9611uxc_audio_init(dev, lt9611uxc);
-       if (ret)
-               goto err_remove_bridge;
-
        return 0;
 
 err_remove_bridge:
@@ -908,7 +882,6 @@ static void lt9611uxc_remove(struct i2c_client *client)
 
        free_irq(client->irq, lt9611uxc);
        cancel_work_sync(&lt9611uxc->work);
-       lt9611uxc_audio_exit(lt9611uxc);
        drm_bridge_remove(&lt9611uxc->bridge);
 
        mutex_destroy(&lt9611uxc->ocm_lock);

-- 
2.39.5

Reply via email to