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

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

sparc64: Use generic CMOS driver.



Based largely upon a patch by Krzysztof Helt <krzysztof.h1@poczta.fm>

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e8b75c4f
Loading
Loading
Loading
Loading
+2 −8
Original line number Original line Diff line number Diff line
@@ -7,12 +7,8 @@
#include <asm/io.h>
#include <asm/io.h>


#ifndef RTC_PORT
#ifndef RTC_PORT
#ifdef CONFIG_PCI
extern unsigned long cmos_regs;
extern unsigned long ds1287_regs;
#define RTC_PORT(x)	(cmos_regs + (x))
#else
#define ds1287_regs (0UL)
#endif
#define RTC_PORT(x)	(ds1287_regs + (x))
#define RTC_ALWAYS_BCD	0
#define RTC_ALWAYS_BCD	0
#endif
#endif


@@ -29,6 +25,4 @@ outb_p((addr),RTC_PORT(0)); \
outb_p((val),RTC_PORT(1)); \
outb_p((val),RTC_PORT(1)); \
})
})


#define RTC_IRQ 8

#endif /* __ASM_SPARC64_MC146818RTC_H */
#endif /* __ASM_SPARC64_MC146818RTC_H */
+1 −0
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ config SPARC64
	select ARCH_WANT_OPTIONAL_GPIOLIB
	select ARCH_WANT_OPTIONAL_GPIOLIB
	select RTC_CLASS
	select RTC_CLASS
	select RTC_DRV_M48T59
	select RTC_DRV_M48T59
	select RTC_DRV_CMOS


config GENERIC_TIME
config GENERIC_TIME
	bool
	bool
+120 −252
Original line number Original line Diff line number Diff line
@@ -52,10 +52,7 @@
#include "entry.h"
#include "entry.h"


DEFINE_SPINLOCK(rtc_lock);
DEFINE_SPINLOCK(rtc_lock);
#ifdef CONFIG_PCI
unsigned long ds1287_regs = 0UL;
static void __iomem *bq4802_regs;
static void __iomem *bq4802_regs;
#endif


static int set_rtc_mmss(unsigned long);
static int set_rtc_mmss(unsigned long);


@@ -413,23 +410,15 @@ int update_persistent_clock(struct timespec now)
static void __init set_system_time(void)
static void __init set_system_time(void)
{
{
	unsigned int year, mon, day, hour, min, sec;
	unsigned int year, mon, day, hour, min, sec;
#ifdef CONFIG_PCI
	unsigned long dregs = ds1287_regs;
	void __iomem *bregs = bq4802_regs;
	void __iomem *bregs = bq4802_regs;
#else
	unsigned char val = readb(bregs + 0x0e);
	unsigned long dregs = 0UL;
	unsigned int century;
	void __iomem *bregs = 0UL;
#endif


	if (!dregs && !bregs) {
	if (!bregs) {
		prom_printf("Something wrong, clock regs not mapped yet.\n");
		prom_printf("Something wrong, clock regs not mapped yet.\n");
		prom_halt();
		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);
@@ -453,29 +442,6 @@ static void __init set_system_time(void)
	BCD_TO_BIN(century);
	BCD_TO_BIN(century);


	year += (century * 100);
	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;
	}


	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
	xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
	xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
@@ -546,48 +512,79 @@ static int hypervisor_set_time(u32 secs)
	return -EOPNOTSUPP;
	return -EOPNOTSUPP;
}
}


static int __init rtc_model_matches(const char *model)
unsigned long cmos_regs;
EXPORT_SYMBOL(cmos_regs);

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)
{
{
	if (strcmp(model, "m5819") &&
	struct resource *r;
	    strcmp(model, "m5819p") &&

	    strcmp(model, "m5823") &&
	printk(KERN_INFO "%s: RTC regs at 0x%lx\n",
	    strcmp(model, "ds1287") &&
	       op->node->full_name, op->resource[0].start);
	    strcmp(model, "bq4802"))

		return 0;
	/* 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.
	 */


	return 1;
	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 int __devinit rtc_probe(struct of_device *op, const struct of_device_id *match)
static struct of_device_id rtc_match[] = {
	{
	{
	struct device_node *dp = op->node;
		.name = "rtc",
	const char *model = of_get_property(dp, "model", NULL);
		.compatible = "m5819",
	const char *compat = of_get_property(dp, "compatible", NULL);
	},
	unsigned long size, flags;
	{
	void __iomem *regs;
		.name = "rtc",
		.compatible = "isa-m5819p",
	},
	{
		.name = "rtc",
		.compatible = "isa-m5823p",
	},
	{
		.name = "rtc",
		.compatible = "ds1287",
	},
	{},
};


	if (!model)
static struct of_platform_driver rtc_driver = {
		model = compat;
	.match_table	= rtc_match,
	.probe		= rtc_probe,
	.driver		= {
		.name	= "rtc",
	},
};


	if (!model || !rtc_model_matches(model))
static int __devinit bq4802_probe(struct of_device *op, const struct of_device_id *match)
		return -ENODEV;
{
	struct device_node *dp = op->node;
	unsigned long flags;


	size = (op->resource[0].end - op->resource[0].start) + 1;
	bq4802_regs = of_ioremap(&op->resource[0], 0, resource_size(&op->resource[0]), "bq4802");
	regs = of_ioremap(&op->resource[0], 0, size, "clock");
	if (!bq4802_regs)
	if (!regs)
		return -ENOMEM;
		return -ENOMEM;


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


	local_irq_save(flags);
	local_irq_save(flags);


@@ -598,18 +595,18 @@ static int __devinit rtc_probe(struct of_device *op, const struct of_device_id *
	return 0;
	return 0;
}
}


static struct of_device_id rtc_match[] = {
static struct of_device_id bq4802_match[] = {
	{
	{
		.name = "rtc",
		.name = "rtc",
		.compatible = "bq4802",
	},
	},
	{},
};
};


static struct of_platform_driver rtc_driver = {
static struct of_platform_driver bq4802_driver = {
	.match_table	= rtc_match,
	.match_table	= bq4802_match,
	.probe		= rtc_probe,
	.probe		= bq4802_probe,
	.driver		= {
	.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(&rtc_driver, &of_platform_bus_type);
	(void) of_register_driver(&mostek_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;
	return 0;
}
}
@@ -989,25 +987,21 @@ unsigned long long sched_clock(void)
static int set_rtc_mmss(unsigned long nowtime)
static int set_rtc_mmss(unsigned long nowtime)
{
{
	int real_seconds, real_minutes, chip_minutes;
	int real_seconds, real_minutes, chip_minutes;
#ifdef CONFIG_PCI
	unsigned long dregs = ds1287_regs;
	void __iomem *bregs = bq4802_regs;
	void __iomem *bregs = bq4802_regs;
#else
	unsigned long dregs = 0UL;
	void __iomem *bregs = 0UL;
#endif
	unsigned long flags;
	unsigned long flags;
	unsigned char val;
	int retval = 0;


	/* 
	/* 
	 * Not having a register set can lead to trouble.
	 * Not having a register set can lead to trouble.
	 * Also starfire doesn't have a tod clock.
	 * Also starfire doesn't have a tod clock.
	 */
	 */
	if (!dregs && !bregs)
	if (!bregs)
		return -1;
		return -1;


	if (bregs) {
	spin_lock_irqsave(&rtc_lock, flags);
		int retval = 0;

		unsigned char val = readb(bregs + 0x0e);
	val = readb(bregs + 0x0e);


	/* BQ4802 RTC chip. */
	/* BQ4802 RTC chip. */


@@ -1035,51 +1029,10 @@ static int set_rtc_mmss(unsigned long nowtime)


	writeb(val, bregs + 0x0e);
	writeb(val, bregs + 0x0e);


		return retval;
	} 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;
		}

		CMOS_WRITE(save_control, RTC_CONTROL);
		CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
	spin_unlock_irqrestore(&rtc_lock, flags);
	spin_unlock_irqrestore(&rtc_lock, flags);


	return retval;
	return retval;
}
}
}


#define RTC_IS_OPEN		0x01	/* means /dev/rtc is in use	*/
#define RTC_IS_OPEN		0x01	/* means /dev/rtc is in use	*/
static unsigned char mini_rtc_status;	/* bitmapped status byte.	*/
static unsigned char mini_rtc_status;	/* bitmapped status byte.	*/
@@ -1202,7 +1155,6 @@ static int hypervisor_set_rtc_time(struct rtc_time *time)
	return hypervisor_set_time(seconds);
	return hypervisor_set_time(seconds);
}
}


#ifdef CONFIG_PCI
static void bq4802_get_rtc_time(struct rtc_time *time)
static void bq4802_get_rtc_time(struct rtc_time *time)
{
{
	unsigned char val = readb(bq4802_regs + 0x0e);
	unsigned char val = readb(bq4802_regs + 0x0e);
@@ -1275,79 +1227,6 @@ static int bq4802_set_rtc_time(struct rtc_time *time)
	return 0;
	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 {
struct mini_rtc_ops {
	void (*get_rtc_time)(struct rtc_time *);
	void (*get_rtc_time)(struct rtc_time *);
	int (*set_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,
	.set_rtc_time = hypervisor_set_rtc_time,
};
};


#ifdef CONFIG_PCI
static struct mini_rtc_ops bq4802_rtc_ops = {
static struct mini_rtc_ops bq4802_rtc_ops = {
	.get_rtc_time = bq4802_get_rtc_time,
	.get_rtc_time = bq4802_get_rtc_time,
	.set_rtc_time = bq4802_set_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 struct mini_rtc_ops *mini_rtc_ops;


static inline void mini_get_rtc_time(struct rtc_time *time)
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;
		mini_rtc_ops = &hypervisor_rtc_ops;
	else if (this_is_starfire)
	else if (this_is_starfire)
		mini_rtc_ops = &starfire_rtc_ops;
		mini_rtc_ops = &starfire_rtc_ops;
#ifdef CONFIG_PCI
	else if (bq4802_regs)
	else if (bq4802_regs)
		mini_rtc_ops = &bq4802_rtc_ops;
		mini_rtc_ops = &bq4802_rtc_ops;
	else if (ds1287_regs)
		mini_rtc_ops = &cmos_rtc_ops;
#endif /* CONFIG_PCI */
	else
	else
		return -ENODEV;
		return -ENODEV;