aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-04-29 09:40:35 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2013-04-29 09:40:35 -0700
commit000a74f41e601bc4e36a760aa42f219a019c5391 (patch)
tree6ff200c5112af40ef97afacac07f862aa428edb9 /drivers
parent8127b39e700f965a60fca443d23f3e171bf7c3a9 (diff)
parent42fed7ba44e4e8c1fb27b28ad14490cb1daff3c7 (diff)
Merge tag 'pinctrl-for-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl
Pull pinctrl update from Linus Walleij: "These are the pinctrl changes for v3.10: - Patrice Chotard contributed a new configuration debugfs interface and reintroduced fine-grained locking into the core: instead of having a "big pinctrl lock" we have a per-controller lock and specialized locks for the global controller and pinctrl handle lists. - Haoijan Zhuang deleted all the PXA and MMP2 pinctrl drivers and replaced them with pinctrl-single (which is also used by other SoCs) so we are gaining consolidation. The platform particulars now come in through the device tree. - Haoijan also added support for generic pin config into the pinctrl-single driver which is another big consolidation win. - Finally also GPIO ranges are now supported by the pinctrl-single driver. - Tomasz Figa contributed a new Samsung S3C pinctrl driver, bringing more of the older Samsung platforms under the pinctrl umbrella and out of arch/arm. - Maxime Ripard contributed new Allwinner A10/A13 drivers. - Sachin Kamat, Wei Yongjun and Axel Lin did a lot of cleanups." * tag 'pinctrl-for-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (66 commits) pinctrl: move subsystem mutex to pinctrl_dev struct pinctrl/pinconfig: fix misplaced goto pinctrl: s3c64xx: Fix build error caused by undefined chained_irq_enter pinctrl/pinconfig: add debug interface pinctrl: abx500: fix issue when no pdata pinctrl: pinctrl-single: add missing double quote pinctrl: sunxi: Rename wemac functions to emac pinctrl: exynos5440: add gpio interrupt support pinctrl: exynos5440: fix probe failure due to missing pin-list in config nodes pinctrl: ab8505: Staticize some symbols pinctrl: ab8540: Staticize some symbols pinctrl: ab9540: Staticize some symbols pinctrl: ab8500: Staticize some symbols pinctrl: abx500: Staticize some symbols pinctrl: Add pinctrl-s3c64xx driver pinctrl: samsung: Handle banks with two configuration registers pinctrl: samsung: Remove hardcoded register offsets pinctrl: samsung: Split pin bank description into two structures pinctrl: samsung: Include pinctrl-exynos driver data conditionally pinctrl: samsung: Protect bank registers with a spinlock ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpio/gpio-pl061.c125
-rw-r--r--drivers/gpio/gpiolib-of.c15
-rw-r--r--drivers/pinctrl/Kconfig25
-rw-r--r--drivers/pinctrl/Makefile5
-rw-r--r--drivers/pinctrl/core.c359
-rw-r--r--drivers/pinctrl/core.h8
-rw-r--r--drivers/pinctrl/devicetree.c19
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-mvebu.c39
-rw-r--r--drivers/pinctrl/pinconf-generic.c20
-rw-r--r--drivers/pinctrl/pinconf.c335
-rw-r--r--drivers/pinctrl/pinconf.h8
-rw-r--r--drivers/pinctrl/pinctrl-ab8500.c5
-rw-r--r--drivers/pinctrl/pinctrl-ab8505.c7
-rw-r--r--drivers/pinctrl/pinctrl-ab8540.c5
-rw-r--r--drivers/pinctrl/pinctrl-ab9540.c7
-rw-r--r--drivers/pinctrl/pinctrl-abx500.c18
-rw-r--r--drivers/pinctrl/pinctrl-at91.c27
-rw-r--r--drivers/pinctrl/pinctrl-bcm2835.c6
-rw-r--r--drivers/pinctrl/pinctrl-coh901.c9
-rw-r--r--drivers/pinctrl/pinctrl-exynos.c36
-rw-r--r--drivers/pinctrl/pinctrl-exynos.h16
-rw-r--r--drivers/pinctrl/pinctrl-exynos5440.c159
-rw-r--r--drivers/pinctrl/pinctrl-falcon.c2
-rw-r--r--drivers/pinctrl/pinctrl-imx.c6
-rw-r--r--drivers/pinctrl/pinctrl-lantiq.c4
-rw-r--r--drivers/pinctrl/pinctrl-mmp2.c722
-rw-r--r--drivers/pinctrl/pinctrl-mxs.c6
-rw-r--r--drivers/pinctrl/pinctrl-nomadik-db8500.c4
-rw-r--r--drivers/pinctrl/pinctrl-nomadik-stn8815.c2
-rw-r--r--drivers/pinctrl/pinctrl-nomadik.c16
-rw-r--r--drivers/pinctrl/pinctrl-pxa168.c651
-rw-r--r--drivers/pinctrl/pinctrl-pxa3xx.c227
-rw-r--r--drivers/pinctrl/pinctrl-pxa3xx.h262
-rw-r--r--drivers/pinctrl/pinctrl-pxa910.c1007
-rw-r--r--drivers/pinctrl/pinctrl-s3c64xx.c816
-rw-r--r--drivers/pinctrl/pinctrl-samsung.c105
-rw-r--r--drivers/pinctrl/pinctrl-samsung.h42
-rw-r--r--drivers/pinctrl/pinctrl-single.c515
-rw-r--r--drivers/pinctrl/pinctrl-sirf.c14
-rw-r--r--drivers/pinctrl/pinctrl-sunxi.c986
-rw-r--r--drivers/pinctrl/pinctrl-tegra.c6
-rw-r--r--drivers/pinctrl/pinctrl-u300.c6
-rw-r--r--drivers/pinctrl/pinctrl-xway.c2
-rw-r--r--drivers/pinctrl/pinmux.c8
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear.c4
45 files changed, 2986 insertions, 3680 deletions
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index b820869ca93..d7008dfdd6f 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -15,6 +15,7 @@
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/bitops.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
@@ -22,6 +23,7 @@
#include <linux/amba/bus.h>
#include <linux/amba/pl061.h>
#include <linux/slab.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/pm.h>
#include <asm/mach/irq.h>
@@ -51,8 +53,7 @@ struct pl061_gpio {
spinlock_t lock;
void __iomem *base;
- int irq_base;
- struct irq_chip_generic *irq_gc;
+ struct irq_domain *domain;
struct gpio_chip gc;
#ifdef CONFIG_PM
@@ -60,6 +61,24 @@ struct pl061_gpio {
#endif
};
+static int pl061_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ /*
+ * Map back to global GPIO space and request muxing, the direction
+ * parameter does not matter for this controller.
+ */
+ int gpio = chip->base + offset;
+
+ return pinctrl_request_gpio(gpio);
+}
+
+static void pl061_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ int gpio = chip->base + offset;
+
+ pinctrl_free_gpio(gpio);
+}
+
static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
{
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
@@ -122,24 +141,20 @@ static int pl061_to_irq(struct gpio_chip *gc, unsigned offset)
{
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
- if (chip->irq_base <= 0)
- return -EINVAL;
-
- return chip->irq_base + offset;
+ return irq_create_mapping(chip->domain, offset);
}
static int pl061_irq_type(struct irq_data *d, unsigned trigger)
{
- struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
- struct pl061_gpio *chip = gc->private;
- int offset = d->irq - chip->irq_base;
+ struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
+ int offset = irqd_to_hwirq(d);
unsigned long flags;
u8 gpiois, gpioibe, gpioiev;
if (offset < 0 || offset >= PL061_GPIO_NR)
return -EINVAL;
- raw_spin_lock_irqsave(&gc->lock, flags);
+ spin_lock_irqsave(&chip->lock, flags);
gpioiev = readb(chip->base + GPIOIEV);
@@ -168,7 +183,7 @@ static int pl061_irq_type(struct irq_data *d, unsigned trigger)
writeb(gpioiev, chip->base + GPIOIEV);
- raw_spin_unlock_irqrestore(&gc->lock, flags);
+ spin_unlock_irqrestore(&chip->lock, flags);
return 0;
}
@@ -192,31 +207,61 @@ static void pl061_irq_handler(unsigned irq, struct irq_desc *desc)
chained_irq_exit(irqchip, desc);
}
-static void __init pl061_init_gc(struct pl061_gpio *chip, int irq_base)
+static void pl061_irq_mask(struct irq_data *d)
+{
+ struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
+ u8 mask = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR);
+ u8 gpioie;
+
+ spin_lock(&chip->lock);
+ gpioie = readb(chip->base + GPIOIE) & ~mask;
+ writeb(gpioie, chip->base + GPIOIE);
+ spin_unlock(&chip->lock);
+}
+
+static void pl061_irq_unmask(struct irq_data *d)
{
- struct irq_chip_type *ct;
+ struct pl061_gpio *chip = irq_data_get_irq_chip_data(d);
+ u8 mask = 1 << (irqd_to_hwirq(d) % PL061_GPIO_NR);
+ u8 gpioie;
+
+ spin_lock(&chip->lock);
+ gpioie = readb(chip->base + GPIOIE) | mask;
+ writeb(gpioie, chip->base + GPIOIE);
+ spin_unlock(&chip->lock);
+}
+
+static struct irq_chip pl061_irqchip = {
+ .name = "pl061 gpio",
+ .irq_mask = pl061_irq_mask,
+ .irq_unmask = pl061_irq_unmask,
+ .irq_set_type = pl061_irq_type,
+};
- chip->irq_gc = irq_alloc_generic_chip("gpio-pl061", 1, irq_base,
- chip->base, handle_simple_irq);
- chip->irq_gc->private = chip;
+static int pl061_irq_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct pl061_gpio *chip = d->host_data;
- ct = chip->irq_gc->chip_types;
- ct->chip.irq_mask = irq_gc_mask_clr_bit;
- ct->chip.irq_unmask = irq_gc_mask_set_bit;
- ct->chip.irq_set_type = pl061_irq_type;
- ct->chip.irq_set_wake = irq_gc_set_wake;
- ct->regs.mask = GPIOIE;
+ irq_set_chip_and_handler_name(virq, &pl061_irqchip, handle_simple_irq,
+ "pl061");
+ irq_set_chip_data(virq, chip);
+ irq_set_irq_type(virq, IRQ_TYPE_NONE);
- irq_setup_generic_chip(chip->irq_gc, IRQ_MSK(PL061_GPIO_NR),
- IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0);
+ return 0;
}
+static const struct irq_domain_ops pl061_domain_ops = {
+ .map = pl061_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
{
struct device *dev = &adev->dev;
struct pl061_platform_data *pdata = dev->platform_data;
struct pl061_gpio *chip;
- int ret, irq, i;
+ int ret, irq, i, irq_base;
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (chip == NULL)
@@ -224,24 +269,32 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
if (pdata) {
chip->gc.base = pdata->gpio_base;
- chip->irq_base = pdata->irq_base;
- } else if (adev->dev.of_node) {
+ irq_base = pdata->irq_base;
+ if (irq_base <= 0)
+ return -ENODEV;
+ } else {
chip->gc.base = -1;
- chip->irq_base = 0;
- } else
- return -ENODEV;
+ irq_base = 0;
+ }
if (!devm_request_mem_region(dev, adev->res.start,
- resource_size(&adev->res), "pl061"))
+ resource_size(&adev->res), "pl061"))
return -EBUSY;
chip->base = devm_ioremap(dev, adev->res.start,
- resource_size(&adev->res));
- if (chip->base == NULL)
+ resource_size(&adev->res));
+ if (!chip->base)
return -ENOMEM;
+ chip->domain = irq_domain_add_simple(adev->dev.of_node, PL061_GPIO_NR,
+ irq_base, &pl061_domain_ops, chip);
+ if (!chip->domain)
+ return -ENODEV;
+
spin_lock_init(&chip->lock);
+ chip->gc.request = pl061_gpio_request;
+ chip->gc.free = pl061_gpio_free;
chip->gc.direction_input = pl061_direction_input;
chip->gc.direction_output = pl061_direction_output;
chip->gc.get = pl061_get_value;
@@ -259,12 +312,6 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
/*
* irq_chip support
*/
-
- if (chip->irq_base <= 0)
- return 0;
-
- pl061_init_gc(chip, chip->irq_base);
-
writeb(0, chip->base + GPIOIE); /* disable irqs */
irq = adev->irq[0];
if (irq < 0)
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 5150df6cba0..465f4ca57e8 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -203,22 +203,11 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
if (!pctldev)
break;
- /*
- * This assumes that the n GPIO pins are consecutive in the
- * GPIO number space, and that the pins are also consecutive
- * in their local number space. Currently it is not possible
- * to add different ranges for one and the same GPIO chip,
- * as the code assumes that we have one consecutive range
- * on both, mapping 1-to-1.
- *
- * TODO: make the OF bindings handle multiple sparse ranges
- * on the same GPIO chip.
- */
ret = gpiochip_add_pin_range(chip,
pinctrl_dev_get_devname(pctldev),
- 0, /* offset in gpiochip */
pinspec.args[0],
- pinspec.args[1]);
+ pinspec.args[1],
+ pinspec.args[2]);
if (ret)
break;
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 34f51d2d90d..f910962baaa 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -106,20 +106,11 @@ config PINCTRL_LANTIQ
select PINMUX
select PINCONF
-config PINCTRL_PXA3xx
- bool
- select PINMUX
-
config PINCTRL_FALCON
bool
depends on SOC_FALCON
depends on PINCTRL_LANTIQ
-config PINCTRL_MMP2
- bool "MMP2 pin controller driver"
- depends on ARCH_MMP
- select PINCTRL_PXA3xx
-
config PINCTRL_MXS
bool
select PINMUX
@@ -151,21 +142,12 @@ config PINCTRL_DB8540
bool "DB8540 pin controller driver"
depends on PINCTRL_NOMADIK && ARCH_U8500
-config PINCTRL_PXA168
- bool "PXA168 pin controller driver"
- depends on ARCH_MMP
- select PINCTRL_PXA3xx
-
-config PINCTRL_PXA910
- bool "PXA910 pin controller driver"
- depends on ARCH_MMP
- select PINCTRL_PXA3xx
-
config PINCTRL_SINGLE
tristate "One-register-per-pin type device tree based pinctrl driver"
depends on OF
select PINMUX
select PINCONF
+ select GENERIC_PINCONF
help
This selects the device tree based generic pinctrl driver.
@@ -226,6 +208,11 @@ config PINCTRL_EXYNOS5440
select PINMUX
select PINCONF
+config PINCTRL_S3C64XX
+ bool "Samsung S3C64XX SoC pinctrl driver"
+ depends on ARCH_S3C64XX
+ select PINCTRL_SAMSUNG
+
source "drivers/pinctrl/mvebu/Kconfig"
source "drivers/pinctrl/sh-pfc/Kconfig"
source "drivers/pinctrl/spear/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index f82cc5baf76..988279ae23c 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -21,9 +21,7 @@ obj-$(CONFIG_PINCTRL_IMX35) += pinctrl-imx35.o
obj-$(CONFIG_PINCTRL_IMX51) += pinctrl-imx51.o
obj-$(CONFIG_PINCTRL_IMX53) += pinctrl-imx53.o
obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6q.o
-obj-$(CONFIG_PINCTRL_PXA3xx) += pinctrl-pxa3xx.o
obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o
-obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o
obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o
obj-$(CONFIG_PINCTRL_IMX23) += pinctrl-imx23.o
obj-$(CONFIG_PINCTRL_IMX28) += pinctrl-imx28.o
@@ -31,8 +29,6 @@ obj-$(CONFIG_PINCTRL_NOMADIK) += pinctrl-nomadik.o
obj-$(CONFIG_PINCTRL_STN8815) += pinctrl-nomadik-stn8815.o
obj-$(CONFIG_PINCTRL_DB8500) += pinctrl-nomadik-db8500.o
obj-$(CONFIG_PINCTRL_DB8540) += pinctrl-nomadik-db8540.o
-obj-$(CONFIG_PINCTRL_PXA168) += pinctrl-pxa168.o
-obj-$(CONFIG_PINCTRL_PXA910) += pinctrl-pxa910.o
obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
obj-$(CONFIG_PINCTRL_SIRF) += pinctrl-sirf.o
obj-$(CONFIG_PINCTRL_SUNXI) += pinctrl-sunxi.o
@@ -45,6 +41,7 @@ obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o
obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o
obj-$(CONFIG_PINCTRL_EXYNOS) += pinctrl-exynos.o
obj-$(CONFIG_PINCTRL_EXYNOS5440) += pinctrl-exynos5440.o
+obj-$(CONFIG_PINCTRL_S3C64XX) += pinctrl-s3c64xx.o
obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o
obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index b0de6e7f1fd..c3d222ed39a 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -27,6 +27,11 @@
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/machine.h>
+
+#ifdef CONFIG_GPIOLIB
+#include <asm-generic/gpio.h>
+#endif
+
#include "core.h"
#include "devicetree.h"
#include "pinmux.h"
@@ -35,11 +40,17 @@
static bool pinctrl_dummy_state;
-/* Mutex taken by all entry points */
-DEFINE_MUTEX(pinctrl_mutex);
+/* Mutex taken to protect pinctrl_list */
+DEFINE_MUTEX(pinctrl_list_mutex);
+
+/* Mutex taken to protect pinctrl_maps */
+DEFINE_MUTEX(pinctrl_maps_mutex);
+
+/* Mutex taken to protect pinctrldev_list */
+DEFINE_MUTEX(pinctrldev_list_mutex);
/* Global list of pin control devices (struct pinctrl_dev) */
-LIST_HEAD(pinctrldev_list);
+static LIST_HEAD(pinctrldev_list);
/* List of pin controller handles (struct pinctrl) */
static LIST_HEAD(pinctrl_list);
@@ -106,6 +117,23 @@ struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *devname)
return found ? pctldev : NULL;
}
+struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np)
+{
+ struct pinctrl_dev *pctldev;
+
+ mutex_lock(&pinctrldev_list_mutex);
+
+ list_for_each_entry(pctldev, &pinctrldev_list, node)
+ if (pctldev->dev->of_node == np) {
+ mutex_unlock(&pinctrldev_list_mutex);
+ return pctldev;
+ }
+
+ mutex_lock(&pinctrldev_list_mutex);
+
+ return NULL;
+}
+
/**
* pin_get_from_name() - look up a pin number from a name
* @pctldev: the pin control device to lookup the pin on
@@ -165,9 +193,9 @@ bool pin_is_valid(struct pinctrl_dev *pctldev, int pin)
if (pin < 0)
return false;
- mutex_lock(&pinctrl_mutex);
+ mutex_lock(&pctldev->mutex);
pindesc = pin_desc_get(pctldev, pin);
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pctldev->mutex);
return pindesc != NULL;
}
@@ -264,19 +292,58 @@ pinctrl_match_gpio_range(struct pinctrl_dev *pctldev, unsigned gpio)
{
struct pinctrl_gpio_range *range = NULL;
+ mutex_lock(&pctldev->mutex);
/* Loop over the ranges */
list_for_each_entry(range, &pctldev->gpio_ranges, node) {
/* Check if we're in the valid range */
if (gpio >= range->base &&
gpio < range->base + range->npins) {
+ mutex_unlock(&pctldev->mutex);
return range;
}
}
-
+ mutex_unlock(&pctldev->mutex);
return NULL;
}
/**
+ * pinctrl_ready_for_gpio_range() - check if other GPIO pins of
+ * the same GPIO chip are in range
+ * @gpio: gpio pin to check taken from the global GPIO pin space
+ *
+ * This function is complement of pinctrl_match_gpio_range(). If the return
+ * value of pinctrl_match_gpio_range() is NULL, this function could be used
+ * to check whether pinctrl device is ready or not. Maybe some GPIO pins
+ * of the same GPIO chip don't have back-end pinctrl interface.
+ * If the return value is true, it means that pinctrl device is ready & the
+ * certain GPIO pin doesn't have back-end pinctrl device. If the return value
+ * is false, it means that pinctrl device may not be ready.
+ */
+#ifdef CONFIG_GPIOLIB
+static bool pinctrl_ready_for_gpio_range(unsigned gpio)
+{
+ struct pinctrl_dev *pctldev;
+ struct pinctrl_gpio_range *range = NULL;
+ struct gpio_chip *chip = gpio_to_chip(gpio);
+
+ /* Loop over the pin controllers */
+ list_for_each_entry(pctldev, &pinctrldev_list, node) {
+ /* Loop over the ranges */
+ list_for_each_entry(range, &pctldev->gpio_ranges, node) {
+ /* Check if any gpio range overlapped with gpio chip */
+ if (range->base + range->npins - 1 < chip->base ||
+ range->base > chip->base + chip->ngpio - 1)
+ continue;
+ return true;
+ }
+ }
+ return false;
+}
+#else
+static bool pinctrl_ready_for_gpio_range(unsigned gpio) { return true; }
+#endif
+
+/**
* pinctrl_get_device_gpio_range() - find device for GPIO range
* @gpio: the pin to locate the pin controller for
* @outdev: the pin control device if found
@@ -319,9 +386,9 @@ static int pinctrl_get_device_gpio_range(unsigned gpio,
void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range)
{
- mutex_lock(&pinctrl_mutex);
+ mutex_lock(&pctldev->mutex);
list_add_tail(&range->node, &pctldev->gpio_ranges);
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pctldev->mutex);
}
EXPORT_SYMBOL_GPL(pinctrl_add_gpio_range);
@@ -339,17 +406,25 @@ EXPORT_SYMBOL_GPL(pinctrl_add_gpio_ranges);
struct pinctrl_dev *pinctrl_find_and_add_gpio_range(const char *devname,
struct pinctrl_gpio_range *range)
{
- struct pinctrl_dev *pctldev = get_pinctrl_dev_from_devname(devname);
+ struct pinctrl_dev *pctldev;
+
+ mutex_lock(&pinctrldev_list_mutex);
+
+ pctldev = get_pinctrl_dev_from_devname(devname);
/*
* If we can't find this device, let's assume that is because
* it has not probed yet, so the driver trying to register this
* range need to defer probing.
*/
- if (!pctldev)
+ if (!pctldev) {
+ mutex_unlock(&pinctrldev_list_mutex);
return ERR_PTR(-EPROBE_DEFER);
-
+ }
pinctrl_add_gpio_range(pctldev, range);
+
+ mutex_unlock(&pinctrldev_list_mutex);
+
return pctldev;
}
EXPORT_SYMBOL_GPL(pinctrl_find_and_add_gpio_range);
@@ -365,14 +440,17 @@ pinctrl_find_gpio_range_from_pin(struct pinctrl_dev *pctldev,
{
struct pinctrl_gpio_range *range = NULL;
+ mutex_lock(&pctldev->mutex);
/* Loop over the ranges */
list_for_each_entry(range, &pctldev->gpio_ranges, node) {
/* Check if we're in the valid range */
if (pin >= range->pin_base &&
pin < range->pin_base + range->npins) {
+ mutex_unlock(&pctldev->mutex);
return range;
}
}
+ mutex_unlock(&pctldev->mutex);
return NULL;
}
@@ -386,9 +464,9 @@ EXPORT_SYMBOL_GPL(pinctrl_find_gpio_range_from_pin);
void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range)
{
- mutex_lock(&pinctrl_mutex);
+ mutex_lock(&pctldev->mutex);
list_del(&range->node);
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pctldev->mutex);
}
EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range);
@@ -439,11 +517,13 @@ int pinctrl_request_gpio(unsigned gpio)
int ret;
int pin;
- mutex_lock(&pinctrl_mutex);
+ mutex_lock(&pinctrldev_list_mutex);
ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
if (ret) {
- mutex_unlock(&pinctrl_mutex);
+ if (pinctrl_ready_for_gpio_range(gpio))
+ ret = 0;
+ mutex_unlock(&pinctrldev_list_mutex);
return ret;
}
@@ -452,7 +532,7 @@ int pinctrl_request_gpio(unsigned gpio)
ret = pinmux_request_gpio(pctldev, range, pin, gpio);
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pinctrldev_list_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(pinctrl_request_gpio);
@@ -472,20 +552,22 @@ void pinctrl_free_gpio(unsigned gpio)
int ret;
int pin;
- mutex_lock(&pinctrl_mutex);
+ mutex_lock(&pinctrldev_list_mutex);
ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
if (ret) {
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pinctrldev_list_mutex);
return;
}
+ mutex_lock(&pctldev->mutex);
/* Convert to the pin controllers number space */
pin = gpio - range->base + range->pin_base;
pinmux_free_gpio(pctldev, pin, range);
- mutex_unlock(&pinctrl_mutex);
+ mutex_unlock(&pctldev->mutex);
+ mutex_unlock(&pinctrldev_list_mutex);
}
EXPORT_SYMBOL_GPL(pinctrl_free_gpio);
@@ -496,14 +578,24 @@ static int pinctrl_gpio_direction(unsigned gpio, bool input)
int ret;
int pin;
+ mutex_lock(&pinctrldev_list_mutex);
+
ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
- if (ret)
+ if (ret) {
+ mutex_unlock(&pinctrldev_list_mutex);
return ret;
+ }
+
+ mutex_lock(&pctldev->mutex);
/* Convert to the pin controllers number space */
pin = gpio - range->base + range->pin_base;
+ ret = pinmux_gpio_direction(pctldev, range, pin, input);
+
+ mutex_unlock(&pctldev->mutex);
+ mutex_unlock(&pinctrldev_list_mutex);
- return pinmux_gpio_direction(pctldev, range, pin, input);
+ return ret;
}
/**
@@ -516,11 +608,7 @@ static int pinctrl_gpio_direction(unsigned gpio, bool input)
*/
int pinctrl_gpio_direction_input(unsigned gpio)
{
- int ret;
- mutex_lock(&pinctrl_mutex);
- ret = pinctrl_gpio_direction(gpio, true);
- mutex_unlock(&pinctrl_mutex);
- return ret;
+ return pinctrl_gpio_direction(gpio, true);
}
EXPORT_SYMBOL_GPL(pinctrl_gpio_direction_input);
@@ -534,11 +622,7 @@ EXPORT_SYMBOL_GPL(pinctrl_gpio_direction_input);
*/
int pinctrl_gpio_direction_output(unsigned gpio)
{
- int ret;
- mutex_lock(&pinctrl_mutex);
- ret = pinctrl_gpio_direction(gpio, false);
- mutex_unlock(&pinctrl_mutex);
- return ret;
+ return pinctrl_gpio_direction(gpio, false);
}
EXPORT_SYMBOL_GPL(pinctrl_gpio_direction_output);
@@ -641,14 +725,18 @@ static struct pinctrl *find_pinctrl(struct device *dev)
{
struct pinctrl *p;
+ mutex_lock(&pinctrl_list_mutex);
list_for_each_entry(p, &pinctrl_list, node)
- if (p->dev == dev)
+ if (p->dev == dev) {
+ mutex_unlock(&pinctrl_list_mutex);
return p;
+ }
+ mutex_unlock(&pinctrl_list_mutex);
return NULL;
}
-static void pinctrl_put_locked(struct pinctrl *p, bool inlist);
+static void pinctrl_free(struct pinctrl *p, bool inlist);
static struct pinctrl *create_pinctrl(struct device *dev)
{
@@ -681,6 +769,7 @@ static struct pinctrl *create_pinctrl(struct device *dev)
devname = dev_name(dev);
+ mutex_lock(&pinctrl_maps_mutex);
/* Iterate over the pin control maps to locate the right ones */
for_each_maps(maps_node, i, map) {
/* Map must be for this device */
@@ -702,13 +791,16 @@ static struct pinctrl *create_pinctrl(struct device *dev)
* an -EPROBE_DEFER later, as that is the worst case.
*/
if (ret == -EPROBE_DEFER) {
- pinctrl_put_locked(p, false);
+ pinctrl_free(p, false);
+ mutex_unlock(&pinctrl_maps_mutex);
return ERR_PTR(ret);
}
}
+ mutex_unlock(&pinctrl_maps_mutex);
+
if (ret < 0) {
/* If some other error than deferral occured, return here */
- pinctrl_put_locked(p, false);
+ pinctrl_free(p, false);
return ERR_PTR(ret);
}
@@ -720,7 +812,11 @@ static struct pinctrl *create_pinctrl(struct device *dev)