Skip to content

Commit

Permalink
drivers: input: added input_tsc_keys
Browse files Browse the repository at this point in the history
input_tsc_keys to detect key press releases
using STM32 TSC

Signed-off-by: Arif Balik <[email protected]>
  • Loading branch information
arifbalik committed Dec 1, 2024
1 parent 7ce39c3 commit 83a465d
Show file tree
Hide file tree
Showing 7 changed files with 303 additions and 2 deletions.
18 changes: 16 additions & 2 deletions boards/st/stm32u083c_dk/stm32u083c_dk.dts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = <INPUT_KEY_0>;
};

};
};

&usart1 {
Expand Down Expand Up @@ -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 = <TSC_IO2>;
sampling-io = <TSC_IO1>;
};

g6 {
tsc_group6: g6 {
group = <6>;
channel-ios = <TSC_IO2>;
sampling-io = <TSC_IO1>;
Expand Down
1 change: 1 addition & 0 deletions drivers/input/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions drivers/input/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 17 additions & 0 deletions drivers/input/Kconfig.tsc_keys
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright (c) 2024 Arif Balik <[email protected]>
# 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.
174 changes: 174 additions & 0 deletions drivers/input/input_tsc_keys.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*
* Copyright (c) 2024 Arif Balik <[email protected]>
* SPDX-License-Identifier: Apache-2.0
*/

#define DT_DRV_COMPAT tsc_keys

#include <autoconf.h>
#include <stdbool.h>
#include <stdlib.h>
#include <zephyr/device.h>
#include <zephyr/drivers/misc/stm32_tsc/stm32_tsc.h>
#include <zephyr/input/input.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/spsc_lockfree.h>
#include <zephyr/sys/spsc_pbuf.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys/ring_buffer.h>

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);
82 changes: 82 additions & 0 deletions dts/bindings/input/tsc-keys.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Copyright (c) 2024 Arif Balik <[email protected]>
# 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 <dt-bindings/input/input-event-codes.h>
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 = <INPUT_KEY_0>;
};
};
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.
12 changes: 12 additions & 0 deletions samples/subsys/input/input_dump/boards/stm32u083c_dk.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright (c) 2024 Arif Balik <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0
*/

&tsc {
status = "okay";

spread-spectrum;
spread-spectrum-deviation = <100>;
};

0 comments on commit 83a465d

Please sign in to comment.