summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorXiubo Li <Li.Xiubo@freescale.com>2014-03-24 05:21:00 (GMT)
committerMatthew Weigel <Matthew.Weigel@freescale.com>2014-12-11 18:36:46 (GMT)
commitbcb5f7f7f44f3df88f9703bc3caed9805175464a (patch)
tree44ee92410b701ba53fb2293d56ae98300e3df541 /sound
parent9c10bc680c2f621b66f1ed1ccf35b44f75263385 (diff)
downloadlinux-fsl-qoriq-bcb5f7f7f44f3df88f9703bc3caed9805175464a.tar.xz
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 <Li.Xiubo@freescale.com> Signed-off-by: Alison Wang <b18965@freescale.com> --- 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 <CDREVIEW@freescale.com> Reviewed-by: Jingchang Lu <jingchang.lu@freescale.com> Reviewed-by: Huan Wang <alison.wang@freescale.com> Reviewed-by: Zhengxiong Jin <Jason.Jin@freescale.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/fsl/Kconfig23
-rw-r--r--sound/soc/fsl/Makefile4
-rw-r--r--sound/soc/fsl/vf610-sgtl5000.c169
3 files changed, 196 insertions, 0 deletions
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 <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+
+#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");