diff options
Diffstat (limited to 'drivers/pinctrl/intel')
-rw-r--r-- | drivers/pinctrl/intel/pinctrl-baytrail.c | 3 | ||||
-rw-r--r-- | drivers/pinctrl/intel/pinctrl-cherryview.c | 60 | ||||
-rw-r--r-- | drivers/pinctrl/intel/pinctrl-intel.c | 58 | ||||
-rw-r--r-- | drivers/pinctrl/intel/pinctrl-merrifield.c | 3 |
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; |