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