Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pinctrl: exynos: Handle suspend/resume of GPIO EINT registers

Some GPIO EINT control registers needs to be preserved across
suspend/resume cycle. This patch extends the driver to take care of
this.

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

authored by

Tomasz Figa and committed by
Linus Walleij
7ccbc60c 3385474c

+114 -3
+113 -3
drivers/pinctrl/pinctrl-exynos.c
··· 196 196 return IRQ_HANDLED; 197 197 } 198 198 199 + struct exynos_eint_gpio_save { 200 + u32 eint_con; 201 + u32 eint_fltcon0; 202 + u32 eint_fltcon1; 203 + }; 204 + 199 205 /* 200 206 * exynos_eint_gpio_init() - setup handling of external gpio interrupts. 201 207 * @d: driver data of samsung pinctrl driver. ··· 210 204 { 211 205 struct samsung_pin_bank *bank; 212 206 struct device *dev = d->dev; 213 - unsigned int ret; 214 - unsigned int i; 207 + int ret; 208 + int i; 215 209 216 210 if (!d->irq) { 217 211 dev_err(dev, "irq number not available\n"); ··· 233 227 bank->nr_pins, &exynos_gpio_irqd_ops, bank); 234 228 if (!bank->irq_domain) { 235 229 dev_err(dev, "gpio irq domain add failed\n"); 236 - return -ENXIO; 230 + ret = -ENXIO; 231 + goto err_domains; 232 + } 233 + 234 + bank->soc_priv = devm_kzalloc(d->dev, 235 + sizeof(struct exynos_eint_gpio_save), GFP_KERNEL); 236 + if (!bank->soc_priv) { 237 + irq_domain_remove(bank->irq_domain); 238 + ret = -ENOMEM; 239 + goto err_domains; 237 240 } 238 241 } 239 242 240 243 return 0; 244 + 245 + err_domains: 246 + for (--i, --bank; i >= 0; --i, --bank) { 247 + if (bank->eint_type != EINT_TYPE_GPIO) 248 + continue; 249 + irq_domain_remove(bank->irq_domain); 250 + } 251 + 252 + return ret; 241 253 } 242 254 243 255 static void exynos_wkup_irq_unmask(struct irq_data *irqd) ··· 552 528 return 0; 553 529 } 554 530 531 + static void exynos_pinctrl_suspend_bank( 532 + struct samsung_pinctrl_drv_data *drvdata, 533 + struct samsung_pin_bank *bank) 534 + { 535 + struct exynos_eint_gpio_save *save = bank->soc_priv; 536 + void __iomem *regs = drvdata->virt_base; 537 + 538 + save->eint_con = readl(regs + EXYNOS_GPIO_ECON_OFFSET 539 + + bank->eint_offset); 540 + save->eint_fltcon0 = readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET 541 + + 2 * bank->eint_offset); 542 + save->eint_fltcon1 = readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET 543 + + 2 * bank->eint_offset + 4); 544 + 545 + pr_debug("%s: save con %#010x\n", bank->name, save->eint_con); 546 + pr_debug("%s: save fltcon0 %#010x\n", bank->name, save->eint_fltcon0); 547 + pr_debug("%s: save fltcon1 %#010x\n", bank->name, save->eint_fltcon1); 548 + } 549 + 550 + static void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata) 551 + { 552 + struct samsung_pin_ctrl *ctrl = drvdata->ctrl; 553 + struct samsung_pin_bank *bank = ctrl->pin_banks; 554 + int i; 555 + 556 + for (i = 0; i < ctrl->nr_banks; ++i, ++bank) 557 + if (bank->eint_type == EINT_TYPE_GPIO) 558 + exynos_pinctrl_suspend_bank(drvdata, bank); 559 + } 560 + 561 + static void exynos_pinctrl_resume_bank( 562 + struct samsung_pinctrl_drv_data *drvdata, 563 + struct samsung_pin_bank *bank) 564 + { 565 + struct exynos_eint_gpio_save *save = bank->soc_priv; 566 + void __iomem *regs = drvdata->virt_base; 567 + 568 + pr_debug("%s: con %#010x => %#010x\n", bank->name, 569 + readl(regs + EXYNOS_GPIO_ECON_OFFSET 570 + + bank->eint_offset), save->eint_con); 571 + pr_debug("%s: fltcon0 %#010x => %#010x\n", bank->name, 572 + readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET 573 + + 2 * bank->eint_offset), save->eint_fltcon0); 574 + pr_debug("%s: fltcon1 %#010x => %#010x\n", bank->name, 575 + readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET 576 + + 2 * bank->eint_offset + 4), save->eint_fltcon1); 577 + 578 + writel(save->eint_con, regs + EXYNOS_GPIO_ECON_OFFSET 579 + + bank->eint_offset); 580 + writel(save->eint_fltcon0, regs + EXYNOS_GPIO_EFLTCON_OFFSET 581 + + 2 * bank->eint_offset); 582 + writel(save->eint_fltcon1, regs + EXYNOS_GPIO_EFLTCON_OFFSET 583 + + 2 * bank->eint_offset + 4); 584 + } 585 + 586 + static void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata) 587 + { 588 + struct samsung_pin_ctrl *ctrl = drvdata->ctrl; 589 + struct samsung_pin_bank *bank = ctrl->pin_banks; 590 + int i; 591 + 592 + for (i = 0; i < ctrl->nr_banks; ++i, ++bank) 593 + if (bank->eint_type == EINT_TYPE_GPIO) 594 + exynos_pinctrl_resume_bank(drvdata, bank); 595 + } 596 + 555 597 /* pin banks of exynos4210 pin-controller 0 */ 556 598 static struct samsung_pin_bank exynos4210_pin_banks0[] = { 557 599 EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), ··· 681 591 .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, 682 592 .svc = EXYNOS_SVC_OFFSET, 683 593 .eint_gpio_init = exynos_eint_gpio_init, 594 + .suspend = exynos_pinctrl_suspend, 595 + .resume = exynos_pinctrl_resume, 684 596 .label = "exynos4210-gpio-ctrl0", 685 597 }, { 686 598 /* pin-controller instance 1 data */ ··· 697 605 .svc = EXYNOS_SVC_OFFSET, 698 606 .eint_gpio_init = exynos_eint_gpio_init, 699 607 .eint_wkup_init = exynos_eint_wkup_init, 608 + .suspend = exynos_pinctrl_suspend, 609 + .resume = exynos_pinctrl_resume, 700 610 .label = "exynos4210-gpio-ctrl1", 701 611 }, { 702 612 /* pin-controller instance 2 data */ ··· 780 686 .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, 781 687 .svc = EXYNOS_SVC_OFFSET, 782 688 .eint_gpio_init = exynos_eint_gpio_init, 689 + .suspend = exynos_pinctrl_suspend, 690 + .resume = exynos_pinctrl_resume, 783 691 .label = "exynos4x12-gpio-ctrl0", 784 692 }, { 785 693 /* pin-controller instance 1 data */ ··· 796 700 .svc = EXYNOS_SVC_OFFSET, 797 701 .eint_gpio_init = exynos_eint_gpio_init, 798 702 .eint_wkup_init = exynos_eint_wkup_init, 703 + .suspend = exynos_pinctrl_suspend, 704 + .resume = exynos_pinctrl_resume, 799 705 .label = "exynos4x12-gpio-ctrl1", 800 706 }, { 801 707 /* pin-controller instance 2 data */ ··· 808 710 .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, 809 711 .svc = EXYNOS_SVC_OFFSET, 810 712 .eint_gpio_init = exynos_eint_gpio_init, 713 + .suspend = exynos_pinctrl_suspend, 714 + .resume = exynos_pinctrl_resume, 811 715 .label = "exynos4x12-gpio-ctrl2", 812 716 }, { 813 717 /* pin-controller instance 3 data */ ··· 820 720 .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, 821 721 .svc = EXYNOS_SVC_OFFSET, 822 722 .eint_gpio_init = exynos_eint_gpio_init, 723 + .suspend = exynos_pinctrl_suspend, 724 + .resume = exynos_pinctrl_resume, 823 725 .label = "exynos4x12-gpio-ctrl3", 824 726 }, 825 727 }; ··· 900 798 .svc = EXYNOS_SVC_OFFSET, 901 799 .eint_gpio_init = exynos_eint_gpio_init, 902 800 .eint_wkup_init = exynos_eint_wkup_init, 801 + .suspend = exynos_pinctrl_suspend, 802 + .resume = exynos_pinctrl_resume, 903 803 .label = "exynos5250-gpio-ctrl0", 904 804 }, { 905 805 /* pin-controller instance 1 data */ ··· 912 808 .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, 913 809 .svc = EXYNOS_SVC_OFFSET, 914 810 .eint_gpio_init = exynos_eint_gpio_init, 811 + .suspend = exynos_pinctrl_suspend, 812 + .resume = exynos_pinctrl_resume, 915 813 .label = "exynos5250-gpio-ctrl1", 916 814 }, { 917 815 /* pin-controller instance 2 data */ ··· 924 818 .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, 925 819 .svc = EXYNOS_SVC_OFFSET, 926 820 .eint_gpio_init = exynos_eint_gpio_init, 821 + .suspend = exynos_pinctrl_suspend, 822 + .resume = exynos_pinctrl_resume, 927 823 .label = "exynos5250-gpio-ctrl2", 928 824 }, { 929 825 /* pin-controller instance 3 data */ ··· 936 828 .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, 937 829 .svc = EXYNOS_SVC_OFFSET, 938 830 .eint_gpio_init = exynos_eint_gpio_init, 831 + .suspend = exynos_pinctrl_suspend, 832 + .resume = exynos_pinctrl_resume, 939 833 .label = "exynos5250-gpio-ctrl3", 940 834 }, 941 835 };
+1
drivers/pinctrl/pinctrl-exynos.h
··· 19 19 20 20 /* External GPIO and wakeup interrupt related definitions */ 21 21 #define EXYNOS_GPIO_ECON_OFFSET 0x700 22 + #define EXYNOS_GPIO_EFLTCON_OFFSET 0x800 22 23 #define EXYNOS_GPIO_EMASK_OFFSET 0x900 23 24 #define EXYNOS_GPIO_EPEND_OFFSET 0xA00 24 25 #define EXYNOS_WKUP_ECON_OFFSET 0xE00