diff --git a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml index e5630bd2821..09fe856c766 100644 --- a/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml +++ b/boards/arm/xmc47_relax_kit/xmc47_relax_kit.yaml @@ -9,6 +9,7 @@ supported: - adc - dma - gpio + - i2c - spi - uart ram: 352 diff --git a/drivers/i2c/CMakeLists.txt b/drivers/i2c/CMakeLists.txt index 6362ae46ecd..82b716ac13c 100644 --- a/drivers/i2c/CMakeLists.txt +++ b/drivers/i2c/CMakeLists.txt @@ -46,6 +46,7 @@ zephyr_library_sources_ifdef(CONFIG_I2C_TCA954X i2c_tca954x.c) zephyr_library_sources_ifdef(CONFIG_I2C_XEC_V2 i2c_mchp_xec_v2.c) zephyr_library_sources_ifdef(CONFIG_I2C_GD32 i2c_gd32.c) zephyr_library_sources_ifdef(CONFIG_I2C_INFINEON_CAT1 i2c_ifx_cat1.c) +zephyr_library_sources_ifdef(CONFIG_I2C_INFINEON_XMC4 i2c_ifx_xmc4.c) zephyr_library_sources_ifdef(CONFIG_I2C_ANDES_ATCIIC100 i2c_andes_atciic100.c) zephyr_library_sources_ifdef(CONFIG_I2C_SC18IM704 i2c_sc18im704.c) zephyr_library_sources_ifdef(CONFIG_I2C_SMARTBOND i2c_smartbond.c) diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 159cab781cc..003b33d8aa5 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -70,6 +70,7 @@ source "drivers/i2c/Kconfig.rcar" source "drivers/i2c/Kconfig.tca954x" source "drivers/i2c/Kconfig.gd32" source "drivers/i2c/Kconfig.ifx_cat1" +source "drivers/i2c/Kconfig.ifx_xmc4" source "drivers/i2c/Kconfig.andes_atciic100" source "drivers/i2c/Kconfig.sc18im704" source "drivers/i2c/Kconfig.smartbond" diff --git a/drivers/i2c/Kconfig.ifx_xmc4 b/drivers/i2c/Kconfig.ifx_xmc4 new file mode 100644 index 00000000000..52231d48735 --- /dev/null +++ b/drivers/i2c/Kconfig.ifx_xmc4 @@ -0,0 +1,25 @@ +# Infineon XMC4 I2C configuration options + +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +menuconfig I2C_INFINEON_XMC4 + bool "Infineon XMC4 I2C driver" + default y + depends on DT_HAS_INFINEON_XMC4_I2C_ENABLED + help + This option enables the I2C driver for Infineon XMC4 family. + +if I2C_INFINEON_XMC4 + +config I2C_INFINEON_XMC4_TARGET_BUF + int "I2C Target data buffer length" + depends on I2C_INFINEON_XMC4 + range 1 1024 + default 64 + help + Buffer to receive data as an I2C Target. + +endif # I2C_INFINEON_XMC4 diff --git a/drivers/i2c/i2c_ifx_xmc4.c b/drivers/i2c/i2c_ifx_xmc4.c new file mode 100644 index 00000000000..2a882170519 --- /dev/null +++ b/drivers/i2c/i2c_ifx_xmc4.c @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or + * an affiliate of Cypress Semiconductor Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @brief I2C driver for Infineon XMC MCU family. + */ + +#define DT_DRV_COMPAT infineon_xmc4_i2c + +#include +#include + +#include +#include + +#define USIC_IRQ_MIN 84 +#define IRQS_PER_USIC 6 + +#include +LOG_MODULE_REGISTER(i2c_infineon_xmc4, CONFIG_I2C_LOG_LEVEL); + +#define I2C_XMC_EVENTS_MASK ( \ + XMC_I2C_CH_EVENT_RECEIVE_START | \ + XMC_I2C_CH_EVENT_DATA_LOST | \ + XMC_I2C_CH_EVENT_TRANSMIT_SHIFT | \ + XMC_I2C_CH_EVENT_TRANSMIT_BUFFER | \ + XMC_I2C_CH_EVENT_STANDARD_RECEIVE | \ + XMC_I2C_CH_EVENT_ALTERNATIVE_RECEIVE | \ + XMC_I2C_CH_EVENT_BAUD_RATE_GENERATOR | \ + XMC_I2C_CH_EVENT_START_CONDITION_RECEIVED | \ + XMC_I2C_CH_EVENT_REPEATED_START_CONDITION_RECEIVED | \ + XMC_I2C_CH_EVENT_STOP_CONDITION_RECEIVED | \ + XMC_I2C_CH_EVENT_NACK | \ + XMC_I2C_CH_EVENT_ARBITRATION_LOST | \ + XMC_I2C_CH_EVENT_SLAVE_READ_REQUEST | \ + XMC_I2C_CH_EVENT_ERROR | \ + XMC_I2C_CH_EVENT_ACK) + +#define I2C_XMC_STATUS_FLAG_ERROR_MASK ( \ + XMC_I2C_CH_STATUS_FLAG_WRONG_TDF_CODE_FOUND | \ + XMC_I2C_CH_STATUS_FLAG_NACK_RECEIVED | \ + XMC_I2C_CH_STATUS_FLAG_ARBITRATION_LOST | \ + XMC_I2C_CH_STATUS_FLAG_ERROR | \ + XMC_I2C_CH_STATUS_FLAG_DATA_LOST_INDICATION) + +/* I2C speed */ +#define XMC4_I2C_SPEED_STANDARD (100000UL) +#define XMC4_I2C_SPEED_FAST (400000UL) + +/* Data structure */ +struct ifx_xmc4_i2c_data { + XMC_I2C_CH_CONFIG_t cfg; + struct k_sem operation_sem; + struct k_sem target_sem; + struct i2c_target_config *p_target_config; + uint32_t dev_config; + uint8_t target_wr_byte; + uint8_t target_wr_buffer[CONFIG_I2C_INFINEON_XMC4_TARGET_BUF]; + bool ignore_slave_select; +}; + +/* Device config structure */ +struct ifx_xmc4_i2c_config { + XMC_USIC_CH_t *i2c; + const struct pinctrl_dev_config *pcfg; + uint8_t scl_src; + uint8_t sda_src; + uint32_t master_frequency; + void (*irq_config_func)(const struct device *dev); +}; + +static int ifx_xmc4_i2c_configure(const struct device *dev, uint32_t dev_config) +{ + struct ifx_xmc4_i2c_data *data = dev->data; + const struct ifx_xmc4_i2c_config *config = dev->config; + + if (dev_config != 0) { + switch (I2C_SPEED_GET(dev_config)) { + case I2C_SPEED_STANDARD: + data->cfg.baudrate = XMC4_I2C_SPEED_STANDARD; + break; + case I2C_SPEED_FAST: + data->cfg.baudrate = XMC4_I2C_SPEED_FAST; + break; + default: + LOG_ERR("Unsupported speed"); + return -ERANGE; + } + + /* This is deprecated and could be ignored in the future */ + if (dev_config & I2C_ADDR_10_BITS) { + LOG_ERR("Use I2C_MSG_ADDR_10_BITS instead of I2C_ADDR_10_BITS"); + return -EIO; + } + } + + data->dev_config = dev_config; + + /* Acquire semaphore (block I2C operation for another thread) */ + if (k_sem_take(&data->operation_sem, K_FOREVER)) { + return -EIO; + } + + /* Configure the I2C resource */ + data->cfg.normal_divider_mode = false; + XMC_I2C_CH_Init(config->i2c, &data->cfg); + XMC_I2C_CH_SetInputSource(config->i2c, XMC_I2C_CH_INPUT_SCL, config->scl_src); + XMC_I2C_CH_SetInputSource(config->i2c, XMC_I2C_CH_INPUT_SDA, config->sda_src); + if (data->dev_config & I2C_MODE_CONTROLLER) { + XMC_USIC_CH_SetFractionalDivider(config->i2c, + XMC_USIC_CH_BRG_CLOCK_DIVIDER_MODE_FRACTIONAL, + 1023U); + } else { + config->irq_config_func(dev); + } + XMC_I2C_CH_Start(config->i2c); + + /* Release semaphore */ + k_sem_give(&data->operation_sem); + + return 0; +} + +static int ifx_xmc4_i2c_get_config(const struct device *dev, uint32_t *dev_config) +{ + struct ifx_xmc4_i2c_data *data = dev->data; + uint32_t config; + + switch (data->cfg.baudrate) { + case XMC4_I2C_SPEED_STANDARD: + config = I2C_SPEED_SET(I2C_SPEED_STANDARD); + break; + case XMC4_I2C_SPEED_FAST: + config = I2C_SPEED_SET(I2C_SPEED_FAST); + break; + default: + LOG_ERR("Unsupported speed"); + return -ERANGE; + } + + if (data->dev_config & I2C_MODE_CONTROLLER) { + config |= I2C_MODE_CONTROLLER; + } + + /* Return current configuration */ + *dev_config = config; + + return 0; +} + +static int ifx_xmc4_i2c_msg_validate(struct i2c_msg *msg, uint8_t num_msgs) +{ + for (uint32_t i = 0u; i < num_msgs; i++) { + if ((I2C_MSG_ADDR_10_BITS & msg[i].flags) || (msg[i].buf == NULL)) { + return -EINVAL; + } + } + return 0; +} + +static int ifx_xmc4_i2c_transfer(const struct device *dev, struct i2c_msg *msg, uint8_t num_msgs, + uint16_t addr) +{ + struct ifx_xmc4_i2c_data *data = dev->data; + const struct ifx_xmc4_i2c_config *config = dev->config; + XMC_I2C_CH_CMD_t cmd_type; + + if (!num_msgs) { + return 0; + } + + /* Acquire semaphore (block I2C transfer for another thread) */ + if (k_sem_take(&data->operation_sem, K_FOREVER)) { + return -EIO; + } + + /* This function checks if msg.buf is not NULL and if target address is not 10 bit. */ + if (ifx_xmc4_i2c_msg_validate(msg, num_msgs) != 0) { + k_sem_give(&data->operation_sem); + return -EINVAL; + } + + for (uint32_t msg_index = 0u; msg_index < num_msgs; msg_index++) { + XMC_I2C_CH_ClearStatusFlag(config->i2c, 0xFFFFFFFF); + + if ((msg_index == 0) || (msg[msg_index].flags & I2C_MSG_RESTART)) { + /* Send START conditon */ + cmd_type = ((msg[msg_index].flags & I2C_MSG_RW_MASK) == I2C_MSG_READ) ? + XMC_I2C_CH_CMD_READ : XMC_I2C_CH_CMD_WRITE; + + if (msg[msg_index].flags & I2C_MSG_RESTART) { + XMC_I2C_CH_MasterRepeatedStart(config->i2c, addr << 1, cmd_type); + } else { + XMC_I2C_CH_MasterStart(config->i2c, addr << 1, cmd_type); + } + + /* Wait for acknowledge */ + while ((XMC_I2C_CH_GetStatusFlag(config->i2c) & + XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED) == 0U) { + /* wait for ACK from slave */ + if (XMC_I2C_CH_GetStatusFlag(config->i2c) & + I2C_XMC_STATUS_FLAG_ERROR_MASK) { + k_sem_give(&data->operation_sem); + return -EIO; + } + } + XMC_I2C_CH_ClearStatusFlag(config->i2c, + XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED); + } + + for (uint32_t buf_index = 0u; buf_index < msg[msg_index].len; buf_index++) { + if (cmd_type == XMC_I2C_CH_CMD_WRITE) { + /* Transmit next command from I2C master to I2C slave */ + XMC_I2C_CH_MasterTransmit(config->i2c, + msg[msg_index].buf[buf_index]); + + /* Wait for acknowledge */ + while ((XMC_I2C_CH_GetStatusFlag(config->i2c) & + XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED) == 0U) { + /* wait for ACK from slave */ + if (XMC_I2C_CH_GetStatusFlag(config->i2c) & + I2C_XMC_STATUS_FLAG_ERROR_MASK) { + k_sem_give(&data->operation_sem); + return -EIO; + } + } + XMC_I2C_CH_ClearStatusFlag(config->i2c, + XMC_I2C_CH_STATUS_FLAG_ACK_RECEIVED); + + /* Wait until TX FIFO is empty */ + while (!XMC_USIC_CH_TXFIFO_IsEmpty(config->i2c)) { + /* wait until all data is sent by HW */ + if (XMC_I2C_CH_GetStatusFlag(config->i2c) & + I2C_XMC_STATUS_FLAG_ERROR_MASK) { + k_sem_give(&data->operation_sem); + return -EIO; + } + } + } else { + if (buf_index == (msg[msg_index].len - 1)) { + XMC_I2C_CH_MasterReceiveNack(config->i2c); + } else { + XMC_I2C_CH_MasterReceiveAck(config->i2c); + } + + while ((XMC_I2C_CH_GetStatusFlag(config->i2c) & + (XMC_I2C_CH_STATUS_FLAG_ALTERNATIVE_RECEIVE_INDICATION | + XMC_I2C_CH_STATUS_FLAG_RECEIVE_INDICATION)) == 0U) { + /* wait for data byte from slave */ + if (XMC_I2C_CH_GetStatusFlag(config->i2c) & + I2C_XMC_STATUS_FLAG_ERROR_MASK) { + k_sem_give(&data->operation_sem); + return -EIO; + } + } + XMC_I2C_CH_ClearStatusFlag(config->i2c, + XMC_I2C_CH_STATUS_FLAG_ALTERNATIVE_RECEIVE_INDICATION | + XMC_I2C_CH_STATUS_FLAG_RECEIVE_INDICATION); + + msg[msg_index].buf[buf_index] = + XMC_I2C_CH_GetReceivedData(config->i2c); + } + } + + /* Send STOP conditon */ + if (msg[msg_index].flags & I2C_MSG_STOP) { + XMC_I2C_CH_MasterStop(config->i2c); + } + } + + /* Release semaphore (After I2C transfer is complete) */ + k_sem_give(&data->operation_sem); + return 0; +} + +static int ifx_xmc4_i2c_init(const struct device *dev) +{ + struct ifx_xmc4_i2c_data *data = dev->data; + const struct ifx_xmc4_i2c_config *config = dev->config; + int ret; + + /* Configure semaphores */ + ret = k_sem_init(&data->operation_sem, 1, 1); + if (ret) { + return ret; + } + + ret = k_sem_init(&data->target_sem, 1, 1); + if (ret) { + return ret; + } + + /* Configure dt provided device signals when available */ + ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + return ret; + } + + return 0; +} + +static int ifx_xmc4_i2c_target_register(const struct device *dev, struct i2c_target_config *cfg) +{ + struct ifx_xmc4_i2c_data *data = (struct ifx_xmc4_i2c_data *)dev->data; + + if (!cfg || + !cfg->callbacks->read_requested || + !cfg->callbacks->read_processed || + !cfg->callbacks->write_requested || + !cfg->callbacks->write_received || + !cfg->callbacks->stop) { + return -EINVAL; + } + + if (cfg->flags & I2C_TARGET_FLAGS_ADDR_10_BITS) { + return -ENOTSUP; + } + + /* Acquire semaphore (block I2C operation for another thread) */ + if (k_sem_take(&data->target_sem, K_FOREVER)) { + return -EIO; + } + + data->p_target_config = cfg; + data->cfg.address = cfg->address << 1; + + if (ifx_xmc4_i2c_configure(dev, I2C_SPEED_SET(I2C_SPEED_STANDARD)) != 0) { + /* Release semaphore */ + k_sem_give(&data->target_sem); + return -EIO; + } + + k_sem_give(&data->target_sem); + return 0; +} + +static int ifx_xmc4_i2c_target_unregister(const struct device *dev, struct i2c_target_config *cfg) +{ + struct ifx_xmc4_i2c_data *data = (struct ifx_xmc4_i2c_data *)dev->data; + const struct ifx_xmc4_i2c_config *config = dev->config; + + /* Acquire semaphore (block I2C operation for another thread) */ + if (k_sem_take(&data->operation_sem, K_FOREVER)) { + return -EIO; + } + + data->p_target_config = NULL; + XMC_I2C_CH_DisableEvent(config->i2c, I2C_XMC_EVENTS_MASK); + + /* Release semaphore */ + k_sem_give(&data->operation_sem); + return 0; +} + + +static void i2c_xmc4_isr(const struct device *dev) +{ + struct ifx_xmc4_i2c_data *data = dev->data; + const struct ifx_xmc4_i2c_config *config = dev->config; + const struct i2c_target_callbacks *callbacks = data->p_target_config->callbacks; + uint32_t status = XMC_I2C_CH_GetStatusFlag(config->i2c); + + while (status) { + XMC_I2C_CH_ClearStatusFlag(config->i2c, status); + + if (status & XMC_I2C_CH_STATUS_FLAG_STOP_CONDITION_RECEIVED) { + /* Flush the TX buffer */ + XMC_USIC_CH_SetTransmitBufferStatus(config->i2c, + XMC_USIC_CH_TBUF_STATUS_SET_IDLE); + + callbacks->stop(data->p_target_config); + break; + } + + if (!data->ignore_slave_select && (status & XMC_I2C_CH_STATUS_FLAG_SLAVE_SELECT)) { + data->ignore_slave_select = true; + + /* Start a slave read */ + if (status & XMC_I2C_CH_STATUS_FLAG_SLAVE_READ_REQUESTED) { + callbacks->read_requested(data->p_target_config, + &data->target_wr_byte); + XMC_I2C_CH_SlaveTransmit(config->i2c, data->target_wr_byte); + } else { + callbacks->write_requested(data->p_target_config); + } + } + + /* Continue a slave read */ + if (status & XMC_I2C_CH_STATUS_FLAG_TRANSMIT_SHIFT_INDICATION) { + callbacks->read_processed(data->p_target_config, &data->target_wr_byte); + XMC_I2C_CH_SlaveTransmit(config->i2c, data->target_wr_byte); + } + + /* Start/Continue a slave write */ + if (status & (XMC_I2C_CH_STATUS_FLAG_RECEIVE_INDICATION | + XMC_I2C_CH_STATUS_FLAG_ALTERNATIVE_RECEIVE_INDICATION)) { + callbacks->write_received(data->p_target_config, + XMC_I2C_CH_GetReceivedData(config->i2c)); + } + + if ((status & XMC_I2C_CH_STATUS_FLAG_START_CONDITION_RECEIVED) || + (status & XMC_I2C_CH_STATUS_FLAG_REPEATED_START_CONDITION_RECEIVED)) { + data->ignore_slave_select = false; + } + + status = XMC_I2C_CH_GetStatusFlag(config->i2c); + } +} + + +/* I2C API structure */ +static const struct i2c_driver_api i2c_xmc4_driver_api = { + .configure = ifx_xmc4_i2c_configure, + .transfer = ifx_xmc4_i2c_transfer, + .get_config = ifx_xmc4_i2c_get_config, + .target_register = ifx_xmc4_i2c_target_register, + .target_unregister = ifx_xmc4_i2c_target_unregister}; + +/* Macros for I2C instance declaration */ +#define XMC4_IRQ_HANDLER_INIT(index) \ + static void i2c_xmc4_irq_setup_##index(const struct device *dev) \ + { \ + const struct ifx_xmc4_i2c_config *config = dev->config; \ + uint8_t irq_num = DT_INST_IRQN(index); \ + uint8_t service_request = (irq_num - USIC_IRQ_MIN) % IRQS_PER_USIC; \ + \ + XMC_I2C_CH_SelectInterruptNodePointer(config->i2c, \ + XMC_I2C_CH_INTERRUPT_NODE_POINTER_RECEIVE, service_request); \ + XMC_I2C_CH_SelectInterruptNodePointer(config->i2c, \ + XMC_I2C_CH_INTERRUPT_NODE_POINTER_ALTERNATE_RECEIVE, service_request); \ + \ + XMC_I2C_CH_EnableEvent(config->i2c, I2C_XMC_EVENTS_MASK); \ + \ + IRQ_CONNECT(DT_INST_IRQN(index), DT_INST_IRQ(index, priority), i2c_xmc4_isr, \ + DEVICE_DT_INST_GET(index), 0); \ + \ + irq_enable(irq_num); \ + } + +#define XMC4_IRQ_HANDLER_STRUCT_INIT(index) .irq_config_func = i2c_xmc4_irq_setup_##index + +#define INFINEON_XMC4_I2C_INIT(n) \ + PINCTRL_DT_INST_DEFINE(n); \ + XMC4_IRQ_HANDLER_INIT(n) \ + \ + static struct ifx_xmc4_i2c_data ifx_xmc4_i2c_data##n; \ + \ + static const struct ifx_xmc4_i2c_config i2c_xmc4_cfg_##n = { \ + .i2c = (XMC_USIC_CH_t *)DT_INST_REG_ADDR(n), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .scl_src = DT_INST_ENUM_IDX(n, scl_src), \ + .sda_src = DT_INST_ENUM_IDX(n, sda_src), \ + .master_frequency = DT_INST_PROP_OR(n, clock_frequency, XMC4_I2C_SPEED_STANDARD), \ + XMC4_IRQ_HANDLER_STRUCT_INIT(n) \ + }; \ + \ + I2C_DEVICE_DT_INST_DEFINE(n, ifx_xmc4_i2c_init, NULL, &ifx_xmc4_i2c_data##n, \ + &i2c_xmc4_cfg_##n, POST_KERNEL, \ + CONFIG_I2C_INIT_PRIORITY, &i2c_xmc4_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(INFINEON_XMC4_I2C_INIT) diff --git a/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi b/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi index 537d27b36f5..dd03fad3617 100644 --- a/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi +++ b/dts/arm/infineon/xmc4700_F144x2048-pinctrl.dtsi @@ -593,4 +593,125 @@ pinmux = ; hwctrl = "periph2"; }; + + /omit-if-no-ref/ i2c_controller_scl_p0_8_u0c0: i2c_controller_scl_p0_8_u0c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_scl_p1_1_u0c0: i2c_controller_scl_p1_1_u0c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_scl_p2_4_u0c1: i2c_controller_scl_p2_4_u0c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_scl_p3_0_u0c1: i2c_controller_scl_p3_0_u0c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_scl_p6_2_u0c1: i2c_controller_scl_p6_2_u0c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_scl_p0_11_u1c0: i2c_controller_scl_p0_11_u1c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_scl_p5_8_u1c0: i2c_controller_scl_p5_8_u1c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_scl_p0_10_u1c1: i2c_controller_scl_p0_10_u1c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_scl_p0_13_u1c1: i2c_controller_scl_p0_13_u1c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_scl_p5_2_u2c0: i2c_controller_scl_p5_2_u2c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_scl_p3_6_u2c1: i2c_controller_scl_p3_6_u2c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_sda_p1_5_u0c0: i2c_controller_sda_p1_5_u0c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_sda_p2_5_u0c1: i2c_controller_sda_p2_5_u0c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_sda_p3_13_u0c1: i2c_controller_sda_p3_13_u0c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_sda_p0_5_u1c0: i2c_controller_sda_p0_5_u1c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_sda_p2_14_u1c0: i2c_controller_sda_p2_14_u1c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_sda_p3_15_u1c1: i2c_controller_sda_p3_15_u1c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_sda_p4_2_u1c1: i2c_controller_sda_p4_2_u1c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_sda_p5_0_u2c0: i2c_controller_sda_p5_0_u2c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_controller_sda_p3_5_u2c1: i2c_controller_sda_p3_5_u2c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p0_8_u0c0: i2c_target_scl_p0_8_u0c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p1_1_u0c0: i2c_target_scl_p1_1_u0c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p2_4_u0c1: i2c_target_scl_p2_4_u0c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p3_0_u0c1: i2c_target_scl_p3_0_u0c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p6_2_u0c1: i2c_target_scl_p6_2_u0c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p0_11_u1c0: i2c_target_scl_p0_11_u1c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p5_8_u1c0: i2c_target_scl_p5_8_u1c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p0_10_u1c1: i2c_target_scl_p0_10_u1c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p0_13_u1c1: i2c_target_scl_p0_13_u1c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p5_2_u2c0: i2c_target_scl_p5_2_u2c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_scl_p3_6_u2c1: i2c_target_scl_p3_6_u2c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_sda_p1_5_u0c0: i2c_target_sda_p1_5_u0c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_sda_p2_5_u0c1: i2c_target_sda_p2_5_u0c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_sda_p3_13_u0c1: i2c_target_sda_p3_13_u0c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_sda_p0_5_u1c0: i2c_target_sda_p0_5_u1c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_sda_p2_14_u1c0: i2c_target_sda_p2_14_u1c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_sda_p3_15_u1c1: i2c_target_sda_p3_15_u1c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_sda_p4_2_u1c1: i2c_target_sda_p4_2_u1c1 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_sda_p5_0_u2c0: i2c_target_sda_p5_0_u2c0 { + pinmux = ; + }; + /omit-if-no-ref/ i2c_target_sda_p3_5_u2c1: i2c_target_sda_p3_5_u2c1 { + pinmux = ; + }; }; diff --git a/dts/bindings/i2c/infineon,cat1-i2c.yaml b/dts/bindings/i2c/infineon,cat1-i2c.yaml index 2ed002a2c97..fa7ca1b8f4a 100644 --- a/dts/bindings/i2c/infineon,cat1-i2c.yaml +++ b/dts/bindings/i2c/infineon,cat1-i2c.yaml @@ -21,10 +21,10 @@ properties: pinctrl-0: description: | PORT pin configuration for SCL, SDA signals. - We expect that the phandles will reference pinctrl nodes.These + We expect that the phandles will reference pinctrl nodes. These nodes will have a nodelabel that matches the Infineon SoC Pinctrl defines and have following - format: p__. + format: p___. Examples: pinctrl-0 = <&p6_0_scb3_i2c_scl &p6_1_scb3_i2c_sda>; diff --git a/dts/bindings/i2c/infineon,xmc4-i2c.yaml b/dts/bindings/i2c/infineon,xmc4-i2c.yaml new file mode 100644 index 00000000000..7672bdf1b49 --- /dev/null +++ b/dts/bindings/i2c/infineon,xmc4-i2c.yaml @@ -0,0 +1,77 @@ +# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or +# an affiliate of Cypress Semiconductor Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +description: Infineon XMC4 I2C + +compatible: "infineon,xmc4-i2c" + +include: [i2c-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + type: array + required: true + + scl-src: + description: | + Connects the I2C clock line (USIC DX0 input) to a specific GPIO pin. + The USIC DX0 input is a multiplexer which connects to different GPIO pins. + Refer to the XMC4XXX reference manual for the GPIO pin/mux mappings. + type: string + required: true + enum: + - "DX0A" + - "DX0B" + - "DX0C" + - "DX0D" + - "DX0E" + - "DX0F" + - "DX0G" + + sda-src: + description: | + Connects the I2C data line (USIC DX0 input) to a specific GPIO pin. + The USIC DX0 input is a multiplexer which connects to different GPIO pins. + Refer to the XMC4XXX reference manual for the GPIO pin/mux mappings. + type: string + required: true + enum: + - "DX0A" + - "DX0B" + - "DX0C" + - "DX0D" + - "DX0E" + - "DX0F" + - "DX0G" + + interrupts: + type: array + required: true + description: | + IRQ number and priority to use for interrupt driven by I2C. + Each USIC must use a certain interrupt range: + USIC0 = [84, 89] + USIC1 = [90, 95] + USIC2 = [96, 101] + + pinctrl-0: + description: | + PORT pin configuration for SCL, SDA signals. + We expect that the phandles will reference pinctrl nodes. These + nodes will have a nodelabel that matches the Infineon SoC Pinctrl + defines and have following + format: _p__ + + Examples: + pinctrl-0 = <&i2c_scl_p5_2_u2c0 &i2c_sda_p5_0_u2c0>; + required: true + + pinctrl-names: + required: true + + clock-frequency: + type: int + description: | + Frequency that the I2C bus runs diff --git a/include/zephyr/dt-bindings/pinctrl/xmc4xxx-pinctrl.h b/include/zephyr/dt-bindings/pinctrl/xmc4xxx-pinctrl.h index 2fed5aff280..f209b719222 100644 --- a/include/zephyr/dt-bindings/pinctrl/xmc4xxx-pinctrl.h +++ b/include/zephyr/dt-bindings/pinctrl/xmc4xxx-pinctrl.h @@ -16,33 +16,33 @@ #define XMC4XXX_PIN_MASK 0xf #define XMC4XXX_ALT_POS 8 -#define XMC4XXX_ALT_MASK 0xf +#define XMC4XXX_ALT_MASK 0x1f -#define XMC4XXX_PULL_DOWN_POS 12 +#define XMC4XXX_PULL_DOWN_POS 13 #define XMC4XXX_PULL_DOWN_MASK 0x1 -#define XMC4XXX_PULL_UP_POS 13 +#define XMC4XXX_PULL_UP_POS 14 #define XMC4XXX_PULL_UP_MASK 0x1 -#define XMC4XXX_PUSH_PULL_POS 14 +#define XMC4XXX_PUSH_PULL_POS 15 #define XMC4XXX_PUSH_PULL_MASK 0x1 -#define XMC4XXX_OPEN_DRAIN_POS 15 +#define XMC4XXX_OPEN_DRAIN_POS 16 #define XMC4XXX_OPEN_DRAIN_MASK 0x1 -#define XMC4XXX_OUT_HIGH_POS 16 +#define XMC4XXX_OUT_HIGH_POS 17 #define XMC4XXX_OUT_HIGH_MASK 0x1 -#define XMC4XXX_OUT_LOW_POS 17 +#define XMC4XXX_OUT_LOW_POS 18 #define XMC4XXX_OUT_LOW_MASK 0x1 -#define XMC4XXX_INV_INPUT_POS 18 +#define XMC4XXX_INV_INPUT_POS 19 #define XMC4XXX_INV_INPUT_MASK 0x1 -#define XMC4XXX_DRIVE_POS 19 +#define XMC4XXX_DRIVE_POS 20 #define XMC4XXX_DRIVE_MASK 0x7 -#define XMC4XXX_HWCTRL_POS 22 +#define XMC4XXX_HWCTRL_POS 23 #define XMC4XXX_HWCTRL_MASK 0x3 /* Setters and getters */ diff --git a/modules/Kconfig.infineon b/modules/Kconfig.infineon index 0268a8db008..87d140bc9af 100644 --- a/modules/Kconfig.infineon +++ b/modules/Kconfig.infineon @@ -40,4 +40,9 @@ config HAS_XMCLIB_SPI help Enable XMCLIB SPI +config HAS_XMCLIB_I2C + bool + help + Enable XMCLIB I2C + endif # HAS_XMCLIB diff --git a/soc/arm/infineon_xmc/4xxx/Kconfig.series b/soc/arm/infineon_xmc/4xxx/Kconfig.series index 4e130ba3563..66a93102352 100644 --- a/soc/arm/infineon_xmc/4xxx/Kconfig.series +++ b/soc/arm/infineon_xmc/4xxx/Kconfig.series @@ -18,5 +18,6 @@ config SOC_SERIES_XMC_4XXX select HAS_XMCLIB_VADC select HAS_XMCLIB_DMA select HAS_XMCLIB_SPI + select HAS_XMCLIB_I2C help Enable support for XMC 4xxx MCU series diff --git a/tests/drivers/i2c/i2c_api/boards/xmc47_relax_kit.conf b/tests/drivers/i2c/i2c_api/boards/xmc47_relax_kit.conf new file mode 100644 index 00000000000..9ef6cbaaa50 --- /dev/null +++ b/tests/drivers/i2c/i2c_api/boards/xmc47_relax_kit.conf @@ -0,0 +1 @@ +CONFIG_I2C_INFINEON_XMC4_TARGET_BUF=128 diff --git a/tests/drivers/i2c/i2c_api/boards/xmc47_relax_kit.overlay b/tests/drivers/i2c/i2c_api/boards/xmc47_relax_kit.overlay new file mode 100644 index 00000000000..9403069a596 --- /dev/null +++ b/tests/drivers/i2c/i2c_api/boards/xmc47_relax_kit.overlay @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or + * an affiliate of Cypress Semiconductor Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + i2c-0 = &usic0ch1; + }; +}; + +&i2c_controller_scl_p6_2_u0c1 { + drive-strength = "strong-sharp-edge"; + hwctrl = "disabled"; +}; + +&i2c_controller_sda_p3_13_u0c1 { + drive-strength = "strong-soft-edge"; + hwctrl = "disabled"; +}; + +&usic0ch1 { + compatible = "infineon,xmc4-i2c"; + pinctrl-0 = <&i2c_controller_scl_p6_2_u0c1 &i2c_controller_sda_p3_13_u0c1>; + pinctrl-names = "default"; + scl-src = "DX0C"; + sda-src = "DX0D"; + interrupts = <86 1>; + + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; +};