.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Driver for the Atmel PIO4 controller |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2015 Atmel, |
---|
5 | 6 | * 2015 Ludovic Desroches <ludovic.desroches@atmel.com> |
---|
6 | | - * |
---|
7 | | - * This software is licensed under the terms of the GNU General Public |
---|
8 | | - * License version 2, as published by the Free Software Foundation, and |
---|
9 | | - * may be copied, distributed, and modified under those terms. |
---|
10 | | - * |
---|
11 | | - * This program is distributed in the hope that it will be useful, |
---|
12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
14 | | - * GNU General Public License for more details. |
---|
15 | 7 | */ |
---|
16 | 8 | |
---|
17 | 9 | #include <dt-bindings/pinctrl/at91.h> |
---|
18 | 10 | #include <linux/clk.h> |
---|
19 | 11 | #include <linux/gpio/driver.h> |
---|
20 | | -/* FIXME: needed for gpio_to_irq(), get rid of this */ |
---|
21 | | -#include <linux/gpio.h> |
---|
22 | 12 | #include <linux/interrupt.h> |
---|
23 | 13 | #include <linux/io.h> |
---|
24 | 14 | #include <linux/init.h> |
---|
.. | .. |
---|
116 | 106 | * @irq_domain: irq domain for the gpio controller. |
---|
117 | 107 | * @irqs: table containing the hw irq number of the bank. The index of the |
---|
118 | 108 | * table is the bank id. |
---|
| 109 | + * @pm_wakeup_sources: bitmap of wakeup sources (lines) |
---|
| 110 | + * @pm_suspend_backup: backup/restore register values on suspend/resume |
---|
119 | 111 | * @dev: device entry for the Atmel PIO controller. |
---|
120 | 112 | * @node: node of the Atmel PIO controller. |
---|
121 | 113 | */ |
---|
.. | .. |
---|
264 | 256 | .irq_set_wake = atmel_gpio_irq_set_wake, |
---|
265 | 257 | }; |
---|
266 | 258 | |
---|
| 259 | +static int atmel_gpio_to_irq(struct gpio_chip *chip, unsigned offset) |
---|
| 260 | +{ |
---|
| 261 | + struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip); |
---|
| 262 | + |
---|
| 263 | + return irq_find_mapping(atmel_pioctrl->irq_domain, offset); |
---|
| 264 | +} |
---|
| 265 | + |
---|
267 | 266 | static void atmel_gpio_irq_handler(struct irq_desc *desc) |
---|
268 | 267 | { |
---|
269 | 268 | unsigned int irq = irq_desc_get_irq(desc); |
---|
.. | .. |
---|
297 | 296 | break; |
---|
298 | 297 | |
---|
299 | 298 | for_each_set_bit(n, &isr, BITS_PER_LONG) |
---|
300 | | - generic_handle_irq(gpio_to_irq(bank * |
---|
301 | | - ATMEL_PIO_NPINS_PER_BANK + n)); |
---|
| 299 | + generic_handle_irq(atmel_gpio_to_irq( |
---|
| 300 | + atmel_pioctrl->gpio_chip, |
---|
| 301 | + bank * ATMEL_PIO_NPINS_PER_BANK + n)); |
---|
302 | 302 | } |
---|
303 | 303 | |
---|
304 | 304 | chained_irq_exit(chip, desc); |
---|
.. | .. |
---|
328 | 328 | reg = atmel_gpio_read(atmel_pioctrl, pin->bank, ATMEL_PIO_PDSR); |
---|
329 | 329 | |
---|
330 | 330 | return !!(reg & BIT(pin->line)); |
---|
| 331 | +} |
---|
| 332 | + |
---|
| 333 | +static int atmel_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, |
---|
| 334 | + unsigned long *bits) |
---|
| 335 | +{ |
---|
| 336 | + struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip); |
---|
| 337 | + unsigned int bank; |
---|
| 338 | + |
---|
| 339 | + bitmap_zero(bits, atmel_pioctrl->npins); |
---|
| 340 | + |
---|
| 341 | + for (bank = 0; bank < atmel_pioctrl->nbanks; bank++) { |
---|
| 342 | + unsigned int word = bank; |
---|
| 343 | + unsigned int offset = 0; |
---|
| 344 | + unsigned int reg; |
---|
| 345 | + |
---|
| 346 | +#if ATMEL_PIO_NPINS_PER_BANK != BITS_PER_LONG |
---|
| 347 | + word = BIT_WORD(bank * ATMEL_PIO_NPINS_PER_BANK); |
---|
| 348 | + offset = bank * ATMEL_PIO_NPINS_PER_BANK % BITS_PER_LONG; |
---|
| 349 | +#endif |
---|
| 350 | + if (!mask[word]) |
---|
| 351 | + continue; |
---|
| 352 | + |
---|
| 353 | + reg = atmel_gpio_read(atmel_pioctrl, bank, ATMEL_PIO_PDSR); |
---|
| 354 | + bits[word] |= mask[word] & (reg << offset); |
---|
| 355 | + } |
---|
| 356 | + |
---|
| 357 | + return 0; |
---|
331 | 358 | } |
---|
332 | 359 | |
---|
333 | 360 | static int atmel_gpio_direction_output(struct gpio_chip *chip, unsigned offset, |
---|
.. | .. |
---|
360 | 387 | BIT(pin->line)); |
---|
361 | 388 | } |
---|
362 | 389 | |
---|
363 | | -static int atmel_gpio_to_irq(struct gpio_chip *chip, unsigned offset) |
---|
| 390 | +static void atmel_gpio_set_multiple(struct gpio_chip *chip, unsigned long *mask, |
---|
| 391 | + unsigned long *bits) |
---|
364 | 392 | { |
---|
365 | 393 | struct atmel_pioctrl *atmel_pioctrl = gpiochip_get_data(chip); |
---|
| 394 | + unsigned int bank; |
---|
366 | 395 | |
---|
367 | | - return irq_find_mapping(atmel_pioctrl->irq_domain, offset); |
---|
| 396 | + for (bank = 0; bank < atmel_pioctrl->nbanks; bank++) { |
---|
| 397 | + unsigned int bitmask; |
---|
| 398 | + unsigned int word = bank; |
---|
| 399 | + |
---|
| 400 | +/* |
---|
| 401 | + * On a 64-bit platform, BITS_PER_LONG is 64 so it is necessary to iterate over |
---|
| 402 | + * two 32bit words to handle the whole bitmask |
---|
| 403 | + */ |
---|
| 404 | +#if ATMEL_PIO_NPINS_PER_BANK != BITS_PER_LONG |
---|
| 405 | + word = BIT_WORD(bank * ATMEL_PIO_NPINS_PER_BANK); |
---|
| 406 | +#endif |
---|
| 407 | + if (!mask[word]) |
---|
| 408 | + continue; |
---|
| 409 | + |
---|
| 410 | + bitmask = mask[word] & bits[word]; |
---|
| 411 | + atmel_gpio_write(atmel_pioctrl, bank, ATMEL_PIO_SODR, bitmask); |
---|
| 412 | + |
---|
| 413 | + bitmask = mask[word] & ~bits[word]; |
---|
| 414 | + atmel_gpio_write(atmel_pioctrl, bank, ATMEL_PIO_CODR, bitmask); |
---|
| 415 | + |
---|
| 416 | +#if ATMEL_PIO_NPINS_PER_BANK != BITS_PER_LONG |
---|
| 417 | + mask[word] >>= ATMEL_PIO_NPINS_PER_BANK; |
---|
| 418 | + bits[word] >>= ATMEL_PIO_NPINS_PER_BANK; |
---|
| 419 | +#endif |
---|
| 420 | + } |
---|
368 | 421 | } |
---|
369 | 422 | |
---|
370 | 423 | static struct gpio_chip atmel_gpio_chip = { |
---|
371 | 424 | .direction_input = atmel_gpio_direction_input, |
---|
372 | 425 | .get = atmel_gpio_get, |
---|
| 426 | + .get_multiple = atmel_gpio_get_multiple, |
---|
373 | 427 | .direction_output = atmel_gpio_direction_output, |
---|
374 | 428 | .set = atmel_gpio_set, |
---|
| 429 | + .set_multiple = atmel_gpio_set_multiple, |
---|
375 | 430 | .to_irq = atmel_gpio_to_irq, |
---|
376 | 431 | .base = 0, |
---|
377 | 432 | }; |
---|
.. | .. |
---|
869 | 924 | |
---|
870 | 925 | static int __maybe_unused atmel_pctrl_suspend(struct device *dev) |
---|
871 | 926 | { |
---|
872 | | - struct platform_device *pdev = to_platform_device(dev); |
---|
873 | | - struct atmel_pioctrl *atmel_pioctrl = platform_get_drvdata(pdev); |
---|
| 927 | + struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(dev); |
---|
874 | 928 | int i, j; |
---|
875 | 929 | |
---|
876 | 930 | /* |
---|
.. | .. |
---|
898 | 952 | |
---|
899 | 953 | static int __maybe_unused atmel_pctrl_resume(struct device *dev) |
---|
900 | 954 | { |
---|
901 | | - struct platform_device *pdev = to_platform_device(dev); |
---|
902 | | - struct atmel_pioctrl *atmel_pioctrl = platform_get_drvdata(pdev); |
---|
| 955 | + struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(dev); |
---|
903 | 956 | int i, j; |
---|
904 | 957 | |
---|
905 | 958 | for (i = 0; i < atmel_pioctrl->nbanks; i++) { |
---|
.. | .. |
---|
930 | 983 | .nbanks = 4, |
---|
931 | 984 | }; |
---|
932 | 985 | |
---|
| 986 | +static const struct atmel_pioctrl_data microchip_sama7g5_pioctrl_data = { |
---|
| 987 | + .nbanks = 5, |
---|
| 988 | +}; |
---|
| 989 | + |
---|
933 | 990 | static const struct of_device_id atmel_pctrl_of_match[] = { |
---|
934 | 991 | { |
---|
935 | 992 | .compatible = "atmel,sama5d2-pinctrl", |
---|
936 | 993 | .data = &atmel_sama5d2_pioctrl_data, |
---|
| 994 | + }, { |
---|
| 995 | + .compatible = "microchip,sama7g5-pinctrl", |
---|
| 996 | + .data = µchip_sama7g5_pioctrl_data, |
---|
937 | 997 | }, { |
---|
938 | 998 | /* sentinel */ |
---|
939 | 999 | } |
---|
.. | .. |
---|
966 | 1026 | atmel_pioctrl->nbanks = atmel_pioctrl_data->nbanks; |
---|
967 | 1027 | atmel_pioctrl->npins = atmel_pioctrl->nbanks * ATMEL_PIO_NPINS_PER_BANK; |
---|
968 | 1028 | |
---|
969 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
970 | | - atmel_pioctrl->reg_base = devm_ioremap_resource(dev, res); |
---|
| 1029 | + atmel_pioctrl->reg_base = devm_platform_ioremap_resource(pdev, 0); |
---|
971 | 1030 | if (IS_ERR(atmel_pioctrl->reg_base)) |
---|
972 | | - return -EINVAL; |
---|
| 1031 | + return PTR_ERR(atmel_pioctrl->reg_base); |
---|
973 | 1032 | |
---|
974 | 1033 | atmel_pioctrl->clk = devm_clk_get(dev, NULL); |
---|
975 | 1034 | if (IS_ERR(atmel_pioctrl->clk)) { |
---|