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