Merge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[pandora-kernel.git] / arch / sparc64 / kernel / time.c
index 348b820..094d3e3 100644 (file)
@@ -9,7 +9,6 @@
  * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
  */
 
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <asm/timer.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <asm/sbus.h>
-#include <asm/fhc.h>
-#include <asm/pbm.h>
-#include <asm/ebus.h>
-#include <asm/isa.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
 #include <asm/starfire.h>
 #include <asm/smp.h>
 #include <asm/sections.h>
@@ -770,237 +766,109 @@ static int __init clock_model_matches(char *model)
        return 1;
 }
 
-static void __init __clock_assign_common(void __iomem *addr, char *model)
-{
-       if (model[5] == '0' && model[6] == '2') {
-               mstk48t02_regs = addr;
-       } else if(model[5] == '0' && model[6] == '8') {
-               mstk48t08_regs = addr;
-               mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02;
-       } else {
-               mstk48t59_regs = addr;
-               mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
-       }
-}
-
-static void __init clock_assign_clk_reg(struct linux_prom_registers *clk_reg,
-                                       char *model)
-{
-       unsigned long addr;
-
-       addr = ((unsigned long) clk_reg[0].phys_addr |
-               (((unsigned long) clk_reg[0].which_io) << 32UL));
-
-       __clock_assign_common((void __iomem *) addr, model);
-}
-
-static int __init clock_probe_central(void)
+static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
 {
-       struct linux_prom_registers clk_reg[2], *pr;
-       struct device_node *dp;
-       char *model;
-
-       if (!central_bus)
-               return 0;
-
-       /* Get Central FHC's prom node.  */
-       dp = central_bus->child->prom_node;
-
-       /* Then get the first child device below it.  */
-       dp = dp->child;
-
-       while (dp) {
-               model = of_get_property(dp, "model", NULL);
-               if (!model || !clock_model_matches(model))
-                       goto next_sibling;
-
-               pr = of_get_property(dp, "reg", NULL);
-               memcpy(clk_reg, pr, sizeof(clk_reg));
-
-               apply_fhc_ranges(central_bus->child, clk_reg, 1);
-               apply_central_ranges(central_bus, clk_reg, 1);
+       struct device_node *dp = op->node;
+       char *model = of_get_property(dp, "model", NULL);
+       unsigned long size, flags;
+       void __iomem *regs;
 
-               clock_assign_clk_reg(clk_reg, model);
-               return 1;
+       if (!model || !clock_model_matches(model))
+               return -ENODEV;
 
-       next_sibling:
-               dp = dp->sibling;
-       }
+       /* On an Enterprise system there can be multiple mostek clocks.
+        * We should only match the one that is on the central FHC bus.
+        */
+       if (!strcmp(dp->parent->name, "fhc") &&
+           strcmp(dp->parent->parent->name, "central") != 0)
+               return -ENODEV;
 
-       return 0;
-}
+       size = (op->resource[0].end - op->resource[0].start) + 1;
+       regs = of_ioremap(&op->resource[0], 0, size, "clock");
+       if (!regs)
+               return -ENOMEM;
 
 #ifdef CONFIG_PCI
-static void __init clock_isa_ebus_assign_regs(struct resource *res, char *model)
-{
        if (!strcmp(model, "ds1287") ||
            !strcmp(model, "m5819") ||
            !strcmp(model, "m5819p") ||
            !strcmp(model, "m5823")) {
-               ds1287_regs = res->start;
+               ds1287_regs = (unsigned long) regs;
+       } else
+#endif
+       if (model[5] == '0' && model[6] == '2') {
+               mstk48t02_regs = regs;
+       } else if(model[5] == '0' && model[6] == '8') {
+               mstk48t08_regs = regs;
+               mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02;
        } else {
-               mstk48t59_regs = (void __iomem *) res->start;
+               mstk48t59_regs = regs;
                mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
        }
-}
-
-static int __init clock_probe_one_ebus_dev(struct linux_ebus_device *edev)
-{
-       struct device_node *dp = edev->prom_node;
-       char *model;
 
-       model = of_get_property(dp, "model", NULL);
-       if (!clock_model_matches(model))
-               return 0;
+       printk(KERN_INFO "%s: Clock regs at %p\n", dp->full_name, regs);
 
-       clock_isa_ebus_assign_regs(&edev->resource[0], model);
-
-       return 1;
-}
-
-static int __init clock_probe_ebus(void)
-{
-       struct linux_ebus *ebus;
+       local_irq_save(flags);
 
-       for_each_ebus(ebus) {
-               struct linux_ebus_device *edev;
+       if (mstk48t02_regs != NULL) {
+               /* Report a low battery voltage condition. */
+               if (has_low_battery())
+                       prom_printf("NVRAM: Low battery voltage!\n");
 
-               for_each_ebusdev(edev, ebus) {
-                       if (clock_probe_one_ebus_dev(edev))
-                               return 1;
-               }
+               /* Kick start the clock if it is completely stopped. */
+               if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
+                       kick_start_clock();
        }
 
-       return 0;
-}
-
-static int __init clock_probe_one_isa_dev(struct sparc_isa_device *idev)
-{
-       struct device_node *dp = idev->prom_node;
-       char *model;
-
-       model = of_get_property(dp, "model", NULL);
-       if (!clock_model_matches(model))
-               return 0;
-
-       clock_isa_ebus_assign_regs(&idev->resource, model);
-
-       return 1;
-}
-
-static int __init clock_probe_isa(void)
-{
-       struct sparc_isa_bridge *isa_br;
-
-       for_each_isa(isa_br) {
-               struct sparc_isa_device *isa_dev;
-
-               for_each_isadev(isa_dev, isa_br) {
-                       if (clock_probe_one_isa_dev(isa_dev))
-                               return 1;
-               }
-       }
+       set_system_time();
+       
+       local_irq_restore(flags);
 
        return 0;
 }
-#endif /* CONFIG_PCI */
-
-#ifdef CONFIG_SBUS
-static int __init clock_probe_one_sbus_dev(struct sbus_bus *sbus, struct sbus_dev *sdev)
-{
-       struct resource *res;
-       char model[64];
-       void __iomem *addr;
-
-       prom_getstring(sdev->prom_node, "model", model, sizeof(model));
-       if (!clock_model_matches(model))
-               return 0;
-
-       res = &sdev->resource[0];
-       addr = sbus_ioremap(res, 0, 0x800UL, "eeprom");
-
-       __clock_assign_common(addr, model);
-
-       return 1;
-}
-
-static int __init clock_probe_sbus(void)
-{
-       struct sbus_bus *sbus;
-
-       for_each_sbus(sbus) {
-               struct sbus_dev *sdev;
 
-               for_each_sbusdev(sdev, sbus) {
-                       if (clock_probe_one_sbus_dev(sbus, sdev))
-                               return 1;
-               }
-       }
+static struct of_device_id clock_match[] = {
+       {
+               .name = "eeprom",
+       },
+       {
+               .name = "rtc",
+       },
+       {},
+};
 
-       return 0;
-}
-#endif
+static struct of_platform_driver clock_driver = {
+       .name           = "clock",
+       .match_table    = clock_match,
+       .probe          = clock_probe,
+};
 
-void __init clock_probe(void)
+static int __init clock_init(void)
 {
-       static int invoked;
-       unsigned long flags;
-
-       if (invoked)
-               return;
-       invoked = 1;
-
        if (this_is_starfire) {
                xtime.tv_sec = starfire_get_time();
                xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
                set_normalized_timespec(&wall_to_monotonic,
                                        -xtime.tv_sec, -xtime.tv_nsec);
-               return;
+               return 0;
        }
        if (tlb_type == hypervisor) {
                xtime.tv_sec = hypervisor_get_time();
                xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
                set_normalized_timespec(&wall_to_monotonic,
                                        -xtime.tv_sec, -xtime.tv_nsec);
-               return;
-       }
-
-       /* Check FHC Central then EBUSs then ISA bridges then SBUSs.
-        * That way we handle the presence of multiple properly.
-        *
-        * As a special case, machines with Central must provide the
-        * timer chip there.
-        */
-       if (!clock_probe_central() &&
-#ifdef CONFIG_PCI
-           !clock_probe_ebus() &&
-           !clock_probe_isa() &&
-#endif
-#ifdef CONFIG_SBUS
-           !clock_probe_sbus()
-#endif
-               ) {
-               printk(KERN_WARNING "No clock chip found.\n");
-               return;
-       }
-
-       local_irq_save(flags);
-
-       if (mstk48t02_regs != NULL) {
-               /* Report a low battery voltage condition. */
-               if (has_low_battery())
-                       prom_printf("NVRAM: Low battery voltage!\n");
-
-               /* Kick start the clock if it is completely stopped. */
-               if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
-                       kick_start_clock();
+               return 0;
        }
 
-       set_system_time();
-       
-       local_irq_restore(flags);
+       return of_register_driver(&clock_driver, &of_bus_type);
 }
 
+/* Must be after subsys_initcall() so that busses are probed.  Must
+ * be before device_initcall() because things like the RTC driver
+ * need to see the clock registers.
+ */
+fs_initcall(clock_init);
+
 /* This is gets the master TICK_INT timer going. */
 static unsigned long sparc64_init_timers(void)
 {
@@ -1060,8 +928,6 @@ static void sparc64_start_timers(void)
        __asm__ __volatile__("wrpr      %0, 0x0, %%pstate"
                             : /* no outputs */
                             : "r" (pstate));
-
-       local_irq_enable();
 }
 
 struct freq_table {