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