forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-01-31 f70575805708cabdedea7498aaa3f710fde4d920
kernel/drivers/irqchip/irq-meson-gpio.c
....@@ -1,22 +1,9 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Copyright (c) 2015 Endless Mobile, Inc.
34 * Author: Carlo Caione <carlo@endlessm.com>
45 * Copyright (c) 2016 BayLibre, SAS.
56 * Author: Jerome Brunet <jbrunet@baylibre.com>
6
- *
7
- * This program is free software; you can redistribute it and/or modify
8
- * it under the terms of version 2 of the GNU General Public License as
9
- * published by the Free Software Foundation.
10
- *
11
- * This program is distributed in the hope that it will be useful, but
12
- * WITHOUT ANY WARRANTY; without even the implied warranty of
13
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
- * General Public License for more details.
15
- *
16
- * You should have received a copy of the GNU General Public License
17
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
18
- * The full GNU General Public License is included in this distribution
19
- * in the file called COPYING.
207 */
218
229 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
....@@ -28,6 +15,7 @@
2815 #include <linux/irqchip.h>
2916 #include <linux/of.h>
3017 #include <linux/of_address.h>
18
+#include <linux/of_irq.h>
3119
3220 #define NUM_CHANNEL 8
3321 #define MAX_INPUT_MUX 256
....@@ -37,34 +25,101 @@
3725 #define REG_PIN_47_SEL 0x08
3826 #define REG_FILTER_SEL 0x0c
3927
40
-#define REG_EDGE_POL_MASK(x) (BIT(x) | BIT(16 + (x)))
41
-#define REG_EDGE_POL_EDGE(x) BIT(x)
42
-#define REG_EDGE_POL_LOW(x) BIT(16 + (x))
28
+/* use for A1 like chips */
29
+#define REG_PIN_A1_SEL 0x04
30
+
31
+/*
32
+ * Note: The S905X3 datasheet reports that BOTH_EDGE is controlled by
33
+ * bits 24 to 31. Tests on the actual HW show that these bits are
34
+ * stuck at 0. Bits 8 to 15 are responsive and have the expected
35
+ * effect.
36
+ */
37
+#define REG_EDGE_POL_EDGE(params, x) BIT((params)->edge_single_offset + (x))
38
+#define REG_EDGE_POL_LOW(params, x) BIT((params)->pol_low_offset + (x))
39
+#define REG_BOTH_EDGE(params, x) BIT((params)->edge_both_offset + (x))
40
+#define REG_EDGE_POL_MASK(params, x) ( \
41
+ REG_EDGE_POL_EDGE(params, x) | \
42
+ REG_EDGE_POL_LOW(params, x) | \
43
+ REG_BOTH_EDGE(params, x))
4344 #define REG_PIN_SEL_SHIFT(x) (((x) % 4) * 8)
4445 #define REG_FILTER_SEL_SHIFT(x) ((x) * 4)
4546
46
-struct meson_gpio_irq_params {
47
- unsigned int nr_hwirq;
47
+struct meson_gpio_irq_controller;
48
+static void meson8_gpio_irq_sel_pin(struct meson_gpio_irq_controller *ctl,
49
+ unsigned int channel, unsigned long hwirq);
50
+static void meson_gpio_irq_init_dummy(struct meson_gpio_irq_controller *ctl);
51
+static void meson_a1_gpio_irq_sel_pin(struct meson_gpio_irq_controller *ctl,
52
+ unsigned int channel,
53
+ unsigned long hwirq);
54
+static void meson_a1_gpio_irq_init(struct meson_gpio_irq_controller *ctl);
55
+
56
+struct irq_ctl_ops {
57
+ void (*gpio_irq_sel_pin)(struct meson_gpio_irq_controller *ctl,
58
+ unsigned int channel, unsigned long hwirq);
59
+ void (*gpio_irq_init)(struct meson_gpio_irq_controller *ctl);
4860 };
4961
62
+struct meson_gpio_irq_params {
63
+ unsigned int nr_hwirq;
64
+ bool support_edge_both;
65
+ unsigned int edge_both_offset;
66
+ unsigned int edge_single_offset;
67
+ unsigned int pol_low_offset;
68
+ unsigned int pin_sel_mask;
69
+ struct irq_ctl_ops ops;
70
+};
71
+
72
+#define INIT_MESON_COMMON(irqs, init, sel) \
73
+ .nr_hwirq = irqs, \
74
+ .ops = { \
75
+ .gpio_irq_init = init, \
76
+ .gpio_irq_sel_pin = sel, \
77
+ },
78
+
79
+#define INIT_MESON8_COMMON_DATA(irqs) \
80
+ INIT_MESON_COMMON(irqs, meson_gpio_irq_init_dummy, \
81
+ meson8_gpio_irq_sel_pin) \
82
+ .edge_single_offset = 0, \
83
+ .pol_low_offset = 16, \
84
+ .pin_sel_mask = 0xff, \
85
+
86
+#define INIT_MESON_A1_COMMON_DATA(irqs) \
87
+ INIT_MESON_COMMON(irqs, meson_a1_gpio_irq_init, \
88
+ meson_a1_gpio_irq_sel_pin) \
89
+ .support_edge_both = true, \
90
+ .edge_both_offset = 16, \
91
+ .edge_single_offset = 8, \
92
+ .pol_low_offset = 0, \
93
+ .pin_sel_mask = 0x7f, \
94
+
5095 static const struct meson_gpio_irq_params meson8_params = {
51
- .nr_hwirq = 134,
96
+ INIT_MESON8_COMMON_DATA(134)
5297 };
5398
5499 static const struct meson_gpio_irq_params meson8b_params = {
55
- .nr_hwirq = 119,
100
+ INIT_MESON8_COMMON_DATA(119)
56101 };
57102
58103 static const struct meson_gpio_irq_params gxbb_params = {
59
- .nr_hwirq = 133,
104
+ INIT_MESON8_COMMON_DATA(133)
60105 };
61106
62107 static const struct meson_gpio_irq_params gxl_params = {
63
- .nr_hwirq = 110,
108
+ INIT_MESON8_COMMON_DATA(110)
64109 };
65110
66111 static const struct meson_gpio_irq_params axg_params = {
67
- .nr_hwirq = 100,
112
+ INIT_MESON8_COMMON_DATA(100)
113
+};
114
+
115
+static const struct meson_gpio_irq_params sm1_params = {
116
+ INIT_MESON8_COMMON_DATA(100)
117
+ .support_edge_both = true,
118
+ .edge_both_offset = 8,
119
+};
120
+
121
+static const struct meson_gpio_irq_params a1_params = {
122
+ INIT_MESON_A1_COMMON_DATA(62)
68123 };
69124
70125 static const struct of_device_id meson_irq_gpio_matches[] = {
....@@ -74,12 +129,15 @@
74129 { .compatible = "amlogic,meson-gxl-gpio-intc", .data = &gxl_params },
75130 { .compatible = "amlogic,meson-axg-gpio-intc", .data = &axg_params },
76131 { .compatible = "amlogic,meson-g12a-gpio-intc", .data = &axg_params },
132
+ { .compatible = "amlogic,meson-sm1-gpio-intc", .data = &sm1_params },
133
+ { .compatible = "amlogic,meson-a1-gpio-intc", .data = &a1_params },
77134 { }
78135 };
79136
80137 struct meson_gpio_irq_controller {
81
- unsigned int nr_hwirq;
138
+ const struct meson_gpio_irq_params *params;
82139 void __iomem *base;
140
+ struct irq_domain *domain;
83141 u32 channel_irqs[NUM_CHANNEL];
84142 DECLARE_BITMAP(channel_map, NUM_CHANNEL);
85143 spinlock_t lock;
....@@ -88,17 +146,56 @@
88146 static void meson_gpio_irq_update_bits(struct meson_gpio_irq_controller *ctl,
89147 unsigned int reg, u32 mask, u32 val)
90148 {
149
+ unsigned long flags;
91150 u32 tmp;
151
+
152
+ spin_lock_irqsave(&ctl->lock, flags);
92153
93154 tmp = readl_relaxed(ctl->base + reg);
94155 tmp &= ~mask;
95156 tmp |= val;
96157 writel_relaxed(tmp, ctl->base + reg);
158
+
159
+ spin_unlock_irqrestore(&ctl->lock, flags);
97160 }
98161
99
-static unsigned int meson_gpio_irq_channel_to_reg(unsigned int channel)
162
+static void meson_gpio_irq_init_dummy(struct meson_gpio_irq_controller *ctl)
100163 {
101
- return (channel < 4) ? REG_PIN_03_SEL : REG_PIN_47_SEL;
164
+}
165
+
166
+static void meson8_gpio_irq_sel_pin(struct meson_gpio_irq_controller *ctl,
167
+ unsigned int channel, unsigned long hwirq)
168
+{
169
+ unsigned int reg_offset;
170
+ unsigned int bit_offset;
171
+
172
+ reg_offset = (channel < 4) ? REG_PIN_03_SEL : REG_PIN_47_SEL;
173
+ bit_offset = REG_PIN_SEL_SHIFT(channel);
174
+
175
+ meson_gpio_irq_update_bits(ctl, reg_offset,
176
+ ctl->params->pin_sel_mask << bit_offset,
177
+ hwirq << bit_offset);
178
+}
179
+
180
+static void meson_a1_gpio_irq_sel_pin(struct meson_gpio_irq_controller *ctl,
181
+ unsigned int channel,
182
+ unsigned long hwirq)
183
+{
184
+ unsigned int reg_offset;
185
+ unsigned int bit_offset;
186
+
187
+ bit_offset = ((channel % 2) == 0) ? 0 : 16;
188
+ reg_offset = REG_PIN_A1_SEL + ((channel / 2) << 2);
189
+
190
+ meson_gpio_irq_update_bits(ctl, reg_offset,
191
+ ctl->params->pin_sel_mask << bit_offset,
192
+ hwirq << bit_offset);
193
+}
194
+
195
+/* For a1 or later chips like a1 there is a switch to enable/disable irq */
196
+static void meson_a1_gpio_irq_init(struct meson_gpio_irq_controller *ctl)
197
+{
198
+ meson_gpio_irq_update_bits(ctl, REG_EDGE_POL, BIT(31), BIT(31));
102199 }
103200
104201 static int
....@@ -106,14 +203,15 @@
106203 unsigned long hwirq,
107204 u32 **channel_hwirq)
108205 {
109
- unsigned int reg, idx;
206
+ unsigned long flags;
207
+ unsigned int idx;
110208
111
- spin_lock(&ctl->lock);
209
+ spin_lock_irqsave(&ctl->lock, flags);
112210
113211 /* Find a free channel */
114212 idx = find_first_zero_bit(ctl->channel_map, NUM_CHANNEL);
115213 if (idx >= NUM_CHANNEL) {
116
- spin_unlock(&ctl->lock);
214
+ spin_unlock_irqrestore(&ctl->lock, flags);
117215 pr_err("No channel available\n");
118216 return -ENOSPC;
119217 }
....@@ -121,24 +219,21 @@
121219 /* Mark the channel as used */
122220 set_bit(idx, ctl->channel_map);
123221
222
+ spin_unlock_irqrestore(&ctl->lock, flags);
223
+
124224 /*
125225 * Setup the mux of the channel to route the signal of the pad
126226 * to the appropriate input of the GIC
127227 */
128
- reg = meson_gpio_irq_channel_to_reg(idx);
129
- meson_gpio_irq_update_bits(ctl, reg,
130
- 0xff << REG_PIN_SEL_SHIFT(idx),
131
- hwirq << REG_PIN_SEL_SHIFT(idx));
228
+ ctl->params->ops.gpio_irq_sel_pin(ctl, idx, hwirq);
132229
133230 /*
134231 * Get the hwirq number assigned to this channel through
135
- * a pointer the channel_irq table. The added benifit of this
232
+ * a pointer the channel_irq table. The added benefit of this
136233 * method is that we can also retrieve the channel index with
137234 * it, using the table base.
138235 */
139236 *channel_hwirq = &(ctl->channel_irqs[idx]);
140
-
141
- spin_unlock(&ctl->lock);
142237
143238 pr_debug("hwirq %lu assigned to channel %d - irq %u\n",
144239 hwirq, idx, **channel_hwirq);
....@@ -169,7 +264,9 @@
169264 {
170265 u32 val = 0;
171266 unsigned int idx;
267
+ const struct meson_gpio_irq_params *params;
172268
269
+ params = ctl->params;
173270 idx = meson_gpio_irq_get_channel_idx(ctl, channel_hwirq);
174271
175272 /*
....@@ -181,21 +278,25 @@
181278 */
182279 type &= IRQ_TYPE_SENSE_MASK;
183280
184
- if (type == IRQ_TYPE_EDGE_BOTH)
185
- return -EINVAL;
281
+ /*
282
+ * New controller support EDGE_BOTH trigger. This setting takes
283
+ * precedence over the other edge/polarity settings
284
+ */
285
+ if (type == IRQ_TYPE_EDGE_BOTH) {
286
+ if (!params->support_edge_both)
287
+ return -EINVAL;
186288
187
- if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
188
- val |= REG_EDGE_POL_EDGE(idx);
289
+ val |= REG_BOTH_EDGE(params, idx);
290
+ } else {
291
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
292
+ val |= REG_EDGE_POL_EDGE(params, idx);
189293
190
- if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))
191
- val |= REG_EDGE_POL_LOW(idx);
192
-
193
- spin_lock(&ctl->lock);
294
+ if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING))
295
+ val |= REG_EDGE_POL_LOW(params, idx);
296
+ }
194297
195298 meson_gpio_irq_update_bits(ctl, REG_EDGE_POL,
196
- REG_EDGE_POL_MASK(idx), val);
197
-
198
- spin_unlock(&ctl->lock);
299
+ REG_EDGE_POL_MASK(params, idx), val);
199300
200301 return 0;
201302 }
....@@ -212,7 +313,7 @@
212313 */
213314 if (sense & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
214315 type |= IRQ_TYPE_LEVEL_HIGH;
215
- else if (sense & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
316
+ else
216317 type |= IRQ_TYPE_EDGE_RISING;
217318
218319 return type;
....@@ -337,19 +438,17 @@
337438 .translate = meson_gpio_irq_domain_translate,
338439 };
339440
340
-static int __init meson_gpio_irq_parse_dt(struct device_node *node,
341
- struct meson_gpio_irq_controller *ctl)
441
+static int meson_gpio_irq_parse_dt(struct device_node *node,
442
+ struct meson_gpio_irq_controller *ctl)
342443 {
343444 const struct of_device_id *match;
344
- const struct meson_gpio_irq_params *params;
345445 int ret;
346446
347447 match = of_match_node(meson_irq_gpio_matches, node);
348448 if (!match)
349449 return -ENODEV;
350450
351
- params = match->data;
352
- ctl->nr_hwirq = params->nr_hwirq;
451
+ ctl->params = match->data;
353452
354453 ret = of_property_read_variable_u32_array(node,
355454 "amlogic,channel-interrupts",
....@@ -361,65 +460,89 @@
361460 return ret;
362461 }
363462
463
+ ctl->params->ops.gpio_irq_init(ctl);
464
+
364465 return 0;
365466 }
366467
367
-static int __init meson_gpio_irq_of_init(struct device_node *node,
368
- struct device_node *parent)
468
+static int meson_gpio_intc_probe(struct platform_device *pdev)
369469 {
370
- struct irq_domain *domain, *parent_domain;
470
+ struct device_node *node = pdev->dev.of_node, *parent;
371471 struct meson_gpio_irq_controller *ctl;
472
+ struct irq_domain *parent_domain;
473
+ struct resource *res;
372474 int ret;
373475
476
+ parent = of_irq_find_parent(node);
374477 if (!parent) {
375
- pr_err("missing parent interrupt node\n");
478
+ dev_err(&pdev->dev, "missing parent interrupt node\n");
376479 return -ENODEV;
377480 }
378481
379482 parent_domain = irq_find_host(parent);
380483 if (!parent_domain) {
381
- pr_err("unable to obtain parent domain\n");
484
+ dev_err(&pdev->dev, "unable to obtain parent domain\n");
382485 return -ENXIO;
383486 }
384487
385
- ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
488
+ ctl = devm_kzalloc(&pdev->dev, sizeof(*ctl), GFP_KERNEL);
386489 if (!ctl)
387490 return -ENOMEM;
388491
389492 spin_lock_init(&ctl->lock);
390493
391
- ctl->base = of_iomap(node, 0);
392
- if (!ctl->base) {
393
- ret = -ENOMEM;
394
- goto free_ctl;
395
- }
494
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
495
+ ctl->base = devm_ioremap_resource(&pdev->dev, res);
496
+ if (IS_ERR(ctl->base))
497
+ return PTR_ERR(ctl->base);
396498
397499 ret = meson_gpio_irq_parse_dt(node, ctl);
398500 if (ret)
399
- goto free_channel_irqs;
501
+ return ret;
400502
401
- domain = irq_domain_create_hierarchy(parent_domain, 0, ctl->nr_hwirq,
402
- of_node_to_fwnode(node),
403
- &meson_gpio_irq_domain_ops,
404
- ctl);
405
- if (!domain) {
406
- pr_err("failed to add domain\n");
407
- ret = -ENODEV;
408
- goto free_channel_irqs;
503
+ ctl->domain = irq_domain_create_hierarchy(parent_domain, 0,
504
+ ctl->params->nr_hwirq,
505
+ of_node_to_fwnode(node),
506
+ &meson_gpio_irq_domain_ops,
507
+ ctl);
508
+ if (!ctl->domain) {
509
+ dev_err(&pdev->dev, "failed to add domain\n");
510
+ return -ENODEV;
409511 }
410512
411
- pr_info("%d to %d gpio interrupt mux initialized\n",
412
- ctl->nr_hwirq, NUM_CHANNEL);
513
+ platform_set_drvdata(pdev, ctl);
514
+
515
+ dev_info(&pdev->dev, "%d to %d gpio interrupt mux initialized\n",
516
+ ctl->params->nr_hwirq, NUM_CHANNEL);
413517
414518 return 0;
415
-
416
-free_channel_irqs:
417
- iounmap(ctl->base);
418
-free_ctl:
419
- kfree(ctl);
420
-
421
- return ret;
422519 }
423520
424
-IRQCHIP_DECLARE(meson_gpio_intc, "amlogic,meson-gpio-intc",
425
- meson_gpio_irq_of_init);
521
+static int meson_gpio_intc_remove(struct platform_device *pdev)
522
+{
523
+ struct meson_gpio_irq_controller *ctl = platform_get_drvdata(pdev);
524
+
525
+ irq_domain_remove(ctl->domain);
526
+
527
+ return 0;
528
+}
529
+
530
+static const struct of_device_id meson_gpio_intc_of_match[] = {
531
+ { .compatible = "amlogic,meson-gpio-intc", },
532
+ {},
533
+};
534
+MODULE_DEVICE_TABLE(of, meson_gpio_intc_of_match);
535
+
536
+static struct platform_driver meson_gpio_intc_driver = {
537
+ .probe = meson_gpio_intc_probe,
538
+ .remove = meson_gpio_intc_remove,
539
+ .driver = {
540
+ .name = "meson-gpio-intc",
541
+ .of_match_table = meson_gpio_intc_of_match,
542
+ },
543
+};
544
+module_platform_driver(meson_gpio_intc_driver);
545
+
546
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
547
+MODULE_LICENSE("GPL v2");
548
+MODULE_ALIAS("platform:meson-gpio-intc");