1 /* Copyright (c) 2024 Daniel Kampert
2  * Author: Daniel Kampert <DanielKampert@kampis-Elektroecke.de>
3  */
4 
5 #include <zephyr/device.h>
6 #include <zephyr/devicetree.h>
7 #include <zephyr/drivers/i2c.h>
8 #include <zephyr/drivers/gpio.h>
9 #include <zephyr/drivers/rtc.h>
10 #include <zephyr/logging/log.h>
11 #include <zephyr/sys/byteorder.h>
12 #include "rtc_utils.h"
13 
14 #define RV8263C8_REGISTER_CONTROL_1     0x00
15 #define RV8263C8_REGISTER_CONTROL_2     0x01
16 #define RV8263C8_REGISTER_OFFSET        0x02
17 #define RV8263C8_REGISTER_RAM           0x03
18 #define RV8263C8_REGISTER_SECONDS       0x04
19 #define RV8263C8_REGISTER_MINUTES       0x05
20 #define RV8263C8_REGISTER_HOURS         0x06
21 #define RV8263C8_REGISTER_DATE          0x07
22 #define RV8263C8_REGISTER_WEEKDAY       0x08
23 #define RV8263C8_REGISTER_MONTH         0x09
24 #define RV8263C8_REGISTER_YEAR          0x0A
25 #define RV8263C8_REGISTER_SECONDS_ALARM 0x0B
26 #define RV8263C8_REGISTER_MINUTES_ALARM 0x0C
27 #define RV8263C8_REGISTER_HOURS_ALARM   0x0D
28 #define RV8263C8_REGISTER_DATE_ALARM    0x0E
29 #define RV8263C8_REGISTER_WEEKDAY_ALARM 0x0F
30 #define RV8263C8_REGISTER_TIMER_VALUE   0x10
31 #define RV8263C8_REGISTER_TIMER_MODE    0x11
32 
33 #define RV8263_BM_FAST_MODE                 (0x01 << 7)
34 #define RV8263_BM_NORMAL_MODE               (0x00 << 7)
35 #define RV8263C8_BM_24H_MODE_ENABLE         (0x00 << 1)
36 #define RV8263C8_BM_24H_MODE_DISABLE        (0x00 << 1)
37 #define RV8263C8_BM_CLOCK_ENABLE            (0x00 << 5)
38 #define RV8263C8_BM_CLOCK_DISABLE           (0x01 << 5)
39 #define RV8263C8_BM_ALARM_INT_ENABLE        (0x01 << 7)
40 #define RV8263C8_BM_ALARM_INT_DISABLE       (0x00 << 7)
41 #define RV8263C8_BM_MINUTE_INT_ENABLE       (0x01 << 5)
42 #define RV8263C8_BM_MINUTE_INT_DISABLE      (0x00 << 5)
43 #define RV8263C8_BM_HALF_MINUTE_INT_ENABLE  (0x01 << 4)
44 #define RV8263C8_BM_HALF_MINUTE_INT_DISABLE (0x00 << 4)
45 #define RV8263C8_BM_ALARM_ENABLE            (0x00 << 7)
46 #define RV8263C8_BM_ALARM_DISABLE           (0x01 << 7)
47 #define RV8263C8_BM_AF                      (0x01 << 6)
48 #define RV8263C8_BM_TF                      (0x01 << 3)
49 #define RV8263_BM_MODE                      (0x01 << 7)
50 #define RV8263_BM_TD_1HZ                    (0x02 << 3)
51 #define RV8263_BM_TE_ENABLE                 (0x01 << 2)
52 #define RV8263_BM_TIE_ENABLE                (0x01 << 1)
53 #define RV8263_BM_TI_TP_PULSE               (0x01 << 0)
54 #define RV8263_BM_OS                        (0x01 << 7)
55 #define RV8263C8_BM_SOFTWARE_RESET          (0x58)
56 #define RV8263C8_BM_REGISTER_OFFSET         0x7F
57 #define RV8263_YEAR_OFFSET                  (2000 - 1900)
58 
59 #define SECONDS_BITS  GENMASK(6, 0)
60 #define MINUTES_BITS  GENMASK(7, 0)
61 #define HOURS_BITS    GENMASK(5, 0)
62 #define DATE_BITS     GENMASK(5, 0)
63 #define MONTHS_BITS   GENMASK(4, 0)
64 #define WEEKDAY_BITS  GENMASK(2, 0)
65 #define YEAR_BITS     GENMASK(7, 0)
66 #define VALIDATE_24HR BIT(6)
67 
68 #define MIN_SEC       0
69 #define MAX_SEC       59
70 #define MIN_MIN       0
71 #define MAX_MIN       59
72 #define MIN_HOUR      0
73 #define MAX_HOUR      23
74 #define MAX_WDAY      7
75 #define MIN_WDAY      1
76 #define MAX_MDAY      31
77 #define MIN_MDAY      1
78 #define MAX_MON       12
79 #define MIN_MON       1
80 #define MIN_YEAR_DIFF 0
81 #define MAX_YEAR_DIFF 99
82 
83 #define DT_DRV_COMPAT microcrystal_rv_8263_c8
84 
85 LOG_MODULE_REGISTER(microcrystal_rv8263c8, CONFIG_RTC_LOG_LEVEL);
86 
87 struct rv8263c8_config {
88 	struct i2c_dt_spec i2c_bus;
89 	uint32_t clkout;
90 
91 #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
92 	struct gpio_dt_spec int_gpio;
93 #endif
94 };
95 
96 struct rv8263c8_data {
97 	struct k_sem lock;
98 
99 #if (CONFIG_RTC_ALARM || CONFIG_RTC_UPDATE) && DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
100 	const struct device *dev;
101 	struct gpio_callback gpio_cb;
102 #endif
103 
104 #if CONFIG_RTC_ALARM && DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
105 	rtc_alarm_callback alarm_cb;
106 	void *alarm_cb_data;
107 	struct k_work alarm_work;
108 #endif
109 
110 #if CONFIG_RTC_UPDATE && DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
111 	rtc_update_callback update_cb;
112 	void *update_cb_data;
113 	struct k_work update_work;
114 #endif
115 };
116 
rv8263c8_update_disable_timer(const struct device * dev)117 static int rv8263c8_update_disable_timer(const struct device *dev)
118 {
119 	int err;
120 	uint8_t buf[2];
121 	const struct rv8263c8_config *config = dev->config;
122 
123 	/* Value 0 disables the timer. */
124 	buf[0] = RV8263C8_REGISTER_TIMER_VALUE;
125 	buf[1] = 0;
126 	err = i2c_write_dt(&config->i2c_bus, buf, 2);
127 	if (err < 0) {
128 		return err;
129 	}
130 
131 	buf[0] = RV8263C8_REGISTER_TIMER_MODE;
132 	return i2c_write_dt(&config->i2c_bus, buf, 2);
133 }
134 
135 #if (CONFIG_RTC_ALARM || CONFIG_RTC_UPDATE) && DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
rv8263c8_gpio_callback_handler(const struct device * p_port,struct gpio_callback * p_cb,gpio_port_pins_t pins)136 static void rv8263c8_gpio_callback_handler(const struct device *p_port, struct gpio_callback *p_cb,
137 					   gpio_port_pins_t pins)
138 {
139 	ARG_UNUSED(pins);
140 	ARG_UNUSED(p_port);
141 
142 	struct rv8263c8_data *data = CONTAINER_OF(p_cb, struct rv8263c8_data, gpio_cb);
143 
144 #if CONFIG_RTC_ALARM
145 	k_work_submit(&data->alarm_work);
146 #endif
147 
148 #if CONFIG_RTC_UPDATE
149 	k_work_submit(&data->update_work);
150 #endif
151 }
152 #endif
153 
154 #if CONFIG_RTC_ALARM && DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
rv8263c8_alarm_worker(struct k_work * p_work)155 static void rv8263c8_alarm_worker(struct k_work *p_work)
156 {
157 	struct rv8263c8_data *data = CONTAINER_OF(p_work, struct rv8263c8_data, alarm_work);
158 	const struct rv8263c8_config *config = data->dev->config;
159 
160 	LOG_DBG("Process alarm worker from interrupt");
161 
162 	if (data->alarm_cb != NULL) {
163 		uint8_t reg;
164 
165 		i2c_reg_read_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2, &reg);
166 
167 		if (reg & RV8263C8_BM_AF) {
168 			reg &= ~RV8263C8_BM_AF;
169 
170 			LOG_DBG("Calling alarm callback");
171 			data->alarm_cb(data->dev, 0, data->alarm_cb_data);
172 
173 			i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2, reg);
174 		}
175 	}
176 }
177 #endif
178 
179 #if CONFIG_RTC_UPDATE && DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
rv8263c8_update_enable_timer(const struct device * dev)180 static int rv8263c8_update_enable_timer(const struct device *dev)
181 {
182 	int err;
183 	const struct rv8263c8_config *config = dev->config;
184 	uint8_t buf[2];
185 
186 	/* Set the timer preload value for 1 second. */
187 	buf[0] = RV8263C8_REGISTER_TIMER_VALUE;
188 	buf[1] = 1;
189 	err = i2c_write_dt(&config->i2c_bus, buf, 2);
190 	if (err < 0) {
191 		return err;
192 	}
193 
194 	buf[0] = RV8263C8_REGISTER_TIMER_MODE;
195 	buf[1] = RV8263_BM_TD_1HZ | RV8263_BM_TE_ENABLE | RV8263_BM_TIE_ENABLE |
196 		 RV8263_BM_TI_TP_PULSE;
197 	return i2c_write_dt(&config->i2c_bus, buf, 2);
198 }
199 
rv8263c8_update_worker(struct k_work * p_work)200 static void rv8263c8_update_worker(struct k_work *p_work)
201 {
202 	uint8_t reg;
203 	struct rv8263c8_data *data = CONTAINER_OF(p_work, struct rv8263c8_data, update_work);
204 	const struct rv8263c8_config *config = data->dev->config;
205 
206 	LOG_DBG("Process update worker from interrupt");
207 
208 	if (data->update_cb != NULL) {
209 		i2c_reg_read_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2, &reg);
210 
211 		if (reg & RV8263C8_BM_TF) {
212 			LOG_DBG("Calling update callback");
213 			data->update_cb(data->dev, data->update_cb_data);
214 		}
215 	}
216 
217 	rv8263c8_update_enable_timer(data->dev);
218 	i2c_reg_update_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2, RV8263C8_BM_TF,
219 			       RV8263C8_BM_TF);
220 }
221 #endif
222 
rv8263c8_time_set(const struct device * dev,const struct rtc_time * timeptr)223 static int rv8263c8_time_set(const struct device *dev, const struct rtc_time *timeptr)
224 {
225 	uint8_t regs[8];
226 	const struct rv8263c8_config *config = dev->config;
227 
228 	if (timeptr == NULL || (timeptr->tm_year < RV8263_YEAR_OFFSET)) {
229 		LOG_ERR("invalid time");
230 		return -EINVAL;
231 	}
232 
233 	LOG_DBG("Set time: year = %u, mon = %u, mday = %u, wday = %u, hour = %u, min = %u, sec = "
234 		"%u",
235 		timeptr->tm_year, timeptr->tm_mon, timeptr->tm_mday, timeptr->tm_wday,
236 		timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec);
237 
238 	regs[0] = RV8263C8_REGISTER_SECONDS;
239 	regs[1] = bin2bcd(timeptr->tm_sec) & SECONDS_BITS;
240 	regs[2] = bin2bcd(timeptr->tm_min) & MINUTES_BITS;
241 	regs[3] = bin2bcd(timeptr->tm_hour) & HOURS_BITS;
242 	regs[4] = bin2bcd(timeptr->tm_mday) & DATE_BITS;
243 	regs[5] = bin2bcd(timeptr->tm_wday) & WEEKDAY_BITS;
244 	regs[6] = bin2bcd(timeptr->tm_mon) & MONTHS_BITS;
245 	regs[7] = bin2bcd(timeptr->tm_year - RV8263_YEAR_OFFSET) & YEAR_BITS;
246 
247 	return i2c_write_dt(&config->i2c_bus, regs, 8);
248 }
249 
rv8263c8_time_get(const struct device * dev,struct rtc_time * timeptr)250 static int rv8263c8_time_get(const struct device *dev, struct rtc_time *timeptr)
251 {
252 	int err;
253 	uint8_t regs[7];
254 	const struct rv8263c8_config *config = dev->config;
255 
256 	if (timeptr == NULL) {
257 		return -EINVAL;
258 	}
259 
260 	err = i2c_burst_read_dt(&config->i2c_bus, RV8263C8_REGISTER_SECONDS, regs, sizeof(regs));
261 	if (err < 0) {
262 		return err;
263 	}
264 
265 	/* Return an error when the oscillator is stopped. */
266 	if (regs[0] & RV8263_BM_OS) {
267 		return -ENODATA;
268 	}
269 
270 	timeptr->tm_sec = bcd2bin(regs[0] & SECONDS_BITS);
271 	timeptr->tm_min = bcd2bin(regs[1] & MINUTES_BITS);
272 	timeptr->tm_hour = bcd2bin(regs[2] & HOURS_BITS);
273 	timeptr->tm_mday = bcd2bin(regs[3] & DATE_BITS);
274 	timeptr->tm_wday = bcd2bin(regs[4] & WEEKDAY_BITS);
275 	timeptr->tm_mon = bcd2bin(regs[5] & MONTHS_BITS);
276 	timeptr->tm_year = bcd2bin(regs[6] & YEAR_BITS) + RV8263_YEAR_OFFSET;
277 
278 	/* Unused. */
279 	timeptr->tm_nsec = 0;
280 	timeptr->tm_isdst = -1;
281 	timeptr->tm_yday = -1;
282 
283 	/* Validate the chip in 24hr mode. */
284 	if (regs[2] & VALIDATE_24HR) {
285 		return -ENODATA;
286 	}
287 
288 	LOG_DBG("Get time: year = %u, mon = %u, mday = %u, wday = %u, hour = %u, min = %u, sec = "
289 		"%u",
290 		timeptr->tm_year, timeptr->tm_mon, timeptr->tm_mday, timeptr->tm_wday,
291 		timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec);
292 
293 	return 0;
294 }
295 
rv8263c8_init(const struct device * dev)296 static int rv8263c8_init(const struct device *dev)
297 {
298 	int err;
299 	int temp;
300 	struct rv8263c8_data *data = dev->data;
301 	const struct rv8263c8_config *config = dev->config;
302 
303 #if (CONFIG_RTC_ALARM || CONFIG_RTC_UPDATE) && DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
304 	if (config->int_gpio.port == NULL) {
305 		return -EINVAL;
306 	}
307 #endif
308 
309 	if (!i2c_is_ready_dt(&config->i2c_bus)) {
310 		LOG_ERR("I2C bus not ready!");
311 		return -ENODEV;
312 	}
313 
314 	k_sem_init(&data->lock, 1, 1);
315 
316 	err = rv8263c8_update_disable_timer(dev);
317 	if (err < 0) {
318 		LOG_ERR("Error while disabling the timer! Error: %i", err);
319 		return err;
320 	}
321 
322 	err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_1,
323 				    RV8263C8_BM_24H_MODE_DISABLE | RV8263C8_BM_CLOCK_ENABLE);
324 	if (err < 0) {
325 		LOG_ERR("Error while writing CONTROL_1! Error: %i", err);
326 		return err;
327 	}
328 
329 	temp = config->clkout;
330 	LOG_DBG("Configure ClkOut: %u", temp);
331 
332 	err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2,
333 				    RV8263C8_BM_AF | temp);
334 	if (err < 0) {
335 		LOG_ERR("Error while writing CONTROL_2! Error: %i", err);
336 		return err;
337 	}
338 
339 	LOG_DBG("Configure ClkOut: %u", temp);
340 
341 #if CONFIG_RTC_UPDATE && DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
342 	uint8_t buf[2];
343 
344 	buf[0] = RV8263C8_REGISTER_TIMER_MODE;
345 	buf[1] = 0;
346 	err = i2c_write_dt(&config->i2c_bus, buf, 2);
347 	if (err < 0) {
348 		LOG_ERR("Error while writing CONTROL2! Error: %i", err);
349 		return err;
350 	}
351 #endif
352 
353 #if (CONFIG_RTC_ALARM || CONFIG_RTC_UPDATE) && DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
354 	if (!gpio_is_ready_dt(&config->int_gpio)) {
355 		LOG_ERR("GPIO not ready!");
356 		return err;
357 	}
358 
359 	err = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT);
360 	if (err < 0) {
361 		LOG_ERR("Failed to configure GPIO! Error: %u", err);
362 		return err;
363 	}
364 
365 	err = gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_EDGE_FALLING);
366 	if (err < 0) {
367 		LOG_ERR("Failed to configure interrupt! Error: %u", err);
368 		return err;
369 	}
370 
371 	gpio_init_callback(&data->gpio_cb, rv8263c8_gpio_callback_handler,
372 			   BIT(config->int_gpio.pin));
373 
374 	err = gpio_add_callback_dt(&config->int_gpio, &data->gpio_cb);
375 	if (err < 0) {
376 		LOG_ERR("Failed to add GPIO callback! Error: %u", err);
377 		return err;
378 	}
379 #endif
380 
381 	(void)k_sem_take(&data->lock, K_FOREVER);
382 #if CONFIG_RTC_ALARM && DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
383 	data->alarm_work.handler = rv8263c8_alarm_worker;
384 #endif
385 
386 #if CONFIG_RTC_UPDATE && DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
387 	data->update_work.handler = rv8263c8_update_worker;
388 #endif
389 
390 #if (CONFIG_RTC_ALARM || CONFIG_RTC_UPDATE) && DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
391 	data->dev = dev;
392 #endif
393 	k_sem_give(&data->lock);
394 
395 	return 0;
396 }
397 
398 #if CONFIG_RTC_ALARM
rv8263c8_alarm_get_supported_fields(const struct device * dev,uint16_t id,uint16_t * p_mask)399 static int rv8263c8_alarm_get_supported_fields(const struct device *dev, uint16_t id,
400 					       uint16_t *p_mask)
401 {
402 	ARG_UNUSED(dev);
403 	ARG_UNUSED(id);
404 
405 	(*p_mask) = (RTC_ALARM_TIME_MASK_SECOND | RTC_ALARM_TIME_MASK_MINUTE |
406 		     RTC_ALARM_TIME_MASK_HOUR | RTC_ALARM_TIME_MASK_MONTHDAY |
407 		     RTC_ALARM_TIME_MASK_WEEKDAY);
408 
409 	return 0;
410 }
411 
rv8263c8_alarm_set_time(const struct device * dev,uint16_t id,uint16_t mask,const struct rtc_time * timeptr)412 static int rv8263c8_alarm_set_time(const struct device *dev, uint16_t id, uint16_t mask,
413 				   const struct rtc_time *timeptr)
414 {
415 	int err;
416 	uint8_t regs[5];
417 	const struct rv8263c8_config *config = dev->config;
418 
419 	ARG_UNUSED(id);
420 
421 	if ((mask > 0) && (timeptr == NULL)) {
422 		return -EINVAL;
423 	}
424 
425 	/* Disable the alarm when mask is zero. */
426 	if (mask == 0) {
427 		return i2c_reg_update_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2,
428 					      RV8263C8_BM_ALARM_INT_ENABLE,
429 					      RV8263C8_BM_ALARM_INT_DISABLE);
430 	}
431 
432 	if (!rtc_utils_validate_rtc_time(timeptr, mask)) {
433 		LOG_ERR("Invalid mask!");
434 		return -EINVAL;
435 	}
436 
437 	regs[0] = bin2bcd(timeptr->tm_sec) & SECONDS_BITS;
438 	regs[1] = bin2bcd(timeptr->tm_min) & MINUTES_BITS;
439 	regs[2] = bin2bcd(timeptr->tm_hour) & HOURS_BITS;
440 	regs[3] = bin2bcd(timeptr->tm_mday) & DATE_BITS;
441 	regs[4] = bin2bcd(timeptr->tm_wday) & WEEKDAY_BITS;
442 
443 	if (mask & RTC_ALARM_TIME_MASK_SECOND) {
444 		err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_SECONDS_ALARM,
445 					    RV8263C8_BM_ALARM_ENABLE | regs[0]);
446 	} else {
447 		err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_SECONDS_ALARM,
448 					    RV8263C8_BM_ALARM_DISABLE);
449 	}
450 
451 	if (err < 0) {
452 		LOG_ERR("Error while writing SECONDS alarm! Error: %i", err);
453 		return err;
454 	}
455 
456 	if (mask & RTC_ALARM_TIME_MASK_MINUTE) {
457 		err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_MINUTES_ALARM,
458 					    RV8263C8_BM_ALARM_ENABLE | regs[1]);
459 	} else {
460 		err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_MINUTES_ALARM,
461 					    RV8263C8_BM_ALARM_DISABLE);
462 	}
463 
464 	if (err < 0) {
465 		LOG_ERR("Error while writing MINUTE alarm! Error: %i", err);
466 		return err;
467 	}
468 
469 	if (mask & RTC_ALARM_TIME_MASK_HOUR) {
470 		err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_HOURS_ALARM,
471 					    RV8263C8_BM_ALARM_ENABLE | regs[2]);
472 	} else {
473 		err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_HOURS_ALARM,
474 					    RV8263C8_BM_ALARM_DISABLE);
475 	}
476 
477 	if (err < 0) {
478 		LOG_ERR("Error while writing HOUR alarm! Error: %i", err);
479 		return err;
480 	}
481 
482 	if (mask & RTC_ALARM_TIME_MASK_MONTHDAY) {
483 		err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_DATE_ALARM,
484 					    RV8263C8_BM_ALARM_ENABLE | regs[3]);
485 	} else {
486 		err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_DATE_ALARM,
487 					    RV8263C8_BM_ALARM_DISABLE);
488 	}
489 
490 	if (err < 0) {
491 		LOG_ERR("Error while writing MONTHDAY alarm! Error: %i", err);
492 		return err;
493 	}
494 
495 	if (mask & RTC_ALARM_TIME_MASK_WEEKDAY) {
496 		err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_WEEKDAY_ALARM,
497 					    RV8263C8_BM_ALARM_ENABLE | regs[4]);
498 	} else {
499 		err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_WEEKDAY_ALARM,
500 					    RV8263C8_BM_ALARM_DISABLE);
501 	}
502 
503 	if (err < 0) {
504 		LOG_ERR("Error while writing WEEKDAY alarm! Error: %i", err);
505 	}
506 
507 	return err;
508 }
509 
rv8263c8_alarm_get_time(const struct device * dev,uint16_t id,uint16_t * p_mask,struct rtc_time * timeptr)510 static int rv8263c8_alarm_get_time(const struct device *dev, uint16_t id, uint16_t *p_mask,
511 				   struct rtc_time *timeptr)
512 {
513 	int err;
514 	const struct rv8263c8_config *config = dev->config;
515 	uint8_t value[5];
516 
517 	ARG_UNUSED(id);
518 
519 	if (timeptr == NULL) {
520 		return -EINVAL;
521 	}
522 
523 	(*p_mask) = 0;
524 
525 	err = i2c_burst_read_dt(&config->i2c_bus, RV8263C8_REGISTER_SECONDS_ALARM, value,
526 				sizeof(value));
527 	if (err < 0) {
528 		LOG_ERR("Error while reading alarm! Error: %i", err);
529 		return err;
530 	}
531 
532 	if (value[0] <= MAX_SEC) {
533 		timeptr->tm_sec = bcd2bin(value[0]) & SECONDS_BITS;
534 		(*p_mask) |= RTC_ALARM_TIME_MASK_SECOND;
535 	}
536 
537 	if (value[1] <= MAX_MIN) {
538 		timeptr->tm_min = bcd2bin(value[1]) & MINUTES_BITS;
539 		(*p_mask) |= RTC_ALARM_TIME_MASK_MINUTE;
540 	}
541 
542 	if (value[2] <= MAX_HOUR) {
543 		timeptr->tm_hour = bcd2bin(value[2]) & HOURS_BITS;
544 		(*p_mask) |= RTC_ALARM_TIME_MASK_HOUR;
545 	}
546 
547 	if (value[3] <= MAX_MDAY) {
548 		timeptr->tm_mday = bcd2bin(value[3]) & DATE_BITS;
549 		(*p_mask) |= RTC_ALARM_TIME_MASK_MONTHDAY;
550 	}
551 
552 	if (value[4] <= MAX_WDAY) {
553 		timeptr->tm_wday = bcd2bin(value[4]) & WEEKDAY_BITS;
554 		(*p_mask) |= RTC_ALARM_TIME_MASK_WEEKDAY;
555 	}
556 
557 	return 0;
558 }
559 
rv8263c8_alarm_set_callback(const struct device * dev,uint16_t id,rtc_alarm_callback callback,void * user_data)560 static int rv8263c8_alarm_set_callback(const struct device *dev, uint16_t id,
561 				       rtc_alarm_callback callback, void *user_data)
562 {
563 	int err;
564 	const struct rv8263c8_config *config = dev->config;
565 
566 #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
567 	struct rv8263c8_data *data = dev->data;
568 #endif
569 
570 	ARG_UNUSED(id);
571 
572 #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
573 	if (config->int_gpio.port == NULL) {
574 		return -ENOTSUP;
575 	}
576 
577 	(void)k_sem_take(&data->lock, K_FOREVER);
578 	data->alarm_cb = callback;
579 	data->alarm_cb_data = user_data;
580 	k_sem_give(&data->lock);
581 #else
582 	return -ENOTSUP;
583 #endif
584 
585 	if ((callback == NULL) && (user_data == NULL)) {
586 		LOG_DBG("Disable alarm function");
587 
588 		err = i2c_reg_update_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2,
589 					     RV8263C8_BM_ALARM_INT_ENABLE,
590 					     RV8263C8_BM_ALARM_INT_DISABLE);
591 	} else {
592 		LOG_DBG("Enable alarm function");
593 
594 		err = i2c_reg_update_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2,
595 					     RV8263C8_BM_ALARM_INT_ENABLE | RV8263C8_BM_AF,
596 					     RV8263C8_BM_ALARM_INT_ENABLE);
597 	}
598 
599 	if (err < 0) {
600 		LOG_ERR("Error while writing CONTROL2! Error: %i", err);
601 	}
602 
603 	return err;
604 }
605 
rv8263c8_alarm_is_pending(const struct device * dev,uint16_t id)606 static int rv8263c8_alarm_is_pending(const struct device *dev, uint16_t id)
607 {
608 	int err;
609 	uint8_t reg;
610 	const struct rv8263c8_config *config = dev->config;
611 
612 	ARG_UNUSED(id);
613 
614 	err = i2c_reg_read_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2, &reg);
615 	if (err) {
616 		return err;
617 	}
618 
619 	if (reg & RV8263C8_BM_AF) {
620 		reg &= ~RV8263C8_BM_AF;
621 		err = i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_CONTROL_2, reg);
622 		if (err) {
623 			return err;
624 		}
625 
626 		return 1;
627 	}
628 
629 	return 0;
630 }
631 #endif
632 
633 #if CONFIG_RTC_UPDATE && DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
rv8263_update_callback(const struct device * dev,rtc_update_callback callback,void * user_data)634 int rv8263_update_callback(const struct device *dev, rtc_update_callback callback, void *user_data)
635 {
636 	struct rv8263c8_data *const data = dev->data;
637 
638 	(void)k_sem_take(&data->lock, K_FOREVER);
639 	data->update_cb = callback;
640 	data->update_cb_data = user_data;
641 	k_sem_give(&data->lock);
642 
643 	/* Disable the update callback. */
644 	if ((callback == NULL) && (user_data == NULL)) {
645 		return rv8263c8_update_disable_timer(dev);
646 	}
647 
648 	return rv8263c8_update_enable_timer(dev);
649 }
650 #endif
651 
652 #ifdef CONFIG_RTC_CALIBRATION
rv8263c8_calibration_set(const struct device * dev,int32_t calibration)653 int rv8263c8_calibration_set(const struct device *dev, int32_t calibration)
654 {
655 	int8_t offset;
656 	int32_t test_mode0;
657 	int32_t test_mode1;
658 	int32_t offset_ppm_mode0;
659 	int32_t offset_ppm_mode1;
660 	const struct rv8263c8_config *config = dev->config;
661 
662 	/* NOTE: The RTC API is using a PPB (Parts Per Billion) value. The RTC is using PPM.
663 	 * Here we calculate the offset when using MODE = 0.
664 	 *  Formula from the application manual:
665 	 *  Offset [ppm] = (calibration [ppb] / (4.34 [ppm] x 1000))
666 	 */
667 	offset_ppm_mode0 = calibration / 4340;
668 
669 	/* Here we calculate the offset when using MODE = 1.
670 	 *  Formula from the application manual:
671 	 *  Offset [ppm] = (calibration [ppb] / (4.069 [ppm] x 1000))
672 	 */
673 	offset_ppm_mode1 = calibration / 4069;
674 
675 	LOG_DBG("Offset Mode = 0: %i", offset_ppm_mode0);
676 	LOG_DBG("Offset Mode = 1: %i", offset_ppm_mode1);
677 
678 	test_mode0 = offset_ppm_mode0 * 4340;
679 	test_mode0 = calibration - test_mode0;
680 	test_mode1 = offset_ppm_mode1 * 4069;
681 	test_mode1 = calibration - test_mode1;
682 
683 	/* Compare the values and select the value with the smallest error. */
684 	test_mode0 = test_mode0 < 0 ? -test_mode0 : test_mode0;
685 	test_mode1 = test_mode1 < 0 ? -test_mode1 : test_mode1;
686 	if (test_mode0 > test_mode1) {
687 		LOG_DBG("Use fast mode (Mode = 1)");
688 
689 		/* Error with MODE = 1 is smaller -> Use MODE = 1. */
690 		offset = RV8263_BM_FAST_MODE | (offset_ppm_mode1 & GENMASK(7, 0));
691 	} else {
692 		LOG_DBG("Use normal mode (Mode = 0)");
693 
694 		/* Error with MODE = 0 is smaller -> Use MODE = 0. */
695 		offset = RV8263_BM_NORMAL_MODE | (offset_ppm_mode0 & GENMASK(7, 0));
696 	}
697 
698 	LOG_DBG("Set offset value: %i", (offset & RV8263C8_BM_REGISTER_OFFSET));
699 
700 	return i2c_reg_write_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_OFFSET, offset);
701 }
702 
rv8263c8_calibration_get(const struct device * dev,int32_t * calibration)703 int rv8263c8_calibration_get(const struct device *dev, int32_t *calibration)
704 {
705 	int err;
706 	int32_t temp;
707 	int8_t offset;
708 	const struct rv8263c8_config *config = dev->config;
709 
710 	if (calibration == NULL) {
711 		return -EINVAL;
712 	}
713 
714 	err = i2c_reg_read_byte_dt(&config->i2c_bus, RV8263C8_REGISTER_OFFSET, &offset);
715 	if (err) {
716 		return err;
717 	}
718 
719 	/* Convert the signed 7 bit into a signed 8 bit value. */
720 	if (offset & (0x01 << 6)) {
721 		temp = offset | (0x01 << 7);
722 	} else {
723 		temp = offset & (0x3F);
724 		temp &= ~(0x01 << 7);
725 	}
726 
727 	LOG_DBG("Read offset: %i", temp);
728 
729 	if (offset & RV8263_BM_FAST_MODE) {
730 		temp = temp * 4340L;
731 	} else {
732 		temp = temp * 4069L;
733 	}
734 
735 	*calibration = temp;
736 
737 	return 0;
738 }
739 #endif
740 
741 static const struct rtc_driver_api rv8263c8_driver_api = {
742 	.set_time = rv8263c8_time_set,
743 	.get_time = rv8263c8_time_get,
744 #if CONFIG_RTC_ALARM
745 	.alarm_get_supported_fields = rv8263c8_alarm_get_supported_fields,
746 	.alarm_set_time = rv8263c8_alarm_set_time,
747 	.alarm_get_time = rv8263c8_alarm_get_time,
748 	.alarm_is_pending = rv8263c8_alarm_is_pending,
749 	.alarm_set_callback = rv8263c8_alarm_set_callback,
750 #endif
751 #if CONFIG_RTC_UPDATE && DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
752 	.update_set_callback = rv8263_update_callback,
753 #endif
754 #ifdef CONFIG_RTC_CALIBRATION
755 	.set_calibration = rv8263c8_calibration_set,
756 	.get_calibration = rv8263c8_calibration_get,
757 #endif
758 };
759 
760 #define RV8263_DEFINE(inst)                                                                        \
761 	static struct rv8263c8_data rv8263c8_data_##inst;                                          \
762 	static const struct rv8263c8_config rv8263c8_config_##inst = {                             \
763 		.i2c_bus = I2C_DT_SPEC_INST_GET(inst),                                             \
764 		.clkout = DT_INST_ENUM_IDX(inst, clkout),                                          \
765 		IF_ENABLED(DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios),                            \
766 			   (.int_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, int_gpios, {0})))};         \
767 	DEVICE_DT_INST_DEFINE(inst, &rv8263c8_init, NULL, &rv8263c8_data_##inst,                   \
768 			      &rv8263c8_config_##inst, POST_KERNEL, CONFIG_RTC_INIT_PRIORITY,      \
769 			      &rv8263c8_driver_api);
770 
771 DT_INST_FOREACH_STATUS_OKAY(RV8263_DEFINE)
772