Commit | Line | Data |
---|---|---|
09c434b8 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
0b6a8f5c AM |
2 | /* |
3 | * EPSON TOYOCOM RTC-7301SF/DG Driver | |
4 | * | |
5 | * Copyright (c) 2016 Akinobu Mita <akinobu.mita@gmail.com> | |
6 | * | |
7 | * Based on rtc-rp5c01.c | |
8 | * | |
9 | * Datasheet: http://www5.epsondevice.com/en/products/parallel/rtc7301sf.html | |
10 | */ | |
11 | ||
12 | #include <linux/io.h> | |
13 | #include <linux/kernel.h> | |
14 | #include <linux/module.h> | |
ac316725 | 15 | #include <linux/mod_devicetable.h> |
0b6a8f5c AM |
16 | #include <linux/delay.h> |
17 | #include <linux/regmap.h> | |
18 | #include <linux/platform_device.h> | |
19 | #include <linux/rtc.h> | |
20 | ||
21 | #define DRV_NAME "rtc-r7301" | |
22 | ||
23 | #define RTC7301_1_SEC 0x0 /* Bank 0 and Band 1 */ | |
24 | #define RTC7301_10_SEC 0x1 /* Bank 0 and Band 1 */ | |
25 | #define RTC7301_AE BIT(3) | |
26 | #define RTC7301_1_MIN 0x2 /* Bank 0 and Band 1 */ | |
27 | #define RTC7301_10_MIN 0x3 /* Bank 0 and Band 1 */ | |
28 | #define RTC7301_1_HOUR 0x4 /* Bank 0 and Band 1 */ | |
29 | #define RTC7301_10_HOUR 0x5 /* Bank 0 and Band 1 */ | |
30 | #define RTC7301_DAY_OF_WEEK 0x6 /* Bank 0 and Band 1 */ | |
31 | #define RTC7301_1_DAY 0x7 /* Bank 0 and Band 1 */ | |
32 | #define RTC7301_10_DAY 0x8 /* Bank 0 and Band 1 */ | |
33 | #define RTC7301_1_MONTH 0x9 /* Bank 0 */ | |
34 | #define RTC7301_10_MONTH 0xa /* Bank 0 */ | |
35 | #define RTC7301_1_YEAR 0xb /* Bank 0 */ | |
36 | #define RTC7301_10_YEAR 0xc /* Bank 0 */ | |
37 | #define RTC7301_100_YEAR 0xd /* Bank 0 */ | |
38 | #define RTC7301_1000_YEAR 0xe /* Bank 0 */ | |
39 | #define RTC7301_ALARM_CONTROL 0xe /* Bank 1 */ | |
40 | #define RTC7301_ALARM_CONTROL_AIE BIT(0) | |
41 | #define RTC7301_ALARM_CONTROL_AF BIT(1) | |
42 | #define RTC7301_TIMER_CONTROL 0xe /* Bank 2 */ | |
43 | #define RTC7301_TIMER_CONTROL_TIE BIT(0) | |
44 | #define RTC7301_TIMER_CONTROL_TF BIT(1) | |
45 | #define RTC7301_CONTROL 0xf /* All banks */ | |
46 | #define RTC7301_CONTROL_BUSY BIT(0) | |
47 | #define RTC7301_CONTROL_STOP BIT(1) | |
48 | #define RTC7301_CONTROL_BANK_SEL_0 BIT(2) | |
49 | #define RTC7301_CONTROL_BANK_SEL_1 BIT(3) | |
50 | ||
51 | struct rtc7301_priv { | |
52 | struct regmap *regmap; | |
53 | int irq; | |
54 | spinlock_t lock; | |
55 | u8 bank; | |
56 | }; | |
57 | ||
58 | static const struct regmap_config rtc7301_regmap_config = { | |
59 | .reg_bits = 32, | |
60 | .val_bits = 8, | |
61 | .reg_stride = 4, | |
62 | }; | |
63 | ||
64 | static u8 rtc7301_read(struct rtc7301_priv *priv, unsigned int reg) | |
65 | { | |
66 | int reg_stride = regmap_get_reg_stride(priv->regmap); | |
67 | unsigned int val; | |
68 | ||
69 | regmap_read(priv->regmap, reg_stride * reg, &val); | |
70 | ||
71 | return val & 0xf; | |
72 | } | |
73 | ||
74 | static void rtc7301_write(struct rtc7301_priv *priv, u8 val, unsigned int reg) | |
75 | { | |
76 | int reg_stride = regmap_get_reg_stride(priv->regmap); | |
77 | ||
78 | regmap_write(priv->regmap, reg_stride * reg, val); | |
79 | } | |
80 | ||
81 | static void rtc7301_update_bits(struct rtc7301_priv *priv, unsigned int reg, | |
82 | u8 mask, u8 val) | |
83 | { | |
84 | int reg_stride = regmap_get_reg_stride(priv->regmap); | |
85 | ||
86 | regmap_update_bits(priv->regmap, reg_stride * reg, mask, val); | |
87 | } | |
88 | ||
89 | static int rtc7301_wait_while_busy(struct rtc7301_priv *priv) | |
90 | { | |
91 | int retries = 100; | |
92 | ||
93 | while (retries-- > 0) { | |
94 | u8 val; | |
95 | ||
96 | val = rtc7301_read(priv, RTC7301_CONTROL); | |
97 | if (!(val & RTC7301_CONTROL_BUSY)) | |
98 | return 0; | |
99 | ||
cd8c0bb2 | 100 | udelay(300); |
0b6a8f5c AM |
101 | } |
102 | ||
103 | return -ETIMEDOUT; | |
104 | } | |
105 | ||
106 | static void rtc7301_stop(struct rtc7301_priv *priv) | |
107 | { | |
108 | rtc7301_update_bits(priv, RTC7301_CONTROL, RTC7301_CONTROL_STOP, | |
109 | RTC7301_CONTROL_STOP); | |
110 | } | |
111 | ||
112 | static void rtc7301_start(struct rtc7301_priv *priv) | |
113 | { | |
114 | rtc7301_update_bits(priv, RTC7301_CONTROL, RTC7301_CONTROL_STOP, 0); | |
115 | } | |
116 | ||
117 | static void rtc7301_select_bank(struct rtc7301_priv *priv, u8 bank) | |
118 | { | |
119 | u8 val = 0; | |
120 | ||
121 | if (bank == priv->bank) | |
122 | return; | |
123 | ||
124 | if (bank & BIT(0)) | |
125 | val |= RTC7301_CONTROL_BANK_SEL_0; | |
126 | if (bank & BIT(1)) | |
127 | val |= RTC7301_CONTROL_BANK_SEL_1; | |
128 | ||
129 | rtc7301_update_bits(priv, RTC7301_CONTROL, | |
130 | RTC7301_CONTROL_BANK_SEL_0 | | |
131 | RTC7301_CONTROL_BANK_SEL_1, val); | |
132 | ||
133 | priv->bank = bank; | |
134 | } | |
135 | ||
136 | static void rtc7301_get_time(struct rtc7301_priv *priv, struct rtc_time *tm, | |
137 | bool alarm) | |
138 | { | |
139 | int year; | |
140 | ||
141 | tm->tm_sec = rtc7301_read(priv, RTC7301_1_SEC); | |
142 | tm->tm_sec += (rtc7301_read(priv, RTC7301_10_SEC) & ~RTC7301_AE) * 10; | |
143 | tm->tm_min = rtc7301_read(priv, RTC7301_1_MIN); | |
144 | tm->tm_min += (rtc7301_read(priv, RTC7301_10_MIN) & ~RTC7301_AE) * 10; | |
145 | tm->tm_hour = rtc7301_read(priv, RTC7301_1_HOUR); | |
146 | tm->tm_hour += (rtc7301_read(priv, RTC7301_10_HOUR) & ~RTC7301_AE) * 10; | |
147 | tm->tm_mday = rtc7301_read(priv, RTC7301_1_DAY); | |
148 | tm->tm_mday += (rtc7301_read(priv, RTC7301_10_DAY) & ~RTC7301_AE) * 10; | |
149 | ||
150 | if (alarm) { | |
151 | tm->tm_wday = -1; | |
152 | tm->tm_mon = -1; | |
153 | tm->tm_year = -1; | |
154 | tm->tm_yday = -1; | |
155 | tm->tm_isdst = -1; | |
156 | return; | |
157 | } | |
158 | ||
159 | tm->tm_wday = (rtc7301_read(priv, RTC7301_DAY_OF_WEEK) & ~RTC7301_AE); | |
160 | tm->tm_mon = rtc7301_read(priv, RTC7301_10_MONTH) * 10 + | |
161 | rtc7301_read(priv, RTC7301_1_MONTH) - 1; | |
162 | year = rtc7301_read(priv, RTC7301_1000_YEAR) * 1000 + | |
163 | rtc7301_read(priv, RTC7301_100_YEAR) * 100 + | |
164 | rtc7301_read(priv, RTC7301_10_YEAR) * 10 + | |
165 | rtc7301_read(priv, RTC7301_1_YEAR); | |
166 | ||
167 | tm->tm_year = year - 1900; | |
168 | } | |
169 | ||
170 | static void rtc7301_write_time(struct rtc7301_priv *priv, struct rtc_time *tm, | |
171 | bool alarm) | |
172 | { | |
173 | int year; | |
174 | ||
175 | rtc7301_write(priv, tm->tm_sec % 10, RTC7301_1_SEC); | |
176 | rtc7301_write(priv, tm->tm_sec / 10, RTC7301_10_SEC); | |
177 | ||
178 | rtc7301_write(priv, tm->tm_min % 10, RTC7301_1_MIN); | |
179 | rtc7301_write(priv, tm->tm_min / 10, RTC7301_10_MIN); | |
180 | ||
181 | rtc7301_write(priv, tm->tm_hour % 10, RTC7301_1_HOUR); | |
182 | rtc7301_write(priv, tm->tm_hour / 10, RTC7301_10_HOUR); | |
183 | ||
184 | rtc7301_write(priv, tm->tm_mday % 10, RTC7301_1_DAY); | |
185 | rtc7301_write(priv, tm->tm_mday / 10, RTC7301_10_DAY); | |
186 | ||
187 | /* Don't care for alarm register */ | |
188 | rtc7301_write(priv, alarm ? RTC7301_AE : tm->tm_wday, | |
189 | RTC7301_DAY_OF_WEEK); | |
190 | ||
191 | if (alarm) | |
192 | return; | |
193 | ||
194 | rtc7301_write(priv, (tm->tm_mon + 1) % 10, RTC7301_1_MONTH); | |
195 | rtc7301_write(priv, (tm->tm_mon + 1) / 10, RTC7301_10_MONTH); | |
196 | ||
197 | year = tm->tm_year + 1900; | |
198 | ||
199 | rtc7301_write(priv, year % 10, RTC7301_1_YEAR); | |
200 | rtc7301_write(priv, (year / 10) % 10, RTC7301_10_YEAR); | |
201 | rtc7301_write(priv, (year / 100) % 10, RTC7301_100_YEAR); | |
202 | rtc7301_write(priv, year / 1000, RTC7301_1000_YEAR); | |
203 | } | |
204 | ||
205 | static void rtc7301_alarm_irq(struct rtc7301_priv *priv, unsigned int enabled) | |
206 | { | |
207 | rtc7301_update_bits(priv, RTC7301_ALARM_CONTROL, | |
208 | RTC7301_ALARM_CONTROL_AF | | |
209 | RTC7301_ALARM_CONTROL_AIE, | |
210 | enabled ? RTC7301_ALARM_CONTROL_AIE : 0); | |
211 | } | |
212 | ||
213 | static int rtc7301_read_time(struct device *dev, struct rtc_time *tm) | |
214 | { | |
215 | struct rtc7301_priv *priv = dev_get_drvdata(dev); | |
216 | unsigned long flags; | |
217 | int err; | |
218 | ||
219 | spin_lock_irqsave(&priv->lock, flags); | |
220 | ||
221 | rtc7301_select_bank(priv, 0); | |
222 | ||
223 | err = rtc7301_wait_while_busy(priv); | |
224 | if (!err) | |
225 | rtc7301_get_time(priv, tm, false); | |
226 | ||
227 | spin_unlock_irqrestore(&priv->lock, flags); | |
228 | ||
50a9a35a | 229 | return err; |
0b6a8f5c AM |
230 | } |
231 | ||
232 | static int rtc7301_set_time(struct device *dev, struct rtc_time *tm) | |
233 | { | |
234 | struct rtc7301_priv *priv = dev_get_drvdata(dev); | |
235 | unsigned long flags; | |
236 | ||
237 | spin_lock_irqsave(&priv->lock, flags); | |
238 | ||
239 | rtc7301_stop(priv); | |
298c8545 | 240 | udelay(300); |
0b6a8f5c AM |
241 | rtc7301_select_bank(priv, 0); |
242 | rtc7301_write_time(priv, tm, false); | |
243 | rtc7301_start(priv); | |
244 | ||
245 | spin_unlock_irqrestore(&priv->lock, flags); | |
246 | ||
247 | return 0; | |
248 | } | |
249 | ||
250 | static int rtc7301_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) | |
251 | { | |
252 | struct rtc7301_priv *priv = dev_get_drvdata(dev); | |
253 | unsigned long flags; | |
254 | u8 alrm_ctrl; | |
255 | ||
256 | if (priv->irq <= 0) | |
257 | return -EINVAL; | |
258 | ||
259 | spin_lock_irqsave(&priv->lock, flags); | |
260 | ||
261 | rtc7301_select_bank(priv, 1); | |
262 | rtc7301_get_time(priv, &alarm->time, true); | |
263 | ||
264 | alrm_ctrl = rtc7301_read(priv, RTC7301_ALARM_CONTROL); | |
265 | ||
266 | alarm->enabled = !!(alrm_ctrl & RTC7301_ALARM_CONTROL_AIE); | |
267 | alarm->pending = !!(alrm_ctrl & RTC7301_ALARM_CONTROL_AF); | |
268 | ||
269 | spin_unlock_irqrestore(&priv->lock, flags); | |
270 | ||
271 | return 0; | |
272 | } | |
273 | ||
274 | static int rtc7301_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) | |
275 | { | |
276 | struct rtc7301_priv *priv = dev_get_drvdata(dev); | |
277 | unsigned long flags; | |
278 | ||
279 | if (priv->irq <= 0) | |
280 | return -EINVAL; | |
281 | ||
282 | spin_lock_irqsave(&priv->lock, flags); | |
283 | ||
284 | rtc7301_select_bank(priv, 1); | |
285 | rtc7301_write_time(priv, &alarm->time, true); | |
286 | rtc7301_alarm_irq(priv, alarm->enabled); | |
287 | ||
288 | spin_unlock_irqrestore(&priv->lock, flags); | |
289 | ||
290 | return 0; | |
291 | } | |
292 | ||
293 | static int rtc7301_alarm_irq_enable(struct device *dev, unsigned int enabled) | |
294 | { | |
295 | struct rtc7301_priv *priv = dev_get_drvdata(dev); | |
296 | unsigned long flags; | |
297 | ||
298 | if (priv->irq <= 0) | |
299 | return -EINVAL; | |
300 | ||
301 | spin_lock_irqsave(&priv->lock, flags); | |
302 | ||
303 | rtc7301_select_bank(priv, 1); | |
304 | rtc7301_alarm_irq(priv, enabled); | |
305 | ||
306 | spin_unlock_irqrestore(&priv->lock, flags); | |
307 | ||
308 | return 0; | |
309 | } | |
310 | ||
311 | static const struct rtc_class_ops rtc7301_rtc_ops = { | |
312 | .read_time = rtc7301_read_time, | |
313 | .set_time = rtc7301_set_time, | |
314 | .read_alarm = rtc7301_read_alarm, | |
315 | .set_alarm = rtc7301_set_alarm, | |
316 | .alarm_irq_enable = rtc7301_alarm_irq_enable, | |
317 | }; | |
318 | ||
319 | static irqreturn_t rtc7301_irq_handler(int irq, void *dev_id) | |
320 | { | |
321 | struct rtc_device *rtc = dev_id; | |
322 | struct rtc7301_priv *priv = dev_get_drvdata(rtc->dev.parent); | |
323 | unsigned long flags; | |
324 | irqreturn_t ret = IRQ_NONE; | |
325 | u8 alrm_ctrl; | |
326 | ||
327 | spin_lock_irqsave(&priv->lock, flags); | |
328 | ||
329 | rtc7301_select_bank(priv, 1); | |
330 | ||
331 | alrm_ctrl = rtc7301_read(priv, RTC7301_ALARM_CONTROL); | |
332 | if (alrm_ctrl & RTC7301_ALARM_CONTROL_AF) { | |
333 | ret = IRQ_HANDLED; | |
334 | rtc7301_alarm_irq(priv, false); | |
335 | rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF); | |
336 | } | |
337 | ||
338 | spin_unlock_irqrestore(&priv->lock, flags); | |
339 | ||
340 | return ret; | |
341 | } | |
342 | ||
343 | static void rtc7301_init(struct rtc7301_priv *priv) | |
344 | { | |
345 | unsigned long flags; | |
346 | ||
347 | spin_lock_irqsave(&priv->lock, flags); | |
348 | ||
349 | rtc7301_select_bank(priv, 2); | |
350 | rtc7301_write(priv, 0, RTC7301_TIMER_CONTROL); | |
351 | ||
352 | spin_unlock_irqrestore(&priv->lock, flags); | |
353 | } | |
354 | ||
355 | static int __init rtc7301_rtc_probe(struct platform_device *dev) | |
356 | { | |
0b6a8f5c AM |
357 | void __iomem *regs; |
358 | struct rtc7301_priv *priv; | |
359 | struct rtc_device *rtc; | |
360 | int ret; | |
361 | ||
0b6a8f5c AM |
362 | priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL); |
363 | if (!priv) | |
364 | return -ENOMEM; | |
365 | ||
89576beb | 366 | regs = devm_platform_ioremap_resource(dev, 0); |
0b6a8f5c AM |
367 | if (IS_ERR(regs)) |
368 | return PTR_ERR(regs); | |
369 | ||
370 | priv->regmap = devm_regmap_init_mmio(&dev->dev, regs, | |
371 | &rtc7301_regmap_config); | |
372 | if (IS_ERR(priv->regmap)) | |
373 | return PTR_ERR(priv->regmap); | |
374 | ||
375 | priv->irq = platform_get_irq(dev, 0); | |
376 | ||
377 | spin_lock_init(&priv->lock); | |
378 | priv->bank = -1; | |
379 | ||
380 | rtc7301_init(priv); | |
381 | ||
382 | platform_set_drvdata(dev, priv); | |
383 | ||
384 | rtc = devm_rtc_device_register(&dev->dev, DRV_NAME, &rtc7301_rtc_ops, | |
385 | THIS_MODULE); | |
386 | if (IS_ERR(rtc)) | |
387 | return PTR_ERR(rtc); | |
388 | ||
389 | if (priv->irq > 0) { | |
390 | ret = devm_request_irq(&dev->dev, priv->irq, | |
391 | rtc7301_irq_handler, IRQF_SHARED, | |
392 | dev_name(&dev->dev), rtc); | |
393 | if (ret) { | |
394 | priv->irq = 0; | |
395 | dev_err(&dev->dev, "unable to request IRQ\n"); | |
396 | } else { | |
397 | device_set_wakeup_capable(&dev->dev, true); | |
398 | } | |
399 | } | |
400 | ||
401 | return 0; | |
402 | } | |
403 | ||
404 | #ifdef CONFIG_PM_SLEEP | |
405 | ||
406 | static int rtc7301_suspend(struct device *dev) | |
407 | { | |
408 | struct rtc7301_priv *priv = dev_get_drvdata(dev); | |
409 | ||
410 | if (device_may_wakeup(dev)) | |
411 | enable_irq_wake(priv->irq); | |
412 | ||
413 | return 0; | |
414 | } | |
415 | ||
416 | static int rtc7301_resume(struct device *dev) | |
417 | { | |
418 | struct rtc7301_priv *priv = dev_get_drvdata(dev); | |
419 | ||
420 | if (device_may_wakeup(dev)) | |
421 | disable_irq_wake(priv->irq); | |
422 | ||
423 | return 0; | |
424 | } | |
425 | ||
426 | #endif | |
427 | ||
428 | static SIMPLE_DEV_PM_OPS(rtc7301_pm_ops, rtc7301_suspend, rtc7301_resume); | |
429 | ||
430 | static const struct of_device_id rtc7301_dt_match[] = { | |
431 | { .compatible = "epson,rtc7301sf" }, | |
432 | { .compatible = "epson,rtc7301dg" }, | |
433 | {} | |
434 | }; | |
435 | MODULE_DEVICE_TABLE(of, rtc7301_dt_match); | |
436 | ||
437 | static struct platform_driver rtc7301_rtc_driver = { | |
438 | .driver = { | |
439 | .name = DRV_NAME, | |
440 | .of_match_table = rtc7301_dt_match, | |
441 | .pm = &rtc7301_pm_ops, | |
442 | }, | |
443 | }; | |
444 | ||
445 | module_platform_driver_probe(rtc7301_rtc_driver, rtc7301_rtc_probe); | |
446 | ||
447 | MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>"); | |
448 | MODULE_LICENSE("GPL"); | |
449 | MODULE_DESCRIPTION("EPSON TOYOCOM RTC-7301SF/DG Driver"); | |
450 | MODULE_ALIAS("platform:rtc-r7301"); |