From 753419f59e10d7181e43f0b9cc5beff43ef3f7a4 Mon Sep 17 00:00:00 2001 From: Vishwanath BS Date: Thu, 30 Sep 2010 14:14:22 +0200 Subject: i2c: Fix for suspend/resume issue In current i2c core driver, call to pm_runtime_set_active from i2c_device_pm_resume will unconditionally enable i2c module and increment child count of the parent. Because of this, in CPU Idle path, i2c does not idle, preventing Core to enter retention. Also i2c module will not be suspended upon system suspend as pm_runtime_set_suspended is not called from i2c_device_pm_suspend. This issue is fixed by removing pm_runtime_set_active call from resume path which is not necessary. This fix has been tested on OMAP4430. Signed-off-by: Partha Basak Signed-off-by: Vishwanath BS Acked-by: Rafael J. Wysocki Cc: Kevin Hilman Cc: Ben Dooks Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 6649176..13927d5 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -216,12 +216,6 @@ static int i2c_device_pm_resume(struct device *dev) else ret = i2c_legacy_resume(dev); - if (!ret) { - pm_runtime_disable(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - } - return ret; } -- cgit v1.1 From 6abb930af064fb1cf4177d32e2c7bfb89eee0fe5 Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Thu, 30 Sep 2010 14:14:22 +0200 Subject: i2c-pca: Fix waitforcompletion() return value ret is still -1, if during the polling read_byte() returns at once with I2C_PCA_CON_SI set. So ret > 0 would lead *_waitforcompletion() to return 0, in spite of the proper behavior. The routine was rewritten, so that ret has always a proper value, before returning. Signed-off-by: Yegor Yefremov Reviewed-by: Wolfram Sang Cc: stable@kernel.org Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-pca-isa.c | 12 ++++++++---- drivers/i2c/busses/i2c-pca-platform.c | 11 +++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c index bbd7760..29933f8 100644 --- a/drivers/i2c/busses/i2c-pca-isa.c +++ b/drivers/i2c/busses/i2c-pca-isa.c @@ -71,8 +71,8 @@ static int pca_isa_readbyte(void *pd, int reg) static int pca_isa_waitforcompletion(void *pd) { - long ret = ~0; unsigned long timeout; + long ret; if (irq > -1) { ret = wait_event_timeout(pca_wait, @@ -81,11 +81,15 @@ static int pca_isa_waitforcompletion(void *pd) } else { /* Do polling */ timeout = jiffies + pca_isa_ops.timeout; - while (((pca_isa_readbyte(pd, I2C_PCA_CON) - & I2C_PCA_CON_SI) == 0) - && (ret = time_before(jiffies, timeout))) + do { + ret = time_before(jiffies, timeout); + if (pca_isa_readbyte(pd, I2C_PCA_CON) + & I2C_PCA_CON_SI) + break; udelay(100); + } while (ret); } + return ret > 0; } diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c index ef5c784..5f6d7f8 100644 --- a/drivers/i2c/busses/i2c-pca-platform.c +++ b/drivers/i2c/busses/i2c-pca-platform.c @@ -80,8 +80,8 @@ static void i2c_pca_pf_writebyte32(void *pd, int reg, int val) static int i2c_pca_pf_waitforcompletion(void *pd) { struct i2c_pca_pf_data *i2c = pd; - long ret = ~0; unsigned long timeout; + long ret; if (i2c->irq) { ret = wait_event_timeout(i2c->wait, @@ -90,10 +90,13 @@ static int i2c_pca_pf_waitforcompletion(void *pd) } else { /* Do polling */ timeout = jiffies + i2c->adap.timeout; - while (((i2c->algo_data.read_byte(i2c, I2C_PCA_CON) - & I2C_PCA_CON_SI) == 0) - && (ret = time_before(jiffies, timeout))) + do { + ret = time_before(jiffies, timeout); + if (i2c->algo_data.read_byte(i2c, I2C_PCA_CON) + & I2C_PCA_CON_SI) + break; udelay(100); + } while (ret); } return ret > 0; -- cgit v1.1 From 64b4782fc9e4bdc59ae90897e2258e4ec938690e Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Thu, 30 Sep 2010 14:14:22 +0200 Subject: i2c: Fix checks which cause legacy suspend to never get called For devices which are not adapted to runtime PM a call to pm_runtime_suspended always returns true. Hence the pm_runtime_suspended checks below prevent legacy suspend from getting called. So do a pm_runtime_suspended check only for devices with a dev_pm_ops populated (which hence do not rely on the legacy suspend.) Signed-off-by: Rajendra Nayak Acked-by: Rafael J. Wysocki Cc: Ben Dooks Cc: Mark Brown Cc: Kevin Hilman Signed-off-by: Jean Delvare --- drivers/i2c/i2c-core.c | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 13927d5..9b3cac1 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -197,11 +197,12 @@ static int i2c_device_pm_suspend(struct device *dev) { const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - if (pm_runtime_suspended(dev)) - return 0; - - if (pm) - return pm->suspend ? pm->suspend(dev) : 0; + if (pm) { + if (pm_runtime_suspended(dev)) + return 0; + else + return pm->suspend ? pm->suspend(dev) : 0; + } return i2c_legacy_suspend(dev, PMSG_SUSPEND); } @@ -223,11 +224,12 @@ static int i2c_device_pm_freeze(struct device *dev) { const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - if (pm_runtime_suspended(dev)) - return 0; - - if (pm) - return pm->freeze ? pm->freeze(dev) : 0; + if (pm) { + if (pm_runtime_suspended(dev)) + return 0; + else + return pm->freeze ? pm->freeze(dev) : 0; + } return i2c_legacy_suspend(dev, PMSG_FREEZE); } @@ -236,11 +238,12 @@ static int i2c_device_pm_thaw(struct device *dev) { const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - if (pm_runtime_suspended(dev)) - return 0; - - if (pm) - return pm->thaw ? pm->thaw(dev) : 0; + if (pm) { + if (pm_runtime_suspended(dev)) + return 0; + else + return pm->thaw ? pm->thaw(dev) : 0; + } return i2c_legacy_resume(dev); } @@ -249,11 +252,12 @@ static int i2c_device_pm_poweroff(struct device *dev) { const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; - if (pm_runtime_suspended(dev)) - return 0; - - if (pm) - return pm->poweroff ? pm->poweroff(dev) : 0; + if (pm) { + if (pm_runtime_suspended(dev)) + return 0; + else + return pm->poweroff ? pm->poweroff(dev) : 0; + } return i2c_legacy_suspend(dev, PMSG_HIBERNATE); } -- cgit v1.1 From 925bb9c649cf8d7200549b395f2ae291833dd494 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Thu, 30 Sep 2010 14:14:23 +0200 Subject: of/i2c: Fix module load order issue caused by of_i2c.c Commit 959e85f7, "i2c: add OF-style registration and binding" caused a module dependency loop where of_i2c.c calls functions in i2c-core, and i2c-core calls of_i2c_register_devices() in of_i2c. This means that when i2c support is built as a module when CONFIG_OF is set, then neither i2c_core nor of_i2c are able to be loaded. This patch fixes the problem by moving the of_i2c_register_devices() calls back into the device drivers. Device drivers already specifically request the core code to parse the device tree for devices anyway by setting the of_node pointer, so it isn't a big deal to also call the registration function. The drivers just become slightly more verbose. Signed-off-by: Grant Likely Signed-off-by: Jean Delvare --- drivers/i2c/busses/i2c-cpm.c | 5 +++++ drivers/i2c/busses/i2c-ibm_iic.c | 3 +++ drivers/i2c/busses/i2c-mpc.c | 1 + drivers/i2c/i2c-core.c | 4 ---- 4 files changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/i2c') diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index f7bd261..f2de3be 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -677,6 +677,11 @@ static int __devinit cpm_i2c_probe(struct platform_device *ofdev, dev_dbg(&ofdev->dev, "hw routines for %s registered.\n", cpm->adap.name); + /* + * register OF I2C devices + */ + of_i2c_register_devices(&cpm->adap); + return 0; out_shut: cpm_i2c_shutdown(cpm); diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 43ca32f..89eedf4 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -761,6 +761,9 @@ static int __devinit iic_probe(struct platform_device *ofdev, dev_info(&ofdev->dev, "using %s mode\n", dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)"); + /* Now register all the child nodes */ + of_i2c_register_devices(adap); + return 0; error_cleanup: diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index a1c419a..b74e6dc 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -632,6 +632,7 @@ static int __devinit fsl_i2c_probe(struct platform_device *op, dev_err(i2c->dev, "failed to add adapter\n"); goto fail_add; } + of_i2c_register_devices(&i2c->adap); return result; diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 9b3cac1..bea4c50 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -874,9 +873,6 @@ static int i2c_register_adapter(struct i2c_adapter *adap) if (adap->nr < __i2c_first_dynamic_bus_num) i2c_scan_static_board_info(adap); - /* Register devices from the device tree */ - of_i2c_register_devices(adap); - /* Notify drivers */ mutex_lock(&core_lock); bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter); -- cgit v1.1