From: Wadim Mueller <wafgo01@gmail.com>
To: William Breathitt Gray <wbg@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Rob Herring <robh@kernel.org>, Conor Dooley <conor+dt@kernel.org>
Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, Wadim Mueller <wafgo01@gmail.com>
Subject: [PATCH v4 0/3] counter: add GPIO-based quadrature encoder driver
Date: Fri, 15 May 2026 17:36:13 +0200 [thread overview]
Message-ID: <20260515153616.157605-1-wafgo01@gmail.com> (raw)
In-Reply-To: <20260501200749.20029-1-wafgo01@gmail.com>
This series adds a new counter subsystem driver which implements
quadrature encoder position tracking using plain GPIO pins with
edge-triggered interrupts.
The driver targets low- to medium-speed rotary encoders on SoCs where
hardware quadrature counter peripherals (eQEP, FTM, ...) are either
not available or already in use. It complements interrupt-cnt.c by
providing full A/B/Index quadrature decoding instead of just pulse
counting.
The strategic question from v3 -- "why kernel and not libgpiod in
userspace?" -- was already discussed in the v3 cover thread. A
reproducible benchmark on AM64x (kernel counter vs gpiomon/libgpiod
2.1.2, 3-run sweeps from 1 kHz up to 200 kHz) was posted there and
is also mirrored at https://github.com/wafgo/qenc-bench. William
accepted the case for a kernel implementation based on this, so i
will not repeat the numbers here, only the link.
Changes in v4 address the detailed review feedback from William on
PATCH 3/3 of v3:
Counter ABI / generic semantics:
- Drop the private gpio_qenc_function enum, store and exchange the
function as enum counter_function directly. function_read/write
become trivial accessors.
- Support the full set of generic Count functions:
INCREASE, DECREASE, PULSE_DIRECTION,
QUADRATURE_X1_{A,B}, QUADRATURE_X2_{A,B}, QUADRATURE_X4.
- Add COUNTER_SYNAPSE_ACTION_FALLING_EDGE to the synapse action
list and report it from action_read for the function modes
where it does apply.
- In QUADRATURE_X1_{A,B} the reported synapse action is now
direction-dependent (RISING_EDGE when going forward, FALLING_EDGE
when going backward) to match the Counter ABI semantics.
- Restructure action_read: default to NONE, handle the Index
synapse as a single early-return case, drop the per-function
if/else cascade.
- Use a dedicated action list for the Index synapse with only NONE
and RISING_EDGE, since the other synapse actions do not apply
there.
- Migrate the Index feature from a custom "index_enabled"
COUNTER_COMP_COUNT_BOOL to the generic COUNTER_COMP_PRESET +
COUNTER_COMP_PRESET_ENABLE pair. The Index ISR now loads the
preset value into count when preset_enable is set, like
intel-qep and other drivers do.
Driver internals:
- Change priv->count from s64 to u64. ceiling now defaults to
U64_MAX instead of using ceiling == 0 as a sentinel for "no
ceiling", which i think is also more clean.
- Rewrite gpio_qenc_update_count direction-first, +/-1, with
proper saturation at 0 and at ceiling.
- Introduce CREATE_QE_STATE(prev_a, prev_b, curr_a, curr_b) and a
single 16-entry X4 transition table indexed by the macro. The
delta == 2 "invalid transition" path is gone, the table just
has 0 in that slot.
- Use default: in the ISR switches instead of listing every
ignored case.
- Drop the now-redundant enabled flag in the ISRs. Gating happens
via enable_irq/disable_irq anyway and enable_read derives the
state from irq_get_irq_data() so there is only one source of
truth.
- Simplify enable_write: no !!, assign directly, split the two
branches by return.
- Drop the no-op events_configure() hook from counter_ops, this
one was just left over.
- Do not register a synapse for the Index signal when no Index
GPIO is wired (no zombie entries) and drop the corresponding
!gpio guard in signal_read which was only there to catch the
zombie case.
- Declare priv->cnts as a single-element array and use
ARRAY_SIZE(priv->cnts) for counter->num_counts, for consistency
with the rest of the subsystem.
- Rename the Count from "Position" to the more generic "Count",
since positioning is only one of the use cases for a quadrature
encoder.
Documentation / style:
- Add a short comment to the priv spinlock.
Krzysztofs "drop const on scalar parameters" note from PATCH 2/3
of v2 is also taken care of in this rewrite -- v3 was Acked-by
Conor only and did not carry code changes yet, so the const scalar
parameters survived there. In v4 there are no const-qualified scalar
parameters left in the driver.
The follow-up scope which was discussed with William -- COMPARE/FLOOR
components plus OVERFLOW/UNDERFLOW/THRESHOLD/DIRECTION_CHANGE events
-- is on purpose not included in v4. I will send those as a separate
series on top of this one once it lands, so the diff size stays
reviewable.
Changes in v4:
- Major review-driven rewrite of the driver (see above).
Changes in v3:
- Pick up Acked-by: Conor Dooley on the DT binding patch.
- No code changes.
Changes in v2:
- DT binding: rephrase description to describe the hardware, not
the driver/sysfs behaviour (Conor Dooley)
- DT binding: drop redundant example without index GPIO (Conor Dooley)
Wadim Mueller (3):
dt-bindings: counter: add gpio-quadrature-encoder binding
counter: add GPIO-based quadrature encoder driver
MAINTAINERS: add entry for GPIO quadrature encoder counter driver
.../counter/gpio-quadrature-encoder.yaml | 60 ++
MAINTAINERS | 7 +
drivers/counter/Kconfig | 15 +
drivers/counter/Makefile | 1 +
drivers/counter/gpio-quadrature-encoder.c | 739 ++++++++++++++++++
5 files changed, 822 insertions(+)
create mode 100644 Documentation/devicetree/bindings/counter/gpio-quadrature-encoder.yaml
create mode 100644 drivers/counter/gpio-quadrature-encoder.c
base-commit: 3cd8b194bf3428dfa53120fee47e827a7c495815
--
2.52.0
next prev parent reply other threads:[~2026-05-15 15:36 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-01 20:07 [PATCH v3 0/3] counter: add GPIO-based quadrature encoder driver Wadim Mueller
2026-05-01 20:07 ` [PATCH v3 1/3] dt-bindings: counter: add gpio-quadrature-encoder binding Wadim Mueller
2026-05-01 20:07 ` [PATCH v3 2/3] counter: add GPIO-based quadrature encoder driver Wadim Mueller
2026-05-04 20:54 ` Krzysztof Kozlowski
2026-05-04 21:15 ` Wadim Mueller
2026-05-15 5:48 ` William Breathitt Gray
2026-05-15 15:28 ` Wadim Mueller
2026-05-01 20:07 ` [PATCH v3 3/3] MAINTAINERS: add entry for GPIO quadrature encoder counter driver Wadim Mueller
2026-05-04 9:36 ` [PATCH v3 0/3] counter: add GPIO-based quadrature encoder driver William Breathitt Gray
2026-05-04 19:37 ` Wadim Mueller
2026-05-06 6:50 ` Wadim Mueller
2026-05-14 13:17 ` William Breathitt Gray
2026-05-15 15:36 ` Wadim Mueller [this message]
2026-05-15 15:36 ` [PATCH v4 1/3] dt-bindings: counter: add gpio-quadrature-encoder binding Wadim Mueller
2026-05-15 15:36 ` [PATCH v4 2/3] counter: add GPIO-based quadrature encoder driver Wadim Mueller
2026-05-15 16:14 ` sashiko-bot
2026-05-15 15:36 ` [PATCH v4 3/3] MAINTAINERS: add entry for GPIO quadrature encoder counter driver Wadim Mueller
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=20260515153616.157605-1-wafgo01@gmail.com \
--to=wafgo01@gmail.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=krzk+dt@kernel.org \
--cc=linux-iio@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=robh@kernel.org \
--cc=wbg@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.