asoc/exynos: dapm switch added for hdmi audio
authorRahul Sharma <rahul.sharma@samsung.com>
Wed, 29 Aug 2012 13:34:51 +0000 (19:04 +0530)
committerGerrit <chrome-bot@google.com>
Fri, 14 Sep 2012 21:46:11 +0000 (14:46 -0700)
i2s card is modified to add dapm switch for hdmi-audio. Without
this change in place audio will be heard from speakers as well as
hdmi output. This switch needs to be toggled from the user space
for enabling disabling hdmi audio.

BUG=none
TEST=verified various audio files using amixer
application.

Change-Id: I1e30ec316f1dbe2bf3d03ab7c42d0334b26ecfd7
Signed-off-by: Rahul Sharma <rahul.sharma@samsung.com>
Reviewed-on: https://gerrit.chromium.org/gerrit/31696
Reviewed-by: Dylan Reid <dgreid@chromium.org>
Reviewed-by: Grant Grundler <grundler@chromium.org>
Commit-Ready: Dylan Reid <dgreid@chromium.org>
Tested-by: Dylan Reid <dgreid@chromium.org>
sound/soc/samsung/codec_plugin.h
sound/soc/samsung/daisy_max98095.c
sound/soc/samsung/hdmi_audio.c
sound/soc/samsung/hdmi_audio.h

index 1606157..59d9483 100644 (file)
 #define __SND_SOC_SAMSUNG_PLUGIN_H
 
 struct audio_plugin_ops {
+       int (*set_state)(struct device *dev, int enable);
+
+       int (*get_state)(struct device *dev, int *is_enabled);
+
        int (*hw_params)(struct device *dev, struct snd_pcm_substream *,
                struct snd_pcm_hw_params *, struct snd_soc_dai *);
 
index 62227a9..3eea317 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/of_gpio.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
@@ -37,6 +39,7 @@
 #include "i2s.h"
 #include "s3c-i2s-v2.h"
 #include "../codecs/max98095.h"
+#include "codec_plugin.h"
 
 #define DRV_NAME "daisy-snd-max98095"
 
@@ -310,6 +313,55 @@ static const struct snd_soc_dapm_widget daisy_dapm_widgets[] = {
        SND_SOC_DAPM_HP("Headphone Jack", NULL),
 };
 
+static int get_hdmi(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct audio_codec_plugin *plugin;
+       int ret = 0, state = 0;
+
+       plugin = (struct audio_codec_plugin *)kcontrol->private_value;
+
+       if (!plugin)
+               return 0;
+
+       if (!plugin->ops.hw_params)
+               return 0;
+
+       ret = plugin->ops.get_state(plugin->dev, &state);
+       if (ret < 0)
+               return 0;
+
+       ucontrol->value.integer.value[0] = (long int)state;
+       return 1;
+}
+
+static int put_hdmi(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct audio_codec_plugin *plugin;
+       int ret = 0, state;
+
+       plugin = (struct audio_codec_plugin *)kcontrol->private_value;
+
+       if (!plugin)
+               return 0;
+
+       if (!plugin->ops.hw_params)
+               return 0;
+
+       state = (int)ucontrol->value.integer.value[0];
+       ret = plugin->ops.set_state(plugin->dev,
+               ucontrol->value.integer.value[0]);
+
+       if (ret < 0)
+               return 0;
+       return 1;
+}
+
+static struct snd_kcontrol_new daisy_dapm_controls[] = {
+       SOC_SINGLE_BOOL_EXT("HDMI Playback Switch", 0, get_hdmi, put_hdmi),
+};
+
 static int daisy_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
@@ -390,17 +442,42 @@ static struct snd_soc_card daisy_snd = {
        .name = "DAISY-I2S",
        .dai_link = daisy_dai,
        .num_links = ARRAY_SIZE(daisy_dai),
+       .controls = daisy_dapm_controls,
+       .num_controls = ARRAY_SIZE(daisy_dapm_controls),
        .dapm_widgets = daisy_dapm_widgets,
        .num_dapm_widgets = ARRAY_SIZE(daisy_dapm_widgets),
        .dapm_routes = daisy_audio_map,
        .num_dapm_routes = ARRAY_SIZE(daisy_audio_map),
 };
 
+static int plugin_init(struct audio_codec_plugin **pplugin)
+{
+       struct device_node *plugin_node = NULL;
+       struct platform_device *plugin_pdev;
+       struct audio_codec_plugin *plugin;
+
+       plugin_node = of_find_node_by_name(NULL, "hdmi-audio");
+       if (!plugin_node)
+               return -EFAULT;
+
+       plugin_pdev = of_find_device_by_node(plugin_node);
+       if (!plugin_node)
+               return -EFAULT;
+
+       plugin = dev_get_drvdata(&plugin_pdev->dev);
+       if (!plugin)
+               return -EFAULT;
+       else
+               *pplugin = plugin;
+       return 0;
+}
+
 static __devinit int daisy_max98095_driver_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card = &daisy_snd;
        struct device_node *dn;
        struct daisy_max98095 *machine;
+       struct audio_codec_plugin *plugin = NULL;
        int i, ret;
 
        if (!pdev->dev.platform_data && !pdev->dev.of_node) {
@@ -433,6 +510,9 @@ static __devinit int daisy_max98095_driver_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       plugin_init(&plugin);
+       daisy_dapm_controls[0].private_value = (unsigned long)plugin;
+
        card->dev = &pdev->dev;
        platform_set_drvdata(pdev, card);
        snd_soc_card_set_drvdata(card, machine);
index 3280d60..66dd01d 100644 (file)
@@ -205,6 +205,7 @@ static void hdmi_audio_control(struct hdmi_audio_context *ctx,
        if (mod & HDMI_DVI_MODE_EN)
                onoff = false;
 
+       ctx->enabled = onoff;
        hdmi_reg_writeb(ctx, HDMI_AUI_CON, onoff ? 2 : 0);
        hdmi_reg_writemask(ctx, HDMI_CON_0, onoff ?
                        HDMI_ASP_EN : HDMI_ASP_DIS, HDMI_ASP_MASK);
@@ -350,6 +351,50 @@ static int hdmi_audio_trigger(struct device *dev,
        return ret;
 }
 
+static int hdmi_set_state(struct device *dev, int enable)
+{
+       struct hdmi_audio_context *ctx = NULL;
+       struct audio_codec_plugin *plugin;
+       int ret = 0;
+
+       if (!dev) {
+               dev_err(dev, "invalid device.\n");
+               ret = -EINVAL;
+               return ret;
+       }
+
+       plugin = dev_get_drvdata(dev);
+       ctx = container_of(plugin, struct hdmi_audio_context, plugin);
+
+       if (enable)
+               hdmi_audio_control(ctx, true);
+       else
+               hdmi_audio_control(ctx, false);
+       return ret;
+}
+
+static int hdmi_get_state(struct device *dev, int *is_enabled)
+{
+       struct hdmi_audio_context *ctx = NULL;
+       struct audio_codec_plugin *plugin;
+       int ret = 0;
+
+       if (!dev) {
+               dev_err(dev, "invalid device.\n");
+               ret = -EINVAL;
+               return ret;
+       }
+
+       plugin = dev_get_drvdata(dev);
+       ctx = container_of(plugin, struct hdmi_audio_context, plugin);
+
+       if (is_enabled && ctx)
+               *is_enabled = ctx->enabled;
+       else
+               return -EINVAL;
+       return 0;
+}
+
 
 static __devinit int hdmi_audio_probe(struct platform_device *pdev)
 {
@@ -379,9 +424,12 @@ static __devinit int hdmi_audio_probe(struct platform_device *pdev)
        }
 
        ctx->pdev = pdev;
+       ctx->enabled = true;
        ctx->plugin.dev = &pdev->dev;
        ctx->plugin.ops.hw_params = hdmi_audio_hw_params;
        ctx->plugin.ops.trigger = hdmi_audio_trigger;
+       ctx->plugin.ops.get_state = hdmi_get_state;
+       ctx->plugin.ops.set_state = hdmi_set_state;
        ctx->params.sample_rate = DEFAULT_RATE;
        ctx->params.bits_per_sample = DEFAULT_BPS;
 
index b5ffec9..1007945 100644 (file)
@@ -346,6 +346,7 @@ struct hdmi_audio_context {
        void __iomem                    *regs;
        struct audio_params             params;
        struct audio_codec_plugin       plugin;
+       bool                                    enabled;
 };
 
 #endif /* __SND_SOC_SAMSUNG_SPDIF_H */