aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clocksource')
-rw-r--r--drivers/clocksource/sh_mtu2.c184
1 files changed, 130 insertions, 54 deletions
diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c
index 14cc7b6f703b..7cc6d9429f81 100644
--- a/drivers/clocksource/sh_mtu2.c
+++ b/drivers/clocksource/sh_mtu2.c
@@ -54,6 +54,9 @@ struct sh_mtu2_device {
54 54
55 struct sh_mtu2_channel *channels; 55 struct sh_mtu2_channel *channels;
56 unsigned int num_channels; 56 unsigned int num_channels;
57
58 bool legacy;
59 bool has_clockevent;
57}; 60};
58 61
59static DEFINE_RAW_SPINLOCK(sh_mtu2_lock); 62static DEFINE_RAW_SPINLOCK(sh_mtu2_lock);
@@ -163,8 +166,12 @@ static inline unsigned long sh_mtu2_read(struct sh_mtu2_channel *ch, int reg_nr)
163{ 166{
164 unsigned long offs; 167 unsigned long offs;
165 168
166 if (reg_nr == TSTR) 169 if (reg_nr == TSTR) {
167 return ioread8(ch->mtu->mapbase); 170 if (ch->mtu->legacy)
171 return ioread8(ch->mtu->mapbase);
172 else
173 return ioread8(ch->mtu->mapbase + 0x280);
174 }
168 175
169 offs = mtu2_reg_offs[reg_nr]; 176 offs = mtu2_reg_offs[reg_nr];
170 177
@@ -180,8 +187,10 @@ static inline void sh_mtu2_write(struct sh_mtu2_channel *ch, int reg_nr,
180 unsigned long offs; 187 unsigned long offs;
181 188
182 if (reg_nr == TSTR) { 189 if (reg_nr == TSTR) {
183 iowrite8(value, ch->mtu->mapbase); 190 if (ch->mtu->legacy)
184 return; 191 return iowrite8(value, ch->mtu->mapbase);
192 else
193 return iowrite8(value, ch->mtu->mapbase + 0x280);
185 } 194 }
186 195
187 offs = mtu2_reg_offs[reg_nr]; 196 offs = mtu2_reg_offs[reg_nr];
@@ -353,109 +362,168 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_channel *ch,
353static int sh_mtu2_register(struct sh_mtu2_channel *ch, const char *name, 362static int sh_mtu2_register(struct sh_mtu2_channel *ch, const char *name,
354 bool clockevent) 363 bool clockevent)
355{ 364{
356 if (clockevent) 365 if (clockevent) {
366 ch->mtu->has_clockevent = true;
357 sh_mtu2_register_clockevent(ch, name); 367 sh_mtu2_register_clockevent(ch, name);
368 }
358 369
359 return 0; 370 return 0;
360} 371}
361 372
362static int sh_mtu2_setup_channel(struct sh_mtu2_channel *ch, 373static int sh_mtu2_setup_channel(struct sh_mtu2_channel *ch, unsigned int index,
363 struct sh_mtu2_device *mtu) 374 struct sh_mtu2_device *mtu)
364{ 375{
365 struct sh_timer_config *cfg = mtu->pdev->dev.platform_data; 376 static const unsigned int channel_offsets[] = {
377 0x300, 0x380, 0x000,
378 };
379 bool clockevent;
366 380
367 ch->mtu = mtu; 381 ch->mtu = mtu;
368 ch->index = cfg->timer_bit;
369 382
370 ch->irq = platform_get_irq(mtu->pdev, 0); 383 if (mtu->legacy) {
384 struct sh_timer_config *cfg = mtu->pdev->dev.platform_data;
385
386 clockevent = cfg->clockevent_rating != 0;
387
388 ch->irq = platform_get_irq(mtu->pdev, 0);
389 ch->base = mtu->mapbase - cfg->channel_offset;
390 ch->index = cfg->timer_bit;
391 } else {
392 char name[6];
393
394 clockevent = true;
395
396 sprintf(name, "tgi%ua", index);
397 ch->irq = platform_get_irq_byname(mtu->pdev, name);
398 ch->base = mtu->mapbase + channel_offsets[index];
399 ch->index = index;
400 }
401
371 if (ch->irq < 0) { 402 if (ch->irq < 0) {
403 /* Skip channels with no declared interrupt. */
404 if (!mtu->legacy)
405 return 0;
406
372 dev_err(&mtu->pdev->dev, "ch%u: failed to get irq\n", 407 dev_err(&mtu->pdev->dev, "ch%u: failed to get irq\n",
373 ch->index); 408 ch->index);
374 return ch->irq; 409 return ch->irq;
375 } 410 }
376 411
377 return sh_mtu2_register(ch, dev_name(&mtu->pdev->dev), 412 return sh_mtu2_register(ch, dev_name(&mtu->pdev->dev), clockevent);
378 cfg->clockevent_rating != 0);
379} 413}
380 414
381static int sh_mtu2_setup(struct sh_mtu2_device *mtu, 415static int sh_mtu2_map_memory(struct sh_mtu2_device *mtu)
382 struct platform_device *pdev)
383{ 416{
384 struct sh_timer_config *cfg = pdev->dev.platform_data;
385 struct resource *res; 417 struct resource *res;
386 void __iomem *base;
387 int ret;
388 ret = -ENXIO;
389
390 mtu->pdev = pdev;
391
392 if (!cfg) {
393 dev_err(&mtu->pdev->dev, "missing platform data\n");
394 goto err0;
395 }
396
397 platform_set_drvdata(pdev, mtu);
398 418
399 res = platform_get_resource(mtu->pdev, IORESOURCE_MEM, 0); 419 res = platform_get_resource(mtu->pdev, IORESOURCE_MEM, 0);
400 if (!res) { 420 if (!res) {
401 dev_err(&mtu->pdev->dev, "failed to get I/O memory\n"); 421 dev_err(&mtu->pdev->dev, "failed to get I/O memory\n");
402 goto err0; 422 return -ENXIO;
403 } 423 }
404 424
425 mtu->mapbase = ioremap_nocache(res->start, resource_size(res));
426 if (mtu->mapbase == NULL)
427 return -ENXIO;
428
405 /* 429 /*
406 * Map memory, let base point to our channel and mapbase to the 430 * In legacy platform device configuration (with one device per channel)
407 * start/stop shared register. 431 * the resource points to the channel base address.
408 */ 432 */
409 base = ioremap_nocache(res->start, resource_size(res)); 433 if (mtu->legacy) {
410 if (base == NULL) { 434 struct sh_timer_config *cfg = mtu->pdev->dev.platform_data;
411 dev_err(&mtu->pdev->dev, "failed to remap I/O memory\n"); 435 mtu->mapbase += cfg->channel_offset;
412 goto err0; 436 }
437
438 return 0;
439}
440
441static void sh_mtu2_unmap_memory(struct sh_mtu2_device *mtu)
442{
443 if (mtu->legacy) {
444 struct sh_timer_config *cfg = mtu->pdev->dev.platform_data;
445 mtu->mapbase -= cfg->channel_offset;
413 } 446 }
414 447
415 mtu->mapbase = base + cfg->channel_offset; 448 iounmap(mtu->mapbase);
449}
450
451static int sh_mtu2_setup(struct sh_mtu2_device *mtu,
452 struct platform_device *pdev)
453{
454 struct sh_timer_config *cfg = pdev->dev.platform_data;
455 const struct platform_device_id *id = pdev->id_entry;
456 unsigned int i;
457 int ret;
458
459 mtu->pdev = pdev;
460 mtu->legacy = id->driver_data;
461
462 if (mtu->legacy && !cfg) {
463 dev_err(&mtu->pdev->dev, "missing platform data\n");
464 return -ENXIO;
465 }
416 466
417 /* get hold of clock */ 467 /* Get hold of clock. */
418 mtu->clk = clk_get(&mtu->pdev->dev, "mtu2_fck"); 468 mtu->clk = clk_get(&mtu->pdev->dev, "mtu2_fck");
419 if (IS_ERR(mtu->clk)) { 469 if (IS_ERR(mtu->clk)) {
420 dev_err(&mtu->pdev->dev, "cannot get clock\n"); 470 dev_err(&mtu->pdev->dev, "cannot get clock\n");
421 ret = PTR_ERR(mtu->clk); 471 return PTR_ERR(mtu->clk);
422 goto err1;
423 } 472 }
424 473
425 ret = clk_prepare(mtu->clk); 474 ret = clk_prepare(mtu->clk);
426 if (ret < 0) 475 if (ret < 0)
427 goto err2; 476 goto err_clk_put;
428 477
429 mtu->channels = kzalloc(sizeof(*mtu->channels), GFP_KERNEL); 478 /* Map the memory resource. */
479 ret = sh_mtu2_map_memory(mtu);
480 if (ret < 0) {
481 dev_err(&mtu->pdev->dev, "failed to remap I/O memory\n");
482 goto err_clk_unprepare;
483 }
484
485 /* Allocate and setup the channels. */
486 if (mtu->legacy)
487 mtu->num_channels = 1;
488 else
489 mtu->num_channels = 3;
490
491 mtu->channels = kzalloc(sizeof(*mtu->channels) * mtu->num_channels,
492 GFP_KERNEL);
430 if (mtu->channels == NULL) { 493 if (mtu->channels == NULL) {
431 ret = -ENOMEM; 494 ret = -ENOMEM;
432 goto err3; 495 goto err_unmap;
433 } 496 }
434 497
435 mtu->num_channels = 1; 498 if (mtu->legacy) {
436 499 ret = sh_mtu2_setup_channel(&mtu->channels[0], 0, mtu);
437 mtu->channels[0].base = base; 500 if (ret < 0)
501 goto err_unmap;
502 } else {
503 for (i = 0; i < mtu->num_channels; ++i) {
504 ret = sh_mtu2_setup_channel(&mtu->channels[i], i, mtu);
505 if (ret < 0)
506 goto err_unmap;
507 }
508 }
438 509
439 ret = sh_mtu2_setup_channel(&mtu->channels[0], mtu); 510 platform_set_drvdata(pdev, mtu);
440 if (ret < 0)
441 goto err3;
442 511
443 return 0; 512 return 0;
444 err3: 513
514err_unmap:
445 kfree(mtu->channels); 515 kfree(mtu->channels);
516 sh_mtu2_unmap_memory(mtu);
517err_clk_unprepare:
446 clk_unprepare(mtu->clk); 518 clk_unprepare(mtu->clk);
447 err2: 519err_clk_put:
448 clk_put(mtu->clk); 520 clk_put(mtu->clk);
449 err1:
450 iounmap(base);
451 err0:
452 return ret; 521 return ret;
453} 522}
454 523
455static int sh_mtu2_probe(struct platform_device *pdev) 524static int sh_mtu2_probe(struct platform_device *pdev)
456{ 525{
457 struct sh_mtu2_device *mtu = platform_get_drvdata(pdev); 526 struct sh_mtu2_device *mtu = platform_get_drvdata(pdev);
458 struct sh_timer_config *cfg = pdev->dev.platform_data;
459 int ret; 527 int ret;
460 528
461 if (!is_early_platform_device(pdev)) { 529 if (!is_early_platform_device(pdev)) {
@@ -484,7 +552,7 @@ static int sh_mtu2_probe(struct platform_device *pdev)
484 return 0; 552 return 0;
485 553
486 out: 554 out:
487 if (cfg->clockevent_rating) 555 if (mtu->has_clockevent)
488 pm_runtime_irq_safe(&pdev->dev); 556 pm_runtime_irq_safe(&pdev->dev);
489 else 557 else
490 pm_runtime_idle(&pdev->dev); 558 pm_runtime_idle(&pdev->dev);
@@ -497,12 +565,20 @@ static int sh_mtu2_remove(struct platform_device *pdev)
497 return -EBUSY; /* cannot unregister clockevent */ 565 return -EBUSY; /* cannot unregister clockevent */
498} 566}
499 567
568static const struct platform_device_id sh_mtu2_id_table[] = {
569 { "sh_mtu2", 1 },
570 { "sh-mtu2", 0 },
571 { },
572};
573MODULE_DEVICE_TABLE(platform, sh_mtu2_id_table);
574
500static struct platform_driver sh_mtu2_device_driver = { 575static struct platform_driver sh_mtu2_device_driver = {
501 .probe = sh_mtu2_probe, 576 .probe = sh_mtu2_probe,
502 .remove = sh_mtu2_remove, 577 .remove = sh_mtu2_remove,
503 .driver = { 578 .driver = {
504 .name = "sh_mtu2", 579 .name = "sh_mtu2",
505 } 580 },
581 .id_table = sh_mtu2_id_table,
506}; 582};
507 583
508static int __init sh_mtu2_init(void) 584static int __init sh_mtu2_init(void)