From a9d2ba1444b0af6c2d8534f0b306660ffc045bc6 Mon Sep 17 00:00:00 2001 From: Ian Wisbon Date: Thu, 10 Feb 2011 17:15:15 -0500 Subject: Linux 2.6.31 Release for Digi ConnectCore Wi-i.MX boards --- sound/arm/mxc-alsa-spdif.c | 18 +- sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/mxs-adc-codec.c | 237 ++++++++++++++++++++----- sound/soc/codecs/sgtl5000.c | 49 +---- sound/soc/codecs/wm8753.c | 14 ++ sound/soc/codecs/wm8753.h | 1 + sound/soc/imx/Kconfig | 10 ++ sound/soc/imx/Makefile | 3 + sound/soc/imx/imx-3stack-ak4647.c | 3 - sound/soc/imx/imx-3stack-ak5702.c | 4 +- sound/soc/imx/imx-3stack-wm8580.c | 10 +- sound/soc/imx/imx-ccwmx51-wm8753.c | 38 +++- sound/soc/imx/imx-esai.c | 353 ++++++------------------------------- sound/soc/imx/imx-esai.h | 286 +++++++++++++++++++++++++++++- sound/soc/imx/imx-pcm.c | 8 + sound/soc/mxs/mxs-adc.c | 246 +++++++++++++++++++++----- sound/soc/mxs/mxs-dai.c | 1 + sound/soc/mxs/mxs-evk-adc.c | 107 +++++++++++ sound/soc/mxs/mxs-pcm.c | 4 + 20 files changed, 942 insertions(+), 456 deletions(-) (limited to 'sound') 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); -- cgit v1.2.3