diff options
author | Lionel Xu <Lionel.Xu@freescale.com> | 2010-03-18 21:50:06 +0800 |
---|---|---|
committer | Alejandro Gonzalez <alex.gonzalez@digi.com> | 2010-05-25 11:20:16 +0200 |
commit | 18c5d7491f4fcee0b7d1e5a2b0dc42660e5c67a6 (patch) | |
tree | 650dbfbb01b64c9e9794e24f841b272deae028a8 /sound/soc | |
parent | 6443e51cfc24c968939a9a49c502b6f1564dbdfa (diff) |
ENGR00117751 MX28 ALSA: Support audio record through saif
Support audio record through saif, support playback/record simultaneously
Signed-off-by: Lionel Xu <r63889@freescale.com>
(cherry picked from commit 18627873f6332e03ebd03691f51937559bbdf03d)
Signed-off-by: Alejandro Gonzalez <alex.gonzalez@digi.com>
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/codecs/sgtl5000.c | 34 | ||||
-rw-r--r-- | sound/soc/mxs/Kconfig | 13 | ||||
-rw-r--r-- | sound/soc/mxs/mxs-dai.c | 160 | ||||
-rw-r--r-- | sound/soc/mxs/mxs-dai.h | 18 | ||||
-rw-r--r-- | sound/soc/mxs/mxs-devb.c | 47 |
5 files changed, 122 insertions, 150 deletions
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index f9f9a1a3b3fb..991088774580 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -611,6 +611,7 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream, int i2s_ctl; int div2 = 0; int reg; + u32 fs; pr_debug("%s channels=%d\n", __func__, channels); @@ -645,25 +646,25 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream, sgtl5000->lrclk); return -EFAULT; } - -#if 0 /* SGTL5000 rev1 has a IC bug to prevent switching to MCLK from PLL. */ - if (fs * 256 == sgtl5000->sysclk) - clk_ctl |= SGTL5000_MCLK_FREQ_256FS << SGTL5000_MCLK_FREQ_SHIFT; - else if (fs * 384 == sgtl5000->sysclk && fs != 96000) - clk_ctl |= SGTL5000_MCLK_FREQ_384FS << SGTL5000_MCLK_FREQ_SHIFT; - else if (fs * 512 == sgtl5000->sysclk && fs != 96000) - clk_ctl |= SGTL5000_MCLK_FREQ_512FS << SGTL5000_MCLK_FREQ_SHIFT; - else -#endif - { - /* - if (!sgtl5000->master) { + fs = sgtl5000->lrclk; + /* SGTL5000 rev1 has a IC bug to prevent switching to MCLK from PLL. */ + if (!sgtl5000->master) { + if (fs * 256 == sgtl5000->sysclk) + clk_ctl |= SGTL5000_MCLK_FREQ_256FS << \ + SGTL5000_MCLK_FREQ_SHIFT; + else if (fs * 384 == sgtl5000->sysclk && fs != 96000) + clk_ctl |= SGTL5000_MCLK_FREQ_384FS << \ + SGTL5000_MCLK_FREQ_SHIFT; + else if (fs * 512 == sgtl5000->sysclk && fs != 96000) + clk_ctl |= SGTL5000_MCLK_FREQ_512FS << \ + SGTL5000_MCLK_FREQ_SHIFT; + else { pr_err("%s: PLL not supported in slave mode\n", __func__); return -EINVAL; - }*/ + } + } else clk_ctl |= SGTL5000_MCLK_FREQ_PLL << SGTL5000_MCLK_FREQ_SHIFT; - } if ((clk_ctl & SGTL5000_MCLK_FREQ_MASK) == SGTL5000_MCLK_FREQ_PLL) { u64 out, t; @@ -1124,9 +1125,6 @@ static __devinit int sgtl5000_i2c_probe(struct i2c_client *client, int ret = 0; u32 val; - if (client->dev.platform_data) - clk_enable((struct clk *)client->dev.platform_data); - if (sgtl5000_codec) { dev_err(&client->dev, "Multiple SGTL5000 devices not supported\n"); diff --git a/sound/soc/mxs/Kconfig b/sound/soc/mxs/Kconfig index d4dc2b795eb0..10bed6d4f436 100644 --- a/sound/soc/mxs/Kconfig +++ b/sound/soc/mxs/Kconfig @@ -33,19 +33,6 @@ config SND_MXS_SOC_DAI help Enable MXS Digital Audio Interface SAIF -config SND_MXS_SOC_SAIF0_SELECT - bool "Enable SAIF0 module" - default y - depends on SND_MXS_SOC_DAI - help - Enable MXS SAIF0 Module - -config SND_MXS_SOC_SAIF1_SELECT - bool "Enable SAIF1 module" - depends on SND_MXS_SOC_DAI - help - Enable MXS SAIF1 Module - config SND_MXS_SOC_ADC tristate "MXS ADC/DAC Audio Interface" default y diff --git a/sound/soc/mxs/mxs-dai.c b/sound/soc/mxs/mxs-dai.c index de759b5face4..6250eb1214dc 100644 --- a/sound/soc/mxs/mxs-dai.c +++ b/sound/soc/mxs/mxs-dai.c @@ -185,6 +185,8 @@ #define MXS_DAI_SAIF0 0 #define MXS_DAI_SAIF1 1 +static struct mxs_saif mxs_saif_en; + static int saif_active[2] = { 0, 0 }; struct mxs_pcm_dma_params mxs_saif_0 = { @@ -206,19 +208,16 @@ struct mxs_pcm_dma_params mxs_saif_1 = { static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { - u32 scr; struct clk *saif_clk; - - if (cpu_dai->id == MXS_DAI_SAIF0) { - scr = __raw_readl(SAIF0_CTRL); - saif_clk = clk_get(NULL, "saif.0"); - } else { - scr = __raw_readl(SAIF1_CTRL); - saif_clk = clk_get(NULL, "saif.1"); - } + struct mxs_saif *saif_select = (struct mxs_saif *)cpu_dai->private_data; switch (clk_id) { case IMX_SSP_SYS_CLK: + saif_clk = saif_select->saif_mclk; + if (IS_ERR(saif_clk)) { + pr_err("%s:failed to get sys_clk\n", __func__); + return -EINVAL; + } clk_set_rate(saif_clk, freq); clk_enable(saif_clk); break; @@ -247,8 +246,8 @@ static int mxs_saif_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, static int mxs_saif_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { u32 scr, stat; - - if (cpu_dai->id == MXS_DAI_SAIF0) { + struct mxs_saif *saif_select = (struct mxs_saif *)cpu_dai->private_data; + if (saif_select->saif_en == SAIF0) { scr = __raw_readl(SAIF0_CTRL); stat = __raw_readl(SAIF0_STAT); } else { @@ -307,9 +306,7 @@ static int mxs_saif_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) scr |= BM_SAIF_CTRL_SLAVE_MODE; break; } - - - if (cpu_dai->id == MXS_DAI_SAIF0) + if (saif_select->saif_en == SAIF0) __raw_writel(scr, SAIF0_CTRL); else __raw_writel(scr, SAIF1_CTRL); @@ -321,23 +318,26 @@ static int mxs_saif_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) static int mxs_saif_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { - /* we cant really change any saif values after saif is enabled - * need to fix in software for max flexibility - lrg */ - if (cpu_dai->playback.active || cpu_dai->capture.active) + /* we cant really change any saif values after saif is enabled*/ + struct mxs_saif *saif_select = (struct mxs_saif *)cpu_dai->private_data; + + if (((saif_select->stream_mapping == PLAYBACK_SAIF0_CAPTURE_SAIF1) && \ + (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) || \ + ((saif_select->stream_mapping == PLAYBACK_SAIF1_CAPTURE_SAIF0) \ + && (substream->stream == SNDRV_PCM_STREAM_CAPTURE))) + cpu_dai->dma_data = &mxs_saif_0; + else + cpu_dai->dma_data = &mxs_saif_1; + + if (cpu_dai->playback.active && cpu_dai->capture.active) return 0; - /* reset the SAIF port - Sect 45.4.4 */ - if (cpu_dai->id == MXS_DAI_SAIF0) + if (saif_select->saif_en == SAIF0) if (saif_active[SAIF0_PORT]++) return 0; - if (cpu_dai->id == MXS_DAI_SAIF1) + if (saif_select->saif_en == SAIF1) if (saif_active[SAIF1_PORT]++) return 0; - - if (cpu_dai->id == MXS_DAI_SAIF0) - cpu_dai->dma_data = &mxs_saif_0; - else - cpu_dai->dma_data = &mxs_saif_1; SAIF_DUMP(); return 0; } @@ -350,18 +350,15 @@ static int mxs_saif_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai) { - int id; u32 scr, stat; - id = cpu_dai->id; - - if (cpu_dai->id == MXS_DAI_SAIF0) { + struct mxs_saif *saif_select = (struct mxs_saif *)cpu_dai->private_data; + if (saif_select->saif_en == SAIF0) { scr = __raw_readl(SAIF0_CTRL); stat = __raw_readl(SAIF0_STAT); } else { scr = __raw_readl(SAIF1_CTRL); stat = __raw_readl(SAIF1_STAT); } - /* cant change any parameters when SAIF is running */ /* DAI data (word) size */ scr &= ~BM_SAIF_CTRL_WORD_LENGTH; @@ -379,7 +376,6 @@ static int mxs_saif_hw_params(struct snd_pcm_substream *substream, scr |= BM_SAIF_CTRL_BITCLK_48XFS_ENABLE; break; } - /* Tx/Rx config */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* enable TX mode */ @@ -389,48 +385,52 @@ static int mxs_saif_hw_params(struct snd_pcm_substream *substream, scr |= BM_SAIF_CTRL_READ_MODE; } - if (cpu_dai->id == MXS_DAI_SAIF0) + if (saif_select->saif_en == SAIF0) __raw_writel(scr, SAIF0_CTRL); else __raw_writel(scr, SAIF1_CTRL); - return 0; } static int mxs_saif_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { - if (cpu_dai->id == MXS_DAI_SAIF0) + struct mxs_saif *saif_select = (struct mxs_saif *)cpu_dai->private_data; + if (saif_select->saif_en == SAIF0) __raw_writel(BM_SAIF_CTRL_CLKGATE, SAIF0_CTRL_CLR); else __raw_writel(BM_SAIF_CTRL_CLKGATE, SAIF1_CTRL_CLR); - - /* enable the saif port, note that no other port config - * should happen after SSIEN is set */ SAIF_DUMP(); return 0; } static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *cpu_dai) + struct snd_soc_dai *cpu_dai) { - u32 scr; - if (cpu_dai->id == MXS_DAI_SAIF0) - scr = __raw_readl(SAIF0_CTRL); - else - scr = __raw_readl(SAIF1_CTRL); - + void __iomem *reg; + struct mxs_saif *saif_select = (struct mxs_saif *)cpu_dai->private_data; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - /*write a data to saif data register to trigger the transfer*/ - __raw_writel(0x0, SAIF0_DATA); + + if (saif_select->saif_en == SAIF0) + reg = (void __iomem *)SAIF0_DATA; + else + reg = (void __iomem *)SAIF1_DATA; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + /*write a data to saif data register to trigger + the transfer*/ + __raw_writel(0, reg); + else + /*read a data from saif data register to trigger + the receive*/ + __raw_readl(reg); break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - scr &= ~BM_SAIF_CTRL_RUN; break; default: return -EINVAL; @@ -442,18 +442,16 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd, static void mxs_saif_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { - int id; - - id = cpu_dai->id; - + struct mxs_saif *saif_select = (struct mxs_saif *)cpu_dai->private_data; /* shutdown SAIF if neither Tx or Rx is active */ if (cpu_dai->playback.active || cpu_dai->capture.active) return; - if (id == MXS_DAI_SAIF0) { + if (saif_select->saif_en == SAIF0) { if (--saif_active[SAIF0_PORT] > 1) return; - } else { + } + if (saif_select->saif_en == SAIF1) { if (--saif_active[SAIF1_PORT]) return; } @@ -510,32 +508,25 @@ static irqreturn_t saif1_irq(int irq, void *dev_id) static int mxs_saif_probe(struct platform_device *pdev, struct snd_soc_dai *dai) { - printk("in mxs_saif_probe\n"); - if (!strcmp(dai->name, "mxs-saif-0")) - if (request_irq(IRQ_SAIF0, saif0_irq, 0, "saif0", dai)) { - printk(KERN_ERR "%s: failure requesting irq %s\n", - __func__, "saif0"); - return -EBUSY; - } - - if (!strcmp(dai->name, "mxs-saif-1")) - if (request_irq(IRQ_SAIF1, saif1_irq, 0, "saif1", dai)) { - printk(KERN_ERR "%s: failure requesting irq %s\n", - __func__, "saif1"); - return -EBUSY; - } + if (request_irq(IRQ_SAIF0, saif0_irq, 0, "saif0", dai)) { + printk(KERN_ERR "%s: failure requesting irq %s\n", + __func__, "saif0"); + return -EBUSY; + } + if (request_irq(IRQ_SAIF1, saif1_irq, 0, "saif1", dai)) { + printk(KERN_ERR "%s: failure requesting irq %s\n", + __func__, "saif1"); + return -EBUSY; + } return 0; } static void mxs_saif_remove(struct platform_device *pdev, struct snd_soc_dai *dai) { - if (!strcmp(dai->name, "mxs-saif-0")) - free_irq(IRQ_SAIF0, dai); - - if (!strcmp(dai->name, "mxs-saif-1")) - free_irq(IRQ_SAIF1, dai); + free_irq(IRQ_SAIF0, dai); + free_irq(IRQ_SAIF1, dai); } #define MXS_SAIF_RATES \ @@ -563,29 +554,7 @@ static struct snd_soc_dai_ops mxs_saif_dai_ops = { struct snd_soc_dai mxs_saif_dai[] = { { - .name = "mxs-saif-0", - .id = MXS_DAI_SAIF0, - .probe = mxs_saif_probe, - .remove = mxs_saif_remove, - .suspend = mxs_saif_suspend, - .resume = mxs_saif_resume, - .playback = { - .channels_min = 2, - .channels_max = 2, - .rates = MXS_SAIF_RATES, - .formats = MXS_SAIF_FORMATS, - }, - .capture = { - .channels_min = 2, - .channels_max = 2, - .rates = MXS_SAIF_RATES, - .formats = MXS_SAIF_FORMATS, - }, - .ops = &mxs_saif_dai_ops, - }, - { - .name = "mxs-saif-1", - .id = MXS_DAI_SAIF1, + .name = "mxs-saif", .probe = mxs_saif_probe, .remove = mxs_saif_remove, .suspend = mxs_saif_suspend, @@ -603,6 +572,7 @@ struct snd_soc_dai mxs_saif_dai[] = { .formats = MXS_SAIF_FORMATS, }, .ops = &mxs_saif_dai_ops, + .private_data = &mxs_saif_en, } }; EXPORT_SYMBOL_GPL(mxs_saif_dai); diff --git a/sound/soc/mxs/mxs-dai.h b/sound/soc/mxs/mxs-dai.h index 93b4038c5ca9..d9538b1b788d 100644 --- a/sound/soc/mxs/mxs-dai.h +++ b/sound/soc/mxs/mxs-dai.h @@ -24,13 +24,17 @@ /* SSI clock sources */ #define IMX_SSP_SYS_CLK 0 - -/* SSI Div 2 */ -#define IMX_SSI_DIV_2_OFF (~SSI_STCCR_DIV2) -#define IMX_SSI_DIV_2_ON SSI_STCCR_DIV2 - -#define IMX_DAI_AC97_1 0 -#define IMX_DAI_AC97_2 1 +#define SAIF0 0 +#define SAIF1 1 + +/*private info*/ +struct mxs_saif { + u8 saif_en; +#define PLAYBACK_SAIF0_CAPTURE_SAIF1 0 +#define PLAYBACK_SAIF1_CAPTURE_SAIF0 1 + u16 stream_mapping; + struct clk *saif_mclk; +}; extern struct snd_soc_dai mxs_saif_dai[]; diff --git a/sound/soc/mxs/mxs-devb.c b/sound/soc/mxs/mxs-devb.c index e92f99b1ae95..a56955ddb677 100644 --- a/sound/soc/mxs/mxs-devb.c +++ b/sound/soc/mxs/mxs-devb.c @@ -42,9 +42,6 @@ #include "mxs-pcm.h" #include "../codecs/sgtl5000.h" -/* SAIF BCLK and LRC master */ -#define SGTL5000_SAIF_MASTER 0 - struct mxs_evk_priv { int sysclk; int hw; @@ -74,19 +71,18 @@ static int mxs_evk_audio_hw_params(struct snd_pcm_substream *substream, snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, priv->sysclk, 0); snd_soc_dai_set_sysclk(codec_dai, SGTL5000_LRCLK, rate, 0); - -#if SGTL5000_SAIF_MASTER - dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM; -#else + /* set codec to slave mode */ dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; -#endif /* set codec DAI configuration */ ret = snd_soc_dai_set_fmt(codec_dai, dai_format); if (ret < 0) return ret; + /* set cpu_dai to master mode for playback, slave mode for record */ + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM; /* set cpu DAI configuration */ ret = snd_soc_dai_set_fmt(cpu_dai, dai_format); @@ -102,13 +98,32 @@ static int mxs_evk_audio_hw_params(struct snd_pcm_substream *substream, static int mxs_evk_startup(struct snd_pcm_substream *substream) { + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai_link *machine = rtd->dai; + struct snd_soc_dai *cpu_dai = machine->cpu_dai; + struct mxs_saif *saif_select = (struct mxs_saif *)cpu_dai->private_data; + + if (((saif_select->stream_mapping == PLAYBACK_SAIF0_CAPTURE_SAIF1) && \ + (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) || \ + ((saif_select->stream_mapping == PLAYBACK_SAIF1_CAPTURE_SAIF0) \ + && (substream->stream == SNDRV_PCM_STREAM_CAPTURE))) + saif_select->saif_en = 0; + else + saif_select->saif_en = 1; return 0; } static void mxs_evk_shutdown(struct snd_pcm_substream *substream) { struct mxs_evk_priv *priv = &card_priv; - priv->hw = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai_link *machine = rtd->dai; + struct snd_soc_dai *cpu_dai = machine->cpu_dai; + + if (cpu_dai->playback.active || cpu_dai->capture.active) + priv->hw = 1; + else + priv->hw = 0; } /* @@ -209,16 +224,14 @@ static struct snd_soc_device mxs_evk_snd_devdata = { static int __devinit mxs_evk_sgtl5000_probe(struct platform_device *pdev) { struct mxs_audio_platform_data *plat = pdev->dev.platform_data; - + struct mxs_saif *saif_select; int ret = -EINVAL; - /*init the clk*/ if (plat->init && plat->init()) goto err_plat_init; - - if (plat->saif0_select == 1) - mxs_evk_dai.cpu_dai = &mxs_saif_dai[0]; - else - mxs_evk_dai.cpu_dai = &mxs_saif_dai[1]; + mxs_evk_dai.cpu_dai = &mxs_saif_dai[0]; + saif_select = (struct mxs_saif *)mxs_evk_dai.cpu_dai->private_data; + saif_select->stream_mapping = PLAYBACK_SAIF0_CAPTURE_SAIF1; + saif_select->saif_mclk = plat->saif_mclock; return 0; err_plat_init: if (plat->finit) |