aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2013-08-14 02:33:07 -0400
committerOlof Johansson <olof@lixom.net>2013-08-14 02:33:07 -0400
commit8b2496a22810531cb9157191cd0264bae8efeca0 (patch)
tree04b3e07e094df65b2ea083eea30af6ac9a15c34e /drivers/clocksource
parentbee22087faf5bbf33fcb61e6c5e8f8ef7ebd77a5 (diff)
parent4380c39ad3efbe58d7ed3b6adf6e602b23402b1e (diff)
Merge tag 'v3.12-pwm-cleanup-for-olof' of git://github.com/tom3q/linux into next/cleanup
From Tomasz Figa: Here is the Samsung PWM cleanup series. Particular patches of the series involve following modifications: - fixing up few things in samsung_pwm_timer clocksource driver, - moving remaining Samsung platforms to the new clocksource driver, - removing old clocksource driver, - adding new multiplatform- and DT-aware PWM driver, - moving all Samsung platforms to use the new PWM driver, - removing old PWM driver, - removing all PWM-related code that is not used anymore. * tag 'v3.12-pwm-cleanup-for-olof' of git://github.com/tom3q/linux: (684 commits) ARM: SAMSUNG: Remove plat/regs-timer.h header ARM: SAMSUNG: Remove remaining uses of plat/regs-timer.h header ARM: SAMSUNG: Remove pwm-clock infrastructure ARM: SAMSUNG: Remove old PWM timer platform devices pwm: Remove superseded pwm-samsung-legacy driver ARM: SAMSUNG: Modify board files to use new PWM platform device ARM: SAMSUNG: Rework private data handling in dev-backlight pwm: Add new pwm-samsung driver pwm: samsung: Rename to pwm-samsung-legacy ARM: SAMSUNG: Remove unused PWM timer IRQ chip code ARM: SAMSUNG: Remove old samsung-time driver ARM: SAMSUNG: Move all platforms to new clocksource driver ARM: SAMSUNG: Set PWM platform data ARM: SAMSUNG: Add new PWM platform device ARM: SAMSUNG: Unify base address definitions of timer block clocksource: samsung_pwm_timer: Handle suspend/resume correctly clocksource: samsung_pwm_timer: Do not use clocksource_mmio clocksource: samsung_pwm_timer: Cache clocksource register address clocksource: samsung_pwm_timer: Correct definition of AUTORELOAD bit clocksource: samsung_pwm_timer: Do not request PWM mem region + v3.11-rc4 Conflicts: arch/arm/Kconfig.debug Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'drivers/clocksource')
-rw-r--r--drivers/clocksource/Kconfig1
-rw-r--r--drivers/clocksource/samsung_pwm_timer.c108
2 files changed, 59 insertions, 50 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index b7b9b040a89b..41c69469ce20 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -99,7 +99,6 @@ config CLKSRC_EXYNOS_MCT
99 99
100config CLKSRC_SAMSUNG_PWM 100config CLKSRC_SAMSUNG_PWM
101 bool 101 bool
102 select CLKSRC_MMIO
103 help 102 help
104 This is a new clocksource driver for the PWM timer found in 103 This is a new clocksource driver for the PWM timer found in
105 Samsung S3C, S5P and Exynos SoCs, replacing an earlier driver 104 Samsung S3C, S5P and Exynos SoCs, replacing an earlier driver
diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c
index 584b5472eea3..ac60f8b8a5f7 100644
--- a/drivers/clocksource/samsung_pwm_timer.c
+++ b/drivers/clocksource/samsung_pwm_timer.c
@@ -44,16 +44,28 @@
44#define TCFG1_SHIFT(x) ((x) * 4) 44#define TCFG1_SHIFT(x) ((x) * 4)
45#define TCFG1_MUX_MASK 0xf 45#define TCFG1_MUX_MASK 0xf
46 46
47/*
48 * Each channel occupies 4 bits in TCON register, but there is a gap of 4
49 * bits (one channel) after channel 0, so channels have different numbering
50 * when accessing TCON register.
51 *
52 * In addition, the location of autoreload bit for channel 4 (TCON channel 5)
53 * in its set of bits is 2 as opposed to 3 for other channels.
54 */
47#define TCON_START(chan) (1 << (4 * (chan) + 0)) 55#define TCON_START(chan) (1 << (4 * (chan) + 0))
48#define TCON_MANUALUPDATE(chan) (1 << (4 * (chan) + 1)) 56#define TCON_MANUALUPDATE(chan) (1 << (4 * (chan) + 1))
49#define TCON_INVERT(chan) (1 << (4 * (chan) + 2)) 57#define TCON_INVERT(chan) (1 << (4 * (chan) + 2))
50#define TCON_AUTORELOAD(chan) (1 << (4 * (chan) + 3)) 58#define _TCON_AUTORELOAD(chan) (1 << (4 * (chan) + 3))
59#define _TCON_AUTORELOAD4(chan) (1 << (4 * (chan) + 2))
60#define TCON_AUTORELOAD(chan) \
61 ((chan < 5) ? _TCON_AUTORELOAD(chan) : _TCON_AUTORELOAD4(chan))
51 62
52DEFINE_SPINLOCK(samsung_pwm_lock); 63DEFINE_SPINLOCK(samsung_pwm_lock);
53EXPORT_SYMBOL(samsung_pwm_lock); 64EXPORT_SYMBOL(samsung_pwm_lock);
54 65
55struct samsung_pwm_clocksource { 66struct samsung_pwm_clocksource {
56 void __iomem *base; 67 void __iomem *base;
68 void __iomem *source_reg;
57 unsigned int irq[SAMSUNG_PWM_NUM]; 69 unsigned int irq[SAMSUNG_PWM_NUM];
58 struct samsung_pwm_variant variant; 70 struct samsung_pwm_variant variant;
59 71
@@ -195,17 +207,6 @@ static int samsung_set_next_event(unsigned long cycles,
195 return 0; 207 return 0;
196} 208}
197 209
198static void samsung_timer_resume(void)
199{
200 /* event timer restart */
201 samsung_time_setup(pwm.event_id, pwm.clock_count_per_tick - 1);
202 samsung_time_start(pwm.event_id, true);
203
204 /* source timer restart */
205 samsung_time_setup(pwm.source_id, pwm.tcnt_max);
206 samsung_time_start(pwm.source_id, true);
207}
208
209static void samsung_set_mode(enum clock_event_mode mode, 210static void samsung_set_mode(enum clock_event_mode mode,
210 struct clock_event_device *evt) 211 struct clock_event_device *evt)
211{ 212{
@@ -222,20 +223,29 @@ static void samsung_set_mode(enum clock_event_mode mode,
222 223
223 case CLOCK_EVT_MODE_UNUSED: 224 case CLOCK_EVT_MODE_UNUSED:
224 case CLOCK_EVT_MODE_SHUTDOWN: 225 case CLOCK_EVT_MODE_SHUTDOWN:
225 break;
226
227 case CLOCK_EVT_MODE_RESUME: 226 case CLOCK_EVT_MODE_RESUME:
228 samsung_timer_resume();
229 break; 227 break;
230 } 228 }
231} 229}
232 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
233static struct clock_event_device time_event_device = { 242static struct clock_event_device time_event_device = {
234 .name = "samsung_event_timer", 243 .name = "samsung_event_timer",
235 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 244 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
236 .rating = 200, 245 .rating = 200,
237 .set_next_event = samsung_set_next_event, 246 .set_next_event = samsung_set_next_event,
238 .set_mode = samsung_set_mode, 247 .set_mode = samsung_set_mode,
248 .resume = samsung_clockevent_resume,
239}; 249};
240 250
241static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id) 251static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id)
@@ -286,23 +296,34 @@ static void __init samsung_clockevent_init(void)
286 } 296 }
287} 297}
288 298
289static void __iomem *samsung_timer_reg(void) 299static void samsung_clocksource_suspend(struct clocksource *cs)
290{ 300{
291 switch (pwm.source_id) { 301 samsung_time_stop(pwm.source_id);
292 case 0:
293 case 1:
294 case 2:
295 case 3:
296 return pwm.base + pwm.source_id * 0x0c + 0x14;
297
298 case 4:
299 return pwm.base + 0x40;
300
301 default:
302 BUG();
303 }
304} 302}
305 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
313static cycle_t samsung_clocksource_read(struct clocksource *c)
314{
315 return ~readl_relaxed(pwm.source_reg);
316}
317
318static struct clocksource samsung_clocksource = {
319 .name = "samsung_clocksource_timer",
320 .rating = 250,
321 .read = samsung_clocksource_read,
322 .suspend = samsung_clocksource_suspend,
323 .resume = samsung_clocksource_resume,
324 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
325};
326
306/* 327/*
307 * Override the global weak sched_clock symbol with this 328 * Override the global weak sched_clock symbol with this
308 * local implementation which uses the clocksource to get some 329 * local implementation which uses the clocksource to get some
@@ -312,17 +333,11 @@ static void __iomem *samsung_timer_reg(void)
312 */ 333 */
313static u32 notrace samsung_read_sched_clock(void) 334static u32 notrace samsung_read_sched_clock(void)
314{ 335{
315 void __iomem *reg = samsung_timer_reg(); 336 return samsung_clocksource_read(NULL);
316
317 if (!reg)
318 return 0;
319
320 return ~__raw_readl(reg);
321} 337}
322 338
323static void __init samsung_clocksource_init(void) 339static void __init samsung_clocksource_init(void)
324{ 340{
325 void __iomem *reg = samsung_timer_reg();
326 unsigned long pclk; 341 unsigned long pclk;
327 unsigned long clock_rate; 342 unsigned long clock_rate;
328 int ret; 343 int ret;
@@ -337,12 +352,16 @@ static void __init samsung_clocksource_init(void)
337 samsung_time_setup(pwm.source_id, pwm.tcnt_max); 352 samsung_time_setup(pwm.source_id, pwm.tcnt_max);
338 samsung_time_start(pwm.source_id, true); 353 samsung_time_start(pwm.source_id, true);
339 354
355 if (pwm.source_id == 4)
356 pwm.source_reg = pwm.base + 0x40;
357 else
358 pwm.source_reg = pwm.base + pwm.source_id * 0x0c + 0x14;
359
340 setup_sched_clock(samsung_read_sched_clock, 360 setup_sched_clock(samsung_read_sched_clock,
341 pwm.variant.bits, clock_rate); 361 pwm.variant.bits, clock_rate);
342 362
343 ret = clocksource_mmio_init(reg, "samsung_clocksource_timer", 363 samsung_clocksource.mask = CLOCKSOURCE_MASK(pwm.variant.bits);
344 clock_rate, 250, pwm.variant.bits, 364 ret = clocksource_register_hz(&samsung_clocksource, clock_rate);
345 clocksource_mmio_readl_down);
346 if (ret) 365 if (ret)
347 panic("samsung_clocksource_timer: can't register clocksource\n"); 366 panic("samsung_clocksource_timer: can't register clocksource\n");
348} 367}
@@ -404,7 +423,6 @@ void __init samsung_pwm_clocksource_init(void __iomem *base,
404static void __init samsung_pwm_alloc(struct device_node *np, 423static void __init samsung_pwm_alloc(struct device_node *np,
405 const struct samsung_pwm_variant *variant) 424 const struct samsung_pwm_variant *variant)
406{ 425{
407 struct resource res;
408 struct property *prop; 426 struct property *prop;
409 const __be32 *cur; 427 const __be32 *cur;
410 u32 val; 428 u32 val;
@@ -423,17 +441,9 @@ static void __init samsung_pwm_alloc(struct device_node *np,
423 pwm.variant.output_mask |= 1 << val; 441 pwm.variant.output_mask |= 1 << val;
424 } 442 }
425 443
426 of_address_to_resource(np, 0, &res); 444 pwm.base = of_iomap(np, 0);
427 if (!request_mem_region(res.start,
428 resource_size(&res), "samsung-pwm")) {
429 pr_err("%s: failed to request IO mem region\n", __func__);
430 return;
431 }
432
433 pwm.base = ioremap(res.start, resource_size(&res));
434 if (!pwm.base) { 445 if (!pwm.base) {
435 pr_err("%s: failed to map PWM registers\n", __func__); 446 pr_err("%s: failed to map PWM registers\n", __func__);
436 release_mem_region(res.start, resource_size(&res));
437 return; 447 return;
438 } 448 }
439 449