linux/sound/soc/pxa/pxa2xx-i2s.c
<<
>>
Prefs
   1/*
   2 * pxa2xx-i2s.c  --  ALSA Soc Audio Layer
   3 *
   4 * Copyright 2005 Wolfson Microelectronics PLC.
   5 * Author: Liam Girdwood
   6 *         lrg@slimlogic.co.uk
   7 *
   8 *  This program is free software; you can redistribute  it and/or modify it
   9 *  under  the terms of  the GNU General  Public License as published by the
  10 *  Free Software Foundation;  either version 2 of the  License, or (at your
  11 *  option) any later version.
  12 */
  13
  14#include <linux/init.h>
  15#include <linux/module.h>
  16#include <linux/device.h>
  17#include <linux/delay.h>
  18#include <linux/clk.h>
  19#include <linux/platform_device.h>
  20#include <linux/io.h>
  21#include <sound/core.h>
  22#include <sound/pcm.h>
  23#include <sound/initval.h>
  24#include <sound/soc.h>
  25#include <sound/pxa2xx-lib.h>
  26
  27#include <mach/hardware.h>
  28#include <mach/dma.h>
  29#include <mach/audio.h>
  30
  31#include "pxa2xx-i2s.h"
  32
  33/*
  34 * I2S Controller Register and Bit Definitions
  35 */
  36#define SACR0           __REG(0x40400000)  /* Global Control Register */
  37#define SACR1           __REG(0x40400004)  /* Serial Audio I 2 S/MSB-Justified Control Register */
  38#define SASR0           __REG(0x4040000C)  /* Serial Audio I 2 S/MSB-Justified Interface and FIFO Status Register */
  39#define SAIMR           __REG(0x40400014)  /* Serial Audio Interrupt Mask Register */
  40#define SAICR           __REG(0x40400018)  /* Serial Audio Interrupt Clear Register */
  41#define SADIV           __REG(0x40400060)  /* Audio Clock Divider Register. */
  42#define SADR            __REG(0x40400080)  /* Serial Audio Data Register (TX and RX FIFO access Register). */
  43
  44#define SACR0_RFTH(x)   ((x) << 12)     /* Rx FIFO Interrupt or DMA Trigger Threshold */
  45#define SACR0_TFTH(x)   ((x) << 8)      /* Tx FIFO Interrupt or DMA Trigger Threshold */
  46#define SACR0_STRF      (1 << 5)        /* FIFO Select for EFWR Special Function */
  47#define SACR0_EFWR      (1 << 4)        /* Enable EFWR Function  */
  48#define SACR0_RST       (1 << 3)        /* FIFO, i2s Register Reset */
  49#define SACR0_BCKD      (1 << 2)        /* Bit Clock Direction */
  50#define SACR0_ENB       (1 << 0)        /* Enable I2S Link */
  51#define SACR1_ENLBF     (1 << 5)        /* Enable Loopback */
  52#define SACR1_DRPL      (1 << 4)        /* Disable Replaying Function */
  53#define SACR1_DREC      (1 << 3)        /* Disable Recording Function */
  54#define SACR1_AMSL      (1 << 0)        /* Specify Alternate Mode */
  55
  56#define SASR0_I2SOFF    (1 << 7)        /* Controller Status */
  57#define SASR0_ROR       (1 << 6)        /* Rx FIFO Overrun */
  58#define SASR0_TUR       (1 << 5)        /* Tx FIFO Underrun */
  59#define SASR0_RFS       (1 << 4)        /* Rx FIFO Service Request */
  60#define SASR0_TFS       (1 << 3)        /* Tx FIFO Service Request */
  61#define SASR0_BSY       (1 << 2)        /* I2S Busy */
  62#define SASR0_RNE       (1 << 1)        /* Rx FIFO Not Empty */
  63#define SASR0_TNF       (1 << 0)        /* Tx FIFO Not Empty */
  64
  65#define SAICR_ROR       (1 << 6)        /* Clear Rx FIFO Overrun Interrupt */
  66#define SAICR_TUR       (1 << 5)        /* Clear Tx FIFO Underrun Interrupt */
  67
  68#define SAIMR_ROR       (1 << 6)        /* Enable Rx FIFO Overrun Condition Interrupt */
  69#define SAIMR_TUR       (1 << 5)        /* Enable Tx FIFO Underrun Condition Interrupt */
  70#define SAIMR_RFS       (1 << 4)        /* Enable Rx FIFO Service Interrupt */
  71#define SAIMR_TFS       (1 << 3)        /* Enable Tx FIFO Service Interrupt */
  72
  73struct pxa_i2s_port {
  74        u32 sadiv;
  75        u32 sacr0;
  76        u32 sacr1;
  77        u32 saimr;
  78        int master;
  79        u32 fmt;
  80};
  81static struct pxa_i2s_port pxa_i2s;
  82static struct clk *clk_i2s;
  83static int clk_ena = 0;
  84
  85static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = {
  86        .name                   = "I2S PCM Stereo out",
  87        .dev_addr               = __PREG(SADR),
  88        .drcmr                  = &DRCMR(3),
  89        .dcmd                   = DCMD_INCSRCADDR | DCMD_FLOWTRG |
  90                                  DCMD_BURST32 | DCMD_WIDTH4,
  91};
  92
  93static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_in = {
  94        .name                   = "I2S PCM Stereo in",
  95        .dev_addr               = __PREG(SADR),
  96        .drcmr                  = &DRCMR(2),
  97        .dcmd                   = DCMD_INCTRGADDR | DCMD_FLOWSRC |
  98                                  DCMD_BURST32 | DCMD_WIDTH4,
  99};
 100
 101static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream,
 102                              struct snd_soc_dai *dai)
 103{
 104        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 105        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 106
 107        if (IS_ERR(clk_i2s))
 108                return PTR_ERR(clk_i2s);
 109
 110        if (!cpu_dai->active)
 111                SACR0 = 0;
 112
 113        return 0;
 114}
 115
 116/* wait for I2S controller to be ready */
 117static int pxa_i2s_wait(void)
 118{
 119        int i;
 120
 121        /* flush the Rx FIFO */
 122        for(i = 0; i < 16; i++)
 123                SADR;
 124        return 0;
 125}
 126
 127static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 128                unsigned int fmt)
 129{
 130        /* interface format */
 131        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 132        case SND_SOC_DAIFMT_I2S:
 133                pxa_i2s.fmt = 0;
 134                break;
 135        case SND_SOC_DAIFMT_LEFT_J:
 136                pxa_i2s.fmt = SACR1_AMSL;
 137                break;
 138        }
 139
 140        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 141        case SND_SOC_DAIFMT_CBS_CFS:
 142                pxa_i2s.master = 1;
 143                break;
 144        case SND_SOC_DAIFMT_CBM_CFS:
 145                pxa_i2s.master = 0;
 146                break;
 147        default:
 148                break;
 149        }
 150        return 0;
 151}
 152
 153static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
 154                int clk_id, unsigned int freq, int dir)
 155{
 156        if (clk_id != PXA2XX_I2S_SYSCLK)
 157                return -ENODEV;
 158
 159        return 0;
 160}
 161
 162static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
 163                                struct snd_pcm_hw_params *params,
 164                                struct snd_soc_dai *dai)
 165{
 166        struct pxa2xx_pcm_dma_params *dma_data;
 167
 168        BUG_ON(IS_ERR(clk_i2s));
 169        clk_prepare_enable(clk_i2s);
 170        clk_ena = 1;
 171        pxa_i2s_wait();
 172
 173        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 174                dma_data = &pxa2xx_i2s_pcm_stereo_out;
 175        else
 176                dma_data = &pxa2xx_i2s_pcm_stereo_in;
 177
 178        snd_soc_dai_set_dma_data(dai, substream, dma_data);
 179
 180        /* is port used by another stream */
 181        if (!(SACR0 & SACR0_ENB)) {
 182                SACR0 = 0;
 183                if (pxa_i2s.master)
 184                        SACR0 |= SACR0_BCKD;
 185
 186                SACR0 |= SACR0_RFTH(14) | SACR0_TFTH(1);
 187                SACR1 |= pxa_i2s.fmt;
 188        }
 189        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 190                SAIMR |= SAIMR_TFS;
 191        else
 192                SAIMR |= SAIMR_RFS;
 193
 194        switch (params_rate(params)) {
 195        case 8000:
 196                SADIV = 0x48;
 197                break;
 198        case 11025:
 199                SADIV = 0x34;
 200                break;
 201        case 16000:
 202                SADIV = 0x24;
 203                break;
 204        case 22050:
 205                SADIV = 0x1a;
 206                break;
 207        case 44100:
 208                SADIV = 0xd;
 209                break;
 210        case 48000:
 211                SADIV = 0xc;
 212                break;
 213        case 96000: /* not in manual and possibly slightly inaccurate */
 214                SADIV = 0x6;
 215                break;
 216        }
 217
 218        return 0;
 219}
 220
 221static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
 222                              struct snd_soc_dai *dai)
 223{
 224        int ret = 0;
 225
 226        switch (cmd) {
 227        case SNDRV_PCM_TRIGGER_START:
 228                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 229                        SACR1 &= ~SACR1_DRPL;
 230                else
 231                        SACR1 &= ~SACR1_DREC;
 232                SACR0 |= SACR0_ENB;
 233                break;
 234        case SNDRV_PCM_TRIGGER_RESUME:
 235        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 236        case SNDRV_PCM_TRIGGER_STOP:
 237        case SNDRV_PCM_TRIGGER_SUSPEND:
 238        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 239                break;
 240        default:
 241                ret = -EINVAL;
 242        }
 243
 244        return ret;
 245}
 246
 247static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream,
 248                                struct snd_soc_dai *dai)
 249{
 250        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 251                SACR1 |= SACR1_DRPL;
 252                SAIMR &= ~SAIMR_TFS;
 253        } else {
 254                SACR1 |= SACR1_DREC;
 255                SAIMR &= ~SAIMR_RFS;
 256        }
 257
 258        if ((SACR1 & (SACR1_DREC | SACR1_DRPL)) == (SACR1_DREC | SACR1_DRPL)) {
 259                SACR0 &= ~SACR0_ENB;
 260                pxa_i2s_wait();
 261                if (clk_ena) {
 262                        clk_disable_unprepare(clk_i2s);
 263                        clk_ena = 0;
 264                }
 265        }
 266}
 267
 268#ifdef CONFIG_PM
 269static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai)
 270{
 271        /* store registers */
 272        pxa_i2s.sacr0 = SACR0;
 273        pxa_i2s.sacr1 = SACR1;
 274        pxa_i2s.saimr = SAIMR;
 275        pxa_i2s.sadiv = SADIV;
 276
 277        /* deactivate link */
 278        SACR0 &= ~SACR0_ENB;
 279        pxa_i2s_wait();
 280        return 0;
 281}
 282
 283static int pxa2xx_i2s_resume(struct snd_soc_dai *dai)
 284{
 285        pxa_i2s_wait();
 286
 287        SACR0 = pxa_i2s.sacr0 & ~SACR0_ENB;
 288        SACR1 = pxa_i2s.sacr1;
 289        SAIMR = pxa_i2s.saimr;
 290        SADIV = pxa_i2s.sadiv;
 291
 292        SACR0 = pxa_i2s.sacr0;
 293
 294        return 0;
 295}
 296
 297#else
 298#define pxa2xx_i2s_suspend      NULL
 299#define pxa2xx_i2s_resume       NULL
 300#endif
 301
 302static int pxa2xx_i2s_probe(struct snd_soc_dai *dai)
 303{
 304        clk_i2s = clk_get(dai->dev, "I2SCLK");
 305        if (IS_ERR(clk_i2s))
 306                return PTR_ERR(clk_i2s);
 307
 308        /*
 309         * PXA Developer's Manual:
 310         * If SACR0[ENB] is toggled in the middle of a normal operation,
 311         * the SACR0[RST] bit must also be set and cleared to reset all
 312         * I2S controller registers.
 313         */
 314        SACR0 = SACR0_RST;
 315        SACR0 = 0;
 316        /* Make sure RPL and REC are disabled */
 317        SACR1 = SACR1_DRPL | SACR1_DREC;
 318        /* Along with FIFO servicing */
 319        SAIMR &= ~(SAIMR_RFS | SAIMR_TFS);
 320
 321        return 0;
 322}
 323
 324static int  pxa2xx_i2s_remove(struct snd_soc_dai *dai)
 325{
 326        clk_put(clk_i2s);
 327        clk_i2s = ERR_PTR(-ENOENT);
 328        return 0;
 329}
 330
 331#define PXA2XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
 332                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
 333                SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
 334
 335static const struct snd_soc_dai_ops pxa_i2s_dai_ops = {
 336        .startup        = pxa2xx_i2s_startup,
 337        .shutdown       = pxa2xx_i2s_shutdown,
 338        .trigger        = pxa2xx_i2s_trigger,
 339        .hw_params      = pxa2xx_i2s_hw_params,
 340        .set_fmt        = pxa2xx_i2s_set_dai_fmt,
 341        .set_sysclk     = pxa2xx_i2s_set_dai_sysclk,
 342};
 343
 344static struct snd_soc_dai_driver pxa_i2s_dai = {
 345        .probe = pxa2xx_i2s_probe,
 346        .remove = pxa2xx_i2s_remove,
 347        .suspend = pxa2xx_i2s_suspend,
 348        .resume = pxa2xx_i2s_resume,
 349        .playback = {
 350                .channels_min = 2,
 351                .channels_max = 2,
 352                .rates = PXA2XX_I2S_RATES,
 353                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
 354        .capture = {
 355                .channels_min = 2,
 356                .channels_max = 2,
 357                .rates = PXA2XX_I2S_RATES,
 358                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
 359        .ops = &pxa_i2s_dai_ops,
 360        .symmetric_rates = 1,
 361};
 362
 363static const struct snd_soc_component_driver pxa_i2s_component = {
 364        .name           = "pxa-i2s",
 365};
 366
 367static int pxa2xx_i2s_drv_probe(struct platform_device *pdev)
 368{
 369        return snd_soc_register_component(&pdev->dev, &pxa_i2s_component,
 370                                          &pxa_i2s_dai, 1);
 371}
 372
 373static int pxa2xx_i2s_drv_remove(struct platform_device *pdev)
 374{
 375        snd_soc_unregister_component(&pdev->dev);
 376        return 0;
 377}
 378
 379static struct platform_driver pxa2xx_i2s_driver = {
 380        .probe = pxa2xx_i2s_drv_probe,
 381        .remove = pxa2xx_i2s_drv_remove,
 382
 383        .driver = {
 384                .name = "pxa2xx-i2s",
 385                .owner = THIS_MODULE,
 386        },
 387};
 388
 389static int __init pxa2xx_i2s_init(void)
 390{
 391        clk_i2s = ERR_PTR(-ENOENT);
 392        return platform_driver_register(&pxa2xx_i2s_driver);
 393}
 394
 395static void __exit pxa2xx_i2s_exit(void)
 396{
 397        platform_driver_unregister(&pxa2xx_i2s_driver);
 398}
 399
 400module_init(pxa2xx_i2s_init);
 401module_exit(pxa2xx_i2s_exit);
 402
 403/* Module information */
 404MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
 405MODULE_DESCRIPTION("pxa2xx I2S SoC Interface");
 406MODULE_LICENSE("GPL");
 407MODULE_ALIAS("platform:pxa2xx-i2s");
 408