Update Linux to v5.10.109
Sourced from [1]
[1] https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.109.tar.xz
Change-Id: I19bca9fc6762d4e63bcf3e4cba88bbe560d9c76c
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
index 4e89bbf..348c670 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -8,8 +8,8 @@
*/
#include <linux/acpi.h>
-#include <linux/interrupt.h>
#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
#include <linux/log2.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -62,10 +62,10 @@
#define PADCFG1_TERM_UP BIT(13)
#define PADCFG1_TERM_SHIFT 10
#define PADCFG1_TERM_MASK GENMASK(12, 10)
-#define PADCFG1_TERM_20K 4
-#define PADCFG1_TERM_2K 3
-#define PADCFG1_TERM_5K 2
-#define PADCFG1_TERM_1K 1
+#define PADCFG1_TERM_20K BIT(2)
+#define PADCFG1_TERM_5K BIT(1)
+#define PADCFG1_TERM_1K BIT(0)
+#define PADCFG1_TERM_833 (BIT(1) | BIT(0))
#define PADCFG2 0x008
#define PADCFG2_DEBEN BIT(0)
@@ -85,39 +85,6 @@
u32 *hostown;
};
-struct intel_pinctrl_context {
- struct intel_pad_context *pads;
- struct intel_community_context *communities;
-};
-
-/**
- * struct intel_pinctrl - Intel pinctrl private structure
- * @dev: Pointer to the device structure
- * @lock: Lock to serialize register access
- * @pctldesc: Pin controller description
- * @pctldev: Pointer to the pin controller device
- * @chip: GPIO chip in this pin controller
- * @irqchip: IRQ chip in this pin controller
- * @soc: SoC/PCH specific pin configuration data
- * @communities: All communities in this pin controller
- * @ncommunities: Number of communities in this pin controller
- * @context: Configuration saved over system sleep
- * @irq: pinctrl/GPIO chip irq number
- */
-struct intel_pinctrl {
- struct device *dev;
- raw_spinlock_t lock;
- struct pinctrl_desc pctldesc;
- struct pinctrl_dev *pctldev;
- struct gpio_chip chip;
- struct irq_chip irqchip;
- const struct intel_pinctrl_soc_data *soc;
- struct intel_community *communities;
- size_t ncommunities;
- struct intel_pinctrl_context context;
- int irq;
-};
-
#define pin_to_padno(c, p) ((p) - (c)->pin_base)
#define padgroup_offset(g, p) ((p) - (g)->base)
@@ -468,11 +435,20 @@
{
u32 value;
+ value = readl(padcfg0);
+
/* Put the pad into GPIO mode */
- value = readl(padcfg0) & ~PADCFG0_PMODE_MASK;
+ value &= ~PADCFG0_PMODE_MASK;
+ value |= PADCFG0_PMODE_GPIO;
+
+ /* Disable TX buffer and enable RX (this will be input) */
+ value &= ~PADCFG0_GPIORXDIS;
+ value |= PADCFG0_GPIOTXDIS;
+
/* Disable SCI/SMI/NMI generation */
value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI);
value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI);
+
writel(value, padcfg0);
}
@@ -484,6 +460,8 @@
void __iomem *padcfg0;
unsigned long flags;
+ padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
+
raw_spin_lock_irqsave(&pctrl->lock, flags);
if (!intel_pad_owned_by_host(pctrl, pin)) {
@@ -496,8 +474,6 @@
return 0;
}
- padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
-
/*
* If pin is already configured in GPIO mode, we assume that
* firmware provides correct settings. In such case we avoid
@@ -511,9 +487,6 @@
intel_gpio_set_gpio_mode(padcfg0);
- /* Disable TX buffer and enable RX (this will be input) */
- __intel_gpio_set_direction(padcfg0, true);
-
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
return 0;
@@ -527,11 +500,10 @@
void __iomem *padcfg0;
unsigned long flags;
- raw_spin_lock_irqsave(&pctrl->lock, flags);
-
padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
- __intel_gpio_set_direction(padcfg0, input);
+ raw_spin_lock_irqsave(&pctrl->lock, flags);
+ __intel_gpio_set_direction(padcfg0, input);
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
return 0;
@@ -546,20 +518,21 @@
.gpio_set_direction = intel_gpio_set_direction,
};
-static int intel_config_get(struct pinctrl_dev *pctldev, unsigned int pin,
- unsigned long *config)
+static int intel_config_get_pull(struct intel_pinctrl *pctrl, unsigned int pin,
+ enum pin_config_param param, u32 *arg)
{
- struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
- enum pin_config_param param = pinconf_to_config_param(*config);
const struct intel_community *community;
+ void __iomem *padcfg1;
+ unsigned long flags;
u32 value, term;
- u32 arg = 0;
-
- if (!intel_pad_owned_by_host(pctrl, pin))
- return -ENOTSUPP;
community = intel_get_community(pctrl, pin);
- value = readl(intel_get_padcfg(pctrl, pin, PADCFG1));
+ padcfg1 = intel_get_padcfg(pctrl, pin, PADCFG1);
+
+ raw_spin_lock_irqsave(&pctrl->lock, flags);
+ value = readl(padcfg1);
+ raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+
term = (value & PADCFG1_TERM_MASK) >> PADCFG1_TERM_SHIFT;
switch (param) {
@@ -573,17 +546,17 @@
return -EINVAL;
switch (term) {
- case PADCFG1_TERM_1K:
- arg = 1000;
+ case PADCFG1_TERM_833:
+ *arg = 833;
break;
- case PADCFG1_TERM_2K:
- arg = 2000;
+ case PADCFG1_TERM_1K:
+ *arg = 1000;
break;
case PADCFG1_TERM_5K:
- arg = 5000;
+ *arg = 5000;
break;
case PADCFG1_TERM_20K:
- arg = 20000;
+ *arg = 20000;
break;
}
@@ -594,39 +567,83 @@
return -EINVAL;
switch (term) {
+ case PADCFG1_TERM_833:
+ if (!(community->features & PINCTRL_FEATURE_1K_PD))
+ return -EINVAL;
+ *arg = 833;
+ break;
case PADCFG1_TERM_1K:
if (!(community->features & PINCTRL_FEATURE_1K_PD))
return -EINVAL;
- arg = 1000;
+ *arg = 1000;
break;
case PADCFG1_TERM_5K:
- arg = 5000;
+ *arg = 5000;
break;
case PADCFG1_TERM_20K:
- arg = 20000;
+ *arg = 20000;
break;
}
break;
- case PIN_CONFIG_INPUT_DEBOUNCE: {
- void __iomem *padcfg2;
- u32 v;
-
- padcfg2 = intel_get_padcfg(pctrl, pin, PADCFG2);
- if (!padcfg2)
- return -ENOTSUPP;
-
- v = readl(padcfg2);
- if (!(v & PADCFG2_DEBEN))
- return -EINVAL;
-
- v = (v & PADCFG2_DEBOUNCE_MASK) >> PADCFG2_DEBOUNCE_SHIFT;
- arg = BIT(v) * DEBOUNCE_PERIOD_NSEC / NSEC_PER_USEC;
-
- break;
+ default:
+ return -EINVAL;
}
+ return 0;
+}
+
+static int intel_config_get_debounce(struct intel_pinctrl *pctrl, unsigned int pin,
+ enum pin_config_param param, u32 *arg)
+{
+ void __iomem *padcfg2;
+ unsigned long flags;
+ unsigned long v;
+ u32 value2;
+
+ padcfg2 = intel_get_padcfg(pctrl, pin, PADCFG2);
+ if (!padcfg2)
+ return -ENOTSUPP;
+
+ raw_spin_lock_irqsave(&pctrl->lock, flags);
+ value2 = readl(padcfg2);
+ raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+ if (!(value2 & PADCFG2_DEBEN))
+ return -EINVAL;
+
+ v = (value2 & PADCFG2_DEBOUNCE_MASK) >> PADCFG2_DEBOUNCE_SHIFT;
+ *arg = BIT(v) * DEBOUNCE_PERIOD_NSEC / NSEC_PER_USEC;
+
+ return 0;
+}
+
+static int intel_config_get(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned long *config)
+{
+ struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ enum pin_config_param param = pinconf_to_config_param(*config);
+ u32 arg = 0;
+ int ret;
+
+ if (!intel_pad_owned_by_host(pctrl, pin))
+ return -ENOTSUPP;
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ case PIN_CONFIG_BIAS_PULL_UP:
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ ret = intel_config_get_pull(pctrl, pin, param, &arg);
+ if (ret)
+ return ret;
+ break;
+
+ case PIN_CONFIG_INPUT_DEBOUNCE:
+ ret = intel_config_get_debounce(pctrl, pin, param, &arg);
+ if (ret)
+ return ret;
+ break;
+
default:
return -ENOTSUPP;
}
@@ -646,10 +663,11 @@
int ret = 0;
u32 value;
- raw_spin_lock_irqsave(&pctrl->lock, flags);
-
community = intel_get_community(pctrl, pin);
padcfg1 = intel_get_padcfg(pctrl, pin, PADCFG1);
+
+ raw_spin_lock_irqsave(&pctrl->lock, flags);
+
value = readl(padcfg1);
switch (param) {
@@ -673,12 +691,12 @@
case 5000:
value |= PADCFG1_TERM_5K << PADCFG1_TERM_SHIFT;
break;
- case 2000:
- value |= PADCFG1_TERM_2K << PADCFG1_TERM_SHIFT;
- break;
case 1000:
value |= PADCFG1_TERM_1K << PADCFG1_TERM_SHIFT;
break;
+ case 833:
+ value |= PADCFG1_TERM_833 << PADCFG1_TERM_SHIFT;
+ break;
default:
ret = -EINVAL;
}
@@ -706,6 +724,13 @@
}
value |= PADCFG1_TERM_1K << PADCFG1_TERM_SHIFT;
break;
+ case 833:
+ if (!(community->features & PINCTRL_FEATURE_1K_PD)) {
+ ret = -EINVAL;
+ break;
+ }
+ value |= PADCFG1_TERM_833 << PADCFG1_TERM_SHIFT;
+ break;
default:
ret = -EINVAL;
}
@@ -727,7 +752,6 @@
void __iomem *padcfg0, *padcfg2;
unsigned long flags;
u32 value0, value2;
- int ret = 0;
padcfg2 = intel_get_padcfg(pctrl, pin, PADCFG2);
if (!padcfg2)
@@ -749,23 +773,22 @@
v = order_base_2(debounce * NSEC_PER_USEC / DEBOUNCE_PERIOD_NSEC);
if (v < 3 || v > 15) {
- ret = -EINVAL;
- goto exit_unlock;
- } else {
- /* Enable glitch filter and debouncer */
- value0 |= PADCFG0_PREGFRXSEL;
- value2 |= v << PADCFG2_DEBOUNCE_SHIFT;
- value2 |= PADCFG2_DEBEN;
+ raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+ return -EINVAL;
}
+
+ /* Enable glitch filter and debouncer */
+ value0 |= PADCFG0_PREGFRXSEL;
+ value2 |= v << PADCFG2_DEBOUNCE_SHIFT;
+ value2 |= PADCFG2_DEBEN;
}
writel(value0, padcfg0);
writel(value2, padcfg2);
-exit_unlock:
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
- return ret;
+ return 0;
}
static int intel_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
@@ -839,7 +862,7 @@
for (j = 0; j < comm->ngpps; j++) {
const struct intel_padgroup *pgrp = &comm->gpps[j];
- if (pgrp->gpio_base < 0)
+ if (pgrp->gpio_base == INTEL_GPIO_BASE_NOMAP)
continue;
if (offset >= pgrp->gpio_base &&
@@ -935,6 +958,7 @@
static int intel_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
{
struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
+ unsigned long flags;
void __iomem *reg;
u32 padcfg0;
int pin;
@@ -947,12 +971,16 @@
if (!reg)
return -EINVAL;
+ raw_spin_lock_irqsave(&pctrl->lock, flags);
padcfg0 = readl(reg);
-
+ raw_spin_unlock_irqrestore(&pctrl->lock, flags);
if (padcfg0 & PADCFG0_PMODE_MASK)
return -EINVAL;
- return !!(padcfg0 & PADCFG0_GPIOTXDIS);
+ if (padcfg0 & PADCFG0_GPIOTXDIS)
+ return GPIO_LINE_DIRECTION_IN;
+
+ return GPIO_LINE_DIRECTION_OUT;
}
static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
@@ -1119,34 +1147,39 @@
return 0;
}
-static irqreturn_t intel_gpio_community_irq_handler(struct intel_pinctrl *pctrl,
- const struct intel_community *community)
+static int intel_gpio_community_irq_handler(struct intel_pinctrl *pctrl,
+ const struct intel_community *community)
{
struct gpio_chip *gc = &pctrl->chip;
- irqreturn_t ret = IRQ_NONE;
- int gpp;
+ unsigned int gpp;
+ int ret = 0;
for (gpp = 0; gpp < community->ngpps; gpp++) {
const struct intel_padgroup *padgrp = &community->gpps[gpp];
unsigned long pending, enabled, gpp_offset;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&pctrl->lock, flags);
pending = readl(community->regs + community->is_offset +
padgrp->reg_num * 4);
enabled = readl(community->regs + community->ie_offset +
padgrp->reg_num * 4);
+ raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+
/* Only interrupts that are enabled */
pending &= enabled;
for_each_set_bit(gpp_offset, &pending, padgrp->size) {
- unsigned irq;
+ unsigned int irq;
irq = irq_find_mapping(gc->irq.domain,
padgrp->gpio_base + gpp_offset);
generic_handle_irq(irq);
-
- ret |= IRQ_HANDLED;
}
+
+ ret += pending ? 1 : 0;
}
return ret;
@@ -1156,27 +1189,60 @@
{
const struct intel_community *community;
struct intel_pinctrl *pctrl = data;
- irqreturn_t ret = IRQ_NONE;
- int i;
+ unsigned int i;
+ int ret = 0;
/* Need to check all communities for pending interrupts */
for (i = 0; i < pctrl->ncommunities; i++) {
community = &pctrl->communities[i];
- ret |= intel_gpio_community_irq_handler(pctrl, community);
+ ret += intel_gpio_community_irq_handler(pctrl, community);
}
- return ret;
+ return IRQ_RETVAL(ret);
}
-static int intel_gpio_add_pin_ranges(struct intel_pinctrl *pctrl,
- const struct intel_community *community)
+static void intel_gpio_irq_init(struct intel_pinctrl *pctrl)
+{
+ int i;
+
+ for (i = 0; i < pctrl->ncommunities; i++) {
+ const struct intel_community *community;
+ void __iomem *base;
+ unsigned int gpp;
+
+ community = &pctrl->communities[i];
+ base = community->regs;
+
+ for (gpp = 0; gpp < community->ngpps; gpp++) {
+ /* Mask and clear all interrupts */
+ writel(0, base + community->ie_offset + gpp * 4);
+ writel(0xffff, base + community->is_offset + gpp * 4);
+ }
+ }
+}
+
+static int intel_gpio_irq_init_hw(struct gpio_chip *gc)
+{
+ struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
+
+ /*
+ * Make sure the interrupt lines are in a proper state before
+ * further configuration.
+ */
+ intel_gpio_irq_init(pctrl);
+
+ return 0;
+}
+
+static int intel_gpio_add_community_ranges(struct intel_pinctrl *pctrl,
+ const struct intel_community *community)
{
int ret = 0, i;
for (i = 0; i < community->ngpps; i++) {
const struct intel_padgroup *gpp = &community->gpps[i];
- if (gpp->gpio_base < 0)
+ if (gpp->gpio_base == INTEL_GPIO_BASE_NOMAP)
continue;
ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev),
@@ -1189,7 +1255,25 @@
return ret;
}
-static unsigned intel_gpio_ngpio(const struct intel_pinctrl *pctrl)
+static int intel_gpio_add_pin_ranges(struct gpio_chip *gc)
+{
+ struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
+ int ret, i;
+
+ for (i = 0; i < pctrl->ncommunities; i++) {
+ struct intel_community *community = &pctrl->communities[i];
+
+ ret = intel_gpio_add_community_ranges(pctrl, community);
+ if (ret) {
+ dev_err(pctrl->dev, "failed to add GPIO pin range\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static unsigned int intel_gpio_ngpio(const struct intel_pinctrl *pctrl)
{
const struct intel_community *community;
unsigned int ngpio = 0;
@@ -1200,7 +1284,7 @@
for (j = 0; j < community->ngpps; j++) {
const struct intel_padgroup *gpp = &community->gpps[j];
- if (gpp->gpio_base < 0)
+ if (gpp->gpio_base == INTEL_GPIO_BASE_NOMAP)
continue;
if (gpp->gpio_base + gpp->size > ngpio)
@@ -1213,7 +1297,8 @@
static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq)
{
- int ret, i;
+ int ret;
+ struct gpio_irq_chip *girq;
pctrl->chip = intel_gpio_chip;
@@ -1222,6 +1307,7 @@
pctrl->chip.label = dev_name(pctrl->dev);
pctrl->chip.parent = pctrl->dev;
pctrl->chip.base = -1;
+ pctrl->chip.add_pin_ranges = intel_gpio_add_pin_ranges;
pctrl->irq = irq;
/* Setup IRQ chip */
@@ -1233,26 +1319,9 @@
pctrl->irqchip.irq_set_wake = intel_gpio_irq_wake;
pctrl->irqchip.flags = IRQCHIP_MASK_ON_SUSPEND;
- ret = devm_gpiochip_add_data(pctrl->dev, &pctrl->chip, pctrl);
- if (ret) {
- dev_err(pctrl->dev, "failed to register gpiochip\n");
- return ret;
- }
-
- for (i = 0; i < pctrl->ncommunities; i++) {
- struct intel_community *community = &pctrl->communities[i];
-
- ret = intel_gpio_add_pin_ranges(pctrl, community);
- if (ret) {
- dev_err(pctrl->dev, "failed to add GPIO pin range\n");
- return ret;
- }
- }
-
/*
- * We need to request the interrupt here (instead of providing chip
- * to the irq directly) because on some platforms several GPIO
- * controllers share the same interrupt line.
+ * On some platforms several GPIO controllers share the same interrupt
+ * line.
*/
ret = devm_request_irq(pctrl->dev, irq, intel_gpio_irq,
IRQF_SHARED | IRQF_NO_THREAD,
@@ -1262,14 +1331,21 @@
return ret;
}
- ret = gpiochip_irqchip_add(&pctrl->chip, &pctrl->irqchip, 0,
- handle_bad_irq, IRQ_TYPE_NONE);
+ girq = &pctrl->chip.irq;
+ girq->chip = &pctrl->irqchip;
+ /* This will let us handle the IRQ in the driver */
+ girq->parent_handler = NULL;
+ girq->num_parents = 0;
+ girq->default_type = IRQ_TYPE_NONE;
+ girq->handler = handle_bad_irq;
+ girq->init_hw = intel_gpio_irq_init_hw;
+
+ ret = devm_gpiochip_add_data(pctrl->dev, &pctrl->chip, pctrl);
if (ret) {
- dev_err(pctrl->dev, "failed to add irqchip\n");
+ dev_err(pctrl->dev, "failed to register gpiochip\n");
return ret;
}
- gpiochip_set_chained_irqchip(&pctrl->chip, &pctrl->irqchip, irq, NULL);
return 0;
}
@@ -1305,8 +1381,18 @@
if (gpps[i].size > 32)
return -EINVAL;
- if (!gpps[i].gpio_base)
- gpps[i].gpio_base = gpps[i].base;
+ /* Special treatment for GPIO base */
+ switch (gpps[i].gpio_base) {
+ case INTEL_GPIO_BASE_MATCH:
+ gpps[i].gpio_base = gpps[i].base;
+ break;
+ case INTEL_GPIO_BASE_ZERO:
+ gpps[i].gpio_base = 0;
+ break;
+ case INTEL_GPIO_BASE_NOMAP:
+ default:
+ break;
+ }
gpps[i].padown_num = padown_num;
@@ -1376,9 +1462,6 @@
struct intel_pinctrl *pctrl;
int i, ret, irq;
- if (!soc_data)
- return -EINVAL;
-
pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
if (!pctrl)
return -ENOMEM;
@@ -1467,12 +1550,27 @@
const struct intel_pinctrl_soc_data *data;
data = device_get_match_data(&pdev->dev);
+ if (!data)
+ return -ENODATA;
+
return intel_pinctrl_probe(pdev, data);
}
EXPORT_SYMBOL_GPL(intel_pinctrl_probe_by_hid);
int intel_pinctrl_probe_by_uid(struct platform_device *pdev)
{
+ const struct intel_pinctrl_soc_data *data;
+
+ data = intel_pinctrl_get_soc_data(pdev);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ return intel_pinctrl_probe(pdev, data);
+}
+EXPORT_SYMBOL_GPL(intel_pinctrl_probe_by_uid);
+
+const struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_device *pdev)
+{
const struct intel_pinctrl_soc_data *data = NULL;
const struct intel_pinctrl_soc_data **table;
struct acpi_device *adev;
@@ -1494,15 +1592,15 @@
id = platform_get_device_id(pdev);
if (!id)
- return -ENODEV;
+ return ERR_PTR(-ENODEV);
table = (const struct intel_pinctrl_soc_data **)id->driver_data;
data = table[pdev->id];
}
- return intel_pinctrl_probe(pdev, data);
+ return data ?: ERR_PTR(-ENODATA);
}
-EXPORT_SYMBOL_GPL(intel_pinctrl_probe_by_uid);
+EXPORT_SYMBOL_GPL(intel_pinctrl_get_soc_data);
#ifdef CONFIG_PM_SLEEP
static bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int pin)
@@ -1570,49 +1668,69 @@
}
EXPORT_SYMBOL_GPL(intel_pinctrl_suspend_noirq);
-static void intel_gpio_irq_init(struct intel_pinctrl *pctrl)
-{
- size_t i;
-
- for (i = 0; i < pctrl->ncommunities; i++) {
- const struct intel_community *community;
- void __iomem *base;
- unsigned int gpp;
-
- community = &pctrl->communities[i];
- base = community->regs;
-
- for (gpp = 0; gpp < community->ngpps; gpp++) {
- /* Mask and clear all interrupts */
- writel(0, base + community->ie_offset + gpp * 4);
- writel(0xffff, base + community->is_offset + gpp * 4);
- }
- }
-}
-
-static u32
-intel_gpio_is_requested(struct gpio_chip *chip, int base, unsigned int size)
-{
- u32 requested = 0;
- unsigned int i;
-
- for (i = 0; i < size; i++)
- if (gpiochip_is_requested(chip, base + i))
- requested |= BIT(i);
-
- return requested;
-}
-
-static u32
-intel_gpio_update_pad_mode(void __iomem *hostown, u32 mask, u32 value)
+static bool intel_gpio_update_reg(void __iomem *reg, u32 mask, u32 value)
{
u32 curr, updated;
- curr = readl(hostown);
- updated = (curr & ~mask) | (value & mask);
- writel(updated, hostown);
+ curr = readl(reg);
- return curr;
+ updated = (curr & ~mask) | (value & mask);
+ if (curr == updated)
+ return false;
+
+ writel(updated, reg);
+ return true;
+}
+
+static void intel_restore_hostown(struct intel_pinctrl *pctrl, unsigned int c,
+ void __iomem *base, unsigned int gpp, u32 saved)
+{
+ const struct intel_community *community = &pctrl->communities[c];
+ const struct intel_padgroup *padgrp = &community->gpps[gpp];
+ struct device *dev = pctrl->dev;
+ const char *dummy;
+ u32 requested = 0;
+ unsigned int i;
+
+ if (padgrp->gpio_base == INTEL_GPIO_BASE_NOMAP)
+ return;
+
+ for_each_requested_gpio_in_range(&pctrl->chip, i, padgrp->gpio_base, padgrp->size, dummy)
+ requested |= BIT(i);
+
+ if (!intel_gpio_update_reg(base + gpp * 4, requested, saved))
+ return;
+
+ dev_dbg(dev, "restored hostown %u/%u %#08x\n", c, gpp, readl(base + gpp * 4));
+}
+
+static void intel_restore_intmask(struct intel_pinctrl *pctrl, unsigned int c,
+ void __iomem *base, unsigned int gpp, u32 saved)
+{
+ struct device *dev = pctrl->dev;
+
+ if (!intel_gpio_update_reg(base + gpp * 4, ~0U, saved))
+ return;
+
+ dev_dbg(dev, "restored mask %u/%u %#08x\n", c, gpp, readl(base + gpp * 4));
+}
+
+static void intel_restore_padcfg(struct intel_pinctrl *pctrl, unsigned int pin,
+ unsigned int reg, u32 saved)
+{
+ u32 mask = (reg == PADCFG0) ? PADCFG0_GPIORXSTATE : 0;
+ unsigned int n = reg / sizeof(u32);
+ struct device *dev = pctrl->dev;
+ void __iomem *padcfg;
+
+ padcfg = intel_get_padcfg(pctrl, pin, reg);
+ if (!padcfg)
+ return;
+
+ if (!intel_gpio_update_reg(padcfg, ~mask, saved))
+ return;
+
+ dev_dbg(dev, "restored pin %u padcfg%u %#08x\n", pin, n, readl(padcfg));
}
int intel_pinctrl_resume_noirq(struct device *dev)
@@ -1628,37 +1746,13 @@
pads = pctrl->context.pads;
for (i = 0; i < pctrl->soc->npins; i++) {
const struct pinctrl_pin_desc *desc = &pctrl->soc->pins[i];
- void __iomem *padcfg;
- u32 val;
if (!intel_pinctrl_should_save(pctrl, desc->number))
continue;
- padcfg = intel_get_padcfg(pctrl, desc->number, PADCFG0);
- val = readl(padcfg) & ~PADCFG0_GPIORXSTATE;
- if (val != pads[i].padcfg0) {
- writel(pads[i].padcfg0, padcfg);
- dev_dbg(dev, "restored pin %u padcfg0 %#08x\n",
- desc->number, readl(padcfg));
- }
-
- padcfg = intel_get_padcfg(pctrl, desc->number, PADCFG1);
- val = readl(padcfg);
- if (val != pads[i].padcfg1) {
- writel(pads[i].padcfg1, padcfg);
- dev_dbg(dev, "restored pin %u padcfg1 %#08x\n",
- desc->number, readl(padcfg));
- }
-
- padcfg = intel_get_padcfg(pctrl, desc->number, PADCFG2);
- if (padcfg) {
- val = readl(padcfg);
- if (val != pads[i].padcfg2) {
- writel(pads[i].padcfg2, padcfg);
- dev_dbg(dev, "restored pin %u padcfg2 %#08x\n",
- desc->number, readl(padcfg));
- }
- }
+ intel_restore_padcfg(pctrl, desc->number, PADCFG0, pads[i].padcfg0);
+ intel_restore_padcfg(pctrl, desc->number, PADCFG1, pads[i].padcfg1);
+ intel_restore_padcfg(pctrl, desc->number, PADCFG2, pads[i].padcfg2);
}
communities = pctrl->context.communities;
@@ -1668,30 +1762,12 @@
unsigned int gpp;
base = community->regs + community->ie_offset;
- for (gpp = 0; gpp < community->ngpps; gpp++) {
- writel(communities[i].intmask[gpp], base + gpp * 4);
- dev_dbg(dev, "restored mask %d/%u %#08x\n", i, gpp,
- readl(base + gpp * 4));
- }
+ for (gpp = 0; gpp < community->ngpps; gpp++)
+ intel_restore_intmask(pctrl, i, base, gpp, communities[i].intmask[gpp]);
base = community->regs + community->hostown_offset;
- for (gpp = 0; gpp < community->ngpps; gpp++) {
- const struct intel_padgroup *padgrp = &community->gpps[gpp];
- u32 requested = 0, value = 0;
- u32 saved = communities[i].hostown[gpp];
-
- if (padgrp->gpio_base < 0)
- continue;
-
- requested = intel_gpio_is_requested(&pctrl->chip,
- padgrp->gpio_base, padgrp->size);
- value = intel_gpio_update_pad_mode(base + gpp * 4,
- requested, saved);
- if ((value ^ saved) & requested) {
- dev_warn(dev, "restore hostown %d/%u %#8x->%#8x\n",
- i, gpp, value, saved);
- }
- }
+ for (gpp = 0; gpp < community->ngpps; gpp++)
+ intel_restore_hostown(pctrl, i, base, gpp, communities[i].hostown[gpp]);
}
return 0;