2 * A simple generic Real Time Clock interface for Linux/Moxa R7000
6 * 11-27-2003 Victor Yu. Create it.
7 * 01-26-2006 Jimmy_chen@moxa.com.tw Copy UC7420 RTC and fix it to meet MOXART
8 * 02-09-2007 Victor Yu. Porting to kernel 2.6.19. Interrupt kernel API changed.
9 * 09-05-2007 Victor Yu. Change to use raw level gpio API.
12 #define RTC_VERSION "1.0"
14 //#include <linux/config.h>
15 #include <linux/version.h>
16 #include <linux/module.h>
17 #include <linux/kernel.h>
18 #include <linux/types.h>
19 #include <linux/miscdevice.h>
20 #include <linux/fcntl.h>
21 #include <linux/init.h>
22 #include <linux/poll.h>
23 #include <linux/proc_fs.h>
24 #include <linux/spinlock.h>
25 #include <linux/interrupt.h>
26 #include <linux/delay.h>
27 #include <linux/rtc.h>
30 #include <asm/hardware.h>
31 #include <asm/uaccess.h>
32 #include <asm/system.h>
33 #include <asm/arch/moxa.h>
34 #include <asm/arch/gpio.h>
35 #if defined(CONFIG_ARCH_EM1240) || defined(CONFIG_ARCH_EM1240_IVTC) || defined(CONFIG_ARCH_EM1240_MT)
36 #define GPIO_RTC_SCLK (1<<20) /* GPIO5 */
37 #define GPIO_RTC_DATA (1<<21) /* GPIO6 */
38 #define GPIO_RTC_RESET (1<<9) /* GPIO7 */
40 #define GPIO_RTC_SCLK (1<<5) /* GPIO5 */
41 #define GPIO_RTC_DATA (1<<6) /* GPIO6 */
42 #define GPIO_RTC_RESET (1<<7) /* GPIO7 */
44 #define GPIO_RTC_MASK (GPIO_RTC_SCLK|GPIO_RTC_DATA|GPIO_RTC_RESET)
45 #define MOXA_GPIO_PPENABLE 0x18
46 #define MOXA_GPIO_PPTYPE 0x1C
47 #define MOXA_GPIO_DATAOUT 0x0
48 #define MOXA_GPIO_DATAIN 0x04
49 #define MOXA_GPIO_PINDIR 0x08
50 #define GPIO_PINDIR_HIGH 1
51 #define GPIO_PINDIR_LOW 0
52 #define EM1240_GPIO_HIGH 1
53 #define EM1240_GPIO_LOW 0
54 #define RTC_PROTECT_W 0x8E
55 #define RTC_PROTECT_R 0x8F
56 #define RTC_YEAR_W 0x8C
57 #define RTC_YEAR_R 0x8D
58 #define RTC_DAY_W 0x8A
59 #define RTC_DAY_R 0x8B
60 #define RTC_MONTH_W 0x88
61 #define RTC_MONTH_R 0x89
62 #define RTC_DATE_W 0x86
63 #define RTC_DATE_R 0x87
64 #define RTC_HOURS_W 0x84
65 #define RTC_HOURS_R 0x85
66 #define RTC_MINUTES_W 0x82
67 #define RTC_MINUTES_R 0x83
68 #define RTC_SECONDS_W 0x80
69 #define RTC_SECONDS_R 0x81
70 #define RTC_DELAY_TIME 8 // 8 usecond
71 #define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */
74 static void gpio_line_inout(unsigned long gpio, int state)
76 if(state){/* 1:output, 0:input */
77 outl((inl(CPE_GPIO_BASE+MOXA_GPIO_PINDIR)|gpio),CPE_GPIO_BASE+MOXA_GPIO_PINDIR);
79 outl((inl(CPE_GPIO_BASE+MOXA_GPIO_PINDIR)&~gpio), CPE_GPIO_BASE+MOXA_GPIO_PINDIR);
83 static void gpio_line_set(unsigned long gpio, int status)
86 outl((inl(CPE_GPIO_BASE+MOXA_GPIO_DATAOUT)|gpio), CPE_GPIO_BASE+MOXA_GPIO_DATAOUT);
88 outl((inl(CPE_GPIO_BASE+MOXA_GPIO_DATAOUT)&~gpio), CPE_GPIO_BASE+MOXA_GPIO_DATAOUT);
92 static void gpio_line_get(int gpio, int *value)
96 result = inl(CPE_GPIO_BASE+MOXA_GPIO_DATAIN);
97 if((result&gpio)==0) *value = 0;
100 static unsigned long rtc_status = 0; /* bitmapped status byte. */
102 static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data);
103 static spinlock_t rtc_lock;
104 static unsigned long epoch = 2000; /* year corresponding to 0x00 */
106 static const unsigned char days_in_mo[] =
107 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
109 static u8 RTCReadRegister(u8 Cmd)
115 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9) // chagnged by Victor Yu. 02-09-2007
116 local_irq_save(flags);
121 gpio_line_inout(GPIO_RTC_DATA, GPIO_PINDIR_HIGH);
122 gpio_line_set(GPIO_RTC_RESET, EM1240_GPIO_HIGH);
123 udelay(RTC_DELAY_TIME);
124 /* write command byte */
125 for ( i=0; i<8; i++, Cmd>>=1 ){
126 gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_LOW);
128 gpio_line_set(GPIO_RTC_DATA, EM1240_GPIO_HIGH);
130 gpio_line_set(GPIO_RTC_DATA, EM1240_GPIO_LOW);
131 udelay(RTC_DELAY_TIME);
132 gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_HIGH);
133 udelay(RTC_DELAY_TIME);
136 gpio_line_inout(GPIO_RTC_DATA, GPIO_PINDIR_LOW);
138 udelay(RTC_DELAY_TIME);
139 for ( i=0,data=0; i<8; i++ ){
140 gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_LOW);
141 udelay(RTC_DELAY_TIME);
142 gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_HIGH);
143 gpio_line_get(GPIO_RTC_DATA, &v);
146 udelay(RTC_DELAY_TIME);
148 gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_LOW);
149 gpio_line_set(GPIO_RTC_RESET, EM1240_GPIO_LOW);
150 udelay(RTC_DELAY_TIME);
151 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9) // changed by Victor Yu, 02-09-2007
152 local_irq_restore(flags);
154 restore_flags(flags);
160 static void RTCWriteRegister(u8 Cmd, u8 Data)
165 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9) // chagnged by Victor Yu. 02-09-2007
166 local_irq_save(flags);
171 gpio_line_inout(GPIO_RTC_DATA, GPIO_PINDIR_HIGH);
172 gpio_line_set(GPIO_RTC_RESET, EM1240_GPIO_HIGH);
173 udelay(RTC_DELAY_TIME);
174 /* write command byte */
175 for ( i=0; i<8; i++,Cmd>>=1 ) {
176 gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_LOW);
178 gpio_line_set(GPIO_RTC_DATA, EM1240_GPIO_HIGH);
180 gpio_line_set(GPIO_RTC_DATA, EM1240_GPIO_LOW);
181 udelay(RTC_DELAY_TIME);
182 gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_HIGH);
183 udelay(RTC_DELAY_TIME);
186 /* write data byte */
187 gpio_line_inout(GPIO_RTC_DATA, GPIO_PINDIR_HIGH);
188 for ( i=0; i<8; i++,Data>>=1 ){
189 gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_LOW);
191 gpio_line_set(GPIO_RTC_DATA, EM1240_GPIO_HIGH);
193 gpio_line_set(GPIO_RTC_DATA, EM1240_GPIO_LOW);
194 udelay(RTC_DELAY_TIME);
195 gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_HIGH);
196 udelay(RTC_DELAY_TIME);
198 gpio_line_set(GPIO_RTC_SCLK, EM1240_GPIO_LOW);
199 gpio_line_set(GPIO_RTC_RESET, EM1240_GPIO_LOW);
200 udelay(RTC_DELAY_TIME);
201 gpio_line_inout(GPIO_RTC_DATA, GPIO_PINDIR_LOW);
202 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9) // changed by Victor Yu, 02-09-2007
203 local_irq_restore(flags);
205 restore_flags(flags);
209 #if 1 // add by Victor Yu. 01-10-2005
210 static int day_of_year[12]={0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
212 static void get_rtc_time(struct rtc_time *rtc_tm)
216 spin_lock_irq(&rtc_lock);
217 v = RTCReadRegister(RTC_SECONDS_R);
218 rtc_tm->tm_sec = (((v & 0x70) >> 4) * 10) + (v & 0x0F);
219 v = RTCReadRegister(RTC_MINUTES_R);
220 rtc_tm->tm_min = (((v & 0x70) >> 4) * 10) + (v & 0x0F);
221 v = RTCReadRegister(RTC_HOURS_R);
222 if ( v & 0x80 ) { // 12-hour mode
223 rtc_tm->tm_hour = (((v & 0x10) >> 4) * 10) + (v & 0x0F);
224 if ( v & 0x20 ) { // PM mode
225 rtc_tm->tm_hour += 12;
226 if ( rtc_tm->tm_hour >= 24 )
229 } else { // 24-hour mode
230 rtc_tm->tm_hour = (((v & 0x30) >> 4) * 10) + (v & 0x0F);
232 v = RTCReadRegister(RTC_DATE_R);
233 rtc_tm->tm_mday = (((v & 0x30) >> 4) * 10) + (v & 0x0F);
234 v = RTCReadRegister(RTC_MONTH_R);
235 rtc_tm->tm_mon = (((v & 0x10) >> 4) * 10) + (v & 0x0F);
237 v = RTCReadRegister(RTC_YEAR_R);
238 rtc_tm->tm_year = (((v & 0xF0) >> 4) * 10) + (v & 0x0F);
239 if ((rtc_tm->tm_year += (epoch - 1900)) <= 69)
240 rtc_tm->tm_year += 100;
241 #if 1 // add by Victor Yu. 01-10-2005
242 v = RTCReadRegister(RTC_DAY_R);
243 rtc_tm->tm_wday = (v & 0x0f) - 1;
244 rtc_tm->tm_yday = day_of_year[rtc_tm->tm_mon];
245 rtc_tm->tm_yday += (rtc_tm->tm_mday-1);
246 if ( rtc_tm->tm_mon >= 2 ) {
247 if ( !(rtc_tm->tm_year % 4) && (rtc_tm->tm_year % 100) )
250 rtc_tm->tm_isdst = 0;
252 spin_unlock_irq(&rtc_lock);
256 rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
259 struct rtc_time rtc_tm;
263 case RTC_RD_TIME: /* Read the time/date from RTC */
264 get_rtc_time(&rtc_tm);
265 return copy_to_user((void *) arg, &rtc_tm, sizeof(rtc_tm)) ?
267 case RTC_SET_TIME: /* Set the RTC */
269 unsigned char mon, day, hrs, min, sec, leap_yr;
272 if (!capable(CAP_SYS_TIME))
275 if (copy_from_user(&rtc_tm,
276 (struct rtc_time *) arg,
277 sizeof(struct rtc_time)))
280 yrs = rtc_tm.tm_year + 1900;
281 mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */
282 day = rtc_tm.tm_mday;
283 hrs = rtc_tm.tm_hour;
290 leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
292 if ((mon > 12) || (day == 0))
295 if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
298 if ((hrs >= 24) || (min >= 60) || (sec >= 60))
301 if ((yrs -= epoch) > 255) /* They are unsigned */
303 spin_lock_irq(&rtc_lock);
304 /* These limits and adjustments are independant of
305 * whether the chip is in binary mode or not.
308 spin_unlock_irq(&rtc_lock);
314 RTCWriteRegister(RTC_PROTECT_W, 0);
315 v = ((hrs / 10) << 4) | (hrs % 10);
316 RTCWriteRegister(RTC_HOURS_W, v);
317 v = ((min / 10) << 4) | (min % 10);
318 RTCWriteRegister(RTC_MINUTES_W, v);
319 v = ((sec / 10) << 4) | (sec % 10);
320 RTCWriteRegister(RTC_SECONDS_W, v);
321 v = ((yrs / 10) << 4) | (yrs % 10);
322 RTCWriteRegister(RTC_YEAR_W, v);
323 v = ((mon / 10) << 4) | (mon % 10);
324 RTCWriteRegister(RTC_MONTH_W, v);
325 v = ((day / 10) << 4) | (day % 10);
326 RTCWriteRegister(RTC_DATE_W, v);
327 RTCWriteRegister(RTC_PROTECT_W, 0x80);
329 spin_unlock_irq(&rtc_lock);
337 /* We use rtc_lock to protect against concurrent opens. So the BKL is not
338 * needed here. Or anywhere else in this driver. */
339 static int rtc_open(struct inode *inode, struct file *file)
341 spin_lock_irq(&rtc_lock);
343 if (rtc_status & RTC_IS_OPEN) {
344 spin_unlock_irq(&rtc_lock);
348 rtc_status |= RTC_IS_OPEN;
350 spin_unlock_irq(&rtc_lock);
354 static int rtc_release(struct inode *inode, struct file *file)
356 spin_lock_irq(&rtc_lock);
357 rtc_status &= ~RTC_IS_OPEN;
358 spin_unlock_irq(&rtc_lock);
363 * The various file operations we support.
366 static struct file_operations rtc_fops = {
374 static struct miscdevice rtc_dev = {
380 #define PMU_GPIO_ON 0xdfc003f0
381 static int __init rtc_init(void)
383 struct rtc_time rtc_tm;
385 //outw(inl(CPE_PMU_BASE+0x100)|PMU_GPIO_ON,CPE_PMU_BASE+0x100) ;
386 outl(inl(CPE_GPIO_BASE+MOXA_GPIO_PINDIR)|(GPIO_RTC_SCLK|GPIO_RTC_DATA|GPIO_RTC_RESET),(CPE_GPIO_BASE+MOXA_GPIO_PINDIR)) ;
387 mcpu_gpio_mp_set(GPIO_RTC_MASK);
388 gpio_line_inout(GPIO_RTC_RESET, GPIO_PINDIR_HIGH);
389 gpio_line_inout(GPIO_RTC_SCLK, GPIO_PINDIR_HIGH);
391 #if 1 // add by Victor Yu. 04-21-2005, to avoid the RTS stop
392 get_rtc_time(&rtc_tm);
393 //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);
394 if ( rtc_tm.tm_sec == 0 && rtc_tm.tm_min == 0 && rtc_tm.tm_min == 0 && rtc_tm.tm_hour == 0 && rtc_tm.tm_year == 100 && rtc_tm.tm_mon == 0 && rtc_tm.tm_mday == 1 ) {
395 printk("The RTC has stoped. Now reenable it.\n");
396 RTCWriteRegister(RTC_PROTECT_W,0);/* Disable Write Protect */
397 RTCWriteRegister(RTC_SECONDS_W,0);/* Enable OSC */
398 RTCWriteRegister(RTC_PROTECT_W,0x80);/* Enable Write Protect */
401 misc_register(&rtc_dev);
402 create_proc_read_entry("driver/rtc", 0, 0, rtc_read_proc, NULL);
404 printk(KERN_INFO "Generic Moxa RTC Driver v" RTC_VERSION "\n");
408 static void __exit rtc_exit(void)
410 remove_proc_entry("driver/rtc", NULL);
411 misc_deregister(&rtc_dev);
415 module_init(rtc_init);
416 module_exit(rtc_exit);
419 * Info exported via "/proc/driver/rtc".
422 static int rtc_proc_output(char *buf)
432 * There is no way to tell if the luser has the RTC set for local
433 * time or for Universal Standard Time (GMT). Probably local though.
436 "rtc_time\t: %02d:%02d:%02d\n"
437 "rtc_date\t: %04d-%02d-%02d\n"
438 "rtc_epoch\t: %04lu\n",
439 tm.tm_hour, tm.tm_min, tm.tm_sec,
440 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch);
445 static int rtc_read_proc(char *page, char **start, off_t off,
446 int count, int *eof, void *data)
448 int len = rtc_proc_output(page);
449 if (len <= off + count)
460 MODULE_AUTHOR("Victor Yu");
461 MODULE_LICENSE("GPL");