aboutsummaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
authorJonas Aaberg <jonas.aberg@stericsson.com>2010-10-13 11:56:21 +0200
committerSundar Iyer <sundar.iyer@stericsson.com>2010-11-10 17:04:07 +0530
commitd69f4599cd57cab180407b631226546c6da82b10 (patch)
tree2a7703306063dfed4d55e16880d3f011c70e3828 /drivers/i2c
parentb0a5008041b7fa30393cb812d99f3234b868a05e (diff)
i2c-nomadik: Fix regulator handling
The regulator was not enabled at the proper places. i2c hw initialization could happen without the regulator enabled. Change-Id: I6feb6edcad1d312fa5c8618abf6ddd9de72bba0a Signed-off-by: Jonas Aaberg <jonas.aberg@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/6441 Reviewed-by: Martin PERSSON <martin.persson@stericsson.com>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c62
1 files changed, 41 insertions, 21 deletions
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index 49a8674070b..c9d21cb3a97 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -152,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;
@@ -165,6 +166,7 @@ struct nmk_i2c_dev {
struct completion xfer_complete;
int result;
struct regulator *regulator;
+ bool busy;
};
/* controller's abort causes */
@@ -259,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);
@@ -270,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 */
@@ -565,13 +573,15 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
u32 cause;
struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap);
- status = init_hw(dev);
- if (status)
- return status;
+ dev->busy = true;
if (dev->regulator)
regulator_enable(dev->regulator);
+ status = init_hw(dev);
+ if (status)
+ goto out2;
+
clk_enable(dev->clk);
/* setup the i2c controller */
@@ -616,10 +626,12 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
out:
clk_disable(dev->clk);
-
+out2:
if (dev->regulator)
regulator_disable(dev->regulator);
+ dev->busy = false;
+
/* return the no. messages processed */
if (status)
return status;
@@ -817,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
@@ -845,7 +872,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);
@@ -877,10 +904,8 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
dev->regulator = regulator_get(&pdev->dev, "v-i2c");
if (IS_ERR(dev->regulator)) {
- dev_err(&pdev->dev, "could not get i2c regulator\n");
- ret = PTR_ERR(dev->regulator);
+ dev_warn(&pdev->dev, "could not get i2c regulator\n");
dev->regulator = NULL;
- goto err_no_regulator;
}
dev->clk = clk_get(&pdev->dev, NULL);
@@ -908,12 +933,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_dbg(&pdev->dev, "initialize I2C%d bus on virtual "
"base %p\n", pdev->id, dev->virtbase);
@@ -925,12 +944,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:
- regulator_put(dev->regulator);
- err_no_regulator:
+ if (dev->regulator)
+ regulator_put(dev->regulator);
free_irq(dev->irq, dev);
err_irq:
iounmap(dev->virtbase);
@@ -961,7 +979,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);
- regulator_put(dev->regulator);
+ if (dev->regulator)
+ regulator_put(dev->regulator);
platform_set_drvdata(pdev, NULL);
kfree(dev);
@@ -975,6 +994,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)