Merge tag 'v5.6-rc7' into devel
authorLinus Walleij <linus.walleij@linaro.org>
Fri, 27 Mar 2020 21:36:17 +0000 (22:36 +0100)
committerLinus Walleij <linus.walleij@linaro.org>
Fri, 27 Mar 2020 21:36:17 +0000 (22:36 +0100)
Linux 5.6-rc7

39 files changed:
Documentation/driver-api/gpio/driver.rst
arch/arm/mach-integrator/impd1.c
arch/arm/mach-omap2/cpuidle34xx.c
arch/arm/mach-omap2/cpuidle44xx.c
arch/arm/mach-omap2/pm34xx.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-brcmstb.c
drivers/gpio/gpio-mlxbf2.c [new file with mode: 0644]
drivers/gpio/gpio-mmio.c
drivers/gpio/gpio-mockup.c
drivers/gpio/gpio-mt7621.c
drivers/gpio/gpio-mvebu.c
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-pl061.c
drivers/gpio/gpio-pxa.c
drivers/gpio/gpio-rcar.c
drivers/gpio/gpio-siox.c
drivers/gpio/gpio-tegra186.c
drivers/gpio/gpio-uniphier.c
drivers/gpio/gpio-wcd934x.c
drivers/gpio/gpiolib-devres.c
drivers/gpio/gpiolib-of.c
drivers/gpio/gpiolib-of.h
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.h
include/asm-generic/gpio.h
include/linux/gpio.h
include/linux/gpio/consumer.h
include/linux/gpio/driver.h
include/linux/kfifo.h
include/linux/of_gpio.h
include/uapi/linux/gpio.h
tools/gpio/.gitignore
tools/gpio/Build
tools/gpio/Makefile
tools/gpio/gpio-hammer.c
tools/gpio/gpio-utils.c
tools/gpio/gpio-watch.c [new file with mode: 0644]

index 8719225..9809f59 100644 (file)
@@ -416,7 +416,7 @@ The preferred way to set up the helpers is to fill in the
 struct gpio_irq_chip inside struct gpio_chip before adding the gpio_chip.
 If you do this, the additional irq_chip will be set up by gpiolib at the
 same time as setting up the rest of the GPIO functionality. The following
-is a typical example of a cascaded interrupt handler using gpio_irq_chip::
+is a typical example of a cascaded interrupt handler using gpio_irq_chip:
 
 .. code-block:: c
 
@@ -453,7 +453,7 @@ is a typical example of a cascaded interrupt handler using gpio_irq_chip::
   return devm_gpiochip_add_data(dev, &g->gc, g);
 
 The helper support using hierarchical interrupt controllers as well.
-In this case the typical set-up will look like this::
+In this case the typical set-up will look like this:
 
 .. code-block:: c
 
index 1ecbea5..6f875de 100644 (file)
@@ -410,13 +410,10 @@ static int __ref impd1_probe(struct lm_device *dev)
                         * 5 = Key lower right
                         */
                        /* We need the two MMCI GPIO entries */
-                       lookup->table[0].chip_label = chipname;
-                       lookup->table[0].chip_hwnum = 3;
-                       lookup->table[0].con_id = "wp";
-                       lookup->table[1].chip_label = chipname;
-                       lookup->table[1].chip_hwnum = 4;
-                       lookup->table[1].con_id = "cd";
-                       lookup->table[1].flags = GPIO_ACTIVE_LOW;
+                       lookup->table[0] = (struct gpiod_lookup)
+                               GPIO_LOOKUP(chipname, 3, "wp", 0);
+                       lookup->table[1] = (struct gpiod_lookup)
+                               GPIO_LOOKUP(chipname, 4, "cd", GPIO_ACTIVE_LOW);
                        gpiod_add_lookup_table(lookup);
                }
 
index 532a3e4..090a8aa 100644 (file)
@@ -109,6 +109,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
                            int index)
 {
        struct omap3_idle_statedata *cx = &omap3_idle_data[index];
+       int error;
 
        if (omap_irq_pending() || need_resched())
                goto return_sleep_time;
@@ -125,8 +126,11 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
         * Call idle CPU PM enter notifier chain so that
         * VFP context is saved.
         */
-       if (cx->mpu_state == PWRDM_POWER_OFF)
-               cpu_pm_enter();
+       if (cx->mpu_state == PWRDM_POWER_OFF) {
+               error = cpu_pm_enter();
+               if (error)
+                       goto out_clkdm_set;
+       }
 
        /* Execute ARM wfi */
        omap_sram_idle();
@@ -139,6 +143,7 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
            pwrdm_read_prev_pwrst(mpu_pd) == PWRDM_POWER_OFF)
                cpu_pm_exit();
 
+out_clkdm_set:
        /* Re-allow idle for C1 */
        if (cx->flags & OMAP_CPUIDLE_CX_NO_CLKDM_IDLE)
                clkdm_allow_idle(mpu_pd->pwrdm_clkdms[0]);
index fe75d4f..6f5f897 100644 (file)
@@ -122,6 +122,7 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
 {
        struct idle_statedata *cx = state_ptr + index;
        u32 mpuss_can_lose_context = 0;
+       int error;
 
        /*
         * CPU0 has to wait and stay ON until CPU1 is OFF state.
@@ -159,7 +160,9 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
         * Call idle CPU PM enter notifier chain so that
         * VFP and per CPU interrupt context is saved.
         */
-       cpu_pm_enter();
+       error = cpu_pm_enter();
+       if (error)
+               goto cpu_pm_out;
 
        if (dev->cpu == 0) {
                pwrdm_set_logic_retst(mpu_pd, cx->mpu_logic_state);
@@ -169,13 +172,17 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
                 * Call idle CPU cluster PM enter notifier chain
                 * to save GIC and wakeupgen context.
                 */
-               if (mpuss_can_lose_context)
-                       cpu_cluster_pm_enter();
+               if (mpuss_can_lose_context) {
+                       error = cpu_cluster_pm_enter();
+                       if (error)
+                               goto cpu_cluster_pm_out;
+               }
        }
 
        omap4_enter_lowpower(dev->cpu, cx->cpu_state);
        cpu_done[dev->cpu] = true;
 
+cpu_cluster_pm_out:
        /* Wakeup CPU1 only if it is not offlined */
        if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) {
 
@@ -198,18 +205,19 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev,
        }
 
        /*
-        * Call idle CPU PM exit notifier chain to restore
-        * VFP and per CPU IRQ context.
-        */
-       cpu_pm_exit();
-
-       /*
         * Call idle CPU cluster PM exit notifier chain
         * to restore GIC and wakeupgen context.
         */
        if (dev->cpu == 0 && mpuss_can_lose_context)
                cpu_cluster_pm_exit();
 
+       /*
+        * Call idle CPU PM exit notifier chain to restore
+        * VFP and per CPU IRQ context.
+        */
+       cpu_pm_exit();
+
+cpu_pm_out:
        tick_broadcast_exit();
 
 fail:
index e66e994..6df395f 100644 (file)
@@ -191,6 +191,7 @@ void omap_sram_idle(void)
        int per_next_state = PWRDM_POWER_ON;
        int core_next_state = PWRDM_POWER_ON;
        u32 sdrc_pwr = 0;
+       int error;
 
        mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
        switch (mpu_next_state) {
@@ -219,8 +220,11 @@ void omap_sram_idle(void)
        pwrdm_pre_transition(NULL);
 
        /* PER */
-       if (per_next_state == PWRDM_POWER_OFF)
-               cpu_cluster_pm_enter();
+       if (per_next_state == PWRDM_POWER_OFF) {
+               error = cpu_cluster_pm_enter();
+               if (error)
+                       return;
+       }
 
        /* CORE */
        if (core_next_state < PWRDM_POWER_ON) {
index b8013cf..1b96169 100644 (file)
@@ -394,13 +394,13 @@ config GPIO_MVEBU
 
 config GPIO_MXC
        def_bool y
-       depends on ARCH_MXC
+       depends on ARCH_MXC || COMPILE_TEST
        select GPIO_GENERIC
        select GENERIC_IRQ_CHIP
 
 config GPIO_MXS
        def_bool y
-       depends on ARCH_MXS
+       depends on ARCH_MXS || COMPILE_TEST
        select GPIO_GENERIC
        select GENERIC_IRQ_CHIP
 
@@ -1399,6 +1399,13 @@ config GPIO_MLXBF
        help
          Say Y here if you want GPIO support on Mellanox BlueField SoC.
 
+config GPIO_MLXBF2
+       tristate "Mellanox BlueField 2 SoC GPIO"
+       depends on (MELLANOX_PLATFORM && ARM64 && ACPI) || (64BIT && COMPILE_TEST)
+       select GPIO_GENERIC
+       help
+         Say Y here if you want GPIO support on Mellanox BlueField 2 SoC.
+
 config GPIO_ML_IOH
        tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
        depends on X86 || COMPILE_TEST
index 0b57126..b2cfc21 100644 (file)
@@ -93,6 +93,7 @@ obj-$(CONFIG_GPIO_MENZ127)            += gpio-menz127.o
 obj-$(CONFIG_GPIO_MERRIFIELD)          += gpio-merrifield.o
 obj-$(CONFIG_GPIO_ML_IOH)              += gpio-ml-ioh.o
 obj-$(CONFIG_GPIO_MLXBF)               += gpio-mlxbf.o
+obj-$(CONFIG_GPIO_MLXBF2)              += gpio-mlxbf2.o
 obj-$(CONFIG_GPIO_MM_LANTIQ)           += gpio-mm-lantiq.o
 obj-$(CONFIG_GPIO_MOCKUP)              += gpio-mockup.o
 obj-$(CONFIG_GPIO_MOXTET)              += gpio-moxtet.o
index 05e3f99..fcfc1a1 100644 (file)
@@ -603,6 +603,49 @@ static const struct dev_pm_ops brcmstb_gpio_pm_ops = {
        .resume_noirq = brcmstb_gpio_resume,
 };
 
+static void brcmstb_gpio_set_names(struct device *dev,
+                                  struct brcmstb_gpio_bank *bank)
+{
+       struct device_node *np = dev->of_node;
+       const char **names;
+       int nstrings, base;
+       unsigned int i;
+
+       base = bank->id * MAX_GPIO_PER_BANK;
+
+       nstrings = of_property_count_strings(np, "gpio-line-names");
+       if (nstrings <= base)
+               /* Line names not present */
+               return;
+
+       names = devm_kcalloc(dev, MAX_GPIO_PER_BANK, sizeof(*names),
+                            GFP_KERNEL);
+       if (!names)
+               return;
+
+       /*
+        * Make sure to not index beyond the end of the number of descriptors
+        * of the GPIO device.
+        */
+       for (i = 0; i < bank->width; i++) {
+               const char *name;
+               int ret;
+
+               ret = of_property_read_string_index(np, "gpio-line-names",
+                                                   base + i, &name);
+               if (ret) {
+                       if (ret != -ENODATA)
+                               dev_err(dev, "unable to name line %d: %d\n",
+                                       base + i, ret);
+                       break;
+               }
+               if (*name)
+                       names[i] = name;
+       }
+
+       bank->gc.names = names;
+}
+
 static int brcmstb_gpio_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -726,6 +769,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
                need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank);
                gc->write_reg(reg_base + GIO_MASK(bank->id), 0);
 
+               brcmstb_gpio_set_names(dev, bank);
                err = gpiochip_add_data(gc, bank);
                if (err) {
                        dev_err(dev, "Could not add gpiochip for bank %d\n",
diff --git a/drivers/gpio/gpio-mlxbf2.c b/drivers/gpio/gpio-mlxbf2.c
new file mode 100644 (file)
index 0000000..7b70850
--- /dev/null
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/acpi.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/gpio/driver.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/resource.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/version.h>
+
+/*
+ * There are 3 YU GPIO blocks:
+ * gpio[0]: HOST_GPIO0->HOST_GPIO31
+ * gpio[1]: HOST_GPIO32->HOST_GPIO63
+ * gpio[2]: HOST_GPIO64->HOST_GPIO69
+ */
+#define MLXBF2_GPIO_MAX_PINS_PER_BLOCK 32
+
+/*
+ * arm_gpio_lock register:
+ * bit[31]     lock status: active if set
+ * bit[15:0]   set lock
+ * The lock is enabled only if 0xd42f is written to this field
+ */
+#define YU_ARM_GPIO_LOCK_ADDR          0x2801088
+#define YU_ARM_GPIO_LOCK_SIZE          0x8
+#define YU_LOCK_ACTIVE_BIT(val)                (val >> 31)
+#define YU_ARM_GPIO_LOCK_ACQUIRE       0xd42f
+#define YU_ARM_GPIO_LOCK_RELEASE       0x0
+
+/*
+ * gpio[x] block registers and their offset
+ */
+#define YU_GPIO_DATAIN                 0x04
+#define YU_GPIO_MODE1                  0x08
+#define YU_GPIO_MODE0                  0x0c
+#define YU_GPIO_DATASET                        0x14
+#define YU_GPIO_DATACLEAR              0x18
+#define YU_GPIO_MODE1_CLEAR            0x50
+#define YU_GPIO_MODE0_SET              0x54
+#define YU_GPIO_MODE0_CLEAR            0x58
+
+#ifdef CONFIG_PM
+struct mlxbf2_gpio_context_save_regs {
+       u32 gpio_mode0;
+       u32 gpio_mode1;
+};
+#endif
+
+/* BlueField-2 gpio block context structure. */
+struct mlxbf2_gpio_context {
+       struct gpio_chip gc;
+
+       /* YU GPIO blocks address */
+       void __iomem *gpio_io;
+
+#ifdef CONFIG_PM
+       struct mlxbf2_gpio_context_save_regs *csave_regs;
+#endif
+};
+
+/* BlueField-2 gpio shared structure. */
+struct mlxbf2_gpio_param {
+       void __iomem *io;
+       struct resource *res;
+       struct mutex *lock;
+};
+
+static struct resource yu_arm_gpio_lock_res = {
+       .start = YU_ARM_GPIO_LOCK_ADDR,
+       .end   = YU_ARM_GPIO_LOCK_ADDR + YU_ARM_GPIO_LOCK_SIZE - 1,
+       .name  = "YU_ARM_GPIO_LOCK",
+};
+
+static DEFINE_MUTEX(yu_arm_gpio_lock_mutex);
+
+static struct mlxbf2_gpio_param yu_arm_gpio_lock_param = {
+       .res = &yu_arm_gpio_lock_res,
+       .lock = &yu_arm_gpio_lock_mutex,
+};
+
+/* Request memory region and map yu_arm_gpio_lock resource */
+static int mlxbf2_gpio_get_lock_res(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       resource_size_t size;
+       int ret = 0;
+
+       mutex_lock(yu_arm_gpio_lock_param.lock);
+
+       /* Check if the memory map already exists */
+       if (yu_arm_gpio_lock_param.io)
+               goto exit;
+
+       res = yu_arm_gpio_lock_param.res;
+       size = resource_size(res);
+
+       if (!devm_request_mem_region(dev, res->start, size, res->name)) {
+               ret = -EFAULT;
+               goto exit;
+       }
+
+       yu_arm_gpio_lock_param.io = devm_ioremap(dev, res->start, size);
+       if (IS_ERR(yu_arm_gpio_lock_param.io))
+               ret = PTR_ERR(yu_arm_gpio_lock_param.io);
+
+exit:
+       mutex_unlock(yu_arm_gpio_lock_param.lock);
+
+       return ret;
+}
+
+/*
+ * Acquire the YU arm_gpio_lock to be able to change the direction
+ * mode. If the lock_active bit is already set, return an error.
+ */
+static int mlxbf2_gpio_lock_acquire(struct mlxbf2_gpio_context *gs)
+{
+       u32 arm_gpio_lock_val;
+
+       spin_lock(&gs->gc.bgpio_lock);
+       mutex_lock(yu_arm_gpio_lock_param.lock);
+
+       arm_gpio_lock_val = readl(yu_arm_gpio_lock_param.io);
+
+       /*
+        * When lock active bit[31] is set, ModeX is write enabled
+        */
+       if (YU_LOCK_ACTIVE_BIT(arm_gpio_lock_val)) {
+               mutex_unlock(yu_arm_gpio_lock_param.lock);
+               spin_unlock(&gs->gc.bgpio_lock);
+               return -EINVAL;
+       }
+
+       writel(YU_ARM_GPIO_LOCK_ACQUIRE, yu_arm_gpio_lock_param.io);
+
+       return 0;
+}
+
+/*
+ * Release the YU arm_gpio_lock after changing the direction mode.
+ */
+static void mlxbf2_gpio_lock_release(struct mlxbf2_gpio_context *gs)
+{
+       writel(YU_ARM_GPIO_LOCK_RELEASE, yu_arm_gpio_lock_param.io);
+       mutex_unlock(yu_arm_gpio_lock_param.lock);
+       spin_unlock(&gs->gc.bgpio_lock);
+}
+
+/*
+ * mode0 and mode1 are both locked by the gpio_lock field.
+ *
+ * Together, mode0 and mode1 define the gpio Mode dependeing also
+ * on Reg_DataOut.
+ *
+ * {mode1,mode0}:{Reg_DataOut=0,Reg_DataOut=1}->{DataOut=0,DataOut=1}
+ *
+ * {0,0}:Reg_DataOut{0,1}->{Z,Z} Input PAD
+ * {0,1}:Reg_DataOut{0,1}->{0,1} Full drive Output PAD
+ * {1,0}:Reg_DataOut{0,1}->{0,Z} 0-set PAD to low, 1-float
+ * {1,1}:Reg_DataOut{0,1}->{Z,1} 0-float, 1-set PAD to high
+ */
+
+/*
+ * Set input direction:
+ * {mode1,mode0} = {0,0}
+ */
+static int mlxbf2_gpio_direction_input(struct gpio_chip *chip,
+                                      unsigned int offset)
+{
+       struct mlxbf2_gpio_context *gs = gpiochip_get_data(chip);
+       int ret;
+
+       /*
+        * Although the arm_gpio_lock was set in the probe function, check again
+        * if it is still enabled to be able to write to the ModeX registers.
+        */
+       ret = mlxbf2_gpio_lock_acquire(gs);
+       if (ret < 0)
+               return ret;
+
+       writel(BIT(offset), gs->gpio_io + YU_GPIO_MODE0_CLEAR);
+       writel(BIT(offset), gs->gpio_io + YU_GPIO_MODE1_CLEAR);
+
+       mlxbf2_gpio_lock_release(gs);
+
+       return ret;
+}
+
+/*
+ * Set output direction:
+ * {mode1,mode0} = {0,1}
+ */
+static int mlxbf2_gpio_direction_output(struct gpio_chip *chip,
+                                       unsigned int offset,
+                                       int value)
+{
+       struct mlxbf2_gpio_context *gs = gpiochip_get_data(chip);
+       int ret = 0;
+
+       /*
+        * Although the arm_gpio_lock was set in the probe function,
+        * check again it is still enabled to be able to write to the
+        * ModeX registers.
+        */
+       ret = mlxbf2_gpio_lock_acquire(gs);
+       if (ret < 0)
+               return ret;
+
+       writel(BIT(offset), gs->gpio_io + YU_GPIO_MODE1_CLEAR);
+       writel(BIT(offset), gs->gpio_io + YU_GPIO_MODE0_SET);
+
+       mlxbf2_gpio_lock_release(gs);
+
+       return ret;
+}
+
+/* BlueField-2 GPIO driver initialization routine. */
+static int
+mlxbf2_gpio_probe(struct platform_device *pdev)
+{
+       struct mlxbf2_gpio_context *gs;
+       struct device *dev = &pdev->dev;
+       struct gpio_chip *gc;
+       struct resource *res;
+       unsigned int npins;
+       int ret;
+
+       gs = devm_kzalloc(dev, sizeof(*gs), GFP_KERNEL);
+       if (!gs)
+               return -ENOMEM;
+
+       /* YU GPIO block address */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       gs->gpio_io = devm_ioremap(dev, res->start, resource_size(res));
+       if (!gs->gpio_io)
+               return -ENOMEM;
+
+       ret = mlxbf2_gpio_get_lock_res(pdev);
+       if (ret) {
+               dev_err(dev, "Failed to get yu_arm_gpio_lock resource\n");
+               return ret;
+       }
+
+       if (device_property_read_u32(dev, "npins", &npins))
+               npins = MLXBF2_GPIO_MAX_PINS_PER_BLOCK;
+
+       gc = &gs->gc;
+
+       ret = bgpio_init(gc, dev, 4,
+                       gs->gpio_io + YU_GPIO_DATAIN,
+                       gs->gpio_io + YU_GPIO_DATASET,
+                       gs->gpio_io + YU_GPIO_DATACLEAR,
+                       NULL,
+                       NULL,
+                       0);
+
+       gc->direction_input = mlxbf2_gpio_direction_input;
+       gc->direction_output = mlxbf2_gpio_direction_output;
+       gc->ngpio = npins;
+       gc->owner = THIS_MODULE;
+
+       platform_set_drvdata(pdev, gs);
+
+       ret = devm_gpiochip_add_data(dev, &gs->gc, gs);
+       if (ret) {
+               dev_err(dev, "Failed adding memory mapped gpiochip\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int mlxbf2_gpio_suspend(struct platform_device *pdev,
+                               pm_message_t state)
+{
+       struct mlxbf2_gpio_context *gs = platform_get_drvdata(pdev);
+
+       gs->csave_regs->gpio_mode0 = readl(gs->gpio_io +
+               YU_GPIO_MODE0);
+       gs->csave_regs->gpio_mode1 = readl(gs->gpio_io +
+               YU_GPIO_MODE1);
+
+       return 0;
+}
+
+static int mlxbf2_gpio_resume(struct platform_device *pdev)
+{
+       struct mlxbf2_gpio_context *gs = platform_get_drvdata(pdev);
+
+       writel(gs->csave_regs->gpio_mode0, gs->gpio_io +
+               YU_GPIO_MODE0);
+       writel(gs->csave_regs->gpio_mode1, gs->gpio_io +
+               YU_GPIO_MODE1);
+
+       return 0;
+}
+#endif
+
+static const struct acpi_device_id mlxbf2_gpio_acpi_match[] = {
+       { "MLNXBF22", 0 },
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, mlxbf2_gpio_acpi_match);
+
+static struct platform_driver mlxbf2_gpio_driver = {
+       .driver = {
+               .name = "mlxbf2_gpio",
+               .acpi_match_table = ACPI_PTR(mlxbf2_gpio_acpi_match),
+       },
+       .probe    = mlxbf2_gpio_probe,
+#ifdef CONFIG_PM
+       .suspend  = mlxbf2_gpio_suspend,
+       .resume   = mlxbf2_gpio_resume,
+#endif
+};
+
+module_platform_driver(mlxbf2_gpio_driver);
+
+MODULE_DESCRIPTION("Mellanox BlueField-2 GPIO Driver");
+MODULE_AUTHOR("Mellanox Technologies");
+MODULE_LICENSE("GPL v2");
index f729e3e..b778f33 100644 (file)
@@ -389,12 +389,10 @@ static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio)
        return GPIO_LINE_DIRECTION_IN;
 }
 
-static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+static void bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
 {
        unsigned long flags;
 
-       gc->set(gc, gpio, val);
-
        spin_lock_irqsave(&gc->bgpio_lock, flags);
 
        gc->bgpio_dir |= bgpio_line2mask(gc, gpio);
@@ -405,7 +403,21 @@ static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
                gc->write_reg(gc->reg_dir_out, gc->bgpio_dir);
 
        spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+}
 
+static int bgpio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio,
+                                  int val)
+{
+       bgpio_dir_out(gc, gpio, val);
+       gc->set(gc, gpio, val);
+       return 0;
+}
+
+static int bgpio_dir_out_val_first(struct gpio_chip *gc, unsigned int gpio,
+                                  int val)
+{
+       gc->set(gc, gpio, val);
+       bgpio_dir_out(gc, gpio, val);
        return 0;
 }
 
@@ -538,7 +550,10 @@ static int bgpio_setup_direction(struct gpio_chip *gc,
        if (dirout || dirin) {
                gc->reg_dir_out = dirout;
                gc->reg_dir_in = dirin;
-               gc->direction_output = bgpio_dir_out;
+               if (flags & BGPIOF_NO_SET_ON_INPUT)
+                       gc->direction_output = bgpio_dir_out_dir_first;
+               else
+                       gc->direction_output = bgpio_dir_out_val_first;
                gc->direction_input = bgpio_dir_in;
                gc->get_direction = bgpio_get_dir;
        } else {
index 7d343be..3eb94f3 100644 (file)
@@ -171,7 +171,7 @@ static int gpio_mockup_apply_pull(struct gpio_mockup_chip *chip,
 
        /* Change the value unless we're actively driving the line. */
        if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
-               !test_bit(FLAG_IS_OUT, &desc->flags))
+           !test_bit(FLAG_IS_OUT, &desc->flags))
                __gpio_mockup_set(chip, offset, value);
 
 out:
index b992321..82fb20d 100644 (file)
@@ -227,8 +227,8 @@ mediatek_gpio_bank_probe(struct device *dev,
        ctrl = mtk->base + GPIO_REG_DCLR + (rg->bank * GPIO_BANK_STRIDE);
        diro = mtk->base + GPIO_REG_CTRL + (rg->bank * GPIO_BANK_STRIDE);
 
-       ret = bgpio_init(&rg->chip, dev, 4,
-                        dat, set, ctrl, diro, NULL, 0);
+       ret = bgpio_init(&rg->chip, dev, 4, dat, set, ctrl, diro, NULL,
+                        BGPIOF_NO_SET_ON_INPUT);
        if (ret) {
                dev_err(dev, "bgpio_init() failed\n");
                return ret;
index d2b999c..3c9f4fb 100644 (file)
@@ -1247,7 +1247,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
         * pins.
         */
        for (i = 0; i < 4; i++) {
-               int irq = platform_get_irq(pdev, i);
+               int irq = platform_get_irq_optional(pdev, i);
 
                if (irq < 0)
                        continue;
index 3bd8ada..b8e2ecc 100644 (file)
@@ -1102,23 +1102,13 @@ static void omap_gpio_idle(struct gpio_bank *bank, bool may_lose_context)
 {
        struct device *dev = bank->chip.parent;
        void __iomem *base = bank->base;
-       u32 mask, nowake;
+       u32 nowake;
 
        bank->saved_datain = readl_relaxed(base + bank->regs->datain);
 
        if (!bank->enabled_non_wakeup_gpios)
                goto update_gpio_context_count;
 
-       /* Check for pending EDGE_FALLING, ignore EDGE_BOTH */
-       mask = bank->enabled_non_wakeup_gpios & bank->context.fallingdetect;
-       mask &= ~bank->context.risingdetect;
-       bank->saved_datain |= mask;
-
-       /* Check for pending EDGE_RISING, ignore EDGE_BOTH */
-       mask = bank->enabled_non_wakeup_gpios & bank->context.risingdetect;
-       mask &= ~bank->context.fallingdetect;
-       bank->saved_datain &= ~mask;
-
        if (!may_lose_context)
                goto update_gpio_context_count;
 
@@ -1237,26 +1227,35 @@ static int gpio_omap_cpu_notifier(struct notifier_block *nb,
 {
        struct gpio_bank *bank;
        unsigned long flags;
+       int ret = NOTIFY_OK;
+       u32 isr, mask;
 
        bank = container_of(nb, struct gpio_bank, nb);
 
        raw_spin_lock_irqsave(&bank->lock, flags);
+       if (bank->is_suspended)
+               goto out_unlock;
+
        switch (cmd) {
        case CPU_CLUSTER_PM_ENTER:
-               if (bank->is_suspended)
+               mask = omap_get_gpio_irqbank_mask(bank);
+               isr = readl_relaxed(bank->base + bank->regs->irqstatus) & mask;
+               if (isr) {
+                       ret = NOTIFY_BAD;
                        break;
+               }
                omap_gpio_idle(bank, true);
                break;
        case CPU_CLUSTER_PM_ENTER_FAILED:
        case CPU_CLUSTER_PM_EXIT:
-               if (bank->is_suspended)
-                       break;
                omap_gpio_unidle(bank);
                break;
        }
+
+out_unlock:
        raw_spin_unlock_irqrestore(&bank->lock, flags);
 
-       return NOTIFY_OK;
+       return ret;
 }
 
 static const struct omap_gpio_reg_offs omap2_gpio_regs = {
index 5df7782..3439120 100644 (file)
@@ -326,10 +326,8 @@ static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
 
        writeb(0, pl061->base + GPIOIE); /* disable irqs */
        irq = adev->irq[0];
-       if (irq < 0) {
-               dev_err(&adev->dev, "invalid IRQ\n");
-               return -ENODEV;
-       }
+       if (!irq)
+               dev_warn(&adev->dev, "IRQ support disabled\n");
        pl061->parent_irq = irq;
 
        girq = &pl061->gc.irq;
index 9888b62..567742d 100644 (file)
@@ -652,8 +652,8 @@ static int pxa_gpio_probe(struct platform_device *pdev)
        if (!pchip->irqdomain)
                return -ENOMEM;
 
-       irq0 = platform_get_irq_byname(pdev, "gpio0");
-       irq1 = platform_get_irq_byname(pdev, "gpio1");
+       irq0 = platform_get_irq_byname_optional(pdev, "gpio0");
+       irq1 = platform_get_irq_byname_optional(pdev, "gpio1");
        irq_mux = platform_get_irq_byname(pdev, "gpio_mux");
        if ((irq0 > 0 && irq1 <= 0) || (irq0 <= 0 && irq1 > 0)
                || (irq_mux <= 0))
index f800b25..7284473 100644 (file)
@@ -116,7 +116,7 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
 
        spin_lock_irqsave(&p->lock, flags);
 
-       /* Configure postive or negative logic in POSNEG */
+       /* Configure positive or negative logic in POSNEG */
        gpio_rcar_modify_bit(p, POSNEG, hwirq, !active_high_rising_edge);
 
        /* Configure edge or level trigger in EDGLEVEL */
@@ -228,7 +228,7 @@ static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip,
 
        spin_lock_irqsave(&p->lock, flags);
 
-       /* Configure postive logic in POSNEG */
+       /* Configure positive logic in POSNEG */
        gpio_rcar_modify_bit(p, POSNEG, gpio, false);
 
        /* Select "General Input/Output Mode" in IOINTSEL */
index 311f667..26e1fe0 100644 (file)
@@ -15,7 +15,7 @@ struct gpio_siox_ddata {
        u8 setdata[1];
        u8 getdata[3];
 
-       spinlock_t irqlock;
+       raw_spinlock_t irqlock;
        u32 irq_enable;
        u32 irq_status;
        u32 irq_type[20];
@@ -44,7 +44,7 @@ static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[])
 
        mutex_lock(&ddata->lock);
 
-       spin_lock_irq(&ddata->irqlock);
+       raw_spin_lock_irq(&ddata->irqlock);
 
        for (offset = 0; offset < 12; ++offset) {
                unsigned int bitpos = 11 - offset;
@@ -66,7 +66,7 @@ static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[])
 
        trigger = ddata->irq_status & ddata->irq_enable;
 
-       spin_unlock_irq(&ddata->irqlock);
+       raw_spin_unlock_irq(&ddata->irqlock);
 
        ddata->getdata[0] = buf[0];
        ddata->getdata[1] = buf[1];
@@ -84,9 +84,9 @@ static int gpio_siox_get_data(struct siox_device *sdevice, const u8 buf[])
                         * handler of the irq chip. But it doesn't, so we have
                         * to clean the irq_status here.
                         */
-                       spin_lock_irq(&ddata->irqlock);
+                       raw_spin_lock_irq(&ddata->irqlock);
                        ddata->irq_status &= ~(1 << offset);
-                       spin_unlock_irq(&ddata->irqlock);
+                       raw_spin_unlock_irq(&ddata->irqlock);
 
                        handle_nested_irq(irq);
                }
@@ -101,9 +101,9 @@ static void gpio_siox_irq_ack(struct irq_data *d)
        struct gpio_siox_ddata *ddata =
                container_of(ic, struct gpio_siox_ddata, ichip);
 
-       spin_lock_irq(&ddata->irqlock);
+       raw_spin_lock(&ddata->irqlock);
        ddata->irq_status &= ~(1 << d->hwirq);
-       spin_unlock_irq(&ddata->irqlock);
+       raw_spin_unlock(&ddata->irqlock);
 }
 
 static void gpio_siox_irq_mask(struct irq_data *d)
@@ -112,9 +112,9 @@ static void gpio_siox_irq_mask(struct irq_data *d)
        struct gpio_siox_ddata *ddata =
                container_of(ic, struct gpio_siox_ddata, ichip);
 
-       spin_lock_irq(&ddata->irqlock);
+       raw_spin_lock(&ddata->irqlock);
        ddata->irq_enable &= ~(1 << d->hwirq);
-       spin_unlock_irq(&ddata->irqlock);
+       raw_spin_unlock(&ddata->irqlock);
 }
 
 static void gpio_siox_irq_unmask(struct irq_data *d)
@@ -123,9 +123,9 @@ static void gpio_siox_irq_unmask(struct irq_data *d)
        struct gpio_siox_ddata *ddata =
                container_of(ic, struct gpio_siox_ddata, ichip);
 
-       spin_lock_irq(&ddata->irqlock);
+       raw_spin_lock(&ddata->irqlock);
        ddata->irq_enable |= 1 << d->hwirq;
-       spin_unlock_irq(&ddata->irqlock);
+       raw_spin_unlock(&ddata->irqlock);
 }
 
 static int gpio_siox_irq_set_type(struct irq_data *d, u32 type)
@@ -134,9 +134,9 @@ static int gpio_siox_irq_set_type(struct irq_data *d, u32 type)
        struct gpio_siox_ddata *ddata =
                container_of(ic, struct gpio_siox_ddata, ichip);
 
-       spin_lock_irq(&ddata->irqlock);
+       raw_spin_lock(&ddata->irqlock);
        ddata->irq_type[d->hwirq] = type;
-       spin_unlock_irq(&ddata->irqlock);
+       raw_spin_unlock(&ddata->irqlock);
 
        return 0;
 }
@@ -222,7 +222,7 @@ static int gpio_siox_probe(struct siox_device *sdevice)
        dev_set_drvdata(dev, ddata);
 
        mutex_init(&ddata->lock);
-       spin_lock_init(&ddata->irqlock);
+       raw_spin_lock_init(&ddata->irqlock);
 
        ddata->gchip.base = -1;
        ddata->gchip.can_sleep = 1;
index de24126..79b553d 100644 (file)
@@ -58,11 +58,20 @@ struct tegra_gpio_port {
        unsigned int pins;
 };
 
+struct tegra186_pin_range {
+       unsigned int offset;
+       const char *group;
+};
+
 struct tegra_gpio_soc {
        const struct tegra_gpio_port *ports;
        unsigned int num_ports;
        const char *name;
        unsigned int instance;
+
+       const struct tegra186_pin_range *pin_ranges;
+       unsigned int num_pin_ranges;
+       const char *pinmux;
 };
 
 struct tegra_gpio {
@@ -254,6 +263,50 @@ static int tegra186_gpio_set_config(struct gpio_chip *chip,
        return 0;
 }
 
+static int tegra186_gpio_add_pin_ranges(struct gpio_chip *chip)
+{
+       struct tegra_gpio *gpio = gpiochip_get_data(chip);
+       struct pinctrl_dev *pctldev;
+       struct device_node *np;
+       unsigned int i, j;
+       int err;
+
+       if (!gpio->soc->pinmux || gpio->soc->num_pin_ranges == 0)
+               return 0;
+
+       np = of_find_compatible_node(NULL, NULL, gpio->soc->pinmux);
+       if (!np)
+               return -ENODEV;
+
+       pctldev = of_pinctrl_get(np);
+       of_node_put(np);
+       if (!pctldev)
+               return -EPROBE_DEFER;
+
+       for (i = 0; i < gpio->soc->num_pin_ranges; i++) {
+               unsigned int pin = gpio->soc->pin_ranges[i].offset, port;
+               const char *group = gpio->soc->pin_ranges[i].group;
+
+               port = pin / 8;
+               pin = pin % 8;
+
+               if (port >= gpio->soc->num_ports) {
+                       dev_warn(chip->parent, "invalid port %u for %s\n",
+                                port, group);
+                       continue;
+               }
+
+               for (j = 0; j < port; j++)
+                       pin += gpio->soc->ports[j].pins;
+
+               err = gpiochip_add_pingroup_range(chip, pctldev, pin, group);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
 static int tegra186_gpio_of_xlate(struct gpio_chip *chip,
                                  const struct of_phandle_args *spec,
                                  u32 *flags)
@@ -578,12 +631,15 @@ static int tegra186_gpio_probe(struct platform_device *pdev)
        gpio->gpio.label = gpio->soc->name;
        gpio->gpio.parent = &pdev->dev;
 
+       gpio->gpio.request = gpiochip_generic_request;
+       gpio->gpio.free = gpiochip_generic_free;
        gpio->gpio.get_direction = tegra186_gpio_get_direction;
        gpio->gpio.direction_input = tegra186_gpio_direction_input;
        gpio->gpio.direction_output = tegra186_gpio_direction_output;
        gpio->gpio.get = tegra186_gpio_get,
        gpio->gpio.set = tegra186_gpio_set;
        gpio->gpio.set_config = tegra186_gpio_set_config;
+       gpio->gpio.add_pin_ranges = tegra186_gpio_add_pin_ranges;
 
        gpio->gpio.base = -1;
 
@@ -783,11 +839,19 @@ static const struct tegra_gpio_port tegra194_main_ports[] = {
        TEGRA194_MAIN_GPIO_PORT(GG, 0, 0, 2)
 };
 
+static const struct tegra186_pin_range tegra194_main_pin_ranges[] = {
+       { TEGRA194_MAIN_GPIO(GG, 0), "pex_l5_clkreq_n_pgg0" },
+       { TEGRA194_MAIN_GPIO(GG, 1), "pex_l5_rst_n_pgg1" },
+};
+
 static const struct tegra_gpio_soc tegra194_main_soc = {
        .num_ports = ARRAY_SIZE(tegra194_main_ports),
        .ports = tegra194_main_ports,
        .name = "tegra194-gpio",
        .instance = 0,
+       .num_pin_ranges = ARRAY_SIZE(tegra194_main_pin_ranges),
+       .pin_ranges = tegra194_main_pin_ranges,
+       .pinmux = "nvidia,tegra194-pinmux",
 };
 
 #define TEGRA194_AON_GPIO_PORT(_name, _bank, _port, _pins)     \
index 7ec9749..f99f3c1 100644 (file)
@@ -30,7 +30,7 @@ struct uniphier_gpio_priv {
        struct irq_domain *domain;
        void __iomem *regs;
        spinlock_t lock;
-       u32 saved_vals[0];
+       u32 saved_vals[];
 };
 
 static unsigned int uniphier_gpio_bank_to_reg(unsigned int bank)
index 74913f2..1cbce59 100644 (file)
@@ -57,16 +57,19 @@ static int wcd_gpio_direction_output(struct gpio_chip *chip, unsigned int pin,
 static int wcd_gpio_get(struct gpio_chip *chip, unsigned int pin)
 {
        struct wcd_gpio_data *data = gpiochip_get_data(chip);
-       int value;
+       unsigned int value;
 
        regmap_read(data->map, WCD_REG_VAL_CTL_OFFSET, &value);
 
-       return !!(value && WCD_PIN_MASK(pin));
+       return !!(value & WCD_PIN_MASK(pin));
 }
 
 static void wcd_gpio_set(struct gpio_chip *chip, unsigned int pin, int val)
 {
-       wcd_gpio_direction_output(chip, pin, val);
+       struct wcd_gpio_data *data = gpiochip_get_data(chip);
+
+       regmap_update_bits(data->map, WCD_REG_VAL_CTL_OFFSET,
+                          WCD_PIN_MASK(pin), val ? WCD_PIN_MASK(pin) : 0);
 }
 
 static int wcd_gpio_probe(struct platform_device *pdev)
index 72b6001..5c91c43 100644 (file)
@@ -478,3 +478,49 @@ void devm_gpio_free(struct device *dev, unsigned int gpio)
                &gpio));
 }
 EXPORT_SYMBOL_GPL(devm_gpio_free);
+
+static void devm_gpio_chip_release(struct device *dev, void *res)
+{
+       struct gpio_chip *gc = *(struct gpio_chip **)res;
+
+       gpiochip_remove(gc);
+}
+
+/**
+ * devm_gpiochip_add_data() - Resource managed gpiochip_add_data()
+ * @dev: pointer to the device that gpio_chip belongs to.
+ * @gc: the GPIO chip to register
+ * @data: driver-private data associated with this chip
+ *
+ * Context: potentially before irqs will work
+ *
+ * The gpio chip automatically be released when the device is unbound.
+ *
+ * Returns:
+ * A negative errno if the chip can't be registered, such as because the
+ * gc->base is invalid or already associated with a different chip.
+ * Otherwise it returns zero as a success code.
+ */
+int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *gc,
+                          void *data)
+{
+       struct gpio_chip **ptr;
+       int ret;
+
+       ptr = devres_alloc(devm_gpio_chip_release, sizeof(*ptr),
+                            GFP_KERNEL);
+       if (!ptr)
+               return -ENOMEM;
+
+       ret = gpiochip_add_data(gc, data);
+       if (ret < 0) {
+               devres_free(ptr);
+               return ret;
+       }
+
+       *ptr = gc;
+       devres_add(dev, ptr);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(devm_gpiochip_add_data);
index c6d30f7..ccc449d 100644 (file)
@@ -605,6 +605,39 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
 }
 
 /**
+ * of_gpiochip_add_hog - Add all hogs in a hog device node
+ * @chip:      gpio chip to act on
+ * @hog:       device node describing the hogs
+ *
+ * Returns error if it fails otherwise 0 on success.
+ */
+static int of_gpiochip_add_hog(struct gpio_chip *chip, struct device_node *hog)
+{
+       enum gpiod_flags dflags;
+       struct gpio_desc *desc;
+       unsigned long lflags;
+       const char *name;
+       unsigned int i;
+       int ret;
+
+       for (i = 0;; i++) {
+               desc = of_parse_own_gpio(hog, chip, i, &name, &lflags, &dflags);
+               if (IS_ERR(desc))
+                       break;
+
+               ret = gpiod_hog(desc, name, lflags, dflags);
+               if (ret < 0)
+                       return ret;
+
+#ifdef CONFIG_OF_DYNAMIC
+               desc->hog = hog;
+#endif
+       }
+
+       return 0;
+}
+
+/**
  * of_gpiochip_scan_gpios - Scan gpio-controller for gpio definitions
  * @chip:      gpio chip to act on
  *
@@ -614,35 +647,109 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np,
  */
 static int of_gpiochip_scan_gpios(struct gpio_chip *chip)
 {
-       struct gpio_desc *desc = NULL;
        struct device_node *np;
-       const char *name;
-       unsigned long lflags;
-       enum gpiod_flags dflags;
-       unsigned int i;
        int ret;
 
        for_each_available_child_of_node(chip->of_node, np) {
                if (!of_property_read_bool(np, "gpio-hog"))
                        continue;
 
-               for (i = 0;; i++) {
-                       desc = of_parse_own_gpio(np, chip, i, &name, &lflags,
-                                                &dflags);
-                       if (IS_ERR(desc))
-                               break;
-
-                       ret = gpiod_hog(desc, name, lflags, dflags);
-                       if (ret < 0) {
-                               of_node_put(np);
-                               return ret;
-                       }
+               ret = of_gpiochip_add_hog(chip, np);
+               if (ret < 0) {
+                       of_node_put(np);
+                       return ret;
                }
+
+               of_node_set_flag(np, OF_POPULATED);
        }
 
        return 0;
 }
 
+#ifdef CONFIG_OF_DYNAMIC
+/**
+ * of_gpiochip_remove_hog - Remove all hogs in a hog device node
+ * @chip:      gpio chip to act on
+ * @hog:       device node describing the hogs
+ */
+static void of_gpiochip_remove_hog(struct gpio_chip *chip,
+                                  struct device_node *hog)
+{
+       struct gpio_desc *descs = chip->gpiodev->descs;
+       unsigned int i;
+
+       for (i = 0; i < chip->ngpio; i++) {
+               if (test_bit(FLAG_IS_HOGGED, &descs[i].flags) &&
+                   descs[i].hog == hog)
+                       gpiochip_free_own_desc(&descs[i]);
+       }
+}
+
+static int of_gpiochip_match_node(struct gpio_chip *chip, void *data)
+{
+       return chip->gpiodev->dev.of_node == data;
+}
+
+static struct gpio_chip *of_find_gpiochip_by_node(struct device_node *np)
+{
+       return gpiochip_find(np, of_gpiochip_match_node);
+}
+
+static int of_gpio_notify(struct notifier_block *nb, unsigned long action,
+                         void *arg)
+{
+       struct of_reconfig_data *rd = arg;
+       struct gpio_chip *chip;
+       int ret;
+
+       /*
+        * This only supports adding and removing complete gpio-hog nodes.
+        * Modifying an existing gpio-hog node is not supported (except for
+        * changing its "status" property, which is treated the same as
+        * addition/removal).
+        */
+       switch (of_reconfig_get_state_change(action, arg)) {
+       case OF_RECONFIG_CHANGE_ADD:
+               if (!of_property_read_bool(rd->dn, "gpio-hog"))
+                       return NOTIFY_OK;       /* not for us */
+
+               if (of_node_test_and_set_flag(rd->dn, OF_POPULATED))
+                       return NOTIFY_OK;
+
+               chip = of_find_gpiochip_by_node(rd->dn->parent);
+               if (chip == NULL)
+                       return NOTIFY_OK;       /* not for us */
+
+               ret = of_gpiochip_add_hog(chip, rd->dn);
+               if (ret < 0) {
+                       pr_err("%s: failed to add hogs for %pOF\n", __func__,
+                              rd->dn);
+                       of_node_clear_flag(rd->dn, OF_POPULATED);
+                       return notifier_from_errno(ret);
+               }
+               break;
+
+       case OF_RECONFIG_CHANGE_REMOVE:
+               if (!of_node_check_flag(rd->dn, OF_POPULATED))
+                       return NOTIFY_OK;       /* already depopulated */
+
+               chip = of_find_gpiochip_by_node(rd->dn->parent);
+               if (chip == NULL)
+                       return NOTIFY_OK;       /* not for us */
+
+               of_gpiochip_remove_hog(chip, rd->dn);
+               of_node_clear_flag(rd->dn, OF_POPULATED);
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
+struct notifier_block gpio_of_notifier = {
+       .notifier_call = of_gpio_notify,
+};
+#endif /* CONFIG_OF_DYNAMIC */
+
 /**
  * of_gpio_simple_xlate - translate gpiospec to the GPIO number and flags
  * @gc:                pointer to the gpio_chip structure
index 9768831..ed26664 100644 (file)
@@ -35,4 +35,6 @@ static inline bool of_gpio_need_valid_mask(const struct gpio_chip *gc)
 }
 #endif /* CONFIG_OF_GPIO */
 
+extern struct notifier_block gpio_of_notifier;
+
 #endif /* GPIOLIB_OF_H */
index 4d0106c..e3616cc 100644 (file)
@@ -136,7 +136,7 @@ EXPORT_SYMBOL_GPL(gpio_to_desc);
  * @hwnum: hardware number of the GPIO for this chip
  *
  * Returns:
- * A pointer to the GPIO descriptor or %ERR_PTR(-EINVAL) if no GPIO exists
+ * A pointer to the GPIO descriptor or ``ERR_PTR(-EINVAL)`` if no GPIO exists
  * in the given chip for the specified hardware number.
  */
 struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip,
@@ -301,6 +301,9 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name)
        struct gpio_device *gdev;
        unsigned long flags;
 
+       if (!name)
+               return NULL;
+
        spin_lock_irqsave(&gpio_lock, flags);
 
        list_for_each_entry(gdev, &gpio_devices, list) {
@@ -309,7 +312,7 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name)
                for (i = 0; i != gdev->ngpio; ++i) {
                        struct gpio_desc *desc = &gdev->descs[i];
 
-                       if (!desc->name || !name)
+                       if (!desc->name)
                                continue;
 
                        if (!strcmp(desc->name, name)) {
@@ -546,6 +549,9 @@ static long linehandle_set_config(struct linehandle_state *lh,
                        if (ret)
                                return ret;
                }
+
+               atomic_notifier_call_chain(&desc->gdev->notifier,
+                                          GPIOLINE_CHANGED_CONFIG, desc);
        }
        return 0;
 }
@@ -787,8 +793,6 @@ out_free_lh:
  * @irq: the interrupt that trigger in response to events on this GPIO
  * @wait: wait queue that handles blocking reads of events
  * @events: KFIFO for the GPIO events
- * @read_lock: mutex lock to protect reads from colliding with adding
- * new events to the FIFO
  * @timestamp: cache for the timestamp storing it between hardirq
  * and IRQ thread, used to bring the timestamp close to the actual
  * event
@@ -801,7 +805,6 @@ struct lineevent_state {
        int irq;
        wait_queue_head_t wait;
        DECLARE_KFIFO(events, struct gpioevent_data, 16);
-       struct mutex read_lock;
        u64 timestamp;
 };
 
@@ -817,7 +820,7 @@ static __poll_t lineevent_poll(struct file *filep,
 
        poll_wait(filep, &le->wait, wait);
 
-       if (!kfifo_is_empty(&le->events))
+       if (!kfifo_is_empty_spinlocked_noirqsave(&le->events, &le->wait.lock))
                events = EPOLLIN | EPOLLRDNORM;
 
        return events;
@@ -830,43 +833,52 @@ static ssize_t lineevent_read(struct file *filep,
                              loff_t *f_ps)
 {
        struct lineevent_state *le = filep->private_data;
-       unsigned int copied;
+       struct gpioevent_data ge;
+       ssize_t bytes_read = 0;
        int ret;
 
-       if (count < sizeof(struct gpioevent_data))
+       if (count < sizeof(ge))
                return -EINVAL;
 
        do {
+               spin_lock(&le->wait.lock);
                if (kfifo_is_empty(&le->events)) {
-                       if (filep->f_flags & O_NONBLOCK)
+                       if (bytes_read) {
+                               spin_unlock(&le->wait.lock);
+                               return bytes_read;
+                       }
+
+                       if (filep->f_flags & O_NONBLOCK) {
+                               spin_unlock(&le->wait.lock);
                                return -EAGAIN;
+                       }
 
-                       ret = wait_event_interruptible(le->wait,
+                       ret = wait_event_interruptible_locked(le->wait,
                                        !kfifo_is_empty(&le->events));
-                       if (ret)
+                       if (ret) {
+                               spin_unlock(&le->wait.lock);
                                return ret;
+                       }
                }
 
-               if (mutex_lock_interruptible(&le->read_lock))
-                       return -ERESTARTSYS;
-               ret = kfifo_to_user(&le->events, buf, count, &copied);
-               mutex_unlock(&le->read_lock);
-
-               if (ret)
-                       return ret;
-
-               /*
-                * If we couldn't read anything from the fifo (a different
-                * thread might have been faster) we either return -EAGAIN if
-                * the file descriptor is non-blocking, otherwise we go back to
-                * sleep and wait for more data to arrive.
-                */
-               if (copied == 0 && (filep->f_flags & O_NONBLOCK))
-                       return -EAGAIN;
+               ret = kfifo_out(&le->events, &ge, 1);
+               spin_unlock(&le->wait.lock);
+               if (ret != 1) {
+                       /*
+                        * This should never happen - we were holding the lock
+                        * from the moment we learned the fifo is no longer
+                        * empty until now.
+                        */
+                       ret = -EIO;
+                       break;
+               }
 
-       } while (copied == 0);
+               if (copy_to_user(buf + bytes_read, &ge, sizeof(ge)))
+                       return -EFAULT;
+               bytes_read += sizeof(ge);
+       } while (count >= bytes_read + sizeof(ge));
 
-       return copied;
+       return bytes_read;
 }
 
 static int lineevent_release(struct inode *inode, struct file *filep)
@@ -945,7 +957,7 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p)
         * we didn't get the timestamp from lineevent_irq_handler().
         */
        if (!le->timestamp)
-               ge.timestamp = ktime_get_real_ns();
+               ge.timestamp = ktime_get_ns();
        else
                ge.timestamp = le->timestamp;
 
@@ -968,9 +980,12 @@ static irqreturn_t lineevent_irq_thread(int irq, void *p)
                return IRQ_NONE;
        }
 
-       ret = kfifo_put(&le->events, ge);
+       ret = kfifo_in_spinlocked_noirqsave(&le->events, &ge,
+                                           1, &le->wait.lock);
        if (ret)
                wake_up_poll(&le->wait, EPOLLIN);
+       else
+               pr_debug_ratelimited("event FIFO is full - event dropped\n");
 
        return IRQ_HANDLED;
 }
@@ -983,7 +998,7 @@ static irqreturn_t lineevent_irq_handler(int irq, void *p)
         * Just store the timestamp in hardirq context so we get it as
         * close in time as possible to the actual event.
         */
-       le->timestamp = ktime_get_real_ns();
+       le->timestamp = ktime_get_ns();
 
        return IRQ_WAKE_THREAD;
 }
@@ -1083,7 +1098,6 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
 
        INIT_KFIFO(le->events);
        init_waitqueue_head(&le->wait);
-       mutex_init(&le->read_lock);
 
        /* Request a thread to read the events */
        ret = request_threaded_irq(le->irq,
@@ -1139,14 +1153,79 @@ out_free_le:
        return ret;
 }
 
+static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
+                                 struct gpioline_info *info)
+{
+       struct gpio_chip *chip = desc->gdev->chip;
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpio_lock, flags);
+
+       if (desc->name) {
+               strncpy(info->name, desc->name, sizeof(info->name));
+               info->name[sizeof(info->name) - 1] = '\0';
+       } else {
+               info->name[0] = '\0';
+       }
+
+       if (desc->label) {
+               strncpy(info->consumer, desc->label, sizeof(info->consumer));
+               info->consumer[sizeof(info->consumer) - 1] = '\0';
+       } else {
+               info->consumer[0] = '\0';
+       }
+
+       /*
+        * Userspace only need to know that the kernel is using this GPIO so
+        * it can't use it.
+        */
+       info->flags = 0;
+       if (test_bit(FLAG_REQUESTED, &desc->flags) ||
+           test_bit(FLAG_IS_HOGGED, &desc->flags) ||
+           test_bit(FLAG_USED_AS_IRQ, &desc->flags) ||
+           test_bit(FLAG_EXPORT, &desc->flags) ||
+           test_bit(FLAG_SYSFS, &desc->flags) ||
+           !pinctrl_gpio_can_use_line(chip->base + info->line_offset))
+               info->flags |= GPIOLINE_FLAG_KERNEL;
+       if (test_bit(FLAG_IS_OUT, &desc->flags))
+               info->flags |= GPIOLINE_FLAG_IS_OUT;
+       if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
+               info->flags |= GPIOLINE_FLAG_ACTIVE_LOW;
+       if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
+               info->flags |= (GPIOLINE_FLAG_OPEN_DRAIN |
+                               GPIOLINE_FLAG_IS_OUT);
+       if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
+               info->flags |= (GPIOLINE_FLAG_OPEN_SOURCE |
+                               GPIOLINE_FLAG_IS_OUT);
+       if (test_bit(FLAG_BIAS_DISABLE, &desc->flags))
+               info->flags |= GPIOLINE_FLAG_BIAS_DISABLE;
+       if (test_bit(FLAG_PULL_DOWN, &desc->flags))
+               info->flags |= GPIOLINE_FLAG_BIAS_PULL_DOWN;
+       if (test_bit(FLAG_PULL_UP, &desc->flags))
+               info->flags |= GPIOLINE_FLAG_BIAS_PULL_UP;
+
+       spin_unlock_irqrestore(&gpio_lock, flags);
+}
+
+struct gpio_chardev_data {
+       struct gpio_device *gdev;
+       wait_queue_head_t wait;
+       DECLARE_KFIFO(events, struct gpioline_info_changed, 32);
+       struct notifier_block lineinfo_changed_nb;
+       unsigned long *watched_lines;
+};
+
 /*
  * gpio_ioctl() - ioctl handler for the GPIO chardev
  */
 static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
-       struct gpio_device *gdev = filp->private_data;
+       struct gpio_chardev_data *priv = filp->private_data;
+       struct gpio_device *gdev = priv->gdev;
        struct gpio_chip *chip = gdev->chip;
        void __user *ip = (void __user *)arg;
+       struct gpio_desc *desc;
+       __u32 offset;
 
        /* We fail any subsequent ioctl():s when the chip is gone */
        if (!chip)
@@ -1168,9 +1247,9 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                if (copy_to_user(ip, &chipinfo, sizeof(chipinfo)))
                        return -EFAULT;
                return 0;
-       } else if (cmd == GPIO_GET_LINEINFO_IOCTL) {
+       } else if (cmd == GPIO_GET_LINEINFO_IOCTL ||
+                  cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) {
                struct gpioline_info lineinfo;
-               struct gpio_desc *desc;
 
                if (copy_from_user(&lineinfo, ip, sizeof(lineinfo)))
                        return -EFAULT;
@@ -1179,57 +1258,29 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                if (IS_ERR(desc))
                        return PTR_ERR(desc);
 
-               if (desc->name) {
-                       strncpy(lineinfo.name, desc->name,
-                               sizeof(lineinfo.name));
-                       lineinfo.name[sizeof(lineinfo.name)-1] = '\0';
-               } else {
-                       lineinfo.name[0] = '\0';
-               }
-               if (desc->label) {
-                       strncpy(lineinfo.consumer, desc->label,
-                               sizeof(lineinfo.consumer));
-                       lineinfo.consumer[sizeof(lineinfo.consumer)-1] = '\0';
-               } else {
-                       lineinfo.consumer[0] = '\0';
-               }
-
-               /*
-                * Userspace only need to know that the kernel is using
-                * this GPIO so it can't use it.
-                */
-               lineinfo.flags = 0;
-               if (test_bit(FLAG_REQUESTED, &desc->flags) ||
-                   test_bit(FLAG_IS_HOGGED, &desc->flags) ||
-                   test_bit(FLAG_USED_AS_IRQ, &desc->flags) ||
-                   test_bit(FLAG_EXPORT, &desc->flags) ||
-                   test_bit(FLAG_SYSFS, &desc->flags) ||
-                   !pinctrl_gpio_can_use_line(chip->base + lineinfo.line_offset))
-                       lineinfo.flags |= GPIOLINE_FLAG_KERNEL;
-               if (test_bit(FLAG_IS_OUT, &desc->flags))
-                       lineinfo.flags |= GPIOLINE_FLAG_IS_OUT;
-               if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
-                       lineinfo.flags |= GPIOLINE_FLAG_ACTIVE_LOW;
-               if (test_bit(FLAG_OPEN_DRAIN, &desc->flags))
-                       lineinfo.flags |= (GPIOLINE_FLAG_OPEN_DRAIN |
-                                          GPIOLINE_FLAG_IS_OUT);
-               if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
-                       lineinfo.flags |= (GPIOLINE_FLAG_OPEN_SOURCE |
-                                          GPIOLINE_FLAG_IS_OUT);
-               if (test_bit(FLAG_BIAS_DISABLE, &desc->flags))
-                       lineinfo.flags |= GPIOLINE_FLAG_BIAS_DISABLE;
-               if (test_bit(FLAG_PULL_DOWN, &desc->flags))
-                       lineinfo.flags |= GPIOLINE_FLAG_BIAS_PULL_DOWN;
-               if (test_bit(FLAG_PULL_UP, &desc->flags))
-                       lineinfo.flags |= GPIOLINE_FLAG_BIAS_PULL_UP;
+               gpio_desc_to_lineinfo(desc, &lineinfo);
 
                if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
                        return -EFAULT;
+
+               if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL)
+                       set_bit(gpio_chip_hwgpio(desc), priv->watched_lines);
+
                return 0;
        } else if (cmd == GPIO_GET_LINEHANDLE_IOCTL) {
                return linehandle_create(gdev, ip);
        } else if (cmd == GPIO_GET_LINEEVENT_IOCTL) {
                return lineevent_create(gdev, ip);
+       } else if (cmd == GPIO_GET_LINEINFO_UNWATCH_IOCTL) {
+               if (copy_from_user(&offset, ip, sizeof(offset)))
+                       return -EFAULT;
+
+               desc = gpiochip_get_desc(chip, offset);
+               if (IS_ERR(desc))
+                       return PTR_ERR(desc);
+
+               clear_bit(gpio_chip_hwgpio(desc), priv->watched_lines);
+               return 0;
        }
        return -EINVAL;
 }
@@ -1242,6 +1293,101 @@ static long gpio_ioctl_compat(struct file *filp, unsigned int cmd,
 }
 #endif
 
+static struct gpio_chardev_data *
+to_gpio_chardev_data(struct notifier_block *nb)
+{
+       return container_of(nb, struct gpio_chardev_data, lineinfo_changed_nb);
+}
+
+static int lineinfo_changed_notify(struct notifier_block *nb,
+                                  unsigned long action, void *data)
+{
+       struct gpio_chardev_data *priv = to_gpio_chardev_data(nb);
+       struct gpioline_info_changed chg;
+       struct gpio_desc *desc = data;
+       int ret;
+
+       if (!test_bit(gpio_chip_hwgpio(desc), priv->watched_lines))
+               return NOTIFY_DONE;
+
+       memset(&chg, 0, sizeof(chg));
+       chg.info.line_offset = gpio_chip_hwgpio(desc);
+       chg.event_type = action;
+       chg.timestamp = ktime_get_ns();
+       gpio_desc_to_lineinfo(desc, &chg.info);
+
+       ret = kfifo_in_spinlocked(&priv->events, &chg, 1, &priv->wait.lock);
+       if (ret)
+               wake_up_poll(&priv->wait, EPOLLIN);
+       else
+               pr_debug_ratelimited("lineinfo event FIFO is full - event dropped\n");
+
+       return NOTIFY_OK;
+}
+
+static __poll_t lineinfo_watch_poll(struct file *filep,
+                                   struct poll_table_struct *pollt)
+{
+       struct gpio_chardev_data *priv = filep->private_data;
+       __poll_t events = 0;
+
+       poll_wait(filep, &priv->wait, pollt);
+
+       if (!kfifo_is_empty_spinlocked_noirqsave(&priv->events,
+                                                &priv->wait.lock))
+               events = EPOLLIN | EPOLLRDNORM;
+
+       return events;
+}
+
+static ssize_t lineinfo_watch_read(struct file *filep, char __user *buf,
+                                  size_t count, loff_t *off)
+{
+       struct gpio_chardev_data *priv = filep->private_data;
+       struct gpioline_info_changed event;
+       ssize_t bytes_read = 0;
+       int ret;
+
+       if (count < sizeof(event))
+               return -EINVAL;
+
+       do {
+               spin_lock(&priv->wait.lock);
+               if (kfifo_is_empty(&priv->events)) {
+                       if (bytes_read) {
+                               spin_unlock(&priv->wait.lock);
+                               return bytes_read;
+                       }
+
+                       if (filep->f_flags & O_NONBLOCK) {
+                               spin_unlock(&priv->wait.lock);
+                               return -EAGAIN;
+                       }
+
+                       ret = wait_event_interruptible_locked(priv->wait,
+                                       !kfifo_is_empty(&priv->events));
+                       if (ret) {
+                               spin_unlock(&priv->wait.lock);
+                               return ret;
+                       }
+               }
+
+               ret = kfifo_out(&priv->events, &event, 1);
+               spin_unlock(&priv->wait.lock);
+               if (ret != 1) {
+                       ret = -EIO;
+                       break;
+                       /* We should never get here. See lineevent_read(). */
+               }
+
+               if (copy_to_user(buf + bytes_read, &event, sizeof(event)))
+                       return -EFAULT;
+               bytes_read += sizeof(event);
+       } while (count >= bytes_read + sizeof(event));
+
+       return bytes_read;
+}
+
 /**
  * gpio_chrdev_open() - open the chardev for ioctl operations
  * @inode: inode for this chardev
@@ -1252,14 +1398,48 @@ static int gpio_chrdev_open(struct inode *inode, struct file *filp)
 {
        struct gpio_device *gdev = container_of(inode->i_cdev,
                                              struct gpio_device, chrdev);
+       struct gpio_chardev_data *priv;
+       int ret = -ENOMEM;
 
        /* Fail on open if the backing gpiochip is gone */
        if (!gdev->chip)
                return -ENODEV;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->watched_lines = bitmap_zalloc(gdev->chip->ngpio, GFP_KERNEL);
+       if (!priv->watched_lines)
+               goto out_free_priv;
+
+       init_waitqueue_head(&priv->wait);
+       INIT_KFIFO(priv->events);
+       priv->gdev = gdev;
+
+       priv->lineinfo_changed_nb.notifier_call = lineinfo_changed_notify;
+       ret = atomic_notifier_chain_register(&gdev->notifier,
+                                            &priv->lineinfo_changed_nb);
+       if (ret)
+               goto out_free_bitmap;
+
        get_device(&gdev->dev);
-       filp->private_data = gdev;
+       filp->private_data = priv;
+
+       ret = nonseekable_open(inode, filp);
+       if (ret)
+               goto out_unregister_notifier;
+
+       return ret;
 
-       return nonseekable_open(inode, filp);
+out_unregister_notifier:
+       atomic_notifier_chain_unregister(&gdev->notifier,
+                                        &priv->lineinfo_changed_nb);
+out_free_bitmap:
+       bitmap_free(priv->watched_lines);
+out_free_priv:
+       kfree(priv);
+       return ret;
 }
 
 /**
@@ -1270,17 +1450,23 @@ static int gpio_chrdev_open(struct inode *inode, struct file *filp)
  */
 static int gpio_chrdev_release(struct inode *inode, struct file *filp)
 {
-       struct gpio_device *gdev = container_of(inode->i_cdev,
-                                             struct gpio_device, chrdev);
+       struct gpio_chardev_data *priv = filp->private_data;
+       struct gpio_device *gdev = priv->gdev;
 
+       bitmap_free(priv->watched_lines);
+       atomic_notifier_chain_unregister(&gdev->notifier,
+                                        &priv->lineinfo_changed_nb);
        put_device(&gdev->dev);
+       kfree(priv);
+
        return 0;
 }
 
-
 static const struct file_operations gpio_fileops = {
        .release = gpio_chrdev_release,
        .open = gpio_chrdev_open,
+       .poll = lineinfo_watch_poll,
+       .read = lineinfo_watch_read,
        .owner = THIS_MODULE,
        .llseek = no_llseek,
        .unlocked_ioctl = gpio_ioctl,
@@ -1491,6 +1677,8 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data,
 
        spin_unlock_irqrestore(&gpio_lock, flags);
 
+       ATOMIC_INIT_NOTIFIER_HEAD(&gdev->notifier);
+
 #ifdef CONFIG_PINCTRL
        INIT_LIST_HEAD(&gdev->pin_ranges);
 #endif
@@ -1612,10 +1800,8 @@ EXPORT_SYMBOL_GPL(gpiochip_get_data);
 void gpiochip_remove(struct gpio_chip *chip)
 {
        struct gpio_device *gdev = chip->gpiodev;
-       struct gpio_desc *desc;
        unsigned long   flags;
-       unsigned        i;
-       bool            requested = false;
+       unsigned int    i;
 
        /* FIXME: should the legacy sysfs handling be moved to gpio_device? */
        gpiochip_sysfs_unregister(gdev);
@@ -1635,13 +1821,12 @@ void gpiochip_remove(struct gpio_chip *chip)
 
        spin_lock_irqsave(&gpio_lock, flags);
        for (i = 0; i < gdev->ngpio; i++) {
-               desc = &gdev->descs[i];
-               if (test_bit(FLAG_REQUESTED, &desc->flags))
-                       requested = true;
+               if (gpiochip_is_requested(chip, i))
+                       break;
        }
        spin_unlock_irqrestore(&gpio_lock, flags);
 
-       if (requested)
+       if (i != gdev->ngpio)
                dev_crit(&gdev->dev,
                         "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
 
@@ -1656,52 +1841,6 @@ void gpiochip_remove(struct gpio_chip *chip)
 }
 EXPORT_SYMBOL_GPL(gpiochip_remove);
 
-static void devm_gpio_chip_release(struct device *dev, void *res)
-{
-       struct gpio_chip *chip = *(struct gpio_chip **)res;
-
-       gpiochip_remove(chip);
-}
-
-/**
- * devm_gpiochip_add_data() - Resource managed gpiochip_add_data()
- * @dev: pointer to the device that gpio_chip belongs to.
- * @chip: the chip to register, with chip->base initialized
- * @data: driver-private data associated with this chip
- *
- * Context: potentially before irqs will work
- *
- * The gpio chip automatically be released when the device is unbound.
- *
- * Returns:
- * A negative errno if the chip can't be registered, such as because the
- * chip->base is invalid or already associated with a different chip.
- * Otherwise it returns zero as a success code.
- */
-int devm_gpiochip_add_data(struct device *dev, struct gpio_chip *chip,
-                          void *data)
-{
-       struct gpio_chip **ptr;
-       int ret;
-
-       ptr = devres_alloc(devm_gpio_chip_release, sizeof(*ptr),
-                            GFP_KERNEL);
-       if (!ptr)
-               return -ENOMEM;
-
-       ret = gpiochip_add_data(chip, data);
-       if (ret < 0) {
-               devres_free(ptr);
-               return ret;
-       }
-
-       *ptr = chip;
-       devres_add(dev, ptr);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(devm_gpiochip_add_data);
-
 /**
  * gpiochip_find() - iterator for locating a specific gpio_chip
  * @data: data to pass to match function
@@ -2606,7 +2745,10 @@ static inline void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip)
  */
 int gpiochip_generic_request(struct gpio_chip *chip, unsigned offset)
 {
-       return pinctrl_gpio_request(chip->gpiodev->base + offset);
+       if (!list_empty(&chip->gpiodev->pin_ranges))
+               return pinctrl_gpio_request(chip->gpiodev->base + offset);
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(gpiochip_generic_request);
 
@@ -2823,6 +2965,8 @@ static int gpiod_request_commit(struct gpio_desc *desc, const char *label)
        }
 done:
        spin_unlock_irqrestore(&gpio_lock, flags);
+       atomic_notifier_call_chain(&desc->gdev->notifier,
+                                  GPIOLINE_CHANGED_REQUESTED, desc);
        return ret;
 }
 
@@ -2916,10 +3060,16 @@ static bool gpiod_free_commit(struct gpio_desc *desc)
                clear_bit(FLAG_PULL_DOWN, &desc->flags);
                clear_bit(FLAG_BIAS_DISABLE, &desc->flags);
                clear_bit(FLAG_IS_HOGGED, &desc->flags);
+#ifdef CONFIG_OF_DYNAMIC
+               desc->hog = NULL;
+#endif
                ret = true;
        }
 
        spin_unlock_irqrestore(&gpio_lock, flags);
+       atomic_notifier_call_chain(&desc->gdev->notifier,
+                                  GPIOLINE_CHANGED_RELEASED, desc);
+
        return ret;
 }
 
@@ -2953,7 +3103,9 @@ const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset)
        if (offset >= chip->ngpio)
                return NULL;
 
-       desc = &chip->gpiodev->descs[offset];
+       desc = gpiochip_get_desc(chip, offset);
+       if (IS_ERR(desc))
+               return NULL;
 
        if (test_bit(FLAG_REQUESTED, &desc->flags) == 0)
                return NULL;
@@ -5109,10 +5261,15 @@ static int __init gpiolib_dev_init(void)
        if (ret < 0) {
                pr_err("gpiolib: failed to allocate char dev region\n");
                bus_unregister(&gpio_bus_type);
-       } else {
-               gpiolib_initialized = true;
-               gpiochip_setup_devs();
+               return ret;
        }
+
+       gpiolib_initialized = true;
+       gpiochip_setup_devs();
+
+       if (IS_ENABLED(CONFIG_OF_DYNAMIC))
+               WARN_ON(of_reconfig_notifier_register(&gpio_of_notifier));
+
        return ret;
 }
 core_initcall(gpiolib_dev_init);
index 3e0aab2..853ce68 100644 (file)
@@ -56,6 +56,7 @@ struct gpio_device {
        const char              *label;
        void                    *data;
        struct list_head        list;
+       struct atomic_notifier_head notifier;
 
 #ifdef CONFIG_PINCTRL
        /*
@@ -119,6 +120,9 @@ struct gpio_desc {
        const char              *label;
        /* Name of the GPIO */
        const char              *name;
+#ifdef CONFIG_OF_DYNAMIC
+       struct device_node      *hog;
+#endif
 };
 
 int gpiod_request(struct gpio_desc *desc, const char *label);
index 19eadac..aea9aee 100644 (file)
@@ -2,10 +2,8 @@
 #ifndef _ASM_GENERIC_GPIO_H
 #define _ASM_GENERIC_GPIO_H
 
-#include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/errno.h>
-#include <linux/of.h>
 
 #ifdef CONFIG_GPIOLIB
 
@@ -140,6 +138,8 @@ static inline void gpio_unexport(unsigned gpio)
 
 #else  /* !CONFIG_GPIOLIB */
 
+#include <linux/kernel.h>
+
 static inline bool gpio_is_valid(int number)
 {
        /* only non-negative numbers are valid */
index 2157717..008ad3e 100644 (file)
@@ -102,11 +102,9 @@ void devm_gpio_free(struct device *dev, unsigned int gpio);
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/bug.h>
-#include <linux/pinctrl/pinctrl.h>
 
 struct device;
 struct gpio_chip;
-struct pinctrl_dev;
 
 static inline bool gpio_is_valid(int number)
 {
index bf2d017..0a72fcc 100644 (file)
@@ -2,9 +2,10 @@
 #ifndef __LINUX_GPIO_CONSUMER_H
 #define __LINUX_GPIO_CONSUMER_H
 
+#include <linux/bits.h>
 #include <linux/bug.h>
+#include <linux/compiler_types.h>
 #include <linux/err.h>
-#include <linux/kernel.h>
 
 struct device;
 
@@ -189,6 +190,8 @@ struct gpio_desc *devm_fwnode_gpiod_get_index(struct device *dev,
 
 #else /* CONFIG_GPIOLIB */
 
+#include <linux/kernel.h>
+
 static inline int gpiod_count(struct device *dev, const char *con_id)
 {
        return 0;
index 6ef05bc..ed65e00 100644 (file)
@@ -572,6 +572,7 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
 #define BGPIOF_BIG_ENDIAN_BYTE_ORDER   BIT(3)
 #define BGPIOF_READ_OUTPUT_REG_SET     BIT(4) /* reg_set stores output value */
 #define BGPIOF_NO_OUTPUT               BIT(5) /* only input */
+#define BGPIOF_NO_SET_ON_INPUT         BIT(6)
 
 int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
                     irq_hw_number_t hwirq);
index fc4b0b1..8624947 100644 (file)
@@ -247,6 +247,37 @@ __kfifo_int_must_check_helper(int val)
 })
 
 /**
+ * kfifo_is_empty_spinlocked - returns true if the fifo is empty using
+ * a spinlock for locking
+ * @fifo: address of the fifo to be used
+ * @lock: spinlock to be used for locking
+ */
+#define kfifo_is_empty_spinlocked(fifo, lock) \
+({ \
+       unsigned long __flags; \
+       bool __ret; \
+       spin_lock_irqsave(lock, __flags); \
+       __ret = kfifo_is_empty(fifo); \
+       spin_unlock_irqrestore(lock, __flags); \
+       __ret; \
+})
+
+/**
+ * kfifo_is_empty_spinlocked_noirqsave  - returns true if the fifo is empty
+ * using a spinlock for locking, doesn't disable interrupts
+ * @fifo: address of the fifo to be used
+ * @lock: spinlock to be used for locking
+ */
+#define kfifo_is_empty_spinlocked_noirqsave(fifo, lock) \
+({ \
+       bool __ret; \
+       spin_lock(lock); \
+       __ret = kfifo_is_empty(fifo); \
+       spin_unlock(lock); \
+       __ret; \
+})
+
+/**
  * kfifo_is_full - returns true if the fifo is full
  * @fifo: address of the fifo to be used
  */
@@ -517,6 +548,26 @@ __kfifo_uint_must_check_helper( \
        __ret; \
 })
 
+/**
+ * kfifo_in_spinlocked_noirqsave - put data into fifo using a spinlock for
+ * locking, don't disable interrupts
+ * @fifo: address of the fifo to be used
+ * @buf: the data to be added
+ * @n: number of elements to be added
+ * @lock: pointer to the spinlock to use for locking
+ *
+ * This is a variant of kfifo_in_spinlocked() but uses spin_lock/unlock()
+ * for locking and doesn't disable interrupts.
+ */
+#define kfifo_in_spinlocked_noirqsave(fifo, buf, n, lock) \
+({ \
+       unsigned int __ret; \
+       spin_lock(lock); \
+       __ret = kfifo_in(fifo, buf, n); \
+       spin_unlock(lock); \
+       __ret; \
+})
+
 /* alias for kfifo_in_spinlocked, will be removed in a future release */
 #define kfifo_in_locked(fifo, buf, n, lock) \
                kfifo_in_spinlocked(fifo, buf, n, lock)
@@ -569,6 +620,28 @@ __kfifo_uint_must_check_helper( \
 }) \
 )
 
+/**
+ * kfifo_out_spinlocked_noirqsave - get data from the fifo using a spinlock
+ * for locking, don't disable interrupts
+ * @fifo: address of the fifo to be used
+ * @buf: pointer to the storage buffer
+ * @n: max. number of elements to get
+ * @lock: pointer to the spinlock to use for locking
+ *
+ * This is a variant of kfifo_out_spinlocked() which uses spin_lock/unlock()
+ * for locking and doesn't disable interrupts.
+ */
+#define kfifo_out_spinlocked_noirqsave(fifo, buf, n, lock) \
+__kfifo_uint_must_check_helper( \
+({ \
+       unsigned int __ret; \
+       spin_lock(lock); \
+       __ret = kfifo_out(fifo, buf, n); \
+       spin_unlock(lock); \
+       __ret; \
+}) \
+)
+
 /* alias for kfifo_out_spinlocked, will be removed in a future release */
 #define kfifo_out_locked(fifo, buf, n, lock) \
                kfifo_out_spinlocked(fifo, buf, n, lock)
index 1696739..f821095 100644 (file)
@@ -11,9 +11,8 @@
 #define __LINUX_OF_GPIO_H
 
 #include <linux/compiler.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
+#include <linux/gpio.h>                /* FIXME: Shouldn't be here */
 #include <linux/of.h>
 
 struct device_node;
@@ -34,6 +33,8 @@ enum of_gpio_flags {
 
 #ifdef CONFIG_OF_GPIO
 
+#include <linux/kernel.h>
+
 /*
  * OF GPIO chip for memory mapped banks
  */
@@ -63,6 +64,8 @@ extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc);
 
 #else /* CONFIG_OF_GPIO */
 
+#include <linux/errno.h>
+
 /* Drivers may not strictly depend on the GPIO support, so let them link. */
 static inline int of_get_named_gpio_flags(struct device_node *np,
                const char *list_name, int index, enum of_gpio_flags *flags)
index 799cf82..0206383 100644 (file)
@@ -18,7 +18,7 @@
  * struct gpiochip_info - Information about a certain GPIO chip
  * @name: the Linux kernel name of this GPIO chip
  * @label: a functional name for this GPIO chip, such as a product
- * number, may be NULL
+ * number, may be empty
  * @lines: number of GPIO lines on this chip
  */
 struct gpiochip_info {
@@ -44,10 +44,10 @@ struct gpiochip_info {
  * @flags: various flags for this line
  * @name: the name of this GPIO line, such as the output pin of the line on the
  * chip, a rail or a pin header name on a board, as specified by the gpio
- * chip, may be NULL
+ * chip, may be empty
  * @consumer: a functional name for the consumer of this GPIO line as set by
- * whatever is using it, will be NULL if there is no current user but may
- * also be NULL if the consumer doesn't set this up
+ * whatever is using it, will be empty if there is no current user but may
+ * also be empty if the consumer doesn't set this up
  */
 struct gpioline_info {
        __u32 line_offset;
@@ -59,6 +59,34 @@ struct gpioline_info {
 /* Maximum number of requested handles */
 #define GPIOHANDLES_MAX 64
 
+/* Possible line status change events */
+enum {
+       GPIOLINE_CHANGED_REQUESTED = 1,
+       GPIOLINE_CHANGED_RELEASED,
+       GPIOLINE_CHANGED_CONFIG,
+};
+
+/**
+ * struct gpioline_info_changed - Information about a change in status
+ * of a GPIO line
+ * @info: updated line information
+ * @timestamp: estimate of time of status change occurrence, in nanoseconds
+ * and GPIOLINE_CHANGED_CONFIG
+ * @event_type: one of GPIOLINE_CHANGED_REQUESTED, GPIOLINE_CHANGED_RELEASED
+ *
+ * Note: struct gpioline_info embedded here has 32-bit alignment on its own,
+ * but it works fine with 64-bit alignment too. With its 72 byte size, we can
+ * guarantee there are no implicit holes between it and subsequent members.
+ * The 20-byte padding at the end makes sure we don't add any implicit padding
+ * at the end of the structure on 64-bit architectures.
+ */
+struct gpioline_info_changed {
+       struct gpioline_info info;
+       __u64 timestamp;
+       __u32 event_type;
+       __u32 padding[5]; /* for future use */
+};
+
 /* Linerequest flags */
 #define GPIOHANDLE_REQUEST_INPUT       (1UL << 0)
 #define GPIOHANDLE_REQUEST_OUTPUT      (1UL << 1)
@@ -176,6 +204,8 @@ struct gpioevent_data {
 
 #define GPIO_GET_CHIPINFO_IOCTL _IOR(0xB4, 0x01, struct gpiochip_info)
 #define GPIO_GET_LINEINFO_IOCTL _IOWR(0xB4, 0x02, struct gpioline_info)
+#define GPIO_GET_LINEINFO_WATCH_IOCTL _IOWR(0xB4, 0x0b, struct gpioline_info)
+#define GPIO_GET_LINEINFO_UNWATCH_IOCTL _IOWR(0xB4, 0x0c, __u32)
 #define GPIO_GET_LINEHANDLE_IOCTL _IOWR(0xB4, 0x03, struct gpiohandle_request)
 #define GPIO_GET_LINEEVENT_IOCTL _IOWR(0xB4, 0x04, struct gpioevent_request)
 
index a94c0e8..eab36c6 100644 (file)
@@ -1,4 +1,5 @@
 gpio-event-mon
 gpio-hammer
+gpio-watch
 lsgpio
 include/linux/gpio.h
index 4141f35..67c7b7f 100644 (file)
@@ -2,3 +2,4 @@ gpio-utils-y += gpio-utils.o
 lsgpio-y += lsgpio.o gpio-utils.o
 gpio-hammer-y += gpio-hammer.o gpio-utils.o
 gpio-event-mon-y += gpio-event-mon.o gpio-utils.o
+gpio-watch-y += gpio-watch.o
index 6080de5..4404340 100644 (file)
@@ -18,7 +18,7 @@ MAKEFLAGS += -r
 
 override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
 
-ALL_TARGETS := lsgpio gpio-hammer gpio-event-mon
+ALL_TARGETS := lsgpio gpio-hammer gpio-event-mon gpio-watch
 ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))
 
 all: $(ALL_PROGRAMS)
@@ -35,7 +35,7 @@ $(OUTPUT)include/linux/gpio.h: ../../include/uapi/linux/gpio.h
 
 prepare: $(OUTPUT)include/linux/gpio.h
 
-GPIO_UTILS_IN := $(output)gpio-utils-in.o
+GPIO_UTILS_IN := $(OUTPUT)gpio-utils-in.o
 $(GPIO_UTILS_IN): prepare FORCE
        $(Q)$(MAKE) $(build)=gpio-utils
 
@@ -66,6 +66,15 @@ $(GPIO_EVENT_MON_IN): prepare FORCE $(OUTPUT)gpio-utils-in.o
 $(OUTPUT)gpio-event-mon: $(GPIO_EVENT_MON_IN)
        $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
 
+#
+# gpio-watch
+#
+GPIO_WATCH_IN := $(OUTPUT)gpio-watch-in.o
+$(GPIO_WATCH_IN): prepare FORCE
+       $(Q)$(MAKE) $(build)=gpio-watch
+$(OUTPUT)gpio-watch: $(GPIO_WATCH_IN)
+       $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
+
 clean:
        rm -f $(ALL_PROGRAMS)
        rm -f $(OUTPUT)include/linux/gpio.h
index 0e0060a..9fd926e 100644 (file)
@@ -77,7 +77,7 @@ int hammer_device(const char *device_name, unsigned int *lines, int nlines,
 
                fprintf(stdout, "[%c] ", swirr[j]);
                j++;
-               if (j == sizeof(swirr)-1)
+               if (j == sizeof(swirr) - 1)
                        j = 0;
 
                fprintf(stdout, "[");
@@ -135,7 +135,14 @@ int main(int argc, char **argv)
                        device_name = optarg;
                        break;
                case 'o':
-                       lines[i] = strtoul(optarg, NULL, 10);
+                       /*
+                        * Avoid overflow. Do not immediately error, we want to
+                        * be able to accurately report on the amount of times
+                        * '-o' was given to give an accurate error message
+                        */
+                       if (i < GPIOHANDLES_MAX)
+                               lines[i] = strtoul(optarg, NULL, 10);
+
                        i++;
                        break;
                case '?':
@@ -143,6 +150,14 @@ int main(int argc, char **argv)
                        return -1;
                }
        }
+
+       if (i >= GPIOHANDLES_MAX) {
+               fprintf(stderr,
+                       "Only %d occurrences of '-o' are allowed, %d were found\n",
+                       GPIOHANDLES_MAX, i + 1);
+               return -1;
+       }
+
        nlines = i;
 
        if (!device_name || !nlines) {
index 53470de..0600378 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/gpio.h>
 #include "gpio-utils.h"
 
-#define COMSUMER "gpio-utils"
+#define CONSUMER "gpio-utils"
 
 /**
  * doc: Operation of gpio
@@ -209,7 +209,7 @@ int gpiotools_gets(const char *device_name, unsigned int *lines,
 
        ret = gpiotools_request_linehandle(device_name, lines, nlines,
                                           GPIOHANDLE_REQUEST_INPUT, data,
-                                          COMSUMER);
+                                          CONSUMER);
        if (ret < 0)
                return ret;
 
@@ -259,7 +259,7 @@ int gpiotools_sets(const char *device_name, unsigned int *lines,
 
        ret = gpiotools_request_linehandle(device_name, lines, nlines,
                                           GPIOHANDLE_REQUEST_OUTPUT, data,
-                                          COMSUMER);
+                                          CONSUMER);
        if (ret < 0)
                return ret;
 
diff --git a/tools/gpio/gpio-watch.c b/tools/gpio/gpio-watch.c
new file mode 100644 (file)
index 0000000..5cea24f
--- /dev/null
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * gpio-watch - monitor unrequested lines for property changes using the
+ *              character device
+ *
+ * Copyright (C) 2019 BayLibre SAS
+ * Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/gpio.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+int main(int argc, char **argv)
+{
+       struct gpioline_info_changed chg;
+       struct gpioline_info req;
+       struct pollfd pfd;
+       int fd, i, j, ret;
+       char *event, *end;
+       ssize_t rd;
+
+       if (argc < 3)
+               goto err_usage;
+
+       fd = open(argv[1], O_RDWR | O_CLOEXEC);
+       if (fd < 0) {
+               perror("unable to open gpiochip");
+               return EXIT_FAILURE;
+       }
+
+       for (i = 0, j = 2; i < argc - 2; i++, j++) {
+               memset(&req, 0, sizeof(req));
+
+               req.line_offset = strtoul(argv[j], &end, 0);
+               if (*end != '\0')
+                       goto err_usage;
+
+               ret = ioctl(fd, GPIO_GET_LINEINFO_WATCH_IOCTL, &req);
+               if (ret) {
+                       perror("unable to set up line watch");
+                       return EXIT_FAILURE;
+               }
+       }
+
+       pfd.fd = fd;
+       pfd.events = POLLIN | POLLPRI;
+
+       for (;;) {
+               ret = poll(&pfd, 1, 5000);
+               if (ret < 0) {
+                       perror("error polling the linechanged fd");
+                       return EXIT_FAILURE;
+               } else if (ret > 0) {
+                       memset(&chg, 0, sizeof(chg));
+                       rd = read(pfd.fd, &chg, sizeof(chg));
+                       if (rd < 0 || rd != sizeof(chg)) {
+                               if (rd != sizeof(chg))
+                                       errno = EIO;
+
+                               perror("error reading line change event");
+                               return EXIT_FAILURE;
+                       }
+
+                       switch (chg.event_type) {
+                       case GPIOLINE_CHANGED_REQUESTED:
+                               event = "requested";
+                               break;
+                       case GPIOLINE_CHANGED_RELEASED:
+                               event = "released";
+                               break;
+                       case GPIOLINE_CHANGED_CONFIG:
+                               event = "config changed";
+                               break;
+                       default:
+                               fprintf(stderr,
+                                       "invalid event type received from the kernel\n");
+                               return EXIT_FAILURE;
+                       }
+
+                       printf("line %u: %s at %llu\n",
+                              chg.info.line_offset, event, chg.timestamp);
+               }
+       }
+
+       return 0;
+
+err_usage:
+       printf("%s: <gpiochip> <line0> <line1> ...\n", argv[0]);
+       return EXIT_FAILURE;
+}