2 * A simple generic Real Time Clock interface for Linux.
6 * 12-27-2005 Victor Yu. Create it.
9 #define RTC_VERSION "1.0"
11 #include <linux/config.h>
12 #include <linux/module.h>
13 #include <linux/kernel.h>
14 #include <linux/types.h>
15 #include <linux/miscdevice.h>
16 #include <linux/fcntl.h>
17 #include <linux/init.h>
18 #include <linux/poll.h>
19 #include <linux/proc_fs.h>
20 #include <linux/spinlock.h>
21 #include <linux/delay.h>
22 #include <linux/rtc.h>
23 #include <linux/interrupt.h>
26 #include <asm/uaccess.h>
27 #include <asm/system.h>
28 #include <asm/arch/cpe/cpe.h>
29 #include <asm/arch/gpio.h>
31 #if (defined CONFIG_ARCH_IA241_32128)||(defined CONFIG_ARCH_IA241_16128) // add by Victor Yu. 05-22-2007
32 #define CONFIG_ARCH_IA241
35 #if (defined CONFIG_ARCH_UC_7112_LX_PLUS_LITON)
36 #define CONFIG_ARCH_UC_7112_LX_PLUS
39 #if ( defined CONFIG_ARCH_W341 ) || ( defined CONFIG_ARCH_W345 ) || ( defined CONFIG_ARCH_W345_IMP1 ) || ( defined CONFIG_ARCH_UC_7112_LX_PLUS ) || ( defined CONFIG_ARCH_W321 ) || ( defined CONFIG_ARCH_W311 )|| ( defined CONFIG_ARCH_W325 ) || (defined CONFIG_ARCH_W315)
40 #define GPIO_RTC_RESET (1<<7)
41 #define GPIO_RTC_SCLK (1<<5)
42 #define GPIO_RTC_DATA (1<<6)
43 #elif ( defined CONFIG_ARCH_IA240 ) || ( defined CONFIG_ARCH_IA241 )
44 #define GPIO_RTC_RESET (1<<8)
45 #define GPIO_RTC_SCLK (1<<28)
46 #define GPIO_RTC_DATA (1<<9)
48 #elif ( defined CONFIG_ARCH_W311 )
49 #define GPIO_RTC_RESET (1<<26)
50 #define GPIO_RTC_SCLK (1<<24)
51 #define GPIO_RTC_DATA (1<<25)
55 #define RTC_PROTECT_W 0x8E
56 #define RTC_PROTECT_R 0x8F
57 #define RTC_YEAR_W 0x8C
58 #define RTC_YEAR_R 0x8D
59 #define RTC_DAY_W 0x8A
60 #define RTC_DAY_R 0x8B
61 #define RTC_MONTH_W 0x88
62 #define RTC_MONTH_R 0x89
63 #define RTC_DATE_W 0x86
64 #define RTC_DATE_R 0x87
65 #define RTC_HOURS_W 0x84
66 #define RTC_HOURS_R 0x85
67 #define RTC_MINUTES_W 0x82
68 #define RTC_MINUTES_R 0x83
69 #define RTC_SECONDS_W 0x80
70 #define RTC_SECONDS_R 0x81
72 #define RTC_DELAY_TIME 8 // 8 usecond
74 static unsigned long rtc_status
= 0; /* bitmapped status byte. */
76 static int rtc_read_proc(char *page
, char **start
, off_t off
,
77 int count
, int *eof
, void *data
);
80 #define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */
82 static spinlock_t rtc_lock
;
83 static unsigned long epoch
= 2000; /* year corresponding to 0x00 */
85 static const unsigned char days_in_mo
[] =
86 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
88 static u8
RTCReadRegister(u8 Cmd
)
96 mcpu_gpio_inout(GPIO_RTC_DATA
, MCPU_GPIO_OUTPUT
);
97 mcpu_gpio_set(GPIO_RTC_RESET
, MCPU_GPIO_HIGH
);
98 //udelay(RTC_DELAY_TIME);
99 /* write command byte */
100 for ( i
=0; i
<8; i
++, Cmd
>>=1 ){
101 mcpu_gpio_set(GPIO_RTC_SCLK
, MCPU_GPIO_LOW
);
103 mcpu_gpio_set(GPIO_RTC_DATA
, MCPU_GPIO_HIGH
);
105 mcpu_gpio_set(GPIO_RTC_DATA
, MCPU_GPIO_LOW
);
106 //udelay(RTC_DELAY_TIME);
107 mcpu_gpio_set(GPIO_RTC_SCLK
, MCPU_GPIO_HIGH
);
108 //udelay(RTC_DELAY_TIME);
111 mcpu_gpio_inout(GPIO_RTC_DATA
, MCPU_GPIO_INPUT
);
113 //udelay(RTC_DELAY_TIME);
114 for ( i
=0,data
=0; i
<8; i
++ ){
115 mcpu_gpio_set(GPIO_RTC_SCLK
, MCPU_GPIO_LOW
);
116 //udelay(RTC_DELAY_TIME);
117 mcpu_gpio_set(GPIO_RTC_SCLK
, MCPU_GPIO_HIGH
);
118 v
= mcpu_gpio_get(GPIO_RTC_DATA
);
121 //udelay(RTC_DELAY_TIME);
123 mcpu_gpio_set(GPIO_RTC_SCLK
, MCPU_GPIO_LOW
);
124 mcpu_gpio_set(GPIO_RTC_RESET
, MCPU_GPIO_LOW
);
125 //udelay(RTC_DELAY_TIME);
126 restore_flags(flags
);
131 static void RTCWriteRegister(u8 Cmd
, u8 Data
)
138 mcpu_gpio_inout(GPIO_RTC_DATA
, MCPU_GPIO_OUTPUT
);
139 mcpu_gpio_set(GPIO_RTC_RESET
, MCPU_GPIO_HIGH
);
140 //udelay(RTC_DELAY_TIME);
141 /* write command byte */
142 for ( i
=0; i
<8; i
++,Cmd
>>=1 ) {
143 mcpu_gpio_set(GPIO_RTC_SCLK
, MCPU_GPIO_LOW
);
145 mcpu_gpio_set(GPIO_RTC_DATA
, MCPU_GPIO_HIGH
);
147 mcpu_gpio_set(GPIO_RTC_DATA
, MCPU_GPIO_LOW
);
148 //udelay(RTC_DELAY_TIME);
149 mcpu_gpio_set(GPIO_RTC_SCLK
, MCPU_GPIO_HIGH
);
150 //udelay(RTC_DELAY_TIME);
153 /* write data byte */
154 mcpu_gpio_inout(GPIO_RTC_DATA
, MCPU_GPIO_OUTPUT
);
155 for ( i
=0; i
<8; i
++,Data
>>=1 ){
156 mcpu_gpio_set(GPIO_RTC_SCLK
, MCPU_GPIO_LOW
);
158 mcpu_gpio_set(GPIO_RTC_DATA
, MCPU_GPIO_HIGH
);
160 mcpu_gpio_set(GPIO_RTC_DATA
, MCPU_GPIO_LOW
);
161 //udelay(RTC_DELAY_TIME);
162 mcpu_gpio_set(GPIO_RTC_SCLK
, MCPU_GPIO_HIGH
);
163 //udelay(RTC_DELAY_TIME);
165 mcpu_gpio_set(GPIO_RTC_SCLK
, MCPU_GPIO_LOW
);
166 mcpu_gpio_set(GPIO_RTC_RESET
, MCPU_GPIO_LOW
);
167 //udelay(RTC_DELAY_TIME);
168 mcpu_gpio_inout(GPIO_RTC_DATA
, MCPU_GPIO_INPUT
);
169 restore_flags(flags
);
172 #if 1 // add by Victor Yu. 01-10-2005
173 static int day_of_year
[12]={0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
175 static void get_rtc_time(struct rtc_time
*rtc_tm
)
179 spin_lock_irq(&rtc_lock
);
180 v
= RTCReadRegister(RTC_SECONDS_R
);
181 rtc_tm
->tm_sec
= (((v
& 0x70) >> 4) * 10) + (v
& 0x0F);
182 v
= RTCReadRegister(RTC_MINUTES_R
);
183 rtc_tm
->tm_min
= (((v
& 0x70) >> 4) * 10) + (v
& 0x0F);
184 v
= RTCReadRegister(RTC_HOURS_R
);
185 if ( v
& 0x80 ) { // 12-hour mode
186 rtc_tm
->tm_hour
= (((v
& 0x10) >> 4) * 10) + (v
& 0x0F);
187 if ( v
& 0x20 ) { // PM mode
188 rtc_tm
->tm_hour
+= 12;
189 if ( rtc_tm
->tm_hour
>= 24 )
192 } else { // 24-hour mode
193 rtc_tm
->tm_hour
= (((v
& 0x30) >> 4) * 10) + (v
& 0x0F);
195 v
= RTCReadRegister(RTC_DATE_R
);
196 rtc_tm
->tm_mday
= (((v
& 0x30) >> 4) * 10) + (v
& 0x0F);
197 v
= RTCReadRegister(RTC_MONTH_R
);
198 rtc_tm
->tm_mon
= (((v
& 0x10) >> 4) * 10) + (v
& 0x0F);
200 v
= RTCReadRegister(RTC_YEAR_R
);
201 rtc_tm
->tm_year
= (((v
& 0xF0) >> 4) * 10) + (v
& 0x0F);
202 if ((rtc_tm
->tm_year
+= (epoch
- 1900)) <= 69)
203 rtc_tm
->tm_year
+= 100;
204 #if 1 // add by Victor Yu. 01-10-2005
205 v
= RTCReadRegister(RTC_DAY_R
);
206 rtc_tm
->tm_wday
= (v
& 0x0f) - 1;
207 rtc_tm
->tm_yday
= day_of_year
[rtc_tm
->tm_mon
];
208 rtc_tm
->tm_yday
+= (rtc_tm
->tm_mday
-1);
209 if ( rtc_tm
->tm_mon
>= 2 ) {
210 if ( !(rtc_tm
->tm_year
% 4) && (rtc_tm
->tm_year
% 100) )
213 rtc_tm
->tm_isdst
= 0;
215 spin_unlock_irq(&rtc_lock
);
219 rtc_ioctl(struct inode
*inode
, struct file
*file
, unsigned int cmd
,
222 struct rtc_time rtc_tm
;
226 case RTC_RD_TIME
: /* Read the time/date from RTC */
227 get_rtc_time(&rtc_tm
);
228 return copy_to_user((void *) arg
, &rtc_tm
, sizeof(rtc_tm
)) ?
230 case RTC_SET_TIME
: /* Set the RTC */
232 unsigned char mon
, day
, hrs
, min
, sec
, leap_yr
;
235 if (!capable(CAP_SYS_TIME
))
238 if (copy_from_user(&rtc_tm
,
239 (struct rtc_time
*) arg
,
240 sizeof(struct rtc_time
)))
243 yrs
= rtc_tm
.tm_year
+ 1900;
244 mon
= rtc_tm
.tm_mon
+ 1; /* tm_mon starts at zero */
245 day
= rtc_tm
.tm_mday
;
246 hrs
= rtc_tm
.tm_hour
;
253 leap_yr
= ((!(yrs
% 4) && (yrs
% 100)) || !(yrs
% 400));
255 if ((mon
> 12) || (day
== 0))
258 if (day
> (days_in_mo
[mon
] + ((mon
== 2) && leap_yr
)))
261 if ((hrs
>= 24) || (min
>= 60) || (sec
>= 60))
264 if ((yrs
-= epoch
) > 255) /* They are unsigned */
266 spin_lock_irq(&rtc_lock
);
267 /* These limits and adjustments are independant of
268 * whether the chip is in binary mode or not.
271 spin_unlock_irq(&rtc_lock
);
277 RTCWriteRegister(RTC_PROTECT_W
, 0);
278 v
= ((hrs
/ 10) << 4) | (hrs
% 10);
279 RTCWriteRegister(RTC_HOURS_W
, v
);
280 v
= ((min
/ 10) << 4) | (min
% 10);
281 RTCWriteRegister(RTC_MINUTES_W
, v
);
282 v
= ((sec
/ 10) << 4) | (sec
% 10);
283 RTCWriteRegister(RTC_SECONDS_W
, v
);
284 v
= ((yrs
/ 10) << 4) | (yrs
% 10);
285 RTCWriteRegister(RTC_YEAR_W
, v
);
286 v
= ((mon
/ 10) << 4) | (mon
% 10);
287 RTCWriteRegister(RTC_MONTH_W
, v
);
288 v
= ((day
/ 10) << 4) | (day
% 10);
289 RTCWriteRegister(RTC_DATE_W
, v
);
290 RTCWriteRegister(RTC_PROTECT_W
, 0x80);
292 spin_unlock_irq(&rtc_lock
);
300 /* We use rtc_lock to protect against concurrent opens. So the BKL is not
301 * needed here. Or anywhere else in this driver. */
302 static int rtc_open(struct inode
*inode
, struct file
*file
)
304 spin_lock_irq(&rtc_lock
);
306 if (rtc_status
& RTC_IS_OPEN
) {
307 spin_unlock_irq(&rtc_lock
);
311 rtc_status
|= RTC_IS_OPEN
;
313 spin_unlock_irq(&rtc_lock
);
317 static int rtc_release(struct inode
*inode
, struct file
*file
)
319 spin_lock_irq(&rtc_lock
);
320 rtc_status
&= ~RTC_IS_OPEN
;
321 spin_unlock_irq(&rtc_lock
);
326 * The various file operations we support.
329 static struct file_operations rtc_fops
= {
337 static struct miscdevice rtc_dev
= {
343 static int __init
rtc_init(void)
345 #if 1 // add by Victor Yu. 04-21-2005, to avoid the RTS stop
346 struct rtc_time rtc_tm
;
348 // set the CPU for GPIO
349 mcpu_gpio_mp_set(GPIO_RTC_RESET
|GPIO_RTC_SCLK
|GPIO_RTC_DATA
);
352 // default set all RTC GPIO to output on the Moxa CPU
353 mcpu_gpio_inout(GPIO_RTC_RESET
|GPIO_RTC_SCLK
|GPIO_RTC_DATA
, MCPU_GPIO_OUTPUT
);
355 get_rtc_time(&rtc_tm
);
356 //printk("YYYY-MON-DAY-HH-MM-SS=%d-%d-%d-%d-%d-%d\n", rtc_tm.tm_year, rtc_tm.tm_mon, rtc_tm.tm_mday, rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
357 if ( rtc_tm
.tm_sec
== 0 && rtc_tm
.tm_min
== 0 && rtc_tm
.tm_min
== 0 && rtc_tm
.tm_hour
== 0 &&
358 rtc_tm
.tm_year
== 100 && rtc_tm
.tm_mon
== 0 && rtc_tm
.tm_mday
== 1 ) {
359 printk("The RTC has stoped. Now reenable it.\n");
360 RTCWriteRegister(RTC_PROTECT_W
,0);/* Disable Write Protect */
361 RTCWriteRegister(RTC_SECONDS_W
,0);/* Enable OSC */
362 RTCWriteRegister(RTC_PROTECT_W
,0x80);/* Enable Write Protect */
365 misc_register(&rtc_dev
);
366 create_proc_read_entry("driver/rtc", 0, 0, rtc_read_proc
, NULL
);
368 printk(KERN_INFO
"Generic Moxa RC7000 RTC Driver v" RTC_VERSION
"\n");
373 static void __exit
rtc_exit(void)
375 remove_proc_entry("driver/rtc", NULL
);
376 misc_deregister(&rtc_dev
);
380 module_init(rtc_init
);
381 module_exit(rtc_exit
);
384 * Info exported via "/proc/driver/rtc".
387 static int rtc_proc_output(char *buf
)
397 * There is no way to tell if the luser has the RTC set for local
398 * time or for Universal Standard Time (GMT). Probably local though.
401 "rtc_time\t: %02d:%02d:%02d\n"
402 "rtc_date\t: %04d-%02d-%02d\n"
403 "rtc_epoch\t: %04lu\n",
404 tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
,
405 tm
.tm_year
+ 1900, tm
.tm_mon
+ 1, tm
.tm_mday
, epoch
);
410 static int rtc_read_proc(char *page
, char **start
, off_t off
,
411 int count
, int *eof
, void *data
)
413 int len
= rtc_proc_output(page
);
414 if (len
<= off
+ count
)
425 MODULE_AUTHOR("Victor Yu");
426 MODULE_LICENSE("GPL");