diff options
Diffstat (limited to 'drivers/pinctrl/pinctrl-amd.c')
| -rw-r--r-- | drivers/pinctrl/pinctrl-amd.c | 327 |
1 files changed, 208 insertions, 119 deletions
diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c index 9bc6e3922e78..2dac5c71eb00 100644 --- a/drivers/pinctrl/pinctrl-amd.c +++ b/drivers/pinctrl/pinctrl-amd.c @@ -30,11 +30,17 @@ #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinconf-generic.h> #include <linux/pinctrl/pinmux.h> +#include <linux/string_choices.h> +#include <linux/suspend.h> #include "core.h" #include "pinctrl-utils.h" #include "pinctrl-amd.h" +#ifdef CONFIG_SUSPEND +static struct amd_gpio *pinctrl_dev; +#endif + static int amd_gpio_get_direction(struct gpio_chip *gc, unsigned offset) { unsigned long flags; @@ -99,7 +105,8 @@ static int amd_gpio_get_value(struct gpio_chip *gc, unsigned offset) return !!(pin_reg & BIT(PIN_STS_OFF)); } -static void amd_gpio_set_value(struct gpio_chip *gc, unsigned offset, int value) +static int amd_gpio_set_value(struct gpio_chip *gc, unsigned int offset, + int value) { u32 pin_reg; unsigned long flags; @@ -113,18 +120,24 @@ static void amd_gpio_set_value(struct gpio_chip *gc, unsigned offset, int value) pin_reg &= ~BIT(OUTPUT_VALUE_OFF); writel(pin_reg, gpio_dev->base + offset * 4); raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); + + return 0; } -static int amd_gpio_set_debounce(struct gpio_chip *gc, unsigned offset, - unsigned debounce) +static int amd_gpio_set_debounce(struct amd_gpio *gpio_dev, unsigned int offset, + unsigned int debounce) { u32 time; u32 pin_reg; int ret = 0; - unsigned long flags; - struct amd_gpio *gpio_dev = gpiochip_get_data(gc); - raw_spin_lock_irqsave(&gpio_dev->lock, flags); + /* Use special handling for Pin0 debounce */ + if (offset == 0) { + pin_reg = readl(gpio_dev->base + WAKE_INT_MASTER_REG); + if (pin_reg & INTERNAL_GPIO0_DEBOUNCE) + debounce = 0; + } + pin_reg = readl(gpio_dev->base + offset * 4); if (debounce) { @@ -175,23 +188,10 @@ static int amd_gpio_set_debounce(struct gpio_chip *gc, unsigned offset, pin_reg &= ~(DB_CNTRl_MASK << DB_CNTRL_OFF); } writel(pin_reg, gpio_dev->base + offset * 4); - raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); return ret; } -static int amd_gpio_set_config(struct gpio_chip *gc, unsigned offset, - unsigned long config) -{ - u32 debounce; - - if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE) - return -ENOTSUPP; - - debounce = pinconf_to_config_argument(config); - return amd_gpio_set_debounce(gc, offset, debounce); -} - #ifdef CONFIG_DEBUG_FS static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) { @@ -206,19 +206,19 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) char *level_trig; char *active_level; - char *interrupt_enable; char *interrupt_mask; char *wake_cntrl0; char *wake_cntrl1; char *wake_cntrl2; char *pin_sts; - char *pull_up_sel; - char *pull_up_enable; - char *pull_down_enable; + char *interrupt_sts; + char *wake_sts; char *orientation; char debounce_value[40]; char *debounce_enable; + char *wake_cntrlz; + seq_printf(s, "WAKE_INT_MASTER_REG: 0x%08x\n", readl(gpio_dev->base + WAKE_INT_MASTER_REG)); for (bank = 0; bank < gpio_dev->hwbank_num; bank++) { unsigned int time = 0; unsigned int unit = 0; @@ -245,6 +245,7 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) continue; } seq_printf(s, "GPIO bank%d\n", bank); + seq_puts(s, "gpio\t int|active|trigger|S0i3| S3|S4/S5| Z|wake|pull| orient| debounce|reg\n"); for (; i < pin_num; i++) { seq_printf(s, "#%d\t", i); raw_spin_lock_irqsave(&gpio_dev->lock, flags); @@ -254,7 +255,6 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) if (pin_reg & BIT(INTERRUPT_ENABLE_OFF)) { u8 level = (pin_reg >> ACTIVE_LEVEL_OFF) & ACTIVE_LEVEL_MASK; - interrupt_enable = "+"; if (level == ACTIVE_LEVEL_HIGH) active_level = "↑"; @@ -271,59 +271,61 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) else level_trig = " edge"; - } else { - interrupt_enable = "∅"; - active_level = "∅"; - level_trig = " ∅"; - } + if (pin_reg & BIT(INTERRUPT_MASK_OFF)) + interrupt_mask = "😛"; + else + interrupt_mask = "😷"; - if (pin_reg & BIT(INTERRUPT_MASK_OFF)) - interrupt_mask = "😛"; - else - interrupt_mask = "😷"; - seq_printf(s, "int %s (%s)| active-%s| %s-⚡| ", - interrupt_enable, + if (pin_reg & BIT(INTERRUPT_STS_OFF)) + interrupt_sts = "🔥"; + else + interrupt_sts = " "; + + seq_printf(s, "%s %s| %s| %s|", + interrupt_sts, interrupt_mask, active_level, level_trig); + } else + seq_puts(s, " ∅| | |"); if (pin_reg & BIT(WAKE_CNTRL_OFF_S0I3)) wake_cntrl0 = "⏰"; else - wake_cntrl0 = " ∅"; - seq_printf(s, "S0i3 %s| ", wake_cntrl0); + wake_cntrl0 = " "; + seq_printf(s, " %s| ", wake_cntrl0); if (pin_reg & BIT(WAKE_CNTRL_OFF_S3)) wake_cntrl1 = "⏰"; else - wake_cntrl1 = " ∅"; - seq_printf(s, "S3 %s| ", wake_cntrl1); + wake_cntrl1 = " "; + seq_printf(s, "%s|", wake_cntrl1); if (pin_reg & BIT(WAKE_CNTRL_OFF_S4)) wake_cntrl2 = "⏰"; else - wake_cntrl2 = " ∅"; - seq_printf(s, "S4/S5 %s| ", wake_cntrl2); + wake_cntrl2 = " "; + seq_printf(s, " %s|", wake_cntrl2); - if (pin_reg & BIT(PULL_UP_ENABLE_OFF)) { - pull_up_enable = "+"; - if (pin_reg & BIT(PULL_UP_SEL_OFF)) - pull_up_sel = "8k"; - else - pull_up_sel = "4k"; - } else { - pull_up_enable = "∅"; - pull_up_sel = " "; - } - seq_printf(s, "pull-↑ %s (%s)| ", - pull_up_enable, - pull_up_sel); + if (pin_reg & BIT(WAKECNTRL_Z_OFF)) + wake_cntrlz = "⏰"; + else + wake_cntrlz = " "; + seq_printf(s, "%s|", wake_cntrlz); - if (pin_reg & BIT(PULL_DOWN_ENABLE_OFF)) - pull_down_enable = "+"; + if (pin_reg & BIT(WAKE_STS_OFF)) + wake_sts = "🔥"; else - pull_down_enable = "∅"; - seq_printf(s, "pull-↓ %s| ", pull_down_enable); + wake_sts = " "; + seq_printf(s, " %s|", wake_sts); + + if (pin_reg & BIT(PULL_UP_ENABLE_OFF)) { + seq_puts(s, " ↑ |"); + } else if (pin_reg & BIT(PULL_DOWN_ENABLE_OFF)) { + seq_puts(s, " ↓ |"); + } else { + seq_puts(s, " |"); + } if (pin_reg & BIT(OUTPUT_ENABLE_OFF)) { pin_sts = "output"; @@ -338,7 +340,7 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) else orientation = "↓"; } - seq_printf(s, "%s %s| ", pin_sts, orientation); + seq_printf(s, "%s %s|", pin_sts, orientation); db_cntrl = (DB_CNTRl_MASK << DB_CNTRL_OFF) & pin_reg; if (db_cntrl) { @@ -357,18 +359,17 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) unit = 61; } if ((DB_TYPE_REMOVE_GLITCH << DB_CNTRL_OFF) == db_cntrl) - debounce_enable = "b +"; + debounce_enable = "b"; else if ((DB_TYPE_PRESERVE_LOW_GLITCH << DB_CNTRL_OFF) == db_cntrl) - debounce_enable = "↓ +"; + debounce_enable = "↓"; else - debounce_enable = "↑ +"; - + debounce_enable = "↑"; + snprintf(debounce_value, sizeof(debounce_value), "%06u", time * unit); + seq_printf(s, "%s (🕑 %sus)|", debounce_enable, debounce_value); } else { - debounce_enable = " ∅"; + seq_puts(s, " |"); } - snprintf(debounce_value, sizeof(debounce_value), "%u", time * unit); - seq_printf(s, "debounce %s (🕑 %sus)| ", debounce_enable, debounce_value); - seq_printf(s, " 0x%x\n", pin_reg); + seq_printf(s, "0x%x\n", pin_reg); } } } @@ -382,14 +383,15 @@ static void amd_gpio_irq_enable(struct irq_data *d) unsigned long flags; struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct amd_gpio *gpio_dev = gpiochip_get_data(gc); + irq_hw_number_t hwirq = irqd_to_hwirq(d); - gpiochip_enable_irq(gc, d->hwirq); + gpiochip_enable_irq(gc, hwirq); raw_spin_lock_irqsave(&gpio_dev->lock, flags); - pin_reg = readl(gpio_dev->base + (d->hwirq)*4); + pin_reg = readl(gpio_dev->base + hwirq * 4); pin_reg |= BIT(INTERRUPT_ENABLE_OFF); pin_reg |= BIT(INTERRUPT_MASK_OFF); - writel(pin_reg, gpio_dev->base + (d->hwirq)*4); + writel(pin_reg, gpio_dev->base + hwirq * 4); raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); } @@ -399,15 +401,16 @@ static void amd_gpio_irq_disable(struct irq_data *d) unsigned long flags; struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct amd_gpio *gpio_dev = gpiochip_get_data(gc); + irq_hw_number_t hwirq = irqd_to_hwirq(d); raw_spin_lock_irqsave(&gpio_dev->lock, flags); - pin_reg = readl(gpio_dev->base + (d->hwirq)*4); + pin_reg = readl(gpio_dev->base + hwirq * 4); pin_reg &= ~BIT(INTERRUPT_ENABLE_OFF); pin_reg &= ~BIT(INTERRUPT_MASK_OFF); - writel(pin_reg, gpio_dev->base + (d->hwirq)*4); + writel(pin_reg, gpio_dev->base + hwirq * 4); raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); - gpiochip_disable_irq(gc, d->hwirq); + gpiochip_disable_irq(gc, hwirq); } static void amd_gpio_irq_mask(struct irq_data *d) @@ -416,11 +419,12 @@ static void amd_gpio_irq_mask(struct irq_data *d) unsigned long flags; struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct amd_gpio *gpio_dev = gpiochip_get_data(gc); + irq_hw_number_t hwirq = irqd_to_hwirq(d); raw_spin_lock_irqsave(&gpio_dev->lock, flags); - pin_reg = readl(gpio_dev->base + (d->hwirq)*4); + pin_reg = readl(gpio_dev->base + hwirq * 4); pin_reg &= ~BIT(INTERRUPT_MASK_OFF); - writel(pin_reg, gpio_dev->base + (d->hwirq)*4); + writel(pin_reg, gpio_dev->base + hwirq * 4); raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); } @@ -430,11 +434,12 @@ static void amd_gpio_irq_unmask(struct irq_data *d) unsigned long flags; struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct amd_gpio *gpio_dev = gpiochip_get_data(gc); + irq_hw_number_t hwirq = irqd_to_hwirq(d); raw_spin_lock_irqsave(&gpio_dev->lock, flags); - pin_reg = readl(gpio_dev->base + (d->hwirq)*4); + pin_reg = readl(gpio_dev->base + hwirq * 4); pin_reg |= BIT(INTERRUPT_MASK_OFF); - writel(pin_reg, gpio_dev->base + (d->hwirq)*4); + writel(pin_reg, gpio_dev->base + hwirq * 4); raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); } @@ -445,17 +450,21 @@ static int amd_gpio_irq_set_wake(struct irq_data *d, unsigned int on) struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct amd_gpio *gpio_dev = gpiochip_get_data(gc); u32 wake_mask = BIT(WAKE_CNTRL_OFF_S0I3) | BIT(WAKE_CNTRL_OFF_S3); + irq_hw_number_t hwirq = irqd_to_hwirq(d); int err; + pm_pr_dbg("Setting wake for GPIO %lu to %s\n", + hwirq, str_enable_disable(on)); + raw_spin_lock_irqsave(&gpio_dev->lock, flags); - pin_reg = readl(gpio_dev->base + (d->hwirq)*4); + pin_reg = readl(gpio_dev->base + hwirq * 4); if (on) pin_reg |= wake_mask; else pin_reg &= ~wake_mask; - writel(pin_reg, gpio_dev->base + (d->hwirq)*4); + writel(pin_reg, gpio_dev->base + hwirq * 4); raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); if (on) @@ -465,7 +474,7 @@ static int amd_gpio_irq_set_wake(struct irq_data *d, unsigned int on) if (err) dev_err(&gpio_dev->pdev->dev, "failed to %s wake-up interrupt\n", - on ? "enable" : "disable"); + str_enable_disable(on)); return 0; } @@ -491,9 +500,10 @@ static int amd_gpio_irq_set_type(struct irq_data *d, unsigned int type) unsigned long flags; struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct amd_gpio *gpio_dev = gpiochip_get_data(gc); + irq_hw_number_t hwirq = irqd_to_hwirq(d); raw_spin_lock_irqsave(&gpio_dev->lock, flags); - pin_reg = readl(gpio_dev->base + (d->hwirq)*4); + pin_reg = readl(gpio_dev->base + hwirq * 4); switch (type & IRQ_TYPE_SENSE_MASK) { case IRQ_TYPE_EDGE_RISING: @@ -513,7 +523,7 @@ static int amd_gpio_irq_set_type(struct irq_data *d, unsigned int type) case IRQ_TYPE_EDGE_BOTH: pin_reg &= ~BIT(LEVEL_TRIG_OFF); pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF); - pin_reg |= BOTH_EADGE << ACTIVE_LEVEL_OFF; + pin_reg |= BOTH_EDGES << ACTIVE_LEVEL_OFF; irq_set_handler_locked(d, handle_edge_irq); break; @@ -559,10 +569,10 @@ static int amd_gpio_irq_set_type(struct irq_data *d, unsigned int type) pin_reg_irq_en = pin_reg; pin_reg_irq_en |= mask; pin_reg_irq_en &= ~BIT(INTERRUPT_MASK_OFF); - writel(pin_reg_irq_en, gpio_dev->base + (d->hwirq)*4); - while ((readl(gpio_dev->base + (d->hwirq)*4) & mask) != mask) + writel(pin_reg_irq_en, gpio_dev->base + hwirq * 4); + while ((readl(gpio_dev->base + hwirq * 4) & mask) != mask) continue; - writel(pin_reg, gpio_dev->base + (d->hwirq)*4); + writel(pin_reg, gpio_dev->base + hwirq * 4); raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); return ret; @@ -630,9 +640,8 @@ static bool do_amd_gpio_irq_handler(int irq, void *dev_id) regval = readl(regs + i); if (regval & PIN_IRQ_PENDING) - dev_dbg(&gpio_dev->pdev->dev, - "GPIO %d is active: 0x%x", - irqnr + i, regval); + pm_pr_dbg("GPIO %d is active: 0x%x", + irqnr + i, regval); /* caused wake on resume context for shared IRQ */ if (irq < 0 && (regval & BIT(WAKE_STS_OFF))) @@ -647,21 +656,21 @@ static bool do_amd_gpio_irq_handler(int irq, void *dev_id) * We must read the pin register again, in case the * value was changed while executing * generic_handle_domain_irq() above. - * If we didn't find a mapping for the interrupt, - * disable it in order to avoid a system hang caused - * by an interrupt storm. + * If the line is not an irq, disable it in order to + * avoid a system hang caused by an interrupt storm. */ raw_spin_lock_irqsave(&gpio_dev->lock, flags); regval = readl(regs + i); - if (irq == 0) { - regval &= ~BIT(INTERRUPT_ENABLE_OFF); + if (!gpiochip_line_is_irq(gc, irqnr + i)) { + regval &= ~BIT(INTERRUPT_MASK_OFF); dev_dbg(&gpio_dev->pdev->dev, "Disabling spurious GPIO IRQ %d\n", irqnr + i); + } else { + ret = true; } writel(regval, regs + i); raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); - ret = true; } } /* did not cause wake on resume context for shared IRQ */ @@ -748,7 +757,7 @@ static int amd_pinconf_get(struct pinctrl_dev *pctldev, break; case PIN_CONFIG_BIAS_PULL_UP: - arg = (pin_reg >> PULL_UP_SEL_OFF) & (BIT(0) | BIT(1)); + arg = (pin_reg >> PULL_UP_ENABLE_OFF) & BIT(0); break; case PIN_CONFIG_DRIVE_STRENGTH: @@ -756,7 +765,7 @@ static int amd_pinconf_get(struct pinctrl_dev *pctldev, break; default: - dev_err(&gpio_dev->pdev->dev, "Invalid config param %04x\n", + dev_dbg(&gpio_dev->pdev->dev, "Invalid config param %04x\n", param); return -ENOTSUPP; } @@ -767,7 +776,7 @@ static int amd_pinconf_get(struct pinctrl_dev *pctldev, } static int amd_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, - unsigned long *configs, unsigned num_configs) + unsigned long *configs, unsigned int num_configs) { int i; u32 arg; @@ -785,9 +794,8 @@ static int amd_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, switch (param) { case PIN_CONFIG_INPUT_DEBOUNCE: - pin_reg &= ~DB_TMR_OUT_MASK; - pin_reg |= arg & DB_TMR_OUT_MASK; - break; + ret = amd_gpio_set_debounce(gpio_dev, pin, arg); + goto out_unlock; case PIN_CONFIG_BIAS_PULL_DOWN: pin_reg &= ~BIT(PULL_DOWN_ENABLE_OFF); @@ -795,10 +803,8 @@ static int amd_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, break; case PIN_CONFIG_BIAS_PULL_UP: - pin_reg &= ~BIT(PULL_UP_SEL_OFF); - pin_reg |= (arg & BIT(0)) << PULL_UP_SEL_OFF; pin_reg &= ~BIT(PULL_UP_ENABLE_OFF); - pin_reg |= ((arg>>1) & BIT(0)) << PULL_UP_ENABLE_OFF; + pin_reg |= (arg & BIT(0)) << PULL_UP_ENABLE_OFF; break; case PIN_CONFIG_DRIVE_STRENGTH: @@ -809,13 +815,14 @@ static int amd_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, break; default: - dev_err(&gpio_dev->pdev->dev, + dev_dbg(&gpio_dev->pdev->dev, "Invalid config param %04x\n", param); ret = -ENOTSUPP; } writel(pin_reg, gpio_dev->base + pin*4); } +out_unlock: raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); return ret; @@ -857,6 +864,14 @@ static int amd_pinconf_group_set(struct pinctrl_dev *pctldev, return 0; } +static int amd_gpio_set_config(struct gpio_chip *gc, unsigned int pin, + unsigned long config) +{ + struct amd_gpio *gpio_dev = gpiochip_get_data(gc); + + return amd_pinconf_set(gpio_dev->pctrl, pin, &config, 1); +} + static const struct pinconf_ops amd_pinconf_ops = { .pin_config_get = amd_pinconf_get, .pin_config_set = amd_pinconf_set, @@ -866,13 +881,12 @@ static const struct pinconf_ops amd_pinconf_ops = { static void amd_gpio_irq_init(struct amd_gpio *gpio_dev) { - struct pinctrl_desc *desc = gpio_dev->pctrl->desc; + const struct pinctrl_desc *desc = gpio_dev->pctrl->desc; unsigned long flags; u32 pin_reg, mask; int i; mask = BIT(WAKE_CNTRL_OFF_S0I3) | BIT(WAKE_CNTRL_OFF_S3) | - BIT(INTERRUPT_MASK_OFF) | BIT(INTERRUPT_ENABLE_OFF) | BIT(WAKE_CNTRL_OFF_S4); for (i = 0; i < desc->npins; i++) { @@ -884,14 +898,52 @@ static void amd_gpio_irq_init(struct amd_gpio *gpio_dev) raw_spin_lock_irqsave(&gpio_dev->lock, flags); - pin_reg = readl(gpio_dev->base + i * 4); + pin_reg = readl(gpio_dev->base + pin * 4); pin_reg &= ~mask; - writel(pin_reg, gpio_dev->base + i * 4); + writel(pin_reg, gpio_dev->base + pin * 4); raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); } } +#if defined(CONFIG_SUSPEND) && defined(CONFIG_ACPI) +static void amd_gpio_check_pending(void) +{ + struct amd_gpio *gpio_dev = pinctrl_dev; + const struct pinctrl_desc *desc = gpio_dev->pctrl->desc; + int i; + + if (!pm_debug_messages_on) + return; + + for (i = 0; i < desc->npins; i++) { + int pin = desc->pins[i].number; + u32 tmp; + + tmp = readl(gpio_dev->base + pin * 4); + if (tmp & PIN_IRQ_PENDING) + pm_pr_dbg("%s: GPIO %d is active: 0x%x.\n", __func__, pin, tmp); + } +} + +static struct acpi_s2idle_dev_ops pinctrl_amd_s2idle_dev_ops = { + .check = amd_gpio_check_pending, +}; + +static void amd_gpio_register_s2idle_ops(void) +{ + acpi_register_lps0_dev(&pinctrl_amd_s2idle_dev_ops); +} + +static void amd_gpio_unregister_s2idle_ops(void) +{ + acpi_unregister_lps0_dev(&pinctrl_amd_s2idle_dev_ops); +} +#else +static inline void amd_gpio_register_s2idle_ops(void) {} +static inline void amd_gpio_unregister_s2idle_ops(void) {} +#endif + #ifdef CONFIG_PM_SLEEP static bool amd_gpio_should_save(struct amd_gpio *gpio_dev, unsigned int pin) { @@ -911,12 +963,13 @@ static bool amd_gpio_should_save(struct amd_gpio *gpio_dev, unsigned int pin) return false; } -static int amd_gpio_suspend(struct device *dev) +static int amd_gpio_suspend_hibernate_common(struct device *dev, bool is_suspend) { struct amd_gpio *gpio_dev = dev_get_drvdata(dev); - struct pinctrl_desc *desc = gpio_dev->pctrl->desc; + const struct pinctrl_desc *desc = gpio_dev->pctrl->desc; unsigned long flags; int i; + u32 wake_mask = is_suspend ? WAKE_SOURCE_SUSPEND : WAKE_SOURCE_HIBERNATE; for (i = 0; i < desc->npins; i++) { int pin = desc->pins[i].number; @@ -926,16 +979,49 @@ static int amd_gpio_suspend(struct device *dev) raw_spin_lock_irqsave(&gpio_dev->lock, flags); gpio_dev->saved_regs[i] = readl(gpio_dev->base + pin * 4) & ~PIN_IRQ_PENDING; + + /* mask any interrupts not intended to be a wake source */ + if (!(gpio_dev->saved_regs[i] & wake_mask)) { + writel(gpio_dev->saved_regs[i] & ~BIT(INTERRUPT_MASK_OFF), + gpio_dev->base + pin * 4); + pm_pr_dbg("Disabling GPIO #%d interrupt for %s.\n", + pin, is_suspend ? "suspend" : "hibernate"); + } + + /* + * debounce enabled over suspend has shown issues with a GPIO + * being unable to wake the system, as we're only interested in + * the actual wakeup event, clear it. + */ + if (gpio_dev->saved_regs[i] & (DB_CNTRl_MASK << DB_CNTRL_OFF)) { + amd_gpio_set_debounce(gpio_dev, pin, 0); + pm_pr_dbg("Clearing debounce for GPIO #%d during %s.\n", + pin, is_suspend ? "suspend" : "hibernate"); + } + raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); } return 0; } +static int amd_gpio_suspend(struct device *dev) +{ +#ifdef CONFIG_SUSPEND + pinctrl_dev = dev_get_drvdata(dev); +#endif + return amd_gpio_suspend_hibernate_common(dev, true); +} + +static int amd_gpio_hibernate(struct device *dev) +{ + return amd_gpio_suspend_hibernate_common(dev, false); +} + static int amd_gpio_resume(struct device *dev) { struct amd_gpio *gpio_dev = dev_get_drvdata(dev); - struct pinctrl_desc *desc = gpio_dev->pctrl->desc; + const struct pinctrl_desc *desc = gpio_dev->pctrl->desc; unsigned long flags; int i; @@ -955,8 +1041,12 @@ static int amd_gpio_resume(struct device *dev) } static const struct dev_pm_ops amd_gpio_pm_ops = { - SET_LATE_SYSTEM_SLEEP_PM_OPS(amd_gpio_suspend, - amd_gpio_resume) + .suspend_late = amd_gpio_suspend, + .resume_early = amd_gpio_resume, + .freeze_late = amd_gpio_hibernate, + .thaw_early = amd_gpio_resume, + .poweroff_late = amd_gpio_hibernate, + .restore_early = amd_gpio_resume, }; #endif @@ -1093,7 +1183,7 @@ static int amd_gpio_probe(struct platform_device *pdev) if (gpio_dev->irq < 0) return gpio_dev->irq; -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_SUSPEND gpio_dev->saved_regs = devm_kcalloc(&pdev->dev, amd_pinctrl_desc.npins, sizeof(*gpio_dev->saved_regs), GFP_KERNEL); @@ -1153,12 +1243,13 @@ static int amd_gpio_probe(struct platform_device *pdev) } ret = devm_request_irq(&pdev->dev, gpio_dev->irq, amd_gpio_irq_handler, - IRQF_SHARED, KBUILD_MODNAME, gpio_dev); + IRQF_SHARED | IRQF_COND_ONESHOT, KBUILD_MODNAME, gpio_dev); if (ret) goto out2; platform_set_drvdata(pdev, gpio_dev); acpi_register_wakeup_handler(gpio_dev->irq, amd_gpio_check_wake, gpio_dev); + amd_gpio_register_s2idle_ops(); dev_dbg(&pdev->dev, "amd gpio driver loaded\n"); return ret; @@ -1169,7 +1260,7 @@ out2: return ret; } -static int amd_gpio_remove(struct platform_device *pdev) +static void amd_gpio_remove(struct platform_device *pdev) { struct amd_gpio *gpio_dev; @@ -1177,8 +1268,7 @@ static int amd_gpio_remove(struct platform_device *pdev) gpiochip_remove(&gpio_dev->gc); acpi_unregister_wakeup_handler(amd_gpio_check_wake, gpio_dev); - - return 0; + amd_gpio_unregister_s2idle_ops(); } #ifdef CONFIG_ACPI @@ -1205,6 +1295,5 @@ static struct platform_driver amd_gpio_driver = { module_platform_driver(amd_gpio_driver); -MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Ken Xue <Ken.Xue@amd.com>, Jeff Wu <Jeff.Wu@amd.com>"); MODULE_DESCRIPTION("AMD GPIO pinctrl driver"); |
