summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-12-15 09:45:51 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2022-12-15 09:45:51 -0800
commitc0f234ff90a211272138be1611ba53f3155ebd78 (patch)
tree956c32a903675d690631100ae829e810b4b4515b /drivers
parent9fa4abc9ad2a18410a7087e6cea15ad1ffb172c6 (diff)
parent11e47bbd700f31bd1ee9f8863381bc9e741c0e97 (diff)
Merge tag 'gpio-updates-for-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio updates from Bartosz Golaszewski: "We have a new GPIO multiplexer driver, bunch of driver updates and refactoring in the core GPIO library. GPIO core: - teach gpiolib to work with software nodes for HW description - remove ARCH_NR_GPIOS treewide as we no longer impose any limit on the number of GPIOS since the allocation became entirely dynamic - add support for HW quirks for Cirrus CS42L56 codec, Marvell NFC controller, Freescale PCIe and Ethernet controller, Himax LCDs and Mediatek mt2701 - refactor OF quirk code - some general refactoring of the OF and ACPI code, adding new helpers, minor tweaks and fixes, making fwnode usage consistent etc. GPIO uAPI: - fix an issue where the user-space can trigger a NULL-pointer dereference in the kernel by opening a device file, forcing a driver unbind and then calling one of the syscalls on the associated file descriptor New drivers: - add gpio-latch: a new GPIO multiplexer based on latches connected to other GPIOs Driver updates: - convert i2c GPIO expanders to using .probe_new() - drop the gpio-sta2x11 driver - factor out common code for the ACCES IDIO-16 family of controllers and use this new library wherever applicable in drivers - add DT support to gpio-hisi - allow building gpio-davinci as a module and increase its maxItems property - add support for a new model to gpio-pca9570 - other minor changes to various drivers" * tag 'gpio-updates-for-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (66 commits) gpio: sim: set a limit on the number of GPIOs gpiolib: protect the GPIO device against being dropped while in use by user-space gpiolib: cdev: fix NULL-pointer dereferences gpiolib: Provide to_gpio_device() helper gpiolib: Unify access to the device properties gpio: Do not include <linux/kernel.h> when not really needed. gpio: pcf857x: Convert to i2c's .probe_new() gpio: pca953x: Convert to i2c's .probe_new() gpio: max732x: Convert to i2c's .probe_new() dt-bindings: gpio: gpio-davinci: Increase maxItems in gpio-line-names gpiolib: ensure that fwnode is properly set gpio: sl28cpld: Replace irqchip mask_invert with unmask_base gpiolib: of: Use correct fwnode for DT-probed chips gpiolib: of: Drop redundant check in of_mm_gpiochip_remove() gpiolib: of: Prepare of_mm_gpiochip_add_data() for fwnode gpiolib: add support for software nodes gpiolib: consolidate GPIO lookups gpiolib: acpi: avoid leaking ACPI details into upper gpiolib layers gpiolib: acpi: teach acpi_find_gpio() to handle data-only nodes gpiolib: acpi: change acpi_find_gpio() to accept firmware node ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpio/Kconfig29
-rw-r--r--drivers/gpio/Makefile4
-rw-r--r--drivers/gpio/TODO7
-rw-r--r--drivers/gpio/gpio-104-idio-16.c88
-rw-r--r--drivers/gpio/gpio-aggregator.c7
-rw-r--r--drivers/gpio/gpio-davinci.c14
-rw-r--r--drivers/gpio/gpio-exar.c1
-rw-r--r--drivers/gpio/gpio-ftgpio010.c2
-rw-r--r--drivers/gpio/gpio-gw-pld.c5
-rw-r--r--drivers/gpio/gpio-hisi.c7
-rw-r--r--drivers/gpio/gpio-idio-16.c146
-rw-r--r--drivers/gpio/gpio-idio-16.h71
-rw-r--r--drivers/gpio/gpio-latch.c219
-rw-r--r--drivers/gpio/gpio-max7300.c5
-rw-r--r--drivers/gpio/gpio-max732x.c6
-rw-r--r--drivers/gpio/gpio-merrifield.c3
-rw-r--r--drivers/gpio/gpio-pca953x.c6
-rw-r--r--drivers/gpio/gpio-pca9570.c49
-rw-r--r--drivers/gpio/gpio-pcf857x.c6
-rw-r--r--drivers/gpio/gpio-pci-idio-16.c119
-rw-r--r--drivers/gpio/gpio-sim.c4
-rw-r--r--drivers/gpio/gpio-sl28cpld.c3
-rw-r--r--drivers/gpio/gpio-sta2x11.c411
-rw-r--r--drivers/gpio/gpio-tpic2810.c5
-rw-r--r--drivers/gpio/gpio-ts4900.c5
-rw-r--r--drivers/gpio/gpiolib-acpi.c134
-rw-r--r--drivers/gpio/gpiolib-acpi.h54
-rw-r--r--drivers/gpio/gpiolib-cdev.c206
-rw-r--r--drivers/gpio/gpiolib-of.c452
-rw-r--r--drivers/gpio/gpiolib-of.h9
-rw-r--r--drivers/gpio/gpiolib-swnode.c123
-rw-r--r--drivers/gpio/gpiolib-swnode.h14
-rw-r--r--drivers/gpio/gpiolib.c295
-rw-r--r--drivers/gpio/gpiolib.h14
-rw-r--r--drivers/leds/blink/leds-lgm-sso.c5
-rw-r--r--drivers/leds/leds-gpio.c5
36 files changed, 1421 insertions, 1112 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index a01af1180616..ec7cfd4f52b1 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -109,6 +109,15 @@ config GPIO_REGMAP
config GPIO_MAX730X
tristate
+config GPIO_IDIO_16
+ tristate
+ help
+ Enables support for the idio-16 library functions. The idio-16 library
+ provides functions to facilitate communication with devices within the
+ ACCES IDIO-16 family such as the 104-IDIO-16 and the PCI-IDIO-16.
+
+ If built as a module its name will be gpio-idio-16.
+
menu "Memory mapped GPIO drivers"
depends on HAS_IOMEM
@@ -219,7 +228,7 @@ config GPIO_CLPS711X
Say yes here to support GPIO on CLPS711X SoCs.
config GPIO_DAVINCI
- bool "TI Davinci/Keystone GPIO support"
+ tristate "TI Davinci/Keystone GPIO support"
default y if ARCH_DAVINCI
depends on (ARM || ARM64) && (ARCH_DAVINCI || ARCH_KEYSTONE || ARCH_K3)
help
@@ -310,7 +319,7 @@ config GPIO_GRGPIO
config GPIO_HISI
tristate "HiSilicon GPIO controller driver"
- depends on (ARM64 && ACPI) || COMPILE_TEST
+ depends on ARM64 || COMPILE_TEST
select GPIO_GENERIC
select GPIOLIB_IRQCHIP
help
@@ -600,14 +609,6 @@ config GPIO_SPRD
help
Say yes here to support Spreadtrum GPIO device.
-config GPIO_STA2X11
- bool "STA2x11/ConneXt GPIO support"
- depends on MFD_STA2X11
- select GENERIC_IRQ_CHIP
- help
- Say yes here to support the STA2x11/ConneXt GPIO device.
- The GPIO module has 128 GPIO pins with alternate functions.
-
config GPIO_STP_XWAY
bool "XWAY STP GPIOs"
depends on SOC_XWAY || COMPILE_TEST
@@ -857,6 +858,7 @@ config GPIO_104_IDIO_16
depends on PC104
select ISA_BUS_API
select GPIOLIB_IRQCHIP
+ select GPIO_IDIO_16
help
Enables GPIO support for the ACCES 104-IDIO-16 family (104-IDIO-16,
104-IDIO-16E, 104-IDO-16, 104-IDIO-8, 104-IDIO-8E, 104-IDO-8). The
@@ -1561,6 +1563,7 @@ config GPIO_PCH
config GPIO_PCI_IDIO_16
tristate "ACCES PCI-IDIO-16 GPIO support"
select GPIOLIB_IRQCHIP
+ select GPIO_IDIO_16
help
Enables GPIO support for the ACCES PCI-IDIO-16. An interrupt is
generated when any of the inputs change state (low to high or high to
@@ -1681,6 +1684,12 @@ config GPIO_AGGREGATOR
industrial control context, to be operated from userspace using
the GPIO chardev interface.
+config GPIO_LATCH
+ tristate "GPIO latch driver"
+ help
+ Say yes here to enable a driver for GPIO multiplexers based on latches
+ connected to other GPIOs.
+
config GPIO_MOCKUP
tristate "GPIO Testing Driver"
select IRQ_SIM
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 29e3beb6548c..010587025fc8 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
obj-$(CONFIG_GPIO_CDEV) += gpiolib-cdev.o
obj-$(CONFIG_GPIO_SYSFS) += gpiolib-sysfs.o
obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
+obj-$(CONFIG_GPIOLIB) += gpiolib-swnode.o
# Device drivers. Generally keep list sorted alphabetically
obj-$(CONFIG_GPIO_REGMAP) += gpio-regmap.o
@@ -68,6 +69,7 @@ obj-$(CONFIG_GPIO_HLWD) += gpio-hlwd.o
obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o
obj-$(CONFIG_GPIO_I8255) += gpio-i8255.o
obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
+obj-$(CONFIG_GPIO_IDIO_16) += gpio-idio-16.o
obj-$(CONFIG_GPIO_IDT3243X) += gpio-idt3243x.o
obj-$(CONFIG_GPIO_IMX_SCU) += gpio-imx-scu.o
obj-$(CONFIG_GPIO_IOP) += gpio-iop.o
@@ -75,6 +77,7 @@ obj-$(CONFIG_GPIO_IT87) += gpio-it87.o
obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o
obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o
obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o
+obj-$(CONFIG_GPIO_LATCH) += gpio-latch.o
obj-$(CONFIG_GPIO_LOGICVC) += gpio-logicvc.o
obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o
obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o
@@ -140,7 +143,6 @@ obj-$(CONFIG_GPIO_SL28CPLD) += gpio-sl28cpld.o
obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o
obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o
obj-$(CONFIG_GPIO_SPRD) += gpio-sprd.o
-obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o
obj-$(CONFIG_GPIO_SYSCON) += gpio-syscon.o
diff --git a/drivers/gpio/TODO b/drivers/gpio/TODO
index f87ff3fa8a53..76560744587a 100644
--- a/drivers/gpio/TODO
+++ b/drivers/gpio/TODO
@@ -124,6 +124,13 @@ Work items:
this with dry-coding and sending to maintainers to test
+Generic regmap GPIO
+
+In the very similar way to Generic MMIO GPIO convert the users which can
+take advantage of using regmap over direct IO accessors. Note, even in
+MMIO case the regmap MMIO with gpio-regmap.c is preferable over gpio-mmio.c.
+
+
GPIOLIB irqchip
The GPIOLIB irqchip is a helper irqchip for "simple cases" that should
diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c
index 718bd54e2a25..098fbefdbe22 100644
--- a/drivers/gpio/gpio-104-idio-16.c
+++ b/drivers/gpio/gpio-104-idio-16.c
@@ -6,7 +6,7 @@
* This driver supports the following ACCES devices: 104-IDIO-16,
* 104-IDIO-16E, 104-IDO-16, 104-IDIO-8, 104-IDIO-8E, and 104-IDO-8.
*/
-#include <linux/bits.h>
+#include <linux/bitmap.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
@@ -21,6 +21,8 @@
#include <linux/spinlock.h>
#include <linux/types.h>
+#include "gpio-idio-16.h"
+
#define IDIO_16_EXTENT 8
#define MAX_NUM_IDIO_16 max_num_isa_dev(IDIO_16_EXTENT)
@@ -35,48 +37,25 @@ module_param_hw_array(irq, uint, irq, &num_irq, 0);
MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers");
/**
- * struct idio_16_reg - device registers structure
- * @out0_7: Read: N/A
- * Write: FET Drive Outputs 0-7
- * @in0_7: Read: Isolated Inputs 0-7
- * Write: Clear Interrupt
- * @irq_ctl: Read: Enable IRQ
- * Write: Disable IRQ
- * @unused: N/A
- * @out8_15: Read: N/A
- * Write: FET Drive Outputs 8-15
- * @in8_15: Read: Isolated Inputs 8-15
- * Write: N/A
- */
-struct idio_16_reg {
- u8 out0_7;
- u8 in0_7;
- u8 irq_ctl;
- u8 unused;
- u8 out8_15;
- u8 in8_15;
-};
-
-/**
* struct idio_16_gpio - GPIO device private data structure
* @chip: instance of the gpio_chip
* @lock: synchronization lock to prevent I/O race conditions
* @irq_mask: I/O bits affected by interrupts
* @reg: I/O address offset for the device registers
- * @out_state: output bits state
+ * @state: ACCES IDIO-16 device state
*/
struct idio_16_gpio {
struct gpio_chip chip;
raw_spinlock_t lock;
unsigned long irq_mask;
- struct idio_16_reg __iomem *reg;
- unsigned int out_state;
+ struct idio_16 __iomem *reg;
+ struct idio_16_state state;
};
static int idio_16_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset)
{
- if (offset > 15)
+ if (idio_16_get_direction(offset))
return GPIO_LINE_DIRECTION_IN;
return GPIO_LINE_DIRECTION_OUT;
@@ -98,15 +77,8 @@ static int idio_16_gpio_direction_output(struct gpio_chip *chip,
static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
- const unsigned int mask = BIT(offset-16);
- if (offset < 16)
- return -EINVAL;
-
- if (offset < 24)
- return !!(ioread8(&idio16gpio->reg->in0_7) & mask);
-
- return !!(ioread8(&idio16gpio->reg->in8_15) & (mask>>8));
+ return idio_16_get(idio16gpio->reg, &idio16gpio->state, offset);
}
static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
@@ -114,11 +86,7 @@ static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
{
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
- *bits = 0;
- if (*mask & GENMASK(23, 16))
- *bits |= (unsigned long)ioread8(&idio16gpio->reg->in0_7) << 16;
- if (*mask & GENMASK(31, 24))
- *bits |= (unsigned long)ioread8(&idio16gpio->reg->in8_15) << 24;
+ idio_16_get_multiple(idio16gpio->reg, &idio16gpio->state, mask, bits);
return 0;
}
@@ -127,44 +95,16 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
- const unsigned int mask = BIT(offset);
- unsigned long flags;
- if (offset > 15)
- return;
-
- raw_spin_lock_irqsave(&idio16gpio->lock, flags);
-
- if (value)
- idio16gpio->out_state |= mask;
- else
- idio16gpio->out_state &= ~mask;
-
- if (offset > 7)
- iowrite8(idio16gpio->out_state >> 8, &idio16gpio->reg->out8_15);
- else
- iowrite8(idio16gpio->out_state, &idio16gpio->reg->out0_7);
-
- raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
+ idio_16_set(idio16gpio->reg, &idio16gpio->state, offset, value);
}
static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
unsigned long *mask, unsigned long *bits)
{
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
- unsigned long flags;
- raw_spin_lock_irqsave(&idio16gpio->lock, flags);
-
- idio16gpio->out_state &= ~*mask;
- idio16gpio->out_state |= *mask & *bits;
-
- if (*mask & 0xFF)
- iowrite8(idio16gpio->out_state, &idio16gpio->reg->out0_7);
- if ((*mask >> 8) & 0xFF)
- iowrite8(idio16gpio->out_state >> 8, &idio16gpio->reg->out8_15);
-
- raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
+ idio_16_set_multiple(idio16gpio->reg, &idio16gpio->state, mask, bits);
}
static void idio_16_irq_ack(struct irq_data *data)
@@ -301,7 +241,10 @@ static int idio_16_probe(struct device *dev, unsigned int id)
idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
idio16gpio->chip.set = idio_16_gpio_set;
idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
- idio16gpio->out_state = 0xFFFF;
+
+ idio_16_state_init(&idio16gpio->state);
+ /* FET off states are represented by bit values of "1" */
+ bitmap_fill(idio16gpio->state.out_state, IDIO_16_NOUT);
girq = &idio16gpio->chip.irq;
gpio_irq_chip_set_chip(girq, &idio_16_irqchip);
@@ -343,3 +286,4 @@ module_isa_driver_with_irq(idio_16_driver, num_idio_16, num_irq);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
MODULE_DESCRIPTION("ACCES 104-IDIO-16 GPIO driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(GPIO_IDIO_16);
diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c
index 0cb2664085cf..6d17d262ad91 100644
--- a/drivers/gpio/gpio-aggregator.c
+++ b/drivers/gpio/gpio-aggregator.c
@@ -23,6 +23,7 @@
#include <linux/spinlock.h>
#include <linux/string.h>
+#define AGGREGATOR_MAX_GPIOS 512
/*
* GPIO Aggregator sysfs interface
@@ -64,7 +65,7 @@ static int aggr_parse(struct gpio_aggregator *aggr)
unsigned int i, n = 0;
int error = 0;
- bitmap = bitmap_alloc(ARCH_NR_GPIOS, GFP_KERNEL);
+ bitmap = bitmap_alloc(AGGREGATOR_MAX_GPIOS, GFP_KERNEL);
if (!bitmap)
return -ENOMEM;
@@ -84,13 +85,13 @@ static int aggr_parse(struct gpio_aggregator *aggr)
}
/* GPIO chip + offset(s) */
- error = bitmap_parselist(offsets, bitmap, ARCH_NR_GPIOS);
+ error = bitmap_parselist(offsets, bitmap, AGGREGATOR_MAX_GPIOS);
if (error) {
pr_err("Cannot parse %s: %d\n", offsets, error);
goto free_bitmap;
}
- for_each_set_bit(i, bitmap, ARCH_NR_GPIOS) {
+ for_each_set_bit(i, bitmap, AGGREGATOR_MAX_GPIOS) {
error = aggr_add_gpio(aggr, name, i, &n);
if (error)
goto free_bitmap;
diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c
index 59c4c48d8296..fa51a91afa54 100644
--- a/drivers/gpio/gpio-davinci.c
+++ b/drivers/gpio/gpio-davinci.c
@@ -217,9 +217,6 @@ static int davinci_gpio_probe(struct platform_device *pdev)
return -EINVAL;
}
- if (WARN_ON(ARCH_NR_GPIOS < ngpio))
- ngpio = ARCH_NR_GPIOS;
-
/*
* If there are unbanked interrupts then the number of
* interrupts is equal to number of gpios else all are banked so
@@ -730,3 +727,14 @@ static int __init davinci_gpio_drv_reg(void)
return platform_driver_register(&davinci_gpio_driver);
}
postcore_initcall(davinci_gpio_drv_reg);
+
+static void __exit davinci_gpio_exit(void)
+{
+ platform_driver_unregister(&davinci_gpio_driver);
+}
+module_exit(davinci_gpio_exit);
+
+MODULE_AUTHOR("Jan Kotas <jank@cadence.com>");
+MODULE_DESCRIPTION("DAVINCI GPIO driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:gpio-davinci");
diff --git a/drivers/gpio/gpio-exar.c b/drivers/gpio/gpio-exar.c
index 482f678c893e..df1bdaae441c 100644
--- a/drivers/gpio/gpio-exar.c
+++ b/drivers/gpio/gpio-exar.c
@@ -141,6 +141,7 @@ static const struct regmap_config exar_regmap_config = {
.name = "exar-gpio",
.reg_bits = 16,
.val_bits = 8,
+ .io_port = true,
};
static int gpio_exar_probe(struct platform_device *pdev)
diff --git a/drivers/gpio/gpio-ftgpio010.c b/drivers/gpio/gpio-ftgpio010.c
index f77a965f5780..2728672ef9f8 100644
--- a/drivers/gpio/gpio-ftgpio010.c
+++ b/drivers/gpio/gpio-ftgpio010.c
@@ -277,7 +277,7 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
dev_err(dev, "unable to init generic GPIO\n");
goto dis_clk;
}
- g->gc.label = "FTGPIO010";
+ g->gc.label = dev_name(dev);
g->gc.base = -1;
g->gc.parent = dev;
g->gc.owner = THIS_MODULE;
diff --git a/drivers/gpio/gpio-gw-pld.c b/drivers/gpio/gpio-gw-pld.c
index 2109803ffb38..5057fa9ad610 100644
--- a/drivers/gpio/gpio-gw-pld.c
+++ b/drivers/gpio/gpio-gw-pld.c
@@ -67,8 +67,7 @@ static void gw_pld_set8(struct gpio_chip *gc, unsigned offset, int value)
gw_pld_output8(gc, offset, value);
}
-static int gw_pld_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int gw_pld_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct gw_pld *gw;
@@ -126,7 +125,7 @@ static struct i2c_driver gw_pld_driver = {
.name = "gw_pld",
.of_match_table = gw_pld_dt_ids,
},
- .probe = gw_pld_probe,
+ .probe_new = gw_pld_probe,
.id_table = gw_pld_id,
};
module_i2c_driver(gw_pld_driver);
diff --git a/drivers/gpio/gpio-hisi.c b/drivers/gpio/gpio-hisi.c
index 3caabef5c7a2..55bd69043bf4 100644
--- a/drivers/gpio/gpio-hisi.c
+++ b/drivers/gpio/gpio-hisi.c
@@ -221,6 +221,12 @@ static const struct acpi_device_id hisi_gpio_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, hisi_gpio_acpi_match);
+static const struct of_device_id hisi_gpio_dts_match[] = {
+ { .compatible = "hisilicon,ascend910-gpio", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, hisi_gpio_dts_match);
+
static void hisi_gpio_get_pdata(struct device *dev,
struct hisi_gpio *hisi_gpio)
{
@@ -311,6 +317,7 @@ static struct platform_driver hisi_gpio_driver = {
.driver = {
.name = HISI_GPIO_DRIVER_NAME,
.acpi_match_table = hisi_gpio_acpi_match,
+ .of_match_table = hisi_gpio_dts_match,
},
.probe = hisi_gpio_probe,
};
diff --git a/drivers/gpio/gpio-idio-16.c b/drivers/gpio/gpio-idio-16.c
new file mode 100644
index 000000000000..13315242d220
--- /dev/null
+++ b/drivers/gpio/gpio-idio-16.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * GPIO library for the ACCES IDIO-16 family
+ * Copyright (C) 2022 William Breathitt Gray
+ */
+#include <linux/bitmap.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include "gpio-idio-16.h"
+
+#define DEFAULT_SYMBOL_NAMESPACE GPIO_IDIO_16
+
+/**
+ * idio_16_get - get signal value at signal offset
+ * @reg: ACCES IDIO-16 device registers
+ * @state: ACCES IDIO-16 device state
+ * @offset: offset of signal to get
+ *
+ * Returns the signal value (0=low, 1=high) for the signal at @offset.
+ */
+int idio_16_get(struct idio_16 __iomem *const reg,
+ struct idio_16_state *const state, const unsigned long offset)
+{
+ const unsigned long mask = BIT(offset);
+
+ if (offset < IDIO_16_NOUT)
+ return test_bit(offset, state->out_state);
+
+ if (offset < 24)
+ return !!(ioread8(&reg->in0_7) & (mask >> IDIO_16_NOUT));
+
+ if (offset < 32)
+ return !!(ioread8(&reg->in8_15) & (mask >> 24));
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(idio_16_get);
+
+/**
+ * idio_16_get_multiple - get multiple signal values at multiple signal offsets
+ * @reg: ACCES IDIO-16 device registers
+ * @state: ACCES IDIO-16 device state
+ * @mask: mask of signals to get
+ * @bits: bitmap to store signal values
+ *
+ * Stores in @bits the values (0=low, 1=high) for the signals defined by @mask.
+ */
+void idio_16_get_multiple(struct idio_16 __iomem *const reg,
+ struct idio_16_state *const state,
+ const unsigned long *const mask,
+ unsigned long *const bits)
+{
+ unsigned long flags;
+ const unsigned long out_mask = GENMASK(IDIO_16_NOUT - 1, 0);
+
+ spin_lock_irqsave(&state->lock, flags);
+
+ bitmap_replace(bits, bits, state->out_state, &out_mask, IDIO_16_NOUT);
+ if (*mask & GENMASK(23, 16))
+ bitmap_set_value8(bits, ioread8(&reg->in0_7), 16);
+ if (*mask & GENMASK(31, 24))
+ bitmap_set_value8(bits, ioread8(&reg->in8_15), 24);
+
+ spin_unlock_irqrestore(&state->lock, flags);
+}
+EXPORT_SYMBOL_GPL(idio_16_get_multiple);
+
+/**
+ * idio_16_set - set signal value at signal offset
+ * @reg: ACCES IDIO-16 device registers
+ * @state: ACCES IDIO-16 device state
+ * @offset: offset of signal to set
+ * @value: value of signal to set
+ *
+ * Assigns output @value for the signal at @offset.
+ */
+void idio_16_set(struct idio_16 __iomem *const reg,
+ struct idio_16_state *const state, const unsigned long offset,
+ const unsigned long value)
+{
+ unsigned long flags;
+
+ if (offset >= IDIO_16_NOUT)
+ return;
+
+ spin_lock_irqsave(&state->lock, flags);
+
+ __assign_bit(offset, state->out_state, value);
+ if (offset < 8)
+ iowrite8(bitmap_get_value8(state->out_state, 0), &reg->out0_7);
+ else
+ iowrite8(bitmap_get_value8(state->out_state, 8), &reg->out8_15);
+
+ spin_unlock_irqrestore(&state->lock, flags);
+}
+EXPORT_SYMBOL_GPL(idio_16_set);
+
+/**
+ * idio_16_set_multiple - set signal values at multiple signal offsets
+ * @reg: ACCES IDIO-16 device registers
+ * @state: ACCES IDIO-16 device state
+ * @mask: mask of signals to set
+ * @bits: bitmap of signal output values
+ *
+ * Assigns output values defined by @bits for the signals defined by @mask.
+ */
+void idio_16_set_multiple(struct idio_16 __iomem *const reg,
+ struct idio_16_state *const state,
+ const unsigned long *const mask,
+ const unsigned long *const bits)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->lock, flags);
+
+ bitmap_replace(state->out_state, state->out_state, bits, mask,
+ IDIO_16_NOUT);
+ if (*mask & GENMASK(7, 0))
+ iowrite8(bitmap_get_value8(state->out_state, 0), &reg->out0_7);
+ if (*mask & GENMASK(15, 8))
+ iowrite8(bitmap_get_value8(state->out_state, 8), &reg->out8_15);
+
+ spin_unlock_irqrestore(&state->lock, flags);
+}
+EXPORT_SYMBOL_GPL(idio_16_set_multiple);
+
+/**
+ * idio_16_state_init - initialize idio_16_state structure
+ * @state: ACCES IDIO-16 device state
+ *
+ * Initializes the ACCES IDIO-16 device @state for use in idio-16 library
+ * functions.
+ */
+void idio_16_state_init(struct idio_16_state *const state)
+{
+ spin_lock_init(&state->lock);
+}
+EXPORT_SYMBOL_GPL(idio_16_state_init);
+
+MODULE_AUTHOR("William Breathitt Gray");
+MODULE_DESCRIPTION("ACCES IDIO-16 GPIO Library");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-idio-16.h b/drivers/gpio/gpio-idio-16.h
new file mode 100644
index 000000000000..928f8251a2bd
--- /dev/null
+++ b/drivers/gpio/gpio-idio-16.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright 2022 William Breathitt Gray */
+#ifndef _IDIO_16_H_
+#define _IDIO_16_H_
+
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+/**
+ * struct idio_16 - IDIO-16 registers structure
+ * @out0_7: Read: FET Drive Outputs 0-7
+ * Write: FET Drive Outputs 0-7
+ * @in0_7: Read: Isolated Inputs 0-7
+ * Write: Clear Interrupt
+ * @irq_ctl: Read: Enable IRQ
+ * Write: Disable IRQ
+ * @filter_ctl: Read: Activate Input Filters 0-15
+ * Write: Deactivate Input Filters 0-15
+ * @out8_15: Read: FET Drive Outputs 8-15
+ * Write: FET Drive Outputs 8-15
+ * @in8_15: Read: Isolated Inputs 8-15
+ * Write: Unused
+ * @irq_status: Read: Interrupt status
+ * Write: Unused
+ */
+struct idio_16 {
+ u8 out0_7;
+ u8 in0_7;
+ u8 irq_ctl;
+ u8 filter_ctl;
+ u8 out8_15;
+ u8 in8_15;
+ u8 irq_status;
+};
+
+#define IDIO_16_NOUT 16
+
+/**
+ * struct idio_16_state - IDIO-16 state structure
+ * @lock: synchronization lock for accessing device state
+ * @out_state: output signals state
+ */
+struct idio_16_state {
+ spinlock_t lock;
+ DECLARE_BITMAP(out_state, IDIO_16_NOUT);
+};
+
+/**
+ * idio_16_get_direction - get the I/O direction for a signal offset
+ * @offset: offset of signal to get direction
+ *
+ * Returns the signal direction (0=output, 1=input) for the signal at @offset.
+ */
+static inline int idio_16_get_direction(const unsigned long offset)
+{
+ return (offset >= IDIO_16_NOUT) ? 1 : 0;
+}
+
+int idio_16_get(struct idio_16 __iomem *reg, struct idio_16_state *state,
+ unsigned long offset);
+void idio_16_get_multiple(struct idio_16 __iomem *reg,
+ struct idio_16_state *state,
+ const unsigned long *mask, unsigned long *bits);
+void idio_16_set(struct idio_16 __iomem *reg, struct idio_16_state *state,
+ unsigned long offset, unsigned long value);
+void idio_16_set_multiple(struct idio_16 __iomem *reg,
+ struct idio_16_state *state,
+ const unsigned long *mask, const unsigned long *bits);
+void idio_16_state_init(struct idio_16_state *state);
+
+#endif /* _IDIO_16_H_ */
diff --git a/drivers/gpio/gpio-latch.c b/drivers/gpio/gpio-latch.c
new file mode 100644
index 000000000000..d7c3b20c8482
--- /dev/null
+++ b/drivers/gpio/gpio-latch.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * GPIO latch driver
+ *
+ * Copyright (C) 2022 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * This driver implements a GPIO (or better GPO as there is no input)
+ * multiplexer based on latches like this:
+ *
+ * CLK0 ----------------------. ,--------.
+ * CLK1 -------------------. `--------|> #0 |
+ * | | |
+ * OUT0 ----------------+--|-----------|D0 Q0|-----|<
+ * OUT1 --------------+-|--|-----------|D1 Q1|-----|<
+ * OUT2 ------------+-|-|--|-----------|D2 Q2|-----|<
+ * OUT3 ----------+-|-|-|--|-----------|D3 Q3|-----|<
+ * OUT4 --------+-|-|-|-|--|-----------|D4 Q4|-----|<
+ * OUT5 ------+-|-|-|-|-|--|-----------|D5 Q5|-----|<
+ * OUT6 ----+-|-|-|-|-|-|--|-----------|D6 Q6|-----|<
+ * OUT7 --+-|-|-|-|-|-|-|--|-----------|D7 Q7|-----|<
+ * | | | | | | | | | `--------'
+ * | | | | | | | | |
+ * | | | | | | | | | ,--------.
+ * | | | | | | | | `-----------|> #1 |
+ * | | | | | | | | | |
+ * | | | | | | | `--------------|D0 Q0|-----|<
+ * | | | | | | `----------------|D1 Q1|-----|<
+ * | | | | | `------------------|D2 Q2|-----|<
+ * | | | | `--------------------|D3 Q3|-----|<
+ * | | | `----------------------|D4 Q4|-----|<
+ * | | `------------------------|D5 Q5|-----|<
+ * | `--------------------------|D6 Q6|-----|<
+ * `----------------------------|D7 Q7|-----|<
+ * `--------'
+ *
+ * The above is just an example. The actual number of number of latches and
+ * the number of inputs per latch is derived from the number of GPIOs given
+ * in the corresponding device tree properties.
+ */
+
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+
+#include "gpiolib.h"
+
+struct gpio_latch_priv {
+ struct gpio_chip gc;
+ struct gpio_descs *clk_gpios;
+ struct gpio_descs *latched_gpios;
+ int n_latched_gpios;
+ unsigned int setup_duration_ns;
+ unsigned int clock_duration_ns;
+ unsigned long *shadow;
+ /*
+ * Depending on whether any of the underlying GPIOs may sleep we either
+ * use a mutex or a spinlock to protect our shadow map.
+ */
+ union {
+ struct mutex mutex; /* protects @shadow */
+ spinlock_t spinlock; /* protects @shadow */
+ };
+};
+
+static int gpio_latch_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ return GPIO_LINE_DIRECTION_OUT;
+}
+
+static void gpio_latch_set_unlocked(struct gpio_latch_priv *priv,
+ void (*set)(struct gpio_desc *desc, int value),
+ unsigned int offset, bool val)
+{
+ int latch = offset / priv->n_latched_gpios;
+ int i;
+
+ assign_bit(offset, priv->shadow, val);
+
+ for (i = 0; i < priv->n_latched_gpios; i++)
+ set(priv->latched_gpios->desc[i],
+ test_bit(latch * priv->n_latched_gpios + i, priv->shadow));
+
+ ndelay(priv->setup_duration_ns);
+ set(priv->clk_gpios->desc[latch], 1);
+ ndelay(priv->clock_duration_ns);
+ set(priv->clk_gpios->desc[latch], 0);
+}
+
+static void gpio_latch_set(struct gpio_chip *gc, unsigned int offset, int val)
+{
+ struct gpio_latch_priv *priv = gpiochip_get_data(gc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->spinlock, flags);
+
+ gpio_latch_set_unlocked(priv, gpiod_set_value, offset, val);
+
+ spin_unlock_irqrestore(&priv->spinlock, flags);
+}
+
+static void gpio_latch_set_can_sleep(struct gpio_chip *gc, unsigned int offset, int val)
+{
+ struct gpio_latch_priv *priv = gpiochip_get_data(gc);
+
+ mutex_lock(&priv->mutex);
+
+ gpio_latch_set_unlocked(priv, gpiod_set_value_cansleep, offset, val);
+
+ mutex_unlock(&priv->mutex);
+}
+
+static bool gpio_latch_can_sleep(struct gpio_latch_priv *priv, unsigned int n_latches)
+{
+ int i;
+
+ for (i = 0; i < n_latches; i++)
+ if (gpiod_cansleep(priv->clk_gpios->desc[i]))
+ return true;
+
+ for (i = 0; i < priv->n_latched_gpios; i++)
+ if (gpiod_cansleep(priv->latched_gpios->desc[i]))
+ return true;
+
+ return false;
+}
+
+/*
+ * Some value which is still acceptable to delay in atomic context.
+ * If we need to go higher we might have to switch to usleep_range(),
+ * but that cannot ne used in atomic context and the driver would have
+ * to be adjusted to support that.
+ */
+#define DURATION_NS_MAX 5000
+
+static int gpio_latch_probe(struct platform_device *pdev)
+{
+ struct gpio_latch_priv *priv;
+ unsigned int n_latches;
+ struct device_node *np = pdev->dev.of_node;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->clk_gpios = devm_gpiod_get_array(&pdev->dev, "clk", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->clk_gpios))
+ return PTR_ERR(priv->clk_gpios);
+
+ priv->latched_gpios = devm_gpiod_get_array(&pdev->dev, "latched", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->latched_gpios))
+ return PTR_ERR(priv->latched_gpios);
+
+ n_latches = priv->clk_gpios->ndescs;
+ priv->n_latched_gpios = priv->latched_gpios->ndescs;
+
+ priv->shadow = devm_bitmap_zalloc(&pdev->dev, n_latches * priv->n_latched_gpios,
+ GFP_KERNEL);
+ if (!priv->shadow)
+ return -ENOMEM;
+
+ if (gpio_latch_can_sleep(priv, n_latches)) {
+ priv->gc.can_sleep = true;
+ priv->gc.set = gpio_latch_set_can_sleep;
+ mutex_init(&priv->mutex);
+ } else {
+ priv->gc.can_sleep = false;
+ priv->gc.set = gpio_latch_set;
+ spin_lock_init(&priv->spinlock);
+ }
+
+ of_property_read_u32(np, "setup-duration-ns", &priv->setup_duration_ns);
+ if (priv->setup_duration_ns > DURATION_NS_MAX) {
+ dev_warn(&pdev->dev, "setup-duration-ns too high, limit to %d\n",
+ DURATION_NS_MAX);
+ priv->setup_duration_ns = DURATION_NS_MAX;
+ }
+
+ of_property_read_u32(np, "clock-duration-ns", &priv->clock_duration_ns);
+ if (priv->clock_duration_ns > DURATION_NS_MAX) {
+ dev_warn(&pdev->dev, "clock-duration-ns too high, limit to %d\n",
+ DURATION_NS_MAX);
+ priv->clock_duration_ns = DURATION_NS_MAX;
+ }
+
+ priv->gc.get_direction = gpio_latch_get_direction;
+ priv->gc.ngpio = n_latches * priv->n_latched_gpios;
+ priv->gc.owner = THIS_MODULE;
+ priv->gc.base = -1;
+ priv->gc.parent = &pdev->dev;
+
+ platform_set_drvdata(pdev, priv);
+
+ return devm_gpiochip_add_data(&pdev->dev, &priv->gc, priv);
+}
+
+static const struct of_device_id gpio_latch_ids[] = {
+ {
+ .compatible = "gpio-latch",
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, gpio_latch_ids);
+
+static struct platform_driver gpio_latch_driver = {
+ .driver = {
+ .name = "gpio-latch",
+ .of_match_table = gpio_latch_ids,
+ },
+ .probe = gpio_latch_probe,
+};
+module_platform_driver(gpio_latch_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION("GPIO latch driver");
diff --git a/drivers/gpio/gpio-max7300.c b/drivers/gpio/gpio-max7300.c
index 43da381a4d7e..cf482f4f0098 100644
--- a/drivers/gpio/gpio-max7300.c
+++ b/drivers/gpio/gpio-max7300.c
@@ -28,8 +28,7 @@ static int max7300_i2c_read(struct device *dev, unsigned int reg)
return i2c_smbus_read_byte_data(client, reg);
}
-static int max7300_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int max7300_probe(struct i2c_client *client)
{
struct max7301 *ts;
@@ -63,7 +62,7 @@ static struct i2c_driver max7300_driver = {
.driver = {
.name = "max7300",
},
- .probe = max7300_probe,
+ .probe_new = max7300_probe,
.remove = max7300_remove,
.id_table = max7300_id,
};
diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c
index da6972117030..68e982cdee73 100644
--- a/drivers/gpio/gpio-max732x.c
+++ b/drivers/gpio/gpio-max732x.c
@@ -608,9 +608,9 @@ static struct max732x_platform_data *of_gpio_max732x(struct device *dev)
return pdata;
}
-static int max732x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int max732x_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct max732x_platform_data *pdata;
struct device_node *node;
struct max732x_chip *chip;
@@ -707,7 +707,7 @@ static struct i2c_driver max732x_driver = {
.name = "max732x",
.of_match_table = of_match_ptr(max732x_of_table),
},
- .probe = max732x_probe,
+ .probe_new = max732x_probe,
.id_table = max732x_id,
};
diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c
index 72ac09a59702..92ea8411050d 100644
--- a/drivers/gpio/gpio-merrifield.c
+++ b/drivers/gpio/gpio-merrifield.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/string_helpers.h>
#define GCCR 0x000 /* controller configuration */
#define GPLR 0x004 /* pin level r/o */
@@ -331,7 +332,7 @@ static int mrfld_irq_set_wake(struct irq_data *d, unsigned int on)
raw_spin_unlock_irqrestore(&priv->lock, flags);
- dev_dbg(priv->dev, "%sable wake for gpio %u\n", on ? "en" : "dis", gpio);
+ dev_dbg(priv->dev, "%s wake for gpio %u\n", str_enable_disable(on), gpio);
return 0;
}
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 6e67867e1dcd..a59d61cd44b2 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -1050,9 +1050,9 @@ out:
return ret;
}
-static int pca953x_probe(struct i2c_client *client,
- const struct i2c_device_id *i2c_id)
+static int pca953x_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *i2c_id = i2c_client_get_device_id(client);
struct pca953x_platform_data *pdata;
struct pca953x_chip *chip;
int irq_base = 0;
@@ -1376,7 +1376,7 @@ static struct i2c_driver pca953x_driver = {
.of_match_table = pca953x_dt_ids,
.acpi_match_table = pca953x_acpi_ids,
},
- .probe = pca953x_probe,
+ .probe_new = pca953x_probe,
.remove = pca953x_remove,
.id_table = pca953x_id,
};
diff --git a/drivers/gpio/gpio-pca9570.c b/drivers/gpio/gpio-pca9570.c
index ab2a652964ec..6c07a8811a7a 100644
--- a/drivers/gpio/gpio-pca9570.c
+++ b/drivers/gpio/gpio-pca9570.c
@@ -15,14 +15,28 @@
#include <linux/mutex.h>
#include <linux/property.h>
+#define SLG7XL45106_GPO_REG 0xDB
+
+/**
+ * struct pca9570_platform_data - GPIO platformdata
+ * @ngpio: no of gpios
+ * @command: Command to be sent
+ */
+struct pca9570_platform_data {
+ u16 ngpio;
+ u32 command;
+};
+
/**
* struct pca9570 - GPIO driver data
* @chip: GPIO controller chip
+ * @p_data: GPIO controller platform data
* @lock: Protects write sequences
* @out: Buffer for device register
*/
struct pca9570 {
struct gpio_chip chip;
+ const struct pca9570_platform_data *p_data;
struct mutex lock;
u8 out;
};
@@ -32,7 +46,11 @@ static int pca9570_read(struct pca9570 *gpio, u8 *value)
struct i2c_client *client = to_i2c_client(gpio->chip.parent);
int ret;
- ret = i2c_smbus_read_byte(client);
+ if (gpio->p_data->command != 0)
+ ret = i2c_smbus_read_byte_data(client, gpio->p_data->command);
+ else
+ ret = i2c_smbus_read_byte(client);
+
if (ret < 0)
return ret;
@@ -44,6 +62,9 @@ static int pca9570_write(struct pca9570 *gpio, u8 value)
{
struct i2c_client *client = to_i2c_client(gpio->chip.parent);
+ if (gpio->p_data->command != 0)
+ return i2c_smbus_write_byte_data(client, gpio->p_data->command, value);
+
return i2c_smbus_write_byte(client, value);
}
@@ -106,7 +127,8 @@ static int pca9570_probe(struct i2c_client *client)
gpio->chip.get = pca9570_get;
gpio->chip.set = pca9570_set;
gpio->chip.base = -1;
- gpio->chip.ngpio = (uintptr_t)device_get_match_data(&client->dev);
+ gpio->p_data = device_get_match_data(&client->dev);
+ gpio->chip.ngpio = gpio->p_data->ngpio;
gpio->chip.can_sleep = true;
mutex_init(&gpio->lock);
@@ -119,16 +141,31 @@ static int pca9570_probe(struct i2c_client *client)
return devm_gpiochip_add_data(&client->dev, &gpio->chip, gpio);
}
+static const struct pca9570_platform_data pca9570_gpio = {
+ .ngpio = 4,
+};
+
+static const struct pca9570_platform_data pca9571_gpio = {
+ .ngpio = 8,
+};
+
+static const struct pca9570_platform_data slg7xl45106_gpio = {
+ .ngpio = 8,
+ .command = SLG7XL45106_GPO_REG,
+};
+
static const struct i2c_device_id pca9570_id_table[] = {
- { "pca9570", 4 },
- { "pca9571", 8 },
+ { "pca9570", (kernel_ulong_t)&pca9570_gpio},
+ { "pca9571", (kernel_ulong_t)&pca9571_gpio },
+ { "slg7xl45106", (kernel_ulong_t)&slg7xl45106_gpio },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, pca9570_id_table);
static const struct of_device_id pca9570_of_match_table[] = {
- { .compatible = "nxp,pca9570", .data = (void *)4 },
- { .compatible = "nxp,pca9571", .data = (void *)8 },
+ { .compatible = "dlg,slg7xl45106", .data = &slg7xl45106_gpio},
+ { .compatible = "nxp,pca9570", .data = &pca9570_gpio },
+ { .compatible = "nxp,pca9571", .data = &pca9571_gpio },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, pca9570_of_match_table);
diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c
index e98ea47d7237..cec2f2c78255 100644
--- a/drivers/gpio/gpio-pcf857x.c
+++ b/drivers/gpio/gpio-pcf857x.c
@@ -247,9 +247,9 @@ static const struct irq_chip pcf857x_irq_chip = {
/*-------------------------------------------------------------------------*/
-static int pcf857x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int pcf857x_probe(struct i2c_client *client)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct pcf857x_platform_data *pdata = dev_get_platdata(&client->dev);
struct device_node *np = client->dev.of_node;
struct pcf857x *gpio;
@@ -422,7 +422,7 @@ static struct i2c_driver pcf857x_driver = {
.name = "pcf857x",
.of_match_table = of_match_ptr(pcf857x_of_table),
},
- .probe = pcf857x_probe,
+ .probe_new = pcf857x_probe,
.remove = pcf857x_remove,
.shutdown = pcf857x_shutdown,
.id_table = pcf857x_id,
diff --git a/drivers/gpio/gpio-pci-idio-16.c b/drivers/gpio/gpio-pci-idio-16.c
index 71a13a394050..a86ce748384b 100644
--- a/drivers/gpio/gpio-pci-idio-16.c
+++ b/drivers/gpio/gpio-pci-idio-16.c
@@ -3,8 +3,7 @@
* GPIO driver for the ACCES PCI-IDIO-16
* Copyright (C) 2017 William Breathitt Gray
*/
-#include <linux/bitmap.h>
-#include <linux/bitops.h>
+#include <linux/bits.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
@@ -16,51 +15,28 @@
#include <linux/spinlock.h>
#include <linux/types.h>
-/**
- * struct idio_16_gpio_reg - GPIO device registers structure
- * @out0_7: Read: FET Drive Outputs 0-7
- * Write: FET Drive Outputs 0-7
- * @in0_7: Read: Isolated Inputs 0-7
- * Write: Clear Interrupt
- * @irq_ctl: Read: Enable IRQ
- * Write: Disable IRQ
- * @filter_ctl: Read: Activate Input Filters 0-15
- * Write: Deactivate Input Filters 0-15
- * @out8_15: Read: FET Drive Outputs 8-15
- * Write: FET Drive Outputs 8-15
- * @in8_15: Read: Isolated Inputs 8-15
- * Write: Unused
- * @irq_status: Read: Interrupt status
- * Write: Unused
- */
-struct idio_16_gpio_reg {
- u8 out0_7;
- u8 in0_7;
- u8 irq_ctl;
- u8 filter_ctl;
- u8 out8_15;
- u8 in8_15;
- u8 irq_status;
-};
+#include "gpio-idio-16.h"
/**
* struct idio_16_gpio - GPIO device private data structure
* @chip: instance of the gpio_chip
* @lock: synchronization lock to prevent I/O race conditions
* @reg: I/O address offset for the GPIO device registers
+ * @state: ACCES IDIO-16 device state
* @irq_mask: I/O bits affected by interrupts
*/
struct idio_16_gpio {
struct gpio_chip chip;
raw_spinlock_t lock;
- struct idio_16_gpio_reg __iomem *reg;
+ struct idio_16 __iomem *reg;
+ struct idio_16_state state;
unsigned long irq_mask;
};
static int idio_16_gpio_get_direction(struct gpio_chip *chip,
unsigned int offset)
{
- if (offset > 15)
+ if (idio_16_get_direction(offset))
return GPIO_LINE_DIRECTION_IN;
return GPIO_LINE_DIRECTION_OUT;
@@ -82,43 +58,16 @@ static int idio_16_gpio_direction_output(struct gpio_chip *chip,
static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
- unsigned long mask = BIT(offset);
-
- if (offset < 8)
- return !!(ioread8(&idio16gpio->reg->out0_7) & mask);
-
- if (offset < 16)
- return !!(ioread8(&idio16gpio->reg->out8_15) & (mask >> 8));
-
- if (offset < 24)
- return !!(ioread8(&idio16gpio->reg->in0_7) & (mask >> 16));
- return !!(ioread8(&idio16gpio->reg->in8_15) & (mask >> 24));
+ return idio_16_get(idio16gpio->reg, &idio16gpio->state, offset);
}
static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
unsigned long *mask, unsigned long *bits)
{
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
- unsigned long offset;
- unsigned long gpio_mask;
- void __iomem *ports[] = {
- &idio16gpio->reg->out0_7, &idio16gpio->reg->out8_15,
- &idio16gpio->reg->in0_7, &idio16gpio->reg->in8_15,
- };
- void __iomem *port_addr;
- unsigned long port_state;
-
- /* clear bits array to a clean slate */
- bitmap_zero(bits, chip->ngpio);
-
- for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
- port_addr = ports[offset / 8];
- port_state = ioread8(port_addr) & gpio_mask;
-
- bitmap_set_value8(bits, port_state, offset);
- }
+ idio_16_get_multiple(idio16gpio->reg, &idio16gpio->state, mask, bits);
return 0;
}
@@ -126,61 +75,16 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
- unsigned int mask = BIT(offset);
- void __iomem *base;
- unsigned long flags;
- unsigned int out_state;
-
- if (offset > 15)
- return;
-
- if (offset > 7) {
- mask >>= 8;
- base = &idio16gpio->reg->out8_15;
- } else
- base = &idio16gpio->reg->out0_7;
-
- raw_spin_lock_irqsave(&idio16gpio->lock, flags);
- if (value)
- out_state = ioread8(base) | mask;
- else
- out_state = ioread8(base) & ~mask;
-
- iowrite8(out_state, base);
-
- raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
+ idio_16_set(idio16gpio->reg, &idio16gpio->state, offset, value);
}
static void idio_16_gpio_set_multiple(struct gpio_chip *chip,
unsigned long *mask, unsigned long *bits)
{
struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
- unsigned long offset;
- unsigned long gpio_mask;
- void __iomem *ports[] = {
- &idio16gpio->reg->out0_7, &idio16gpio->reg->out8_15,
- };
- size_t index;
- void __iomem *port_addr;
- unsigned long bitmask;
- unsigned long flags;
- unsigned long out_state;
- for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) {
- index = offset / 8;
- port_addr = ports[index];
-
- bitmask = bitmap_get_value8(bits, offset) & gpio_mask;
-
- raw_spin_lock_irqsave(&idio16gpio->lock, flags);
-
- out_state = ioread8(port_addr) & ~gpio_mask;
- out_state |= bitmask;
- iowrite8(out_state, port_addr);
-
- raw_spin_unlock_irqrestore(&idio16gpio->lock, flags);
- }
+ idio_16_set_multiple(idio16gpio->reg, &idio16gpio->state, mask, bits);
}
static void idio_16_irq_ack(struct irq_data *data)
@@ -335,6 +239,8 @@ static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
idio16gpio->chip.set = idio_16_gpio_set;
idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
+ idio_16_state_init(&idio16gpio->state);
+
girq = &idio16gpio->chip.irq;
girq->chip = &idio_16_irqchip;
/* This will let us handle the parent IRQ in the driver */
@@ -379,3 +285,4 @@ module_pci_driver(idio_16_driver);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
MODULE_DESCRIPTION("ACCES PCI-IDIO-16 GPIO driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS(GPIO_IDIO_16);
diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c
index 1020c2feb249..60514bc5454f 100644
--- a/drivers/gpio/gpio-sim.c
+++ b/drivers/gpio/gpio-sim.c
@@ -31,6 +31,7 @@
#include "gpiolib.h"
+#define GPIO_SIM_NGPIO_MAX 1024
#define GPIO_SIM_PROP_MAX 4 /* Max 3 properties + sentinel. */
#define GPIO_SIM_NUM_ATTRS 3 /* value, pull and sentinel */
@@ -371,6 +372,9 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev)
if (ret)
return ret;
+ if (num_lines > GPIO_SIM_NGPIO_MAX)
+ return -ERANGE;
+
ret = fwnode_property_read_string(swnode, "gpio-sim,label", &label);
if (ret) {
label = devm_kasprintf(dev, GFP_KERNEL, "%s-%s",
diff --git a/drivers/gpio/gpio-sl28cpld.c b/drivers/gpio/gpio-sl28cpld.c
index 52404736ac86..2195f88c2048 100644
--- a/drivers/gpio/gpio-sl28cpld.c
+++ b/drivers/gpio/gpio-sl28cpld.c
@@ -70,8 +70,7 @@ static int sl28cpld_gpio_irq_init(struct platform_device *pdev,
irq_chip->num_irqs = ARRAY_SIZE(sl28cpld_gpio_irqs);
irq_chip->num_regs = 1;
irq_chip->status_base = base + GPIO_REG_IP;
- irq_chip->mask_base = base + GPIO_REG_IE;
- irq_chip->mask_invert = true;
+ irq_chip->unmask_base = base + GPIO_REG_IE;
irq_chip->ack_base = base + GPIO_REG_IP;
ret = devm_regmap_add_irq_chip_fwnode(dev, dev_fwnode(dev),
diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c
deleted file mode 100644
index e07cca0f8d35..000000000000
--- a/drivers/gpio/gpio-sta2x11.c
+++ /dev/null
@@ -1,411 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * STMicroelectronics ConneXt (STA2X11) GPIO driver
- *
- * Copyright 2012 ST Microelectronics (Alessandro Rubini)
- * Based on gpio-ml-ioh.c, Copyright 2010 OKI Semiconductors Ltd.
- * Also based on previous sta2x11 work, Copyright 2011 Wind River Systems, Inc.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/gpio/driver.h>
-#include <linux/bitops.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/pci.h>
-#include <linux/platform_device.h>
-#include <linux/mfd/sta2x11-mfd.h>
-
-struct gsta_regs {
- u32 dat; /* 0x00 */
- u32 dats;
- u32 datc;
- u32 pdis;
- u32 dir; /* 0x10 */
- u32 dirs;
- u32 dirc;
- u32 unused_1c;
- u32 afsela; /* 0x20 */
- u32 unused_24[7];
- u32 rimsc; /* 0x40 */
- u32 fimsc;
- u32 is;
- u32 ic;
-};
-
-struct gsta_gpio {
- spinlock_t lock;
- struct device *dev;
- void __iomem *reg_base;
- struct gsta_regs __iomem *regs[GSTA_NR_BLOCKS];
- struct gpio_chip gpio;
- int irq_base;
- /* FIXME: save the whole config here (AF, ...) */
- unsigned irq_type[GSTA_NR_GPIO];
-};
-
-/*
- * gpio methods
- */
-
-static void gsta_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
-{
- struct gsta_gpio *chip = gpiochip_get_data(gpio);
- struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK];
- u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK);
-
- if (val)
- writel(bit, &regs->dats);
- else
- writel(bit, &regs->datc);
-}
-
-static int gsta_gpio_get(struct gpio_chip *gpio, unsigned nr)
-{
- struct gsta_gpio *chip = gpiochip_get_data(gpio);
- struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK];
- u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK);
-
- return !!(readl(&regs->dat) & bit);
-}
-
-static int gsta_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
- int val)
-{
- struct gsta_gpio *chip = gpiochip_get_data(gpio);
- struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK];
- u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK);
-
- writel(bit, &regs->dirs);
- /* Data register after direction, otherwise pullup/down is selected */
- if (val)
- writel(bit, &regs->dats);
- else
- writel(bit, &regs->datc);
- return 0;
-}
-
-static int gsta_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
-{
- struct gsta_gpio *chip = gpiochip_get_data(gpio);
- struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK];
- u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK);
-
- writel(bit, &regs->dirc);
- return 0;
-}
-
-static int gsta_gpio_to_irq(struct gpio_chip *gpio, unsigned offset)
-{
- struct gsta_gpio *chip = gpiochip_get_data(gpio);
- return chip->irq_base + offset;
-}
-
-static void gsta_gpio_setup(struct gsta_gpio *chip) /* called from probe */
-{
- struct gpio_chip *gpio = &chip->gpio;
-
- /*
- * ARCH_NR_GPIOS is currently 256 and dynamic allocation starts
- * from the end. However, for compatibility, we need the first
- * ConneXt device to start from gpio 0: it's the main chipset
- * on most boards so documents and drivers assume gpio0..gpio127
- */
- static int gpio_base;
-
- gpio->label = dev_name(chip->dev);
- gpio->owner = THIS_MODULE;
- gpio->direction_input = gsta_gpio_direction_input;
- gpio->get = gsta_gpio_get;
- gpio->direction_output = gsta_gpio_direction_output;
- gpio->set = gsta_gpio_set;
- gpio->dbg_show = NULL;
- gpio->base = gpio_base;
- gpio->ngpio = GSTA_NR_GPIO;
- gpio->can_sleep = false;
- gpio->to_irq = gsta_gpio_to_irq;
-
- /*
- * After the first device, turn to dynamic gpio numbers.
- * For example, with ARCH_NR_GPIOS = 256 we can fit two cards
- */
- if (!gpio_base)
- gpio_base = -1;
-}
-
-/*
- * Special method: alternate functions and pullup/pulldown. This is only
- * invoked on startup to configure gpio's according to platform data.
- * FIXME : this functionality shall be managed (and exported to other drivers)
- * via the pin control subsystem.
- */
-static void gsta_set_config(struct gsta_gpio *chip, int nr, unsigned cfg)
-{
- struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK];
- unsigned long flags;
- u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK);
- u32 val;
- int err = 0;
-
- pr_info("%s: %p %i %i\n", __func__, chip, nr, cfg);
-
- if (cfg == PINMUX_TYPE_NONE)
- return;
-
- /* Alternate function or not? */
- spin_lock_irqsave(&chip->lock, flags);
- val = readl(&regs->afsela);
- if (cfg == PINMUX_TYPE_FUNCTION)
- val |= bit;
- else
- val &= ~bit;
- writel(val | bit, &regs->afsela);
- if (cfg == PINMUX_TYPE_FUNCTION) {
- spin_unlock_irqrestore(&chip->lock, flags);
- return;
- }
-
- /* not alternate function: set details */
- switch (cfg) {
- case PINMUX_TYPE_OUTPUT_LOW:
- writel(bit, &regs->dirs);
- writel(bit, &regs->datc);
- break;
- case PINMUX_TYPE_OUTPUT_HIGH:
- writel(bit, &regs->dirs);
- writel(bit, &regs->dats);
- break;
- case PINMUX_TYPE_INPUT:
- writel(bit, &regs->dirc);
- val = readl(&regs->pdis) | bit;
- writel(val, &regs->pdis);
- break;
- case PINMUX_TYPE_INPUT_PULLUP:
- writel(bit, &regs->dirc);
- val = readl(&regs->pdis) & ~bit;
- writel(val, &regs->pdis);
- writel(bit, &regs->dats);
- break;
- case PINMUX_TYPE_INPUT_PULLDOWN:
- writel(bit, &regs->dirc);
- val = readl(&regs->pdis) & ~bit;
- writel(val, &regs->pdis);
- writel(bit, &regs->datc);
- break;
- default:
- err = 1;
- }
- spin_unlock_irqrestore(&chip->lock, flags);
- if (err)
- pr_err("%s: chip %p, pin %i, cfg %i is invalid\n",
- __func__, chip, nr, cfg);
-}
-
-/*
- * Irq methods
- */
-
-static void gsta_irq_disable(struct irq_data *data)
-{
- struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
- struct gsta_gpio *chip = gc->private;
- int nr = data->irq - chip->irq_base;
- struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK];
- u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK);
- u32 val;
- unsigned long flags;
-
- spin_lock_irqsave(&chip->lock, flags);
- if (chip->irq_type[nr] & IRQ_TYPE_EDGE_RISING) {
- val = readl(&regs->rimsc) & ~bit;
- writel(val, &regs->rimsc);
- }
- if (chip->irq_type[nr] & IRQ_TYPE_EDGE_FALLING) {
- val = readl(&regs->fimsc) & ~bit;
- writel(val, &regs->fimsc);
- }
- spin_unlock_irqrestore(&chip->lock, flags);
- return;
-}
-
-static void gsta_irq_enable(struct irq_data *data)
-{
- struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
- struct gsta_gpio *chip = gc->private;
- int nr = data->irq - chip->irq_base;
- struct gsta_regs __iomem *regs = chip->regs[nr / GSTA_GPIO_PER_BLOCK];
- u32 bit = BIT(nr % GSTA_GPIO_PER_BLOCK);
- u32 val;
- int type;
- unsigned long flags;
-
- type = chip->irq_type[nr];
-
- spin_lock_irqsave(&chip->lock, flags);
- val = readl(&regs->rimsc);
- if (type & IRQ_TYPE_EDGE_RISING)
- writel(val | bit, &regs->rimsc);
- else
- writel(val & ~bit, &regs->rimsc);
- val = readl(&regs->rimsc);
- if (type & IRQ_TYPE_EDGE_FALLING)
- writel(val | bit, &regs->fimsc);
- else
- writel(val & ~bit, &regs->fimsc);
- spin_unlock_irqrestore(&chip->lock, flags);
- return;
-}
-
-static int gsta_irq_type(struct irq_data *d, unsigned int type)
-{
- struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
- struct gsta_gpio *chip = gc->private;
- int nr = d->irq - chip->irq_base;
-
- /* We only support edge interrupts */
- if (!(type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))) {
- pr_debug("%s: unsupported type 0x%x\n", __func__, type);
- return -EINVAL;
- }
-
- chip->irq_type[nr] = type; /* used for enable/disable */
-
- gsta_irq_enable(d);
- return 0;
-}
-
-static irqreturn_t gsta_gpio_handler(int irq, void *dev_id)
-{
- struct gsta_gpio *chip = dev_id;
- struct gsta_regs __iomem *regs;
- u32 is;
- int i, nr, base;
- irqreturn_t ret = IRQ_NONE;
-
- for (i = 0; i < GSTA_NR_BLOCKS; i++) {
- regs = chip->regs[i];
- base = chip->irq_base + i * GSTA_GPIO_PER_BLOCK;
- while ((is = readl(&regs->is))) {
- nr = __ffs(is);
- irq = base + nr;
- generic_handle_irq(irq);
- writel(1 << nr, &regs->ic);
- ret = IRQ_HANDLED;
- }
- }
- return ret;
-}
-
-static int gsta_alloc_irq_chip(struct gsta_gpio *chip)
-{
- struct irq_chip_generic *gc;
- struct irq_chip_type *ct;
- int rv;
-
- gc = devm_irq_alloc_generic_chip(chip->dev, KBUILD_MODNAME, 1,
- chip->irq_base,
- chip->reg_base, handle_simple_irq);
- if (!gc)
- return -ENOMEM;
-
- gc->private = chip;
- ct = gc->chip_types;
-
- ct->chip.irq_set_type = gsta_irq_type;
- ct->chip.irq_disable = gsta_irq_disable;
- ct->chip.irq_enable = gsta_irq_enable;
-
- /* FIXME: this makes at most 32 interrupts. Request 0 by now */
- rv = devm_irq_setup_generic_chip(chip->dev, gc,
- 0 /* IRQ_MSK(GSTA_GPIO_PER_BLOCK) */,
- 0, IRQ_NOREQUEST | IRQ_NOPROBE, 0);
- if (rv)
- return rv;
-
- /* Set up all 128 interrupts: code from setup_generic_chip */
- {
- struct irq_chip_type *ct = gc->chip_types;
- int i, j;
- for (j = 0; j < GSTA_NR_GPIO; j++) {
- i = chip->irq_base + j;
- irq_set_chip_and_handler(i, &ct->chip, ct->handler);
- irq_set_chip_data(i, gc);
- irq_clear_status_flags(i, IRQ_NOREQUEST | IRQ_NOPROBE);
- }
- gc->irq_cnt = i - gc->irq_base;
- }
-
- return 0;
-}
-
-/* The platform device used here is instantiated by the MFD device */
-static int gsta_probe(struct platform_device *dev)
-{
- int i, err;
- struct pci_dev *pdev;
- struct sta2x11_gpio_pdata *gpio_pdata;
- struct gsta_gpio *chip;
-
- pdev = *(struct pci_dev **)dev_get_platdata(&dev->dev);
- gpio_pdata = dev_get_platdata(&pdev->dev);
-
- if (gpio_pdata == NULL)
- dev_err(&dev->dev, "no gpio config\n");
- pr_debug("gpio config: %p\n", gpio_pdata);
-
- chip = devm_kzalloc(&dev->dev, sizeof(*chip), GFP_KERNEL);
- if (!chip)
- return -ENOMEM;
- chip->dev = &dev->dev;
- chip->reg_base = devm_platform_ioremap_resource(dev, 0);
- if (IS_ERR(chip->reg_base))
- return PTR_ERR(chip->reg_base);
-
- for (i = 0; i < GSTA_NR_BLOCKS; i++) {
- chip->regs[i] = chip->reg_base + i * 4096;
- /* disable all irqs */
- writel(0, &chip->regs[i]->rimsc);
- writel(0, &chip->regs[i]->fimsc);
- writel(~0, &chip->regs[i]->ic);
- }
- spin_lock_init(&chip->lock);
- gsta_gpio_setup(chip);
- if (gpio_pdata)
- for (i = 0; i < GSTA_NR_GPIO; i++)
- gsta_set_config(chip, i, gpio_pdata->pinconfig[i]);
-
- /* 384 was used in previous code: be compatible for other drivers */
- err = devm_irq_alloc_descs(&dev->dev, -1, 384,
- GSTA_NR_GPIO, NUMA_NO_NODE);
- if (err < 0) {
- dev_warn(&dev->dev, "sta2x11 gpio: Can't get irq base (%i)\n",
- -err);
- return err;
- }
- chip->irq_base = err;
-
- err = gsta_alloc_irq_chip(chip);
- if (err)
- return err;
-
- err = devm_request_irq(&dev->dev, pdev->irq, gsta_gpio_handler,
- IRQF_SHARED, KBUILD_MODNAME, chip);
- if (err < 0) {
- dev_err(&dev->dev, "sta2x11 gpio: Can't request irq (%i)\n",
- -err);
- return err;
- }
-
- return devm_gpiochip_add_data(&dev->dev, &chip->gpio, chip);
-}
-
-static struct platform_driver sta2x11_gpio_platform_driver = {
- .driver = {
- .name = "sta2x11-gpio",
- .suppress_bind_attrs = true,
- },
- .probe = gsta_probe,
-};
-builtin_platform_driver(sta2x11_gpio_platform_driver);
diff --git a/drivers/gpio/gpio-tpic2810.c b/drivers/gpio/gpio-tpic2810.c
index d642c35cb97c..349c5fbd9b02 100644
--- a/drivers/gpio/gpio-tpic2810.c
+++ b/drivers/gpio/gpio-tpic2810.c
@@ -98,8 +98,7 @@ static const struct of_device_id tpic2810_of_match_table[] = {
};
MODULE_DEVICE_TABLE(of, tpic2810_of_match_table);
-static int tpic2810_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int tpic2810_probe(struct i2c_client *client)
{
struct tpic2810 *gpio;
int ret;
@@ -144,7 +143,7 @@ static struct i2c_driver tpic2810_driver = {
.name = "tpic2810",
.of_match_table = tpic2810_of_match_table,
},
- .probe = tpic2810_probe,
+ .probe_new = tpic2810_probe,
.remove = tpic2810_remove,
.id_table = tpic2810_id_table,
};
diff --git a/drivers/gpio/gpio-ts4900.c b/drivers/gpio/gpio-ts4900.c
index 416725c26e94..43e8b66e04f7 100644
--- a/drivers/gpio/gpio-ts4900.c
+++ b/drivers/gpio/gpio-ts4900.c
@@ -136,8 +136,7 @@ static const struct of_device_id ts4900_gpio_of_match_table[] = {
};
MODULE_DEVICE_TABLE(of, ts4900_gpio_of_match_table);
-static int ts4900_gpio_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ts4900_gpio_probe(struct i2c_client *client)
{
struct ts4900_gpio_priv *priv;
u32 ngpio;
@@ -186,7 +185,7 @@ static struct i2c_driver ts4900_gpio_driver = {
.name = "ts4900-gpio",
.of_match_table = ts4900_gpio_of_match_table,
},
- .probe = ts4900_gpio_probe,
+ .probe_new = ts4900_gpio_probe,
.id_table = ts4900_gpio_id_table,
};
module_i2c_driver(ts4900_gpio_driver);
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index a7d2358736fe..bed0380c5136 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -89,6 +89,30 @@ struct acpi_gpio_chip {
struct list_head deferred_req_irqs_list_entry;
};
+/**
+ * struct acpi_gpio_info - ACPI GPIO specific information
+ * @adev: reference to ACPI device which consumes GPIO resource
+ * @flags: GPIO initialization flags
+ * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
+ * @pin_config: pin bias as provided by ACPI
+ * @polarity: interrupt polarity as provided by ACPI
+ * @triggering: triggering type as provided by ACPI
+ * @wake_capable: wake capability as provided by ACPI
+ * @debounce: debounce timeout as provided by ACPI
+ * @quirks: Linux specific quirks as provided by struct acpi_gpio_mapping
+ */
+struct acpi_gpio_info {
+ struct acpi_device *adev;
+ enum gpiod_flags flags;
+ bool gpioint;
+ int pin_config;
+ int polarity;
+ int triggering;
+ bool wake_capable;
+ unsigned int debounce;
+ unsigned int quirks;
+};
+
/*
* For GPIO chips which call acpi_gpiochip_request_interrupts() before late_init
* (so builtin drivers) we register the ACPI GpioInt IRQ handlers from a
@@ -512,7 +536,7 @@ void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
if (ACPI_FAILURE(status))
return;
- acpi_walk_resources(handle, "_AEI",
+ acpi_walk_resources(handle, METHOD_NAME__AEI,
acpi_gpiochip_alloc_event, acpi_gpio);
mutex_lock(&acpi_gpio_deferred_req_irqs_lock);
@@ -670,8 +694,8 @@ __acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update)
return ret;
}
-int
-acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *info)
+static int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags,
+ struct acpi_gpio_info *info)
{
struct device *dev = &info->adev->dev;
enum gpiod_flags old = *flags;
@@ -690,8 +714,8 @@ acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *inf
return ret;
}
-int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
- struct acpi_gpio_info *info)
+static int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
+ struct acpi_gpio_info *info)
{
switch (info->pin_config) {
case ACPI_PIN_CONFIG_PULLUP:
@@ -864,8 +888,9 @@ static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode,
* function only returns the first.
*/
static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
- const char *propname, int index,
- struct acpi_gpio_info *info)
+ const char *propname,
+ int index,
+ struct acpi_gpio_info *info)
{
struct acpi_gpio_lookup lookup;
int ret;
@@ -896,6 +921,44 @@ static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
return ret ? ERR_PTR(ret) : lookup.desc;
}
+/**
+ * acpi_get_gpiod_from_data() - get a GPIO descriptor from ACPI data node
+ * @fwnode: pointer to an ACPI firmware node to get the GPIO information from
+ * @propname: Property name of the GPIO
+ * @index: index of GpioIo/GpioInt resource (starting from %0)
+ * @info: info pointer to fill in (optional)
+ *
+ * This function uses the property-based GPIO lookup to get to the GPIO
+ * resource with the relevant information from a data-only ACPI firmware node
+ * and uses that to obtain the GPIO descriptor to return.
+ *
+ * If the GPIO cannot be translated or there is an error an ERR_PTR is
+ * returned.
+ */
+static struct gpio_desc *acpi_get_gpiod_from_data(struct fwnode_handle *fwnode,
+ const char *propname,
+ int index,
+ struct acpi_gpio_info *info)
+{
+ struct acpi_gpio_lookup lookup;
+ int ret;
+
+ if (!is_acpi_data_node(fwnode))
+ return ERR_PTR(-ENODEV);
+
+ if (!propname)
+ return ERR_PTR(-EINVAL);
+
+ lookup.index = index;
+
+ ret = acpi_gpio_property_lookup(fwnode, propname, index, &lookup);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = acpi_gpio_resource_lookup(&lookup, info);
+ return ret ? ERR_PTR(ret) : lookup.desc;
+}
+
static bool acpi_can_fallback_to_crs(struct acpi_device *adev,
const char *con_id)
{
@@ -906,13 +969,13 @@ static bool acpi_can_fallback_to_crs(struct acpi_device *adev,
return con_id == NULL;
}
-struct gpio_desc *acpi_find_gpio(struct device *dev,
+struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode,
const char *con_id,
unsigned int idx,
enum gpiod_flags *dflags,
unsigned long *lookupflags)
{
- struct acpi_device *adev = ACPI_COMPANION(dev);
+ struct acpi_device *adev = to_acpi_device_node(fwnode);
struct acpi_gpio_info info;
struct gpio_desc *desc;
char propname[32];
@@ -928,7 +991,12 @@ struct gpio_desc *acpi_find_gpio(struct device *dev,
gpio_suffixes[i]);
}
- desc = acpi_get_gpiod_by_index(adev, propname, idx, &info);
+ if (adev)
+ desc = acpi_get_gpiod_by_index(adev,
+ propname, idx, &info);
+ else
+ desc = acpi_get_gpiod_from_data(fwnode,
+ propname, idx, &info);
if (!IS_ERR(desc))
break;
if (PTR_ERR(desc) == -EPROBE_DEFER)
@@ -937,7 +1005,7 @@ struct gpio_desc *acpi_find_gpio(struct device *dev,
/* Then from plain _CRS GPIOs */
if (IS_ERR(desc)) {
- if (!acpi_can_fallback_to_crs(adev, con_id))
+ if (!adev || !acpi_can_fallback_to_crs(adev, con_id))
return ERR_PTR(-ENOENT);
desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
@@ -957,50 +1025,6 @@ struct gpio_desc *acpi_find_gpio(struct device *dev,
}
/**
- * acpi_node_get_gpiod() - get a GPIO descriptor from ACPI resources
- * @fwnode: pointer to an ACPI firmware node to get the GPIO information from
- * @propname: Property name of the GPIO
- * @index: index of GpioIo/GpioInt resource (starting from %0)
- * @info: info pointer to fill in (optional)
- *
- * If @fwnode is an ACPI device object, call acpi_get_gpiod_by_index() for it.
- * Otherwise (i.e. it is a data-only non-device object), use the property-based
- * GPIO lookup to get to the GPIO resource with the relevant information and use
- * that to obtain the GPIO descriptor to return.
- *
- * If the GPIO cannot be translated or there is an error an ERR_PTR is
- * returned.
- */
-struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
- const char *propname, int index,
- struct acpi_gpio_info *info)
-{
- struct acpi_gpio_lookup lookup;
- struct acpi_device *adev;
- int ret;
-
- adev = to_acpi_device_node(fwnode);
- if (adev)
- return acpi_get_gpiod_by_index(adev, propname, index, info);
-
- if (!is_acpi_data_node(fwnode))
- return ERR_PTR(-ENODEV);
-
- if (!propname)
- return ERR_PTR(-EINVAL);
-
- memset(&lookup, 0, sizeof(lookup));
- lookup.index = index;
-
- ret = acpi_gpio_property_lookup(fwnode, propname, index, &lookup);
- if (ret)
- return ERR_PTR(ret);
-
- ret = acpi_gpio_resource_lookup(&lookup, info);
- return ret ? ERR_PTR(ret) : lookup.desc;
-}
-
-/**
* acpi_dev_gpio_irq_wake_get_by() - Find GpioInt and translate it to Linux IRQ number
* @adev: pointer to a ACPI device to get IRQ from
* @name: optional name of GpioInt resource
diff --git a/drivers/gpio/gpiolib-acpi.h b/drivers/gpio/gpiolib-acpi.h
index 01e0cb480a00..9475f99a9694 100644
--- a/drivers/gpio/gpiolib-acpi.h
+++ b/drivers/gpio/gpiolib-acpi.h
@@ -22,30 +22,6 @@ struct gpio_chip;
struct gpio_desc;
struct gpio_device;
-/**
- * struct acpi_gpio_info - ACPI GPIO specific information
- * @adev: reference to ACPI device which consumes GPIO resource
- * @flags: GPIO initialization flags
- * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
- * @pin_config: pin bias as provided by ACPI
- * @polarity: interrupt polarity as provided by ACPI
- * @triggering: triggering type as provided by ACPI
- * @wake_capable: wake capability as provided by ACPI
- * @debounce: debounce timeout as provided by ACPI
- * @quirks: Linux specific quirks as provided by struct acpi_gpio_mapping
- */
-struct acpi_gpio_info {
- struct acpi_device *adev;
- enum gpiod_flags flags;
- bool gpioint;
- int pin_config;
- int polarity;
- int triggering;
- bool wake_capable;
- unsigned int debounce;
- unsigned int quirks;
-};
-
#ifdef CONFIG_ACPI
void acpi_gpiochip_add(struct gpio_chip *chip);
void acpi_gpiochip_remove(struct gpio_chip *chip);
@@ -55,19 +31,11 @@ void acpi_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev);
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
-int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags,
- struct acpi_gpio_info *info);
-int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
- struct acpi_gpio_info *info);
-
-struct gpio_desc *acpi_find_gpio(struct device *dev,
+struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode,
const char *con_id,
unsigned int idx,
enum gpiod_flags *dflags,
unsigned long *lookupflags);
-struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
- const char *propname, int index,
- struct acpi_gpio_info *info);
int acpi_gpio_count(struct device *dev, const char *con_id);
#else
@@ -82,31 +50,13 @@ acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { }
static inline void
acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }
-static inline int
-acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *info)
-{
- return 0;
-}
-static inline int
-acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
- struct acpi_gpio_info *info)
-{
- return 0;
-}
-
static inline struct gpio_desc *
-acpi_find_gpio(struct device *dev, const char *con_id,
+acpi_find_gpio(struct fwnode_handle *fwnode, const char *con_id,
unsigned int idx, enum gpiod_flags *dflags,
unsigned long *lookupflags)
{
return ERR_PTR(-ENOENT);
}
-static inline struct gpio_desc *
-acpi_node_get_gpiod(struct fwnode_handle *fwnode, const char *propname,
- int index, struct acpi_gpio_info *info)
-{
- return ERR_PTR(-ENXIO);
-}
static inline int acpi_gpio_count(struct device *dev, const char *con_id)
{
return -ENODEV;
diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c
index 65b2c09a4576..e878e3f22b0e 100644
--- a/drivers/gpio/gpiolib-cdev.c
+++ b/drivers/gpio/gpiolib-cdev.c
@@ -57,6 +57,50 @@ static_assert(IS_ALIGNED(sizeof(struct gpio_v2_line_values), 8));
* interface to gpiolib GPIOs via ioctl()s.
*/
+typedef __poll_t (*poll_fn)(struct file *, struct poll_table_struct *);
+typedef long (*ioctl_fn)(struct file *, unsigned int, unsigned long);
+typedef ssize_t (*read_fn)(struct file *, char __user *,
+ size_t count, loff_t *);
+
+static __poll_t call_poll_locked(struct file *file,
+ struct poll_table_struct *wait,
+ struct gpio_device *gdev, poll_fn func)
+{
+ __poll_t ret;
+
+ down_read(&gdev->sem);
+ ret = func(file, wait);
+ up_read(&gdev->sem);
+
+ return ret;
+}
+
+static long call_ioctl_locked(struct file *file, unsigned int cmd,
+ unsigned long arg, struct gpio_device *gdev,
+ ioctl_fn func)
+{
+ long ret;
+
+ down_read(&gdev->sem);
+ ret = func(file, cmd, arg);
+ up_read(&gdev->sem);
+
+ return ret;
+}
+
+static ssize_t call_read_locked(struct file *file, char __user *buf,
+ size_t count, loff_t *f_ps,
+ struct gpio_device *gdev, read_fn func)
+{
+ ssize_t ret;
+
+ down_read(&gdev->sem);
+ ret = func(file, buf, count, f_ps);
+ up_read(&gdev->sem);
+
+ return ret;
+}
+
/*
* GPIO line handle management
*/
@@ -193,8 +237,8 @@ static long linehandle_set_config(struct linehandle_state *lh,
return 0;
}
-static long linehandle_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
+static long linehandle_ioctl_unlocked(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
struct linehandle_state *lh = file->private_data;
void __user *ip = (void __user *)arg;
@@ -203,6 +247,9 @@ static long linehandle_ioctl(struct file *file, unsigned int cmd,
unsigned int i;
int ret;
+ if (!lh->gdev->chip)
+ return -ENODEV;
+
switch (cmd) {
case GPIOHANDLE_GET_LINE_VALUES_IOCTL:
/* NOTE: It's okay to read values of output lines */
@@ -249,6 +296,15 @@ static long linehandle_ioctl(struct file *file, unsigned int cmd,
}
}
+static long linehandle_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct linehandle_state *lh = file->private_data;
+
+ return call_ioctl_locked(file, cmd, arg, lh->gdev,
+ linehandle_ioctl_unlocked);
+}
+
#ifdef CONFIG_COMPAT
static long linehandle_ioctl_compat(struct file *file, unsigned int cmd,
unsigned long arg)
@@ -412,7 +468,7 @@ out_free_lh:
* @desc: the GPIO descriptor for this line.
* @req: the corresponding line request
* @irq: the interrupt triggered in response to events on this GPIO
- * @eflags: the edge flags, GPIO_V2_LINE_FLAG_EDGE_RISING and/or
+ * @edflags: the edge flags, GPIO_V2_LINE_FLAG_EDGE_RISING and/or
* GPIO_V2_LINE_FLAG_EDGE_FALLING, indicating the edge detection applied
* @timestamp_ns: cache for the timestamp storing it between hardirq and
* IRQ thread, used to bring the timestamp close to the actual event
@@ -1380,12 +1436,15 @@ static long linereq_set_config(struct linereq *lr, void __user *ip)
return ret;
}
-static long linereq_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
+static long linereq_ioctl_unlocked(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
struct linereq *lr = file->private_data;
void __user *ip = (void __user *)arg;
+ if (!lr->gdev->chip)
+ return -ENODEV;
+
switch (cmd) {
case GPIO_V2_LINE_GET_VALUES_IOCTL:
return linereq_get_values(lr, ip);
@@ -1398,6 +1457,15 @@ static long linereq_ioctl(struct file *file, unsigned int cmd,
}
}
+static long linereq_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct linereq *lr = file->private_data;
+
+ return call_ioctl_locked(file, cmd, arg, lr->gdev,
+ linereq_ioctl_unlocked);
+}
+
#ifdef CONFIG_COMPAT
static long linereq_ioctl_compat(struct file *file, unsigned int cmd,
unsigned long arg)
@@ -1406,12 +1474,15 @@ static long linereq_ioctl_compat(struct file *file, unsigned int cmd,
}
#endif
-static __poll_t linereq_poll(struct file *file,
- struct poll_table_struct *wait)
+static __poll_t linereq_poll_unlocked(struct file *file,
+ struct poll_table_struct *wait)
{
struct linereq *lr = file->private_data;
__poll_t events = 0;
+ if (!lr->gdev->chip)
+ return EPOLLHUP | EPOLLERR;
+
poll_wait(file, &lr->wait, wait);
if (!kfifo_is_empty_spinlocked_noirqsave(&lr->events,
@@ -1421,16 +1492,25 @@ static __poll_t linereq_poll(struct file *file,
return events;
}
-static ssize_t linereq_read(struct file *file,
- char __user *buf,
- size_t count,
- loff_t *f_ps)
+static __poll_t linereq_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct linereq *lr = file->private_data;
+
+ return call_poll_locked(file, wait, lr->gdev, linereq_poll_unlocked);
+}
+
+static ssize_t linereq_read_unlocked(struct file *file, char __user *buf,
+ size_t count, loff_t *f_ps)
{
struct linereq *lr = file->private_data;
struct gpio_v2_line_event le;
ssize_t bytes_read = 0;
int ret;
+ if (!lr->gdev->chip)
+ return -ENODEV;
+
if (count < sizeof(le))
return -EINVAL;
@@ -1475,6 +1555,15 @@ static ssize_t linereq_read(struct file *file,
return bytes_read;
}
+static ssize_t linereq_read(struct file *file, char __user *buf,
+ size_t count, loff_t *f_ps)
+{
+ struct linereq *lr = file->private_data;
+
+ return call_read_locked(file, buf, count, f_ps, lr->gdev,
+ linereq_read_unlocked);
+}
+
static void linereq_free(struct linereq *lr)
{
unsigned int i;
@@ -1712,12 +1801,15 @@ struct lineevent_state {
(GPIOEVENT_REQUEST_RISING_EDGE | \
GPIOEVENT_REQUEST_FALLING_EDGE)
-static __poll_t lineevent_poll(struct file *file,
- struct poll_table_struct *wait)
+static __poll_t lineevent_poll_unlocked(struct file *file,
+ struct poll_table_struct *wait)
{
struct lineevent_state *le = file->private_data;
__poll_t events = 0;
+ if (!le->gdev->chip)
+ return EPOLLHUP | EPOLLERR;
+
poll_wait(file, &le->wait, wait);
if (!kfifo_is_empty_spinlocked_noirqsave(&le->events, &le->wait.lock))
@@ -1726,15 +1818,21 @@ static __poll_t lineevent_poll(struct file *file,
return events;
}
+static __poll_t lineevent_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct lineevent_state *le = file->private_data;
+
+ return call_poll_locked(file, wait, le->gdev, lineevent_poll_unlocked);
+}
+
struct compat_gpioeevent_data {
compat_u64 timestamp;
u32 id;
};
-static ssize_t lineevent_read(struct file *file,
- char __user *buf,
- size_t count,
- loff_t *f_ps)
+static ssize_t lineevent_read_unlocked(struct file *file, char __user *buf,
+ size_t count, loff_t *f_ps)
{
struct lineevent_state *le = file->private_data;
struct gpioevent_data ge;
@@ -1742,6 +1840,9 @@ static ssize_t lineevent_read(struct file *file,
ssize_t ge_size;
int ret;
+ if (!le->gdev->chip)
+ return -ENODEV;
+
/*
* When compatible system call is being used the struct gpioevent_data,
* in case of at least ia32, has different size due to the alignment
@@ -1799,6 +1900,15 @@ static ssize_t lineevent_read(struct file *file,
return bytes_read;
}
+static ssize_t lineevent_read(struct file *file, char __user *buf,
+ size_t count, loff_t *f_ps)
+{
+ struct lineevent_state *le = file->private_data;
+
+ return call_read_locked(file, buf, count, f_ps, le->gdev,
+ lineevent_read_unlocked);
+}
+
static void lineevent_free(struct lineevent_state *le)
{
if (le->irq)
@@ -1816,13 +1926,16 @@ static int lineevent_release(struct inode *inode, struct file *file)
return 0;
}
-static long lineevent_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
+static long lineevent_ioctl_unlocked(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
struct lineevent_state *le = file->private_data;
void __user *ip = (void __user *)arg;
struct gpiohandle_data ghd;
+ if (!le->gdev->chip)
+ return -ENODEV;
+
/*
* We can get the value for an event line but not set it,
* because it is input by definition.
@@ -1845,6 +1958,15 @@ static long lineevent_ioctl(struct file *file, unsigned int cmd,
return -EINVAL;
}
+static long lineevent_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct lineevent_state *le = file->private_data;
+
+ return call_ioctl_locked(file, cmd, arg, le->gdev,
+ lineevent_ioctl_unlocked);
+}
+
#ifdef CONFIG_COMPAT
static long lineevent_ioctl_compat(struct file *file, unsigned int cmd,
unsigned long arg)
@@ -2403,12 +2525,15 @@ static int lineinfo_changed_notify(struct notifier_block *nb,
return NOTIFY_OK;
}
-static __poll_t lineinfo_watch_poll(struct file *file,
- struct poll_table_struct *pollt)
+static __poll_t lineinfo_watch_poll_unlocked(struct file *file,
+ struct poll_table_struct *pollt)
{
struct gpio_chardev_data *cdev = file->private_data;
__poll_t events = 0;
+ if (!cdev->gdev->chip)
+ return EPOLLHUP | EPOLLERR;
+
poll_wait(file, &cdev->wait, pollt);
if (!kfifo_is_empty_spinlocked_noirqsave(&cdev->events,
@@ -2418,8 +2543,17 @@ static __poll_t lineinfo_watch_poll(struct file *file,
return events;
}
-static ssize_t lineinfo_watch_read(struct file *file, char __user *buf,
- size_t count, loff_t *off)
+static __poll_t lineinfo_watch_poll(struct file *file,
+ struct poll_table_struct *pollt)
+{
+ struct gpio_chardev_data *cdev = file->private_data;
+
+ return call_poll_locked(file, pollt, cdev->gdev,
+ lineinfo_watch_poll_unlocked);
+}
+
+static ssize_t lineinfo_watch_read_unlocked(struct file *file, char __user *buf,
+ size_t count, loff_t *off)
{
struct gpio_chardev_data *cdev = file->private_data;
struct gpio_v2_line_info_changed event;
@@ -2427,6 +2561,9 @@ static ssize_t lineinfo_watch_read(struct file *file, char __user *buf,
int ret;
size_t event_size;
+ if (!cdev->gdev->chip)
+ return -ENODEV;
+
#ifndef CONFIG_GPIO_CDEV_V1
event_size = sizeof(struct gpio_v2_line_info_changed);
if (count < event_size)
@@ -2494,6 +2631,15 @@ static ssize_t lineinfo_watch_read(struct file *file, char __user *buf,
return bytes_read;
}
+static ssize_t lineinfo_watch_read(struct file *file, char __user *buf,
+ size_t count, loff_t *off)
+{
+ struct gpio_chardev_data *cdev = file->private_data;
+
+ return call_read_locked(file, buf, count, off, cdev->gdev,
+ lineinfo_watch_read_unlocked);
+}
+
/**
* gpio_chrdev_open() - open the chardev for ioctl operations
* @inode: inode for this chardev
@@ -2507,13 +2653,17 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file)
struct gpio_chardev_data *cdev;
int ret = -ENOMEM;
+ down_read(&gdev->sem);
+
/* Fail on open if the backing gpiochip is gone */
- if (!gdev->chip)
- return -ENODEV;
+ if (!gdev->chip) {
+ ret = -ENODEV;
+ goto out_unlock;
+ }
cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
if (!cdev)
- return -ENOMEM;
+ goto out_unlock;
cdev->watched_lines = bitmap_zalloc(gdev->chip->ngpio, GFP_KERNEL);
if (!cdev->watched_lines)
@@ -2536,6 +2686,8 @@ static int gpio_chrdev_open(struct inode *inode, struct file *file)
if (ret)
goto out_unregister_notifier;
+ up_read(&gdev->sem);
+
return ret;
out_unregister_notifier:
@@ -2545,6 +2697,8 @@ out_free_bitmap:
bitmap_free(cdev->watched_lines);
out_free_cdev:
kfree(cdev);
+out_unlock:
+ up_read(&gdev->sem);
return ret;
}
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 0e4e1291604d..4fff7258ee41 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -85,7 +85,7 @@ static int of_gpiochip_match_node_and_xlate(struct gpio_chip *chip, void *data)
{
struct of_phandle_args *gpiospec = data;
- return chip->gpiodev->dev.of_node == gpiospec->np &&
+ return device_match_of_node(&chip->gpiodev->dev, gpiospec->np) &&
chip->of_xlate &&
chip->of_xlate(chip, gpiospec, NULL) >= 0;
}
@@ -112,55 +112,133 @@ static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
return gpiochip_get_desc(chip, ret);
}
-/**
- * of_gpio_need_valid_mask() - figure out if the OF GPIO driver needs
- * to set the .valid_mask
- * @gc: the target gpio_chip
- *
- * Return: true if the valid mask needs to be set
+/*
+ * Overrides stated polarity of a gpio line and warns when there is a
+ * discrepancy.
*/
-bool of_gpio_need_valid_mask(const struct gpio_chip *gc)
+static void of_gpio_quirk_polarity(const struct device_node *np,
+ bool active_high,
+ enum of_gpio_flags *flags)
{
- int size;
- const struct device_node *np = gc->of_node;
+ if (active_high) {
+ if (*flags & OF_GPIO_ACTIVE_LOW) {
+ pr_warn("%s GPIO handle specifies active low - ignored\n",
+ of_node_full_name(np));
+ *flags &= ~OF_GPIO_ACTIVE_LOW;
+ }
+ } else {
+ if (!(*flags & OF_GPIO_ACTIVE_LOW))
+ pr_info("%s enforce active low on GPIO handle\n",
+ of_node_full_name(np));
+ *flags |= OF_GPIO_ACTIVE_LOW;
+ }
+}
- size = of_property_count_u32_elems(np, "gpio-reserved-ranges");
- if (size > 0 && size % 2 == 0)
- return true;
- return false;
+/*
+ * This quirk does static polarity overrides in cases where existing
+ * DTS specified incorrect polarity.
+ */
+static void of_gpio_try_fixup_polarity(const struct device_node *np,
+ const char *propname,
+ enum of_gpio_flags *flags)
+{
+ static const struct {
+ const char *compatible;
+ const char *propname;
+ bool active_high;
+ } gpios[] = {
+#if !IS_ENABLED(CONFIG_LCD_HX8357)
+ /*
+ * Himax LCD controllers used incorrectly named
+ * "gpios-reset" property and also specified wrong
+ * polarity.
+ */
+ { "himax,hx8357", "gpios-reset", false },
+ { "himax,hx8369", "gpios-reset", false },
+#endif
+ };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(gpios); i++) {
+ if (of_device_is_compatible(np, gpios[i].compatible) &&
+ !strcmp(propname, gpios[i].propname)) {
+ of_gpio_quirk_polarity(np, gpios[i].active_high, flags);
+ break;
+ }
+ }
}
-static void of_gpio_flags_quirks(const struct device_node *np,
- const char *propname,
- enum of_gpio_flags *flags,
- int index)
+static void of_gpio_set_polarity_by_property(const struct device_node *np,
+ const char *propname,
+ enum of_gpio_flags *flags)
{
- /*
- * Some GPIO fixed regulator quirks.
- * Note that active low is the default.
- */
- if (IS_ENABLED(CONFIG_REGULATOR) &&
- (of_device_is_compatible(np, "regulator-fixed") ||
- of_device_is_compatible(np, "reg-fixed-voltage") ||
- (!(strcmp(propname, "enable-gpio") &&
- strcmp(propname, "enable-gpios")) &&
- of_device_is_compatible(np, "regulator-gpio")))) {
- bool active_low = !of_property_read_bool(np,
- "enable-active-high");
+ static const struct {
+ const char *compatible;
+ const char *gpio_propname;
+ const char *polarity_propname;
+ } gpios[] = {
+#if IS_ENABLED(CONFIG_FEC)
+ /* Freescale Fast Ethernet Controller */
+ { "fsl,imx25-fec", "phy-reset-gpios", "phy-reset-active-high" },
+ { "fsl,imx27-fec", "phy-reset-gpios", "phy-reset-active-high" },
+ { "fsl,imx28-fec", "phy-reset-gpios", "phy-reset-active-high" },
+ { "fsl,imx6q-fec", "phy-reset-gpios", "phy-reset-active-high" },
+ { "fsl,mvf600-fec", "phy-reset-gpios", "phy-reset-active-high" },
+ { "fsl,imx6sx-fec", "phy-reset-gpios", "phy-reset-active-high" },
+ { "fsl,imx6ul-fec", "phy-reset-gpios", "phy-reset-active-high" },
+ { "fsl,imx8mq-fec", "phy-reset-gpios", "phy-reset-active-high" },
+ { "fsl,imx8qm-fec", "phy-reset-gpios", "phy-reset-active-high" },
+ { "fsl,s32v234-fec", "phy-reset-gpios", "phy-reset-active-high" },
+#endif
+#if IS_ENABLED(CONFIG_PCI_IMX6)
+ { "fsl,imx6q-pcie", "reset-gpio", "reset-gpio-active-high" },
+ { "fsl,imx6sx-pcie", "reset-gpio", "reset-gpio-active-high" },
+ { "fsl,imx6qp-pcie", "reset-gpio", "reset-gpio-active-high" },
+ { "fsl,imx7d-pcie", "reset-gpio", "reset-gpio-active-high" },
+ { "fsl,imx8mq-pcie", "reset-gpio", "reset-gpio-active-high" },
+ { "fsl,imx8mm-pcie", "reset-gpio", "reset-gpio-active-high" },
+ { "fsl,imx8mp-pcie", "reset-gpio", "reset-gpio-active-high" },
+#endif
+
/*
* The regulator GPIO handles are specified such that the
* presence or absence of "enable-active-high" solely controls
* the polarity of the GPIO line. Any phandle flags must
* be actively ignored.
*/
- if ((*flags & OF_GPIO_ACTIVE_LOW) && !active_low) {
- pr_warn("%s GPIO handle specifies active low - ignored\n",
- of_node_full_name(np));
- *flags &= ~OF_GPIO_ACTIVE_LOW;
+#if IS_ENABLED(CONFIG_REGULATOR_FIXED_VOLTAGE)
+ { "regulator-fixed", "gpios", "enable-active-high" },
+ { "regulator-fixed", "gpio", "enable-active-high" },
+ { "reg-fixed-voltage", "gpios", "enable-active-high" },
+ { "reg-fixed-voltage", "gpio", "enable-active-high" },
+#endif
+#if IS_ENABLED(CONFIG_REGULATOR_GPIO)
+ { "regulator-gpio", "enable-gpio", "enable-active-high" },
+ { "regulator-gpio", "enable-gpios", "enable-active-high" },
+#endif
+ };
+ unsigned int i;
+ bool active_high;
+
+ for (i = 0; i < ARRAY_SIZE(gpios); i++) {
+ if (of_device_is_compatible(np, gpios[i].compatible) &&
+ !strcmp(propname, gpios[i].gpio_propname)) {
+ active_high = of_property_read_bool(np,
+ gpios[i].polarity_propname);
+ of_gpio_quirk_polarity(np, active_high, flags);
+ break;
}
- if (active_low)
- *flags |= OF_GPIO_ACTIVE_LOW;
}
+}
+
+static void of_gpio_flags_quirks(const struct device_node *np,
+ const char *propname,
+ enum of_gpio_flags *flags,
+ int index)
+{
+ of_gpio_try_fixup_polarity(np, propname, flags);
+ of_gpio_set_polarity_by_property(np, propname, flags);
+
/*
* Legacy open drain handling for fixed voltage regulators.
*/
@@ -200,18 +278,10 @@ static void of_gpio_flags_quirks(const struct device_node *np,
* conflict and the "spi-cs-high" flag will
* take precedence.
*/
- if (of_property_read_bool(child, "spi-cs-high")) {
- if (*flags & OF_GPIO_ACTIVE_LOW) {
- pr_warn("%s GPIO handle specifies active low - ignored\n",
- of_node_full_name(child));
- *flags &= ~OF_GPIO_ACTIVE_LOW;
- }
- } else {
- if (!(*flags & OF_GPIO_ACTIVE_LOW))
- pr_info("%s enforce active low on chipselect handle\n",
- of_node_full_name(child));
- *flags |= OF_GPIO_ACTIVE_LOW;
- }
+ bool active_high = of_property_read_bool(child,
+ "spi-cs-high");
+ of_gpio_quirk_polarity(child, active_high,
+ flags);
of_node_put(child);
break;
}
@@ -365,127 +435,164 @@ struct gpio_desc *gpiod_get_from_of_node(const struct device_node *node,
}
EXPORT_SYMBOL_GPL(gpiod_get_from_of_node);
-/*
- * The SPI GPIO bindings happened before we managed to establish that GPIO
- * properties should be named "foo-gpios" so we have this special kludge for
- * them.
- */
-static struct gpio_desc *of_find_spi_gpio(struct device_node *np,
- const char *con_id,
- unsigned int idx,
- enum of_gpio_flags *of_flags)
-{
- char prop_name[32]; /* 32 is max size of property name */
-
- /*
- * Hopefully the compiler stubs the rest of the function if this
- * is false.
- */
- if (!IS_ENABLED(CONFIG_SPI_MASTER))
- return ERR_PTR(-ENOENT);
-
- /* Allow this specifically for "spi-gpio" devices */
- if (!of_device_is_compatible(np, "spi-gpio") || !con_id)
- return ERR_PTR(-ENOENT);
-
- /* Will be "gpio-sck", "gpio-mosi" or "gpio-miso" */
- snprintf(prop_name, sizeof(prop_name), "%s-%s", "gpio", con_id);
-
- return of_get_named_gpiod_flags(np, prop_name, idx, of_flags);
-}
-
-/*
- * The old Freescale bindings use simply "gpios" as name for the chip select
- * lines rather than "cs-gpios" like all other SPI hardware. Account for this
- * with a special quirk.
- */
-static struct gpio_desc *of_find_spi_cs_gpio(struct device_node *np,
+static struct gpio_desc *of_find_gpio_rename(struct device_node *np,
const char *con_id,
unsigned int idx,
enum of_gpio_flags *of_flags)
{
- if (!IS_ENABLED(CONFIG_SPI_MASTER))
- return ERR_PTR(-ENOENT);
+ static const struct of_rename_gpio {
+ const char *con_id;
+ const char *legacy_id; /* NULL - same as con_id */
+ /*
+ * Compatible string can be set to NULL in case where
+ * matching to a particular compatible is not practical,
+ * but it should only be done for gpio names that have
+ * vendor prefix to reduce risk of false positives.
+ * Addition of such entries is strongly discouraged.
+ */
+ const char *compatible;
+ } gpios[] = {
+#if !IS_ENABLED(CONFIG_LCD_HX8357)
+ /* Himax LCD controllers used "gpios-reset" */
+ { "reset", "gpios-reset", "himax,hx8357" },
+ { "reset", "gpios-reset", "himax,hx8369" },
+#endif
+#if IS_ENABLED(CONFIG_MFD_ARIZONA)
+ { "wlf,reset", NULL, NULL },
+#endif
+#if IS_ENABLED(CONFIG_RTC_DRV_MOXART)
+ { "rtc-data", "gpio-rtc-data", "moxa,moxart-rtc" },
+ { "rtc-sclk", "gpio-rtc-sclk", "moxa,moxart-rtc" },
+ { "rtc-reset", "gpio-rtc-reset", "moxa,moxart-rtc" },
+#endif
+#if IS_ENABLED(CONFIG_NFC_MRVL_I2C)
+ { "reset", "reset-n-io", "marvell,nfc-i2c" },
+#endif
+#if IS_ENABLED(CONFIG_NFC_MRVL_SPI)
+ { "reset", "reset-n-io", "marvell,nfc-spi" },
+#endif
+#if IS_ENABLED(CONFIG_NFC_MRVL_UART)
+ { "reset", "reset-n-io", "marvell,nfc-uart" },
+ { "reset", "reset-n-io", "mrvl,nfc-uart" },
+#endif
+#if !IS_ENABLED(CONFIG_PCI_LANTIQ)
+ /* MIPS Lantiq PCI */
+ { "reset", "gpios-reset", "lantiq,pci-xway" },
+#endif
- /* Allow this specifically for Freescale and PPC devices */
- if (!of_device_is_compatible(np, "fsl,spi") &&
- !of_device_is_compatible(np, "aeroflexgaisler,spictrl") &&
- !of_device_is_compatible(np, "ibm,ppc4xx-spi"))
- return ERR_PTR(-ENOENT);
- /* Allow only if asking for "cs-gpios" */
- if (!con_id || strcmp(con_id, "cs"))
- return ERR_PTR(-ENOENT);
+ /*
+ * Some regulator bindings happened before we managed to
+ * establish that GPIO properties should be named
+ * "foo-gpios" so we have this special kludge for them.
+ */
+#if IS_ENABLED(CONFIG_REGULATOR_ARIZONA_LDO1)
+ { "wlf,ldoena", NULL, NULL }, /* Arizona */
+#endif
+#if IS_ENABLED(CONFIG_REGULATOR_WM8994)
+ { "wlf,ldo1ena", NULL, NULL }, /* WM8994 */
+ { "wlf,ldo2ena", NULL, NULL }, /* WM8994 */
+#endif
- /*
- * While all other SPI controllers use "cs-gpios" the Freescale
- * uses just "gpios" so translate to that when "cs-gpios" is
- * requested.
- */
- return of_get_named_gpiod_flags(np, "gpios", idx, of_flags);
-}
+#if IS_ENABLED(CONFIG_SND_SOC_CS42L56)
+ { "reset", "cirrus,gpio-nreset", "cirrus,cs42l56" },
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_TLV320AIC3X)
+ { "reset", "gpio-reset", "ti,tlv320aic3x" },
+ { "reset", "gpio-reset", "ti,tlv320aic33" },
+ { "reset", "gpio-reset", "ti,tlv320aic3007" },
+ { "reset", "gpio-reset", "ti,tlv320aic3104" },
+ { "reset", "gpio-reset", "ti,tlv320aic3106" },
+#endif
+#if IS_ENABLED(CONFIG_SPI_GPIO)
+ /*
+ * The SPI GPIO bindings happened before we managed to
+ * establish that GPIO properties should be named
+ * "foo-gpios" so we have this special kludge for them.
+ */
+ { "miso", "gpio-miso", "spi-gpio" },
+ { "mosi", "gpio-mosi", "spi-gpio" },
+ { "sck", "gpio-sck", "spi-gpio" },
+#endif
-/*
- * Some regulator bindings happened before we managed to establish that GPIO
- * properties should be named "foo-gpios" so we have this special kludge for
- * them.
- */
-static struct gpio_desc *of_find_regulator_gpio(struct device_node *np,
- const char *con_id,
- unsigned int idx,
- enum of_gpio_flags *of_flags)
-{
- /* These are the connection IDs we accept as legacy GPIO phandles */
- const char *whitelist[] = {
- "wlf,ldoena", /* Arizona */
- "wlf,ldo1ena", /* WM8994 */
- "wlf,ldo2ena", /* WM8994 */
- };
- int i;
+ /*
+ * The old Freescale bindings use simply "gpios" as name
+ * for the chip select lines rather than "cs-gpios" like
+ * all other SPI hardware. Allow this specifically for
+ * Freescale and PPC devices.
+ */
+#if IS_ENABLED(CONFIG_SPI_FSL_SPI)
+ { "cs", "gpios", "fsl,spi" },
+ { "cs", "gpios", "aeroflexgaisler,spictrl" },
+#endif
+#if IS_ENABLED(CONFIG_SPI_PPC4xx)
+ { "cs", "gpios", "ibm,ppc4xx-spi" },
+#endif
- if (!IS_ENABLED(CONFIG_REGULATOR))
- return ERR_PTR(-ENOENT);
+#if IS_ENABLED(CONFIG_TYPEC_FUSB302)
+ /*
+ * Fairchild FUSB302 host is using undocumented "fcs,int_n"
+ * property without the compulsory "-gpios" suffix.
+ */
+ { "fcs,int_n", NULL, "fcs,fusb302" },
+#endif
+ };
+ struct gpio_desc *desc;
+ const char *legacy_id;
+ unsigned int i;
if (!con_id)
return ERR_PTR(-ENOENT);
- i = match_string(whitelist, ARRAY_SIZE(whitelist), con_id);
- if (i < 0)
- return ERR_PTR(-ENOENT);
+ for (i = 0; i < ARRAY_SIZE(gpios); i++) {
+ if (strcmp(con_id, gpios[i].con_id))
+ continue;
+
+ if (gpios[i].compatible &&
+ !of_device_is_compatible(np, gpios[i].compatible))
+ continue;
+
+ legacy_id = gpios[i].legacy_id ?: gpios[i].con_id;
+ desc = of_get_named_gpiod_flags(np, legacy_id, idx, of_flags);
+ if (!gpiod_not_found(desc)) {
+ pr_info("%s uses legacy gpio name '%s' instead of '%s-gpios'\n",
+ of_node_full_name(np), legacy_id, con_id);
+ return desc;
+ }
+ }
- return of_get_named_gpiod_flags(np, con_id, idx, of_flags);
+ return ERR_PTR(-ENOENT);
}
-static struct gpio_desc *of_find_arizona_gpio(struct device_node *np,
- const char *con_id,
- unsigned int idx,
- enum of_gpio_flags *of_flags)
+static struct gpio_desc *of_find_mt2701_gpio(struct device_node *np,
+ const char *con_id,
+ unsigned int idx,
+ enum of_gpio_flags *of_flags)
{
- if (!IS_ENABLED(CONFIG_MFD_ARIZONA))
- return ERR_PTR(-ENOENT);
+ struct gpio_desc *desc;
+ const char *legacy_id;
- if (!con_id || strcmp(con_id, "wlf,reset"))
+ if (!IS_ENABLED(CONFIG_SND_SOC_MT2701_CS42448))
return ERR_PTR(-ENOENT);
- return of_get_named_gpiod_flags(np, con_id, idx, of_flags);
-}
+ if (!of_device_is_compatible(np, "mediatek,mt2701-cs42448-machine"))
+ return ERR_PTR(-ENOENT);
-static struct gpio_desc *of_find_usb_gpio(struct device_node *np,
- const char *con_id,
- unsigned int idx,
- enum of_gpio_flags *of_flags)
-{
- /*
- * Currently this USB quirk is only for the Fairchild FUSB302 host
- * which is using an undocumented DT GPIO line named "fcs,int_n"
- * without the compulsory "-gpios" suffix.
- */
- if (!IS_ENABLED(CONFIG_TYPEC_FUSB302))
+ if (!con_id || strcmp(con_id, "i2s1-in-sel"))
return ERR_PTR(-ENOENT);
- if (!con_id || strcmp(con_id, "fcs,int_n"))
+ if (idx == 0)
+ legacy_id = "i2s1-in-sel-gpio1";
+ else if (idx == 1)
+ legacy_id = "i2s1-in-sel-gpio2";
+ else
return ERR_PTR(-ENOENT);
- return of_get_named_gpiod_flags(np, con_id, idx, of_flags);
+ desc = of_get_named_gpiod_flags(np, legacy_id, 0, of_flags);
+ if (!gpiod_not_found(desc))
+ pr_info("%s is using legacy gpio name '%s' instead of '%s-gpios'\n",
+ of_node_full_name(np), legacy_id, con_id);
+
+ return desc;
}
typedef struct gpio_desc *(*of_find_gpio_quirk)(struct device_node *np,
@@ -493,15 +600,12 @@ typedef struct gpio_desc *(*of_find_gpio_quirk)(struct device_node *np,
unsigned int idx,
enum of_gpio_flags *of_flags);
static const of_find_gpio_quirk of_find_gpio_quirks[] = {
- of_find_spi_gpio,
- of_find_spi_cs_gpio,
- of_find_regulator_gpio,
- of_find_arizona_gpio,
- of_find_usb_gpio,
+ of_find_gpio_rename,
+ of_find_mt2701_gpio,
NULL
};
-struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
+struct gpio_desc *of_find_gpio(struct device_node *np, const char *con_id,
unsigned int idx, unsigned long *flags)
{
char prop_name[32]; /* 32 is max size of property name */
@@ -519,8 +623,7 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
snprintf(prop_name, sizeof(prop_name), "%s",
gpio_suffixes[i]);
- desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx,
- &of_flags);
+ desc = of_get_named_gpiod_flags(np, prop_name, idx, &of_flags);
if (!gpiod_not_found(desc))
break;
@@ -528,7 +631,7 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
/* Properly named GPIO was not found, try workarounds */
for (q = of_find_gpio_quirks; gpiod_not_found(desc) && *q; q++)
- desc = (*q)(dev->of_node, con_id, idx, &of_flags);
+ desc = (*q)(np, con_id, idx, &of_flags);
if (IS_ERR(desc))
return desc;
@@ -831,8 +934,8 @@ int of_mm_gpiochip_add_data(struct device_node *np,
if (mm_gc->save_regs)
mm_gc->save_regs(mm_gc);
- of_node_put(mm_gc->gc.of_node);
- mm_gc->gc.of_node = of_node_get(np);
+ fwnode_handle_put(mm_gc->gc.fwnode);
+ mm_gc->gc.fwnode = fwnode_handle_get(of_fwnode_handle(np));
ret = gpiochip_add_data(gc, data);
if (ret)
@@ -858,37 +961,12 @@ void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc)
{
struct gpio_chip *gc = &mm_gc->gc;
- if (!mm_gc)
- return;
-
gpiochip_remove(gc);
iounmap(mm_gc->regs);
kfree(gc->label);
}
EXPORT_SYMBOL_GPL(of_mm_gpiochip_remove);
-static void of_gpiochip_init_valid_mask(struct gpio_chip *chip)
-{
- int len, i;
- u32 start, count;
- struct device_node *np = chip->of_node;
-
- len = of_property_count_u32_elems(np, "gpio-reserved-ranges");
- if (len < 0 || len % 2 != 0)
- return;
-
- for (i = 0; i < len; i += 2) {
- of_property_read_u32_index(np, "gpio-reserved-ranges",
- i, &start);
- of_property_read_u32_index(np, "gpio-reserved-ranges",
- i + 1, &count);
- if (start >= chip->ngpio || start + count > chip->ngpio)
- continue;
-
- bitmap_clear(chip->valid_mask, start, count);
- }
-};
-
#ifdef CONFIG_PINCTRL
static int of_gpiochip_add_pin_range(struct gpio_chip *chip)
{
@@ -982,9 +1060,11 @@ static int of_gpiochip_add_pin_range(struct gpio_chip *chip) { return 0; }
int of_gpiochip_add(struct gpio_chip *chip)
{
+ struct device_node *np;
int ret;
- if (!chip->of_node)
+ np = to_of_node(dev_fwnode(&chip->gpiodev->dev));
+ if (!np)
return 0;
if (!chip->of_xlate) {
@@ -995,24 +1075,22 @@ int of_gpiochip_add(struct gpio_chip *chip)
if (chip->of_gpio_n_cells > MAX_PHANDLE_ARGS)
return -EINVAL;
- of_gpiochip_init_valid_mask(chip);
-
ret = of_gpiochip_add_pin_range(chip);
if (ret)
return ret;
- of_node_get(chip->of_node);
+ fwnode_handle_get(chip->fwnode);
ret = of_gpiochip_scan_gpios(chip);
if (ret)
- of_node_put(chip->of_node);
+ fwnode_handle_put(chip->fwnode);
return ret;
}
void of_gpiochip_remove(struct gpio_chip *chip)
{
- of_node_put(chip->of_node);
+ fwnode_handle_put(chip->fwnode);
}
void of_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev)
diff --git a/drivers/gpio/gpiolib-of.h b/drivers/gpio/gpiolib-of.h
index 1b5df39a952e..a6c593e6766c 100644
--- a/drivers/gpio/gpiolib-of.h
+++ b/drivers/gpio/gpiolib-of.h
@@ -16,17 +16,16 @@ struct gpio_desc;
struct gpio_device;
#ifdef CONFIG_OF_GPIO
-struct gpio_desc *of_find_gpio(struct device *dev,
+struct gpio_desc *of_find_gpio(struct device_node *np,
const char *con_id,
unsigned int idx,
unsigned long *lookupflags);
int of_gpiochip_add(struct gpio_chip *gc);
void of_gpiochip_remove(struct gpio_chip *gc);
int of_gpio_get_count(struct device *dev, const char *con_id);
-bool of_gpio_need_valid_mask(const struct gpio_chip *gc);
void of_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev);
#else
-static inline struct gpio_desc *of_find_gpio(struct device *dev,
+static inline struct gpio_desc *of_find_gpio(struct device_node *np,
const char *con_id,
unsigned int idx,
unsigned long *lookupflags)
@@ -39,10 +38,6 @@ static inline int of_gpio_get_count(struct device *dev, const char *con_id)
{
return 0;
}
-static inline bool of_gpio_need_valid_mask(const struct gpio_chip *gc)
-{
- return false;
-}
static inline void of_gpio_dev_init(struct gpio_chip *gc,
struct gpio_device *gdev)
{
diff --git a/drivers/gpio/gpiolib-swnode.c b/drivers/gpio/gpiolib-swnode.c
new file mode 100644
index 000000000000..dd9ccac214d1
--- /dev/null
+++ b/drivers/gpio/gpiolib-swnode.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Software Node helpers for the GPIO API
+ *
+ * Copyright 2022 Google LLC
+ */
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/kernel.h>
+#include <linux/printk.h>
+#include <linux/property.h>
+#include <linux/string.h>
+
+#include "gpiolib.h"
+#include "gpiolib-swnode.h"
+
+static void swnode_format_propname(const char *con_id, char *propname,
+ size_t max_size)
+{
+ /*
+ * Note we do not need to try both -gpios and -gpio suffixes,
+ * as, unlike OF and ACPI, we can fix software nodes to conform
+ * to the proper binding.
+ */
+ if (con_id)
+ snprintf(propname, max_size, "%s-gpios", con_id);
+ else
+ strscpy(propname, "gpios", max_size);
+}
+
+static int swnode_gpiochip_match_name(struct gpio_chip *chip, void *data)
+{
+ return !strcmp(chip->label, data);
+}
+
+static struct gpio_chip *swnode_get_chip(struct fwnode_handle *fwnode)
+{
+ const struct software_node *chip_node;
+ struct gpio_chip *chip;
+
+ chip_node = to_software_node(fwnode);
+ if (!chip_node || !chip_node->name)
+ return ERR_PTR(-EINVAL);
+
+ chip = gpiochip_find((void *)chip_node->name, swnode_gpiochip_match_name);
+ return chip ?: ERR_PTR(-EPROBE_DEFER);
+}
+
+struct gpio_desc *swnode_find_gpio(struct fwnode_handle *fwnode,
+ const char *con_id, unsigned int idx,
+ unsigned long *flags)
+{
+ const struct software_node *swnode;
+ struct fwnode_reference_args args;
+ struct gpio_chip *chip;
+ struct gpio_desc *desc;
+ char propname[32]; /* 32 is max size of property name */
+ int error;
+
+ swnode = to_software_node(fwnode);
+ if (!swnode)
+ return ERR_PTR(-EINVAL);
+
+ swnode_format_propname(con_id, propname, sizeof(propname));
+
+ /*
+ * We expect all swnode-described GPIOs have GPIO number and
+ * polarity arguments, hence nargs is set to 2.
+ */
+ error = fwnode_property_get_reference_args(fwnode, propname, NULL, 2, idx, &args);
+ if (error) {
+ pr_debug("%s: can't parse '%s' property of node '%pfwP[%d]'\n",
+ __func__, propname, fwnode, idx);
+ return ERR_PTR(error);
+ }
+
+ chip = swnode_get_chip(args.fwnode);
+ fwnode_handle_put(args.fwnode);
+ if (IS_ERR(chip))
+ return ERR_CAST(chip);
+
+ desc = gpiochip_get_desc(chip, args.args[0]);
+ *flags = args.args[1]; /* We expect native GPIO flags */
+
+ pr_debug("%s: parsed '%s' property of node '%pfwP[%d]' - status (%d)\n",
+ __func__, propname, fwnode, idx, PTR_ERR_OR_ZERO(desc));
+
+ return desc;
+}
+
+/**
+ * swnode_gpio_count - count the GPIOs associated with a device / function
+ * @fwnode: firmware node of the GPIO consumer, can be %NULL for
+ * system-global GPIOs
+ * @con_id: function within the GPIO consumer
+ *
+ * Return:
+ * The number of GPIOs associated with a device / function or %-ENOENT,
+ * if no GPIO has been assigned to the requested function.
+ */
+int swnode_gpio_count(const struct fwnode_handle *fwnode, const char *con_id)
+{
+ struct fwnode_reference_args args;
+ char propname[32];
+ int count;
+
+ swnode_format_propname(con_id, propname, sizeof(propname));
+
+ /*
+ * This is not very efficient, but GPIO lists usually have only
+ * 1 or 2 entries.
+ */
+ count = 0;
+ while (fwnode_property_get_reference_args(fwnode, propname, NULL, 0,
+ count, &args) == 0) {
+ fwnode_handle_put(args.fwnode);
+ count++;
+ }
+
+ return count ?: -ENOENT;
+}
diff --git a/drivers/gpio/gpiolib-swnode.h b/drivers/gpio/gpiolib-swnode.h
new file mode 100644
index 000000000000..af849e56f6bc
--- /dev/null
+++ b/drivers/gpio/gpiolib-swnode.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef GPIOLIB_SWNODE_H
+#define GPIOLIB_SWNODE_H
+
+struct fwnode_handle;
+struct gpio_desc;
+
+struct gpio_desc *swnode_find_gpio(struct fwnode_handle *fwnode,
+ const char *con_id, unsigned int idx,
+ unsigned long *flags);
+int swnode_gpio_count(const struct fwnode_handle *fwnode, const char *con_id);
+
+#endif /* GPIOLIB_SWNODE_H */
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index a70522aef355..5a66d9616d7c 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -26,6 +26,7 @@
#include "gpiolib.h"
#include "gpiolib-of.h"
#include "gpiolib-acpi.h"
+#include "gpiolib-swnode.h"
#include "gpiolib-cdev.h"
#include "gpiolib-sysfs.h"
@@ -183,14 +184,14 @@ EXPORT_SYMBOL_GPL(gpiod_to_chip);
static int gpiochip_find_base(int ngpio)
{
struct gpio_device *gdev;
- int base = ARCH_NR_GPIOS - ngpio;
+ int base = GPIO_DYNAMIC_BASE;
- list_for_each_entry_reverse(gdev, &gpio_devices, list) {
+ list_for_each_entry(gdev, &gpio_devices, list) {
/* found a free space? */
- if (gdev->base + gdev->ngpio <= base)
+ if (gdev->base >= base + ngpio)
break;
- /* nope, check the space right before the chip */
- base = gdev->base - ngpio;
+ /* nope, check the space right after the chip */
+ base = gdev->base + gdev->ngpio;
}
if (gpio_is_valid(base)) {
@@ -366,12 +367,12 @@ static int gpiochip_set_desc_names(struct gpio_chip *gc)
static int devprop_gpiochip_set_names(struct gpio_chip *chip)
{
struct gpio_device *gdev = chip->gpiodev;
- struct fwnode_handle *fwnode = dev_fwnode(&gdev->dev);
+ struct device *dev = &gdev->dev;
const char **names;
int ret, i;
int count;
- count = fwnode_property_string_array_count(fwnode, "gpio-line-names");
+ count = device_property_string_array_count(dev, "gpio-line-names");
if (count < 0)
return 0;
@@ -384,7 +385,7 @@ static int devprop_gpiochip_set_names(struct gpio_chip *chip)
* gpiochips.
*/
if (count <= chip->offset) {
- dev_warn(&gdev->dev, "gpio-line-names too short (length %d), cannot map names for the gpiochip at offset %u\n",
+ dev_warn(dev, "gpio-line-names too short (length %d), cannot map names for the gpiochip at offset %u\n",
count, chip->offset);
return 0;
}
@@ -393,10 +394,10 @@ static int devprop_gpiochip_set_names(struct gpio_chip *chip)
if (!names)
return -ENOMEM;
- ret = fwnode_property_read_string_array(fwnode, "gpio-line-names",
+ ret = device_property_read_string_array(dev, "gpio-line-names",
names, count);
if (ret < 0) {
- dev_warn(&gdev->dev, "failed to read GPIO line names\n");
+ dev_warn(dev, "failed to read GPIO line names\n");
kfree(names);
return ret;
}
@@ -445,9 +446,22 @@ static unsigned long *gpiochip_allocate_mask(struct gpio_chip *gc)
return p;
}
+static unsigned int gpiochip_count_reserved_ranges(struct gpio_chip *gc)
+{
+ struct device *dev = &gc->gpiodev->dev;
+ int size;
+
+ /* Format is "start, count, ..." */
+ size = device_property_count_u32(dev, "gpio-reserved-ranges");
+ if (size > 0 && size % 2 == 0)
+ return size;
+
+ return 0;
+}
+
static int gpiochip_alloc_valid_mask(struct gpio_chip *gc)
{
- if (!(of_gpio_need_valid_mask(gc) || gc->init_valid_mask))
+ if (!(gpiochip_count_reserved_ranges(gc) || gc->init_valid_mask))
return 0;
gc->valid_mask = gpiochip_allocate_mask(gc);
@@ -457,8 +471,50 @@ static int gpiochip_alloc_valid_mask(struct gpio_chip *gc)
return 0;
}
+static int gpiochip_apply_reserved_ranges(struct gpio_chip *gc)
+{
+ struct device *dev = &gc->gpiodev->dev;
+ unsigned int size;
+ u32 *ranges;
+ int ret;
+
+ size = gpiochip_count_reserved_ranges(gc);
+ if (size == 0)
+ return 0;
+
+ ranges = kmalloc_array(size, sizeof(*ranges), GFP_KERNEL);
+ if (!ranges)
+ return -ENOMEM;
+
+ ret = device_property_read_u32_array(dev, "gpio-reserved-ranges",
+ ranges, size);
+ if (ret) {
+ kfree(ranges);
+ return ret;
+ }
+
+ while (size) {
+ u32 count = ranges[--size];
+ u32 start = ranges[--size];
+
+ if (start >= gc->ngpio || start + count > gc->ngpio)
+ continue;
+
+ bitmap_clear(gc->valid_mask, start, count);
+ }
+
+ kfree(ranges);
+ return 0;
+}
+
static int gpiochip_init_valid_mask(struct gpio_chip *gc)
{
+ int ret;
+
+ ret = gpiochip_apply_reserved_ranges(gc);
+ if (ret)
+ return ret;
+
if (gc->init_valid_mask)
return gc->init_valid_mask(gc,
gc->valid_mask,
@@ -493,7 +549,7 @@ EXPORT_SYMBOL_GPL(gpiochip_line_is_valid);
static void gpiodevice_release(struct device *dev)
{
- struct gpio_device *gdev = container_of(dev, struct gpio_device, dev);
+ struct gpio_device *gdev = to_gpio_device(dev);
unsigned long flags;
spin_lock_irqsave(&gpio_lock, flags);
@@ -627,7 +683,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
* Assign fwnode depending on the result of the previous calls,
* if none of them succeed, assign it to the parent's one.
*/
- gdev->dev.fwnode = dev_fwnode(&gdev->dev) ?: fwnode;
+ gc->fwnode = gdev->dev.fwnode = dev_fwnode(&gdev->dev) ?: fwnode;
gdev->id = ida_alloc(&gpio_ida, GFP_KERNEL);
if (gdev->id < 0) {
@@ -719,6 +775,9 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
* a poison instead.
*/
gc->base = base;
+ } else {
+ dev_warn(&gdev->dev,
+ "Static allocation of GPIO base is deprecated, use dynamic allocation.\n");
}
gdev->base = base;
@@ -735,6 +794,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
spin_unlock_irqrestore(&gpio_lock, flags);
BLOCKING_INIT_NOTIFIER_HEAD(&gdev->notifier);
+ init_rwsem(&gdev->sem);
#ifdef CONFIG_PINCTRL
INIT_LIST_HEAD(&gdev->pin_ranges);
@@ -875,6 +935,8 @@ void gpiochip_remove(struct gpio_chip *gc)
unsigned long flags;
unsigned int i;
+ down_write(&gdev->sem);
+
/* FIXME: should the legacy sysfs handling be moved to gpio_device? */
gpiochip_sysfs_unregister(gdev);
gpiochip_free_hogs(gc);
@@ -909,6 +971,7 @@ void gpiochip_remove(struct gpio_chip *gc)
* gone.
*/
gcdev_unregister(gdev);
+ up_write(&gdev->sem);
put_device(&gdev->dev);
}
EXPORT_SYMBOL_GPL(gpiochip_remove);
@@ -3808,62 +3871,88 @@ static int platform_gpio_count(struct device *dev, const char *con_id)
return count;
}
-/**
- * fwnode_get_named_gpiod - obtain a GPIO from firmware node
- * @fwnode: handle of the firmware node
- * @propname: name of the firmware property representing the GPIO
- * @index: index of the GPIO to obtain for the consumer
- * @dflags: GPIO initialization flags
- * @label: label to attach to the requested GPIO
- *
- * This function can be used for drivers that get their configuration
- * from opaque firmware.
- *
- * The function properly finds the corresponding GPIO using whatever is the
- * underlying firmware interface and then makes sure that the GPIO
- * descriptor is requested before it is returned to the caller.
- *
- * Returns:
- * On successful request the GPIO pin is configured in accordance with
- * provided @dflags.
- *
- * In case of error an ERR_PTR() is returned.
- */
-static struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
- const char *propname, int index,
- enum gpiod_flags dflags,
- const char *label)
+static struct gpio_desc *gpiod_find_by_fwnode(struct fwnode_handle *fwnode,
+ struct device *consumer,
+ const char *con_id,
+ unsigned int idx,
+ enum gpiod_flags *flags,
+ unsigned long *lookupflags)
{
- unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
- struct gpio_desc *desc = ERR_PTR(-ENODEV);
- int ret;
+ struct gpio_desc *desc = ERR_PTR(-ENOENT);
if (is_of_node(fwnode)) {
- desc = gpiod_get_from_of_node(to_of_node(fwnode),
- propname, index,
- dflags,
- label);
- return desc;
+ dev_dbg(consumer, "using DT '%pfw' for '%s' GPIO lookup\n",
+ fwnode, con_id);
+ desc = of_find_gpio(to_of_node(fwnode), con_id, idx, lookupflags);
} else if (is_acpi_node(fwnode)) {
- struct acpi_gpio_info info;
+ dev_dbg(consumer, "using ACPI '%pfw' for '%s' GPIO lookup\n",
+ fwnode, con_id);
+ desc = acpi_find_gpio(fwnode, con_id, idx, flags, lookupflags);
+ } else if (is_software_node(fwnode)) {
+ dev_dbg(consumer, "using swnode '%pfw' for '%s' GPIO lookup\n",
+ fwnode, con_id);
+ desc = swnode_find_gpio(fwnode, con_id, idx, lookupflags);
+ }
- desc = acpi_node_get_gpiod(fwnode, propname, index, &info);
- if (IS_ERR(desc))
- return desc;
+ return desc;
+}
- acpi_gpio_update_gpiod_flags(&dflags, &info);
- acpi_gpio_update_gpiod_lookup_flags(&lflags, &info);
- } else {
- return ERR_PTR(-EINVAL);
+static struct gpio_desc *gpiod_find_and_request(struct device *consumer,
+ struct fwnode_handle *fwnode,
+ const char *con_id,
+ unsigned int idx,
+ enum gpiod_flags flags,
+ const char *label,
+ bool platform_lookup_allowed)
+{
+ struct gpio_desc *desc = ERR_PTR(-ENOENT);
+ unsigned long lookupflags;
+ int ret;
+
+ if (!IS_ERR_OR_NULL(fwnode))
+ desc = gpiod_find_by_fwnode(fwnode, consumer, con_id, idx,
+ &flags, &lookupflags);
+
+ if (gpiod_not_found(desc) && platform_lookup_allowed) {
+ /*
+ * Either we are not using DT or ACPI, or their lookup did not
+ * return a result. In that case, use platform lookup as a
+ * fallback.
+ */
+ dev_dbg(consumer, "using lookup tables for GPIO lookup\n");
+ desc = gpiod_find(consumer, con_id, idx, &lookupflags);
}
- /* Currently only ACPI takes this path */
+ if (IS_ERR(desc)) {
+ dev_dbg(consumer, "No GPIO consumer %s found\n", con_id);
+ return desc;
+ }
+
+ /*
+ * If a connection label was passed use that, else attempt to use
+ * the device name as label
+ */
ret = gpiod_request(desc, label);
- if (ret)
- return ERR_PTR(ret);
+ if (ret) {
+ if (!(ret == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
+ return ERR_PTR(ret);
+
+ /*
+ * This happens when there are several consumers for
+ * the same GPIO line: we just return here without
+ * further initialization. It is a bit of a hack.
+ * This is necessary to support fixed regulators.
+ *
+ * FIXME: Make this more sane and safe.
+ */
+ dev_info(consumer,
+ "nonexclusive access to GPIO for %s\n", con_id);
+ return desc;
+ }
- ret = gpiod_configure_flags(desc, propname, lflags, dflags);
+ ret = gpiod_configure_flags(desc, con_id, lookupflags, flags);
if (ret < 0) {
+ dev_dbg(consumer, "setup of GPIO %s failed\n", con_id);
gpiod_put(desc);
return ERR_PTR(ret);
}
@@ -3896,29 +3985,12 @@ static struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
* In case of error an ERR_PTR() is returned.
*/
struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode,
- const char *con_id, int index,
+ const char *con_id,
+ int index,
enum gpiod_flags flags,
const char *label)
{
- struct gpio_desc *desc;
- char prop_name[32]; /* 32 is max size of property name */
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
- if (con_id)
- snprintf(prop_name, sizeof(prop_name), "%s-%s",
- con_id, gpio_suffixes[i]);
- else
- snprintf(prop_name, sizeof(prop_name), "%s",
- gpio_suffixes[i]);
-
- desc = fwnode_get_named_gpiod(fwnode, prop_name, index, flags,
- label);
- if (!gpiod_not_found(desc))
- break;
- }
-
- return desc;
+ return gpiod_find_and_request(NULL, fwnode, con_id, index, flags, label, false);
}
EXPORT_SYMBOL_GPL(fwnode_gpiod_get_index);
@@ -3937,6 +4009,8 @@ int gpiod_count(struct device *dev, const char *con_id)
count = of_gpio_get_count(dev, con_id);
else if (is_acpi_node(fwnode))
count = acpi_gpio_count(dev, con_id);
+ else if (is_software_node(fwnode))
+ count = swnode_gpio_count(fwnode, con_id);
if (count < 0)
count = platform_gpio_count(dev, con_id);
@@ -4072,70 +4146,11 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
unsigned int idx,
enum gpiod_flags flags)
{
- unsigned long lookupflags = GPIO_LOOKUP_FLAGS_DEFAULT;
- struct gpio_desc *desc = NULL;
- int ret;
- /* Maybe we have a device name, maybe not */
+ struct fwnode_handle *fwnode = dev ? dev_fwnode(dev) : NULL;
const char *devname = dev ? dev_name(dev) : "?";
- const struct fwnode_handle *fwnode = dev ? dev_fwnode(dev) : NULL;
-
- dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id);
-
- /* Using device tree? */
- if (is_of_node(fwnode)) {
- dev_dbg(dev, "using device tree for GPIO lookup\n");
- desc = of_find_gpio(dev, con_id, idx, &lookupflags);
- } else if (is_acpi_node(fwnode)) {
- dev_dbg(dev, "using ACPI for GPIO lookup\n");
- desc = acpi_find_gpio(dev, con_id, idx, &flags, &lookupflags);
- }
-
- /*
- * Either we are not using DT or ACPI, or their lookup did not return
- * a result. In that case, use platform lookup as a fallback.
- */
- if (!desc || gpiod_not_found(desc)) {
- dev_dbg(dev, "using lookup tables for GPIO lookup\n");
- desc = gpiod_find(dev, con_id, idx, &lookupflags);
- }
-
- if (IS_ERR(desc)) {
- dev_dbg(dev, "No GPIO consumer %s found\n", con_id);
- return desc;
- }
-
- /*
- * If a connection label was passed use that, else attempt to use
- * the device name as label
- */
- ret = gpiod_request(desc, con_id ?: devname);
- if (ret) {
- if (!(ret == -EBUSY && flags & GPIOD_FLAGS_BIT_NONEXCLUSIVE))
- return ERR_PTR(ret);
-
- /*
- * This happens when there are several consumers for
- * the same GPIO line: we just return here without
- * further initialization. It is a bit of a hack.
- * This is necessary to support fixed regulators.
- *
- * FIXME: Make this more sane and safe.
- */
- dev_info(dev, "nonexclusive access to GPIO for %s\n", con_id ?: devname);
- return desc;
- }
-
- ret = gpiod_configure_flags(desc, con_id, lookupflags, flags);
- if (ret < 0) {
- dev_dbg(dev, "setup of GPIO %s failed\n", con_id);
- gpiod_put(desc);
- return ERR_PTR(ret);
- }
+ const char *label = con_id ?: devname;
- blocking_notifier_call_chain(&desc->gdev->notifier,
- GPIOLINE_CHANGED_REQUESTED, desc);
-
- return desc;
+ return gpiod_find_and_request(dev, fwnode, con_id, idx, flags, label, true);
}
EXPORT_SYMBOL_GPL(gpiod_get_index);
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index d900ecdbac46..b3c2db6eba80 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -15,14 +15,15 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/cdev.h>
+#include <linux/rwsem.h>
#define GPIOCHIP_NAME "gpiochip"
/**
* struct gpio_device - internal state container for GPIO devices
- * @id: numerical ID number for the GPIO chip
* @dev: the GPIO device struct
* @chrdev: character device for the GPIO device
+ * @id: numerical ID number for the GPIO chip
* @mockdev: class device used by the deprecated sysfs interface (may be
* NULL)
* @owner: helps prevent removal of modules exporting active GPIOs
@@ -39,6 +40,9 @@
* @list: links gpio_device:s together for traversal
* @notifier: used to notify subscribers about lines being requested, released
* or reconfigured
+ * @sem: protects the structure from a NULL-pointer dereference of @chip by
+ * user-space operations when the device gets unregistered during
+ * a hot-unplug event
* @pin_ranges: range of pins served by the GPIO driver
*
* This state container holds most of the runtime variable data
@@ -47,9 +51,9 @@
* userspace.
*/
struct gpio_device {
- int id;
struct device dev;
struct cdev chrdev;
+ int id;
struct device *mockdev;
struct module *owner;
struct gpio_chip *chip;
@@ -60,6 +64,7 @@ struct gpio_device {
void *data;
struct list_head list;
struct blocking_notifier_head notifier;
+ struct rw_semaphore sem;
#ifdef CONFIG_PINCTRL
/*
@@ -72,6 +77,11 @@ struct gpio_device {
#endif
};
+static inline struct gpio_device *to_gpio_device(struct device *dev)
+{
+ return container_of(dev, struct gpio_device, dev);
+}
+
/* gpio suffixes used for ACPI and device tree lookup */
static __maybe_unused const char * const gpio_suffixes[] = { "gpios", "gpio" };
diff --git a/drivers/leds/blink/leds-lgm-sso.c b/drivers/leds/blink/leds-lgm-sso.c
index 6f270c0272fb..35c61311e7fd 100644
--- a/drivers/leds/blink/leds-lgm-sso.c
+++ b/drivers/leds/blink/leds-lgm-sso.c
@@ -635,9 +635,8 @@ __sso_led_dt_parse(struct sso_led_priv *priv, struct fwnode_handle *fw_ssoled)
led->priv = priv;
desc = &led->desc;
- led->gpiod = devm_fwnode_get_gpiod_from_child(dev, NULL,
- fwnode_child,
- GPIOD_ASIS, NULL);
+ led->gpiod = devm_fwnode_gpiod_get(dev, fwnode_child, NULL,
+ GPIOD_ASIS, NULL);
if (IS_ERR(led->gpiod)) {
ret = dev_err_probe(dev, PTR_ERR(led->gpiod), "led: get gpio fail!\n");
goto __dt_err;
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index 092eb59a7d32..ce4e79939731 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -151,9 +151,8 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
* will be updated after LED class device is registered,
* Only then the final LED name is known.
*/
- led.gpiod = devm_fwnode_get_gpiod_from_child(dev, NULL, child,
- GPIOD_ASIS,
- NULL);
+ led.gpiod = devm_fwnode_gpiod_get(dev, child, NULL, GPIOD_ASIS,
+ NULL);
if (IS_ERR(led.gpiod)) {
fwnode_handle_put(child);
return ERR_CAST(led.gpiod);