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