diff --git a/boards/renesas/ek_ra2a1/Kconfig.defconfig b/boards/renesas/ek_ra2a1/Kconfig.defconfig new file mode 100644 index 000000000000..842902a62b95 --- /dev/null +++ b/boards/renesas/ek_ra2a1/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +if !INPUT_RENESAS_RA_QE_TOUCH_CFG + +config INPUT_RENESAS_RA_CTSU_NUM_SELF_ELEMENTS + default 1 + +endif # INPUT_RENESAS_RA_QE_TOUCH_CFG diff --git a/boards/renesas/ek_ra2a1/ek_ra2a1-pinctrl.dtsi b/boards/renesas/ek_ra2a1/ek_ra2a1-pinctrl.dtsi index 690f5736c759..79fe97458138 100644 --- a/boards/renesas/ek_ra2a1/ek_ra2a1-pinctrl.dtsi +++ b/boards/renesas/ek_ra2a1/ek_ra2a1-pinctrl.dtsi @@ -51,4 +51,12 @@ renesas,analog-enable; }; }; + + ctsu_default: ctsu_default { + group1 { + /* TS01 TSCAP */ + psels = , + ; + }; + }; }; diff --git a/boards/renesas/ek_ra2a1/ek_ra2a1.dts b/boards/renesas/ek_ra2a1/ek_ra2a1.dts index 39d5d372cd96..6004c429c1e7 100644 --- a/boards/renesas/ek_ra2a1/ek_ra2a1.dts +++ b/boards/renesas/ek_ra2a1/ek_ra2a1.dts @@ -83,6 +83,10 @@ status = "okay"; }; +&ioport4 { + status = "okay"; +}; + &port_irq6 { interrupts = <29 3>; status = "okay"; @@ -120,3 +124,40 @@ &wdt { status = "okay"; }; + +&ctsu { + pinctrl-0 = <&ctsu_default>; + pinctrl-names = "default"; + interrupts = <10 3>, <11 3>, <12 3>; + interrupt-names = "ctsuwr", "ctsurd", "ctsufn"; + clock-div = <1>; + pwr-supply-sel = "vcc"; + atune1 = "normal"; + measure-mode = "self-multi-scan"; + tscap-gpios = <&ioport4 9 0>; + status = "okay"; + + group1 { + ctsuchac = <0x00>, <0x80>, <0x00>, <0x00>, <0x00>; + ctsuchtrc = <0x00>, <0x00>, <0x00>, <0x00>, <0x00>; + rx-count = <1>; + tx-count = <0>; + ssdiv = "1.00"; + so = <0x108>; + snum = <0x01>; + sdpa = <0x0B>; + on-freq = <3>; + off-freq = <3>; + drift-freq = <255>; + cancel-freq = <0>; + num-moving-avg = <4>; + + ts1: button1 { + compatible = "renesas,ra-ctsu-button"; + event-code = ; + elements = <0>; + threshold = <2305>; + hysteresis = <115>; + }; + }; +}; diff --git a/drivers/input/CMakeLists.txt b/drivers/input/CMakeLists.txt index 054c04ff60cd..832d08465555 100644 --- a/drivers/input/CMakeLists.txt +++ b/drivers/input/CMakeLists.txt @@ -31,6 +31,7 @@ zephyr_library_sources_ifdef(CONFIG_INPUT_PAW32XX input_paw32xx.c) zephyr_library_sources_ifdef(CONFIG_INPUT_PINNACLE input_pinnacle.c) zephyr_library_sources_ifdef(CONFIG_INPUT_PMW3610 input_pmw3610.c) zephyr_library_sources_ifdef(CONFIG_INPUT_REALTEK_RTS5912_KBD input_realtek_rts5912_kbd.c) +zephyr_library_sources_ifdef(CONFIG_INPUT_RENESAS_RA_CTSU input_renesas_ra_ctsu.c) zephyr_library_sources_ifdef(CONFIG_INPUT_SBUS input_sbus.c) zephyr_library_sources_ifdef(CONFIG_INPUT_STM32_TSC_KEYS input_tsc_keys.c) zephyr_library_sources_ifdef(CONFIG_INPUT_STMPE811 input_stmpe811.c) diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index b8dc0890b567..785f11a76ff2 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -32,6 +32,7 @@ source "drivers/input/Kconfig.pat912x" source "drivers/input/Kconfig.paw32xx" source "drivers/input/Kconfig.pinnacle" source "drivers/input/Kconfig.pmw3610" +source "drivers/input/Kconfig.renesas_ra" source "drivers/input/Kconfig.rts5912" source "drivers/input/Kconfig.sbus" source "drivers/input/Kconfig.sdl" diff --git a/drivers/input/Kconfig.renesas_ra b/drivers/input/Kconfig.renesas_ra new file mode 100644 index 000000000000..f6459fc3db57 --- /dev/null +++ b/drivers/input/Kconfig.renesas_ra @@ -0,0 +1,96 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config INPUT_RENESAS_RA_CTSU + bool "Renesas RA Capacitive Touch driver" + default y + depends on DT_HAS_RENESAS_RA_CTSU_ENABLED + select USE_RA_FSP_CTSU + select USE_RA_FSP_TOUCH + select SYS_MEM_BLOCKS + select GPIO + select PINCTRL + help + Enable Renesas RA Touch Sensing driver. + +if INPUT_RENESAS_RA_CTSU + +config INPUT_RENESAS_RA_DEVICE_VCC + int "SoC VCC input in minivolt" + default 3300 + help + SoC VCC input in milivolt. + +config INPUT_RENESAS_RA_QE_TOUCH_CFG + bool "Using QE Touch Workflow to config this driver" + help + If this config was enabled, setting for CTSU and Cap + Touch driver will be reflected the setting that generated + from QE Touch Workflow. + Please add the generated C source files into the app CMakeLists + to make the driver can using it. + +if !INPUT_RENESAS_RA_QE_TOUCH_CFG + +config INPUT_RENESAS_RA_CTSU_NUM_SELF_ELEMENTS + int "Number of self-capacitance elements" + default 0 + help + Number of self-capacitance elements in the CTSU. + +config INPUT_RENESAS_RA_CTSU_NUM_MUTUAL_ELEMENTS + int "Number of mutual-capacitance elements" + default 0 + help + Number of mutual-capacitance elements in the CTSU. + +choice INPUT_RENESAS_RA_CTSU_CHATTERING_SUPPRESSION_TYPE + prompt "Type of chattering suppression" + default INPUT_RENESAS_RA_CTSU_CHATTERING_SUPPRESSION_TYPE_A + +config INPUT_RENESAS_RA_CTSU_CHATTERING_SUPPRESSION_TYPE_A + bool "Counter of exceed threshold is hold within hysteresis range" + help + Counter of exceed threshold is hold within hysteresis range. + +config INPUT_RENESAS_RA_CTSU_CHATTERING_SUPPRESSION_TYPE_B + bool "Counter of exceed threshold is reset within hysteresis range" + help + Counter of exceed threshold is reset within hysteresis range. + +endchoice # INPUT_RENESAS_RA_CTSU_CHATTERING_SUPPRESSION_TYPE + +endif # !INPUT_RENESAS_RA_QE_TOUCH_CFG + +config INPUT_RENESAS_RA_CTSU_POLLING_INTERVAL_MS + int "CTSU debounce interval time" + range 20 500 + default 100 + help + Debouncing interval time in milliseconds. + +config INPUT_RENESAS_RA_CTSU_STABILIZATION_TIME_US + int "CTSU stabilization time" + default 20 + help + Stabilization time required to wait between 2 scans. + +config INPUT_RENESAS_RA_CTSU_DRV_STACK_SIZE + int "CTSU internal thread stack size" + default 512 + help + CTSU driver internal thread stack size. + +config INPUT_RENESAS_RA_CTSU_DRV_PRIORITY + int "CTSU internal thread priority" + default 8 + help + CTSU driver internal thread priority. + +config INPUT_RENESAS_RA_CTSU_MSG_MEM_BLOCK_SIZE + int "CTSU internal sys_mem_blocks allocator size" + default 10 + help + CTSU driver internal sys_mem_blocks allocator maximum num blocks. + +endif # INPUT_RENESAS_RA_CTSU diff --git a/drivers/input/input_renesas_ra_ctsu.c b/drivers/input/input_renesas_ra_ctsu.c new file mode 100644 index 000000000000..f6f4ce663491 --- /dev/null +++ b/drivers/input/input_renesas_ra_ctsu.c @@ -0,0 +1,704 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +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_MS 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 = (const struct device *)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_MS); + } +} + +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); +} + +#if DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_ctsu_button) +static void renesas_ra_ctsu_group_buttons_read(const struct device *dev) +{ + 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) */ + +#if DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_ctsu_slider) +static void renesas_ra_ctsu_group_sliders_read(const struct device *dev) +{ + 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) */ + +#if DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_ctsu_wheel) +static void renesas_ra_ctsu_group_wheels_read(const struct device *dev) +{ + 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; + } + + IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_ctsu_button), + (renesas_ra_ctsu_group_buttons_read(dev);)) + + IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_ctsu_slider), + (renesas_ra_ctsu_group_sliders_read(dev);)) + + IF_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_ctsu_wheel), + (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) diff --git a/dts/arm/renesas/ra/ra2/r7fa2a1xh.dtsi b/dts/arm/renesas/ra/ra2/r7fa2a1xh.dtsi index 053bc9ac165d..2ae3d89839de 100644 --- a/dts/arm/renesas/ra/ra2/r7fa2a1xh.dtsi +++ b/dts/arm/renesas/ra/ra2/r7fa2a1xh.dtsi @@ -100,6 +100,14 @@ clocks = <&pclkb 0 0>; status = "disabled"; }; + + ctsu: ctsua@40081000 { + compatible = "renesas,ra-ctsu"; + reg = <0x40081000 0x24>; + clocks = <&pclkb MSTPC 3>; + variant = "ctsua"; + status = "disabled"; + }; }; clocks: clocks { diff --git a/dts/arm/renesas/ra/ra2/ra2l1.dtsi b/dts/arm/renesas/ra/ra2/ra2l1.dtsi index 23bb39e78524..d484f7ec2536 100644 --- a/dts/arm/renesas/ra/ra2/ra2l1.dtsi +++ b/dts/arm/renesas/ra/ra2/ra2l1.dtsi @@ -515,6 +515,14 @@ #port-irq-cells = <0>; status = "disabled"; }; + + ctsu: ctsu2@40082000 { + compatible = "renesas,ra-ctsu"; + reg = <0x40082000 0x70>; + clocks = <&pclkb MSTPC 3>; + variant = "ctsu2"; + status = "disabled"; + }; }; clocks: clocks { diff --git a/dts/arm/renesas/ra/ra4/r7fa4m2ax.dtsi b/dts/arm/renesas/ra/ra4/r7fa4m2ax.dtsi index 8a155a1f6e8f..98baf88cca8e 100644 --- a/dts/arm/renesas/ra/ra4/r7fa4m2ax.dtsi +++ b/dts/arm/renesas/ra/ra4/r7fa4m2ax.dtsi @@ -144,6 +144,14 @@ compatible = "renesas,ra-sce9-rng"; status = "disabled"; }; + + ctsu: ctsua@40081000 { + compatible = "renesas,ra-ctsu"; + reg = <0x40081000 0x24>; + clocks = <&pclkb MSTPC 3>; + variant = "ctsua"; + status = "disabled"; + }; }; clocks: clocks { diff --git a/dts/arm/renesas/ra/ra4/r7fa4m3ax.dtsi b/dts/arm/renesas/ra/ra4/r7fa4m3ax.dtsi index a34f041f1a41..3031ef7396e3 100644 --- a/dts/arm/renesas/ra/ra4/r7fa4m3ax.dtsi +++ b/dts/arm/renesas/ra/ra4/r7fa4m3ax.dtsi @@ -157,6 +157,14 @@ compatible = "renesas,ra-sce9-rng"; status = "disabled"; }; + + ctsu: ctsua@40081000 { + compatible = "renesas,ra-ctsu"; + reg = <0x40081000 0x24>; + clocks = <&pclkb MSTPC 3>; + variant = "ctsua"; + status = "disabled"; + }; }; clocks: clocks { diff --git a/dts/arm/renesas/ra/ra4/ra4-cm4-common.dtsi b/dts/arm/renesas/ra/ra4/ra4-cm4-common.dtsi index 7319a75f79f6..d6604128f23a 100644 --- a/dts/arm/renesas/ra/ra4/ra4-cm4-common.dtsi +++ b/dts/arm/renesas/ra/ra4/ra4-cm4-common.dtsi @@ -441,6 +441,14 @@ clocks = <&pclkb 0 0>; status = "disabled"; }; + + ctsu: ctsua@40081000 { + compatible = "renesas,ra-ctsu"; + reg = <0x40081000 0x24>; + clocks = <&pclkb MSTPC 3>; + variant = "ctsua"; + status = "disabled"; + }; }; usbfs_phy: usbfs-phy { diff --git a/dts/arm/renesas/ra/ra6/ra6-cm33-common.dtsi b/dts/arm/renesas/ra/ra6/ra6-cm33-common.dtsi index 9625343ec278..6ca8afabbaa4 100644 --- a/dts/arm/renesas/ra/ra6/ra6-cm33-common.dtsi +++ b/dts/arm/renesas/ra/ra6/ra6-cm33-common.dtsi @@ -560,6 +560,14 @@ #size-cells = <0>; status = "disabled"; }; + + ctsu: ctsua@40081000 { + compatible = "renesas,ra-ctsu"; + reg = <0x40081000 0x24>; + clocks = <&pclkb MSTPC 3>; + variant = "ctsua"; + status = "disabled"; + }; }; usbfs_phy: usbfs-phy { diff --git a/dts/arm/renesas/ra/ra6/ra6-cm4-common.dtsi b/dts/arm/renesas/ra/ra6/ra6-cm4-common.dtsi index dd2c9cacddff..fce62f0de81b 100644 --- a/dts/arm/renesas/ra/ra6/ra6-cm4-common.dtsi +++ b/dts/arm/renesas/ra/ra6/ra6-cm4-common.dtsi @@ -655,6 +655,14 @@ clocks = <&pclkb 0 0>; status = "disabled"; }; + + ctsu: ctsua@40081000 { + compatible = "renesas,ra-ctsu"; + reg = <0x40081000 0x24>; + clocks = <&pclkb MSTPC 3>; + variant = "ctsua"; + status = "disabled"; + }; }; usbfs_phy: usbfs-phy { diff --git a/dts/bindings/input/renesas,ra-ctsu-button.yaml b/dts/bindings/input/renesas,ra-ctsu-button.yaml new file mode 100644 index 000000000000..38083f949799 --- /dev/null +++ b/dts/bindings/input/renesas,ra-ctsu-button.yaml @@ -0,0 +1,69 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: | + Renesas RA Capacitive Touch Button instance. + + This node is a renesas,ra-ctsu grandchild node and applies filters and calculations + to detect an input event on a group which is the child of renesas,ra-ctsu. + For more information see input/renesas,ra-ctsu.yaml + + Example: + + #include + + &ctsu { + compatible = "renesas,ra-ctsu"; + + group1 { + ... + button1 { + compatible = "renesas,ra-ctsu-button"; + elements = <0>; + threshold = <769>; + hysteresis = <38>; + event-code = ; + }; + + button2 { + compatible = "renesas,ra-ctsu-button"; + elements = <1>; + threshold = <769>; + hysteresis = <38>; + event-code = ; + }; + }; + }; + + Notes: The order of the CTSU button nodes in the same group must follow these elements index. + +compatible: "renesas,ra-ctsu-button" + +include: [base.yaml] + +properties: + event-code: + type: int + required: true + description: | + The key code for the device. This is used to identify the device in the + input subsystem. It should be one of the values defined in + include/input-event-codes.h. + + elements: + type: int + default: 0 + description: | + Element number from CTSU group that this button located on. + + threshold: + type: int + default: 0 + description: | + Touch/non-touch judgement threshold for automatic judgement. + + hysteresis: + type: int + default: 0 + description: | + Threshold hysteresis for chattering prevention for automatic judgement. diff --git a/dts/bindings/input/renesas,ra-ctsu-slider.yaml b/dts/bindings/input/renesas,ra-ctsu-slider.yaml new file mode 100644 index 000000000000..2c3a1b64b571 --- /dev/null +++ b/dts/bindings/input/renesas,ra-ctsu-slider.yaml @@ -0,0 +1,52 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: | + Renesas RA Capacitive Touch Slider instance. + + This node is a renesas,ra-ctsu grandchild node and applies filters and calculations + to detect an input event on a group which is the child of renesas,ra-ctsu. + For more information see input/renesas,ra-ctsu.yaml + + Example: + + #include + + &ctsu { + compatible = "renesas,ra-ctsu"; + + group1 { + ... + slider { + compatible = "renesas,ra-ctsu-slider"; + elements = <1>, <0>, <2>, <4>, <3>; + threshold = <573>; + event-code = ; + }; + }; + }; + +compatible: "renesas,ra-ctsu-slider" + +include: [base.yaml] + +properties: + event-code: + type: int + required: true + description: | + The key code for the device. This is used to identify the device in the + input subsystem. It should be one of the values defined in + include/input-event-codes.h. + + elements: + type: array + description: | + Element number array from CTSU group that used by this node. It should have the same + order with electrode located on the Capacitive Pad. + + threshold: + type: int + default: 0 + description: | + Touch/non-touch judgement threshold for automatic judgement. diff --git a/dts/bindings/input/renesas,ra-ctsu-wheel.yaml b/dts/bindings/input/renesas,ra-ctsu-wheel.yaml new file mode 100644 index 000000000000..33b8dcb0c6b4 --- /dev/null +++ b/dts/bindings/input/renesas,ra-ctsu-wheel.yaml @@ -0,0 +1,52 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: | + Renesas RA Capacitive Touch Wheel + + This node is a renesas,ra-ctsu grandchild node and applies filters and calculations + to detect an input event on a group which is the child of renesas,ra-ctsu. + For more information see input/renesas,ra-ctsu.yaml + + Example: + + #include + + &ctsu { + compatible = "renesas,ra-ctsu"; + + group1 { + ... + wheel { + compatible = "renesas,ra-ctsu-wheel"; + elements = <0>, <3>, <2>, <1>; + threshold = <711>; + event-code = ; + }; + }; + }; + +compatible: "renesas,ra-ctsu-wheel" + +include: [base.yaml] + +properties: + event-code: + type: int + required: true + description: | + The key code for the device. This is used to identify the device in the + input subsystem. It should be one of the values defined in + include/input-event-codes.h. + + elements: + type: array + description: | + Element number array from CTSU group that used by this node. It should have the same + order with electrode located on the Capacitive Pad. + + threshold: + type: int + default: 0 + description: | + Touch/non-touch judgement threshold for automatic judgement. diff --git a/dts/bindings/input/renesas,ra-ctsu.yaml b/dts/bindings/input/renesas,ra-ctsu.yaml new file mode 100644 index 000000000000..91f528dc1a5f --- /dev/null +++ b/dts/bindings/input/renesas,ra-ctsu.yaml @@ -0,0 +1,199 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas RA Capacitive Sensing Unit + +compatible: "renesas,ra-ctsu" + +include: [base.yaml, pinctrl-device.yaml] + +properties: + pinctrl-0: + required: true + + clocks: + required: true + + interrupts: + required: true + description: IRQ number and priority to use for CTSU. + + interrupt-names: + required: true + description: | + Interrupts must be given corresponding names so that the shim driver can recognize them. + - "ctsuwr": write interrupt + - "ctsurd": read interrupt + - "ctsufn": end interrupt + + variant: + required: true + type: string + enum: ["ctsua", "ctsu2"] + description: Determine which ctsu device is in use + + clock-div: + type: int + enum: [1, 2, 4, 8] + default: 1 + description: Select divider value for operating input clock. Default as div by 1. + + pwr-supply-sel: + type: string + enum: ["vcc", "internal-power"] + default: "internal-power" + description: CTSU Transmission Power Supply Select (for both CTSUa and CTSU2). + + pwr-supply-sel2: + type: string + enum: ["pwr-supply-sel", "vcc-private"] + default: "pwr-supply-sel" + description: CTSU Transmission Power Supply Select 2 (CTSU2 Only) + + atune1: + type: string + enum: ["normal", "high"] + default: "normal" + description: | + CTSU Power Supply Capacity Adjustment (CTSUa Only): + - "normal": 40uA + - "high": 80uA + + atune12: + type: int + enum: [80, 40, 20, 160] + default: 40 + description: | + CTSU Power Supply Capacity Adjustment in uA (CTSU2 Only) + + measure-mode: + type: string + enum: + - "self-multi-scan" + - "mutual-full-scan" + - "mutual-cfc-scan" + - "current-scan" + - "correction-scan" + - "diagnosis-scan" + default: "self-multi-scan" + description: CTSU Measurement Mode Select + + po-sel: + type: string + enum: + - "low-gpio" + - "hi-z" + - "low" + - "same-pulse" + default: "same-pulse" + description: CTSU Non-Measured Channel Output Select (CTSU2 Only) + + tscap-gpios: + type: phandle-array + required: true + description: | + CTSU TSCAP Pin. This pin is used to discharge the capacitior by + control to output low, before switching to CTSU function. + +child-binding: + description: Renesas RA CTSU touch configuration + properties: + ctsuchac: + type: array + default: [0, 0, 0, 0, 0] + description: | + TSCAP pin enable mask. Expected fields, in order, are: + - ctsuchac0: TS00-TS07 enable mask + - ctsuchac1: TS08-TS15 enable mask + - ctsuchac2: TS16-TS23 enable mask + - ctsuchac3: TS24-TS31 enable mask + - ctsuchac4: TS32-TS39 enable mask + + ctsuchtrc: + type: array + default: [0, 0, 0, 0, 0] + description: | + TSCAP pin mutual-tx mask. Expected fields, in order, are: + - ctsuchtrc0: TS00-TS07 mutual-tx mask + - ctsuchtrc1: TS08-TS15 mutual-tx mask + - ctsuchtrc2: TS16-TS23 mutual-tx mask + - ctsuchtrc3: TS24-TS31 mutual-tx mask + - ctsuchtrc4: TS32-TS39 mutual-tx mask + + rx-count: + type: int + default: 0 + description: | + The number of RX channels to be used. This should be set to the number of + channels that are enabled in the ctsuchac0-4 properties. + + tx-count: + type: int + default: 0 + description: | + The number of TX channels to be used. This should be set to the number of + channels that are enabled in the ctsuchtrc0-4 properties. + + ssdiv: + type: string-array + default: ["4.00"] + enum: + - "4.00" + - "2.00" + - "1.33" + - "1.00" + - "0.80" + - "0.67" + - "0.57" + - "0.50" + - "0.44" + - "0.40" + - "0.36" + - "0.33" + - "0.31" + - "0.29" + - "0.27" + - "0.00" + description: CTSU Spectrum Diffusion Frequency Division Setting (CTSUa Only) + + so: + type: array + default: [0] + description: CTSU Sensor Offset Adjustment + + snum: + type: array + default: [0] + description: CTSU Measurement Count Setting + + sdpa: + type: array + default: [0] + description: CTSU Base Clock Setting + + on-freq: + type: int + default: 0 + description: The cumulative number of determinations of ON. + + off-freq: + type: int + default: 0 + description: The cumulative number of determinations of OFF. + + drift-freq: + type: int + default: 0 + description: Base value drift frequency (0 mean no use). + + cancel-freq: + type: int + default: 0 + description: Maximum continuous ON (0 mean no use). + + num-moving-avg: + type: int + default: 0 + description: | + The number of samples to use for moving average. If set to 0, no moving average is applied. + This is useful for smoothing the sensor readings. diff --git a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-ra.h b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-ra.h index a077cd226866..133ea0ca5760 100644 --- a/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-ra.h +++ b/include/zephyr/dt-bindings/pinctrl/renesas/pinctrl-ra.h @@ -48,6 +48,7 @@ #define RA_PSEL_ETH_RMII 0x17 #define RA_PSEL_GLCDC 0x19 #define RA_PSEL_OSPI 0x1c +#define RA_PSEL_CTSU 0x0c #define RA_PSEL_POS 8 #define RA_PSEL_MASK 0x1f diff --git a/include/zephyr/input/input_renesas_ra_ctsu.h b/include/zephyr/input/input_renesas_ra_ctsu.h new file mode 100644 index 000000000000..df890f4fc033 --- /dev/null +++ b/include/zephyr/input/input_renesas_ra_ctsu.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_ZEPHYR_INPUT_INPUT_RENESAS_RA_CTSU_H_ +#define ZEPHYR_INCLUDE_ZEPHYR_INPUT_INPUT_RENESAS_RA_CTSU_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct renesas_ra_ctsu_touch_cfg { + struct st_touch_instance touch_instance; +}; + +/** + * @brief Configure CTSU group device with a Renesas QE for Capacitive Touch Workflow generated + * configuration + * + * @param dev Pointer to the input device instance + * @param cfg Pointer to the configuration data for the device + * + * @retval 0 on success + * @retval -ENOSYS in case INPUT_RENESAS_RA_QE_TOUCH_CFG was not enabled + * @retval -errno on failure + */ +__syscall int renesas_ra_ctsu_group_configure(const struct device *dev, + const struct renesas_ra_ctsu_touch_cfg *cfg); + +#ifdef __cplusplus +} +#endif + +#include + +#endif /* ZEPHYR_INCLUDE_ZEPHYR_INPUT_INPUT_RENESAS_RA_CTSU_H_ */ diff --git a/modules/Kconfig.renesas b/modules/Kconfig.renesas index 12a898e2d8e8..78dd7fff951e 100644 --- a/modules/Kconfig.renesas +++ b/modules/Kconfig.renesas @@ -201,6 +201,23 @@ config USE_RA_FSP_SSI help Enable RA FSP I2S SSI driver +config USE_RA_FSP_IOPORT + bool + help + Enable RA FSP IOPORT driver + +config USE_RA_FSP_CTSU + bool + select USE_RA_FSP_IOPORT + help + Enable RA FSP CTSU driver + +config USE_RA_FSP_TOUCH + bool + depends on USE_RA_FSP_CTSU + help + Enable RA FSP TOUCH library + endif # HAS_RENESAS_RA_FSP if HAS_RENESAS_RZ_FSP diff --git a/west.yml b/west.yml index 7032362af5ce..1ac3f698bd47 100644 --- a/west.yml +++ b/west.yml @@ -226,7 +226,7 @@ manifest: - hal - name: hal_renesas path: modules/hal/renesas - revision: 0769fe1520f6c14e6301188588da758a609f181d + revision: pull/115/head groups: - hal - name: hal_rpi_pico