fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / cris / arch-v10 / drivers / ds1302.c
index b244f40..3cf4f23 100644 (file)
@@ -4,9 +4,30 @@
 *!
 *! DESCRIPTION: Implements an interface for the DS1302 RTC through Etrax I/O
 *!
-*! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status
+*! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init
 *!
 *! $Log: ds1302.c,v $
+*! Revision 1.18  2005/01/24 09:11:26  mikaelam
+*! Minor changes to get DS1302 RTC chip driver to work
+*!
+*! Revision 1.17  2005/01/05 06:11:22  starvik
+*! No need to do local_irq_disable after local_irq_save.
+*!
+*! Revision 1.16  2004/12/13 12:21:52  starvik
+*! Added I/O and DMA allocators from Linux 2.4
+*!
+*! Revision 1.14  2004/08/24 06:48:43  starvik
+*! Whitespace cleanup
+*!
+*! Revision 1.13  2004/05/28 09:26:59  starvik
+*! Modified I2C initialization to work in 2.6.
+*!
+*! Revision 1.12  2004/05/14 07:58:03  starvik
+*! Merge of changes from 2.4
+*!
+*! Revision 1.10  2004/02/04 09:25:12  starvik
+*! Merge of Linux 2.6.2
+*!
 *! Revision 1.9  2003/07/04 08:27:37  starvik
 *! Merge of Linux 2.5.74
 *!
 *!
 *! ---------------------------------------------------------------------------
 *!
-*! (C) Copyright 1999, 2000, 2001  Axis Communications AB, LUND, SWEDEN
+*! (C) Copyright 1999, 2000, 2001, 2002, 2003, 2004  Axis Communications AB, LUND, SWEDEN
 *!
-*! $Id: ds1302.c,v 1.9 2003/07/04 08:27:37 starvik Exp $
+*! $Id: ds1302.c,v 1.18 2005/01/24 09:11:26 mikaelam Exp $
 *!
 *!***************************************************************************/
 
-#include <linux/config.h>
 
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/miscdevice.h>
 #include <linux/delay.h>
 #include <linux/bcd.h>
+#include <linux/capability.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/arch/svinto.h>
 #include <asm/io.h>
 #include <asm/rtc.h>
+#include <asm/arch/io_interface_mux.h>
 
 #define RTC_MAJOR_NR 121 /* local major, change later */
 
@@ -283,12 +305,23 @@ ds1302_readreg(int reg)
 void
 ds1302_writereg(int reg, unsigned char val) 
 {
-       ds1302_wenable();
-       start();
-       out_byte(0x80 | (reg << 1)); /* write register */
-       out_byte(val);
-       stop();
-       ds1302_wdisable();
+#ifndef CONFIG_ETRAX_RTC_READONLY
+       int do_writereg = 1;
+#else
+       int do_writereg = 0;
+
+       if (reg == RTC_TRICKLECHARGER)
+               do_writereg = 1;
+#endif
+
+       if (do_writereg) {
+               ds1302_wenable();
+               start();
+               out_byte(0x80 | (reg << 1)); /* write register */
+               out_byte(val);
+               stop();
+               ds1302_wdisable();
+       }
 }
 
 void
@@ -297,7 +330,6 @@ get_rtc_time(struct rtc_time *rtc_tm)
        unsigned long flags;
 
        local_irq_save(flags);
-       local_irq_disable();
 
        rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
        rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
@@ -335,7 +367,7 @@ static int
 rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
          unsigned long arg) 
 {
-        unsigned long flags;
+       unsigned long flags;
 
        switch(cmd) {
                case RTC_RD_TIME:       /* read the time/date from RTC  */
@@ -359,7 +391,7 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                                return -EPERM;
 
                        if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)))
-                               return -EFAULT;         
+                               return -EFAULT;
 
                        yrs = rtc_tm.tm_year + 1900;
                        mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
@@ -396,7 +428,6 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                        BIN_TO_BCD(yrs);
 
                        local_irq_save(flags);
-                       local_irq_disable();
                        CMOS_WRITE(yrs, RTC_YEAR);
                        CMOS_WRITE(mon, RTC_MONTH);
                        CMOS_WRITE(day, RTC_DAY_OF_MONTH);
@@ -415,7 +446,7 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 
                case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */
                {
-                       int tcs_val;                        
+                       int tcs_val;
 
                        if (!capable(CAP_SYS_TIME))
                                return -EPERM;
@@ -426,20 +457,33 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
                        tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F);
                        ds1302_writereg(RTC_TRICKLECHARGER, tcs_val);
                        return 0;
-               }                
+               }
+               case RTC_VLOW_RD:
+               {
+                       /* TODO:
+                        * Implement voltage low detection support
+                        */
+                       printk(KERN_WARNING "DS1302: RTC Voltage Low detection"
+                              " is not supported\n");
+                       return 0;
+               }
+               case RTC_VLOW_SET:
+               {
+                       /* TODO:
+                        * Nothing to do since Voltage Low detection is not supported
+                        */
+                       return 0;
+               }
                default:
                        return -ENOIOCTLCMD;
        }
 }
 
-int
-get_rtc_status(char *buf) 
+static void
+print_rtc_status(void)
 {
-       char *p;
        struct rtc_time tm;
 
-       p = buf;
-
        get_rtc_time(&tm);
 
        /*
@@ -447,21 +491,17 @@ get_rtc_status(char *buf)
         * time or for Universal Standard Time (GMT). Probably local though.
         */
 
-       p += sprintf(p,
-               "rtc_time\t: %02d:%02d:%02d\n"
-               "rtc_date\t: %04d-%02d-%02d\n",
-               tm.tm_hour, tm.tm_min, tm.tm_sec,
-               tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
-
-       return  p - buf;
+       printk(KERN_INFO "rtc_time\t: %02d:%02d:%02d\n",
+              tm.tm_hour, tm.tm_min, tm.tm_sec);
+       printk(KERN_INFO "rtc_date\t: %04d-%02d-%02d\n",
+              tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
 }
 
-
 /* The various file operations we support. */
 
 static struct file_operations rtc_fops = {
-        .owner          = THIS_MODULE,
-        .ioctl          = rtc_ioctl,   
+       .owner =        THIS_MODULE,
+       .ioctl =        rtc_ioctl,
 }; 
 
 /* Probe for the chip by writing something to its RAM and try reading it back. */
@@ -487,11 +527,10 @@ ds1302_probe(void)
        out_byte(0xc1); /* read RAM byte 0 */
 
        if((res = in_byte()) == MAGIC_PATTERN) {
-               char buf[100];
                stop();
                ds1302_wdisable();
-               printk("%s: RTC found.\n", ds1302_name);
-               printk("%s: SDA, SCL, RST on PB%i, PB%i, %s%i\n",
+               printk(KERN_INFO "%s: RTC found.\n", ds1302_name);
+               printk(KERN_INFO "%s: SDA, SCL, RST on PB%i, PB%i, %s%i\n",
                       ds1302_name,
                       CONFIG_ETRAX_DS1302_SDABIT,
                       CONFIG_ETRAX_DS1302_SCLBIT,
@@ -501,12 +540,10 @@ ds1302_probe(void)
                       "PB",
 #endif
                       CONFIG_ETRAX_DS1302_RSTBIT);
-                get_rtc_status(buf);
-                printk(buf);
+                      print_rtc_status();
                retval = 1;
        } else {
                stop();
-               printk("%s: RTC not found.\n", ds1302_name);
                retval = 0;
        }
 
@@ -518,7 +555,11 @@ ds1302_probe(void)
 
 int __init
 ds1302_init(void) 
-{ 
+{
+#ifdef CONFIG_ETRAX_I2C
+       i2c_init();
+#endif
+
        if (!ds1302_probe()) {
 #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
 #if CONFIG_ETRAX_DS1302_RSTBIT == 27
@@ -527,28 +568,49 @@ ds1302_init(void)
                 *
                 * Make sure that R_GEN_CONFIG is setup correct.
                 */
-               genconfig_shadow = ((genconfig_shadow &
-                                    ~IO_MASK(R_GEN_CONFIG, ata)) | 
-                                  (IO_STATE(R_GEN_CONFIG, ata, select)));    
-               *R_GEN_CONFIG = genconfig_shadow;
+               /* Allocating the ATA interface will grab almost all
+                * pins in I/O groups a, b, c and d.  A consequence of
+                * allocating the ATA interface is that the fixed
+                * interfaces shared RAM, parallel port 0, parallel
+                * port 1, parallel port W, SCSI-8 port 0, SCSI-8 port
+                * 1, SCSI-W, serial port 2, serial port 3,
+                * synchronous serial port 3 and USB port 2 and almost
+                * all GPIO pins on port g cannot be used.
+                */
+               if (cris_request_io_interface(if_ata, "ds1302/ATA")) {
+                       printk(KERN_WARNING "ds1302: Failed to get IO interface\n");
+                       return -1;
+               }
+
 #elif CONFIG_ETRAX_DS1302_RSTBIT == 0
-               
-               /* Set the direction of this bit to out. */             
-               genconfig_shadow = ((genconfig_shadow &
-                                    ~IO_MASK(R_GEN_CONFIG, g0dir)) | 
-                                  (IO_STATE(R_GEN_CONFIG, g0dir, out)));    
-               *R_GEN_CONFIG = genconfig_shadow;
+               if (cris_io_interface_allocate_pins(if_gpio_grp_a,
+                                                   'g',
+                                                   CONFIG_ETRAX_DS1302_RSTBIT,
+                                                   CONFIG_ETRAX_DS1302_RSTBIT)) {
+                       printk(KERN_WARNING "ds1302: Failed to get IO interface\n");
+                       return -1;
+               }
+
+               /* Set the direction of this bit to out. */
+               genconfig_shadow = ((genconfig_shadow &
+                                    ~IO_MASK(R_GEN_CONFIG, g0dir)) |
+                                  (IO_STATE(R_GEN_CONFIG, g0dir, out)));
+               *R_GEN_CONFIG = genconfig_shadow;
 #endif
-               if (!ds1302_probe())
-                       return -1;
+               if (!ds1302_probe()) {
+                       printk(KERN_WARNING "%s: RTC not found.\n", ds1302_name);
+                       return -1;
+               }
 #else
-               return -1;
+               printk(KERN_WARNING "%s: RTC not found.\n", ds1302_name);
+               return -1;
 #endif
        }
-  
        /* Initialise trickle charger */
        ds1302_writereg(RTC_TRICKLECHARGER,
                        RTC_TCR_PATTERN |(CONFIG_ETRAX_DS1302_TRICKLE_CHARGE & 0x0F));
+        /* Start clock by resetting CLOCK_HALT */
+       ds1302_writereg(RTC_SECONDS, (ds1302_readreg(RTC_SECONDS) & 0x7F));
        return 0;
 }