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

pinctrl: tegra: Add suspend and resume support

This patch adds support for Tegra pinctrl driver suspend and resume.

During suspend, context of all pinctrl registers are stored and
on resume they are all restored to have all the pinmux and pad
configuration for normal operation.

Acked-by: Thierry Reding <treding@nvidia.com>
Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
Link: https://lore.kernel.org/r/1564607463-28802-2-git-send-email-skomatineni@nvidia.com
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

authored by

Sowjanya Komatineni and committed by
Linus Walleij
9870acd3 3d6ade0a

+62
+59
drivers/pinctrl/tegra/pinctrl-tegra.c
··· 631 631 } 632 632 } 633 633 634 + static size_t tegra_pinctrl_get_bank_size(struct device *dev, 635 + unsigned int bank_id) 636 + { 637 + struct platform_device *pdev = to_platform_device(dev); 638 + struct resource *res; 639 + 640 + res = platform_get_resource(pdev, IORESOURCE_MEM, bank_id); 641 + 642 + return resource_size(res) / 4; 643 + } 644 + 645 + static int tegra_pinctrl_suspend(struct device *dev) 646 + { 647 + struct tegra_pmx *pmx = dev_get_drvdata(dev); 648 + u32 *backup_regs = pmx->backup_regs; 649 + u32 *regs; 650 + size_t bank_size; 651 + unsigned int i, k; 652 + 653 + for (i = 0; i < pmx->nbanks; i++) { 654 + bank_size = tegra_pinctrl_get_bank_size(dev, i); 655 + regs = pmx->regs[i]; 656 + for (k = 0; k < bank_size; k++) 657 + *backup_regs++ = readl_relaxed(regs++); 658 + } 659 + 660 + return pinctrl_force_sleep(pmx->pctl); 661 + } 662 + 663 + static int tegra_pinctrl_resume(struct device *dev) 664 + { 665 + struct tegra_pmx *pmx = dev_get_drvdata(dev); 666 + u32 *backup_regs = pmx->backup_regs; 667 + u32 *regs; 668 + size_t bank_size; 669 + unsigned int i, k; 670 + 671 + for (i = 0; i < pmx->nbanks; i++) { 672 + bank_size = tegra_pinctrl_get_bank_size(dev, i); 673 + regs = pmx->regs[i]; 674 + for (k = 0; k < bank_size; k++) 675 + writel_relaxed(*backup_regs++, regs++); 676 + } 677 + 678 + return 0; 679 + } 680 + 681 + const struct dev_pm_ops tegra_pinctrl_pm = { 682 + .suspend = &tegra_pinctrl_suspend, 683 + .resume = &tegra_pinctrl_resume 684 + }; 685 + 634 686 static bool gpio_node_has_range(const char *compatible) 635 687 { 636 688 struct device_node *np; ··· 707 655 int i; 708 656 const char **group_pins; 709 657 int fn, gn, gfn; 658 + unsigned long backup_regs_size = 0; 710 659 711 660 pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL); 712 661 if (!pmx) ··· 760 707 res = platform_get_resource(pdev, IORESOURCE_MEM, i); 761 708 if (!res) 762 709 break; 710 + backup_regs_size += resource_size(res); 763 711 } 764 712 pmx->nbanks = i; 765 713 766 714 pmx->regs = devm_kcalloc(&pdev->dev, pmx->nbanks, sizeof(*pmx->regs), 767 715 GFP_KERNEL); 768 716 if (!pmx->regs) 717 + return -ENOMEM; 718 + 719 + pmx->backup_regs = devm_kzalloc(&pdev->dev, backup_regs_size, 720 + GFP_KERNEL); 721 + if (!pmx->backup_regs) 769 722 return -ENOMEM; 770 723 771 724 for (i = 0; i < pmx->nbanks; i++) {
+3
drivers/pinctrl/tegra/pinctrl-tegra.h
··· 17 17 18 18 int nbanks; 19 19 void __iomem **regs; 20 + u32 *backup_regs; 20 21 }; 21 22 22 23 enum tegra_pinconf_param { ··· 193 192 bool schmitt_in_mux; 194 193 bool drvtype_in_mux; 195 194 }; 195 + 196 + extern const struct dev_pm_ops tegra_pinctrl_pm; 196 197 197 198 int tegra_pinctrl_probe(struct platform_device *pdev, 198 199 const struct tegra_pinctrl_soc_data *soc_data);