diff options
Diffstat (limited to 'arch/x86/kernel/rtc.c')
| -rw-r--r-- | arch/x86/kernel/rtc.c | 121 | 
1 files changed, 42 insertions, 79 deletions
diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c index 1cfbbfc3ae2..ca9622a25e9 100644 --- a/arch/x86/kernel/rtc.c +++ b/arch/x86/kernel/rtc.c @@ -5,11 +5,15 @@  #include <linux/mc146818rtc.h>  #include <linux/acpi.h>  #include <linux/bcd.h> +#include <linux/export.h>  #include <linux/pnp.h> +#include <linux/of.h>  #include <asm/vsyscall.h>  #include <asm/x86_init.h>  #include <asm/time.h> +#include <asm/intel-mid.h> +#include <asm/rtc.h>  #ifdef CONFIG_X86_32  /* @@ -33,71 +37,34 @@ EXPORT_SYMBOL(rtc_lock);   * nowtime is written into the registers of the CMOS clock, it will   * jump to the next second precisely 500 ms later. Check the Motorola   * MC146818A or Dallas DS12887 data sheet for details. - * - * BUG: This routine does not handle hour overflow properly; it just - *      sets the minutes. Usually you'll only notice that after reboot!   */ -int mach_set_rtc_mmss(unsigned long nowtime) +int mach_set_rtc_mmss(const struct timespec *now)  { -	int real_seconds, real_minutes, cmos_minutes; -	unsigned char save_control, save_freq_select; +	unsigned long nowtime = now->tv_sec; +	struct rtc_time tm;  	int retval = 0; -	 /* tell the clock it's being set */ -	save_control = CMOS_READ(RTC_CONTROL); -	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); - -	/* stop and reset prescaler */ -	save_freq_select = CMOS_READ(RTC_FREQ_SELECT); -	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); - -	cmos_minutes = CMOS_READ(RTC_MINUTES); -	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) -		cmos_minutes = bcd2bin(cmos_minutes); - -	/* -	 * since we're only adjusting minutes and seconds, -	 * don't interfere with hour overflow. This avoids -	 * messing with unknown time zones but requires your -	 * RTC not to be off by more than 15 minutes -	 */ -	real_seconds = nowtime % 60; -	real_minutes = nowtime / 60; -	/* correct for half hour time zone */ -	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) -		real_minutes += 30; -	real_minutes %= 60; - -	if (abs(real_minutes - cmos_minutes) < 30) { -		if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { -			real_seconds = bin2bcd(real_seconds); -			real_minutes = bin2bcd(real_minutes); -		} -		CMOS_WRITE(real_seconds, RTC_SECONDS); -		CMOS_WRITE(real_minutes, RTC_MINUTES); +	rtc_time_to_tm(nowtime, &tm); +	if (!rtc_valid_tm(&tm)) { +		retval = set_rtc_time(&tm); +		if (retval) +			printk(KERN_ERR "%s: RTC write failed with error %d\n", +			       __FUNCTION__, retval);  	} else { -		printk(KERN_WARNING -		       "set_rtc_mmss: can't update from %d to %d\n", -		       cmos_minutes, real_minutes); -		retval = -1; +		printk(KERN_ERR +		       "%s: Invalid RTC value: write of %lx to RTC failed\n", +			__FUNCTION__, nowtime); +		retval = -EINVAL;  	} - -	/* The following flags have to be released exactly in this order, -	 * otherwise the DS12887 (popular MC146818A clone with integrated -	 * battery and quartz) will not reset the oscillator and will not -	 * update precisely 500 ms later. You won't find this mentioned in -	 * the Dallas Semiconductor data sheets, but who believes data -	 * sheets anyway ...                           -- Markus Kuhn -	 */ -	CMOS_WRITE(save_control, RTC_CONTROL); -	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); -  	return retval;  } -unsigned long mach_get_cmos_time(void) +void mach_get_cmos_time(struct timespec *now)  {  	unsigned int status, year, mon, day, hour, min, sec, century = 0; +	unsigned long flags; + +	spin_lock_irqsave(&rtc_lock, flags);  	/*  	 * If UIP is clear, then we have >= 244 microseconds before @@ -124,6 +91,8 @@ unsigned long mach_get_cmos_time(void)  	status = CMOS_READ(RTC_CONTROL);  	WARN_ON_ONCE(RTC_ALWAYS_BCD && (status & RTC_DM_BINARY)); +	spin_unlock_irqrestore(&rtc_lock, flags); +  	if (RTC_ALWAYS_BCD || !(status & RTC_DM_BINARY)) {  		sec = bcd2bin(sec);  		min = bcd2bin(min); @@ -136,11 +105,11 @@ unsigned long mach_get_cmos_time(void)  	if (century) {  		century = bcd2bin(century);  		year += century * 100; -		printk(KERN_INFO "Extended CMOS year: %d\n", century * 100);  	} else  		year += CMOS_YEARS_OFFS; -	return mktime(year, mon, day, hour, min, sec); +	now->tv_sec = mktime(year, mon, day, hour, min, sec); +	now->tv_nsec = 0;  }  /* Routines for accessing the CMOS RAM/RTC. */ @@ -168,34 +137,14 @@ EXPORT_SYMBOL(rtc_cmos_write);  int update_persistent_clock(struct timespec now)  { -	unsigned long flags; -	int retval; - -	spin_lock_irqsave(&rtc_lock, flags); -	retval = x86_platform.set_wallclock(now.tv_sec); -	spin_unlock_irqrestore(&rtc_lock, flags); - -	return retval; +	return x86_platform.set_wallclock(&now);  }  /* not static: needed by APM */  void read_persistent_clock(struct timespec *ts)  { -	unsigned long retval, flags; - -	spin_lock_irqsave(&rtc_lock, flags); -	retval = x86_platform.get_wallclock(); -	spin_unlock_irqrestore(&rtc_lock, flags); - -	ts->tv_sec = retval; -	ts->tv_nsec = 0; -} - -unsigned long long native_read_tsc(void) -{ -	return __native_read_tsc(); +	x86_platform.get_wallclock(ts);  } -EXPORT_SYMBOL(native_read_tsc);  static struct resource rtc_resources[] = { @@ -221,7 +170,7 @@ static struct platform_device rtc_device = {  static __init int add_rtc_cmos(void)  {  #ifdef CONFIG_PNP -	static const char *ids[] __initconst = +	static const char * const  const ids[] __initconst =  	    { "PNP0b00", "PNP0b01", "PNP0b02", };  	struct pnp_dev *dev;  	struct pnp_id *id; @@ -236,6 +185,20 @@ static __init int add_rtc_cmos(void)  		}  	}  #endif +	if (of_have_populated_dt()) +		return 0; + +	/* Intel MID platforms don't have ioport rtc */ +	if (intel_mid_identify_cpu()) +		return -ENODEV; + +#ifdef CONFIG_ACPI +	if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_CMOS_RTC) { +		/* This warning can likely go away again in a year or two. */ +		pr_info("ACPI: not registering RTC platform device\n"); +		return -ENODEV; +	} +#endif  	platform_device_register(&rtc_device);  	dev_info(&rtc_device.dev,  | 
