1 /*
2 * Copyright (c) 2019-2023 Henrik Brix Andersen <henrik@brixandersen.dk>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT nxp_pcf8523
8
9 #include <zephyr/drivers/gpio.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/drivers/rtc.h>
12 #include <zephyr/logging/log.h>
13 #include <zephyr/pm/device.h>
14 #include <zephyr/sys/util.h>
15
16 LOG_MODULE_REGISTER(pcf8523, CONFIG_RTC_LOG_LEVEL);
17
18 /* PCF8523 register addresses */
19 #define PCF8523_CONTROL_1 0x00U
20 #define PCF8523_CONTROL_2 0x01U
21 #define PCF8523_CONTROL_3 0x02U
22 #define PCF8523_SECONDS 0x03U
23 #define PCF8523_MINUTES 0x04U
24 #define PCF8523_HOURS 0x05U
25 #define PCF8523_DAYS 0x06U
26 #define PCF8523_WEEKDAYS 0x07U
27 #define PCF8523_MONTHS 0x08U
28 #define PCF8523_YEARS 0x09U
29 #define PCF8523_MINUTE_ALARM 0x0aU
30 #define PCF8523_HOUR_ALARM 0x0bU
31 #define PCF8523_DAY_ALARM 0x0cU
32 #define PCF8523_WEEKDAY_ALARM 0x0dU
33 #define PCF8523_OFFSET 0x0eU
34 #define PCF8523_TMR_CLKOUT_CTRL 0x0fU
35 #define PCF8523_TMR_A_FREQ_CTRL 0x10U
36 #define PCF8523_TMR_A_REG 0x11U
37 #define PCF8523_TMR_B_FREQ_CTRL 0x12U
38 #define PCF8523_TMR_B_REG 0x13U
39
40 /* Control register bits */
41 #define PCF8523_CONTROL_1_CAP_SEL BIT(7)
42 #define PCF8523_CONTROL_1_T BIT(6)
43 #define PCF8523_CONTROL_1_STOP BIT(5)
44 #define PCF8523_CONTROL_1_SR BIT(4)
45 #define PCF8523_CONTROL_1_12_24 BIT(3)
46 #define PCF8523_CONTROL_1_SIE BIT(2)
47 #define PCF8523_CONTROL_1_AIE BIT(1)
48 #define PCF8523_CONTROL_1_CIE BIT(0)
49 #define PCF8523_CONTROL_2_WTAF BIT(7)
50 #define PCF8523_CONTROL_2_CTAF BIT(6)
51 #define PCF8523_CONTROL_2_CTBF BIT(5)
52 #define PCF8523_CONTROL_2_SF BIT(4)
53 #define PCF8523_CONTROL_2_AF BIT(3)
54 #define PCF8523_CONTROL_2_WTAIE BIT(2)
55 #define PCF8523_CONTROL_2_CTAIE BIT(1)
56 #define PCF8523_CONTROL_2_CTBIE BIT(0)
57 #define PCF8523_CONTROL_3_PM_MASK GENMASK(7, 5)
58 #define PCF8523_CONTROL_3_BSF BIT(3)
59 #define PCF8523_CONTROL_3_BLF BIT(2)
60 #define PCF8523_CONTROL_3_BSIE BIT(1)
61 #define PCF8523_CONTROL_3_BLIE BIT(0)
62
63 /* Time and date register bits */
64 #define PCF8523_SECONDS_OS BIT(7)
65 #define PCF8523_SECONDS_MASK GENMASK(6, 0)
66 #define PCF8523_MINUTES_MASK GENMASK(6, 0)
67 #define PCF8523_HOURS_AMPM BIT(5)
68 #define PCF8523_HOURS_12H_MASK GENMASK(4, 0)
69 #define PCF8523_HOURS_24H_MASK GENMASK(5, 0)
70 #define PCF8523_DAYS_MASK GENMASK(5, 0)
71 #define PCF8523_WEEKDAYS_MASK GENMASK(2, 0)
72 #define PCF8523_MONTHS_MASK GENMASK(4, 0)
73 #define PCF8523_YEARS_MASK GENMASK(7, 0)
74
75 /* Alarm register bits */
76 #define PCF8523_MINUTE_ALARM_AEN_M BIT(7)
77 #define PCF8523_MINUTE_ALARM_MASK GENMASK(6, 0)
78 #define PCF8523_HOUR_ALARM_AEN_H BIT(7)
79 #define PCF8523_HOUR_ALARM_AMPM BIT(5)
80 #define PCF8523_HOUR_ALARM_12H_MASK GENMASK(4, 0)
81 #define PCF8523_HOUR_ALARM_24H_MASK GENMASK(5, 0)
82 #define PCF8523_DAY_ALARM_AEN_D BIT(7)
83 #define PCF8523_DAY_ALARM_MASK GENMASK(5, 0)
84 #define PCF8523_WEEKDAY_ALARM_AEN_W BIT(7)
85 #define PCF8523_WEEKDAY_ALARM_MASK GENMASK(5, 0)
86
87 /* Timer register bits */
88 #define PCF8523_TMR_CLKOUT_CTRL_TAM BIT(7)
89 #define PCF8523_TMR_CLKOUT_CTRL_TBM BIT(6)
90 #define PCF8523_TMR_CLKOUT_CTRL_COF_MASK GENMASK(5, 3)
91 #define PCF8523_TMR_CLKOUT_CTRL_TAC_MASK GENMASK(2, 1)
92 #define PCF8523_TMR_CLKOUT_CTRL_TBC BIT(0)
93 #define PCF8523_TMR_A_FREQ_CTRL_TAQ_MASK GENMASK(2, 0)
94 #define PCF8523_TMR_A_REG_T_A_MASK GENMASK(7, 0)
95 #define PCF8523_TMR_B_FREQ_CTRL_TBW_MASK GENMASK(6, 4)
96 #define PCF8523_TMR_B_FREQ_CTRL_TBQ_MASK GENMASK(2, 0)
97 #define PCF8523_TMR_B_REG_T_B_MASK GENMASK(7, 0)
98
99 /* Offset register bits */
100 #define PCF8523_OFFSET_MODE BIT(7)
101 #define PCF8523_OFFSET_MASK GENMASK(6, 0)
102
103 /* RTC alarm time fields supported by the PCF8523 */
104 #define PCF8523_RTC_ALARM_TIME_MASK \
105 (RTC_ALARM_TIME_MASK_MINUTE | RTC_ALARM_TIME_MASK_HOUR | RTC_ALARM_TIME_MASK_MONTHDAY | \
106 RTC_ALARM_TIME_MASK_WEEKDAY)
107
108 /* The PCF8523 only supports two-digit years, calculate offset to use */
109 #define PCF8523_YEARS_OFFSET (2000 - 1900)
110
111 /* The PCF8523 enumerates months 1 to 12, RTC API uses 0 to 11 */
112 #define PCF8523_MONTHS_OFFSET 1
113
114 /* Helper macro to guard int1-gpios related code */
115 #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(int1_gpios) && \
116 (defined(CONFIG_RTC_ALARM) || defined(CONFIG_RTC_UPDATE))
117 #define PCF8523_INT1_GPIOS_IN_USE 1
118 #endif
119
120 struct pcf8523_config {
121 const struct i2c_dt_spec i2c;
122 #ifdef PCF8523_INT1_GPIOS_IN_USE
123 struct gpio_dt_spec int1;
124 #endif /* PCF8523_INT1_GPIOS_IN_USE */
125 uint8_t cof;
126 uint8_t pm;
127 bool cap_sel;
128 bool wakeup_source;
129 };
130
131 struct pcf8523_data {
132 struct k_mutex lock;
133 #if PCF8523_INT1_GPIOS_IN_USE
134 struct gpio_callback int1_callback;
135 struct k_thread int1_thread;
136 struct k_sem int1_sem;
137
138 K_KERNEL_STACK_MEMBER(int1_stack, CONFIG_RTC_PCF8523_THREAD_STACK_SIZE);
139 #ifdef CONFIG_RTC_ALARM
140 rtc_alarm_callback alarm_callback;
141 void *alarm_user_data;
142 #endif /* CONFIG_RTC_ALARM */
143 #ifdef CONFIG_RTC_UPDATE
144 rtc_update_callback update_callback;
145 void *update_user_data;
146 #endif /* CONFIG_RTC_UPDATE */
147 #endif /* PCF8523_INT1_GPIOS_IN_USE */
148 };
149
pcf8523_read_regs(const struct device * dev,uint8_t addr,void * buf,size_t len)150 static int pcf8523_read_regs(const struct device *dev, uint8_t addr, void *buf, size_t len)
151 {
152 const struct pcf8523_config *config = dev->config;
153 int err;
154
155 err = i2c_write_read_dt(&config->i2c, &addr, sizeof(addr), buf, len);
156 if (err != 0) {
157 LOG_ERR("failed to read reg addr 0x%02x, len %d (err %d)", addr, len, err);
158 return err;
159 }
160
161 return 0;
162 }
163
pcf8523_read_reg8(const struct device * dev,uint8_t addr,uint8_t * val)164 static int pcf8523_read_reg8(const struct device *dev, uint8_t addr, uint8_t *val)
165 {
166 return pcf8523_read_regs(dev, addr, val, sizeof(*val));
167 }
168
pcf8523_write_regs(const struct device * dev,uint8_t addr,void * buf,size_t len)169 static int pcf8523_write_regs(const struct device *dev, uint8_t addr, void *buf, size_t len)
170 {
171 const struct pcf8523_config *config = dev->config;
172 uint8_t block[sizeof(addr) + len];
173 int err;
174
175 block[0] = addr;
176 memcpy(&block[1], buf, len);
177
178 err = i2c_write_dt(&config->i2c, block, sizeof(block));
179 if (err != 0) {
180 LOG_ERR("failed to write reg addr 0x%02x, len %d (err %d)", addr, len, err);
181 return err;
182 }
183
184 return 0;
185 }
186
pcf8523_write_reg8(const struct device * dev,uint8_t addr,uint8_t val)187 static int pcf8523_write_reg8(const struct device *dev, uint8_t addr, uint8_t val)
188 {
189 return pcf8523_write_regs(dev, addr, &val, sizeof(val));
190 }
191
pcf8523_write_stop_bit_unlocked(const struct device * dev,bool value)192 static int pcf8523_write_stop_bit_unlocked(const struct device *dev, bool value)
193 {
194 uint8_t control_1;
195 int err;
196
197 err = pcf8523_read_reg8(dev, PCF8523_CONTROL_1, &control_1);
198 if (err != 0) {
199 return err;
200 }
201
202 if (value) {
203 control_1 |= PCF8523_CONTROL_1_STOP;
204 } else {
205 control_1 &= ~(PCF8523_CONTROL_1_STOP);
206 }
207
208 err = pcf8523_write_reg8(dev, PCF8523_CONTROL_1, control_1);
209 if (err != 0) {
210 return err;
211 }
212
213 return 0;
214 }
215
216 #if PCF8523_INT1_GPIOS_IN_USE
pcf8523_int1_enable_unlocked(const struct device * dev,bool enable)217 static int pcf8523_int1_enable_unlocked(const struct device *dev, bool enable)
218 {
219 const struct pcf8523_config *config = dev->config;
220 uint8_t tmr_clkout_ctrl;
221 int err;
222
223 if (!config->wakeup_source) {
224 /* Only change COF if not configured as wakeup-source */
225 err = pcf8523_read_reg8(dev, PCF8523_TMR_CLKOUT_CTRL, &tmr_clkout_ctrl);
226 if (err != 0) {
227 return err;
228 }
229
230 if (enable) {
231 /* Disable CLKOUT */
232 tmr_clkout_ctrl |= PCF8523_TMR_CLKOUT_CTRL_COF_MASK;
233 } else if (!config->wakeup_source) {
234 /* Enable CLKOUT */
235 tmr_clkout_ctrl &= ~(PCF8523_TMR_CLKOUT_CTRL_COF_MASK);
236 tmr_clkout_ctrl |=
237 FIELD_PREP(PCF8523_TMR_CLKOUT_CTRL_COF_MASK, config->cof);
238 }
239
240 err = pcf8523_write_reg8(dev, PCF8523_TMR_CLKOUT_CTRL, tmr_clkout_ctrl);
241 if (err != 0) {
242 return err;
243 }
244 }
245
246 /* Use edge interrupts to avoid multiple GPIO IRQs while servicing the IRQ in the thread */
247 err = gpio_pin_interrupt_configure_dt(&config->int1,
248 enable ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE);
249 if (err != 0) {
250 LOG_ERR("failed to %s GPIO IRQ (err %d)", enable ? "enable" : "disable", err);
251 return err;
252 }
253
254 return 0;
255 }
256
pcf8523_int1_thread(void * p1,void * p2,void * p3)257 static void pcf8523_int1_thread(void *p1, void *p2, void *p3)
258 {
259 ARG_UNUSED(p2);
260 ARG_UNUSED(p3);
261
262 const struct device *dev = p1;
263 struct pcf8523_data *data = dev->data;
264 rtc_alarm_callback alarm_callback = NULL;
265 void *alarm_user_data = NULL;
266 rtc_update_callback update_callback = NULL;
267 void *update_user_data = NULL;
268 uint8_t control_2;
269 int err;
270
271 while (true) {
272 k_sem_take(&data->int1_sem, K_FOREVER);
273 k_mutex_lock(&data->lock, K_FOREVER);
274
275 err = pcf8523_read_reg8(dev, PCF8523_CONTROL_2, &control_2);
276 if (err != 0) {
277 goto unlock;
278 }
279
280 #ifdef CONFIG_RTC_ALARM
281 if ((control_2 & PCF8523_CONTROL_2_AF) != 0 && data->alarm_callback != NULL) {
282 control_2 &= ~(PCF8523_CONTROL_2_AF);
283 alarm_callback = data->alarm_callback;
284 alarm_user_data = data->alarm_user_data;
285 }
286 #endif /* CONFIG_RTC_ALARM */
287
288 #ifdef CONFIG_RTC_UPDATE
289 if ((control_2 & PCF8523_CONTROL_2_SF) != 0) {
290 control_2 &= ~(PCF8523_CONTROL_2_SF);
291 update_callback = data->update_callback;
292 update_user_data = data->update_user_data;
293 }
294 #endif /* CONFIG_RTC_UPDATE */
295
296 control_2 |= PCF8523_CONTROL_2_CTAF | PCF8523_CONTROL_2_CTBF;
297
298 err = pcf8523_write_reg8(dev, PCF8523_CONTROL_2, control_2);
299 if (err != 0) {
300 goto unlock;
301 }
302
303 /* Check if interrupt occurred between CONTROL_2 read/write */
304 err = pcf8523_read_reg8(dev, PCF8523_CONTROL_2, &control_2);
305 if (err != 0) {
306 goto unlock;
307 }
308
309 if (((control_2 & PCF8523_CONTROL_2_AF) != 0U && alarm_callback != NULL) ||
310 ((control_2 & PCF8523_CONTROL_2_SF) != 0U)) {
311 /*
312 * Another interrupt occurred while servicing this one, process current
313 * callback(s) and yield.
314 */
315 k_sem_give(&data->int1_sem);
316 }
317
318 unlock:
319 k_mutex_unlock(&data->lock);
320
321 if (alarm_callback != NULL) {
322 alarm_callback(dev, 0U, alarm_user_data);
323 alarm_callback = NULL;
324 }
325
326 if (update_callback != NULL) {
327 update_callback(dev, update_user_data);
328 update_callback = NULL;
329 }
330 }
331 }
332
pcf8523_int1_callback_handler(const struct device * port,struct gpio_callback * cb,gpio_port_pins_t pins)333 static void pcf8523_int1_callback_handler(const struct device *port, struct gpio_callback *cb,
334 gpio_port_pins_t pins)
335 {
336 struct pcf8523_data *data = CONTAINER_OF(cb, struct pcf8523_data, int1_callback);
337
338 ARG_UNUSED(port);
339 ARG_UNUSED(pins);
340
341 k_sem_give(&data->int1_sem);
342 }
343 #endif /* PCF8523_INT1_GPIOS_IN_USE */
344
pcf8523_set_time(const struct device * dev,const struct rtc_time * timeptr)345 static int pcf8523_set_time(const struct device *dev, const struct rtc_time *timeptr)
346 {
347 struct pcf8523_data *data = dev->data;
348 uint8_t regs[7];
349 int err;
350
351 if (timeptr->tm_year < PCF8523_YEARS_OFFSET ||
352 timeptr->tm_year > PCF8523_YEARS_OFFSET + 99) {
353 return -EINVAL;
354 }
355
356 k_mutex_lock(&data->lock, K_FOREVER);
357
358 /* Freeze the time circuits */
359 err = pcf8523_write_stop_bit_unlocked(dev, true);
360 if (err != 0) {
361 goto unlock;
362 }
363
364 LOG_DBG("set time: year = %d, mon = %d, mday = %d, wday = %d, hour = %d, "
365 "min = %d, sec = %d",
366 timeptr->tm_year, timeptr->tm_mon, timeptr->tm_mday, timeptr->tm_wday,
367 timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec);
368
369 regs[0] = bin2bcd(timeptr->tm_sec) & PCF8523_SECONDS_MASK;
370 regs[1] = bin2bcd(timeptr->tm_min) & PCF8523_MINUTES_MASK;
371 regs[2] = bin2bcd(timeptr->tm_hour) & PCF8523_HOURS_24H_MASK;
372 regs[3] = bin2bcd(timeptr->tm_mday) & PCF8523_DAYS_MASK;
373 regs[4] = bin2bcd(timeptr->tm_wday) & PCF8523_WEEKDAYS_MASK;
374 regs[5] = bin2bcd(timeptr->tm_mon + PCF8523_MONTHS_OFFSET) & PCF8523_MONTHS_MASK;
375 regs[6] = bin2bcd(timeptr->tm_year - PCF8523_YEARS_OFFSET) & PCF8523_YEARS_MASK;
376
377 /* Write registers PCF8523_SECONDS through PCF8523_YEARS */
378 err = pcf8523_write_regs(dev, PCF8523_SECONDS, ®s, sizeof(regs));
379 if (err != 0) {
380 goto unlock;
381 }
382
383 /* Unfreeze time circuits */
384 err = pcf8523_write_stop_bit_unlocked(dev, false);
385 if (err != 0) {
386 goto unlock;
387 }
388
389 unlock:
390 k_mutex_unlock(&data->lock);
391
392 return err;
393 }
394
pcf8523_get_time(const struct device * dev,struct rtc_time * timeptr)395 static int pcf8523_get_time(const struct device *dev, struct rtc_time *timeptr)
396 {
397 uint8_t regs[10];
398 int err;
399
400 /* Read registers PCF8523_CONTROL_1 through PCF8523_YEARS */
401 err = pcf8523_read_regs(dev, PCF8523_CONTROL_1, ®s, sizeof(regs));
402 if (err != 0) {
403 return err;
404 }
405
406 if ((regs[0] & PCF8523_CONTROL_1_STOP) != 0) {
407 LOG_WRN("time circuits frozen");
408 return -ENODATA;
409 }
410
411 if ((regs[3] & PCF8523_SECONDS_OS) != 0) {
412 LOG_WRN("oscillator stopped or interrupted");
413 return -ENODATA;
414 }
415
416 memset(timeptr, 0U, sizeof(*timeptr));
417 timeptr->tm_sec = bcd2bin(regs[3] & PCF8523_SECONDS_MASK);
418 timeptr->tm_min = bcd2bin(regs[4] & PCF8523_MINUTES_MASK);
419 timeptr->tm_hour = bcd2bin(regs[5] & PCF8523_HOURS_24H_MASK);
420 timeptr->tm_mday = bcd2bin(regs[6] & PCF8523_DAYS_MASK);
421 timeptr->tm_wday = bcd2bin(regs[7] & PCF8523_WEEKDAYS_MASK);
422 timeptr->tm_mon = bcd2bin(regs[8] & PCF8523_MONTHS_MASK) - PCF8523_MONTHS_OFFSET;
423 timeptr->tm_year = bcd2bin(regs[9] & PCF8523_YEARS_MASK) + PCF8523_YEARS_OFFSET;
424 timeptr->tm_yday = -1;
425 timeptr->tm_isdst = -1;
426
427 LOG_DBG("get time: year = %d, mon = %d, mday = %d, wday = %d, hour = %d, "
428 "min = %d, sec = %d",
429 timeptr->tm_year, timeptr->tm_mon, timeptr->tm_mday, timeptr->tm_wday,
430 timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec);
431
432 return 0;
433 }
434
435 #ifdef CONFIG_RTC_ALARM
pcf8523_alarm_get_supported_fields(const struct device * dev,uint16_t id,uint16_t * mask)436 static int pcf8523_alarm_get_supported_fields(const struct device *dev, uint16_t id, uint16_t *mask)
437 {
438 ARG_UNUSED(dev);
439
440 if (id != 0U) {
441 LOG_ERR("invalid ID %d", id);
442 return -EINVAL;
443 }
444
445 *mask = PCF8523_RTC_ALARM_TIME_MASK;
446
447 return 0;
448 }
449
pcf8523_alarm_set_time(const struct device * dev,uint16_t id,uint16_t mask,const struct rtc_time * timeptr)450 static int pcf8523_alarm_set_time(const struct device *dev, uint16_t id, uint16_t mask,
451 const struct rtc_time *timeptr)
452 {
453 uint8_t regs[4];
454
455 if (id != 0U) {
456 LOG_ERR("invalid ID %d", id);
457 return -EINVAL;
458 }
459
460 if ((mask & ~(PCF8523_RTC_ALARM_TIME_MASK)) != 0U) {
461 LOG_ERR("unsupported alarm field mask 0x%04x", mask);
462 return -EINVAL;
463 }
464
465 if ((mask & RTC_ALARM_TIME_MASK_MINUTE) != 0U) {
466 regs[0] = bin2bcd(timeptr->tm_min) & PCF8523_MINUTE_ALARM_MASK;
467 } else {
468 regs[0] = PCF8523_MINUTE_ALARM_AEN_M;
469 }
470
471 if ((mask & RTC_ALARM_TIME_MASK_HOUR) != 0U) {
472 regs[1] = bin2bcd(timeptr->tm_hour) & PCF8523_HOUR_ALARM_24H_MASK;
473 } else {
474 regs[1] = PCF8523_HOUR_ALARM_AEN_H;
475 }
476
477 if ((mask & RTC_ALARM_TIME_MASK_MONTHDAY) != 0U) {
478 regs[2] = bin2bcd(timeptr->tm_mday) & PCF8523_DAY_ALARM_MASK;
479 } else {
480 regs[2] = PCF8523_DAY_ALARM_AEN_D;
481 }
482
483 if ((mask & RTC_ALARM_TIME_MASK_WEEKDAY) != 0U) {
484 regs[3] = bin2bcd(timeptr->tm_wday) & PCF8523_WEEKDAY_ALARM_MASK;
485 } else {
486 regs[3] = PCF8523_WEEKDAY_ALARM_AEN_W;
487 }
488
489 LOG_DBG("set alarm: year = %d, mon = %d, mday = %d, hour = %d, min = %d, mask = 0x%04x",
490 timeptr->tm_year, timeptr->tm_mon, timeptr->tm_mday, timeptr->tm_hour,
491 timeptr->tm_min, mask);
492
493 /* Write registers PCF8523_MINUTE_ALARM through PCF8523_WEEKDAY_ALARM */
494 return pcf8523_write_regs(dev, PCF8523_MINUTE_ALARM, ®s, sizeof(regs));
495 }
496
pcf8523_alarm_get_time(const struct device * dev,uint16_t id,uint16_t * mask,struct rtc_time * timeptr)497 static int pcf8523_alarm_get_time(const struct device *dev, uint16_t id, uint16_t *mask,
498 struct rtc_time *timeptr)
499 {
500 uint8_t regs[4];
501 int err;
502
503 if (id != 0U) {
504 LOG_ERR("invalid ID %d", id);
505 return -EINVAL;
506 }
507
508 /* Read registers PCF8523_MINUTE_ALARM through PCF8523_WEEKDAY_ALARM */
509 err = pcf8523_read_regs(dev, PCF8523_MINUTE_ALARM, ®s, sizeof(regs));
510 if (err != 0) {
511 return err;
512 }
513
514 memset(timeptr, 0U, sizeof(*timeptr));
515 *mask = 0U;
516
517 if ((regs[0] & PCF8523_MINUTE_ALARM_AEN_M) == 0) {
518 timeptr->tm_min = bcd2bin(regs[0] & PCF8523_MINUTE_ALARM_MASK);
519 *mask |= RTC_ALARM_TIME_MASK_MINUTE;
520 }
521
522 if ((regs[1] & PCF8523_HOUR_ALARM_AEN_H) == 0) {
523 timeptr->tm_hour = bcd2bin(regs[1] & PCF8523_HOUR_ALARM_24H_MASK);
524 *mask |= RTC_ALARM_TIME_MASK_HOUR;
525 }
526
527 if ((regs[2] & PCF8523_DAY_ALARM_AEN_D) == 0) {
528 timeptr->tm_mday = bcd2bin(regs[2] & PCF8523_DAY_ALARM_MASK);
529 *mask |= RTC_ALARM_TIME_MASK_MONTHDAY;
530 }
531
532 if ((regs[3] & PCF8523_WEEKDAY_ALARM_AEN_W) == 0) {
533 timeptr->tm_wday = bcd2bin(regs[3] & PCF8523_WEEKDAY_ALARM_MASK);
534 *mask |= RTC_ALARM_TIME_MASK_WEEKDAY;
535 }
536
537 LOG_DBG("get alarm: year = %d, mon = %d, mday = %d, hour = %d, min = %d, mask = 0x%04x",
538 timeptr->tm_year, timeptr->tm_mon, timeptr->tm_mday, timeptr->tm_hour,
539 timeptr->tm_min, *mask);
540
541 return 0;
542 }
543
pcf8523_alarm_is_pending(const struct device * dev,uint16_t id)544 static int pcf8523_alarm_is_pending(const struct device *dev, uint16_t id)
545 {
546 struct pcf8523_data *data = dev->data;
547 uint8_t control_2;
548 int err;
549
550 if (id != 0U) {
551 LOG_ERR("invalid ID %d", id);
552 return -EINVAL;
553 }
554
555 k_mutex_lock(&data->lock, K_FOREVER);
556
557 err = pcf8523_read_reg8(dev, PCF8523_CONTROL_2, &control_2);
558 if (err != 0) {
559 goto unlock;
560 }
561
562 if ((control_2 & PCF8523_CONTROL_2_AF) != 0) {
563 /* Clear alarm flag */
564 control_2 &= ~(PCF8523_CONTROL_2_AF);
565
566 /* Ensure other flags are left unchanged (PCF8523 performs logic AND at write) */
567 control_2 |= PCF8523_CONTROL_2_CTAF | PCF8523_CONTROL_2_CTBF | PCF8523_CONTROL_2_SF;
568
569 err = pcf8523_write_reg8(dev, PCF8523_CONTROL_2, control_2);
570 if (err != 0) {
571 goto unlock;
572 }
573
574 /* Alarm pending */
575 err = 1;
576 }
577
578 unlock:
579 k_mutex_unlock(&data->lock);
580
581 return err;
582 }
583
584 #if PCF8523_INT1_GPIOS_IN_USE
pcf8523_alarm_set_callback(const struct device * dev,uint16_t id,rtc_alarm_callback callback,void * user_data)585 static int pcf8523_alarm_set_callback(const struct device *dev, uint16_t id,
586 rtc_alarm_callback callback, void *user_data)
587 {
588 const struct pcf8523_config *config = dev->config;
589 struct pcf8523_data *data = dev->data;
590 uint8_t control_1;
591 int err = 0;
592
593 if (config->int1.port == NULL) {
594 return -ENOTSUP;
595 }
596
597 if (id != 0U) {
598 LOG_ERR("invalid ID %d", id);
599 return -EINVAL;
600 }
601
602 k_mutex_lock(&data->lock, K_FOREVER);
603
604 data->alarm_callback = callback;
605 data->alarm_user_data = user_data;
606
607 if (!config->wakeup_source) {
608 /* Only change AIE if not configured as wakeup-source */
609 err = pcf8523_read_reg8(dev, PCF8523_CONTROL_1, &control_1);
610 if (err != 0) {
611 goto unlock;
612 }
613
614 if (callback != NULL) {
615 control_1 |= PCF8523_CONTROL_1_AIE;
616 } else {
617 control_1 &= ~(PCF8523_CONTROL_1_AIE);
618 }
619
620 if ((control_1 & PCF8523_CONTROL_1_SIE) == 0U) {
621 /* Only change INT1 GPIO if seconds timer interrupt not enabled */
622 err = pcf8523_int1_enable_unlocked(dev, callback != NULL);
623 if (err != 0) {
624 goto unlock;
625 }
626 }
627
628 err = pcf8523_write_reg8(dev, PCF8523_CONTROL_1, control_1);
629 if (err != 0) {
630 goto unlock;
631 }
632 }
633
634 unlock:
635 k_mutex_unlock(&data->lock);
636
637 /* Wake up the INT1 thread since the alarm flag may already be set */
638 k_sem_give(&data->int1_sem);
639
640 return err;
641 }
642 #endif /* PCF8523_INT1_GPIOS_IN_USE */
643 #endif /* CONFIG_RTC_ALARM */
644
645 #if PCF8523_INT1_GPIOS_IN_USE && defined(CONFIG_RTC_UPDATE)
pcf8523_update_set_callback(const struct device * dev,rtc_update_callback callback,void * user_data)646 static int pcf8523_update_set_callback(const struct device *dev, rtc_update_callback callback,
647 void *user_data)
648 {
649 const struct pcf8523_config *config = dev->config;
650 struct pcf8523_data *data = dev->data;
651 uint8_t control_1;
652 int err;
653
654 if (config->int1.port == NULL) {
655 return -ENOTSUP;
656 }
657
658 k_mutex_lock(&data->lock, K_FOREVER);
659
660 data->update_callback = callback;
661 data->update_user_data = user_data;
662
663 err = pcf8523_read_reg8(dev, PCF8523_CONTROL_1, &control_1);
664 if (err != 0) {
665 goto unlock;
666 }
667
668 if (callback != NULL) {
669 control_1 |= PCF8523_CONTROL_1_SIE;
670 } else {
671 control_1 &= ~(PCF8523_CONTROL_1_SIE);
672 }
673
674 if ((control_1 & PCF8523_CONTROL_1_AIE) == 0U) {
675 /* Only change INT1 GPIO if alarm interrupt not enabled */
676 err = pcf8523_int1_enable_unlocked(dev, callback != NULL);
677 if (err != 0) {
678 goto unlock;
679 }
680 }
681
682 err = pcf8523_write_reg8(dev, PCF8523_CONTROL_1, control_1);
683 if (err != 0) {
684 goto unlock;
685 }
686
687 unlock:
688 k_mutex_unlock(&data->lock);
689
690 /* Wake up the INT1 thread since the seconds flag may already be set */
691 k_sem_give(&data->int1_sem);
692
693 return err;
694 }
695 #endif /* PCF8523_INT1_GPIOS_IN_USE && defined(CONFIG_RTC_UPDATE) */
696
697 #ifdef CONFIG_RTC_CALIBRATION
698
699 /* See PCF8523 data sheet table 29 */
700 #if defined(CONFIG_RTC_PCF8523_OFFSET_MODE_SLOW)
701 #define PCF8523_OFFSET_PPB_PER_LSB 4340
702 #elif defined(CONFIG_RTC_PCF8523_OFFSET_MODE_FAST)
703 #define PCF8523_OFFSET_PPB_PER_LSB 4069
704 #else
705 #error Unsupported offset mode
706 #endif
707
708 #define PCF8523_OFFSET_PPB_MIN (-64 * PCF8523_OFFSET_PPB_PER_LSB)
709 #define PCF8523_OFFSET_PPB_MAX (63 * PCF8523_OFFSET_PPB_PER_LSB)
710
pcf8523_set_calibration(const struct device * dev,int32_t freq_ppb)711 static int pcf8523_set_calibration(const struct device *dev, int32_t freq_ppb)
712 {
713 int32_t period_ppb = freq_ppb * -1;
714 int8_t offset;
715
716 if (period_ppb < PCF8523_OFFSET_PPB_MIN || period_ppb > PCF8523_OFFSET_PPB_MAX) {
717 LOG_WRN("calibration value (%d ppb) out of range", freq_ppb);
718 return -EINVAL;
719 }
720
721 offset = period_ppb / PCF8523_OFFSET_PPB_PER_LSB;
722
723 if (IS_ENABLED(CONFIG_RTC_PCF8523_OFFSET_MODE_FAST)) {
724 offset |= PCF8523_OFFSET_MODE;
725 }
726
727 LOG_DBG("freq_ppb = %d, period_ppb = %d, offset = %d", freq_ppb, period_ppb, offset);
728
729 return pcf8523_write_reg8(dev, PCF8523_OFFSET, offset);
730 }
731
pcf8523_get_calibration(const struct device * dev,int32_t * freq_ppb)732 static int pcf8523_get_calibration(const struct device *dev, int32_t *freq_ppb)
733 {
734 int32_t period_ppb;
735 int8_t offset;
736 int err;
737
738 err = pcf8523_read_reg8(dev, PCF8523_OFFSET, &offset);
739 if (err != 0) {
740 return err;
741 }
742
743 /* Clear mode bit and sign extend the offset */
744 period_ppb = (offset << 1U) >> 1U;
745
746 period_ppb = period_ppb * PCF8523_OFFSET_PPB_PER_LSB;
747 *freq_ppb = period_ppb * -1;
748
749 LOG_DBG("freq_ppb = %d, period_ppb = %d, offset = %d", *freq_ppb, period_ppb, offset);
750
751 return 0;
752 }
753 #endif /* CONFIG_RTC_CALIBRATION */
754
pcf8523_init(const struct device * dev)755 static int pcf8523_init(const struct device *dev)
756 {
757 const struct pcf8523_config *config = dev->config;
758 struct pcf8523_data *data = dev->data;
759 uint8_t tmr_clkout_ctrl;
760 uint8_t regs[3];
761 int err;
762
763 k_mutex_init(&data->lock);
764
765 if (!i2c_is_ready_dt(&config->i2c)) {
766 LOG_ERR("I2C bus not ready");
767 return -ENODEV;
768 }
769
770 #if PCF8523_INT1_GPIOS_IN_USE
771 k_tid_t tid;
772
773 if (config->int1.port != NULL) {
774 k_sem_init(&data->int1_sem, 0, INT_MAX);
775
776 if (!gpio_is_ready_dt(&config->int1)) {
777 LOG_ERR("GPIO not ready");
778 return -ENODEV;
779 }
780
781 err = gpio_pin_configure_dt(&config->int1, GPIO_INPUT);
782 if (err != 0) {
783 LOG_ERR("failed to configure GPIO (err %d)", err);
784 return -ENODEV;
785 }
786
787 gpio_init_callback(&data->int1_callback, pcf8523_int1_callback_handler,
788 BIT(config->int1.pin));
789
790 err = gpio_add_callback_dt(&config->int1, &data->int1_callback);
791 if (err != 0) {
792 LOG_ERR("failed to add GPIO callback (err %d)", err);
793 return -ENODEV;
794 }
795
796 tid = k_thread_create(&data->int1_thread, data->int1_stack,
797 K_THREAD_STACK_SIZEOF(data->int1_stack),
798 pcf8523_int1_thread, (void *)dev, NULL,
799 NULL, CONFIG_RTC_PCF8523_THREAD_PRIO, 0, K_NO_WAIT);
800 k_thread_name_set(tid, "pcf8523");
801
802 /*
803 * Defer GPIO interrupt configuration due to INT1/CLKOUT pin sharing. This allows
804 * using the CLKOUT square-wave signal for RTC calibration when no alarm/update
805 * callbacks are enabled (and not configured as a wakeup-source).
806 */
807 }
808 #endif /* PCF8523_INT1_GPIOS_IN_USE */
809
810 /*
811 * Manually initialize the required PCF8523 registers as performing a software reset will
812 * reset the time circuits.
813 */
814
815 /* Read registers PCF8523_CONTROL_1 through PCF8523_CONTROL_3 */
816 err = pcf8523_read_regs(dev, PCF8523_CONTROL_1, ®s, sizeof(regs));
817 if (err != 0) {
818 return -ENODEV;
819 }
820
821 /* Set quartz crystal load capacitance */
822 if (config->cap_sel) {
823 regs[0] |= PCF8523_CONTROL_1_CAP_SEL;
824 } else {
825 regs[0] &= ~(PCF8523_CONTROL_1_CAP_SEL);
826 }
827
828 /* Use 24h time format */
829 regs[0] &= ~(PCF8523_CONTROL_1_12_24);
830
831 /* Disable second, alarm, and correction interrupts */
832 regs[0] &= ~(PCF8523_CONTROL_1_SIE | PCF8523_CONTROL_1_AIE | PCF8523_CONTROL_1_CIE);
833
834 if (config->wakeup_source) {
835 /*
836 * Always set AIE if wakeup-source. This allows the RTC to wake up the system even
837 * if the INT1 interrupt output is not directly connected to a GPIO (i.e. if
838 * connected to a PMIC input).
839 */
840 regs[0] |= PCF8523_CONTROL_1_AIE;
841 }
842
843 /* Clear interrupt flags (except alarm flag, as a wake-up alarm may be pending) */
844 regs[1] &= ~(PCF8523_CONTROL_2_CTAF | PCF8523_CONTROL_2_CTBF | PCF8523_CONTROL_2_SF);
845
846 /* Disable watchdog, timer A, and timer B interrupts */
847 regs[1] &= ~(PCF8523_CONTROL_2_WTAIE | PCF8523_CONTROL_2_CTAIE | PCF8523_CONTROL_2_CTBIE);
848
849 /* Configure battery switch-over function */
850 regs[2] &= ~(PCF8523_CONTROL_3_PM_MASK);
851 regs[2] |= FIELD_PREP(PCF8523_CONTROL_3_PM_MASK, config->pm);
852
853 /* Clear battery status interrupt flag */
854 regs[2] &= ~(PCF8523_CONTROL_3_BSF);
855
856 /* Disable battery status interrupts */
857 regs[2] &= ~(PCF8523_CONTROL_3_BSIE | PCF8523_CONTROL_3_BLIE);
858
859 /* Write registers PCF8523_CONTROL_1 through PCF8523_CONTROL_3 */
860 err = pcf8523_write_regs(dev, PCF8523_CONTROL_1, ®s, sizeof(regs));
861 if (err != 0) {
862 return -ENODEV;
863 }
864
865 /* Disable watchdog and countdown timers, configure IRQ level*/
866 tmr_clkout_ctrl = 0U;
867
868 if (config->wakeup_source) {
869 /* Disable CLKOUT */
870 tmr_clkout_ctrl |= PCF8523_TMR_CLKOUT_CTRL_COF_MASK;
871 } else {
872 /* Configure CLKOUT frequency */
873 tmr_clkout_ctrl |= FIELD_PREP(PCF8523_TMR_CLKOUT_CTRL_COF_MASK, config->cof);
874 }
875
876 err = pcf8523_write_reg8(dev, PCF8523_TMR_CLKOUT_CTRL, tmr_clkout_ctrl);
877 if (err != 0) {
878 return -ENODEV;
879 }
880
881 return 0;
882 }
883
884 /* Mapping from DT battery-switch-over enum to CONTROL_3 PM field value */
885 #define PCF8523_PM_STANDARD 4U
886 #define PCF8523_PM_DIRECT 5U
887 #define PCF8523_PM_DISABLED 7U
888
889 #ifdef CONFIG_PM_DEVICE
pcf8523_pm_action(const struct device * dev,enum pm_device_action action)890 static int pcf8523_pm_action(const struct device *dev, enum pm_device_action action)
891 {
892 const struct pcf8523_config *config = dev->config;
893 uint8_t control_3;
894 int err;
895
896 if (config->pm == PCF8523_PM_DISABLED) {
897 /* Only one power supply */
898 return -ENOTSUP;
899 }
900
901 switch (action) {
902 case PM_DEVICE_ACTION_SUSPEND:
903 /* Disable battery switch-over function */
904 control_3 = FIELD_PREP(PCF8523_CONTROL_3_PM_MASK, PCF8523_PM_DISABLED);
905 break;
906 case PM_DEVICE_ACTION_RESUME:
907 /* Re-enable battery switch-over function */
908 control_3 = FIELD_PREP(PCF8523_CONTROL_3_PM_MASK, config->pm);
909 break;
910 default:
911 return -ENOTSUP;
912 }
913
914 err = pcf8523_write_reg8(dev, PCF8523_CONTROL_3, control_3);
915 if (err != 0) {
916 return -EIO;
917 }
918
919 return 0;
920 }
921 #endif /* CONFIG_PM_DEVICE */
922
923 static const struct rtc_driver_api pcf8523_driver_api = {
924 .set_time = pcf8523_set_time,
925 .get_time = pcf8523_get_time,
926 #ifdef CONFIG_RTC_ALARM
927 .alarm_get_supported_fields = pcf8523_alarm_get_supported_fields,
928 .alarm_set_time = pcf8523_alarm_set_time,
929 .alarm_get_time = pcf8523_alarm_get_time,
930 .alarm_is_pending = pcf8523_alarm_is_pending,
931 #if PCF8523_INT1_GPIOS_IN_USE
932 .alarm_set_callback = pcf8523_alarm_set_callback,
933 #endif /* PCF8523_INT1_GPIOS_IN_USE */
934 #endif /* CONFIG_RTC_ALARM */
935 #if PCF8523_INT1_GPIOS_IN_USE && defined(CONFIG_RTC_UPDATE)
936 .update_set_callback = pcf8523_update_set_callback,
937 #endif /* PCF8523_INT1_GPIOS_IN_USE && defined(CONFIG_RTC_UPDATE) */
938 #ifdef CONFIG_RTC_CALIBRATION
939 .set_calibration = pcf8523_set_calibration,
940 .get_calibration = pcf8523_get_calibration,
941 #endif /* CONFIG_RTC_CALIBRATION */
942 };
943
944 #define PCF8523_PM_FROM_DT_INST(inst) \
945 UTIL_CAT(PCF8523_PM_, DT_INST_STRING_UPPER_TOKEN(inst, battery_switch_over))
946 #define PCF8523_CAP_SEL_FROM_DT_INST(inst) (DT_INST_PROP(inst, quartz_load_femtofarads) == 12500)
947
948 #define PCF8523_INIT(inst) \
949 static const struct pcf8523_config pcf8523_config_##inst = { \
950 .i2c = I2C_DT_SPEC_INST_GET(inst), \
951 .cof = DT_INST_ENUM_IDX(inst, clkout_frequency), \
952 .pm = PCF8523_PM_FROM_DT_INST(inst), \
953 .cap_sel = PCF8523_CAP_SEL_FROM_DT_INST(inst), \
954 .wakeup_source = DT_INST_PROP(inst, wakeup_source), \
955 IF_ENABLED(PCF8523_INT1_GPIOS_IN_USE, \
956 (.int1 = GPIO_DT_SPEC_INST_GET_OR(inst, int1_gpios, {0})))}; \
957 \
958 static struct pcf8523_data pcf8523_data_##inst; \
959 \
960 PM_DEVICE_DT_INST_DEFINE(inst, pcf8523_pm_action); \
961 \
962 DEVICE_DT_INST_DEFINE(inst, &pcf8523_init, PM_DEVICE_DT_INST_GET(inst), \
963 &pcf8523_data_##inst, &pcf8523_config_##inst, POST_KERNEL, \
964 CONFIG_RTC_INIT_PRIORITY, &pcf8523_driver_api);
965
966 DT_INST_FOREACH_STATUS_OKAY(PCF8523_INIT)
967