summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-09-14 23:01:09 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2017-09-14 23:01:09 +0300
commitba768535b467bb2d342a1581450394f1148dc8ae (patch)
tree1a5e235f988b9601592981507a0975d911974b7c
parent7a95bdb092c66b6473aa2fc848862ae557ab08f7 (diff)
parent79d2c8bede2c93f9432d7da0bc2f76a195c90fc0 (diff)
downloadlinux-ba768535b467bb2d342a1581450394f1148dc8ae.tar.xz
Merge tag 'pinctrl-v4.14-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl
Pull pin control fixes from Linus Walleij: "This slew of fixes for pin control was noticed and patched up early, so to get the annoyance out of the way for -rc1 it would make sense to send them already. - Fix a build include in the Uniphier driver to keep pace with ongoing refactorings. - Fix a slew of minor semantic and syntactic issues as well as stricting up Kconfig for the new Spreadtrum driver. - Fix the GPIO interrupt set-up on the Marvell 37xx Armada as fallout for dynamically allocating irq descriptors from the core. (Also tagged for stable.) - Fix AMD register suspend/resume state spool/unspooling so that wakeup works as it should. (Also tagged for stable.)" * tag 'pinctrl-v4.14-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: pinctrl/amd: save pin registers over suspend/resume pinctrl: armada-37xx: Fix gpio interrupt setup pinctrl: sprd: fix off by one bugs pinctrl: sprd: check for allocation failure pinctrl: sprd: Restrict PINCTRL_SPRD to ARCH_SPRD or COMPILE_TEST pinctrl: sprd: fix build errors and dependencies pinctrl: sprd: make three local functions static pinctrl: uniphier: include <linux/build_bug.h> instead of <linux/bug.h>
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-37xx.c41
-rw-r--r--drivers/pinctrl/pinctrl-amd.c75
-rw-r--r--drivers/pinctrl/pinctrl-amd.h1
-rw-r--r--drivers/pinctrl/sprd/Kconfig3
-rw-r--r--drivers/pinctrl/sprd/pinctrl-sprd.c32
-rw-r--r--drivers/pinctrl/uniphier/pinctrl-uniphier.h2
6 files changed, 120 insertions, 34 deletions
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
index b8b6ab072cd0..71b944748304 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
@@ -550,9 +550,9 @@ static int armada_37xx_irq_set_wake(struct irq_data *d, unsigned int on)
spin_lock_irqsave(&info->irq_lock, flags);
val = readl(info->base + reg);
if (on)
- val |= d->mask;
+ val |= (BIT(d->hwirq % GPIO_PER_REG));
else
- val &= ~d->mask;
+ val &= ~(BIT(d->hwirq % GPIO_PER_REG));
writel(val, info->base + reg);
spin_unlock_irqrestore(&info->irq_lock, flags);
@@ -571,10 +571,10 @@ static int armada_37xx_irq_set_type(struct irq_data *d, unsigned int type)
val = readl(info->base + reg);
switch (type) {
case IRQ_TYPE_EDGE_RISING:
- val &= ~d->mask;
+ val &= ~(BIT(d->hwirq % GPIO_PER_REG));
break;
case IRQ_TYPE_EDGE_FALLING:
- val |= d->mask;
+ val |= (BIT(d->hwirq % GPIO_PER_REG));
break;
default:
spin_unlock_irqrestore(&info->irq_lock, flags);
@@ -624,11 +624,27 @@ static void armada_37xx_irq_handler(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
+static unsigned int armada_37xx_irq_startup(struct irq_data *d)
+{
+ struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+ int irq = d->hwirq - chip->irq_base;
+ /*
+ * The mask field is a "precomputed bitmask for accessing the
+ * chip registers" which was introduced for the generic
+ * irqchip framework. As we don't use this framework, we can
+ * reuse this field for our own usage.
+ */
+ d->mask = BIT(irq % GPIO_PER_REG);
+
+ armada_37xx_irq_unmask(d);
+
+ return 0;
+}
+
static int armada_37xx_irqchip_register(struct platform_device *pdev,
struct armada_37xx_pinctrl *info)
{
struct device_node *np = info->dev->of_node;
- int nrirqs = info->data->nr_pins;
struct gpio_chip *gc = &info->gpio_chip;
struct irq_chip *irqchip = &info->irq_chip;
struct resource res;
@@ -666,8 +682,8 @@ static int armada_37xx_irqchip_register(struct platform_device *pdev,
irqchip->irq_unmask = armada_37xx_irq_unmask;
irqchip->irq_set_wake = armada_37xx_irq_set_wake;
irqchip->irq_set_type = armada_37xx_irq_set_type;
+ irqchip->irq_startup = armada_37xx_irq_startup;
irqchip->name = info->data->name;
-
ret = gpiochip_irqchip_add(gc, irqchip, 0,
handle_edge_irq, IRQ_TYPE_NONE);
if (ret) {
@@ -680,19 +696,6 @@ static int armada_37xx_irqchip_register(struct platform_device *pdev,
* controller. But we do not take advantage of this and use
* the chained irq with all of them.
*/
- for (i = 0; i < nrirqs; i++) {
- struct irq_data *d = irq_get_irq_data(gc->irq_base + i);
-
- /*
- * The mask field is a "precomputed bitmask for
- * accessing the chip registers" which was introduced
- * for the generic irqchip framework. As we don't use
- * this framework, we can reuse this field for our own
- * usage.
- */
- d->mask = BIT(i % GPIO_PER_REG);
- }
-
for (i = 0; i < nr_irq_parent; i++) {
int irq = irq_of_parse_and_map(np, i);
diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c
index 38af1ec2df0c..3f6b34febbf1 100644
--- a/drivers/pinctrl/pinctrl-amd.c
+++ b/drivers/pinctrl/pinctrl-amd.c
@@ -36,6 +36,7 @@
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
+#include "core.h"
#include "pinctrl-utils.h"
#include "pinctrl-amd.h"
@@ -725,6 +726,69 @@ static const struct pinconf_ops amd_pinconf_ops = {
.pin_config_group_set = amd_pinconf_group_set,
};
+#ifdef CONFIG_PM_SLEEP
+static bool amd_gpio_should_save(struct amd_gpio *gpio_dev, unsigned int pin)
+{
+ const struct pin_desc *pd = pin_desc_get(gpio_dev->pctrl, pin);
+
+ if (!pd)
+ return false;
+
+ /*
+ * Only restore the pin if it is actually in use by the kernel (or
+ * by userspace).
+ */
+ if (pd->mux_owner || pd->gpio_owner ||
+ gpiochip_line_is_irq(&gpio_dev->gc, pin))
+ return true;
+
+ return false;
+}
+
+int amd_gpio_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct amd_gpio *gpio_dev = platform_get_drvdata(pdev);
+ struct pinctrl_desc *desc = gpio_dev->pctrl->desc;
+ int i;
+
+ for (i = 0; i < desc->npins; i++) {
+ int pin = desc->pins[i].number;
+
+ if (!amd_gpio_should_save(gpio_dev, pin))
+ continue;
+
+ gpio_dev->saved_regs[i] = readl(gpio_dev->base + pin*4);
+ }
+
+ return 0;
+}
+
+int amd_gpio_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct amd_gpio *gpio_dev = platform_get_drvdata(pdev);
+ struct pinctrl_desc *desc = gpio_dev->pctrl->desc;
+ int i;
+
+ for (i = 0; i < desc->npins; i++) {
+ int pin = desc->pins[i].number;
+
+ if (!amd_gpio_should_save(gpio_dev, pin))
+ continue;
+
+ writel(gpio_dev->saved_regs[i], gpio_dev->base + pin*4);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops amd_gpio_pm_ops = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(amd_gpio_suspend,
+ amd_gpio_resume)
+};
+#endif
+
static struct pinctrl_desc amd_pinctrl_desc = {
.pins = kerncz_pins,
.npins = ARRAY_SIZE(kerncz_pins),
@@ -764,6 +828,14 @@ static int amd_gpio_probe(struct platform_device *pdev)
return irq_base;
}
+#ifdef CONFIG_PM_SLEEP
+ gpio_dev->saved_regs = devm_kcalloc(&pdev->dev, amd_pinctrl_desc.npins,
+ sizeof(*gpio_dev->saved_regs),
+ GFP_KERNEL);
+ if (!gpio_dev->saved_regs)
+ return -ENOMEM;
+#endif
+
gpio_dev->pdev = pdev;
gpio_dev->gc.direction_input = amd_gpio_direction_input;
gpio_dev->gc.direction_output = amd_gpio_direction_output;
@@ -853,6 +925,9 @@ static struct platform_driver amd_gpio_driver = {
.driver = {
.name = "amd_gpio",
.acpi_match_table = ACPI_PTR(amd_gpio_acpi_match),
+#ifdef CONFIG_PM_SLEEP
+ .pm = &amd_gpio_pm_ops,
+#endif
},
.probe = amd_gpio_probe,
.remove = amd_gpio_remove,
diff --git a/drivers/pinctrl/pinctrl-amd.h b/drivers/pinctrl/pinctrl-amd.h
index 5b1cb965c767..8fa453a59da5 100644
--- a/drivers/pinctrl/pinctrl-amd.h
+++ b/drivers/pinctrl/pinctrl-amd.h
@@ -97,6 +97,7 @@ struct amd_gpio {
unsigned int hwbank_num;
struct resource *res;
struct platform_device *pdev;
+ u32 *saved_regs;
};
/* KERNCZ configuration*/
diff --git a/drivers/pinctrl/sprd/Kconfig b/drivers/pinctrl/sprd/Kconfig
index 6f4a7f9ac6fd..bc7f3fab22f1 100644
--- a/drivers/pinctrl/sprd/Kconfig
+++ b/drivers/pinctrl/sprd/Kconfig
@@ -4,6 +4,8 @@
config PINCTRL_SPRD
bool "Spreadtrum pinctrl driver"
+ depends on OF
+ depends on ARCH_SPRD || COMPILE_TEST
select PINMUX
select PINCONF
select GENERIC_PINCONF
@@ -13,5 +15,6 @@ config PINCTRL_SPRD
config PINCTRL_SPRD_SC9860
bool "Spreadtrum SC9860 pinctrl driver"
+ depends on PINCTRL_SPRD
help
Say Y here to enable Spreadtrum SC9860 pinctrl driver
diff --git a/drivers/pinctrl/sprd/pinctrl-sprd.c b/drivers/pinctrl/sprd/pinctrl-sprd.c
index 7e7b9ac7e836..63529911445c 100644
--- a/drivers/pinctrl/sprd/pinctrl-sprd.c
+++ b/drivers/pinctrl/sprd/pinctrl-sprd.c
@@ -353,13 +353,13 @@ static const struct pinctrl_ops sprd_pctrl_ops = {
.dt_free_map = pinctrl_utils_free_map,
};
-int sprd_pmx_get_function_count(struct pinctrl_dev *pctldev)
+static int sprd_pmx_get_function_count(struct pinctrl_dev *pctldev)
{
return PIN_FUNC_MAX;
}
-const char *sprd_pmx_get_function_name(struct pinctrl_dev *pctldev,
- unsigned int selector)
+static const char *sprd_pmx_get_function_name(struct pinctrl_dev *pctldev,
+ unsigned int selector)
{
switch (selector) {
case PIN_FUNC_1:
@@ -375,10 +375,10 @@ const char *sprd_pmx_get_function_name(struct pinctrl_dev *pctldev,
}
}
-int sprd_pmx_get_function_groups(struct pinctrl_dev *pctldev,
- unsigned int selector,
- const char * const **groups,
- unsigned int * const num_groups)
+static int sprd_pmx_get_function_groups(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ const char * const **groups,
+ unsigned int * const num_groups)
{
struct sprd_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
struct sprd_pinctrl_soc_info *info = pctl->info;
@@ -400,7 +400,7 @@ static int sprd_pmx_set_mux(struct pinctrl_dev *pctldev,
unsigned long reg;
unsigned int val = 0;
- if (group_selector > info->ngroups)
+ if (group_selector >= info->ngroups)
return -EINVAL;
switch (func_selector) {
@@ -734,7 +734,7 @@ static int sprd_pinconf_group_get(struct pinctrl_dev *pctldev,
struct sprd_pin_group *grp;
unsigned int pin_id;
- if (selector > info->ngroups)
+ if (selector >= info->ngroups)
return -EINVAL;
grp = &info->groups[selector];
@@ -753,7 +753,7 @@ static int sprd_pinconf_group_set(struct pinctrl_dev *pctldev,
struct sprd_pin_group *grp;
int ret, i;
- if (selector > info->ngroups)
+ if (selector >= info->ngroups)
return -EINVAL;
grp = &info->groups[selector];
@@ -813,7 +813,7 @@ static void sprd_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
const char *name;
int i, ret;
- if (selector > info->ngroups)
+ if (selector >= info->ngroups)
return;
grp = &info->groups[selector];
@@ -1100,12 +1100,16 @@ int sprd_pinctrl_remove(struct platform_device *pdev)
void sprd_pinctrl_shutdown(struct platform_device *pdev)
{
- struct pinctrl *pinctl = devm_pinctrl_get(&pdev->dev);
+ struct pinctrl *pinctl;
struct pinctrl_state *state;
+ pinctl = devm_pinctrl_get(&pdev->dev);
+ if (IS_ERR(pinctl))
+ return;
state = pinctrl_lookup_state(pinctl, "shutdown");
- if (!IS_ERR(state))
- pinctrl_select_state(pinctl, state);
+ if (IS_ERR(state))
+ return;
+ pinctrl_select_state(pinctl, state);
}
MODULE_DESCRIPTION("SPREADTRUM Pin Controller Driver");
diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier.h b/drivers/pinctrl/uniphier/pinctrl-uniphier.h
index c075ecb8e5db..0a3d2ac27503 100644
--- a/drivers/pinctrl/uniphier/pinctrl-uniphier.h
+++ b/drivers/pinctrl/uniphier/pinctrl-uniphier.h
@@ -17,7 +17,7 @@
#define __PINCTRL_UNIPHIER_H__
#include <linux/bitops.h>
-#include <linux/bug.h>
+#include <linux/build_bug.h>
#include <linux/kernel.h>
#include <linux/types.h>