I2C driver does not allow auto runtime pm by default. And it go to suspend after every accessing. It is not efficient for continual I2C accessing.
This patch allows auto suspend by default. And it add a delay suspend which keeps I2C active for at least 500ms after every accessing. If device driver accesses I2C frequently, it will not go to suspend and keep high performance. After long time idle, it will go to suspend auto. Signed-off-by: Bin Yang <[email protected]> --- drivers/i2c/busses/i2c-mrst.c | 43 ++++++++++++++++++++++++---------------- 1 files changed, 26 insertions(+), 17 deletions(-) diff --git a/drivers/i2c/busses/i2c-mrst.c b/drivers/i2c/busses/i2c-mrst.c index 26c8f1c..3c055d7 100644 --- a/drivers/i2c/busses/i2c-mrst.c +++ b/drivers/i2c/busses/i2c-mrst.c @@ -538,7 +538,7 @@ static int mrst_i2c_xfer(struct i2c_adapter *adap, (struct mrst_i2c_private *)i2c_get_adapdata(adap); int i, err; - pm_runtime_get(i2c->dev); + pm_runtime_get_sync(i2c->dev); mutex_lock(&i2c->lock); dev_dbg(&adap->dev, "mrst_i2c_xfer, process %d msg(s)\n", num); @@ -547,40 +547,35 @@ static int mrst_i2c_xfer(struct i2c_adapter *adap, if (i2c->status != STATUS_IDLE) { dev_err(&adap->dev, "Adapter %d in transfer/standby\n", adap->nr); - mutex_unlock(&i2c->lock); - pm_runtime_put(i2c->dev); - return -1; + err = -1; + goto err_1; } /* if number of messages equal 0*/ if (num == 0) { - mutex_unlock(&i2c->lock); - pm_runtime_put(i2c->dev); - return 0; + err = 0; + goto err_1; } /* Checked the sanity of passed messages. */ if (unlikely(mrst_i2c_invalid_address(&pmsg[0]))) { dev_err(&adap->dev, "Invalid address 0x%03x (%d-bit)\n", pmsg[0].addr, pmsg[0].flags & I2C_M_TEN ? 10 : 7); - mutex_unlock(&i2c->lock); - pm_runtime_put(i2c->dev); - return -EINVAL; + err = -EINVAL; + goto err_1; } for (i = 0; i < num; i++) { /* Message address equal? */ if (unlikely(mrst_i2c_address_neq(&pmsg[0], &pmsg[i]))) { dev_err(&adap->dev, "Invalid address in msg[%d]\n", i); - mutex_unlock(&i2c->lock); - pm_runtime_put(i2c->dev); - return -EINVAL; + err = -EINVAL; + goto err_1; } } if (mrst_i2c_setup(adap, pmsg)) { - mutex_unlock(&i2c->lock); - pm_runtime_put(i2c->dev); - return -EINVAL; + err = -EINVAL; + goto err_1; } for (i = 0; i < num; i++) { @@ -701,6 +696,14 @@ static int mrst_i2c_runtime_resume(struct device *dev) return err; } +static int mrst_i2c_runtime_idle(struct device *dev) +{ + int err = pm_schedule_suspend(dev, 500); + if (err != 0) + return 0; + return -EBUSY; +} + static void i2c_isr_read(struct mrst_i2c_private *i2c) { struct i2c_msg *msg = i2c->msg; @@ -810,6 +813,7 @@ static struct i2c_algorithm mrst_i2c_algorithm = { static const struct dev_pm_ops mrst_i2c_pm_ops = { .runtime_suspend = mrst_i2c_runtime_suspend, .runtime_resume = mrst_i2c_runtime_resume, + .runtime_idle = mrst_i2c_runtime_idle, }; static struct pci_driver mrst_i2c_driver = { @@ -966,7 +970,10 @@ static int __devinit mrst_i2c_probe(struct pci_dev *dev, (mrst->platform == MOORESTOWN) ? "Moorestown" : "Medfield", busnum); + pm_runtime_set_active(&dev->dev); pm_runtime_enable(&dev->dev); + pm_runtime_allow(&dev->dev); + return 0; fail4: @@ -989,10 +996,12 @@ static void __devexit mrst_i2c_remove(struct pci_dev *dev) { struct mrst_i2c_private *mrst = (struct mrst_i2c_private *) pci_get_drvdata(dev); + + pm_runtime_forbid(&dev->dev); + pm_runtime_disable(&dev->dev); mrst_i2c_disable(mrst->adap); if (i2c_del_adapter(mrst->adap)) dev_err(&dev->dev, "Failed to delete i2c adapter"); - free_irq(dev->irq, mrst); pci_set_drvdata(dev, NULL); iounmap(mrst->base); -- 1.7.0.4 _______________________________________________ MeeGo-kernel mailing list [email protected] http://lists.meego.com/listinfo/meego-kernel
