driver: i2c: infineon: Adding XMC4 I2C driver
- This includes the driver, test app, and sample app - Only the boards\arm\xmc47_relax_kit board is supported for now Signed-off-by: Bill Waters <bill.waters@infineon.com>
This commit is contained in:
parent
cf29b8caad
commit
541482ff20
13 changed files with 745 additions and 12 deletions
|
@ -9,6 +9,7 @@ supported:
|
|||
- adc
|
||||
- dma
|
||||
- gpio
|
||||
- i2c
|
||||
- spi
|
||||
- uart
|
||||
ram: 352
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
25
drivers/i2c/Kconfig.ifx_xmc4
Normal file
25
drivers/i2c/Kconfig.ifx_xmc4
Normal file
|
@ -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
|
465
drivers/i2c/i2c_ifx_xmc4.c
Normal file
465
drivers/i2c/i2c_ifx_xmc4.c
Normal file
|
@ -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 <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/drivers/pinctrl.h>
|
||||
|
||||
#include <xmc_i2c.h>
|
||||
#include <xmc_usic.h>
|
||||
|
||||
#define USIC_IRQ_MIN 84
|
||||
#define IRQS_PER_USIC 6
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
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)
|
|
@ -593,4 +593,125 @@
|
|||
pinmux = <XMC4XXX_PINMUX_SET(6, 6, 0)>;
|
||||
hwctrl = "periph2";
|
||||
};
|
||||
|
||||
/omit-if-no-ref/ i2c_controller_scl_p0_8_u0c0: i2c_controller_scl_p0_8_u0c0 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 8, 0x1A)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_controller_scl_p1_1_u0c0: i2c_controller_scl_p1_1_u0c0 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 1, 0x1A)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_controller_scl_p2_4_u0c1: i2c_controller_scl_p2_4_u0c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 4, 0x1A)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_controller_scl_p3_0_u0c1: i2c_controller_scl_p3_0_u0c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(3, 0, 0x1A)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_controller_scl_p6_2_u0c1: i2c_controller_scl_p6_2_u0c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(6, 2, 0x1A)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_controller_scl_p0_11_u1c0: i2c_controller_scl_p0_11_u1c0 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 11, 0x1A)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_controller_scl_p5_8_u1c0: i2c_controller_scl_p5_8_u1c0 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 8, 0x1A)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_controller_scl_p0_10_u1c1: i2c_controller_scl_p0_10_u1c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 10, 0x1A)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_controller_scl_p0_13_u1c1: i2c_controller_scl_p0_13_u1c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 13, 0x1A)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_controller_scl_p5_2_u2c0: i2c_controller_scl_p5_2_u2c0 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 2, 0x1A)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_controller_scl_p3_6_u2c1: i2c_controller_scl_p3_6_u2c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(3, 6, 0x1A)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_controller_sda_p1_5_u0c0: i2c_controller_sda_p1_5_u0c0 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 5, 0x1A)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_controller_sda_p2_5_u0c1: i2c_controller_sda_p2_5_u0c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 5, 0x1A)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_controller_sda_p3_13_u0c1: i2c_controller_sda_p3_13_u0c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(3, 13, 0x1A)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_controller_sda_p0_5_u1c0: i2c_controller_sda_p0_5_u1c0 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 5, 0x1A)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_controller_sda_p2_14_u1c0: i2c_controller_sda_p2_14_u1c0 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 14, 0x1A)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_controller_sda_p3_15_u1c1: i2c_controller_sda_p3_15_u1c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(3, 15, 0x1A)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_controller_sda_p4_2_u1c1: i2c_controller_sda_p4_2_u1c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(4, 2, 0x1A)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_controller_sda_p5_0_u2c0: i2c_controller_sda_p5_0_u2c0 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 0, 0x1A)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_controller_sda_p3_5_u2c1: i2c_controller_sda_p3_5_u2c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(3, 5, 0x1A)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_target_scl_p0_8_u0c0: i2c_target_scl_p0_8_u0c0 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 8, 0x19)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_target_scl_p1_1_u0c0: i2c_target_scl_p1_1_u0c0 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 1, 0x19)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_target_scl_p2_4_u0c1: i2c_target_scl_p2_4_u0c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 4, 0x19)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_target_scl_p3_0_u0c1: i2c_target_scl_p3_0_u0c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(3, 0, 0x19)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_target_scl_p6_2_u0c1: i2c_target_scl_p6_2_u0c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(6, 2, 0x19)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_target_scl_p0_11_u1c0: i2c_target_scl_p0_11_u1c0 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 11, 0x19)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_target_scl_p5_8_u1c0: i2c_target_scl_p5_8_u1c0 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 8, 0x19)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_target_scl_p0_10_u1c1: i2c_target_scl_p0_10_u1c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 10, 0x19)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_target_scl_p0_13_u1c1: i2c_target_scl_p0_13_u1c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 13, 0x19)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_target_scl_p5_2_u2c0: i2c_target_scl_p5_2_u2c0 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 2, 0x19)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_target_scl_p3_6_u2c1: i2c_target_scl_p3_6_u2c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(3, 6, 0x19)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_target_sda_p1_5_u0c0: i2c_target_sda_p1_5_u0c0 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(1, 5, 0x19)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_target_sda_p2_5_u0c1: i2c_target_sda_p2_5_u0c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 5, 0x19)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_target_sda_p3_13_u0c1: i2c_target_sda_p3_13_u0c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(3, 13, 0x19)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_target_sda_p0_5_u1c0: i2c_target_sda_p0_5_u1c0 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(0, 5, 0x19)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_target_sda_p2_14_u1c0: i2c_target_sda_p2_14_u1c0 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(2, 14, 0x19)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_target_sda_p3_15_u1c1: i2c_target_sda_p3_15_u1c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(3, 15, 0x19)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_target_sda_p4_2_u1c1: i2c_target_sda_p4_2_u1c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(4, 2, 0x19)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_target_sda_p5_0_u2c0: i2c_target_sda_p5_0_u2c0 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(5, 0, 0x19)>;
|
||||
};
|
||||
/omit-if-no-ref/ i2c_target_sda_p3_5_u2c1: i2c_target_sda_p3_5_u2c1 {
|
||||
pinmux = <XMC4XXX_PINMUX_SET(3, 5, 0x19)>;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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<port>_<pin><peripheral inst>_<signal>.
|
||||
format: p<port>_<pin>_<peripheral inst>_<signal>.
|
||||
|
||||
Examples:
|
||||
pinctrl-0 = <&p6_0_scb3_i2c_scl &p6_1_scb3_i2c_sda>;
|
||||
|
|
77
dts/bindings/i2c/infineon,xmc4-i2c.yaml
Normal file
77
dts/bindings/i2c/infineon,xmc4-i2c.yaml
Normal file
|
@ -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: <signal>_p<port>_<pin>_<peripheral inst>
|
||||
|
||||
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
|
|
@ -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 */
|
||||
|
|
|
@ -40,4 +40,9 @@ config HAS_XMCLIB_SPI
|
|||
help
|
||||
Enable XMCLIB SPI
|
||||
|
||||
config HAS_XMCLIB_I2C
|
||||
bool
|
||||
help
|
||||
Enable XMCLIB I2C
|
||||
|
||||
endif # HAS_XMCLIB
|
||||
|
|
|
@ -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
|
||||
|
|
1
tests/drivers/i2c/i2c_api/boards/xmc47_relax_kit.conf
Normal file
1
tests/drivers/i2c/i2c_api/boards/xmc47_relax_kit.conf
Normal file
|
@ -0,0 +1 @@
|
|||
CONFIG_I2C_INFINEON_XMC4_TARGET_BUF=128
|
35
tests/drivers/i2c/i2c_api/boards/xmc47_relax_kit.overlay
Normal file
35
tests/drivers/i2c/i2c_api/boards/xmc47_relax_kit.overlay
Normal file
|
@ -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";
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue