You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
728 lines
25 KiB
728 lines
25 KiB
/* |
|
* Copyright (c) 2025 Renesas Electronics Corporation |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#define DT_DRV_COMPAT renesas_ra_i2c_sci_b |
|
|
|
#define MDDR_DISABLE 256 |
|
|
|
#include <zephyr/devicetree.h> |
|
#include <zephyr/drivers/clock_control.h> |
|
#include <zephyr/drivers/i2c.h> |
|
#include <zephyr/drivers/pinctrl.h> |
|
#include <zephyr/irq.h> |
|
#include <zephyr/sys/util.h> |
|
#include <zephyr/logging/log.h> |
|
|
|
#include "r_sci_b_i2c.h" |
|
#ifdef CONFIG_I2C_RENESAS_RA_SCI_B_DTC |
|
#include "r_dtc.h" |
|
#endif |
|
|
|
#include <soc.h> |
|
|
|
LOG_MODULE_REGISTER(renesas_ra_i2c_sci_b, CONFIG_I2C_LOG_LEVEL); |
|
|
|
#define I2C_MAX_MSG_LEN (1 << (sizeof(uint8_t) * 8)) |
|
|
|
typedef void (*init_func_t)(const struct device *dev); |
|
struct sci_b_i2c_config { |
|
void (*irq_config_func)(const struct device *dev); |
|
const struct pinctrl_dev_config *pcfg; |
|
uint16_t sda_output_delay; |
|
}; |
|
|
|
struct sci_b_i2c_data { |
|
sci_b_i2c_instance_ctrl_t ctrl; |
|
i2c_master_cfg_t i2c_config; |
|
sci_b_i2c_extended_cfg_t ext_cfg; |
|
struct k_sem bus_lock; |
|
struct k_sem complete_sem; |
|
i2c_master_event_t event; |
|
uint32_t dev_config; |
|
|
|
#ifdef CONFIG_I2C_CALLBACK |
|
uint16_t addr; |
|
uint32_t msg_idx; |
|
struct i2c_msg *msgs; |
|
uint32_t num_msgs; |
|
i2c_callback_t cb; |
|
void *p_context; |
|
#endif /* CONFIG_I2C_CALLBACK */ |
|
|
|
#ifdef CONFIG_I2C_RENESAS_RA_SCI_B_DTC |
|
/* RX */ |
|
transfer_instance_t rx_transfer; |
|
transfer_info_t rx_transfer_info DTC_TRANSFER_INFO_ALIGNMENT; |
|
transfer_cfg_t rx_transfer_cfg; |
|
dtc_instance_ctrl_t rx_transfer_ctrl; |
|
dtc_extended_cfg_t rx_transfer_cfg_extend; |
|
|
|
/* TX */ |
|
transfer_instance_t tx_transfer; |
|
transfer_info_t tx_transfer_info DTC_TRANSFER_INFO_ALIGNMENT; |
|
transfer_cfg_t tx_transfer_cfg; |
|
dtc_instance_ctrl_t tx_transfer_ctrl; |
|
dtc_extended_cfg_t tx_transfer_cfg_extend; |
|
#endif /* CONFIG_I2C_RENESAS_RA_SCI_B_DTC */ |
|
}; |
|
|
|
static void calc_sci_b_iic_clock_setting(const struct device *dev, const uint32_t fsp_i2c_rate, |
|
sci_b_i2c_clock_settings_t *clk_cfg); |
|
|
|
/* FSP interruption handlers. */ |
|
void sci_b_i2c_txi_isr(void); |
|
void sci_b_i2c_tei_isr(void); |
|
void sci_b_i2c_rxi_isr(void); |
|
|
|
static int renesas_ra_sci_b_i2c_configure(const struct device *dev, uint32_t dev_config) |
|
{ |
|
struct sci_b_i2c_data *data = (struct sci_b_i2c_data *const)dev->data; |
|
|
|
if (!(dev_config & I2C_MODE_CONTROLLER)) { |
|
LOG_ERR("Only I2C Master mode supported."); |
|
return -EIO; |
|
} |
|
|
|
switch (I2C_SPEED_GET(dev_config)) { |
|
case I2C_SPEED_STANDARD: |
|
data->i2c_config.rate = I2C_MASTER_RATE_STANDARD; |
|
break; |
|
case I2C_SPEED_FAST: |
|
data->i2c_config.rate = I2C_MASTER_RATE_FAST; |
|
break; |
|
default: |
|
LOG_ERR("Invalid I2C speed rate flag: %d", I2C_SPEED_GET(dev_config)); |
|
return -EIO; |
|
} |
|
|
|
calc_sci_b_iic_clock_setting(dev, data->i2c_config.rate, &data->ext_cfg.clock_settings); |
|
|
|
R_SCI_B_I2C_Close(&data->ctrl); |
|
R_SCI_B_I2C_Open(&data->ctrl, &data->i2c_config); |
|
|
|
/* save current devconfig. */ |
|
data->dev_config = dev_config; |
|
|
|
return 0; |
|
} |
|
|
|
static int renesas_ra_sci_b_i2c_get_config(const struct device *dev, uint32_t *dev_config) |
|
{ |
|
struct sci_b_i2c_data *data = (struct sci_b_i2c_data *const)dev->data; |
|
*dev_config = data->dev_config; |
|
return 0; |
|
} |
|
|
|
#define OPERATION(msg) (((struct i2c_msg *)msg)->flags & I2C_MSG_RW_MASK) |
|
|
|
static int renesas_ra_sci_b_i2c_transfer(const struct device *dev, struct i2c_msg *msgs, |
|
uint8_t num_msgs, uint16_t addr) |
|
{ |
|
struct sci_b_i2c_data *data = (struct sci_b_i2c_data *const)dev->data; |
|
struct i2c_msg *current, *next; |
|
fsp_err_t fsp_err; |
|
int ret; |
|
|
|
if (!num_msgs) { |
|
return 0; |
|
} |
|
|
|
/* Handle i2c burst write, restructure message to be compatible with HAL*/ |
|
if (num_msgs == 2) { |
|
if (msgs[0].len == 1U && !(msgs[0].flags & I2C_MSG_READ) && |
|
!(msgs[1].flags & I2C_MSG_READ)) { |
|
uint16_t tmp_len = msgs[0].len + msgs[1].len; |
|
|
|
if (tmp_len <= I2C_MAX_MSG_LEN) { |
|
static uint8_t merge_buf[I2C_MAX_MSG_LEN]; |
|
struct i2c_msg tmp_msg; |
|
|
|
memcpy(&merge_buf[0], msgs[0].buf, msgs[0].len); |
|
memcpy(&merge_buf[msgs[0].len], msgs[1].buf, msgs[1].len); |
|
tmp_msg.buf = &merge_buf[0]; |
|
tmp_msg.flags = I2C_MSG_WRITE | I2C_MSG_STOP; |
|
tmp_msg.len = (uint8_t)tmp_len; |
|
/* Merge 2 msgs into 1 msg */ |
|
msgs[0] = tmp_msg; |
|
num_msgs = 1; |
|
} else { |
|
LOG_DBG("messages are too large to merge"); |
|
} |
|
} |
|
} |
|
|
|
current = msgs; |
|
ret = 0; |
|
|
|
/* Check for validity of all messages before transfer */ |
|
for (int i = 1; i <= num_msgs; i++) { |
|
if (i < num_msgs) { |
|
next = current + 1; |
|
|
|
/* |
|
* Restart condition between messages |
|
* of different directions is required |
|
*/ |
|
if (OPERATION(current) != OPERATION(next)) { |
|
if (!(next->flags & I2C_MSG_RESTART)) { |
|
LOG_ERR("Restart condition between messages of " |
|
"different directions is required." |
|
"Current/Total: [%d/%d]", |
|
i, num_msgs); |
|
ret = -EIO; |
|
break; |
|
} |
|
} |
|
|
|
/* Stop condition is only allowed on last message */ |
|
if (current->flags & I2C_MSG_STOP) { |
|
LOG_ERR("Invalid stop flag. Stop condition is only allowed on " |
|
"last message. " |
|
"Current/Total: [%d/%d]", |
|
i, num_msgs); |
|
ret = -EIO; |
|
break; |
|
} |
|
} else { |
|
current->flags |= I2C_MSG_STOP; |
|
} |
|
|
|
current++; |
|
} |
|
|
|
if (ret) { |
|
return ret; |
|
} |
|
|
|
k_sem_take(&data->bus_lock, K_FOREVER); |
|
|
|
/* Set destination address with configured address mode before sending msg. */ |
|
|
|
i2c_master_addr_mode_t addr_mode = 0; |
|
|
|
if (I2C_MSG_ADDR_10_BITS & data->dev_config) { |
|
addr_mode = I2C_MASTER_ADDR_MODE_10BIT; |
|
} else { |
|
addr_mode = I2C_MASTER_ADDR_MODE_7BIT; |
|
} |
|
|
|
R_SCI_B_I2C_SlaveAddressSet(&data->ctrl, addr, addr_mode); |
|
|
|
/* Process input `msgs`. */ |
|
|
|
current = msgs; |
|
|
|
while (num_msgs > 0) { |
|
if (num_msgs > 1) { |
|
next = current + 1; |
|
} else { |
|
next = NULL; |
|
} |
|
|
|
if (current->flags & I2C_MSG_READ) { |
|
fsp_err = R_SCI_B_I2C_Read(&data->ctrl, current->buf, current->len, |
|
next != NULL && (next->flags & I2C_MSG_RESTART)); |
|
} else { |
|
fsp_err = |
|
R_SCI_B_I2C_Write(&data->ctrl, current->buf, current->len, |
|
next != NULL && (next->flags & I2C_MSG_RESTART)); |
|
} |
|
|
|
if (fsp_err != FSP_SUCCESS) { |
|
switch (fsp_err) { |
|
case FSP_ERR_INVALID_SIZE: |
|
LOG_ERR("Provided number of bytes more than uint16_t size " |
|
"(65535) while DTC is used for data transfer."); |
|
break; |
|
case FSP_ERR_IN_USE: |
|
LOG_ERR("Bus busy condition. Another transfer was in progress."); |
|
break; |
|
default: |
|
LOG_ERR("Unknown error."); |
|
break; |
|
} |
|
|
|
ret = -EIO; |
|
goto RELEASE_BUS; |
|
} |
|
|
|
/* Wait for callback to return. */ |
|
k_sem_take(&data->complete_sem, K_FOREVER); |
|
|
|
/* Handle event msg from callback. */ |
|
switch (data->event) { |
|
case I2C_MASTER_EVENT_ABORTED: |
|
LOG_ERR("%s failed.", (current->flags & I2C_MSG_READ) ? "Read" : "Write"); |
|
ret = -EIO; |
|
goto RELEASE_BUS; |
|
case I2C_MASTER_EVENT_RX_COMPLETE: |
|
break; |
|
case I2C_MASTER_EVENT_TX_COMPLETE: |
|
break; |
|
default: |
|
break; |
|
} |
|
|
|
current++; |
|
num_msgs--; |
|
} |
|
|
|
RELEASE_BUS: |
|
k_sem_give(&data->bus_lock); |
|
|
|
return ret; |
|
} |
|
|
|
#ifdef CONFIG_I2C_CALLBACK |
|
|
|
static void renesas_ra_sci_b_i2c_async_done(const struct device *dev, struct sci_b_i2c_data *data, |
|
int result) |
|
{ |
|
|
|
i2c_callback_t cb = data->cb; |
|
void *p_context = data->p_context; |
|
|
|
data->msg_idx = 0; |
|
data->msgs = NULL; |
|
data->num_msgs = 0; |
|
data->cb = NULL; |
|
data->p_context = NULL; |
|
data->addr = 0; |
|
|
|
k_sem_give(&data->bus_lock); |
|
|
|
/* Callback may wish to start another transfer */ |
|
cb(dev, result, p_context); |
|
} |
|
|
|
/* Start a transfer asynchronously */ |
|
static void renesas_ra_sci_b_i2c_async_iter(const struct device *dev) |
|
{ |
|
struct sci_b_i2c_data *data = dev->data; |
|
fsp_err_t fsp_err; |
|
struct i2c_msg *current, *next; |
|
|
|
struct i2c_msg *msg = &data->msgs[data->msg_idx]; |
|
|
|
/* Check for validity of all messages before transfer */ |
|
current = msg; |
|
if (data->msg_idx < (data->num_msgs - 1)) { |
|
next = current + 1; |
|
|
|
/* |
|
* Restart condition between messages |
|
* of different directions is required |
|
*/ |
|
if (OPERATION(current) != OPERATION(next)) { |
|
if (!(next->flags & I2C_MSG_RESTART)) { |
|
LOG_ERR("Restart condition between messages of " |
|
"different directions is required." |
|
"Current/Total: [%d/%d]", |
|
data->msg_idx + 1, data->num_msgs); |
|
renesas_ra_sci_b_i2c_async_done(dev, data, -EIO); |
|
return; |
|
} |
|
} |
|
|
|
if (current->flags & I2C_MSG_STOP) { |
|
LOG_ERR("Invalid stop flag. Stop condition is only allowed on " |
|
"last message. " |
|
"Current/Total: [%d/%d]", |
|
data->msg_idx + 1, data->num_msgs); |
|
renesas_ra_sci_b_i2c_async_done(dev, data, -EIO); |
|
return; |
|
} |
|
} else { |
|
current->flags |= I2C_MSG_STOP; |
|
next = NULL; |
|
} |
|
|
|
if (current->flags & I2C_MSG_READ) { |
|
fsp_err = R_SCI_B_I2C_Read(&data->ctrl, current->buf, current->len, |
|
(next != NULL) && (next->flags & I2C_MSG_RESTART)); |
|
} else { |
|
fsp_err = R_SCI_B_I2C_Write(&data->ctrl, current->buf, current->len, |
|
(next != NULL) && (next->flags & I2C_MSG_RESTART)); |
|
} |
|
|
|
/* Return an error if the transfer didn't start successfully |
|
* e.g., if the bus was busy |
|
*/ |
|
if (fsp_err != FSP_SUCCESS) { |
|
switch (fsp_err) { |
|
case FSP_ERR_INVALID_SIZE: |
|
LOG_ERR("Provided number of bytes more than uint16_t size " |
|
"(65535) while DTC is used for data transfer."); |
|
break; |
|
case FSP_ERR_IN_USE: |
|
LOG_ERR("Bus busy condition. Another transfer was in progress."); |
|
break; |
|
default: |
|
LOG_ERR("Unknown error."); |
|
break; |
|
} |
|
|
|
R_SCI_B_I2C_Abort(&data->ctrl); |
|
return; |
|
} |
|
} |
|
|
|
static int renesas_ra_sci_b_i2c_transfer_cb(const struct device *dev, struct i2c_msg *msgs, |
|
uint8_t num_msgs, uint16_t addr, i2c_callback_t cb, |
|
void *p_context) |
|
{ |
|
struct sci_b_i2c_data *data = dev->data; |
|
|
|
int res = k_sem_take(&data->bus_lock, K_NO_WAIT); |
|
|
|
if (res != 0) { |
|
return -EWOULDBLOCK; |
|
} |
|
|
|
data->msg_idx = 0; |
|
data->msgs = msgs; |
|
data->num_msgs = num_msgs; |
|
data->addr = addr; |
|
data->cb = cb; |
|
data->p_context = p_context; |
|
|
|
renesas_ra_sci_b_i2c_async_iter(dev); |
|
|
|
return 0; |
|
} |
|
|
|
#endif /* CONFIG_I2C_CALLBACK */ |
|
|
|
static void renesas_ra_sci_b_i2c_callback(i2c_master_callback_args_t *p_args) |
|
{ |
|
const struct device *dev = p_args->p_context; |
|
struct sci_b_i2c_data *data = dev->data; |
|
|
|
#ifdef CONFIG_I2C_CALLBACK |
|
if (data->cb != NULL) { |
|
/* Async transfer */ |
|
if (p_args->event == I2C_MASTER_EVENT_ABORTED) { |
|
R_SCI_B_I2C_Abort(&data->ctrl); |
|
renesas_ra_sci_b_i2c_async_done(dev, data, -EIO); |
|
} else if (data->msg_idx == data->num_msgs - 1) { |
|
renesas_ra_sci_b_i2c_async_done(dev, data, 0); |
|
} else { |
|
data->msg_idx++; |
|
renesas_ra_sci_b_i2c_async_iter(dev); |
|
} |
|
return; |
|
} |
|
#endif /* CONFIG_I2C_CALLBACK */ |
|
|
|
data->event = p_args->event; |
|
|
|
k_sem_give(&data->complete_sem); |
|
} |
|
|
|
static int renesas_ra_sci_b_i2c_init(const struct device *dev) |
|
{ |
|
const struct sci_b_i2c_config *config = dev->config; |
|
struct sci_b_i2c_data *data = (struct sci_b_i2c_data *)dev->data; |
|
fsp_err_t fsp_err; |
|
int ret; |
|
|
|
data->dev_config |= I2C_MODE_CONTROLLER; |
|
|
|
/* Configure dt provided device signals when available */ |
|
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT); |
|
|
|
if (ret < 0) { |
|
LOG_ERR("Pinctrl config failed."); |
|
return ret; |
|
} |
|
|
|
k_sem_init(&data->bus_lock, 1, 1); |
|
k_sem_init(&data->complete_sem, 0, 1); |
|
|
|
switch (data->i2c_config.rate) { |
|
case I2C_MASTER_RATE_STANDARD: |
|
calc_sci_b_iic_clock_setting(dev, data->i2c_config.rate, |
|
&data->ext_cfg.clock_settings); |
|
data->i2c_config.p_extend = &data->ext_cfg; |
|
data->dev_config |= I2C_SPEED_SET(I2C_SPEED_STANDARD); |
|
break; |
|
case I2C_MASTER_RATE_FAST: |
|
calc_sci_b_iic_clock_setting(dev, data->i2c_config.rate, |
|
&data->ext_cfg.clock_settings); |
|
data->i2c_config.p_extend = &data->ext_cfg; |
|
data->dev_config |= I2C_SPEED_SET(I2C_SPEED_FAST); |
|
break; |
|
default: |
|
LOG_ERR("Invalid I2C speed rate: %d", data->i2c_config.rate); |
|
return -ENOTSUP; |
|
} |
|
|
|
#ifdef CONFIG_I2C_RENESAS_RA_SCI_B_DTC |
|
data->i2c_config.p_transfer_rx = &data->rx_transfer; |
|
data->i2c_config.p_transfer_tx = &data->tx_transfer; |
|
#endif |
|
|
|
fsp_err = R_SCI_B_I2C_Open(&data->ctrl, &data->i2c_config); |
|
|
|
if (fsp_err != FSP_SUCCESS) { |
|
LOG_ERR("I2C init failed."); |
|
} |
|
|
|
config->irq_config_func(dev); |
|
|
|
return 0; |
|
}; |
|
|
|
static void calc_sci_b_iic_clock_setting(const struct device *dev, const uint32_t fsp_i2c_rate, |
|
sci_b_i2c_clock_settings_t *clk_cfg) |
|
{ |
|
const struct sci_b_i2c_config *config = dev->config; |
|
|
|
uint32_t bitrate = 0; |
|
bool use_mddr = clk_cfg->bitrate_modulation; |
|
|
|
uint32_t divisor = 0; |
|
uint32_t divisor_bitrate_multiple = 0; |
|
uint32_t brr = 0; |
|
int32_t cks = 0; |
|
uint32_t delta_error = 0; |
|
|
|
uint32_t sda_delay_clock = 0; |
|
uint32_t sda_delay_counts = 0; |
|
uint32_t temp_mddr; |
|
uint32_t calculated_bitrate = 0; |
|
|
|
uint32_t mddr = MDDR_DISABLE; |
|
|
|
uint32_t peripheral_clock = R_FSP_SciClockHzGet(); |
|
|
|
uint32_t sda_delay_ns = config->sda_output_delay; |
|
|
|
if (I2C_MASTER_RATE_FAST == fsp_i2c_rate) { |
|
bitrate = 400000; |
|
} else { |
|
bitrate = 100000; |
|
} |
|
|
|
for (uint32_t i = 0; i <= 3; i++) { |
|
|
|
divisor_bitrate_multiple = (1 << (2 * (i + 1))) * 8; |
|
divisor = divisor_bitrate_multiple * bitrate; |
|
|
|
/* Calculate BRR so that the bit rate is the largest possible value less than or |
|
* equal to the desired bitrate. |
|
*/ |
|
brr = (uint32_t)ceil(((double)peripheral_clock) / divisor - 1); |
|
if (brr <= 255) { |
|
break; |
|
} |
|
cks++; |
|
} |
|
calculated_bitrate = (uint32_t)((double)peripheral_clock) / |
|
(divisor_bitrate_multiple * (256 / mddr) * (brr + 1)); |
|
delta_error = bitrate - calculated_bitrate; |
|
|
|
if (use_mddr) { |
|
for (uint32_t temp_brr = brr; temp_brr > 0; temp_brr--) { |
|
|
|
/** Calculate the MDDR (M) value if bit rate modulation is enabled, |
|
* The formula to calculate MBBR (from the M and N relationship given in the |
|
* hardware manual) is as follows and it must be between 128 and 256. MDDR = |
|
* ((divisor * 256) * (BRR + 1)) / PCLK |
|
*/ |
|
temp_mddr = (uint32_t)floor(((double)divisor) * 256 * (temp_brr + 1) / |
|
peripheral_clock); |
|
|
|
/* The maximum value that could result from the calculation above is 256, |
|
* which is a valid MDDR value, so only the lower bound is checked. |
|
*/ |
|
if (temp_mddr < 128) { |
|
break; |
|
} |
|
|
|
/* The maximum for MDDR is 256 (MDDR unused). */ |
|
if (temp_mddr > 256) { |
|
continue; |
|
} |
|
|
|
calculated_bitrate = |
|
(uint32_t)(peripheral_clock / |
|
(divisor_bitrate_multiple * (256 / ((double)temp_mddr)) * |
|
(temp_brr + 1))); |
|
|
|
/** If the bit rate error is less than the previous lowest bit rate error, |
|
* then store these settings as the best value. |
|
*/ |
|
if ((bitrate - calculated_bitrate) < delta_error) { |
|
delta_error = bitrate - calculated_bitrate; |
|
brr = temp_brr; |
|
mddr = temp_mddr; |
|
} |
|
} |
|
} |
|
|
|
/* If MDDR == 256, disable bitrate modulation and set MDDR to a valid value. */ |
|
if (mddr == 256) { |
|
mddr = 255; |
|
use_mddr = false; |
|
} |
|
|
|
/* Calculate SDA delay. */ |
|
sda_delay_clock = peripheral_clock >> cks; |
|
sda_delay_counts = (uint32_t)ceil(((double)sda_delay_ns) * sda_delay_clock / 1000000000); |
|
if (sda_delay_counts > 31) { |
|
sda_delay_counts = 31; |
|
} |
|
|
|
clk_cfg->clk_divisor_value = (uint8_t)cks; |
|
clk_cfg->brr_value = (uint8_t)brr; |
|
clk_cfg->mddr_value = (uint8_t)mddr; |
|
clk_cfg->bitrate_modulation = use_mddr; |
|
clk_cfg->cycles_value = (uint8_t)sda_delay_counts; |
|
} |
|
|
|
static const struct i2c_driver_api renesas_ra_sci_b_i2c_driver_api = { |
|
.configure = renesas_ra_sci_b_i2c_configure, |
|
.get_config = renesas_ra_sci_b_i2c_get_config, |
|
.transfer = renesas_ra_sci_b_i2c_transfer, |
|
#ifdef CONFIG_I2C_CALLBACK |
|
.transfer_cb = renesas_ra_sci_b_i2c_transfer_cb, |
|
#endif /* CONFIG_I2C_CALLBACK */ |
|
}; |
|
|
|
#define _ELC_EVENT_SCI_RXI(channel) ELC_EVENT_SCI##channel##_RXI |
|
#define _ELC_EVENT_SCI_TXI(channel) ELC_EVENT_SCI##channel##_TXI |
|
#define _ELC_EVENT_SCI_TEI(channel) ELC_EVENT_SCI##channel##_TEI |
|
|
|
#define ELC_EVENT_SCI_RXI(channel) _ELC_EVENT_SCI_RXI(channel) |
|
#define ELC_EVENT_SCI_TXI(channel) _ELC_EVENT_SCI_TXI(channel) |
|
#define ELC_EVENT_SCI_TEI(channel) _ELC_EVENT_SCI_TEI(channel) |
|
|
|
#ifndef CONFIG_I2C_RENESAS_RA_SCI_B_DTC |
|
#define SCI_B_I2C_DTC_INIT(index) |
|
#define RXI_TRANSFER(index) |
|
#else |
|
#define SCI_B_I2C_DTC_INIT(index) \ |
|
.rx_transfer_info = \ |
|
{ \ |
|
.transfer_settings_word_b.dest_addr_mode = TRANSFER_ADDR_MODE_INCREMENTED, \ |
|
.transfer_settings_word_b.repeat_area = TRANSFER_REPEAT_AREA_DESTINATION, \ |
|
.transfer_settings_word_b.irq = TRANSFER_IRQ_END, \ |
|
.transfer_settings_word_b.chain_mode = TRANSFER_CHAIN_MODE_DISABLED, \ |
|
.transfer_settings_word_b.src_addr_mode = TRANSFER_ADDR_MODE_FIXED, \ |
|
.transfer_settings_word_b.size = TRANSFER_SIZE_1_BYTE, \ |
|
.transfer_settings_word_b.mode = TRANSFER_MODE_NORMAL, \ |
|
.p_dest = (void *)NULL, \ |
|
.p_src = (void const *)NULL, \ |
|
.num_blocks = 0, \ |
|
.length = 0, \ |
|
}, \ |
|
.rx_transfer_cfg_extend = {.activation_source = \ |
|
DT_IRQ_BY_NAME(DT_INST_PARENT(index), rxi, irq)}, \ |
|
.rx_transfer_cfg = \ |
|
{ \ |
|
.p_info = &sci_b_i2c_data_##index.rx_transfer_info, \ |
|
.p_extend = &sci_b_i2c_data_##index.rx_transfer_cfg_extend, \ |
|
}, \ |
|
.rx_transfer = \ |
|
{ \ |
|
.p_ctrl = &sci_b_i2c_data_##index.rx_transfer_ctrl, \ |
|
.p_cfg = &sci_b_i2c_data_##index.rx_transfer_cfg, \ |
|
.p_api = &g_transfer_on_dtc, \ |
|
}, \ |
|
.tx_transfer_info = \ |
|
{ \ |
|
.transfer_settings_word_b.dest_addr_mode = TRANSFER_ADDR_MODE_FIXED, \ |
|
.transfer_settings_word_b.repeat_area = TRANSFER_REPEAT_AREA_SOURCE, \ |
|
.transfer_settings_word_b.irq = TRANSFER_IRQ_END, \ |
|
.transfer_settings_word_b.chain_mode = TRANSFER_CHAIN_MODE_DISABLED, \ |
|
.transfer_settings_word_b.src_addr_mode = TRANSFER_ADDR_MODE_INCREMENTED, \ |
|
.transfer_settings_word_b.size = TRANSFER_SIZE_1_BYTE, \ |
|
.transfer_settings_word_b.mode = TRANSFER_MODE_NORMAL, \ |
|
.p_dest = (void *)NULL, \ |
|
.p_src = (void const *)NULL, \ |
|
.num_blocks = 0, \ |
|
.length = 0, \ |
|
}, \ |
|
.tx_transfer_cfg_extend = {.activation_source = \ |
|
DT_IRQ_BY_NAME(DT_INST_PARENT(index), txi, irq)}, \ |
|
.tx_transfer_cfg = \ |
|
{ \ |
|
.p_info = &sci_b_i2c_data_##index.tx_transfer_info, \ |
|
.p_extend = &sci_b_i2c_data_##index.tx_transfer_cfg_extend, \ |
|
}, \ |
|
.tx_transfer = { \ |
|
.p_ctrl = &sci_b_i2c_data_##index.tx_transfer_ctrl, \ |
|
.p_cfg = &sci_b_i2c_data_##index.tx_transfer_cfg, \ |
|
.p_api = &g_transfer_on_dtc, \ |
|
}, |
|
|
|
#define RXI_TRANSFER(index) \ |
|
/* rxi */ \ |
|
R_ICU->IELSR[DT_IRQ_BY_NAME(DT_INST_PARENT(index), rxi, irq)] = \ |
|
ELC_EVENT_SCI_RXI(DT_INST_PROP(index, channel)); \ |
|
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_INST_PARENT(index), rxi, irq), \ |
|
DT_IRQ_BY_NAME(DT_INST_PARENT(index), rxi, priority), sci_b_i2c_rxi_isr, \ |
|
DEVICE_DT_INST_GET(index), 0); \ |
|
irq_enable(DT_IRQ_BY_NAME(DT_INST_PARENT(index), rxi, irq)); |
|
#endif |
|
|
|
#define SCI_B_I2C_RA_INIT(index) \ |
|
static void renesas_ra_sci_b_i2c_irq_config_func##index(const struct device *dev) \ |
|
{ \ |
|
RXI_TRANSFER(index) \ |
|
\ |
|
/* txi */ \ |
|
R_ICU->IELSR[DT_IRQ_BY_NAME(DT_INST_PARENT(index), txi, irq)] = \ |
|
ELC_EVENT_SCI_TXI(DT_INST_PROP(index, channel)); \ |
|
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_INST_PARENT(index), txi, irq), \ |
|
DT_IRQ_BY_NAME(DT_INST_PARENT(index), txi, priority), \ |
|
sci_b_i2c_txi_isr, DEVICE_DT_INST_GET(index), 0); \ |
|
irq_enable(DT_IRQ_BY_NAME(DT_INST_PARENT(index), txi, irq)); \ |
|
\ |
|
/* tei */ \ |
|
R_ICU->IELSR[DT_IRQ_BY_NAME(DT_INST_PARENT(index), tei, irq)] = \ |
|
ELC_EVENT_SCI_TEI(DT_INST_PROP(index, channel)); \ |
|
IRQ_CONNECT(DT_IRQ_BY_NAME(DT_INST_PARENT(index), tei, irq), \ |
|
DT_IRQ_BY_NAME(DT_INST_PARENT(index), tei, priority), \ |
|
sci_b_i2c_tei_isr, DEVICE_DT_INST_GET(index), 0); \ |
|
irq_enable(DT_IRQ_BY_NAME(DT_INST_PARENT(index), tei, irq)); \ |
|
} \ |
|
PINCTRL_DT_DEFINE(DT_INST_PARENT(index)); \ |
|
\ |
|
static const struct sci_b_i2c_config sci_b_i2c_config_##index = { \ |
|
.pcfg = PINCTRL_DT_DEV_CONFIG_GET(DT_INST_PARENT(index)), \ |
|
.irq_config_func = renesas_ra_sci_b_i2c_irq_config_func##index, \ |
|
.sda_output_delay = DT_INST_PROP(index, sda_output_delay), \ |
|
}; \ |
|
static struct sci_b_i2c_data sci_b_i2c_data_##index = { \ |
|
.i2c_config = \ |
|
{ \ |
|
.channel = DT_INST_PROP(index, channel), \ |
|
.slave = 0, \ |
|
.rate = I2C_MASTER_RATE_STANDARD, \ |
|
.addr_mode = I2C_MASTER_ADDR_MODE_7BIT, \ |
|
.ipl = DT_IRQ_BY_NAME(DT_INST_PARENT(index), txi, priority), \ |
|
.rxi_irq = DT_IRQ_BY_NAME(DT_INST_PARENT(index), rxi, irq), \ |
|
.txi_irq = DT_IRQ_BY_NAME(DT_INST_PARENT(index), txi, irq), \ |
|
.tei_irq = DT_IRQ_BY_NAME(DT_INST_PARENT(index), tei, irq), \ |
|
.p_callback = renesas_ra_sci_b_i2c_callback, \ |
|
.p_context = DEVICE_DT_GET(DT_DRV_INST(index)), \ |
|
}, \ |
|
.ext_cfg = \ |
|
{ \ |
|
.clock_settings.snfr_value = \ |
|
DT_INST_PROP(index, noise_filter_clock_select), \ |
|
.clock_settings.bitrate_modulation = DT_INST_NODE_HAS_PROP( \ |
|
DT_DRV_INST(index), bit_rate_modulation), \ |
|
.clock_settings.clock_source = SCI_B_I2C_CLOCK_SOURCE_SCISPICLK, \ |
|
}, \ |
|
SCI_B_I2C_DTC_INIT(index)}; \ |
|
I2C_DEVICE_DT_INST_DEFINE(index, renesas_ra_sci_b_i2c_init, NULL, &sci_b_i2c_data_##index, \ |
|
&sci_b_i2c_config_##index, POST_KERNEL, \ |
|
CONFIG_I2C_INIT_PRIORITY, &renesas_ra_sci_b_i2c_driver_api); |
|
|
|
DT_INST_FOREACH_STATUS_OKAY(SCI_B_I2C_RA_INIT)
|
|
|