From eb5eba4ef72248b976465906cfed5fca2e9d8831 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 21 Feb 2013 16:44:35 -0800 Subject: drivers/rtc/rtc-tps65910.c: enable/disable wake in suspend/resume Making the rtc driver as wakeup capabale and leaving the wake enable/disable decision to user space through a sysfs attribute. In suspend, enable wake if device wakeup enabled. In resume disable wake again. This change is inline with the Documentation/power/devices.txt# /sys/devices/.../power/wakeup files Signed-off-by: Laxman Dewangan Cc: Mark Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-tps65910.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/rtc/rtc-tps65910.c') diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index e5fef141a0e2..932a655aa41c 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -27,6 +27,7 @@ struct tps65910_rtc { struct rtc_device *rtc; + int irq; /* To store the list of enabled interrupts */ u32 irqstat; }; @@ -273,7 +274,8 @@ static int tps65910_rtc_probe(struct platform_device *pdev) dev_err(&pdev->dev, "IRQ is not free.\n"); return ret; } - device_init_wakeup(&pdev->dev, 1); + tps_rtc->irq = irq; + device_set_wakeup_capable(&pdev->dev, 1); tps_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &tps65910_rtc_ops, THIS_MODULE); @@ -308,9 +310,13 @@ static int tps65910_rtc_remove(struct platform_device *pdev) static int tps65910_rtc_suspend(struct device *dev) { struct tps65910 *tps = dev_get_drvdata(dev->parent); + struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev); u8 alarm = TPS65910_RTC_INTERRUPTS_IT_ALARM; int ret; + if (device_may_wakeup(dev)) + enable_irq_wake(tps_rtc->irq); + /* Store current list of enabled interrupts*/ ret = regmap_read(tps->regmap, TPS65910_RTC_INTERRUPTS, &tps->rtc->irqstat); @@ -324,6 +330,10 @@ static int tps65910_rtc_suspend(struct device *dev) static int tps65910_rtc_resume(struct device *dev) { struct tps65910 *tps = dev_get_drvdata(dev->parent); + struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(tps_rtc->irq); /* Restore list of enabled interrupts before suspend */ return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS, -- cgit v1.2.3 From dfaf09ac8555141b7311bb69b456bd96886fd90c Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 21 Feb 2013 16:44:36 -0800 Subject: drivers/rtc/rtc-tps65910.c: remove unnecessary irq stat save and restore The driver stores the interrupt enable register before going to suspend and restore in resume. Also it enables alarm before going to suspend. The driver only write the Interrupt enable register for enabling ALARM and does not enable any other bits. So it is not require to save complete register and enable ALARM interrupt before suspend and restore in resume. Also ALARM interrupt already enable if alarm is enabled before going to suspend and hence it is not require to enable explictly in suspend. Removing such above code. Signed-off-by: Laxman Dewangan Cc: Mark Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-tps65910.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) (limited to 'drivers/rtc/rtc-tps65910.c') diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index 932a655aa41c..7ef42c25358c 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -28,8 +28,6 @@ struct tps65910_rtc { struct rtc_device *rtc; int irq; - /* To store the list of enabled interrupts */ - u32 irqstat; }; /* Total number of RTC registers needed to set time*/ @@ -309,35 +307,20 @@ static int tps65910_rtc_remove(struct platform_device *pdev) static int tps65910_rtc_suspend(struct device *dev) { - struct tps65910 *tps = dev_get_drvdata(dev->parent); struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev); - u8 alarm = TPS65910_RTC_INTERRUPTS_IT_ALARM; - int ret; if (device_may_wakeup(dev)) enable_irq_wake(tps_rtc->irq); - - /* Store current list of enabled interrupts*/ - ret = regmap_read(tps->regmap, TPS65910_RTC_INTERRUPTS, - &tps->rtc->irqstat); - if (ret < 0) - return ret; - - /* Enable RTC ALARM interrupt only */ - return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS, alarm); + return 0; } static int tps65910_rtc_resume(struct device *dev) { - struct tps65910 *tps = dev_get_drvdata(dev->parent); struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev); if (device_may_wakeup(dev)) disable_irq_wake(tps_rtc->irq); - - /* Restore list of enabled interrupts before suspend */ - return regmap_write(tps->regmap, TPS65910_RTC_INTERRUPTS, - tps->rtc->irqstat); + return 0; } static const struct dev_pm_ops tps65910_rtc_pm_ops = { -- cgit v1.2.3 From 176a9f20d29de594c07faaeb10fecff664c956c6 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 21 Feb 2013 16:44:37 -0800 Subject: drivers/rtc/rtc-tps65910.c: use sleep_pm_ops macro for initialising suspend/resume callbacks Use SET_SYSTEM_SLEEP_PM_OPS for setting suspend/resume callbacks for dev_pm_ops. Signed-off-by: Laxman Dewangan Cc: Mark Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-tps65910.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers/rtc/rtc-tps65910.c') diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index 7ef42c25358c..ff7cfe90b0c0 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -304,7 +305,6 @@ static int tps65910_rtc_remove(struct platform_device *pdev) } #ifdef CONFIG_PM_SLEEP - static int tps65910_rtc_suspend(struct device *dev) { struct tps65910_rtc *tps_rtc = dev_get_drvdata(dev); @@ -322,24 +322,19 @@ static int tps65910_rtc_resume(struct device *dev) disable_irq_wake(tps_rtc->irq); return 0; } +#endif static const struct dev_pm_ops tps65910_rtc_pm_ops = { - .suspend = tps65910_rtc_suspend, - .resume = tps65910_rtc_resume, + SET_SYSTEM_SLEEP_PM_OPS(tps65910_rtc_suspend, tps65910_rtc_resume) }; -#define DEV_PM_OPS (&tps65910_rtc_pm_ops) -#else -#define DEV_PM_OPS NULL -#endif - static struct platform_driver tps65910_rtc_driver = { .probe = tps65910_rtc_probe, .remove = tps65910_rtc_remove, .driver = { .owner = THIS_MODULE, .name = "tps65910-rtc", - .pm = DEV_PM_OPS, + .pm = &tps65910_rtc_pm_ops, }, }; -- cgit v1.2.3 From 225ccc28726ca8849e5bfc9148c343e258737f3b Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Thu, 21 Feb 2013 16:44:38 -0800 Subject: drivers/rtc/rtc-tps65910.c: set irq flag to IRQF_EARLY_RESUME during irq request All interrupt get disabled during system suspend and enabled during system resume. The enabling/disabling of interrupt happen in sequence of interrupt registration with framework. Therefore, in resume, the parent interrupt of this device enabled before the RTC irq interrupt enabled. If RTC is enabled for alarm wake and if system wake by alarm then there is interrupt pending for RTC. In resume, the parent interrupt get enabled before the rtc interrupt and hence ISR get served. In ISR, it founds that rtc interrupt is disabled and so it does not call the rtc isr handler and hence it misses the interrupt. Setting flag for early resume so that rtc interrupt get enabled before parent interrupt and so rtc interrupt get enabled when parent interrupt handler check for interrupt of device and call the rtc handler if it is there. This way it will not miss the interrupt. Signed-off-by: Laxman Dewangan Cc: Mark Brown Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-tps65910.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc/rtc-tps65910.c') diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index ff7cfe90b0c0..8bd8115329b5 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -267,7 +267,7 @@ static int tps65910_rtc_probe(struct platform_device *pdev) } ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, - tps65910_rtc_interrupt, IRQF_TRIGGER_LOW, + tps65910_rtc_interrupt, IRQF_TRIGGER_LOW | IRQF_EARLY_RESUME, dev_name(&pdev->dev), &pdev->dev); if (ret < 0) { dev_err(&pdev->dev, "IRQ is not free.\n"); -- cgit v1.2.3