xref: /linux/drivers/pinctrl/bcm/pinctrl-bcm2835.c (revision 0227b49b50276657243e54f5609e65c4f0eaaf4d)
1a62c3677SStefan Wahren // SPDX-License-Identifier: GPL-2.0+
2e1b2dc70SSimon Arlott /*
3e1b2dc70SSimon Arlott  * Driver for Broadcom BCM2835 GPIO unit (pinctrl + GPIO)
4e1b2dc70SSimon Arlott  *
5e1b2dc70SSimon Arlott  * Copyright (C) 2012 Chris Boot, Simon Arlott, Stephen Warren
6e1b2dc70SSimon Arlott  *
7e1b2dc70SSimon Arlott  * This driver is inspired by:
8e1b2dc70SSimon Arlott  * pinctrl-nomadik.c, please see original file for copyright information
9e1b2dc70SSimon Arlott  * pinctrl-tegra.c, please see original file for copyright information
10e1b2dc70SSimon Arlott  */
11e1b2dc70SSimon Arlott 
12e1b2dc70SSimon Arlott #include <linux/bitmap.h>
13e1b2dc70SSimon Arlott #include <linux/bug.h>
14e1b2dc70SSimon Arlott #include <linux/delay.h>
15e1b2dc70SSimon Arlott #include <linux/device.h>
16e1b2dc70SSimon Arlott #include <linux/err.h>
17e19a5f79SLinus Walleij #include <linux/gpio/driver.h>
18e1b2dc70SSimon Arlott #include <linux/io.h>
19e1b2dc70SSimon Arlott #include <linux/irq.h>
20e1b2dc70SSimon Arlott #include <linux/irqdesc.h>
2134f46848SPaul Gortmaker #include <linux/init.h>
22920fecc1SFlorian Fainelli #include <linux/interrupt.h>
234434f4c5SFlorian Fainelli #include <linux/module.h>
24e1b2dc70SSimon Arlott #include <linux/of_address.h>
25e1b2dc70SSimon Arlott #include <linux/of.h>
26e1b2dc70SSimon Arlott #include <linux/of_irq.h>
27e1b2dc70SSimon Arlott #include <linux/pinctrl/consumer.h>
28e1b2dc70SSimon Arlott #include <linux/pinctrl/machine.h>
29e1b2dc70SSimon Arlott #include <linux/pinctrl/pinconf.h>
30e1b2dc70SSimon Arlott #include <linux/pinctrl/pinctrl.h>
31e1b2dc70SSimon Arlott #include <linux/pinctrl/pinmux.h>
320de70495SMatheus Castello #include <linux/pinctrl/pinconf-generic.h>
33e1b2dc70SSimon Arlott #include <linux/platform_device.h>
34e1b2dc70SSimon Arlott #include <linux/seq_file.h>
35e1b2dc70SSimon Arlott #include <linux/slab.h>
36e1b2dc70SSimon Arlott #include <linux/spinlock.h>
371583dc16SStefan Wahren #include <linux/string_choices.h>
38e1b2dc70SSimon Arlott #include <linux/types.h>
390de70495SMatheus Castello #include <dt-bindings/pinctrl/bcm2835.h>
40e1b2dc70SSimon Arlott 
41e1b2dc70SSimon Arlott #define MODULE_NAME "pinctrl-bcm2835"
42e1b2dc70SSimon Arlott #define BCM2835_NUM_GPIOS 54
43b1d84a3dSStefan Wahren #define BCM2711_NUM_GPIOS 58
44e1b2dc70SSimon Arlott #define BCM2835_NUM_BANKS 2
4500445b5dSPhil Elwell #define BCM2835_NUM_IRQS  3
46e1b2dc70SSimon Arlott 
47e1b2dc70SSimon Arlott /* GPIO register offsets */
48e1b2dc70SSimon Arlott #define GPFSEL0		0x0	/* Function Select */
49e1b2dc70SSimon Arlott #define GPSET0		0x1c	/* Pin Output Set */
50e1b2dc70SSimon Arlott #define GPCLR0		0x28	/* Pin Output Clear */
51e1b2dc70SSimon Arlott #define GPLEV0		0x34	/* Pin Level */
52e1b2dc70SSimon Arlott #define GPEDS0		0x40	/* Pin Event Detect Status */
53e1b2dc70SSimon Arlott #define GPREN0		0x4c	/* Pin Rising Edge Detect Enable */
54e1b2dc70SSimon Arlott #define GPFEN0		0x58	/* Pin Falling Edge Detect Enable */
55e1b2dc70SSimon Arlott #define GPHEN0		0x64	/* Pin High Detect Enable */
56e1b2dc70SSimon Arlott #define GPLEN0		0x70	/* Pin Low Detect Enable */
57e1b2dc70SSimon Arlott #define GPAREN0		0x7c	/* Pin Async Rising Edge Detect */
58e1b2dc70SSimon Arlott #define GPAFEN0		0x88	/* Pin Async Falling Edge Detect */
59e1b2dc70SSimon Arlott #define GPPUD		0x94	/* Pin Pull-up/down Enable */
60e1b2dc70SSimon Arlott #define GPPUDCLK0	0x98	/* Pin Pull-up/down Enable Clock */
61e38a9a43SStefan Wahren #define GP_GPIO_PUP_PDN_CNTRL_REG0 0xe4 /* 2711 Pin Pull-up/down select */
62e1b2dc70SSimon Arlott 
63e1b2dc70SSimon Arlott #define FSEL_REG(p)		(GPFSEL0 + (((p) / 10) * 4))
64e1b2dc70SSimon Arlott #define FSEL_SHIFT(p)		(((p) % 10) * 3)
65e1b2dc70SSimon Arlott #define GPIO_REG_OFFSET(p)	((p) / 32)
66e1b2dc70SSimon Arlott #define GPIO_REG_SHIFT(p)	((p) % 32)
67e1b2dc70SSimon Arlott 
68e38a9a43SStefan Wahren #define PUD_2711_MASK		0x3
69e38a9a43SStefan Wahren #define PUD_2711_REG_OFFSET(p)	((p) / 16)
70e38a9a43SStefan Wahren #define PUD_2711_REG_SHIFT(p)	(((p) % 16) * 2)
71e38a9a43SStefan Wahren 
72e1b2dc70SSimon Arlott /* argument: bcm2835_pinconf_pull */
73b40ac08fSNathan Chancellor #define BCM2835_PINCONF_PARAM_PULL	(PIN_CONFIG_END + 1)
74e1b2dc70SSimon Arlott 
75e38a9a43SStefan Wahren #define BCM2711_PULL_NONE	0x0
76e38a9a43SStefan Wahren #define BCM2711_PULL_UP		0x1
77e38a9a43SStefan Wahren #define BCM2711_PULL_DOWN	0x2
78e38a9a43SStefan Wahren 
79e1b2dc70SSimon Arlott struct bcm2835_pinctrl {
80e1b2dc70SSimon Arlott 	struct device *dev;
81e1b2dc70SSimon Arlott 	void __iomem *base;
82920fecc1SFlorian Fainelli 	int *wake_irq;
83e1b2dc70SSimon Arlott 
84e1b2dc70SSimon Arlott 	/* note: locking assumes each bank will have its own unsigned long */
85e1b2dc70SSimon Arlott 	unsigned long enabled_irq_map[BCM2835_NUM_BANKS];
86b1d84a3dSStefan Wahren 	unsigned int irq_type[BCM2711_NUM_GPIOS];
87e1b2dc70SSimon Arlott 
88e1b2dc70SSimon Arlott 	struct pinctrl_dev *pctl_dev;
89e1b2dc70SSimon Arlott 	struct gpio_chip gpio_chip;
9090bfaf02SStefan Wahren 	struct pinctrl_desc pctl_desc;
91e1b2dc70SSimon Arlott 	struct pinctrl_gpio_range gpio_range;
92e1b2dc70SSimon Arlott 
933c7b30f7SLukas Wunner 	raw_spinlock_t irq_lock[BCM2835_NUM_BANKS];
94b7badd75SHans Verkuil 	/* Protect FSEL registers */
95b7badd75SHans Verkuil 	spinlock_t fsel_lock;
96e1b2dc70SSimon Arlott };
97e1b2dc70SSimon Arlott 
98e1b2dc70SSimon Arlott /* pins are just named GPIO0..GPIO53 */
99e1b2dc70SSimon Arlott #define BCM2835_GPIO_PIN(a) PINCTRL_PIN(a, "gpio" #a)
100e8ed912eSSachin Kamat static struct pinctrl_pin_desc bcm2835_gpio_pins[] = {
101e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(0),
102e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(1),
103e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(2),
104e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(3),
105e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(4),
106e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(5),
107e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(6),
108e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(7),
109e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(8),
110e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(9),
111e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(10),
112e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(11),
113e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(12),
114e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(13),
115e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(14),
116e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(15),
117e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(16),
118e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(17),
119e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(18),
120e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(19),
121e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(20),
122e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(21),
123e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(22),
124e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(23),
125e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(24),
126e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(25),
127e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(26),
128e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(27),
129e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(28),
130e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(29),
131e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(30),
132e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(31),
133e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(32),
134e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(33),
135e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(34),
136e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(35),
137e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(36),
138e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(37),
139e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(38),
140e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(39),
141e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(40),
142e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(41),
143e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(42),
144e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(43),
145e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(44),
146e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(45),
147e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(46),
148e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(47),
149e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(48),
150e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(49),
151e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(50),
152e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(51),
153e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(52),
154e1b2dc70SSimon Arlott 	BCM2835_GPIO_PIN(53),
155b1d84a3dSStefan Wahren 	BCM2835_GPIO_PIN(54),
156b1d84a3dSStefan Wahren 	BCM2835_GPIO_PIN(55),
157b1d84a3dSStefan Wahren 	BCM2835_GPIO_PIN(56),
158b1d84a3dSStefan Wahren 	BCM2835_GPIO_PIN(57),
159e1b2dc70SSimon Arlott };
160e1b2dc70SSimon Arlott 
161e1b2dc70SSimon Arlott /* one pin per group */
162e1b2dc70SSimon Arlott static const char * const bcm2835_gpio_groups[] = {
163e1b2dc70SSimon Arlott 	"gpio0",
164e1b2dc70SSimon Arlott 	"gpio1",
165e1b2dc70SSimon Arlott 	"gpio2",
166e1b2dc70SSimon Arlott 	"gpio3",
167e1b2dc70SSimon Arlott 	"gpio4",
168e1b2dc70SSimon Arlott 	"gpio5",
169e1b2dc70SSimon Arlott 	"gpio6",
170e1b2dc70SSimon Arlott 	"gpio7",
171e1b2dc70SSimon Arlott 	"gpio8",
172e1b2dc70SSimon Arlott 	"gpio9",
173e1b2dc70SSimon Arlott 	"gpio10",
174e1b2dc70SSimon Arlott 	"gpio11",
175e1b2dc70SSimon Arlott 	"gpio12",
176e1b2dc70SSimon Arlott 	"gpio13",
177e1b2dc70SSimon Arlott 	"gpio14",
178e1b2dc70SSimon Arlott 	"gpio15",
179e1b2dc70SSimon Arlott 	"gpio16",
180e1b2dc70SSimon Arlott 	"gpio17",
181e1b2dc70SSimon Arlott 	"gpio18",
182e1b2dc70SSimon Arlott 	"gpio19",
183e1b2dc70SSimon Arlott 	"gpio20",
184e1b2dc70SSimon Arlott 	"gpio21",
185e1b2dc70SSimon Arlott 	"gpio22",
186e1b2dc70SSimon Arlott 	"gpio23",
187e1b2dc70SSimon Arlott 	"gpio24",
188e1b2dc70SSimon Arlott 	"gpio25",
189e1b2dc70SSimon Arlott 	"gpio26",
190e1b2dc70SSimon Arlott 	"gpio27",
191e1b2dc70SSimon Arlott 	"gpio28",
192e1b2dc70SSimon Arlott 	"gpio29",
193e1b2dc70SSimon Arlott 	"gpio30",
194e1b2dc70SSimon Arlott 	"gpio31",
195e1b2dc70SSimon Arlott 	"gpio32",
196e1b2dc70SSimon Arlott 	"gpio33",
197e1b2dc70SSimon Arlott 	"gpio34",
198e1b2dc70SSimon Arlott 	"gpio35",
199e1b2dc70SSimon Arlott 	"gpio36",
200e1b2dc70SSimon Arlott 	"gpio37",
201e1b2dc70SSimon Arlott 	"gpio38",
202e1b2dc70SSimon Arlott 	"gpio39",
203e1b2dc70SSimon Arlott 	"gpio40",
204e1b2dc70SSimon Arlott 	"gpio41",
205e1b2dc70SSimon Arlott 	"gpio42",
206e1b2dc70SSimon Arlott 	"gpio43",
207e1b2dc70SSimon Arlott 	"gpio44",
208e1b2dc70SSimon Arlott 	"gpio45",
209e1b2dc70SSimon Arlott 	"gpio46",
210e1b2dc70SSimon Arlott 	"gpio47",
211e1b2dc70SSimon Arlott 	"gpio48",
212e1b2dc70SSimon Arlott 	"gpio49",
213e1b2dc70SSimon Arlott 	"gpio50",
214e1b2dc70SSimon Arlott 	"gpio51",
215e1b2dc70SSimon Arlott 	"gpio52",
216e1b2dc70SSimon Arlott 	"gpio53",
217b1d84a3dSStefan Wahren 	"gpio54",
218b1d84a3dSStefan Wahren 	"gpio55",
219b1d84a3dSStefan Wahren 	"gpio56",
220b1d84a3dSStefan Wahren 	"gpio57",
221e1b2dc70SSimon Arlott };
222e1b2dc70SSimon Arlott 
223e1b2dc70SSimon Arlott enum bcm2835_fsel {
224e1b2dc70SSimon Arlott 	BCM2835_FSEL_COUNT = 8,
225e1b2dc70SSimon Arlott 	BCM2835_FSEL_MASK = 0x7,
226e1b2dc70SSimon Arlott };
227e1b2dc70SSimon Arlott 
228e1b2dc70SSimon Arlott static const char * const bcm2835_functions[BCM2835_FSEL_COUNT] = {
229e1b2dc70SSimon Arlott 	[BCM2835_FSEL_GPIO_IN] = "gpio_in",
230e1b2dc70SSimon Arlott 	[BCM2835_FSEL_GPIO_OUT] = "gpio_out",
231e1b2dc70SSimon Arlott 	[BCM2835_FSEL_ALT0] = "alt0",
232e1b2dc70SSimon Arlott 	[BCM2835_FSEL_ALT1] = "alt1",
233e1b2dc70SSimon Arlott 	[BCM2835_FSEL_ALT2] = "alt2",
234e1b2dc70SSimon Arlott 	[BCM2835_FSEL_ALT3] = "alt3",
235e1b2dc70SSimon Arlott 	[BCM2835_FSEL_ALT4] = "alt4",
236e1b2dc70SSimon Arlott 	[BCM2835_FSEL_ALT5] = "alt5",
237e1b2dc70SSimon Arlott };
238e1b2dc70SSimon Arlott 
239e1b2dc70SSimon Arlott static const char * const irq_type_names[] = {
240e1b2dc70SSimon Arlott 	[IRQ_TYPE_NONE] = "none",
241e1b2dc70SSimon Arlott 	[IRQ_TYPE_EDGE_RISING] = "edge-rising",
242e1b2dc70SSimon Arlott 	[IRQ_TYPE_EDGE_FALLING] = "edge-falling",
243e1b2dc70SSimon Arlott 	[IRQ_TYPE_EDGE_BOTH] = "edge-both",
244e1b2dc70SSimon Arlott 	[IRQ_TYPE_LEVEL_HIGH] = "level-high",
245e1b2dc70SSimon Arlott 	[IRQ_TYPE_LEVEL_LOW] = "level-low",
246e1b2dc70SSimon Arlott };
247e1b2dc70SSimon Arlott 
2488ff05989SStefan Wahren static bool persist_gpio_outputs;
24961fef29aSStefan Wahren module_param(persist_gpio_outputs, bool, 0444);
2508ff05989SStefan Wahren MODULE_PARM_DESC(persist_gpio_outputs, "Enable GPIO_OUT persistence when pin is freed");
2518ff05989SStefan Wahren 
bcm2835_gpio_rd(struct bcm2835_pinctrl * pc,unsigned reg)252e1b2dc70SSimon Arlott static inline u32 bcm2835_gpio_rd(struct bcm2835_pinctrl *pc, unsigned reg)
253e1b2dc70SSimon Arlott {
254e1b2dc70SSimon Arlott 	return readl(pc->base + reg);
255e1b2dc70SSimon Arlott }
256e1b2dc70SSimon Arlott 
bcm2835_gpio_wr(struct bcm2835_pinctrl * pc,unsigned reg,u32 val)257e1b2dc70SSimon Arlott static inline void bcm2835_gpio_wr(struct bcm2835_pinctrl *pc, unsigned reg,
258e1b2dc70SSimon Arlott 		u32 val)
259e1b2dc70SSimon Arlott {
260e1b2dc70SSimon Arlott 	writel(val, pc->base + reg);
261e1b2dc70SSimon Arlott }
262e1b2dc70SSimon Arlott 
bcm2835_gpio_get_bit(struct bcm2835_pinctrl * pc,unsigned reg,unsigned bit)263e1b2dc70SSimon Arlott static inline int bcm2835_gpio_get_bit(struct bcm2835_pinctrl *pc, unsigned reg,
264e1b2dc70SSimon Arlott 		unsigned bit)
265e1b2dc70SSimon Arlott {
266e1b2dc70SSimon Arlott 	reg += GPIO_REG_OFFSET(bit) * 4;
267e1b2dc70SSimon Arlott 	return (bcm2835_gpio_rd(pc, reg) >> GPIO_REG_SHIFT(bit)) & 1;
268e1b2dc70SSimon Arlott }
269e1b2dc70SSimon Arlott 
270e1b2dc70SSimon Arlott /* note NOT a read/modify/write cycle */
bcm2835_gpio_set_bit(struct bcm2835_pinctrl * pc,unsigned reg,unsigned bit)271e1b2dc70SSimon Arlott static inline void bcm2835_gpio_set_bit(struct bcm2835_pinctrl *pc,
272e1b2dc70SSimon Arlott 		unsigned reg, unsigned bit)
273e1b2dc70SSimon Arlott {
274e1b2dc70SSimon Arlott 	reg += GPIO_REG_OFFSET(bit) * 4;
275e1b2dc70SSimon Arlott 	bcm2835_gpio_wr(pc, reg, BIT(GPIO_REG_SHIFT(bit)));
276e1b2dc70SSimon Arlott }
277e1b2dc70SSimon Arlott 
bcm2835_pinctrl_fsel_get(struct bcm2835_pinctrl * pc,unsigned pin)278e1b2dc70SSimon Arlott static inline enum bcm2835_fsel bcm2835_pinctrl_fsel_get(
279e1b2dc70SSimon Arlott 		struct bcm2835_pinctrl *pc, unsigned pin)
280e1b2dc70SSimon Arlott {
281e1b2dc70SSimon Arlott 	u32 val = bcm2835_gpio_rd(pc, FSEL_REG(pin));
282e1b2dc70SSimon Arlott 	enum bcm2835_fsel status = (val >> FSEL_SHIFT(pin)) & BCM2835_FSEL_MASK;
283e1b2dc70SSimon Arlott 
284e1b2dc70SSimon Arlott 	dev_dbg(pc->dev, "get %08x (%u => %s)\n", val, pin,
285e1b2dc70SSimon Arlott 			bcm2835_functions[status]);
286e1b2dc70SSimon Arlott 
287e1b2dc70SSimon Arlott 	return status;
288e1b2dc70SSimon Arlott }
289e1b2dc70SSimon Arlott 
bcm2835_pinctrl_fsel_set(struct bcm2835_pinctrl * pc,unsigned pin,enum bcm2835_fsel fsel)290e1b2dc70SSimon Arlott static inline void bcm2835_pinctrl_fsel_set(
291e1b2dc70SSimon Arlott 		struct bcm2835_pinctrl *pc, unsigned pin,
292e1b2dc70SSimon Arlott 		enum bcm2835_fsel fsel)
293e1b2dc70SSimon Arlott {
294b7badd75SHans Verkuil 	u32 val;
295b7badd75SHans Verkuil 	enum bcm2835_fsel cur;
296b7badd75SHans Verkuil 	unsigned long flags;
297b7badd75SHans Verkuil 
298b7badd75SHans Verkuil 	spin_lock_irqsave(&pc->fsel_lock, flags);
299b7badd75SHans Verkuil 	val = bcm2835_gpio_rd(pc, FSEL_REG(pin));
300b7badd75SHans Verkuil 	cur = (val >> FSEL_SHIFT(pin)) & BCM2835_FSEL_MASK;
301e1b2dc70SSimon Arlott 
302e1b2dc70SSimon Arlott 	dev_dbg(pc->dev, "read %08x (%u => %s)\n", val, pin,
303e1b2dc70SSimon Arlott 		bcm2835_functions[cur]);
304e1b2dc70SSimon Arlott 
305e1b2dc70SSimon Arlott 	if (cur == fsel)
306b7badd75SHans Verkuil 		goto unlock;
307e1b2dc70SSimon Arlott 
308e1b2dc70SSimon Arlott 	if (cur != BCM2835_FSEL_GPIO_IN && fsel != BCM2835_FSEL_GPIO_IN) {
309e1b2dc70SSimon Arlott 		/* always transition through GPIO_IN */
310e1b2dc70SSimon Arlott 		val &= ~(BCM2835_FSEL_MASK << FSEL_SHIFT(pin));
311e1b2dc70SSimon Arlott 		val |= BCM2835_FSEL_GPIO_IN << FSEL_SHIFT(pin);
312e1b2dc70SSimon Arlott 
313e1b2dc70SSimon Arlott 		dev_dbg(pc->dev, "trans %08x (%u <= %s)\n", val, pin,
314e1b2dc70SSimon Arlott 				bcm2835_functions[BCM2835_FSEL_GPIO_IN]);
315e1b2dc70SSimon Arlott 		bcm2835_gpio_wr(pc, FSEL_REG(pin), val);
316e1b2dc70SSimon Arlott 	}
317e1b2dc70SSimon Arlott 
318e1b2dc70SSimon Arlott 	val &= ~(BCM2835_FSEL_MASK << FSEL_SHIFT(pin));
319e1b2dc70SSimon Arlott 	val |= fsel << FSEL_SHIFT(pin);
320e1b2dc70SSimon Arlott 
321e1b2dc70SSimon Arlott 	dev_dbg(pc->dev, "write %08x (%u <= %s)\n", val, pin,
322e1b2dc70SSimon Arlott 			bcm2835_functions[fsel]);
323e1b2dc70SSimon Arlott 	bcm2835_gpio_wr(pc, FSEL_REG(pin), val);
324b7badd75SHans Verkuil 
325b7badd75SHans Verkuil unlock:
326b7badd75SHans Verkuil 	spin_unlock_irqrestore(&pc->fsel_lock, flags);
327e1b2dc70SSimon Arlott }
328e1b2dc70SSimon Arlott 
bcm2835_gpio_direction_input(struct gpio_chip * chip,unsigned offset)329e1b2dc70SSimon Arlott static int bcm2835_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
330e1b2dc70SSimon Arlott {
3311a4541b6SHans Verkuil 	struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
3321a4541b6SHans Verkuil 
3331a4541b6SHans Verkuil 	bcm2835_pinctrl_fsel_set(pc, offset, BCM2835_FSEL_GPIO_IN);
3341a4541b6SHans Verkuil 	return 0;
335e1b2dc70SSimon Arlott }
336e1b2dc70SSimon Arlott 
bcm2835_gpio_get(struct gpio_chip * chip,unsigned offset)337e1b2dc70SSimon Arlott static int bcm2835_gpio_get(struct gpio_chip *chip, unsigned offset)
338e1b2dc70SSimon Arlott {
339e19a5f79SLinus Walleij 	struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
340e1b2dc70SSimon Arlott 
341e1b2dc70SSimon Arlott 	return bcm2835_gpio_get_bit(pc, GPLEV0, offset);
342e1b2dc70SSimon Arlott }
343e1b2dc70SSimon Arlott 
bcm2835_gpio_get_direction(struct gpio_chip * chip,unsigned int offset)34420b3d2a7SStefan Wahren static int bcm2835_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
34520b3d2a7SStefan Wahren {
34620b3d2a7SStefan Wahren 	struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
34720b3d2a7SStefan Wahren 	enum bcm2835_fsel fsel = bcm2835_pinctrl_fsel_get(pc, offset);
34820b3d2a7SStefan Wahren 
34975f87f5dSBartosz Golaszewski 	if (fsel == BCM2835_FSEL_GPIO_OUT)
3503c827873SMatti Vaittinen 		return GPIO_LINE_DIRECTION_OUT;
35175f87f5dSBartosz Golaszewski 
35275f87f5dSBartosz Golaszewski 	/*
35375f87f5dSBartosz Golaszewski 	 * Alternative function doesn't clearly provide a direction. Default
35475f87f5dSBartosz Golaszewski 	 * to INPUT.
35575f87f5dSBartosz Golaszewski 	 */
35675f87f5dSBartosz Golaszewski 	return GPIO_LINE_DIRECTION_IN;
35720b3d2a7SStefan Wahren }
35820b3d2a7SStefan Wahren 
bcm2835_gpio_set(struct gpio_chip * chip,unsigned int offset,int value)359941a099dSBartosz Golaszewski static int bcm2835_gpio_set(struct gpio_chip *chip, unsigned int offset,
360941a099dSBartosz Golaszewski 			    int value)
361e1b2dc70SSimon Arlott {
362e19a5f79SLinus Walleij 	struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
363e1b2dc70SSimon Arlott 
364e1b2dc70SSimon Arlott 	bcm2835_gpio_set_bit(pc, value ? GPSET0 : GPCLR0, offset);
365941a099dSBartosz Golaszewski 
366941a099dSBartosz Golaszewski 	return 0;
367e1b2dc70SSimon Arlott }
368e1b2dc70SSimon Arlott 
bcm2835_gpio_direction_output(struct gpio_chip * chip,unsigned offset,int value)3694c02cba1SStefan Wahren static int bcm2835_gpio_direction_output(struct gpio_chip *chip,
3704c02cba1SStefan Wahren 		unsigned offset, int value)
3714c02cba1SStefan Wahren {
3721a4541b6SHans Verkuil 	struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
3731a4541b6SHans Verkuil 
3741a4541b6SHans Verkuil 	bcm2835_gpio_set_bit(pc, value ? GPSET0 : GPCLR0, offset);
3751a4541b6SHans Verkuil 	bcm2835_pinctrl_fsel_set(pc, offset, BCM2835_FSEL_GPIO_OUT);
3761a4541b6SHans Verkuil 	return 0;
3774c02cba1SStefan Wahren }
3784c02cba1SStefan Wahren 
bcm2835_add_pin_ranges_fallback(struct gpio_chip * gc)379bc962997SAndy Shevchenko static int bcm2835_add_pin_ranges_fallback(struct gpio_chip *gc)
380d2b67744SStefan Wahren {
381bc962997SAndy Shevchenko 	struct device_node *np = dev_of_node(gc->parent);
382d2b67744SStefan Wahren 	struct pinctrl_dev *pctldev = of_pinctrl_get(np);
383d2b67744SStefan Wahren 
384d2b67744SStefan Wahren 	if (!pctldev)
385d2b67744SStefan Wahren 		return 0;
386d2b67744SStefan Wahren 
387cdf7e616SChristophe JAILLET 	return gpiochip_add_pin_range(gc, pinctrl_dev_get_devname(pctldev), 0, 0,
388d2b67744SStefan Wahren 				      gc->ngpio);
389d2b67744SStefan Wahren }
390d2b67744SStefan Wahren 
391531bcf73SGustavo A. R. Silva static const struct gpio_chip bcm2835_gpio_chip = {
392e1b2dc70SSimon Arlott 	.label = MODULE_NAME,
393e1b2dc70SSimon Arlott 	.owner = THIS_MODULE,
39498c85d58SJonas Gorski 	.request = gpiochip_generic_request,
39598c85d58SJonas Gorski 	.free = gpiochip_generic_free,
396e1b2dc70SSimon Arlott 	.direction_input = bcm2835_gpio_direction_input,
397e1b2dc70SSimon Arlott 	.direction_output = bcm2835_gpio_direction_output,
39820b3d2a7SStefan Wahren 	.get_direction = bcm2835_gpio_get_direction,
399e1b2dc70SSimon Arlott 	.get = bcm2835_gpio_get,
400*d9d87d90SBartosz Golaszewski 	.set = bcm2835_gpio_set,
401b6e5531cSStefan Wahren 	.set_config = gpiochip_generic_config,
402e1b2dc70SSimon Arlott 	.base = -1,
403e1b2dc70SSimon Arlott 	.ngpio = BCM2835_NUM_GPIOS,
4049fb1f39eSLinus Walleij 	.can_sleep = false,
405bc962997SAndy Shevchenko 	.add_pin_ranges = bcm2835_add_pin_ranges_fallback,
406e1b2dc70SSimon Arlott };
407e1b2dc70SSimon Arlott 
408b1d84a3dSStefan Wahren static const struct gpio_chip bcm2711_gpio_chip = {
409b1d84a3dSStefan Wahren 	.label = "pinctrl-bcm2711",
410b1d84a3dSStefan Wahren 	.owner = THIS_MODULE,
411b1d84a3dSStefan Wahren 	.request = gpiochip_generic_request,
412b1d84a3dSStefan Wahren 	.free = gpiochip_generic_free,
413b1d84a3dSStefan Wahren 	.direction_input = bcm2835_gpio_direction_input,
414b1d84a3dSStefan Wahren 	.direction_output = bcm2835_gpio_direction_output,
415b1d84a3dSStefan Wahren 	.get_direction = bcm2835_gpio_get_direction,
416b1d84a3dSStefan Wahren 	.get = bcm2835_gpio_get,
417*d9d87d90SBartosz Golaszewski 	.set = bcm2835_gpio_set,
418b1d84a3dSStefan Wahren 	.set_config = gpiochip_generic_config,
419b1d84a3dSStefan Wahren 	.base = -1,
420b1d84a3dSStefan Wahren 	.ngpio = BCM2711_NUM_GPIOS,
421b1d84a3dSStefan Wahren 	.can_sleep = false,
422bc962997SAndy Shevchenko 	.add_pin_ranges = bcm2835_add_pin_ranges_fallback,
423b1d84a3dSStefan Wahren };
424b1d84a3dSStefan Wahren 
bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl * pc,unsigned int bank,u32 mask)42585ae9e51SLinus Walleij static void bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl *pc,
42600445b5dSPhil Elwell 					 unsigned int bank, u32 mask)
427e1b2dc70SSimon Arlott {
428e1b2dc70SSimon Arlott 	unsigned long events;
429e1b2dc70SSimon Arlott 	unsigned offset;
430e1b2dc70SSimon Arlott 	unsigned gpio;
431e1b2dc70SSimon Arlott 
432e1b2dc70SSimon Arlott 	events = bcm2835_gpio_rd(pc, GPEDS0 + bank * 4);
43300445b5dSPhil Elwell 	events &= mask;
434e1b2dc70SSimon Arlott 	events &= pc->enabled_irq_map[bank];
435e1b2dc70SSimon Arlott 	for_each_set_bit(offset, &events, 32) {
436e1b2dc70SSimon Arlott 		gpio = (32 * bank) + offset;
437a9cb09b7SMarc Zyngier 		generic_handle_domain_irq(pc->gpio_chip.irq.domain,
438a9cb09b7SMarc Zyngier 					  gpio);
43985ae9e51SLinus Walleij 	}
440e1b2dc70SSimon Arlott }
44100445b5dSPhil Elwell 
bcm2835_gpio_irq_handler(struct irq_desc * desc)44285ae9e51SLinus Walleij static void bcm2835_gpio_irq_handler(struct irq_desc *desc)
44300445b5dSPhil Elwell {
44485ae9e51SLinus Walleij 	struct gpio_chip *chip = irq_desc_get_handler_data(desc);
44585ae9e51SLinus Walleij 	struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
44685ae9e51SLinus Walleij 	struct irq_chip *host_chip = irq_desc_get_chip(desc);
44785ae9e51SLinus Walleij 	int irq = irq_desc_get_irq(desc);
448dc1b2424SLinus Walleij 	int group = 0;
44985ae9e51SLinus Walleij 	int i;
45000445b5dSPhil Elwell 
45173345a18SLinus Walleij 	for (i = 0; i < BCM2835_NUM_IRQS; i++) {
45273345a18SLinus Walleij 		if (chip->irq.parents[i] == irq) {
4530d885e9dSThierry Reding 			group = i;
45485ae9e51SLinus Walleij 			break;
45585ae9e51SLinus Walleij 		}
45685ae9e51SLinus Walleij 	}
45785ae9e51SLinus Walleij 	/* This should not happen, every IRQ has a bank */
45829d45a64SJason Wang 	BUG_ON(i == BCM2835_NUM_IRQS);
45985ae9e51SLinus Walleij 
46085ae9e51SLinus Walleij 	chained_irq_enter(host_chip, desc);
46185ae9e51SLinus Walleij 
46285ae9e51SLinus Walleij 	switch (group) {
46300445b5dSPhil Elwell 	case 0: /* IRQ0 covers GPIOs 0-27 */
46485ae9e51SLinus Walleij 		bcm2835_gpio_irq_handle_bank(pc, 0, 0x0fffffff);
46500445b5dSPhil Elwell 		break;
46600445b5dSPhil Elwell 	case 1: /* IRQ1 covers GPIOs 28-45 */
46785ae9e51SLinus Walleij 		bcm2835_gpio_irq_handle_bank(pc, 0, 0xf0000000);
46800445b5dSPhil Elwell 		bcm2835_gpio_irq_handle_bank(pc, 1, 0x00003fff);
46900445b5dSPhil Elwell 		break;
470b1d84a3dSStefan Wahren 	case 2: /* IRQ2 covers GPIOs 46-57 */
47185ae9e51SLinus Walleij 		bcm2835_gpio_irq_handle_bank(pc, 1, 0x003fc000);
47200445b5dSPhil Elwell 		break;
47300445b5dSPhil Elwell 	}
47400445b5dSPhil Elwell 
47585ae9e51SLinus Walleij 	chained_irq_exit(host_chip, desc);
476e1b2dc70SSimon Arlott }
477e1b2dc70SSimon Arlott 
bcm2835_gpio_wake_irq_handler(int irq,void * dev_id)478920fecc1SFlorian Fainelli static irqreturn_t bcm2835_gpio_wake_irq_handler(int irq, void *dev_id)
479920fecc1SFlorian Fainelli {
480920fecc1SFlorian Fainelli 	return IRQ_HANDLED;
481920fecc1SFlorian Fainelli }
482920fecc1SFlorian Fainelli 
__bcm2835_gpio_irq_config(struct bcm2835_pinctrl * pc,unsigned reg,unsigned offset,bool enable)483e1b2dc70SSimon Arlott static inline void __bcm2835_gpio_irq_config(struct bcm2835_pinctrl *pc,
484e1b2dc70SSimon Arlott 	unsigned reg, unsigned offset, bool enable)
485e1b2dc70SSimon Arlott {
486e1b2dc70SSimon Arlott 	u32 value;
487e1b2dc70SSimon Arlott 	reg += GPIO_REG_OFFSET(offset) * 4;
488e1b2dc70SSimon Arlott 	value = bcm2835_gpio_rd(pc, reg);
489e1b2dc70SSimon Arlott 	if (enable)
490e1b2dc70SSimon Arlott 		value |= BIT(GPIO_REG_SHIFT(offset));
491e1b2dc70SSimon Arlott 	else
492e1b2dc70SSimon Arlott 		value &= ~(BIT(GPIO_REG_SHIFT(offset)));
493e1b2dc70SSimon Arlott 	bcm2835_gpio_wr(pc, reg, value);
494e1b2dc70SSimon Arlott }
495e1b2dc70SSimon Arlott 
496e1b2dc70SSimon Arlott /* fast path for IRQ handler */
bcm2835_gpio_irq_config(struct bcm2835_pinctrl * pc,unsigned offset,bool enable)497e1b2dc70SSimon Arlott static void bcm2835_gpio_irq_config(struct bcm2835_pinctrl *pc,
498e1b2dc70SSimon Arlott 	unsigned offset, bool enable)
499e1b2dc70SSimon Arlott {
500e1b2dc70SSimon Arlott 	switch (pc->irq_type[offset]) {
501e1b2dc70SSimon Arlott 	case IRQ_TYPE_EDGE_RISING:
502e1b2dc70SSimon Arlott 		__bcm2835_gpio_irq_config(pc, GPREN0, offset, enable);
503e1b2dc70SSimon Arlott 		break;
504e1b2dc70SSimon Arlott 
505e1b2dc70SSimon Arlott 	case IRQ_TYPE_EDGE_FALLING:
506e1b2dc70SSimon Arlott 		__bcm2835_gpio_irq_config(pc, GPFEN0, offset, enable);
507e1b2dc70SSimon Arlott 		break;
508e1b2dc70SSimon Arlott 
509e1b2dc70SSimon Arlott 	case IRQ_TYPE_EDGE_BOTH:
510e1b2dc70SSimon Arlott 		__bcm2835_gpio_irq_config(pc, GPREN0, offset, enable);
511e1b2dc70SSimon Arlott 		__bcm2835_gpio_irq_config(pc, GPFEN0, offset, enable);
512e1b2dc70SSimon Arlott 		break;
513e1b2dc70SSimon Arlott 
514e1b2dc70SSimon Arlott 	case IRQ_TYPE_LEVEL_HIGH:
515e1b2dc70SSimon Arlott 		__bcm2835_gpio_irq_config(pc, GPHEN0, offset, enable);
516e1b2dc70SSimon Arlott 		break;
517e1b2dc70SSimon Arlott 
518e1b2dc70SSimon Arlott 	case IRQ_TYPE_LEVEL_LOW:
519e1b2dc70SSimon Arlott 		__bcm2835_gpio_irq_config(pc, GPLEN0, offset, enable);
520e1b2dc70SSimon Arlott 		break;
521e1b2dc70SSimon Arlott 	}
522e1b2dc70SSimon Arlott }
523e1b2dc70SSimon Arlott 
bcm2835_gpio_irq_unmask(struct irq_data * data)524db1b3eceSStefan Wahren static void bcm2835_gpio_irq_unmask(struct irq_data *data)
525e1b2dc70SSimon Arlott {
52685ae9e51SLinus Walleij 	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
52785ae9e51SLinus Walleij 	struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
528e1b2dc70SSimon Arlott 	unsigned gpio = irqd_to_hwirq(data);
529e1b2dc70SSimon Arlott 	unsigned offset = GPIO_REG_SHIFT(gpio);
530e1b2dc70SSimon Arlott 	unsigned bank = GPIO_REG_OFFSET(gpio);
531e1b2dc70SSimon Arlott 	unsigned long flags;
532e1b2dc70SSimon Arlott 
53308752e07SStefan Wahren 	gpiochip_enable_irq(chip, gpio);
53408752e07SStefan Wahren 
5353c7b30f7SLukas Wunner 	raw_spin_lock_irqsave(&pc->irq_lock[bank], flags);
536e1b2dc70SSimon Arlott 	set_bit(offset, &pc->enabled_irq_map[bank]);
537e1b2dc70SSimon Arlott 	bcm2835_gpio_irq_config(pc, gpio, true);
5383c7b30f7SLukas Wunner 	raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags);
539e1b2dc70SSimon Arlott }
540e1b2dc70SSimon Arlott 
bcm2835_gpio_irq_mask(struct irq_data * data)541db1b3eceSStefan Wahren static void bcm2835_gpio_irq_mask(struct irq_data *data)
542e1b2dc70SSimon Arlott {
54385ae9e51SLinus Walleij 	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
54485ae9e51SLinus Walleij 	struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
545e1b2dc70SSimon Arlott 	unsigned gpio = irqd_to_hwirq(data);
546e1b2dc70SSimon Arlott 	unsigned offset = GPIO_REG_SHIFT(gpio);
547e1b2dc70SSimon Arlott 	unsigned bank = GPIO_REG_OFFSET(gpio);
548e1b2dc70SSimon Arlott 	unsigned long flags;
549e1b2dc70SSimon Arlott 
5503c7b30f7SLukas Wunner 	raw_spin_lock_irqsave(&pc->irq_lock[bank], flags);
551e1b2dc70SSimon Arlott 	bcm2835_gpio_irq_config(pc, gpio, false);
552714b1dd8SJonathan Bell 	/* Clear events that were latched prior to clearing event sources */
553714b1dd8SJonathan Bell 	bcm2835_gpio_set_bit(pc, GPEDS0, gpio);
554e1b2dc70SSimon Arlott 	clear_bit(offset, &pc->enabled_irq_map[bank]);
5553c7b30f7SLukas Wunner 	raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags);
55608752e07SStefan Wahren 
55708752e07SStefan Wahren 	gpiochip_disable_irq(chip, gpio);
558e1b2dc70SSimon Arlott }
559e1b2dc70SSimon Arlott 
__bcm2835_gpio_irq_set_type_disabled(struct bcm2835_pinctrl * pc,unsigned offset,unsigned int type)560e1b2dc70SSimon Arlott static int __bcm2835_gpio_irq_set_type_disabled(struct bcm2835_pinctrl *pc,
561e1b2dc70SSimon Arlott 	unsigned offset, unsigned int type)
562e1b2dc70SSimon Arlott {
563e1b2dc70SSimon Arlott 	switch (type) {
564e1b2dc70SSimon Arlott 	case IRQ_TYPE_NONE:
565e1b2dc70SSimon Arlott 	case IRQ_TYPE_EDGE_RISING:
566e1b2dc70SSimon Arlott 	case IRQ_TYPE_EDGE_FALLING:
567e1b2dc70SSimon Arlott 	case IRQ_TYPE_EDGE_BOTH:
568e1b2dc70SSimon Arlott 	case IRQ_TYPE_LEVEL_HIGH:
569e1b2dc70SSimon Arlott 	case IRQ_TYPE_LEVEL_LOW:
570e1b2dc70SSimon Arlott 		pc->irq_type[offset] = type;
571e1b2dc70SSimon Arlott 		break;
572e1b2dc70SSimon Arlott 
573e1b2dc70SSimon Arlott 	default:
574e1b2dc70SSimon Arlott 		return -EINVAL;
575e1b2dc70SSimon Arlott 	}
576e1b2dc70SSimon Arlott 	return 0;
577e1b2dc70SSimon Arlott }
578e1b2dc70SSimon Arlott 
579e1b2dc70SSimon Arlott /* slower path for reconfiguring IRQ type */
__bcm2835_gpio_irq_set_type_enabled(struct bcm2835_pinctrl * pc,unsigned offset,unsigned int type)580e1b2dc70SSimon Arlott static int __bcm2835_gpio_irq_set_type_enabled(struct bcm2835_pinctrl *pc,
581e1b2dc70SSimon Arlott 	unsigned offset, unsigned int type)
582e1b2dc70SSimon Arlott {
583e1b2dc70SSimon Arlott 	switch (type) {
584e1b2dc70SSimon Arlott 	case IRQ_TYPE_NONE:
585e1b2dc70SSimon Arlott 		if (pc->irq_type[offset] != type) {
586e1b2dc70SSimon Arlott 			bcm2835_gpio_irq_config(pc, offset, false);
587e1b2dc70SSimon Arlott 			pc->irq_type[offset] = type;
588e1b2dc70SSimon Arlott 		}
589e1b2dc70SSimon Arlott 		break;
590e1b2dc70SSimon Arlott 
591e1b2dc70SSimon Arlott 	case IRQ_TYPE_EDGE_RISING:
592e1b2dc70SSimon Arlott 		if (pc->irq_type[offset] == IRQ_TYPE_EDGE_BOTH) {
593e1b2dc70SSimon Arlott 			/* RISING already enabled, disable FALLING */
594e1b2dc70SSimon Arlott 			pc->irq_type[offset] = IRQ_TYPE_EDGE_FALLING;
595e1b2dc70SSimon Arlott 			bcm2835_gpio_irq_config(pc, offset, false);
596e1b2dc70SSimon Arlott 			pc->irq_type[offset] = type;
597e1b2dc70SSimon Arlott 		} else if (pc->irq_type[offset] != type) {
598e1b2dc70SSimon Arlott 			bcm2835_gpio_irq_config(pc, offset, false);
599e1b2dc70SSimon Arlott 			pc->irq_type[offset] = type;
600e1b2dc70SSimon Arlott 			bcm2835_gpio_irq_config(pc, offset, true);
601e1b2dc70SSimon Arlott 		}
602e1b2dc70SSimon Arlott 		break;
603e1b2dc70SSimon Arlott 
604e1b2dc70SSimon Arlott 	case IRQ_TYPE_EDGE_FALLING:
605e1b2dc70SSimon Arlott 		if (pc->irq_type[offset] == IRQ_TYPE_EDGE_BOTH) {
606e1b2dc70SSimon Arlott 			/* FALLING already enabled, disable RISING */
607e1b2dc70SSimon Arlott 			pc->irq_type[offset] = IRQ_TYPE_EDGE_RISING;
608e1b2dc70SSimon Arlott 			bcm2835_gpio_irq_config(pc, offset, false);
609e1b2dc70SSimon Arlott 			pc->irq_type[offset] = type;
610e1b2dc70SSimon Arlott 		} else if (pc->irq_type[offset] != type) {
611e1b2dc70SSimon Arlott 			bcm2835_gpio_irq_config(pc, offset, false);
612e1b2dc70SSimon Arlott 			pc->irq_type[offset] = type;
613e1b2dc70SSimon Arlott 			bcm2835_gpio_irq_config(pc, offset, true);
614e1b2dc70SSimon Arlott 		}
615e1b2dc70SSimon Arlott 		break;
616e1b2dc70SSimon Arlott 
617e1b2dc70SSimon Arlott 	case IRQ_TYPE_EDGE_BOTH:
618e1b2dc70SSimon Arlott 		if (pc->irq_type[offset] == IRQ_TYPE_EDGE_RISING) {
619e1b2dc70SSimon Arlott 			/* RISING already enabled, enable FALLING too */
620e1b2dc70SSimon Arlott 			pc->irq_type[offset] = IRQ_TYPE_EDGE_FALLING;
621e1b2dc70SSimon Arlott 			bcm2835_gpio_irq_config(pc, offset, true);
622e1b2dc70SSimon Arlott 			pc->irq_type[offset] = type;
623e1b2dc70SSimon Arlott 		} else if (pc->irq_type[offset] == IRQ_TYPE_EDGE_FALLING) {
624e1b2dc70SSimon Arlott 			/* FALLING already enabled, enable RISING too */
625e1b2dc70SSimon Arlott 			pc->irq_type[offset] = IRQ_TYPE_EDGE_RISING;
626e1b2dc70SSimon Arlott 			bcm2835_gpio_irq_config(pc, offset, true);
627e1b2dc70SSimon Arlott 			pc->irq_type[offset] = type;
628e1b2dc70SSimon Arlott 		} else if (pc->irq_type[offset] != type) {
629e1b2dc70SSimon Arlott 			bcm2835_gpio_irq_config(pc, offset, false);
630e1b2dc70SSimon Arlott 			pc->irq_type[offset] = type;
631e1b2dc70SSimon Arlott 			bcm2835_gpio_irq_config(pc, offset, true);
632e1b2dc70SSimon Arlott 		}
633e1b2dc70SSimon Arlott 		break;
634e1b2dc70SSimon Arlott 
635e1b2dc70SSimon Arlott 	case IRQ_TYPE_LEVEL_HIGH:
636e1b2dc70SSimon Arlott 	case IRQ_TYPE_LEVEL_LOW:
637e1b2dc70SSimon Arlott 		if (pc->irq_type[offset] != type) {
638e1b2dc70SSimon Arlott 			bcm2835_gpio_irq_config(pc, offset, false);
639e1b2dc70SSimon Arlott 			pc->irq_type[offset] = type;
640e1b2dc70SSimon Arlott 			bcm2835_gpio_irq_config(pc, offset, true);
641e1b2dc70SSimon Arlott 		}
642e1b2dc70SSimon Arlott 		break;
643e1b2dc70SSimon Arlott 
644e1b2dc70SSimon Arlott 	default:
645e1b2dc70SSimon Arlott 		return -EINVAL;
646e1b2dc70SSimon Arlott 	}
647e1b2dc70SSimon Arlott 	return 0;
648e1b2dc70SSimon Arlott }
649e1b2dc70SSimon Arlott 
bcm2835_gpio_irq_set_type(struct irq_data * data,unsigned int type)650e1b2dc70SSimon Arlott static int bcm2835_gpio_irq_set_type(struct irq_data *data, unsigned int type)
651e1b2dc70SSimon Arlott {
65285ae9e51SLinus Walleij 	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
65385ae9e51SLinus Walleij 	struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
654e1b2dc70SSimon Arlott 	unsigned gpio = irqd_to_hwirq(data);
655e1b2dc70SSimon Arlott 	unsigned offset = GPIO_REG_SHIFT(gpio);
656e1b2dc70SSimon Arlott 	unsigned bank = GPIO_REG_OFFSET(gpio);
657e1b2dc70SSimon Arlott 	unsigned long flags;
658e1b2dc70SSimon Arlott 	int ret;
659e1b2dc70SSimon Arlott 
6603c7b30f7SLukas Wunner 	raw_spin_lock_irqsave(&pc->irq_lock[bank], flags);
661e1b2dc70SSimon Arlott 
662e1b2dc70SSimon Arlott 	if (test_bit(offset, &pc->enabled_irq_map[bank]))
663e1b2dc70SSimon Arlott 		ret = __bcm2835_gpio_irq_set_type_enabled(pc, gpio, type);
664e1b2dc70SSimon Arlott 	else
665e1b2dc70SSimon Arlott 		ret = __bcm2835_gpio_irq_set_type_disabled(pc, gpio, type);
666e1b2dc70SSimon Arlott 
667b8a19382SCharles Keepax 	if (type & IRQ_TYPE_EDGE_BOTH)
6681aa74fd0SThomas Gleixner 		irq_set_handler_locked(data, handle_edge_irq);
669b8a19382SCharles Keepax 	else
6701aa74fd0SThomas Gleixner 		irq_set_handler_locked(data, handle_level_irq);
671b8a19382SCharles Keepax 
6723c7b30f7SLukas Wunner 	raw_spin_unlock_irqrestore(&pc->irq_lock[bank], flags);
673e1b2dc70SSimon Arlott 
674e1b2dc70SSimon Arlott 	return ret;
675e1b2dc70SSimon Arlott }
676e1b2dc70SSimon Arlott 
bcm2835_gpio_irq_ack(struct irq_data * data)677b8a19382SCharles Keepax static void bcm2835_gpio_irq_ack(struct irq_data *data)
678b8a19382SCharles Keepax {
67985ae9e51SLinus Walleij 	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
68085ae9e51SLinus Walleij 	struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
681b8a19382SCharles Keepax 	unsigned gpio = irqd_to_hwirq(data);
682b8a19382SCharles Keepax 
683b8a19382SCharles Keepax 	bcm2835_gpio_set_bit(pc, GPEDS0, gpio);
684b8a19382SCharles Keepax }
685b8a19382SCharles Keepax 
bcm2835_gpio_irq_set_wake(struct irq_data * data,unsigned int on)686920fecc1SFlorian Fainelli static int bcm2835_gpio_irq_set_wake(struct irq_data *data, unsigned int on)
687920fecc1SFlorian Fainelli {
688920fecc1SFlorian Fainelli 	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
689920fecc1SFlorian Fainelli 	struct bcm2835_pinctrl *pc = gpiochip_get_data(chip);
690920fecc1SFlorian Fainelli 	unsigned gpio = irqd_to_hwirq(data);
691920fecc1SFlorian Fainelli 	unsigned int irqgroup;
692920fecc1SFlorian Fainelli 	int ret = -EINVAL;
693920fecc1SFlorian Fainelli 
694920fecc1SFlorian Fainelli 	if (!pc->wake_irq)
695920fecc1SFlorian Fainelli 		return ret;
696920fecc1SFlorian Fainelli 
697920fecc1SFlorian Fainelli 	if (gpio <= 27)
698920fecc1SFlorian Fainelli 		irqgroup = 0;
699920fecc1SFlorian Fainelli 	else if (gpio >= 28 && gpio <= 45)
700920fecc1SFlorian Fainelli 		irqgroup = 1;
701920fecc1SFlorian Fainelli 	else if (gpio >= 46 && gpio <= 57)
702920fecc1SFlorian Fainelli 		irqgroup = 2;
703920fecc1SFlorian Fainelli 	else
704920fecc1SFlorian Fainelli 		return ret;
705920fecc1SFlorian Fainelli 
706920fecc1SFlorian Fainelli 	if (on)
707920fecc1SFlorian Fainelli 		ret = enable_irq_wake(pc->wake_irq[irqgroup]);
708920fecc1SFlorian Fainelli 	else
709920fecc1SFlorian Fainelli 		ret = disable_irq_wake(pc->wake_irq[irqgroup]);
710920fecc1SFlorian Fainelli 
711920fecc1SFlorian Fainelli 	return ret;
712920fecc1SFlorian Fainelli }
713920fecc1SFlorian Fainelli 
71408752e07SStefan Wahren static const struct irq_chip bcm2835_gpio_irq_chip = {
715e1b2dc70SSimon Arlott 	.name = MODULE_NAME,
716e1b2dc70SSimon Arlott 	.irq_set_type = bcm2835_gpio_irq_set_type,
717b8a19382SCharles Keepax 	.irq_ack = bcm2835_gpio_irq_ack,
718db1b3eceSStefan Wahren 	.irq_mask = bcm2835_gpio_irq_mask,
719db1b3eceSStefan Wahren 	.irq_unmask = bcm2835_gpio_irq_unmask,
720920fecc1SFlorian Fainelli 	.irq_set_wake = bcm2835_gpio_irq_set_wake,
72108752e07SStefan Wahren 	.flags = (IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE),
72208752e07SStefan Wahren 	GPIOCHIP_IRQ_RESOURCE_HELPERS,
723e1b2dc70SSimon Arlott };
724e1b2dc70SSimon Arlott 
bcm2835_pctl_get_groups_count(struct pinctrl_dev * pctldev)725e1b2dc70SSimon Arlott static int bcm2835_pctl_get_groups_count(struct pinctrl_dev *pctldev)
726e1b2dc70SSimon Arlott {
727b1d84a3dSStefan Wahren 	return BCM2835_NUM_GPIOS;
728e1b2dc70SSimon Arlott }
729e1b2dc70SSimon Arlott 
bcm2835_pctl_get_group_name(struct pinctrl_dev * pctldev,unsigned selector)730e1b2dc70SSimon Arlott static const char *bcm2835_pctl_get_group_name(struct pinctrl_dev *pctldev,
731e1b2dc70SSimon Arlott 		unsigned selector)
732e1b2dc70SSimon Arlott {
733e1b2dc70SSimon Arlott 	return bcm2835_gpio_groups[selector];
734e1b2dc70SSimon Arlott }
735e1b2dc70SSimon Arlott 
bcm2835_pctl_get_group_pins(struct pinctrl_dev * pctldev,unsigned selector,const unsigned ** pins,unsigned * num_pins)736e1b2dc70SSimon Arlott static int bcm2835_pctl_get_group_pins(struct pinctrl_dev *pctldev,
737e1b2dc70SSimon Arlott 		unsigned selector,
738e1b2dc70SSimon Arlott 		const unsigned **pins,
739e1b2dc70SSimon Arlott 		unsigned *num_pins)
740e1b2dc70SSimon Arlott {
741e1b2dc70SSimon Arlott 	*pins = &bcm2835_gpio_pins[selector].number;
742e1b2dc70SSimon Arlott 	*num_pins = 1;
743e1b2dc70SSimon Arlott 
744e1b2dc70SSimon Arlott 	return 0;
745e1b2dc70SSimon Arlott }
746e1b2dc70SSimon Arlott 
bcm2835_pctl_pin_dbg_show(struct pinctrl_dev * pctldev,struct seq_file * s,unsigned offset)747e1b2dc70SSimon Arlott static void bcm2835_pctl_pin_dbg_show(struct pinctrl_dev *pctldev,
748e1b2dc70SSimon Arlott 		struct seq_file *s,
749e1b2dc70SSimon Arlott 		unsigned offset)
750e1b2dc70SSimon Arlott {
751e1b2dc70SSimon Arlott 	struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
75285ae9e51SLinus Walleij 	struct gpio_chip *chip = &pc->gpio_chip;
753e1b2dc70SSimon Arlott 	enum bcm2835_fsel fsel = bcm2835_pinctrl_fsel_get(pc, offset);
754e1b2dc70SSimon Arlott 	const char *fname = bcm2835_functions[fsel];
755e1b2dc70SSimon Arlott 	int value = bcm2835_gpio_get_bit(pc, GPLEV0, offset);
756f0fbe7bcSThierry Reding 	int irq = irq_find_mapping(chip->irq.domain, offset);
757e1b2dc70SSimon Arlott 
758e1b2dc70SSimon Arlott 	seq_printf(s, "function %s in %s; irq %d (%s)",
7591583dc16SStefan Wahren 		fname, str_hi_lo(value),
760e1b2dc70SSimon Arlott 		irq, irq_type_names[pc->irq_type[offset]]);
761e1b2dc70SSimon Arlott }
762e1b2dc70SSimon Arlott 
bcm2835_pctl_dt_free_map(struct pinctrl_dev * pctldev,struct pinctrl_map * maps,unsigned num_maps)763e1b2dc70SSimon Arlott static void bcm2835_pctl_dt_free_map(struct pinctrl_dev *pctldev,
764e1b2dc70SSimon Arlott 		struct pinctrl_map *maps, unsigned num_maps)
765e1b2dc70SSimon Arlott {
766e1b2dc70SSimon Arlott 	int i;
767e1b2dc70SSimon Arlott 
768e1b2dc70SSimon Arlott 	for (i = 0; i < num_maps; i++)
769e1b2dc70SSimon Arlott 		if (maps[i].type == PIN_MAP_TYPE_CONFIGS_PIN)
770e1b2dc70SSimon Arlott 			kfree(maps[i].data.configs.configs);
771e1b2dc70SSimon Arlott 
772e1b2dc70SSimon Arlott 	kfree(maps);
773e1b2dc70SSimon Arlott }
774e1b2dc70SSimon Arlott 
bcm2835_pctl_dt_node_to_map_func(struct bcm2835_pinctrl * pc,struct device_node * np,u32 pin,u32 fnum,struct pinctrl_map ** maps)775e1b2dc70SSimon Arlott static int bcm2835_pctl_dt_node_to_map_func(struct bcm2835_pinctrl *pc,
776e1b2dc70SSimon Arlott 		struct device_node *np, u32 pin, u32 fnum,
777e1b2dc70SSimon Arlott 		struct pinctrl_map **maps)
778e1b2dc70SSimon Arlott {
779e1b2dc70SSimon Arlott 	struct pinctrl_map *map = *maps;
780e1b2dc70SSimon Arlott 
781e1b2dc70SSimon Arlott 	if (fnum >= ARRAY_SIZE(bcm2835_functions)) {
782f5292d06SRob Herring 		dev_err(pc->dev, "%pOF: invalid brcm,function %d\n", np, fnum);
783e1b2dc70SSimon Arlott 		return -EINVAL;
784e1b2dc70SSimon Arlott 	}
785e1b2dc70SSimon Arlott 
786e1b2dc70SSimon Arlott 	map->type = PIN_MAP_TYPE_MUX_GROUP;
787e1b2dc70SSimon Arlott 	map->data.mux.group = bcm2835_gpio_groups[pin];
788e1b2dc70SSimon Arlott 	map->data.mux.function = bcm2835_functions[fnum];
789e1b2dc70SSimon Arlott 	(*maps)++;
790e1b2dc70SSimon Arlott 
791e1b2dc70SSimon Arlott 	return 0;
792e1b2dc70SSimon Arlott }
793e1b2dc70SSimon Arlott 
bcm2835_pctl_dt_node_to_map_pull(struct bcm2835_pinctrl * pc,struct device_node * np,u32 pin,u32 pull,struct pinctrl_map ** maps)794e1b2dc70SSimon Arlott static int bcm2835_pctl_dt_node_to_map_pull(struct bcm2835_pinctrl *pc,
795e1b2dc70SSimon Arlott 		struct device_node *np, u32 pin, u32 pull,
796e1b2dc70SSimon Arlott 		struct pinctrl_map **maps)
797e1b2dc70SSimon Arlott {
798e1b2dc70SSimon Arlott 	struct pinctrl_map *map = *maps;
799e1b2dc70SSimon Arlott 	unsigned long *configs;
800e1b2dc70SSimon Arlott 
801e1b2dc70SSimon Arlott 	if (pull > 2) {
802f5292d06SRob Herring 		dev_err(pc->dev, "%pOF: invalid brcm,pull %d\n", np, pull);
803e1b2dc70SSimon Arlott 		return -EINVAL;
804e1b2dc70SSimon Arlott 	}
805e1b2dc70SSimon Arlott 
806e1b2dc70SSimon Arlott 	configs = kzalloc(sizeof(*configs), GFP_KERNEL);
807e1b2dc70SSimon Arlott 	if (!configs)
808e1b2dc70SSimon Arlott 		return -ENOMEM;
8090de70495SMatheus Castello 	configs[0] = pinconf_to_config_packed(BCM2835_PINCONF_PARAM_PULL, pull);
810e1b2dc70SSimon Arlott 
811e1b2dc70SSimon Arlott 	map->type = PIN_MAP_TYPE_CONFIGS_PIN;
812e1b2dc70SSimon Arlott 	map->data.configs.group_or_pin = bcm2835_gpio_pins[pin].name;
813e1b2dc70SSimon Arlott 	map->data.configs.configs = configs;
814e1b2dc70SSimon Arlott 	map->data.configs.num_configs = 1;
815e1b2dc70SSimon Arlott 	(*maps)++;
816e1b2dc70SSimon Arlott 
817e1b2dc70SSimon Arlott 	return 0;
818e1b2dc70SSimon Arlott }
819e1b2dc70SSimon Arlott 
bcm2835_pctl_dt_node_to_map(struct pinctrl_dev * pctldev,struct device_node * np,struct pinctrl_map ** map,unsigned int * num_maps)820e1b2dc70SSimon Arlott static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
821e1b2dc70SSimon Arlott 		struct device_node *np,
8220de70495SMatheus Castello 		struct pinctrl_map **map, unsigned int *num_maps)
823e1b2dc70SSimon Arlott {
824e1b2dc70SSimon Arlott 	struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
825e1b2dc70SSimon Arlott 	struct property *pins, *funcs, *pulls;
826e1b2dc70SSimon Arlott 	int num_pins, num_funcs, num_pulls, maps_per_pin;
827e1b2dc70SSimon Arlott 	struct pinctrl_map *maps, *cur_map;
828e1b2dc70SSimon Arlott 	int i, err;
829e1b2dc70SSimon Arlott 	u32 pin, func, pull;
830e1b2dc70SSimon Arlott 
8310de70495SMatheus Castello 	/* Check for generic binding in this node */
8320de70495SMatheus Castello 	err = pinconf_generic_dt_node_to_map_all(pctldev, np, map, num_maps);
8330de70495SMatheus Castello 	if (err || *num_maps)
8340de70495SMatheus Castello 		return err;
8350de70495SMatheus Castello 
8360de70495SMatheus Castello 	/* Generic binding did not find anything continue with legacy parse */
837e1b2dc70SSimon Arlott 	pins = of_find_property(np, "brcm,pins", NULL);
838e1b2dc70SSimon Arlott 	if (!pins) {
839f5292d06SRob Herring 		dev_err(pc->dev, "%pOF: missing brcm,pins property\n", np);
840e1b2dc70SSimon Arlott 		return -EINVAL;
841e1b2dc70SSimon Arlott 	}
842e1b2dc70SSimon Arlott 
843e1b2dc70SSimon Arlott 	funcs = of_find_property(np, "brcm,function", NULL);
844e1b2dc70SSimon Arlott 	pulls = of_find_property(np, "brcm,pull", NULL);
845e1b2dc70SSimon Arlott 
846e1b2dc70SSimon Arlott 	if (!funcs && !pulls) {
847e1b2dc70SSimon Arlott 		dev_err(pc->dev,
848f5292d06SRob Herring 			"%pOF: neither brcm,function nor brcm,pull specified\n",
849f5292d06SRob Herring 			np);
850e1b2dc70SSimon Arlott 		return -EINVAL;
851e1b2dc70SSimon Arlott 	}
852e1b2dc70SSimon Arlott 
853e1b2dc70SSimon Arlott 	num_pins = pins->length / 4;
854e1b2dc70SSimon Arlott 	num_funcs = funcs ? (funcs->length / 4) : 0;
855e1b2dc70SSimon Arlott 	num_pulls = pulls ? (pulls->length / 4) : 0;
856e1b2dc70SSimon Arlott 
857e1b2dc70SSimon Arlott 	if (num_funcs > 1 && num_funcs != num_pins) {
858e1b2dc70SSimon Arlott 		dev_err(pc->dev,
859f5292d06SRob Herring 			"%pOF: brcm,function must have 1 or %d entries\n",
860f5292d06SRob Herring 			np, num_pins);
861e1b2dc70SSimon Arlott 		return -EINVAL;
862e1b2dc70SSimon Arlott 	}
863e1b2dc70SSimon Arlott 
864e1b2dc70SSimon Arlott 	if (num_pulls > 1 && num_pulls != num_pins) {
865e1b2dc70SSimon Arlott 		dev_err(pc->dev,
866f5292d06SRob Herring 			"%pOF: brcm,pull must have 1 or %d entries\n",
867f5292d06SRob Herring 			np, num_pins);
868e1b2dc70SSimon Arlott 		return -EINVAL;
869e1b2dc70SSimon Arlott 	}
870e1b2dc70SSimon Arlott 
871e1b2dc70SSimon Arlott 	maps_per_pin = 0;
872e1b2dc70SSimon Arlott 	if (num_funcs)
873e1b2dc70SSimon Arlott 		maps_per_pin++;
874e1b2dc70SSimon Arlott 	if (num_pulls)
875e1b2dc70SSimon Arlott 		maps_per_pin++;
8766396bb22SKees Cook 	cur_map = maps = kcalloc(num_pins * maps_per_pin, sizeof(*maps),
877e1b2dc70SSimon Arlott 				 GFP_KERNEL);
878e1b2dc70SSimon Arlott 	if (!maps)
879e1b2dc70SSimon Arlott 		return -ENOMEM;
880e1b2dc70SSimon Arlott 
881e1b2dc70SSimon Arlott 	for (i = 0; i < num_pins; i++) {
882ce63d6d4SStephen Warren 		err = of_property_read_u32_index(np, "brcm,pins", i, &pin);
883ce63d6d4SStephen Warren 		if (err)
884ce63d6d4SStephen Warren 			goto out;
885b1d84a3dSStefan Wahren 		if (pin >= pc->pctl_desc.npins) {
886f5292d06SRob Herring 			dev_err(pc->dev, "%pOF: invalid brcm,pins value %d\n",
887f5292d06SRob Herring 				np, pin);
888e1b2dc70SSimon Arlott 			err = -EINVAL;
889e1b2dc70SSimon Arlott 			goto out;
890e1b2dc70SSimon Arlott 		}
891e1b2dc70SSimon Arlott 
892e1b2dc70SSimon Arlott 		if (num_funcs) {
893ce63d6d4SStephen Warren 			err = of_property_read_u32_index(np, "brcm,function",
894ce63d6d4SStephen Warren 					(num_funcs > 1) ? i : 0, &func);
895ce63d6d4SStephen Warren 			if (err)
896ce63d6d4SStephen Warren 				goto out;
897e1b2dc70SSimon Arlott 			err = bcm2835_pctl_dt_node_to_map_func(pc, np, pin,
898e1b2dc70SSimon Arlott 							func, &cur_map);
899e1b2dc70SSimon Arlott 			if (err)
900e1b2dc70SSimon Arlott 				goto out;
901e1b2dc70SSimon Arlott 		}
902e1b2dc70SSimon Arlott 		if (num_pulls) {
903ce63d6d4SStephen Warren 			err = of_property_read_u32_index(np, "brcm,pull",
9042c7e3306SPhil Elwell 					(num_pulls > 1) ? i : 0, &pull);
905ce63d6d4SStephen Warren 			if (err)
906ce63d6d4SStephen Warren 				goto out;
907e1b2dc70SSimon Arlott 			err = bcm2835_pctl_dt_node_to_map_pull(pc, np, pin,
908e1b2dc70SSimon Arlott 							pull, &cur_map);
909e1b2dc70SSimon Arlott 			if (err)
910e1b2dc70SSimon Arlott 				goto out;
911e1b2dc70SSimon Arlott 		}
912e1b2dc70SSimon Arlott 	}
913e1b2dc70SSimon Arlott 
914e1b2dc70SSimon Arlott 	*map = maps;
915e1b2dc70SSimon Arlott 	*num_maps = num_pins * maps_per_pin;
916e1b2dc70SSimon Arlott 
917e1b2dc70SSimon Arlott 	return 0;
918e1b2dc70SSimon Arlott 
919e1b2dc70SSimon Arlott out:
92053653c6bSStefan Wahren 	bcm2835_pctl_dt_free_map(pctldev, maps, num_pins * maps_per_pin);
921e1b2dc70SSimon Arlott 	return err;
922e1b2dc70SSimon Arlott }
923e1b2dc70SSimon Arlott 
924022ab148SLaurent Pinchart static const struct pinctrl_ops bcm2835_pctl_ops = {
925e1b2dc70SSimon Arlott 	.get_groups_count = bcm2835_pctl_get_groups_count,
926e1b2dc70SSimon Arlott 	.get_group_name = bcm2835_pctl_get_group_name,
927e1b2dc70SSimon Arlott 	.get_group_pins = bcm2835_pctl_get_group_pins,
928e1b2dc70SSimon Arlott 	.pin_dbg_show = bcm2835_pctl_pin_dbg_show,
929e1b2dc70SSimon Arlott 	.dt_node_to_map = bcm2835_pctl_dt_node_to_map,
930e1b2dc70SSimon Arlott 	.dt_free_map = bcm2835_pctl_dt_free_map,
931e1b2dc70SSimon Arlott };
932e1b2dc70SSimon Arlott 
bcm2835_pmx_free(struct pinctrl_dev * pctldev,unsigned offset)933ccca1ad5SPhil Elwell static int bcm2835_pmx_free(struct pinctrl_dev *pctldev,
934ccca1ad5SPhil Elwell 		unsigned offset)
935ccca1ad5SPhil Elwell {
936ccca1ad5SPhil Elwell 	struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
9378ff05989SStefan Wahren 	enum bcm2835_fsel fsel = bcm2835_pinctrl_fsel_get(pc, offset);
9388ff05989SStefan Wahren 
9398ff05989SStefan Wahren 	if (fsel == BCM2835_FSEL_GPIO_IN)
9408ff05989SStefan Wahren 		return 0;
9418ff05989SStefan Wahren 
9428ff05989SStefan Wahren 	if (persist_gpio_outputs && fsel == BCM2835_FSEL_GPIO_OUT)
9438ff05989SStefan Wahren 		return 0;
944ccca1ad5SPhil Elwell 
945ccca1ad5SPhil Elwell 	/* disable by setting to GPIO_IN */
946ccca1ad5SPhil Elwell 	bcm2835_pinctrl_fsel_set(pc, offset, BCM2835_FSEL_GPIO_IN);
947ccca1ad5SPhil Elwell 	return 0;
948ccca1ad5SPhil Elwell }
949ccca1ad5SPhil Elwell 
bcm2835_pmx_get_functions_count(struct pinctrl_dev * pctldev)950e1b2dc70SSimon Arlott static int bcm2835_pmx_get_functions_count(struct pinctrl_dev *pctldev)
951e1b2dc70SSimon Arlott {
952e1b2dc70SSimon Arlott 	return BCM2835_FSEL_COUNT;
953e1b2dc70SSimon Arlott }
954e1b2dc70SSimon Arlott 
bcm2835_pmx_get_function_name(struct pinctrl_dev * pctldev,unsigned selector)955e1b2dc70SSimon Arlott static const char *bcm2835_pmx_get_function_name(struct pinctrl_dev *pctldev,
956e1b2dc70SSimon Arlott 		unsigned selector)
957e1b2dc70SSimon Arlott {
958e1b2dc70SSimon Arlott 	return bcm2835_functions[selector];
959e1b2dc70SSimon Arlott }
960e1b2dc70SSimon Arlott 
bcm2835_pmx_get_function_groups(struct pinctrl_dev * pctldev,unsigned selector,const char * const ** groups,unsigned * const num_groups)961e1b2dc70SSimon Arlott static int bcm2835_pmx_get_function_groups(struct pinctrl_dev *pctldev,
962e1b2dc70SSimon Arlott 		unsigned selector,
963e1b2dc70SSimon Arlott 		const char * const **groups,
964e1b2dc70SSimon Arlott 		unsigned * const num_groups)
965e1b2dc70SSimon Arlott {
966e1b2dc70SSimon Arlott 	/* every pin can do every function */
967e1b2dc70SSimon Arlott 	*groups = bcm2835_gpio_groups;
968b1d84a3dSStefan Wahren 	*num_groups = BCM2835_NUM_GPIOS;
969e1b2dc70SSimon Arlott 
970e1b2dc70SSimon Arlott 	return 0;
971e1b2dc70SSimon Arlott }
972e1b2dc70SSimon Arlott 
bcm2835_pmx_set(struct pinctrl_dev * pctldev,unsigned func_selector,unsigned group_selector)97303e9f0caSLinus Walleij static int bcm2835_pmx_set(struct pinctrl_dev *pctldev,
974e1b2dc70SSimon Arlott 		unsigned func_selector,
975e1b2dc70SSimon Arlott 		unsigned group_selector)
976e1b2dc70SSimon Arlott {
977e1b2dc70SSimon Arlott 	struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
978e1b2dc70SSimon Arlott 
979e1b2dc70SSimon Arlott 	bcm2835_pinctrl_fsel_set(pc, group_selector, func_selector);
980e1b2dc70SSimon Arlott 
981e1b2dc70SSimon Arlott 	return 0;
982e1b2dc70SSimon Arlott }
983e1b2dc70SSimon Arlott 
bcm2835_pmx_gpio_disable_free(struct pinctrl_dev * pctldev,struct pinctrl_gpio_range * range,unsigned offset)984e1b2dc70SSimon Arlott static void bcm2835_pmx_gpio_disable_free(struct pinctrl_dev *pctldev,
985e1b2dc70SSimon Arlott 		struct pinctrl_gpio_range *range,
986e1b2dc70SSimon Arlott 		unsigned offset)
987e1b2dc70SSimon Arlott {
9888ff05989SStefan Wahren 	bcm2835_pmx_free(pctldev, offset);
989e1b2dc70SSimon Arlott }
990e1b2dc70SSimon Arlott 
bcm2835_pmx_gpio_set_direction(struct pinctrl_dev * pctldev,struct pinctrl_gpio_range * range,unsigned offset,bool input)991e1b2dc70SSimon Arlott static int bcm2835_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
992e1b2dc70SSimon Arlott 		struct pinctrl_gpio_range *range,
993e1b2dc70SSimon Arlott 		unsigned offset,
994e1b2dc70SSimon Arlott 		bool input)
995e1b2dc70SSimon Arlott {
996e1b2dc70SSimon Arlott 	struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
997e1b2dc70SSimon Arlott 	enum bcm2835_fsel fsel = input ?
998e1b2dc70SSimon Arlott 		BCM2835_FSEL_GPIO_IN : BCM2835_FSEL_GPIO_OUT;
999e1b2dc70SSimon Arlott 
1000e1b2dc70SSimon Arlott 	bcm2835_pinctrl_fsel_set(pc, offset, fsel);
1001e1b2dc70SSimon Arlott 
1002e1b2dc70SSimon Arlott 	return 0;
1003e1b2dc70SSimon Arlott }
1004e1b2dc70SSimon Arlott 
1005022ab148SLaurent Pinchart static const struct pinmux_ops bcm2835_pmx_ops = {
1006ccca1ad5SPhil Elwell 	.free = bcm2835_pmx_free,
1007e1b2dc70SSimon Arlott 	.get_functions_count = bcm2835_pmx_get_functions_count,
1008e1b2dc70SSimon Arlott 	.get_function_name = bcm2835_pmx_get_function_name,
1009e1b2dc70SSimon Arlott 	.get_function_groups = bcm2835_pmx_get_function_groups,
101003e9f0caSLinus Walleij 	.set_mux = bcm2835_pmx_set,
1011e1b2dc70SSimon Arlott 	.gpio_disable_free = bcm2835_pmx_gpio_disable_free,
1012e1b2dc70SSimon Arlott 	.gpio_set_direction = bcm2835_pmx_gpio_set_direction,
1013e1b2dc70SSimon Arlott };
1014e1b2dc70SSimon Arlott 
bcm2835_pinconf_get(struct pinctrl_dev * pctldev,unsigned pin,unsigned long * config)1015e1b2dc70SSimon Arlott static int bcm2835_pinconf_get(struct pinctrl_dev *pctldev,
1016e1b2dc70SSimon Arlott 			unsigned pin, unsigned long *config)
1017e1b2dc70SSimon Arlott {
101885b02bc0SStefan Wahren 	enum pin_config_param param = pinconf_to_config_param(*config);
101985b02bc0SStefan Wahren 	struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
102085b02bc0SStefan Wahren 	enum bcm2835_fsel fsel = bcm2835_pinctrl_fsel_get(pc, pin);
102185b02bc0SStefan Wahren 	u32 val;
102285b02bc0SStefan Wahren 
102385b02bc0SStefan Wahren 	/* No way to read back bias config in HW */
102485b02bc0SStefan Wahren 
102585b02bc0SStefan Wahren 	switch (param) {
102685b02bc0SStefan Wahren 	case PIN_CONFIG_OUTPUT:
102785b02bc0SStefan Wahren 		if (fsel != BCM2835_FSEL_GPIO_OUT)
102885b02bc0SStefan Wahren 			return -EINVAL;
102985b02bc0SStefan Wahren 
103085b02bc0SStefan Wahren 		val = bcm2835_gpio_get_bit(pc, GPLEV0, pin);
103185b02bc0SStefan Wahren 		*config = pinconf_to_config_packed(param, val);
103285b02bc0SStefan Wahren 		break;
103385b02bc0SStefan Wahren 
103485b02bc0SStefan Wahren 	default:
1035e1b2dc70SSimon Arlott 		return -ENOTSUPP;
1036e1b2dc70SSimon Arlott 	}
1037e1b2dc70SSimon Arlott 
103885b02bc0SStefan Wahren 	return 0;
103985b02bc0SStefan Wahren }
104085b02bc0SStefan Wahren 
bcm2835_pull_config_set(struct bcm2835_pinctrl * pc,unsigned int pin,unsigned int arg)10410de70495SMatheus Castello static void bcm2835_pull_config_set(struct bcm2835_pinctrl *pc,
10420de70495SMatheus Castello 		unsigned int pin, unsigned int arg)
1043e1b2dc70SSimon Arlott {
1044e1b2dc70SSimon Arlott 	u32 off, bit;
1045e1b2dc70SSimon Arlott 
1046e1b2dc70SSimon Arlott 	off = GPIO_REG_OFFSET(pin);
1047e1b2dc70SSimon Arlott 	bit = GPIO_REG_SHIFT(pin);
1048e1b2dc70SSimon Arlott 
1049e1b2dc70SSimon Arlott 	bcm2835_gpio_wr(pc, GPPUD, arg & 3);
1050e1b2dc70SSimon Arlott 	/*
1051b83bd893SStefan Wahren 	 * BCM2835 datasheet say to wait 150 cycles, but not of what.
1052b83bd893SStefan Wahren 	 * But the VideoCore firmware delay for this operation
1053b83bd893SStefan Wahren 	 * based nearly on the same amount of VPU cycles and this clock
1054b83bd893SStefan Wahren 	 * runs at 250 MHz.
1055e1b2dc70SSimon Arlott 	 */
1056b83bd893SStefan Wahren 	udelay(1);
1057e1b2dc70SSimon Arlott 	bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), BIT(bit));
1058b83bd893SStefan Wahren 	udelay(1);
1059e1b2dc70SSimon Arlott 	bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), 0);
10600de70495SMatheus Castello }
10610de70495SMatheus Castello 
bcm2835_pinconf_set(struct pinctrl_dev * pctldev,unsigned int pin,unsigned long * configs,unsigned int num_configs)10620de70495SMatheus Castello static int bcm2835_pinconf_set(struct pinctrl_dev *pctldev,
10630de70495SMatheus Castello 			unsigned int pin, unsigned long *configs,
10640de70495SMatheus Castello 			unsigned int num_configs)
10650de70495SMatheus Castello {
10660de70495SMatheus Castello 	struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
10670de70495SMatheus Castello 	u32 param, arg;
10680de70495SMatheus Castello 	int i;
10690de70495SMatheus Castello 
10700de70495SMatheus Castello 	for (i = 0; i < num_configs; i++) {
10710de70495SMatheus Castello 		param = pinconf_to_config_param(configs[i]);
10720de70495SMatheus Castello 		arg = pinconf_to_config_argument(configs[i]);
10730de70495SMatheus Castello 
10740de70495SMatheus Castello 		switch (param) {
10750de70495SMatheus Castello 		/* Set legacy brcm,pull */
10760de70495SMatheus Castello 		case BCM2835_PINCONF_PARAM_PULL:
10770de70495SMatheus Castello 			bcm2835_pull_config_set(pc, pin, arg);
10780de70495SMatheus Castello 			break;
10790de70495SMatheus Castello 
10800de70495SMatheus Castello 		/* Set pull generic bindings */
10810de70495SMatheus Castello 		case PIN_CONFIG_BIAS_DISABLE:
10820de70495SMatheus Castello 			bcm2835_pull_config_set(pc, pin, BCM2835_PUD_OFF);
10830de70495SMatheus Castello 			break;
10840de70495SMatheus Castello 
10850de70495SMatheus Castello 		case PIN_CONFIG_BIAS_PULL_DOWN:
10860de70495SMatheus Castello 			bcm2835_pull_config_set(pc, pin, BCM2835_PUD_DOWN);
10870de70495SMatheus Castello 			break;
10880de70495SMatheus Castello 
10890de70495SMatheus Castello 		case PIN_CONFIG_BIAS_PULL_UP:
10900de70495SMatheus Castello 			bcm2835_pull_config_set(pc, pin, BCM2835_PUD_UP);
10910de70495SMatheus Castello 			break;
10920de70495SMatheus Castello 
109390b60552SMatheus Castello 		/* Set output-high or output-low */
109490b60552SMatheus Castello 		case PIN_CONFIG_OUTPUT:
109590b60552SMatheus Castello 			bcm2835_gpio_set_bit(pc, arg ? GPSET0 : GPCLR0, pin);
109690b60552SMatheus Castello 			break;
109790b60552SMatheus Castello 
10980de70495SMatheus Castello 		default:
1099b6e5531cSStefan Wahren 			return -ENOTSUPP;
11000de70495SMatheus Castello 
11010de70495SMatheus Castello 		} /* switch param type */
110203b054e9SSherman Yin 	} /* for each config */
1103e1b2dc70SSimon Arlott 
1104e1b2dc70SSimon Arlott 	return 0;
1105e1b2dc70SSimon Arlott }
1106e1b2dc70SSimon Arlott 
1107022ab148SLaurent Pinchart static const struct pinconf_ops bcm2835_pinconf_ops = {
11081cb66f08SStefan Wahren 	.is_generic = true,
1109e1b2dc70SSimon Arlott 	.pin_config_get = bcm2835_pinconf_get,
1110e1b2dc70SSimon Arlott 	.pin_config_set = bcm2835_pinconf_set,
1111e1b2dc70SSimon Arlott };
1112e1b2dc70SSimon Arlott 
bcm2711_pinconf_get(struct pinctrl_dev * pctldev,unsigned pin,unsigned long * config)1113d54e4cdaSStefan Wahren static int bcm2711_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin,
1114d54e4cdaSStefan Wahren 			       unsigned long *config)
1115d54e4cdaSStefan Wahren {
1116d54e4cdaSStefan Wahren 	struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
1117d54e4cdaSStefan Wahren 	enum pin_config_param param = pinconf_to_config_param(*config);
1118d54e4cdaSStefan Wahren 	u32 offset, shift, val;
1119d54e4cdaSStefan Wahren 
1120d54e4cdaSStefan Wahren 	offset = PUD_2711_REG_OFFSET(pin);
1121d54e4cdaSStefan Wahren 	shift = PUD_2711_REG_SHIFT(pin);
1122d54e4cdaSStefan Wahren 	val = bcm2835_gpio_rd(pc, GP_GPIO_PUP_PDN_CNTRL_REG0 + (offset * 4));
1123d54e4cdaSStefan Wahren 
1124d54e4cdaSStefan Wahren 	switch (param) {
1125d54e4cdaSStefan Wahren 	case PIN_CONFIG_BIAS_DISABLE:
1126d54e4cdaSStefan Wahren 		if (((val >> shift) & PUD_2711_MASK) != BCM2711_PULL_NONE)
1127d54e4cdaSStefan Wahren 			return -EINVAL;
1128d54e4cdaSStefan Wahren 
1129d54e4cdaSStefan Wahren 		break;
1130d54e4cdaSStefan Wahren 
1131d54e4cdaSStefan Wahren 	case PIN_CONFIG_BIAS_PULL_UP:
1132d54e4cdaSStefan Wahren 		if (((val >> shift) & PUD_2711_MASK) != BCM2711_PULL_UP)
1133d54e4cdaSStefan Wahren 			return -EINVAL;
1134d54e4cdaSStefan Wahren 
1135d54e4cdaSStefan Wahren 		*config = pinconf_to_config_packed(param, 50000);
1136d54e4cdaSStefan Wahren 		break;
1137d54e4cdaSStefan Wahren 
1138d54e4cdaSStefan Wahren 	case PIN_CONFIG_BIAS_PULL_DOWN:
1139d54e4cdaSStefan Wahren 		if (((val >> shift) & PUD_2711_MASK) != BCM2711_PULL_DOWN)
1140d54e4cdaSStefan Wahren 			return -EINVAL;
1141d54e4cdaSStefan Wahren 
1142d54e4cdaSStefan Wahren 		*config = pinconf_to_config_packed(param, 50000);
1143d54e4cdaSStefan Wahren 		break;
1144d54e4cdaSStefan Wahren 
1145d54e4cdaSStefan Wahren 	default:
1146d54e4cdaSStefan Wahren 		return bcm2835_pinconf_get(pctldev, pin, config);
1147d54e4cdaSStefan Wahren 	}
1148d54e4cdaSStefan Wahren 
1149d54e4cdaSStefan Wahren 	return 0;
1150d54e4cdaSStefan Wahren }
1151d54e4cdaSStefan Wahren 
bcm2711_pull_config_set(struct bcm2835_pinctrl * pc,unsigned int pin,unsigned int arg)1152e38a9a43SStefan Wahren static void bcm2711_pull_config_set(struct bcm2835_pinctrl *pc,
1153e38a9a43SStefan Wahren 				    unsigned int pin, unsigned int arg)
1154e38a9a43SStefan Wahren {
1155e38a9a43SStefan Wahren 	u32 shifter;
1156e38a9a43SStefan Wahren 	u32 value;
1157e38a9a43SStefan Wahren 	u32 off;
1158e38a9a43SStefan Wahren 
1159e38a9a43SStefan Wahren 	off = PUD_2711_REG_OFFSET(pin);
1160e38a9a43SStefan Wahren 	shifter = PUD_2711_REG_SHIFT(pin);
1161e38a9a43SStefan Wahren 
1162e38a9a43SStefan Wahren 	value = bcm2835_gpio_rd(pc, GP_GPIO_PUP_PDN_CNTRL_REG0 + (off * 4));
1163e38a9a43SStefan Wahren 	value &= ~(PUD_2711_MASK << shifter);
1164e38a9a43SStefan Wahren 	value |= (arg << shifter);
1165e38a9a43SStefan Wahren 	bcm2835_gpio_wr(pc, GP_GPIO_PUP_PDN_CNTRL_REG0 + (off * 4), value);
1166e38a9a43SStefan Wahren }
1167e38a9a43SStefan Wahren 
bcm2711_pinconf_set(struct pinctrl_dev * pctldev,unsigned int pin,unsigned long * configs,unsigned int num_configs)1168e38a9a43SStefan Wahren static int bcm2711_pinconf_set(struct pinctrl_dev *pctldev,
1169e38a9a43SStefan Wahren 			       unsigned int pin, unsigned long *configs,
1170e38a9a43SStefan Wahren 			       unsigned int num_configs)
1171e38a9a43SStefan Wahren {
1172e38a9a43SStefan Wahren 	struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
1173e38a9a43SStefan Wahren 	u32 param, arg;
1174e38a9a43SStefan Wahren 	int i;
1175e38a9a43SStefan Wahren 
1176e38a9a43SStefan Wahren 	for (i = 0; i < num_configs; i++) {
1177e38a9a43SStefan Wahren 		param = pinconf_to_config_param(configs[i]);
1178e38a9a43SStefan Wahren 		arg = pinconf_to_config_argument(configs[i]);
1179e38a9a43SStefan Wahren 
1180e38a9a43SStefan Wahren 		switch (param) {
1181e38a9a43SStefan Wahren 		/* convert legacy brcm,pull */
1182e38a9a43SStefan Wahren 		case BCM2835_PINCONF_PARAM_PULL:
1183e38a9a43SStefan Wahren 			if (arg == BCM2835_PUD_UP)
1184e38a9a43SStefan Wahren 				arg = BCM2711_PULL_UP;
1185e38a9a43SStefan Wahren 			else if (arg == BCM2835_PUD_DOWN)
1186e38a9a43SStefan Wahren 				arg = BCM2711_PULL_DOWN;
1187e38a9a43SStefan Wahren 			else
1188e38a9a43SStefan Wahren 				arg = BCM2711_PULL_NONE;
1189e38a9a43SStefan Wahren 
1190e38a9a43SStefan Wahren 			bcm2711_pull_config_set(pc, pin, arg);
1191e38a9a43SStefan Wahren 			break;
1192e38a9a43SStefan Wahren 
1193e38a9a43SStefan Wahren 		/* Set pull generic bindings */
1194e38a9a43SStefan Wahren 		case PIN_CONFIG_BIAS_DISABLE:
1195e38a9a43SStefan Wahren 			bcm2711_pull_config_set(pc, pin, BCM2711_PULL_NONE);
1196e38a9a43SStefan Wahren 			break;
1197e38a9a43SStefan Wahren 		case PIN_CONFIG_BIAS_PULL_DOWN:
1198e38a9a43SStefan Wahren 			bcm2711_pull_config_set(pc, pin, BCM2711_PULL_DOWN);
1199e38a9a43SStefan Wahren 			break;
1200e38a9a43SStefan Wahren 		case PIN_CONFIG_BIAS_PULL_UP:
1201e38a9a43SStefan Wahren 			bcm2711_pull_config_set(pc, pin, BCM2711_PULL_UP);
1202e38a9a43SStefan Wahren 			break;
1203e38a9a43SStefan Wahren 
1204e38a9a43SStefan Wahren 		/* Set output-high or output-low */
1205e38a9a43SStefan Wahren 		case PIN_CONFIG_OUTPUT:
1206e38a9a43SStefan Wahren 			bcm2835_gpio_set_bit(pc, arg ? GPSET0 : GPCLR0, pin);
1207e38a9a43SStefan Wahren 			break;
1208e38a9a43SStefan Wahren 
1209e38a9a43SStefan Wahren 		default:
1210e38a9a43SStefan Wahren 			return -ENOTSUPP;
1211e38a9a43SStefan Wahren 		}
1212e38a9a43SStefan Wahren 	} /* for each config */
1213e38a9a43SStefan Wahren 
1214e38a9a43SStefan Wahren 	return 0;
1215e38a9a43SStefan Wahren }
1216e38a9a43SStefan Wahren 
1217e38a9a43SStefan Wahren static const struct pinconf_ops bcm2711_pinconf_ops = {
1218e38a9a43SStefan Wahren 	.is_generic = true,
1219d54e4cdaSStefan Wahren 	.pin_config_get = bcm2711_pinconf_get,
1220e38a9a43SStefan Wahren 	.pin_config_set = bcm2711_pinconf_set,
1221e38a9a43SStefan Wahren };
1222e38a9a43SStefan Wahren 
122390bfaf02SStefan Wahren static const struct pinctrl_desc bcm2835_pinctrl_desc = {
1224e1b2dc70SSimon Arlott 	.name = MODULE_NAME,
1225e1b2dc70SSimon Arlott 	.pins = bcm2835_gpio_pins,
1226b1d84a3dSStefan Wahren 	.npins = BCM2835_NUM_GPIOS,
1227e1b2dc70SSimon Arlott 	.pctlops = &bcm2835_pctl_ops,
1228e1b2dc70SSimon Arlott 	.pmxops = &bcm2835_pmx_ops,
1229e1b2dc70SSimon Arlott 	.confops = &bcm2835_pinconf_ops,
1230e1b2dc70SSimon Arlott 	.owner = THIS_MODULE,
1231e1b2dc70SSimon Arlott };
1232e1b2dc70SSimon Arlott 
123390bfaf02SStefan Wahren static const struct pinctrl_desc bcm2711_pinctrl_desc = {
1234b1d84a3dSStefan Wahren 	.name = "pinctrl-bcm2711",
123590bfaf02SStefan Wahren 	.pins = bcm2835_gpio_pins,
1236b1d84a3dSStefan Wahren 	.npins = BCM2711_NUM_GPIOS,
123790bfaf02SStefan Wahren 	.pctlops = &bcm2835_pctl_ops,
123890bfaf02SStefan Wahren 	.pmxops = &bcm2835_pmx_ops,
123990bfaf02SStefan Wahren 	.confops = &bcm2711_pinconf_ops,
124090bfaf02SStefan Wahren 	.owner = THIS_MODULE,
124190bfaf02SStefan Wahren };
124290bfaf02SStefan Wahren 
124390bfaf02SStefan Wahren static const struct pinctrl_gpio_range bcm2835_pinctrl_gpio_range = {
1244e1b2dc70SSimon Arlott 	.name = MODULE_NAME,
1245e1b2dc70SSimon Arlott 	.npins = BCM2835_NUM_GPIOS,
1246e1b2dc70SSimon Arlott };
1247e1b2dc70SSimon Arlott 
1248b1d84a3dSStefan Wahren static const struct pinctrl_gpio_range bcm2711_pinctrl_gpio_range = {
1249b1d84a3dSStefan Wahren 	.name = "pinctrl-bcm2711",
1250b1d84a3dSStefan Wahren 	.npins = BCM2711_NUM_GPIOS,
1251b1d84a3dSStefan Wahren };
1252b1d84a3dSStefan Wahren 
125390bfaf02SStefan Wahren struct bcm_plat_data {
125490bfaf02SStefan Wahren 	const struct gpio_chip *gpio_chip;
125590bfaf02SStefan Wahren 	const struct pinctrl_desc *pctl_desc;
125690bfaf02SStefan Wahren 	const struct pinctrl_gpio_range *gpio_range;
125790bfaf02SStefan Wahren };
125890bfaf02SStefan Wahren 
125990bfaf02SStefan Wahren static const struct bcm_plat_data bcm2835_plat_data = {
126090bfaf02SStefan Wahren 	.gpio_chip = &bcm2835_gpio_chip,
126190bfaf02SStefan Wahren 	.pctl_desc = &bcm2835_pinctrl_desc,
126290bfaf02SStefan Wahren 	.gpio_range = &bcm2835_pinctrl_gpio_range,
126390bfaf02SStefan Wahren };
126490bfaf02SStefan Wahren 
126590bfaf02SStefan Wahren static const struct bcm_plat_data bcm2711_plat_data = {
1266b1d84a3dSStefan Wahren 	.gpio_chip = &bcm2711_gpio_chip,
126790bfaf02SStefan Wahren 	.pctl_desc = &bcm2711_pinctrl_desc,
1268b1d84a3dSStefan Wahren 	.gpio_range = &bcm2711_pinctrl_gpio_range,
126990bfaf02SStefan Wahren };
127090bfaf02SStefan Wahren 
1271e38a9a43SStefan Wahren static const struct of_device_id bcm2835_pinctrl_match[] = {
1272e38a9a43SStefan Wahren 	{
1273e38a9a43SStefan Wahren 		.compatible = "brcm,bcm2835-gpio",
127490bfaf02SStefan Wahren 		.data = &bcm2835_plat_data,
1275e38a9a43SStefan Wahren 	},
1276e38a9a43SStefan Wahren 	{
1277e38a9a43SStefan Wahren 		.compatible = "brcm,bcm2711-gpio",
127890bfaf02SStefan Wahren 		.data = &bcm2711_plat_data,
1279e38a9a43SStefan Wahren 	},
1280562c856fSFlorian Fainelli 	{
1281562c856fSFlorian Fainelli 		.compatible = "brcm,bcm7211-gpio",
1282562c856fSFlorian Fainelli 		.data = &bcm2711_plat_data,
1283562c856fSFlorian Fainelli 	},
1284e38a9a43SStefan Wahren 	{}
1285e38a9a43SStefan Wahren };
12860f978da6SLiao Chen MODULE_DEVICE_TABLE(of, bcm2835_pinctrl_match);
1287e38a9a43SStefan Wahren 
bcm2835_pinctrl_probe(struct platform_device * pdev)1288150632b0SGreg Kroah-Hartman static int bcm2835_pinctrl_probe(struct platform_device *pdev)
1289e1b2dc70SSimon Arlott {
1290e1b2dc70SSimon Arlott 	struct device *dev = &pdev->dev;
1291e1b2dc70SSimon Arlott 	struct device_node *np = dev->of_node;
129290bfaf02SStefan Wahren 	const struct bcm_plat_data *pdata;
1293e1b2dc70SSimon Arlott 	struct bcm2835_pinctrl *pc;
129473345a18SLinus Walleij 	struct gpio_irq_chip *girq;
1295e1b2dc70SSimon Arlott 	struct resource iomem;
1296e1b2dc70SSimon Arlott 	int err, i;
1297e38a9a43SStefan Wahren 	const struct of_device_id *match;
1298920fecc1SFlorian Fainelli 	int is_7211 = 0;
1299e38a9a43SStefan Wahren 
1300b1d84a3dSStefan Wahren 	BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_pins) != BCM2711_NUM_GPIOS);
1301b1d84a3dSStefan Wahren 	BUILD_BUG_ON(ARRAY_SIZE(bcm2835_gpio_groups) != BCM2711_NUM_GPIOS);
1302e1b2dc70SSimon Arlott 
1303e1b2dc70SSimon Arlott 	pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL);
1304e1b2dc70SSimon Arlott 	if (!pc)
1305e1b2dc70SSimon Arlott 		return -ENOMEM;
1306e1b2dc70SSimon Arlott 
1307e1b2dc70SSimon Arlott 	platform_set_drvdata(pdev, pc);
1308e1b2dc70SSimon Arlott 	pc->dev = dev;
1309e1b2dc70SSimon Arlott 
1310e1b2dc70SSimon Arlott 	err = of_address_to_resource(np, 0, &iomem);
1311e1b2dc70SSimon Arlott 	if (err) {
1312e1b2dc70SSimon Arlott 		dev_err(dev, "could not get IO memory\n");
1313e1b2dc70SSimon Arlott 		return err;
1314e1b2dc70SSimon Arlott 	}
1315e1b2dc70SSimon Arlott 
13169e0c1fb2SThierry Reding 	pc->base = devm_ioremap_resource(dev, &iomem);
13179e0c1fb2SThierry Reding 	if (IS_ERR(pc->base))
13189e0c1fb2SThierry Reding 		return PTR_ERR(pc->base);
1319e1b2dc70SSimon Arlott 
132090bfaf02SStefan Wahren 	match = of_match_node(bcm2835_pinctrl_match, pdev->dev.of_node);
132190bfaf02SStefan Wahren 	if (!match)
132290bfaf02SStefan Wahren 		return -EINVAL;
132390bfaf02SStefan Wahren 
132490bfaf02SStefan Wahren 	pdata = match->data;
1325920fecc1SFlorian Fainelli 	is_7211 = of_device_is_compatible(np, "brcm,bcm7211-gpio");
132690bfaf02SStefan Wahren 
132790bfaf02SStefan Wahren 	pc->gpio_chip = *pdata->gpio_chip;
132858383c78SLinus Walleij 	pc->gpio_chip.parent = dev;
1329e1b2dc70SSimon Arlott 
1330b7badd75SHans Verkuil 	spin_lock_init(&pc->fsel_lock);
1331e1b2dc70SSimon Arlott 	for (i = 0; i < BCM2835_NUM_BANKS; i++) {
1332e1b2dc70SSimon Arlott 		unsigned long events;
1333e1b2dc70SSimon Arlott 		unsigned offset;
1334e1b2dc70SSimon Arlott 
1335e1b2dc70SSimon Arlott 		/* clear event detection flags */
1336e1b2dc70SSimon Arlott 		bcm2835_gpio_wr(pc, GPREN0 + i * 4, 0);
1337e1b2dc70SSimon Arlott 		bcm2835_gpio_wr(pc, GPFEN0 + i * 4, 0);
1338e1b2dc70SSimon Arlott 		bcm2835_gpio_wr(pc, GPHEN0 + i * 4, 0);
1339e1b2dc70SSimon Arlott 		bcm2835_gpio_wr(pc, GPLEN0 + i * 4, 0);
1340e1b2dc70SSimon Arlott 		bcm2835_gpio_wr(pc, GPAREN0 + i * 4, 0);
1341e1b2dc70SSimon Arlott 		bcm2835_gpio_wr(pc, GPAFEN0 + i * 4, 0);
1342e1b2dc70SSimon Arlott 
1343e1b2dc70SSimon Arlott 		/* clear all the events */
1344e1b2dc70SSimon Arlott 		events = bcm2835_gpio_rd(pc, GPEDS0 + i * 4);
1345e1b2dc70SSimon Arlott 		for_each_set_bit(offset, &events, 32)
1346e1b2dc70SSimon Arlott 			bcm2835_gpio_wr(pc, GPEDS0 + i * 4, BIT(offset));
1347e1b2dc70SSimon Arlott 
13483c7b30f7SLukas Wunner 		raw_spin_lock_init(&pc->irq_lock[i]);
134900445b5dSPhil Elwell 	}
135000445b5dSPhil Elwell 
1351266423e6SPhil Elwell 	pc->pctl_desc = *pdata->pctl_desc;
1352266423e6SPhil Elwell 	pc->pctl_dev = devm_pinctrl_register(dev, &pc->pctl_desc, pc);
1353266423e6SPhil Elwell 	if (IS_ERR(pc->pctl_dev)) {
1354266423e6SPhil Elwell 		gpiochip_remove(&pc->gpio_chip);
1355266423e6SPhil Elwell 		return PTR_ERR(pc->pctl_dev);
1356266423e6SPhil Elwell 	}
1357266423e6SPhil Elwell 
1358266423e6SPhil Elwell 	pc->gpio_range = *pdata->gpio_range;
1359266423e6SPhil Elwell 	pc->gpio_range.base = pc->gpio_chip.base;
1360266423e6SPhil Elwell 	pc->gpio_range.gc = &pc->gpio_chip;
1361266423e6SPhil Elwell 	pinctrl_add_gpio_range(pc->pctl_dev, &pc->gpio_range);
1362266423e6SPhil Elwell 
136373345a18SLinus Walleij 	girq = &pc->gpio_chip.irq;
136408752e07SStefan Wahren 	gpio_irq_chip_set_chip(girq, &bcm2835_gpio_irq_chip);
136573345a18SLinus Walleij 	girq->parent_handler = bcm2835_gpio_irq_handler;
136673345a18SLinus Walleij 	girq->num_parents = BCM2835_NUM_IRQS;
136773345a18SLinus Walleij 	girq->parents = devm_kcalloc(dev, BCM2835_NUM_IRQS,
136873345a18SLinus Walleij 				     sizeof(*girq->parents),
136973345a18SLinus Walleij 				     GFP_KERNEL);
1370266423e6SPhil Elwell 	if (!girq->parents) {
13715297c693SFlorian Fainelli 		err = -ENOMEM;
13725297c693SFlorian Fainelli 		goto out_remove;
1373266423e6SPhil Elwell 	}
1374920fecc1SFlorian Fainelli 
1375920fecc1SFlorian Fainelli 	if (is_7211) {
1376920fecc1SFlorian Fainelli 		pc->wake_irq = devm_kcalloc(dev, BCM2835_NUM_IRQS,
1377920fecc1SFlorian Fainelli 					    sizeof(*pc->wake_irq),
1378920fecc1SFlorian Fainelli 					    GFP_KERNEL);
13795297c693SFlorian Fainelli 		if (!pc->wake_irq) {
13805297c693SFlorian Fainelli 			err = -ENOMEM;
13815297c693SFlorian Fainelli 			goto out_remove;
13825297c693SFlorian Fainelli 		}
1383920fecc1SFlorian Fainelli 	}
1384920fecc1SFlorian Fainelli 
138585ae9e51SLinus Walleij 	/*
138685ae9e51SLinus Walleij 	 * Use the same handler for all groups: this is necessary
138785ae9e51SLinus Walleij 	 * since we use one gpiochip to cover all lines - the
138885ae9e51SLinus Walleij 	 * irq handler then needs to figure out which group and
138985ae9e51SLinus Walleij 	 * bank that was firing the IRQ and look up the per-group
139085ae9e51SLinus Walleij 	 * and bank data.
139185ae9e51SLinus Walleij 	 */
1392920fecc1SFlorian Fainelli 	for (i = 0; i < BCM2835_NUM_IRQS; i++) {
1393920fecc1SFlorian Fainelli 		int len;
1394920fecc1SFlorian Fainelli 		char *name;
1395920fecc1SFlorian Fainelli 
139673345a18SLinus Walleij 		girq->parents[i] = irq_of_parse_and_map(np, i);
13974bc80da5SPhil Elwell 		if (!is_7211) {
13984bc80da5SPhil Elwell 			if (!girq->parents[i]) {
13994bc80da5SPhil Elwell 				girq->num_parents = i;
14004bc80da5SPhil Elwell 				break;
14014bc80da5SPhil Elwell 			}
1402920fecc1SFlorian Fainelli 			continue;
14034bc80da5SPhil Elwell 		}
1404920fecc1SFlorian Fainelli 		/* Skip over the all banks interrupts */
1405920fecc1SFlorian Fainelli 		pc->wake_irq[i] = irq_of_parse_and_map(np, i +
1406920fecc1SFlorian Fainelli 						       BCM2835_NUM_IRQS + 1);
1407920fecc1SFlorian Fainelli 
1408920fecc1SFlorian Fainelli 		len = strlen(dev_name(pc->dev)) + 16;
1409920fecc1SFlorian Fainelli 		name = devm_kzalloc(pc->dev, len, GFP_KERNEL);
14105297c693SFlorian Fainelli 		if (!name) {
14115297c693SFlorian Fainelli 			err = -ENOMEM;
14125297c693SFlorian Fainelli 			goto out_remove;
14135297c693SFlorian Fainelli 		}
1414920fecc1SFlorian Fainelli 
1415920fecc1SFlorian Fainelli 		snprintf(name, len, "%s:bank%d", dev_name(pc->dev), i);
1416920fecc1SFlorian Fainelli 
1417920fecc1SFlorian Fainelli 		/* These are optional interrupts */
1418920fecc1SFlorian Fainelli 		err = devm_request_irq(dev, pc->wake_irq[i],
1419920fecc1SFlorian Fainelli 				       bcm2835_gpio_wake_irq_handler,
1420920fecc1SFlorian Fainelli 				       IRQF_SHARED, name, pc);
1421920fecc1SFlorian Fainelli 		if (err)
1422920fecc1SFlorian Fainelli 			dev_warn(dev, "unable to request wake IRQ %d\n",
1423920fecc1SFlorian Fainelli 				 pc->wake_irq[i]);
1424920fecc1SFlorian Fainelli 	}
1425920fecc1SFlorian Fainelli 
142673345a18SLinus Walleij 	girq->default_type = IRQ_TYPE_NONE;
142773345a18SLinus Walleij 	girq->handler = handle_level_irq;
142873345a18SLinus Walleij 
142973345a18SLinus Walleij 	err = gpiochip_add_data(&pc->gpio_chip, pc);
143073345a18SLinus Walleij 	if (err) {
143173345a18SLinus Walleij 		dev_err(dev, "could not add GPIO chip\n");
14325297c693SFlorian Fainelli 		goto out_remove;
143385ae9e51SLinus Walleij 	}
143485ae9e51SLinus Walleij 
14358ff05989SStefan Wahren 	dev_info(dev, "GPIO_OUT persistence: %s\n",
14361583dc16SStefan Wahren 		 str_yes_no(persist_gpio_outputs));
14378ff05989SStefan Wahren 
1438e1b2dc70SSimon Arlott 	return 0;
14395297c693SFlorian Fainelli 
14405297c693SFlorian Fainelli out_remove:
14415297c693SFlorian Fainelli 	pinctrl_remove_gpio_range(pc->pctl_dev, &pc->gpio_range);
14425297c693SFlorian Fainelli 	return err;
1443e1b2dc70SSimon Arlott }
1444e1b2dc70SSimon Arlott 
1445e1b2dc70SSimon Arlott static struct platform_driver bcm2835_pinctrl_driver = {
1446e1b2dc70SSimon Arlott 	.probe = bcm2835_pinctrl_probe,
1447e1b2dc70SSimon Arlott 	.driver = {
1448e1b2dc70SSimon Arlott 		.name = MODULE_NAME,
1449e1b2dc70SSimon Arlott 		.of_match_table = bcm2835_pinctrl_match,
145034f46848SPaul Gortmaker 		.suppress_bind_attrs = true,
1451e1b2dc70SSimon Arlott 	},
1452e1b2dc70SSimon Arlott };
14534434f4c5SFlorian Fainelli module_platform_driver(bcm2835_pinctrl_driver);
14544434f4c5SFlorian Fainelli 
14554434f4c5SFlorian Fainelli MODULE_AUTHOR("Chris Boot");
14564434f4c5SFlorian Fainelli MODULE_AUTHOR("Simon Arlott");
14574434f4c5SFlorian Fainelli MODULE_AUTHOR("Stephen Warren");
14584434f4c5SFlorian Fainelli MODULE_DESCRIPTION("Broadcom BCM2835/2711 pinctrl and GPIO driver");
14594434f4c5SFlorian Fainelli MODULE_LICENSE("GPL");
1460