aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-nomadik
diff options
context:
space:
mode:
authorRabin Vincent <rabin.vincent@stericsson.com>2011-02-10 01:15:58 -0500
committerLinus Walleij <linus.walleij@linaro.org>2011-03-14 09:05:17 -0400
commitb9df468d8630c583e3597e24ad8cc4c0318790c1 (patch)
tree2abfac8c7aa590a874eb49d6dd83036847a269f2 /arch/arm/plat-nomadik
parent96cb164bdec6f91eadf09a858c4820701f791b37 (diff)
plat-nomadik: make GPIO interrupts work with cpuidle ApSleep
Enable wakeups by default for any GPIO interrupts and in the suspend/resume path narrow this down to only the the real wakeup interrupts. This approach is based on the assumption that cpuidle ApSleep will be entered more often than system suspend. Signed-off-by: Rabin Vincent <rabin.vincent@stericsson.com> Reviewed-by: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> [Fixup for genirq changes to struct irq_data on 2.6.38] Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'arch/arm/plat-nomadik')
-rw-r--r--arch/arm/plat-nomadik/gpio.c114
-rw-r--r--arch/arm/plat-nomadik/include/plat/gpio.h3
2 files changed, 100 insertions, 17 deletions
diff --git a/arch/arm/plat-nomadik/gpio.c b/arch/arm/plat-nomadik/gpio.c
index 45b1cf95e378..70620426ee55 100644
--- a/arch/arm/plat-nomadik/gpio.c
+++ b/arch/arm/plat-nomadik/gpio.c
@@ -50,6 +50,10 @@ struct nmk_gpio_chip {
50 /* Keep track of configured edges */ 50 /* Keep track of configured edges */
51 u32 edge_rising; 51 u32 edge_rising;
52 u32 edge_falling; 52 u32 edge_falling;
53 u32 real_wake;
54 u32 rwimsc;
55 u32 fwimsc;
56 u32 slpm;
53}; 57};
54 58
55static struct nmk_gpio_chip * 59static struct nmk_gpio_chip *
@@ -534,8 +538,20 @@ static void __nmk_gpio_irq_modify(struct nmk_gpio_chip *nmk_chip,
534 } 538 }
535} 539}
536 540
537static int nmk_gpio_irq_modify(struct irq_data *d, enum nmk_gpio_irq_type which, 541static void __nmk_gpio_set_wake(struct nmk_gpio_chip *nmk_chip,
538 bool enable) 542 int gpio, bool on)
543{
544#ifdef CONFIG_ARCH_U8500
545 if (cpu_is_u8500v2()) {
546 __nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base,
547 on ? NMK_GPIO_SLPM_WAKEUP_ENABLE
548 : NMK_GPIO_SLPM_WAKEUP_DISABLE);
549 }
550#endif
551 __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, on);
552}
553
554static int nmk_gpio_irq_maskunmask(struct irq_data *d, bool enable)
539{ 555{
540 int gpio; 556 int gpio;
541 struct nmk_gpio_chip *nmk_chip; 557 struct nmk_gpio_chip *nmk_chip;
@@ -548,45 +564,55 @@ static int nmk_gpio_irq_modify(struct irq_data *d, enum nmk_gpio_irq_type which,
548 if (!nmk_chip) 564 if (!nmk_chip)
549 return -EINVAL; 565 return -EINVAL;
550 566
551 spin_lock_irqsave(&nmk_chip->lock, flags); 567 spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
552 __nmk_gpio_irq_modify(nmk_chip, gpio, which, enable); 568 spin_lock(&nmk_chip->lock);
553 spin_unlock_irqrestore(&nmk_chip->lock, flags); 569
570 __nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, enable);
571
572 if (!(nmk_chip->real_wake & bitmask))
573 __nmk_gpio_set_wake(nmk_chip, gpio, enable);
574
575 spin_unlock(&nmk_chip->lock);
576 spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
554 577
555 return 0; 578 return 0;
556} 579}
557 580
558static void nmk_gpio_irq_mask(struct irq_data *d) 581static void nmk_gpio_irq_mask(struct irq_data *d)
559{ 582{
560 nmk_gpio_irq_modify(d, NORMAL, false); 583 nmk_gpio_irq_maskunmask(d, false);
561} 584}
562 585
563static void nmk_gpio_irq_unmask(struct irq_data *d) 586static void nmk_gpio_irq_unmask(struct irq_data *d)
564{ 587{
565 nmk_gpio_irq_modify(d, NORMAL, true); 588 nmk_gpio_irq_maskunmask(d, true);
566} 589}
567 590
568static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on) 591static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
569{ 592{
593 struct irq_desc *desc = irq_to_desc(d->irq);
594 bool enabled = !(desc->status & IRQ_DISABLED);
570 struct nmk_gpio_chip *nmk_chip; 595 struct nmk_gpio_chip *nmk_chip;
571 unsigned long flags; 596 unsigned long flags;
597 u32 bitmask;
572 int gpio; 598 int gpio;
573 599
574 gpio = NOMADIK_IRQ_TO_GPIO(d->irq); 600 gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
575 nmk_chip = irq_data_get_irq_chip_data(d); 601 nmk_chip = irq_data_get_irq_chip_data(d);
576 if (!nmk_chip) 602 if (!nmk_chip)
577 return -EINVAL; 603 return -EINVAL;
604 bitmask = nmk_gpio_get_bitmask(gpio);
578 605
579 spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); 606 spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
580 spin_lock(&nmk_chip->lock); 607 spin_lock(&nmk_chip->lock);
581 608
582#ifdef CONFIG_ARCH_U8500 609 if (!enabled)
583 if (cpu_is_u8500v2()) { 610 __nmk_gpio_set_wake(nmk_chip, gpio, on);
584 __nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base, 611
585 on ? NMK_GPIO_SLPM_WAKEUP_ENABLE 612 if (on)
586 : NMK_GPIO_SLPM_WAKEUP_DISABLE); 613 nmk_chip->real_wake |= bitmask;
587 } 614 else
588#endif 615 nmk_chip->real_wake &= ~bitmask;
589 __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, on);
590 616
591 spin_unlock(&nmk_chip->lock); 617 spin_unlock(&nmk_chip->lock);
592 spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags); 618 spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
@@ -620,7 +646,7 @@ static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type)
620 if (enabled) 646 if (enabled)
621 __nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, false); 647 __nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, false);
622 648
623 if (wake) 649 if (enabled || wake)
624 __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, false); 650 __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, false);
625 651
626 nmk_chip->edge_rising &= ~bitmask; 652 nmk_chip->edge_rising &= ~bitmask;
@@ -634,7 +660,7 @@ static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type)
634 if (enabled) 660 if (enabled)
635 __nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, true); 661 __nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, true);
636 662
637 if (wake) 663 if (enabled || wake)
638 __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, true); 664 __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, true);
639 665
640 spin_unlock_irqrestore(&nmk_chip->lock, flags); 666 spin_unlock_irqrestore(&nmk_chip->lock, flags);
@@ -870,6 +896,60 @@ static struct gpio_chip nmk_gpio_template = {
870 .can_sleep = 0, 896 .can_sleep = 0,
871}; 897};
872 898
899/*
900 * Called from the suspend/resume path to only keep the real wakeup interrupts
901 * (those that have had set_irq_wake() called on them) as wakeup interrupts,
902 * and not the rest of the interrupts which we needed to have as wakeups for
903 * cpuidle.
904 *
905 * PM ops are not used since this needs to be done at the end, after all the
906 * other drivers are done with their suspend callbacks.
907 */
908void nmk_gpio_wakeups_suspend(void)
909{
910 int i;
911
912 for (i = 0; i < NUM_BANKS; i++) {
913 struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
914
915 if (!chip)
916 break;
917
918 chip->rwimsc = readl(chip->addr + NMK_GPIO_RWIMSC);
919 chip->fwimsc = readl(chip->addr + NMK_GPIO_FWIMSC);
920
921 writel(chip->rwimsc & chip->real_wake,
922 chip->addr + NMK_GPIO_RWIMSC);
923 writel(chip->fwimsc & chip->real_wake,
924 chip->addr + NMK_GPIO_FWIMSC);
925
926 if (cpu_is_u8500v2()) {
927 chip->slpm = readl(chip->addr + NMK_GPIO_SLPC);
928
929 /* 0 -> wakeup enable */
930 writel(~chip->real_wake, chip->addr + NMK_GPIO_SLPC);
931 }
932 }
933}
934
935void nmk_gpio_wakeups_resume(void)
936{
937 int i;
938
939 for (i = 0; i < NUM_BANKS; i++) {
940 struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
941
942 if (!chip)
943 break;
944
945 writel(chip->rwimsc, chip->addr + NMK_GPIO_RWIMSC);
946 writel(chip->fwimsc, chip->addr + NMK_GPIO_FWIMSC);
947
948 if (cpu_is_u8500v2())
949 writel(chip->slpm, chip->addr + NMK_GPIO_SLPC);
950 }
951}
952
873static int __devinit nmk_gpio_probe(struct platform_device *dev) 953static int __devinit nmk_gpio_probe(struct platform_device *dev)
874{ 954{
875 struct nmk_gpio_platform_data *pdata = dev->dev.platform_data; 955 struct nmk_gpio_platform_data *pdata = dev->dev.platform_data;
diff --git a/arch/arm/plat-nomadik/include/plat/gpio.h b/arch/arm/plat-nomadik/include/plat/gpio.h
index e3a4837e86f4..1b9f6f0843d1 100644
--- a/arch/arm/plat-nomadik/include/plat/gpio.h
+++ b/arch/arm/plat-nomadik/include/plat/gpio.h
@@ -75,6 +75,9 @@ extern int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull);
75extern int nmk_gpio_set_mode(int gpio, int gpio_mode); 75extern int nmk_gpio_set_mode(int gpio, int gpio_mode);
76extern int nmk_gpio_get_mode(int gpio); 76extern int nmk_gpio_get_mode(int gpio);
77 77
78extern void nmk_gpio_wakeups_suspend(void);
79extern void nmk_gpio_wakeups_resume(void);
80
78/* 81/*
79 * Platform data to register a block: only the initial gpio/irq number. 82 * Platform data to register a block: only the initial gpio/irq number.
80 */ 83 */