Blame view

arch/x86/kernel/rtc.c 6.42 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
fe599f9fb   Thomas Gleixner   x86: isolate the ...
2
   * RTC related functions
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
   */
8383d821e   Jaswinder Singh Rajput   x86: rtc.c cleanup
4
5
  #include <linux/platform_device.h>
  #include <linux/mc146818rtc.h>
1122b134b   Thomas Gleixner   x86: share rtc code
6
  #include <linux/acpi.h>
fe599f9fb   Thomas Gleixner   x86: isolate the ...
7
  #include <linux/bcd.h>
69c60c88e   Paul Gortmaker   x86: Fix files ex...
8
  #include <linux/export.h>
1da2e3d67   Stas Sergeev   provide rtc_cmos ...
9
  #include <linux/pnp.h>
3bcbaf6e0   Sebastian Andrzej Siewior   rtc: cmos: Add OF...
10
  #include <linux/of.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11

cdc7957d1   Ingo Molnar   x86: move native_...
12
  #include <asm/vsyscall.h>
7bd867dfb   Feng Tang   x86: Move get/set...
13
  #include <asm/x86_init.h>
8383d821e   Jaswinder Singh Rajput   x86: rtc.c cleanup
14
  #include <asm/time.h>
35d476996   Mathias Nyman   x86/rtc, mrst: Do...
15
  #include <asm/mrst.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16

1122b134b   Thomas Gleixner   x86: share rtc code
17
  #ifdef CONFIG_X86_32
1122b134b   Thomas Gleixner   x86: share rtc code
18
19
20
21
22
  /*
   * This is a special lock that is owned by the CPU and holds the index
   * register we are working with.  It is required for NMI access to the
   * CMOS/RTC registers.  See include/asm-i386/mc146818rtc.h for details.
   */
8383d821e   Jaswinder Singh Rajput   x86: rtc.c cleanup
23
  volatile unsigned long cmos_lock;
1122b134b   Thomas Gleixner   x86: share rtc code
24
  EXPORT_SYMBOL(cmos_lock);
8383d821e   Jaswinder Singh Rajput   x86: rtc.c cleanup
25
  #endif /* CONFIG_X86_32 */
1122b134b   Thomas Gleixner   x86: share rtc code
26

b62576a2f   Andi Kleen   x86: use year 200...
27
28
  /* For two digit years assume time is always after that */
  #define CMOS_YEARS_OFFS 2000
1122b134b   Thomas Gleixner   x86: share rtc code
29
30
  DEFINE_SPINLOCK(rtc_lock);
  EXPORT_SYMBOL(rtc_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
34
35
36
37
38
39
40
  /*
   * In order to set the CMOS clock precisely, set_rtc_mmss has to be
   * called 500 ms after the second nowtime has started, because when
   * 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!
   */
fe599f9fb   Thomas Gleixner   x86: isolate the ...
41
  int mach_set_rtc_mmss(unsigned long nowtime)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
  	int real_seconds, real_minutes, cmos_minutes;
  	unsigned char save_control, save_freq_select;
47997d756   Matt Fleming   x86/rtc: Don't re...
45
  	unsigned long flags;
8383d821e   Jaswinder Singh Rajput   x86: rtc.c cleanup
46
  	int retval = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47

47997d756   Matt Fleming   x86/rtc: Don't re...
48
  	spin_lock_irqsave(&rtc_lock, flags);
1122b134b   Thomas Gleixner   x86: share rtc code
49
50
  	 /* tell the clock it's being set */
  	save_control = CMOS_READ(RTC_CONTROL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
  	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
1122b134b   Thomas Gleixner   x86: share rtc code
52
53
  	/* stop and reset prescaler */
  	save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
56
57
  	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)
357c6e635   Adrian Bunk   rtc: use bcd2bin/...
58
  		cmos_minutes = bcd2bin(cmos_minutes);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
60
61
62
63
64
65
66
67
  
  	/*
  	 * 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;
1122b134b   Thomas Gleixner   x86: share rtc code
68
  	/* correct for half hour time zone */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
  	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
1122b134b   Thomas Gleixner   x86: share rtc code
70
  		real_minutes += 30;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
74
  	real_minutes %= 60;
  
  	if (abs(real_minutes - cmos_minutes) < 30) {
  		if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
357c6e635   Adrian Bunk   rtc: use bcd2bin/...
75
76
  			real_seconds = bin2bcd(real_seconds);
  			real_minutes = bin2bcd(real_minutes);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
  		}
8383d821e   Jaswinder Singh Rajput   x86: rtc.c cleanup
78
79
  		CMOS_WRITE(real_seconds, RTC_SECONDS);
  		CMOS_WRITE(real_minutes, RTC_MINUTES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
  	} else {
3e5c12409   Stephen Hemminger   set_rtc_mmss: sho...
81
  		printk_once(KERN_NOTICE
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  		       "set_rtc_mmss: can't update from %d to %d
  ",
  		       cmos_minutes, real_minutes);
  		retval = -1;
  	}
  
  	/* 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);
47997d756   Matt Fleming   x86/rtc: Don't re...
97
  	spin_unlock_irqrestore(&rtc_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
99
  	return retval;
  }
fe599f9fb   Thomas Gleixner   x86: isolate the ...
100
  unsigned long mach_get_cmos_time(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
  {
068c9222d   Andi Kleen   x86: add warning ...
102
  	unsigned int status, year, mon, day, hour, min, sec, century = 0;
47997d756   Matt Fleming   x86/rtc: Don't re...
103
104
105
  	unsigned long flags;
  
  	spin_lock_irqsave(&rtc_lock, flags);
1122b134b   Thomas Gleixner   x86: share rtc code
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
  
  	/*
  	 * If UIP is clear, then we have >= 244 microseconds before
  	 * RTC registers will be updated.  Spec sheet says that this
  	 * is the reliable way to read RTC - registers. If UIP is set
  	 * then the register access might be invalid.
  	 */
  	while ((CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
  		cpu_relax();
  
  	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);
45de70791   Andi Kleen   x86: enable ACPI ...
122
  #ifdef CONFIG_ACPI
1122b134b   Thomas Gleixner   x86: share rtc code
123
124
125
126
  	if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
  	    acpi_gbl_FADT.century)
  		century = CMOS_READ(acpi_gbl_FADT.century);
  #endif
068c9222d   Andi Kleen   x86: add warning ...
127
  	status = CMOS_READ(RTC_CONTROL);
45de70791   Andi Kleen   x86: enable ACPI ...
128
  	WARN_ON_ONCE(RTC_ALWAYS_BCD && (status & RTC_DM_BINARY));
068c9222d   Andi Kleen   x86: add warning ...
129

47997d756   Matt Fleming   x86/rtc: Don't re...
130
  	spin_unlock_irqrestore(&rtc_lock, flags);
068c9222d   Andi Kleen   x86: add warning ...
131
  	if (RTC_ALWAYS_BCD || !(status & RTC_DM_BINARY)) {
357c6e635   Adrian Bunk   rtc: use bcd2bin/...
132
133
134
135
136
137
  		sec = bcd2bin(sec);
  		min = bcd2bin(min);
  		hour = bcd2bin(hour);
  		day = bcd2bin(day);
  		mon = bcd2bin(mon);
  		year = bcd2bin(year);
41623b064   Matt Mackall   [PATCH] RTC: Fix ...
138
  	}
1122b134b   Thomas Gleixner   x86: share rtc code
139
  	if (century) {
357c6e635   Adrian Bunk   rtc: use bcd2bin/...
140
  		century = bcd2bin(century);
1122b134b   Thomas Gleixner   x86: share rtc code
141
142
143
  		year += century * 100;
  		printk(KERN_INFO "Extended CMOS year: %d
  ", century * 100);
b62576a2f   Andi Kleen   x86: use year 200...
144
  	} else
1122b134b   Thomas Gleixner   x86: share rtc code
145
  		year += CMOS_YEARS_OFFS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
148
  
  	return mktime(year, mon, day, hour, min, sec);
  }
fe599f9fb   Thomas Gleixner   x86: isolate the ...
149
150
151
152
153
154
  /* Routines for accessing the CMOS RAM/RTC. */
  unsigned char rtc_cmos_read(unsigned char addr)
  {
  	unsigned char val;
  
  	lock_cmos_prefix(addr);
04aaa7ba0   David P. Reed   x86: fix cmos rea...
155
156
  	outb(addr, RTC_PORT(0));
  	val = inb(RTC_PORT(1));
fe599f9fb   Thomas Gleixner   x86: isolate the ...
157
  	lock_cmos_suffix(addr);
8383d821e   Jaswinder Singh Rajput   x86: rtc.c cleanup
158

fe599f9fb   Thomas Gleixner   x86: isolate the ...
159
160
161
162
163
164
165
  	return val;
  }
  EXPORT_SYMBOL(rtc_cmos_read);
  
  void rtc_cmos_write(unsigned char val, unsigned char addr)
  {
  	lock_cmos_prefix(addr);
04aaa7ba0   David P. Reed   x86: fix cmos rea...
166
167
  	outb(addr, RTC_PORT(0));
  	outb(val, RTC_PORT(1));
fe599f9fb   Thomas Gleixner   x86: isolate the ...
168
169
170
  	lock_cmos_suffix(addr);
  }
  EXPORT_SYMBOL(rtc_cmos_write);
7bd867dfb   Feng Tang   x86: Move get/set...
171
  int update_persistent_clock(struct timespec now)
fe599f9fb   Thomas Gleixner   x86: isolate the ...
172
  {
47997d756   Matt Fleming   x86/rtc: Don't re...
173
  	return x86_platform.set_wallclock(now.tv_sec);
fe599f9fb   Thomas Gleixner   x86: isolate the ...
174
175
176
  }
  
  /* not static: needed by APM */
d4f587c67   Martin Schwidefsky   timekeeping: Incr...
177
  void read_persistent_clock(struct timespec *ts)
fe599f9fb   Thomas Gleixner   x86: isolate the ...
178
  {
47997d756   Matt Fleming   x86/rtc: Don't re...
179
  	unsigned long retval;
fe599f9fb   Thomas Gleixner   x86: isolate the ...
180

7bd867dfb   Feng Tang   x86: Move get/set...
181
  	retval = x86_platform.get_wallclock();
fe599f9fb   Thomas Gleixner   x86: isolate the ...
182

d4f587c67   Martin Schwidefsky   timekeeping: Incr...
183
184
  	ts->tv_sec = retval;
  	ts->tv_nsec = 0;
fe599f9fb   Thomas Gleixner   x86: isolate the ...
185
  }
92767af0e   Ingo Molnar   x86: fix sched_cl...
186
  unsigned long long native_read_tsc(void)
cdc7957d1   Ingo Molnar   x86: move native_...
187
  {
92767af0e   Ingo Molnar   x86: fix sched_cl...
188
  	return __native_read_tsc();
cdc7957d1   Ingo Molnar   x86: move native_...
189
  }
92767af0e   Ingo Molnar   x86: fix sched_cl...
190
  EXPORT_SYMBOL(native_read_tsc);
1da2e3d67   Stas Sergeev   provide rtc_cmos ...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
  
  static struct resource rtc_resources[] = {
  	[0] = {
  		.start	= RTC_PORT(0),
  		.end	= RTC_PORT(1),
  		.flags	= IORESOURCE_IO,
  	},
  	[1] = {
  		.start	= RTC_IRQ,
  		.end	= RTC_IRQ,
  		.flags	= IORESOURCE_IRQ,
  	}
  };
  
  static struct platform_device rtc_device = {
  	.name		= "rtc_cmos",
  	.id		= -1,
  	.resource	= rtc_resources,
  	.num_resources	= ARRAY_SIZE(rtc_resources),
  };
  
  static __init int add_rtc_cmos(void)
  {
  #ifdef CONFIG_PNP
758a7f7bb   Bjorn Helgaas   x86: register a p...
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
  	static const char *ids[] __initconst =
  	    { "PNP0b00", "PNP0b01", "PNP0b02", };
  	struct pnp_dev *dev;
  	struct pnp_id *id;
  	int i;
  
  	pnp_for_each_dev(dev) {
  		for (id = dev->id; id; id = id->next) {
  			for (i = 0; i < ARRAY_SIZE(ids); i++) {
  				if (compare_pnp_id(id, ids[i]) != 0)
  					return 0;
  			}
  		}
  	}
  #endif
3bcbaf6e0   Sebastian Andrzej Siewior   rtc: cmos: Add OF...
230
231
  	if (of_have_populated_dt())
  		return 0;
758a7f7bb   Bjorn Helgaas   x86: register a p...
232

35d476996   Mathias Nyman   x86/rtc, mrst: Do...
233
234
235
  	/* Intel MID platforms don't have ioport rtc */
  	if (mrst_identify_cpu())
  		return -ENODEV;
1da2e3d67   Stas Sergeev   provide rtc_cmos ...
236
  	platform_device_register(&rtc_device);
758a7f7bb   Bjorn Helgaas   x86: register a p...
237
238
239
  	dev_info(&rtc_device.dev,
  		 "registered platform RTC device (no PNP device found)
  ");
8383d821e   Jaswinder Singh Rajput   x86: rtc.c cleanup
240

1da2e3d67   Stas Sergeev   provide rtc_cmos ...
241
242
243
  	return 0;
  }
  device_initcall(add_rtc_cmos);