Assign custom GPIO pin to custom driver on NVIDIA AGX ORIN

Hi, I have Nvidia Orin AGX.
I want to use GPIO9 (32 pin on 40 pin expansion header, mapped to 356 GPIO on system-PBB.00) and GPIO17 (22 pin on 40 pin expansion header, mapped to 444 GPIO on system-PP.04) inside my custom I2C driver.
Device tree overlay should go something like this:

/dts-v1/;
/plugin/;

/ {
    fragment@0 {
        target-path = "/bus@0/i2c@c250000";  // I2C SW bus 7, or pins 3 and 5 on 40 pin connector
        __overlay__ {
            #address-cells = <1>;
            #size-cells = <0>;
            mysensorxbg@69 { 
                compatible = "mysensorxbg";
                reg = <0x69>; 
                // Interrupt pin, GPIO17 as low
                sensor,int-gpios = <0xf1 0x1BC 0x00>;   
                // Reset pin, GPIO9 as low
                sensor,resetn-gpios = <0xf1 0x164 0x00>;
                status = "okay";
            };
        };
    };
};

Where 0xf1 is phandle of gpio controller “2200000”.

After that I want to use this pin inside driver probe function like this:

  resetn_gpio = gpiod_get(&client->dev, "sensor,resetn", GPIOD_OUT_LOW);
  if (IS_ERR(resetn_gpio))
  {
      pr_err("%s: Failed to get RESETN GPIO pin from device tree!\n", __func__);
      return -EINVAL;
  }

But this fails with error mesage:

[   59.917908] mysensorxbg_probe triggered.
[   59.917956] mysensorxbg_probe: INT pin '-2081705472' successfully retrieved from device tree!
[   65.382240] mysensorxbg_remove triggered.


[   66.590710] mysensorxbg_probe triggered.
[   66.590736] mysensorxbg_probe: Failed to get INT GPIO pin from device tree!
[   66.590740] mysensorxbg: probe of 7-0069 failed with error -22

NOTE: Pins are unused when listed using “sudo /opt/nvidia/jetson-io/jetson-io.py”.

I am new to Orin device, so not sure if I am missing something.

Regards

Hi cveks,

Are you using the devkit or custom board for AGX Orin?
What’s the Jetpack version in use?

PP.04 is configured as TEGRA234_MAIN_GPIO(P, 4) in device tree source, which mapping to 0x74 so that you should configure it as following:

sensor,int-gpios = <0xf1 0x74 0x00>;   

Please refer to tegra234-gpio.h for details.

You said that 0xf1 is the phandle of GPIO controller (2200000), but PBB.00 belongs to AON-GPIO controller(c2f0000) so that you have to use the phandle of AON-GPIO controller instead of 0xf1 here.

Hi KevinFFF

I am using devkit. This is system information:

PRETTY_NAME=“Ubuntu 22.04.4 LTS”
NAME=“Ubuntu”
VERSION_ID=“22.04”
VERSION=“22.04.4 LTS (Jammy Jellyfish)”
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL=“https://www.ubuntu.com/”
SUPPORT_URL=“https://help.ubuntu.com/”
BUG_REPORT_URL=“Bugs : Ubuntu”
PRIVACY_POLICY_URL=“Data privacy | Ubuntu and Canonical Legal | Ubuntu”

Regarding pin PP.04 I saw here https://jetsonhacks.com/nvidia-jetson-agx-orin-gpio-header-pinout/ that it is 444 decimal value, also output of command is:

cveks@agxorin:~/gpio$ sudo cat /sys/kernel/debug/gpio | grep PP.04
gpio-444 (PP.04 )

says same, so I am confused now regarding 0x74 value. Ofcourse If iI check tegra234-gpio.h I can see:

#define TEGRA234_MAIN_GPIO(port, offset) \
        ((TEGRA234_MAIN_GPIO_PORT_##port * 8) + offset)

If I use define TEGRA234_MAIN_GPIO_PORT_P 14 + offset from device tree TEGRA234_MAIN_GPIO(P, 4) under gpio@2200000 it will be 0x74 or 116 in decimal.

Regarding PBB.00 (pin 32 on 40 pin header) I saw yesterday that it belongs to second gpiochip.
Anyways, I wrote this simple C program:

#include <stdio.h>
#include <gpiod.h>
#include <unistd.h>

#define GPIO_CHIP_NAME "/dev/gpiochip1" // GPIO chip device (c2f0000)
#define GPIO_LINE 8 //This is pin 32 on 40 pin header (PBB.00)

int main() {
    struct gpiod_chip *chip;
    struct gpiod_line *line;
    int ret;

    // Open the GPIO chip
    chip = gpiod_chip_open(GPIO_CHIP_NAME);
    if (!chip) {
        perror("Failed to open GPIO chip");
        return 1;
    }

    // Get the GPIO line
    line = gpiod_chip_get_line(chip, GPIO_LINE);
    if (!line) {
        perror("Failed to get GPIO line");
        gpiod_chip_close(chip);
        return 1;
    }

    // Request the GPIO line as an output
    ret = gpiod_line_request_output(line, "gpio_control", 0);
    if (ret < 0) {
        perror("Failed to request GPIO line as output");
        gpiod_chip_close(chip);
        return 1;
    }

    // Print line information
    unsigned int line_num = gpiod_line_offset(line);
    const char *line_name = gpiod_line_name(line);
    printf("Line information:\n");
    printf("Line number: %u\n", line_num);
    printf("Line name: %s\n", line_name ? line_name : "Unnamed");

    // Set the GPIO line value to low (0)
    ret = gpiod_line_set_value(line, 0);
    if (ret < 0) {
        perror("Failed to set GPIO line value to 0");
        gpiod_chip_close(chip);
        return 1;
    }

    // Read and print the state after setting to 0
    int value = gpiod_line_get_value(line);
    if (value >= 0) {
        printf("Line value after setting to 0: %d\n", value);
    } else {
        perror("Failed to read line value after setting to 0");
    }

    sleep(10);

    // Set the GPIO line value to high (1)
    ret = gpiod_line_set_value(line, 1);
    if (ret < 0) {
        perror("Failed to set GPIO line value to 1");
        gpiod_chip_close(chip);
        return 1;
    }

    // Read and print the state after setting to 1
    value = gpiod_line_get_value(line);
    if (value >= 0) {
        printf("Line value after setting to 1: %d\n", value);
    } else {
        perror("Failed to read line value after setting to 1");
    }

   sleep(10);

    // Release the GPIO line and close the chip
    gpiod_chip_close(chip);

    return 0;
}

Output of program is next:

Line information:
Line number: 8
Line name: PBB.00
Line value after setting to 0: 0
Line value after setting to 1: 1

gpioinfo output is next:

gpiochip1 - 32 lines:
        line   0:     "PAA.00"       unused   input  active-high 
        line   1:     "PAA.01"       unused   input  active-high 
        line   2:     "PAA.02"       unused   input  active-high 
        line   3:     "PAA.03"       unused   input  active-high 
        line   4:     "PAA.04"       unused   input  active-high 
        line   5:     "PAA.05"       unused   input  active-high 
        line   6:     "PAA.06"       unused   input  active-high 
        line   7:     "PAA.07"       unused   input  active-high 
        line   8:     "PBB.00" "gpio_control" output active-high [used]
        line   9:     "PBB.01"       unused   input  active-high 
        line  10:     "PBB.02"       unused   input  active-high 
        line  11:     "PBB.03"       unused  output  active-high 
        line  12:     "PCC.00"       unused   input  active-high 
        line  13:     "PCC.01"       unused   input  active-high 
        line  14:     "PCC.02"       unused   input  active-high 
        line  15:     "PCC.03"       unused   input  active-high 
        line  16:     "PCC.04"       unused  output  active-high 
        line  17:     "PCC.05"       unused   input  active-high 
        line  18:     "PCC.06"       unused   input  active-high 
        line  19:     "PCC.07"       unused   input  active-high 
        line  20:     "PDD.00"       unused   input  active-high 
        line  21:     "PDD.01"       unused   input  active-high 
        line  22:     "PDD.02"       unused   input  active-high 
        line  23:     "PEE.00"       unused   input  active-high 
        line  24:     "PEE.01"       unused   input  active-high 
        line  25:     "PEE.02"       unused   input  active-high 
        line  26:     "PEE.03"       unused   input  active-high 
        line  27:     "PEE.04"      "Power"   input   active-low [used]
        line  28:     "PEE.05"       unused   input  active-high 
        line  29:     "PEE.06"       unused   input  active-high 
        line  30:     "PEE.07"       unused   input  active-high 
        line  31:     "PGG.00"       unused   input  active-high 

I can see here that my program is controlling it, but the problem is that pin state does not change.
It is stuck to 3.3V when I connect multimeter to it, to pin 32 on 40 pin header. When code sets it to low state, voltage is still 3.3V.

Why is pin state not changing even tough software says it is?
Is this related to device tree configuration, because it is set to input pin:

	gpio@c2f0000 {
		gpio-init-names = "default";
		gpio-init-0 = <&gpio_aon_default>;

		gpio_aon_default: default {
			gpio-input = <
				TEGRA234_AON_GPIO(EE, 5)
				TEGRA234_AON_GPIO(EE, 6)
				TEGRA234_AON_GPIO(EE, 2)
				TEGRA234_AON_GPIO(EE, 4)
				TEGRA234_AON_GPIO(CC, 0)
				TEGRA234_AON_GPIO(CC, 1)
				TEGRA234_AON_GPIO(CC, 2)
				TEGRA234_AON_GPIO(CC, 3)
				TEGRA234_AON_GPIO(AA, 0)
				TEGRA234_AON_GPIO(AA, 1)
				TEGRA234_AON_GPIO(AA, 2)
				TEGRA234_AON_GPIO(AA, 3)
				TEGRA234_AON_GPIO(BB, 0)
				TEGRA234_AON_GPIO(BB, 1)
				>;
			gpio-output-low = <
				>;
			gpio-output-high = <
				TEGRA234_AON_GPIO(BB, 3)
				>;
		};
	};

Also PBB.00 is 324 using link from above, but if I calculate it using TEGRA234_AON_GPIO I will get:
1x8 + 0 = 8. So does this 8 represents number I should use for this pin in device tree like:

sensor,resetn-gpios = <0x10c 0x8 0x00>;

where 0x10c is phandle of c2f0000 controller?

you cannot change the value of a gpio pin which is configured as “Input”.
You need to configure its direction as “Output” so that you can successfully toggle the values between 0 and 1.

I am trying to find the steps to update pinmux configuration.
I found excel sheet “Orin_Jetson_Series_Pinmux_Config_Template_2.0.xlsm” that is used to generate new dtsi files, but how do I apply them to system?
There are no useful links for this…

For building DTBs/Kernel refer to below link:

To flash the unit refer to this link:

1 Like

Thank you, I will try it now.
Thanks for you patience because this is probably easy thing to do.

1 Like

When I was flashing Orin first time, I used next command:

sudo ./flash.sh jetson-agx-orin-devkit mmcblk0p1

This means flash script will use “jetson-agx-orin-devkit.conf” configuration file.

Picture from above states that once I generate pmux and gpio files, I should copy them to specified location then point to them inside new board conf file.

How do I add these new files to new board config file?

I tried to use “jetson-agx-orin-devkit.conf” to track things:
“jetson-agx-orin-devkit.conf” includes “p3737-0000-p3701-0000.conf.common” that includes “p3701.conf.common” that defines:

GPIOINT_CONFIG="tegra234-mb1-bct-gpioint-p3767-0000.dts";

But this is dts file not dtsi file, so I do not understand how to add my newly generated files, where I changed pins from input to output and verified changes inside them.

just update as shown below in .conf file:

As I described above, it is using .dts file instead of .dtsi file for GPIOINT_CONFIG.
This is part of p3701.conf.common content:

PINMUX_CONFIG="tegra234-mb1-bct-pinmux-p3701-0000-a04.dtsi";
PMIC_CONFIG="tegra234-mb1-bct-pmic-p3701-0000.dts";
PMC_CONFIG="tegra234-mb1-bct-padvoltage-p3701-0000-a04.dtsi";
DEVICEPROD_CONFIG="tegra234-mb1-bct-cprod-p3701-0000.dts";
PROD_CONFIG="tegra234-mb1-bct-prod-p3701-0000.dts";
BOOTROM_CONFIG="tegra234-mb1-bct-reset-p3701-0000.dts";
DEVICE_CONFIG="tegra234-mb1-bct-device-p3701-0000.dts";
UPHYLANE_CONFIG="tegra234-mb1-bct-uphylane-si.dtsi"
GPIOINT_CONFIG="tegra234-mb1-bct-gpioint-p3701-0000.dts";

So you are suggesting me just to remove tegra234-mb1-bct-gpioint-p3701-0000.dts and put gpio.dtsi file?

not sure. I havent done this relatedto gpio dts/dtsi files. Had tried only pinmux related dtsi file long back in older version jetpack 5.1.2.

you need to wait for some mods to reply here.

try to check other threads in the forum for similar case, you may find some hint..

So if I check tegra234-mb1-bct-pinmux-p3701-0000-a04.dtsi it includes tegra234-mb1-bct-gpio-p3701-0000-a04.dtsi file that contains GPIO definitions.

So I guess if I change tegra234-mb1-bct-pinmux-p3701-0000-a04.dtsi to pinmux.dtsi and also inside of pinmux.dtsi point to gpio.dtsi file that it will work.

yes only this change should be fine I suppose.
as per the steps provided in the previous link I shared.

this change not required i think

By defualt no, since excel automatically includes gpio.dtsi inside pmux.dtsi when it is generated. I just need to copy both files and it will work.

1 Like

copy files to the folders specified in the documentation below:

I will wait for someone to answer this in a correct way, meaning what is the procedure here and what files to change in ORIN AXG case, later how to include these changes to device.

Basically what are steps after generating pinmux and gpio .dtsi files.
Where to add them and what to do so they finish on board at the end.

Note: Current DTB on my board is kernel_tegra234-p3737-0000+p3701-0005-nv.dtb.
This means flash script used 0005 as board SKU.

So my question is how to adapt current config jetson-agx-orin-devkit.conf and it’s include files to it uses my GPIO and PINMUX .dtsi files, that I copied to specified locations?

One more question, is flash script applying .dtsi configuration to device when it flashes the device? Because description says only to add new files and adapt paths, no one mentions kernel rebuild?

Managed to resolve.
Steps:

  1. Using excel sheet generate new configuration
  2. Take gpio.dtsi and pinmux.dtsi files only
  3. Copy gpio.dtsi to Linux_for_Tegra/bootloader
  4. Copy pinmux.dtsi to Linux_for_Tegra/bootloader/generic/BCT
  5. Inside pinmux.dtsi change “./gpio.dtsi” to include “gpio.dtsi”
  6. Open Linux_for_Tegra/p3701.conf.common and change:
- PINMUX_CONFIG="tegra234-mb1-bct-pinmux-p3701-0000-a04.dtsi";
+ PINMUX_CONFIG="pinmux.dtsi";
  1. Save files, power off device and put it to flash mode
  2. Run sudo ./flash.sh jetson-agx-orin-devkit mmcblk0p1
  3. Output of flash command should have something like:
....
Board ID(3701) version(501) sku(0005) revision(F.0)
Preset RAMCODE is 3
Chip SKU(00:00:00:D0) ramcode(3) fuselevel(fuselevel_production) board_FAB(501)
Copy you_home_directory/Linux_for_Tegra/kernel/dtb/tegra234-p3737-0000+p3701-0005-nv.dtb to you_home_directory/Linux_for_Tegra/kernel/dtb/tegra234-p3737-0000+p3701-0005-nv.dtb.rec
copying bctfile(you_home_directory/Linux_for_Tegra/bootloader/generic/BCT/tegra234-p3701-0005-sdram-l4t.dts)... done.
copying minratchet_config(you_home_directory/Linux_for_Tegra/bootloader/generic/BCT/tegra234-mb1-bct-ratchet-p3701-0000.dts)... done.
copying device_config(you_home_directory/Linux_for_Tegra/bootloader/generic/BCT/tegra234-mb1-bct-device-p3701-0000.dts)... done.
copying misc_config(you_home_directory/Linux_for_Tegra/bootloader/generic/BCT/tegra234-mb1-bct-misc-p3701-0000.dts)... done.
copying pinmux_config(you_home_directory/Linux_for_Tegra/bootloader/generic/BCT/pinmux.dtsi)... done.
copying gpioint_config(you_home_directory/Linux_for_Tegra/bootloader/generic/BCT/tegra234-mb1-bct-gpioint-p3701-0000.dts)... done.
copying pmic_config(you_home_directory/Linux_for_Tegra/bootloader/generic/BCT/tegra234-mb1-bct-pmic-p3701-0005.dts)... done.
copying pmc_config(you_home_directory/Linux_for_Tegra/bootloader/generic/BCT/tegra234-mb1-bct-padvoltage-p3701-0000-a04.dtsi)... done.
copying deviceprod_config(you_home_directory/Linux_for_Tegra/bootloader/generic/BCT/tegra234-mb1-bct-cprod-p3701-0000.dts)... done.
copying prod_config(you_home_directory/Linux_for_Tegra/bootloader/generic/BCT/tegra234-mb1-bct-prod-p3701-0000.dts)... done.
copying scr_config(you_home_directory/Linux_for_Tegra/bootloader/generic/BCT/tegra234-mb2-bct-scr-p3701-0000.dts)... done.
copying wb0sdram(you_home_directory/Linux_for_Tegra/bootloader/generic/BCT/tegra234-p3701-0005-wb0sdram-l4t.dts)... done.
copying bootrom_config(you_home_directory/Linux_for_Tegra/bootloader/generic/BCT/tegra234-mb1-bct-reset-p3701-0000.dts)... done.
Existing uphylane_config(you_home_directory/Linux_for_Tegra/bootloader/tegra234-mb1-bct-uphylane-si.dtsi) reused.
copying dev_params(you_home_directory/Linux_for_Tegra/bootloader/generic/BCT/tegra234-br-bct-p3701-0000.dts)... done.
copying dev_params_b(you_home_directory/Linux_for_Tegra/bootloader/generic/BCT/tegra234-br-bct_b-p3701-0000.dts)... done.
copying mb2bct_cfg(you_home_directory/Linux_for_Tegra/bootloader/generic/BCT/tegra234-mb2-bct-misc-p3701-0000.dts)... done.
Existing pscfwfile(you_home_directory/Linux_for_Tegra/bootloader/pscfw_t234_prod.bin) reused.
Existing pscbl1file(you_home_directory/Linux_for_Tegra/bootloader/psc_bl1_t234_prod.bin) reused.
Existing mtsmcefile(you_home_directory/Linux_for_Tegra/bootloader/mce_flash_o10_cr_prod.bin) reused.
Existing tscfwfile(you_home_directory/Linux_for_Tegra/bootloader/tsec_t234.bin) reused.
Existing mb2applet(you_home_directory/Linux_for_Tegra/bootloader/applet_t234.bin) reused.
Existing bootloader(you_home_directory/Linux_for_Tegra/bootloader/mb2_t234.bin) reused.
copying initrd(you_home_directory/Linux_for_Tegra/bootloader/l4t_initrd.img)... done.
...

where pinmux.dtsi is applied to device.

After flashing I used above test C program to change pin state (Both PBB.00 and PP.04) and it worked fine.

2 Likes

Problem with device tree remains, meaning pulling them like described above.

[   59.917908] mysensorxbg_probe triggered.
[   59.917956] mysensorxbg_probe: INT pin '-2081705472' successfully retrieved from device tree!
[   65.382240] mysensorxbg_remove triggered.


[   66.590710] mysensorxbg_probe triggered.
[   66.590736] mysensorxbg_probe: Failed to get INT GPIO pin from device tree!
[   66.590740] mysensorxbg: probe of 7-0069 failed with error -22

Calculation of GPIO values:

#define TEGRA234_MAIN_GPIO_PORT_P 14
#define TEGRA234_MAIN_GPIO(port, offset) \
		((TEGRA234_MAIN_GPIO_PORT_##port * 8) + offset)

TEGRA234_MAIN_GPIO(P, 4) => 14*8 + 4 = 116 => 0x74

#define TEGRA234_AON_GPIO_PORT_BB 1
#define TEGRA234_AON_GPIO(port, offset) \
		((TEGRA234_AON_GPIO_PORT_##port * 8) + offset)

TEGRA234_AON_GPIO(BB, 0) => 1*8 + 0 = 8 => 0x8
/dts-v1/;
/plugin/;

/ {
    fragment@0 {
        target-path = "/bus@0/i2c@c250000";  // I2C SW bus 7, or pins 3 and 5 on 40 pin connector
        __overlay__ {
            #address-cells = <1>;
            #size-cells = <0>;
            mysensorxbg@69 {
                compatible = "mysensorxbg";
                reg = <0x69>;

                // Interrupt pin, GPIO17 (pin 22 on 40 pin header) as low (first GPIO controller)
                sensor,int-gpios = <0xf1 0x74 0x00>;

                // Reset pin, GPIO9 (pin 32 on 40 pin header) as low (second GPIO controller)
                sensor,resetn-gpios = <0x10c 0x8 0x00>;

                status = "okay";
            };
        };
    };
};

Same error is present, it can not get pins inside driver code.
I have to point out that device tree seems to be successfully applied:

cveks@agxorin:~$ ls -l /sys/firmware/devicetree/base/bus@0/i2c@c250000
total 0
-r--r--r-- 1 root root  4 Apr  2 10:02 '#address-cells'
-r--r--r-- 1 root root  8 Apr  2 10:02  assigned-clock-parents
-r--r--r-- 1 root root  8 Apr  2 10:02  assigned-clocks
-r--r--r-- 1 root root  4 Apr  2 10:02  clock-frequency
-r--r--r-- 1 root root 15 Apr  2 10:02  clock-names
-r--r--r-- 1 root root 16 Apr  2 10:02  clocks
-r--r--r-- 1 root root 20 Apr  2 10:02  compatible
-r--r--r-- 1 root root  0 Apr  2 10:02  dma-coherent
-r--r--r-- 1 root root  6 Apr  2 10:02  dma-names
-r--r--r-- 1 root root 16 Apr  2 10:02  dmas
-r--r--r-- 1 root root 12 Apr  2 10:02  interrupts
-r--r--r-- 1 root root  8 Apr  2 10:02  iommus
-r--r--r-- 1 root root  4 Apr  2 10:02  name
-r--r--r-- 1 root root  4 Apr  2 10:02  nvidia,hw-instance-id
-r--r--r-- 1 root root  4 Apr  2 10:02  phandle
drwxr-xr-x 7 root root  0 Apr  2 10:02  prod-settings
-r--r--r-- 1 root root 16 Apr  2 10:02  reg
-r--r--r-- 1 root root  4 Apr  2 10:02  reset-names
-r--r--r-- 1 root root  8 Apr  2 10:02  resets
-r--r--r-- 1 root root  4 Apr  2 10:02 '#size-cells'
-r--r--r-- 1 root root  5 Apr  2 10:02  status
drwxr-xr-x 2 root root  0 Apr  2 10:02  mysensorxbg@69

I do get these errors when compiling and appending device tree overlay:

sensorxbg.dts:15.17-49: Warning (gpios_property): /fragment@0/__overlay__/sensorxbg@69:sensor,int-gpios: cell 0 is not a phandle reference
sensorxbg.dts:15.17-49: Warning (gpios_property): /fragment@0/__overlay__/sensorxbg@69:sensor,int-gpios: Could not get phandle node for (cell 0)
sensorxbg.dts:18.17-52: Warning (gpios_property): /fragment@0/__overlay__/sensorxbg@69:sensor,resetn-gpios: cell 0 is not a phandle reference
sensorxbg.dts:18.17-52: Warning (gpios_property): /fragment@0/__overlay__/sensorxbg@69:sensor,resetn-gpios: Could not get phandle node for (cell 0)

You have to configure the pinmux before use.
(i.e. if you want to control it high/low, you have to configure it as Output/Drive 0 or Drive 1 in pinmux spreadsheet)

Yes, you should check the exact value from device tree.

Correct!

Those dtsi would be used during flash(you can see them in flash log).
Please note that pinmux/gpio dtsi are loaded in early boot(MB1) rather than kernel.

1 Like