From 0bb8e80b58c90208fdea05bd51d24b26af98a71c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 15 Dec 2020 10:53:29 +0000 Subject: gpio: fix spelling mistake in Kconfig "supprot" -> "support" There is a spelling mistake in the Kconfig help text. Fix it. Signed-off-by: Colin Ian King Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index fa225175e68d..6907f04f9fd3 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -670,7 +670,7 @@ 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 + This driver is to support GPIO block found on the Qualcomm Technologies Inc WCD9340/WCD9341 Audio Codec. config GPIO_XGENE -- cgit v1.2.3 From db63c0953cfa678ae199d7449705ccd076cb174a Mon Sep 17 00:00:00 2001 From: Jonathan Neuschäfer Date: Fri, 1 Jan 2021 21:00:51 +0100 Subject: docs: gpio: Fix formatting in description of gpiod_*_array_* functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gpiod_*_array_* functions take four arguments, not three. Additionally, the formatting of the "value_bitmap" line results in misformatted HTML, so fix that. Signed-off-by: Jonathan Neuschäfer Signed-off-by: Bartosz Golaszewski --- Documentation/driver-api/gpio/consumer.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/driver-api/gpio/consumer.rst b/Documentation/driver-api/gpio/consumer.rst index 173e4c7b037d..22271c342d92 100644 --- a/Documentation/driver-api/gpio/consumer.rst +++ b/Documentation/driver-api/gpio/consumer.rst @@ -361,12 +361,13 @@ corresponding chip driver. In that case a significantly improved performance can be expected. If simultaneous access is not possible the GPIOs will be accessed sequentially. -The functions take three arguments: +The functions take four arguments: + * array_size - the number of array elements * desc_array - an array of GPIO descriptors * array_info - optional information obtained from gpiod_get_array() * value_bitmap - a bitmap to store the GPIOs' values (get) or - a bitmap of values to assign to the GPIOs (set) + a bitmap of values to assign to the GPIOs (set) The descriptor array can be obtained using the gpiod_get_array() function or one of its variants. If the group of descriptors returned by that function -- cgit v1.2.3 From e1d4d6633816d39e433154499bc4b9b5ee2b2258 Mon Sep 17 00:00:00 2001 From: Jonathan Neuschäfer Date: Fri, 1 Jan 2021 21:43:25 +0100 Subject: docs: gpio: intro: Improve HTML formatting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the HTML output for Documentation/driver-api/gpio/intro.rst doesn't look right. The lines that start with LOW or HIGH are formatted in bold, while the next line after each is not bold. With this patch, the HTML looks better. Signed-off-by: Jonathan Neuschäfer Signed-off-by: Bartosz Golaszewski --- Documentation/driver-api/gpio/intro.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/driver-api/gpio/intro.rst b/Documentation/driver-api/gpio/intro.rst index 74591489d0b5..94dd7185e76e 100644 --- a/Documentation/driver-api/gpio/intro.rst +++ b/Documentation/driver-api/gpio/intro.rst @@ -106,11 +106,11 @@ don't. When you need open drain signaling but your hardware doesn't directly support it, there's a common idiom you can use to emulate it with any GPIO pin that can be used as either an input or an output: - LOW: gpiod_direction_output(gpio, 0) ... this drives the signal and overrides - the pullup. + **LOW**: ``gpiod_direction_output(gpio, 0)`` ... this drives the signal and + overrides the pullup. - HIGH: gpiod_direction_input(gpio) ... this turns off the output, so the pullup - (or some other device) controls the signal. + **HIGH**: ``gpiod_direction_input(gpio)`` ... this turns off the output, so + the pullup (or some other device) controls the signal. The same logic can be applied to emulate open source signaling, by driving the high signal and configuring the GPIO as input for low. This open drain/open -- cgit v1.2.3 From 0521ae0107f77301040a3bb653303d57d991063e Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Thu, 31 Dec 2020 15:31:41 +0000 Subject: gpio: rcar: Remove redundant compatible values The mandatory compatible values 'renesas,rcar-gen{1,2,3}-gpio' have been already added to all the respective R-Car Gen{1,2,3} SoC DTSI files, remove the redundant device specific values from the driver. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-rcar.c | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 0b572dbc4a36..f3b8c4b44cab 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -392,33 +392,6 @@ static const struct gpio_rcar_info gpio_rcar_info_gen2 = { static const struct of_device_id gpio_rcar_of_table[] = { { - .compatible = "renesas,gpio-r8a7743", - /* RZ/G1 GPIO is identical to R-Car Gen2. */ - .data = &gpio_rcar_info_gen2, - }, { - .compatible = "renesas,gpio-r8a7790", - .data = &gpio_rcar_info_gen2, - }, { - .compatible = "renesas,gpio-r8a7791", - .data = &gpio_rcar_info_gen2, - }, { - .compatible = "renesas,gpio-r8a7792", - .data = &gpio_rcar_info_gen2, - }, { - .compatible = "renesas,gpio-r8a7793", - .data = &gpio_rcar_info_gen2, - }, { - .compatible = "renesas,gpio-r8a7794", - .data = &gpio_rcar_info_gen2, - }, { - .compatible = "renesas,gpio-r8a7795", - /* Gen3 GPIO is identical to Gen2. */ - .data = &gpio_rcar_info_gen2, - }, { - .compatible = "renesas,gpio-r8a7796", - /* Gen3 GPIO is identical to Gen2. */ - .data = &gpio_rcar_info_gen2, - }, { .compatible = "renesas,rcar-gen1-gpio", .data = &gpio_rcar_info_gen1, }, { -- cgit v1.2.3 From aab0508e37c11c0574819ccfb05e14281a240d77 Mon Sep 17 00:00:00 2001 From: Zheng Yongjun Date: Wed, 16 Dec 2020 21:26:57 +0800 Subject: gpio: sl28cpld: convert comma to semicolon Replace a comma between expression statements by a semicolon. Signed-off-by: Zheng Yongjun Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-sl28cpld.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-sl28cpld.c b/drivers/gpio/gpio-sl28cpld.c index 889b8f5622c2..52404736ac86 100644 --- a/drivers/gpio/gpio-sl28cpld.c +++ b/drivers/gpio/gpio-sl28cpld.c @@ -65,13 +65,13 @@ static int sl28cpld_gpio_irq_init(struct platform_device *pdev, if (!irq_chip) return -ENOMEM; - irq_chip->name = "sl28cpld-gpio-irq", + irq_chip->name = "sl28cpld-gpio-irq"; irq_chip->irqs = sl28cpld_gpio_irqs; irq_chip->num_irqs = ARRAY_SIZE(sl28cpld_gpio_irqs); irq_chip->num_regs = 1; irq_chip->status_base = base + GPIO_REG_IP; irq_chip->mask_base = base + GPIO_REG_IE; - irq_chip->mask_invert = true, + irq_chip->mask_invert = true; irq_chip->ack_base = base + GPIO_REG_IP; ret = devm_regmap_add_irq_chip_fwnode(dev, dev_fwnode(dev), -- cgit v1.2.3 From 032653ef1b9dee6176a82b890395a1a1c7ca2c56 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Mon, 4 Jan 2021 11:37:44 +0000 Subject: gpio: Kconfig: Update help description for GPIO_RCAR config The gpio-rcar driver also supports RZ/G SoC's, update the description to reflect this. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 6907f04f9fd3..6addc923fa70 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -487,11 +487,11 @@ config GPIO_PXA Say yes here to support the PXA GPIO device config GPIO_RCAR - tristate "Renesas R-Car GPIO" + tristate "Renesas R-Car and RZ/G GPIO support" depends on ARCH_RENESAS || COMPILE_TEST select GPIOLIB_IRQCHIP help - Say yes here to support GPIO on Renesas R-Car SoCs. + Say yes here to support GPIO on Renesas R-Car or RZ/G SoCs. config GPIO_RDA bool "RDA Micro GPIO controller support" -- cgit v1.2.3 From 82bf0afd57deac5ba7b5642e10d7759222d15347 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Tue, 5 Jan 2021 14:53:35 +0200 Subject: gpio: bd7xxxx: Do not depend on parent driver data The ROHM BD70528 and BD71828 GPIO drivers only need the regmap pointer from parent. Regmap can be obtained via dev_get_regmap() so do not require parent to populate driver data for that. Signed-off-by: Matti Vaittinen Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-bd70528.c | 46 +++++++++++++++++++++------------------------ drivers/gpio/gpio-bd71828.c | 28 ++++++++++++--------------- 2 files changed, 33 insertions(+), 41 deletions(-) diff --git a/drivers/gpio/gpio-bd70528.c b/drivers/gpio/gpio-bd70528.c index 45b3da8da336..276a0fe6346d 100644 --- a/drivers/gpio/gpio-bd70528.c +++ b/drivers/gpio/gpio-bd70528.c @@ -12,7 +12,8 @@ #define GPIO_OUT_REG(offset) (BD70528_REG_GPIO1_OUT + (offset) * 2) struct bd70528_gpio { - struct rohm_regmap_dev chip; + struct regmap *regmap; + struct device *dev; struct gpio_chip gpio; }; @@ -35,11 +36,11 @@ static int bd70528_set_debounce(struct bd70528_gpio *bdgpio, val = BD70528_DEBOUNCE_50MS; break; default: - dev_err(bdgpio->chip.dev, + dev_err(bdgpio->dev, "Invalid debounce value %u\n", debounce); return -EINVAL; } - return regmap_update_bits(bdgpio->chip.regmap, GPIO_IN_REG(offset), + return regmap_update_bits(bdgpio->regmap, GPIO_IN_REG(offset), BD70528_DEBOUNCE_MASK, val); } @@ -49,9 +50,9 @@ static int bd70528_get_direction(struct gpio_chip *chip, unsigned int offset) int val, ret; /* Do we need to do something to IRQs here? */ - ret = regmap_read(bdgpio->chip.regmap, GPIO_OUT_REG(offset), &val); + ret = regmap_read(bdgpio->regmap, GPIO_OUT_REG(offset), &val); if (ret) { - dev_err(bdgpio->chip.dev, "Could not read gpio direction\n"); + dev_err(bdgpio->dev, "Could not read gpio direction\n"); return ret; } if (val & BD70528_GPIO_OUT_EN_MASK) @@ -67,13 +68,13 @@ static int bd70528_gpio_set_config(struct gpio_chip *chip, unsigned int offset, switch (pinconf_to_config_param(config)) { case PIN_CONFIG_DRIVE_OPEN_DRAIN: - return regmap_update_bits(bdgpio->chip.regmap, + return regmap_update_bits(bdgpio->regmap, GPIO_OUT_REG(offset), BD70528_GPIO_DRIVE_MASK, BD70528_GPIO_OPEN_DRAIN); break; case PIN_CONFIG_DRIVE_PUSH_PULL: - return regmap_update_bits(bdgpio->chip.regmap, + return regmap_update_bits(bdgpio->regmap, GPIO_OUT_REG(offset), BD70528_GPIO_DRIVE_MASK, BD70528_GPIO_PUSH_PULL); @@ -93,7 +94,7 @@ static int bd70528_direction_input(struct gpio_chip *chip, unsigned int offset) struct bd70528_gpio *bdgpio = gpiochip_get_data(chip); /* Do we need to do something to IRQs here? */ - return regmap_update_bits(bdgpio->chip.regmap, GPIO_OUT_REG(offset), + return regmap_update_bits(bdgpio->regmap, GPIO_OUT_REG(offset), BD70528_GPIO_OUT_EN_MASK, BD70528_GPIO_OUT_DISABLE); } @@ -105,10 +106,10 @@ static void bd70528_gpio_set(struct gpio_chip *chip, unsigned int offset, struct bd70528_gpio *bdgpio = gpiochip_get_data(chip); u8 val = (value) ? BD70528_GPIO_OUT_HI : BD70528_GPIO_OUT_LO; - ret = regmap_update_bits(bdgpio->chip.regmap, GPIO_OUT_REG(offset), + ret = regmap_update_bits(bdgpio->regmap, GPIO_OUT_REG(offset), BD70528_GPIO_OUT_MASK, val); if (ret) - dev_err(bdgpio->chip.dev, "Could not set gpio to %d\n", value); + dev_err(bdgpio->dev, "Could not set gpio to %d\n", value); } static int bd70528_direction_output(struct gpio_chip *chip, unsigned int offset, @@ -117,7 +118,7 @@ static int bd70528_direction_output(struct gpio_chip *chip, unsigned int offset, struct bd70528_gpio *bdgpio = gpiochip_get_data(chip); bd70528_gpio_set(chip, offset, value); - return regmap_update_bits(bdgpio->chip.regmap, GPIO_OUT_REG(offset), + return regmap_update_bits(bdgpio->regmap, GPIO_OUT_REG(offset), BD70528_GPIO_OUT_EN_MASK, BD70528_GPIO_OUT_ENABLE); } @@ -129,11 +130,11 @@ static int bd70528_gpio_get_o(struct bd70528_gpio *bdgpio, unsigned int offset) int ret; unsigned int val; - ret = regmap_read(bdgpio->chip.regmap, GPIO_OUT_REG(offset), &val); + ret = regmap_read(bdgpio->regmap, GPIO_OUT_REG(offset), &val); if (!ret) ret = !!(val & BD70528_GPIO_OUT_MASK); else - dev_err(bdgpio->chip.dev, "GPIO (out) state read failed\n"); + dev_err(bdgpio->dev, "GPIO (out) state read failed\n"); return ret; } @@ -143,12 +144,12 @@ static int bd70528_gpio_get_i(struct bd70528_gpio *bdgpio, unsigned int offset) unsigned int val; int ret; - ret = regmap_read(bdgpio->chip.regmap, BD70528_REG_GPIO_STATE, &val); + ret = regmap_read(bdgpio->regmap, BD70528_REG_GPIO_STATE, &val); if (!ret) ret = !(val & GPIO_IN_STATE_MASK(offset)); else - dev_err(bdgpio->chip.dev, "GPIO (in) state read failed\n"); + dev_err(bdgpio->dev, "GPIO (in) state read failed\n"); return ret; } @@ -173,7 +174,7 @@ static int bd70528_gpio_get(struct gpio_chip *chip, unsigned int offset) else if (ret == GPIO_LINE_DIRECTION_IN) ret = bd70528_gpio_get_i(bdgpio, offset); else - dev_err(bdgpio->chip.dev, "failed to read GPIO direction\n"); + dev_err(bdgpio->dev, "failed to read GPIO direction\n"); return ret; } @@ -181,20 +182,13 @@ static int bd70528_gpio_get(struct gpio_chip *chip, unsigned int offset) static int bd70528_probe(struct platform_device *pdev) { struct bd70528_gpio *bdgpio; - struct rohm_regmap_dev *bd70528; int ret; - bd70528 = dev_get_drvdata(pdev->dev.parent); - if (!bd70528) { - dev_err(&pdev->dev, "No MFD driver data\n"); - return -EINVAL; - } - bdgpio = devm_kzalloc(&pdev->dev, sizeof(*bdgpio), GFP_KERNEL); if (!bdgpio) return -ENOMEM; - bdgpio->chip.dev = &pdev->dev; + bdgpio->dev = &pdev->dev; bdgpio->gpio.parent = pdev->dev.parent; bdgpio->gpio.label = "bd70528-gpio"; bdgpio->gpio.owner = THIS_MODULE; @@ -210,7 +204,9 @@ static int bd70528_probe(struct platform_device *pdev) #ifdef CONFIG_OF_GPIO bdgpio->gpio.of_node = pdev->dev.parent->of_node; #endif - bdgpio->chip.regmap = bd70528->regmap; + bdgpio->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!bdgpio->regmap) + return -ENODEV; ret = devm_gpiochip_add_data(&pdev->dev, &bdgpio->gpio, bdgpio); diff --git a/drivers/gpio/gpio-bd71828.c b/drivers/gpio/gpio-bd71828.c index 3dbbc638e9a9..fcdcbb57c76d 100644 --- a/drivers/gpio/gpio-bd71828.c +++ b/drivers/gpio/gpio-bd71828.c @@ -11,7 +11,8 @@ #define HALL_GPIO_OFFSET 3 struct bd71828_gpio { - struct rohm_regmap_dev chip; + struct regmap *regmap; + struct device *dev; struct gpio_chip gpio; }; @@ -29,10 +30,10 @@ static void bd71828_gpio_set(struct gpio_chip *chip, unsigned int offset, if (offset == HALL_GPIO_OFFSET) return; - ret = regmap_update_bits(bdgpio->chip.regmap, GPIO_OUT_REG(offset), + ret = regmap_update_bits(bdgpio->regmap, GPIO_OUT_REG(offset), BD71828_GPIO_OUT_MASK, val); if (ret) - dev_err(bdgpio->chip.dev, "Could not set gpio to %d\n", value); + dev_err(bdgpio->dev, "Could not set gpio to %d\n", value); } static int bd71828_gpio_get(struct gpio_chip *chip, unsigned int offset) @@ -42,10 +43,10 @@ static int bd71828_gpio_get(struct gpio_chip *chip, unsigned int offset) struct bd71828_gpio *bdgpio = gpiochip_get_data(chip); if (offset == HALL_GPIO_OFFSET) - ret = regmap_read(bdgpio->chip.regmap, BD71828_REG_IO_STAT, + ret = regmap_read(bdgpio->regmap, BD71828_REG_IO_STAT, &val); else - ret = regmap_read(bdgpio->chip.regmap, GPIO_OUT_REG(offset), + ret = regmap_read(bdgpio->regmap, GPIO_OUT_REG(offset), &val); if (!ret) ret = (val & BD71828_GPIO_OUT_MASK); @@ -63,12 +64,12 @@ static int bd71828_gpio_set_config(struct gpio_chip *chip, unsigned int offset, switch (pinconf_to_config_param(config)) { case PIN_CONFIG_DRIVE_OPEN_DRAIN: - return regmap_update_bits(bdgpio->chip.regmap, + return regmap_update_bits(bdgpio->regmap, GPIO_OUT_REG(offset), BD71828_GPIO_DRIVE_MASK, BD71828_GPIO_OPEN_DRAIN); case PIN_CONFIG_DRIVE_PUSH_PULL: - return regmap_update_bits(bdgpio->chip.regmap, + return regmap_update_bits(bdgpio->regmap, GPIO_OUT_REG(offset), BD71828_GPIO_DRIVE_MASK, BD71828_GPIO_PUSH_PULL); @@ -97,20 +98,13 @@ static int bd71828_get_direction(struct gpio_chip *chip, unsigned int offset) static int bd71828_probe(struct platform_device *pdev) { struct bd71828_gpio *bdgpio; - struct rohm_regmap_dev *bd71828; - - bd71828 = dev_get_drvdata(pdev->dev.parent); - if (!bd71828) { - dev_err(&pdev->dev, "No MFD driver data\n"); - return -EINVAL; - } bdgpio = devm_kzalloc(&pdev->dev, sizeof(*bdgpio), GFP_KERNEL); if (!bdgpio) return -ENOMEM; - bdgpio->chip.dev = &pdev->dev; + bdgpio->dev = &pdev->dev; bdgpio->gpio.parent = pdev->dev.parent; bdgpio->gpio.label = "bd71828-gpio"; bdgpio->gpio.owner = THIS_MODULE; @@ -128,7 +122,9 @@ static int bd71828_probe(struct platform_device *pdev) */ bdgpio->gpio.ngpio = 4; bdgpio->gpio.of_node = pdev->dev.parent->of_node; - bdgpio->chip.regmap = bd71828->regmap; + bdgpio->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!bdgpio->regmap) + return -ENODEV; return devm_gpiochip_add_data(&pdev->dev, &bdgpio->gpio, bdgpio); -- cgit v1.2.3 From c233912f6b99242f12da84a2f22418e2e08c0b38 Mon Sep 17 00:00:00 2001 From: Aswath Govindraju Date: Wed, 9 Dec 2020 22:27:31 +0530 Subject: dt-bindings: gpio: Add compatible string for AM64 SoC Add compatible string for AM64 SoC in device tree binding of davinci GPIO modules as the same IP is used. Signed-off-by: Aswath Govindraju Acked-by: Rob Herring Signed-off-by: Bartosz Golaszewski --- Documentation/devicetree/bindings/gpio/gpio-davinci.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/gpio/gpio-davinci.txt b/Documentation/devicetree/bindings/gpio/gpio-davinci.txt index cd91d61eac31..696ea46227d1 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-davinci.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-davinci.txt @@ -7,6 +7,7 @@ Required Properties: "ti,k2g-gpio", "ti,keystone-gpio": for 66AK2G "ti,am654-gpio", "ti,keystone-gpio": for TI K3 AM654 "ti,j721e-gpio", "ti,keystone-gpio": for J721E SoCs + "ti,am64-gpio", "ti,keystone-gpio": for AM64 SoCs - reg: Physical base address of the controller and the size of memory mapped registers. -- cgit v1.2.3 From 858093f73634393931743acf7dd398b92935753e Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Thu, 17 Dec 2020 23:43:35 +0900 Subject: dt-bindings: gpio: Add bindings for Toshiba Visconti GPIO Controller Add bindings for the Toshiba Visconti GPIO Controller. Signed-off-by: Nobuhiro Iwamatsu Reviewed-by: Rob Herring Reviewed-by: Punit Agrawal Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- .../bindings/gpio/toshiba,gpio-visconti.yaml | 70 ++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/toshiba,gpio-visconti.yaml diff --git a/Documentation/devicetree/bindings/gpio/toshiba,gpio-visconti.yaml b/Documentation/devicetree/bindings/gpio/toshiba,gpio-visconti.yaml new file mode 100644 index 000000000000..9ad470e01953 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/toshiba,gpio-visconti.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpio/toshiba,gpio-visconti.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Toshiba Visconti ARM SoCs GPIO controller + +maintainers: + - Nobuhiro Iwamatsu + +properties: + compatible: + items: + - const: toshiba,gpio-tmpv7708 + + reg: + maxItems: 1 + + "#gpio-cells": + const: 2 + + gpio-ranges: true + + gpio-controller: true + + interrupt-controller: true + + "#interrupt-cells": + const: 2 + + interrupts: + description: + interrupt mapping one per GPIO. + minItems: 16 + maxItems: 16 + +required: + - compatible + - reg + - "#gpio-cells" + - gpio-ranges + - gpio-controller + - interrupt-controller + - "#interrupt-cells" + - interrupt-parent + +additionalProperties: false + +examples: + - | + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + gpio: gpio@28020000 { + compatible = "toshiba,gpio-tmpv7708"; + reg = <0 0x28020000 0 0x1000>; + #gpio-cells = <0x2>; + gpio-ranges = <&pmux 0 0 32>; + gpio-controller; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + }; + }; +... -- cgit v1.2.3 From 2ad74f40dacc411546d737ce92197384cd8587bd Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Thu, 17 Dec 2020 23:43:36 +0900 Subject: gpio: visconti: Add Toshiba Visconti GPIO support Add the GPIO driver for Toshiba Visconti ARM SoCs. Signed-off-by: Nobuhiro Iwamatsu Reviewed-by: Punit Agrawal Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 10 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-visconti.c | 218 ++++++++++++++++++++++++++++++ drivers/pinctrl/visconti/pinctrl-common.c | 23 ++++ 4 files changed, 252 insertions(+) create mode 100644 drivers/gpio/gpio-visconti.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 6addc923fa70..520fdf2bda30 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -648,6 +648,16 @@ config GPIO_VF610 help Say yes here to support Vybrid vf610 GPIOs. +config GPIO_VISCONTI + tristate "Toshiba Visconti GPIO support" + depends on ARCH_VISCONTI || COMPILE_TEST + depends on OF_GPIO + select GPIOLIB_IRQCHIP + select GPIO_GENERIC + select IRQ_DOMAIN_HIERARCHY + help + Say yes here to support GPIO on Tohisba Visconti. + config GPIO_VR41XX tristate "NEC VR4100 series General-purpose I/O Uint support" depends on CPU_VR41XX diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 35e3b6026665..2c2a705766f3 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -164,6 +164,7 @@ obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o +obj-$(CONFIG_GPIO_VISCONTI) += gpio-visconti.o obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o obj-$(CONFIG_GPIO_WCD934X) += gpio-wcd934x.o diff --git a/drivers/gpio/gpio-visconti.c b/drivers/gpio/gpio-visconti.c new file mode 100644 index 000000000000..0e3d19828eb1 --- /dev/null +++ b/drivers/gpio/gpio-visconti.c @@ -0,0 +1,218 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Toshiba Visconti GPIO Support + * + * (C) Copyright 2020 Toshiba Electronic Devices & Storage Corporation + * (C) Copyright 2020 TOSHIBA CORPORATION + * + * Nobuhiro Iwamatsu + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* register offset */ +#define GPIO_DIR 0x00 +#define GPIO_IDATA 0x08 +#define GPIO_ODATA 0x10 +#define GPIO_OSET 0x18 +#define GPIO_OCLR 0x20 +#define GPIO_INTMODE 0x30 + +#define BASE_HW_IRQ 24 + +struct visconti_gpio { + void __iomem *base; + spinlock_t lock; /* protect gpio register */ + struct gpio_chip gpio_chip; + struct irq_chip irq_chip; +}; + +static int visconti_gpio_irq_set_type(struct irq_data *d, unsigned int type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct visconti_gpio *priv = gpiochip_get_data(gc); + u32 offset = irqd_to_hwirq(d); + u32 bit = BIT(offset); + u32 intc_type = IRQ_TYPE_EDGE_RISING; + u32 intmode, odata; + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + odata = readl(priv->base + GPIO_ODATA); + intmode = readl(priv->base + GPIO_INTMODE); + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + odata &= ~bit; + intmode &= ~bit; + break; + case IRQ_TYPE_EDGE_FALLING: + odata |= bit; + intmode &= ~bit; + break; + case IRQ_TYPE_EDGE_BOTH: + intmode |= bit; + break; + case IRQ_TYPE_LEVEL_HIGH: + intc_type = IRQ_TYPE_LEVEL_HIGH; + odata &= ~bit; + intmode &= ~bit; + break; + case IRQ_TYPE_LEVEL_LOW: + intc_type = IRQ_TYPE_LEVEL_HIGH; + odata |= bit; + intmode &= ~bit; + break; + default: + ret = -EINVAL; + goto err; + } + + writel(odata, priv->base + GPIO_ODATA); + writel(intmode, priv->base + GPIO_INTMODE); + irq_set_irq_type(offset, intc_type); + + ret = irq_chip_set_type_parent(d, type); +err: + spin_unlock_irqrestore(&priv->lock, flags); + return ret; +} + +static int visconti_gpio_child_to_parent_hwirq(struct gpio_chip *gc, + unsigned int child, + unsigned int child_type, + unsigned int *parent, + unsigned int *parent_type) +{ + /* Interrupts 0..15 mapped to interrupts 24..39 on the GIC */ + if (child < 16) { + /* All these interrupts are level high in the CPU */ + *parent_type = IRQ_TYPE_LEVEL_HIGH; + *parent = child + BASE_HW_IRQ; + return 0; + } + return -EINVAL; +} + +static void *visconti_gpio_populate_parent_fwspec(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 = 3; + fwspec->param[0] = 0; + fwspec->param[1] = parent_hwirq; + fwspec->param[2] = parent_type; + + return fwspec; +} + +static int visconti_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct visconti_gpio *priv; + struct irq_chip *irq_chip; + struct gpio_irq_chip *girq; + struct irq_domain *parent; + struct device_node *irq_parent; + struct fwnode_handle *fwnode; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&priv->lock); + + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + irq_parent = of_irq_find_parent(dev->of_node); + if (!irq_parent) { + dev_err(dev, "No IRQ parent node\n"); + return -ENODEV; + } + + parent = irq_find_host(irq_parent); + if (!parent) { + dev_err(dev, "No IRQ parent domain\n"); + return -ENODEV; + } + + fwnode = of_node_to_fwnode(irq_parent); + of_node_put(irq_parent); + + ret = bgpio_init(&priv->gpio_chip, dev, 4, + priv->base + GPIO_IDATA, + priv->base + GPIO_OSET, + priv->base + GPIO_OCLR, + priv->base + GPIO_DIR, + NULL, + 0); + if (ret) { + dev_err(dev, "unable to init generic GPIO\n"); + return ret; + } + + irq_chip = &priv->irq_chip; + irq_chip->name = dev_name(dev); + irq_chip->irq_mask = irq_chip_mask_parent; + irq_chip->irq_unmask = irq_chip_unmask_parent; + irq_chip->irq_eoi = irq_chip_eoi_parent; + irq_chip->irq_set_type = visconti_gpio_irq_set_type; + irq_chip->flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND; + + girq = &priv->gpio_chip.irq; + girq->chip = irq_chip; + girq->fwnode = fwnode; + girq->parent_domain = parent; + girq->child_to_parent_hwirq = visconti_gpio_child_to_parent_hwirq; + girq->populate_parent_alloc_arg = visconti_gpio_populate_parent_fwspec; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_level_irq; + + ret = devm_gpiochip_add_data(dev, &priv->gpio_chip, priv); + if (ret) { + dev_err(dev, "failed to add GPIO chip\n"); + return ret; + } + + platform_set_drvdata(pdev, priv); + + return ret; +} + +static const struct of_device_id visconti_gpio_of_match[] = { + { .compatible = "toshiba,gpio-tmpv7708", }, + { /* end of table */ } +}; +MODULE_DEVICE_TABLE(of, visconti_gpio_of_match); + +static struct platform_driver visconti_gpio_driver = { + .probe = visconti_gpio_probe, + .driver = { + .name = "visconti_gpio", + .of_match_table = of_match_ptr(visconti_gpio_of_match), + } +}; +module_platform_driver(visconti_gpio_driver); + +MODULE_AUTHOR("Nobuhiro Iwamatsu "); +MODULE_DESCRIPTION("Toshiba Visconti GPIO Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/visconti/pinctrl-common.c b/drivers/pinctrl/visconti/pinctrl-common.c index 0cb10b7b4430..21c7e0d18fea 100644 --- a/drivers/pinctrl/visconti/pinctrl-common.c +++ b/drivers/pinctrl/visconti/pinctrl-common.c @@ -245,11 +245,34 @@ static int visconti_set_mux(struct pinctrl_dev *pctldev, return 0; } +static int visconti_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int pin) +{ + struct visconti_pinctrl *priv = pinctrl_dev_get_drvdata(pctldev); + const struct visconti_mux *gpio_mux = &priv->devdata->gpio_mux[pin]; + unsigned long flags; + unsigned int val; + + dev_dbg(priv->dev, "%s: pin = %d\n", __func__, pin); + + /* update mux */ + spin_lock_irqsave(&priv->lock, flags); + val = readl(priv->base + gpio_mux->offset); + val &= ~gpio_mux->mask; + val |= gpio_mux->val; + writel(val, priv->base + gpio_mux->offset); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + static const struct pinmux_ops visconti_pinmux_ops = { .get_functions_count = visconti_get_functions_count, .get_function_name = visconti_get_function_name, .get_function_groups = visconti_get_function_groups, .set_mux = visconti_set_mux, + .gpio_request_enable = visconti_gpio_request_enable, .strict = true, }; -- cgit v1.2.3 From 5103c90d133cb496ce80f81ae9357920f33a5e60 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Thu, 17 Dec 2020 23:43:37 +0900 Subject: MAINTAINERS: Add entries for Toshiba Visconti GPIO controller Add entries for Toshiba Visconti GPIO Controller binding and driver. Signed-off-by: Nobuhiro Iwamatsu Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index bfc1b86e3e73..bc4d80bcdf52 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2641,8 +2641,10 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwamatsu/linux-visconti.git F: Documentation/devicetree/bindings/arm/toshiba.yaml +F: Documentation/devicetree/bindings/gpio/toshiba,gpio-visconti.yaml F: Documentation/devicetree/bindings/pinctrl/toshiba,tmpv7700-pinctrl.yaml F: arch/arm64/boot/dts/toshiba/ +F: drivers/gpio/gpio-visconti.c F: drivers/pinctrl/visconti/ N: visconti -- cgit v1.2.3 From c988ae37c7225c290939c65544c5c380efd60c90 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Thu, 17 Dec 2020 23:43:38 +0900 Subject: arm: dts: visconti: Add DT support for Toshiba Visconti5 GPIO driver Add the GPIO node in Toshiba Visconti5 SoC-specific DT file. And enable the GPIO node in TMPV7708 RM main board's board-specific DT file. Signed-off-by: Nobuhiro Iwamatsu Reviewed-by: Punit Agrawal Acked-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts | 4 ++++ arch/arm64/boot/dts/toshiba/tmpv7708.dtsi | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts b/arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts index ed0bf7f13f54..950010a290f0 100644 --- a/arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts +++ b/arch/arm64/boot/dts/toshiba/tmpv7708-rm-mbrc.dts @@ -41,3 +41,7 @@ clocks = <&uart_clk>; clock-names = "apb_pclk"; }; + +&gpio { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/toshiba/tmpv7708.dtsi b/arch/arm64/boot/dts/toshiba/tmpv7708.dtsi index 242f25f4e12a..17fdcbd4b075 100644 --- a/arch/arm64/boot/dts/toshiba/tmpv7708.dtsi +++ b/arch/arm64/boot/dts/toshiba/tmpv7708.dtsi @@ -157,6 +157,17 @@ reg = <0 0x24190000 0 0x10000>; }; + gpio: gpio@28020000 { + compatible = "toshiba,gpio-tmpv7708"; + reg = <0 0x28020000 0 0x1000>; + #gpio-cells = <0x2>; + gpio-ranges = <&pmux 0 0 32>; + gpio-controller; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&gic>; + }; + uart0: serial@28200000 { compatible = "arm,pl011", "arm,primecell"; reg = <0 0x28200000 0 0x1000>; -- cgit v1.2.3 From 66fecef5bde07857d6306f569d71af5bd092c00b Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 27 Nov 2020 15:08:52 +0100 Subject: gpio: tegra: Convert to gpio_irq_chip Convert the Tegra GPIO driver to use the gpio_irq_chip infrastructure. This allows a bit of boiler plate to be removed and while at it enables support for hierarchical domains, which is useful to support PMC wake events on Tegra210 and earlier. Signed-off-by: Thierry Reding Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-tegra.c | 218 +++++++++++++++++++++++++++++++--------------- 1 file changed, 146 insertions(+), 72 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index e19ebff6018c..b8a4fd07c559 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -60,7 +60,6 @@ struct tegra_gpio_info; struct tegra_gpio_bank { unsigned int bank; - unsigned int irq; /* * IRQ-core code uses raw locking, and thus, nested locking also @@ -81,7 +80,6 @@ struct tegra_gpio_bank { u32 dbc_enb[4]; #endif u32 dbc_cnt[4]; - struct tegra_gpio_info *tgi; }; struct tegra_gpio_soc_config { @@ -93,12 +91,12 @@ struct tegra_gpio_soc_config { struct tegra_gpio_info { struct device *dev; void __iomem *regs; - struct irq_domain *irq_domain; struct tegra_gpio_bank *bank_info; const struct tegra_gpio_soc_config *soc; struct gpio_chip gc; struct irq_chip ic; u32 bank_count; + unsigned int *irqs; }; static inline void tegra_gpio_writel(struct tegra_gpio_info *tgi, @@ -274,17 +272,10 @@ static int tegra_gpio_set_config(struct gpio_chip *chip, unsigned int offset, return tegra_gpio_set_debounce(chip, offset, debounce); } -static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) -{ - struct tegra_gpio_info *tgi = gpiochip_get_data(chip); - - return irq_find_mapping(tgi->irq_domain, offset); -} - static void tegra_gpio_irq_ack(struct irq_data *d) { - struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); - struct tegra_gpio_info *tgi = bank->tgi; + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct tegra_gpio_info *tgi = gpiochip_get_data(chip); unsigned int gpio = d->hwirq; tegra_gpio_writel(tgi, 1 << GPIO_BIT(gpio), GPIO_INT_CLR(tgi, gpio)); @@ -292,8 +283,8 @@ static void tegra_gpio_irq_ack(struct irq_data *d) static void tegra_gpio_irq_mask(struct irq_data *d) { - struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); - struct tegra_gpio_info *tgi = bank->tgi; + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct tegra_gpio_info *tgi = gpiochip_get_data(chip); unsigned int gpio = d->hwirq; tegra_gpio_mask_write(tgi, GPIO_MSK_INT_ENB(tgi, gpio), gpio, 0); @@ -301,8 +292,8 @@ static void tegra_gpio_irq_mask(struct irq_data *d) static void tegra_gpio_irq_unmask(struct irq_data *d) { - struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); - struct tegra_gpio_info *tgi = bank->tgi; + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct tegra_gpio_info *tgi = gpiochip_get_data(chip); unsigned int gpio = d->hwirq; tegra_gpio_mask_write(tgi, GPIO_MSK_INT_ENB(tgi, gpio), gpio, 1); @@ -311,11 +302,14 @@ static void tegra_gpio_irq_unmask(struct irq_data *d) static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) { unsigned int gpio = d->hwirq, port = GPIO_PORT(gpio), lvl_type; - struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); - struct tegra_gpio_info *tgi = bank->tgi; + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct tegra_gpio_info *tgi = gpiochip_get_data(chip); + struct tegra_gpio_bank *bank; unsigned long flags; - u32 val; int ret; + u32 val; + + bank = &tgi->bank_info[GPIO_BANK(d->hwirq)]; switch (type & IRQ_TYPE_SENSE_MASK) { case IRQ_TYPE_EDGE_RISING: @@ -367,13 +361,16 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) irq_set_handler_locked(d, handle_edge_irq); - return 0; + if (d->parent_data) + ret = irq_chip_set_type_parent(d, type); + + return ret; } static void tegra_gpio_irq_shutdown(struct irq_data *d) { - struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); - struct tegra_gpio_info *tgi = bank->tgi; + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct tegra_gpio_info *tgi = gpiochip_get_data(chip); unsigned int gpio = d->hwirq; tegra_gpio_irq_mask(d); @@ -382,13 +379,25 @@ static void tegra_gpio_irq_shutdown(struct irq_data *d) static void tegra_gpio_irq_handler(struct irq_desc *desc) { - unsigned int port, pin, gpio; + struct tegra_gpio_info *tgi = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct irq_domain *domain = tgi->gc.irq.domain; + unsigned int irq = irq_desc_get_irq(desc); + struct tegra_gpio_bank *bank = NULL; + unsigned int port, pin, gpio, i; bool unmasked = false; - u32 lvl; unsigned long sta; - struct irq_chip *chip = irq_desc_get_chip(desc); - struct tegra_gpio_bank *bank = irq_desc_get_handler_data(desc); - struct tegra_gpio_info *tgi = bank->tgi; + u32 lvl; + + for (i = 0; i < tgi->bank_count; i++) { + if (tgi->irqs[i] == irq) { + bank = &tgi->bank_info[i]; + break; + } + } + + if (WARN_ON(bank == NULL)) + return; chained_irq_enter(chip, desc); @@ -411,14 +420,44 @@ static void tegra_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } - generic_handle_irq(irq_find_mapping(tgi->irq_domain, - gpio + pin)); + irq = irq_find_mapping(domain, gpio + pin); + if (WARN_ON(irq == 0)) + continue; + + generic_handle_irq(irq); } } if (!unmasked) chained_irq_exit(chip, desc); +} + +static int tegra_gpio_child_to_parent_hwirq(struct gpio_chip *chip, unsigned int hwirq, + unsigned int type, unsigned int *parent_hwirq, + unsigned int *parent_type) +{ + *parent_hwirq = chip->irq.child_offset_to_irq(chip, hwirq); + *parent_type = type; + return 0; +} + +static void *tegra_gpio_populate_parent_fwspec(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 = 3; + fwspec->param[0] = 0; + fwspec->param[1] = parent_hwirq; + fwspec->param[2] = parent_type; + + return fwspec; } #ifdef CONFIG_PM_SLEEP @@ -497,14 +536,13 @@ static int tegra_gpio_suspend(struct device *dev) 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); + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct tegra_gpio_info *tgi = gpiochip_get_data(chip); + struct tegra_gpio_bank *bank; unsigned int gpio = d->hwirq; u32 port, bit, mask; - int err; - err = irq_set_irq_wake(bank->irq, enable); - if (err) - return err; + bank = &tgi->bank_info[GPIO_BANK(d->hwirq)]; port = GPIO_PORT(gpio); bit = GPIO_BIT(gpio); @@ -515,10 +553,41 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) else bank->wake_enb[port] &= ~mask; + if (d->parent_data) + return irq_chip_set_wake_parent(d, enable); + return 0; } #endif +static int tegra_gpio_irq_set_affinity(struct irq_data *data, const struct cpumask *dest, + bool force) +{ + if (data->parent_data) + return irq_chip_set_affinity_parent(data, dest, force); + + return -EINVAL; +} + +static int tegra_gpio_irq_request_resources(struct irq_data *d) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct tegra_gpio_info *tgi = gpiochip_get_data(chip); + + tegra_gpio_enable(tgi, d->hwirq); + + return gpiochip_reqres_irq(chip, d->hwirq); +} + +static void tegra_gpio_irq_release_resources(struct irq_data *d) +{ + struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + struct tegra_gpio_info *tgi = gpiochip_get_data(chip); + + gpiochip_relres_irq(chip, d->hwirq); + tegra_gpio_enable(tgi, d->hwirq); +} + #ifdef CONFIG_DEBUG_FS #include @@ -568,14 +637,18 @@ static const struct dev_pm_ops tegra_gpio_pm_ops = { SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume) }; -static struct lock_class_key gpio_lock_class; -static struct lock_class_key gpio_request_class; +static const struct of_device_id tegra_pmc_of_match[] = { + { .compatible = "nvidia,tegra210-pmc", }, + { /* sentinel */ }, +}; static int tegra_gpio_probe(struct platform_device *pdev) { - struct tegra_gpio_info *tgi; struct tegra_gpio_bank *bank; - unsigned int gpio, i, j; + struct tegra_gpio_info *tgi; + struct gpio_irq_chip *irq; + struct device_node *np; + unsigned int i, j; int ret; tgi = devm_kzalloc(&pdev->dev, sizeof(*tgi), GFP_KERNEL); @@ -604,7 +677,6 @@ static int tegra_gpio_probe(struct platform_device *pdev) tgi->gc.direction_output = tegra_gpio_direction_output; tgi->gc.set = tegra_gpio_set; tgi->gc.get_direction = tegra_gpio_get_direction; - tgi->gc.to_irq = tegra_gpio_to_irq; tgi->gc.base = 0; tgi->gc.ngpio = tgi->bank_count * 32; tgi->gc.parent = &pdev->dev; @@ -619,6 +691,9 @@ static int tegra_gpio_probe(struct platform_device *pdev) #ifdef CONFIG_PM_SLEEP tgi->ic.irq_set_wake = tegra_gpio_irq_set_wake; #endif + tgi->ic.irq_set_affinity = tegra_gpio_irq_set_affinity; + tgi->ic.irq_request_resources = tegra_gpio_irq_request_resources; + tgi->ic.irq_release_resources = tegra_gpio_irq_release_resources; platform_set_drvdata(pdev, tgi); @@ -630,11 +705,9 @@ static int tegra_gpio_probe(struct platform_device *pdev) if (!tgi->bank_info) return -ENOMEM; - tgi->irq_domain = irq_domain_add_linear(pdev->dev.of_node, - tgi->gc.ngpio, - &irq_domain_simple_ops, NULL); - if (!tgi->irq_domain) - return -ENODEV; + tgi->irqs = devm_kcalloc(&pdev->dev, tgi->bank_count, sizeof(*tgi->irqs), GFP_KERNEL); + if (!tgi->irqs) + return -ENOMEM; for (i = 0; i < tgi->bank_count; i++) { ret = platform_get_irq(pdev, i); @@ -643,8 +716,34 @@ static int tegra_gpio_probe(struct platform_device *pdev) bank = &tgi->bank_info[i]; bank->bank = i; - bank->irq = ret; - bank->tgi = tgi; + + tgi->irqs[i] = ret; + + for (j = 0; j < 4; j++) { + raw_spin_lock_init(&bank->lvl_lock[j]); + spin_lock_init(&bank->dbc_lock[j]); + } + } + + irq = &tgi->gc.irq; + irq->chip = &tgi->ic; + irq->fwnode = of_node_to_fwnode(pdev->dev.of_node); + irq->child_to_parent_hwirq = tegra_gpio_child_to_parent_hwirq; + irq->populate_parent_alloc_arg = tegra_gpio_populate_parent_fwspec; + irq->handler = handle_simple_irq; + irq->default_type = IRQ_TYPE_NONE; + irq->parent_handler = tegra_gpio_irq_handler; + irq->parent_handler_data = tgi; + irq->num_parents = tgi->bank_count; + irq->parents = tgi->irqs; + + np = of_find_matching_node(NULL, tegra_pmc_of_match); + if (np) { + irq->parent_domain = irq_find_host(np); + of_node_put(np); + + if (!irq->parent_domain) + return -EPROBE_DEFER; } tgi->regs = devm_platform_ioremap_resource(pdev, 0); @@ -660,33 +759,8 @@ static int tegra_gpio_probe(struct platform_device *pdev) } ret = devm_gpiochip_add_data(&pdev->dev, &tgi->gc, tgi); - if (ret < 0) { - irq_domain_remove(tgi->irq_domain); + if (ret < 0) return ret; - } - - for (gpio = 0; gpio < tgi->gc.ngpio; gpio++) { - int irq = irq_create_mapping(tgi->irq_domain, gpio); - /* No validity check; all Tegra GPIOs are valid IRQs */ - - bank = &tgi->bank_info[GPIO_BANK(gpio)]; - - irq_set_chip_data(irq, bank); - irq_set_lockdep_class(irq, &gpio_lock_class, &gpio_request_class); - irq_set_chip_and_handler(irq, &tgi->ic, handle_simple_irq); - } - - for (i = 0; i < tgi->bank_count; i++) { - bank = &tgi->bank_info[i]; - - irq_set_chained_handler_and_data(bank->irq, - tegra_gpio_irq_handler, bank); - - for (j = 0; j < 4; j++) { - raw_spin_lock_init(&bank->lvl_lock[j]); - spin_lock_init(&bank->dbc_lock[j]); - } - } tegra_gpio_debuginit(tgi); -- cgit v1.2.3 From cb38cd70354f6c6d94c072c65e2dfd19c8724c04 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 6 Jan 2021 11:11:33 +0100 Subject: gpio: bd7xxxx: use helper variable for pdev->dev Using a helper local variable to store the address of &pdev->dev adds to readability and allows us to avoid unnecessary line breaks. Signed-off-by: Bartosz Golaszewski Reviewed-by: Matti Vaittinen --- drivers/gpio/gpio-bd70528.c | 17 ++++++++--------- drivers/gpio/gpio-bd71828.c | 15 +++++++-------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/drivers/gpio/gpio-bd70528.c b/drivers/gpio/gpio-bd70528.c index 276a0fe6346d..397a50d6bc65 100644 --- a/drivers/gpio/gpio-bd70528.c +++ b/drivers/gpio/gpio-bd70528.c @@ -181,15 +181,15 @@ static int bd70528_gpio_get(struct gpio_chip *chip, unsigned int offset) static int bd70528_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct bd70528_gpio *bdgpio; int ret; - bdgpio = devm_kzalloc(&pdev->dev, sizeof(*bdgpio), - GFP_KERNEL); + bdgpio = devm_kzalloc(dev, sizeof(*bdgpio), GFP_KERNEL); if (!bdgpio) return -ENOMEM; - bdgpio->dev = &pdev->dev; - bdgpio->gpio.parent = pdev->dev.parent; + bdgpio->dev = dev; + bdgpio->gpio.parent = dev->parent; bdgpio->gpio.label = "bd70528-gpio"; bdgpio->gpio.owner = THIS_MODULE; bdgpio->gpio.get_direction = bd70528_get_direction; @@ -202,16 +202,15 @@ static int bd70528_probe(struct platform_device *pdev) bdgpio->gpio.ngpio = 4; bdgpio->gpio.base = -1; #ifdef CONFIG_OF_GPIO - bdgpio->gpio.of_node = pdev->dev.parent->of_node; + bdgpio->gpio.of_node = dev->parent->of_node; #endif - bdgpio->regmap = dev_get_regmap(pdev->dev.parent, NULL); + bdgpio->regmap = dev_get_regmap(dev->parent, NULL); if (!bdgpio->regmap) return -ENODEV; - ret = devm_gpiochip_add_data(&pdev->dev, &bdgpio->gpio, - bdgpio); + ret = devm_gpiochip_add_data(dev, &bdgpio->gpio, bdgpio); if (ret) - dev_err(&pdev->dev, "gpio_init: Failed to add bd70528-gpio\n"); + dev_err(dev, "gpio_init: Failed to add bd70528-gpio\n"); return ret; } diff --git a/drivers/gpio/gpio-bd71828.c b/drivers/gpio/gpio-bd71828.c index fcdcbb57c76d..c8e382b53f2f 100644 --- a/drivers/gpio/gpio-bd71828.c +++ b/drivers/gpio/gpio-bd71828.c @@ -97,15 +97,15 @@ static int bd71828_get_direction(struct gpio_chip *chip, unsigned int offset) static int bd71828_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct bd71828_gpio *bdgpio; - bdgpio = devm_kzalloc(&pdev->dev, sizeof(*bdgpio), - GFP_KERNEL); + bdgpio = devm_kzalloc(dev, sizeof(*bdgpio), GFP_KERNEL); if (!bdgpio) return -ENOMEM; - bdgpio->dev = &pdev->dev; - bdgpio->gpio.parent = pdev->dev.parent; + bdgpio->dev = dev; + bdgpio->gpio.parent = dev->parent; bdgpio->gpio.label = "bd71828-gpio"; bdgpio->gpio.owner = THIS_MODULE; bdgpio->gpio.get_direction = bd71828_get_direction; @@ -121,13 +121,12 @@ static int bd71828_probe(struct platform_device *pdev) * "gpio-reserved-ranges" and exclude them from control */ bdgpio->gpio.ngpio = 4; - bdgpio->gpio.of_node = pdev->dev.parent->of_node; - bdgpio->regmap = dev_get_regmap(pdev->dev.parent, NULL); + bdgpio->gpio.of_node = dev->parent->of_node; + bdgpio->regmap = dev_get_regmap(dev->parent, NULL); if (!bdgpio->regmap) return -ENODEV; - return devm_gpiochip_add_data(&pdev->dev, &bdgpio->gpio, - bdgpio); + return devm_gpiochip_add_data(dev, &bdgpio->gpio, bdgpio); } static struct platform_driver bd71828_gpio = { -- cgit v1.2.3 From 2a84708c2f2f9d134abd21d1f2fe6ce5a87dffaa Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 8 Jan 2021 11:20:24 +0100 Subject: dt-bindings: gpio: rcar: Add r8a779a0 support Document the compatible value for the GPIO block in the Renesas R-Car V3U (R8A779A0) SoC. While this GPIO block is mostly compatible with GPIO blocks on R-Car Gen3 SoCs, there are small differences, and one of the new registers needs to be configured differently from its initial reset state. Signed-off-by: Geert Uytterhoeven Reviewed-by: Wolfram Sang Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- Documentation/devicetree/bindings/gpio/renesas,rcar-gpio.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/gpio/renesas,rcar-gpio.yaml b/Documentation/devicetree/bindings/gpio/renesas,rcar-gpio.yaml index 5026662e4508..f2541739ee3b 100644 --- a/Documentation/devicetree/bindings/gpio/renesas,rcar-gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/renesas,rcar-gpio.yaml @@ -48,6 +48,9 @@ properties: - renesas,gpio-r8a77995 # R-Car D3 - const: renesas,rcar-gen3-gpio # R-Car Gen3 or RZ/G2 + - items: + - const: renesas,gpio-r8a779a0 # R-Car V3U + reg: maxItems: 1 -- cgit v1.2.3 From ecba1eaa7906b0ce864e7eee27ea6cf5d6844e8a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 8 Jan 2021 11:20:25 +0100 Subject: gpio: rcar: Optimize GPIO pin state read on R-Car Gen3 Currently, the R-Car GPIO driver treats R-Car Gen2 and R-Car Gen3 GPIO controllers the same. However, there exist small differences, like the behavior of the General Input Register (INDT): - On R-Car Gen1, R-Car Gen2, and RZ/G1, INDT only reflects the state of an input pin if the GPIO is configured for input, - On R-Car Gen3 and RZ/G2, INDT always reflects the state of the input pins. Hence to accommodate all variants, the driver does not use the INDT register to read the status of a GPIO line when configured for output, at the expense of doing 2 or 3 register reads instead of 1. Given register accesses are slow, change the .get() and .get_multiple() callbacks to always use INDT to read pin state on SoCs where this is supported. Signed-off-by: Geert Uytterhoeven Reviewed-by: Yoshihiro Shimoda Tested-by: Wolfram Sang Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-rcar.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index f3b8c4b44cab..edded6478792 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -35,6 +35,7 @@ struct gpio_rcar_bank_info { struct gpio_rcar_info { bool has_outdtsel; bool has_both_edge_trigger; + bool has_always_in; }; struct gpio_rcar_priv { @@ -302,9 +303,11 @@ static int gpio_rcar_get(struct gpio_chip *chip, unsigned offset) struct gpio_rcar_priv *p = gpiochip_get_data(chip); u32 bit = BIT(offset); - /* testing on r8a7790 shows that INDT does not show correct pin state - * when configured as output, so use OUTDT in case of output pins */ - if (gpio_rcar_read(p, INOUTSEL) & bit) + /* + * Before R-Car Gen3, INDT does not show correct pin state when + * configured as output, so use OUTDT in case of output pins + */ + if (!p->info.has_always_in && (gpio_rcar_read(p, INOUTSEL) & bit)) return !!(gpio_rcar_read(p, OUTDT) & bit); else return !!(gpio_rcar_read(p, INDT) & bit); @@ -324,6 +327,11 @@ static int gpio_rcar_get_multiple(struct gpio_chip *chip, unsigned long *mask, if (!bankmask) return 0; + if (p->info.has_always_in) { + bits[0] = gpio_rcar_read(p, INDT) & bankmask; + return 0; + } + spin_lock_irqsave(&p->lock, flags); outputs = gpio_rcar_read(p, INOUTSEL); m = outputs & bankmask; @@ -383,11 +391,19 @@ static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset, static const struct gpio_rcar_info gpio_rcar_info_gen1 = { .has_outdtsel = false, .has_both_edge_trigger = false, + .has_always_in = false, }; static const struct gpio_rcar_info gpio_rcar_info_gen2 = { .has_outdtsel = true, .has_both_edge_trigger = true, + .has_always_in = false, +}; + +static const struct gpio_rcar_info gpio_rcar_info_gen3 = { + .has_outdtsel = true, + .has_both_edge_trigger = true, + .has_always_in = true, }; static const struct of_device_id gpio_rcar_of_table[] = { @@ -399,8 +415,7 @@ static const struct of_device_id gpio_rcar_of_table[] = { .data = &gpio_rcar_info_gen2, }, { .compatible = "renesas,rcar-gen3-gpio", - /* Gen3 GPIO is identical to Gen2. */ - .data = &gpio_rcar_info_gen2, + .data = &gpio_rcar_info_gen3, }, { .compatible = "renesas,gpio-rcar", .data = &gpio_rcar_info_gen1, -- cgit v1.2.3 From 93ac0b0c68c0cff8e49d2a7c08525824dbb8642e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 8 Jan 2021 11:20:26 +0100 Subject: gpio: rcar: Add R-Car V3U (R8A779A0) support Add support for the GPIO controller block in the R-Car V3U (R8A779A0) SoC, which is very similar to the block found on other R-Car Gen3 SoCs. However, this block has a new General Input Enable Register (INEN), whose reset state is to have all inputs disabled. Enable input for all available pins in probe and resume, to support the use of the General Input Register (INDT) for reading pin state at all times. This preserves backwards compatibility with other R-Car Gen3 SoCs, as recommended by the Hardware Manual. Signed-off-by: Geert Uytterhoeven Reviewed-by: Yoshihiro Shimoda Tested-by: Wolfram Sang Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-rcar.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index edded6478792..e7092d5fe700 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -36,6 +36,7 @@ struct gpio_rcar_info { bool has_outdtsel; bool has_both_edge_trigger; bool has_always_in; + bool has_inen; }; struct gpio_rcar_priv { @@ -63,6 +64,7 @@ struct gpio_rcar_priv { #define FILONOFF 0x28 /* Chattering Prevention On/Off Register */ #define OUTDTSEL 0x40 /* Output Data Select Register */ #define BOTHEDGE 0x4c /* One Edge/Both Edge Select Register */ +#define INEN 0x50 /* General Input Enable Register */ #define RCAR_MAX_GPIO_PER_BANK 32 @@ -392,22 +394,35 @@ static const struct gpio_rcar_info gpio_rcar_info_gen1 = { .has_outdtsel = false, .has_both_edge_trigger = false, .has_always_in = false, + .has_inen = false, }; static const struct gpio_rcar_info gpio_rcar_info_gen2 = { .has_outdtsel = true, .has_both_edge_trigger = true, .has_always_in = false, + .has_inen = false, }; static const struct gpio_rcar_info gpio_rcar_info_gen3 = { .has_outdtsel = true, .has_both_edge_trigger = true, .has_always_in = true, + .has_inen = false, +}; + +static const struct gpio_rcar_info gpio_rcar_info_v3u = { + .has_outdtsel = true, + .has_both_edge_trigger = true, + .has_always_in = true, + .has_inen = true, }; static const struct of_device_id gpio_rcar_of_table[] = { { + .compatible = "renesas,gpio-r8a779a0", + .data = &gpio_rcar_info_v3u, + }, { .compatible = "renesas,rcar-gen1-gpio", .data = &gpio_rcar_info_gen1, }, { @@ -448,6 +463,17 @@ static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins) return 0; } +static void gpio_rcar_enable_inputs(struct gpio_rcar_priv *p) +{ + u32 mask = GENMASK(p->gpio_chip.ngpio - 1, 0); + + /* Select "Input Enable" in INEN */ + if (p->gpio_chip.valid_mask) + mask &= p->gpio_chip.valid_mask[0]; + if (mask) + gpio_rcar_write(p, INEN, gpio_rcar_read(p, INEN) | mask); +} + static int gpio_rcar_probe(struct platform_device *pdev) { struct gpio_rcar_priv *p; @@ -537,6 +563,12 @@ static int gpio_rcar_probe(struct platform_device *pdev) goto err1; } + if (p->info.has_inen) { + pm_runtime_get_sync(p->dev); + gpio_rcar_enable_inputs(p); + pm_runtime_put(p->dev); + } + dev_info(dev, "driving %d GPIOs\n", npins); return 0; @@ -612,6 +644,9 @@ static int gpio_rcar_resume(struct device *dev) } } + if (p->info.has_inen) + gpio_rcar_enable_inputs(p); + return 0; } #endif /* CONFIG_PM_SLEEP*/ -- cgit v1.2.3 From 1421b447ae7b419ed8303c1af8632b5884b59704 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 15 Jan 2021 17:46:56 +0100 Subject: gpio: pca953x: Add support for pca9506 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the reference manual "The PCA9505 is identical to the PCA9506 except that it includes 100 kΩ internal pull-up resistors on all the I/Os." So the pca9506 device can be considered identical to the pca9505 for the gpio driver. Signed-off-by: Uwe Kleine-König Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pca953x.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 825b362eb4b7..5ea09fd01544 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -73,6 +73,7 @@ static const struct i2c_device_id pca953x_id[] = { { "pca6416", 16 | PCA953X_TYPE | PCA_INT, }, { "pca9505", 40 | PCA953X_TYPE | PCA_INT, }, + { "pca9506", 40 | PCA953X_TYPE | PCA_INT, }, { "pca9534", 8 | PCA953X_TYPE | PCA_INT, }, { "pca9535", 16 | PCA953X_TYPE | PCA_INT, }, { "pca9536", 4 | PCA953X_TYPE, }, @@ -1236,6 +1237,7 @@ static int pca953x_resume(struct device *dev) static const struct of_device_id pca953x_dt_ids[] = { { .compatible = "nxp,pca6416", .data = OF_953X(16, PCA_INT), }, { .compatible = "nxp,pca9505", .data = OF_953X(40, PCA_INT), }, + { .compatible = "nxp,pca9506", .data = OF_953X(40, PCA_INT), }, { .compatible = "nxp,pca9534", .data = OF_953X( 8, PCA_INT), }, { .compatible = "nxp,pca9535", .data = OF_953X(16, PCA_INT), }, { .compatible = "nxp,pca9536", .data = OF_953X( 4, 0), }, -- cgit v1.2.3 From 600be6522a5ae94e3e121c71d6228807820e76f2 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 15 Jan 2021 17:46:57 +0100 Subject: dt-bindings: gpio: pca953x: Document new supported chip pca9506 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous patch added support for this chip. Add its name to the list of allowed compatibles. Signed-off-by: Uwe Kleine-König Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml b/Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml index f5ee23c2df60..cdd7744b8723 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml +++ b/Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml @@ -32,6 +32,7 @@ properties: - maxim,max7327 - nxp,pca6416 - nxp,pca9505 + - nxp,pca9506 - nxp,pca9534 - nxp,pca9535 - nxp,pca9536 -- cgit v1.2.3 From 9067b3014d45c6b18c242ba98a21403f4d471606 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 15 Jan 2021 17:46:58 +0100 Subject: dt-bindings: gpio: pca953x: Increase allowed length for gpio-line-names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some supported chips (e.g. pca9505) support 40 lines. To be able to give each line a name the length of the gpio-line-names property must be allowed to contain up to 40 entries. Signed-off-by: Uwe Kleine-König Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml b/Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml index cdd7744b8723..246bae53be8b 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml +++ b/Documentation/devicetree/bindings/gpio/gpio-pca95xx.yaml @@ -71,7 +71,7 @@ properties: gpio-line-names: minItems: 1 - maxItems: 32 + maxItems: 40 interrupts: maxItems: 1 -- cgit v1.2.3 From 27f8feea4091a733b8f6ddfe8090c8b3d7a45a15 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Tue, 12 Jan 2021 16:30:09 +0300 Subject: gpio: tegra: Fix wake interrupt The GPIO bank wake interrupt setting was erroneously removed after conversion to gpio_irq_chip, thus the wake interrupt programming is broken now. Secondly, the wake_enb of the GPIO driver should be changed only after the successful toggling of the IRQ wake-state. Restore the wake interrupt setting and the programming order. Fixes: efcdca286eef ("gpio: tegra: Convert to gpio_irq_chip") Signed-off-by: Dmitry Osipenko Acked-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-tegra.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index b8a4fd07c559..6c79e9d2f932 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -541,6 +541,7 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) struct tegra_gpio_bank *bank; unsigned int gpio = d->hwirq; u32 port, bit, mask; + int err; bank = &tgi->bank_info[GPIO_BANK(d->hwirq)]; @@ -548,14 +549,23 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) bit = GPIO_BIT(gpio); mask = BIT(bit); + err = irq_set_irq_wake(tgi->irqs[bank->bank], enable); + if (err) + return err; + + if (d->parent_data) { + err = irq_chip_set_wake_parent(d, enable); + if (err) { + irq_set_irq_wake(tgi->irqs[bank->bank], !enable); + return err; + } + } + if (enable) bank->wake_enb[port] |= mask; else bank->wake_enb[port] &= ~mask; - if (d->parent_data) - return irq_chip_set_wake_parent(d, enable); - return 0; } #endif -- cgit v1.2.3 From 8bc395a6a2e24bfae934e43c7f968b23f9b9b55f Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Tue, 19 Jan 2021 20:30:53 +0800 Subject: selftests: gpio: rework and simplify test implementation The GPIO mockup selftests are overly complicated with separate implementations of the tests for sysfs and cdev uAPI, and with the cdev implementation being dependent on tools/gpio and libmount. Rework the test implementation to provide a common test suite with a simplified pluggable uAPI interface. The cdev implementation utilises the GPIO uAPI directly to remove the dependence on tools/gpio. The simplified uAPI interface removes the need for any file system mount checks in C, and so removes the dependence on libmount. The rework also fixes the sysfs test implementation which has been broken since the device created in the multiple gpiochip case was split into separate devices. Fixes: 8a39f597bcfd ("gpio: mockup: rework device probing") Signed-off-by: Kent Gibson Acked-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- tools/testing/selftests/gpio/Makefile | 26 +- tools/testing/selftests/gpio/gpio-mockup-cdev.c | 139 ++++++ tools/testing/selftests/gpio/gpio-mockup-sysfs.sh | 168 +++----- tools/testing/selftests/gpio/gpio-mockup.sh | 490 +++++++++++++++------- 4 files changed, 535 insertions(+), 288 deletions(-) create mode 100644 tools/testing/selftests/gpio/gpio-mockup-cdev.c diff --git a/tools/testing/selftests/gpio/Makefile b/tools/testing/selftests/gpio/Makefile index 41582fe485ee..39f2bbe8dd3d 100644 --- a/tools/testing/selftests/gpio/Makefile +++ b/tools/testing/selftests/gpio/Makefile @@ -1,31 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 -VAR_CFLAGS := $(shell pkg-config --cflags mount 2>/dev/null) -VAR_LDLIBS := $(shell pkg-config --libs mount 2>/dev/null) -ifeq ($(VAR_LDLIBS),) -VAR_LDLIBS := -lmount -I/usr/include/libmount -endif - -CFLAGS += -O2 -g -std=gnu99 -Wall -I../../../../usr/include/ $(VAR_CFLAGS) -LDLIBS += $(VAR_LDLIBS) - TEST_PROGS := gpio-mockup.sh TEST_FILES := gpio-mockup-sysfs.sh -TEST_GEN_PROGS_EXTENDED := gpio-mockup-chardev +TEST_GEN_PROGS_EXTENDED := gpio-mockup-cdev -KSFT_KHDR_INSTALL := 1 include ../lib.mk - -GPIODIR := $(realpath ../../../gpio) -GPIOOUT := $(OUTPUT)/tools-gpio/ -GPIOOBJ := $(GPIOOUT)/gpio-utils.o - -CLEAN += ; $(RM) -rf $(GPIOOUT) - -$(TEST_GEN_PROGS_EXTENDED): $(GPIOOBJ) - -$(GPIOOUT): - mkdir -p $@ - -$(GPIOOBJ): $(GPIOOUT) - $(MAKE) OUTPUT=$(GPIOOUT) -C $(GPIODIR) diff --git a/tools/testing/selftests/gpio/gpio-mockup-cdev.c b/tools/testing/selftests/gpio/gpio-mockup-cdev.c new file mode 100644 index 000000000000..3a7fc3ac1349 --- /dev/null +++ b/tools/testing/selftests/gpio/gpio-mockup-cdev.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * GPIO mockup cdev test helper + * + * Copyright (C) 2020 Kent Gibson + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CONSUMER "gpio-mockup-cdev" + +static int request_line_v1(int cfd, unsigned int offset, + uint32_t flags, unsigned int val) +{ + struct gpiohandle_request req; + int ret; + + memset(&req, 0, sizeof(req)); + req.lines = 1; + req.lineoffsets[0] = offset; + req.flags = flags; + strcpy(req.consumer_label, CONSUMER); + if (flags & GPIOHANDLE_REQUEST_OUTPUT) + req.default_values[0] = val; + + ret = ioctl(cfd, GPIO_GET_LINEHANDLE_IOCTL, &req); + if (ret == -1) + return -errno; + return req.fd; +} + +static int get_value_v1(int lfd) +{ + struct gpiohandle_data vals; + int ret; + + memset(&vals, 0, sizeof(vals)); + ret = ioctl(lfd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &vals); + if (ret == -1) + return -errno; + return vals.values[0]; +} + +static void usage(char *prog) +{ + printf("Usage: %s [-l] [-b ] [-s ] [-u ] \n", prog); + printf(" -b: set line bias to one of pull-down, pull-up, disabled\n"); + printf(" (default is to leave bias unchanged):\n"); + printf(" -l: set line active low (default is active high)\n"); + printf(" -s: set line value (default is to get line value)\n"); + exit(-1); +} + +static int wait_signal(void) +{ + int sig; + sigset_t wset; + + sigemptyset(&wset); + sigaddset(&wset, SIGHUP); + sigaddset(&wset, SIGINT); + sigaddset(&wset, SIGTERM); + sigwait(&wset, &sig); + + return sig; +} + +int main(int argc, char *argv[]) +{ + char *chip; + int opt, ret, cfd, lfd; + unsigned int offset, val; + uint32_t flags_v1; + + ret = 0; + flags_v1 = GPIOHANDLE_REQUEST_INPUT; + + while ((opt = getopt(argc, argv, "lb:s:u:")) != -1) { + switch (opt) { + case 'l': + flags_v1 |= GPIOHANDLE_REQUEST_ACTIVE_LOW; + break; + case 'b': + if (strcmp("pull-up", optarg) == 0) + flags_v1 |= GPIOHANDLE_REQUEST_BIAS_PULL_UP; + else if (strcmp("pull-down", optarg) == 0) + flags_v1 |= GPIOHANDLE_REQUEST_BIAS_PULL_DOWN; + else if (strcmp("disabled", optarg) == 0) + flags_v1 |= GPIOHANDLE_REQUEST_BIAS_DISABLE; + break; + case 's': + val = atoi(optarg); + flags_v1 &= ~GPIOHANDLE_REQUEST_INPUT; + flags_v1 |= GPIOHANDLE_REQUEST_OUTPUT; + break; + default: + usage(argv[0]); + } + } + + if (argc < optind + 2) + usage(argv[0]); + + chip = argv[optind]; + offset = atoi(argv[optind + 1]); + + cfd = open(chip, 0); + if (cfd == -1) { + fprintf(stderr, "Failed to open %s: %s\n", chip, strerror(errno)); + return -errno; + } + + lfd = request_line_v1(cfd, offset, flags_v1, val); + + close(cfd); + + if (lfd < 0) { + fprintf(stderr, "Failed to request %s:%d: %s\n", chip, offset, strerror(-lfd)); + return lfd; + } + + if (flags_v1 & GPIOHANDLE_REQUEST_OUTPUT) + wait_signal(); + else + ret = get_value_v1(lfd); + + close(lfd); + + return ret; +} diff --git a/tools/testing/selftests/gpio/gpio-mockup-sysfs.sh b/tools/testing/selftests/gpio/gpio-mockup-sysfs.sh index dd269d877562..2d2e5d8763b6 100755 --- a/tools/testing/selftests/gpio/gpio-mockup-sysfs.sh +++ b/tools/testing/selftests/gpio/gpio-mockup-sysfs.sh @@ -1,135 +1,77 @@ # SPDX-License-Identifier: GPL-2.0 -is_consistent() -{ - val= - - active_low_sysfs=`cat $GPIO_SYSFS/gpio$nr/active_low` - val_sysfs=`cat $GPIO_SYSFS/gpio$nr/value` - dir_sysfs=`cat $GPIO_SYSFS/gpio$nr/direction` - gpio_this_debugfs=`cat $GPIO_DEBUGFS |grep "gpio-$nr" | sed "s/(.*)//g"` - dir_debugfs=`echo $gpio_this_debugfs | awk '{print $2}'` - val_debugfs=`echo $gpio_this_debugfs | awk '{print $3}'` - if [ $val_debugfs = "lo" ]; then - val=0 - elif [ $val_debugfs = "hi" ]; then - val=1 - fi +# Overrides functions in gpio-mockup.sh to test using the GPIO SYSFS uAPI - if [ $active_low_sysfs = "1" ]; then - if [ $val = "0" ]; then - val="1" - else - val="0" - fi - fi +SYSFS=`grep -w sysfs /proc/mounts | cut -f2 -d' '` +[ -d "$SYSFS" ] || skip "sysfs is not mounted" - if [ $val_sysfs = $val ] && [ $dir_sysfs = $dir_debugfs ]; then - echo -n "." - else - echo "test fail, exit" - die - fi -} +GPIO_SYSFS="${SYSFS}/class/gpio" +[ -d "$GPIO_SYSFS" ] || skip "CONFIG_GPIO_SYSFS is not selected" -test_pin_logic() -{ - nr=$1 - direction=$2 - active_low=$3 - value=$4 +PLATFORM_SYSFS=$SYSFS/devices/platform - echo $direction > $GPIO_SYSFS/gpio$nr/direction - echo $active_low > $GPIO_SYSFS/gpio$nr/active_low - if [ $direction = "out" ]; then - echo $value > $GPIO_SYSFS/gpio$nr/value - fi - is_consistent $nr -} +sysfs_nr= +sysfs_ldir= -test_one_pin() +# determine the sysfs GPIO number given the $chip and $offset +# e.g. gpiochip1:32 +find_sysfs_nr() { - nr=$1 - - echo -n "test pin<$nr>" - - echo $nr > $GPIO_SYSFS/export 2>/dev/null - - if [ X$? != X0 ]; then - echo "test GPIO pin $nr failed" - die - fi - - #"Checking if the sysfs is consistent with debugfs: " - is_consistent $nr - - #"Checking the logic of active_low: " - test_pin_logic $nr out 1 1 - test_pin_logic $nr out 1 0 - test_pin_logic $nr out 0 1 - test_pin_logic $nr out 0 0 - - #"Checking the logic of direction: " - test_pin_logic $nr in 1 1 - test_pin_logic $nr out 1 0 - test_pin_logic $nr low 0 1 - test_pin_logic $nr high 0 0 - - echo $nr > $GPIO_SYSFS/unexport - - echo "successful" + # e.g. /sys/devices/platform/gpio-mockup.1/gpiochip1 + local platform=$(find $PLATFORM_SYSFS -mindepth 2 -maxdepth 2 -type d -name $chip) + [ "$platform" ] || fail "can't find platform of $chip" + # e.g. /sys/devices/platform/gpio-mockup.1/gpio/gpiochip508/base + local base=$(find ${platform%/*}/gpio/ -mindepth 2 -maxdepth 2 -type f -name base) + [ "$base" ] || fail "can't find base of $chip" + sysfs_nr=$(($(< "$base") + $offset)) + sysfs_ldir="$GPIO_SYSFS/gpio$sysfs_nr" } -test_one_pin_fail() +acquire_line() { - nr=$1 - - echo $nr > $GPIO_SYSFS/export 2>/dev/null - - if [ X$? != X0 ]; then - echo "test invalid pin $nr successful" - else - echo "test invalid pin $nr failed" - echo $nr > $GPIO_SYSFS/unexport 2>/dev/null - die - fi + [ "$sysfs_nr" ] && return + find_sysfs_nr + echo "$sysfs_nr" > "$GPIO_SYSFS/export" } -list_chip() +# The helpers being overridden... +get_line() { - echo `ls -d $GPIO_DRV_SYSFS/gpiochip* 2>/dev/null` + [ -e "$sysfs_ldir/value" ] && echo $(< "$sysfs_ldir/value") } -test_chip() +set_line() { - chip=$1 - name=`basename $chip` - base=`cat $chip/base` - ngpio=`cat $chip/ngpio` - printf "%-10s %-5s %-5s\n" $name $base $ngpio - if [ $ngpio = "0" ]; then - echo "number of gpio is zero is not allowed". - fi - test_one_pin $base - test_one_pin $(($base + $ngpio - 1)) - test_one_pin $((( RANDOM % $ngpio ) + $base )) + acquire_line + + for option in $*; do + case $option in + active-high) + echo 0 > "$sysfs_ldir/active_low" + ;; + active-low) + echo 1 > "$sysfs_ldir/active_low" + ;; + input) + echo "in" > "$sysfs_ldir/direction" + ;; + 0) + echo "out" > "$sysfs_ldir/direction" + echo 0 > "$sysfs_ldir/value" + ;; + 1) + echo "out" > "$sysfs_ldir/direction" + echo 1 > "$sysfs_ldir/value" + ;; + esac + done } -test_chips_sysfs() +release_line() { - gpiochip=`list_chip $module` - if [ X"$gpiochip" = X ]; then - if [ X"$valid" = Xfalse ]; then - echo "successful" - else - echo "fail" - die - fi - else - for chip in $gpiochip; do - test_chip $chip - done - fi + [ "$sysfs_nr" ] || return 0 + echo "$sysfs_nr" > "$GPIO_SYSFS/unexport" + sysfs_nr= + sysfs_ldir= } - diff --git a/tools/testing/selftests/gpio/gpio-mockup.sh b/tools/testing/selftests/gpio/gpio-mockup.sh index 7f35b9880485..0aa8e4294de1 100755 --- a/tools/testing/selftests/gpio/gpio-mockup.sh +++ b/tools/testing/selftests/gpio/gpio-mockup.sh @@ -1,72 +1,55 @@ -#!/bin/bash +#!/bin/bash -efu # SPDX-License-Identifier: GPL-2.0 #exit status -#1: Internal error -#2: sysfs/debugfs not mount -#3: insert module fail when gpio-mockup is a module. -#4: Skip test including run as non-root user. -#5: other reason. - -SYSFS= -GPIO_SYSFS= -GPIO_DRV_SYSFS= +#0: success +#1: fail +#4: skip test - including run as non-root user + +BASE=${0%/*} DEBUGFS= GPIO_DEBUGFS= -dev_type= -module= +dev_type="cdev" +module="gpio-mockup" +verbose= +full_test= +random= +active_opt= +bias_opt= +line_set_pid= -# Kselftest framework requirement - SKIP code is 4. +# Kselftest return codes +ksft_fail=1 ksft_skip=4 usage() { echo "Usage:" - echo "$0 [-f] [-m name] [-t type]" - echo "-f: full test. It maybe conflict with existence gpio device." - echo "-m: module name, default name is gpio-mockup. It could also test" - echo " other gpio device." - echo "-t: interface type: chardev(char device) and sysfs(being" - echo " deprecated). The first one is default" - echo "" - echo "$0 -h" - echo "This usage" + echo "$0 [-frv] [-t type]" + echo "-f: full test (minimal set run by default)" + echo "-r: test random lines as well as fence posts" + echo "-t: interface type:" + echo " cdev (character device ABI) - default" + echo " sysfs (deprecated SYSFS ABI)" + echo "-v: verbose progress reporting" + exit $ksft_fail } -prerequisite() +skip() { - msg="skip all tests:" - if [ $UID != 0 ]; then - echo $msg must be run as root >&2 - exit $ksft_skip - fi - SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'` - if [ ! -d "$SYSFS" ]; then - echo $msg sysfs is not mounted >&2 - exit 2 - fi - GPIO_SYSFS=`echo $SYSFS/class/gpio` - GPIO_DRV_SYSFS=`echo $SYSFS/devices/platform/$module/gpio` - DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'` - if [ ! -d "$DEBUGFS" ]; then - echo $msg debugfs is not mounted >&2 - exit 2 - fi - GPIO_DEBUGFS=`echo $DEBUGFS/gpio` - source gpio-mockup-sysfs.sh + echo "$*" >&2 + echo "GPIO $module test SKIP" + exit $ksft_skip } -try_insert_module() +prerequisite() { - if [ -d "$GPIO_DRV_SYSFS" ]; then - echo "$GPIO_DRV_SYSFS exist. Skip insert module" - else - modprobe -q $module $1 - if [ X$? != X0 ]; then - echo $msg insmod $module failed >&2 - exit 3 - fi - fi + [ $(id -u) -eq 0 ] || skip "must be run as root" + + DEBUGFS=$(grep -w debugfs /proc/mounts | cut -f2 -d' ') + [ -d "$DEBUGFS" ] || skip "debugfs is not mounted" + + GPIO_DEBUGFS=$DEBUGFS/$module } remove_module() @@ -74,133 +57,340 @@ remove_module() modprobe -r -q $module } -die() +cleanup() { + set +e + release_line remove_module - exit 5 + jobs -p | xargs -r kill > /dev/null 2>&1 } -test_chips() +fail() { - if [ X$dev_type = Xsysfs ]; then - echo "WARNING: sysfs ABI of gpio is going to deprecated." - test_chips_sysfs $* - else - $BASE/gpio-mockup-chardev $* - fi + echo "test failed: $*" >&2 + echo "GPIO $module test FAIL" + exit $ksft_fail +} + +try_insert_module() +{ + modprobe -q $module "$1" || fail "insert $module failed with error $?" +} + +log() +{ + [ -z "$verbose" ] || echo "$*" } -gpio_test() +# The following line helpers, release_Line, get_line and set_line, all +# make use of the global $chip and $offset variables. +# +# This implementation drives the GPIO character device (cdev) uAPI. +# Other implementations may override these to test different uAPIs. + +# Release any resources related to the line +release_line() { - param=$1 - valid=$2 + [ "$line_set_pid" ] && kill $line_set_pid && wait $line_set_pid || true + line_set_pid= +} - if [ X"$param" = X ]; then - die +# Read the current value of the line +get_line() +{ + release_line + + $BASE/gpio-mockup-cdev $active_opt /dev/$chip $offset + echo $? +} + +# Set the state of the line +# +# Changes to line configuration are provided as parameters. +# The line is assumed to be an output if the line value 0 or 1 is +# specified, else an input. +set_line() +{ + local val= + + release_line + + # parse config options... + for option in $*; do + case $option in + active-low) + active_opt="-l " + ;; + active-high) + active_opt= + ;; + bias-none) + bias_opt= + ;; + pull-down) + bias_opt="-bpull-down " + ;; + pull-up) + bias_opt="-bpull-up " + ;; + 0) + val=0 + ;; + 1) + val=1 + ;; + esac + done + + local cdev_opts=${active_opt} + if [ "$val" ]; then + $BASE/gpio-mockup-cdev $cdev_opts -s$val /dev/$chip $offset & + # failure to set is detected by reading mockup and toggling values + line_set_pid=$! + # allow for gpio-mockup-cdev to launch and request line + # (there is limited value in checking if line has been requested) + sleep 0.01 + elif [ "$bias_opt" ]; then + cdev_opts=${cdev_opts}${bias_opt} + $BASE/gpio-mockup-cdev $cdev_opts /dev/$chip $offset || true fi - try_insert_module "gpio_mockup_ranges=$param" - echo -n "GPIO $module test with ranges: <" - echo "$param>: " - printf "%-10s %s\n" $param - test_chips $module $valid - remove_module } -BASE=`dirname $0` +assert_line() +{ + local val + # don't need any retry here as set_mock allows for propagation + val=$(get_line) + [ "$val" = "$1" ] || fail "line value is ${val:-empty} when $1 was expected" +} + +# The following mockup helpers all make use of the $mock_line +assert_mock() +{ + local backoff_wait=10 + local retry=0 + local val + # retry allows for set propagation from uAPI to mockup + while true; do + val=$(< $mock_line) + [ "$val" = "$1" ] && break + retry=$((retry + 1)) + [ $retry -lt 5 ] || fail "mockup $mock_line value ${val:-empty} when $1 expected" + sleep $(printf "%0.2f" $((backoff_wait))e-3) + backoff_wait=$((backoff_wait * 2)) + done +} + +set_mock() +{ + echo "$1" > $mock_line + # allow for set propagation - so we won't be in a race with set_line + assert_mock "$1" +} -dev_type= -TEMP=`getopt -o fhm:t: -n '$0' -- "$@"` +# test the functionality of a line +# +# The line is set from the mockup side and is read from the userspace side +# (input), and is set from the userspace side and is read from the mockup side +# (output). +# +# Setting the mockup pull using the userspace interface bias settings is +# tested where supported by the userspace interface (cdev). +test_line() +{ + chip=$1 + offset=$2 + log "test_line $chip $offset" + mock_line=$GPIO_DEBUGFS/$chip/$offset + [ -e "$mock_line" ] || fail "missing line $chip:$offset" -if [ "$?" != "0" ]; then - echo "Parameter process failed, Terminating..." >&2 - exit 1 -fi + # test input active-high + set_mock 1 + set_line input active-high + assert_line 1 + set_mock 0 + assert_line 0 + set_mock 1 + assert_line 1 + + if [ "$full_test" ]; then + if [ "$dev_type" != "sysfs" ]; then + # test pulls + set_mock 0 + set_line input pull-up + assert_line 1 + set_mock 0 + assert_line 0 + + set_mock 1 + set_line input pull-down + assert_line 0 + set_mock 1 + assert_line 1 + + set_line bias-none + fi + + # test input active-low + set_mock 0 + set_line active-low + assert_line 1 + set_mock 1 + assert_line 0 + set_mock 0 + assert_line 1 + + # test output active-high + set_mock 1 + set_line active-high 0 + assert_mock 0 + set_line 1 + assert_mock 1 + set_line 0 + assert_mock 0 + fi + + # test output active-low + set_mock 0 + set_line active-low 0 + assert_mock 1 + set_line 1 + assert_mock 0 + set_line 0 + assert_mock 1 + + release_line +} + +test_no_line() +{ + log test_no_line "$*" + [ ! -e "$GPIO_DEBUGFS/$1/$2" ] || fail "unexpected line $1:$2" +} -# Note the quotes around `$TEMP': they are essential! -eval set -- "$TEMP" +# Load the module and check that the expected number of gpiochips, with the +# expected number of lines, are created and are functional. +# +# $1 is the gpio_mockup_ranges parameter for the module +# The remaining parameters are the number of lines, n, expected for each of +# the gpiochips expected to be created. +# +# For each gpiochip the fence post lines, 0 and n-1, are tested, and the +# line on the far side of the fence post, n, is tested to not exist. +# +# If the $random flag is set then a random line in the middle of the +# gpiochip is tested as well. +insmod_test() +{ + local ranges= + local gc= + local width= -while true; do - case $1 in - -f) + [ "${1:-}" ] || fail "missing ranges" + ranges=$1 ; shift + try_insert_module "gpio_mockup_ranges=$ranges" + log "GPIO $module test with ranges: <$ranges>:" + # e.g. /sys/kernel/debug/gpio-mockup/gpiochip1 + gpiochip=$(find "$DEBUGFS/$module/" -name gpiochip* -type d | sort) + for chip in $gpiochip; do + gc=${chip##*/} + [ "${1:-}" ] || fail "unexpected chip - $gc" + width=$1 ; shift + test_line $gc 0 + if [ "$random" -a $width -gt 2 ]; then + test_line $gc $((RANDOM % ($width - 2) + 1)) + fi + test_line $gc $(($width - 1)) + test_no_line $gc $width + done + [ "${1:-}" ] && fail "missing expected chip of width $1" + remove_module || fail "failed to remove module with error $?" +} + +while getopts ":frvt:" opt; do + case $opt in + f) full_test=true - shift - ;; - -h) - usage - exit ;; - -m) - module=$2 - shift 2 + r) + random=true ;; - -t) - dev_type=$2 - shift 2 + t) + dev_type=$OPTARG ;; - --) - shift - break + v) + verbose=true ;; *) - echo "Internal error!" - exit 1 + usage ;; esac done +shift $((OPTIND - 1)) -if [ X"$module" = X ]; then - module="gpio-mockup" -fi - -if [ X$dev_type != Xsysfs ]; then - dev_type="chardev" -fi +[ "${1:-}" ] && fail "unknown argument '$1'" prerequisite -echo "1. Test dynamic allocation of gpio successful means insert gpiochip and" -echo " manipulate gpio pin successful" -gpio_test "-1,32" true -gpio_test "-1,32,-1,32" true -gpio_test "-1,32,-1,32,-1,32" true -if [ X$full_test = Xtrue ]; then - gpio_test "-1,32,32,64" true - gpio_test "-1,32,40,64,-1,5" true - gpio_test "-1,32,32,64,-1,32" true - gpio_test "0,32,32,64,-1,32,-1,32" true - gpio_test "-1,32,-1,32,0,32,32,64" true - echo "2. Do basic test: successful means insert gpiochip and" - echo " manipulate gpio pin successful" - gpio_test "0,32" true - gpio_test "0,32,32,64" true - gpio_test "0,32,40,64,64,96" true +trap 'exit $ksft_fail' SIGTERM SIGINT +trap cleanup EXIT + +case "$dev_type" in +sysfs) + source $BASE/gpio-mockup-sysfs.sh + echo "WARNING: gpio sysfs ABI is deprecated." + ;; +cdev) + ;; +*) + fail "unknown interface type: $dev_type" + ;; +esac + +remove_module || fail "can't remove existing $module module" + +# manual gpio allocation tests fail if a physical chip already exists +[ "$full_test" -a -e "/dev/gpiochip0" ] && skip "full tests conflict with gpiochip0" + +echo "1. Module load tests" +echo "1.1. dynamic allocation of gpio" +insmod_test "-1,32" 32 +insmod_test "-1,23,-1,32" 23 32 +insmod_test "-1,23,-1,26,-1,32" 23 26 32 +if [ "$full_test" ]; then + echo "1.2. manual allocation of gpio" + insmod_test "0,32" 32 + insmod_test "0,32,32,60" 32 28 + insmod_test "0,32,40,64,64,96" 32 24 32 + echo "1.3. dynamic and manual allocation of gpio" + insmod_test "-1,32,32,62" 32 30 + insmod_test "-1,22,-1,23,0,24,32,64" 22 23 24 32 + insmod_test "-1,32,32,60,-1,29" 32 28 29 + insmod_test "-1,32,40,64,-1,5" 32 24 5 + insmod_test "0,32,32,44,-1,22,-1,31" 32 12 22 31 fi -echo "3. Error test: successful means insert gpiochip failed" -echo "3.1 Test number of gpio overflow" -#Currently: The max number of gpio(1024) is defined in arm architecture. -gpio_test "-1,32,-1,1024" false -if [ X$full_test = Xtrue ]; then - echo "3.2 Test zero line of gpio" - gpio_test "0,0" false - echo "3.3 Test range overlap" - echo "3.3.1 Test corner case" - gpio_test "0,32,0,1" false - gpio_test "0,32,32,64,32,40" false - gpio_test "0,32,35,64,35,45" false - gpio_test "0,32,31,32" false - gpio_test "0,32,32,64,36,37" false - gpio_test "0,32,35,64,34,36" false - echo "3.3.2 Test inserting invalid second gpiochip" - gpio_test "0,32,30,35" false - gpio_test "0,32,1,5" false - gpio_test "10,32,9,14" false - gpio_test "10,32,30,35" false - echo "3.3.3 Test others" - gpio_test "0,32,40,56,39,45" false - gpio_test "0,32,40,56,30,33" false - gpio_test "0,32,40,56,30,41" false - gpio_test "0,32,40,56,20,21" false +echo "2. Module load error tests" +echo "2.1 gpio overflow" +# Currently: The max number of gpio(1024) is defined in arm architecture. +insmod_test "-1,1024" +if [ "$full_test" ]; then + echo "2.2 no lines defined" + insmod_test "0,0" + echo "2.3 ignore range overlap" + insmod_test "0,32,0,1" 32 + insmod_test "0,32,1,5" 32 + insmod_test "0,32,30,35" 32 + insmod_test "0,32,31,32" 32 + insmod_test "10,32,30,35" 22 + insmod_test "10,32,9,14" 22 + insmod_test "0,32,20,21,40,56" 32 16 + insmod_test "0,32,32,64,32,40" 32 32 + insmod_test "0,32,32,64,36,37" 32 32 + insmod_test "0,32,35,64,34,36" 32 29 + insmod_test "0,30,35,64,35,45" 30 29 + insmod_test "0,32,40,56,30,33" 32 16 + insmod_test "0,32,40,56,30,41" 32 16 + insmod_test "0,32,40,56,39,45" 32 16 fi -echo GPIO test PASS - +echo "GPIO $module test PASS" -- cgit v1.2.3 From e029759861d6376c1245fad983907c13d9b9d039 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Tue, 19 Jan 2021 20:30:54 +0800 Subject: selftests: gpio: remove obsolete gpio-mockup-chardev.c GPIO selftests have changed to new gpio-mockup-cdev helper, so remove old gpio-mockup-chardev helper. Signed-off-by: Kent Gibson Acked-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- tools/testing/selftests/gpio/gpio-mockup-chardev.c | 323 --------------------- 1 file changed, 323 deletions(-) delete mode 100644 tools/testing/selftests/gpio/gpio-mockup-chardev.c diff --git a/tools/testing/selftests/gpio/gpio-mockup-chardev.c b/tools/testing/selftests/gpio/gpio-mockup-chardev.c deleted file mode 100644 index 73ead8828d3a..000000000000 --- a/tools/testing/selftests/gpio/gpio-mockup-chardev.c +++ /dev/null @@ -1,323 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * GPIO chardev test helper - * - * Copyright (C) 2016 Bamvor Jian Zhang - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../../../gpio/gpio-utils.h" - -#define CONSUMER "gpio-selftest" -#define GC_NUM 10 -enum direction { - OUT, - IN -}; - -static int get_debugfs(char **path) -{ - struct libmnt_context *cxt; - struct libmnt_table *tb; - struct libmnt_iter *itr = NULL; - struct libmnt_fs *fs; - int found = 0, ret; - - cxt = mnt_new_context(); - if (!cxt) - err(EXIT_FAILURE, "libmount context allocation failed"); - - itr = mnt_new_iter(MNT_ITER_FORWARD); - if (!itr) - err(EXIT_FAILURE, "failed to initialize libmount iterator"); - - if (mnt_context_get_mtab(cxt, &tb)) - err(EXIT_FAILURE, "failed to read mtab"); - - while (mnt_table_next_fs(tb, itr, &fs) == 0) { - const char *type = mnt_fs_get_fstype(fs); - - if (!strcmp(type, "debugfs")) { - found = 1; - break; - } - } - if (found) { - ret = asprintf(path, "%s/gpio", mnt_fs_get_target(fs)); - if (ret < 0) - err(EXIT_FAILURE, "failed to format string"); - } - - mnt_free_iter(itr); - mnt_free_context(cxt); - - if (!found) - return -1; - - return 0; -} - -static int gpio_debugfs_get(const char *consumer, int *dir, int *value) -{ - char *debugfs; - FILE *f; - char *line = NULL; - size_t len = 0; - char *cur; - int found = 0; - - if (get_debugfs(&debugfs) != 0) - err(EXIT_FAILURE, "debugfs is not mounted"); - - f = fopen(debugfs, "r"); - if (!f) - err(EXIT_FAILURE, "read from gpio debugfs failed"); - - /* - * gpio-2 ( |gpio-selftest ) in lo - */ - while (getline(&line, &len, f) != -1) { - cur = strstr(line, consumer); - if (cur == NULL) - continue; - - cur = strchr(line, ')'); - if (!cur) - continue; - - cur += 2; - if (!strncmp(cur, "out", 3)) { - *dir = OUT; - cur += 4; - } else if (!strncmp(cur, "in", 2)) { - *dir = IN; - cur += 4; - } - - if (!strncmp(cur, "hi", 2)) - *value = 1; - else if (!strncmp(cur, "lo", 2)) - *value = 0; - - found = 1; - break; - } - free(debugfs); - fclose(f); - free(line); - - if (!found) - return -1; - - return 0; -} - -static struct gpiochip_info *list_gpiochip(const char *gpiochip_name, int *ret) -{ - struct gpiochip_info *cinfo; - struct gpiochip_info *current; - const struct dirent *ent; - DIR *dp; - char *chrdev_name; - int fd; - int i = 0; - - cinfo = calloc(sizeof(struct gpiochip_info) * 4, GC_NUM + 1); - if (!cinfo) - err(EXIT_FAILURE, "gpiochip_info allocation failed"); - - current = cinfo; - dp = opendir("/dev"); - if (!dp) { - *ret = -errno; - goto error_out; - } else { - *ret = 0; - } - - while (ent = readdir(dp), ent) { - if (check_prefix(ent->d_name, "gpiochip")) { - *ret = asprintf(&chrdev_name, "/dev/%s", ent->d_name); - if (*ret < 0) - goto error_out; - - fd = open(chrdev_name, 0); - if (fd == -1) { - *ret = -errno; - fprintf(stderr, "Failed to open %s\n", - chrdev_name); - goto error_close_dir; - } - *ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, current); - if (*ret == -1) { - perror("Failed to issue CHIPINFO IOCTL\n"); - goto error_close_dir; - } - close(fd); - if (strcmp(current->label, gpiochip_name) == 0 - || check_prefix(current->label, gpiochip_name)) { - *ret = 0; - current++; - i++; - } - } - } - - if ((!*ret && i == 0) || *ret < 0) { - free(cinfo); - cinfo = NULL; - } - if (!*ret && i > 0) { - cinfo = realloc(cinfo, sizeof(struct gpiochip_info) * 4 * i); - *ret = i; - } - -error_close_dir: - closedir(dp); -error_out: - if (*ret < 0) - err(EXIT_FAILURE, "list gpiochip failed: %s", strerror(*ret)); - - return cinfo; -} - -int gpio_pin_test(struct gpiochip_info *cinfo, int line, int flag, int value) -{ - struct gpiohandle_data data; - unsigned int lines[] = {line}; - int fd; - int debugfs_dir = IN; - int debugfs_value = 0; - int ret; - - data.values[0] = value; - ret = gpiotools_request_linehandle(cinfo->name, lines, 1, flag, &data, - CONSUMER); - if (ret < 0) - goto fail_out; - else - fd = ret; - - ret = gpio_debugfs_get(CONSUMER, &debugfs_dir, &debugfs_value); - if (ret) { - ret = -EINVAL; - goto fail_out; - } - if (flag & GPIOHANDLE_REQUEST_INPUT) { - if (debugfs_dir != IN) { - errno = -EINVAL; - ret = -errno; - } - } else if (flag & GPIOHANDLE_REQUEST_OUTPUT) { - if (flag & GPIOHANDLE_REQUEST_ACTIVE_LOW) - debugfs_value = !debugfs_value; - - if (!(debugfs_dir == OUT && value == debugfs_value)) { - errno = -EINVAL; - ret = -errno; - } - } - gpiotools_release_linehandle(fd); - -fail_out: - if (ret) - err(EXIT_FAILURE, "gpio<%s> line<%d> test flag<0x%x> value<%d>", - cinfo->name, line, flag, value); - - return ret; -} - -void gpio_pin_tests(struct gpiochip_info *cinfo, unsigned int line) -{ - printf("line<%d>", line); - gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_OUTPUT, 0); - printf("."); - gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_OUTPUT, 1); - printf("."); - gpio_pin_test(cinfo, line, - GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW, - 0); - printf("."); - gpio_pin_test(cinfo, line, - GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW, - 1); - printf("."); - gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_INPUT, 0); - printf("."); -} - -/* - * ./gpio-mockup-chardev gpio_chip_name_prefix is_valid_gpio_chip - * Return 0 if successful or exit with EXIT_FAILURE if test failed. - * gpio_chip_name_prefix: The prefix of gpiochip you want to test. E.g. - * gpio-mockup - * is_valid_gpio_chip: Whether the gpio_chip is valid. 1 means valid, - * 0 means invalid which could not be found by - * list_gpiochip. - */ -int main(int argc, char *argv[]) -{ - char *prefix; - int valid; - struct gpiochip_info *cinfo; - struct gpiochip_info *current; - int i; - int ret; - - if (argc < 3) { - printf("Usage: %s prefix is_valid", argv[0]); - exit(EXIT_FAILURE); - } - - prefix = argv[1]; - valid = strcmp(argv[2], "true") == 0 ? 1 : 0; - - printf("Test gpiochip %s: ", prefix); - cinfo = list_gpiochip(prefix, &ret); - if (!cinfo) { - if (!valid && ret == 0) { - printf("Invalid test successful\n"); - ret = 0; - goto out; - } else { - ret = -EINVAL; - goto out; - } - } else if (cinfo && !valid) { - ret = -EINVAL; - goto out; - } - current = cinfo; - for (i = 0; i < ret; i++) { - gpio_pin_tests(current, 0); - gpio_pin_tests(current, current->lines - 1); - gpio_pin_tests(current, random() % current->lines); - current++; - } - ret = 0; - printf("successful\n"); - -out: - if (ret) - fprintf(stderr, "gpio<%s> test failed\n", prefix); - - if (cinfo) - free(cinfo); - - if (ret) - exit(EXIT_FAILURE); - - return ret; -} -- cgit v1.2.3 From 01e1250f135b081accb03155225d793bb80cef54 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Tue, 19 Jan 2021 20:30:55 +0800 Subject: selftests: remove obsolete build restriction for gpio Build restrictions related to the gpio-mockup-chardev helper are no longer relevant so remove them. Signed-off-by: Kent Gibson Acked-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- tools/testing/selftests/Makefile | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 8a917cb4426a..d0566be260a2 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -125,15 +125,6 @@ ARCH ?= $(SUBARCH) export KSFT_KHDR_INSTALL_DONE := 1 export BUILD -# build and run gpio when output directory is the src dir. -# gpio has dependency on tools/gpio and builds tools/gpio -# objects in the src directory in all cases making the src -# repo dirty even when objects are relocated. -ifneq (1,$(DEFAULT_INSTALL_HDR_PATH)) - TMP := $(filter-out gpio, $(TARGETS)) - TARGETS := $(TMP) -endif - # set default goal to all, so make without a target runs all, even when # all isn't the first target in the file. .DEFAULT_GOAL := all -- cgit v1.2.3 From 999e71c35122b4e9d9a9f7245c9fe7fd72ae5ca3 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Tue, 19 Jan 2021 20:30:56 +0800 Subject: selftests: remove obsolete gpio references from kselftest_deps.sh GPIO Makefile has been greatly simplified so remove references to lines which no longer exist. Signed-off-by: Kent Gibson Acked-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- tools/testing/selftests/kselftest_deps.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/testing/selftests/kselftest_deps.sh b/tools/testing/selftests/kselftest_deps.sh index bbc04646346b..00e60d6eb16b 100755 --- a/tools/testing/selftests/kselftest_deps.sh +++ b/tools/testing/selftests/kselftest_deps.sh @@ -129,13 +129,11 @@ l2_tests=$(grep -r --include=Makefile ": LDLIBS" | \ grep -v "VAR_LDLIBS" | awk -F: '{print $1}') # Level 3 -# gpio, memfd and others use pkg-config to find mount and fuse libs +# memfd and others use pkg-config to find mount and fuse libs # respectively and save it in VAR_LDLIBS. If pkg-config doesn't find # any, VAR_LDLIBS set to default. # Use the default value and filter out pkg-config for dependency check. # e.g: -# gpio/Makefile -# VAR_LDLIBS := $(shell pkg-config --libs mount) 2>/dev/null) # memfd/Makefile # VAR_LDLIBS := $(shell pkg-config fuse --libs 2>/dev/null) -- cgit v1.2.3 From ef0d6d977502dacf38fb33a294a43bd0e631fbd2 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Tue, 19 Jan 2021 20:30:57 +0800 Subject: tools: gpio: remove uAPI v1 code no longer used by selftests gpio-mockup-chardev helper has been obsoleted and removed, so also remove the tools/gpio code that it, and nothing else, was using. Signed-off-by: Kent Gibson Acked-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- tools/gpio/gpio-utils.c | 89 ------------------------------------------------- tools/gpio/gpio-utils.h | 6 ---- 2 files changed, 95 deletions(-) diff --git a/tools/gpio/gpio-utils.c b/tools/gpio/gpio-utils.c index 37187e056c8b..1639b4d832cd 100644 --- a/tools/gpio/gpio-utils.c +++ b/tools/gpio/gpio-utils.c @@ -32,74 +32,6 @@ * following api will request gpio lines, do the operation and then * release these lines. */ -/** - * gpiotools_request_linehandle() - request gpio lines in a gpiochip - * @device_name: The name of gpiochip without prefix "/dev/", - * such as "gpiochip0" - * @lines: An array desired lines, specified by offset - * index for the associated GPIO device. - * @num_lines: The number of lines to request. - * @flag: The new flag for requsted gpio. Reference - * "linux/gpio.h" for the meaning of flag. - * @data: Default value will be set to gpio when flag is - * GPIOHANDLE_REQUEST_OUTPUT. - * @consumer_label: The name of consumer, such as "sysfs", - * "powerkey". This is useful for other users to - * know who is using. - * - * Request gpio lines through the ioctl provided by chardev. User - * could call gpiotools_set_values() and gpiotools_get_values() to - * read and write respectively through the returned fd. Call - * gpiotools_release_linehandle() to release these lines after that. - * - * Return: On success return the fd; - * On failure return the errno. - */ -int gpiotools_request_linehandle(const char *device_name, unsigned int *lines, - unsigned int num_lines, unsigned int flag, - struct gpiohandle_data *data, - const char *consumer_label) -{ - struct gpiohandle_request req; - char *chrdev_name; - int fd; - int i; - int ret; - - ret = asprintf(&chrdev_name, "/dev/%s", device_name); - if (ret < 0) - return -ENOMEM; - - fd = open(chrdev_name, 0); - if (fd == -1) { - ret = -errno; - fprintf(stderr, "Failed to open %s, %s\n", - chrdev_name, strerror(errno)); - goto exit_free_name; - } - - for (i = 0; i < num_lines; i++) - req.lineoffsets[i] = lines[i]; - - req.flags = flag; - strcpy(req.consumer_label, consumer_label); - req.lines = num_lines; - if (flag & GPIOHANDLE_REQUEST_OUTPUT) - memcpy(req.default_values, data, sizeof(req.default_values)); - - ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req); - if (ret == -1) { - ret = -errno; - fprintf(stderr, "Failed to issue %s (%d), %s\n", - "GPIO_GET_LINEHANDLE_IOCTL", ret, strerror(errno)); - } - - if (close(fd) == -1) - perror("Failed to close GPIO character device file"); -exit_free_name: - free(chrdev_name); - return ret < 0 ? ret : req.fd; -} /** * gpiotools_request_line() - request gpio lines in a gpiochip @@ -215,27 +147,6 @@ int gpiotools_get_values(const int fd, struct gpio_v2_line_values *values) return ret; } -/** - * gpiotools_release_linehandle(): Release the line(s) of gpiochip - * @fd: The fd returned by - * gpiotools_request_linehandle(). - * - * Return: On success return 0; - * On failure return the errno. - */ -int gpiotools_release_linehandle(const int fd) -{ - int ret; - - ret = close(fd); - if (ret == -1) { - perror("Failed to close GPIO LINEHANDLE device file"); - ret = -errno; - } - - return ret; -} - /** * gpiotools_release_line(): Release the line(s) of gpiochip * @fd: The fd returned by diff --git a/tools/gpio/gpio-utils.h b/tools/gpio/gpio-utils.h index 6c69a9f1c253..8af7c8ee19ce 100644 --- a/tools/gpio/gpio-utils.h +++ b/tools/gpio/gpio-utils.h @@ -24,12 +24,6 @@ static inline int check_prefix(const char *str, const char *prefix) strncmp(str, prefix, strlen(prefix)) == 0; } -int gpiotools_request_linehandle(const char *device_name, unsigned int *lines, - unsigned int num_lines, unsigned int flag, - struct gpiohandle_data *data, - const char *consumer_label); -int gpiotools_release_linehandle(const int fd); - int gpiotools_request_line(const char *device_name, unsigned int *lines, unsigned int num_lines, -- cgit v1.2.3 From 10f33652c0e791fcc36201cacd78cc83db9baa9e Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Tue, 19 Jan 2021 20:30:58 +0800 Subject: selftests: gpio: port to GPIO uAPI v2 Add a port to the GPIO uAPI v2 interface and make it the default. Signed-off-by: Kent Gibson Acked-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- tools/testing/selftests/gpio/gpio-mockup-cdev.c | 75 ++++++++++++++++++++++--- tools/testing/selftests/gpio/gpio-mockup.sh | 11 +++- 2 files changed, 76 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/gpio/gpio-mockup-cdev.c b/tools/testing/selftests/gpio/gpio-mockup-cdev.c index 3a7fc3ac1349..e83eac71621a 100644 --- a/tools/testing/selftests/gpio/gpio-mockup-cdev.c +++ b/tools/testing/selftests/gpio/gpio-mockup-cdev.c @@ -18,6 +18,44 @@ #define CONSUMER "gpio-mockup-cdev" +static int request_line_v2(int cfd, unsigned int offset, + uint64_t flags, unsigned int val) +{ + struct gpio_v2_line_request req; + int ret; + + memset(&req, 0, sizeof(req)); + req.num_lines = 1; + req.offsets[0] = offset; + req.config.flags = flags; + strcpy(req.consumer, CONSUMER); + if (flags & GPIO_V2_LINE_FLAG_OUTPUT) { + req.config.num_attrs = 1; + req.config.attrs[0].mask = 1; + req.config.attrs[0].attr.id = GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES; + if (val) + req.config.attrs[0].attr.values = 1; + } + ret = ioctl(cfd, GPIO_V2_GET_LINE_IOCTL, &req); + if (ret == -1) + return -errno; + return req.fd; +} + + +static int get_value_v2(int lfd) +{ + struct gpio_v2_line_values vals; + int ret; + + memset(&vals, 0, sizeof(vals)); + vals.mask = 1; + ret = ioctl(lfd, GPIO_V2_LINE_GET_VALUES_IOCTL, &vals); + if (ret == -1) + return -errno; + return vals.bits & 0x1; +} + static int request_line_v1(int cfd, unsigned int offset, uint32_t flags, unsigned int val) { @@ -57,6 +95,7 @@ static void usage(char *prog) printf(" (default is to leave bias unchanged):\n"); printf(" -l: set line active low (default is active high)\n"); printf(" -s: set line value (default is to get line value)\n"); + printf(" -u: uAPI version to use (default is 2)\n"); exit(-1); } @@ -78,29 +117,42 @@ int main(int argc, char *argv[]) { char *chip; int opt, ret, cfd, lfd; - unsigned int offset, val; + unsigned int offset, val, abiv; uint32_t flags_v1; + uint64_t flags_v2; + abiv = 2; ret = 0; flags_v1 = GPIOHANDLE_REQUEST_INPUT; + flags_v2 = GPIO_V2_LINE_FLAG_INPUT; while ((opt = getopt(argc, argv, "lb:s:u:")) != -1) { switch (opt) { case 'l': flags_v1 |= GPIOHANDLE_REQUEST_ACTIVE_LOW; + flags_v2 |= GPIO_V2_LINE_FLAG_ACTIVE_LOW; break; case 'b': - if (strcmp("pull-up", optarg) == 0) + if (strcmp("pull-up", optarg) == 0) { flags_v1 |= GPIOHANDLE_REQUEST_BIAS_PULL_UP; - else if (strcmp("pull-down", optarg) == 0) + flags_v2 |= GPIO_V2_LINE_FLAG_BIAS_PULL_UP; + } else if (strcmp("pull-down", optarg) == 0) { flags_v1 |= GPIOHANDLE_REQUEST_BIAS_PULL_DOWN; - else if (strcmp("disabled", optarg) == 0) + flags_v2 |= GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN; + } else if (strcmp("disabled", optarg) == 0) { flags_v1 |= GPIOHANDLE_REQUEST_BIAS_DISABLE; + flags_v2 |= GPIO_V2_LINE_FLAG_BIAS_DISABLED; + } break; case 's': val = atoi(optarg); flags_v1 &= ~GPIOHANDLE_REQUEST_INPUT; flags_v1 |= GPIOHANDLE_REQUEST_OUTPUT; + flags_v2 &= ~GPIO_V2_LINE_FLAG_INPUT; + flags_v2 |= GPIO_V2_LINE_FLAG_OUTPUT; + break; + case 'u': + abiv = atoi(optarg); break; default: usage(argv[0]); @@ -119,7 +171,10 @@ int main(int argc, char *argv[]) return -errno; } - lfd = request_line_v1(cfd, offset, flags_v1, val); + if (abiv == 1) + lfd = request_line_v1(cfd, offset, flags_v1, val); + else + lfd = request_line_v2(cfd, offset, flags_v2, val); close(cfd); @@ -128,10 +183,14 @@ int main(int argc, char *argv[]) return lfd; } - if (flags_v1 & GPIOHANDLE_REQUEST_OUTPUT) + if (flags_v2 & GPIO_V2_LINE_FLAG_OUTPUT) { wait_signal(); - else - ret = get_value_v1(lfd); + } else { + if (abiv == 1) + ret = get_value_v1(lfd); + else + ret = get_value_v2(lfd); + } close(lfd); diff --git a/tools/testing/selftests/gpio/gpio-mockup.sh b/tools/testing/selftests/gpio/gpio-mockup.sh index 0aa8e4294de1..0d6c5f7f95d2 100755 --- a/tools/testing/selftests/gpio/gpio-mockup.sh +++ b/tools/testing/selftests/gpio/gpio-mockup.sh @@ -14,6 +14,7 @@ module="gpio-mockup" verbose= full_test= random= +uapi_opt= active_opt= bias_opt= line_set_pid= @@ -30,6 +31,7 @@ usage() echo "-r: test random lines as well as fence posts" echo "-t: interface type:" echo " cdev (character device ABI) - default" + echo " cdev_v1 (deprecated character device ABI)" echo " sysfs (deprecated SYSFS ABI)" echo "-v: verbose progress reporting" exit $ksft_fail @@ -100,7 +102,8 @@ get_line() { release_line - $BASE/gpio-mockup-cdev $active_opt /dev/$chip $offset + local cdev_opts=${uapi_opt}${active_opt} + $BASE/gpio-mockup-cdev $cdev_opts /dev/$chip $offset echo $? } @@ -142,7 +145,7 @@ set_line() esac done - local cdev_opts=${active_opt} + local cdev_opts=${uapi_opt}${active_opt} if [ "$val" ]; then $BASE/gpio-mockup-cdev $cdev_opts -s$val /dev/$chip $offset & # failure to set is detected by reading mockup and toggling values @@ -340,6 +343,10 @@ sysfs) source $BASE/gpio-mockup-sysfs.sh echo "WARNING: gpio sysfs ABI is deprecated." ;; +cdev_v1) + echo "WARNING: gpio cdev ABI v1 is deprecated." + uapi_opt="-u1 " + ;; cdev) ;; *) -- cgit v1.2.3 From 94329e158e341bbeb777c7b5af085cce3ca3d344 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Tue, 19 Jan 2021 20:30:59 +0800 Subject: selftests: gpio: add CONFIG_GPIO_CDEV to config GPIO CDEV is now optional and required for the selftests so add it to the config. Signed-off-by: Kent Gibson Acked-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- tools/testing/selftests/gpio/config | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/testing/selftests/gpio/config b/tools/testing/selftests/gpio/config index abaa6902b7b6..ce100342c20b 100644 --- a/tools/testing/selftests/gpio/config +++ b/tools/testing/selftests/gpio/config @@ -1,2 +1,3 @@ CONFIG_GPIOLIB=y +CONFIG_GPIO_CDEV=y CONFIG_GPIO_MOCKUP=m -- cgit v1.2.3 From f61d3f0c6912c54f6a468318907a5c554e116516 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Tue, 19 Jan 2021 21:57:27 +0800 Subject: gpio: uapi: fix line info flags description The description of the flags field of the struct gpio_v2_line_info mentions "the GPIO lines" while the info only applies to an individual GPIO line. This was accidentally changed from "the GPIO line" during formatting improvements. Reword to "this GPIO line" to clarify and to be consistent with other struct gpio_v2_line_info fields. Fixes: 2cc522d3931b ("gpio: uapi: kernel-doc formatting improvements") Signed-off-by: Kent Gibson Signed-off-by: Bartosz Golaszewski --- include/uapi/linux/gpio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/gpio.h b/include/uapi/linux/gpio.h index e4eb0b8c5cf9..7a6f7948a7df 100644 --- a/include/uapi/linux/gpio.h +++ b/include/uapi/linux/gpio.h @@ -212,7 +212,7 @@ struct gpio_v2_line_request { * @offset: the local offset on this GPIO chip, fill this in when * requesting the line information from the kernel * @num_attrs: the number of attributes in @attrs - * @flags: flags for the GPIO lines, with values from &enum + * @flags: flags for this GPIO line, with values from &enum * gpio_v2_line_flag, such as %GPIO_V2_LINE_FLAG_ACTIVE_LOW, * %GPIO_V2_LINE_FLAG_OUTPUT etc, added together. * @attrs: the configuration attributes associated with the line -- cgit v1.2.3 From f0a2c77eb8e9ac5a4d783ef04c3e0f712cb707d6 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 20 Jan 2021 14:20:41 +0100 Subject: gpio: remove zte zx driver The zte zx platform is getting removed, so this driver is no longer needed. Cc: Jun Nie Cc: Shawn Guo Signed-off-by: Arnd Bergmann Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- .../devicetree/bindings/gpio/zx296702-gpio.txt | 24 -- drivers/gpio/Kconfig | 7 - drivers/gpio/Makefile | 1 - drivers/gpio/gpio-zx.c | 289 --------------------- 4 files changed, 321 deletions(-) delete mode 100644 Documentation/devicetree/bindings/gpio/zx296702-gpio.txt delete mode 100644 drivers/gpio/gpio-zx.c diff --git a/Documentation/devicetree/bindings/gpio/zx296702-gpio.txt b/Documentation/devicetree/bindings/gpio/zx296702-gpio.txt deleted file mode 100644 index 0dab156fcf41..000000000000 --- a/Documentation/devicetree/bindings/gpio/zx296702-gpio.txt +++ /dev/null @@ -1,24 +0,0 @@ -ZTE ZX296702 GPIO controller - -Required properties: -- compatible : "zte,zx296702-gpio" -- #gpio-cells : Should be two. The first cell is the pin number and the - second cell is used to specify optional parameters: - - bit 0 specifies polarity (0 for normal, 1 for inverted) -- gpio-controller : Marks the device node as a GPIO controller. -- interrupts : Interrupt mapping for GPIO IRQ. -- gpio-ranges : Interaction with the PINCTRL subsystem. - -gpio1: gpio@b008040 { - compatible = "zte,zx296702-gpio"; - reg = <0xb008040 0x40>; - gpio-controller; - #gpio-cells = <2>; - gpio-ranges = < &pmx0 0 54 2 &pmx0 2 59 14>; - interrupts = ; - interrupt-parent = <&intc>; - interrupt-controller; - #interrupt-cells = <2>; - clock-names = "gpio_pclk"; - clocks = <&lsp0clk ZX296702_GPIO_CLK>; -}; diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 520fdf2bda30..482d1e84ce14 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -741,13 +741,6 @@ config GPIO_ZYNQ help Say yes here to support Xilinx Zynq GPIO controller. -config GPIO_ZX - bool "ZTE ZX GPIO support" - depends on ARCH_ZX || COMPILE_TEST - select GPIOLIB_IRQCHIP - help - Say yes here to support the GPIO device on ZTE ZX SoCs. - config GPIO_LOONGSON1 tristate "Loongson1 GPIO support" depends on MACH_LOONGSON32 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 2c2a705766f3..43250931ee73 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -181,5 +181,4 @@ obj-$(CONFIG_GPIO_XLP) += gpio-xlp.o obj-$(CONFIG_GPIO_XRA1403) += gpio-xra1403.o obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o -obj-$(CONFIG_GPIO_ZX) += gpio-zx.o obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o diff --git a/drivers/gpio/gpio-zx.c b/drivers/gpio/gpio-zx.c deleted file mode 100644 index 64bfb722756a..000000000000 --- a/drivers/gpio/gpio-zx.c +++ /dev/null @@ -1,289 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * ZTE ZX296702 GPIO driver - * - * Author: Jun Nie - * - * Copyright (C) 2015 Linaro Ltd. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ZX_GPIO_DIR 0x00 -#define ZX_GPIO_IVE 0x04 -#define ZX_GPIO_IV 0x08 -#define ZX_GPIO_IEP 0x0C -#define ZX_GPIO_IEN 0x10 -#define ZX_GPIO_DI 0x14 -#define ZX_GPIO_DO1 0x18 -#define ZX_GPIO_DO0 0x1C -#define ZX_GPIO_DO 0x20 - -#define ZX_GPIO_IM 0x28 -#define ZX_GPIO_IE 0x2C - -#define ZX_GPIO_MIS 0x30 -#define ZX_GPIO_IC 0x34 - -#define ZX_GPIO_NR 16 - -struct zx_gpio { - raw_spinlock_t lock; - - void __iomem *base; - struct gpio_chip gc; -}; - -static int zx_direction_input(struct gpio_chip *gc, unsigned offset) -{ - struct zx_gpio *chip = gpiochip_get_data(gc); - unsigned long flags; - u16 gpiodir; - - if (offset >= gc->ngpio) - return -EINVAL; - - raw_spin_lock_irqsave(&chip->lock, flags); - gpiodir = readw_relaxed(chip->base + ZX_GPIO_DIR); - gpiodir &= ~BIT(offset); - writew_relaxed(gpiodir, chip->base + ZX_GPIO_DIR); - raw_spin_unlock_irqrestore(&chip->lock, flags); - - return 0; -} - -static int zx_direction_output(struct gpio_chip *gc, unsigned offset, - int value) -{ - struct zx_gpio *chip = gpiochip_get_data(gc); - unsigned long flags; - u16 gpiodir; - - if (offset >= gc->ngpio) - return -EINVAL; - - raw_spin_lock_irqsave(&chip->lock, flags); - gpiodir = readw_relaxed(chip->base + ZX_GPIO_DIR); - gpiodir |= BIT(offset); - writew_relaxed(gpiodir, chip->base + ZX_GPIO_DIR); - - if (value) - writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO1); - else - writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO0); - raw_spin_unlock_irqrestore(&chip->lock, flags); - - return 0; -} - -static int zx_get_value(struct gpio_chip *gc, unsigned offset) -{ - struct zx_gpio *chip = gpiochip_get_data(gc); - - return !!(readw_relaxed(chip->base + ZX_GPIO_DI) & BIT(offset)); -} - -static void zx_set_value(struct gpio_chip *gc, unsigned offset, int value) -{ - struct zx_gpio *chip = gpiochip_get_data(gc); - - if (value) - writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO1); - else - writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO0); -} - -static int zx_irq_type(struct irq_data *d, unsigned trigger) -{ - struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct zx_gpio *chip = gpiochip_get_data(gc); - int offset = irqd_to_hwirq(d); - unsigned long flags; - u16 gpiois, gpioi_epos, gpioi_eneg, gpioiev; - u16 bit = BIT(offset); - - if (offset < 0 || offset >= ZX_GPIO_NR) - return -EINVAL; - - raw_spin_lock_irqsave(&chip->lock, flags); - - gpioiev = readw_relaxed(chip->base + ZX_GPIO_IV); - gpiois = readw_relaxed(chip->base + ZX_GPIO_IVE); - gpioi_epos = readw_relaxed(chip->base + ZX_GPIO_IEP); - gpioi_eneg = readw_relaxed(chip->base + ZX_GPIO_IEN); - - if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { - gpiois |= bit; - if (trigger & IRQ_TYPE_LEVEL_HIGH) - gpioiev |= bit; - else - gpioiev &= ~bit; - } else - gpiois &= ~bit; - - if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { - gpioi_epos |= bit; - gpioi_eneg |= bit; - } else { - if (trigger & IRQ_TYPE_EDGE_RISING) { - gpioi_epos |= bit; - gpioi_eneg &= ~bit; - } else if (trigger & IRQ_TYPE_EDGE_FALLING) { - gpioi_eneg |= bit; - gpioi_epos &= ~bit; - } - } - - writew_relaxed(gpiois, chip->base + ZX_GPIO_IVE); - writew_relaxed(gpioi_epos, chip->base + ZX_GPIO_IEP); - writew_relaxed(gpioi_eneg, chip->base + ZX_GPIO_IEN); - writew_relaxed(gpioiev, chip->base + ZX_GPIO_IV); - raw_spin_unlock_irqrestore(&chip->lock, flags); - - return 0; -} - -static void zx_irq_handler(struct irq_desc *desc) -{ - unsigned long pending; - int offset; - struct gpio_chip *gc = irq_desc_get_handler_data(desc); - struct zx_gpio *chip = gpiochip_get_data(gc); - struct irq_chip *irqchip = irq_desc_get_chip(desc); - - chained_irq_enter(irqchip, desc); - - pending = readw_relaxed(chip->base + ZX_GPIO_MIS); - writew_relaxed(pending, chip->base + ZX_GPIO_IC); - if (pending) { - for_each_set_bit(offset, &pending, ZX_GPIO_NR) - generic_handle_irq(irq_find_mapping(gc->irq.domain, - offset)); - } - - chained_irq_exit(irqchip, desc); -} - -static void zx_irq_mask(struct irq_data *d) -{ - struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct zx_gpio *chip = gpiochip_get_data(gc); - u16 mask = BIT(irqd_to_hwirq(d) % ZX_GPIO_NR); - u16 gpioie; - - raw_spin_lock(&chip->lock); - gpioie = readw_relaxed(chip->base + ZX_GPIO_IM) | mask; - writew_relaxed(gpioie, chip->base + ZX_GPIO_IM); - gpioie = readw_relaxed(chip->base + ZX_GPIO_IE) & ~mask; - writew_relaxed(gpioie, chip->base + ZX_GPIO_IE); - raw_spin_unlock(&chip->lock); -} - -static void zx_irq_unmask(struct irq_data *d) -{ - struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct zx_gpio *chip = gpiochip_get_data(gc); - u16 mask = BIT(irqd_to_hwirq(d) % ZX_GPIO_NR); - u16 gpioie; - - raw_spin_lock(&chip->lock); - gpioie = readw_relaxed(chip->base + ZX_GPIO_IM) & ~mask; - writew_relaxed(gpioie, chip->base + ZX_GPIO_IM); - gpioie = readw_relaxed(chip->base + ZX_GPIO_IE) | mask; - writew_relaxed(gpioie, chip->base + ZX_GPIO_IE); - raw_spin_unlock(&chip->lock); -} - -static struct irq_chip zx_irqchip = { - .name = "zx-gpio", - .irq_mask = zx_irq_mask, - .irq_unmask = zx_irq_unmask, - .irq_set_type = zx_irq_type, -}; - -static int zx_gpio_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct zx_gpio *chip; - struct gpio_irq_chip *girq; - int irq, id, ret; - - chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - chip->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(chip->base)) - return PTR_ERR(chip->base); - - id = of_alias_get_id(dev->of_node, "gpio"); - - raw_spin_lock_init(&chip->lock); - chip->gc.request = gpiochip_generic_request; - chip->gc.free = gpiochip_generic_free; - chip->gc.direction_input = zx_direction_input; - chip->gc.direction_output = zx_direction_output; - chip->gc.get = zx_get_value; - chip->gc.set = zx_set_value; - chip->gc.base = ZX_GPIO_NR * id; - chip->gc.ngpio = ZX_GPIO_NR; - chip->gc.label = dev_name(dev); - chip->gc.parent = dev; - chip->gc.owner = THIS_MODULE; - - /* - * irq_chip support - */ - writew_relaxed(0xffff, chip->base + ZX_GPIO_IM); - writew_relaxed(0, chip->base + ZX_GPIO_IE); - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - girq = &chip->gc.irq; - girq->chip = &zx_irqchip; - girq->parent_handler = zx_irq_handler; - girq->num_parents = 1; - girq->parents = devm_kcalloc(&pdev->dev, 1, - sizeof(*girq->parents), - GFP_KERNEL); - if (!girq->parents) - return -ENOMEM; - girq->parents[0] = irq; - girq->default_type = IRQ_TYPE_NONE; - girq->handler = handle_simple_irq; - - ret = gpiochip_add_data(&chip->gc, chip); - if (ret) - return ret; - - platform_set_drvdata(pdev, chip); - dev_info(dev, "ZX GPIO chip registered\n"); - - return 0; -} - -static const struct of_device_id zx_gpio_match[] = { - { - .compatible = "zte,zx296702-gpio", - }, - { }, -}; - -static struct platform_driver zx_gpio_driver = { - .probe = zx_gpio_probe, - .driver = { - .name = "zx_gpio", - .of_match_table = of_match_ptr(zx_gpio_match), - }, -}; -builtin_platform_driver(zx_gpio_driver) -- cgit v1.2.3 From de49e83c21209a2f128fc9248eebb6cb58d85996 Mon Sep 17 00:00:00 2001 From: Zheng Yongjun Date: Fri, 8 Jan 2021 17:24:05 +0800 Subject: gpio: max77620: convert comma to semicolon Replace a comma between expression statements by a semicolon. Signed-off-by: Zheng Yongjun Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-max77620.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-max77620.c b/drivers/gpio/gpio-max77620.c index 7c0a9ef0b500..82b3a913005d 100644 --- a/drivers/gpio/gpio-max77620.c +++ b/drivers/gpio/gpio-max77620.c @@ -325,7 +325,7 @@ static int max77620_gpio_probe(struct platform_device *pdev) girq->parents = NULL; girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_edge_irq; - girq->init_hw = max77620_gpio_irq_init_hw, + girq->init_hw = max77620_gpio_irq_init_hw; girq->threaded = true; platform_set_drvdata(pdev, mgpio); -- cgit v1.2.3 From 7de2e5fc51eea412abb42193181fc0cc3ecc2851 Mon Sep 17 00:00:00 2001 From: Zheng Yongjun Date: Fri, 8 Jan 2021 17:23:55 +0800 Subject: gpio: tegra186: convert comma to semicolon Replace a comma between expression statements by a semicolon. Signed-off-by: Zheng Yongjun Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-tegra186.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c index 286e0b1f46e4..1bd9e44df718 100644 --- a/drivers/gpio/gpio-tegra186.c +++ b/drivers/gpio/gpio-tegra186.c @@ -657,7 +657,7 @@ static int tegra186_gpio_probe(struct platform_device *pdev) gpio->gpio.get_direction = tegra186_gpio_get_direction; gpio->gpio.direction_input = tegra186_gpio_direction_input; gpio->gpio.direction_output = tegra186_gpio_direction_output; - gpio->gpio.get = tegra186_gpio_get, + gpio->gpio.get = tegra186_gpio_get; gpio->gpio.set = tegra186_gpio_set; gpio->gpio.set_config = tegra186_gpio_set_config; gpio->gpio.add_pin_ranges = tegra186_gpio_add_pin_ranges; -- cgit v1.2.3 From 10c942a157c5788f6659152f55741afc10e53048 Mon Sep 17 00:00:00 2001 From: Zheng Yongjun Date: Fri, 8 Jan 2021 17:23:45 +0800 Subject: gpio: vx855: convert comma to semicolon Replace a comma between expression statements by a semicolon. Signed-off-by: Zheng Yongjun Signed-off-by: Bartosz Golaszewski --- 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 3bf397b8dfbc..69713fd5485b 100644 --- a/drivers/gpio/gpio-vx855.c +++ b/drivers/gpio/gpio-vx855.c @@ -216,7 +216,7 @@ static void vx855gpio_gpio_setup(struct vx855_gpio *vg) c->direction_output = vx855gpio_direction_output; c->get = vx855gpio_get; c->set = vx855gpio_set; - c->set_config = vx855gpio_set_config, + c->set_config = vx855gpio_set_config; c->dbg_show = NULL; c->base = 0; c->ngpio = NR_VX855_GP; -- cgit v1.2.3 From 481a4209de3f49ba8affb21fa0e1dca6e4f6c8c6 Mon Sep 17 00:00:00 2001 From: Zheng Yongjun Date: Fri, 8 Jan 2021 17:24:13 +0800 Subject: gpio: wcove: convert comma to semicolon Replace a comma between expression statements by a semicolon. Signed-off-by: Zheng Yongjun Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-wcove.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c index b5fbba5a783a..97c5f1d01b62 100644 --- a/drivers/gpio/gpio-wcove.c +++ b/drivers/gpio/gpio-wcove.c @@ -434,7 +434,7 @@ static int wcove_gpio_probe(struct platform_device *pdev) wg->chip.get_direction = wcove_gpio_get_direction; wg->chip.get = wcove_gpio_get; wg->chip.set = wcove_gpio_set; - wg->chip.set_config = wcove_gpio_set_config, + wg->chip.set_config = wcove_gpio_set_config; wg->chip.base = -1; wg->chip.ngpio = WCOVE_VGPIO_NUM; wg->chip.can_sleep = true; -- cgit v1.2.3 From 4bf2426103d2dd89c1b48bd5eba8cd16903ec40b Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 21 Jan 2021 13:13:55 +0100 Subject: gpio: mockup: tweak the Kconfig help text gpio-mockup doesn't require SYSFS to be selected so drop that bit from the Kconfig text. Signed-off-by: Bartosz Golaszewski Acked-by: Linus Walleij --- drivers/gpio/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 482d1e84ce14..f50532e1cf18 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1640,8 +1640,7 @@ config GPIO_MOCKUP select IRQ_SIM help This enables GPIO Testing driver, which provides a way to test GPIO - subsystem through sysfs(or char device) and debugfs. GPIO_SYSFS - must be selected for this test. + subsystem through sysfs (or char device) and debugfs. User could use it through the script in tools/testing/selftests/gpio/gpio-mockup.sh. Reference the usage in it. -- cgit v1.2.3 From aa37e27f610fe3e7539c066d9c1f5304390086d6 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Wed, 20 Jan 2021 18:16:25 +0200 Subject: gpio: mvebu: improve pwm period calculation accuracy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change 'off' register value calculation from $off = (period - duty_cycle) * clkrate / NSEC_PER_SEC to $off = (period * clkrate / NSEC_PER_SEC) - $on That is, divide the full period value to reduce rounding error. Reported-by: Uwe Kleine-König Reviewed-by: Uwe Kleine-König Reviewed-by: Linus Walleij Signed-off-by: Baruch Siach Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-mvebu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index a912a8fed197..c424d88e9e2b 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -715,9 +715,9 @@ static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, else on = 1; - val = (unsigned long long) mvpwm->clk_rate * - (state->period - state->duty_cycle); + val = (unsigned long long) mvpwm->clk_rate * state->period; do_div(val, NSEC_PER_SEC); + val -= on; if (val > UINT_MAX) return -EINVAL; if (val) -- cgit v1.2.3 From de1eaf6016b311dcc53d2297952edcdc87bcc941 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Wed, 20 Jan 2021 18:16:26 +0200 Subject: gpio: mvebu: make pwm .get_state closer to idempotent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Round up the divisions in .get_state() to make applying the read out configuration idempotent in most cases as .apply rounds down. Reported-by: Uwe Kleine-König Reviewed-by: Uwe Kleine-König Reviewed-by: Linus Walleij Signed-off-by: Baruch Siach Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-mvebu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index c424d88e9e2b..8673ba77af5a 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -668,7 +668,7 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip, regmap_read(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm), &u); val = (unsigned long long) u * NSEC_PER_SEC; - do_div(val, mvpwm->clk_rate); + val = DIV_ROUND_UP_ULL(val, mvpwm->clk_rate); if (val > UINT_MAX) state->duty_cycle = UINT_MAX; else if (val) @@ -680,7 +680,7 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip, regmap_read(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), &u); val += (unsigned long long) u; /* period = on + off duration */ val *= NSEC_PER_SEC; - do_div(val, mvpwm->clk_rate); + val = DIV_ROUND_UP_ULL(val, mvpwm->clk_rate); if (val > UINT_MAX) state->period = UINT_MAX; else if (val) -- cgit v1.2.3 From 2bee255a5ecf3213d118f22f6d8f65e4ec9101f2 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Wed, 20 Jan 2021 18:16:27 +0200 Subject: gpio: mvebu: don't limit pwm period/duty_cycle to UINT_MAX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PWM on/off registers are limited to UINT_MAX. However the state period and duty_cycle fields are ns values of type u64. There is no reason to limit them to UINT_MAX. Reported-by: Uwe Kleine-König Reviewed-by: Uwe Kleine-König Reviewed-by: Linus Walleij Signed-off-by: Baruch Siach Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-mvebu.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 8673ba77af5a..6b017854ce61 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -669,9 +669,7 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip, regmap_read(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm), &u); val = (unsigned long long) u * NSEC_PER_SEC; val = DIV_ROUND_UP_ULL(val, mvpwm->clk_rate); - if (val > UINT_MAX) - state->duty_cycle = UINT_MAX; - else if (val) + if (val) state->duty_cycle = val; else state->duty_cycle = 1; @@ -681,9 +679,7 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip, val += (unsigned long long) u; /* period = on + off duration */ val *= NSEC_PER_SEC; val = DIV_ROUND_UP_ULL(val, mvpwm->clk_rate); - if (val > UINT_MAX) - state->period = UINT_MAX; - else if (val) + if (val) state->period = val; else state->period = 1; -- cgit v1.2.3 From 0b68d02b6a0dd2c7174a86a882e23d04fc7e7ca8 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Wed, 20 Jan 2021 18:16:28 +0200 Subject: gpio: mvebu: improve handling of pwm zero on/off values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hardware appears to treat zero value as 2^32. Take advantage of this fact to support on/off values of up to UINT_MAX+1 == 2^32. Adjust both .apply and .get_state to handle zero as a special case. Rounded up division result in .get_state can't be zero, since the dividend is now larger than 0. Remove check for this case. Reported-by: Uwe Kleine-König Analyzed-by: Russell King Signed-off-by: Baruch Siach Reviewed-by: Uwe Kleine-König Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-mvebu.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 6b017854ce61..75e3c235bd3a 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -667,22 +667,21 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip, spin_lock_irqsave(&mvpwm->lock, flags); regmap_read(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm), &u); - val = (unsigned long long) u * NSEC_PER_SEC; - val = DIV_ROUND_UP_ULL(val, mvpwm->clk_rate); - if (val) - state->duty_cycle = val; + /* Hardware treats zero as 2^32. See mvebu_pwm_apply(). */ + if (u > 0) + val = u; else - state->duty_cycle = 1; + val = UINT_MAX + 1ULL; + state->duty_cycle = DIV_ROUND_UP_ULL(val * NSEC_PER_SEC, + mvpwm->clk_rate); - val = (unsigned long long) u; /* on duration */ regmap_read(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), &u); - val += (unsigned long long) u; /* period = on + off duration */ - val *= NSEC_PER_SEC; - val = DIV_ROUND_UP_ULL(val, mvpwm->clk_rate); - if (val) - state->period = val; + /* period = on + off duration */ + if (u > 0) + val += u; else - state->period = 1; + val += UINT_MAX + 1ULL; + state->period = DIV_ROUND_UP_ULL(val * NSEC_PER_SEC, mvpwm->clk_rate); regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, &u); if (u) @@ -704,9 +703,15 @@ static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, val = (unsigned long long) mvpwm->clk_rate * state->duty_cycle; do_div(val, NSEC_PER_SEC); - if (val > UINT_MAX) + if (val > UINT_MAX + 1ULL) return -EINVAL; - if (val) + /* + * Zero on/off values don't work as expected. Experimentation shows + * that zero value is treated as 2^32. This behavior is not documented. + */ + if (val == UINT_MAX + 1ULL) + on = 0; + else if (val) on = val; else on = 1; @@ -714,9 +719,11 @@ static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, val = (unsigned long long) mvpwm->clk_rate * state->period; do_div(val, NSEC_PER_SEC); val -= on; - if (val > UINT_MAX) + if (val > UINT_MAX + 1ULL) return -EINVAL; - if (val) + if (val == UINT_MAX + 1ULL) + off = 0; + else if (val) off = val; else off = 1; -- cgit v1.2.3 From 718ff946668ed5f22477bf88d8e2a8630370586b Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Fri, 22 Jan 2021 22:59:59 +0300 Subject: gpio: tegra: Improve formatting of the code Don't cross 80 chars of line length in order to keep formatting of the code consistent. Signed-off-by: Dmitry Osipenko Acked-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-tegra.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 6c79e9d2f932..93f471d8c69c 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -432,8 +432,10 @@ static void tegra_gpio_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); } -static int tegra_gpio_child_to_parent_hwirq(struct gpio_chip *chip, unsigned int hwirq, - unsigned int type, unsigned int *parent_hwirq, +static int tegra_gpio_child_to_parent_hwirq(struct gpio_chip *chip, + unsigned int hwirq, + unsigned int type, + unsigned int *parent_hwirq, unsigned int *parent_type) { *parent_hwirq = chip->irq.child_offset_to_irq(chip, hwirq); @@ -442,7 +444,8 @@ static int tegra_gpio_child_to_parent_hwirq(struct gpio_chip *chip, unsigned int return 0; } -static void *tegra_gpio_populate_parent_fwspec(struct gpio_chip *chip, unsigned int parent_hwirq, +static void *tegra_gpio_populate_parent_fwspec(struct gpio_chip *chip, + unsigned int parent_hwirq, unsigned int parent_type) { struct irq_fwspec *fwspec; @@ -570,7 +573,8 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable) } #endif -static int tegra_gpio_irq_set_affinity(struct irq_data *data, const struct cpumask *dest, +static int tegra_gpio_irq_set_affinity(struct irq_data *data, + const struct cpumask *dest, bool force) { if (data->parent_data) @@ -715,7 +719,8 @@ static int tegra_gpio_probe(struct platform_device *pdev) if (!tgi->bank_info) return -ENOMEM; - tgi->irqs = devm_kcalloc(&pdev->dev, tgi->bank_count, sizeof(*tgi->irqs), GFP_KERNEL); + tgi->irqs = devm_kcalloc(&pdev->dev, tgi->bank_count, + sizeof(*tgi->irqs), GFP_KERNEL); if (!tgi->irqs) return -ENOMEM; -- cgit v1.2.3 From b2a6115f31a53fac54c792e8215da3aed47f8008 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Fri, 22 Jan 2021 21:55:41 +0300 Subject: gpio: tegra: Use debugfs_create_devm_seqfile() Use resource-managed variant of debugfs_create_file(0444) to prepare code for the modularization of the driver. Signed-off-by: Dmitry Osipenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-tegra.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 93f471d8c69c..8eb2fa369470 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -609,7 +609,7 @@ static void tegra_gpio_irq_release_resources(struct irq_data *d) static int tegra_dbg_gpio_show(struct seq_file *s, void *unused) { - struct tegra_gpio_info *tgi = s->private; + struct tegra_gpio_info *tgi = dev_get_drvdata(s->private); unsigned int i, j; for (i = 0; i < tgi->bank_count; i++) { @@ -631,12 +631,10 @@ static int tegra_dbg_gpio_show(struct seq_file *s, void *unused) return 0; } -DEFINE_SHOW_ATTRIBUTE(tegra_dbg_gpio); - static void tegra_gpio_debuginit(struct tegra_gpio_info *tgi) { - debugfs_create_file("tegra_gpio", 0444, NULL, tgi, - &tegra_dbg_gpio_fops); + debugfs_create_devm_seqfile(tgi->dev, "tegra_gpio", NULL, + tegra_dbg_gpio_show); } #else -- cgit v1.2.3 From 66f7aaa448a71781a623817cd26551e8179927f8 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Fri, 22 Jan 2021 21:55:42 +0300 Subject: gpio: tegra: Clean up whitespaces in tegra_gpio_driver Clean up inconsistent whitespaces and tabs in the definition of tegra_gpio_driver to make code look better a tad. Signed-off-by: Dmitry Osipenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-tegra.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 8eb2fa369470..e2b739a95ee0 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -804,12 +804,12 @@ static const struct of_device_id tegra_gpio_of_match[] = { }; static struct platform_driver tegra_gpio_driver = { - .driver = { - .name = "tegra-gpio", - .pm = &tegra_gpio_pm_ops, + .driver = { + .name = "tegra-gpio", + .pm = &tegra_gpio_pm_ops, .of_match_table = tegra_gpio_of_match, }, - .probe = tegra_gpio_probe, + .probe = tegra_gpio_probe, }; static int __init tegra_gpio_init(void) -- cgit v1.2.3 From 4a6eac2b4b129800a2ab37d7127e2244bce37653 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Fri, 22 Jan 2021 21:55:43 +0300 Subject: gpio: tegra: Support building driver as a loadable module Support building driver as a loadable kernel module. This allows to reduce size of a kernel zImage, which is important for some devices since size of kernel partition may be limited and since some bootloader variants have known problems in regards to the initrd placement if kernel image is too big. $ lsmod Module Size Used by gpio_tegra 16384 27 Signed-off-by: Dmitry Osipenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 2 +- drivers/gpio/gpio-tegra.c | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index f50532e1cf18..c96086f15bc0 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -595,7 +595,7 @@ config GPIO_TB10X select OF_GPIO config GPIO_TEGRA - bool "NVIDIA Tegra GPIO support" + tristate "NVIDIA Tegra GPIO support" default ARCH_TEGRA depends on ARCH_TEGRA || COMPILE_TEST depends on OF_GPIO diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index e2b739a95ee0..a3c8cea69628 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -802,6 +802,7 @@ static const struct of_device_id tegra_gpio_of_match[] = { { .compatible = "nvidia,tegra20-gpio", .data = &tegra20_gpio_config }, { }, }; +MODULE_DEVICE_TABLE(of, tegra_gpio_of_match); static struct platform_driver tegra_gpio_driver = { .driver = { @@ -811,9 +812,11 @@ static struct platform_driver tegra_gpio_driver = { }, .probe = tegra_gpio_probe, }; - -static int __init tegra_gpio_init(void) -{ - return platform_driver_register(&tegra_gpio_driver); -} -subsys_initcall(tegra_gpio_init); +module_platform_driver(tegra_gpio_driver); + +MODULE_DESCRIPTION("NVIDIA Tegra GPIO controller driver"); +MODULE_AUTHOR("Laxman Dewangan "); +MODULE_AUTHOR("Stephen Warren "); +MODULE_AUTHOR("Thierry Reding "); +MODULE_AUTHOR("Erik Gilling "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 94de03ccc9f5d13e36cf1db8f9dfbf676fdfec07 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 20 Jan 2021 03:45:48 +0300 Subject: gpio: tegra: Fix irq_set_affinity The irq_set_affinity callback should not be set if parent IRQ domain doesn't present because gpio-tegra driver callback fails in this case, causing a noisy error messages on system suspend: Disabling non-boot CPUs ... IRQ 26: no longer affine to CPU1 IRQ128: set affinity failed(-22). IRQ130: set affinity failed(-22). IRQ131: set affinity failed(-22). IRQ 27: no longer affine to CPU2 IRQ128: set affinity failed(-22). IRQ130: set affinity failed(-22). IRQ131: set affinity failed(-22). IRQ 28: no longer affine to CPU3 IRQ128: set affinity failed(-22). IRQ130: set affinity failed(-22). IRQ131: set affinity failed(-22). Entering suspend state LP1 Hence just don't specify the irq_set_affinity callback if parent PMC IRQ domain is missing. Tegra isn't capable of setting affinity per GPIO, affinity could be set only per GPIO bank, thus there is nothing to do for gpio-tegra in regards to CPU affinity without the parent IRQ domain. Tested-by: Peter Geis # Ouya T30 Tested-by: Matt Merhar # Ouya T30 Tested-by: Dmitry Osipenko # A500 T20 and Nexus7 T30 Fixes: efcdca286eef ("gpio: tegra: Convert to gpio_irq_chip") Reported-by: Matt Merhar Signed-off-by: Dmitry Osipenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-tegra.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index a3c8cea69628..0025f613d9b3 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -703,7 +703,6 @@ static int tegra_gpio_probe(struct platform_device *pdev) #ifdef CONFIG_PM_SLEEP tgi->ic.irq_set_wake = tegra_gpio_irq_set_wake; #endif - tgi->ic.irq_set_affinity = tegra_gpio_irq_set_affinity; tgi->ic.irq_request_resources = tegra_gpio_irq_request_resources; tgi->ic.irq_release_resources = tegra_gpio_irq_release_resources; @@ -757,6 +756,8 @@ static int tegra_gpio_probe(struct platform_device *pdev) if (!irq->parent_domain) return -EPROBE_DEFER; + + tgi->ic.irq_set_affinity = tegra_gpio_irq_set_affinity; } tgi->regs = devm_platform_ioremap_resource(pdev, 0); -- cgit v1.2.3 From 85b7d8abfec70ae820ddfea493f93b0af7e50b51 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Mon, 11 Jan 2021 13:46:27 +0200 Subject: gpio: mvebu: add pwm support for Armada 8K/7K Use the marvell,pwm-offset DT property to store the location of PWM signal duration registers. Since we have more than two GPIO chips per system, we can't use the alias id to differentiate between them. Use the offset value for that. Signed-off-by: Baruch Siach Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-mvebu.c | 101 +++++++++++++++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 33 deletions(-) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 75e3c235bd3a..8f429d9f3661 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -70,7 +70,12 @@ */ #define PWM_BLINK_ON_DURATION_OFF 0x0 #define PWM_BLINK_OFF_DURATION_OFF 0x4 +#define PWM_BLINK_COUNTER_B_OFF 0x8 +/* Armada 8k variant gpios register offsets */ +#define AP80X_GPIO0_OFF_A8K 0x1040 +#define CP11X_GPIO0_OFF_A8K 0x100 +#define CP11X_GPIO1_OFF_A8K 0x140 /* The MV78200 has per-CPU registers for edge mask and level mask */ #define GPIO_EDGE_MASK_MV78200_OFF(cpu) ((cpu) ? 0x30 : 0x18) @@ -93,6 +98,7 @@ struct mvebu_pwm { struct regmap *regs; + u32 offset; unsigned long clk_rate; struct gpio_desc *gpiod; struct pwm_chip chip; @@ -283,12 +289,12 @@ mvebu_gpio_write_level_mask(struct mvebu_gpio_chip *mvchip, u32 val) */ static unsigned int mvebu_pwmreg_blink_on_duration(struct mvebu_pwm *mvpwm) { - return PWM_BLINK_ON_DURATION_OFF; + return mvpwm->offset + PWM_BLINK_ON_DURATION_OFF; } static unsigned int mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm) { - return PWM_BLINK_OFF_DURATION_OFF; + return mvpwm->offset + PWM_BLINK_OFF_DURATION_OFF; } /* @@ -781,51 +787,80 @@ static int mvebu_pwm_probe(struct platform_device *pdev, struct device *dev = &pdev->dev; struct mvebu_pwm *mvpwm; void __iomem *base; + u32 offset; u32 set; - if (!of_device_is_compatible(mvchip->chip.of_node, - "marvell,armada-370-gpio")) - return 0; - - /* - * There are only two sets of PWM configuration registers for - * all the GPIO lines on those SoCs which this driver reserves - * for the first two GPIO chips. So if the resource is missing - * we can't treat it as an error. - */ - if (!platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm")) + if (of_device_is_compatible(mvchip->chip.of_node, + "marvell,armada-370-gpio")) { + /* + * There are only two sets of PWM configuration registers for + * all the GPIO lines on those SoCs which this driver reserves + * for the first two GPIO chips. So if the resource is missing + * we can't treat it as an error. + */ + if (!platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm")) + return 0; + offset = 0; + } else if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) { + int ret = of_property_read_u32(dev->of_node, + "marvell,pwm-offset", &offset); + if (ret < 0) + return 0; + } else { return 0; + } if (IS_ERR(mvchip->clk)) return PTR_ERR(mvchip->clk); - /* - * Use set A for lines of GPIO chip with id 0, B for GPIO chip - * with id 1. Don't allow further GPIO chips to be used for PWM. - */ - if (id == 0) - set = 0; - else if (id == 1) - set = U32_MAX; - else - return -EINVAL; - regmap_write(mvchip->regs, - GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, set); - mvpwm = devm_kzalloc(dev, sizeof(struct mvebu_pwm), GFP_KERNEL); if (!mvpwm) return -ENOMEM; mvchip->mvpwm = mvpwm; mvpwm->mvchip = mvchip; + mvpwm->offset = offset; + + if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) { + mvpwm->regs = mvchip->regs; + + switch (mvchip->offset) { + case AP80X_GPIO0_OFF_A8K: + case CP11X_GPIO0_OFF_A8K: + /* Blink counter A */ + set = 0; + break; + case CP11X_GPIO1_OFF_A8K: + /* Blink counter B */ + set = U32_MAX; + mvpwm->offset += PWM_BLINK_COUNTER_B_OFF; + break; + default: + return -EINVAL; + } + } else { + base = devm_platform_ioremap_resource_byname(pdev, "pwm"); + if (IS_ERR(base)) + return PTR_ERR(base); - base = devm_platform_ioremap_resource_byname(pdev, "pwm"); - if (IS_ERR(base)) - return PTR_ERR(base); + mvpwm->regs = devm_regmap_init_mmio(&pdev->dev, base, + &mvebu_gpio_regmap_config); + if (IS_ERR(mvpwm->regs)) + return PTR_ERR(mvpwm->regs); - mvpwm->regs = devm_regmap_init_mmio(&pdev->dev, base, - &mvebu_gpio_regmap_config); - if (IS_ERR(mvpwm->regs)) - return PTR_ERR(mvpwm->regs); + /* + * Use set A for lines of GPIO chip with id 0, B for GPIO chip + * with id 1. Don't allow further GPIO chips to be used for PWM. + */ + if (id == 0) + set = 0; + else if (id == 1) + set = U32_MAX; + else + return -EINVAL; + } + + regmap_write(mvchip->regs, + GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, set); mvpwm->clk_rate = clk_get_rate(mvchip->clk); if (!mvpwm->clk_rate) { -- cgit v1.2.3 From ea6fe47f3ed4f89f9216e98f1344c06d6516cb28 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Mon, 11 Jan 2021 13:46:29 +0200 Subject: dt-bindings: ap806: document gpio marvell,pwm-offset property Update the example as well. Add the '#pwm-cells' and 'clocks' properties for a complete working example. Reviewed-by: Rob Herring Signed-off-by: Baruch Siach Signed-off-by: Bartosz Golaszewski --- .../devicetree/bindings/arm/marvell/ap80x-system-controller.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/marvell/ap80x-system-controller.txt b/Documentation/devicetree/bindings/arm/marvell/ap80x-system-controller.txt index e31511255d8e..052a967c1f28 100644 --- a/Documentation/devicetree/bindings/arm/marvell/ap80x-system-controller.txt +++ b/Documentation/devicetree/bindings/arm/marvell/ap80x-system-controller.txt @@ -80,6 +80,11 @@ Required properties: - offset: offset address inside the syscon block +Optional properties: + +- marvell,pwm-offset: offset address of PWM duration control registers inside + the syscon block + Example: ap_syscon: system-controller@6f4000 { compatible = "syscon", "simple-mfd"; @@ -101,6 +106,9 @@ ap_syscon: system-controller@6f4000 { gpio-controller; #gpio-cells = <2>; gpio-ranges = <&ap_pinctrl 0 0 19>; + marvell,pwm-offset = <0x10c0>; + #pwm-cells = <2>; + clocks = <&ap_clk 3>; }; }; -- cgit v1.2.3 From 1d10243dc295d2f49b73b1320a177491767f180d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 11 Nov 2020 13:47:20 +0200 Subject: gpio: merrifield: Make bias configuration available for GPIOs If we get bias set request, for example, from GpioIo() resource, we silently ignore it. Make bias configuration available for GPIOs. Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-merrifield.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c index 706687fab634..22f3ce218f5d 100644 --- a/drivers/gpio/gpio-merrifield.c +++ b/drivers/gpio/gpio-merrifield.c @@ -194,6 +194,11 @@ static int mrfld_gpio_set_config(struct gpio_chip *chip, unsigned int offset, { u32 debounce; + if ((pinconf_to_config_param(config) == PIN_CONFIG_BIAS_DISABLE) || + (pinconf_to_config_param(config) == PIN_CONFIG_BIAS_PULL_UP) || + (pinconf_to_config_param(config) == PIN_CONFIG_BIAS_PULL_DOWN)) + return gpiochip_generic_config(chip, offset, config); + if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE) return -ENOTSUPP; -- cgit v1.2.3 From d3c7cfc6d3dc315ca58b516303ccb0ac8b005600 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 22 Jan 2021 14:38:48 +0200 Subject: lib/cmdline_kunit: add a new test case for get_options() Add a test case for get_options() which is provided by cmdline.c. Signed-off-by: Andy Shevchenko --- lib/cmdline_kunit.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/lib/cmdline_kunit.c b/lib/cmdline_kunit.c index 550e7a47fd24..bf8b3ee9e897 100644 --- a/lib/cmdline_kunit.c +++ b/lib/cmdline_kunit.c @@ -18,6 +18,26 @@ static const int cmdline_test_values[] = { 1, 3, 2, 1, 1, 1, 3, 1, }; +static_assert(ARRAY_SIZE(cmdline_test_strings) == ARRAY_SIZE(cmdline_test_values)); + +static const char *cmdline_test_range_strings[] = { + "-7" , "--7" , "-1-2" , "7--9", + "7-" , "-7--9", "7-9," , "9-7" , + "5-a", "a-5" , "5-8" , ",8-5", + "+,1", "-,4" , "-3,0-1,6", "4,-" , + " +2", " -9" , "0-1,-3,6", "- 9" , +}; + +static const int cmdline_test_range_values[][16] = { + { 1, -7, }, { 0, -0, }, { 4, -1, 0, +1, 2, }, { 0, 7, }, + { 0, +7, }, { 0, -7, }, { 3, +7, 8, +9, 0, }, { 0, 9, }, + { 0, +5, }, { 0, -0, }, { 4, +5, 6, +7, 8, }, { 0, 0, }, + { 0, +0, }, { 0, -0, }, { 4, -3, 0, +1, 6, }, { 1, 4, }, + { 0, +0, }, { 0, -0, }, { 4, +0, 1, -3, 6, }, { 0, 0, }, +}; + +static_assert(ARRAY_SIZE(cmdline_test_range_strings) == ARRAY_SIZE(cmdline_test_range_values)); + static void cmdline_do_one_test(struct kunit *test, const char *in, int rc, int offset) { const char *fmt = "Pattern: %s"; @@ -84,10 +104,37 @@ static void cmdline_test_tail_int(struct kunit *test) } while (++i < ARRAY_SIZE(cmdline_test_strings)); } +static void cmdline_do_one_range_test(struct kunit *test, const char *in, + unsigned int n, const int *e) +{ + unsigned int i; + int r[16]; + + memset(r, 0, sizeof(r)); + get_options(in, ARRAY_SIZE(r), r); + KUNIT_EXPECT_EQ_MSG(test, r[0], e[0], "in test %u expected %d numbers, got %d", + n, e[0], r[0]); + for (i = 1; i < ARRAY_SIZE(r); i++) + KUNIT_EXPECT_EQ_MSG(test, r[i], e[i], "in test %u at %u", n, i); +} + +static void cmdline_test_range(struct kunit *test) +{ + unsigned int i = 0; + + do { + const char *str = cmdline_test_range_strings[i]; + const int *e = cmdline_test_range_values[i]; + + cmdline_do_one_range_test(test, str, i, e); + } while (++i < ARRAY_SIZE(cmdline_test_range_strings)); +} + static struct kunit_case cmdline_test_cases[] = { KUNIT_CASE(cmdline_test_noint), KUNIT_CASE(cmdline_test_lead_int), KUNIT_CASE(cmdline_test_tail_int), + KUNIT_CASE(cmdline_test_range), {} }; -- cgit v1.2.3 From f1f405c35ec217e4f68f9e25cd83d003f8a6d03e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 22 Jan 2021 14:38:49 +0200 Subject: lib/cmdline: Update documentation to reflect behaviour get_options() API has some tricks to optimize that may be not so obvious to the caller. Update documentation to reflect current behaviour. Signed-off-by: Andy Shevchenko Reviewed-by: Bartosz Golaszewski Reviewed-by: Geert Uytterhoeven --- lib/cmdline.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/cmdline.c b/lib/cmdline.c index b390dd03363b..f33882f1cd52 100644 --- a/lib/cmdline.c +++ b/lib/cmdline.c @@ -83,7 +83,7 @@ EXPORT_SYMBOL(get_option); * get_options - Parse a string into a list of integers * @str: String to be parsed * @nints: size of integer array - * @ints: integer array + * @ints: integer array (must have room for at least one element) * * This function parses a string containing a comma-separated * list of integers, a hyphen-separated range of _positive_ integers, @@ -91,6 +91,11 @@ EXPORT_SYMBOL(get_option); * full, or when no more numbers can be retrieved from the * string. * + * Returns: + * + * The first element is filled by the number of collected integers + * in the range. The rest is what was parsed from the @str. + * * Return value is the character in the string which caused * the parse to end (typically a null terminator, if @str is * completely parseable). -- cgit v1.2.3 From 0ea09083116de44f1a938482fb704bbfcc7ae6f4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 22 Jan 2021 15:56:52 +0200 Subject: lib/cmdline: Allow get_options() to take 0 to validate the input Allow get_options() to take 0 as a number of integers parameter to validate the input. Signed-off-by: Andy Shevchenko Reviewed-by: Geert Uytterhoeven --- lib/cmdline.c | 14 +++++++++++--- lib/cmdline_kunit.c | 11 ++++++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/cmdline.c b/lib/cmdline.c index f33882f1cd52..dfd4c4423f9a 100644 --- a/lib/cmdline.c +++ b/lib/cmdline.c @@ -91,6 +91,9 @@ EXPORT_SYMBOL(get_option); * full, or when no more numbers can be retrieved from the * string. * + * When @nints is 0, the function just validates the given @str and + * returns the amount of parseable integers as described below. + * * Returns: * * The first element is filled by the number of collected integers @@ -103,15 +106,20 @@ EXPORT_SYMBOL(get_option); char *get_options(const char *str, int nints, int *ints) { + bool validate = (nints == 0); int res, i = 1; - while (i < nints) { - res = get_option((char **)&str, ints + i); + while (i < nints || validate) { + int *pint = validate ? ints : ints + i; + + res = get_option((char **)&str, pint); if (res == 0) break; if (res == 3) { + int n = validate ? 0 : nints - i; int range_nums; - range_nums = get_range((char **)&str, ints + i, nints - i); + + range_nums = get_range((char **)&str, pint, n); if (range_nums < 0) break; /* diff --git a/lib/cmdline_kunit.c b/lib/cmdline_kunit.c index bf8b3ee9e897..018bfc8113c4 100644 --- a/lib/cmdline_kunit.c +++ b/lib/cmdline_kunit.c @@ -109,13 +109,22 @@ static void cmdline_do_one_range_test(struct kunit *test, const char *in, { unsigned int i; int r[16]; + int *p; memset(r, 0, sizeof(r)); get_options(in, ARRAY_SIZE(r), r); - KUNIT_EXPECT_EQ_MSG(test, r[0], e[0], "in test %u expected %d numbers, got %d", + KUNIT_EXPECT_EQ_MSG(test, r[0], e[0], "in test %u (parsed) expected %d numbers, got %d", n, e[0], r[0]); for (i = 1; i < ARRAY_SIZE(r); i++) KUNIT_EXPECT_EQ_MSG(test, r[i], e[i], "in test %u at %u", n, i); + + memset(r, 0, sizeof(r)); + get_options(in, 0, r); + KUNIT_EXPECT_EQ_MSG(test, r[0], e[0], "in test %u (validated) expected %d numbers, got %d", + n, e[0], r[0]); + + p = memchr_inv(&r[1], 0, sizeof(r) - sizeof(r[0])); + KUNIT_EXPECT_PTR_EQ_MSG(test, p, (int *)0, "in test %u at %u out of bound", n, p - r); } static void cmdline_test_range(struct kunit *test) -- cgit v1.2.3 From deb631c40114409077bb972b99fe80967bd62fd1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 22 Jan 2021 14:38:51 +0200 Subject: gpio: aggregator: Replace isrange() by using get_options() We already have a nice helper called get_options() which can be used to validate the input format. Replace isrange() by using it. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Reviewed-by: Bartosz Golaszewski Reviewed-by: Geert Uytterhoeven --- drivers/gpio/gpio-aggregator.c | 33 +++------------------------------ 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index dfd8a4876a27..40a081b095fb 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -62,34 +62,6 @@ static char *get_arg(char **args) return start; } -static bool isrange(const char *s) -{ - size_t n; - - if (IS_ERR_OR_NULL(s)) - return false; - - while (1) { - n = strspn(s, "0123456789"); - if (!n) - return false; - - s += n; - - switch (*s++) { - case '\0': - return true; - - case '-': - case ',': - break; - - default: - return false; - } - } -} - static int aggr_add_gpio(struct gpio_aggregator *aggr, const char *key, int hwnum, unsigned int *n) { @@ -112,10 +84,10 @@ static int aggr_add_gpio(struct gpio_aggregator *aggr, const char *key, static int aggr_parse(struct gpio_aggregator *aggr) { + char *name, *offsets, *p; char *args = aggr->args; unsigned long *bitmap; unsigned int i, n = 0; - char *name, *offsets; int error = 0; bitmap = bitmap_alloc(ARCH_NR_GPIOS, GFP_KERNEL); @@ -130,7 +102,8 @@ static int aggr_parse(struct gpio_aggregator *aggr) goto free_bitmap; } - if (!isrange(offsets)) { + p = get_options(offsets, 0, &error); + if (error == 0 || *p) { /* Named GPIO line */ error = aggr_add_gpio(aggr, name, U16_MAX, &n); if (error) -- cgit v1.2.3 From b2498cb87c4ba87580e5975e049d589b6786ff75 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 22 Jan 2021 14:38:52 +0200 Subject: gpio: aggregator: Use compound literal from the header Instead of doing it in place, convert GPIO_LOOKUP_IDX() and GPIO_HOG() to be compund literals that's allow to use them as rvalue in assignments. Due to above conversion, use compound literal from the header in the gpio-aggregator.c. Signed-off-by: Andy Shevchenko Reviewed-by: Geert Uytterhoeven --- drivers/gpio/gpio-aggregator.c | 3 +-- include/linux/gpio/machine.h | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 40a081b095fb..13e473c97ce4 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -72,8 +72,7 @@ static int aggr_add_gpio(struct gpio_aggregator *aggr, const char *key, if (!lookups) return -ENOMEM; - lookups->table[*n] = - (struct gpiod_lookup)GPIO_LOOKUP_IDX(key, hwnum, NULL, *n, 0); + lookups->table[*n] = GPIO_LOOKUP_IDX(key, hwnum, NULL, *n, 0); (*n)++; memset(&lookups->table[*n], 0, sizeof(lookups->table[*n])); diff --git a/include/linux/gpio/machine.h b/include/linux/gpio/machine.h index 781a053abbb9..d755e529c1e3 100644 --- a/include/linux/gpio/machine.h +++ b/include/linux/gpio/machine.h @@ -75,7 +75,7 @@ struct gpiod_hog { * gpiod_get_index() */ #define GPIO_LOOKUP_IDX(_key, _chip_hwnum, _con_id, _idx, _flags) \ -{ \ +(struct gpiod_lookup) { \ .key = _key, \ .chip_hwnum = _chip_hwnum, \ .con_id = _con_id, \ @@ -87,7 +87,7 @@ struct gpiod_hog { * Simple definition of a single GPIO hog in an array. */ #define GPIO_HOG(_chip_label, _chip_hwnum, _line_name, _lflags, _dflags) \ -{ \ +(struct gpiod_hog) { \ .chip_label = _chip_label, \ .chip_hwnum = _chip_hwnum, \ .line_name = _line_name, \ -- cgit v1.2.3 From 6e004a98299cb477c44b7518a37ff03596d4c385 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 22 Jan 2021 14:38:53 +0200 Subject: gpio: aggregator: Remove trailing comma in terminator entries Remove trailing comma in terminator entries to avoid potential expanding an array behind it. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Reviewed-by: Bartosz Golaszewski Reviewed-by: Geert Uytterhoeven --- drivers/gpio/gpio-aggregator.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index 13e473c97ce4..08171431bb8f 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -243,7 +243,7 @@ static DRIVER_ATTR_WO(delete_device); static struct attribute *gpio_aggregator_attrs[] = { &driver_attr_new_device.attr, &driver_attr_delete_device.attr, - NULL, + NULL }; ATTRIBUTE_GROUPS(gpio_aggregator); @@ -517,7 +517,7 @@ static const struct of_device_id gpio_aggregator_dt_ids[] = { * Add GPIO-operated devices controlled from userspace below, * or use "driver_override" in sysfs */ - {}, + {} }; MODULE_DEVICE_TABLE(of, gpio_aggregator_dt_ids); #endif -- cgit v1.2.3 From fe08e9e26ae78bdbf0e445a02b953e17222349ac Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 22 Nov 2019 16:57:30 +0200 Subject: gpio: msic: Remove driver for deprecated platform Intel Moorestown and Medfield are quite old Intel Atom based 32-bit platforms, which were in limited use in some Android phones, tablets and consumer electronics more than eight years ago. There are no bugs or problems ever reported outside from Intel for breaking any of that platforms for years. It seems no real users exists who run more or less fresh kernel on it. The commit 05f4434bc130 ("ASoC: Intel: remove mfld_machine") also in align with this theory. Due to above and to reduce a burden of supporting outdated drivers we remove the support of outdated platforms completely. Signed-off-by: Andy Shevchenko Acked-by: Linus Walleij --- MAINTAINERS | 1 - drivers/gpio/Kconfig | 7 -- drivers/gpio/gpio-msic.c | 314 ----------------------------------------------- 3 files changed, 322 deletions(-) delete mode 100644 drivers/gpio/gpio-msic.c diff --git a/MAINTAINERS b/MAINTAINERS index bc4d80bcdf52..c6dd3d40bbab 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9095,7 +9095,6 @@ M: Andy Shevchenko S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git F: drivers/gpio/gpio-*cove.c -F: drivers/gpio/gpio-msic.c INTEL PMIC MULTIFUNCTION DEVICE DRIVERS M: Andy Shevchenko diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index c96086f15bc0..5c0d46369591 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1256,13 +1256,6 @@ config GPIO_MAX77650 GPIO driver for MAX77650/77651 PMIC from Maxim Semiconductor. These chips have a single pin that can be configured as GPIO. -config GPIO_MSIC - bool "Intel MSIC mixed signal gpio support" - depends on (X86 || COMPILE_TEST) && MFD_INTEL_MSIC - help - Enable support for GPIO on intel MSIC controllers found in - intel MID devices - config GPIO_PALMAS bool "TI PALMAS series PMICs GPIO" depends on MFD_PALMAS diff --git a/drivers/gpio/gpio-msic.c b/drivers/gpio/gpio-msic.c deleted file mode 100644 index 7e3c96e4ab2c..000000000000 --- a/drivers/gpio/gpio-msic.c +++ /dev/null @@ -1,314 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intel Medfield MSIC GPIO driver> - * Copyright (c) 2011, Intel Corporation. - * - * Author: Mathias Nyman - * Based on intel_pmic_gpio.c - */ - -#include -#include -#include -#include -#include -#include -#include - -/* the offset for the mapping of global gpio pin to irq */ -#define MSIC_GPIO_IRQ_OFFSET 0x100 - -#define MSIC_GPIO_DIR_IN 0 -#define MSIC_GPIO_DIR_OUT BIT(5) -#define MSIC_GPIO_TRIG_FALL BIT(1) -#define MSIC_GPIO_TRIG_RISE BIT(2) - -/* masks for msic gpio output GPIOxxxxCTLO registers */ -#define MSIC_GPIO_DIR_MASK BIT(5) -#define MSIC_GPIO_DRV_MASK BIT(4) -#define MSIC_GPIO_REN_MASK BIT(3) -#define MSIC_GPIO_RVAL_MASK (BIT(2) | BIT(1)) -#define MSIC_GPIO_DOUT_MASK BIT(0) - -/* masks for msic gpio input GPIOxxxxCTLI registers */ -#define MSIC_GPIO_GLBYP_MASK BIT(5) -#define MSIC_GPIO_DBNC_MASK (BIT(4) | BIT(3)) -#define MSIC_GPIO_INTCNT_MASK (BIT(2) | BIT(1)) -#define MSIC_GPIO_DIN_MASK BIT(0) - -#define MSIC_NUM_GPIO 24 - -struct msic_gpio { - struct platform_device *pdev; - struct mutex buslock; - struct gpio_chip chip; - int irq; - unsigned irq_base; - unsigned long trig_change_mask; - unsigned trig_type; -}; - -/* - * MSIC has 24 gpios, 16 low voltage (1.2-1.8v) and 8 high voltage (3v). - * Both the high and low voltage gpios are divided in two banks. - * GPIOs are numbered with GPIO0LV0 as gpio_base in the following order: - * GPIO0LV0..GPIO0LV7: low voltage, bank 0, gpio_base - * GPIO1LV0..GPIO1LV7: low voltage, bank 1, gpio_base + 8 - * GPIO0HV0..GPIO0HV3: high voltage, bank 0, gpio_base + 16 - * GPIO1HV0..GPIO1HV3: high voltage, bank 1, gpio_base + 20 - */ - -static int msic_gpio_to_ireg(unsigned offset) -{ - if (offset >= MSIC_NUM_GPIO) - return -EINVAL; - - if (offset < 8) - return INTEL_MSIC_GPIO0LV0CTLI - offset; - if (offset < 16) - return INTEL_MSIC_GPIO1LV0CTLI - offset + 8; - if (offset < 20) - return INTEL_MSIC_GPIO0HV0CTLI - offset + 16; - - return INTEL_MSIC_GPIO1HV0CTLI - offset + 20; -} - -static int msic_gpio_to_oreg(unsigned offset) -{ - if (offset >= MSIC_NUM_GPIO) - return -EINVAL; - - if (offset < 8) - return INTEL_MSIC_GPIO0LV0CTLO - offset; - if (offset < 16) - return INTEL_MSIC_GPIO1LV0CTLO - offset + 8; - if (offset < 20) - return INTEL_MSIC_GPIO0HV0CTLO - offset + 16; - - return INTEL_MSIC_GPIO1HV0CTLO - offset + 20; -} - -static int msic_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - int reg; - - reg = msic_gpio_to_oreg(offset); - if (reg < 0) - return reg; - - return intel_msic_reg_update(reg, MSIC_GPIO_DIR_IN, MSIC_GPIO_DIR_MASK); -} - -static int msic_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - int reg; - unsigned mask; - - value = (!!value) | MSIC_GPIO_DIR_OUT; - mask = MSIC_GPIO_DIR_MASK | MSIC_GPIO_DOUT_MASK; - - reg = msic_gpio_to_oreg(offset); - if (reg < 0) - return reg; - - return intel_msic_reg_update(reg, value, mask); -} - -static int msic_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - u8 r; - int ret; - int reg; - - reg = msic_gpio_to_ireg(offset); - if (reg < 0) - return reg; - - ret = intel_msic_reg_read(reg, &r); - if (ret < 0) - return ret; - - return !!(r & MSIC_GPIO_DIN_MASK); -} - -static void msic_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - int reg; - - reg = msic_gpio_to_oreg(offset); - if (reg < 0) - return; - - intel_msic_reg_update(reg, !!value , MSIC_GPIO_DOUT_MASK); -} - -/* - * This is called from genirq with mg->buslock locked and - * irq_desc->lock held. We can not access the scu bus here, so we - * store the change and update in the bus_sync_unlock() function below - */ -static int msic_irq_type(struct irq_data *data, unsigned type) -{ - struct msic_gpio *mg = irq_data_get_irq_chip_data(data); - u32 gpio = data->irq - mg->irq_base; - - if (gpio >= mg->chip.ngpio) - return -EINVAL; - - /* mark for which gpio the trigger changed, protected by buslock */ - mg->trig_change_mask |= (1 << gpio); - mg->trig_type = type; - - return 0; -} - -static int msic_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct msic_gpio *mg = gpiochip_get_data(chip); - return mg->irq_base + offset; -} - -static void msic_bus_lock(struct irq_data *data) -{ - struct msic_gpio *mg = irq_data_get_irq_chip_data(data); - mutex_lock(&mg->buslock); -} - -static void msic_bus_sync_unlock(struct irq_data *data) -{ - struct msic_gpio *mg = irq_data_get_irq_chip_data(data); - int offset; - int reg; - u8 trig = 0; - - /* We can only get one change at a time as the buslock covers the - entire transaction. The irq_desc->lock is dropped before we are - called but that is fine */ - if (mg->trig_change_mask) { - offset = __ffs(mg->trig_change_mask); - - reg = msic_gpio_to_ireg(offset); - if (reg < 0) - goto out; - - if (mg->trig_type & IRQ_TYPE_EDGE_RISING) - trig |= MSIC_GPIO_TRIG_RISE; - if (mg->trig_type & IRQ_TYPE_EDGE_FALLING) - trig |= MSIC_GPIO_TRIG_FALL; - - intel_msic_reg_update(reg, trig, MSIC_GPIO_INTCNT_MASK); - mg->trig_change_mask = 0; - } -out: - mutex_unlock(&mg->buslock); -} - -/* Firmware does all the masking and unmasking for us, no masking here. */ -static void msic_irq_unmask(struct irq_data *data) { } - -static void msic_irq_mask(struct irq_data *data) { } - -static struct irq_chip msic_irqchip = { - .name = "MSIC-GPIO", - .irq_mask = msic_irq_mask, - .irq_unmask = msic_irq_unmask, - .irq_set_type = msic_irq_type, - .irq_bus_lock = msic_bus_lock, - .irq_bus_sync_unlock = msic_bus_sync_unlock, -}; - -static void msic_gpio_irq_handler(struct irq_desc *desc) -{ - struct irq_data *data = irq_desc_get_irq_data(desc); - struct msic_gpio *mg = irq_data_get_irq_handler_data(data); - struct irq_chip *chip = irq_data_get_irq_chip(data); - struct intel_msic *msic = pdev_to_intel_msic(mg->pdev); - unsigned long pending; - int i; - int bitnr; - u8 pin; - - for (i = 0; i < (mg->chip.ngpio / BITS_PER_BYTE); i++) { - intel_msic_irq_read(msic, INTEL_MSIC_GPIO0LVIRQ + i, &pin); - pending = pin; - - for_each_set_bit(bitnr, &pending, BITS_PER_BYTE) - generic_handle_irq(mg->irq_base + i * BITS_PER_BYTE + bitnr); - } - chip->irq_eoi(data); -} - -static int platform_msic_gpio_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct intel_msic_gpio_pdata *pdata = dev_get_platdata(dev); - struct msic_gpio *mg; - int irq = platform_get_irq(pdev, 0); - int retval; - int i; - - if (irq < 0) { - dev_err(dev, "no IRQ line: %d\n", irq); - return irq; - } - - if (!pdata || !pdata->gpio_base) { - dev_err(dev, "incorrect or missing platform data\n"); - return -EINVAL; - } - - mg = kzalloc(sizeof(*mg), GFP_KERNEL); - if (!mg) - return -ENOMEM; - - dev_set_drvdata(dev, mg); - - mg->pdev = pdev; - mg->irq = irq; - mg->irq_base = pdata->gpio_base + MSIC_GPIO_IRQ_OFFSET; - mg->chip.label = "msic_gpio"; - mg->chip.direction_input = msic_gpio_direction_input; - mg->chip.direction_output = msic_gpio_direction_output; - mg->chip.get = msic_gpio_get; - mg->chip.set = msic_gpio_set; - mg->chip.to_irq = msic_gpio_to_irq; - mg->chip.base = pdata->gpio_base; - mg->chip.ngpio = MSIC_NUM_GPIO; - mg->chip.can_sleep = true; - mg->chip.parent = dev; - - mutex_init(&mg->buslock); - - retval = gpiochip_add_data(&mg->chip, mg); - if (retval) { - dev_err(dev, "Adding MSIC gpio chip failed\n"); - goto err; - } - - for (i = 0; i < mg->chip.ngpio; i++) { - irq_set_chip_data(i + mg->irq_base, mg); - irq_set_chip_and_handler(i + mg->irq_base, - &msic_irqchip, - handle_simple_irq); - } - irq_set_chained_handler_and_data(mg->irq, msic_gpio_irq_handler, mg); - - return 0; -err: - kfree(mg); - return retval; -} - -static struct platform_driver platform_msic_gpio_driver = { - .driver = { - .name = "msic_gpio", - }, - .probe = platform_msic_gpio_probe, -}; - -static int __init platform_msic_gpio_init(void) -{ - return platform_driver_register(&platform_msic_gpio_driver); -} -subsys_initcall(platform_msic_gpio_init); -- cgit v1.2.3 From 944dcbe84b8ab7efdfcc592b6905a797324da51c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 22 Nov 2019 16:57:30 +0200 Subject: gpio: intel-mid: Remove driver for deprecated platform Intel Moorestown and Medfield are quite old Intel Atom based 32-bit platforms, which were in limited use in some Android phones, tablets and consumer electronics more than eight years ago. There are no bugs or problems ever reported outside from Intel for breaking any of that platforms for years. It seems no real users exists who run more or less fresh kernel on it. The commit 05f4434bc130 ("ASoC: Intel: remove mfld_machine") also in align with this theory. Due to above and to reduce a burden of supporting outdated drivers we remove the support of outdated platforms completely. Moreover this code duplicates gpio-pxa since the IP has been derived from XScale implementation. If anybody wants to resurrect this it has to be part of gpio-pxa.c. Signed-off-by: Andy Shevchenko Acked-by: Linus Walleij --- MAINTAINERS | 1 - drivers/gpio/Kconfig | 7 - drivers/gpio/Makefile | 1 - drivers/gpio/TODO | 2 +- drivers/gpio/gpio-intel-mid.c | 414 ------------------------------------------ 5 files changed, 1 insertion(+), 424 deletions(-) delete mode 100644 drivers/gpio/gpio-intel-mid.c diff --git a/MAINTAINERS b/MAINTAINERS index c6dd3d40bbab..656ae6685430 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8936,7 +8936,6 @@ L: linux-gpio@vger.kernel.org S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/andy/linux-gpio-intel.git F: drivers/gpio/gpio-ich.c -F: drivers/gpio/gpio-intel-mid.c F: drivers/gpio/gpio-merrifield.c F: drivers/gpio/gpio-ml-ioh.c F: drivers/gpio/gpio-pch.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 5c0d46369591..a6200a7b4a0e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1451,13 +1451,6 @@ config GPIO_BT8XX If unsure, say N. -config GPIO_INTEL_MID - bool "Intel MID GPIO support" - depends on X86_INTEL_MID - select GPIOLIB_IRQCHIP - help - Say Y here to support Intel MID GPIO. - config GPIO_MERRIFIELD tristate "Intel Merrifield GPIO support" depends on X86_INTEL_MID diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 43250931ee73..364f31abf5a5 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -67,7 +67,6 @@ obj-$(CONFIG_GPIO_HISI) += gpio-hisi.o obj-$(CONFIG_GPIO_HLWD) += gpio-hlwd.o obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o obj-$(CONFIG_GPIO_ICH) += gpio-ich.o -obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o obj-$(CONFIG_GPIO_IOP) += gpio-iop.o obj-$(CONFIG_GPIO_IT87) += gpio-it87.o obj-$(CONFIG_GPIO_IXP4XX) += gpio-ixp4xx.o diff --git a/drivers/gpio/TODO b/drivers/gpio/TODO index 0229fa79499e..b8b1473a5b1e 100644 --- a/drivers/gpio/TODO +++ b/drivers/gpio/TODO @@ -101,7 +101,7 @@ for a few GPIOs. Those should stay where they are. At the same time it makes sense to get rid of code duplication in existing or new coming drivers. For example, gpio-ml-ioh should be incorporated into -gpio-pch. In similar way gpio-intel-mid into gpio-pxa. +gpio-pch. Generic MMIO GPIO diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c deleted file mode 100644 index 86a10c808ef6..000000000000 --- a/drivers/gpio/gpio-intel-mid.c +++ /dev/null @@ -1,414 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intel MID GPIO driver - * - * Copyright (c) 2008-2014,2016 Intel Corporation. - */ - -/* Supports: - * Moorestown platform Langwell chip. - * Medfield platform Penwell chip. - * Clovertrail platform Cloverview chip. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define INTEL_MID_IRQ_TYPE_EDGE (1 << 0) -#define INTEL_MID_IRQ_TYPE_LEVEL (1 << 1) - -/* - * Langwell chip has 64 pins and thus there are 2 32bit registers to control - * each feature, while Penwell chip has 96 pins for each block, and need 3 32bit - * registers to control them, so we only define the order here instead of a - * structure, to get a bit offset for a pin (use GPDR as an example): - * - * nreg = ngpio / 32; - * reg = offset / 32; - * bit = offset % 32; - * reg_addr = reg_base + GPDR * nreg * 4 + reg * 4; - * - * so the bit of reg_addr is to control pin offset's GPDR feature -*/ - -enum GPIO_REG { - GPLR = 0, /* pin level read-only */ - GPDR, /* pin direction */ - GPSR, /* pin set */ - GPCR, /* pin clear */ - GRER, /* rising edge detect */ - GFER, /* falling edge detect */ - GEDR, /* edge detect result */ - GAFR, /* alt function */ -}; - -/* intel_mid gpio driver data */ -struct intel_mid_gpio_ddata { - u16 ngpio; /* number of gpio pins */ - u32 chip_irq_type; /* chip interrupt type */ -}; - -struct intel_mid_gpio { - struct gpio_chip chip; - void __iomem *reg_base; - spinlock_t lock; - struct pci_dev *pdev; -}; - -static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, - enum GPIO_REG reg_type) -{ - struct intel_mid_gpio *priv = gpiochip_get_data(chip); - unsigned nreg = chip->ngpio / 32; - u8 reg = offset / 32; - - return priv->reg_base + reg_type * nreg * 4 + reg * 4; -} - -static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset, - enum GPIO_REG reg_type) -{ - struct intel_mid_gpio *priv = gpiochip_get_data(chip); - unsigned nreg = chip->ngpio / 32; - u8 reg = offset / 16; - - return priv->reg_base + reg_type * nreg * 4 + reg * 4; -} - -static int intel_gpio_request(struct gpio_chip *chip, unsigned offset) -{ - void __iomem *gafr = gpio_reg_2bit(chip, offset, GAFR); - u32 value = readl(gafr); - int shift = (offset % 16) << 1, af = (value >> shift) & 3; - - if (af) { - value &= ~(3 << shift); - writel(value, gafr); - } - return 0; -} - -static int intel_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - void __iomem *gplr = gpio_reg(chip, offset, GPLR); - - return !!(readl(gplr) & BIT(offset % 32)); -} - -static void intel_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - void __iomem *gpsr, *gpcr; - - if (value) { - gpsr = gpio_reg(chip, offset, GPSR); - writel(BIT(offset % 32), gpsr); - } else { - gpcr = gpio_reg(chip, offset, GPCR); - writel(BIT(offset % 32), gpcr); - } -} - -static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - struct intel_mid_gpio *priv = gpiochip_get_data(chip); - void __iomem *gpdr = gpio_reg(chip, offset, GPDR); - u32 value; - unsigned long flags; - - if (priv->pdev) - pm_runtime_get(&priv->pdev->dev); - - spin_lock_irqsave(&priv->lock, flags); - value = readl(gpdr); - value &= ~BIT(offset % 32); - writel(value, gpdr); - spin_unlock_irqrestore(&priv->lock, flags); - - if (priv->pdev) - pm_runtime_put(&priv->pdev->dev); - - return 0; -} - -static int intel_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - struct intel_mid_gpio *priv = gpiochip_get_data(chip); - void __iomem *gpdr = gpio_reg(chip, offset, GPDR); - unsigned long flags; - - intel_gpio_set(chip, offset, value); - - if (priv->pdev) - pm_runtime_get(&priv->pdev->dev); - - spin_lock_irqsave(&priv->lock, flags); - value = readl(gpdr); - value |= BIT(offset % 32); - writel(value, gpdr); - spin_unlock_irqrestore(&priv->lock, flags); - - if (priv->pdev) - pm_runtime_put(&priv->pdev->dev); - - return 0; -} - -static int intel_mid_irq_type(struct irq_data *d, unsigned type) -{ - struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct intel_mid_gpio *priv = gpiochip_get_data(gc); - u32 gpio = irqd_to_hwirq(d); - unsigned long flags; - u32 value; - void __iomem *grer = gpio_reg(&priv->chip, gpio, GRER); - void __iomem *gfer = gpio_reg(&priv->chip, gpio, GFER); - - if (gpio >= priv->chip.ngpio) - return -EINVAL; - - if (priv->pdev) - pm_runtime_get(&priv->pdev->dev); - - spin_lock_irqsave(&priv->lock, flags); - if (type & IRQ_TYPE_EDGE_RISING) - value = readl(grer) | BIT(gpio % 32); - else - value = readl(grer) & (~BIT(gpio % 32)); - writel(value, grer); - - if (type & IRQ_TYPE_EDGE_FALLING) - value = readl(gfer) | BIT(gpio % 32); - else - value = readl(gfer) & (~BIT(gpio % 32)); - writel(value, gfer); - spin_unlock_irqrestore(&priv->lock, flags); - - if (priv->pdev) - pm_runtime_put(&priv->pdev->dev); - - return 0; -} - -static void intel_mid_irq_unmask(struct irq_data *d) -{ -} - -static void intel_mid_irq_mask(struct irq_data *d) -{ -} - -static struct irq_chip intel_mid_irqchip = { - .name = "INTEL_MID-GPIO", - .irq_mask = intel_mid_irq_mask, - .irq_unmask = intel_mid_irq_unmask, - .irq_set_type = intel_mid_irq_type, -}; - -static const struct intel_mid_gpio_ddata gpio_lincroft = { - .ngpio = 64, -}; - -static const struct intel_mid_gpio_ddata gpio_penwell_aon = { - .ngpio = 96, - .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, -}; - -static const struct intel_mid_gpio_ddata gpio_penwell_core = { - .ngpio = 96, - .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, -}; - -static const struct intel_mid_gpio_ddata gpio_cloverview_aon = { - .ngpio = 96, - .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE | INTEL_MID_IRQ_TYPE_LEVEL, -}; - -static const struct intel_mid_gpio_ddata gpio_cloverview_core = { - .ngpio = 96, - .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, -}; - -static const struct pci_device_id intel_gpio_ids[] = { - { - /* Lincroft */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f), - .driver_data = (kernel_ulong_t)&gpio_lincroft, - }, - { - /* Penwell AON */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081f), - .driver_data = (kernel_ulong_t)&gpio_penwell_aon, - }, - { - /* Penwell Core */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081a), - .driver_data = (kernel_ulong_t)&gpio_penwell_core, - }, - { - /* Cloverview Aon */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08eb), - .driver_data = (kernel_ulong_t)&gpio_cloverview_aon, - }, - { - /* Cloverview Core */ - PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7), - .driver_data = (kernel_ulong_t)&gpio_cloverview_core, - }, - { } -}; - -static void intel_mid_irq_handler(struct irq_desc *desc) -{ - struct gpio_chip *gc = irq_desc_get_handler_data(desc); - struct intel_mid_gpio *priv = gpiochip_get_data(gc); - struct irq_data *data = irq_desc_get_irq_data(desc); - struct irq_chip *chip = irq_data_get_irq_chip(data); - u32 base, gpio, mask; - unsigned long pending; - void __iomem *gedr; - - /* check GPIO controller to check which pin triggered the interrupt */ - for (base = 0; base < priv->chip.ngpio; base += 32) { - gedr = gpio_reg(&priv->chip, base, GEDR); - while ((pending = readl(gedr))) { - gpio = __ffs(pending); - mask = BIT(gpio); - /* Clear before handling so we can't lose an edge */ - writel(mask, gedr); - generic_handle_irq(irq_find_mapping(gc->irq.domain, - base + gpio)); - } - } - - chip->irq_eoi(data); -} - -static int intel_mid_irq_init_hw(struct gpio_chip *chip) -{ - struct intel_mid_gpio *priv = gpiochip_get_data(chip); - void __iomem *reg; - unsigned base; - - for (base = 0; base < priv->chip.ngpio; base += 32) { - /* Clear the rising-edge detect register */ - reg = gpio_reg(&priv->chip, base, GRER); - writel(0, reg); - /* Clear the falling-edge detect register */ - reg = gpio_reg(&priv->chip, base, GFER); - writel(0, reg); - /* Clear the edge detect status register */ - reg = gpio_reg(&priv->chip, base, GEDR); - writel(~0, reg); - } - - return 0; -} - -static int __maybe_unused intel_gpio_runtime_idle(struct device *dev) -{ - int err = pm_schedule_suspend(dev, 500); - return err ?: -EBUSY; -} - -static const struct dev_pm_ops intel_gpio_pm_ops = { - SET_RUNTIME_PM_OPS(NULL, NULL, intel_gpio_runtime_idle) -}; - -static int intel_gpio_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - void __iomem *base; - struct intel_mid_gpio *priv; - u32 gpio_base; - u32 irq_base; - int retval; - struct gpio_irq_chip *girq; - struct intel_mid_gpio_ddata *ddata = - (struct intel_mid_gpio_ddata *)id->driver_data; - - retval = pcim_enable_device(pdev); - if (retval) - return retval; - - retval = pcim_iomap_regions(pdev, 1 << 0 | 1 << 1, pci_name(pdev)); - if (retval) { - dev_err(&pdev->dev, "I/O memory mapping error\n"); - return retval; - } - - base = pcim_iomap_table(pdev)[1]; - - irq_base = readl(base); - gpio_base = readl(sizeof(u32) + base); - - /* release the IO mapping, since we already get the info from bar1 */ - pcim_iounmap_regions(pdev, 1 << 1); - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->reg_base = pcim_iomap_table(pdev)[0]; - priv->chip.label = dev_name(&pdev->dev); - priv->chip.parent = &pdev->dev; - priv->chip.request = intel_gpio_request; - priv->chip.direction_input = intel_gpio_direction_input; - priv->chip.direction_output = intel_gpio_direction_output; - priv->chip.get = intel_gpio_get; - priv->chip.set = intel_gpio_set; - priv->chip.base = gpio_base; - priv->chip.ngpio = ddata->ngpio; - priv->chip.can_sleep = false; - priv->pdev = pdev; - - spin_lock_init(&priv->lock); - - girq = &priv->chip.irq; - girq->chip = &intel_mid_irqchip; - girq->init_hw = intel_mid_irq_init_hw; - girq->parent_handler = intel_mid_irq_handler; - girq->num_parents = 1; - girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents, - sizeof(*girq->parents), - GFP_KERNEL); - if (!girq->parents) - return -ENOMEM; - girq->parents[0] = pdev->irq; - girq->first = irq_base; - girq->default_type = IRQ_TYPE_NONE; - girq->handler = handle_simple_irq; - - pci_set_drvdata(pdev, priv); - - retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv); - if (retval) { - dev_err(&pdev->dev, "gpiochip_add error %d\n", retval); - return retval; - } - - pm_runtime_put_noidle(&pdev->dev); - pm_runtime_allow(&pdev->dev); - - return 0; -} - -static struct pci_driver intel_gpio_driver = { - .name = "intel_mid_gpio", - .id_table = intel_gpio_ids, - .probe = intel_gpio_probe, - .driver = { - .pm = &intel_gpio_pm_ops, - }, -}; - -builtin_pci_driver(intel_gpio_driver); -- cgit v1.2.3 From 2edba74c9d3499472caf6f76e518b4d9d1b04e6e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 29 Jan 2019 16:40:50 +0200 Subject: gpio: wcove: Get rid of error prone casting in IRQ handler The casting from int to long on 64-bit platform is error prone. Replace it with proper type of the variable on stack. Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-wcove.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c index 97c5f1d01b62..6b47505f4070 100644 --- a/drivers/gpio/gpio-wcove.c +++ b/drivers/gpio/gpio-wcove.c @@ -324,7 +324,8 @@ static struct irq_chip wcove_irqchip = { static irqreturn_t wcove_gpio_irq_handler(int irq, void *data) { struct wcove_gpio *wg = (struct wcove_gpio *)data; - unsigned int pending, virq, gpio, mask, offset; + unsigned int virq, gpio, mask, offset; + unsigned long pending; u8 p[2]; if (regmap_bulk_read(wg->regmap, IRQ_STATUS_BASE, p, 2)) { @@ -339,8 +340,7 @@ static irqreturn_t wcove_gpio_irq_handler(int irq, void *data) /* Iterate until no interrupt is pending */ while (pending) { /* One iteration is for all pending bits */ - for_each_set_bit(gpio, (const unsigned long *)&pending, - WCOVE_GPIO_NUM) { + for_each_set_bit(gpio, &pending, WCOVE_GPIO_NUM) { offset = (gpio > GROUP0_NR_IRQS) ? 1 : 0; mask = (offset == 1) ? BIT(gpio - GROUP0_NR_IRQS) : BIT(gpio); -- cgit v1.2.3 From 9fe5fcd640359c113060676174039b8940f588e1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 29 Jan 2021 18:24:28 +0200 Subject: gpio: wcove: Switch to use regmap_set_bits(), regmap_clear_bits() the regmap_set_bits(), regmap_clear_bits() API makes code better to understand. Switch the driver to use them, Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-wcove.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c index 6b47505f4070..8097c8726790 100644 --- a/drivers/gpio/gpio-wcove.c +++ b/drivers/gpio/gpio-wcove.c @@ -125,9 +125,9 @@ static void wcove_update_irq_mask(struct wcove_gpio *wg, int gpio) } if (wg->set_irq_mask) - regmap_update_bits(wg->regmap, reg, mask, mask); + regmap_set_bits(wg->regmap, reg, mask); else - regmap_update_bits(wg->regmap, reg, mask, 0); + regmap_clear_bits(wg->regmap, reg, mask); } static void wcove_update_irq_ctrl(struct wcove_gpio *wg, int gpio) @@ -207,9 +207,9 @@ static void wcove_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value) return; if (value) - regmap_update_bits(wg->regmap, reg, 1, 1); + regmap_set_bits(wg->regmap, reg, 1); else - regmap_update_bits(wg->regmap, reg, 1, 0); + regmap_clear_bits(wg->regmap, reg, 1); } static int wcove_gpio_set_config(struct gpio_chip *chip, unsigned int gpio, @@ -346,8 +346,7 @@ static irqreturn_t wcove_gpio_irq_handler(int irq, void *data) BIT(gpio); virq = irq_find_mapping(wg->chip.irq.domain, gpio); handle_nested_irq(virq); - regmap_update_bits(wg->regmap, IRQ_STATUS_BASE + offset, - mask, mask); + regmap_set_bits(wg->regmap, IRQ_STATUS_BASE + offset, mask); } /* Next iteration */ @@ -473,14 +472,12 @@ static int wcove_gpio_probe(struct platform_device *pdev) } /* Enable GPIO0 interrupts */ - ret = regmap_update_bits(wg->regmap, IRQ_MASK_BASE, GPIO_IRQ0_MASK, - 0x00); + ret = regmap_clear_bits(wg->regmap, IRQ_MASK_BASE + 0, GPIO_IRQ0_MASK); if (ret) return ret; /* Enable GPIO1 interrupts */ - ret = regmap_update_bits(wg->regmap, IRQ_MASK_BASE + 1, GPIO_IRQ1_MASK, - 0x00); + ret = regmap_clear_bits(wg->regmap, IRQ_MASK_BASE + 1, GPIO_IRQ1_MASK); if (ret) return ret; -- cgit v1.2.3 From 5a2a46ae4b26501aab068a9a94dc581af040c7ed Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 14 Oct 2020 17:13:23 +0300 Subject: gpio: wcove: Split out to_ireg() helper and deduplicate the code There are a few places in the code where IRQ status and mask register values are being updated. Use a new exctracted helper to deduplicate the code. While at it, get rid of unnecessary divisions. Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-wcove.c | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c index 8097c8726790..a19eeef6cf1e 100644 --- a/drivers/gpio/gpio-wcove.c +++ b/drivers/gpio/gpio-wcove.c @@ -73,6 +73,8 @@ enum ctrl_register { CTRL_IN, CTRL_OUT, + IRQ_STATUS, + IRQ_MASK, }; /* @@ -112,18 +114,25 @@ static inline int to_reg(int gpio, enum ctrl_register reg_type) return reg; } -static void wcove_update_irq_mask(struct wcove_gpio *wg, int gpio) +static inline int to_ireg(int gpio, enum ctrl_register type, unsigned int *mask) { - unsigned int reg, mask; + unsigned int reg = type == IRQ_STATUS ? IRQ_STATUS_BASE : IRQ_MASK_BASE; if (gpio < GROUP0_NR_IRQS) { - reg = IRQ_MASK_BASE; - mask = BIT(gpio % GROUP0_NR_IRQS); + reg += 0; + *mask = BIT(gpio); } else { - reg = IRQ_MASK_BASE + 1; - mask = BIT((gpio - GROUP0_NR_IRQS) % GROUP1_NR_IRQS); + reg += 1; + *mask = BIT(gpio - GROUP0_NR_IRQS); } + return reg; +} + +static void wcove_update_irq_mask(struct wcove_gpio *wg, int gpio) +{ + unsigned int mask, reg = to_ireg(gpio, IRQ_MASK, &mask); + if (wg->set_irq_mask) regmap_set_bits(wg->regmap, reg, mask); else @@ -324,7 +333,7 @@ static struct irq_chip wcove_irqchip = { static irqreturn_t wcove_gpio_irq_handler(int irq, void *data) { struct wcove_gpio *wg = (struct wcove_gpio *)data; - unsigned int virq, gpio, mask, offset; + unsigned int virq, gpio; unsigned long pending; u8 p[2]; @@ -341,12 +350,11 @@ static irqreturn_t wcove_gpio_irq_handler(int irq, void *data) while (pending) { /* One iteration is for all pending bits */ for_each_set_bit(gpio, &pending, WCOVE_GPIO_NUM) { - offset = (gpio > GROUP0_NR_IRQS) ? 1 : 0; - mask = (offset == 1) ? BIT(gpio - GROUP0_NR_IRQS) : - BIT(gpio); + unsigned int mask, reg = to_ireg(gpio, IRQ_STATUS, &mask); + virq = irq_find_mapping(wg->chip.irq.domain, gpio); handle_nested_irq(virq); - regmap_set_bits(wg->regmap, IRQ_STATUS_BASE + offset, mask); + regmap_set_bits(wg->regmap, reg, mask); } /* Next iteration */ @@ -366,30 +374,26 @@ static void wcove_gpio_dbg_show(struct seq_file *s, { unsigned int ctlo, ctli, irq_mask, irq_status; struct wcove_gpio *wg = gpiochip_get_data(chip); - int gpio, offset, group, ret = 0; + int gpio, mask, ret = 0; for (gpio = 0; gpio < WCOVE_GPIO_NUM; gpio++) { - group = gpio < GROUP0_NR_IRQS ? 0 : 1; ret += regmap_read(wg->regmap, to_reg(gpio, CTRL_OUT), &ctlo); ret += regmap_read(wg->regmap, to_reg(gpio, CTRL_IN), &ctli); - ret += regmap_read(wg->regmap, IRQ_MASK_BASE + group, - &irq_mask); - ret += regmap_read(wg->regmap, IRQ_STATUS_BASE + group, - &irq_status); + ret += regmap_read(wg->regmap, to_ireg(gpio, IRQ_MASK, &mask), &irq_mask); + ret += regmap_read(wg->regmap, to_ireg(gpio, IRQ_STATUS, &mask), &irq_status); if (ret) { pr_err("Failed to read registers: ctrl out/in or irq status/mask\n"); break; } - offset = gpio % 8; seq_printf(s, " gpio-%-2d %s %s %s %s ctlo=%2x,%s %s\n", gpio, ctlo & CTLO_DIR_OUT ? "out" : "in ", ctli & 0x1 ? "hi" : "lo", ctli & CTLI_INTCNT_NE ? "fall" : " ", ctli & CTLI_INTCNT_PE ? "rise" : " ", ctlo, - irq_mask & BIT(offset) ? "mask " : "unmask", - irq_status & BIT(offset) ? "pending" : " "); + irq_mask & mask ? "mask " : "unmask", + irq_status & mask ? "pending" : " "); } } -- cgit v1.2.3 From 78034b8e072d01a9c9cf8ef667b7fc2806017608 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 3 Feb 2021 12:57:56 +0200 Subject: gpio: msic: Drop driver from Makefile Driver is gone, no need to keep a Makefile entry for it. Remove. Reported-by: Hans de Goede Signed-off-by: Andy Shevchenko --- drivers/gpio/Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 364f31abf5a5..c58a90a3c3b1 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -102,7 +102,6 @@ obj-$(CONFIG_GPIO_MOXTET) += gpio-moxtet.o obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o obj-$(CONFIG_GPIO_MSC313) += gpio-msc313.o -obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o obj-$(CONFIG_GPIO_MT7621) += gpio-mt7621.o obj-$(CONFIG_GPIO_MVEBU) += gpio-mvebu.o obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o -- cgit v1.2.3 From 45c5277f347841daefb1a7b48da9904ef9b46ca9 Mon Sep 17 00:00:00 2001 From: Srinivas Neeli Date: Fri, 29 Jan 2021 19:56:46 +0530 Subject: gpio: gpio-xilinx: Simplify with dev_err_probe() Common pattern of handling deferred probe can be simplified with dev_err_probe(). Less code and also it prints the error value. Signed-off-by: Srinivas Neeli Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-xilinx.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index be539381fd82..d010a63d5d15 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -357,11 +357,8 @@ static int xgpio_probe(struct platform_device *pdev) } chip->clk = devm_clk_get_optional(&pdev->dev, NULL); - if (IS_ERR(chip->clk)) { - if (PTR_ERR(chip->clk) != -EPROBE_DEFER) - dev_dbg(&pdev->dev, "Input clock not found\n"); - return PTR_ERR(chip->clk); - } + if (IS_ERR(chip->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(chip->clk), "input clock not found.\n"); status = clk_prepare_enable(chip->clk); if (status < 0) { -- cgit v1.2.3 From 37ef334680800263b32bb96a5156a4b47f0244a2 Mon Sep 17 00:00:00 2001 From: Srinivas Neeli Date: Fri, 29 Jan 2021 19:56:47 +0530 Subject: gpio: gpio-xilinx: Reduce spinlock array to array Changed spinlock array to single. It is preparation for irq support which is shared between two channels that's why spinlock should be only one. Signed-off-by: Srinivas Neeli Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-xilinx.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index d010a63d5d15..f88db56543c2 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -47,7 +47,7 @@ struct xgpio_instance { unsigned int gpio_width[2]; u32 gpio_state[2]; u32 gpio_dir[2]; - spinlock_t gpio_lock[2]; + spinlock_t gpio_lock; /* For serializing operations */ struct clk *clk; }; @@ -113,7 +113,7 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) int index = xgpio_index(chip, gpio); int offset = xgpio_offset(chip, gpio); - spin_lock_irqsave(&chip->gpio_lock[index], flags); + spin_lock_irqsave(&chip->gpio_lock, flags); /* Write to GPIO signal and set its direction to output */ if (val) @@ -124,7 +124,7 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET + xgpio_regoffset(chip, gpio), chip->gpio_state[index]); - spin_unlock_irqrestore(&chip->gpio_lock[index], flags); + spin_unlock_irqrestore(&chip->gpio_lock, flags); } /** @@ -144,7 +144,7 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, int index = xgpio_index(chip, 0); int offset, i; - spin_lock_irqsave(&chip->gpio_lock[index], flags); + spin_lock_irqsave(&chip->gpio_lock, flags); /* Write to GPIO signals */ for (i = 0; i < gc->ngpio; i++) { @@ -155,9 +155,9 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET + index * XGPIO_CHANNEL_OFFSET, chip->gpio_state[index]); - spin_unlock_irqrestore(&chip->gpio_lock[index], flags); + spin_unlock_irqrestore(&chip->gpio_lock, flags); index = xgpio_index(chip, i); - spin_lock_irqsave(&chip->gpio_lock[index], flags); + spin_lock_irqsave(&chip->gpio_lock, flags); } if (__test_and_clear_bit(i, mask)) { offset = xgpio_offset(chip, i); @@ -171,7 +171,7 @@ static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, xgpio_writereg(chip->regs + XGPIO_DATA_OFFSET + index * XGPIO_CHANNEL_OFFSET, chip->gpio_state[index]); - spin_unlock_irqrestore(&chip->gpio_lock[index], flags); + spin_unlock_irqrestore(&chip->gpio_lock, flags); } /** @@ -190,14 +190,14 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) int index = xgpio_index(chip, gpio); int offset = xgpio_offset(chip, gpio); - spin_lock_irqsave(&chip->gpio_lock[index], flags); + spin_lock_irqsave(&chip->gpio_lock, flags); /* Set the GPIO bit in shadow register and set direction as input */ chip->gpio_dir[index] |= BIT(offset); xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET + xgpio_regoffset(chip, gpio), chip->gpio_dir[index]); - spin_unlock_irqrestore(&chip->gpio_lock[index], flags); + spin_unlock_irqrestore(&chip->gpio_lock, flags); return 0; } @@ -221,7 +221,7 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) int index = xgpio_index(chip, gpio); int offset = xgpio_offset(chip, gpio); - spin_lock_irqsave(&chip->gpio_lock[index], flags); + spin_lock_irqsave(&chip->gpio_lock, flags); /* Write state of GPIO signal */ if (val) @@ -236,7 +236,7 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) xgpio_writereg(chip->regs + XGPIO_TRI_OFFSET + xgpio_regoffset(chip, gpio), chip->gpio_dir[index]); - spin_unlock_irqrestore(&chip->gpio_lock[index], flags); + spin_unlock_irqrestore(&chip->gpio_lock, flags); return 0; } @@ -312,7 +312,7 @@ static int xgpio_probe(struct platform_device *pdev) if (of_property_read_u32(np, "xlnx,gpio-width", &chip->gpio_width[0])) chip->gpio_width[0] = 32; - spin_lock_init(&chip->gpio_lock[0]); + spin_lock_init(&chip->gpio_lock); if (of_property_read_u32(np, "xlnx,is-dual", &is_dual)) is_dual = 0; @@ -336,7 +336,6 @@ static int xgpio_probe(struct platform_device *pdev) &chip->gpio_width[1])) chip->gpio_width[1] = 32; - spin_lock_init(&chip->gpio_lock[1]); } chip->gc.base = -1; -- cgit v1.2.3 From a32c7caea292c4d1e417eae6e5a348d187546acf Mon Sep 17 00:00:00 2001 From: Srinivas Neeli Date: Fri, 29 Jan 2021 19:56:48 +0530 Subject: gpio: gpio-xilinx: Add interrupt support Adds interrupt support to the Xilinx GPIO driver so that rising and falling edge line events can be supported. Since interrupt support is an optional feature in the Xilinx IP, the driver continues to support devices which have no interrupt provided. Depends on OF_GPIO framework for of_xlate function to translate gpiospec to the GPIO number and flags. Signed-off-by: Robert Hancock Signed-off-by: Shubhrajyoti Datta Signed-off-by: Srinivas Neeli Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 2 + drivers/gpio/gpio-xilinx.c | 246 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 244 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index a6200a7b4a0e..e3607ec4c2e8 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -704,6 +704,8 @@ config GPIO_XGENE_SB config GPIO_XILINX tristate "Xilinx GPIO support" + select GPIOLIB_IRQCHIP + depends on OF_GPIO help Say yes here to support the Xilinx FPGA GPIO device diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index f88db56543c2..62deb755f910 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -10,7 +10,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -22,6 +24,11 @@ #define XGPIO_CHANNEL_OFFSET 0x8 +#define XGPIO_GIER_OFFSET 0x11c /* Global Interrupt Enable */ +#define XGPIO_GIER_IE BIT(31) +#define XGPIO_IPISR_OFFSET 0x120 /* IP Interrupt Status */ +#define XGPIO_IPIER_OFFSET 0x128 /* IP Interrupt Enable */ + /* Read/Write access to the GPIO registers */ #if defined(CONFIG_ARCH_ZYNQ) || defined(CONFIG_X86) # define xgpio_readreg(offset) readl(offset) @@ -36,9 +43,15 @@ * @gc: GPIO chip * @regs: register block * @gpio_width: GPIO width for every channel - * @gpio_state: GPIO state shadow register + * @gpio_state: GPIO write state shadow register + * @gpio_last_irq_read: GPIO read state register from last interrupt * @gpio_dir: GPIO direction shadow register * @gpio_lock: Lock used for synchronization + * @irq: IRQ used by GPIO device + * @irqchip: IRQ chip + * @irq_enable: GPIO IRQ enable/disable bitfield + * @irq_rising_edge: GPIO IRQ rising edge enable/disable bitfield + * @irq_falling_edge: GPIO IRQ falling edge enable/disable bitfield * @clk: clock resource for this driver */ struct xgpio_instance { @@ -46,8 +59,14 @@ struct xgpio_instance { void __iomem *regs; unsigned int gpio_width[2]; u32 gpio_state[2]; + u32 gpio_last_irq_read[2]; u32 gpio_dir[2]; spinlock_t gpio_lock; /* For serializing operations */ + int irq; + struct irq_chip irqchip; + u32 irq_enable[2]; + u32 irq_rising_edge[2]; + u32 irq_falling_edge[2]; struct clk *clk; }; @@ -276,6 +295,175 @@ static int xgpio_remove(struct platform_device *pdev) return 0; } +/** + * xgpio_irq_ack - Acknowledge a child GPIO interrupt. + * @irq_data: per IRQ and chip data passed down to chip functions + * This currently does nothing, but irq_ack is unconditionally called by + * handle_edge_irq and therefore must be defined. + */ +static void xgpio_irq_ack(struct irq_data *irq_data) +{ +} + +/** + * xgpio_irq_mask - Write the specified signal of the GPIO device. + * @irq_data: per IRQ and chip data passed down to chip functions + */ +static void xgpio_irq_mask(struct irq_data *irq_data) +{ + unsigned long flags; + struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data); + int irq_offset = irqd_to_hwirq(irq_data); + int index = xgpio_index(chip, irq_offset); + int offset = xgpio_offset(chip, irq_offset); + + spin_lock_irqsave(&chip->gpio_lock, flags); + + chip->irq_enable[index] &= ~BIT(offset); + + if (!chip->irq_enable[index]) { + /* Disable per channel interrupt */ + u32 temp = xgpio_readreg(chip->regs + XGPIO_IPIER_OFFSET); + + temp &= ~BIT(index); + xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, temp); + } + spin_unlock_irqrestore(&chip->gpio_lock, flags); +} + +/** + * xgpio_irq_unmask - Write the specified signal of the GPIO device. + * @irq_data: per IRQ and chip data passed down to chip functions + */ +static void xgpio_irq_unmask(struct irq_data *irq_data) +{ + unsigned long flags; + struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data); + int irq_offset = irqd_to_hwirq(irq_data); + int index = xgpio_index(chip, irq_offset); + int offset = xgpio_offset(chip, irq_offset); + u32 old_enable = chip->irq_enable[index]; + + spin_lock_irqsave(&chip->gpio_lock, flags); + + chip->irq_enable[index] |= BIT(offset); + + if (!old_enable) { + /* Clear any existing per-channel interrupts */ + u32 val = xgpio_readreg(chip->regs + XGPIO_IPISR_OFFSET) & + BIT(index); + + if (val) + xgpio_writereg(chip->regs + XGPIO_IPISR_OFFSET, val); + + /* Update GPIO IRQ read data before enabling interrupt*/ + val = xgpio_readreg(chip->regs + XGPIO_DATA_OFFSET + + index * XGPIO_CHANNEL_OFFSET); + chip->gpio_last_irq_read[index] = val; + + /* Enable per channel interrupt */ + val = xgpio_readreg(chip->regs + XGPIO_IPIER_OFFSET); + val |= BIT(index); + xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, val); + } + + spin_unlock_irqrestore(&chip->gpio_lock, flags); +} + +/** + * xgpio_set_irq_type - Write the specified signal of the GPIO device. + * @irq_data: Per IRQ and chip data passed down to chip functions + * @type: Interrupt type that is to be set for the gpio pin + * + * Return: + * 0 if interrupt type is supported otherwise -EINVAL + */ +static int xgpio_set_irq_type(struct irq_data *irq_data, unsigned int type) +{ + struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data); + int irq_offset = irqd_to_hwirq(irq_data); + int index = xgpio_index(chip, irq_offset); + int offset = xgpio_offset(chip, irq_offset); + + /* + * The Xilinx GPIO hardware provides a single interrupt status + * indication for any state change in a given GPIO channel (bank). + * Therefore, only rising edge or falling edge triggers are + * supported. + */ + switch (type & IRQ_TYPE_SENSE_MASK) { + case IRQ_TYPE_EDGE_BOTH: + chip->irq_rising_edge[index] |= BIT(offset); + chip->irq_falling_edge[index] |= BIT(offset); + break; + case IRQ_TYPE_EDGE_RISING: + chip->irq_rising_edge[index] |= BIT(offset); + chip->irq_falling_edge[index] &= ~BIT(offset); + break; + case IRQ_TYPE_EDGE_FALLING: + chip->irq_rising_edge[index] &= ~BIT(offset); + chip->irq_falling_edge[index] |= BIT(offset); + break; + default: + return -EINVAL; + } + + irq_set_handler_locked(irq_data, handle_edge_irq); + return 0; +} + +/** + * xgpio_irqhandler - Gpio interrupt service routine + * @desc: Pointer to interrupt description + */ +static void xgpio_irqhandler(struct irq_desc *desc) +{ + struct xgpio_instance *chip = irq_desc_get_handler_data(desc); + struct irq_chip *irqchip = irq_desc_get_chip(desc); + u32 num_channels = chip->gpio_width[1] ? 2 : 1; + u32 offset = 0, index; + u32 status = xgpio_readreg(chip->regs + XGPIO_IPISR_OFFSET); + + xgpio_writereg(chip->regs + XGPIO_IPISR_OFFSET, status); + + chained_irq_enter(irqchip, desc); + for (index = 0; index < num_channels; index++) { + if ((status & BIT(index))) { + unsigned long rising_events, falling_events, all_events; + unsigned long flags; + u32 data, bit; + unsigned int irq; + + spin_lock_irqsave(&chip->gpio_lock, flags); + data = xgpio_readreg(chip->regs + XGPIO_DATA_OFFSET + + index * XGPIO_CHANNEL_OFFSET); + rising_events = data & + ~chip->gpio_last_irq_read[index] & + chip->irq_enable[index] & + chip->irq_rising_edge[index]; + falling_events = ~data & + chip->gpio_last_irq_read[index] & + chip->irq_enable[index] & + chip->irq_falling_edge[index]; + dev_dbg(chip->gc.parent, + "IRQ chan %u rising 0x%lx falling 0x%lx\n", + index, rising_events, falling_events); + all_events = rising_events | falling_events; + chip->gpio_last_irq_read[index] = data; + spin_unlock_irqrestore(&chip->gpio_lock, flags); + + for_each_set_bit(bit, &all_events, 32) { + irq = irq_find_mapping(chip->gc.irq.domain, + offset + bit); + generic_handle_irq(irq); + } + } + offset += chip->gpio_width[index]; + } + + chained_irq_exit(irqchip, desc); +} + /** * xgpio_of_probe - Probe method for the GPIO device. * @pdev: pointer to the platform device @@ -289,7 +477,10 @@ static int xgpio_probe(struct platform_device *pdev) struct xgpio_instance *chip; int status = 0; struct device_node *np = pdev->dev.of_node; - u32 is_dual; + u32 is_dual = 0; + u32 cells = 2; + struct gpio_irq_chip *girq; + u32 temp; chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) @@ -305,6 +496,15 @@ static int xgpio_probe(struct platform_device *pdev) if (of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir[0])) chip->gpio_dir[0] = 0xFFFFFFFF; + /* Update cells with gpio-cells value */ + if (of_property_read_u32(np, "#gpio-cells", &cells)) + dev_dbg(&pdev->dev, "Missing gpio-cells property\n"); + + if (cells != 2) { + dev_err(&pdev->dev, "#gpio-cells mismatch\n"); + return -EINVAL; + } + /* * Check device node and parent device node for device width * and assume default width of 32 @@ -343,6 +543,7 @@ static int xgpio_probe(struct platform_device *pdev) chip->gc.parent = &pdev->dev; chip->gc.direction_input = xgpio_dir_in; chip->gc.direction_output = xgpio_dir_out; + chip->gc.of_gpio_n_cells = cells; chip->gc.get = xgpio_get; chip->gc.set = xgpio_set; chip->gc.set_multiple = xgpio_set_multiple; @@ -367,14 +568,51 @@ static int xgpio_probe(struct platform_device *pdev) xgpio_save_regs(chip); + chip->irq = platform_get_irq_optional(pdev, 0); + if (chip->irq <= 0) + goto skip_irq; + + chip->irqchip.name = "gpio-xilinx"; + chip->irqchip.irq_ack = xgpio_irq_ack; + chip->irqchip.irq_mask = xgpio_irq_mask; + chip->irqchip.irq_unmask = xgpio_irq_unmask; + chip->irqchip.irq_set_type = xgpio_set_irq_type; + + /* Disable per-channel interrupts */ + xgpio_writereg(chip->regs + XGPIO_IPIER_OFFSET, 0); + /* Clear any existing per-channel interrupts */ + temp = xgpio_readreg(chip->regs + XGPIO_IPISR_OFFSET); + xgpio_writereg(chip->regs + XGPIO_IPISR_OFFSET, temp); + /* Enable global interrupts */ + xgpio_writereg(chip->regs + XGPIO_GIER_OFFSET, XGPIO_GIER_IE); + + girq = &chip->gc.irq; + girq->chip = &chip->irqchip; + girq->parent_handler = xgpio_irqhandler; + girq->num_parents = 1; + girq->parents = devm_kcalloc(&pdev->dev, 1, + sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) { + status = -ENOMEM; + goto err_unprepare_clk; + } + girq->parents[0] = chip->irq; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_bad_irq; + +skip_irq: status = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip); if (status) { dev_err(&pdev->dev, "failed to add GPIO chip\n"); - clk_disable_unprepare(chip->clk); - return status; + goto err_unprepare_clk; } return 0; + +err_unprepare_clk: + clk_disable_unprepare(chip->clk); + return status; } static const struct of_device_id xgpio_of_match[] = { -- cgit v1.2.3 From 26b04774621ed333e8bc56479feb6e31625df58c Mon Sep 17 00:00:00 2001 From: Srinivas Neeli Date: Fri, 29 Jan 2021 19:56:49 +0530 Subject: gpio: gpio-xilinx: Add support for suspend and resume Add support for suspend and resume, pm runtime suspend and resume. Added free and request calls. Signed-off-by: Srinivas Neeli Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-xilinx.c | 92 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index 62deb755f910..acd574779ca6 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -16,6 +16,7 @@ #include #include #include +#include #include /* Register Offset Definitions */ @@ -278,6 +279,39 @@ static void xgpio_save_regs(struct xgpio_instance *chip) chip->gpio_dir[1]); } +static int xgpio_request(struct gpio_chip *chip, unsigned int offset) +{ + int ret; + + ret = pm_runtime_get_sync(chip->parent); + /* + * If the device is already active pm_runtime_get() will return 1 on + * success, but gpio_request still needs to return 0. + */ + return ret < 0 ? ret : 0; +} + +static void xgpio_free(struct gpio_chip *chip, unsigned int offset) +{ + pm_runtime_put(chip->parent); +} + +static int __maybe_unused xgpio_suspend(struct device *dev) +{ + struct xgpio_instance *gpio = dev_get_drvdata(dev); + struct irq_data *data = irq_get_irq_data(gpio->irq); + + if (!data) { + dev_err(dev, "irq_get_irq_data() failed\n"); + return -EINVAL; + } + + if (!irqd_is_wakeup_set(data)) + return pm_runtime_force_suspend(dev); + + return 0; +} + /** * xgpio_remove - Remove method for the GPIO device. * @pdev: pointer to the platform device @@ -290,6 +324,9 @@ static int xgpio_remove(struct platform_device *pdev) { struct xgpio_instance *gpio = platform_get_drvdata(pdev); + pm_runtime_get_sync(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(&pdev->dev); clk_disable_unprepare(gpio->clk); return 0; @@ -305,6 +342,46 @@ static void xgpio_irq_ack(struct irq_data *irq_data) { } +static int __maybe_unused xgpio_resume(struct device *dev) +{ + struct xgpio_instance *gpio = dev_get_drvdata(dev); + struct irq_data *data = irq_get_irq_data(gpio->irq); + + if (!data) { + dev_err(dev, "irq_get_irq_data() failed\n"); + return -EINVAL; + } + + if (!irqd_is_wakeup_set(data)) + return pm_runtime_force_resume(dev); + + return 0; +} + +static int __maybe_unused xgpio_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xgpio_instance *gpio = platform_get_drvdata(pdev); + + clk_disable(gpio->clk); + + return 0; +} + +static int __maybe_unused xgpio_runtime_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xgpio_instance *gpio = platform_get_drvdata(pdev); + + return clk_enable(gpio->clk); +} + +static const struct dev_pm_ops xgpio_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(xgpio_suspend, xgpio_resume) + SET_RUNTIME_PM_OPS(xgpio_runtime_suspend, + xgpio_runtime_resume, NULL) +}; + /** * xgpio_irq_mask - Write the specified signal of the GPIO device. * @irq_data: per IRQ and chip data passed down to chip functions @@ -546,6 +623,8 @@ static int xgpio_probe(struct platform_device *pdev) chip->gc.of_gpio_n_cells = cells; chip->gc.get = xgpio_get; chip->gc.set = xgpio_set; + chip->gc.request = xgpio_request; + chip->gc.free = xgpio_free; chip->gc.set_multiple = xgpio_set_multiple; chip->gc.label = dev_name(&pdev->dev); @@ -565,6 +644,9 @@ static int xgpio_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed to prepare clk\n"); return status; } + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); xgpio_save_regs(chip); @@ -595,7 +677,7 @@ static int xgpio_probe(struct platform_device *pdev) GFP_KERNEL); if (!girq->parents) { status = -ENOMEM; - goto err_unprepare_clk; + goto err_pm_put; } girq->parents[0] = chip->irq; girq->default_type = IRQ_TYPE_NONE; @@ -605,12 +687,15 @@ skip_irq: status = devm_gpiochip_add_data(&pdev->dev, &chip->gc, chip); if (status) { dev_err(&pdev->dev, "failed to add GPIO chip\n"); - goto err_unprepare_clk; + goto err_pm_put; } + pm_runtime_put(&pdev->dev); return 0; -err_unprepare_clk: +err_pm_put: + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); clk_disable_unprepare(chip->clk); return status; } @@ -628,6 +713,7 @@ static struct platform_driver xgpio_plat_driver = { .driver = { .name = "gpio-xilinx", .of_match_table = xgpio_of_match, + .pm = &xgpio_dev_pm_ops, }, }; -- cgit v1.2.3 From 6e551bfa9872cd335d0929411cfdefe99ce65a1d Mon Sep 17 00:00:00 2001 From: Srinivas Neeli Date: Fri, 29 Jan 2021 19:56:50 +0530 Subject: gpio: gpio-xilinx: Add check if width exceeds 32 Add check to see if gpio-width property does not exceed 32. If it exceeds then return -EINVAL. Signed-off-by: Srinivas Neeli Reviewed-by: Linus Walleij Acked-by: William Breathitt Gray Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-xilinx.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index acd574779ca6..b411d3156e0b 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -589,6 +589,9 @@ static int xgpio_probe(struct platform_device *pdev) if (of_property_read_u32(np, "xlnx,gpio-width", &chip->gpio_width[0])) chip->gpio_width[0] = 32; + if (chip->gpio_width[0] > 32) + return -EINVAL; + spin_lock_init(&chip->gpio_lock); if (of_property_read_u32(np, "xlnx,is-dual", &is_dual)) @@ -613,6 +616,8 @@ static int xgpio_probe(struct platform_device *pdev) &chip->gpio_width[1])) chip->gpio_width[1] = 32; + if (chip->gpio_width[1] > 32) + return -EINVAL; } chip->gc.base = -1; -- cgit v1.2.3 From 50f9a6c254c60bbad4cde050dbc39b46b61f7a5d Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 4 Feb 2021 13:43:57 +0100 Subject: gpio: uapi: use the preferred SPDX license identifier GPL-2.0 license identifier is deprecated. User-space projects that want to include the kernel header with their source-code will be unable to become fully REUSE compliant due to the reuse tool complaining about deprecated licenses. Change the SPDX identifier to GPL-2.0-only. Signed-off-by: Bartosz Golaszewski --- include/uapi/linux/gpio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/gpio.h b/include/uapi/linux/gpio.h index 7a6f7948a7df..eaaea3d8e6b4 100644 --- a/include/uapi/linux/gpio.h +++ b/include/uapi/linux/gpio.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* * - userspace ABI for the GPIO character devices * -- cgit v1.2.3 From 1827a8978d2683d9d285985b02c17b862d0832e8 Mon Sep 17 00:00:00 2001 From: Nikita Shubin Date: Tue, 9 Feb 2021 16:31:06 +0300 Subject: gpio: ep93xx: Fix wrong irq numbers in port F Port F IRQ's should be statically mapped to EP93XX_GPIO_F_IRQ_BASE. So we need to specify girq->first otherwise: "If device tree is used, then first_irq will be 0 and IRQ's get mapped dynamically on the fly" And that's not the thing we want. Reviewed-by: Linus Walleij Acked-by: Alexander Sverdlin Signed-off-by: Nikita Shubin Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-ep93xx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 94d9fa0d6aa7..3dea4ce929ab 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -416,6 +416,7 @@ static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc, girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_level_irq; gc->to_irq = ep93xx_gpio_f_to_irq; + girq->first = EP93XX_GPIO_F_IRQ_BASE; } return devm_gpiochip_add_data(dev, gc, epg); -- cgit v1.2.3 From 193f1b746812b6a5c69164e0401487f63c5a47c8 Mon Sep 17 00:00:00 2001 From: Nikita Shubin Date: Tue, 9 Feb 2021 16:31:07 +0300 Subject: gpio: ep93xx: drop to_irq binding As ->to_irq is redefined in gpiochip_add_irqchip, having it defined in driver is useless, so let's drop it. Reviewed-by: Linus Walleij Acked-by: Alexander Sverdlin Signed-off-by: Nikita Shubin Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-ep93xx.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 3dea4ce929ab..a69bf3100f99 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -318,11 +318,6 @@ static int ep93xx_gpio_set_config(struct gpio_chip *gc, unsigned offset, return 0; } -static int ep93xx_gpio_f_to_irq(struct gpio_chip *gc, unsigned offset) -{ - return EP93XX_GPIO_F_IRQ_BASE + offset; -} - static void ep93xx_init_irq_chip(struct device *dev, struct irq_chip *ic) { ic->irq_ack = ep93xx_gpio_irq_ack; @@ -415,7 +410,6 @@ static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc, } girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_level_irq; - gc->to_irq = ep93xx_gpio_f_to_irq; girq->first = EP93XX_GPIO_F_IRQ_BASE; } -- cgit v1.2.3 From 78f85c73e63cc70003e19e2cbb7f9abdd883b1ab Mon Sep 17 00:00:00 2001 From: Nikita Shubin Date: Tue, 9 Feb 2021 16:31:08 +0300 Subject: gpio: ep93xx: Fix typo s/hierarchial/hierarchical Fix typo in comment. Reviewed-by: Linus Walleij Acked-by: Alexander Sverdlin Signed-off-by: Nikita Shubin Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-ep93xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index a69bf3100f99..9760df7d1172 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -388,7 +388,7 @@ static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc, /* * FIXME: convert this to use hierarchical IRQ support! - * this requires fixing the root irqchip to be hierarchial. + * this requires fixing the root irqchip to be hierarchical. */ girq->parent_handler = ep93xx_gpio_f_irq_handler; girq->num_parents = 8; -- cgit v1.2.3 From f6b61541865f79807a43d3dec791eb0d6fc95d26 Mon Sep 17 00:00:00 2001 From: Nikita Shubin Date: Tue, 9 Feb 2021 16:31:09 +0300 Subject: gpio: ep93xx: refactor ep93xx_gpio_add_bank - replace plain numbers with girq->num_parents in devm_kcalloc - replace plain numbers with girq->num_parents for port F - refactor i - 1 to i + 1 to make loop more readable - combine getting IRQ's loop and setting handler's into single loop Reviewed-by: Linus Walleij Acked-by: Alexander Sverdlin Signed-off-by: Nikita Shubin Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-ep93xx.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 9760df7d1172..56ddf6b9baba 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -370,7 +370,7 @@ static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc, girq->parent_handler = ep93xx_gpio_ab_irq_handler; girq->num_parents = 1; - girq->parents = devm_kcalloc(dev, 1, + girq->parents = devm_kcalloc(dev, girq->num_parents, sizeof(*girq->parents), GFP_KERNEL); if (!girq->parents) @@ -392,15 +392,14 @@ static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc, */ girq->parent_handler = ep93xx_gpio_f_irq_handler; girq->num_parents = 8; - girq->parents = devm_kcalloc(dev, 8, + girq->parents = devm_kcalloc(dev, girq->num_parents, sizeof(*girq->parents), GFP_KERNEL); if (!girq->parents) return -ENOMEM; /* Pick resources 1..8 for these IRQs */ - for (i = 1; i <= 8; i++) - girq->parents[i - 1] = platform_get_irq(pdev, i); - for (i = 0; i < 8; i++) { + for (i = 0; i < girq->num_parents; i++) { + girq->parents[i] = platform_get_irq(pdev, i + 1); gpio_irq = EP93XX_GPIO_F_IRQ_BASE + i; irq_set_chip_data(gpio_irq, &epg->gc[5]); irq_set_chip_and_handler(gpio_irq, -- cgit v1.2.3 From 35d9e69592419fa2d138f64a2e4286635cdd98ac Mon Sep 17 00:00:00 2001 From: Nikita Shubin Date: Tue, 9 Feb 2021 16:31:10 +0300 Subject: gpio: ep93xx: refactor base IRQ number - use predefined constants instead of plain numbers - use provided bank IRQ number instead of defined constant for port F Reviewed-by: Linus Walleij Reviewed-by: Alexander Sverdlin Signed-off-by: Nikita Shubin Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-ep93xx.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 56ddf6b9baba..ef148b26b587 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -31,6 +31,8 @@ /* Maximum value for irq capable line identifiers */ #define EP93XX_GPIO_LINE_MAX_IRQ 23 +#define EP93XX_GPIO_A_IRQ_BASE 64 +#define EP93XX_GPIO_B_IRQ_BASE 72 /* * Static mapping of GPIO bank F IRQS: * F0..F7 (16..24) to irq 80..87. @@ -292,14 +294,14 @@ struct ep93xx_gpio_bank { static struct ep93xx_gpio_bank ep93xx_gpio_banks[] = { /* Bank A has 8 IRQs */ - EP93XX_GPIO_BANK("A", 0x00, 0x10, 0x90, 0, true, false, 64), + EP93XX_GPIO_BANK("A", 0x00, 0x10, 0x90, 0, true, false, EP93XX_GPIO_A_IRQ_BASE), /* Bank B has 8 IRQs */ - EP93XX_GPIO_BANK("B", 0x04, 0x14, 0xac, 8, true, false, 72), + EP93XX_GPIO_BANK("B", 0x04, 0x14, 0xac, 8, true, false, EP93XX_GPIO_B_IRQ_BASE), EP93XX_GPIO_BANK("C", 0x08, 0x18, 0x00, 40, false, false, 0), EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 0x00, 24, false, false, 0), EP93XX_GPIO_BANK("E", 0x20, 0x24, 0x00, 32, false, false, 0), /* Bank F has 8 IRQs */ - EP93XX_GPIO_BANK("F", 0x30, 0x34, 0x4c, 16, false, true, 0), + EP93XX_GPIO_BANK("F", 0x30, 0x34, 0x4c, 16, false, true, EP93XX_GPIO_F_IRQ_BASE), EP93XX_GPIO_BANK("G", 0x38, 0x3c, 0x00, 48, false, false, 0), EP93XX_GPIO_BANK("H", 0x40, 0x44, 0x00, 56, false, false, 0), }; @@ -400,7 +402,7 @@ static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc, /* Pick resources 1..8 for these IRQs */ for (i = 0; i < girq->num_parents; i++) { girq->parents[i] = platform_get_irq(pdev, i + 1); - gpio_irq = EP93XX_GPIO_F_IRQ_BASE + i; + gpio_irq = bank->irq_base + i; irq_set_chip_data(gpio_irq, &epg->gc[5]); irq_set_chip_and_handler(gpio_irq, girq->chip, @@ -409,7 +411,7 @@ static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc, } girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_level_irq; - girq->first = EP93XX_GPIO_F_IRQ_BASE; + girq->first = bank->irq_base; } return devm_gpiochip_add_data(dev, gc, epg); -- cgit v1.2.3 From a8002a35935aaefcd6a42ad3289f62bab947f2ca Mon Sep 17 00:00:00 2001 From: Maxim Kiselev Date: Wed, 17 Feb 2021 14:10:00 +0100 Subject: gpio: pcf857x: Fix missing first interrupt If no n_latch value will be provided at driver probe then all pins will be used as an input: gpio->out = ~n_latch; In that case initial state for all pins is "one": gpio->status = gpio->out; So if pcf857x IRQ happens with change pin value from "zero" to "one" then we miss it, because of "one" from IRQ and "one" from initial state leaves corresponding pin unchanged: change = (gpio->status ^ status) & gpio->irq_enabled; The right solution will be to read actual state at driver probe. Cc: stable@vger.kernel.org Fixes: 6e20a0a429bd ("gpio: pcf857x: enable gpio_to_irq() support") Signed-off-by: Maxim Kiselev Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pcf857x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index a2a8d155c75e..b7568ee33696 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -332,7 +332,7 @@ static int pcf857x_probe(struct i2c_client *client, * reset state. Otherwise it flags pins to be driven low. */ gpio->out = ~n_latch; - gpio->status = gpio->out; + gpio->status = gpio->read(gpio->client); /* Enable irqchip if we have an interrupt */ if (client->irq) { -- cgit v1.2.3