Commit 357c6e63590895dc87cc9300f5a1c27544ea69e8
Committed by
Linus Torvalds
1 parent
fe20ba70ab
Exists in
master
and in
7 other branches
rtc: use bcd2bin/bin2bcd
Change various rtc related code to use the new bcd2bin/bin2bcd functions instead of the obsolete BCD_TO_BIN/BIN_TO_BCD/BCD2BIN/BIN2BCD macros. Signed-off-by: Adrian Bunk <bunk@kernel.org> Acked-by: Alessandro Zummo <a.zummo@towertech.it> Cc: David Brownell <david-b@pacbell.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 6 changed files with 83 additions and 83 deletions Inline Diff
arch/x86/kernel/rtc.c
1 | /* | 1 | /* |
2 | * RTC related functions | 2 | * RTC related functions |
3 | */ | 3 | */ |
4 | #include <linux/acpi.h> | 4 | #include <linux/acpi.h> |
5 | #include <linux/bcd.h> | 5 | #include <linux/bcd.h> |
6 | #include <linux/mc146818rtc.h> | 6 | #include <linux/mc146818rtc.h> |
7 | #include <linux/platform_device.h> | 7 | #include <linux/platform_device.h> |
8 | #include <linux/pnp.h> | 8 | #include <linux/pnp.h> |
9 | 9 | ||
10 | #include <asm/time.h> | 10 | #include <asm/time.h> |
11 | #include <asm/vsyscall.h> | 11 | #include <asm/vsyscall.h> |
12 | 12 | ||
13 | #ifdef CONFIG_X86_32 | 13 | #ifdef CONFIG_X86_32 |
14 | /* | 14 | /* |
15 | * This is a special lock that is owned by the CPU and holds the index | 15 | * This is a special lock that is owned by the CPU and holds the index |
16 | * register we are working with. It is required for NMI access to the | 16 | * register we are working with. It is required for NMI access to the |
17 | * CMOS/RTC registers. See include/asm-i386/mc146818rtc.h for details. | 17 | * CMOS/RTC registers. See include/asm-i386/mc146818rtc.h for details. |
18 | */ | 18 | */ |
19 | volatile unsigned long cmos_lock = 0; | 19 | volatile unsigned long cmos_lock = 0; |
20 | EXPORT_SYMBOL(cmos_lock); | 20 | EXPORT_SYMBOL(cmos_lock); |
21 | #endif | 21 | #endif |
22 | 22 | ||
23 | /* For two digit years assume time is always after that */ | 23 | /* For two digit years assume time is always after that */ |
24 | #define CMOS_YEARS_OFFS 2000 | 24 | #define CMOS_YEARS_OFFS 2000 |
25 | 25 | ||
26 | DEFINE_SPINLOCK(rtc_lock); | 26 | DEFINE_SPINLOCK(rtc_lock); |
27 | EXPORT_SYMBOL(rtc_lock); | 27 | EXPORT_SYMBOL(rtc_lock); |
28 | 28 | ||
29 | /* | 29 | /* |
30 | * In order to set the CMOS clock precisely, set_rtc_mmss has to be | 30 | * In order to set the CMOS clock precisely, set_rtc_mmss has to be |
31 | * called 500 ms after the second nowtime has started, because when | 31 | * called 500 ms after the second nowtime has started, because when |
32 | * nowtime is written into the registers of the CMOS clock, it will | 32 | * nowtime is written into the registers of the CMOS clock, it will |
33 | * jump to the next second precisely 500 ms later. Check the Motorola | 33 | * jump to the next second precisely 500 ms later. Check the Motorola |
34 | * MC146818A or Dallas DS12887 data sheet for details. | 34 | * MC146818A or Dallas DS12887 data sheet for details. |
35 | * | 35 | * |
36 | * BUG: This routine does not handle hour overflow properly; it just | 36 | * BUG: This routine does not handle hour overflow properly; it just |
37 | * sets the minutes. Usually you'll only notice that after reboot! | 37 | * sets the minutes. Usually you'll only notice that after reboot! |
38 | */ | 38 | */ |
39 | int mach_set_rtc_mmss(unsigned long nowtime) | 39 | int mach_set_rtc_mmss(unsigned long nowtime) |
40 | { | 40 | { |
41 | int retval = 0; | 41 | int retval = 0; |
42 | int real_seconds, real_minutes, cmos_minutes; | 42 | int real_seconds, real_minutes, cmos_minutes; |
43 | unsigned char save_control, save_freq_select; | 43 | unsigned char save_control, save_freq_select; |
44 | 44 | ||
45 | /* tell the clock it's being set */ | 45 | /* tell the clock it's being set */ |
46 | save_control = CMOS_READ(RTC_CONTROL); | 46 | save_control = CMOS_READ(RTC_CONTROL); |
47 | CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); | 47 | CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); |
48 | 48 | ||
49 | /* stop and reset prescaler */ | 49 | /* stop and reset prescaler */ |
50 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); | 50 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); |
51 | CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); | 51 | CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); |
52 | 52 | ||
53 | cmos_minutes = CMOS_READ(RTC_MINUTES); | 53 | cmos_minutes = CMOS_READ(RTC_MINUTES); |
54 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | 54 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) |
55 | BCD_TO_BIN(cmos_minutes); | 55 | cmos_minutes = bcd2bin(cmos_minutes); |
56 | 56 | ||
57 | /* | 57 | /* |
58 | * since we're only adjusting minutes and seconds, | 58 | * since we're only adjusting minutes and seconds, |
59 | * don't interfere with hour overflow. This avoids | 59 | * don't interfere with hour overflow. This avoids |
60 | * messing with unknown time zones but requires your | 60 | * messing with unknown time zones but requires your |
61 | * RTC not to be off by more than 15 minutes | 61 | * RTC not to be off by more than 15 minutes |
62 | */ | 62 | */ |
63 | real_seconds = nowtime % 60; | 63 | real_seconds = nowtime % 60; |
64 | real_minutes = nowtime / 60; | 64 | real_minutes = nowtime / 60; |
65 | /* correct for half hour time zone */ | 65 | /* correct for half hour time zone */ |
66 | if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) | 66 | if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) |
67 | real_minutes += 30; | 67 | real_minutes += 30; |
68 | real_minutes %= 60; | 68 | real_minutes %= 60; |
69 | 69 | ||
70 | if (abs(real_minutes - cmos_minutes) < 30) { | 70 | if (abs(real_minutes - cmos_minutes) < 30) { |
71 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | 71 | if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { |
72 | BIN_TO_BCD(real_seconds); | 72 | real_seconds = bin2bcd(real_seconds); |
73 | BIN_TO_BCD(real_minutes); | 73 | real_minutes = bin2bcd(real_minutes); |
74 | } | 74 | } |
75 | CMOS_WRITE(real_seconds,RTC_SECONDS); | 75 | CMOS_WRITE(real_seconds,RTC_SECONDS); |
76 | CMOS_WRITE(real_minutes,RTC_MINUTES); | 76 | CMOS_WRITE(real_minutes,RTC_MINUTES); |
77 | } else { | 77 | } else { |
78 | printk(KERN_WARNING | 78 | printk(KERN_WARNING |
79 | "set_rtc_mmss: can't update from %d to %d\n", | 79 | "set_rtc_mmss: can't update from %d to %d\n", |
80 | cmos_minutes, real_minutes); | 80 | cmos_minutes, real_minutes); |
81 | retval = -1; | 81 | retval = -1; |
82 | } | 82 | } |
83 | 83 | ||
84 | /* The following flags have to be released exactly in this order, | 84 | /* The following flags have to be released exactly in this order, |
85 | * otherwise the DS12887 (popular MC146818A clone with integrated | 85 | * otherwise the DS12887 (popular MC146818A clone with integrated |
86 | * battery and quartz) will not reset the oscillator and will not | 86 | * battery and quartz) will not reset the oscillator and will not |
87 | * update precisely 500 ms later. You won't find this mentioned in | 87 | * update precisely 500 ms later. You won't find this mentioned in |
88 | * the Dallas Semiconductor data sheets, but who believes data | 88 | * the Dallas Semiconductor data sheets, but who believes data |
89 | * sheets anyway ... -- Markus Kuhn | 89 | * sheets anyway ... -- Markus Kuhn |
90 | */ | 90 | */ |
91 | CMOS_WRITE(save_control, RTC_CONTROL); | 91 | CMOS_WRITE(save_control, RTC_CONTROL); |
92 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); | 92 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); |
93 | 93 | ||
94 | return retval; | 94 | return retval; |
95 | } | 95 | } |
96 | 96 | ||
97 | unsigned long mach_get_cmos_time(void) | 97 | unsigned long mach_get_cmos_time(void) |
98 | { | 98 | { |
99 | unsigned int status, year, mon, day, hour, min, sec, century = 0; | 99 | unsigned int status, year, mon, day, hour, min, sec, century = 0; |
100 | 100 | ||
101 | /* | 101 | /* |
102 | * If UIP is clear, then we have >= 244 microseconds before | 102 | * If UIP is clear, then we have >= 244 microseconds before |
103 | * RTC registers will be updated. Spec sheet says that this | 103 | * RTC registers will be updated. Spec sheet says that this |
104 | * is the reliable way to read RTC - registers. If UIP is set | 104 | * is the reliable way to read RTC - registers. If UIP is set |
105 | * then the register access might be invalid. | 105 | * then the register access might be invalid. |
106 | */ | 106 | */ |
107 | while ((CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) | 107 | while ((CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) |
108 | cpu_relax(); | 108 | cpu_relax(); |
109 | 109 | ||
110 | sec = CMOS_READ(RTC_SECONDS); | 110 | sec = CMOS_READ(RTC_SECONDS); |
111 | min = CMOS_READ(RTC_MINUTES); | 111 | min = CMOS_READ(RTC_MINUTES); |
112 | hour = CMOS_READ(RTC_HOURS); | 112 | hour = CMOS_READ(RTC_HOURS); |
113 | day = CMOS_READ(RTC_DAY_OF_MONTH); | 113 | day = CMOS_READ(RTC_DAY_OF_MONTH); |
114 | mon = CMOS_READ(RTC_MONTH); | 114 | mon = CMOS_READ(RTC_MONTH); |
115 | year = CMOS_READ(RTC_YEAR); | 115 | year = CMOS_READ(RTC_YEAR); |
116 | 116 | ||
117 | #ifdef CONFIG_ACPI | 117 | #ifdef CONFIG_ACPI |
118 | if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && | 118 | if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && |
119 | acpi_gbl_FADT.century) | 119 | acpi_gbl_FADT.century) |
120 | century = CMOS_READ(acpi_gbl_FADT.century); | 120 | century = CMOS_READ(acpi_gbl_FADT.century); |
121 | #endif | 121 | #endif |
122 | 122 | ||
123 | status = CMOS_READ(RTC_CONTROL); | 123 | status = CMOS_READ(RTC_CONTROL); |
124 | WARN_ON_ONCE(RTC_ALWAYS_BCD && (status & RTC_DM_BINARY)); | 124 | WARN_ON_ONCE(RTC_ALWAYS_BCD && (status & RTC_DM_BINARY)); |
125 | 125 | ||
126 | if (RTC_ALWAYS_BCD || !(status & RTC_DM_BINARY)) { | 126 | if (RTC_ALWAYS_BCD || !(status & RTC_DM_BINARY)) { |
127 | BCD_TO_BIN(sec); | 127 | sec = bcd2bin(sec); |
128 | BCD_TO_BIN(min); | 128 | min = bcd2bin(min); |
129 | BCD_TO_BIN(hour); | 129 | hour = bcd2bin(hour); |
130 | BCD_TO_BIN(day); | 130 | day = bcd2bin(day); |
131 | BCD_TO_BIN(mon); | 131 | mon = bcd2bin(mon); |
132 | BCD_TO_BIN(year); | 132 | year = bcd2bin(year); |
133 | } | 133 | } |
134 | 134 | ||
135 | if (century) { | 135 | if (century) { |
136 | BCD_TO_BIN(century); | 136 | century = bcd2bin(century); |
137 | year += century * 100; | 137 | year += century * 100; |
138 | printk(KERN_INFO "Extended CMOS year: %d\n", century * 100); | 138 | printk(KERN_INFO "Extended CMOS year: %d\n", century * 100); |
139 | } else | 139 | } else |
140 | year += CMOS_YEARS_OFFS; | 140 | year += CMOS_YEARS_OFFS; |
141 | 141 | ||
142 | return mktime(year, mon, day, hour, min, sec); | 142 | return mktime(year, mon, day, hour, min, sec); |
143 | } | 143 | } |
144 | 144 | ||
145 | /* Routines for accessing the CMOS RAM/RTC. */ | 145 | /* Routines for accessing the CMOS RAM/RTC. */ |
146 | unsigned char rtc_cmos_read(unsigned char addr) | 146 | unsigned char rtc_cmos_read(unsigned char addr) |
147 | { | 147 | { |
148 | unsigned char val; | 148 | unsigned char val; |
149 | 149 | ||
150 | lock_cmos_prefix(addr); | 150 | lock_cmos_prefix(addr); |
151 | outb(addr, RTC_PORT(0)); | 151 | outb(addr, RTC_PORT(0)); |
152 | val = inb(RTC_PORT(1)); | 152 | val = inb(RTC_PORT(1)); |
153 | lock_cmos_suffix(addr); | 153 | lock_cmos_suffix(addr); |
154 | return val; | 154 | return val; |
155 | } | 155 | } |
156 | EXPORT_SYMBOL(rtc_cmos_read); | 156 | EXPORT_SYMBOL(rtc_cmos_read); |
157 | 157 | ||
158 | void rtc_cmos_write(unsigned char val, unsigned char addr) | 158 | void rtc_cmos_write(unsigned char val, unsigned char addr) |
159 | { | 159 | { |
160 | lock_cmos_prefix(addr); | 160 | lock_cmos_prefix(addr); |
161 | outb(addr, RTC_PORT(0)); | 161 | outb(addr, RTC_PORT(0)); |
162 | outb(val, RTC_PORT(1)); | 162 | outb(val, RTC_PORT(1)); |
163 | lock_cmos_suffix(addr); | 163 | lock_cmos_suffix(addr); |
164 | } | 164 | } |
165 | EXPORT_SYMBOL(rtc_cmos_write); | 165 | EXPORT_SYMBOL(rtc_cmos_write); |
166 | 166 | ||
167 | static int set_rtc_mmss(unsigned long nowtime) | 167 | static int set_rtc_mmss(unsigned long nowtime) |
168 | { | 168 | { |
169 | int retval; | 169 | int retval; |
170 | unsigned long flags; | 170 | unsigned long flags; |
171 | 171 | ||
172 | spin_lock_irqsave(&rtc_lock, flags); | 172 | spin_lock_irqsave(&rtc_lock, flags); |
173 | retval = set_wallclock(nowtime); | 173 | retval = set_wallclock(nowtime); |
174 | spin_unlock_irqrestore(&rtc_lock, flags); | 174 | spin_unlock_irqrestore(&rtc_lock, flags); |
175 | 175 | ||
176 | return retval; | 176 | return retval; |
177 | } | 177 | } |
178 | 178 | ||
179 | /* not static: needed by APM */ | 179 | /* not static: needed by APM */ |
180 | unsigned long read_persistent_clock(void) | 180 | unsigned long read_persistent_clock(void) |
181 | { | 181 | { |
182 | unsigned long retval, flags; | 182 | unsigned long retval, flags; |
183 | 183 | ||
184 | spin_lock_irqsave(&rtc_lock, flags); | 184 | spin_lock_irqsave(&rtc_lock, flags); |
185 | retval = get_wallclock(); | 185 | retval = get_wallclock(); |
186 | spin_unlock_irqrestore(&rtc_lock, flags); | 186 | spin_unlock_irqrestore(&rtc_lock, flags); |
187 | 187 | ||
188 | return retval; | 188 | return retval; |
189 | } | 189 | } |
190 | 190 | ||
191 | int update_persistent_clock(struct timespec now) | 191 | int update_persistent_clock(struct timespec now) |
192 | { | 192 | { |
193 | return set_rtc_mmss(now.tv_sec); | 193 | return set_rtc_mmss(now.tv_sec); |
194 | } | 194 | } |
195 | 195 | ||
196 | unsigned long long native_read_tsc(void) | 196 | unsigned long long native_read_tsc(void) |
197 | { | 197 | { |
198 | return __native_read_tsc(); | 198 | return __native_read_tsc(); |
199 | } | 199 | } |
200 | EXPORT_SYMBOL(native_read_tsc); | 200 | EXPORT_SYMBOL(native_read_tsc); |
201 | 201 | ||
202 | 202 | ||
203 | static struct resource rtc_resources[] = { | 203 | static struct resource rtc_resources[] = { |
204 | [0] = { | 204 | [0] = { |
205 | .start = RTC_PORT(0), | 205 | .start = RTC_PORT(0), |
206 | .end = RTC_PORT(1), | 206 | .end = RTC_PORT(1), |
207 | .flags = IORESOURCE_IO, | 207 | .flags = IORESOURCE_IO, |
208 | }, | 208 | }, |
209 | [1] = { | 209 | [1] = { |
210 | .start = RTC_IRQ, | 210 | .start = RTC_IRQ, |
211 | .end = RTC_IRQ, | 211 | .end = RTC_IRQ, |
212 | .flags = IORESOURCE_IRQ, | 212 | .flags = IORESOURCE_IRQ, |
213 | } | 213 | } |
214 | }; | 214 | }; |
215 | 215 | ||
216 | static struct platform_device rtc_device = { | 216 | static struct platform_device rtc_device = { |
217 | .name = "rtc_cmos", | 217 | .name = "rtc_cmos", |
218 | .id = -1, | 218 | .id = -1, |
219 | .resource = rtc_resources, | 219 | .resource = rtc_resources, |
220 | .num_resources = ARRAY_SIZE(rtc_resources), | 220 | .num_resources = ARRAY_SIZE(rtc_resources), |
221 | }; | 221 | }; |
222 | 222 | ||
223 | static __init int add_rtc_cmos(void) | 223 | static __init int add_rtc_cmos(void) |
224 | { | 224 | { |
225 | #ifdef CONFIG_PNP | 225 | #ifdef CONFIG_PNP |
226 | static const char *ids[] __initconst = | 226 | static const char *ids[] __initconst = |
227 | { "PNP0b00", "PNP0b01", "PNP0b02", }; | 227 | { "PNP0b00", "PNP0b01", "PNP0b02", }; |
228 | struct pnp_dev *dev; | 228 | struct pnp_dev *dev; |
229 | struct pnp_id *id; | 229 | struct pnp_id *id; |
230 | int i; | 230 | int i; |
231 | 231 | ||
232 | pnp_for_each_dev(dev) { | 232 | pnp_for_each_dev(dev) { |
233 | for (id = dev->id; id; id = id->next) { | 233 | for (id = dev->id; id; id = id->next) { |
234 | for (i = 0; i < ARRAY_SIZE(ids); i++) { | 234 | for (i = 0; i < ARRAY_SIZE(ids); i++) { |
235 | if (compare_pnp_id(id, ids[i]) != 0) | 235 | if (compare_pnp_id(id, ids[i]) != 0) |
236 | return 0; | 236 | return 0; |
237 | } | 237 | } |
238 | } | 238 | } |
239 | } | 239 | } |
240 | #endif | 240 | #endif |
241 | 241 | ||
242 | platform_device_register(&rtc_device); | 242 | platform_device_register(&rtc_device); |
243 | dev_info(&rtc_device.dev, | 243 | dev_info(&rtc_device.dev, |
244 | "registered platform RTC device (no PNP device found)\n"); | 244 | "registered platform RTC device (no PNP device found)\n"); |
245 | return 0; | 245 | return 0; |
246 | } | 246 | } |
247 | device_initcall(add_rtc_cmos); | 247 | device_initcall(add_rtc_cmos); |
248 | 248 |
drivers/char/ds1286.c
1 | /* | 1 | /* |
2 | * DS1286 Real Time Clock interface for Linux | 2 | * DS1286 Real Time Clock interface for Linux |
3 | * | 3 | * |
4 | * Copyright (C) 1998, 1999, 2000 Ralf Baechle | 4 | * Copyright (C) 1998, 1999, 2000 Ralf Baechle |
5 | * | 5 | * |
6 | * Based on code written by Paul Gortmaker. | 6 | * Based on code written by Paul Gortmaker. |
7 | * | 7 | * |
8 | * This driver allows use of the real time clock (built into nearly all | 8 | * This driver allows use of the real time clock (built into nearly all |
9 | * computers) from user space. It exports the /dev/rtc interface supporting | 9 | * computers) from user space. It exports the /dev/rtc interface supporting |
10 | * various ioctl() and also the /proc/rtc pseudo-file for status | 10 | * various ioctl() and also the /proc/rtc pseudo-file for status |
11 | * information. | 11 | * information. |
12 | * | 12 | * |
13 | * The ioctls can be used to set the interrupt behaviour and generation rate | 13 | * The ioctls can be used to set the interrupt behaviour and generation rate |
14 | * from the RTC via IRQ 8. Then the /dev/rtc interface can be used to make | 14 | * from the RTC via IRQ 8. Then the /dev/rtc interface can be used to make |
15 | * use of these timer interrupts, be they interval or alarm based. | 15 | * use of these timer interrupts, be they interval or alarm based. |
16 | * | 16 | * |
17 | * The /dev/rtc interface will block on reads until an interrupt has been | 17 | * The /dev/rtc interface will block on reads until an interrupt has been |
18 | * received. If a RTC interrupt has already happened, it will output an | 18 | * received. If a RTC interrupt has already happened, it will output an |
19 | * unsigned long and then block. The output value contains the interrupt | 19 | * unsigned long and then block. The output value contains the interrupt |
20 | * status in the low byte and the number of interrupts since the last read | 20 | * status in the low byte and the number of interrupts since the last read |
21 | * in the remaining high bytes. The /dev/rtc interface can also be used with | 21 | * in the remaining high bytes. The /dev/rtc interface can also be used with |
22 | * the select(2) call. | 22 | * the select(2) call. |
23 | * | 23 | * |
24 | * This program is free software; you can redistribute it and/or modify it | 24 | * This program is free software; you can redistribute it and/or modify it |
25 | * under the terms of the GNU General Public License as published by the | 25 | * under the terms of the GNU General Public License as published by the |
26 | * Free Software Foundation; either version 2 of the License, or (at your | 26 | * Free Software Foundation; either version 2 of the License, or (at your |
27 | * option) any later version. | 27 | * option) any later version. |
28 | */ | 28 | */ |
29 | #include <linux/ds1286.h> | 29 | #include <linux/ds1286.h> |
30 | #include <linux/smp_lock.h> | 30 | #include <linux/smp_lock.h> |
31 | #include <linux/types.h> | 31 | #include <linux/types.h> |
32 | #include <linux/errno.h> | 32 | #include <linux/errno.h> |
33 | #include <linux/miscdevice.h> | 33 | #include <linux/miscdevice.h> |
34 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
35 | #include <linux/ioport.h> | 35 | #include <linux/ioport.h> |
36 | #include <linux/fcntl.h> | 36 | #include <linux/fcntl.h> |
37 | #include <linux/init.h> | 37 | #include <linux/init.h> |
38 | #include <linux/poll.h> | 38 | #include <linux/poll.h> |
39 | #include <linux/rtc.h> | 39 | #include <linux/rtc.h> |
40 | #include <linux/spinlock.h> | 40 | #include <linux/spinlock.h> |
41 | #include <linux/bcd.h> | 41 | #include <linux/bcd.h> |
42 | #include <linux/proc_fs.h> | 42 | #include <linux/proc_fs.h> |
43 | #include <linux/jiffies.h> | 43 | #include <linux/jiffies.h> |
44 | 44 | ||
45 | #include <asm/uaccess.h> | 45 | #include <asm/uaccess.h> |
46 | #include <asm/system.h> | 46 | #include <asm/system.h> |
47 | 47 | ||
48 | #define DS1286_VERSION "1.0" | 48 | #define DS1286_VERSION "1.0" |
49 | 49 | ||
50 | /* | 50 | /* |
51 | * We sponge a minor off of the misc major. No need slurping | 51 | * We sponge a minor off of the misc major. No need slurping |
52 | * up another valuable major dev number for this. If you add | 52 | * up another valuable major dev number for this. If you add |
53 | * an ioctl, make sure you don't conflict with SPARC's RTC | 53 | * an ioctl, make sure you don't conflict with SPARC's RTC |
54 | * ioctls. | 54 | * ioctls. |
55 | */ | 55 | */ |
56 | 56 | ||
57 | static DECLARE_WAIT_QUEUE_HEAD(ds1286_wait); | 57 | static DECLARE_WAIT_QUEUE_HEAD(ds1286_wait); |
58 | 58 | ||
59 | static ssize_t ds1286_read(struct file *file, char *buf, | 59 | static ssize_t ds1286_read(struct file *file, char *buf, |
60 | size_t count, loff_t *ppos); | 60 | size_t count, loff_t *ppos); |
61 | 61 | ||
62 | static int ds1286_ioctl(struct inode *inode, struct file *file, | 62 | static int ds1286_ioctl(struct inode *inode, struct file *file, |
63 | unsigned int cmd, unsigned long arg); | 63 | unsigned int cmd, unsigned long arg); |
64 | 64 | ||
65 | static unsigned int ds1286_poll(struct file *file, poll_table *wait); | 65 | static unsigned int ds1286_poll(struct file *file, poll_table *wait); |
66 | 66 | ||
67 | static void ds1286_get_alm_time (struct rtc_time *alm_tm); | 67 | static void ds1286_get_alm_time (struct rtc_time *alm_tm); |
68 | static void ds1286_get_time(struct rtc_time *rtc_tm); | 68 | static void ds1286_get_time(struct rtc_time *rtc_tm); |
69 | static int ds1286_set_time(struct rtc_time *rtc_tm); | 69 | static int ds1286_set_time(struct rtc_time *rtc_tm); |
70 | 70 | ||
71 | static inline unsigned char ds1286_is_updating(void); | 71 | static inline unsigned char ds1286_is_updating(void); |
72 | 72 | ||
73 | static DEFINE_SPINLOCK(ds1286_lock); | 73 | static DEFINE_SPINLOCK(ds1286_lock); |
74 | 74 | ||
75 | static int ds1286_read_proc(char *page, char **start, off_t off, | 75 | static int ds1286_read_proc(char *page, char **start, off_t off, |
76 | int count, int *eof, void *data); | 76 | int count, int *eof, void *data); |
77 | 77 | ||
78 | /* | 78 | /* |
79 | * Bits in rtc_status. (7 bits of room for future expansion) | 79 | * Bits in rtc_status. (7 bits of room for future expansion) |
80 | */ | 80 | */ |
81 | 81 | ||
82 | #define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ | 82 | #define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ |
83 | #define RTC_TIMER_ON 0x02 /* missed irq timer active */ | 83 | #define RTC_TIMER_ON 0x02 /* missed irq timer active */ |
84 | 84 | ||
85 | static unsigned char ds1286_status; /* bitmapped status byte. */ | 85 | static unsigned char ds1286_status; /* bitmapped status byte. */ |
86 | 86 | ||
87 | static unsigned char days_in_mo[] = { | 87 | static unsigned char days_in_mo[] = { |
88 | 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 | 88 | 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 |
89 | }; | 89 | }; |
90 | 90 | ||
91 | /* | 91 | /* |
92 | * Now all the various file operations that we export. | 92 | * Now all the various file operations that we export. |
93 | */ | 93 | */ |
94 | 94 | ||
95 | static ssize_t ds1286_read(struct file *file, char *buf, | 95 | static ssize_t ds1286_read(struct file *file, char *buf, |
96 | size_t count, loff_t *ppos) | 96 | size_t count, loff_t *ppos) |
97 | { | 97 | { |
98 | return -EIO; | 98 | return -EIO; |
99 | } | 99 | } |
100 | 100 | ||
101 | static int ds1286_ioctl(struct inode *inode, struct file *file, | 101 | static int ds1286_ioctl(struct inode *inode, struct file *file, |
102 | unsigned int cmd, unsigned long arg) | 102 | unsigned int cmd, unsigned long arg) |
103 | { | 103 | { |
104 | struct rtc_time wtime; | 104 | struct rtc_time wtime; |
105 | 105 | ||
106 | switch (cmd) { | 106 | switch (cmd) { |
107 | case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ | 107 | case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ |
108 | { | 108 | { |
109 | unsigned long flags; | 109 | unsigned long flags; |
110 | unsigned char val; | 110 | unsigned char val; |
111 | 111 | ||
112 | if (!capable(CAP_SYS_TIME)) | 112 | if (!capable(CAP_SYS_TIME)) |
113 | return -EACCES; | 113 | return -EACCES; |
114 | 114 | ||
115 | spin_lock_irqsave(&ds1286_lock, flags); | 115 | spin_lock_irqsave(&ds1286_lock, flags); |
116 | val = rtc_read(RTC_CMD); | 116 | val = rtc_read(RTC_CMD); |
117 | val |= RTC_TDM; | 117 | val |= RTC_TDM; |
118 | rtc_write(val, RTC_CMD); | 118 | rtc_write(val, RTC_CMD); |
119 | spin_unlock_irqrestore(&ds1286_lock, flags); | 119 | spin_unlock_irqrestore(&ds1286_lock, flags); |
120 | 120 | ||
121 | return 0; | 121 | return 0; |
122 | } | 122 | } |
123 | case RTC_AIE_ON: /* Allow alarm interrupts. */ | 123 | case RTC_AIE_ON: /* Allow alarm interrupts. */ |
124 | { | 124 | { |
125 | unsigned long flags; | 125 | unsigned long flags; |
126 | unsigned char val; | 126 | unsigned char val; |
127 | 127 | ||
128 | if (!capable(CAP_SYS_TIME)) | 128 | if (!capable(CAP_SYS_TIME)) |
129 | return -EACCES; | 129 | return -EACCES; |
130 | 130 | ||
131 | spin_lock_irqsave(&ds1286_lock, flags); | 131 | spin_lock_irqsave(&ds1286_lock, flags); |
132 | val = rtc_read(RTC_CMD); | 132 | val = rtc_read(RTC_CMD); |
133 | val &= ~RTC_TDM; | 133 | val &= ~RTC_TDM; |
134 | rtc_write(val, RTC_CMD); | 134 | rtc_write(val, RTC_CMD); |
135 | spin_unlock_irqrestore(&ds1286_lock, flags); | 135 | spin_unlock_irqrestore(&ds1286_lock, flags); |
136 | 136 | ||
137 | return 0; | 137 | return 0; |
138 | } | 138 | } |
139 | case RTC_WIE_OFF: /* Mask watchdog int. enab. bit */ | 139 | case RTC_WIE_OFF: /* Mask watchdog int. enab. bit */ |
140 | { | 140 | { |
141 | unsigned long flags; | 141 | unsigned long flags; |
142 | unsigned char val; | 142 | unsigned char val; |
143 | 143 | ||
144 | if (!capable(CAP_SYS_TIME)) | 144 | if (!capable(CAP_SYS_TIME)) |
145 | return -EACCES; | 145 | return -EACCES; |
146 | 146 | ||
147 | spin_lock_irqsave(&ds1286_lock, flags); | 147 | spin_lock_irqsave(&ds1286_lock, flags); |
148 | val = rtc_read(RTC_CMD); | 148 | val = rtc_read(RTC_CMD); |
149 | val |= RTC_WAM; | 149 | val |= RTC_WAM; |
150 | rtc_write(val, RTC_CMD); | 150 | rtc_write(val, RTC_CMD); |
151 | spin_unlock_irqrestore(&ds1286_lock, flags); | 151 | spin_unlock_irqrestore(&ds1286_lock, flags); |
152 | 152 | ||
153 | return 0; | 153 | return 0; |
154 | } | 154 | } |
155 | case RTC_WIE_ON: /* Allow watchdog interrupts. */ | 155 | case RTC_WIE_ON: /* Allow watchdog interrupts. */ |
156 | { | 156 | { |
157 | unsigned long flags; | 157 | unsigned long flags; |
158 | unsigned char val; | 158 | unsigned char val; |
159 | 159 | ||
160 | if (!capable(CAP_SYS_TIME)) | 160 | if (!capable(CAP_SYS_TIME)) |
161 | return -EACCES; | 161 | return -EACCES; |
162 | 162 | ||
163 | spin_lock_irqsave(&ds1286_lock, flags); | 163 | spin_lock_irqsave(&ds1286_lock, flags); |
164 | val = rtc_read(RTC_CMD); | 164 | val = rtc_read(RTC_CMD); |
165 | val &= ~RTC_WAM; | 165 | val &= ~RTC_WAM; |
166 | rtc_write(val, RTC_CMD); | 166 | rtc_write(val, RTC_CMD); |
167 | spin_unlock_irqrestore(&ds1286_lock, flags); | 167 | spin_unlock_irqrestore(&ds1286_lock, flags); |
168 | 168 | ||
169 | return 0; | 169 | return 0; |
170 | } | 170 | } |
171 | case RTC_ALM_READ: /* Read the present alarm time */ | 171 | case RTC_ALM_READ: /* Read the present alarm time */ |
172 | { | 172 | { |
173 | /* | 173 | /* |
174 | * This returns a struct rtc_time. Reading >= 0xc0 | 174 | * This returns a struct rtc_time. Reading >= 0xc0 |
175 | * means "don't care" or "match all". Only the tm_hour, | 175 | * means "don't care" or "match all". Only the tm_hour, |
176 | * tm_min, and tm_sec values are filled in. | 176 | * tm_min, and tm_sec values are filled in. |
177 | */ | 177 | */ |
178 | 178 | ||
179 | memset(&wtime, 0, sizeof(wtime)); | 179 | memset(&wtime, 0, sizeof(wtime)); |
180 | ds1286_get_alm_time(&wtime); | 180 | ds1286_get_alm_time(&wtime); |
181 | break; | 181 | break; |
182 | } | 182 | } |
183 | case RTC_ALM_SET: /* Store a time into the alarm */ | 183 | case RTC_ALM_SET: /* Store a time into the alarm */ |
184 | { | 184 | { |
185 | /* | 185 | /* |
186 | * This expects a struct rtc_time. Writing 0xff means | 186 | * This expects a struct rtc_time. Writing 0xff means |
187 | * "don't care" or "match all". Only the tm_hour, | 187 | * "don't care" or "match all". Only the tm_hour, |
188 | * tm_min and tm_sec are used. | 188 | * tm_min and tm_sec are used. |
189 | */ | 189 | */ |
190 | unsigned char hrs, min, sec; | 190 | unsigned char hrs, min, sec; |
191 | struct rtc_time alm_tm; | 191 | struct rtc_time alm_tm; |
192 | 192 | ||
193 | if (!capable(CAP_SYS_TIME)) | 193 | if (!capable(CAP_SYS_TIME)) |
194 | return -EACCES; | 194 | return -EACCES; |
195 | 195 | ||
196 | if (copy_from_user(&alm_tm, (struct rtc_time*)arg, | 196 | if (copy_from_user(&alm_tm, (struct rtc_time*)arg, |
197 | sizeof(struct rtc_time))) | 197 | sizeof(struct rtc_time))) |
198 | return -EFAULT; | 198 | return -EFAULT; |
199 | 199 | ||
200 | hrs = alm_tm.tm_hour; | 200 | hrs = alm_tm.tm_hour; |
201 | min = alm_tm.tm_min; | 201 | min = alm_tm.tm_min; |
202 | sec = alm_tm.tm_sec; | 202 | sec = alm_tm.tm_sec; |
203 | 203 | ||
204 | if (hrs >= 24) | 204 | if (hrs >= 24) |
205 | hrs = 0xff; | 205 | hrs = 0xff; |
206 | 206 | ||
207 | if (min >= 60) | 207 | if (min >= 60) |
208 | min = 0xff; | 208 | min = 0xff; |
209 | 209 | ||
210 | if (sec != 0) | 210 | if (sec != 0) |
211 | return -EINVAL; | 211 | return -EINVAL; |
212 | 212 | ||
213 | min = BIN2BCD(min); | 213 | min = bin2bcd(min); |
214 | min = BIN2BCD(hrs); | 214 | min = bin2bcd(hrs); |
215 | 215 | ||
216 | spin_lock(&ds1286_lock); | 216 | spin_lock(&ds1286_lock); |
217 | rtc_write(hrs, RTC_HOURS_ALARM); | 217 | rtc_write(hrs, RTC_HOURS_ALARM); |
218 | rtc_write(min, RTC_MINUTES_ALARM); | 218 | rtc_write(min, RTC_MINUTES_ALARM); |
219 | spin_unlock(&ds1286_lock); | 219 | spin_unlock(&ds1286_lock); |
220 | 220 | ||
221 | return 0; | 221 | return 0; |
222 | } | 222 | } |
223 | case RTC_RD_TIME: /* Read the time/date from RTC */ | 223 | case RTC_RD_TIME: /* Read the time/date from RTC */ |
224 | { | 224 | { |
225 | memset(&wtime, 0, sizeof(wtime)); | 225 | memset(&wtime, 0, sizeof(wtime)); |
226 | ds1286_get_time(&wtime); | 226 | ds1286_get_time(&wtime); |
227 | break; | 227 | break; |
228 | } | 228 | } |
229 | case RTC_SET_TIME: /* Set the RTC */ | 229 | case RTC_SET_TIME: /* Set the RTC */ |
230 | { | 230 | { |
231 | struct rtc_time rtc_tm; | 231 | struct rtc_time rtc_tm; |
232 | 232 | ||
233 | if (!capable(CAP_SYS_TIME)) | 233 | if (!capable(CAP_SYS_TIME)) |
234 | return -EACCES; | 234 | return -EACCES; |
235 | 235 | ||
236 | if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, | 236 | if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, |
237 | sizeof(struct rtc_time))) | 237 | sizeof(struct rtc_time))) |
238 | return -EFAULT; | 238 | return -EFAULT; |
239 | 239 | ||
240 | return ds1286_set_time(&rtc_tm); | 240 | return ds1286_set_time(&rtc_tm); |
241 | } | 241 | } |
242 | default: | 242 | default: |
243 | return -EINVAL; | 243 | return -EINVAL; |
244 | } | 244 | } |
245 | return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; | 245 | return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; |
246 | } | 246 | } |
247 | 247 | ||
248 | /* | 248 | /* |
249 | * We enforce only one user at a time here with the open/close. | 249 | * We enforce only one user at a time here with the open/close. |
250 | * Also clear the previous interrupt data on an open, and clean | 250 | * Also clear the previous interrupt data on an open, and clean |
251 | * up things on a close. | 251 | * up things on a close. |
252 | */ | 252 | */ |
253 | 253 | ||
254 | static int ds1286_open(struct inode *inode, struct file *file) | 254 | static int ds1286_open(struct inode *inode, struct file *file) |
255 | { | 255 | { |
256 | lock_kernel(); | 256 | lock_kernel(); |
257 | spin_lock_irq(&ds1286_lock); | 257 | spin_lock_irq(&ds1286_lock); |
258 | 258 | ||
259 | if (ds1286_status & RTC_IS_OPEN) | 259 | if (ds1286_status & RTC_IS_OPEN) |
260 | goto out_busy; | 260 | goto out_busy; |
261 | 261 | ||
262 | ds1286_status |= RTC_IS_OPEN; | 262 | ds1286_status |= RTC_IS_OPEN; |
263 | 263 | ||
264 | spin_unlock_irq(&ds1286_lock); | 264 | spin_unlock_irq(&ds1286_lock); |
265 | unlock_kernel(); | 265 | unlock_kernel(); |
266 | return 0; | 266 | return 0; |
267 | 267 | ||
268 | out_busy: | 268 | out_busy: |
269 | spin_lock_irq(&ds1286_lock); | 269 | spin_lock_irq(&ds1286_lock); |
270 | unlock_kernel(); | 270 | unlock_kernel(); |
271 | return -EBUSY; | 271 | return -EBUSY; |
272 | } | 272 | } |
273 | 273 | ||
274 | static int ds1286_release(struct inode *inode, struct file *file) | 274 | static int ds1286_release(struct inode *inode, struct file *file) |
275 | { | 275 | { |
276 | ds1286_status &= ~RTC_IS_OPEN; | 276 | ds1286_status &= ~RTC_IS_OPEN; |
277 | 277 | ||
278 | return 0; | 278 | return 0; |
279 | } | 279 | } |
280 | 280 | ||
281 | static unsigned int ds1286_poll(struct file *file, poll_table *wait) | 281 | static unsigned int ds1286_poll(struct file *file, poll_table *wait) |
282 | { | 282 | { |
283 | poll_wait(file, &ds1286_wait, wait); | 283 | poll_wait(file, &ds1286_wait, wait); |
284 | 284 | ||
285 | return 0; | 285 | return 0; |
286 | } | 286 | } |
287 | 287 | ||
288 | /* | 288 | /* |
289 | * The various file operations we support. | 289 | * The various file operations we support. |
290 | */ | 290 | */ |
291 | 291 | ||
292 | static const struct file_operations ds1286_fops = { | 292 | static const struct file_operations ds1286_fops = { |
293 | .llseek = no_llseek, | 293 | .llseek = no_llseek, |
294 | .read = ds1286_read, | 294 | .read = ds1286_read, |
295 | .poll = ds1286_poll, | 295 | .poll = ds1286_poll, |
296 | .ioctl = ds1286_ioctl, | 296 | .ioctl = ds1286_ioctl, |
297 | .open = ds1286_open, | 297 | .open = ds1286_open, |
298 | .release = ds1286_release, | 298 | .release = ds1286_release, |
299 | }; | 299 | }; |
300 | 300 | ||
301 | static struct miscdevice ds1286_dev= | 301 | static struct miscdevice ds1286_dev= |
302 | { | 302 | { |
303 | .minor = RTC_MINOR, | 303 | .minor = RTC_MINOR, |
304 | .name = "rtc", | 304 | .name = "rtc", |
305 | .fops = &ds1286_fops, | 305 | .fops = &ds1286_fops, |
306 | }; | 306 | }; |
307 | 307 | ||
308 | static int __init ds1286_init(void) | 308 | static int __init ds1286_init(void) |
309 | { | 309 | { |
310 | int err; | 310 | int err; |
311 | 311 | ||
312 | printk(KERN_INFO "DS1286 Real Time Clock Driver v%s\n", DS1286_VERSION); | 312 | printk(KERN_INFO "DS1286 Real Time Clock Driver v%s\n", DS1286_VERSION); |
313 | 313 | ||
314 | err = misc_register(&ds1286_dev); | 314 | err = misc_register(&ds1286_dev); |
315 | if (err) | 315 | if (err) |
316 | goto out; | 316 | goto out; |
317 | 317 | ||
318 | if (!create_proc_read_entry("driver/rtc", 0, 0, ds1286_read_proc, NULL)) { | 318 | if (!create_proc_read_entry("driver/rtc", 0, 0, ds1286_read_proc, NULL)) { |
319 | err = -ENOMEM; | 319 | err = -ENOMEM; |
320 | 320 | ||
321 | goto out_deregister; | 321 | goto out_deregister; |
322 | } | 322 | } |
323 | 323 | ||
324 | return 0; | 324 | return 0; |
325 | 325 | ||
326 | out_deregister: | 326 | out_deregister: |
327 | misc_deregister(&ds1286_dev); | 327 | misc_deregister(&ds1286_dev); |
328 | 328 | ||
329 | out: | 329 | out: |
330 | return err; | 330 | return err; |
331 | } | 331 | } |
332 | 332 | ||
333 | static void __exit ds1286_exit(void) | 333 | static void __exit ds1286_exit(void) |
334 | { | 334 | { |
335 | remove_proc_entry("driver/rtc", NULL); | 335 | remove_proc_entry("driver/rtc", NULL); |
336 | misc_deregister(&ds1286_dev); | 336 | misc_deregister(&ds1286_dev); |
337 | } | 337 | } |
338 | 338 | ||
339 | static char *days[] = { | 339 | static char *days[] = { |
340 | "***", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" | 340 | "***", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" |
341 | }; | 341 | }; |
342 | 342 | ||
343 | /* | 343 | /* |
344 | * Info exported via "/proc/rtc". | 344 | * Info exported via "/proc/rtc". |
345 | */ | 345 | */ |
346 | static int ds1286_proc_output(char *buf) | 346 | static int ds1286_proc_output(char *buf) |
347 | { | 347 | { |
348 | char *p, *s; | 348 | char *p, *s; |
349 | struct rtc_time tm; | 349 | struct rtc_time tm; |
350 | unsigned char hundredth, month, cmd, amode; | 350 | unsigned char hundredth, month, cmd, amode; |
351 | 351 | ||
352 | p = buf; | 352 | p = buf; |
353 | 353 | ||
354 | ds1286_get_time(&tm); | 354 | ds1286_get_time(&tm); |
355 | hundredth = rtc_read(RTC_HUNDREDTH_SECOND); | 355 | hundredth = rtc_read(RTC_HUNDREDTH_SECOND); |
356 | BCD_TO_BIN(hundredth); | 356 | hundredth = bcd2bin(hundredth); |
357 | 357 | ||
358 | p += sprintf(p, | 358 | p += sprintf(p, |
359 | "rtc_time\t: %02d:%02d:%02d.%02d\n" | 359 | "rtc_time\t: %02d:%02d:%02d.%02d\n" |
360 | "rtc_date\t: %04d-%02d-%02d\n", | 360 | "rtc_date\t: %04d-%02d-%02d\n", |
361 | tm.tm_hour, tm.tm_min, tm.tm_sec, hundredth, | 361 | tm.tm_hour, tm.tm_min, tm.tm_sec, hundredth, |
362 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); | 362 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); |
363 | 363 | ||
364 | /* | 364 | /* |
365 | * We implicitly assume 24hr mode here. Alarm values >= 0xc0 will | 365 | * We implicitly assume 24hr mode here. Alarm values >= 0xc0 will |
366 | * match any value for that particular field. Values that are | 366 | * match any value for that particular field. Values that are |
367 | * greater than a valid time, but less than 0xc0 shouldn't appear. | 367 | * greater than a valid time, but less than 0xc0 shouldn't appear. |
368 | */ | 368 | */ |
369 | ds1286_get_alm_time(&tm); | 369 | ds1286_get_alm_time(&tm); |
370 | p += sprintf(p, "alarm\t\t: %s ", days[tm.tm_wday]); | 370 | p += sprintf(p, "alarm\t\t: %s ", days[tm.tm_wday]); |
371 | if (tm.tm_hour <= 24) | 371 | if (tm.tm_hour <= 24) |
372 | p += sprintf(p, "%02d:", tm.tm_hour); | 372 | p += sprintf(p, "%02d:", tm.tm_hour); |
373 | else | 373 | else |
374 | p += sprintf(p, "**:"); | 374 | p += sprintf(p, "**:"); |
375 | 375 | ||
376 | if (tm.tm_min <= 59) | 376 | if (tm.tm_min <= 59) |
377 | p += sprintf(p, "%02d\n", tm.tm_min); | 377 | p += sprintf(p, "%02d\n", tm.tm_min); |
378 | else | 378 | else |
379 | p += sprintf(p, "**\n"); | 379 | p += sprintf(p, "**\n"); |
380 | 380 | ||
381 | month = rtc_read(RTC_MONTH); | 381 | month = rtc_read(RTC_MONTH); |
382 | p += sprintf(p, | 382 | p += sprintf(p, |
383 | "oscillator\t: %s\n" | 383 | "oscillator\t: %s\n" |
384 | "square_wave\t: %s\n", | 384 | "square_wave\t: %s\n", |
385 | (month & RTC_EOSC) ? "disabled" : "enabled", | 385 | (month & RTC_EOSC) ? "disabled" : "enabled", |
386 | (month & RTC_ESQW) ? "disabled" : "enabled"); | 386 | (month & RTC_ESQW) ? "disabled" : "enabled"); |
387 | 387 | ||
388 | amode = ((rtc_read(RTC_MINUTES_ALARM) & 0x80) >> 5) | | 388 | amode = ((rtc_read(RTC_MINUTES_ALARM) & 0x80) >> 5) | |
389 | ((rtc_read(RTC_HOURS_ALARM) & 0x80) >> 6) | | 389 | ((rtc_read(RTC_HOURS_ALARM) & 0x80) >> 6) | |
390 | ((rtc_read(RTC_DAY_ALARM) & 0x80) >> 7); | 390 | ((rtc_read(RTC_DAY_ALARM) & 0x80) >> 7); |
391 | if (amode == 7) s = "each minute"; | 391 | if (amode == 7) s = "each minute"; |
392 | else if (amode == 3) s = "minutes match"; | 392 | else if (amode == 3) s = "minutes match"; |
393 | else if (amode == 1) s = "hours and minutes match"; | 393 | else if (amode == 1) s = "hours and minutes match"; |
394 | else if (amode == 0) s = "days, hours and minutes match"; | 394 | else if (amode == 0) s = "days, hours and minutes match"; |
395 | else s = "invalid"; | 395 | else s = "invalid"; |
396 | p += sprintf(p, "alarm_mode\t: %s\n", s); | 396 | p += sprintf(p, "alarm_mode\t: %s\n", s); |
397 | 397 | ||
398 | cmd = rtc_read(RTC_CMD); | 398 | cmd = rtc_read(RTC_CMD); |
399 | p += sprintf(p, | 399 | p += sprintf(p, |
400 | "alarm_enable\t: %s\n" | 400 | "alarm_enable\t: %s\n" |
401 | "wdog_alarm\t: %s\n" | 401 | "wdog_alarm\t: %s\n" |
402 | "alarm_mask\t: %s\n" | 402 | "alarm_mask\t: %s\n" |
403 | "wdog_alarm_mask\t: %s\n" | 403 | "wdog_alarm_mask\t: %s\n" |
404 | "interrupt_mode\t: %s\n" | 404 | "interrupt_mode\t: %s\n" |
405 | "INTB_mode\t: %s_active\n" | 405 | "INTB_mode\t: %s_active\n" |
406 | "interrupt_pins\t: %s\n", | 406 | "interrupt_pins\t: %s\n", |
407 | (cmd & RTC_TDF) ? "yes" : "no", | 407 | (cmd & RTC_TDF) ? "yes" : "no", |
408 | (cmd & RTC_WAF) ? "yes" : "no", | 408 | (cmd & RTC_WAF) ? "yes" : "no", |
409 | (cmd & RTC_TDM) ? "disabled" : "enabled", | 409 | (cmd & RTC_TDM) ? "disabled" : "enabled", |
410 | (cmd & RTC_WAM) ? "disabled" : "enabled", | 410 | (cmd & RTC_WAM) ? "disabled" : "enabled", |
411 | (cmd & RTC_PU_LVL) ? "pulse" : "level", | 411 | (cmd & RTC_PU_LVL) ? "pulse" : "level", |
412 | (cmd & RTC_IBH_LO) ? "low" : "high", | 412 | (cmd & RTC_IBH_LO) ? "low" : "high", |
413 | (cmd & RTC_IPSW) ? "unswapped" : "swapped"); | 413 | (cmd & RTC_IPSW) ? "unswapped" : "swapped"); |
414 | 414 | ||
415 | return p - buf; | 415 | return p - buf; |
416 | } | 416 | } |
417 | 417 | ||
418 | static int ds1286_read_proc(char *page, char **start, off_t off, | 418 | static int ds1286_read_proc(char *page, char **start, off_t off, |
419 | int count, int *eof, void *data) | 419 | int count, int *eof, void *data) |
420 | { | 420 | { |
421 | int len = ds1286_proc_output (page); | 421 | int len = ds1286_proc_output (page); |
422 | if (len <= off+count) *eof = 1; | 422 | if (len <= off+count) *eof = 1; |
423 | *start = page + off; | 423 | *start = page + off; |
424 | len -= off; | 424 | len -= off; |
425 | if (len>count) | 425 | if (len>count) |
426 | len = count; | 426 | len = count; |
427 | if (len<0) | 427 | if (len<0) |
428 | len = 0; | 428 | len = 0; |
429 | 429 | ||
430 | return len; | 430 | return len; |
431 | } | 431 | } |
432 | 432 | ||
433 | /* | 433 | /* |
434 | * Returns true if a clock update is in progress | 434 | * Returns true if a clock update is in progress |
435 | */ | 435 | */ |
436 | static inline unsigned char ds1286_is_updating(void) | 436 | static inline unsigned char ds1286_is_updating(void) |
437 | { | 437 | { |
438 | return rtc_read(RTC_CMD) & RTC_TE; | 438 | return rtc_read(RTC_CMD) & RTC_TE; |
439 | } | 439 | } |
440 | 440 | ||
441 | 441 | ||
442 | static void ds1286_get_time(struct rtc_time *rtc_tm) | 442 | static void ds1286_get_time(struct rtc_time *rtc_tm) |
443 | { | 443 | { |
444 | unsigned char save_control; | 444 | unsigned char save_control; |
445 | unsigned long flags; | 445 | unsigned long flags; |
446 | 446 | ||
447 | /* | 447 | /* |
448 | * read RTC once any update in progress is done. The update | 448 | * read RTC once any update in progress is done. The update |
449 | * can take just over 2ms. We wait 10 to 20ms. There is no need to | 449 | * can take just over 2ms. We wait 10 to 20ms. There is no need to |
450 | * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. | 450 | * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. |
451 | * If you need to know *exactly* when a second has started, enable | 451 | * If you need to know *exactly* when a second has started, enable |
452 | * periodic update complete interrupts, (via ioctl) and then | 452 | * periodic update complete interrupts, (via ioctl) and then |
453 | * immediately read /dev/rtc which will block until you get the IRQ. | 453 | * immediately read /dev/rtc which will block until you get the IRQ. |
454 | * Once the read clears, read the RTC time (again via ioctl). Easy. | 454 | * Once the read clears, read the RTC time (again via ioctl). Easy. |
455 | */ | 455 | */ |
456 | 456 | ||
457 | if (ds1286_is_updating() != 0) | 457 | if (ds1286_is_updating() != 0) |
458 | msleep(20); | 458 | msleep(20); |
459 | 459 | ||
460 | /* | 460 | /* |
461 | * Only the values that we read from the RTC are set. We leave | 461 | * Only the values that we read from the RTC are set. We leave |
462 | * tm_wday, tm_yday and tm_isdst untouched. Even though the | 462 | * tm_wday, tm_yday and tm_isdst untouched. Even though the |
463 | * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated | 463 | * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated |
464 | * by the RTC when initially set to a non-zero value. | 464 | * by the RTC when initially set to a non-zero value. |
465 | */ | 465 | */ |
466 | spin_lock_irqsave(&ds1286_lock, flags); | 466 | spin_lock_irqsave(&ds1286_lock, flags); |
467 | save_control = rtc_read(RTC_CMD); | 467 | save_control = rtc_read(RTC_CMD); |
468 | rtc_write((save_control|RTC_TE), RTC_CMD); | 468 | rtc_write((save_control|RTC_TE), RTC_CMD); |
469 | 469 | ||
470 | rtc_tm->tm_sec = rtc_read(RTC_SECONDS); | 470 | rtc_tm->tm_sec = rtc_read(RTC_SECONDS); |
471 | rtc_tm->tm_min = rtc_read(RTC_MINUTES); | 471 | rtc_tm->tm_min = rtc_read(RTC_MINUTES); |
472 | rtc_tm->tm_hour = rtc_read(RTC_HOURS) & 0x3f; | 472 | rtc_tm->tm_hour = rtc_read(RTC_HOURS) & 0x3f; |
473 | rtc_tm->tm_mday = rtc_read(RTC_DATE); | 473 | rtc_tm->tm_mday = rtc_read(RTC_DATE); |
474 | rtc_tm->tm_mon = rtc_read(RTC_MONTH) & 0x1f; | 474 | rtc_tm->tm_mon = rtc_read(RTC_MONTH) & 0x1f; |
475 | rtc_tm->tm_year = rtc_read(RTC_YEAR); | 475 | rtc_tm->tm_year = rtc_read(RTC_YEAR); |
476 | 476 | ||
477 | rtc_write(save_control, RTC_CMD); | 477 | rtc_write(save_control, RTC_CMD); |
478 | spin_unlock_irqrestore(&ds1286_lock, flags); | 478 | spin_unlock_irqrestore(&ds1286_lock, flags); |
479 | 479 | ||
480 | BCD_TO_BIN(rtc_tm->tm_sec); | 480 | rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec); |
481 | BCD_TO_BIN(rtc_tm->tm_min); | 481 | rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min); |
482 | BCD_TO_BIN(rtc_tm->tm_hour); | 482 | rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour); |
483 | BCD_TO_BIN(rtc_tm->tm_mday); | 483 | rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday); |
484 | BCD_TO_BIN(rtc_tm->tm_mon); | 484 | rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon); |
485 | BCD_TO_BIN(rtc_tm->tm_year); | 485 | rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year); |
486 | 486 | ||
487 | /* | 487 | /* |
488 | * Account for differences between how the RTC uses the values | 488 | * Account for differences between how the RTC uses the values |
489 | * and how they are defined in a struct rtc_time; | 489 | * and how they are defined in a struct rtc_time; |
490 | */ | 490 | */ |
491 | if (rtc_tm->tm_year < 45) | 491 | if (rtc_tm->tm_year < 45) |
492 | rtc_tm->tm_year += 30; | 492 | rtc_tm->tm_year += 30; |
493 | if ((rtc_tm->tm_year += 40) < 70) | 493 | if ((rtc_tm->tm_year += 40) < 70) |
494 | rtc_tm->tm_year += 100; | 494 | rtc_tm->tm_year += 100; |
495 | 495 | ||
496 | rtc_tm->tm_mon--; | 496 | rtc_tm->tm_mon--; |
497 | } | 497 | } |
498 | 498 | ||
499 | static int ds1286_set_time(struct rtc_time *rtc_tm) | 499 | static int ds1286_set_time(struct rtc_time *rtc_tm) |
500 | { | 500 | { |
501 | unsigned char mon, day, hrs, min, sec, leap_yr; | 501 | unsigned char mon, day, hrs, min, sec, leap_yr; |
502 | unsigned char save_control; | 502 | unsigned char save_control; |
503 | unsigned int yrs; | 503 | unsigned int yrs; |
504 | unsigned long flags; | 504 | unsigned long flags; |
505 | 505 | ||
506 | 506 | ||
507 | yrs = rtc_tm->tm_year + 1900; | 507 | yrs = rtc_tm->tm_year + 1900; |
508 | mon = rtc_tm->tm_mon + 1; /* tm_mon starts at zero */ | 508 | mon = rtc_tm->tm_mon + 1; /* tm_mon starts at zero */ |
509 | day = rtc_tm->tm_mday; | 509 | day = rtc_tm->tm_mday; |
510 | hrs = rtc_tm->tm_hour; | 510 | hrs = rtc_tm->tm_hour; |
511 | min = rtc_tm->tm_min; | 511 | min = rtc_tm->tm_min; |
512 | sec = rtc_tm->tm_sec; | 512 | sec = rtc_tm->tm_sec; |
513 | 513 | ||
514 | if (yrs < 1970) | 514 | if (yrs < 1970) |
515 | return -EINVAL; | 515 | return -EINVAL; |
516 | 516 | ||
517 | leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); | 517 | leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); |
518 | 518 | ||
519 | if ((mon > 12) || (day == 0)) | 519 | if ((mon > 12) || (day == 0)) |
520 | return -EINVAL; | 520 | return -EINVAL; |
521 | 521 | ||
522 | if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) | 522 | if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) |
523 | return -EINVAL; | 523 | return -EINVAL; |
524 | 524 | ||
525 | if ((hrs >= 24) || (min >= 60) || (sec >= 60)) | 525 | if ((hrs >= 24) || (min >= 60) || (sec >= 60)) |
526 | return -EINVAL; | 526 | return -EINVAL; |
527 | 527 | ||
528 | if ((yrs -= 1940) > 255) /* They are unsigned */ | 528 | if ((yrs -= 1940) > 255) /* They are unsigned */ |
529 | return -EINVAL; | 529 | return -EINVAL; |
530 | 530 | ||
531 | if (yrs >= 100) | 531 | if (yrs >= 100) |
532 | yrs -= 100; | 532 | yrs -= 100; |
533 | 533 | ||
534 | BIN_TO_BCD(sec); | 534 | sec = bin2bcd(sec); |
535 | BIN_TO_BCD(min); | 535 | min = bin2bcd(min); |
536 | BIN_TO_BCD(hrs); | 536 | hrs = bin2bcd(hrs); |
537 | BIN_TO_BCD(day); | 537 | day = bin2bcd(day); |
538 | BIN_TO_BCD(mon); | 538 | mon = bin2bcd(mon); |
539 | BIN_TO_BCD(yrs); | 539 | yrs = bin2bcd(yrs); |
540 | 540 | ||
541 | spin_lock_irqsave(&ds1286_lock, flags); | 541 | spin_lock_irqsave(&ds1286_lock, flags); |
542 | save_control = rtc_read(RTC_CMD); | 542 | save_control = rtc_read(RTC_CMD); |
543 | rtc_write((save_control|RTC_TE), RTC_CMD); | 543 | rtc_write((save_control|RTC_TE), RTC_CMD); |
544 | 544 | ||
545 | rtc_write(yrs, RTC_YEAR); | 545 | rtc_write(yrs, RTC_YEAR); |
546 | rtc_write(mon, RTC_MONTH); | 546 | rtc_write(mon, RTC_MONTH); |
547 | rtc_write(day, RTC_DATE); | 547 | rtc_write(day, RTC_DATE); |
548 | rtc_write(hrs, RTC_HOURS); | 548 | rtc_write(hrs, RTC_HOURS); |
549 | rtc_write(min, RTC_MINUTES); | 549 | rtc_write(min, RTC_MINUTES); |
550 | rtc_write(sec, RTC_SECONDS); | 550 | rtc_write(sec, RTC_SECONDS); |
551 | rtc_write(0, RTC_HUNDREDTH_SECOND); | 551 | rtc_write(0, RTC_HUNDREDTH_SECOND); |
552 | 552 | ||
553 | rtc_write(save_control, RTC_CMD); | 553 | rtc_write(save_control, RTC_CMD); |
554 | spin_unlock_irqrestore(&ds1286_lock, flags); | 554 | spin_unlock_irqrestore(&ds1286_lock, flags); |
555 | 555 | ||
556 | return 0; | 556 | return 0; |
557 | } | 557 | } |
558 | 558 | ||
559 | static void ds1286_get_alm_time(struct rtc_time *alm_tm) | 559 | static void ds1286_get_alm_time(struct rtc_time *alm_tm) |
560 | { | 560 | { |
561 | unsigned char cmd; | 561 | unsigned char cmd; |
562 | unsigned long flags; | 562 | unsigned long flags; |
563 | 563 | ||
564 | /* | 564 | /* |
565 | * Only the values that we read from the RTC are set. That | 565 | * Only the values that we read from the RTC are set. That |
566 | * means only tm_wday, tm_hour, tm_min. | 566 | * means only tm_wday, tm_hour, tm_min. |
567 | */ | 567 | */ |
568 | spin_lock_irqsave(&ds1286_lock, flags); | 568 | spin_lock_irqsave(&ds1286_lock, flags); |
569 | alm_tm->tm_min = rtc_read(RTC_MINUTES_ALARM) & 0x7f; | 569 | alm_tm->tm_min = rtc_read(RTC_MINUTES_ALARM) & 0x7f; |
570 | alm_tm->tm_hour = rtc_read(RTC_HOURS_ALARM) & 0x1f; | 570 | alm_tm->tm_hour = rtc_read(RTC_HOURS_ALARM) & 0x1f; |
571 | alm_tm->tm_wday = rtc_read(RTC_DAY_ALARM) & 0x07; | 571 | alm_tm->tm_wday = rtc_read(RTC_DAY_ALARM) & 0x07; |
572 | cmd = rtc_read(RTC_CMD); | 572 | cmd = rtc_read(RTC_CMD); |
573 | spin_unlock_irqrestore(&ds1286_lock, flags); | 573 | spin_unlock_irqrestore(&ds1286_lock, flags); |
574 | 574 | ||
575 | BCD_TO_BIN(alm_tm->tm_min); | 575 | alm_tm->tm_min = bcd2bin(alm_tm->tm_min); |
576 | BCD_TO_BIN(alm_tm->tm_hour); | 576 | alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour); |
577 | alm_tm->tm_sec = 0; | 577 | alm_tm->tm_sec = 0; |
578 | } | 578 | } |
579 | 579 | ||
580 | module_init(ds1286_init); | 580 | module_init(ds1286_init); |
581 | module_exit(ds1286_exit); | 581 | module_exit(ds1286_exit); |
582 | 582 | ||
583 | MODULE_AUTHOR("Ralf Baechle"); | 583 | MODULE_AUTHOR("Ralf Baechle"); |
584 | MODULE_LICENSE("GPL"); | 584 | MODULE_LICENSE("GPL"); |
585 | MODULE_ALIAS_MISCDEV(RTC_MINOR); | 585 | MODULE_ALIAS_MISCDEV(RTC_MINOR); |
586 | 586 |
drivers/char/ds1302.c
1 | /*!*************************************************************************** | 1 | /*!*************************************************************************** |
2 | *! | 2 | *! |
3 | *! FILE NAME : ds1302.c | 3 | *! FILE NAME : ds1302.c |
4 | *! | 4 | *! |
5 | *! DESCRIPTION: Implements an interface for the DS1302 RTC | 5 | *! DESCRIPTION: Implements an interface for the DS1302 RTC |
6 | *! | 6 | *! |
7 | *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status | 7 | *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status |
8 | *! | 8 | *! |
9 | *! --------------------------------------------------------------------------- | 9 | *! --------------------------------------------------------------------------- |
10 | *! | 10 | *! |
11 | *! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN | 11 | *! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN |
12 | *! | 12 | *! |
13 | *!***************************************************************************/ | 13 | *!***************************************************************************/ |
14 | 14 | ||
15 | 15 | ||
16 | #include <linux/fs.h> | 16 | #include <linux/fs.h> |
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/mm.h> | 18 | #include <linux/mm.h> |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/miscdevice.h> | 20 | #include <linux/miscdevice.h> |
21 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
22 | #include <linux/bcd.h> | 22 | #include <linux/bcd.h> |
23 | #include <linux/smp_lock.h> | 23 | #include <linux/smp_lock.h> |
24 | #include <linux/uaccess.h> | 24 | #include <linux/uaccess.h> |
25 | #include <linux/io.h> | 25 | #include <linux/io.h> |
26 | 26 | ||
27 | #include <asm/system.h> | 27 | #include <asm/system.h> |
28 | #include <asm/rtc.h> | 28 | #include <asm/rtc.h> |
29 | #if defined(CONFIG_M32R) | 29 | #if defined(CONFIG_M32R) |
30 | #include <asm/m32r.h> | 30 | #include <asm/m32r.h> |
31 | #endif | 31 | #endif |
32 | 32 | ||
33 | #define RTC_MAJOR_NR 121 /* local major, change later */ | 33 | #define RTC_MAJOR_NR 121 /* local major, change later */ |
34 | 34 | ||
35 | static const char ds1302_name[] = "ds1302"; | 35 | static const char ds1302_name[] = "ds1302"; |
36 | 36 | ||
37 | /* Send 8 bits. */ | 37 | /* Send 8 bits. */ |
38 | static void | 38 | static void |
39 | out_byte_rtc(unsigned int reg_addr, unsigned char x) | 39 | out_byte_rtc(unsigned int reg_addr, unsigned char x) |
40 | { | 40 | { |
41 | //RST H | 41 | //RST H |
42 | outw(0x0001,(unsigned long)PLD_RTCRSTODT); | 42 | outw(0x0001,(unsigned long)PLD_RTCRSTODT); |
43 | //write data | 43 | //write data |
44 | outw(((x<<8)|(reg_addr&0xff)),(unsigned long)PLD_RTCWRDATA); | 44 | outw(((x<<8)|(reg_addr&0xff)),(unsigned long)PLD_RTCWRDATA); |
45 | //WE | 45 | //WE |
46 | outw(0x0002,(unsigned long)PLD_RTCCR); | 46 | outw(0x0002,(unsigned long)PLD_RTCCR); |
47 | //wait | 47 | //wait |
48 | while(inw((unsigned long)PLD_RTCCR)); | 48 | while(inw((unsigned long)PLD_RTCCR)); |
49 | 49 | ||
50 | //RST L | 50 | //RST L |
51 | outw(0x0000,(unsigned long)PLD_RTCRSTODT); | 51 | outw(0x0000,(unsigned long)PLD_RTCRSTODT); |
52 | 52 | ||
53 | } | 53 | } |
54 | 54 | ||
55 | static unsigned char | 55 | static unsigned char |
56 | in_byte_rtc(unsigned int reg_addr) | 56 | in_byte_rtc(unsigned int reg_addr) |
57 | { | 57 | { |
58 | unsigned char retval; | 58 | unsigned char retval; |
59 | 59 | ||
60 | //RST H | 60 | //RST H |
61 | outw(0x0001,(unsigned long)PLD_RTCRSTODT); | 61 | outw(0x0001,(unsigned long)PLD_RTCRSTODT); |
62 | //write data | 62 | //write data |
63 | outw((reg_addr&0xff),(unsigned long)PLD_RTCRDDATA); | 63 | outw((reg_addr&0xff),(unsigned long)PLD_RTCRDDATA); |
64 | //RE | 64 | //RE |
65 | outw(0x0001,(unsigned long)PLD_RTCCR); | 65 | outw(0x0001,(unsigned long)PLD_RTCCR); |
66 | //wait | 66 | //wait |
67 | while(inw((unsigned long)PLD_RTCCR)); | 67 | while(inw((unsigned long)PLD_RTCCR)); |
68 | 68 | ||
69 | //read data | 69 | //read data |
70 | retval=(inw((unsigned long)PLD_RTCRDDATA) & 0xff00)>>8; | 70 | retval=(inw((unsigned long)PLD_RTCRDDATA) & 0xff00)>>8; |
71 | 71 | ||
72 | //RST L | 72 | //RST L |
73 | outw(0x0000,(unsigned long)PLD_RTCRSTODT); | 73 | outw(0x0000,(unsigned long)PLD_RTCRSTODT); |
74 | 74 | ||
75 | return retval; | 75 | return retval; |
76 | } | 76 | } |
77 | 77 | ||
78 | /* Enable writing. */ | 78 | /* Enable writing. */ |
79 | 79 | ||
80 | static void | 80 | static void |
81 | ds1302_wenable(void) | 81 | ds1302_wenable(void) |
82 | { | 82 | { |
83 | out_byte_rtc(0x8e,0x00); | 83 | out_byte_rtc(0x8e,0x00); |
84 | } | 84 | } |
85 | 85 | ||
86 | /* Disable writing. */ | 86 | /* Disable writing. */ |
87 | 87 | ||
88 | static void | 88 | static void |
89 | ds1302_wdisable(void) | 89 | ds1302_wdisable(void) |
90 | { | 90 | { |
91 | out_byte_rtc(0x8e,0x80); | 91 | out_byte_rtc(0x8e,0x80); |
92 | } | 92 | } |
93 | 93 | ||
94 | 94 | ||
95 | 95 | ||
96 | /* Read a byte from the selected register in the DS1302. */ | 96 | /* Read a byte from the selected register in the DS1302. */ |
97 | 97 | ||
98 | unsigned char | 98 | unsigned char |
99 | ds1302_readreg(int reg) | 99 | ds1302_readreg(int reg) |
100 | { | 100 | { |
101 | unsigned char x; | 101 | unsigned char x; |
102 | 102 | ||
103 | x=in_byte_rtc((0x81 | (reg << 1))); /* read register */ | 103 | x=in_byte_rtc((0x81 | (reg << 1))); /* read register */ |
104 | 104 | ||
105 | return x; | 105 | return x; |
106 | } | 106 | } |
107 | 107 | ||
108 | /* Write a byte to the selected register. */ | 108 | /* Write a byte to the selected register. */ |
109 | 109 | ||
110 | void | 110 | void |
111 | ds1302_writereg(int reg, unsigned char val) | 111 | ds1302_writereg(int reg, unsigned char val) |
112 | { | 112 | { |
113 | ds1302_wenable(); | 113 | ds1302_wenable(); |
114 | out_byte_rtc((0x80 | (reg << 1)),val); | 114 | out_byte_rtc((0x80 | (reg << 1)),val); |
115 | ds1302_wdisable(); | 115 | ds1302_wdisable(); |
116 | } | 116 | } |
117 | 117 | ||
118 | void | 118 | void |
119 | get_rtc_time(struct rtc_time *rtc_tm) | 119 | get_rtc_time(struct rtc_time *rtc_tm) |
120 | { | 120 | { |
121 | unsigned long flags; | 121 | unsigned long flags; |
122 | 122 | ||
123 | local_irq_save(flags); | 123 | local_irq_save(flags); |
124 | 124 | ||
125 | rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); | 125 | rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); |
126 | rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); | 126 | rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); |
127 | rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); | 127 | rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); |
128 | rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); | 128 | rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); |
129 | rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); | 129 | rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); |
130 | rtc_tm->tm_year = CMOS_READ(RTC_YEAR); | 130 | rtc_tm->tm_year = CMOS_READ(RTC_YEAR); |
131 | 131 | ||
132 | local_irq_restore(flags); | 132 | local_irq_restore(flags); |
133 | 133 | ||
134 | BCD_TO_BIN(rtc_tm->tm_sec); | 134 | rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec); |
135 | BCD_TO_BIN(rtc_tm->tm_min); | 135 | rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min); |
136 | BCD_TO_BIN(rtc_tm->tm_hour); | 136 | rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour); |
137 | BCD_TO_BIN(rtc_tm->tm_mday); | 137 | rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday); |
138 | BCD_TO_BIN(rtc_tm->tm_mon); | 138 | rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon); |
139 | BCD_TO_BIN(rtc_tm->tm_year); | 139 | rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year); |
140 | 140 | ||
141 | /* | 141 | /* |
142 | * Account for differences between how the RTC uses the values | 142 | * Account for differences between how the RTC uses the values |
143 | * and how they are defined in a struct rtc_time; | 143 | * and how they are defined in a struct rtc_time; |
144 | */ | 144 | */ |
145 | 145 | ||
146 | if (rtc_tm->tm_year <= 69) | 146 | if (rtc_tm->tm_year <= 69) |
147 | rtc_tm->tm_year += 100; | 147 | rtc_tm->tm_year += 100; |
148 | 148 | ||
149 | rtc_tm->tm_mon--; | 149 | rtc_tm->tm_mon--; |
150 | } | 150 | } |
151 | 151 | ||
152 | static unsigned char days_in_mo[] = | 152 | static unsigned char days_in_mo[] = |
153 | {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | 153 | {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; |
154 | 154 | ||
155 | /* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date). */ | 155 | /* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date). */ |
156 | 156 | ||
157 | static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 157 | static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
158 | { | 158 | { |
159 | unsigned long flags; | 159 | unsigned long flags; |
160 | 160 | ||
161 | switch(cmd) { | 161 | switch(cmd) { |
162 | case RTC_RD_TIME: /* read the time/date from RTC */ | 162 | case RTC_RD_TIME: /* read the time/date from RTC */ |
163 | { | 163 | { |
164 | struct rtc_time rtc_tm; | 164 | struct rtc_time rtc_tm; |
165 | 165 | ||
166 | memset(&rtc_tm, 0, sizeof (struct rtc_time)); | 166 | memset(&rtc_tm, 0, sizeof (struct rtc_time)); |
167 | lock_kernel(); | 167 | lock_kernel(); |
168 | get_rtc_time(&rtc_tm); | 168 | get_rtc_time(&rtc_tm); |
169 | unlock_kernel(); | 169 | unlock_kernel(); |
170 | if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time))) | 170 | if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time))) |
171 | return -EFAULT; | 171 | return -EFAULT; |
172 | return 0; | 172 | return 0; |
173 | } | 173 | } |
174 | 174 | ||
175 | case RTC_SET_TIME: /* set the RTC */ | 175 | case RTC_SET_TIME: /* set the RTC */ |
176 | { | 176 | { |
177 | struct rtc_time rtc_tm; | 177 | struct rtc_time rtc_tm; |
178 | unsigned char mon, day, hrs, min, sec, leap_yr; | 178 | unsigned char mon, day, hrs, min, sec, leap_yr; |
179 | unsigned int yrs; | 179 | unsigned int yrs; |
180 | 180 | ||
181 | if (!capable(CAP_SYS_TIME)) | 181 | if (!capable(CAP_SYS_TIME)) |
182 | return -EPERM; | 182 | return -EPERM; |
183 | 183 | ||
184 | if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) | 184 | if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) |
185 | return -EFAULT; | 185 | return -EFAULT; |
186 | 186 | ||
187 | yrs = rtc_tm.tm_year + 1900; | 187 | yrs = rtc_tm.tm_year + 1900; |
188 | mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ | 188 | mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ |
189 | day = rtc_tm.tm_mday; | 189 | day = rtc_tm.tm_mday; |
190 | hrs = rtc_tm.tm_hour; | 190 | hrs = rtc_tm.tm_hour; |
191 | min = rtc_tm.tm_min; | 191 | min = rtc_tm.tm_min; |
192 | sec = rtc_tm.tm_sec; | 192 | sec = rtc_tm.tm_sec; |
193 | 193 | ||
194 | 194 | ||
195 | if ((yrs < 1970) || (yrs > 2069)) | 195 | if ((yrs < 1970) || (yrs > 2069)) |
196 | return -EINVAL; | 196 | return -EINVAL; |
197 | 197 | ||
198 | leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); | 198 | leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); |
199 | 199 | ||
200 | if ((mon > 12) || (day == 0)) | 200 | if ((mon > 12) || (day == 0)) |
201 | return -EINVAL; | 201 | return -EINVAL; |
202 | 202 | ||
203 | if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) | 203 | if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) |
204 | return -EINVAL; | 204 | return -EINVAL; |
205 | 205 | ||
206 | if ((hrs >= 24) || (min >= 60) || (sec >= 60)) | 206 | if ((hrs >= 24) || (min >= 60) || (sec >= 60)) |
207 | return -EINVAL; | 207 | return -EINVAL; |
208 | 208 | ||
209 | if (yrs >= 2000) | 209 | if (yrs >= 2000) |
210 | yrs -= 2000; /* RTC (0, 1, ... 69) */ | 210 | yrs -= 2000; /* RTC (0, 1, ... 69) */ |
211 | else | 211 | else |
212 | yrs -= 1900; /* RTC (70, 71, ... 99) */ | 212 | yrs -= 1900; /* RTC (70, 71, ... 99) */ |
213 | 213 | ||
214 | BIN_TO_BCD(sec); | 214 | sec = bin2bcd(sec); |
215 | BIN_TO_BCD(min); | 215 | min = bin2bcd(min); |
216 | BIN_TO_BCD(hrs); | 216 | hrs = bin2bcd(hrs); |
217 | BIN_TO_BCD(day); | 217 | day = bin2bcd(day); |
218 | BIN_TO_BCD(mon); | 218 | mon = bin2bcd(mon); |
219 | BIN_TO_BCD(yrs); | 219 | yrs = bin2bcd(yrs); |
220 | 220 | ||
221 | lock_kernel(); | 221 | lock_kernel(); |
222 | local_irq_save(flags); | 222 | local_irq_save(flags); |
223 | CMOS_WRITE(yrs, RTC_YEAR); | 223 | CMOS_WRITE(yrs, RTC_YEAR); |
224 | CMOS_WRITE(mon, RTC_MONTH); | 224 | CMOS_WRITE(mon, RTC_MONTH); |
225 | CMOS_WRITE(day, RTC_DAY_OF_MONTH); | 225 | CMOS_WRITE(day, RTC_DAY_OF_MONTH); |
226 | CMOS_WRITE(hrs, RTC_HOURS); | 226 | CMOS_WRITE(hrs, RTC_HOURS); |
227 | CMOS_WRITE(min, RTC_MINUTES); | 227 | CMOS_WRITE(min, RTC_MINUTES); |
228 | CMOS_WRITE(sec, RTC_SECONDS); | 228 | CMOS_WRITE(sec, RTC_SECONDS); |
229 | local_irq_restore(flags); | 229 | local_irq_restore(flags); |
230 | unlock_kernel(); | 230 | unlock_kernel(); |
231 | 231 | ||
232 | /* Notice that at this point, the RTC is updated but | 232 | /* Notice that at this point, the RTC is updated but |
233 | * the kernel is still running with the old time. | 233 | * the kernel is still running with the old time. |
234 | * You need to set that separately with settimeofday | 234 | * You need to set that separately with settimeofday |
235 | * or adjtimex. | 235 | * or adjtimex. |
236 | */ | 236 | */ |
237 | return 0; | 237 | return 0; |
238 | } | 238 | } |
239 | 239 | ||
240 | case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */ | 240 | case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */ |
241 | { | 241 | { |
242 | int tcs_val; | 242 | int tcs_val; |
243 | 243 | ||
244 | if (!capable(CAP_SYS_TIME)) | 244 | if (!capable(CAP_SYS_TIME)) |
245 | return -EPERM; | 245 | return -EPERM; |
246 | 246 | ||
247 | if(copy_from_user(&tcs_val, (int*)arg, sizeof(int))) | 247 | if(copy_from_user(&tcs_val, (int*)arg, sizeof(int))) |
248 | return -EFAULT; | 248 | return -EFAULT; |
249 | 249 | ||
250 | lock_kernel(); | 250 | lock_kernel(); |
251 | tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F); | 251 | tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F); |
252 | ds1302_writereg(RTC_TRICKLECHARGER, tcs_val); | 252 | ds1302_writereg(RTC_TRICKLECHARGER, tcs_val); |
253 | unlock_kernel(); | 253 | unlock_kernel(); |
254 | return 0; | 254 | return 0; |
255 | } | 255 | } |
256 | default: | 256 | default: |
257 | return -EINVAL; | 257 | return -EINVAL; |
258 | } | 258 | } |
259 | } | 259 | } |
260 | 260 | ||
261 | int | 261 | int |
262 | get_rtc_status(char *buf) | 262 | get_rtc_status(char *buf) |
263 | { | 263 | { |
264 | char *p; | 264 | char *p; |
265 | struct rtc_time tm; | 265 | struct rtc_time tm; |
266 | 266 | ||
267 | p = buf; | 267 | p = buf; |
268 | 268 | ||
269 | get_rtc_time(&tm); | 269 | get_rtc_time(&tm); |
270 | 270 | ||
271 | /* | 271 | /* |
272 | * There is no way to tell if the luser has the RTC set for local | 272 | * There is no way to tell if the luser has the RTC set for local |
273 | * time or for Universal Standard Time (GMT). Probably local though. | 273 | * time or for Universal Standard Time (GMT). Probably local though. |
274 | */ | 274 | */ |
275 | 275 | ||
276 | p += sprintf(p, | 276 | p += sprintf(p, |
277 | "rtc_time\t: %02d:%02d:%02d\n" | 277 | "rtc_time\t: %02d:%02d:%02d\n" |
278 | "rtc_date\t: %04d-%02d-%02d\n", | 278 | "rtc_date\t: %04d-%02d-%02d\n", |
279 | tm.tm_hour, tm.tm_min, tm.tm_sec, | 279 | tm.tm_hour, tm.tm_min, tm.tm_sec, |
280 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); | 280 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); |
281 | 281 | ||
282 | return p - buf; | 282 | return p - buf; |
283 | } | 283 | } |
284 | 284 | ||
285 | 285 | ||
286 | /* The various file operations we support. */ | 286 | /* The various file operations we support. */ |
287 | 287 | ||
288 | static const struct file_operations rtc_fops = { | 288 | static const struct file_operations rtc_fops = { |
289 | .owner = THIS_MODULE, | 289 | .owner = THIS_MODULE, |
290 | .unlocked_ioctl = rtc_ioctl, | 290 | .unlocked_ioctl = rtc_ioctl, |
291 | }; | 291 | }; |
292 | 292 | ||
293 | /* Probe for the chip by writing something to its RAM and try reading it back. */ | 293 | /* Probe for the chip by writing something to its RAM and try reading it back. */ |
294 | 294 | ||
295 | #define MAGIC_PATTERN 0x42 | 295 | #define MAGIC_PATTERN 0x42 |
296 | 296 | ||
297 | static int __init | 297 | static int __init |
298 | ds1302_probe(void) | 298 | ds1302_probe(void) |
299 | { | 299 | { |
300 | int retval, res, baur; | 300 | int retval, res, baur; |
301 | 301 | ||
302 | baur=(boot_cpu_data.bus_clock/(2*1000*1000)); | 302 | baur=(boot_cpu_data.bus_clock/(2*1000*1000)); |
303 | 303 | ||
304 | printk("%s: Set PLD_RTCBAUR = %d\n", ds1302_name,baur); | 304 | printk("%s: Set PLD_RTCBAUR = %d\n", ds1302_name,baur); |
305 | 305 | ||
306 | outw(0x0000,(unsigned long)PLD_RTCCR); | 306 | outw(0x0000,(unsigned long)PLD_RTCCR); |
307 | outw(0x0000,(unsigned long)PLD_RTCRSTODT); | 307 | outw(0x0000,(unsigned long)PLD_RTCRSTODT); |
308 | outw(baur,(unsigned long)PLD_RTCBAUR); | 308 | outw(baur,(unsigned long)PLD_RTCBAUR); |
309 | 309 | ||
310 | /* Try to talk to timekeeper. */ | 310 | /* Try to talk to timekeeper. */ |
311 | 311 | ||
312 | ds1302_wenable(); | 312 | ds1302_wenable(); |
313 | /* write RAM byte 0 */ | 313 | /* write RAM byte 0 */ |
314 | /* write something magic */ | 314 | /* write something magic */ |
315 | out_byte_rtc(0xc0,MAGIC_PATTERN); | 315 | out_byte_rtc(0xc0,MAGIC_PATTERN); |
316 | 316 | ||
317 | /* read RAM byte 0 */ | 317 | /* read RAM byte 0 */ |
318 | if((res = in_byte_rtc(0xc1)) == MAGIC_PATTERN) { | 318 | if((res = in_byte_rtc(0xc1)) == MAGIC_PATTERN) { |
319 | char buf[100]; | 319 | char buf[100]; |
320 | ds1302_wdisable(); | 320 | ds1302_wdisable(); |
321 | printk("%s: RTC found.\n", ds1302_name); | 321 | printk("%s: RTC found.\n", ds1302_name); |
322 | get_rtc_status(buf); | 322 | get_rtc_status(buf); |
323 | printk(buf); | 323 | printk(buf); |
324 | retval = 1; | 324 | retval = 1; |
325 | } else { | 325 | } else { |
326 | printk("%s: RTC not found.\n", ds1302_name); | 326 | printk("%s: RTC not found.\n", ds1302_name); |
327 | retval = 0; | 327 | retval = 0; |
328 | } | 328 | } |
329 | 329 | ||
330 | return retval; | 330 | return retval; |
331 | } | 331 | } |
332 | 332 | ||
333 | 333 | ||
334 | /* Just probe for the RTC and register the device to handle the ioctl needed. */ | 334 | /* Just probe for the RTC and register the device to handle the ioctl needed. */ |
335 | 335 | ||
336 | int __init | 336 | int __init |
337 | ds1302_init(void) | 337 | ds1302_init(void) |
338 | { | 338 | { |
339 | if (!ds1302_probe()) { | 339 | if (!ds1302_probe()) { |
340 | return -1; | 340 | return -1; |
341 | } | 341 | } |
342 | return 0; | 342 | return 0; |
343 | } | 343 | } |
344 | 344 | ||
345 | static int __init ds1302_register(void) | 345 | static int __init ds1302_register(void) |
346 | { | 346 | { |
347 | ds1302_init(); | 347 | ds1302_init(); |
348 | if (register_chrdev(RTC_MAJOR_NR, ds1302_name, &rtc_fops)) { | 348 | if (register_chrdev(RTC_MAJOR_NR, ds1302_name, &rtc_fops)) { |
349 | printk(KERN_INFO "%s: unable to get major %d for rtc\n", | 349 | printk(KERN_INFO "%s: unable to get major %d for rtc\n", |
350 | ds1302_name, RTC_MAJOR_NR); | 350 | ds1302_name, RTC_MAJOR_NR); |
351 | return -1; | 351 | return -1; |
352 | } | 352 | } |
353 | return 0; | 353 | return 0; |
354 | } | 354 | } |
355 | 355 | ||
356 | module_init(ds1302_register); | 356 | module_init(ds1302_register); |
357 | 357 |
drivers/char/ip27-rtc.c
1 | /* | 1 | /* |
2 | * Driver for the SGS-Thomson M48T35 Timekeeper RAM chip | 2 | * Driver for the SGS-Thomson M48T35 Timekeeper RAM chip |
3 | * | 3 | * |
4 | * Real Time Clock interface for Linux | 4 | * Real Time Clock interface for Linux |
5 | * | 5 | * |
6 | * TODO: Implement periodic interrupts. | 6 | * TODO: Implement periodic interrupts. |
7 | * | 7 | * |
8 | * Copyright (C) 2000 Silicon Graphics, Inc. | 8 | * Copyright (C) 2000 Silicon Graphics, Inc. |
9 | * Written by Ulf Carlsson (ulfc@engr.sgi.com) | 9 | * Written by Ulf Carlsson (ulfc@engr.sgi.com) |
10 | * | 10 | * |
11 | * Based on code written by Paul Gortmaker. | 11 | * Based on code written by Paul Gortmaker. |
12 | * | 12 | * |
13 | * This driver allows use of the real time clock (built into | 13 | * This driver allows use of the real time clock (built into |
14 | * nearly all computers) from user space. It exports the /dev/rtc | 14 | * nearly all computers) from user space. It exports the /dev/rtc |
15 | * interface supporting various ioctl() and also the /proc/rtc | 15 | * interface supporting various ioctl() and also the /proc/rtc |
16 | * pseudo-file for status information. | 16 | * pseudo-file for status information. |
17 | * | 17 | * |
18 | * This program is free software; you can redistribute it and/or | 18 | * This program is free software; you can redistribute it and/or |
19 | * modify it under the terms of the GNU General Public License | 19 | * modify it under the terms of the GNU General Public License |
20 | * as published by the Free Software Foundation; either version | 20 | * as published by the Free Software Foundation; either version |
21 | * 2 of the License, or (at your option) any later version. | 21 | * 2 of the License, or (at your option) any later version. |
22 | * | 22 | * |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #define RTC_VERSION "1.09b" | 25 | #define RTC_VERSION "1.09b" |
26 | 26 | ||
27 | #include <linux/bcd.h> | 27 | #include <linux/bcd.h> |
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
30 | #include <linux/smp_lock.h> | 30 | #include <linux/smp_lock.h> |
31 | #include <linux/types.h> | 31 | #include <linux/types.h> |
32 | #include <linux/miscdevice.h> | 32 | #include <linux/miscdevice.h> |
33 | #include <linux/ioport.h> | 33 | #include <linux/ioport.h> |
34 | #include <linux/fcntl.h> | 34 | #include <linux/fcntl.h> |
35 | #include <linux/rtc.h> | 35 | #include <linux/rtc.h> |
36 | #include <linux/init.h> | 36 | #include <linux/init.h> |
37 | #include <linux/poll.h> | 37 | #include <linux/poll.h> |
38 | #include <linux/proc_fs.h> | 38 | #include <linux/proc_fs.h> |
39 | 39 | ||
40 | #include <asm/m48t35.h> | 40 | #include <asm/m48t35.h> |
41 | #include <asm/sn/ioc3.h> | 41 | #include <asm/sn/ioc3.h> |
42 | #include <asm/io.h> | 42 | #include <asm/io.h> |
43 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
44 | #include <asm/system.h> | 44 | #include <asm/system.h> |
45 | #include <asm/sn/klconfig.h> | 45 | #include <asm/sn/klconfig.h> |
46 | #include <asm/sn/sn0/ip27.h> | 46 | #include <asm/sn/sn0/ip27.h> |
47 | #include <asm/sn/sn0/hub.h> | 47 | #include <asm/sn/sn0/hub.h> |
48 | #include <asm/sn/sn_private.h> | 48 | #include <asm/sn/sn_private.h> |
49 | 49 | ||
50 | static long rtc_ioctl(struct file *filp, unsigned int cmd, | 50 | static long rtc_ioctl(struct file *filp, unsigned int cmd, |
51 | unsigned long arg); | 51 | unsigned long arg); |
52 | 52 | ||
53 | static int rtc_read_proc(char *page, char **start, off_t off, | 53 | static int rtc_read_proc(char *page, char **start, off_t off, |
54 | int count, int *eof, void *data); | 54 | int count, int *eof, void *data); |
55 | 55 | ||
56 | static void get_rtc_time(struct rtc_time *rtc_tm); | 56 | static void get_rtc_time(struct rtc_time *rtc_tm); |
57 | 57 | ||
58 | /* | 58 | /* |
59 | * Bits in rtc_status. (6 bits of room for future expansion) | 59 | * Bits in rtc_status. (6 bits of room for future expansion) |
60 | */ | 60 | */ |
61 | 61 | ||
62 | #define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ | 62 | #define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ |
63 | #define RTC_TIMER_ON 0x02 /* missed irq timer active */ | 63 | #define RTC_TIMER_ON 0x02 /* missed irq timer active */ |
64 | 64 | ||
65 | static unsigned char rtc_status; /* bitmapped status byte. */ | 65 | static unsigned char rtc_status; /* bitmapped status byte. */ |
66 | static unsigned long rtc_freq; /* Current periodic IRQ rate */ | 66 | static unsigned long rtc_freq; /* Current periodic IRQ rate */ |
67 | static struct m48t35_rtc *rtc; | 67 | static struct m48t35_rtc *rtc; |
68 | 68 | ||
69 | /* | 69 | /* |
70 | * If this driver ever becomes modularised, it will be really nice | 70 | * If this driver ever becomes modularised, it will be really nice |
71 | * to make the epoch retain its value across module reload... | 71 | * to make the epoch retain its value across module reload... |
72 | */ | 72 | */ |
73 | 73 | ||
74 | static unsigned long epoch = 1970; /* year corresponding to 0x00 */ | 74 | static unsigned long epoch = 1970; /* year corresponding to 0x00 */ |
75 | 75 | ||
76 | static const unsigned char days_in_mo[] = | 76 | static const unsigned char days_in_mo[] = |
77 | {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | 77 | {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; |
78 | 78 | ||
79 | static long rtc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 79 | static long rtc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
80 | { | 80 | { |
81 | 81 | ||
82 | struct rtc_time wtime; | 82 | struct rtc_time wtime; |
83 | 83 | ||
84 | switch (cmd) { | 84 | switch (cmd) { |
85 | case RTC_RD_TIME: /* Read the time/date from RTC */ | 85 | case RTC_RD_TIME: /* Read the time/date from RTC */ |
86 | { | 86 | { |
87 | get_rtc_time(&wtime); | 87 | get_rtc_time(&wtime); |
88 | break; | 88 | break; |
89 | } | 89 | } |
90 | case RTC_SET_TIME: /* Set the RTC */ | 90 | case RTC_SET_TIME: /* Set the RTC */ |
91 | { | 91 | { |
92 | struct rtc_time rtc_tm; | 92 | struct rtc_time rtc_tm; |
93 | unsigned char mon, day, hrs, min, sec, leap_yr; | 93 | unsigned char mon, day, hrs, min, sec, leap_yr; |
94 | unsigned int yrs; | 94 | unsigned int yrs; |
95 | 95 | ||
96 | if (!capable(CAP_SYS_TIME)) | 96 | if (!capable(CAP_SYS_TIME)) |
97 | return -EACCES; | 97 | return -EACCES; |
98 | 98 | ||
99 | if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, | 99 | if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, |
100 | sizeof(struct rtc_time))) | 100 | sizeof(struct rtc_time))) |
101 | return -EFAULT; | 101 | return -EFAULT; |
102 | 102 | ||
103 | yrs = rtc_tm.tm_year + 1900; | 103 | yrs = rtc_tm.tm_year + 1900; |
104 | mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ | 104 | mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ |
105 | day = rtc_tm.tm_mday; | 105 | day = rtc_tm.tm_mday; |
106 | hrs = rtc_tm.tm_hour; | 106 | hrs = rtc_tm.tm_hour; |
107 | min = rtc_tm.tm_min; | 107 | min = rtc_tm.tm_min; |
108 | sec = rtc_tm.tm_sec; | 108 | sec = rtc_tm.tm_sec; |
109 | 109 | ||
110 | if (yrs < 1970) | 110 | if (yrs < 1970) |
111 | return -EINVAL; | 111 | return -EINVAL; |
112 | 112 | ||
113 | leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); | 113 | leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); |
114 | 114 | ||
115 | if ((mon > 12) || (day == 0)) | 115 | if ((mon > 12) || (day == 0)) |
116 | return -EINVAL; | 116 | return -EINVAL; |
117 | 117 | ||
118 | if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) | 118 | if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) |
119 | return -EINVAL; | 119 | return -EINVAL; |
120 | 120 | ||
121 | if ((hrs >= 24) || (min >= 60) || (sec >= 60)) | 121 | if ((hrs >= 24) || (min >= 60) || (sec >= 60)) |
122 | return -EINVAL; | 122 | return -EINVAL; |
123 | 123 | ||
124 | if ((yrs -= epoch) > 255) /* They are unsigned */ | 124 | if ((yrs -= epoch) > 255) /* They are unsigned */ |
125 | return -EINVAL; | 125 | return -EINVAL; |
126 | 126 | ||
127 | if (yrs > 169) | 127 | if (yrs > 169) |
128 | return -EINVAL; | 128 | return -EINVAL; |
129 | 129 | ||
130 | if (yrs >= 100) | 130 | if (yrs >= 100) |
131 | yrs -= 100; | 131 | yrs -= 100; |
132 | 132 | ||
133 | sec = BIN2BCD(sec); | 133 | sec = bin2bcd(sec); |
134 | min = BIN2BCD(min); | 134 | min = bin2bcd(min); |
135 | hrs = BIN2BCD(hrs); | 135 | hrs = bin2bcd(hrs); |
136 | day = BIN2BCD(day); | 136 | day = bin2bcd(day); |
137 | mon = BIN2BCD(mon); | 137 | mon = bin2bcd(mon); |
138 | yrs = BIN2BCD(yrs); | 138 | yrs = bin2bcd(yrs); |
139 | 139 | ||
140 | spin_lock_irq(&rtc_lock); | 140 | spin_lock_irq(&rtc_lock); |
141 | rtc->control |= M48T35_RTC_SET; | 141 | rtc->control |= M48T35_RTC_SET; |
142 | rtc->year = yrs; | 142 | rtc->year = yrs; |
143 | rtc->month = mon; | 143 | rtc->month = mon; |
144 | rtc->date = day; | 144 | rtc->date = day; |
145 | rtc->hour = hrs; | 145 | rtc->hour = hrs; |
146 | rtc->min = min; | 146 | rtc->min = min; |
147 | rtc->sec = sec; | 147 | rtc->sec = sec; |
148 | rtc->control &= ~M48T35_RTC_SET; | 148 | rtc->control &= ~M48T35_RTC_SET; |
149 | spin_unlock_irq(&rtc_lock); | 149 | spin_unlock_irq(&rtc_lock); |
150 | 150 | ||
151 | return 0; | 151 | return 0; |
152 | } | 152 | } |
153 | default: | 153 | default: |
154 | return -EINVAL; | 154 | return -EINVAL; |
155 | } | 155 | } |
156 | return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; | 156 | return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; |
157 | } | 157 | } |
158 | 158 | ||
159 | /* | 159 | /* |
160 | * We enforce only one user at a time here with the open/close. | 160 | * We enforce only one user at a time here with the open/close. |
161 | * Also clear the previous interrupt data on an open, and clean | 161 | * Also clear the previous interrupt data on an open, and clean |
162 | * up things on a close. | 162 | * up things on a close. |
163 | */ | 163 | */ |
164 | 164 | ||
165 | static int rtc_open(struct inode *inode, struct file *file) | 165 | static int rtc_open(struct inode *inode, struct file *file) |
166 | { | 166 | { |
167 | lock_kernel(); | 167 | lock_kernel(); |
168 | spin_lock_irq(&rtc_lock); | 168 | spin_lock_irq(&rtc_lock); |
169 | 169 | ||
170 | if (rtc_status & RTC_IS_OPEN) { | 170 | if (rtc_status & RTC_IS_OPEN) { |
171 | spin_unlock_irq(&rtc_lock); | 171 | spin_unlock_irq(&rtc_lock); |
172 | unlock_kernel(); | 172 | unlock_kernel(); |
173 | return -EBUSY; | 173 | return -EBUSY; |
174 | } | 174 | } |
175 | 175 | ||
176 | rtc_status |= RTC_IS_OPEN; | 176 | rtc_status |= RTC_IS_OPEN; |
177 | spin_unlock_irq(&rtc_lock); | 177 | spin_unlock_irq(&rtc_lock); |
178 | unlock_kernel(); | 178 | unlock_kernel(); |
179 | 179 | ||
180 | return 0; | 180 | return 0; |
181 | } | 181 | } |
182 | 182 | ||
183 | static int rtc_release(struct inode *inode, struct file *file) | 183 | static int rtc_release(struct inode *inode, struct file *file) |
184 | { | 184 | { |
185 | /* | 185 | /* |
186 | * Turn off all interrupts once the device is no longer | 186 | * Turn off all interrupts once the device is no longer |
187 | * in use, and clear the data. | 187 | * in use, and clear the data. |
188 | */ | 188 | */ |
189 | 189 | ||
190 | spin_lock_irq(&rtc_lock); | 190 | spin_lock_irq(&rtc_lock); |
191 | rtc_status &= ~RTC_IS_OPEN; | 191 | rtc_status &= ~RTC_IS_OPEN; |
192 | spin_unlock_irq(&rtc_lock); | 192 | spin_unlock_irq(&rtc_lock); |
193 | 193 | ||
194 | return 0; | 194 | return 0; |
195 | } | 195 | } |
196 | 196 | ||
197 | /* | 197 | /* |
198 | * The various file operations we support. | 198 | * The various file operations we support. |
199 | */ | 199 | */ |
200 | 200 | ||
201 | static const struct file_operations rtc_fops = { | 201 | static const struct file_operations rtc_fops = { |
202 | .owner = THIS_MODULE, | 202 | .owner = THIS_MODULE, |
203 | .unlocked_ioctl = rtc_ioctl, | 203 | .unlocked_ioctl = rtc_ioctl, |
204 | .open = rtc_open, | 204 | .open = rtc_open, |
205 | .release = rtc_release, | 205 | .release = rtc_release, |
206 | }; | 206 | }; |
207 | 207 | ||
208 | static struct miscdevice rtc_dev= | 208 | static struct miscdevice rtc_dev= |
209 | { | 209 | { |
210 | RTC_MINOR, | 210 | RTC_MINOR, |
211 | "rtc", | 211 | "rtc", |
212 | &rtc_fops | 212 | &rtc_fops |
213 | }; | 213 | }; |
214 | 214 | ||
215 | static int __init rtc_init(void) | 215 | static int __init rtc_init(void) |
216 | { | 216 | { |
217 | rtc = (struct m48t35_rtc *) | 217 | rtc = (struct m48t35_rtc *) |
218 | (KL_CONFIG_CH_CONS_INFO(master_nasid)->memory_base + IOC3_BYTEBUS_DEV0); | 218 | (KL_CONFIG_CH_CONS_INFO(master_nasid)->memory_base + IOC3_BYTEBUS_DEV0); |
219 | 219 | ||
220 | printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION); | 220 | printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION); |
221 | if (misc_register(&rtc_dev)) { | 221 | if (misc_register(&rtc_dev)) { |
222 | printk(KERN_ERR "rtc: cannot register misc device.\n"); | 222 | printk(KERN_ERR "rtc: cannot register misc device.\n"); |
223 | return -ENODEV; | 223 | return -ENODEV; |
224 | } | 224 | } |
225 | if (!create_proc_read_entry("driver/rtc", 0, NULL, rtc_read_proc, NULL)) { | 225 | if (!create_proc_read_entry("driver/rtc", 0, NULL, rtc_read_proc, NULL)) { |
226 | printk(KERN_ERR "rtc: cannot create /proc/rtc.\n"); | 226 | printk(KERN_ERR "rtc: cannot create /proc/rtc.\n"); |
227 | misc_deregister(&rtc_dev); | 227 | misc_deregister(&rtc_dev); |
228 | return -ENOENT; | 228 | return -ENOENT; |
229 | } | 229 | } |
230 | 230 | ||
231 | rtc_freq = 1024; | 231 | rtc_freq = 1024; |
232 | 232 | ||
233 | return 0; | 233 | return 0; |
234 | } | 234 | } |
235 | 235 | ||
236 | static void __exit rtc_exit (void) | 236 | static void __exit rtc_exit (void) |
237 | { | 237 | { |
238 | /* interrupts and timer disabled at this point by rtc_release */ | 238 | /* interrupts and timer disabled at this point by rtc_release */ |
239 | 239 | ||
240 | remove_proc_entry ("rtc", NULL); | 240 | remove_proc_entry ("rtc", NULL); |
241 | misc_deregister(&rtc_dev); | 241 | misc_deregister(&rtc_dev); |
242 | } | 242 | } |
243 | 243 | ||
244 | module_init(rtc_init); | 244 | module_init(rtc_init); |
245 | module_exit(rtc_exit); | 245 | module_exit(rtc_exit); |
246 | 246 | ||
247 | /* | 247 | /* |
248 | * Info exported via "/proc/rtc". | 248 | * Info exported via "/proc/rtc". |
249 | */ | 249 | */ |
250 | 250 | ||
251 | static int rtc_get_status(char *buf) | 251 | static int rtc_get_status(char *buf) |
252 | { | 252 | { |
253 | char *p; | 253 | char *p; |
254 | struct rtc_time tm; | 254 | struct rtc_time tm; |
255 | 255 | ||
256 | /* | 256 | /* |
257 | * Just emulate the standard /proc/rtc | 257 | * Just emulate the standard /proc/rtc |
258 | */ | 258 | */ |
259 | 259 | ||
260 | p = buf; | 260 | p = buf; |
261 | 261 | ||
262 | get_rtc_time(&tm); | 262 | get_rtc_time(&tm); |
263 | 263 | ||
264 | /* | 264 | /* |
265 | * There is no way to tell if the luser has the RTC set for local | 265 | * There is no way to tell if the luser has the RTC set for local |
266 | * time or for Universal Standard Time (GMT). Probably local though. | 266 | * time or for Universal Standard Time (GMT). Probably local though. |
267 | */ | 267 | */ |
268 | p += sprintf(p, | 268 | p += sprintf(p, |
269 | "rtc_time\t: %02d:%02d:%02d\n" | 269 | "rtc_time\t: %02d:%02d:%02d\n" |
270 | "rtc_date\t: %04d-%02d-%02d\n" | 270 | "rtc_date\t: %04d-%02d-%02d\n" |
271 | "rtc_epoch\t: %04lu\n" | 271 | "rtc_epoch\t: %04lu\n" |
272 | "24hr\t\t: yes\n", | 272 | "24hr\t\t: yes\n", |
273 | tm.tm_hour, tm.tm_min, tm.tm_sec, | 273 | tm.tm_hour, tm.tm_min, tm.tm_sec, |
274 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); | 274 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); |
275 | 275 | ||
276 | return p - buf; | 276 | return p - buf; |
277 | } | 277 | } |
278 | 278 | ||
279 | static int rtc_read_proc(char *page, char **start, off_t off, | 279 | static int rtc_read_proc(char *page, char **start, off_t off, |
280 | int count, int *eof, void *data) | 280 | int count, int *eof, void *data) |
281 | { | 281 | { |
282 | int len = rtc_get_status(page); | 282 | int len = rtc_get_status(page); |
283 | if (len <= off+count) *eof = 1; | 283 | if (len <= off+count) *eof = 1; |
284 | *start = page + off; | 284 | *start = page + off; |
285 | len -= off; | 285 | len -= off; |
286 | if (len>count) len = count; | 286 | if (len>count) len = count; |
287 | if (len<0) len = 0; | 287 | if (len<0) len = 0; |
288 | return len; | 288 | return len; |
289 | } | 289 | } |
290 | 290 | ||
291 | static void get_rtc_time(struct rtc_time *rtc_tm) | 291 | static void get_rtc_time(struct rtc_time *rtc_tm) |
292 | { | 292 | { |
293 | /* | 293 | /* |
294 | * Do we need to wait for the last update to finish? | 294 | * Do we need to wait for the last update to finish? |
295 | */ | 295 | */ |
296 | 296 | ||
297 | /* | 297 | /* |
298 | * Only the values that we read from the RTC are set. We leave | 298 | * Only the values that we read from the RTC are set. We leave |
299 | * tm_wday, tm_yday and tm_isdst untouched. Even though the | 299 | * tm_wday, tm_yday and tm_isdst untouched. Even though the |
300 | * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated | 300 | * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated |
301 | * by the RTC when initially set to a non-zero value. | 301 | * by the RTC when initially set to a non-zero value. |
302 | */ | 302 | */ |
303 | spin_lock_irq(&rtc_lock); | 303 | spin_lock_irq(&rtc_lock); |
304 | rtc->control |= M48T35_RTC_READ; | 304 | rtc->control |= M48T35_RTC_READ; |
305 | rtc_tm->tm_sec = rtc->sec; | 305 | rtc_tm->tm_sec = rtc->sec; |
306 | rtc_tm->tm_min = rtc->min; | 306 | rtc_tm->tm_min = rtc->min; |
307 | rtc_tm->tm_hour = rtc->hour; | 307 | rtc_tm->tm_hour = rtc->hour; |
308 | rtc_tm->tm_mday = rtc->date; | 308 | rtc_tm->tm_mday = rtc->date; |
309 | rtc_tm->tm_mon = rtc->month; | 309 | rtc_tm->tm_mon = rtc->month; |
310 | rtc_tm->tm_year = rtc->year; | 310 | rtc_tm->tm_year = rtc->year; |
311 | rtc->control &= ~M48T35_RTC_READ; | 311 | rtc->control &= ~M48T35_RTC_READ; |
312 | spin_unlock_irq(&rtc_lock); | 312 | spin_unlock_irq(&rtc_lock); |
313 | 313 | ||
314 | rtc_tm->tm_sec = BCD2BIN(rtc_tm->tm_sec); | 314 | rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec); |
315 | rtc_tm->tm_min = BCD2BIN(rtc_tm->tm_min); | 315 | rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min); |
316 | rtc_tm->tm_hour = BCD2BIN(rtc_tm->tm_hour); | 316 | rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour); |
317 | rtc_tm->tm_mday = BCD2BIN(rtc_tm->tm_mday); | 317 | rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday); |
318 | rtc_tm->tm_mon = BCD2BIN(rtc_tm->tm_mon); | 318 | rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon); |
319 | rtc_tm->tm_year = BCD2BIN(rtc_tm->tm_year); | 319 | rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year); |
320 | 320 | ||
321 | /* | 321 | /* |
322 | * Account for differences between how the RTC uses the values | 322 | * Account for differences between how the RTC uses the values |
323 | * and how they are defined in a struct rtc_time; | 323 | * and how they are defined in a struct rtc_time; |
324 | */ | 324 | */ |
325 | if ((rtc_tm->tm_year += (epoch - 1900)) <= 69) | 325 | if ((rtc_tm->tm_year += (epoch - 1900)) <= 69) |
326 | rtc_tm->tm_year += 100; | 326 | rtc_tm->tm_year += 100; |
327 | 327 | ||
328 | rtc_tm->tm_mon--; | 328 | rtc_tm->tm_mon--; |
329 | } | 329 | } |
330 | 330 |
drivers/char/rtc.c
1 | /* | 1 | /* |
2 | * Real Time Clock interface for Linux | 2 | * Real Time Clock interface for Linux |
3 | * | 3 | * |
4 | * Copyright (C) 1996 Paul Gortmaker | 4 | * Copyright (C) 1996 Paul Gortmaker |
5 | * | 5 | * |
6 | * This driver allows use of the real time clock (built into | 6 | * This driver allows use of the real time clock (built into |
7 | * nearly all computers) from user space. It exports the /dev/rtc | 7 | * nearly all computers) from user space. It exports the /dev/rtc |
8 | * interface supporting various ioctl() and also the | 8 | * interface supporting various ioctl() and also the |
9 | * /proc/driver/rtc pseudo-file for status information. | 9 | * /proc/driver/rtc pseudo-file for status information. |
10 | * | 10 | * |
11 | * The ioctls can be used to set the interrupt behaviour and | 11 | * The ioctls can be used to set the interrupt behaviour and |
12 | * generation rate from the RTC via IRQ 8. Then the /dev/rtc | 12 | * generation rate from the RTC via IRQ 8. Then the /dev/rtc |
13 | * interface can be used to make use of these timer interrupts, | 13 | * interface can be used to make use of these timer interrupts, |
14 | * be they interval or alarm based. | 14 | * be they interval or alarm based. |
15 | * | 15 | * |
16 | * The /dev/rtc interface will block on reads until an interrupt | 16 | * The /dev/rtc interface will block on reads until an interrupt |
17 | * has been received. If a RTC interrupt has already happened, | 17 | * has been received. If a RTC interrupt has already happened, |
18 | * it will output an unsigned long and then block. The output value | 18 | * it will output an unsigned long and then block. The output value |
19 | * contains the interrupt status in the low byte and the number of | 19 | * contains the interrupt status in the low byte and the number of |
20 | * interrupts since the last read in the remaining high bytes. The | 20 | * interrupts since the last read in the remaining high bytes. The |
21 | * /dev/rtc interface can also be used with the select(2) call. | 21 | * /dev/rtc interface can also be used with the select(2) call. |
22 | * | 22 | * |
23 | * This program is free software; you can redistribute it and/or | 23 | * This program is free software; you can redistribute it and/or |
24 | * modify it under the terms of the GNU General Public License | 24 | * modify it under the terms of the GNU General Public License |
25 | * as published by the Free Software Foundation; either version | 25 | * as published by the Free Software Foundation; either version |
26 | * 2 of the License, or (at your option) any later version. | 26 | * 2 of the License, or (at your option) any later version. |
27 | * | 27 | * |
28 | * Based on other minimal char device drivers, like Alan's | 28 | * Based on other minimal char device drivers, like Alan's |
29 | * watchdog, Ted's random, etc. etc. | 29 | * watchdog, Ted's random, etc. etc. |
30 | * | 30 | * |
31 | * 1.07 Paul Gortmaker. | 31 | * 1.07 Paul Gortmaker. |
32 | * 1.08 Miquel van Smoorenburg: disallow certain things on the | 32 | * 1.08 Miquel van Smoorenburg: disallow certain things on the |
33 | * DEC Alpha as the CMOS clock is also used for other things. | 33 | * DEC Alpha as the CMOS clock is also used for other things. |
34 | * 1.09 Nikita Schmidt: epoch support and some Alpha cleanup. | 34 | * 1.09 Nikita Schmidt: epoch support and some Alpha cleanup. |
35 | * 1.09a Pete Zaitcev: Sun SPARC | 35 | * 1.09a Pete Zaitcev: Sun SPARC |
36 | * 1.09b Jeff Garzik: Modularize, init cleanup | 36 | * 1.09b Jeff Garzik: Modularize, init cleanup |
37 | * 1.09c Jeff Garzik: SMP cleanup | 37 | * 1.09c Jeff Garzik: SMP cleanup |
38 | * 1.10 Paul Barton-Davis: add support for async I/O | 38 | * 1.10 Paul Barton-Davis: add support for async I/O |
39 | * 1.10a Andrea Arcangeli: Alpha updates | 39 | * 1.10a Andrea Arcangeli: Alpha updates |
40 | * 1.10b Andrew Morton: SMP lock fix | 40 | * 1.10b Andrew Morton: SMP lock fix |
41 | * 1.10c Cesar Barros: SMP locking fixes and cleanup | 41 | * 1.10c Cesar Barros: SMP locking fixes and cleanup |
42 | * 1.10d Paul Gortmaker: delete paranoia check in rtc_exit | 42 | * 1.10d Paul Gortmaker: delete paranoia check in rtc_exit |
43 | * 1.10e Maciej W. Rozycki: Handle DECstation's year weirdness. | 43 | * 1.10e Maciej W. Rozycki: Handle DECstation's year weirdness. |
44 | * 1.11 Takashi Iwai: Kernel access functions | 44 | * 1.11 Takashi Iwai: Kernel access functions |
45 | * rtc_register/rtc_unregister/rtc_control | 45 | * rtc_register/rtc_unregister/rtc_control |
46 | * 1.11a Daniele Bellucci: Audit create_proc_read_entry in rtc_init | 46 | * 1.11a Daniele Bellucci: Audit create_proc_read_entry in rtc_init |
47 | * 1.12 Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer | 47 | * 1.12 Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer |
48 | * CONFIG_HPET_EMULATE_RTC | 48 | * CONFIG_HPET_EMULATE_RTC |
49 | * 1.12a Maciej W. Rozycki: Handle memory-mapped chips properly. | 49 | * 1.12a Maciej W. Rozycki: Handle memory-mapped chips properly. |
50 | * 1.12ac Alan Cox: Allow read access to the day of week register | 50 | * 1.12ac Alan Cox: Allow read access to the day of week register |
51 | */ | 51 | */ |
52 | 52 | ||
53 | #define RTC_VERSION "1.12ac" | 53 | #define RTC_VERSION "1.12ac" |
54 | 54 | ||
55 | /* | 55 | /* |
56 | * Note that *all* calls to CMOS_READ and CMOS_WRITE are done with | 56 | * Note that *all* calls to CMOS_READ and CMOS_WRITE are done with |
57 | * interrupts disabled. Due to the index-port/data-port (0x70/0x71) | 57 | * interrupts disabled. Due to the index-port/data-port (0x70/0x71) |
58 | * design of the RTC, we don't want two different things trying to | 58 | * design of the RTC, we don't want two different things trying to |
59 | * get to it at once. (e.g. the periodic 11 min sync from time.c vs. | 59 | * get to it at once. (e.g. the periodic 11 min sync from time.c vs. |
60 | * this driver.) | 60 | * this driver.) |
61 | */ | 61 | */ |
62 | 62 | ||
63 | #include <linux/interrupt.h> | 63 | #include <linux/interrupt.h> |
64 | #include <linux/module.h> | 64 | #include <linux/module.h> |
65 | #include <linux/kernel.h> | 65 | #include <linux/kernel.h> |
66 | #include <linux/types.h> | 66 | #include <linux/types.h> |
67 | #include <linux/miscdevice.h> | 67 | #include <linux/miscdevice.h> |
68 | #include <linux/ioport.h> | 68 | #include <linux/ioport.h> |
69 | #include <linux/fcntl.h> | 69 | #include <linux/fcntl.h> |
70 | #include <linux/mc146818rtc.h> | 70 | #include <linux/mc146818rtc.h> |
71 | #include <linux/init.h> | 71 | #include <linux/init.h> |
72 | #include <linux/poll.h> | 72 | #include <linux/poll.h> |
73 | #include <linux/proc_fs.h> | 73 | #include <linux/proc_fs.h> |
74 | #include <linux/seq_file.h> | 74 | #include <linux/seq_file.h> |
75 | #include <linux/spinlock.h> | 75 | #include <linux/spinlock.h> |
76 | #include <linux/smp_lock.h> | 76 | #include <linux/smp_lock.h> |
77 | #include <linux/sysctl.h> | 77 | #include <linux/sysctl.h> |
78 | #include <linux/wait.h> | 78 | #include <linux/wait.h> |
79 | #include <linux/bcd.h> | 79 | #include <linux/bcd.h> |
80 | #include <linux/delay.h> | 80 | #include <linux/delay.h> |
81 | #include <linux/uaccess.h> | 81 | #include <linux/uaccess.h> |
82 | 82 | ||
83 | #include <asm/current.h> | 83 | #include <asm/current.h> |
84 | #include <asm/system.h> | 84 | #include <asm/system.h> |
85 | 85 | ||
86 | #ifdef CONFIG_X86 | 86 | #ifdef CONFIG_X86 |
87 | #include <asm/hpet.h> | 87 | #include <asm/hpet.h> |
88 | #endif | 88 | #endif |
89 | 89 | ||
90 | #ifdef CONFIG_SPARC32 | 90 | #ifdef CONFIG_SPARC32 |
91 | #include <linux/of.h> | 91 | #include <linux/of.h> |
92 | #include <linux/of_device.h> | 92 | #include <linux/of_device.h> |
93 | #include <asm/io.h> | 93 | #include <asm/io.h> |
94 | 94 | ||
95 | static unsigned long rtc_port; | 95 | static unsigned long rtc_port; |
96 | static int rtc_irq; | 96 | static int rtc_irq; |
97 | #endif | 97 | #endif |
98 | 98 | ||
99 | #ifdef CONFIG_HPET_EMULATE_RTC | 99 | #ifdef CONFIG_HPET_EMULATE_RTC |
100 | #undef RTC_IRQ | 100 | #undef RTC_IRQ |
101 | #endif | 101 | #endif |
102 | 102 | ||
103 | #ifdef RTC_IRQ | 103 | #ifdef RTC_IRQ |
104 | static int rtc_has_irq = 1; | 104 | static int rtc_has_irq = 1; |
105 | #endif | 105 | #endif |
106 | 106 | ||
107 | #ifndef CONFIG_HPET_EMULATE_RTC | 107 | #ifndef CONFIG_HPET_EMULATE_RTC |
108 | #define is_hpet_enabled() 0 | 108 | #define is_hpet_enabled() 0 |
109 | #define hpet_set_alarm_time(hrs, min, sec) 0 | 109 | #define hpet_set_alarm_time(hrs, min, sec) 0 |
110 | #define hpet_set_periodic_freq(arg) 0 | 110 | #define hpet_set_periodic_freq(arg) 0 |
111 | #define hpet_mask_rtc_irq_bit(arg) 0 | 111 | #define hpet_mask_rtc_irq_bit(arg) 0 |
112 | #define hpet_set_rtc_irq_bit(arg) 0 | 112 | #define hpet_set_rtc_irq_bit(arg) 0 |
113 | #define hpet_rtc_timer_init() do { } while (0) | 113 | #define hpet_rtc_timer_init() do { } while (0) |
114 | #define hpet_rtc_dropped_irq() 0 | 114 | #define hpet_rtc_dropped_irq() 0 |
115 | #define hpet_register_irq_handler(h) ({ 0; }) | 115 | #define hpet_register_irq_handler(h) ({ 0; }) |
116 | #define hpet_unregister_irq_handler(h) ({ 0; }) | 116 | #define hpet_unregister_irq_handler(h) ({ 0; }) |
117 | #ifdef RTC_IRQ | 117 | #ifdef RTC_IRQ |
118 | static irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) | 118 | static irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) |
119 | { | 119 | { |
120 | return 0; | 120 | return 0; |
121 | } | 121 | } |
122 | #endif | 122 | #endif |
123 | #endif | 123 | #endif |
124 | 124 | ||
125 | /* | 125 | /* |
126 | * We sponge a minor off of the misc major. No need slurping | 126 | * We sponge a minor off of the misc major. No need slurping |
127 | * up another valuable major dev number for this. If you add | 127 | * up another valuable major dev number for this. If you add |
128 | * an ioctl, make sure you don't conflict with SPARC's RTC | 128 | * an ioctl, make sure you don't conflict with SPARC's RTC |
129 | * ioctls. | 129 | * ioctls. |
130 | */ | 130 | */ |
131 | 131 | ||
132 | static struct fasync_struct *rtc_async_queue; | 132 | static struct fasync_struct *rtc_async_queue; |
133 | 133 | ||
134 | static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); | 134 | static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); |
135 | 135 | ||
136 | #ifdef RTC_IRQ | 136 | #ifdef RTC_IRQ |
137 | static void rtc_dropped_irq(unsigned long data); | 137 | static void rtc_dropped_irq(unsigned long data); |
138 | 138 | ||
139 | static DEFINE_TIMER(rtc_irq_timer, rtc_dropped_irq, 0, 0); | 139 | static DEFINE_TIMER(rtc_irq_timer, rtc_dropped_irq, 0, 0); |
140 | #endif | 140 | #endif |
141 | 141 | ||
142 | static ssize_t rtc_read(struct file *file, char __user *buf, | 142 | static ssize_t rtc_read(struct file *file, char __user *buf, |
143 | size_t count, loff_t *ppos); | 143 | size_t count, loff_t *ppos); |
144 | 144 | ||
145 | static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg); | 145 | static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg); |
146 | static void rtc_get_rtc_time(struct rtc_time *rtc_tm); | 146 | static void rtc_get_rtc_time(struct rtc_time *rtc_tm); |
147 | 147 | ||
148 | #ifdef RTC_IRQ | 148 | #ifdef RTC_IRQ |
149 | static unsigned int rtc_poll(struct file *file, poll_table *wait); | 149 | static unsigned int rtc_poll(struct file *file, poll_table *wait); |
150 | #endif | 150 | #endif |
151 | 151 | ||
152 | static void get_rtc_alm_time(struct rtc_time *alm_tm); | 152 | static void get_rtc_alm_time(struct rtc_time *alm_tm); |
153 | #ifdef RTC_IRQ | 153 | #ifdef RTC_IRQ |
154 | static void set_rtc_irq_bit_locked(unsigned char bit); | 154 | static void set_rtc_irq_bit_locked(unsigned char bit); |
155 | static void mask_rtc_irq_bit_locked(unsigned char bit); | 155 | static void mask_rtc_irq_bit_locked(unsigned char bit); |
156 | 156 | ||
157 | static inline void set_rtc_irq_bit(unsigned char bit) | 157 | static inline void set_rtc_irq_bit(unsigned char bit) |
158 | { | 158 | { |
159 | spin_lock_irq(&rtc_lock); | 159 | spin_lock_irq(&rtc_lock); |
160 | set_rtc_irq_bit_locked(bit); | 160 | set_rtc_irq_bit_locked(bit); |
161 | spin_unlock_irq(&rtc_lock); | 161 | spin_unlock_irq(&rtc_lock); |
162 | } | 162 | } |
163 | 163 | ||
164 | static void mask_rtc_irq_bit(unsigned char bit) | 164 | static void mask_rtc_irq_bit(unsigned char bit) |
165 | { | 165 | { |
166 | spin_lock_irq(&rtc_lock); | 166 | spin_lock_irq(&rtc_lock); |
167 | mask_rtc_irq_bit_locked(bit); | 167 | mask_rtc_irq_bit_locked(bit); |
168 | spin_unlock_irq(&rtc_lock); | 168 | spin_unlock_irq(&rtc_lock); |
169 | } | 169 | } |
170 | #endif | 170 | #endif |
171 | 171 | ||
172 | #ifdef CONFIG_PROC_FS | 172 | #ifdef CONFIG_PROC_FS |
173 | static int rtc_proc_open(struct inode *inode, struct file *file); | 173 | static int rtc_proc_open(struct inode *inode, struct file *file); |
174 | #endif | 174 | #endif |
175 | 175 | ||
176 | /* | 176 | /* |
177 | * Bits in rtc_status. (6 bits of room for future expansion) | 177 | * Bits in rtc_status. (6 bits of room for future expansion) |
178 | */ | 178 | */ |
179 | 179 | ||
180 | #define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ | 180 | #define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ |
181 | #define RTC_TIMER_ON 0x02 /* missed irq timer active */ | 181 | #define RTC_TIMER_ON 0x02 /* missed irq timer active */ |
182 | 182 | ||
183 | /* | 183 | /* |
184 | * rtc_status is never changed by rtc_interrupt, and ioctl/open/close is | 184 | * rtc_status is never changed by rtc_interrupt, and ioctl/open/close is |
185 | * protected by the big kernel lock. However, ioctl can still disable the timer | 185 | * protected by the big kernel lock. However, ioctl can still disable the timer |
186 | * in rtc_status and then with del_timer after the interrupt has read | 186 | * in rtc_status and then with del_timer after the interrupt has read |
187 | * rtc_status but before mod_timer is called, which would then reenable the | 187 | * rtc_status but before mod_timer is called, which would then reenable the |
188 | * timer (but you would need to have an awful timing before you'd trip on it) | 188 | * timer (but you would need to have an awful timing before you'd trip on it) |
189 | */ | 189 | */ |
190 | static unsigned long rtc_status; /* bitmapped status byte. */ | 190 | static unsigned long rtc_status; /* bitmapped status byte. */ |
191 | static unsigned long rtc_freq; /* Current periodic IRQ rate */ | 191 | static unsigned long rtc_freq; /* Current periodic IRQ rate */ |
192 | static unsigned long rtc_irq_data; /* our output to the world */ | 192 | static unsigned long rtc_irq_data; /* our output to the world */ |
193 | static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */ | 193 | static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */ |
194 | 194 | ||
195 | #ifdef RTC_IRQ | 195 | #ifdef RTC_IRQ |
196 | /* | 196 | /* |
197 | * rtc_task_lock nests inside rtc_lock. | 197 | * rtc_task_lock nests inside rtc_lock. |
198 | */ | 198 | */ |
199 | static DEFINE_SPINLOCK(rtc_task_lock); | 199 | static DEFINE_SPINLOCK(rtc_task_lock); |
200 | static rtc_task_t *rtc_callback; | 200 | static rtc_task_t *rtc_callback; |
201 | #endif | 201 | #endif |
202 | 202 | ||
203 | /* | 203 | /* |
204 | * If this driver ever becomes modularised, it will be really nice | 204 | * If this driver ever becomes modularised, it will be really nice |
205 | * to make the epoch retain its value across module reload... | 205 | * to make the epoch retain its value across module reload... |
206 | */ | 206 | */ |
207 | 207 | ||
208 | static unsigned long epoch = 1900; /* year corresponding to 0x00 */ | 208 | static unsigned long epoch = 1900; /* year corresponding to 0x00 */ |
209 | 209 | ||
210 | static const unsigned char days_in_mo[] = | 210 | static const unsigned char days_in_mo[] = |
211 | {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | 211 | {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; |
212 | 212 | ||
213 | /* | 213 | /* |
214 | * Returns true if a clock update is in progress | 214 | * Returns true if a clock update is in progress |
215 | */ | 215 | */ |
216 | static inline unsigned char rtc_is_updating(void) | 216 | static inline unsigned char rtc_is_updating(void) |
217 | { | 217 | { |
218 | unsigned long flags; | 218 | unsigned long flags; |
219 | unsigned char uip; | 219 | unsigned char uip; |
220 | 220 | ||
221 | spin_lock_irqsave(&rtc_lock, flags); | 221 | spin_lock_irqsave(&rtc_lock, flags); |
222 | uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); | 222 | uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); |
223 | spin_unlock_irqrestore(&rtc_lock, flags); | 223 | spin_unlock_irqrestore(&rtc_lock, flags); |
224 | return uip; | 224 | return uip; |
225 | } | 225 | } |
226 | 226 | ||
227 | #ifdef RTC_IRQ | 227 | #ifdef RTC_IRQ |
228 | /* | 228 | /* |
229 | * A very tiny interrupt handler. It runs with IRQF_DISABLED set, | 229 | * A very tiny interrupt handler. It runs with IRQF_DISABLED set, |
230 | * but there is possibility of conflicting with the set_rtc_mmss() | 230 | * but there is possibility of conflicting with the set_rtc_mmss() |
231 | * call (the rtc irq and the timer irq can easily run at the same | 231 | * call (the rtc irq and the timer irq can easily run at the same |
232 | * time in two different CPUs). So we need to serialize | 232 | * time in two different CPUs). So we need to serialize |
233 | * accesses to the chip with the rtc_lock spinlock that each | 233 | * accesses to the chip with the rtc_lock spinlock that each |
234 | * architecture should implement in the timer code. | 234 | * architecture should implement in the timer code. |
235 | * (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.) | 235 | * (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.) |
236 | */ | 236 | */ |
237 | 237 | ||
238 | static irqreturn_t rtc_interrupt(int irq, void *dev_id) | 238 | static irqreturn_t rtc_interrupt(int irq, void *dev_id) |
239 | { | 239 | { |
240 | /* | 240 | /* |
241 | * Can be an alarm interrupt, update complete interrupt, | 241 | * Can be an alarm interrupt, update complete interrupt, |
242 | * or a periodic interrupt. We store the status in the | 242 | * or a periodic interrupt. We store the status in the |
243 | * low byte and the number of interrupts received since | 243 | * low byte and the number of interrupts received since |
244 | * the last read in the remainder of rtc_irq_data. | 244 | * the last read in the remainder of rtc_irq_data. |
245 | */ | 245 | */ |
246 | 246 | ||
247 | spin_lock(&rtc_lock); | 247 | spin_lock(&rtc_lock); |
248 | rtc_irq_data += 0x100; | 248 | rtc_irq_data += 0x100; |
249 | rtc_irq_data &= ~0xff; | 249 | rtc_irq_data &= ~0xff; |
250 | if (is_hpet_enabled()) { | 250 | if (is_hpet_enabled()) { |
251 | /* | 251 | /* |
252 | * In this case it is HPET RTC interrupt handler | 252 | * In this case it is HPET RTC interrupt handler |
253 | * calling us, with the interrupt information | 253 | * calling us, with the interrupt information |
254 | * passed as arg1, instead of irq. | 254 | * passed as arg1, instead of irq. |
255 | */ | 255 | */ |
256 | rtc_irq_data |= (unsigned long)irq & 0xF0; | 256 | rtc_irq_data |= (unsigned long)irq & 0xF0; |
257 | } else { | 257 | } else { |
258 | rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); | 258 | rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); |
259 | } | 259 | } |
260 | 260 | ||
261 | if (rtc_status & RTC_TIMER_ON) | 261 | if (rtc_status & RTC_TIMER_ON) |
262 | mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); | 262 | mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); |
263 | 263 | ||
264 | spin_unlock(&rtc_lock); | 264 | spin_unlock(&rtc_lock); |
265 | 265 | ||
266 | /* Now do the rest of the actions */ | 266 | /* Now do the rest of the actions */ |
267 | spin_lock(&rtc_task_lock); | 267 | spin_lock(&rtc_task_lock); |
268 | if (rtc_callback) | 268 | if (rtc_callback) |
269 | rtc_callback->func(rtc_callback->private_data); | 269 | rtc_callback->func(rtc_callback->private_data); |
270 | spin_unlock(&rtc_task_lock); | 270 | spin_unlock(&rtc_task_lock); |
271 | wake_up_interruptible(&rtc_wait); | 271 | wake_up_interruptible(&rtc_wait); |
272 | 272 | ||
273 | kill_fasync(&rtc_async_queue, SIGIO, POLL_IN); | 273 | kill_fasync(&rtc_async_queue, SIGIO, POLL_IN); |
274 | 274 | ||
275 | return IRQ_HANDLED; | 275 | return IRQ_HANDLED; |
276 | } | 276 | } |
277 | #endif | 277 | #endif |
278 | 278 | ||
279 | /* | 279 | /* |
280 | * sysctl-tuning infrastructure. | 280 | * sysctl-tuning infrastructure. |
281 | */ | 281 | */ |
282 | static ctl_table rtc_table[] = { | 282 | static ctl_table rtc_table[] = { |
283 | { | 283 | { |
284 | .ctl_name = CTL_UNNUMBERED, | 284 | .ctl_name = CTL_UNNUMBERED, |
285 | .procname = "max-user-freq", | 285 | .procname = "max-user-freq", |
286 | .data = &rtc_max_user_freq, | 286 | .data = &rtc_max_user_freq, |
287 | .maxlen = sizeof(int), | 287 | .maxlen = sizeof(int), |
288 | .mode = 0644, | 288 | .mode = 0644, |
289 | .proc_handler = &proc_dointvec, | 289 | .proc_handler = &proc_dointvec, |
290 | }, | 290 | }, |
291 | { .ctl_name = 0 } | 291 | { .ctl_name = 0 } |
292 | }; | 292 | }; |
293 | 293 | ||
294 | static ctl_table rtc_root[] = { | 294 | static ctl_table rtc_root[] = { |
295 | { | 295 | { |
296 | .ctl_name = CTL_UNNUMBERED, | 296 | .ctl_name = CTL_UNNUMBERED, |
297 | .procname = "rtc", | 297 | .procname = "rtc", |
298 | .mode = 0555, | 298 | .mode = 0555, |
299 | .child = rtc_table, | 299 | .child = rtc_table, |
300 | }, | 300 | }, |
301 | { .ctl_name = 0 } | 301 | { .ctl_name = 0 } |
302 | }; | 302 | }; |
303 | 303 | ||
304 | static ctl_table dev_root[] = { | 304 | static ctl_table dev_root[] = { |
305 | { | 305 | { |
306 | .ctl_name = CTL_DEV, | 306 | .ctl_name = CTL_DEV, |
307 | .procname = "dev", | 307 | .procname = "dev", |
308 | .mode = 0555, | 308 | .mode = 0555, |
309 | .child = rtc_root, | 309 | .child = rtc_root, |
310 | }, | 310 | }, |
311 | { .ctl_name = 0 } | 311 | { .ctl_name = 0 } |
312 | }; | 312 | }; |
313 | 313 | ||
314 | static struct ctl_table_header *sysctl_header; | 314 | static struct ctl_table_header *sysctl_header; |
315 | 315 | ||
316 | static int __init init_sysctl(void) | 316 | static int __init init_sysctl(void) |
317 | { | 317 | { |
318 | sysctl_header = register_sysctl_table(dev_root); | 318 | sysctl_header = register_sysctl_table(dev_root); |
319 | return 0; | 319 | return 0; |
320 | } | 320 | } |
321 | 321 | ||
322 | static void __exit cleanup_sysctl(void) | 322 | static void __exit cleanup_sysctl(void) |
323 | { | 323 | { |
324 | unregister_sysctl_table(sysctl_header); | 324 | unregister_sysctl_table(sysctl_header); |
325 | } | 325 | } |
326 | 326 | ||
327 | /* | 327 | /* |
328 | * Now all the various file operations that we export. | 328 | * Now all the various file operations that we export. |
329 | */ | 329 | */ |
330 | 330 | ||
331 | static ssize_t rtc_read(struct file *file, char __user *buf, | 331 | static ssize_t rtc_read(struct file *file, char __user *buf, |
332 | size_t count, loff_t *ppos) | 332 | size_t count, loff_t *ppos) |
333 | { | 333 | { |
334 | #ifndef RTC_IRQ | 334 | #ifndef RTC_IRQ |
335 | return -EIO; | 335 | return -EIO; |
336 | #else | 336 | #else |
337 | DECLARE_WAITQUEUE(wait, current); | 337 | DECLARE_WAITQUEUE(wait, current); |
338 | unsigned long data; | 338 | unsigned long data; |
339 | ssize_t retval; | 339 | ssize_t retval; |
340 | 340 | ||
341 | if (rtc_has_irq == 0) | 341 | if (rtc_has_irq == 0) |
342 | return -EIO; | 342 | return -EIO; |
343 | 343 | ||
344 | /* | 344 | /* |
345 | * Historically this function used to assume that sizeof(unsigned long) | 345 | * Historically this function used to assume that sizeof(unsigned long) |
346 | * is the same in userspace and kernelspace. This lead to problems | 346 | * is the same in userspace and kernelspace. This lead to problems |
347 | * for configurations with multiple ABIs such a the MIPS o32 and 64 | 347 | * for configurations with multiple ABIs such a the MIPS o32 and 64 |
348 | * ABIs supported on the same kernel. So now we support read of both | 348 | * ABIs supported on the same kernel. So now we support read of both |
349 | * 4 and 8 bytes and assume that's the sizeof(unsigned long) in the | 349 | * 4 and 8 bytes and assume that's the sizeof(unsigned long) in the |
350 | * userspace ABI. | 350 | * userspace ABI. |
351 | */ | 351 | */ |
352 | if (count != sizeof(unsigned int) && count != sizeof(unsigned long)) | 352 | if (count != sizeof(unsigned int) && count != sizeof(unsigned long)) |
353 | return -EINVAL; | 353 | return -EINVAL; |
354 | 354 | ||
355 | add_wait_queue(&rtc_wait, &wait); | 355 | add_wait_queue(&rtc_wait, &wait); |
356 | 356 | ||
357 | do { | 357 | do { |
358 | /* First make it right. Then make it fast. Putting this whole | 358 | /* First make it right. Then make it fast. Putting this whole |
359 | * block within the parentheses of a while would be too | 359 | * block within the parentheses of a while would be too |
360 | * confusing. And no, xchg() is not the answer. */ | 360 | * confusing. And no, xchg() is not the answer. */ |
361 | 361 | ||
362 | __set_current_state(TASK_INTERRUPTIBLE); | 362 | __set_current_state(TASK_INTERRUPTIBLE); |
363 | 363 | ||
364 | spin_lock_irq(&rtc_lock); | 364 | spin_lock_irq(&rtc_lock); |
365 | data = rtc_irq_data; | 365 | data = rtc_irq_data; |
366 | rtc_irq_data = 0; | 366 | rtc_irq_data = 0; |
367 | spin_unlock_irq(&rtc_lock); | 367 | spin_unlock_irq(&rtc_lock); |
368 | 368 | ||
369 | if (data != 0) | 369 | if (data != 0) |
370 | break; | 370 | break; |
371 | 371 | ||
372 | if (file->f_flags & O_NONBLOCK) { | 372 | if (file->f_flags & O_NONBLOCK) { |
373 | retval = -EAGAIN; | 373 | retval = -EAGAIN; |
374 | goto out; | 374 | goto out; |
375 | } | 375 | } |
376 | if (signal_pending(current)) { | 376 | if (signal_pending(current)) { |
377 | retval = -ERESTARTSYS; | 377 | retval = -ERESTARTSYS; |
378 | goto out; | 378 | goto out; |
379 | } | 379 | } |
380 | schedule(); | 380 | schedule(); |
381 | } while (1); | 381 | } while (1); |
382 | 382 | ||
383 | if (count == sizeof(unsigned int)) { | 383 | if (count == sizeof(unsigned int)) { |
384 | retval = put_user(data, | 384 | retval = put_user(data, |
385 | (unsigned int __user *)buf) ?: sizeof(int); | 385 | (unsigned int __user *)buf) ?: sizeof(int); |
386 | } else { | 386 | } else { |
387 | retval = put_user(data, | 387 | retval = put_user(data, |
388 | (unsigned long __user *)buf) ?: sizeof(long); | 388 | (unsigned long __user *)buf) ?: sizeof(long); |
389 | } | 389 | } |
390 | if (!retval) | 390 | if (!retval) |
391 | retval = count; | 391 | retval = count; |
392 | out: | 392 | out: |
393 | __set_current_state(TASK_RUNNING); | 393 | __set_current_state(TASK_RUNNING); |
394 | remove_wait_queue(&rtc_wait, &wait); | 394 | remove_wait_queue(&rtc_wait, &wait); |
395 | 395 | ||
396 | return retval; | 396 | return retval; |
397 | #endif | 397 | #endif |
398 | } | 398 | } |
399 | 399 | ||
400 | static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) | 400 | static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) |
401 | { | 401 | { |
402 | struct rtc_time wtime; | 402 | struct rtc_time wtime; |
403 | 403 | ||
404 | #ifdef RTC_IRQ | 404 | #ifdef RTC_IRQ |
405 | if (rtc_has_irq == 0) { | 405 | if (rtc_has_irq == 0) { |
406 | switch (cmd) { | 406 | switch (cmd) { |
407 | case RTC_AIE_OFF: | 407 | case RTC_AIE_OFF: |
408 | case RTC_AIE_ON: | 408 | case RTC_AIE_ON: |
409 | case RTC_PIE_OFF: | 409 | case RTC_PIE_OFF: |
410 | case RTC_PIE_ON: | 410 | case RTC_PIE_ON: |
411 | case RTC_UIE_OFF: | 411 | case RTC_UIE_OFF: |
412 | case RTC_UIE_ON: | 412 | case RTC_UIE_ON: |
413 | case RTC_IRQP_READ: | 413 | case RTC_IRQP_READ: |
414 | case RTC_IRQP_SET: | 414 | case RTC_IRQP_SET: |
415 | return -EINVAL; | 415 | return -EINVAL; |
416 | }; | 416 | }; |
417 | } | 417 | } |
418 | #endif | 418 | #endif |
419 | 419 | ||
420 | switch (cmd) { | 420 | switch (cmd) { |
421 | #ifdef RTC_IRQ | 421 | #ifdef RTC_IRQ |
422 | case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ | 422 | case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ |
423 | { | 423 | { |
424 | mask_rtc_irq_bit(RTC_AIE); | 424 | mask_rtc_irq_bit(RTC_AIE); |
425 | return 0; | 425 | return 0; |
426 | } | 426 | } |
427 | case RTC_AIE_ON: /* Allow alarm interrupts. */ | 427 | case RTC_AIE_ON: /* Allow alarm interrupts. */ |
428 | { | 428 | { |
429 | set_rtc_irq_bit(RTC_AIE); | 429 | set_rtc_irq_bit(RTC_AIE); |
430 | return 0; | 430 | return 0; |
431 | } | 431 | } |
432 | case RTC_PIE_OFF: /* Mask periodic int. enab. bit */ | 432 | case RTC_PIE_OFF: /* Mask periodic int. enab. bit */ |
433 | { | 433 | { |
434 | /* can be called from isr via rtc_control() */ | 434 | /* can be called from isr via rtc_control() */ |
435 | unsigned long flags; | 435 | unsigned long flags; |
436 | 436 | ||
437 | spin_lock_irqsave(&rtc_lock, flags); | 437 | spin_lock_irqsave(&rtc_lock, flags); |
438 | mask_rtc_irq_bit_locked(RTC_PIE); | 438 | mask_rtc_irq_bit_locked(RTC_PIE); |
439 | if (rtc_status & RTC_TIMER_ON) { | 439 | if (rtc_status & RTC_TIMER_ON) { |
440 | rtc_status &= ~RTC_TIMER_ON; | 440 | rtc_status &= ~RTC_TIMER_ON; |
441 | del_timer(&rtc_irq_timer); | 441 | del_timer(&rtc_irq_timer); |
442 | } | 442 | } |
443 | spin_unlock_irqrestore(&rtc_lock, flags); | 443 | spin_unlock_irqrestore(&rtc_lock, flags); |
444 | 444 | ||
445 | return 0; | 445 | return 0; |
446 | } | 446 | } |
447 | case RTC_PIE_ON: /* Allow periodic ints */ | 447 | case RTC_PIE_ON: /* Allow periodic ints */ |
448 | { | 448 | { |
449 | /* can be called from isr via rtc_control() */ | 449 | /* can be called from isr via rtc_control() */ |
450 | unsigned long flags; | 450 | unsigned long flags; |
451 | 451 | ||
452 | /* | 452 | /* |
453 | * We don't really want Joe User enabling more | 453 | * We don't really want Joe User enabling more |
454 | * than 64Hz of interrupts on a multi-user machine. | 454 | * than 64Hz of interrupts on a multi-user machine. |
455 | */ | 455 | */ |
456 | if (!kernel && (rtc_freq > rtc_max_user_freq) && | 456 | if (!kernel && (rtc_freq > rtc_max_user_freq) && |
457 | (!capable(CAP_SYS_RESOURCE))) | 457 | (!capable(CAP_SYS_RESOURCE))) |
458 | return -EACCES; | 458 | return -EACCES; |
459 | 459 | ||
460 | spin_lock_irqsave(&rtc_lock, flags); | 460 | spin_lock_irqsave(&rtc_lock, flags); |
461 | if (!(rtc_status & RTC_TIMER_ON)) { | 461 | if (!(rtc_status & RTC_TIMER_ON)) { |
462 | mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + | 462 | mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + |
463 | 2*HZ/100); | 463 | 2*HZ/100); |
464 | rtc_status |= RTC_TIMER_ON; | 464 | rtc_status |= RTC_TIMER_ON; |
465 | } | 465 | } |
466 | set_rtc_irq_bit_locked(RTC_PIE); | 466 | set_rtc_irq_bit_locked(RTC_PIE); |
467 | spin_unlock_irqrestore(&rtc_lock, flags); | 467 | spin_unlock_irqrestore(&rtc_lock, flags); |
468 | 468 | ||
469 | return 0; | 469 | return 0; |
470 | } | 470 | } |
471 | case RTC_UIE_OFF: /* Mask ints from RTC updates. */ | 471 | case RTC_UIE_OFF: /* Mask ints from RTC updates. */ |
472 | { | 472 | { |
473 | mask_rtc_irq_bit(RTC_UIE); | 473 | mask_rtc_irq_bit(RTC_UIE); |
474 | return 0; | 474 | return 0; |
475 | } | 475 | } |
476 | case RTC_UIE_ON: /* Allow ints for RTC updates. */ | 476 | case RTC_UIE_ON: /* Allow ints for RTC updates. */ |
477 | { | 477 | { |
478 | set_rtc_irq_bit(RTC_UIE); | 478 | set_rtc_irq_bit(RTC_UIE); |
479 | return 0; | 479 | return 0; |
480 | } | 480 | } |
481 | #endif | 481 | #endif |
482 | case RTC_ALM_READ: /* Read the present alarm time */ | 482 | case RTC_ALM_READ: /* Read the present alarm time */ |
483 | { | 483 | { |
484 | /* | 484 | /* |
485 | * This returns a struct rtc_time. Reading >= 0xc0 | 485 | * This returns a struct rtc_time. Reading >= 0xc0 |
486 | * means "don't care" or "match all". Only the tm_hour, | 486 | * means "don't care" or "match all". Only the tm_hour, |
487 | * tm_min, and tm_sec values are filled in. | 487 | * tm_min, and tm_sec values are filled in. |
488 | */ | 488 | */ |
489 | memset(&wtime, 0, sizeof(struct rtc_time)); | 489 | memset(&wtime, 0, sizeof(struct rtc_time)); |
490 | get_rtc_alm_time(&wtime); | 490 | get_rtc_alm_time(&wtime); |
491 | break; | 491 | break; |
492 | } | 492 | } |
493 | case RTC_ALM_SET: /* Store a time into the alarm */ | 493 | case RTC_ALM_SET: /* Store a time into the alarm */ |
494 | { | 494 | { |
495 | /* | 495 | /* |
496 | * This expects a struct rtc_time. Writing 0xff means | 496 | * This expects a struct rtc_time. Writing 0xff means |
497 | * "don't care" or "match all". Only the tm_hour, | 497 | * "don't care" or "match all". Only the tm_hour, |
498 | * tm_min and tm_sec are used. | 498 | * tm_min and tm_sec are used. |
499 | */ | 499 | */ |
500 | unsigned char hrs, min, sec; | 500 | unsigned char hrs, min, sec; |
501 | struct rtc_time alm_tm; | 501 | struct rtc_time alm_tm; |
502 | 502 | ||
503 | if (copy_from_user(&alm_tm, (struct rtc_time __user *)arg, | 503 | if (copy_from_user(&alm_tm, (struct rtc_time __user *)arg, |
504 | sizeof(struct rtc_time))) | 504 | sizeof(struct rtc_time))) |
505 | return -EFAULT; | 505 | return -EFAULT; |
506 | 506 | ||
507 | hrs = alm_tm.tm_hour; | 507 | hrs = alm_tm.tm_hour; |
508 | min = alm_tm.tm_min; | 508 | min = alm_tm.tm_min; |
509 | sec = alm_tm.tm_sec; | 509 | sec = alm_tm.tm_sec; |
510 | 510 | ||
511 | spin_lock_irq(&rtc_lock); | 511 | spin_lock_irq(&rtc_lock); |
512 | if (hpet_set_alarm_time(hrs, min, sec)) { | 512 | if (hpet_set_alarm_time(hrs, min, sec)) { |
513 | /* | 513 | /* |
514 | * Fallthru and set alarm time in CMOS too, | 514 | * Fallthru and set alarm time in CMOS too, |
515 | * so that we will get proper value in RTC_ALM_READ | 515 | * so that we will get proper value in RTC_ALM_READ |
516 | */ | 516 | */ |
517 | } | 517 | } |
518 | if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || | 518 | if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || |
519 | RTC_ALWAYS_BCD) { | 519 | RTC_ALWAYS_BCD) { |
520 | if (sec < 60) | 520 | if (sec < 60) |
521 | BIN_TO_BCD(sec); | 521 | sec = bin2bcd(sec); |
522 | else | 522 | else |
523 | sec = 0xff; | 523 | sec = 0xff; |
524 | 524 | ||
525 | if (min < 60) | 525 | if (min < 60) |
526 | BIN_TO_BCD(min); | 526 | min = bin2bcd(min); |
527 | else | 527 | else |
528 | min = 0xff; | 528 | min = 0xff; |
529 | 529 | ||
530 | if (hrs < 24) | 530 | if (hrs < 24) |
531 | BIN_TO_BCD(hrs); | 531 | hrs = bin2bcd(hrs); |
532 | else | 532 | else |
533 | hrs = 0xff; | 533 | hrs = 0xff; |
534 | } | 534 | } |
535 | CMOS_WRITE(hrs, RTC_HOURS_ALARM); | 535 | CMOS_WRITE(hrs, RTC_HOURS_ALARM); |
536 | CMOS_WRITE(min, RTC_MINUTES_ALARM); | 536 | CMOS_WRITE(min, RTC_MINUTES_ALARM); |
537 | CMOS_WRITE(sec, RTC_SECONDS_ALARM); | 537 | CMOS_WRITE(sec, RTC_SECONDS_ALARM); |
538 | spin_unlock_irq(&rtc_lock); | 538 | spin_unlock_irq(&rtc_lock); |
539 | 539 | ||
540 | return 0; | 540 | return 0; |
541 | } | 541 | } |
542 | case RTC_RD_TIME: /* Read the time/date from RTC */ | 542 | case RTC_RD_TIME: /* Read the time/date from RTC */ |
543 | { | 543 | { |
544 | memset(&wtime, 0, sizeof(struct rtc_time)); | 544 | memset(&wtime, 0, sizeof(struct rtc_time)); |
545 | rtc_get_rtc_time(&wtime); | 545 | rtc_get_rtc_time(&wtime); |
546 | break; | 546 | break; |
547 | } | 547 | } |
548 | case RTC_SET_TIME: /* Set the RTC */ | 548 | case RTC_SET_TIME: /* Set the RTC */ |
549 | { | 549 | { |
550 | struct rtc_time rtc_tm; | 550 | struct rtc_time rtc_tm; |
551 | unsigned char mon, day, hrs, min, sec, leap_yr; | 551 | unsigned char mon, day, hrs, min, sec, leap_yr; |
552 | unsigned char save_control, save_freq_select; | 552 | unsigned char save_control, save_freq_select; |
553 | unsigned int yrs; | 553 | unsigned int yrs; |
554 | #ifdef CONFIG_MACH_DECSTATION | 554 | #ifdef CONFIG_MACH_DECSTATION |
555 | unsigned int real_yrs; | 555 | unsigned int real_yrs; |
556 | #endif | 556 | #endif |
557 | 557 | ||
558 | if (!capable(CAP_SYS_TIME)) | 558 | if (!capable(CAP_SYS_TIME)) |
559 | return -EACCES; | 559 | return -EACCES; |
560 | 560 | ||
561 | if (copy_from_user(&rtc_tm, (struct rtc_time __user *)arg, | 561 | if (copy_from_user(&rtc_tm, (struct rtc_time __user *)arg, |
562 | sizeof(struct rtc_time))) | 562 | sizeof(struct rtc_time))) |
563 | return -EFAULT; | 563 | return -EFAULT; |
564 | 564 | ||
565 | yrs = rtc_tm.tm_year + 1900; | 565 | yrs = rtc_tm.tm_year + 1900; |
566 | mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ | 566 | mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ |
567 | day = rtc_tm.tm_mday; | 567 | day = rtc_tm.tm_mday; |
568 | hrs = rtc_tm.tm_hour; | 568 | hrs = rtc_tm.tm_hour; |
569 | min = rtc_tm.tm_min; | 569 | min = rtc_tm.tm_min; |
570 | sec = rtc_tm.tm_sec; | 570 | sec = rtc_tm.tm_sec; |
571 | 571 | ||
572 | if (yrs < 1970) | 572 | if (yrs < 1970) |
573 | return -EINVAL; | 573 | return -EINVAL; |
574 | 574 | ||
575 | leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); | 575 | leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); |
576 | 576 | ||
577 | if ((mon > 12) || (day == 0)) | 577 | if ((mon > 12) || (day == 0)) |
578 | return -EINVAL; | 578 | return -EINVAL; |
579 | 579 | ||
580 | if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) | 580 | if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) |
581 | return -EINVAL; | 581 | return -EINVAL; |
582 | 582 | ||
583 | if ((hrs >= 24) || (min >= 60) || (sec >= 60)) | 583 | if ((hrs >= 24) || (min >= 60) || (sec >= 60)) |
584 | return -EINVAL; | 584 | return -EINVAL; |
585 | 585 | ||
586 | yrs -= epoch; | 586 | yrs -= epoch; |
587 | if (yrs > 255) /* They are unsigned */ | 587 | if (yrs > 255) /* They are unsigned */ |
588 | return -EINVAL; | 588 | return -EINVAL; |
589 | 589 | ||
590 | spin_lock_irq(&rtc_lock); | 590 | spin_lock_irq(&rtc_lock); |
591 | #ifdef CONFIG_MACH_DECSTATION | 591 | #ifdef CONFIG_MACH_DECSTATION |
592 | real_yrs = yrs; | 592 | real_yrs = yrs; |
593 | yrs = 72; | 593 | yrs = 72; |
594 | 594 | ||
595 | /* | 595 | /* |
596 | * We want to keep the year set to 73 until March | 596 | * We want to keep the year set to 73 until March |
597 | * for non-leap years, so that Feb, 29th is handled | 597 | * for non-leap years, so that Feb, 29th is handled |
598 | * correctly. | 598 | * correctly. |
599 | */ | 599 | */ |
600 | if (!leap_yr && mon < 3) { | 600 | if (!leap_yr && mon < 3) { |
601 | real_yrs--; | 601 | real_yrs--; |
602 | yrs = 73; | 602 | yrs = 73; |
603 | } | 603 | } |
604 | #endif | 604 | #endif |
605 | /* These limits and adjustments are independent of | 605 | /* These limits and adjustments are independent of |
606 | * whether the chip is in binary mode or not. | 606 | * whether the chip is in binary mode or not. |
607 | */ | 607 | */ |
608 | if (yrs > 169) { | 608 | if (yrs > 169) { |
609 | spin_unlock_irq(&rtc_lock); | 609 | spin_unlock_irq(&rtc_lock); |
610 | return -EINVAL; | 610 | return -EINVAL; |
611 | } | 611 | } |
612 | if (yrs >= 100) | 612 | if (yrs >= 100) |
613 | yrs -= 100; | 613 | yrs -= 100; |
614 | 614 | ||
615 | if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) | 615 | if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) |
616 | || RTC_ALWAYS_BCD) { | 616 | || RTC_ALWAYS_BCD) { |
617 | BIN_TO_BCD(sec); | 617 | sec = bin2bcd(sec); |
618 | BIN_TO_BCD(min); | 618 | min = bin2bcd(min); |
619 | BIN_TO_BCD(hrs); | 619 | hrs = bin2bcd(hrs); |
620 | BIN_TO_BCD(day); | 620 | day = bin2bcd(day); |
621 | BIN_TO_BCD(mon); | 621 | mon = bin2bcd(mon); |
622 | BIN_TO_BCD(yrs); | 622 | yrs = bin2bcd(yrs); |
623 | } | 623 | } |
624 | 624 | ||
625 | save_control = CMOS_READ(RTC_CONTROL); | 625 | save_control = CMOS_READ(RTC_CONTROL); |
626 | CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); | 626 | CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); |
627 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); | 627 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); |
628 | CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); | 628 | CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); |
629 | 629 | ||
630 | #ifdef CONFIG_MACH_DECSTATION | 630 | #ifdef CONFIG_MACH_DECSTATION |
631 | CMOS_WRITE(real_yrs, RTC_DEC_YEAR); | 631 | CMOS_WRITE(real_yrs, RTC_DEC_YEAR); |
632 | #endif | 632 | #endif |
633 | CMOS_WRITE(yrs, RTC_YEAR); | 633 | CMOS_WRITE(yrs, RTC_YEAR); |
634 | CMOS_WRITE(mon, RTC_MONTH); | 634 | CMOS_WRITE(mon, RTC_MONTH); |
635 | CMOS_WRITE(day, RTC_DAY_OF_MONTH); | 635 | CMOS_WRITE(day, RTC_DAY_OF_MONTH); |
636 | CMOS_WRITE(hrs, RTC_HOURS); | 636 | CMOS_WRITE(hrs, RTC_HOURS); |
637 | CMOS_WRITE(min, RTC_MINUTES); | 637 | CMOS_WRITE(min, RTC_MINUTES); |
638 | CMOS_WRITE(sec, RTC_SECONDS); | 638 | CMOS_WRITE(sec, RTC_SECONDS); |
639 | 639 | ||
640 | CMOS_WRITE(save_control, RTC_CONTROL); | 640 | CMOS_WRITE(save_control, RTC_CONTROL); |
641 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); | 641 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); |
642 | 642 | ||
643 | spin_unlock_irq(&rtc_lock); | 643 | spin_unlock_irq(&rtc_lock); |
644 | return 0; | 644 | return 0; |
645 | } | 645 | } |
646 | #ifdef RTC_IRQ | 646 | #ifdef RTC_IRQ |
647 | case RTC_IRQP_READ: /* Read the periodic IRQ rate. */ | 647 | case RTC_IRQP_READ: /* Read the periodic IRQ rate. */ |
648 | { | 648 | { |
649 | return put_user(rtc_freq, (unsigned long __user *)arg); | 649 | return put_user(rtc_freq, (unsigned long __user *)arg); |
650 | } | 650 | } |
651 | case RTC_IRQP_SET: /* Set periodic IRQ rate. */ | 651 | case RTC_IRQP_SET: /* Set periodic IRQ rate. */ |
652 | { | 652 | { |
653 | int tmp = 0; | 653 | int tmp = 0; |
654 | unsigned char val; | 654 | unsigned char val; |
655 | /* can be called from isr via rtc_control() */ | 655 | /* can be called from isr via rtc_control() */ |
656 | unsigned long flags; | 656 | unsigned long flags; |
657 | 657 | ||
658 | /* | 658 | /* |
659 | * The max we can do is 8192Hz. | 659 | * The max we can do is 8192Hz. |
660 | */ | 660 | */ |
661 | if ((arg < 2) || (arg > 8192)) | 661 | if ((arg < 2) || (arg > 8192)) |
662 | return -EINVAL; | 662 | return -EINVAL; |
663 | /* | 663 | /* |
664 | * We don't really want Joe User generating more | 664 | * We don't really want Joe User generating more |
665 | * than 64Hz of interrupts on a multi-user machine. | 665 | * than 64Hz of interrupts on a multi-user machine. |
666 | */ | 666 | */ |
667 | if (!kernel && (arg > rtc_max_user_freq) && | 667 | if (!kernel && (arg > rtc_max_user_freq) && |
668 | !capable(CAP_SYS_RESOURCE)) | 668 | !capable(CAP_SYS_RESOURCE)) |
669 | return -EACCES; | 669 | return -EACCES; |
670 | 670 | ||
671 | while (arg > (1<<tmp)) | 671 | while (arg > (1<<tmp)) |
672 | tmp++; | 672 | tmp++; |
673 | 673 | ||
674 | /* | 674 | /* |
675 | * Check that the input was really a power of 2. | 675 | * Check that the input was really a power of 2. |
676 | */ | 676 | */ |
677 | if (arg != (1<<tmp)) | 677 | if (arg != (1<<tmp)) |
678 | return -EINVAL; | 678 | return -EINVAL; |
679 | 679 | ||
680 | rtc_freq = arg; | 680 | rtc_freq = arg; |
681 | 681 | ||
682 | spin_lock_irqsave(&rtc_lock, flags); | 682 | spin_lock_irqsave(&rtc_lock, flags); |
683 | if (hpet_set_periodic_freq(arg)) { | 683 | if (hpet_set_periodic_freq(arg)) { |
684 | spin_unlock_irqrestore(&rtc_lock, flags); | 684 | spin_unlock_irqrestore(&rtc_lock, flags); |
685 | return 0; | 685 | return 0; |
686 | } | 686 | } |
687 | 687 | ||
688 | val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0; | 688 | val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0; |
689 | val |= (16 - tmp); | 689 | val |= (16 - tmp); |
690 | CMOS_WRITE(val, RTC_FREQ_SELECT); | 690 | CMOS_WRITE(val, RTC_FREQ_SELECT); |
691 | spin_unlock_irqrestore(&rtc_lock, flags); | 691 | spin_unlock_irqrestore(&rtc_lock, flags); |
692 | return 0; | 692 | return 0; |
693 | } | 693 | } |
694 | #endif | 694 | #endif |
695 | case RTC_EPOCH_READ: /* Read the epoch. */ | 695 | case RTC_EPOCH_READ: /* Read the epoch. */ |
696 | { | 696 | { |
697 | return put_user(epoch, (unsigned long __user *)arg); | 697 | return put_user(epoch, (unsigned long __user *)arg); |
698 | } | 698 | } |
699 | case RTC_EPOCH_SET: /* Set the epoch. */ | 699 | case RTC_EPOCH_SET: /* Set the epoch. */ |
700 | { | 700 | { |
701 | /* | 701 | /* |
702 | * There were no RTC clocks before 1900. | 702 | * There were no RTC clocks before 1900. |
703 | */ | 703 | */ |
704 | if (arg < 1900) | 704 | if (arg < 1900) |
705 | return -EINVAL; | 705 | return -EINVAL; |
706 | 706 | ||
707 | if (!capable(CAP_SYS_TIME)) | 707 | if (!capable(CAP_SYS_TIME)) |
708 | return -EACCES; | 708 | return -EACCES; |
709 | 709 | ||
710 | epoch = arg; | 710 | epoch = arg; |
711 | return 0; | 711 | return 0; |
712 | } | 712 | } |
713 | default: | 713 | default: |
714 | return -ENOTTY; | 714 | return -ENOTTY; |
715 | } | 715 | } |
716 | return copy_to_user((void __user *)arg, | 716 | return copy_to_user((void __user *)arg, |
717 | &wtime, sizeof wtime) ? -EFAULT : 0; | 717 | &wtime, sizeof wtime) ? -EFAULT : 0; |
718 | } | 718 | } |
719 | 719 | ||
720 | static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 720 | static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
721 | { | 721 | { |
722 | long ret; | 722 | long ret; |
723 | lock_kernel(); | 723 | lock_kernel(); |
724 | ret = rtc_do_ioctl(cmd, arg, 0); | 724 | ret = rtc_do_ioctl(cmd, arg, 0); |
725 | unlock_kernel(); | 725 | unlock_kernel(); |
726 | return ret; | 726 | return ret; |
727 | } | 727 | } |
728 | 728 | ||
729 | /* | 729 | /* |
730 | * We enforce only one user at a time here with the open/close. | 730 | * We enforce only one user at a time here with the open/close. |
731 | * Also clear the previous interrupt data on an open, and clean | 731 | * Also clear the previous interrupt data on an open, and clean |
732 | * up things on a close. | 732 | * up things on a close. |
733 | */ | 733 | */ |
734 | 734 | ||
735 | /* We use rtc_lock to protect against concurrent opens. So the BKL is not | 735 | /* We use rtc_lock to protect against concurrent opens. So the BKL is not |
736 | * needed here. Or anywhere else in this driver. */ | 736 | * needed here. Or anywhere else in this driver. */ |
737 | static int rtc_open(struct inode *inode, struct file *file) | 737 | static int rtc_open(struct inode *inode, struct file *file) |
738 | { | 738 | { |
739 | lock_kernel(); | 739 | lock_kernel(); |
740 | spin_lock_irq(&rtc_lock); | 740 | spin_lock_irq(&rtc_lock); |
741 | 741 | ||
742 | if (rtc_status & RTC_IS_OPEN) | 742 | if (rtc_status & RTC_IS_OPEN) |
743 | goto out_busy; | 743 | goto out_busy; |
744 | 744 | ||
745 | rtc_status |= RTC_IS_OPEN; | 745 | rtc_status |= RTC_IS_OPEN; |
746 | 746 | ||
747 | rtc_irq_data = 0; | 747 | rtc_irq_data = 0; |
748 | spin_unlock_irq(&rtc_lock); | 748 | spin_unlock_irq(&rtc_lock); |
749 | unlock_kernel(); | 749 | unlock_kernel(); |
750 | return 0; | 750 | return 0; |
751 | 751 | ||
752 | out_busy: | 752 | out_busy: |
753 | spin_unlock_irq(&rtc_lock); | 753 | spin_unlock_irq(&rtc_lock); |
754 | unlock_kernel(); | 754 | unlock_kernel(); |
755 | return -EBUSY; | 755 | return -EBUSY; |
756 | } | 756 | } |
757 | 757 | ||
758 | static int rtc_fasync(int fd, struct file *filp, int on) | 758 | static int rtc_fasync(int fd, struct file *filp, int on) |
759 | { | 759 | { |
760 | return fasync_helper(fd, filp, on, &rtc_async_queue); | 760 | return fasync_helper(fd, filp, on, &rtc_async_queue); |
761 | } | 761 | } |
762 | 762 | ||
763 | static int rtc_release(struct inode *inode, struct file *file) | 763 | static int rtc_release(struct inode *inode, struct file *file) |
764 | { | 764 | { |
765 | #ifdef RTC_IRQ | 765 | #ifdef RTC_IRQ |
766 | unsigned char tmp; | 766 | unsigned char tmp; |
767 | 767 | ||
768 | if (rtc_has_irq == 0) | 768 | if (rtc_has_irq == 0) |
769 | goto no_irq; | 769 | goto no_irq; |
770 | 770 | ||
771 | /* | 771 | /* |
772 | * Turn off all interrupts once the device is no longer | 772 | * Turn off all interrupts once the device is no longer |
773 | * in use, and clear the data. | 773 | * in use, and clear the data. |
774 | */ | 774 | */ |
775 | 775 | ||
776 | spin_lock_irq(&rtc_lock); | 776 | spin_lock_irq(&rtc_lock); |
777 | if (!hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE)) { | 777 | if (!hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE)) { |
778 | tmp = CMOS_READ(RTC_CONTROL); | 778 | tmp = CMOS_READ(RTC_CONTROL); |
779 | tmp &= ~RTC_PIE; | 779 | tmp &= ~RTC_PIE; |
780 | tmp &= ~RTC_AIE; | 780 | tmp &= ~RTC_AIE; |
781 | tmp &= ~RTC_UIE; | 781 | tmp &= ~RTC_UIE; |
782 | CMOS_WRITE(tmp, RTC_CONTROL); | 782 | CMOS_WRITE(tmp, RTC_CONTROL); |
783 | CMOS_READ(RTC_INTR_FLAGS); | 783 | CMOS_READ(RTC_INTR_FLAGS); |
784 | } | 784 | } |
785 | if (rtc_status & RTC_TIMER_ON) { | 785 | if (rtc_status & RTC_TIMER_ON) { |
786 | rtc_status &= ~RTC_TIMER_ON; | 786 | rtc_status &= ~RTC_TIMER_ON; |
787 | del_timer(&rtc_irq_timer); | 787 | del_timer(&rtc_irq_timer); |
788 | } | 788 | } |
789 | spin_unlock_irq(&rtc_lock); | 789 | spin_unlock_irq(&rtc_lock); |
790 | 790 | ||
791 | if (file->f_flags & FASYNC) | 791 | if (file->f_flags & FASYNC) |
792 | rtc_fasync(-1, file, 0); | 792 | rtc_fasync(-1, file, 0); |
793 | no_irq: | 793 | no_irq: |
794 | #endif | 794 | #endif |
795 | 795 | ||
796 | spin_lock_irq(&rtc_lock); | 796 | spin_lock_irq(&rtc_lock); |
797 | rtc_irq_data = 0; | 797 | rtc_irq_data = 0; |
798 | rtc_status &= ~RTC_IS_OPEN; | 798 | rtc_status &= ~RTC_IS_OPEN; |
799 | spin_unlock_irq(&rtc_lock); | 799 | spin_unlock_irq(&rtc_lock); |
800 | 800 | ||
801 | return 0; | 801 | return 0; |
802 | } | 802 | } |
803 | 803 | ||
804 | #ifdef RTC_IRQ | 804 | #ifdef RTC_IRQ |
805 | /* Called without the kernel lock - fine */ | 805 | /* Called without the kernel lock - fine */ |
806 | static unsigned int rtc_poll(struct file *file, poll_table *wait) | 806 | static unsigned int rtc_poll(struct file *file, poll_table *wait) |
807 | { | 807 | { |
808 | unsigned long l; | 808 | unsigned long l; |
809 | 809 | ||
810 | if (rtc_has_irq == 0) | 810 | if (rtc_has_irq == 0) |
811 | return 0; | 811 | return 0; |
812 | 812 | ||
813 | poll_wait(file, &rtc_wait, wait); | 813 | poll_wait(file, &rtc_wait, wait); |
814 | 814 | ||
815 | spin_lock_irq(&rtc_lock); | 815 | spin_lock_irq(&rtc_lock); |
816 | l = rtc_irq_data; | 816 | l = rtc_irq_data; |
817 | spin_unlock_irq(&rtc_lock); | 817 | spin_unlock_irq(&rtc_lock); |
818 | 818 | ||
819 | if (l != 0) | 819 | if (l != 0) |
820 | return POLLIN | POLLRDNORM; | 820 | return POLLIN | POLLRDNORM; |
821 | return 0; | 821 | return 0; |
822 | } | 822 | } |
823 | #endif | 823 | #endif |
824 | 824 | ||
825 | int rtc_register(rtc_task_t *task) | 825 | int rtc_register(rtc_task_t *task) |
826 | { | 826 | { |
827 | #ifndef RTC_IRQ | 827 | #ifndef RTC_IRQ |
828 | return -EIO; | 828 | return -EIO; |
829 | #else | 829 | #else |
830 | if (task == NULL || task->func == NULL) | 830 | if (task == NULL || task->func == NULL) |
831 | return -EINVAL; | 831 | return -EINVAL; |
832 | spin_lock_irq(&rtc_lock); | 832 | spin_lock_irq(&rtc_lock); |
833 | if (rtc_status & RTC_IS_OPEN) { | 833 | if (rtc_status & RTC_IS_OPEN) { |
834 | spin_unlock_irq(&rtc_lock); | 834 | spin_unlock_irq(&rtc_lock); |
835 | return -EBUSY; | 835 | return -EBUSY; |
836 | } | 836 | } |
837 | spin_lock(&rtc_task_lock); | 837 | spin_lock(&rtc_task_lock); |
838 | if (rtc_callback) { | 838 | if (rtc_callback) { |
839 | spin_unlock(&rtc_task_lock); | 839 | spin_unlock(&rtc_task_lock); |
840 | spin_unlock_irq(&rtc_lock); | 840 | spin_unlock_irq(&rtc_lock); |
841 | return -EBUSY; | 841 | return -EBUSY; |
842 | } | 842 | } |
843 | rtc_status |= RTC_IS_OPEN; | 843 | rtc_status |= RTC_IS_OPEN; |
844 | rtc_callback = task; | 844 | rtc_callback = task; |
845 | spin_unlock(&rtc_task_lock); | 845 | spin_unlock(&rtc_task_lock); |
846 | spin_unlock_irq(&rtc_lock); | 846 | spin_unlock_irq(&rtc_lock); |
847 | return 0; | 847 | return 0; |
848 | #endif | 848 | #endif |
849 | } | 849 | } |
850 | EXPORT_SYMBOL(rtc_register); | 850 | EXPORT_SYMBOL(rtc_register); |
851 | 851 | ||
852 | int rtc_unregister(rtc_task_t *task) | 852 | int rtc_unregister(rtc_task_t *task) |
853 | { | 853 | { |
854 | #ifndef RTC_IRQ | 854 | #ifndef RTC_IRQ |
855 | return -EIO; | 855 | return -EIO; |
856 | #else | 856 | #else |
857 | unsigned char tmp; | 857 | unsigned char tmp; |
858 | 858 | ||
859 | spin_lock_irq(&rtc_lock); | 859 | spin_lock_irq(&rtc_lock); |
860 | spin_lock(&rtc_task_lock); | 860 | spin_lock(&rtc_task_lock); |
861 | if (rtc_callback != task) { | 861 | if (rtc_callback != task) { |
862 | spin_unlock(&rtc_task_lock); | 862 | spin_unlock(&rtc_task_lock); |
863 | spin_unlock_irq(&rtc_lock); | 863 | spin_unlock_irq(&rtc_lock); |
864 | return -ENXIO; | 864 | return -ENXIO; |
865 | } | 865 | } |
866 | rtc_callback = NULL; | 866 | rtc_callback = NULL; |
867 | 867 | ||
868 | /* disable controls */ | 868 | /* disable controls */ |
869 | if (!hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE)) { | 869 | if (!hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE)) { |
870 | tmp = CMOS_READ(RTC_CONTROL); | 870 | tmp = CMOS_READ(RTC_CONTROL); |
871 | tmp &= ~RTC_PIE; | 871 | tmp &= ~RTC_PIE; |
872 | tmp &= ~RTC_AIE; | 872 | tmp &= ~RTC_AIE; |
873 | tmp &= ~RTC_UIE; | 873 | tmp &= ~RTC_UIE; |
874 | CMOS_WRITE(tmp, RTC_CONTROL); | 874 | CMOS_WRITE(tmp, RTC_CONTROL); |
875 | CMOS_READ(RTC_INTR_FLAGS); | 875 | CMOS_READ(RTC_INTR_FLAGS); |
876 | } | 876 | } |
877 | if (rtc_status & RTC_TIMER_ON) { | 877 | if (rtc_status & RTC_TIMER_ON) { |
878 | rtc_status &= ~RTC_TIMER_ON; | 878 | rtc_status &= ~RTC_TIMER_ON; |
879 | del_timer(&rtc_irq_timer); | 879 | del_timer(&rtc_irq_timer); |
880 | } | 880 | } |
881 | rtc_status &= ~RTC_IS_OPEN; | 881 | rtc_status &= ~RTC_IS_OPEN; |
882 | spin_unlock(&rtc_task_lock); | 882 | spin_unlock(&rtc_task_lock); |
883 | spin_unlock_irq(&rtc_lock); | 883 | spin_unlock_irq(&rtc_lock); |
884 | return 0; | 884 | return 0; |
885 | #endif | 885 | #endif |
886 | } | 886 | } |
887 | EXPORT_SYMBOL(rtc_unregister); | 887 | EXPORT_SYMBOL(rtc_unregister); |
888 | 888 | ||
889 | int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg) | 889 | int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg) |
890 | { | 890 | { |
891 | #ifndef RTC_IRQ | 891 | #ifndef RTC_IRQ |
892 | return -EIO; | 892 | return -EIO; |
893 | #else | 893 | #else |
894 | unsigned long flags; | 894 | unsigned long flags; |
895 | if (cmd != RTC_PIE_ON && cmd != RTC_PIE_OFF && cmd != RTC_IRQP_SET) | 895 | if (cmd != RTC_PIE_ON && cmd != RTC_PIE_OFF && cmd != RTC_IRQP_SET) |
896 | return -EINVAL; | 896 | return -EINVAL; |
897 | spin_lock_irqsave(&rtc_task_lock, flags); | 897 | spin_lock_irqsave(&rtc_task_lock, flags); |
898 | if (rtc_callback != task) { | 898 | if (rtc_callback != task) { |
899 | spin_unlock_irqrestore(&rtc_task_lock, flags); | 899 | spin_unlock_irqrestore(&rtc_task_lock, flags); |
900 | return -ENXIO; | 900 | return -ENXIO; |
901 | } | 901 | } |
902 | spin_unlock_irqrestore(&rtc_task_lock, flags); | 902 | spin_unlock_irqrestore(&rtc_task_lock, flags); |
903 | return rtc_do_ioctl(cmd, arg, 1); | 903 | return rtc_do_ioctl(cmd, arg, 1); |
904 | #endif | 904 | #endif |
905 | } | 905 | } |
906 | EXPORT_SYMBOL(rtc_control); | 906 | EXPORT_SYMBOL(rtc_control); |
907 | 907 | ||
908 | /* | 908 | /* |
909 | * The various file operations we support. | 909 | * The various file operations we support. |
910 | */ | 910 | */ |
911 | 911 | ||
912 | static const struct file_operations rtc_fops = { | 912 | static const struct file_operations rtc_fops = { |
913 | .owner = THIS_MODULE, | 913 | .owner = THIS_MODULE, |
914 | .llseek = no_llseek, | 914 | .llseek = no_llseek, |
915 | .read = rtc_read, | 915 | .read = rtc_read, |
916 | #ifdef RTC_IRQ | 916 | #ifdef RTC_IRQ |
917 | .poll = rtc_poll, | 917 | .poll = rtc_poll, |
918 | #endif | 918 | #endif |
919 | .unlocked_ioctl = rtc_ioctl, | 919 | .unlocked_ioctl = rtc_ioctl, |
920 | .open = rtc_open, | 920 | .open = rtc_open, |
921 | .release = rtc_release, | 921 | .release = rtc_release, |
922 | .fasync = rtc_fasync, | 922 | .fasync = rtc_fasync, |
923 | }; | 923 | }; |
924 | 924 | ||
925 | static struct miscdevice rtc_dev = { | 925 | static struct miscdevice rtc_dev = { |
926 | .minor = RTC_MINOR, | 926 | .minor = RTC_MINOR, |
927 | .name = "rtc", | 927 | .name = "rtc", |
928 | .fops = &rtc_fops, | 928 | .fops = &rtc_fops, |
929 | }; | 929 | }; |
930 | 930 | ||
931 | #ifdef CONFIG_PROC_FS | 931 | #ifdef CONFIG_PROC_FS |
932 | static const struct file_operations rtc_proc_fops = { | 932 | static const struct file_operations rtc_proc_fops = { |
933 | .owner = THIS_MODULE, | 933 | .owner = THIS_MODULE, |
934 | .open = rtc_proc_open, | 934 | .open = rtc_proc_open, |
935 | .read = seq_read, | 935 | .read = seq_read, |
936 | .llseek = seq_lseek, | 936 | .llseek = seq_lseek, |
937 | .release = single_release, | 937 | .release = single_release, |
938 | }; | 938 | }; |
939 | #endif | 939 | #endif |
940 | 940 | ||
941 | static resource_size_t rtc_size; | 941 | static resource_size_t rtc_size; |
942 | 942 | ||
943 | static struct resource * __init rtc_request_region(resource_size_t size) | 943 | static struct resource * __init rtc_request_region(resource_size_t size) |
944 | { | 944 | { |
945 | struct resource *r; | 945 | struct resource *r; |
946 | 946 | ||
947 | if (RTC_IOMAPPED) | 947 | if (RTC_IOMAPPED) |
948 | r = request_region(RTC_PORT(0), size, "rtc"); | 948 | r = request_region(RTC_PORT(0), size, "rtc"); |
949 | else | 949 | else |
950 | r = request_mem_region(RTC_PORT(0), size, "rtc"); | 950 | r = request_mem_region(RTC_PORT(0), size, "rtc"); |
951 | 951 | ||
952 | if (r) | 952 | if (r) |
953 | rtc_size = size; | 953 | rtc_size = size; |
954 | 954 | ||
955 | return r; | 955 | return r; |
956 | } | 956 | } |
957 | 957 | ||
958 | static void rtc_release_region(void) | 958 | static void rtc_release_region(void) |
959 | { | 959 | { |
960 | if (RTC_IOMAPPED) | 960 | if (RTC_IOMAPPED) |
961 | release_region(RTC_PORT(0), rtc_size); | 961 | release_region(RTC_PORT(0), rtc_size); |
962 | else | 962 | else |
963 | release_mem_region(RTC_PORT(0), rtc_size); | 963 | release_mem_region(RTC_PORT(0), rtc_size); |
964 | } | 964 | } |
965 | 965 | ||
966 | static int __init rtc_init(void) | 966 | static int __init rtc_init(void) |
967 | { | 967 | { |
968 | #ifdef CONFIG_PROC_FS | 968 | #ifdef CONFIG_PROC_FS |
969 | struct proc_dir_entry *ent; | 969 | struct proc_dir_entry *ent; |
970 | #endif | 970 | #endif |
971 | #if defined(__alpha__) || defined(__mips__) | 971 | #if defined(__alpha__) || defined(__mips__) |
972 | unsigned int year, ctrl; | 972 | unsigned int year, ctrl; |
973 | char *guess = NULL; | 973 | char *guess = NULL; |
974 | #endif | 974 | #endif |
975 | #ifdef CONFIG_SPARC32 | 975 | #ifdef CONFIG_SPARC32 |
976 | struct device_node *ebus_dp; | 976 | struct device_node *ebus_dp; |
977 | struct of_device *op; | 977 | struct of_device *op; |
978 | #else | 978 | #else |
979 | void *r; | 979 | void *r; |
980 | #ifdef RTC_IRQ | 980 | #ifdef RTC_IRQ |
981 | irq_handler_t rtc_int_handler_ptr; | 981 | irq_handler_t rtc_int_handler_ptr; |
982 | #endif | 982 | #endif |
983 | #endif | 983 | #endif |
984 | 984 | ||
985 | #ifdef CONFIG_SPARC32 | 985 | #ifdef CONFIG_SPARC32 |
986 | for_each_node_by_name(ebus_dp, "ebus") { | 986 | for_each_node_by_name(ebus_dp, "ebus") { |
987 | struct device_node *dp; | 987 | struct device_node *dp; |
988 | for (dp = ebus_dp; dp; dp = dp->sibling) { | 988 | for (dp = ebus_dp; dp; dp = dp->sibling) { |
989 | if (!strcmp(dp->name, "rtc")) { | 989 | if (!strcmp(dp->name, "rtc")) { |
990 | op = of_find_device_by_node(dp); | 990 | op = of_find_device_by_node(dp); |
991 | if (op) { | 991 | if (op) { |
992 | rtc_port = op->resource[0].start; | 992 | rtc_port = op->resource[0].start; |
993 | rtc_irq = op->irqs[0]; | 993 | rtc_irq = op->irqs[0]; |
994 | goto found; | 994 | goto found; |
995 | } | 995 | } |
996 | } | 996 | } |
997 | } | 997 | } |
998 | } | 998 | } |
999 | rtc_has_irq = 0; | 999 | rtc_has_irq = 0; |
1000 | printk(KERN_ERR "rtc_init: no PC rtc found\n"); | 1000 | printk(KERN_ERR "rtc_init: no PC rtc found\n"); |
1001 | return -EIO; | 1001 | return -EIO; |
1002 | 1002 | ||
1003 | found: | 1003 | found: |
1004 | if (!rtc_irq) { | 1004 | if (!rtc_irq) { |
1005 | rtc_has_irq = 0; | 1005 | rtc_has_irq = 0; |
1006 | goto no_irq; | 1006 | goto no_irq; |
1007 | } | 1007 | } |
1008 | 1008 | ||
1009 | /* | 1009 | /* |
1010 | * XXX Interrupt pin #7 in Espresso is shared between RTC and | 1010 | * XXX Interrupt pin #7 in Espresso is shared between RTC and |
1011 | * PCI Slot 2 INTA# (and some INTx# in Slot 1). | 1011 | * PCI Slot 2 INTA# (and some INTx# in Slot 1). |
1012 | */ | 1012 | */ |
1013 | if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc", | 1013 | if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc", |
1014 | (void *)&rtc_port)) { | 1014 | (void *)&rtc_port)) { |
1015 | rtc_has_irq = 0; | 1015 | rtc_has_irq = 0; |
1016 | printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq); | 1016 | printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq); |
1017 | return -EIO; | 1017 | return -EIO; |
1018 | } | 1018 | } |
1019 | no_irq: | 1019 | no_irq: |
1020 | #else | 1020 | #else |
1021 | r = rtc_request_region(RTC_IO_EXTENT); | 1021 | r = rtc_request_region(RTC_IO_EXTENT); |
1022 | 1022 | ||
1023 | /* | 1023 | /* |
1024 | * If we've already requested a smaller range (for example, because | 1024 | * If we've already requested a smaller range (for example, because |
1025 | * PNPBIOS or ACPI told us how the device is configured), the request | 1025 | * PNPBIOS or ACPI told us how the device is configured), the request |
1026 | * above might fail because it's too big. | 1026 | * above might fail because it's too big. |
1027 | * | 1027 | * |
1028 | * If so, request just the range we actually use. | 1028 | * If so, request just the range we actually use. |
1029 | */ | 1029 | */ |
1030 | if (!r) | 1030 | if (!r) |
1031 | r = rtc_request_region(RTC_IO_EXTENT_USED); | 1031 | r = rtc_request_region(RTC_IO_EXTENT_USED); |
1032 | if (!r) { | 1032 | if (!r) { |
1033 | #ifdef RTC_IRQ | 1033 | #ifdef RTC_IRQ |
1034 | rtc_has_irq = 0; | 1034 | rtc_has_irq = 0; |
1035 | #endif | 1035 | #endif |
1036 | printk(KERN_ERR "rtc: I/O resource %lx is not free.\n", | 1036 | printk(KERN_ERR "rtc: I/O resource %lx is not free.\n", |
1037 | (long)(RTC_PORT(0))); | 1037 | (long)(RTC_PORT(0))); |
1038 | return -EIO; | 1038 | return -EIO; |
1039 | } | 1039 | } |
1040 | 1040 | ||
1041 | #ifdef RTC_IRQ | 1041 | #ifdef RTC_IRQ |
1042 | if (is_hpet_enabled()) { | 1042 | if (is_hpet_enabled()) { |
1043 | int err; | 1043 | int err; |
1044 | 1044 | ||
1045 | rtc_int_handler_ptr = hpet_rtc_interrupt; | 1045 | rtc_int_handler_ptr = hpet_rtc_interrupt; |
1046 | err = hpet_register_irq_handler(rtc_interrupt); | 1046 | err = hpet_register_irq_handler(rtc_interrupt); |
1047 | if (err != 0) { | 1047 | if (err != 0) { |
1048 | printk(KERN_WARNING "hpet_register_irq_handler failed " | 1048 | printk(KERN_WARNING "hpet_register_irq_handler failed " |
1049 | "in rtc_init()."); | 1049 | "in rtc_init()."); |
1050 | return err; | 1050 | return err; |
1051 | } | 1051 | } |
1052 | } else { | 1052 | } else { |
1053 | rtc_int_handler_ptr = rtc_interrupt; | 1053 | rtc_int_handler_ptr = rtc_interrupt; |
1054 | } | 1054 | } |
1055 | 1055 | ||
1056 | if (request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED, | 1056 | if (request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED, |
1057 | "rtc", NULL)) { | 1057 | "rtc", NULL)) { |
1058 | /* Yeah right, seeing as irq 8 doesn't even hit the bus. */ | 1058 | /* Yeah right, seeing as irq 8 doesn't even hit the bus. */ |
1059 | rtc_has_irq = 0; | 1059 | rtc_has_irq = 0; |
1060 | printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ); | 1060 | printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ); |
1061 | rtc_release_region(); | 1061 | rtc_release_region(); |
1062 | 1062 | ||
1063 | return -EIO; | 1063 | return -EIO; |
1064 | } | 1064 | } |
1065 | hpet_rtc_timer_init(); | 1065 | hpet_rtc_timer_init(); |
1066 | 1066 | ||
1067 | #endif | 1067 | #endif |
1068 | 1068 | ||
1069 | #endif /* CONFIG_SPARC32 vs. others */ | 1069 | #endif /* CONFIG_SPARC32 vs. others */ |
1070 | 1070 | ||
1071 | if (misc_register(&rtc_dev)) { | 1071 | if (misc_register(&rtc_dev)) { |
1072 | #ifdef RTC_IRQ | 1072 | #ifdef RTC_IRQ |
1073 | free_irq(RTC_IRQ, NULL); | 1073 | free_irq(RTC_IRQ, NULL); |
1074 | hpet_unregister_irq_handler(rtc_interrupt); | 1074 | hpet_unregister_irq_handler(rtc_interrupt); |
1075 | rtc_has_irq = 0; | 1075 | rtc_has_irq = 0; |
1076 | #endif | 1076 | #endif |
1077 | rtc_release_region(); | 1077 | rtc_release_region(); |
1078 | return -ENODEV; | 1078 | return -ENODEV; |
1079 | } | 1079 | } |
1080 | 1080 | ||
1081 | #ifdef CONFIG_PROC_FS | 1081 | #ifdef CONFIG_PROC_FS |
1082 | ent = proc_create("driver/rtc", 0, NULL, &rtc_proc_fops); | 1082 | ent = proc_create("driver/rtc", 0, NULL, &rtc_proc_fops); |
1083 | if (!ent) | 1083 | if (!ent) |
1084 | printk(KERN_WARNING "rtc: Failed to register with procfs.\n"); | 1084 | printk(KERN_WARNING "rtc: Failed to register with procfs.\n"); |
1085 | #endif | 1085 | #endif |
1086 | 1086 | ||
1087 | #if defined(__alpha__) || defined(__mips__) | 1087 | #if defined(__alpha__) || defined(__mips__) |
1088 | rtc_freq = HZ; | 1088 | rtc_freq = HZ; |
1089 | 1089 | ||
1090 | /* Each operating system on an Alpha uses its own epoch. | 1090 | /* Each operating system on an Alpha uses its own epoch. |
1091 | Let's try to guess which one we are using now. */ | 1091 | Let's try to guess which one we are using now. */ |
1092 | 1092 | ||
1093 | if (rtc_is_updating() != 0) | 1093 | if (rtc_is_updating() != 0) |
1094 | msleep(20); | 1094 | msleep(20); |
1095 | 1095 | ||
1096 | spin_lock_irq(&rtc_lock); | 1096 | spin_lock_irq(&rtc_lock); |
1097 | year = CMOS_READ(RTC_YEAR); | 1097 | year = CMOS_READ(RTC_YEAR); |
1098 | ctrl = CMOS_READ(RTC_CONTROL); | 1098 | ctrl = CMOS_READ(RTC_CONTROL); |
1099 | spin_unlock_irq(&rtc_lock); | 1099 | spin_unlock_irq(&rtc_lock); |
1100 | 1100 | ||
1101 | if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | 1101 | if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) |
1102 | BCD_TO_BIN(year); /* This should never happen... */ | 1102 | year = bcd2bin(year); /* This should never happen... */ |
1103 | 1103 | ||
1104 | if (year < 20) { | 1104 | if (year < 20) { |
1105 | epoch = 2000; | 1105 | epoch = 2000; |
1106 | guess = "SRM (post-2000)"; | 1106 | guess = "SRM (post-2000)"; |
1107 | } else if (year >= 20 && year < 48) { | 1107 | } else if (year >= 20 && year < 48) { |
1108 | epoch = 1980; | 1108 | epoch = 1980; |
1109 | guess = "ARC console"; | 1109 | guess = "ARC console"; |
1110 | } else if (year >= 48 && year < 72) { | 1110 | } else if (year >= 48 && year < 72) { |
1111 | epoch = 1952; | 1111 | epoch = 1952; |
1112 | guess = "Digital UNIX"; | 1112 | guess = "Digital UNIX"; |
1113 | #if defined(__mips__) | 1113 | #if defined(__mips__) |
1114 | } else if (year >= 72 && year < 74) { | 1114 | } else if (year >= 72 && year < 74) { |
1115 | epoch = 2000; | 1115 | epoch = 2000; |
1116 | guess = "Digital DECstation"; | 1116 | guess = "Digital DECstation"; |
1117 | #else | 1117 | #else |
1118 | } else if (year >= 70) { | 1118 | } else if (year >= 70) { |
1119 | epoch = 1900; | 1119 | epoch = 1900; |
1120 | guess = "Standard PC (1900)"; | 1120 | guess = "Standard PC (1900)"; |
1121 | #endif | 1121 | #endif |
1122 | } | 1122 | } |
1123 | if (guess) | 1123 | if (guess) |
1124 | printk(KERN_INFO "rtc: %s epoch (%lu) detected\n", | 1124 | printk(KERN_INFO "rtc: %s epoch (%lu) detected\n", |
1125 | guess, epoch); | 1125 | guess, epoch); |
1126 | #endif | 1126 | #endif |
1127 | #ifdef RTC_IRQ | 1127 | #ifdef RTC_IRQ |
1128 | if (rtc_has_irq == 0) | 1128 | if (rtc_has_irq == 0) |
1129 | goto no_irq2; | 1129 | goto no_irq2; |
1130 | 1130 | ||
1131 | spin_lock_irq(&rtc_lock); | 1131 | spin_lock_irq(&rtc_lock); |
1132 | rtc_freq = 1024; | 1132 | rtc_freq = 1024; |
1133 | if (!hpet_set_periodic_freq(rtc_freq)) { | 1133 | if (!hpet_set_periodic_freq(rtc_freq)) { |
1134 | /* | 1134 | /* |
1135 | * Initialize periodic frequency to CMOS reset default, | 1135 | * Initialize periodic frequency to CMOS reset default, |
1136 | * which is 1024Hz | 1136 | * which is 1024Hz |
1137 | */ | 1137 | */ |
1138 | CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), | 1138 | CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), |
1139 | RTC_FREQ_SELECT); | 1139 | RTC_FREQ_SELECT); |
1140 | } | 1140 | } |
1141 | spin_unlock_irq(&rtc_lock); | 1141 | spin_unlock_irq(&rtc_lock); |
1142 | no_irq2: | 1142 | no_irq2: |
1143 | #endif | 1143 | #endif |
1144 | 1144 | ||
1145 | (void) init_sysctl(); | 1145 | (void) init_sysctl(); |
1146 | 1146 | ||
1147 | printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n"); | 1147 | printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n"); |
1148 | 1148 | ||
1149 | return 0; | 1149 | return 0; |
1150 | } | 1150 | } |
1151 | 1151 | ||
1152 | static void __exit rtc_exit(void) | 1152 | static void __exit rtc_exit(void) |
1153 | { | 1153 | { |
1154 | cleanup_sysctl(); | 1154 | cleanup_sysctl(); |
1155 | remove_proc_entry("driver/rtc", NULL); | 1155 | remove_proc_entry("driver/rtc", NULL); |
1156 | misc_deregister(&rtc_dev); | 1156 | misc_deregister(&rtc_dev); |
1157 | 1157 | ||
1158 | #ifdef CONFIG_SPARC32 | 1158 | #ifdef CONFIG_SPARC32 |
1159 | if (rtc_has_irq) | 1159 | if (rtc_has_irq) |
1160 | free_irq(rtc_irq, &rtc_port); | 1160 | free_irq(rtc_irq, &rtc_port); |
1161 | #else | 1161 | #else |
1162 | rtc_release_region(); | 1162 | rtc_release_region(); |
1163 | #ifdef RTC_IRQ | 1163 | #ifdef RTC_IRQ |
1164 | if (rtc_has_irq) { | 1164 | if (rtc_has_irq) { |
1165 | free_irq(RTC_IRQ, NULL); | 1165 | free_irq(RTC_IRQ, NULL); |
1166 | hpet_unregister_irq_handler(hpet_rtc_interrupt); | 1166 | hpet_unregister_irq_handler(hpet_rtc_interrupt); |
1167 | } | 1167 | } |
1168 | #endif | 1168 | #endif |
1169 | #endif /* CONFIG_SPARC32 */ | 1169 | #endif /* CONFIG_SPARC32 */ |
1170 | } | 1170 | } |
1171 | 1171 | ||
1172 | module_init(rtc_init); | 1172 | module_init(rtc_init); |
1173 | module_exit(rtc_exit); | 1173 | module_exit(rtc_exit); |
1174 | 1174 | ||
1175 | #ifdef RTC_IRQ | 1175 | #ifdef RTC_IRQ |
1176 | /* | 1176 | /* |
1177 | * At IRQ rates >= 4096Hz, an interrupt may get lost altogether. | 1177 | * At IRQ rates >= 4096Hz, an interrupt may get lost altogether. |
1178 | * (usually during an IDE disk interrupt, with IRQ unmasking off) | 1178 | * (usually during an IDE disk interrupt, with IRQ unmasking off) |
1179 | * Since the interrupt handler doesn't get called, the IRQ status | 1179 | * Since the interrupt handler doesn't get called, the IRQ status |
1180 | * byte doesn't get read, and the RTC stops generating interrupts. | 1180 | * byte doesn't get read, and the RTC stops generating interrupts. |
1181 | * A timer is set, and will call this function if/when that happens. | 1181 | * A timer is set, and will call this function if/when that happens. |
1182 | * To get it out of this stalled state, we just read the status. | 1182 | * To get it out of this stalled state, we just read the status. |
1183 | * At least a jiffy of interrupts (rtc_freq/HZ) will have been lost. | 1183 | * At least a jiffy of interrupts (rtc_freq/HZ) will have been lost. |
1184 | * (You *really* shouldn't be trying to use a non-realtime system | 1184 | * (You *really* shouldn't be trying to use a non-realtime system |
1185 | * for something that requires a steady > 1KHz signal anyways.) | 1185 | * for something that requires a steady > 1KHz signal anyways.) |
1186 | */ | 1186 | */ |
1187 | 1187 | ||
1188 | static void rtc_dropped_irq(unsigned long data) | 1188 | static void rtc_dropped_irq(unsigned long data) |
1189 | { | 1189 | { |
1190 | unsigned long freq; | 1190 | unsigned long freq; |
1191 | 1191 | ||
1192 | spin_lock_irq(&rtc_lock); | 1192 | spin_lock_irq(&rtc_lock); |
1193 | 1193 | ||
1194 | if (hpet_rtc_dropped_irq()) { | 1194 | if (hpet_rtc_dropped_irq()) { |
1195 | spin_unlock_irq(&rtc_lock); | 1195 | spin_unlock_irq(&rtc_lock); |
1196 | return; | 1196 | return; |
1197 | } | 1197 | } |
1198 | 1198 | ||
1199 | /* Just in case someone disabled the timer from behind our back... */ | 1199 | /* Just in case someone disabled the timer from behind our back... */ |
1200 | if (rtc_status & RTC_TIMER_ON) | 1200 | if (rtc_status & RTC_TIMER_ON) |
1201 | mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); | 1201 | mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); |
1202 | 1202 | ||
1203 | rtc_irq_data += ((rtc_freq/HZ)<<8); | 1203 | rtc_irq_data += ((rtc_freq/HZ)<<8); |
1204 | rtc_irq_data &= ~0xff; | 1204 | rtc_irq_data &= ~0xff; |
1205 | rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */ | 1205 | rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */ |
1206 | 1206 | ||
1207 | freq = rtc_freq; | 1207 | freq = rtc_freq; |
1208 | 1208 | ||
1209 | spin_unlock_irq(&rtc_lock); | 1209 | spin_unlock_irq(&rtc_lock); |
1210 | 1210 | ||
1211 | if (printk_ratelimit()) { | 1211 | if (printk_ratelimit()) { |
1212 | printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", | 1212 | printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", |
1213 | freq); | 1213 | freq); |
1214 | } | 1214 | } |
1215 | 1215 | ||
1216 | /* Now we have new data */ | 1216 | /* Now we have new data */ |
1217 | wake_up_interruptible(&rtc_wait); | 1217 | wake_up_interruptible(&rtc_wait); |
1218 | 1218 | ||
1219 | kill_fasync(&rtc_async_queue, SIGIO, POLL_IN); | 1219 | kill_fasync(&rtc_async_queue, SIGIO, POLL_IN); |
1220 | } | 1220 | } |
1221 | #endif | 1221 | #endif |
1222 | 1222 | ||
1223 | #ifdef CONFIG_PROC_FS | 1223 | #ifdef CONFIG_PROC_FS |
1224 | /* | 1224 | /* |
1225 | * Info exported via "/proc/driver/rtc". | 1225 | * Info exported via "/proc/driver/rtc". |
1226 | */ | 1226 | */ |
1227 | 1227 | ||
1228 | static int rtc_proc_show(struct seq_file *seq, void *v) | 1228 | static int rtc_proc_show(struct seq_file *seq, void *v) |
1229 | { | 1229 | { |
1230 | #define YN(bit) ((ctrl & bit) ? "yes" : "no") | 1230 | #define YN(bit) ((ctrl & bit) ? "yes" : "no") |
1231 | #define NY(bit) ((ctrl & bit) ? "no" : "yes") | 1231 | #define NY(bit) ((ctrl & bit) ? "no" : "yes") |
1232 | struct rtc_time tm; | 1232 | struct rtc_time tm; |
1233 | unsigned char batt, ctrl; | 1233 | unsigned char batt, ctrl; |
1234 | unsigned long freq; | 1234 | unsigned long freq; |
1235 | 1235 | ||
1236 | spin_lock_irq(&rtc_lock); | 1236 | spin_lock_irq(&rtc_lock); |
1237 | batt = CMOS_READ(RTC_VALID) & RTC_VRT; | 1237 | batt = CMOS_READ(RTC_VALID) & RTC_VRT; |
1238 | ctrl = CMOS_READ(RTC_CONTROL); | 1238 | ctrl = CMOS_READ(RTC_CONTROL); |
1239 | freq = rtc_freq; | 1239 | freq = rtc_freq; |
1240 | spin_unlock_irq(&rtc_lock); | 1240 | spin_unlock_irq(&rtc_lock); |
1241 | 1241 | ||
1242 | 1242 | ||
1243 | rtc_get_rtc_time(&tm); | 1243 | rtc_get_rtc_time(&tm); |
1244 | 1244 | ||
1245 | /* | 1245 | /* |
1246 | * There is no way to tell if the luser has the RTC set for local | 1246 | * There is no way to tell if the luser has the RTC set for local |
1247 | * time or for Universal Standard Time (GMT). Probably local though. | 1247 | * time or for Universal Standard Time (GMT). Probably local though. |
1248 | */ | 1248 | */ |
1249 | seq_printf(seq, | 1249 | seq_printf(seq, |
1250 | "rtc_time\t: %02d:%02d:%02d\n" | 1250 | "rtc_time\t: %02d:%02d:%02d\n" |
1251 | "rtc_date\t: %04d-%02d-%02d\n" | 1251 | "rtc_date\t: %04d-%02d-%02d\n" |
1252 | "rtc_epoch\t: %04lu\n", | 1252 | "rtc_epoch\t: %04lu\n", |
1253 | tm.tm_hour, tm.tm_min, tm.tm_sec, | 1253 | tm.tm_hour, tm.tm_min, tm.tm_sec, |
1254 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); | 1254 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); |
1255 | 1255 | ||
1256 | get_rtc_alm_time(&tm); | 1256 | get_rtc_alm_time(&tm); |
1257 | 1257 | ||
1258 | /* | 1258 | /* |
1259 | * We implicitly assume 24hr mode here. Alarm values >= 0xc0 will | 1259 | * We implicitly assume 24hr mode here. Alarm values >= 0xc0 will |
1260 | * match any value for that particular field. Values that are | 1260 | * match any value for that particular field. Values that are |
1261 | * greater than a valid time, but less than 0xc0 shouldn't appear. | 1261 | * greater than a valid time, but less than 0xc0 shouldn't appear. |
1262 | */ | 1262 | */ |
1263 | seq_puts(seq, "alarm\t\t: "); | 1263 | seq_puts(seq, "alarm\t\t: "); |
1264 | if (tm.tm_hour <= 24) | 1264 | if (tm.tm_hour <= 24) |
1265 | seq_printf(seq, "%02d:", tm.tm_hour); | 1265 | seq_printf(seq, "%02d:", tm.tm_hour); |
1266 | else | 1266 | else |
1267 | seq_puts(seq, "**:"); | 1267 | seq_puts(seq, "**:"); |
1268 | 1268 | ||
1269 | if (tm.tm_min <= 59) | 1269 | if (tm.tm_min <= 59) |
1270 | seq_printf(seq, "%02d:", tm.tm_min); | 1270 | seq_printf(seq, "%02d:", tm.tm_min); |
1271 | else | 1271 | else |
1272 | seq_puts(seq, "**:"); | 1272 | seq_puts(seq, "**:"); |
1273 | 1273 | ||
1274 | if (tm.tm_sec <= 59) | 1274 | if (tm.tm_sec <= 59) |
1275 | seq_printf(seq, "%02d\n", tm.tm_sec); | 1275 | seq_printf(seq, "%02d\n", tm.tm_sec); |
1276 | else | 1276 | else |
1277 | seq_puts(seq, "**\n"); | 1277 | seq_puts(seq, "**\n"); |
1278 | 1278 | ||
1279 | seq_printf(seq, | 1279 | seq_printf(seq, |
1280 | "DST_enable\t: %s\n" | 1280 | "DST_enable\t: %s\n" |
1281 | "BCD\t\t: %s\n" | 1281 | "BCD\t\t: %s\n" |
1282 | "24hr\t\t: %s\n" | 1282 | "24hr\t\t: %s\n" |
1283 | "square_wave\t: %s\n" | 1283 | "square_wave\t: %s\n" |
1284 | "alarm_IRQ\t: %s\n" | 1284 | "alarm_IRQ\t: %s\n" |
1285 | "update_IRQ\t: %s\n" | 1285 | "update_IRQ\t: %s\n" |
1286 | "periodic_IRQ\t: %s\n" | 1286 | "periodic_IRQ\t: %s\n" |
1287 | "periodic_freq\t: %ld\n" | 1287 | "periodic_freq\t: %ld\n" |
1288 | "batt_status\t: %s\n", | 1288 | "batt_status\t: %s\n", |
1289 | YN(RTC_DST_EN), | 1289 | YN(RTC_DST_EN), |
1290 | NY(RTC_DM_BINARY), | 1290 | NY(RTC_DM_BINARY), |
1291 | YN(RTC_24H), | 1291 | YN(RTC_24H), |
1292 | YN(RTC_SQWE), | 1292 | YN(RTC_SQWE), |
1293 | YN(RTC_AIE), | 1293 | YN(RTC_AIE), |
1294 | YN(RTC_UIE), | 1294 | YN(RTC_UIE), |
1295 | YN(RTC_PIE), | 1295 | YN(RTC_PIE), |
1296 | freq, | 1296 | freq, |
1297 | batt ? "okay" : "dead"); | 1297 | batt ? "okay" : "dead"); |
1298 | 1298 | ||
1299 | return 0; | 1299 | return 0; |
1300 | #undef YN | 1300 | #undef YN |
1301 | #undef NY | 1301 | #undef NY |
1302 | } | 1302 | } |
1303 | 1303 | ||
1304 | static int rtc_proc_open(struct inode *inode, struct file *file) | 1304 | static int rtc_proc_open(struct inode *inode, struct file *file) |
1305 | { | 1305 | { |
1306 | return single_open(file, rtc_proc_show, NULL); | 1306 | return single_open(file, rtc_proc_show, NULL); |
1307 | } | 1307 | } |
1308 | #endif | 1308 | #endif |
1309 | 1309 | ||
1310 | static void rtc_get_rtc_time(struct rtc_time *rtc_tm) | 1310 | static void rtc_get_rtc_time(struct rtc_time *rtc_tm) |
1311 | { | 1311 | { |
1312 | unsigned long uip_watchdog = jiffies, flags; | 1312 | unsigned long uip_watchdog = jiffies, flags; |
1313 | unsigned char ctrl; | 1313 | unsigned char ctrl; |
1314 | #ifdef CONFIG_MACH_DECSTATION | 1314 | #ifdef CONFIG_MACH_DECSTATION |
1315 | unsigned int real_year; | 1315 | unsigned int real_year; |
1316 | #endif | 1316 | #endif |
1317 | 1317 | ||
1318 | /* | 1318 | /* |
1319 | * read RTC once any update in progress is done. The update | 1319 | * read RTC once any update in progress is done. The update |
1320 | * can take just over 2ms. We wait 20ms. There is no need to | 1320 | * can take just over 2ms. We wait 20ms. There is no need to |
1321 | * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. | 1321 | * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. |
1322 | * If you need to know *exactly* when a second has started, enable | 1322 | * If you need to know *exactly* when a second has started, enable |
1323 | * periodic update complete interrupts, (via ioctl) and then | 1323 | * periodic update complete interrupts, (via ioctl) and then |
1324 | * immediately read /dev/rtc which will block until you get the IRQ. | 1324 | * immediately read /dev/rtc which will block until you get the IRQ. |
1325 | * Once the read clears, read the RTC time (again via ioctl). Easy. | 1325 | * Once the read clears, read the RTC time (again via ioctl). Easy. |
1326 | */ | 1326 | */ |
1327 | 1327 | ||
1328 | while (rtc_is_updating() != 0 && | 1328 | while (rtc_is_updating() != 0 && |
1329 | time_before(jiffies, uip_watchdog + 2*HZ/100)) | 1329 | time_before(jiffies, uip_watchdog + 2*HZ/100)) |
1330 | cpu_relax(); | 1330 | cpu_relax(); |
1331 | 1331 | ||
1332 | /* | 1332 | /* |
1333 | * Only the values that we read from the RTC are set. We leave | 1333 | * Only the values that we read from the RTC are set. We leave |
1334 | * tm_wday, tm_yday and tm_isdst untouched. Note that while the | 1334 | * tm_wday, tm_yday and tm_isdst untouched. Note that while the |
1335 | * RTC has RTC_DAY_OF_WEEK, we should usually ignore it, as it is | 1335 | * RTC has RTC_DAY_OF_WEEK, we should usually ignore it, as it is |
1336 | * only updated by the RTC when initially set to a non-zero value. | 1336 | * only updated by the RTC when initially set to a non-zero value. |
1337 | */ | 1337 | */ |
1338 | spin_lock_irqsave(&rtc_lock, flags); | 1338 | spin_lock_irqsave(&rtc_lock, flags); |
1339 | rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); | 1339 | rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); |
1340 | rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); | 1340 | rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); |
1341 | rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); | 1341 | rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); |
1342 | rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); | 1342 | rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); |
1343 | rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); | 1343 | rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); |
1344 | rtc_tm->tm_year = CMOS_READ(RTC_YEAR); | 1344 | rtc_tm->tm_year = CMOS_READ(RTC_YEAR); |
1345 | /* Only set from 2.6.16 onwards */ | 1345 | /* Only set from 2.6.16 onwards */ |
1346 | rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK); | 1346 | rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK); |
1347 | 1347 | ||
1348 | #ifdef CONFIG_MACH_DECSTATION | 1348 | #ifdef CONFIG_MACH_DECSTATION |
1349 | real_year = CMOS_READ(RTC_DEC_YEAR); | 1349 | real_year = CMOS_READ(RTC_DEC_YEAR); |
1350 | #endif | 1350 | #endif |
1351 | ctrl = CMOS_READ(RTC_CONTROL); | 1351 | ctrl = CMOS_READ(RTC_CONTROL); |
1352 | spin_unlock_irqrestore(&rtc_lock, flags); | 1352 | spin_unlock_irqrestore(&rtc_lock, flags); |
1353 | 1353 | ||
1354 | if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | 1354 | if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { |
1355 | BCD_TO_BIN(rtc_tm->tm_sec); | 1355 | rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec); |
1356 | BCD_TO_BIN(rtc_tm->tm_min); | 1356 | rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min); |
1357 | BCD_TO_BIN(rtc_tm->tm_hour); | 1357 | rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour); |
1358 | BCD_TO_BIN(rtc_tm->tm_mday); | 1358 | rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday); |
1359 | BCD_TO_BIN(rtc_tm->tm_mon); | 1359 | rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon); |
1360 | BCD_TO_BIN(rtc_tm->tm_year); | 1360 | rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year); |
1361 | BCD_TO_BIN(rtc_tm->tm_wday); | 1361 | rtc_tm->tm_wday = bcd2bin(rtc_tm->tm_wday); |
1362 | } | 1362 | } |
1363 | 1363 | ||
1364 | #ifdef CONFIG_MACH_DECSTATION | 1364 | #ifdef CONFIG_MACH_DECSTATION |
1365 | rtc_tm->tm_year += real_year - 72; | 1365 | rtc_tm->tm_year += real_year - 72; |
1366 | #endif | 1366 | #endif |
1367 | 1367 | ||
1368 | /* | 1368 | /* |
1369 | * Account for differences between how the RTC uses the values | 1369 | * Account for differences between how the RTC uses the values |
1370 | * and how they are defined in a struct rtc_time; | 1370 | * and how they are defined in a struct rtc_time; |
1371 | */ | 1371 | */ |
1372 | rtc_tm->tm_year += epoch - 1900; | 1372 | rtc_tm->tm_year += epoch - 1900; |
1373 | if (rtc_tm->tm_year <= 69) | 1373 | if (rtc_tm->tm_year <= 69) |
1374 | rtc_tm->tm_year += 100; | 1374 | rtc_tm->tm_year += 100; |
1375 | 1375 | ||
1376 | rtc_tm->tm_mon--; | 1376 | rtc_tm->tm_mon--; |
1377 | } | 1377 | } |
1378 | 1378 | ||
1379 | static void get_rtc_alm_time(struct rtc_time *alm_tm) | 1379 | static void get_rtc_alm_time(struct rtc_time *alm_tm) |
1380 | { | 1380 | { |
1381 | unsigned char ctrl; | 1381 | unsigned char ctrl; |
1382 | 1382 | ||
1383 | /* | 1383 | /* |
1384 | * Only the values that we read from the RTC are set. That | 1384 | * Only the values that we read from the RTC are set. That |
1385 | * means only tm_hour, tm_min, and tm_sec. | 1385 | * means only tm_hour, tm_min, and tm_sec. |
1386 | */ | 1386 | */ |
1387 | spin_lock_irq(&rtc_lock); | 1387 | spin_lock_irq(&rtc_lock); |
1388 | alm_tm->tm_sec = CMOS_READ(RTC_SECONDS_ALARM); | 1388 | alm_tm->tm_sec = CMOS_READ(RTC_SECONDS_ALARM); |
1389 | alm_tm->tm_min = CMOS_READ(RTC_MINUTES_ALARM); | 1389 | alm_tm->tm_min = CMOS_READ(RTC_MINUTES_ALARM); |
1390 | alm_tm->tm_hour = CMOS_READ(RTC_HOURS_ALARM); | 1390 | alm_tm->tm_hour = CMOS_READ(RTC_HOURS_ALARM); |
1391 | ctrl = CMOS_READ(RTC_CONTROL); | 1391 | ctrl = CMOS_READ(RTC_CONTROL); |
1392 | spin_unlock_irq(&rtc_lock); | 1392 | spin_unlock_irq(&rtc_lock); |
1393 | 1393 | ||
1394 | if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { | 1394 | if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { |
1395 | BCD_TO_BIN(alm_tm->tm_sec); | 1395 | alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec); |
1396 | BCD_TO_BIN(alm_tm->tm_min); | 1396 | alm_tm->tm_min = bcd2bin(alm_tm->tm_min); |
1397 | BCD_TO_BIN(alm_tm->tm_hour); | 1397 | alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour); |
1398 | } | 1398 | } |
1399 | } | 1399 | } |
1400 | 1400 | ||
1401 | #ifdef RTC_IRQ | 1401 | #ifdef RTC_IRQ |
1402 | /* | 1402 | /* |
1403 | * Used to disable/enable interrupts for any one of UIE, AIE, PIE. | 1403 | * Used to disable/enable interrupts for any one of UIE, AIE, PIE. |
1404 | * Rumour has it that if you frob the interrupt enable/disable | 1404 | * Rumour has it that if you frob the interrupt enable/disable |
1405 | * bits in RTC_CONTROL, you should read RTC_INTR_FLAGS, to | 1405 | * bits in RTC_CONTROL, you should read RTC_INTR_FLAGS, to |
1406 | * ensure you actually start getting interrupts. Probably for | 1406 | * ensure you actually start getting interrupts. Probably for |
1407 | * compatibility with older/broken chipset RTC implementations. | 1407 | * compatibility with older/broken chipset RTC implementations. |
1408 | * We also clear out any old irq data after an ioctl() that | 1408 | * We also clear out any old irq data after an ioctl() that |
1409 | * meddles with the interrupt enable/disable bits. | 1409 | * meddles with the interrupt enable/disable bits. |
1410 | */ | 1410 | */ |
1411 | 1411 | ||
1412 | static void mask_rtc_irq_bit_locked(unsigned char bit) | 1412 | static void mask_rtc_irq_bit_locked(unsigned char bit) |
1413 | { | 1413 | { |
1414 | unsigned char val; | 1414 | unsigned char val; |
1415 | 1415 | ||
1416 | if (hpet_mask_rtc_irq_bit(bit)) | 1416 | if (hpet_mask_rtc_irq_bit(bit)) |
1417 | return; | 1417 | return; |
1418 | val = CMOS_READ(RTC_CONTROL); | 1418 | val = CMOS_READ(RTC_CONTROL); |
1419 | val &= ~bit; | 1419 | val &= ~bit; |
1420 | CMOS_WRITE(val, RTC_CONTROL); | 1420 | CMOS_WRITE(val, RTC_CONTROL); |
1421 | CMOS_READ(RTC_INTR_FLAGS); | 1421 | CMOS_READ(RTC_INTR_FLAGS); |
1422 | 1422 | ||
1423 | rtc_irq_data = 0; | 1423 | rtc_irq_data = 0; |
1424 | } | 1424 | } |
1425 | 1425 | ||
1426 | static void set_rtc_irq_bit_locked(unsigned char bit) | 1426 | static void set_rtc_irq_bit_locked(unsigned char bit) |
1427 | { | 1427 | { |
1428 | unsigned char val; | 1428 | unsigned char val; |
1429 | 1429 | ||
1430 | if (hpet_set_rtc_irq_bit(bit)) | 1430 | if (hpet_set_rtc_irq_bit(bit)) |
1431 | return; | 1431 | return; |
1432 | val = CMOS_READ(RTC_CONTROL); | 1432 | val = CMOS_READ(RTC_CONTROL); |
1433 | val |= bit; | 1433 | val |= bit; |
1434 | CMOS_WRITE(val, RTC_CONTROL); | 1434 | CMOS_WRITE(val, RTC_CONTROL); |
1435 | CMOS_READ(RTC_INTR_FLAGS); | 1435 | CMOS_READ(RTC_INTR_FLAGS); |
1436 | 1436 | ||
1437 | rtc_irq_data = 0; | 1437 | rtc_irq_data = 0; |
1438 | } | 1438 | } |
1439 | #endif | 1439 | #endif |
1440 | 1440 | ||
1441 | MODULE_AUTHOR("Paul Gortmaker"); | 1441 | MODULE_AUTHOR("Paul Gortmaker"); |
1442 | MODULE_LICENSE("GPL"); | 1442 | MODULE_LICENSE("GPL"); |
1443 | MODULE_ALIAS_MISCDEV(RTC_MINOR); | 1443 | MODULE_ALIAS_MISCDEV(RTC_MINOR); |
1444 | 1444 |
include/asm-generic/rtc.h
1 | /* | 1 | /* |
2 | * include/asm-generic/rtc.h | 2 | * include/asm-generic/rtc.h |
3 | * | 3 | * |
4 | * Author: Tom Rini <trini@mvista.com> | 4 | * Author: Tom Rini <trini@mvista.com> |
5 | * | 5 | * |
6 | * Based on: | 6 | * Based on: |
7 | * drivers/char/rtc.c | 7 | * drivers/char/rtc.c |
8 | * | 8 | * |
9 | * Please read the COPYING file for all license details. | 9 | * Please read the COPYING file for all license details. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #ifndef __ASM_RTC_H__ | 12 | #ifndef __ASM_RTC_H__ |
13 | #define __ASM_RTC_H__ | 13 | #define __ASM_RTC_H__ |
14 | 14 | ||
15 | #include <linux/mc146818rtc.h> | 15 | #include <linux/mc146818rtc.h> |
16 | #include <linux/rtc.h> | 16 | #include <linux/rtc.h> |
17 | #include <linux/bcd.h> | 17 | #include <linux/bcd.h> |
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | 19 | ||
20 | #define RTC_PIE 0x40 /* periodic interrupt enable */ | 20 | #define RTC_PIE 0x40 /* periodic interrupt enable */ |
21 | #define RTC_AIE 0x20 /* alarm interrupt enable */ | 21 | #define RTC_AIE 0x20 /* alarm interrupt enable */ |
22 | #define RTC_UIE 0x10 /* update-finished interrupt enable */ | 22 | #define RTC_UIE 0x10 /* update-finished interrupt enable */ |
23 | 23 | ||
24 | /* some dummy definitions */ | 24 | /* some dummy definitions */ |
25 | #define RTC_BATT_BAD 0x100 /* battery bad */ | 25 | #define RTC_BATT_BAD 0x100 /* battery bad */ |
26 | #define RTC_SQWE 0x08 /* enable square-wave output */ | 26 | #define RTC_SQWE 0x08 /* enable square-wave output */ |
27 | #define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */ | 27 | #define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */ |
28 | #define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */ | 28 | #define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */ |
29 | #define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */ | 29 | #define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */ |
30 | 30 | ||
31 | /* | 31 | /* |
32 | * Returns true if a clock update is in progress | 32 | * Returns true if a clock update is in progress |
33 | */ | 33 | */ |
34 | static inline unsigned char rtc_is_updating(void) | 34 | static inline unsigned char rtc_is_updating(void) |
35 | { | 35 | { |
36 | unsigned char uip; | 36 | unsigned char uip; |
37 | unsigned long flags; | 37 | unsigned long flags; |
38 | 38 | ||
39 | spin_lock_irqsave(&rtc_lock, flags); | 39 | spin_lock_irqsave(&rtc_lock, flags); |
40 | uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); | 40 | uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); |
41 | spin_unlock_irqrestore(&rtc_lock, flags); | 41 | spin_unlock_irqrestore(&rtc_lock, flags); |
42 | return uip; | 42 | return uip; |
43 | } | 43 | } |
44 | 44 | ||
45 | static inline unsigned int get_rtc_time(struct rtc_time *time) | 45 | static inline unsigned int get_rtc_time(struct rtc_time *time) |
46 | { | 46 | { |
47 | unsigned char ctrl; | 47 | unsigned char ctrl; |
48 | unsigned long flags; | 48 | unsigned long flags; |
49 | 49 | ||
50 | #ifdef CONFIG_MACH_DECSTATION | 50 | #ifdef CONFIG_MACH_DECSTATION |
51 | unsigned int real_year; | 51 | unsigned int real_year; |
52 | #endif | 52 | #endif |
53 | 53 | ||
54 | /* | 54 | /* |
55 | * read RTC once any update in progress is done. The update | 55 | * read RTC once any update in progress is done. The update |
56 | * can take just over 2ms. We wait 20ms. There is no need to | 56 | * can take just over 2ms. We wait 20ms. There is no need to |
57 | * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. | 57 | * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. |
58 | * If you need to know *exactly* when a second has started, enable | 58 | * If you need to know *exactly* when a second has started, enable |
59 | * periodic update complete interrupts, (via ioctl) and then | 59 | * periodic update complete interrupts, (via ioctl) and then |
60 | * immediately read /dev/rtc which will block until you get the IRQ. | 60 | * immediately read /dev/rtc which will block until you get the IRQ. |
61 | * Once the read clears, read the RTC time (again via ioctl). Easy. | 61 | * Once the read clears, read the RTC time (again via ioctl). Easy. |
62 | */ | 62 | */ |
63 | if (rtc_is_updating()) | 63 | if (rtc_is_updating()) |
64 | mdelay(20); | 64 | mdelay(20); |
65 | 65 | ||
66 | /* | 66 | /* |
67 | * Only the values that we read from the RTC are set. We leave | 67 | * Only the values that we read from the RTC are set. We leave |
68 | * tm_wday, tm_yday and tm_isdst untouched. Even though the | 68 | * tm_wday, tm_yday and tm_isdst untouched. Even though the |
69 | * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated | 69 | * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated |
70 | * by the RTC when initially set to a non-zero value. | 70 | * by the RTC when initially set to a non-zero value. |
71 | */ | 71 | */ |
72 | spin_lock_irqsave(&rtc_lock, flags); | 72 | spin_lock_irqsave(&rtc_lock, flags); |
73 | time->tm_sec = CMOS_READ(RTC_SECONDS); | 73 | time->tm_sec = CMOS_READ(RTC_SECONDS); |
74 | time->tm_min = CMOS_READ(RTC_MINUTES); | 74 | time->tm_min = CMOS_READ(RTC_MINUTES); |
75 | time->tm_hour = CMOS_READ(RTC_HOURS); | 75 | time->tm_hour = CMOS_READ(RTC_HOURS); |
76 | time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); | 76 | time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); |
77 | time->tm_mon = CMOS_READ(RTC_MONTH); | 77 | time->tm_mon = CMOS_READ(RTC_MONTH); |
78 | time->tm_year = CMOS_READ(RTC_YEAR); | 78 | time->tm_year = CMOS_READ(RTC_YEAR); |
79 | #ifdef CONFIG_MACH_DECSTATION | 79 | #ifdef CONFIG_MACH_DECSTATION |
80 | real_year = CMOS_READ(RTC_DEC_YEAR); | 80 | real_year = CMOS_READ(RTC_DEC_YEAR); |
81 | #endif | 81 | #endif |
82 | ctrl = CMOS_READ(RTC_CONTROL); | 82 | ctrl = CMOS_READ(RTC_CONTROL); |
83 | spin_unlock_irqrestore(&rtc_lock, flags); | 83 | spin_unlock_irqrestore(&rtc_lock, flags); |
84 | 84 | ||
85 | if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) | 85 | if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) |
86 | { | 86 | { |
87 | BCD_TO_BIN(time->tm_sec); | 87 | time->tm_sec = bcd2bin(time->tm_sec); |
88 | BCD_TO_BIN(time->tm_min); | 88 | time->tm_min = bcd2bin(time->tm_min); |
89 | BCD_TO_BIN(time->tm_hour); | 89 | time->tm_hour = bcd2bin(time->tm_hour); |
90 | BCD_TO_BIN(time->tm_mday); | 90 | time->tm_mday = bcd2bin(time->tm_mday); |
91 | BCD_TO_BIN(time->tm_mon); | 91 | time->tm_mon = bcd2bin(time->tm_mon); |
92 | BCD_TO_BIN(time->tm_year); | 92 | time->tm_year = bcd2bin(time->tm_year); |
93 | } | 93 | } |
94 | 94 | ||
95 | #ifdef CONFIG_MACH_DECSTATION | 95 | #ifdef CONFIG_MACH_DECSTATION |
96 | time->tm_year += real_year - 72; | 96 | time->tm_year += real_year - 72; |
97 | #endif | 97 | #endif |
98 | 98 | ||
99 | /* | 99 | /* |
100 | * Account for differences between how the RTC uses the values | 100 | * Account for differences between how the RTC uses the values |
101 | * and how they are defined in a struct rtc_time; | 101 | * and how they are defined in a struct rtc_time; |
102 | */ | 102 | */ |
103 | if (time->tm_year <= 69) | 103 | if (time->tm_year <= 69) |
104 | time->tm_year += 100; | 104 | time->tm_year += 100; |
105 | 105 | ||
106 | time->tm_mon--; | 106 | time->tm_mon--; |
107 | 107 | ||
108 | return RTC_24H; | 108 | return RTC_24H; |
109 | } | 109 | } |
110 | 110 | ||
111 | /* Set the current date and time in the real time clock. */ | 111 | /* Set the current date and time in the real time clock. */ |
112 | static inline int set_rtc_time(struct rtc_time *time) | 112 | static inline int set_rtc_time(struct rtc_time *time) |
113 | { | 113 | { |
114 | unsigned long flags; | 114 | unsigned long flags; |
115 | unsigned char mon, day, hrs, min, sec; | 115 | unsigned char mon, day, hrs, min, sec; |
116 | unsigned char save_control, save_freq_select; | 116 | unsigned char save_control, save_freq_select; |
117 | unsigned int yrs; | 117 | unsigned int yrs; |
118 | #ifdef CONFIG_MACH_DECSTATION | 118 | #ifdef CONFIG_MACH_DECSTATION |
119 | unsigned int real_yrs, leap_yr; | 119 | unsigned int real_yrs, leap_yr; |
120 | #endif | 120 | #endif |
121 | 121 | ||
122 | yrs = time->tm_year; | 122 | yrs = time->tm_year; |
123 | mon = time->tm_mon + 1; /* tm_mon starts at zero */ | 123 | mon = time->tm_mon + 1; /* tm_mon starts at zero */ |
124 | day = time->tm_mday; | 124 | day = time->tm_mday; |
125 | hrs = time->tm_hour; | 125 | hrs = time->tm_hour; |
126 | min = time->tm_min; | 126 | min = time->tm_min; |
127 | sec = time->tm_sec; | 127 | sec = time->tm_sec; |
128 | 128 | ||
129 | if (yrs > 255) /* They are unsigned */ | 129 | if (yrs > 255) /* They are unsigned */ |
130 | return -EINVAL; | 130 | return -EINVAL; |
131 | 131 | ||
132 | spin_lock_irqsave(&rtc_lock, flags); | 132 | spin_lock_irqsave(&rtc_lock, flags); |
133 | #ifdef CONFIG_MACH_DECSTATION | 133 | #ifdef CONFIG_MACH_DECSTATION |
134 | real_yrs = yrs; | 134 | real_yrs = yrs; |
135 | leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) || | 135 | leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) || |
136 | !((yrs + 1900) % 400)); | 136 | !((yrs + 1900) % 400)); |
137 | yrs = 72; | 137 | yrs = 72; |
138 | 138 | ||
139 | /* | 139 | /* |
140 | * We want to keep the year set to 73 until March | 140 | * We want to keep the year set to 73 until March |
141 | * for non-leap years, so that Feb, 29th is handled | 141 | * for non-leap years, so that Feb, 29th is handled |
142 | * correctly. | 142 | * correctly. |
143 | */ | 143 | */ |
144 | if (!leap_yr && mon < 3) { | 144 | if (!leap_yr && mon < 3) { |
145 | real_yrs--; | 145 | real_yrs--; |
146 | yrs = 73; | 146 | yrs = 73; |
147 | } | 147 | } |
148 | #endif | 148 | #endif |
149 | /* These limits and adjustments are independent of | 149 | /* These limits and adjustments are independent of |
150 | * whether the chip is in binary mode or not. | 150 | * whether the chip is in binary mode or not. |
151 | */ | 151 | */ |
152 | if (yrs > 169) { | 152 | if (yrs > 169) { |
153 | spin_unlock_irqrestore(&rtc_lock, flags); | 153 | spin_unlock_irqrestore(&rtc_lock, flags); |
154 | return -EINVAL; | 154 | return -EINVAL; |
155 | } | 155 | } |
156 | 156 | ||
157 | if (yrs >= 100) | 157 | if (yrs >= 100) |
158 | yrs -= 100; | 158 | yrs -= 100; |
159 | 159 | ||
160 | if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) | 160 | if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) |
161 | || RTC_ALWAYS_BCD) { | 161 | || RTC_ALWAYS_BCD) { |
162 | BIN_TO_BCD(sec); | 162 | sec = bin2bcd(sec); |
163 | BIN_TO_BCD(min); | 163 | min = bin2bcd(min); |
164 | BIN_TO_BCD(hrs); | 164 | hrs = bin2bcd(hrs); |
165 | BIN_TO_BCD(day); | 165 | day = bin2bcd(day); |
166 | BIN_TO_BCD(mon); | 166 | mon = bin2bcd(mon); |
167 | BIN_TO_BCD(yrs); | 167 | yrs = bin2bcd(yrs); |
168 | } | 168 | } |
169 | 169 | ||
170 | save_control = CMOS_READ(RTC_CONTROL); | 170 | save_control = CMOS_READ(RTC_CONTROL); |
171 | CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); | 171 | CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); |
172 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); | 172 | save_freq_select = CMOS_READ(RTC_FREQ_SELECT); |
173 | CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); | 173 | CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); |
174 | 174 | ||
175 | #ifdef CONFIG_MACH_DECSTATION | 175 | #ifdef CONFIG_MACH_DECSTATION |
176 | CMOS_WRITE(real_yrs, RTC_DEC_YEAR); | 176 | CMOS_WRITE(real_yrs, RTC_DEC_YEAR); |
177 | #endif | 177 | #endif |
178 | CMOS_WRITE(yrs, RTC_YEAR); | 178 | CMOS_WRITE(yrs, RTC_YEAR); |
179 | CMOS_WRITE(mon, RTC_MONTH); | 179 | CMOS_WRITE(mon, RTC_MONTH); |
180 | CMOS_WRITE(day, RTC_DAY_OF_MONTH); | 180 | CMOS_WRITE(day, RTC_DAY_OF_MONTH); |
181 | CMOS_WRITE(hrs, RTC_HOURS); | 181 | CMOS_WRITE(hrs, RTC_HOURS); |
182 | CMOS_WRITE(min, RTC_MINUTES); | 182 | CMOS_WRITE(min, RTC_MINUTES); |
183 | CMOS_WRITE(sec, RTC_SECONDS); | 183 | CMOS_WRITE(sec, RTC_SECONDS); |
184 | 184 | ||
185 | CMOS_WRITE(save_control, RTC_CONTROL); | 185 | CMOS_WRITE(save_control, RTC_CONTROL); |
186 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); | 186 | CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); |
187 | 187 | ||
188 | spin_unlock_irqrestore(&rtc_lock, flags); | 188 | spin_unlock_irqrestore(&rtc_lock, flags); |
189 | 189 | ||
190 | return 0; | 190 | return 0; |
191 | } | 191 | } |
192 | 192 | ||
193 | static inline unsigned int get_rtc_ss(void) | 193 | static inline unsigned int get_rtc_ss(void) |
194 | { | 194 | { |
195 | struct rtc_time h; | 195 | struct rtc_time h; |
196 | 196 | ||
197 | get_rtc_time(&h); | 197 | get_rtc_time(&h); |
198 | return h.tm_sec; | 198 | return h.tm_sec; |
199 | } | 199 | } |
200 | 200 | ||
201 | static inline int get_rtc_pll(struct rtc_pll_info *pll) | 201 | static inline int get_rtc_pll(struct rtc_pll_info *pll) |
202 | { | 202 | { |
203 | return -EINVAL; | 203 | return -EINVAL; |
204 | } | 204 | } |
205 | static inline int set_rtc_pll(struct rtc_pll_info *pll) | 205 | static inline int set_rtc_pll(struct rtc_pll_info *pll) |
206 | { | 206 | { |
207 | return -EINVAL; | 207 | return -EINVAL; |
208 | } | 208 | } |
209 | 209 | ||
210 | #endif /* __ASM_RTC_H__ */ | 210 | #endif /* __ASM_RTC_H__ */ |
211 | 211 |