/* * Copyright (c) 2018 Cypress * SPDX-License-Identifier: Apache-2.0 */ /** @file * @brief UART driver for Cypress PSoC6 MCU family. * * Note: * - Error handling is not implemented. * - The driver works only in polling mode, interrupt mode is not implemented. */ #include #include #include #include #include #include #include "cy_syslib.h" #include "cy_sysclk.h" #include "cy_gpio.h" #include "cy_scb_uart.h" /* * Verify Kconfig configuration */ struct cypress_psoc6_config { CySCB_Type *base; GPIO_PRT_Type *port; u32_t rx_num; u32_t tx_num; en_hsiom_sel_t rx_val; en_hsiom_sel_t tx_val; en_clk_dst_t scb_clock; }; /* Populate configuration structure */ static const cy_stc_scb_uart_config_t uartConfig = { .uartMode = CY_SCB_UART_STANDARD, .enableMutliProcessorMode = false, .smartCardRetryOnNack = false, .irdaInvertRx = false, .irdaEnableLowPowerReceiver = false, .oversample = DT_UART_PSOC6_CONFIG_OVERSAMPLE, .enableMsbFirst = false, .dataWidth = DT_UART_PSOC6_CONFIG_DATAWIDTH, .parity = CY_SCB_UART_PARITY_NONE, .stopBits = CY_SCB_UART_STOP_BITS_1, .enableInputFilter = false, .breakWidth = DT_UART_PSOC6_CONFIG_BREAKWIDTH, .dropOnFrameError = false, .dropOnParityError = false, .receiverAddress = 0UL, .receiverAddressMask = 0UL, .acceptAddrInFifo = false, .enableCts = false, .ctsPolarity = CY_SCB_UART_ACTIVE_LOW, .rtsRxFifoLevel = 0UL, .rtsPolarity = CY_SCB_UART_ACTIVE_LOW, .rxFifoTriggerLevel = 0UL, .rxFifoIntEnableMask = 0UL, .txFifoTriggerLevel = 0UL, .txFifoIntEnableMask = 0UL, }; /** * Function Name: uart_psoc6_init() * * Peforms hardware initialization: debug UART. * */ static int uart_psoc6_init(struct device *dev) { const struct cypress_psoc6_config *config = dev->config->config_info; /* Connect SCB5 UART function to pins */ Cy_GPIO_SetHSIOM(config->port, config->rx_num, config->rx_val); Cy_GPIO_SetHSIOM(config->port, config->tx_num, config->tx_val); /* Configure pins for UART operation */ Cy_GPIO_SetDrivemode(config->port, config->rx_num, CY_GPIO_DM_HIGHZ); Cy_GPIO_SetDrivemode(config->port, config->tx_num, CY_GPIO_DM_STRONG_IN_OFF); /* Connect assigned divider to be a clock source for UART */ Cy_SysClk_PeriphAssignDivider(config->scb_clock, DT_UART_PSOC6_UART_CLK_DIV_TYPE, DT_UART_PSOC6_UART_CLK_DIV_NUMBER); Cy_SysClk_PeriphSetDivider(DT_UART_PSOC6_UART_CLK_DIV_TYPE, DT_UART_PSOC6_UART_CLK_DIV_NUMBER, DT_UART_PSOC6_UART_CLK_DIV_VAL); Cy_SysClk_PeriphEnableDivider(DT_UART_PSOC6_UART_CLK_DIV_TYPE, DT_UART_PSOC6_UART_CLK_DIV_NUMBER); /* Configure UART to operate */ (void) Cy_SCB_UART_Init(config->base, &uartConfig, NULL); Cy_SCB_UART_Enable(config->base); return 0; } static int uart_psoc6_poll_in(struct device *dev, unsigned char *c) { const struct cypress_psoc6_config *config = dev->config->config_info; u32_t rec; rec = Cy_SCB_UART_Get(config->base); *c = (unsigned char)(rec & 0xff); return ((rec == CY_SCB_UART_RX_NO_DATA) ? -1 : 0); } static void uart_psoc6_poll_out(struct device *dev, unsigned char c) { const struct cypress_psoc6_config *config = dev->config->config_info; while (Cy_SCB_UART_Put(config->base, (uint32_t)c) != 1UL) { } } static const struct uart_driver_api uart_psoc6_driver_api = { .poll_in = uart_psoc6_poll_in, .poll_out = uart_psoc6_poll_out, }; #ifdef CONFIG_UART_PSOC6_UART_5 static const struct cypress_psoc6_config cypress_psoc6_uart5_config = { .base = DT_UART_PSOC6_UART_5_BASE_ADDRESS, .port = DT_UART_PSOC6_UART_5_PORT, .rx_num = DT_UART_PSOC6_UART_5_RX_NUM, .tx_num = DT_UART_PSOC6_UART_5_TX_NUM, .rx_val = DT_UART_PSOC6_UART_5_RX_VAL, .tx_val = DT_UART_PSOC6_UART_5_TX_VAL, .scb_clock = DT_UART_PSOC6_UART_5_CLOCK, }; DEVICE_AND_API_INIT(uart_5, DT_UART_PSOC6_UART_5_NAME, uart_psoc6_init, NULL, &cypress_psoc6_uart5_config, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, (void *)&uart_psoc6_driver_api); #endif /* CONFIG_UART_PSOC6_UART_5 */ #ifdef CONFIG_UART_PSOC6_UART_6 static const struct cypress_psoc6_config cypress_psoc6_uart6_config = { .base = DT_UART_PSOC6_UART_6_BASE_ADDRESS, .port = DT_UART_PSOC6_UART_6_PORT, .rx_num = DT_UART_PSOC6_UART_6_RX_NUM, .tx_num = DT_UART_PSOC6_UART_6_TX_NUM, .rx_val = DT_UART_PSOC6_UART_6_RX_VAL, .tx_val = DT_UART_PSOC6_UART_6_TX_VAL, .scb_clock = DT_UART_PSOC6_UART_6_CLOCK, }; DEVICE_AND_API_INIT(uart_6, DT_UART_PSOC6_UART_6_NAME, uart_psoc6_init, NULL, &cypress_psoc6_uart6_config, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, (void *)&uart_psoc6_driver_api); #endif /* CONFIG_UART_PSOC6_UART_6 */