This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM3351: (AM335x) - how export DTS-defined GPIO using ABI descriptors (struct gpiod_desc)

Part Number: AM3351

[Most of the threads on GPIO use the deprecated sysfs interface; this request is for the current ABI character-based interface using GPIO descriptors]

AM3351 - custom board; similar to evm or BBB
TI-SDK v08.02 (w/kernel 5.10)

I am trying to gpiod_export() from a driver (drivers/pinctrl/pinctrl-single.c), some named user gpios declared in the devicetree. I want them available in userspace to get/set from an application. I also expect they would show as "named" and "used" from # gpioinfo. I can get the gpiod_count() and an associated name from the devicetree using of_property_read_string_index(), but I fail to get descriptors using either gpiod_get_array() or gpiod_get_index().

After getting the descriptors, I was planning to gpiod_export() the array of gpios and gpiod_export_link() to associate a name with them.

Why is gpiod_get_array() failing in the sequence below to return the descriptors gpio_count() sees?

(Some error checking omitted for conciseness)

    int gpio_count, gpio_name_count;
    struct gpio_descs *gpiodescs;
    
    gpio_count = gpiod_count(pcs->dev, "my"); // RETURNS 3
    gpio_name_count = of_property_count_strings(np, "my-gpio-names"); // RETURNS 3
    
    // THE FOLLOWING FAILS TO RETURN THE DESCRIPTORS
    gpiodescs = devm_gpiod_get_array(pcs->dev, "my", GPIOD_OUT_LOW); // returns IN_ERR
    if (IS_ERR(gpiodescs)) {
        dev_warn(pcs->dev, "failed to get gpio array (%d)\n", gpiodescs);
    }
    

Also tested in a loop, the following which also fails to get the descriptor

        descp = devm_gpiod_get_index(pcs->dev, "my", i, GPIOD_OUT_LOW);
        if (IS_ERR(descp)) {
            dev_warn(pcs->dev, "failed to get gpio desc\n");
        }

My abbreviated dts is:

&am33xx_pinmux {
    pinctrl-names = "default";
    my-gpios =  <&gpio2 4 GPIO_ACTIVE_HIGH>,
            <&gpio2 3 GPIO_ACTIVE_HIGH>,
            <&gpio2 0 GPIO_ACTIVE_HIGH>;

    my-gpio-names = "name1",
            "name2",
            "name3";

  • Hi Glen,

    I don't have comments to your driver code, but your device tree setting for the gpio does not look correct:

    The gpio line names should be defined with property "gpio-line-names", not a random name "my-gpio-names". And "gpio-line-names" should be defined in gpio controller node (&gpio2 node in your case).

    I don't see any reference which defines gpio settings (my-gpios property in your case) in the pinmux controller node. I am not sure how it should behave.

  • Thank you for your observations; partial success.

    Adding gpiod_enable()s to the driver may not be necessary in kernel 5.10 (I'm porting from kernel 4.x in TI-SDK v05).

    I've moved the gpios out of the pinmux to gpioX controller nodes and the gpio for gpio0 gets hogged automatically during boot. But gpio1, gpio2 and gpio3 are ignored. Below are output from `cat /sys/kernel/debug/gpio` (`gpioinfo` output is similar) and my improved devicetree.

    Why are controller nodes &gpio1, &gpio2 and &gpio3 ignored? I do see they are defined differently than &gpio0 in am33xx-l4.dtsi.

    cat /sys/kernel/debug/gpio
    gpiochip0: GPIOs 0-31, parent: platform/44e07000.gpio, gpio-0-31:
     gpio-22  (                    |gpo1                ) out lo ACTIVE LOW
     gpio-23  (                    |gpo0                ) out lo ACTIVE LOW
     gpio-26  (                    |gpi0                ) in  hi ACTIVE LOW
     gpio-27  (                    |gpi1                ) in  hi ACTIVE LOW
    
    
    gpiochip1: GPIOs 32-63, parent: platform/4804c000.gpio, gpio-32-63:
    
    gpiochip2: GPIOs 64-95, parent: platform/481ac000.gpio, gpio-64-95:
    
    gpiochip3: GPIOs 96-127, parent: platform/481ae000.gpio, gpio-96-127:

    excerpt from DTS. For &gpio1, I've tried both gpio numbers that are gpiochip1:[0-31] based as well as gpiochip1 [32-63] as seen below. Neiter produce the desired result as in the &gpio0 node.

    &gpio0 {
    	status = "okay";
    
    	gpi0 {
    		gpio-hog;
    		gpios = <26 GPIO_ACTIVE_LOW>;
    		input;
    		line-name = "gpi0";
    	};	
    	gpo0 {
    		gpio-hog;
    		gpios = <23 GPIO_ACTIVE_LOW>;
    		output-high;
    		line-name = "gpo0";
    	};
    
    	gpi1 {
    		gpio-hog;
    		gpios = <27 GPIO_ACTIVE_LOW>;
    		input;
    		line-name = "gpi1";
    	};
    	gpo1 {
    		gpio-hog;
    		gpios = <22 GPIO_ACTIVE_LOW>;
    		output-high;
    		line-names = "gpo1";
    	};
    };
    
    &gpio1 {
    	status = "okay";
    
    	name1 {
    		gpio-hog;
    		gpios = <32 GPIO_ACTIVE_LOW>;
    		output-high;
    		line-name = "name1";
    	};
    
    	name2 {
    		gpio-hog;
    		gpios = <33 GPIO_ACTIVE_LOW>;
    		input;
    		line-name = "name2";
    	};
    };

  • Some add'l info.

    If I look at /sys/firmware/devicetree, I see the dts nodes for "name1" and "name2", but they are not at the offsets I'd expect to see.

    ./firmware/devicetree/base/ocp/interconnect@44c00000/segment@200000/target-module@7000/gpio@0/gpo0/gpios
    ./firmware/devicetree/base/ocp/interconnect@44c00000/segment@200000/target-module@7000/gpio@0/gpo0/gpio-hog
    ./firmware/devicetree/base/ocp/interconnect@44c00000/segment@200000/target-module@7000/gpio@0/gpi0/gpios
    ./firmware/devicetree/base/ocp/interconnect@44c00000/segment@200000/target-module@7000/gpio@0/gpi0/gpio-hog
    ./firmware/devicetree/base/ocp/interconnect@44c00000/segment@200000/target-module@7000/gpio@0/gpi1/gpios
    ./firmware/devicetree/base/ocp/interconnect@44c00000/segment@200000/target-module@7000/gpio@0/gpi1/gpio-hog
    ./firmware/devicetree/base/ocp/interconnect@44c00000/segment@200000/target-module@7000/gpio@0/gpo1/gpios
    ./firmware/devicetree/base/ocp/interconnect@44c00000/segment@200000/target-module@7000/gpio@0/gpo1/gpio-hog
    
    ./firmware/devicetree/base/ocp/interconnect@44c00000/segment@200000/target-module@7000/gpio@0/name1/gpios
    ./firmware/devicetree/base/ocp/interconnect@44c00000/segment@200000/target-module@7000/gpio@0/name1/gpio-hog
    ./firmware/devicetree/base/ocp/interconnect@44c00000/segment@200000/target-module@7000/gpio@0/name2/gpios
    ./firmware/devicetree/base/ocp/interconnect@44c00000/segment@200000/target-module@7000/gpio@0/name2/gpio-hog

    I would have thought the offsets for "name1" and "name2" in the gpio1 node would be @4c000 as defined in am33xx-l4.dtsi

    		target-module@4c000 {			/* 0x4804c000, ap 32 36.0 */
    			compatible = "ti,sysc-omap2", "ti,sysc";
    			reg = <0x4c000 0x4>,
    			      <0x4c010 0x4>,
    			      <0x4c114 0x4>;
    			reg-names = "rev", "sysc", "syss";
    			ti,sysc-mask = <(SYSC_OMAP2_ENAWAKEUP |
    					 SYSC_OMAP2_SOFTRESET |
    					 SYSC_OMAP2_AUTOIDLE)>;
    			ti,sysc-sidle = <SYSC_IDLE_FORCE>,
    					<SYSC_IDLE_NO>,
    					<SYSC_IDLE_SMART>,
    					<SYSC_IDLE_SMART_WKUP>;
    			ti,syss-mask = <1>;
    			/* Domains (P, C): per_pwrdm, l4ls_clkdm */
    			clocks = <&l4ls_clkctrl AM3_L4LS_GPIO2_CLKCTRL 0>,
    				 <&l4ls_clkctrl AM3_L4LS_GPIO2_CLKCTRL 18>;
    			clock-names = "fck", "dbclk";
    			#address-cells = <1>;
    			#size-cells = <1>;
    			ranges = <0x0 0x4c000 0x1000>;
    
    			gpio1: gpio@0 {
    				compatible = "ti,omap4-gpio";
    				gpio-ranges =   <&am33xx_pinmux  0  0  8>,
    						<&am33xx_pinmux  8 90  4>,
    						<&am33xx_pinmux 12 12 16>,
    						<&am33xx_pinmux 28 30  4>;
    				gpio-controller;
    				#gpio-cells = <2>;
    				interrupt-controller;
    				#interrupt-cells = <2>;
    				reg = <0x0 0x1000>;
    				interrupts = <98>;
    			};
    		};

    Also, I decompiled the DTB to DTS to ensure "name1" and "name2" are in the gpio at offset @4c000

    				target-module@4c000 {
    					compatible = "ti,sysc-omap2\0ti,sysc";
    					reg = <0x4c000 0x04 0x4c010 0x04 0x4c114 0x04>;
    					reg-names = "rev\0sysc\0syss";
    					ti,sysc-mask = <0x07>;
    					ti,sysc-sidle = <0x00 0x01 0x02 0x03>;
    					ti,syss-mask = <0x01>;
    					clocks = <0x2f 0x74 0x00 0x2f 0x74 0x12>;
    					clock-names = "fck\0dbclk";
    					#address-cells = <0x01>;
    					#size-cells = <0x01>;
    					ranges = <0x00 0x4c000 0x1000>;
    
    					gpio@0 {
    						compatible = "ti,omap4-gpio";
    						gpio-ranges = <0x20 0x00 0x00 0x08 0x20 0x08 0x5a 0x04 0x20 0x0c 0x0c 0x10 0x20 0x1c 0x1e 0x04>;
    						gpio-controller;
    						#gpio-cells = <0x02>;
    						interrupt-controller;
    						#interrupt-cells = <0x02>;
    						reg = <0x00 0x1000>;
    						interrupts = <0x62>;
    						status = "okay";
    
    						name1 {
    							gpio-hog;
    							gpios = <0x20 0x01>;
    							output-high;
    							line-name = "name1";
    						};
    
    						name2 {
    							gpio-hog;
    							gpios = <0x21 0x01>;
    							input;
    							line-name = "name2";
    						};
    

    Why wouldn't these be getting loaded into offset @4c000?

  • after a `make clean;make dtbs;make zImage`, I now have all of my gpios as defined in the devicetree