[RFC PATCH 4/4] alsa/soc: add hdmi audio codec based on cdf

Rahul Sharma r.sh.open at gmail.com
Sun Jan 13 22:04:52 PST 2013


Thanks Sachin,

On Mon, Jan 14, 2013 at 11:13 AM, Sachin Kamat <sachin.kamat at linaro.org> wrote:
> +CC: ALSA mailing list, Mark Brown
>
> On 13 January 2013 18:22, Rahul Sharma <rahul.sharma at samsung.com> wrote:
>> This patch registers hdmi-audio codec to the ALSA framework. This is the second
>> client to the hdmi panel. Once notified by the CDF Core it proceeds towards
>> audio setting and audio control. It also subscribes for hpd notification to
>> implement hpd related audio requirements.
>>
>> Signed-off-by: Rahul Sharma <rahul.sharma at samsung.com>
>> ---
>>  sound/soc/codecs/Kconfig             |   4 +
>>  sound/soc/codecs/Makefile            |   2 +
>>  sound/soc/codecs/exynos_hdmi_audio.c | 307 +++++++++++++++++++++++++++++++++++
>>  3 files changed, 313 insertions(+)
>>  create mode 100644 sound/soc/codecs/exynos_hdmi_audio.c
>>
>> diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
>> index b92759a..93f3f6b 100644
>> --- a/sound/soc/codecs/Kconfig
>> +++ b/sound/soc/codecs/Kconfig
>> @@ -496,3 +496,7 @@ config SND_SOC_ML26124
>>
>>  config SND_SOC_TPA6130A2
>>         tristate
>> +
>> +config SND_SOC_EXYNOS_HDMI_AUDIO
>> +       tristate
>> +       default y
>
> Do you want to enable this by default? Shouldn't this be depending on
> HDMI support?
>

Yes, it should depend on Exynos HDMI support. I will add it in v2.

>> diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
>> index 9bd4d95..bfe93e6 100644
>> --- a/sound/soc/codecs/Makefile
>> +++ b/sound/soc/codecs/Makefile
>> @@ -112,6 +112,7 @@ snd-soc-wm9705-objs := wm9705.o
>>  snd-soc-wm9712-objs := wm9712.o
>>  snd-soc-wm9713-objs := wm9713.o
>>  snd-soc-wm-hubs-objs := wm_hubs.o
>> +snd-soc-exynos-hdmi-audio-objs := exynos_hdmi_audio.o
>>
>>  # Amp
>>  snd-soc-max9877-objs := max9877.o
>> @@ -230,6 +231,7 @@ obj-$(CONFIG_SND_SOC_WM9705)        += snd-soc-wm9705.o
>>  obj-$(CONFIG_SND_SOC_WM9712)   += snd-soc-wm9712.o
>>  obj-$(CONFIG_SND_SOC_WM9713)   += snd-soc-wm9713.o
>>  obj-$(CONFIG_SND_SOC_WM_HUBS)  += snd-soc-wm-hubs.o
>> +obj-$(CONFIG_SND_SOC_EXYNOS_HDMI_AUDIO)        += snd-soc-exynos-hdmi-audio.o
>>
>>  # Amp
>>  obj-$(CONFIG_SND_SOC_MAX9877)  += snd-soc-max9877.o
>> diff --git a/sound/soc/codecs/exynos_hdmi_audio.c b/sound/soc/codecs/exynos_hdmi_audio.c
>> new file mode 100644
>> index 0000000..50e8564
>> --- /dev/null
>> +++ b/sound/soc/codecs/exynos_hdmi_audio.c
>> @@ -0,0 +1,307 @@
>> +/*
>> + * ALSA SoC codec driver for HDMI audio on Samsung Exynos processors.
>> + * Copyright (C) 2012 Samsung corp.
>
> Copyright (c) 2012 (-13?) Samsung Electronics Co., Ltd.
>

I will correct this.

>
>> + * Author: Rahul Sharma <rahul.sharma at samsung.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.
>> + *
>> + * This program is distributed in the hope that it will be useful, but
>> + * WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * General Public License for more details.
>> + *
>> + */
>> +#include <linux/module.h>
>> +#include <linux/delay.h>
>> +#include <sound/soc.h>
>> +#include <video/display.h>
>> +#include <video/exynos_hdmi.h>
>> +#include <sound/pcm.h>
>> +#include <sound/pcm_params.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/platform_device.h>
>> +
>> +#undef dev_info
>> +
>> +#define dev_info(dev, format, arg...)          \
>> +       dev_printk(KERN_CRIT, dev, format, ##arg)
>
> You may directly use dev_crit instead of dev_printk.
>

I will clean this in v2.

>> +
>> +static struct snd_soc_codec_driver hdmi_codec;
>> +
>> +/* platform device pointer for eynos hdmi audio device. */
>> +static struct platform_device *exynos_hdmi_audio_pdev;
>> +
>> +struct hdmi_audio_context {
>> +       struct platform_device          *pdev;
>> +       atomic_t                                plugged;
>> +       struct display_entity_audio_params      audio_params;
>> +       struct display_entity           *entity;
>> +       struct display_entity_notifier  notf;
>> +       struct display_event_subscriber subscriber;
>> +};
>> +
>> +static int exynos_hdmi_audio_hw_params(struct snd_pcm_substream *substream,
>> +               struct snd_pcm_hw_params *params,
>> +               struct snd_soc_dai *dai)
>> +{
>> +       struct snd_soc_codec *codec = dai->codec;
>> +       struct hdmi_audio_context *ctx = snd_soc_codec_get_drvdata(codec);
>> +       int ret;
>> +
>> +       dev_info(codec->dev, "[%d] %s\n", __LINE__, __func__);
>
> How about making this a debug message as it does not convey anything useful?
ok.
>
>> +
>> +       ctx->audio_params.type = DISPLAY_ENTITY_AUDIO_I2S;
>> +
>> +       switch (params_channels(params)) {
>> +       case 6:
>> +       case 4:
>> +       case 2:
>> +       case 1:
>> +               ctx->audio_params.channels = params_channels(params);
>> +               break;
>> +       default:
>> +               dev_err(codec->dev, "%d channels not supported\n",
>> +                               params_channels(params));
>> +               return -EINVAL;
>> +       }
>> +
>> +       switch (params_format(params)) {
>> +       case SNDRV_PCM_FORMAT_S8:
>> +               ctx->audio_params.bits_per_sample = 8;
>> +               break;
>> +       case SNDRV_PCM_FORMAT_S16_LE:
>> +               ctx->audio_params.bits_per_sample = 12;
>> +               break;
>> +       case SNDRV_PCM_FORMAT_S24_LE:
>> +               ctx->audio_params.bits_per_sample = 16;
>> +               break;
>> +       default:
>> +               dev_err(codec->dev, "Format(%d) not supported\n",
>> +                               params_format(params));
>> +               return -EINVAL;
>> +       }
>> +
>> +       switch (params_rate(params)) {
>> +       case 32000:
>> +       case 44100:
>> +       case 88200:
>> +       case 176400:
>> +       case 48000:
>> +       case 96000:
>> +       case 192000:
>> +               ctx->audio_params.sf = params_rate(params);
>> +               break;
>> +       default:
>> +               dev_err(codec->dev, "%d Rate supported\n",
>> +                               params_rate(params));
>> +               return -EINVAL;
>> +       }
>> +
>> +       /* checking here to cache audioparms for hpd plug handling */
>> +       if (!atomic_read(&ctx->plugged))
>> +               return -EINVAL;
>> +
>> +       ret =
>> +       display_entity_hdmi_init_audio(ctx->entity, &ctx->audio_params);
>> +       return ret;
>> +}
>> +
>> +static int exynos_hdmi_audio_trigger(struct snd_pcm_substream *substream,
>> +                       int cmd, struct snd_soc_dai *dai)
>> +{
>> +       struct snd_soc_codec *codec = dai->codec;
>> +       struct hdmi_audio_context *ctx = snd_soc_codec_get_drvdata(codec);
>> +       int ret;
>> +
>> +       dev_info(codec->dev, "[%d] %s\n", __LINE__, __func__);
>
> ditto
>
>> +
>> +       /* checking here to cache audioparms for hpd plug handling */
>> +       if (!atomic_read(&ctx->plugged))
>> +               return -EINVAL;
>> +
>> +       switch (cmd) {
>> +       case SNDRV_PCM_TRIGGER_START:
>> +               ret = display_entity_hdmi_set_audiostate(ctx->entity,
>> +                       DISPLAY_ENTITY_AUDIOSTATE_ON);
>> +               if (ret) {
>> +                       dev_err(codec->dev, "audio enable failed.\n");
>> +                       return -EINVAL;
>> +               }
>> +               break;
>> +       case SNDRV_PCM_TRIGGER_STOP:
>> +               ret = display_entity_hdmi_set_audiostate(ctx->entity,
>> +                       DISPLAY_ENTITY_AUDIOSTATE_OFF);
>> +               break;
>> +       default:
>> +               ret = -EINVAL;
>> +               break;
>> +       }
>> +
>> +       return ret;
>> +}
>> +
>> +static const struct snd_soc_dai_ops exynos_hdmi_audio_dai_ops = {
>> +       .hw_params = exynos_hdmi_audio_hw_params,
>> +       .trigger = exynos_hdmi_audio_trigger,
>> +};
>> +
>> +static struct snd_soc_dai_driver hdmi_codec_dai = {
>> +       .name = "exynos-hdmi-audio",
>> +       .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,
>> +       },
>> +       .ops = &exynos_hdmi_audio_dai_ops,
>> +};
>> +
>> +void hdmi_audio_event_notify(struct display_entity *entity,
>> +               enum display_entity_event_type type,
>> +               unsigned int value, void *context)
>> +{
>> +       struct hdmi_audio_context *ctx = (struct hdmi_audio_context *)context;
>> +
>> +       if (type == DISPLAY_ENTITY_HDMI_HOTPLUG) {
>> +               dev_info(&ctx->pdev->dev, "[%d][%s] hpd(%d)\n", __LINE__,
>> +                       __func__, value);
>> +               atomic_set(&ctx->plugged, !!value);
>> +       }
>> +}
>> +
>> +int exynos_hdmi_audio_notification(struct display_entity_notifier *notf,
>> +               struct display_entity *entity, int status)
>> +{
>> +       struct hdmi_audio_context *ctx = container_of(notf,
>> +               struct hdmi_audio_context, notf);
>> +       struct exynos_hdmi_control_ops *exynos_ops =
>> +               (struct exynos_hdmi_control_ops *)entity->private;
>> +       int hpd;
>> +
>> +       if (status != DISPLAY_ENTITY_NOTIFIER_CONNECT && entity)
>> +               return -EINVAL;
>> +
>> +       dev_info(&ctx->pdev->dev, "[%d][%s]\n", __LINE__, __func__);
>> +
>> +       ctx->entity = entity;
>> +
>> +       ctx->subscriber.context = ctx;
>> +       ctx->subscriber.notify = hdmi_audio_event_notify;
>> +
>> +       display_entity_subscribe_event(entity, &ctx->subscriber);
>> +
>> +       exynos_ops->get_hpdstate(entity, &hpd);
>> +       atomic_set(&ctx->plugged, !!hpd);
>> +
>> +       return 0;
>> +}
>> +
>> +static __devinit int hdmi_codec_probe(struct platform_device *pdev)
>
> __devinit is not necessary.

ok. I will correct these.

regards,
Rahul Sharma.


>
> +{
>> +       int ret;
>> +       struct hdmi_audio_context *ctx;
>> +       struct device_node *dev_node;
>> +       struct platform_device *disp_pdev;
>> +
>> +       dev_info(&pdev->dev, "[%d][%s]\n", __LINE__, __func__);
>> +
>> +       ret = snd_soc_register_codec(&pdev->dev, &hdmi_codec,
>> +                       &hdmi_codec_dai, 1);
>> +
>> +       if (ret) {
>> +               dev_err(&pdev->dev, "register_codec failed (%d)\n", ret);
>> +               return ret;
>> +       }
>> +
>> +       ctx = devm_kzalloc(&pdev->dev, sizeof(struct hdmi_audio_context),
>> +                               GFP_KERNEL);
>> +       if (ctx == NULL)
>> +               return -ENOMEM;
>> +
>> +       ctx->pdev = pdev;
>> +       atomic_set(&ctx->plugged, 0);
>> +       platform_set_drvdata(pdev, ctx);
>> +
>> +       dev_node = of_find_compatible_node(NULL, NULL,
>> +                       "samsung,exynos5-hdmi");
>> +       if (!dev_node) {
>> +               dev_err(&pdev->dev, "[%d][%s] dt node not found.\n",
>> +                       __LINE__, __func__);
>> +               return -EINVAL;
>> +       }
>> +
>> +       disp_pdev = of_find_device_by_node(dev_node);
>> +       if (!disp_pdev) {
>> +               dev_err(&pdev->dev, "[ERROR][%d][%s] No pdev\n",
>> +                       __LINE__, __func__);
>> +               return -EINVAL;
>> +       }
>> +
>> +       ctx->notf.dev = &disp_pdev->dev;
>> +       ctx->notf.notify = exynos_hdmi_audio_notification;
>> +
>> +       ret = display_entity_register_notifier(&ctx->notf);
>> +       if (ret) {
>> +               dev_err(&pdev->dev, "[%d][%s] entity registe failed.\n",
>> +                       __LINE__, __func__);
>> +               return -EINVAL;
>> +       }
>> +       return ret;
>> +}
>> +
>> +static __devexit int hdmi_codec_remove(struct platform_device *pdev)
>
> __devexit is not necessary.
>
>
>> +{
>> +       dev_info(&pdev->dev, " %s:%s:%d", __FILE__, __func__, __LINE__);
>> +       mdelay(1000);
>> +
>> +       snd_soc_unregister_codec(&pdev->dev);
>> +       return 0;
>> +}
>> +
>> +static struct platform_driver hdmi_codec_driver = {
>> +       .driver         = {
>> +               .name   = "exynos-hdmi-audio-codec",
>> +               .owner  = THIS_MODULE,
>> +       },
>> +
>> +       .probe          = hdmi_codec_probe,
>> +       .remove         = __devexit_p(hdmi_codec_remove),
>> +};
>> +
>> +static int __init hdmi_codec_init(void)
>> +{
>> +       int ret;
>> +
>> +       ret = platform_driver_register(&hdmi_codec_driver);
>> +       if (ret < 0)
>> +               return -EINVAL;
>> +
>> +       exynos_hdmi_audio_pdev = platform_device_register_simple
>> +               ("exynos-hdmi-audio-codec", -1, NULL, 0);
>> +       if (IS_ERR_OR_NULL(exynos_hdmi_audio_pdev)) {
>> +               ret = PTR_ERR(exynos_hdmi_audio_pdev);
>> +               platform_driver_unregister(&hdmi_codec_driver);
>> +               return ret;
>> +       }
>> +
>> +       return 0;
>> +}
>> +static void __exit hdmi_codec_exit(void)
>> +{
>> +       platform_driver_unregister(&hdmi_codec_driver);
>> +       platform_device_unregister(exynos_hdmi_audio_pdev);
>> +}
>> +
>> +module_init(hdmi_codec_init);
>> +module_exit(hdmi_codec_exit);
>> +
>> +MODULE_AUTHOR("Rahul Sharma <rahul.sharma at samsung.com>");
>> +MODULE_DESCRIPTION("ASoC EXYNOS HDMI codec driver");
>> +MODULE_LICENSE("GPL");
>> +MODULE_ALIAS("platform:" DRV_NAME);
>> --
>> 1.8.0
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-media" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>
>
> --
> With warm regards,
> Sachin


More information about the dri-devel mailing list