blob: 353bd2de65730401baf657bf00ee168593347b89 [file] [log] [blame]
/*
* Copyright (c) 2025 Renesas Electronics Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT renesas_rx_ctsu
#include <zephyr/device.h>
#include <zephyr/input/input.h>
#include <zephyr/drivers/pinctrl.h>
#include <r_ctsu_qe_pinset.h>
#include <zephyr/kernel.h>
#include <zephyr/irq.h>
#include <zephyr/logging/log.h>
#include <soc.h>
#include <r_ctsu_qe_if.h>
#include <rm_touch_qe_if.h>
#include <zephyr/input/input_renesas_rx_ctsu.h>
#include <zephyr/dt-bindings/input/input-event-codes.h>
LOG_MODULE_REGISTER(renesas_rx_ctsu, CONFIG_INPUT_LOG_LEVEL);
#define BUTTON_TYPE 0
#define SLIDER_TYPE 1
#define WHEEL_TYPE 2
#define MAX_TUNING_LOOP_COUNT 1024
typedef enum {
INITIALIZING = 0,
TUNING = 1,
SCANNING = 2,
} working_phase_t;
enum touch_event {
RELEASE = 0, /* state change from TOUCHING to UNTOUCH */
PRESS = 1, /* state change from UNTOUCH to TOUCHING */
};
/** Configuration of each TS channel */
typedef struct st_touch_channel_config {
uint8_t channel_num;
ctsu_element_cfg_t config;
} touch_channel_cfg_t;
/** Component context */
typedef struct st_buttons_context {
/** TS channel of button */
uint8_t element;
/** Configuration for each button */
touch_button_cfg_t config;
/** Event for that will be reported to higher layer */
uint16_t event;
} touch_button_context_t;
typedef struct st_sliders_context {
/** Array of TS channels used in slider */
uint8_t *p_elements;
/** Configuration for each slider */
touch_slider_cfg_t config;
/** Event for that will be reported to higher layer */
uint16_t event;
} touch_slider_context_t;
typedef struct st_wheels_context {
/** Array of TS channels used in wheel */
uint8_t *p_elements;
/** Configuration for each wheel */
touch_wheel_cfg_t config;
/** Event that will be reported to higher layer */
uint16_t event;
} touch_wheel_context_t;
struct renesas_rx_ctsu_config {
const struct pinctrl_dev_config *pcfg;
/** CTSU channels config */
touch_channel_cfg_t *channel_cfgs;
uint8_t *channels_index_map;
uint8_t *button_position_index;
/** Touch components */
touch_button_context_t *buttons;
touch_slider_context_t *sliders;
touch_wheel_context_t *wheels;
};
struct renesas_rx_ctsu_data {
const struct device *dev;
/** Data processing */
struct k_work data_process_work;
struct k_work scan_work;
struct k_timer scan_timer;
struct k_sem tune_scan_end;
working_phase_t work_phase;
/** Touch instances */
touch_instance_t touch_instance;
#ifndef CONFIG_INPUT_RENESAS_RX_QE_TOUCH_CFG
touch_instance_ctrl_t touch_ctrl;
touch_cfg_t touch_cfg;
/** CTSU instances */
ctsu_instance_t ctsu_instance;
ctsu_instance_ctrl_t ctsu_ctrl;
ctsu_cfg_t ctsu_cfg;
#endif /* CONFIG_INPUT_RENESAS_RX_QE_TOUCH_CFG */
/** Touch driver output data */
uint64_t curr_buttons_data;
uint64_t prev_buttons_data;
uint16_t *curr_sliders_position;
uint16_t *prev_sliders_position;
uint16_t *curr_wheels_position;
uint16_t *prev_wheels_position;
};
void ctsu_ctsuend_isr(void);
void ctsu_ctsuwr_isr(void);
void ctsu_ctsurd_isr(void);
static void ctsuwr_isr(const struct device *dev)
{
ARG_UNUSED(dev);
ctsu_ctsuwr_isr();
}
static void ctsurd_isr(const struct device *dev)
{
ARG_UNUSED(dev);
ctsu_ctsurd_isr();
}
static void ctsufn_isr(const struct device *dev)
{
ARG_UNUSED(dev);
ctsu_ctsuend_isr();
}
static void ctsu_scan_callback(ctsu_callback_args_t *p_arg)
{
const struct device *dev = p_arg->p_context;
struct renesas_rx_ctsu_data *data = dev->data;
if (data->work_phase == TUNING) {
k_sem_give(&data->tune_scan_end);
return;
}
if (data->work_phase != SCANNING || p_arg->event != CTSU_EVENT_SCAN_COMPLETE) {
return;
}
k_work_submit(&data->data_process_work);
}
static void process_data(struct k_work *work)
{
struct renesas_rx_ctsu_data *data =
CONTAINER_OF(work, struct renesas_rx_ctsu_data, data_process_work);
const struct device *dev = data->dev;
const struct renesas_rx_ctsu_config *config = dev->config;
fsp_err_t ret;
ret = RM_TOUCH_DataGet(data->touch_instance.p_ctrl, &data->curr_buttons_data,
data->curr_sliders_position, data->curr_wheels_position);
if (ret != FSP_SUCCESS) {
LOG_ERR("CTSU: Failed to get data %d", ret);
return;
}
/** Buttons */
int changed_buttons = data->curr_buttons_data ^ data->prev_buttons_data;
int button_position = 0;
while (changed_buttons != 0) {
if (changed_buttons & BIT(0)) {
int index = config->button_position_index[button_position];
input_report_key(dev, config->buttons[index].event,
data->curr_buttons_data & BIT(button_position), true,
K_FOREVER);
}
button_position++;
changed_buttons = changed_buttons >> 1;
}
data->prev_buttons_data = data->curr_buttons_data;
/** Sliders */
for (int i = 0; i < data->touch_instance.p_cfg->num_sliders; i++) {
if (data->curr_sliders_position[i] != data->prev_sliders_position[i]) {
input_report_abs(dev, config->sliders[i].event,
data->curr_sliders_position[i], true, K_FOREVER);
}
data->prev_sliders_position[i] = data->curr_sliders_position[i];
}
/** Wheels */
for (int i = 0; i < data->touch_instance.p_cfg->num_wheels; i++) {
if (data->curr_wheels_position[i] != data->prev_wheels_position[i]) {
input_report_abs(dev, config->wheels[i].event,
data->curr_wheels_position[i], true, K_FOREVER);
}
data->prev_wheels_position[i] = data->curr_wheels_position[i];
}
}
static void timer_callback(struct k_timer *timer)
{
struct renesas_rx_ctsu_data *data =
CONTAINER_OF(timer, struct renesas_rx_ctsu_data, scan_timer);
k_work_submit(&data->scan_work);
}
static void trigger_scan(struct k_work *work)
{
struct renesas_rx_ctsu_data *data =
CONTAINER_OF(work, struct renesas_rx_ctsu_data, scan_work);
/** Start next scan */
RM_TOUCH_ScanStart(data->touch_instance.p_ctrl);
}
#ifndef CONFIG_INPUT_RENESAS_RX_QE_TOUCH_CFG
static inline int set_scan_channel(const struct device *dev)
{
struct renesas_rx_ctsu_data *data = dev->data;
const struct renesas_rx_ctsu_config *config = dev->config;
touch_channel_cfg_t *channel_cfgs = config->channel_cfgs;
for (int i = 0; i < data->ctsu_cfg.num_rx; i++) {
int cha_reg = channel_cfgs[i].channel_num / 8;
int cha_pos = channel_cfgs[i].channel_num % 8;
switch (cha_reg) {
case 0:
data->ctsu_cfg.ctsuchac0 |= (1 << cha_pos);
break;
case 1:
data->ctsu_cfg.ctsuchac1 |= (1 << cha_pos);
break;
case 2:
data->ctsu_cfg.ctsuchac2 |= (1 << cha_pos);
break;
case 3:
data->ctsu_cfg.ctsuchac3 |= (1 << cha_pos);
break;
case 4:
data->ctsu_cfg.ctsuchac4 |= (1 << cha_pos);
break;
default:
LOG_ERR("Invalid TS channel");
return -EINVAL;
}
}
return 0;
}
#endif /* !CONFIG_INPUT_RENESAS_RX_QE_TOUCH_CFG */
static int input_renesas_rx_ctsu_configure(const struct device *dev,
const struct renesas_rx_ctsu_touch_cfg *cfg)
{
struct renesas_rx_ctsu_data *data = dev->data;
fsp_err_t ret;
int tuning_loop_count = 0;
data->touch_instance = cfg->touch_instance;
k_sem_init(&data->tune_scan_end, 0, 1);
/** Set initial states */
for (int i = 0; i < data->touch_instance.p_cfg->num_sliders; i++) {
data->prev_sliders_position[i] = TOUCH_OFF_VALUE;
data->curr_sliders_position[i] = TOUCH_OFF_VALUE;
}
for (int i = 0; i < data->touch_instance.p_cfg->num_wheels; i++) {
data->prev_wheels_position[i] = TOUCH_OFF_VALUE;
data->curr_wheels_position[i] = TOUCH_OFF_VALUE;
}
data->work_phase = INITIALIZING;
ret = RM_TOUCH_Open(data->touch_instance.p_ctrl, data->touch_instance.p_cfg);
if (ret != FSP_SUCCESS) {
LOG_ERR("CTSU Open failed");
return -EIO;
}
ret = RM_TOUCH_CallbackSet(data->touch_instance.p_ctrl, ctsu_scan_callback, (void *)dev,
NULL);
if (ret != FSP_SUCCESS) {
LOG_ERR("CTSU Failed to set callback");
return -EIO;
}
data->work_phase = TUNING;
do {
ret = RM_TOUCH_ScanStart(data->touch_instance.p_ctrl);
if (ret != FSP_SUCCESS) {
LOG_ERR("CTSU: Failed to start scan");
return -EIO;
}
k_sem_take(&data->tune_scan_end, K_FOREVER);
ret = RM_TOUCH_DataGet(data->touch_instance.p_ctrl, &data->curr_buttons_data,
data->curr_sliders_position, data->curr_wheels_position);
tuning_loop_count++;
} while (ret != FSP_SUCCESS && tuning_loop_count < MAX_TUNING_LOOP_COUNT);
if (tuning_loop_count >= MAX_TUNING_LOOP_COUNT) {
LOG_ERR("CTSU: Failed to tune the touch sensor");
return -EIO;
}
data->dev = dev;
/* Processing data handler */
k_work_init(&data->data_process_work, process_data);
/* Scanning trigger */
k_work_init(&data->scan_work, trigger_scan);
/* Timer for to set scanning work */
k_timer_init(&data->scan_timer, timer_callback, NULL);
/* Start first scan to ensure the scanning can run normally */
data->work_phase = SCANNING;
ret = RM_TOUCH_ScanStart(data->touch_instance.p_ctrl);
if (ret != FSP_SUCCESS) {
LOG_ERR("CTSU: Failed to start scan");
return -EIO;
}
/* Start timer to periodically run scanning work */
k_timer_start(&data->scan_timer, K_MSEC(CONFIG_INPUT_RENESAS_RX_CTSU_SCAN_INTERVAL_MS),
K_MSEC(CONFIG_INPUT_RENESAS_RX_CTSU_SCAN_INTERVAL_MS));
return 0;
}
int z_impl_renesas_rx_ctsu_group_configure(const struct device *dev,
const struct renesas_rx_ctsu_touch_cfg *cfg)
{
#ifndef CONFIG_INPUT_RENESAS_RX_QE_TOUCH_CFG
ARG_UNUSED(dev);
ARG_UNUSED(cfg);
return -ENOSYS;
#else
return input_renesas_rx_ctsu_configure(dev, cfg);
#endif /* CONFIG_INPUT_RENESAS_RX_QE_TOUCH_CFG */
}
static int renesas_rx_ctsu_init(const struct device *dev)
{
#ifndef CONFIG_INPUT_RENESAS_RX_QE_TOUCH_CFG
struct renesas_rx_ctsu_data *data = dev->data;
#endif /* !CONFIG_INPUT_RENESAS_RX_QE_TOUCH_CFG */
const struct renesas_rx_ctsu_config *config = dev->config;
int err;
err = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
if (err < 0) {
LOG_ERR("CTSU: Failed to set pinctrl");
return err;
}
#ifndef CONFIG_INPUT_RENESAS_RX_QE_TOUCH_CFG
err = set_scan_channel(dev);
if (err < 0) {
LOG_ERR("CTSU: Failed to set scan channel");
return err;
}
data->ctsu_instance.p_ctrl = &data->ctsu_ctrl;
data->ctsu_instance.p_cfg = &data->ctsu_cfg;
data->ctsu_instance.p_api = &g_ctsu_on_ctsu;
data->touch_cfg.p_ctsu_instance = &data->ctsu_instance;
data->touch_instance.p_ctrl = &data->touch_ctrl;
data->touch_instance.p_cfg = &data->touch_cfg;
data->touch_instance.p_api = &g_touch_on_ctsu;
return input_renesas_rx_ctsu_configure(
dev, (const struct renesas_rx_ctsu_touch_cfg *)&data->touch_instance);
#else
return 0;
#endif /* !CONFIG_INPUT_RENESAS_RX_QE_TOUCH_CFG */
}
#define CHANNEL_GET_CONFIG(node_id, prop, idx) \
{ \
.channel_num = DT_PROP_BY_IDX(node_id, prop, idx), \
.config = \
{ \
.ssdiv = DT_PROP(node_id, ssdiv), \
.so = DT_PROP(node_id, so), \
.snum = DT_PROP(node_id, snum), \
.sdpa = DT_PROP(node_id, sdpa), \
}, \
},
#define CTSU_CHANNEL_CFG_INIT(node_id) \
DT_FOREACH_PROP_ELEM(node_id, channels_num, CHANNEL_GET_CONFIG)
#define CTSU_GET_CHANNELS_COUNT(node_id) DT_PROP_LEN(node_id, channels_num)
#define BUTTON_GET_CONTEXT(node_id) \
IF_ENABLED(IS_EQ(DT_ENUM_IDX(node_id, component_type), BUTTON_TYPE), \
({ \
.element = DT_PROP_BY_IDX(node_id, channels_num, 0), \
.config = { \
.elem_index = 0, \
.threshold = DT_PROP(node_id, touch_count_threshold), \
.hysteresis = DT_PROP(node_id, threshold_range), \
}, \
.event = DT_PROP(node_id, zephyr_code), \
},))
#define SLIDER_GET_CONTEXT(node_id) \
IF_ENABLED(IS_EQ(DT_ENUM_IDX(node_id, component_type), SLIDER_TYPE), \
({ \
.p_elements = (uint8_t[])DT_PROP(node_id, channels_num), \
.config = { \
.p_elem_index = NULL, \
.num_elements = DT_PROP_LEN(node_id, channels_num), \
.threshold = DT_PROP(node_id, touch_count_threshold), \
}, \
.event = DT_PROP(node_id, zephyr_code), \
},))
#define WHEEL_GET_CONTEXT(node_id) \
IF_ENABLED(IS_EQ(DT_ENUM_IDX(node_id, component_type), WHEEL_TYPE), \
({ \
.p_elements = (uint8_t[])DT_PROP(node_id, channels_num), \
.config = { \
.p_elem_index = NULL, \
.num_elements = DT_PROP_LEN(node_id, channels_num), \
.threshold = DT_PROP(node_id, touch_count_threshold), \
}, \
.event = DT_PROP(node_id, zephyr_code), \
},))
#define NUM_ELEMENTS(idx) DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP(idx, CTSU_GET_CHANNELS_COUNT, (+))
#define COMPONENT_COUNT(node_id, type) IS_EQ(DT_ENUM_IDX(node_id, component_type), type)
#define COMPONENT_GET_COUNT_BY_TYPE(idx, type) \
DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP_VARGS(idx, COMPONENT_COUNT, (+), type)
#ifndef CONFIG_INPUT_RENESAS_RX_QE_TOUCH_CFG
#define CTSU_HAL_CONFIG_DEFINE(idx) \
.ctsu_cfg = \
{ \
.cap = CTSU_CAP_SOFTWARE, \
.md = CTSU_MODE_SELF_MULTI_SCAN, \
.num_rx = NUM_ELEMENTS(idx), \
.num_moving_average = CONFIG_INPUT_RENESAS_RX_CTSU_NUM_MOVING_AVERAGE, \
.atune1 = CONFIG_INPUT_RENESAS_RX_CTSU_POWER_SUPPLY_CAPACITY, \
.txvsel = CONFIG_INPUT_RENESAS_RX_CTSU_TRANSMISSION_POWER_SUPPLY, \
.ctsuchac0 = 0, \
.ctsuchac1 = 0, \
.ctsuchac2 = 0, \
.ctsuchac3 = 0, \
.ctsuchac4 = 0, \
.ctsuchtrc0 = 0, \
.ctsuchtrc1 = 0, \
.ctsuchtrc2 = 0, \
.ctsuchtrc3 = 0, \
.ctsuchtrc4 = 0, \
.tuning_enable = true, \
.p_elements = ctsu_element_cfgs_##idx, \
.p_callback = ctsu_scan_callback, \
.p_context = NULL, \
}, \
.touch_cfg = { \
.p_buttons = button_cfgs_##idx, \
.num_buttons = COMPONENT_GET_COUNT_BY_TYPE(idx, BUTTON_TYPE), \
.p_sliders = slider_cfgs_##idx, \
.num_sliders = COMPONENT_GET_COUNT_BY_TYPE(idx, SLIDER_TYPE), \
.p_wheels = wheel_cfgs_##idx, \
.num_wheels = COMPONENT_GET_COUNT_BY_TYPE(idx, WHEEL_TYPE), \
.on_freq = CONFIG_INPUT_RENESAS_RX_CTSU_ON_FREQ, \
.off_freq = CONFIG_INPUT_RENESAS_RX_CTSU_OFF_FREQ, \
.drift_freq = CONFIG_INPUT_RENESAS_RX_CTSU_DRIFT_FREQ, \
.cancel_freq = CONFIG_INPUT_RENESAS_RX_CTSU_CANCEL_FREQ, \
},
#else
#define CTSU_HAL_CONFIG_DEFINE(idx)
#endif /* !CONFIG_INPUT_RENESAS_RX_QE_TOUCH_CFG */
#define RENESAS_RX_CTSU_INIT(idx) \
PINCTRL_DT_INST_DEFINE(idx); \
static void ctsu_irq_config_func_##idx(void) \
{ \
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(idx, ctsuwr, irq), \
DT_INST_IRQ_BY_NAME(idx, ctsuwr, priority), ctsuwr_isr, \
DEVICE_DT_INST_GET(idx), 0); \
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(idx, ctsurd, irq), \
DT_INST_IRQ_BY_NAME(idx, ctsurd, priority), ctsurd_isr, \
DEVICE_DT_INST_GET(idx), 0); \
IRQ_CONNECT(DT_INST_IRQ_BY_NAME(idx, ctsufn, irq), \
DT_INST_IRQ_BY_NAME(idx, ctsufn, priority), ctsufn_isr, \
DEVICE_DT_INST_GET(idx), 0); \
irq_enable(DT_INST_IRQ_BY_NAME(idx, ctsuwr, irq)); \
irq_enable(DT_INST_IRQ_BY_NAME(idx, ctsurd, irq)); \
irq_enable(DT_INST_IRQ_BY_NAME(idx, ctsufn, irq)); \
} \
\
static touch_channel_cfg_t ctsu_channel_cfgs_##idx[] = { \
DT_INST_FOREACH_CHILD_STATUS_OKAY(idx, CTSU_CHANNEL_CFG_INIT)}; \
static uint8_t channels_index_map_##idx[DT_PROP(DT_DRV_INST(idx), max_num_sensors)]; \
\
static ctsu_element_cfg_t ctsu_element_cfgs_##idx[NUM_ELEMENTS(idx)]; \
\
static void sort_configs_by_channel_num##idx(void) \
{ \
memset(channels_index_map_##idx, 0xff, sizeof(channels_index_map_##idx)); \
for (int i = 0; i < NUM_ELEMENTS(idx); i++) { \
int min_idx = i; \
for (int j = i + 1; j < NUM_ELEMENTS(idx); j++) { \
if (ctsu_channel_cfgs_##idx[j].channel_num < \
ctsu_channel_cfgs_##idx[min_idx].channel_num) { \
min_idx = j; \
} \
} \
if (min_idx != i) { \
touch_channel_cfg_t tmp = ctsu_channel_cfgs_##idx[i]; \
ctsu_channel_cfgs_##idx[i] = ctsu_channel_cfgs_##idx[min_idx]; \
ctsu_channel_cfgs_##idx[min_idx] = tmp; \
} \
ctsu_element_cfgs_##idx[i] = ctsu_channel_cfgs_##idx[i].config; \
channels_index_map_##idx[ctsu_channel_cfgs_##idx[i].channel_num] = i; \
} \
} \
\
static touch_button_context_t buttons_##idx[] = { \
DT_INST_FOREACH_CHILD_STATUS_OKAY(idx, BUTTON_GET_CONTEXT)}; \
static touch_slider_context_t sliders_##idx[] = { \
DT_INST_FOREACH_CHILD_STATUS_OKAY(idx, SLIDER_GET_CONTEXT)}; \
static touch_wheel_context_t wheels_##idx[] = { \
DT_INST_FOREACH_CHILD_STATUS_OKAY(idx, WHEEL_GET_CONTEXT)}; \
\
static touch_button_cfg_t \
button_cfgs_##idx[COMPONENT_GET_COUNT_BY_TYPE(idx, BUTTON_TYPE)]; \
static touch_slider_cfg_t \
slider_cfgs_##idx[COMPONENT_GET_COUNT_BY_TYPE(idx, SLIDER_TYPE)]; \
static touch_wheel_cfg_t wheel_cfgs_##idx[COMPONENT_GET_COUNT_BY_TYPE(idx, WHEEL_TYPE)]; \
\
static uint8_t sliders_element_index[COMPONENT_GET_COUNT_BY_TYPE(idx, SLIDER_TYPE)] \
[DT_PROP(DT_DRV_INST(idx), max_num_sensors)]; \
static uint8_t wheels_element_index[COMPONENT_GET_COUNT_BY_TYPE(idx, WHEEL_TYPE)] \
[DT_PROP(DT_DRV_INST(idx), max_num_sensors)]; \
\
static uint8_t button_position_to_cfg_index##idx[COMPONENT_GET_COUNT_BY_TYPE( \
idx, BUTTON_TYPE)] = {0}; \
\
static void map_component_cfgs##idx(void) \
{ \
uint8_t temp[COMPONENT_GET_COUNT_BY_TYPE(idx, BUTTON_TYPE)]; \
for (int i = 0; i < COMPONENT_GET_COUNT_BY_TYPE(idx, BUTTON_TYPE); i++) { \
button_cfgs_##idx[i] = buttons_##idx[i].config; \
button_cfgs_##idx[i].elem_index = \
channels_index_map_##idx[buttons_##idx[i].element]; \
temp[i] = button_cfgs_##idx[i].elem_index; \
button_position_to_cfg_index##idx[i] = i; \
} \
for (int i = 0; i < COMPONENT_GET_COUNT_BY_TYPE(idx, BUTTON_TYPE) - 1; i++) { \
for (int j = i + 1; j < COMPONENT_GET_COUNT_BY_TYPE(idx, BUTTON_TYPE); \
j++) { \
if (temp[i] > temp[j]) { \
int tmp = temp[i]; \
temp[i] = temp[j]; \
temp[j] = tmp; \
tmp = button_position_to_cfg_index##idx[i]; \
button_position_to_cfg_index##idx[i] = \
button_position_to_cfg_index##idx[j]; \
button_position_to_cfg_index##idx[j] = tmp; \
} \
} \
} \
for (int i = 0; i < COMPONENT_GET_COUNT_BY_TYPE(idx, SLIDER_TYPE); i++) { \
slider_cfgs_##idx[i] = sliders_##idx[i].config; \
for (int j = 0; j < slider_cfgs_##idx[i].num_elements; j++) { \
sliders_element_index[i][j] = \
channels_index_map_##idx[sliders_##idx[i].p_elements[j]]; \
} \
slider_cfgs_##idx[i].p_elem_index = sliders_element_index[i]; \
} \
for (int i = 0; i < COMPONENT_GET_COUNT_BY_TYPE(idx, WHEEL_TYPE); i++) { \
wheel_cfgs_##idx[i] = wheels_##idx[i].config; \
for (int j = 0; j < wheel_cfgs_##idx[i].num_elements; j++) { \
wheels_element_index[i][j] = \
channels_index_map_##idx[wheels_##idx[i].p_elements[j]]; \
} \
wheel_cfgs_##idx[i].p_elem_index = wheels_element_index[i]; \
} \
} \
\
static const struct renesas_rx_ctsu_config renesas_rx_ctsu_config_##idx = { \
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(idx), \
.channel_cfgs = ctsu_channel_cfgs_##idx, \
.channels_index_map = channels_index_map_##idx, \
.button_position_index = button_position_to_cfg_index##idx, \
.buttons = buttons_##idx, \
.sliders = sliders_##idx, \
.wheels = wheels_##idx, \
}; \
\
static uint16_t slider_prev_position_##idx[COMPONENT_GET_COUNT_BY_TYPE(idx, SLIDER_TYPE)]; \
static uint16_t slider_curr_position_##idx[COMPONENT_GET_COUNT_BY_TYPE(idx, SLIDER_TYPE)]; \
static uint16_t prev_wheels_position_##idx[COMPONENT_GET_COUNT_BY_TYPE(idx, WHEEL_TYPE)]; \
static uint16_t curr_wheels_position_##idx[COMPONENT_GET_COUNT_BY_TYPE(idx, WHEEL_TYPE)]; \
\
static struct renesas_rx_ctsu_data renesas_rx_ctsu_data_##idx = { \
.prev_buttons_data = 0, \
.curr_buttons_data = 0, \
.prev_sliders_position = slider_prev_position_##idx, \
.curr_sliders_position = slider_curr_position_##idx, \
.prev_wheels_position = prev_wheels_position_##idx, \
.curr_wheels_position = curr_wheels_position_##idx, \
.work_phase = INITIALIZING, \
CTSU_HAL_CONFIG_DEFINE(idx)}; \
\
static int renesas_rx_ctsu_init_##idx(const struct device *dev) \
{ \
sort_configs_by_channel_num##idx(); \
map_component_cfgs##idx(); \
ctsu_irq_config_func_##idx(); \
return renesas_rx_ctsu_init(dev); \
} \
\
DEVICE_DT_INST_DEFINE(idx, &renesas_rx_ctsu_init_##idx, NULL, &renesas_rx_ctsu_data_##idx, \
&renesas_rx_ctsu_config_##idx, POST_KERNEL, \
CONFIG_INPUT_INIT_PRIORITY, NULL);
DT_INST_FOREACH_STATUS_OKAY(RENESAS_RX_CTSU_INIT)