diff options
Diffstat (limited to 'arch/sparc64/kernel/time.c')
-rw-r--r-- | arch/sparc64/kernel/time.c | 1187 |
1 files changed, 165 insertions, 1022 deletions
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index cc16fdcf98af..80d71a5ce1e3 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c | |||
@@ -30,13 +30,14 @@ | |||
30 | #include <linux/percpu.h> | 30 | #include <linux/percpu.h> |
31 | #include <linux/miscdevice.h> | 31 | #include <linux/miscdevice.h> |
32 | #include <linux/rtc.h> | 32 | #include <linux/rtc.h> |
33 | #include <linux/rtc/m48t59.h> | ||
33 | #include <linux/kernel_stat.h> | 34 | #include <linux/kernel_stat.h> |
34 | #include <linux/clockchips.h> | 35 | #include <linux/clockchips.h> |
35 | #include <linux/clocksource.h> | 36 | #include <linux/clocksource.h> |
36 | #include <linux/of_device.h> | 37 | #include <linux/of_device.h> |
38 | #include <linux/platform_device.h> | ||
37 | 39 | ||
38 | #include <asm/oplib.h> | 40 | #include <asm/oplib.h> |
39 | #include <asm/mostek.h> | ||
40 | #include <asm/timer.h> | 41 | #include <asm/timer.h> |
41 | #include <asm/irq.h> | 42 | #include <asm/irq.h> |
42 | #include <asm/io.h> | 43 | #include <asm/io.h> |
@@ -50,18 +51,7 @@ | |||
50 | 51 | ||
51 | #include "entry.h" | 52 | #include "entry.h" |
52 | 53 | ||
53 | DEFINE_SPINLOCK(mostek_lock); | ||
54 | DEFINE_SPINLOCK(rtc_lock); | 54 | DEFINE_SPINLOCK(rtc_lock); |
55 | void __iomem *mstk48t02_regs = NULL; | ||
56 | #ifdef CONFIG_PCI | ||
57 | unsigned long ds1287_regs = 0UL; | ||
58 | static void __iomem *bq4802_regs; | ||
59 | #endif | ||
60 | |||
61 | static void __iomem *mstk48t08_regs; | ||
62 | static void __iomem *mstk48t59_regs; | ||
63 | |||
64 | static int set_rtc_mmss(unsigned long); | ||
65 | 55 | ||
66 | #define TICK_PRIV_BIT (1UL << 63) | 56 | #define TICK_PRIV_BIT (1UL << 63) |
67 | #define TICKCMP_IRQ_BIT (1UL << 63) | 57 | #define TICKCMP_IRQ_BIT (1UL << 63) |
@@ -405,313 +395,167 @@ static unsigned long timer_ticks_per_nsec_quotient __read_mostly; | |||
405 | 395 | ||
406 | int update_persistent_clock(struct timespec now) | 396 | int update_persistent_clock(struct timespec now) |
407 | { | 397 | { |
408 | return set_rtc_mmss(now.tv_sec); | 398 | struct rtc_device *rtc = rtc_class_open("rtc0"); |
409 | } | 399 | int err = -1; |
410 | 400 | ||
411 | /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ | 401 | if (rtc) { |
412 | static void __init kick_start_clock(void) | 402 | err = rtc_set_mmss(rtc, now.tv_sec); |
413 | { | 403 | rtc_class_close(rtc); |
414 | void __iomem *regs = mstk48t02_regs; | ||
415 | u8 sec, tmp; | ||
416 | int i, count; | ||
417 | |||
418 | prom_printf("CLOCK: Clock was stopped. Kick start "); | ||
419 | |||
420 | spin_lock_irq(&mostek_lock); | ||
421 | |||
422 | /* Turn on the kick start bit to start the oscillator. */ | ||
423 | tmp = mostek_read(regs + MOSTEK_CREG); | ||
424 | tmp |= MSTK_CREG_WRITE; | ||
425 | mostek_write(regs + MOSTEK_CREG, tmp); | ||
426 | tmp = mostek_read(regs + MOSTEK_SEC); | ||
427 | tmp &= ~MSTK_STOP; | ||
428 | mostek_write(regs + MOSTEK_SEC, tmp); | ||
429 | tmp = mostek_read(regs + MOSTEK_HOUR); | ||
430 | tmp |= MSTK_KICK_START; | ||
431 | mostek_write(regs + MOSTEK_HOUR, tmp); | ||
432 | tmp = mostek_read(regs + MOSTEK_CREG); | ||
433 | tmp &= ~MSTK_CREG_WRITE; | ||
434 | mostek_write(regs + MOSTEK_CREG, tmp); | ||
435 | |||
436 | spin_unlock_irq(&mostek_lock); | ||
437 | |||
438 | /* Delay to allow the clock oscillator to start. */ | ||
439 | sec = MSTK_REG_SEC(regs); | ||
440 | for (i = 0; i < 3; i++) { | ||
441 | while (sec == MSTK_REG_SEC(regs)) | ||
442 | for (count = 0; count < 100000; count++) | ||
443 | /* nothing */ ; | ||
444 | prom_printf("."); | ||
445 | sec = MSTK_REG_SEC(regs); | ||
446 | } | ||
447 | prom_printf("\n"); | ||
448 | |||
449 | spin_lock_irq(&mostek_lock); | ||
450 | |||
451 | /* Turn off kick start and set a "valid" time and date. */ | ||
452 | tmp = mostek_read(regs + MOSTEK_CREG); | ||
453 | tmp |= MSTK_CREG_WRITE; | ||
454 | mostek_write(regs + MOSTEK_CREG, tmp); | ||
455 | tmp = mostek_read(regs + MOSTEK_HOUR); | ||
456 | tmp &= ~MSTK_KICK_START; | ||
457 | mostek_write(regs + MOSTEK_HOUR, tmp); | ||
458 | MSTK_SET_REG_SEC(regs,0); | ||
459 | MSTK_SET_REG_MIN(regs,0); | ||
460 | MSTK_SET_REG_HOUR(regs,0); | ||
461 | MSTK_SET_REG_DOW(regs,5); | ||
462 | MSTK_SET_REG_DOM(regs,1); | ||
463 | MSTK_SET_REG_MONTH(regs,8); | ||
464 | MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO); | ||
465 | tmp = mostek_read(regs + MOSTEK_CREG); | ||
466 | tmp &= ~MSTK_CREG_WRITE; | ||
467 | mostek_write(regs + MOSTEK_CREG, tmp); | ||
468 | |||
469 | spin_unlock_irq(&mostek_lock); | ||
470 | |||
471 | /* Ensure the kick start bit is off. If it isn't, turn it off. */ | ||
472 | while (mostek_read(regs + MOSTEK_HOUR) & MSTK_KICK_START) { | ||
473 | prom_printf("CLOCK: Kick start still on!\n"); | ||
474 | |||
475 | spin_lock_irq(&mostek_lock); | ||
476 | |||
477 | tmp = mostek_read(regs + MOSTEK_CREG); | ||
478 | tmp |= MSTK_CREG_WRITE; | ||
479 | mostek_write(regs + MOSTEK_CREG, tmp); | ||
480 | |||
481 | tmp = mostek_read(regs + MOSTEK_HOUR); | ||
482 | tmp &= ~MSTK_KICK_START; | ||
483 | mostek_write(regs + MOSTEK_HOUR, tmp); | ||
484 | |||
485 | tmp = mostek_read(regs + MOSTEK_CREG); | ||
486 | tmp &= ~MSTK_CREG_WRITE; | ||
487 | mostek_write(regs + MOSTEK_CREG, tmp); | ||
488 | |||
489 | spin_unlock_irq(&mostek_lock); | ||
490 | } | 404 | } |
491 | 405 | ||
492 | prom_printf("CLOCK: Kick start procedure successful.\n"); | 406 | return err; |
493 | } | 407 | } |
494 | 408 | ||
495 | /* Return nonzero if the clock chip battery is low. */ | 409 | unsigned long cmos_regs; |
496 | static int __init has_low_battery(void) | 410 | EXPORT_SYMBOL(cmos_regs); |
497 | { | ||
498 | void __iomem *regs = mstk48t02_regs; | ||
499 | u8 data1, data2; | ||
500 | |||
501 | spin_lock_irq(&mostek_lock); | ||
502 | 411 | ||
503 | data1 = mostek_read(regs + MOSTEK_EEPROM); /* Read some data. */ | 412 | static struct resource rtc_cmos_resource; |
504 | mostek_write(regs + MOSTEK_EEPROM, ~data1); /* Write back the complement. */ | ||
505 | data2 = mostek_read(regs + MOSTEK_EEPROM); /* Read back the complement. */ | ||
506 | mostek_write(regs + MOSTEK_EEPROM, data1); /* Restore original value. */ | ||
507 | 413 | ||
508 | spin_unlock_irq(&mostek_lock); | 414 | static struct platform_device rtc_cmos_device = { |
509 | 415 | .name = "rtc_cmos", | |
510 | return (data1 == data2); /* Was the write blocked? */ | 416 | .id = -1, |
511 | } | 417 | .resource = &rtc_cmos_resource, |
418 | .num_resources = 1, | ||
419 | }; | ||
512 | 420 | ||
513 | static void __init mostek_set_system_time(void __iomem *mregs) | 421 | static int __devinit rtc_probe(struct of_device *op, const struct of_device_id *match) |
514 | { | 422 | { |
515 | unsigned int year, mon, day, hour, min, sec; | 423 | struct resource *r; |
516 | u8 tmp; | ||
517 | |||
518 | spin_lock_irq(&mostek_lock); | ||
519 | 424 | ||
520 | /* Traditional Mostek chip. */ | 425 | printk(KERN_INFO "%s: RTC regs at 0x%lx\n", |
521 | tmp = mostek_read(mregs + MOSTEK_CREG); | 426 | op->node->full_name, op->resource[0].start); |
522 | tmp |= MSTK_CREG_READ; | ||
523 | mostek_write(mregs + MOSTEK_CREG, tmp); | ||
524 | 427 | ||
525 | sec = MSTK_REG_SEC(mregs); | 428 | /* The CMOS RTC driver only accepts IORESOURCE_IO, so cons |
526 | min = MSTK_REG_MIN(mregs); | 429 | * up a fake resource so that the probe works for all cases. |
527 | hour = MSTK_REG_HOUR(mregs); | 430 | * When the RTC is behind an ISA bus it will have IORESOURCE_IO |
528 | day = MSTK_REG_DOM(mregs); | 431 | * already, whereas when it's behind EBUS is will be IORESOURCE_MEM. |
529 | mon = MSTK_REG_MONTH(mregs); | 432 | */ |
530 | year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) ); | ||
531 | |||
532 | xtime.tv_sec = mktime(year, mon, day, hour, min, sec); | ||
533 | xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | ||
534 | set_normalized_timespec(&wall_to_monotonic, | ||
535 | -xtime.tv_sec, -xtime.tv_nsec); | ||
536 | 433 | ||
537 | tmp = mostek_read(mregs + MOSTEK_CREG); | 434 | r = &rtc_cmos_resource; |
538 | tmp &= ~MSTK_CREG_READ; | 435 | r->flags = IORESOURCE_IO; |
539 | mostek_write(mregs + MOSTEK_CREG, tmp); | 436 | r->name = op->resource[0].name; |
437 | r->start = op->resource[0].start; | ||
438 | r->end = op->resource[0].end; | ||
540 | 439 | ||
541 | spin_unlock_irq(&mostek_lock); | 440 | cmos_regs = op->resource[0].start; |
441 | return platform_device_register(&rtc_cmos_device); | ||
542 | } | 442 | } |
543 | 443 | ||
544 | /* Probe for the real time clock chip. */ | 444 | static struct of_device_id __initdata rtc_match[] = { |
545 | static void __init set_system_time(void) | 445 | { |
546 | { | 446 | .name = "rtc", |
547 | unsigned int year, mon, day, hour, min, sec; | 447 | .compatible = "m5819", |
548 | void __iomem *mregs = mstk48t02_regs; | 448 | }, |
549 | #ifdef CONFIG_PCI | 449 | { |
550 | unsigned long dregs = ds1287_regs; | 450 | .name = "rtc", |
551 | void __iomem *bregs = bq4802_regs; | 451 | .compatible = "isa-m5819p", |
552 | #else | 452 | }, |
553 | unsigned long dregs = 0UL; | 453 | { |
554 | void __iomem *bregs = 0UL; | 454 | .name = "rtc", |
555 | #endif | 455 | .compatible = "isa-m5823p", |
556 | 456 | }, | |
557 | if (!mregs && !dregs && !bregs) { | 457 | { |
558 | prom_printf("Something wrong, clock regs not mapped yet.\n"); | 458 | .name = "rtc", |
559 | prom_halt(); | 459 | .compatible = "ds1287", |
560 | } | 460 | }, |
561 | 461 | {}, | |
562 | if (mregs) { | 462 | }; |
563 | mostek_set_system_time(mregs); | ||
564 | return; | ||
565 | } | ||
566 | |||
567 | if (bregs) { | ||
568 | unsigned char val = readb(bregs + 0x0e); | ||
569 | unsigned int century; | ||
570 | 463 | ||
571 | /* BQ4802 RTC chip. */ | 464 | static struct of_platform_driver rtc_driver = { |
465 | .match_table = rtc_match, | ||
466 | .probe = rtc_probe, | ||
467 | .driver = { | ||
468 | .name = "rtc", | ||
469 | }, | ||
470 | }; | ||
572 | 471 | ||
573 | writeb(val | 0x08, bregs + 0x0e); | 472 | static struct platform_device rtc_bq4802_device = { |
473 | .name = "rtc-bq4802", | ||
474 | .id = -1, | ||
475 | .num_resources = 1, | ||
476 | }; | ||
574 | 477 | ||
575 | sec = readb(bregs + 0x00); | 478 | static int __devinit bq4802_probe(struct of_device *op, const struct of_device_id *match) |
576 | min = readb(bregs + 0x02); | 479 | { |
577 | hour = readb(bregs + 0x04); | ||
578 | day = readb(bregs + 0x06); | ||
579 | mon = readb(bregs + 0x09); | ||
580 | year = readb(bregs + 0x0a); | ||
581 | century = readb(bregs + 0x0f); | ||
582 | 480 | ||
583 | writeb(val, bregs + 0x0e); | 481 | printk(KERN_INFO "%s: BQ4802 regs at 0x%lx\n", |
482 | op->node->full_name, op->resource[0].start); | ||
584 | 483 | ||
585 | BCD_TO_BIN(sec); | 484 | rtc_bq4802_device.resource = &op->resource[0]; |
586 | BCD_TO_BIN(min); | 485 | return platform_device_register(&rtc_bq4802_device); |
587 | BCD_TO_BIN(hour); | 486 | } |
588 | BCD_TO_BIN(day); | ||
589 | BCD_TO_BIN(mon); | ||
590 | BCD_TO_BIN(year); | ||
591 | BCD_TO_BIN(century); | ||
592 | 487 | ||
593 | year += (century * 100); | 488 | static struct of_device_id __initdata bq4802_match[] = { |
594 | } else { | 489 | { |
595 | /* Dallas 12887 RTC chip. */ | 490 | .name = "rtc", |
596 | 491 | .compatible = "bq4802", | |
597 | do { | 492 | }, |
598 | sec = CMOS_READ(RTC_SECONDS); | 493 | }; |
599 | min = CMOS_READ(RTC_MINUTES); | ||
600 | hour = CMOS_READ(RTC_HOURS); | ||
601 | day = CMOS_READ(RTC_DAY_OF_MONTH); | ||
602 | mon = CMOS_READ(RTC_MONTH); | ||
603 | year = CMOS_READ(RTC_YEAR); | ||
604 | } while (sec != CMOS_READ(RTC_SECONDS)); | ||
605 | |||
606 | if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | ||
607 | BCD_TO_BIN(sec); | ||
608 | BCD_TO_BIN(min); | ||
609 | BCD_TO_BIN(hour); | ||
610 | BCD_TO_BIN(day); | ||
611 | BCD_TO_BIN(mon); | ||
612 | BCD_TO_BIN(year); | ||
613 | } | ||
614 | if ((year += 1900) < 1970) | ||
615 | year += 100; | ||
616 | } | ||
617 | 494 | ||
618 | xtime.tv_sec = mktime(year, mon, day, hour, min, sec); | 495 | static struct of_platform_driver bq4802_driver = { |
619 | xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | 496 | .match_table = bq4802_match, |
620 | set_normalized_timespec(&wall_to_monotonic, | 497 | .probe = bq4802_probe, |
621 | -xtime.tv_sec, -xtime.tv_nsec); | 498 | .driver = { |
622 | } | 499 | .name = "bq4802", |
500 | }, | ||
501 | }; | ||
623 | 502 | ||
624 | /* davem suggests we keep this within the 4M locked kernel image */ | 503 | static unsigned char mostek_read_byte(struct device *dev, u32 ofs) |
625 | static u32 starfire_get_time(void) | ||
626 | { | 504 | { |
627 | static char obp_gettod[32]; | 505 | struct platform_device *pdev = to_platform_device(dev); |
628 | static u32 unix_tod; | 506 | struct m48t59_plat_data *pdata = pdev->dev.platform_data; |
507 | void __iomem *regs; | ||
508 | unsigned char val; | ||
629 | 509 | ||
630 | sprintf(obp_gettod, "h# %08x unix-gettod", | 510 | regs = (void __iomem *) pdev->resource[0].start; |
631 | (unsigned int) (long) &unix_tod); | 511 | val = readb(regs + ofs); |
632 | prom_feval(obp_gettod); | ||
633 | 512 | ||
634 | return unix_tod; | 513 | /* the year 0 is 1968 */ |
514 | if (ofs == pdata->offset + M48T59_YEAR) { | ||
515 | val += 0x68; | ||
516 | if ((val & 0xf) > 9) | ||
517 | val += 6; | ||
518 | } | ||
519 | return val; | ||
635 | } | 520 | } |
636 | 521 | ||
637 | static int starfire_set_time(u32 val) | 522 | static void mostek_write_byte(struct device *dev, u32 ofs, u8 val) |
638 | { | 523 | { |
639 | /* Do nothing, time is set using the service processor | 524 | struct platform_device *pdev = to_platform_device(dev); |
640 | * console on this platform. | 525 | struct m48t59_plat_data *pdata = pdev->dev.platform_data; |
641 | */ | 526 | void __iomem *regs; |
642 | return 0; | ||
643 | } | ||
644 | 527 | ||
645 | static u32 hypervisor_get_time(void) | 528 | regs = (void __iomem *) pdev->resource[0].start; |
646 | { | 529 | if (ofs == pdata->offset + M48T59_YEAR) { |
647 | unsigned long ret, time; | 530 | if (val < 0x68) |
648 | int retries = 10000; | 531 | val += 0x32; |
649 | 532 | else | |
650 | retry: | 533 | val -= 0x68; |
651 | ret = sun4v_tod_get(&time); | 534 | if ((val & 0xf) > 9) |
652 | if (ret == HV_EOK) | 535 | val += 6; |
653 | return time; | 536 | if ((val & 0xf0) > 0x9A) |
654 | if (ret == HV_EWOULDBLOCK) { | 537 | val += 0x60; |
655 | if (--retries > 0) { | ||
656 | udelay(100); | ||
657 | goto retry; | ||
658 | } | ||
659 | printk(KERN_WARNING "SUN4V: tod_get() timed out.\n"); | ||
660 | return 0; | ||
661 | } | 538 | } |
662 | printk(KERN_WARNING "SUN4V: tod_get() not supported.\n"); | 539 | writeb(val, regs + ofs); |
663 | return 0; | ||
664 | } | 540 | } |
665 | 541 | ||
666 | static int hypervisor_set_time(u32 secs) | 542 | static struct m48t59_plat_data m48t59_data = { |
667 | { | 543 | .read_byte = mostek_read_byte, |
668 | unsigned long ret; | 544 | .write_byte = mostek_write_byte, |
669 | int retries = 10000; | 545 | }; |
670 | |||
671 | retry: | ||
672 | ret = sun4v_tod_set(secs); | ||
673 | if (ret == HV_EOK) | ||
674 | return 0; | ||
675 | if (ret == HV_EWOULDBLOCK) { | ||
676 | if (--retries > 0) { | ||
677 | udelay(100); | ||
678 | goto retry; | ||
679 | } | ||
680 | printk(KERN_WARNING "SUN4V: tod_set() timed out.\n"); | ||
681 | return -EAGAIN; | ||
682 | } | ||
683 | printk(KERN_WARNING "SUN4V: tod_set() not supported.\n"); | ||
684 | return -EOPNOTSUPP; | ||
685 | } | ||
686 | 546 | ||
687 | static int __init clock_model_matches(const char *model) | 547 | static struct platform_device m48t59_rtc = { |
688 | { | 548 | .name = "rtc-m48t59", |
689 | if (strcmp(model, "mk48t02") && | 549 | .id = 0, |
690 | strcmp(model, "mk48t08") && | 550 | .num_resources = 1, |
691 | strcmp(model, "mk48t59") && | 551 | .dev = { |
692 | strcmp(model, "m5819") && | 552 | .platform_data = &m48t59_data, |
693 | strcmp(model, "m5819p") && | 553 | }, |
694 | strcmp(model, "m5823") && | 554 | }; |
695 | strcmp(model, "ds1287") && | ||
696 | strcmp(model, "bq4802")) | ||
697 | return 0; | ||
698 | |||
699 | return 1; | ||
700 | } | ||
701 | 555 | ||
702 | static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match) | 556 | static int __devinit mostek_probe(struct of_device *op, const struct of_device_id *match) |
703 | { | 557 | { |
704 | struct device_node *dp = op->node; | 558 | struct device_node *dp = op->node; |
705 | const char *model = of_get_property(dp, "model", NULL); | ||
706 | const char *compat = of_get_property(dp, "compatible", NULL); | ||
707 | unsigned long size, flags; | ||
708 | void __iomem *regs; | ||
709 | |||
710 | if (!model) | ||
711 | model = compat; | ||
712 | |||
713 | if (!model || !clock_model_matches(model)) | ||
714 | return -ENODEV; | ||
715 | 559 | ||
716 | /* On an Enterprise system there can be multiple mostek clocks. | 560 | /* On an Enterprise system there can be multiple mostek clocks. |
717 | * We should only match the one that is on the central FHC bus. | 561 | * We should only match the one that is on the central FHC bus. |
@@ -720,88 +564,51 @@ static int __devinit clock_probe(struct of_device *op, const struct of_device_id | |||
720 | strcmp(dp->parent->parent->name, "central") != 0) | 564 | strcmp(dp->parent->parent->name, "central") != 0) |
721 | return -ENODEV; | 565 | return -ENODEV; |
722 | 566 | ||
723 | size = (op->resource[0].end - op->resource[0].start) + 1; | 567 | printk(KERN_INFO "%s: Mostek regs at 0x%lx\n", |
724 | regs = of_ioremap(&op->resource[0], 0, size, "clock"); | 568 | dp->full_name, op->resource[0].start); |
725 | if (!regs) | ||
726 | return -ENOMEM; | ||
727 | |||
728 | #ifdef CONFIG_PCI | ||
729 | if (!strcmp(model, "ds1287") || | ||
730 | !strcmp(model, "m5819") || | ||
731 | !strcmp(model, "m5819p") || | ||
732 | !strcmp(model, "m5823")) { | ||
733 | ds1287_regs = (unsigned long) regs; | ||
734 | } else if (!strcmp(model, "bq4802")) { | ||
735 | bq4802_regs = regs; | ||
736 | } else | ||
737 | #endif | ||
738 | if (model[5] == '0' && model[6] == '2') { | ||
739 | mstk48t02_regs = regs; | ||
740 | } else if(model[5] == '0' && model[6] == '8') { | ||
741 | mstk48t08_regs = regs; | ||
742 | mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02; | ||
743 | } else { | ||
744 | mstk48t59_regs = regs; | ||
745 | mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; | ||
746 | } | ||
747 | |||
748 | printk(KERN_INFO "%s: Clock regs at %p\n", dp->full_name, regs); | ||
749 | |||
750 | local_irq_save(flags); | ||
751 | |||
752 | if (mstk48t02_regs != NULL) { | ||
753 | /* Report a low battery voltage condition. */ | ||
754 | if (has_low_battery()) | ||
755 | prom_printf("NVRAM: Low battery voltage!\n"); | ||
756 | |||
757 | /* Kick start the clock if it is completely stopped. */ | ||
758 | if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP) | ||
759 | kick_start_clock(); | ||
760 | } | ||
761 | |||
762 | set_system_time(); | ||
763 | |||
764 | local_irq_restore(flags); | ||
765 | 569 | ||
766 | return 0; | 570 | m48t59_rtc.resource = &op->resource[0]; |
571 | return platform_device_register(&m48t59_rtc); | ||
767 | } | 572 | } |
768 | 573 | ||
769 | static struct of_device_id clock_match[] = { | 574 | static struct of_device_id __initdata mostek_match[] = { |
770 | { | 575 | { |
771 | .name = "eeprom", | 576 | .name = "eeprom", |
772 | }, | 577 | }, |
773 | { | ||
774 | .name = "rtc", | ||
775 | }, | ||
776 | {}, | 578 | {}, |
777 | }; | 579 | }; |
778 | 580 | ||
779 | static struct of_platform_driver clock_driver = { | 581 | static struct of_platform_driver mostek_driver = { |
780 | .match_table = clock_match, | 582 | .match_table = mostek_match, |
781 | .probe = clock_probe, | 583 | .probe = mostek_probe, |
782 | .driver = { | 584 | .driver = { |
783 | .name = "clock", | 585 | .name = "mostek", |
784 | }, | 586 | }, |
785 | }; | 587 | }; |
786 | 588 | ||
589 | static struct platform_device rtc_sun4v_device = { | ||
590 | .name = "rtc-sun4v", | ||
591 | .id = -1, | ||
592 | }; | ||
593 | |||
594 | static struct platform_device rtc_starfire_device = { | ||
595 | .name = "rtc-starfire", | ||
596 | .id = -1, | ||
597 | }; | ||
598 | |||
787 | static int __init clock_init(void) | 599 | static int __init clock_init(void) |
788 | { | 600 | { |
789 | if (this_is_starfire) { | 601 | if (this_is_starfire) |
790 | xtime.tv_sec = starfire_get_time(); | 602 | return platform_device_register(&rtc_starfire_device); |
791 | xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | 603 | |
792 | set_normalized_timespec(&wall_to_monotonic, | 604 | if (tlb_type == hypervisor) |
793 | -xtime.tv_sec, -xtime.tv_nsec); | 605 | return platform_device_register(&rtc_sun4v_device); |
794 | return 0; | 606 | |
795 | } | 607 | (void) of_register_driver(&rtc_driver, &of_platform_bus_type); |
796 | if (tlb_type == hypervisor) { | 608 | (void) of_register_driver(&mostek_driver, &of_platform_bus_type); |
797 | xtime.tv_sec = hypervisor_get_time(); | 609 | (void) of_register_driver(&bq4802_driver, &of_platform_bus_type); |
798 | xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | ||
799 | set_normalized_timespec(&wall_to_monotonic, | ||
800 | -xtime.tv_sec, -xtime.tv_nsec); | ||
801 | return 0; | ||
802 | } | ||
803 | 610 | ||
804 | return of_register_driver(&clock_driver, &of_platform_bus_type); | 611 | return 0; |
805 | } | 612 | } |
806 | 613 | ||
807 | /* Must be after subsys_initcall() so that busses are probed. Must | 614 | /* Must be after subsys_initcall() so that busses are probed. Must |
@@ -814,7 +621,7 @@ fs_initcall(clock_init); | |||
814 | static unsigned long sparc64_init_timers(void) | 621 | static unsigned long sparc64_init_timers(void) |
815 | { | 622 | { |
816 | struct device_node *dp; | 623 | struct device_node *dp; |
817 | unsigned long clock; | 624 | unsigned long freq; |
818 | 625 | ||
819 | dp = of_find_node_by_path("/"); | 626 | dp = of_find_node_by_path("/"); |
820 | if (tlb_type == spitfire) { | 627 | if (tlb_type == spitfire) { |
@@ -827,17 +634,17 @@ static unsigned long sparc64_init_timers(void) | |||
827 | if (manuf == 0x17 && impl == 0x13) { | 634 | if (manuf == 0x17 && impl == 0x13) { |
828 | /* Hummingbird, aka Ultra-IIe */ | 635 | /* Hummingbird, aka Ultra-IIe */ |
829 | tick_ops = &hbtick_operations; | 636 | tick_ops = &hbtick_operations; |
830 | clock = of_getintprop_default(dp, "stick-frequency", 0); | 637 | freq = of_getintprop_default(dp, "stick-frequency", 0); |
831 | } else { | 638 | } else { |
832 | tick_ops = &tick_operations; | 639 | tick_ops = &tick_operations; |
833 | clock = local_cpu_data().clock_tick; | 640 | freq = local_cpu_data().clock_tick; |
834 | } | 641 | } |
835 | } else { | 642 | } else { |
836 | tick_ops = &stick_operations; | 643 | tick_ops = &stick_operations; |
837 | clock = of_getintprop_default(dp, "stick-frequency", 0); | 644 | freq = of_getintprop_default(dp, "stick-frequency", 0); |
838 | } | 645 | } |
839 | 646 | ||
840 | return clock; | 647 | return freq; |
841 | } | 648 | } |
842 | 649 | ||
843 | struct freq_table { | 650 | struct freq_table { |
@@ -1029,16 +836,16 @@ EXPORT_SYMBOL(udelay); | |||
1029 | 836 | ||
1030 | void __init time_init(void) | 837 | void __init time_init(void) |
1031 | { | 838 | { |
1032 | unsigned long clock = sparc64_init_timers(); | 839 | unsigned long freq = sparc64_init_timers(); |
1033 | 840 | ||
1034 | tb_ticks_per_usec = clock / USEC_PER_SEC; | 841 | tb_ticks_per_usec = freq / USEC_PER_SEC; |
1035 | 842 | ||
1036 | timer_ticks_per_nsec_quotient = | 843 | timer_ticks_per_nsec_quotient = |
1037 | clocksource_hz2mult(clock, SPARC64_NSEC_PER_CYC_SHIFT); | 844 | clocksource_hz2mult(freq, SPARC64_NSEC_PER_CYC_SHIFT); |
1038 | 845 | ||
1039 | clocksource_tick.name = tick_ops->name; | 846 | clocksource_tick.name = tick_ops->name; |
1040 | clocksource_tick.mult = | 847 | clocksource_tick.mult = |
1041 | clocksource_hz2mult(clock, | 848 | clocksource_hz2mult(freq, |
1042 | clocksource_tick.shift); | 849 | clocksource_tick.shift); |
1043 | clocksource_tick.read = tick_ops->get_tick; | 850 | clocksource_tick.read = tick_ops->get_tick; |
1044 | 851 | ||
@@ -1049,7 +856,7 @@ void __init time_init(void) | |||
1049 | 856 | ||
1050 | sparc64_clockevent.name = tick_ops->name; | 857 | sparc64_clockevent.name = tick_ops->name; |
1051 | 858 | ||
1052 | setup_clockevent_multiplier(clock); | 859 | setup_clockevent_multiplier(freq); |
1053 | 860 | ||
1054 | sparc64_clockevent.max_delta_ns = | 861 | sparc64_clockevent.max_delta_ns = |
1055 | clockevent_delta2ns(0x7fffffffffffffffUL, &sparc64_clockevent); | 862 | clockevent_delta2ns(0x7fffffffffffffffUL, &sparc64_clockevent); |
@@ -1070,672 +877,8 @@ unsigned long long sched_clock(void) | |||
1070 | >> SPARC64_NSEC_PER_CYC_SHIFT; | 877 | >> SPARC64_NSEC_PER_CYC_SHIFT; |
1071 | } | 878 | } |
1072 | 879 | ||
1073 | static int set_rtc_mmss(unsigned long nowtime) | ||
1074 | { | ||
1075 | int real_seconds, real_minutes, chip_minutes; | ||
1076 | void __iomem *mregs = mstk48t02_regs; | ||
1077 | #ifdef CONFIG_PCI | ||
1078 | unsigned long dregs = ds1287_regs; | ||
1079 | void __iomem *bregs = bq4802_regs; | ||
1080 | #else | ||
1081 | unsigned long dregs = 0UL; | ||
1082 | void __iomem *bregs = 0UL; | ||
1083 | #endif | ||
1084 | unsigned long flags; | ||
1085 | u8 tmp; | ||
1086 | |||
1087 | /* | ||
1088 | * Not having a register set can lead to trouble. | ||
1089 | * Also starfire doesn't have a tod clock. | ||
1090 | */ | ||
1091 | if (!mregs && !dregs && !bregs) | ||
1092 | return -1; | ||
1093 | |||
1094 | if (mregs) { | ||
1095 | spin_lock_irqsave(&mostek_lock, flags); | ||
1096 | |||
1097 | /* Read the current RTC minutes. */ | ||
1098 | tmp = mostek_read(mregs + MOSTEK_CREG); | ||
1099 | tmp |= MSTK_CREG_READ; | ||
1100 | mostek_write(mregs + MOSTEK_CREG, tmp); | ||
1101 | |||
1102 | chip_minutes = MSTK_REG_MIN(mregs); | ||
1103 | |||
1104 | tmp = mostek_read(mregs + MOSTEK_CREG); | ||
1105 | tmp &= ~MSTK_CREG_READ; | ||
1106 | mostek_write(mregs + MOSTEK_CREG, tmp); | ||
1107 | |||
1108 | /* | ||
1109 | * since we're only adjusting minutes and seconds, | ||
1110 | * don't interfere with hour overflow. This avoids | ||
1111 | * messing with unknown time zones but requires your | ||
1112 | * RTC not to be off by more than 15 minutes | ||
1113 | */ | ||
1114 | real_seconds = nowtime % 60; | ||
1115 | real_minutes = nowtime / 60; | ||
1116 | if (((abs(real_minutes - chip_minutes) + 15)/30) & 1) | ||
1117 | real_minutes += 30; /* correct for half hour time zone */ | ||
1118 | real_minutes %= 60; | ||
1119 | |||
1120 | if (abs(real_minutes - chip_minutes) < 30) { | ||
1121 | tmp = mostek_read(mregs + MOSTEK_CREG); | ||
1122 | tmp |= MSTK_CREG_WRITE; | ||
1123 | mostek_write(mregs + MOSTEK_CREG, tmp); | ||
1124 | |||
1125 | MSTK_SET_REG_SEC(mregs,real_seconds); | ||
1126 | MSTK_SET_REG_MIN(mregs,real_minutes); | ||
1127 | |||
1128 | tmp = mostek_read(mregs + MOSTEK_CREG); | ||
1129 | tmp &= ~MSTK_CREG_WRITE; | ||
1130 | mostek_write(mregs + MOSTEK_CREG, tmp); | ||
1131 | |||
1132 | spin_unlock_irqrestore(&mostek_lock, flags); | ||
1133 | |||
1134 | return 0; | ||
1135 | } else { | ||
1136 | spin_unlock_irqrestore(&mostek_lock, flags); | ||
1137 | |||
1138 | return -1; | ||
1139 | } | ||
1140 | } else if (bregs) { | ||
1141 | int retval = 0; | ||
1142 | unsigned char val = readb(bregs + 0x0e); | ||
1143 | |||
1144 | /* BQ4802 RTC chip. */ | ||
1145 | |||
1146 | writeb(val | 0x08, bregs + 0x0e); | ||
1147 | |||
1148 | chip_minutes = readb(bregs + 0x02); | ||
1149 | BCD_TO_BIN(chip_minutes); | ||
1150 | real_seconds = nowtime % 60; | ||
1151 | real_minutes = nowtime / 60; | ||
1152 | if (((abs(real_minutes - chip_minutes) + 15)/30) & 1) | ||
1153 | real_minutes += 30; | ||
1154 | real_minutes %= 60; | ||
1155 | |||
1156 | if (abs(real_minutes - chip_minutes) < 30) { | ||
1157 | BIN_TO_BCD(real_seconds); | ||
1158 | BIN_TO_BCD(real_minutes); | ||
1159 | writeb(real_seconds, bregs + 0x00); | ||
1160 | writeb(real_minutes, bregs + 0x02); | ||
1161 | } else { | ||
1162 | printk(KERN_WARNING | ||
1163 | "set_rtc_mmss: can't update from %d to %d\n", | ||
1164 | chip_minutes, real_minutes); | ||
1165 | retval = -1; | ||
1166 | } | ||
1167 | |||
1168 | writeb(val, bregs + 0x0e); | ||
1169 | |||
1170 | return retval; | ||
1171 | } else { | ||
1172 | int retval = 0; | ||
1173 | unsigned char save_control, save_freq_select; | ||
1174 | |||
1175 | /* Stolen from arch/i386/kernel/time.c, see there for | ||
1176 | * credits and descriptive comments. | ||
1177 | */ | ||
1178 | spin_lock_irqsave(&rtc_lock, flags); | ||
1179 | save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ | ||
1180 | CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); | ||
1181 | |||
1182 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ | ||
1183 | CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); | ||
1184 | |||
1185 | chip_minutes = CMOS_READ(RTC_MINUTES); | ||
1186 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | ||
1187 | BCD_TO_BIN(chip_minutes); | ||
1188 | real_seconds = nowtime % 60; | ||
1189 | real_minutes = nowtime / 60; | ||
1190 | if (((abs(real_minutes - chip_minutes) + 15)/30) & 1) | ||
1191 | real_minutes += 30; | ||
1192 | real_minutes %= 60; | ||
1193 | |||
1194 | if (abs(real_minutes - chip_minutes) < 30) { | ||
1195 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | ||
1196 | BIN_TO_BCD(real_seconds); | ||
1197 | BIN_TO_BCD(real_minutes); | ||
1198 | } | ||
1199 | CMOS_WRITE(real_seconds,RTC_SECONDS); | ||
1200 | CMOS_WRITE(real_minutes,RTC_MINUTES); | ||
1201 | } else { | ||
1202 | printk(KERN_WARNING | ||
1203 | "set_rtc_mmss: can't update from %d to %d\n", | ||
1204 | chip_minutes, real_minutes); | ||
1205 | retval = -1; | ||
1206 | } | ||
1207 | |||
1208 | CMOS_WRITE(save_control, RTC_CONTROL); | ||
1209 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); | ||
1210 | spin_unlock_irqrestore(&rtc_lock, flags); | ||
1211 | |||
1212 | return retval; | ||
1213 | } | ||
1214 | } | ||
1215 | |||
1216 | #define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ | ||
1217 | static unsigned char mini_rtc_status; /* bitmapped status byte. */ | ||
1218 | |||
1219 | #define FEBRUARY 2 | ||
1220 | #define STARTOFTIME 1970 | ||
1221 | #define SECDAY 86400L | ||
1222 | #define SECYR (SECDAY * 365) | ||
1223 | #define leapyear(year) ((year) % 4 == 0 && \ | ||
1224 | ((year) % 100 != 0 || (year) % 400 == 0)) | ||
1225 | #define days_in_year(a) (leapyear(a) ? 366 : 365) | ||
1226 | #define days_in_month(a) (month_days[(a) - 1]) | ||
1227 | |||
1228 | static int month_days[12] = { | ||
1229 | 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 | ||
1230 | }; | ||
1231 | |||
1232 | /* | ||
1233 | * This only works for the Gregorian calendar - i.e. after 1752 (in the UK) | ||
1234 | */ | ||
1235 | static void GregorianDay(struct rtc_time * tm) | ||
1236 | { | ||
1237 | int leapsToDate; | ||
1238 | int lastYear; | ||
1239 | int day; | ||
1240 | int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; | ||
1241 | |||
1242 | lastYear = tm->tm_year - 1; | ||
1243 | |||
1244 | /* | ||
1245 | * Number of leap corrections to apply up to end of last year | ||
1246 | */ | ||
1247 | leapsToDate = lastYear / 4 - lastYear / 100 + lastYear / 400; | ||
1248 | |||
1249 | /* | ||
1250 | * This year is a leap year if it is divisible by 4 except when it is | ||
1251 | * divisible by 100 unless it is divisible by 400 | ||
1252 | * | ||
1253 | * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 was | ||
1254 | */ | ||
1255 | day = tm->tm_mon > 2 && leapyear(tm->tm_year); | ||
1256 | |||
1257 | day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + | ||
1258 | tm->tm_mday; | ||
1259 | |||
1260 | tm->tm_wday = day % 7; | ||
1261 | } | ||
1262 | |||
1263 | static void to_tm(int tim, struct rtc_time *tm) | ||
1264 | { | ||
1265 | register int i; | ||
1266 | register long hms, day; | ||
1267 | |||
1268 | day = tim / SECDAY; | ||
1269 | hms = tim % SECDAY; | ||
1270 | |||
1271 | /* Hours, minutes, seconds are easy */ | ||
1272 | tm->tm_hour = hms / 3600; | ||
1273 | tm->tm_min = (hms % 3600) / 60; | ||
1274 | tm->tm_sec = (hms % 3600) % 60; | ||
1275 | |||
1276 | /* Number of years in days */ | ||
1277 | for (i = STARTOFTIME; day >= days_in_year(i); i++) | ||
1278 | day -= days_in_year(i); | ||
1279 | tm->tm_year = i; | ||
1280 | |||
1281 | /* Number of months in days left */ | ||
1282 | if (leapyear(tm->tm_year)) | ||
1283 | days_in_month(FEBRUARY) = 29; | ||
1284 | for (i = 1; day >= days_in_month(i); i++) | ||
1285 | day -= days_in_month(i); | ||
1286 | days_in_month(FEBRUARY) = 28; | ||
1287 | tm->tm_mon = i; | ||
1288 | |||
1289 | /* Days are what is left over (+1) from all that. */ | ||
1290 | tm->tm_mday = day + 1; | ||
1291 | |||
1292 | /* | ||
1293 | * Determine the day of week | ||
1294 | */ | ||
1295 | GregorianDay(tm); | ||
1296 | } | ||
1297 | |||
1298 | /* Both Starfire and SUN4V give us seconds since Jan 1st, 1970, | ||
1299 | * aka Unix time. So we have to convert to/from rtc_time. | ||
1300 | */ | ||
1301 | static void starfire_get_rtc_time(struct rtc_time *time) | ||
1302 | { | ||
1303 | u32 seconds = starfire_get_time(); | ||
1304 | |||
1305 | to_tm(seconds, time); | ||
1306 | time->tm_year -= 1900; | ||
1307 | time->tm_mon -= 1; | ||
1308 | } | ||
1309 | |||
1310 | static int starfire_set_rtc_time(struct rtc_time *time) | ||
1311 | { | ||
1312 | u32 seconds = mktime(time->tm_year + 1900, time->tm_mon + 1, | ||
1313 | time->tm_mday, time->tm_hour, | ||
1314 | time->tm_min, time->tm_sec); | ||
1315 | |||
1316 | return starfire_set_time(seconds); | ||
1317 | } | ||
1318 | |||
1319 | static void hypervisor_get_rtc_time(struct rtc_time *time) | ||
1320 | { | ||
1321 | u32 seconds = hypervisor_get_time(); | ||
1322 | |||
1323 | to_tm(seconds, time); | ||
1324 | time->tm_year -= 1900; | ||
1325 | time->tm_mon -= 1; | ||
1326 | } | ||
1327 | |||
1328 | static int hypervisor_set_rtc_time(struct rtc_time *time) | ||
1329 | { | ||
1330 | u32 seconds = mktime(time->tm_year + 1900, time->tm_mon + 1, | ||
1331 | time->tm_mday, time->tm_hour, | ||
1332 | time->tm_min, time->tm_sec); | ||
1333 | |||
1334 | return hypervisor_set_time(seconds); | ||
1335 | } | ||
1336 | |||
1337 | #ifdef CONFIG_PCI | ||
1338 | static void bq4802_get_rtc_time(struct rtc_time *time) | ||
1339 | { | ||
1340 | unsigned char val = readb(bq4802_regs + 0x0e); | ||
1341 | unsigned int century; | ||
1342 | |||
1343 | writeb(val | 0x08, bq4802_regs + 0x0e); | ||
1344 | |||
1345 | time->tm_sec = readb(bq4802_regs + 0x00); | ||
1346 | time->tm_min = readb(bq4802_regs + 0x02); | ||
1347 | time->tm_hour = readb(bq4802_regs + 0x04); | ||
1348 | time->tm_mday = readb(bq4802_regs + 0x06); | ||
1349 | time->tm_mon = readb(bq4802_regs + 0x09); | ||
1350 | time->tm_year = readb(bq4802_regs + 0x0a); | ||
1351 | time->tm_wday = readb(bq4802_regs + 0x08); | ||
1352 | century = readb(bq4802_regs + 0x0f); | ||
1353 | |||
1354 | writeb(val, bq4802_regs + 0x0e); | ||
1355 | |||
1356 | BCD_TO_BIN(time->tm_sec); | ||
1357 | BCD_TO_BIN(time->tm_min); | ||
1358 | BCD_TO_BIN(time->tm_hour); | ||
1359 | BCD_TO_BIN(time->tm_mday); | ||
1360 | BCD_TO_BIN(time->tm_mon); | ||
1361 | BCD_TO_BIN(time->tm_year); | ||
1362 | BCD_TO_BIN(time->tm_wday); | ||
1363 | BCD_TO_BIN(century); | ||
1364 | |||
1365 | time->tm_year += (century * 100); | ||
1366 | time->tm_year -= 1900; | ||
1367 | |||
1368 | time->tm_mon--; | ||
1369 | } | ||
1370 | |||
1371 | static int bq4802_set_rtc_time(struct rtc_time *time) | ||
1372 | { | ||
1373 | unsigned char val = readb(bq4802_regs + 0x0e); | ||
1374 | unsigned char sec, min, hrs, day, mon, yrs, century; | ||
1375 | unsigned int year; | ||
1376 | |||
1377 | year = time->tm_year + 1900; | ||
1378 | century = year / 100; | ||
1379 | yrs = year % 100; | ||
1380 | |||
1381 | mon = time->tm_mon + 1; /* tm_mon starts at zero */ | ||
1382 | day = time->tm_mday; | ||
1383 | hrs = time->tm_hour; | ||
1384 | min = time->tm_min; | ||
1385 | sec = time->tm_sec; | ||
1386 | |||
1387 | BIN_TO_BCD(sec); | ||
1388 | BIN_TO_BCD(min); | ||
1389 | BIN_TO_BCD(hrs); | ||
1390 | BIN_TO_BCD(day); | ||
1391 | BIN_TO_BCD(mon); | ||
1392 | BIN_TO_BCD(yrs); | ||
1393 | BIN_TO_BCD(century); | ||
1394 | |||
1395 | writeb(val | 0x08, bq4802_regs + 0x0e); | ||
1396 | |||
1397 | writeb(sec, bq4802_regs + 0x00); | ||
1398 | writeb(min, bq4802_regs + 0x02); | ||
1399 | writeb(hrs, bq4802_regs + 0x04); | ||
1400 | writeb(day, bq4802_regs + 0x06); | ||
1401 | writeb(mon, bq4802_regs + 0x09); | ||
1402 | writeb(yrs, bq4802_regs + 0x0a); | ||
1403 | writeb(century, bq4802_regs + 0x0f); | ||
1404 | |||
1405 | writeb(val, bq4802_regs + 0x0e); | ||
1406 | |||
1407 | return 0; | ||
1408 | } | ||
1409 | |||
1410 | static void cmos_get_rtc_time(struct rtc_time *rtc_tm) | ||
1411 | { | ||
1412 | unsigned char ctrl; | ||
1413 | |||
1414 | rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); | ||
1415 | rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); | ||
1416 | rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); | ||
1417 | rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); | ||
1418 | rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); | ||
1419 | rtc_tm->tm_year = CMOS_READ(RTC_YEAR); | ||
1420 | rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK); | ||
1421 | |||
1422 | ctrl = CMOS_READ(RTC_CONTROL); | ||
1423 | if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | ||
1424 | BCD_TO_BIN(rtc_tm->tm_sec); | ||
1425 | BCD_TO_BIN(rtc_tm->tm_min); | ||
1426 | BCD_TO_BIN(rtc_tm->tm_hour); | ||
1427 | BCD_TO_BIN(rtc_tm->tm_mday); | ||
1428 | BCD_TO_BIN(rtc_tm->tm_mon); | ||
1429 | BCD_TO_BIN(rtc_tm->tm_year); | ||
1430 | BCD_TO_BIN(rtc_tm->tm_wday); | ||
1431 | } | ||
1432 | |||
1433 | if (rtc_tm->tm_year <= 69) | ||
1434 | rtc_tm->tm_year += 100; | ||
1435 | |||
1436 | rtc_tm->tm_mon--; | ||
1437 | } | ||
1438 | |||
1439 | static int cmos_set_rtc_time(struct rtc_time *rtc_tm) | ||
1440 | { | ||
1441 | unsigned char mon, day, hrs, min, sec; | ||
1442 | unsigned char save_control, save_freq_select; | ||
1443 | unsigned int yrs; | ||
1444 | |||
1445 | yrs = rtc_tm->tm_year; | ||
1446 | mon = rtc_tm->tm_mon + 1; | ||
1447 | day = rtc_tm->tm_mday; | ||
1448 | hrs = rtc_tm->tm_hour; | ||
1449 | min = rtc_tm->tm_min; | ||
1450 | sec = rtc_tm->tm_sec; | ||
1451 | |||
1452 | if (yrs >= 100) | ||
1453 | yrs -= 100; | ||
1454 | |||
1455 | if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | ||
1456 | BIN_TO_BCD(sec); | ||
1457 | BIN_TO_BCD(min); | ||
1458 | BIN_TO_BCD(hrs); | ||
1459 | BIN_TO_BCD(day); | ||
1460 | BIN_TO_BCD(mon); | ||
1461 | BIN_TO_BCD(yrs); | ||
1462 | } | ||
1463 | |||
1464 | save_control = CMOS_READ(RTC_CONTROL); | ||
1465 | CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); | ||
1466 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); | ||
1467 | CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); | ||
1468 | |||
1469 | CMOS_WRITE(yrs, RTC_YEAR); | ||
1470 | CMOS_WRITE(mon, RTC_MONTH); | ||
1471 | CMOS_WRITE(day, RTC_DAY_OF_MONTH); | ||
1472 | CMOS_WRITE(hrs, RTC_HOURS); | ||
1473 | CMOS_WRITE(min, RTC_MINUTES); | ||
1474 | CMOS_WRITE(sec, RTC_SECONDS); | ||
1475 | |||
1476 | CMOS_WRITE(save_control, RTC_CONTROL); | ||
1477 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); | ||
1478 | |||
1479 | return 0; | ||
1480 | } | ||
1481 | #endif /* CONFIG_PCI */ | ||
1482 | |||
1483 | static void mostek_get_rtc_time(struct rtc_time *rtc_tm) | ||
1484 | { | ||
1485 | void __iomem *regs = mstk48t02_regs; | ||
1486 | u8 tmp; | ||
1487 | |||
1488 | spin_lock_irq(&mostek_lock); | ||
1489 | |||
1490 | tmp = mostek_read(regs + MOSTEK_CREG); | ||
1491 | tmp |= MSTK_CREG_READ; | ||
1492 | mostek_write(regs + MOSTEK_CREG, tmp); | ||
1493 | |||
1494 | rtc_tm->tm_sec = MSTK_REG_SEC(regs); | ||
1495 | rtc_tm->tm_min = MSTK_REG_MIN(regs); | ||
1496 | rtc_tm->tm_hour = MSTK_REG_HOUR(regs); | ||
1497 | rtc_tm->tm_mday = MSTK_REG_DOM(regs); | ||
1498 | rtc_tm->tm_mon = MSTK_REG_MONTH(regs); | ||
1499 | rtc_tm->tm_year = MSTK_CVT_YEAR( MSTK_REG_YEAR(regs) ); | ||
1500 | rtc_tm->tm_wday = MSTK_REG_DOW(regs); | ||
1501 | |||
1502 | tmp = mostek_read(regs + MOSTEK_CREG); | ||
1503 | tmp &= ~MSTK_CREG_READ; | ||
1504 | mostek_write(regs + MOSTEK_CREG, tmp); | ||
1505 | |||
1506 | spin_unlock_irq(&mostek_lock); | ||
1507 | |||
1508 | rtc_tm->tm_mon--; | ||
1509 | rtc_tm->tm_wday--; | ||
1510 | rtc_tm->tm_year -= 1900; | ||
1511 | } | ||
1512 | |||
1513 | static int mostek_set_rtc_time(struct rtc_time *rtc_tm) | ||
1514 | { | ||
1515 | unsigned char mon, day, hrs, min, sec, wday; | ||
1516 | void __iomem *regs = mstk48t02_regs; | ||
1517 | unsigned int yrs; | ||
1518 | u8 tmp; | ||
1519 | |||
1520 | yrs = rtc_tm->tm_year + 1900; | ||
1521 | mon = rtc_tm->tm_mon + 1; | ||
1522 | day = rtc_tm->tm_mday; | ||
1523 | wday = rtc_tm->tm_wday + 1; | ||
1524 | hrs = rtc_tm->tm_hour; | ||
1525 | min = rtc_tm->tm_min; | ||
1526 | sec = rtc_tm->tm_sec; | ||
1527 | |||
1528 | spin_lock_irq(&mostek_lock); | ||
1529 | |||
1530 | tmp = mostek_read(regs + MOSTEK_CREG); | ||
1531 | tmp |= MSTK_CREG_WRITE; | ||
1532 | mostek_write(regs + MOSTEK_CREG, tmp); | ||
1533 | |||
1534 | MSTK_SET_REG_SEC(regs, sec); | ||
1535 | MSTK_SET_REG_MIN(regs, min); | ||
1536 | MSTK_SET_REG_HOUR(regs, hrs); | ||
1537 | MSTK_SET_REG_DOW(regs, wday); | ||
1538 | MSTK_SET_REG_DOM(regs, day); | ||
1539 | MSTK_SET_REG_MONTH(regs, mon); | ||
1540 | MSTK_SET_REG_YEAR(regs, yrs - MSTK_YEAR_ZERO); | ||
1541 | |||
1542 | tmp = mostek_read(regs + MOSTEK_CREG); | ||
1543 | tmp &= ~MSTK_CREG_WRITE; | ||
1544 | mostek_write(regs + MOSTEK_CREG, tmp); | ||
1545 | |||
1546 | spin_unlock_irq(&mostek_lock); | ||
1547 | |||
1548 | return 0; | ||
1549 | } | ||
1550 | |||
1551 | struct mini_rtc_ops { | ||
1552 | void (*get_rtc_time)(struct rtc_time *); | ||
1553 | int (*set_rtc_time)(struct rtc_time *); | ||
1554 | }; | ||
1555 | |||
1556 | static struct mini_rtc_ops starfire_rtc_ops = { | ||
1557 | .get_rtc_time = starfire_get_rtc_time, | ||
1558 | .set_rtc_time = starfire_set_rtc_time, | ||
1559 | }; | ||
1560 | |||
1561 | static struct mini_rtc_ops hypervisor_rtc_ops = { | ||
1562 | .get_rtc_time = hypervisor_get_rtc_time, | ||
1563 | .set_rtc_time = hypervisor_set_rtc_time, | ||
1564 | }; | ||
1565 | |||
1566 | #ifdef CONFIG_PCI | ||
1567 | static struct mini_rtc_ops bq4802_rtc_ops = { | ||
1568 | .get_rtc_time = bq4802_get_rtc_time, | ||
1569 | .set_rtc_time = bq4802_set_rtc_time, | ||
1570 | }; | ||
1571 | |||
1572 | static struct mini_rtc_ops cmos_rtc_ops = { | ||
1573 | .get_rtc_time = cmos_get_rtc_time, | ||
1574 | .set_rtc_time = cmos_set_rtc_time, | ||
1575 | }; | ||
1576 | #endif /* CONFIG_PCI */ | ||
1577 | |||
1578 | static struct mini_rtc_ops mostek_rtc_ops = { | ||
1579 | .get_rtc_time = mostek_get_rtc_time, | ||
1580 | .set_rtc_time = mostek_set_rtc_time, | ||
1581 | }; | ||
1582 | |||
1583 | static struct mini_rtc_ops *mini_rtc_ops; | ||
1584 | |||
1585 | static inline void mini_get_rtc_time(struct rtc_time *time) | ||
1586 | { | ||
1587 | unsigned long flags; | ||
1588 | |||
1589 | spin_lock_irqsave(&rtc_lock, flags); | ||
1590 | mini_rtc_ops->get_rtc_time(time); | ||
1591 | spin_unlock_irqrestore(&rtc_lock, flags); | ||
1592 | } | ||
1593 | |||
1594 | static inline int mini_set_rtc_time(struct rtc_time *time) | ||
1595 | { | ||
1596 | unsigned long flags; | ||
1597 | int err; | ||
1598 | |||
1599 | spin_lock_irqsave(&rtc_lock, flags); | ||
1600 | err = mini_rtc_ops->set_rtc_time(time); | ||
1601 | spin_unlock_irqrestore(&rtc_lock, flags); | ||
1602 | |||
1603 | return err; | ||
1604 | } | ||
1605 | |||
1606 | static int mini_rtc_ioctl(struct inode *inode, struct file *file, | ||
1607 | unsigned int cmd, unsigned long arg) | ||
1608 | { | ||
1609 | struct rtc_time wtime; | ||
1610 | void __user *argp = (void __user *)arg; | ||
1611 | |||
1612 | switch (cmd) { | ||
1613 | |||
1614 | case RTC_PLL_GET: | ||
1615 | return -EINVAL; | ||
1616 | |||
1617 | case RTC_PLL_SET: | ||
1618 | return -EINVAL; | ||
1619 | |||
1620 | case RTC_UIE_OFF: /* disable ints from RTC updates. */ | ||
1621 | return 0; | ||
1622 | |||
1623 | case RTC_UIE_ON: /* enable ints for RTC updates. */ | ||
1624 | return -EINVAL; | ||
1625 | |||
1626 | case RTC_RD_TIME: /* Read the time/date from RTC */ | ||
1627 | /* this doesn't get week-day, who cares */ | ||
1628 | memset(&wtime, 0, sizeof(wtime)); | ||
1629 | mini_get_rtc_time(&wtime); | ||
1630 | |||
1631 | return copy_to_user(argp, &wtime, sizeof(wtime)) ? -EFAULT : 0; | ||
1632 | |||
1633 | case RTC_SET_TIME: /* Set the RTC */ | ||
1634 | { | ||
1635 | int year, days; | ||
1636 | |||
1637 | if (!capable(CAP_SYS_TIME)) | ||
1638 | return -EACCES; | ||
1639 | |||
1640 | if (copy_from_user(&wtime, argp, sizeof(wtime))) | ||
1641 | return -EFAULT; | ||
1642 | |||
1643 | year = wtime.tm_year + 1900; | ||
1644 | days = month_days[wtime.tm_mon] + | ||
1645 | ((wtime.tm_mon == 1) && leapyear(year)); | ||
1646 | |||
1647 | if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) || | ||
1648 | (wtime.tm_mday < 1)) | ||
1649 | return -EINVAL; | ||
1650 | |||
1651 | if (wtime.tm_mday < 0 || wtime.tm_mday > days) | ||
1652 | return -EINVAL; | ||
1653 | |||
1654 | if (wtime.tm_hour < 0 || wtime.tm_hour >= 24 || | ||
1655 | wtime.tm_min < 0 || wtime.tm_min >= 60 || | ||
1656 | wtime.tm_sec < 0 || wtime.tm_sec >= 60) | ||
1657 | return -EINVAL; | ||
1658 | |||
1659 | return mini_set_rtc_time(&wtime); | ||
1660 | } | ||
1661 | } | ||
1662 | |||
1663 | return -EINVAL; | ||
1664 | } | ||
1665 | |||
1666 | static int mini_rtc_open(struct inode *inode, struct file *file) | ||
1667 | { | ||
1668 | lock_kernel(); | ||
1669 | if (mini_rtc_status & RTC_IS_OPEN) { | ||
1670 | unlock_kernel(); | ||
1671 | return -EBUSY; | ||
1672 | } | ||
1673 | |||
1674 | mini_rtc_status |= RTC_IS_OPEN; | ||
1675 | unlock_kernel(); | ||
1676 | |||
1677 | return 0; | ||
1678 | } | ||
1679 | |||
1680 | static int mini_rtc_release(struct inode *inode, struct file *file) | ||
1681 | { | ||
1682 | mini_rtc_status &= ~RTC_IS_OPEN; | ||
1683 | return 0; | ||
1684 | } | ||
1685 | |||
1686 | |||
1687 | static const struct file_operations mini_rtc_fops = { | ||
1688 | .owner = THIS_MODULE, | ||
1689 | .ioctl = mini_rtc_ioctl, | ||
1690 | .open = mini_rtc_open, | ||
1691 | .release = mini_rtc_release, | ||
1692 | }; | ||
1693 | |||
1694 | static struct miscdevice rtc_mini_dev = | ||
1695 | { | ||
1696 | .minor = RTC_MINOR, | ||
1697 | .name = "rtc", | ||
1698 | .fops = &mini_rtc_fops, | ||
1699 | }; | ||
1700 | |||
1701 | static int __init rtc_mini_init(void) | ||
1702 | { | ||
1703 | int retval; | ||
1704 | |||
1705 | if (tlb_type == hypervisor) | ||
1706 | mini_rtc_ops = &hypervisor_rtc_ops; | ||
1707 | else if (this_is_starfire) | ||
1708 | mini_rtc_ops = &starfire_rtc_ops; | ||
1709 | #ifdef CONFIG_PCI | ||
1710 | else if (bq4802_regs) | ||
1711 | mini_rtc_ops = &bq4802_rtc_ops; | ||
1712 | else if (ds1287_regs) | ||
1713 | mini_rtc_ops = &cmos_rtc_ops; | ||
1714 | #endif /* CONFIG_PCI */ | ||
1715 | else if (mstk48t02_regs) | ||
1716 | mini_rtc_ops = &mostek_rtc_ops; | ||
1717 | else | ||
1718 | return -ENODEV; | ||
1719 | |||
1720 | printk(KERN_INFO "Mini RTC Driver\n"); | ||
1721 | |||
1722 | retval = misc_register(&rtc_mini_dev); | ||
1723 | if (retval < 0) | ||
1724 | return retval; | ||
1725 | |||
1726 | return 0; | ||
1727 | } | ||
1728 | |||
1729 | static void __exit rtc_mini_exit(void) | ||
1730 | { | ||
1731 | misc_deregister(&rtc_mini_dev); | ||
1732 | } | ||
1733 | |||
1734 | int __devinit read_current_timer(unsigned long *timer_val) | 880 | int __devinit read_current_timer(unsigned long *timer_val) |
1735 | { | 881 | { |
1736 | *timer_val = tick_ops->get_tick(); | 882 | *timer_val = tick_ops->get_tick(); |
1737 | return 0; | 883 | return 0; |
1738 | } | 884 | } |
1739 | |||
1740 | module_init(rtc_mini_init); | ||
1741 | module_exit(rtc_mini_exit); | ||