v1.5 branch refresh based upon upstream master @ c8677ca89e53e3be7988d54280fce166cc894a7e
[librecmc/librecmc.git] / target / linux / sunxi / patches-4.9 / 0040-pinctrl-sunxi-Add-support-for-interrupt-debouncing.patch
1 From 7c926492d38a3feef4b4b29c91b7c03eb1b8b546 Mon Sep 17 00:00:00 2001
2 From: Maxime Ripard <maxime.ripard@free-electrons.com>
3 Date: Mon, 14 Nov 2016 21:53:03 +0100
4 Subject: pinctrl: sunxi: Add support for interrupt debouncing
5
6 The pin controller found in the Allwinner SoCs has support for interrupts
7 debouncing.
8
9 However, this is not done per-pin, preventing us from using the generic
10 pinconf binding for that, but per irq bank, which, depending on the SoC,
11 ranges from one to five.
12
13 Introduce a device-wide property to deal with this using a microsecond
14 resolution. We can re-use the per-pin input-debounce property for that, so
15 let's do it!
16
17 Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
18 Acked-by: Rob Herring <robh@kernel.org>
19 Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
20 ---
21  .../bindings/pinctrl/allwinner,sunxi-pinctrl.txt   | 14 ++++
22  drivers/pinctrl/sunxi/pinctrl-sunxi.c              | 84 ++++++++++++++++++++++
23  drivers/pinctrl/sunxi/pinctrl-sunxi.h              |  7 ++
24  3 files changed, 105 insertions(+)
25
26 --- a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
27 +++ b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
28 @@ -28,6 +28,20 @@ Required properties:
29  - reg: Should contain the register physical address and length for the
30    pin controller.
31  
32 +- clocks: phandle to the clocks feeding the pin controller:
33 +  - "apb": the gated APB parent clock
34 +  - "hosc": the high frequency oscillator in the system
35 +  - "losc": the low frequency oscillator in the system
36 +
37 +Note: For backward compatibility reasons, the hosc and losc clocks are only
38 +required if you need to use the optional input-debounce property. Any new
39 +device tree should set them.
40 +
41 +Optional properties:
42 +  - input-debounce: Array of debouncing periods in microseconds. One period per
43 +    irq bank found in the controller. 0 if no setup required.
44 +
45 +
46  Please refer to pinctrl-bindings.txt in this directory for details of the
47  common pinctrl bindings used by client devices.
48  
49 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
50 +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
51 @@ -1122,6 +1122,88 @@ static int sunxi_pinctrl_build_state(str
52         return 0;
53  }
54  
55 +static int sunxi_pinctrl_get_debounce_div(struct clk *clk, int freq, int *diff)
56 +{
57 +       unsigned long clock = clk_get_rate(clk);
58 +       unsigned int best_diff = ~0, best_div;
59 +       int i;
60 +
61 +       for (i = 0; i < 8; i++) {
62 +               int cur_diff = abs(freq - (clock >> i));
63 +
64 +               if (cur_diff < best_diff) {
65 +                       best_diff = cur_diff;
66 +                       best_div = i;
67 +               }
68 +       }
69 +
70 +       *diff = best_diff;
71 +       return best_div;
72 +}
73 +
74 +static int sunxi_pinctrl_setup_debounce(struct sunxi_pinctrl *pctl,
75 +                                       struct device_node *node)
76 +{
77 +       unsigned int hosc_diff, losc_diff;
78 +       unsigned int hosc_div, losc_div;
79 +       struct clk *hosc, *losc;
80 +       u8 div, src;
81 +       int i, ret;
82 +
83 +       /* Deal with old DTs that didn't have the oscillators */
84 +       if (of_count_phandle_with_args(node, "clocks", "#clock-cells") != 3)
85 +               return 0;
86 +
87 +       /* If we don't have any setup, bail out */
88 +       if (!of_find_property(node, "input-debounce", NULL))
89 +               return 0;
90 +
91 +       losc = devm_clk_get(pctl->dev, "losc");
92 +       if (IS_ERR(losc))
93 +               return PTR_ERR(losc);
94 +
95 +       hosc = devm_clk_get(pctl->dev, "hosc");
96 +       if (IS_ERR(hosc))
97 +               return PTR_ERR(hosc);
98 +
99 +       for (i = 0; i < pctl->desc->irq_banks; i++) {
100 +               unsigned long debounce_freq;
101 +               u32 debounce;
102 +
103 +               ret = of_property_read_u32_index(node, "input-debounce",
104 +                                                i, &debounce);
105 +               if (ret)
106 +                       return ret;
107 +
108 +               if (!debounce)
109 +                       continue;
110 +
111 +               debounce_freq = DIV_ROUND_CLOSEST(USEC_PER_SEC, debounce);
112 +               losc_div = sunxi_pinctrl_get_debounce_div(losc,
113 +                                                         debounce_freq,
114 +                                                         &losc_diff);
115 +
116 +               hosc_div = sunxi_pinctrl_get_debounce_div(hosc,
117 +                                                         debounce_freq,
118 +                                                         &hosc_diff);
119 +
120 +               if (hosc_diff < losc_diff) {
121 +                       div = hosc_div;
122 +                       src = 1;
123 +               } else {
124 +                       div = losc_div;
125 +                       src = 0;
126 +               }
127 +
128 +               writel(src | div << 4,
129 +                      pctl->membase +
130 +                      sunxi_irq_debounce_reg_from_bank(i,
131 +                                                       pctl->desc->irq_bank_base));
132 +       }
133 +
134 +       return 0;
135 +}
136 +
137  int sunxi_pinctrl_init(struct platform_device *pdev,
138                        const struct sunxi_pinctrl_desc *desc)
139  {
140 @@ -1284,6 +1366,8 @@ int sunxi_pinctrl_init(struct platform_d
141                                                  pctl);
142         }
143  
144 +       sunxi_pinctrl_setup_debounce(pctl, node);
145 +
146         dev_info(&pdev->dev, "initialized sunXi PIO driver\n");
147  
148         return 0;
149 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h
150 +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
151 @@ -69,6 +69,8 @@
152  #define IRQ_STATUS_IRQ_BITS            1
153  #define IRQ_STATUS_IRQ_MASK            ((1 << IRQ_STATUS_IRQ_BITS) - 1)
154  
155 +#define IRQ_DEBOUNCE_REG       0x218
156 +
157  #define IRQ_MEM_SIZE           0x20
158  
159  #define IRQ_EDGE_RISING                0x00
160 @@ -265,6 +267,11 @@ static inline u32 sunxi_irq_ctrl_offset(
161         return irq_num * IRQ_CTRL_IRQ_BITS;
162  }
163  
164 +static inline u32 sunxi_irq_debounce_reg_from_bank(u8 bank, unsigned bank_base)
165 +{
166 +       return IRQ_DEBOUNCE_REG + (bank_base + bank) * IRQ_MEM_SIZE;
167 +}
168 +
169  static inline u32 sunxi_irq_status_reg_from_bank(u8 bank, unsigned bank_base)
170  {
171         return IRQ_STATUS_REG + (bank_base + bank) * IRQ_MEM_SIZE;