Version:  2.0.40 2.2.26 2.4.37 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16

Linux/drivers/rtc/rtc-m48t86.c

  1 /*
  2  * ST M48T86 / Dallas DS12887 RTC driver
  3  * Copyright (c) 2006 Tower Technologies
  4  *
  5  * Author: Alessandro Zummo <a.zummo@towertech.it>
  6  *
  7  * This program is free software; you can redistribute it and/or modify
  8  * it under the terms of the GNU General Public License version 2 as
  9  * published by the Free Software Foundation.
 10  *
 11  * This drivers only supports the clock running in BCD and 24H mode.
 12  * If it will be ever adapted to binary and 12H mode, care must be taken
 13  * to not introduce bugs.
 14  */
 15 
 16 #include <linux/module.h>
 17 #include <linux/rtc.h>
 18 #include <linux/platform_device.h>
 19 #include <linux/m48t86.h>
 20 #include <linux/bcd.h>
 21 
 22 #define M48T86_REG_SEC          0x00
 23 #define M48T86_REG_SECALRM      0x01
 24 #define M48T86_REG_MIN          0x02
 25 #define M48T86_REG_MINALRM      0x03
 26 #define M48T86_REG_HOUR         0x04
 27 #define M48T86_REG_HOURALRM     0x05
 28 #define M48T86_REG_DOW          0x06 /* 1 = sunday */
 29 #define M48T86_REG_DOM          0x07
 30 #define M48T86_REG_MONTH        0x08 /* 1 - 12 */
 31 #define M48T86_REG_YEAR         0x09 /* 0 - 99 */
 32 #define M48T86_REG_A            0x0A
 33 #define M48T86_REG_B            0x0B
 34 #define M48T86_REG_C            0x0C
 35 #define M48T86_REG_D            0x0D
 36 
 37 #define M48T86_REG_B_H24        (1 << 1)
 38 #define M48T86_REG_B_DM         (1 << 2)
 39 #define M48T86_REG_B_SET        (1 << 7)
 40 #define M48T86_REG_D_VRT        (1 << 7)
 41 
 42 #define DRV_VERSION "0.1"
 43 
 44 
 45 static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm)
 46 {
 47         unsigned char reg;
 48         struct platform_device *pdev = to_platform_device(dev);
 49         struct m48t86_ops *ops = dev_get_platdata(&pdev->dev);
 50 
 51         reg = ops->readbyte(M48T86_REG_B);
 52 
 53         if (reg & M48T86_REG_B_DM) {
 54                 /* data (binary) mode */
 55                 tm->tm_sec      = ops->readbyte(M48T86_REG_SEC);
 56                 tm->tm_min      = ops->readbyte(M48T86_REG_MIN);
 57                 tm->tm_hour     = ops->readbyte(M48T86_REG_HOUR) & 0x3F;
 58                 tm->tm_mday     = ops->readbyte(M48T86_REG_DOM);
 59                 /* tm_mon is 0-11 */
 60                 tm->tm_mon      = ops->readbyte(M48T86_REG_MONTH) - 1;
 61                 tm->tm_year     = ops->readbyte(M48T86_REG_YEAR) + 100;
 62                 tm->tm_wday     = ops->readbyte(M48T86_REG_DOW);
 63         } else {
 64                 /* bcd mode */
 65                 tm->tm_sec      = bcd2bin(ops->readbyte(M48T86_REG_SEC));
 66                 tm->tm_min      = bcd2bin(ops->readbyte(M48T86_REG_MIN));
 67                 tm->tm_hour     = bcd2bin(ops->readbyte(M48T86_REG_HOUR) & 0x3F);
 68                 tm->tm_mday     = bcd2bin(ops->readbyte(M48T86_REG_DOM));
 69                 /* tm_mon is 0-11 */
 70                 tm->tm_mon      = bcd2bin(ops->readbyte(M48T86_REG_MONTH)) - 1;
 71                 tm->tm_year     = bcd2bin(ops->readbyte(M48T86_REG_YEAR)) + 100;
 72                 tm->tm_wday     = bcd2bin(ops->readbyte(M48T86_REG_DOW));
 73         }
 74 
 75         /* correct the hour if the clock is in 12h mode */
 76         if (!(reg & M48T86_REG_B_H24))
 77                 if (ops->readbyte(M48T86_REG_HOUR) & 0x80)
 78                         tm->tm_hour += 12;
 79 
 80         return rtc_valid_tm(tm);
 81 }
 82 
 83 static int m48t86_rtc_set_time(struct device *dev, struct rtc_time *tm)
 84 {
 85         unsigned char reg;
 86         struct platform_device *pdev = to_platform_device(dev);
 87         struct m48t86_ops *ops = dev_get_platdata(&pdev->dev);
 88 
 89         reg = ops->readbyte(M48T86_REG_B);
 90 
 91         /* update flag and 24h mode */
 92         reg |= M48T86_REG_B_SET | M48T86_REG_B_H24;
 93         ops->writebyte(reg, M48T86_REG_B);
 94 
 95         if (reg & M48T86_REG_B_DM) {
 96                 /* data (binary) mode */
 97                 ops->writebyte(tm->tm_sec, M48T86_REG_SEC);
 98                 ops->writebyte(tm->tm_min, M48T86_REG_MIN);
 99                 ops->writebyte(tm->tm_hour, M48T86_REG_HOUR);
100                 ops->writebyte(tm->tm_mday, M48T86_REG_DOM);
101                 ops->writebyte(tm->tm_mon + 1, M48T86_REG_MONTH);
102                 ops->writebyte(tm->tm_year % 100, M48T86_REG_YEAR);
103                 ops->writebyte(tm->tm_wday, M48T86_REG_DOW);
104         } else {
105                 /* bcd mode */
106                 ops->writebyte(bin2bcd(tm->tm_sec), M48T86_REG_SEC);
107                 ops->writebyte(bin2bcd(tm->tm_min), M48T86_REG_MIN);
108                 ops->writebyte(bin2bcd(tm->tm_hour), M48T86_REG_HOUR);
109                 ops->writebyte(bin2bcd(tm->tm_mday), M48T86_REG_DOM);
110                 ops->writebyte(bin2bcd(tm->tm_mon + 1), M48T86_REG_MONTH);
111                 ops->writebyte(bin2bcd(tm->tm_year % 100), M48T86_REG_YEAR);
112                 ops->writebyte(bin2bcd(tm->tm_wday), M48T86_REG_DOW);
113         }
114 
115         /* update ended */
116         reg &= ~M48T86_REG_B_SET;
117         ops->writebyte(reg, M48T86_REG_B);
118 
119         return 0;
120 }
121 
122 static int m48t86_rtc_proc(struct device *dev, struct seq_file *seq)
123 {
124         unsigned char reg;
125         struct platform_device *pdev = to_platform_device(dev);
126         struct m48t86_ops *ops = dev_get_platdata(&pdev->dev);
127 
128         reg = ops->readbyte(M48T86_REG_B);
129 
130         seq_printf(seq, "mode\t\t: %s\n",
131                  (reg & M48T86_REG_B_DM) ? "binary" : "bcd");
132 
133         reg = ops->readbyte(M48T86_REG_D);
134 
135         seq_printf(seq, "battery\t\t: %s\n",
136                  (reg & M48T86_REG_D_VRT) ? "ok" : "exhausted");
137 
138         return 0;
139 }
140 
141 static const struct rtc_class_ops m48t86_rtc_ops = {
142         .read_time      = m48t86_rtc_read_time,
143         .set_time       = m48t86_rtc_set_time,
144         .proc           = m48t86_rtc_proc,
145 };
146 
147 static int m48t86_rtc_probe(struct platform_device *dev)
148 {
149         unsigned char reg;
150         struct m48t86_ops *ops = dev_get_platdata(&dev->dev);
151         struct rtc_device *rtc;
152 
153         rtc = devm_rtc_device_register(&dev->dev, "m48t86",
154                                 &m48t86_rtc_ops, THIS_MODULE);
155 
156         if (IS_ERR(rtc))
157                 return PTR_ERR(rtc);
158 
159         platform_set_drvdata(dev, rtc);
160 
161         /* read battery status */
162         reg = ops->readbyte(M48T86_REG_D);
163         dev_info(&dev->dev, "battery %s\n",
164                 (reg & M48T86_REG_D_VRT) ? "ok" : "exhausted");
165 
166         return 0;
167 }
168 
169 static struct platform_driver m48t86_rtc_platform_driver = {
170         .driver         = {
171                 .name   = "rtc-m48t86",
172                 .owner  = THIS_MODULE,
173         },
174         .probe          = m48t86_rtc_probe,
175 };
176 
177 module_platform_driver(m48t86_rtc_platform_driver);
178 
179 MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
180 MODULE_DESCRIPTION("M48T86 RTC driver");
181 MODULE_LICENSE("GPL");
182 MODULE_VERSION(DRV_VERSION);
183 MODULE_ALIAS("platform:rtc-m48t86");
184 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us