MOXA linux-2.6.x / linux-2.6.19-uc1 from UC-7110-LX-BOOTLOADER-1.9_VERSION-4.2.tgz
[linux-2.6.19-moxart.git] / drivers / char / rtc.c-bak-09052007
blob3bdc7e2daf96c84802b5ef18902e2e82f4adbb79
1 /*
2  *      A simple generic Real Time Clock interface for Linux/Moxa R7000
3  *
4  *      History:
5  *      Date            Author                  Comment
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.
10  */
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>
29 #include <asm/io.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 */
39 #else
40 #define GPIO_RTC_SCLK           (1<<5)  /* GPIO5 */
41 #define GPIO_RTC_DATA           (1<<6)  /* GPIO6 */
42 #define GPIO_RTC_RESET          (1<<7)  /* GPIO7 */
43 #endif
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     */
72 #define PIO(x)                  1<<x
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);
78         }else{
79                 outl((inl(CPE_GPIO_BASE+MOXA_GPIO_PINDIR)&~gpio), CPE_GPIO_BASE+MOXA_GPIO_PINDIR);
80         }
83 static void     gpio_line_set(unsigned long gpio, int status)
85         if(status){
86                 outl((inl(CPE_GPIO_BASE+MOXA_GPIO_DATAOUT)|gpio), CPE_GPIO_BASE+MOXA_GPIO_DATAOUT);
87         } else{
88                 outl((inl(CPE_GPIO_BASE+MOXA_GPIO_DATAOUT)&~gpio), CPE_GPIO_BASE+MOXA_GPIO_DATAOUT);
89         }
92 static void     gpio_line_get(int gpio, int *value)
94         unsigned long result;
96         result =  inl(CPE_GPIO_BASE+MOXA_GPIO_DATAIN);
97         if((result&gpio)==0) *value = 0;
98         else *value = 1;
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)
111     u8          data;
112     int         i, v;
113     unsigned long       flags;
114     
115 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9)        // chagnged by Victor Yu. 02-09-2007
116     local_irq_save(flags);
117 #else
118     save_flags(flags);
119     cli();
120 #endif
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);
127         if ( Cmd & 1 )
128                 gpio_line_set(GPIO_RTC_DATA, EM1240_GPIO_HIGH);
129         else
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);
134     }
135     
136     gpio_line_inout(GPIO_RTC_DATA, GPIO_PINDIR_LOW);
137     /* read data byte */
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);
144         if ( v )
145                 data |= (1<<i);
146         udelay(RTC_DELAY_TIME);
147     }
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);
153 #else
154     restore_flags(flags);
155 #endif
157     return data;
160 static void RTCWriteRegister(u8 Cmd, u8 Data)
162     int         i;
163     unsigned long       flags;
165 #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9)        // chagnged by Victor Yu. 02-09-2007
166     local_irq_save(flags);
167 #else
168     save_flags(flags);
169     cli();
170 #endif
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);
177         if ( Cmd & 1 )
178                 gpio_line_set(GPIO_RTC_DATA, EM1240_GPIO_HIGH);
179         else
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);
184     }
185     
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);
190         if ( Data & 1 )
191                 gpio_line_set(GPIO_RTC_DATA, EM1240_GPIO_HIGH);
192         else
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);
197     }
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);
204 #else
205     restore_flags(flags);
206 #endif
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};
211 #endif
212 static void get_rtc_time(struct rtc_time *rtc_tm)
214         unsigned char   v;
215         
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 )
227                                 rtc_tm->tm_hour = 0;
228                 }
229         } else {        // 24-hour mode
230                 rtc_tm->tm_hour = (((v & 0x30) >> 4) * 10) + (v & 0x0F);
231         }
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);
236         rtc_tm->tm_mon--;
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) )
248                         rtc_tm->tm_yday++;
249         }
250         rtc_tm->tm_isdst = 0;
251 #endif
252         spin_unlock_irq(&rtc_lock);
255 static int
256 rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
257           unsigned long arg)
259         struct rtc_time rtc_tm;
260         unsigned char   v;
262         switch (cmd) {
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)) ? 
266                         -EFAULT : 0;
267         case RTC_SET_TIME:      /* Set the RTC */
268         {
269                 unsigned char mon, day, hrs, min, sec, leap_yr;
270                 unsigned int yrs;
271                 
272                 if (!capable(CAP_SYS_TIME))
273                         return -EACCES;
275                 if (copy_from_user(&rtc_tm, 
276                                    (struct rtc_time *) arg,
277                                    sizeof(struct rtc_time))) 
278                         return -EFAULT;
279                         
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;
284                 min = rtc_tm.tm_min;
285                 sec = rtc_tm.tm_sec;
287                 if (yrs < 1970)
288                         return -EINVAL;
290                 leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
292                 if ((mon > 12) || (day == 0))
293                         return -EINVAL;
295                 if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
296                         return -EINVAL;
297                         
298                 if ((hrs >= 24) || (min >= 60) || (sec >= 60))
299                         return -EINVAL;
301                 if ((yrs -= epoch) > 255)    /* They are unsigned */
302                         return -EINVAL;
303                 spin_lock_irq(&rtc_lock);
304                 /* These limits and adjustments are independant of
305                  * whether the chip is in binary mode or not.
306                  */
307                 if (yrs > 169) {
308                         spin_unlock_irq(&rtc_lock);
309                         return -EINVAL;
310                 }
311                 if (yrs >= 100)
312                         yrs -= 100;
313                         
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);
328                 
329                 spin_unlock_irq(&rtc_lock);
330                 return 0;
331         }
332         default:
333                 return -EINVAL;
334         }
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);
345                 return -EBUSY;
346         }
348         rtc_status |= RTC_IS_OPEN;
350         spin_unlock_irq(&rtc_lock);
351         return 0;
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);
359         return 0;
363  *      The various file operations we support.
364  */
366 static struct file_operations rtc_fops = {
367         owner:THIS_MODULE,
368         llseek:no_llseek,
369         ioctl:rtc_ioctl,
370         open:rtc_open,
371         release:rtc_release,
374 static struct miscdevice rtc_dev = {
375         RTC_MINOR,
376         "rtc",
377         &rtc_fops
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 */
399         }
400 #endif
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");
405         return 0;
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".
420  */
422 static int rtc_proc_output(char *buf)
424         char *p;
425         struct rtc_time tm;
427         get_rtc_time(&tm);
429         p = buf;
431         /*
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.
434          */
435         p += sprintf(p,
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);
442         return p - buf;
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)
450                 *eof = 1;
451         *start = page + off;
452         len -= off;
453         if (len > count)
454                 len = count;
455         if (len < 0)
456                 len = 0;
457         return len;
460 MODULE_AUTHOR("Victor Yu");
461 MODULE_LICENSE("GPL");