aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/sunxi/patches-4.9/0040-pinctrl-sunxi-Add-support-for-interrupt-debouncing.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/sunxi/patches-4.9/0040-pinctrl-sunxi-Add-support-for-interrupt-debouncing.patch')
-rw-r--r--target/linux/sunxi/patches-4.9/0040-pinctrl-sunxi-Add-support-for-interrupt-debouncing.patch171
1 files changed, 171 insertions, 0 deletions
diff --git a/target/linux/sunxi/patches-4.9/0040-pinctrl-sunxi-Add-support-for-interrupt-debouncing.patch b/target/linux/sunxi/patches-4.9/0040-pinctrl-sunxi-Add-support-for-interrupt-debouncing.patch
new file mode 100644
index 0000000000..01cbe31bef
--- /dev/null
+++ b/target/linux/sunxi/patches-4.9/0040-pinctrl-sunxi-Add-support-for-interrupt-debouncing.patch
@@ -0,0 +1,171 @@
+From 7c926492d38a3feef4b4b29c91b7c03eb1b8b546 Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Mon, 14 Nov 2016 21:53:03 +0100
+Subject: pinctrl: sunxi: Add support for interrupt debouncing
+
+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 microsecond
+resolution. We can re-use the per-pin input-debounce property for that, so
+let's do it!
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+Acked-by: Rob Herring <robh@kernel.org>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+---
+ .../bindings/pinctrl/allwinner,sunxi-pinctrl.txt | 14 ++++
+ drivers/pinctrl/sunxi/pinctrl-sunxi.c | 84 ++++++++++++++++++++++
+ drivers/pinctrl/sunxi/pinctrl-sunxi.h | 7 ++
+ 3 files changed, 105 insertions(+)
+
+--- 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 input-debounce property. Any new
++device tree should set them.
++
++Optional properties:
++ - input-debounce: Array of debouncing periods in microseconds. One period per
++ irq bank found in the controller. 0 if no setup required.
++
++
+ Please refer to pinctrl-bindings.txt in this directory for details of the
+ common pinctrl bindings used by client devices.
+
+--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
++++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+@@ -1122,6 +1122,88 @@ static int sunxi_pinctrl_build_state(str
+ return 0;
+ }
+
++static int sunxi_pinctrl_get_debounce_div(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, "input-debounce", 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, "input-debounce",
++ i, &debounce);
++ if (ret)
++ return ret;
++
++ if (!debounce)
++ continue;
++
++ debounce_freq = DIV_ROUND_CLOSEST(USEC_PER_SEC, debounce);
++ losc_div = sunxi_pinctrl_get_debounce_div(losc,
++ debounce_freq,
++ &losc_diff);
++
++ 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;
++ }
++
++ 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)
+ {
+@@ -1284,6 +1366,8 @@ int sunxi_pinctrl_init(struct platform_d
+ pctl);
+ }
+
++ sunxi_pinctrl_setup_debounce(pctl, node);
++
+ dev_info(&pdev->dev, "initialized sunXi PIO driver\n");
+
+ return 0;
+--- 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
+@@ -265,6 +267,11 @@ static inline u32 sunxi_irq_ctrl_offset(
+ 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;