|  | /* | 
|  | * Copyright (c) 2025 Renesas Electronics Corporation | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | #include <zephyr/kernel.h> | 
|  | #include <zephyr/drivers/pinctrl.h> | 
|  | #include <zephyr/drivers/gpio.h> | 
|  | #include <zephyr/irq.h> | 
|  | #include <zephyr/input/input.h> | 
|  | #include <zephyr/sys/math_extras.h> | 
|  | #include <zephyr/sys/mem_blocks.h> | 
|  | #include <soc.h> | 
|  |  | 
|  | #include <zephyr/drivers/clock_control/renesas_ra_cgc.h> | 
|  | #include <zephyr/input/input_renesas_ra_ctsu.h> | 
|  | #include <rm_touch.h> | 
|  |  | 
|  | #include <zephyr/logging/log.h> | 
|  | LOG_MODULE_REGISTER(renesas_ra_touch, CONFIG_INPUT_LOG_LEVEL); | 
|  |  | 
|  | struct renesas_ra_ctsu_cfg { | 
|  | const struct gpio_dt_spec tscap_pin; | 
|  | const struct pinctrl_dev_config *pcfg; | 
|  | const struct device *clock; | 
|  | const struct clock_control_ra_subsys_cfg clock_subsys; | 
|  | void (*irq_config)(void); | 
|  | }; | 
|  |  | 
|  | struct renesas_ra_ctsu_data { | 
|  | struct k_sem scanning; | 
|  | struct k_queue scan_q; | 
|  | struct k_thread thread_data; | 
|  |  | 
|  | K_KERNEL_STACK_MEMBER(thread_stack, CONFIG_INPUT_RENESAS_RA_CTSU_DRV_STACK_SIZE); | 
|  | }; | 
|  |  | 
|  | struct renesas_ra_ctsu_group_cfg { | 
|  | const struct device *ctsu_dev; | 
|  | size_t num_button; | 
|  | size_t num_slider; | 
|  | size_t num_wheel; | 
|  | }; | 
|  |  | 
|  | struct renesas_ra_ctsu_device_cb { | 
|  | const struct device *dev; | 
|  | void (*device_cb)(const struct device *dev, void *data); | 
|  | }; | 
|  |  | 
|  | struct renesas_ra_ctsu_group_data { | 
|  | const struct device *dev; | 
|  | /* FSP Touch data */ | 
|  | struct st_touch_instance touch_instance; | 
|  | #ifndef CONFIG_INPUT_RENESAS_RA_QE_TOUCH_CFG | 
|  | struct st_touch_instance_ctrl touch_ctrl; | 
|  | struct st_touch_cfg touch_cfg; | 
|  | /* FSP CTSU data */ | 
|  | struct st_ctsu_instance ctsu_instance; | 
|  | struct st_ctsu_instance_ctrl ctsu_ctrl; | 
|  | struct st_ctsu_cfg ctsu_cfg; | 
|  | #endif /* CONFIG_INPUT_RENESAS_RA_QE_TOUCH_CFG */ | 
|  | /* Touch driver private data */ | 
|  | struct k_work reading_work; | 
|  | struct k_timer sampling_timer; | 
|  | /* Touch driver sample result */ | 
|  | uint64_t *p_button_status; | 
|  | uint16_t *p_slider_position; | 
|  | uint16_t *p_wheel_position; | 
|  | /* Touch device callback data */ | 
|  | struct renesas_ra_ctsu_device_cb *p_button_cb; | 
|  | struct renesas_ra_ctsu_device_cb *p_slider_cb; | 
|  | struct renesas_ra_ctsu_device_cb *p_wheel_cb; | 
|  | }; | 
|  |  | 
|  | extern void ctsu_write_isr(void); | 
|  | extern void ctsu_read_isr(void); | 
|  | extern void ctsu_end_isr(void); | 
|  |  | 
|  | struct ctsu_device_cfg { | 
|  | const struct device *group_dev; | 
|  | uint16_t event_code; | 
|  | }; | 
|  |  | 
|  | struct ctsu_scan_msg { | 
|  | void *reserved; /* first word of queue data item reserved for the kernel */ | 
|  | struct st_touch_instance *p_instance; | 
|  | }; | 
|  |  | 
|  | SYS_MEM_BLOCKS_DEFINE_STATIC(scan_msg_allocator, sizeof(struct ctsu_scan_msg), | 
|  | CONFIG_INPUT_RENESAS_RA_CTSU_MSG_MEM_BLOCK_SIZE, sizeof(uint32_t)); | 
|  |  | 
|  | static void renesas_ra_callback_adapter(touch_callback_args_t *p_args) | 
|  | { | 
|  | const struct device *dev = p_args->p_context; | 
|  | const struct renesas_ra_ctsu_group_cfg *cfg = dev->config; | 
|  | const struct device *ctsu_dev = cfg->ctsu_dev; | 
|  | struct renesas_ra_ctsu_data *ctsu_data = ctsu_dev->data; | 
|  | struct renesas_ra_ctsu_group_data *data = dev->data; | 
|  |  | 
|  | if (p_args->event == CTSU_EVENT_SCAN_COMPLETE) { | 
|  | k_work_submit(&data->reading_work); | 
|  | } | 
|  |  | 
|  | k_sem_give(&ctsu_data->scanning); | 
|  | } | 
|  |  | 
|  | #define POLLING_INTERVAL_MS K_MSEC(CONFIG_INPUT_RENESAS_RA_CTSU_POLLING_INTERVAL_MS) | 
|  | #define STABILIZATION_US    K_USEC(CONFIG_INPUT_RENESAS_RA_CTSU_STABILIZATION_TIME_US) | 
|  |  | 
|  | static void renesas_ra_ctsu_drv_handler(void *arg0, void *arg1, void *arg2) | 
|  | { | 
|  | ARG_UNUSED(arg1); | 
|  | ARG_UNUSED(arg2); | 
|  | const struct device *ctsu_dev = arg0; | 
|  | struct renesas_ra_ctsu_data *ctsu_data = ctsu_dev->data; | 
|  |  | 
|  | while (true) { | 
|  | struct ctsu_scan_msg *msg = k_queue_get(&ctsu_data->scan_q, K_FOREVER); | 
|  | struct st_touch_instance *p_instance = msg->p_instance; | 
|  | fsp_err_t err; | 
|  |  | 
|  | k_sem_reset(&ctsu_data->scanning); | 
|  | err = p_instance->p_api->scanStart(p_instance->p_ctrl); | 
|  | if (err == FSP_SUCCESS) { | 
|  | k_sem_take(&ctsu_data->scanning, K_FOREVER); | 
|  | } | 
|  |  | 
|  | sys_mem_blocks_free(&scan_msg_allocator, 1, (void **)&msg); | 
|  |  | 
|  | k_sleep(STABILIZATION_US); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void renesas_ra_ctsu_group_sampling_handler(struct k_timer *timer) | 
|  | { | 
|  | struct renesas_ra_ctsu_group_data *data = | 
|  | CONTAINER_OF(timer, struct renesas_ra_ctsu_group_data, sampling_timer); | 
|  | const struct device *ctsu_dev = k_timer_user_data_get(timer); | 
|  | struct renesas_ra_ctsu_data *ctsu_data = ctsu_dev->data; | 
|  | struct ctsu_scan_msg *msg; | 
|  |  | 
|  | if (sys_mem_blocks_alloc(&scan_msg_allocator, 1, (void **)&msg) != 0) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | msg->p_instance = (void *)&data->touch_instance; | 
|  | k_queue_append(&ctsu_data->scan_q, msg); | 
|  | } | 
|  |  | 
|  | static void renesas_ra_ctsu_group_buttons_read(const struct device *dev) | 
|  | { | 
|  | #if !DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_ctsu_button) | 
|  | ARG_UNUSED(dev); | 
|  | #else | 
|  | const struct renesas_ra_ctsu_group_cfg *cfg = dev->config; | 
|  | struct renesas_ra_ctsu_group_data *data = dev->data; | 
|  |  | 
|  | if (cfg->num_button == 0) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (*data->p_button_status != 0) { | 
|  | uint64_t tmp_status = *data->p_button_status; | 
|  |  | 
|  | while (tmp_status != 0) { | 
|  | int num = u64_count_trailing_zeros(tmp_status); | 
|  | struct renesas_ra_ctsu_device_cb *p_button_cb = &data->p_button_cb[num]; | 
|  |  | 
|  | p_button_cb->device_cb(p_button_cb->dev, NULL); | 
|  | WRITE_BIT(tmp_status, num, 0); | 
|  | } | 
|  | } | 
|  | #endif /* DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_ctsu_button) */ | 
|  | } | 
|  |  | 
|  | static void renesas_ra_ctsu_group_sliders_read(const struct device *dev) | 
|  | { | 
|  | #if !DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_ctsu_slider) | 
|  | ARG_UNUSED(dev); | 
|  | #else | 
|  | const struct renesas_ra_ctsu_group_cfg *cfg = dev->config; | 
|  | struct renesas_ra_ctsu_group_data *data = dev->data; | 
|  |  | 
|  | if (cfg->num_slider == 0) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | for (int i = 0; i < cfg->num_slider; i++) { | 
|  | uint16_t slider_position = data->p_slider_position[i]; | 
|  |  | 
|  | if (slider_position != UINT16_MAX) { | 
|  | struct renesas_ra_ctsu_device_cb *p_slider_cb = &data->p_slider_cb[i]; | 
|  |  | 
|  | p_slider_cb->device_cb(p_slider_cb->dev, &slider_position); | 
|  | } | 
|  | } | 
|  | #endif /* DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_ctsu_slider) */ | 
|  | } | 
|  |  | 
|  | static void renesas_ra_ctsu_group_wheels_read(const struct device *dev) | 
|  | { | 
|  | #if !DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_ctsu_wheel) | 
|  | ARG_UNUSED(dev); | 
|  | #else | 
|  | const struct renesas_ra_ctsu_group_cfg *cfg = dev->config; | 
|  | struct renesas_ra_ctsu_group_data *data = dev->data; | 
|  |  | 
|  | if (cfg->num_wheel == 0) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | for (int i = 0; i < cfg->num_wheel; i++) { | 
|  | uint16_t wheel_position = data->p_wheel_position[i]; | 
|  |  | 
|  | if (wheel_position != UINT16_MAX) { | 
|  | struct renesas_ra_ctsu_device_cb *p_wheel_cb = &data->p_wheel_cb[i]; | 
|  |  | 
|  | p_wheel_cb->device_cb(p_wheel_cb->dev, &wheel_position); | 
|  | } | 
|  | } | 
|  | #endif /* DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_ctsu_wheel) */ | 
|  | } | 
|  |  | 
|  | static void renesas_ra_ctsu_group_reading_handler(struct k_work *work) | 
|  | { | 
|  | struct renesas_ra_ctsu_group_data *data = | 
|  | CONTAINER_OF(work, struct renesas_ra_ctsu_group_data, reading_work); | 
|  | const struct device *dev = data->dev; | 
|  | const struct st_touch_instance *p_instance = &data->touch_instance; | 
|  | fsp_err_t err; | 
|  |  | 
|  | err = p_instance->p_api->dataGet(p_instance->p_ctrl, data->p_button_status, | 
|  | data->p_slider_position, data->p_wheel_position); | 
|  | if (err != FSP_SUCCESS) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | renesas_ra_ctsu_group_buttons_read(dev); | 
|  | renesas_ra_ctsu_group_sliders_read(dev); | 
|  | renesas_ra_ctsu_group_wheels_read(dev); | 
|  | } | 
|  |  | 
|  | static int input_renesas_ra_ctsu_group_configure(const struct device *dev, | 
|  | const struct renesas_ra_ctsu_touch_cfg *cfg) | 
|  | { | 
|  | const struct st_touch_instance *p_instance = &cfg->touch_instance; | 
|  | const struct renesas_ra_ctsu_group_cfg *config = dev->config; | 
|  | struct renesas_ra_ctsu_group_data *data = dev->data; | 
|  | fsp_err_t err; | 
|  |  | 
|  | err = p_instance->p_api->open(p_instance->p_ctrl, p_instance->p_cfg); | 
|  | if (err != FSP_SUCCESS) { | 
|  | return -EIO; | 
|  | } | 
|  |  | 
|  | err = p_instance->p_api->callbackSet(p_instance->p_ctrl, renesas_ra_callback_adapter, | 
|  | (void *)dev, NULL); | 
|  | if (err != FSP_SUCCESS) { | 
|  | p_instance->p_api->close(p_instance->p_ctrl); | 
|  | return -EIO; | 
|  | } | 
|  |  | 
|  | #ifdef CONFIG_INPUT_RENESAS_RA_QE_TOUCH_CFG | 
|  | data->touch_instance = *p_instance; | 
|  | #endif /* CONFIG_INPUT_RENESAS_RA_QE_TOUCH_CFG */ | 
|  |  | 
|  | k_work_init(&data->reading_work, renesas_ra_ctsu_group_reading_handler); | 
|  | k_timer_init(&data->sampling_timer, renesas_ra_ctsu_group_sampling_handler, NULL); | 
|  | k_timer_user_data_set(&data->sampling_timer, (void *)config->ctsu_dev); | 
|  | k_timer_start(&data->sampling_timer, POLLING_INTERVAL_MS, POLLING_INTERVAL_MS); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int z_impl_renesas_ra_ctsu_group_configure(const struct device *dev, | 
|  | const struct renesas_ra_ctsu_touch_cfg *cfg) | 
|  | { | 
|  | #ifndef CONFIG_INPUT_RENESAS_RA_QE_TOUCH_CFG | 
|  | ARG_UNUSED(dev); | 
|  | ARG_UNUSED(cfg); | 
|  | return -ENOSYS; | 
|  | #else | 
|  | return input_renesas_ra_ctsu_group_configure(dev, cfg); | 
|  | #endif /* CONFIG_INPUT_RENESAS_RA_QE_TOUCH_CFG */ | 
|  | } | 
|  |  | 
|  | static int renesas_ra_ctsu_group_init(const struct device *dev) | 
|  | { | 
|  | const struct renesas_ra_ctsu_group_cfg *cfg = dev->config; | 
|  | #ifndef CONFIG_INPUT_RENESAS_RA_QE_TOUCH_CFG | 
|  | struct renesas_ra_ctsu_group_data *data = dev->data; | 
|  | const struct renesas_ra_ctsu_touch_cfg *touch_cfg = | 
|  | (const struct renesas_ra_ctsu_touch_cfg *)&data->touch_instance; | 
|  | #endif /* CONFIG_INPUT_RENESAS_RA_QE_TOUCH_CFG */ | 
|  |  | 
|  | if (!device_is_ready(cfg->ctsu_dev)) { | 
|  | return -ENODEV; | 
|  | } | 
|  |  | 
|  | #ifndef CONFIG_INPUT_RENESAS_RA_QE_TOUCH_CFG | 
|  | return input_renesas_ra_ctsu_group_configure(dev, touch_cfg); | 
|  | #else | 
|  | return 0; | 
|  | #endif /* CONFIG_INPUT_RENESAS_RA_QE_TOUCH_CFG */ | 
|  | } | 
|  |  | 
|  | static void renesas_ra_ctsu_write_isr(void *arg) | 
|  | { | 
|  | ARG_UNUSED(arg); | 
|  | ctsu_write_isr(); | 
|  | } | 
|  |  | 
|  | static void renesas_ra_ctsu_read_isr(void *arg) | 
|  | { | 
|  | ARG_UNUSED(arg); | 
|  | ctsu_read_isr(); | 
|  | } | 
|  |  | 
|  | static void renesas_ra_ctsu_end_isr(void *arg) | 
|  | { | 
|  | ARG_UNUSED(arg); | 
|  | ctsu_end_isr(); | 
|  | } | 
|  |  | 
|  | __maybe_unused static void ctsu_renesas_ra_button_cb(const struct device *dev, void *data) | 
|  | { | 
|  | ARG_UNUSED(data); | 
|  | const struct ctsu_device_cfg *cfg = dev->config; | 
|  |  | 
|  | input_report_key(dev, cfg->event_code, 0, false, K_NO_WAIT); | 
|  | } | 
|  |  | 
|  | __maybe_unused static void ctsu_renesas_ra_slider_cb(const struct device *dev, void *data) | 
|  | { | 
|  | const struct ctsu_device_cfg *cfg = dev->config; | 
|  | uint16_t *p_data = data; | 
|  |  | 
|  | if (p_data == NULL) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | input_report_abs(dev, cfg->event_code, *p_data, false, K_NO_WAIT); | 
|  | } | 
|  |  | 
|  | #define ctsu_renesas_ra_wheel_cb ctsu_renesas_ra_slider_cb | 
|  |  | 
|  | #define FOREACH_CHILD_CB(node_id, fn, compat)                                                      \ | 
|  | IF_ENABLED(DT_NODE_HAS_COMPAT(node_id, compat), (fn(node_id))) | 
|  |  | 
|  | #define FOREACH_CHILD(node_id, fn, compat)                                                         \ | 
|  | DT_FOREACH_CHILD_STATUS_OKAY_VARGS(node_id, FOREACH_CHILD_CB, fn, compat) | 
|  |  | 
|  | /* CTSU instance define */ | 
|  | #define DT_DRV_COMPAT renesas_ra_ctsu | 
|  |  | 
|  | /* CTSU group instance define */ | 
|  | #define CTSU_ELEMENT_CFG_GET_BY_IDX(idx, id)                                                       \ | 
|  | {                                                                                          \ | 
|  | .ssdiv = DT_ENUM_IDX_BY_IDX(id, ssdiv, idx),                                       \ | 
|  | .so = DT_PROP_BY_IDX(id, so, idx),                                                 \ | 
|  | .snum = DT_PROP_BY_IDX(id, snum, idx),                                             \ | 
|  | .sdpa = DT_PROP_BY_IDX(id, sdpa, idx),                                             \ | 
|  | } | 
|  |  | 
|  | #define RENESAS_RA_CTSU_ELEM_GET(idx, node_id) DT_PROP_BY_IDX(node_id, elements, idx) | 
|  |  | 
|  | #define CTSU_ELEM_IDX_DEFINE(node_id)                                                              \ | 
|  | static uint8_t CONCAT(DT_NODE_FULL_NAME_TOKEN(node_id), _elem_index)[] = {                 \ | 
|  | LISTIFY(DT_PROP_LEN(node_id, elements), RENESAS_RA_CTSU_ELEM_GET, (,), node_id)}; | 
|  |  | 
|  | #define CTSU_DEVICE_BUTTON_CALLBACK_DEFINE(node_id)                                                \ | 
|  | {                                                                                          \ | 
|  | .dev = DEVICE_DT_GET(node_id),                                                     \ | 
|  | .device_cb = ctsu_renesas_ra_button_cb,                                            \ | 
|  | }, | 
|  |  | 
|  | #define CTSU_DEVICE_SLIDER_CALLBACK_DEFINE(node_id)                                                \ | 
|  | {                                                                                          \ | 
|  | .dev = DEVICE_DT_GET(node_id),                                                     \ | 
|  | .device_cb = ctsu_renesas_ra_slider_cb,                                            \ | 
|  | }, | 
|  |  | 
|  | #define CTSU_DEVICE_WHEEL_CALLBACK_DEFINE(node_id)                                                 \ | 
|  | {                                                                                          \ | 
|  | .dev = DEVICE_DT_GET(node_id),                                                     \ | 
|  | .device_cb = ctsu_renesas_ra_wheel_cb,                                             \ | 
|  | }, | 
|  |  | 
|  | #define CTSU_BUTTON_DT_SPEC_GET(node_id)                                                           \ | 
|  | {                                                                                          \ | 
|  | .elem_index = DT_PROP(node_id, elements),                                          \ | 
|  | .threshold = DT_PROP(node_id, threshold),                                          \ | 
|  | .hysteresis = DT_PROP(node_id, hysteresis),                                        \ | 
|  | }, | 
|  |  | 
|  | #define CTSU_SLIDER_DT_SPEC_GET(node_id)                                                           \ | 
|  | {                                                                                          \ | 
|  | .p_elem_index = CONCAT(DT_NODE_FULL_NAME_TOKEN(node_id), _elem_index),             \ | 
|  | .num_elements = ARRAY_SIZE(CONCAT(DT_NODE_FULL_NAME_TOKEN(node_id), _elem_index)), \ | 
|  | .threshold = DT_PROP(node_id, threshold),                                          \ | 
|  | }, | 
|  |  | 
|  | #define CTSU_WHEEL_DT_SPEC_GET(node_id) CTSU_SLIDER_DT_SPEC_GET(node_id) | 
|  |  | 
|  | #define CTSU_GROUP_VAR_NAME(node_id, surfix)                                                       \ | 
|  | CONCAT(renesas_ra_ctsu_, DT_NODE_FULL_NAME_TOKEN(node_id), surfix) | 
|  |  | 
|  | #define CTSU_ELEMENTS_DEFINE(node_id)                                                              \ | 
|  | {LISTIFY(DT_PROP_LEN(node_id, ssdiv), CTSU_ELEMENT_CFG_GET_BY_IDX, (,), node_id)} | 
|  |  | 
|  | #ifndef CONFIG_INPUT_RENESAS_RA_QE_TOUCH_CFG | 
|  | #define RENESAS_RA_CTSU_GROUP_DEFINE(id)                                                           \ | 
|  | static const ctsu_element_cfg_t CTSU_GROUP_VAR_NAME(id, _elements_cfg)[] =                 \ | 
|  | CTSU_ELEMENTS_DEFINE(id);                                                          \ | 
|  | \ | 
|  | FOREACH_CHILD(id, CTSU_ELEM_IDX_DEFINE, renesas_ra_ctsu_slider);                           \ | 
|  | FOREACH_CHILD(id, CTSU_ELEM_IDX_DEFINE, renesas_ra_ctsu_wheel);                            \ | 
|  | \ | 
|  | static touch_button_cfg_t CTSU_GROUP_VAR_NAME(id, _button_cfg)[] = {                       \ | 
|  | FOREACH_CHILD(id, CTSU_BUTTON_DT_SPEC_GET, renesas_ra_ctsu_button)};               \ | 
|  | \ | 
|  | static touch_slider_cfg_t CTSU_GROUP_VAR_NAME(id, _slider_cfg)[] = {                       \ | 
|  | FOREACH_CHILD(id, CTSU_SLIDER_DT_SPEC_GET, renesas_ra_ctsu_slider)};               \ | 
|  | \ | 
|  | static touch_wheel_cfg_t CTSU_GROUP_VAR_NAME(id, _wheel_cfg)[] = {                         \ | 
|  | FOREACH_CHILD(id, CTSU_WHEEL_DT_SPEC_GET, renesas_ra_ctsu_wheel)};                 \ | 
|  | \ | 
|  | struct renesas_ra_ctsu_device_cb CTSU_GROUP_VAR_NAME(id, _button_cb)[] = {                 \ | 
|  | FOREACH_CHILD(id, CTSU_DEVICE_BUTTON_CALLBACK_DEFINE, renesas_ra_ctsu_button)};    \ | 
|  | struct renesas_ra_ctsu_device_cb CTSU_GROUP_VAR_NAME(id, _slider_cb)[] = {                 \ | 
|  | FOREACH_CHILD(id, CTSU_DEVICE_SLIDER_CALLBACK_DEFINE, renesas_ra_ctsu_slider)};    \ | 
|  | struct renesas_ra_ctsu_device_cb CTSU_GROUP_VAR_NAME(id, _wheel_cb)[] = {                  \ | 
|  | FOREACH_CHILD(id, CTSU_DEVICE_WHEEL_CALLBACK_DEFINE, renesas_ra_ctsu_wheel)};      \ | 
|  | \ | 
|  | struct renesas_ra_ctsu_group_cfg CONCAT(renesas_ra_ctsu_, DT_NODE_FULL_NAME_TOKEN(id),     \ | 
|  | _cfg) = {                                          \ | 
|  | .ctsu_dev = DEVICE_DT_GET(DT_PARENT(id)),                                          \ | 
|  | .num_button = ARRAY_SIZE(CTSU_GROUP_VAR_NAME(id, _button_cfg)),                    \ | 
|  | .num_slider = ARRAY_SIZE(CTSU_GROUP_VAR_NAME(id, _slider_cfg)),                    \ | 
|  | .num_wheel = ARRAY_SIZE(CTSU_GROUP_VAR_NAME(id, _wheel_cfg)),                      \ | 
|  | };                                                                                         \ | 
|  | \ | 
|  | static uint64_t CTSU_GROUP_VAR_NAME(id, _button_data);                                     \ | 
|  | static uint16_t CTSU_GROUP_VAR_NAME(                                                       \ | 
|  | id, _slider_data)[ARRAY_SIZE(CTSU_GROUP_VAR_NAME(id, _slider_cfg))];               \ | 
|  | static uint16_t CTSU_GROUP_VAR_NAME(                                                       \ | 
|  | id, _wheel_data)[ARRAY_SIZE(CTSU_GROUP_VAR_NAME(id, _wheel_cfg))];                 \ | 
|  | \ | 
|  | static struct renesas_ra_ctsu_group_data CTSU_GROUP_VAR_NAME(id, _data) = {                \ | 
|  | .dev = DEVICE_DT_GET(id),                                                          \ | 
|  | .touch_instance =                                                                  \ | 
|  | {                                                                          \ | 
|  | .p_ctrl = &CTSU_GROUP_VAR_NAME(id, _data).touch_ctrl,              \ | 
|  | .p_cfg = &CTSU_GROUP_VAR_NAME(id, _data).touch_cfg,                \ | 
|  | .p_api = &g_touch_on_ctsu,                                         \ | 
|  | },                                                                         \ | 
|  | .ctsu_instance =                                                                   \ | 
|  | {                                                                          \ | 
|  | .p_ctrl = &CTSU_GROUP_VAR_NAME(id, _data).ctsu_ctrl,               \ | 
|  | .p_cfg = &CTSU_GROUP_VAR_NAME(id, _data).ctsu_cfg,                 \ | 
|  | .p_api = &g_ctsu_on_ctsu,                                          \ | 
|  | },                                                                         \ | 
|  | .touch_cfg =                                                                       \ | 
|  | {                                                                          \ | 
|  | .on_freq = DT_PROP(id, on_freq),                                   \ | 
|  | .off_freq = DT_PROP(id, off_freq),                                 \ | 
|  | .drift_freq = DT_PROP(id, drift_freq),                             \ | 
|  | .cancel_freq = DT_PROP(id, cancel_freq),                           \ | 
|  | .p_ctsu_instance = &CTSU_GROUP_VAR_NAME(id, _data).ctsu_instance,  \ | 
|  | .p_buttons = CTSU_GROUP_VAR_NAME(id, _button_cfg),                 \ | 
|  | .p_sliders = CTSU_GROUP_VAR_NAME(id, _slider_cfg),                 \ | 
|  | .p_wheels = CTSU_GROUP_VAR_NAME(id, _wheel_cfg),                   \ | 
|  | .num_sliders = ARRAY_SIZE(CTSU_GROUP_VAR_NAME(id, _slider_cfg)),   \ | 
|  | .num_wheels = ARRAY_SIZE(CTSU_GROUP_VAR_NAME(id, _wheel_cfg)),     \ | 
|  | .num_buttons = ARRAY_SIZE(CTSU_GROUP_VAR_NAME(id, _button_cfg)),   \ | 
|  | },                                                                         \ | 
|  | .ctsu_cfg =                                                                        \ | 
|  | {                                                                          \ | 
|  | .cap = CTSU_CAP_SOFTWARE,                                          \ | 
|  | .txvsel = DT_ENUM_IDX(DT_PARENT(id), pwr_supply_sel),              \ | 
|  | .txvsel2 = DT_ENUM_IDX(DT_PARENT(id), pwr_supply_sel2),            \ | 
|  | .atune1 = DT_ENUM_IDX(DT_PARENT(id), atune1),                      \ | 
|  | .atune12 = DT_ENUM_IDX(DT_PARENT(id), atune12),                    \ | 
|  | .md = CONCAT(CTSU_MODE_,                                           \ | 
|  | DT_STRING_UPPER_TOKEN(DT_PARENT(id), measure_mode)),  \ | 
|  | .posel = DT_ENUM_IDX(DT_PARENT(id), po_sel),                       \ | 
|  | .ctsuchac0 = DT_PROP_BY_IDX(id, ctsuchac, 0),                      \ | 
|  | .ctsuchac1 = DT_PROP_BY_IDX(id, ctsuchac, 1),                      \ | 
|  | .ctsuchac2 = DT_PROP_BY_IDX(id, ctsuchac, 2),                      \ | 
|  | .ctsuchac3 = DT_PROP_BY_IDX(id, ctsuchac, 3),                      \ | 
|  | .ctsuchac4 = DT_PROP_BY_IDX(id, ctsuchac, 4),                      \ | 
|  | .ctsuchtrc0 = DT_PROP_BY_IDX(id, ctsuchtrc, 0),                    \ | 
|  | .ctsuchtrc1 = DT_PROP_BY_IDX(id, ctsuchtrc, 1),                    \ | 
|  | .ctsuchtrc2 = DT_PROP_BY_IDX(id, ctsuchtrc, 2),                    \ | 
|  | .ctsuchtrc3 = DT_PROP_BY_IDX(id, ctsuchtrc, 3),                    \ | 
|  | .ctsuchtrc4 = DT_PROP_BY_IDX(id, ctsuchtrc, 4),                    \ | 
|  | .num_rx = DT_PROP(id, rx_count),                                   \ | 
|  | .num_tx = DT_PROP(id, tx_count),                                   \ | 
|  | .num_moving_average = DT_PROP(id, num_moving_avg),                 \ | 
|  | .p_elements = CTSU_GROUP_VAR_NAME(id, _elements_cfg),              \ | 
|  | .write_irq = DT_IRQ_BY_NAME(DT_PARENT(id), ctsuwr, irq),           \ | 
|  | .read_irq = DT_IRQ_BY_NAME(DT_PARENT(id), ctsurd, irq),            \ | 
|  | .end_irq = DT_IRQ_BY_NAME(DT_PARENT(id), ctsufn, irq),             \ | 
|  | },                                                                         \ | 
|  | .p_button_status = &CTSU_GROUP_VAR_NAME(id, _button_data),                         \ | 
|  | .p_slider_position = CTSU_GROUP_VAR_NAME(id, _slider_data),                        \ | 
|  | .p_wheel_position = CTSU_GROUP_VAR_NAME(id, _wheel_data),                          \ | 
|  | .p_button_cb = CTSU_GROUP_VAR_NAME(id, _button_cb),                                \ | 
|  | .p_slider_cb = CTSU_GROUP_VAR_NAME(id, _slider_cb),                                \ | 
|  | .p_wheel_cb = CTSU_GROUP_VAR_NAME(id, _wheel_cb),                                  \ | 
|  | };                                                                                         \ | 
|  | \ | 
|  | DEVICE_DT_DEFINE(id, renesas_ra_ctsu_group_init, NULL, &CTSU_GROUP_VAR_NAME(id, _data),    \ | 
|  | &CTSU_GROUP_VAR_NAME(id, _cfg), POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY,  \ | 
|  | NULL); | 
|  | #else | 
|  | #define RENESAS_RA_CTSU_GROUP_DEFINE(id)                                                           \ | 
|  | struct renesas_ra_ctsu_device_cb CTSU_GROUP_VAR_NAME(id, _button_cb)[] = {                 \ | 
|  | FOREACH_CHILD(id, CTSU_DEVICE_BUTTON_CALLBACK_DEFINE, renesas_ra_ctsu_button)};    \ | 
|  | struct renesas_ra_ctsu_device_cb CTSU_GROUP_VAR_NAME(id, _slider_cb)[] = {                 \ | 
|  | FOREACH_CHILD(id, CTSU_DEVICE_SLIDER_CALLBACK_DEFINE, renesas_ra_ctsu_slider)};    \ | 
|  | struct renesas_ra_ctsu_device_cb CTSU_GROUP_VAR_NAME(id, _wheel_cb)[] = {                  \ | 
|  | FOREACH_CHILD(id, CTSU_DEVICE_WHEEL_CALLBACK_DEFINE, renesas_ra_ctsu_wheel)};      \ | 
|  | \ | 
|  | struct renesas_ra_ctsu_group_cfg CTSU_GROUP_VAR_NAME(id, _cfg) = {                         \ | 
|  | .ctsu_dev = DEVICE_DT_GET(DT_PARENT(id)),                                          \ | 
|  | .num_button = ARRAY_SIZE(CTSU_GROUP_VAR_NAME(id, _button_cb)),                     \ | 
|  | .num_slider = ARRAY_SIZE(CTSU_GROUP_VAR_NAME(id, _slider_cb)),                     \ | 
|  | .num_wheel = ARRAY_SIZE(CTSU_GROUP_VAR_NAME(id, _wheel_cb)),                       \ | 
|  | };                                                                                         \ | 
|  | \ | 
|  | static uint64_t CTSU_GROUP_VAR_NAME(id, _button_data);                                     \ | 
|  | static uint16_t CTSU_GROUP_VAR_NAME(                                                       \ | 
|  | id, _slider_data)[ARRAY_SIZE(CTSU_GROUP_VAR_NAME(id, _slider_cb))];                \ | 
|  | static uint16_t CTSU_GROUP_VAR_NAME(                                                       \ | 
|  | id, _wheel_data)[ARRAY_SIZE(CTSU_GROUP_VAR_NAME(id, _wheel_cb))];                  \ | 
|  | \ | 
|  | static struct renesas_ra_ctsu_group_data CTSU_GROUP_VAR_NAME(id, _data) = {                \ | 
|  | .dev = DEVICE_DT_GET(id),                                                          \ | 
|  | .p_button_status = &CTSU_GROUP_VAR_NAME(id, _button_data),                         \ | 
|  | .p_slider_position = CTSU_GROUP_VAR_NAME(id, _slider_data),                        \ | 
|  | .p_wheel_position = CTSU_GROUP_VAR_NAME(id, _wheel_data),                          \ | 
|  | .p_button_cb = CTSU_GROUP_VAR_NAME(id, _button_cb),                                \ | 
|  | .p_slider_cb = CTSU_GROUP_VAR_NAME(id, _slider_cb),                                \ | 
|  | .p_wheel_cb = CTSU_GROUP_VAR_NAME(id, _wheel_cb),                                  \ | 
|  | };                                                                                         \ | 
|  | \ | 
|  | DEVICE_DT_DEFINE(id, renesas_ra_ctsu_group_init, NULL, &CTSU_GROUP_VAR_NAME(id, _data),    \ | 
|  | &CTSU_GROUP_VAR_NAME(id, _cfg), POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY,  \ | 
|  | NULL); | 
|  | #endif | 
|  |  | 
|  | static int renesas_ra_ctsu_init(const struct device *dev) | 
|  | { | 
|  | const struct renesas_ra_ctsu_cfg *ctsu_cfg = dev->config; | 
|  | struct renesas_ra_ctsu_data *data = dev->data; | 
|  | k_tid_t tid; | 
|  | int ret; | 
|  |  | 
|  | if (!device_is_ready(ctsu_cfg->clock)) { | 
|  | return -ENODEV; | 
|  | } | 
|  |  | 
|  | /* Perform discharge process for the TSCAP pin */ | 
|  | ret = gpio_pin_configure_dt(&ctsu_cfg->tscap_pin, GPIO_OUTPUT_LOW); | 
|  | if (ret != 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* Wait 10 usec for discharge to complete before switching to the CTSU pin function */ | 
|  | k_busy_wait(10); | 
|  |  | 
|  | ret = pinctrl_apply_state(ctsu_cfg->pcfg, PINCTRL_STATE_DEFAULT); | 
|  | if (ret != 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | ret = clock_control_on(ctsu_cfg->clock, (clock_control_subsys_t)&ctsu_cfg->clock_subsys); | 
|  | if (ret != 0) { | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | k_sem_init(&data->scanning, 0, 1); | 
|  | k_queue_init(&data->scan_q); | 
|  |  | 
|  | tid = k_thread_create( | 
|  | &data->thread_data, data->thread_stack, K_THREAD_STACK_SIZEOF(data->thread_stack), | 
|  | renesas_ra_ctsu_drv_handler, (void *)dev, NULL, NULL, | 
|  | K_PRIO_COOP(CONFIG_INPUT_RENESAS_RA_CTSU_DRV_PRIORITY), K_ESSENTIAL, K_NO_WAIT); | 
|  | if (tid == NULL) { | 
|  | LOG_ERR("thread creation failed"); | 
|  | return -ENODEV; | 
|  | } | 
|  |  | 
|  | k_thread_name_set(&data->thread_data, dev->name); | 
|  |  | 
|  | ctsu_cfg->irq_config(); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #define RENESAS_RA_CTSU_DEFINE(inst)                                                               \ | 
|  | PINCTRL_DT_INST_DEFINE(inst);                                                              \ | 
|  | \ | 
|  | static void renesas_ra_ctsu_irq_config##inst(void)                                         \ | 
|  | {                                                                                          \ | 
|  | IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, ctsuwr, irq),                                \ | 
|  | DT_INST_IRQ_BY_NAME(inst, ctsuwr, priority),                           \ | 
|  | renesas_ra_ctsu_write_isr, NULL, 0);                                   \ | 
|  | IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, ctsurd, irq),                                \ | 
|  | DT_INST_IRQ_BY_NAME(inst, ctsurd, priority), renesas_ra_ctsu_read_isr, \ | 
|  | NULL, 0);                                                              \ | 
|  | IRQ_CONNECT(DT_INST_IRQ_BY_NAME(inst, ctsufn, irq),                                \ | 
|  | DT_INST_IRQ_BY_NAME(inst, ctsufn, priority), renesas_ra_ctsu_end_isr,  \ | 
|  | NULL, 0);                                                              \ | 
|  | \ | 
|  | R_ICU->IELSR[DT_INST_IRQ_BY_NAME(inst, ctsuwr, irq)] =                             \ | 
|  | BSP_PRV_IELS_ENUM(EVENT_CTSU_WRITE);                                       \ | 
|  | R_ICU->IELSR[DT_INST_IRQ_BY_NAME(inst, ctsurd, irq)] =                             \ | 
|  | BSP_PRV_IELS_ENUM(EVENT_CTSU_READ);                                        \ | 
|  | R_ICU->IELSR[DT_INST_IRQ_BY_NAME(inst, ctsufn, irq)] =                             \ | 
|  | BSP_PRV_IELS_ENUM(EVENT_CTSU_END);                                         \ | 
|  | \ | 
|  | irq_enable(DT_INST_IRQ_BY_NAME(inst, ctsuwr, irq));                                \ | 
|  | irq_enable(DT_INST_IRQ_BY_NAME(inst, ctsurd, irq));                                \ | 
|  | irq_enable(DT_INST_IRQ_BY_NAME(inst, ctsufn, irq));                                \ | 
|  | }                                                                                          \ | 
|  | \ | 
|  | static const struct renesas_ra_ctsu_cfg renesas_ra_ctsu_cfg##inst = {                      \ | 
|  | .tscap_pin = GPIO_DT_SPEC_INST_GET(inst, tscap_gpios),                             \ | 
|  | .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst),                                      \ | 
|  | .clock = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)),                                 \ | 
|  | .clock_subsys =                                                                    \ | 
|  | {                                                                          \ | 
|  | .mstp = DT_INST_CLOCKS_CELL(inst, mstp),                           \ | 
|  | .stop_bit = DT_INST_CLOCKS_CELL(inst, stop_bit),                   \ | 
|  | },                                                                         \ | 
|  | .irq_config = renesas_ra_ctsu_irq_config##inst,                                    \ | 
|  | };                                                                                         \ | 
|  | \ | 
|  | static struct renesas_ra_ctsu_data renesas_ra_ctsu_data##inst;                             \ | 
|  | \ | 
|  | DEVICE_DT_INST_DEFINE(inst, renesas_ra_ctsu_init, NULL, &renesas_ra_ctsu_data##inst,       \ | 
|  | &renesas_ra_ctsu_cfg##inst, POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \ | 
|  | NULL);                                                               \ | 
|  | \ | 
|  | DT_INST_FOREACH_CHILD_STATUS_OKAY(inst, RENESAS_RA_CTSU_GROUP_DEFINE) | 
|  |  | 
|  | DT_INST_FOREACH_STATUS_OKAY(RENESAS_RA_CTSU_DEFINE) | 
|  |  | 
|  | static int ctsu_device_init(const struct device *dev) | 
|  | { | 
|  | const struct ctsu_device_cfg *cfg = dev->config; | 
|  |  | 
|  | return device_is_ready(cfg->group_dev) ? 0 : -ENODEV; | 
|  | } | 
|  |  | 
|  | #undef DT_DRV_COMPAT | 
|  | #define DT_DRV_COMPAT renesas_ra_ctsu_button | 
|  |  | 
|  | #define RENESAS_RA_CTSU_BUTTON_DEFINE(inst)                                                        \ | 
|  | IF_ENABLED(DT_NODE_HAS_STATUS_OKAY(DT_INST_PARENT(inst)), (                                \ | 
|  | const struct ctsu_device_cfg ctsu_button_cfg##inst = {                             \ | 
|  | .group_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)),                          \ | 
|  | .event_code = DT_INST_PROP(inst, event_code),                              \ | 
|  | };                                                                                 \ | 
|  | \ | 
|  | DEVICE_DT_INST_DEFINE(inst, ctsu_device_init, NULL, NULL, &ctsu_button_cfg##inst,  \ | 
|  | POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL);                    \ | 
|  | )) | 
|  |  | 
|  | DT_INST_FOREACH_STATUS_OKAY(RENESAS_RA_CTSU_BUTTON_DEFINE) | 
|  |  | 
|  | #undef DT_DRV_COMPAT | 
|  | #define DT_DRV_COMPAT renesas_ra_ctsu_slider | 
|  |  | 
|  | #define RENESAS_RA_CTSU_SLIDER_DEFINE(inst)                                                        \ | 
|  | IF_ENABLED(DT_NODE_HAS_STATUS_OKAY(DT_INST_PARENT(inst)), (                                \ | 
|  | const struct ctsu_device_cfg ctsu_slider_cfg##inst = {                             \ | 
|  | .group_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)),                          \ | 
|  | .event_code = DT_INST_PROP(inst, event_code),                              \ | 
|  | };                                                                                 \ | 
|  | \ | 
|  | DEVICE_DT_INST_DEFINE(inst, ctsu_device_init, NULL, NULL, &ctsu_slider_cfg##inst,  \ | 
|  | POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL);                    \ | 
|  | )) | 
|  |  | 
|  | DT_INST_FOREACH_STATUS_OKAY(RENESAS_RA_CTSU_SLIDER_DEFINE) | 
|  |  | 
|  | #undef DT_DRV_COMPAT | 
|  | #define DT_DRV_COMPAT renesas_ra_ctsu_wheel | 
|  |  | 
|  | #define RENESAS_RA_CTSU_WHEEL_DEFINE(inst)                                                         \ | 
|  | IF_ENABLED(DT_NODE_HAS_STATUS_OKAY(DT_INST_PARENT(inst)), (                                \ | 
|  | const struct ctsu_device_cfg ctsu_wheel_cfg##inst = {                              \ | 
|  | .group_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)),                          \ | 
|  | .event_code = DT_INST_PROP(inst, event_code),                              \ | 
|  | };                                                                                 \ | 
|  | \ | 
|  | DEVICE_DT_INST_DEFINE(inst, ctsu_device_init, NULL, NULL, &ctsu_wheel_cfg##inst,   \ | 
|  | POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL);                    \ | 
|  | )) | 
|  |  | 
|  | DT_INST_FOREACH_STATUS_OKAY(RENESAS_RA_CTSU_WHEEL_DEFINE) |