Commit | Line | Data |
---|---|---|
f876dbff | 1 | // SPDX-License-Identifier: GPL-2.0-only |
b64333ce | 2 | /* |
18f75c0a | 3 | * Copyright (C) 2014-2017 Broadcom |
18f75c0a SB |
4 | */ |
5 | ||
6 | /* | |
afc8c78d PK |
7 | * This file contains the Broadcom Iproc GPIO driver that supports 3 |
8 | * GPIO controllers on Iproc including the ASIU GPIO controller, the | |
b64333ce RJ |
9 | * chipCommonG GPIO controller, and the always-on GPIO controller. Basic |
10 | * PINCONF such as bias pull up/down, and drive strength are also supported | |
11 | * in this driver. | |
12 | * | |
afc8c78d PK |
13 | * It provides the functionality where pins from the GPIO can be |
14 | * individually muxed to GPIO function, if individual pad | |
15 | * configuration is supported, through the interaction with respective | |
16 | * SoCs IOMUX controller. | |
b64333ce RJ |
17 | */ |
18 | ||
19 | #include <linux/kernel.h> | |
20 | #include <linux/slab.h> | |
21 | #include <linux/interrupt.h> | |
22 | #include <linux/io.h> | |
69fd6aea | 23 | #include <linux/gpio/driver.h> |
b64333ce RJ |
24 | #include <linux/ioport.h> |
25 | #include <linux/of_device.h> | |
26 | #include <linux/of_irq.h> | |
27 | #include <linux/pinctrl/pinctrl.h> | |
b64333ce RJ |
28 | #include <linux/pinctrl/pinconf.h> |
29 | #include <linux/pinctrl/pinconf-generic.h> | |
30 | ||
31 | #include "../pinctrl-utils.h" | |
32 | ||
afc8c78d PK |
33 | #define IPROC_GPIO_DATA_IN_OFFSET 0x00 |
34 | #define IPROC_GPIO_DATA_OUT_OFFSET 0x04 | |
35 | #define IPROC_GPIO_OUT_EN_OFFSET 0x08 | |
36 | #define IPROC_GPIO_INT_TYPE_OFFSET 0x0c | |
37 | #define IPROC_GPIO_INT_DE_OFFSET 0x10 | |
38 | #define IPROC_GPIO_INT_EDGE_OFFSET 0x14 | |
39 | #define IPROC_GPIO_INT_MSK_OFFSET 0x18 | |
40 | #define IPROC_GPIO_INT_STAT_OFFSET 0x1c | |
41 | #define IPROC_GPIO_INT_MSTAT_OFFSET 0x20 | |
42 | #define IPROC_GPIO_INT_CLR_OFFSET 0x24 | |
43 | #define IPROC_GPIO_PAD_RES_OFFSET 0x34 | |
44 | #define IPROC_GPIO_RES_EN_OFFSET 0x38 | |
b64333ce RJ |
45 | |
46 | /* drive strength control for ASIU GPIO */ | |
afc8c78d | 47 | #define IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET 0x58 |
b64333ce | 48 | |
398a1f50 LJ |
49 | /* pinconf for CCM GPIO */ |
50 | #define IPROC_GPIO_PULL_DN_OFFSET 0x10 | |
51 | #define IPROC_GPIO_PULL_UP_OFFSET 0x14 | |
52 | ||
53 | /* pinconf for CRMU(aon) GPIO and CCM GPIO*/ | |
54 | #define IPROC_GPIO_DRV_CTRL_OFFSET 0x00 | |
b64333ce RJ |
55 | |
56 | #define GPIO_BANK_SIZE 0x200 | |
57 | #define NGPIOS_PER_BANK 32 | |
58 | #define GPIO_BANK(pin) ((pin) / NGPIOS_PER_BANK) | |
59 | ||
afc8c78d PK |
60 | #define IPROC_GPIO_REG(pin, reg) (GPIO_BANK(pin) * GPIO_BANK_SIZE + (reg)) |
61 | #define IPROC_GPIO_SHIFT(pin) ((pin) % NGPIOS_PER_BANK) | |
b64333ce RJ |
62 | |
63 | #define GPIO_DRV_STRENGTH_BIT_SHIFT 20 | |
64 | #define GPIO_DRV_STRENGTH_BITS 3 | |
65 | #define GPIO_DRV_STRENGTH_BIT_MASK ((1 << GPIO_DRV_STRENGTH_BITS) - 1) | |
66 | ||
f58de3d9 RJ |
67 | enum iproc_pinconf_param { |
68 | IPROC_PINCONF_DRIVE_STRENGTH = 0, | |
69 | IPROC_PINCONF_BIAS_DISABLE, | |
70 | IPROC_PINCONF_BIAS_PULL_UP, | |
71 | IPROC_PINCONF_BIAS_PULL_DOWN, | |
72 | IPROC_PINCON_MAX, | |
73 | }; | |
74 | ||
398a1f50 LJ |
75 | enum iproc_pinconf_ctrl_type { |
76 | IOCTRL_TYPE_AON = 1, | |
77 | IOCTRL_TYPE_CDRU, | |
78 | IOCTRL_TYPE_INVALID, | |
79 | }; | |
80 | ||
b64333ce | 81 | /* |
afc8c78d | 82 | * Iproc GPIO core |
b64333ce RJ |
83 | * |
84 | * @dev: pointer to device | |
afc8c78d PK |
85 | * @base: I/O register base for Iproc GPIO controller |
86 | * @io_ctrl: I/O register base for certain type of Iproc GPIO controller that | |
b64333ce RJ |
87 | * has the PINCONF support implemented outside of the GPIO block |
88 | * @lock: lock to protect access to I/O registers | |
89 | * @gc: GPIO chip | |
90 | * @num_banks: number of GPIO banks, each bank supports up to 32 GPIOs | |
91 | * @pinmux_is_supported: flag to indicate this GPIO controller contains pins | |
92 | * that can be individually muxed to GPIO | |
f58de3d9 RJ |
93 | * @pinconf_disable: contains a list of PINCONF parameters that need to be |
94 | * disabled | |
95 | * @nr_pinconf_disable: total number of PINCONF parameters that need to be | |
96 | * disabled | |
b64333ce RJ |
97 | * @pctl: pointer to pinctrl_dev |
98 | * @pctldesc: pinctrl descriptor | |
99 | */ | |
afc8c78d | 100 | struct iproc_gpio { |
b64333ce RJ |
101 | struct device *dev; |
102 | ||
103 | void __iomem *base; | |
104 | void __iomem *io_ctrl; | |
398a1f50 | 105 | enum iproc_pinconf_ctrl_type io_ctrl_type; |
b64333ce | 106 | |
cb96a662 | 107 | raw_spinlock_t lock; |
b64333ce | 108 | |
547f073f | 109 | struct irq_chip irqchip; |
b64333ce RJ |
110 | struct gpio_chip gc; |
111 | unsigned num_banks; | |
112 | ||
113 | bool pinmux_is_supported; | |
114 | ||
f58de3d9 RJ |
115 | enum pin_config_param *pinconf_disable; |
116 | unsigned int nr_pinconf_disable; | |
117 | ||
b64333ce RJ |
118 | struct pinctrl_dev *pctl; |
119 | struct pinctrl_desc pctldesc; | |
120 | }; | |
121 | ||
b64333ce RJ |
122 | /* |
123 | * Mapping from PINCONF pins to GPIO pins is 1-to-1 | |
124 | */ | |
afc8c78d | 125 | static inline unsigned iproc_pin_to_gpio(unsigned pin) |
b64333ce RJ |
126 | { |
127 | return pin; | |
128 | } | |
129 | ||
130 | /** | |
afc8c78d PK |
131 | * iproc_set_bit - set or clear one bit (corresponding to the GPIO pin) in a |
132 | * Iproc GPIO register | |
b64333ce | 133 | * |
2dd2dbc5 | 134 | * @chip: Iproc GPIO device |
b64333ce RJ |
135 | * @reg: register offset |
136 | * @gpio: GPIO pin | |
137 | * @set: set or clear | |
138 | */ | |
afc8c78d | 139 | static inline void iproc_set_bit(struct iproc_gpio *chip, unsigned int reg, |
b64333ce RJ |
140 | unsigned gpio, bool set) |
141 | { | |
afc8c78d PK |
142 | unsigned int offset = IPROC_GPIO_REG(gpio, reg); |
143 | unsigned int shift = IPROC_GPIO_SHIFT(gpio); | |
b64333ce RJ |
144 | u32 val; |
145 | ||
146 | val = readl(chip->base + offset); | |
147 | if (set) | |
148 | val |= BIT(shift); | |
149 | else | |
150 | val &= ~BIT(shift); | |
151 | writel(val, chip->base + offset); | |
152 | } | |
153 | ||
afc8c78d | 154 | static inline bool iproc_get_bit(struct iproc_gpio *chip, unsigned int reg, |
b64333ce RJ |
155 | unsigned gpio) |
156 | { | |
afc8c78d PK |
157 | unsigned int offset = IPROC_GPIO_REG(gpio, reg); |
158 | unsigned int shift = IPROC_GPIO_SHIFT(gpio); | |
b64333ce RJ |
159 | |
160 | return !!(readl(chip->base + offset) & BIT(shift)); | |
161 | } | |
162 | ||
afc8c78d | 163 | static void iproc_gpio_irq_handler(struct irq_desc *desc) |
b64333ce RJ |
164 | { |
165 | struct gpio_chip *gc = irq_desc_get_handler_data(desc); | |
69fd6aea | 166 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
b64333ce RJ |
167 | struct irq_chip *irq_chip = irq_desc_get_chip(desc); |
168 | int i, bit; | |
169 | ||
170 | chained_irq_enter(irq_chip, desc); | |
171 | ||
172 | /* go through the entire GPIO banks and handle all interrupts */ | |
173 | for (i = 0; i < chip->num_banks; i++) { | |
174 | unsigned long val = readl(chip->base + (i * GPIO_BANK_SIZE) + | |
afc8c78d | 175 | IPROC_GPIO_INT_MSTAT_OFFSET); |
b64333ce RJ |
176 | |
177 | for_each_set_bit(bit, &val, NGPIOS_PER_BANK) { | |
178 | unsigned pin = NGPIOS_PER_BANK * i + bit; | |
b64333ce RJ |
179 | |
180 | /* | |
181 | * Clear the interrupt before invoking the | |
182 | * handler, so we do not leave any window | |
183 | */ | |
184 | writel(BIT(bit), chip->base + (i * GPIO_BANK_SIZE) + | |
afc8c78d | 185 | IPROC_GPIO_INT_CLR_OFFSET); |
b64333ce | 186 | |
a9cb09b7 | 187 | generic_handle_domain_irq(gc->irq.domain, pin); |
b64333ce RJ |
188 | } |
189 | } | |
190 | ||
191 | chained_irq_exit(irq_chip, desc); | |
192 | } | |
193 | ||
194 | ||
afc8c78d | 195 | static void iproc_gpio_irq_ack(struct irq_data *d) |
b64333ce RJ |
196 | { |
197 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | |
69fd6aea | 198 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
b64333ce | 199 | unsigned gpio = d->hwirq; |
afc8c78d PK |
200 | unsigned int offset = IPROC_GPIO_REG(gpio, |
201 | IPROC_GPIO_INT_CLR_OFFSET); | |
202 | unsigned int shift = IPROC_GPIO_SHIFT(gpio); | |
b64333ce RJ |
203 | u32 val = BIT(shift); |
204 | ||
205 | writel(val, chip->base + offset); | |
206 | } | |
207 | ||
208 | /** | |
afc8c78d | 209 | * iproc_gpio_irq_set_mask - mask/unmask a GPIO interrupt |
b64333ce RJ |
210 | * |
211 | * @d: IRQ chip data | |
212 | * @unmask: mask/unmask GPIO interrupt | |
213 | */ | |
afc8c78d | 214 | static void iproc_gpio_irq_set_mask(struct irq_data *d, bool unmask) |
b64333ce RJ |
215 | { |
216 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | |
69fd6aea | 217 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
b64333ce RJ |
218 | unsigned gpio = d->hwirq; |
219 | ||
afc8c78d | 220 | iproc_set_bit(chip, IPROC_GPIO_INT_MSK_OFFSET, gpio, unmask); |
b64333ce RJ |
221 | } |
222 | ||
afc8c78d | 223 | static void iproc_gpio_irq_mask(struct irq_data *d) |
b64333ce RJ |
224 | { |
225 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | |
69fd6aea | 226 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
b64333ce RJ |
227 | unsigned long flags; |
228 | ||
cb96a662 | 229 | raw_spin_lock_irqsave(&chip->lock, flags); |
afc8c78d | 230 | iproc_gpio_irq_set_mask(d, false); |
cb96a662 | 231 | raw_spin_unlock_irqrestore(&chip->lock, flags); |
b64333ce RJ |
232 | } |
233 | ||
afc8c78d | 234 | static void iproc_gpio_irq_unmask(struct irq_data *d) |
b64333ce RJ |
235 | { |
236 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | |
69fd6aea | 237 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
b64333ce RJ |
238 | unsigned long flags; |
239 | ||
cb96a662 | 240 | raw_spin_lock_irqsave(&chip->lock, flags); |
afc8c78d | 241 | iproc_gpio_irq_set_mask(d, true); |
cb96a662 | 242 | raw_spin_unlock_irqrestore(&chip->lock, flags); |
b64333ce RJ |
243 | } |
244 | ||
afc8c78d | 245 | static int iproc_gpio_irq_set_type(struct irq_data *d, unsigned int type) |
b64333ce RJ |
246 | { |
247 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | |
69fd6aea | 248 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
b64333ce RJ |
249 | unsigned gpio = d->hwirq; |
250 | bool level_triggered = false; | |
251 | bool dual_edge = false; | |
252 | bool rising_or_high = false; | |
253 | unsigned long flags; | |
254 | ||
255 | switch (type & IRQ_TYPE_SENSE_MASK) { | |
256 | case IRQ_TYPE_EDGE_RISING: | |
257 | rising_or_high = true; | |
258 | break; | |
259 | ||
260 | case IRQ_TYPE_EDGE_FALLING: | |
261 | break; | |
262 | ||
263 | case IRQ_TYPE_EDGE_BOTH: | |
264 | dual_edge = true; | |
265 | break; | |
266 | ||
267 | case IRQ_TYPE_LEVEL_HIGH: | |
268 | level_triggered = true; | |
269 | rising_or_high = true; | |
270 | break; | |
271 | ||
272 | case IRQ_TYPE_LEVEL_LOW: | |
273 | level_triggered = true; | |
274 | break; | |
275 | ||
276 | default: | |
277 | dev_err(chip->dev, "invalid GPIO IRQ type 0x%x\n", | |
278 | type); | |
279 | return -EINVAL; | |
280 | } | |
281 | ||
cb96a662 | 282 | raw_spin_lock_irqsave(&chip->lock, flags); |
afc8c78d | 283 | iproc_set_bit(chip, IPROC_GPIO_INT_TYPE_OFFSET, gpio, |
b64333ce | 284 | level_triggered); |
afc8c78d PK |
285 | iproc_set_bit(chip, IPROC_GPIO_INT_DE_OFFSET, gpio, dual_edge); |
286 | iproc_set_bit(chip, IPROC_GPIO_INT_EDGE_OFFSET, gpio, | |
b64333ce | 287 | rising_or_high); |
534ad357 HM |
288 | |
289 | if (type & IRQ_TYPE_EDGE_BOTH) | |
290 | irq_set_handler_locked(d, handle_edge_irq); | |
291 | else | |
292 | irq_set_handler_locked(d, handle_level_irq); | |
293 | ||
cb96a662 | 294 | raw_spin_unlock_irqrestore(&chip->lock, flags); |
b64333ce RJ |
295 | |
296 | dev_dbg(chip->dev, | |
297 | "gpio:%u level_triggered:%d dual_edge:%d rising_or_high:%d\n", | |
298 | gpio, level_triggered, dual_edge, rising_or_high); | |
299 | ||
300 | return 0; | |
301 | } | |
302 | ||
b64333ce | 303 | /* |
afc8c78d | 304 | * Request the Iproc IOMUX pinmux controller to mux individual pins to GPIO |
b64333ce | 305 | */ |
afc8c78d | 306 | static int iproc_gpio_request(struct gpio_chip *gc, unsigned offset) |
b64333ce | 307 | { |
69fd6aea | 308 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
b64333ce RJ |
309 | unsigned gpio = gc->base + offset; |
310 | ||
afc8c78d | 311 | /* not all Iproc GPIO pins can be muxed individually */ |
b64333ce RJ |
312 | if (!chip->pinmux_is_supported) |
313 | return 0; | |
314 | ||
a9a1d2a7 | 315 | return pinctrl_gpio_request(gpio); |
b64333ce RJ |
316 | } |
317 | ||
afc8c78d | 318 | static void iproc_gpio_free(struct gpio_chip *gc, unsigned offset) |
b64333ce | 319 | { |
69fd6aea | 320 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
b64333ce RJ |
321 | unsigned gpio = gc->base + offset; |
322 | ||
323 | if (!chip->pinmux_is_supported) | |
324 | return; | |
325 | ||
a9a1d2a7 | 326 | pinctrl_gpio_free(gpio); |
b64333ce RJ |
327 | } |
328 | ||
afc8c78d | 329 | static int iproc_gpio_direction_input(struct gpio_chip *gc, unsigned gpio) |
b64333ce | 330 | { |
69fd6aea | 331 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
b64333ce RJ |
332 | unsigned long flags; |
333 | ||
cb96a662 | 334 | raw_spin_lock_irqsave(&chip->lock, flags); |
afc8c78d | 335 | iproc_set_bit(chip, IPROC_GPIO_OUT_EN_OFFSET, gpio, false); |
cb96a662 | 336 | raw_spin_unlock_irqrestore(&chip->lock, flags); |
b64333ce RJ |
337 | |
338 | dev_dbg(chip->dev, "gpio:%u set input\n", gpio); | |
339 | ||
340 | return 0; | |
341 | } | |
342 | ||
afc8c78d | 343 | static int iproc_gpio_direction_output(struct gpio_chip *gc, unsigned gpio, |
b64333ce RJ |
344 | int val) |
345 | { | |
69fd6aea | 346 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
b64333ce RJ |
347 | unsigned long flags; |
348 | ||
cb96a662 | 349 | raw_spin_lock_irqsave(&chip->lock, flags); |
afc8c78d PK |
350 | iproc_set_bit(chip, IPROC_GPIO_OUT_EN_OFFSET, gpio, true); |
351 | iproc_set_bit(chip, IPROC_GPIO_DATA_OUT_OFFSET, gpio, !!(val)); | |
cb96a662 | 352 | raw_spin_unlock_irqrestore(&chip->lock, flags); |
b64333ce RJ |
353 | |
354 | dev_dbg(chip->dev, "gpio:%u set output, value:%d\n", gpio, val); | |
355 | ||
356 | return 0; | |
357 | } | |
358 | ||
03518271 RK |
359 | static int iproc_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio) |
360 | { | |
361 | struct iproc_gpio *chip = gpiochip_get_data(gc); | |
362 | unsigned int offset = IPROC_GPIO_REG(gpio, IPROC_GPIO_OUT_EN_OFFSET); | |
363 | unsigned int shift = IPROC_GPIO_SHIFT(gpio); | |
364 | ||
3c827873 MV |
365 | if (readl(chip->base + offset) & BIT(shift)) |
366 | return GPIO_LINE_DIRECTION_OUT; | |
367 | ||
368 | return GPIO_LINE_DIRECTION_IN; | |
03518271 RK |
369 | } |
370 | ||
afc8c78d | 371 | static void iproc_gpio_set(struct gpio_chip *gc, unsigned gpio, int val) |
b64333ce | 372 | { |
69fd6aea | 373 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
b64333ce RJ |
374 | unsigned long flags; |
375 | ||
cb96a662 | 376 | raw_spin_lock_irqsave(&chip->lock, flags); |
afc8c78d | 377 | iproc_set_bit(chip, IPROC_GPIO_DATA_OUT_OFFSET, gpio, !!(val)); |
cb96a662 | 378 | raw_spin_unlock_irqrestore(&chip->lock, flags); |
b64333ce RJ |
379 | |
380 | dev_dbg(chip->dev, "gpio:%u set, value:%d\n", gpio, val); | |
381 | } | |
382 | ||
afc8c78d | 383 | static int iproc_gpio_get(struct gpio_chip *gc, unsigned gpio) |
b64333ce | 384 | { |
69fd6aea | 385 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
afc8c78d PK |
386 | unsigned int offset = IPROC_GPIO_REG(gpio, |
387 | IPROC_GPIO_DATA_IN_OFFSET); | |
388 | unsigned int shift = IPROC_GPIO_SHIFT(gpio); | |
b64333ce RJ |
389 | |
390 | return !!(readl(chip->base + offset) & BIT(shift)); | |
391 | } | |
392 | ||
f58de3d9 RJ |
393 | /* |
394 | * Mapping of the iProc PINCONF parameters to the generic pin configuration | |
395 | * parameters | |
396 | */ | |
397 | static const enum pin_config_param iproc_pinconf_disable_map[] = { | |
398 | [IPROC_PINCONF_DRIVE_STRENGTH] = PIN_CONFIG_DRIVE_STRENGTH, | |
399 | [IPROC_PINCONF_BIAS_DISABLE] = PIN_CONFIG_BIAS_DISABLE, | |
400 | [IPROC_PINCONF_BIAS_PULL_UP] = PIN_CONFIG_BIAS_PULL_UP, | |
401 | [IPROC_PINCONF_BIAS_PULL_DOWN] = PIN_CONFIG_BIAS_PULL_DOWN, | |
402 | }; | |
403 | ||
404 | static bool iproc_pinconf_param_is_disabled(struct iproc_gpio *chip, | |
405 | enum pin_config_param param) | |
406 | { | |
407 | unsigned int i; | |
408 | ||
409 | if (!chip->nr_pinconf_disable) | |
410 | return false; | |
411 | ||
412 | for (i = 0; i < chip->nr_pinconf_disable; i++) | |
413 | if (chip->pinconf_disable[i] == param) | |
414 | return true; | |
415 | ||
416 | return false; | |
417 | } | |
418 | ||
419 | static int iproc_pinconf_disable_map_create(struct iproc_gpio *chip, | |
420 | unsigned long disable_mask) | |
421 | { | |
422 | unsigned int map_size = ARRAY_SIZE(iproc_pinconf_disable_map); | |
423 | unsigned int bit, nbits = 0; | |
424 | ||
425 | /* figure out total number of PINCONF parameters to disable */ | |
426 | for_each_set_bit(bit, &disable_mask, map_size) | |
427 | nbits++; | |
428 | ||
429 | if (!nbits) | |
430 | return 0; | |
431 | ||
432 | /* | |
433 | * Allocate an array to store PINCONF parameters that need to be | |
434 | * disabled | |
435 | */ | |
436 | chip->pinconf_disable = devm_kcalloc(chip->dev, nbits, | |
437 | sizeof(*chip->pinconf_disable), | |
438 | GFP_KERNEL); | |
439 | if (!chip->pinconf_disable) | |
440 | return -ENOMEM; | |
441 | ||
442 | chip->nr_pinconf_disable = nbits; | |
443 | ||
444 | /* now store these parameters */ | |
445 | nbits = 0; | |
446 | for_each_set_bit(bit, &disable_mask, map_size) | |
447 | chip->pinconf_disable[nbits++] = iproc_pinconf_disable_map[bit]; | |
448 | ||
449 | return 0; | |
450 | } | |
451 | ||
afc8c78d | 452 | static int iproc_get_groups_count(struct pinctrl_dev *pctldev) |
b64333ce RJ |
453 | { |
454 | return 1; | |
455 | } | |
456 | ||
457 | /* | |
458 | * Only one group: "gpio_grp", since this local pinctrl device only performs | |
459 | * GPIO specific PINCONF configurations | |
460 | */ | |
afc8c78d | 461 | static const char *iproc_get_group_name(struct pinctrl_dev *pctldev, |
b64333ce RJ |
462 | unsigned selector) |
463 | { | |
464 | return "gpio_grp"; | |
465 | } | |
466 | ||
afc8c78d PK |
467 | static const struct pinctrl_ops iproc_pctrl_ops = { |
468 | .get_groups_count = iproc_get_groups_count, | |
469 | .get_group_name = iproc_get_group_name, | |
b64333ce | 470 | .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, |
d32f7fd3 | 471 | .dt_free_map = pinctrl_utils_free_map, |
b64333ce RJ |
472 | }; |
473 | ||
afc8c78d | 474 | static int iproc_gpio_set_pull(struct iproc_gpio *chip, unsigned gpio, |
b64333ce RJ |
475 | bool disable, bool pull_up) |
476 | { | |
398a1f50 | 477 | void __iomem *base; |
b64333ce | 478 | unsigned long flags; |
398a1f50 LJ |
479 | unsigned int shift; |
480 | u32 val_1, val_2; | |
b64333ce | 481 | |
cb96a662 | 482 | raw_spin_lock_irqsave(&chip->lock, flags); |
398a1f50 LJ |
483 | if (chip->io_ctrl_type == IOCTRL_TYPE_CDRU) { |
484 | base = chip->io_ctrl; | |
485 | shift = IPROC_GPIO_SHIFT(gpio); | |
486 | ||
487 | val_1 = readl(base + IPROC_GPIO_PULL_UP_OFFSET); | |
488 | val_2 = readl(base + IPROC_GPIO_PULL_DN_OFFSET); | |
489 | if (disable) { | |
490 | /* no pull-up or pull-down */ | |
491 | val_1 &= ~BIT(shift); | |
492 | val_2 &= ~BIT(shift); | |
493 | } else if (pull_up) { | |
494 | val_1 |= BIT(shift); | |
495 | val_2 &= ~BIT(shift); | |
496 | } else { | |
497 | val_1 &= ~BIT(shift); | |
498 | val_2 |= BIT(shift); | |
499 | } | |
500 | writel(val_1, base + IPROC_GPIO_PULL_UP_OFFSET); | |
501 | writel(val_2, base + IPROC_GPIO_PULL_DN_OFFSET); | |
b64333ce | 502 | } else { |
398a1f50 LJ |
503 | if (disable) { |
504 | iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio, | |
505 | false); | |
506 | } else { | |
507 | iproc_set_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio, | |
508 | pull_up); | |
509 | iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio, | |
510 | true); | |
511 | } | |
b64333ce RJ |
512 | } |
513 | ||
cb96a662 | 514 | raw_spin_unlock_irqrestore(&chip->lock, flags); |
b64333ce RJ |
515 | dev_dbg(chip->dev, "gpio:%u set pullup:%d\n", gpio, pull_up); |
516 | ||
517 | return 0; | |
518 | } | |
519 | ||
afc8c78d | 520 | static void iproc_gpio_get_pull(struct iproc_gpio *chip, unsigned gpio, |
b64333ce RJ |
521 | bool *disable, bool *pull_up) |
522 | { | |
398a1f50 | 523 | void __iomem *base; |
b64333ce | 524 | unsigned long flags; |
398a1f50 LJ |
525 | unsigned int shift; |
526 | u32 val_1, val_2; | |
b64333ce | 527 | |
cb96a662 | 528 | raw_spin_lock_irqsave(&chip->lock, flags); |
398a1f50 LJ |
529 | if (chip->io_ctrl_type == IOCTRL_TYPE_CDRU) { |
530 | base = chip->io_ctrl; | |
531 | shift = IPROC_GPIO_SHIFT(gpio); | |
532 | ||
533 | val_1 = readl(base + IPROC_GPIO_PULL_UP_OFFSET) & BIT(shift); | |
534 | val_2 = readl(base + IPROC_GPIO_PULL_DN_OFFSET) & BIT(shift); | |
535 | ||
536 | *pull_up = val_1 ? true : false; | |
537 | *disable = (val_1 | val_2) ? false : true; | |
538 | ||
539 | } else { | |
540 | *disable = !iproc_get_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio); | |
541 | *pull_up = iproc_get_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio); | |
542 | } | |
cb96a662 | 543 | raw_spin_unlock_irqrestore(&chip->lock, flags); |
b64333ce RJ |
544 | } |
545 | ||
398a1f50 LJ |
546 | #define DRV_STRENGTH_OFFSET(gpio, bit, type) ((type) == IOCTRL_TYPE_AON ? \ |
547 | ((2 - (bit)) * 4 + IPROC_GPIO_DRV_CTRL_OFFSET) : \ | |
548 | ((type) == IOCTRL_TYPE_CDRU) ? \ | |
549 | ((bit) * 4 + IPROC_GPIO_DRV_CTRL_OFFSET) : \ | |
550 | ((bit) * 4 + IPROC_GPIO_REG(gpio, IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET))) | |
551 | ||
afc8c78d | 552 | static int iproc_gpio_set_strength(struct iproc_gpio *chip, unsigned gpio, |
b64333ce RJ |
553 | unsigned strength) |
554 | { | |
555 | void __iomem *base; | |
556 | unsigned int i, offset, shift; | |
557 | u32 val; | |
558 | unsigned long flags; | |
559 | ||
560 | /* make sure drive strength is supported */ | |
561 | if (strength < 2 || strength > 16 || (strength % 2)) | |
562 | return -ENOTSUPP; | |
563 | ||
564 | if (chip->io_ctrl) { | |
565 | base = chip->io_ctrl; | |
b64333ce RJ |
566 | } else { |
567 | base = chip->base; | |
b64333ce RJ |
568 | } |
569 | ||
afc8c78d | 570 | shift = IPROC_GPIO_SHIFT(gpio); |
b64333ce RJ |
571 | |
572 | dev_dbg(chip->dev, "gpio:%u set drive strength:%d mA\n", gpio, | |
573 | strength); | |
574 | ||
cb96a662 | 575 | raw_spin_lock_irqsave(&chip->lock, flags); |
b64333ce RJ |
576 | strength = (strength / 2) - 1; |
577 | for (i = 0; i < GPIO_DRV_STRENGTH_BITS; i++) { | |
398a1f50 | 578 | offset = DRV_STRENGTH_OFFSET(gpio, i, chip->io_ctrl_type); |
b64333ce RJ |
579 | val = readl(base + offset); |
580 | val &= ~BIT(shift); | |
581 | val |= ((strength >> i) & 0x1) << shift; | |
582 | writel(val, base + offset); | |
b64333ce | 583 | } |
cb96a662 | 584 | raw_spin_unlock_irqrestore(&chip->lock, flags); |
b64333ce RJ |
585 | |
586 | return 0; | |
587 | } | |
588 | ||
afc8c78d | 589 | static int iproc_gpio_get_strength(struct iproc_gpio *chip, unsigned gpio, |
b64333ce RJ |
590 | u16 *strength) |
591 | { | |
592 | void __iomem *base; | |
593 | unsigned int i, offset, shift; | |
594 | u32 val; | |
595 | unsigned long flags; | |
596 | ||
597 | if (chip->io_ctrl) { | |
598 | base = chip->io_ctrl; | |
b64333ce RJ |
599 | } else { |
600 | base = chip->base; | |
b64333ce RJ |
601 | } |
602 | ||
afc8c78d | 603 | shift = IPROC_GPIO_SHIFT(gpio); |
b64333ce | 604 | |
cb96a662 | 605 | raw_spin_lock_irqsave(&chip->lock, flags); |
b64333ce RJ |
606 | *strength = 0; |
607 | for (i = 0; i < GPIO_DRV_STRENGTH_BITS; i++) { | |
398a1f50 | 608 | offset = DRV_STRENGTH_OFFSET(gpio, i, chip->io_ctrl_type); |
b64333ce RJ |
609 | val = readl(base + offset) & BIT(shift); |
610 | val >>= shift; | |
611 | *strength += (val << i); | |
b64333ce RJ |
612 | } |
613 | ||
614 | /* convert to mA */ | |
615 | *strength = (*strength + 1) * 2; | |
cb96a662 | 616 | raw_spin_unlock_irqrestore(&chip->lock, flags); |
b64333ce RJ |
617 | |
618 | return 0; | |
619 | } | |
620 | ||
afc8c78d | 621 | static int iproc_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin, |
b64333ce RJ |
622 | unsigned long *config) |
623 | { | |
afc8c78d | 624 | struct iproc_gpio *chip = pinctrl_dev_get_drvdata(pctldev); |
b64333ce | 625 | enum pin_config_param param = pinconf_to_config_param(*config); |
afc8c78d | 626 | unsigned gpio = iproc_pin_to_gpio(pin); |
b64333ce RJ |
627 | u16 arg; |
628 | bool disable, pull_up; | |
629 | int ret; | |
630 | ||
f58de3d9 RJ |
631 | if (iproc_pinconf_param_is_disabled(chip, param)) |
632 | return -ENOTSUPP; | |
633 | ||
b64333ce RJ |
634 | switch (param) { |
635 | case PIN_CONFIG_BIAS_DISABLE: | |
afc8c78d | 636 | iproc_gpio_get_pull(chip, gpio, &disable, &pull_up); |
b64333ce RJ |
637 | if (disable) |
638 | return 0; | |
639 | else | |
640 | return -EINVAL; | |
641 | ||
642 | case PIN_CONFIG_BIAS_PULL_UP: | |
afc8c78d | 643 | iproc_gpio_get_pull(chip, gpio, &disable, &pull_up); |
b64333ce RJ |
644 | if (!disable && pull_up) |
645 | return 0; | |
646 | else | |
647 | return -EINVAL; | |
648 | ||
649 | case PIN_CONFIG_BIAS_PULL_DOWN: | |
afc8c78d | 650 | iproc_gpio_get_pull(chip, gpio, &disable, &pull_up); |
b64333ce RJ |
651 | if (!disable && !pull_up) |
652 | return 0; | |
653 | else | |
654 | return -EINVAL; | |
655 | ||
656 | case PIN_CONFIG_DRIVE_STRENGTH: | |
afc8c78d | 657 | ret = iproc_gpio_get_strength(chip, gpio, &arg); |
b64333ce RJ |
658 | if (ret) |
659 | return ret; | |
616043d5 | 660 | *config = pinconf_to_config_packed(param, arg); |
b64333ce RJ |
661 | |
662 | return 0; | |
663 | ||
664 | default: | |
665 | return -ENOTSUPP; | |
666 | } | |
667 | ||
668 | return -ENOTSUPP; | |
669 | } | |
670 | ||
afc8c78d | 671 | static int iproc_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, |
b64333ce RJ |
672 | unsigned long *configs, unsigned num_configs) |
673 | { | |
afc8c78d | 674 | struct iproc_gpio *chip = pinctrl_dev_get_drvdata(pctldev); |
b64333ce | 675 | enum pin_config_param param; |
58957d2e | 676 | u32 arg; |
afc8c78d | 677 | unsigned i, gpio = iproc_pin_to_gpio(pin); |
b64333ce RJ |
678 | int ret = -ENOTSUPP; |
679 | ||
680 | for (i = 0; i < num_configs; i++) { | |
681 | param = pinconf_to_config_param(configs[i]); | |
f58de3d9 RJ |
682 | |
683 | if (iproc_pinconf_param_is_disabled(chip, param)) | |
684 | return -ENOTSUPP; | |
685 | ||
b64333ce RJ |
686 | arg = pinconf_to_config_argument(configs[i]); |
687 | ||
688 | switch (param) { | |
689 | case PIN_CONFIG_BIAS_DISABLE: | |
afc8c78d | 690 | ret = iproc_gpio_set_pull(chip, gpio, true, false); |
b64333ce RJ |
691 | if (ret < 0) |
692 | goto out; | |
693 | break; | |
694 | ||
695 | case PIN_CONFIG_BIAS_PULL_UP: | |
afc8c78d | 696 | ret = iproc_gpio_set_pull(chip, gpio, false, true); |
b64333ce RJ |
697 | if (ret < 0) |
698 | goto out; | |
699 | break; | |
700 | ||
701 | case PIN_CONFIG_BIAS_PULL_DOWN: | |
afc8c78d | 702 | ret = iproc_gpio_set_pull(chip, gpio, false, false); |
b64333ce RJ |
703 | if (ret < 0) |
704 | goto out; | |
705 | break; | |
706 | ||
707 | case PIN_CONFIG_DRIVE_STRENGTH: | |
afc8c78d | 708 | ret = iproc_gpio_set_strength(chip, gpio, arg); |
b64333ce RJ |
709 | if (ret < 0) |
710 | goto out; | |
711 | break; | |
712 | ||
713 | default: | |
714 | dev_err(chip->dev, "invalid configuration\n"); | |
715 | return -ENOTSUPP; | |
716 | } | |
717 | } /* for each config */ | |
718 | ||
719 | out: | |
720 | return ret; | |
721 | } | |
722 | ||
afc8c78d | 723 | static const struct pinconf_ops iproc_pconf_ops = { |
b64333ce | 724 | .is_generic = true, |
afc8c78d PK |
725 | .pin_config_get = iproc_pin_config_get, |
726 | .pin_config_set = iproc_pin_config_set, | |
b64333ce RJ |
727 | }; |
728 | ||
b64333ce | 729 | /* |
afc8c78d | 730 | * Iproc GPIO controller supports some PINCONF related configurations such as |
b64333ce RJ |
731 | * pull up, pull down, and drive strength, when the pin is configured to GPIO |
732 | * | |
733 | * Here a local pinctrl device is created with simple 1-to-1 pin mapping to the | |
734 | * local GPIO pins | |
735 | */ | |
afc8c78d | 736 | static int iproc_gpio_register_pinconf(struct iproc_gpio *chip) |
b64333ce RJ |
737 | { |
738 | struct pinctrl_desc *pctldesc = &chip->pctldesc; | |
739 | struct pinctrl_pin_desc *pins; | |
740 | struct gpio_chip *gc = &chip->gc; | |
741 | int i; | |
742 | ||
743 | pins = devm_kcalloc(chip->dev, gc->ngpio, sizeof(*pins), GFP_KERNEL); | |
744 | if (!pins) | |
745 | return -ENOMEM; | |
746 | ||
747 | for (i = 0; i < gc->ngpio; i++) { | |
748 | pins[i].number = i; | |
749 | pins[i].name = devm_kasprintf(chip->dev, GFP_KERNEL, | |
750 | "gpio-%d", i); | |
751 | if (!pins[i].name) | |
752 | return -ENOMEM; | |
753 | } | |
754 | ||
755 | pctldesc->name = dev_name(chip->dev); | |
afc8c78d | 756 | pctldesc->pctlops = &iproc_pctrl_ops; |
b64333ce RJ |
757 | pctldesc->pins = pins; |
758 | pctldesc->npins = gc->ngpio; | |
afc8c78d | 759 | pctldesc->confops = &iproc_pconf_ops; |
b64333ce | 760 | |
ee17e041 | 761 | chip->pctl = devm_pinctrl_register(chip->dev, pctldesc, chip); |
323de9ef | 762 | if (IS_ERR(chip->pctl)) { |
b64333ce | 763 | dev_err(chip->dev, "unable to register pinctrl device\n"); |
323de9ef | 764 | return PTR_ERR(chip->pctl); |
b64333ce RJ |
765 | } |
766 | ||
767 | return 0; | |
768 | } | |
769 | ||
afc8c78d | 770 | static const struct of_device_id iproc_gpio_of_match[] = { |
f58de3d9 | 771 | { .compatible = "brcm,iproc-gpio" }, |
e1aaaf3f PK |
772 | { .compatible = "brcm,cygnus-ccm-gpio" }, |
773 | { .compatible = "brcm,cygnus-asiu-gpio" }, | |
774 | { .compatible = "brcm,cygnus-crmu-gpio" }, | |
f58de3d9 RJ |
775 | { .compatible = "brcm,iproc-nsp-gpio" }, |
776 | { .compatible = "brcm,iproc-stingray-gpio" }, | |
777 | { /* sentinel */ } | |
b64333ce RJ |
778 | }; |
779 | ||
afc8c78d | 780 | static int iproc_gpio_probe(struct platform_device *pdev) |
b64333ce RJ |
781 | { |
782 | struct device *dev = &pdev->dev; | |
783 | struct resource *res; | |
afc8c78d | 784 | struct iproc_gpio *chip; |
b64333ce | 785 | struct gpio_chip *gc; |
f58de3d9 | 786 | u32 ngpios, pinconf_disable_mask = 0; |
b64333ce | 787 | int irq, ret; |
f58de3d9 | 788 | bool no_pinconf = false; |
398a1f50 | 789 | enum iproc_pinconf_ctrl_type io_ctrl_type = IOCTRL_TYPE_INVALID; |
f58de3d9 RJ |
790 | |
791 | /* NSP does not support drive strength config */ | |
792 | if (of_device_is_compatible(dev->of_node, "brcm,iproc-nsp-gpio")) | |
793 | pinconf_disable_mask = BIT(IPROC_PINCONF_DRIVE_STRENGTH); | |
794 | /* Stingray does not support pinconf in this controller */ | |
795 | else if (of_device_is_compatible(dev->of_node, | |
796 | "brcm,iproc-stingray-gpio")) | |
797 | no_pinconf = true; | |
b64333ce RJ |
798 | |
799 | chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); | |
800 | if (!chip) | |
801 | return -ENOMEM; | |
802 | ||
803 | chip->dev = dev; | |
804 | platform_set_drvdata(pdev, chip); | |
805 | ||
4b024225 | 806 | chip->base = devm_platform_ioremap_resource(pdev, 0); |
b64333ce RJ |
807 | if (IS_ERR(chip->base)) { |
808 | dev_err(dev, "unable to map I/O memory\n"); | |
809 | return PTR_ERR(chip->base); | |
810 | } | |
811 | ||
812 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | |
813 | if (res) { | |
814 | chip->io_ctrl = devm_ioremap_resource(dev, res); | |
ef9385fb | 815 | if (IS_ERR(chip->io_ctrl)) |
b64333ce | 816 | return PTR_ERR(chip->io_ctrl); |
398a1f50 LJ |
817 | if (of_device_is_compatible(dev->of_node, |
818 | "brcm,cygnus-ccm-gpio")) | |
819 | io_ctrl_type = IOCTRL_TYPE_CDRU; | |
820 | else | |
821 | io_ctrl_type = IOCTRL_TYPE_AON; | |
b64333ce RJ |
822 | } |
823 | ||
398a1f50 LJ |
824 | chip->io_ctrl_type = io_ctrl_type; |
825 | ||
e1aaaf3f PK |
826 | if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) { |
827 | dev_err(&pdev->dev, "missing ngpios DT property\n"); | |
828 | return -ENODEV; | |
829 | } | |
830 | ||
cb96a662 | 831 | raw_spin_lock_init(&chip->lock); |
b64333ce RJ |
832 | |
833 | gc = &chip->gc; | |
834 | gc->base = -1; | |
835 | gc->ngpio = ngpios; | |
836 | chip->num_banks = (ngpios + NGPIOS_PER_BANK - 1) / NGPIOS_PER_BANK; | |
837 | gc->label = dev_name(dev); | |
58383c78 | 838 | gc->parent = dev; |
afc8c78d PK |
839 | gc->request = iproc_gpio_request; |
840 | gc->free = iproc_gpio_free; | |
841 | gc->direction_input = iproc_gpio_direction_input; | |
842 | gc->direction_output = iproc_gpio_direction_output; | |
03518271 | 843 | gc->get_direction = iproc_gpio_get_direction; |
afc8c78d PK |
844 | gc->set = iproc_gpio_set; |
845 | gc->get = iproc_gpio_get; | |
b64333ce | 846 | |
ea92211c PK |
847 | chip->pinmux_is_supported = of_property_read_bool(dev->of_node, |
848 | "gpio-ranges"); | |
849 | ||
6f265e5d | 850 | /* optional GPIO interrupt support */ |
783e9986 | 851 | irq = platform_get_irq_optional(pdev, 0); |
48659227 | 852 | if (irq > 0) { |
547f073f | 853 | struct irq_chip *irqc; |
6f265e5d LW |
854 | struct gpio_irq_chip *girq; |
855 | ||
547f073f | 856 | irqc = &chip->irqchip; |
74033d99 | 857 | irqc->name = dev_name(dev); |
547f073f RK |
858 | irqc->irq_ack = iproc_gpio_irq_ack; |
859 | irqc->irq_mask = iproc_gpio_irq_mask; | |
860 | irqc->irq_unmask = iproc_gpio_irq_unmask; | |
861 | irqc->irq_set_type = iproc_gpio_irq_set_type; | |
862 | irqc->irq_enable = iproc_gpio_irq_unmask; | |
863 | irqc->irq_disable = iproc_gpio_irq_mask; | |
864 | ||
6f265e5d | 865 | girq = &gc->irq; |
547f073f | 866 | girq->chip = irqc; |
6f265e5d LW |
867 | girq->parent_handler = iproc_gpio_irq_handler; |
868 | girq->num_parents = 1; | |
869 | girq->parents = devm_kcalloc(dev, 1, | |
870 | sizeof(*girq->parents), | |
871 | GFP_KERNEL); | |
872 | if (!girq->parents) | |
873 | return -ENOMEM; | |
874 | girq->parents[0] = irq; | |
875 | girq->default_type = IRQ_TYPE_NONE; | |
534ad357 | 876 | girq->handler = handle_bad_irq; |
6f265e5d LW |
877 | } |
878 | ||
69fd6aea | 879 | ret = gpiochip_add_data(gc, chip); |
b64333ce RJ |
880 | if (ret < 0) { |
881 | dev_err(dev, "unable to add GPIO chip\n"); | |
882 | return ret; | |
883 | } | |
884 | ||
f58de3d9 RJ |
885 | if (!no_pinconf) { |
886 | ret = iproc_gpio_register_pinconf(chip); | |
887 | if (ret) { | |
888 | dev_err(dev, "unable to register pinconf\n"); | |
889 | goto err_rm_gpiochip; | |
890 | } | |
891 | ||
892 | if (pinconf_disable_mask) { | |
893 | ret = iproc_pinconf_disable_map_create(chip, | |
894 | pinconf_disable_mask); | |
895 | if (ret) { | |
896 | dev_err(dev, | |
897 | "unable to create pinconf disable map\n"); | |
898 | goto err_rm_gpiochip; | |
899 | } | |
900 | } | |
b64333ce RJ |
901 | } |
902 | ||
b64333ce RJ |
903 | return 0; |
904 | ||
b64333ce RJ |
905 | err_rm_gpiochip: |
906 | gpiochip_remove(gc); | |
907 | ||
908 | return ret; | |
909 | } | |
910 | ||
afc8c78d | 911 | static struct platform_driver iproc_gpio_driver = { |
b64333ce | 912 | .driver = { |
afc8c78d PK |
913 | .name = "iproc-gpio", |
914 | .of_match_table = iproc_gpio_of_match, | |
b64333ce | 915 | }, |
afc8c78d | 916 | .probe = iproc_gpio_probe, |
b64333ce RJ |
917 | }; |
918 | ||
afc8c78d | 919 | static int __init iproc_gpio_init(void) |
b64333ce | 920 | { |
091c531b | 921 | return platform_driver_register(&iproc_gpio_driver); |
b64333ce | 922 | } |
afc8c78d | 923 | arch_initcall_sync(iproc_gpio_init); |