1 /*
2  *  Copyright (C) 2017-2024 Alibaba Group Holding Limited
3  */
4 
5 /*******************************************************
6  * @file    dw_timer.c
7  * @brief   source file for timer csi driver
8  * @version V1.0
9  * @date    28. Apr 2020
10  * ******************************************************/
11 
12 #include <csi_config.h>
13 #include <drv/timer.h>
14 #include <drv/irq.h>
15 #include "dw_timer_ll.h"
16 
17 /**
18   \brief       Timer interrupt handling function
19   \param[in]   arg    Callback function member variables
20   \return      None
21 */
dw_timer_irq_handler(void * arg)22 void dw_timer_irq_handler(void *arg)
23 {
24     csi_timer_t *timer = (csi_timer_t *)arg;
25     dw_timer_regs_t *timer_base = (dw_timer_regs_t *)timer->dev.reg_base;
26 
27     if (dw_timer_get_int_status(timer_base)) {
28         if (timer->callback) {
29             timer->callback(timer, timer->arg);
30         }
31 
32         dw_timer_clear_irq(timer_base);
33     }
34 }
35 #if CONFIG_SUPPORT_NMI_DEMO
timer_clear_irq()36 void timer_clear_irq()
37 {
38     dw_timer_clear_irq((dw_timer_regs_t*)DW_TIMER4_BASE);
39 }
40 #endif
41 /**
42   \brief       Initialize TIMER Interface. 1. Initializes the resources needed for the TIMER interface 2.registers callback function
43   \param[in]   timer    handle timer handle to operate
44   \param[in]   idx      timer index
45   \return      error code \ref csi_error_t
46 */
csi_timer_init(csi_timer_t * timer,uint32_t idx)47 csi_error_t csi_timer_init(csi_timer_t *timer, uint32_t idx)
48 {
49     CSI_PARAM_CHK(timer, CSI_ERROR);
50 
51     csi_error_t ret = CSI_OK;
52     dw_timer_regs_t *timer_base = NULL;
53 
54     if (0 == target_get(DEV_DW_TIMER_TAG, idx, &timer->dev)) {
55         timer_base = (dw_timer_regs_t *)HANDLE_REG_BASE(timer);
56         memset((void *)timer_base, 0, sizeof(dw_timer_regs_t));
57 
58     } else {
59         ret = CSI_ERROR;
60     }
61 
62     return ret;
63 }
64 /**
65   \brief       De-initialize TIMER Interface. stops operation and releases the software resources used by the interface
66   \param[in]   timer    handle timer handle to operate
67   \return      None
68 */
csi_timer_uninit(csi_timer_t * timer)69 void csi_timer_uninit(csi_timer_t *timer)
70 {
71     CSI_PARAM_CHK_NORETVAL(timer);
72     dw_timer_regs_t *timer_base = (dw_timer_regs_t *)HANDLE_REG_BASE(timer);
73 
74     memset((void *)timer_base, 0, sizeof(dw_timer_regs_t));
75 }
76 /**
77   \brief       Start timer
78   \param[in]   timer         handle timer handle to operate
79   \param[in]   timeout_us    the timeout for timer
80   \return      error code \ref csi_error_t
81 */
csi_timer_start(csi_timer_t * timer,uint32_t timeout_us)82 csi_error_t csi_timer_start(csi_timer_t *timer, uint32_t timeout_us)
83 {
84     CSI_PARAM_CHK(timer, CSI_ERROR);
85     CSI_PARAM_CHK(timeout_us, CSI_ERROR);
86     csi_error_t ret = CSI_OK;
87     dw_timer_regs_t *timer_base = (dw_timer_regs_t *)HANDLE_REG_BASE(timer);
88     uint32_t tmp_load = timeout_us * (soc_get_timer_freq((uint32_t)timer->dev.idx) / 1000000U);
89 
90     dw_timer_set_mode_load(timer_base);
91     dw_timer_write_load(timer_base, tmp_load);
92 
93     dw_timer_set_disable(timer_base);
94     dw_timer_set_enable(timer_base);
95     dw_timer_set_unmask(timer_base);
96 
97     return ret;
98 }
99 /**
100   \brief       Stop timer
101   \param[in]   timer    handle timer handle to operate
102   \return      None
103 */
csi_timer_stop(csi_timer_t * timer)104 void csi_timer_stop(csi_timer_t *timer)
105 {
106     CSI_PARAM_CHK_NORETVAL(timer);
107 
108     dw_timer_regs_t *timer_base;
109     timer_base = (dw_timer_regs_t *)HANDLE_REG_BASE(timer);
110 
111     dw_timer_set_mask(timer_base);
112     dw_timer_set_disable(timer_base);
113 }
114 /**
115   \brief       Get timer remaining value
116   \param[in]   timer    handle timer handle to operate
117   \return      the remaining value
118 */
csi_timer_get_remaining_value(csi_timer_t * timer)119 uint32_t csi_timer_get_remaining_value(csi_timer_t *timer)
120 {
121     CSI_PARAM_CHK(timer, 0U);
122 
123     dw_timer_regs_t *timer_base;
124     timer_base = (dw_timer_regs_t *)HANDLE_REG_BASE(timer);
125     return dw_timer_get_current(timer_base);
126 }
127 /**
128   \brief       Get timer load value
129   \param[in]   timer    handle timer handle to operate
130   \return      the load value
131 */
csi_timer_get_load_value(csi_timer_t * timer)132 uint32_t csi_timer_get_load_value(csi_timer_t *timer)
133 {
134     CSI_PARAM_CHK(timer, 0U);
135 
136     dw_timer_regs_t *timer_base = (dw_timer_regs_t *)HANDLE_REG_BASE(timer);
137 
138     return (dw_timer_read_load(timer_base));
139 }
140 /**
141   \brief       Check timer is running
142   \param[in]   timer    handle timer handle to operate
143   \return      true->running, false->stopped
144 */
csi_timer_is_running(csi_timer_t * timer)145 bool csi_timer_is_running(csi_timer_t *timer)
146 {
147     CSI_PARAM_CHK(timer, false);
148 
149     dw_timer_regs_t *timer_base = (dw_timer_regs_t *)HANDLE_REG_BASE(timer);
150 
151     return (dw_timer_get_enable(timer_base) ? true : false);
152 }
153 
154 /**
155   \brief       Attach the callback handler to timer
156   \param[in]   timer       operate handle.
157   \param[in]   callback    callback function
158   \param[in]   arg         callback's param
159   \return      error code \ref csi_error_t
160 */
csi_timer_attach_callback(csi_timer_t * timer,void * callback,void * arg)161 csi_error_t csi_timer_attach_callback(csi_timer_t *timer, void *callback, void *arg)
162 {
163     CSI_PARAM_CHK(timer, CSI_ERROR);
164 
165     timer->callback = callback;
166     timer->arg = arg;
167     csi_irq_attach((uint32_t)timer->dev.irq_num, &dw_timer_irq_handler, &timer->dev);
168     csi_irq_enable((uint32_t)timer->dev.irq_num);
169 
170     return CSI_OK;
171 }
172 
173 /**
174   \brief       Detach the callback handler
175   \param[in]   timer    operate handle.
176 */
csi_timer_detach_callback(csi_timer_t * timer)177 void csi_timer_detach_callback(csi_timer_t *timer)
178 {
179     CSI_PARAM_CHK_NORETVAL(timer);
180 
181     timer->callback = NULL;
182     timer->arg = NULL;
183     csi_irq_disable((uint32_t)timer->dev.irq_num);
184     csi_irq_detach((uint32_t)timer->dev.irq_num);
185 }
186 
187 #ifdef CONFIG_PM
dw_timer_pm_action(csi_dev_t * dev,csi_pm_dev_action_t action)188 csi_error_t dw_timer_pm_action(csi_dev_t *dev, csi_pm_dev_action_t action)
189 {
190     CSI_PARAM_CHK(dev, CSI_ERROR);
191 
192     csi_error_t ret = CSI_OK;
193     csi_pm_dev_t *pm_dev = &dev->pm_dev;
194 
195     switch (action) {
196     case PM_DEV_SUSPEND:
197         csi_pm_dev_save_regs(pm_dev->reten_mem, (uint32_t *)dev->reg_base, 1U);
198         csi_pm_dev_save_regs(pm_dev->reten_mem + 1, (uint32_t *)(dev->reg_base + 8U), 1U);
199         break;
200 
201     case PM_DEV_RESUME:
202         csi_pm_dev_restore_regs(pm_dev->reten_mem, (uint32_t *)dev->reg_base, 1U);
203         csi_pm_dev_restore_regs(pm_dev->reten_mem + 1, (uint32_t *)(dev->reg_base + 8U), 1U);
204         break;
205 
206     default:
207         ret = CSI_ERROR;
208         break;
209     }
210 
211     return ret;
212 }
213 
csi_timer_enable_pm(csi_timer_t * timer)214 csi_error_t csi_timer_enable_pm(csi_timer_t *timer)
215 {
216     return csi_pm_dev_register(&timer->dev, dw_timer_pm_action, 8U, 0U);
217 }
218 
csi_timer_disable_pm(csi_timer_t * timer)219 void csi_timer_disable_pm(csi_timer_t *timer)
220 {
221     csi_pm_dev_unregister(&timer->dev);
222 }
223 #endif
224 
225