Merge branch 'merge'
[pandora-kernel.git] / arch / arm / mach-pxa / ssp.c
index a68b30e..1fddfea 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/hardware.h>
@@ -39,6 +40,8 @@
 
 #define PXA_SSP_PORTS  3
 
+#define TIMEOUT 100000
+
 struct ssp_info_ {
        int irq;
        u32 clock;
@@ -59,7 +62,7 @@ static const struct ssp_info_ ssp_info[PXA_SSP_PORTS] = {
 #endif
 };
 
-static DECLARE_MUTEX(sem);
+static DEFINE_MUTEX(mutex);
 static int use_count[PXA_SSP_PORTS] = {0, 0, 0};
 
 static irqreturn_t ssp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -91,13 +94,18 @@ static irqreturn_t ssp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
  * The caller is expected to perform the necessary locking.
  *
  * Returns:
- *   %-ETIMEDOUT       timeout occurred (for future)
+ *   %-ETIMEDOUT       timeout occurred
  *   0                 success
  */
 int ssp_write_word(struct ssp_dev *dev, u32 data)
 {
-       while (!(SSSR_P(dev->port) & SSSR_TNF))
+       int timeout = TIMEOUT;
+
+       while (!(SSSR_P(dev->port) & SSSR_TNF)) {
+               if (!--timeout)
+                       return -ETIMEDOUT;
                cpu_relax();
+       }
 
        SSDR_P(dev->port) = data;
 
@@ -116,15 +124,21 @@ int ssp_write_word(struct ssp_dev *dev, u32 data)
  * The caller is expected to perform the necessary locking.
  *
  * Returns:
- *   %-ETIMEDOUT       timeout occurred (for future)
+ *   %-ETIMEDOUT       timeout occurred
  *   32-bit data       success
  */
-int ssp_read_word(struct ssp_dev *dev)
+int ssp_read_word(struct ssp_dev *dev, u32 *data)
 {
-       while (!(SSSR_P(dev->port) & SSSR_RNE))
+       int timeout = TIMEOUT;
+
+       while (!(SSSR_P(dev->port) & SSSR_RNE)) {
+               if (!--timeout)
+                       return -ETIMEDOUT;
                cpu_relax();
+       }
 
-       return SSDR_P(dev->port);
+       *data = SSDR_P(dev->port);
+       return 0;
 }
 
 /**
@@ -135,13 +149,21 @@ int ssp_read_word(struct ssp_dev *dev)
  *
  * The caller is expected to perform the necessary locking.
  */
-void ssp_flush(struct ssp_dev *dev)
+int ssp_flush(struct ssp_dev *dev)
 {
+       int timeout = TIMEOUT * 2;
+
        do {
                while (SSSR_P(dev->port) & SSSR_RNE) {
+                       if (!--timeout)
+                               return -ETIMEDOUT;
                        (void) SSDR_P(dev->port);
                }
+               if (!--timeout)
+                       return -ETIMEDOUT;
        } while (SSSR_P(dev->port) & SSSR_BSY);
+
+       return 0;
 }
 
 /**
@@ -239,16 +261,16 @@ int ssp_init(struct ssp_dev *dev, u32 port, u32 init_flags)
        if (port > PXA_SSP_PORTS || port == 0)
                return -ENODEV;
 
-       down(&sem);
+       mutex_lock(&mutex);
        if (use_count[port - 1]) {
-               up(&sem);
+               mutex_unlock(&mutex);
                return -EBUSY;
        }
        use_count[port - 1]++;
 
        if (!request_mem_region(__PREG(SSCR0_P(port)), 0x2c, "SSP")) {
                use_count[port - 1]--;
-               up(&sem);
+               mutex_unlock(&mutex);
                return -EBUSY;
        }
        dev->port = port;
@@ -265,13 +287,13 @@ int ssp_init(struct ssp_dev *dev, u32 port, u32 init_flags)
 
        /* turn on SSP port clock */
        pxa_set_cken(ssp_info[port-1].clock, 1);
-       up(&sem);
+       mutex_unlock(&mutex);
        return 0;
 
 out_region:
        release_mem_region(__PREG(SSCR0_P(port)), 0x2c);
        use_count[port - 1]--;
-       up(&sem);
+       mutex_unlock(&mutex);
        return ret;
 }
 
@@ -282,7 +304,7 @@ out_region:
  */
 void ssp_exit(struct ssp_dev *dev)
 {
-       down(&sem);
+       mutex_lock(&mutex);
        SSCR0_P(dev->port) &= ~SSCR0_SSE;
 
        if (dev->port > PXA_SSP_PORTS || dev->port == 0) {
@@ -295,7 +317,7 @@ void ssp_exit(struct ssp_dev *dev)
                free_irq(dev->irq, dev);
        release_mem_region(__PREG(SSCR0_P(dev->port)), 0x2c);
        use_count[dev->port - 1]--;
-       up(&sem);
+       mutex_unlock(&mutex);
 }
 
 EXPORT_SYMBOL(ssp_write_word);