Skip to content

Commit

Permalink
pinctrl: intel: Only restore pins that are used by the driver
Browse files Browse the repository at this point in the history
Dell XPS 13 (and maybe some others) uses a GPIO (CPU_GP_1) during suspend
to explicitly disable USB touchscreen interrupt. This is done to prevent
situation where the lid is closed the touchscreen is left functional.

The pinctrl driver (wrongly) assumes it owns all pins which are owned by
host and not locked down. It is perfectly fine for BIOS to use those pins
as it is also considered as host in this context.

What happens is that when the lid of Dell XPS 13 is closed, the BIOS
configures CPU_GP_1 low disabling the touchscreen interrupt. During resume
we restore all host owned pins to the known state which includes CPU_GP_1
and this overwrites what the BIOS has programmed there causing the
touchscreen to fail as no interrupts are reaching the CPU anymore.

Fix this by restoring only those pins we know are explicitly requested by
the kernel one way or other.

Cc: stable@vger.kernel.org
Link: https://bugzilla.kernel.org/show_bug.cgi?id=176361
Reported-by: AceLan Kao <acelan.kao@canonical.com>
Tested-by: AceLan Kao <acelan.kao@canonical.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
  • Loading branch information
Mika Westerberg authored and Linus Walleij committed Oct 18, 2016
1 parent a171bc5 commit c538b94
Showing 1 changed file with 23 additions and 2 deletions.
25 changes: 23 additions & 2 deletions drivers/pinctrl/intel/pinctrl-intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>

#include "../core.h"
#include "pinctrl-intel.h"

/* Offset from regs */
Expand Down Expand Up @@ -1056,6 +1057,26 @@ int intel_pinctrl_remove(struct platform_device *pdev)
EXPORT_SYMBOL_GPL(intel_pinctrl_remove);

#ifdef CONFIG_PM_SLEEP
static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned pin)
{
const struct pin_desc *pd = pin_desc_get(pctrl->pctldev, pin);

if (!pd || !intel_pad_usable(pctrl, pin))
return false;

/*
* Only restore the pin if it is actually in use by the kernel (or
* by userspace). It is possible that some pins are used by the
* BIOS during resume and those are not always locked down so leave
* them alone.
*/
if (pd->mux_owner || pd->gpio_owner ||
gpiochip_line_is_irq(&pctrl->chip, pin))
return true;

return false;
}

int intel_pinctrl_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
Expand All @@ -1069,7 +1090,7 @@ int intel_pinctrl_suspend(struct device *dev)
const struct pinctrl_pin_desc *desc = &pctrl->soc->pins[i];
u32 val;

if (!intel_pad_usable(pctrl, desc->number))
if (!intel_pinctrl_should_save(pctrl, desc->number))
continue;

val = readl(intel_get_padcfg(pctrl, desc->number, PADCFG0));
Expand Down Expand Up @@ -1130,7 +1151,7 @@ int intel_pinctrl_resume(struct device *dev)
void __iomem *padcfg;
u32 val;

if (!intel_pad_usable(pctrl, desc->number))
if (!intel_pinctrl_should_save(pctrl, desc->number))
continue;

padcfg = intel_get_padcfg(pctrl, desc->number, PADCFG0);
Expand Down

0 comments on commit c538b94

Please sign in to comment.