i2c-nomadik: corrrect returned error numbers
[pandora-kernel.git] / drivers / i2c / busses / i2c-nomadik.c
index e10e5cf..a02141a 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/regulator/consumer.h>
 
 #include <plat/i2c.h>
 
@@ -120,9 +121,6 @@ enum i2c_operation {
        I2C_READ = 0x01
 };
 
-/* controller response timeout in ms */
-#define I2C_TIMEOUT_MS 2000
-
 /**
  * struct i2c_nmk_client - client specific data
  * @slave_adr: 7-bit slave address
@@ -151,6 +149,7 @@ struct i2c_nmk_client {
  * @stop: stop condition
  * @xfer_complete: acknowledge completion for a I2C message
  * @result: controller propogated result
+ * @busy: Busy doing transfer
  */
 struct nmk_i2c_dev {
        struct platform_device          *pdev;
@@ -163,6 +162,8 @@ struct nmk_i2c_dev {
        int                             stop;
        struct completion               xfer_complete;
        int                             result;
+       struct regulator                *regulator;
+       bool                            busy;
 };
 
 /* controller's abort causes */
@@ -209,7 +210,7 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev)
        writel((I2C_CR_FTX | I2C_CR_FRX), dev->virtbase + I2C_CR);
 
        for (i = 0; i < LOOP_ATTEMPTS; i++) {
-               timeout = jiffies + msecs_to_jiffies(I2C_TIMEOUT_MS);
+               timeout = jiffies + msecs_to_jiffies(dev->adap.timeout);
 
                while (!time_after(jiffies, timeout)) {
                        if ((readl(dev->virtbase + I2C_CR) &
@@ -257,7 +258,7 @@ static int init_hw(struct nmk_i2c_dev *dev)
 
        stat = flush_i2c_fifo(dev);
        if (stat)
-               return stat;
+               goto exit;
 
        /* disable the controller */
        i2c_clr_bit(dev->virtbase + I2C_CR , I2C_CR_PE);
@@ -268,10 +269,16 @@ static int init_hw(struct nmk_i2c_dev *dev)
 
        dev->cli.operation = I2C_NO_OPERATION;
 
+exit:
+       /* TODO: Why disable clocks after init hw? */
        clk_disable(dev->clk);
-
+       /*
+        * TODO: What is this delay for?
+        * Must be pretty pointless since the hw block
+        * is frozen. Or?
+        */
        udelay(I2C_DELAY);
-       return 0;
+       return stat;
 }
 
 /* enable peripheral, master mode operation */
@@ -424,7 +431,7 @@ static int read_i2c(struct nmk_i2c_dev *dev)
                        dev->virtbase + I2C_IMSCR);
 
        timeout = wait_for_completion_interruptible_timeout(
-               &dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS));
+               &dev->xfer_complete, msecs_to_jiffies(dev->adap.timeout));
 
        if (timeout < 0) {
                dev_err(&dev->pdev->dev,
@@ -488,7 +495,7 @@ static int write_i2c(struct nmk_i2c_dev *dev)
                        dev->virtbase + I2C_IMSCR);
 
        timeout = wait_for_completion_interruptible_timeout(
-               &dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS));
+               &dev->xfer_complete, msecs_to_jiffies(dev->adap.timeout));
 
        if (timeout < 0) {
                dev_err(&dev->pdev->dev,
@@ -562,9 +569,14 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
        u32 cause;
        struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap);
 
+       dev->busy = true;
+
+       if (dev->regulator)
+               regulator_enable(dev->regulator);
+
        status = init_hw(dev);
        if (status)
-               return status;
+               goto out2;
 
        clk_enable(dev->clk);
 
@@ -575,7 +587,9 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
                if (unlikely(msgs[i].flags & I2C_M_TEN)) {
                        dev_err(&dev->pdev->dev, "10 bit addressing"
                                        "not supported\n");
-                       return -EINVAL;
+
+                       status = -EINVAL;
+                       goto out;
                }
                dev->cli.slave_adr      = msgs[i].addr;
                dev->cli.buffer         = msgs[i].buf;
@@ -600,12 +614,21 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
                        dev_err(&dev->pdev->dev, "%s\n",
                                cause >= ARRAY_SIZE(abort_causes)
                                ? "unknown reason" : abort_causes[cause]);
-                       clk_disable(dev->clk);
-                       return status;
+
+                       status = status ? status : dev->result;
+
+                       goto out;
                }
                udelay(I2C_DELAY);
        }
+
+out:
        clk_disable(dev->clk);
+out2:
+       if (dev->regulator)
+               regulator_disable(dev->regulator);
+
+       dev->busy = false;
 
        /* return the no. messages processed */
        if (status)
@@ -738,7 +761,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
                                        | I2C_IT_RXFF | I2C_IT_RXFE));
 
                if (dev->cli.count) {
-                       dev->result = -1;
+                       dev->result = -EIO;
                        dev_err(&dev->pdev->dev, "%lu bytes still remain to be"
                                        "xfered\n", dev->cli.count);
                        (void) init_hw(dev);
@@ -749,7 +772,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
 
        /* Master Arbitration lost interrupt */
        case I2C_IT_MAL:
-               dev->result = -1;
+               dev->result = -EIO;
                (void) init_hw(dev);
 
                i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MAL);
@@ -763,7 +786,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
         * during the transaction.
         */
        case I2C_IT_BERR:
-               dev->result = -1;
+               dev->result = -EIO;
                /* get the status */
                if (((readl(dev->virtbase + I2C_SR) >> 2) & 0x3) == I2C_ABORT)
                        (void) init_hw(dev);
@@ -779,7 +802,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
         * the Tx FIFO is full.
         */
        case I2C_IT_TXFOVR:
-               dev->result = -1;
+               dev->result = -EIO;
                (void) init_hw(dev);
 
                dev_err(&dev->pdev->dev, "Tx Fifo Over run\n");
@@ -805,6 +828,21 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
        return IRQ_HANDLED;
 }
 
+
+#ifdef CONFIG_PM
+static int nmk_i2c_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+       struct nmk_i2c_dev *dev = platform_get_drvdata(pdev);
+
+       if (dev->busy)
+               return -EBUSY;
+       else
+               return 0;
+}
+#else
+#define nmk_i2c_suspend        NULL
+#endif
+
 static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)
 {
        return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
@@ -830,7 +868,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
                ret = -ENOMEM;
                goto err_no_mem;
        }
-
+       dev->busy = false;
        dev->pdev = pdev;
        platform_set_drvdata(pdev, dev);
 
@@ -860,6 +898,12 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
                goto err_irq;
        }
 
+       dev->regulator = regulator_get(&pdev->dev, "v-i2c");
+       if (IS_ERR(dev->regulator)) {
+               dev_warn(&pdev->dev, "could not get i2c regulator\n");
+               dev->regulator = NULL;
+       }
+
        dev->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(dev->clk)) {
                dev_err(&pdev->dev, "could not get i2c clock\n");
@@ -872,6 +916,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
        adap->owner     = THIS_MODULE;
        adap->class     = I2C_CLASS_HWMON | I2C_CLASS_SPD;
        adap->algo      = &nmk_i2c_algo;
+       adap->timeout   = pdata->timeout ? pdata->timeout : 20000;
        snprintf(adap->name, sizeof(adap->name),
                 "Nomadik I2C%d at %lx", pdev->id, (unsigned long)res->start);
 
@@ -887,12 +932,6 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
 
        i2c_set_adapdata(adap, dev);
 
-       ret = init_hw(dev);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "error in initializing i2c hardware\n");
-               goto err_init_hw;
-       }
-
        dev_info(&pdev->dev, "initialize %s on virtual "
                "base %p\n", adap->name, dev->virtbase);
 
@@ -904,10 +943,11 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
 
        return 0;
 
- err_init_hw:
  err_add_adap:
        clk_put(dev->clk);
  err_no_clk:
+       if (dev->regulator)
+               regulator_put(dev->regulator);
        free_irq(dev->irq, dev);
  err_irq:
        iounmap(dev->virtbase);
@@ -938,6 +978,8 @@ static int __devexit nmk_i2c_remove(struct platform_device *pdev)
        if (res)
                release_mem_region(res->start, resource_size(res));
        clk_put(dev->clk);
+       if (dev->regulator)
+               regulator_put(dev->regulator);
        platform_set_drvdata(pdev, NULL);
        kfree(dev);
 
@@ -951,6 +993,7 @@ static struct platform_driver nmk_i2c_driver = {
        },
        .probe = nmk_i2c_probe,
        .remove = __devexit_p(nmk_i2c_remove),
+       .suspend = nmk_i2c_suspend,
 };
 
 static int __init nmk_i2c_init(void)