diff options
author | Jonas Aaberg <jonas.aberg@stericsson.com> | 2010-10-13 11:56:21 +0200 |
---|---|---|
committer | Sundar Iyer <sundar.iyer@stericsson.com> | 2010-11-10 17:04:07 +0530 |
commit | d69f4599cd57cab180407b631226546c6da82b10 (patch) | |
tree | 2a7703306063dfed4d55e16880d3f011c70e3828 /drivers/i2c | |
parent | b0a5008041b7fa30393cb812d99f3234b868a05e (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.c | 62 |
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) |