summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-10-08 09:46:29 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2022-10-08 09:46:29 -0700
commitf01603979a4afaad7504a728918b678d572cda9e (patch)
treec88ced8221cbc6eba9e1ea8a421d7cae7c9f8cd5 /drivers
parent3002b7a31894cfa0e57080f7e0961b5fee788aa3 (diff)
parent3c92506d86785967fd7e7933e04491b9276c2f00 (diff)
downloadlinux-f01603979a4afaad7504a728918b678d572cda9e.tar.gz
linux-f01603979a4afaad7504a728918b678d572cda9e.tar.bz2
linux-f01603979a4afaad7504a728918b678d572cda9e.zip
Merge tag 'gpio-updates-for-v6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux
Pull gpio updates from Bartosz Golaszewski: "We have a single new driver, support for a bunch of new models, improvements in drivers and core gpiolib code as well device-tree bindings changes. Summary: New driver: - IMX System Controller Unit GPIOs GPIO core: - add fdinfo output for the GPIO character device file descriptors (allows user-space to determine which processes own which GPIO lines) - improvements to OF GPIO code - new quirk for Asus UM325UAZ in gpiolib-acpi - new quirk for Freescale SPI in gpiolib-of Driver improvements: - add a new macro that reduces the amount of boilerplate code in ISA drivers and use it in relevant drivers - support two new models in gpio-pca953x - support new model in gpio-f7188x - convert more drivers to use immutable irq chips - other minor tweaks Device-tree bindings: - add DT bindings for gpio-imx-scu - convert Xilinx GPIO bindings to YAML - reference the properties from the SPI peripheral device-tree bindings instead of providing custom ones in the GPIO controller document - add parsing of GPIO hog nodes to the DT bindings for gpio-mpfs-gpio - relax the node name requirements in gpio-stmpe - add new models for gpio-rcar and gpio-pxa95xx - add a new vendor prefix: Diodes (for Diodes, Inc.) Misc: - pulled in the immutable branch from the x86 platform drivers tree including support for a new simatic board that depends on GPIO changes" * tag 'gpio-updates-for-v6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (36 commits) gpio: tc3589x: Make irqchip immutable gpiolib: cdev: add fdinfo output for line request file descriptors gpio: twl4030: Reorder functions which allows to drop a forward declaraion gpiolib: fix OOB access in quirk callbacks gpiolib: of: factor out conversion from OF flags gpiolib: rework quirk handling in of_find_gpio() gpiolib: of: make Freescale SPI quirk similar to all others gpiolib: of: do not ignore requested index when applying quirks gpio: ws16c48: Ensure number of irq matches number of base gpio: 104-idio-16: Ensure number of irq matches number of base gpio: 104-idi-48: Ensure number of irq matches number of base gpio: 104-dio-48e: Ensure number of irq matches number of base counter: 104-quad-8: Ensure number of irq matches number of base isa: Introduce the module_isa_driver_with_irq helper macro gpio: pca953x: Add support for PCAL6534 gpio: pca953x: Swap if statements to save later complexity gpio: pca953x: Fix pca953x_gpio_set_pull_up_down() dt-bindings: gpio: pca95xx: add entry for pcal6534 and PI4IOE5V6534Q dt-bindings: vendor-prefixes: add Diodes gpio: mt7621: Switch to use platform_get_irq() function ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/counter/104-quad-8.c5
-rw-r--r--drivers/gpio/Kconfig4
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-104-dio-48e.c5
-rw-r--r--drivers/gpio/gpio-104-idi-48.c5
-rw-r--r--drivers/gpio/gpio-104-idio-16.c5
-rw-r--r--drivers/gpio/gpio-exar.c40
-rw-r--r--drivers/gpio/gpio-imx-scu.c139
-rw-r--r--drivers/gpio/gpio-mt7621.c7
-rw-r--r--drivers/gpio/gpio-pca953x.c177
-rw-r--r--drivers/gpio/gpio-rockchip.c21
-rw-r--r--drivers/gpio/gpio-tc3589x.c8
-rw-r--r--drivers/gpio/gpio-twl4030.c26
-rw-r--r--drivers/gpio/gpio-ucb1400.c1
-rw-r--r--drivers/gpio/gpio-ws16c48.c5
-rw-r--r--drivers/gpio/gpiolib-acpi.c38
-rw-r--r--drivers/gpio/gpiolib-cdev.c18
-rw-r--r--drivers/gpio/gpiolib-of.c184
-rw-r--r--drivers/gpio/gpiolib.c132
19 files changed, 553 insertions, 268 deletions
diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c
index 1188673d8521..77a863b7eefe 100644
--- a/drivers/counter/104-quad-8.c
+++ b/drivers/counter/104-quad-8.c
@@ -28,7 +28,8 @@ module_param_hw_array(base, uint, ioport, &num_quad8, 0);
MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");
static unsigned int irq[max_num_isa_dev(QUAD8_EXTENT)];
-module_param_hw_array(irq, uint, irq, NULL, 0);
+static unsigned int num_irq;
+module_param_hw_array(irq, uint, irq, &num_irq, 0);
MODULE_PARM_DESC(irq, "ACCES 104-QUAD-8 interrupt line numbers");
#define QUAD8_NUM_COUNTERS 8
@@ -1271,7 +1272,7 @@ static struct isa_driver quad8_driver = {
}
};
-module_isa_driver(quad8_driver, num_quad8);
+module_isa_driver_with_irq(quad8_driver, num_quad8, num_irq);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
MODULE_DESCRIPTION("ACCES 104-QUAD-8 driver");
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 3f64345fe40b..ed9e71d6713e 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -341,6 +341,10 @@ config GPIO_ICH
If unsure, say N.
+config GPIO_IMX_SCU
+ def_bool y
+ depends on IMX_SCU
+
config GPIO_IOP
tristate "Intel IOP GPIO"
depends on ARCH_IOP32X || COMPILE_TEST
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index a0985d30f51b..b67e29d348cf 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -70,6 +70,7 @@ 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_IDT3243X) += gpio-idt3243x.o
+obj-$(CONFIG_GPIO_IMX_SCU) += gpio-imx-scu.o
obj-$(CONFIG_GPIO_IOP) += gpio-iop.o
obj-$(CONFIG_GPIO_IT87) += gpio-it87.o
obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o
diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c
index 74cc71bb3984..7b8829c8e423 100644
--- a/drivers/gpio/gpio-104-dio-48e.c
+++ b/drivers/gpio/gpio-104-dio-48e.c
@@ -34,7 +34,8 @@ module_param_hw_array(base, uint, ioport, &num_dio48e, 0);
MODULE_PARM_DESC(base, "ACCES 104-DIO-48E base addresses");
static unsigned int irq[MAX_NUM_DIO48E];
-module_param_hw_array(irq, uint, irq, NULL, 0);
+static unsigned int num_irq;
+module_param_hw_array(irq, uint, irq, &num_irq, 0);
MODULE_PARM_DESC(irq, "ACCES 104-DIO-48E interrupt line numbers");
#define DIO48E_NUM_PPI 2
@@ -362,7 +363,7 @@ static struct isa_driver dio48e_driver = {
.name = "104-dio-48e"
},
};
-module_isa_driver(dio48e_driver, num_dio48e);
+module_isa_driver_with_irq(dio48e_driver, num_dio48e, num_irq);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
MODULE_DESCRIPTION("ACCES 104-DIO-48E GPIO driver");
diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c
index 3286b914a2cf..c5e231fde1af 100644
--- a/drivers/gpio/gpio-104-idi-48.c
+++ b/drivers/gpio/gpio-104-idi-48.c
@@ -34,7 +34,8 @@ module_param_hw_array(base, uint, ioport, &num_idi_48, 0);
MODULE_PARM_DESC(base, "ACCES 104-IDI-48 base addresses");
static unsigned int irq[MAX_NUM_IDI_48];
-module_param_hw_array(irq, uint, irq, NULL, 0);
+static unsigned int num_irq;
+module_param_hw_array(irq, uint, irq, &num_irq, 0);
MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers");
/**
@@ -304,7 +305,7 @@ static struct isa_driver idi_48_driver = {
.name = "104-idi-48"
},
};
-module_isa_driver(idi_48_driver, num_idi_48);
+module_isa_driver_with_irq(idi_48_driver, num_idi_48, num_irq);
MODULE_AUTHOR("William Breathitt Gray <vilhelm.gray@gmail.com>");
MODULE_DESCRIPTION("ACCES 104-IDI-48 GPIO driver");
diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c
index 4756e583f223..718bd54e2a25 100644
--- a/drivers/gpio/gpio-104-idio-16.c
+++ b/drivers/gpio/gpio-104-idio-16.c
@@ -30,7 +30,8 @@ module_param_hw_array(base, uint, ioport, &num_idio_16, 0);
MODULE_PARM_DESC(base, "ACCES 104-IDIO-16 base addresses");
static unsigned int irq[MAX_NUM_IDIO_16];
-module_param_hw_array(irq, uint, irq, NULL, 0);
+static unsigned int num_irq;
+module_param_hw_array(irq, uint, irq, &num_irq, 0);
MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers");
/**
@@ -337,7 +338,7 @@ static struct isa_driver idio_16_driver = {
},
};
-module_isa_driver(idio_16_driver, num_idio_16);
+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");
diff --git a/drivers/gpio/gpio-exar.c b/drivers/gpio/gpio-exar.c
index d37de78247a6..482f678c893e 100644
--- a/drivers/gpio/gpio-exar.c
+++ b/drivers/gpio/gpio-exar.c
@@ -21,6 +21,12 @@
#define EXAR_OFFSET_MPIOLVL_HI 0x96
#define EXAR_OFFSET_MPIOSEL_HI 0x99
+/*
+ * The Device Configuration and UART Configuration Registers
+ * for each UART channel take 1KB of memory address space.
+ */
+#define EXAR_UART_CHANNEL_SIZE 0x400
+
#define DRIVER_NAME "gpio_exar"
static DEFINE_IDA(ida_index);
@@ -31,26 +37,39 @@ struct exar_gpio_chip {
int index;
char name[20];
unsigned int first_pin;
+ /*
+ * The offset to the cascaded device's (if existing)
+ * Device Configuration Registers.
+ */
+ unsigned int cascaded_offset;
};
static unsigned int
exar_offset_to_sel_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset)
{
- return (offset + exar_gpio->first_pin) / 8 ? EXAR_OFFSET_MPIOSEL_HI
- : EXAR_OFFSET_MPIOSEL_LO;
+ unsigned int pin = exar_gpio->first_pin + (offset % 16);
+ unsigned int cascaded = offset / 16;
+ unsigned int addr = pin / 8 ? EXAR_OFFSET_MPIOSEL_HI : EXAR_OFFSET_MPIOSEL_LO;
+
+ return addr + (cascaded ? exar_gpio->cascaded_offset : 0);
}
static unsigned int
exar_offset_to_lvl_addr(struct exar_gpio_chip *exar_gpio, unsigned int offset)
{
- return (offset + exar_gpio->first_pin) / 8 ? EXAR_OFFSET_MPIOLVL_HI
- : EXAR_OFFSET_MPIOLVL_LO;
+ unsigned int pin = exar_gpio->first_pin + (offset % 16);
+ unsigned int cascaded = offset / 16;
+ unsigned int addr = pin / 8 ? EXAR_OFFSET_MPIOLVL_HI : EXAR_OFFSET_MPIOLVL_LO;
+
+ return addr + (cascaded ? exar_gpio->cascaded_offset : 0);
}
static unsigned int
exar_offset_to_bit(struct exar_gpio_chip *exar_gpio, unsigned int offset)
{
- return (offset + exar_gpio->first_pin) % 8;
+ unsigned int pin = exar_gpio->first_pin + (offset % 16);
+
+ return pin % 8;
}
static int exar_get_direction(struct gpio_chip *chip, unsigned int offset)
@@ -154,6 +173,17 @@ static int gpio_exar_probe(struct platform_device *pdev)
return -ENOMEM;
/*
+ * If cascaded, secondary xr17v354 or xr17v358 have the same amount
+ * of MPIOs as their primaries and the last 4 bits of the primary's
+ * PCI Device ID is the number of its UART channels.
+ */
+ if (pcidev->device & GENMASK(15, 12)) {
+ ngpios += ngpios;
+ exar_gpio->cascaded_offset = (pcidev->device & GENMASK(3, 0)) *
+ EXAR_UART_CHANNEL_SIZE;
+ }
+
+ /*
* We don't need to check the return values of mmio regmap operations (unless
* the regmap has a clock attached which is not the case here).
*/
diff --git a/drivers/gpio/gpio-imx-scu.c b/drivers/gpio/gpio-imx-scu.c
new file mode 100644
index 000000000000..17be21b8f3b7
--- /dev/null
+++ b/drivers/gpio/gpio-imx-scu.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2021~2022 NXP
+ *
+ * The driver exports a standard gpiochip interface
+ * to control the PIN resources on SCU domain.
+ */
+
+#include <linux/module.h>
+#include <linux/gpio/driver.h>
+#include <linux/platform_device.h>
+#include <linux/firmware/imx/svc/rm.h>
+#include <dt-bindings/firmware/imx/rsrc.h>
+
+struct scu_gpio_priv {
+ struct gpio_chip chip;
+ struct mutex lock;
+ struct device *dev;
+ struct imx_sc_ipc *handle;
+};
+
+static unsigned int scu_rsrc_arr[] = {
+ IMX_SC_R_BOARD_R0,
+ IMX_SC_R_BOARD_R1,
+ IMX_SC_R_BOARD_R2,
+ IMX_SC_R_BOARD_R3,
+ IMX_SC_R_BOARD_R4,
+ IMX_SC_R_BOARD_R5,
+ IMX_SC_R_BOARD_R6,
+ IMX_SC_R_BOARD_R7,
+};
+
+static int imx_scu_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct scu_gpio_priv *priv = gpiochip_get_data(chip);
+ int level;
+ int err;
+
+ if (offset >= chip->ngpio)
+ return -EINVAL;
+
+ mutex_lock(&priv->lock);
+
+ /* to read PIN state via scu api */
+ err = imx_sc_misc_get_control(priv->handle,
+ scu_rsrc_arr[offset], 0, &level);
+ mutex_unlock(&priv->lock);
+
+ if (err) {
+ dev_err(priv->dev, "SCU get failed: %d\n", err);
+ return err;
+ }
+
+ return level;
+}
+
+static void imx_scu_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+{
+ struct scu_gpio_priv *priv = gpiochip_get_data(chip);
+ int err;
+
+ if (offset >= chip->ngpio)
+ return;
+
+ mutex_lock(&priv->lock);
+
+ /* to set PIN output level via scu api */
+ err = imx_sc_misc_set_control(priv->handle,
+ scu_rsrc_arr[offset], 0, value);
+ mutex_unlock(&priv->lock);
+
+ if (err)
+ dev_err(priv->dev, "SCU set (%d) failed: %d\n",
+ scu_rsrc_arr[offset], err);
+}
+
+static int imx_scu_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
+{
+ if (offset >= chip->ngpio)
+ return -EINVAL;
+
+ return GPIO_LINE_DIRECTION_OUT;
+}
+
+static int imx_scu_gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct scu_gpio_priv *priv;
+ struct gpio_chip *gc;
+ int ret;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ ret = imx_scu_get_handle(&priv->handle);
+ if (ret)
+ return ret;
+
+ priv->dev = dev;
+ mutex_init(&priv->lock);
+
+ gc = &priv->chip;
+ gc->base = -1;
+ gc->parent = dev;
+ gc->ngpio = sizeof(scu_rsrc_arr)/sizeof(unsigned int);
+ gc->label = dev_name(dev);
+ gc->get = imx_scu_gpio_get;
+ gc->set = imx_scu_gpio_set;
+ gc->get_direction = imx_scu_gpio_get_direction;
+
+ platform_set_drvdata(pdev, priv);
+
+ return devm_gpiochip_add_data(dev, gc, priv);
+}
+
+static const struct of_device_id imx_scu_gpio_dt_ids[] = {
+ { .compatible = "fsl,imx8qxp-sc-gpio" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver imx_scu_gpio_driver = {
+ .driver = {
+ .name = "gpio-imx-scu",
+ .of_match_table = imx_scu_gpio_dt_ids,
+ },
+ .probe = imx_scu_gpio_probe,
+};
+
+static int __init _imx_scu_gpio_init(void)
+{
+ return platform_driver_register(&imx_scu_gpio_driver);
+}
+
+subsys_initcall_sync(_imx_scu_gpio_init);
+
+MODULE_AUTHOR("Shenwei Wang <shenwei.wang@nxp.com>");
+MODULE_DESCRIPTION("NXP GPIO over IMX SCU API");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-mt7621.c b/drivers/gpio/gpio-mt7621.c
index f163f5ca857b..93facbebb80e 100644
--- a/drivers/gpio/gpio-mt7621.c
+++ b/drivers/gpio/gpio-mt7621.c
@@ -9,7 +9,6 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
@@ -299,7 +298,6 @@ static int
mediatek_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
struct mtk *mtk;
int i;
int ret;
@@ -312,7 +310,10 @@ mediatek_gpio_probe(struct platform_device *pdev)
if (IS_ERR(mtk->base))
return PTR_ERR(mtk->base);
- mtk->gpio_irq = irq_of_parse_and_map(np, 0);
+ mtk->gpio_irq = platform_get_irq(pdev, 0);
+ if (mtk->gpio_irq < 0)
+ return mtk->gpio_irq;
+
mtk->dev = dev;
platform_set_drvdata(pdev, mtk);
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index cf9bf3fcaee2..ebe1943b85dd 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -66,6 +66,7 @@
#define PCA_LATCH_INT (PCA_PCAL | PCA_INT)
#define PCA953X_TYPE BIT(12)
#define PCA957X_TYPE BIT(13)
+#define PCAL653X_TYPE BIT(14)
#define PCA_TYPE_MASK GENMASK(15, 12)
#define PCA_CHIP_TYPE(x) ((x) & PCA_TYPE_MASK)
@@ -89,8 +90,10 @@ static const struct i2c_device_id pca953x_id[] = {
{ "pca9575", 16 | PCA957X_TYPE | PCA_INT, },
{ "pca9698", 40 | PCA953X_TYPE, },
+ { "pcal6408", 8 | PCA953X_TYPE | PCA_LATCH_INT, },
{ "pcal6416", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
{ "pcal6524", 24 | PCA953X_TYPE | PCA_LATCH_INT, },
+ { "pcal6534", 34 | PCAL653X_TYPE | PCA_LATCH_INT, },
{ "pcal9535", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
{ "pcal9554b", 8 | PCA953X_TYPE | PCA_LATCH_INT, },
{ "pcal9555a", 16 | PCA953X_TYPE | PCA_LATCH_INT, },
@@ -211,6 +214,10 @@ struct pca953x_chip {
struct regulator *regulator;
const struct pca953x_reg_config *regs;
+
+ u8 (*recalc_addr)(struct pca953x_chip *chip, int reg, int off);
+ bool (*check_reg)(struct pca953x_chip *chip, unsigned int reg,
+ u32 checkbank);
};
static int pca953x_bank_shift(struct pca953x_chip *chip)
@@ -288,18 +295,67 @@ static bool pca953x_check_register(struct pca953x_chip *chip, unsigned int reg,
return true;
}
+/*
+ * Unfortunately, whilst the PCAL6534 chip (and compatibles) broadly follow the
+ * same register layout as the PCAL6524, the spacing of the registers has been
+ * fundamentally altered by compacting them and thus does not obey the same
+ * rules, including being able to use bit shifting to determine bank. These
+ * chips hence need special handling here.
+ */
+static bool pcal6534_check_register(struct pca953x_chip *chip, unsigned int reg,
+ u32 checkbank)
+{
+ int bank;
+ int offset;
+
+ if (reg >= 0x30) {
+ /*
+ * Reserved block between 14h and 2Fh does not align on
+ * expected bank boundaries like other devices.
+ */
+ int temp = reg - 0x30;
+
+ bank = temp / NBANK(chip);
+ offset = temp - (bank * NBANK(chip));
+ bank += 8;
+ } else if (reg >= 0x54) {
+ /*
+ * Handle lack of reserved registers after output port
+ * configuration register to form a bank.
+ */
+ int temp = reg - 0x54;
+
+ bank = temp / NBANK(chip);
+ offset = temp - (bank * NBANK(chip));
+ bank += 16;
+ } else {
+ bank = reg / NBANK(chip);
+ offset = reg - (bank * NBANK(chip));
+ }
+
+ /* Register is not in the matching bank. */
+ if (!(BIT(bank) & checkbank))
+ return false;
+
+ /* Register is not within allowed range of bank. */
+ if (offset >= NBANK(chip))
+ return false;
+
+ return true;
+}
+
static bool pca953x_readable_register(struct device *dev, unsigned int reg)
{
struct pca953x_chip *chip = dev_get_drvdata(dev);
u32 bank;
- if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE) {
- bank = PCA953x_BANK_INPUT | PCA953x_BANK_OUTPUT |
- PCA953x_BANK_POLARITY | PCA953x_BANK_CONFIG;
- } else {
+ if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) {
bank = PCA957x_BANK_INPUT | PCA957x_BANK_OUTPUT |
PCA957x_BANK_POLARITY | PCA957x_BANK_CONFIG |
PCA957x_BANK_BUSHOLD;
+ } else {
+ bank = PCA953x_BANK_INPUT | PCA953x_BANK_OUTPUT |
+ PCA953x_BANK_POLARITY | PCA953x_BANK_CONFIG;
}
if (chip->driver_data & PCA_PCAL) {
@@ -308,7 +364,7 @@ static bool pca953x_readable_register(struct device *dev, unsigned int reg)
PCAL9xxx_BANK_IRQ_STAT;
}
- return pca953x_check_register(chip, reg, bank);
+ return chip->check_reg(chip, reg, bank);
}
static bool pca953x_writeable_register(struct device *dev, unsigned int reg)
@@ -316,19 +372,19 @@ static bool pca953x_writeable_register(struct device *dev, unsigned int reg)
struct pca953x_chip *chip = dev_get_drvdata(dev);
u32 bank;
- if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE) {
- bank = PCA953x_BANK_OUTPUT | PCA953x_BANK_POLARITY |
- PCA953x_BANK_CONFIG;
- } else {
+ if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) {
bank = PCA957x_BANK_OUTPUT | PCA957x_BANK_POLARITY |
PCA957x_BANK_CONFIG | PCA957x_BANK_BUSHOLD;
+ } else {
+ bank = PCA953x_BANK_OUTPUT | PCA953x_BANK_POLARITY |
+ PCA953x_BANK_CONFIG;
}
if (chip->driver_data & PCA_PCAL)
bank |= PCAL9xxx_BANK_IN_LATCH | PCAL9xxx_BANK_PULL_EN |
PCAL9xxx_BANK_PULL_SEL | PCAL9xxx_BANK_IRQ_MASK;
- return pca953x_check_register(chip, reg, bank);
+ return chip->check_reg(chip, reg, bank);
}
static bool pca953x_volatile_register(struct device *dev, unsigned int reg)
@@ -336,15 +392,15 @@ static bool pca953x_volatile_register(struct device *dev, unsigned int reg)
struct pca953x_chip *chip = dev_get_drvdata(dev);
u32 bank;
- if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE)
- bank = PCA953x_BANK_INPUT;
- else
+ if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE)
bank = PCA957x_BANK_INPUT;
+ else
+ bank = PCA953x_BANK_INPUT;
if (chip->driver_data & PCA_PCAL)
bank |= PCAL9xxx_BANK_IRQ_STAT;
- return pca953x_check_register(chip, reg, bank);
+ return chip->check_reg(chip, reg, bank);
}
static const struct regmap_config pca953x_i2c_regmap = {
@@ -389,9 +445,42 @@ static u8 pca953x_recalc_addr(struct pca953x_chip *chip, int reg, int off)
return regaddr;
}
+/*
+ * The PCAL6534 and compatible chips have altered bank alignment that doesn't
+ * fit within the bit shifting scheme used for other devices.
+ */
+static u8 pcal6534_recalc_addr(struct pca953x_chip *chip, int reg, int off)
+{
+ int addr;
+ int pinctrl;
+
+ addr = (reg & PCAL_GPIO_MASK) * NBANK(chip);
+
+ switch (reg) {
+ case PCAL953X_OUT_STRENGTH:
+ case PCAL953X_IN_LATCH:
+ case PCAL953X_PULL_EN:
+ case PCAL953X_PULL_SEL:
+ case PCAL953X_INT_MASK:
+ case PCAL953X_INT_STAT:
+ case PCAL953X_OUT_CONF:
+ pinctrl = ((reg & PCAL_PINCTRL_MASK) >> 1) + 0x20;
+ break;
+ case PCAL6524_INT_EDGE:
+ case PCAL6524_INT_CLR:
+ case PCAL6524_IN_STATUS:
+ case PCAL6524_OUT_INDCONF:
+ case PCAL6524_DEBOUNCE:
+ pinctrl = ((reg & PCAL_PINCTRL_MASK) >> 1) + 0x1c;
+ break;
+ }
+
+ return pinctrl + addr + (off / BANK_SZ);
+}
+
static int pca953x_write_regs(struct pca953x_chip *chip, int reg, unsigned long *val)
{
- u8 regaddr = pca953x_recalc_addr(chip, reg, 0);
+ u8 regaddr = chip->recalc_addr(chip, reg, 0);
u8 value[MAX_BANK];
int i, ret;
@@ -409,7 +498,7 @@ static int pca953x_write_regs(struct pca953x_chip *chip, int reg, unsigned long
static int pca953x_read_regs(struct pca953x_chip *chip, int reg, unsigned long *val)
{
- u8 regaddr = pca953x_recalc_addr(chip, reg, 0);
+ u8 regaddr = chip->recalc_addr(chip, reg, 0);
u8 value[MAX_BANK];
int i, ret;
@@ -428,7 +517,7 @@ static int pca953x_read_regs(struct pca953x_chip *chip, int reg, unsigned long *
static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
{
struct pca953x_chip *chip = gpiochip_get_data(gc);
- u8 dirreg = pca953x_recalc_addr(chip, chip->regs->direction, off);
+ u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off);
u8 bit = BIT(off % BANK_SZ);
int ret;
@@ -442,8 +531,8 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
unsigned off, int val)
{
struct pca953x_chip *chip = gpiochip_get_data(gc);
- u8 dirreg = pca953x_recalc_addr(chip, chip->regs->direction, off);
- u8 outreg = pca953x_recalc_addr(chip, chip->regs->output, off);
+ u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off);
+ u8 outreg = chip->recalc_addr(chip, chip->regs->output, off);
u8 bit = BIT(off % BANK_SZ);
int ret;
@@ -463,7 +552,7 @@ exit:
static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
{
struct pca953x_chip *chip = gpiochip_get_data(gc);
- u8 inreg = pca953x_recalc_addr(chip, chip->regs->input, off);
+ u8 inreg = chip->recalc_addr(chip, chip->regs->input, off);
u8 bit = BIT(off % BANK_SZ);
u32 reg_val;
int ret;
@@ -480,7 +569,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
{
struct pca953x_chip *chip = gpiochip_get_data(gc);
- u8 outreg = pca953x_recalc_addr(chip, chip->regs->output, off);
+ u8 outreg = chip->recalc_addr(chip, chip->regs->output, off);
u8 bit = BIT(off % BANK_SZ);
mutex_lock(&chip->i2c_lock);
@@ -491,7 +580,7 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off)
{
struct pca953x_chip *chip = gpiochip_get_data(gc);
- u8 dirreg = pca953x_recalc_addr(chip, chip->regs->direction, off);
+ u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off);
u8 bit = BIT(off % BANK_SZ);
u32 reg_val;
int ret;
@@ -548,8 +637,10 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip,
unsigned int offset,
unsigned long config)
{
- u8 pull_en_reg = pca953x_recalc_addr(chip, PCAL953X_PULL_EN, offset);
- u8 pull_sel_reg = pca953x_recalc_addr(chip, PCAL953X_PULL_SEL, offset);
+ enum pin_config_param param = pinconf_to_config_param(config);
+
+ u8 pull_en_reg = chip->recalc_addr(chip, PCAL953X_PULL_EN, offset);
+ u8 pull_sel_reg = chip->recalc_addr(chip, PCAL953X_PULL_SEL, offset);
u8 bit = BIT(offset % BANK_SZ);
int ret;
@@ -563,9 +654,9 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip,
mutex_lock(&chip->i2c_lock);
/* Configure pull-up/pull-down */
- if (config == PIN_CONFIG_BIAS_PULL_UP)
+ if (param == PIN_CONFIG_BIAS_PULL_UP)
ret = regmap_write_bits(chip->regmap, pull_sel_reg, bit, bit);
- else if (config == PIN_CONFIG_BIAS_PULL_DOWN)
+ else if (param == PIN_CONFIG_BIAS_PULL_DOWN)
ret = regmap_write_bits(chip->regmap, pull_sel_reg, bit, 0);
else
ret = 0;
@@ -573,7 +664,7 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip,
goto exit;
/* Disable/Enable pull-up/pull-down */
- if (config == PIN_CONFIG_BIAS_DISABLE)
+ if (param == PIN_CONFIG_BIAS_DISABLE)
ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, 0);
else
ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, bit);
@@ -912,13 +1003,13 @@ static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert)
u8 regaddr;
int ret;
- regaddr = pca953x_recalc_addr(chip, chip->regs->output, 0);
+ regaddr = chip->recalc_addr(chip, chip->regs->output, 0);
ret = regcache_sync_region(chip->regmap, regaddr,
regaddr + NBANK(chip) - 1);
if (ret)
goto out;
- regaddr = pca953x_recalc_addr(chip, chip->regs->direction, 0);
+ regaddr = chip->recalc_addr(chip, chip->regs->direction, 0);
ret = regcache_sync_region(chip->regmap, regaddr,
regaddr + NBANK(chip) - 1);
if (ret)
@@ -1037,6 +1128,14 @@ static int pca953x_probe(struct i2c_client *client,
regmap_config = &pca953x_i2c_regmap;
}
+ if (PCA_CHIP_TYPE(chip->driver_data) == PCAL653X_TYPE) {
+ chip->recalc_addr = pcal6534_recalc_addr;
+ chip->check_reg = pcal6534_check_register;
+ } else {
+ chip->recalc_addr = pca953x_recalc_addr;
+ chip->check_reg = pca953x_check_register;
+ }
+
chip->regmap = devm_regmap_init_i2c(client, regmap_config);
if (IS_ERR(chip->regmap)) {
ret = PTR_ERR(chip->regmap);
@@ -1068,13 +1167,12 @@ static int pca953x_probe(struct i2c_client *client,
/* initialize cached registers from their original values.
* we can't share this chip with another i2c master.
*/
-
- if (PCA_CHIP_TYPE(chip->driver_data) == PCA953X_TYPE) {
- chip->regs = &pca953x_regs;
- ret = device_pca95xx_init(chip, invert);
- } else {
+ if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) {
chip->regs = &pca957x_regs;
ret = device_pca957x_init(chip, invert);
+ } else {
+ chip->regs = &pca953x_regs;
+ ret = device_pca95xx_init(chip, invert);
}
if (ret)
goto err_exit;
@@ -1125,14 +1223,14 @@ static int pca953x_regcache_sync(struct device *dev)
* The ordering between direction and output is important,
* sync these registers first and only then sync the rest.
*/
- regaddr = pca953x_recalc_addr(chip, chip->regs->direction, 0);
+ regaddr = chip->recalc_addr(chip, chip->regs->direction, 0);
ret = regcache_sync_region(chip->regmap, regaddr, regaddr + NBANK(chip) - 1);
if (ret) {
dev_err(dev, "Failed to sync GPIO dir registers: %d\n", ret);
return ret;
}
- regaddr = pca953x_recalc_addr(chip, chip->regs->output, 0);
+ regaddr = chip->recalc_addr(chip, chip->regs->output, 0);
ret = regcache_sync_region(chip->regmap, regaddr, regaddr + NBANK(chip) - 1);
if (ret) {
dev_err(dev, "Failed to sync GPIO out registers: %d\n", ret);
@@ -1141,7 +1239,7 @@ static int pca953x_regcache_sync(struct device *dev)
#ifdef CONFIG_GPIO_PCA953X_IRQ
if (chip->driver_data & PCA_PCAL) {
- regaddr = pca953x_recalc_addr(chip, PCAL953X_IN_LATCH, 0);
+ regaddr = chip->recalc_addr(chip, PCAL953X_IN_LATCH, 0);
ret = regcache_sync_region(chip->regmap, regaddr,
regaddr + NBANK(chip) - 1);
if (ret) {
@@ -1150,7 +1248,7 @@ static int pca953x_regcache_sync(struct device *dev)
return ret;
}
- regaddr = pca953x_recalc_addr(chip, PCAL953X_INT_MASK, 0);
+ regaddr = chip->recalc_addr(chip, PCAL953X_INT_MASK, 0);
ret = regcache_sync_region(chip->regmap, regaddr,
regaddr + NBANK(chip) - 1);
if (ret) {
@@ -1214,6 +1312,7 @@ static int pca953x_resume(struct device *dev)
#endif
/* convenience to stop overlong match-table lines */
+#define OF_653X(__nrgpio, __int) ((void *)(__nrgpio | PCAL653X_TYPE | __int))
#define OF_953X(__nrgpio, __int) (void *)(__nrgpio | PCA953X_TYPE | __int)
#define OF_957X(__nrgpio, __int) (void *)(__nrgpio | PCA957X_TYPE | __int)
@@ -1236,8 +1335,10 @@ static const struct of_device_id pca953x_dt_ids[] = {
{ .compatible = "nxp,pca9575", .data = OF_957X(16, PCA_INT), },
{ .compatible = "nxp,pca9698", .data = OF_953X(40, 0), },
+ { .compatible = "nxp,pcal6408", .data = OF_953X(8, PCA_LATCH_INT), },
{ .compatible = "nxp,pcal6416", .data = OF_953X(16, PCA_LATCH_INT), },
{ .compatible = "nxp,pcal6524", .data = OF_953X(24, PCA_LATCH_INT), },
+ { .compatible = "nxp,pcal6534", .data = OF_653X(34, PCA_LATCH_INT), },
{ .compatible = "nxp,pcal9535", .data = OF_953X(16, PCA_LATCH_INT), },
{ .compatible = "nxp,pcal9554b", .data = OF_953X( 8, PCA_LATCH_INT), },
{ .compatible = "nxp,pcal9555a", .data = OF_953X(16, PCA_LATCH_INT), },
diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c
index bb50335239ac..6765477edb06 100644
--- a/drivers/gpio/gpio-rockchip.c
+++ b/drivers/gpio/gpio-rockchip.c
@@ -325,26 +325,15 @@ static void rockchip_irq_demux(struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
struct rockchip_pin_bank *bank = irq_desc_get_handler_data(desc);
- u32 pend;
+ unsigned long pending;
+ unsigned int irq;
dev_dbg(bank->dev, "got irq for bank %s\n", bank->name);
chained_irq_enter(chip, desc);
- pend = readl_relaxed(bank->reg_base + bank->gpio_regs->int_status);
-
- while (pend) {
- unsigned int irq, virq;
-
- irq = __ffs(pend);
- pend &= ~BIT(irq);
- virq = irq_find_mapping(bank->domain, irq);
-
- if (!virq) {
- dev_err(bank->dev, "unmapped irq %d\n", irq);
- continue;
- }
-
+ pending = readl_relaxed(bank->reg_base + bank->gpio_regs->int_status);
+ for_each_set_bit(irq, &pending, 32) {
dev_dbg(bank->dev, "handling irq %d\n", irq);
/*
@@ -378,7 +367,7 @@ static voi