drivers: i2c: Add Infineon CAT1 i2c driver
- Add initial version of Infineon CAT1 i2c driver. - Add initial version of binding file for Infineon CAT1 I2C driver Signed-off-by: Sreeram Tatapudi <sreeram.praveen@infineon.com>
This commit is contained in:
parent
1b2942ffee
commit
185aa1c2c5
|
@ -15,6 +15,7 @@
|
|||
|
||||
aliases {
|
||||
uart-5 = &uart5;
|
||||
i2c-0 = &i2c3;
|
||||
};
|
||||
|
||||
chosen {
|
||||
|
@ -91,3 +92,9 @@
|
|||
&clk_peri {
|
||||
clock-div = <1>;
|
||||
};
|
||||
|
||||
&i2c3 {
|
||||
/* I2C pins */
|
||||
pinctrl-0 = <&p6_0_scb3_i2c_scl &p6_1_scb3_i2c_sda>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
|
|
@ -15,3 +15,4 @@ toolchain:
|
|||
supported:
|
||||
- gpio
|
||||
- uart
|
||||
- i2c
|
||||
|
|
|
@ -38,6 +38,7 @@ zephyr_library_sources_ifdef(CONFIG_I2C_RCAR i2c_rcar.c)
|
|||
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_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)
|
||||
|
|
|
@ -63,6 +63,7 @@ source "drivers/i2c/Kconfig.test"
|
|||
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.andes_atciic100"
|
||||
source "drivers/i2c/Kconfig.sc18im704"
|
||||
source "drivers/i2c/Kconfig.smartbond"
|
||||
|
|
29
drivers/i2c/Kconfig.ifx_cat1
Normal file
29
drivers/i2c/Kconfig.ifx_cat1
Normal file
|
@ -0,0 +1,29 @@
|
|||
# Infineon CAT1 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
|
||||
|
||||
config I2C_INFINEON_CAT1
|
||||
bool "Infineon CAT1 I2C driver"
|
||||
default y
|
||||
depends on DT_HAS_INFINEON_CAT1_I2C_ENABLED
|
||||
select USE_INFINEON_I2C
|
||||
help
|
||||
This option enables the I2C driver for Infineon CAT1 family.
|
||||
|
||||
config I2C_INFINEON_CAT1_TARGET_BUF
|
||||
int "I2C Target data buffer length"
|
||||
depends on I2C_INFINEON_CAT1
|
||||
range 1 1024
|
||||
default 64
|
||||
help
|
||||
Buffer to receive data as an I2C Target.
|
||||
|
||||
config I2C_INFINEON_CAT1_ASYNC
|
||||
bool "Support Asynchronous I2C driver"
|
||||
default y
|
||||
depends on I2C_INFINEON_CAT1
|
||||
help
|
||||
Configure the I2C driver to be non-blocking/Asynchronous mode.
|
519
drivers/i2c/i2c_ifx_cat1.c
Normal file
519
drivers/i2c/i2c_ifx_cat1.c
Normal file
|
@ -0,0 +1,519 @@
|
|||
/*
|
||||
* 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 CAT1 MCU family.
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT infineon_cat1_i2c
|
||||
|
||||
#include <zephyr/drivers/i2c.h>
|
||||
#include <zephyr/drivers/pinctrl.h>
|
||||
#include <cyhal_i2c.h>
|
||||
#include <cyhal_utils_psoc.h>
|
||||
#include <cyhal_utils_psoc.h>
|
||||
#include <cyhal_scb_common.h>
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(i2c_infineon_cat1, CONFIG_I2C_LOG_LEVEL);
|
||||
|
||||
#define I2C_CAT1_EVENTS_MASK (CYHAL_I2C_MASTER_WR_CMPLT_EVENT | CYHAL_I2C_MASTER_RD_CMPLT_EVENT | \
|
||||
CYHAL_I2C_MASTER_ERR_EVENT)
|
||||
|
||||
#define I2C_CAT1_SLAVE_EVENTS_MASK \
|
||||
(CYHAL_I2C_SLAVE_READ_EVENT | CYHAL_I2C_SLAVE_WRITE_EVENT | \
|
||||
CYHAL_I2C_SLAVE_RD_BUF_EMPTY_EVENT | CYHAL_I2C_SLAVE_RD_CMPLT_EVENT | \
|
||||
CYHAL_I2C_SLAVE_WR_CMPLT_EVENT | CYHAL_I2C_SLAVE_RD_BUF_EMPTY_EVENT | \
|
||||
CYHAL_I2C_SLAVE_ERR_EVENT)
|
||||
|
||||
/* States for ASYNC operations */
|
||||
#define CAT1_I2C_PENDING_NONE (0U)
|
||||
#define CAT1_I2C_PENDING_RX (1U)
|
||||
#define CAT1_I2C_PENDING_TX (2U)
|
||||
#define CAT1_I2C_PENDING_TX_RX (3U)
|
||||
|
||||
/* I2C speed */
|
||||
#define CAT1_I2C_SPEED_STANDARD_HZ (100000UL)
|
||||
#define CAT1_I2C_SPEED_FAST_HZ (400000UL)
|
||||
#define CAT1_I2C_SPEED_FAST_PLUS_HZ (1000000UL)
|
||||
|
||||
/* Data structure */
|
||||
struct ifx_cat1_i2c_data {
|
||||
cyhal_i2c_t obj;
|
||||
cyhal_i2c_cfg_t cfg;
|
||||
struct k_sem operation_sem;
|
||||
struct k_sem transfer_sem;
|
||||
uint32_t error_status;
|
||||
uint32_t async_pending;
|
||||
cyhal_resource_inst_t hw_resource;
|
||||
cyhal_clock_t clock;
|
||||
struct i2c_target_config *p_target_config;
|
||||
uint8_t i2c_target_wr_byte;
|
||||
uint8_t target_wr_buffer[CONFIG_I2C_INFINEON_CAT1_TARGET_BUF];
|
||||
};
|
||||
|
||||
/* Device config structure */
|
||||
struct ifx_cat1_i2c_config {
|
||||
uint32_t master_frequency;
|
||||
CySCB_Type *reg_addr;
|
||||
const struct pinctrl_dev_config *pcfg;
|
||||
uint8_t irq_priority;
|
||||
};
|
||||
|
||||
/* Default SCB/I2C configuration structure */
|
||||
static const cy_stc_scb_i2c_config_t _cyhal_i2c_default_config = {
|
||||
.i2cMode = CY_SCB_I2C_MASTER,
|
||||
.useRxFifo = false,
|
||||
.useTxFifo = true,
|
||||
.slaveAddress = 0U,
|
||||
.slaveAddressMask = 0U,
|
||||
.acceptAddrInFifo = false,
|
||||
.ackGeneralAddr = false,
|
||||
.enableWakeFromSleep = false,
|
||||
.enableDigitalFilter = false,
|
||||
.lowPhaseDutyCycle = 8U,
|
||||
.highPhaseDutyCycle = 8U,
|
||||
};
|
||||
|
||||
static int32_t _get_hw_block_num(CySCB_Type *reg_addr)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0u; i < _SCB_ARRAY_SIZE; i++) {
|
||||
if (_CYHAL_SCB_BASE_ADDRESSES[i] == reg_addr) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_I2C_INFINEON_CAT1_ASYNC
|
||||
static void ifx_master_event_handler(void *callback_arg, cyhal_i2c_event_t event)
|
||||
{
|
||||
const struct device *dev = (const struct device *) callback_arg;
|
||||
struct ifx_cat1_i2c_data *data = dev->data;
|
||||
|
||||
if (((CYHAL_I2C_MASTER_ERR_EVENT | CYHAL_I2C_SLAVE_ERR_EVENT) & event) != 0U) {
|
||||
/* In case of error abort transfer */
|
||||
(void)cyhal_i2c_abort_async(&data->obj);
|
||||
data->error_status = 1;
|
||||
}
|
||||
|
||||
/* Release semaphore if operation complete
|
||||
* When we have pending TX, RX operations, the semaphore will be released
|
||||
* after TX, RX complete.
|
||||
*/
|
||||
if (((data->async_pending == CAT1_I2C_PENDING_TX_RX) &&
|
||||
((CYHAL_I2C_MASTER_RD_CMPLT_EVENT & event) != 0U)) ||
|
||||
(data->async_pending != CAT1_I2C_PENDING_TX_RX)) {
|
||||
|
||||
/* Release semaphore (After I2C async transfer is complete) */
|
||||
k_sem_give(&data->transfer_sem);
|
||||
}
|
||||
|
||||
if (0 != (CYHAL_I2C_SLAVE_READ_EVENT & event)) {
|
||||
if (data->p_target_config->callbacks->read_requested) {
|
||||
data->p_target_config->callbacks->read_requested(data->p_target_config,
|
||||
&data->i2c_target_wr_byte);
|
||||
data->obj.context.slaveTxBufferIdx = 0;
|
||||
data->obj.context.slaveTxBufferCnt = 0;
|
||||
data->obj.context.slaveTxBufferSize = 1;
|
||||
data->obj.context.slaveTxBuffer = &data->i2c_target_wr_byte;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != (CYHAL_I2C_SLAVE_RD_BUF_EMPTY_EVENT & event)) {
|
||||
if (data->p_target_config->callbacks->read_processed) {
|
||||
data->p_target_config->callbacks->read_processed(data->p_target_config,
|
||||
&data->i2c_target_wr_byte);
|
||||
data->obj.context.slaveTxBufferIdx = 0;
|
||||
data->obj.context.slaveTxBufferCnt = 0;
|
||||
data->obj.context.slaveTxBufferSize = 1;
|
||||
data->obj.context.slaveTxBuffer = &data->i2c_target_wr_byte;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != (CYHAL_I2C_SLAVE_WRITE_EVENT & event)) {
|
||||
cyhal_i2c_slave_config_write_buffer(&data->obj, data->target_wr_buffer,
|
||||
CONFIG_I2C_INFINEON_CAT1_TARGET_BUF);
|
||||
if (data->p_target_config->callbacks->write_requested) {
|
||||
data->p_target_config->callbacks->write_requested(data->p_target_config);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != (CYHAL_I2C_SLAVE_WR_CMPLT_EVENT & event)) {
|
||||
if (data->p_target_config->callbacks->write_received) {
|
||||
for (int i = 0; i < data->obj.context.slaveRxBufferIdx; i++) {
|
||||
data->p_target_config->callbacks->write_received(
|
||||
data->p_target_config, data->target_wr_buffer[i]);
|
||||
}
|
||||
}
|
||||
if (data->p_target_config->callbacks->stop) {
|
||||
data->p_target_config->callbacks->stop(data->p_target_config);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != (CYHAL_I2C_SLAVE_RD_CMPLT_EVENT & event)) {
|
||||
if (data->p_target_config->callbacks->stop) {
|
||||
data->p_target_config->callbacks->stop(data->p_target_config);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ifx_cat1_i2c_configure(const struct device *dev, uint32_t dev_config)
|
||||
{
|
||||
struct ifx_cat1_i2c_data *data = dev->data;
|
||||
cy_rslt_t rslt;
|
||||
int ret;
|
||||
|
||||
if (dev_config != 0) {
|
||||
switch (I2C_SPEED_GET(dev_config)) {
|
||||
case I2C_SPEED_STANDARD:
|
||||
data->cfg.frequencyhal_hz = CAT1_I2C_SPEED_STANDARD_HZ;
|
||||
break;
|
||||
case I2C_SPEED_FAST:
|
||||
data->cfg.frequencyhal_hz = CAT1_I2C_SPEED_FAST_HZ;
|
||||
break;
|
||||
case I2C_SPEED_FAST_PLUS:
|
||||
data->cfg.frequencyhal_hz = CAT1_I2C_SPEED_FAST_PLUS_HZ;
|
||||
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("10-bit addressing mode is not supported");
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
/* Acquire semaphore (block I2C operation for another thread) */
|
||||
ret = k_sem_take(&data->operation_sem, K_FOREVER);
|
||||
if (ret) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Configure the I2C resource to be master */
|
||||
rslt = cyhal_i2c_configure(&data->obj, &data->cfg);
|
||||
if (rslt != CY_RSLT_SUCCESS) {
|
||||
LOG_ERR("cyhal_i2c_configure failed with err 0x%x", rslt);
|
||||
k_sem_give(&data->operation_sem);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_I2C_INFINEON_CAT1_ASYNC
|
||||
/* Register an I2C event callback handler */
|
||||
cyhal_i2c_register_callback(&data->obj, ifx_master_event_handler, (void *)dev);
|
||||
#endif
|
||||
/* Release semaphore */
|
||||
k_sem_give(&data->operation_sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ifx_cat1_i2c_get_config(const struct device *dev, uint32_t *dev_config)
|
||||
{
|
||||
struct ifx_cat1_i2c_data *data = dev->data;
|
||||
uint32_t config;
|
||||
|
||||
switch (data->cfg.frequencyhal_hz) {
|
||||
case CAT1_I2C_SPEED_STANDARD_HZ:
|
||||
config = I2C_SPEED_SET(I2C_SPEED_STANDARD);
|
||||
break;
|
||||
case CAT1_I2C_SPEED_FAST_HZ:
|
||||
config = I2C_SPEED_SET(I2C_SPEED_FAST);
|
||||
break;
|
||||
case CAT1_I2C_SPEED_FAST_PLUS_HZ:
|
||||
config = I2C_SPEED_SET(I2C_SPEED_FAST_PLUS);
|
||||
break;
|
||||
default:
|
||||
LOG_ERR("Unsupported speed");
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/* Return current configuration */
|
||||
*dev_config = config | I2C_MODE_CONTROLLER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ifx_cat1_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_cat1_i2c_transfer(const struct device *dev, struct i2c_msg *msg, uint8_t num_msgs,
|
||||
uint16_t addr)
|
||||
{
|
||||
struct ifx_cat1_i2c_data *data = dev->data;
|
||||
cy_rslt_t rslt = CY_RSLT_SUCCESS;
|
||||
int ret;
|
||||
|
||||
if (!num_msgs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Acquire semaphore (block I2C transfer for another thread) */
|
||||
ret = k_sem_take(&data->operation_sem, K_FOREVER);
|
||||
if (ret) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* This function checks if msg.buf is not NULL and if
|
||||
* target address is not 10 bit.
|
||||
*/
|
||||
if (ifx_cat1_i2c_msg_validate(msg, num_msgs) != 0) {
|
||||
k_sem_give(&data->operation_sem);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_I2C_INFINEON_CAT1_ASYNC
|
||||
const struct ifx_cat1_i2c_config *const config = dev->config;
|
||||
|
||||
struct i2c_msg *tx_msg;
|
||||
struct i2c_msg *rx_msg;
|
||||
|
||||
data->error_status = 0;
|
||||
data->async_pending = CAT1_I2C_PENDING_NONE;
|
||||
|
||||
/* Enable I2C Interrupt */
|
||||
cyhal_i2c_enable_event(&data->obj, (cyhal_i2c_event_t)I2C_CAT1_EVENTS_MASK,
|
||||
config->irq_priority, true);
|
||||
|
||||
for (uint32_t i = 0u; i < num_msgs; i++) {
|
||||
tx_msg = NULL;
|
||||
rx_msg = NULL;
|
||||
|
||||
if ((msg[i].flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
|
||||
tx_msg = &msg[i];
|
||||
data->async_pending = CAT1_I2C_PENDING_TX;
|
||||
}
|
||||
|
||||
if ((msg[i].flags & I2C_MSG_RW_MASK) == I2C_MSG_READ) {
|
||||
rx_msg = &msg[i];
|
||||
data->async_pending = CAT1_I2C_PENDING_TX;
|
||||
}
|
||||
|
||||
if ((tx_msg != NULL) && ((i + 1U) < num_msgs) &&
|
||||
((msg[i + 1U].flags & I2C_MSG_RW_MASK) == I2C_MSG_READ)) {
|
||||
rx_msg = &msg[i + 1U];
|
||||
i++;
|
||||
data->async_pending = CAT1_I2C_PENDING_TX_RX;
|
||||
}
|
||||
|
||||
/* Initiate master write and read transfer
|
||||
* using tx_buff and rx_buff respectively
|
||||
*/
|
||||
rslt = cyhal_i2c_master_transfer_async(&data->obj, addr,
|
||||
(tx_msg == NULL) ? NULL : tx_msg->buf,
|
||||
(tx_msg == NULL) ? 0u : tx_msg->len,
|
||||
(rx_msg == NULL) ? NULL : rx_msg->buf,
|
||||
(rx_msg == NULL) ? 0u : rx_msg->len);
|
||||
|
||||
if (rslt != CY_RSLT_SUCCESS) {
|
||||
k_sem_give(&data->operation_sem);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Acquire semaphore (block I2C async transfer for another thread) */
|
||||
ret = k_sem_take(&data->transfer_sem, K_FOREVER);
|
||||
if (ret) {
|
||||
k_sem_give(&data->operation_sem);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* If error_status != 1 we have error during transfer async.
|
||||
* error_status is handling in master_event_handler function.
|
||||
*/
|
||||
if (data->error_status != 0) {
|
||||
/* Release semaphore */
|
||||
k_sem_give(&data->operation_sem);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable I2C Interrupt */
|
||||
cyhal_i2c_enable_event(&data->obj, (cyhal_i2c_event_t)
|
||||
I2C_CAT1_EVENTS_MASK, config->irq_priority, false);
|
||||
#else
|
||||
for (uint32_t i = 0u; i < num_msgs; i++) {
|
||||
bool stop_flag = ((msg[i].flags & I2C_MSG_STOP) != 0u) ? true : false;
|
||||
|
||||
if ((msg[i].flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
|
||||
rslt = cyhal_i2c_master_write(&data->obj,
|
||||
addr, msg[i].buf, msg[i].len, 0, stop_flag);
|
||||
}
|
||||
if ((msg[i].flags & I2C_MSG_RW_MASK) == I2C_MSG_READ) {
|
||||
rslt = cyhal_i2c_master_read(&data->obj,
|
||||
addr, msg[i].buf, msg[i].len, 0, stop_flag);
|
||||
}
|
||||
|
||||
if (rslt != CY_RSLT_SUCCESS) {
|
||||
/* Release semaphore */
|
||||
k_sem_give(&data->operation_sem);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Release semaphore (After I2C transfer is complete) */
|
||||
k_sem_give(&data->operation_sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ifx_cat1_i2c_init(const struct device *dev)
|
||||
{
|
||||
struct ifx_cat1_i2c_data *data = dev->data;
|
||||
const struct ifx_cat1_i2c_config *config = dev->config;
|
||||
cy_rslt_t result;
|
||||
int ret;
|
||||
|
||||
/* Configuration structure to initialisation I2C */
|
||||
cyhal_i2c_configurator_t i2c_init_cfg = {
|
||||
.resource = &data->hw_resource,
|
||||
.config = &_cyhal_i2c_default_config,
|
||||
.clock = &data->clock,
|
||||
};
|
||||
|
||||
/* Dedicate SCB HW resource */
|
||||
data->hw_resource.type = CYHAL_RSC_SCB;
|
||||
data->hw_resource.block_num = _get_hw_block_num(config->reg_addr);
|
||||
|
||||
|
||||
/* Configure semaphores */
|
||||
ret = k_sem_init(&data->transfer_sem, 0, 1);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = k_sem_init(&data->operation_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;
|
||||
}
|
||||
|
||||
/* Allocating clock for I2C driver */
|
||||
result = _cyhal_utils_allocate_clock(&data->clock, &data->hw_resource,
|
||||
CYHAL_CLOCK_BLOCK_PERIPHERAL_16BIT, true);
|
||||
if (result != CY_RSLT_SUCCESS) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* Assigns a programmable divider to a selected IP block */
|
||||
en_clk_dst_t clk_idx = _cyhal_scb_get_clock_index(i2c_init_cfg.resource->block_num);
|
||||
|
||||
result = _cyhal_utils_peri_pclk_assign_divider(clk_idx, i2c_init_cfg.clock);
|
||||
if (result != CY_RSLT_SUCCESS) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* Initialize the I2C peripheral */
|
||||
result = cyhal_i2c_init_cfg(&data->obj, &i2c_init_cfg);
|
||||
if (result != CY_RSLT_SUCCESS) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
data->obj.is_clock_owned = true;
|
||||
|
||||
/* Store Master initial configuration */
|
||||
data->cfg.is_slave = false;
|
||||
data->cfg.address = 0;
|
||||
data->cfg.frequencyhal_hz = config->master_frequency;
|
||||
|
||||
if (ifx_cat1_i2c_configure(dev, 0) != 0) {
|
||||
/* Free I2C resource */
|
||||
cyhal_i2c_free(&data->obj);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ifx_cat1_i2c_target_register(const struct device *dev, struct i2c_target_config *cfg)
|
||||
{
|
||||
struct ifx_cat1_i2c_data *data = (struct ifx_cat1_i2c_data *)dev->data;
|
||||
const struct ifx_cat1_i2c_config *config = dev->config;
|
||||
|
||||
if (!cfg) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cfg->flags & I2C_TARGET_FLAGS_ADDR_10_BITS) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
data->p_target_config = cfg;
|
||||
data->cfg.is_slave = true;
|
||||
data->cfg.address = data->p_target_config->address;
|
||||
data->cfg.frequencyhal_hz = 100000;
|
||||
|
||||
if (ifx_cat1_i2c_configure(dev, I2C_SPEED_SET(I2C_SPEED_FAST)) != 0) {
|
||||
/* Free I2C resource */
|
||||
cyhal_i2c_free(&data->obj);
|
||||
/* Release semaphore */
|
||||
k_sem_give(&data->operation_sem);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
cyhal_i2c_enable_event(&data->obj, (cyhal_i2c_event_t)I2C_CAT1_SLAVE_EVENTS_MASK,
|
||||
config->irq_priority, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ifx_cat1_i2c_target_unregister(const struct device *dev, struct i2c_target_config *cfg)
|
||||
{
|
||||
struct ifx_cat1_i2c_data *data = (struct ifx_cat1_i2c_data *)dev->data;
|
||||
const struct ifx_cat1_i2c_config *config = dev->config;
|
||||
|
||||
/* Acquire semaphore (block I2C operation for another thread) */
|
||||
k_sem_take(&data->operation_sem, K_FOREVER);
|
||||
|
||||
cyhal_i2c_free(&data->obj);
|
||||
data->p_target_config = NULL;
|
||||
cyhal_i2c_enable_event(&data->obj, (cyhal_i2c_event_t)I2C_CAT1_SLAVE_EVENTS_MASK,
|
||||
config->irq_priority, false);
|
||||
|
||||
/* Release semaphore */
|
||||
k_sem_give(&data->operation_sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* I2C API structure */
|
||||
static const struct i2c_driver_api i2c_cat1_driver_api = {
|
||||
.configure = ifx_cat1_i2c_configure,
|
||||
.transfer = ifx_cat1_i2c_transfer,
|
||||
.get_config = ifx_cat1_i2c_get_config,
|
||||
.target_register = ifx_cat1_i2c_target_register,
|
||||
.target_unregister = ifx_cat1_i2c_target_unregister};
|
||||
|
||||
/* Macros for I2C instance declaration */
|
||||
#define INFINEON_CAT1_I2C_INIT(n) \
|
||||
PINCTRL_DT_INST_DEFINE(n); \
|
||||
\
|
||||
static struct ifx_cat1_i2c_data ifx_cat1_i2c_data##n; \
|
||||
\
|
||||
static const struct ifx_cat1_i2c_config i2c_cat1_cfg_##n = { \
|
||||
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
|
||||
.master_frequency = DT_INST_PROP_OR(n, clock_frequency, 100000), \
|
||||
.reg_addr = (CySCB_Type *)DT_INST_REG_ADDR(n), \
|
||||
.irq_priority = DT_INST_IRQ(n, priority), \
|
||||
}; \
|
||||
\
|
||||
I2C_DEVICE_DT_INST_DEFINE(n, ifx_cat1_i2c_init, NULL, &ifx_cat1_i2c_data##n, \
|
||||
&i2c_cat1_cfg_##n, POST_KERNEL, \
|
||||
CONFIG_I2C_INIT_PRIORITY, &i2c_cat1_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(INFINEON_CAT1_I2C_INIT)
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon company) or
|
||||
* Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or
|
||||
* an affiliate of Cypress Semiconductor Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
|
@ -9,6 +9,110 @@
|
|||
|
||||
/ {
|
||||
soc {
|
||||
i2c0: i2c@40600000 {
|
||||
compatible = "infineon,cat1-i2c";
|
||||
reg = <0x40600000 0x10000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <39 6>;
|
||||
status = "disabled";
|
||||
};
|
||||
i2c1: i2c@40610000 {
|
||||
compatible = "infineon,cat1-i2c";
|
||||
reg = <0x40610000 0x10000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <40 6>;
|
||||
status = "disabled";
|
||||
};
|
||||
i2c2: i2c@40620000 {
|
||||
compatible = "infineon,cat1-i2c";
|
||||
reg = <0x40620000 0x10000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <41 6>;
|
||||
status = "disabled";
|
||||
};
|
||||
i2c3: i2c@40630000 {
|
||||
compatible = "infineon,cat1-i2c";
|
||||
reg = <0x40630000 0x10000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <42 6>;
|
||||
status = "disabled";
|
||||
};
|
||||
i2c4: i2c@40640000 {
|
||||
compatible = "infineon,cat1-i2c";
|
||||
reg = <0x40640000 0x10000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <43 6>;
|
||||
status = "disabled";
|
||||
};
|
||||
i2c5: i2c@40650000 {
|
||||
compatible = "infineon,cat1-i2c";
|
||||
reg = <0x40650000 0x10000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <44 6>;
|
||||
status = "disabled";
|
||||
};
|
||||
i2c6: i2c@40660000 {
|
||||
compatible = "infineon,cat1-i2c";
|
||||
reg = <0x40660000 0x10000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <45 6>;
|
||||
status = "disabled";
|
||||
};
|
||||
i2c7: i2c@40670000 {
|
||||
compatible = "infineon,cat1-i2c";
|
||||
reg = <0x40670000 0x10000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <46 6>;
|
||||
status = "disabled";
|
||||
};
|
||||
i2c8: i2c@40680000 {
|
||||
compatible = "infineon,cat1-i2c";
|
||||
reg = <0x40680000 0x10000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <18 6>;
|
||||
status = "disabled";
|
||||
};
|
||||
i2c9: i2c@40690000 {
|
||||
compatible = "infineon,cat1-i2c";
|
||||
reg = <0x40690000 0x10000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <47 6>;
|
||||
status = "disabled";
|
||||
};
|
||||
i2c10: i2c@406a0000 {
|
||||
compatible = "infineon,cat1-i2c";
|
||||
reg = <0x406a0000 0x10000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <48 6>;
|
||||
status = "disabled";
|
||||
};
|
||||
i2c11: i2c@406b0000 {
|
||||
compatible = "infineon,cat1-i2c";
|
||||
reg = <0x406b0000 0x10000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <49 6>;
|
||||
status = "disabled";
|
||||
};
|
||||
i2c12: i2c@406c0000 {
|
||||
compatible = "infineon,cat1-i2c";
|
||||
reg = <0x406c0000 0x10000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <50 6>;
|
||||
status = "disabled";
|
||||
};
|
||||
uart0: uart@40600000 {
|
||||
compatible = "infineon,cat1-uart";
|
||||
reg = <0x40600000 0x10000>;
|
||||
|
|
39
dts/bindings/i2c/infineon,cat1-i2c.yaml
Normal file
39
dts/bindings/i2c/infineon,cat1-i2c.yaml
Normal file
|
@ -0,0 +1,39 @@
|
|||
# Copyright (c) 2023 Cypress Semiconductor Corporation (an Infineon company) or
|
||||
# an affiliate of Cypress Semiconductor Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: Infineon CAT1 I2C
|
||||
|
||||
compatible: "infineon,cat1-i2c"
|
||||
|
||||
include: [i2c-controller.yaml, pinctrl-device.yaml]
|
||||
|
||||
properties:
|
||||
reg:
|
||||
type: array
|
||||
required: true
|
||||
|
||||
interrupts:
|
||||
type: array
|
||||
required: true
|
||||
|
||||
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<port>_<pin><peripheral inst>_<signal>.
|
||||
|
||||
Examples:
|
||||
pinctrl-0 = <&p6_0_scb3_i2c_scl &p6_1_scb3_i2c_sda>;
|
||||
required: true
|
||||
|
||||
pinctrl-names:
|
||||
required: true
|
||||
|
||||
clock-frequency:
|
||||
type: int
|
||||
description: |
|
||||
Frequency that the I2C bus runs
|
14
tests/drivers/i2c/i2c_api/boards/cy8cproto_062_4343w.overlay
Normal file
14
tests/drivers/i2c/i2c_api/boards/cy8cproto_062_4343w.overlay
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Cypress Semiconductor Corporation.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/ {
|
||||
aliases {
|
||||
gy271 = &i2c3;
|
||||
};
|
||||
};
|
||||
|
||||
&i2c3 {
|
||||
status = "okay";
|
||||
};
|
Loading…
Reference in a new issue