sunxi: Backport patches needed for A64
[openwrt/staging/lynxis.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;