Add audio support for it6505

1. Bridge to hdmi-codec to support audio feature. At the same time,
   the function of automatically detecting audio is removed.
2. It is observed that some DP-to-HDMI dongles will get into bad
   states if sending InfoFrame without audio data. Defer to enable
   it6505's audio feature when PCM triggers START or RESUME.

Signed-off-by: Jiaxin Yu <jiaxin...@mediatek.com>
---
 drivers/gpu/drm/bridge/ite-it6505.c | 81 ++++++++++++++++++++++++++---
 1 file changed, 75 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/bridge/ite-it6505.c 
b/drivers/gpu/drm/bridge/ite-it6505.c
index 504d51c42f79..1cfcb0731288 100644
--- a/drivers/gpu/drm/bridge/ite-it6505.c
+++ b/drivers/gpu/drm/bridge/ite-it6505.c
@@ -2162,7 +2162,6 @@ static void it6505_stop_link_train(struct it6505 *it6505)
 
 static void it6505_link_train_ok(struct it6505 *it6505)
 {
-       struct device *dev = &it6505->client->dev;
 
        it6505->link_state = LINK_OK;
        /* disalbe mute enable avi info frame */
@@ -2170,11 +2169,6 @@ static void it6505_link_train_ok(struct it6505 *it6505)
        it6505_set_bits(it6505, REG_INFOFRAME_CTRL,
                        EN_VID_CTRL_PKT, EN_VID_CTRL_PKT);
 
-       if (it6505_audio_input(it6505)) {
-               DRM_DEV_DEBUG_DRIVER(dev, "Enable audio!");
-               it6505_enable_audio(it6505);
-       }
-
        if (it6505->hdcp_desired)
                it6505_start_hdcp(it6505);
 }
@@ -2846,6 +2840,45 @@ static void __maybe_unused it6505_audio_shutdown(struct 
device *dev, void *data)
                it6505_disable_audio(it6505);
 }
 
+static int it6505_audio_hw_params(struct device *dev, void *data,
+                                 struct hdmi_codec_daifmt *daifmt,
+                                 struct hdmi_codec_params *params)
+{
+       struct it6505 *it6505 = dev_get_drvdata(dev);
+
+       return it6505_audio_setup_hw_params(it6505, params);
+}
+
+static int it6505_audio_setup_trigger(struct it6505 *it6505, int cmd)
+{
+       struct device *dev = &it6505->client->dev;
+
+       DRM_DEV_DEBUG_DRIVER(dev, "event: %d", cmd);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               queue_delayed_work(system_wq, &it6505->delayed_audio,
+                                  msecs_to_jiffies(180));
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+               cancel_delayed_work(&it6505->delayed_audio);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int it6505_audio_trigger(struct device *dev, int cmd)
+{
+       struct it6505 *it6505 = dev_get_drvdata(dev);
+
+       return it6505_audio_setup_trigger(it6505, cmd);
+}
+
 static int __maybe_unused it6505_audio_hook_plugged_cb(struct device *dev,
                                                       void *data,
                                                       hdmi_codec_plugged_cb fn,
@@ -2860,6 +2893,36 @@ static int __maybe_unused 
it6505_audio_hook_plugged_cb(struct device *dev,
        return 0;
 }
 
+static const struct hdmi_codec_ops it6505_audio_codec_ops = {
+       .hw_params = it6505_audio_hw_params,
+       .trigger = it6505_audio_trigger,
+       .audio_shutdown = it6505_audio_shutdown,
+       .hook_plugged_cb = it6505_audio_hook_plugged_cb,
+};
+
+static int it6505_register_audio_driver(struct device *dev)
+{
+       struct it6505 *it6505 = dev_get_drvdata(dev);
+       struct hdmi_codec_pdata codec_data = {
+               .ops = &it6505_audio_codec_ops,
+               .max_i2s_channels = 8,
+               .i2s = 1,
+               .data = it6505,
+       };
+       struct platform_device *pdev;
+
+       pdev = platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
+                                            PLATFORM_DEVID_AUTO, &codec_data,
+                                            sizeof(codec_data));
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
+
+       INIT_DELAYED_WORK(&it6505->delayed_audio, it6505_delayed_audio);
+       DRM_DEV_DEBUG_DRIVER(dev, "bound to %s", HDMI_CODEC_DRV_NAME);
+
+       return 0;
+}
+
 static inline struct it6505 *bridge_to_it6505(struct drm_bridge *bridge)
 {
        return container_of(bridge, struct it6505, bridge);
@@ -3421,6 +3484,12 @@ static int it6505_i2c_probe(struct i2c_client *client)
                return err;
        }
 
+       err = it6505_register_audio_driver(dev);
+       if (err < 0) {
+               DRM_DEV_ERROR(dev, "Failed to register audio driver: %d", err);
+               return err;
+       }
+
        INIT_WORK(&it6505->link_works, it6505_link_training_work);
        INIT_WORK(&it6505->hdcp_wait_ksv_list, it6505_hdcp_wait_ksv_list);
        INIT_DELAYED_WORK(&it6505->hdcp_work, it6505_hdcp_work);
-- 
2.25.1

Reply via email to