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 | ||
69 | /* | |
afc8c78d | 70 | * Iproc GPIO core |
b64333ce RJ |
71 | * |
72 | * @dev: pointer to device | |
afc8c78d PK |
73 | * @base: I/O register base for Iproc GPIO controller |
74 | * @io_ctrl: I/O register base for certain type of Iproc GPIO controller that | |
b64333ce RJ |
75 | * has the PINCONF support implemented outside of the GPIO block |
76 | * @lock: lock to protect access to I/O registers | |
77 | * @gc: GPIO chip | |
78 | * @num_banks: number of GPIO banks, each bank supports up to 32 GPIOs | |
79 | * @pinmux_is_supported: flag to indicate this GPIO controller contains pins | |
80 | * that can be individually muxed to GPIO | |
81 | * @pctl: pointer to pinctrl_dev | |
82 | * @pctldesc: pinctrl descriptor | |
83 | */ | |
afc8c78d | 84 | struct iproc_gpio { |
b64333ce RJ |
85 | struct device *dev; |
86 | ||
87 | void __iomem *base; | |
88 | void __iomem *io_ctrl; | |
89 | ||
90 | spinlock_t lock; | |
91 | ||
92 | struct gpio_chip gc; | |
93 | unsigned num_banks; | |
94 | ||
95 | bool pinmux_is_supported; | |
96 | ||
97 | struct pinctrl_dev *pctl; | |
98 | struct pinctrl_desc pctldesc; | |
99 | }; | |
100 | ||
b64333ce RJ |
101 | /* |
102 | * Mapping from PINCONF pins to GPIO pins is 1-to-1 | |
103 | */ | |
afc8c78d | 104 | static inline unsigned iproc_pin_to_gpio(unsigned pin) |
b64333ce RJ |
105 | { |
106 | return pin; | |
107 | } | |
108 | ||
109 | /** | |
afc8c78d PK |
110 | * iproc_set_bit - set or clear one bit (corresponding to the GPIO pin) in a |
111 | * Iproc GPIO register | |
b64333ce | 112 | * |
afc8c78d | 113 | * @iproc_gpio: Iproc GPIO device |
b64333ce RJ |
114 | * @reg: register offset |
115 | * @gpio: GPIO pin | |
116 | * @set: set or clear | |
117 | */ | |
afc8c78d | 118 | static inline void iproc_set_bit(struct iproc_gpio *chip, unsigned int reg, |
b64333ce RJ |
119 | unsigned gpio, bool set) |
120 | { | |
afc8c78d PK |
121 | unsigned int offset = IPROC_GPIO_REG(gpio, reg); |
122 | unsigned int shift = IPROC_GPIO_SHIFT(gpio); | |
b64333ce RJ |
123 | u32 val; |
124 | ||
125 | val = readl(chip->base + offset); | |
126 | if (set) | |
127 | val |= BIT(shift); | |
128 | else | |
129 | val &= ~BIT(shift); | |
130 | writel(val, chip->base + offset); | |
131 | } | |
132 | ||
afc8c78d | 133 | static inline bool iproc_get_bit(struct iproc_gpio *chip, unsigned int reg, |
b64333ce RJ |
134 | unsigned gpio) |
135 | { | |
afc8c78d PK |
136 | unsigned int offset = IPROC_GPIO_REG(gpio, reg); |
137 | unsigned int shift = IPROC_GPIO_SHIFT(gpio); | |
b64333ce RJ |
138 | |
139 | return !!(readl(chip->base + offset) & BIT(shift)); | |
140 | } | |
141 | ||
afc8c78d | 142 | static void iproc_gpio_irq_handler(struct irq_desc *desc) |
b64333ce RJ |
143 | { |
144 | struct gpio_chip *gc = irq_desc_get_handler_data(desc); | |
69fd6aea | 145 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
b64333ce RJ |
146 | struct irq_chip *irq_chip = irq_desc_get_chip(desc); |
147 | int i, bit; | |
148 | ||
149 | chained_irq_enter(irq_chip, desc); | |
150 | ||
151 | /* go through the entire GPIO banks and handle all interrupts */ | |
152 | for (i = 0; i < chip->num_banks; i++) { | |
153 | unsigned long val = readl(chip->base + (i * GPIO_BANK_SIZE) + | |
afc8c78d | 154 | IPROC_GPIO_INT_MSTAT_OFFSET); |
b64333ce RJ |
155 | |
156 | for_each_set_bit(bit, &val, NGPIOS_PER_BANK) { | |
157 | unsigned pin = NGPIOS_PER_BANK * i + bit; | |
158 | int child_irq = irq_find_mapping(gc->irqdomain, pin); | |
159 | ||
160 | /* | |
161 | * Clear the interrupt before invoking the | |
162 | * handler, so we do not leave any window | |
163 | */ | |
164 | writel(BIT(bit), chip->base + (i * GPIO_BANK_SIZE) + | |
afc8c78d | 165 | IPROC_GPIO_INT_CLR_OFFSET); |
b64333ce RJ |
166 | |
167 | generic_handle_irq(child_irq); | |
168 | } | |
169 | } | |
170 | ||
171 | chained_irq_exit(irq_chip, desc); | |
172 | } | |
173 | ||
174 | ||
afc8c78d | 175 | static void iproc_gpio_irq_ack(struct irq_data *d) |
b64333ce RJ |
176 | { |
177 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | |
69fd6aea | 178 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
b64333ce | 179 | unsigned gpio = d->hwirq; |
afc8c78d PK |
180 | unsigned int offset = IPROC_GPIO_REG(gpio, |
181 | IPROC_GPIO_INT_CLR_OFFSET); | |
182 | unsigned int shift = IPROC_GPIO_SHIFT(gpio); | |
b64333ce RJ |
183 | u32 val = BIT(shift); |
184 | ||
185 | writel(val, chip->base + offset); | |
186 | } | |
187 | ||
188 | /** | |
afc8c78d | 189 | * iproc_gpio_irq_set_mask - mask/unmask a GPIO interrupt |
b64333ce RJ |
190 | * |
191 | * @d: IRQ chip data | |
192 | * @unmask: mask/unmask GPIO interrupt | |
193 | */ | |
afc8c78d | 194 | static void iproc_gpio_irq_set_mask(struct irq_data *d, bool unmask) |
b64333ce RJ |
195 | { |
196 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | |
69fd6aea | 197 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
b64333ce RJ |
198 | unsigned gpio = d->hwirq; |
199 | ||
afc8c78d | 200 | iproc_set_bit(chip, IPROC_GPIO_INT_MSK_OFFSET, gpio, unmask); |
b64333ce RJ |
201 | } |
202 | ||
afc8c78d | 203 | static void iproc_gpio_irq_mask(struct irq_data *d) |
b64333ce RJ |
204 | { |
205 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | |
69fd6aea | 206 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
b64333ce RJ |
207 | unsigned long flags; |
208 | ||
209 | spin_lock_irqsave(&chip->lock, flags); | |
afc8c78d | 210 | iproc_gpio_irq_set_mask(d, false); |
b64333ce RJ |
211 | spin_unlock_irqrestore(&chip->lock, flags); |
212 | } | |
213 | ||
afc8c78d | 214 | static void iproc_gpio_irq_unmask(struct irq_data *d) |
b64333ce RJ |
215 | { |
216 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | |
69fd6aea | 217 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
b64333ce RJ |
218 | unsigned long flags; |
219 | ||
220 | spin_lock_irqsave(&chip->lock, flags); | |
afc8c78d | 221 | iproc_gpio_irq_set_mask(d, true); |
b64333ce RJ |
222 | spin_unlock_irqrestore(&chip->lock, flags); |
223 | } | |
224 | ||
afc8c78d | 225 | static int iproc_gpio_irq_set_type(struct irq_data *d, unsigned int type) |
b64333ce RJ |
226 | { |
227 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | |
69fd6aea | 228 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
b64333ce RJ |
229 | unsigned gpio = d->hwirq; |
230 | bool level_triggered = false; | |
231 | bool dual_edge = false; | |
232 | bool rising_or_high = false; | |
233 | unsigned long flags; | |
234 | ||
235 | switch (type & IRQ_TYPE_SENSE_MASK) { | |
236 | case IRQ_TYPE_EDGE_RISING: | |
237 | rising_or_high = true; | |
238 | break; | |
239 | ||
240 | case IRQ_TYPE_EDGE_FALLING: | |
241 | break; | |
242 | ||
243 | case IRQ_TYPE_EDGE_BOTH: | |
244 | dual_edge = true; | |
245 | break; | |
246 | ||
247 | case IRQ_TYPE_LEVEL_HIGH: | |
248 | level_triggered = true; | |
249 | rising_or_high = true; | |
250 | break; | |
251 | ||
252 | case IRQ_TYPE_LEVEL_LOW: | |
253 | level_triggered = true; | |
254 | break; | |
255 | ||
256 | default: | |
257 | dev_err(chip->dev, "invalid GPIO IRQ type 0x%x\n", | |
258 | type); | |
259 | return -EINVAL; | |
260 | } | |
261 | ||
262 | spin_lock_irqsave(&chip->lock, flags); | |
afc8c78d | 263 | iproc_set_bit(chip, IPROC_GPIO_INT_TYPE_OFFSET, gpio, |
b64333ce | 264 | level_triggered); |
afc8c78d PK |
265 | iproc_set_bit(chip, IPROC_GPIO_INT_DE_OFFSET, gpio, dual_edge); |
266 | iproc_set_bit(chip, IPROC_GPIO_INT_EDGE_OFFSET, gpio, | |
b64333ce RJ |
267 | rising_or_high); |
268 | spin_unlock_irqrestore(&chip->lock, flags); | |
269 | ||
270 | dev_dbg(chip->dev, | |
271 | "gpio:%u level_triggered:%d dual_edge:%d rising_or_high:%d\n", | |
272 | gpio, level_triggered, dual_edge, rising_or_high); | |
273 | ||
274 | return 0; | |
275 | } | |
276 | ||
afc8c78d PK |
277 | static struct irq_chip iproc_gpio_irq_chip = { |
278 | .name = "bcm-iproc-gpio", | |
279 | .irq_ack = iproc_gpio_irq_ack, | |
280 | .irq_mask = iproc_gpio_irq_mask, | |
281 | .irq_unmask = iproc_gpio_irq_unmask, | |
282 | .irq_set_type = iproc_gpio_irq_set_type, | |
b64333ce RJ |
283 | }; |
284 | ||
285 | /* | |
afc8c78d | 286 | * Request the Iproc IOMUX pinmux controller to mux individual pins to GPIO |
b64333ce | 287 | */ |
afc8c78d | 288 | static int iproc_gpio_request(struct gpio_chip *gc, unsigned offset) |
b64333ce | 289 | { |
69fd6aea | 290 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
b64333ce RJ |
291 | unsigned gpio = gc->base + offset; |
292 | ||
afc8c78d | 293 | /* not all Iproc GPIO pins can be muxed individually */ |
b64333ce RJ |
294 | if (!chip->pinmux_is_supported) |
295 | return 0; | |
296 | ||
297 | return pinctrl_request_gpio(gpio); | |
298 | } | |
299 | ||
afc8c78d | 300 | static void iproc_gpio_free(struct gpio_chip *gc, unsigned offset) |
b64333ce | 301 | { |
69fd6aea | 302 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
b64333ce RJ |
303 | unsigned gpio = gc->base + offset; |
304 | ||
305 | if (!chip->pinmux_is_supported) | |
306 | return; | |
307 | ||
308 | pinctrl_free_gpio(gpio); | |
309 | } | |
310 | ||
afc8c78d | 311 | static int iproc_gpio_direction_input(struct gpio_chip *gc, unsigned gpio) |
b64333ce | 312 | { |
69fd6aea | 313 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
b64333ce RJ |
314 | unsigned long flags; |
315 | ||
316 | spin_lock_irqsave(&chip->lock, flags); | |
afc8c78d | 317 | iproc_set_bit(chip, IPROC_GPIO_OUT_EN_OFFSET, gpio, false); |
b64333ce RJ |
318 | spin_unlock_irqrestore(&chip->lock, flags); |
319 | ||
320 | dev_dbg(chip->dev, "gpio:%u set input\n", gpio); | |
321 | ||
322 | return 0; | |
323 | } | |
324 | ||
afc8c78d | 325 | static int iproc_gpio_direction_output(struct gpio_chip *gc, unsigned gpio, |
b64333ce RJ |
326 | int val) |
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 PK |
332 | iproc_set_bit(chip, IPROC_GPIO_OUT_EN_OFFSET, gpio, true); |
333 | iproc_set_bit(chip, IPROC_GPIO_DATA_OUT_OFFSET, gpio, !!(val)); | |
b64333ce RJ |
334 | spin_unlock_irqrestore(&chip->lock, flags); |
335 | ||
336 | dev_dbg(chip->dev, "gpio:%u set output, value:%d\n", gpio, val); | |
337 | ||
338 | return 0; | |
339 | } | |
340 | ||
afc8c78d | 341 | static void iproc_gpio_set(struct gpio_chip *gc, unsigned gpio, int val) |
b64333ce | 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 | 347 | iproc_set_bit(chip, IPROC_GPIO_DATA_OUT_OFFSET, gpio, !!(val)); |
b64333ce RJ |
348 | spin_unlock_irqrestore(&chip->lock, flags); |
349 | ||
350 | dev_dbg(chip->dev, "gpio:%u set, value:%d\n", gpio, val); | |
351 | } | |
352 | ||
afc8c78d | 353 | static int iproc_gpio_get(struct gpio_chip *gc, unsigned gpio) |
b64333ce | 354 | { |
69fd6aea | 355 | struct iproc_gpio *chip = gpiochip_get_data(gc); |
afc8c78d PK |
356 | unsigned int offset = IPROC_GPIO_REG(gpio, |
357 | IPROC_GPIO_DATA_IN_OFFSET); | |
358 | unsigned int shift = IPROC_GPIO_SHIFT(gpio); | |
b64333ce RJ |
359 | |
360 | return !!(readl(chip->base + offset) & BIT(shift)); | |
361 | } | |
362 | ||
afc8c78d | 363 | static int iproc_get_groups_count(struct pinctrl_dev *pctldev) |
b64333ce RJ |
364 | { |
365 | return 1; | |
366 | } | |
367 | ||
368 | /* | |
369 | * Only one group: "gpio_grp", since this local pinctrl device only performs | |
370 | * GPIO specific PINCONF configurations | |
371 | */ | |
afc8c78d | 372 | static const char *iproc_get_group_name(struct pinctrl_dev *pctldev, |
b64333ce RJ |
373 | unsigned selector) |
374 | { | |
375 | return "gpio_grp"; | |
376 | } | |
377 | ||
afc8c78d PK |
378 | static const struct pinctrl_ops iproc_pctrl_ops = { |
379 | .get_groups_count = iproc_get_groups_count, | |
380 | .get_group_name = iproc_get_group_name, | |
b64333ce | 381 | .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, |
d32f7fd3 | 382 | .dt_free_map = pinctrl_utils_free_map, |
b64333ce RJ |
383 | }; |
384 | ||
afc8c78d | 385 | static int iproc_gpio_set_pull(struct iproc_gpio *chip, unsigned gpio, |
b64333ce RJ |
386 | bool disable, bool pull_up) |
387 | { | |
388 | unsigned long flags; | |
389 | ||
390 | spin_lock_irqsave(&chip->lock, flags); | |
391 | ||
392 | if (disable) { | |
afc8c78d | 393 | iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio, false); |
b64333ce | 394 | } else { |
afc8c78d | 395 | iproc_set_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio, |
b64333ce | 396 | pull_up); |
afc8c78d | 397 | iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio, true); |
b64333ce RJ |
398 | } |
399 | ||
400 | spin_unlock_irqrestore(&chip->lock, flags); | |
401 | ||
402 | dev_dbg(chip->dev, "gpio:%u set pullup:%d\n", gpio, pull_up); | |
403 | ||
404 | return 0; | |
405 | } | |
406 | ||
afc8c78d | 407 | static void iproc_gpio_get_pull(struct iproc_gpio *chip, unsigned gpio, |
b64333ce RJ |
408 | bool *disable, bool *pull_up) |
409 | { | |
410 | unsigned long flags; | |
411 | ||
412 | spin_lock_irqsave(&chip->lock, flags); | |
afc8c78d PK |
413 | *disable = !iproc_get_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio); |
414 | *pull_up = iproc_get_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio); | |
b64333ce RJ |
415 | spin_unlock_irqrestore(&chip->lock, flags); |
416 | } | |
417 | ||
afc8c78d | 418 | static int iproc_gpio_set_strength(struct iproc_gpio *chip, unsigned gpio, |
b64333ce RJ |
419 | unsigned strength) |
420 | { | |
421 | void __iomem *base; | |
422 | unsigned int i, offset, shift; | |
423 | u32 val; | |
424 | unsigned long flags; | |
425 | ||
426 | /* make sure drive strength is supported */ | |
427 | if (strength < 2 || strength > 16 || (strength % 2)) | |
428 | return -ENOTSUPP; | |
429 | ||
430 | if (chip->io_ctrl) { | |
431 | base = chip->io_ctrl; | |
afc8c78d | 432 | offset = IPROC_GPIO_DRV0_CTRL_OFFSET; |
b64333ce RJ |
433 | } else { |
434 | base = chip->base; | |
afc8c78d PK |
435 | offset = IPROC_GPIO_REG(gpio, |
436 | IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET); | |
b64333ce RJ |
437 | } |
438 | ||
afc8c78d | 439 | shift = IPROC_GPIO_SHIFT(gpio); |
b64333ce RJ |
440 | |
441 | dev_dbg(chip->dev, "gpio:%u set drive strength:%d mA\n", gpio, | |
442 | strength); | |
443 | ||
444 | spin_lock_irqsave(&chip->lock, flags); | |
445 | strength = (strength / 2) - 1; | |
446 | for (i = 0; i < GPIO_DRV_STRENGTH_BITS; i++) { | |
447 | val = readl(base + offset); | |
448 | val &= ~BIT(shift); | |
449 | val |= ((strength >> i) & 0x1) << shift; | |
450 | writel(val, base + offset); | |
451 | offset += 4; | |
452 | } | |
453 | spin_unlock_irqrestore(&chip->lock, flags); | |
454 | ||
455 | return 0; | |
456 | } | |
457 | ||
afc8c78d | 458 | static int iproc_gpio_get_strength(struct iproc_gpio *chip, unsigned gpio, |
b64333ce RJ |
459 | u16 *strength) |
460 | { | |
461 | void __iomem *base; | |
462 | unsigned int i, offset, shift; | |
463 | u32 val; | |
464 | unsigned long flags; | |
465 | ||
466 | if (chip->io_ctrl) { | |
467 | base = chip->io_ctrl; | |
afc8c78d | 468 | offset = IPROC_GPIO_DRV0_CTRL_OFFSET; |
b64333ce RJ |
469 | } else { |
470 | base = chip->base; | |
afc8c78d PK |
471 | offset = IPROC_GPIO_REG(gpio, |
472 | IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET); | |
b64333ce RJ |
473 | } |
474 | ||
afc8c78d | 475 | shift = IPROC_GPIO_SHIFT(gpio); |
b64333ce RJ |
476 | |
477 | spin_lock_irqsave(&chip->lock, flags); | |
478 | *strength = 0; | |
479 | for (i = 0; i < GPIO_DRV_STRENGTH_BITS; i++) { | |
480 | val = readl(base + offset) & BIT(shift); | |
481 | val >>= shift; | |
482 | *strength += (val << i); | |
483 | offset += 4; | |
484 | } | |
485 | ||
486 | /* convert to mA */ | |
487 | *strength = (*strength + 1) * 2; | |
488 | spin_unlock_irqrestore(&chip->lock, flags); | |
489 | ||
490 | return 0; | |
491 | } | |
492 | ||
afc8c78d | 493 | static int iproc_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin, |
b64333ce RJ |
494 | unsigned long *config) |
495 | { | |
afc8c78d | 496 | struct iproc_gpio *chip = pinctrl_dev_get_drvdata(pctldev); |
b64333ce | 497 | enum pin_config_param param = pinconf_to_config_param(*config); |
afc8c78d | 498 | unsigned gpio = iproc_pin_to_gpio(pin); |
b64333ce RJ |
499 | u16 arg; |
500 | bool disable, pull_up; | |
501 | int ret; | |
502 | ||
503 | switch (param) { | |
504 | case PIN_CONFIG_BIAS_DISABLE: | |
afc8c78d | 505 | iproc_gpio_get_pull(chip, gpio, &disable, &pull_up); |
b64333ce RJ |
506 | if (disable) |
507 | return 0; | |
508 | else | |
509 | return -EINVAL; | |
510 | ||
511 | case PIN_CONFIG_BIAS_PULL_UP: | |
afc8c78d | 512 | iproc_gpio_get_pull(chip, gpio, &disable, &pull_up); |
b64333ce RJ |
513 | if (!disable && pull_up) |
514 | return 0; | |
515 | else | |
516 | return -EINVAL; | |
517 | ||
518 | case PIN_CONFIG_BIAS_PULL_DOWN: | |
afc8c78d | 519 | iproc_gpio_get_pull(chip, gpio, &disable, &pull_up); |
b64333ce RJ |
520 | if (!disable && !pull_up) |
521 | return 0; | |
522 | else | |
523 | return -EINVAL; | |
524 | ||
525 | case PIN_CONFIG_DRIVE_STRENGTH: | |
afc8c78d | 526 | ret = iproc_gpio_get_strength(chip, gpio, &arg); |
b64333ce RJ |
527 | if (ret) |
528 | return ret; | |
616043d5 | 529 | *config = pinconf_to_config_packed(param, arg); |
b64333ce RJ |
530 | |
531 | return 0; | |
532 | ||
533 | default: | |
534 | return -ENOTSUPP; | |
535 | } | |
536 | ||
537 | return -ENOTSUPP; | |
538 | } | |
539 | ||
afc8c78d | 540 | static int iproc_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, |
b64333ce RJ |
541 | unsigned long *configs, unsigned num_configs) |
542 | { | |
afc8c78d | 543 | struct iproc_gpio *chip = pinctrl_dev_get_drvdata(pctldev); |
b64333ce RJ |
544 | enum pin_config_param param; |
545 | u16 arg; | |
afc8c78d | 546 | unsigned i, gpio = iproc_pin_to_gpio(pin); |
b64333ce RJ |
547 | int ret = -ENOTSUPP; |
548 | ||
549 | for (i = 0; i < num_configs; i++) { | |
550 | param = pinconf_to_config_param(configs[i]); | |
551 | arg = pinconf_to_config_argument(configs[i]); | |
552 | ||
553 | switch (param) { | |
554 | case PIN_CONFIG_BIAS_DISABLE: | |
afc8c78d | 555 | ret = iproc_gpio_set_pull(chip, gpio, true, false); |
b64333ce RJ |
556 | if (ret < 0) |
557 | goto out; | |
558 | break; | |
559 | ||
560 | case PIN_CONFIG_BIAS_PULL_UP: | |
afc8c78d | 561 | ret = iproc_gpio_set_pull(chip, gpio, false, true); |
b64333ce RJ |
562 | if (ret < 0) |
563 | goto out; | |
564 | break; | |
565 | ||
566 | case PIN_CONFIG_BIAS_PULL_DOWN: | |
afc8c78d | 567 | ret = iproc_gpio_set_pull(chip, gpio, false, false); |
b64333ce RJ |
568 | if (ret < 0) |
569 | goto out; | |
570 | break; | |
571 | ||
572 | case PIN_CONFIG_DRIVE_STRENGTH: | |
afc8c78d | 573 | ret = iproc_gpio_set_strength(chip, gpio, arg); |
b64333ce RJ |
574 | if (ret < 0) |
575 | goto out; | |
576 | break; | |
577 | ||
578 | default: | |
579 | dev_err(chip->dev, "invalid configuration\n"); | |
580 | return -ENOTSUPP; | |
581 | } | |
582 | } /* for each config */ | |
583 | ||
584 | out: | |
585 | return ret; | |
586 | } | |
587 | ||
afc8c78d | 588 | static const struct pinconf_ops iproc_pconf_ops = { |
b64333ce | 589 | .is_generic = true, |
afc8c78d PK |
590 | .pin_config_get = iproc_pin_config_get, |
591 | .pin_config_set = iproc_pin_config_set, | |
b64333ce RJ |
592 | }; |
593 | ||
b64333ce | 594 | /* |
afc8c78d | 595 | * Iproc GPIO controller supports some PINCONF related configurations such as |
b64333ce RJ |
596 | * pull up, pull down, and drive strength, when the pin is configured to GPIO |
597 | * | |
598 | * Here a local pinctrl device is created with simple 1-to-1 pin mapping to the | |
599 | * local GPIO pins | |
600 | */ | |
afc8c78d | 601 | static int iproc_gpio_register_pinconf(struct iproc_gpio *chip) |
b64333ce RJ |
602 | { |
603 | struct pinctrl_desc *pctldesc = &chip->pctldesc; | |
604 | struct pinctrl_pin_desc *pins; | |
605 | struct gpio_chip *gc = &chip->gc; | |
606 | int i; | |
607 | ||
608 | pins = devm_kcalloc(chip->dev, gc->ngpio, sizeof(*pins), GFP_KERNEL); | |
609 | if (!pins) | |
610 | return -ENOMEM; | |
611 | ||
612 | for (i = 0; i < gc->ngpio; i++) { | |
613 | pins[i].number = i; | |
614 | pins[i].name = devm_kasprintf(chip->dev, GFP_KERNEL, | |
615 | "gpio-%d", i); | |
616 | if (!pins[i].name) | |
617 | return -ENOMEM; | |
618 | } | |
619 | ||
620 | pctldesc->name = dev_name(chip->dev); | |
afc8c78d | 621 | pctldesc->pctlops = &iproc_pctrl_ops; |
b64333ce RJ |
622 | pctldesc->pins = pins; |
623 | pctldesc->npins = gc->ngpio; | |
afc8c78d | 624 | pctldesc->confops = &iproc_pconf_ops; |
b64333ce | 625 | |
ee17e041 | 626 | chip->pctl = devm_pinctrl_register(chip->dev, pctldesc, chip); |
323de9ef | 627 | if (IS_ERR(chip->pctl)) { |
b64333ce | 628 | dev_err(chip->dev, "unable to register pinctrl device\n"); |
323de9ef | 629 | return PTR_ERR(chip->pctl); |
b64333ce RJ |
630 | } |
631 | ||
632 | return 0; | |
633 | } | |
634 | ||
afc8c78d | 635 | static const struct of_device_id iproc_gpio_of_match[] = { |
e1aaaf3f PK |
636 | { .compatible = "brcm,cygnus-ccm-gpio" }, |
637 | { .compatible = "brcm,cygnus-asiu-gpio" }, | |
638 | { .compatible = "brcm,cygnus-crmu-gpio" }, | |
462de629 | 639 | { .compatible = "brcm,iproc-gpio" }, |
e1aaaf3f | 640 | { } |
b64333ce RJ |
641 | }; |
642 | ||
afc8c78d | 643 | static int iproc_gpio_probe(struct platform_device *pdev) |
b64333ce RJ |
644 | { |
645 | struct device *dev = &pdev->dev; | |
646 | struct resource *res; | |
afc8c78d | 647 | struct iproc_gpio *chip; |
b64333ce RJ |
648 | struct gpio_chip *gc; |
649 | u32 ngpios; | |
650 | int irq, ret; | |
b64333ce RJ |
651 | |
652 | chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); | |
653 | if (!chip) | |
654 | return -ENOMEM; | |
655 | ||
656 | chip->dev = dev; | |
657 | platform_set_drvdata(pdev, chip); | |
658 | ||
659 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
660 | chip->base = devm_ioremap_resource(dev, res); | |
661 | if (IS_ERR(chip->base)) { | |
662 | dev_err(dev, "unable to map I/O memory\n"); | |
663 | return PTR_ERR(chip->base); | |
664 | } | |
665 | ||
666 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | |
667 | if (res) { | |
668 | chip->io_ctrl = devm_ioremap_resource(dev, res); | |
669 | if (IS_ERR(chip->io_ctrl)) { | |
670 | dev_err(dev, "unable to map I/O memory\n"); | |
671 | return PTR_ERR(chip->io_ctrl); | |
672 | } | |
673 | } | |
674 | ||
e1aaaf3f PK |
675 | if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) { |
676 | dev_err(&pdev->dev, "missing ngpios DT property\n"); | |
677 | return -ENODEV; | |
678 | } | |
679 | ||
b64333ce RJ |
680 | spin_lock_init(&chip->lock); |
681 | ||
682 | gc = &chip->gc; | |
683 | gc->base = -1; | |
684 | gc->ngpio = ngpios; | |
685 | chip->num_banks = (ngpios + NGPIOS_PER_BANK - 1) / NGPIOS_PER_BANK; | |
686 | gc->label = dev_name(dev); | |
58383c78 | 687 | gc->parent = dev; |
b64333ce | 688 | gc->of_node = dev->of_node; |
afc8c78d PK |
689 | gc->request = iproc_gpio_request; |
690 | gc->free = iproc_gpio_free; | |
691 | gc->direction_input = iproc_gpio_direction_input; | |
692 | gc->direction_output = iproc_gpio_direction_output; | |
693 | gc->set = iproc_gpio_set; | |
694 | gc->get = iproc_gpio_get; | |
b64333ce | 695 | |
ea92211c PK |
696 | chip->pinmux_is_supported = of_property_read_bool(dev->of_node, |
697 | "gpio-ranges"); | |
698 | ||
69fd6aea | 699 | ret = gpiochip_add_data(gc, chip); |
b64333ce RJ |
700 | if (ret < 0) { |
701 | dev_err(dev, "unable to add GPIO chip\n"); | |
702 | return ret; | |
703 | } | |
704 | ||
afc8c78d | 705 | ret = iproc_gpio_register_pinconf(chip); |
b64333ce RJ |
706 | if (ret) { |
707 | dev_err(dev, "unable to register pinconf\n"); | |
708 | goto err_rm_gpiochip; | |
709 | } | |
710 | ||
711 | /* optional GPIO interrupt support */ | |
712 | irq = platform_get_irq(pdev, 0); | |
713 | if (irq) { | |
afc8c78d | 714 | ret = gpiochip_irqchip_add(gc, &iproc_gpio_irq_chip, 0, |
b64333ce RJ |
715 | handle_simple_irq, IRQ_TYPE_NONE); |
716 | if (ret) { | |
717 | dev_err(dev, "no GPIO irqchip\n"); | |
ee17e041 | 718 | goto err_rm_gpiochip; |
b64333ce RJ |
719 | } |
720 | ||
afc8c78d PK |
721 | gpiochip_set_chained_irqchip(gc, &iproc_gpio_irq_chip, irq, |
722 | iproc_gpio_irq_handler); | |
b64333ce RJ |
723 | } |
724 | ||
725 | return 0; | |
726 | ||
b64333ce RJ |
727 | err_rm_gpiochip: |
728 | gpiochip_remove(gc); | |
729 | ||
730 | return ret; | |
731 | } | |
732 | ||
afc8c78d | 733 | static struct platform_driver iproc_gpio_driver = { |
b64333ce | 734 | .driver = { |
afc8c78d PK |
735 | .name = "iproc-gpio", |
736 | .of_match_table = iproc_gpio_of_match, | |
b64333ce | 737 | }, |
afc8c78d | 738 | .probe = iproc_gpio_probe, |
b64333ce RJ |
739 | }; |
740 | ||
afc8c78d | 741 | static int __init iproc_gpio_init(void) |
b64333ce | 742 | { |
afc8c78d | 743 | return platform_driver_probe(&iproc_gpio_driver, iproc_gpio_probe); |
b64333ce | 744 | } |
afc8c78d | 745 | arch_initcall_sync(iproc_gpio_init); |