diff options
Diffstat (limited to 'arch/sparc/kernel/time.c')
-rw-r--r-- | arch/sparc/kernel/time.c | 382 |
1 files changed, 64 insertions, 318 deletions
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c index 0762f5db1924..62c1d94cb434 100644 --- a/arch/sparc/kernel/time.c +++ b/arch/sparc/kernel/time.c | |||
@@ -23,22 +23,24 @@ | |||
23 | #include <linux/mm.h> | 23 | #include <linux/mm.h> |
24 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
25 | #include <linux/time.h> | 25 | #include <linux/time.h> |
26 | #include <linux/rtc.h> | ||
27 | #include <linux/rtc/m48t59.h> | ||
26 | #include <linux/timex.h> | 28 | #include <linux/timex.h> |
27 | #include <linux/init.h> | 29 | #include <linux/init.h> |
28 | #include <linux/pci.h> | 30 | #include <linux/pci.h> |
29 | #include <linux/ioport.h> | 31 | #include <linux/ioport.h> |
30 | #include <linux/profile.h> | 32 | #include <linux/profile.h> |
33 | #include <linux/of.h> | ||
31 | #include <linux/of_device.h> | 34 | #include <linux/of_device.h> |
35 | #include <linux/platform_device.h> | ||
32 | 36 | ||
33 | #include <asm/oplib.h> | 37 | #include <asm/oplib.h> |
34 | #include <asm/timer.h> | 38 | #include <asm/timer.h> |
35 | #include <asm/mostek.h> | ||
36 | #include <asm/system.h> | 39 | #include <asm/system.h> |
37 | #include <asm/irq.h> | 40 | #include <asm/irq.h> |
38 | #include <asm/io.h> | 41 | #include <asm/io.h> |
39 | #include <asm/idprom.h> | 42 | #include <asm/idprom.h> |
40 | #include <asm/machines.h> | 43 | #include <asm/machines.h> |
41 | #include <asm/sun4paddr.h> | ||
42 | #include <asm/page.h> | 44 | #include <asm/page.h> |
43 | #include <asm/pcic.h> | 45 | #include <asm/pcic.h> |
44 | #include <asm/irq_regs.h> | 46 | #include <asm/irq_regs.h> |
@@ -46,34 +48,9 @@ | |||
46 | #include "irq.h" | 48 | #include "irq.h" |
47 | 49 | ||
48 | DEFINE_SPINLOCK(rtc_lock); | 50 | DEFINE_SPINLOCK(rtc_lock); |
49 | static enum sparc_clock_type sp_clock_typ; | ||
50 | DEFINE_SPINLOCK(mostek_lock); | ||
51 | void __iomem *mstk48t02_regs = NULL; | ||
52 | static struct mostek48t08 __iomem *mstk48t08_regs = NULL; | ||
53 | static int set_rtc_mmss(unsigned long); | 51 | static int set_rtc_mmss(unsigned long); |
54 | static int sbus_do_settimeofday(struct timespec *tv); | 52 | static int sbus_do_settimeofday(struct timespec *tv); |
55 | 53 | ||
56 | #ifdef CONFIG_SUN4 | ||
57 | struct intersil *intersil_clock; | ||
58 | #define intersil_cmd(intersil_reg, intsil_cmd) intersil_reg->int_cmd_reg = \ | ||
59 | (intsil_cmd) | ||
60 | |||
61 | #define intersil_intr(intersil_reg, intsil_cmd) intersil_reg->int_intr_reg = \ | ||
62 | (intsil_cmd) | ||
63 | |||
64 | #define intersil_start(intersil_reg) intersil_cmd(intersil_reg, \ | ||
65 | ( INTERSIL_START | INTERSIL_32K | INTERSIL_NORMAL | INTERSIL_24H |\ | ||
66 | INTERSIL_INTR_ENABLE)) | ||
67 | |||
68 | #define intersil_stop(intersil_reg) intersil_cmd(intersil_reg, \ | ||
69 | ( INTERSIL_STOP | INTERSIL_32K | INTERSIL_NORMAL | INTERSIL_24H |\ | ||
70 | INTERSIL_INTR_ENABLE)) | ||
71 | |||
72 | #define intersil_read_intr(intersil_reg, towhere) towhere = \ | ||
73 | intersil_reg->int_intr_reg | ||
74 | |||
75 | #endif | ||
76 | |||
77 | unsigned long profile_pc(struct pt_regs *regs) | 54 | unsigned long profile_pc(struct pt_regs *regs) |
78 | { | 55 | { |
79 | extern char __copy_user_begin[], __copy_user_end[]; | 56 | extern char __copy_user_begin[], __copy_user_end[]; |
@@ -96,7 +73,6 @@ unsigned long profile_pc(struct pt_regs *regs) | |||
96 | EXPORT_SYMBOL(profile_pc); | 73 | EXPORT_SYMBOL(profile_pc); |
97 | 74 | ||
98 | __volatile__ unsigned int *master_l10_counter; | 75 | __volatile__ unsigned int *master_l10_counter; |
99 | __volatile__ unsigned int *master_l10_limit; | ||
100 | 76 | ||
101 | /* | 77 | /* |
102 | * timer_interrupt() needs to keep up the real-time clock, | 78 | * timer_interrupt() needs to keep up the real-time clock, |
@@ -116,15 +92,7 @@ static irqreturn_t timer_interrupt(int dummy, void *dev_id) | |||
116 | 92 | ||
117 | /* Protect counter clear so that do_gettimeoffset works */ | 93 | /* Protect counter clear so that do_gettimeoffset works */ |
118 | write_seqlock(&xtime_lock); | 94 | write_seqlock(&xtime_lock); |
119 | #ifdef CONFIG_SUN4 | 95 | |
120 | if((idprom->id_machtype == (SM_SUN4 | SM_4_260)) || | ||
121 | (idprom->id_machtype == (SM_SUN4 | SM_4_110))) { | ||
122 | int temp; | ||
123 | intersil_read_intr(intersil_clock, temp); | ||
124 | /* re-enable the irq */ | ||
125 | enable_pil_irq(10); | ||
126 | } | ||
127 | #endif | ||
128 | clear_clock_irq(); | 96 | clear_clock_irq(); |
129 | 97 | ||
130 | do_timer(1); | 98 | do_timer(1); |
@@ -147,157 +115,56 @@ static irqreturn_t timer_interrupt(int dummy, void *dev_id) | |||
147 | return IRQ_HANDLED; | 115 | return IRQ_HANDLED; |
148 | } | 116 | } |
149 | 117 | ||
150 | /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ | 118 | static unsigned char mostek_read_byte(struct device *dev, u32 ofs) |
151 | static void __devinit kick_start_clock(void) | ||
152 | { | 119 | { |
153 | struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; | 120 | struct platform_device *pdev = to_platform_device(dev); |
154 | unsigned char sec; | 121 | struct m48t59_plat_data *pdata = pdev->dev.platform_data; |
155 | int i, count; | 122 | void __iomem *regs = pdata->ioaddr; |
156 | 123 | unsigned char val = readb(regs + ofs); | |
157 | prom_printf("CLOCK: Clock was stopped. Kick start "); | 124 | |
158 | 125 | /* the year 0 is 1968 */ | |
159 | spin_lock_irq(&mostek_lock); | 126 | if (ofs == pdata->offset + M48T59_YEAR) { |
160 | 127 | val += 0x68; | |
161 | /* Turn on the kick start bit to start the oscillator. */ | 128 | if ((val & 0xf) > 9) |
162 | regs->creg |= MSTK_CREG_WRITE; | 129 | val += 6; |
163 | regs->sec &= ~MSTK_STOP; | ||
164 | regs->hour |= MSTK_KICK_START; | ||
165 | regs->creg &= ~MSTK_CREG_WRITE; | ||
166 | |||
167 | spin_unlock_irq(&mostek_lock); | ||
168 | |||
169 | /* Delay to allow the clock oscillator to start. */ | ||
170 | sec = MSTK_REG_SEC(regs); | ||
171 | for (i = 0; i < 3; i++) { | ||
172 | while (sec == MSTK_REG_SEC(regs)) | ||
173 | for (count = 0; count < 100000; count++) | ||
174 | /* nothing */ ; | ||
175 | prom_printf("."); | ||
176 | sec = regs->sec; | ||
177 | } | ||
178 | prom_printf("\n"); | ||
179 | |||
180 | spin_lock_irq(&mostek_lock); | ||
181 | |||
182 | /* Turn off kick start and set a "valid" time and date. */ | ||
183 | regs->creg |= MSTK_CREG_WRITE; | ||
184 | regs->hour &= ~MSTK_KICK_START; | ||
185 | MSTK_SET_REG_SEC(regs,0); | ||
186 | MSTK_SET_REG_MIN(regs,0); | ||
187 | MSTK_SET_REG_HOUR(regs,0); | ||
188 | MSTK_SET_REG_DOW(regs,5); | ||
189 | MSTK_SET_REG_DOM(regs,1); | ||
190 | MSTK_SET_REG_MONTH(regs,8); | ||
191 | MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO); | ||
192 | regs->creg &= ~MSTK_CREG_WRITE; | ||
193 | |||
194 | spin_unlock_irq(&mostek_lock); | ||
195 | |||
196 | /* Ensure the kick start bit is off. If it isn't, turn it off. */ | ||
197 | while (regs->hour & MSTK_KICK_START) { | ||
198 | prom_printf("CLOCK: Kick start still on!\n"); | ||
199 | |||
200 | spin_lock_irq(&mostek_lock); | ||
201 | regs->creg |= MSTK_CREG_WRITE; | ||
202 | regs->hour &= ~MSTK_KICK_START; | ||
203 | regs->creg &= ~MSTK_CREG_WRITE; | ||
204 | spin_unlock_irq(&mostek_lock); | ||
205 | } | 130 | } |
206 | 131 | return val; | |
207 | prom_printf("CLOCK: Kick start procedure successful.\n"); | ||
208 | } | ||
209 | |||
210 | /* Return nonzero if the clock chip battery is low. */ | ||
211 | static inline int has_low_battery(void) | ||
212 | { | ||
213 | struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; | ||
214 | unsigned char data1, data2; | ||
215 | |||
216 | spin_lock_irq(&mostek_lock); | ||
217 | data1 = regs->eeprom[0]; /* Read some data. */ | ||
218 | regs->eeprom[0] = ~data1; /* Write back the complement. */ | ||
219 | data2 = regs->eeprom[0]; /* Read back the complement. */ | ||
220 | regs->eeprom[0] = data1; /* Restore the original value. */ | ||
221 | spin_unlock_irq(&mostek_lock); | ||
222 | |||
223 | return (data1 == data2); /* Was the write blocked? */ | ||
224 | } | 132 | } |
225 | 133 | ||
226 | static void __devinit mostek_set_system_time(void) | 134 | static void mostek_write_byte(struct device *dev, u32 ofs, u8 val) |
227 | { | 135 | { |
228 | unsigned int year, mon, day, hour, min, sec; | 136 | struct platform_device *pdev = to_platform_device(dev); |
229 | struct mostek48t02 *mregs; | 137 | struct m48t59_plat_data *pdata = pdev->dev.platform_data; |
230 | 138 | void __iomem *regs = pdata->ioaddr; | |
231 | mregs = (struct mostek48t02 *)mstk48t02_regs; | 139 | |
232 | if(!mregs) { | 140 | if (ofs == pdata->offset + M48T59_YEAR) { |
233 | prom_printf("Something wrong, clock regs not mapped yet.\n"); | 141 | if (val < 0x68) |
234 | prom_halt(); | 142 | val += 0x32; |
235 | } | 143 | else |
236 | spin_lock_irq(&mostek_lock); | 144 | val -= 0x68; |
237 | mregs->creg |= MSTK_CREG_READ; | 145 | if ((val & 0xf) > 9) |
238 | sec = MSTK_REG_SEC(mregs); | 146 | val += 6; |
239 | min = MSTK_REG_MIN(mregs); | 147 | if ((val & 0xf0) > 0x9A) |
240 | hour = MSTK_REG_HOUR(mregs); | 148 | val += 0x60; |
241 | day = MSTK_REG_DOM(mregs); | 149 | } |
242 | mon = MSTK_REG_MONTH(mregs); | 150 | writeb(val, regs + ofs); |
243 | year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) ); | ||
244 | xtime.tv_sec = mktime(year, mon, day, hour, min, sec); | ||
245 | xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | ||
246 | set_normalized_timespec(&wall_to_monotonic, | ||
247 | -xtime.tv_sec, -xtime.tv_nsec); | ||
248 | mregs->creg &= ~MSTK_CREG_READ; | ||
249 | spin_unlock_irq(&mostek_lock); | ||
250 | } | 151 | } |
251 | 152 | ||
252 | /* Probe for the real time clock chip on Sun4 */ | 153 | static struct m48t59_plat_data m48t59_data = { |
253 | static inline void sun4_clock_probe(void) | 154 | .read_byte = mostek_read_byte, |
254 | { | 155 | .write_byte = mostek_write_byte, |
255 | #ifdef CONFIG_SUN4 | 156 | }; |
256 | int temp; | ||
257 | struct resource r; | ||
258 | |||
259 | memset(&r, 0, sizeof(r)); | ||
260 | if( idprom->id_machtype == (SM_SUN4 | SM_4_330) ) { | ||
261 | sp_clock_typ = MSTK48T02; | ||
262 | r.start = sun4_clock_physaddr; | ||
263 | mstk48t02_regs = sbus_ioremap(&r, 0, | ||
264 | sizeof(struct mostek48t02), NULL); | ||
265 | mstk48t08_regs = NULL; /* To catch weirdness */ | ||
266 | intersil_clock = NULL; /* just in case */ | ||
267 | |||
268 | /* Kick start the clock if it is completely stopped. */ | ||
269 | if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP) | ||
270 | kick_start_clock(); | ||
271 | } else if( idprom->id_machtype == (SM_SUN4 | SM_4_260)) { | ||
272 | /* intersil setup code */ | ||
273 | printk("Clock: INTERSIL at %8x ",sun4_clock_physaddr); | ||
274 | sp_clock_typ = INTERSIL; | ||
275 | r.start = sun4_clock_physaddr; | ||
276 | intersil_clock = (struct intersil *) | ||
277 | sbus_ioremap(&r, 0, sizeof(*intersil_clock), "intersil"); | ||
278 | mstk48t02_regs = 0; /* just be sure */ | ||
279 | mstk48t08_regs = NULL; /* ditto */ | ||
280 | /* initialise the clock */ | ||
281 | |||
282 | intersil_intr(intersil_clock,INTERSIL_INT_100HZ); | ||
283 | |||
284 | intersil_start(intersil_clock); | ||
285 | |||
286 | intersil_read_intr(intersil_clock, temp); | ||
287 | while (!(temp & 0x80)) | ||
288 | intersil_read_intr(intersil_clock, temp); | ||
289 | |||
290 | intersil_read_intr(intersil_clock, temp); | ||
291 | while (!(temp & 0x80)) | ||
292 | intersil_read_intr(intersil_clock, temp); | ||
293 | |||
294 | intersil_stop(intersil_clock); | ||
295 | 157 | ||
296 | } | 158 | /* resource is set at runtime */ |
297 | #endif | 159 | static struct platform_device m48t59_rtc = { |
298 | } | 160 | .name = "rtc-m48t59", |
161 | .id = 0, | ||
162 | .num_resources = 1, | ||
163 | .dev = { | ||
164 | .platform_data = &m48t59_data, | ||
165 | }, | ||
166 | }; | ||
299 | 167 | ||
300 | #ifndef CONFIG_SUN4 | ||
301 | static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match) | 168 | static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match) |
302 | { | 169 | { |
303 | struct device_node *dp = op->node; | 170 | struct device_node *dp = op->node; |
@@ -306,38 +173,26 @@ static int __devinit clock_probe(struct of_device *op, const struct of_device_id | |||
306 | if (!model) | 173 | if (!model) |
307 | return -ENODEV; | 174 | return -ENODEV; |
308 | 175 | ||
176 | m48t59_rtc.resource = &op->resource[0]; | ||
309 | if (!strcmp(model, "mk48t02")) { | 177 | if (!strcmp(model, "mk48t02")) { |
310 | sp_clock_typ = MSTK48T02; | ||
311 | |||
312 | /* Map the clock register io area read-only */ | 178 | /* Map the clock register io area read-only */ |
313 | mstk48t02_regs = of_ioremap(&op->resource[0], 0, | 179 | m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0, |
314 | sizeof(struct mostek48t02), | 180 | 2048, "rtc-m48t59"); |
315 | "mk48t02"); | 181 | m48t59_data.type = M48T59RTC_TYPE_M48T02; |
316 | mstk48t08_regs = NULL; /* To catch weirdness */ | ||
317 | } else if (!strcmp(model, "mk48t08")) { | 182 | } else if (!strcmp(model, "mk48t08")) { |
318 | sp_clock_typ = MSTK48T08; | 183 | m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0, |
319 | mstk48t08_regs = of_ioremap(&op->resource[0], 0, | 184 | 8192, "rtc-m48t59"); |
320 | sizeof(struct mostek48t08), | 185 | m48t59_data.type = M48T59RTC_TYPE_M48T08; |
321 | "mk48t08"); | ||
322 | |||
323 | mstk48t02_regs = &mstk48t08_regs->regs; | ||
324 | } else | 186 | } else |
325 | return -ENODEV; | 187 | return -ENODEV; |
326 | 188 | ||
327 | /* Report a low battery voltage condition. */ | 189 | if (platform_device_register(&m48t59_rtc) < 0) |
328 | if (has_low_battery()) | 190 | printk(KERN_ERR "Registering RTC device failed\n"); |
329 | printk(KERN_CRIT "NVRAM: Low battery voltage!\n"); | ||
330 | |||
331 | /* Kick start the clock if it is completely stopped. */ | ||
332 | if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP) | ||
333 | kick_start_clock(); | ||
334 | |||
335 | mostek_set_system_time(); | ||
336 | 191 | ||
337 | return 0; | 192 | return 0; |
338 | } | 193 | } |
339 | 194 | ||
340 | static struct of_device_id clock_match[] = { | 195 | static struct of_device_id __initdata clock_match[] = { |
341 | { | 196 | { |
342 | .name = "eeprom", | 197 | .name = "eeprom", |
343 | }, | 198 | }, |
@@ -348,7 +203,7 @@ static struct of_platform_driver clock_driver = { | |||
348 | .match_table = clock_match, | 203 | .match_table = clock_match, |
349 | .probe = clock_probe, | 204 | .probe = clock_probe, |
350 | .driver = { | 205 | .driver = { |
351 | .name = "clock", | 206 | .name = "rtc", |
352 | }, | 207 | }, |
353 | }; | 208 | }; |
354 | 209 | ||
@@ -364,7 +219,6 @@ static int __init clock_init(void) | |||
364 | * need to see the clock registers. | 219 | * need to see the clock registers. |
365 | */ | 220 | */ |
366 | fs_initcall(clock_init); | 221 | fs_initcall(clock_init); |
367 | #endif /* !CONFIG_SUN4 */ | ||
368 | 222 | ||
369 | static void __init sbus_time_init(void) | 223 | static void __init sbus_time_init(void) |
370 | { | 224 | { |
@@ -372,51 +226,8 @@ static void __init sbus_time_init(void) | |||
372 | BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM); | 226 | BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM); |
373 | btfixup(); | 227 | btfixup(); |
374 | 228 | ||
375 | if (ARCH_SUN4) | ||
376 | sun4_clock_probe(); | ||
377 | |||
378 | sparc_init_timers(timer_interrupt); | 229 | sparc_init_timers(timer_interrupt); |
379 | 230 | ||
380 | #ifdef CONFIG_SUN4 | ||
381 | if(idprom->id_machtype == (SM_SUN4 | SM_4_330)) { | ||
382 | mostek_set_system_time(); | ||
383 | } else if(idprom->id_machtype == (SM_SUN4 | SM_4_260) ) { | ||
384 | /* initialise the intersil on sun4 */ | ||
385 | unsigned int year, mon, day, hour, min, sec; | ||
386 | int temp; | ||
387 | struct intersil *iregs; | ||
388 | |||
389 | iregs=intersil_clock; | ||
390 | if(!iregs) { | ||
391 | prom_printf("Something wrong, clock regs not mapped yet.\n"); | ||
392 | prom_halt(); | ||
393 | } | ||
394 | |||
395 | intersil_intr(intersil_clock,INTERSIL_INT_100HZ); | ||
396 | disable_pil_irq(10); | ||
397 | intersil_stop(iregs); | ||
398 | intersil_read_intr(intersil_clock, temp); | ||
399 | |||
400 | temp = iregs->clk.int_csec; | ||
401 | |||
402 | sec = iregs->clk.int_sec; | ||
403 | min = iregs->clk.int_min; | ||
404 | hour = iregs->clk.int_hour; | ||
405 | day = iregs->clk.int_day; | ||
406 | mon = iregs->clk.int_month; | ||
407 | year = MSTK_CVT_YEAR(iregs->clk.int_year); | ||
408 | |||
409 | enable_pil_irq(10); | ||
410 | intersil_start(iregs); | ||
411 | |||
412 | xtime.tv_sec = mktime(year, mon, day, hour, min, sec); | ||
413 | xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | ||
414 | set_normalized_timespec(&wall_to_monotonic, | ||
415 | -xtime.tv_sec, -xtime.tv_nsec); | ||
416 | printk("%u/%u/%u %u:%u:%u\n",day,mon,year,hour,min,sec); | ||
417 | } | ||
418 | #endif | ||
419 | |||
420 | /* Now that OBP ticker has been silenced, it is safe to enable IRQ. */ | 231 | /* Now that OBP ticker has been silenced, it is safe to enable IRQ. */ |
421 | local_irq_enable(); | 232 | local_irq_enable(); |
422 | } | 233 | } |
@@ -522,80 +333,15 @@ static int sbus_do_settimeofday(struct timespec *tv) | |||
522 | return 0; | 333 | return 0; |
523 | } | 334 | } |
524 | 335 | ||
525 | /* | 336 | static int set_rtc_mmss(unsigned long secs) |
526 | * BUG: This routine does not handle hour overflow properly; it just | ||
527 | * sets the minutes. Usually you won't notice until after reboot! | ||
528 | */ | ||
529 | static int set_rtc_mmss(unsigned long nowtime) | ||
530 | { | 337 | { |
531 | int real_seconds, real_minutes, mostek_minutes; | 338 | struct rtc_device *rtc = rtc_class_open("rtc0"); |
532 | struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; | 339 | int err = -1; |
533 | unsigned long flags; | ||
534 | #ifdef CONFIG_SUN4 | ||
535 | struct intersil *iregs = intersil_clock; | ||
536 | int temp; | ||
537 | #endif | ||
538 | 340 | ||
539 | /* Not having a register set can lead to trouble. */ | 341 | if (rtc) { |
540 | if (!regs) { | 342 | err = rtc_set_mmss(rtc, secs); |
541 | #ifdef CONFIG_SUN4 | 343 | rtc_class_close(rtc); |
542 | if(!iregs) | ||
543 | return -1; | ||
544 | else { | ||
545 | temp = iregs->clk.int_csec; | ||
546 | |||
547 | mostek_minutes = iregs->clk.int_min; | ||
548 | |||
549 | real_seconds = nowtime % 60; | ||
550 | real_minutes = nowtime / 60; | ||
551 | if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1) | ||
552 | real_minutes += 30; /* correct for half hour time zone */ | ||
553 | real_minutes %= 60; | ||
554 | |||
555 | if (abs(real_minutes - mostek_minutes) < 30) { | ||
556 | intersil_stop(iregs); | ||
557 | iregs->clk.int_sec=real_seconds; | ||
558 | iregs->clk.int_min=real_minutes; | ||
559 | intersil_start(iregs); | ||
560 | } else { | ||
561 | printk(KERN_WARNING | ||
562 | "set_rtc_mmss: can't update from %d to %d\n", | ||
563 | mostek_minutes, real_minutes); | ||
564 | return -1; | ||
565 | } | ||
566 | |||
567 | return 0; | ||
568 | } | ||
569 | #endif | ||
570 | } | 344 | } |
571 | 345 | ||
572 | spin_lock_irqsave(&mostek_lock, flags); | 346 | return err; |
573 | /* Read the current RTC minutes. */ | ||
574 | regs->creg |= MSTK_CREG_READ; | ||
575 | mostek_minutes = MSTK_REG_MIN(regs); | ||
576 | regs->creg &= ~MSTK_CREG_READ; | ||
577 | |||
578 | /* | ||
579 | * since we're only adjusting minutes and seconds, | ||
580 | * don't interfere with hour overflow. This avoids | ||
581 | * messing with unknown time zones but requires your | ||
582 | * RTC not to be off by more than 15 minutes | ||
583 | */ | ||
584 | real_seconds = nowtime % 60; | ||
585 | real_minutes = nowtime / 60; | ||
586 | if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1) | ||
587 | real_minutes += 30; /* correct for half hour time zone */ | ||
588 | real_minutes %= 60; | ||
589 | |||
590 | if (abs(real_minutes - mostek_minutes) < 30) { | ||
591 | regs->creg |= MSTK_CREG_WRITE; | ||
592 | MSTK_SET_REG_SEC(regs,real_seconds); | ||
593 | MSTK_SET_REG_MIN(regs,real_minutes); | ||
594 | regs->creg &= ~MSTK_CREG_WRITE; | ||
595 | spin_unlock_irqrestore(&mostek_lock, flags); | ||
596 | return 0; | ||
597 | } else { | ||
598 | spin_unlock_irqrestore(&mostek_lock, flags); | ||
599 | return -1; | ||
600 | } | ||
601 | } | 347 | } |