From: Thierry Reding <treding@xxxxxxxxxx> Backup GPIO control registers on suspend and restore them on resume to ensure that the GPIOs' configuration remains the same across suspend and resume. Signed-off-by: Thierry Reding <treding@xxxxxxxxxx> --- drivers/gpio/gpio-tegra186.c | 51 ++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index a9058fda187e..3ded6ba2f997 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -64,6 +64,12 @@ struct tegra_gpio { const struct tegra_gpio_soc *soc; void __iomem *base; + + struct tegra_gpio_context { + u32 value; + u32 control; + u32 config; + } *context; }; static const struct tegra_gpio_port * @@ -455,6 +461,11 @@ static int tegra186_gpio_probe(struct platform_device *pdev) for (i = 0; i < gpio->soc->num_ports; i++) gpio->gpio.ngpio += gpio->soc->ports[i].pins; + gpio->context = devm_kmalloc_array(gpio->gpio.parent, gpio->gpio.ngpio, + sizeof(*gpio->context), GFP_KERNEL); + if (!gpio->context) + return -ENOMEM; + names = devm_kcalloc(gpio->gpio.parent, gpio->gpio.ngpio, sizeof(*names), GFP_KERNEL); if (!names) @@ -526,6 +537,45 @@ static int tegra186_gpio_remove(struct platform_device *pdev) return 0; } +static int tegra186_gpio_suspend(struct device *dev) +{ + struct tegra_gpio *gpio = dev_get_drvdata(dev); + unsigned int i; + + for (i = 0; i < gpio->gpio.ngpio; i++) { + struct tegra_gpio_context *context = &gpio->context[i]; + void __iomem *base = tegra186_gpio_get_base(gpio, i); + + context->config = readl(base + TEGRA186_GPIO_ENABLE_CONFIG); + context->control = readl(base + TEGRA186_GPIO_OUTPUT_CONTROL); + context->value = readl(base + TEGRA186_GPIO_OUTPUT_VALUE); + } + + return 0; +} + +static int tegra186_gpio_resume(struct device *dev) +{ + struct tegra_gpio *gpio = dev_get_drvdata(dev); + unsigned int i; + + for (i = 0; i < gpio->gpio.ngpio; i++) { + struct tegra_gpio_context *context = &gpio->context[i]; + void __iomem *base = tegra186_gpio_get_base(gpio, i); + + writel(context->value, base + TEGRA186_GPIO_OUTPUT_VALUE); + writel(context->control, base + TEGRA186_GPIO_OUTPUT_CONTROL); + writel(context->config, base + TEGRA186_GPIO_ENABLE_CONFIG); + } + + return 0; +} + +static const struct dev_pm_ops tegra186_gpio_pm = { + .suspend_late = tegra186_gpio_suspend, + .resume_early = tegra186_gpio_resume, +}; + #define TEGRA186_MAIN_GPIO_PORT(port, base, count, controller) \ [TEGRA186_MAIN_GPIO_PORT_##port] = { \ .name = #port, \ @@ -680,6 +730,7 @@ static struct platform_driver tegra186_gpio_driver = { .driver = { .name = "tegra186-gpio", .of_match_table = tegra186_gpio_of_match, + .pm = &tegra186_gpio_pm, }, .probe = tegra186_gpio_probe, .remove = tegra186_gpio_remove, -- 2.23.0