diff options
author | Xinyu Chen <xinyu.chen@freescale.com> | 2012-03-30 11:36:25 +0800 |
---|---|---|
committer | Xinyu Chen <xinyu.chen@freescale.com> | 2012-03-30 11:36:25 +0800 |
commit | 88f08b421c91f2d4db3a110e5e3a86d64e2b40c9 (patch) | |
tree | e3af9f0bf2a355fd69119ae9b680371d39012a2d /sound | |
parent | 6cf2f136f3df6fad82ddabd89d93c53181564274 (diff) | |
parent | f53c766e85d69add6a26d6f3e233dec6dc98de1e (diff) |
Merge remote branch 'fsl-linux-sdk/imx_3.0.15' into imx_3.0.15_4.6.6
Conflicts:
arch/arm/configs/imx6_defconfig
arch/arm/configs/imx6_updater_defconfig
arch/arm/mach-mx6/board-mx6q_sabreauto.c
arch/arm/mach-mx6/board-mx6q_sabresd.c
arch/arm/mach-mx6/clock.c
arch/arm/mach-mx6/localtimer.c
drivers/cpufreq/Makefile
drivers/cpufreq/cpufreq_interactive.c
drivers/input/keyboard/gpio_keys.c
drivers/media/video/mxc/capture/Kconfig
drivers/media/video/mxc/capture/mxc_v4l2_capture.c
drivers/mmc/card/block.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_device.c
drivers/usb/otg/fsl_otg.c
drivers/video/mxc/mxc_ipuv3_fb.c
include/linux/fsl_devices.h
include/linux/mmc/host.h
sound/soc/imx/Kconfig
sound/soc/imx/Makefile
sound/soc/imx/imx-hdmi-dma.c
sound/soc/imx/imx-wm8958.c
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/codecs/cs42888.c | 70 | ||||
-rw-r--r-- | sound/soc/codecs/cs42888.h | 3 | ||||
-rw-r--r-- | sound/soc/codecs/mxc_spdif.c | 97 | ||||
-rw-r--r-- | sound/soc/codecs/mxc_spdif.h | 9 | ||||
-rw-r--r-- | sound/soc/codecs/wm8962.c | 2 | ||||
-rw-r--r-- | sound/soc/imx/Kconfig | 8 | ||||
-rw-r--r-- | sound/soc/imx/Makefile | 5 | ||||
-rw-r--r-- | sound/soc/imx/imx-cs42888.c | 21 | ||||
-rw-r--r-- | sound/soc/imx/imx-esai.c | 11 | ||||
-rw-r--r-- | sound/soc/imx/imx-hdmi-dma.c | 102 | ||||
-rwxr-xr-x | sound/soc/imx/imx-wm8958.c | 32 | ||||
-rw-r--r-- | sound/soc/imx/imx-wm8962.c | 354 |
12 files changed, 498 insertions, 216 deletions
diff --git a/sound/soc/codecs/cs42888.c b/sound/soc/codecs/cs42888.c index bc88a719df6f..86feec2676df 100644 --- a/sound/soc/codecs/cs42888.c +++ b/sound/soc/codecs/cs42888.c @@ -155,6 +155,7 @@ struct cs42888_private { unsigned int slave_mode; unsigned int manual_mute; struct regulator_bulk_data supplies[CS42888_NUM_SUPPLIES]; + struct mxc_audio_codec_platform_data pdata; }; /** @@ -445,21 +446,36 @@ SND_SOC_DAPM_INPUT("AIN1L"), SND_SOC_DAPM_INPUT("AIN1R"), SND_SOC_DAPM_INPUT("AIN2L"), SND_SOC_DAPM_INPUT("AIN2R"), + +SND_SOC_DAPM_PGA_E("PWR", CS42888_PWRCTL, 0, 1, NULL, 0, + NULL, 0), }; static const struct snd_soc_dapm_route audio_map[] = { /* Playback */ - { "AOUT1L", NULL, "DAC1" }, - { "AOUT1R", NULL, "DAC1" }, + { "PWR", NULL, "DAC1" }, + { "PWR", NULL, "DAC1" }, + + { "PWR", NULL, "DAC2" }, + { "PWR", NULL, "DAC2" }, + + { "PWR", NULL, "DAC3" }, + { "PWR", NULL, "DAC3" }, - { "AOUT2L", NULL, "DAC2" }, - { "AOUT2R", NULL, "DAC2" }, + { "PWR", NULL, "DAC4" }, + { "PWR", NULL, "DAC4" }, - { "AOUT3L", NULL, "DAC3" }, - { "AOUT3R", NULL, "DAC3" }, + { "AOUT1L", NULL, "PWR" }, + { "AOUT1R", NULL, "PWR" }, - { "AOUT4L", NULL, "DAC4" }, - { "AOUT4R", NULL, "DAC4" }, + { "AOUT2L", NULL, "PWR" }, + { "AOUT2R", NULL, "PWR" }, + + { "AOUT3L", NULL, "PWR" }, + { "AOUT3R", NULL, "PWR" }, + + { "AOUT4L", NULL, "PWR" }, + { "AOUT4R", NULL, "PWR" }, /* Capture */ { "ADC1", NULL, "AIN1L" }, @@ -682,15 +698,6 @@ static int cs42888_hw_params(struct snd_pcm_substream *substream, return ret; } - /* Out of low power state */ - val = snd_soc_read(codec, CS42888_PWRCTL); - val &= ~CS42888_PWRCTL_PDN_MASK; - ret = snd_soc_write(codec, CS42888_PWRCTL, val); - if (ret < 0) { - pr_err("i2c write failed\n"); - return ret; - } - /* Unmute all the channels */ val = snd_soc_read(codec, CS42888_MUTE); val &= ~CS42888_MUTE_ALL; @@ -737,12 +744,6 @@ static void cs42888_shutdown(struct snd_pcm_substream *substream, if (ret < 0) pr_err("i2c write failed\n"); - /* Enter low power state */ - val = snd_soc_read(codec, CS42888_PWRCTL); - val |= CS42888_PWRCTL_PDN_MASK; - ret = snd_soc_write(codec, CS42888_PWRCTL, val); - if (ret < 0) - pr_err("i2c write failed\n"); } static struct snd_soc_dai_ops cs42888_dai_ops = { @@ -759,28 +760,16 @@ struct snd_soc_dai_driver cs42888_dai = { .stream_name = "Playback", .channels_min = 1, .channels_max = 8, -#ifdef CONFIG_SOC_IMX53 - .rates = (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |\ + .rates = (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000), -#endif -#ifdef CONFIG_SOC_IMX6Q - .rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\ - SNDRV_PCM_RATE_176400), -#endif .formats = CS42888_FORMATS, }, .capture = { .stream_name = "Capture", .channels_min = 1, .channels_max = 4, -#ifdef CONFIG_SOC_IMX53 - .rates = (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |\ + .rates = (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000), -#endif -#ifdef CONFIG_SOC_IMX6Q - .rates = (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_88200 |\ - SNDRV_PCM_RATE_176400), -#endif .formats = CS42888_FORMATS, }, .ops = &cs42888_dai_ops, @@ -940,6 +929,13 @@ static int cs42888_i2c_probe(struct i2c_client *i2c_client, return -ENOMEM; } + if (i2c_client->dev.platform_data) { + memcpy(&cs42888->pdata, i2c_client->dev.platform_data, + sizeof(cs42888->pdata)); + cs42888_dai.playback.rates = cs42888->pdata.rates; + cs42888_dai.capture.rates = cs42888->pdata.rates; + } + i2c_set_clientdata(i2c_client, cs42888); ret = snd_soc_register_codec(&i2c_client->dev, diff --git a/sound/soc/codecs/cs42888.h b/sound/soc/codecs/cs42888.h index bea8beb8b70d..b4f3950e8271 100644 --- a/sound/soc/codecs/cs42888.h +++ b/sound/soc/codecs/cs42888.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2010-2012 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -19,7 +19,6 @@ * the .codec_dai field of your machine driver's snd_soc_dai_link structure. */ extern struct snd_soc_dai_driver cs42888_dai; -#define CS42888_RST 235 /* * The ASoC codec device structure for the CS42888. Assign this structure diff --git a/sound/soc/codecs/mxc_spdif.c b/sound/soc/codecs/mxc_spdif.c index e275735faa05..4d8e83b2032d 100644 --- a/sound/soc/codecs/mxc_spdif.c +++ b/sound/soc/codecs/mxc_spdif.c @@ -1,7 +1,7 @@ /* * MXC SPDIF ALSA Soc Codec Driver * - * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2007-2012 Freescale Semiconductor, Inc. */ /* @@ -329,20 +329,46 @@ static void spdif_softreset(void) value = __raw_readl(spdif_base_addr + SPDIF_REG_SCR) & 0x1000; } -/* - * Set clock accuracy information in consumer channel status. - */ -static int spdif_set_clk_accuracy(enum spdif_clk_accuracy level) +static void spdif_set_clk_accuracy(u8 level) { - unsigned long value; + mxc_spdif_control.ch_status[3] &= ~IEC958_AES3_CON_CLOCK; + mxc_spdif_control.ch_status[3] |= level & IEC958_AES3_CON_CLOCK; +} + +static void spdif_set_cstatus_fs(u8 cstatus_fs) +{ + /* set fs field in consumer channel status */ + mxc_spdif_control.ch_status[3] &= ~IEC958_AES3_CON_FS; + mxc_spdif_control.ch_status[3] |= cstatus_fs & IEC958_AES3_CON_FS; +} - value = __raw_readl(SPDIF_REG_STCSCL + spdif_base_addr) & 0xffffcf; - value |= (level << 4); - __raw_writel(value, SPDIF_REG_STCSCL + spdif_base_addr); +static u8 reverse_bits(u8 input) +{ + u8 i, output = 0; + for (i = 8 ; i > 0 ; i--) { + output <<= 1; + output |= input & 0x01; + input >>= 1; + } + return output; +} + +static void spdif_write_channel_status(void) +{ + unsigned int ch_status; - pr_debug("STCSCL: 0x%08x\n", __raw_readl(spdif_base_addr + SPDIF_REG_STCSCL)); + ch_status = + (reverse_bits(mxc_spdif_control.ch_status[0]) << 16) | + (reverse_bits(mxc_spdif_control.ch_status[1]) << 8) | + reverse_bits(mxc_spdif_control.ch_status[2]); - return 0; + __raw_writel(ch_status, SPDIF_REG_STCSCH + spdif_base_addr); + + ch_status = reverse_bits(mxc_spdif_control.ch_status[3]) << 16; + __raw_writel(ch_status, SPDIF_REG_STCSCL + spdif_base_addr); + + pr_debug("STCSCH: 0x%06x\n", __raw_readl(spdif_base_addr + SPDIF_REG_STCSCH)); + pr_debug("STCSCL: 0x%06x\n", __raw_readl(spdif_base_addr + SPDIF_REG_STCSCL)); } /* @@ -403,7 +429,7 @@ static int spdif_set_sample_rate(struct snd_soc_codec *codec, int sample_rate) { struct mxc_spdif_priv *spdif_priv = snd_soc_codec_get_drvdata(codec); struct mxc_spdif_platform_data *plat_data = spdif_priv->plat_data; - unsigned long cstatus, stc, clk = -1, div = 1, cstatus_fs = 0; + unsigned long stc, clk = -1, div = 1, cstatus_fs = 0; int clk_fs; switch (sample_rate) { @@ -411,14 +437,14 @@ static int spdif_set_sample_rate(struct snd_soc_codec *codec, int sample_rate) clk_fs = 44100; clk = plat_data->spdif_clk_44100; div = plat_data->spdif_div_44100; - cstatus_fs = 0; + cstatus_fs = IEC958_AES3_CON_FS_44100; break; case 48000: clk_fs = 48000; clk = plat_data->spdif_clk_48000; div = plat_data->spdif_div_48000; - cstatus_fs = 0x04; + cstatus_fs = IEC958_AES3_CON_FS_48000; break; case 32000: @@ -426,7 +452,7 @@ static int spdif_set_sample_rate(struct snd_soc_codec *codec, int sample_rate) clk_fs = 48000; clk = plat_data->spdif_clk_48000; div = plat_data->spdif_div_32000; - cstatus_fs = 0x0c; + cstatus_fs = IEC958_AES3_CON_FS_32000; break; default: @@ -455,10 +481,7 @@ static int spdif_set_sample_rate(struct snd_soc_codec *codec, int sample_rate) (int)clk_get_rate(plat_data->spdif_clk)); #endif - /* set fs field in consumer channel status */ - cstatus = __raw_readl(SPDIF_REG_STCSCL + spdif_base_addr) & 0xfffff0; - cstatus |= cstatus_fs; - __raw_writel(cstatus, SPDIF_REG_STCSCL + spdif_base_addr); + spdif_set_cstatus_fs(cstatus_fs); /* select clock source and divisor */ stc = __raw_readl(SPDIF_REG_STC + spdif_base_addr) & ~0x7FF; @@ -466,15 +489,6 @@ static int spdif_set_sample_rate(struct snd_soc_codec *codec, int sample_rate) __raw_writel(stc, SPDIF_REG_STC + spdif_base_addr); pr_debug("set sample rate to %d\n", sample_rate); - pr_debug("STCSCL: 0x%08x\n", __raw_readl(spdif_base_addr + SPDIF_REG_STCSCL)); - - return 0; -} - -static int spdif_set_channel_status(int value, unsigned long reg) -{ - __raw_writel(value & 0xffffff, reg + spdif_base_addr); - return 0; } @@ -537,7 +551,6 @@ static int mxc_spdif_playback_prepare(struct snd_pcm_substream *substream, struct mxc_spdif_priv *spdif_priv = snd_soc_codec_get_drvdata(codec); struct mxc_spdif_platform_data *plat_data = spdif_priv->plat_data; struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int ch_status; unsigned long regval; int err; @@ -555,27 +568,20 @@ static int mxc_spdif_playback_prepare(struct snd_pcm_substream *substream, sample rate */ __raw_writel(0x07, SPDIF_REG_STC + spdif_base_addr); - ch_status = ((mxc_spdif_control.ch_status[2] << 16) | - (mxc_spdif_control.ch_status[1] << 8) | - mxc_spdif_control.ch_status[0]); - spdif_set_channel_status(ch_status, SPDIF_REG_STCSCH); - ch_status = mxc_spdif_control.ch_status[3]; - spdif_set_channel_status(ch_status, SPDIF_REG_STCSCL); spdif_intr_enable(INT_TXFIFO_RESYNC, 1); + err = spdif_set_sample_rate(codec, runtime->rate); if (err < 0) { pr_info("%s - err < 0\n", __func__); return err; } - spdif_set_clk_accuracy(SPDIF_CLK_ACCURACY_LEV2); + spdif_set_clk_accuracy(IEC958_AES3_CON_CLOCK_1000PPM); + spdif_write_channel_status(); pr_debug("SCR: 0x%08x\n", __raw_readl(spdif_base_addr + SPDIF_REG_SCR)); pr_debug("SIE: 0x%08x\n", __raw_readl(spdif_base_addr + SPDIF_REG_SIE)); pr_debug("STC: 0x%08x\n", __raw_readl(spdif_base_addr + SPDIF_REG_STC)); - pr_debug("STCSCH: 0x%08x\n", __raw_readl(spdif_base_addr + SPDIF_REG_STCSCH)); - pr_debug("STCSCL: 0x%08x\n", __raw_readl(spdif_base_addr + SPDIF_REG_STCSCL)); - regval = __raw_readl(SPDIF_REG_SCR + spdif_base_addr); regval |= SCR_DMA_TX_EN; __raw_writel(regval, SPDIF_REG_SCR + spdif_base_addr); @@ -771,21 +777,12 @@ static int mxc_pb_spdif_get(struct snd_kcontrol *kcontrol, static int mxc_pb_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *uvalue) { - unsigned int ch_status; mxc_spdif_control.ch_status[0] = uvalue->value.iec958.status[0]; mxc_spdif_control.ch_status[1] = uvalue->value.iec958.status[1]; mxc_spdif_control.ch_status[2] = uvalue->value.iec958.status[2]; mxc_spdif_control.ch_status[3] = uvalue->value.iec958.status[3]; - ch_status = - ((mxc_spdif_control.ch_status[2] << 16) | - (mxc_spdif_control.ch_status[1] << 8) | - mxc_spdif_control.ch_status[0]); - spdif_set_channel_status(ch_status, SPDIF_REG_STCSCH); - ch_status = mxc_spdif_control.ch_status[3]; - spdif_set_channel_status(ch_status, SPDIF_REG_STCSCL); - - pr_debug("STCSCH: 0x%08x\n", __raw_readl(spdif_base_addr + SPDIF_REG_STCSCH)); - pr_debug("STCSCL: 0x%08x\n", __raw_readl(spdif_base_addr + SPDIF_REG_STCSCL)); + + spdif_write_channel_status(); return 0; } diff --git a/sound/soc/codecs/mxc_spdif.h b/sound/soc/codecs/mxc_spdif.h index 5c167e5bc76e..18ec3a7d9b3f 100644 --- a/sound/soc/codecs/mxc_spdif.h +++ b/sound/soc/codecs/mxc_spdif.h @@ -1,7 +1,7 @@ /* * ALSA SoC MXC SPDIF codec driver * - * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008-2012 Freescale Semiconductor, Inc. * * Based on stmp3xxx_spdif.h by: * Vladimir Barinov <vbarinov@embeddedalley.com> @@ -116,13 +116,6 @@ enum spdif_gainsel { #define SPDIF_UBITS_SIZE 96 #define SPDIF_QSUB_SIZE (SPDIF_UBITS_SIZE/8) -enum spdif_clk_accuracy { - SPDIF_CLK_ACCURACY_LEV2 = 0, - SPDIF_CLK_ACCURACY_LEV1 = 2, - SPDIF_CLK_ACCURACY_LEV3 = 1, - SPDIF_CLK_ACCURACY_RESV = 3 -}; - /* SPDIF clock source */ enum spdif_clk_src { SPDIF_CLK_SRC1 = 0, diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 4a0f666a90bd..7b14746d9336 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3834,7 +3834,7 @@ static int wm8962_probe(struct snd_soc_codec *codec) WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA, 0); - regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies); +/* regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);*/ if (pdata) { /* Apply static configuration for GPIOs */ diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index 4f95bacebae6..35472e835cf9 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig @@ -69,6 +69,14 @@ config SND_SOC_IMX_WM8958 Say Y if you want to add support for SoC audio on an i.MX board with a WM8958 codec. +config SND_SOC_IMX_WM8962 + tristate "SoC Audio support for IMX boards with WM8958" + select SND_MXC_SOC_MX2 + select SND_SOC_WM8962 + help + Say Y if you want to add support for SoC audio on an i.MX board with + a WM8958 codec. + config SND_SOC_IMX_CS42888 tristate "SoC Audio support for i.MX boards with cs42888" depends on I2C && (MACH_MX6Q_ARM2 || MACH_MX6Q_SABREAUTO || MACH_MX53_ARD) diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile index c1abab092adc..7b2fce6a37fc 100644 --- a/sound/soc/imx/Makefile +++ b/sound/soc/imx/Makefile @@ -14,6 +14,8 @@ snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o snd-soc-phycore-ac97-objs := phycore-ac97.o snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o snd-soc-wm1133-ev1-objs := wm1133-ev1.o +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-cs42888-objs := imx-cs42888.o snd-soc-imx-spdif-objs := imx-spdif.o @@ -24,8 +26,9 @@ obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o +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_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 -obj-$(CONFIG_SND_SOC_IMX_WM8958) += snd-soc-imx-wm8958.o
\ No newline at end of file diff --git a/sound/soc/imx/imx-cs42888.c b/sound/soc/imx/imx-cs42888.c index 26745d35b936..dc46fa676386 100644 --- a/sound/soc/imx/imx-cs42888.c +++ b/sound/soc/imx/imx-cs42888.c @@ -30,6 +30,7 @@ #include <mach/hardware.h> #include <mach/clock.h> +#include <asm/mach-types.h> #include "imx-esai.h" #include "../codecs/cs42888.h" @@ -40,7 +41,6 @@ struct imx_priv_state { static struct imx_priv_state hw_state; unsigned int mclk_freq; -int rst_gpio; static int imx_3stack_startup(struct snd_pcm_substream *substream) { @@ -49,15 +49,6 @@ static int imx_3stack_startup(struct snd_pcm_substream *substream) if (!cpu_dai->active) { hw_state.hw = 0; - if (rst_gpio) { - gpio_direction_output(rst_gpio, 0); - msleep(100); - gpio_direction_output(rst_gpio, 1); - } else { - gpio_direction_output(CS42888_RST, 0); - msleep(100); - gpio_direction_output(CS42888_RST, 1); - } } return 0; @@ -84,7 +75,7 @@ static int imx_3stack_surround_hw_params(struct snd_pcm_substream *substream, if (hw_state.hw) return 0; hw_state.hw = 1; - if (cpu_is_mx53()) { + if (cpu_is_mx53() || machine_is_mx6q_sabreauto()) { switch (rate) { case 32000: lrclk_ratio = 3; @@ -154,13 +145,12 @@ static int imx_3stack_surround_hw_params(struct snd_pcm_substream *substream, dai_format = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; - /* set cpu DAI configuration */ snd_soc_dai_set_fmt(cpu_dai, dai_format); /* set i.MX active slot mask */ snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 32); /* set the ESAI system clock as output */ - if (cpu_is_mx53()) { + if (cpu_is_mx53() || machine_is_mx6q_sabreauto()) { snd_soc_dai_set_sysclk(cpu_dai, ESAI_CLK_EXTAL, mclk_freq, SND_SOC_CLOCK_OUT); } else if (cpu_is_mx6q() || cpu_is_mx6dl()) { @@ -169,14 +159,14 @@ static int imx_3stack_surround_hw_params(struct snd_pcm_substream *substream, } /* set the ratio */ snd_soc_dai_set_clkdiv(cpu_dai, ESAI_TX_DIV_PSR, 1); - if (cpu_is_mx53()) + if (cpu_is_mx53() || machine_is_mx6q_sabreauto()) snd_soc_dai_set_clkdiv(cpu_dai, ESAI_TX_DIV_PM, 0); else if (cpu_is_mx6q() || cpu_is_mx6dl()) snd_soc_dai_set_clkdiv(cpu_dai, ESAI_TX_DIV_PM, 2); snd_soc_dai_set_clkdiv(cpu_dai, ESAI_TX_DIV_FP, lrclk_ratio); snd_soc_dai_set_clkdiv(cpu_dai, ESAI_RX_DIV_PSR, 1); - if (cpu_is_mx53()) + if (cpu_is_mx53() || machine_is_mx6q_sabreauto()) snd_soc_dai_set_clkdiv(cpu_dai, ESAI_RX_DIV_PM, 0); else if (cpu_is_mx6q() || cpu_is_mx6dl()) snd_soc_dai_set_clkdiv(cpu_dai, ESAI_RX_DIV_PM, 2); @@ -267,7 +257,6 @@ static int __devinit imx_3stack_cs42888_probe(struct platform_device *pdev) return -EINVAL; } mclk_freq = plat_data->sysclk; - rst_gpio = plat_data->rst_gpio; if (plat_data->codec_name) imx_3stack_dai[0].codec_name = plat_data->codec_name; return 0; diff --git a/sound/soc/imx/imx-esai.c b/sound/soc/imx/imx-esai.c index d3cf553bee2e..f6361716c20c 100644 --- a/sound/soc/imx/imx-esai.c +++ b/sound/soc/imx/imx-esai.c @@ -1,5 +1,5 @@ /* - * Copyright 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008-2012 Freescale Semiconductor, Inc. All Rights Reserved. */ /* @@ -280,16 +280,12 @@ static int imx_esai_startup(struct snd_pcm_substream *substream, if (!(local_esai->imx_esai_txrx_state & IMX_DAI_ESAI_TXRX)) { clk_enable(esai->clk); - writel(ESAI_ECR_ERST, esai->base + ESAI_ECR); - writel(ESAI_ECR_ESAIEN, esai->base + ESAI_ECR); - writel(ESAI_GPIO_ESAI, esai->base + ESAI_PRRC); writel(ESAI_GPIO_ESAI, esai->base + ESAI_PCRC); } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { local_esai->imx_esai_txrx_state |= IMX_DAI_ESAI_TX; - writel(ESAI_TCR_TPR, esai->base + ESAI_TCR); } else { local_esai->imx_esai_txrx_state |= IMX_DAI_ESAI_RX; writel(ESAI_RCR_RPR, esai->base + ESAI_RCR); @@ -458,7 +454,6 @@ static int imx_esai_trigger(struct snd_pcm_substream *substream, int cmd, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { tfcr |= ESAI_TFCR_TFEN; writel(tfcr, esai->base + ESAI_TFCR); - reg &= ~ESAI_TCR_TPR; reg |= ESAI_TCR_TE(substream->runtime->channels); writel(reg, esai->base + ESAI_TCR); } else { @@ -478,7 +473,6 @@ static int imx_esai_trigger(struct snd_pcm_substream *substream, int cmd, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { reg &= ~ESAI_TCR_TE(substream->runtime->channels); writel(reg, esai->base + ESAI_TCR); - reg |= ESAI_TCR_TPR; writel(reg, esai->base + ESAI_TCR); tfcr |= ESAI_TFCR_TFR; tfcr &= ~ESAI_TFCR_TFEN; @@ -661,6 +655,9 @@ static int imx_esai_probe(struct platform_device *pdev) goto failed_pdev_add; } + writel(ESAI_ECR_ERST, esai->base + ESAI_ECR); + writel(ESAI_ECR_ESAIEN, esai->base + ESAI_ECR); + return 0; failed_pdev_add: diff --git a/sound/soc/imx/imx-hdmi-dma.c b/sound/soc/imx/imx-hdmi-dma.c index 930cc2cc5785..c8e88ff79e3b 100644 --- a/sound/soc/imx/imx-hdmi-dma.c +++ b/sound/soc/imx/imx-hdmi-dma.c @@ -39,8 +39,7 @@ struct imx_hdmi_dma_runtime_data { struct snd_pcm_substream *tx_substream; unsigned long buffer_bytes; - struct snd_dma_buffer hw_buffer; - unsigned long appl_bytes; + void *buf; int period_time; int periods; @@ -148,7 +147,7 @@ static void dumprtd(struct imx_hdmi_dma_runtime_data *rtd) pr_debug("period_bytes = %d\n", rtd->period_bytes); pr_debug("dma period_bytes = %d\n", rtd->dma_period_bytes); pr_debug("buffer_ratio = %d\n", rtd->buffer_ratio); - pr_debug("hw dma buffer = 0x%08x\n", (int)rtd->hw_buffer.addr); + pr_debug("dma buf addr = 0x%08x\n", (int)rtd->buf); pr_debug("dma buf size = %d\n", (int)rtd->buffer_bytes); pr_debug("sample_rate = %d\n", (int)rtd->rate); } @@ -270,41 +269,10 @@ static void hdmi_dma_incr_frame_idx(struct imx_hdmi_dma_runtime_data *rtd) rtd->frame_idx = 0; } -static void hdmi_dma_mmap_copy(struct snd_pcm_substream *substream, - int offset, int count) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct imx_hdmi_dma_runtime_data *rtd = runtime->private_data; - u32 *hw_buf, *dma_buf_u32; - u16 *dma_buf_u16; - int subframe_idx; - - /* dma_buffer is the mmapped buffer we are copying pcm from. */ - dma_buf_u16 = (u16 *)(runtime->dma_area + offset); - dma_buf_u32 = (u32 *)(runtime->dma_area + offset); - - /* hw_buffer is the destination for pcm data plus frame info. */ - hw_buf = (u32 *)(rtd->hw_buffer.area + (offset * rtd->buffer_ratio)); - - while (count > 0) { - for (subframe_idx = 1 ; subframe_idx <= rtd->channels ; subframe_idx++) { - if (rtd->sample_align == 2) - *hw_buf++ = hdmi_dma_add_frame_info(rtd, *dma_buf_u16++, subframe_idx); - else - *hw_buf++ = hdmi_dma_add_frame_info(rtd, *dma_buf_u32++, subframe_idx); - - count -= rtd->sample_align; - } - hdmi_dma_incr_frame_idx(rtd); - } -} - static irqreturn_t hdmi_dma_isr(int irq, void *dev_id) { struct imx_hdmi_dma_runtime_data *rtd = dev_id; struct snd_pcm_substream *substream = rtd->tx_substream; - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned long offset, count, space_to_end, appl_bytes; unsigned int status; unsigned long flags; @@ -314,32 +282,14 @@ static irqreturn_t hdmi_dma_isr(int irq, void *dev_id) status = hdmi_dma_get_irq_status(); hdmi_dma_clear_irq_status(status); - if (runtime && runtime->dma_area && rtd->tx_active && - (status & HDMI_IH_AHBDMAAUD_STAT0_DONE)) { + if (rtd->tx_active && (status & HDMI_IH_AHBDMAAUD_STAT0_DONE)) { rtd->offset += rtd->period_bytes; rtd->offset %= rtd->period_bytes * rtd->periods; - /* For mmap access, need to copy data from dma_buffer to hw_buffer - * and add the frame info. */ - if (runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) { - appl_bytes = frames_to_bytes(runtime, - runtime->control->appl_ptr); - count = appl_bytes - rtd->appl_bytes; - offset = rtd->appl_bytes % rtd->buffer_bytes; - space_to_end = rtd->buffer_bytes - offset; - - if (count <= space_to_end) - hdmi_dma_mmap_copy(substream, offset, count); - else { - hdmi_dma_mmap_copy(substream, offset, space_to_end); - hdmi_dma_mmap_copy(substream, 0, count - space_to_end); - } - rtd->appl_bytes = appl_bytes; - } - snd_pcm_period_elapsed(substream); - hdmi_dma_set_addr(rtd->hw_buffer.addr + (rtd->offset * rtd->buffer_ratio), + hdmi_dma_set_addr(substream->dma_buffer.addr + + (rtd->offset * rtd->buffer_ratio), rtd->dma_period_bytes); hdmi_dma_start(); @@ -514,8 +464,8 @@ static int hdmi_dma_copy(struct snd_pcm_substream *substream, int channel, int subframe_idx; u32 pcm_data; - /* Copy pcm data from userspace and add frame info. Destination is hw_buffer. */ - hw_buf = (u32 *)(rtd->hw_buffer.area + (pos_bytes * rtd->buffer_ratio)); + /* Copy pcm data from userspace and add frame info. */ + hw_buf = (u32 *)(rtd->buf + (pos_bytes * rtd->buffer_ratio)); while (count > 0) { for (subframe_idx = 1 ; subframe_idx <= rtd->channels ; subframe_idx++) { @@ -550,6 +500,7 @@ static int hdmi_dma_hw_params(struct snd_pcm_substream *substream, rtd->offset = 0; rtd->period_time = HZ / (params_rate(params) / params_period_size(params)); + rtd->buf = (unsigned int *)substream->dma_buffer.area; switch (rtd->format) { case SNDRV_PCM_FORMAT_S16_LE: @@ -574,7 +525,7 @@ static int hdmi_dma_hw_params(struct snd_pcm_substream *substream, snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); hdmi_dma_configure_dma(rtd->channels); - hdmi_dma_set_addr(rtd->hw_buffer.addr, rtd->dma_period_bytes); + hdmi_dma_set_addr(substream->dma_buffer.addr, rtd->dma_period_bytes); dumprtd(rtd); @@ -593,12 +544,6 @@ static int hdmi_dma_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: rtd->frame_idx = 0; - if (runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) { - rtd->appl_bytes = frames_to_bytes(runtime, - runtime->control->appl_ptr); - - hdmi_dma_mmap_copy(substream, 0, rtd->appl_bytes); - } dumpregs(); hdmi_dma_irq_mask(0); hdmi_dma_priv->tx_active = true; @@ -631,8 +576,6 @@ static snd_pcm_uframes_t hdmi_dma_pointer(struct snd_pcm_substream *substream) static struct snd_pcm_hardware snd_imx_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, .formats = MXC_HDMI_FORMATS_PLAYBACK, @@ -734,12 +677,9 @@ static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) { struct snd_pcm_substream *substream = pcm->streams[stream].substream; struct snd_dma_buffer *buf = &substream->dma_buffer; - struct snd_dma_buffer *hw_buffer = &hdmi_dma_priv->hw_buffer; + size_t size = HDMI_DMA_BUF_SIZE; - /* The 'dma_buffer' is the buffer alsa knows about. - * It contains only raw audio. */ - buf->area = dma_alloc_writecombine(pcm->card->dev, - HDMI_DMA_BUF_SIZE / 2, + buf->area = dma_alloc_writecombine(pcm->card->dev, size, &buf->addr, GFP_KERNEL); if (!buf->area) return -ENOMEM; @@ -747,19 +687,10 @@ static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) buf->dev.type = SNDRV_DMA_TYPE_DEV; buf->dev.dev = pcm->card->dev; buf->private_data = NULL; - buf->bytes = HDMI_DMA_BUF_SIZE / 2; + buf->bytes = size; hdmi_dma_priv->tx_substream = substream; - /* For mmap access, isr will copy from the dma_buffer to the hw_buffer */ - hw_buffer->area = dma_alloc_writecombine(pcm->card->dev, - HDMI_DMA_BUF_SIZE, - &hw_buffer->addr, GFP_KERNEL); - if (!hw_buffer->area) - return -ENOMEM; - - hw_buffer->bytes = HDMI_DMA_BUF_SIZE; - return 0; } @@ -790,7 +721,6 @@ static void imx_hdmi_dma_pcm_free(struct snd_pcm *pcm) struct snd_dma_buffer *buf; int stream; - /* free each dma_buffer */ for (stream = 0; stream < 2; stream++) { substream = pcm->streams[stream].substream; if (!substream) @@ -804,14 +734,6 @@ static void imx_hdmi_dma_pcm_free(struct snd_pcm *pcm) buf->area, buf->addr); buf->area = NULL; } - - /* free the hw_buffer */ - buf = &hdmi_dma_priv->hw_buffer; - if (buf->area) { - dma_free_writecombine(pcm->card->dev, buf->bytes, - buf->area, buf->addr); - buf->area = NULL; - } } static struct snd_soc_platform_driver imx_soc_platform_mx2 = { diff --git a/sound/soc/imx/imx-wm8958.c b/sound/soc/imx/imx-wm8958.c index f40d8adc347b..328bb0b6ca10 100755 --- a/sound/soc/imx/imx-wm8958.c +++ b/sound/soc/imx/imx-wm8958.c @@ -27,6 +27,7 @@ #include <linux/fsl_devices.h> #include <linux/slab.h> #include <linux/gpio.h> +#include <linux/clk.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -54,6 +55,7 @@ struct imx_priv { static struct imx_priv card_priv; static struct snd_soc_card snd_soc_card_imx; +struct clk *codec_mclk; static struct snd_soc_jack hs_jack; /* Headphones jack detection DAPM pins */ @@ -76,11 +78,23 @@ static struct snd_soc_jack_gpio hs_jack_gpios[] = { static int imx_hifi_startup(struct snd_pcm_substream *substream) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + if (!codec_dai->active) + clk_enable(codec_mclk); + return 0; } static void imx_hifi_shutdown(struct snd_pcm_substream *substream) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + if (!codec_dai->active) + clk_disable(codec_mclk); + return; } @@ -241,7 +255,7 @@ static DRIVER_ATTR(headphone, S_IRUGO | S_IWUSR, show_headphone, NULL); static int imx_wm8958_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; - int ret, i; + int ret; /* Add imx specific widgets */ snd_soc_dapm_new_controls(&codec->dapm, imx_dapm_widgets, @@ -250,11 +264,12 @@ static int imx_wm8958_init(struct snd_soc_pcm_runtime *rtd) /* Set up imx specific audio path audio_map */ snd_soc_dapm_add_routes(&codec->dapm, audio_map, ARRAY_SIZE(audio_map)); + snd_soc_dapm_enable_pin(&codec->dapm, "Headphone Jack"); + snd_soc_dapm_sync(&codec->dapm); -/*headphone detection conflict with the headphone jack*/ -/* if (hs_jack_gpios[0].gpio != -1) { + /* Jack detection API stuff */ ret = snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, &hs_jack); if (ret) @@ -272,7 +287,7 @@ static int imx_wm8958_init(struct snd_soc_pcm_runtime *rtd) if (ret) printk(KERN_WARNING "failed to call snd_soc_jack_add_gpios\n"); } -*/ + return 0; } @@ -333,6 +348,12 @@ static int __devinit imx_wm8958_probe(struct platform_device *pdev) struct wm8994 *wm8958 = plat->priv; int ret = 0; + codec_mclk = clk_get(NULL, "clko_clk"); + if (IS_ERR(codec_mclk)) { + printk(KERN_ERR "can't get CLKO clock.\n"); + return PTR_ERR(codec_mclk); + } + priv->pdev = pdev; priv->wm8958 = wm8958; priv->hp_irq = gpio_to_irq(plat->hp_gpio); @@ -372,6 +393,9 @@ static int __devexit imx_wm8958_remove(struct platform_device *pdev) if (plat->finit) plat->finit(); + clk_disable(codec_mclk); + clk_put(codec_mclk); + return 0; } diff --git a/sound/soc/imx/imx-wm8962.c b/sound/soc/imx/imx-wm8962.c new file mode 100644 index 000000000000..3154cbcd7dfc --- /dev/null +++ b/sound/soc/imx/imx-wm8962.c @@ -0,0 +1,354 @@ +/* + * imx-wm8962.c + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * 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: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/bitops.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/fsl_devices.h> +#include <linux/slab.h> +#include <linux/clk.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 <sound/jack.h> +#include <mach/dma.h> +#include <mach/clock.h> +#include <mach/audmux.h> + +#include "imx-ssi.h" +#include "../codecs/wm8962.h" + +struct imx_priv { + int sysclk; /*mclk from the outside*/ + int codec_sysclk; + int dai_hifi; + struct platform_device *pdev; +}; + +static struct imx_priv card_priv; +static struct snd_soc_card snd_soc_card_imx; +struct clk *wm8962_mclk; +static struct snd_soc_jack hs_jack; + +/* Headphones jack detection DAPM pins */ +static struct snd_soc_jack_pin hs_jack_pins[] = { + { + .pin = "Headphone Jack", + .mask = SND_JACK_HEADPHONE, + }, +}; + +/* Headphones jack detection gpios */ +static struct snd_soc_jack_gpio hs_jack_gpios[] = { + [0] = { + /* gpio is set on per-platform basis */ + .name = "hp-gpio", + .report = SND_JACK_HEADPHONE, + .debounce_time = 200, + }, +}; + +static int imx_hifi_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + if (!codec_dai->active) + clk_enable(wm8962_mclk); + + return 0; +} + +static void imx_hifi_shutdown(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + if (!codec_dai->active) + clk_disable(wm8962_mclk); + + return; +} + +static int imx_hifi_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; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct imx_priv *priv = &card_priv; + unsigned int channels = params_channels(params); + unsigned int sample_rate = 44100; + int ret = 0; + u32 dai_format; + + dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM; + + /* set codec DAI configuration */ + ret = snd_soc_dai_set_fmt(codec_dai, dai_format); + if (ret < 0) + return ret; + + /* set i.MX active slot mask */ + snd_soc_dai_set_tdm_slot(cpu_dai, + channels == 1 ? 0xfffffffe : 0xfffffffc, + channels == 1 ? 0xfffffffe : 0xfffffffc, + 2, 32); + + /* set cpu DAI configuration */ + ret = snd_soc_dai_set_fmt(cpu_dai, dai_format); + if (ret < 0) + return ret; + + sample_rate = params_rate(params); + + ret = snd_soc_dai_set_pll(codec_dai, WM8962_FLL_INT, + WM8962_FLL_MCLK, priv->sysclk, + sample_rate * 768); + if (ret < 0) + pr_err("Failed to start FLL: %d\n", ret); + + ret = snd_soc_dai_set_sysclk(codec_dai, + WM8962_SYSCLK_FLL, + sample_rate * 768, + SND_SOC_CLOCK_IN); + if (ret < 0) { + pr_err("Failed to set SYSCLK: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct snd_kcontrol_new controls[] = { + SOC_DAPM_PIN_SWITCH("Main Speaker"), + SOC_DAPM_PIN_SWITCH("DMIC"), +}; + +/* imx card dapm widgets */ +static const struct snd_soc_dapm_widget imx_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + + SND_SOC_DAPM_MIC("AMIC", NULL), + + SND_SOC_DAPM_SPK("Ext Spk", NULL), +}; + +/* imx machine connections to the codec pins */ +static const struct snd_soc_dapm_route audio_map[] = { + { "Headphone Jack", NULL, "HPOUTL" }, + { "Headphone Jack", NULL, "HPOUTR" }, + + { "Ext Spk", NULL, "SPKOUTL" }, + { "Ext Spk", NULL, "SPKOUTR" }, + + { "MICBIAS", NULL, "AMIC" }, + { "IN3R", NULL, "MICBIAS" }, + +}; + +static int imx_wm8962_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_codec *codec = rtd->codec; + int ret; + +/* Add imx specific widgets */ + snd_soc_dapm_new_controls(&codec->dapm, imx_dapm_widgets, + ARRAY_SIZE(imx_dapm_widgets)); + + /* Set up imx specific audio path audio_map */ + snd_soc_dapm_add_routes(&codec->dapm, audio_map, ARRAY_SIZE(audio_map)); + + snd_soc_dapm_enable_pin(&codec->dapm, "Headphone Jack"); + snd_soc_dapm_enable_pin(&codec->dapm, "AMIC"); + + snd_soc_dapm_sync(&codec->dapm); + + if (hs_jack_gpios[0].gpio != -1) { + /* Jack detection API stuff */ + ret = snd_soc_jack_new(codec, "Headphone Jack", + SND_JACK_HEADPHONE, &hs_jack); + if (ret) + return ret; + + ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), + hs_jack_pins); + if (ret) { + printk(KERN_ERR "failed to call snd_soc_jack_add_pins\n"); + return ret; + } + + ret = snd_soc_jack_add_gpios(&hs_jack, + ARRAY_SIZE(hs_jack_gpios), hs_jack_gpios); + if (ret) + printk(KERN_WARNING "failed to call snd_soc_jack_add_gpios\n"); + } + + return 0; +} + +static struct snd_soc_ops imx_hifi_ops = { + .startup = imx_hifi_startup, + .shutdown = imx_hifi_shutdown, + .hw_params = imx_hifi_hw_params, +}; + +static struct snd_soc_dai_link imx_dai[] = { + { + .name = "HiFi", + .stream_name = "HiFi", + .codec_dai_name = "wm8962", + .codec_name = "wm8962.0-001a", + .cpu_dai_name = "imx-ssi.1", + .platform_name = "imx-pcm-audio.1", + .init = imx_wm8962_init, + .ops = &imx_hifi_ops, + }, +}; + +static struct snd_soc_card snd_soc_card_imx = { + .name = "wm8962-audio", + .dai_link = imx_dai, + .num_links = ARRAY_SIZE(imx_dai), +}; + +static int imx_audmux_config(int slave, int master) +{ + unsigned int ptcr, pdcr; + slave = slave - 1; + master = master - 1; + + ptcr = MXC_AUDMUX_V2_PTCR_SYN | + MXC_AUDMUX_V2_PTCR_TFSDIR | + MXC_AUDMUX_V2_PTCR_TFSEL(master) | + MXC_AUDMUX_V2_PTCR_TCLKDIR | + MXC_AUDMUX_V2_PTCR_TCSEL(master); + pdcr = MXC_AUDMUX_V2_PDCR_RXDSEL(master); + mxc_audmux_v2_configure_port(slave, ptcr, pdcr); + + ptcr = MXC_AUDMUX_V2_PTCR_SYN; + pdcr = MXC_AUDMUX_V2_PDCR_RXDSEL(slave); + mxc_audmux_v2_configure_port(master, ptcr, pdcr); + + return 0; +} + +/* + * This function will register the snd_soc_pcm_link drivers. + */ +static int __devinit imx_wm8962_probe(struct platform_device *pdev) +{ + + struct mxc_audio_platform_data *plat = pdev->dev.platform_data; + struct imx_priv *priv = &card_priv; + int ret = 0; + + wm8962_mclk = clk_get(NULL, "clko_clk"); + if (IS_ERR(wm8962_mclk)) { + printk(KERN_ERR "can't get CLKO clock.\n"); + return PTR_ERR(wm8962_mclk); + } + + priv->pdev = pdev; + + imx_audmux_config(plat->src_port, plat->ext_port); + + if (plat->init && plat->init()) { + ret = -EINVAL; + return ret; + } + + priv->sysclk = plat->sysclk; + hs_jack_gpios[0].gpio = plat->hp_gpio; + hs_jack_gpios[0].invert = plat->hp_active_low; + + return ret; +} + +static int __devexit imx_wm8962_remove(struct platform_device *pdev) +{ + struct mxc_audio_platform_data *plat = pdev->dev.platform_data; + + if (plat->finit) + plat->finit(); + + clk_disable(wm8962_mclk); + clk_put(wm8962_mclk); + + return 0; +} + +static struct platform_driver imx_wm8962_driver = { + .probe = imx_wm8962_probe, + .remove = imx_wm8962_remove, + .driver = { + .name = "imx-wm8962", + .owner = THIS_MODULE, + }, +}; + +static struct platform_device *imx_snd_device; + +static int __init imx_asoc_init(void) +{ + int ret; + + ret = platform_driver_register(&imx_wm8962_driver); + if (ret < 0) + goto exit; + + imx_snd_device = platform_device_alloc("soc-audio", 5); + if (!imx_snd_device) + goto err_device_alloc; + + platform_set_drvdata(imx_snd_device, &snd_soc_card_imx); + + ret = platform_device_add(imx_snd_device); + + if (0 == ret) + goto exit; + + platform_device_put(imx_snd_device); + +err_device_alloc: + platform_driver_unregister(&imx_wm8962_driver); +exit: + return ret; +} + +static void __exit imx_asoc_exit(void) +{ + platform_driver_unregister(&imx_wm8962_driver); + platform_device_unregister(imx_snd_device); +} + +module_init(imx_asoc_init); +module_exit(imx_asoc_exit); + +/* Module information */ +MODULE_DESCRIPTION("ALSA SoC imx wm8962"); +MODULE_LICENSE("GPL"); |