Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 | // SPDX-License-Identifier: GPL-2.0 // // Copyright (c) 2009-2011 Samsung Electronics Co., Ltd. // http://www.samsung.com/ // // Copyright 2008 Openmoko, Inc. // Copyright 2008 Simtec Electronics // Ben Dooks <ben@simtec.co.uk> // http://armlinux.simtec.co.uk/ // // Samsung - GPIOlib support #include <linux/kernel.h> #include <linux/irq.h> #include <linux/io.h> #include <linux/gpio.h> #include <linux/init.h> #include <linux/spinlock.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/device.h> #include <linux/ioport.h> #include <linux/of.h> #include <linux/slab.h> #include <linux/of_address.h> #include <asm/irq.h> #include "irqs.h" #include "map.h" #include "regs-gpio.h" #include "gpio-samsung.h" #include "cpu.h" #include "gpio-core.h" #include "gpio-cfg.h" #include "gpio-cfg-helpers.h" #include "pm.h" static int samsung_gpio_setpull_updown(struct samsung_gpio_chip *chip, unsigned int off, samsung_gpio_pull_t pull) { void __iomem *reg = chip->base + 0x08; int shift = off * 2; u32 pup; pup = __raw_readl(reg); pup &= ~(3 << shift); pup |= pull << shift; __raw_writel(pup, reg); return 0; } static samsung_gpio_pull_t samsung_gpio_getpull_updown(struct samsung_gpio_chip *chip, unsigned int off) { void __iomem *reg = chip->base + 0x08; int shift = off * 2; u32 pup = __raw_readl(reg); pup >>= shift; pup &= 0x3; return (__force samsung_gpio_pull_t)pup; } static int samsung_gpio_setcfg_2bit(struct samsung_gpio_chip *chip, unsigned int off, unsigned int cfg) { void __iomem *reg = chip->base; unsigned int shift = off * 2; u32 con; if (samsung_gpio_is_cfg_special(cfg)) { cfg &= 0xf; if (cfg > 3) return -EINVAL; cfg <<= shift; } con = __raw_readl(reg); con &= ~(0x3 << shift); con |= cfg; __raw_writel(con, reg); return 0; } /* * samsung_gpio_getcfg_2bit - Samsung 2bit style GPIO configuration read. * @chip: The gpio chip that is being configured. * @off: The offset for the GPIO being configured. * * The reverse of samsung_gpio_setcfg_2bit(). Will return a value which * could be directly passed back to samsung_gpio_setcfg_2bit(), from the * S3C_GPIO_SPECIAL() macro. */ static unsigned int samsung_gpio_getcfg_2bit(struct samsung_gpio_chip *chip, unsigned int off) { u32 con; con = __raw_readl(chip->base); con >>= off * 2; con &= 3; /* this conversion works for IN and OUT as well as special mode */ return S3C_GPIO_SPECIAL(con); } /* * samsung_gpio_setcfg_4bit - Samsung 4bit single register GPIO config. * @chip: The gpio chip that is being configured. * @off: The offset for the GPIO being configured. * @cfg: The configuration value to set. * * This helper deal with the GPIO cases where the control register has 4 bits * of control per GPIO, generally in the form of: * 0000 = Input * 0001 = Output * others = Special functions (dependent on bank) * * Note, since the code to deal with the case where there are two control * registers instead of one, we do not have a separate set of functions for * each case. */ static int samsung_gpio_setcfg_4bit(struct samsung_gpio_chip *chip, unsigned int off, unsigned int cfg) { void __iomem *reg = chip->base; unsigned int shift = (off & 7) * 4; u32 con; if (off < 8 && chip->chip.ngpio > 8) reg -= 4; if (samsung_gpio_is_cfg_special(cfg)) { cfg &= 0xf; cfg <<= shift; } con = __raw_readl(reg); con &= ~(0xf << shift); con |= cfg; __raw_writel(con, reg); return 0; } /* * samsung_gpio_getcfg_4bit - Samsung 4bit single register GPIO config read. * @chip: The gpio chip that is being configured. * @off: The offset for the GPIO being configured. * * The reverse of samsung_gpio_setcfg_4bit(), turning a gpio configuration * register setting into a value the software can use, such as could be passed * to samsung_gpio_setcfg_4bit(). * * @sa samsung_gpio_getcfg_2bit */ static unsigned samsung_gpio_getcfg_4bit(struct samsung_gpio_chip *chip, unsigned int off) { void __iomem *reg = chip->base; unsigned int shift = (off & 7) * 4; u32 con; if (off < 8 && chip->chip.ngpio > 8) reg -= 4; con = __raw_readl(reg); con >>= shift; con &= 0xf; /* this conversion works for IN and OUT as well as special mode */ return S3C_GPIO_SPECIAL(con); } static void __init samsung_gpiolib_set_cfg(struct samsung_gpio_cfg *chipcfg, int nr_chips) { for (; nr_chips > 0; nr_chips--, chipcfg++) { if (!chipcfg->set_config) chipcfg->set_config = samsung_gpio_setcfg_4bit; if (!chipcfg->get_config) chipcfg->get_config = samsung_gpio_getcfg_4bit; if (!chipcfg->set_pull) chipcfg->set_pull = samsung_gpio_setpull_updown; if (!chipcfg->get_pull) chipcfg->get_pull = samsung_gpio_getpull_updown; } } static struct samsung_gpio_cfg samsung_gpio_cfgs[] = { [0] = { .cfg_eint = 0x0, }, [1] = { .cfg_eint = 0x3, }, [2] = { .cfg_eint = 0x7, }, [3] = { .cfg_eint = 0xF, }, [4] = { .cfg_eint = 0x0, .set_config = samsung_gpio_setcfg_2bit, .get_config = samsung_gpio_getcfg_2bit, }, [5] = { .cfg_eint = 0x2, .set_config = samsung_gpio_setcfg_2bit, .get_config = samsung_gpio_getcfg_2bit, }, [6] = { .cfg_eint = 0x3, .set_config = samsung_gpio_setcfg_2bit, .get_config = samsung_gpio_getcfg_2bit, }, [7] = { .set_config = samsung_gpio_setcfg_2bit, .get_config = samsung_gpio_getcfg_2bit, }, }; /* * Default routines for controlling GPIO, based on the original S3C24XX * GPIO functions which deal with the case where each gpio bank of the * chip is as following: * * base + 0x00: Control register, 2 bits per gpio * gpio n: 2 bits starting at (2*n) * 00 = input, 01 = output, others mean special-function * base + 0x04: Data register, 1 bit per gpio * bit n: data bit n */ static int samsung_gpiolib_2bit_input(struct gpio_chip *chip, unsigned offset) { struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); void __iomem *base = ourchip->base; unsigned long flags; unsigned long con; samsung_gpio_lock(ourchip, flags); con = __raw_readl(base + 0x00); con &= ~(3 << (offset * 2)); __raw_writel(con, base + 0x00); samsung_gpio_unlock(ourchip, flags); return 0; } static int samsung_gpiolib_2bit_output(struct gpio_chip *chip, unsigned offset, int value) { struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); void __iomem *base = ourchip->base; unsigned long flags; unsigned long dat; unsigned long con; samsung_gpio_lock(ourchip, flags); dat = __raw_readl(base + 0x04); dat &= ~(1 << offset); if (value) dat |= 1 << offset; __raw_writel(dat, base + 0x04); con = __raw_readl(base + 0x00); con &= ~(3 << (offset * 2)); con |= 1 << (offset * 2); __raw_writel(con, base + 0x00); __raw_writel(dat, base + 0x04); samsung_gpio_unlock(ourchip, flags); return 0; } /* * The samsung_gpiolib_4bit routines are to control the gpio banks where * the gpio configuration register (GPxCON) has 4 bits per GPIO, as the * following example: * * base + 0x00: Control register, 4 bits per gpio * gpio n: 4 bits starting at (4*n) * 0000 = input, 0001 = output, others mean special-function * base + 0x04: Data register, 1 bit per gpio * bit n: data bit n * * Note, since the data register is one bit per gpio and is at base + 0x4 * we can use samsung_gpiolib_get and samsung_gpiolib_set to change the * state of the output. */ static int samsung_gpiolib_4bit_input(struct gpio_chip *chip, unsigned int offset) { struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); void __iomem *base = ourchip->base; unsigned long con; con = __raw_readl(base + GPIOCON_OFF); if (ourchip->bitmap_gpio_int & BIT(offset)) con |= 0xf << con_4bit_shift(offset); else con &= ~(0xf << con_4bit_shift(offset)); __raw_writel(con, base + GPIOCON_OFF); pr_debug("%s: %p: CON now %08lx\n", __func__, base, con); return 0; } static int samsung_gpiolib_4bit_output(struct gpio_chip *chip, unsigned int offset, int value) { struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); void __iomem *base = ourchip->base; unsigned long con; unsigned long dat; con = __raw_readl(base + GPIOCON_OFF); con &= ~(0xf << con_4bit_shift(offset)); con |= 0x1 << con_4bit_shift(offset); dat = __raw_readl(base + GPIODAT_OFF); if (value) dat |= 1 << offset; else dat &= ~(1 << offset); __raw_writel(dat, base + GPIODAT_OFF); __raw_writel(con, base + GPIOCON_OFF); __raw_writel(dat, base + GPIODAT_OFF); pr_debug("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); return 0; } /* * The next set of routines are for the case where the GPIO configuration * registers are 4 bits per GPIO but there is more than one register (the * bank has more than 8 GPIOs. * * This case is the similar to the 4 bit case, but the registers are as * follows: * * base + 0x00: Control register, 4 bits per gpio (lower 8 GPIOs) * gpio n: 4 bits starting at (4*n) * 0000 = input, 0001 = output, others mean special-function * base + 0x04: Control register, 4 bits per gpio (up to 8 additions GPIOs) * gpio n: 4 bits starting at (4*n) * 0000 = input, 0001 = output, others mean special-function * base + 0x08: Data register, 1 bit per gpio * bit n: data bit n * * To allow us to use the samsung_gpiolib_get and samsung_gpiolib_set * routines we store the 'base + 0x4' address so that these routines see * the data register at ourchip->base + 0x04. */ static int samsung_gpiolib_4bit2_input(struct gpio_chip *chip, unsigned int offset) { struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); void __iomem *base = ourchip->base; void __iomem *regcon = base; unsigned long con; if (offset > 7) offset -= 8; else regcon -= 4; con = __raw_readl(regcon); con &= ~(0xf << con_4bit_shift(offset)); __raw_writel(con, regcon); pr_debug("%s: %p: CON %08lx\n", __func__, base, con); return 0; } static int samsung_gpiolib_4bit2_output(struct gpio_chip *chip, unsigned int offset, int value) { struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); void __iomem *base = ourchip->base; void __iomem *regcon = base; unsigned long con; unsigned long dat; unsigned con_offset = offset; if (con_offset > 7) con_offset -= 8; else regcon -= 4; con = __raw_readl(regcon); con &= ~(0xf << con_4bit_shift(con_offset)); con |= 0x1 << con_4bit_shift(con_offset); dat = __raw_readl(base + GPIODAT_OFF); if (value) dat |= 1 << offset; else dat &= ~(1 << offset); __raw_writel(dat, base + GPIODAT_OFF); __raw_writel(con, regcon); __raw_writel(dat, base + GPIODAT_OFF); pr_debug("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); return 0; } static void samsung_gpiolib_set(struct gpio_chip *chip, unsigned offset, int value) { struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); void __iomem *base = ourchip->base; unsigned long flags; unsigned long dat; samsung_gpio_lock(ourchip, flags); dat = __raw_readl(base + 0x04); dat &= ~(1 << offset); if (value) dat |= 1 << offset; __raw_writel(dat, base + 0x04); samsung_gpio_unlock(ourchip, flags); } static int samsung_gpiolib_get(struct gpio_chip *chip, unsigned offset) { struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); unsigned long val; val = __raw_readl(ourchip->base + 0x04); val >>= offset; val &= 1; return val; } /* * CONFIG_S3C_GPIO_TRACK enables the tracking of the s3c specific gpios * for use with the configuration calls, and other parts of the s3c gpiolib * support code. * * Not all s3c support code will need this, as some configurations of cpu * may only support one or two different configuration options and have an * easy gpio to samsung_gpio_chip mapping function. If this is the case, then * the machine support file should provide its own samsung_gpiolib_getchip() * and any other necessary functions. */ #ifdef CONFIG_S3C_GPIO_TRACK struct samsung_gpio_chip *s3c_gpios[S3C_GPIO_END]; static __init void s3c_gpiolib_track(struct samsung_gpio_chip *chip) { unsigned int gpn; int i; gpn = chip->chip.base; for (i = 0; i < chip->chip.ngpio; i++, gpn++) { BUG_ON(gpn >= ARRAY_SIZE(s3c_gpios)); s3c_gpios[gpn] = chip; } } #endif /* CONFIG_S3C_GPIO_TRACK */ /* * samsung_gpiolib_add() - add the Samsung gpio_chip. * @chip: The chip to register * * This is a wrapper to gpiochip_add() that takes our specific gpio chip * information and makes the necessary alterations for the platform and * notes the information for use with the configuration systems and any * other parts of the system. */ static void __init samsung_gpiolib_add(struct samsung_gpio_chip *chip) { struct gpio_chip *gc = &chip->chip; int ret; BUG_ON(!chip->base); BUG_ON(!gc->label); BUG_ON(!gc->ngpio); spin_lock_init(&chip->lock); if (!gc->direction_input) gc->direction_input = samsung_gpiolib_2bit_input; if (!gc->direction_output) gc->direction_output = samsung_gpiolib_2bit_output; if (!gc->set) gc->set = samsung_gpiolib_set; if (!gc->get) gc->get = samsung_gpiolib_get; #ifdef CONFIG_PM if (chip->pm != NULL) { if (!chip->pm->save || !chip->pm->resume) pr_err("gpio: %s has missing PM functions\n", gc->label); } else pr_err("gpio: %s has no PM function\n", gc->label); #endif /* gpiochip_add() prints own failure message on error. */ ret = gpiochip_add_data(gc, chip); if (ret >= 0) s3c_gpiolib_track(chip); } static void __init samsung_gpiolib_add_2bit_chips(struct samsung_gpio_chip *chip, int nr_chips, void __iomem *base, unsigned int offset) { int i; for (i = 0 ; i < nr_chips; i++, chip++) { chip->chip.direction_input = samsung_gpiolib_2bit_input; chip->chip.direction_output = samsung_gpiolib_2bit_output; if (!chip->config) chip->config = &samsung_gpio_cfgs[7]; if (!chip->pm) chip->pm = __gpio_pm(&samsung_gpio_pm_2bit); if ((base != NULL) && (chip->base == NULL)) chip->base = base + ((i) * offset); samsung_gpiolib_add(chip); } } /* * samsung_gpiolib_add_4bit_chips - 4bit single register GPIO config. * @chip: The gpio chip that is being configured. * @nr_chips: The no of chips (gpio ports) for the GPIO being configured. * * This helper deal with the GPIO cases where the control register has 4 bits * of control per GPIO, generally in the form of: * 0000 = Input * 0001 = Output * others = Special functions (dependent on bank) * * Note, since the code to deal with the case where there are two control * registers instead of one, we do not have a separate set of function * (samsung_gpiolib_add_4bit2_chips)for each case. */ static void __init samsung_gpiolib_add_4bit_chips(struct samsung_gpio_chip *chip, int nr_chips, void __iomem *base) { int i; for (i = 0 ; i < nr_chips; i++, chip++) { chip->chip.direction_input = samsung_gpiolib_4bit_input; chip->chip.direction_output = samsung_gpiolib_4bit_output; if (!chip->config) chip->config = &samsung_gpio_cfgs[2]; if (!chip->pm) chip->pm = __gpio_pm(&samsung_gpio_pm_4bit); if ((base != NULL) && (chip->base == NULL)) chip->base = base + ((i) * 0x20); chip->bitmap_gpio_int = 0; samsung_gpiolib_add(chip); } } static void __init samsung_gpiolib_add_4bit2_chips(struct samsung_gpio_chip *chip, int nr_chips) { for (; nr_chips > 0; nr_chips--, chip++) { chip->chip.direction_input = samsung_gpiolib_4bit2_input; chip->chip.direction_output = samsung_gpiolib_4bit2_output; if (!chip->config) chip->config = &samsung_gpio_cfgs[2]; if (!chip->pm) chip->pm = __gpio_pm(&samsung_gpio_pm_4bit); samsung_gpiolib_add(chip); } } int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset) { struct samsung_gpio_chip *samsung_chip = gpiochip_get_data(chip); return samsung_chip->irq_base + offset; } static int s3c64xx_gpiolib_mbank_to_irq(struct gpio_chip *chip, unsigned pin) { return pin < 5 ? IRQ_EINT(23) + pin : -ENXIO; } static int s3c64xx_gpiolib_lbank_to_irq(struct gpio_chip *chip, unsigned pin) { return pin >= 8 ? IRQ_EINT(16) + pin - 8 : -ENXIO; } /* * GPIO bank summary: * * Bank GPIOs Style SlpCon ExtInt Group * A 8 4Bit Yes 1 * B 7 4Bit Yes 1 * C 8 4Bit Yes 2 * D 5 4Bit Yes 3 * E 5 4Bit Yes None * F 16 2Bit Yes 4 [1] * G 7 4Bit Yes 5 * H 10 4Bit[2] Yes 6 * I 16 2Bit Yes None * J 12 2Bit Yes None * K 16 4Bit[2] No None * L 15 4Bit[2] No None * M 6 4Bit No IRQ_EINT * N 16 2Bit No IRQ_EINT * O 16 2Bit Yes 7 * P 15 2Bit Yes 8 * Q 9 2Bit Yes 9 * * [1] BANKF pins 14,15 do not form part of the external interrupt sources * [2] BANK has two control registers, GPxCON0 and GPxCON1 */ static struct samsung_gpio_chip s3c64xx_gpios_4bit[] = { { .chip = { .base = S3C64XX_GPA(0), .ngpio = S3C64XX_GPIO_A_NR, .label = "GPA", }, }, { .chip = { .base = S3C64XX_GPB(0), .ngpio = S3C64XX_GPIO_B_NR, .label = "GPB", }, }, { .chip = { .base = S3C64XX_GPC(0), .ngpio = S3C64XX_GPIO_C_NR, .label = "GPC", }, }, { .chip = { .base = S3C64XX_GPD(0), .ngpio = S3C64XX_GPIO_D_NR, .label = "GPD", }, }, { .config = &samsung_gpio_cfgs[0], .chip = { .base = S3C64XX_GPE(0), .ngpio = S3C64XX_GPIO_E_NR, .label = "GPE", }, }, { .base = S3C64XX_GPG_BASE, .chip = { .base = S3C64XX_GPG(0), .ngpio = S3C64XX_GPIO_G_NR, .label = "GPG", }, }, { .base = S3C64XX_GPM_BASE, .config = &samsung_gpio_cfgs[1], .chip = { .base = S3C64XX_GPM(0), .ngpio = S3C64XX_GPIO_M_NR, .label = "GPM", .to_irq = s3c64xx_gpiolib_mbank_to_irq, }, }, }; static struct samsung_gpio_chip s3c64xx_gpios_4bit2[] = { { .base = S3C64XX_GPH_BASE + 0x4, .chip = { .base = S3C64XX_GPH(0), .ngpio = S3C64XX_GPIO_H_NR, .label = "GPH", }, }, { .base = S3C64XX_GPK_BASE + 0x4, .config = &samsung_gpio_cfgs[0], .chip = { .base = S3C64XX_GPK(0), .ngpio = S3C64XX_GPIO_K_NR, .label = "GPK", }, }, { .base = S3C64XX_GPL_BASE + 0x4, .config = &samsung_gpio_cfgs[1], .chip = { .base = S3C64XX_GPL(0), .ngpio = S3C64XX_GPIO_L_NR, .label = "GPL", .to_irq = s3c64xx_gpiolib_lbank_to_irq, }, }, }; static struct samsung_gpio_chip s3c64xx_gpios_2bit[] = { { .base = S3C64XX_GPF_BASE, .config = &samsung_gpio_cfgs[6], .chip = { .base = S3C64XX_GPF(0), .ngpio = S3C64XX_GPIO_F_NR, .label = "GPF", }, }, { .config = &samsung_gpio_cfgs[7], .chip = { .base = S3C64XX_GPI(0), .ngpio = S3C64XX_GPIO_I_NR, .label = "GPI", }, }, { .config = &samsung_gpio_cfgs[7], .chip = { .base = S3C64XX_GPJ(0), .ngpio = S3C64XX_GPIO_J_NR, .label = "GPJ", }, }, { .config = &samsung_gpio_cfgs[6], .chip = { .base = S3C64XX_GPO(0), .ngpio = S3C64XX_GPIO_O_NR, .label = "GPO", }, }, { .config = &samsung_gpio_cfgs[6], .chip = { .base = S3C64XX_GPP(0), .ngpio = S3C64XX_GPIO_P_NR, .label = "GPP", }, }, { .config = &samsung_gpio_cfgs[6], .chip = { .base = S3C64XX_GPQ(0), .ngpio = S3C64XX_GPIO_Q_NR, .label = "GPQ", }, }, { .base = S3C64XX_GPN_BASE, .irq_base = IRQ_EINT(0), .config = &samsung_gpio_cfgs[5], .chip = { .base = S3C64XX_GPN(0), .ngpio = S3C64XX_GPIO_N_NR, .label = "GPN", .to_irq = samsung_gpiolib_to_irq, }, }, }; /* TODO: cleanup soc_is_* */ static __init int samsung_gpiolib_init(void) { /* * Currently there are two drivers that can provide GPIO support for * Samsung SoCs. For device tree enabled platforms, the new * pinctrl-samsung driver is used, providing both GPIO and pin control * interfaces. For legacy (non-DT) platforms this driver is used. */ if (of_have_populated_dt()) return 0; if (soc_is_s3c64xx()) { samsung_gpiolib_set_cfg(samsung_gpio_cfgs, ARRAY_SIZE(samsung_gpio_cfgs)); samsung_gpiolib_add_2bit_chips(s3c64xx_gpios_2bit, ARRAY_SIZE(s3c64xx_gpios_2bit), S3C64XX_VA_GPIO + 0xE0, 0x20); samsung_gpiolib_add_4bit_chips(s3c64xx_gpios_4bit, ARRAY_SIZE(s3c64xx_gpios_4bit), S3C64XX_VA_GPIO); samsung_gpiolib_add_4bit2_chips(s3c64xx_gpios_4bit2, ARRAY_SIZE(s3c64xx_gpios_4bit2)); } return 0; } core_initcall(samsung_gpiolib_init); int s3c_gpio_cfgpin(unsigned int pin, unsigned int config) { struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); unsigned long flags; int offset; int ret; if (!chip) return -EINVAL; offset = pin - chip->chip.base; samsung_gpio_lock(chip, flags); ret = samsung_gpio_do_setcfg(chip, offset, config); samsung_gpio_unlock(chip, flags); return ret; } EXPORT_SYMBOL(s3c_gpio_cfgpin); int s3c_gpio_cfgpin_range(unsigned int start, unsigned int nr, unsigned int cfg) { int ret; for (; nr > 0; nr--, start++) { ret = s3c_gpio_cfgpin(start, cfg); if (ret != 0) return ret; } return 0; } EXPORT_SYMBOL_GPL(s3c_gpio_cfgpin_range); int s3c_gpio_cfgall_range(unsigned int start, unsigned int nr, unsigned int cfg, samsung_gpio_pull_t pull) { int ret; for (; nr > 0; nr--, start++) { s3c_gpio_setpull(start, pull); ret = s3c_gpio_cfgpin(start, cfg); if (ret != 0) return ret; } return 0; } EXPORT_SYMBOL_GPL(s3c_gpio_cfgall_range); int s3c_gpio_setpull(unsigned int pin, samsung_gpio_pull_t pull) { struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); unsigned long flags; int offset, ret; if (!chip) return -EINVAL; offset = pin - chip->chip.base; samsung_gpio_lock(chip, flags); ret = samsung_gpio_do_setpull(chip, offset, pull); samsung_gpio_unlock(chip, flags); return ret; } EXPORT_SYMBOL(s3c_gpio_setpull); |