Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ee5caf0e authored by David S. Miller's avatar David S. Miller Committed by David S. Miller
Browse files

[SPARC]: Convert clock drivers to of_driver framework.

parent 36a59bd8
Loading
Loading
Loading
Loading
+40 −69
Original line number Diff line number Diff line
@@ -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;

	cpuunit = bootbus = 0;
	memset(&r, 0, sizeof(r));
	struct device_node *dp = op->node;
	char *model = of_get_property(dp, "model", NULL);

	/* 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();
	}
	if (!model)
		return -ENODEV;

	/* 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);
	
+0 −2
Original line number Diff line number Diff line
@@ -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;
+0 −2
Original line number Diff line number Diff line
@@ -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();
}
+54 −192
Original line number Diff line number Diff line
@@ -770,236 +770,98 @@ 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;
	}
}

static void __init clock_assign_clk_reg(struct linux_prom_registers *clk_reg,
					char *model)
{
	unsigned long addr;
	struct device_node *dp = op->node;
	char *model = of_get_property(dp, "model", NULL);
	unsigned long size, flags;
	void __iomem *regs;

	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)
{
	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;
		return -ENODEV;

	next_sibling:
		dp = dp->sibling;
	}
	size = (op->resource[0].end - op->resource[0].start) + 1;
	regs = of_ioremap(&op->resource[0], 0, size, "clock");
	if (!regs)
		return -ENOMEM;

	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;
	printk(KERN_INFO "%s: Clock regs at %p\n", dp->full_name, regs);

	model = of_get_property(dp, "model", NULL);
	if (!clock_model_matches(model))
		return 0;
	local_irq_save(flags);

	clock_isa_ebus_assign_regs(&idev->resource, model);
	if (mstk48t02_regs != NULL) {
		/* Report a low battery voltage condition. */
		if (has_low_battery())
			prom_printf("NVRAM: Low battery voltage!\n");

	return 1;
		/* Kick start the clock if it is completely stopped. */
		if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
			kick_start_clock();
	}

static int __init clock_probe_isa(void)
{
	struct sparc_isa_bridge *isa_br;

	for_each_isa(isa_br) {
		struct sparc_isa_device *isa_dev;
	set_system_time();
	
		for_each_isadev(isa_dev, isa_br) {
			if (clock_probe_one_isa_dev(isa_dev))
				return 1;
		}
	}
	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)
static struct of_device_id clock_match[] = {
	{
	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)
		.name = "eeprom",
	},
	{
	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;
		}
	}
		.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;
		return 0;
	}

	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 of_register_driver(&clock_driver, &of_bus_type);
}

	set_system_time();
	
	local_irq_restore(flags);
}
/* 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)