1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author         Notes
8  * 2021-11-4      GuEe-GUI       first version
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include <sys/time.h>
14 #include <board.h>
15 
16 #include "drv_rtc.h"
17 
18 #ifdef BSP_USING_RTC
19 
20 #define RTC_DR      0x00    /* data read register */
21 #define RTC_MR      0x04    /* match register */
22 #define RTC_LR      0x08    /* data load register */
23 #define RTC_CR      0x0c    /* control register */
24 #define RTC_IMSC    0x10    /* interrupt mask and set register */
25 #define RTC_RIS     0x14    /* raw interrupt status register */
26 #define RTC_MIS     0x18    /* masked interrupt status register */
27 #define RTC_ICR     0x1c    /* interrupt clear register */
28 
29 #define RTC_CR_OPEN     1
30 #define RTC_CR_CLOSE    0
31 
32 static struct hw_rtc_device rtc_device;
33 static rt_ubase_t pl031_rtc_base = PL031_RTC_BASE;
34 
pl031_read32(rt_ubase_t offset)35 rt_inline rt_uint32_t pl031_read32(rt_ubase_t offset)
36 {
37     return (*((volatile unsigned int *)(pl031_rtc_base + offset)));
38 }
39 
pl031_write32(rt_ubase_t offset,rt_uint32_t value)40 rt_inline void pl031_write32(rt_ubase_t offset, rt_uint32_t value)
41 {
42     (*((volatile unsigned int *)(pl031_rtc_base + offset))) = value;
43 }
44 
pl031_rtc_init(rt_device_t dev)45 static rt_err_t pl031_rtc_init(rt_device_t dev)
46 {
47     return RT_EOK;
48 }
49 
pl031_rtc_open(rt_device_t dev,rt_uint16_t oflag)50 static rt_err_t pl031_rtc_open(rt_device_t dev, rt_uint16_t oflag)
51 {
52     pl031_write32(RTC_CR, RTC_CR_OPEN);
53     return RT_EOK;
54 }
55 
pl031_rtc_close(rt_device_t dev)56 static rt_err_t pl031_rtc_close(rt_device_t dev)
57 {
58     pl031_write32(RTC_CR, RTC_CR_CLOSE);
59     return RT_EOK;
60 }
61 
pl031_rtc_control(rt_device_t dev,int cmd,void * args)62 static rt_err_t pl031_rtc_control(rt_device_t dev, int cmd, void *args)
63 {
64 
65     RT_ASSERT(dev != RT_NULL);
66 
67     switch (cmd)
68     {
69     case RT_DEVICE_CTRL_RTC_GET_TIME:
70         *(rt_uint32_t *)args = pl031_read32(RTC_DR);
71         break;
72     case RT_DEVICE_CTRL_RTC_SET_TIME:
73         pl031_write32(RTC_LR, *(time_t *)args);
74         break;
75     default:
76         return -RT_EINVAL;
77     }
78     return RT_EOK;
79 }
80 
pl031_rtc_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)81 static rt_ssize_t pl031_rtc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
82 {
83     pl031_rtc_control(dev, RT_DEVICE_CTRL_RTC_GET_TIME, buffer);
84     return size;
85 }
86 
pl031_rtc_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)87 static rt_ssize_t pl031_rtc_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
88 {
89     pl031_rtc_control(dev, RT_DEVICE_CTRL_RTC_SET_TIME, (void *)buffer);
90     return size;
91 }
92 
93 const static struct rt_device_ops pl031_rtc_ops =
94 {
95     .init = pl031_rtc_init,
96     .open = pl031_rtc_open,
97     .close = pl031_rtc_close,
98     .read = pl031_rtc_read,
99     .write = pl031_rtc_write,
100     .control = pl031_rtc_control
101 };
102 
rt_hw_rtc_init(void)103 int rt_hw_rtc_init(void)
104 {
105     pl031_rtc_base = (rt_size_t)rt_ioremap((void *)pl031_rtc_base, PL031_RTC_SIZE);
106 
107     rt_memset(&rtc_device, 0, sizeof(rtc_device));
108 
109     rtc_device.device.type        = RT_Device_Class_RTC;
110     rtc_device.device.rx_indicate = RT_NULL;
111     rtc_device.device.tx_complete = RT_NULL;
112     rtc_device.device.ops         = &pl031_rtc_ops;
113     rtc_device.device.user_data   = RT_NULL;
114 
115     /* register a rtc device */
116     rt_device_register(&rtc_device.device, "rtc0", RT_DEVICE_FLAG_RDWR);
117     rt_soft_rtc_set_source("rtc0");
118     return 0;
119 }
120 INIT_DEVICE_EXPORT(rt_hw_rtc_init);
121 #endif /* BSP_USING_RTC */
122