From patchwork Mon Sep 11 06:11:56 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Drake X-Patchwork-Id: 812225 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-gpio-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=endlessm-com.20150623.gappssmtp.com header.i=@endlessm-com.20150623.gappssmtp.com header.b="n3a+GUHf"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3xrHdS1Y6Gz9s76 for ; Mon, 11 Sep 2017 16:12:12 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750806AbdIKGMJ (ORCPT ); Mon, 11 Sep 2017 02:12:09 -0400 Received: from mail-pf0-f170.google.com ([209.85.192.170]:36699 "EHLO mail-pf0-f170.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750748AbdIKGMI (ORCPT ); Mon, 11 Sep 2017 02:12:08 -0400 Received: by mail-pf0-f170.google.com with SMTP id e199so12617359pfh.3 for ; Sun, 10 Sep 2017 23:12:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=endlessm-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id; bh=vH8MR9dieHbx0Cgzg6uSE4Hnbwqj+XTCdZ+AFs0ZwvQ=; b=n3a+GUHfjssSA//usGLUS426Y+8ixNgRNUQI+n2Czw1P0kPw2kXDf5jyPoHJLO94iU ws62i5YrxhF9iY77hNI/5HfS7B9EyDDeQoanYZmkwNDvFxOJV/tI0iYILB5csLau0KL1 YKXl8rmzPNfOFemVQlcqBHRLY4EDj8ZlvWi1JwLQl08Z7ZOpf2RhEm87iDsV2SFc8kRW hnquEhr84RuCHYEsS/V/8T1qWV6GmxmKHf0BNIJOzD2MNxTKIioc4GBPlpFARDYt7ecG M+KiNiKV88ESZpWk1pZgIRRMQnhIUbf5b5J6ye2xYWVzUXWnAt1s7RMQVkEoqPl7brTW PL2g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=vH8MR9dieHbx0Cgzg6uSE4Hnbwqj+XTCdZ+AFs0ZwvQ=; b=d87/Mz4pr6Di4e7FXQbe11A/wLxO7m/2RzdTaZxnE22sXg2BQdUyUP127FJqOGvduK NbH7WagvPO01Y9VdbyPX9KfpKe512UI+DGonS4MovKYxJHBlQmGt6TJ4AVmnhWEPro8n tVEoVjLSDCrVZSCCPwAq8awv7bdK6NJrAqWqU96zGmox4iw+SMQONK+aFueerno8rTrF c2pmKIdrOBpgfoNyFdKjPK8poGcJMXTAS9P6UFCwt9ZTryOelSVk0suz2XiOSvmtCrVm 9aJRf9pWexkyHcA9lcdDp6KeHblCaYnbQRrZbhvUMZ/fPHXRu23wqXJMlyJ1g3qrMRPn lJRQ== X-Gm-Message-State: AHPjjUjBF8PQziFvM8Y6i6gqoR6OTE+z++2rrzTEXWkCDTsZH4QNmEwM vsHGQs+SVM+2lbPL X-Google-Smtp-Source: ADKCNb7A89wyGFXcVZ4Ex39JhSDOUhYahfF31KIqu36yDveYVGTZCIZ/ZQwr4zL4EMgYL7veD1jhTA== X-Received: by 10.98.223.137 with SMTP id d9mr11091082pfl.171.1505110328152; Sun, 10 Sep 2017 23:12:08 -0700 (PDT) Received: from localhost.localdomain (125-227-158-176.HINET-IP.hinet.net. [125.227.158.176]) by smtp.gmail.com with ESMTPSA id p5sm12919837pgc.94.2017.09.10.23.12.04 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 10 Sep 2017 23:12:07 -0700 (PDT) From: Daniel Drake To: linus.walleij@linaro.org Cc: linux-gpio@vger.kernel.org, Nehal-bakulchandra.Shah@amd.com, Shyam-sundar.S-k@amd.com, linux@endlessm.com Subject: [PATCH] pinctrl/amd: save pin registers over suspend/resume Date: Mon, 11 Sep 2017 14:11:56 +0800 Message-Id: <20170911061156.31872-1-drake@endlessm.com> X-Mailer: git-send-email 2.11.0 Sender: linux-gpio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org The touchpad in the Asus laptop models X505BA/BP and X542BA/BP is unresponsive after suspend/resume. The following error appears during resume: i2c_hid i2c-ELAN1300:00: failed to reset device. The problem here is that i2c_hid does not notice the interrupt being generated at this point, because the GPIO is no longer configured for interrupts. Fix this by saving pinctrl-amd pin registers during suspend and restoring them at resume time. Based on code from pinctrl-intel. Signed-off-by: Daniel Drake --- drivers/pinctrl/pinctrl-amd.c | 75 +++++++++++++++++++++++++++++++++++++++++++ drivers/pinctrl/pinctrl-amd.h | 1 + 2 files changed, 76 insertions(+) diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c index 38af1ec2df0c..3f6b34febbf1 100644 --- a/drivers/pinctrl/pinctrl-amd.c +++ b/drivers/pinctrl/pinctrl-amd.c @@ -36,6 +36,7 @@ #include #include +#include "core.h" #include "pinctrl-utils.h" #include "pinctrl-amd.h" @@ -725,6 +726,69 @@ static const struct pinconf_ops amd_pinconf_ops = { .pin_config_group_set = amd_pinconf_group_set, }; +#ifdef CONFIG_PM_SLEEP +static bool amd_gpio_should_save(struct amd_gpio *gpio_dev, unsigned int pin) +{ + const struct pin_desc *pd = pin_desc_get(gpio_dev->pctrl, pin); + + if (!pd) + return false; + + /* + * Only restore the pin if it is actually in use by the kernel (or + * by userspace). + */ + if (pd->mux_owner || pd->gpio_owner || + gpiochip_line_is_irq(&gpio_dev->gc, pin)) + return true; + + return false; +} + +int amd_gpio_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct amd_gpio *gpio_dev = platform_get_drvdata(pdev); + struct pinctrl_desc *desc = gpio_dev->pctrl->desc; + int i; + + for (i = 0; i < desc->npins; i++) { + int pin = desc->pins[i].number; + + if (!amd_gpio_should_save(gpio_dev, pin)) + continue; + + gpio_dev->saved_regs[i] = readl(gpio_dev->base + pin*4); + } + + return 0; +} + +int amd_gpio_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct amd_gpio *gpio_dev = platform_get_drvdata(pdev); + struct pinctrl_desc *desc = gpio_dev->pctrl->desc; + int i; + + for (i = 0; i < desc->npins; i++) { + int pin = desc->pins[i].number; + + if (!amd_gpio_should_save(gpio_dev, pin)) + continue; + + writel(gpio_dev->saved_regs[i], gpio_dev->base + pin*4); + } + + return 0; +} + +static const struct dev_pm_ops amd_gpio_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(amd_gpio_suspend, + amd_gpio_resume) +}; +#endif + static struct pinctrl_desc amd_pinctrl_desc = { .pins = kerncz_pins, .npins = ARRAY_SIZE(kerncz_pins), @@ -764,6 +828,14 @@ static int amd_gpio_probe(struct platform_device *pdev) return irq_base; } +#ifdef CONFIG_PM_SLEEP + gpio_dev->saved_regs = devm_kcalloc(&pdev->dev, amd_pinctrl_desc.npins, + sizeof(*gpio_dev->saved_regs), + GFP_KERNEL); + if (!gpio_dev->saved_regs) + return -ENOMEM; +#endif + gpio_dev->pdev = pdev; gpio_dev->gc.direction_input = amd_gpio_direction_input; gpio_dev->gc.direction_output = amd_gpio_direction_output; @@ -853,6 +925,9 @@ static struct platform_driver amd_gpio_driver = { .driver = { .name = "amd_gpio", .acpi_match_table = ACPI_PTR(amd_gpio_acpi_match), +#ifdef CONFIG_PM_SLEEP + .pm = &amd_gpio_pm_ops, +#endif }, .probe = amd_gpio_probe, .remove = amd_gpio_remove, diff --git a/drivers/pinctrl/pinctrl-amd.h b/drivers/pinctrl/pinctrl-amd.h index 5b1cb965c767..8fa453a59da5 100644 --- a/drivers/pinctrl/pinctrl-amd.h +++ b/drivers/pinctrl/pinctrl-amd.h @@ -97,6 +97,7 @@ struct amd_gpio { unsigned int hwbank_num; struct resource *res; struct platform_device *pdev; + u32 *saved_regs; }; /* KERNCZ configuration*/