blob: 995896ac0e39012f9b707860a429c79244908fce [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright 2001 MontaVista Software Inc.
3 * Author: jsun@mvista.com or jsun@junsun.net
4 *
5 * arch/mips/ddb5xxx/common/rtc_ds1386.c
6 * low-level RTC hookups for s for Dallas 1396 chip.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13
14
15/*
16 * This file exports a function, rtc_ds1386_init(), which expects an
17 * uncached base address as the argument. It will set the two function
18 * pointers expected by the MIPS generic timer code.
19 */
20
21#include <linux/types.h>
22#include <linux/time.h>
23#include <linux/bcd.h>
24
25#include <asm/time.h>
26#include <asm/addrspace.h>
27
28#include <asm/mc146818rtc.h>
29#include <asm/debug.h>
30
31#define EPOCH 2000
32
33#define READ_RTC(x) *(volatile unsigned char*)(rtc_base+x)
34#define WRITE_RTC(x, y) *(volatile unsigned char*)(rtc_base+x) = y
35
36static unsigned long rtc_base;
37
38static unsigned long
39rtc_ds1386_get_time(void)
40{
41 u8 byte;
42 u8 temp;
43 unsigned int year, month, day, hour, minute, second;
Atsushi Nemoto53c2df22005-11-03 01:01:15 +090044 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
Atsushi Nemoto53c2df22005-11-03 01:01:15 +090046 spin_lock_irqsave(&rtc_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -070047 /* let us freeze external registers */
48 byte = READ_RTC(0xB);
49 byte &= 0x3f;
50 WRITE_RTC(0xB, byte);
51
52 /* read time data */
53 year = BCD2BIN(READ_RTC(0xA)) + EPOCH;
54 month = BCD2BIN(READ_RTC(0x9) & 0x1f);
55 day = BCD2BIN(READ_RTC(0x8));
56 minute = BCD2BIN(READ_RTC(0x2));
57 second = BCD2BIN(READ_RTC(0x1));
58
59 /* hour is special - deal with it later */
60 temp = READ_RTC(0x4);
61
62 /* enable time transfer */
63 byte |= 0x80;
64 WRITE_RTC(0xB, byte);
Atsushi Nemoto53c2df22005-11-03 01:01:15 +090065 spin_unlock_irqrestore(&rtc_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67 /* calc hour */
68 if (temp & 0x40) {
69 /* 12 hour format */
70 hour = BCD2BIN(temp & 0x1f);
71 if (temp & 0x20) hour += 12; /* PM */
72 } else {
73 /* 24 hour format */
74 hour = BCD2BIN(temp & 0x3f);
75 }
76
77 return mktime(year, month, day, hour, minute, second);
78}
79
80static int
81rtc_ds1386_set_time(unsigned long t)
82{
83 struct rtc_time tm;
84 u8 byte;
85 u8 temp;
86 u8 year, month, day, hour, minute, second;
Atsushi Nemoto53c2df22005-11-03 01:01:15 +090087 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
Atsushi Nemoto53c2df22005-11-03 01:01:15 +090089 spin_lock_irqsave(&rtc_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 /* let us freeze external registers */
91 byte = READ_RTC(0xB);
92 byte &= 0x3f;
93 WRITE_RTC(0xB, byte);
94
95 /* convert */
96 to_tm(t, &tm);
97
98
99 /* check each field one by one */
100 year = BIN2BCD(tm.tm_year - EPOCH);
101 if (year != READ_RTC(0xA)) {
102 WRITE_RTC(0xA, year);
103 }
104
105 temp = READ_RTC(0x9);
106 month = BIN2BCD(tm.tm_mon+1); /* tm_mon starts from 0 to 11 */
107 if (month != (temp & 0x1f)) {
108 WRITE_RTC( 0x9,
109 (month & 0x1f) | (temp & ~0x1f) );
110 }
111
112 day = BIN2BCD(tm.tm_mday);
113 if (day != READ_RTC(0x8)) {
114 WRITE_RTC(0x8, day);
115 }
116
117 temp = READ_RTC(0x4);
118 if (temp & 0x40) {
119 /* 12 hour format */
120 hour = 0x40;
121 if (tm.tm_hour > 12) {
122 hour |= 0x20 | (BIN2BCD(hour-12) & 0x1f);
123 } else {
124 hour |= BIN2BCD(tm.tm_hour);
125 }
126 } else {
127 /* 24 hour format */
128 hour = BIN2BCD(tm.tm_hour) & 0x3f;
129 }
130 if (hour != temp) WRITE_RTC(0x4, hour);
131
132 minute = BIN2BCD(tm.tm_min);
133 if (minute != READ_RTC(0x2)) {
134 WRITE_RTC(0x2, minute);
135 }
136
137 second = BIN2BCD(tm.tm_sec);
138 if (second != READ_RTC(0x1)) {
139 WRITE_RTC(0x1, second);
140 }
Atsushi Nemoto53c2df22005-11-03 01:01:15 +0900141 spin_unlock_irqrestore(&rtc_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
143 return 0;
144}
145
146void
147rtc_ds1386_init(unsigned long base)
148{
149 unsigned char byte;
150
151 /* remember the base */
152 rtc_base = base;
153 db_assert((rtc_base & 0xe0000000) == KSEG1);
154
155 /* turn on RTC if it is not on */
156 byte = READ_RTC(0x9);
157 if (byte & 0x80) {
158 byte &= 0x7f;
159 WRITE_RTC(0x9, byte);
160 }
161
162 /* enable time transfer */
163 byte = READ_RTC(0xB);
164 byte |= 0x80;
165 WRITE_RTC(0xB, byte);
166
167 /* set the function pointers */
168 rtc_get_time = rtc_ds1386_get_time;
169 rtc_set_time = rtc_ds1386_set_time;
170}