diff options
| -rw-r--r-- | drivers/pinctrl/intel/pinctrl-baytrail.c | 83 |
1 files changed, 81 insertions, 2 deletions
diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index 2318057a309b..2062c224e32f 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c | |||
| @@ -66,6 +66,10 @@ | |||
| 66 | #define BYT_DIR_MASK (BIT(1) | BIT(2)) | 66 | #define BYT_DIR_MASK (BIT(1) | BIT(2)) |
| 67 | #define BYT_TRIG_MASK (BIT(26) | BIT(25) | BIT(24)) | 67 | #define BYT_TRIG_MASK (BIT(26) | BIT(25) | BIT(24)) |
| 68 | 68 | ||
| 69 | #define BYT_CONF0_RESTORE_MASK (BYT_DIRECT_IRQ_EN | BYT_TRIG_MASK | \ | ||
| 70 | BYT_PIN_MUX) | ||
| 71 | #define BYT_VAL_RESTORE_MASK (BYT_DIR_MASK | BYT_LEVEL) | ||
| 72 | |||
| 69 | #define BYT_NGPIO_SCORE 102 | 73 | #define BYT_NGPIO_SCORE 102 |
| 70 | #define BYT_NGPIO_NCORE 28 | 74 | #define BYT_NGPIO_NCORE 28 |
| 71 | #define BYT_NGPIO_SUS 44 | 75 | #define BYT_NGPIO_SUS 44 |
| @@ -134,12 +138,18 @@ static struct pinctrl_gpio_range byt_ranges[] = { | |||
| 134 | }, | 138 | }, |
| 135 | }; | 139 | }; |
| 136 | 140 | ||
| 141 | struct byt_gpio_pin_context { | ||
| 142 | u32 conf0; | ||
| 143 | u32 val; | ||
| 144 | }; | ||
| 145 | |||
| 137 | struct byt_gpio { | 146 | struct byt_gpio { |
| 138 | struct gpio_chip chip; | 147 | struct gpio_chip chip; |
| 139 | struct platform_device *pdev; | 148 | struct platform_device *pdev; |
| 140 | spinlock_t lock; | 149 | spinlock_t lock; |
| 141 | void __iomem *reg_base; | 150 | void __iomem *reg_base; |
| 142 | struct pinctrl_gpio_range *range; | 151 | struct pinctrl_gpio_range *range; |
| 152 | struct byt_gpio_pin_context *saved_context; | ||
| 143 | }; | 153 | }; |
| 144 | 154 | ||
| 145 | #define to_byt_gpio(c) container_of(c, struct byt_gpio, chip) | 155 | #define to_byt_gpio(c) container_of(c, struct byt_gpio, chip) |
| @@ -584,6 +594,11 @@ static int byt_gpio_probe(struct platform_device *pdev) | |||
| 584 | gc->can_sleep = false; | 594 | gc->can_sleep = false; |
| 585 | gc->dev = dev; | 595 | gc->dev = dev; |
| 586 | 596 | ||
| 597 | #ifdef CONFIG_PM_SLEEP | ||
| 598 | vg->saved_context = devm_kcalloc(&pdev->dev, gc->ngpio, | ||
| 599 | sizeof(*vg->saved_context), GFP_KERNEL); | ||
| 600 | #endif | ||
| 601 | |||
| 587 | ret = gpiochip_add(gc); | 602 | ret = gpiochip_add(gc); |
| 588 | if (ret) { | 603 | if (ret) { |
| 589 | dev_err(&pdev->dev, "failed adding byt-gpio chip\n"); | 604 | dev_err(&pdev->dev, "failed adding byt-gpio chip\n"); |
| @@ -612,6 +627,69 @@ static int byt_gpio_probe(struct platform_device *pdev) | |||
| 612 | return 0; | 627 | return 0; |
| 613 | } | 628 | } |
| 614 | 629 | ||
| 630 | #ifdef CONFIG_PM_SLEEP | ||
| 631 | static int byt_gpio_suspend(struct device *dev) | ||
| 632 | { | ||
| 633 | struct platform_device *pdev = to_platform_device(dev); | ||
| 634 | struct byt_gpio *vg = platform_get_drvdata(pdev); | ||
| 635 | int i; | ||
| 636 | |||
| 637 | for (i = 0; i < vg->chip.ngpio; i++) { | ||
| 638 | void __iomem *reg; | ||
| 639 | u32 value; | ||
| 640 | |||
| 641 | reg = byt_gpio_reg(&vg->chip, i, BYT_CONF0_REG); | ||
| 642 | value = readl(reg) & BYT_CONF0_RESTORE_MASK; | ||
| 643 | vg->saved_context[i].conf0 = value; | ||
| 644 | |||
| 645 | reg = byt_gpio_reg(&vg->chip, i, BYT_VAL_REG); | ||
| 646 | value = readl(reg) & BYT_VAL_RESTORE_MASK; | ||
| 647 | vg->saved_context[i].val = value; | ||
| 648 | } | ||
| 649 | |||
| 650 | return 0; | ||
| 651 | } | ||
| 652 | |||
| 653 | static int byt_gpio_resume(struct device *dev) | ||
| 654 | { | ||
| 655 | struct platform_device *pdev = to_platform_device(dev); | ||
| 656 | struct byt_gpio *vg = platform_get_drvdata(pdev); | ||
| 657 | int i; | ||
| 658 | |||
| 659 | for (i = 0; i < vg->chip.ngpio; i++) { | ||
| 660 | void __iomem *reg; | ||
| 661 | u32 value; | ||
| 662 | |||
| 663 | reg = byt_gpio_reg(&vg->chip, i, BYT_CONF0_REG); | ||
| 664 | value = readl(reg); | ||
| 665 | if ((value & BYT_CONF0_RESTORE_MASK) != | ||
| 666 | vg->saved_context[i].conf0) { | ||
| 667 | value &= ~BYT_CONF0_RESTORE_MASK; | ||
| 668 | value |= vg->saved_context[i].conf0; | ||
| 669 | writel(value, reg); | ||
| 670 | dev_info(dev, "restored pin %d conf0 %#08x", i, value); | ||
| 671 | } | ||
| 672 | |||
| 673 | reg = byt_gpio_reg(&vg->chip, i, BYT_VAL_REG); | ||
| 674 | value = readl(reg); | ||
| 675 | if ((value & BYT_VAL_RESTORE_MASK) != | ||
| 676 | vg->saved_context[i].val) { | ||
| 677 | u32 v; | ||
| 678 | |||
| 679 | v = value & ~BYT_VAL_RESTORE_MASK; | ||
| 680 | v |= vg->saved_context[i].val; | ||
| 681 | if (v != value) { | ||
| 682 | writel(v, reg); | ||
| 683 | dev_dbg(dev, "restored pin %d val %#08x\n", | ||
| 684 | i, v); | ||
| 685 | } | ||
| 686 | } | ||
| 687 | } | ||
| 688 | |||
| 689 | return 0; | ||
| 690 | } | ||
| 691 | #endif | ||
| 692 | |||
| 615 | static int byt_gpio_runtime_suspend(struct device *dev) | 693 | static int byt_gpio_runtime_suspend(struct device *dev) |
| 616 | { | 694 | { |
| 617 | return 0; | 695 | return 0; |
| @@ -623,8 +701,9 @@ static int byt_gpio_runtime_resume(struct device *dev) | |||
| 623 | } | 701 | } |
| 624 | 702 | ||
| 625 | static const struct dev_pm_ops byt_gpio_pm_ops = { | 703 | static const struct dev_pm_ops byt_gpio_pm_ops = { |
| 626 | .runtime_suspend = byt_gpio_runtime_suspend, | 704 | SET_LATE_SYSTEM_SLEEP_PM_OPS(byt_gpio_suspend, byt_gpio_resume) |
| 627 | .runtime_resume = byt_gpio_runtime_resume, | 705 | SET_RUNTIME_PM_OPS(byt_gpio_runtime_suspend, byt_gpio_runtime_resume, |
| 706 | NULL) | ||
| 628 | }; | 707 | }; |
| 629 | 708 | ||
| 630 | static const struct acpi_device_id byt_gpio_acpi_match[] = { | 709 | static const struct acpi_device_id byt_gpio_acpi_match[] = { |
