Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ba768535 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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>
parents 7a95bdb0 79d2c8be
Loading
Loading
Loading
Loading
+22 −19
Original line number Diff line number Diff line
@@ -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);

+75 −0
Original line number Diff line number Diff line
@@ -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,
+1 −0
Original line number Diff line number Diff line
@@ -97,6 +97,7 @@ struct amd_gpio {
	unsigned int            hwbank_num;
	struct resource         *res;
	struct platform_device  *pdev;
	u32			*saved_regs;
};

/*  KERNCZ configuration*/
+3 −0
Original line number Diff line number Diff line
@@ -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
+18 −14
Original line number Diff line number Diff line
@@ -353,12 +353,12 @@ 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,
static const char *sprd_pmx_get_function_name(struct pinctrl_dev *pctldev,
					      unsigned int selector)
{
	switch (selector) {
@@ -375,7 +375,7 @@ const char *sprd_pmx_get_function_name(struct pinctrl_dev *pctldev,
	}
}

int sprd_pmx_get_function_groups(struct pinctrl_dev *pctldev,
static int sprd_pmx_get_function_groups(struct pinctrl_dev *pctldev,
					unsigned int selector,
					const char * const **groups,
					unsigned int * const num_groups)
@@ -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,11 +1100,15 @@ 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))
	if (IS_ERR(state))
		return;
	pinctrl_select_state(pinctl, state);
}

Loading