Accessing SPI Devices in Linux Print

 

The i.MX 8M provides 3 ECSPI interfaces. Two of those, ECSPI1 and ECSPI2, are available on the i.MX 8M SOM connectors. The remaining ECSPI interface, ECSPI3, multiplexes with the i.MX 8M signals used for implementation of the on-module WiFi/BT module and is therefore unavailable.

The Linux kernel provides a device driver for the ECSPI controller of the i.MX 8M. Appropriate configuration options are enabled in the meta-emcraft/recipes-kernel/linux/linux-imx/imx8m-som.dts and meta-emcraft/recipes-kernel/linux/linux-imx/imx8m-som.kernel files, shipped as part of Emcraft i.MX 8M BSP. However, you would still have to perform some configuration of the Linux kernel in order to access specific SPI devices connected to the i.MX 8M in your embedded design.

Raw SPI Device Access

In this example, a M25P32 SPI Flash device will be connected to the SPI1 bus on the i.MX 8M.

The specific connection of the SPI Flash device to the P1 connector on the IMX8M-SOM-BSB board is as follows:

P1.14 GND
P1.17 3V3
P1.19 MOSI
P1.21 MISO
P1.23 SCLK
P1.24 SS0
P1.26 SS1 (alternate chip select)

Add an spidev node to the meta-emcraft/recipes-kernel/linux/linux-imx/imx8m-som.dts file as follows:

{ .... aliases { spi0 = &ecspi1; }; .... }; ..... &ecspi1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spi1>; status = "okay"; cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>, <&gpio3 2 GPIO_ACTIVE_LOW>; #address-cells = <1>; #size-cells = <0>; spidev: spidev@0 { compatible = "spidev"; status = "okay"; spi-max-frequency = <5000000>; reg = <0>; }; };

To configure the SPI interface to work in the DMA mode, the dmas and dma-names parameters must be added to the ecspi1 node as follows:

&ecspi1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spi1>; status = "okay"; cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>, <&gpio3 2 GPIO_ACTIVE_LOW>; #address-cells = <1>; #size-cells = <0>; dmas = <&sdma2 10 24 0>, <&sdma2 11 24 0>; dma-names = "rx", "tx"; ... };

Note that both chip select signals, the SS0 and the SS1, can be used for accessing the SPI Flash. In order to switch to using the SS1, re-connect the SPI Flash SS line to the P1.26 pin on the IMX8M-SOM-BSB, and change the reg property of the spidev node in the meta-emcraft/recipes-kernel/linux/linux-imx/imx8m-som.dts file as follows:

... spidev: spidev@0 { compatible = "spidev"; status = "okay"; spi-max-frequency = <5000000>; reg = <1>; }; ...

The SPI bus node format is described in detail in the linux/Documentation/devicetree/bindings/spi/spi-bus.txt file, so just a few notes:

  • The cs-gpios property is an array with the chip selects per device available on this bus. The compatible property provides a link to the client SPI device driver, which will be used by the kernel to service a specific SPI device. In the example above, the client SPI device driver for both devices is SPIDEV (compatible = "spidev";), which provides access to the SPI device from the user space using raw SPI transactions. This interface is frequently used in embedded applications to control SPI devices (such as, for instance, SPI sensors) directly from user space code. To enable the SPIDEV interface in the kernel, the rootfs project has the CONFIG_SPI_SPIDEV option enabled by default.
  • The reg property allows to specify the chip select used to access the device (as the index in the
    cs-gpios array).

Having updated the meta-emcraft/recipes-kernel/linux/linux-imx/imx8m-som.dts file as described above, rebuild the kernel, and boot Linux on the target. Observe the kernel messages about successful initialization of the SPI controller as the kernel boots up on the target:

[ 2.497589] spi_imx 30820000.ecspi: probed

The following device files will be available in this example:

/ # ls -1 /dev/spidev* /dev/spidev0.0

Now everything is ready to access the SPI devices from a user-space application using the SPIDEV interface. There is abundant documentation in the Internet on how to use SPIDEV in application code. The basics are described, for instance, in the following article: https://www.kernel.org/doc/Documentation/spi/spidev.

The below example commands use the flashrom tool for erasing and programming the SPI Flash via the SPIDEV interface:

  1. Generate a 4MB test file:
  2. root@imx8m-som:~# dd if=/dev/urandom of=/test.bin bs=1K count=4096 4096+0 records in 4096+0 records out 4194304 bytes (4.2 MB, 4.0 MiB) copied, 0.0728756 s, 57.6 MB/s

  3. Erase the Flash chip:
  4. root@imx8m-som:~# flashrom -p linux_spi:dev=/dev/spidev0.0 -c M25P32 -E flashrom p1.0-69-g3f7e341 on Linux 4.9.51 (aarch64) flashrom is free software, get the source code at https://flashrom.org Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns). Found Micron/Numonyx/ST flash chip "M25P32" (4096 kB, SPI) on linux_spi. Erasing and writing flash chip... Erase/write done.

  5. Write the test file into the Flash:
  6. root@imx8m-som:~# flashrom -p linux_spi:dev=/dev/spidev0.0 -n -w /test.bin flashrom p1.0-69-g3f7e341 on Linux 4.9.51 (aarch64) flashrom is free software, get the source code at https://flashrom.org Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns). Found Micron/Numonyx/ST flash chip "M25P32" (4096 kB, SPI) on linux_spi. Reading old flash chip contents... done. Erasing and writing flash chip... Erase/write done.

  7. Read the Flash and verify the contents:
  8. root@imx8m-som:~# flashrom -p linux_spi:dev=/dev/spidev0.0 -c M25P32 -r /test_out.bin flashrom p1.0-69-g3f7e341 on Linux 4.9.51 (aarch64) flashrom is free software, get the source code at https://flashrom.org Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns). Found Micron/Numonyx/ST flash chip "M25P32" (4096 kB, SPI) on linux_spi. Reading flash... done done. root@imx8m-som:~# md5sum /test.bin /test_out.bin c1847985900dccc458fa3122b63e3b27 /test.bin c1847985900dccc458fa3122b63e3b27 /test_out.bin