diff mbox

[1/2] pinctrl: sunxi: Add support for interrupt debouncing

Message ID fa022cca9917917ace4af7d5e852c9348ec5b553.1476868462.git-series.maxime.ripard@free-electrons.com
State New
Headers show

Commit Message

Maxime Ripard Oct. 19, 2016, 9:15 a.m. UTC
The pin controller found in the Allwinner SoCs has support for interrupts
debouncing.

However, this is not done per-pin, preventing us from using the generic
pinconf binding for that, but per irq bank, which, depending on the SoC,
ranges from one to five.

Introduce a device-wide property to deal with this using a nanosecond
resolution.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt | 14 ++++++++++++-
 drivers/pinctrl/sunxi/pinctrl-sunxi.c                                 | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 drivers/pinctrl/sunxi/pinctrl-sunxi.h                                 |  7 ++++++-
 3 files changed, 102 insertions(+), 0 deletions(-)

Comments

Linus Walleij Oct. 20, 2016, 1:04 p.m. UTC | #1
On Wed, Oct 19, 2016 at 11:15 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:

> The pin controller found in the Allwinner SoCs has support for interrupts
> debouncing.
>
> However, this is not done per-pin, preventing us from using the generic
> pinconf binding for that,

How typical.

> but per irq bank, which, depending on the SoC,
> ranges from one to five.
>
> Introduce a device-wide property to deal with this using a nanosecond
> resolution.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
(...)
> +Note: For backward compatibility reasons, the hosc and losc clocks are
> +only required if you need to use the optional
> +allwinner,debounce-time-ns property. Any new device tree should set them.
> +
> +Optional properties:
> +  - allwinner,debounce-time-ns: Array of debouncing periods in
> +    nanoseconds. One period per irq bank found in the controller

Do you really *need* to specify this with nanosecond resolution?

Else I would suggest to use microsecond resolution and just use
the generic binding (input-debounce) but on the device node instead
of the specific handler.

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Maxime Ripard Oct. 20, 2016, 1:56 p.m. UTC | #2
Hi Linus,

On Thu, Oct 20, 2016 at 03:04:46PM +0200, Linus Walleij wrote:
> On Wed, Oct 19, 2016 at 11:15 AM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> 
> > The pin controller found in the Allwinner SoCs has support for interrupts
> > debouncing.
> >
> > However, this is not done per-pin, preventing us from using the generic
> > pinconf binding for that,
> 
> How typical.
> 
> > but per irq bank, which, depending on the SoC,
> > ranges from one to five.
> >
> > Introduce a device-wide property to deal with this using a nanosecond
> > resolution.
> >
> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> (...)
> > +Note: For backward compatibility reasons, the hosc and losc clocks are
> > +only required if you need to use the optional
> > +allwinner,debounce-time-ns property. Any new device tree should set them.
> > +
> > +Optional properties:
> > +  - allwinner,debounce-time-ns: Array of debouncing periods in
> > +    nanoseconds. One period per irq bank found in the controller
> 
> Do you really *need* to specify this with nanosecond resolution?
>
> Else I would suggest to use microsecond resolution and just use
> the generic binding (input-debounce) but on the device node instead
> of the specific handler.

Theorically, the debouncing clock can be set at 24MHz, which means a
42ns resolution.

I've seen that the other bindings usually use microseconds, but in our
case, we can really go lower than that.

I don't really know if it makes sense though.

Thanks!
Maxime
Maxime Ripard Nov. 2, 2016, 7:51 p.m. UTC | #3
Hi Linus,

On Thu, Oct 20, 2016 at 03:56:25PM +0200, Maxime Ripard wrote:
> Hi Linus,
> 
> On Thu, Oct 20, 2016 at 03:04:46PM +0200, Linus Walleij wrote:
> > On Wed, Oct 19, 2016 at 11:15 AM, Maxime Ripard
> > <maxime.ripard@free-electrons.com> wrote:
> > 
> > > The pin controller found in the Allwinner SoCs has support for interrupts
> > > debouncing.
> > >
> > > However, this is not done per-pin, preventing us from using the generic
> > > pinconf binding for that,
> > 
> > How typical.
> > 
> > > but per irq bank, which, depending on the SoC,
> > > ranges from one to five.
> > >
> > > Introduce a device-wide property to deal with this using a nanosecond
> > > resolution.
> > >
> > > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > (...)
> > > +Note: For backward compatibility reasons, the hosc and losc clocks are
> > > +only required if you need to use the optional
> > > +allwinner,debounce-time-ns property. Any new device tree should set them.
> > > +
> > > +Optional properties:
> > > +  - allwinner,debounce-time-ns: Array of debouncing periods in
> > > +    nanoseconds. One period per irq bank found in the controller
> > 
> > Do you really *need* to specify this with nanosecond resolution?
> >
> > Else I would suggest to use microsecond resolution and just use
> > the generic binding (input-debounce) but on the device node instead
> > of the specific handler.
> 
> Theorically, the debouncing clock can be set at 24MHz, which means a
> 42ns resolution.
> 
> I've seen that the other bindings usually use microseconds, but in our
> case, we can really go lower than that.
> 
> I don't really know if it makes sense though.

Any comments on this?

Thanks,
Maxime
Linus Walleij Nov. 7, 2016, 9:40 a.m. UTC | #4
On Wed, Nov 2, 2016 at 8:51 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> On Thu, Oct 20, 2016 at 03:56:25PM +0200, Maxime Ripard wrote:
>> On Thu, Oct 20, 2016 at 03:04:46PM +0200, Linus Walleij wrote:
>> > On Wed, Oct 19, 2016 at 11:15 AM, Maxime Ripard
>> > <maxime.ripard@free-electrons.com> wrote:
>> >
>> > > The pin controller found in the Allwinner SoCs has support for interrupts
>> > > debouncing.
>> > >
>> > > However, this is not done per-pin, preventing us from using the generic
>> > > pinconf binding for that,
>> >
>> > How typical.
>> >
>> > > but per irq bank, which, depending on the SoC,
>> > > ranges from one to five.
>> > >
>> > > Introduce a device-wide property to deal with this using a nanosecond
>> > > resolution.
>> > >
>> > > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
>> > (...)
>> > > +Note: For backward compatibility reasons, the hosc and losc clocks are
>> > > +only required if you need to use the optional
>> > > +allwinner,debounce-time-ns property. Any new device tree should set them.
>> > > +
>> > > +Optional properties:
>> > > +  - allwinner,debounce-time-ns: Array of debouncing periods in
>> > > +    nanoseconds. One period per irq bank found in the controller
>> >
>> > Do you really *need* to specify this with nanosecond resolution?
>> >
>> > Else I would suggest to use microsecond resolution and just use
>> > the generic binding (input-debounce) but on the device node instead
>> > of the specific handler.
>>
>> Theorically, the debouncing clock can be set at 24MHz, which means a
>> 42ns resolution.
>>
>> I've seen that the other bindings usually use microseconds, but in our
>> case, we can really go lower than that.
>>
>> I don't really know if it makes sense though.
>
> Any comments on this?

My first thought: can you atleast support both?

My preference would be to add the standard binding and use that,
and the day you realize that "howli mackarowli, this thingofabob
actually needs to specify with nanosecond precision" then we
could add the nanosecond granularity binding?

Yours,
Linus Walleij
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Maxime Ripard Nov. 8, 2016, 7:23 p.m. UTC | #5
On Mon, Nov 07, 2016 at 10:40:04AM +0100, Linus Walleij wrote:
> On Wed, Nov 2, 2016 at 8:51 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > On Thu, Oct 20, 2016 at 03:56:25PM +0200, Maxime Ripard wrote:
> >> On Thu, Oct 20, 2016 at 03:04:46PM +0200, Linus Walleij wrote:
> >> > On Wed, Oct 19, 2016 at 11:15 AM, Maxime Ripard
> >> > <maxime.ripard@free-electrons.com> wrote:
> >> >
> >> > > The pin controller found in the Allwinner SoCs has support for interrupts
> >> > > debouncing.
> >> > >
> >> > > However, this is not done per-pin, preventing us from using the generic
> >> > > pinconf binding for that,
> >> >
> >> > How typical.
> >> >
> >> > > but per irq bank, which, depending on the SoC,
> >> > > ranges from one to five.
> >> > >
> >> > > Introduce a device-wide property to deal with this using a nanosecond
> >> > > resolution.
> >> > >
> >> > > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> >> > (...)
> >> > > +Note: For backward compatibility reasons, the hosc and losc clocks are
> >> > > +only required if you need to use the optional
> >> > > +allwinner,debounce-time-ns property. Any new device tree should set them.
> >> > > +
> >> > > +Optional properties:
> >> > > +  - allwinner,debounce-time-ns: Array of debouncing periods in
> >> > > +    nanoseconds. One period per irq bank found in the controller
> >> >
> >> > Do you really *need* to specify this with nanosecond resolution?
> >> >
> >> > Else I would suggest to use microsecond resolution and just use
> >> > the generic binding (input-debounce) but on the device node instead
> >> > of the specific handler.
> >>
> >> Theorically, the debouncing clock can be set at 24MHz, which means a
> >> 42ns resolution.
> >>
> >> I've seen that the other bindings usually use microseconds, but in our
> >> case, we can really go lower than that.
> >>
> >> I don't really know if it makes sense though.
> >
> > Any comments on this?
> 
> My first thought: can you atleast support both?
> 
> My preference would be to add the standard binding and use that,
> and the day you realize that "howli mackarowli, this thingofabob
> actually needs to specify with nanosecond precision" then we
> could add the nanosecond granularity binding?

That works for me. I'll resend the patch.

Thanks!
Maxime
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
index 1685821eea41..1456507844aa 100644
--- a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
@@ -28,6 +28,20 @@  Required properties:
 - reg: Should contain the register physical address and length for the
   pin controller.
 
+- clocks: phandle to the clocks feeding the pin controller:
+  - "apb": the gated APB parent clock
+  - "hosc": the high frequency oscillator in the system
+  - "losc": the low frequency oscillator in the system
+
+Note: For backward compatibility reasons, the hosc and losc clocks are
+only required if you need to use the optional
+allwinner,debounce-time-ns property. Any new device tree should set them.
+
+Optional properties:
+  - allwinner,debounce-time-ns: Array of debouncing periods in
+    nanoseconds. One period per irq bank found in the controller
+
+
 Please refer to pinctrl-bindings.txt in this directory for details of the
 common pinctrl bindings used by client devices.
 
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index 0facbea5f465..9d420fb9a35a 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -870,6 +870,85 @@  static int sunxi_pinctrl_build_state(struct platform_device *pdev)
 	return 0;
 }
 
+static int sunxi_pinctrl_compute_debounce(struct clk *clk, int freq, int *diff)
+{
+	unsigned long clock = clk_get_rate(clk);
+	unsigned int best_diff = ~0, best_div;
+	int i;
+
+	for (i = 0; i < 8; i++) {
+		int cur_diff = abs(freq - (clock >> i));
+
+		if (cur_diff < best_diff) {
+			best_diff = cur_diff;
+			best_div = i;
+		}
+	}
+
+	*diff = best_diff;
+	return best_div;
+}
+
+static int sunxi_pinctrl_setup_debounce(struct sunxi_pinctrl *pctl,
+					struct device_node *node)
+{
+	unsigned int hosc_diff, losc_diff;
+	unsigned int hosc_div, losc_div;
+	struct clk *hosc, *losc;
+	u8 div, src;
+	int i, ret;
+
+	/* Deal with old DTs that didn't have the oscillators */
+	if (of_count_phandle_with_args(node, "clocks", "#clock-cells") != 3)
+		return 0;
+
+	/* If we don't have any setup, bail out */
+	if (!of_find_property(node, "allwinner,debounce-time-ns", NULL))
+		return 0;
+
+	losc = devm_clk_get(pctl->dev, "losc");
+	if (IS_ERR(losc))
+		return PTR_ERR(losc);
+
+	hosc = devm_clk_get(pctl->dev, "hosc");
+	if (IS_ERR(hosc))
+		return PTR_ERR(hosc);
+
+	for (i = 0; i < pctl->desc->irq_banks; i++) {
+		unsigned long debounce_freq;
+		u32 debounce;
+
+		ret = of_property_read_u32_index(node, "allwinner,debounce-time-ns",
+						 i, &debounce);
+		if (ret)
+			return ret;
+
+		debounce_freq = NSEC_PER_SEC / debounce;
+		losc_div = sunxi_pinctrl_compute_debounce(losc,
+							  debounce_freq,
+							  &losc_diff);
+
+		hosc_div = sunxi_pinctrl_compute_debounce(hosc,
+							  debounce_freq,
+							  &hosc_diff);
+
+		if (hosc_diff < losc_diff) {
+			div = hosc_div;
+			src = 1;
+		} else {
+			div = losc_div;
+			src = 0;
+		}
+
+		writel(src | div << 4,
+		       pctl->membase +
+		       sunxi_irq_debounce_reg_from_bank(i,
+							pctl->desc->irq_bank_base));
+	}
+
+	return 0;
+}
+
 int sunxi_pinctrl_init(struct platform_device *pdev,
 		       const struct sunxi_pinctrl_desc *desc)
 {
@@ -1032,6 +1111,8 @@  int sunxi_pinctrl_init(struct platform_device *pdev,
 						 pctl);
 	}
 
+	sunxi_pinctrl_setup_debounce(pctl, node);
+
 	dev_info(&pdev->dev, "initialized sunXi PIO driver\n");
 
 	return 0;
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
index 0afce1ab12d0..c0d97fe58e84 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
@@ -69,6 +69,8 @@ 
 #define IRQ_STATUS_IRQ_BITS		1
 #define IRQ_STATUS_IRQ_MASK		((1 << IRQ_STATUS_IRQ_BITS) - 1)
 
+#define IRQ_DEBOUNCE_REG	0x218
+
 #define IRQ_MEM_SIZE		0x20
 
 #define IRQ_EDGE_RISING		0x00
@@ -266,6 +268,11 @@  static inline u32 sunxi_irq_ctrl_offset(u16 irq)
 	return irq_num * IRQ_CTRL_IRQ_BITS;
 }
 
+static inline u32 sunxi_irq_debounce_reg_from_bank(u8 bank, unsigned bank_base)
+{
+	return IRQ_DEBOUNCE_REG + (bank_base + bank) * IRQ_MEM_SIZE;
+}
+
 static inline u32 sunxi_irq_status_reg_from_bank(u8 bank, unsigned bank_base)
 {
 	return IRQ_STATUS_REG + (bank_base + bank) * IRQ_MEM_SIZE;