aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/clocksource/samsung_pwm_timer.c157
1 files changed, 74 insertions, 83 deletions
diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c
index d9048b843546..e3257fae04e6 100644
--- a/drivers/clocksource/samsung_pwm_timer.c
+++ b/drivers/clocksource/samsung_pwm_timer.c
@@ -52,21 +52,25 @@
52DEFINE_SPINLOCK(samsung_pwm_lock); 52DEFINE_SPINLOCK(samsung_pwm_lock);
53EXPORT_SYMBOL(samsung_pwm_lock); 53EXPORT_SYMBOL(samsung_pwm_lock);
54 54
55struct samsung_timer_source { 55struct samsung_pwm_clocksource {
56 void __iomem *base;
57 unsigned int irq[SAMSUNG_PWM_NUM];
58 struct samsung_pwm_variant variant;
59
60 struct clk *timerclk;
61
56 unsigned int event_id; 62 unsigned int event_id;
57 unsigned int source_id; 63 unsigned int source_id;
58 unsigned int tcnt_max; 64 unsigned int tcnt_max;
59 unsigned int tscaler_div; 65 unsigned int tscaler_div;
60 unsigned int tdiv; 66 unsigned int tdiv;
67
68 unsigned long clock_count_per_tick;
61}; 69};
62 70
63static struct samsung_pwm *pwm; 71static struct samsung_pwm_clocksource pwm;
64static struct clk *timerclk;
65static struct samsung_timer_source timer_source;
66static unsigned long clock_count_per_tick;
67 72
68static void samsung_timer_set_prescale(struct samsung_pwm *pwm, 73static void samsung_timer_set_prescale(unsigned int channel, u16 prescale)
69 unsigned int channel, u16 prescale)
70{ 74{
71 unsigned long flags; 75 unsigned long flags;
72 u8 shift = 0; 76 u8 shift = 0;
@@ -77,30 +81,29 @@ static void samsung_timer_set_prescale(struct samsung_pwm *pwm,
77 81
78 spin_lock_irqsave(&samsung_pwm_lock, flags); 82 spin_lock_irqsave(&samsung_pwm_lock, flags);
79 83
80 reg = readl(pwm->base + REG_TCFG0); 84 reg = readl(pwm.base + REG_TCFG0);
81 reg &= ~(TCFG0_PRESCALER_MASK << shift); 85 reg &= ~(TCFG0_PRESCALER_MASK << shift);
82 reg |= (prescale - 1) << shift; 86 reg |= (prescale - 1) << shift;
83 writel(reg, pwm->base + REG_TCFG0); 87 writel(reg, pwm.base + REG_TCFG0);
84 88
85 spin_unlock_irqrestore(&samsung_pwm_lock, flags); 89 spin_unlock_irqrestore(&samsung_pwm_lock, flags);
86} 90}
87 91
88static void samsung_timer_set_divisor(struct samsung_pwm *pwm, 92static void samsung_timer_set_divisor(unsigned int channel, u8 divisor)
89 unsigned int channel, u8 divisor)
90{ 93{
91 u8 shift = TCFG1_SHIFT(channel); 94 u8 shift = TCFG1_SHIFT(channel);
92 unsigned long flags; 95 unsigned long flags;
93 u32 reg; 96 u32 reg;
94 u8 bits; 97 u8 bits;
95 98
96 bits = (fls(divisor) - 1) - pwm->variant.div_base; 99 bits = (fls(divisor) - 1) - pwm.variant.div_base;
97 100
98 spin_lock_irqsave(&samsung_pwm_lock, flags); 101 spin_lock_irqsave(&samsung_pwm_lock, flags);
99 102
100 reg = readl(pwm->base + REG_TCFG1); 103 reg = readl(pwm.base + REG_TCFG1);
101 reg &= ~(TCFG1_MUX_MASK << shift); 104 reg &= ~(TCFG1_MUX_MASK << shift);
102 reg |= bits << shift; 105 reg |= bits << shift;
103 writel(reg, pwm->base + REG_TCFG1); 106 writel(reg, pwm.base + REG_TCFG1);
104 107
105 spin_unlock_irqrestore(&samsung_pwm_lock, flags); 108 spin_unlock_irqrestore(&samsung_pwm_lock, flags);
106} 109}
@@ -115,9 +118,9 @@ static void samsung_time_stop(unsigned int channel)
115 118
116 spin_lock_irqsave(&samsung_pwm_lock, flags); 119 spin_lock_irqsave(&samsung_pwm_lock, flags);
117 120
118 tcon = __raw_readl(pwm->base + REG_TCON); 121 tcon = __raw_readl(pwm.base + REG_TCON);
119 tcon &= ~TCON_START(channel); 122 tcon &= ~TCON_START(channel);
120 __raw_writel(tcon, pwm->base + REG_TCON); 123 __raw_writel(tcon, pwm.base + REG_TCON);
121 124
122 spin_unlock_irqrestore(&samsung_pwm_lock, flags); 125 spin_unlock_irqrestore(&samsung_pwm_lock, flags);
123} 126}
@@ -133,16 +136,16 @@ static void samsung_time_setup(unsigned int channel, unsigned long tcnt)
133 136
134 spin_lock_irqsave(&samsung_pwm_lock, flags); 137 spin_lock_irqsave(&samsung_pwm_lock, flags);
135 138
136 tcon = __raw_readl(pwm->base + REG_TCON); 139 tcon = __raw_readl(pwm.base + REG_TCON);
137 140
138 tcnt--; 141 tcnt--;
139 142
140 tcon &= ~(TCON_START(tcon_chan) | TCON_AUTORELOAD(tcon_chan)); 143 tcon &= ~(TCON_START(tcon_chan) | TCON_AUTORELOAD(tcon_chan));
141 tcon |= TCON_MANUALUPDATE(tcon_chan); 144 tcon |= TCON_MANUALUPDATE(tcon_chan);
142 145
143 __raw_writel(tcnt, pwm->base + REG_TCNTB(channel)); 146 __raw_writel(tcnt, pwm.base + REG_TCNTB(channel));
144 __raw_writel(tcnt, pwm->base + REG_TCMPB(channel)); 147 __raw_writel(tcnt, pwm.base + REG_TCMPB(channel));
145 __raw_writel(tcon, pwm->base + REG_TCON); 148 __raw_writel(tcon, pwm.base + REG_TCON);
146 149
147 spin_unlock_irqrestore(&samsung_pwm_lock, flags); 150 spin_unlock_irqrestore(&samsung_pwm_lock, flags);
148} 151}
@@ -157,7 +160,7 @@ static void samsung_time_start(unsigned int channel, bool periodic)
157 160
158 spin_lock_irqsave(&samsung_pwm_lock, flags); 161 spin_lock_irqsave(&samsung_pwm_lock, flags);
159 162
160 tcon = __raw_readl(pwm->base + REG_TCON); 163 tcon = __raw_readl(pwm.base + REG_TCON);
161 164
162 tcon &= ~TCON_MANUALUPDATE(channel); 165 tcon &= ~TCON_MANUALUPDATE(channel);
163 tcon |= TCON_START(channel); 166 tcon |= TCON_START(channel);
@@ -167,7 +170,7 @@ static void samsung_time_start(unsigned int channel, bool periodic)
167 else 170 else
168 tcon &= ~TCON_AUTORELOAD(channel); 171 tcon &= ~TCON_AUTORELOAD(channel);
169 172
170 __raw_writel(tcon, pwm->base + REG_TCON); 173 __raw_writel(tcon, pwm.base + REG_TCON);
171 174
172 spin_unlock_irqrestore(&samsung_pwm_lock, flags); 175 spin_unlock_irqrestore(&samsung_pwm_lock, flags);
173} 176}
@@ -175,8 +178,8 @@ static void samsung_time_start(unsigned int channel, bool periodic)
175static int samsung_set_next_event(unsigned long cycles, 178static int samsung_set_next_event(unsigned long cycles,
176 struct clock_event_device *evt) 179 struct clock_event_device *evt)
177{ 180{
178 samsung_time_setup(timer_source.event_id, cycles); 181 samsung_time_setup(pwm.event_id, cycles);
179 samsung_time_start(timer_source.event_id, false); 182 samsung_time_start(pwm.event_id, false);
180 183
181 return 0; 184 return 0;
182} 185}
@@ -184,23 +187,23 @@ static int samsung_set_next_event(unsigned long cycles,
184static void samsung_timer_resume(void) 187static void samsung_timer_resume(void)
185{ 188{
186 /* event timer restart */ 189 /* event timer restart */
187 samsung_time_setup(timer_source.event_id, clock_count_per_tick); 190 samsung_time_setup(pwm.event_id, pwm.clock_count_per_tick);
188 samsung_time_start(timer_source.event_id, true); 191 samsung_time_start(pwm.event_id, true);
189 192
190 /* source timer restart */ 193 /* source timer restart */
191 samsung_time_setup(timer_source.source_id, timer_source.tcnt_max); 194 samsung_time_setup(pwm.source_id, pwm.tcnt_max);
192 samsung_time_start(timer_source.source_id, true); 195 samsung_time_start(pwm.source_id, true);
193} 196}
194 197
195static void samsung_set_mode(enum clock_event_mode mode, 198static void samsung_set_mode(enum clock_event_mode mode,
196 struct clock_event_device *evt) 199 struct clock_event_device *evt)
197{ 200{
198 samsung_time_stop(timer_source.event_id); 201 samsung_time_stop(pwm.event_id);
199 202
200 switch (mode) { 203 switch (mode) {
201 case CLOCK_EVT_MODE_PERIODIC: 204 case CLOCK_EVT_MODE_PERIODIC:
202 samsung_time_setup(timer_source.event_id, clock_count_per_tick); 205 samsung_time_setup(pwm.event_id, pwm.clock_count_per_tick);
203 samsung_time_start(timer_source.event_id, true); 206 samsung_time_start(pwm.event_id, true);
204 break; 207 break;
205 208
206 case CLOCK_EVT_MODE_ONESHOT: 209 case CLOCK_EVT_MODE_ONESHOT:
@@ -228,9 +231,9 @@ static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id)
228{ 231{
229 struct clock_event_device *evt = dev_id; 232 struct clock_event_device *evt = dev_id;
230 233
231 if (pwm->variant.has_tint_cstat) { 234 if (pwm.variant.has_tint_cstat) {
232 u32 mask = (1 << timer_source.event_id); 235 u32 mask = (1 << pwm.event_id);
233 writel(mask | (mask << 5), pwm->base + REG_TINT_CSTAT); 236 writel(mask | (mask << 5), pwm.base + REG_TINT_CSTAT);
234 } 237 }
235 238
236 evt->event_handler(evt); 239 evt->event_handler(evt);
@@ -251,39 +254,37 @@ static void __init samsung_clockevent_init(void)
251 unsigned long clock_rate; 254 unsigned long clock_rate;
252 unsigned int irq_number; 255 unsigned int irq_number;
253 256
254 pclk = clk_get_rate(timerclk); 257 pclk = clk_get_rate(pwm.timerclk);
255 258
256 samsung_timer_set_prescale(pwm, timer_source.event_id, 259 samsung_timer_set_prescale(pwm.event_id, pwm.tscaler_div);
257 timer_source.tscaler_div); 260 samsung_timer_set_divisor(pwm.event_id, pwm.tdiv);
258 samsung_timer_set_divisor(pwm, timer_source.event_id,
259 timer_source.tdiv);
260 261
261 clock_rate = pclk / (timer_source.tscaler_div * timer_source.tdiv); 262 clock_rate = pclk / (pwm.tscaler_div * pwm.tdiv);
262 clock_count_per_tick = clock_rate / HZ; 263 pwm.clock_count_per_tick = clock_rate / HZ;
263 264
264 time_event_device.cpumask = cpumask_of(0); 265 time_event_device.cpumask = cpumask_of(0);
265 clockevents_config_and_register(&time_event_device, clock_rate, 1, -1); 266 clockevents_config_and_register(&time_event_device, clock_rate, 1, -1);
266 267
267 irq_number = pwm->irq[timer_source.event_id]; 268 irq_number = pwm.irq[pwm.event_id];
268 setup_irq(irq_number, &samsung_clock_event_irq); 269 setup_irq(irq_number, &samsung_clock_event_irq);
269 270
270 if (pwm->variant.has_tint_cstat) { 271 if (pwm.variant.has_tint_cstat) {
271 u32 mask = (1 << timer_source.event_id); 272 u32 mask = (1 << pwm.event_id);
272 writel(mask | (mask << 5), pwm->base + REG_TINT_CSTAT); 273 writel(mask | (mask << 5), pwm.base + REG_TINT_CSTAT);
273 } 274 }
274} 275}
275 276
276static void __iomem *samsung_timer_reg(void) 277static void __iomem *samsung_timer_reg(void)
277{ 278{
278 switch (timer_source.source_id) { 279 switch (pwm.source_id) {
279 case 0: 280 case 0:
280 case 1: 281 case 1:
281 case 2: 282 case 2:
282 case 3: 283 case 3:
283 return pwm->base + timer_source.source_id * 0x0c + 0x14; 284 return pwm.base + pwm.source_id * 0x0c + 0x14;
284 285
285 case 4: 286 case 4:
286 return pwm->base + 0x40; 287 return pwm.base + 0x40;
287 288
288 default: 289 default:
289 BUG(); 290 BUG();
@@ -314,23 +315,21 @@ static void __init samsung_clocksource_init(void)
314 unsigned long clock_rate; 315 unsigned long clock_rate;
315 int ret; 316 int ret;
316 317
317 pclk = clk_get_rate(timerclk); 318 pclk = clk_get_rate(pwm.timerclk);
318 319
319 samsung_timer_set_prescale(pwm, timer_source.source_id, 320 samsung_timer_set_prescale(pwm.source_id, pwm.tscaler_div);
320 timer_source.tscaler_div); 321 samsung_timer_set_divisor(pwm.source_id, pwm.tdiv);
321 samsung_timer_set_divisor(pwm, timer_source.source_id,
322 timer_source.tdiv);
323 322
324 clock_rate = pclk / (timer_source.tscaler_div * timer_source.tdiv); 323 clock_rate = pclk / (pwm.tscaler_div * pwm.tdiv);
325 324
326 samsung_time_setup(timer_source.source_id, timer_source.tcnt_max); 325 samsung_time_setup(pwm.source_id, pwm.tcnt_max);
327 samsung_time_start(timer_source.source_id, true); 326 samsung_time_start(pwm.source_id, true);
328 327
329 setup_sched_clock(samsung_read_sched_clock, 328 setup_sched_clock(samsung_read_sched_clock,
330 pwm->variant.bits, clock_rate); 329 pwm.variant.bits, clock_rate);
331 330
332 ret = clocksource_mmio_init(reg, "samsung_clocksource_timer", 331 ret = clocksource_mmio_init(reg, "samsung_clocksource_timer",
333 clock_rate, 250, pwm->variant.bits, 332 clock_rate, 250, pwm.variant.bits,
334 clocksource_mmio_readl_down); 333 clocksource_mmio_readl_down);
335 if (ret) 334 if (ret)
336 panic("samsung_clocksource_timer: can't register clocksource\n"); 335 panic("samsung_clocksource_timer: can't register clocksource\n");
@@ -338,19 +337,19 @@ static void __init samsung_clocksource_init(void)
338 337
339static void __init samsung_timer_resources(void) 338static void __init samsung_timer_resources(void)
340{ 339{
341 timerclk = clk_get(NULL, "timers"); 340 pwm.timerclk = clk_get(NULL, "timers");
342 if (IS_ERR(timerclk)) 341 if (IS_ERR(pwm.timerclk))
343 panic("failed to get timers clock for timer"); 342 panic("failed to get timers clock for timer");
344 343
345 clk_prepare_enable(timerclk); 344 clk_prepare_enable(pwm.timerclk);
346 345
347 timer_source.tcnt_max = (1UL << pwm->variant.bits) - 1; 346 pwm.tcnt_max = (1UL << pwm.variant.bits) - 1;
348 if (pwm->variant.bits == 16) { 347 if (pwm.variant.bits == 16) {
349 timer_source.tscaler_div = 25; 348 pwm.tscaler_div = 25;
350 timer_source.tdiv = 2; 349 pwm.tdiv = 2;
351 } else { 350 } else {
352 timer_source.tscaler_div = 2; 351 pwm.tscaler_div = 2;
353 timer_source.tdiv = 1; 352 pwm.tdiv = 1;
354 } 353 }
355} 354}
356 355
@@ -362,20 +361,17 @@ static void __init samsung_pwm_clocksource_init(void)
362 u8 mask; 361 u8 mask;
363 int channel; 362 int channel;
364 363
365 if (!pwm) 364 mask = ~pwm.variant.output_mask & ((1 << SAMSUNG_PWM_NUM) - 1);
366 panic("no pwm clocksource device found");
367
368 mask = ~pwm->variant.output_mask & ((1 << SAMSUNG_PWM_NUM) - 1);
369 channel = fls(mask) - 1; 365 channel = fls(mask) - 1;
370 if (channel < 0) 366 if (channel < 0)
371 panic("failed to find PWM channel for clocksource"); 367 panic("failed to find PWM channel for clocksource");
372 timer_source.source_id = channel; 368 pwm.source_id = channel;
373 369
374 mask &= ~(1 << channel); 370 mask &= ~(1 << channel);
375 channel = fls(mask) - 1; 371 channel = fls(mask) - 1;
376 if (channel < 0) 372 if (channel < 0)
377 panic("failed to find PWM channel for clock event"); 373 panic("failed to find PWM channel for clock event");
378 timer_source.event_id = channel; 374 pwm.event_id = channel;
379 375
380 samsung_timer_resources(); 376 samsung_timer_resources();
381 samsung_clockevent_init(); 377 samsung_clockevent_init();
@@ -391,14 +387,9 @@ static void __init samsung_pwm_alloc(struct device_node *np,
391 u32 val; 387 u32 val;
392 int i; 388 int i;
393 389
394 pwm = kzalloc(sizeof(*pwm), GFP_KERNEL); 390 memcpy(&pwm.variant, variant, sizeof(pwm.variant));
395 if (!pwm) {
396 pr_err("%s: could not allocate PWM device struct\n", __func__);
397 return;
398 }
399 memcpy(&pwm->variant, variant, sizeof(pwm->variant));
400 for (i = 0; i < SAMSUNG_PWM_NUM; ++i) 391 for (i = 0; i < SAMSUNG_PWM_NUM; ++i)
401 pwm->irq[i] = irq_of_parse_and_map(np, i); 392 pwm.irq[i] = irq_of_parse_and_map(np, i);
402 393
403 of_property_for_each_u32(np, "samsung,pwm-outputs", prop, cur, val) { 394 of_property_for_each_u32(np, "samsung,pwm-outputs", prop, cur, val) {
404 if (val >= SAMSUNG_PWM_NUM) { 395 if (val >= SAMSUNG_PWM_NUM) {
@@ -406,7 +397,7 @@ static void __init samsung_pwm_alloc(struct device_node *np,
406 __func__); 397 __func__);
407 continue; 398 continue;
408 } 399 }
409 pwm->variant.output_mask |= 1 << val; 400 pwm.variant.output_mask |= 1 << val;
410 } 401 }
411 402
412 of_address_to_resource(np, 0, &res); 403 of_address_to_resource(np, 0, &res);
@@ -416,8 +407,8 @@ static void __init samsung_pwm_alloc(struct device_node *np,
416 return; 407 return;
417 } 408 }
418 409
419 pwm->base = ioremap(res.start, resource_size(&res)); 410 pwm.base = ioremap(res.start, resource_size(&res));
420 if (!pwm->base) { 411 if (!pwm.base) {
421 pr_err("%s: failed to map PWM registers\n", __func__); 412 pr_err("%s: failed to map PWM registers\n", __func__);
422 release_mem_region(res.start, resource_size(&res)); 413 release_mem_region(res.start, resource_size(&res));
423 return; 414 return;