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, &regs, 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, &regs, 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, &regs, 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, &regs, 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, &regs, 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, &regs, 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