[ARM] 5210/2: AFEB9260: board support
[safe/jmp/linux-2.6] / arch / arm / mach-pxa / ssp.c
index be6fee7..9bd93c5 100644 (file)
  *  IO-based SSP applications and allows easy port setup for DMA access.
  *
  *  Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
- *
- *  Revision history:
- *   22nd Aug 2003 Initial version.
- *   20th Dec 2004 Added ssp_config for changing port config without
- *                 closing the port.
- *    4th Aug 2005 Added option to disable irq handler registration and
- *                 cleaned up irq and clock detection.
  */
 
 #include <linux/module.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/hardware.h>
-#include <asm/arch/ssp.h>
-#include <asm/arch/pxa-regs.h>
+#include <mach/hardware.h>
+#include <mach/ssp.h>
+#include <mach/pxa-regs.h>
+#include <mach/regs-ssp.h>
 
 #define TIMEOUT 100000
 
 static irqreturn_t ssp_interrupt(int irq, void *dev_id)
 {
-       struct ssp_dev *dev = (struct ssp_dev*) dev_id;
-       unsigned int status = SSSR_P(dev->port);
+       struct ssp_dev *dev = dev_id;
+       struct ssp_device *ssp = dev->ssp;
+       unsigned int status;
 
-       SSSR_P(dev->port) = status; /* clear status bits */
+       status = __raw_readl(ssp->mmio_base + SSSR);
+       __raw_writel(status, ssp->mmio_base + SSSR);
 
        if (status & SSSR_ROR)
                printk(KERN_WARNING "SSP(%d): receiver overrun\n", dev->port);
@@ -78,15 +74,16 @@ static irqreturn_t ssp_interrupt(int irq, void *dev_id)
  */
 int ssp_write_word(struct ssp_dev *dev, u32 data)
 {
+       struct ssp_device *ssp = dev->ssp;
        int timeout = TIMEOUT;
 
-       while (!(SSSR_P(dev->port) & SSSR_TNF)) {
+       while (!(__raw_readl(ssp->mmio_base + SSSR) & SSSR_TNF)) {
                if (!--timeout)
                        return -ETIMEDOUT;
                cpu_relax();
        }
 
-       SSDR_P(dev->port) = data;
+       __raw_writel(data, ssp->mmio_base + SSDR);
 
        return 0;
 }
@@ -108,15 +105,16 @@ int ssp_write_word(struct ssp_dev *dev, u32 data)
  */
 int ssp_read_word(struct ssp_dev *dev, u32 *data)
 {
+       struct ssp_device *ssp = dev->ssp;
        int timeout = TIMEOUT;
 
-       while (!(SSSR_P(dev->port) & SSSR_RNE)) {
+       while (!(__raw_readl(ssp->mmio_base + SSSR) & SSSR_RNE)) {
                if (!--timeout)
                        return -ETIMEDOUT;
                cpu_relax();
        }
 
-       *data = SSDR_P(dev->port);
+       *data = __raw_readl(ssp->mmio_base + SSDR);
        return 0;
 }
 
@@ -130,17 +128,28 @@ int ssp_read_word(struct ssp_dev *dev, u32 *data)
  */
 int ssp_flush(struct ssp_dev *dev)
 {
+       struct ssp_device *ssp = dev->ssp;
        int timeout = TIMEOUT * 2;
 
+       /* ensure TX FIFO is empty instead of not full */
+       if (cpu_is_pxa3xx()) {
+               while (__raw_readl(ssp->mmio_base + SSSR) & 0xf00) {
+                       if (!--timeout)
+                               return -ETIMEDOUT;
+                       cpu_relax();
+               }
+               timeout = TIMEOUT * 2;
+       }
+
        do {
-               while (SSSR_P(dev->port) & SSSR_RNE) {
+               while (__raw_readl(ssp->mmio_base + SSSR) & SSSR_RNE) {
                        if (!--timeout)
                                return -ETIMEDOUT;
-                       (void) SSDR_P(dev->port);
+                       (void)__raw_readl(ssp->mmio_base + SSDR);
                }
                if (!--timeout)
                        return -ETIMEDOUT;
-       } while (SSSR_P(dev->port) & SSSR_BSY);
+       } while (__raw_readl(ssp->mmio_base + SSSR) & SSSR_BSY);
 
        return 0;
 }
@@ -152,7 +161,12 @@ int ssp_flush(struct ssp_dev *dev)
  */
 void ssp_enable(struct ssp_dev *dev)
 {
-       SSCR0_P(dev->port) |= SSCR0_SSE;
+       struct ssp_device *ssp = dev->ssp;
+       uint32_t sscr0;
+
+       sscr0 = __raw_readl(ssp->mmio_base + SSCR0);
+       sscr0 |= SSCR0_SSE;
+       __raw_writel(sscr0, ssp->mmio_base + SSCR0);
 }
 
 /**
@@ -162,7 +176,12 @@ void ssp_enable(struct ssp_dev *dev)
  */
 void ssp_disable(struct ssp_dev *dev)
 {
-       SSCR0_P(dev->port) &= ~SSCR0_SSE;
+       struct ssp_device *ssp = dev->ssp;
+       uint32_t sscr0;
+
+       sscr0 = __raw_readl(ssp->mmio_base + SSCR0);
+       sscr0 &= ~SSCR0_SSE;
+       __raw_writel(sscr0, ssp->mmio_base + SSCR0);
 }
 
 /**
@@ -171,14 +190,16 @@ void ssp_disable(struct ssp_dev *dev)
  *
  * Save the configured SSP state for suspend.
  */
-void ssp_save_state(struct ssp_dev *dev, struct ssp_state *ssp)
+void ssp_save_state(struct ssp_dev *dev, struct ssp_state *state)
 {
-       ssp->cr0 = SSCR0_P(dev->port);
-       ssp->cr1 = SSCR1_P(dev->port);
-       ssp->to = SSTO_P(dev->port);
-       ssp->psp = SSPSP_P(dev->port);
+       struct ssp_device *ssp = dev->ssp;
 
-       SSCR0_P(dev->port) &= ~SSCR0_SSE;
+       state->cr0 = __raw_readl(ssp->mmio_base + SSCR0);
+       state->cr1 = __raw_readl(ssp->mmio_base + SSCR1);
+       state->to  = __raw_readl(ssp->mmio_base + SSTO);
+       state->psp = __raw_readl(ssp->mmio_base + SSPSP);
+
+       ssp_disable(dev);
 }
 
 /**
@@ -187,16 +208,18 @@ void ssp_save_state(struct ssp_dev *dev, struct ssp_state *ssp)
  *
  * Restore the SSP configuration saved previously by ssp_save_state.
  */
-void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp)
+void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *state)
 {
-       SSSR_P(dev->port) = SSSR_ROR | SSSR_TUR | SSSR_BCE;
+       struct ssp_device *ssp = dev->ssp;
+       uint32_t sssr = SSSR_ROR | SSSR_TUR | SSSR_BCE;
 
-       SSCR0_P(dev->port) = ssp->cr0 & ~SSCR0_SSE;
-       SSCR1_P(dev->port) = ssp->cr1;
-       SSTO_P(dev->port) = ssp->to;
-       SSPSP_P(dev->port) = ssp->psp;
+       __raw_writel(sssr, ssp->mmio_base + SSSR);
 
-       SSCR0_P(dev->port) = ssp->cr0;
+       __raw_writel(state->cr0 & ~SSCR0_SSE, ssp->mmio_base + SSCR0);
+       __raw_writel(state->cr1, ssp->mmio_base + SSCR1);
+       __raw_writel(state->to,  ssp->mmio_base + SSTO);
+       __raw_writel(state->psp, ssp->mmio_base + SSPSP);
+       __raw_writel(state->cr0, ssp->mmio_base + SSCR0);
 }
 
 /**
@@ -210,15 +233,17 @@ void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp)
  */
 int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32 psp_flags, u32 speed)
 {
+       struct ssp_device *ssp = dev->ssp;
+
        dev->mode = mode;
        dev->flags = flags;
        dev->psp_flags = psp_flags;
        dev->speed = speed;
 
        /* set up port type, speed, port settings */
-       SSCR0_P(dev->port) = (dev->speed | dev->mode);
-       SSCR1_P(dev->port) = dev->flags;
-       SSPSP_P(dev->port) = dev->psp_flags;
+       __raw_writel((dev->speed | dev->mode), ssp->mmio_base + SSCR0);
+       __raw_writel(dev->flags, ssp->mmio_base + SSCR1);
+       __raw_writel(dev->psp_flags, ssp->mmio_base + SSPSP);
 
        return 0;
 }
@@ -253,7 +278,7 @@ int ssp_init(struct ssp_dev *dev, u32 port, u32 init_flags)
                        goto out_region;
                dev->irq = ssp->irq;
        } else
-               dev->irq = 0;
+               dev->irq = NO_IRQ;
 
        /* turn on SSP port clock */
        clk_enable(ssp->clk);
@@ -273,8 +298,9 @@ void ssp_exit(struct ssp_dev *dev)
 {
        struct ssp_device *ssp = dev->ssp;
 
-       SSCR0_P(dev->port) &= ~SSCR0_SSE;
-       free_irq(dev->irq, dev);
+       ssp_disable(dev);
+       if (dev->irq != NO_IRQ)
+               free_irq(dev->irq, dev);
        clk_disable(ssp->clk);
        ssp_free(ssp);
 }
@@ -298,7 +324,7 @@ struct ssp_device *ssp_request(int port, const char *label)
 
        mutex_unlock(&ssp_lock);
 
-       if (ssp->port_id != port)
+       if (&ssp->node == &ssp_list)
                return NULL;
 
        return ssp;
@@ -328,6 +354,7 @@ static int __devinit ssp_probe(struct platform_device *pdev, int type)
                dev_err(&pdev->dev, "failed to allocate memory");
                return -ENOMEM;
        }
+       ssp->pdev = pdev;
 
        ssp->clk = clk_get(&pdev->dev, "SSPCLK");
        if (IS_ERR(ssp->clk)) {
@@ -502,7 +529,7 @@ static void __exit pxa_ssp_exit(void)
        platform_driver_unregister(&pxa27x_ssp_driver);
 }
 
-module_init(pxa_ssp_init);
+arch_initcall(pxa_ssp_init);
 module_exit(pxa_ssp_exit);
 
 EXPORT_SYMBOL(ssp_write_word);