/* * Copyright (C) 2014 René Kijewski * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @brief Interfacing the realtime clock on x86 boards. * * Only use this module to read the current time. * Using the other functions in applications would break the hwtimer. * * @ingroup x86-irq * @{ * @file * @author René Kijewski */ #ifndef CPU__X86__RTC__H__ #define CPU__X86__RTC__H__ #include "msg.h" #include "x86_cmos.h" #include #ifdef __cplusplus extern "C" { #endif /** * @brief A timestamp. * * The value of the century is unreliable. */ typedef union x86_rtc_data { __extension__ struct { uint8_t second, minute, hour; uint8_t day, month, year, century; }; uint64_t timestamp; } x86_rtc_data_t; #define RTC_REG_SECOND (0x00) #define RTC_REG_ALARM_SECOND (0x01) #define RTC_REG_MINUTE (0x02) #define RTC_REG_ALARM_MINUTE (0x03) #define RTC_REG_HOUR (0x04) #define RTC_REG_ALARM_HOUR (0x05) #define RTC_REG_DOW (0x06) #define RTC_REG_DAY (0x07) #define RTC_REG_MONTH (0x08) #define RTC_REG_YEAR (0x09) #define RTC_REG_A (0x0a) #define RTC_REG_B (0x0b) #define RTC_REG_C (0x0c) #define RTC_REG_D (0x0d) #define RTC_REG_POST (0x0e) #define RTC_REG_CENTURY (0x32) #define RTC_REG_A_HZ_OFF ( 0 << 0) #define RTC_REG_A_HZ_8192 ( 3 << 0) #define RTC_REG_A_HZ_4096 ( 4 << 0) #define RTC_REG_A_HZ_2048 ( 5 << 0) #define RTC_REG_A_HZ_1024 ( 6 << 0) #define RTC_REG_A_HZ_512 ( 7 << 0) #define RTC_REG_A_HZ_256 ( 8 << 0) #define RTC_REG_A_HZ_128 ( 9 << 0) #define RTC_REG_A_HZ_64 (10 << 0) #define RTC_REG_A_HZ_32 (11 << 0) #define RTC_REG_A_HZ_16 (12 << 0) #define RTC_REG_A_HZ_8 (13 << 0) #define RTC_REG_A_HZ_4 (14 << 0) #define RTC_REG_A_HZ_2 (15 << 0) #define RTC_REG_A_HZ_MASK (15 << 0) #define RTC_REG_A_DIVIDER_MASK ( 3 << 4) #define RTC_REG_A_UPDATING ( 1 << 7) #define RTC_REG_B_DST (1 << 0) #define RTC_REG_B_24H (1 << 1) #define RTC_REG_B_BIN (1 << 2) #define RTC_REG_B_WAVE (1 << 3) #define RTC_REG_B_INT_UPDATE (1 << 4) #define RTC_REG_B_INT_ALARM (1 << 5) #define RTC_REG_B_INT_PERIODIC (1 << 6) #define RTC_REG_B_INT_MASK (7 << 4) #define RTC_REG_B_UPDATE (1 << 7) #define RTC_REG_C_IRQ_UPDATE (1 << 4) #define RTC_REG_C_IRQ_ALARM (1 << 5) #define RTC_REG_C_IRQ_PERIODIC (1 << 6) #define RTC_REG_C_IRQ (1 << 7) #define RTC_REG_D_VALID (1 << 7) #define RTC_REG_POST_TIME_INVALID (1 << 2) #define RTC_REG_POST_POWER_LOSS (1 << 7) /** * @brief Initialize the Real Time Clock. * * This function is called during initialization by x86_startup(). * You must not call this function on your own accord. * * The RTC subsystem will refuse to work if the CMOS says that * @li there was a power loss, * @li the stored time is invalid (i.e. February 30), or * @li the CMOS had a checksum failure. */ void x86_init_rtc(void); /** * @brief Read the current time. * @returns false iff the RTC is unreliable, the value of dest is random is this case. * * This reads the CMOS value * The standard does not tell the timezone of this value. */ bool x86_rtc_read(x86_rtc_data_t *dest); /** * @brief A custom callback handler for RTC interrupts. * @param reg_c The value of CMOS register C. */ typedef void (*x86_rtc_callback_t)(uint8_t reg_c); /** * @brief Set an RTC alarm. * @param[in] when Time when the RTC you raise an interrupt. The date part is ignored. * @param msg_content The value for msg_t::content.value. * @param target_pid The process which shall receive the message, `KERNEL_PID_UNDEF` to disable. * @param allow_replace Whether it is allowed to overwrite an existing alarm. * * The value of msg_t::type will be `reg_c | (RTC_REG_B_INT_UPDATE << 8)`, * where `reg_c` is the value of CMOS register C. * * You should not call this function directly. * You should use xtimer instead. */ bool x86_rtc_set_alarm(const x86_rtc_data_t *when, uint32_t msg_content, kernel_pid_t target_pid, bool allow_replace); /** * @brief Set up periodic interrupts * @param hz How often a second the interrupt should fire, e.g. RTC_REG_A_HZ_8192. * @param msg_content The value for msg_t::content.value. * @param target_pid The process which shall receive the message, `KERNEL_PID_UNDEF` to disable. * @param allow_replace Whether it is allowed to overwrite an existing alarm. * * The value of msg_t::type will be `reg_c | (RTC_REG_B_INT_PERIODIC << 8)`, * where `reg_c` is the value of CMOS register C. * * You should not call this function directly. * You should use xtimer instead. */ bool x86_rtc_set_periodic(uint8_t hz, uint32_t msg_content, kernel_pid_t target_pid, bool allow_replace); /** * @brief Set up secondly interrupts. * @param msg_content The value for msg_t::content.value. * @param target_pid The process which shall receive the message, `KERNEL_PID_UNDEF` to disable. * @param allow_replace Whether it is allowed to overwrite an existing alarm. * * The value of msg_t::type will be `reg_c | (RTC_REG_B_INT_UPDATE << 8)`, * where `reg_c` is the value of CMOS register C. * * You should not call this function directly. * You should use xtimer instead. */ bool x86_rtc_set_update(uint32_t msg_content, kernel_pid_t target_pid, bool allow_replace); /** * @brief Set custom alarm interrupt handler. * @param cb Your custom handler, or NULL to use default. * * You must never use this function. * It is only there for x86_hwtimer.c, * because the hwtimer subsystem gets set up before the message system works. */ void x86_rtc_set_alarm_callback(x86_rtc_callback_t cb); /** * @brief Set custom periodic interrupt handler. * @param cb Your custom handler, or NULL to use default. * * You must never use this function. * It is only there for x86_hwtimer.c, * because the hwtimer subsystem gets set up before the message system works. */ void x86_rtc_set_periodic_callback(x86_rtc_callback_t cb); /** * @brief Set custom update interrupt handler. * @param cb Your custom handler, or NULL to use default. * * You must never use this function. * It is only there for x86_hwtimer.c, * because the hwtimer subsystem gets set up before the message system works. */ void x86_rtc_set_update_callback(x86_rtc_callback_t cb); #ifdef __cplusplus } #endif #endif /** @} */