new file mode 100644
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* KeemBay ASOC Machine driver
+ *
+ * Copyright (C) 2020 Intel Corporation.
+ *
+ */
+
+#include <linux/module.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/soc.h>
+#include "../../codecs/tlv320aic32x4.h"
+
+static unsigned int channels[] = {
+ 2,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_ch = {
+ .count = ARRAY_SIZE(channels),
+ .list = channels,
+};
+
+static unsigned int rates[] = {
+ 16000,
+ 48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_rates = {
+ .count = ARRAY_SIZE(rates),
+ .list = rates,
+};
+
+static int kmb_mach_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ int ret;
+ unsigned int sysclk;
+
+ /* As per codec datasheet Sysclk = 256 * fs */
+ sysclk = 12288000;
+
+ /* set the codec system clock */
+ ret = snd_soc_dai_set_sysclk(codec_dai, 1, sysclk, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
+
+ return ret;
+}
+
+static int kmb_mach_dai_link_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *str_runtime;
+
+ str_runtime = substream->runtime;
+
+ snd_pcm_hw_constraint_list(str_runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ &constraints_ch);
+
+ snd_pcm_hw_constraint_list(str_runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_rates);
+
+ return 0;
+}
+
+static const struct snd_soc_ops kmb_mach_dai_link_ops = {
+ .startup = kmb_mach_dai_link_startup,
+ .hw_params = kmb_mach_hw_params,
+};
+
+static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = {
+ SND_SOC_DAPM_MIC("External Mic", NULL),
+ SND_SOC_DAPM_HP("Headphone", NULL),
+};
+
+static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = {
+ {"Headphone", NULL, "HPL"},
+ {"Headphone", NULL, "HPR"},
+ {"IN3_R", NULL, "External Mic"},
+ {"IN3_L", NULL, "External Mic"},
+};
+
+/* Linking platform to the codec-drivers */
+SND_SOC_DAILINK_DEFS(link1,
+ DAILINK_COMP_ARRAY(COMP_CPU("20140000.i2s")),
+ DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic32x4.2-0018",
+ "tlv320aic32x4-hifi")),
+ DAILINK_COMP_ARRAY(COMP_PLATFORM("20140000.i2s")));
+
+/* kmb digital audio interface glue */
+static struct snd_soc_dai_link kmb_mach_dais[] = {
+ {
+ .name = "tlv320aic32x4",
+ .stream_name = "TLV320AIC32X4",
+ .ops = &kmb_mach_dai_link_ops,
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ SND_SOC_DAILINK_REG(link1),
+ },
+};
+
+/* kmb audio machine driver */
+static struct snd_soc_card kmb_mach = {
+ .name = "kmb_audio_card",
+ .dai_link = kmb_mach_dais,
+ .num_links = ARRAY_SIZE(kmb_mach_dais),
+ .dapm_routes = aic32x4_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes),
+ .dapm_widgets = aic32x4_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(aic32x4_dapm_widgets),
+ .fully_routed = true,
+};
+
+static int kmb_mach_audio_probe(struct platform_device *pdev)
+{
+ kmb_mach.dev = &pdev->dev;
+
+ return devm_snd_soc_register_card(&pdev->dev, &kmb_mach);
+}
+
+static const struct of_device_id kmb_mach_of_match[] = {
+ { .compatible = "intel,kmb-snd-asoc", },
+ {}
+};
+
+static struct platform_driver kmb_mach_audio = {
+ .probe = kmb_mach_audio_probe,
+ .driver = {
+ .name = "kmb_tlv3204",
+ .of_match_table = kmb_mach_of_match,
+ },
+};
+
+module_platform_driver(kmb_mach_audio)
+
+/* Module information */
+MODULE_DESCRIPTION("Intel Audio tlv3204 machine driver for KeemBay");
+MODULE_AUTHOR("Sia Jee Heng <jee.heng.sia@intel.com>");
+MODULE_AUTHOR("Sit, Michael Wei Hong <michael.wei.hong.sit@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:kmb_tlv3204");