PWM in Tegra Jetson TK1 not giving any pulse.

Hello All,
I am facing a problem to use pwm in Tegra Jetson TK1. I have exported pwm0 in “/sys/class/pwm/pwmchip0” then i have change (i) period (ii) duty_cycle and (iii) enable.
But at pin49 on J3A2 it is not giving any pulses.
If anyone has answer for this kindly post.
I am using L4T 21.2 and my kernel version is “Linux tegra-ubuntu 3.10.40-ged4f697”.

My second question is How to change pin behavior with register value? I want to change default behavior of pin.
I have to change pinmuxing of pin at 49 to use PWM0 ?

I’m not very familiar how to do the pinmuxing. The older Grinch kernel had the PWM enabled and also the DTB changed to to enable the pin output.

But big ARM SOCs can also be more limited in what kind of PWM signals they can output compared to microcontrollers so you should probably check the TRM for PWM limits.

Thanks for reply kulve,
In my setup it is showing “pwm” directory in “/sys/class” I am not sure it means ‘enabled’ in my kernel…
And it is also showing status of pwm in “cat /sys/kernel/debug/pwm” like this-

platform/tegra-pwm, 4 PWM devices
pwm-0 (sysfs ): requested enabled
pwm-1 (pwm-backlight ): requested
pwm-2 ((null) ):
pwm-3 ((null) ):

I am new to this board so not able to figure it out. your help much appreciated…
Thanks in advance…

As far as I know, the PWM is not working on L4T 21.2 as noted at the end of the Grinch thread.

I’d assume that this applies to nvidia’s release (if it worked from nvidia, why wouldnt Santyago’s work?)

So, if you need to use the PWM, ‘downgrade’ to L4T 19.3


pwm0 is not available by default on rel21 on J3A2 pin 49
pwm1 is available on pin 50 of J3A1 and is being used for eDP display backlight
pwm2 is not available on by default on rel21 on J3A2 pin 55
pwm3 not available by default on rel21 on J3A2 pin 58

  1. For PWM0, PWM2 and PWM3 to work, make this change:
    diff --git a/arch/arm/boot/dts/tegra124-platforms/tegra124-jetson_tk1-gpio-pm375-0000-c00-00.dtsi b/arch/arm/boot/dts/tegra124-platforms/tegra124-jetson_tk1-gpio-pm375-0000-c00-00.dtsi
    index d8aa450…555522e 100644
    — a/arch/arm/boot/dts/tegra124-platforms/tegra124-jetson_tk1-gpio-pm375-0000-c00-00.dtsi
    +++ b/arch/arm/boot/dts/tegra124-platforms/tegra124-jetson_tk1-gpio-pm375-0000-c00-00.dtsi
    @@ -36,10 +36,7 @@
    TEGRA_GPIO(U, 0)
    TEGRA_GPIO(U, 1)
    TEGRA_GPIO(U, 2)
  •                           TEGRA_GPIO(U, 3)
                              TEGRA_GPIO(U, 4)
  •                           TEGRA_GPIO(U, 5)
  •                           TEGRA_GPIO(U, 6)
                              TEGRA_GPIO(N, 7)
                      gpio-output-low = <

diff --git a/arch/arm/boot/dts/tegra124-platforms/tegra124-jetson_tk1-pinmux-pm375-0000-c00-00.dtsi b/arch/arm/boot/dts/tegra124-platforms/tegra124-jetson_tk1-pinmux-pm375-0000-c00-00.dtsi
index 520937d…2f44479 100644
— a/arch/arm/boot/dts/tegra124-platforms/tegra124-jetson_tk1-pinmux-pm375-0000-c00-00.dtsi
+++ b/arch/arm/boot/dts/tegra124-platforms/tegra124-jetson_tk1-pinmux-pm375-0000-c00-00.dtsi
@@ -1015,10 +1015,10 @@

                    pu3 {
                            nvidia,pins = "pu3";
  •                           nvidia,function = "gmi";
  •                           nvidia,function = "pwm0";
                              nvidia,pull = <TEGRA_PIN_PULL_NONE>;
                              nvidia,tristate = <TEGRA_PIN_DISABLE>;
  •                           nvidia,enable-input = <TEGRA_PIN_ENABLE>;
  •                           nvidia,enable-input = <TEGRA_PIN_DISABLE>;
                      pu4 {

@@ -1031,18 +1031,18 @@

                    pu5 {
                            nvidia,pins = "pu5";
  •                           nvidia,function = "gmi";
  •                           nvidia,function = "pwm2";
                              nvidia,pull = <TEGRA_PIN_PULL_NONE>;
                              nvidia,tristate = <TEGRA_PIN_DISABLE>;
  •                           nvidia,enable-input = <TEGRA_PIN_ENABLE>;
  •                           nvidia,enable-input = <TEGRA_PIN_DISABLE>;
                      pu6 {
                              nvidia,pins = "pu6";
  •                           nvidia,function = "rsvd3";
  •                           nvidia,function = "pwm3";
                              nvidia,pull = <TEGRA_PIN_PULL_NONE>;
                              nvidia,tristate = <TEGRA_PIN_DISABLE>;
  •                           nvidia,enable-input = <TEGRA_PIN_ENABLE>;
  •                           nvidia,enable-input = <TEGRA_PIN_DISABLE>;
                      hdmi_int_pn7 {

2.PWM1 usage is kind of hardcoded in present code and thus as such user can not use this pwm on pin 50 of J3A1 for any other purpose.
But I believe we should remove the hardcoding when panel is not connected. I will push the below patch in rel21 branch to free up pwm1 if edp panel is not connected.
bbasu@bbasu:~/l4t_rel21/kernel$ git diff
diff --git a/arch/arm/mach-tegra/board-ardbeg-panel.c b/arch/arm/mach-tegra/board-ardbeg-panel.c
index c7da1e3…f954956 100644
— a/arch/arm/mach-tegra/board-ardbeg-panel.c
+++ b/arch/arm/mach-tegra/board-ardbeg-panel.c
@@ -765,7 +765,6 @@ static struct tegra_panel *ardbeg_panel_configure(struct board_info *board_out,

  •          panel = &dsi_p_wuxga_10_1; 

@@ -775,7 +774,7 @@ static struct tegra_panel *ardbeg_panel_configure(struct board_info *board_out,
return panel;

-static void ardbeg_panel_select(void)
+static struct tegra_panel *ardbeg_panel_select(void)
struct tegra_panel *panel = NULL;
struct board_info board;
@@ -828,6 +827,8 @@ static void ardbeg_panel_select(void)

  •  return panel; 


@@ -837,7 +838,7 @@ int __init ardbeg_panel_init(void)
struct resource __maybe_unused *res;
struct platform_device *phost1x = NULL;
struct board_info board_info;

  •  struct tegra_panel *panel = NULL; 
     struct device_node *dc1_node = NULL; 
     struct device_node *dc2_node = NULL; 

@@ -848,7 +849,7 @@ int __init ardbeg_panel_init(void)
find_dc_node(&dc1_node, &dc2_node);


  •  ardbeg_panel_select(); 
  •  panel = ardbeg_panel_select(); 


@@ -943,8 +944,8 @@ int __init ardbeg_panel_init(void)
tegra_fb2_start, tegra_fb2_size);


  •  if (!of_have_populated_dt() || !dc1_node || 
  •          !of_device_is_available(dc1_node)) { 
  •  if (panel && (!of_have_populated_dt() || !dc1_node || 
  •          !of_device_is_available(dc1_node))) { 
    = &phost1x->dev; 
             err = platform_device_register(&ardbeg_disp1_device); 
             if (err) { 

After applying this patch. User has to do the following to get pwm1 working
echo 57 > /sys/class/gpio/export
echo 57 > /sys/class/gpio/unexport

echo 1 > /sys/class/pwm/pwmchip0/export
echo > /sys/class/pwm/pwmchip0/pwm1/period
echo > /sys/class/pwm/pwmchip0/pwm1/duty_cycle
echo 1 > echo > /sys/class/pwm/pwmchip0/pwm1/enable

This will get PWM1 working


Thanks Bibek, I posted your info onto the Wiki at so others will find it more easily in the future.

Thanks bbasu, I will do this change.


I am trying to use pwm1 on pin 50.

root@tegra-ubuntu:/sys/devices/platform/tegra-pwm/pwm/pwmchip0# echo 1 > export
bash: echo: write error: Device or resource busy

I should apply Bibek patch but I have never applied a patch to the kernel. After some search I still do not know how to do it. How do I have to proceed? Copy that content into a .patch file and then…?

If I do “git diff” it returns:

Not a git repository
To compare two paths outside a working tree:
usage: git diff [--no-index] <path> <path>

After applying the patch in someway, I imagine I have to recompile the kernel and install again?

I am using L4T 21.3

Typically, start with a clean kernel source. Copy the patch to the top level of the source. Depending on how the patch was generated:

patch -p1 < patchfile.diff

If it succeeds, it’ll say so. The “-p1” could be something else, like “-p0”.

You still have to configure and compile just like any other kernel. If the patch applied only to a module driver, you could build and install just the module. Existing config can be found compressed in /proc/config.gz, except for the LOCALVERSION. R21.x uses u-boot, so installing a new kernel is easy, even if it isn’t just a module (you’d use the arch/arm/boot/zImage as the kernel).

Hi linuxdev,

Thank you for the help. I copied the content into a patchfile.diff file. Formating it by hand, the command “patch -p1 < patchfile.diff” worked until the first brace. I couldn’t fix the format to apply the batch, but I changed the lines of the code manually, I succesfully compiled the kernel and install it.

But still the next command is not working:

#echo 1 > /sys/class/pwm/pwmchip0/export
bash: echo: write error: Device or resource busy

Anyway I think I have just burn out the board touching accidentally the pin 25 (+12 V) and the pin 1 (+5V) testing the other pwm using a servo motor :( When I plug the board and turn on, sounds a very low electrical noise from the board but nothing else, is not turning on. It will take me some time to develop again with the Jetson. I suppose is imposible fix it?

Regards, Juan.

If there is an electrical noise I’d assume something fatal has happened. Accidentally touching the wrong thing with an inductive load (the servo) amplifies how dangerous it is to apply the wrong voltage to the wrong location.

I’m not sure what the export error means, but the various pins are often capable of more than one mode or function, where either some other function has control of the pin or a driver of the same function already has the pin. Without the Jetson functioning you can’t view other /sys files to check.

If someone is not able to apply the patch, you can do the change manually to the files mentioned and rebuild kernel. Change for PWM0,2,3 are minimal.
Files affected are

Lines starting with - has to be deleted. Lines starting with + has to be added.

Hi, I am using the Grinch 21.3.4 Kernel for L4T 21.3.4 and I don’t seem to have the .dtsi files that are mentioned by @bbasu.

Any ideas as to how I should proceed to enable PWM for the Grinch Kernel?

The .dts and related are in the kernel source subdirectory:


When compiled these “human readable” files become the “.dtb” binary variant needed in the rootfs/boot directory. So you would need to recompile from Grinch source.

Information on how to add the patch for PWM isn’t very clear. Do I have to get the source for Grinch kernel and make changes to the dtsi? If I do that how do I recompile the kernel then? I have never applied a kernel patch before. It would help a great deal if someone could make a video on how to do this so some of us people who have never patched a kernel before would get a better understanding of this.

That patch was from quite some time back, I’m not even sure if it referred to a Grinch kernel at all. In either case, you would always need the kernel source to apply patches to. Looks like if the patch is not outdated, it edits these two kernel files:

arch/arm/mach-tegra/board-ardbeg-panel.c b/arch/arm/mach-tegra/board-ardbeg-panel.c

Before going down that road though, I’d suggest waiting a short time to find out if this patch still has meaning. After that, compile is a standard Linux kernel compile, with some added install steps depending on which L4T version (because early versions used fastboot and newer versions use u-boot).

Anyone know if this patch is still needed?

Thanks for the help on this. I think this patch may still be needed because when I tried to use PWM without the patch I also got no pulse. I have since then made the changes to a fresh source of the kernel and compiled it but I am now confused on the process of updating the kernel on the board. There were a few websites that said to reflash the board with ./ -k 6 but that didn’t work for me it said flashing ardbeg failed. I also tried copying the zImage file from the compiled source and replacing it with the zImage in the /boot on the board and also installing the modules to /lib/modules but when I restarted the board nothing would appear on the screen. I feel that there may have been some in the compile process.

Much of the original published information on Jetson is now incorrect if it relates to boot loader. Originally, fastboot was the default boot loader, and this required the -k option, along with flash for kernel update. For quite some time now the default boot loader has been u-boot, which simply looks for zImage and related files in /boot, so -k is no longer used. It’s kind of hard to explain everything about kernels and patches, but here are some notes on patches and some specifics of kernel install on Jetson. This all assumes u-boot, which allows a kernel upgrade without flashing, and that kernel from R21.4 is the reference kernel.

The patch information is basically removing lines from files or adding lines…an edit is removing then adding the same line number. The first example applies to lines in kernel file:


The patch starts its reference to finding edits by naming line 36 as a reference point, along with saying before patch there are 10 lines in the patch area, but only 7 lines once patched:

@@ -36,10 +36,7 @@

If you go to line 36 in the actual file, and compare to the patch, lines without the “+” or “-” can be used as a reference to name surrounding lines which do NOT change. So at line 36 in the unpatched file:


The patch then says to remove these 3 lines which are slightly past the unchanged reference lines:


This completes one section of patching. GPIO pins which were set up to perform as GPIO function in firmware will no longer be set up this way once the firmware file (.dtb file in /boot) is updated. Note that this is built when building a kernel, but this does not require flash. This should free up GPIO to be used as PWM.

In the same directory as the other file shown for change is:


…this file changes boot time setup of assigned pin function (PINMUX). The starting line reference is 1015, but this does not match the R21.4 kernel, this file was changed at some point and line numbers will be off. It’s easy to track the block of code to be edited though. The blocks are well-defined structs with labels of pu3 through pu6. A line prefixed with a “-” is removed, and a line with a “+” is added. So edit the pu3 block to have “nvidia,function” changed from “gmi” to “pwm0”. Rinse and repeat with the rest of the pu# structs.

The final patch is for file:

arch/arm/mach-tegra/board-ardbeg-panel.c b/arch/arm/mach-tegra/board-ardbeg-panel.c

Change the lines in this file as per the same patch formula, removing “-” lines and adding “+” lines. This file has had many changes since the patch was compared to it, so line numbers are fairly far off. However, if you search for the unchanged reference line:

static struct tegra_panel *ardbeg_panel_configure(struct board_info

…you’ll be in the right struct, and can then search within the struct for:

panel = &dsi_p_wuxga_10_1;

…this line is shown with a “-” so remove it. Similar changes can be edited the same way.

FYI, if you have a patch file generated via a diff tool and if nothing has changed, this is all automated. Minor changes are figured out by the patch tool when code looks unchanged but line numbers are slightly altered.

Before building the kernel, make sure it is configured the same as the running kernel, and that “LOCALVERSION” is a modified version of the suffix of “uname -r”. This will make it easy to install the new kernel without overwriting anything for the old kernel, and tests can be done non-destructively. Since uname -r on R21.4 default is “3.10.40-gdacac96”, I would suggest LOCALVERSION be set to “-gdacac96_test”. Build the kernel, and copy these files to /boot with the suffix name added:

cp arch/arm/boot/zImage /boot/zImage-3.10.40-gdacac96_test
cp boot/dts/tegra124-jetson_tk1-pm375-000-c00-00.dtb /boot/tegra124-jetson_tk1-pm375-000-c00-00_3.10.40-gdacac96_test.dtb
cp arch/arm/boot/zImage /boot/zImage-3.10.40-gdacac96_test

From there you can copy the default boot entry in /boot/extlinux/extlinux.conf with edits in name and using the alternate zImage and alternate dtb file names. Make modules install would install to 3.10.40-gdacac96_test and leave the original modules directory alone. Serial console would let you test the new entry before making it a default. If you’ve been flashing, I’d recommend start with a clean R21.4 flash then do the edits.

I followed everything but now when I reboot the board it says running in low graphics mode. I looked at the X Server log file and it says:

[  11.876] (EE) Segmentation fault at address 0x44
Fatal server error:
[  11.876] (EE) Caught signal 11(Segmentation fault). Server aborting

Thanks for all the help.