Enable SPI on Jetson TK1 (L4T R21.1)

I ensured that everything required to enable SPI is there but still I can’t see /dev/spi* device. cat /proc/devices doesn’t have SPI device.

Following things are enabled in kernel configuration ->

SPI device entry in devicetree file ->
spi@7000d400 {
compatible = “nvidia,tegra114-spi”;
reg = <0x0 0x7000d400 0x0 0x200>;
interrupts = <0x0 0x3b 0x4>;
nvidia,dma-request-selector = <0x7 0xf>;
nvidia,memory-clients = <0xe>;
#address-cells = <0x1>;
#size-cells = <0x0>;
clocks = <0xc 0x29>;
status = “okay”;
dmas = <0x7 0xf 0x7 0xf>;
dma-names = “rx”, “tx”;
spi-max-frequency = <0x17d7840>;

When I look for SPI related things after the bootup in command prompt, I can see following things.

ls /dev/ | grep spi doesn’t yield any result. Even I checked with grep -irin “spi” /etc/modprobe.d/, no SPI specific blacklist as such. Can you tell what I’m missing in here, why I’m unable to see /dev/spi* device.

1 Like

Hi Venkatesh,
Everything is correct but you are missing the spidev entry on the DTS file.

If you add the spidev with proper spi dt node with cs, then it will enable the /dev/spi…

DTS file change:

  •   spi@7000d600 {
  •           status = "okay";
  •            spi@0 {
  •                    compatible = "spidev";
  •                    reg = <0>;
  •                    spi-max-frequency = <25000000>;
  •                    /* spi-cpha;
  •                     * spi-cpol;
  •                     * spi-cs-high;
  •                     */  
  •            };  
  •   };

After adding the above sub-node on DTS file, I can see it as /dev/spidev1.0.

The node spi@7000d600 is aliased as spi1 and CS is 0 here so spidev1.0.

I’m not too familiar with dts files. What does spi@7000d600 mean? I’m trying to access SPI on the expansion header.


This is the hexadecimal physical address of the controller, listed in the technical reference manual.

I see 6 SPI controllers listed in the technical reference manual. How do I know which one to use?

I don’t know enough about SPI to answer that. What it usually involves is a lot of reading in the TRM to figure out which ones are capable of your goals…followed by looking at the Jetson schematic to figure out which of those are routed to pins you can access. If more than one controller can do the job and more than one has access routed to a connector it might just be a case of picking the one which is most convenient…which in turn might be one where by default it functions as you need without going through pinmux issues.

The one listed at 0x7000d600 is named “SPI 2B-2” in the TRM, so I’d start by researching that. Keep in mind that hardware listed in a device tree blob is generally initialized at boot time (this blob is just a database of hardware needing early initialization via a compiled DTS)…other controllers might still be available but may have simply been deferred for later configuration. By putting this controller in the DTB the driver or other configuration has a way to find the controller.

There is 5 spi controller located on different addresses:
SPI1: spi@0x7000d400
SPI2: spi@0x7000d600
SPI3: spi@0x7000d800
SPI4: spi@0x7000dA00
SPI5: spi@0x7000dC00

Based on schematic, you need to find out that your device is connected to which spi controller? Then you need to add detail on that spi node in your dts file as my post on 01/09/2015 05:44 AM

It is SPI1: spi@0x7000d400 in case of SPI on the expansion header (J3A1)

As per schematic: 602-7R375-0000-D00.Schematics.Rev.4.02.pdf, connector J3A1 are having SPI signals.

    These signals are belong to ULPI pins which is configured as SPI1 on BSP.

  2. The node name of SPI1 is spi@7000d400.

  3. To add SPI device,
    a. Enable the spi node status.
    b. Add the spi device node under this spi node. (suppose device is addeed on CS 0)
    Typical change:
    Add following on your top level DTS file.
    spi@7000d400 {
    status = “okay”;

                         spidev@0 {
                               compatible = "spidev";
                               reg = <0>;

This will expose /dev/spidev0.0

Thanks, I’ve posted a link to this discussion onto the Wiki (http://elinux.org/Jetson/GPIO#PWM_output) so future users can find it more easily.

FYI: I just posted a blog series that explains in detail how to use the touch screen SPI on the Jetson to send and receive data at 25 MHz. You can find it here:

This provides a lot of useful information. I added the link to the URL sticky thread.

Is it possible to have interrupts for the SPI? The original configuration specifies interrupts. What does it signify? Does it corresspond to any pin?

For SPI, I see this:

If you need an interrupt, you could use a GPIO for that (several go to header J3A1/J3A2).

The neurorobotictech is using Grinch. I want to use the default kernel. Where are all these modifications suppose to be done? I do not have any /usr/src/kernel folder. In the boot folder I have /tegra124-jetson_tk1-pm375-000-c00-00.dtb file. Shall I modify this? How do I change it to dts file

The kernel is downloadable and can be unpacked into “/usr/src/kernel”. See this page, look for “kernel source” (assumes L4T R21.4):

The bootloader dtb files are the compiled output of dts source files. These are in the kernel source tree, subdirectory “arch/arm/boot/dts”. There are places in the kernel source Documentation directory where “devicetree” is explained in further detail.

The /usr/src/kernel directory is the source for the Linux kernel. For L4T 21.4, the Kernel source is on the page https://developer.nvidia.com/platform-software-development under ‘Kernel Sources’. If you need to modify the kernel source , you will need to rebuild the kernel or module that you apply the changes.

The .dtb file is a ‘compiled’ version of the .dtsi file. Again, there is a specific .dtsi file for each L4T release. There is an excellent writeup on the subject at Neurorobotictech: http://neurorobotictech.com/Community/Blog/tabid/184/ID/13/Using-the-Jetson-TK1-SPI–Part-3-Configuring-SPI-in-the-device-tree.aspx

Unfortunately this is too large of a subject to address in a forum post, but if you have specific questions as you go along, feel free to ask.

So I used the kernel source and got the dts file. I modified it to use spidev0.0 but it did not show anything in /dev. But when I enabled spi@7000d600 It now shows as /dev/spidev1.0

spi@7000d600 {
compatible = “nvidia,tegra114-spi”;
reg = <0x7000d400 0x200>;
interrupts = <0x0 0x3b 0x4>;
nvidia,dma-request-selector = <0x7 0x10>;
nvidia,memory-clients = <0xe>;
#address-cells = <0x1>;
#size-cells = <0x0>;
status = “okay”;
spi-max-frequency = <0x17d7840>;

	spi0_1 {
		#address-cells = <0x1>;
		#size-cells = <0x0>;
		compatible = "spidev";
		reg = <0x1>;
		spi-max-frequency = <0x17d7840>;
		nvidia,cs-setup-clk-count = <0x1e>;
		nvidia,cs-hold-clk-count = <0x1e>;
		nvidia,rx-clk-tap-delay = <0x1f>;
		nvidia,tx-clk-tap-delay = <0x0>;

I can see spidev1.0 (spi@7000d600). What are the hardware pins on the header J3A1 which I can use to obtain the SPI signals? Also, how do you control the CS?

I’m kind of exploring this too, and I do not have a complete answer. Some information might help you though.

Take a look at kernel source:


Search for “spi”. These “spi” entries occur related to “function”, while the containing struct has a name which relates to the physical chip. Before going further, look at the schmatic, search for “j3a1”, e.g.:

On the schematic page listing J3A1, find “TS_SPI_CS_L” shown to connect to J3A1 pin 6. This is where one of the SPI interfaces connect to. Search for “TS_SPI_CS_L” in the schematic to find the physical pin on the tegra124 chip itself. You’ll find this connects to U3C1 ball grid array (I believe the tegra124 is the only ball grid array on the board). The function is listed as ULPI_STP.

Now go back to tegra124-jetson_tk1-pinmux-pm375-0000-c00-00.dtsi. Search (case insensitive) for ulpi_stp. You find this:

ulpi_stp_py3 {
        nvidia,pins = "ulpi_stp_py3";
        nvidia,function = "spi1";
        nvidia,pull = <TEGRA_PIN_PULL_NONE>;
        nvidia,tristate = <TEGRA_PIN_DISABLE>;
        nvidia,enable-input = <TEGRA_PIN_DISABLE>;

Note the “_py3” addition to the name “ulpi_stp”. This would be the marker of a specific controller or specific pin. In GPIO it is a bit more clear because because the TRM chapter on GPIO uses a naming convention which directly corresponds to a header file. A file which specifically uses this designation of ulpi_stp_py3 which is specific to the tegra124 chip:


The line in that file is:

#define TEGRA_PIN_ULPI_STP_PY3                  _GPIO(195)

Now one has to go back and find out what _GPIO(195) corresponds to. This in turn refers to naming defined in:

#define TEGRA_GPIO_PY3          195

The PY3 can be found in TRM under GPIO (chapter 8, mult-purpose I/O). There are multiple GPIO controllers, each controller has a repeating theme, and individual controller determines part of the PY3 designation, while specific GPIO pins of the controller determine the rest (certain bits of GPIO controller may set up the pin as SPI, referring to specific controller as something such as SPI2). Looking at the gpio-tegra.h defines, notice this pattern:

  • Everything starts with TEGRA_GPIO_P
  • These defines are grouped with 8 entries per starting with _PA0 through _PA7
  • There continues to be more groups with 8 entries each, in order.
  • There are listings from controllers A-Z and AA-FF (total of 32 controllers times 8 pins for each controller leaving a total of 256 GPIO pins).
  • Each group of 8 applies to a single GPIO controller, each controller has 8 GPIO. The numeric designation goes from 0 to 255. If you find a numeric designation for a GPIO pin, this numbering is your reference to a specific pin, e.g., "gpio143" in /sys should refer to GPIO_PR7, which in turn refers to TRM chapter 8.
  • Under /sys you may find a reference to a numeric GPIO...cross referencing to the listed TRM controller and pin has just been shown. Further information can be found because a reference to a GPIO pin in /sys is usually a symbolic link to another part of /sys. The symbolic link path is likely to show a controller physical address. Example: ``` ls -l /sys/class/gpio/gpio143 /sys/class/gpio/gpio143 -> ../../devices/platform/6000d000.gpio/gpio/gpio143/ ```

    This means the controller address for this pin is 0x6000d000.

Unfortunately, 0x7000d600 is not a GPIO controller, so the specific parts of TRM and GPIO I’m familiar with won’t give the information you need. The method of finding that information should be the same as finding GPIO pin information. However, the use of paths in /sys containing a controller physical address leads to clues, e.g.:

find /sys -name '*7000d600*

It’s much easier to find out such information when you have the actual hardware attached, as this leads to /sys updating.