]> Pileus Git - ~andy/linux/blobdiff - sound/soc/pxa/pxa2xx-i2s.c
Merge phase #4 (X2APIC, APIC unification, CPU identification unification) of git...
[~andy/linux] / sound / soc / pxa / pxa2xx-i2s.c
index 8548818eea085f0b89be4721a296431de5f52795..2fb58298513b32c88e5cf2f74184db37a883d163 100644 (file)
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
+#include <linux/platform_device.h>
 #include <sound/core.h>
 #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 "pxa2xx-pcm.h"
 #include "pxa2xx-i2s.h"
 
+struct pxa2xx_gpio {
+       u32 sys;
+       u32     rx;
+       u32 tx;
+       u32 clk;
+       u32 frm;
+};
+
+/*
+ * 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;
@@ -43,7 +93,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,
 };
@@ -51,7 +101,7 @@ 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,
 };
@@ -64,11 +114,6 @@ static struct pxa2xx_gpio gpio_bus[] = {
                .frm = GPIO31_SYNC_I2S_MD,
        },
        { /* I2S SoC Master */
-#ifdef CONFIG_PXA27x
-               .sys = GPIO113_I2S_SYSCLK_MD,
-#else
-               .sys = GPIO32_SYSCLK_I2S_MD,
-#endif
                .rx = GPIO29_SDATA_IN_I2S_MD,
                .tx = GPIO30_SDATA_OUT_I2S_MD,
                .clk = GPIO28_BITCLK_OUT_I2S_MD,
@@ -81,7 +126,6 @@ static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream)
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 
-       clk_i2s = clk_get(NULL, "I2SCLK");
        if (IS_ERR(clk_i2s))
                return PTR_ERR(clk_i2s);
 
@@ -152,6 +196,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
        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();
 
@@ -317,6 +362,48 @@ struct snd_soc_dai pxa_i2s_dai = {
 
 EXPORT_SYMBOL_GPL(pxa_i2s_dai);
 
+static int pxa2xx_i2s_probe(struct platform_device *dev)
+{
+       clk_i2s = clk_get(&dev->dev, "I2SCLK");
+       return IS_ERR(clk_i2s) ? PTR_ERR(clk_i2s) : 0;
+}
+
+static int __devexit pxa2xx_i2s_remove(struct platform_device *dev)
+{
+       clk_put(clk_i2s);
+       clk_i2s = ERR_PTR(-ENOENT);
+       return 0;
+}
+
+static struct platform_driver pxa2xx_i2s_driver = {
+       .probe = pxa2xx_i2s_probe,
+       .remove = __devexit_p(pxa2xx_i2s_remove),
+
+       .driver = {
+               .name = "pxa2xx-i2s",
+               .owner = THIS_MODULE,
+       },
+};
+
+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);
+}
+
+static void __exit pxa2xx_i2s_exit(void)
+{
+       platform_driver_unregister(&pxa2xx_i2s_driver);
+}
+
+module_init(pxa2xx_i2s_init);
+module_exit(pxa2xx_i2s_exit);
+
 /* Module information */
 MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
 MODULE_DESCRIPTION("pxa2xx I2S SoC Interface");