drv_rtc.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*
  2. * Copyright (c) 2021-2023 HPMicro
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2021-09-19 HPMicro First version
  9. * 2023-05-08 HPMicro Adapt RT-Thread V5.0.0
  10. * 2025-05-23 HPMicro Support setting and getting timeval
  11. * 2025-05-26 HPMicro Support 64-bit time_t and alarm set/getting
  12. */
  13. #include "board.h"
  14. #include "drv_rtc.h"
  15. #include "hpm_rtc_drv.h"
  16. #include "hpm_bpor_drv.h"
  17. #include <rtthread.h>
  18. #include <rtdevice.h>
  19. #include <rtdbg.h>
  20. #ifdef RT_USING_RTC
  21. /*******************************************************************************************
  22. *
  23. * Prototypes
  24. *
  25. ******************************************************************************************/
  26. static rt_err_t hpm_rtc_init(rt_device_t dev);
  27. static rt_err_t hpm_rtc_open(rt_device_t dev, rt_uint16_t oflag);
  28. static rt_err_t hpm_rtc_close(rt_device_t dev);
  29. static rt_ssize_t hpm_rtc_read(rt_device_t dev, rt_off_t pos, void *buf, rt_size_t size);
  30. static rt_ssize_t hpm_rtc_write(rt_device_t dev, rt_off_t pos, const void *buf, rt_size_t size);
  31. static rt_err_t hpm_rtc_control(rt_device_t dev, int cmd, void *args);
  32. static time_t hpm_rtc_get_timestamp(void);
  33. static int hpm_rtc_set_timestamp(time_t timestamp);
  34. static int hpm_rtc_set_alarm(struct rt_rtc_wkalarm *alarm);
  35. static int hpm_rtc_get_alarm(struct rt_rtc_wkalarm *alarm);
  36. /*******************************************************************************************
  37. *
  38. * Variables
  39. *
  40. ******************************************************************************************/
  41. #ifdef RT_USING_DEVICE_OPS
  42. const struct rt_device_ops hpm_rtc_ops = {
  43. .init = hpm_rtc_init,
  44. .open = hpm_rtc_open,
  45. .close = hpm_rtc_close,
  46. .read = hpm_rtc_read,
  47. .write = hpm_rtc_write,
  48. .control = hpm_rtc_control,
  49. };
  50. #endif
  51. static struct rt_device hpm_rtc= {
  52. .type = RT_Device_Class_RTC,
  53. #ifdef RT_USING_DEVICE_OPS
  54. .ops = &hpm_rtc_ops,
  55. #else
  56. .init = hpm_rtc_init,
  57. .open = hpm_rtc_open,
  58. .close = hpm_rtc_close,
  59. .read = hpm_rtc_read,
  60. .write = hpm_rtc_write,
  61. .control = hpm_rtc_control,
  62. #endif
  63. };
  64. /*****************************************************
  65. * RTC interrupt handler
  66. ******************************************************/
  67. #ifdef RT_USING_ALARM
  68. void rtc_isr(void)
  69. {
  70. uint32_t rtc_alarm_flag = rtc_get_alarm_flags(HPM_RTC);
  71. if ((rtc_alarm_flag & RTC_ALARM_FLAG_ALARM0_MASK) != 0)
  72. {
  73. rt_alarm_update(&hpm_rtc, 1);
  74. }
  75. rtc_clear_alarm_flags(HPM_RTC, RTC_ALARM_FLAG_ALARM0_MASK | RTC_ALARM_FLAG_ALARM1_MASK);
  76. }
  77. RTT_DECLARE_EXT_ISR_M(IRQn_RTC, rtc_isr);
  78. #endif
  79. /*******************************************************************************************
  80. *
  81. * Codes
  82. *
  83. ******************************************************************************************/
  84. static rt_err_t hpm_rtc_init(rt_device_t dev)
  85. {
  86. /* Enable Power retention mode for the battery domain */
  87. bpor_enable_reg_value_retention(HPM_BPOR);
  88. return RT_EOK;
  89. }
  90. static rt_err_t hpm_rtc_open(rt_device_t dev, rt_uint16_t oflag)
  91. {
  92. return RT_EOK;
  93. }
  94. static rt_err_t hpm_rtc_close(rt_device_t dev)
  95. {
  96. return RT_EOK;
  97. }
  98. static rt_ssize_t hpm_rtc_read(rt_device_t dev, rt_off_t pos, void *buf, rt_size_t size)
  99. {
  100. return 0;
  101. }
  102. static rt_ssize_t hpm_rtc_write(rt_device_t dev, rt_off_t pos, const void *buf, rt_size_t size)
  103. {
  104. return 0;
  105. }
  106. static rt_err_t hpm_rtc_control(rt_device_t dev, int cmd, void *args)
  107. {
  108. RT_ASSERT(dev != RT_NULL);
  109. rt_err_t err = RT_EOK;
  110. struct timeval tv;
  111. switch(cmd) {
  112. case RT_DEVICE_CTRL_RTC_GET_TIME:
  113. if (sizeof(uint32_t) == sizeof(time_t)) {
  114. *(uint32_t *)args = hpm_rtc_get_timestamp();
  115. } else if (sizeof(uint64_t) == sizeof(time_t)) {
  116. *(uint64_t *)args = hpm_rtc_get_timestamp();
  117. }
  118. break;
  119. case RT_DEVICE_CTRL_RTC_SET_TIME:
  120. hpm_rtc_set_timestamp(*(time_t *)args);
  121. break;
  122. case RT_DEVICE_CTRL_RTC_GET_TIMEVAL:
  123. tv = rtc_get_timeval(HPM_RTC);
  124. memcpy(args, &tv, sizeof(tv));
  125. break;
  126. case RT_DEVICE_CTRL_RTC_SET_TIMEVAL:
  127. memcpy(&tv, args, sizeof(tv));
  128. rtc_config_time(HPM_RTC, tv.tv_sec);
  129. break;
  130. case RT_DEVICE_CTRL_RTC_SET_ALARM:
  131. err = hpm_rtc_set_alarm((struct rt_rtc_wkalarm *)args);
  132. break;
  133. case RT_DEVICE_CTRL_RTC_GET_ALARM:
  134. err = hpm_rtc_get_alarm((struct rt_rtc_wkalarm *)args);
  135. break;
  136. default:
  137. err = RT_EINVAL;
  138. break;
  139. }
  140. return err;
  141. }
  142. static time_t hpm_rtc_get_timestamp(void)
  143. {
  144. time_t time = rtc_get_time(HPM_RTC);
  145. return time;
  146. }
  147. static int hpm_rtc_set_timestamp(time_t timestamp)
  148. {
  149. (void)rtc_config_time(HPM_RTC, timestamp);
  150. return RT_EOK;
  151. }
  152. static int hpm_rtc_set_alarm(struct rt_rtc_wkalarm *alarm)
  153. {
  154. #ifdef RT_USING_ALARM
  155. rtc_alarm_config_t config;
  156. time_t now;
  157. time_t alarm_time;
  158. struct tm tm_alarm = {0};
  159. if (alarm->enable == RT_TRUE) {
  160. /* Clear all pending interrupt flags first */
  161. rtc_clear_alarm_flag(HPM_RTC, 0);
  162. rtc_clear_alarm_flag(HPM_RTC, 1);
  163. tm_alarm.tm_sec = alarm->tm_sec;
  164. tm_alarm.tm_min = alarm->tm_min;
  165. tm_alarm.tm_hour = alarm->tm_hour;
  166. tm_alarm.tm_mday = alarm->tm_mday;
  167. tm_alarm.tm_mon = alarm->tm_mon;
  168. tm_alarm.tm_year = alarm->tm_year;
  169. #ifdef RT_ALARM_USING_LOCAL_TIME
  170. alarm_time = mktime(&tm_alarm);
  171. #else
  172. alarm_time = timegm(&tm_alarm);
  173. #endif
  174. now = rtc_get_time(HPM_RTC);
  175. if (alarm_time <= now) {
  176. return -RT_ERROR;
  177. }
  178. config.period = alarm_time;
  179. config.type = RTC_ALARM_TYPE_ABSOLUTE_TIME_ONE_SHOT;
  180. config.index = 0;
  181. if (rtc_config_alarm(HPM_RTC, &config) != status_success) {
  182. return -RT_ERROR;
  183. }
  184. rtc_enable_alarm_interrupt(HPM_RTC, 0, true);
  185. intc_m_enable_irq_with_priority(IRQn_RTC, 1);
  186. } else {
  187. rtc_enable_alarm_interrupt(HPM_RTC, 0, false);
  188. intc_m_disable_irq(IRQn_RTC);
  189. }
  190. return RT_EOK;
  191. #else
  192. return -RT_EINVAL;
  193. #endif
  194. }
  195. static int hpm_rtc_get_alarm(struct rt_rtc_wkalarm *alarm)
  196. {
  197. #ifdef RT_USING_ALARM
  198. time_t alarm_time;
  199. struct tm alarm_tm;
  200. if (RTC_ALARM_EN_ENABLE0_GET(HPM_RTC->ALARM_EN) == 0) {
  201. alarm->enable = RT_FALSE;
  202. } else {
  203. alarm->enable = RT_TRUE;
  204. }
  205. alarm_time = RTC_ALARM0_ALARM_GET(HPM_RTC->ALARM0);
  206. #ifdef RT_ALARM_USING_LOCAL_TIME
  207. localtime_r(&alarm_time, &alarm_tm);
  208. #else
  209. gmtime_r(&alarm_time, &alarm_tm);
  210. #endif
  211. alarm->tm_sec = alarm_tm.tm_sec;
  212. alarm->tm_min = alarm_tm.tm_min;
  213. alarm->tm_hour = alarm_tm.tm_hour;
  214. alarm->tm_mday = alarm_tm.tm_mday;
  215. alarm->tm_mon = alarm_tm.tm_mon;
  216. alarm->tm_year = alarm_tm.tm_year;
  217. return RT_EOK;
  218. #else
  219. return -RT_EINVAL;
  220. #endif
  221. }
  222. int rt_hw_rtc_init(void)
  223. {
  224. rt_err_t err = RT_EOK;
  225. err = rt_device_register(&hpm_rtc, "rtc", RT_DEVICE_FLAG_RDWR);
  226. if (err != RT_EOK) {
  227. LOG_E("rt device %s failed, status=%d\n", "rtc", err);
  228. return err;
  229. }
  230. rt_device_open(&hpm_rtc, RT_DEVICE_FLAG_RDWR);
  231. return RT_EOK;
  232. }
  233. INIT_DEVICE_EXPORT(rt_hw_rtc_init);
  234. #endif /* RT_USING_RTC */