]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/kernel-video.git/commitdiff
ASoC: kirkwood-i2s: better handling of play/record control registers
authorRussell King <rmk+kernel@arm.linux.org.uk>
Tue, 20 Nov 2012 12:19:53 +0000 (12:19 +0000)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Wed, 21 Nov 2012 01:40:23 +0000 (10:40 +0900)
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
sound/soc/kirkwood/kirkwood-i2s.c
sound/soc/kirkwood/kirkwood.h

index f059f401bdadc0270009aac46924d04ecc4cf727..823ef1e71d191e0fd6d33969f39b38188e94ec40 100644 (file)
@@ -113,15 +113,14 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
        struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
-       unsigned int i2s_reg, reg;
-       unsigned long i2s_value, value;
+       uint32_t ctl_play, ctl_rec;
+       unsigned int i2s_reg;
+       unsigned long i2s_value;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                i2s_reg = KIRKWOOD_I2S_PLAYCTL;
-               reg = KIRKWOOD_PLAYCTL;
        } else {
                i2s_reg = KIRKWOOD_I2S_RECCTL;
-               reg = KIRKWOOD_RECCTL;
        }
 
        /* set dco conf */
@@ -130,9 +129,6 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
        i2s_value = readl(priv->io+i2s_reg);
        i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK;
 
-       value = readl(priv->io+reg);
-       value &= ~KIRKWOOD_PLAYCTL_SIZE_MASK;
-
        /*
         * Size settings in play/rec i2s control regs and play/rec control
         * regs must be the same.
@@ -140,38 +136,57 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
                i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16;
-               value |= KIRKWOOD_PLAYCTL_SIZE_16_C;
+               ctl_play = KIRKWOOD_PLAYCTL_SIZE_16_C |
+                          KIRKWOOD_PLAYCTL_I2S_EN;
+               ctl_rec = KIRKWOOD_RECCTL_SIZE_16_C |
+                         KIRKWOOD_RECCTL_I2S_EN;
                break;
        /*
         * doesn't work... S20_3LE != kirkwood 20bit format ?
         *
        case SNDRV_PCM_FORMAT_S20_3LE:
                i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20;
-               value |= KIRKWOOD_PLAYCTL_SIZE_20;
+               ctl_play = KIRKWOOD_PLAYCTL_SIZE_20 |
+                          KIRKWOOD_PLAYCTL_I2S_EN;
+               ctl_rec = KIRKWOOD_RECCTL_SIZE_20 |
+                         KIRKWOOD_RECCTL_I2S_EN;
                break;
        */
        case SNDRV_PCM_FORMAT_S24_LE:
                i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24;
-               value |= KIRKWOOD_PLAYCTL_SIZE_24;
+               ctl_play = KIRKWOOD_PLAYCTL_SIZE_24 |
+                          KIRKWOOD_PLAYCTL_I2S_EN;
+               ctl_rec = KIRKWOOD_RECCTL_SIZE_24 |
+                         KIRKWOOD_RECCTL_I2S_EN;
                break;
        case SNDRV_PCM_FORMAT_S32_LE:
                i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32;
-               value |= KIRKWOOD_PLAYCTL_SIZE_32;
+               ctl_play = KIRKWOOD_PLAYCTL_SIZE_32 |
+                          KIRKWOOD_PLAYCTL_I2S_EN;
+               ctl_rec = KIRKWOOD_RECCTL_SIZE_32 |
+                         KIRKWOOD_RECCTL_I2S_EN;
                break;
        default:
                return -EINVAL;
        }
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               value &= ~KIRKWOOD_PLAYCTL_MONO_MASK;
                if (params_channels(params) == 1)
-                       value |= KIRKWOOD_PLAYCTL_MONO_BOTH;
+                       ctl_play |= KIRKWOOD_PLAYCTL_MONO_BOTH;
                else
-                       value |= KIRKWOOD_PLAYCTL_MONO_OFF;
+                       ctl_play |= KIRKWOOD_PLAYCTL_MONO_OFF;
+
+               priv->ctl_play &= ~(KIRKWOOD_PLAYCTL_MONO_MASK |
+                                   KIRKWOOD_PLAYCTL_I2S_EN |
+                                   KIRKWOOD_PLAYCTL_SPDIF_EN |
+                                   KIRKWOOD_PLAYCTL_SIZE_MASK);
+               priv->ctl_play |= ctl_play;
+       } else {
+               priv->ctl_rec &= ~KIRKWOOD_RECCTL_SIZE_MASK;
+               priv->ctl_rec |= ctl_rec;
        }
 
        writel(i2s_value, priv->io+i2s_reg);
-       writel(value, priv->io+reg);
 
        return 0;
 }
@@ -205,20 +220,18 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
+               /* configure */
+               ctl = priv->ctl_play;
+               value = ctl & ~(KIRKWOOD_PLAYCTL_I2S_EN |
+                               KIRKWOOD_PLAYCTL_SPDIF_EN);
+               writel(value, priv->io + KIRKWOOD_PLAYCTL);
+
+               /* enable interrupts */
                value = readl(priv->io + KIRKWOOD_INT_MASK);
                value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES;
                writel(value, priv->io + KIRKWOOD_INT_MASK);
 
-               /* configure audio & enable i2s playback */
-               ctl &= ~KIRKWOOD_PLAYCTL_BURST_MASK;
-               ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE
-                               | KIRKWOOD_PLAYCTL_SPDIF_EN);
-
-               if (priv->burst == 32)
-                       ctl |= KIRKWOOD_PLAYCTL_BURST_32;
-               else
-                       ctl |= KIRKWOOD_PLAYCTL_BURST_128;
-               ctl |= KIRKWOOD_PLAYCTL_I2S_EN;
+               /* enable playback */
                writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
                break;
 
@@ -259,30 +272,24 @@ static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
                                int cmd, struct snd_soc_dai *dai)
 {
        struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
-       unsigned long value;
+       uint32_t ctl, value;
 
        value = readl(priv->io + KIRKWOOD_RECCTL);
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
+               /* configure */
+               ctl = priv->ctl_rec;
+               value = ctl & ~KIRKWOOD_RECCTL_I2S_EN;
+               writel(value, priv->io + KIRKWOOD_RECCTL);
+
+               /* enable interrupts */
                value = readl(priv->io + KIRKWOOD_INT_MASK);
                value |= KIRKWOOD_INT_CAUSE_REC_BYTES;
                writel(value, priv->io + KIRKWOOD_INT_MASK);
 
-               /* configure audio & enable i2s record */
-               value = readl(priv->io + KIRKWOOD_RECCTL);
-               value &= ~KIRKWOOD_RECCTL_BURST_MASK;
-               value &= ~KIRKWOOD_RECCTL_MONO;
-               value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE
-                       | KIRKWOOD_RECCTL_SPDIF_EN);
-
-               if (priv->burst == 32)
-                       value |= KIRKWOOD_RECCTL_BURST_32;
-               else
-                       value |= KIRKWOOD_RECCTL_BURST_128;
-               value |= KIRKWOOD_RECCTL_I2S_EN;
-
-               writel(value, priv->io + KIRKWOOD_RECCTL);
+               /* enable record */
+               writel(ctl, priv->io + KIRKWOOD_RECCTL);
                break;
 
        case SNDRV_PCM_TRIGGER_STOP:
@@ -448,6 +455,31 @@ static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
        if (err < 0)
                return err;
 
+       priv->extclk = clk_get(&pdev->dev, "extclk");
+       if (!IS_ERR(priv->extclk)) {
+               if (priv->extclk == priv->clk) {
+                       clk_put(priv->extclk);
+                       priv->extclk = ERR_PTR(-EINVAL);
+               } else {
+                       dev_info(&pdev->dev, "found external clock\n");
+                       clk_prepare_enable(priv->extclk);
+                       soc_dai = &kirkwood_i2s_dai_extclk;
+               }
+       }
+
+       /* Some sensible defaults - this reflects the powerup values */
+       priv->ctl_play = KIRKWOOD_PLAYCTL_SIZE_24;
+       priv->ctl_rec = KIRKWOOD_RECCTL_SIZE_24;
+
+       /* Select the burst size */
+       if (data->burst == 32) {
+               priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_32;
+               priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_32;
+       } else {
+               priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_128;
+               priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128;
+       }
+
        err = snd_soc_register_dai(&pdev->dev, &kirkwood_i2s_dai);
        if (!err)
                return 0;
index 7d92b9e326347097fd8c0ce4ff69b605fd4f5d2f..6e3b14ac24f503e80ea8b8d987fb9f7da8dfbe04 100644 (file)
 
 struct kirkwood_dma_data {
        void __iomem *io;
+       uint32_t ctl_play;
+       uint32_t ctl_rec;
        int irq;
        int burst;
        struct clk *clk;