summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/arm/mxc-alsa-spdif.c18
-rw-r--r--sound/soc/codecs/Kconfig4
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/mxs-adc-codec.c237
-rw-r--r--sound/soc/codecs/sgtl5000.c49
-rw-r--r--sound/soc/codecs/wm8753.c14
-rw-r--r--sound/soc/codecs/wm8753.h1
-rw-r--r--sound/soc/imx/Kconfig10
-rw-r--r--sound/soc/imx/Makefile3
-rw-r--r--sound/soc/imx/imx-3stack-ak4647.c3
-rw-r--r--sound/soc/imx/imx-3stack-ak5702.c4
-rw-r--r--sound/soc/imx/imx-3stack-wm8580.c10
-rw-r--r--sound/soc/imx/imx-ccwmx51-wm8753.c38
-rw-r--r--sound/soc/imx/imx-esai.c353
-rw-r--r--sound/soc/imx/imx-esai.h286
-rw-r--r--sound/soc/imx/imx-pcm.c8
-rw-r--r--sound/soc/mxs/mxs-adc.c246
-rw-r--r--sound/soc/mxs/mxs-dai.c1
-rw-r--r--sound/soc/mxs/mxs-evk-adc.c107
-rw-r--r--sound/soc/mxs/mxs-pcm.c4
20 files changed, 942 insertions, 456 deletions
diff --git a/sound/arm/mxc-alsa-spdif.c b/sound/arm/mxc-alsa-spdif.c
index 93a34cd03e11..ae48051b49e8 100644
--- a/sound/arm/mxc-alsa-spdif.c
+++ b/sound/arm/mxc-alsa-spdif.c
@@ -257,6 +257,7 @@ struct mxc_spdif_device {
* SPDIF module register base address
*/
unsigned long __iomem *reg_base;
+ unsigned long reg_phys_base;
/*!
* spdif tx available or not
@@ -943,8 +944,9 @@ static void spdif_stop_tx(struct mxc_spdif_stream *s)
*/
static void spdif_start_tx(struct mxc_spdif_stream *s)
{
- struct snd_pcm_substream *substream;
- struct snd_pcm_runtime *runtime;
+ struct snd_pcm_substream *substream = s->stream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct mxc_spdif_device *chip = snd_pcm_substream_chip(substream);
unsigned int dma_size = 0;
unsigned int offset;
int ret = 0;
@@ -960,7 +962,7 @@ static void spdif_start_tx(struct mxc_spdif_stream *s)
(NULL, runtime->dma_area + offset, dma_size,
DMA_TO_DEVICE));
- dma_request.dst_addr = (dma_addr_t) (SPDIF_BASE_ADDR + 0x2c);
+ dma_request.dst_addr = (dma_addr_t) (chip->reg_phys_base + 0x2c);
dma_request.num_of_bytes = dma_size;
mxc_dma_config(s->dma_wchannel, &dma_request, 1,
@@ -1279,15 +1281,14 @@ static void spdif_stop_rx(struct mxc_spdif_stream *s)
*/
static void spdif_start_rx(struct mxc_spdif_stream *s)
{
- struct snd_pcm_substream *substream;
- struct snd_pcm_runtime *runtime;
+ struct snd_pcm_substream *substream = s->stream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct mxc_spdif_device *chip = snd_pcm_substream_chip(substream);
unsigned int dma_size = 0;
unsigned int offset;
int ret = 0;
mxc_dma_requestbuf_t dma_request;
- substream = s->stream;
- runtime = substream->runtime;
memset(&dma_request, 0, sizeof(mxc_dma_requestbuf_t));
if (s->active) {
@@ -1305,7 +1306,7 @@ static void spdif_start_rx(struct mxc_spdif_stream *s)
DMA_FROM_DEVICE));
dma_request.src_addr =
- (dma_addr_t) (SPDIF_BASE_ADDR + SPDIF_REG_SRL);
+ (dma_addr_t) (chip->reg_phys_base + SPDIF_REG_SRL);
dma_request.num_of_bytes = dma_size;
/* config and enable sdma for RX */
mxc_dma_config(s->dma_wchannel, &dma_request, 1,
@@ -2089,6 +2090,7 @@ static int mxc_alsa_spdif_probe(struct platform_device
chip = card->private_data;
chip->card = card;
card->dev = &pdev->dev;
+ chip->reg_phys_base = res->start;
chip->reg_base = ioremap(res->start, res->end - res->start + 1);
spdif_base_addr = (unsigned long)chip->reg_base;
plat_data = (struct mxc_spdif_platform_data *)pdev->dev.platform_data;
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 4362689dd639..dd28cad09934 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -17,6 +17,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_AK4104 if SPI_MASTER
select SND_SOC_AK4535 if I2C
select SND_SOC_CS4270 if I2C
+ select SND_SOC_CS42888 if I2C
select SND_SOC_PCM3008
select SND_SOC_SPDIF
select SND_SOC_SSM2602 if I2C
@@ -90,6 +91,9 @@ config SND_SOC_CS4270_VD33_ERRATA
bool
depends on SND_SOC_CS4270
+config SND_SOC_CS42888
+ tristate
+
config SND_SOC_L3
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 8add6333d7c5..8fd4da08392c 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -5,6 +5,7 @@ snd-soc-ak4104-objs := ak4104.o
snd-soc-ak4535-objs := ak4535.o
snd-soc-ak5702-objs := ak5702.o
snd-soc-cs4270-objs := cs4270.o
+snd-soc-cs42888-objs := cs42888.o
snd-soc-l3-objs := l3.o
snd-soc-pcm3008-objs := pcm3008.o
snd-soc-spdif-objs := spdif_transciever.o
@@ -50,6 +51,7 @@ obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o
obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
obj-$(CONFIG_SND_SOC_AK5702) += snd-soc-ak5702.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
+obj-$(CONFIG_SND_SOC_CS42888) += snd-soc-cs42888.o
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o
diff --git a/sound/soc/codecs/mxs-adc-codec.c b/sound/soc/codecs/mxs-adc-codec.c
index 246dab352342..f8f10619731a 100644
--- a/sound/soc/codecs/mxs-adc-codec.c
+++ b/sound/soc/codecs/mxs-adc-codec.c
@@ -48,6 +48,8 @@
#define BF(value, field) (((value) << BP_##field) & BM_##field)
#endif
+#define BM_RTC_PERSISTENT0_RELEASE_GND BF(0x2, RTC_PERSISTENT0_SPARE_ANALOG)
+
#define REGS_RTC_BASE (IO_ADDRESS(RTC_PHYS_ADDR))
struct mxs_codec_priv {
@@ -252,6 +254,47 @@ static int dac_put_volsw(struct snd_kcontrol *kcontrol,
return 0;
}
+static int pga_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Prepare powering up HP and SPEAKER output */
+ __raw_writel(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET);
+ __raw_writel(BM_RTC_PERSISTENT0_RELEASE_GND,
+ REGS_RTC_BASE + HW_RTC_PERSISTENT0_SET);
+ msleep(100);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ __raw_writel(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ __raw_writel(BM_RTC_PERSISTENT0_RELEASE_GND,
+ REGS_RTC_BASE + HW_RTC_PERSISTENT0_CLR);
+ break;
+ }
+ return 0;
+}
+
+static int adc_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ __raw_writel(BM_RTC_PERSISTENT0_RELEASE_GND,
+ REGS_RTC_BASE + HW_RTC_PERSISTENT0_SET);
+ msleep(100);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ __raw_writel(BM_RTC_PERSISTENT0_RELEASE_GND,
+ REGS_RTC_BASE + HW_RTC_PERSISTENT0_CLR);
+ break;
+ }
+ return 0;
+}
+
static const char *mxs_codec_adc_input_sel[] =
{ "Mic", "Line In 1", "Head Phone", "Line In 2" };
@@ -282,8 +325,6 @@ static const struct snd_kcontrol_new mxs_snd_controls[] = {
SOC_DOUBLE_R("DAC Playback Switch",
DAC_VOLUME_H, DAC_VOLUME_L, 8, 0x01, 1),
SOC_DOUBLE("HP Playback Volume", DAC_HPVOL_L, 8, 0, 0x7F, 1),
- SOC_SINGLE("HP Playback Switch", DAC_HPVOL_H, 8, 0x1, 1),
- SOC_SINGLE("Speaker Playback Switch", DAC_SPEAKERCTRL_H, 8, 0x1, 1),
/* Capture Volume */
SOC_DOUBLE_R("ADC Capture Volume",
@@ -310,10 +351,10 @@ SOC_DAPM_ENUM("Route", mxs_codec_enum[2]);
static const struct snd_soc_dapm_widget mxs_codec_widgets[] = {
- SND_SOC_DAPM_ADC("Left ADC", "Left Capture", DAC_PWRDN_L, 8, 1),
- SND_SOC_DAPM_ADC("Right ADC", "Right Capture", DAC_PWRDN_H, 0, 1),
+ SND_SOC_DAPM_ADC_E("ADC", "Capture", DAC_PWRDN_L, 8, 1, adc_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("DAC", "Playback", DAC_PWRDN_L, 12, 1),
SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0,
&mxs_left_adc_controls),
@@ -321,7 +362,10 @@ static const struct snd_soc_dapm_widget mxs_codec_widgets[] = {
&mxs_right_adc_controls),
SND_SOC_DAPM_MUX("HP Mux", SND_SOC_NOPM, 0, 0,
&mxs_hp_controls),
-
+ SND_SOC_DAPM_PGA_E("HP AMP", DAC_PWRDN_L, 0, 1, NULL, 0, pga_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA("SPEAKER AMP", DAC_PWRDN_H, 8, 1, NULL, 0),
SND_SOC_DAPM_INPUT("LINE1L"),
SND_SOC_DAPM_INPUT("LINE1R"),
SND_SOC_DAPM_INPUT("LINE2L"),
@@ -348,20 +392,23 @@ static const struct snd_soc_dapm_route intercon[] = {
{"Right ADC Mux", "Head Phone", "HPR"},
/* ADC */
- {"Left ADC", NULL, "Left ADC Mux"},
- {"Right ADC", NULL, "Right ADC Mux"},
+ {"ADC", NULL, "Left ADC Mux"},
+ {"ADC", NULL, "Right ADC Mux"},
/* HP Mux */
{"HP Mux", "DAC Out", "DAC"},
{"HP Mux", "Line In 1", "LINE1L"},
{"HP Mux", "Line In 1", "LINE1R"},
+ /* HP amp */
+ {"HP AMP", NULL, "HP Mux"},
/* HP output */
- {"HPR", NULL, "HP MUX"},
- {"HPL", NULL, "HP MUX"},
+ {"HPR", NULL, "HP AMP"},
+ {"HPL", NULL, "HP AMP"},
/* Speaker amp */
- {"SPEAKER", NULL, "DAC"},
+ {"SPEAKER AMP", NULL, "DAC"},
+ {"SPEAKER", NULL, "SPEAKER AMP"},
};
static int mxs_codec_add_widgets(struct snd_soc_codec *codec)
@@ -488,29 +535,84 @@ static int mxs_codec_hw_params(struct snd_pcm_substream *substream,
static int mxs_codec_dig_mute(struct snd_soc_dai *dai, int mute)
{
+ int l, r;
+ int ll, rr;
+ u32 reg, reg1, reg2;
u32 dac_mask = BM_AUDIOOUT_DACVOLUME_MUTE_LEFT |
BM_AUDIOOUT_DACVOLUME_MUTE_RIGHT;
- u32 reg1 = 0;
- u32 reg = 0;
if (mute) {
- reg1 = __raw_readl(REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL);
- reg = reg1 | BF_AUDIOOUT_HPVOL_VOL_LEFT(0x7f) | \
- BF_AUDIOOUT_HPVOL_VOL_RIGHT(0x7f);
- __raw_writel(reg, REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL);
+ reg = __raw_readl(REGS_AUDIOOUT_BASE + \
+ HW_AUDIOOUT_DACVOLUME);
+
+ reg1 = reg & ~BM_AUDIOOUT_DACVOLUME_VOLUME_LEFT;
+ reg1 = reg1 & ~BM_AUDIOOUT_DACVOLUME_VOLUME_RIGHT;
+
+ l = (reg & BM_AUDIOOUT_DACVOLUME_VOLUME_LEFT) >>
+ BP_AUDIOOUT_DACVOLUME_VOLUME_LEFT;
+ r = (reg & BM_AUDIOOUT_DACVOLUME_VOLUME_RIGHT) >>
+ BP_AUDIOOUT_DACVOLUME_VOLUME_RIGHT;
+
+ /* fade out dac vol */
+ while ((l > DAC_VOLUME_MIN) || (r > DAC_VOLUME_MIN)) {
+ l -= 0x8;
+ r -= 0x8;
+ ll = l > DAC_VOLUME_MIN ? l : DAC_VOLUME_MIN;
+ rr = r > DAC_VOLUME_MIN ? r : DAC_VOLUME_MIN;
+ reg2 = reg1 | BF_AUDIOOUT_DACVOLUME_VOLUME_LEFT(ll)
+ | BF_AUDIOOUT_DACVOLUME_VOLUME_RIGHT(rr);
+ __raw_writel(reg2,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_DACVOLUME);
+ msleep(1);
+ }
__raw_writel(dac_mask,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_DACVOLUME_SET);
- __raw_writel(BM_AUDIOOUT_HPVOL_MUTE,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_SET);
-
- __raw_writel(reg1, REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL);
- } else {
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_DACVOLUME_SET);
+ reg = reg | dac_mask;
+ __raw_writel(reg,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_DACVOLUME);
+ } else
__raw_writel(dac_mask,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_DACVOLUME_CLR);
- __raw_writel(BM_AUDIOOUT_HPVOL_MUTE,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_CLR);
+
+ return 0;
+}
+
+static int mxs_codec_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ pr_debug("dapm level %d\n", level);
+ switch (level) {
+ case SND_SOC_BIAS_ON: /* full On */
+ if (codec->bias_level == SND_SOC_BIAS_ON)
+ break;
+ break;
+
+ case SND_SOC_BIAS_PREPARE: /* partial On */
+ if (codec->bias_level == SND_SOC_BIAS_PREPARE)
+ break;
+ /* Set Capless mode */
+ __raw_writel(BM_AUDIOOUT_PWRDN_CAPLESS,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_CLR);
+ break;
+
+ case SND_SOC_BIAS_STANDBY: /* Off, with power */
+ if (codec->bias_level == SND_SOC_BIAS_STANDBY)
+ break;
+ /* Unset Capless mode */
+ __raw_writel(BM_AUDIOOUT_PWRDN_CAPLESS,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_SET);
+ break;
+
+ case SND_SOC_BIAS_OFF: /* Off, without power */
+ if (codec->bias_level == SND_SOC_BIAS_OFF)
+ break;
+ /* Unset Capless mode */
+ __raw_writel(BM_AUDIOOUT_PWRDN_CAPLESS,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_SET);
+ break;
}
+ codec->bias_level = level;
return 0;
}
@@ -533,6 +635,58 @@ static void mxs_codec_dac_set_vag(void)
__raw_writel(refctrl_val, REGS_AUDIOOUT_BASE + HW_AUDIOOUT_REFCTRL);
}
+static bool mxs_codec_dac_is_capless()
+{
+ if ((__raw_readl(REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN)
+ & BM_AUDIOOUT_PWRDN_CAPLESS) == 0)
+ return false;
+ else
+ return true;
+}
+static void mxs_codec_dac_arm_short_cm(bool bShort)
+{
+ __raw_writel(BF(3, AUDIOOUT_ANACTRL_SHORTMODE_CM),
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
+ __raw_writel(BM_AUDIOOUT_ANACTRL_SHORT_CM_STS,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
+ if (bShort)
+ __raw_writel(BF(1, AUDIOOUT_ANACTRL_SHORTMODE_CM),
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET);
+}
+static void mxs_codec_dac_arm_short_lr(bool bShort)
+{
+ __raw_writel(BF(3, AUDIOOUT_ANACTRL_SHORTMODE_LR),
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
+ __raw_writel(BM_AUDIOOUT_ANACTRL_SHORT_LR_STS,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
+ if (bShort)
+ __raw_writel(BF(1, AUDIOOUT_ANACTRL_SHORTMODE_LR),
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET);
+}
+static void mxs_codec_dac_set_short_trip_level(u8 u8level)
+{
+ __raw_writel(__raw_readl(REGS_AUDIOOUT_BASE +
+ HW_AUDIOOUT_ANACTRL)
+ & (~BM_AUDIOOUT_ANACTRL_SHORT_LVLADJL)
+ & (~BM_AUDIOOUT_ANACTRL_SHORT_LVLADJR)
+ | BF(u8level, AUDIOOUT_ANACTRL_SHORT_LVLADJL)
+ | BF(u8level, AUDIOOUT_ANACTRL_SHORT_LVLADJR),
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL);
+}
+static void mxs_codec_dac_arm_short(bool bLatchCM, bool bLatchLR)
+{
+ if (bLatchCM) {
+ if (mxs_codec_dac_is_capless())
+ mxs_codec_dac_arm_short_cm(true);
+ } else
+ mxs_codec_dac_arm_short_cm(false);
+
+ if (bLatchLR)
+ mxs_codec_dac_arm_short_lr(true);
+ else
+ mxs_codec_dac_arm_short_lr(false);
+
+}
static void
mxs_codec_dac_power_on(struct mxs_codec_priv *mxs_adc)
{
@@ -542,17 +696,13 @@ mxs_codec_dac_power_on(struct mxs_codec_priv *mxs_adc)
__raw_writel(BM_AUDIOOUT_ANACLKCTRL_CLKGATE,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACLKCTRL_CLR);
- /* Set capless mode */
- __raw_writel(BM_AUDIOOUT_PWRDN_CAPLESS, REGS_AUDIOOUT_BASE
- + HW_AUDIOOUT_PWRDN_CLR);
-
/* 16 bit word length */
__raw_writel(BM_AUDIOOUT_CTRL_WORD_LENGTH,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_SET);
- /* Powerup DAC */
- __raw_writel(BM_AUDIOOUT_PWRDN_DAC,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_CLR);
+ /* Arm headphone LR short protect */
+ mxs_codec_dac_set_short_trip_level(0);
+ mxs_codec_dac_arm_short(false, true);
/* Update DAC volume over zero crossings */
__raw_writel(BM_AUDIOOUT_DACVOLUME_EN_ZCD,
@@ -566,30 +716,26 @@ mxs_codec_dac_power_on(struct mxs_codec_priv *mxs_adc)
__raw_writel(BM_AUDIOOUT_HPVOL_EN_MSTR_ZCD,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_SET);
- /* Prepare powering up HP output */
- __raw_writel(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET);
- __raw_writel(BF(0x2, RTC_PERSISTENT0_SPARE_ANALOG),
- REGS_RTC_BASE + HW_RTC_PERSISTENT0_SET);
- __raw_writel(BM_AUDIOOUT_PWRDN_HEADPHONE,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_CLR);
__raw_writel(BM_AUDIOOUT_ANACTRL_HP_CLASSAB,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET);
- __raw_writel(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
+
/* Mute HP output */
__raw_writel(BM_AUDIOOUT_HPVOL_MUTE,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_SET);
- __raw_writel(BM_AUDIOOUT_PWRDN_SPEAKER,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_CLR);
/* Mute speaker amp */
__raw_writel(BM_AUDIOOUT_SPEAKERCTRL_MUTE,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_SPEAKERCTRL_SET);
+ /* Enable the audioout */
+ __raw_writel(BM_AUDIOOUT_CTRL_RUN,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_SET);
}
static void
mxs_codec_dac_power_down(struct mxs_codec_priv *mxs_adc)
{
+ /* Disable the audioout */
+ __raw_writel(BM_AUDIOOUT_CTRL_RUN,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_CLR);
/* Disable class AB */
__raw_writel(BM_AUDIOOUT_ANACTRL_HP_CLASSAB,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
@@ -858,7 +1004,8 @@ static int mxs_codec_probe(struct platform_device *pdev)
snd_soc_free_pcms(socdev);
return ret;
}
-
+ /* Set default bias level*/
+ mxs_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
@@ -982,6 +1129,8 @@ static int __init mxs_codec_audio_probe(struct platform_device *pdev)
codec->private_data = mxs_adc;
codec->read = mxs_codec_read;
codec->write = mxs_codec_write;
+ codec->bias_level = SND_SOC_BIAS_OFF;
+ codec->set_bias_level = mxs_codec_set_bias_level;
codec->dai = &mxs_codec_dai;
codec->num_dai = 1;
codec->reg_cache_size = sizeof(mxs_audio_regs) >> 1;
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index a63b65cdc04d..9bea4d8a523d 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -200,39 +200,6 @@ static void dump_reg(struct snd_soc_codec *codec)
}
#endif
-static int dac_mux_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
- struct snd_soc_codec *codec = widget->codec;
- unsigned int reg;
-
- if (ucontrol->value.enumerated.item[0]) {
- reg = sgtl5000_read(codec, SGTL5000_CHIP_CLK_TOP_CTRL);
- reg |= SGTL5000_INT_OSC_EN;
- sgtl5000_write(codec, SGTL5000_CHIP_CLK_TOP_CTRL, reg);
-
- if (codec->bias_level != SND_SOC_BIAS_ON) {
- sgtl5000_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
- snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
- sgtl5000_set_bias_level(codec, SND_SOC_BIAS_ON);
- } else
- snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
-
- reg = sgtl5000_read(codec, SGTL5000_CHIP_ANA_CTRL);
- reg &= ~(SGTL5000_LINE_OUT_MUTE | SGTL5000_HP_MUTE);
- sgtl5000_write(codec, SGTL5000_CHIP_ANA_CTRL, reg);
- } else {
- reg = sgtl5000_read(codec, SGTL5000_CHIP_CLK_TOP_CTRL);
- reg &= ~SGTL5000_INT_OSC_EN;
- sgtl5000_write(codec, SGTL5000_CHIP_CLK_TOP_CTRL, reg);
-
- snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
- sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- }
- return 0;
-}
-
static const char *adc_mux_text[] = {
"MIC_IN", "LINE_IN"
};
@@ -250,16 +217,8 @@ SOC_ENUM_SINGLE(SGTL5000_CHIP_ANA_CTRL, 6, 2, dac_mux_text);
static const struct snd_kcontrol_new adc_mux =
SOC_DAPM_ENUM("ADC Mux", adc_enum);
-static const struct snd_kcontrol_new dac_mux = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "DAC Mux",
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE
- | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
- .info = snd_soc_info_enum_double,
- .get = snd_soc_dapm_get_enum_double,
- .put = dac_mux_put,
- .private_value = (unsigned long)&dac_enum,
-};
+static const struct snd_kcontrol_new dac_mux =
+SOC_DAPM_ENUM("DAC Mux", dac_enum);
static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("LINE_IN"),
@@ -649,6 +608,8 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream,
fs = sgtl5000->lrclk;
/* SGTL5000 rev1 has a IC bug to prevent switching to MCLK from PLL. */
if (!sgtl5000->master) {
+ sys_fs = sgtl5000->lrclk;
+ clk_ctl = SGTL5000_RATE_MODE_DIV_1 << SGTL5000_RATE_MODE_SHIFT;
if (fs * 256 == sgtl5000->sysclk)
clk_ctl |= SGTL5000_MCLK_FREQ_256FS << \
SGTL5000_MCLK_FREQ_SHIFT;
@@ -783,7 +744,7 @@ static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,
avoid pops. */
reg = sgtl5000_read(codec, SGTL5000_CHIP_ANA_POWER);
if (reg & SGTL5000_VAG_POWERUP)
- delay = 400;
+ delay = 600;
reg &= ~SGTL5000_VAG_POWERUP;
reg |= SGTL5000_DAC_POWERUP;
reg |= SGTL5000_HP_POWERUP;
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index 921932ab2d3a..7b3963461234 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -595,6 +595,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
/* Mono Capture mixer-mux */
{"Capture Right Mixer", "Stereo", "Capture Right Mux"},
+ {"Capture Left Mixer", "Stereo", "Capture Left Mux"},
{"Capture Left Mixer", "Analogue Mix Left", "Capture Left Mux"},
{"Capture Left Mixer", "Analogue Mix Left", "Capture Right Mux"},
{"Capture Right Mixer", "Analogue Mix Right", "Capture Left Mux"},
@@ -1265,6 +1266,13 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_ON:
/* set vmid to 50k and unmute dac */
wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0);
+
+ /* wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00c0); */
+ /*
+ * Force the enable of the MICBIAS, otherwise the microphone will not
+ * work.
+ */
+ wm8753_write(codec, WM8753_PWR1, pwr_reg | 0x00e0);
break;
case SND_SOC_BIAS_PREPARE:
/* set vmid to 5k for quick power up */
@@ -1702,6 +1710,12 @@ static int wm8753_register(struct wm8753_priv *wm8753)
wm8753_codec = codec;
+ /* Configure bclk as mclk/4 */
+ reg = wm8753_read_reg_cache(codec, WM8753_SRATE2);
+ reg &= ~WM8753_BCLK_DIV_MASK;
+ reg |= WM8753_BCLK_DIV_4;
+ wm8753_write(codec, WM8753_SRATE2, reg);
+
for (i = 0; i < ARRAY_SIZE(wm8753_dai); i++)
wm8753_dai[i].dev = codec->dev;
diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h
index 57b2ba244040..40c55ad713aa 100644
--- a/sound/soc/codecs/wm8753.h
+++ b/sound/soc/codecs/wm8753.h
@@ -99,6 +99,7 @@
#define WM8753_PCM_DIV_8 (7 << 6)
/* BCLK clock dividers */
+#define WM8753_BCLK_DIV_MASK (7 << 3)
#define WM8753_BCLK_DIV_1 (0 << 3)
#define WM8753_BCLK_DIV_2 (1 << 3)
#define WM8753_BCLK_DIV_4 (2 << 3)
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
index 43b6d8e3b10c..afefe2c5585c 100644
--- a/sound/soc/imx/Kconfig
+++ b/sound/soc/imx/Kconfig
@@ -79,4 +79,14 @@ config SND_SOC_IMX_3STACK_BLUETOOTH
help
Say Y if you want to add support for Soc audio on IMX 3STACK
with the BLUETOOTH
+
+config SND_SOC_IMX_3STACK_CS42888
+ tristate "SoC Audio support for IMX - CS42888"
+ select SND_MXC_SOC_ESAI
+ select SND_SOC_CS42888
+ help
+ Say Y if you want to add support for Soc audio on IMX 3STACK
+ with the CS42888
+
+
endif
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
index 284be7777de7..7cc8d1f32674 100644
--- a/sound/soc/imx/Makefile
+++ b/sound/soc/imx/Makefile
@@ -24,3 +24,6 @@ snd-soc-imx-3stack-ak5702-objs := imx-3stack-ak5702.o
obj-$(CONFIG_SND_SOC_IMX_3STACK_AK5702) += snd-soc-imx-3stack-ak5702.o
snd-soc-imx-3stack-bt-objs := imx-3stack-bt.o
obj-$(CONFIG_SND_SOC_IMX_3STACK_BLUETOOTH) += snd-soc-imx-3stack-bt.o
+snd-soc-imx-3stack-cs42888-objs := imx-3stack-cs42888.o
+obj-$(CONFIG_SND_SOC_IMX_3STACK_CS42888) += snd-soc-imx-3stack-cs42888.o
+
diff --git a/sound/soc/imx/imx-3stack-ak4647.c b/sound/soc/imx/imx-3stack-ak4647.c
index 6d6a98fd02e0..56c7a498e5b1 100644
--- a/sound/soc/imx/imx-3stack-ak4647.c
+++ b/sound/soc/imx/imx-3stack-ak4647.c
@@ -363,8 +363,6 @@ static int __init imx_3stack_ak4647_probe(struct platform_device *pdev)
imx_3stack_dai.cpu_dai = ak4647_cpu_dai;
- /* Configure audio port 3 */
- gpio_activate_audio_ports();
imx_3stack_init_dam(dev_data->src_port, dev_data->ext_port);
ret = request_irq(dev_data->intr_id_hp, imx_headphone_detect_handler, 0,
@@ -388,7 +386,6 @@ err:
static int __devexit imx_3stack_ak4647_remove(struct platform_device *pdev)
{
struct mxc_audio_platform_data *dev_data = pdev->dev.platform_data;
- gpio_inactivate_audio_ports();
free_irq(dev_data->intr_id_hp, NULL);
driver_remove_file(pdev->dev.driver, &driver_attr_headphone);
return 0;
diff --git a/sound/soc/imx/imx-3stack-ak5702.c b/sound/soc/imx/imx-3stack-ak5702.c
index 7603c0f0ae19..734399434aa9 100644
--- a/sound/soc/imx/imx-3stack-ak5702.c
+++ b/sound/soc/imx/imx-3stack-ak5702.c
@@ -1,7 +1,7 @@
/*
* imx-3stack-ak5702.c -- SoC audio for imx_3stack
*
- * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -171,13 +171,11 @@ static int __devinit imx_3stack_ak5702_probe(struct platform_device *pdev)
setup->i2c_address = 0x13;
imx_3stack_snd_devdata.codec_data = setup;
- gpio_activate_esai_ports();
return 0;
}
static int imx_3stack_ak5702_remove(struct platform_device *pdev)
{
- gpio_deactivate_esai_ports();
return 0;
}
diff --git a/sound/soc/imx/imx-3stack-wm8580.c b/sound/soc/imx/imx-3stack-wm8580.c
index 631571ddb5ef..f3f9f85ca0f0 100644
--- a/sound/soc/imx/imx-3stack-wm8580.c
+++ b/sound/soc/imx/imx-3stack-wm8580.c
@@ -1,7 +1,7 @@
/*
* imx-3stack-wm8580.c -- SoC 5.1 audio for imx_3stack
*
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -69,9 +69,6 @@ struct imx_3stack_pcm_state {
int lr_clk_active;
};
-extern void gpio_activate_esai_ports(void);
-extern void gpio_deactivate_esai_ports(void);
-
static struct imx_3stack_pcm_state clk_state;
static int imx_3stack_startup(struct snd_pcm_substream *substream)
@@ -374,20 +371,17 @@ static int __devinit imx_3stack_wm8580_probe(struct platform_device *pdev)
struct wm8580_setup_data *setup;
imx_3stack_dai.cpu_dai = &imx_esai_dai[2];
+ imx_3stack_dai.cpu_dai->dev = &pdev->dev;
setup = kzalloc(sizeof(struct wm8580_setup_data), GFP_KERNEL);
setup->spi = 1;
imx_3stack_snd_devdata.codec_data = setup;
- /* Configure audio port 3 */
- gpio_activate_esai_ports();
-
return 0;
}
static int __devexit imx_3stack_wm8580_remove(struct platform_device *pdev)
{
- gpio_deactivate_esai_ports();
return 0;
}
diff --git a/sound/soc/imx/imx-ccwmx51-wm8753.c b/sound/soc/imx/imx-ccwmx51-wm8753.c
index a12285fb1a8d..e92df8914b1c 100644
--- a/sound/soc/imx/imx-ccwmx51-wm8753.c
+++ b/sound/soc/imx/imx-ccwmx51-wm8753.c
@@ -54,14 +54,47 @@ static int imx_ccwmx51_audio_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai_link *machine = rtd->dai;
struct snd_soc_dai *cpu_dai = machine->cpu_dai;
struct snd_soc_dai *codec_dai = machine->codec_dai;
+ unsigned int rate = params_rate(params);
struct imx_ccwmx51_priv *priv = &card_priv;
struct imx_ssi *ssi_mode = (struct imx_ssi *)cpu_dai->private_data;
int ret = 0;
+ unsigned int pll_out = 0;
unsigned int channels = params_channels(params);
u32 dai_format;
- snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, priv->sysclk, 0);
+ switch (rate) {
+ case 8000:
+ pll_out = 12288000;
+ break;
+ case 11025:
+ pll_out = 11289600;
+ break;
+ case 16000:
+ pll_out = 12288000;
+ break;
+ case 22050:
+ pll_out = 11289600;
+ break;
+ case 32000:
+ pll_out = 12288000;
+ break;
+ case 44100:
+ pll_out = 11289600;
+ break;
+ case 48000:
+ pll_out = 12288000;
+ break;
+ case 88200:
+ pll_out = 11289600;
+ break;
+ case 96000:
+ pll_out = 12288000;
+ break;
+ default:
+ pr_info("Rate not supported.\n");
+ return -EINVAL;;
+ }
#if WM8753_SSI_MASTER
dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
@@ -94,6 +127,9 @@ static int imx_ccwmx51_audio_hw_params(struct snd_pcm_substream *substream,
/* set the SSI system clock as input (unused) */
snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, SND_SOC_CLOCK_IN);
+ priv->sysclk = pll_out;
+ snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, priv->sysclk, 0);
+ snd_soc_dai_set_pll(codec_dai, WM8753_MCLK, 13000000, pll_out);
return 0;
}
diff --git a/sound/soc/imx/imx-esai.c b/sound/soc/imx/imx-esai.c
index 71dd62cff509..0c6b234f29ec 100644
--- a/sound/soc/imx/imx-esai.c
+++ b/sound/soc/imx/imx-esai.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -35,292 +35,9 @@
#include "imx-esai.h"
#include "imx-pcm.h"
-/*#define IMX_ESAI_DUMP 1*/
-
-#ifdef IMX_ESAI_DUMP
-#define ESAI_DUMP() \
- do {pr_info("dump @ %s\n", __func__); \
- pr_info("ecr %x\n", __raw_readl(ESAI_ECR)); \
- pr_info("esr %x\n", __raw_readl(ESAI_ESR)); \
- pr_info("tfcr %x\n", __raw_readl(ESAI_TFCR)); \
- pr_info("tfsr %x\n", __raw_readl(ESAI_TFSR)); \
- pr_info("rfcr %x\n", __raw_readl(ESAI_RFCR)); \
- pr_info("rfsr %x\n", __raw_readl(ESAI_RFSR)); \
- pr_info("tsr %x\n", __raw_readl(ESAI_TSR)); \
- pr_info("saisr %x\n", __raw_readl(ESAI_SAISR)); \
- pr_info("saicr %x\n", __raw_readl(ESAI_SAICR)); \
- pr_info("tcr %x\n", __raw_readl(ESAI_TCR)); \
- pr_info("tccr %x\n", __raw_readl(ESAI_TCCR)); \
- pr_info("rcr %x\n", __raw_readl(ESAI_RCR)); \
- pr_info("rccr %x\n", __raw_readl(ESAI_RCCR)); \
- pr_info("tsma %x\n", __raw_readl(ESAI_TSMA)); \
- pr_info("tsmb %x\n", __raw_readl(ESAI_TSMB)); \
- pr_info("rsma %x\n", __raw_readl(ESAI_RSMA)); \
- pr_info("rsmb %x\n", __raw_readl(ESAI_RSMB)); \
- pr_info("prrc %x\n", __raw_readl(ESAI_PRRC)); \
- pr_info("pcrc %x\n", __raw_readl(ESAI_PCRC)); } while (0);
-#else
-#define ESAI_DUMP()
-#endif
-
-#define ESAI_IO_BASE_ADDR IO_ADDRESS(ESAI_BASE_ADDR)
-
-#define ESAI_ETDR (ESAI_IO_BASE_ADDR + 0x00)
-#define ESAI_ERDR (ESAI_IO_BASE_ADDR + 0x04)
-#define ESAI_ECR (ESAI_IO_BASE_ADDR + 0x08)
-#define ESAI_ESR (ESAI_IO_BASE_ADDR + 0x0C)
-#define ESAI_TFCR (ESAI_IO_BASE_ADDR + 0x10)
-#define ESAI_TFSR (ESAI_IO_BASE_ADDR + 0x14)
-#define ESAI_RFCR (ESAI_IO_BASE_ADDR + 0x18)
-#define ESAI_RFSR (ESAI_IO_BASE_ADDR + 0x1C)
-#define ESAI_TX0 (ESAI_IO_BASE_ADDR + 0x80)
-#define ESAI_TX1 (ESAI_IO_BASE_ADDR + 0x84)
-#define ESAI_TX2 (ESAI_IO_BASE_ADDR + 0x88)
-#define ESAI_TX3 (ESAI_IO_BASE_ADDR + 0x8C)
-#define ESAI_TX4 (ESAI_IO_BASE_ADDR + 0x90)
-#define ESAI_TX5 (ESAI_IO_BASE_ADDR + 0x94)
-#define ESAI_TSR (ESAI_IO_BASE_ADDR + 0x98)
-#define ESAI_RX0 (ESAI_IO_BASE_ADDR + 0xA0)
-#define ESAI_RX1 (ESAI_IO_BASE_ADDR + 0xA4)
-#define ESAI_RX2 (ESAI_IO_BASE_ADDR + 0xA8)
-#define ESAI_RX3 (ESAI_IO_BASE_ADDR + 0xAC)
-#define ESAI_SAISR (ESAI_IO_BASE_ADDR + 0xCC)
-#define ESAI_SAICR (ESAI_IO_BASE_ADDR + 0xD0)
-#define ESAI_TCR (ESAI_IO_BASE_ADDR + 0xD4)
-#define ESAI_TCCR (ESAI_IO_BASE_ADDR + 0xD8)
-#define ESAI_RCR (ESAI_IO_BASE_ADDR + 0xDC)
-#define ESAI_RCCR (ESAI_IO_BASE_ADDR + 0xE0)
-#define ESAI_TSMA (ESAI_IO_BASE_ADDR + 0xE4)
-#define ESAI_TSMB (ESAI_IO_BASE_ADDR + 0xE8)
-#define ESAI_RSMA (ESAI_IO_BASE_ADDR + 0xEC)
-#define ESAI_RSMB (ESAI_IO_BASE_ADDR + 0xF0)
-#define ESAI_PRRC (ESAI_IO_BASE_ADDR + 0xF8)
-#define ESAI_PCRC (ESAI_IO_BASE_ADDR + 0xFC)
-
-#define ESAI_ECR_ETI (1 << 19)
-#define ESAI_ECR_ETO (1 << 18)
-#define ESAI_ECR_ERI (1 << 17)
-#define ESAI_ECR_ERO (1 << 16)
-#define ESAI_ECR_ERST (1 << 1)
-#define ESAI_ECR_ESAIEN (1 << 0)
-
-#define ESAI_ESR_TINIT (1 << 10)
-#define ESAI_ESR_RFF (1 << 9)
-#define ESAI_ESR_TFE (1 << 8)
-#define ESAI_ESR_TLS (1 << 7)
-#define ESAI_ESR_TDE (1 << 6)
-#define ESAI_ESR_TED (1 << 5)
-#define ESAI_ESR_TD (1 << 4)
-#define ESAI_ESR_RLS (1 << 3)
-#define ESAI_ESR_RDE (1 << 2)
-#define ESAI_ESR_RED (1 << 1)
-#define ESAI_ESR_RD (1 << 0)
-
-#define ESAI_TFCR_TIEN (1 << 19)
-#define ESAI_TFCR_TE5 (1 << 7)
-#define ESAI_TFCR_TE4 (1 << 6)
-#define ESAI_TFCR_TE3 (1 << 5)
-#define ESAI_TFCR_TE2 (1 << 4)
-#define ESAI_TFCR_TE1 (1 << 3)
-#define ESAI_TFCR_TE0 (1 << 2)
-#define ESAI_TFCR_TFR (1 << 1)
-#define ESAI_TFCR_TFEN (1 << 0)
-#define ESAI_TFCR_TE(x) ((0x3f >> (6 - ((x + 1) >> 1))) << 2)
-#define ESAI_TFCR_TE_MASK 0xfff03
-#define ESAI_TFCR_TFWM(x) ((x - 1) << 8)
-#define ESAI_TFCR_TWA_MASK 0xf8ffff
-
-#define ESAI_RFCR_REXT (1 << 19)
-#define ESAI_RFCR_RE3 (1 << 5)
-#define ESAI_RFCR_RE2 (1 << 4)
-#define ESAI_RFCR_RE1 (1 << 3)
-#define ESAI_RFCR_RE0 (1 << 2)
-#define ESAI_RFCR_RFR (1 << 1)
-#define ESAI_RFCR_RFEN (1 << 0)
-#define ESAI_RFCR_RE(x) ((0xf >> (4 - ((x + 1) >> 1))) << 3)
-#define ESAI_RFCR_RE_MASK 0xfffc3
-#define ESAI_RFCR_RFWM(x) ((x-1) << 8)
-#define ESAI_RFCR_RWA_MASK 0xf8ffff
-
-#define ESAI_WORD_LEN_32 (0x00 << 16)
-#define ESAI_WORD_LEN_28 (0x01 << 16)
-#define ESAI_WORD_LEN_24 (0x02 << 16)
-#define ESAI_WORD_LEN_20 (0x03 << 16)
-#define ESAI_WORD_LEN_16 (0x04 << 16)
-#define ESAI_WORD_LEN_12 (0x05 << 16)
-#define ESAI_WORD_LEN_8 (0x06 << 16)
-#define ESAI_WORD_LEN_4 (0x07 << 16)
-
-#define ESAI_SAISR_TODFE (1 << 17)
-#define ESAI_SAISR_TEDE (1 << 16)
-#define ESAI_SAISR_TDE (1 << 15)
-#define ESAI_SAISR_TUE (1 << 14)
-#define ESAI_SAISR_TFS (1 << 13)
-#define ESAI_SAISR_RODF (1 << 10)
-#define ESAI_SAISR_REDF (1 << 9)
-#define ESAI_SAISR_RDF (1 << 8)
-#define ESAI_SAISR_ROE (1 << 7)
-#define ESAI_SAISR_RFS (1 << 6)
-#define ESAI_SAISR_IF2 (1 << 2)
-#define ESAI_SAISR_IF1 (1 << 1)
-#define ESAI_SAISR_IF0 (1 << 0)
-
-#define ESAI_SAICR_ALC (1 << 8)
-#define ESAI_SAICR_TEBE (1 << 7)
-#define ESAI_SAICR_SYNC (1 << 6)
-#define ESAI_SAICR_OF2 (1 << 2)
-#define ESAI_SAICR_OF1 (1 << 1)
-#define ESAI_SAICR_OF0 (1 << 0)
-
-#define ESAI_TCR_TLIE (1 << 23)
-#define ESAI_TCR_TIE (1 << 22)
-#define ESAI_TCR_TEDIE (1 << 21)
-#define ESAI_TCR_TEIE (1 << 20)
-#define ESAI_TCR_TPR (1 << 19)
-#define ESAI_TCR_PADC (1 << 17)
-#define ESAI_TCR_TFSR (1 << 16)
-#define ESAI_TCR_TFSL (1 << 15)
-#define ESAI_TCR_TWA (1 << 7)
-#define ESAI_TCR_TSHFD_MSB (0 << 6)
-#define ESAI_TCR_TSHFD_LSB (1 << 6)
-#define ESAI_TCR_TE5 (1 << 5)
-#define ESAI_TCR_TE4 (1 << 4)
-#define ESAI_TCR_TE3 (1 << 3)
-#define ESAI_TCR_TE2 (1 << 2)
-#define ESAI_TCR_TE1 (1 << 1)
-#define ESAI_TCR_TE0 (1 << 0)
-#define ESAI_TCR_TE(x) (0x3f >> (6 - ((x + 1) >> 1)))
-
-#define ESAI_TCR_TSWS_MASK 0xff83ff
-#define ESAI_TCR_TSWS_STL8_WDL8 (0x00 << 10)
-#define ESAI_TCR_TSWS_STL12_WDL8 (0x04 << 10)
-#define ESAI_TCR_TSWS_STL12_WDL12 (0x01 << 10)
-#define ESAI_TCR_TSWS_STL16_WDL8 (0x08 << 10)
-#define ESAI_TCR_TSWS_STL16_WDL12 (0x05 << 10)
-#define ESAI_TCR_TSWS_STL16_WDL16 (0x02 << 10)
-#define ESAI_TCR_TSWS_STL20_WDL8 (0x0c << 10)
-#define ESAI_TCR_TSWS_STL20_WDL12 (0x09 << 10)
-#define ESAI_TCR_TSWS_STL20_WDL16 (0x06 << 10)
-#define ESAI_TCR_TSWS_STL20_WDL20 (0x03 << 10)
-#define ESAI_TCR_TSWS_STL24_WDL8 (0x10 << 10)
-#define ESAI_TCR_TSWS_STL24_WDL12 (0x0d << 10)
-#define ESAI_TCR_TSWS_STL24_WDL16 (0x0a << 10)
-#define ESAI_TCR_TSWS_STL24_WDL20 (0x07 << 10)
-#define ESAI_TCR_TSWS_STL24_WDL24 (0x1e << 10)
-#define ESAI_TCR_TSWS_STL32_WDL8 (0x18 << 10)
-#define ESAI_TCR_TSWS_STL32_WDL12 (0x15 << 10)
-#define ESAI_TCR_TSWS_STL32_WDL16 (0x12 << 10)
-#define ESAI_TCR_TSWS_STL32_WDL20 (0x0f << 10)
-#define ESAI_TCR_TSWS_STL32_WDL24 (0x1f << 10)
-
-#define ESAI_TCR_TMOD_MASK 0xfffcff
-#define ESAI_TCR_TMOD_NORMAL (0x00 << 8)
-#define ESAI_TCR_TMOD_ONDEMAND (0x01 << 8)
-#define ESAI_TCR_TMOD_NETWORK (0x01 << 8)
-#define ESAI_TCR_TMOD_RESERVED (0x02 << 8)
-#define ESAI_TCR_TMOD_AC97 (0x03 << 8)
-
-#define ESAI_TCCR_THCKD (1 << 23)
-#define ESAI_TCCR_TFSD (1 << 22)
-#define ESAI_TCCR_TCKD (1 << 21)
-#define ESAI_TCCR_THCKP (1 << 20)
-#define ESAI_TCCR_TFSP (1 << 19)
-#define ESAI_TCCR_TCKP (1 << 18)
-
-#define ESAI_TCCR_TPSR_MASK 0xfffeff
-#define ESAI_TCCR_TPSR_BYPASS (1 << 8)
-#define ESAI_TCCR_TPSR_DIV8 (0 << 8)
-
-#define ESAI_TCCR_TFP_MASK 0xfc3fff
-#define ESAI_TCCR_TFP(x) ((x & 0xf) << 14)
-
-#define ESAI_TCCR_TDC_MASK 0xffc1ff
-#define ESAI_TCCR_TDC(x) (((x) & 0x1f) << 9)
-
-#define ESAI_TCCR_TPM_MASK 0xffff00
-#define ESAI_TCCR_TPM(x) (x & 0xff)
-
-#define ESAI_RCR_RLIE (1 << 23)
-#define ESAI_RCR_RIE (1 << 22)
-#define ESAI_RCR_REDIE (1 << 21)
-#define ESAI_RCR_REIE (1 << 20)
-#define ESAI_RCR_RPR (1 << 19)
-#define ESAI_RCR_RFSR (1 << 16)
-#define ESAI_RCR_RFSL (1 << 15)
-#define ESAI_RCR_RWA (1 << 7)
-#define ESAI_RCR_RSHFD_MSB (0 << 6)
-#define ESAI_RCR_RSHFD_LSB (1 << 6)
-#define ESAI_RCR_RE3 (1 << 3)
-#define ESAI_RCR_RE2 (1 << 2)
-#define ESAI_RCR_RE1 (1 << 1)
-#define ESAI_RCR_RE0 (1 << 0)
-#define ESAI_RCR_RE(x) ((0xf >> (4 - ((x + 1) >> 1))) << 1)
-
-#define ESAI_RCR_RSWS_MASK 0xff83ff
-#define ESAI_RCR_RSWS_STL8_WDL8 (0x00 << 10)
-#define ESAI_RCR_RSWS_STL12_WDL8 (0x04 << 10)
-#define ESAI_RCR_RSWS_STL12_WDL12 (0x01 << 10)
-#define ESAI_RCR_RSWS_STL16_WDL8 (0x08 << 10)
-#define ESAI_RCR_RSWS_STL16_WDL12 (0x05 << 10)
-#define ESAI_RCR_RSWS_STL16_WDL16 (0x02 << 10)
-#define ESAI_RCR_RSWS_STL20_WDL8 (0x0c << 10)
-#define ESAI_RCR_RSWS_STL20_WDL12 (0x09 << 10)
-#define ESAI_RCR_RSWS_STL20_WDL16 (0x06 << 10)
-#define ESAI_RCR_RSWS_STL20_WDL20 (0x03 << 10)
-#define ESAI_RCR_RSWS_STL24_WDL8 (0x10 << 10)
-#define ESAI_RCR_RSWS_STL24_WDL12 (0x0d << 10)
-#define ESAI_RCR_RSWS_STL24_WDL16 (0x0a << 10)
-#define ESAI_RCR_RSWS_STL24_WDL20 (0x07 << 10)
-#define ESAI_RCR_RSWS_STL24_WDL24 (0x1e << 10)
-#define ESAI_RCR_RSWS_STL32_WDL8 (0x18 << 10)
-#define ESAI_RCR_RSWS_STL32_WDL12 (0x15 << 10)
-#define ESAI_RCR_RSWS_STL32_WDL16 (0x12 << 10)
-#define ESAI_RCR_RSWS_STL32_WDL20 (0x0f << 10)
-#define ESAI_RCR_RSWS_STL32_WDL24 (0x1f << 10)
-
-#define ESAI_RCR_RMOD_MASK 0xfffcff
-#define ESAI_RCR_RMOD_NORMAL (0x00 << 8)
-#define ESAI_RCR_RMOD_ONDEMAND (0x01 << 8)
-#define ESAI_RCR_RMOD_NETWORK (0x01 << 8)
-#define ESAI_RCR_RMOD_RESERVED (0x02 << 8)
-#define ESAI_RCR_RMOD_AC97 (0x03 << 8)
-
-#define ESAI_RCCR_RHCKD (1 << 23)
-#define ESAI_RCCR_RFSD (1 << 22)
-#define ESAI_RCCR_RCKD (1 << 21)
-#define ESAI_RCCR_RHCKP (1 << 20)
-#define ESAI_RCCR_RFSP (1 << 19)
-#define ESAI_RCCR_RCKP (1 << 18)
-
-#define ESAI_RCCR_RPSR_MASK 0xfffeff
-#define ESAI_RCCR_RPSR_BYPASS (1 << 8)
-#define ESAI_RCCR_RPSR_DIV8 (0 << 8)
-
-#define ESAI_RCCR_RFP_MASK 0xfc3fff
-#define ESAI_RCCR_RFP(x) ((x & 0xf) << 14)
-
-#define ESAI_RCCR_RDC_MASK 0xffc1ff
-#define ESAI_RCCR_RDC(x) (((x) & 0x1f) << 9)
-
-#define ESAI_RCCR_RPM_MASK 0xffff00
-#define ESAI_RCCR_RPM(x) (x & 0xff)
-
-#define ESAI_GPIO_ESAI 0xfff
-
-/* ESAI clock source */
-#define ESAI_CLK_FSYS 0
-#define ESAI_CLK_EXTAL 1
-
-/* ESAI clock divider */
-#define ESAI_TX_DIV_PSR 0
-#define ESAI_TX_DIV_PM 1
-#define ESAI_TX_DIV_FP 2
-#define ESAI_RX_DIV_PSR 3
-#define ESAI_RX_DIV_PM 4
-#define ESAI_RX_DIV_FP 5
-
static int imx_esai_txrx_state;
static struct imx_esai imx_esai_priv[3];
+static void __iomem *esai_ioaddr;
static int imx_esai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
int clk_id, unsigned int freq, int dir)
@@ -341,10 +58,8 @@ static int imx_esai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
~(ESAI_RCCR_RHCKD | ESAI_RCCR_RCKD |
ESAI_RCCR_RFSD);
} else {
- if (cpu_dai->id & IMX_DAI_ESAI_TX)
tccr |=
ESAI_TCCR_THCKD | ESAI_TCCR_TCKD | ESAI_TCCR_TFSD;
- if (cpu_dai->id & IMX_DAI_ESAI_RX)
rccr |=
ESAI_RCCR_RHCKD | ESAI_RCCR_RCKD | ESAI_RCCR_RFSD;
if (clk_id == ESAI_CLK_FSYS) {
@@ -353,14 +68,10 @@ static int imx_esai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
if (cpu_dai->id & IMX_DAI_ESAI_RX)
ecr &= ~(ESAI_ECR_ERI | ESAI_ECR_ERO);
} else if (clk_id == ESAI_CLK_EXTAL) {
- if (cpu_dai->id & IMX_DAI_ESAI_TX) {
ecr |= ESAI_ECR_ETI;
ecr &= ~ESAI_ECR_ETO;
- }
- if (cpu_dai->id & IMX_DAI_ESAI_RX) {
ecr |= ESAI_ECR_ERI;
ecr &= ~ESAI_ECR_ERO;
- }
}
}
@@ -386,7 +97,10 @@ static int imx_esai_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
switch (div_id) {
case ESAI_TX_DIV_PSR:
tccr &= ESAI_TCCR_TPSR_MASK;
- tccr |= div;
+ if (div)
+ tccr |= ESAI_TCCR_TPSR_BYPASS;
+ else
+ tccr &= ~ESAI_TCCR_TPSR_DIV8;
break;
case ESAI_TX_DIV_PM:
tccr &= ESAI_TCCR_TPM_MASK;
@@ -398,7 +112,10 @@ static int imx_esai_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
break;
case ESAI_RX_DIV_PSR:
rccr &= ESAI_RCCR_RPSR_MASK;
- rccr |= div;
+ if (div)
+ rccr |= ESAI_RCCR_RPSR_BYPASS;
+ else
+ rccr &= ~ESAI_RCCR_RPSR_DIV8;
break;
case ESAI_RX_DIV_PM:
rccr &= ESAI_RCCR_RPM_MASK;
@@ -691,7 +408,7 @@ static int imx_esai_hw_rx_params(struct snd_pcm_substream *substream,
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
rfcr |= ESAI_WORD_LEN_16;
- rcr |= ESAI_RCR_RSHFD_MSB | ESAI_RCR_RSWS_STL16_WDL16;
+ rcr |= ESAI_RCR_RSHFD_MSB | ESAI_RCR_RSWS_STL32_WDL16;
break;
}
@@ -729,6 +446,7 @@ static int imx_esai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
u32 reg, tfcr = 0, rfcr = 0;
+ u32 temp;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
tfcr = __raw_readl(ESAI_TFCR);
@@ -748,6 +466,9 @@ static int imx_esai_trigger(struct snd_pcm_substream *substream, int cmd,
reg |= ESAI_TCR_TE(substream->runtime->channels);
__raw_writel(reg, ESAI_TCR);
} else {
+ temp = __raw_readl(ESAI_TCR);
+ temp &= ~ESAI_TCR_TPR;
+ __raw_writel(temp, ESAI_TCR);
rfcr |= ESAI_RFCR_RFEN;
__raw_writel(rfcr, ESAI_RFCR);
reg &= ~ESAI_RCR_RPR;
@@ -783,7 +504,6 @@ static int imx_esai_trigger(struct snd_pcm_substream *substream, int cmd,
default:
return -EINVAL;
}
-
ESAI_DUMP();
return 0;
}
@@ -932,14 +652,53 @@ struct snd_soc_dai imx_esai_dai[] = {
EXPORT_SYMBOL_GPL(imx_esai_dai);
+static int imx_esai_dev_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct mxc_esai_platform_data *plat_data = pdev->dev.platform_data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ esai_ioaddr = ioremap(res->start, res->end - res->start + 1);
+
+ if (plat_data->activate_esai_ports)
+ plat_data->activate_esai_ports();
+
+ snd_soc_register_dais(imx_esai_dai, ARRAY_SIZE(imx_esai_dai));
+ return 0;
+}
+
+static int __devexit imx_esai_dev_remove(struct platform_device *pdev)
+{
+
+ struct mxc_esai_platform_data *plat_data = pdev->dev.platform_data;
+ iounmap(esai_ioaddr);
+ if (plat_data->deactivate_esai_ports)
+ plat_data->deactivate_esai_ports();
+
+ snd_soc_unregister_dais(imx_esai_dai, ARRAY_SIZE(imx_esai_dai));
+ return 0;
+}
+
+
+static struct platform_driver imx_esai_driver = {
+ .probe = imx_esai_dev_probe,
+ .remove = __devexit_p(imx_esai_dev_remove),
+ .driver = {
+ .name = "mxc_esai",
+ },
+};
+
static int __init imx_esai_init(void)
{
- return snd_soc_register_dais(imx_esai_dai, ARRAY_SIZE(imx_esai_dai));
+ return platform_driver_register(&imx_esai_driver);
}
static void __exit imx_esai_exit(void)
{
- snd_soc_unregister_dais(imx_esai_dai, ARRAY_SIZE(imx_esai_dai));
+ platform_driver_unregister(&imx_esai_driver);
}
module_init(imx_esai_init);
diff --git a/sound/soc/imx/imx-esai.h b/sound/soc/imx/imx-esai.h
index 58ad601c119f..6e2cce0eff4a 100644
--- a/sound/soc/imx/imx-esai.h
+++ b/sound/soc/imx/imx-esai.h
@@ -1,7 +1,7 @@
/*
* imx-esai.h -- ESAI driver header file for Freescale IMX
*
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -16,6 +16,290 @@
#ifndef _MXC_ESAI_H
#define _MXC_ESAI_H
+/*#define IMX_ESAI_DUMP 1*/
+
+#ifdef IMX_ESAI_DUMP
+#define ESAI_DUMP() \
+ do {pr_info("dump @ %s\n", __func__); \
+ pr_info("ecr %x\n", __raw_readl(ESAI_ECR)); \
+ pr_info("esr %x\n", __raw_readl(ESAI_ESR)); \
+ pr_info("tfcr %x\n", __raw_readl(ESAI_TFCR)); \
+ pr_info("tfsr %x\n", __raw_readl(ESAI_TFSR)); \
+ pr_info("rfcr %x\n", __raw_readl(ESAI_RFCR)); \
+ pr_info("rfsr %x\n", __raw_readl(ESAI_RFSR)); \
+ pr_info("tsr %x\n", __raw_readl(ESAI_TSR)); \
+ pr_info("saisr %x\n", __raw_readl(ESAI_SAISR)); \
+ pr_info("saicr %x\n", __raw_readl(ESAI_SAICR)); \
+ pr_info("tcr %x\n", __raw_readl(ESAI_TCR)); \
+ pr_info("tccr %x\n", __raw_readl(ESAI_TCCR)); \
+ pr_info("rcr %x\n", __raw_readl(ESAI_RCR)); \
+ pr_info("rccr %x\n", __raw_readl(ESAI_RCCR)); \
+ pr_info("tsma %x\n", __raw_readl(ESAI_TSMA)); \
+ pr_info("tsmb %x\n", __raw_readl(ESAI_TSMB)); \
+ pr_info("rsma %x\n", __raw_readl(ESAI_RSMA)); \
+ pr_info("rsmb %x\n", __raw_readl(ESAI_RSMB)); \
+ pr_info("prrc %x\n", __raw_readl(ESAI_PRRC)); \
+ pr_info("pcrc %x\n", __raw_readl(ESAI_PCRC)); } while (0);
+#else
+#define ESAI_DUMP()
+#endif
+
+#define ESAI_IO_BASE_ADDR (esai_ioaddr)
+
+#define ESAI_ETDR (ESAI_IO_BASE_ADDR + 0x00)
+#define ESAI_ERDR (ESAI_IO_BASE_ADDR + 0x04)
+#define ESAI_ECR (ESAI_IO_BASE_ADDR + 0x08)
+#define ESAI_ESR (ESAI_IO_BASE_ADDR + 0x0C)
+#define ESAI_TFCR (ESAI_IO_BASE_ADDR + 0x10)
+#define ESAI_TFSR (ESAI_IO_BASE_ADDR + 0x14)
+#define ESAI_RFCR (ESAI_IO_BASE_ADDR + 0x18)
+#define ESAI_RFSR (ESAI_IO_BASE_ADDR + 0x1C)
+#define ESAI_TX0 (ESAI_IO_BASE_ADDR + 0x80)
+#define ESAI_TX1 (ESAI_IO_BASE_ADDR + 0x84)
+#define ESAI_TX2 (ESAI_IO_BASE_ADDR + 0x88)
+#define ESAI_TX3 (ESAI_IO_BASE_ADDR + 0x8C)
+#define ESAI_TX4 (ESAI_IO_BASE_ADDR + 0x90)
+#define ESAI_TX5 (ESAI_IO_BASE_ADDR + 0x94)
+#define ESAI_TSR (ESAI_IO_BASE_ADDR + 0x98)
+#define ESAI_RX0 (ESAI_IO_BASE_ADDR + 0xA0)
+#define ESAI_RX1 (ESAI_IO_BASE_ADDR + 0xA4)
+#define ESAI_RX2 (ESAI_IO_BASE_ADDR + 0xA8)
+#define ESAI_RX3 (ESAI_IO_BASE_ADDR + 0xAC)
+#define ESAI_SAISR (ESAI_IO_BASE_ADDR + 0xCC)
+#define ESAI_SAICR (ESAI_IO_BASE_ADDR + 0xD0)
+#define ESAI_TCR (ESAI_IO_BASE_ADDR + 0xD4)
+#define ESAI_TCCR (ESAI_IO_BASE_ADDR + 0xD8)
+#define ESAI_RCR (ESAI_IO_BASE_ADDR + 0xDC)
+#define ESAI_RCCR (ESAI_IO_BASE_ADDR + 0xE0)
+#define ESAI_TSMA (ESAI_IO_BASE_ADDR + 0xE4)
+#define ESAI_TSMB (ESAI_IO_BASE_ADDR + 0xE8)
+#define ESAI_RSMA (ESAI_IO_BASE_ADDR + 0xEC)
+#define ESAI_RSMB (ESAI_IO_BASE_ADDR + 0xF0)
+#define ESAI_PRRC (ESAI_IO_BASE_ADDR + 0xF8)
+#define ESAI_PCRC (ESAI_IO_BASE_ADDR + 0xFC)
+
+#define ESAI_ECR_ETI (1 << 19)
+#define ESAI_ECR_ETO (1 << 18)
+#define ESAI_ECR_ERI (1 << 17)
+#define ESAI_ECR_ERO (1 << 16)
+#define ESAI_ECR_ERST (1 << 1)
+#define ESAI_ECR_ESAIEN (1 << 0)
+
+#define ESAI_ESR_TINIT (1 << 10)
+#define ESAI_ESR_RFF (1 << 9)
+#define ESAI_ESR_TFE (1 << 8)
+#define ESAI_ESR_TLS (1 << 7)
+#define ESAI_ESR_TDE (1 << 6)
+#define ESAI_ESR_TED (1 << 5)
+#define ESAI_ESR_TD (1 << 4)
+#define ESAI_ESR_RLS (1 << 3)
+#define ESAI_ESR_RDE (1 << 2)
+#define ESAI_ESR_RED (1 << 1)
+#define ESAI_ESR_RD (1 << 0)
+
+#define ESAI_TFCR_TIEN (1 << 19)
+#define ESAI_TFCR_TE5 (1 << 7)
+#define ESAI_TFCR_TE4 (1 << 6)
+#define ESAI_TFCR_TE3 (1 << 5)
+#define ESAI_TFCR_TE2 (1 << 4)
+#define ESAI_TFCR_TE1 (1 << 3)
+#define ESAI_TFCR_TE0 (1 << 2)
+#define ESAI_TFCR_TFR (1 << 1)
+#define ESAI_TFCR_TFEN (1 << 0)
+#define ESAI_TFCR_TE(x) ((0x3f >> (6 - ((x + 1) >> 1))) << 2)
+#define ESAI_TFCR_TE_MASK 0xfff03
+#define ESAI_TFCR_TFWM(x) ((x - 1) << 8)
+#define ESAI_TFCR_TWA_MASK 0xf8ffff
+
+#define ESAI_RFCR_REXT (1 << 19)
+#define ESAI_RFCR_RE3 (1 << 5)
+#define ESAI_RFCR_RE2 (1 << 4)
+#define ESAI_RFCR_RE1 (1 << 3)
+#define ESAI_RFCR_RE0 (1 << 2)
+#define ESAI_RFCR_RFR (1 << 1)
+#define ESAI_RFCR_RFEN (1 << 0)
+#define ESAI_RFCR_RE(x) ((0xf >> (4 - ((x + 1) >> 1))) << 2)
+#define ESAI_RFCR_RE_MASK 0xfffc3
+#define ESAI_RFCR_RFWM(x) ((x-1) << 8)
+#define ESAI_RFCR_RWA_MASK 0xf8ffff
+
+#define ESAI_WORD_LEN_32 (0x00 << 16)
+#define ESAI_WORD_LEN_28 (0x01 << 16)
+#define ESAI_WORD_LEN_24 (0x02 << 16)
+#define ESAI_WORD_LEN_20 (0x03 << 16)
+#define ESAI_WORD_LEN_16 (0x04 << 16)
+#define ESAI_WORD_LEN_12 (0x05 << 16)
+#define ESAI_WORD_LEN_8 (0x06 << 16)
+#define ESAI_WORD_LEN_4 (0x07 << 16)
+
+#define ESAI_SAISR_TODFE (1 << 17)
+#define ESAI_SAISR_TEDE (1 << 16)
+#define ESAI_SAISR_TDE (1 << 15)
+#define ESAI_SAISR_TUE (1 << 14)
+#define ESAI_SAISR_TFS (1 << 13)
+#define ESAI_SAISR_RODF (1 << 10)
+#define ESAI_SAISR_REDF (1 << 9)
+#define ESAI_SAISR_RDF (1 << 8)
+#define ESAI_SAISR_ROE (1 << 7)
+#define ESAI_SAISR_RFS (1 << 6)
+#define ESAI_SAISR_IF2 (1 << 2)
+#define ESAI_SAISR_IF1 (1 << 1)
+#define ESAI_SAISR_IF0 (1 << 0)
+
+#define ESAI_SAICR_ALC (1 << 8)
+#define ESAI_SAICR_TEBE (1 << 7)
+#define ESAI_SAICR_SYNC (1 << 6)
+#define ESAI_SAICR_OF2 (1 << 2)
+#define ESAI_SAICR_OF1 (1 << 1)
+#define ESAI_SAICR_OF0 (1 << 0)
+
+#define ESAI_TCR_TLIE (1 << 23)
+#define ESAI_TCR_TIE (1 << 22)
+#define ESAI_TCR_TEDIE (1 << 21)
+#define ESAI_TCR_TEIE (1 << 20)
+#define ESAI_TCR_TPR (1 << 19)
+#define ESAI_TCR_PADC (1 << 17)
+#define ESAI_TCR_TFSR (1 << 16)
+#define ESAI_TCR_TFSL (1 << 15)
+#define ESAI_TCR_TWA (1 << 7)
+#define ESAI_TCR_TSHFD_MSB (0 << 6)
+#define ESAI_TCR_TSHFD_LSB (1 << 6)
+#define ESAI_TCR_TE5 (1 << 5)
+#define ESAI_TCR_TE4 (1 << 4)
+#define ESAI_TCR_TE3 (1 << 3)
+#define ESAI_TCR_TE2 (1 << 2)
+#define ESAI_TCR_TE1 (1 << 1)
+#define ESAI_TCR_TE0 (1 << 0)
+#define ESAI_TCR_TE(x) (0x3f >> (6 - ((x + 1) >> 1)))
+
+#define ESAI_TCR_TSWS_MASK 0xff83ff
+#define ESAI_TCR_TSWS_STL8_WDL8 (0x00 << 10)
+#define ESAI_TCR_TSWS_STL12_WDL8 (0x04 << 10)
+#define ESAI_TCR_TSWS_STL12_WDL12 (0x01 << 10)
+#define ESAI_TCR_TSWS_STL16_WDL8 (0x08 << 10)
+#define ESAI_TCR_TSWS_STL16_WDL12 (0x05 << 10)
+#define ESAI_TCR_TSWS_STL16_WDL16 (0x02 << 10)
+#define ESAI_TCR_TSWS_STL20_WDL8 (0x0c << 10)
+#define ESAI_TCR_TSWS_STL20_WDL12 (0x09 << 10)
+#define ESAI_TCR_TSWS_STL20_WDL16 (0x06 << 10)
+#define ESAI_TCR_TSWS_STL20_WDL20 (0x03 << 10)
+#define ESAI_TCR_TSWS_STL24_WDL8 (0x10 << 10)
+#define ESAI_TCR_TSWS_STL24_WDL12 (0x0d << 10)
+#define ESAI_TCR_TSWS_STL24_WDL16 (0x0a << 10)
+#define ESAI_TCR_TSWS_STL24_WDL20 (0x07 << 10)
+#define ESAI_TCR_TSWS_STL24_WDL24 (0x1e << 10)
+#define ESAI_TCR_TSWS_STL32_WDL8 (0x18 << 10)
+#define ESAI_TCR_TSWS_STL32_WDL12 (0x15 << 10)
+#define ESAI_TCR_TSWS_STL32_WDL16 (0x12 << 10)
+#define ESAI_TCR_TSWS_STL32_WDL20 (0x0f << 10)
+#define ESAI_TCR_TSWS_STL32_WDL24 (0x1f << 10)
+
+#define ESAI_TCR_TMOD_MASK 0xfffcff
+#define ESAI_TCR_TMOD_NORMAL (0x00 << 8)
+#define ESAI_TCR_TMOD_ONDEMAND (0x01 << 8)
+#define ESAI_TCR_TMOD_NETWORK (0x01 << 8)
+#define ESAI_TCR_TMOD_RESERVED (0x02 << 8)
+#define ESAI_TCR_TMOD_AC97 (0x03 << 8)
+
+#define ESAI_TCCR_THCKD (1 << 23)
+#define ESAI_TCCR_TFSD (1 << 22)
+#define ESAI_TCCR_TCKD (1 << 21)
+#define ESAI_TCCR_THCKP (1 << 20)
+#define ESAI_TCCR_TFSP (1 << 19)
+#define ESAI_TCCR_TCKP (1 << 18)
+
+#define ESAI_TCCR_TPSR_MASK 0xfffeff
+#define ESAI_TCCR_TPSR_BYPASS (1 << 8)
+#define ESAI_TCCR_TPSR_DIV8 (0 << 8)
+
+#define ESAI_TCCR_TFP_MASK 0xfc3fff
+#define ESAI_TCCR_TFP(x) ((x & 0xf) << 14)
+
+#define ESAI_TCCR_TDC_MASK 0xffc1ff
+#define ESAI_TCCR_TDC(x) (((x) & 0x1f) << 9)
+
+#define ESAI_TCCR_TPM_MASK 0xffff00
+#define ESAI_TCCR_TPM(x) (x & 0xff)
+
+#define ESAI_RCR_RLIE (1 << 23)
+#define ESAI_RCR_RIE (1 << 22)
+#define ESAI_RCR_REDIE (1 << 21)
+#define ESAI_RCR_REIE (1 << 20)
+#define ESAI_RCR_RPR (1 << 19)
+#define ESAI_RCR_RFSR (1 << 16)
+#define ESAI_RCR_RFSL (1 << 15)
+#define ESAI_RCR_RWA (1 << 7)
+#define ESAI_RCR_RSHFD_MSB (0 << 6)
+#define ESAI_RCR_RSHFD_LSB (1 << 6)
+#define ESAI_RCR_RE3 (1 << 3)
+#define ESAI_RCR_RE2 (1 << 2)
+#define ESAI_RCR_RE1 (1 << 1)
+#define ESAI_RCR_RE0 (1 << 0)
+#define ESAI_RCR_RE(x) (0xf >> (4 - ((x + 1) >> 1)))
+
+#define ESAI_RCR_RSWS_MASK 0xff83ff
+#define ESAI_RCR_RSWS_STL8_WDL8 (0x00 << 10)
+#define ESAI_RCR_RSWS_STL12_WDL8 (0x04 << 10)
+#define ESAI_RCR_RSWS_STL12_WDL12 (0x01 << 10)
+#define ESAI_RCR_RSWS_STL16_WDL8 (0x08 << 10)
+#define ESAI_RCR_RSWS_STL16_WDL12 (0x05 << 10)
+#define ESAI_RCR_RSWS_STL16_WDL16 (0x02 << 10)
+#define ESAI_RCR_RSWS_STL20_WDL8 (0x0c << 10)
+#define ESAI_RCR_RSWS_STL20_WDL12 (0x09 << 10)
+#define ESAI_RCR_RSWS_STL20_WDL16 (0x06 << 10)
+#define ESAI_RCR_RSWS_STL20_WDL20 (0x03 << 10)
+#define ESAI_RCR_RSWS_STL24_WDL8 (0x10 << 10)
+#define ESAI_RCR_RSWS_STL24_WDL12 (0x0d << 10)
+#define ESAI_RCR_RSWS_STL24_WDL16 (0x0a << 10)
+#define ESAI_RCR_RSWS_STL24_WDL20 (0x07 << 10)
+#define ESAI_RCR_RSWS_STL24_WDL24 (0x1e << 10)
+#define ESAI_RCR_RSWS_STL32_WDL8 (0x18 << 10)
+#define ESAI_RCR_RSWS_STL32_WDL12 (0x15 << 10)
+#define ESAI_RCR_RSWS_STL32_WDL16 (0x12 << 10)
+#define ESAI_RCR_RSWS_STL32_WDL20 (0x0f << 10)
+#define ESAI_RCR_RSWS_STL32_WDL24 (0x1f << 10)
+
+#define ESAI_RCR_RMOD_MASK 0xfffcff
+#define ESAI_RCR_RMOD_NORMAL (0x00 << 8)
+#define ESAI_RCR_RMOD_ONDEMAND (0x01 << 8)
+#define ESAI_RCR_RMOD_NETWORK (0x01 << 8)
+#define ESAI_RCR_RMOD_RESERVED (0x02 << 8)
+#define ESAI_RCR_RMOD_AC97 (0x03 << 8)
+
+#define ESAI_RCCR_RHCKD (1 << 23)
+#define ESAI_RCCR_RFSD (1 << 22)
+#define ESAI_RCCR_RCKD (1 << 21)
+#define ESAI_RCCR_RHCKP (1 << 20)
+#define ESAI_RCCR_RFSP (1 << 19)
+#define ESAI_RCCR_RCKP (1 << 18)
+
+#define ESAI_RCCR_RPSR_MASK 0xfffeff
+#define ESAI_RCCR_RPSR_BYPASS (1 << 8)
+#define ESAI_RCCR_RPSR_DIV8 (0 << 8)
+
+#define ESAI_RCCR_RFP_MASK 0xfc3fff
+#define ESAI_RCCR_RFP(x) ((x & 0xf) << 14)
+
+#define ESAI_RCCR_RDC_MASK 0xffc1ff
+#define ESAI_RCCR_RDC(x) (((x) & 0x1f) << 9)
+
+#define ESAI_RCCR_RPM_MASK 0xffff00
+#define ESAI_RCCR_RPM(x) (x & 0xff)
+
+#define ESAI_GPIO_ESAI 0xfff
+
+/* ESAI clock source */
+#define ESAI_CLK_FSYS 0
+#define ESAI_CLK_EXTAL 1
+
+/* ESAI clock divider */
+#define ESAI_TX_DIV_PSR 0
+#define ESAI_TX_DIV_PM 1
+#define ESAI_TX_DIV_FP 2
+#define ESAI_RX_DIV_PSR 3
+#define ESAI_RX_DIV_PM 4
+#define ESAI_RX_DIV_FP 5
+
#define IMX_DAI_ESAI_TX 0x04
#define IMX_DAI_ESAI_RX 0x08
#define IMX_DAI_ESAI_TXRX (IMX_DAI_ESAI_TX | IMX_DAI_ESAI_RX)
diff --git a/sound/soc/imx/imx-pcm.c b/sound/soc/imx/imx-pcm.c
index 2487d9284ac3..3e8a90da35c2 100644
--- a/sound/soc/imx/imx-pcm.c
+++ b/sound/soc/imx/imx-pcm.c
@@ -579,6 +579,14 @@ static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
else {
buf->area = iram_alloc(size, &buf_paddr);
buf->addr = buf_paddr;
+
+ if (!buf->area) {
+ pr_warning("imx-pcm: Falling back to external ram.\n");
+ UseIram = 0;
+ buf->area =
+ dma_alloc_writecombine(pcm->card->dev, size,
+ &buf->addr, GFP_KERNEL);
+ }
}
if (!buf->area)
diff --git a/sound/soc/mxs/mxs-adc.c b/sound/soc/mxs/mxs-adc.c
index e8bb4255fff5..7069927b1ac3 100644
--- a/sound/soc/mxs/mxs-adc.c
+++ b/sound/soc/mxs/mxs-adc.c
@@ -37,6 +37,7 @@
#define MXS_ADC_RATES SNDRV_PCM_RATE_8000_192000
#define MXS_ADC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
+#define ADC_VOLUME_MIN 0x37
struct mxs_pcm_dma_params mxs_audio_in = {
.name = "mxs-audio-in",
@@ -50,6 +51,166 @@ struct mxs_pcm_dma_params mxs_audio_out = {
.irq = IRQ_DAC_DMA,
};
+static struct delayed_work work;
+static struct delayed_work adc_ramp_work;
+static struct delayed_work dac_ramp_work;
+static bool adc_ramp_done = 1;
+static bool dac_ramp_done = 1;
+
+static void mxs_adc_schedule_work(struct delayed_work *work)
+{
+ schedule_delayed_work(work, HZ / 10);
+}
+static void mxs_adc_work(struct work_struct *work)
+{
+ /* disable irq */
+ disable_irq(IRQ_HEADPHONE_SHORT);
+
+ while (true) {
+ __raw_writel(BM_AUDIOOUT_PWRDN_HEADPHONE,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_CLR);
+ msleep(10);
+ if ((__raw_readl(REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL)
+ & BM_AUDIOOUT_ANACTRL_SHORT_LR_STS) != 0) {
+ /* rearm the short protection */
+ __raw_writel(BM_AUDIOOUT_ANACTRL_SHORTMODE_LR,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
+ __raw_writel(BM_AUDIOOUT_ANACTRL_SHORT_LR_STS,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
+ __raw_writel(BF_AUDIOOUT_ANACTRL_SHORTMODE_LR(0x1),
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET);
+
+ __raw_writel(BM_AUDIOOUT_PWRDN_HEADPHONE,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_SET);
+ printk(KERN_WARNING "WARNING : Headphone LR short!\r\n");
+ } else {
+ printk(KERN_WARNING "INFO : Headphone LR no longer short!\r\n");
+ break;
+ }
+ msleep(1000);
+ }
+
+ /* power up the HEADPHONE and un-mute the HPVOL */
+ __raw_writel(BM_AUDIOOUT_HPVOL_MUTE,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_CLR);
+ __raw_writel(BM_AUDIOOUT_PWRDN_HEADPHONE,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_CLR);
+
+ /* enable irq for next short detect*/
+ enable_irq(IRQ_HEADPHONE_SHORT);
+}
+
+static void mxs_adc_schedule_ramp_work(struct delayed_work *work)
+{
+ schedule_delayed_work(work, msecs_to_jiffies(2));
+ adc_ramp_done = 0;
+}
+
+static void mxs_adc_ramp_work(struct work_struct *work)
+{
+ u32 reg = 0;
+ u32 reg1 = 0;
+ u32 reg2 = 0;
+ u32 l, r;
+ u32 ll, rr;
+ int i;
+
+ reg = __raw_readl(REGS_AUDIOIN_BASE + \
+ HW_AUDIOIN_ADCVOLUME);
+
+ reg1 = reg & ~BM_AUDIOIN_ADCVOLUME_VOLUME_LEFT;
+ reg1 = reg1 & ~BM_AUDIOIN_ADCVOLUME_VOLUME_RIGHT;
+ /* minimize adc volume */
+ reg2 = reg1 |
+ BF_AUDIOIN_ADCVOLUME_VOLUME_LEFT(ADC_VOLUME_MIN) |
+ BF_AUDIOIN_ADCVOLUME_VOLUME_RIGHT(ADC_VOLUME_MIN);
+ __raw_writel(reg2,
+ REGS_AUDIOIN_BASE + HW_AUDIOIN_ADCVOLUME);
+ msleep(1);
+
+ l = (reg & BM_AUDIOIN_ADCVOLUME_VOLUME_LEFT) >>
+ BP_AUDIOIN_ADCVOLUME_VOLUME_LEFT;
+ r = (reg & BM_AUDIOIN_ADCVOLUME_VOLUME_RIGHT) >>
+ BP_AUDIOIN_ADCVOLUME_VOLUME_RIGHT;
+
+ /* fade in adc vol */
+ for (i = ADC_VOLUME_MIN; (i < l) || (i < r);) {
+ i += 0x8;
+ ll = i < l ? i : l;
+ rr = i < r ? i : r;
+ reg2 = reg1 |
+ BF_AUDIOIN_ADCVOLUME_VOLUME_LEFT(ll) |
+ BF_AUDIOIN_ADCVOLUME_VOLUME_RIGHT(rr);
+ __raw_writel(reg2,
+ REGS_AUDIOIN_BASE + HW_AUDIOIN_ADCVOLUME);
+ msleep(1);
+ }
+ adc_ramp_done = 1;
+}
+
+static void mxs_dac_schedule_ramp_work(struct delayed_work *work)
+{
+ schedule_delayed_work(work, msecs_to_jiffies(2));
+ dac_ramp_done = 0;
+}
+
+static void mxs_dac_ramp_work(struct work_struct *work)
+{
+ u32 reg = 0;
+ u32 reg1 = 0;
+ u32 l, r;
+ u32 ll, rr;
+ int i;
+
+ /* unmute hp and speaker */
+ __raw_writel(BM_AUDIOOUT_HPVOL_MUTE,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_CLR);
+ __raw_writel(BM_AUDIOOUT_SPEAKERCTRL_MUTE,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_SPEAKERCTRL_CLR);
+
+ reg = __raw_readl(REGS_AUDIOOUT_BASE + \
+ HW_AUDIOOUT_HPVOL);
+
+ reg1 = reg & ~BM_AUDIOOUT_HPVOL_VOL_LEFT;
+ reg1 = reg1 & ~BM_AUDIOOUT_HPVOL_VOL_RIGHT;
+
+ l = (reg & BM_AUDIOOUT_HPVOL_VOL_LEFT) >>
+ BP_AUDIOOUT_HPVOL_VOL_LEFT;
+ r = (reg & BM_AUDIOOUT_HPVOL_VOL_RIGHT) >>
+ BP_AUDIOOUT_HPVOL_VOL_RIGHT;
+ /* fade in hp vol */
+ for (i = 0x7f; i > 0 ;) {
+ i -= 0x8;
+ ll = i > (int)l ? i : l;
+ rr = i > (int)r ? i : r;
+ reg = reg1 | BF_AUDIOOUT_HPVOL_VOL_LEFT(ll)
+ | BF_AUDIOOUT_HPVOL_VOL_RIGHT(rr);
+ __raw_writel(reg,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL);
+ msleep(1);
+ }
+ dac_ramp_done = 1;
+}
+
+static irqreturn_t mxs_short_irq(int irq, void *dev_id)
+{
+ __raw_writel(BM_AUDIOOUT_ANACTRL_SHORTMODE_LR,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
+ __raw_writel(BM_AUDIOOUT_ANACTRL_SHORT_LR_STS,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
+ __raw_writel(BF_AUDIOOUT_ANACTRL_SHORTMODE_LR(0x1),
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET);
+
+ __raw_writel(BM_AUDIOOUT_HPVOL_MUTE,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_SET);
+ __raw_writel(BM_AUDIOOUT_PWRDN_HEADPHONE,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_PWRDN_SET);
+ __raw_writel(BM_AUDIOOUT_ANACTRL_HP_CLASSAB,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET);
+
+ mxs_adc_schedule_work(&work);
+ return IRQ_HANDLED;
+}
static irqreturn_t mxs_err_irq(int irq, void *dev_id)
{
struct snd_pcm_substream *substream = dev_id;
@@ -104,68 +265,47 @@ static int mxs_adc_trigger(struct snd_pcm_substream *substream,
{
int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0;
int ret = 0;
- u32 reg = 0;
- u32 reg1 = 0;
- u32 l, r;
- u32 ll, rr;
- int i;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
if (playback) {
- reg = __raw_readl(REGS_AUDIOOUT_BASE + \
- HW_AUDIOOUT_HPVOL);
- reg1 = BM_AUDIOOUT_HPVOL_VOL_LEFT | \
- BM_AUDIOOUT_HPVOL_VOL_RIGHT;
- __raw_writel(reg1, REGS_AUDIOOUT_BASE + \
- HW_AUDIOOUT_HPVOL);
-
- __raw_writel(BM_AUDIOOUT_CTRL_RUN,
+ /* enable the fifo error interrupt */
+ __raw_writel(BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_SET);
- __raw_writel(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_CLR);
-
- reg1 = reg & ~BM_AUDIOOUT_HPVOL_VOL_LEFT;
- reg1 = reg1 & ~BM_AUDIOOUT_HPVOL_VOL_RIGHT;
-
- l = (reg & BM_AUDIOOUT_HPVOL_VOL_LEFT) >>
- BP_AUDIOOUT_HPVOL_VOL_LEFT;
- r = (reg & BM_AUDIOOUT_HPVOL_VOL_RIGHT) >>
- BP_AUDIOOUT_HPVOL_VOL_RIGHT;
- for (i = 0x7f; i > 0 ; i -= 0x8) {
- ll = i > l ? i : l;
- rr = i > r ? i : r;
- /* fade in hp vol */
- reg = reg1 | BF_AUDIOOUT_HPVOL_VOL_LEFT(ll)
- | BF_AUDIOOUT_HPVOL_VOL_RIGHT(rr);
- __raw_writel(reg,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL);
- udelay(100);
- }
- __raw_writel(BM_AUDIOOUT_SPEAKERCTRL_MUTE,
- REGS_AUDIOIN_BASE + HW_AUDIOOUT_SPEAKERCTRL_CLR);
- }
- else
+ /* write a data to data reg to trigger the transfer */
+ __raw_writel(0x0,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_DATA);
+ mxs_dac_schedule_ramp_work(&dac_ramp_work);
+ } else {
__raw_writel(BM_AUDIOIN_CTRL_RUN,
REGS_AUDIOIN_BASE + HW_AUDIOIN_CTRL_SET);
-
+ mxs_adc_schedule_ramp_work(&adc_ramp_work);
+ }
break;
case SNDRV_PCM_TRIGGER_STOP:
if (playback) {
- __raw_writel(BM_AUDIOOUT_ANACTRL_HP_HOLD_GND,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_ANACTRL_SET);
+ if (dac_ramp_done == 0) {
+ cancel_delayed_work(&dac_ramp_work);
+ dac_ramp_done = 1;
+ }
+ __raw_writel(BM_AUDIOOUT_HPVOL_MUTE,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_HPVOL_SET);
__raw_writel(BM_AUDIOOUT_SPEAKERCTRL_MUTE,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_SPEAKERCTRL_SET);
-
- __raw_writel(BM_AUDIOOUT_CTRL_RUN,
+ REGS_AUDIOOUT_BASE + HW_AUDIOOUT_SPEAKERCTRL_SET);
+ /* disable the fifo error interrupt */
+ __raw_writel(BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_CLR);
- }
- else
+ } else {
+ if (adc_ramp_done == 0) {
+ cancel_delayed_work(&adc_ramp_work);
+ adc_ramp_done = 1;
+ }
__raw_writel(BM_AUDIOIN_CTRL_RUN,
REGS_AUDIOIN_BASE + HW_AUDIOIN_CTRL_CLR);
+ }
break;
case SNDRV_PCM_TRIGGER_RESUME:
@@ -187,8 +327,13 @@ static int mxs_adc_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0;
int irq;
+ int irq_short;
int ret;
+ INIT_DELAYED_WORK(&work, mxs_adc_work);
+ INIT_DELAYED_WORK(&adc_ramp_work, mxs_adc_ramp_work);
+ INIT_DELAYED_WORK(&dac_ramp_work, mxs_dac_ramp_work);
+
if (playback) {
irq = IRQ_DAC_ERROR;
cpu_dai->dma_data = &mxs_audio_out;
@@ -205,14 +350,21 @@ static int mxs_adc_startup(struct snd_pcm_substream *substream,
return ret;
}
+ irq_short = IRQ_HEADPHONE_SHORT;
+ ret = request_irq(irq_short, mxs_short_irq,
+ IRQF_DISABLED | IRQF_SHARED, "MXS DAC/ADC HP SHORT", substream);
+ if (ret) {
+ printk(KERN_ERR "%s: Unable to request ADC/DAC HP SHORT irq %d\n",
+ __func__, IRQ_DAC_ERROR);
+ return ret;
+ }
+
/* Enable error interrupt */
if (playback) {
__raw_writel(BM_AUDIOOUT_CTRL_FIFO_OVERFLOW_IRQ,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_CLR);
__raw_writel(BM_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ,
REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_CLR);
- __raw_writel(BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN,
- REGS_AUDIOOUT_BASE + HW_AUDIOOUT_CTRL_SET);
} else {
__raw_writel(BM_AUDIOIN_CTRL_FIFO_OVERFLOW_IRQ,
REGS_AUDIOIN_BASE + HW_AUDIOIN_CTRL_CLR);
diff --git a/sound/soc/mxs/mxs-dai.c b/sound/soc/mxs/mxs-dai.c
index a548b9948516..9ca22ecdb4b0 100644
--- a/sound/soc/mxs/mxs-dai.c
+++ b/sound/soc/mxs/mxs-dai.c
@@ -288,6 +288,7 @@ static int mxs_saif_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
default:
return -EINVAL;
}
+ break;
default:
return -EINVAL;
}
diff --git a/sound/soc/mxs/mxs-evk-adc.c b/sound/soc/mxs/mxs-evk-adc.c
index bd1ed6bf691f..16c1cb4fab96 100644
--- a/sound/soc/mxs/mxs-evk-adc.c
+++ b/sound/soc/mxs/mxs-evk-adc.c
@@ -33,12 +33,119 @@
#include "mxs-adc.h"
#include "mxs-pcm.h"
+/* mxs evk machine connections to the codec pins */
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* HPR/HPL OUT --> Headphone Jack */
+ {"Headphone Jack", NULL, "HPR"},
+ {"Headphone Jack", NULL, "HPL"},
+
+ /* SPEAKER OUT --> Ext Speaker */
+ {"Ext Spk", NULL, "SPEAKER"},
+};
+
+static int mxs_evk_jack_func;
+static int mxs_evk_spk_func;
+
+static const char *jack_function[] = { "off", "on"};
+
+static const char *spk_function[] = { "off", "on" };
+
+
+static const struct soc_enum mxs_evk_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, jack_function),
+ SOC_ENUM_SINGLE_EXT(2, spk_function),
+};
+
+static int mxs_evk_get_jack(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.enumerated.item[0] = mxs_evk_jack_func;
+ return 0;
+}
+
+static int mxs_evk_set_jack(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (mxs_evk_jack_func == ucontrol->value.enumerated.item[0])
+ return 0;
+
+ mxs_evk_jack_func = ucontrol->value.enumerated.item[0];
+ if (mxs_evk_jack_func)
+ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
+ else
+ snd_soc_dapm_disable_pin(codec, "Headphone Jack");
+
+ snd_soc_dapm_sync(codec);
+ return 1;
+}
+
+static int mxs_evk_get_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.enumerated.item[0] = mxs_evk_spk_func;
+ return 0;
+}
+
+static int mxs_evk_set_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (mxs_evk_spk_func == ucontrol->value.enumerated.item[0])
+ return 0;
+
+ mxs_evk_spk_func = ucontrol->value.enumerated.item[0];
+ if (mxs_evk_spk_func)
+ snd_soc_dapm_enable_pin(codec, "Ext Spk");
+ else
+ snd_soc_dapm_disable_pin(codec, "Ext Spk");
+
+ snd_soc_dapm_sync(codec);
+ return 1;
+}
+/* mxs evk card dapm widgets */
+static const struct snd_soc_dapm_widget mxs_evk_dapm_widgets[] = {
+ SND_SOC_DAPM_SPK("Ext Spk", NULL),
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+};
+
+static const struct snd_kcontrol_new mxs_evk_controls[] = {
+ SOC_ENUM_EXT("HP Playback Switch", mxs_evk_enum[0], mxs_evk_get_jack,
+ mxs_evk_set_jack),
+ SOC_ENUM_EXT("Speaker Playback Switch", mxs_evk_enum[1],
+ mxs_evk_get_spk, mxs_evk_set_spk),
+};
+
+static int mxs_evk_codec_init(struct snd_soc_codec *codec)
+{
+ int i, ret;
+ /* Add mxs evk specific controls */
+ snd_soc_add_controls(codec, mxs_evk_controls,
+ ARRAY_SIZE(mxs_evk_controls));
+
+ /* Add mxs evk specific widgets */
+ snd_soc_dapm_new_controls(codec, mxs_evk_dapm_widgets,
+ ARRAY_SIZE(mxs_evk_dapm_widgets));
+
+ /* Set up mxs evk specific audio path audio_map */
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ snd_soc_dapm_sync(codec);
+ /* default on */
+ mxs_evk_jack_func = 1;
+ mxs_evk_spk_func = 1;
+
+ return ret;
+}
/* mxs evk dac/adc audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link mxs_evk_codec_dai = {
.name = "MXS ADC/DAC",
.stream_name = "MXS ADC/DAC",
.cpu_dai = &mxs_adc_dai,
.codec_dai = &mxs_codec_dai,
+ .init = mxs_evk_codec_init,
};
/* mxs evk audio machine driver */
diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c
index a9f0358687f4..dac91e3eb8fb 100644
--- a/sound/soc/mxs/mxs-pcm.c
+++ b/sound/soc/mxs/mxs-pcm.c
@@ -141,6 +141,7 @@ static int mxs_pcm_prepare(struct snd_pcm_substream *substream)
/* Link with previous command */
prtd->dma_desc_array[i]->cmd.cmd.bits.bytes = prtd->dma_period;
prtd->dma_desc_array[i]->cmd.cmd.bits.irq = 1;
+ prtd->dma_desc_array[i]->cmd.cmd.bits.dec_sem = 0;
prtd->dma_desc_array[i]->cmd.cmd.bits.chain = 1;
/* Set DMA direction */
if (playback)
@@ -194,6 +195,8 @@ static void mxs_pcm_stop(struct snd_pcm_substream *substream)
prtd->dma_desc_array[(desc + 1)%8]->cmd.cmd.bits.command = NO_DMA_XFER;
mxs_dma_unfreeze(prtd->dma_ch);
+
+ mxs_dma_disable(prtd->dma_ch);
}
static int mxs_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
@@ -375,6 +378,7 @@ static int mxs_pcm_close(struct snd_pcm_substream *substream)
free_irq(prtd->params->irq, substream);
mxs_dma_get_cooked(prtd->dma_ch, &list);
/* Free DMA channel*/
+ mxs_dma_reset(prtd->dma_ch);
for (desc = 0; desc < desc_num; desc++)
mxs_dma_free_desc(prtd->dma_desc_array[desc]);
mxs_dma_release(prtd->dma_ch, mxs_pcm_dev);