diff options
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.patch | 171 |
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; |