rtc.h 6.0 KB
Newer Older
L
Linus Torvalds 已提交
1
/* 
2
 * include/asm-generic/rtc.h
L
Linus Torvalds 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * Author: Tom Rini <trini@mvista.com>
 *
 * Based on:
 * drivers/char/rtc.c
 *
 * Please read the COPYING file for all license details.
 */

#ifndef __ASM_RTC_H__
#define __ASM_RTC_H__

#include <linux/mc146818rtc.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
I
Ingo Molnar 已提交
18
#include <linux/delay.h>
S
Sylvain Chouleur 已提交
19 20 21
#ifdef CONFIG_ACPI
#include <linux/acpi.h>
#endif
L
Linus Torvalds 已提交
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39

#define RTC_PIE 0x40		/* periodic interrupt enable */
#define RTC_AIE 0x20		/* alarm interrupt enable */
#define RTC_UIE 0x10		/* update-finished interrupt enable */

/* some dummy definitions */
#define RTC_BATT_BAD 0x100	/* battery bad */
#define RTC_SQWE 0x08		/* enable square-wave output */
#define RTC_DM_BINARY 0x04	/* all time/date values are BCD if clear */
#define RTC_24H 0x02		/* 24 hour mode - else hours bit 7 means pm */
#define RTC_DST_EN 0x01	        /* auto switch DST - works f. USA only */

/*
 * Returns true if a clock update is in progress
 */
static inline unsigned char rtc_is_updating(void)
{
	unsigned char uip;
40
	unsigned long flags;
L
Linus Torvalds 已提交
41

42
	spin_lock_irqsave(&rtc_lock, flags);
L
Linus Torvalds 已提交
43
	uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
44
	spin_unlock_irqrestore(&rtc_lock, flags);
L
Linus Torvalds 已提交
45 46 47
	return uip;
}

I
Ivan Kokshaysky 已提交
48
static inline unsigned int __get_rtc_time(struct rtc_time *time)
L
Linus Torvalds 已提交
49 50
{
	unsigned char ctrl;
51
	unsigned long flags;
S
Sylvain Chouleur 已提交
52
	unsigned char century = 0;
53

L
Linus Torvalds 已提交
54 55 56 57 58 59
#ifdef CONFIG_MACH_DECSTATION
	unsigned int real_year;
#endif

	/*
	 * read RTC once any update in progress is done. The update
I
Ingo Molnar 已提交
60
	 * can take just over 2ms. We wait 20ms. There is no need to
L
Linus Torvalds 已提交
61 62 63 64 65 66
	 * 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.
	 */
I
Ingo Molnar 已提交
67 68
	if (rtc_is_updating())
		mdelay(20);
L
Linus Torvalds 已提交
69 70 71 72 73 74 75

	/*
	 * 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.
	 */
76
	spin_lock_irqsave(&rtc_lock, flags);
L
Linus Torvalds 已提交
77 78 79 80 81 82 83 84
	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);
S
Sylvain Chouleur 已提交
85 86 87 88 89
#endif
#ifdef CONFIG_ACPI
	if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
	    acpi_gbl_FADT.century)
		century = CMOS_READ(acpi_gbl_FADT.century);
L
Linus Torvalds 已提交
90 91
#endif
	ctrl = CMOS_READ(RTC_CONTROL);
92
	spin_unlock_irqrestore(&rtc_lock, flags);
L
Linus Torvalds 已提交
93 94 95

	if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
	{
A
Adrian Bunk 已提交
96 97 98 99 100 101
		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);
S
Sylvain Chouleur 已提交
102
		century = bcd2bin(century);
L
Linus Torvalds 已提交
103 104 105 106 107 108
	}

#ifdef CONFIG_MACH_DECSTATION
	time->tm_year += real_year - 72;
#endif

S
Sylvain Chouleur 已提交
109 110 111
	if (century)
		time->tm_year += (century - 19) * 100;

L
Linus Torvalds 已提交
112 113 114 115 116 117 118 119 120 121 122 123
	/*
	 * 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;
}

I
Ivan Kokshaysky 已提交
124 125 126 127
#ifndef get_rtc_time
#define get_rtc_time	__get_rtc_time
#endif

L
Linus Torvalds 已提交
128
/* Set the current date and time in the real time clock. */
I
Ivan Kokshaysky 已提交
129
static inline int __set_rtc_time(struct rtc_time *time)
L
Linus Torvalds 已提交
130
{
131
	unsigned long flags;
L
Linus Torvalds 已提交
132 133 134 135 136 137
	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
S
Sylvain Chouleur 已提交
138
	unsigned char century = 0;
L
Linus Torvalds 已提交
139 140 141 142 143 144 145 146 147 148 149

	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;

150
	spin_lock_irqsave(&rtc_lock, flags);
L
Linus Torvalds 已提交
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
#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
S
Sylvain Chouleur 已提交
167 168 169 170 171 172 173 174 175

#ifdef CONFIG_ACPI
	if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
	    acpi_gbl_FADT.century) {
		century = (yrs + 1900) / 100;
		yrs %= 100;
	}
#endif

L
Linus Torvalds 已提交
176 177 178 179
	/* These limits and adjustments are independent of
	 * whether the chip is in binary mode or not.
	 */
	if (yrs > 169) {
180
		spin_unlock_irqrestore(&rtc_lock, flags);
L
Linus Torvalds 已提交
181 182 183 184 185 186 187 188
		return -EINVAL;
	}

	if (yrs >= 100)
		yrs -= 100;

	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
	    || RTC_ALWAYS_BCD) {
A
Adrian Bunk 已提交
189 190 191 192 193 194
		sec = bin2bcd(sec);
		min = bin2bcd(min);
		hrs = bin2bcd(hrs);
		day = bin2bcd(day);
		mon = bin2bcd(mon);
		yrs = bin2bcd(yrs);
S
Sylvain Chouleur 已提交
195
		century = bin2bcd(century);
L
Linus Torvalds 已提交
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
	}

	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);
S
Sylvain Chouleur 已提交
212 213 214 215 216
#ifdef CONFIG_ACPI
	if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
	    acpi_gbl_FADT.century)
		CMOS_WRITE(century, acpi_gbl_FADT.century);
#endif
L
Linus Torvalds 已提交
217 218 219 220

	CMOS_WRITE(save_control, RTC_CONTROL);
	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);

221
	spin_unlock_irqrestore(&rtc_lock, flags);
L
Linus Torvalds 已提交
222 223 224 225

	return 0;
}

I
Ivan Kokshaysky 已提交
226 227 228 229
#ifndef set_rtc_time
#define set_rtc_time	__set_rtc_time
#endif

L
Linus Torvalds 已提交
230 231 232 233
static inline unsigned int get_rtc_ss(void)
{
	struct rtc_time h;

234
	get_rtc_time(&h);
L
Linus Torvalds 已提交
235 236 237 238 239 240 241 242 243 244 245 246 247
	return h.tm_sec;
}

static inline int get_rtc_pll(struct rtc_pll_info *pll)
{
	return -EINVAL;
}
static inline int set_rtc_pll(struct rtc_pll_info *pll)
{
	return -EINVAL;
}

#endif /* __ASM_RTC_H__ */