summaryrefslogtreecommitdiff
path: root/drivers/pinctrl/intel
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pinctrl/intel')
-rw-r--r--drivers/pinctrl/intel/pinctrl-baytrail.c3
-rw-r--r--drivers/pinctrl/intel/pinctrl-cherryview.c60
-rw-r--r--drivers/pinctrl/intel/pinctrl-intel.c58
-rw-r--r--drivers/pinctrl/intel/pinctrl-merrifield.c3
4 files changed, 70 insertions, 54 deletions
diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c
index d22a9fe2e6df..71bbeb9321ba 100644
--- a/drivers/pinctrl/intel/pinctrl-baytrail.c
+++ b/drivers/pinctrl/intel/pinctrl-baytrail.c
@@ -1808,6 +1808,8 @@ static int byt_pinctrl_probe(struct platform_device *pdev)
return PTR_ERR(vg->pctl_dev);
}
+ raw_spin_lock_init(&vg->lock);
+
ret = byt_gpio_probe(vg);
if (ret) {
pinctrl_unregister(vg->pctl_dev);
@@ -1815,7 +1817,6 @@ static int byt_pinctrl_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, vg);
- raw_spin_lock_init(&vg->lock);
pm_runtime_enable(&pdev->dev);
return 0;
diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c
index 5749a4eee746..30389f4ccab4 100644
--- a/drivers/pinctrl/intel/pinctrl-cherryview.c
+++ b/drivers/pinctrl/intel/pinctrl-cherryview.c
@@ -134,6 +134,7 @@ struct chv_gpio_pinrange {
* @gpio_ranges: An array of GPIO ranges in this community
* @ngpio_ranges: Number of GPIO ranges
* @ngpios: Total number of GPIOs in this community
+ * @nirqs: Total number of IRQs this community can generate
*/
struct chv_community {
const char *uid;
@@ -146,6 +147,7 @@ struct chv_community {
const struct chv_gpio_pinrange *gpio_ranges;
size_t ngpio_ranges;
size_t ngpios;
+ size_t nirqs;
};
struct chv_pin_context {
@@ -396,6 +398,12 @@ static const struct chv_community southwest_community = {
.gpio_ranges = southwest_gpio_ranges,
.ngpio_ranges = ARRAY_SIZE(southwest_gpio_ranges),
.ngpios = ARRAY_SIZE(southwest_pins),
+ /*
+ * Southwest community can benerate GPIO interrupts only for the
+ * first 8 interrupts. The upper half (8-15) can only be used to
+ * trigger GPEs.
+ */
+ .nirqs = 8,
};
static const struct pinctrl_pin_desc north_pins[] = {
@@ -479,6 +487,12 @@ static const struct chv_community north_community = {
.gpio_ranges = north_gpio_ranges,
.ngpio_ranges = ARRAY_SIZE(north_gpio_ranges),
.ngpios = ARRAY_SIZE(north_pins),
+ /*
+ * North community can benerate GPIO interrupts only for the first
+ * 8 interrupts. The upper half (8-15) can only be used to trigger
+ * GPEs.
+ */
+ .nirqs = 8,
};
static const struct pinctrl_pin_desc east_pins[] = {
@@ -521,6 +535,7 @@ static const struct chv_community east_community = {
.gpio_ranges = east_gpio_ranges,
.ngpio_ranges = ARRAY_SIZE(east_gpio_ranges),
.ngpios = ARRAY_SIZE(east_pins),
+ .nirqs = 16,
};
static const struct pinctrl_pin_desc southeast_pins[] = {
@@ -646,6 +661,7 @@ static const struct chv_community southeast_community = {
.gpio_ranges = southeast_gpio_ranges,
.ngpio_ranges = ARRAY_SIZE(southeast_gpio_ranges),
.ngpios = ARRAY_SIZE(southeast_pins),
+ .nirqs = 16,
};
static const struct chv_community *chv_communities[] = {
@@ -1497,7 +1513,7 @@ static void chv_gpio_irq_handler(struct irq_desc *desc)
chained_irq_enter(chip, desc);
pending = readl(pctrl->regs + CHV_INTSTAT);
- for_each_set_bit(intr_line, &pending, 16) {
+ for_each_set_bit(intr_line, &pending, pctrl->community->nirqs) {
unsigned irq, offset;
offset = pctrl->intr_lines[intr_line];
@@ -1520,8 +1536,9 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
chip->label = dev_name(pctrl->dev);
chip->parent = pctrl->dev;
chip->base = -1;
+ chip->irq_need_valid_mask = true;
- ret = gpiochip_add_data(chip, pctrl);
+ ret = devm_gpiochip_add_data(pctrl->dev, chip, pctrl);
if (ret) {
dev_err(pctrl->dev, "Failed to register gpiochip\n");
return ret;
@@ -1533,31 +1550,40 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
range->base, range->npins);
if (ret) {
dev_err(pctrl->dev, "failed to add GPIO pin range\n");
- goto fail;
+ return ret;
}
offset += range->npins;
}
- /* Mask and clear all interrupts */
- chv_writel(0, pctrl->regs + CHV_INTMASK);
+ /* Do not add GPIOs that can only generate GPEs to the IRQ domain */
+ for (i = 0; i < pctrl->community->npins; i++) {
+ const struct pinctrl_pin_desc *desc;
+ u32 intsel;
+
+ desc = &pctrl->community->pins[i];
+
+ intsel = readl(chv_padreg(pctrl, desc->number, CHV_PADCTRL0));
+ intsel &= CHV_PADCTRL0_INTSEL_MASK;
+ intsel >>= CHV_PADCTRL0_INTSEL_SHIFT;
+
+ if (intsel >= pctrl->community->nirqs)
+ clear_bit(i, chip->irq_valid_mask);
+ }
+
+ /* Clear all interrupts */
chv_writel(0xffff, pctrl->regs + CHV_INTSTAT);
ret = gpiochip_irqchip_add(chip, &chv_gpio_irqchip, 0,
- handle_simple_irq, IRQ_TYPE_NONE);
+ handle_bad_irq, IRQ_TYPE_NONE);
if (ret) {
dev_err(pctrl->dev, "failed to add IRQ chip\n");
- goto fail;
+ return ret;
}
gpiochip_set_chained_irqchip(chip, &chv_gpio_irqchip, irq,
chv_gpio_irq_handler);
return 0;
-
-fail:
- gpiochip_remove(chip);
-
- return ret;
}
static int chv_pinctrl_probe(struct platform_device *pdev)
@@ -1625,15 +1651,6 @@ static int chv_pinctrl_probe(struct platform_device *pdev)
return 0;
}
-static int chv_pinctrl_remove(struct platform_device *pdev)
-{
- struct chv_pinctrl *pctrl = platform_get_drvdata(pdev);
-
- gpiochip_remove(&pctrl->chip);
-
- return 0;
-}
-
#ifdef CONFIG_PM_SLEEP
static int chv_pinctrl_suspend(struct device *dev)
{
@@ -1730,7 +1747,6 @@ MODULE_DEVICE_TABLE(acpi, chv_pinctrl_acpi_match);
static struct platform_driver chv_pinctrl_driver = {
.probe = chv_pinctrl_probe,
- .remove = chv_pinctrl_remove,
.driver = {
.name = "cherryview-pinctrl",
.pm = &chv_pinctrl_pm_ops,
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
index 257cab129692..01443762e570 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -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 */
@@ -86,6 +87,7 @@ struct intel_pinctrl_context {
* @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;
@@ -97,6 +99,7 @@ struct intel_pinctrl {
struct intel_community *communities;
size_t ncommunities;
struct intel_pinctrl_context context;
+ int irq;
};
#define pin_to_padno(c, p) ((p) - (c)->pin_base)
@@ -793,38 +796,12 @@ static int intel_gpio_irq_wake(struct irq_data *d, unsigned int on)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
- const struct intel_community *community;
unsigned pin = irqd_to_hwirq(d);
- unsigned padno, gpp, gpp_offset;
- unsigned long flags;
- u32 gpe_en;
-
- community = intel_get_community(pctrl, pin);
- if (!community)
- return -EINVAL;
-
- raw_spin_lock_irqsave(&pctrl->lock, flags);
-
- padno = pin_to_padno(community, pin);
- gpp = padno / community->gpp_size;
- gpp_offset = padno % community->gpp_size;
- /* Clear the existing wake status */
- writel(BIT(gpp_offset), community->regs + GPI_GPE_STS + gpp * 4);
-
- /*
- * The controller will generate wake when GPE of the corresponding
- * pad is enabled and it is not routed to SCI (GPIROUTSCI is not
- * set).
- */
- gpe_en = readl(community->regs + GPI_GPE_EN + gpp * 4);
if (on)
- gpe_en |= BIT(gpp_offset);
+ enable_irq_wake(pctrl->irq);
else
- gpe_en &= ~BIT(gpp_offset);
- writel(gpe_en, community->regs + GPI_GPE_EN + gpp * 4);
-
- raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+ disable_irq_wake(pctrl->irq);
dev_dbg(pctrl->dev, "%sable wake for pin %u\n", on ? "en" : "dis", pin);
return 0;
@@ -905,6 +882,7 @@ static int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq)
pctrl->chip.label = dev_name(pctrl->dev);
pctrl->chip.parent = pctrl->dev;
pctrl->chip.base = -1;
+ pctrl->irq = irq;
ret = gpiochip_add_data(&pctrl->chip, pctrl);
if (ret) {
@@ -1079,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);
@@ -1092,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));
@@ -1153,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);
diff --git a/drivers/pinctrl/intel/pinctrl-merrifield.c b/drivers/pinctrl/intel/pinctrl-merrifield.c
index eb4990ff26ca..7826c7f0cb7c 100644
--- a/drivers/pinctrl/intel/pinctrl-merrifield.c
+++ b/drivers/pinctrl/intel/pinctrl-merrifield.c
@@ -11,6 +11,7 @@
#include <linux/bitops.h>
#include <linux/err.h>
+#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/pinconf.h>
@@ -853,7 +854,7 @@ static int mrfld_pinctrl_probe(struct platform_device *pdev)
*/
nfamilies = ARRAY_SIZE(mrfld_families),
families = devm_kmemdup(&pdev->dev, mrfld_families,
- nfamilies * sizeof(mrfld_families),
+ sizeof(mrfld_families),
GFP_KERNEL);
if (!families)
return -ENOMEM;