gpiolib: do not add duplicated GPIO Pin ranges
PATCH v3 1/2 gpiolib: do not add duplicated GPIO Pin ranges
look if a GPIO range with the same ID has already
been registered.
For pinctrls that are set up through devicetree, the GPIO Range might be already set by the the gpio-ranges property.
(see Documentation/devicetree/bindings/gpio/gpio.txt)
--- drivers/gpio/gpiolib.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+)
drivers/gpio/gpiolib.c +41 -0
@@ -2069,6 +2069,19 @@ int gpiochip_generic_config(struct gpio_chip *chip, unsigned offset, }EXPORT_SYMBOL_GPL (gpiochip_generic_config); +static struct gpio_pin_range *gpiochip_find_by_id (struct gpio_chip *chip, +unsigned int id) +{ +struct gpio_pin_range *pin_range; +struct gpio_device *gdev = chip->gpiodev; + +list_for_each_entry (pin_range, &gdev->pin_ranges, node) { +if (pin_range->range.id == id) +return pin_range; + } +return NULL ; +} +#ifdef CONFIG_PINCTRL /**
@@ -2086,6 +2099,20 @@ int gpiochip_add_pingroup_range(struct gpio_chip *chip,struct gpio_device *gdev = chip->gpiodev;int ret; +/* +* look if a GPIO range with the same ID has already been registered. +* For pinctrls that are set up through devicetree, the GPIO Range +* might be already set by the the gpio-ranges property. +* (see Documentation/devicetree/bindings/gpio/gpio.txt) +*/ + pin_range =gpiochip_find_by_id (chip, gpio_offset); +if (pin_range) { +chip_dbg (chip,"found existing GPIO range %d->%d - skipping\n" , + gpio_offset, + gpio_offset + pin_range->range.npins -1 ); +return 0 ; + } + pin_range =kzalloc (sizeof (*pin_range),GFP_KERNEL );if (!pin_range) {chip_err (chip,"failed to allocate pin ranges\n" );
@@ -2139,6 +2166,20 @@ int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,struct gpio_device *gdev = chip->gpiodev;int ret; +/* +* look if a GPIO range with the same ID has already been registered. +* For pinctrls that are set up through devicetree, the GPIO Range +* might be already set by the the gpio-ranges property. +* (see Documentation/devicetree/bindings/gpio/gpio.txt) +*/ + pin_range =gpiochip_find_by_id (chip, gpio_offset); +if (pin_range) { +chip_dbg (chip,"found existing GPIO range %d->%d - skipping\n" , + gpio_offset, + gpio_offset + pin_range->range.npins -1 ); +return 0 ; + } + pin_range =kzalloc (sizeof (*pin_range),GFP_KERNEL );if (!pin_range) {chip_err (chip,"failed to allocate pin ranges\n" );
Signature · 1 line
2.17.0
PATCH v3 2/2 pinctrl: msm: fix gpio-hog related boot issues
Sven Eckelmann reported an issue with the current IPQ4019 pinctrl. Setting up any gpio-hog in the device-tree for his device would "kill the bootup completely":
| [ 0.477838] msm_serial 78af000.serial: could not find pctldev for node /soc/pinctrl at 1000000/serial_pinmux, deferring probe | [ 0.499828] spi_qup 78b5000.spi: could not find pctldev for node /soc/pinctrl at 1000000/spi_0_pinmux, deferring probe | [ 1.298883] requesting hog GPIO enable USB2 power (chip 1000000.pinctrl, offset 58) failed, -517 | [ 1.299609] gpiochip_add_data: GPIOs 0..99 (1000000.pinctrl) failed to register | [ 1.308589] ipq4019-pinctrl 1000000.pinctrl: Failed register gpiochip | [ 1.316586] msm_serial 78af000.serial: could not find pctldev for node /soc/pinctrl at 1000000/serial_pinmux, deferring probe | [ 1.322415] spi_qup 78b5000.spi: could not find pctldev for node /soc/pinctrl at 1000000/spi_0_pinmux, deferri
This was also verified on a RT-AC58U (IPQ4018) which would no longer boot, if a gpio-hog was specified. (Tried forcing the USB LED PIN (GPIO0) to high.).
The problem is that Pinctrl+GPIO registration is currently peformed in the following order in pinctrl-msm.c:
1. pinctrl_register()
2. gpiochip_add()
3. gpiochip_add_pin_range()
The actual error code -517 == -EPROBE_DEFER is coming from pinctrl_get_device_gpio_range(), which is called through:
gpiochip_add
of_gpiochip_add
of_gpiochip_scan_gpios
gpiod_hog
gpiochip_request_own_desc
__gpiod_request
chip->request
gpiochip_generic_request
pinctrl_gpio_request
pinctrl_get_device_gpio_rangepinctrl_get_device_gpio_range() is unable to find any valid pin ranges, since nothing has been added to the pinctrldev_list yet. so the range can't be found, and the operation fails with -EPROBE_DEFER.
This patch fixes the issue by adding the "gpio-ranges" property to the pinctrl device node of all upstream Qcom SoC, so the ranges are added by of_gpiochip_add_pin_range(), which is called by of_gpiochip_add() before the call to of_gpiochip_scan_gpios() happens.gpiochip_add_pin_range() is longer needed and removed (to prevent adding the same entry to the pinctrldev_list twice).
--- arch/arm/boot/dts/qcom-apq8064.dtsi | 1 + arch/arm/boot/dts/qcom-apq8084.dtsi | 1 + arch/arm/boot/dts/qcom-ipq4019.dtsi | 1 + arch/arm/boot/dts/qcom-ipq8064.dtsi | 1 + arch/arm/boot/dts/qcom-mdm9615.dtsi | 1 + arch/arm/boot/dts/qcom-msm8660.dtsi | 1 + arch/arm/boot/dts/qcom-msm8960.dtsi | 1 + arch/arm/boot/dts/qcom-msm8974.dtsi | 1 + arch/arm64/boot/dts/qcom/ipq8074.dtsi | 3 ++- arch/arm64/boot/dts/qcom/msm8916.dtsi | 1 + arch/arm64/boot/dts/qcom/msm8992.dtsi | 1 + arch/arm64/boot/dts/qcom/msm8994.dtsi | 1 + arch/arm64/boot/dts/qcom/msm8996.dtsi | 1 + 13 files changed, 14 insertions(+), 1 deletion(-)
arch/arm/boot/dts/qcom-apq8064.dtsi +1 -0
@@ -327,6 +327,7 @@ reg = <0x800000 0x4000>; gpio-controller; + gpio-ranges = <&tlmm_pinmux 0 0 90>; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>;
arch/arm/boot/dts/qcom-apq8084.dtsi +1 -0
@@ -396,6 +396,7 @@ compatible = "qcom,apq8084-pinctrl"; reg = <0xfd510000 0x4000>; gpio-controller; + gpio-ranges = <&tlmm 0 0 147>; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>;
arch/arm/boot/dts/qcom-ipq4019.dtsi +1 -0
@@ -146,6 +146,7 @@ compatible = "qcom,ipq4019-pinctrl"; reg = <0x01000000 0x300000>; gpio-controller; + gpio-ranges = <&tlmm 0 0 100>; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>;
arch/arm/boot/dts/qcom-ipq8064.dtsi +1 -0
@@ -108,6 +108,7 @@ reg = <0x800000 0x4000>; gpio-controller; + gpio-ranges = <&qcom_pinmux 0 0 69>; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>;
arch/arm/boot/dts/qcom-mdm9615.dtsi +1 -0
@@ -128,6 +128,7 @@ msmgpio: pinctrl at 800000 { compatible = "qcom,mdm9615-pinctrl"; gpio-controller; + gpio-ranges = <&msmgpio 0 0 88>; #gpio-cells = <2>; interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>; interrupt-controller;
arch/arm/boot/dts/qcom-msm8660.dtsi +1 -0
@@ -110,6 +110,7 @@ reg = <0x800000 0x4000>; gpio-controller; + gpio-ranges = <&tlmm 0 0 173>; #gpio-cells = <2>; interrupts = <0 16 0x4>; interrupt-controller;
arch/arm/boot/dts/qcom-msm8960.dtsi +1 -0
@@ -102,6 +102,7 @@ msmgpio: pinctrl at 800000 { compatible = "qcom,msm8960-pinctrl"; gpio-controller; + gpio-ranges = <&msmgpio 0 0 152>; #gpio-cells = <2>; interrupts = <0 16 0x4>; interrupt-controller;
arch/arm/boot/dts/qcom-msm8974.dtsi +1 -0
@@ -696,6 +696,7 @@ compatible = "qcom,msm8974-pinctrl"; reg = <0xfd510000 0x4000>; gpio-controller; + gpio-ranges = <&msmgpio 0 0 146>; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>;
arch/arm64/boot/dts/qcom/ipq8074.dtsi +2 -1
@@ -24,11 +24,12 @@ ranges = <0 0 0 0xffffffff>; compatible = "simple-bus"; - pinctrl at 1000000 { + tlmm: pinctrl at 1000000 { compatible = "qcom,ipq8074-pinctrl"; reg = <0x1000000 0x300000>; interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; + gpio-ranges = <&tlmm 0 0 70>; #gpio-cells = <0x2>; interrupt-controller; #interrupt-cells = <0x2>;
arch/arm64/boot/dts/qcom/msm8916.dtsi +1 -0
@@ -281,6 +281,7 @@ reg = <0x1000000 0x300000>; interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; + gpio-ranges = <&msmgpio 0 0 122>; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>;
arch/arm64/boot/dts/qcom/msm8992.dtsi +1 -0
@@ -179,6 +179,7 @@ reg = <0xfd510000 0x4000>; interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; + gpio-ranges = <&msmgpio 0 0 146>; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>;
arch/arm64/boot/dts/qcom/msm8994.dtsi +1 -0
@@ -141,6 +141,7 @@ reg = <0xfd510000 0x4000>; interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; + gpio-ranges = <&msmgpio 0 0 146>; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>;
arch/arm64/boot/dts/qcom/msm8996.dtsi +1 -0
@@ -530,6 +530,7 @@ reg = <0x01010000 0x300000>; interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>; gpio-controller; + gpio-ranges = <&msmgpio 0 0 150>; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>;
Signature · 1 line
2.17.0