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 <anisetti.avinash.krishna@intel.com>
This commit is contained in:
parent
5076476cf5
commit
bfeb5043ac
16 changed files with 642 additions and 12 deletions
|
@ -21,4 +21,8 @@
|
|||
zephyr,console = &uart2;
|
||||
zephyr,shell-uart = &uart2;
|
||||
};
|
||||
|
||||
aliases {
|
||||
rtc = &rtc;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@ ram: 2048
|
|||
supported:
|
||||
- gpio
|
||||
- smbus
|
||||
- rtc
|
||||
testing:
|
||||
ignore_tags:
|
||||
- net
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
uart-1 = &uart1;
|
||||
eeprom-0 = &eeprom0;
|
||||
eeprom-1 = &eeprom1;
|
||||
rtc = &rtc;
|
||||
};
|
||||
|
||||
chosen {
|
||||
|
|
|
@ -23,5 +23,6 @@
|
|||
|
||||
aliases {
|
||||
watchdog0 = &tco_wdt;
|
||||
rtc = &rtc;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@ ram: 2048
|
|||
supported:
|
||||
- smbus
|
||||
- watchdog
|
||||
- rtc
|
||||
testing:
|
||||
ignore_tags:
|
||||
- net
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -37,5 +37,6 @@ config RTC_CALIBRATION
|
|||
|
||||
source "drivers/rtc/Kconfig.emul"
|
||||
source "drivers/rtc/Kconfig.pcf8523"
|
||||
source "drivers/rtc/Kconfig.mc146818"
|
||||
|
||||
endif # RTC
|
||||
|
|
9
drivers/rtc/Kconfig.mc146818
Normal file
9
drivers/rtc/Kconfig.mc146818
Normal file
|
@ -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
|
592
drivers/rtc/rtc_mc146818.c
Normal file
592
drivers/rtc/rtc_mc146818.c
Normal file
|
@ -0,0 +1,592 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT motorola_mc146818
|
||||
|
||||
#include <errno.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/init.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/spinlock.h>
|
||||
#include <zephyr/devicetree.h>
|
||||
#include <zephyr/drivers/rtc.h>
|
||||
#include <zephyr/sys/sys_io.h>
|
||||
|
||||
#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)
|
|
@ -6,4 +6,4 @@ description: Motorola MC146818 compatible Real Timer Clock
|
|||
|
||||
compatible: "motorola,mc146818"
|
||||
|
||||
include: base.yaml
|
||||
include: rtc-device.yaml
|
|
@ -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";
|
||||
};
|
||||
|
|
|
@ -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";
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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";
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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";
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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>;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue