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