diff --git a/boards/st/stm32u083c_dk/stm32u083c_dk.dts b/boards/st/stm32u083c_dk/stm32u083c_dk.dts index 3ec13abe6c70a7..8b3db6451e6e9c 100644 --- a/boards/st/stm32u083c_dk/stm32u083c_dk.dts +++ b/boards/st/stm32u083c_dk/stm32u083c_dk.dts @@ -36,6 +36,20 @@ aliases { led0 = &green_led_1; }; + + touch_buttons { + compatible = "tsc-keys"; + status = "okay"; + tsc-controller = <&tsc>; + sampling-interval-ms = <10>; + demo_button { + label = "Demo Button"; + group = <&tsc_group6>; + noise-threshold = <50>; + zephyr,code = ; + }; + + }; }; &usart1 { @@ -119,14 +133,14 @@ pinctrl-0 = <&tsc_shield_pb12 &tsc_shield_cs_pb13 &tsc_g6_io1_pd10 &tsc_g6_io2_pd11>; pinctrl-names = "default"; - g1 { + tsc_group1: g1 { group = <1>; use-as-shield; channel-ios = ; sampling-io = ; }; - g6 { + tsc_group6: g6 { group = <6>; channel-ios = ; sampling-io = ; diff --git a/drivers/input/CMakeLists.txt b/drivers/input/CMakeLists.txt index aa1f843476288c..71e8421e0c9ea8 100644 --- a/drivers/input/CMakeLists.txt +++ b/drivers/input/CMakeLists.txt @@ -27,6 +27,7 @@ zephyr_library_sources_ifdef(CONFIG_INPUT_PMW3610 input_pmw3610.c) zephyr_library_sources_ifdef(CONFIG_INPUT_SBUS input_sbus.c) zephyr_library_sources_ifdef(CONFIG_INPUT_STMPE811 input_stmpe811.c) zephyr_library_sources_ifdef(CONFIG_INPUT_TOUCH input_touch.c) +zephyr_library_sources_ifdef(CONFIG_INPUT_TSC_KEYS input_tsc_keys.c) zephyr_library_sources_ifdef(CONFIG_INPUT_XEC_KBD input_xec_kbd.c) zephyr_library_sources_ifdef(CONFIG_INPUT_XPT2046 input_xpt2046.c) # zephyr-keep-sorted-stop diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index e76d3fc6fc76bd..15655dfe393ce0 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -30,6 +30,7 @@ source "drivers/input/Kconfig.sbus" source "drivers/input/Kconfig.sdl" source "drivers/input/Kconfig.stmpe811" source "drivers/input/Kconfig.touch" +source "drivers/input/Kconfig.tsc_keys" source "drivers/input/Kconfig.xec" source "drivers/input/Kconfig.xpt2046" # zephyr-keep-sorted-stop diff --git a/drivers/input/Kconfig.tsc_keys b/drivers/input/Kconfig.tsc_keys new file mode 100644 index 00000000000000..7a0cde2351e3a3 --- /dev/null +++ b/drivers/input/Kconfig.tsc_keys @@ -0,0 +1,17 @@ +# Copyright (c) 2024 Arif Balik +# SPDX-License-Identifier: Apache-2.0 + +config INPUT_TSC_KEYS + bool "STM32 TSC touch library" + default y + depends on STM32_TSC + select RING_BUFFER + help + Enable support for STM32 TSC touch library. + +config INPUT_TSC_KEYS_BUFFER_WORD_SIZE + int "STM32 TSC touch buffer size in words" + default 10 + depends on INPUT_TSC_KEYS + help + Set the size of the buffer for the STM32 TSC touch library. diff --git a/drivers/input/input_tsc_keys.c b/drivers/input/input_tsc_keys.c new file mode 100644 index 00000000000000..e93ffe5cd93167 --- /dev/null +++ b/drivers/input/input_tsc_keys.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2024 Arif Balik + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT tsc_keys + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(tsc_keys, CONFIG_INPUT_LOG_LEVEL); + +struct input_tsc_keys_child_data { + uint32_t buffer[CONFIG_INPUT_TSC_KEYS_BUFFER_WORD_SIZE]; + struct ring_buf rb; + enum { + INPUT_TSC_KEYS_EXPECT_DOWN, + INPUT_TSC_KEYS_EXPECT_UP, + } state; +}; + +struct input_tsc_keys_child_config { + char *label; + uint8_t group_index; + int32_t noise_threshold; + int zephyr_code; + struct input_tsc_keys_child_data *data; +}; + +struct input_tsc_keys_data { + struct k_timer sampling_timer; +}; + +struct input_tsc_keys_config { + const struct device *tsc_dev; + stm32_tsc_callback_t tsc_callback; + uint32_t sampling_interval_ms; + struct input_tsc_keys_child_config *children; + uint8_t child_num; +}; + +static void input_tsc_sampling_timer_callback(struct k_timer *timer) +{ + const struct device *dev = k_timer_user_data_get(timer); + + stm32_tsc_start(dev); +} + +static inline struct input_tsc_keys_child_config * +input_tsc_child_config_get(const struct device *dev, uint8_t group) +{ + const struct input_tsc_keys_config *config = dev->config; + + for (int i = 0; i < config->child_num; i++) { + const struct input_tsc_keys_child_config *child = &config->children[i]; + + if (child->group_index == group) { + return (struct input_tsc_keys_child_config *)child; + } + } + + return NULL; +} + +static void input_tsc_callback_handler(const struct device *dev, uint8_t group, uint32_t value) +{ + const struct input_tsc_keys_config *config = dev->config; + + const struct input_tsc_keys_child_config *child_config = + input_tsc_child_config_get(dev, group); + + if (!child_config) { + LOG_ERR("TSC@%p: No child config for group %d", config->tsc_dev, group); + return; + } + + struct input_tsc_keys_child_data *child_data = child_config->data; + + if (ring_buf_item_space_get(&child_data->rb) == 0) { + uint32_t oldest_point; + int32_t slope; + + (void)ring_buf_get(&child_data->rb, (uint8_t *)&oldest_point, sizeof(oldest_point)); + + slope = value - oldest_point; + if (slope < -child_config->noise_threshold && + child_data->state == INPUT_TSC_KEYS_EXPECT_DOWN) { + /* this is a key press, now expect a release */ + child_data->state = INPUT_TSC_KEYS_EXPECT_UP; + input_report_key(dev, child_config->zephyr_code, 1, false, K_NO_WAIT); + } else if (slope > child_config->noise_threshold && + child_data->state == INPUT_TSC_KEYS_EXPECT_UP) { + /* this is a key release, now expect a press */ + child_data->state = INPUT_TSC_KEYS_EXPECT_DOWN; + input_report_key(dev, child_config->zephyr_code, 0, false, K_NO_WAIT); + } + } + + (void)ring_buf_put(&child_data->rb, (uint8_t *)&value, sizeof(value)); +} + +int input_tsc_keys_init(const struct device *dev) +{ + const struct input_tsc_keys_config *config = dev->config; + struct input_tsc_keys_data *data = dev->data; + + if (!device_is_ready(config->tsc_dev)) { + LOG_ERR("TSC@%p: TSC device not ready", config->tsc_dev); + return -ENODEV; + } + + for (uint8_t i = 0; i < config->child_num; i++) { + const struct input_tsc_keys_child_config *child = &config->children[i]; + struct input_tsc_keys_child_data *child_data = child->data; + + ring_buf_item_init(&child_data->rb, CONFIG_INPUT_TSC_KEYS_BUFFER_WORD_SIZE, + child_data->buffer); + } + + stm32_tsc_register_callback(config->tsc_dev, config->tsc_callback); + + k_timer_init(&data->sampling_timer, input_tsc_sampling_timer_callback, NULL); + k_timer_user_data_set(&data->sampling_timer, (void *)config->tsc_dev); + k_timer_start(&data->sampling_timer, K_NO_WAIT, K_MSEC(config->sampling_interval_ms)); + + return 0; +} + +#define TSC_KEYS_CHILD(node_id) \ + { \ + .label = DT_PROP(node_id, label), \ + .group_index = DT_PROP(DT_PHANDLE(node_id, group), group), \ + .zephyr_code = DT_PROP(node_id, zephyr_code), \ + .noise_threshold = DT_PROP(node_id, noise_threshold), \ + .data = &tsc_keys_child_data_##node_id, \ + }, + +#define TSC_KEYS_CHILD_DATA(node_id) \ + static struct input_tsc_keys_child_data tsc_keys_child_data_##node_id; + +#define TSC_KEYS_INIT(node_id) \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(node_id, TSC_KEYS_CHILD_DATA) \ + static struct input_tsc_keys_child_config tsc_keys_children_##node_id[] = { \ + DT_INST_FOREACH_CHILD_STATUS_OKAY(node_id, TSC_KEYS_CHILD)}; \ + static void stm32_tsc_callback_##node_id(uint8_t group, uint32_t value) \ + { \ + input_tsc_callback_handler(DEVICE_DT_INST_GET(node_id), group, value); \ + } \ + \ + static struct input_tsc_keys_data tsc_keys_data_##node_id; \ + \ + static const struct input_tsc_keys_config tsc_keys_config_##node_id = { \ + .tsc_dev = DEVICE_DT_GET(DT_INST_PHANDLE(node_id, tsc_controller)), \ + .sampling_interval_ms = DT_INST_PROP(node_id, sampling_interval_ms), \ + .child_num = DT_INST_CHILD_NUM_STATUS_OKAY(node_id), \ + .children = tsc_keys_children_##node_id, \ + .tsc_callback = stm32_tsc_callback_##node_id, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(node_id, input_tsc_keys_init, NULL, &tsc_keys_data_##node_id, \ + &tsc_keys_config_##node_id, POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, \ + NULL); + +DT_INST_FOREACH_STATUS_OKAY(TSC_KEYS_INIT); diff --git a/dts/bindings/input/tsc-keys.yaml b/dts/bindings/input/tsc-keys.yaml new file mode 100644 index 00000000000000..a04ab137071d9e --- /dev/null +++ b/dts/bindings/input/tsc-keys.yaml @@ -0,0 +1,82 @@ +# Copyright (c) 2024 Arif Balik +# SPDX-License-Identifier: Apache-2.0 + +description: | + Input driver for STM32 Tocuh Sensing Controller (TSC). + + This node takes a st,stm32-tsc child node and applies + filters and calculations to detect an input event + Each of the `tsc-keys` child nodes represents a key + in the context of the input subsystem, and a group in + the context of the TSC controller, for more + information see drivers/misc/st,stm32-tsc.yaml + + Example: + + #include + + touch_buttons { + compatible = "tsc-keys"; + status = "okay"; + tsc-controller = <&tsc>; + sampling-interval-ms = <10>; + demo_button { + label = "Demo Button"; + group = <&tsc_group0>; + noise-threshold = <50>; + zephyr,code = ; + }; + }; + +compatible: "tsc-keys" + +include: + - name: base.yaml + property-allowlist: + - compatible + - zephyr,deferred-init + - label + - status + +properties: + tsc-controller: + type: phandle + required: true + description: Phandle to the TSC controller node. + sampling-interval-ms: + type: int + default: 1 + description: | + Sampling interval in milliseconds. + oversampling: + type: int + default: 10 + description: | + Over sampling factor. + +child-binding: + include: + - name: base.yaml + property-allowlist: + - label + + properties: + group: + type: phandle + required: true + description: Phandle to the TSC group node. + noise-threshold: + type: int + required: true + description: | + This value will be used to reject the noise for both + directions of the slope. + sticky-key-timeout-ms: + type: int + default: 10000 + description: | + Time in milliseconds to wait before releasing a key. + zephyr,code: + type: int + required: true + description: Key code to emit. diff --git a/samples/subsys/input/input_dump/boards/stm32u083c_dk.overlay b/samples/subsys/input/input_dump/boards/stm32u083c_dk.overlay new file mode 100644 index 00000000000000..3f843967f6f13d --- /dev/null +++ b/samples/subsys/input/input_dump/boards/stm32u083c_dk.overlay @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2024 Arif Balik + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&tsc { +status = "okay"; + +spread-spectrum; +spread-spectrum-deviation = <100>; +};