| /* |
| * 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) |