+CC: ALSA mailing list, Mark Brown On 13 January 2013 18:22, Rahul Sharma <rahul.sharma@xxxxxxxxxxx> 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@xxxxxxxxxxx> > --- > 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? > 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. > + * Author: Rahul Sharma <rahul.sharma@xxxxxxxxxxx> > + * > + * 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. > + > +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? > + > + 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. +{ > + 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@xxxxxxxxxxx>"); > +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@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- With warm regards, Sachin -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html