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