diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-pxa.c | 25 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-s3c2410.c | 25 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-sh_mobile.c | 39 |
3 files changed, 70 insertions, 19 deletions
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 762e1e53088..049555777f6 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1134,35 +1134,44 @@ static int __exit i2c_pxa_remove(struct platform_device *dev) } #ifdef CONFIG_PM -static int i2c_pxa_suspend_late(struct platform_device *dev, pm_message_t state) +static int i2c_pxa_suspend_noirq(struct device *dev) { - struct pxa_i2c *i2c = platform_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct pxa_i2c *i2c = platform_get_drvdata(pdev); + clk_disable(i2c->clk); + return 0; } -static int i2c_pxa_resume_early(struct platform_device *dev) +static int i2c_pxa_resume_noirq(struct device *dev) { - struct pxa_i2c *i2c = platform_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct pxa_i2c *i2c = platform_get_drvdata(pdev); clk_enable(i2c->clk); i2c_pxa_reset(i2c); return 0; } + +static struct dev_pm_ops i2c_pxa_dev_pm_ops = { + .suspend_noirq = i2c_pxa_suspend_noirq, + .resume_noirq = i2c_pxa_resume_noirq, +}; + +#define I2C_PXA_DEV_PM_OPS (&i2c_pxa_dev_pm_ops) #else -#define i2c_pxa_suspend_late NULL -#define i2c_pxa_resume_early NULL +#define I2C_PXA_DEV_PM_OPS NULL #endif static struct platform_driver i2c_pxa_driver = { .probe = i2c_pxa_probe, .remove = __exit_p(i2c_pxa_remove), - .suspend_late = i2c_pxa_suspend_late, - .resume_early = i2c_pxa_resume_early, .driver = { .name = "pxa2xx-i2c", .owner = THIS_MODULE, + .pm = I2C_PXA_DEV_PM_OPS, }, .id_table = i2c_pxa_id_table, }; diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 20bb0ceb027..96aafb91b69 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -946,17 +946,20 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) } #ifdef CONFIG_PM -static int s3c24xx_i2c_suspend_late(struct platform_device *dev, - pm_message_t msg) +static int s3c24xx_i2c_suspend_noirq(struct device *dev) { - struct s3c24xx_i2c *i2c = platform_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); + i2c->suspended = 1; + return 0; } -static int s3c24xx_i2c_resume(struct platform_device *dev) +static int s3c24xx_i2c_resume(struct device *dev) { - struct s3c24xx_i2c *i2c = platform_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); i2c->suspended = 0; s3c24xx_i2c_init(i2c); @@ -964,9 +967,14 @@ static int s3c24xx_i2c_resume(struct platform_device *dev) return 0; } +static struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = { + .suspend_noirq = s3c24xx_i2c_suspend_noirq, + .resume = s3c24xx_i2c_resume, +}; + +#define S3C24XX_DEV_PM_OPS (&s3c24xx_i2c_dev_pm_ops) #else -#define s3c24xx_i2c_suspend_late NULL -#define s3c24xx_i2c_resume NULL +#define S3C24XX_DEV_PM_OPS NULL #endif /* device driver for platform bus bits */ @@ -985,12 +993,11 @@ MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); static struct platform_driver s3c24xx_i2c_driver = { .probe = s3c24xx_i2c_probe, .remove = s3c24xx_i2c_remove, - .suspend_late = s3c24xx_i2c_suspend_late, - .resume = s3c24xx_i2c_resume, .id_table = s3c24xx_driver_ids, .driver = { .owner = THIS_MODULE, .name = "s3c-i2c", + .pm = S3C24XX_DEV_PM_OPS, }, }; diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 820487d0d5c..86a9d4e8147 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -28,6 +28,7 @@ #include <linux/interrupt.h> #include <linux/i2c.h> #include <linux/err.h> +#include <linux/pm_runtime.h> #include <linux/clk.h> #include <linux/io.h> @@ -165,7 +166,8 @@ static void activate_ch(struct sh_mobile_i2c_data *pd) u_int32_t denom; u_int32_t tmp; - /* Make sure the clock is enabled */ + /* Wake up device and enable clock */ + pm_runtime_get_sync(pd->dev); clk_enable(pd->clk); /* Get clock rate after clock is enabled */ @@ -213,8 +215,9 @@ static void deactivate_ch(struct sh_mobile_i2c_data *pd) /* Disable channel */ iowrite8(ioread8(ICCR(pd)) & ~ICCR_ICE, ICCR(pd)); - /* Disable clock */ + /* Disable clock and mark device as idle */ clk_disable(pd->clk); + pm_runtime_put_sync(pd->dev); } static unsigned char i2c_op(struct sh_mobile_i2c_data *pd, @@ -572,6 +575,19 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) goto err_irq; } + /* Enable Runtime PM for this device. + * + * Also tell the Runtime PM core to ignore children + * for this device since it is valid for us to suspend + * this I2C master driver even though the slave devices + * on the I2C bus may not be suspended. + * + * The state of the I2C hardware bus is unaffected by + * the Runtime PM state. + */ + pm_suspend_ignore_children(&dev->dev, true); + pm_runtime_enable(&dev->dev); + /* setup the private data */ adap = &pd->adap; i2c_set_adapdata(adap, pd); @@ -614,14 +630,33 @@ static int sh_mobile_i2c_remove(struct platform_device *dev) iounmap(pd->reg); sh_mobile_i2c_hook_irqs(dev, 0); clk_put(pd->clk); + pm_runtime_disable(&dev->dev); kfree(pd); return 0; } +static int sh_mobile_i2c_runtime_nop(struct device *dev) +{ + /* Runtime PM callback shared between ->runtime_suspend() + * and ->runtime_resume(). Simply returns success. + * + * This driver re-initializes all registers after + * pm_runtime_get_sync() anyway so there is no need + * to save and restore registers here. + */ + return 0; +} + +static struct dev_pm_ops sh_mobile_i2c_dev_pm_ops = { + .runtime_suspend = sh_mobile_i2c_runtime_nop, + .runtime_resume = sh_mobile_i2c_runtime_nop, +}; + static struct platform_driver sh_mobile_i2c_driver = { .driver = { .name = "i2c-sh_mobile", .owner = THIS_MODULE, + .pm = &sh_mobile_i2c_dev_pm_ops, }, .probe = sh_mobile_i2c_probe, .remove = sh_mobile_i2c_remove, |