1
2
3
4
5
6
7
8
9
10
11
12#include <linux/bcd.h>
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/platform_device.h>
16#include <linux/rtc.h>
17#include <linux/spi/spi.h>
18
19#define M41T93_REG_SSEC 0
20#define M41T93_REG_ST_SEC 1
21#define M41T93_REG_MIN 2
22#define M41T93_REG_CENT_HOUR 3
23#define M41T93_REG_WDAY 4
24#define M41T93_REG_DAY 5
25#define M41T93_REG_MON 6
26#define M41T93_REG_YEAR 7
27
28
29#define M41T93_REG_ALM_HOUR_HT 0xc
30#define M41T93_REG_FLAGS 0xf
31
32#define M41T93_FLAG_ST (1 << 7)
33#define M41T93_FLAG_OF (1 << 2)
34#define M41T93_FLAG_BL (1 << 4)
35#define M41T93_FLAG_HT (1 << 6)
36
37static inline int m41t93_set_reg(struct spi_device *spi, u8 addr, u8 data)
38{
39 u8 buf[2];
40
41
42 buf[0] = addr | 0x80;
43 buf[1] = data;
44
45 return spi_write(spi, buf, sizeof(buf));
46}
47
48static int m41t93_set_time(struct device *dev, struct rtc_time *tm)
49{
50 struct spi_device *spi = to_spi_device(dev);
51 int tmp;
52 u8 buf[9] = {0x80};
53 u8 * const data = &buf[1];
54
55 dev_dbg(dev, "%s secs=%d, mins=%d, "
56 "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
57 "write", tm->tm_sec, tm->tm_min,
58 tm->tm_hour, tm->tm_mday,
59 tm->tm_mon, tm->tm_year, tm->tm_wday);
60
61 if (tm->tm_year < 100) {
62 dev_warn(&spi->dev, "unsupported date (before 2000-01-01).\n");
63 return -EINVAL;
64 }
65
66 tmp = spi_w8r8(spi, M41T93_REG_FLAGS);
67 if (tmp < 0)
68 return tmp;
69
70 if (tmp & M41T93_FLAG_OF) {
71 dev_warn(&spi->dev, "OF bit is set, resetting.\n");
72 m41t93_set_reg(spi, M41T93_REG_FLAGS, tmp & ~M41T93_FLAG_OF);
73
74 tmp = spi_w8r8(spi, M41T93_REG_FLAGS);
75 if (tmp < 0) {
76 return tmp;
77 } else if (tmp & M41T93_FLAG_OF) {
78
79
80 u8 reset_osc = buf[M41T93_REG_ST_SEC] | M41T93_FLAG_ST;
81
82 dev_warn(&spi->dev,
83 "OF bit is still set, kickstarting clock.\n");
84 m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc);
85 reset_osc &= ~M41T93_FLAG_ST;
86 m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc);
87 }
88 }
89
90 data[M41T93_REG_SSEC] = 0;
91 data[M41T93_REG_ST_SEC] = bin2bcd(tm->tm_sec);
92 data[M41T93_REG_MIN] = bin2bcd(tm->tm_min);
93 data[M41T93_REG_CENT_HOUR] = bin2bcd(tm->tm_hour) |
94 ((tm->tm_year/100-1) << 6);
95 data[M41T93_REG_DAY] = bin2bcd(tm->tm_mday);
96 data[M41T93_REG_WDAY] = bin2bcd(tm->tm_wday + 1);
97 data[M41T93_REG_MON] = bin2bcd(tm->tm_mon + 1);
98 data[M41T93_REG_YEAR] = bin2bcd(tm->tm_year % 100);
99
100 return spi_write(spi, buf, sizeof(buf));
101}
102
103
104static int m41t93_get_time(struct device *dev, struct rtc_time *tm)
105{
106 struct spi_device *spi = to_spi_device(dev);
107 const u8 start_addr = 0;
108 u8 buf[8];
109 int century_after_1900;
110 int tmp;
111 int ret = 0;
112
113
114
115
116
117
118
119 tmp = spi_w8r8(spi, M41T93_REG_ALM_HOUR_HT);
120 if (tmp < 0)
121 return tmp;
122
123 if (tmp & M41T93_FLAG_HT) {
124 dev_dbg(&spi->dev, "HT bit is set, reenable clock update.\n");
125 m41t93_set_reg(spi, M41T93_REG_ALM_HOUR_HT,
126 tmp & ~M41T93_FLAG_HT);
127 }
128
129 tmp = spi_w8r8(spi, M41T93_REG_FLAGS);
130 if (tmp < 0)
131 return tmp;
132
133 if (tmp & M41T93_FLAG_OF) {
134 ret = -EINVAL;
135 dev_warn(&spi->dev, "OF bit is set, write time to restart.\n");
136 }
137
138 if (tmp & M41T93_FLAG_BL)
139 dev_warn(&spi->dev, "BL bit is set, replace battery.\n");
140
141
142 tmp = spi_write_then_read(spi, &start_addr, 1, buf, sizeof(buf));
143 if (tmp < 0)
144 return tmp;
145
146 tm->tm_sec = bcd2bin(buf[M41T93_REG_ST_SEC]);
147 tm->tm_min = bcd2bin(buf[M41T93_REG_MIN]);
148 tm->tm_hour = bcd2bin(buf[M41T93_REG_CENT_HOUR] & 0x3f);
149 tm->tm_mday = bcd2bin(buf[M41T93_REG_DAY]);
150 tm->tm_mon = bcd2bin(buf[M41T93_REG_MON]) - 1;
151 tm->tm_wday = bcd2bin(buf[M41T93_REG_WDAY] & 0x0f) - 1;
152
153 century_after_1900 = (buf[M41T93_REG_CENT_HOUR] >> 6) + 1;
154 tm->tm_year = bcd2bin(buf[M41T93_REG_YEAR]) + century_after_1900 * 100;
155
156 dev_dbg(dev, "%s secs=%d, mins=%d, "
157 "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
158 "read", tm->tm_sec, tm->tm_min,
159 tm->tm_hour, tm->tm_mday,
160 tm->tm_mon, tm->tm_year, tm->tm_wday);
161
162 return ret;
163}
164
165
166static const struct rtc_class_ops m41t93_rtc_ops = {
167 .read_time = m41t93_get_time,
168 .set_time = m41t93_set_time,
169};
170
171static struct spi_driver m41t93_driver;
172
173static int m41t93_probe(struct spi_device *spi)
174{
175 struct rtc_device *rtc;
176 int res;
177
178 spi->bits_per_word = 8;
179 spi_setup(spi);
180
181 res = spi_w8r8(spi, M41T93_REG_WDAY);
182 if (res < 0 || (res & 0xf8) != 0) {
183 dev_err(&spi->dev, "not found 0x%x.\n", res);
184 return -ENODEV;
185 }
186
187 rtc = devm_rtc_device_register(&spi->dev, m41t93_driver.driver.name,
188 &m41t93_rtc_ops, THIS_MODULE);
189 if (IS_ERR(rtc))
190 return PTR_ERR(rtc);
191
192 spi_set_drvdata(spi, rtc);
193
194 return 0;
195}
196
197static struct spi_driver m41t93_driver = {
198 .driver = {
199 .name = "rtc-m41t93",
200 },
201 .probe = m41t93_probe,
202};
203
204module_spi_driver(m41t93_driver);
205
206MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>");
207MODULE_DESCRIPTION("Driver for ST M41T93 SPI RTC");
208MODULE_LICENSE("GPL");
209MODULE_ALIAS("spi:rtc-m41t93");
210