From 049aaac696e8ba028ff0100633c874b816c8fae7 Mon Sep 17 00:00:00 2001 From: Sri Surya Date: Fri, 4 Aug 2023 21:51:53 +0530 Subject: [PATCH] drivers: rtc: new ambiq am1805 rtc driver Added RTC driver for am1805 with rtc time, alarm set/get, callback and calibration. Signed-off-by: Sri Surya --- drivers/rtc/CMakeLists.txt | 1 + drivers/rtc/Kconfig | 1 + drivers/rtc/Kconfig.am1805 | 27 ++ drivers/rtc/rtc_am1805.c | 599 +++++++++++++++++++++++++++++ dts/bindings/rtc/ambiq,am1805.yaml | 20 + 5 files changed, 648 insertions(+) create mode 100644 drivers/rtc/Kconfig.am1805 create mode 100644 drivers/rtc/rtc_am1805.c create mode 100644 dts/bindings/rtc/ambiq,am1805.yaml diff --git a/drivers/rtc/CMakeLists.txt b/drivers/rtc/CMakeLists.txt index a770523f33b..94cda7627c4 100644 --- a/drivers/rtc/CMakeLists.txt +++ b/drivers/rtc/CMakeLists.txt @@ -5,6 +5,7 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/rtc.h) zephyr_library() +zephyr_library_sources_ifdef(CONFIG_RTC_AM1805 rtc_am1805.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE rtc_handlers.c) zephyr_library_sources_ifdef(CONFIG_RTC_EMUL rtc_emul.c) zephyr_library_sources_ifdef(CONFIG_RTC_PCF8523 rtc_pcf8523.c) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 8df08f38009..97cc21fef0e 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -41,6 +41,7 @@ config RTC_SHELL help RTC Shell commands +source "drivers/rtc/Kconfig.am1805" source "drivers/rtc/Kconfig.emul" source "drivers/rtc/Kconfig.fake" source "drivers/rtc/Kconfig.pcf8523" diff --git a/drivers/rtc/Kconfig.am1805 b/drivers/rtc/Kconfig.am1805 new file mode 100644 index 00000000000..4c7319ebd0b --- /dev/null +++ b/drivers/rtc/Kconfig.am1805 @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2023 Linumiz +# Author: Sri Surya + +config RTC_AM1805 + bool "AMBIQ AM1805 RTC driver" + default y + depends on DT_HAS_AMBIQ_AM1805_ENABLED + select I2C + help + Enable the AMBIQ AM1805 RTC driver. + +if RTC_AM1805 + +config RTC_AM1805_THREAD_STACK_SIZE + int "Stack size for the am1805 interrupt thread" + default 512 + help + Size of the stack used for the thread handling interrupts and dispatching callbacks. + +config RTC_AM1805_THREAD_PRIO + int "Priority for the am1805 interrupt thread" + default 0 + help + Priority level for the thread handling interrupts and dispatching callbacks. + +endif diff --git a/drivers/rtc/rtc_am1805.c b/drivers/rtc/rtc_am1805.c new file mode 100644 index 00000000000..b6282d0f8ae --- /dev/null +++ b/drivers/rtc/rtc_am1805.c @@ -0,0 +1,599 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Copyright (c) 2023 Linumiz + * Author: Sri Surya + */ + +#include +#include +#include +#include +#include +#include + +#define DT_DRV_COMPAT ambiq_am1805 + +LOG_MODULE_REGISTER(am1805, CONFIG_RTC_LOG_LEVEL); + +#define AM1805_IDENTITY_CODE 0x69 + +/* AM1805 register address */ +#define REG_HUNDREDS_ADDR 0x00 +#define REG_SECONDS_ADDR 0x01 +#define REG_MINUTES_ADDR 0x02 +#define REG_HOURS_ADDR 0x03 +#define REG_MDAY_ADDR 0x04 +#define REG_MONTH_ADDR 0x05 +#define REG_YEAR_ADDR 0x06 +#define REG_WDAY_ADDR 0x07 + +#define REG_ALM_HUNDREDS_ADDR 0x08 +#define REG_ALM_SECONDS_ADDR 0x09 +#define REG_ALM_MINUTES_ADDR 0x0A +#define REG_ALM_HOURS_ADDR 0x0B +#define REG_ALM_MDAY_ADDR 0x0C +#define REG_ALM_MONTH_ADDR 0x0D +#define REG_ALM_WDAY_ADDR 0x0E +#define REG_STATUS_ADDR 0x0F +#define REG_CONTROL1_ADDR 0x10 +#define REG_CONTROL2_ADDR 0x11 +#define REG_XT_CALIB_ADDR 0x14 +#define REG_TIMER_CTRL_ADDR 0x18 +#define REG_IRQ_MASK_ADDR 0x12 +#define REG_WATCHDOG_ADDR 0x1B +#define REG_OSC_STATUS_ADDR 0x1D + +/* AM1805 control bits */ +#define SECONDS_BITS GENMASK(6, 0) +#define MINUTES_BITS GENMASK(6, 0) +#define HOURS_BITS GENMASK(5, 0) +#define DATE_BITS GENMASK(5, 0) +#define MONTHS_BITS GENMASK(4, 0) +#define WEEKDAY_BITS GENMASK(2, 0) +#define YEAR_BITS GENMASK(7, 0) +#define REG_CONTROL2_OUT2S_BITS GENMASK(4, 2) +#define REG_TIMER_CTRL_RPT_BITS GENMASK(4, 2) +#define REG_XT_CALIB_OFF_MASK GENMASK(6, 0) + +#define REG_STATUS_ALM BIT(2) +#define REG_CONTROL1_STOP BIT(7) +#define REG_IRQ_MASK_AIE BIT(2) +#define REG_XT_CALIB_CMDX BIT(7) + +#define TIMER_CTRL_ALM_OFF 0x00 +#define TIMER_CTRL_ALM_DAY BIT(4) +#define TIMER_CTRL_ALM_YEAR BIT(2) +#define TIMER_CTRL_ALM_HR (BIT(2) | BIT(4)) +#define TIMER_CTRL_ALM_SEC GENMASK(4, 2) +#define TIMER_CTRL_ALM_MIN GENMASK(4, 3) +#define TIMER_CTRL_ALM_WEEK GENMASK(3, 2) + +#define REG_WATCHDOG_WDS BIT(7) +#define WRB_1_SECOND BIT(1) +#define WRB_4_SECONDS GENMASK(1, 0) + +#define REG_OSC_STATUS_ACAL_0 0x00 +#define REG_OSC_STATUS_ACAL_1 BIT(6) +#define REG_OSC_STATUS_ACAL_2 BIT(7) +#define REG_OSC_STATUS_ACAL_3 GENMASK(7, 6) +#define REG_OSC_STATUS_MASK BIT(1) +#define REG_STATUS_DEFAULT 0x00 + +#define AM1805_RTC_ALARM_TIME_MASK \ + (RTC_ALARM_TIME_MASK_SECOND | RTC_ALARM_TIME_MASK_MINUTE | RTC_ALARM_TIME_MASK_HOUR | \ + RTC_ALARM_TIME_MASK_MONTHDAY | RTC_ALARM_TIME_MASK_MONTH | RTC_ALARM_TIME_MASK_WEEKDAY) + +#ifdef CONFIG_RTC_ALARM +/* am1805-gpios property must be in the devicetree inorder to use the RTC_ALARM */ +#if !DT_ANY_INST_HAS_PROP_STATUS_OKAY(am1805_gpios) +#error "am1805-gpios" - property not available in devicetree. +#endif +#endif + +struct am1805_config { + const struct i2c_dt_spec int_i2c; +#ifdef CONFIG_RTC_ALARM + struct gpio_dt_spec int_gpio; +#endif +}; + +struct am1805_data { + struct k_mutex lock; +#ifdef CONFIG_RTC_ALARM + rtc_alarm_callback alarm_user_callback; + void *alarm_user_data; + /* For gpio-interrupt */ + struct gpio_callback am1805_callback; + struct k_thread am1805_thread; + struct k_sem int_sem; + + K_KERNEL_STACK_MEMBER(am1805_stack, CONFIG_RTC_AM1805_THREAD_STACK_SIZE); +#endif +}; + +/* To set the timer registers */ +static int am1805_set_time(const struct device *dev, const struct rtc_time *tm) +{ + int err; + uint8_t regs[7]; + + struct am1805_data *data = dev->data; + const struct am1805_config *config = dev->config; + + k_mutex_lock(&data->lock, K_FOREVER); + + /* To unlock Stop-bit */ + err = i2c_reg_update_byte_dt(&config->int_i2c, REG_CONTROL1_ADDR, + REG_CONTROL1_STOP, REG_CONTROL1_STOP); + if (err != 0) { + goto unlock; + } + + LOG_DBG("set time: year = %d, mon = %d, mday = %d, wday = %d, hour = %d, " + "min = %d, sec = %d", + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, tm->tm_hour, tm->tm_min, + tm->tm_sec); + + regs[0] = bin2bcd(tm->tm_sec) & SECONDS_BITS; + regs[1] = bin2bcd(tm->tm_min) & MINUTES_BITS; + regs[2] = bin2bcd(tm->tm_hour) & HOURS_BITS; + regs[3] = bin2bcd(tm->tm_mday) & DATE_BITS; + regs[4] = bin2bcd(tm->tm_mon) & MONTHS_BITS; + regs[5] = bin2bcd(tm->tm_year) & YEAR_BITS; + regs[6] = bin2bcd(tm->tm_wday) & WEEKDAY_BITS; + + err = i2c_burst_write_dt(&config->int_i2c, REG_SECONDS_ADDR, regs, sizeof(regs)); + if (err != 0) { + goto unlock; + } + + /* To lock Stop-bit */ + err = i2c_reg_update_byte_dt(&config->int_i2c, REG_CONTROL1_ADDR, REG_CONTROL1_STOP, 0); + +unlock: + k_mutex_unlock(&data->lock); + + return err; +} + +/* To get from the timer registers */ +static int am1805_get_time(const struct device *dev, struct rtc_time *timeptr) +{ + int err; + uint8_t ctl_reg; + uint8_t regs[7]; + + struct am1805_data *data = dev->data; + const struct am1805_config *config = dev->config; + + k_mutex_lock(&data->lock, K_FOREVER); + + err = i2c_reg_read_byte_dt(&config->int_i2c, REG_CONTROL1_ADDR, &ctl_reg); + if (err != 0) { + goto unlock; + } + + err = ctl_reg & REG_CONTROL1_STOP; + if (err != 0) { + LOG_WRN("No control to get time now!!"); + goto unlock; + } + + err = i2c_burst_read_dt(&config->int_i2c, REG_SECONDS_ADDR, regs, sizeof(regs)); + if (err != 0) { + goto unlock; + } + + timeptr->tm_sec = bcd2bin(regs[0] & SECONDS_BITS); + timeptr->tm_min = bcd2bin(regs[1] & MINUTES_BITS); + timeptr->tm_hour = bcd2bin(regs[2] & HOURS_BITS); + timeptr->tm_mday = bcd2bin(regs[3] & DATE_BITS); + timeptr->tm_mon = bcd2bin(regs[4] & MONTHS_BITS); + timeptr->tm_year = bcd2bin(regs[5] & YEAR_BITS); + timeptr->tm_wday = bcd2bin(regs[6] & WEEKDAY_BITS); + + LOG_DBG("get time: year = %d, mon = %d, mday = %d, wday = %d, hour = %d, " + "min = %d, sec = %d", + timeptr->tm_year, timeptr->tm_mon, timeptr->tm_mday, timeptr->tm_wday, + timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec); + +unlock: + k_mutex_unlock(&data->lock); + + return err; +} + +#ifdef CONFIG_RTC_CALIBRATION +/* To Calibrate the XT oscillator */ +static int am1805_set_calibration(const struct device *dev, int32_t xt_clock_adj) +{ + int err; + uint8_t xt_calib_value; + + struct am1805_data *data = dev->data; + const struct am1805_config *config = dev->config; + uint8_t reg = REG_OSC_STATUS_MASK; + + if (xt_clock_adj < -320 || xt_clock_adj > 127) { + LOG_DBG("Cannot be calibrated adj = %d\n", xt_clock_adj); + return -EINVAL; + } else if (xt_clock_adj < -256) { + /* XTCAL=3 CMDX=1 OFFSETX=(adj+192)/2 */ + reg |= REG_OSC_STATUS_ACAL_3; + xt_calib_value = ((uint8_t)(xt_clock_adj + 192) >> 1); + xt_calib_value &= REG_XT_CALIB_OFF_MASK; + xt_calib_value |= REG_XT_CALIB_CMDX; + } else if (xt_clock_adj < -192) { + /* XTCAL=3 CMDX=0 OFFSETX=(adj+192) */ + reg |= REG_OSC_STATUS_ACAL_3; + xt_calib_value = (uint8_t)(xt_clock_adj + 192); + xt_calib_value &= REG_XT_CALIB_OFF_MASK; + } else if (xt_clock_adj < -128) { + /* XTCAL=2 CMDX=0 OFFSETX=(adj+128) */ + reg |= REG_OSC_STATUS_ACAL_2; + xt_calib_value = (uint8_t)(xt_clock_adj + 128); + xt_calib_value &= REG_XT_CALIB_OFF_MASK; + } else if (xt_clock_adj < -64) { + /* XTCAL=1 CMDX=0 OFFSETX=(adj+64) */ + reg |= REG_OSC_STATUS_ACAL_1; + xt_calib_value = (uint8_t)(xt_clock_adj + 64); + xt_calib_value &= REG_XT_CALIB_OFF_MASK; + } else if (xt_clock_adj < 64) { + /* XTCAL=0 CMDX=0 OFFSETX=(adj) */ + reg |= REG_OSC_STATUS_ACAL_0; + xt_calib_value = (uint8_t)(xt_clock_adj); + xt_calib_value &= REG_XT_CALIB_OFF_MASK; + } else if (xt_clock_adj < 128) { + /* XTCAL=0 CMDX=1 OFFSETX=(adj)/2 */ + reg |= REG_OSC_STATUS_ACAL_0; + xt_calib_value = ((uint8_t)(xt_clock_adj >> 1)); + xt_calib_value &= REG_XT_CALIB_OFF_MASK; + xt_calib_value |= REG_XT_CALIB_CMDX; + } + + k_mutex_lock(&data->lock, K_FOREVER); + + err = i2c_reg_write_byte_dt(&config->int_i2c, REG_OSC_STATUS_ADDR, reg); + if (err != 0) { + LOG_DBG("fail to set oscillator status register\n"); + goto unlock; + } + + /* Calibration XT Register */ + reg = xt_calib_value; + err = i2c_reg_write_byte_dt(&config->int_i2c, REG_XT_CALIB_ADDR, reg); + if (err != 0) { + LOG_DBG("fail to set XT calibration register\n"); + } + +unlock: + k_mutex_unlock(&data->lock); + + return err; +} + +static int am1805_get_calibration(const struct device *dev, int32_t *calib) +{ + int err; + bool cmdx; + uint8_t reg; + uint8_t xtcal; + + struct am1805_data *data = dev->data; + const struct am1805_config *config = dev->config; + + k_mutex_lock(&data->lock, K_FOREVER); + + err = i2c_reg_read_byte_dt(&config->int_i2c, REG_OSC_STATUS_ADDR, ®); + if (err != 0) { + goto unlock; + } + + /* First 2-bits (from MSB) */ + xtcal = reg >> 6; + + err = i2c_reg_read_byte_dt(&config->int_i2c, REG_XT_CALIB_ADDR, ®); + if (err != 0) { + goto unlock; + } + + *calib = reg; + /* First bit (from MSB) */ + cmdx = reg & BIT(7); + /* Set or Clear the bit-7 based on bit-6, to achieve the given range (in datasheet) */ + WRITE_BIT(reg, 7, (reg & BIT(6))); + WRITE_BIT(reg, 6, 0); + + LOG_DBG("XTCAL = %d, CMDX = %d, OFFSETX = %d\n", xtcal, cmdx, (int8_t) reg); + +unlock: + k_mutex_unlock(&data->lock); + + return err; +} +#endif + +#ifdef CONFIG_RTC_ALARM +/* To get from the alarm registers */ +static int am1805_alarm_get_time(const struct device *dev, uint16_t id, uint16_t *mask, + struct rtc_time *timeptr) +{ + + int err; + uint8_t regs[6]; + + struct am1805_data *data = dev->data; + const struct am1805_config *config = dev->config; + + if (id != 0U) { + LOG_ERR("invalid ID %d", id); + return -EINVAL; + } + + k_mutex_lock(&data->lock, K_FOREVER); + + err = i2c_burst_read_dt(&config->int_i2c, REG_ALM_SECONDS_ADDR, regs, sizeof(regs)); + if (err != 0) { + goto unlock; + } + + timeptr->tm_sec = bcd2bin(regs[0] & SECONDS_BITS); + timeptr->tm_min = bcd2bin(regs[1] & MINUTES_BITS); + timeptr->tm_hour = bcd2bin(regs[2] & HOURS_BITS); + timeptr->tm_mday = bcd2bin(regs[3] & DATE_BITS); + timeptr->tm_mon = bcd2bin(regs[4] & MONTHS_BITS); + timeptr->tm_wday = bcd2bin(regs[5] & WEEKDAY_BITS); + + *mask = (AM1805_RTC_ALARM_TIME_MASK); + + LOG_DBG("get alarm: wday = %d, mon = %d, mday = %d, hour = %d, min = %d, sec = %d, " + "mask = 0x%04x", timeptr->tm_wday, timeptr->tm_mon, timeptr->tm_mday, + timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec, *mask); + +unlock: + k_mutex_unlock(&data->lock); + + return err; +} + +static int am1805_alarm_set_time(const struct device *dev, uint16_t id, uint16_t mask, + const struct rtc_time *timeptr) +{ + int err; + uint8_t regs[6]; + + struct am1805_data *data = dev->data; + const struct am1805_config *config = dev->config; + + if (id != 0U) { + LOG_ERR("invalid ID %d", id); + return -EINVAL; + } + + if ((mask & ~(AM1805_RTC_ALARM_TIME_MASK)) != 0U) { + LOG_ERR("unsupported alarm field mask 0x%04x", mask); + return -EINVAL; + } + + k_mutex_lock(&data->lock, K_FOREVER); + + /* Disable timer control registers before the initialization */ + err = i2c_reg_update_byte_dt(&config->int_i2c, REG_TIMER_CTRL_ADDR, + REG_TIMER_CTRL_RPT_BITS, 0); + if (err != 0) { + goto unlock; + } + + /* Clear the interrupt mask for alarm */ + err = i2c_reg_update_byte_dt(&config->int_i2c, REG_IRQ_MASK_ADDR, + REG_IRQ_MASK_AIE, 0); + if (err != 0) { + goto unlock; + } + + /* Clear the status bit */ + err = i2c_reg_update_byte_dt(&config->int_i2c, REG_STATUS_ADDR, + REG_STATUS_ALM, 0); + if (err != 0) { + goto unlock; + } + + /* When mask is 0 */ + if (mask == 0) { + LOG_DBG("The alarm is disabled"); + goto unlock; + } + + regs[0] = bin2bcd(timeptr->tm_sec) & SECONDS_BITS; + regs[1] = bin2bcd(timeptr->tm_min) & MINUTES_BITS; + regs[2] = bin2bcd(timeptr->tm_hour) & HOURS_BITS; + regs[3] = bin2bcd(timeptr->tm_mday) & DATE_BITS; + regs[4] = bin2bcd(timeptr->tm_mon) & MONTHS_BITS; + regs[5] = bin2bcd(timeptr->tm_wday) & WEEKDAY_BITS; + + LOG_DBG("set alarm: second = %d, min = %d, hour = %d, mday = %d, month = %d," + "wday = %d, mask = 0x%04x", + timeptr->tm_sec, timeptr->tm_min, timeptr->tm_hour, timeptr->tm_mday, + timeptr->tm_mon, timeptr->tm_wday, mask); + + err = i2c_burst_write_dt(&config->int_i2c, REG_ALM_SECONDS_ADDR, regs, sizeof(regs)); + if (err != 0) { + goto unlock; + } + + /* Enable irq timer after the initialization */ + err = i2c_reg_update_byte_dt(&config->int_i2c, REG_IRQ_MASK_ADDR, + REG_IRQ_MASK_AIE, REG_IRQ_MASK_AIE); + if (err != 0) { + goto unlock; + } + + /* Enable timer after the initialization for the config of repetation */ + err = i2c_reg_update_byte_dt(&config->int_i2c, REG_TIMER_CTRL_ADDR, + TIMER_CTRL_ALM_SEC, TIMER_CTRL_ALM_SEC); + +unlock: + k_mutex_unlock(&data->lock); + + return err; +} + +static int am1805_alarm_get_supported_fields(const struct device *dev, uint16_t id, uint16_t *mask) +{ + ARG_UNUSED(dev); + + if (id != 0U) { + LOG_ERR("invalid ID %d", id); + return -EINVAL; + } + + *mask = AM1805_RTC_ALARM_TIME_MASK; + + return 0; +} + +static int am1805_alarm_set_callback(const struct device *dev, uint16_t id, + rtc_alarm_callback callback, void *user_data) +{ + + struct am1805_data *data = dev->data; + const struct am1805_config *config = dev->config; + + if (config->int_gpio.port == NULL) { + return -ENOTSUP; + } + + if (id != 0U) { + LOG_ERR("invalid ID %d", id); + return -EINVAL; + } + + k_mutex_lock(&data->lock, K_FOREVER); + + /* Passing the callback function and userdata filled by the user */ + data->alarm_user_callback = callback; + data->alarm_user_data = user_data; + + k_mutex_unlock(&data->lock); + + return 0; +} + +static void am1805_interrupt_thread(const struct device *dev) +{ + struct am1805_data *data = dev->data; + + while (1) { + k_sem_take(&data->int_sem, K_FOREVER); + + if (data->alarm_user_callback == NULL) { + LOG_DBG("Interrupt received, But No Alarm-Callback Initilized!!\n"); + continue; + } + data->alarm_user_callback(dev, 0, data->alarm_user_data); + } +} + +static void am1805_gpio_callback_handler(const struct device *port, struct gpio_callback *cb, + gpio_port_pins_t pins) +{ + struct am1805_data *data = CONTAINER_OF(cb, struct am1805_data, am1805_callback); + + ARG_UNUSED(port); + ARG_UNUSED(pins); + + k_sem_give(&data->int_sem); +} +#endif + +static int am1805_init(const struct device *dev) +{ + int err; + uint8_t reg; + + const struct am1805_config *config = dev->config; + struct am1805_data *data = dev->data; + + k_mutex_init(&data->lock); + + if (!i2c_is_ready_dt(&config->int_i2c)) { + LOG_ERR("I2C bus not ready"); + return -ENODEV; + } + + err = i2c_reg_read_byte_dt(&config->int_i2c, REG_STATUS_ADDR, ®); + if (err != 0) { + LOG_ERR("failed to read the status register"); + return -ENODEV; + } + +#ifdef CONFIG_RTC_ALARM + k_tid_t tid; + + k_sem_init(&data->int_sem, 0, INT_MAX); + + if (!gpio_is_ready_dt(&config->int_gpio)) { + LOG_ERR("GPIO not ready"); + return -ENODEV; + } + + err = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT); + if (err != 0) { + LOG_ERR("failed to configure GPIO (err %d)", err); + return -ENODEV; + } + + err = gpio_pin_interrupt_configure_dt(&config->int_gpio, + GPIO_INT_EDGE_TO_INACTIVE); + if (err != 0) { + LOG_ERR("failed to configure interrupt (err %d)", err); + return -ENODEV; + } + + gpio_init_callback(&data->am1805_callback, am1805_gpio_callback_handler, + BIT(config->int_gpio.pin)); + + err = gpio_add_callback_dt(&config->int_gpio, &data->am1805_callback); + if (err != 0) { + LOG_ERR("failed to add GPIO callback (err %d)", err); + return -ENODEV; + } + + tid = k_thread_create(&data->am1805_thread, data->am1805_stack, + K_THREAD_STACK_SIZEOF(data->am1805_stack), + (k_thread_entry_t)am1805_interrupt_thread, (void *)dev, NULL, + NULL, CONFIG_RTC_AM1805_THREAD_PRIO, 0, K_NO_WAIT); + k_thread_name_set(tid, dev->name); +#endif + return 0; +} + +static const struct rtc_driver_api am1805_driver_api = { + .set_time = am1805_set_time, + .get_time = am1805_get_time, +#ifdef CONFIG_RTC_ALARM + .alarm_get_supported_fields = am1805_alarm_get_supported_fields, + .alarm_set_time = am1805_alarm_set_time, + .alarm_get_time = am1805_alarm_get_time, + .alarm_set_callback = am1805_alarm_set_callback, +#endif +#ifdef CONFIG_RTC_CALIBRATION + .set_calibration = am1805_set_calibration, + .get_calibration = am1805_get_calibration, +#endif +}; + +#define AM1805_INIT(inst) \ +static const struct am1805_config am1805_config_##inst = { \ + .int_i2c = I2C_DT_SPEC_INST_GET(inst), \ + IF_ENABLED(CONFIG_RTC_ALARM, \ + (.int_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, am1805_gpios, {0})))}; \ + \ +static struct am1805_data am1805_data_##inst; \ + \ +DEVICE_DT_INST_DEFINE(inst, &am1805_init, NULL, &am1805_data_##inst, \ + &am1805_config_##inst, POST_KERNEL, CONFIG_RTC_INIT_PRIORITY, \ + &am1805_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(AM1805_INIT) diff --git a/dts/bindings/rtc/ambiq,am1805.yaml b/dts/bindings/rtc/ambiq,am1805.yaml new file mode 100644 index 00000000000..be807778f2c --- /dev/null +++ b/dts/bindings/rtc/ambiq,am1805.yaml @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2023 Linumiz +# Author: Sri Surya + +description: AMBIQ AM1805 RTC + +compatible: "ambiq,am1805" + +include: + - name: rtc-device.yaml + - name: i2c-device.yaml + +properties: + reg: + required: true + + am1805-gpios: + type: phandle-array + description: | + GPIO connected to the AM1805 INT1 interrupt output. This signal is open-drain, active low.