summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/imx/Kconfig9
-rw-r--r--sound/soc/imx/Makefile3
-rw-r--r--sound/soc/imx/imx-ccwmx51js-wm8753.c342
3 files changed, 353 insertions, 1 deletions
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
index c81f943a2e10..ddecb6ad62fe 100644
--- a/sound/soc/imx/Kconfig
+++ b/sound/soc/imx/Kconfig
@@ -37,6 +37,15 @@ config SND_SOC_IMX_3STACK_SGTL5000
Say Y if you want to add support for SoC audio on IMX 3STACK
with the SGTL5000.
+
+config SND_SOC_IMX_CCWMX51JS
+ tristate "SoC Audio support for Digi CCWMX51JS"
+ select SND_MXC_SOC_SSI
+ select SND_SOC_WM8753
+ help
+ Say Y if you want to add support for SoC audio on Digi
+ CCWMX51JS with the WM8753 codec.
+
config SND_SOC_IMX_3STACK_AK4647
tristate "SoC Audio support for IMX - AK4647"
select SND_MXC_SOC_SSI
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
index 0460f965a85b..57c645ae7c44 100644
--- a/sound/soc/imx/Makefile
+++ b/sound/soc/imx/Makefile
@@ -20,4 +20,5 @@ snd-soc-imx-3stack-ak5702-objs := imx-3stack-ak5702.o
obj-$(CONFIG_SND_SOC_IMX_3STACK_AK5702) += snd-soc-imx-3stack-ak5702.o
snd-soc-imx-3stack-bt-objs := imx-3stack-bt.o
obj-$(CONFIG_SND_SOC_IMX_3STACK_BLUETOOTH) += snd-soc-imx-3stack-bt.o
-
+snd-soc-imx-ccwmx51js-wm8753-objs := imx-ccwmx51js-wm8753.o
+obj-$(CONFIG_SND_SOC_IMX_CCWMX51JS) += snd-soc-imx-ccwmx51js-wm8753.o
diff --git a/sound/soc/imx/imx-ccwmx51js-wm8753.c b/sound/soc/imx/imx-ccwmx51js-wm8753.c
new file mode 100644
index 000000000000..c9c4d425143f
--- /dev/null
+++ b/sound/soc/imx/imx-ccwmx51js-wm8753.c
@@ -0,0 +1,342 @@
+/*
+ * imx-ccwmx51js-wm8753.c -- i.MX Driver for Digi CCWMS51JS and the Wolfson WM8753 Codec
+ *
+ * Adapted by Timesys from sgtl5000 machine driver and other sources.
+ *
+ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2010 Timesys Corpotation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Based on sound/soc/imx/imx-3stack-sgtl5000.c
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+
+#include <mach/dma.h>
+#include <mach/spba.h>
+#include <mach/clock.h>
+#include <mach/mxc.h>
+#include "../codecs/wm8753.h"
+#include "imx-ssi.h"
+#include "imx-pcm.h"
+
+
+/* SSI BCLK and LRC master
+ *
+ * Set WM8753_SSI_MASTER to operate the WM8753 codec in master mode,
+ * and set to zero to operate it in slave mode.
+ */
+#define WM8753_SSI_MASTER 1
+
+
+struct ccwmx51_priv {
+ int sysclk;
+ struct platform_device *pdev;
+};
+
+static struct ccwmx51_priv machine_priv;
+
+static struct snd_soc_dai ccwmx51_cpu_dai;
+
+
+static int ccwmx51js_audio_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_link *machine = rtd->dai;
+ struct snd_soc_dai *cpu_dai = machine->cpu_dai;
+ struct snd_soc_dai *codec_dai = machine->codec_dai;
+ struct ccwmx51_priv *priv = &machine_priv;
+ int ret = 0;
+
+ unsigned int channels = params_channels(params);
+ u32 dai_format;
+
+
+#if WM8753_SSI_MASTER
+ dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_SYNC;
+ if (channels == 2)
+ dai_format |= SND_SOC_DAIFMT_TDM;
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, dai_format);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, dai_format);
+
+ if (ret < 0)
+ return ret;
+#else
+ dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_SYNC;
+ if (channels == 2)
+ dai_format |= SND_SOC_DAIFMT_TDM;
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, dai_format);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, dai_format);
+
+ if (ret < 0)
+ return ret;
+#endif
+
+ snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, priv->sysclk, 0);
+
+ /* set i.MX active slot mask */
+ snd_soc_dai_set_tdm_slot(cpu_dai,
+ channels == 1 ? 0xfffffffe : 0xfffffffc, 2);
+
+ /* set the SSI system clock as input (unused) */
+ snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, SND_SOC_CLOCK_IN);
+
+
+ /* The WM8753 PLL on the Digi CCWMX51JS is referenced to a fixed 13-MHz
+ * oscillator. We presently operate the PLL only at 11.289600
+ * MHz output, which supports a 44.1-kHz sample rate and a few others.
+ *
+ */
+
+ // set codec BCLK division for sample rate */
+ ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_BCLKDIV, WM8753_BCLK_DIV_4);
+ if (ret < 0)
+ return ret;
+
+ // Specify input PLL frequency and desired output frequency.
+ ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 13000000, 11289600);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+
+
+ // Sets up the i.mx51 Digital Audio Multiplexer
+static void ccwmx51_init_dam(int ssi_port, int dai_port)
+{
+ unsigned int ssi_ptcr = 0;
+ unsigned int dai_ptcr = 0;
+ unsigned int ssi_pdcr = 0;
+ unsigned int dai_pdcr = 0;
+ /* i.mx51 uses SSI1 or SSI2 via AUDMUX port dai_port for audio */
+
+ /* reset port ssi_port & dai_port */
+ __raw_writel(0, DAM_PTCR(ssi_port));
+ __raw_writel(0, DAM_PTCR(dai_port));
+ __raw_writel(0, DAM_PDCR(ssi_port));
+ __raw_writel(0, DAM_PDCR(dai_port));
+
+ /* set to synchronous */
+ ssi_ptcr |= AUDMUX_PTCR_SYN;
+ dai_ptcr |= AUDMUX_PTCR_SYN;
+
+#if WM8753_SSI_MASTER
+ /* set Rx sources ssi_port <--> dai_port */
+ ssi_pdcr |= AUDMUX_PDCR_RXDSEL(dai_port);
+ dai_pdcr |= AUDMUX_PDCR_RXDSEL(ssi_port);
+
+ /* set Tx frame direction and source dai_port--> ssi_port output */
+ ssi_ptcr |= AUDMUX_PTCR_TFSDIR;
+ ssi_ptcr |= AUDMUX_PTCR_TFSSEL(AUDMUX_FROM_TXFS, dai_port);
+
+ /* set Tx Clock direction and source dai_port--> ssi_port output */
+ ssi_ptcr |= AUDMUX_PTCR_TCLKDIR;
+ ssi_ptcr |= AUDMUX_PTCR_TCSEL(AUDMUX_FROM_TXFS, dai_port);
+#else
+ /* set Rx sources ssi_port <--> dai_port */
+ ssi_pdcr |= AUDMUX_PDCR_RXDSEL(dai_port);
+ dai_pdcr |= AUDMUX_PDCR_RXDSEL(ssi_port);
+
+ /* set Tx frame direction and source ssi_port --> dai_port output */
+ dai_ptcr |= AUDMUX_PTCR_TFSDIR;
+ dai_ptcr |= AUDMUX_PTCR_TFSSEL(AUDMUX_FROM_TXFS, ssi_port);
+
+ /* set Tx Clock direction and source ssi_port--> dai_port output */
+ dai_ptcr |= AUDMUX_PTCR_TCLKDIR;
+ dai_ptcr |= AUDMUX_PTCR_TCSEL(AUDMUX_FROM_TXFS, ssi_port);
+#endif
+
+ __raw_writel(ssi_ptcr, DAM_PTCR(ssi_port));
+ __raw_writel(dai_ptcr, DAM_PTCR(dai_port));
+ __raw_writel(ssi_pdcr, DAM_PDCR(ssi_port));
+ __raw_writel(dai_pdcr, DAM_PDCR(dai_port));
+}
+
+
+
+/*
+ * Still to do: set the line out to become enabled within
+ * this driver. Currently the initial driver configuration
+ * has all outputs disabled. They can be enabled in user space
+ * by doing:
+ *
+ * amixer sset 'Left Mixer Left' unmute
+ * amixer sset 'Right Mixer Right Playback Swit' unmute
+ *
+ */
+static int ccwmx51js_startup(struct snd_pcm_substream *substream)
+{
+ return 0;
+}
+
+static void ccwmx51js_shutdown(struct snd_pcm_substream *substream)
+{
+}
+
+static struct snd_soc_ops ccwmx51js_ops = {
+ .startup = ccwmx51js_startup,
+ .shutdown = ccwmx51js_shutdown,
+ .hw_params = ccwmx51js_audio_hw_params,
+};
+
+
+ // Logic for wm8753 as connected on Digi CCWMX51JS board.
+static int ccwmx51js_wm8753_init(struct snd_soc_codec *codec)
+{
+ return 0;
+}
+
+
+/* digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link ccwmx51js_dai = {
+ .name = "CCWMX51JS WM8753",
+
+ .stream_name = "WM8753 HiFi",
+ .cpu_dai = &ccwmx51_cpu_dai,
+ .codec_dai = &wm8753_dai[WM8753_DAI_HIFI],
+ .init = ccwmx51js_wm8753_init,
+ .ops = &ccwmx51js_ops,
+};
+
+static int ccwmx51js_machine_remove(struct platform_device *pdev)
+{
+ struct ccwmx51_priv *priv = &machine_priv;
+ struct mxc_audio_platform_data *plat;
+
+ if (priv->pdev) {
+ plat = priv->pdev->dev.platform_data;
+ if (plat->finit)
+ plat->finit();
+ }
+
+ return 0;
+}
+
+/* audio machine driver */
+static struct snd_soc_machine snd_soc_machine_ccwmx51js = {
+ .name = "imx-ccwmx51js",
+ .dai_link = &ccwmx51js_dai,
+ .num_links = 1,
+ .remove = ccwmx51js_machine_remove,
+};
+
+static struct wm8753_setup_data ccwmx51_wm8753_setup = {
+ .i2c_address = 0x1a,
+ .i2c_bus = 1,
+};
+
+static struct snd_soc_device ccwmx51js_snd_devdata = {
+ .machine = &snd_soc_machine_ccwmx51js,
+ .platform = &imx_soc_platform,
+ .codec_dev = &soc_codec_dev_wm8753,
+ .codec_data = &ccwmx51_wm8753_setup,
+};
+
+static int __devinit ccwmx51js_wm8753_probe(struct platform_device *pdev)
+{
+ struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
+ struct ccwmx51_priv *priv = &machine_priv;
+ int ret = 0;
+
+ priv->sysclk = plat->sysclk;
+ priv->pdev = pdev;
+
+ imx_ssi_dai_init(&ccwmx51_cpu_dai);
+ ccwmx51_cpu_dai.private_data = plat;
+
+ ccwmx51_init_dam(plat->src_port, plat->ext_port);
+
+ if (plat->src_port == 2)
+ ccwmx51_cpu_dai.name = "imx-ssi-3";
+ else
+ ccwmx51_cpu_dai.name = "imx-ssi-1";
+
+ ret = -EINVAL;
+ if (plat->init && plat->init()){
+ goto err_plat_init;
+ }
+ return 0;
+
+err_plat_init:
+ return ret;
+}
+
+static int ccwmx51js_wm8753_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver ccwmx51js_wm8753_audio_driver = {
+ .probe = ccwmx51js_wm8753_probe,
+ .remove = ccwmx51js_wm8753_remove,
+ .driver = {
+ .name = "imx-ccwmx51js-wm8753",
+ },
+};
+
+static struct platform_device *ccwmx51js_snd_device;
+
+static int __init ccwmx51js_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&ccwmx51js_wm8753_audio_driver);
+ if (ret)
+ return -ENOMEM;
+
+ ccwmx51js_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!ccwmx51js_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(ccwmx51js_snd_device, &ccwmx51js_snd_devdata);
+ ccwmx51js_snd_devdata.dev = &ccwmx51js_snd_device->dev;
+ ret = platform_device_add(ccwmx51js_snd_device);
+
+ if (ret)
+ platform_device_put(ccwmx51js_snd_device);
+
+ return ret;
+}
+
+static void __exit ccwmx51js_exit(void)
+{
+ platform_driver_unregister(&ccwmx51js_wm8753_audio_driver);
+ platform_device_unregister(ccwmx51js_snd_device);
+}
+
+module_init(ccwmx51js_init);
+module_exit(ccwmx51js_exit);
+
+MODULE_AUTHOR("Timesys");
+MODULE_DESCRIPTION("WM8753 Driver for Digi CCWMX51JS");
+MODULE_LICENSE("GPL");