From 55f8bbb5137936cb32ca3bb420e4942cf6f275b6 Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Mon, 9 Dec 2019 11:57:49 +0530 Subject: [PATCH 01/48] gpio: pca953x: Don't hardcode irq trigger type Don't hardcode irq trigger to IRQF_TRIGGER_LOW while registering IRQ handler. IRQ/platform core will take care of setting appropriate trigger type. Signed-off-by: Vignesh Raghavendra Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pca953x.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 6652bee01966..40e48f7d83bb 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -770,8 +770,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base) ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, pca953x_irq_handler, - IRQF_TRIGGER_LOW | IRQF_ONESHOT | - IRQF_SHARED, + IRQF_ONESHOT | IRQF_SHARED, dev_name(&client->dev), chip); if (ret) { dev_err(&client->dev, "failed to request irq %d\n", From 725c1cb6987ad1258cc15792a55535a11308dc5a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 9 Dec 2019 14:35:45 +0200 Subject: [PATCH 02/48] gpio: pca953x: Remove redundant forward declaration There is no need to have a forward declaration for pca953x_dt_ids[]. Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pca953x.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 40e48f7d83bb..24ffe78ffe71 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -860,8 +860,6 @@ out: return ret; } -static const struct of_device_id pca953x_dt_ids[]; - static int pca953x_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { From 0c21639f5a4b1f91b8b963058f2aa8b2a9e5f61c Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 4 Dec 2019 09:24:35 +0000 Subject: [PATCH 03/48] gpio: mvebu: use platform_irq_count MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit platform_irq_count() is the more generic way (independent of device trees) to determine the count of available interrupts. So use this instead. As platform_irq_count() might return an error code (which of_irq_count doesn't) some additional handling is necessary. Reviewed-by: Uwe Kleine-König Signed-off-by: Peng Fan Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-mvebu.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 993bbeb3c006..f0fd82b3417c 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -46,7 +46,6 @@ #include #include #include -#include #include #include #include @@ -1102,7 +1101,11 @@ static int mvebu_gpio_probe(struct platform_device *pdev) soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION; /* Some gpio controllers do not provide irq support */ - have_irqs = of_irq_count(np) != 0; + err = platform_irq_count(pdev); + if (err < 0) + return err; + + have_irqs = err != 0; mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip), GFP_KERNEL); From cfdca14c44a79b9c9c491235a39b9fc1e520820b Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 4 Dec 2019 09:24:39 +0000 Subject: [PATCH 04/48] gpio: bcm-kona: use platform_irq_count platform_irq_count() is the more generic way (independent of device trees) to determine the count of available interrupts. So use this instead. As platform_irq_count() might return an error code (which of_irq_count doesn't) some additional handling is necessary. Signed-off-by: Peng Fan Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-bcm-kona.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 4122683eb1f9..baee8c3f06ad 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -586,11 +585,18 @@ static int bcm_kona_gpio_probe(struct platform_device *pdev) kona_gpio->gpio_chip = template_chip; chip = &kona_gpio->gpio_chip; - kona_gpio->num_bank = of_irq_count(dev->of_node); - if (kona_gpio->num_bank == 0) { + ret = platform_irq_count(pdev); + if (!ret) { dev_err(dev, "Couldn't determine # GPIO banks\n"); return -ENOENT; + } else if (ret < 0) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "Couldn't determine GPIO banks: (%pe)\n", + ERR_PTR(ret)); + return ret; } + kona_gpio->num_bank = ret; + if (kona_gpio->num_bank > GPIO_MAX_BANK_NUM) { dev_err(dev, "Too many GPIO banks configured (max=%d)\n", GPIO_MAX_BANK_NUM); From ddd8891e01ecd87c81c04f6eb169be193868b884 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 27 Nov 2019 09:42:47 +0100 Subject: [PATCH 05/48] gpiolib: Add GPIOCHIP_NAME definition The string literal "gpiochip" is used in several places. Add a definition for it, and use it everywhere, to make sure everything stays in sync. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20191127084253.16356-2-geert+renesas@glider.be Reviewed-by: Ulrich Hecht Reviewed-by: Eugeniu Rosca Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-sysfs.c | 7 +++---- drivers/gpio/gpiolib.c | 4 ++-- drivers/gpio/gpiolib.h | 2 ++ 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c index fbf6b1a0a4fa..23e3d335cd54 100644 --- a/drivers/gpio/gpiolib-sysfs.c +++ b/drivers/gpio/gpiolib-sysfs.c @@ -762,10 +762,9 @@ int gpiochip_sysfs_register(struct gpio_device *gdev) parent = &gdev->dev; /* use chip->base for the ID; it's already known to be unique */ - dev = device_create_with_groups(&gpio_class, parent, - MKDEV(0, 0), - chip, gpiochip_groups, - "gpiochip%d", chip->base); + dev = device_create_with_groups(&gpio_class, parent, MKDEV(0, 0), chip, + gpiochip_groups, GPIOCHIP_NAME "%d", + chip->base); if (IS_ERR(dev)) return PTR_ERR(dev); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 9913886ede90..a502228a326d 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1419,7 +1419,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, ret = gdev->id; goto err_free_gdev; } - dev_set_name(&gdev->dev, "gpiochip%d", gdev->id); + dev_set_name(&gdev->dev, GPIOCHIP_NAME "%d", gdev->id); device_initialize(&gdev->dev); dev_set_drvdata(&gdev->dev, gdev); if (chip->parent && chip->parent->driver) @@ -5104,7 +5104,7 @@ static int __init gpiolib_dev_init(void) return ret; } - ret = alloc_chrdev_region(&gpio_devt, 0, GPIO_DEV_MAX, "gpiochip"); + ret = alloc_chrdev_region(&gpio_devt, 0, GPIO_DEV_MAX, GPIOCHIP_NAME); if (ret < 0) { pr_err("gpiolib: failed to allocate char dev region\n"); bus_unregister(&gpio_bus_type); diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index ca9bc1e4803c..a4a759920faa 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -16,6 +16,8 @@ #include #include +#define GPIOCHIP_NAME "gpiochip" + /** * struct gpio_device - internal state container for GPIO devices * @id: numerical ID number for the GPIO chip From 373894f83b52423e4eb05566977c9c38985b0b57 Mon Sep 17 00:00:00 2001 From: "Enrico Weigelt, metux IT consult" Date: Thu, 12 Dec 2019 14:33:06 +0100 Subject: [PATCH 06/48] gpio: remove unneeded MODULE_VERSION() usage Remove MODULE_VERSION(), as it isn't needed at all: the only version making sense is the kernel version. Signed-off-by: Enrico Weigelt, metux IT consult Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-sama5d2-piobu.c | 1 - drivers/gpio/gpio-tb10x.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/gpio/gpio-sama5d2-piobu.c b/drivers/gpio/gpio-sama5d2-piobu.c index b04c561f3280..4d47b2c41186 100644 --- a/drivers/gpio/gpio-sama5d2-piobu.c +++ b/drivers/gpio/gpio-sama5d2-piobu.c @@ -244,7 +244,6 @@ static struct platform_driver sama5d2_piobu_driver = { module_platform_driver(sama5d2_piobu_driver); -MODULE_VERSION("1.0"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("SAMA5D2 PIOBU controller driver"); MODULE_AUTHOR("Andrei Stefanescu "); diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c index 5e375186f90e..866201cf5f65 100644 --- a/drivers/gpio/gpio-tb10x.c +++ b/drivers/gpio/gpio-tb10x.c @@ -243,4 +243,3 @@ static struct platform_driver tb10x_gpio_driver = { module_platform_driver(tb10x_gpio_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("tb10x gpio."); -MODULE_VERSION("0.0.1"); From 885503fbea210bc8f4ac70fa530ed05fade4bc94 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Tue, 3 Dec 2019 15:12:40 +0100 Subject: [PATCH 07/48] dt-bindings: Add Xylon vendor prefix Xylon is an electronics company that produces FPGA hardware block designs optimized for Xilinx FPGAs. Signed-off-by: Paul Kocialkowski Acked-by: Rob Herring Link: https://lore.kernel.org/r/20191203141243.251058-2-paul.kocialkowski@bootlin.com Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 6046f4555852..9cb3bc683db7 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1060,6 +1060,8 @@ patternProperties: description: Xilinx "^xunlong,.*": description: Shenzhen Xunlong Software CO.,Limited + "^xylon,.*": + description: Xylon "^yones-toptech,.*": description: Yones Toptech Co., Ltd. "^ysoft,.*": From e10781c118c986a3eb7c4b2edb4bdaba37bb5635 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Tue, 3 Dec 2019 15:12:41 +0100 Subject: [PATCH 08/48] dt-bindings: mfd: Document the Xylon LogiCVC multi-function device The LogiCVC is a display engine which also exposes GPIO functionality. For this reason, it is described as a multi-function device that is expected to provide register access to its children nodes for gpio and display. Signed-off-by: Paul Kocialkowski Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20191203141243.251058-3-paul.kocialkowski@bootlin.com Signed-off-by: Linus Walleij --- .../bindings/mfd/xylon,logicvc.yaml | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/xylon,logicvc.yaml diff --git a/Documentation/devicetree/bindings/mfd/xylon,logicvc.yaml b/Documentation/devicetree/bindings/mfd/xylon,logicvc.yaml new file mode 100644 index 000000000000..abc9937506e0 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/xylon,logicvc.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2019 Bootlin +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/mfd/xylon,logicvc.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Xylon LogiCVC multi-function device + +maintainers: + - Paul Kocialkowski + +description: | + The LogiCVC is a display controller that also contains a GPIO controller. + As a result, a multi-function device is exposed as parent of the display + and GPIO blocks. + +properties: + compatible: + items: + - enum: + - xylon,logicvc-3.02.a + - const: syscon + - const: simple-mfd + + reg: + maxItems: 1 + +select: + properties: + compatible: + contains: + enum: + - xylon,logicvc-3.02.a + + required: + - compatible + +required: + - compatible + - reg + +examples: + - | + logicvc: logicvc@43c00000 { + compatible = "xylon,logicvc-3.02.a", "syscon", "simple-mfd"; + reg = <0x43c00000 0x6000>; + #address-cells = <1>; + #size-cells = <1>; + }; From 6bdbe62c748c4b8cfe3555bb9b1daecc0d1e585a Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Tue, 3 Dec 2019 15:12:42 +0100 Subject: [PATCH 09/48] dt-bindings: gpio: Document the Xylon LogiCVC GPIO controller The Xylon LogiCVC display controller exports some GPIOs, which are exposed as a separate entity. Signed-off-by: Paul Kocialkowski Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20191203141243.251058-4-paul.kocialkowski@bootlin.com Signed-off-by: Linus Walleij --- .../bindings/gpio/xylon,logicvc-gpio.yaml | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/xylon,logicvc-gpio.yaml diff --git a/Documentation/devicetree/bindings/gpio/xylon,logicvc-gpio.yaml b/Documentation/devicetree/bindings/gpio/xylon,logicvc-gpio.yaml new file mode 100644 index 000000000000..d102888c1be7 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/xylon,logicvc-gpio.yaml @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# Copyright 2019 Bootlin +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/gpio/xylon,logicvc-gpio.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Xylon LogiCVC GPIO controller + +maintainers: + - Paul Kocialkowski + +description: | + The LogiCVC GPIO describes the GPIO block included in the LogiCVC display + controller. These are meant to be used for controlling display-related + signals. + + The controller exposes GPIOs from the display and power control registers, + which are mapped by the driver as follows: + - GPIO[4:0] (display control) mapped to index 0-4 + - EN_BLIGHT (power control) mapped to index 5 + - EN_VDD (power control) mapped to index 6 + - EN_VEE (power control) mapped to index 7 + - V_EN (power control) mapped to index 8 + +properties: + $nodename: + pattern: "^gpio@[0-9a-f]+$" + + compatible: + enum: + - xylon,logicvc-3.02.a-gpio + + reg: + maxItems: 1 + + "#gpio-cells": + const: 2 + + gpio-controller: true + + gpio-line-names: + minItems: 1 + maxItems: 9 + +required: + - compatible + - reg + - "#gpio-cells" + - gpio-controller + +examples: + - | + logicvc: logicvc@43c00000 { + compatible = "xylon,logicvc-3.02.a", "syscon", "simple-mfd"; + reg = <0x43c00000 0x6000>; + + #address-cells = <1>; + #size-cells = <1>; + + logicvc_gpio: gpio@40 { + compatible = "xylon,logicvc-3.02.a-gpio"; + reg = <0x40 0x40>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "GPIO0", "GPIO1", "GPIO2", "GPIO3", "GPIO4", + "EN_BLIGHT", "EN_VDD", "EN_VEE", "V_EN"; + }; + }; From c16485ad8e023b2188d19f0ace3bc2af500884e1 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Tue, 3 Dec 2019 15:12:43 +0100 Subject: [PATCH 10/48] gpio: Add support for the Xylon LogiCVC GPIOs The LogiCVC display hardware block comes with GPIO capabilities that must be exposed separately from the main driver (as GPIOs) for use with regulators and panels. A syscon is used to share the same regmap across the two drivers. Add a minimalistic GPIO driver to drive these GPIOs, using a syscon regmap when available. Signed-off-by: Paul Kocialkowski Link: https://lore.kernel.org/r/20191203141243.251058-5-paul.kocialkowski@bootlin.com Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 6 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-logicvc.c | 170 ++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+) create mode 100644 drivers/gpio/gpio-logicvc.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 8adffd42f8cb..79f153b1da7e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -312,6 +312,12 @@ config GPIO_IXP4XX IXP4xx series of chips. If unsure, say N. +config GPIO_LOGICVC + tristate "Xylon LogiCVC GPIO support" + depends on MFD_SYSCON && OF + help + Say yes here to support GPIO functionality of the Xylon LogiCVC + programmable logic block. config GPIO_LOONGSON bool "Loongson-2/3 GPIO support" diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 34eb8b2b12dd..ba53f1fcde3a 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -69,6 +69,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_LOGICVC) += gpio-logicvc.o obj-$(CONFIG_GPIO_LOONGSON1) += gpio-loongson1.o obj-$(CONFIG_GPIO_LOONGSON) += gpio-loongson.o obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o diff --git a/drivers/gpio/gpio-logicvc.c b/drivers/gpio/gpio-logicvc.c new file mode 100644 index 000000000000..015632cf159f --- /dev/null +++ b/drivers/gpio/gpio-logicvc.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 Bootlin + * Author: Paul Kocialkowski + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOGICVC_CTRL_REG 0x40 +#define LOGICVC_CTRL_GPIO_SHIFT 11 +#define LOGICVC_CTRL_GPIO_BITS 5 + +#define LOGICVC_POWER_CTRL_REG 0x78 +#define LOGICVC_POWER_CTRL_GPIO_SHIFT 0 +#define LOGICVC_POWER_CTRL_GPIO_BITS 4 + +struct logicvc_gpio { + struct gpio_chip chip; + struct regmap *regmap; +}; + +static void logicvc_gpio_offset(struct logicvc_gpio *logicvc, unsigned offset, + unsigned int *reg, unsigned int *bit) +{ + if (offset >= LOGICVC_CTRL_GPIO_BITS) { + *reg = LOGICVC_POWER_CTRL_REG; + + /* To the (virtual) power ctrl offset. */ + offset -= LOGICVC_CTRL_GPIO_BITS; + /* To the actual bit offset in reg. */ + offset += LOGICVC_POWER_CTRL_GPIO_SHIFT; + } else { + *reg = LOGICVC_CTRL_REG; + + /* To the actual bit offset in reg. */ + offset += LOGICVC_CTRL_GPIO_SHIFT; + } + + *bit = BIT(offset); +} + +static int logicvc_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct logicvc_gpio *logicvc = gpiochip_get_data(chip); + unsigned int reg, bit, value; + int ret; + + logicvc_gpio_offset(logicvc, offset, ®, &bit); + + ret = regmap_read(logicvc->regmap, reg, &value); + if (ret) + return ret; + + return !!(value & bit); +} + +static void logicvc_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct logicvc_gpio *logicvc = gpiochip_get_data(chip); + unsigned int reg, bit; + + logicvc_gpio_offset(logicvc, offset, ®, &bit); + + regmap_update_bits(logicvc->regmap, reg, bit, value ? bit : 0); +} + +static int logicvc_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + /* Pins are always configured as output, so just set the value. */ + logicvc_gpio_set(chip, offset, value); + + return 0; +} + +static struct regmap_config logicvc_gpio_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .name = "logicvc-gpio", +}; + +static int logicvc_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *of_node = dev->of_node; + struct logicvc_gpio *logicvc; + int ret; + + logicvc = devm_kzalloc(dev, sizeof(*logicvc), GFP_KERNEL); + if (!logicvc) + return -ENOMEM; + + /* Try to get regmap from parent first. */ + logicvc->regmap = syscon_node_to_regmap(of_node->parent); + + /* Grab our own regmap if that fails. */ + if (IS_ERR(logicvc->regmap)) { + struct resource res; + void __iomem *base; + + ret = of_address_to_resource(of_node, 0, &res); + if (ret) { + dev_err(dev, "Failed to get resource from address\n"); + return ret; + } + + base = devm_ioremap_resource(dev, &res); + if (IS_ERR(base)) { + dev_err(dev, "Failed to map I/O base\n"); + return PTR_ERR(base); + } + + logicvc_gpio_regmap_config.max_register = resource_size(&res) - + logicvc_gpio_regmap_config.reg_stride; + + logicvc->regmap = + devm_regmap_init_mmio(dev, base, + &logicvc_gpio_regmap_config); + if (IS_ERR(logicvc->regmap)) { + dev_err(dev, "Failed to create regmap for I/O\n"); + return PTR_ERR(logicvc->regmap); + } + } + + logicvc->chip.parent = dev; + logicvc->chip.owner = THIS_MODULE; + logicvc->chip.label = dev_name(dev); + logicvc->chip.base = -1; + logicvc->chip.ngpio = LOGICVC_CTRL_GPIO_BITS + + LOGICVC_POWER_CTRL_GPIO_BITS; + logicvc->chip.get = logicvc_gpio_get; + logicvc->chip.set = logicvc_gpio_set; + logicvc->chip.direction_output = logicvc_gpio_direction_output; + + platform_set_drvdata(pdev, logicvc); + + return devm_gpiochip_add_data(dev, &logicvc->chip, logicvc); +} + +static const struct of_device_id logicivc_gpio_of_table[] = { + { + .compatible = "xylon,logicvc-3.02.a-gpio", + }, + { } +}; + +MODULE_DEVICE_TABLE(of, logicivc_gpio_of_table); + +static struct platform_driver logicvc_gpio_driver = { + .driver = { + .name = "gpio-logicvc", + .of_match_table = logicivc_gpio_of_table, + }, + .probe = logicvc_gpio_probe, +}; + +module_platform_driver(logicvc_gpio_driver); + +MODULE_AUTHOR("Paul Kocialkowski "); +MODULE_DESCRIPTION("Xylon LogiCVC GPIO driver"); +MODULE_LICENSE("GPL"); From 4fc5bfeb4b7d8306be6ed828df2cb5bdd14e3ed1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 4 Dec 2019 21:42:29 +0200 Subject: [PATCH 11/48] gpiolib: Make use of assign_bit() API We have for some time the assign_bit() API to replace open coded if (foo) set_bit(n, bar); else clear_bit(n, bar); Use this API in GPIO library code. No functional change intended. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20191204194229.64251-2-andriy.shevchenko@linux.intel.com Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 59 ++++++++++++++---------------------------- 1 file changed, 20 insertions(+), 39 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index a502228a326d..def586bc2568 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -224,15 +224,15 @@ int gpiod_get_direction(struct gpio_desc *desc) return -ENOTSUPP; ret = chip->get_direction(chip, offset); - if (ret > 0) { - /* GPIOF_DIR_IN, or other positive */ + if (ret < 0) + return ret; + + /* GPIOF_DIR_IN or other positive, otherwise GPIOF_DIR_OUT */ + if (ret > 0) ret = 1; - clear_bit(FLAG_IS_OUT, &desc->flags); - } - if (ret == 0) { - /* GPIOF_DIR_OUT */ - set_bit(FLAG_IS_OUT, &desc->flags); - } + + assign_bit(FLAG_IS_OUT, &desc->flags, !ret); + return ret; } EXPORT_SYMBOL_GPL(gpiod_get_direction); @@ -484,15 +484,6 @@ static int linehandle_validate_flags(u32 flags) return 0; } -static void linehandle_configure_flag(unsigned long *flagsp, - u32 bit, bool active) -{ - if (active) - set_bit(bit, flagsp); - else - clear_bit(bit, flagsp); -} - static long linehandle_set_config(struct linehandle_state *lh, void __user *ip) { @@ -514,22 +505,22 @@ static long linehandle_set_config(struct linehandle_state *lh, desc = lh->descs[i]; flagsp = &desc->flags; - linehandle_configure_flag(flagsp, FLAG_ACTIVE_LOW, + assign_bit(FLAG_ACTIVE_LOW, flagsp, lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW); - linehandle_configure_flag(flagsp, FLAG_OPEN_DRAIN, + assign_bit(FLAG_OPEN_DRAIN, flagsp, lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN); - linehandle_configure_flag(flagsp, FLAG_OPEN_SOURCE, + assign_bit(FLAG_OPEN_SOURCE, flagsp, lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE); - linehandle_configure_flag(flagsp, FLAG_PULL_UP, + assign_bit(FLAG_PULL_UP, flagsp, lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP); - linehandle_configure_flag(flagsp, FLAG_PULL_DOWN, + assign_bit(FLAG_PULL_DOWN, flagsp, lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN); - linehandle_configure_flag(flagsp, FLAG_BIAS_DISABLE, + assign_bit(FLAG_BIAS_DISABLE, flagsp, lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE); /* @@ -1516,15 +1507,11 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, struct gpio_desc *desc = &gdev->descs[i]; if (chip->get_direction && gpiochip_line_is_valid(chip, i)) { - if (!chip->get_direction(chip, i)) - set_bit(FLAG_IS_OUT, &desc->flags); - else - clear_bit(FLAG_IS_OUT, &desc->flags); + assign_bit(FLAG_IS_OUT, + &desc->flags, !chip->get_direction(chip, i)); } else { - if (!chip->direction_input) - set_bit(FLAG_IS_OUT, &desc->flags); - else - clear_bit(FLAG_IS_OUT, &desc->flags); + assign_bit(FLAG_IS_OUT, + &desc->flags, !chip->direction_input); } } @@ -3326,10 +3313,7 @@ int gpiod_set_transitory(struct gpio_desc *desc, bool transitory) * Handle FLAG_TRANSITORY first, enabling queries to gpiolib for * persistence state. */ - if (transitory) - set_bit(FLAG_TRANSITORY, &desc->flags); - else - clear_bit(FLAG_TRANSITORY, &desc->flags); + assign_bit(FLAG_TRANSITORY, &desc->flags, transitory); /* If the driver supports it, set the persistence state now */ chip = desc->gdev->chip; @@ -3785,10 +3769,7 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, gpio_set_open_source_value_commit(desc, value); } else { __set_bit(hwgpio, mask); - if (value) - __set_bit(hwgpio, bits); - else - __clear_bit(hwgpio, bits); + __assign_bit(hwgpio, bits, value); count++; } i++; From 894731a5c9d0ea801a7ea1aba2f7c7b69fef6e85 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 5 Dec 2019 14:39:12 +0100 Subject: [PATCH 12/48] dt-bindings: gpio: rcar: Document r8a77961 support Document support for the GPIO controller in the Renesas R-Car M3-W+ (R8A77961) SoC. Update all references to R-Car M3-W from "r8a7796" to "r8a77960", to avoid confusion between R-Car M3-W (R8A77960) and M3-W+. No driver update is needed. Signed-off-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20191205133912.6048-1-geert+renesas@glider.be Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt index 41e5fed0f842..10dce84b1545 100644 --- a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt +++ b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt @@ -18,7 +18,8 @@ Required Properties: - "renesas,gpio-r8a7793": for R8A7793 (R-Car M2-N) compatible GPIO controller. - "renesas,gpio-r8a7794": for R8A7794 (R-Car E2) compatible GPIO controller. - "renesas,gpio-r8a7795": for R8A7795 (R-Car H3) compatible GPIO controller. - - "renesas,gpio-r8a7796": for R8A7796 (R-Car M3-W) compatible GPIO controller. + - "renesas,gpio-r8a7796": for R8A77960 (R-Car M3-W) compatible GPIO controller. + - "renesas,gpio-r8a77961": for R8A77961 (R-Car M3-W+) compatible GPIO controller. - "renesas,gpio-r8a77965": for R8A77965 (R-Car M3-N) compatible GPIO controller. - "renesas,gpio-r8a77970": for R8A77970 (R-Car V3M) compatible GPIO controller. - "renesas,gpio-r8a77980": for R8A77980 (R-Car V3H) compatible GPIO controller. From 6cc1d4568120bc8013b52873d9a40bdc6ae7802a Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 11 Dec 2019 11:47:57 +0200 Subject: [PATCH 13/48] docs: driver-model: Add missing managed GPIO array get functions devm_gpiod_get_array and devm_gpiod_get_array_optional were missing from the list. Add them. Signed-off-by: Matti Vaittinen Link: https://lore.kernel.org/r/f56dce4fcb71592cbcf0fc48a841f86f52770d4c.1576054779.git.matti.vaittinen@fi.rohmeurope.com Signed-off-by: Linus Walleij --- Documentation/driver-api/driver-model/devres.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index 13046fcf0a5d..f37d9ded8ddc 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -267,6 +267,8 @@ DRM GPIO devm_gpiod_get() + devm_gpiod_get_array() + devm_gpiod_get_array_optional() devm_gpiod_get_index() devm_gpiod_get_index_optional() devm_gpiod_get_optional() From fc782e47e601843163034a68c29ea1abe2578570 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 15 Dec 2019 21:30:45 +0300 Subject: [PATCH 14/48] gpio: tegra: Use generic readl_relaxed/writel_relaxed accessors There is no point in using old-style raw accessors, the generic accessors do the same thing and also take into account CPU endianness. Tegra SoCs do not support big-endian mode in the upstream kernel, but let's switch away from the outdated things anyway, just to keep code up-to-date. Signed-off-by: Dmitry Osipenko Reviewed-by: Thierry Reding Tested-by: Thierry Reding Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-tegra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 6fdfe4c5303e..f6a382fbd12d 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -96,12 +96,12 @@ struct tegra_gpio_info { static inline void tegra_gpio_writel(struct tegra_gpio_info *tgi, u32 val, u32 reg) { - __raw_writel(val, tgi->regs + reg); + writel_relaxed(val, tgi->regs + reg); } static inline u32 tegra_gpio_readl(struct tegra_gpio_info *tgi, u32 reg) { - return __raw_readl(tgi->regs + reg); + return readl_relaxed(tgi->regs + reg); } static unsigned int tegra_gpio_compose(unsigned int bank, unsigned int port, From f56d979cc58e9a361e0bf1b764fdadc85ee2d7c8 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 15 Dec 2019 21:30:46 +0300 Subject: [PATCH 15/48] gpio: tegra: Properly handle irq_set_irq_wake() error Technically upstream interrupt controller may fail changing of GPIO's bank wake-state and in this case the GPIO's wake-state shouldn't be changed. Signed-off-by: Dmitry Osipenko Reviewed-by: Thierry Reding Tested-by: Thierry Reding Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-tegra.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index f6a382fbd12d..4790dfec7758 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -497,6 +497,11 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); unsigned int gpio = d->hwirq; u32 port, bit, mask; + int err; + + err = irq_set_irq_wake(bank->irq, enable); + if (err) + return err; port = GPIO_PORT(gpio); bit = GPIO_BIT(gpio); @@ -507,7 +512,7 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) else bank->wake_enb[port] &= ~mask; - return irq_set_irq_wake(bank->irq, enable); + return 0; } #endif From 9ccaf106c2cf1591cdcc5434ef08d3edfbe06944 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 15 Dec 2019 21:30:47 +0300 Subject: [PATCH 16/48] gpio: tegra: Use NOIRQ phase for suspend/resume All GPIO interrupts are disabled during of the NOIRQ suspend/resume phase, thus there is no need to manually disable the interrupts. This patch doesn't fix any problem, this is just a minor clean-up. Signed-off-by: Dmitry Osipenko Reviewed-by: Thierry Reding Tested-by: Thierry Reding Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-tegra.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 4790dfec7758..acb99eff9939 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -416,11 +416,8 @@ static void tegra_gpio_irq_handler(struct irq_desc *desc) static int tegra_gpio_resume(struct device *dev) { struct tegra_gpio_info *tgi = dev_get_drvdata(dev); - unsigned long flags; unsigned int b, p; - local_irq_save(flags); - for (b = 0; b < tgi->bank_count; b++) { struct tegra_gpio_bank *bank = &tgi->bank_info[b]; @@ -448,17 +445,14 @@ static int tegra_gpio_resume(struct device *dev) } } - local_irq_restore(flags); return 0; } static int tegra_gpio_suspend(struct device *dev) { struct tegra_gpio_info *tgi = dev_get_drvdata(dev); - unsigned long flags; unsigned int b, p; - local_irq_save(flags); for (b = 0; b < tgi->bank_count; b++) { struct tegra_gpio_bank *bank = &tgi->bank_info[b]; @@ -488,7 +482,7 @@ static int tegra_gpio_suspend(struct device *dev) GPIO_INT_ENB(tgi, gpio)); } } - local_irq_restore(flags); + return 0; } @@ -562,7 +556,7 @@ static inline void tegra_gpio_debuginit(struct tegra_gpio_info *tgi) #endif static const struct dev_pm_ops tegra_gpio_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume) + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume) }; static int tegra_gpio_probe(struct platform_device *pdev) From 2ddac5ae1eaeb5da8e18749887e620d8566a80c9 Mon Sep 17 00:00:00 2001 From: "Enrico Weigelt, metux IT consult" Date: Sat, 4 Jan 2020 20:43:34 +0100 Subject: [PATCH 17/48] gpio: gpiolib: fix confusing indention There's a confusing indention in gpiochip_add_data_with_key(), which could be misinterpreted on a quick walkthrough. Fixing this in order to improve code readability a bit. Signed-off-by: Enrico Weigelt, metux IT consult Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 9913886ede90..2d8182d4bda5 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1444,7 +1444,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, if (chip->ngpio > FASTPATH_NGPIO) chip_warn(chip, "line cnt %u is greater than fast path cnt %u\n", - chip->ngpio, FASTPATH_NGPIO); + chip->ngpio, FASTPATH_NGPIO); gdev->label = kstrdup_const(chip->label ?: "unknown", GFP_KERNEL); if (!gdev->label) { From a9001764c6fad9baf24172a4f585f7dcd6214c04 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 24 Dec 2019 13:06:57 +0100 Subject: [PATCH 18/48] gpiolib: use 'unsigned int' instead of 'unsigned' in gpio_set_config() Checkpatch complains about using 'unsigned' instead of 'unsigned int'. Signed-off-by: Bartosz Golaszewski Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij --- drivers/gpio/gpiolib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 2d8182d4bda5..d43c6a2d40c4 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3042,7 +3042,7 @@ EXPORT_SYMBOL_GPL(gpiochip_free_own_desc); * rely on gpio_request() having been called beforehand. */ -static int gpio_set_config(struct gpio_chip *gc, unsigned offset, +static int gpio_set_config(struct gpio_chip *gc, unsigned int offset, enum pin_config_param mode) { unsigned long config; From d90f36851d6595136b461773846b76e0c45e3e0c Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 24 Dec 2019 13:06:58 +0100 Subject: [PATCH 19/48] gpiolib: have a single place of calling set_config() Instead of calling the gpiochip's set_config() callback directly and checking its existence every time - just add a new routine that performs this check internally. Call it in gpio_set_config() and gpiod_set_transitory(). Also call it in gpiod_set_debounce() and drop the check for chip->set() as it's irrelevant to this config option. Signed-off-by: Bartosz Golaszewski Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij --- drivers/gpio/gpiolib.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index d43c6a2d40c4..2260786994ac 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3042,6 +3042,15 @@ EXPORT_SYMBOL_GPL(gpiochip_free_own_desc); * rely on gpio_request() having been called beforehand. */ +static int gpio_do_set_config(struct gpio_chip *gc, unsigned int offset, + enum pin_config_param mode) +{ + if (!gc->set_config) + return -ENOTSUPP; + + return gc->set_config(gc, offset, mode); +} + static int gpio_set_config(struct gpio_chip *gc, unsigned int offset, enum pin_config_param mode) { @@ -3060,7 +3069,7 @@ static int gpio_set_config(struct gpio_chip *gc, unsigned int offset, } config = PIN_CONF_PACKED(mode, arg); - return gc->set_config ? gc->set_config(gc, offset, config) : -ENOTSUPP; + return gpio_do_set_config(gc, offset, mode); } static int gpio_set_bias(struct gpio_chip *chip, struct gpio_desc *desc) @@ -3294,15 +3303,9 @@ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) VALIDATE_DESC(desc); chip = desc->gdev->chip; - if (!chip->set || !chip->set_config) { - gpiod_dbg(desc, - "%s: missing set() or set_config() operations\n", - __func__); - return -ENOTSUPP; - } config = pinconf_to_config_packed(PIN_CONFIG_INPUT_DEBOUNCE, debounce); - return chip->set_config(chip, gpio_chip_hwgpio(desc), config); + return gpio_do_set_config(chip, gpio_chip_hwgpio(desc), config); } EXPORT_SYMBOL_GPL(gpiod_set_debounce); @@ -3339,7 +3342,7 @@ int gpiod_set_transitory(struct gpio_desc *desc, bool transitory) packed = pinconf_to_config_packed(PIN_CONFIG_PERSIST_STATE, !transitory); gpio = gpio_chip_hwgpio(desc); - rc = chip->set_config(chip, gpio, packed); + rc = gpio_do_set_config(chip, gpio, packed); if (rc == -ENOTSUPP) { dev_dbg(&desc->gdev->dev, "Persistence not supported for GPIO %d\n", gpio); From 06863620edfeadbe9e0ea5eb01dd94ce07f37549 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 24 Dec 2019 13:06:59 +0100 Subject: [PATCH 20/48] gpiolib: convert the type of hwnum to unsigned int in gpiochip_get_desc() gpiochip_get_desc() takes a u16 hwnum, but it turns out most users don't respect that and usually pass an unsigned int. Since implicit casting to a smaller type is dangerous - let's change the type of hwnum to unsigned int in gpiochip_get_desc() and in gpiochip_request_own_desc() where the size of hwnum is not respected either and who's a user of the former. This is safe as we then check the hwnum against the number of lines before proceeding in gpiochip_get_desc(). Signed-off-by: Bartosz Golaszewski Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij --- drivers/gpio/gpiolib.c | 5 +++-- drivers/gpio/gpiolib.h | 3 ++- include/linux/gpio/driver.h | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 2260786994ac..342c9604f46a 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -140,7 +140,7 @@ EXPORT_SYMBOL_GPL(gpio_to_desc); * in the given chip for the specified hardware number. */ struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, - u16 hwnum) + unsigned int hwnum) { struct gpio_device *gdev = chip->gpiodev; @@ -2990,7 +2990,8 @@ EXPORT_SYMBOL_GPL(gpiochip_is_requested); * A pointer to the GPIO descriptor, or an ERR_PTR()-encoded negative error * code on failure. */ -struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum, +struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, + unsigned int hwnum, const char *label, enum gpio_lookup_flags lflags, enum gpiod_flags dflags) diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index ca9bc1e4803c..a1cbeabadc69 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -78,7 +78,8 @@ struct gpio_array { unsigned long invert_mask[]; }; -struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum); +struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, + unsigned int hwnum); int gpiod_get_array_value_complex(bool raw, bool can_sleep, unsigned int array_size, struct gpio_desc **desc_array, diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index e2480ef94c55..4f032de10bae 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -715,7 +715,8 @@ gpiochip_remove_pin_ranges(struct gpio_chip *chip) #endif /* CONFIG_PINCTRL */ -struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, u16 hwnum, +struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *chip, + unsigned int hwnum, const char *label, enum gpio_lookup_flags lflags, enum gpiod_flags dflags); From 0f41dabe45df9fe68d3207c5b7af905db7c00ce4 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 24 Dec 2019 13:07:00 +0100 Subject: [PATCH 21/48] gpiolib: use gpiochip_get_desc() in linehandle_create() Unduplicate the ngpio check by simply calling gpiochip_get_desc() and checking its return value. Signed-off-by: Bartosz Golaszewski Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij --- drivers/gpio/gpiolib.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 342c9604f46a..166160cc9956 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -678,14 +678,13 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip) /* Request each GPIO */ for (i = 0; i < handlereq.lines; i++) { u32 offset = handlereq.lineoffsets[i]; - struct gpio_desc *desc; + struct gpio_desc *desc = gpiochip_get_desc(gdev->chip, offset); - if (offset >= gdev->ngpio) { - ret = -EINVAL; + if (IS_ERR(desc)) { + ret = PTR_ERR(desc); goto out_free_descs; } - desc = &gdev->descs[offset]; ret = gpiod_request(desc, lh->label); if (ret) goto out_free_descs; From 45e2360480b939173af70a2221ab63ffdaa1d325 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 24 Dec 2019 13:07:01 +0100 Subject: [PATCH 22/48] gpiolib: use gpiochip_get_desc() in lineevent_create() Unduplicate the ngpio check by simply calling gpiochip_get_desc() and checking its return value. Signed-off-by: Bartosz Golaszewski Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij --- drivers/gpio/gpiolib.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 166160cc9956..a11c4ee3e47f 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1009,8 +1009,9 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) lflags = eventreq.handleflags; eflags = eventreq.eventflags; - if (offset >= gdev->ngpio) - return -EINVAL; + desc = gpiochip_get_desc(gdev->chip, offset); + if (IS_ERR(desc)) + return PTR_ERR(desc); /* Return an error if a unknown flag is set */ if ((lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) || @@ -1048,7 +1049,6 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) } } - desc = &gdev->descs[offset]; ret = gpiod_request(desc, le->label); if (ret) goto out_free_label; From 2a2cabd8bc1715ceceb9d9566055f4a0a8ff749a Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 24 Dec 2019 13:07:02 +0100 Subject: [PATCH 23/48] gpiolib: use gpiochip_get_desc() in gpio_ioctl() Unduplicate the offset check by simply calling gpiochip_get_desc() and checking its return value. Signed-off-by: Bartosz Golaszewski Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij --- drivers/gpio/gpiolib.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index a11c4ee3e47f..5eef7ddddd0e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1175,10 +1175,11 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (copy_from_user(&lineinfo, ip, sizeof(lineinfo))) return -EFAULT; - if (lineinfo.line_offset >= gdev->ngpio) - return -EINVAL; - desc = &gdev->descs[lineinfo.line_offset]; + desc = gpiochip_get_desc(chip, lineinfo.line_offset); + if (IS_ERR(desc)) + return PTR_ERR(desc); + if (desc->name) { strncpy(lineinfo.name, desc->name, sizeof(lineinfo.name)); From 048ae7e8b5dbee053b208fd93d68bc2125fed03c Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Sat, 14 Dec 2019 12:49:13 +0100 Subject: [PATCH 24/48] fmc: remove left-over ipmi-fru.h after fmc deletion Commit 6a80b30086b8 ("fmc: Delete the FMC subsystem") from Linus Walleij deleted the obsolete FMC subsystem, but missed the MAINTAINERS entry and include/linux/ipmi-fru.h mentioned in the MAINTAINERS entry. Later, commit d5d4aa1ec198 ("MAINTAINERS: Remove FMC subsystem") from Denis Efremov cleaned up the MAINTAINERS entry, but actually also missed that include/linux/ipmi-fru.h should also be deleted while deleting its reference in MAINTAINERS. So, deleting include/linux/ipmi-fru.h slipped through the previous clean-ups. As there is no further use for include/linux/ipmi-fru.h, finally delete include/linux/ipmi-fru.h for good now. Fixes: d5d4aa1ec198 ("MAINTAINERS: Remove FMC subsystem") Fixes: 6a80b30086b8 ("fmc: Delete the FMC subsystem") Signed-off-by: Lukas Bulwahn Link: https://lore.kernel.org/r/20191214114913.8610-1-lukas.bulwahn@gmail.com Acked-by: Federico Vaga Signed-off-by: Linus Walleij --- include/linux/ipmi-fru.h | 134 --------------------------------------- 1 file changed, 134 deletions(-) delete mode 100644 include/linux/ipmi-fru.h diff --git a/include/linux/ipmi-fru.h b/include/linux/ipmi-fru.h deleted file mode 100644 index 05c9422624c6..000000000000 --- a/include/linux/ipmi-fru.h +++ /dev/null @@ -1,134 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2012 CERN (www.cern.ch) - * Author: Alessandro Rubini - * - * This work is part of the White Rabbit project, a research effort led - * by CERN, the European Institute for Nuclear Research. - */ -#ifndef __LINUX_IPMI_FRU_H__ -#define __LINUX_IPMI_FRU_H__ -#ifdef __KERNEL__ -# include -# include -#else -# include -# include -#endif - -/* - * These structures match the unaligned crap we have in FRU1011.pdf - * (http://download.intel.com/design/servers/ipmi/FRU1011.pdf) - */ - -/* chapter 8, page 5 */ -struct fru_common_header { - uint8_t format; /* 0x01 */ - uint8_t internal_use_off; /* multiple of 8 bytes */ - uint8_t chassis_info_off; /* multiple of 8 bytes */ - uint8_t board_area_off; /* multiple of 8 bytes */ - uint8_t product_area_off; /* multiple of 8 bytes */ - uint8_t multirecord_off; /* multiple of 8 bytes */ - uint8_t pad; /* must be 0 */ - uint8_t checksum; /* sum modulo 256 must be 0 */ -}; - -/* chapter 9, page 5 -- internal_use: not used by us */ - -/* chapter 10, page 6 -- chassis info: not used by us */ - -/* chapter 13, page 9 -- used by board_info_area below */ -struct fru_type_length { - uint8_t type_length; - uint8_t data[0]; -}; - -/* chapter 11, page 7 */ -struct fru_board_info_area { - uint8_t format; /* 0x01 */ - uint8_t area_len; /* multiple of 8 bytes */ - uint8_t language; /* I hope it's 0 */ - uint8_t mfg_date[3]; /* LSB, minutes since 1996-01-01 */ - struct fru_type_length tl[0]; /* type-length stuff follows */ - - /* - * the TL there are in order: - * Board Manufacturer - * Board Product Name - * Board Serial Number - * Board Part Number - * FRU File ID (may be null) - * more manufacturer-specific stuff - * 0xc1 as a terminator - * 0x00 pad to a multiple of 8 bytes - 1 - * checksum (sum of all stuff module 256 must be zero) - */ -}; - -enum fru_type { - FRU_TYPE_BINARY = 0x00, - FRU_TYPE_BCDPLUS = 0x40, - FRU_TYPE_ASCII6 = 0x80, - FRU_TYPE_ASCII = 0xc0, /* not ascii: depends on language */ -}; - -/* - * some helpers - */ -static inline struct fru_board_info_area *fru_get_board_area( - const struct fru_common_header *header) -{ - /* we know for sure that the header is 8 bytes in size */ - return (struct fru_board_info_area *)(header + header->board_area_off); -} - -static inline int fru_type(struct fru_type_length *tl) -{ - return tl->type_length & 0xc0; -} - -static inline int fru_length(struct fru_type_length *tl) -{ - return (tl->type_length & 0x3f) + 1; /* len of whole record */ -} - -/* assume ascii-latin1 encoding */ -static inline int fru_strlen(struct fru_type_length *tl) -{ - return fru_length(tl) - 1; -} - -static inline char *fru_strcpy(char *dest, struct fru_type_length *tl) -{ - int len = fru_strlen(tl); - memcpy(dest, tl->data, len); - dest[len] = '\0'; - return dest; -} - -static inline struct fru_type_length *fru_next_tl(struct fru_type_length *tl) -{ - return tl + fru_length(tl); -} - -static inline int fru_is_eof(struct fru_type_length *tl) -{ - return tl->type_length == 0xc1; -} - -/* - * External functions defined in fru-parse.c. - */ -extern int fru_header_cksum_ok(struct fru_common_header *header); -extern int fru_bia_cksum_ok(struct fru_board_info_area *bia); - -/* All these 4 return allocated strings by calling fru_alloc() */ -extern char *fru_get_board_manufacturer(struct fru_common_header *header); -extern char *fru_get_product_name(struct fru_common_header *header); -extern char *fru_get_serial_number(struct fru_common_header *header); -extern char *fru_get_part_number(struct fru_common_header *header); - -/* This must be defined by the caller of the above functions */ -extern void *fru_alloc(size_t size); - -#endif /* __LINUX_IMPI_FRU_H__ */ From 25d071b3f6dbe4c4b9c9d0df76fbe9292310e799 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Thu, 19 Dec 2019 21:14:59 +0800 Subject: [PATCH 25/48] gpio: gpio-grgpio: fix possible sleep-in-atomic-context bugs in grgpio_remove() drivers/gpio/gpiolib-sysfs.c, 796: mutex_lock in gpiochip_sysfs_unregister drivers/gpio/gpiolib.c, 1455: gpiochip_sysfs_unregister in gpiochip_remove drivers/gpio/gpio-grgpio.c, 460: gpiochip_remove in grgpio_remove drivers/gpio/gpio-grgpio.c, 449: _raw_spin_lock_irqsave in grgpio_remove kernel/irq/irqdomain.c, 243: mutex_lock in irq_domain_remove drivers/gpio/gpio-grgpio.c, 463: irq_domain_remove in grgpio_remove drivers/gpio/gpio-grgpio.c, 449: _raw_spin_lock_irqsave in grgpio_remove mutex_lock() can sleep at runtime. To fix these bugs, the lock is dropped in grgpio_remove(), because there is no need for locking in remove() callbacks. These bugs are found by a static analysis tool STCheck written by myself. Signed-off-by: Jia-Ju Bai Link: https://lore.kernel.org/r/20191219131459.18640-1-baijiaju1990@gmail.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-grgpio.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index 08234e64993a..a49f0711ca94 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -437,8 +437,6 @@ static int grgpio_remove(struct platform_device *ofdev) int i; int ret = 0; - spin_lock_irqsave(&priv->gc.bgpio_lock, flags); - if (priv->domain) { for (i = 0; i < GRGPIO_MAX_NGPIO; i++) { if (priv->uirqs[i].refcnt != 0) { @@ -454,8 +452,6 @@ static int grgpio_remove(struct platform_device *ofdev) irq_domain_remove(priv->domain); out: - spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); - return ret; } From e36eaf94be8f7bc4e686246eed3cf92d845e2ef8 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Wed, 18 Dec 2019 21:26:05 +0800 Subject: [PATCH 26/48] gpio: gpio-grgpio: fix possible sleep-in-atomic-context bugs in grgpio_irq_map/unmap() The driver may sleep while holding a spinlock. The function call path (from bottom to top) in Linux 4.19 is: drivers/gpio/gpio-grgpio.c, 261: request_irq in grgpio_irq_map drivers/gpio/gpio-grgpio.c, 255: _raw_spin_lock_irqsave in grgpio_irq_map drivers/gpio/gpio-grgpio.c, 318: free_irq in grgpio_irq_unmap drivers/gpio/gpio-grgpio.c, 299: _raw_spin_lock_irqsave in grgpio_irq_unmap request_irq() and free_irq() can sleep at runtime. To fix these bugs, request_irq() and free_irq() are called without holding the spinlock. These bugs are found by a static analysis tool STCheck written by myself. Signed-off-by: Jia-Ju Bai Link: https://lore.kernel.org/r/20191218132605.10594-1-baijiaju1990@gmail.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-grgpio.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index a49f0711ca94..1922adf96fc9 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -253,17 +253,16 @@ static int grgpio_irq_map(struct irq_domain *d, unsigned int irq, lirq->irq = irq; uirq = &priv->uirqs[lirq->index]; if (uirq->refcnt == 0) { + spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); ret = request_irq(uirq->uirq, grgpio_irq_handler, 0, dev_name(priv->dev), priv); if (ret) { dev_err(priv->dev, "Could not request underlying irq %d\n", uirq->uirq); - - spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); - return ret; } + spin_lock_irqsave(&priv->gc.bgpio_lock, flags); } uirq->refcnt++; @@ -309,8 +308,11 @@ static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq) if (index >= 0) { uirq = &priv->uirqs[lirq->index]; uirq->refcnt--; - if (uirq->refcnt == 0) + if (uirq->refcnt == 0) { + spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); free_irq(uirq->uirq, priv); + return; + } } spin_unlock_irqrestore(&priv->gc.bgpio_lock, flags); From 227caae52bcf245a5f6f73c3e26c3ef656735c5e Mon Sep 17 00:00:00 2001 From: Song Hui Date: Fri, 22 Nov 2019 14:18:39 +0800 Subject: [PATCH 27/48] gpio: mpc8xxx: ls1088a/ls1028a edge detection mode bug fixs. On these boards, the irq_set_type must point one valid function pointer that can correctly set both edge and falling edge. Signed-off-by: Song Hui Link: https://lore.kernel.org/r/20191122061839.24904-1-hui.song_1@nxp.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mpc8xxx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index f1e164cecff8..bd833f06b6c3 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -296,6 +296,7 @@ static const struct mpc8xxx_gpio_devtype mpc512x_gpio_devtype = { static const struct mpc8xxx_gpio_devtype ls1028a_gpio_devtype = { .gpio_dir_in_init = ls1028a_gpio_dir_in_init, + .irq_set_type = mpc8xxx_irq_set_type, }; static const struct mpc8xxx_gpio_devtype mpc5125_gpio_devtype = { From 970828901390ab7fdfa023fb8b6e5753613f8ae3 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 7 Jan 2020 22:24:32 +0100 Subject: [PATCH 28/48] gpio: Update TODO Drop the completed item: hierarchical irqchip helpers. Add motivation for gpio descriptor refactoring. Extend the list of stuff to do. Minor fixups. Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20200107212432.27587-1-linus.walleij@linaro.org --- drivers/gpio/TODO | 46 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/TODO b/drivers/gpio/TODO index 76f8c7ff18ff..3a44e6ae52bd 100644 --- a/drivers/gpio/TODO +++ b/drivers/gpio/TODO @@ -10,6 +10,28 @@ approach. This means that GPIO consumers, drivers and machine descriptions ideally have no use or idea of the global GPIO numberspace that has/was used in the inception of the GPIO subsystem. +The numberspace issue is the same as to why irq is moving away from irq +numbers to IRQ descriptors. + +The underlying motivation for this is that the GPIO numberspace has become +unmanageable: machine board files tend to become full of macros trying to +establish the numberspace at compile-time, making it hard to add any numbers +in the middle (such as if you missed a pin on a chip) without the numberspace +breaking. + +Machine descriptions such as device tree or ACPI does not have a concept of the +Linux GPIO number as those descriptions are external to the Linux kernel +and treat GPIO lines as abstract entities. + +The runtime-assigned GPIO numberspace (what you get if you assign the GPIO +base as -1 in struct gpio_chip) has also became unpredictable due to factors +such as probe ordering and the introduction of -EPROBE_DEFER making probe +ordering of independent GPIO chips essentially unpredictable, as their base +number will be assigned on a first come first serve basis. + +The best way to get out of the problem is to make the global GPIO numbers +unimportant by simply not using them. GPIO descriptors deal with this. + Work items: - Convert all GPIO device drivers to only #include @@ -33,7 +55,7 @@ This header and helpers appeared at one point when there was no proper driver infrastructure for doing simpler MMIO GPIO devices and there was no core support for parsing device tree GPIOs from the core library with the [devm_]gpiod_get() calls we have today that will implicitly go into -the device tree back-end. +the device tree back-end. It is legacy and should not be used in new code. Work items: @@ -59,6 +81,15 @@ Work items: uses or instead. +Get rid of + +This legacy header is a one stop shop for anything GPIO is closely tied +to the global GPIO numberspace. The endgame of the above refactorings will +be the removal of and from that point only the specialized +headers under will be used. This requires all the above to +be completed and is expected to take a long time. + + Collect drivers Collect GPIO drivers from arch/* and other places that should be placed @@ -109,7 +140,7 @@ try to cover any generic kind of irqchip cascaded from a GPIO. int irq; /* from platform etc */ struct my_gpio *g; - struct gpio_irq_chip *girq + struct gpio_irq_chip *girq; /* Set up the irqchip dynamically */ g->irq.name = "my_gpio_irq"; @@ -137,9 +168,14 @@ try to cover any generic kind of irqchip cascaded from a GPIO. - Look over and identify any remaining easily converted drivers and dry-code conversions to gpiolib irqchip for maintainers to test -- Support generic hierarchical GPIO interrupts: these are for the - non-cascading case where there is one IRQ per GPIO line, there is - currently no common infrastructure for this. +- Drop gpiochip_set_chained_irqchip() when all the chained irqchips + have been converted to the above infrastructure. + +- Add more infrastructure to make it possible to also pass a threaded + irqchip in struct gpio_irq_chip. + +- Drop gpiochip_irqchip_add_nested() when all the chained irqchips + have been converted to the above infrastructure. Increase integration with pin control From 1e4d149e901769fcde71be039227d184c6e4fda9 Mon Sep 17 00:00:00 2001 From: "Ooi, Joyce" Date: Thu, 9 Jan 2020 00:16:20 +0800 Subject: [PATCH 29/48] gpio: altera: change to platform_get_irq_optional to avoid false-positive error This patch switches to platform_get_irq_optional() from platform_get_irq() as it causes a false-positive error such as 'IRQ index 0 not found' when IRQ is not used. The IRQ usage is optional in this gpio-altera driver, so the error log is undesirable. Signed-off-by: Ooi, Joyce Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-altera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c index 9f2e6b04c361..cc4ba71e4fe3 100644 --- a/drivers/gpio/gpio-altera.c +++ b/drivers/gpio/gpio-altera.c @@ -266,7 +266,7 @@ static int altera_gpio_probe(struct platform_device *pdev) altera_gc->mmchip.gc.owner = THIS_MODULE; altera_gc->mmchip.gc.parent = &pdev->dev; - altera_gc->mapped_irq = platform_get_irq(pdev, 0); + altera_gc->mapped_irq = platform_get_irq_optional(pdev, 0); if (altera_gc->mapped_irq < 0) goto skip_irq; From b0d126e1d64e76f165dc9ce6a4b02497c48053fb Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 7 Jan 2020 13:08:43 +0000 Subject: [PATCH 30/48] dt-bindings: gpio: wcd934x: Add bindings for gpio Qualcomm Technologies Inc WCD9340/WCD9341 Audio Codec has integrated gpio controller to control 5 gpios on the chip. This patch adds required device tree bindings for it. Signed-off-by: Srinivas Kandagatla Reviewed-by: Rob Herring Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20200107130844.20763-2-srinivas.kandagatla@linaro.org Signed-off-by: Linus Walleij --- .../bindings/gpio/qcom,wcd934x-gpio.yaml | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/qcom,wcd934x-gpio.yaml diff --git a/Documentation/devicetree/bindings/gpio/qcom,wcd934x-gpio.yaml b/Documentation/devicetree/bindings/gpio/qcom,wcd934x-gpio.yaml new file mode 100644 index 000000000000..32a566ec3558 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/qcom,wcd934x-gpio.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpio/qcom,wcd934x-gpio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: WCD9340/WCD9341 GPIO controller + +maintainers: + - Srinivas Kandagatla + +description: | + Qualcomm Technologies Inc WCD9340/WCD9341 Audio Codec has integrated + gpio controller to control 5 gpios on the chip. + +properties: + compatible: + enum: + - qcom,wcd9340-gpio + - qcom,wcd9341-gpio + + reg: + maxItems: 1 + + gpio-controller: true + + '#gpio-cells': + const: 2 + +required: + - compatible + - reg + - gpio-controller + - "#gpio-cells" + +additionalProperties: false + +examples: + - | + wcdgpio: gpio@42 { + compatible = "qcom,wcd9340-gpio"; + reg = <0x042 0x2>; + gpio-controller; + #gpio-cells = <2>; + }; + +... From ddb4e53fc72ec907f99199749cb4c71af4794607 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 8 Jan 2020 01:17:12 +0100 Subject: [PATCH 31/48] gpio: Add use guidance documentation The text in this new document is a response to recurring questions about the GPIO in-kernel API vs the userspace ABI. When do you use one or the other? It can be a bit intuitive, but I tried to sum it all up. Reviewed-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20200108001712.47500-1-linus.walleij@linaro.org Signed-off-by: Linus Walleij --- .../driver-api/gpio/drivers-on-gpio.rst | 8 +-- Documentation/driver-api/gpio/index.rst | 1 + Documentation/driver-api/gpio/using-gpio.rst | 50 +++++++++++++++++++ 3 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 Documentation/driver-api/gpio/using-gpio.rst diff --git a/Documentation/driver-api/gpio/drivers-on-gpio.rst b/Documentation/driver-api/gpio/drivers-on-gpio.rst index f3a189320e11..820b403d50f6 100644 --- a/Documentation/driver-api/gpio/drivers-on-gpio.rst +++ b/Documentation/driver-api/gpio/drivers-on-gpio.rst @@ -95,7 +95,7 @@ to emulate MCTRL (modem control) signals CTS/RTS by using two GPIO lines. The MTD NOR flash has add-ons for extra GPIO lines too, though the address bus is usually connected directly to the flash. -Use those instead of talking directly to the GPIOs using sysfs; they integrate -with kernel frameworks better than your userspace code could. Needless to say, -just using the appropriate kernel drivers will simplify and speed up your -embedded hacking in particular by providing ready-made components. +Use those instead of talking directly to the GPIOs from userspace; they +integrate with kernel frameworks better than your userspace code could. +Needless to say, just using the appropriate kernel drivers will simplify and +speed up your embedded hacking in particular by providing ready-made components. diff --git a/Documentation/driver-api/gpio/index.rst b/Documentation/driver-api/gpio/index.rst index 5b61032aa4ea..1d48fe248f05 100644 --- a/Documentation/driver-api/gpio/index.rst +++ b/Documentation/driver-api/gpio/index.rst @@ -8,6 +8,7 @@ Contents: :maxdepth: 2 intro + using-gpio driver consumer board diff --git a/Documentation/driver-api/gpio/using-gpio.rst b/Documentation/driver-api/gpio/using-gpio.rst new file mode 100644 index 000000000000..dda069444032 --- /dev/null +++ b/Documentation/driver-api/gpio/using-gpio.rst @@ -0,0 +1,50 @@ +========================= +Using GPIO Lines in Linux +========================= + +The Linux kernel exists to abstract and present hardware to users. GPIO lines +as such are normally not user facing abstractions. The most obvious, natural +and preferred way to use GPIO lines is to let kernel hardware drivers deal +with them. + +For examples of already existing generic drivers that will also be good +examples for any other kernel drivers you want to author, refer to +:doc:`drivers-on-gpio` + +For any kind of mass produced system you want to support, such as servers, +laptops, phones, tablets, routers, and any consumer or office or business goods +using appropriate kernel drivers is paramount. Submit your code for inclusion +in the upstream Linux kernel when you feel it is mature enough and you will get +help to refine it, see :doc:`../../process/submitting-patches`. + +In Linux GPIO lines also have a userspace ABI. + +The userspace ABI is intended for one-off deployments. Examples are prototypes, +factory lines, maker community projects, workshop specimen, production tools, +industrial automation, PLC-type use cases, door controllers, in short a piece +of specialized equipment that is not produced by the numbers, requiring +operators to have a deep knowledge of the equipment and knows about the +software-hardware interface to be set up. They should not have a natural fit +to any existing kernel subsystem and not be a good fit for an operating system, +because of not being reusable or abstract enough, or involving a lot of non +computer hardware related policy. + +Applications that have a good reason to use the industrial I/O (IIO) subsystem +from userspace will likely be a good fit for using GPIO lines from userspace as +well. + +Do not under any circumstances abuse the GPIO userspace ABI to cut corners in +any product development projects. If you use it for prototyping, then do not +productify the prototype: rewrite it using proper kernel drivers. Do not under +any circumstances deploy any uniform products using GPIO from userspace. + +The userspace ABI is a character device for each GPIO hardware unit (GPIO chip). +These devices will appear on the system as ``/dev/gpiochip0`` thru +``/dev/gpiochipN``. Examples of how to directly use the userspace ABI can be +found in the kernel tree ``tools/gpio`` subdirectory. + +For structured and managed applications, we recommend that you make use of the +libgpiod_ library. This provides helper abstractions, command line utlities +and arbitration for multiple simultaneous consumers on the same GPIO chip. + +.. _libgpiod: https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/ From 242587616710576808dc8d7cdf18cfe0d7bf9831 Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Tue, 14 Jan 2020 16:28:19 +0800 Subject: [PATCH 32/48] gpiolib: Add support for the irqdomain which doesn't use irq_fwspec as arg Some gpio's parent irqdomain may not use the struct irq_fwspec as argument, such as msi irqdomain. So rename the callback populate_parent_fwspec() to populate_parent_alloc_arg() and make it allocate and populate the specific struct which is needed by the parent irqdomain. Signed-off-by: Kevin Hao Link: https://lore.kernel.org/r/20200114082821.14015-3-haokexin@gmail.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tegra186.c | 13 +++++-- drivers/gpio/gpiolib.c | 45 +++++++++++++++--------- drivers/pinctrl/qcom/pinctrl-spmi-gpio.c | 2 +- drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c | 2 +- include/linux/gpio/driver.h | 21 +++++------ 5 files changed, 49 insertions(+), 34 deletions(-) diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index 55b43b7ce88d..de241263d4be 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -448,17 +448,24 @@ static int tegra186_gpio_irq_domain_translate(struct irq_domain *domain, return 0; } -static void tegra186_gpio_populate_parent_fwspec(struct gpio_chip *chip, - struct irq_fwspec *fwspec, +static void *tegra186_gpio_populate_parent_fwspec(struct gpio_chip *chip, unsigned int parent_hwirq, unsigned int parent_type) { struct tegra_gpio *gpio = gpiochip_get_data(chip); + struct irq_fwspec *fwspec; + fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL); + if (!fwspec) + return NULL; + + fwspec->fwnode = chip->irq.parent_domain->fwnode; fwspec->param_count = 3; fwspec->param[0] = gpio->soc->instance; fwspec->param[1] = parent_hwirq; fwspec->param[2] = parent_type; + + return fwspec; } static int tegra186_gpio_child_to_parent_hwirq(struct gpio_chip *chip, @@ -621,7 +628,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev) irq->chip = &gpio->intc; irq->fwnode = of_node_to_fwnode(pdev->dev.of_node); irq->child_to_parent_hwirq = tegra186_gpio_child_to_parent_hwirq; - irq->populate_parent_fwspec = tegra186_gpio_populate_parent_fwspec; + irq->populate_parent_alloc_arg = tegra186_gpio_populate_parent_fwspec; irq->child_offset_to_irq = tegra186_gpio_child_offset_to_irq; irq->child_irq_domain_ops.translate = tegra186_gpio_irq_domain_translate; irq->handler = handle_simple_irq; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 78a16e42f222..e0200dda2aee 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2003,7 +2003,7 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d, irq_hw_number_t hwirq; unsigned int type = IRQ_TYPE_NONE; struct irq_fwspec *fwspec = data; - struct irq_fwspec parent_fwspec; + void *parent_arg; unsigned int parent_hwirq; unsigned int parent_type; struct gpio_irq_chip *girq = &gc->irq; @@ -2042,23 +2042,20 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d, NULL, NULL); irq_set_probe(irq); - /* - * Create a IRQ fwspec to send up to the parent irqdomain: - * specify the hwirq we address on the parent and tie it - * all together up the chain. - */ - parent_fwspec.fwnode = d->parent->fwnode; /* This parent only handles asserted level IRQs */ - girq->populate_parent_fwspec(gc, &parent_fwspec, parent_hwirq, - parent_type); + parent_arg = girq->populate_parent_alloc_arg(gc, parent_hwirq, parent_type); + if (!parent_arg) + return -ENOMEM; + chip_info(gc, "alloc_irqs_parent for %d parent hwirq %d\n", irq, parent_hwirq); - ret = irq_domain_alloc_irqs_parent(d, irq, 1, &parent_fwspec); + ret = irq_domain_alloc_irqs_parent(d, irq, 1, parent_arg); if (ret) chip_err(gc, "failed to allocate parent hwirq %d for hwirq %lu\n", parent_hwirq, hwirq); + kfree(parent_arg); return ret; } @@ -2095,8 +2092,8 @@ static int gpiochip_hierarchy_add_domain(struct gpio_chip *gc) if (!gc->irq.child_offset_to_irq) gc->irq.child_offset_to_irq = gpiochip_child_offset_to_irq_noop; - if (!gc->irq.populate_parent_fwspec) - gc->irq.populate_parent_fwspec = + if (!gc->irq.populate_parent_alloc_arg) + gc->irq.populate_parent_alloc_arg = gpiochip_populate_parent_fwspec_twocell; gpiochip_hierarchy_setup_domain_ops(&gc->irq.child_irq_domain_ops); @@ -2122,27 +2119,43 @@ static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc) return !!gc->irq.parent_domain; } -void gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip, - struct irq_fwspec *fwspec, +void *gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip, unsigned int parent_hwirq, unsigned int parent_type) { + struct irq_fwspec *fwspec; + + fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL); + if (!fwspec) + return NULL; + + fwspec->fwnode = chip->irq.parent_domain->fwnode; fwspec->param_count = 2; fwspec->param[0] = parent_hwirq; fwspec->param[1] = parent_type; + + return fwspec; } EXPORT_SYMBOL_GPL(gpiochip_populate_parent_fwspec_twocell); -void gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *chip, - struct irq_fwspec *fwspec, +void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *chip, unsigned int parent_hwirq, unsigned int parent_type) { + struct irq_fwspec *fwspec; + + fwspec = kmalloc(sizeof(*fwspec), GFP_KERNEL); + if (!fwspec) + return NULL; + + fwspec->fwnode = chip->irq.parent_domain->fwnode; fwspec->param_count = 4; fwspec->param[0] = 0; fwspec->param[1] = parent_hwirq; fwspec->param[2] = 0; fwspec->param[3] = parent_type; + + return fwspec; } EXPORT_SYMBOL_GPL(gpiochip_populate_parent_fwspec_fourcell); diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index 653d1095bfea..fe0be8a6ebb7 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -1060,7 +1060,7 @@ static int pmic_gpio_probe(struct platform_device *pdev) girq->fwnode = of_node_to_fwnode(state->dev->of_node); girq->parent_domain = parent_domain; girq->child_to_parent_hwirq = pmic_gpio_child_to_parent_hwirq; - girq->populate_parent_fwspec = gpiochip_populate_parent_fwspec_fourcell; + girq->populate_parent_alloc_arg = gpiochip_populate_parent_fwspec_fourcell; girq->child_offset_to_irq = pmic_gpio_child_offset_to_irq; girq->child_irq_domain_ops.translate = pmic_gpio_domain_translate; diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c index dca86886b1f9..73d986a903f1 100644 --- a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c @@ -794,7 +794,7 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev) girq->fwnode = of_node_to_fwnode(pctrl->dev->of_node); girq->parent_domain = parent_domain; girq->child_to_parent_hwirq = pm8xxx_child_to_parent_hwirq; - girq->populate_parent_fwspec = gpiochip_populate_parent_fwspec_fourcell; + girq->populate_parent_alloc_arg = gpiochip_populate_parent_fwspec_fourcell; girq->child_offset_to_irq = pm8xxx_child_offset_to_irq; girq->child_irq_domain_ops.translate = pm8xxx_domain_translate; diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index e2480ef94c55..9bb43467ed11 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -94,16 +94,15 @@ struct gpio_irq_chip { unsigned int *parent_type); /** - * @populate_parent_fwspec: + * @populate_parent_alloc_arg : * - * This optional callback populates the &struct irq_fwspec for the - * parent's IRQ domain. If this is not specified, then + * This optional callback allocates and populates the specific struct + * for the parent's IRQ domain. If this is not specified, then * &gpiochip_populate_parent_fwspec_twocell will be used. A four-cell * variant named &gpiochip_populate_parent_fwspec_fourcell is also * available. */ - void (*populate_parent_fwspec)(struct gpio_chip *chip, - struct irq_fwspec *fwspec, + void *(*populate_parent_alloc_arg)(struct gpio_chip *chip, unsigned int parent_hwirq, unsigned int parent_type); @@ -537,26 +536,22 @@ struct bgpio_pdata { #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY -void gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip, - struct irq_fwspec *fwspec, +void *gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip, unsigned int parent_hwirq, unsigned int parent_type); -void gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *chip, - struct irq_fwspec *fwspec, +void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *chip, unsigned int parent_hwirq, unsigned int parent_type); #else -static inline void gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip, - struct irq_fwspec *fwspec, +static inline void *gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *chip, unsigned int parent_hwirq, unsigned int parent_type) { } -static inline void gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *chip, - struct irq_fwspec *fwspec, +static inline void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *chip, unsigned int parent_hwirq, unsigned int parent_type) { From 880b7cf22e8ca08abd969b0f1c65a79121e025c5 Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Tue, 14 Jan 2020 16:28:20 +0800 Subject: [PATCH 33/48] gpiolib: Add the support for the msi parent domain If the gpio's parent irqdomain is a msi irqdomain, we should ignore the EEXIST error returned by the msi irqdomain because all the msi interrupts have already been allocated. Signed-off-by: Kevin Hao Link: https://lore.kernel.org/r/20200114082821.14015-4-haokexin@gmail.com Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e0200dda2aee..4b94b9e37fdb 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2050,6 +2050,12 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d, chip_info(gc, "alloc_irqs_parent for %d parent hwirq %d\n", irq, parent_hwirq); ret = irq_domain_alloc_irqs_parent(d, irq, 1, parent_arg); + /* + * If the parent irqdomain is msi, the interrupts have already + * been allocated, so the EEXIST is good. + */ + if (irq_domain_is_msi(d->parent) && (ret == -EEXIST)) + ret = 0; if (ret) chip_err(gc, "failed to allocate parent hwirq %d for hwirq %lu\n", From 7a9f4460f74d705014aaab1900be688d20c75909 Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Tue, 14 Jan 2020 16:28:21 +0800 Subject: [PATCH 34/48] gpio: thunderx: Switch to GPIOLIB_IRQCHIP The main parts of this patch are from commit a7fc89f9d5fc ("gpio: thunderx: Switch to GPIOLIB_IRQCHIP") and patch [1]. And also adjust thunderx_gpio_child_to_parent_hwirq() and add thunderx_gpio_populate_parent_alloc_info() to make sure that the correct hwirq are passed to the parent msi irqdomain. [1] https://patchwork.ozlabs.org/patch/1210180/ Signed-off-by: Kevin Hao Link: https://lore.kernel.org/r/20200114082821.14015-5-haokexin@gmail.com Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-thunderx.c | 177 +++++++++++++++-------------------- 2 files changed, 78 insertions(+), 100 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 4b6d2ef15c39..2ed599236a1c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -573,6 +573,7 @@ config GPIO_THUNDERX tristate "Cavium ThunderX/OCTEON-TX GPIO" depends on ARCH_THUNDER || (64BIT && COMPILE_TEST) depends on PCI_MSI + select GPIOLIB_IRQCHIP select IRQ_DOMAIN_HIERARCHY select IRQ_FASTEOI_HIERARCHY_HANDLERS help diff --git a/drivers/gpio/gpio-thunderx.c b/drivers/gpio/gpio-thunderx.c index 462770479045..9f66deab46ea 100644 --- a/drivers/gpio/gpio-thunderx.c +++ b/drivers/gpio/gpio-thunderx.c @@ -15,6 +15,7 @@ #include #include #include +#include #define GPIO_RX_DAT 0x0 @@ -53,7 +54,6 @@ struct thunderx_line { struct thunderx_gpio { struct gpio_chip chip; u8 __iomem *register_base; - struct irq_domain *irqd; struct msix_entry *msix_entries; /* per line MSI-X */ struct thunderx_line *line_entries; /* per line irq info */ raw_spinlock_t lock; @@ -286,54 +286,60 @@ static void thunderx_gpio_set_multiple(struct gpio_chip *chip, } } -static void thunderx_gpio_irq_ack(struct irq_data *data) +static void thunderx_gpio_irq_ack(struct irq_data *d) { - struct thunderx_line *txline = irq_data_get_irq_chip_data(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct thunderx_gpio *txgpio = gpiochip_get_data(gc); writeq(GPIO_INTR_INTR, - txline->txgpio->register_base + intr_reg(txline->line)); + txgpio->register_base + intr_reg(irqd_to_hwirq(d))); } -static void thunderx_gpio_irq_mask(struct irq_data *data) +static void thunderx_gpio_irq_mask(struct irq_data *d) { - struct thunderx_line *txline = irq_data_get_irq_chip_data(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct thunderx_gpio *txgpio = gpiochip_get_data(gc); writeq(GPIO_INTR_ENA_W1C, - txline->txgpio->register_base + intr_reg(txline->line)); + txgpio->register_base + intr_reg(irqd_to_hwirq(d))); } -static void thunderx_gpio_irq_mask_ack(struct irq_data *data) +static void thunderx_gpio_irq_mask_ack(struct irq_data *d) { - struct thunderx_line *txline = irq_data_get_irq_chip_data(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct thunderx_gpio *txgpio = gpiochip_get_data(gc); writeq(GPIO_INTR_ENA_W1C | GPIO_INTR_INTR, - txline->txgpio->register_base + intr_reg(txline->line)); + txgpio->register_base + intr_reg(irqd_to_hwirq(d))); } -static void thunderx_gpio_irq_unmask(struct irq_data *data) +static void thunderx_gpio_irq_unmask(struct irq_data *d) { - struct thunderx_line *txline = irq_data_get_irq_chip_data(data); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct thunderx_gpio *txgpio = gpiochip_get_data(gc); writeq(GPIO_INTR_ENA_W1S, - txline->txgpio->register_base + intr_reg(txline->line)); + txgpio->register_base + intr_reg(irqd_to_hwirq(d))); } -static int thunderx_gpio_irq_set_type(struct irq_data *data, +static int thunderx_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type) { - struct thunderx_line *txline = irq_data_get_irq_chip_data(data); - struct thunderx_gpio *txgpio = txline->txgpio; + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct thunderx_gpio *txgpio = gpiochip_get_data(gc); + struct thunderx_line *txline = + &txgpio->line_entries[irqd_to_hwirq(d)]; u64 bit_cfg; - irqd_set_trigger_type(data, flow_type); + irqd_set_trigger_type(d, flow_type); bit_cfg = txline->fil_bits | GPIO_BIT_CFG_INT_EN; if (flow_type & IRQ_TYPE_EDGE_BOTH) { - irq_set_handler_locked(data, handle_fasteoi_ack_irq); + irq_set_handler_locked(d, handle_fasteoi_ack_irq); bit_cfg |= GPIO_BIT_CFG_INT_TYPE; } else { - irq_set_handler_locked(data, handle_fasteoi_mask_irq); + irq_set_handler_locked(d, handle_fasteoi_mask_irq); } raw_spin_lock(&txgpio->lock); @@ -362,33 +368,6 @@ static void thunderx_gpio_irq_disable(struct irq_data *data) irq_chip_disable_parent(data); } -static int thunderx_gpio_irq_request_resources(struct irq_data *data) -{ - struct thunderx_line *txline = irq_data_get_irq_chip_data(data); - struct thunderx_gpio *txgpio = txline->txgpio; - int r; - - r = gpiochip_lock_as_irq(&txgpio->chip, txline->line); - if (r) - return r; - - r = irq_chip_request_resources_parent(data); - if (r) - gpiochip_unlock_as_irq(&txgpio->chip, txline->line); - - return r; -} - -static void thunderx_gpio_irq_release_resources(struct irq_data *data) -{ - struct thunderx_line *txline = irq_data_get_irq_chip_data(data); - struct thunderx_gpio *txgpio = txline->txgpio; - - irq_chip_release_resources_parent(data); - - gpiochip_unlock_as_irq(&txgpio->chip, txline->line); -} - /* * Interrupts are chained from underlying MSI-X vectors. We have * these irq_chip functions to be able to handle level triggering @@ -405,48 +384,42 @@ static struct irq_chip thunderx_gpio_irq_chip = { .irq_unmask = thunderx_gpio_irq_unmask, .irq_eoi = irq_chip_eoi_parent, .irq_set_affinity = irq_chip_set_affinity_parent, - .irq_request_resources = thunderx_gpio_irq_request_resources, - .irq_release_resources = thunderx_gpio_irq_release_resources, .irq_set_type = thunderx_gpio_irq_set_type, .flags = IRQCHIP_SET_TYPE_MASKED }; -static int thunderx_gpio_irq_translate(struct irq_domain *d, - struct irq_fwspec *fwspec, - irq_hw_number_t *hwirq, - unsigned int *type) +static int thunderx_gpio_child_to_parent_hwirq(struct gpio_chip *gc, + unsigned int child, + unsigned int child_type, + unsigned int *parent, + unsigned int *parent_type) { - struct thunderx_gpio *txgpio = d->host_data; + struct thunderx_gpio *txgpio = gpiochip_get_data(gc); + struct irq_data *irqd; + unsigned int irq; - if (WARN_ON(fwspec->param_count < 2)) + irq = txgpio->msix_entries[child].vector; + irqd = irq_domain_get_irq_data(gc->irq.parent_domain, irq); + if (!irqd) return -EINVAL; - if (fwspec->param[0] >= txgpio->chip.ngpio) - return -EINVAL; - *hwirq = fwspec->param[0]; - *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; + *parent = irqd_to_hwirq(irqd); + *parent_type = IRQ_TYPE_LEVEL_HIGH; return 0; } -static int thunderx_gpio_irq_alloc(struct irq_domain *d, unsigned int virq, - unsigned int nr_irqs, void *arg) +static void *thunderx_gpio_populate_parent_alloc_info(struct gpio_chip *chip, + unsigned int parent_hwirq, + unsigned int parent_type) { - struct thunderx_line *txline = arg; + msi_alloc_info_t *info; - return irq_domain_set_hwirq_and_chip(d, virq, txline->line, - &thunderx_gpio_irq_chip, txline); -} + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return NULL; -static const struct irq_domain_ops thunderx_gpio_irqd_ops = { - .alloc = thunderx_gpio_irq_alloc, - .translate = thunderx_gpio_irq_translate -}; - -static int thunderx_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) -{ - struct thunderx_gpio *txgpio = gpiochip_get_data(chip); - - return irq_find_mapping(txgpio->irqd, offset); + info->hwirq = parent_hwirq; + return info; } static int thunderx_gpio_probe(struct pci_dev *pdev, @@ -456,6 +429,7 @@ static int thunderx_gpio_probe(struct pci_dev *pdev, struct device *dev = &pdev->dev; struct thunderx_gpio *txgpio; struct gpio_chip *chip; + struct gpio_irq_chip *girq; int ngpio, i; int err = 0; @@ -500,8 +474,8 @@ static int thunderx_gpio_probe(struct pci_dev *pdev, } txgpio->msix_entries = devm_kcalloc(dev, - ngpio, sizeof(struct msix_entry), - GFP_KERNEL); + ngpio, sizeof(struct msix_entry), + GFP_KERNEL); if (!txgpio->msix_entries) { err = -ENOMEM; goto out; @@ -542,27 +516,6 @@ static int thunderx_gpio_probe(struct pci_dev *pdev, if (err < 0) goto out; - /* - * Push GPIO specific irqdomain on hierarchy created as a side - * effect of the pci_enable_msix() - */ - txgpio->irqd = irq_domain_create_hierarchy(irq_get_irq_data(txgpio->msix_entries[0].vector)->domain, - 0, 0, of_node_to_fwnode(dev->of_node), - &thunderx_gpio_irqd_ops, txgpio); - if (!txgpio->irqd) { - err = -ENOMEM; - goto out; - } - - /* Push on irq_data and the domain for each line. */ - for (i = 0; i < ngpio; i++) { - err = irq_domain_push_irq(txgpio->irqd, - txgpio->msix_entries[i].vector, - &txgpio->line_entries[i]); - if (err < 0) - dev_err(dev, "irq_domain_push_irq: %d\n", err); - } - chip->label = KBUILD_MODNAME; chip->parent = dev; chip->owner = THIS_MODULE; @@ -577,11 +530,35 @@ static int thunderx_gpio_probe(struct pci_dev *pdev, chip->set = thunderx_gpio_set; chip->set_multiple = thunderx_gpio_set_multiple; chip->set_config = thunderx_gpio_set_config; - chip->to_irq = thunderx_gpio_to_irq; + girq = &chip->irq; + girq->chip = &thunderx_gpio_irq_chip; + girq->fwnode = of_node_to_fwnode(dev->of_node); + girq->parent_domain = + irq_get_irq_data(txgpio->msix_entries[0].vector)->domain; + girq->child_to_parent_hwirq = thunderx_gpio_child_to_parent_hwirq; + girq->populate_parent_alloc_arg = thunderx_gpio_populate_parent_alloc_info; + girq->handler = handle_bad_irq; + girq->default_type = IRQ_TYPE_NONE; + err = devm_gpiochip_add_data(dev, chip, txgpio); if (err) goto out; + /* Push on irq_data and the domain for each line. */ + for (i = 0; i < ngpio; i++) { + struct irq_fwspec fwspec; + + fwspec.fwnode = of_node_to_fwnode(dev->of_node); + fwspec.param_count = 2; + fwspec.param[0] = i; + fwspec.param[1] = IRQ_TYPE_NONE; + err = irq_domain_push_irq(girq->domain, + txgpio->msix_entries[i].vector, + &fwspec); + if (err < 0) + dev_err(dev, "irq_domain_push_irq: %d\n", err); + } + dev_info(dev, "ThunderX GPIO: %d lines with base %d.\n", ngpio, chip->base); return 0; @@ -596,10 +573,10 @@ static void thunderx_gpio_remove(struct pci_dev *pdev) struct thunderx_gpio *txgpio = pci_get_drvdata(pdev); for (i = 0; i < txgpio->chip.ngpio; i++) - irq_domain_pop_irq(txgpio->irqd, + irq_domain_pop_irq(txgpio->chip.irq.domain, txgpio->msix_entries[i].vector); - irq_domain_remove(txgpio->irqd); + irq_domain_remove(txgpio->chip.irq.domain); pci_set_drvdata(pdev, NULL); } From c34f6dc8c9e6bbe9fba1d53acd6d9a3889599da3 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 14 Jan 2020 15:11:03 -0800 Subject: [PATCH 35/48] gpiolib: Set lockdep class for hierarchical irq domains I see the following lockdep splat in the qcom pinctrl driver when attempting to suspend the device. ============================================ WARNING: possible recursive locking detected 5.4.2 #2 Tainted: G S -------------------------------------------- cat/6536 is trying to acquire lock: ffffff814787ccc0 (&irq_desc_lock_class){-.-.}, at: __irq_get_desc_lock+0x64/0x94 but task is already holding lock: ffffff81436740c0 (&irq_desc_lock_class){-.-.}, at: __irq_get_desc_lock+0x64/0x94 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(&irq_desc_lock_class); lock(&irq_desc_lock_class); *** DEADLOCK *** May be due to missing lock nesting notation 7 locks held by cat/6536: #0: ffffff8140e0c420 (sb_writers#7){.+.+}, at: vfs_write+0xc8/0x19c #1: ffffff8121eec480 (&of->mutex){+.+.}, at: kernfs_fop_write+0x128/0x1f4 #2: ffffff8147cad668 (kn->count#263){.+.+}, at: kernfs_fop_write+0x130/0x1f4 #3: ffffffd011446000 (system_transition_mutex){+.+.}, at: pm_suspend+0x108/0x354 #4: ffffff814302b970 (&dev->mutex){....}, at: __device_suspend+0x16c/0x420 #5: ffffff81436740c0 (&irq_desc_lock_class){-.-.}, at: __irq_get_desc_lock+0x64/0x94 #6: ffffff81479b8c10 (&pctrl->lock){....}, at: msm_gpio_irq_set_wake+0x48/0x7c stack backtrace: CPU: 4 PID: 6536 Comm: cat Tainted: G S 5.4.2 #2 Call trace: dump_backtrace+0x0/0x174 show_stack+0x20/0x2c dump_stack+0xdc/0x144 __lock_acquire+0x52c/0x2268 lock_acquire+0x1dc/0x220 _raw_spin_lock_irqsave+0x64/0x80 __irq_get_desc_lock+0x64/0x94 irq_set_irq_wake+0x40/0x144 msm_gpio_irq_set_wake+0x5c/0x7c set_irq_wake_real+0x40/0x5c irq_set_irq_wake+0x70/0x144 cros_ec_rtc_suspend+0x38/0x4c platform_pm_suspend+0x34/0x60 dpm_run_callback+0x64/0xcc __device_suspend+0x314/0x420 dpm_suspend+0xf8/0x298 dpm_suspend_start+0x84/0xb4 suspend_devices_and_enter+0xbc/0x628 pm_suspend+0x214/0x354 state_store+0xb0/0x108 kobj_attr_store+0x14/0x24 sysfs_kf_write+0x4c/0x64 kernfs_fop_write+0x158/0x1f4 __vfs_write+0x54/0x18c vfs_write+0xdc/0x19c ksys_write+0x7c/0xe4 __arm64_sys_write+0x20/0x2c el0_svc_common+0xa8/0x160 el0_svc_compat_handler+0x2c/0x38 el0_svc_compat+0x8/0x10 This is because the msm_gpio_irq_set_wake() function calls irq_set_irq_wake() as a backup in case the irq comes in during the path to idle. Given that we're calling irqchip functions from within an irqchip we need to set the lockdep class to be different for this child controller vs. the default one that the parent irqchip gets. This used to be done before this driver was converted to hierarchical irq domains in commit e35a6ae0eb3a ("pinctrl/msm: Setup GPIO chip in hierarchy") via the gpiochip_irq_map() function. With hierarchical irq domains this function has been replaced by gpiochip_hierarchy_irq_domain_alloc(). Therefore, set the lockdep class like was done previously in the irq domain path so we can avoid this lockdep warning. Fixes: fdd61a013a24 ("gpio: Add support for hierarchical IRQ domains") Cc: Thierry Reding Cc: Brian Masney Cc: Lina Iyer Cc: Marc Zyngier Cc: Maulik Shah Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20200114231103.85641-1-swboyd@chromium.org Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e5057c0ca7e4..91a0e83c465d 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2032,6 +2032,7 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d, parent_type); chip_info(gc, "alloc_irqs_parent for %d parent hwirq %d\n", irq, parent_hwirq); + irq_set_lockdep_class(irq, gc->irq.lock_key, gc->irq.request_key); ret = irq_domain_alloc_irqs_parent(d, irq, 1, &parent_fwspec); if (ret) chip_err(gc, From 9a2b5b301d2a61f5dbd32cf0d908fd328436083d Mon Sep 17 00:00:00 2001 From: Shaokun Zhang Date: Tue, 14 Jan 2020 21:37:42 +0800 Subject: [PATCH 36/48] gpio: Remove the unused flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/gpio/gpio-grgpio.c: In function ‘grgpio_remove’: drivers/gpio/gpio-grgpio.c:438:16: warning: unused variable ‘flags’ [-Wunused-variable] unsigned long flags; ^ Fixes: 25d071b3f6db ("gpio: gpio-grgpio: fix possible sleep-in-atomic-context bugs in grgpio_remove()") Signed-off-by: Shaokun Zhang Link: https://lore.kernel.org/r/1579009062-7154-1-git-send-email-zhangshaokun@hisilicon.com Reviewed-by: Bartosz Golaszewski Signed-off-by: Linus Walleij --- drivers/gpio/gpio-grgpio.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index 1922adf96fc9..f954359c9544 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -435,7 +435,6 @@ static int grgpio_probe(struct platform_device *ofdev) static int grgpio_remove(struct platform_device *ofdev) { struct grgpio_priv *priv = platform_get_drvdata(ofdev); - unsigned long flags; int i; int ret = 0; From f2f679832d0c40b575b16d2da3ac8263ae9471ed Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 14 Jan 2020 16:02:52 +0100 Subject: [PATCH 37/48] gpio: mockup: update the license tag The current GPL v2.0 or later SPDX tag is 'GPL-2.0-or-later' as defined at https://spdx.org/licenses/. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20200114150253.28716-2-brgl@bgdev.pl Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mockup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 56d647a30e3e..3b666acfedc4 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +// SPDX-License-Identifier: GPL-2.0-or-later /* * GPIO Testing Device Driver * From 726a44531a8f90fb3dc01e1e9b578e767bf0738b Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 14 Jan 2020 16:02:53 +0100 Subject: [PATCH 38/48] gpio: mockup: sort headers alphabetically For consistency and easier maintenance: sort the headers alphabetically. Signed-off-by: Bartosz Golaszewski Link: https://lore.kernel.org/r/20200114150253.28716-3-brgl@bgdev.pl Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mockup.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 3b666acfedc4..88a81a92175e 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -7,18 +7,18 @@ * Copyright (C) 2017 Bartosz Golaszewski */ -#include -#include -#include +#include #include -#include -#include +#include +#include #include #include #include -#include -#include +#include +#include #include +#include +#include #include "gpiolib.h" From e81ccba69549630838f8e40cd3369607db8613c9 Mon Sep 17 00:00:00 2001 From: Sachin agarwal Date: Sun, 12 Jan 2020 20:03:12 +0530 Subject: [PATCH 39/48] gpio: vx855: fixed a typo we had written "betwee" rather than "between". Signed-off-by: Sachin agarwal Link: https://lore.kernel.org/r/20200112143312.66048-1-sachinagarwal@sachins-MacBook-2.local Signed-off-by: Linus Walleij --- drivers/gpio/gpio-vx855.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c index 4ff146ca32fe..3bf397b8dfbc 100644 --- a/drivers/gpio/gpio-vx855.c +++ b/drivers/gpio/gpio-vx855.c @@ -71,7 +71,7 @@ static inline u_int32_t gpio_o_bit(int i) return 1 << (i + 13); } -/* Mapping betwee numeric GPIO ID and the actual GPIO hardware numbering: +/* Mapping between numeric GPIO ID and the actual GPIO hardware numbering: * 0..13 GPI 0..13 * 14..26 GPO 0..12 * 27..41 GPIO 0..14 From e5e42ad224a040f93bf112e96f82b3a0ed97ffab Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 8 Jan 2020 20:11:17 +0800 Subject: [PATCH 40/48] gpiolib: remove set but not used variable 'config' drivers/gpio/gpiolib.c: In function gpio_set_config: drivers/gpio/gpiolib.c:3053:16: warning: variable config set but not used [-Wunused-but-set-variable] commit d90f36851d65 ("gpiolib: have a single place of calling set_config()") left behind this unused variable. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20200108121117.45060-1-yuehaibing@huawei.com Reviewed-by: Bartosz Golaszewski Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 91a0e83c465d..6d04e444f422 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3043,7 +3043,6 @@ static int gpio_do_set_config(struct gpio_chip *gc, unsigned int offset, static int gpio_set_config(struct gpio_chip *gc, unsigned int offset, enum pin_config_param mode) { - unsigned long config; unsigned arg; switch (mode) { @@ -3057,7 +3056,6 @@ static int gpio_set_config(struct gpio_chip *gc, unsigned int offset, arg = 0; } - config = PIN_CONF_PACKED(mode, arg); return gpio_do_set_config(gc, offset, mode); } From 59c324683400b41caa6d85b091e812ee3d5415c3 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 7 Jan 2020 13:08:44 +0000 Subject: [PATCH 41/48] gpio: wcd934x: Add support to wcd934x gpio controller This patch adds support to wcd934x gpio block found in WCD9340/WC9341 Audio codecs. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20200107130844.20763-3-srinivas.kandagatla@linaro.org Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 7 +++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-wcd934x.c | 121 ++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 drivers/gpio/gpio-wcd934x.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 79f153b1da7e..e8ca679ae1bb 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -619,6 +619,13 @@ config GPIO_VX855 additional drivers must be enabled in order to use the functionality of the device. +config GPIO_WCD934X + tristate "Qualcomm Technologies Inc WCD9340/WCD9341 gpio controller driver" + depends on MFD_WCD934X && OF_GPIO + help + This driver is to supprot GPIO block found on the Qualcomm Technologies + Inc WCD9340/WCD9341 Audio Codec. + config GPIO_XGENE bool "APM X-Gene GPIO controller support" depends on ARM64 && OF_GPIO diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index ba53f1fcde3a..655058ff1efe 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -158,6 +158,7 @@ obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o +obj-$(CONFIG_GPIO_WCD934X) += gpio-wcd934x.o obj-$(CONFIG_GPIO_WHISKEY_COVE) += gpio-wcove.o obj-$(CONFIG_GPIO_WINBOND) += gpio-winbond.o obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o diff --git a/drivers/gpio/gpio-wcd934x.c b/drivers/gpio/gpio-wcd934x.c new file mode 100644 index 000000000000..74913f2e5697 --- /dev/null +++ b/drivers/gpio/gpio-wcd934x.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019, Linaro Limited + +#include +#include +#include +#include +#include + +#define WCD_PIN_MASK(p) BIT(p - 1) +#define WCD_REG_DIR_CTL_OFFSET 0x42 +#define WCD_REG_VAL_CTL_OFFSET 0x43 +#define WCD934X_NPINS 5 + +struct wcd_gpio_data { + struct regmap *map; + struct gpio_chip chip; +}; + +static int wcd_gpio_get_direction(struct gpio_chip *chip, unsigned int pin) +{ + struct wcd_gpio_data *data = gpiochip_get_data(chip); + unsigned int value; + int ret; + + ret = regmap_read(data->map, WCD_REG_DIR_CTL_OFFSET, &value); + if (ret < 0) + return ret; + + if (value & WCD_PIN_MASK(pin)) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; +} + +static int wcd_gpio_direction_input(struct gpio_chip *chip, unsigned int pin) +{ + struct wcd_gpio_data *data = gpiochip_get_data(chip); + + return regmap_update_bits(data->map, WCD_REG_DIR_CTL_OFFSET, + WCD_PIN_MASK(pin), 0); +} + +static int wcd_gpio_direction_output(struct gpio_chip *chip, unsigned int pin, + int val) +{ + struct wcd_gpio_data *data = gpiochip_get_data(chip); + + regmap_update_bits(data->map, WCD_REG_DIR_CTL_OFFSET, + WCD_PIN_MASK(pin), WCD_PIN_MASK(pin)); + + return regmap_update_bits(data->map, WCD_REG_VAL_CTL_OFFSET, + WCD_PIN_MASK(pin), + val ? WCD_PIN_MASK(pin) : 0); +} + +static int wcd_gpio_get(struct gpio_chip *chip, unsigned int pin) +{ + struct wcd_gpio_data *data = gpiochip_get_data(chip); + int value; + + regmap_read(data->map, WCD_REG_VAL_CTL_OFFSET, &value); + + return !!(value && WCD_PIN_MASK(pin)); +} + +static void wcd_gpio_set(struct gpio_chip *chip, unsigned int pin, int val) +{ + wcd_gpio_direction_output(chip, pin, val); +} + +static int wcd_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct wcd_gpio_data *data; + struct gpio_chip *chip; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->map = dev_get_regmap(dev->parent, NULL); + if (!data->map) { + dev_err(dev, "%s: failed to get regmap\n", __func__); + return -EINVAL; + } + + chip = &data->chip; + chip->direction_input = wcd_gpio_direction_input; + chip->direction_output = wcd_gpio_direction_output; + chip->get_direction = wcd_gpio_get_direction; + chip->get = wcd_gpio_get; + chip->set = wcd_gpio_set; + chip->parent = dev; + chip->base = -1; + chip->ngpio = WCD934X_NPINS; + chip->label = dev_name(dev); + chip->of_gpio_n_cells = 2; + chip->can_sleep = false; + + return devm_gpiochip_add_data(dev, chip, data); +} + +static const struct of_device_id wcd_gpio_of_match[] = { + { .compatible = "qcom,wcd9340-gpio" }, + { .compatible = "qcom,wcd9341-gpio" }, + { } +}; +MODULE_DEVICE_TABLE(of, wcd_gpio_of_match); + +static struct platform_driver wcd_gpio_driver = { + .driver = { + .name = "wcd934x-gpio", + .of_match_table = wcd_gpio_of_match, + }, + .probe = wcd_gpio_probe, +}; + +module_platform_driver(wcd_gpio_driver); +MODULE_DESCRIPTION("Qualcomm Technologies, Inc WCD GPIO control driver"); +MODULE_LICENSE("GPL v2"); From 9c6722d85e92233082da2b3623685bba54d6093e Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Thu, 16 Jan 2020 17:50:03 +0800 Subject: [PATCH 42/48] gpio: Fix the no return statement warning In commit 242587616710 ("gpiolib: Add support for the irqdomain which doesn't use irq_fwspec as arg") we have changed the return type of gpiochip_populate_parent_fwspec_twocell/fourcell() from void to void *, but forgot to add a return statement for these two dummy functions. Add "return NULL" to fix the build warnings. Reported-by: kbuild test robot Signed-off-by: Kevin Hao Link: https://lore.kernel.org/r/20200116095003.30324-1-haokexin@gmail.com Signed-off-by: Linus Walleij --- include/linux/gpio/driver.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 9bb43467ed11..00d9f5b464c7 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -549,12 +549,14 @@ static inline void *gpiochip_populate_parent_fwspec_twocell(struct gpio_chip *ch unsigned int parent_hwirq, unsigned int parent_type) { + return NULL; } static inline void *gpiochip_populate_parent_fwspec_fourcell(struct gpio_chip *chip, unsigned int parent_hwirq, unsigned int parent_type) { + return NULL; } #endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */ From d18fddff061d2796525e6d4a958cb3d30aed8efd Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 16 Jan 2020 22:29:27 +0800 Subject: [PATCH 43/48] gpiolib: Remove duplicated function gpio_do_set_config() gpio_set_config() simply call gpio_do_set_config(), so remove the duplicated function. Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20200116142927.58908-1-yuehaibing@huawei.com Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e2749d26c6b5..5999bab3ba91 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3058,8 +3058,8 @@ EXPORT_SYMBOL_GPL(gpiochip_free_own_desc); * rely on gpio_request() having been called beforehand. */ -static int gpio_do_set_config(struct gpio_chip *gc, unsigned int offset, - enum pin_config_param mode) +static int gpio_set_config(struct gpio_chip *gc, unsigned int offset, + enum pin_config_param mode) { if (!gc->set_config) return -ENOTSUPP; @@ -3067,25 +3067,6 @@ static int gpio_do_set_config(struct gpio_chip *gc, unsigned int offset, return gc->set_config(gc, offset, mode); } -static int gpio_set_config(struct gpio_chip *gc, unsigned int offset, - enum pin_config_param mode) -{ - unsigned arg; - - switch (mode) { - case PIN_CONFIG_BIAS_DISABLE: - case PIN_CONFIG_BIAS_PULL_DOWN: - case PIN_CONFIG_BIAS_PULL_UP: - arg = 1; - break; - - default: - arg = 0; - } - - return gpio_do_set_config(gc, offset, mode); -} - static int gpio_set_bias(struct gpio_chip *chip, struct gpio_desc *desc) { int bias = 0; @@ -3319,7 +3300,7 @@ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) chip = desc->gdev->chip; config = pinconf_to_config_packed(PIN_CONFIG_INPUT_DEBOUNCE, debounce); - return gpio_do_set_config(chip, gpio_chip_hwgpio(desc), config); + return gpio_set_config(chip, gpio_chip_hwgpio(desc), config); } EXPORT_SYMBOL_GPL(gpiod_set_debounce); @@ -3353,7 +3334,7 @@ int gpiod_set_transitory(struct gpio_desc *desc, bool transitory) packed = pinconf_to_config_packed(PIN_CONFIG_PERSIST_STATE, !transitory); gpio = gpio_chip_hwgpio(desc); - rc = gpio_do_set_config(chip, gpio, packed); + rc = gpio_set_config(chip, gpio, packed); if (rc == -ENOTSUPP) { dev_dbg(&desc->gdev->dev, "Persistence not supported for GPIO %d\n", gpio); From 366950eeb6ee7ba6693129899452e0ba890cbe4d Mon Sep 17 00:00:00 2001 From: Kevin Hao Date: Mon, 20 Jan 2020 17:56:25 +0800 Subject: [PATCH 44/48] gpiolib: Lower verbosity when allocating hierarchy irq In the current codes, the following 3 lines would be output to the console for each irq line. gpio gpiochip0: (gpio_thunderx): allocate IRQ 10, hwirq 0 gpio gpiochip0: (gpio_thunderx): found parent hwirq 245784 gpio gpiochip0: (gpio_thunderx): alloc_irqs_parent for 10 parent hwirq 245784 In general, there are about tens of irq lines for each gpio chip, and then it would emit so many insignificant log in the boot process. These infos are more suitable for the dbg purpose. So change these to the dbg level. With this change, about 200 lines are suppressed on my Marvell cn96xx board. Signed-off-by: Kevin Hao Link: https://lore.kernel.org/r/20200120095625.25164-1-haokexin@gmail.com Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 5999bab3ba91..e48461ced552 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2006,7 +2006,7 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d, if (ret) return ret; - chip_info(gc, "allocate IRQ %d, hwirq %lu\n", irq, hwirq); + chip_dbg(gc, "allocate IRQ %d, hwirq %lu\n", irq, hwirq); ret = girq->child_to_parent_hwirq(gc, hwirq, type, &parent_hwirq, &parent_type); @@ -2014,7 +2014,7 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d, chip_err(gc, "can't look up hwirq %lu\n", hwirq); return ret; } - chip_info(gc, "found parent hwirq %u\n", parent_hwirq); + chip_dbg(gc, "found parent hwirq %u\n", parent_hwirq); /* * We set handle_bad_irq because the .set_type() should @@ -2034,7 +2034,7 @@ static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d, if (!parent_arg) return -ENOMEM; - chip_info(gc, "alloc_irqs_parent for %d parent hwirq %d\n", + chip_dbg(gc, "alloc_irqs_parent for %d parent hwirq %d\n", irq, parent_hwirq); irq_set_lockdep_class(irq, gc->irq.lock_key, gc->irq.request_key); ret = irq_domain_alloc_irqs_parent(d, irq, 1, parent_arg); From d5331ec2cc6e8b79b8b0027091d1ebb395e833b5 Mon Sep 17 00:00:00 2001 From: Maxim Kiselev Date: Wed, 15 Jan 2020 10:38:11 +0300 Subject: [PATCH 45/48] gpio: mvebu: clear irq in edge cause register before unmask edge irq When input GPIO set from 0 to 1, the interrupt bit asserted in the GPIO Interrupt Cause Register (ICR) even if the corresponding interrupt masked in the GPIO Interrupt Mask Register. Because interrupt mask register only affects assertion of the interrupt bits in Main Interrupt Cause Register and it does not affect the setting of bits in the GPIO ICR. So, there is problem, when we unmask interrupt with already asserted bit in the GPIO ICR, then false interrupt immediately occurs even if GPIO don't change their value since last unmask. Signed-off-by: Maxim Kiselev Link: https://lore.kernel.org/r/20200115073811.24438-1-bigunclemax@gmail.com Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mvebu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index f0fd82b3417c..d2b999c7987f 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -431,6 +431,7 @@ static void mvebu_gpio_edge_irq_unmask(struct irq_data *d) u32 mask = d->mask; irq_gc_lock(gc); + mvebu_gpio_write_edge_cause(mvchip, ~mask); ct->mask_cache_priv |= mask; mvebu_gpio_write_edge_mask(mvchip, ct->mask_cache_priv); irq_gc_unlock(gc); From 0d311d8b93cfc8ab36aa11f09e15a5fe87147c02 Mon Sep 17 00:00:00 2001 From: Sachin agarwal Date: Sat, 18 Jan 2020 16:23:19 +0530 Subject: [PATCH 46/48] gpio: aspeed-sgpio: fixed typos This fixes some various typos. Signed-off-by: Sachin Agarwal Link: https://lore.kernel.org/r/20200118105319.68637-1-sachinagarwal@sachins-MacBook-2.local Signed-off-by: Linus Walleij --- drivers/gpio/gpio-aspeed-sgpio.c | 2 +- drivers/gpio/gpio-aspeed.c | 2 +- drivers/gpio/gpio-creg-snps.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-aspeed-sgpio.c b/drivers/gpio/gpio-aspeed-sgpio.c index 8319812593e3..d16645c1d8d9 100644 --- a/drivers/gpio/gpio-aspeed-sgpio.c +++ b/drivers/gpio/gpio-aspeed-sgpio.c @@ -391,7 +391,7 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio, gpio->irq = rc; - /* Disable IRQ and clear Interrupt status registers for all SPGIO Pins. */ + /* Disable IRQ and clear Interrupt status registers for all SGPIO Pins. */ for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { bank = &aspeed_sgpio_banks[i]; /* disable irq enable bits */ diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index f1037b61f763..879db23d8454 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -978,7 +978,7 @@ static int aspeed_gpio_set_config(struct gpio_chip *chip, unsigned int offset, } /** - * aspeed_gpio_copro_set_ops - Sets the callbacks used for handhsaking with + * aspeed_gpio_copro_set_ops - Sets the callbacks used for handshaking with * the coprocessor for shared GPIO banks * @ops: The callbacks * @data: Pointer passed back to the callbacks diff --git a/drivers/gpio/gpio-creg-snps.c b/drivers/gpio/gpio-creg-snps.c index ff19a8ad5663..1d0827e79703 100644 --- a/drivers/gpio/gpio-creg-snps.c +++ b/drivers/gpio/gpio-creg-snps.c @@ -64,11 +64,11 @@ static int creg_gpio_validate_pg(struct device *dev, struct creg_gpio *hcg, if (layout->bit_per_gpio[i] < 1 || layout->bit_per_gpio[i] > 8) return -EINVAL; - /* Check that on valiue fits it's placeholder */ + /* Check that on value fits its placeholder */ if (GENMASK(31, layout->bit_per_gpio[i]) & layout->on[i]) return -EINVAL; - /* Check that off valiue fits it's placeholder */ + /* Check that off value fits its placeholder */ if (GENMASK(31, layout->bit_per_gpio[i]) & layout->off[i]) return -EINVAL; From 207270dd0b2d593a8b92043c9bcdabb42111fcc3 Mon Sep 17 00:00:00 2001 From: Dan Callaghan Date: Tue, 21 Jan 2020 10:12:17 +1000 Subject: [PATCH 47/48] gpiolib: hold gpio devices lock until ->descs array is initialised If a driver consuming the GPIO chip is being probed at the same time as the GPIO driver is registering the chip, it is possible for the consuming driver to see the ->descs array in an uninitialised state. For example, the gpio-keys-polled driver can fail like this: kernel: gpiod_request: invalid GPIO (no device) kernel: gpio-keys-polled PRP0001:07: failed to get gpio: -22 kernel: gpio-keys-polled: probe of PRP0001:07 failed with error -22 This patch makes gpiochip_add() hold the lock protecting gpio_devices until it has finished setting desc->gdev on the newly inserted list entry. Signed-off-by: Dan Callaghan Link: https://lore.kernel.org/r/20200121001216.15964-1-dan.callaghan@opengear.com Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e48461ced552..d5f997761d3e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1486,11 +1486,11 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, goto err_free_label; } - spin_unlock_irqrestore(&gpio_lock, flags); - for (i = 0; i < chip->ngpio; i++) gdev->descs[i].gdev = gdev; + spin_unlock_irqrestore(&gpio_lock, flags); + #ifdef CONFIG_PINCTRL INIT_LIST_HEAD(&gdev->pin_ranges); #endif From 81563bed1e11a184a753148c0e7dfc5e26a71981 Mon Sep 17 00:00:00 2001 From: "Ooi, Joyce" Date: Sat, 4 Jan 2020 01:01:55 +0800 Subject: [PATCH 48/48] MAINTAINERS: Replace Tien Hock Loh as Altera PIO maintainer This patch is to replace Tien Hock Loh as Altera PIO maintainer as he has moved to a different role. Signed-off-by: Ooi, Joyce Link: https://lore.kernel.org/r/20200103170155.100743-1-joyce.ooi@intel.com Acked-by: Tien Hock Loh Signed-off-by: Linus Walleij --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 4017e6b760be..98c16944b402 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -726,7 +726,7 @@ S: Maintained F: drivers/mailbox/mailbox-altera.c ALTERA PIO DRIVER -M: Tien Hock Loh +M: Joyce Ooi L: linux-gpio@vger.kernel.org S: Maintained F: drivers/gpio/gpio-altera.c