1f9b95980Sapatard@mandriva.com /* 2f9b95980Sapatard@mandriva.com * kirkwood-i2s.c 3f9b95980Sapatard@mandriva.com * 4f9b95980Sapatard@mandriva.com * (c) 2010 Arnaud Patard <apatard@mandriva.com> 569737897SArnaud Patard (Rtp) * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org> 6f9b95980Sapatard@mandriva.com * 7f9b95980Sapatard@mandriva.com * This program is free software; you can redistribute it and/or modify it 8f9b95980Sapatard@mandriva.com * under the terms of the GNU General Public License as published by the 9f9b95980Sapatard@mandriva.com * Free Software Foundation; either version 2 of the License, or (at your 10f9b95980Sapatard@mandriva.com * option) any later version. 11f9b95980Sapatard@mandriva.com */ 12f9b95980Sapatard@mandriva.com 13f9b95980Sapatard@mandriva.com #include <linux/init.h> 14f9b95980Sapatard@mandriva.com #include <linux/module.h> 15f9b95980Sapatard@mandriva.com #include <linux/platform_device.h> 16f9b95980Sapatard@mandriva.com #include <linux/io.h> 17f9b95980Sapatard@mandriva.com #include <linux/slab.h> 18f9b95980Sapatard@mandriva.com #include <linux/mbus.h> 19f9b95980Sapatard@mandriva.com #include <linux/delay.h> 20e919c716SAndrew Lunn #include <linux/clk.h> 21f9b95980Sapatard@mandriva.com #include <sound/pcm.h> 22f9b95980Sapatard@mandriva.com #include <sound/pcm_params.h> 23f9b95980Sapatard@mandriva.com #include <sound/soc.h> 24c02cecb9SArnd Bergmann #include <linux/platform_data/asoc-kirkwood.h> 25f9b95980Sapatard@mandriva.com #include "kirkwood.h" 26f9b95980Sapatard@mandriva.com 27f9b95980Sapatard@mandriva.com #define DRV_NAME "kirkwood-i2s" 28f9b95980Sapatard@mandriva.com 29f9b95980Sapatard@mandriva.com #define KIRKWOOD_I2S_RATES \ 30f9b95980Sapatard@mandriva.com (SNDRV_PCM_RATE_44100 | \ 31f9b95980Sapatard@mandriva.com SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) 32f9b95980Sapatard@mandriva.com #define KIRKWOOD_I2S_FORMATS \ 33f9b95980Sapatard@mandriva.com (SNDRV_PCM_FMTBIT_S16_LE | \ 34f9b95980Sapatard@mandriva.com SNDRV_PCM_FMTBIT_S24_LE | \ 35f9b95980Sapatard@mandriva.com SNDRV_PCM_FMTBIT_S32_LE) 36f9b95980Sapatard@mandriva.com 37f9b95980Sapatard@mandriva.com static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai, 38f9b95980Sapatard@mandriva.com unsigned int fmt) 39f9b95980Sapatard@mandriva.com { 40f0fba2adSLiam Girdwood struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(cpu_dai); 41f9b95980Sapatard@mandriva.com unsigned long mask; 42f9b95980Sapatard@mandriva.com unsigned long value; 43f9b95980Sapatard@mandriva.com 44f9b95980Sapatard@mandriva.com switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 45f9b95980Sapatard@mandriva.com case SND_SOC_DAIFMT_RIGHT_J: 46f9b95980Sapatard@mandriva.com mask = KIRKWOOD_I2S_CTL_RJ; 47f9b95980Sapatard@mandriva.com break; 48f9b95980Sapatard@mandriva.com case SND_SOC_DAIFMT_LEFT_J: 49f9b95980Sapatard@mandriva.com mask = KIRKWOOD_I2S_CTL_LJ; 50f9b95980Sapatard@mandriva.com break; 51f9b95980Sapatard@mandriva.com case SND_SOC_DAIFMT_I2S: 52f9b95980Sapatard@mandriva.com mask = KIRKWOOD_I2S_CTL_I2S; 53f9b95980Sapatard@mandriva.com break; 54f9b95980Sapatard@mandriva.com default: 55f9b95980Sapatard@mandriva.com return -EINVAL; 56f9b95980Sapatard@mandriva.com } 57f9b95980Sapatard@mandriva.com 58f9b95980Sapatard@mandriva.com /* 59f9b95980Sapatard@mandriva.com * Set same format for playback and record 60f9b95980Sapatard@mandriva.com * This avoids some troubles. 61f9b95980Sapatard@mandriva.com */ 62f9b95980Sapatard@mandriva.com value = readl(priv->io+KIRKWOOD_I2S_PLAYCTL); 63f9b95980Sapatard@mandriva.com value &= ~KIRKWOOD_I2S_CTL_JUST_MASK; 64f9b95980Sapatard@mandriva.com value |= mask; 65f9b95980Sapatard@mandriva.com writel(value, priv->io+KIRKWOOD_I2S_PLAYCTL); 66f9b95980Sapatard@mandriva.com 67f9b95980Sapatard@mandriva.com value = readl(priv->io+KIRKWOOD_I2S_RECCTL); 68f9b95980Sapatard@mandriva.com value &= ~KIRKWOOD_I2S_CTL_JUST_MASK; 69f9b95980Sapatard@mandriva.com value |= mask; 70f9b95980Sapatard@mandriva.com writel(value, priv->io+KIRKWOOD_I2S_RECCTL); 71f9b95980Sapatard@mandriva.com 72f9b95980Sapatard@mandriva.com return 0; 73f9b95980Sapatard@mandriva.com } 74f9b95980Sapatard@mandriva.com 75f9b95980Sapatard@mandriva.com static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate) 76f9b95980Sapatard@mandriva.com { 77f9b95980Sapatard@mandriva.com unsigned long value; 78f9b95980Sapatard@mandriva.com 79f9b95980Sapatard@mandriva.com value = KIRKWOOD_DCO_CTL_OFFSET_0; 80f9b95980Sapatard@mandriva.com switch (rate) { 81f9b95980Sapatard@mandriva.com default: 82f9b95980Sapatard@mandriva.com case 44100: 83f9b95980Sapatard@mandriva.com value |= KIRKWOOD_DCO_CTL_FREQ_11; 84f9b95980Sapatard@mandriva.com break; 85f9b95980Sapatard@mandriva.com case 48000: 86f9b95980Sapatard@mandriva.com value |= KIRKWOOD_DCO_CTL_FREQ_12; 87f9b95980Sapatard@mandriva.com break; 88f9b95980Sapatard@mandriva.com case 96000: 89f9b95980Sapatard@mandriva.com value |= KIRKWOOD_DCO_CTL_FREQ_24; 90f9b95980Sapatard@mandriva.com break; 91f9b95980Sapatard@mandriva.com } 92f9b95980Sapatard@mandriva.com writel(value, io + KIRKWOOD_DCO_CTL); 93f9b95980Sapatard@mandriva.com 94f9b95980Sapatard@mandriva.com /* wait for dco locked */ 95f9b95980Sapatard@mandriva.com do { 96f9b95980Sapatard@mandriva.com cpu_relax(); 97f9b95980Sapatard@mandriva.com value = readl(io + KIRKWOOD_DCO_SPCR_STATUS); 982424d458SRussell King value &= KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK; 99f9b95980Sapatard@mandriva.com } while (value == 0); 100f9b95980Sapatard@mandriva.com } 101f9b95980Sapatard@mandriva.com 102f0fba2adSLiam Girdwood static int kirkwood_i2s_startup(struct snd_pcm_substream *substream, 103f0fba2adSLiam Girdwood struct snd_soc_dai *dai) 104f0fba2adSLiam Girdwood { 105f0fba2adSLiam Girdwood struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); 106f0fba2adSLiam Girdwood 107f0fba2adSLiam Girdwood snd_soc_dai_set_dma_data(dai, substream, priv); 108f0fba2adSLiam Girdwood return 0; 109f0fba2adSLiam Girdwood } 110f0fba2adSLiam Girdwood 111f9b95980Sapatard@mandriva.com static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, 112f9b95980Sapatard@mandriva.com struct snd_pcm_hw_params *params, 113f9b95980Sapatard@mandriva.com struct snd_soc_dai *dai) 114f9b95980Sapatard@mandriva.com { 115f0fba2adSLiam Girdwood struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); 116f9b95980Sapatard@mandriva.com unsigned int i2s_reg, reg; 117f9b95980Sapatard@mandriva.com unsigned long i2s_value, value; 118f9b95980Sapatard@mandriva.com 119f9b95980Sapatard@mandriva.com if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 120f9b95980Sapatard@mandriva.com i2s_reg = KIRKWOOD_I2S_PLAYCTL; 121f9b95980Sapatard@mandriva.com reg = KIRKWOOD_PLAYCTL; 122f9b95980Sapatard@mandriva.com } else { 123f9b95980Sapatard@mandriva.com i2s_reg = KIRKWOOD_I2S_RECCTL; 124f9b95980Sapatard@mandriva.com reg = KIRKWOOD_RECCTL; 125f9b95980Sapatard@mandriva.com } 126f9b95980Sapatard@mandriva.com 127f9b95980Sapatard@mandriva.com /* set dco conf */ 128f9b95980Sapatard@mandriva.com kirkwood_set_dco(priv->io, params_rate(params)); 129f9b95980Sapatard@mandriva.com 130f9b95980Sapatard@mandriva.com i2s_value = readl(priv->io+i2s_reg); 131f9b95980Sapatard@mandriva.com i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK; 132f9b95980Sapatard@mandriva.com 133f9b95980Sapatard@mandriva.com value = readl(priv->io+reg); 134f9b95980Sapatard@mandriva.com value &= ~KIRKWOOD_PLAYCTL_SIZE_MASK; 135f9b95980Sapatard@mandriva.com 136f9b95980Sapatard@mandriva.com /* 137f9b95980Sapatard@mandriva.com * Size settings in play/rec i2s control regs and play/rec control 138f9b95980Sapatard@mandriva.com * regs must be the same. 139f9b95980Sapatard@mandriva.com */ 140f9b95980Sapatard@mandriva.com switch (params_format(params)) { 141f9b95980Sapatard@mandriva.com case SNDRV_PCM_FORMAT_S16_LE: 142f9b95980Sapatard@mandriva.com i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16; 143f9b95980Sapatard@mandriva.com value |= KIRKWOOD_PLAYCTL_SIZE_16_C; 144f9b95980Sapatard@mandriva.com break; 145f9b95980Sapatard@mandriva.com /* 146f9b95980Sapatard@mandriva.com * doesn't work... S20_3LE != kirkwood 20bit format ? 147f9b95980Sapatard@mandriva.com * 148f9b95980Sapatard@mandriva.com case SNDRV_PCM_FORMAT_S20_3LE: 149f9b95980Sapatard@mandriva.com i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20; 150f9b95980Sapatard@mandriva.com value |= KIRKWOOD_PLAYCTL_SIZE_20; 151f9b95980Sapatard@mandriva.com break; 152f9b95980Sapatard@mandriva.com */ 153f9b95980Sapatard@mandriva.com case SNDRV_PCM_FORMAT_S24_LE: 154f9b95980Sapatard@mandriva.com i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24; 155f9b95980Sapatard@mandriva.com value |= KIRKWOOD_PLAYCTL_SIZE_24; 156f9b95980Sapatard@mandriva.com break; 157f9b95980Sapatard@mandriva.com case SNDRV_PCM_FORMAT_S32_LE: 158f9b95980Sapatard@mandriva.com i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32; 159f9b95980Sapatard@mandriva.com value |= KIRKWOOD_PLAYCTL_SIZE_32; 160f9b95980Sapatard@mandriva.com break; 161f9b95980Sapatard@mandriva.com default: 162f9b95980Sapatard@mandriva.com return -EINVAL; 163f9b95980Sapatard@mandriva.com } 164dfe4c936Sarnaud.patard@rtp-net.org 165dfe4c936Sarnaud.patard@rtp-net.org if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 166dfe4c936Sarnaud.patard@rtp-net.org value &= ~KIRKWOOD_PLAYCTL_MONO_MASK; 167dfe4c936Sarnaud.patard@rtp-net.org if (params_channels(params) == 1) 168dfe4c936Sarnaud.patard@rtp-net.org value |= KIRKWOOD_PLAYCTL_MONO_BOTH; 169dfe4c936Sarnaud.patard@rtp-net.org else 170dfe4c936Sarnaud.patard@rtp-net.org value |= KIRKWOOD_PLAYCTL_MONO_OFF; 171dfe4c936Sarnaud.patard@rtp-net.org } 172dfe4c936Sarnaud.patard@rtp-net.org 173f9b95980Sapatard@mandriva.com writel(i2s_value, priv->io+i2s_reg); 174f9b95980Sapatard@mandriva.com writel(value, priv->io+reg); 175f9b95980Sapatard@mandriva.com 176f9b95980Sapatard@mandriva.com return 0; 177f9b95980Sapatard@mandriva.com } 178f9b95980Sapatard@mandriva.com 179f9b95980Sapatard@mandriva.com static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, 180f9b95980Sapatard@mandriva.com int cmd, struct snd_soc_dai *dai) 181f9b95980Sapatard@mandriva.com { 182f0fba2adSLiam Girdwood struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); 183*982b604bSRussell King uint32_t ctl, value; 184f9b95980Sapatard@mandriva.com 185*982b604bSRussell King ctl = readl(priv->io + KIRKWOOD_PLAYCTL); 186*982b604bSRussell King if (ctl & KIRKWOOD_PLAYCTL_PAUSE) { 187*982b604bSRussell King unsigned timeout = 5000; 188f9b95980Sapatard@mandriva.com /* 189*982b604bSRussell King * The Armada510 spec says that if we enter pause mode, the 190*982b604bSRussell King * busy bit must be read back as clear _twice_. Make sure 191*982b604bSRussell King * we respect that otherwise we get DMA underruns. 192f9b95980Sapatard@mandriva.com */ 193*982b604bSRussell King do { 194*982b604bSRussell King value = ctl; 195*982b604bSRussell King ctl = readl(priv->io + KIRKWOOD_PLAYCTL); 196*982b604bSRussell King if (!((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY)) 197*982b604bSRussell King break; 198*982b604bSRussell King udelay(1); 199*982b604bSRussell King } while (timeout--); 200*982b604bSRussell King 201*982b604bSRussell King if ((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY) 202*982b604bSRussell King dev_notice(dai->dev, "timed out waiting for busy to deassert: %08x\n", 203*982b604bSRussell King ctl); 204*982b604bSRussell King } 205f9b95980Sapatard@mandriva.com 206f9b95980Sapatard@mandriva.com switch (cmd) { 207f9b95980Sapatard@mandriva.com case SNDRV_PCM_TRIGGER_START: 208f9b95980Sapatard@mandriva.com /* stop audio, enable interrupts */ 209*982b604bSRussell King ctl |= KIRKWOOD_PLAYCTL_PAUSE; 210*982b604bSRussell King writel(ctl, priv->io + KIRKWOOD_PLAYCTL); 211f9b95980Sapatard@mandriva.com 212f9b95980Sapatard@mandriva.com value = readl(priv->io + KIRKWOOD_INT_MASK); 213f9b95980Sapatard@mandriva.com value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES; 214f9b95980Sapatard@mandriva.com writel(value, priv->io + KIRKWOOD_INT_MASK); 215f9b95980Sapatard@mandriva.com 216f9b95980Sapatard@mandriva.com /* configure audio & enable i2s playback */ 217*982b604bSRussell King ctl &= ~KIRKWOOD_PLAYCTL_BURST_MASK; 218*982b604bSRussell King ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE 219b424ec95Sarnaud.patard@rtp-net.org | KIRKWOOD_PLAYCTL_SPDIF_EN); 220f9b95980Sapatard@mandriva.com 221f9b95980Sapatard@mandriva.com if (priv->burst == 32) 222*982b604bSRussell King ctl |= KIRKWOOD_PLAYCTL_BURST_32; 223f9b95980Sapatard@mandriva.com else 224*982b604bSRussell King ctl |= KIRKWOOD_PLAYCTL_BURST_128; 225*982b604bSRussell King ctl |= KIRKWOOD_PLAYCTL_I2S_EN; 226*982b604bSRussell King writel(ctl, priv->io + KIRKWOOD_PLAYCTL); 227f9b95980Sapatard@mandriva.com break; 228f9b95980Sapatard@mandriva.com 229f9b95980Sapatard@mandriva.com case SNDRV_PCM_TRIGGER_STOP: 230f9b95980Sapatard@mandriva.com /* stop audio, disable interrupts */ 231*982b604bSRussell King ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; 232*982b604bSRussell King writel(ctl, priv->io + KIRKWOOD_PLAYCTL); 233f9b95980Sapatard@mandriva.com 234f9b95980Sapatard@mandriva.com value = readl(priv->io + KIRKWOOD_INT_MASK); 235f9b95980Sapatard@mandriva.com value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES; 236f9b95980Sapatard@mandriva.com writel(value, priv->io + KIRKWOOD_INT_MASK); 237f9b95980Sapatard@mandriva.com 238f9b95980Sapatard@mandriva.com /* disable all playbacks */ 239*982b604bSRussell King ctl &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN); 240*982b604bSRussell King writel(ctl, priv->io + KIRKWOOD_PLAYCTL); 241f9b95980Sapatard@mandriva.com break; 242f9b95980Sapatard@mandriva.com 243f9b95980Sapatard@mandriva.com case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 244f9b95980Sapatard@mandriva.com case SNDRV_PCM_TRIGGER_SUSPEND: 245*982b604bSRussell King ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE; 246*982b604bSRussell King writel(ctl, priv->io + KIRKWOOD_PLAYCTL); 247f9b95980Sapatard@mandriva.com break; 248f9b95980Sapatard@mandriva.com 249f9b95980Sapatard@mandriva.com case SNDRV_PCM_TRIGGER_RESUME: 250f9b95980Sapatard@mandriva.com case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 251*982b604bSRussell King ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE); 252*982b604bSRussell King writel(ctl, priv->io + KIRKWOOD_PLAYCTL); 253f9b95980Sapatard@mandriva.com break; 254f9b95980Sapatard@mandriva.com 255f9b95980Sapatard@mandriva.com default: 256f9b95980Sapatard@mandriva.com return -EINVAL; 257f9b95980Sapatard@mandriva.com } 258f9b95980Sapatard@mandriva.com 259f9b95980Sapatard@mandriva.com return 0; 260f9b95980Sapatard@mandriva.com } 261f9b95980Sapatard@mandriva.com 262f9b95980Sapatard@mandriva.com static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream, 263f9b95980Sapatard@mandriva.com int cmd, struct snd_soc_dai *dai) 264f9b95980Sapatard@mandriva.com { 265f0fba2adSLiam Girdwood struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); 266f9b95980Sapatard@mandriva.com unsigned long value; 267f9b95980Sapatard@mandriva.com 268f9b95980Sapatard@mandriva.com value = readl(priv->io + KIRKWOOD_RECCTL); 269f9b95980Sapatard@mandriva.com 270f9b95980Sapatard@mandriva.com switch (cmd) { 271f9b95980Sapatard@mandriva.com case SNDRV_PCM_TRIGGER_START: 272f9b95980Sapatard@mandriva.com /* stop audio, enable interrupts */ 273f9b95980Sapatard@mandriva.com value = readl(priv->io + KIRKWOOD_RECCTL); 274f9b95980Sapatard@mandriva.com value |= KIRKWOOD_RECCTL_PAUSE; 275f9b95980Sapatard@mandriva.com writel(value, priv->io + KIRKWOOD_RECCTL); 276f9b95980Sapatard@mandriva.com 277f9b95980Sapatard@mandriva.com value = readl(priv->io + KIRKWOOD_INT_MASK); 278f9b95980Sapatard@mandriva.com value |= KIRKWOOD_INT_CAUSE_REC_BYTES; 279f9b95980Sapatard@mandriva.com writel(value, priv->io + KIRKWOOD_INT_MASK); 280f9b95980Sapatard@mandriva.com 281f9b95980Sapatard@mandriva.com /* configure audio & enable i2s record */ 282f9b95980Sapatard@mandriva.com value = readl(priv->io + KIRKWOOD_RECCTL); 283f9b95980Sapatard@mandriva.com value &= ~KIRKWOOD_RECCTL_BURST_MASK; 284f9b95980Sapatard@mandriva.com value &= ~KIRKWOOD_RECCTL_MONO; 285b424ec95Sarnaud.patard@rtp-net.org value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE 286b424ec95Sarnaud.patard@rtp-net.org | KIRKWOOD_RECCTL_SPDIF_EN); 287f9b95980Sapatard@mandriva.com 288f9b95980Sapatard@mandriva.com if (priv->burst == 32) 289f9b95980Sapatard@mandriva.com value |= KIRKWOOD_RECCTL_BURST_32; 290f9b95980Sapatard@mandriva.com else 291f9b95980Sapatard@mandriva.com value |= KIRKWOOD_RECCTL_BURST_128; 292f9b95980Sapatard@mandriva.com value |= KIRKWOOD_RECCTL_I2S_EN; 293f9b95980Sapatard@mandriva.com 294f9b95980Sapatard@mandriva.com writel(value, priv->io + KIRKWOOD_RECCTL); 295f9b95980Sapatard@mandriva.com break; 296f9b95980Sapatard@mandriva.com 297f9b95980Sapatard@mandriva.com case SNDRV_PCM_TRIGGER_STOP: 298f9b95980Sapatard@mandriva.com /* stop audio, disable interrupts */ 299f9b95980Sapatard@mandriva.com value = readl(priv->io + KIRKWOOD_RECCTL); 300b424ec95Sarnaud.patard@rtp-net.org value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE; 301f9b95980Sapatard@mandriva.com writel(value, priv->io + KIRKWOOD_RECCTL); 302f9b95980Sapatard@mandriva.com 303f9b95980Sapatard@mandriva.com value = readl(priv->io + KIRKWOOD_INT_MASK); 304f9b95980Sapatard@mandriva.com value &= ~KIRKWOOD_INT_CAUSE_REC_BYTES; 305f9b95980Sapatard@mandriva.com writel(value, priv->io + KIRKWOOD_INT_MASK); 306f9b95980Sapatard@mandriva.com 307f9b95980Sapatard@mandriva.com /* disable all records */ 308f9b95980Sapatard@mandriva.com value = readl(priv->io + KIRKWOOD_RECCTL); 309f9b95980Sapatard@mandriva.com value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN); 310f9b95980Sapatard@mandriva.com writel(value, priv->io + KIRKWOOD_RECCTL); 311f9b95980Sapatard@mandriva.com break; 312f9b95980Sapatard@mandriva.com 313f9b95980Sapatard@mandriva.com case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 314f9b95980Sapatard@mandriva.com case SNDRV_PCM_TRIGGER_SUSPEND: 315f9b95980Sapatard@mandriva.com value = readl(priv->io + KIRKWOOD_RECCTL); 316b424ec95Sarnaud.patard@rtp-net.org value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE; 317f9b95980Sapatard@mandriva.com writel(value, priv->io + KIRKWOOD_RECCTL); 318f9b95980Sapatard@mandriva.com break; 319f9b95980Sapatard@mandriva.com 320f9b95980Sapatard@mandriva.com case SNDRV_PCM_TRIGGER_RESUME: 321f9b95980Sapatard@mandriva.com case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 322f9b95980Sapatard@mandriva.com value = readl(priv->io + KIRKWOOD_RECCTL); 323b424ec95Sarnaud.patard@rtp-net.org value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE); 324f9b95980Sapatard@mandriva.com writel(value, priv->io + KIRKWOOD_RECCTL); 325f9b95980Sapatard@mandriva.com break; 326f9b95980Sapatard@mandriva.com 327f9b95980Sapatard@mandriva.com default: 328f9b95980Sapatard@mandriva.com return -EINVAL; 329f9b95980Sapatard@mandriva.com } 330f9b95980Sapatard@mandriva.com 331f9b95980Sapatard@mandriva.com return 0; 332f9b95980Sapatard@mandriva.com } 333f9b95980Sapatard@mandriva.com 334f9b95980Sapatard@mandriva.com static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd, 335f9b95980Sapatard@mandriva.com struct snd_soc_dai *dai) 336f9b95980Sapatard@mandriva.com { 337f9b95980Sapatard@mandriva.com if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 338f9b95980Sapatard@mandriva.com return kirkwood_i2s_play_trigger(substream, cmd, dai); 339f9b95980Sapatard@mandriva.com else 340f9b95980Sapatard@mandriva.com return kirkwood_i2s_rec_trigger(substream, cmd, dai); 341f9b95980Sapatard@mandriva.com 342f9b95980Sapatard@mandriva.com return 0; 343f9b95980Sapatard@mandriva.com } 344f9b95980Sapatard@mandriva.com 345f0fba2adSLiam Girdwood static int kirkwood_i2s_probe(struct snd_soc_dai *dai) 346f9b95980Sapatard@mandriva.com { 347f0fba2adSLiam Girdwood struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); 348f9b95980Sapatard@mandriva.com unsigned long value; 349f9b95980Sapatard@mandriva.com unsigned int reg_data; 350f9b95980Sapatard@mandriva.com 351f9b95980Sapatard@mandriva.com /* put system in a "safe" state : */ 352f9b95980Sapatard@mandriva.com /* disable audio interrupts */ 353f9b95980Sapatard@mandriva.com writel(0xffffffff, priv->io + KIRKWOOD_INT_CAUSE); 354f9b95980Sapatard@mandriva.com writel(0, priv->io + KIRKWOOD_INT_MASK); 355f9b95980Sapatard@mandriva.com 356f9b95980Sapatard@mandriva.com reg_data = readl(priv->io + 0x1200); 357f9b95980Sapatard@mandriva.com reg_data &= (~(0x333FF8)); 358f9b95980Sapatard@mandriva.com reg_data |= 0x111D18; 359f9b95980Sapatard@mandriva.com writel(reg_data, priv->io + 0x1200); 360f9b95980Sapatard@mandriva.com 361f9b95980Sapatard@mandriva.com msleep(500); 362f9b95980Sapatard@mandriva.com 363f9b95980Sapatard@mandriva.com reg_data = readl(priv->io + 0x1200); 364f9b95980Sapatard@mandriva.com reg_data &= (~(0x333FF8)); 365f9b95980Sapatard@mandriva.com reg_data |= 0x111D18; 366f9b95980Sapatard@mandriva.com writel(reg_data, priv->io + 0x1200); 367f9b95980Sapatard@mandriva.com 368f9b95980Sapatard@mandriva.com /* disable playback/record */ 369f9b95980Sapatard@mandriva.com value = readl(priv->io + KIRKWOOD_PLAYCTL); 370f9b95980Sapatard@mandriva.com value &= ~(KIRKWOOD_PLAYCTL_I2S_EN|KIRKWOOD_PLAYCTL_SPDIF_EN); 371f9b95980Sapatard@mandriva.com writel(value, priv->io + KIRKWOOD_PLAYCTL); 372f9b95980Sapatard@mandriva.com 373f9b95980Sapatard@mandriva.com value = readl(priv->io + KIRKWOOD_RECCTL); 374f9b95980Sapatard@mandriva.com value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN); 375f9b95980Sapatard@mandriva.com writel(value, priv->io + KIRKWOOD_RECCTL); 376f9b95980Sapatard@mandriva.com 377f9b95980Sapatard@mandriva.com return 0; 378f9b95980Sapatard@mandriva.com 379f9b95980Sapatard@mandriva.com } 380f9b95980Sapatard@mandriva.com 381f0fba2adSLiam Girdwood static int kirkwood_i2s_remove(struct snd_soc_dai *dai) 382f9b95980Sapatard@mandriva.com { 383f0fba2adSLiam Girdwood return 0; 384f9b95980Sapatard@mandriva.com } 385f9b95980Sapatard@mandriva.com 38685e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = { 387f0fba2adSLiam Girdwood .startup = kirkwood_i2s_startup, 388f9b95980Sapatard@mandriva.com .trigger = kirkwood_i2s_trigger, 389f9b95980Sapatard@mandriva.com .hw_params = kirkwood_i2s_hw_params, 390f9b95980Sapatard@mandriva.com .set_fmt = kirkwood_i2s_set_fmt, 391f9b95980Sapatard@mandriva.com }; 392f9b95980Sapatard@mandriva.com 393f9b95980Sapatard@mandriva.com 394f0fba2adSLiam Girdwood static struct snd_soc_dai_driver kirkwood_i2s_dai = { 395f9b95980Sapatard@mandriva.com .probe = kirkwood_i2s_probe, 396f9b95980Sapatard@mandriva.com .remove = kirkwood_i2s_remove, 397f9b95980Sapatard@mandriva.com .playback = { 398f9b95980Sapatard@mandriva.com .channels_min = 1, 399f9b95980Sapatard@mandriva.com .channels_max = 2, 400f9b95980Sapatard@mandriva.com .rates = KIRKWOOD_I2S_RATES, 401f9b95980Sapatard@mandriva.com .formats = KIRKWOOD_I2S_FORMATS,}, 402f9b95980Sapatard@mandriva.com .capture = { 403f9b95980Sapatard@mandriva.com .channels_min = 1, 404f9b95980Sapatard@mandriva.com .channels_max = 2, 405f9b95980Sapatard@mandriva.com .rates = KIRKWOOD_I2S_RATES, 406f9b95980Sapatard@mandriva.com .formats = KIRKWOOD_I2S_FORMATS,}, 407f9b95980Sapatard@mandriva.com .ops = &kirkwood_i2s_dai_ops, 408f9b95980Sapatard@mandriva.com }; 409f9b95980Sapatard@mandriva.com 410f9b95980Sapatard@mandriva.com static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev) 411f9b95980Sapatard@mandriva.com { 412f9b95980Sapatard@mandriva.com struct resource *mem; 413f9b95980Sapatard@mandriva.com struct kirkwood_asoc_platform_data *data = 414f9b95980Sapatard@mandriva.com pdev->dev.platform_data; 415f0fba2adSLiam Girdwood struct kirkwood_dma_data *priv; 416f9b95980Sapatard@mandriva.com int err; 417f9b95980Sapatard@mandriva.com 418f9b95980Sapatard@mandriva.com priv = kzalloc(sizeof(struct kirkwood_dma_data), GFP_KERNEL); 419f9b95980Sapatard@mandriva.com if (!priv) { 420f9b95980Sapatard@mandriva.com dev_err(&pdev->dev, "allocation failed\n"); 421f9b95980Sapatard@mandriva.com err = -ENOMEM; 422f9b95980Sapatard@mandriva.com goto error; 423f9b95980Sapatard@mandriva.com } 424f0fba2adSLiam Girdwood dev_set_drvdata(&pdev->dev, priv); 425f9b95980Sapatard@mandriva.com 426f9b95980Sapatard@mandriva.com mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 427f9b95980Sapatard@mandriva.com if (!mem) { 428f9b95980Sapatard@mandriva.com dev_err(&pdev->dev, "platform_get_resource failed\n"); 429f9b95980Sapatard@mandriva.com err = -ENXIO; 430f9b95980Sapatard@mandriva.com goto err_alloc; 431f9b95980Sapatard@mandriva.com } 432f9b95980Sapatard@mandriva.com 433f9b95980Sapatard@mandriva.com priv->mem = request_mem_region(mem->start, SZ_16K, DRV_NAME); 434f9b95980Sapatard@mandriva.com if (!priv->mem) { 435f9b95980Sapatard@mandriva.com dev_err(&pdev->dev, "request_mem_region failed\n"); 436f9b95980Sapatard@mandriva.com err = -EBUSY; 4375013951bSArnd Bergmann goto err_alloc; 438f9b95980Sapatard@mandriva.com } 439f9b95980Sapatard@mandriva.com 440f9b95980Sapatard@mandriva.com priv->io = ioremap(priv->mem->start, SZ_16K); 441f9b95980Sapatard@mandriva.com if (!priv->io) { 442f9b95980Sapatard@mandriva.com dev_err(&pdev->dev, "ioremap failed\n"); 443f9b95980Sapatard@mandriva.com err = -ENOMEM; 444f9b95980Sapatard@mandriva.com goto err_iomem; 445f9b95980Sapatard@mandriva.com } 446f9b95980Sapatard@mandriva.com 447f9b95980Sapatard@mandriva.com priv->irq = platform_get_irq(pdev, 0); 448f9b95980Sapatard@mandriva.com if (priv->irq <= 0) { 449f9b95980Sapatard@mandriva.com dev_err(&pdev->dev, "platform_get_irq failed\n"); 450f9b95980Sapatard@mandriva.com err = -ENXIO; 451f9b95980Sapatard@mandriva.com goto err_ioremap; 452f9b95980Sapatard@mandriva.com } 453f9b95980Sapatard@mandriva.com 454d4d9820bSAxel Lin if (!data) { 455f9b95980Sapatard@mandriva.com dev_err(&pdev->dev, "no platform data ?!\n"); 456f9b95980Sapatard@mandriva.com err = -EINVAL; 457f9b95980Sapatard@mandriva.com goto err_ioremap; 458f9b95980Sapatard@mandriva.com } 459f9b95980Sapatard@mandriva.com 460f9b95980Sapatard@mandriva.com priv->burst = data->burst; 461f9b95980Sapatard@mandriva.com 462e919c716SAndrew Lunn priv->clk = clk_get(&pdev->dev, NULL); 463e919c716SAndrew Lunn if (IS_ERR(priv->clk)) { 464e919c716SAndrew Lunn dev_err(&pdev->dev, "no clock\n"); 465e919c716SAndrew Lunn err = PTR_ERR(priv->clk); 466e919c716SAndrew Lunn goto err_ioremap; 467e919c716SAndrew Lunn } 468e919c716SAndrew Lunn clk_prepare_enable(priv->clk); 469e919c716SAndrew Lunn 470baffab28SSimon Baatz err = snd_soc_register_dai(&pdev->dev, &kirkwood_i2s_dai); 471baffab28SSimon Baatz if (!err) 472baffab28SSimon Baatz return 0; 473baffab28SSimon Baatz dev_err(&pdev->dev, "snd_soc_register_dai failed\n"); 474baffab28SSimon Baatz 475baffab28SSimon Baatz clk_disable_unprepare(priv->clk); 476baffab28SSimon Baatz clk_put(priv->clk); 477f9b95980Sapatard@mandriva.com 478f9b95980Sapatard@mandriva.com err_ioremap: 479f9b95980Sapatard@mandriva.com iounmap(priv->io); 480f9b95980Sapatard@mandriva.com err_iomem: 481f9b95980Sapatard@mandriva.com release_mem_region(priv->mem->start, SZ_16K); 482f9b95980Sapatard@mandriva.com err_alloc: 483f9b95980Sapatard@mandriva.com kfree(priv); 484f9b95980Sapatard@mandriva.com error: 485f9b95980Sapatard@mandriva.com return err; 486f9b95980Sapatard@mandriva.com } 487f9b95980Sapatard@mandriva.com 488f9b95980Sapatard@mandriva.com static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev) 489f9b95980Sapatard@mandriva.com { 490f0fba2adSLiam Girdwood struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev); 491f0fba2adSLiam Girdwood 492f0fba2adSLiam Girdwood snd_soc_unregister_dai(&pdev->dev); 493e919c716SAndrew Lunn 494e919c716SAndrew Lunn clk_disable_unprepare(priv->clk); 495e919c716SAndrew Lunn clk_put(priv->clk); 496e919c716SAndrew Lunn 497f9b95980Sapatard@mandriva.com iounmap(priv->io); 498f9b95980Sapatard@mandriva.com release_mem_region(priv->mem->start, SZ_16K); 499f9b95980Sapatard@mandriva.com kfree(priv); 500f0fba2adSLiam Girdwood 501f9b95980Sapatard@mandriva.com return 0; 502f9b95980Sapatard@mandriva.com } 503f9b95980Sapatard@mandriva.com 504f9b95980Sapatard@mandriva.com static struct platform_driver kirkwood_i2s_driver = { 505f9b95980Sapatard@mandriva.com .probe = kirkwood_i2s_dev_probe, 50648860e40SAxel Lin .remove = __devexit_p(kirkwood_i2s_dev_remove), 507f9b95980Sapatard@mandriva.com .driver = { 508f9b95980Sapatard@mandriva.com .name = DRV_NAME, 509f9b95980Sapatard@mandriva.com .owner = THIS_MODULE, 510f9b95980Sapatard@mandriva.com }, 511f9b95980Sapatard@mandriva.com }; 512f9b95980Sapatard@mandriva.com 51341b10225SAxel Lin module_platform_driver(kirkwood_i2s_driver); 514f9b95980Sapatard@mandriva.com 515f9b95980Sapatard@mandriva.com /* Module information */ 51669737897SArnaud Patard (Rtp) MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>"); 517f9b95980Sapatard@mandriva.com MODULE_DESCRIPTION("Kirkwood I2S SoC Interface"); 518f9b95980Sapatard@mandriva.com MODULE_LICENSE("GPL"); 519f9b95980Sapatard@mandriva.com MODULE_ALIAS("platform:kirkwood-i2s"); 520