1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * drivers/rtc/rtc-pcf85363.c |
4 | * |
5 | * Driver for NXP PCF85363 real-time clock. |
6 | * |
7 | * Copyright (C) 2017 Eric Nelson |
8 | */ |
9 | #include <linux/module.h> |
10 | #include <linux/i2c.h> |
11 | #include <linux/slab.h> |
12 | #include <linux/rtc.h> |
13 | #include <linux/init.h> |
14 | #include <linux/err.h> |
15 | #include <linux/errno.h> |
16 | #include <linux/bcd.h> |
17 | #include <linux/of.h> |
18 | #include <linux/regmap.h> |
19 | |
20 | /* |
21 | * Date/Time registers |
22 | */ |
23 | #define DT_100THS 0x00 |
24 | #define DT_SECS 0x01 |
25 | #define DT_MINUTES 0x02 |
26 | #define DT_HOURS 0x03 |
27 | #define DT_DAYS 0x04 |
28 | #define DT_WEEKDAYS 0x05 |
29 | #define DT_MONTHS 0x06 |
30 | #define DT_YEARS 0x07 |
31 | |
32 | /* |
33 | * Alarm registers |
34 | */ |
35 | #define DT_SECOND_ALM1 0x08 |
36 | #define DT_MINUTE_ALM1 0x09 |
37 | #define DT_HOUR_ALM1 0x0a |
38 | #define DT_DAY_ALM1 0x0b |
39 | #define DT_MONTH_ALM1 0x0c |
40 | #define DT_MINUTE_ALM2 0x0d |
41 | #define DT_HOUR_ALM2 0x0e |
42 | #define DT_WEEKDAY_ALM2 0x0f |
43 | #define DT_ALARM_EN 0x10 |
44 | |
45 | /* |
46 | * Time stamp registers |
47 | */ |
48 | #define DT_TIMESTAMP1 0x11 |
49 | #define DT_TIMESTAMP2 0x17 |
50 | #define DT_TIMESTAMP3 0x1d |
51 | #define DT_TS_MODE 0x23 |
52 | |
53 | /* |
54 | * control registers |
55 | */ |
56 | #define CTRL_OFFSET 0x24 |
57 | #define CTRL_OSCILLATOR 0x25 |
58 | #define CTRL_BATTERY 0x26 |
59 | #define CTRL_PIN_IO 0x27 |
60 | #define CTRL_FUNCTION 0x28 |
61 | #define CTRL_INTA_EN 0x29 |
62 | #define CTRL_INTB_EN 0x2a |
63 | #define CTRL_FLAGS 0x2b |
64 | #define CTRL_RAMBYTE 0x2c |
65 | #define CTRL_WDOG 0x2d |
66 | #define CTRL_STOP_EN 0x2e |
67 | #define CTRL_RESETS 0x2f |
68 | #define CTRL_RAM 0x40 |
69 | |
70 | #define ALRM_SEC_A1E BIT(0) |
71 | #define ALRM_MIN_A1E BIT(1) |
72 | #define ALRM_HR_A1E BIT(2) |
73 | #define ALRM_DAY_A1E BIT(3) |
74 | #define ALRM_MON_A1E BIT(4) |
75 | #define ALRM_MIN_A2E BIT(5) |
76 | #define ALRM_HR_A2E BIT(6) |
77 | #define ALRM_DAY_A2E BIT(7) |
78 | |
79 | #define INT_WDIE BIT(0) |
80 | #define INT_BSIE BIT(1) |
81 | #define INT_TSRIE BIT(2) |
82 | #define INT_A2IE BIT(3) |
83 | #define INT_A1IE BIT(4) |
84 | #define INT_OIE BIT(5) |
85 | #define INT_PIE BIT(6) |
86 | #define INT_ILP BIT(7) |
87 | |
88 | #define FLAGS_TSR1F BIT(0) |
89 | #define FLAGS_TSR2F BIT(1) |
90 | #define FLAGS_TSR3F BIT(2) |
91 | #define FLAGS_BSF BIT(3) |
92 | #define FLAGS_WDF BIT(4) |
93 | #define FLAGS_A1F BIT(5) |
94 | #define FLAGS_A2F BIT(6) |
95 | #define FLAGS_PIF BIT(7) |
96 | |
97 | #define PIN_IO_INTAPM GENMASK(1, 0) |
98 | #define PIN_IO_INTA_CLK 0 |
99 | #define PIN_IO_INTA_BAT 1 |
100 | #define PIN_IO_INTA_OUT 2 |
101 | #define PIN_IO_INTA_HIZ 3 |
102 | |
103 | #define OSC_CAP_SEL GENMASK(1, 0) |
104 | #define OSC_CAP_6000 0x01 |
105 | #define OSC_CAP_12500 0x02 |
106 | |
107 | #define STOP_EN_STOP BIT(0) |
108 | |
109 | #define RESET_CPR 0xa4 |
110 | |
111 | #define NVRAM_SIZE 0x40 |
112 | |
113 | struct pcf85363 { |
114 | struct rtc_device *rtc; |
115 | struct regmap *regmap; |
116 | }; |
117 | |
118 | struct pcf85x63_config { |
119 | struct regmap_config regmap; |
120 | unsigned int num_nvram; |
121 | }; |
122 | |
123 | static int pcf85363_load_capacitance(struct pcf85363 *pcf85363, struct device_node *node) |
124 | { |
125 | u32 load = 7000; |
126 | u8 value = 0; |
127 | |
128 | of_property_read_u32(np: node, propname: "quartz-load-femtofarads" , out_value: &load); |
129 | |
130 | switch (load) { |
131 | default: |
132 | dev_warn(&pcf85363->rtc->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 7000" , |
133 | load); |
134 | fallthrough; |
135 | case 7000: |
136 | break; |
137 | case 6000: |
138 | value = OSC_CAP_6000; |
139 | break; |
140 | case 12500: |
141 | value = OSC_CAP_12500; |
142 | break; |
143 | } |
144 | |
145 | return regmap_update_bits(map: pcf85363->regmap, CTRL_OSCILLATOR, |
146 | OSC_CAP_SEL, val: value); |
147 | } |
148 | |
149 | static int pcf85363_rtc_read_time(struct device *dev, struct rtc_time *tm) |
150 | { |
151 | struct pcf85363 *pcf85363 = dev_get_drvdata(dev); |
152 | unsigned char buf[DT_YEARS + 1]; |
153 | int ret, len = sizeof(buf); |
154 | |
155 | /* read the RTC date and time registers all at once */ |
156 | ret = regmap_bulk_read(map: pcf85363->regmap, DT_100THS, val: buf, val_count: len); |
157 | if (ret) { |
158 | dev_err(dev, "%s: error %d\n" , __func__, ret); |
159 | return ret; |
160 | } |
161 | |
162 | tm->tm_year = bcd2bin(buf[DT_YEARS]); |
163 | /* adjust for 1900 base of rtc_time */ |
164 | tm->tm_year += 100; |
165 | |
166 | tm->tm_wday = buf[DT_WEEKDAYS] & 7; |
167 | buf[DT_SECS] &= 0x7F; |
168 | tm->tm_sec = bcd2bin(buf[DT_SECS]); |
169 | buf[DT_MINUTES] &= 0x7F; |
170 | tm->tm_min = bcd2bin(buf[DT_MINUTES]); |
171 | tm->tm_hour = bcd2bin(buf[DT_HOURS]); |
172 | tm->tm_mday = bcd2bin(buf[DT_DAYS]); |
173 | tm->tm_mon = bcd2bin(buf[DT_MONTHS]) - 1; |
174 | |
175 | return 0; |
176 | } |
177 | |
178 | static int pcf85363_rtc_set_time(struct device *dev, struct rtc_time *tm) |
179 | { |
180 | struct pcf85363 *pcf85363 = dev_get_drvdata(dev); |
181 | unsigned char tmp[11]; |
182 | unsigned char *buf = &tmp[2]; |
183 | int ret; |
184 | |
185 | tmp[0] = STOP_EN_STOP; |
186 | tmp[1] = RESET_CPR; |
187 | |
188 | buf[DT_100THS] = 0; |
189 | buf[DT_SECS] = bin2bcd(tm->tm_sec); |
190 | buf[DT_MINUTES] = bin2bcd(tm->tm_min); |
191 | buf[DT_HOURS] = bin2bcd(tm->tm_hour); |
192 | buf[DT_DAYS] = bin2bcd(tm->tm_mday); |
193 | buf[DT_WEEKDAYS] = tm->tm_wday; |
194 | buf[DT_MONTHS] = bin2bcd(tm->tm_mon + 1); |
195 | buf[DT_YEARS] = bin2bcd(tm->tm_year % 100); |
196 | |
197 | ret = regmap_bulk_write(map: pcf85363->regmap, CTRL_STOP_EN, |
198 | val: tmp, val_count: 2); |
199 | if (ret) |
200 | return ret; |
201 | |
202 | ret = regmap_bulk_write(map: pcf85363->regmap, DT_100THS, |
203 | val: buf, val_count: sizeof(tmp) - 2); |
204 | if (ret) |
205 | return ret; |
206 | |
207 | return regmap_write(map: pcf85363->regmap, CTRL_STOP_EN, val: 0); |
208 | } |
209 | |
210 | static int pcf85363_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
211 | { |
212 | struct pcf85363 *pcf85363 = dev_get_drvdata(dev); |
213 | unsigned char buf[DT_MONTH_ALM1 - DT_SECOND_ALM1 + 1]; |
214 | unsigned int val; |
215 | int ret; |
216 | |
217 | ret = regmap_bulk_read(map: pcf85363->regmap, DT_SECOND_ALM1, val: buf, |
218 | val_count: sizeof(buf)); |
219 | if (ret) |
220 | return ret; |
221 | |
222 | alrm->time.tm_sec = bcd2bin(buf[0]); |
223 | alrm->time.tm_min = bcd2bin(buf[1]); |
224 | alrm->time.tm_hour = bcd2bin(buf[2]); |
225 | alrm->time.tm_mday = bcd2bin(buf[3]); |
226 | alrm->time.tm_mon = bcd2bin(buf[4]) - 1; |
227 | |
228 | ret = regmap_read(map: pcf85363->regmap, CTRL_INTA_EN, val: &val); |
229 | if (ret) |
230 | return ret; |
231 | |
232 | alrm->enabled = !!(val & INT_A1IE); |
233 | |
234 | return 0; |
235 | } |
236 | |
237 | static int _pcf85363_rtc_alarm_irq_enable(struct pcf85363 *pcf85363, unsigned |
238 | int enabled) |
239 | { |
240 | unsigned int alarm_flags = ALRM_SEC_A1E | ALRM_MIN_A1E | ALRM_HR_A1E | |
241 | ALRM_DAY_A1E | ALRM_MON_A1E; |
242 | int ret; |
243 | |
244 | ret = regmap_update_bits(map: pcf85363->regmap, DT_ALARM_EN, mask: alarm_flags, |
245 | val: enabled ? alarm_flags : 0); |
246 | if (ret) |
247 | return ret; |
248 | |
249 | ret = regmap_update_bits(map: pcf85363->regmap, CTRL_INTA_EN, |
250 | INT_A1IE, val: enabled ? INT_A1IE : 0); |
251 | |
252 | if (ret || enabled) |
253 | return ret; |
254 | |
255 | /* clear current flags */ |
256 | return regmap_update_bits(map: pcf85363->regmap, CTRL_FLAGS, FLAGS_A1F, val: 0); |
257 | } |
258 | |
259 | static int pcf85363_rtc_alarm_irq_enable(struct device *dev, |
260 | unsigned int enabled) |
261 | { |
262 | struct pcf85363 *pcf85363 = dev_get_drvdata(dev); |
263 | |
264 | return _pcf85363_rtc_alarm_irq_enable(pcf85363, enabled); |
265 | } |
266 | |
267 | static int pcf85363_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
268 | { |
269 | struct pcf85363 *pcf85363 = dev_get_drvdata(dev); |
270 | unsigned char buf[DT_MONTH_ALM1 - DT_SECOND_ALM1 + 1]; |
271 | int ret; |
272 | |
273 | buf[0] = bin2bcd(alrm->time.tm_sec); |
274 | buf[1] = bin2bcd(alrm->time.tm_min); |
275 | buf[2] = bin2bcd(alrm->time.tm_hour); |
276 | buf[3] = bin2bcd(alrm->time.tm_mday); |
277 | buf[4] = bin2bcd(alrm->time.tm_mon + 1); |
278 | |
279 | /* |
280 | * Disable the alarm interrupt before changing the value to avoid |
281 | * spurious interrupts |
282 | */ |
283 | ret = _pcf85363_rtc_alarm_irq_enable(pcf85363, enabled: 0); |
284 | if (ret) |
285 | return ret; |
286 | |
287 | ret = regmap_bulk_write(map: pcf85363->regmap, DT_SECOND_ALM1, val: buf, |
288 | val_count: sizeof(buf)); |
289 | if (ret) |
290 | return ret; |
291 | |
292 | return _pcf85363_rtc_alarm_irq_enable(pcf85363, enabled: alrm->enabled); |
293 | } |
294 | |
295 | static irqreturn_t pcf85363_rtc_handle_irq(int irq, void *dev_id) |
296 | { |
297 | struct pcf85363 *pcf85363 = i2c_get_clientdata(client: dev_id); |
298 | unsigned int flags; |
299 | int err; |
300 | |
301 | err = regmap_read(map: pcf85363->regmap, CTRL_FLAGS, val: &flags); |
302 | if (err) |
303 | return IRQ_NONE; |
304 | |
305 | if (flags & FLAGS_A1F) { |
306 | rtc_update_irq(rtc: pcf85363->rtc, num: 1, RTC_IRQF | RTC_AF); |
307 | regmap_update_bits(map: pcf85363->regmap, CTRL_FLAGS, FLAGS_A1F, val: 0); |
308 | return IRQ_HANDLED; |
309 | } |
310 | |
311 | return IRQ_NONE; |
312 | } |
313 | |
314 | static const struct rtc_class_ops rtc_ops = { |
315 | .read_time = pcf85363_rtc_read_time, |
316 | .set_time = pcf85363_rtc_set_time, |
317 | .read_alarm = pcf85363_rtc_read_alarm, |
318 | .set_alarm = pcf85363_rtc_set_alarm, |
319 | .alarm_irq_enable = pcf85363_rtc_alarm_irq_enable, |
320 | }; |
321 | |
322 | static int pcf85363_nvram_read(void *priv, unsigned int offset, void *val, |
323 | size_t bytes) |
324 | { |
325 | struct pcf85363 *pcf85363 = priv; |
326 | |
327 | return regmap_bulk_read(map: pcf85363->regmap, CTRL_RAM + offset, |
328 | val, val_count: bytes); |
329 | } |
330 | |
331 | static int pcf85363_nvram_write(void *priv, unsigned int offset, void *val, |
332 | size_t bytes) |
333 | { |
334 | struct pcf85363 *pcf85363 = priv; |
335 | |
336 | return regmap_bulk_write(map: pcf85363->regmap, CTRL_RAM + offset, |
337 | val, val_count: bytes); |
338 | } |
339 | |
340 | static int pcf85x63_nvram_read(void *priv, unsigned int offset, void *val, |
341 | size_t bytes) |
342 | { |
343 | struct pcf85363 *pcf85363 = priv; |
344 | unsigned int tmp_val; |
345 | int ret; |
346 | |
347 | ret = regmap_read(map: pcf85363->regmap, CTRL_RAMBYTE, val: &tmp_val); |
348 | (*(unsigned char *) val) = (unsigned char) tmp_val; |
349 | |
350 | return ret; |
351 | } |
352 | |
353 | static int pcf85x63_nvram_write(void *priv, unsigned int offset, void *val, |
354 | size_t bytes) |
355 | { |
356 | struct pcf85363 *pcf85363 = priv; |
357 | unsigned char tmp_val; |
358 | |
359 | tmp_val = *((unsigned char *)val); |
360 | return regmap_write(map: pcf85363->regmap, CTRL_RAMBYTE, |
361 | val: (unsigned int)tmp_val); |
362 | } |
363 | |
364 | static const struct pcf85x63_config pcf_85263_config = { |
365 | .regmap = { |
366 | .reg_bits = 8, |
367 | .val_bits = 8, |
368 | .max_register = 0x2f, |
369 | }, |
370 | .num_nvram = 1 |
371 | }; |
372 | |
373 | static const struct pcf85x63_config pcf_85363_config = { |
374 | .regmap = { |
375 | .reg_bits = 8, |
376 | .val_bits = 8, |
377 | .max_register = 0x7f, |
378 | }, |
379 | .num_nvram = 2 |
380 | }; |
381 | |
382 | static int pcf85363_probe(struct i2c_client *client) |
383 | { |
384 | struct pcf85363 *pcf85363; |
385 | const struct pcf85x63_config *config = &pcf_85363_config; |
386 | const void *data = of_device_get_match_data(dev: &client->dev); |
387 | static struct nvmem_config nvmem_cfg[] = { |
388 | { |
389 | .name = "pcf85x63-" , |
390 | .word_size = 1, |
391 | .stride = 1, |
392 | .size = 1, |
393 | .reg_read = pcf85x63_nvram_read, |
394 | .reg_write = pcf85x63_nvram_write, |
395 | }, { |
396 | .name = "pcf85363-" , |
397 | .word_size = 1, |
398 | .stride = 1, |
399 | .size = NVRAM_SIZE, |
400 | .reg_read = pcf85363_nvram_read, |
401 | .reg_write = pcf85363_nvram_write, |
402 | }, |
403 | }; |
404 | int ret, i, err; |
405 | bool wakeup_source; |
406 | |
407 | if (data) |
408 | config = data; |
409 | |
410 | pcf85363 = devm_kzalloc(dev: &client->dev, size: sizeof(struct pcf85363), |
411 | GFP_KERNEL); |
412 | if (!pcf85363) |
413 | return -ENOMEM; |
414 | |
415 | pcf85363->regmap = devm_regmap_init_i2c(client, &config->regmap); |
416 | if (IS_ERR(ptr: pcf85363->regmap)) { |
417 | dev_err(&client->dev, "regmap allocation failed\n" ); |
418 | return PTR_ERR(ptr: pcf85363->regmap); |
419 | } |
420 | |
421 | i2c_set_clientdata(client, data: pcf85363); |
422 | |
423 | pcf85363->rtc = devm_rtc_allocate_device(dev: &client->dev); |
424 | if (IS_ERR(ptr: pcf85363->rtc)) |
425 | return PTR_ERR(ptr: pcf85363->rtc); |
426 | |
427 | err = pcf85363_load_capacitance(pcf85363, node: client->dev.of_node); |
428 | if (err < 0) |
429 | dev_warn(&client->dev, "failed to set xtal load capacitance: %d" , |
430 | err); |
431 | |
432 | pcf85363->rtc->ops = &rtc_ops; |
433 | pcf85363->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; |
434 | pcf85363->rtc->range_max = RTC_TIMESTAMP_END_2099; |
435 | |
436 | wakeup_source = device_property_read_bool(dev: &client->dev, |
437 | propname: "wakeup-source" ); |
438 | if (client->irq > 0 || wakeup_source) { |
439 | regmap_write(map: pcf85363->regmap, CTRL_FLAGS, val: 0); |
440 | regmap_update_bits(map: pcf85363->regmap, CTRL_PIN_IO, |
441 | PIN_IO_INTAPM, PIN_IO_INTA_OUT); |
442 | } |
443 | |
444 | if (client->irq > 0) { |
445 | unsigned long irqflags = IRQF_TRIGGER_LOW; |
446 | |
447 | if (dev_fwnode(&client->dev)) |
448 | irqflags = 0; |
449 | ret = devm_request_threaded_irq(dev: &client->dev, irq: client->irq, |
450 | NULL, thread_fn: pcf85363_rtc_handle_irq, |
451 | irqflags: irqflags | IRQF_ONESHOT, |
452 | devname: "pcf85363" , dev_id: client); |
453 | if (ret) { |
454 | dev_warn(&client->dev, |
455 | "unable to request IRQ, alarms disabled\n" ); |
456 | client->irq = 0; |
457 | } |
458 | } |
459 | |
460 | if (client->irq > 0 || wakeup_source) { |
461 | device_init_wakeup(dev: &client->dev, enable: true); |
462 | set_bit(RTC_FEATURE_ALARM, addr: pcf85363->rtc->features); |
463 | } else { |
464 | clear_bit(RTC_FEATURE_ALARM, addr: pcf85363->rtc->features); |
465 | } |
466 | |
467 | ret = devm_rtc_register_device(pcf85363->rtc); |
468 | |
469 | for (i = 0; i < config->num_nvram; i++) { |
470 | nvmem_cfg[i].priv = pcf85363; |
471 | devm_rtc_nvmem_register(rtc: pcf85363->rtc, nvmem_config: &nvmem_cfg[i]); |
472 | } |
473 | |
474 | return ret; |
475 | } |
476 | |
477 | static const __maybe_unused struct of_device_id dev_ids[] = { |
478 | { .compatible = "nxp,pcf85263" , .data = &pcf_85263_config }, |
479 | { .compatible = "nxp,pcf85363" , .data = &pcf_85363_config }, |
480 | { /* sentinel */ } |
481 | }; |
482 | MODULE_DEVICE_TABLE(of, dev_ids); |
483 | |
484 | static struct i2c_driver pcf85363_driver = { |
485 | .driver = { |
486 | .name = "pcf85363" , |
487 | .of_match_table = of_match_ptr(dev_ids), |
488 | }, |
489 | .probe = pcf85363_probe, |
490 | }; |
491 | |
492 | module_i2c_driver(pcf85363_driver); |
493 | |
494 | MODULE_AUTHOR("Eric Nelson" ); |
495 | MODULE_DESCRIPTION("pcf85263/pcf85363 I2C RTC driver" ); |
496 | MODULE_LICENSE("GPL" ); |
497 | |