1 /*
2 * Copyright (c) 2006-2022, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2011-02-21 onelife Initial creation for EFM32
9 * 2011-06-17 onelife Modify init and control function for efm32lib v2 upgrading
10 */
11
12 /***************************************************************************//**
13 * @addtogroup efm32
14 * @{
15 ******************************************************************************/
16
17 /* Includes ------------------------------------------------------------------*/
18 #include "board.h"
19 #include "drv_acmp.h"
20
21 #if (defined(RT_USING_ACMP0) || defined(RT_USING_ACMP1))
22 /* Private typedef -----------------------------------------------------------*/
23 /* Private define ------------------------------------------------------------*/
24 /* Private macro -------------------------------------------------------------*/
25 #ifdef RT_ACMP_DEBUG
26 #define acmp_debug(format,args...) rt_kprintf(format, ##args)
27 #else
28 #define acmp_debug(format,args...)
29 #endif
30
31 /* Private variables ---------------------------------------------------------*/
32 #ifdef RT_USING_ACMP0
33 static struct rt_device acmp0_device;
34 #endif
35
36 #ifdef RT_USING_ACMP1
37 static struct rt_device acmp1_device;
38 #endif
39
40 /* Private function prototypes -----------------------------------------------*/
41 ACMP_WarmTime_TypeDef efm32_acmp_WarmTimeCalc(rt_uint32_t hfperFreq);
42
43 /* Private functions ---------------------------------------------------------*/
44 /***************************************************************************//**
45 * @brief
46 * Initialize ACMP device
47 *
48 * @details
49 *
50 * @note
51 *
52 * @param[in] dev
53 * Pointer to device descriptor
54 *
55 * @return
56 * Error code
57 ******************************************************************************/
rt_acmp_init(rt_device_t dev)58 static rt_err_t rt_acmp_init(rt_device_t dev)
59 {
60 RT_ASSERT(dev != RT_NULL);
61
62 struct efm32_acmp_device_t *acmp;
63
64 acmp = (struct efm32_acmp_device_t *)(dev->user_data);
65
66 acmp->hook.cbFunc = RT_NULL;
67 acmp->hook.userPtr = RT_NULL;
68
69 return RT_EOK;
70 }
71
72 /***************************************************************************//**
73 * @brief
74 * Configure ACMP device
75 *
76 * @details
77 *
78 * @note
79 *
80 * @param[in] dev
81 * Pointer to device descriptor
82 *
83 * @param[in] cmd
84 * ACMP control command
85 *
86 * @param[in] args
87 * Arguments
88 *
89 * @return
90 * Error code
91 ******************************************************************************/
rt_acmp_control(rt_device_t dev,rt_uint8_t cmd,void * args)92 static rt_err_t rt_acmp_control(
93 rt_device_t dev,
94 rt_uint8_t cmd,
95 void *args)
96 {
97 RT_ASSERT(dev != RT_NULL);
98
99 struct efm32_acmp_device_t *acmp;
100
101 acmp = (struct efm32_acmp_device_t *)(dev->user_data);
102
103 switch (cmd)
104 {
105 case RT_DEVICE_CTRL_SUSPEND:
106 /* Suspend device */
107 dev->flag |= RT_DEVICE_FLAG_SUSPENDED;
108 ACMP_Disable(acmp->acmp_device);
109 break;
110
111 case RT_DEVICE_CTRL_RESUME:
112 /* Resume device */
113 dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED;
114 ACMP_Enable(acmp->acmp_device);
115 break;
116
117 case RT_DEVICE_CTRL_ACMP_INIT:
118 {
119 rt_bool_t int_en = false;
120 struct efm32_acmp_control_t *control;
121
122 control = (struct efm32_acmp_control_t *)args;
123 acmp_debug("ACMP: control -> init start\n");
124
125 /* Configure ACMPn */
126 if (control->init == RT_NULL)
127 {
128 return -RT_ERROR;
129 }
130 ACMP_Init(acmp->acmp_device, control->init);
131 ACMP_ChannelSet(acmp->acmp_device, control->negInput, control->posInput);
132 if (control->output != RT_NULL)
133 {
134 ACMP_GPIOSetup(
135 acmp->acmp_device,
136 control->output->location,
137 control->output->enable,
138 control->output->invert);
139 int_en = true;
140 }
141 if (control->hook.cbFunc != RT_NULL)
142 {
143 acmp->hook.cbFunc = control->hook.cbFunc;
144 acmp->hook.userPtr = control->hook.userPtr;
145 int_en = true;
146 }
147
148 if (int_en)
149 {
150 /* Enable edge interrupt */
151 ACMP_IntEnable(acmp->acmp_device, ACMP_IEN_EDGE);
152 ACMP_IntClear(acmp->acmp_device, ACMP_IFC_EDGE);
153
154 /* Enable ACMP0/1 interrupt vector in NVIC */
155 NVIC_ClearPendingIRQ(ACMP0_IRQn);
156 NVIC_SetPriority(ACMP0_IRQn, EFM32_IRQ_PRI_DEFAULT);
157 NVIC_EnableIRQ(ACMP0_IRQn);
158 }
159 }
160 break;
161
162 case RT_DEVICE_CTRL_ACMP_OUTPUT:
163 *((rt_bool_t *)args) = \
164 (acmp->acmp_device->STATUS & ACMP_STATUS_ACMPOUT) ? true : false;
165 break;
166
167 default:
168 return -RT_ERROR;
169 }
170
171 return RT_EOK;
172 }
173
174 /***************************************************************************//**
175 * @brief
176 * Register ACMP device
177 *
178 * @details
179 *
180 * @note
181 *
182 * @param[in] device
183 * Pointer to device descriptor
184 *
185 * @param[in] name
186 * Device name
187 *
188 * @param[in] flag
189 * Configuration flags
190 *
191 * @param[in] acmp
192 * Pointer to ACMP device descriptor
193 *
194 * @return
195 * Error code
196 ******************************************************************************/
rt_hw_acmp_register(rt_device_t device,const char * name,rt_uint32_t flag,struct efm32_acmp_device_t * acmp)197 rt_err_t rt_hw_acmp_register(
198 rt_device_t device,
199 const char *name,
200 rt_uint32_t flag,
201 struct efm32_acmp_device_t *acmp)
202 {
203 RT_ASSERT(device != RT_NULL);
204
205 device->type = RT_Device_Class_Char; /* fixme: should be acmp type */
206 device->rx_indicate = RT_NULL;
207 device->tx_complete = RT_NULL;
208 device->init = rt_acmp_init;
209 device->open = RT_NULL;
210 device->close = RT_NULL;
211 device->read = RT_NULL;
212 device->write = RT_NULL;
213 device->control = rt_acmp_control;
214 device->user_data = acmp;
215
216 /* register a character device */
217 return rt_device_register(device, name, flag);
218 }
219
220 /***************************************************************************//**
221 * @brief
222 * ACMP edge trigger interrupt handler
223 *
224 * @details
225 *
226 * @note
227 ******************************************************************************/
rt_hw_acmp_isr(rt_device_t dev)228 void rt_hw_acmp_isr(rt_device_t dev)
229 {
230 RT_ASSERT(dev != RT_NULL);
231
232 struct efm32_acmp_device_t *acmp;
233
234 acmp = (struct efm32_acmp_device_t *)(dev->user_data);
235
236 if (acmp->hook.cbFunc != RT_NULL)
237 {
238 (acmp->hook.cbFunc)(acmp->hook.userPtr);
239 }
240 }
241
242 /***************************************************************************//**
243 * @brief
244 * Initialize the specified ACMP unit
245 *
246 * @details
247 *
248 * @note
249 *
250 * @param[in] device
251 * Pointer to device descriptor
252 *
253 * @param[in] unitNumber
254 * Unit number
255 *
256 * @return
257 * Pointer to ACMP device
258 ******************************************************************************/
rt_hw_acmp_unit_init(rt_device_t device,rt_uint8_t unitNumber)259 static struct efm32_acmp_device_t *rt_hw_acmp_unit_init(
260 rt_device_t device,
261 rt_uint8_t unitNumber)
262 {
263 struct efm32_acmp_device_t *acmp;
264 efm32_irq_hook_init_t hook;
265 CMU_Clock_TypeDef acmpClock;
266
267 do
268 {
269 /* Allocate device */
270 acmp = rt_malloc(sizeof(struct efm32_acmp_device_t));
271 if (acmp == RT_NULL)
272 {
273 acmp_debug("ACMP err: no mem for ACMP%d\n", unitNumber);
274 break;
275 }
276
277 /* Initialization */
278 if (unitNumber >= ACMP_COUNT)
279 {
280 break;
281 }
282 switch (unitNumber)
283 {
284 case 0:
285 acmp->acmp_device = ACMP0;
286 acmpClock = (CMU_Clock_TypeDef)cmuClock_ACMP0;
287 break;
288
289 case 1:
290 acmp->acmp_device = ACMP1;
291 acmpClock = (CMU_Clock_TypeDef)cmuClock_ACMP1;
292 break;
293
294 default:
295 break;
296 }
297
298 /* Enable ACMP clock */
299 CMU_ClockEnable(acmpClock, true);
300
301 /* Reset */
302 ACMP_Reset(acmp->acmp_device);
303
304 /* Config interrupt and NVIC */
305 hook.type = efm32_irq_type_acmp;
306 hook.unit = unitNumber;
307 hook.cbFunc = rt_hw_acmp_isr;
308 hook.userPtr = device;
309 efm32_irq_hook_register(&hook);
310
311 return acmp;
312 } while(0);
313
314 if (acmp)
315 {
316 rt_free(acmp);
317 }
318 rt_kprintf("ACMP: Init failed!\n");
319 return RT_NULL;
320 }
321
322 /***************************************************************************//**
323 * @brief
324 * Initialize all ACMP module related hardware and register ACMP device to
325 * kernel
326 *
327 * @details
328 *
329 * @note
330 *
331 ******************************************************************************/
rt_hw_acmp_init(void)332 void rt_hw_acmp_init(void)
333 {
334 struct efm32_acmp_device_t *acmp;
335
336 #ifdef RT_USING_ACMP0
337 if ((acmp = rt_hw_acmp_unit_init(&acmp0_device, 0)) != RT_NULL)
338 {
339 rt_hw_acmp_register(&acmp0_device, RT_ACMP0_NAME, EFM32_NO_DATA, acmp);
340 }
341 #endif
342
343 #ifdef RT_USING_ACMP1
344 if ((acmp = rt_hw_acmp_unit_init(&acmp1_device, 1)) != RT_NULL)
345 {
346 rt_hw_acmp_register(&acmp1_device, RT_ACMP1_NAME, EFM32_NO_DATA, acmp);
347 }
348 #endif
349
350 }
351
352 /***************************************************************************//**
353 * @brief
354 * Calculate the warm-up time value providing at least 10us
355 *
356 * @param[in] hfperFreq
357 * Frequency in Hz of reference HFPER clock. Set to 0 to use currently defined
358 * HFPER clock setting
359 *
360 * @return
361 * Warm-up time value to use for ACMP in order to achieve at least 10us
362 ******************************************************************************/
efm32_acmp_WarmTimeCalc(rt_uint32_t hfperFreq)363 ACMP_WarmTime_TypeDef efm32_acmp_WarmTimeCalc(rt_uint32_t hfperFreq)
364 {
365 if (!hfperFreq)
366 {
367 hfperFreq = CMU_ClockFreqGet(cmuClock_HFPER);
368
369 /* Just in case, make sure we get non-zero freq for below calculation */
370 if (!hfperFreq)
371 {
372 hfperFreq = 1;
373 }
374 }
375
376 /* Determine number of HFPERCLK cycle >= 10us */
377 if (4 * 1000000 / hfperFreq > 10)
378 {
379 return acmpWarmTime4;
380 }
381 else if (8 * 1000000 / hfperFreq > 10)
382 {
383 return acmpWarmTime8;
384 }
385 else if (16 * 1000000 / hfperFreq > 10)
386 {
387 return acmpWarmTime16;
388 }
389 else if (32 * 1000000 / hfperFreq > 10)
390 {
391 return acmpWarmTime32;
392 }
393 else if (64 * 1000000 / hfperFreq > 10)
394 {
395 return acmpWarmTime64;
396 }
397 else if (128 * 1000000 / hfperFreq > 10)
398 {
399 return acmpWarmTime128;
400 }
401 else if (256 * 1000000 / hfperFreq > 10)
402 {
403 return acmpWarmTime256;
404 }
405 else if (512 * 1000000 / hfperFreq > 10)
406 {
407 return acmpWarmTime512;
408 }
409 }
410
411 #endif
412 /***************************************************************************//**
413 * @}
414 ******************************************************************************/
415