xref: /linux/drivers/rtc/rtc-m48t86.c (revision 26ba30221c03364d6ed9910be8da4c1fd871b07b)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * ST M48T86 / Dallas DS12887 RTC driver
4  * Copyright (c) 2006 Tower Technologies
5  *
6  * Author: Alessandro Zummo <a.zummo@towertech.it>
7  *
8  * This drivers only supports the clock running in BCD and 24H mode.
9  * If it will be ever adapted to binary and 12H mode, care must be taken
10  * to not introduce bugs.
11  */
12 
13 #include <linux/module.h>
14 #include <linux/rtc.h>
15 #include <linux/platform_device.h>
16 #include <linux/bcd.h>
17 #include <linux/io.h>
18 
19 #define M48T86_SEC		0x00
20 #define M48T86_SECALRM		0x01
21 #define M48T86_MIN		0x02
22 #define M48T86_MINALRM		0x03
23 #define M48T86_HOUR		0x04
24 #define M48T86_HOURALRM		0x05
25 #define M48T86_DOW		0x06 /* 1 = sunday */
26 #define M48T86_DOM		0x07
27 #define M48T86_MONTH		0x08 /* 1 - 12 */
28 #define M48T86_YEAR		0x09 /* 0 - 99 */
29 #define M48T86_A		0x0a
30 #define M48T86_B		0x0b
31 #define M48T86_B_SET		BIT(7)
32 #define M48T86_B_DM		BIT(2)
33 #define M48T86_B_H24		BIT(1)
34 #define M48T86_C		0x0c
35 #define M48T86_D		0x0d
36 #define M48T86_D_VRT		BIT(7)
37 #define M48T86_NVRAM(x)		(0x0e + (x))
38 #define M48T86_NVRAM_LEN	114
39 
40 struct m48t86_rtc_info {
41 	void __iomem *index_reg;
42 	void __iomem *data_reg;
43 };
44 
45 static unsigned char m48t86_readb(struct device *dev, unsigned long addr)
46 {
47 	struct m48t86_rtc_info *info = dev_get_drvdata(dev);
48 	unsigned char value;
49 
50 	writeb(addr, info->index_reg);
51 	value = readb(info->data_reg);
52 
53 	return value;
54 }
55 
56 static void m48t86_writeb(struct device *dev,
57 			  unsigned char value, unsigned long addr)
58 {
59 	struct m48t86_rtc_info *info = dev_get_drvdata(dev);
60 
61 	writeb(addr, info->index_reg);
62 	writeb(value, info->data_reg);
63 }
64 
65 static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm)
66 {
67 	unsigned char reg;
68 
69 	reg = m48t86_readb(dev, M48T86_B);
70 
71 	if (reg & M48T86_B_DM) {
72 		/* data (binary) mode */
73 		tm->tm_sec	= m48t86_readb(dev, M48T86_SEC);
74 		tm->tm_min	= m48t86_readb(dev, M48T86_MIN);
75 		tm->tm_hour	= m48t86_readb(dev, M48T86_HOUR) & 0x3f;
76 		tm->tm_mday	= m48t86_readb(dev, M48T86_DOM);
77 		/* tm_mon is 0-11 */
78 		tm->tm_mon	= m48t86_readb(dev, M48T86_MONTH) - 1;
79 		tm->tm_year	= m48t86_readb(dev, M48T86_YEAR) + 100;
80 		tm->tm_wday	= m48t86_readb(dev, M48T86_DOW);
81 	} else {
82 		/* bcd mode */
83 		tm->tm_sec	= bcd2bin(m48t86_readb(dev, M48T86_SEC));
84 		tm->tm_min	= bcd2bin(m48t86_readb(dev, M48T86_MIN));
85 		tm->tm_hour	= bcd2bin(m48t86_readb(dev, M48T86_HOUR) &
86 					  0x3f);
87 		tm->tm_mday	= bcd2bin(m48t86_readb(dev, M48T86_DOM));
88 		/* tm_mon is 0-11 */
89 		tm->tm_mon	= bcd2bin(m48t86_readb(dev, M48T86_MONTH)) - 1;
90 		tm->tm_year	= bcd2bin(m48t86_readb(dev, M48T86_YEAR)) + 100;
91 		tm->tm_wday	= bcd2bin(m48t86_readb(dev, M48T86_DOW));
92 	}
93 
94 	/* correct the hour if the clock is in 12h mode */
95 	if (!(reg & M48T86_B_H24))
96 		if (m48t86_readb(dev, M48T86_HOUR) & 0x80)
97 			tm->tm_hour += 12;
98 
99 	return 0;
100 }
101 
102 static int m48t86_rtc_set_time(struct device *dev, struct rtc_time *tm)
103 {
104 	unsigned char reg;
105 
106 	reg = m48t86_readb(dev, M48T86_B);
107 
108 	/* update flag and 24h mode */
109 	reg |= M48T86_B_SET | M48T86_B_H24;
110 	m48t86_writeb(dev, reg, M48T86_B);
111 
112 	if (reg & M48T86_B_DM) {
113 		/* data (binary) mode */
114 		m48t86_writeb(dev, tm->tm_sec, M48T86_SEC);
115 		m48t86_writeb(dev, tm->tm_min, M48T86_MIN);
116 		m48t86_writeb(dev, tm->tm_hour, M48T86_HOUR);
117 		m48t86_writeb(dev, tm->tm_mday, M48T86_DOM);
118 		m48t86_writeb(dev, tm->tm_mon + 1, M48T86_MONTH);
119 		m48t86_writeb(dev, tm->tm_year % 100, M48T86_YEAR);
120 		m48t86_writeb(dev, tm->tm_wday, M48T86_DOW);
121 	} else {
122 		/* bcd mode */
123 		m48t86_writeb(dev, bin2bcd(tm->tm_sec), M48T86_SEC);
124 		m48t86_writeb(dev, bin2bcd(tm->tm_min), M48T86_MIN);
125 		m48t86_writeb(dev, bin2bcd(tm->tm_hour), M48T86_HOUR);
126 		m48t86_writeb(dev, bin2bcd(tm->tm_mday), M48T86_DOM);
127 		m48t86_writeb(dev, bin2bcd(tm->tm_mon + 1), M48T86_MONTH);
128 		m48t86_writeb(dev, bin2bcd(tm->tm_year % 100), M48T86_YEAR);
129 		m48t86_writeb(dev, bin2bcd(tm->tm_wday), M48T86_DOW);
130 	}
131 
132 	/* update ended */
133 	reg &= ~M48T86_B_SET;
134 	m48t86_writeb(dev, reg, M48T86_B);
135 
136 	return 0;
137 }
138 
139 static int m48t86_rtc_proc(struct device *dev, struct seq_file *seq)
140 {
141 	unsigned char reg;
142 
143 	reg = m48t86_readb(dev, M48T86_B);
144 
145 	seq_printf(seq, "mode\t\t: %s\n",
146 		   (reg & M48T86_B_DM) ? "binary" : "bcd");
147 
148 	reg = m48t86_readb(dev, M48T86_D);
149 
150 	seq_printf(seq, "battery\t\t: %s\n",
151 		   (reg & M48T86_D_VRT) ? "ok" : "exhausted");
152 
153 	return 0;
154 }
155 
156 static const struct rtc_class_ops m48t86_rtc_ops = {
157 	.read_time	= m48t86_rtc_read_time,
158 	.set_time	= m48t86_rtc_set_time,
159 	.proc		= m48t86_rtc_proc,
160 };
161 
162 static int m48t86_nvram_read(void *priv, unsigned int off, void *buf,
163 			     size_t count)
164 {
165 	struct device *dev = priv;
166 	unsigned int i;
167 
168 	for (i = 0; i < count; i++)
169 		((u8 *)buf)[i] = m48t86_readb(dev, M48T86_NVRAM(off + i));
170 
171 	return 0;
172 }
173 
174 static int m48t86_nvram_write(void *priv, unsigned int off, void *buf,
175 			      size_t count)
176 {
177 	struct device *dev = priv;
178 	unsigned int i;
179 
180 	for (i = 0; i < count; i++)
181 		m48t86_writeb(dev, ((u8 *)buf)[i], M48T86_NVRAM(off + i));
182 
183 	return 0;
184 }
185 
186 /*
187  * The RTC is an optional feature at purchase time on some Technologic Systems
188  * boards. Verify that it actually exists by checking if the last two bytes
189  * of the NVRAM can be changed.
190  *
191  * This is based on the method used in their rtc7800.c example.
192  */
193 static bool m48t86_verify_chip(struct platform_device *pdev)
194 {
195 	unsigned int offset0 = M48T86_NVRAM(M48T86_NVRAM_LEN - 2);
196 	unsigned int offset1 = M48T86_NVRAM(M48T86_NVRAM_LEN - 1);
197 	unsigned char tmp0, tmp1;
198 
199 	tmp0 = m48t86_readb(&pdev->dev, offset0);
200 	tmp1 = m48t86_readb(&pdev->dev, offset1);
201 
202 	m48t86_writeb(&pdev->dev, 0x00, offset0);
203 	m48t86_writeb(&pdev->dev, 0x55, offset1);
204 	if (m48t86_readb(&pdev->dev, offset1) == 0x55) {
205 		m48t86_writeb(&pdev->dev, 0xaa, offset1);
206 		if (m48t86_readb(&pdev->dev, offset1) == 0xaa &&
207 		    m48t86_readb(&pdev->dev, offset0) == 0x00) {
208 			m48t86_writeb(&pdev->dev, tmp0, offset0);
209 			m48t86_writeb(&pdev->dev, tmp1, offset1);
210 
211 			return true;
212 		}
213 	}
214 	return false;
215 }
216 
217 static int m48t86_rtc_probe(struct platform_device *pdev)
218 {
219 	struct m48t86_rtc_info *info;
220 	struct rtc_device *rtc;
221 	unsigned char reg;
222 	int err;
223 	struct nvmem_config m48t86_nvmem_cfg = {
224 		.name = "m48t86_nvram",
225 		.word_size = 1,
226 		.stride = 1,
227 		.size = M48T86_NVRAM_LEN,
228 		.reg_read = m48t86_nvram_read,
229 		.reg_write = m48t86_nvram_write,
230 		.priv = &pdev->dev,
231 	};
232 
233 	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
234 	if (!info)
235 		return -ENOMEM;
236 
237 	info->index_reg = devm_platform_ioremap_resource(pdev, 0);
238 	if (IS_ERR(info->index_reg))
239 		return PTR_ERR(info->index_reg);
240 
241 	info->data_reg = devm_platform_ioremap_resource(pdev, 1);
242 	if (IS_ERR(info->data_reg))
243 		return PTR_ERR(info->data_reg);
244 
245 	dev_set_drvdata(&pdev->dev, info);
246 
247 	if (!m48t86_verify_chip(pdev)) {
248 		dev_info(&pdev->dev, "RTC not present\n");
249 		return -ENODEV;
250 	}
251 
252 	rtc = devm_rtc_allocate_device(&pdev->dev);
253 	if (IS_ERR(rtc))
254 		return PTR_ERR(rtc);
255 
256 	rtc->ops = &m48t86_rtc_ops;
257 
258 	err = devm_rtc_register_device(rtc);
259 	if (err)
260 		return err;
261 
262 	devm_rtc_nvmem_register(rtc, &m48t86_nvmem_cfg);
263 
264 	/* read battery status */
265 	reg = m48t86_readb(&pdev->dev, M48T86_D);
266 	dev_info(&pdev->dev, "battery %s\n",
267 		 (reg & M48T86_D_VRT) ? "ok" : "exhausted");
268 
269 	return 0;
270 }
271 
272 static const struct of_device_id m48t86_rtc_of_ids[] = {
273 	{ .compatible = "st,m48t86" },
274 	{ /* sentinel */ }
275 };
276 MODULE_DEVICE_TABLE(of, m48t86_rtc_of_ids);
277 
278 static struct platform_driver m48t86_rtc_platform_driver = {
279 	.driver		= {
280 		.name	= "rtc-m48t86",
281 		.of_match_table = m48t86_rtc_of_ids,
282 	},
283 	.probe		= m48t86_rtc_probe,
284 };
285 
286 module_platform_driver(m48t86_rtc_platform_driver);
287 
288 MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
289 MODULE_DESCRIPTION("M48T86 RTC driver");
290 MODULE_LICENSE("GPL");
291 MODULE_ALIAS("platform:rtc-m48t86");
292