OpenWrt – Blame information for rev 4
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
4 | office | 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; |