ASoC: pxa-ssp: Use 16-bit DMA for magician stereo
[safe/jmp/linux-2.6] / sound / soc / pxa / pxa2xx-i2s.c
index 21ca3fe..e6c2440 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright 2005 Wolfson Microelectronics PLC.
  * Author: Liam Girdwood
- *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
+ *         lrg@slimlogic.co.uk
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  under  the terms of  the GNU General  Public License as published by the
 #include <sound/pcm.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
+#include <sound/pxa2xx-lib.h>
 
 #include <mach/hardware.h>
 #include <mach/pxa-regs.h>
-#include <mach/pxa2xx-gpio.h>
 #include <mach/audio.h>
 
 #include "pxa2xx-pcm.h"
 #include "pxa2xx-i2s.h"
 
+/*
+ * I2S Controller Register and Bit Definitions
+ */
+#define SACR0          __REG(0x40400000)  /* Global Control Register */
+#define SACR1          __REG(0x40400004)  /* Serial Audio I 2 S/MSB-Justified Control Register */
+#define SASR0          __REG(0x4040000C)  /* Serial Audio I 2 S/MSB-Justified Interface and FIFO Status Register */
+#define SAIMR          __REG(0x40400014)  /* Serial Audio Interrupt Mask Register */
+#define SAICR          __REG(0x40400018)  /* Serial Audio Interrupt Clear Register */
+#define SADIV          __REG(0x40400060)  /* Audio Clock Divider Register. */
+#define SADR           __REG(0x40400080)  /* Serial Audio Data Register (TX and RX FIFO access Register). */
+
+#define SACR0_RFTH(x)  ((x) << 12)     /* Rx FIFO Interrupt or DMA Trigger Threshold */
+#define SACR0_TFTH(x)  ((x) << 8)      /* Tx FIFO Interrupt or DMA Trigger Threshold */
+#define SACR0_STRF     (1 << 5)        /* FIFO Select for EFWR Special Function */
+#define SACR0_EFWR     (1 << 4)        /* Enable EFWR Function  */
+#define SACR0_RST      (1 << 3)        /* FIFO, i2s Register Reset */
+#define SACR0_BCKD     (1 << 2)        /* Bit Clock Direction */
+#define SACR0_ENB      (1 << 0)        /* Enable I2S Link */
+#define SACR1_ENLBF    (1 << 5)        /* Enable Loopback */
+#define SACR1_DRPL     (1 << 4)        /* Disable Replaying Function */
+#define SACR1_DREC     (1 << 3)        /* Disable Recording Function */
+#define SACR1_AMSL     (1 << 0)        /* Specify Alternate Mode */
+
+#define SASR0_I2SOFF   (1 << 7)        /* Controller Status */
+#define SASR0_ROR      (1 << 6)        /* Rx FIFO Overrun */
+#define SASR0_TUR      (1 << 5)        /* Tx FIFO Underrun */
+#define SASR0_RFS      (1 << 4)        /* Rx FIFO Service Request */
+#define SASR0_TFS      (1 << 3)        /* Tx FIFO Service Request */
+#define SASR0_BSY      (1 << 2)        /* I2S Busy */
+#define SASR0_RNE      (1 << 1)        /* Rx FIFO Not Empty */
+#define SASR0_TNF      (1 << 0)        /* Tx FIFO Not Empty */
+
+#define SAICR_ROR      (1 << 6)        /* Clear Rx FIFO Overrun Interrupt */
+#define SAICR_TUR      (1 << 5)        /* Clear Tx FIFO Underrun Interrupt */
+
+#define SAIMR_ROR      (1 << 6)        /* Enable Rx FIFO Overrun Condition Interrupt */
+#define SAIMR_TUR      (1 << 5)        /* Enable Tx FIFO Underrun Condition Interrupt */
+#define SAIMR_RFS      (1 << 4)        /* Enable Rx FIFO Service Interrupt */
+#define SAIMR_TFS      (1 << 3)        /* Enable Tx FIFO Service Interrupt */
+
 struct pxa_i2s_port {
        u32 sadiv;
        u32 sacr0;
@@ -44,7 +84,7 @@ static struct clk *clk_i2s;
 static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = {
        .name                   = "I2S PCM Stereo out",
        .dev_addr               = __PREG(SADR),
-       .drcmr                  = &DRCMRTXSADR,
+       .drcmr                  = &DRCMR(3),
        .dcmd                   = DCMD_INCSRCADDR | DCMD_FLOWTRG |
                                  DCMD_BURST32 | DCMD_WIDTH4,
 };
@@ -52,27 +92,13 @@ static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = {
 static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_in = {
        .name                   = "I2S PCM Stereo in",
        .dev_addr               = __PREG(SADR),
-       .drcmr                  = &DRCMRRXSADR,
+       .drcmr                  = &DRCMR(2),
        .dcmd                   = DCMD_INCTRGADDR | DCMD_FLOWSRC |
                                  DCMD_BURST32 | DCMD_WIDTH4,
 };
 
-static struct pxa2xx_gpio gpio_bus[] = {
-       { /* I2S SoC Slave */
-               .rx = GPIO29_SDATA_IN_I2S_MD,
-               .tx = GPIO30_SDATA_OUT_I2S_MD,
-               .clk = GPIO28_BITCLK_IN_I2S_MD,
-               .frm = GPIO31_SYNC_I2S_MD,
-       },
-       { /* I2S SoC Master */
-               .rx = GPIO29_SDATA_IN_I2S_MD,
-               .tx = GPIO30_SDATA_OUT_I2S_MD,
-               .clk = GPIO28_BITCLK_OUT_I2S_MD,
-               .frm = GPIO31_SYNC_I2S_MD,
-       },
-};
-
-static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream)
+static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream,
+                             struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
@@ -131,22 +157,16 @@ static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        if (clk_id != PXA2XX_I2S_SYSCLK)
                return -ENODEV;
 
-       if (pxa_i2s.master && dir == SND_SOC_CLOCK_OUT)
-               pxa_gpio_mode(gpio_bus[pxa_i2s.master].sys);
-
        return 0;
 }
 
 static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *params)
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
-       pxa_gpio_mode(gpio_bus[pxa_i2s.master].rx);
-       pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx);
-       pxa_gpio_mode(gpio_bus[pxa_i2s.master].frm);
-       pxa_gpio_mode(gpio_bus[pxa_i2s.master].clk);
        BUG_ON(IS_ERR(clk_i2s));
        clk_enable(clk_i2s);
        pxa_i2s_wait();
@@ -199,7 +219,8 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
+static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+                             struct snd_soc_dai *dai)
 {
        int ret = 0;
 
@@ -220,7 +241,8 @@ static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
        return ret;
 }
 
-static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream)
+static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
 {
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                SACR1 |= SACR1_DRPL;
@@ -240,8 +262,7 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream)
 }
 
 #ifdef CONFIG_PM
-static int pxa2xx_i2s_suspend(struct platform_device *dev,
-       struct snd_soc_dai *dai)
+static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai)
 {
        if (!dai->active)
                return 0;
@@ -258,8 +279,7 @@ static int pxa2xx_i2s_suspend(struct platform_device *dev,
        return 0;
 }
 
-static int pxa2xx_i2s_resume(struct platform_device *pdev,
-       struct snd_soc_dai *dai)
+static int pxa2xx_i2s_resume(struct snd_soc_dai *dai)
 {
        if (!dai->active)
                return 0;
@@ -284,10 +304,18 @@ static int pxa2xx_i2s_resume(struct platform_device *pdev,
                SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
                SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
 
+static struct snd_soc_dai_ops pxa_i2s_dai_ops = {
+       .startup        = pxa2xx_i2s_startup,
+       .shutdown       = pxa2xx_i2s_shutdown,
+       .trigger        = pxa2xx_i2s_trigger,
+       .hw_params      = pxa2xx_i2s_hw_params,
+       .set_fmt        = pxa2xx_i2s_set_dai_fmt,
+       .set_sysclk     = pxa2xx_i2s_set_dai_sysclk,
+};
+
 struct snd_soc_dai pxa_i2s_dai = {
        .name = "pxa2xx-i2s",
        .id = 0,
-       .type = SND_SOC_DAI_I2S,
        .suspend = pxa2xx_i2s_suspend,
        .resume = pxa2xx_i2s_resume,
        .playback = {
@@ -300,27 +328,30 @@ struct snd_soc_dai pxa_i2s_dai = {
                .channels_max = 2,
                .rates = PXA2XX_I2S_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = {
-               .startup = pxa2xx_i2s_startup,
-               .shutdown = pxa2xx_i2s_shutdown,
-               .trigger = pxa2xx_i2s_trigger,
-               .hw_params = pxa2xx_i2s_hw_params,},
-       .dai_ops = {
-               .set_fmt = pxa2xx_i2s_set_dai_fmt,
-               .set_sysclk = pxa2xx_i2s_set_dai_sysclk,
-       },
+       .ops = &pxa_i2s_dai_ops,
 };
 
 EXPORT_SYMBOL_GPL(pxa_i2s_dai);
 
 static int pxa2xx_i2s_probe(struct platform_device *dev)
 {
+       int ret;
+
        clk_i2s = clk_get(&dev->dev, "I2SCLK");
-       return IS_ERR(clk_i2s) ? PTR_ERR(clk_i2s) : 0;
+       if (IS_ERR(clk_i2s))
+               return PTR_ERR(clk_i2s);
+
+       pxa_i2s_dai.dev = &dev->dev;
+       ret = snd_soc_register_dai(&pxa_i2s_dai);
+       if (ret != 0)
+               clk_put(clk_i2s);
+
+       return ret;
 }
 
 static int __devexit pxa2xx_i2s_remove(struct platform_device *dev)
 {
+       snd_soc_unregister_dai(&pxa_i2s_dai);
        clk_put(clk_i2s);
        clk_i2s = ERR_PTR(-ENOENT);
        return 0;
@@ -338,11 +369,6 @@ static struct platform_driver pxa2xx_i2s_driver = {
 
 static int __init pxa2xx_i2s_init(void)
 {
-       if (cpu_is_pxa27x())
-               gpio_bus[1].sys = GPIO113_I2S_SYSCLK_MD;
-       else
-               gpio_bus[1].sys = GPIO32_SYSCLK_I2S_MD;
-
        clk_i2s = ERR_PTR(-ENOENT);
        return platform_driver_register(&pxa2xx_i2s_driver);
 }
@@ -356,6 +382,6 @@ module_init(pxa2xx_i2s_init);
 module_exit(pxa2xx_i2s_exit);
 
 /* Module information */
-MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
 MODULE_DESCRIPTION("pxa2xx I2S SoC Interface");
 MODULE_LICENSE("GPL");