aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh64/kernel/time.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2007-11-08 00:45:55 -0500
committerPaul Mundt <lethal@linux-sh.org>2008-01-27 23:18:38 -0500
commit6c7e2a55d3f89deb5bc478ab1759a3a799890c7d (patch)
treedace0466f6e305aa4fb5ed23465d6fd3c75e3c6c /arch/sh64/kernel/time.c
parent9a519f62a18c258c8ba695f82b6a9542bde4ca06 (diff)
sh64: Use the generic rtc-sh driver.
Rip out the sh64-specific RTC bits, use rtc-sh instead. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh64/kernel/time.c')
-rw-r--r--arch/sh64/kernel/time.c196
1 files changed, 67 insertions, 129 deletions
diff --git a/arch/sh64/kernel/time.c b/arch/sh64/kernel/time.c
index 06f3c179e345..d1a9b5b078bd 100644
--- a/arch/sh64/kernel/time.c
+++ b/arch/sh64/kernel/time.c
@@ -6,7 +6,7 @@
6 * arch/sh64/kernel/time.c 6 * arch/sh64/kernel/time.c
7 * 7 *
8 * Copyright (C) 2000, 2001 Paolo Alberelli 8 * Copyright (C) 2000, 2001 Paolo Alberelli
9 * Copyright (C) 2003, 2004 Paul Mundt 9 * Copyright (C) 2003 - 2007 Paul Mundt
10 * Copyright (C) 2003 Richard Curnow 10 * Copyright (C) 2003 Richard Curnow
11 * 11 *
12 * Original TMU/RTC code taken from sh version. 12 * Original TMU/RTC code taken from sh version.
@@ -14,7 +14,6 @@
14 * Some code taken from i386 version. 14 * Some code taken from i386 version.
15 * Copyright (C) 1991, 1992, 1995 Linus Torvalds 15 * Copyright (C) 1991, 1992, 1995 Linus Torvalds
16 */ 16 */
17
18#include <linux/errno.h> 17#include <linux/errno.h>
19#include <linux/rwsem.h> 18#include <linux/rwsem.h>
20#include <linux/sched.h> 19#include <linux/sched.h>
@@ -30,17 +29,15 @@
30#include <linux/smp.h> 29#include <linux/smp.h>
31#include <linux/module.h> 30#include <linux/module.h>
32#include <linux/bcd.h> 31#include <linux/bcd.h>
33 32#include <linux/timex.h>
33#include <linux/irq.h>
34#include <linux/platform_device.h>
34#include <asm/registers.h> /* required by inline __asm__ stmt. */ 35#include <asm/registers.h> /* required by inline __asm__ stmt. */
35
36#include <asm/processor.h> 36#include <asm/processor.h>
37#include <asm/uaccess.h> 37#include <asm/uaccess.h>
38#include <asm/io.h> 38#include <asm/io.h>
39#include <asm/irq.h> 39#include <asm/irq.h>
40#include <asm/delay.h> 40#include <asm/delay.h>
41
42#include <linux/timex.h>
43#include <linux/irq.h>
44#include <asm/hardware.h> 41#include <asm/hardware.h>
45 42
46#define TMU_TOCR_INIT 0x00 43#define TMU_TOCR_INIT 0x00
@@ -48,19 +45,11 @@
48#define TMU_TSTR_INIT 1 45#define TMU_TSTR_INIT 1
49#define TMU_TSTR_OFF 0 46#define TMU_TSTR_OFF 0
50 47
51/* RCR1 Bits */ 48/* Real Time Clock */
52#define RCR1_CF 0x80 /* Carry Flag */ 49#define RTC_BLOCK_OFF 0x01040000
53#define RCR1_CIE 0x10 /* Carry Interrupt Enable */ 50#define RTC_BASE PHYS_PERIPHERAL_BLOCK + RTC_BLOCK_OFF
54#define RCR1_AIE 0x08 /* Alarm Interrupt Enable */ 51#define RTC_RCR1_CIE 0x10 /* Carry Interrupt Enable */
55#define RCR1_AF 0x01 /* Alarm Flag */ 52#define RTC_RCR1 (rtc_base + 0x38)
56
57/* RCR2 Bits */
58#define RCR2_PEF 0x80 /* PEriodic interrupt Flag */
59#define RCR2_PESMASK 0x70 /* Periodic interrupt Set */
60#define RCR2_RTCEN 0x08 /* ENable RTC */
61#define RCR2_ADJ 0x04 /* ADJustment (30-second) */
62#define RCR2_RESET 0x02 /* Reset bit */
63#define RCR2_START 0x01 /* Start bit */
64 53
65/* Clock, Power and Reset Controller */ 54/* Clock, Power and Reset Controller */
66#define CPRC_BLOCK_OFF 0x01010000 55#define CPRC_BLOCK_OFF 0x01010000
@@ -84,27 +73,6 @@
84#define TMU0_TCNT TMU0_BASE+0x4 /* Long access */ 73#define TMU0_TCNT TMU0_BASE+0x4 /* Long access */
85#define TMU0_TCR TMU0_BASE+0x8 /* Word access */ 74#define TMU0_TCR TMU0_BASE+0x8 /* Word access */
86 75
87/* Real Time Clock */
88#define RTC_BLOCK_OFF 0x01040000
89#define RTC_BASE PHYS_PERIPHERAL_BLOCK + RTC_BLOCK_OFF
90
91#define R64CNT rtc_base+0x00
92#define RSECCNT rtc_base+0x04
93#define RMINCNT rtc_base+0x08
94#define RHRCNT rtc_base+0x0c
95#define RWKCNT rtc_base+0x10
96#define RDAYCNT rtc_base+0x14
97#define RMONCNT rtc_base+0x18
98#define RYRCNT rtc_base+0x1c /* 16bit */
99#define RSECAR rtc_base+0x20
100#define RMINAR rtc_base+0x24
101#define RHRAR rtc_base+0x28
102#define RWKAR rtc_base+0x2c
103#define RDAYAR rtc_base+0x30
104#define RMONAR rtc_base+0x34
105#define RCR1 rtc_base+0x38
106#define RCR2 rtc_base+0x3c
107
108#define TICK_SIZE (tick_nsec / 1000) 76#define TICK_SIZE (tick_nsec / 1000)
109 77
110static unsigned long tmu_base, rtc_base; 78static unsigned long tmu_base, rtc_base;
@@ -236,47 +204,23 @@ int do_settimeofday(struct timespec *tv)
236} 204}
237EXPORT_SYMBOL(do_settimeofday); 205EXPORT_SYMBOL(do_settimeofday);
238 206
239static int set_rtc_time(unsigned long nowtime) 207/* Dummy RTC ops */
208static void null_rtc_get_time(struct timespec *tv)
240{ 209{
241 int retval = 0; 210 tv->tv_sec = mktime(2000, 1, 1, 0, 0, 0);
242 int real_seconds, real_minutes, cmos_minutes; 211 tv->tv_nsec = 0;
243 212}
244 ctrl_outb(RCR2_RESET, RCR2); /* Reset pre-scaler & stop RTC */
245
246 cmos_minutes = ctrl_inb(RMINCNT);
247 BCD_TO_BIN(cmos_minutes);
248
249 /*
250 * since we're only adjusting minutes and seconds,
251 * don't interfere with hour overflow. This avoids
252 * messing with unknown time zones but requires your
253 * RTC not to be off by more than 15 minutes
254 */
255 real_seconds = nowtime % 60;
256 real_minutes = nowtime / 60;
257 if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
258 real_minutes += 30; /* correct for half hour time zone */
259 real_minutes %= 60;
260
261 if (abs(real_minutes - cmos_minutes) < 30) {
262 BIN_TO_BCD(real_seconds);
263 BIN_TO_BCD(real_minutes);
264 ctrl_outb(real_seconds, RSECCNT);
265 ctrl_outb(real_minutes, RMINCNT);
266 } else {
267 printk(KERN_WARNING
268 "set_rtc_time: can't update from %d to %d\n",
269 cmos_minutes, real_minutes);
270 retval = -1;
271 }
272
273 ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start RTC */
274 213
275 return retval; 214static int null_rtc_set_time(const time_t secs)
215{
216 return 0;
276} 217}
277 218
219void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
220int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
221
278/* last time the RTC clock got updated */ 222/* last time the RTC clock got updated */
279static long last_rtc_update = 0; 223static long last_rtc_update;
280 224
281/* 225/*
282 * timer_interrupt() needs to keep up the real-time clock, 226 * timer_interrupt() needs to keep up the real-time clock,
@@ -312,10 +256,11 @@ static inline void do_timer_interrupt(void)
312 xtime.tv_sec > last_rtc_update + 660 && 256 xtime.tv_sec > last_rtc_update + 660 &&
313 (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && 257 (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
314 (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { 258 (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
315 if (set_rtc_time(xtime.tv_sec) == 0) 259 if (rtc_sh_set_time(xtime.tv_sec) == 0)
316 last_rtc_update = xtime.tv_sec; 260 last_rtc_update = xtime.tv_sec;
317 else 261 else
318 last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ 262 /* do it again in 60 s */
263 last_rtc_update = xtime.tv_sec - 600;
319 } 264 }
320} 265}
321 266
@@ -347,50 +292,6 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
347 return IRQ_HANDLED; 292 return IRQ_HANDLED;
348} 293}
349 294
350static unsigned long get_rtc_time(void)
351{
352 unsigned int sec, min, hr, wk, day, mon, yr, yr100;
353
354 again:
355 do {
356 ctrl_outb(0, RCR1); /* Clear CF-bit */
357 sec = ctrl_inb(RSECCNT);
358 min = ctrl_inb(RMINCNT);
359 hr = ctrl_inb(RHRCNT);
360 wk = ctrl_inb(RWKCNT);
361 day = ctrl_inb(RDAYCNT);
362 mon = ctrl_inb(RMONCNT);
363 yr = ctrl_inw(RYRCNT);
364 yr100 = (yr >> 8);
365 yr &= 0xff;
366 } while ((ctrl_inb(RCR1) & RCR1_CF) != 0);
367
368 BCD_TO_BIN(yr100);
369 BCD_TO_BIN(yr);
370 BCD_TO_BIN(mon);
371 BCD_TO_BIN(day);
372 BCD_TO_BIN(hr);
373 BCD_TO_BIN(min);
374 BCD_TO_BIN(sec);
375
376 if (yr > 99 || mon < 1 || mon > 12 || day > 31 || day < 1 ||
377 hr > 23 || min > 59 || sec > 59) {
378 printk(KERN_ERR
379 "SH RTC: invalid value, resetting to 1 Jan 2000\n");
380 ctrl_outb(RCR2_RESET, RCR2); /* Reset & Stop */
381 ctrl_outb(0, RSECCNT);
382 ctrl_outb(0, RMINCNT);
383 ctrl_outb(0, RHRCNT);
384 ctrl_outb(6, RWKCNT);
385 ctrl_outb(1, RDAYCNT);
386 ctrl_outb(1, RMONCNT);
387 ctrl_outw(0x2000, RYRCNT);
388 ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start */
389 goto again;
390 }
391
392 return mktime(yr100 * 100 + yr, mon, day, hr, min, sec);
393}
394 295
395static __init unsigned int get_cpu_hz(void) 296static __init unsigned int get_cpu_hz(void)
396{ 297{
@@ -406,8 +307,8 @@ static __init unsigned int get_cpu_hz(void)
406 register unsigned long long __rtc_irq_flag __asm__ ("r3"); 307 register unsigned long long __rtc_irq_flag __asm__ ("r3");
407 308
408 local_irq_enable(); 309 local_irq_enable();
409 do {} while (ctrl_inb(R64CNT) != 0); 310 do {} while (ctrl_inb(rtc_base) != 0);
410 ctrl_outb(RCR1_CIE, RCR1); /* Enable carry interrupt */ 311 ctrl_outb(RTC_RCR1_CIE, RTC_RCR1); /* Enable carry interrupt */
411 312
412 /* 313 /*
413 * r3 is arbitrary. CDC does not support "=z". 314 * r3 is arbitrary. CDC does not support "=z".
@@ -470,7 +371,7 @@ static irqreturn_t sh64_rtc_interrupt(int irq, void *dev_id)
470{ 371{
471 struct pt_regs *regs = get_irq_regs(); 372 struct pt_regs *regs = get_irq_regs();
472 373
473 ctrl_outb(0, RCR1); /* Disable Carry Interrupts */ 374 ctrl_outb(0, RTC_RCR1); /* Disable Carry Interrupts */
474 regs->regs[3] = 1; /* Using r3 */ 375 regs->regs[3] = 1; /* Using r3 */
475 376
476 return IRQ_HANDLED; 377 return IRQ_HANDLED;
@@ -513,8 +414,7 @@ void __init time_init(void)
513 panic("Unable to remap CPRC\n"); 414 panic("Unable to remap CPRC\n");
514 } 415 }
515 416
516 xtime.tv_sec = get_rtc_time(); 417 rtc_sh_get_time(&xtime);
517 xtime.tv_nsec = 0;
518 418
519 setup_irq(TIMER_IRQ, &irq0); 419 setup_irq(TIMER_IRQ, &irq0);
520 setup_irq(RTC_IRQ, &irq1); 420 setup_irq(RTC_IRQ, &irq1);
@@ -525,7 +425,7 @@ void __init time_init(void)
525 /* Note careful order of operations to maintain reasonable precision and avoid overflow. */ 425 /* Note careful order of operations to maintain reasonable precision and avoid overflow. */
526 scaled_recip_ctc_ticks_per_jiffy = ((1ULL << CTC_JIFFY_SCALE_SHIFT) / (unsigned long long)(cpu_clock / HZ)); 426 scaled_recip_ctc_ticks_per_jiffy = ((1ULL << CTC_JIFFY_SCALE_SHIFT) / (unsigned long long)(cpu_clock / HZ));
527 427
528 disable_irq(RTC_IRQ); 428 free_irq(RTC_IRQ, NULL);
529 429
530 printk("CPU clock: %d.%02dMHz\n", 430 printk("CPU clock: %d.%02dMHz\n",
531 (cpu_clock / 1000000), (cpu_clock % 1000000)/10000); 431 (cpu_clock / 1000000), (cpu_clock % 1000000)/10000);
@@ -591,3 +491,41 @@ void enter_deep_standby(void)
591 asm __volatile__ ("nop"); 491 asm __volatile__ ("nop");
592 panic("Unexpected wakeup!\n"); 492 panic("Unexpected wakeup!\n");
593} 493}
494
495static struct resource rtc_resources[] = {
496 [0] = {
497 /* RTC base, filled in by rtc_init */
498 .flags = IORESOURCE_IO,
499 },
500 [1] = {
501 /* Period IRQ */
502 .start = IRQ_PRI,
503 .flags = IORESOURCE_IRQ,
504 },
505 [2] = {
506 /* Carry IRQ */
507 .start = IRQ_CUI,
508 .flags = IORESOURCE_IRQ,
509 },
510 [3] = {
511 /* Alarm IRQ */
512 .start = IRQ_ATI,
513 .flags = IORESOURCE_IRQ,
514 },
515};
516
517static struct platform_device rtc_device = {
518 .name = "sh-rtc",
519 .id = -1,
520 .num_resources = ARRAY_SIZE(rtc_resources),
521 .resource = rtc_resources,
522};
523
524static int __init rtc_init(void)
525{
526 rtc_resources[0].start = rtc_base;
527 rtc_resources[0].end = rtc_resources[0].start + 0x58 - 1;
528
529 return platform_device_register(&rtc_device);
530}
531device_initcall(rtc_init);