Commit ebf3aa05 authored by Phuc Pham's avatar Phuc Pham Committed by Benjamin Cabé
Browse files

drivers: i2c: Add I2C support for Renesas RZ/A3UL, T2M, N2L, V2L



Add I2C driver support for Renesas RZ/A3UL, T2M, N2L, V2L

Signed-off-by: default avatarPhuc Pham <phuc.pham.xr@bp.renesas.com>
Signed-off-by: default avatarNhut Nguyen <nhut.nguyen.kc@renesas.com>
parent b1353daf
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ zephyr_library_sources_ifdef(CONFIG_I2C_RCAR i2c_rcar.c)
zephyr_library_sources_ifdef(CONFIG_I2C_RENESAS_RA_IIC	i2c_renesas_ra_iic.c)
zephyr_library_sources_ifdef(CONFIG_I2C_RENESAS_RA_SCI_B	i2c_renesas_ra_sci_b.c)
zephyr_library_sources_ifdef(CONFIG_I2C_RENESAS_RX_RIIC i2c_renesas_rx_riic.c)
zephyr_library_sources_ifdef(CONFIG_I2C_RENESAS_RZ_IIC i2c_renesas_rz_riic.c)
zephyr_library_sources_ifdef(CONFIG_I2C_RENESAS_RZ_RIIC i2c_renesas_rz_riic.c)
zephyr_library_sources_ifdef(CONFIG_I2C_RTS5912		i2c_realtek_rts5912.c)
zephyr_library_sources_ifdef(CONFIG_I2C_RV32M1_LPI2C	i2c_rv32m1_lpi2c.c)
+11 −1
Original line number Diff line number Diff line
# Copyright (c) 2024 Renesas Electronics Corporation
# Copyright (c) 2024-2025 Renesas Electronics Corporation
# SPDX-License-Identifier: Apache-2.0

config I2C_RENESAS_RZ_RIIC
@@ -6,5 +6,15 @@ config I2C_RENESAS_RZ_RIIC
	default y
	depends on DT_HAS_RENESAS_RZ_RIIC_ENABLED
	select USE_RZ_FSP_RIIC_MASTER
	select PINCTRL
	help
	  Enable Renesas RZ I2C RIIC Driver.

config I2C_RENESAS_RZ_IIC
	bool "Renesas RZ I2C IIC Master"
	default y
	depends on DT_HAS_RENESAS_RZ_IIC_ENABLED
	select USE_RZ_FSP_IIC_MASTER
	select PINCTRL
	help
	  Enable Renesas RZ I2C IIC Driver.
+170 −56
Original line number Diff line number Diff line
/*
 * Copyright (c) 2024 Renesas Electronics Corporation
 * Copyright (c) 2024-2025 Renesas Electronics Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */
@@ -9,25 +9,33 @@
#include <math.h>
#include <zephyr/drivers/i2c.h>
#include <zephyr/drivers/pinctrl.h>
#include <instances/rzg/r_riic_master.h>

#if defined(CONFIG_I2C_RENESAS_RZ_RIIC)
#include "r_riic_master.h"
#else /* CONFIG_I2C_RENESAS_RZ_IIC */
#include "r_iic_master.h"
typedef iic_master_extended_cfg_t riic_master_extended_cfg_t;
#define FSP_PRIV_CLOCK_P0CLK FSP_PRIV_CLOCK_PCLKL
#endif

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(renesas_rz_riic);

typedef void (*init_func_t)(const struct device *dev);
#define RZ_RIIC_MASTER_DIV_TIME_NS (1000000000.0)

struct i2c_rz_riic_config {
	const struct pinctrl_dev_config *pin_config;
	i2c_master_cfg_t *fsp_cfg;
	riic_master_extended_cfg_t *riic_master_ext_cfg;
	const i2c_master_api_t *fsp_api;
	double rise_time_s;
	double fall_time_s;
	double duty_cycle_percent;
	uint32_t noise_filter_stage;
};

struct i2c_rz_riic_data {
	i2c_master_ctrl_t *fsp_ctrl;
	i2c_master_cfg_t *fsp_cfg;
	riic_master_extended_cfg_t *riic_master_ext_cfg;
	struct k_mutex bus_mutex;
	struct k_sem complete_sem;
	i2c_master_event_t event;
@@ -38,15 +46,79 @@ struct i2c_rz_riic_data {
static void calc_riic_master_clock_setting(const struct device *dev, const uint32_t fsp_i2c_rate,
					   iic_master_clock_settings_t *clk_cfg);

#if defined(CONFIG_I2C_RENESAS_RZ_RIIC)
/* FSP interruption handlers. */
void riic_master_rxi_isr(void);
void riic_master_txi_isr(void);
void riic_master_tei_isr(void);
void riic_master_naki_isr(void);
void riic_master_sti_isr(void);
void riic_master_spi_isr(void);
void riic_master_ali_isr(void);
void riic_master_tmoi_isr(void);
void riic_master_rxi_isr(void *irq);
void riic_master_txi_isr(void *irq);
void riic_master_tei_isr(void *irq);
void riic_master_naki_isr(void *irq);
void riic_master_sti_isr(void *irq);
void riic_master_spi_isr(void *irq);
void riic_master_ali_isr(void *irq);
void riic_master_tmoi_isr(void *irq);

static void i2c_rz_riic_master_rxi_isr(const struct device *dev)
{
	struct i2c_rz_riic_data *data = dev->data;

	riic_master_rxi_isr((void *)data->fsp_cfg->rxi_irq);
}

static void i2c_rz_riic_master_txi_isr(const struct device *dev)
{
	struct i2c_rz_riic_data *data = dev->data;

	riic_master_txi_isr((void *)data->fsp_cfg->txi_irq);
}

static void i2c_rz_riic_master_tei_isr(const struct device *dev)
{
	struct i2c_rz_riic_data *data = dev->data;

	riic_master_tei_isr((void *)data->fsp_cfg->tei_irq);
}

static void i2c_rz_riic_master_naki_isr(const struct device *dev)
{
	struct i2c_rz_riic_data *data = dev->data;

	riic_master_naki_isr((void *)data->riic_master_ext_cfg->naki_irq);
}

static void i2c_rz_riic_master_sti_isr(const struct device *dev)
{
	struct i2c_rz_riic_data *data = dev->data;

	riic_master_sti_isr((void *)data->riic_master_ext_cfg->sti_irq);
}

static void i2c_rz_riic_master_spi_isr(const struct device *dev)
{
	struct i2c_rz_riic_data *data = dev->data;

	riic_master_spi_isr((void *)data->riic_master_ext_cfg->spi_irq);
}

static void i2c_rz_riic_master_ali_isr(const struct device *dev)
{
	struct i2c_rz_riic_data *data = dev->data;

	riic_master_ali_isr((void *)data->riic_master_ext_cfg->ali_irq);
}

static void i2c_rz_riic_master_tmoi_isr(const struct device *dev)
{
	struct i2c_rz_riic_data *data = dev->data;

	riic_master_tmoi_isr((void *)data->riic_master_ext_cfg->tmoi_irq);
}

#elif defined(CONFIG_I2C_RENESAS_RZ_IIC)
void iic_master_rxi_isr(void);
void iic_master_txi_isr(void);
void iic_master_tei_isr(void);
void iic_master_eri_isr(void);
#endif

struct rz_riic_master_bitrate {
	uint32_t bitrate;
@@ -61,6 +133,7 @@ static int i2c_rz_riic_configure(const struct device *dev, uint32_t dev_config)
{
	const struct i2c_rz_riic_config *config = dev->config;
	struct i2c_rz_riic_data *data = dev->data;
	fsp_err_t err;

	if (!(dev_config & I2C_MODE_CONTROLLER)) {
		LOG_ERR("Only I2C Master mode supported.");
@@ -69,13 +142,13 @@ static int i2c_rz_riic_configure(const struct device *dev, uint32_t dev_config)

	switch (I2C_SPEED_GET(dev_config)) {
	case I2C_SPEED_STANDARD:
		config->fsp_cfg->rate = I2C_MASTER_RATE_STANDARD;
		data->fsp_cfg->rate = I2C_MASTER_RATE_STANDARD;
		break;
	case I2C_SPEED_FAST:
		config->fsp_cfg->rate = I2C_MASTER_RATE_FAST;
		data->fsp_cfg->rate = I2C_MASTER_RATE_FAST;
		break;
	case I2C_SPEED_FAST_PLUS:
		config->fsp_cfg->rate = I2C_MASTER_RATE_FASTPLUS;
		data->fsp_cfg->rate = I2C_MASTER_RATE_FASTPLUS;
		break;
	default:
		LOG_ERR("%s: Invalid I2C speed rate flag: %d", __func__, I2C_SPEED_GET(dev_config));
@@ -83,11 +156,20 @@ static int i2c_rz_riic_configure(const struct device *dev, uint32_t dev_config)
	}

	/* Recalc clock setting after updating config. */
	calc_riic_master_clock_setting(dev, config->fsp_cfg->rate,
				       &config->riic_master_ext_cfg->clock_settings);
	calc_riic_master_clock_setting(dev, data->fsp_cfg->rate,
				       &data->riic_master_ext_cfg->clock_settings);

	config->fsp_api->close(data->fsp_ctrl);
	config->fsp_api->open(data->fsp_ctrl, config->fsp_cfg);
	err = config->fsp_api->close(data->fsp_ctrl);
	if (err != FSP_SUCCESS) {
		LOG_ERR("Failed to configure I2C device");
		return -EIO;
	}

	err = config->fsp_api->open(data->fsp_ctrl, data->fsp_cfg);
	if (err != FSP_SUCCESS) {
		LOG_ERR("Failed to configure I2C device");
		return -EIO;
	}

	/* save current devconfig. */
	data->dev_config = dev_config;
@@ -111,7 +193,7 @@ static int i2c_rz_riic_transfer(const struct device *dev, struct i2c_msg *msgs,
	const struct i2c_rz_riic_config *config = dev->config;
	struct i2c_rz_riic_data *data = (struct i2c_rz_riic_data *const)dev->data;
	struct i2c_msg *current, *next;
	fsp_err_t err = FSP_SUCCESS;
	fsp_err_t err;
	int ret = 0;

	if (!num_msgs) {
@@ -178,7 +260,11 @@ static int i2c_rz_riic_transfer(const struct device *dev, struct i2c_msg *msgs,
		addr_mode = I2C_MASTER_ADDR_MODE_7BIT;
	}

	config->fsp_api->slaveAddressSet(data->fsp_ctrl, addr, addr_mode);
	err = config->fsp_api->slaveAddressSet(data->fsp_ctrl, addr, addr_mode);
	if (err != FSP_SUCCESS) {
		LOG_ERR("Failed to set slave address");
		return -EIO;
	}

	/* Process input `msgs`. */

@@ -259,7 +345,7 @@ static int i2c_rz_riic_init(const struct device *dev)
{
	const struct i2c_rz_riic_config *config = dev->config;
	struct i2c_rz_riic_data *data = dev->data;
	fsp_err_t err = FSP_SUCCESS;
	fsp_err_t err;
	int ret = 0;

	/* Configure dt provided device signals when available */
@@ -275,21 +361,21 @@ static int i2c_rz_riic_init(const struct device *dev)
	k_mutex_init(&data->bus_mutex);
	k_sem_init(&data->complete_sem, 0, 1);

	switch (config->fsp_cfg->rate) {
	switch (data->fsp_cfg->rate) {
	case I2C_MASTER_RATE_STANDARD:
	case I2C_MASTER_RATE_FAST:
	case I2C_MASTER_RATE_FASTPLUS:
		calc_riic_master_clock_setting(dev, config->fsp_cfg->rate,
					       &config->riic_master_ext_cfg->clock_settings);
		config->riic_master_ext_cfg->timeout_mode = IIC_MASTER_TIMEOUT_MODE_SHORT;
		config->riic_master_ext_cfg->timeout_scl_low = IIC_MASTER_TIMEOUT_SCL_LOW_ENABLED;
		calc_riic_master_clock_setting(dev, data->fsp_cfg->rate,
					       &data->riic_master_ext_cfg->clock_settings);
		data->riic_master_ext_cfg->timeout_mode = IIC_MASTER_TIMEOUT_MODE_SHORT;
		data->riic_master_ext_cfg->timeout_scl_low = IIC_MASTER_TIMEOUT_SCL_LOW_ENABLED;
		break;
	default:
		LOG_ERR("%s: Invalid I2C speed rate: %d", __func__, config->fsp_cfg->rate);
		LOG_ERR("%s: Invalid I2C speed rate: %d", __func__, data->fsp_cfg->rate);
		return -ENOTSUP;
	}

	err = config->fsp_api->open(data->fsp_ctrl, config->fsp_cfg);
	err = config->fsp_api->open(data->fsp_ctrl, data->fsp_cfg);

	if (err != FSP_SUCCESS) {
		LOG_ERR("I2C initialization failed");
@@ -303,7 +389,7 @@ static void calc_riic_master_bitrate(const struct i2c_rz_riic_config *config,
				     uint32_t total_brl_brh, uint32_t brh, uint32_t divider,
				     struct rz_riic_master_bitrate *result)
{
	const uint32_t noise_filter_stages = config->riic_master_ext_cfg->noise_filter_stage;
	const uint32_t noise_filter_stages = config->noise_filter_stage;
	const double rise_time_s = config->rise_time_s;
	const double fall_time_s = config->fall_time_s;
	const double requested_duty = config->duty_cycle_percent;
@@ -342,7 +428,7 @@ static void calc_riic_master_clock_setting(const struct device *dev, const uint3
					   iic_master_clock_settings_t *clk_cfg)
{
	const struct i2c_rz_riic_config *config = dev->config;
	const uint32_t noise_filter_stages = config->riic_master_ext_cfg->noise_filter_stage;
	const uint32_t noise_filter_stages = config->noise_filter_stage;
	const double rise_time_s = config->rise_time_s;
	const double fall_time_s = config->fall_time_s;
	const uint32_t requested_duty = config->duty_cycle_percent;
@@ -461,27 +547,32 @@ static DEVICE_API(i2c, i2c_rz_riic_driver_api) = {
	.transfer = i2c_rz_riic_transfer,
};

#define I2C_RZG_IRQ_CONNECT(index, irq_name, isr)                                                  \
#ifdef CONFIG_CPU_CORTEX_M
#define GET_IRQ_FLAGS(index, irq_name) 0
#else /* Cortex-A/R */
#define GET_IRQ_FLAGS(index, irq_name) DT_INST_IRQ_BY_NAME(index, irq_name, flags)
#endif

#define I2C_RZ_IRQ_CONNECT(index, irq_name, isr)                                                   \
	do {                                                                                       \
		IRQ_CONNECT(DT_INST_IRQ_BY_NAME(index, irq_name, irq),                             \
			    DT_INST_IRQ_BY_NAME(index, irq_name, priority), isr,                   \
			    DEVICE_DT_INST_GET(index), 0);                                         \
			    DEVICE_DT_INST_GET(index), GET_IRQ_FLAGS(index, irq_name));            \
		irq_enable(DT_INST_IRQ_BY_NAME(index, irq_name, irq));                             \
	} while (0)

#define I2C_RZG_CONFIG_FUNC(index)                                                                 \
	I2C_RZG_IRQ_CONNECT(index, rxi, riic_master_rxi_isr);                                      \
	I2C_RZG_IRQ_CONNECT(index, txi, riic_master_txi_isr);                                      \
	I2C_RZG_IRQ_CONNECT(index, tei, riic_master_tei_isr);                                      \
	I2C_RZG_IRQ_CONNECT(index, naki, riic_master_naki_isr);                                    \
	I2C_RZG_IRQ_CONNECT(index, sti, riic_master_sti_isr);                                      \
	I2C_RZG_IRQ_CONNECT(index, spi, riic_master_spi_isr);                                      \
	I2C_RZG_IRQ_CONNECT(index, ali, riic_master_ali_isr);                                      \
	I2C_RZG_IRQ_CONNECT(index, tmoi, riic_master_tmoi_isr);

#define I2C_RZG_RIIC_INIT(index)                                                                   \
	static const double RZG_RIIC_MASTER_DIV_TIME_NS = 1000000000;                              \
                                                                                                   \
#if defined(CONFIG_I2C_RENESAS_RZ_RIIC)
#define I2C_RZ_CONFIG_FUNC(index)                                                                  \
	I2C_RZ_IRQ_CONNECT(index, rxi, i2c_rz_riic_master_rxi_isr);                                \
	I2C_RZ_IRQ_CONNECT(index, txi, i2c_rz_riic_master_txi_isr);                                \
	I2C_RZ_IRQ_CONNECT(index, tei, i2c_rz_riic_master_tei_isr);                                \
	I2C_RZ_IRQ_CONNECT(index, naki, i2c_rz_riic_master_naki_isr);                              \
	I2C_RZ_IRQ_CONNECT(index, sti, i2c_rz_riic_master_sti_isr);                                \
	I2C_RZ_IRQ_CONNECT(index, spi, i2c_rz_riic_master_spi_isr);                                \
	I2C_RZ_IRQ_CONNECT(index, ali, i2c_rz_riic_master_ali_isr);                                \
	I2C_RZ_IRQ_CONNECT(index, tmoi, i2c_rz_riic_master_tmoi_isr);

#define I2C_RZ_EXTENDED_CFG(index)                                                                 \
	static riic_master_extended_cfg_t g_i2c_master##index##_extend = {                         \
		.noise_filter_stage = DT_INST_PROP(index, noise_filter_stages),                    \
		.naki_irq = DT_INST_IRQ_BY_NAME(index, naki, irq),                                 \
@@ -489,7 +580,23 @@ static DEVICE_API(i2c, i2c_rz_riic_driver_api) = {
		.spi_irq = DT_INST_IRQ_BY_NAME(index, spi, irq),                                   \
		.ali_irq = DT_INST_IRQ_BY_NAME(index, ali, irq),                                   \
		.tmoi_irq = DT_INST_IRQ_BY_NAME(index, tmoi, irq),                                 \
	};                                                                                         \
	};
#endif /* CONFIG_I2C_RENESAS_RZ_RIIC */

#if defined(CONFIG_I2C_RENESAS_RZ_IIC)
#define I2C_RZ_CONFIG_FUNC(index)                                                                  \
	I2C_RZ_IRQ_CONNECT(index, eri, iic_master_eri_isr);                                        \
	I2C_RZ_IRQ_CONNECT(index, rxi, iic_master_rxi_isr);                                        \
	I2C_RZ_IRQ_CONNECT(index, txi, iic_master_txi_isr);                                        \
	I2C_RZ_IRQ_CONNECT(index, tei, iic_master_tei_isr);

#define I2C_RZ_EXTENDED_CFG(index)                                                                 \
	static riic_master_extended_cfg_t g_i2c_master##index##_extend = {};
#endif /* CONFIG_I2C_RENESAS_RZ_IIC */

#define I2C_RZ_RIIC_INIT(index)                                                                    \
                                                                                                   \
	I2C_RZ_EXTENDED_CFG(index)                                                                 \
                                                                                                   \
	static i2c_master_cfg_t g_i2c_master##index##_cfg = {                                      \
		.channel = DT_INST_PROP(index, channel),                                           \
@@ -505,29 +612,31 @@ static DEVICE_API(i2c, i2c_rz_riic_driver_api) = {
		.tei_irq = DT_INST_IRQ_BY_NAME(index, tei, irq),                                   \
		.ipl = DT_INST_IRQ_BY_NAME(index, rxi, priority),                                  \
		.p_extend = &g_i2c_master##index##_extend,                                         \
	};                                                                                         \
		IF_ENABLED(CONFIG_I2C_RENESAS_RZ_IIC,                                              \
				(.eri_irq = DT_INST_IRQ_BY_NAME(index, eri, irq),))};       \
                                                                                                   \
	PINCTRL_DT_INST_DEFINE(index);                                                             \
                                                                                                   \
	static struct i2c_rz_riic_config i2c_rz_riic_config_##index = {                            \
	static const struct i2c_rz_riic_config i2c_rz_riic_config_##index = {                      \
		.pin_config = PINCTRL_DT_INST_DEV_CONFIG_GET(index),                               \
		.fsp_cfg = &g_i2c_master##index##_cfg,                                             \
		.riic_master_ext_cfg = &g_i2c_master##index##_extend,                              \
		.fsp_api = &g_i2c_master_on_iic,                                                   \
		.rise_time_s = DT_INST_PROP(index, rise_time_ns) / RZG_RIIC_MASTER_DIV_TIME_NS,    \
		.fall_time_s = DT_INST_PROP(index, fall_time_ns) / RZG_RIIC_MASTER_DIV_TIME_NS,    \
		.rise_time_s = DT_INST_PROP(index, rise_time_ns) / RZ_RIIC_MASTER_DIV_TIME_NS,     \
		.fall_time_s = DT_INST_PROP(index, fall_time_ns) / RZ_RIIC_MASTER_DIV_TIME_NS,     \
		.duty_cycle_percent = DT_INST_PROP(index, duty_cycle_percent),                     \
		.noise_filter_stage = DT_INST_PROP(index, noise_filter_stages),                    \
	};                                                                                         \
                                                                                                   \
	static iic_master_instance_ctrl_t g_i2c_master##index##_ctrl;                              \
                                                                                                   \
	static struct i2c_rz_riic_data i2c_rz_riic_data_##index = {                                \
		.fsp_ctrl = (i2c_master_ctrl_t *)&g_i2c_master##index##_ctrl,                      \
		.fsp_cfg = &g_i2c_master##index##_cfg,                                             \
		.riic_master_ext_cfg = &g_i2c_master##index##_extend,                              \
	};                                                                                         \
                                                                                                   \
	static int i2c_rz_riic_init_##index(const struct device *dev)                              \
	{                                                                                          \
		I2C_RZG_CONFIG_FUNC(index)                                                         \
		I2C_RZ_CONFIG_FUNC(index)                                                          \
		return i2c_rz_riic_init(dev);                                                      \
	};                                                                                         \
                                                                                                   \
@@ -536,4 +645,9 @@ static DEVICE_API(i2c, i2c_rz_riic_driver_api) = {
				  PRE_KERNEL_2, CONFIG_I2C_INIT_PRIORITY,                          \
				  &i2c_rz_riic_driver_api);

DT_INST_FOREACH_STATUS_OKAY(I2C_RZG_RIIC_INIT)
DT_INST_FOREACH_STATUS_OKAY(I2C_RZ_RIIC_INIT)

#undef DT_DRV_COMPAT
#define DT_DRV_COMPAT renesas_rz_iic

DT_INST_FOREACH_STATUS_OKAY(I2C_RZ_RIIC_INIT)
+43 −0
Original line number Diff line number Diff line
# Copyright (c) 2025 Renesas Electronics Corporation
# SPDX-License-Identifier: Apache-2.0

description: Renesas RZ I2C controller

compatible: "renesas,rz-iic"

include: [i2c-controller.yaml, pinctrl-device.yaml]

properties:
  reg:
    required: true

  channel:
    required: true
    type: int

  interrupts:
    required: true

  rise-time-ns:
    type: int
    default: 120
    description: |
      Number of nanoseconds the SCL signal takes to rise; t(r) in the I2C specification.

  fall-time-ns:
    type: int
    default: 120
    description: |
      Number of nanoseconds the SCL signal takes to fall; t(f) in the I2C specification.

  duty-cycle-percent:
    type: int
    default: 50

  noise-filter-stages:
    type: int
    default: 1
    enum:
      - 1
    description: |
      Set the noise filter stages. Currently, only single-stage filter is supported.
+2 −2
Original line number Diff line number Diff line
# Copyright (c) 2024 Renesas Electronics Corporation
# Copyright (c) 2024-2025 Renesas Electronics Corporation
# SPDX-License-Identifier: Apache-2.0

description: Renesas RZ/G3S I2C controller
description: Renesas RZ I2C controller

compatible: "renesas,rz-riic"

Loading