[01/13] i2c/i2c-nomadik: add regulator support

Message ID BANLkTikh5mscCxHpNNFqP+pQso9_uFUdVw@mail.gmail.com
State Accepted
Headers show

Commit Message

Linus Walleij May 10, 2011, 11:43 p.m.
---------- Forwarded message ----------
From: Linus Walleij <linus.walleij@linaro.org>
Date: 2011/5/9
Subject: [PATCH 01/13] i2c/i2c-nomadik: add regulator support
To: Ben Dooks <ben-linux@fluff.org>, linux-i2c@vger.kernel.org
Kopia: Jonas Aberg <jonas.aberg@stericsson.com>, Linus Walleij
<linus.walleij@linaro.org>


From: Jonas Aberg <jonas.aberg@stericsson.com>

This on-chip I2C controller needs to fetch the regulator
representing its voltage domain so that it won't be switched off.

Signed-off-by: Jonas Aberg <jonas.aberg@stericsson.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
 drivers/i2c/busses/i2c-nomadik.c |   73 ++++++++++++++++++++++++++++++--------
 1 files changed, 58 insertions(+), 15 deletions(-)


@@ -860,6 +899,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");
@@ -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)
--
1.7.5.1

--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch

diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index e10e5cf..182761e 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -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>

@@ -151,6 +152,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 +165,8 @@  struct nmk_i2c_dev {
       int                             stop;
       struct completion               xfer_complete;
       int                             result;
+       struct regulator                *regulator;
+       bool                            busy;
 };

 /* controller's abort causes */
@@ -257,7 +261,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 +272,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 */
@@ -562,9 +572,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 +590,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 +617,19 @@  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;
+
+                       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)
@@ -805,6 +829,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 +869,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);