/* * SPDX-License-Identifier: Apache-2.0 * * Copyright (c) 2024 Gergo Vari */ /* TODO: implement user mode? */ /* TODO: implement aging offset with calibration */ /* TODO: handle century bit, external storage? */ #include #include #include #include #include #include LOG_MODULE_REGISTER(RTC_DS3231, CONFIG_RTC_LOG_LEVEL); #include #define DT_DRV_COMPAT maxim_ds3231_rtc #ifdef CONFIG_RTC_ALARM #define ALARM_COUNT 2 struct rtc_ds3231_alarm { rtc_alarm_callback cb; void *user_data; }; #endif #ifdef CONFIG_RTC_UPDATE struct rtc_ds3231_update { rtc_update_callback cb; void *user_data; }; #endif struct rtc_ds3231_data { #ifdef CONFIG_RTC_ALARM struct rtc_ds3231_alarm alarms[ALARM_COUNT]; #endif #ifdef CONFIG_RTC_UPDATE struct rtc_ds3231_update update; #endif struct k_sem lock; struct gpio_callback isw_cb_data; struct k_work work; const struct device *dev; }; struct rtc_ds3231_conf { const struct device *mfd; struct gpio_dt_spec freq_32k_gpios; struct gpio_dt_spec isw_gpios; }; static int rtc_ds3231_modify_register(const struct device *dev, uint8_t reg, uint8_t *buf, const uint8_t bitmask) { int err; const struct rtc_ds3231_conf *config = dev->config; if (bitmask != 255) { uint8_t og_buf = 0; err = mfd_ds3231_i2c_get_registers(config->mfd, reg, &og_buf, 1); if (err != 0) { return err; } og_buf &= ~bitmask; *buf &= bitmask; og_buf |= *buf; *buf = og_buf; } if (err != 0) { return err; } err = mfd_ds3231_i2c_set_registers(config->mfd, reg, buf, 1); return err; } enum rtc_ds3231_freq { FREQ_1000, FREQ_1024, FREQ_4096, FREQ_8192 }; struct rtc_ds3231_ctrl { bool en_osc; bool conv; enum rtc_ds3231_freq sqw_freq; bool intctrl; bool en_alarm_1; bool en_alarm_2; }; static int rtc_ds3231_ctrl_to_buf(const struct rtc_ds3231_ctrl *ctrl, uint8_t *buf) { if (ctrl->en_alarm_1) { *buf |= DS3231_BITS_CTRL_ALARM_1_EN; } if (ctrl->en_alarm_2) { *buf |= DS3231_BITS_CTRL_ALARM_2_EN; } switch (ctrl->sqw_freq) { case FREQ_1000: break; case FREQ_1024: *buf |= DS3231_BITS_CTRL_RS1; break; case FREQ_4096: *buf |= DS3231_BITS_CTRL_RS2; break; case FREQ_8192: *buf |= DS3231_BITS_CTRL_RS1; *buf |= DS3231_BITS_CTRL_RS2; break; } if (ctrl->intctrl) { *buf |= DS3231_BITS_CTRL_INTCTRL; } else { /* enable sqw */ *buf |= DS3231_BITS_CTRL_BBSQW; } if (ctrl->conv) { *buf |= DS3231_BITS_CTRL_CONV; } if (!ctrl->en_osc) { /* active low */ *buf |= DS3231_BITS_CTRL_EOSC; } return 0; } static int rtc_ds3231_modify_ctrl(const struct device *dev, const struct rtc_ds3231_ctrl *ctrl, const uint8_t bitmask) { uint8_t reg = DS3231_REG_CTRL; uint8_t buf = 0; int err = rtc_ds3231_ctrl_to_buf(ctrl, &buf); if (err != 0) { return err; } return rtc_ds3231_modify_register(dev, reg, &buf, bitmask); } struct rtc_ds3231_ctrl_sts { bool osf; bool en_32khz; bool bsy; bool a1f; bool a2f; }; static int rtc_ds3231_ctrl_sts_to_buf(const struct rtc_ds3231_ctrl_sts *ctrl, uint8_t *buf) { if (ctrl->a1f) { *buf |= DS3231_BITS_CTRL_STS_ALARM_1_FLAG; } if (ctrl->a2f) { *buf |= DS3231_BITS_CTRL_STS_ALARM_2_FLAG; } if (ctrl->osf) { *buf |= DS3231_BITS_CTRL_STS_OSF; } if (ctrl->en_32khz) { *buf |= DS3231_BITS_CTRL_STS_32_EN; } if (ctrl->bsy) { *buf |= DS3231_BITS_CTRL_STS_BSY; } return 0; } static int rtc_ds3231_modify_ctrl_sts(const struct device *dev, const struct rtc_ds3231_ctrl_sts *ctrl, const uint8_t bitmask) { const uint8_t reg = DS3231_REG_CTRL_STS; uint8_t buf = 0; int err = rtc_ds3231_ctrl_sts_to_buf(ctrl, &buf); if (err != 0) { return err; } return rtc_ds3231_modify_register(dev, reg, &buf, bitmask); } #ifdef CONFIG_RTC_ALARM static int rtc_ds3231_get_ctrl_sts(const struct device *dev, uint8_t *buf) { const struct rtc_ds3231_conf *config = dev->config; return mfd_ds3231_i2c_get_registers(config->mfd, DS3231_REG_CTRL_STS, buf, 1); } #endif /* CONFIG_RTC_ALARM */ struct rtc_ds3231_settings { bool osc; /* bit 0 */ bool intctrl_or_sqw; /* bit 1 */ enum rtc_ds3231_freq freq_sqw; /* bit 2 */ bool freq_32khz; /* bit 3 */ bool alarm_1; /* bit 4 */ bool alarm_2; /* bit 5 */ }; static int rtc_ds3231_modify_settings(const struct device *dev, struct rtc_ds3231_settings *conf, uint8_t mask) { struct rtc_ds3231_ctrl ctrl = {}; uint8_t ctrl_mask = 0; struct rtc_ds3231_ctrl_sts ctrl_sts = {}; uint8_t ctrl_sts_mask = 0; if (mask & DS3231_BITS_STS_OSC) { ctrl.en_osc = conf->osc; ctrl_mask |= DS3231_BITS_CTRL_EOSC; } if (mask & DS3231_BITS_STS_INTCTRL) { ctrl.intctrl = !conf->intctrl_or_sqw; ctrl_mask |= DS3231_BITS_CTRL_BBSQW; } if (mask & DS3231_BITS_STS_SQW) { ctrl.sqw_freq = conf->freq_sqw; ctrl_mask |= DS3231_BITS_CTRL_RS1; ctrl_mask |= DS3231_BITS_CTRL_RS2; } if (mask & DS3231_BITS_STS_32KHZ) { ctrl_sts.en_32khz = conf->freq_32khz; ctrl_sts_mask |= DS3231_BITS_CTRL_STS_32_EN; } if (mask & DS3231_BITS_STS_ALARM_1) { ctrl.en_alarm_1 = conf->alarm_1; ctrl_mask |= DS3231_BITS_CTRL_ALARM_1_EN; } if (mask & DS3231_BITS_STS_ALARM_2) { ctrl.en_alarm_2 = conf->alarm_2; ctrl_mask |= DS3231_BITS_CTRL_ALARM_2_EN; } ctrl.conv = false; int err = rtc_ds3231_modify_ctrl(dev, &ctrl, ctrl_mask); if (err != 0) { LOG_ERR("Couldn't set control register."); return -EIO; } err = rtc_ds3231_modify_ctrl_sts(dev, &ctrl_sts, ctrl_sts_mask); if (err != 0) { LOG_ERR("Couldn't set status register."); return -EIO; } return 0; } static int rtc_ds3231_rtc_time_to_buf(const struct rtc_time *tm, uint8_t *buf) { buf[0] = bin2bcd(tm->tm_sec) & DS3231_BITS_TIME_SECONDS; buf[1] = bin2bcd(tm->tm_min) & DS3231_BITS_TIME_MINUTES; buf[2] = bin2bcd(tm->tm_hour) & DS3231_BITS_TIME_HOURS; buf[3] = bin2bcd(tm->tm_wday) & DS3231_BITS_TIME_DAY_OF_WEEK; buf[4] = bin2bcd(tm->tm_mday) & DS3231_BITS_TIME_DATE; buf[5] = bin2bcd(tm->tm_mon) & DS3231_BITS_TIME_MONTH; /* here modulo 100 returns the last two digits of the year, * as the DS3231 chip can only store year data for 0-99, * hitting that ceiling can be detected with the century bit. */ /* TODO: figure out a way to store the WHOLE year, not just the last 2 digits. */ buf[6] = bin2bcd((tm->tm_year % 100)) & DS3231_BITS_TIME_YEAR; return 0; } static int rtc_ds3231_set_time(const struct device *dev, const struct rtc_time *tm) { const struct rtc_ds3231_conf *config = dev->config; int buf_size = 7; uint8_t buf[buf_size]; int err = rtc_ds3231_rtc_time_to_buf(tm, buf); if (err != 0) { return err; } return mfd_ds3231_i2c_set_registers(config->mfd, DS3231_REG_TIME_SECONDS, buf, buf_size); } static void rtc_ds3231_reset_rtc_time(struct rtc_time *tm) { tm->tm_sec = 0; tm->tm_min = 0; tm->tm_hour = 0; tm->tm_wday = 0; tm->tm_mday = 0; tm->tm_mon = 0; tm->tm_year = 0; tm->tm_nsec = 0; tm->tm_isdst = -1; tm->tm_yday = -1; } static int rtc_ds3231_buf_to_rtc_time(const uint8_t *buf, struct rtc_time *timeptr) { rtc_ds3231_reset_rtc_time(timeptr); timeptr->tm_sec = bcd2bin(buf[0] & DS3231_BITS_TIME_SECONDS); timeptr->tm_min = bcd2bin(buf[1] & DS3231_BITS_TIME_MINUTES); int hour = buf[2] & DS3231_BITS_TIME_HOURS; if (hour & DS3231_BITS_TIME_12HR) { bool pm = hour & DS3231_BITS_TIME_PM; hour &= ~DS3231_BITS_TIME_12HR; hour &= ~DS3231_BITS_TIME_PM; timeptr->tm_hour = bcd2bin(hour + 12 * pm); } else { timeptr->tm_hour = bcd2bin(hour); } timeptr->tm_wday = bcd2bin(buf[3] & DS3231_BITS_TIME_DAY_OF_WEEK); timeptr->tm_mday = bcd2bin(buf[4] & DS3231_BITS_TIME_DATE); timeptr->tm_mon = bcd2bin(buf[5] & DS3231_BITS_TIME_MONTH); timeptr->tm_year = bcd2bin(buf[6] & DS3231_BITS_TIME_YEAR); /* FIXME: we will always just set us to 20xx for year */ timeptr->tm_year = timeptr->tm_year + 100; return 0; } static int rtc_ds3231_get_time(const struct device *dev, struct rtc_time *timeptr) { const struct rtc_ds3231_conf *config = dev->config; const size_t buf_size = 7; uint8_t buf[buf_size]; int err = mfd_ds3231_i2c_get_registers(config->mfd, DS3231_REG_TIME_SECONDS, buf, buf_size); if (err != 0) { return err; } return rtc_ds3231_buf_to_rtc_time(buf, timeptr); } #ifdef CONFIG_RTC_ALARM struct rtc_ds3231_alarm_details { uint8_t start_reg; size_t buf_size; }; static struct rtc_ds3231_alarm_details alarms[] = {{DS3231_REG_ALARM_1_SECONDS, 4}, {DS3231_REG_ALARM_2_MINUTES, 3}}; static int rtc_ds3231_alarm_get_supported_fields(const struct device *dev, uint16_t id, uint16_t *mask) { *mask = RTC_ALARM_TIME_MASK_MONTHDAY | RTC_ALARM_TIME_MASK_WEEKDAY | RTC_ALARM_TIME_MASK_HOUR | RTC_ALARM_TIME_MASK_MINUTE; switch (id) { case 0: *mask |= RTC_ALARM_TIME_MASK_SECOND; break; case 1: break; default: return -EINVAL; } return 0; } static int rtc_ds3231_rtc_time_to_alarm_buf(const struct rtc_time *tm, int id, const uint16_t mask, uint8_t *buf) { if ((mask & RTC_ALARM_TIME_MASK_WEEKDAY) && (mask & RTC_ALARM_TIME_MASK_MONTHDAY)) { LOG_ERR("rtc_time_to_alarm_buf: Mask is invalid (%d)!\n", mask); return -EINVAL; } if (id < 0 || id >= ALARM_COUNT) { LOG_ERR("rtc_time_to_alarm_buf: Alarm ID is out of range (%d)!\n", id); return -EINVAL; } if (mask & RTC_ALARM_TIME_MASK_MINUTE) { buf[1] = bin2bcd(tm->tm_min) & DS3231_BITS_TIME_MINUTES; } else { buf[1] |= DS3231_BITS_ALARM_RATE; } if (mask & RTC_ALARM_TIME_MASK_HOUR) { buf[2] = bin2bcd(tm->tm_hour) & DS3231_BITS_TIME_HOURS; } else { buf[2] |= DS3231_BITS_ALARM_RATE; } if (mask & RTC_ALARM_TIME_MASK_WEEKDAY) { buf[3] = bin2bcd(tm->tm_wday) & DS3231_BITS_TIME_DAY_OF_WEEK; buf[3] |= DS3231_BITS_ALARM_DATE_W_OR_M; } else if (mask & RTC_ALARM_TIME_MASK_MONTHDAY) { buf[3] = bin2bcd(tm->tm_mday) & DS3231_BITS_TIME_DATE; } else { buf[3] |= DS3231_BITS_ALARM_RATE; } switch (id) { case 0: if (mask & RTC_ALARM_TIME_MASK_SECOND) { buf[0] = bin2bcd(tm->tm_sec) & DS3231_BITS_TIME_SECONDS; } else { buf[0] |= DS3231_BITS_ALARM_RATE; } break; case 1: if (mask & RTC_ALARM_TIME_MASK_SECOND) { return -EINVAL; } for (int i = 0; i < 3; i++) { buf[i] = buf[i + 1]; } break; default: return -EINVAL; } return 0; } static int rtc_ds3231_modify_alarm_time(const struct device *dev, int id, const struct rtc_time *tm, const uint8_t mask) { const struct rtc_ds3231_conf *config = dev->config; if (id >= ALARM_COUNT) { return -EINVAL; } struct rtc_ds3231_alarm_details details = alarms[id]; uint8_t start_reg = details.start_reg; size_t buf_size = details.buf_size; uint8_t buf[buf_size]; int err = rtc_ds3231_rtc_time_to_alarm_buf(tm, id, mask, buf); if (err != 0) { return err; } return mfd_ds3231_i2c_set_registers(config->mfd, start_reg, buf, buf_size); } static int rtc_ds3231_modify_alarm_state(const struct device *dev, uint16_t id, bool state) { struct rtc_ds3231_settings conf; uint8_t mask = 0; switch (id) { case 0: conf.alarm_1 = state; mask = DS3231_BITS_STS_ALARM_1; break; case 1: conf.alarm_2 = state; mask = DS3231_BITS_STS_ALARM_2; break; default: return -EINVAL; } return rtc_ds3231_modify_settings(dev, &conf, mask); } static int rtc_ds3231_alarm_set_time(const struct device *dev, uint16_t id, uint16_t mask, const struct rtc_time *timeptr) { if (mask == 0) { return rtc_ds3231_modify_alarm_state(dev, id, false); } int err = rtc_ds3231_modify_alarm_state(dev, id, true); if (err != 0) { return err; } return rtc_ds3231_modify_alarm_time(dev, id, timeptr, mask); } static int rtc_ds3231_alarm_buf_to_rtc_time(uint8_t *buf, int id, struct rtc_time *tm, uint16_t *mask) { rtc_ds3231_reset_rtc_time(tm); if (id < 0 || id > 1) { return -EINVAL; } else if (id == 1) { /* shift to the right to match original func */ for (int i = 3; i > 0; i--) { buf[i] = buf[i - 1]; } buf[0] = 0; } *mask = 0; if (!(buf[1] & DS3231_BITS_ALARM_RATE)) { tm->tm_min = bcd2bin(buf[1] & DS3231_BITS_TIME_MINUTES); *mask |= RTC_ALARM_TIME_MASK_MINUTE; } if (!(buf[2] & DS3231_BITS_ALARM_RATE)) { tm->tm_hour = bcd2bin(buf[2] & DS3231_BITS_TIME_HOURS); *mask |= RTC_ALARM_TIME_MASK_HOUR; } if (!(buf[3] & DS3231_BITS_ALARM_RATE)) { if (buf[3] & DS3231_BITS_ALARM_DATE_W_OR_M) { tm->tm_wday = bcd2bin(buf[3] & DS3231_BITS_TIME_DAY_OF_WEEK); *mask |= RTC_ALARM_TIME_MASK_WEEKDAY; } else { tm->tm_mday = bcd2bin(buf[3] & DS3231_BITS_TIME_DATE); *mask |= RTC_ALARM_TIME_MASK_MONTHDAY; } } if (!(buf[0] & DS3231_BITS_ALARM_RATE)) { tm->tm_sec = bcd2bin(buf[0] & DS3231_BITS_TIME_SECONDS); *mask |= RTC_ALARM_TIME_MASK_SECOND; } if ((*mask & RTC_ALARM_TIME_MASK_WEEKDAY) && (*mask & RTC_ALARM_TIME_MASK_MONTHDAY)) { return -EINVAL; } return 0; } static int rtc_ds3231_alarm_get_time(const struct device *dev, uint16_t id, uint16_t *mask, struct rtc_time *timeptr) { const struct rtc_ds3231_conf *config = dev->config; if (id >= ALARM_COUNT) { return -EINVAL; } struct rtc_ds3231_alarm_details details = alarms[id]; uint8_t start_reg = details.start_reg; size_t buf_size = details.buf_size; uint8_t buf[4]; int err = mfd_ds3231_i2c_get_registers(config->mfd, start_reg, buf, buf_size); if (err != 0) { return err; } return rtc_ds3231_alarm_buf_to_rtc_time(buf, id, timeptr, mask); } static int rtc_ds3231_alarm_is_pending(const struct device *dev, uint16_t id) { uint8_t buf; int err = rtc_ds3231_get_ctrl_sts(dev, &buf); if (err != 0) { return err; } uint8_t mask = 0; switch (id) { case 0: mask |= DS3231_BITS_CTRL_STS_ALARM_1_FLAG; break; case 1: mask |= DS3231_BITS_CTRL_STS_ALARM_2_FLAG; break; default: return -EINVAL; } bool state = buf & mask; if (state) { const struct rtc_ds3231_ctrl_sts ctrl = {.a1f = false, .a2f = false}; err = rtc_ds3231_modify_ctrl_sts(dev, &ctrl, mask); if (err != 0) { return err; } } return state; } static int rtc_ds3231_get_alarm_states(const struct device *dev, bool *states) { int err = 0; for (int i = 0; i < ALARM_COUNT; i++) { states[i] = rtc_ds3231_alarm_is_pending(dev, i); if (!(states[i] == 0 || states[i] == 1)) { states[i] = -EINVAL; err = -EINVAL; } } return err; } static int rtc_ds3231_alarm_set_callback(const struct device *dev, uint16_t id, rtc_alarm_callback cb, void *user_data) { if (id < 0 || id >= ALARM_COUNT) { return -EINVAL; } struct rtc_ds3231_data *data = dev->data; data->alarms[id] = (struct rtc_ds3231_alarm){cb, user_data}; return 0; } static void rtc_ds3231_check_alarms(const struct device *dev) { struct rtc_ds3231_data *data = dev->data; bool states[2]; rtc_ds3231_get_alarm_states(dev, states); for (int i = 0; i < ALARM_COUNT; i++) { if (states[i]) { if (data->alarms[i].cb) { data->alarms[i].cb(dev, i, data->alarms[i].user_data); } } } } static int rtc_ds3231_init_alarms(struct rtc_ds3231_data *data) { data->alarms[0] = (struct rtc_ds3231_alarm){NULL, NULL}; data->alarms[1] = (struct rtc_ds3231_alarm){NULL, NULL}; return 0; } #endif /* CONFIG_RTC_ALARM */ #ifdef CONFIG_RTC_UPDATE static int rtc_ds3231_init_update(struct rtc_ds3231_data *data) { data->update = (struct rtc_ds3231_update){NULL, NULL}; return 0; } static int rtc_ds3231_update_set_callback(const struct device *dev, rtc_update_callback cb, void *user_data) { struct rtc_ds3231_data *data = dev->data; data->update = (struct rtc_ds3231_update){cb, user_data}; return 0; } static void rtc_ds3231_update_callback(const struct device *dev) { struct rtc_ds3231_data *data = dev->data; if (data->update.cb) { data->update.cb(dev, data->update.user_data); } } #endif /* CONFIG_RTC_UPDATE */ #if defined(CONFIG_RTC_UPDATE) || defined(CONFIG_RTC_ALARM) static void rtc_ds3231_isw_h(struct k_work *work) { struct rtc_ds3231_data *data = CONTAINER_OF(work, struct rtc_ds3231_data, work); const struct device *dev = data->dev; #ifdef CONFIG_RTC_UPDATE rtc_ds3231_update_callback(dev); #endif /* CONFIG_RTC_UPDATE */ #ifdef CONFIG_RTC_ALARM rtc_ds3231_check_alarms(dev); #endif /* CONFIG_RTC_ALARM */ } static void rtc_ds3231_isw_isr(const struct device *port, struct gpio_callback *cb, uint32_t pins) { struct rtc_ds3231_data *data = CONTAINER_OF(cb, struct rtc_ds3231_data, isw_cb_data); k_work_submit(&data->work); } static int rtc_ds3231_init_isw(const struct rtc_ds3231_conf *config, struct rtc_ds3231_data *data) { if (!gpio_is_ready_dt(&config->isw_gpios)) { LOG_ERR("ISW GPIO pin is not ready."); return -ENODEV; } k_work_init(&data->work, rtc_ds3231_isw_h); int err = gpio_pin_configure_dt(&(config->isw_gpios), GPIO_INPUT); if (err != 0) { LOG_ERR("Couldn't configure ISW GPIO pin."); return err; } err = gpio_pin_interrupt_configure_dt(&(config->isw_gpios), GPIO_INT_EDGE_TO_ACTIVE); if (err != 0) { LOG_ERR("Couldn't configure ISW interrupt."); return err; } gpio_init_callback(&data->isw_cb_data, rtc_ds3231_isw_isr, BIT((config->isw_gpios).pin)); err = gpio_add_callback((config->isw_gpios).port, &data->isw_cb_data); if (err != 0) { LOG_ERR("Couldn't add ISW interrupt callback."); return err; } return 0; } #endif /* defined(CONFIG_RTC_UPDATE) || defined(CONFIG_RTC_ALARM) */ static DEVICE_API(rtc, driver_api) = { .set_time = rtc_ds3231_set_time, .get_time = rtc_ds3231_get_time, #ifdef CONFIG_RTC_ALARM .alarm_get_supported_fields = rtc_ds3231_alarm_get_supported_fields, .alarm_set_time = rtc_ds3231_alarm_set_time, .alarm_get_time = rtc_ds3231_alarm_get_time, .alarm_is_pending = rtc_ds3231_alarm_is_pending, .alarm_set_callback = rtc_ds3231_alarm_set_callback, #endif /* CONFIG_RTC_ALARM */ #ifdef CONFIG_RTC_UPDATE .update_set_callback = rtc_ds3231_update_set_callback, #endif /* CONFIG_RTC_UPDATE */ #ifdef CONFIG_RTC_CALIBRATION /*.set_calibration = set_calibration, * .get_calibration = get_calibration, */ #endif /* CONFIG_RTC_CALIBRATION */ }; static int rtc_ds3231_init_settings(const struct device *dev, const struct rtc_ds3231_conf *config) { struct rtc_ds3231_settings conf = { .osc = true, #ifdef CONFIG_RTC_UPDATE .intctrl_or_sqw = false, .freq_sqw = FREQ_1000, #else .intctrl_or_sqw = true, #endif .freq_32khz = config->freq_32k_gpios.port, }; uint8_t mask = 255 & ~DS3231_BITS_STS_ALARM_1 & ~DS3231_BITS_STS_ALARM_2; int err = rtc_ds3231_modify_settings(dev, &conf, mask); if (err != 0) { return err; } return 0; } #ifdef CONFIG_PM_DEVICE static int rtc_ds3231_pm_action(const struct device *dev, enum pm_device_action action) { int err = 0; switch (action) { case PM_DEVICE_ACTION_SUSPEND: { struct rtc_ds3231_settings conf = {.osc = true, .intctrl_or_sqw = false, .freq_sqw = FREQ_1000, .freq_32khz = false}; uint8_t mask = 255 & ~DS3231_BITS_STS_ALARM_1 & ~DS3231_BITS_STS_ALARM_2; err = rtc_ds3231_modify_settings(dev, &conf, mask); if (err != 0) { return err; } break; } case PM_DEVICE_ACTION_RESUME: { /* TODO: trigger a temp CONV */ const struct rtc_ds3231_conf *config = dev->config; err = rtc_ds3231_init_settings(dev, config); if (err != 0) { return err; } break; } default: return -ENOTSUP; } return 0; } #endif /* CONFIG_PM_DEVICE */ static int rtc_ds3231_init(const struct device *dev) { int err = 0; const struct rtc_ds3231_conf *config = dev->config; struct rtc_ds3231_data __maybe_unused *data = dev->data; if (!device_is_ready(config->mfd)) { return -ENODEV; } #ifdef CONFIG_RTC_ALARM err = rtc_ds3231_init_alarms(data); if (err != 0) { LOG_ERR("Failed to init alarms."); return err; } #endif #ifdef CONFIG_RTC_UPDATE err = rtc_ds3231_init_update(data); if (err != 0) { LOG_ERR("Failed to init update callback."); return err; } #endif err = rtc_ds3231_init_settings(dev, config); if (err != 0) { LOG_ERR("Failed to init settings."); return err; } #if defined(CONFIG_RTC_UPDATE) || defined(CONFIG_RTC_ALARM) data->dev = dev; err = rtc_ds3231_init_isw(config, data); if (err != 0) { LOG_ERR("Initing ISW interrupt failed!"); return err; } #endif /* defined(CONFIG_RTC_UPDATE) || defined(CONFIG_RTC_ALARM) */ return 0; } #define RTC_DS3231_DEFINE(inst) \ static struct rtc_ds3231_data rtc_ds3231_data_##inst; \ static const struct rtc_ds3231_conf rtc_ds3231_conf_##inst = { \ .mfd = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ .isw_gpios = GPIO_DT_SPEC_INST_GET(inst, isw_gpios), \ .freq_32k_gpios = GPIO_DT_SPEC_INST_GET_OR(inst, freq_32khz_gpios, {NULL})}; \ PM_DEVICE_DT_INST_DEFINE(inst, rtc_ds3231_pm_action); \ DEVICE_DT_INST_DEFINE(inst, &rtc_ds3231_init, PM_DEVICE_DT_INST_GET(inst), \ &rtc_ds3231_data_##inst, &rtc_ds3231_conf_##inst, POST_KERNEL, \ CONFIG_RTC_DS3231_INIT_PRIORITY, &driver_api); DT_INST_FOREACH_STATUS_OKAY(RTC_DS3231_DEFINE)