[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20241119140805.3345412-1-paulk@sys-base.io>
Date: Tue, 19 Nov 2024 15:08:05 +0100
From: Paul Kocialkowski <paulk@...-base.io>
To: linux-arm-kernel@...ts.infradead.org,
linux-sunxi@...ts.linux.dev,
linux-kernel@...r.kernel.org
Cc: Uwe Kleine-König <ukleinek@...nel.org>,
Chen-Yu Tsai <wens@...e.org>,
Jernej Skrabec <jernej.skrabec@...il.com>,
Samuel Holland <samuel@...lland.org>,
Linus Walleij <linus.walleij@...aro.org>,
Maxime Ripard <mripard@...nel.org>,
Paul Kocialkowski <contact@...lk.fr>
Subject: [PATCH] pinctrl: sunxi: Use minimal debouncing period as default
From: Paul Kocialkowski <contact@...lk.fr>
The sunxi external interrupts (available from GPIO pins) come with a
built-in debouncing mechanism that cannot be disabled. It can be
configured to use either the low-frequency oscillator (32 KHz) or the
high-frequency oscillator (24 MHz), with a pre-scaler.
The pinctrl code supports an input-debounce device-tree property to set
a specific debouncing period and choose which clock source is most
relevant. However the property is specified in microseconds, which is
longer than the minimal period achievable from the high-frequency
oscillator without a pre-scaler.
When the property is missing, the reset configuration is kept, which
selects the low-frequency oscillator without pre-scaling. This severely
limits the possible interrupt periods that can be detected.
Instead of keeping this default, use the minimal debouncing period from
the high-frequency oscillator without a pre-scaler to allow the largest
possible range of interrupt periods.
This issue was encountered with a peripheral that generates active-low
interrupts for 1 us. No interrupt was detected with the default setup,
while it is now correctly detected with this change.
Signed-off-by: Paul Kocialkowski <contact@...lk.fr>
---
drivers/pinctrl/sunxi/pinctrl-sunxi.c | 49 ++++++++++++++++-----------
1 file changed, 29 insertions(+), 20 deletions(-)
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index 73bcf806af0e..06c650d97645 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -1416,6 +1416,7 @@ static int sunxi_pinctrl_setup_debounce(struct sunxi_pinctrl *pctl,
unsigned int hosc_diff, losc_diff;
unsigned int hosc_div, losc_div;
struct clk *hosc, *losc;
+ bool debounce_minimal = false;
u8 div, src;
int i, ret;
@@ -1423,9 +1424,9 @@ static int sunxi_pinctrl_setup_debounce(struct sunxi_pinctrl *pctl,
if (of_clk_get_parent_count(node) != 3)
return 0;
- /* If we don't have any setup, bail out */
+ /* If we don't have any setup, use minimal debouncing. */
if (!of_property_present(node, "input-debounce"))
- return 0;
+ debounce_minimal = true;
losc = devm_clk_get(pctl->dev, "losc");
if (IS_ERR(losc))
@@ -1439,29 +1440,37 @@ static int sunxi_pinctrl_setup_debounce(struct sunxi_pinctrl *pctl,
unsigned long debounce_freq;
u32 debounce;
- ret = of_property_read_u32_index(node, "input-debounce",
- i, &debounce);
- if (ret)
- return ret;
+ if (!debounce_minimal) {
+ ret = of_property_read_u32_index(node, "input-debounce",
+ i, &debounce);
+ if (ret)
+ return ret;
- if (!debounce)
- continue;
+ if (!debounce)
+ continue;
- debounce_freq = DIV_ROUND_CLOSEST(USEC_PER_SEC, debounce);
- losc_div = sunxi_pinctrl_get_debounce_div(losc,
- debounce_freq,
- &losc_diff);
+ debounce_freq = DIV_ROUND_CLOSEST(USEC_PER_SEC,
+ debounce);
- hosc_div = sunxi_pinctrl_get_debounce_div(hosc,
- debounce_freq,
- &hosc_diff);
+ losc_div = sunxi_pinctrl_get_debounce_div(losc,
+ debounce_freq,
+ &losc_diff);
- if (hosc_diff < losc_diff) {
- div = hosc_div;
- src = 1;
+ hosc_div = sunxi_pinctrl_get_debounce_div(hosc,
+ debounce_freq,
+ &hosc_diff);
+
+ if (hosc_diff < losc_diff) {
+ div = hosc_div;
+ src = 1;
+ } else {
+ div = losc_div;
+ src = 0;
+ }
} else {
- div = losc_div;
- src = 0;
+ /* Achieve minimal debouncing using undivided hosc. */
+ div = 0;
+ src = 1;
}
writel(src | div << 4,
--
2.47.0
Powered by blists - more mailing lists