///* // * Copyright (c) 2006-2024, RT-Thread Development Team // * // * SPDX-License-Identifier: Apache-2.0 // * // * Change Logs: // * Date Author Notes // * 2019-07-15 Magicoe The first version for LPC55S6x // */ #include #include "drv_uart.h" #include "fsl_lpuart.h" #include "fsl_common.h" #ifdef RT_USING_SERIAL #include /* lpc uart driver */ struct mcx_uart { struct rt_serial_device *serial; LPUART_Type *uart_base; IRQn_Type irqn; clock_name_t clock_src; clock_attach_id_t clock_attach_id; clock_ip_name_t clock_ip_name; clock_div_name_t clock_div_name; char *device_name; }; static void uart_isr(struct rt_serial_device *serial); #if defined(BSP_USING_UART4) struct rt_serial_device serial4; void LP_FLEXCOMM4_IRQHandler(void) { uart_isr(&serial4); } #endif /* BSP_USING_UART4 */ #if defined(BSP_USING_UART6) struct rt_serial_device serial6; void LP_FLEXCOMM6_IRQHandler(void) { uart_isr(&serial6); } #endif /* BSP_USING_UART6 */ static const struct mcx_uart uarts[] = { #ifdef BSP_USING_UART4 { &serial4, LPUART4, LP_FLEXCOMM4_IRQn, kCLOCK_Fro12M, kFRO12M_to_FLEXCOMM4, kCLOCK_LPFlexComm4, kCLOCK_DivFlexcom4Clk, "uart4", }, #endif #ifdef BSP_USING_UART6 { &serial6, LPUART6, LP_FLEXCOMM6_IRQn, kCLOCK_Fro12M, kFRO12M_to_FLEXCOMM6, kCLOCK_LPFlexComm6, kCLOCK_DivFlexcom6Clk, "uart6", }, #endif }; static rt_err_t mcx_configure(struct rt_serial_device *serial, struct serial_configure *cfg) { struct mcx_uart *uart; lpuart_config_t config; RT_ASSERT(serial != RT_NULL); RT_ASSERT(cfg != RT_NULL); uart = (struct mcx_uart *)serial->parent.user_data; CLOCK_SetClkDiv(uart->clock_div_name, 1u); CLOCK_AttachClk(uart->clock_attach_id); CLOCK_EnableClock(uart->clock_ip_name); LPUART_GetDefaultConfig(&config); config.baudRate_Bps = cfg->baud_rate; switch (cfg->data_bits) { case DATA_BITS_7: config.dataBitsCount = kLPUART_SevenDataBits; break; default: config.dataBitsCount = kLPUART_EightDataBits; break; } config.enableTx = true; config.enableRx = true; LPUART_Init(uart->uart_base, &config, CLOCK_GetFreq(uart->clock_src)); return RT_EOK; } static rt_err_t mcx_control(struct rt_serial_device *serial, int cmd, void *arg) { struct mcx_uart *uart = (struct mcx_uart *)serial->parent.user_data; RT_ASSERT(uart != RT_NULL); switch (cmd) { case RT_DEVICE_CTRL_CLR_INT: /* disable rx irq */ LPUART_DisableInterrupts(uart->uart_base, kLPUART_RxDataRegFullInterruptEnable); DisableIRQ(uart->irqn); break; case RT_DEVICE_CTRL_SET_INT: /* enable rx irq */ LPUART_EnableInterrupts(uart->uart_base, kLPUART_RxDataRegFullInterruptEnable); EnableIRQ(uart->irqn); break; } return RT_EOK; } static int mcx_putc(struct rt_serial_device *serial, char ch) { struct mcx_uart *uart = (struct mcx_uart *)serial->parent.user_data; while(!(kLPUART_TxDataRegEmptyFlag & LPUART_GetStatusFlags(uart->uart_base))); LPUART_WriteByte(uart->uart_base, ch); return 1; } static int mcx_getc(struct rt_serial_device *serial) { struct mcx_uart *uart = (struct mcx_uart *)serial->parent.user_data; if (kLPUART_RxDataRegFullInterruptEnable & LPUART_GetStatusFlags(uart->uart_base)) { return LPUART_ReadByte(uart->uart_base); } else { return -1; } } /** * Uart common interrupt process. This need add to uart ISR. * * @param serial serial device */ static void uart_isr(struct rt_serial_device *serial) { struct mcx_uart *uart; RT_ASSERT(serial != RT_NULL); uart = (struct mcx_uart *) serial->parent.user_data; RT_ASSERT(uart != RT_NULL); /* enter interrupt */ rt_interrupt_enter(); /* UART in mode Receiver -------------------------------------------------*/ rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND); /* leave interrupt */ rt_interrupt_leave(); } static const struct rt_uart_ops mcx_uart_ops = { mcx_configure, mcx_control, mcx_putc, mcx_getc, }; int rt_hw_uart_init(void) { struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; int i; for (i = 0; i < sizeof(uarts) / sizeof(uarts[0]); i++) { uarts[i].serial->ops = &mcx_uart_ops; uarts[i].serial->config = config; /* register UART device */ rt_hw_serial_register(uarts[i].serial, uarts[i].device_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, (void *)&uarts[i]); } return 0; } INIT_BOARD_EXPORT(rt_hw_uart_init); #endif /*BSP_USING_SERIAL */