ASoC: Intel: Boards: Machine driver for SKL+ w/ HDAudio codecs
authorRakesh Ughreja <rakesh.a.ughreja@intel.com>
Wed, 22 Aug 2018 20:24:59 +0000 (15:24 -0500)
committerMark Brown <broonie@kernel.org>
Tue, 28 Aug 2018 19:18:08 +0000 (20:18 +0100)
Add machine driver for Intel platforms (SKL/KBL/BXT/APL) with
HDA and iDisp codecs. This patch adds support for only iDisp (HDMI/DP)
codec. In the following patches support for HDA codecs will be added.

This should work for other Intel platforms as well e.g. GLK,CNL
however this series is not tested on all the platforms.

Signed-off-by: Rakesh Ughreja <rakesh.a.ughreja@intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/intel/boards/Kconfig
sound/soc/intel/boards/Makefile
sound/soc/intel/boards/skl_hda_dsp_common.c [new file with mode: 0644]
sound/soc/intel/boards/skl_hda_dsp_common.h [new file with mode: 0644]
sound/soc/intel/boards/skl_hda_dsp_generic.c [new file with mode: 0644]
sound/soc/intel/skylake/skl.h

index cccda87f4b34f12314cb45636a28782fda77ed93..0f0d578595558ff1e5ed8a74fd8aa8575247540c 100644 (file)
@@ -279,6 +279,14 @@ config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH
          This adds support for ASoC Onboard Codec I2S machine driver. This will
          create an alsa sound card for DA7219 + MAX98357A I2S audio codec.
          Say Y if you have such a device.
+
+config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH
+       tristate "SKL/KBL/BXT/APL with HDA Codecs"
+       select SND_SOC_HDAC_HDMI
+       help
+         This adds support for ASoC machine driver for Intel platforms
+         SKL/KBL/BXT/APL with iDisp, HDA audio codecs.
+          Say Y or m if you have such a device. This is a recommended option.
          If unsure select "N".
 
 config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH
index 87ef8b4058e5831f9f21d76e0a815405952f09aa..6e88373cbe355b4d2b40ba6f9d93904a13bd9e4c 100644 (file)
@@ -20,6 +20,7 @@ snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o
 snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o
 snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o
 snd-soc-skl_rt286-objs := skl_rt286.o
+snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o
 snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o
 snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o
 
@@ -46,3 +47,4 @@ obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt566
 obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o
 obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o
 obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o
+obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o
diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.c b/sound/soc/intel/boards/skl_hda_dsp_common.c
new file mode 100644 (file)
index 0000000..f9917e0
--- /dev/null
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2015-18 Intel Corporation.
+
+/*
+ * Common functions used in different Intel machine drivers
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "../../codecs/hdac_hdmi.h"
+#include "../skylake/skl.h"
+#include "skl_hda_dsp_common.h"
+
+#define NAME_SIZE      32
+
+int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device)
+{
+       struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card);
+       struct skl_hda_hdmi_pcm *pcm;
+       char dai_name[NAME_SIZE];
+
+       pcm = devm_kzalloc(card->dev, sizeof(*pcm), GFP_KERNEL);
+       if (!pcm)
+               return -ENOMEM;
+
+       snprintf(dai_name, sizeof(dai_name), "intel-hdmi-hifi%d",
+                ctx->dai_index);
+       pcm->codec_dai = snd_soc_card_get_codec_dai(card, dai_name);
+       if (!pcm->codec_dai)
+               return -EINVAL;
+
+       pcm->device = device;
+       list_add_tail(&pcm->head, &ctx->hdmi_pcm_list);
+
+       return 0;
+}
+
+/* skl_hda_digital audio interface glue - connects codec <--> CPU */
+struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS] = {
+       /* Back End DAI links */
+       {
+               .name = "iDisp1",
+               .id = 1,
+               .cpu_dai_name = "iDisp1 Pin",
+               .codec_name = "ehdaudio0D2",
+               .codec_dai_name = "intel-hdmi-hifi1",
+               .dpcm_playback = 1,
+               .no_pcm = 1,
+       },
+       {
+               .name = "iDisp2",
+               .id = 2,
+               .cpu_dai_name = "iDisp2 Pin",
+               .codec_name = "ehdaudio0D2",
+               .codec_dai_name = "intel-hdmi-hifi2",
+               .dpcm_playback = 1,
+               .no_pcm = 1,
+       },
+       {
+               .name = "iDisp3",
+               .id = 3,
+               .cpu_dai_name = "iDisp3 Pin",
+               .codec_name = "ehdaudio0D2",
+               .codec_dai_name = "intel-hdmi-hifi3",
+               .dpcm_playback = 1,
+               .no_pcm = 1,
+       },
+};
+
+int skl_hda_hdmi_jack_init(struct snd_soc_card *card)
+{
+       struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card);
+       struct snd_soc_component *component = NULL;
+       struct skl_hda_hdmi_pcm *pcm;
+       char jack_name[NAME_SIZE];
+       int err;
+
+       list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) {
+               component = pcm->codec_dai->component;
+               snprintf(jack_name, sizeof(jack_name),
+                        "HDMI/DP, pcm=%d Jack", pcm->device);
+               err = snd_soc_card_jack_new(card, jack_name,
+                                           SND_JACK_AVOUT, &pcm->hdmi_jack,
+                                           NULL, 0);
+
+               if (err)
+                       return err;
+
+               err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
+                                         &pcm->hdmi_jack);
+               if (err < 0)
+                       return err;
+       }
+
+       if (!component)
+               return -EINVAL;
+
+       return hdac_hdmi_jack_port_init(component, &card->dapm);
+}
diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.h b/sound/soc/intel/boards/skl_hda_dsp_common.h
new file mode 100644 (file)
index 0000000..b6c7969
--- /dev/null
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright(c) 2015-18 Intel Corporation.
+ */
+
+/*
+ * This file defines data structures used in Machine Driver for Intel
+ * platforms with HDA Codecs.
+ */
+
+#ifndef __SOUND_SOC_HDA_DSP_COMMON_H
+#define __SOUND_SOC_HDA_DSP_COMMON_H
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+
+#define HDA_DSP_MAX_BE_DAI_LINKS 3
+
+struct skl_hda_hdmi_pcm {
+       struct list_head head;
+       struct snd_soc_dai *codec_dai;
+       struct snd_soc_jack hdmi_jack;
+       int device;
+};
+
+struct skl_hda_private {
+       struct list_head hdmi_pcm_list;
+       int pcm_count;
+       int dai_index;
+       const char *platform_name;
+};
+
+extern struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS];
+int skl_hda_hdmi_jack_init(struct snd_soc_card *card);
+int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device);
+
+#endif /* __SOUND_SOC_HDA_DSP_COMMON_H */
diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c
new file mode 100644 (file)
index 0000000..920bc2c
--- /dev/null
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright(c) 2015-18 Intel Corporation.
+
+/*
+ * Machine Driver for SKL+ platforms with DSP and iDisp, HDA Codecs
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "../../codecs/hdac_hdmi.h"
+#include "../skylake/skl.h"
+#include "skl_hda_dsp_common.h"
+
+static const struct snd_soc_dapm_route skl_hda_map[] = {
+       { "hifi3", NULL, "iDisp3 Tx"},
+       { "iDisp3 Tx", NULL, "iDisp3_out"},
+       { "hifi2", NULL, "iDisp2 Tx"},
+       { "iDisp2 Tx", NULL, "iDisp2_out"},
+       { "hifi1", NULL, "iDisp1 Tx"},
+       { "iDisp1 Tx", NULL, "iDisp1_out"},
+};
+
+static int skl_hda_card_late_probe(struct snd_soc_card *card)
+{
+       return skl_hda_hdmi_jack_init(card);
+}
+
+static int
+skl_hda_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link)
+{
+       struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card);
+       int ret = 0;
+
+       dev_dbg(card->dev, "%s: dai link name - %s\n", __func__, link->name);
+       link->platform_name = ctx->platform_name;
+       link->nonatomic = 1;
+
+       if (strstr(link->name, "HDMI")) {
+               ret = skl_hda_hdmi_add_pcm(card, ctx->pcm_count);
+
+               if (ret < 0)
+                       return ret;
+
+               ctx->dai_index++;
+       }
+
+       ctx->pcm_count++;
+       return ret;
+}
+
+static struct snd_soc_card hda_soc_card = {
+       .name = "skl_hda_card",
+       .owner = THIS_MODULE,
+       .dai_link = skl_hda_be_dai_links,
+       .dapm_routes = skl_hda_map,
+       .add_dai_link = skl_hda_add_dai_link,
+       .fully_routed = true,
+       .late_probe = skl_hda_card_late_probe,
+};
+
+#define IDISP_DAI_COUNT                3
+/* there are two routes per iDisp output */
+#define IDISP_ROUTE_COUNT      (IDISP_DAI_COUNT * 2)
+#define IDISP_CODEC_MASK       0x4
+
+static int skl_hda_fill_card_info(struct skl_machine_pdata *pdata)
+{
+       struct snd_soc_card *card = &hda_soc_card;
+       u32 codec_count, codec_mask;
+       int i, num_links, num_route;
+
+       codec_mask = pdata->codec_mask;
+       codec_count = hweight_long(codec_mask);
+
+       if (codec_count == 1 && pdata->codec_mask & IDISP_CODEC_MASK) {
+               num_links = IDISP_DAI_COUNT;
+               num_route = IDISP_ROUTE_COUNT;
+       } else {
+               return -EINVAL;
+       }
+
+       card->num_links = num_links;
+       card->num_dapm_routes = num_route;
+
+       for (i = 0; i < num_links; i++)
+               skl_hda_be_dai_links[i].platform_name = pdata->platform;
+
+       return 0;
+}
+
+static int skl_hda_audio_probe(struct platform_device *pdev)
+{
+       struct skl_machine_pdata *pdata;
+       struct skl_hda_private *ctx;
+       int ret;
+
+       dev_dbg(&pdev->dev, "%s: entry\n", __func__);
+
+       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC);
+       if (!ctx)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&ctx->hdmi_pcm_list);
+
+       pdata = dev_get_drvdata(&pdev->dev);
+       if (!pdata)
+               return -EINVAL;
+
+       ret = skl_hda_fill_card_info(pdata);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n");
+               return ret;
+       }
+
+       ctx->pcm_count = hda_soc_card.num_links;
+       ctx->dai_index = 1; /* hdmi codec dai name starts from index 1 */
+       ctx->platform_name = pdata->platform;
+
+       hda_soc_card.dev = &pdev->dev;
+       snd_soc_card_set_drvdata(&hda_soc_card, ctx);
+
+       return devm_snd_soc_register_card(&pdev->dev, &hda_soc_card);
+}
+
+static struct platform_driver skl_hda_audio = {
+       .probe = skl_hda_audio_probe,
+       .driver = {
+               .name = "skl_hda_dsp_generic",
+               .pm = &snd_soc_pm_ops,
+       },
+};
+
+module_platform_driver(skl_hda_audio)
+
+/* Module information */
+MODULE_DESCRIPTION("SKL/KBL/BXT/APL HDA Generic Machine driver");
+MODULE_AUTHOR("Rakesh Ughreja <rakesh.a.ughreja@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:skl_hda_dsp_generic");
index 78aa8bdcb61929dcafcd93112e4a2b05cca9fbc1..4105a9371b6425e90d1fa6cac636e7b6b5a64c00 100644 (file)
@@ -117,6 +117,8 @@ struct skl_dma_params {
 struct skl_machine_pdata {
        u32 dmic_num;
        bool use_tplg_pcm; /* use dais and dai links from topology */
+       const char *platform;
+       u32 codec_mask;
 };
 
 struct skl_dsp_ops {