aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomasz Figa <tomasz.figa@gmail.com>2013-06-16 19:11:31 -0400
committerTomasz Figa <tomasz.figa@gmail.com>2013-08-05 19:21:43 -0400
commit0b96258b420208ebaacc0ef4b21b67dba262badf (patch)
tree89bdeebfcbadacdfe614df5c998de38321f03163
parent6792e636d5bfc1b26c25e7ed056b358e1144c6df (diff)
clocksource: samsung_pwm_timer: Handle suspend/resume correctly
Current suspend/resume handling of the driver was broken, because: - periodic timer was being enabled in CLOCK_EVT_MODE_RESUME mode, which does not seem to be correct behavior looking at other platforms, - PWM divisors need to be restored, but they were not, - clockevent interrupt mask needs to be restored, but it was not, - clocksource was being restored in clockevent resume callback. This patch fixes issues mentioned above, making suspend/resume handling in the driver correct. Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com> Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com> Tested-by: Heiko Stuebner <heiko@sntech.de> Tested-by: Mark Brown <broonie@linaro.org> Tested-by: Sylwester Nawrocki <sylvester.nawrocki@gmail.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org>
-rw-r--r--drivers/clocksource/samsung_pwm_timer.c42
1 files changed, 28 insertions, 14 deletions
diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c
index b3112dc293ba..ac60f8b8a5f7 100644
--- a/drivers/clocksource/samsung_pwm_timer.c
+++ b/drivers/clocksource/samsung_pwm_timer.c
@@ -207,17 +207,6 @@ static int samsung_set_next_event(unsigned long cycles,
207 return 0; 207 return 0;
208} 208}
209 209
210static void samsung_timer_resume(void)
211{
212 /* event timer restart */
213 samsung_time_setup(pwm.event_id, pwm.clock_count_per_tick - 1);
214 samsung_time_start(pwm.event_id, true);
215
216 /* source timer restart */
217 samsung_time_setup(pwm.source_id, pwm.tcnt_max);
218 samsung_time_start(pwm.source_id, true);
219}
220
221static void samsung_set_mode(enum clock_event_mode mode, 210static void samsung_set_mode(enum clock_event_mode mode,
222 struct clock_event_device *evt) 211 struct clock_event_device *evt)
223{ 212{
@@ -234,20 +223,29 @@ static void samsung_set_mode(enum clock_event_mode mode,
234 223
235 case CLOCK_EVT_MODE_UNUSED: 224 case CLOCK_EVT_MODE_UNUSED:
236 case CLOCK_EVT_MODE_SHUTDOWN: 225 case CLOCK_EVT_MODE_SHUTDOWN:
237 break;
238
239 case CLOCK_EVT_MODE_RESUME: 226 case CLOCK_EVT_MODE_RESUME:
240 samsung_timer_resume();
241 break; 227 break;
242 } 228 }
243} 229}
244 230
231static void samsung_clockevent_resume(struct clock_event_device *cev)
232{
233 samsung_timer_set_prescale(pwm.event_id, pwm.tscaler_div);
234 samsung_timer_set_divisor(pwm.event_id, pwm.tdiv);
235
236 if (pwm.variant.has_tint_cstat) {
237 u32 mask = (1 << pwm.event_id);
238 writel(mask | (mask << 5), pwm.base + REG_TINT_CSTAT);
239 }
240}
241
245static struct clock_event_device time_event_device = { 242static struct clock_event_device time_event_device = {
246 .name = "samsung_event_timer", 243 .name = "samsung_event_timer",
247 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 244 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
248 .rating = 200, 245 .rating = 200,
249 .set_next_event = samsung_set_next_event, 246 .set_next_event = samsung_set_next_event,
250 .set_mode = samsung_set_mode, 247 .set_mode = samsung_set_mode,
248 .resume = samsung_clockevent_resume,
251}; 249};
252 250
253static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id) 251static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id)
@@ -298,6 +296,20 @@ static void __init samsung_clockevent_init(void)
298 } 296 }
299} 297}
300 298
299static void samsung_clocksource_suspend(struct clocksource *cs)
300{
301 samsung_time_stop(pwm.source_id);
302}
303
304static void samsung_clocksource_resume(struct clocksource *cs)
305{
306 samsung_timer_set_prescale(pwm.source_id, pwm.tscaler_div);
307 samsung_timer_set_divisor(pwm.source_id, pwm.tdiv);
308
309 samsung_time_setup(pwm.source_id, pwm.tcnt_max);
310 samsung_time_start(pwm.source_id, true);
311}
312
301static cycle_t samsung_clocksource_read(struct clocksource *c) 313static cycle_t samsung_clocksource_read(struct clocksource *c)
302{ 314{
303 return ~readl_relaxed(pwm.source_reg); 315 return ~readl_relaxed(pwm.source_reg);
@@ -307,6 +319,8 @@ static struct clocksource samsung_clocksource = {
307 .name = "samsung_clocksource_timer", 319 .name = "samsung_clocksource_timer",
308 .rating = 250, 320 .rating = 250,
309 .read = samsung_clocksource_read, 321 .read = samsung_clocksource_read,
322 .suspend = samsung_clocksource_suspend,
323 .resume = samsung_clocksource_resume,
310 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 324 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
311}; 325};
312 326