forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
rtc: move mc146818 helper functions out-of-line
The mc146818_get_time/mc146818_set_time functions are rather large inline functions in a global header file and are used in several drivers and in x86 specific code. Here we move them into a separate .c file that is compiled whenever any of the users require it. This also lets us remove the linux/acpi.h header inclusion from mc146818rtc.h, which in turn avoids some warnings about duplicate definition of the TRUE/FALSE macros. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
- Loading branch information
1 parent
5ee98ab
commit d6faca4
Showing
5 changed files
with
208 additions
and
191 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
#include <linux/bcd.h> | ||
#include <linux/delay.h> | ||
#include <linux/export.h> | ||
#include <linux/mc146818rtc.h> | ||
|
||
#ifdef CONFIG_ACPI | ||
#include <linux/acpi.h> | ||
#endif | ||
|
||
/* | ||
* Returns true if a clock update is in progress | ||
*/ | ||
static inline unsigned char mc146818_is_updating(void) | ||
{ | ||
unsigned char uip; | ||
unsigned long flags; | ||
|
||
spin_lock_irqsave(&rtc_lock, flags); | ||
uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); | ||
spin_unlock_irqrestore(&rtc_lock, flags); | ||
return uip; | ||
} | ||
|
||
unsigned int mc146818_get_time(struct rtc_time *time) | ||
{ | ||
unsigned char ctrl; | ||
unsigned long flags; | ||
unsigned char century = 0; | ||
|
||
#ifdef CONFIG_MACH_DECSTATION | ||
unsigned int real_year; | ||
#endif | ||
|
||
/* | ||
* read RTC once any update in progress is done. The update | ||
* can take just over 2ms. We wait 20ms. There is no need to | ||
* to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. | ||
* If you need to know *exactly* when a second has started, enable | ||
* periodic update complete interrupts, (via ioctl) and then | ||
* immediately read /dev/rtc which will block until you get the IRQ. | ||
* Once the read clears, read the RTC time (again via ioctl). Easy. | ||
*/ | ||
if (mc146818_is_updating()) | ||
mdelay(20); | ||
|
||
/* | ||
* Only the values that we read from the RTC are set. We leave | ||
* tm_wday, tm_yday and tm_isdst untouched. Even though the | ||
* RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated | ||
* by the RTC when initially set to a non-zero value. | ||
*/ | ||
spin_lock_irqsave(&rtc_lock, flags); | ||
time->tm_sec = CMOS_READ(RTC_SECONDS); | ||
time->tm_min = CMOS_READ(RTC_MINUTES); | ||
time->tm_hour = CMOS_READ(RTC_HOURS); | ||
time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); | ||
time->tm_mon = CMOS_READ(RTC_MONTH); | ||
time->tm_year = CMOS_READ(RTC_YEAR); | ||
#ifdef CONFIG_MACH_DECSTATION | ||
real_year = CMOS_READ(RTC_DEC_YEAR); | ||
#endif | ||
#ifdef CONFIG_ACPI | ||
if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && | ||
acpi_gbl_FADT.century) | ||
century = CMOS_READ(acpi_gbl_FADT.century); | ||
#endif | ||
ctrl = CMOS_READ(RTC_CONTROL); | ||
spin_unlock_irqrestore(&rtc_lock, flags); | ||
|
||
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | ||
{ | ||
time->tm_sec = bcd2bin(time->tm_sec); | ||
time->tm_min = bcd2bin(time->tm_min); | ||
time->tm_hour = bcd2bin(time->tm_hour); | ||
time->tm_mday = bcd2bin(time->tm_mday); | ||
time->tm_mon = bcd2bin(time->tm_mon); | ||
time->tm_year = bcd2bin(time->tm_year); | ||
century = bcd2bin(century); | ||
} | ||
|
||
#ifdef CONFIG_MACH_DECSTATION | ||
time->tm_year += real_year - 72; | ||
#endif | ||
|
||
if (century) | ||
time->tm_year += (century - 19) * 100; | ||
|
||
/* | ||
* Account for differences between how the RTC uses the values | ||
* and how they are defined in a struct rtc_time; | ||
*/ | ||
if (time->tm_year <= 69) | ||
time->tm_year += 100; | ||
|
||
time->tm_mon--; | ||
|
||
return RTC_24H; | ||
} | ||
EXPORT_SYMBOL_GPL(mc146818_get_time); | ||
|
||
/* Set the current date and time in the real time clock. */ | ||
int mc146818_set_time(struct rtc_time *time) | ||
{ | ||
unsigned long flags; | ||
unsigned char mon, day, hrs, min, sec; | ||
unsigned char save_control, save_freq_select; | ||
unsigned int yrs; | ||
#ifdef CONFIG_MACH_DECSTATION | ||
unsigned int real_yrs, leap_yr; | ||
#endif | ||
unsigned char century = 0; | ||
|
||
yrs = time->tm_year; | ||
mon = time->tm_mon + 1; /* tm_mon starts at zero */ | ||
day = time->tm_mday; | ||
hrs = time->tm_hour; | ||
min = time->tm_min; | ||
sec = time->tm_sec; | ||
|
||
if (yrs > 255) /* They are unsigned */ | ||
return -EINVAL; | ||
|
||
spin_lock_irqsave(&rtc_lock, flags); | ||
#ifdef CONFIG_MACH_DECSTATION | ||
real_yrs = yrs; | ||
leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) || | ||
!((yrs + 1900) % 400)); | ||
yrs = 72; | ||
|
||
/* | ||
* We want to keep the year set to 73 until March | ||
* for non-leap years, so that Feb, 29th is handled | ||
* correctly. | ||
*/ | ||
if (!leap_yr && mon < 3) { | ||
real_yrs--; | ||
yrs = 73; | ||
} | ||
#endif | ||
|
||
#ifdef CONFIG_ACPI | ||
if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && | ||
acpi_gbl_FADT.century) { | ||
century = (yrs + 1900) / 100; | ||
yrs %= 100; | ||
} | ||
#endif | ||
|
||
/* These limits and adjustments are independent of | ||
* whether the chip is in binary mode or not. | ||
*/ | ||
if (yrs > 169) { | ||
spin_unlock_irqrestore(&rtc_lock, flags); | ||
return -EINVAL; | ||
} | ||
|
||
if (yrs >= 100) | ||
yrs -= 100; | ||
|
||
if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) | ||
|| RTC_ALWAYS_BCD) { | ||
sec = bin2bcd(sec); | ||
min = bin2bcd(min); | ||
hrs = bin2bcd(hrs); | ||
day = bin2bcd(day); | ||
mon = bin2bcd(mon); | ||
yrs = bin2bcd(yrs); | ||
century = bin2bcd(century); | ||
} | ||
|
||
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); | ||
|
||
#ifdef CONFIG_MACH_DECSTATION | ||
CMOS_WRITE(real_yrs, RTC_DEC_YEAR); | ||
#endif | ||
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); | ||
#ifdef CONFIG_ACPI | ||
if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && | ||
acpi_gbl_FADT.century) | ||
CMOS_WRITE(century, acpi_gbl_FADT.century); | ||
#endif | ||
|
||
CMOS_WRITE(save_control, RTC_CONTROL); | ||
CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); | ||
|
||
spin_unlock_irqrestore(&rtc_lock, flags); | ||
|
||
return 0; | ||
} | ||
EXPORT_SYMBOL_GPL(mc146818_set_time); |
Oops, something went wrong.