diff options
Diffstat (limited to 'drivers/gpio/gpio-brcmstb.c')
-rw-r--r-- | drivers/gpio/gpio-brcmstb.c | 201 |
1 files changed, 151 insertions, 50 deletions
diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c index 9a8c603625a3..545d43a587b7 100644 --- a/drivers/gpio/gpio-brcmstb.c +++ b/drivers/gpio/gpio-brcmstb.c | |||
@@ -19,18 +19,30 @@ | |||
19 | #include <linux/irqdomain.h> | 19 | #include <linux/irqdomain.h> |
20 | #include <linux/irqchip/chained_irq.h> | 20 | #include <linux/irqchip/chained_irq.h> |
21 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
22 | #include <linux/reboot.h> | ||
23 | #include <linux/bitops.h> | 22 | #include <linux/bitops.h> |
24 | 23 | ||
25 | #define GIO_BANK_SIZE 0x20 | 24 | enum gio_reg_index { |
26 | #define GIO_ODEN(bank) (((bank) * GIO_BANK_SIZE) + 0x00) | 25 | GIO_REG_ODEN = 0, |
27 | #define GIO_DATA(bank) (((bank) * GIO_BANK_SIZE) + 0x04) | 26 | GIO_REG_DATA, |
28 | #define GIO_IODIR(bank) (((bank) * GIO_BANK_SIZE) + 0x08) | 27 | GIO_REG_IODIR, |
29 | #define GIO_EC(bank) (((bank) * GIO_BANK_SIZE) + 0x0c) | 28 | GIO_REG_EC, |
30 | #define GIO_EI(bank) (((bank) * GIO_BANK_SIZE) + 0x10) | 29 | GIO_REG_EI, |
31 | #define GIO_MASK(bank) (((bank) * GIO_BANK_SIZE) + 0x14) | 30 | GIO_REG_MASK, |
32 | #define GIO_LEVEL(bank) (((bank) * GIO_BANK_SIZE) + 0x18) | 31 | GIO_REG_LEVEL, |
33 | #define GIO_STAT(bank) (((bank) * GIO_BANK_SIZE) + 0x1c) | 32 | GIO_REG_STAT, |
33 | NUMBER_OF_GIO_REGISTERS | ||
34 | }; | ||
35 | |||
36 | #define GIO_BANK_SIZE (NUMBER_OF_GIO_REGISTERS * sizeof(u32)) | ||
37 | #define GIO_BANK_OFF(bank, off) (((bank) * GIO_BANK_SIZE) + (off * sizeof(u32))) | ||
38 | #define GIO_ODEN(bank) GIO_BANK_OFF(bank, GIO_REG_ODEN) | ||
39 | #define GIO_DATA(bank) GIO_BANK_OFF(bank, GIO_REG_DATA) | ||
40 | #define GIO_IODIR(bank) GIO_BANK_OFF(bank, GIO_REG_IODIR) | ||
41 | #define GIO_EC(bank) GIO_BANK_OFF(bank, GIO_REG_EC) | ||
42 | #define GIO_EI(bank) GIO_BANK_OFF(bank, GIO_REG_EI) | ||
43 | #define GIO_MASK(bank) GIO_BANK_OFF(bank, GIO_REG_MASK) | ||
44 | #define GIO_LEVEL(bank) GIO_BANK_OFF(bank, GIO_REG_LEVEL) | ||
45 | #define GIO_STAT(bank) GIO_BANK_OFF(bank, GIO_REG_STAT) | ||
34 | 46 | ||
35 | struct brcmstb_gpio_bank { | 47 | struct brcmstb_gpio_bank { |
36 | struct list_head node; | 48 | struct list_head node; |
@@ -38,6 +50,8 @@ struct brcmstb_gpio_bank { | |||
38 | struct gpio_chip gc; | 50 | struct gpio_chip gc; |
39 | struct brcmstb_gpio_priv *parent_priv; | 51 | struct brcmstb_gpio_priv *parent_priv; |
40 | u32 width; | 52 | u32 width; |
53 | u32 wake_active; | ||
54 | u32 saved_regs[GIO_REG_STAT]; /* Don't save and restore GIO_REG_STAT */ | ||
41 | }; | 55 | }; |
42 | 56 | ||
43 | struct brcmstb_gpio_priv { | 57 | struct brcmstb_gpio_priv { |
@@ -50,7 +64,6 @@ struct brcmstb_gpio_priv { | |||
50 | int gpio_base; | 64 | int gpio_base; |
51 | int num_gpios; | 65 | int num_gpios; |
52 | int parent_wake_irq; | 66 | int parent_wake_irq; |
53 | struct notifier_block reboot_notifier; | ||
54 | }; | 67 | }; |
55 | 68 | ||
56 | #define MAX_GPIO_PER_BANK 32 | 69 | #define MAX_GPIO_PER_BANK 32 |
@@ -66,15 +79,22 @@ brcmstb_gpio_gc_to_priv(struct gpio_chip *gc) | |||
66 | } | 79 | } |
67 | 80 | ||
68 | static unsigned long | 81 | static unsigned long |
69 | brcmstb_gpio_get_active_irqs(struct brcmstb_gpio_bank *bank) | 82 | __brcmstb_gpio_get_active_irqs(struct brcmstb_gpio_bank *bank) |
70 | { | 83 | { |
71 | void __iomem *reg_base = bank->parent_priv->reg_base; | 84 | void __iomem *reg_base = bank->parent_priv->reg_base; |
85 | |||
86 | return bank->gc.read_reg(reg_base + GIO_STAT(bank->id)) & | ||
87 | bank->gc.read_reg(reg_base + GIO_MASK(bank->id)); | ||
88 | } | ||
89 | |||
90 | static unsigned long | ||
91 | brcmstb_gpio_get_active_irqs(struct brcmstb_gpio_bank *bank) | ||
92 | { | ||
72 | unsigned long status; | 93 | unsigned long status; |
73 | unsigned long flags; | 94 | unsigned long flags; |
74 | 95 | ||
75 | spin_lock_irqsave(&bank->gc.bgpio_lock, flags); | 96 | spin_lock_irqsave(&bank->gc.bgpio_lock, flags); |
76 | status = bank->gc.read_reg(reg_base + GIO_STAT(bank->id)) & | 97 | status = __brcmstb_gpio_get_active_irqs(bank); |
77 | bank->gc.read_reg(reg_base + GIO_MASK(bank->id)); | ||
78 | spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags); | 98 | spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags); |
79 | 99 | ||
80 | return status; | 100 | return status; |
@@ -210,11 +230,6 @@ static int brcmstb_gpio_priv_set_wake(struct brcmstb_gpio_priv *priv, | |||
210 | { | 230 | { |
211 | int ret = 0; | 231 | int ret = 0; |
212 | 232 | ||
213 | /* | ||
214 | * Only enable wake IRQ once for however many hwirqs can wake | ||
215 | * since they all use the same wake IRQ. Mask will be set | ||
216 | * up appropriately thanks to IRQCHIP_MASK_ON_SUSPEND flag. | ||
217 | */ | ||
218 | if (enable) | 233 | if (enable) |
219 | ret = enable_irq_wake(priv->parent_wake_irq); | 234 | ret = enable_irq_wake(priv->parent_wake_irq); |
220 | else | 235 | else |
@@ -228,7 +243,18 @@ static int brcmstb_gpio_priv_set_wake(struct brcmstb_gpio_priv *priv, | |||
228 | static int brcmstb_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) | 243 | static int brcmstb_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) |
229 | { | 244 | { |
230 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | 245 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
231 | struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc); | 246 | struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc); |
247 | struct brcmstb_gpio_priv *priv = bank->parent_priv; | ||
248 | u32 mask = BIT(brcmstb_gpio_hwirq_to_offset(d->hwirq, bank)); | ||
249 | |||
250 | /* | ||
251 | * Do not do anything specific for now, suspend/resume callbacks will | ||
252 | * configure the interrupt mask appropriately | ||
253 | */ | ||
254 | if (enable) | ||
255 | bank->wake_active |= mask; | ||
256 | else | ||
257 | bank->wake_active &= ~mask; | ||
232 | 258 | ||
233 | return brcmstb_gpio_priv_set_wake(priv, enable); | 259 | return brcmstb_gpio_priv_set_wake(priv, enable); |
234 | } | 260 | } |
@@ -239,7 +265,8 @@ static irqreturn_t brcmstb_gpio_wake_irq_handler(int irq, void *data) | |||
239 | 265 | ||
240 | if (!priv || irq != priv->parent_wake_irq) | 266 | if (!priv || irq != priv->parent_wake_irq) |
241 | return IRQ_NONE; | 267 | return IRQ_NONE; |
242 | pm_wakeup_event(&priv->pdev->dev, 0); | 268 | |
269 | /* Nothing to do */ | ||
243 | return IRQ_HANDLED; | 270 | return IRQ_HANDLED; |
244 | } | 271 | } |
245 | 272 | ||
@@ -280,19 +307,6 @@ static void brcmstb_gpio_irq_handler(struct irq_desc *desc) | |||
280 | chained_irq_exit(chip, desc); | 307 | chained_irq_exit(chip, desc); |
281 | } | 308 | } |
282 | 309 | ||
283 | static int brcmstb_gpio_reboot(struct notifier_block *nb, | ||
284 | unsigned long action, void *data) | ||
285 | { | ||
286 | struct brcmstb_gpio_priv *priv = | ||
287 | container_of(nb, struct brcmstb_gpio_priv, reboot_notifier); | ||
288 | |||
289 | /* Enable GPIO for S5 cold boot */ | ||
290 | if (action == SYS_POWER_OFF) | ||
291 | brcmstb_gpio_priv_set_wake(priv, 1); | ||
292 | |||
293 | return NOTIFY_DONE; | ||
294 | } | ||
295 | |||
296 | static struct brcmstb_gpio_bank *brcmstb_gpio_hwirq_to_bank( | 310 | static struct brcmstb_gpio_bank *brcmstb_gpio_hwirq_to_bank( |
297 | struct brcmstb_gpio_priv *priv, irq_hw_number_t hwirq) | 311 | struct brcmstb_gpio_priv *priv, irq_hw_number_t hwirq) |
298 | { | 312 | { |
@@ -397,12 +411,6 @@ static int brcmstb_gpio_remove(struct platform_device *pdev) | |||
397 | list_for_each_entry(bank, &priv->bank_list, node) | 411 | list_for_each_entry(bank, &priv->bank_list, node) |
398 | gpiochip_remove(&bank->gc); | 412 | gpiochip_remove(&bank->gc); |
399 | 413 | ||
400 | if (priv->reboot_notifier.notifier_call) { | ||
401 | ret = unregister_reboot_notifier(&priv->reboot_notifier); | ||
402 | if (ret) | ||
403 | dev_err(&pdev->dev, | ||
404 | "failed to unregister reboot notifier\n"); | ||
405 | } | ||
406 | return ret; | 414 | return ret; |
407 | } | 415 | } |
408 | 416 | ||
@@ -462,9 +470,8 @@ static int brcmstb_gpio_irq_setup(struct platform_device *pdev, | |||
462 | "Couldn't get wake IRQ - GPIOs will not be able to wake from sleep"); | 470 | "Couldn't get wake IRQ - GPIOs will not be able to wake from sleep"); |
463 | } else { | 471 | } else { |
464 | /* | 472 | /* |
465 | * Set wakeup capability before requesting wakeup | 473 | * Set wakeup capability so we can process boot-time |
466 | * interrupt, so we can process boot-time "wakeups" | 474 | * "wakeups" (e.g., from S5 cold boot) |
467 | * (e.g., from S5 cold boot) | ||
468 | */ | 475 | */ |
469 | device_set_wakeup_capable(dev, true); | 476 | device_set_wakeup_capable(dev, true); |
470 | device_wakeup_enable(dev); | 477 | device_wakeup_enable(dev); |
@@ -477,10 +484,6 @@ static int brcmstb_gpio_irq_setup(struct platform_device *pdev, | |||
477 | dev_err(dev, "Couldn't request wake IRQ"); | 484 | dev_err(dev, "Couldn't request wake IRQ"); |
478 | goto out_free_domain; | 485 | goto out_free_domain; |
479 | } | 486 | } |
480 | |||
481 | priv->reboot_notifier.notifier_call = | ||
482 | brcmstb_gpio_reboot; | ||
483 | register_reboot_notifier(&priv->reboot_notifier); | ||
484 | } | 487 | } |
485 | } | 488 | } |
486 | 489 | ||
@@ -491,14 +494,12 @@ static int brcmstb_gpio_irq_setup(struct platform_device *pdev, | |||
491 | priv->irq_chip.irq_ack = brcmstb_gpio_irq_ack; | 494 | priv->irq_chip.irq_ack = brcmstb_gpio_irq_ack; |
492 | priv->irq_chip.irq_set_type = brcmstb_gpio_irq_set_type; | 495 | priv->irq_chip.irq_set_type = brcmstb_gpio_irq_set_type; |
493 | 496 | ||
494 | /* Ensures that all non-wakeup IRQs are disabled at suspend */ | ||
495 | priv->irq_chip.flags = IRQCHIP_MASK_ON_SUSPEND; | ||
496 | |||
497 | if (priv->parent_wake_irq) | 497 | if (priv->parent_wake_irq) |
498 | priv->irq_chip.irq_set_wake = brcmstb_gpio_irq_set_wake; | 498 | priv->irq_chip.irq_set_wake = brcmstb_gpio_irq_set_wake; |
499 | 499 | ||
500 | irq_set_chained_handler_and_data(priv->parent_irq, | 500 | irq_set_chained_handler_and_data(priv->parent_irq, |
501 | brcmstb_gpio_irq_handler, priv); | 501 | brcmstb_gpio_irq_handler, priv); |
502 | irq_set_status_flags(priv->parent_irq, IRQ_DISABLE_UNLAZY); | ||
502 | 503 | ||
503 | return 0; | 504 | return 0; |
504 | 505 | ||
@@ -508,6 +509,99 @@ out_free_domain: | |||
508 | return err; | 509 | return err; |
509 | } | 510 | } |
510 | 511 | ||
512 | static void brcmstb_gpio_bank_save(struct brcmstb_gpio_priv *priv, | ||
513 | struct brcmstb_gpio_bank *bank) | ||
514 | { | ||
515 | struct gpio_chip *gc = &bank->gc; | ||
516 | unsigned int i; | ||
517 | |||
518 | for (i = 0; i < GIO_REG_STAT; i++) | ||
519 | bank->saved_regs[i] = gc->read_reg(priv->reg_base + | ||
520 | GIO_BANK_OFF(bank->id, i)); | ||
521 | } | ||
522 | |||
523 | static void brcmstb_gpio_quiesce(struct device *dev, bool save) | ||
524 | { | ||
525 | struct brcmstb_gpio_priv *priv = dev_get_drvdata(dev); | ||
526 | struct brcmstb_gpio_bank *bank; | ||
527 | struct gpio_chip *gc; | ||
528 | u32 imask; | ||
529 | |||
530 | /* disable non-wake interrupt */ | ||
531 | if (priv->parent_irq >= 0) | ||
532 | disable_irq(priv->parent_irq); | ||
533 | |||
534 | list_for_each_entry(bank, &priv->bank_list, node) { | ||
535 | gc = &bank->gc; | ||
536 | |||
537 | if (save) | ||
538 | brcmstb_gpio_bank_save(priv, bank); | ||
539 | |||
540 | /* Unmask GPIOs which have been flagged as wake-up sources */ | ||
541 | if (priv->parent_wake_irq) | ||
542 | imask = bank->wake_active; | ||
543 | else | ||
544 | imask = 0; | ||
545 | gc->write_reg(priv->reg_base + GIO_MASK(bank->id), | ||
546 | imask); | ||
547 | } | ||
548 | } | ||
549 | |||
550 | static void brcmstb_gpio_shutdown(struct platform_device *pdev) | ||
551 | { | ||
552 | /* Enable GPIO for S5 cold boot */ | ||
553 | brcmstb_gpio_quiesce(&pdev->dev, false); | ||
554 | } | ||
555 | |||
556 | #ifdef CONFIG_PM_SLEEP | ||
557 | static void brcmstb_gpio_bank_restore(struct brcmstb_gpio_priv *priv, | ||
558 | struct brcmstb_gpio_bank *bank) | ||
559 | { | ||
560 | struct gpio_chip *gc = &bank->gc; | ||
561 | unsigned int i; | ||
562 | |||
563 | for (i = 0; i < GIO_REG_STAT; i++) | ||
564 | gc->write_reg(priv->reg_base + GIO_BANK_OFF(bank->id, i), | ||
565 | bank->saved_regs[i]); | ||
566 | } | ||
567 | |||
568 | static int brcmstb_gpio_suspend(struct device *dev) | ||
569 | { | ||
570 | brcmstb_gpio_quiesce(dev, true); | ||
571 | return 0; | ||
572 | } | ||
573 | |||
574 | static int brcmstb_gpio_resume(struct device *dev) | ||
575 | { | ||
576 | struct brcmstb_gpio_priv *priv = dev_get_drvdata(dev); | ||
577 | struct brcmstb_gpio_bank *bank; | ||
578 | bool need_wakeup_event = false; | ||
579 | |||
580 | list_for_each_entry(bank, &priv->bank_list, node) { | ||
581 | need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank); | ||
582 | brcmstb_gpio_bank_restore(priv, bank); | ||
583 | } | ||
584 | |||
585 | if (priv->parent_wake_irq && need_wakeup_event) | ||
586 | pm_wakeup_event(dev, 0); | ||
587 | |||
588 | /* enable non-wake interrupt */ | ||
589 | if (priv->parent_irq >= 0) | ||
590 | enable_irq(priv->parent_irq); | ||
591 | |||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | #else | ||
596 | #define brcmstb_gpio_suspend NULL | ||
597 | #define brcmstb_gpio_resume NULL | ||
598 | #endif /* CONFIG_PM_SLEEP */ | ||
599 | |||
600 | static const struct dev_pm_ops brcmstb_gpio_pm_ops = { | ||
601 | .suspend_noirq = brcmstb_gpio_suspend, | ||
602 | .resume_noirq = brcmstb_gpio_resume, | ||
603 | }; | ||
604 | |||
511 | static int brcmstb_gpio_probe(struct platform_device *pdev) | 605 | static int brcmstb_gpio_probe(struct platform_device *pdev) |
512 | { | 606 | { |
513 | struct device *dev = &pdev->dev; | 607 | struct device *dev = &pdev->dev; |
@@ -522,6 +616,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) | |||
522 | int err; | 616 | int err; |
523 | static int gpio_base; | 617 | static int gpio_base; |
524 | unsigned long flags = 0; | 618 | unsigned long flags = 0; |
619 | bool need_wakeup_event = false; | ||
525 | 620 | ||
526 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | 621 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
527 | if (!priv) | 622 | if (!priv) |
@@ -617,6 +712,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) | |||
617 | * Mask all interrupts by default, since wakeup interrupts may | 712 | * Mask all interrupts by default, since wakeup interrupts may |
618 | * be retained from S5 cold boot | 713 | * be retained from S5 cold boot |
619 | */ | 714 | */ |
715 | need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank); | ||
620 | gc->write_reg(reg_base + GIO_MASK(bank->id), 0); | 716 | gc->write_reg(reg_base + GIO_MASK(bank->id), 0); |
621 | 717 | ||
622 | err = gpiochip_add_data(gc, bank); | 718 | err = gpiochip_add_data(gc, bank); |
@@ -646,6 +742,9 @@ static int brcmstb_gpio_probe(struct platform_device *pdev) | |||
646 | dev_info(dev, "Registered %d banks (GPIO(s): %d-%d)\n", | 742 | dev_info(dev, "Registered %d banks (GPIO(s): %d-%d)\n", |
647 | num_banks, priv->gpio_base, gpio_base - 1); | 743 | num_banks, priv->gpio_base, gpio_base - 1); |
648 | 744 | ||
745 | if (priv->parent_wake_irq && need_wakeup_event) | ||
746 | pm_wakeup_event(dev, 0); | ||
747 | |||
649 | return 0; | 748 | return 0; |
650 | 749 | ||
651 | fail: | 750 | fail: |
@@ -664,9 +763,11 @@ static struct platform_driver brcmstb_gpio_driver = { | |||
664 | .driver = { | 763 | .driver = { |
665 | .name = "brcmstb-gpio", | 764 | .name = "brcmstb-gpio", |
666 | .of_match_table = brcmstb_gpio_of_match, | 765 | .of_match_table = brcmstb_gpio_of_match, |
766 | .pm = &brcmstb_gpio_pm_ops, | ||
667 | }, | 767 | }, |
668 | .probe = brcmstb_gpio_probe, | 768 | .probe = brcmstb_gpio_probe, |
669 | .remove = brcmstb_gpio_remove, | 769 | .remove = brcmstb_gpio_remove, |
770 | .shutdown = brcmstb_gpio_shutdown, | ||
670 | }; | 771 | }; |
671 | module_platform_driver(brcmstb_gpio_driver); | 772 | module_platform_driver(brcmstb_gpio_driver); |
672 | 773 | ||