From da86783dda5ad8c64b945157108d1ace7aa79bbf Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 28 Aug 2008 22:16:15 -0700 Subject: sparc64: Use generic CMOS driver. Based largely upon a patch by Krzysztof Helt Signed-off-by: David S. Miller --- arch/sparc64/kernel/time.c | 372 +++++++++++++++------------------------------ 1 file changed, 120 insertions(+), 252 deletions(-) (limited to 'arch/sparc64/kernel') diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 9c2c3d84443d..abdeead4e5b9 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -52,10 +52,7 @@ #include "entry.h" DEFINE_SPINLOCK(rtc_lock); -#ifdef CONFIG_PCI -unsigned long ds1287_regs = 0UL; static void __iomem *bq4802_regs; -#endif static int set_rtc_mmss(unsigned long); @@ -413,69 +410,38 @@ int update_persistent_clock(struct timespec now) static void __init set_system_time(void) { unsigned int year, mon, day, hour, min, sec; -#ifdef CONFIG_PCI - unsigned long dregs = ds1287_regs; void __iomem *bregs = bq4802_regs; -#else - unsigned long dregs = 0UL; - void __iomem *bregs = 0UL; -#endif + unsigned char val = readb(bregs + 0x0e); + unsigned int century; - if (!dregs && !bregs) { + if (!bregs) { prom_printf("Something wrong, clock regs not mapped yet.\n"); prom_halt(); } - if (bregs) { - unsigned char val = readb(bregs + 0x0e); - unsigned int century; + /* BQ4802 RTC chip. */ - /* BQ4802 RTC chip. */ + writeb(val | 0x08, bregs + 0x0e); - writeb(val | 0x08, bregs + 0x0e); + sec = readb(bregs + 0x00); + min = readb(bregs + 0x02); + hour = readb(bregs + 0x04); + day = readb(bregs + 0x06); + mon = readb(bregs + 0x09); + year = readb(bregs + 0x0a); + century = readb(bregs + 0x0f); - sec = readb(bregs + 0x00); - min = readb(bregs + 0x02); - hour = readb(bregs + 0x04); - day = readb(bregs + 0x06); - mon = readb(bregs + 0x09); - year = readb(bregs + 0x0a); - century = readb(bregs + 0x0f); + writeb(val, bregs + 0x0e); - writeb(val, bregs + 0x0e); - - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hour); - BCD_TO_BIN(day); - BCD_TO_BIN(mon); - BCD_TO_BIN(year); - BCD_TO_BIN(century); + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + BCD_TO_BIN(century); - year += (century * 100); - } else { - /* Dallas 12887 RTC chip. */ - - do { - sec = CMOS_READ(RTC_SECONDS); - min = CMOS_READ(RTC_MINUTES); - hour = CMOS_READ(RTC_HOURS); - day = CMOS_READ(RTC_DAY_OF_MONTH); - mon = CMOS_READ(RTC_MONTH); - year = CMOS_READ(RTC_YEAR); - } while (sec != CMOS_READ(RTC_SECONDS)); - - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hour); - BCD_TO_BIN(day); - BCD_TO_BIN(mon); - BCD_TO_BIN(year); - } - if ((year += 1900) < 1970) - year += 100; - } + year += (century * 100); xtime.tv_sec = mktime(year, mon, day, hour, min, sec); xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); @@ -546,48 +512,79 @@ retry: return -EOPNOTSUPP; } -static int __init rtc_model_matches(const char *model) -{ - if (strcmp(model, "m5819") && - strcmp(model, "m5819p") && - strcmp(model, "m5823") && - strcmp(model, "ds1287") && - strcmp(model, "bq4802")) - return 0; +unsigned long cmos_regs; +EXPORT_SYMBOL(cmos_regs); - return 1; -} +struct resource rtc_cmos_resource; + +static struct platform_device rtc_cmos_device = { + .name = "rtc_cmos", + .id = -1, + .resource = &rtc_cmos_resource, + .num_resources = 1, +}; static int __devinit rtc_probe(struct of_device *op, const struct of_device_id *match) { - struct device_node *dp = op->node; - const char *model = of_get_property(dp, "model", NULL); - const char *compat = of_get_property(dp, "compatible", NULL); - unsigned long size, flags; - void __iomem *regs; + struct resource *r; - if (!model) - model = compat; + printk(KERN_INFO "%s: RTC regs at 0x%lx\n", + op->node->full_name, op->resource[0].start); - if (!model || !rtc_model_matches(model)) - return -ENODEV; + /* The CMOS RTC driver only accepts IORESOURCE_IO, so cons + * up a fake resource so that the probe works for all cases. + * When the RTC is behind an ISA bus it will have IORESOURCE_IO + * already, whereas when it's behind EBUS is will be IORESOURCE_MEM. + */ + + r = &rtc_cmos_resource; + r->flags = IORESOURCE_IO; + r->name = op->resource[0].name; + r->start = op->resource[0].start; + r->end = op->resource[0].end; + + cmos_regs = op->resource[0].start; + return platform_device_register(&rtc_cmos_device); +} + +static struct of_device_id rtc_match[] = { + { + .name = "rtc", + .compatible = "m5819", + }, + { + .name = "rtc", + .compatible = "isa-m5819p", + }, + { + .name = "rtc", + .compatible = "isa-m5823p", + }, + { + .name = "rtc", + .compatible = "ds1287", + }, + {}, +}; + +static struct of_platform_driver rtc_driver = { + .match_table = rtc_match, + .probe = rtc_probe, + .driver = { + .name = "rtc", + }, +}; - size = (op->resource[0].end - op->resource[0].start) + 1; - regs = of_ioremap(&op->resource[0], 0, size, "clock"); - if (!regs) +static int __devinit bq4802_probe(struct of_device *op, const struct of_device_id *match) +{ + struct device_node *dp = op->node; + unsigned long flags; + + bq4802_regs = of_ioremap(&op->resource[0], 0, resource_size(&op->resource[0]), "bq4802"); + if (!bq4802_regs) return -ENOMEM; -#ifdef CONFIG_PCI - if (!strcmp(model, "ds1287") || - !strcmp(model, "m5819") || - !strcmp(model, "m5819p") || - !strcmp(model, "m5823")) { - ds1287_regs = (unsigned long) regs; - } else if (!strcmp(model, "bq4802")) { - bq4802_regs = regs; - } -#endif - printk(KERN_INFO "%s: Clock regs at %p\n", dp->full_name, regs); + printk(KERN_INFO "%s: Clock regs at %p\n", dp->full_name, bq4802_regs); local_irq_save(flags); @@ -598,18 +595,18 @@ static int __devinit rtc_probe(struct of_device *op, const struct of_device_id * return 0; } -static struct of_device_id rtc_match[] = { +static struct of_device_id bq4802_match[] = { { .name = "rtc", + .compatible = "bq4802", }, - {}, }; -static struct of_platform_driver rtc_driver = { - .match_table = rtc_match, - .probe = rtc_probe, +static struct of_platform_driver bq4802_driver = { + .match_table = bq4802_match, + .probe = bq4802_probe, .driver = { - .name = "rtc", + .name = "bq4802", }, }; @@ -716,6 +713,7 @@ static int __init clock_init(void) (void) of_register_driver(&rtc_driver, &of_platform_bus_type); (void) of_register_driver(&mostek_driver, &of_platform_bus_type); + (void) of_register_driver(&bq4802_driver, &of_platform_bus_type); return 0; } @@ -989,96 +987,51 @@ unsigned long long sched_clock(void) static int set_rtc_mmss(unsigned long nowtime) { int real_seconds, real_minutes, chip_minutes; -#ifdef CONFIG_PCI - unsigned long dregs = ds1287_regs; void __iomem *bregs = bq4802_regs; -#else - unsigned long dregs = 0UL; - void __iomem *bregs = 0UL; -#endif unsigned long flags; + unsigned char val; + int retval = 0; /* * Not having a register set can lead to trouble. * Also starfire doesn't have a tod clock. */ - if (!dregs && !bregs) + if (!bregs) return -1; - if (bregs) { - int retval = 0; - unsigned char val = readb(bregs + 0x0e); + spin_lock_irqsave(&rtc_lock, flags); - /* BQ4802 RTC chip. */ + val = readb(bregs + 0x0e); - writeb(val | 0x08, bregs + 0x0e); + /* BQ4802 RTC chip. */ - chip_minutes = readb(bregs + 0x02); - BCD_TO_BIN(chip_minutes); - real_seconds = nowtime % 60; - real_minutes = nowtime / 60; - if (((abs(real_minutes - chip_minutes) + 15)/30) & 1) - real_minutes += 30; - real_minutes %= 60; + writeb(val | 0x08, bregs + 0x0e); - if (abs(real_minutes - chip_minutes) < 30) { - BIN_TO_BCD(real_seconds); - BIN_TO_BCD(real_minutes); - writeb(real_seconds, bregs + 0x00); - writeb(real_minutes, bregs + 0x02); - } else { - printk(KERN_WARNING - "set_rtc_mmss: can't update from %d to %d\n", - chip_minutes, real_minutes); - retval = -1; - } + chip_minutes = readb(bregs + 0x02); + BCD_TO_BIN(chip_minutes); + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - chip_minutes) + 15)/30) & 1) + real_minutes += 30; + real_minutes %= 60; - writeb(val, bregs + 0x0e); - - return retval; + if (abs(real_minutes - chip_minutes) < 30) { + BIN_TO_BCD(real_seconds); + BIN_TO_BCD(real_minutes); + writeb(real_seconds, bregs + 0x00); + writeb(real_minutes, bregs + 0x02); } else { - int retval = 0; - unsigned char save_control, save_freq_select; - - /* Stolen from arch/i386/kernel/time.c, see there for - * credits and descriptive comments. - */ - spin_lock_irqsave(&rtc_lock, flags); - save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ - CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); - - save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ - CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); - - chip_minutes = CMOS_READ(RTC_MINUTES); - if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - BCD_TO_BIN(chip_minutes); - real_seconds = nowtime % 60; - real_minutes = nowtime / 60; - if (((abs(real_minutes - chip_minutes) + 15)/30) & 1) - real_minutes += 30; - real_minutes %= 60; - - if (abs(real_minutes - chip_minutes) < 30) { - if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BIN_TO_BCD(real_seconds); - BIN_TO_BCD(real_minutes); - } - CMOS_WRITE(real_seconds,RTC_SECONDS); - CMOS_WRITE(real_minutes,RTC_MINUTES); - } else { - printk(KERN_WARNING - "set_rtc_mmss: can't update from %d to %d\n", - chip_minutes, real_minutes); - retval = -1; - } + printk(KERN_WARNING + "set_rtc_mmss: can't update from %d to %d\n", + chip_minutes, real_minutes); + retval = -1; + } - CMOS_WRITE(save_control, RTC_CONTROL); - CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); - spin_unlock_irqrestore(&rtc_lock, flags); + writeb(val, bregs + 0x0e); - return retval; - } + spin_unlock_irqrestore(&rtc_lock, flags); + + return retval; } #define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ @@ -1202,7 +1155,6 @@ static int hypervisor_set_rtc_time(struct rtc_time *time) return hypervisor_set_time(seconds); } -#ifdef CONFIG_PCI static void bq4802_get_rtc_time(struct rtc_time *time) { unsigned char val = readb(bq4802_regs + 0x0e); @@ -1275,79 +1227,6 @@ static int bq4802_set_rtc_time(struct rtc_time *time) return 0; } -static void cmos_get_rtc_time(struct rtc_time *rtc_tm) -{ - unsigned char ctrl; - - rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); - rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); - rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); - rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); - rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); - rtc_tm->tm_year = CMOS_READ(RTC_YEAR); - rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK); - - ctrl = CMOS_READ(RTC_CONTROL); - if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BCD_TO_BIN(rtc_tm->tm_sec); - BCD_TO_BIN(rtc_tm->tm_min); - BCD_TO_BIN(rtc_tm->tm_hour); - BCD_TO_BIN(rtc_tm->tm_mday); - BCD_TO_BIN(rtc_tm->tm_mon); - BCD_TO_BIN(rtc_tm->tm_year); - BCD_TO_BIN(rtc_tm->tm_wday); - } - - if (rtc_tm->tm_year <= 69) - rtc_tm->tm_year += 100; - - rtc_tm->tm_mon--; -} - -static int cmos_set_rtc_time(struct rtc_time *rtc_tm) -{ - unsigned char mon, day, hrs, min, sec; - unsigned char save_control, save_freq_select; - unsigned int yrs; - - yrs = rtc_tm->tm_year; - mon = rtc_tm->tm_mon + 1; - day = rtc_tm->tm_mday; - hrs = rtc_tm->tm_hour; - min = rtc_tm->tm_min; - sec = rtc_tm->tm_sec; - - if (yrs >= 100) - yrs -= 100; - - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - BIN_TO_BCD(sec); - BIN_TO_BCD(min); - BIN_TO_BCD(hrs); - BIN_TO_BCD(day); - BIN_TO_BCD(mon); - BIN_TO_BCD(yrs); - } - - save_control = CMOS_READ(RTC_CONTROL); - CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); - save_freq_select = CMOS_READ(RTC_FREQ_SELECT); - CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); - - CMOS_WRITE(yrs, RTC_YEAR); - CMOS_WRITE(mon, RTC_MONTH); - CMOS_WRITE(day, RTC_DAY_OF_MONTH); - CMOS_WRITE(hrs, RTC_HOURS); - CMOS_WRITE(min, RTC_MINUTES); - CMOS_WRITE(sec, RTC_SECONDS); - - CMOS_WRITE(save_control, RTC_CONTROL); - CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); - - return 0; -} -#endif /* CONFIG_PCI */ - struct mini_rtc_ops { void (*get_rtc_time)(struct rtc_time *); int (*set_rtc_time)(struct rtc_time *); @@ -1363,18 +1242,11 @@ static struct mini_rtc_ops hypervisor_rtc_ops = { .set_rtc_time = hypervisor_set_rtc_time, }; -#ifdef CONFIG_PCI static struct mini_rtc_ops bq4802_rtc_ops = { .get_rtc_time = bq4802_get_rtc_time, .set_rtc_time = bq4802_set_rtc_time, }; -static struct mini_rtc_ops cmos_rtc_ops = { - .get_rtc_time = cmos_get_rtc_time, - .set_rtc_time = cmos_set_rtc_time, -}; -#endif /* CONFIG_PCI */ - static struct mini_rtc_ops *mini_rtc_ops; static inline void mini_get_rtc_time(struct rtc_time *time) @@ -1501,12 +1373,8 @@ static int __init rtc_mini_init(void) mini_rtc_ops = &hypervisor_rtc_ops; else if (this_is_starfire) mini_rtc_ops = &starfire_rtc_ops; -#ifdef CONFIG_PCI else if (bq4802_regs) mini_rtc_ops = &bq4802_rtc_ops; - else if (ds1287_regs) - mini_rtc_ops = &cmos_rtc_ops; -#endif /* CONFIG_PCI */ else return -ENODEV; -- cgit v1.2.3-59-g8ed1b