diff options
Diffstat (limited to '')
23 files changed, 640 insertions, 154 deletions
diff --git a/Documentation/devicetree/bindings/gpio/atmel,at91rm9200-gpio.yaml b/Documentation/devicetree/bindings/gpio/atmel,at91rm9200-gpio.yaml index 3dd70933ed8e..d810043b56b6 100644 --- a/Documentation/devicetree/bindings/gpio/atmel,at91rm9200-gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/atmel,at91rm9200-gpio.yaml @@ -69,13 +69,13 @@ examples: #include <dt-bindings/interrupt-controller/irq.h> gpio@fffff400 { - compatible = "atmel,at91rm9200-gpio"; - reg = <0xfffff400 0x200>; - interrupts = <2 IRQ_TYPE_LEVEL_HIGH 1>; - #gpio-cells = <2>; - gpio-controller; - interrupt-controller; - #interrupt-cells = <2>; - clocks = <&pmc PMC_TYPE_PERIPHERAL 2>; + compatible = "atmel,at91rm9200-gpio"; + reg = <0xfffff400 0x200>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH 1>; + #gpio-cells = <2>; + gpio-controller; + interrupt-controller; + #interrupt-cells = <2>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 2>; }; ... diff --git a/Documentation/devicetree/bindings/gpio/blaize,blzp1600-gpio.yaml b/Documentation/devicetree/bindings/gpio/blaize,blzp1600-gpio.yaml new file mode 100644 index 000000000000..a05f6ea619c3 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/blaize,blzp1600-gpio.yaml @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpio/blaize,blzp1600-gpio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Blaize BLZP1600 GPIO controller + +description: + Blaize BLZP1600 GPIO controller is an implementation of the VeriSilicon + APB GPIO v0.2 IP block. It has 32 ports each of which are intended to be + represented as child nodes with the generic GPIO-controller properties + as described in this binding's file. + +maintainers: + - Nikolaos Pasaloukos <nikolaos.pasaloukos@blaize.com> + - James Cowgill <james.cowgill@blaize.com> + - Matt Redfearn <matt.redfearn@blaize.com> + - Neil Jones <neil.jones@blaize.com> + +properties: + $nodename: + pattern: "^gpio@[0-9a-f]+$" + + compatible: + enum: + - blaize,blzp1600-gpio + + reg: + maxItems: 1 + + gpio-controller: true + + '#gpio-cells': + const: 2 + + ngpios: + default: 32 + minimum: 1 + maximum: 32 + + interrupts: + maxItems: 1 + + gpio-line-names: true + + interrupt-controller: true + + '#interrupt-cells': + const: 2 + +required: + - compatible + - reg + - gpio-controller + - '#gpio-cells' + +dependencies: + interrupt-controller: [ interrupts ] + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + + gpio: gpio@4c0000 { + compatible = "blaize,blzp1600-gpio"; + reg = <0x004c0000 0x1000>; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; + }; +... diff --git a/Documentation/devicetree/bindings/gpio/fairchild,74hc595.yaml b/Documentation/devicetree/bindings/gpio/fairchild,74hc595.yaml index 0e5c22929bde..ab35bcf98101 100644 --- a/Documentation/devicetree/bindings/gpio/fairchild,74hc595.yaml +++ b/Documentation/devicetree/bindings/gpio/fairchild,74hc595.yaml @@ -71,15 +71,15 @@ unevaluatedProperties: false examples: - | spi { - #address-cells = <1>; - #size-cells = <0>; - - gpio5: gpio5@0 { - compatible = "fairchild,74hc595"; - reg = <0>; - gpio-controller; - #gpio-cells = <2>; - registers-number = <4>; - spi-max-frequency = <100000>; - }; + #address-cells = <1>; + #size-cells = <0>; + + gpio5@0 { + compatible = "fairchild,74hc595"; + reg = <0>; + gpio-controller; + #gpio-cells = <2>; + registers-number = <4>; + spi-max-frequency = <100000>; + }; }; diff --git a/Documentation/devicetree/bindings/gpio/gpio-mxs.yaml b/Documentation/devicetree/bindings/gpio/gpio-mxs.yaml index 8ff54369d16c..b58e08c8ecd8 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-mxs.yaml +++ b/Documentation/devicetree/bindings/gpio/gpio-mxs.yaml @@ -84,52 +84,52 @@ examples: reg = <0x80018000 0x2000>; gpio@0 { - compatible = "fsl,imx28-gpio"; - reg = <0>; - interrupts = <127>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; + compatible = "fsl,imx28-gpio"; + reg = <0>; + interrupts = <127>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; }; gpio@1 { - compatible = "fsl,imx28-gpio"; - reg = <1>; - interrupts = <126>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; + compatible = "fsl,imx28-gpio"; + reg = <1>; + interrupts = <126>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; }; gpio@2 { - compatible = "fsl,imx28-gpio"; - reg = <2>; - interrupts = <125>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; + compatible = "fsl,imx28-gpio"; + reg = <2>; + interrupts = <125>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; }; gpio@3 { - compatible = "fsl,imx28-gpio"; - reg = <3>; - interrupts = <124>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; + compatible = "fsl,imx28-gpio"; + reg = <3>; + interrupts = <124>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; }; gpio@4 { - compatible = "fsl,imx28-gpio"; - reg = <4>; - interrupts = <123>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; + compatible = "fsl,imx28-gpio"; + reg = <4>; + interrupts = <123>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; }; }; diff --git a/Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml b/Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml index 7b1eb08fa055..4d3f52f8d1b8 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml +++ b/Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml @@ -17,6 +17,9 @@ properties: compatible: oneOf: - items: + - const: toradex,ecgpiol16 + - const: nxp,pcal6416 + - items: - const: diodes,pi4ioe5v6534q - const: nxp,pcal6534 - items: @@ -132,6 +135,7 @@ allOf: - maxim,max7325 - maxim,max7326 - maxim,max7327 + - toradex,ecgpiol16 then: properties: reset-gpios: false diff --git a/Documentation/devicetree/bindings/gpio/nxp,pcf8575.yaml b/Documentation/devicetree/bindings/gpio/nxp,pcf8575.yaml index 8bca574bb66d..5a6ecaa7b44b 100644 --- a/Documentation/devicetree/bindings/gpio/nxp,pcf8575.yaml +++ b/Documentation/devicetree/bindings/gpio/nxp,pcf8575.yaml @@ -128,17 +128,17 @@ additionalProperties: false examples: - | i2c { - #address-cells = <1>; - #size-cells = <0>; - - pcf8575: gpio@20 { - compatible = "nxp,pcf8575"; - reg = <0x20>; - interrupt-parent = <&irqpin2>; - interrupts = <3 0>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; + #address-cells = <1>; + #size-cells = <0>; + + gpio@20 { + compatible = "nxp,pcf8575"; + reg = <0x20>; + interrupt-parent = <&irqpin2>; + interrupts = <3 0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; }; diff --git a/Documentation/devicetree/bindings/gpio/realtek,otto-gpio.yaml b/Documentation/devicetree/bindings/gpio/realtek,otto-gpio.yaml index 39fd959c45d2..728099c65824 100644 --- a/Documentation/devicetree/bindings/gpio/realtek,otto-gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/realtek,otto-gpio.yaml @@ -81,7 +81,7 @@ dependencies: examples: - | - gpio@3500 { + gpio@3500 { compatible = "realtek,rtl8380-gpio", "realtek,otto-gpio"; reg = <0x3500 0x1c>; gpio-controller; @@ -91,9 +91,9 @@ examples: #interrupt-cells = <2>; interrupt-parent = <&rtlintc>; interrupts = <23>; - }; + }; - | - gpio@3300 { + gpio@3300 { compatible = "realtek,rtl9300-gpio", "realtek,otto-gpio"; reg = <0x3300 0x1c>, <0x3338 0x8>; gpio-controller; @@ -103,6 +103,6 @@ examples: #interrupt-cells = <2>; interrupt-parent = <&rtlintc>; interrupts = <13>; - }; + }; ... diff --git a/Documentation/devicetree/bindings/gpio/renesas,em-gio.yaml b/Documentation/devicetree/bindings/gpio/renesas,em-gio.yaml index 8bdef812c87c..49fb8f613ead 100644 --- a/Documentation/devicetree/bindings/gpio/renesas,em-gio.yaml +++ b/Documentation/devicetree/bindings/gpio/renesas,em-gio.yaml @@ -57,14 +57,14 @@ examples: - | #include <dt-bindings/interrupt-controller/arm-gic.h> gpio0: gpio@e0050000 { - compatible = "renesas,em-gio"; - reg = <0xe0050000 0x2c>, <0xe0050040 0x20>; - interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>, - <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>; - gpio-controller; - #gpio-cells = <2>; - gpio-ranges = <&pfc 0 0 32>; - ngpios = <32>; - interrupt-controller; - #interrupt-cells = <2>; + compatible = "renesas,em-gio"; + reg = <0xe0050000 0x2c>, <0xe0050040 0x20>; + interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pfc 0 0 32>; + ngpios = <32>; + interrupt-controller; + #interrupt-cells = <2>; }; diff --git a/Documentation/devicetree/bindings/gpio/renesas,rcar-gpio.yaml b/Documentation/devicetree/bindings/gpio/renesas,rcar-gpio.yaml index cc7a950a6030..d32e103a64aa 100644 --- a/Documentation/devicetree/bindings/gpio/renesas,rcar-gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/renesas,rcar-gpio.yaml @@ -138,16 +138,16 @@ examples: #include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/power/r8a77470-sysc.h> gpio3: gpio@e6053000 { - compatible = "renesas,gpio-r8a77470", "renesas,rcar-gen2-gpio"; - reg = <0xe6053000 0x50>; - interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; - clocks = <&cpg CPG_MOD 909>; - power-domains = <&sysc R8A77470_PD_ALWAYS_ON>; - resets = <&cpg 909>; - gpio-controller; - #gpio-cells = <2>; - gpio-ranges = <&pfc 0 96 30>; - gpio-reserved-ranges = <17 10>; - interrupt-controller; - #interrupt-cells = <2>; + compatible = "renesas,gpio-r8a77470", "renesas,rcar-gen2-gpio"; + reg = <0xe6053000 0x50>; + interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 909>; + power-domains = <&sysc R8A77470_PD_ALWAYS_ON>; + resets = <&cpg 909>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pfc 0 96 30>; + gpio-reserved-ranges = <17 10>; + interrupt-controller; + #interrupt-cells = <2>; }; diff --git a/Documentation/devicetree/bindings/gpio/sifive,gpio.yaml b/Documentation/devicetree/bindings/gpio/sifive,gpio.yaml index fc095646adea..4bdc201b719e 100644 --- a/Documentation/devicetree/bindings/gpio/sifive,gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/sifive,gpio.yaml @@ -76,8 +76,8 @@ additionalProperties: false examples: - | - #include <dt-bindings/clock/sifive-fu540-prci.h> - gpio@10060000 { + #include <dt-bindings/clock/sifive-fu540-prci.h> + gpio@10060000 { compatible = "sifive,fu540-c000-gpio", "sifive,gpio0"; interrupt-parent = <&plic>; interrupts = <7>, <8>, <9>, <10>, <11>, <12>, <13>, <14>, <15>, <16>, @@ -88,6 +88,6 @@ examples: #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; - }; + }; ... diff --git a/Documentation/devicetree/bindings/gpio/toshiba,gpio-visconti.yaml b/Documentation/devicetree/bindings/gpio/toshiba,gpio-visconti.yaml index b085450b527f..712063417bc8 100644 --- a/Documentation/devicetree/bindings/gpio/toshiba,gpio-visconti.yaml +++ b/Documentation/devicetree/bindings/gpio/toshiba,gpio-visconti.yaml @@ -48,22 +48,22 @@ additionalProperties: false examples: - | - #include <dt-bindings/interrupt-controller/irq.h> - #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> - soc { + soc { #address-cells = <2>; #size-cells = <2>; gpio: gpio@28020000 { - compatible = "toshiba,gpio-tmpv7708"; - reg = <0 0x28020000 0 0x1000>; - #gpio-cells = <0x2>; - gpio-ranges = <&pmux 0 0 32>; - gpio-controller; - interrupt-controller; - #interrupt-cells = <2>; - interrupt-parent = <&gic>; + compatible = "toshiba,gpio-tmpv7708"; + reg = <0 0x28020000 0 0x1000>; + #gpio-cells = <0x2>; + gpio-ranges = <&pmux 0 0 32>; + gpio-controller; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; }; - }; + }; ... diff --git a/Documentation/devicetree/bindings/gpio/xlnx,gpio-xilinx.yaml b/Documentation/devicetree/bindings/gpio/xlnx,gpio-xilinx.yaml index d3d8a2e143ed..8fbf12ca067e 100644 --- a/Documentation/devicetree/bindings/gpio/xlnx,gpio-xilinx.yaml +++ b/Documentation/devicetree/bindings/gpio/xlnx,gpio-xilinx.yaml @@ -126,29 +126,29 @@ examples: - | #include <dt-bindings/interrupt-controller/arm-gic.h> - gpio@a0020000 { - compatible = "xlnx,xps-gpio-1.00.a"; - reg = <0xa0020000 0x10000>; - #gpio-cells = <2>; - #interrupt-cells = <0x2>; - clocks = <&zynqmp_clk 71>; - gpio-controller; - interrupt-controller; - interrupt-names = "ip2intc_irpt"; - interrupt-parent = <&gic>; - interrupts = <0 89 4>; - xlnx,all-inputs = <0x0>; - xlnx,all-inputs-2 = <0x0>; - xlnx,all-outputs = <0x0>; - xlnx,all-outputs-2 = <0x0>; - xlnx,dout-default = <0x0>; - xlnx,dout-default-2 = <0x0>; - xlnx,gpio-width = <0x20>; - xlnx,gpio2-width = <0x20>; - xlnx,interrupt-present = <0x1>; - xlnx,is-dual = <0x1>; - xlnx,tri-default = <0xFFFFFFFF>; - xlnx,tri-default-2 = <0xFFFFFFFF>; - }; + gpio@a0020000 { + compatible = "xlnx,xps-gpio-1.00.a"; + reg = <0xa0020000 0x10000>; + #gpio-cells = <2>; + #interrupt-cells = <0x2>; + clocks = <&zynqmp_clk 71>; + gpio-controller; + interrupt-controller; + interrupt-names = "ip2intc_irpt"; + interrupt-parent = <&gic>; + interrupts = <0 89 4>; + xlnx,all-inputs = <0x0>; + xlnx,all-inputs-2 = <0x0>; + xlnx,all-outputs = <0x0>; + xlnx,all-outputs-2 = <0x0>; + xlnx,dout-default = <0x0>; + xlnx,dout-default-2 = <0x0>; + xlnx,gpio-width = <0x20>; + xlnx,gpio2-width = <0x20>; + xlnx,interrupt-present = <0x1>; + xlnx,is-dual = <0x1>; + xlnx,tri-default = <0xFFFFFFFF>; + xlnx,tri-default-2 = <0xFFFFFFFF>; + }; ... diff --git a/MAINTAINERS b/MAINTAINERS index 96b827049501..e0a00b6ede3b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4195,6 +4195,16 @@ F: Documentation/ABI/stable/sysfs-class-bluetooth F: include/net/bluetooth/ F: net/bluetooth/ +BLZP1600 GPIO DRIVER +M: James Cowgill <james.cowgill@blaize.com> +M: Matt Redfearn <matt.redfearn@blaize.com> +M: Neil Jones <neil.jones@blaize.com> +M: Nikolaos Pasaloukos <nikolaos.pasaloukos@blaize.com> +L: linux-gpio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/gpio/blaize,blzp1600-gpio.yaml +F: drivers/gpio/gpio-blzp1600.c + BONDING DRIVER M: Jay Vosburgh <jv@jvosburgh.net> L: netdev@vger.kernel.org diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index f2c39bbff83a..3244b478d078 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -213,6 +213,17 @@ config GPIO_BCM_XGS_IPROC help Say yes here to enable GPIO support for Broadcom XGS iProc SoCs. +config GPIO_BLZP1600 + tristate "Blaize BLZP1600 GPIO support" + default y if ARCH_BLAIZE + depends on OF_GPIO + select GPIO_GENERIC + select GPIOLIB_IRQCHIP + help + Say Y or M here to add support for the Blaize BLZP1600 GPIO device. + The controller is based on the Verisilicon Microelectronics GPIO APB v0.2 + IP block. + config GPIO_BRCMSTB tristate "BRCMSTB GPIO support" default y if (ARCH_BRCMSTB || BMIPS_GENERIC) diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index af130882ffee..8661cfd8fd8c 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_GPIO_BCM_XGS_IPROC) += gpio-xgs-iproc.o obj-$(CONFIG_GPIO_BD71815) += gpio-bd71815.o obj-$(CONFIG_GPIO_BD71828) += gpio-bd71828.o obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o +obj-$(CONFIG_GPIO_BLZP1600) += gpio-blzp1600.o obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_CADENCE) += gpio-cadence.o diff --git a/drivers/gpio/gpio-blzp1600.c b/drivers/gpio/gpio-blzp1600.c new file mode 100644 index 000000000000..77ad0e596f3e --- /dev/null +++ b/drivers/gpio/gpio-blzp1600.c @@ -0,0 +1,283 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2019 VeriSilicon Limited. + * Copyright (C) 2025 Blaize, Inc. + */ + +#include <linux/errno.h> +#include <linux/gpio/driver.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +#define GPIO_DIR_REG 0x00 +#define GPIO_CTRL_REG 0x04 +#define GPIO_SET_REG 0x08 +#define GPIO_CLR_REG 0x0C +#define GPIO_ODATA_REG 0x10 +#define GPIO_IDATA_REG 0x14 +#define GPIO_IEN_REG 0x18 +#define GPIO_IS_REG 0x1C +#define GPIO_IBE_REG 0x20 +#define GPIO_IEV_REG 0x24 +#define GPIO_RIS_REG 0x28 +#define GPIO_IM_REG 0x2C +#define GPIO_MIS_REG 0x30 +#define GPIO_IC_REG 0x34 +#define GPIO_DB_REG 0x38 +#define GPIO_DFG_REG 0x3C + +#define DRIVER_NAME "blzp1600-gpio" + +struct blzp1600_gpio { + void __iomem *base; + struct gpio_chip gc; + int irq; +}; + +static inline struct blzp1600_gpio *get_blzp1600_gpio_from_irq_data(struct irq_data *d) +{ + return gpiochip_get_data(irq_data_get_irq_chip_data(d)); +} + +static inline struct blzp1600_gpio *get_blzp1600_gpio_from_irq_desc(struct irq_desc *d) +{ + return gpiochip_get_data(irq_desc_get_handler_data(d)); +} + +static inline u32 blzp1600_gpio_read(struct blzp1600_gpio *chip, unsigned int offset) +{ + return readl_relaxed(chip->base + offset); +} + +static inline void blzp1600_gpio_write(struct blzp1600_gpio *chip, unsigned int offset, u32 val) +{ + writel_relaxed(val, chip->base + offset); +} + +static inline void blzp1600_gpio_rmw(void __iomem *reg, u32 mask, bool set) +{ + u32 val = readl_relaxed(reg); + + if (set) + val |= mask; + else + val &= ~mask; + + writel_relaxed(val, reg); +} + +static void blzp1600_gpio_irq_mask(struct irq_data *d) +{ + struct blzp1600_gpio *chip = get_blzp1600_gpio_from_irq_data(d); + + guard(raw_spinlock_irqsave)(&chip->gc.bgpio_lock); + blzp1600_gpio_rmw(chip->base + GPIO_IM_REG, BIT(d->hwirq), 1); +} + +static void blzp1600_gpio_irq_unmask(struct irq_data *d) +{ + struct blzp1600_gpio *chip = get_blzp1600_gpio_from_irq_data(d); + + guard(raw_spinlock_irqsave)(&chip->gc.bgpio_lock); + blzp1600_gpio_rmw(chip->base + GPIO_IM_REG, BIT(d->hwirq), 0); +} + +static void blzp1600_gpio_irq_ack(struct irq_data *d) +{ + struct blzp1600_gpio *chip = get_blzp1600_gpio_from_irq_data(d); + + blzp1600_gpio_write(chip, GPIO_IC_REG, BIT(d->hwirq)); +} + +static void blzp1600_gpio_irq_enable(struct irq_data *d) +{ + struct blzp1600_gpio *chip = get_blzp1600_gpio_from_irq_data(d); + + gpiochip_enable_irq(&chip->gc, irqd_to_hwirq(d)); + + guard(raw_spinlock_irqsave)(&chip->gc.bgpio_lock); + blzp1600_gpio_rmw(chip->base + GPIO_DIR_REG, BIT(d->hwirq), 0); + blzp1600_gpio_rmw(chip->base + GPIO_IEN_REG, BIT(d->hwirq), 1); +} + +static void blzp1600_gpio_irq_disable(struct irq_data *d) +{ + struct blzp1600_gpio *chip = get_blzp1600_gpio_from_irq_data(d); + + guard(raw_spinlock_irqsave)(&chip->gc.bgpio_lock); + blzp1600_gpio_rmw(chip->base + GPIO_IEN_REG, BIT(d->hwirq), 0); + gpiochip_disable_irq(&chip->gc, irqd_to_hwirq(d)); +} + +static int blzp1600_gpio_irq_set_type(struct irq_data *d, u32 type) +{ + struct blzp1600_gpio *chip = get_blzp1600_gpio_from_irq_data(d); + u32 edge_level, single_both, fall_rise; + int mask = BIT(d->hwirq); + + guard(raw_spinlock_irqsave)(&chip->gc.bgpio_lock); + edge_level = blzp1600_gpio_read(chip, GPIO_IS_REG); + single_both = blzp1600_gpio_read(chip, GPIO_IBE_REG); + fall_rise = blzp1600_gpio_read(chip, GPIO_IEV_REG); + + switch (type) { + case IRQ_TYPE_EDGE_BOTH: + edge_level &= ~mask; + single_both |= mask; + break; + case IRQ_TYPE_EDGE_RISING: + edge_level &= ~mask; + single_both &= ~mask; + fall_rise |= mask; + break; + case IRQ_TYPE_EDGE_FALLING: + edge_level &= ~mask; + single_both &= ~mask; + fall_rise &= ~mask; + break; + case IRQ_TYPE_LEVEL_HIGH: + edge_level |= mask; + fall_rise |= mask; + break; + case IRQ_TYPE_LEVEL_LOW: + edge_level |= mask; + fall_rise &= ~mask; + break; + default: + return -EINVAL; + } + + blzp1600_gpio_write(chip, GPIO_IS_REG, edge_level); + blzp1600_gpio_write(chip, GPIO_IBE_REG, single_both); + blzp1600_gpio_write(chip, GPIO_IEV_REG, fall_rise); + + if (type & IRQ_TYPE_LEVEL_MASK) + irq_set_handler_locked(d, handle_level_irq); + else + irq_set_handler_locked(d, handle_edge_irq); + + return 0; +} + +static const struct irq_chip blzp1600_gpio_irqchip = { + .name = DRIVER_NAME, + .irq_ack = blzp1600_gpio_irq_ack, + .irq_mask = blzp1600_gpio_irq_mask, + .irq_unmask = blzp1600_gpio_irq_unmask, + .irq_set_type = blzp1600_gpio_irq_set_type, + .irq_enable = blzp1600_gpio_irq_enable, + .irq_disable = blzp1600_gpio_irq_disable, + .flags = IRQCHIP_IMMUTABLE | IRQCHIP_MASK_ON_SUSPEND, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + +static void blzp1600_gpio_irqhandler(struct irq_desc *desc) +{ + struct blzp1600_gpio *gpio = get_blzp1600_gpio_from_irq_desc(desc); + struct irq_chip *irqchip = irq_desc_get_chip(desc); + unsigned long irq_status; + int hwirq = 0; + + chained_irq_enter(irqchip, desc); + irq_status = blzp1600_gpio_read(gpio, GPIO_RIS_REG); + for_each_set_bit(hwirq, &irq_status, gpio->gc.ngpio) + generic_handle_domain_irq(gpio->gc.irq.domain, hwirq); + + chained_irq_exit(irqchip, desc); +} + +static int blzp1600_gpio_set_debounce(struct gpio_chip *gc, unsigned int offset, + unsigned int debounce) +{ + struct blzp1600_gpio *chip = gpiochip_get_data(gc); + + guard(raw_spinlock_irqsave)(&chip->gc.bgpio_lock); + blzp1600_gpio_rmw(chip->base + GPIO_DB_REG, BIT(offset), debounce); + + return 0; +} + +static int blzp1600_gpio_set_config(struct gpio_chip *gc, unsigned int offset, unsigned long config) +{ + u32 debounce; + + if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE) + return -ENOTSUPP; + + debounce = pinconf_to_config_argument(config); + return blzp1600_gpio_set_debounce(gc, offset, debounce); +} + +static int blzp1600_gpio_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct blzp1600_gpio *chip; + struct gpio_chip *gc; + int ret; + + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(chip->base)) + return PTR_ERR(chip->base); + + ret = bgpio_init(&chip->gc, &pdev->dev, 4, chip->base + GPIO_IDATA_REG, + chip->base + GPIO_SET_REG, chip->base + GPIO_CLR_REG, + chip->base + GPIO_DIR_REG, NULL, 0); + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to register generic gpio\n"); + + /* configure the gpio chip */ + gc = &chip->gc; + gc->set_config = blzp1600_gpio_set_config; + + if (of_property_read_bool(node, "interrupt-controller")) { + struct gpio_irq_chip *girq; + + chip->irq = platform_get_irq(pdev, 0); + if (chip->irq < 0) + return chip->irq; + + girq = &gc->irq; + gpio_irq_chip_set_chip(girq, &blzp1600_gpio_irqchip); + girq->parent_handler = blzp1600_gpio_irqhandler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(&pdev->dev, 1, sizeof(*girq->parents), GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + + girq->parents[0] = chip->irq; + girq->default_type = IRQ_TYPE_NONE; + } + + return devm_gpiochip_add_data(&pdev->dev, gc, chip); +} + +static const struct of_device_id blzp1600_gpio_of_match[] = { + { .compatible = "blaize,blzp1600-gpio", }, + { /* Sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, blzp1600_gpio_of_match); + +static struct platform_driver blzp1600_gpio_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(blzp1600_gpio_of_match), + }, + .probe = blzp1600_gpio_probe, +}; + +module_platform_driver(blzp1600_gpio_driver); + +MODULE_AUTHOR("Nikolaos Pasaloukos <nikolaos.pasaloukos@blaize.com>"); +MODULE_DESCRIPTION("Blaize BLZP1600 GPIO driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index 107d75558b5a..e6a289fa0f8f 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -1366,9 +1366,6 @@ static long linereq_set_values(struct linereq *lr, void __user *ip) /* scan requested lines to determine the subset to be set */ for (num_set = 0, i = 0; i < lr->num_lines; i++) { if (lv.mask & BIT_ULL(i)) { - /* setting inputs is not allowed */ - if (!test_bit(FLAG_IS_OUT, &lr->lines[i].desc->flags)) - return -EPERM; /* add to compacted values */ if (lv.bits & BIT_ULL(i)) __set_bit(num_set, vals); diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index eb667f8f1ead..3651c4178b81 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -222,6 +222,15 @@ static void of_gpio_try_fixup_polarity(const struct device_node *np, */ { "lantiq,pci-xway", "gpio-reset", false }, #endif +#if IS_ENABLED(CONFIG_REGULATOR_S5M8767) + /* + * According to S5M8767, the DVS and DS pin are + * active-high signals. However, exynos5250-spring.dts use + * active-low setting. + */ + { "samsung,s5m8767-pmic", "s5m8767,pmic-buck-dvs-gpios", true }, + { "samsung,s5m8767-pmic", "s5m8767,pmic-buck-ds-gpios", true }, +#endif #if IS_ENABLED(CONFIG_TOUCHSCREEN_TSC2005) /* * DTS for Nokia N900 incorrectly specified "active high" @@ -1276,3 +1285,11 @@ void of_gpiochip_remove(struct gpio_chip *chip) { of_node_put(dev_of_node(&chip->gpiodev->dev)); } + +bool of_gpiochip_instance_match(struct gpio_chip *gc, unsigned int index) +{ + if (gc->of_node_instance_match) + return gc->of_node_instance_match(gc, index); + + return false; +} diff --git a/drivers/gpio/gpiolib-of.h b/drivers/gpio/gpiolib-of.h index 16d6ac8cb156..3eebfac290c5 100644 --- a/drivers/gpio/gpiolib-of.h +++ b/drivers/gpio/gpiolib-of.h @@ -22,6 +22,7 @@ struct gpio_desc *of_find_gpio(struct device_node *np, unsigned long *lookupflags); int of_gpiochip_add(struct gpio_chip *gc); void of_gpiochip_remove(struct gpio_chip *gc); +bool of_gpiochip_instance_match(struct gpio_chip *gc, unsigned int index); int of_gpio_count(const struct fwnode_handle *fwnode, const char *con_id); #else static inline struct gpio_desc *of_find_gpio(struct device_node *np, @@ -33,6 +34,11 @@ static inline struct gpio_desc *of_find_gpio(struct device_node *np, } static inline int of_gpiochip_add(struct gpio_chip *gc) { return 0; } static inline void of_gpiochip_remove(struct gpio_chip *gc) { } +static inline bool of_gpiochip_instance_match(struct gpio_chip *gc, + unsigned int index) +{ + return false; +} static inline int of_gpio_count(const struct fwnode_handle *fwnode, const char *con_id) { diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index 1acfa43bf1ab..4a3aa09dad9d 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -134,17 +134,15 @@ static ssize_t value_store(struct device *dev, long value; status = kstrtol(buf, 0, &value); + if (status) + return status; guard(mutex)(&data->mutex); - if (!test_bit(FLAG_IS_OUT, &desc->flags)) - return -EPERM; - + status = gpiod_set_value_cansleep(desc, value); if (status) return status; - gpiod_set_value_cansleep(desc, value); - return size; } static DEVICE_ATTR_PREALLOC(value, S_IWUSR | S_IRUGO, value_show, value_store); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 2e5b6982e76d..f208901ba478 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1521,9 +1521,8 @@ static int gpiochip_hierarchy_irq_domain_translate(struct irq_domain *d, unsigned int *type) { /* We support standard DT translation */ - if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) { - return irq_domain_translate_twocell(d, fwspec, hwirq, type); - } + if (is_of_node(fwspec->fwnode)) + return irq_domain_translate_twothreecell(d, fwspec, hwirq, type); /* This is for board files and others not using DT */ if (is_fwnode_irqchip(fwspec->fwnode)) { @@ -1825,11 +1824,26 @@ static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq) irq_set_chip_data(irq, NULL); } +static int gpiochip_irq_select(struct irq_domain *d, struct irq_fwspec *fwspec, + enum irq_domain_bus_token bus_token) +{ + struct fwnode_handle *fwnode = fwspec->fwnode; + struct gpio_chip *gc = d->host_data; + unsigned int index = fwspec->param[0]; + + if (fwspec->param_count == 3 && is_of_node(fwnode)) + return of_gpiochip_instance_match(gc, index); + + /* Fallback for twocells */ + return (fwnode && (d->fwnode == fwnode) && (d->bus_token == bus_token)); +} + static const struct irq_domain_ops gpiochip_domain_ops = { .map = gpiochip_irq_map, .unmap = gpiochip_irq_unmap, + .select = gpiochip_irq_select, /* Virtually all GPIO irqchips are twocell:ed */ - .xlate = irq_domain_xlate_twocell, + .xlate = irq_domain_xlate_twothreecell, }; static struct irq_domain *gpiochip_simple_create_domain(struct gpio_chip *gc) @@ -3607,6 +3621,9 @@ static int gpio_set_open_source_value_commit(struct gpio_desc *desc, bool value) static int gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value) { + if (unlikely(!test_bit(FLAG_IS_OUT, &desc->flags))) + return -EPERM; + CLASS(gpio_chip_guard, guard)(desc); if (!guard.gc) return -ENODEV; @@ -3678,6 +3695,12 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, if (!can_sleep) WARN_ON(array_info->gdev->can_sleep); + for (i = 0; i < array_size; i++) { + if (unlikely(!test_bit(FLAG_IS_OUT, + &desc_array[i]->flags))) + return -EPERM; + } + guard(srcu)(&array_info->gdev->srcu); gc = srcu_dereference(array_info->gdev->chip, &array_info->gdev->srcu); @@ -3737,6 +3760,9 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, int hwgpio = gpio_chip_hwgpio(desc); int value = test_bit(i, value_bitmap); + if (unlikely(!test_bit(FLAG_IS_OUT, &desc->flags))) + return -EPERM; + /* * Pins applicable for fast input but not for * fast output processing may have been already diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index bb7111105296..df7e9278c8ac 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -571,16 +571,16 @@ int irq_domain_xlate_twocell(struct irq_domain *d, struct device_node *ctrlr, int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_type); - -int irq_domain_translate_twocell(struct irq_domain *d, - struct irq_fwspec *fwspec, - unsigned long *out_hwirq, - unsigned int *out_type); - -int irq_domain_translate_onecell(struct irq_domain *d, - struct irq_fwspec *fwspec, - unsigned long *out_hwirq, - unsigned int *out_type); +int irq_domain_xlate_twothreecell(struct irq_domain *d, struct device_node *ctrlr, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_type); + +int irq_domain_translate_onecell(struct irq_domain *d, struct irq_fwspec *fwspec, + unsigned long *out_hwirq, unsigned int *out_type); +int irq_domain_translate_twocell(struct irq_domain *d, struct irq_fwspec *fwspec, + unsigned long *out_hwirq, unsigned int *out_type); +int irq_domain_translate_twothreecell(struct irq_domain *d, struct irq_fwspec *fwspec, + unsigned long *out_hwirq, unsigned int *out_type); /* IPI functions */ int irq_reserve_ipi(struct irq_domain *domain, const struct cpumask *dest); diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 9d5c8651492d..b294c3ff73b6 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -1133,6 +1133,31 @@ int irq_domain_xlate_twocell(struct irq_domain *d, struct device_node *ctrlr, EXPORT_SYMBOL_GPL(irq_domain_xlate_twocell); /** + * irq_domain_xlate_twothreecell() - Generic xlate for direct two or three cell bindings + * @d: Interrupt domain involved in the translation + * @ctrlr: The device tree node for the device whose interrupt is translated + * @intspec: The interrupt specifier data from the device tree + * @intsize: The number of entries in @intspec + * @out_hwirq: Pointer to storage for the hardware interrupt number + * @out_type: Pointer to storage for the interrupt type + * + * Device Tree interrupt specifier translation function for two or three + * cell bindings, where the cell values map directly to the hardware + * interrupt number and the type specifier. + */ +int irq_domain_xlate_twothreecell(struct irq_domain *d, struct device_node *ctrlr, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_type) +{ + struct irq_fwspec fwspec; + + of_phandle_args_to_fwspec(ctrlr, intspec, intsize, &fwspec); + + return irq_domain_translate_twothreecell(d, &fwspec, out_hwirq, out_type); +} +EXPORT_SYMBOL_GPL(irq_domain_xlate_twothreecell); + +/** * irq_domain_xlate_onetwocell() - Generic xlate for one or two cell bindings * @d: Interrupt domain involved in the translation * @ctrlr: The device tree node for the device whose interrupt is translated @@ -1216,6 +1241,37 @@ int irq_domain_translate_twocell(struct irq_domain *d, } EXPORT_SYMBOL_GPL(irq_domain_translate_twocell); +/** + * irq_domain_translate_twothreecell() - Generic translate for direct two or three cell + * bindings + * @d: Interrupt domain involved in the translation + * @fwspec: The firmware interrupt specifier to translate + * @out_hwirq: Pointer to storage for the hardware interrupt number + * @out_type: Pointer to storage for the interrupt type + * + * Firmware interrupt specifier translation function for two or three cell + * specifications, where the parameter values map directly to the hardware + * interrupt number and the type specifier. + */ +int irq_domain_translate_twothreecell(struct irq_domain *d, struct irq_fwspec *fwspec, + unsigned long *out_hwirq, unsigned int *out_type) +{ + if (fwspec->param_count == 2) { + *out_hwirq = fwspec->param[0]; + *out_type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; + return 0; + } + + if (fwspec->param_count == 3) { + *out_hwirq = fwspec->param[1]; + *out_type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; + return 0; + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(irq_domain_translate_twothreecell); + int irq_domain_alloc_descs(int virq, unsigned int cnt, irq_hw_number_t hwirq, int node, const struct irq_affinity_desc *affinity) { |