aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomasz Figa <t.figa@samsung.com>2013-05-22 10:03:17 -0400
committerLinus Walleij <linus.walleij@linaro.org>2013-05-27 09:37:09 -0400
commit7ccbc60cd9c293304829662b043f4356f554fc3a (patch)
treea8ed13b34bff02a8824d85f1708de7808ee5a1ea
parent3385474c3a2f5e81df67cba426c29beefd8a5c18 (diff)
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>
-rw-r--r--drivers/pinctrl/pinctrl-exynos.c116
-rw-r--r--drivers/pinctrl/pinctrl-exynos.h1
2 files changed, 114 insertions, 3 deletions
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c
index 4f868e59227e..2d76f66a2e0b 100644
--- a/drivers/pinctrl/pinctrl-exynos.c
+++ b/drivers/pinctrl/pinctrl-exynos.c
@@ -196,6 +196,12 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data)
196 return IRQ_HANDLED; 196 return IRQ_HANDLED;
197} 197}
198 198
199struct exynos_eint_gpio_save {
200 u32 eint_con;
201 u32 eint_fltcon0;
202 u32 eint_fltcon1;
203};
204
199/* 205/*
200 * exynos_eint_gpio_init() - setup handling of external gpio interrupts. 206 * exynos_eint_gpio_init() - setup handling of external gpio interrupts.
201 * @d: driver data of samsung pinctrl driver. 207 * @d: driver data of samsung pinctrl driver.
@@ -204,8 +210,8 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
204{ 210{
205 struct samsung_pin_bank *bank; 211 struct samsung_pin_bank *bank;
206 struct device *dev = d->dev; 212 struct device *dev = d->dev;
207 unsigned int ret; 213 int ret;
208 unsigned int i; 214 int i;
209 215
210 if (!d->irq) { 216 if (!d->irq) {
211 dev_err(dev, "irq number not available\n"); 217 dev_err(dev, "irq number not available\n");
@@ -227,11 +233,29 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
227 bank->nr_pins, &exynos_gpio_irqd_ops, bank); 233 bank->nr_pins, &exynos_gpio_irqd_ops, bank);
228 if (!bank->irq_domain) { 234 if (!bank->irq_domain) {
229 dev_err(dev, "gpio irq domain add failed\n"); 235 dev_err(dev, "gpio irq domain add failed\n");
230 return -ENXIO; 236 ret = -ENXIO;
237 goto err_domains;
238 }
239
240 bank->soc_priv = devm_kzalloc(d->dev,
241 sizeof(struct exynos_eint_gpio_save), GFP_KERNEL);
242 if (!bank->soc_priv) {
243 irq_domain_remove(bank->irq_domain);
244 ret = -ENOMEM;
245 goto err_domains;
231 } 246 }
232 } 247 }
233 248
234 return 0; 249 return 0;
250
251err_domains:
252 for (--i, --bank; i >= 0; --i, --bank) {
253 if (bank->eint_type != EINT_TYPE_GPIO)
254 continue;
255 irq_domain_remove(bank->irq_domain);
256 }
257
258 return ret;
235} 259}
236 260
237static void exynos_wkup_irq_unmask(struct irq_data *irqd) 261static void exynos_wkup_irq_unmask(struct irq_data *irqd)
@@ -528,6 +552,72 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
528 return 0; 552 return 0;
529} 553}
530 554
555static void exynos_pinctrl_suspend_bank(
556 struct samsung_pinctrl_drv_data *drvdata,
557 struct samsung_pin_bank *bank)
558{
559 struct exynos_eint_gpio_save *save = bank->soc_priv;
560 void __iomem *regs = drvdata->virt_base;
561
562 save->eint_con = readl(regs + EXYNOS_GPIO_ECON_OFFSET
563 + bank->eint_offset);
564 save->eint_fltcon0 = readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
565 + 2 * bank->eint_offset);
566 save->eint_fltcon1 = readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
567 + 2 * bank->eint_offset + 4);
568
569 pr_debug("%s: save con %#010x\n", bank->name, save->eint_con);
570 pr_debug("%s: save fltcon0 %#010x\n", bank->name, save->eint_fltcon0);
571 pr_debug("%s: save fltcon1 %#010x\n", bank->name, save->eint_fltcon1);
572}
573
574static void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata)
575{
576 struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
577 struct samsung_pin_bank *bank = ctrl->pin_banks;
578 int i;
579
580 for (i = 0; i < ctrl->nr_banks; ++i, ++bank)
581 if (bank->eint_type == EINT_TYPE_GPIO)
582 exynos_pinctrl_suspend_bank(drvdata, bank);
583}
584
585static void exynos_pinctrl_resume_bank(
586 struct samsung_pinctrl_drv_data *drvdata,
587 struct samsung_pin_bank *bank)
588{
589 struct exynos_eint_gpio_save *save = bank->soc_priv;
590 void __iomem *regs = drvdata->virt_base;
591
592 pr_debug("%s: con %#010x => %#010x\n", bank->name,
593 readl(regs + EXYNOS_GPIO_ECON_OFFSET
594 + bank->eint_offset), save->eint_con);
595 pr_debug("%s: fltcon0 %#010x => %#010x\n", bank->name,
596 readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
597 + 2 * bank->eint_offset), save->eint_fltcon0);
598 pr_debug("%s: fltcon1 %#010x => %#010x\n", bank->name,
599 readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
600 + 2 * bank->eint_offset + 4), save->eint_fltcon1);
601
602 writel(save->eint_con, regs + EXYNOS_GPIO_ECON_OFFSET
603 + bank->eint_offset);
604 writel(save->eint_fltcon0, regs + EXYNOS_GPIO_EFLTCON_OFFSET
605 + 2 * bank->eint_offset);
606 writel(save->eint_fltcon1, regs + EXYNOS_GPIO_EFLTCON_OFFSET
607 + 2 * bank->eint_offset + 4);
608}
609
610static void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata)
611{
612 struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
613 struct samsung_pin_bank *bank = ctrl->pin_banks;
614 int i;
615
616 for (i = 0; i < ctrl->nr_banks; ++i, ++bank)
617 if (bank->eint_type == EINT_TYPE_GPIO)
618 exynos_pinctrl_resume_bank(drvdata, bank);
619}
620
531/* pin banks of exynos4210 pin-controller 0 */ 621/* pin banks of exynos4210 pin-controller 0 */
532static struct samsung_pin_bank exynos4210_pin_banks0[] = { 622static struct samsung_pin_bank exynos4210_pin_banks0[] = {
533 EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), 623 EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
@@ -591,6 +681,8 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = {
591 .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, 681 .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
592 .svc = EXYNOS_SVC_OFFSET, 682 .svc = EXYNOS_SVC_OFFSET,
593 .eint_gpio_init = exynos_eint_gpio_init, 683 .eint_gpio_init = exynos_eint_gpio_init,
684 .suspend = exynos_pinctrl_suspend,
685 .resume = exynos_pinctrl_resume,
594 .label = "exynos4210-gpio-ctrl0", 686 .label = "exynos4210-gpio-ctrl0",
595 }, { 687 }, {
596 /* pin-controller instance 1 data */ 688 /* pin-controller instance 1 data */
@@ -605,6 +697,8 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = {
605 .svc = EXYNOS_SVC_OFFSET, 697 .svc = EXYNOS_SVC_OFFSET,
606 .eint_gpio_init = exynos_eint_gpio_init, 698 .eint_gpio_init = exynos_eint_gpio_init,
607 .eint_wkup_init = exynos_eint_wkup_init, 699 .eint_wkup_init = exynos_eint_wkup_init,
700 .suspend = exynos_pinctrl_suspend,
701 .resume = exynos_pinctrl_resume,
608 .label = "exynos4210-gpio-ctrl1", 702 .label = "exynos4210-gpio-ctrl1",
609 }, { 703 }, {
610 /* pin-controller instance 2 data */ 704 /* pin-controller instance 2 data */
@@ -686,6 +780,8 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = {
686 .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, 780 .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
687 .svc = EXYNOS_SVC_OFFSET, 781 .svc = EXYNOS_SVC_OFFSET,
688 .eint_gpio_init = exynos_eint_gpio_init, 782 .eint_gpio_init = exynos_eint_gpio_init,
783 .suspend = exynos_pinctrl_suspend,
784 .resume = exynos_pinctrl_resume,
689 .label = "exynos4x12-gpio-ctrl0", 785 .label = "exynos4x12-gpio-ctrl0",
690 }, { 786 }, {
691 /* pin-controller instance 1 data */ 787 /* pin-controller instance 1 data */
@@ -700,6 +796,8 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = {
700 .svc = EXYNOS_SVC_OFFSET, 796 .svc = EXYNOS_SVC_OFFSET,
701 .eint_gpio_init = exynos_eint_gpio_init, 797 .eint_gpio_init = exynos_eint_gpio_init,
702 .eint_wkup_init = exynos_eint_wkup_init, 798 .eint_wkup_init = exynos_eint_wkup_init,
799 .suspend = exynos_pinctrl_suspend,
800 .resume = exynos_pinctrl_resume,
703 .label = "exynos4x12-gpio-ctrl1", 801 .label = "exynos4x12-gpio-ctrl1",
704 }, { 802 }, {
705 /* pin-controller instance 2 data */ 803 /* pin-controller instance 2 data */
@@ -710,6 +808,8 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = {
710 .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, 808 .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
711 .svc = EXYNOS_SVC_OFFSET, 809 .svc = EXYNOS_SVC_OFFSET,
712 .eint_gpio_init = exynos_eint_gpio_init, 810 .eint_gpio_init = exynos_eint_gpio_init,
811 .suspend = exynos_pinctrl_suspend,
812 .resume = exynos_pinctrl_resume,
713 .label = "exynos4x12-gpio-ctrl2", 813 .label = "exynos4x12-gpio-ctrl2",
714 }, { 814 }, {
715 /* pin-controller instance 3 data */ 815 /* pin-controller instance 3 data */
@@ -720,6 +820,8 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = {
720 .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, 820 .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
721 .svc = EXYNOS_SVC_OFFSET, 821 .svc = EXYNOS_SVC_OFFSET,
722 .eint_gpio_init = exynos_eint_gpio_init, 822 .eint_gpio_init = exynos_eint_gpio_init,
823 .suspend = exynos_pinctrl_suspend,
824 .resume = exynos_pinctrl_resume,
723 .label = "exynos4x12-gpio-ctrl3", 825 .label = "exynos4x12-gpio-ctrl3",
724 }, 826 },
725}; 827};
@@ -798,6 +900,8 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
798 .svc = EXYNOS_SVC_OFFSET, 900 .svc = EXYNOS_SVC_OFFSET,
799 .eint_gpio_init = exynos_eint_gpio_init, 901 .eint_gpio_init = exynos_eint_gpio_init,
800 .eint_wkup_init = exynos_eint_wkup_init, 902 .eint_wkup_init = exynos_eint_wkup_init,
903 .suspend = exynos_pinctrl_suspend,
904 .resume = exynos_pinctrl_resume,
801 .label = "exynos5250-gpio-ctrl0", 905 .label = "exynos5250-gpio-ctrl0",
802 }, { 906 }, {
803 /* pin-controller instance 1 data */ 907 /* pin-controller instance 1 data */
@@ -808,6 +912,8 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
808 .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, 912 .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
809 .svc = EXYNOS_SVC_OFFSET, 913 .svc = EXYNOS_SVC_OFFSET,
810 .eint_gpio_init = exynos_eint_gpio_init, 914 .eint_gpio_init = exynos_eint_gpio_init,
915 .suspend = exynos_pinctrl_suspend,
916 .resume = exynos_pinctrl_resume,
811 .label = "exynos5250-gpio-ctrl1", 917 .label = "exynos5250-gpio-ctrl1",
812 }, { 918 }, {
813 /* pin-controller instance 2 data */ 919 /* pin-controller instance 2 data */
@@ -818,6 +924,8 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
818 .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, 924 .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
819 .svc = EXYNOS_SVC_OFFSET, 925 .svc = EXYNOS_SVC_OFFSET,
820 .eint_gpio_init = exynos_eint_gpio_init, 926 .eint_gpio_init = exynos_eint_gpio_init,
927 .suspend = exynos_pinctrl_suspend,
928 .resume = exynos_pinctrl_resume,
821 .label = "exynos5250-gpio-ctrl2", 929 .label = "exynos5250-gpio-ctrl2",
822 }, { 930 }, {
823 /* pin-controller instance 3 data */ 931 /* pin-controller instance 3 data */
@@ -828,6 +936,8 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
828 .geint_pend = EXYNOS_GPIO_EPEND_OFFSET, 936 .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
829 .svc = EXYNOS_SVC_OFFSET, 937 .svc = EXYNOS_SVC_OFFSET,
830 .eint_gpio_init = exynos_eint_gpio_init, 938 .eint_gpio_init = exynos_eint_gpio_init,
939 .suspend = exynos_pinctrl_suspend,
940 .resume = exynos_pinctrl_resume,
831 .label = "exynos5250-gpio-ctrl3", 941 .label = "exynos5250-gpio-ctrl3",
832 }, 942 },
833}; 943};
diff --git a/drivers/pinctrl/pinctrl-exynos.h b/drivers/pinctrl/pinctrl-exynos.h
index 9b1f77a5bf0f..3c91c357792f 100644
--- a/drivers/pinctrl/pinctrl-exynos.h
+++ b/drivers/pinctrl/pinctrl-exynos.h
@@ -19,6 +19,7 @@
19 19
20/* External GPIO and wakeup interrupt related definitions */ 20/* External GPIO and wakeup interrupt related definitions */
21#define EXYNOS_GPIO_ECON_OFFSET 0x700 21#define EXYNOS_GPIO_ECON_OFFSET 0x700
22#define EXYNOS_GPIO_EFLTCON_OFFSET 0x800
22#define EXYNOS_GPIO_EMASK_OFFSET 0x900 23#define EXYNOS_GPIO_EMASK_OFFSET 0x900
23#define EXYNOS_GPIO_EPEND_OFFSET 0xA00 24#define EXYNOS_GPIO_EPEND_OFFSET 0xA00
24#define EXYNOS_WKUP_ECON_OFFSET 0xE00 25#define EXYNOS_WKUP_ECON_OFFSET 0xE00