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