diff mbox

[RFC,3/5] ASoC: codec: hdmi drm codec driver

Message ID 1442841596-1323-4-git-send-email-arnaud.pouliquen@st.com (mailing list archive)
State New, archived
Headers show

Commit Message

Arnaud POULIQUEN Sept. 21, 2015, 1:19 p.m. UTC
Add a generic codec to interface audio with DRM drivers

Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
---
 include/sound/hdmi_drm.h    |  16 ++++++
 sound/soc/codecs/Kconfig    |   4 ++
 sound/soc/codecs/Makefile   |   2 +
 sound/soc/codecs/hdmi_drm.c | 125 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 147 insertions(+)
 create mode 100644 include/sound/hdmi_drm.h
 create mode 100644 sound/soc/codecs/hdmi_drm.c

Comments

Jyri Sarha Sept. 25, 2015, 2:11 p.m. UTC | #1
Despite my earlier comment this implementation and the related HW is 
quite similar in all significant aspects to the patch set posted couple 
of days ago [1] for Beaglebone-Black HDMI audio.

[1] http://permalink.gmane.org/gmane.linux.alsa.devel/144144

I have not yet gotten to bottom of drm-side audio bride part, but I am 
working on it. Bellow is couple of early comments to the ASoC part.

Best regards,
Jyri

On 09/21/15 16:19, Arnaud Pouliquen wrote:
> Add a generic codec to interface audio with DRM drivers
>
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
> ---
>   include/sound/hdmi_drm.h    |  16 ++++++
>   sound/soc/codecs/Kconfig    |   4 ++
>   sound/soc/codecs/Makefile   |   2 +
>   sound/soc/codecs/hdmi_drm.c | 125 ++++++++++++++++++++++++++++++++++++++++++++
>   4 files changed, 147 insertions(+)
>   create mode 100644 include/sound/hdmi_drm.h
>   create mode 100644 sound/soc/codecs/hdmi_drm.c
>
> diff --git a/include/sound/hdmi_drm.h b/include/sound/hdmi_drm.hhere are several important callbacks missing here
> new file mode 100644
> index 0000000..0146b88
> --- /dev/null
> +++ b/include/sound/hdmi_drm.h
> @@ -0,0 +1,16 @@
> +/*
> + * Interface for HDMI DRM  codec
> + *
> + * Author: Arnaud Pouliquen <arnaud.pouliquen@st.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#ifndef __HDMI_DRM__H__
> +#define __HDMI_DRM__H__
> +
> +int hdmi_drm_codec_register(struct device *dev);
> +void hdmi_drm_codec_unregister(struct device *dev);
> +
> +#endif
> diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
> index 0c9733e..922af30 100644
> --- a/sound/soc/codecs/Kconfig
> +++ b/sound/soc/codecs/Kconfig
> @@ -80,6 +80,7 @@ config SND_SOC_ALL_CODECS
>   	select SND_SOC_MC13783 if MFD_MC13XXX
>   	select SND_SOC_ML26124 if I2C
>   	select SND_SOC_HDMI_CODEC
> +	select SND_SOC_HDMI_DRM_CODEC
>   	select SND_SOC_PCM1681 if I2C
>   	select SND_SOC_PCM1792A if SPI_MASTER
>   	select SND_SOC_PCM3008
> @@ -445,6 +446,9 @@ config SND_SOC_DMIC
>   config SND_SOC_HDMI_CODEC
>          tristate "HDMI stub CODEC"
>
> +config SND_SOC_HDMI_DRM_CODEC
> +       tristate "HDMI DRM CODEC"
> +
>   config SND_SOC_ES8328
>   	tristate "Everest Semi ES8328 CODEC"
>
> diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
> index 4a32077..c92aaf7 100644
> --- a/sound/soc/codecs/Makefile
> +++ b/sound/soc/codecs/Makefile
> @@ -73,6 +73,7 @@ snd-soc-max9850-objs := max9850.o
>   snd-soc-mc13783-objs := mc13783.o
>   snd-soc-ml26124-objs := ml26124.o
>   snd-soc-hdmi-codec-objs := hdmi.o
> +snd-soc-hdmi-drm-codec-objs := hdmi_drm.o
>   snd-soc-pcm1681-objs := pcm1681.o
>   snd-soc-pcm1792a-codec-objs := pcm1792a.o
>   snd-soc-pcm3008-objs := pcm3008.o
> @@ -265,6 +266,7 @@ obj-$(CONFIG_SND_SOC_MAX9850)	+= snd-soc-max9850.o
>   obj-$(CONFIG_SND_SOC_MC13783)	+= snd-soc-mc13783.o
>   obj-$(CONFIG_SND_SOC_ML26124)	+= snd-soc-ml26124.o
>   obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
> +obj-$(CONFIG_SND_SOC_HDMI_DRM_CODEC) += snd-soc-hdmi-drm-codec.o
>   obj-$(CONFIG_SND_SOC_PCM1681)	+= snd-soc-pcm1681.o
>   obj-$(CONFIG_SND_SOC_PCM1792A)	+= snd-soc-pcm1792a-codec.o
>   obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
> diff --git a/sound/soc/codecs/hdmi_drm.c b/sound/soc/codecs/hdmi_drm.c
> new file mode 100644
> index 0000000..2df9a8f
> --- /dev/null
> +++ b/sound/soc/codecs/hdmi_drm.c
> @@ -0,0 +1,125 @@
> +/*
> + * ALSA SoC codec driver for DRM HDMI device.
> + * Copyright (C) STMicroelectronics SA 2015
> + * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
> + *          for STMicroelectronics.
> + * License terms:  GNU General Public License (GPL), version 2
> + */
> +
> +#include <linux/module.h>
> +#include <sound/soc.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +
> +#include <drm/drm_crtc_helper.h>
> +
> +struct hdmi_drm_dai_data {
> +	struct drm_bridge *bridge;
> +};here are several important callbacks missing here
> +
> +static const struct snd_soc_dapm_widget hdmi_drm_widgets[] = {
> +	SND_SOC_DAPM_OUTPUT("TX"),
> +};
> +
> +static const struct snd_soc_dapm_route hdmi_drm_routes[] = {
> +	{ "TX", NULL, "Playback" },
> +};
> +
> +int hdmi_drm_dai_prepare(struct snd_pcm_substream *substream,
> +			 struct snd_soc_dai *dai)
> +{
> +	struct hdmi_drm_dai_data *priv = snd_soc_dai_get_drvdata(dai);
> +
> +	dev_err(dai->dev, "%s: enter for bridge %p\n", __func__, priv->bridge);
> +	drm_audio_bridge_pre_enable(priv->bridge);
> +	return 0;
> +}
> +
> +int hdmi_drm_dai_trigger(struct snd_pcm_substream *substream, int cmd,
> +			 struct snd_soc_dai *dai)
> +{
> +	struct hdmi_drm_dai_data *priv = snd_soc_dai_get_drvdata(dai);
> +
> +	dev_err(dai->dev, "%s: enter\n", __func__);
> +	switch (cmd) {
> +	case SNDRV_PCM_TRIGGER_START:
> +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> +	case SNDRV_PCM_TRIGGER_RESUME:
> +		drm_audio_bridge_enable(priv->bridge);
> +		break;
> +
> +	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> +	case SNDRV_PCM_TRIGGER_STOP:
> +	case SNDRV_PCM_TRIGGER_SUSPEND:
> +		drm_audio_bridge_disable(priv->bridge);
> +		break;
> +	}
> +
> +	return 0;here are several important callbacks missing here
> +}
> +
> +static int st_hdmi_dai_probe(struct snd_soc_dai *dai)
> +{
> +	struct hdmi_drm_dai_data *priv;
> +
> +	dev_err(dai->dev, "%s: enter\n", __func__);
> +	priv = devm_kzalloc(dai->dev, sizeof(*priv), GFP_KERNEL);
> +
> +	priv->bridge = of_drm_find_bridge(dai->dev->of_node);
> +
> +	dev_err(dai->dev, "%s: bridge %p\n", __func__, priv->bridge);
> +
> +	snd_soc_dai_set_drvdata(dai, priv);
> +

The call above overwrites the private data pointer of the drivers that 
registering the codec. This hardly works in general.

A separate platform driver - with this already merged patch [2] - that I 
use with my patch-set solves this issue quite nicely.

[2] http://lists.freedesktop.org/archives/dri-devel/2015-May/083517.html
> +	return 0;
> +}here are several important callbacks missing here
> +
> +static const struct snd_soc_dai_ops hdmi_drm_codec_ops = {
> +		.prepare =  hdmi_drm_dai_prepare,
> +		.trigger = hdmi_drm_dai_trigger,
> +};


At least set_daifmt() and hw_params() callbacks should be defined before 
this could be generally usable. HDMI encoders do not usually support too 
many daifmts, but the driver should be able the check that the selected 
format is supported. But as you said this not complete code yet.

> +
> +static struct snd_soc_dai_driver hdmi_drm_codec_dai = {
> +	.name = "hdmi-hifi",
> +	.playback = {
> +		.stream_name = "Playback",
> +		.channels_min = 2,
> +		.channels_max = 8,
> +		.rates = SNDRV_PCM_RATE_32000 |
> +			SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
> +			SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
> +			SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
> +		.formats = SNDRV_PCM_FMTBIT_S16_LE |
> +			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
> +		.sig_bits = 24,
> +	},11.3
> +	.probe = st_hdmi_dai_probe,
> +	.ops = &hdmi_drm_codec_ops,
> +};
> +
> +static struct snd_soc_codec_driver hdmi_drm_codec = {
> +	.dapm_widgets = hdmi_drm_widgets,
> +	.num_dapm_widgets = ARRAY_SIZE(hdmi_drm_widgets),
> +	.dapm_routes = hdmi_drm_routes,
> +	.num_dapm_routes = ARRAY_SIZE(hdmi_drm_routes),
> +	.ignore_pmdown_time = true,
> +};
> +
> +int hdmi_drm_codec_register(struct device *dev)
> +{
> +	dev_err(dev, "%s: enter", __func__);
> +	return snd_soc_register_codec(dev, &hdmi_drm_codec,
> +				      &hdmi_drm_codec_dai, 1);
> +}
> +EXPORT_SYMBOL_GPL(hdmi_drm_codec_register);
> +
> +void hdmi_drm_codec_unregister(struct device *dev)
> +{
> +	dev_err(dev, "%s: enter", __func__);
> +	snd_soc_unregister_codec(dev);
> +}
> +EXPORT_SYMBOL_GPL(hdmi_drm_codec_unregister);
> +
> +MODULE_AUTHOR("Arnaud.pouliquen@st.com");
> +MODULE_DESCRIPTION("ASoC HDMI codec driver");
> +MODULE_LICENSE("GPL");
>
Arnaud POULIQUEN Sept. 25, 2015, 3:50 p.m. UTC | #2
Hello Jyri,

Yes using or not DRM bridge we should be able to have a common 
implementation

Please find,my answer belows

BR,
Arnaud

On 09/25/2015 04:11 PM, Jyri Sarha wrote:
> Despite my earlier comment this implementation and the related HW is
> quite similar in all significant aspects to the patch set posted couple
> of days ago [1] for Beaglebone-Black HDMI audio.
>
> [1] http://permalink.gmane.org/gmane.linux.alsa.devel/144144
yes i trying to align my dev on it. to match with your development.
Aim for me is to reuse it and adapt it using a DRM bridge interface.
i hope to provide a V2 next week.
>
> I have not yet gotten to bottom of drm-side audio bride part, but I am
> working on it. Bellow is couple of early comments to the ASoC part.
>
> Best regards,
> Jyri
>
> On 09/21/15 16:19, Arnaud Pouliquen wrote:
>> +
>> +static int st_hdmi_dai_probe(struct snd_soc_dai *dai)
>> +{
>> +	struct hdmi_drm_dai_data *priv;
>> +
>> +	dev_err(dai->dev, "%s: enter\n", __func__);
>> +	priv = devm_kzalloc(dai->dev, sizeof(*priv), GFP_KERNEL);
>> +
>> +	priv->bridge = of_drm_find_bridge(dai->dev->of_node);
>> +
>> +	dev_err(dai->dev, "%s: bridge %p\n", __func__, priv->bridge);
>> +
>> +	snd_soc_dai_set_drvdata(dai, priv);
>> +
>
> The call above overwrites the private data pointer of the drivers that
> registering the codec. This hardly works in general.
>
> A separate platform driver - with this already merged patch [2] - that I
> use with my patch-set solves this issue quite nicely.
>
> [2] http://lists.freedesktop.org/archives/dri-devel/2015-May/083517.html
Yes same dev,(but no crash...?).i need to define sub node.
>> +	return 0;
>> +}here are several important callbacks missing here
>> +
>> +static const struct snd_soc_dai_ops hdmi_drm_codec_ops = {
>> +		.prepare =  hdmi_drm_dai_prepare,
>> +		.trigger = hdmi_drm_dai_trigger,
>> +};
>
>
> At least set_daifmt() and hw_params() callbacks should be defined before
> this could be generally usable. HDMI encoders do not usually support too
> many daifmts, but the driver should be able the check that the selected
> format is supported. But as you said this not complete code yet.
I'm trying to match codec ops with following DRM audio bridge ops,
that is similar to the existing drm_bridge_funcs structure.
struct drm_audio_bridge_funcs {
	void (*disable)(struct drm_bridge *bridge);
	void (*post_disable)(struct drm_bridge *bridge);
	void (*pre_enable)(struct drm_bridge *bridge);
	void (*enable)(struct drm_bridge *bridge);
	int  (*mode_set)(struct drm_bridge *bridge,
			struct hdmi_audio_mode *mode);
	uint8_t *(*mode_get)(struct drm_bridge *bridge); /*return eld*/
};
audio parameters should be part of struct hdmi_audio_mode that contains 
audio configurations ( info frame,iec, format, clk...)
Jyri Sarha Sept. 29, 2015, 1:53 p.m. UTC | #3
On 09/25/15 18:50, Arnaud Pouliquen wrote:
> Hello Jyri,
>
> Yes using or not DRM bridge we should be able to have a common
> implementation
>
> Please find,my answer belows
>
> BR,
> Arnaud
>
> On 09/25/2015 04:11 PM, Jyri Sarha wrote:
>> Despite my earlier comment this implementation and the related HW is
>> quite similar in all significant aspects to the patch set posted couple
>> of days ago [1] for Beaglebone-Black HDMI audio.
>>
>> [1] http://permalink.gmane.org/gmane.linux.alsa.devel/144144
> yes i trying to align my dev on it. to match with your development.
> Aim for me is to reuse it and adapt it using a DRM bridge interface.
> i hope to provide a V2 next week.
>>
>> I have not yet gotten to bottom of drm-side audio bride part, but I am
>> working on it. Bellow is couple of early comments to the ASoC part.
>>
>> Best regards,
>> Jyri
>>
>> On 09/21/15 16:19, Arnaud Pouliquen wrote:
>>> +
>>> +static int st_hdmi_dai_probe(struct snd_soc_dai *dai)
>>> +{
>>> +    struct hdmi_drm_dai_data *priv;
>>> +
>>> +    dev_err(dai->dev, "%s: enter\n", __func__);
>>> +    priv = devm_kzalloc(dai->dev, sizeof(*priv), GFP_KERNEL);
>>> +
>>> +    priv->bridge = of_drm_find_bridge(dai->dev->of_node);
>>> +
>>> +    dev_err(dai->dev, "%s: bridge %p\n", __func__, priv->bridge);
>>> +
>>> +    snd_soc_dai_set_drvdata(dai, priv);
>>> +
>>
>> The call above overwrites the private data pointer of the drivers that
>> registering the codec. This hardly works in general.
>>
>> A separate platform driver - with this already merged patch [2] - that I
>> use with my patch-set solves this issue quite nicely.
>>
>> [2] http://lists.freedesktop.org/archives/dri-devel/2015-May/083517.html
> Yes same dev,(but no crash...?).i need to define sub node.
>>> +    return 0;
>>> +}here are several important callbacks missing here
>>> +
>>> +static const struct snd_soc_dai_ops hdmi_drm_codec_ops = {
>>> +        .prepare =  hdmi_drm_dai_prepare,
>>> +        .trigger = hdmi_drm_dai_trigger,
>>> +};
>>
>>
>> At least set_daifmt() and hw_params() callbacks should be defined before
>> this could be generally usable. HDMI encoders do not usually support too
>> many daifmts, but the driver should be able the check that the selected
>> format is supported. But as you said this not complete code yet.
> I'm trying to match codec ops with following DRM audio bridge ops,
> that is similar to the existing drm_bridge_funcs structure.

I am not yet too familiar with drm way of doing things. My code is 
trying to follow the way how ALSA does things. I tried to survive with 
as few callback as possible, but if you think more is needed I can add 
those if there is a corresponding callback in ALSA.

> struct drm_audio_bridge_funcs {
>      void (*disable)(struct drm_bridge *bridge);

There is no such thing in my HDMI codec. However, there is digital_mute 
callback that is used by alsa before the streams are shut down to avoid 
undesired pops and clicks.

>      void (*post_disable)(struct drm_bridge *bridge);

Post_disable should map more or less directly to audio_shutdown() in my 
code.

>      void (*pre_enable)(struct drm_bridge *bridge);

audio_startup() and hw_params() should both be called at pre_enable() 
phase.

>      void (*enable)(struct drm_bridge *bridge);

... or one could see hw_params() to map to enable. And there is 
digital_mute which is toggled by ALSA at this phase.

>      int  (*mode_set)(struct drm_bridge *bridge,
>              struct hdmi_audio_mode *mode);

Actually hw_params() does pretty much the same thing as set_mode(), but 
it should be called after audio_startup() has been called.

>      uint8_t *(*mode_get)(struct drm_bridge *bridge); /*return eld*/
> };

For this there is get_eld() in my HDMI codec code.

> audio parameters should be part of struct hdmi_audio_mode that contains
> audio configurations ( info frame,iec, format, clk...)
>
>

BTW, the HDMI codec is made in such a way that one can get by with only 
hw_params() and audio_shutdown(). In such an implementation hw_params() 
sets the HDMI encoder ready for receiving i2s or spdif from CPU DAI and 
audio_shutdown() disables the audio stream.

Best regards,
Jyri
diff mbox

Patch

diff --git a/include/sound/hdmi_drm.h b/include/sound/hdmi_drm.h
new file mode 100644
index 0000000..0146b88
--- /dev/null
+++ b/include/sound/hdmi_drm.h
@@ -0,0 +1,16 @@ 
+/*
+ * Interface for HDMI DRM  codec
+ *
+ * Author: Arnaud Pouliquen <arnaud.pouliquen@st.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __HDMI_DRM__H__
+#define __HDMI_DRM__H__
+
+int hdmi_drm_codec_register(struct device *dev);
+void hdmi_drm_codec_unregister(struct device *dev);
+
+#endif
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 0c9733e..922af30 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -80,6 +80,7 @@  config SND_SOC_ALL_CODECS
 	select SND_SOC_MC13783 if MFD_MC13XXX
 	select SND_SOC_ML26124 if I2C
 	select SND_SOC_HDMI_CODEC
+	select SND_SOC_HDMI_DRM_CODEC
 	select SND_SOC_PCM1681 if I2C
 	select SND_SOC_PCM1792A if SPI_MASTER
 	select SND_SOC_PCM3008
@@ -445,6 +446,9 @@  config SND_SOC_DMIC
 config SND_SOC_HDMI_CODEC
        tristate "HDMI stub CODEC"
 
+config SND_SOC_HDMI_DRM_CODEC
+       tristate "HDMI DRM CODEC"
+
 config SND_SOC_ES8328
 	tristate "Everest Semi ES8328 CODEC"
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 4a32077..c92aaf7 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -73,6 +73,7 @@  snd-soc-max9850-objs := max9850.o
 snd-soc-mc13783-objs := mc13783.o
 snd-soc-ml26124-objs := ml26124.o
 snd-soc-hdmi-codec-objs := hdmi.o
+snd-soc-hdmi-drm-codec-objs := hdmi_drm.o
 snd-soc-pcm1681-objs := pcm1681.o
 snd-soc-pcm1792a-codec-objs := pcm1792a.o
 snd-soc-pcm3008-objs := pcm3008.o
@@ -265,6 +266,7 @@  obj-$(CONFIG_SND_SOC_MAX9850)	+= snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_MC13783)	+= snd-soc-mc13783.o
 obj-$(CONFIG_SND_SOC_ML26124)	+= snd-soc-ml26124.o
 obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
+obj-$(CONFIG_SND_SOC_HDMI_DRM_CODEC) += snd-soc-hdmi-drm-codec.o
 obj-$(CONFIG_SND_SOC_PCM1681)	+= snd-soc-pcm1681.o
 obj-$(CONFIG_SND_SOC_PCM1792A)	+= snd-soc-pcm1792a-codec.o
 obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
diff --git a/sound/soc/codecs/hdmi_drm.c b/sound/soc/codecs/hdmi_drm.c
new file mode 100644
index 0000000..2df9a8f
--- /dev/null
+++ b/sound/soc/codecs/hdmi_drm.c
@@ -0,0 +1,125 @@ 
+/*
+ * ALSA SoC codec driver for DRM HDMI device.
+ * Copyright (C) STMicroelectronics SA 2015
+ * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
+ *          for STMicroelectronics.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/module.h>
+#include <sound/soc.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <drm/drm_crtc_helper.h>
+
+struct hdmi_drm_dai_data {
+	struct drm_bridge *bridge;
+};
+
+static const struct snd_soc_dapm_widget hdmi_drm_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("TX"),
+};
+
+static const struct snd_soc_dapm_route hdmi_drm_routes[] = {
+	{ "TX", NULL, "Playback" },
+};
+
+int hdmi_drm_dai_prepare(struct snd_pcm_substream *substream,
+			 struct snd_soc_dai *dai)
+{
+	struct hdmi_drm_dai_data *priv = snd_soc_dai_get_drvdata(dai);
+
+	dev_err(dai->dev, "%s: enter for bridge %p\n", __func__, priv->bridge);
+	drm_audio_bridge_pre_enable(priv->bridge);
+	return 0;
+}
+
+int hdmi_drm_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+			 struct snd_soc_dai *dai)
+{
+	struct hdmi_drm_dai_data *priv = snd_soc_dai_get_drvdata(dai);
+
+	dev_err(dai->dev, "%s: enter\n", __func__);
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		drm_audio_bridge_enable(priv->bridge);
+		break;
+
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		drm_audio_bridge_disable(priv->bridge);
+		break;
+	}
+
+	return 0;
+}
+
+static int st_hdmi_dai_probe(struct snd_soc_dai *dai)
+{
+	struct hdmi_drm_dai_data *priv;
+
+	dev_err(dai->dev, "%s: enter\n", __func__);
+	priv = devm_kzalloc(dai->dev, sizeof(*priv), GFP_KERNEL);
+
+	priv->bridge = of_drm_find_bridge(dai->dev->of_node);
+
+	dev_err(dai->dev, "%s: bridge %p\n", __func__, priv->bridge);
+
+	snd_soc_dai_set_drvdata(dai, priv);
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops hdmi_drm_codec_ops = {
+		.prepare =  hdmi_drm_dai_prepare,
+		.trigger = hdmi_drm_dai_trigger,
+};
+
+static struct snd_soc_dai_driver hdmi_drm_codec_dai = {
+	.name = "hdmi-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_32000 |
+			SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+			SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+			SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE |
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+		.sig_bits = 24,
+	},
+	.probe = st_hdmi_dai_probe,
+	.ops = &hdmi_drm_codec_ops,
+};
+
+static struct snd_soc_codec_driver hdmi_drm_codec = {
+	.dapm_widgets = hdmi_drm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(hdmi_drm_widgets),
+	.dapm_routes = hdmi_drm_routes,
+	.num_dapm_routes = ARRAY_SIZE(hdmi_drm_routes),
+	.ignore_pmdown_time = true,
+};
+
+int hdmi_drm_codec_register(struct device *dev)
+{
+	dev_err(dev, "%s: enter", __func__);
+	return snd_soc_register_codec(dev, &hdmi_drm_codec,
+				      &hdmi_drm_codec_dai, 1);
+}
+EXPORT_SYMBOL_GPL(hdmi_drm_codec_register);
+
+void hdmi_drm_codec_unregister(struct device *dev)
+{
+	dev_err(dev, "%s: enter", __func__);
+	snd_soc_unregister_codec(dev);
+}
+EXPORT_SYMBOL_GPL(hdmi_drm_codec_unregister);
+
+MODULE_AUTHOR("Arnaud.pouliquen@st.com");
+MODULE_DESCRIPTION("ASoC HDMI codec driver");
+MODULE_LICENSE("GPL");