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-12-09   onelife     Initial creation for EFM32
9  * 2011-12-27   onelife     Utilize "LEUART_PRESENT" and "LEUART_COUNT"
10  */
11 
12 /***************************************************************************//**
13  * @addtogroup efm32
14  * @{
15  ******************************************************************************/
16 
17 /* Includes ------------------------------------------------------------------*/
18 #include "board.h"
19 #include "hdl_interrupt.h"
20 #include "drv_leuart.h"
21 
22 #if (defined(RT_USING_LEUART0) || defined(RT_USING_LEUART1))
23  #if !defined(LEUART_PRESENT)
24  #error "LEUART module is not available"
25  #endif
26 /* Private typedef -----------------------------------------------------------*/
27 /* Private define ------------------------------------------------------------*/
28 /* Private macro -------------------------------------------------------------*/
29 #ifdef RT_LEUART_DEBUG
30 #define leuart_debug(format,args...)        rt_kprintf(format, ##args)
31 #else
32 #define leuart_debug(format,args...)
33 #endif
34 
35 /* Private variables ---------------------------------------------------------*/
36 #if defined(RT_USING_LEUART0)
37  #if (RT_USING_LEUART0 >= EFM32_LEUART_LOCATION_COUNT)
38     #error "Wrong location number"
39  #endif
40     struct rt_device leuart0_device;
41     static struct rt_semaphore leuart0_lock;
42 #endif
43 
44 #if defined(RT_USING_LEUART1)
45  #if (LEUART_COUNT <= 1)
46  #error "Wrong unit number"
47  #endif
48  #if (RT_USING_LEUART1 >= EFM32_LEUART_LOCATION_COUNT)
49     #error "Wrong location number"
50  #endif
51     struct rt_device leuart1_device;
52     static struct rt_semaphore leuart1_lock;
53 #endif
54 
55 /* Private function prototypes -----------------------------------------------*/
56 /* Private functions ---------------------------------------------------------*/
57 /***************************************************************************//**
58  * @brief
59  *   Initialize LEUART device
60  *
61  * @details
62  *
63  * @note
64  *
65  * @param[in] dev
66  *   Pointer to device descriptor
67  *
68  * @return
69  *   Error code
70  ******************************************************************************/
rt_leuart_init(rt_device_t dev)71 static rt_err_t rt_leuart_init (rt_device_t dev)
72 {
73     struct efm32_leuart_device_t *leuart;
74 
75     leuart = (struct efm32_leuart_device_t *)(dev->user_data);
76 
77     if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED))
78     {
79         if (dev->flag & RT_DEVICE_FLAG_DMA_TX)
80         {
81             struct efm32_leuart_dma_mode_t *dma_tx;
82 
83             dma_tx = (struct efm32_leuart_dma_mode_t *)(leuart->tx_mode);
84 
85             leuart->state |= LEUART_STATE_RX_BUSY;
86         }
87 
88         if (dev->flag & RT_DEVICE_FLAG_INT_RX)
89         {
90             struct efm32_leuart_int_mode_t *int_rx;
91 
92             int_rx = (struct efm32_leuart_int_mode_t *)(leuart->rx_mode);
93 
94             int_rx->data_ptr = RT_NULL;
95         }
96 
97         /* Enable LEUART */
98         LEUART_Enable(leuart->leuart_device, leuartEnable);
99 
100         dev->flag |= RT_DEVICE_FLAG_ACTIVATED;
101     }
102 
103     return RT_EOK;
104 }
105 
106 /***************************************************************************//**
107  * @brief
108  *   Open LEUART device
109  *
110  * @details
111  *
112  * @note
113  *
114  * @param[in] dev
115  *   Pointer to device descriptor
116  *
117  * @param[in] oflag
118  *   Device open flag
119  *
120  * @return
121  *   Error code
122  ******************************************************************************/
rt_leuart_open(rt_device_t dev,rt_uint16_t oflag)123 static rt_err_t rt_leuart_open(rt_device_t dev, rt_uint16_t oflag)
124 {
125     RT_ASSERT(dev != RT_NULL);
126 
127     struct efm32_leuart_device_t    *leuart;
128 
129     leuart = (struct efm32_leuart_device_t *)(dev->user_data);
130 
131     if (dev->flag & RT_DEVICE_FLAG_INT_RX)
132     {
133         IRQn_Type                   rxIrq;
134 
135         //if (leuart->state & LEUART_STATE_CONSOLE)
136         {   /* Allocate new RX buffer */
137             struct efm32_leuart_int_mode_t  *int_mode;
138 
139             int_mode = (struct efm32_leuart_int_mode_t *)(leuart->rx_mode);
140 
141             if ((int_mode->data_ptr = rt_malloc(LEUART_RX_BUFFER_SIZE)) == RT_NULL)
142             {
143                 leuart_debug("LEUART%d err: no mem for RX BUF\n", leuart->unit);
144                 return -RT_ENOMEM;
145             }
146             rt_memset(int_mode->data_ptr, 0, LEUART_RX_BUFFER_SIZE);
147             int_mode->data_size = LEUART_RX_BUFFER_SIZE;
148             int_mode->read_index = 0;
149             int_mode->save_index = 0;
150         }
151 
152         /* Enable RX interrupt */
153         leuart->leuart_device->IEN  = LEUART_IEN_RXDATAV;
154 
155         /* Enable IRQ */
156         switch (leuart->unit)
157         {
158         case 0:
159             rxIrq   = LEUART0_IRQn;
160             break;
161 #if (LEUART_COUNT > 1)
162         case 1:
163             rxIrq   = LEUART1_IRQn;
164             break;
165 #endif
166         }
167         if (oflag != RT_DEVICE_OFLAG_WRONLY)
168         {
169             NVIC_ClearPendingIRQ(rxIrq);
170             NVIC_SetPriority(rxIrq, EFM32_IRQ_PRI_DEFAULT);
171             NVIC_EnableIRQ(rxIrq);
172         }
173     }
174 
175     /* Clear Flag */
176     leuart->leuart_device->IFC      = _LEUART_IFC_MASK;
177 
178     if ((dev->flag & RT_DEVICE_FLAG_DMA_TX) && (oflag != RT_DEVICE_OFLAG_RDONLY))
179     {
180         /* DMA IRQ is enabled by DMA_Init() */
181         NVIC_SetPriority(DMA_IRQn, EFM32_IRQ_PRI_DEFAULT);
182     }
183 
184     leuart->counter++;
185     leuart_debug("LEUART%d: Open with flag %x\n", leuart->unit, oflag);
186     return RT_EOK;
187 }
188 
189 /***************************************************************************//**
190  * @brief
191  *   Close LEUART device
192  *
193  * @details
194  *
195  * @note
196  *
197  * @param[in] dev
198  *   Pointer to device descriptor
199  *
200  * @return
201  *   Error code
202  ******************************************************************************/
rt_leuart_close(rt_device_t dev)203 static rt_err_t rt_leuart_close(rt_device_t dev)
204 {
205     RT_ASSERT(dev != RT_NULL);
206 
207     struct efm32_leuart_device_t    *leuart;
208 
209     leuart = (struct efm32_leuart_device_t *)(dev->user_data);
210 
211     if (--leuart->counter == 0)
212     {
213         if (dev->flag & RT_DEVICE_FLAG_INT_RX)
214         {
215             struct efm32_leuart_int_mode_t *int_rx;
216 
217             int_rx = (struct efm32_leuart_int_mode_t *)leuart->rx_mode;
218 
219             rt_free(int_rx->data_ptr);
220             int_rx->data_ptr = RT_NULL;
221         }
222     }
223 
224     return RT_EOK;
225 }
226 
227 /***************************************************************************//**
228  * @brief
229  *   Read from LEUART device
230  *
231  * @details
232  *
233  * @note
234  *
235  * @param[in] dev
236  *   Pointer to device descriptor
237  *
238  * @param[in] pos
239  *   Offset
240  *
241  * @param[in] buffer
242  *   Poniter to the buffer
243  *
244  * @param[in] size
245  *   Buffer size in byte
246  *
247  * @return
248  *   Number of read bytes
249  ******************************************************************************/
rt_leuart_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)250 static rt_ssize_t rt_leuart_read (
251     rt_device_t     dev,
252     rt_off_t        pos,
253     void            *buffer,
254     rt_size_t       size)
255 {
256     struct efm32_leuart_device_t *leuart;
257     rt_uint8_t  *ptr;
258     rt_err_t    err_code;
259     rt_size_t   read_len;
260 
261     leuart = (struct efm32_leuart_device_t *)(dev->user_data);
262 
263     /* Lock device */
264     if (rt_hw_interrupt_check())
265     {
266         err_code = rt_sem_take(leuart->lock, RT_WAITING_NO);
267     }
268     else
269     {
270         err_code = rt_sem_take(leuart->lock, RT_WAITING_FOREVER);
271     }
272     if (err_code != RT_EOK)
273     {
274         rt_set_errno(err_code);
275         return 0;
276     }
277 
278     if (dev->flag & RT_DEVICE_FLAG_INT_RX)
279     {
280         ptr = buffer;
281 
282         /* interrupt mode Rx */
283         while (size)
284         {
285             rt_base_t level;
286             struct efm32_leuart_int_mode_t *int_rx;
287 
288             int_rx = (struct efm32_leuart_int_mode_t *)\
289                 (((struct efm32_leuart_device_t *)(dev->user_data))->rx_mode);
290 
291             /* disable interrupt */
292             level = rt_hw_interrupt_disable();
293 
294             if (int_rx->read_index != int_rx->save_index)
295             {
296                 /* read a character */
297                 *ptr++ = int_rx->data_ptr[int_rx->read_index];
298                 size--;
299 
300                 /* move to next position */
301                 int_rx->read_index ++;
302                 if (int_rx->read_index >= LEUART_RX_BUFFER_SIZE)
303                 {
304                     int_rx->read_index = 0;
305                 }
306             }
307             else
308             {
309                 /* set error code */
310                 err_code = -RT_EEMPTY;
311 
312                 /* enable interrupt */
313                 rt_hw_interrupt_enable(level);
314                 break;
315             }
316 
317             /* enable interrupt */
318             rt_hw_interrupt_enable(level);
319         }
320 
321         read_len = (rt_uint32_t)ptr - (rt_uint32_t)buffer;
322     }
323     else
324     {
325         LEUART_TypeDef *leuart_device;
326 
327         leuart = (struct efm32_leuart_device_t *)(dev->user_data);
328         leuart_device = ((struct efm32_leuart_device_t *)(dev->user_data))->leuart_device;
329         ptr = buffer;
330 
331         /* polling mode */
332         while ((rt_uint32_t)ptr - (rt_uint32_t)buffer < size)
333         {
334             while (leuart_device->STATUS & LEUART_STATUS_RXDATAV)
335             {
336                 *ptr = leuart_device->RXDATA & 0xff;
337                 ptr ++;
338             }
339         }
340 
341         read_len = size;
342     }
343 
344     /* Unlock device */
345     rt_sem_release(leuart->lock);
346 
347     /* set error code */
348     rt_set_errno(err_code);
349     return read_len;
350 }
351 
352 /***************************************************************************//**
353  * @brief
354  *   Write to LEUART device
355  *
356  * @details
357  *
358  * @note
359  *
360  * @param[in] dev
361  *   Pointer to device descriptor
362  *
363  * @param[in] pos
364  *   Offset
365  *
366  * @param[in] buffer
367  *   Poniter to the buffer
368  *
369  * @param[in] size
370  *   Buffer size in byte
371  *
372  * @return
373  *   Number of written bytes
374  ******************************************************************************/
rt_leuart_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)375 static rt_ssize_t rt_leuart_write (
376     rt_device_t     dev,
377     rt_off_t        pos,
378     const void*     buffer,
379     rt_size_t       size)
380 {
381     rt_err_t                        err_code;
382     rt_size_t                       write_size;
383     struct efm32_leuart_device_t*   leuart;
384 
385     write_size = 0;
386     leuart = (struct efm32_leuart_device_t*)(dev->user_data);
387 
388     /* Lock device */
389     if (rt_hw_interrupt_check())
390     {
391         err_code = rt_sem_take(leuart->lock, RT_WAITING_NO);
392     }
393     else
394     {
395         err_code = rt_sem_take(leuart->lock, RT_WAITING_FOREVER);
396     }
397     if (err_code != RT_EOK)
398     {
399         rt_set_errno(err_code);
400         return 0;
401     }
402 
403     if ((dev->flag & RT_DEVICE_FLAG_DMA_TX) && (size > 2))
404     {   /* DMA mode Tx */
405         struct efm32_leuart_dma_mode_t *dma_tx;
406 
407         if (dev->flag & RT_DEVICE_FLAG_STREAM)
408         {
409             if (*((rt_uint8_t *)buffer + size - 1) == '\n')
410             {
411                 *((rt_uint8_t *)buffer + size - 1) = '\r';
412                 *((rt_uint8_t *)buffer + size++) = '\n';
413                 *((rt_uint8_t *)buffer + size) = 0;
414             }
415         }
416 
417         dma_tx = (struct efm32_leuart_dma_mode_t *)(leuart->tx_mode);
418         dma_tx->data_ptr = (rt_uint32_t *)buffer;
419         dma_tx->data_size = size;
420 
421         leuart->state |= LEUART_STATE_TX_BUSY;
422 
423         DMA_ActivateBasic(
424             dma_tx->dma_channel,
425             true,
426             false,
427             (void *)&(leuart->leuart_device->TXDATA),
428             (void *)buffer,
429             (rt_uint32_t)(size - 1));
430 
431         /* Wait, otherwise the TX buffer is overwrite */
432 //      if (leuart->state & LEUART_STATE_CONSOLE)
433 //      {
434             while(leuart->state & LEUART_STATE_TX_BUSY);
435 //      }
436 //      else
437 //      {
438 //          while(leuart->state & LEUART_STATE_TX_BUSY)
439 //          {
440 //              rt_thread_delay(LEUART_WAIT_TIME_TX);
441 //          }
442 //      }
443 // TODO: This function blocks the process
444         write_size = size;
445     }
446     else
447     {   /* polling mode */
448         rt_uint8_t *ptr = (rt_uint8_t *)buffer;
449 
450         if (dev->flag & RT_DEVICE_FLAG_STREAM)
451         {
452             /* stream mode */
453             while (size)
454             {
455                 if (*ptr == '\n')
456                 {
457                     while (!(leuart->leuart_device->STATUS & LEUART_STATUS_TXBL));
458                     leuart->leuart_device->TXDATA = '\r';
459                 }
460 
461                 while (!(leuart->leuart_device->STATUS & LEUART_STATUS_TXBL));
462                 leuart->leuart_device->TXDATA = (rt_uint32_t)*ptr;
463                 ++ptr; --size;
464             }
465         }
466         else
467         {
468             /* write data directly */
469             while (size)
470             {
471                 while (!(leuart->leuart_device->STATUS & LEUART_STATUS_TXBL));
472                 leuart->leuart_device->TXDATA = (rt_uint32_t)*ptr;
473                 ++ptr; --size;
474             }
475         }
476 
477         write_size = (rt_size_t)ptr - (rt_size_t)buffer;
478     }
479 
480     /* Unlock device */
481     rt_sem_release(leuart->lock);
482 
483     /* set error code */
484     rt_set_errno(err_code);
485     return write_size;
486 }
487 
488 /***************************************************************************//**
489 * @brief
490 *   Configure LEUART device
491 *
492 * @details
493 *
494 * @note
495 *
496 * @param[in] dev
497 *   Pointer to device descriptor
498 *
499 * @param[in] cmd
500 *   IIC control command
501 *
502 * @param[in] args
503 *   Arguments
504 *
505 * @return
506 *   Error code
507 ******************************************************************************/
rt_leuart_control(rt_device_t dev,rt_uint8_t cmd,void * args)508 static rt_err_t rt_leuart_control (
509     rt_device_t     dev,
510     rt_uint8_t      cmd,
511     void            *args)
512 {
513     RT_ASSERT(dev != RT_NULL);
514 
515     rt_err_t    err_code;
516     struct efm32_leuart_device_t *leuart;
517 
518     leuart = (struct efm32_leuart_device_t *)(dev->user_data);
519 
520     /* Lock device */
521     if (rt_hw_interrupt_check())
522     {
523         err_code = rt_sem_take(leuart->lock, RT_WAITING_NO);
524     }
525     else
526     {
527         err_code = rt_sem_take(leuart->lock, RT_WAITING_FOREVER);
528     }
529     if (err_code != RT_EOK)
530     {
531         return err_code;
532     }
533 
534     switch (cmd)
535     {
536     case RT_DEVICE_CTRL_SUSPEND:
537         /* Suspend device */
538         dev->flag |= RT_DEVICE_FLAG_SUSPENDED;
539         LEUART_Enable(leuart->leuart_device, leuartDisable);
540         break;
541 
542     case RT_DEVICE_CTRL_RESUME:
543         /* Resume device */
544         dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED;
545         LEUART_Enable(leuart->leuart_device, leuartEnable);
546         break;
547 
548     case RT_DEVICE_CTRL_LEUART_RBUFFER:
549         /* Set RX buffer */
550         {
551             struct efm32_leuart_int_mode_t *int_rx;
552             rt_uint8_t size;
553 
554             int_rx = (struct efm32_leuart_int_mode_t *)(leuart->rx_mode);
555             size = (rt_uint8_t)((rt_uint32_t)args & 0xFFUL);
556 
557             /* Free previous RX buffer */
558             if (int_rx->data_ptr != RT_NULL)
559             {
560                 if (size == 0)
561                 {   /* Free RX buffer */
562                     rt_free(int_rx->data_ptr);
563                     int_rx->data_ptr = RT_NULL;
564                 }
565                 else if (size != int_rx->data_size)
566                 {
567                     /* Re-allocate RX buffer */
568                     if ((int_rx->data_ptr = rt_realloc(int_rx->data_ptr, size)) \
569                         == RT_NULL)
570                     {
571                         leuart_debug("LEUART%d err: no mem for RX BUF\n", leuart->unit);
572                         err_code = -RT_ENOMEM;
573                         break;
574                     }
575                     // TODO: Is the following line necessary?
576                     //rt_memset(int_rx->data_ptr, 0, size);
577                 }
578             }
579             else
580             {
581                 /* Allocate new RX buffer */
582                 if ((int_rx->data_ptr = rt_malloc(size)) == RT_NULL)
583                 {
584                     leuart_debug("LEUART%d err: no mem for RX BUF\n", leuart->unit);
585                     err_code = -RT_ENOMEM;
586                     break;
587                 }
588             }
589             int_rx->data_size = size;
590             int_rx->read_index = 0;
591             int_rx->save_index = 0;
592         }
593         break;
594 
595     }
596 
597     /* Unlock device */
598     rt_sem_release(leuart->lock);
599 
600     return err_code;
601 }
602 
603 /***************************************************************************//**
604  * @brief
605  *  LEUART RX data valid interrupt handler
606  *
607  * @details
608  *
609  * @note
610  *
611  * @param[in] dev
612  *  Pointer to device descriptor
613  ******************************************************************************/
rt_hw_leuart_rx_isr(rt_device_t dev)614 void rt_hw_leuart_rx_isr(rt_device_t dev)
615 {
616     struct efm32_leuart_device_t    *leuart;
617     struct efm32_leuart_int_mode_t  *int_rx;
618     rt_uint32_t                     flag;
619 
620     /* interrupt mode receive */
621     RT_ASSERT(dev->flag & RT_DEVICE_FLAG_INT_RX);
622 
623     leuart = (struct efm32_leuart_device_t *)(dev->user_data);
624     int_rx = (struct efm32_leuart_int_mode_t *)(leuart->rx_mode);
625 
626     RT_ASSERT(int_rx->data_ptr != RT_NULL);
627 
628     /* Set status */
629     leuart->state |= LEUART_STATE_RX_BUSY;
630 
631     /* save into rx buffer */
632     while (leuart->leuart_device->STATUS & LEUART_STATUS_RXDATAV)
633     {
634         rt_base_t level;
635 
636         /* disable interrupt */
637         level = rt_hw_interrupt_disable();
638 
639         /* save character */
640         int_rx->data_ptr[int_rx->save_index] = \
641             (rt_uint8_t)(leuart->leuart_device->RXDATA & 0xFFUL);
642         int_rx->save_index ++;
643         if (int_rx->save_index >= LEUART_RX_BUFFER_SIZE)
644             int_rx->save_index = 0;
645 
646         /* if the next position is read index, discard this 'read char' */
647         if (int_rx->save_index == int_rx->read_index)
648         {
649             int_rx->read_index ++;
650             if (int_rx->read_index >= LEUART_RX_BUFFER_SIZE)
651             {
652                 int_rx->read_index = 0;
653             }
654         }
655 
656         /* enable interrupt */
657         rt_hw_interrupt_enable(level);
658     }
659 
660     /* invoke callback */
661     if (dev->rx_indicate != RT_NULL)
662     {
663         rt_size_t rx_length;
664 
665         /* get rx length */
666         rx_length = int_rx->read_index > int_rx->save_index ?
667             LEUART_RX_BUFFER_SIZE - int_rx->read_index + int_rx->save_index : \
668             int_rx->save_index - int_rx->read_index;
669 
670         dev->rx_indicate(dev, rx_length);
671     }
672 }
673 
674 /***************************************************************************//**
675  * @brief
676  *  DMA for LEUART TX interrupt handler
677  *
678  * @details
679  *
680  * @note
681  *
682  * @param[in] dev
683  *  Pointer to device descriptor
684  ******************************************************************************/
rt_hw_leuart_dma_tx_isr(rt_device_t dev)685 void rt_hw_leuart_dma_tx_isr(rt_device_t dev)
686 {
687     /* DMA mode receive */
688     struct efm32_leuart_device_t    *leuart;
689     struct efm32_leuart_dma_mode_t  *dma_tx;
690 
691     RT_ASSERT(dev->flag & RT_DEVICE_FLAG_DMA_TX);
692 
693     leuart = (struct efm32_leuart_device_t *)(dev->user_data);
694     dma_tx = (struct efm32_leuart_dma_mode_t *)(leuart->tx_mode);
695 
696     /* invoke call to notify tx complete */
697     if (dev->tx_complete != RT_NULL)
698     {
699         dev->tx_complete(dev, dma_tx->data_ptr);
700     }
701 
702     /* Set status */
703     leuart->state &= ~(rt_uint32_t)LEUART_STATE_TX_BUSY;
704 }
705 
706 /***************************************************************************//**
707 * @brief
708 *   Register LEUART device
709 *
710 * @details
711 *
712 * @note
713 *
714 * @param[in] device
715 *   Pointer to device descriptor
716 *
717 * @param[in] name
718 *   Device name
719 *
720 * @param[in] flag
721 *   Configuration flags
722 *
723 * @param[in] leuart
724 *   Pointer to LEUART device descriptor
725 *
726 * @return
727 *   Error code
728 ******************************************************************************/
rt_hw_leuart_register(rt_device_t device,const char * name,rt_uint32_t flag,struct efm32_leuart_device_t * leuart)729 rt_err_t rt_hw_leuart_register(
730     rt_device_t     device,
731     const char      *name,
732     rt_uint32_t     flag,
733     struct efm32_leuart_device_t *leuart)
734 {
735     RT_ASSERT(device != RT_NULL);
736 
737     if ((flag & RT_DEVICE_FLAG_DMA_RX) ||
738         (flag & RT_DEVICE_FLAG_INT_TX))
739     {
740         RT_ASSERT(0);
741     }
742 
743     device->type        = RT_Device_Class_Char;
744     device->rx_indicate = RT_NULL;
745     device->tx_complete = RT_NULL;
746     device->init        = rt_leuart_init;
747     device->open        = rt_leuart_open;
748     device->close       = rt_leuart_close;
749     device->read        = rt_leuart_read;
750     device->write       = rt_leuart_write;
751     device->control     = rt_leuart_control;
752     device->user_data   = leuart;
753 
754     /* register a character device */
755     return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR | flag);
756 }
757 
758 /***************************************************************************//**
759 * @brief
760 *   Initialize the specified LEUART unit
761 *
762 * @details
763 *
764 * @note
765 *
766 * @param[in] device
767 *   Pointer to device descriptor
768 *
769 * @param[in] unitNumber
770 *   Unit number
771 *
772 * @param[in] location
773 *   Pin location number
774 *
775 * @param[in] flag
776 *   Configuration flag
777 *
778 * @param[in] dmaChannel
779 *   DMA channel number for TX
780 *
781 * @param[in] console
782 *   Indicate if using as console
783 *
784 * @return
785 *   Pointer to LEUART device
786 ******************************************************************************/
rt_hw_leuart_unit_init(rt_device_t device,rt_uint8_t unitNumber,rt_uint8_t location,rt_uint32_t flag,rt_uint32_t dmaChannel,rt_uint8_t config)787 static struct efm32_leuart_device_t *rt_hw_leuart_unit_init(
788     rt_device_t device,
789     rt_uint8_t  unitNumber,
790     rt_uint8_t  location,
791     rt_uint32_t flag,
792     rt_uint32_t dmaChannel,
793     rt_uint8_t  config)
794 {
795     struct efm32_leuart_device_t    *leuart;
796     struct efm32_leuart_dma_mode_t  *dma_mode;
797     DMA_CB_TypeDef                  *callback;
798     CMU_Clock_TypeDef               leuartClock;
799     rt_uint32_t                     txDmaSelect;
800     GPIO_Port_TypeDef               port_tx, port_rx, port_clk, port_cs;
801     rt_uint32_t                     pin_tx, pin_rx, pin_clk, pin_cs;
802     LEUART_Init_TypeDef             init = LEUART_INIT_DEFAULT;
803     efm32_irq_hook_init_t           hook;
804 
805     do
806     {
807         /* Allocate device */
808         leuart = rt_malloc(sizeof(struct efm32_leuart_device_t));
809         if (leuart == RT_NULL)
810         {
811             leuart_debug("LEUART%d err: no mem\n", unitNumber);
812             break;
813         }
814         leuart->counter = 0;
815         leuart->unit    = unitNumber;
816         leuart->state   = config;
817         leuart->tx_mode = RT_NULL;
818         leuart->rx_mode = RT_NULL;
819 
820         /* Allocate TX */
821         dma_mode = RT_NULL;
822         if (flag & RT_DEVICE_FLAG_DMA_TX)
823         {
824             leuart->tx_mode = dma_mode = rt_malloc(sizeof(struct efm32_leuart_dma_mode_t));
825             if (dma_mode == RT_NULL)
826             {
827                 leuart_debug("LEUART%d err: no mem for DMA TX\n", unitNumber);
828                 break;
829             }
830             dma_mode->dma_channel = dmaChannel;
831         }
832 
833         /* Allocate RX */
834         if (flag & RT_DEVICE_FLAG_INT_RX)
835         {
836             leuart->rx_mode = rt_malloc(sizeof(struct efm32_leuart_int_mode_t));
837             if (leuart->rx_mode == RT_NULL)
838             {
839                 leuart_debug("LEUART%d err: no mem for INT RX\n, unitNumber");
840                 break;
841             }
842         }
843 
844         /* Initialization */
845         if (unitNumber >= LEUART_COUNT)
846         {
847             break;
848         }
849         switch (unitNumber)
850         {
851         case 0:
852             leuart->leuart_device    = LEUART0;
853             leuartClock             = (CMU_Clock_TypeDef)cmuClock_LEUART0;
854             txDmaSelect             = DMAREQ_LEUART0_TXBL;
855             port_tx                 = AF_LEUART0_TX_PORT(location);
856             pin_tx                  = AF_LEUART0_TX_PIN(location);
857             port_rx                 = AF_LEUART0_RX_PORT(location);
858             pin_rx                  = AF_LEUART0_RX_PIN(location);
859             break;
860 #if (LEUART_COUNT > 1)
861         case 1:
862             leuart->leuart_device    = LEUART1;
863             leuartClock             = (CMU_Clock_TypeDef)cmuClock_LEUART1;
864             txDmaSelect             = DMAREQ_LEUART1_TXBL;
865             port_tx                 = AF_LEUART1_TX_PORT(location);
866             pin_tx                  = AF_LEUART1_TX_PIN(location);
867             port_rx                 = AF_LEUART1_RX_PORT(location);
868             pin_rx                  = AF_LEUART1_RX_PIN(location);
869             break;
870 #endif
871         default:
872             break;
873         }
874 
875         /* Do not prescale clock */
876         CMU_ClockDivSet(leuartClock, cmuClkDiv_1);
877 
878         /* Enable LEUART clock */
879         CMU_ClockEnable(leuartClock, true);
880 
881         /* Config GPIO */
882         GPIO_PinModeSet(
883             port_tx,
884             pin_tx,
885             gpioModePushPull,
886             0);
887         GPIO_PinModeSet(
888             port_rx,
889             pin_rx,
890             gpioModeInputPull,
891             1);
892 
893         /* Config interrupt and NVIC */
894         if (flag & RT_DEVICE_FLAG_INT_RX)
895         {
896             hook.type       = efm32_irq_type_leuart;
897             hook.unit       = unitNumber;
898             hook.cbFunc     = rt_hw_leuart_rx_isr;
899             hook.userPtr    = device;
900             efm32_irq_hook_register(&hook);
901         }
902 
903         /* Config DMA */
904         if (flag & RT_DEVICE_FLAG_DMA_TX)
905         {
906             DMA_CfgChannel_TypeDef  chnlCfg;
907             DMA_CfgDescr_TypeDef    descrCfg;
908 
909             hook.type           = efm32_irq_type_dma;
910             hook.unit           = dmaChannel;
911             hook.cbFunc         = rt_hw_leuart_dma_tx_isr;
912             hook.userPtr        = device;
913             efm32_irq_hook_register(&hook);
914 
915             callback = (DMA_CB_TypeDef *)rt_malloc(sizeof(DMA_CB_TypeDef));
916             if (callback == RT_NULL)
917             {
918                 leuart_debug("LEUART%d err: no mem for callback\n", unitNumber);
919                 break;
920             }
921             callback->cbFunc    = DMA_IRQHandler_All;
922             callback->userPtr   = RT_NULL;
923             callback->primary   = 0;
924 
925             /* Setting up DMA channel */
926             chnlCfg.highPri     = false;    /* Can't use with peripherals */
927             chnlCfg.enableInt   = true;     /* Interrupt for callback function */
928             chnlCfg.select      = txDmaSelect;
929             chnlCfg.cb          = callback;
930             DMA_CfgChannel(dmaChannel, &chnlCfg);
931 
932             /* Setting up DMA channel descriptor */
933             descrCfg.dstInc     = dmaDataIncNone;
934             descrCfg.srcInc     = dmaDataInc1;
935             descrCfg.size       = dmaDataSize1;
936             descrCfg.arbRate    = dmaArbitrate1;
937             descrCfg.hprot      = 0;
938             DMA_CfgDescr(dmaChannel, true, &descrCfg);
939         }
940 
941         /* Init specified LEUART unit */
942         LEUART_Init(leuart->leuart_device, &init);
943 
944         /* Enable RX and TX pins and set location */
945         leuart->leuart_device->ROUTE = LEUART_ROUTE_RXPEN | LEUART_ROUTE_TXPEN | \
946                         (location << _LEUART_ROUTE_LOCATION_SHIFT);
947 
948         /* Clear RX/TX buffers */
949         leuart->leuart_device->CMD = LEUART_CMD_CLEARRX | LEUART_CMD_CLEARTX;
950 
951         return leuart;
952     } while(0);
953 
954     if (leuart->rx_mode)
955     {
956         rt_free(leuart->rx_mode);
957     }
958     if (leuart->tx_mode)
959     {
960         rt_free(leuart->tx_mode);
961     }
962     if (leuart)
963     {
964         rt_free(leuart);
965     }
966     if (callback)
967     {
968         rt_free(leuart);
969     }
970 
971     leuart_debug("LEUART%d err: init failed!\n", unitNumber);
972     return RT_NULL;
973 }
974 
975 /***************************************************************************//**
976 * @brief
977 *   Initialize all LEUART module related hardware and register LEUART device to
978 * kernel
979 *
980 * @details
981 *
982 * @note
983 ******************************************************************************/
rt_hw_leuart_init(void)984 void rt_hw_leuart_init(void)
985 {
986     struct efm32_leuart_device_t    *leuart;
987     rt_uint32_t                     flag;
988     rt_uint8_t                      config;
989 
990     do
991     {
992 #ifdef RT_USING_LEUART0
993         config = 0;
994         flag = RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX;
995 
996  #if (RT_CONSOLE_DEVICE == EFM_LEUART0)
997         config |= LEUART_STATE_CONSOLE;
998         flag |= RT_DEVICE_FLAG_STREAM;
999  #endif
1000 
1001  #ifdef RT_LEUART0_USING_DMA
1002         RT_ASSERT(RT_LEUART0_USING_DMA < DMA_CHAN_COUNT);
1003         flag |= RT_DEVICE_FLAG_DMA_TX;
1004  #else
1005        #define RT_LEUART0_USING_DMA EFM32_NO_DMA
1006  #endif
1007 
1008         /* Initialize and Register leuart0 */
1009         if ((leuart = rt_hw_leuart_unit_init(
1010             &leuart0_device,
1011             0,
1012             RT_USING_LEUART0,
1013             flag,
1014             RT_LEUART0_USING_DMA,
1015             config)) != RT_NULL)
1016         {
1017             rt_hw_leuart_register(&leuart0_device, RT_LEUART0_NAME, flag, leuart);
1018         }
1019         else
1020         {
1021             break;
1022         }
1023         /* Initialize lock for leuart0 */
1024         leuart->lock = &leuart0_lock;
1025         if (rt_sem_init(leuart->lock, RT_LEUART0_NAME, 1, RT_IPC_FLAG_FIFO) != RT_EOK)
1026         {
1027             break;
1028         }
1029 #endif
1030 
1031 #if ((LEUART_COUNT > 1) && defined(RT_USING_LEUART1))
1032         config = 0;
1033         flag = RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX;
1034 
1035  #if (RT_CONSOLE_DEVICE == EFM_LEUART1)
1036         config |= LEUART_STATE_CONSOLE;
1037         flag |= RT_DEVICE_FLAG_STREAM;
1038  #endif
1039 
1040  #ifdef RT_LEUART1_USING_DMA
1041         RT_ASSERT(RT_LEUART1_USING_DMA < DMA_CHAN_COUNT);
1042         flag |= RT_DEVICE_FLAG_DMA_TX;
1043  #else
1044        #define RT_LEUART1_USING_DMA EFM32_NO_DMA
1045  #endif
1046 
1047         /* Initialize and Register leuart1 */
1048         if ((leuart = rt_hw_leuart_unit_init(
1049             &leuart1_device,
1050             1,
1051             RT_USING_LEUART1,
1052             flag,
1053             RT_LEUART1_USING_DMA,
1054             config)) != RT_NULL)
1055         {
1056             rt_hw_leuart_register(&leuart1_device, RT_LEUART1_NAME, flag, leuart);
1057         }
1058         else
1059         {
1060             break;
1061         }
1062         /* Initialize lock for leuart1 */
1063         leuart->lock = &leuart1_lock;
1064         if (rt_sem_init(leuart->lock, RT_LEUART1_NAME, 1, RT_IPC_FLAG_FIFO) != RT_EOK)
1065         {
1066             break;
1067         }
1068 #endif
1069 
1070         leuart_debug("LEUART: H/W init OK!\n");
1071         return;
1072     } while (0);
1073 
1074     rt_kprintf("LEUART: H/W init failed!\n");
1075 }
1076 
1077 #endif /* (defined(RT_USING_LEUART0) || defined(RT_USING_LEUART1)) */
1078 /***************************************************************************//**
1079  * @}
1080  ******************************************************************************/
1081