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