From bcb5f7f7f44f3df88f9703bc3caed9805175464a Mon Sep 17 00:00:00 2001
From: Xiubo Li
Date: Mon, 24 Mar 2014 13:21:00 +0800
Subject: ASoC: fsl: Add SGTL5000 based audio machine driver.
This is the SGTL5000 codec based audio driver supported with both
playback and capture dai link implemention.
This implementation is only compatible with device tree definition.
Signed-off-by: Xiubo Li
Signed-off-by: Alison Wang
---
This patch has almost been reviewed okay in the mail list. However
the maintainer Mark Brown suggested to use simple-card framework
instead of individual machine driver.
The discussion could be found:
URL: http://lkml.iu.edu//hypermail/linux/kernel/1312.2/02078.html
Since from Linux Kernel V3.12 to V3.14, it changes to much for ALSA
ASoC framework for supporting simple-card, and there will be about
more than 100 patches to backport it, and will also be many potiential
risks, so here just using individual machine driver instead of simple-card on SDK branch.
Change-Id: Ia37f752f8ee6362e726c3a9c602977aa7c0991b2
Reviewed-on: http://git.am.freescale.net:8181/19755
Tested-by: Review Code-CDREVIEW
Reviewed-by: Jingchang Lu
Reviewed-by: Huan Wang
Reviewed-by: Zhengxiong Jin
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index ac4fe4e..f5ad1b2 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -217,3 +217,26 @@ config SND_SOC_IMX_MC13783
select SND_SOC_IMX_PCM_DMA
endif # SND_IMX_SOC
+
+menuconfig SND_VF610_SOC
+ tristate "SoC Audio for Freescale VF610 CPUs"
+ select DMA_ENGINE
+ help
+ Say Y or M if you want to add support for codecs attached to
+ the VF610 CPUs.
+
+ This will enable Freeacale SAI and SGTL5000 codec, and an extra
+ TWR-AUDIO-SGTL sub-board is needed for SGTL5000.
+
+if SND_VF610_SOC
+
+config SND_SOC_VF610_SGTL5000
+ tristate "SoC Audio support for VF610 boards with SGTL5000"
+ depends on OF && I2C
+ select SND_SOC_FSL_SAI
+ select SND_SOC_SGTL5000
+ help
+ Say Y if you want to add support for SoC audio on an VF610 board with
+ a SGTL5000 codec and a SAI.
+
+endif # SND_VF610_SOC
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index aaccbee..96110d1 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -22,6 +22,10 @@ obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o
obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
+# VF610 Platform Support
+snd-soc-vf610-sgtl5000-objs := vf610-sgtl5000.o
+obj-$(CONFIG_SND_SOC_VF610_SGTL5000) += snd-soc-vf610-sgtl5000.o
+
# MPC5200 Platform Support
obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
obj-$(CONFIG_SND_SOC_MPC5200_I2S) += mpc5200_psc_i2s.o
diff --git a/sound/soc/fsl/vf610-sgtl5000.c b/sound/soc/fsl/vf610-sgtl5000.c
new file mode 100644
index 0000000..d53d554
--- /dev/null
+++ b/sound/soc/fsl/vf610-sgtl5000.c
@@ -0,0 +1,169 @@
+/*
+ * Freescale ALSA SoC Audio using SGTL5000 as codec.
+ *
+ * Copyright 2012-2014 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "../codecs/sgtl5000.h"
+#include "fsl_sai.h"
+
+static unsigned int sysclk_rate;
+
+static int vf610_sgtl5000_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret;
+ struct device *dev = rtd->card->dev;
+
+ ret = snd_soc_dai_set_sysclk(rtd->codec_dai, SGTL5000_SYSCLK,
+ sysclk_rate, SND_SOC_CLOCK_IN);
+ if (ret) {
+ dev_err(dev, "could not set codec driver clock params :%d\n",
+ ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, FSL_SAI_CLK_BUS,
+ sysclk_rate, SND_SOC_CLOCK_OUT);
+ if (ret) {
+ dev_err(dev, "could not set cpu dai driver clock params :%d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct snd_soc_dai_link vf610_sgtl5000_dai = {
+ .name = "HiFi",
+ .stream_name = "HiFi",
+ .codec_dai_name = "sgtl5000",
+ .init = &vf610_sgtl5000_dai_init,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
+};
+
+static const struct snd_soc_dapm_widget vf610_sgtl5000_dapm_widgets[] = {
+ SND_SOC_DAPM_MIC("Microphone Jack", NULL),
+ SND_SOC_DAPM_LINE("Line In Jack", NULL),
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_SPK("Speaker Ext", NULL),
+};
+
+static struct snd_soc_card vf610_sgtl5000_card = {
+ .owner = THIS_MODULE,
+ .num_links = 1,
+ .dai_link = &vf610_sgtl5000_dai,
+ .dapm_widgets = vf610_sgtl5000_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(vf610_sgtl5000_dapm_widgets),
+};
+
+static int vf610_sgtl5000_parse_dt(struct platform_device *pdev)
+{
+ int ret;
+ struct device_node *sai_np, *codec_np;
+ struct clk *codec_clk;
+ struct i2c_client *codec_dev;
+ struct device_node *np = pdev->dev.of_node;
+
+ ret = snd_soc_of_parse_card_name(&vf610_sgtl5000_card,
+ "simple-audio-card,name");
+ if (ret)
+ return ret;
+
+ ret = snd_soc_of_parse_audio_routing(&vf610_sgtl5000_card,
+ "simple-audio-card,routing");
+ if (ret)
+ return ret;
+
+ sai_np = of_parse_phandle(np, "simple-audio-card,cpu", 0);
+ if (!sai_np) {
+ dev_err(&pdev->dev, "parsing \"saif-controller\" error\n");
+ return -EINVAL;
+ }
+ vf610_sgtl5000_dai.cpu_of_node = sai_np;
+ vf610_sgtl5000_dai.platform_of_node = sai_np;
+
+ codec_np = of_parse_phandle(np, "simple-audio-card,codec", 0);
+ if (!codec_np) {
+ dev_err(&pdev->dev, "parsing \"audio-codec\" error\n");
+ ret = -EINVAL;
+ goto sai_np_fail;
+ }
+ vf610_sgtl5000_dai.codec_of_node = codec_np;
+
+ codec_dev = of_find_i2c_device_by_node(codec_np);
+ if (!codec_dev) {
+ dev_err(&pdev->dev, "failed to find codec platform device\n");
+ ret = PTR_ERR(codec_dev);
+ goto codec_np_fail;
+ }
+
+ codec_clk = devm_clk_get(&codec_dev->dev, NULL);
+ if (IS_ERR(codec_clk)) {
+ dev_err(&pdev->dev, "failed to get codec clock\n");
+ ret = PTR_ERR(codec_clk);
+ goto codec_np_fail;
+ }
+
+ sysclk_rate = clk_get_rate(codec_clk);
+
+codec_np_fail:
+ of_node_put(codec_np);
+sai_np_fail:
+ of_node_put(sai_np);
+
+ return ret;
+}
+
+static int vf610_sgtl5000_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ vf610_sgtl5000_card.dev = &pdev->dev;
+
+ ret = vf610_sgtl5000_parse_dt(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "parse sgtl5000 device tree failed :%d\n",
+ ret);
+ return ret;
+ }
+
+ ret = snd_soc_register_card(&vf610_sgtl5000_card);
+ if (ret) {
+ dev_err(&pdev->dev, "TWR-AUDIO-SGTL board required :%d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id vf610_sgtl5000_dt_ids[] = {
+ { .compatible = "fsl,vf610-sgtl5000", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, vf610_sgtl5000_dt_ids);
+
+static struct platform_driver vf610_sgtl5000_driver = {
+ .probe = vf610_sgtl5000_probe,
+ .driver = {
+ .name = "vf610-sgtl5000",
+ .owner = THIS_MODULE,
+ .of_match_table = vf610_sgtl5000_dt_ids,
+ },
+};
+module_platform_driver(vf610_sgtl5000_driver);
+
+MODULE_DESCRIPTION("Freescale SGTL5000 ASoC driver");
+MODULE_LICENSE("GPL");
--
cgit v0.10.2