aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/sh_tmu.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2012-08-05 19:41:20 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2012-09-03 19:36:02 -0400
commiteaa49a8cd1f98a6486413d902e7304df026a1fa9 (patch)
tree4a7a45fb9dafa742e698a5cc7d00890fb01a4b52 /drivers/clocksource/sh_tmu.c
parentadc78e6b9946a4b22e22403d961f3b03c469e5d3 (diff)
sh: TMU: Introduce clocksource/clock events suspend/resume routines
Introduce suspend/resume routines for SH TMU clock source and clock event device such that if those devices belong to a PM domain, the generic PM domains framework will be notified that the given domain may be turned off (during system suspend) or that it has to be turned on (during system resume). This change allows the A4R domain on SH7372 to be turned off during system suspend (tested on the Mackerel board) if the TMU clock source and/or clock event device is in use. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Magnus Damm <damm@opensource.se>
Diffstat (limited to 'drivers/clocksource/sh_tmu.c')
-rw-r--r--drivers/clocksource/sh_tmu.c54
1 files changed, 50 insertions, 4 deletions
diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c
index c1b51d49d106..7d700829bb41 100644
--- a/drivers/clocksource/sh_tmu.c
+++ b/drivers/clocksource/sh_tmu.c
@@ -33,6 +33,7 @@
33#include <linux/slab.h> 33#include <linux/slab.h>
34#include <linux/module.h> 34#include <linux/module.h>
35#include <linux/pm_domain.h> 35#include <linux/pm_domain.h>
36#include <linux/pm_runtime.h>
36 37
37struct sh_tmu_priv { 38struct sh_tmu_priv {
38 void __iomem *mapbase; 39 void __iomem *mapbase;
@@ -43,6 +44,7 @@ struct sh_tmu_priv {
43 unsigned long periodic; 44 unsigned long periodic;
44 struct clock_event_device ced; 45 struct clock_event_device ced;
45 struct clocksource cs; 46 struct clocksource cs;
47 bool cs_enabled;
46}; 48};
47 49
48static DEFINE_RAW_SPINLOCK(sh_tmu_lock); 50static DEFINE_RAW_SPINLOCK(sh_tmu_lock);
@@ -204,14 +206,40 @@ static int sh_tmu_clocksource_enable(struct clocksource *cs)
204 int ret; 206 int ret;
205 207
206 ret = sh_tmu_enable(p); 208 ret = sh_tmu_enable(p);
207 if (!ret) 209 if (!ret) {
208 __clocksource_updatefreq_hz(cs, p->rate); 210 __clocksource_updatefreq_hz(cs, p->rate);
211 p->cs_enabled = true;
212 }
209 return ret; 213 return ret;
210} 214}
211 215
212static void sh_tmu_clocksource_disable(struct clocksource *cs) 216static void sh_tmu_clocksource_disable(struct clocksource *cs)
213{ 217{
214 sh_tmu_disable(cs_to_sh_tmu(cs)); 218 struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
219
220 WARN_ON(!p->cs_enabled);
221
222 sh_tmu_disable(p);
223 p->cs_enabled = false;
224}
225
226static void sh_tmu_clocksource_suspend(struct clocksource *cs)
227{
228 struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
229
230 if (p->cs_enabled)
231 sh_tmu_disable(p);
232
233 pm_genpd_syscore_poweroff(&p->pdev->dev);
234}
235
236static void sh_tmu_clocksource_resume(struct clocksource *cs)
237{
238 struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
239
240 pm_genpd_syscore_poweron(&p->pdev->dev);
241 if (p->cs_enabled)
242 sh_tmu_enable(p);
215} 243}
216 244
217static int sh_tmu_register_clocksource(struct sh_tmu_priv *p, 245static int sh_tmu_register_clocksource(struct sh_tmu_priv *p,
@@ -224,6 +252,8 @@ static int sh_tmu_register_clocksource(struct sh_tmu_priv *p,
224 cs->read = sh_tmu_clocksource_read; 252 cs->read = sh_tmu_clocksource_read;
225 cs->enable = sh_tmu_clocksource_enable; 253 cs->enable = sh_tmu_clocksource_enable;
226 cs->disable = sh_tmu_clocksource_disable; 254 cs->disable = sh_tmu_clocksource_disable;
255 cs->suspend = sh_tmu_clocksource_suspend;
256 cs->resume = sh_tmu_clocksource_resume;
227 cs->mask = CLOCKSOURCE_MASK(32); 257 cs->mask = CLOCKSOURCE_MASK(32);
228 cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; 258 cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
229 259
@@ -301,6 +331,16 @@ static int sh_tmu_clock_event_next(unsigned long delta,
301 return 0; 331 return 0;
302} 332}
303 333
334static void sh_tmu_clock_event_suspend(struct clock_event_device *ced)
335{
336 pm_genpd_syscore_poweroff(&ced_to_sh_tmu(ced)->pdev->dev);
337}
338
339static void sh_tmu_clock_event_resume(struct clock_event_device *ced)
340{
341 pm_genpd_syscore_poweron(&ced_to_sh_tmu(ced)->pdev->dev);
342}
343
304static void sh_tmu_register_clockevent(struct sh_tmu_priv *p, 344static void sh_tmu_register_clockevent(struct sh_tmu_priv *p,
305 char *name, unsigned long rating) 345 char *name, unsigned long rating)
306{ 346{
@@ -316,6 +356,8 @@ static void sh_tmu_register_clockevent(struct sh_tmu_priv *p,
316 ced->cpumask = cpumask_of(0); 356 ced->cpumask = cpumask_of(0);
317 ced->set_next_event = sh_tmu_clock_event_next; 357 ced->set_next_event = sh_tmu_clock_event_next;
318 ced->set_mode = sh_tmu_clock_event_mode; 358 ced->set_mode = sh_tmu_clock_event_mode;
359 ced->suspend = sh_tmu_clock_event_suspend;
360 ced->resume = sh_tmu_clock_event_resume;
319 361
320 dev_info(&p->pdev->dev, "used for clock events\n"); 362 dev_info(&p->pdev->dev, "used for clock events\n");
321 363
@@ -407,8 +449,12 @@ static int __devinit sh_tmu_probe(struct platform_device *pdev)
407 struct sh_tmu_priv *p = platform_get_drvdata(pdev); 449 struct sh_tmu_priv *p = platform_get_drvdata(pdev);
408 int ret; 450 int ret;
409 451
410 if (!is_early_platform_device(pdev)) 452 if (!is_early_platform_device(pdev)) {
411 pm_genpd_dev_always_on(&pdev->dev, true); 453 struct sh_timer_config *cfg = pdev->dev.platform_data;
454
455 if (cfg->clocksource_rating || cfg->clockevent_rating)
456 pm_genpd_dev_always_on(&pdev->dev, true);
457 }
412 458
413 if (p) { 459 if (p) {
414 dev_info(&pdev->dev, "kept as earlytimer\n"); 460 dev_info(&pdev->dev, "kept as earlytimer\n");