blob: 738b0818f3eca143b1ebb7011fad089938c40eaf [file] [log] [blame]
/*
* Copyright (c) 2025 Cypress Semiconductor Corporation (an Infineon company) or
* an affiliate of Cypress Semiconductor Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @brief UART driver for Infineon CAT1 MCU family.
*
*/
#define DT_DRV_COMPAT infineon_cat1_uart_pdl
#include <string.h>
#include <zephyr/irq.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/kernel.h>
#include <cy_scb_uart.h>
#include <cy_gpio.h>
#include <cy_syslib.h>
#include <cy_sysint.h>
#include <zephyr/drivers/clock_control/clock_control_ifx_cat1.h>
#include <zephyr/dt-bindings/clock/ifx_clock_source_common.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(uart_ifx_cat1, CONFIG_UART_LOG_LEVEL);
#define IFX_CAT1_UART_OVERSAMPLE_MIN 8UL
#define IFX_CAT1_UART_OVERSAMPLE_MAX 16UL
#define IFX_CAT1_UART_MAX_BAUD_PERCENT_DIFFERENCE 10
/* Data structure */
struct ifx_cat1_uart_data {
struct uart_config cfg;
struct ifx_cat1_resource_inst hw_resource;
struct ifx_cat1_clock clock;
#if defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1C)
uint8_t clock_peri_group;
#endif
#if CONFIG_UART_INTERRUPT_DRIVEN
uart_irq_callback_user_data_t irq_cb; /* Interrupt Callback */
void *irq_cb_data; /* Interrupt Callback Arg */
#endif
bool cts_enabled;
bool rts_enabled;
cy_stc_scb_uart_context_t context;
cy_stc_scb_uart_config_t scb_config;
uint32_t baud_rate;
};
/* Device config structure */
struct ifx_cat1_uart_config {
const struct pinctrl_dev_config *pcfg;
CySCB_Type *reg_addr;
struct uart_config dt_cfg;
uint16_t irq_num;
uint8_t irq_priority;
};
typedef void (*ifx_cat1_uart_event_callback_t)(void *callback_arg);
/* Helper API */
static cy_en_scb_uart_parity_t convert_uart_parity_z_to_cy(const enum uart_config_parity parity)
{
cy_en_scb_uart_parity_t cy_parity;
switch (parity) {
case UART_CFG_PARITY_NONE:
cy_parity = CY_SCB_UART_PARITY_NONE;
break;
case UART_CFG_PARITY_ODD:
cy_parity = CY_SCB_UART_PARITY_ODD;
break;
case UART_CFG_PARITY_EVEN:
cy_parity = CY_SCB_UART_PARITY_EVEN;
break;
default:
cy_parity = CY_SCB_UART_PARITY_NONE;
}
return cy_parity;
}
static uint8_t convert_uart_stop_bits_z_to_cy(const enum uart_config_stop_bits stop_bits)
{
uint32_t cy_stop_bits;
switch (stop_bits) {
case UART_CFG_STOP_BITS_1:
cy_stop_bits = CY_SCB_UART_STOP_BITS_1;
break;
case UART_CFG_STOP_BITS_2:
cy_stop_bits = CY_SCB_UART_STOP_BITS_2;
break;
default:
cy_stop_bits = CY_SCB_UART_STOP_BITS_1;
}
return cy_stop_bits;
}
static uint32_t convert_uart_data_bits_z_to_cy(const enum uart_config_data_bits data_bits)
{
uint32_t cy_data_bits;
switch (data_bits) {
case UART_CFG_DATA_BITS_5:
cy_data_bits = 5u;
break;
case UART_CFG_DATA_BITS_6:
cy_data_bits = 6u;
break;
case UART_CFG_DATA_BITS_7:
cy_data_bits = 7u;
break;
case UART_CFG_DATA_BITS_8:
cy_data_bits = 8u;
break;
case UART_CFG_DATA_BITS_9:
cy_data_bits = 9u;
break;
default:
cy_data_bits = 1u;
}
return cy_data_bits;
}
static uint8_t ifx_cat1_get_hfclk_for_peri_group(uint8_t peri_group)
{
switch (peri_group) {
/* Peripheral groups are device specific. */
case 0:
case 2:
return 0;
case 1:
case 3:
return 1;
case 4:
return 2;
case 5:
return 3;
case 6:
return 4;
default:
break;
}
return -1;
}
cy_rslt_t ifx_cat1_uart_set_baud(const struct device *dev, uint32_t baudrate)
{
cy_rslt_t status;
struct ifx_cat1_uart_data *data = dev->data;
const struct ifx_cat1_uart_config *const config = dev->config;
uint8_t best_oversample = IFX_CAT1_UART_OVERSAMPLE_MIN;
uint8_t best_difference = 0xFF;
uint32_t divider;
uint32_t peri_frequency;
if (data->baud_rate != baudrate) {
data->baud_rate = baudrate;
}
Cy_SCB_UART_Disable(config->reg_addr, NULL);
#if defined(COMPONENT_CAT1A)
peri_frequency = Cy_SysClk_ClkPeriGetFrequency();
#elif defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1C)
uint8_t hfclk = ifx_cat1_get_hfclk_for_peri_group(data->clock_peri_group);
peri_frequency = Cy_SysClk_ClkHfGetFrequency(hfclk);
#endif
for (uint8_t i = IFX_CAT1_UART_OVERSAMPLE_MIN; i < IFX_CAT1_UART_OVERSAMPLE_MAX + 1; i++) {
uint32_t tmp_divider = ((peri_frequency + ((baudrate * i) / 2))) / (baudrate * i);
uint32_t actual_baud = (peri_frequency / (tmp_divider * i));
uint8_t difference = (actual_baud > baudrate)
? ((actual_baud * 100) - (baudrate * 100)) / baudrate
: ((baudrate * 100) - (actual_baud * 100)) / baudrate;
if (difference < best_difference) {
best_difference = difference;
best_oversample = i;
}
}
if (best_difference > IFX_CAT1_UART_MAX_BAUD_PERCENT_DIFFERENCE) {
status = -EINVAL;
}
best_oversample = best_oversample;
data->scb_config.oversample = best_oversample;
divider = ((peri_frequency + ((baudrate * best_oversample) / 2)) /
(baudrate * best_oversample));
en_clk_dst_t clk_idx = ifx_cat1_scb_get_clock_index(data->hw_resource.block_num);
/* Set baud rate */
if ((data->clock.block & 0x02) == 0) {
status = ifx_cat1_utils_peri_pclk_set_divider(clk_idx, &(data->clock), divider - 1);
} else {
status = ifx_cat1_utils_peri_pclk_set_frac_divider(clk_idx, &(data->clock),
divider - 1, 0);
}
/* Configure the UART interface */
#if (CY_IP_MXSCB_VERSION >= 2) || (CY_IP_MXS22SCB_VERSION >= 1)
uint32_t mem_width = (data->scb_config.dataWidth <= CY_SCB_BYTE_WIDTH)
? CY_SCB_MEM_WIDTH_BYTE
: CY_SCB_MEM_WIDTH_HALFWORD;
SCB_CTRL(config->reg_addr) =
_BOOL2FLD(SCB_CTRL_ADDR_ACCEPT, data->scb_config.acceptAddrInFifo) |
_BOOL2FLD(SCB_CTRL_MEM_WIDTH, mem_width) |
_VAL2FLD(SCB_CTRL_OVS, best_oversample - 1) |
_VAL2FLD(SCB_CTRL_MODE, CY_SCB_CTRL_MODE_UART);
#else /* Older versions of the block */
SCB_CTRL(config->reg_addr) =
_BOOL2FLD(SCB_CTRL_ADDR_ACCEPT, data->scb_config.acceptAddrInFifo) |
_BOOL2FLD(SCB_CTRL_BYTE_MODE, (data->scb_config.dataWidth <= CY_SCB_BYTE_WIDTH)) |
_VAL2FLD(SCB_CTRL_OVS, best_oversample - 1) |
_VAL2FLD(SCB_CTRL_MODE, CY_SCB_CTRL_MODE_UART);
#endif
Cy_SCB_UART_Enable(config->reg_addr);
return status;
}
uint32_t ifx_cat1_uart_get_num_in_tx_fifo(const struct device *dev)
{
const struct ifx_cat1_uart_config *const config = dev->config;
return Cy_SCB_GetNumInTxFifo(config->reg_addr);
}
bool ifx_cat1_uart_get_tx_active(const struct device *dev)
{
const struct ifx_cat1_uart_config *const config = dev->config;
return Cy_SCB_GetTxSrValid(config->reg_addr) ? true : false;
}
static int ifx_cat1_uart_poll_in(const struct device *dev, unsigned char *c)
{
const struct ifx_cat1_uart_config *const config = dev->config;
uint32_t read_value = Cy_SCB_UART_Get(config->reg_addr);
while (read_value == CY_SCB_UART_RX_NO_DATA) {
k_sleep(K_MSEC(1));
read_value = Cy_SCB_UART_Get(config->reg_addr);
}
*c = (uint8_t)read_value;
return 0;
}
static void ifx_cat1_uart_poll_out(const struct device *dev, unsigned char c)
{
const struct ifx_cat1_uart_config *const config = dev->config;
while (Cy_SCB_UART_Put(config->reg_addr, c) == 0) {
/* Wait until the character is placed in the FIFO */
}
}
static int ifx_cat1_uart_err_check(const struct device *dev)
{
const struct ifx_cat1_uart_config *const config = dev->config;
uint32_t status = Cy_SCB_UART_GetRxFifoStatus(config->reg_addr);
int errors = 0;
if (status & CY_SCB_UART_RX_OVERFLOW) {
errors |= UART_ERROR_OVERRUN;
}
if (status & CY_SCB_UART_RX_ERR_PARITY) {
errors |= UART_ERROR_PARITY;
}
if (status & CY_SCB_UART_RX_ERR_FRAME) {
errors |= UART_ERROR_FRAMING;
}
return errors;
}
static int ifx_cat1_uart_configure(const struct device *dev, const struct uart_config *cfg)
{
__ASSERT_NO_MSG(cfg != NULL);
cy_rslt_t result;
struct ifx_cat1_uart_data *data = dev->data;
const struct ifx_cat1_uart_config *const config = dev->config;
/* Store Uart Zephyr configuration (uart config) into data structure */
data->cfg = *cfg;
/* Configure parity, data and stop bits */
Cy_SCB_UART_Disable(config->reg_addr, NULL);
data->scb_config.dataWidth = convert_uart_data_bits_z_to_cy(cfg->data_bits);
data->scb_config.stopBits = convert_uart_stop_bits_z_to_cy(cfg->stop_bits);
data->scb_config.parity = convert_uart_parity_z_to_cy(cfg->parity);
data->scb_config.enableCts = data->cts_enabled;
Cy_SCB_UART_Init(config->reg_addr, &(data->scb_config), NULL);
Cy_SCB_UART_Enable(config->reg_addr);
/* Configure the baud rate */
result = ifx_cat1_uart_set_baud(dev, cfg->baudrate);
/* Enable RTS/CTS flow control */
if ((result == CY_RSLT_SUCCESS) && cfg->flow_ctrl) {
Cy_SCB_UART_EnableCts(config->reg_addr);
}
return (result == CY_RSLT_SUCCESS) ? 0 : -ENOTSUP;
};
static int ifx_cat1_uart_config_get(const struct device *dev, struct uart_config *cfg)
{
ARG_UNUSED(dev);
struct ifx_cat1_uart_data *const data = dev->data;
if (cfg == NULL) {
return -EINVAL;
}
*cfg = data->cfg;
return 0;
}
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
/* Fill FIFO with data */
static int ifx_cat1_uart_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size)
{
const struct ifx_cat1_uart_config *const config = dev->config;
size_t tx_length;
tx_length = Cy_SCB_UART_PutArray(config->reg_addr, (void *)tx_data, size);
return (int)tx_length;
}
/* Read data from FIFO */
static int ifx_cat1_uart_fifo_read(const struct device *dev, uint8_t *rx_data, const int size)
{
const struct ifx_cat1_uart_config *const config = dev->config;
size_t rx_length;
rx_length = Cy_SCB_UART_GetArray(config->reg_addr, rx_data, size);
return (int)rx_length;
}
void ifx_cat1_uart_enable_event(const struct device *dev, uint32_t event, bool enable)
{
struct ifx_cat1_uart_data *const data = dev->data;
const struct ifx_cat1_uart_config *const config = dev->config;
uint32_t tx_mask = 0x0;
uint32_t rx_mask = 0x0;
uint32_t current_tx_mask = Cy_SCB_GetTxInterruptMask(config->reg_addr);
uint32_t current_rx_mask = Cy_SCB_GetRxInterruptMask(config->reg_addr);
irq_disable(config->irq_num);
NVIC_ClearPendingIRQ(config->irq_num);
if (event & CY_SCB_UART_TRANSMIT_EMTPY) {
tx_mask |= CY_SCB_UART_TX_EMPTY;
}
if (event & CY_SCB_UART_TRANSMIT_ERR_EVENT) {
/* Omit underflow condition as the interrupt perpetually triggers
* Standard mode only uses OVERFLOW irq
*/
if (data->scb_config.uartMode == CY_SCB_UART_STANDARD) {
tx_mask |= (CY_SCB_UART_TX_OVERFLOW | CY_SCB_UART_TRANSMIT_ERR);
}
/* SMARTCARD mode uses OVERFLOW, NACK, and ARB_LOST irq's */
else if (data->scb_config.uartMode == CY_SCB_UART_SMARTCARD) {
tx_mask |= (CY_SCB_UART_TX_OVERFLOW | CY_SCB_TX_INTR_UART_NACK |
CY_SCB_TX_INTR_UART_ARB_LOST | CY_SCB_UART_TRANSMIT_ERR);
}
/* LIN Mode only uses OVERFLOW, ARB_LOST irq's */
else {
tx_mask |= (CY_SCB_UART_TX_OVERFLOW | CY_SCB_TX_INTR_UART_ARB_LOST |
CY_SCB_UART_TRANSMIT_ERR);
}
}
if (event & CY_SCB_UART_RECEIVE_NOT_EMTPY) {
rx_mask |= CY_SCB_UART_RX_NOT_EMPTY;
}
if (event & CY_SCB_UART_RECEIVE_ERR_EVENT) {
/* Omit underflow condition as the interrupt perpetually triggers. */
rx_mask |= CY_SCB_UART_RECEIVE_ERR;
}
if (enable && tx_mask) {
Cy_SCB_ClearTxInterrupt(config->reg_addr, tx_mask);
}
if (enable && rx_mask) {
Cy_SCB_ClearRxInterrupt(config->reg_addr, rx_mask);
}
Cy_SCB_SetTxInterruptMask(config->reg_addr, (enable ? (current_tx_mask | tx_mask)
: (current_tx_mask & ~tx_mask)));
Cy_SCB_SetRxInterruptMask(config->reg_addr, (enable ? (current_rx_mask | rx_mask)
: (current_rx_mask & ~rx_mask)));
irq_enable(config->irq_num);
}
static void ifx_cat1_uart_irq_tx_enable(const struct device *dev)
{
ifx_cat1_uart_enable_event(dev, (uint32_t)CY_SCB_UART_TRANSMIT_EMTPY, 1);
}
static void ifx_cat1_uart_irq_tx_disable(const struct device *dev)
{
ifx_cat1_uart_enable_event(dev, (uint32_t)CY_SCB_UART_TRANSMIT_EMTPY, 0);
}
/* Check if UART TX buffer can accept a new char */
static int ifx_cat1_uart_irq_tx_ready(const struct device *dev)
{
const struct ifx_cat1_uart_config *const config = dev->config;
uint32_t mask = Cy_SCB_GetTxInterruptStatusMasked(config->reg_addr);
return (((mask & (CY_SCB_UART_TX_NOT_FULL | SCB_INTR_TX_EMPTY_Msk)) != 0u) ? 1 : 0);
}
/* Check if UART TX block finished transmission */
static int ifx_cat1_uart_irq_tx_complete(const struct device *dev)
{
struct ifx_cat1_uart_data *const data = dev->data;
const struct ifx_cat1_uart_config *const config = dev->config;
return Cy_SCB_IsTxComplete(config->reg_addr) ||
(0UL == (data->context.txStatus & CY_SCB_UART_TRANSMIT_ACTIVE));
}
static void ifx_cat1_uart_irq_rx_enable(const struct device *dev)
{
ifx_cat1_uart_enable_event(dev, (uint32_t)CY_SCB_UART_RECEIVE_NOT_EMTPY, 1);
}
static void ifx_cat1_uart_irq_rx_disable(const struct device *dev)
{
ifx_cat1_uart_enable_event(dev, (uint32_t)CY_SCB_UART_RECEIVE_NOT_EMTPY, 0);
}
/* Check if UART RX buffer has a received char */
static int ifx_cat1_uart_irq_rx_ready(const struct device *dev)
{
struct ifx_cat1_uart_data *const data = dev->data;
const struct ifx_cat1_uart_config *const config = dev->config;
uint32_t number_available = Cy_SCB_UART_GetNumInRxFifo(config->reg_addr);
if (data->context.rxRingBuf != NULL) {
number_available +=
Cy_SCB_UART_GetNumInRingBuffer(config->reg_addr, &(data->context));
}
return (number_available) ? 1 : 0;
}
static void ifx_cat1_uart_irq_err_enable(const struct device *dev)
{
ifx_cat1_uart_enable_event(dev,
((uint32_t)CY_SCB_UART_TRANSMIT_ERR_EVENT |
(uint32_t)CY_SCB_UART_RECEIVE_ERR_EVENT),
1);
}
static void ifx_cat1_uart_irq_err_disable(const struct device *dev)
{
ifx_cat1_uart_enable_event(dev,
((uint32_t)CY_SCB_UART_TRANSMIT_ERR_EVENT |
(uint32_t)CY_SCB_UART_RECEIVE_ERR_EVENT),
0);
}
static int ifx_cat1_uart_irq_is_pending(const struct device *dev)
{
const struct ifx_cat1_uart_config *const config = dev->config;
uint32_t intcause = Cy_SCB_GetInterruptCause(config->reg_addr);
return (int)(intcause & (CY_SCB_TX_INTR | CY_SCB_RX_INTR));
}
/* Start processing interrupts in ISR.
* This function should be called the first thing in the ISR. Calling
* uart_irq_rx_ready(), uart_irq_tx_ready(), uart_irq_tx_complete()
* allowed only after this.
*/
static int ifx_cat1_uart_irq_update(const struct device *dev)
{
const struct ifx_cat1_uart_config *const config = dev->config;
uint32_t rx_intr_pending = ((ifx_cat1_uart_irq_is_pending(dev) & CY_SCB_RX_INTR));
uint32_t num_in_rx_fifo = Cy_SCB_UART_GetNumInRxFifo(config->reg_addr);
if (rx_intr_pending != 0u && num_in_rx_fifo == 0u) {
return 0;
}
return 1;
}
static void ifx_cat1_uart_irq_callback_set(const struct device *dev,
uart_irq_callback_user_data_t cb, void *cb_data)
{
struct ifx_cat1_uart_data *data = dev->data;
/* Store user callback info */
data->irq_cb = cb;
data->irq_cb_data = cb_data;
}
static void ifx_cat1_uart_irq_handler(const struct device *dev)
{
/*
* This function clears the interrupt and makes a callback.
* It does not handle events.
*/
const struct ifx_cat1_uart_config *const config = dev->config;
struct ifx_cat1_uart_data *const data = dev->data;
/* Clear all interrupts that could have been configured */
CySCB_Type *base = config->reg_addr;
uint32_t locRxErr = (CY_SCB_UART_RECEIVE_ERR & Cy_SCB_GetRxInterruptStatusMasked(base));
uint32_t locTxErr = (CY_SCB_UART_TRANSMIT_ERR & Cy_SCB_GetTxInterruptStatusMasked(base));
uint32_t rx_clear = locRxErr | CY_SCB_UART_RX_NOT_EMPTY;
uint32_t tx_clear = locTxErr | CY_SCB_UART_TX_EMPTY | CY_SCB_UART_TX_OVERFLOW |
CY_SCB_TX_INTR_UART_NACK | CY_SCB_TX_INTR_UART_ARB_LOST;
Cy_SCB_ClearRxInterrupt(base, rx_clear);
Cy_SCB_ClearTxInterrupt(base, tx_clear);
/* Call the callback with the callback data.
* This does not guarantee a separate callback per event.
*/
if (data->irq_cb != NULL) {
data->irq_cb(dev, data->irq_cb_data);
}
}
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
/* Default Counter configuration structure */
static const cy_stc_scb_uart_config_t _uart_default_config = {
.uartMode = CY_SCB_UART_STANDARD,
.enableMutliProcessorMode = false,
.smartCardRetryOnNack = false,
.irdaInvertRx = false,
.irdaEnableLowPowerReceiver = false,
.halfDuplexMode = false,
.oversample = 8,
.enableMsbFirst = false,
.dataWidth = 8UL,
.parity = CY_SCB_UART_PARITY_NONE,
.stopBits = CY_SCB_UART_STOP_BITS_1,
.enableInputFilter = false,
.breakWidth = 11UL,
.dropOnFrameError = false,
.dropOnParityError = false,
.breaklevel = false,
.receiverAddress = 0x0UL,
.receiverAddressMask = 0x0UL,
.acceptAddrInFifo = false,
.enableCts = false,
.ctsPolarity = CY_SCB_UART_ACTIVE_LOW,
.rtsRxFifoLevel = 0UL,
.rtsPolarity = CY_SCB_UART_ACTIVE_LOW,
.rxFifoTriggerLevel = 63UL,
.rxFifoIntEnableMask = 0UL,
.txFifoTriggerLevel = 63UL,
.txFifoIntEnableMask = 0UL,
};
#if defined(CY_IP_MXSCB_INSTANCES)
#define _IFX_CAT1_SCB_ARRAY_SIZE (CY_IP_MXSCB_INSTANCES)
#elif defined(CY_IP_M0S8SCB_INSTANCES)
#define _IFX_CAT1_SCB_ARRAY_SIZE (CY_IP_M0S8SCB_INSTANCES)
#elif defined(CY_IP_MXS22SCB_INSTANCES)
#define _IFX_CAT1_SCB_ARRAY_SIZE (CY_IP_MXS22SCB_INSTANCES)
#endif /* CY_IP_MXSCB_INSTANCES */
CySCB_Type *const _IFX_CAT1_SCB_BASE_ADDRESSES[_IFX_CAT1_SCB_ARRAY_SIZE] = {
#ifdef SCB0
SCB0,
#endif
#ifdef SCB1
SCB1,
#endif
#ifdef SCB2
SCB2,
#endif
#ifdef SCB3
SCB3,
#endif
#ifdef SCB4
SCB4,
#endif
#ifdef SCB5
SCB5,
#endif
#ifdef SCB6
SCB6,
#endif
#ifdef SCB7
SCB7,
#endif
#ifdef SCB8
SCB8,
#endif
#ifdef SCB9
SCB9,
#endif
#ifdef SCB10
SCB10,
#endif
#ifdef SCB11
SCB11,
#endif
#ifdef SCB12
SCB12,
#endif
#ifdef SCB13
SCB13,
#endif
#ifdef SCB14
SCB14,
#endif
#ifdef SCB15
SCB15,
#endif
};
const uint8_t _IFX_CAT1_SCB_BASE_ADDRESS_INDEX[_IFX_CAT1_SCB_ARRAY_SIZE] = {
#ifdef SCB0
0u,
#endif
#ifdef SCB1
1u,
#endif
#ifdef SCB2
2u,
#endif
#ifdef SCB3
3u,
#endif
#ifdef SCB4
4u,
#endif
#ifdef SCB5
5u,
#endif
#ifdef SCB6
6u,
#endif
#ifdef SCB7
7u,
#endif
#ifdef SCB8
8u,
#endif
#ifdef SCB9
9u,
#endif
#ifdef SCB10
10u,
#endif
#ifdef SCB11
11u,
#endif
#ifdef SCB12
12u,
#endif
#ifdef SCB13
13u,
#endif
#ifdef SCB14
14u,
#endif
#ifdef SCB15
15u,
#endif
};
int32_t ifx_cat1_uart_get_hw_block_num(CySCB_Type *reg_addr)
{
extern const uint8_t _IFX_CAT1_SCB_BASE_ADDRESS_INDEX[_IFX_CAT1_SCB_ARRAY_SIZE];
uint32_t i;
for (i = 0u; i < _IFX_CAT1_SCB_ARRAY_SIZE; i++) {
if (_IFX_CAT1_SCB_BASE_ADDRESSES[i] == reg_addr) {
return _IFX_CAT1_SCB_BASE_ADDRESS_INDEX[i];
}
}
return -1;
}
static int ifx_cat1_uart_init(const struct device *dev)
{
struct ifx_cat1_uart_data *const data = dev->data;
const struct ifx_cat1_uart_config *const config = dev->config;
cy_rslt_t result;
int ret;
/* Dedicate SCB HW resource */
data->hw_resource.type = IFX_RSC_SCB;
data->hw_resource.block_num = ifx_cat1_uart_get_hw_block_num(config->reg_addr);
/* Configure dt provided device signals when available */
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
if (ret < 0) {
return ret;
}
data->scb_config = _uart_default_config;
result = (cy_rslt_t)Cy_SCB_UART_Init(config->reg_addr, &(data->scb_config),
&(data->context));
if (result == CY_RSLT_SUCCESS) {
irq_enable(config->irq_num);
Cy_SCB_UART_Enable(config->reg_addr);
} else {
return -ENOTSUP;
}
#if (CONFIG_SOC_FAMILY_INFINEON_CAT1C && CONFIG_UART_INTERRUPT_DRIVEN)
/* Enable the UART interrupt */
enable_sys_int(config->irq_num, config->irq_priority,
(void (*)(const void *))(void *)ifx_cat1_uart_irq_handler, &data->obj);
#endif
/* Perform initial Uart configuration */
ret = ifx_cat1_uart_configure(dev, &config->dt_cfg);
return ret;
}
static DEVICE_API(uart, ifx_cat1_uart_driver_api) = {
.poll_in = ifx_cat1_uart_poll_in,
.poll_out = ifx_cat1_uart_poll_out,
.err_check = ifx_cat1_uart_err_check,
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
.configure = ifx_cat1_uart_configure,
.config_get = ifx_cat1_uart_config_get,
#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
.fifo_fill = ifx_cat1_uart_fifo_fill,
.fifo_read = ifx_cat1_uart_fifo_read,
.irq_tx_enable = ifx_cat1_uart_irq_tx_enable,
.irq_tx_disable = ifx_cat1_uart_irq_tx_disable,
.irq_tx_ready = ifx_cat1_uart_irq_tx_ready,
.irq_rx_enable = ifx_cat1_uart_irq_rx_enable,
.irq_rx_disable = ifx_cat1_uart_irq_rx_disable,
.irq_tx_complete = ifx_cat1_uart_irq_tx_complete,
.irq_rx_ready = ifx_cat1_uart_irq_rx_ready,
.irq_err_enable = ifx_cat1_uart_irq_err_enable,
.irq_err_disable = ifx_cat1_uart_irq_err_disable,
.irq_is_pending = ifx_cat1_uart_irq_is_pending,
.irq_update = ifx_cat1_uart_irq_update,
.irq_callback_set = ifx_cat1_uart_irq_callback_set,
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
};
#if (CONFIG_SOC_FAMILY_INFINEON_CAT1C)
#define IRQ_INFO(n) \
.irq_num = DT_INST_PROP_BY_IDX(n, system_interrupts, SYS_INT_NUM), \
.irq_priority = DT_INST_PROP_BY_IDX(n, system_interrupts, SYS_INT_PRI)
#else
#define IRQ_INFO(n) .irq_num = DT_INST_IRQN(n), .irq_priority = DT_INST_IRQ(n, priority)
#endif
#if defined(COMPONENT_CAT1B) || defined(COMPONENT_CAT1C)
#define PERI_INFO(n) .clock_peri_group = DT_PROP_BY_IDX(DT_INST_PHANDLE(n, clocks), peri_group, 1),
#else
#define PERI_INFO(n)
#endif
#if (CONFIG_UART_INTERRUPT_DRIVEN)
#define INTERRUPT_DRIVEN_UART_INIT(n) \
void uart_handle_events_func_##n(void) \
{ \
ifx_cat1_uart_irq_handler(DEVICE_DT_INST_GET(n)); \
} \
static void ifx_cat1_uart_irq_config_func_##n(void) \
{ \
IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \
uart_handle_events_func_##n, DEVICE_DT_INST_GET(n), 0); \
}
#define CALL_UART_IRQ_CONFIG(n) ifx_cat1_uart_irq_config_func_##n();
#else
#define INTERRUPT_DRIVEN_UART_INIT(n)
#define CALL_UART_IRQ_CONFIG(n)
#endif
#define UART_PERI_CLOCK_INIT(n) \
.clock = \
{ \
.block = IFX_CAT1_PERIPHERAL_GROUP_ADJUST( \
DT_PROP_BY_IDX(DT_INST_PHANDLE(n, clocks), peri_group, 1), \
DT_INST_PROP_BY_PHANDLE(n, clocks, div_type)), \
.channel = DT_INST_PROP_BY_PHANDLE(n, clocks, channel), \
}, \
PERI_INFO(n)
#define INFINEON_CAT1_UART_INIT(n) \
PINCTRL_DT_INST_DEFINE(n); \
INTERRUPT_DRIVEN_UART_INIT(n) \
static struct ifx_cat1_uart_data ifx_cat1_uart##n##_data = {UART_PERI_CLOCK_INIT(n)}; \
\
static int ifx_cat1_uart_init##n(const struct device *dev) \
{ \
CALL_UART_IRQ_CONFIG(n); \
return ifx_cat1_uart_init(dev); \
} \
\
static struct ifx_cat1_uart_config ifx_cat1_uart##n##_cfg = { \
.dt_cfg.baudrate = DT_INST_PROP(n, current_speed), \
.dt_cfg.parity = DT_INST_ENUM_IDX_OR(n, parity, UART_CFG_PARITY_NONE), \
.dt_cfg.stop_bits = DT_INST_ENUM_IDX_OR(n, stop_bits, UART_CFG_STOP_BITS_1), \
.dt_cfg.data_bits = DT_INST_ENUM_IDX_OR(n, data_bits, UART_CFG_DATA_BITS_8), \
.dt_cfg.flow_ctrl = DT_INST_PROP(n, hw_flow_control), \
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
.reg_addr = (CySCB_Type *)DT_INST_REG_ADDR(n), \
IRQ_INFO(n)}; \
\
DEVICE_DT_INST_DEFINE(n, &ifx_cat1_uart_init##n, NULL, &ifx_cat1_uart##n##_data, \
&ifx_cat1_uart##n##_cfg, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
&ifx_cat1_uart_driver_api);
DT_INST_FOREACH_STATUS_OKAY(INFINEON_CAT1_UART_INIT)