summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnatoly Palto <a.palto@sam-solutions.net>2012-12-27 10:40:58 +0300
committerJustin Waters <justin.waters@timesys.com>2013-11-07 12:19:18 -0500
commit267c0eb89e8391e2edcce20dc45e97f6796d4a09 (patch)
tree9b7bde5d18a57cd123ec6c34a8d371133c33b1b8
parenta0d0cb6a50fd9fb1dd070e2cc47077ca5acd4f82 (diff)
Added AC97 audio driver on wm9712 chip
Signed-off-by: Christian Hemp <c.hemp@phytec.de>
-rw-r--r--arch/arm/mach-mx6/board-mx6q_phycard.c89
-rw-r--r--sound/soc/imx/Kconfig10
-rw-r--r--sound/soc/imx/Makefile2
-rw-r--r--sound/soc/imx/imx-wm9712.c125
4 files changed, 220 insertions, 6 deletions
diff --git a/arch/arm/mach-mx6/board-mx6q_phycard.c b/arch/arm/mach-mx6/board-mx6q_phycard.c
index 2e4ca4304e0a..6cfbf7e61183 100644
--- a/arch/arm/mach-mx6/board-mx6q_phycard.c
+++ b/arch/arm/mach-mx6/board-mx6q_phycard.c
@@ -73,6 +73,7 @@
#include <mach/mxc_asrc.h>
#include <mach/mipi_dsi.h>
#include <mach/mipi_csi2.h>
+#include <mach/audmux.h>
#include <asm/irq.h>
#include <asm/setup.h>
@@ -133,7 +134,7 @@ extern void (*put_cpu_regulator)(void);
extern char *gp_reg_id;
extern void mx6_cpu_regulator_init(void);
-static bool HDA_ON; // HDA audio ON/OFF detect
+static bool hda_on; // HDA audio ON/OFF detect
static const struct anatop_thermal_platform_data
@@ -686,9 +687,76 @@ static struct platform_device mx6_phyflex_audio_device = {
.name = "tlv320aic3007",
};
+/* fo phyCARD */
+static iomux_v3_cfg_t mx6q_ac97_ssi_pads[] = {
+ MX6Q_PAD_DISP0_DAT18__AUDMUX_AUD5_TXFS,
+ MX6Q_PAD_DISP0_DAT16__AUDMUX_AUD5_TXC,
+};
+static iomux_v3_cfg_t mx6q_ac97_gpio_pads[] = {
+ MX6Q_PAD_DISP0_DAT18__GPIO_5_12,
+ MX6Q_PAD_DISP0_DAT16__GPIO_5_10,
+};
+
+// imx_imx_ssi_data imx6_imx_ssi_data[]
+static void mx6_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+ mxc_iomux_v3_setup_multiple_pads(mx6q_ac97_gpio_pads, ARRAY_SIZE(mx6q_ac97_gpio_pads));
+ gpio_set_value(IMX_GPIO_NR(5, 10), 0);
+ gpio_set_value(IMX_GPIO_NR(5, 12), 0);
+ udelay(3);
+ gpio_set_value(IMX_GPIO_NR(5, 12), 1);
+ udelay(3);
+ gpio_set_value(IMX_GPIO_NR(5, 12), 0);
+ udelay(2);
+ mxc_iomux_v3_setup_multiple_pads(mx6q_ac97_ssi_pads, ARRAY_SIZE(mx6q_ac97_ssi_pads));
+ udelay(3);
+}
+
+static void mx6_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+ mxc_iomux_v3_setup_multiple_pads(mx6q_ac97_gpio_pads, ARRAY_SIZE(mx6q_ac97_gpio_pads));
+ gpio_set_value(IMX_GPIO_NR(5, 12), 0);
+ gpio_set_value(IMX_GPIO_NR(5, 10), 0);
+ udelay(3);
+ gpio_set_value(MX6_PHYCARD_SSI_RESET, 0);
+ udelay(5);
+ gpio_set_value(MX6_PHYCARD_SSI_RESET, 1);
+ udelay(2);
+ mxc_iomux_v3_setup_multiple_pads(mx6q_ac97_ssi_pads, ARRAY_SIZE(mx6q_ac97_ssi_pads));
+ mdelay(350);
+}
+
+static struct imx_ssi_platform_data mx6_phycard_ssi_pdata = {
+ .flags = IMX_SSI_DMA | IMX_SSI_SYN | IMX_SSI_USE_AC97 ,
+ .ac97_reset = mx6_ac97_cold_reset ,
+ .ac97_warm_reset = mx6_ac97_warm_reset,
+};
+
+static struct platform_device mx6_phycard_audio_device = {
+ .name = "PhyCARD-ac97-audio",
+};
+
+static int imx_ac97_audmux_config(int slave, int master) {
+
+ slave = slave - 1;
+ master = master - 1;
+
+ // slave port audmux config
+ mxc_audmux_v2_configure_port(slave, MXC_AUDMUX_V2_PTCR_SYN |
+ MXC_AUDMUX_V2_PTCR_TCLKDIR | MXC_AUDMUX_V2_PTCR_TCSEL(master),
+ MXC_AUDMUX_V2_PDCR_RXDSEL(master));
+
+ // master port audmux config
+ mxc_audmux_v2_configure_port(master, MXC_AUDMUX_V2_PTCR_SYN |
+ MXC_AUDMUX_V2_PTCR_TFSDIR | MXC_AUDMUX_V2_PTCR_TFSEL(slave),
+ MXC_AUDMUX_V2_PDCR_RXDSEL(slave));
+
+ return 0;
+}
+
static int __init mx6_phyflex_init_audio(void)
{
- if (HDA_ON) {
+ if (hda_on) {
/* SSI audio init part */
mxc_register_device(&mx6_phyflex_audio_device,
&mx6_phyflex_audio_data);
@@ -701,7 +769,16 @@ static int __init mx6_phyflex_init_audio(void)
platform_device_register(&tlv320aic3007_phyflex_drvdd_reg_devices);
#endif
} else {
- // TODO: insert code for wm9712 audio
+ gpio_request_one(MX6_PHYCARD_SSI_RESET, GPIOF_OUT_INIT_HIGH, "AC97");
+ gpio_request_one(IMX_GPIO_NR(5, 12), GPIOF_OUT_INIT_HIGH, "AC97");
+ gpio_request_one(IMX_GPIO_NR(5, 10), GPIOF_OUT_INIT_HIGH, "AC97");
+
+#define INTERNAL_PORT 2
+#define EXTERNAL_PORT 5
+ imx_ac97_audmux_config(INTERNAL_PORT,EXTERNAL_PORT);
+
+ platform_device_register(&mx6_phycard_audio_device);
+ imx6q_add_imx_ssi(1, &mx6_phycard_ssi_pdata);
}
return 0;
@@ -929,9 +1006,9 @@ static void __init mx6_phyflex_init(void)
* or WM9712 AC97 audio and touchscreen */
gpio_request_one(MX6_PHYCARD_AC97_INT, GPIOF_IN, "Audio Detect");
if (gpio_get_value(MX6_PHYCARD_AC97_INT)) {
- HDA_ON = true;
+ hda_on = true;
} else {
- HDA_ON = false;
+ hda_on = false;
}
gp_reg_id = phyflex_dvfscore_data.reg_id;
@@ -948,7 +1025,7 @@ static void __init mx6_phyflex_init(void)
imx6q_add_imx_i2c(1, &mx6_phyflex_i2c1_data);
i2c_register_board_info(0, mxc_i2c0_board_info, ARRAY_SIZE(mxc_i2c0_board_info));
i2c_register_board_info(1, mxc_i2c1_board_info, ARRAY_SIZE(mxc_i2c1_board_info));
- if (HDA_ON) {
+ if (hda_on) {
i2c_register_board_info(1, mxc_i2c1_board_info_hda, ARRAY_SIZE(mxc_i2c1_board_info_hda));
}
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
index 2e57c7d80969..d23ed07261c2 100644
--- a/sound/soc/imx/Kconfig
+++ b/sound/soc/imx/Kconfig
@@ -139,4 +139,14 @@ config SND_SOC_IMX_TLV320AIC3007
Say Y if you want to add support for SoC audio on an i.MX board with
a tlv320aic3007 codec.
+config SND_SOC_IMX_WM9712
+ tristate "SoC Audio support for i.MX boards with wm9712"
+ depends on MACH_MX6Q_PHYCARD && !SND_SOC_IMX_TLV320AIC3007
+ select SND_SOC_WM9712
+ select SND_MXC_SOC_MX2
+ help
+ Say Y if you want to add support for SoC audio on an i.MX board with
+ a wm9712 codec.
+
+
endif # SND_IMX_SOC
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
index 99de2c10f6d1..898932ef28f0 100644
--- a/sound/soc/imx/Makefile
+++ b/sound/soc/imx/Makefile
@@ -18,6 +18,7 @@ snd-soc-imx-wm8958-objs := imx-wm8958.o
snd-soc-imx-wm8962-objs := imx-wm8962.o
snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
snd-soc-imx-tlv320aic3007-objs := imx-tlv320aic3007.o
+snd-soc-imx-wm9712-objs := imx-wm9712.o
snd-soc-imx-cs42888-objs := imx-cs42888.o
snd-soc-imx-spdif-objs := imx-spdif.o
snd-soc-imx-si4763-objs := imx-si4763.o
@@ -31,6 +32,7 @@ obj-$(CONFIG_SND_SOC_IMX_WM8958) += snd-soc-imx-wm8958.o
obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o
obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
obj-$(CONFIG_SND_SOC_IMX_TLV320AIC3007) += snd-soc-imx-tlv320aic3007.o
+obj-$(CONFIG_SND_SOC_IMX_WM9712) += snd-soc-imx-wm9712.o
obj-$(CONFIG_SND_SOC_IMX_CS42888) += snd-soc-imx-cs42888.o
obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o
obj-$(CONFIG_SND_SOC_IMX_HDMI) += snd-soc-imx-hdmi.o
diff --git a/sound/soc/imx/imx-wm9712.c b/sound/soc/imx/imx-wm9712.c
new file mode 100644
index 000000000000..f98f5378008d
--- /dev/null
+++ b/sound/soc/imx/imx-wm9712.c
@@ -0,0 +1,125 @@
+/*
+ * imx-wm9712.c -- SoC audio for imx phycard in AC97 mode
+ *
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <asm/mach-types.h>
+
+#include <sound/ac97_codec.h>
+
+#include "imx-ssi.h"
+
+#define WORD_PER_FRAME_AC97 13
+#define BIT_PER_WORD_AC97 16
+
+static struct snd_soc_card imx_phycard;
+
+static int imx_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 *cpu_dai = rtd->cpu_dai;
+ unsigned int channels = params_channels(params);
+ int ret;
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, SND_SOC_CLOCK_IN);
+
+ if (ret < 0)
+ return ret;
+
+ snd_soc_dai_set_tdm_slot(cpu_dai, 0xfffc, 0xfffc, WORD_PER_FRAME_AC97 * channels, BIT_PER_WORD_AC97);
+
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, SND_SOC_CLOCK_OUT);
+
+ return 0;
+}
+
+static struct snd_soc_ops imx_phycard_hifi_ops = {
+ .hw_params = imx_hw_params,
+};
+
+
+static struct snd_soc_dai_link imx_phycard_dai_ac97[] = {
+ {
+ .name = "HiFi",
+ .stream_name = "HiFi",
+ .codec_dai_name = "wm9712-hifi",
+ .codec_name = "wm9712-codec",
+ .cpu_dai_name = "imx-ssi.1",
+ .platform_name = "imx-pcm-audio.1",
+ .ops = &imx_phycard_hifi_ops,
+ },
+};
+
+static struct snd_soc_card imx_phycard = {
+ .name = "PhyCARD-ac97-audio",
+ .dai_link = imx_phycard_dai_ac97,
+ .num_links = ARRAY_SIZE(imx_phycard_dai_ac97),
+};
+
+static struct platform_device *imx_phycard_snd_ac97_device;
+static struct platform_device *imx_phycard_snd_device;
+
+static int __init imx_phycard_init(void)
+{
+ int ret;
+
+ imx_phycard_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+ if (!imx_phycard_snd_ac97_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(imx_phycard_snd_ac97_device, &imx_phycard);
+ ret = platform_device_add(imx_phycard_snd_ac97_device);
+ if (ret)
+ goto fail1;
+
+ imx_phycard_snd_device = platform_device_alloc("wm9712-codec", -1);
+ if (!imx_phycard_snd_device) {
+ ret = -ENOMEM;
+ goto fail2;
+ }
+ ret = platform_device_add(imx_phycard_snd_device);
+
+ if (ret) {
+ printk(KERN_ERR "ASoC: Platform device allocation failed\n");
+ goto fail3;
+ }
+
+ return 0;
+
+fail3:
+ platform_device_put(imx_phycard_snd_device);
+fail2:
+ platform_device_del(imx_phycard_snd_ac97_device);
+fail1:
+ platform_device_put(imx_phycard_snd_ac97_device);
+ return ret;
+}
+
+static void __exit imx_phycard_exit(void)
+{
+ platform_device_unregister(imx_phycard_snd_device);
+ platform_device_unregister(imx_phycard_snd_ac97_device);
+}
+
+late_initcall(imx_phycard_init);
+module_exit(imx_phycard_exit);
+
+MODULE_AUTHOR("Anatoly Palto");
+MODULE_DESCRIPTION("WM9712 PHYCard ASoC driver");
+MODULE_LICENSE("GPL");