diff options
author | Shawn Guo <shawn.guo@linaro.org> | 2012-03-05 22:30:53 +0800 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-03-06 00:03:00 +0000 |
commit | 3c77c29c49c6213c55ad8dacc687817b3568c0ce (patch) | |
tree | aa2470aafbd4434d3d7429265ed70e163d45b7f8 /sound/soc/imx | |
parent | 3bc34a6143359d2bf19a5e79b9017aeffc6660ad (diff) |
ASoC: imx: move audmux driver into sound/soc/imx
As audmux becomes a platform driver and its callers are all ASoC
machine drivers, there is no reason to keep it in arch folder, so
move it to sound/soc/imx.
One bonus point would be those ASoC machine drivers stop including
mach/audmux.h, since it's been moved to sound/soc/imx/imx-audmux.h.
This should be a move to the right direction in terms of single kernel
image goal.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/imx')
-rw-r--r-- | sound/soc/imx/Kconfig | 7 | ||||
-rw-r--r-- | sound/soc/imx/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/imx/eukrea-tlv320.c | 2 | ||||
-rw-r--r-- | sound/soc/imx/imx-audmux.c | 300 | ||||
-rw-r--r-- | sound/soc/imx/imx-audmux.h | 60 | ||||
-rw-r--r-- | sound/soc/imx/mx27vis-aic32x4.c | 2 | ||||
-rw-r--r-- | sound/soc/imx/phycore-ac97.c | 3 | ||||
-rw-r--r-- | sound/soc/imx/wm1133-ev1.c | 3 |
8 files changed, 374 insertions, 5 deletions
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index aa4294bf49b2..d3b716663d1d 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig @@ -16,11 +16,15 @@ config SND_MXC_SOC_MX2 select SND_SOC_DMAENGINE_PCM tristate +config SND_SOC_IMX_AUDMUX + tristate + config SND_MXC_SOC_WM1133_EV1 tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted" depends on MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL select SND_SOC_WM8350 select SND_MXC_SOC_FIQ + select SND_SOC_IMX_AUDMUX help Enable support for audio on the i.MX31ADS with the WM1133-EV1 PMIC board with WM8835x fitted. @@ -30,6 +34,7 @@ config SND_SOC_MX27VIS_AIC32X4 depends on MACH_IMX27_VISSTRIM_M10 && I2C select SND_SOC_TLV320AIC32X4 select SND_MXC_SOC_MX2 + select SND_SOC_IMX_AUDMUX help Say Y if you want to add support for SoC audio on Visstrim SM10 board with TLV320AIC32X4 codec. @@ -40,6 +45,7 @@ config SND_SOC_PHYCORE_AC97 select SND_SOC_AC97_BUS select SND_SOC_WM9712 select SND_MXC_SOC_FIQ + select SND_SOC_IMX_AUDMUX help Say Y if you want to add support for SoC audio on Phytec phyCORE and phyCARD boards in AC97 mode @@ -53,6 +59,7 @@ config SND_SOC_EUKREA_TLV320 depends on I2C select SND_SOC_TLV320AIC23 select SND_MXC_SOC_FIQ + select SND_SOC_IMX_AUDMUX help Enable I2S based access to the TLV320AIC23B codec attached to the SSI interface diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile index d6d609ba7e24..5c40541b8315 100644 --- a/sound/soc/imx/Makefile +++ b/sound/soc/imx/Makefile @@ -2,10 +2,12 @@ snd-soc-imx-objs := imx-ssi.o snd-soc-imx-fiq-objs := imx-pcm-fiq.o snd-soc-imx-mx2-objs := imx-pcm-dma-mx2.o +snd-soc-imx-audmux-objs := imx-audmux.o obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o obj-$(CONFIG_SND_MXC_SOC_FIQ) += snd-soc-imx-fiq.o obj-$(CONFIG_SND_MXC_SOC_MX2) += snd-soc-imx-mx2.o +obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o # i.MX Machine Support snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o diff --git a/sound/soc/imx/eukrea-tlv320.c b/sound/soc/imx/eukrea-tlv320.c index bfcb6d9768b8..b375ed4541f6 100644 --- a/sound/soc/imx/eukrea-tlv320.c +++ b/sound/soc/imx/eukrea-tlv320.c @@ -23,10 +23,10 @@ #include <sound/pcm.h> #include <sound/soc.h> #include <asm/mach-types.h> -#include <mach/audmux.h> #include "../codecs/tlv320aic23.h" #include "imx-ssi.h" +#include "imx-audmux.h" #define CODEC_CLOCK 12000000 diff --git a/sound/soc/imx/imx-audmux.c b/sound/soc/imx/imx-audmux.c new file mode 100644 index 000000000000..7b162662fe6b --- /dev/null +++ b/sound/soc/imx/imx-audmux.c @@ -0,0 +1,300 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * Copyright 2012 Linaro Ltd. + * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> + * + * Initial development of this code was funded by + * Phytec Messtechnik GmbH, http://www.phytec.de + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk.h> +#include <linux/debugfs.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include "imx-audmux.h" + +#define DRIVER_NAME "imx-audmux" + +static struct clk *audmux_clk; +static void __iomem *audmux_base; + +#define MXC_AUDMUX_V2_PTCR(x) ((x) * 8) +#define MXC_AUDMUX_V2_PDCR(x) ((x) * 8 + 4) + +#ifdef CONFIG_DEBUG_FS +static struct dentry *audmux_debugfs_root; + +static int audmux_open_file(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +/* There is an annoying discontinuity in the SSI numbering with regard + * to the Linux number of the devices */ +static const char *audmux_port_string(int port) +{ + switch (port) { + case MX31_AUDMUX_PORT1_SSI0: + return "imx-ssi.0"; + case MX31_AUDMUX_PORT2_SSI1: + return "imx-ssi.1"; + case MX31_AUDMUX_PORT3_SSI_PINS_3: + return "SSI3"; + case MX31_AUDMUX_PORT4_SSI_PINS_4: + return "SSI4"; + case MX31_AUDMUX_PORT5_SSI_PINS_5: + return "SSI5"; + case MX31_AUDMUX_PORT6_SSI_PINS_6: + return "SSI6"; + default: + return "UNKNOWN"; + } +} + +static ssize_t audmux_read_file(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + ssize_t ret; + char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + int port = (int)file->private_data; + u32 pdcr, ptcr; + + if (!buf) + return -ENOMEM; + + if (audmux_clk) + clk_enable(audmux_clk); + + ptcr = readl(audmux_base + MXC_AUDMUX_V2_PTCR(port)); + pdcr = readl(audmux_base + MXC_AUDMUX_V2_PDCR(port)); + + if (audmux_clk) + clk_disable(audmux_clk); + + ret = snprintf(buf, PAGE_SIZE, "PDCR: %08x\nPTCR: %08x\n", + pdcr, ptcr); + + if (ptcr & MXC_AUDMUX_V2_PTCR_TFSDIR) + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "TxFS output from %s, ", + audmux_port_string((ptcr >> 27) & 0x7)); + else + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "TxFS input, "); + + if (ptcr & MXC_AUDMUX_V2_PTCR_TCLKDIR) + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "TxClk output from %s", + audmux_port_string((ptcr >> 22) & 0x7)); + else + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "TxClk input"); + + ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n"); + + if (ptcr & MXC_AUDMUX_V2_PTCR_SYN) { + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "Port is symmetric"); + } else { + if (ptcr & MXC_AUDMUX_V2_PTCR_RFSDIR) + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "RxFS output from %s, ", + audmux_port_string((ptcr >> 17) & 0x7)); + else + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "RxFS input, "); + + if (ptcr & MXC_AUDMUX_V2_PTCR_RCLKDIR) + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "RxClk output from %s", + audmux_port_string((ptcr >> 12) & 0x7)); + else + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "RxClk input"); + } + + ret += snprintf(buf + ret, PAGE_SIZE - ret, + "\nData received from %s\n", + audmux_port_string((pdcr >> 13) & 0x7)); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); + + kfree(buf); + + return ret; +} + +static const struct file_operations audmux_debugfs_fops = { + .open = audmux_open_file, + .read = audmux_read_file, + .llseek = default_llseek, +}; + +static void __init audmux_debugfs_init(void) +{ + int i; + char buf[20]; + + audmux_debugfs_root = debugfs_create_dir("audmux", NULL); + if (!audmux_debugfs_root) { + pr_warning("Failed to create AUDMUX debugfs root\n"); + return; + } + + for (i = 1; i < 8; i++) { + snprintf(buf, sizeof(buf), "ssi%d", i); + if (!debugfs_create_file(buf, 0444, audmux_debugfs_root, + (void *)i, &audmux_debugfs_fops)) + pr_warning("Failed to create AUDMUX port %d debugfs file\n", + i); + } +} + +static void __exit audmux_debugfs_remove(void) +{ + debugfs_remove_recursive(audmux_debugfs_root); +} +#else +static inline void audmux_debugfs_init(void) +{ +} + +static inline void audmux_debugfs_remove(void) +{ +} +#endif + +enum imx_audmux_type { + IMX21_AUDMUX, + IMX31_AUDMUX, +} audmux_type; + +static struct platform_device_id imx_audmux_ids[] = { + { + .name = "imx21-audmux", + .driver_data = IMX21_AUDMUX, + }, { + .name = "imx31-audmux", + .driver_data = IMX31_AUDMUX, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, imx_audmux_ids); + +static const uint8_t port_mapping[] = { + 0x0, 0x4, 0x8, 0x10, 0x14, 0x1c, +}; + +int mxc_audmux_v1_configure_port(unsigned int port, unsigned int pcr) +{ + if (audmux_type != IMX21_AUDMUX) + return -EINVAL; + + if (!audmux_base) + return -ENOSYS; + + if (port >= ARRAY_SIZE(port_mapping)) + return -EINVAL; + + writel(pcr, audmux_base + port_mapping[port]); + + return 0; +} +EXPORT_SYMBOL_GPL(mxc_audmux_v1_configure_port); + +int mxc_audmux_v2_configure_port(unsigned int port, unsigned int ptcr, + unsigned int pdcr) +{ + if (audmux_type != IMX31_AUDMUX) + return -EINVAL; + + if (!audmux_base) + return -ENOSYS; + + if (audmux_clk) + clk_enable(audmux_clk); + + writel(ptcr, audmux_base + MXC_AUDMUX_V2_PTCR(port)); + writel(pdcr, audmux_base + MXC_AUDMUX_V2_PDCR(port)); + + if (audmux_clk) + clk_disable(audmux_clk); + + return 0; +} +EXPORT_SYMBOL_GPL(mxc_audmux_v2_configure_port); + +static int __init imx_audmux_probe(struct platform_device *pdev) +{ + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + audmux_base = devm_request_and_ioremap(&pdev->dev, res); + if (!audmux_base) + return -EADDRNOTAVAIL; + + audmux_clk = clk_get(&pdev->dev, "audmux"); + if (IS_ERR(audmux_clk)) { + dev_dbg(&pdev->dev, "cannot get clock: %ld\n", + PTR_ERR(audmux_clk)); + audmux_clk = NULL; + } + + audmux_type = pdev->id_entry->driver_data; + if (audmux_type == IMX31_AUDMUX) + audmux_debugfs_init(); + + return 0; +} + +static int __exit imx_audmux_remove(struct platform_device *pdev) +{ + if (audmux_type == IMX31_AUDMUX) + audmux_debugfs_remove(); + clk_put(audmux_clk); + + return 0; +} + +static struct platform_driver imx_audmux_driver = { + .probe = imx_audmux_probe, + .remove = __exit_p(imx_audmux_remove), + .id_table = imx_audmux_ids, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + } +}; + +static int __init imx_audmux_init(void) +{ + return platform_driver_register(&imx_audmux_driver); +} +subsys_initcall(imx_audmux_init); + +static void __exit imx_audmux_exit(void) +{ + platform_driver_unregister(&imx_audmux_driver); +} +module_exit(imx_audmux_exit); + +MODULE_DESCRIPTION("Freescale i.MX AUDMUX driver"); +MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/sound/soc/imx/imx-audmux.h b/sound/soc/imx/imx-audmux.h new file mode 100644 index 000000000000..5136d9483f46 --- /dev/null +++ b/sound/soc/imx/imx-audmux.h @@ -0,0 +1,60 @@ +#ifndef __IMX_AUDMUX_H +#define __IMX_AUDMUX_H + +#define MX27_AUDMUX_HPCR1_SSI0 0 +#define MX27_AUDMUX_HPCR2_SSI1 1 +#define MX27_AUDMUX_HPCR3_SSI_PINS_4 2 +#define MX27_AUDMUX_PPCR1_SSI_PINS_1 3 +#define MX27_AUDMUX_PPCR2_SSI_PINS_2 4 +#define MX27_AUDMUX_PPCR3_SSI_PINS_3 5 + +#define MX31_AUDMUX_PORT1_SSI0 0 +#define MX31_AUDMUX_PORT2_SSI1 1 +#define MX31_AUDMUX_PORT3_SSI_PINS_3 2 +#define MX31_AUDMUX_PORT4_SSI_PINS_4 3 +#define MX31_AUDMUX_PORT5_SSI_PINS_5 4 +#define MX31_AUDMUX_PORT6_SSI_PINS_6 5 + +#define MX51_AUDMUX_PORT1_SSI0 0 +#define MX51_AUDMUX_PORT2_SSI1 1 +#define MX51_AUDMUX_PORT3 2 +#define MX51_AUDMUX_PORT4 3 +#define MX51_AUDMUX_PORT5 4 +#define MX51_AUDMUX_PORT6 5 +#define MX51_AUDMUX_PORT7 6 + +/* Register definitions for the i.MX21/27 Digital Audio Multiplexer */ +#define MXC_AUDMUX_V1_PCR_INMMASK(x) ((x) & 0xff) +#define MXC_AUDMUX_V1_PCR_INMEN (1 << 8) +#define MXC_AUDMUX_V1_PCR_TXRXEN (1 << 10) +#define MXC_AUDMUX_V1_PCR_SYN (1 << 12) +#define MXC_AUDMUX_V1_PCR_RXDSEL(x) (((x) & 0x7) << 13) +#define MXC_AUDMUX_V1_PCR_RFCSEL(x) (((x) & 0xf) << 20) +#define MXC_AUDMUX_V1_PCR_RCLKDIR (1 << 24) +#define MXC_AUDMUX_V1_PCR_RFSDIR (1 << 25) +#define MXC_AUDMUX_V1_PCR_TFCSEL(x) (((x) & 0xf) << 26) +#define MXC_AUDMUX_V1_PCR_TCLKDIR (1 << 30) +#define MXC_AUDMUX_V1_PCR_TFSDIR (1 << 31) + +/* Register definitions for the i.MX25/31/35/51 Digital Audio Multiplexer */ +#define MXC_AUDMUX_V2_PTCR_TFSDIR (1 << 31) +#define MXC_AUDMUX_V2_PTCR_TFSEL(x) (((x) & 0xf) << 27) +#define MXC_AUDMUX_V2_PTCR_TCLKDIR (1 << 26) +#define MXC_AUDMUX_V2_PTCR_TCSEL(x) (((x) & 0xf) << 22) +#define MXC_AUDMUX_V2_PTCR_RFSDIR (1 << 21) +#define MXC_AUDMUX_V2_PTCR_RFSEL(x) (((x) & 0xf) << 17) +#define MXC_AUDMUX_V2_PTCR_RCLKDIR (1 << 16) +#define MXC_AUDMUX_V2_PTCR_RCSEL(x) (((x) & 0xf) << 12) +#define MXC_AUDMUX_V2_PTCR_SYN (1 << 11) + +#define MXC_AUDMUX_V2_PDCR_RXDSEL(x) (((x) & 0x7) << 13) +#define MXC_AUDMUX_V2_PDCR_TXRXEN (1 << 12) +#define MXC_AUDMUX_V2_PDCR_MODE(x) (((x) & 0x3) << 8) +#define MXC_AUDMUX_V2_PDCR_INMMASK(x) ((x) & 0xff) + +int mxc_audmux_v1_configure_port(unsigned int port, unsigned int pcr); + +int mxc_audmux_v2_configure_port(unsigned int port, unsigned int ptcr, + unsigned int pdcr); + +#endif /* __IMX_AUDMUX_H */ diff --git a/sound/soc/imx/mx27vis-aic32x4.c b/sound/soc/imx/mx27vis-aic32x4.c index 155899c08c0c..dbfad0f62511 100644 --- a/sound/soc/imx/mx27vis-aic32x4.c +++ b/sound/soc/imx/mx27vis-aic32x4.c @@ -32,11 +32,11 @@ #include <sound/soc-dapm.h> #include <sound/tlv.h> #include <asm/mach-types.h> -#include <mach/audmux.h> #include <mach/iomux-mx27.h> #include "../codecs/tlv320aic32x4.h" #include "imx-ssi.h" +#include "imx-audmux.h" #define MX27VIS_AMP_GAIN 0 #define MX27VIS_AMP_MUTE 1 diff --git a/sound/soc/imx/phycore-ac97.c b/sound/soc/imx/phycore-ac97.c index a59692e740b4..7dab077f9c30 100644 --- a/sound/soc/imx/phycore-ac97.c +++ b/sound/soc/imx/phycore-ac97.c @@ -18,7 +18,8 @@ #include <sound/pcm.h> #include <sound/soc.h> #include <asm/mach-types.h> -#include <mach/audmux.h> + +#include "imx-audmux.h" static struct snd_soc_card imx_phycore; diff --git a/sound/soc/imx/wm1133-ev1.c b/sound/soc/imx/wm1133-ev1.c index 37480c90e997..15056d6a1643 100644 --- a/sound/soc/imx/wm1133-ev1.c +++ b/sound/soc/imx/wm1133-ev1.c @@ -21,10 +21,9 @@ #include <sound/pcm_params.h> #include <sound/soc.h> -#include <mach/audmux.h> - #include "imx-ssi.h" #include "../codecs/wm8350.h" +#include "imx-audmux.h" /* There is a silicon mic on the board optionally connected via a solder pad * SP1. Define this to enable it. |