All of lore.kernel.org
 help / color / mirror / Atom feed
From: Xiong Nandi <xndchn@gmail.com>
To: dmitry.torokhov@gmail.com
Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org,
	Xiong Nandi <xndchn@gmail.com>,
	Gatien Chevallier <gatien.chevallier@foss.st.com>,
	Ingo Molnar <mingo@kernel.org>, Thomas Gleixner <tglx@kernel.org>,
	Marco Crivellari <marco.crivellari@suse.com>,
	Fabrice Gasnier <fabrice.gasnier@foss.st.com>
Subject: [PATCH] Input: gpio-keys - add full support of EV_REL and EV_ABS
Date: Fri, 20 Mar 2026 22:52:14 +0800	[thread overview]
Message-ID: <20260320145217.9088-1-xndchn@gmail.com> (raw)

gpio_keys_gpio_report_event() handled EV_ABS but silently ignored EV_REL,
while the polled driver supports both.  Extend the interrupt-driven driver
to fire an EV_REL event on button press.

For EV_ABS, use a shared atomic counter per (type, code) pair so that
a zero-value reset is sent only when the last active button on an axis
is released, avoiding premature axis resets when multiple buttons share
the same axis code.

Add gpio_keys_set_abs_params() to call input_set_abs_params() at setup
time, deriving the axis min/max from the configured button values.
Without this the input subsystem reports unbounded axis ranges.

Signed-off-by: Xiong Nandi <xndchn@gmail.com>
---
 drivers/input/keyboard/gpio_keys.c | 65 +++++++++++++++++++++++++++++-
 include/linux/gpio_keys.h          |  4 +-
 2 files changed, 65 insertions(+), 4 deletions(-)

diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index e19617485679..652a6932c52f 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -51,8 +51,10 @@ struct gpio_button_data {
 	spinlock_t lock;
 	bool disabled;
 	bool key_pressed;
+	bool axis_active;
 	bool suspended;
 	bool debounce_use_hrtimer;
+	atomic_t *axis_count;
 };
 
 struct gpio_keys_drvdata {
@@ -373,9 +375,16 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
 		return;
 	}
 
-	if (type == EV_ABS) {
-		if (state)
+	if (type == EV_ABS || type == EV_REL) {
+		if (state && !bdata->axis_active) {
+			bdata->axis_active = true;
+			atomic_inc(bdata->axis_count);
 			input_event(input, type, button->code, button->value);
+		} else if (!state && bdata->axis_active) {
+			bdata->axis_active = false;
+			if (atomic_dec_and_test(bdata->axis_count))
+				input_event(input, type, button->code, 0);
+		}
 	} else {
 		input_event(input, type, *bdata->code, state);
 	}
@@ -493,6 +502,27 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static void gpio_keys_set_abs_params(struct input_dev *input,
+				     struct gpio_keys_drvdata *ddata,
+				     unsigned int code)
+{
+	int i, min = 0, max = 0;
+
+	for (i = 0; i < ddata->pdata->nbuttons; i++) {
+		const struct gpio_keys_button *button = &ddata->pdata->buttons[i];
+
+		if (button->type != EV_ABS || button->code != code)
+			continue;
+
+		if (button->value < min)
+			min = button->value;
+		if (button->value > max)
+			max = button->value;
+	}
+
+	input_set_abs_params(input, code, min, max, 0, 0);
+}
+
 static int gpio_keys_setup_key(struct platform_device *pdev,
 				struct input_dev *input,
 				struct gpio_keys_drvdata *ddata,
@@ -651,6 +681,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
 	bdata->code = &ddata->keymap[idx];
 	*bdata->code = button->code;
 	input_set_capability(input, button->type ?: EV_KEY, *bdata->code);
+	if ((button->type ?: EV_KEY) == EV_ABS)
+		gpio_keys_set_abs_params(input, ddata, button->code);
 
 	/*
 	 * Install custom action to cancel release timer and
@@ -928,6 +960,35 @@ static int gpio_keys_probe(struct platform_device *pdev)
 
 	fwnode_handle_put(child);
 
+	/* Allocate shared axis counters for EV_ABS/EV_REL buttons */
+	for (i = 0; i < pdata->nbuttons; i++) {
+		struct gpio_button_data *bdata = &ddata->data[i];
+		unsigned int type = bdata->button->type ?: EV_KEY;
+		int j;
+
+		if (type != EV_ABS && type != EV_REL)
+			continue;
+
+		/* Reuse counter from an earlier button with same (type, code) */
+		for (j = 0; j < i; j++) {
+			struct gpio_button_data *prev = &ddata->data[j];
+			unsigned int prev_type = prev->button->type ?: EV_KEY;
+
+			if (prev_type == type &&
+			    prev->button->code == bdata->button->code) {
+				bdata->axis_count = prev->axis_count;
+				break;
+			}
+		}
+
+		if (!bdata->axis_count) {
+			bdata->axis_count = devm_kzalloc(dev,
+					sizeof(*bdata->axis_count), GFP_KERNEL);
+			if (!bdata->axis_count)
+				return -ENOMEM;
+		}
+	}
+
 	error = input_register_device(input);
 	if (error) {
 		dev_err(dev, "Unable to register input device, error: %d\n",
diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h
index 80fa930b04c6..75a745a32fe1 100644
--- a/include/linux/gpio_keys.h
+++ b/include/linux/gpio_keys.h
@@ -13,13 +13,13 @@ struct device;
  * @active_low:		%true indicates that button is considered
  *			depressed when gpio is low
  * @desc:		label that will be attached to button's gpio
- * @type:		input event type (%EV_KEY, %EV_SW, %EV_ABS)
+ * @type:		input event type (%EV_KEY, %EV_SW, %EV_ABS, %EV_REL)
  * @wakeup:		configure the button as a wake-up source
  * @wakeup_event_action:	event action to trigger wakeup
  * @debounce_interval:	debounce ticks interval in msecs
  * @can_disable:	%true indicates that userspace is allowed to
  *			disable button via sysfs
- * @value:		axis value for %EV_ABS
+ * @value:		axis value for %EV_ABS/%EV_REL
  * @irq:		Irq number in case of interrupt keys
  * @wakeirq:		Optional dedicated wake-up interrupt
  */
-- 
2.25.1


             reply	other threads:[~2026-03-20 14:52 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-20 14:52 Xiong Nandi [this message]
2026-03-21  7:06 ` [PATCH] Input: gpio-keys - add full support of EV_REL and EV_ABS Dmitry Torokhov
2026-03-22 11:35   ` [PATCH v2 0/3] " Xiong Nandi
2026-03-22 11:35   ` [PATCH v2 1/3] Input: gpio-keys - set EV_ABS axis parameters at setup time Xiong Nandi
2026-03-22 11:35   ` [PATCH v2 2/3] Input: gpio-keys - use shared axis counter for EV_ABS events Xiong Nandi
2026-03-22 11:35   ` [PATCH v2 3/3] Input: gpio-keys - add EV_REL event type support Xiong Nandi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260320145217.9088-1-xndchn@gmail.com \
    --to=xndchn@gmail.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=fabrice.gasnier@foss.st.com \
    --cc=gatien.chevallier@foss.st.com \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=marco.crivellari@suse.com \
    --cc=mingo@kernel.org \
    --cc=tglx@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.