forked from Minki/linux
[SPARC]: Convert clock drivers to of_driver framework.
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
36a59bd89c
commit
ee5caf0ee1
@ -42,6 +42,7 @@
|
||||
#include <asm/sun4paddr.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pcic.h>
|
||||
#include <asm/of_device.h>
|
||||
|
||||
extern unsigned long wall_jiffies;
|
||||
|
||||
@ -273,83 +274,31 @@ static __inline__ void sun4_clock_probe(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Probe for the mostek real time clock chip. */
|
||||
static __inline__ void clock_probe(void)
|
||||
static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
|
||||
{
|
||||
struct linux_prom_registers clk_reg[2];
|
||||
char model[128];
|
||||
register int node, cpuunit, bootbus;
|
||||
struct resource r;
|
||||
struct device_node *dp = op->node;
|
||||
char *model = of_get_property(dp, "model", NULL);
|
||||
|
||||
cpuunit = bootbus = 0;
|
||||
memset(&r, 0, sizeof(r));
|
||||
if (!model)
|
||||
return -ENODEV;
|
||||
|
||||
/* Determine the correct starting PROM node for the probe. */
|
||||
node = prom_getchild(prom_root_node);
|
||||
switch (sparc_cpu_model) {
|
||||
case sun4c:
|
||||
break;
|
||||
case sun4m:
|
||||
node = prom_getchild(prom_searchsiblings(node, "obio"));
|
||||
break;
|
||||
case sun4d:
|
||||
node = prom_getchild(bootbus = prom_searchsiblings(prom_getchild(cpuunit = prom_searchsiblings(node, "cpu-unit")), "bootbus"));
|
||||
break;
|
||||
default:
|
||||
prom_printf("CLOCK: Unsupported architecture!\n");
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
/* Find the PROM node describing the real time clock. */
|
||||
sp_clock_typ = MSTK_INVALID;
|
||||
node = prom_searchsiblings(node,"eeprom");
|
||||
if (!node) {
|
||||
prom_printf("CLOCK: No clock found!\n");
|
||||
prom_halt();
|
||||
}
|
||||
|
||||
/* Get the model name and setup everything up. */
|
||||
model[0] = '\0';
|
||||
prom_getstring(node, "model", model, sizeof(model));
|
||||
if (strcmp(model, "mk48t02") == 0) {
|
||||
if (!strcmp(model, "mk48t02")) {
|
||||
sp_clock_typ = MSTK48T02;
|
||||
if (prom_getproperty(node, "reg", (char *) clk_reg, sizeof(clk_reg)) == -1) {
|
||||
prom_printf("clock_probe: FAILED!\n");
|
||||
prom_halt();
|
||||
}
|
||||
if (sparc_cpu_model == sun4d)
|
||||
prom_apply_generic_ranges (bootbus, cpuunit, clk_reg, 1);
|
||||
else
|
||||
prom_apply_obio_ranges(clk_reg, 1);
|
||||
|
||||
/* Map the clock register io area read-only */
|
||||
r.flags = clk_reg[0].which_io;
|
||||
r.start = clk_reg[0].phys_addr;
|
||||
mstk48t02_regs = sbus_ioremap(&r, 0,
|
||||
sizeof(struct mostek48t02), "mk48t02");
|
||||
mstk48t02_regs = of_ioremap(&op->resource[0], 0,
|
||||
sizeof(struct mostek48t02),
|
||||
"mk48t02");
|
||||
mstk48t08_regs = NULL; /* To catch weirdness */
|
||||
} else if (strcmp(model, "mk48t08") == 0) {
|
||||
} else if (!strcmp(model, "mk48t08")) {
|
||||
sp_clock_typ = MSTK48T08;
|
||||
if(prom_getproperty(node, "reg", (char *) clk_reg,
|
||||
sizeof(clk_reg)) == -1) {
|
||||
prom_printf("clock_probe: FAILED!\n");
|
||||
prom_halt();
|
||||
}
|
||||
if (sparc_cpu_model == sun4d)
|
||||
prom_apply_generic_ranges (bootbus, cpuunit, clk_reg, 1);
|
||||
else
|
||||
prom_apply_obio_ranges(clk_reg, 1);
|
||||
/* Map the clock register io area read-only */
|
||||
/* XXX r/o attribute is somewhere in r.flags */
|
||||
r.flags = clk_reg[0].which_io;
|
||||
r.start = clk_reg[0].phys_addr;
|
||||
mstk48t08_regs = sbus_ioremap(&r, 0,
|
||||
sizeof(struct mostek48t08), "mk48t08");
|
||||
mstk48t08_regs = of_ioremap(&op->resource[0], 0,
|
||||
sizeof(struct mostek48t08),
|
||||
"mk48t08");
|
||||
|
||||
mstk48t02_regs = &mstk48t08_regs->regs;
|
||||
} else {
|
||||
prom_printf("CLOCK: Unknown model name '%s'\n",model);
|
||||
prom_halt();
|
||||
}
|
||||
} else
|
||||
return -ENODEV;
|
||||
|
||||
/* Report a low battery voltage condition. */
|
||||
if (has_low_battery())
|
||||
@ -358,6 +307,28 @@ static __inline__ void clock_probe(void)
|
||||
/* Kick start the clock if it is completely stopped. */
|
||||
if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
|
||||
kick_start_clock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id clock_match[] = {
|
||||
{
|
||||
.name = "eeprom",
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
static struct of_platform_driver clock_driver = {
|
||||
.name = "clock",
|
||||
.match_table = clock_match,
|
||||
.probe = clock_probe,
|
||||
};
|
||||
|
||||
|
||||
/* Probe for the mostek real time clock chip. */
|
||||
static void clock_init(void)
|
||||
{
|
||||
of_register_driver(&clock_driver, &of_bus_type);
|
||||
}
|
||||
|
||||
void __init sbus_time_init(void)
|
||||
@ -376,7 +347,7 @@ void __init sbus_time_init(void)
|
||||
if (ARCH_SUN4)
|
||||
sun4_clock_probe();
|
||||
else
|
||||
clock_probe();
|
||||
clock_init();
|
||||
|
||||
sparc_init_timers(timer_interrupt);
|
||||
|
||||
|
@ -307,7 +307,6 @@ static void __init pci_scan_each_controller_bus(void)
|
||||
p->scan_bus(p);
|
||||
}
|
||||
|
||||
extern void clock_probe(void);
|
||||
extern void power_init(void);
|
||||
|
||||
static int __init pcibios_init(void)
|
||||
@ -320,7 +319,6 @@ static int __init pcibios_init(void)
|
||||
|
||||
isa_init();
|
||||
ebus_init();
|
||||
clock_probe();
|
||||
power_init();
|
||||
|
||||
return 0;
|
||||
|
@ -1267,8 +1267,6 @@ int __init sbus_arch_preinit(void)
|
||||
void __init sbus_arch_postinit(void)
|
||||
{
|
||||
extern void firetruck_init(void);
|
||||
extern void clock_probe(void);
|
||||
|
||||
firetruck_init();
|
||||
clock_probe();
|
||||
}
|
||||
|
@ -770,219 +770,37 @@ static int __init clock_model_matches(char *model)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void __init __clock_assign_common(void __iomem *addr, char *model)
|
||||
static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
struct device_node *dp = op->node;
|
||||
char *model = of_get_property(dp, "model", NULL);
|
||||
unsigned long size, flags;
|
||||
void __iomem *regs;
|
||||
|
||||
static void __init clock_assign_clk_reg(struct linux_prom_registers *clk_reg,
|
||||
char *model)
|
||||
{
|
||||
unsigned long addr;
|
||||
if (!model || !clock_model_matches(model))
|
||||
return -ENODEV;
|
||||
|
||||
addr = ((unsigned long) clk_reg[0].phys_addr |
|
||||
(((unsigned long) clk_reg[0].which_io) << 32UL));
|
||||
size = (op->resource[0].end - op->resource[0].start) + 1;
|
||||
regs = of_ioremap(&op->resource[0], 0, size, "clock");
|
||||
if (!regs)
|
||||
return -ENOMEM;
|
||||
|
||||
__clock_assign_common((void __iomem *) addr, model);
|
||||
}
|
||||
|
||||
static int __init clock_probe_central(void)
|
||||
{
|
||||
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);
|
||||
|
||||
clock_assign_clk_reg(clk_reg, model);
|
||||
return 1;
|
||||
|
||||
next_sibling:
|
||||
dp = dp->sibling;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#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 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;
|
||||
|
||||
clock_isa_ebus_assign_regs(&edev->resource[0], model);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int __init clock_probe_ebus(void)
|
||||
{
|
||||
struct linux_ebus *ebus;
|
||||
|
||||
for_each_ebus(ebus) {
|
||||
struct linux_ebus_device *edev;
|
||||
|
||||
for_each_ebusdev(edev, ebus) {
|
||||
if (clock_probe_one_ebus_dev(edev))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void __init clock_probe(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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
printk(KERN_INFO "%s: Clock regs at %p\n", dp->full_name, regs);
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
@ -999,8 +817,52 @@ void __init clock_probe(void)
|
||||
set_system_time();
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id clock_match[] = {
|
||||
{
|
||||
.name = "eeprom",
|
||||
},
|
||||
{
|
||||
.name = "rtc",
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
static struct of_platform_driver clock_driver = {
|
||||
.name = "clock",
|
||||
.match_table = clock_match,
|
||||
.probe = clock_probe,
|
||||
};
|
||||
|
||||
static int __init clock_init(void)
|
||||
{
|
||||
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 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 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user