hc
2023-11-22 f743a7adbd6e230d66a6206fa115b59fec2d88eb
kernel/sound/soc/codecs/hdmi-codec.c
....@@ -14,6 +14,7 @@
1414 */
1515 #include <linux/module.h>
1616 #include <linux/string.h>
17
+#include <linux/extcon-provider.h>
1718 #include <sound/core.h>
1819 #include <sound/jack.h>
1920 #include <sound/pcm.h>
....@@ -277,6 +278,11 @@
277278 .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC },
278279 };
279280
281
+static const unsigned int hdmi_extcon_cable[] = {
282
+ EXTCON_DISP_HDMI_AUDIO,
283
+ EXTCON_NONE,
284
+};
285
+
280286 struct hdmi_codec_priv {
281287 struct hdmi_codec_pdata hcd;
282288 struct snd_soc_dai_driver *daidrv;
....@@ -288,6 +294,7 @@
288294 unsigned int chmap_idx;
289295 unsigned int mode;
290296 struct snd_soc_jack *jack;
297
+ struct extcon_dev *edev;
291298 unsigned int jack_status;
292299 };
293300
....@@ -498,7 +505,8 @@
498505 WARN_ON(hcp->current_stream != substream);
499506
500507 hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN;
501
- hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data);
508
+ if (hcp->hcd.ops->audio_shutdown)
509
+ hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data);
502510
503511 mutex_lock(&hcp->current_stream_lock);
504512 hcp->current_stream = NULL;
....@@ -774,10 +782,48 @@
774782 {
775783 struct hdmi_codec_priv *hcp = dev_get_drvdata(dev);
776784
777
- if (plugged)
785
+ if (plugged) {
778786 hdmi_codec_jack_report(hcp, SND_JACK_LINEOUT);
779
- else
787
+ extcon_set_state_sync(hcp->edev,
788
+ EXTCON_DISP_HDMI_AUDIO, true);
789
+ } else {
780790 hdmi_codec_jack_report(hcp, 0);
791
+ extcon_set_state_sync(hcp->edev,
792
+ EXTCON_DISP_HDMI_AUDIO, false);
793
+ }
794
+
795
+ mutex_lock(&hcp->current_stream_lock);
796
+ if (hcp->current_stream) {
797
+ /*
798
+ * Workaround for HDMIIN and HDMIOUT plug-{in,out} when streaming.
799
+ *
800
+ * Actually, we should do stop stream both for HDMI_{OUT,IN} on
801
+ * plug-{out,in} event. but for better experience and depop stream,
802
+ * we optimize as follows:
803
+ *
804
+ * a) Do stop stream for HDMIIN on plug-out when streaming.
805
+ * because HDMIIN work as SLAVE mode, CLK lost after HDMI cable
806
+ * plugged out which will make stream stuck until ALSA timeout(10s).
807
+ * so, for better experience, we should stop stream at the moment.
808
+ *
809
+ * b) Do stop stream for HDMIOUT on plug-in when streaming.
810
+ * because HDMIOUT work as MASTER mode, there is no clk-issue like
811
+ * HDMIIN, but, on HDR situation, HDMI will be reconfigured which
812
+ * make HDMI audio configure lost, especially for NLPCM/HBR bitstream
813
+ * which require IEC937 packet alignment, so, for this situation,
814
+ * we stop stream to notify user to re-open and configure sound card
815
+ * and then go on streaming.
816
+ */
817
+ int stream = hcp->current_stream->stream;
818
+
819
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK && plugged)
820
+ snd_pcm_stop(hcp->current_stream, SNDRV_PCM_STATE_SETUP);
821
+ else if (stream == SNDRV_PCM_STREAM_CAPTURE && !plugged)
822
+ snd_pcm_stop(hcp->current_stream, SNDRV_PCM_STATE_DISCONNECTED);
823
+
824
+ dev_dbg(dev, "stream[%d]: %s\n", stream, plugged ? "plug in" : "plug out");
825
+ }
826
+ mutex_unlock(&hcp->current_stream_lock);
781827 }
782828
783829 static int hdmi_codec_set_jack(struct snd_soc_component *component,
....@@ -884,8 +930,7 @@
884930 }
885931
886932 dai_count = hcd->i2s + hcd->spdif;
887
- if (dai_count < 1 || !hcd->ops || !hcd->ops->hw_params ||
888
- !hcd->ops->audio_shutdown) {
933
+ if (dai_count < 1 || !hcd->ops || !hcd->ops->hw_params) {
889934 dev_err(dev, "%s: Invalid parameters\n", __func__);
890935 return -EINVAL;
891936 }
....@@ -916,6 +961,18 @@
916961
917962 dev_set_drvdata(dev, hcp);
918963
964
+ hcp->edev = devm_extcon_dev_allocate(&pdev->dev, hdmi_extcon_cable);
965
+ if (IS_ERR(hcp->edev)) {
966
+ dev_err(&pdev->dev, "Failed to allocate extcon device\n");
967
+ return -ENOMEM;
968
+ }
969
+
970
+ ret = devm_extcon_dev_register(&pdev->dev, hcp->edev);
971
+ if (ret < 0) {
972
+ dev_err(&pdev->dev, "Failed to register extcon device\n");
973
+ return ret;
974
+ }
975
+
919976 ret = devm_snd_soc_register_component(dev, &hdmi_driver, hcp->daidrv,
920977 dai_count);
921978 if (ret) {