1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* rtc-ds1343.c |
3 | * |
4 | * Driver for Dallas Semiconductor DS1343 Low Current, SPI Compatible |
5 | * Real Time Clock |
6 | * |
7 | * Author : Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com> |
8 | * Ankur Srivastava <sankurece@gmail.com> : DS1343 Nvram Support |
9 | */ |
10 | |
11 | #include <linux/init.h> |
12 | #include <linux/module.h> |
13 | #include <linux/interrupt.h> |
14 | #include <linux/device.h> |
15 | #include <linux/spi/spi.h> |
16 | #include <linux/regmap.h> |
17 | #include <linux/rtc.h> |
18 | #include <linux/bcd.h> |
19 | #include <linux/pm.h> |
20 | #include <linux/pm_wakeirq.h> |
21 | #include <linux/slab.h> |
22 | |
23 | #define DALLAS_MAXIM_DS1343 0 |
24 | #define DALLAS_MAXIM_DS1344 1 |
25 | |
26 | /* RTC DS1343 Registers */ |
27 | #define DS1343_SECONDS_REG 0x00 |
28 | #define DS1343_MINUTES_REG 0x01 |
29 | #define DS1343_HOURS_REG 0x02 |
30 | #define DS1343_DAY_REG 0x03 |
31 | #define DS1343_DATE_REG 0x04 |
32 | #define DS1343_MONTH_REG 0x05 |
33 | #define DS1343_YEAR_REG 0x06 |
34 | #define DS1343_ALM0_SEC_REG 0x07 |
35 | #define DS1343_ALM0_MIN_REG 0x08 |
36 | #define DS1343_ALM0_HOUR_REG 0x09 |
37 | #define DS1343_ALM0_DAY_REG 0x0A |
38 | #define DS1343_ALM1_SEC_REG 0x0B |
39 | #define DS1343_ALM1_MIN_REG 0x0C |
40 | #define DS1343_ALM1_HOUR_REG 0x0D |
41 | #define DS1343_ALM1_DAY_REG 0x0E |
42 | #define DS1343_CONTROL_REG 0x0F |
43 | #define DS1343_STATUS_REG 0x10 |
44 | #define DS1343_TRICKLE_REG 0x11 |
45 | #define DS1343_NVRAM 0x20 |
46 | |
47 | #define DS1343_NVRAM_LEN 96 |
48 | |
49 | /* DS1343 Control Registers bits */ |
50 | #define DS1343_EOSC 0x80 |
51 | #define DS1343_DOSF 0x20 |
52 | #define DS1343_EGFIL 0x10 |
53 | #define DS1343_SQW 0x08 |
54 | #define DS1343_INTCN 0x04 |
55 | #define DS1343_A1IE 0x02 |
56 | #define DS1343_A0IE 0x01 |
57 | |
58 | /* DS1343 Status Registers bits */ |
59 | #define DS1343_OSF 0x80 |
60 | #define DS1343_IRQF1 0x02 |
61 | #define DS1343_IRQF0 0x01 |
62 | |
63 | /* DS1343 Trickle Charger Registers bits */ |
64 | #define DS1343_TRICKLE_MAGIC 0xa0 |
65 | #define DS1343_TRICKLE_DS1 0x08 |
66 | #define DS1343_TRICKLE_1K 0x01 |
67 | #define DS1343_TRICKLE_2K 0x02 |
68 | #define DS1343_TRICKLE_4K 0x03 |
69 | |
70 | static const struct spi_device_id ds1343_id[] = { |
71 | { "ds1343" , DALLAS_MAXIM_DS1343 }, |
72 | { "ds1344" , DALLAS_MAXIM_DS1344 }, |
73 | { } |
74 | }; |
75 | MODULE_DEVICE_TABLE(spi, ds1343_id); |
76 | |
77 | struct ds1343_priv { |
78 | struct rtc_device *rtc; |
79 | struct regmap *map; |
80 | int irq; |
81 | }; |
82 | |
83 | static ssize_t ds1343_show_glitchfilter(struct device *dev, |
84 | struct device_attribute *attr, char *buf) |
85 | { |
86 | struct ds1343_priv *priv = dev_get_drvdata(dev: dev->parent); |
87 | int glitch_filt_status, data; |
88 | int res; |
89 | |
90 | res = regmap_read(map: priv->map, DS1343_CONTROL_REG, val: &data); |
91 | if (res) |
92 | return res; |
93 | |
94 | glitch_filt_status = !!(data & DS1343_EGFIL); |
95 | |
96 | if (glitch_filt_status) |
97 | return sprintf(buf, fmt: "enabled\n" ); |
98 | else |
99 | return sprintf(buf, fmt: "disabled\n" ); |
100 | } |
101 | |
102 | static ssize_t ds1343_store_glitchfilter(struct device *dev, |
103 | struct device_attribute *attr, |
104 | const char *buf, size_t count) |
105 | { |
106 | struct ds1343_priv *priv = dev_get_drvdata(dev: dev->parent); |
107 | int data = 0; |
108 | int res; |
109 | |
110 | if (strncmp(buf, "enabled" , 7) == 0) |
111 | data = DS1343_EGFIL; |
112 | else if (strncmp(buf, "disabled" , 8)) |
113 | return -EINVAL; |
114 | |
115 | res = regmap_update_bits(map: priv->map, DS1343_CONTROL_REG, |
116 | DS1343_EGFIL, val: data); |
117 | if (res) |
118 | return res; |
119 | |
120 | return count; |
121 | } |
122 | |
123 | static DEVICE_ATTR(glitch_filter, S_IRUGO | S_IWUSR, ds1343_show_glitchfilter, |
124 | ds1343_store_glitchfilter); |
125 | |
126 | static int ds1343_nvram_write(void *priv, unsigned int off, void *val, |
127 | size_t bytes) |
128 | { |
129 | struct ds1343_priv *ds1343 = priv; |
130 | |
131 | return regmap_bulk_write(map: ds1343->map, DS1343_NVRAM + off, val, val_count: bytes); |
132 | } |
133 | |
134 | static int ds1343_nvram_read(void *priv, unsigned int off, void *val, |
135 | size_t bytes) |
136 | { |
137 | struct ds1343_priv *ds1343 = priv; |
138 | |
139 | return regmap_bulk_read(map: ds1343->map, DS1343_NVRAM + off, val, val_count: bytes); |
140 | } |
141 | |
142 | static ssize_t ds1343_show_tricklecharger(struct device *dev, |
143 | struct device_attribute *attr, char *buf) |
144 | { |
145 | struct ds1343_priv *priv = dev_get_drvdata(dev: dev->parent); |
146 | int res, data; |
147 | char *diodes = "disabled" , *resistors = " " ; |
148 | |
149 | res = regmap_read(map: priv->map, DS1343_TRICKLE_REG, val: &data); |
150 | if (res) |
151 | return res; |
152 | |
153 | if ((data & 0xf0) == DS1343_TRICKLE_MAGIC) { |
154 | switch (data & 0x0c) { |
155 | case DS1343_TRICKLE_DS1: |
156 | diodes = "one diode," ; |
157 | break; |
158 | |
159 | default: |
160 | diodes = "no diode," ; |
161 | break; |
162 | } |
163 | |
164 | switch (data & 0x03) { |
165 | case DS1343_TRICKLE_1K: |
166 | resistors = "1k Ohm" ; |
167 | break; |
168 | |
169 | case DS1343_TRICKLE_2K: |
170 | resistors = "2k Ohm" ; |
171 | break; |
172 | |
173 | case DS1343_TRICKLE_4K: |
174 | resistors = "4k Ohm" ; |
175 | break; |
176 | |
177 | default: |
178 | diodes = "disabled" ; |
179 | break; |
180 | } |
181 | } |
182 | |
183 | return sprintf(buf, fmt: "%s %s\n" , diodes, resistors); |
184 | } |
185 | |
186 | static DEVICE_ATTR(trickle_charger, S_IRUGO, ds1343_show_tricklecharger, NULL); |
187 | |
188 | static struct attribute *ds1343_attrs[] = { |
189 | &dev_attr_glitch_filter.attr, |
190 | &dev_attr_trickle_charger.attr, |
191 | NULL |
192 | }; |
193 | |
194 | static const struct attribute_group ds1343_attr_group = { |
195 | .attrs = ds1343_attrs, |
196 | }; |
197 | |
198 | static int ds1343_read_time(struct device *dev, struct rtc_time *dt) |
199 | { |
200 | struct ds1343_priv *priv = dev_get_drvdata(dev); |
201 | unsigned char buf[7]; |
202 | int res; |
203 | |
204 | res = regmap_bulk_read(map: priv->map, DS1343_SECONDS_REG, val: buf, val_count: 7); |
205 | if (res) |
206 | return res; |
207 | |
208 | dt->tm_sec = bcd2bin(buf[0]); |
209 | dt->tm_min = bcd2bin(buf[1]); |
210 | dt->tm_hour = bcd2bin(buf[2] & 0x3F); |
211 | dt->tm_wday = bcd2bin(buf[3]) - 1; |
212 | dt->tm_mday = bcd2bin(buf[4]); |
213 | dt->tm_mon = bcd2bin(buf[5] & 0x1F) - 1; |
214 | dt->tm_year = bcd2bin(buf[6]) + 100; /* year offset from 1900 */ |
215 | |
216 | return 0; |
217 | } |
218 | |
219 | static int ds1343_set_time(struct device *dev, struct rtc_time *dt) |
220 | { |
221 | struct ds1343_priv *priv = dev_get_drvdata(dev); |
222 | u8 buf[7]; |
223 | |
224 | buf[0] = bin2bcd(dt->tm_sec); |
225 | buf[1] = bin2bcd(dt->tm_min); |
226 | buf[2] = bin2bcd(dt->tm_hour) & 0x3F; |
227 | buf[3] = bin2bcd(dt->tm_wday + 1); |
228 | buf[4] = bin2bcd(dt->tm_mday); |
229 | buf[5] = bin2bcd(dt->tm_mon + 1); |
230 | buf[6] = bin2bcd(dt->tm_year - 100); |
231 | |
232 | return regmap_bulk_write(map: priv->map, DS1343_SECONDS_REG, |
233 | val: buf, val_count: sizeof(buf)); |
234 | } |
235 | |
236 | static int ds1343_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) |
237 | { |
238 | struct ds1343_priv *priv = dev_get_drvdata(dev); |
239 | unsigned char buf[4]; |
240 | unsigned int val; |
241 | int res; |
242 | |
243 | if (priv->irq <= 0) |
244 | return -EINVAL; |
245 | |
246 | res = regmap_read(map: priv->map, DS1343_STATUS_REG, val: &val); |
247 | if (res) |
248 | return res; |
249 | |
250 | alarm->pending = !!(val & DS1343_IRQF0); |
251 | |
252 | res = regmap_read(map: priv->map, DS1343_CONTROL_REG, val: &val); |
253 | if (res) |
254 | return res; |
255 | alarm->enabled = !!(val & DS1343_A0IE); |
256 | |
257 | res = regmap_bulk_read(map: priv->map, DS1343_ALM0_SEC_REG, val: buf, val_count: 4); |
258 | if (res) |
259 | return res; |
260 | |
261 | alarm->time.tm_sec = bcd2bin(buf[0]) & 0x7f; |
262 | alarm->time.tm_min = bcd2bin(buf[1]) & 0x7f; |
263 | alarm->time.tm_hour = bcd2bin(buf[2]) & 0x3f; |
264 | alarm->time.tm_mday = bcd2bin(buf[3]) & 0x3f; |
265 | |
266 | return 0; |
267 | } |
268 | |
269 | static int ds1343_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) |
270 | { |
271 | struct ds1343_priv *priv = dev_get_drvdata(dev); |
272 | unsigned char buf[4]; |
273 | int res = 0; |
274 | |
275 | if (priv->irq <= 0) |
276 | return -EINVAL; |
277 | |
278 | res = regmap_update_bits(map: priv->map, DS1343_CONTROL_REG, DS1343_A0IE, val: 0); |
279 | if (res) |
280 | return res; |
281 | |
282 | buf[0] = bin2bcd(alarm->time.tm_sec); |
283 | buf[1] = bin2bcd(alarm->time.tm_min); |
284 | buf[2] = bin2bcd(alarm->time.tm_hour); |
285 | buf[3] = bin2bcd(alarm->time.tm_mday); |
286 | |
287 | res = regmap_bulk_write(map: priv->map, DS1343_ALM0_SEC_REG, val: buf, val_count: 4); |
288 | if (res) |
289 | return res; |
290 | |
291 | if (alarm->enabled) |
292 | res = regmap_update_bits(map: priv->map, DS1343_CONTROL_REG, |
293 | DS1343_A0IE, DS1343_A0IE); |
294 | |
295 | return res; |
296 | } |
297 | |
298 | static int ds1343_alarm_irq_enable(struct device *dev, unsigned int enabled) |
299 | { |
300 | struct ds1343_priv *priv = dev_get_drvdata(dev); |
301 | |
302 | if (priv->irq <= 0) |
303 | return -EINVAL; |
304 | |
305 | return regmap_update_bits(map: priv->map, DS1343_CONTROL_REG, |
306 | DS1343_A0IE, val: enabled ? DS1343_A0IE : 0); |
307 | } |
308 | |
309 | static irqreturn_t ds1343_thread(int irq, void *dev_id) |
310 | { |
311 | struct ds1343_priv *priv = dev_id; |
312 | unsigned int stat; |
313 | int res = 0; |
314 | |
315 | rtc_lock(priv->rtc); |
316 | |
317 | res = regmap_read(map: priv->map, DS1343_STATUS_REG, val: &stat); |
318 | if (res) |
319 | goto out; |
320 | |
321 | if (stat & DS1343_IRQF0) { |
322 | stat &= ~DS1343_IRQF0; |
323 | regmap_write(map: priv->map, DS1343_STATUS_REG, val: stat); |
324 | |
325 | rtc_update_irq(rtc: priv->rtc, num: 1, RTC_AF | RTC_IRQF); |
326 | |
327 | regmap_update_bits(map: priv->map, DS1343_CONTROL_REG, |
328 | DS1343_A0IE, val: 0); |
329 | } |
330 | |
331 | out: |
332 | rtc_unlock(priv->rtc); |
333 | return IRQ_HANDLED; |
334 | } |
335 | |
336 | static const struct rtc_class_ops ds1343_rtc_ops = { |
337 | .read_time = ds1343_read_time, |
338 | .set_time = ds1343_set_time, |
339 | .read_alarm = ds1343_read_alarm, |
340 | .set_alarm = ds1343_set_alarm, |
341 | .alarm_irq_enable = ds1343_alarm_irq_enable, |
342 | }; |
343 | |
344 | static int ds1343_probe(struct spi_device *spi) |
345 | { |
346 | struct ds1343_priv *priv; |
347 | struct regmap_config config = { .reg_bits = 8, .val_bits = 8, |
348 | .write_flag_mask = 0x80, }; |
349 | unsigned int data; |
350 | int res; |
351 | struct nvmem_config nvmem_cfg = { |
352 | .name = "ds1343-" , |
353 | .word_size = 1, |
354 | .stride = 1, |
355 | .size = DS1343_NVRAM_LEN, |
356 | .reg_read = ds1343_nvram_read, |
357 | .reg_write = ds1343_nvram_write, |
358 | }; |
359 | |
360 | priv = devm_kzalloc(dev: &spi->dev, size: sizeof(struct ds1343_priv), GFP_KERNEL); |
361 | if (!priv) |
362 | return -ENOMEM; |
363 | |
364 | /* RTC DS1347 works in spi mode 3 and |
365 | * its chip select is active high. Active high should be defined as |
366 | * "inverse polarity" as GPIO-based chip selects can be logically |
367 | * active high but inverted by the GPIO library. |
368 | */ |
369 | spi->mode |= SPI_MODE_3; |
370 | spi->mode ^= SPI_CS_HIGH; |
371 | spi->bits_per_word = 8; |
372 | res = spi_setup(spi); |
373 | if (res) |
374 | return res; |
375 | |
376 | spi_set_drvdata(spi, data: priv); |
377 | |
378 | priv->map = devm_regmap_init_spi(spi, &config); |
379 | |
380 | if (IS_ERR(ptr: priv->map)) { |
381 | dev_err(&spi->dev, "spi regmap init failed for rtc ds1343\n" ); |
382 | return PTR_ERR(ptr: priv->map); |
383 | } |
384 | |
385 | res = regmap_read(map: priv->map, DS1343_SECONDS_REG, val: &data); |
386 | if (res) |
387 | return res; |
388 | |
389 | regmap_read(map: priv->map, DS1343_CONTROL_REG, val: &data); |
390 | data |= DS1343_INTCN; |
391 | data &= ~(DS1343_EOSC | DS1343_A1IE | DS1343_A0IE); |
392 | regmap_write(map: priv->map, DS1343_CONTROL_REG, val: data); |
393 | |
394 | regmap_read(map: priv->map, DS1343_STATUS_REG, val: &data); |
395 | data &= ~(DS1343_OSF | DS1343_IRQF1 | DS1343_IRQF0); |
396 | regmap_write(map: priv->map, DS1343_STATUS_REG, val: data); |
397 | |
398 | priv->rtc = devm_rtc_allocate_device(dev: &spi->dev); |
399 | if (IS_ERR(ptr: priv->rtc)) |
400 | return PTR_ERR(ptr: priv->rtc); |
401 | |
402 | priv->rtc->ops = &ds1343_rtc_ops; |
403 | priv->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; |
404 | priv->rtc->range_max = RTC_TIMESTAMP_END_2099; |
405 | |
406 | res = rtc_add_group(rtc: priv->rtc, grp: &ds1343_attr_group); |
407 | if (res) |
408 | dev_err(&spi->dev, |
409 | "unable to create sysfs entries for rtc ds1343\n" ); |
410 | |
411 | res = devm_rtc_register_device(priv->rtc); |
412 | if (res) |
413 | return res; |
414 | |
415 | nvmem_cfg.priv = priv; |
416 | devm_rtc_nvmem_register(rtc: priv->rtc, nvmem_config: &nvmem_cfg); |
417 | |
418 | priv->irq = spi->irq; |
419 | |
420 | if (priv->irq >= 0) { |
421 | res = devm_request_threaded_irq(dev: &spi->dev, irq: spi->irq, NULL, |
422 | thread_fn: ds1343_thread, IRQF_ONESHOT, |
423 | devname: "ds1343" , dev_id: priv); |
424 | if (res) { |
425 | priv->irq = -1; |
426 | dev_err(&spi->dev, |
427 | "unable to request irq for rtc ds1343\n" ); |
428 | } else { |
429 | device_init_wakeup(dev: &spi->dev, enable: true); |
430 | dev_pm_set_wake_irq(dev: &spi->dev, irq: spi->irq); |
431 | } |
432 | } |
433 | |
434 | return 0; |
435 | } |
436 | |
437 | static void ds1343_remove(struct spi_device *spi) |
438 | { |
439 | dev_pm_clear_wake_irq(dev: &spi->dev); |
440 | } |
441 | |
442 | #ifdef CONFIG_PM_SLEEP |
443 | |
444 | static int ds1343_suspend(struct device *dev) |
445 | { |
446 | struct spi_device *spi = to_spi_device(dev); |
447 | |
448 | if (spi->irq >= 0 && device_may_wakeup(dev)) |
449 | enable_irq_wake(irq: spi->irq); |
450 | |
451 | return 0; |
452 | } |
453 | |
454 | static int ds1343_resume(struct device *dev) |
455 | { |
456 | struct spi_device *spi = to_spi_device(dev); |
457 | |
458 | if (spi->irq >= 0 && device_may_wakeup(dev)) |
459 | disable_irq_wake(irq: spi->irq); |
460 | |
461 | return 0; |
462 | } |
463 | |
464 | #endif |
465 | |
466 | static SIMPLE_DEV_PM_OPS(ds1343_pm, ds1343_suspend, ds1343_resume); |
467 | |
468 | static struct spi_driver ds1343_driver = { |
469 | .driver = { |
470 | .name = "ds1343" , |
471 | .pm = &ds1343_pm, |
472 | }, |
473 | .probe = ds1343_probe, |
474 | .remove = ds1343_remove, |
475 | .id_table = ds1343_id, |
476 | }; |
477 | |
478 | module_spi_driver(ds1343_driver); |
479 | |
480 | MODULE_DESCRIPTION("DS1343 RTC SPI Driver" ); |
481 | MODULE_AUTHOR("Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com>," |
482 | "Ankur Srivastava <sankurece@gmail.com>" ); |
483 | MODULE_LICENSE("GPL v2" ); |
484 | |