summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorXinyu Chen <xinyu.chen@freescale.com>2012-03-30 11:36:25 +0800
committerXinyu Chen <xinyu.chen@freescale.com>2012-03-30 11:36:25 +0800
commit88f08b421c91f2d4db3a110e5e3a86d64e2b40c9 (patch)
treee3af9f0bf2a355fd69119ae9b680371d39012a2d /sound
parent6cf2f136f3df6fad82ddabd89d93c53181564274 (diff)
parentf53c766e85d69add6a26d6f3e233dec6dc98de1e (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.c70
-rw-r--r--sound/soc/codecs/cs42888.h3
-rw-r--r--sound/soc/codecs/mxc_spdif.c97
-rw-r--r--sound/soc/codecs/mxc_spdif.h9
-rw-r--r--sound/soc/codecs/wm8962.c2
-rw-r--r--sound/soc/imx/Kconfig8
-rw-r--r--sound/soc/imx/Makefile5
-rw-r--r--sound/soc/imx/imx-cs42888.c21
-rw-r--r--sound/soc/imx/imx-esai.c11
-rw-r--r--sound/soc/imx/imx-hdmi-dma.c102
-rwxr-xr-xsound/soc/imx/imx-wm8958.c32
-rw-r--r--sound/soc/imx/imx-wm8962.c354
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");