Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Ricoh RS5C313 RTC device/driver
0003  *  Copyright (C) 2007 Nobuhiro Iwamatsu
0004  *
0005  *  2005-09-19 modifed by kogiidena
0006  *
0007  * Based on the old drivers/char/rs5c313_rtc.c  by:
0008  *  Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
0009  *  Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
0010  *
0011  * Based on code written by Paul Gortmaker.
0012  *  Copyright (C) 1996 Paul Gortmaker
0013  *
0014  * This file is subject to the terms and conditions of the GNU General Public
0015  * License.  See the file "COPYING" in the main directory of this archive
0016  * for more details.
0017  *
0018  * Based on other minimal char device drivers, like Alan's
0019  * watchdog, Ted's random, etc. etc.
0020  *
0021  *  1.07    Paul Gortmaker.
0022  *  1.08    Miquel van Smoorenburg: disallow certain things on the
0023  *      DEC Alpha as the CMOS clock is also used for other things.
0024  *  1.09    Nikita Schmidt: epoch support and some Alpha cleanup.
0025  *  1.09a   Pete Zaitcev: Sun SPARC
0026  *  1.09b   Jeff Garzik: Modularize, init cleanup
0027  *  1.09c   Jeff Garzik: SMP cleanup
0028  *  1.10    Paul Barton-Davis: add support for async I/O
0029  *  1.10a   Andrea Arcangeli: Alpha updates
0030  *  1.10b   Andrew Morton: SMP lock fix
0031  *  1.10c   Cesar Barros: SMP locking fixes and cleanup
0032  *  1.10d   Paul Gortmaker: delete paranoia check in rtc_exit
0033  *  1.10e   Maciej W. Rozycki: Handle DECstation's year weirdness.
0034  *      1.11    Takashi Iwai: Kernel access functions
0035  *                rtc_register/rtc_unregister/rtc_control
0036  *      1.11a   Daniele Bellucci: Audit create_proc_read_entry in rtc_init
0037  *  1.12    Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer
0038  *      CONFIG_HPET_EMULATE_RTC
0039  *  1.13    Nobuhiro Iwamatsu: Updata driver.
0040  */
0041 
0042 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0043 
0044 #include <linux/module.h>
0045 #include <linux/err.h>
0046 #include <linux/rtc.h>
0047 #include <linux/platform_device.h>
0048 #include <linux/bcd.h>
0049 #include <linux/delay.h>
0050 #include <linux/io.h>
0051 
0052 #define DRV_NAME    "rs5c313"
0053 
0054 #ifdef CONFIG_SH_LANDISK
0055 /*****************************************************/
0056 /* LANDISK dependence part of RS5C313                */
0057 /*****************************************************/
0058 
0059 #define SCSMR1      0xFFE00000
0060 #define SCSCR1      0xFFE00008
0061 #define SCSMR1_CA   0x80
0062 #define SCSCR1_CKE  0x03
0063 #define SCSPTR1     0xFFE0001C
0064 #define SCSPTR1_EIO 0x80
0065 #define SCSPTR1_SPB1IO  0x08
0066 #define SCSPTR1_SPB1DT  0x04
0067 #define SCSPTR1_SPB0IO  0x02
0068 #define SCSPTR1_SPB0DT  0x01
0069 
0070 #define SDA_OEN     SCSPTR1_SPB1IO
0071 #define SDA     SCSPTR1_SPB1DT
0072 #define SCL_OEN     SCSPTR1_SPB0IO
0073 #define SCL     SCSPTR1_SPB0DT
0074 
0075 /* RICOH RS5C313 CE port */
0076 #define RS5C313_CE  0xB0000003
0077 
0078 /* RICOH RS5C313 CE port bit */
0079 #define RS5C313_CE_RTCCE    0x02
0080 
0081 /* SCSPTR1 data */
0082 unsigned char scsptr1_data;
0083 
0084 #define RS5C313_CEENABLE    __raw_writeb(RS5C313_CE_RTCCE, RS5C313_CE);
0085 #define RS5C313_CEDISABLE   __raw_writeb(0x00, RS5C313_CE)
0086 #define RS5C313_MISCOP      __raw_writeb(0x02, 0xB0000008)
0087 
0088 static void rs5c313_init_port(void)
0089 {
0090     /* Set SCK as I/O port and Initialize SCSPTR1 data & I/O port. */
0091     __raw_writeb(__raw_readb(SCSMR1) & ~SCSMR1_CA, SCSMR1);
0092     __raw_writeb(__raw_readb(SCSCR1) & ~SCSCR1_CKE, SCSCR1);
0093 
0094     /* And Initialize SCL for RS5C313 clock */
0095     scsptr1_data = __raw_readb(SCSPTR1) | SCL;  /* SCL:H */
0096     __raw_writeb(scsptr1_data, SCSPTR1);
0097     scsptr1_data = __raw_readb(SCSPTR1) | SCL_OEN;  /* SCL output enable */
0098     __raw_writeb(scsptr1_data, SCSPTR1);
0099     RS5C313_CEDISABLE;  /* CE:L */
0100 }
0101 
0102 static void rs5c313_write_data(unsigned char data)
0103 {
0104     int i;
0105 
0106     for (i = 0; i < 8; i++) {
0107         /* SDA:Write Data */
0108         scsptr1_data = (scsptr1_data & ~SDA) |
0109                 ((((0x80 >> i) & data) >> (7 - i)) << 2);
0110         __raw_writeb(scsptr1_data, SCSPTR1);
0111         if (i == 0) {
0112             scsptr1_data |= SDA_OEN;    /* SDA:output enable */
0113             __raw_writeb(scsptr1_data, SCSPTR1);
0114         }
0115         ndelay(700);
0116         scsptr1_data &= ~SCL;   /* SCL:L */
0117         __raw_writeb(scsptr1_data, SCSPTR1);
0118         ndelay(700);
0119         scsptr1_data |= SCL;    /* SCL:H */
0120         __raw_writeb(scsptr1_data, SCSPTR1);
0121     }
0122 
0123     scsptr1_data &= ~SDA_OEN;   /* SDA:output disable */
0124     __raw_writeb(scsptr1_data, SCSPTR1);
0125 }
0126 
0127 static unsigned char rs5c313_read_data(void)
0128 {
0129     int i;
0130     unsigned char data = 0;
0131 
0132     for (i = 0; i < 8; i++) {
0133         ndelay(700);
0134         /* SDA:Read Data */
0135         data |= ((__raw_readb(SCSPTR1) & SDA) >> 2) << (7 - i);
0136         scsptr1_data &= ~SCL;   /* SCL:L */
0137         __raw_writeb(scsptr1_data, SCSPTR1);
0138         ndelay(700);
0139         scsptr1_data |= SCL;    /* SCL:H */
0140         __raw_writeb(scsptr1_data, SCSPTR1);
0141     }
0142     return data & 0x0F;
0143 }
0144 
0145 #endif /* CONFIG_SH_LANDISK */
0146 
0147 /*****************************************************/
0148 /* machine independence part of RS5C313              */
0149 /*****************************************************/
0150 
0151 /* RICOH RS5C313 address */
0152 #define RS5C313_ADDR_SEC    0x00
0153 #define RS5C313_ADDR_SEC10  0x01
0154 #define RS5C313_ADDR_MIN    0x02
0155 #define RS5C313_ADDR_MIN10  0x03
0156 #define RS5C313_ADDR_HOUR   0x04
0157 #define RS5C313_ADDR_HOUR10 0x05
0158 #define RS5C313_ADDR_WEEK   0x06
0159 #define RS5C313_ADDR_INTINTVREG 0x07
0160 #define RS5C313_ADDR_DAY    0x08
0161 #define RS5C313_ADDR_DAY10  0x09
0162 #define RS5C313_ADDR_MON    0x0A
0163 #define RS5C313_ADDR_MON10  0x0B
0164 #define RS5C313_ADDR_YEAR   0x0C
0165 #define RS5C313_ADDR_YEAR10 0x0D
0166 #define RS5C313_ADDR_CNTREG 0x0E
0167 #define RS5C313_ADDR_TESTREG    0x0F
0168 
0169 /* RICOH RS5C313 control register */
0170 #define RS5C313_CNTREG_ADJ_BSY  0x01
0171 #define RS5C313_CNTREG_WTEN_XSTP    0x02
0172 #define RS5C313_CNTREG_12_24    0x04
0173 #define RS5C313_CNTREG_CTFG 0x08
0174 
0175 /* RICOH RS5C313 test register */
0176 #define RS5C313_TESTREG_TEST    0x01
0177 
0178 /* RICOH RS5C313 control bit */
0179 #define RS5C313_CNTBIT_READ 0x40
0180 #define RS5C313_CNTBIT_AD   0x20
0181 #define RS5C313_CNTBIT_DT   0x10
0182 
0183 static unsigned char rs5c313_read_reg(unsigned char addr)
0184 {
0185 
0186     rs5c313_write_data(addr | RS5C313_CNTBIT_READ | RS5C313_CNTBIT_AD);
0187     return rs5c313_read_data();
0188 }
0189 
0190 static void rs5c313_write_reg(unsigned char addr, unsigned char data)
0191 {
0192     data &= 0x0f;
0193     rs5c313_write_data(addr | RS5C313_CNTBIT_AD);
0194     rs5c313_write_data(data | RS5C313_CNTBIT_DT);
0195     return;
0196 }
0197 
0198 static inline unsigned char rs5c313_read_cntreg(void)
0199 {
0200     return rs5c313_read_reg(RS5C313_ADDR_CNTREG);
0201 }
0202 
0203 static inline void rs5c313_write_cntreg(unsigned char data)
0204 {
0205     rs5c313_write_reg(RS5C313_ADDR_CNTREG, data);
0206 }
0207 
0208 static inline void rs5c313_write_intintvreg(unsigned char data)
0209 {
0210     rs5c313_write_reg(RS5C313_ADDR_INTINTVREG, data);
0211 }
0212 
0213 static int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm)
0214 {
0215     int data;
0216     int cnt;
0217 
0218     cnt = 0;
0219     while (1) {
0220         RS5C313_CEENABLE;   /* CE:H */
0221 
0222         /* Initialize control reg. 24 hour */
0223         rs5c313_write_cntreg(0x04);
0224 
0225         if (!(rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY))
0226             break;
0227 
0228         RS5C313_CEDISABLE;
0229         ndelay(700);    /* CE:L */
0230 
0231         if (cnt++ > 100) {
0232             dev_err(dev, "%s: timeout error\n", __func__);
0233             return -EIO;
0234         }
0235     }
0236 
0237     data = rs5c313_read_reg(RS5C313_ADDR_SEC);
0238     data |= (rs5c313_read_reg(RS5C313_ADDR_SEC10) << 4);
0239     tm->tm_sec = bcd2bin(data);
0240 
0241     data = rs5c313_read_reg(RS5C313_ADDR_MIN);
0242     data |= (rs5c313_read_reg(RS5C313_ADDR_MIN10) << 4);
0243     tm->tm_min = bcd2bin(data);
0244 
0245     data = rs5c313_read_reg(RS5C313_ADDR_HOUR);
0246     data |= (rs5c313_read_reg(RS5C313_ADDR_HOUR10) << 4);
0247     tm->tm_hour = bcd2bin(data);
0248 
0249     data = rs5c313_read_reg(RS5C313_ADDR_DAY);
0250     data |= (rs5c313_read_reg(RS5C313_ADDR_DAY10) << 4);
0251     tm->tm_mday = bcd2bin(data);
0252 
0253     data = rs5c313_read_reg(RS5C313_ADDR_MON);
0254     data |= (rs5c313_read_reg(RS5C313_ADDR_MON10) << 4);
0255     tm->tm_mon = bcd2bin(data) - 1;
0256 
0257     data = rs5c313_read_reg(RS5C313_ADDR_YEAR);
0258     data |= (rs5c313_read_reg(RS5C313_ADDR_YEAR10) << 4);
0259     tm->tm_year = bcd2bin(data);
0260 
0261     if (tm->tm_year < 70)
0262         tm->tm_year += 100;
0263 
0264     data = rs5c313_read_reg(RS5C313_ADDR_WEEK);
0265     tm->tm_wday = bcd2bin(data);
0266 
0267     RS5C313_CEDISABLE;
0268     ndelay(700);        /* CE:L */
0269 
0270     return 0;
0271 }
0272 
0273 static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm)
0274 {
0275     int data;
0276     int cnt;
0277 
0278     cnt = 0;
0279     /* busy check. */
0280     while (1) {
0281         RS5C313_CEENABLE;   /* CE:H */
0282 
0283         /* Initiatlize control reg. 24 hour */
0284         rs5c313_write_cntreg(0x04);
0285 
0286         if (!(rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY))
0287             break;
0288         RS5C313_MISCOP;
0289         RS5C313_CEDISABLE;
0290         ndelay(700);    /* CE:L */
0291 
0292         if (cnt++ > 100) {
0293             dev_err(dev, "%s: timeout error\n", __func__);
0294             return -EIO;
0295         }
0296     }
0297 
0298     data = bin2bcd(tm->tm_sec);
0299     rs5c313_write_reg(RS5C313_ADDR_SEC, data);
0300     rs5c313_write_reg(RS5C313_ADDR_SEC10, (data >> 4));
0301 
0302     data = bin2bcd(tm->tm_min);
0303     rs5c313_write_reg(RS5C313_ADDR_MIN, data);
0304     rs5c313_write_reg(RS5C313_ADDR_MIN10, (data >> 4));
0305 
0306     data = bin2bcd(tm->tm_hour);
0307     rs5c313_write_reg(RS5C313_ADDR_HOUR, data);
0308     rs5c313_write_reg(RS5C313_ADDR_HOUR10, (data >> 4));
0309 
0310     data = bin2bcd(tm->tm_mday);
0311     rs5c313_write_reg(RS5C313_ADDR_DAY, data);
0312     rs5c313_write_reg(RS5C313_ADDR_DAY10, (data >> 4));
0313 
0314     data = bin2bcd(tm->tm_mon + 1);
0315     rs5c313_write_reg(RS5C313_ADDR_MON, data);
0316     rs5c313_write_reg(RS5C313_ADDR_MON10, (data >> 4));
0317 
0318     data = bin2bcd(tm->tm_year % 100);
0319     rs5c313_write_reg(RS5C313_ADDR_YEAR, data);
0320     rs5c313_write_reg(RS5C313_ADDR_YEAR10, (data >> 4));
0321 
0322     data = bin2bcd(tm->tm_wday);
0323     rs5c313_write_reg(RS5C313_ADDR_WEEK, data);
0324 
0325     RS5C313_CEDISABLE;  /* CE:H */
0326     ndelay(700);
0327 
0328     return 0;
0329 }
0330 
0331 static void rs5c313_check_xstp_bit(void)
0332 {
0333     struct rtc_time tm;
0334     int cnt;
0335 
0336     RS5C313_CEENABLE;   /* CE:H */
0337     if (rs5c313_read_cntreg() & RS5C313_CNTREG_WTEN_XSTP) {
0338         /* INT interval reg. OFF */
0339         rs5c313_write_intintvreg(0x00);
0340         /* Initialize control reg. 24 hour & adjust */
0341         rs5c313_write_cntreg(0x07);
0342 
0343         /* busy check. */
0344         for (cnt = 0; cnt < 100; cnt++) {
0345             if (!(rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY))
0346                 break;
0347             RS5C313_MISCOP;
0348         }
0349 
0350         memset(&tm, 0, sizeof(struct rtc_time));
0351         tm.tm_mday  = 1;
0352         tm.tm_mon   = 1 - 1;
0353         tm.tm_year  = 2000 - 1900;
0354 
0355         rs5c313_rtc_set_time(NULL, &tm);
0356         pr_err("invalid value, resetting to 1 Jan 2000\n");
0357     }
0358     RS5C313_CEDISABLE;
0359     ndelay(700);        /* CE:L */
0360 }
0361 
0362 static const struct rtc_class_ops rs5c313_rtc_ops = {
0363     .read_time = rs5c313_rtc_read_time,
0364     .set_time = rs5c313_rtc_set_time,
0365 };
0366 
0367 static int rs5c313_rtc_probe(struct platform_device *pdev)
0368 {
0369     struct rtc_device *rtc;
0370 
0371     rs5c313_init_port();
0372     rs5c313_check_xstp_bit();
0373 
0374     rtc = devm_rtc_device_register(&pdev->dev, "rs5c313", &rs5c313_rtc_ops,
0375                        THIS_MODULE);
0376 
0377     return PTR_ERR_OR_ZERO(rtc);
0378 }
0379 
0380 static struct platform_driver rs5c313_rtc_platform_driver = {
0381     .driver         = {
0382         .name   = DRV_NAME,
0383     },
0384     .probe  = rs5c313_rtc_probe,
0385 };
0386 
0387 module_platform_driver(rs5c313_rtc_platform_driver);
0388 
0389 MODULE_AUTHOR("kogiidena , Nobuhiro Iwamatsu <iwamatsu@nigauri.org>");
0390 MODULE_DESCRIPTION("Ricoh RS5C313 RTC device driver");
0391 MODULE_LICENSE("GPL");
0392 MODULE_ALIAS("platform:" DRV_NAME);