]>
Commit | Line | Data |
---|---|---|
8bfcbbbc YRDR |
1 | /* |
2 | * Copyright (C) 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 | * | |
13 | * This file contains the Broadcom Northstar Plus (NSP) GPIO driver that | |
14 | * supports the chipCommonA GPIO controller. Basic PINCONF such as bias, | |
15 | * pull up/down, slew and drive strength are also supported in this driver. | |
16 | * | |
17 | * Pins from the chipCommonA GPIO can be individually muxed to GPIO function, | |
18 | * through the interaction with the NSP IOMUX controller. | |
19 | */ | |
20 | ||
27cc78e3 | 21 | #include <linux/gpio/driver.h> |
8bfcbbbc YRDR |
22 | #include <linux/interrupt.h> |
23 | #include <linux/io.h> | |
24 | #include <linux/ioport.h> | |
25 | #include <linux/kernel.h> | |
26 | #include <linux/of_address.h> | |
27 | #include <linux/of_device.h> | |
28 | #include <linux/of_irq.h> | |
29 | #include <linux/pinctrl/pinconf.h> | |
30 | #include <linux/pinctrl/pinconf-generic.h> | |
31 | #include <linux/pinctrl/pinctrl.h> | |
32 | #include <linux/slab.h> | |
33 | ||
34 | #include "../pinctrl-utils.h" | |
35 | ||
36 | #define NSP_CHIP_A_INT_STATUS 0x00 | |
37 | #define NSP_CHIP_A_INT_MASK 0x04 | |
38 | #define NSP_GPIO_DATA_IN 0x40 | |
39 | #define NSP_GPIO_DATA_OUT 0x44 | |
40 | #define NSP_GPIO_OUT_EN 0x48 | |
41 | #define NSP_GPIO_INT_POLARITY 0x50 | |
42 | #define NSP_GPIO_INT_MASK 0x54 | |
43 | #define NSP_GPIO_EVENT 0x58 | |
44 | #define NSP_GPIO_EVENT_INT_MASK 0x5c | |
45 | #define NSP_GPIO_EVENT_INT_POLARITY 0x64 | |
46 | #define NSP_CHIP_A_GPIO_INT_BIT 0x01 | |
47 | ||
48 | /* I/O parameters offset for chipcommon A GPIO */ | |
49 | #define NSP_GPIO_DRV_CTRL 0x00 | |
50 | #define NSP_GPIO_HYSTERESIS_EN 0x10 | |
51 | #define NSP_GPIO_SLEW_RATE_EN 0x14 | |
52 | #define NSP_PULL_UP_EN 0x18 | |
53 | #define NSP_PULL_DOWN_EN 0x1c | |
54 | #define GPIO_DRV_STRENGTH_BITS 0x03 | |
55 | ||
56 | /* | |
57 | * nsp GPIO core | |
58 | * | |
59 | * @dev: pointer to device | |
60 | * @base: I/O register base for nsp GPIO controller | |
61 | * @io_ctrl: I/O register base for PINCONF support outside the GPIO block | |
62 | * @gc: GPIO chip | |
63 | * @pctl: pointer to pinctrl_dev | |
64 | * @pctldesc: pinctrl descriptor | |
65 | * @irq_domain: pointer to irq domain | |
66 | * @lock: lock to protect access to I/O registers | |
67 | */ | |
68 | struct nsp_gpio { | |
69 | struct device *dev; | |
70 | void __iomem *base; | |
71 | void __iomem *io_ctrl; | |
72 | struct gpio_chip gc; | |
73 | struct pinctrl_dev *pctl; | |
74 | struct pinctrl_desc pctldesc; | |
75 | struct irq_domain *irq_domain; | |
76 | spinlock_t lock; | |
77 | }; | |
78 | ||
79 | enum base_type { | |
80 | REG, | |
81 | IO_CTRL | |
82 | }; | |
83 | ||
8bfcbbbc YRDR |
84 | /* |
85 | * Mapping from PINCONF pins to GPIO pins is 1-to-1 | |
86 | */ | |
87 | static inline unsigned nsp_pin_to_gpio(unsigned pin) | |
88 | { | |
89 | return pin; | |
90 | } | |
91 | ||
92 | /* | |
93 | * nsp_set_bit - set or clear one bit (corresponding to the GPIO pin) in a | |
94 | * nsp GPIO register | |
95 | * | |
96 | * @nsp_gpio: nsp GPIO device | |
97 | * @base_type: reg base to modify | |
98 | * @reg: register offset | |
99 | * @gpio: GPIO pin | |
100 | * @set: set or clear | |
101 | */ | |
102 | static inline void nsp_set_bit(struct nsp_gpio *chip, enum base_type address, | |
103 | unsigned int reg, unsigned gpio, bool set) | |
104 | { | |
105 | u32 val; | |
106 | void __iomem *base_address; | |
107 | ||
108 | if (address == IO_CTRL) | |
109 | base_address = chip->io_ctrl; | |
110 | else | |
111 | base_address = chip->base; | |
112 | ||
113 | val = readl(base_address + reg); | |
114 | if (set) | |
115 | val |= BIT(gpio); | |
116 | else | |
117 | val &= ~BIT(gpio); | |
118 | ||
119 | writel(val, base_address + reg); | |
120 | } | |
121 | ||
122 | /* | |
123 | * nsp_get_bit - get one bit (corresponding to the GPIO pin) in a | |
124 | * nsp GPIO register | |
125 | */ | |
126 | static inline bool nsp_get_bit(struct nsp_gpio *chip, enum base_type address, | |
127 | unsigned int reg, unsigned gpio) | |
128 | { | |
129 | if (address == IO_CTRL) | |
130 | return !!(readl(chip->io_ctrl + reg) & BIT(gpio)); | |
131 | else | |
132 | return !!(readl(chip->base + reg) & BIT(gpio)); | |
133 | } | |
134 | ||
135 | static irqreturn_t nsp_gpio_irq_handler(int irq, void *data) | |
136 | { | |
137 | struct nsp_gpio *chip = (struct nsp_gpio *)data; | |
138 | struct gpio_chip gc = chip->gc; | |
139 | int bit; | |
140 | unsigned long int_bits = 0; | |
141 | u32 int_status; | |
142 | ||
143 | /* go through the entire GPIOs and handle all interrupts */ | |
144 | int_status = readl(chip->base + NSP_CHIP_A_INT_STATUS); | |
145 | if (int_status & NSP_CHIP_A_GPIO_INT_BIT) { | |
146 | unsigned int event, level; | |
147 | ||
148 | /* Get level and edge interrupts */ | |
149 | event = readl(chip->base + NSP_GPIO_EVENT_INT_MASK) & | |
150 | readl(chip->base + NSP_GPIO_EVENT); | |
151 | level = readl(chip->base + NSP_GPIO_DATA_IN) ^ | |
152 | readl(chip->base + NSP_GPIO_INT_POLARITY); | |
153 | level &= readl(chip->base + NSP_GPIO_INT_MASK); | |
154 | int_bits = level | event; | |
155 | ||
156 | for_each_set_bit(bit, &int_bits, gc.ngpio) { | |
157 | /* | |
158 | * Clear the interrupt before invoking the | |
159 | * handler, so we do not leave any window | |
160 | */ | |
161 | writel(BIT(bit), chip->base + NSP_GPIO_EVENT); | |
162 | generic_handle_irq( | |
163 | irq_linear_revmap(chip->irq_domain, bit)); | |
164 | } | |
165 | } | |
166 | ||
167 | return int_bits ? IRQ_HANDLED : IRQ_NONE; | |
168 | } | |
169 | ||
170 | static void nsp_gpio_irq_ack(struct irq_data *d) | |
171 | { | |
172 | struct nsp_gpio *chip = irq_data_get_irq_chip_data(d); | |
173 | unsigned gpio = d->hwirq; | |
174 | u32 val = BIT(gpio); | |
175 | u32 trigger_type; | |
176 | ||
177 | trigger_type = irq_get_trigger_type(d->irq); | |
178 | if (trigger_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) | |
179 | nsp_set_bit(chip, REG, NSP_GPIO_EVENT, gpio, val); | |
180 | } | |
181 | ||
182 | /* | |
183 | * nsp_gpio_irq_set_mask - mask/unmask a GPIO interrupt | |
184 | * | |
185 | * @d: IRQ chip data | |
186 | * @unmask: mask/unmask GPIO interrupt | |
187 | */ | |
188 | static void nsp_gpio_irq_set_mask(struct irq_data *d, bool unmask) | |
189 | { | |
190 | struct nsp_gpio *chip = irq_data_get_irq_chip_data(d); | |
191 | unsigned gpio = d->hwirq; | |
192 | u32 trigger_type; | |
193 | ||
194 | trigger_type = irq_get_trigger_type(d->irq); | |
195 | if (trigger_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) | |
196 | nsp_set_bit(chip, REG, NSP_GPIO_EVENT_INT_MASK, gpio, unmask); | |
197 | else | |
198 | nsp_set_bit(chip, REG, NSP_GPIO_INT_MASK, gpio, unmask); | |
199 | } | |
200 | ||
201 | static void nsp_gpio_irq_mask(struct irq_data *d) | |
202 | { | |
203 | struct nsp_gpio *chip = irq_data_get_irq_chip_data(d); | |
204 | unsigned long flags; | |
205 | ||
206 | spin_lock_irqsave(&chip->lock, flags); | |
207 | nsp_gpio_irq_set_mask(d, false); | |
208 | spin_unlock_irqrestore(&chip->lock, flags); | |
209 | } | |
210 | ||
211 | static void nsp_gpio_irq_unmask(struct irq_data *d) | |
212 | { | |
213 | struct nsp_gpio *chip = irq_data_get_irq_chip_data(d); | |
214 | unsigned long flags; | |
215 | ||
216 | spin_lock_irqsave(&chip->lock, flags); | |
217 | nsp_gpio_irq_set_mask(d, true); | |
218 | spin_unlock_irqrestore(&chip->lock, flags); | |
219 | } | |
220 | ||
221 | static int nsp_gpio_irq_set_type(struct irq_data *d, unsigned int type) | |
222 | { | |
223 | struct nsp_gpio *chip = irq_data_get_irq_chip_data(d); | |
224 | unsigned gpio = d->hwirq; | |
225 | bool level_low; | |
226 | bool falling; | |
227 | unsigned long flags; | |
228 | ||
229 | spin_lock_irqsave(&chip->lock, flags); | |
230 | falling = nsp_get_bit(chip, REG, NSP_GPIO_EVENT_INT_POLARITY, gpio); | |
231 | level_low = nsp_get_bit(chip, REG, NSP_GPIO_INT_POLARITY, gpio); | |
232 | ||
233 | switch (type & IRQ_TYPE_SENSE_MASK) { | |
234 | case IRQ_TYPE_EDGE_RISING: | |
235 | falling = false; | |
236 | break; | |
237 | ||
238 | case IRQ_TYPE_EDGE_FALLING: | |
239 | falling = true; | |
240 | break; | |
241 | ||
242 | case IRQ_TYPE_LEVEL_HIGH: | |
243 | level_low = false; | |
244 | break; | |
245 | ||
246 | case IRQ_TYPE_LEVEL_LOW: | |
247 | level_low = true; | |
248 | break; | |
249 | ||
250 | default: | |
251 | dev_err(chip->dev, "invalid GPIO IRQ type 0x%x\n", | |
252 | type); | |
253 | spin_unlock_irqrestore(&chip->lock, flags); | |
254 | return -EINVAL; | |
255 | } | |
256 | ||
257 | nsp_set_bit(chip, REG, NSP_GPIO_EVENT_INT_POLARITY, gpio, falling); | |
258 | nsp_set_bit(chip, REG, NSP_GPIO_INT_POLARITY, gpio, level_low); | |
259 | spin_unlock_irqrestore(&chip->lock, flags); | |
260 | ||
261 | dev_dbg(chip->dev, "gpio:%u level_low:%s falling:%s\n", gpio, | |
262 | level_low ? "true" : "false", falling ? "true" : "false"); | |
263 | return 0; | |
264 | } | |
265 | ||
266 | static struct irq_chip nsp_gpio_irq_chip = { | |
267 | .name = "gpio-a", | |
268 | .irq_enable = nsp_gpio_irq_unmask, | |
269 | .irq_disable = nsp_gpio_irq_mask, | |
270 | .irq_ack = nsp_gpio_irq_ack, | |
271 | .irq_mask = nsp_gpio_irq_mask, | |
272 | .irq_unmask = nsp_gpio_irq_unmask, | |
273 | .irq_set_type = nsp_gpio_irq_set_type, | |
274 | }; | |
275 | ||
276 | /* | |
277 | * Request the nsp IOMUX pinmux controller to mux individual pins to GPIO | |
278 | */ | |
279 | static int nsp_gpio_request(struct gpio_chip *gc, unsigned offset) | |
280 | { | |
281 | unsigned gpio = gc->base + offset; | |
282 | ||
283 | return pinctrl_request_gpio(gpio); | |
284 | } | |
285 | ||
286 | static void nsp_gpio_free(struct gpio_chip *gc, unsigned offset) | |
287 | { | |
288 | unsigned gpio = gc->base + offset; | |
289 | ||
290 | pinctrl_free_gpio(gpio); | |
291 | } | |
292 | ||
293 | static int nsp_gpio_direction_input(struct gpio_chip *gc, unsigned gpio) | |
294 | { | |
27cc78e3 | 295 | struct nsp_gpio *chip = gpiochip_get_data(gc); |
8bfcbbbc YRDR |
296 | unsigned long flags; |
297 | ||
298 | spin_lock_irqsave(&chip->lock, flags); | |
299 | nsp_set_bit(chip, REG, NSP_GPIO_OUT_EN, gpio, false); | |
300 | spin_unlock_irqrestore(&chip->lock, flags); | |
301 | ||
302 | dev_dbg(chip->dev, "gpio:%u set input\n", gpio); | |
303 | return 0; | |
304 | } | |
305 | ||
306 | static int nsp_gpio_direction_output(struct gpio_chip *gc, unsigned gpio, | |
307 | int val) | |
308 | { | |
27cc78e3 | 309 | struct nsp_gpio *chip = gpiochip_get_data(gc); |
8bfcbbbc YRDR |
310 | unsigned long flags; |
311 | ||
312 | spin_lock_irqsave(&chip->lock, flags); | |
313 | nsp_set_bit(chip, REG, NSP_GPIO_OUT_EN, gpio, true); | |
314 | nsp_set_bit(chip, REG, NSP_GPIO_DATA_OUT, gpio, !!(val)); | |
315 | spin_unlock_irqrestore(&chip->lock, flags); | |
316 | ||
317 | dev_dbg(chip->dev, "gpio:%u set output, value:%d\n", gpio, val); | |
318 | return 0; | |
319 | } | |
320 | ||
321 | static void nsp_gpio_set(struct gpio_chip *gc, unsigned gpio, int val) | |
322 | { | |
27cc78e3 | 323 | struct nsp_gpio *chip = gpiochip_get_data(gc); |
8bfcbbbc YRDR |
324 | unsigned long flags; |
325 | ||
326 | spin_lock_irqsave(&chip->lock, flags); | |
327 | nsp_set_bit(chip, REG, NSP_GPIO_DATA_OUT, gpio, !!(val)); | |
328 | spin_unlock_irqrestore(&chip->lock, flags); | |
329 | ||
330 | dev_dbg(chip->dev, "gpio:%u set, value:%d\n", gpio, val); | |
331 | } | |
332 | ||
333 | static int nsp_gpio_get(struct gpio_chip *gc, unsigned gpio) | |
334 | { | |
27cc78e3 | 335 | struct nsp_gpio *chip = gpiochip_get_data(gc); |
8bfcbbbc YRDR |
336 | |
337 | return !!(readl(chip->base + NSP_GPIO_DATA_IN) & BIT(gpio)); | |
338 | } | |
339 | ||
340 | static int nsp_gpio_to_irq(struct gpio_chip *gc, unsigned offset) | |
341 | { | |
27cc78e3 | 342 | struct nsp_gpio *chip = gpiochip_get_data(gc); |
8bfcbbbc YRDR |
343 | |
344 | return irq_linear_revmap(chip->irq_domain, offset); | |
345 | } | |
346 | ||
347 | static int nsp_get_groups_count(struct pinctrl_dev *pctldev) | |
348 | { | |
349 | return 1; | |
350 | } | |
351 | ||
352 | /* | |
353 | * Only one group: "gpio_grp", since this local pinctrl device only performs | |
354 | * GPIO specific PINCONF configurations | |
355 | */ | |
356 | static const char *nsp_get_group_name(struct pinctrl_dev *pctldev, | |
357 | unsigned selector) | |
358 | { | |
359 | return "gpio_grp"; | |
360 | } | |
361 | ||
362 | static const struct pinctrl_ops nsp_pctrl_ops = { | |
363 | .get_groups_count = nsp_get_groups_count, | |
364 | .get_group_name = nsp_get_group_name, | |
365 | .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, | |
d32f7fd3 | 366 | .dt_free_map = pinctrl_utils_free_map, |
8bfcbbbc YRDR |
367 | }; |
368 | ||
369 | static int nsp_gpio_set_slew(struct nsp_gpio *chip, unsigned gpio, u16 slew) | |
370 | { | |
371 | if (slew) | |
372 | nsp_set_bit(chip, IO_CTRL, NSP_GPIO_SLEW_RATE_EN, gpio, true); | |
373 | else | |
374 | nsp_set_bit(chip, IO_CTRL, NSP_GPIO_SLEW_RATE_EN, gpio, false); | |
375 | ||
376 | return 0; | |
377 | } | |
378 | ||
379 | static int nsp_gpio_set_pull(struct nsp_gpio *chip, unsigned gpio, | |
380 | bool pull_up, bool pull_down) | |
381 | { | |
382 | unsigned long flags; | |
383 | ||
384 | spin_lock_irqsave(&chip->lock, flags); | |
385 | nsp_set_bit(chip, IO_CTRL, NSP_PULL_DOWN_EN, gpio, pull_down); | |
386 | nsp_set_bit(chip, IO_CTRL, NSP_PULL_UP_EN, gpio, pull_up); | |
387 | spin_unlock_irqrestore(&chip->lock, flags); | |
388 | ||
389 | dev_dbg(chip->dev, "gpio:%u set pullup:%d pulldown: %d\n", | |
390 | gpio, pull_up, pull_down); | |
391 | return 0; | |
392 | } | |
393 | ||
394 | static void nsp_gpio_get_pull(struct nsp_gpio *chip, unsigned gpio, | |
395 | bool *pull_up, bool *pull_down) | |
396 | { | |
397 | unsigned long flags; | |
398 | ||
399 | spin_lock_irqsave(&chip->lock, flags); | |
400 | *pull_up = nsp_get_bit(chip, IO_CTRL, NSP_PULL_UP_EN, gpio); | |
401 | *pull_down = nsp_get_bit(chip, IO_CTRL, NSP_PULL_DOWN_EN, gpio); | |
402 | spin_unlock_irqrestore(&chip->lock, flags); | |
403 | } | |
404 | ||
405 | static int nsp_gpio_set_strength(struct nsp_gpio *chip, unsigned gpio, | |
406 | u16 strength) | |
407 | { | |
408 | u32 offset, shift, i; | |
409 | u32 val; | |
410 | unsigned long flags; | |
411 | ||
412 | /* make sure drive strength is supported */ | |
413 | if (strength < 2 || strength > 16 || (strength % 2)) | |
414 | return -ENOTSUPP; | |
415 | ||
416 | shift = gpio; | |
417 | offset = NSP_GPIO_DRV_CTRL; | |
418 | dev_dbg(chip->dev, "gpio:%u set drive strength:%d mA\n", gpio, | |
419 | strength); | |
420 | spin_lock_irqsave(&chip->lock, flags); | |
421 | strength = (strength / 2) - 1; | |
422 | for (i = GPIO_DRV_STRENGTH_BITS; i > 0; i--) { | |
423 | val = readl(chip->io_ctrl + offset); | |
424 | val &= ~BIT(shift); | |
425 | val |= ((strength >> (i-1)) & 0x1) << shift; | |
426 | writel(val, chip->io_ctrl + offset); | |
427 | offset += 4; | |
428 | } | |
429 | spin_unlock_irqrestore(&chip->lock, flags); | |
430 | ||
431 | return 0; | |
432 | } | |
433 | ||
434 | static int nsp_gpio_get_strength(struct nsp_gpio *chip, unsigned gpio, | |
435 | u16 *strength) | |
436 | { | |
ce6c1cd2 | 437 | unsigned int offset, shift; |
8bfcbbbc YRDR |
438 | u32 val; |
439 | unsigned long flags; | |
ce6c1cd2 | 440 | int i; |
8bfcbbbc YRDR |
441 | |
442 | offset = NSP_GPIO_DRV_CTRL; | |
443 | shift = gpio; | |
444 | ||
445 | spin_lock_irqsave(&chip->lock, flags); | |
446 | *strength = 0; | |
447 | for (i = (GPIO_DRV_STRENGTH_BITS - 1); i >= 0; i--) { | |
448 | val = readl(chip->io_ctrl + offset) & BIT(shift); | |
449 | val >>= shift; | |
450 | *strength += (val << i); | |
451 | offset += 4; | |
452 | } | |
453 | ||
454 | /* convert to mA */ | |
455 | *strength = (*strength + 1) * 2; | |
456 | spin_unlock_irqrestore(&chip->lock, flags); | |
457 | ||
458 | return 0; | |
459 | } | |
460 | ||
d5e4d7ab BD |
461 | static int nsp_pin_config_group_get(struct pinctrl_dev *pctldev, |
462 | unsigned selector, | |
8bfcbbbc YRDR |
463 | unsigned long *config) |
464 | { | |
465 | return 0; | |
466 | } | |
467 | ||
d5e4d7ab BD |
468 | static int nsp_pin_config_group_set(struct pinctrl_dev *pctldev, |
469 | unsigned selector, | |
8bfcbbbc YRDR |
470 | unsigned long *configs, unsigned num_configs) |
471 | { | |
472 | return 0; | |
473 | } | |
474 | ||
475 | static int nsp_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin, | |
476 | unsigned long *config) | |
477 | { | |
478 | struct nsp_gpio *chip = pinctrl_dev_get_drvdata(pctldev); | |
479 | enum pin_config_param param = pinconf_to_config_param(*config); | |
480 | unsigned int gpio; | |
481 | u16 arg = 0; | |
482 | bool pull_up, pull_down; | |
483 | int ret; | |
484 | ||
485 | gpio = nsp_pin_to_gpio(pin); | |
486 | switch (param) { | |
487 | case PIN_CONFIG_BIAS_DISABLE: | |
488 | nsp_gpio_get_pull(chip, gpio, &pull_up, &pull_down); | |
489 | if ((pull_up == false) && (pull_down == false)) | |
490 | return 0; | |
491 | else | |
492 | return -EINVAL; | |
493 | ||
494 | case PIN_CONFIG_BIAS_PULL_UP: | |
495 | nsp_gpio_get_pull(chip, gpio, &pull_up, &pull_down); | |
496 | if (pull_up) | |
497 | return 0; | |
498 | else | |
499 | return -EINVAL; | |
500 | ||
501 | case PIN_CONFIG_BIAS_PULL_DOWN: | |
502 | nsp_gpio_get_pull(chip, gpio, &pull_up, &pull_down); | |
503 | if (pull_down) | |
504 | return 0; | |
505 | else | |
506 | return -EINVAL; | |
507 | ||
508 | case PIN_CONFIG_DRIVE_STRENGTH: | |
509 | ret = nsp_gpio_get_strength(chip, gpio, &arg); | |
510 | if (ret) | |
511 | return ret; | |
512 | *config = pinconf_to_config_packed(param, arg); | |
513 | return 0; | |
514 | ||
515 | default: | |
516 | return -ENOTSUPP; | |
517 | } | |
518 | } | |
519 | ||
520 | static int nsp_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, | |
521 | unsigned long *configs, unsigned num_configs) | |
522 | { | |
523 | struct nsp_gpio *chip = pinctrl_dev_get_drvdata(pctldev); | |
524 | enum pin_config_param param; | |
525 | u16 arg; | |
526 | unsigned int i, gpio; | |
527 | int ret = -ENOTSUPP; | |
528 | ||
529 | gpio = nsp_pin_to_gpio(pin); | |
530 | for (i = 0; i < num_configs; i++) { | |
531 | param = pinconf_to_config_param(configs[i]); | |
532 | arg = pinconf_to_config_argument(configs[i]); | |
533 | ||
534 | switch (param) { | |
535 | case PIN_CONFIG_BIAS_DISABLE: | |
536 | ret = nsp_gpio_set_pull(chip, gpio, false, false); | |
537 | if (ret < 0) | |
538 | goto out; | |
539 | break; | |
540 | ||
541 | case PIN_CONFIG_BIAS_PULL_UP: | |
542 | ret = nsp_gpio_set_pull(chip, gpio, true, false); | |
543 | if (ret < 0) | |
544 | goto out; | |
545 | break; | |
546 | ||
547 | case PIN_CONFIG_BIAS_PULL_DOWN: | |
548 | ret = nsp_gpio_set_pull(chip, gpio, false, true); | |
549 | if (ret < 0) | |
550 | goto out; | |
551 | break; | |
552 | ||
553 | case PIN_CONFIG_DRIVE_STRENGTH: | |
554 | ret = nsp_gpio_set_strength(chip, gpio, arg); | |
555 | if (ret < 0) | |
556 | goto out; | |
557 | break; | |
558 | ||
559 | case PIN_CONFIG_SLEW_RATE: | |
560 | ret = nsp_gpio_set_slew(chip, gpio, arg); | |
561 | if (ret < 0) | |
562 | goto out; | |
563 | break; | |
564 | ||
565 | default: | |
566 | dev_err(chip->dev, "invalid configuration\n"); | |
567 | return -ENOTSUPP; | |
568 | } | |
569 | } | |
570 | ||
571 | out: | |
572 | return ret; | |
573 | } | |
574 | ||
575 | static const struct pinconf_ops nsp_pconf_ops = { | |
576 | .is_generic = true, | |
577 | .pin_config_get = nsp_pin_config_get, | |
578 | .pin_config_set = nsp_pin_config_set, | |
579 | .pin_config_group_get = nsp_pin_config_group_get, | |
580 | .pin_config_group_set = nsp_pin_config_group_set, | |
581 | }; | |
582 | ||
583 | /* | |
584 | * NSP GPIO controller supports some PINCONF related configurations such as | |
585 | * pull up, pull down, slew and drive strength, when the pin is configured | |
586 | * to GPIO. | |
587 | * | |
588 | * Here a local pinctrl device is created with simple 1-to-1 pin mapping to the | |
589 | * local GPIO pins | |
590 | */ | |
591 | static int nsp_gpio_register_pinconf(struct nsp_gpio *chip) | |
592 | { | |
593 | struct pinctrl_desc *pctldesc = &chip->pctldesc; | |
594 | struct pinctrl_pin_desc *pins; | |
595 | struct gpio_chip *gc = &chip->gc; | |
596 | int i; | |
597 | ||
598 | pins = devm_kcalloc(chip->dev, gc->ngpio, sizeof(*pins), GFP_KERNEL); | |
599 | if (!pins) | |
600 | return -ENOMEM; | |
601 | for (i = 0; i < gc->ngpio; i++) { | |
602 | pins[i].number = i; | |
603 | pins[i].name = devm_kasprintf(chip->dev, GFP_KERNEL, | |
604 | "gpio-%d", i); | |
605 | if (!pins[i].name) | |
606 | return -ENOMEM; | |
607 | } | |
608 | pctldesc->name = dev_name(chip->dev); | |
609 | pctldesc->pctlops = &nsp_pctrl_ops; | |
610 | pctldesc->pins = pins; | |
611 | pctldesc->npins = gc->ngpio; | |
612 | pctldesc->confops = &nsp_pconf_ops; | |
613 | ||
315d118f | 614 | chip->pctl = devm_pinctrl_register(chip->dev, pctldesc, chip); |
8bfcbbbc YRDR |
615 | if (IS_ERR(chip->pctl)) { |
616 | dev_err(chip->dev, "unable to register pinctrl device\n"); | |
617 | return PTR_ERR(chip->pctl); | |
618 | } | |
619 | ||
620 | return 0; | |
621 | } | |
622 | ||
623 | static const struct of_device_id nsp_gpio_of_match[] = { | |
624 | {.compatible = "brcm,nsp-gpio-a",}, | |
625 | {} | |
626 | }; | |
627 | ||
628 | static int nsp_gpio_probe(struct platform_device *pdev) | |
629 | { | |
630 | struct device *dev = &pdev->dev; | |
631 | struct resource *res; | |
632 | struct nsp_gpio *chip; | |
633 | struct gpio_chip *gc; | |
634 | u32 val, count; | |
635 | int irq, ret; | |
636 | ||
637 | if (of_property_read_u32(pdev->dev.of_node, "ngpios", &val)) { | |
638 | dev_err(&pdev->dev, "Missing ngpios OF property\n"); | |
639 | return -ENODEV; | |
640 | } | |
641 | ||
642 | chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); | |
643 | if (!chip) | |
644 | return -ENOMEM; | |
645 | ||
646 | chip->dev = dev; | |
647 | platform_set_drvdata(pdev, chip); | |
648 | ||
649 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
650 | chip->base = devm_ioremap_resource(dev, res); | |
651 | if (IS_ERR(chip->base)) { | |
652 | dev_err(dev, "unable to map I/O memory\n"); | |
653 | return PTR_ERR(chip->base); | |
654 | } | |
655 | ||
656 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | |
657 | chip->io_ctrl = devm_ioremap_resource(dev, res); | |
658 | if (IS_ERR(chip->io_ctrl)) { | |
659 | dev_err(dev, "unable to map I/O memory\n"); | |
660 | return PTR_ERR(chip->io_ctrl); | |
661 | } | |
662 | ||
663 | spin_lock_init(&chip->lock); | |
664 | gc = &chip->gc; | |
665 | gc->base = -1; | |
666 | gc->can_sleep = false; | |
667 | gc->ngpio = val; | |
668 | gc->label = dev_name(dev); | |
01821412 | 669 | gc->parent = dev; |
8bfcbbbc YRDR |
670 | gc->of_node = dev->of_node; |
671 | gc->request = nsp_gpio_request; | |
672 | gc->free = nsp_gpio_free; | |
673 | gc->direction_input = nsp_gpio_direction_input; | |
674 | gc->direction_output = nsp_gpio_direction_output; | |
675 | gc->set = nsp_gpio_set; | |
676 | gc->get = nsp_gpio_get; | |
677 | gc->to_irq = nsp_gpio_to_irq; | |
678 | ||
679 | /* optional GPIO interrupt support */ | |
680 | irq = platform_get_irq(pdev, 0); | |
681 | if (irq > 0) { | |
682 | /* Create irq domain so that each pin can be assigned an IRQ.*/ | |
683 | chip->irq_domain = irq_domain_add_linear(gc->of_node, gc->ngpio, | |
684 | &irq_domain_simple_ops, | |
685 | chip); | |
686 | if (!chip->irq_domain) { | |
687 | dev_err(&pdev->dev, "Couldn't allocate IRQ domain\n"); | |
688 | return -ENXIO; | |
689 | } | |
690 | ||
691 | /* Map each gpio to an IRQ and set the handler for gpiolib. */ | |
692 | for (count = 0; count < gc->ngpio; count++) { | |
693 | int irq = irq_create_mapping(chip->irq_domain, count); | |
694 | ||
695 | irq_set_chip_and_handler(irq, &nsp_gpio_irq_chip, | |
696 | handle_simple_irq); | |
8bfcbbbc YRDR |
697 | irq_set_chip_data(irq, chip); |
698 | } | |
699 | ||
700 | /* Install ISR for this GPIO controller. */ | |
701 | ret = devm_request_irq(&pdev->dev, irq, nsp_gpio_irq_handler, | |
702 | IRQF_SHARED, "gpio-a", chip); | |
703 | if (ret) { | |
704 | dev_err(&pdev->dev, "Unable to request IRQ%d: %d\n", | |
705 | irq, ret); | |
706 | goto err_rm_gpiochip; | |
707 | } | |
708 | ||
709 | val = readl(chip->base + NSP_CHIP_A_INT_MASK); | |
710 | val = val | NSP_CHIP_A_GPIO_INT_BIT; | |
711 | writel(val, (chip->base + NSP_CHIP_A_INT_MASK)); | |
712 | } | |
713 | ||
27cc78e3 | 714 | ret = gpiochip_add_data(gc, chip); |
8bfcbbbc YRDR |
715 | if (ret < 0) { |
716 | dev_err(dev, "unable to add GPIO chip\n"); | |
717 | return ret; | |
718 | } | |
719 | ||
720 | ret = nsp_gpio_register_pinconf(chip); | |
721 | if (ret) { | |
722 | dev_err(dev, "unable to register pinconf\n"); | |
723 | goto err_rm_gpiochip; | |
724 | } | |
725 | ||
726 | return 0; | |
727 | ||
728 | err_rm_gpiochip: | |
729 | gpiochip_remove(gc); | |
730 | ||
731 | return ret; | |
732 | } | |
733 | ||
734 | static struct platform_driver nsp_gpio_driver = { | |
735 | .driver = { | |
736 | .name = "nsp-gpio-a", | |
737 | .of_match_table = nsp_gpio_of_match, | |
738 | }, | |
739 | .probe = nsp_gpio_probe, | |
740 | }; | |
741 | ||
742 | static int __init nsp_gpio_init(void) | |
743 | { | |
091c531b | 744 | return platform_driver_register(&nsp_gpio_driver); |
8bfcbbbc YRDR |
745 | } |
746 | arch_initcall_sync(nsp_gpio_init); |