From 7b494d3c5eac309809eb5f12b08c5464bed44bd2 Mon Sep 17 00:00:00 2001 From: Anisetti Avinash Krishna Date: Thu, 20 Apr 2023 17:46:31 +0530 Subject: [PATCH] drivers: rtc: rtc_mc146818: Added RTC driver for Motorola MC146818B Added RTC driver that supports Motorola MC146818B Enabled RTC set/get time and alarm, alarm callback and update callback. Counter and RTC uses same hardware in case of Motorola MC146818, so they can't be used at a time. Updated stand-alone mc146818 counter dts instances to support rtc and counter with same compatible string of "motorola,mc146818" on ia32, atom, apollo_lake, elhart_lake and raptor_lake platforms. Signed-off-by: Anisetti Avinash Krishna --- boards/x86/ehl_crb/ehl_crb.dts | 4 + boards/x86/ehl_crb/ehl_crb.yaml | 1 + boards/x86/qemu_x86/qemu_x86.dts | 1 + boards/x86/rpl_crb/rpl_crb.dts | 1 + boards/x86/rpl_crb/rpl_crb.yaml | 1 + drivers/counter/Kconfig.cmos | 2 +- drivers/rtc/CMakeLists.txt | 1 + drivers/rtc/Kconfig | 1 + drivers/rtc/Kconfig.mc146818 | 9 + drivers/rtc/rtc_mc146818.c | 592 ++++++++++++++++++ .../{counter => rtc}/motorola,mc146818.yaml | 2 +- dts/x86/intel/apollo_lake.dtsi | 5 +- dts/x86/intel/atom.dtsi | 6 +- dts/x86/intel/elkhart_lake.dtsi | 6 +- dts/x86/intel/ia32.dtsi | 6 +- dts/x86/intel/raptor_lake.dtsi | 16 +- 16 files changed, 642 insertions(+), 12 deletions(-) create mode 100644 drivers/rtc/Kconfig.mc146818 create mode 100644 drivers/rtc/rtc_mc146818.c rename dts/bindings/{counter => rtc}/motorola,mc146818.yaml (87%) diff --git a/boards/x86/ehl_crb/ehl_crb.dts b/boards/x86/ehl_crb/ehl_crb.dts index e836201615e4..f8ebe0e8dad4 100644 --- a/boards/x86/ehl_crb/ehl_crb.dts +++ b/boards/x86/ehl_crb/ehl_crb.dts @@ -21,4 +21,8 @@ zephyr,console = &uart2; zephyr,shell-uart = &uart2; }; + + aliases { + rtc = &rtc; + }; }; diff --git a/boards/x86/ehl_crb/ehl_crb.yaml b/boards/x86/ehl_crb/ehl_crb.yaml index f9e0e7c871dd..d9fbe61bfe33 100644 --- a/boards/x86/ehl_crb/ehl_crb.yaml +++ b/boards/x86/ehl_crb/ehl_crb.yaml @@ -9,6 +9,7 @@ ram: 2048 supported: - gpio - smbus + - rtc testing: ignore_tags: - net diff --git a/boards/x86/qemu_x86/qemu_x86.dts b/boards/x86/qemu_x86/qemu_x86.dts index 61e380721cc1..62fc4dff7a77 100644 --- a/boards/x86/qemu_x86/qemu_x86.dts +++ b/boards/x86/qemu_x86/qemu_x86.dts @@ -29,6 +29,7 @@ uart-1 = &uart1; eeprom-0 = &eeprom0; eeprom-1 = &eeprom1; + rtc = &rtc; }; chosen { diff --git a/boards/x86/rpl_crb/rpl_crb.dts b/boards/x86/rpl_crb/rpl_crb.dts index 59d0baf52e79..23b27f7baaa2 100644 --- a/boards/x86/rpl_crb/rpl_crb.dts +++ b/boards/x86/rpl_crb/rpl_crb.dts @@ -23,5 +23,6 @@ aliases { watchdog0 = &tco_wdt; + rtc = &rtc; }; }; diff --git a/boards/x86/rpl_crb/rpl_crb.yaml b/boards/x86/rpl_crb/rpl_crb.yaml index 129c071320de..8c6b660206ed 100644 --- a/boards/x86/rpl_crb/rpl_crb.yaml +++ b/boards/x86/rpl_crb/rpl_crb.yaml @@ -8,6 +8,7 @@ ram: 2048 supported: - smbus - watchdog + - rtc testing: ignore_tags: - net diff --git a/drivers/counter/Kconfig.cmos b/drivers/counter/Kconfig.cmos index 33fdd4c3e790..1e9de0b3a579 100644 --- a/drivers/counter/Kconfig.cmos +++ b/drivers/counter/Kconfig.cmos @@ -5,5 +5,5 @@ config COUNTER_CMOS bool "Counter driver for x86 CMOS/RTC clock" - default y + default y if !RTC depends on DT_HAS_MOTOROLA_MC146818_ENABLED diff --git a/drivers/rtc/CMakeLists.txt b/drivers/rtc/CMakeLists.txt index 9ba93059d29e..b807adc927b8 100644 --- a/drivers/rtc/CMakeLists.txt +++ b/drivers/rtc/CMakeLists.txt @@ -6,3 +6,4 @@ zephyr_library() 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) +zephyr_library_sources_ifdef(CONFIG_RTC_MOTOROLA_MC146818 rtc_mc146818.c) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 2ee5d8e55fc6..a2f39c0b60fe 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -37,5 +37,6 @@ config RTC_CALIBRATION source "drivers/rtc/Kconfig.emul" source "drivers/rtc/Kconfig.pcf8523" +source "drivers/rtc/Kconfig.mc146818" endif # RTC diff --git a/drivers/rtc/Kconfig.mc146818 b/drivers/rtc/Kconfig.mc146818 new file mode 100644 index 000000000000..5bf2bfde9a2c --- /dev/null +++ b/drivers/rtc/Kconfig.mc146818 @@ -0,0 +1,9 @@ +# Intel SoC RTC configuration options + +# Copyright (c) 2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +config RTC_MOTOROLA_MC146818 + bool "RTC driver for x86 CMOS/RTC clock" + default y if !COUNTER + depends on DT_HAS_MOTOROLA_MC146818_ENABLED diff --git a/drivers/rtc/rtc_mc146818.c b/drivers/rtc/rtc_mc146818.c new file mode 100644 index 000000000000..3f4530c750e4 --- /dev/null +++ b/drivers/rtc/rtc_mc146818.c @@ -0,0 +1,592 @@ +/* + * Copyright (c) 2023 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT motorola_mc146818 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RTC_STD_INDEX (DT_INST_REG_ADDR_BY_IDX(0, 0)) +#define RTC_STD_TARGET (DT_INST_REG_ADDR_BY_IDX(0, 1)) + +/* Time indices in RTC RAM */ +#define RTC_SEC 0x00 +#define RTC_MIN 0x02 +#define RTC_HOUR 0x04 + +/* Day of week index in RTC RAM */ +#define RTC_WDAY 0x06 + +/* Day of month index in RTC RAM */ +#define RTC_MDAY 0x07 + +/* Month and year index in RTC RAM */ +#define RTC_MONTH 0x08 +#define RTC_YEAR 0x09 + +/* Alarm time indices in RTC RAM */ +#define RTC_ALARM_SEC 0x01 +#define RTC_ALARM_MIN 0x03 +#define RTC_ALARM_HOUR 0x05 + +/* Registers A-D indeces in RTC RAM */ +#define RTC_REG_A 0x0A +#define RTC_REG_B 0x0B +#define RTC_REG_C 0x0C +#define RTC_REG_D 0x0D + +#define RTC_UIP RTC_REG_A +#define RTC_DATA RTC_REG_B +#define RTC_FLAG RTC_REG_C +#define RTC_ALARM_MDAY RTC_REG_D + +/* Alarm don't case state */ +#define RTC_ALARM_DC 0xFF + +/* Update In Progress bit in REG_A */ +#define RTC_UIP_BIT BIT(7) + +/* Update Cycle Inhibit bit in REG_B */ +#define RTC_UCI_BIT BIT(7) + +/* Periodic Interrupt Enable bit in REG_B */ +#define RTC_PIE_BIT BIT(6) + +/* Alarm Interrupt Enable bit in REG_B */ +#define RTC_AIE_BIT BIT(5) + +/* Update-ended Interrupt Enable bit in REG_B */ +#define RTC_UIE_BIT BIT(4) + +/* Data mode bit in REG_B */ +#define RTC_DMODE_BIT BIT(2) + +/* Hour Format bit in REG_B */ +#define RTC_HFORMAT_BIT BIT(1) + +/* Daylight Savings Enable Format bit in REG_B */ +#define RTC_DSE_BIT BIT(0) + +/* Interrupt Request Flag bit in REG_C */ +#define RTC_IRF_BIT BIT(7) + +/* Periodic Flag bit in REG_C */ +#define RTC_PF_BIT BIT(6) + +/* Alarm Flag bit in REG_C */ +#define RTC_AF_BIT BIT(5) + +/* Update-end Flag bit in REG_C */ +#define RTC_UEF_BIT BIT(4) + +/* VRT bit in REG_D */ +#define RTC_VRT_BIT BIT(7) + +/* Month day Alarm bits in REG_D */ +#define RTC_MDAY_ALARM BIT_MASK(5) + +/* Maximum and Minimum values of time */ +#define MIN_SEC 0 +#define MAX_SEC 59 +#define MIN_MIN 0 +#define MAX_MIN 59 +#define MIN_HOUR 0 +#define MAX_HOUR 23 +#define MAX_WDAY 7 +#define MIN_WDAY 1 +#define MAX_MDAY 31 +#define MIN_MDAY 1 +#define MAX_MON 11 +#define MIN_MON 0 +#define MIN_YEAR_DIFF 0 /* YEAR - 1900 */ +#define MAX_YEAR_DIFF 199 /* YEAR - 1900 */ + +struct rtc_mc146818_data { + struct k_spinlock lock; + uint16_t alarms_count; + uint16_t mask; + bool alarm_pending; + rtc_alarm_callback cb; + void *cb_data; + rtc_update_callback update_cb; + void *update_cb_data; +}; + +static uint8_t rtc_read(int reg) +{ + uint8_t value; + + sys_out8(reg, RTC_STD_INDEX); + value = sys_in8(RTC_STD_TARGET); + + return value; +} + +static void rtc_write(int reg, uint8_t value) +{ + sys_out8(reg, RTC_STD_INDEX); + sys_out8(value, RTC_STD_TARGET); +} + +static bool rtc_mc146818_validate_time(const struct rtc_time *timeptr) +{ + if (timeptr->tm_sec < MIN_SEC || timeptr->tm_sec > MAX_SEC) { + return false; + } + if (timeptr->tm_min < MIN_MIN || timeptr->tm_min > MAX_MIN) { + return false; + } + if (timeptr->tm_hour < MIN_HOUR || timeptr->tm_hour > MAX_HOUR) { + return false; + } + if (timeptr->tm_wday < MIN_WDAY || timeptr->tm_wday > MAX_WDAY) { + return false; + } + if (timeptr->tm_mday < MIN_MDAY || timeptr->tm_mday > MAX_MDAY) { + return false; + } + if (timeptr->tm_mon < MIN_MON || timeptr->tm_mon > MAX_MON) { + return false; + } + if (timeptr->tm_year < MIN_YEAR_DIFF || timeptr->tm_year > MAX_YEAR_DIFF) { + return false; + } + return true; +} + +static int rtc_mc146818_set_time(const struct device *dev, const struct rtc_time *timeptr) +{ + struct rtc_mc146818_data * const dev_data = dev->data; + uint8_t value; + int ret; + + k_spinlock_key_t key = k_spin_lock(&dev_data->lock); + + if (timeptr == NULL) { + ret = -EINVAL; + goto out; + } + + /* Check time valid */ + if (!rtc_mc146818_validate_time(timeptr)) { + ret = -EINVAL; + goto out; + } + + value = rtc_read(RTC_DATA); + rtc_write(RTC_DATA, value | RTC_UCI_BIT); + + if (!(rtc_read(RTC_DATA) & RTC_DMODE_BIT)) { + rtc_write(RTC_SEC, (uint8_t)bin2bcd(timeptr->tm_sec)); + rtc_write(RTC_MIN, (uint8_t)bin2bcd(timeptr->tm_min)); + rtc_write(RTC_HOUR, (uint8_t)bin2bcd(timeptr->tm_hour)); + rtc_write(RTC_WDAY, (uint8_t)bin2bcd(timeptr->tm_wday)); + rtc_write(RTC_MDAY, (uint8_t)bin2bcd(timeptr->tm_mday)); + rtc_write(RTC_MONTH, (uint8_t)bin2bcd(timeptr->tm_mon + 1)); + rtc_write(RTC_YEAR, (uint8_t)bin2bcd(timeptr->tm_year)); + } else { + rtc_write(RTC_SEC, (uint8_t)timeptr->tm_sec); + rtc_write(RTC_MIN, (uint8_t)timeptr->tm_min); + rtc_write(RTC_HOUR, (uint8_t)timeptr->tm_hour); + rtc_write(RTC_WDAY, (uint8_t)timeptr->tm_wday); + rtc_write(RTC_MDAY, (uint8_t)timeptr->tm_mday); + rtc_write(RTC_MONTH, (uint8_t)timeptr->tm_mon + 1); + rtc_write(RTC_YEAR, (uint8_t)timeptr->tm_year); + } + + if (timeptr->tm_isdst == 1) { + value |= RTC_DSE_BIT; + } else { + value &= (~RTC_DSE_BIT); + } + value &= (~RTC_UCI_BIT); + rtc_write(RTC_DATA, value); + ret = 0; +out: + k_spin_unlock(&dev_data->lock, key); + return ret; +} + +static int rtc_mc146818_get_time(const struct device *dev, struct rtc_time *timeptr) +{ + struct rtc_mc146818_data * const dev_data = dev->data; + int ret; + uint8_t value; + + k_spinlock_key_t key = k_spin_lock(&dev_data->lock); + + /* Validate arguments */ + if (timeptr == NULL) { + ret = -EINVAL; + goto out; + } + + if (!(rtc_read(RTC_ALARM_MDAY) & RTC_VRT_BIT)) { + ret = -ENODATA; + goto out; + } + + while (rtc_read(RTC_UIP) & RTC_UIP_BIT) { + continue; + } + timeptr->tm_year = rtc_read(RTC_YEAR); + timeptr->tm_mon = rtc_read(RTC_MONTH) - 1; + timeptr->tm_mday = rtc_read(RTC_MDAY); + timeptr->tm_wday = rtc_read(RTC_WDAY); + timeptr->tm_hour = rtc_read(RTC_HOUR); + timeptr->tm_min = rtc_read(RTC_MIN); + timeptr->tm_sec = rtc_read(RTC_SEC); + + if (!(rtc_read(RTC_DATA) & RTC_DMODE_BIT)) { + timeptr->tm_year = bcd2bin(timeptr->tm_year); + timeptr->tm_mon = bcd2bin(timeptr->tm_mon); + timeptr->tm_mday = bcd2bin(timeptr->tm_mday); + timeptr->tm_wday = bcd2bin(timeptr->tm_wday); + timeptr->tm_hour = bcd2bin(timeptr->tm_hour); + timeptr->tm_min = bcd2bin(timeptr->tm_min); + timeptr->tm_sec = bcd2bin(timeptr->tm_sec); + } + + timeptr->tm_nsec = 0; + timeptr->tm_yday = 0; + value = rtc_read(RTC_DATA); + if (value & RTC_DSE_BIT) { + timeptr->tm_isdst = 1; + } else { + timeptr->tm_isdst = -1; + } + + /* Check time valid */ + if (!rtc_mc146818_validate_time(timeptr)) { + ret = -ENODATA; + goto out; + } + ret = 0; +out: + k_spin_unlock(&dev_data->lock, key); + return ret; +} + +#if defined(CONFIG_RTC_ALARM) +static bool rtc_mc146818_validate_alarm(const struct rtc_time *timeptr, uint32_t mask) +{ + if ((mask & RTC_ALARM_TIME_MASK_SECOND) && + (timeptr->tm_sec < MIN_SEC || timeptr->tm_sec > MAX_SEC)) { + return false; + } + + if ((mask & RTC_ALARM_TIME_MASK_MINUTE) && + (timeptr->tm_min < MIN_MIN || timeptr->tm_min > MAX_MIN)) { + return false; + } + + if ((mask & RTC_ALARM_TIME_MASK_HOUR) && + (timeptr->tm_hour < MIN_HOUR || timeptr->tm_hour > MAX_HOUR)) { + return false; + } + + if ((mask & RTC_ALARM_TIME_MASK_MONTH) && + (timeptr->tm_mon < MIN_WDAY || timeptr->tm_mon > MAX_WDAY)) { + return false; + } + + if ((mask & RTC_ALARM_TIME_MASK_MONTHDAY) && + (timeptr->tm_mday < MIN_MDAY || timeptr->tm_mday > MAX_MDAY)) { + return false; + } + + if ((mask & RTC_ALARM_TIME_MASK_YEAR) && + (timeptr->tm_year < MIN_YEAR_DIFF || timeptr->tm_year > MAX_YEAR_DIFF)) { + return false; + } + + return true; +} + +static int rtc_mc146818_alarm_get_supported_fields(const struct device *dev, uint16_t id, + uint16_t *mask) +{ + struct rtc_mc146818_data * const dev_data = dev->data; + + if (dev_data->alarms_count <= id) { + return -EINVAL; + } + + (*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); + + return 0; +} + +static int rtc_mc146818_alarm_set_time(const struct device *dev, uint16_t id, uint16_t mask, + const struct rtc_time *timeptr) +{ + struct rtc_mc146818_data * const dev_data = dev->data; + int ret; + + k_spinlock_key_t key = k_spin_lock(&dev_data->lock); + + if (dev_data->alarms_count <= id) { + ret = -EINVAL; + goto out; + } + + if ((mask > 0) && (timeptr == NULL)) { + ret = -EINVAL; + goto out; + } + + /* Check time valid */ + if (!rtc_mc146818_validate_alarm(timeptr, mask)) { + ret = -EINVAL; + goto out; + } + + dev_data->mask = mask; + + if (!(rtc_read(RTC_DATA) & RTC_DMODE_BIT)) { + if (mask & RTC_ALARM_TIME_MASK_SECOND) { + rtc_write(RTC_ALARM_SEC, bin2bcd(timeptr->tm_sec)); + } else { + rtc_write(RTC_ALARM_SEC, bin2bcd(RTC_ALARM_DC)); + } + + if (mask & RTC_ALARM_TIME_MASK_MINUTE) { + rtc_write(RTC_ALARM_MIN, bin2bcd(timeptr->tm_min)); + } else { + rtc_write(RTC_ALARM_SEC, bin2bcd(RTC_ALARM_DC)); + } + + if (mask & RTC_ALARM_TIME_MASK_HOUR) { + rtc_write(RTC_ALARM_HOUR, bin2bcd(timeptr->tm_hour)); + } else { + rtc_write(RTC_ALARM_SEC, bin2bcd(RTC_ALARM_DC)); + } + + } else { + if (mask & RTC_ALARM_TIME_MASK_SECOND) { + rtc_write(RTC_ALARM_SEC, timeptr->tm_sec); + } else { + rtc_write(RTC_ALARM_SEC, RTC_ALARM_DC); + } + + if (mask & RTC_ALARM_TIME_MASK_MINUTE) { + rtc_write(RTC_ALARM_MIN, timeptr->tm_min); + } else { + rtc_write(RTC_ALARM_SEC, RTC_ALARM_DC); + } + if (mask & RTC_ALARM_TIME_MASK_HOUR) { + rtc_write(RTC_ALARM_HOUR, timeptr->tm_hour); + } else { + rtc_write(RTC_ALARM_SEC, RTC_ALARM_DC); + } + + } + + if (mask & RTC_ALARM_TIME_MASK_MONTHDAY) { + rtc_write(RTC_ALARM_MDAY, rtc_read(RTC_REG_D) | + timeptr->tm_mday); + } else { + rtc_write(RTC_ALARM_SEC, rtc_read(RTC_REG_D) & + (~RTC_MDAY_ALARM)); + } + + rtc_write(RTC_DATA, rtc_read(RTC_DATA) | RTC_AIE_BIT); + ret = 0; +out: + k_spin_unlock(&dev_data->lock, key); + return ret; +} + +static int rtc_mc146818_alarm_get_time(const struct device *dev, uint16_t id, uint16_t *mask, + struct rtc_time *timeptr) +{ + struct rtc_mc146818_data * const dev_data = dev->data; + int ret; + + k_spinlock_key_t key = k_spin_lock(&dev_data->lock); + + if (dev_data->alarms_count <= id) { + ret = -EINVAL; + goto out; + } + + if (timeptr == NULL) { + ret = -EINVAL; + goto out; + } + + timeptr->tm_sec = rtc_read(RTC_ALARM_SEC); + timeptr->tm_min = rtc_read(RTC_ALARM_MIN); + timeptr->tm_hour = rtc_read(RTC_ALARM_HOUR); + timeptr->tm_mday = (rtc_read(RTC_ALARM_MDAY) & RTC_MDAY_ALARM); + + if (!(rtc_read(RTC_DATA) & RTC_DMODE_BIT)) { + timeptr->tm_sec = bcd2bin(timeptr->tm_sec); + timeptr->tm_min = bcd2bin(timeptr->tm_min); + timeptr->tm_hour = bcd2bin(timeptr->tm_hour); + } + + (*mask) = dev_data->mask; + + /* Check time valid */ + if (!rtc_mc146818_validate_alarm(timeptr, (*mask))) { + ret = -ENODATA; + goto out; + } + + ret = 0; +out: + k_spin_unlock(&dev_data->lock, key); + return ret; +} + +static int rtc_mc146818_alarm_set_callback(const struct device *dev, uint16_t id, + rtc_alarm_callback callback, void *user_data) +{ + struct rtc_mc146818_data * const dev_data = dev->data; + + if (dev_data->alarms_count <= id) { + return -EINVAL; + } + + k_spinlock_key_t key = k_spin_lock(&dev_data->lock); + + dev_data->cb = callback; + dev_data->cb_data = user_data; + + if (callback != NULL) { + /* Enable Alarm callback */ + rtc_write(RTC_DATA, (rtc_read(RTC_DATA) | RTC_AIE_BIT)); + } else { + /* Disable Alarm callback */ + rtc_write(RTC_DATA, (rtc_read(RTC_DATA) & (~RTC_AIE_BIT))); + } + + k_spin_unlock(&dev_data->lock, key); + return 0; +} + +static int rtc_mc146818_alarm_is_pending(const struct device *dev, uint16_t id) +{ + struct rtc_mc146818_data * const dev_data = dev->data; + int ret; + + if (dev_data->alarms_count <= id) { + return -EINVAL; + } + + k_spinlock_key_t key = k_spin_lock(&dev_data->lock); + + ret = (dev_data->alarm_pending == true) ? 1 : 0; + + dev_data->alarm_pending = false; + + k_spin_unlock(&dev_data->lock, key); + return ret; +} +#endif /* CONFIG_RTC_ALARM */ + +#if defined(CONFIG_RTC_UPDATE) +static int rtc_mc146818_update_set_callback(const struct device *dev, + rtc_update_callback callback, void *user_data) +{ + struct rtc_mc146818_data * const dev_data = dev->data; + + k_spinlock_key_t key = k_spin_lock(&dev_data->lock); + + dev_data->update_cb = callback; + dev_data->update_cb_data = user_data; + + if (callback != NULL) { + /* Enable update callback */ + rtc_write(RTC_DATA, (rtc_read(RTC_DATA) | RTC_UIE_BIT)); + } else { + /* Disable update callback */ + rtc_write(RTC_DATA, (rtc_read(RTC_DATA) & (~RTC_UIE_BIT))); + } + + + k_spin_unlock(&dev_data->lock, key); + return 0; +} + +#endif /* CONFIG_RTC_UPDATE */ + +static void rtc_mc146818_isr(const struct device *dev) +{ + struct rtc_mc146818_data * const dev_data = dev->data; + + ARG_UNUSED(dev_data); + +#if defined(CONFIG_RTC_ALARM) + if (rtc_read(RTC_FLAG) & RTC_AF_BIT) { + if (dev_data->cb) { + dev_data->cb(dev, 0, dev_data->cb_data); + dev_data->alarm_pending = false; + } + } +#endif + +#if defined(CONFIG_RTC_UPDATE) + if (rtc_read(RTC_FLAG) & RTC_UEF_BIT) { + if (dev_data->update_cb) { + dev_data->update_cb(dev, dev_data->update_cb_data); + } + } +#endif + +} + +struct rtc_driver_api rtc_mc146818_driver_api = { + .set_time = rtc_mc146818_set_time, + .get_time = rtc_mc146818_get_time, +#if defined(CONFIG_RTC_ALARM) + .alarm_get_supported_fields = rtc_mc146818_alarm_get_supported_fields, + .alarm_set_time = rtc_mc146818_alarm_set_time, + .alarm_get_time = rtc_mc146818_alarm_get_time, + .alarm_is_pending = rtc_mc146818_alarm_is_pending, + .alarm_set_callback = rtc_mc146818_alarm_set_callback, +#endif /* CONFIG_RTC_ALARM */ + +#if defined(CONFIG_RTC_UPDATE) + .update_set_callback = rtc_mc146818_update_set_callback, +#endif /* CONFIG_RTC_UPDATE */ +}; + +static int rtc_mc146818_init(const struct device *dev) +{ + IRQ_CONNECT(DT_INST_IRQN(0), + DT_INST_IRQ(0, priority), + rtc_mc146818_isr, NULL, + DT_INST_IRQ(0, sense)); + irq_enable(DT_INST_IRQN(0)); + + return 0; +} + +#define RTC_MC146818_DEV_CFG(n) \ + static struct rtc_mc146818_data rtc_data_##n = { \ + .alarms_count = DT_INST_PROP(n, alarms_count), \ + .mask = 0, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, &rtc_mc146818_init, NULL, &rtc_data_##n, \ + NULL, POST_KERNEL, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &rtc_mc146818_driver_api); \ + +DT_INST_FOREACH_STATUS_OKAY(RTC_MC146818_DEV_CFG) diff --git a/dts/bindings/counter/motorola,mc146818.yaml b/dts/bindings/rtc/motorola,mc146818.yaml similarity index 87% rename from dts/bindings/counter/motorola,mc146818.yaml rename to dts/bindings/rtc/motorola,mc146818.yaml index 8c067ed0ea54..11fd987ab586 100644 --- a/dts/bindings/counter/motorola,mc146818.yaml +++ b/dts/bindings/rtc/motorola,mc146818.yaml @@ -6,4 +6,4 @@ description: Motorola MC146818 compatible Real Timer Clock compatible: "motorola,mc146818" -include: base.yaml +include: rtc-device.yaml diff --git a/dts/x86/intel/apollo_lake.dtsi b/dts/x86/intel/apollo_lake.dtsi index e637dd448399..e6936c6ddaba 100644 --- a/dts/x86/intel/apollo_lake.dtsi +++ b/dts/x86/intel/apollo_lake.dtsi @@ -379,9 +379,12 @@ status = "okay"; }; - counter: counter@70 { + rtc: counter: rtc@70 { compatible = "motorola,mc146818"; reg = <0x70 0x0D 0x71 0x0D>; + interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; + interrupt-parent = <&intc>; + alarms-count = <1>; status = "okay"; }; diff --git a/dts/x86/intel/atom.dtsi b/dts/x86/intel/atom.dtsi index 56a57019da82..8e9fb04032ad 100644 --- a/dts/x86/intel/atom.dtsi +++ b/dts/x86/intel/atom.dtsi @@ -68,11 +68,15 @@ status = "disabled"; }; - counter: counter@70 { + rtc: counter: rtc@70 { compatible = "motorola,mc146818"; reg = <0x70 0x0D 0x71 0x0D>; + interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; + interrupt-parent = <&intc>; + alarms-count = <1>; status = "okay"; }; + }; }; diff --git a/dts/x86/intel/elkhart_lake.dtsi b/dts/x86/intel/elkhart_lake.dtsi index 056f2dbfd258..d039d41c9156 100644 --- a/dts/x86/intel/elkhart_lake.dtsi +++ b/dts/x86/intel/elkhart_lake.dtsi @@ -689,11 +689,15 @@ status = "okay"; }; - counter: counter@70 { + rtc: counter: rtc@70 { compatible = "motorola,mc146818"; reg = <0x70 0x0D 0x71 0x0D>; + interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; + interrupt-parent = <&intc>; + alarms-count = <1>; status = "okay"; }; + }; }; diff --git a/dts/x86/intel/ia32.dtsi b/dts/x86/intel/ia32.dtsi index 9dfe5cca5e36..35f38b0cec38 100644 --- a/dts/x86/intel/ia32.dtsi +++ b/dts/x86/intel/ia32.dtsi @@ -68,11 +68,15 @@ status = "disabled"; }; - counter: counter@70 { + rtc: counter: rtc@70 { compatible = "motorola,mc146818"; reg = <0x70 0x0D 0x71 0x0D>; + interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; + interrupt-parent = <&intc>; + alarms-count = <1>; status = "okay"; }; + }; }; diff --git a/dts/x86/intel/raptor_lake.dtsi b/dts/x86/intel/raptor_lake.dtsi index b110b17a5884..7dc528aede02 100644 --- a/dts/x86/intel/raptor_lake.dtsi +++ b/dts/x86/intel/raptor_lake.dtsi @@ -496,6 +496,16 @@ status = "okay"; }; + rtc: counter: rtc@70 { + compatible = "motorola,mc146818"; + reg = <0x70 0x0D 0x71 0x0D>; + interrupts = <8 IRQ_TYPE_LOWEST_EDGE_RISING 3>; + interrupt-parent = <&intc>; + alarms-count = <1>; + + status = "okay"; + }; + hpet: hpet@fed00000 { compatible = "intel,hpet"; reg = <0xfed00000 0x400>; @@ -505,12 +515,6 @@ status = "okay"; }; - counter: counter@70 { - compatible = "motorola,mc146818"; - reg = <0x70 0x0D 0x71 0x0D>; - status = "okay"; - }; - tco_wdt: tco_wdt@400 { compatible = "intel,tco-wdt"; reg = <0x0400 0x20>;