diff --git a/boards/renesas/rsk_rx130/rsk_rx130.dts b/boards/renesas/rsk_rx130/rsk_rx130.dts index 4473713f38c71..1471e3a0a6fcb 100644 --- a/boards/renesas/rsk_rx130/rsk_rx130.dts +++ b/boards/renesas/rsk_rx130/rsk_rx130.dts @@ -86,6 +86,10 @@ status = "okay"; }; +&ioportc { + status = "okay"; +}; + &ioportd { status = "okay"; }; @@ -118,6 +122,58 @@ clock-frequency = ; }; +&ctsu { + pinctrl-0 = <&ctsu_default>; + pinctrl-names = "default"; + max-num-sensors = <36>; + tscap-gpios = <&ioportc 4 0>; + status = "okay"; + + onboard_slider: touch_slider_0 { + component-type = "slider"; + ssdiv = <1>; + so = <0x040>; + snum = <0x03>; + sdpa = <0x07>; + channels-num = <10>, <9>, <8>, <7>; + zephyr,code = ; + touch-count-threshold = <750>; + + sld0 { + compatible = "renesas,rx-ctsu-slider"; + status = "okay"; + }; + }; + + onboard_button_1: touch_button_1 { + component-type = "button"; + ssdiv = <0x0>; + snum = <0x07>; + sdpa = <0x03>; + channels-num = <11>; + zephyr,code = ; + + button1 { + compatible = "renesas,rx-ctsu-button"; + status = "okay"; + }; + }; + + onboard_button_2: touch_button_2 { + component-type = "button"; + ssdiv = <0x0>; + snum = <0x07>; + sdpa = <0x03>; + channels-num = <12>; + zephyr,code = ; + + button2 { + compatible = "renesas,rx-ctsu-button"; + status = "okay"; + }; + }; +}; + &port_irq1 { status = "okay"; }; diff --git a/boards/renesas/rsk_rx130/rsk_rx130_512kb-pinctrl.dtsi b/boards/renesas/rsk_rx130/rsk_rx130_512kb-pinctrl.dtsi index 2d56a0ef36f3e..9fde9f8924f18 100644 --- a/boards/renesas/rsk_rx130/rsk_rx130_512kb-pinctrl.dtsi +++ b/boards/renesas/rsk_rx130/rsk_rx130_512kb-pinctrl.dtsi @@ -41,4 +41,16 @@ renesas,analog-enable; }; }; + + ctsu_default: ctsu_default { + group1 { + psels = , + , + , + , + , + , + ; + }; + }; }; diff --git a/drivers/input/CMakeLists.txt b/drivers/input/CMakeLists.txt index 5007123095602..60b288b44357e 100644 --- a/drivers/input/CMakeLists.txt +++ b/drivers/input/CMakeLists.txt @@ -34,6 +34,7 @@ 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_RENESAS_RX_CTSU input_renesas_rx_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 be547866a417e..5111c4db37d59 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -35,6 +35,7 @@ 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.renesas_rx" source "drivers/input/Kconfig.rts5912" source "drivers/input/Kconfig.sbus" source "drivers/input/Kconfig.sdl" diff --git a/drivers/input/Kconfig.renesas_rx b/drivers/input/Kconfig.renesas_rx new file mode 100644 index 0000000000000..dce5db65f2b8d --- /dev/null +++ b/drivers/input/Kconfig.renesas_rx @@ -0,0 +1,92 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config INPUT_RENESAS_RX_CTSU + bool "Renesas Capacitive Touch Sensing Unit" + default y + depends on DT_HAS_RENESAS_RX_CTSU_ENABLED + select USE_RX_RDP_CTSU + select PINCTRL + help + Enable RX series CTSU driver + +if INPUT_RENESAS_RX_CTSU + +config INPUT_RENESAS_RX_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. + +config INPUT_RENESAS_RX_CTSU_SCAN_INTERVAL_MS + int "CTSU channels scan interval" + default 5 + help + Interval time (milliseconds) between two scans. + +if !INPUT_RENESAS_RX_QE_TOUCH_CFG + +config INPUT_RENESAS_RX_CTSU_ON_FREQ + int "CTSU On Frequency" + default 3 + help + Number of Debouncing count of touch-on filtering + +config INPUT_RENESAS_RX_CTSU_OFF_FREQ + int "CTSU Off Frequency" + default 3 + help + Number of Debouncing count of touch-off filtering + +config INPUT_RENESAS_RX_CTSU_DRIFT_FREQ + int "CTSU drift frequency" + default 255 + help + Sample count for drift correction (0 mean no use). + +config INPUT_RENESAS_RX_CTSU_CANCEL_FREQ + int "CTSU Cancel Frequency" + default 0 + help + Continuous Touch Cancel Count (0 mean no use). + +config INPUT_RENESAS_RX_CTSU_NUM_MOVING_AVERAGE + int "CTSU Moving average" + default 4 + help + Number of moving average for measurement data + +config INPUT_RENESAS_RX_CTSU_POWER_SUPPLY_CAPACITY + int "CTSU Power supply capacity" + default 0 + range 0 1 + help + Power Supply Capacity Adjustment + - 0: Normal (40uA) + - 1: High-current output (80uA) + +config INPUT_RENESAS_RX_CTSU_TRANSMISSION_POWER_SUPPLY + int "CTSU transmission power supply" + default 0 + range 0 1 + help + Transmission Power Supply Select + - 0: VCC selected + - 1: Internal logic power supply selected + +config INPUT_RENESAS_RX_CTSU_PCLK_DIVISION + int "CTSU: Division of PCLK" + default 0 + range 0 2 + help + Division of PCLK + - 0: PCLK/1 + - 1: PCLK/2 + - 2: PCLK/4 + +endif #!INPUT_RENESAS_RX_QE_TOUCH_CFG + +endif #INPUT_CTSU diff --git a/drivers/input/input_renesas_rx_ctsu.c b/drivers/input/input_renesas_rx_ctsu.c new file mode 100644 index 0000000000000..353bd2de65730 --- /dev/null +++ b/drivers/input/input_renesas_rx_ctsu.c @@ -0,0 +1,633 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_rx_ctsu + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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) diff --git a/dts/bindings/input/renesas,rx-ctsu-button.yaml b/dts/bindings/input/renesas,rx-ctsu-button.yaml new file mode 100644 index 0000000000000..95dcc73e8a5fa --- /dev/null +++ b/dts/bindings/input/renesas,rx-ctsu-button.yaml @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: RX Renesas Capatitive Touch Button Component + +compatible: "renesas,rx-ctsu-button" diff --git a/dts/bindings/input/renesas,rx-ctsu-slider.yaml b/dts/bindings/input/renesas,rx-ctsu-slider.yaml new file mode 100644 index 0000000000000..7a4c5af30b851 --- /dev/null +++ b/dts/bindings/input/renesas,rx-ctsu-slider.yaml @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: RX Renesas Capatitive Touch Slider Component + +compatible: "renesas,rx-ctsu-slider" diff --git a/dts/bindings/input/renesas,rx-ctsu-wheel.yaml b/dts/bindings/input/renesas,rx-ctsu-wheel.yaml new file mode 100644 index 0000000000000..5931f5764b7ec --- /dev/null +++ b/dts/bindings/input/renesas,rx-ctsu-wheel.yaml @@ -0,0 +1,6 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: RX Renesas Capatitive Touch Wheel Component + +compatible: "renesas,rx-ctsu-wheel" diff --git a/dts/bindings/input/renesas,rx-ctsu.yaml b/dts/bindings/input/renesas,rx-ctsu.yaml new file mode 100644 index 0000000000000..b52a6b9d978c0 --- /dev/null +++ b/dts/bindings/input/renesas,rx-ctsu.yaml @@ -0,0 +1,111 @@ +# Copyright (c) 2025 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: RX Renesas Capatitive Touch Sensing Unit + +compatible: "renesas,rx-ctsu" + +include: [base.yaml, pinctrl-device.yaml] + +properties: + max-num-sensors: + type: int + required: true + description: Maximum number of sensors available in the CTSU + + low-voltage-mode: + type: boolean + description: | + Enable low voltage mode + In this mode, the CTSU will work with lower voltage + This mode is useful when the system is working with low voltage + + tscap-gpios: + type: phandle-array + required: true + description: | + CTSU TSCAP Pin + + pinctrl-0: + required: true + + pinctrl-names: + required: true + +child-binding: + description: CTSU Sensor Component + + properties: + component-type: + type: string + required: true + enum: + - "button" + - "slider" + - "wheel" + description: | + Type of component + + ssdiv: + type: int + default: 1 + description: | + Spectrum Diffusion Frequency Division Setting + - 0: 4.00 <= Base Clock Frequency fb (MHz) + - 1..14: 4.00/(ssdiv+1) <= fb < 4.00/(ssdiv) + - 15: fb < 0.27 + + so: + type: int + default: 0x074 + description: | + Sensor Offset Adjustment (10 bits): + Current offset amount + + snum: + type: int + default: 3 + description: | + Set the number of measurements = snum + 1 + + sdpa: + type: int + default: 7 + description: | + Base Clock Setting (5 bits)(0 - 31): + Operating clock divided by 2*(sdpa+1) + + resolution: + type: int + default: 100 + description: Resolution of wheel or slider + + channels-num: + type: array + required: true + description: | + Channels number that are used by the component + In case of "slider" or "wheel", channels should be placed in order + as they are on the slider or wheel. (from the lowest value to the highest value) + In case of "button", there must be only 1 element in array. + Otherwise, CTSU will not working. + + touch-count-threshold: + type: int + default: 1500 + description: | + Count threshold to determine touching or not + In case of "slider" or "wheel", + this is the threshold to start the position calculation + + threshold-range: + type: int + default: 500 + description: | + Range of threshold: if count > threshold + range => touching + if count < threshold => untouch + + zephyr,code: + type: int + required: true + description: Key code to emit. diff --git a/dts/rx/renesas/rx130-common.dtsi b/dts/rx/renesas/rx130-common.dtsi index 50167ca423515..930d4857abede 100644 --- a/dts/rx/renesas/rx130-common.dtsi +++ b/dts/rx/renesas/rx130-common.dtsi @@ -837,6 +837,15 @@ status = "disabled"; }; + ctsu: ctsu@a0900 { + compatible = "renesas,rx-ctsu"; + reg = < 0x000A0900 0x100 >; + clocks = <&pclkb MSTPD 10>; + interrupts = <60 1>, <61 1>, <62 1>; + interrupt-names = "ctsuwr", "ctsurd", "ctsufn"; + status = "disabled"; + }; + ofsm: ofsm@ffffff80 { compatible = "zephyr,memory-region"; reg = <0xFFFFFF80 0x0F>; diff --git a/include/zephyr/input/input_renesas_rx_ctsu.h b/include/zephyr/input/input_renesas_rx_ctsu.h new file mode 100644 index 0000000000000..d74c1db90e35a --- /dev/null +++ b/include/zephyr/input/input_renesas_rx_ctsu.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Header file for Renesas RX CTSU input driver. + * @ingroup renesas_rx_ctsu_interface + */ + +#ifndef ZEPHYR_INCLUDE_ZEPHYR_INPUT_INPUT_RENESAS_RX_CTSU_H_ +#define ZEPHYR_INCLUDE_ZEPHYR_INPUT_INPUT_RENESAS_RX_CTSU_H_ + +/** + * @defgroup renesas_rx_ctsu_interface Renesas RX CTSU + * @ingroup input_interface_ext + * @brief Renesas RX Capacitive Touch Sensor Unit + * @{ + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Configuration data for the Renesas RX CTSU device + */ +struct renesas_rx_ctsu_touch_cfg { + /** FSP Touch instance */ + 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_RX_QE_TOUCH_CFG was not enabled + * @retval -errno on failure + */ +__syscall int renesas_rx_ctsu_group_configure(const struct device *dev, + const struct renesas_rx_ctsu_touch_cfg *cfg); + +#ifdef __cplusplus +} +#endif + +#include + +/** @} */ + +#endif /* ZEPHYR_INCLUDE_ZEPHYR_INPUT_INPUT_RENESAS_RX_CTSU_H_ */ diff --git a/modules/Kconfig.renesas b/modules/Kconfig.renesas index 0a1f49453d708..3a06cb339c672 100644 --- a/modules/Kconfig.renesas +++ b/modules/Kconfig.renesas @@ -381,4 +381,9 @@ config USE_RX_RDP_IWDT help Enable RX RDP IWDT driver +config USE_RX_RDP_CTSU + bool + help + Enable RX RDP CTSU driver + endif # HAS_RENESAS_RX_RDP diff --git a/samples/boards/renesas/ctsu_input/CMakeLists.txt b/samples/boards/renesas/ctsu_input/CMakeLists.txt new file mode 100644 index 0000000000000..48994f46b3072 --- /dev/null +++ b/samples/boards/renesas/ctsu_input/CMakeLists.txt @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(renesas_ctsu) + +target_sources(app PRIVATE src/main.c) + +if(CONFIG_INPUT_RENESAS_RX_QE_TOUCH_CFG) + zephyr_include_directories(src/qe_generated_files) + zephyr_sources(src/qe_generated_files/qe_touch_config.c) +endif() diff --git a/samples/boards/renesas/ctsu_input/boards/rsk_rx130_512kb.overlay b/samples/boards/renesas/ctsu_input/boards/rsk_rx130_512kb.overlay new file mode 100644 index 0000000000000..ee4811e69505f --- /dev/null +++ b/samples/boards/renesas/ctsu_input/boards/rsk_rx130_512kb.overlay @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&ctsu { + status = "okay"; +}; + +&onboard_slider { + zephyr,code = <1>; +}; + +&onboard_button_1 { + zephyr,code = <10>; +}; + +&onboard_button_2 { + zephyr,code = <11>; +}; + +/ { + leds { + testled0: testled0 { + gpios = <&ioportd 3 GPIO_ACTIVE_LOW>; + label = "LED0"; + }; + + testled1: testled1 { + gpios = <&ioportd 4 GPIO_ACTIVE_LOW>; + label = "LED1"; + }; + + testled2: testled2 { + gpios = <&ioporte 6 GPIO_ACTIVE_LOW>; + label = "LED2"; + }; + + testled3: testled3 { + gpios = <&ioporte 7 GPIO_ACTIVE_LOW>; + label = "LED3"; + }; + }; +}; diff --git a/samples/boards/renesas/ctsu_input/prj.conf b/samples/boards/renesas/ctsu_input/prj.conf new file mode 100644 index 0000000000000..f691746838264 --- /dev/null +++ b/samples/boards/renesas/ctsu_input/prj.conf @@ -0,0 +1,4 @@ +CONFIG_GPIO=y +CONFIG_INPUT=y +CONFIG_INPUT_MODE_SYNCHRONOUS=y +CONFIG_INPUT_RENESAS_RX_QE_TOUCH_CFG=y diff --git a/samples/boards/renesas/ctsu_input/src/main.c b/samples/boards/renesas/ctsu_input/src/main.c new file mode 100644 index 0000000000000..5912c5e3245f0 --- /dev/null +++ b/samples/boards/renesas/ctsu_input/src/main.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_INPUT_RENESAS_RX_QE_TOUCH_CFG +#include "qe_touch_config.h" +#endif /* CONFIG_INPUT_RENESAS_RX_QE_TOUCH_CFG */ + +static const struct device *const test_touch_dev = DEVICE_DT_GET(DT_NODELABEL(ctsu)); +#define BUTTON_1_IDX DT_NODE_CHILD_IDX(DT_NODELABEL(onboard_button_1)) +#define BUTTON_2_IDX DT_NODE_CHILD_IDX(DT_NODELABEL(onboard_button_2)) +#define SLIDER_IDX DT_NODE_CHILD_IDX(DT_NODELABEL(onboard_slider)) + +#define STACKSIZE 1024 +#define PRIORITY 7 +#define LED0_NODE DT_NODELABEL(testled0) +#define LED1_NODE DT_NODELABEL(testled1) +#define LED2_NODE DT_NODELABEL(testled2) +#define LED3_NODE DT_NODELABEL(testled3) +#define NUM_TEST_LED 4 + +#define LED_ON 1 +#define LED_OFF 0 + +enum { + TOUCH_BUTTON_1 = 10, + TOUCH_BUTTON_2 = 11, + TOUCH_SLIDER = 1, +}; + +static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios); +static const struct gpio_dt_spec led1 = GPIO_DT_SPEC_GET(LED1_NODE, gpios); +static const struct gpio_dt_spec led2 = GPIO_DT_SPEC_GET(LED2_NODE, gpios); +static const struct gpio_dt_spec led3 = GPIO_DT_SPEC_GET(LED3_NODE, gpios); +static const struct gpio_dt_spec *leds[] = {&led0, &led1, &led2, &led3}; +static volatile int led_state; +static volatile int leds_on_off[NUM_TEST_LED] = {0}; +static volatile int current_main_led; + +static volatile int event_count[DT_CHILD_NUM_STATUS_OKAY(DT_NODELABEL(ctsu))] = {0}; +static uint16_t last_code; +static volatile int32_t last_val[DT_CHILD_NUM_STATUS_OKAY(DT_NODELABEL(ctsu))]; +static struct k_sem btn1_sem; +static struct k_sem btn2_sem; +static struct k_sem sldr_sem; +static struct k_sem render_sem; + +static void sample_setup(void) +{ + gpio_pin_configure_dt(&led0, GPIO_OUTPUT_INACTIVE); + gpio_pin_configure_dt(&led1, GPIO_OUTPUT_INACTIVE); + gpio_pin_configure_dt(&led2, GPIO_OUTPUT_INACTIVE); + gpio_pin_configure_dt(&led3, GPIO_OUTPUT_INACTIVE); + + k_sem_init(&btn1_sem, 0, 1); + k_sem_init(&btn2_sem, 0, 1); + k_sem_init(&sldr_sem, 0, 1); + k_sem_init(&render_sem, 0, 1); + +#ifdef CONFIG_INPUT_RENESAS_RX_QE_TOUCH_CFG + int ret = renesas_rx_ctsu_group_configure( + test_touch_dev, (struct renesas_rx_ctsu_touch_cfg *)&g_qe_touch_instance_config01); + + if (ret < 0) { + printk("Failed to configure QE Touch: %d\n", ret); + return; + } +#endif /* CONFIG_INPUT_RENESAS_RX_QE_TOUCH_CFG */ +} + +static void button1_task(void) +{ + while (1) { + k_sem_take(&btn1_sem, K_FOREVER); + if (led_state == 0) { + /** Current leds are OFF, do nothing */ + } else { + if (led_state >= 15) { + led_state = 1; + } else { + led_state++; + } + } + k_sem_give(&render_sem); + } +} + +static void button2_task(void) +{ + int prev_state = 0; + + while (1) { + k_sem_take(&btn2_sem, K_FOREVER); + if (led_state == 0) { + /** Current led state is OFF */ + if (prev_state == 0) { + /** First time power on */ + led_state = 1; + } else { + /** Restore prev_state */ + led_state = prev_state; + } + } else { + prev_state = led_state; + led_state = 0; + } + k_sem_give(&render_sem); + } +} + +static void slider_task(void) +{ + while (1) { + k_sem_take(&sldr_sem, K_FOREVER); + if (led_state == 0) { + continue; + } + int curr_val = last_val[SLIDER_IDX]; + + if (curr_val != TOUCH_OFF_VALUE) { + if (curr_val == 100) { + curr_val = 99; + } + current_main_led = 3 - (curr_val / 25); + } + k_sem_give(&render_sem); + } +} + +static void render_task(void) +{ + while (1) { + k_sem_take(&render_sem, K_FOREVER); + for (int i = 0; i < NUM_TEST_LED; i++) { + if (led_state & BIT(i)) { + gpio_pin_set_dt(leds[(current_main_led + i) % 4], LED_ON); + } else { + gpio_pin_set_dt(leds[(current_main_led + i) % 4], LED_OFF); + } + } + } +} + +static void test_touch_keys_cb_handler(struct input_event *evt, void *user_data) +{ + switch (evt->code) { + case TOUCH_BUTTON_1: + if (evt->value == 0) { + printk("Button 1 released\n"); + if (last_val[BUTTON_1_IDX] != 0) { + k_sem_give(&btn1_sem); + } + } else { + event_count[BUTTON_1_IDX]++; + printk("Button 1 pressed %d time(s)\n", event_count[BUTTON_1_IDX]); + } + last_val[BUTTON_1_IDX] = evt->value; + break; + + case TOUCH_BUTTON_2: + if (evt->value == 0) { + printk("Button 2 released\n"); + if (last_val[BUTTON_2_IDX] != 0) { + k_sem_give(&btn2_sem); + } + } else { + event_count[BUTTON_2_IDX]++; + printk("Button 2 pressed %d time(s)\n", event_count[BUTTON_2_IDX]); + } + last_val[BUTTON_2_IDX] = evt->value; + break; + + case TOUCH_SLIDER: + if (evt->value == TOUCH_OFF_VALUE) { + printk("Slider released\n"); + if (last_val[SLIDER_IDX] != TOUCH_OFF_VALUE) { + } + } else { + if (last_val[SLIDER_IDX] == TOUCH_OFF_VALUE) { + event_count[SLIDER_IDX]++; + printk("Slider pressed\n"); + } + printk("Position: %d\n", evt->value); + } + k_sem_give(&sldr_sem); + last_val[SLIDER_IDX] = evt->value; + break; + + default: + break; + } + last_code = evt->code; +} +INPUT_CALLBACK_DEFINE(test_touch_dev, test_touch_keys_cb_handler, NULL); + +K_THREAD_DEFINE(button1_id, STACKSIZE, button1_task, NULL, NULL, NULL, PRIORITY, 0, 0); +K_THREAD_DEFINE(button2_id, STACKSIZE, button2_task, NULL, NULL, NULL, PRIORITY, 0, 0); +K_THREAD_DEFINE(slider_id, STACKSIZE, slider_task, NULL, NULL, NULL, PRIORITY, 0, 0); +K_THREAD_DEFINE(render_id, STACKSIZE, render_task, NULL, NULL, NULL, PRIORITY, 0, 0); + +int main(void) +{ + sample_setup(); + printk("On board CTSU components sample started!\n"); + printk("Press on touch nodes for sample\n"); + return 0; +} diff --git a/samples/boards/renesas/ctsu_input/src/qe_generated_files/qe_touch_config.c b/samples/boards/renesas/ctsu_input/src/qe_generated_files/qe_touch_config.c new file mode 100644 index 0000000000000..afd30b71027b9 --- /dev/null +++ b/samples/boards/renesas/ctsu_input/src/qe_generated_files/qe_touch_config.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "qe_touch_config.h" + +volatile uint8_t g_qe_touch_flag; +volatile ctsu_event_t g_qe_ctsu_event; + +void qe_touch_callback(touch_callback_args_t *p_args) +{ + g_qe_touch_flag = 1; + g_qe_ctsu_event = p_args->event; +} + +/* CTSU Related Information for [CONFIG01] configuration. */ + +const ctsu_element_cfg_t g_qe_ctsu_element_cfg_config01[] = { + {.ssdiv = CTSU_SSDIV_2000, .so = 0x045, .snum = 0x03, .sdpa = 0x07}, + {.ssdiv = CTSU_SSDIV_2000, .so = 0x055, .snum = 0x03, .sdpa = 0x07}, + {.ssdiv = CTSU_SSDIV_2000, .so = 0x04D, .snum = 0x03, .sdpa = 0x07}, + {.ssdiv = CTSU_SSDIV_2000, .so = 0x042, .snum = 0x03, .sdpa = 0x07}, + {.ssdiv = CTSU_SSDIV_4000, .so = 0x0D0, .snum = 0x07, .sdpa = 0x03}, + {.ssdiv = CTSU_SSDIV_4000, .so = 0x0C9, .snum = 0x07, .sdpa = 0x03}, +}; + +const ctsu_cfg_t g_qe_ctsu_cfg_config01 = { + .cap = CTSU_CAP_SOFTWARE, + + .txvsel = CTSU_TXVSEL_VCC, + + .atune1 = CTSU_ATUNE1_NORMAL, + + .md = CTSU_MODE_SELF_MULTI_SCAN, + + .ctsuchac0 = 0x80, /* ch0-ch7 enable mask */ + .ctsuchac1 = 0x1F, /* ch8-ch15 enable mask */ + .ctsuchac2 = 0x00, /* ch16-ch23 enable mask */ + .ctsuchac3 = 0x00, /* ch24-ch31 enable mask */ + .ctsuchac4 = 0x00, /* ch32-ch39 enable mask */ + .ctsuchtrc0 = 0x00, /* ch0-ch7 mutual tx mask */ + .ctsuchtrc1 = 0x00, /* ch8-ch15 mutual tx mask */ + .ctsuchtrc2 = 0x00, /* ch16-ch23 mutual tx mask */ + .ctsuchtrc3 = 0x00, /* ch24-ch31 mutual tx mask */ + .ctsuchtrc4 = 0x00, /* ch32-ch39 mutual tx mask */ + .num_rx = 6, + .num_tx = 0, + .p_elements = g_qe_ctsu_element_cfg_config01, + +#if (CTSU_TARGET_VALUE_CONFIG_SUPPORT == 1) + .tuning_self_target_value = 15360, + .tuning_mutual_target_value = 10240, +#endif + + .num_moving_average = 4, + .tuning_enable = true, + .p_callback = &qe_touch_callback, + +}; + +ctsu_instance_ctrl_t g_qe_ctsu_ctrl_config01; + +const ctsu_instance_t g_qe_ctsu_instance_config01 = { + .p_ctrl = &g_qe_ctsu_ctrl_config01, + .p_cfg = &g_qe_ctsu_cfg_config01, + .p_api = &g_ctsu_on_ctsu, +}; + +/* Touch Related Information for [CONFIG01] configuration. */ + +#define QE_TOUCH_CONFIG01_NUM_BUTTONS (2) +#define QE_TOUCH_CONFIG01_NUM_SLIDERS (1) +#define QE_TOUCH_CONFIG01_NUM_WHEELS (0) + +/* Button configurations */ +#if (QE_TOUCH_CONFIG01_NUM_BUTTONS != 0) +const touch_button_cfg_t g_qe_touch_button_cfg_config01[] = { + + /* button1 */ + { + .elem_index = 4, + .threshold = 2056, + .hysteresis = 102, + }, + /* button02 */ + { + .elem_index = 5, + .threshold = 2865, + .hysteresis = 143, + }, +}; +#endif + +/* Slider configurations */ +const uint8_t g_qe_touch_elem_slider_config01_slider01[] = {3, 2, 1, 0}; + +#if (QE_TOUCH_CONFIG01_NUM_SLIDERS != 0) +const touch_slider_cfg_t g_qe_touch_slider_cfg_config01[] = { + /* slider01 */ + { + .p_elem_index = g_qe_touch_elem_slider_config01_slider01, + .num_elements = 4, + .threshold = 1157, + }, +}; +#endif + +/* Wheel configurations */ +#if (QE_TOUCH_CONFIG01_NUM_WHEELS != 0) +const touch_wheel_cfg_t g_qe_touch_wheel_cfg_config01[] = {NULL}; +#endif + +/* Touch configurations */ +const touch_cfg_t g_qe_touch_cfg_config01 = { + .p_buttons = g_qe_touch_button_cfg_config01, + .p_sliders = g_qe_touch_slider_cfg_config01, + .p_wheels = NULL, + .num_buttons = QE_TOUCH_CONFIG01_NUM_BUTTONS, + .num_sliders = QE_TOUCH_CONFIG01_NUM_SLIDERS, + .num_wheels = QE_TOUCH_CONFIG01_NUM_WHEELS, + + .number = 0, + + .on_freq = 3, + .off_freq = 3, + .drift_freq = 255, + .cancel_freq = 0, + + .p_ctsu_instance = &g_qe_ctsu_instance_config01, +}; + +touch_instance_ctrl_t g_qe_touch_ctrl_config01; + +const touch_instance_t g_qe_touch_instance_config01 = { + .p_ctrl = &g_qe_touch_ctrl_config01, + .p_cfg = &g_qe_touch_cfg_config01, + .p_api = &g_touch_on_ctsu, +}; diff --git a/samples/boards/renesas/ctsu_input/src/qe_generated_files/qe_touch_config.h b/samples/boards/renesas/ctsu_input/src/qe_generated_files/qe_touch_config.h new file mode 100644 index 0000000000000..fbf8f27cecd26 --- /dev/null +++ b/samples/boards/renesas/ctsu_input/src/qe_generated_files/qe_touch_config.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef QE_TOUCH_CONFIG_H +#define QE_TOUCH_CONFIG_H + +#include "r_ctsu_qe.h" +#include "rm_touch_qe.h" +#include "qe_touch_define.h" + +/* Exported global variables */ +extern const ctsu_instance_t g_qe_ctsu_instance_config01; +extern const touch_instance_t g_qe_touch_instance_config01; + +extern volatile uint8_t g_qe_touch_flag; +extern volatile ctsu_event_t g_qe_ctsu_event; + +/* Exported global functions (to be accessed by other files) */ +extern void qe_touch_callback(touch_callback_args_t *p_args); + +#endif /* QE_TOUCH_CONFIG_H */ diff --git a/samples/boards/renesas/ctsu_input/src/qe_generated_files/qe_touch_define.h b/samples/boards/renesas/ctsu_input/src/qe_generated_files/qe_touch_define.h new file mode 100644 index 0000000000000..d57c453eaf791 --- /dev/null +++ b/samples/boards/renesas/ctsu_input/src/qe_generated_files/qe_touch_define.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef QE_TOUCH_DEFINE_H +#define QE_TOUCH_DEFINE_H + +/* Macro definitions */ +#define QE_TOUCH_VERSION 0x0420 + +#define CTSU_CFG_NUM_SELF_ELEMENTS 6 + +#define CTSU_CFG_NUM_MUTUAL_ELEMENTS 0 + +#define TOUCH_CFG_MONITOR_ENABLE 1 +#define TOUCH_CFG_NUM_BUTTONS 2 +#define TOUCH_CFG_NUM_SLIDERS 1 +#define TOUCH_CFG_NUM_WHEELS 0 +#define TOUCH_CFG_PAD_ENABLE 0 + +#define QE_TOUCH_MACRO_CTSU_IP_KIND 1 + +#define CTSU_CFG_VCC_MV 3300 +#define CTSU_CFG_LOW_VOLTAGE_MODE 0 + +#define CTSU_CFG_PCLK_DIVISION 0 + +#define CTSU_CFG_TSCAP_PORT 0x0C04 + +#define CTSU_CFG_NUM_SUMULTI 1 + +#define CTSU_CFG_TARGET_VALUE_QE_SUPPORT 1 + +#define CTSU_CFG_NUM_AUTOJUDGE_SELF_ELEMENTS 0 +#define CTSU_CFG_NUM_AUTOJUDGE_MUTUAL_ELEMENTS 0 + +/* Button State Mask for each configuration. */ +#define CONFIG01_INDEX_BUTTON1 0 +#define CONFIG01_MASK_BUTTON1 (1ULL << CONFIG01_INDEX_BUTTON1) +#define CONFIG01_INDEX_BUTTON02 1 +#define CONFIG01_MASK_BUTTON02 (1ULL << CONFIG01_INDEX_BUTTON02) + +#endif /* QE_TOUCH_DEFINE_H */