diff options
| author | Anatoly Palto <a.palto@sam-solutions.net> | 2012-12-27 10:40:58 +0300 |
|---|---|---|
| committer | Justin Waters <justin.waters@timesys.com> | 2013-11-07 12:19:18 -0500 |
| commit | 267c0eb89e8391e2edcce20dc45e97f6796d4a09 (patch) | |
| tree | 9b7bde5d18a57cd123ec6c34a8d371133c33b1b8 | |
| parent | a0d0cb6a50fd9fb1dd070e2cc47077ca5acd4f82 (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.c | 89 | ||||
| -rw-r--r-- | sound/soc/imx/Kconfig | 10 | ||||
| -rw-r--r-- | sound/soc/imx/Makefile | 2 | ||||
| -rw-r--r-- | sound/soc/imx/imx-wm9712.c | 125 |
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"); |
