diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clocksource/sh_tmu.c | 54 |
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 | ||
37 | struct sh_tmu_priv { | 38 | struct 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 | ||
48 | static DEFINE_RAW_SPINLOCK(sh_tmu_lock); | 50 | static 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 | ||
212 | static void sh_tmu_clocksource_disable(struct clocksource *cs) | 216 | static 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 | |||
226 | static 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 | |||
236 | static 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 | ||
217 | static int sh_tmu_register_clocksource(struct sh_tmu_priv *p, | 245 | static 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 | ||
334 | static 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 | |||
339 | static 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 | |||
304 | static void sh_tmu_register_clockevent(struct sh_tmu_priv *p, | 344 | static 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"); |