On 10/2/19 7:45 AM, Thierry Reding wrote:
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,
I see jetson Xavier RTC wakeup test fail with this patch. It no longer
reaches the UART shell after suspend exit. Jetson-TX2 works fine with
this patch. There seems to be some hang on Xavier.
-regards,
Bitan