[[PageOutline]] = Serial Peripheral Interface Bus (SPI) = The Serial Peripheral Interface bus is a synchronous serial communication interface specification used for short distance communication primary in embedded systems. The interface was originally developed by Motorola and can be used in a master or slave configuration. It is typically used as a 3-wire bus containing the following signals (other than power and ground and chip-selects): * SCLK * MISO * MOSI * SS# (Optional Slave Select) == SPI bus FAQ SPI can be a multi-slave bus if chip selects are used which are asserted by the host controller to enable one device at a time. The clock rate can differ between SPI slave devices as only the one with the asserted (active low) chip-select is active. The SPI bus on Newport is capable of clocking up to 50Mhz, although the MCP2515 can only clock up to 10Mhz. The clock rate dictates how long SPI transactions take in real-time, therefore you want to use the highest rate possible to minimize the amount of time a chip is owning the bus. The type of activity being performed with each slave device dictates how often and how long each device is owning the bus. The SPI subsystem has a SPI message queue which is handled as a FIFO. See the Elixir page linked below for more details. Your CPU frequency, co-processors frequency, and kernel tuning will dictate how often the SPI host is serviced in order to service the queue. Questions related to SPI host servicing and queuing should be sent to the linux-spi mailing list !linux-spi@vger.kernel.org References: * http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus * https://www.kernel.org/doc/html/latest/driver-api/spi.html * https://elixir.bootlin.com/linux/latest/source/Documentation/spi/spi-summary.rst [=#spitable] == On-Board SPI controllers The following Gateworks boards support on-board SPI controllers: ||= Family =||= Board =||= Connector =||= Notes =|| || Newport || GW640x || J8 || single CS^^^2^^^; spi_7_0 dts node; half-duplex^^^1^^^; modes 1^^^3^^^ || || || GW630x || J8 || single CS^^^2^^^; spi_7_0 dts node; half-duplex^^^1^^^; modes 1^^^3^^^ || || || GW620x || J5 || single CS^^^2^^^; spi_7_0 dts node; half-duplex^^^1^^^; modes 1^^^3^^^ || || || GW610x || J10 || single CS^^^2^^^; spi_7_0 dts node; half-duplex^^^1^^^; modes 1^^^3^^^ || || || || Ventana || GW54xx-E+ || J24 || single CS^^^2^^^; ecspi2 dts node || || || GW522x || J32 || single CS^^^2^^^; ecspi3 dts node || || || GW5910 || J11 || single CS^^^2^^^; ecspi3 dts node || || || || Laguna || GW2388 || J9 || || 1. Note that the Cavium ThunderX SPI controller in the CN80XX on the Newport Product family only supports half-duplex SPI transfers. In hardware the connections are full duplex MISO and MOSI lines are not shared, in software reads and writes need to be sent in separate calls, rather than simultaneously (full duplex). Drivers that use full-duplex transactions can be modified to support half-duplex (see [https://github.com/Gateworks/linux-newport/commit/cb270339619ccf2b50dfd3604a03626f85830453 'can:mcp251x: convert driver to half-duplex SPI'] as en example. 2. While only a single Chip Select (CS) is brought out to an external connector any of the DIO pins routed to ARM GPIO's can be used as additional chip-selects. For Ventana this is done via device-tree pinctrl and for Newport this must be done via a PINSEL GPIO (contact support@gateworks.com) 3. Note that the Cavium ThunderX SPI controller in the CN80XX only supports SPI mode 1 (which clock polarity (CPOL/CKP) is low, clock phase (CPHA) is high, and Clock edge (CKE/NCPHA) is low. See the below product family specific sections for pinout details. === Newport Gateworks Newport boards support 3.3V TTL SPI up to 50MHz clock to an off-board expansion connector with the following pinout: * 1 - MOSI * 2 - MISO * 3 - SCLK (Up to 50MHz clock supported) * 4 - SS0# (This is chip select 0) * 5 - 3.3V * GND Notes: 1. While only a single Chip Select (CS) is brought out to an external connector and of the DIO pins routed to ARM GPIO's can be used as additional chip-selects (contact support@gateworks.com for details) 2. Note that the Cavium ThunderX SPI controller in the CN80XX on the Newport Product family only supports half-duplex SPI transfers. Drivers that use full-duplex transactions can be modified to support half-duplex (see [https://github.com/Gateworks/linux-newport/commit/cb270339619ccf2b50dfd3604a03626f85830453 'can:mcp251x: convert driver to half-duplex SPI'] as en example. 3. Note that the Cavium ThunderX SPI controller in the CN80XX only supports SPI mode 1 (which clock polarity (CPOL/CKP) is low, clock phase (CPHA) is high, and Clock edge (CKE/NCPHA) is low. You need to add a device-tree node to the SPI controller to use a kernel driver. Note that you can also access SPI from userspace using {{{spidev}}} (see [#spidev below]) An example device-tree child node for a Spansion m25p128 compatible device (S25FL128) 128Mbit (16MB) SPI NOR FLASH device would be: {{{#!c &spi_7_0 { flash: m25p80@0 { compatible = "spansion,m25p128", "jedec,spi-nor"; spi-max-frequency = <30000000>; reg = <0>; #address-cells = <1>; #size-cells = <1>; m25p,fast-read; partition@0 { label = "data"; reg = <0x0 0x1000000>; }; }; }; }}} - Note that this node must appear within the SPI host controller node (&spi_7_0) along with any other devices on the SPI bus. - Note that the values shown in the above node are specific to the m25p128, and can vary greatly from the actual device you are using. Replace attribute values as necessary. - When searching for your device ID string or its controlling driver, searching via a Linux LXR site like the one at [https://lxr.missinglinkelectronics.com/linux missing link electronics] for your device name can be helpful. === Ventana Gateworks Ventana boards support 3.3V TTL SPI to an off-board expansion connector with the following pinout: * 1 - MOSI * 2 - MISO * 3 - SCLK * 4 - SS0# (This is chip select 0) * 5 - 3.3V * GND Notes: 1. While only a single Chip Select (CS) is brought out to an external connector and of the DIO pins routed to ARM GPIO's can be used as additional chip-selects. For Ventana this is done via device-tree pinctrl. You need to add add a device-tree node to the SPI controller to use a kernel driver. Note that you can also access SPI from userspace using {{{spidev}}} (see [#spidev below]) An example device-tree child node for a Spansion m25p128 compatible device (S25FL128) 128Mbit (16MB) SPI NOR FLASH device would be: {{{#!c &ecspi2 { flash: m25p80@0 { compatible = "spansion,m25p128", "jedec,spi-nor"; spi-max-frequency = <30000000>; reg = <0>; #address-cells = <1>; #size-cells = <1>; m25p,fast-read; partition@0 { label = "data"; reg = <0x0 0x1000000>; }; }; }; }}} - Note that this node must appear within the SPI host controller. For a list of device-tree nodes [#spitable see above]. - Note that the values shown in the above node are specific to the m25p128, and can vary greatly from the actual device you are using. Replace attribute values as necessary. - When searching for your device ID string or its controlling driver, searching via a Linux LXR site like the one at [https://lxr.missinglinkelectronics.com/linux missing link electronics] for your device name can be helpful. === Laguna Gateworks Laguna boards support 3.3V TTL SPI to an off-board expansion connector with the following pinout: * J9.2 - CS# * J9.4 - SCLK * J9.6 - MISO * J9.8 - MOSI * J9.10 - GND Notes: 1. The SPI bus is shared with the alternate flash device 2. For details on adding kernel devices to the Laguna kernel see [#laguna below] [[Image(spi2388.png,800px)]] The Laguna Linux kernels which does not use device-tree needs to register a {{{spi_board_info}}} struct with the kernel via {{{spi_register_board_info()}}}. To add a SPI device to Laguna you would add it to the spi_board_info array in {{{laguna.c}}}. Be sure to specify chip_select=1 to use CS1 as CS0 is used for the on-board SPI FLASH device: * [https://github.com/Gateworks/openwrt/blob/16.02/target/linux/cns3xxx/files/arch/arm/mach-cns3xxx/laguna.c#L188 spi_board_info struct] * [https://github.com/Gateworks/openwrt/blob/16.02/target/linux/cns3xxx/files/arch/arm/mach-cns3xxx/laguna.c#L1097 call to spi_register_board_info()] [=#usb] == USB SPI controllers == A SPI master can also be added via USB expansion. For example: * [http://trac.gateworks.com/wiki/expansion/gw16113 GW16113 firmware-flexible USB 2.0 FS expansion] * [http://www.commell.com.tw/product/Peripheral/PCI%20Express%20mini%20card/MPX-24794S.HTM Commell MPX-24794S USB 2.0 FS SPI/I2C/GPIO expansion] [=#spidev] == Linux spidev userspace API == SPI devices have a limited userspace API, supporting basic half-duplex read() and write() access to SPI slave devices referred to as {{{spidev}}}. Using ioctl() requests, full duplex transfers and device I/O configuration are also available. Some reasons you might want to use this programming interface include: * Prototyping in an environment that's not crash-prone; stray pointers in userspace won't normally bring down any Linux system. * Developing simple protocols used to talk to micro-controllers acting as SPI slaves, which you may need to change quite often. Of course there are drivers that can never be written in userspace, because they need to access kernel interfaces (such as IRQ handlers or other layers of the driver stack) that are not accessible to userspace. Userspace access to SPI devices is done through the /dev/spidev. device interface. In order to use this you must have spidev enabled in the kernel (CONFIG_SPI_SPIDEV) and have a spidev node defined under the SPI controller in the device-tree. In order to support {{{spidev}}} a spidev child node needs to be present in the device-tree under the SPI host controller. Examples: * Venice: - GW71xx (imx8mm-venice-gw71xx.dtsi), GW72xx (imx8mm-venice-gw72xx.dtsi), and GW73xx (imx8mm-venice-gw73xx.dtsi) all provide ecspi2 to an off-board connector with GPIO5_IO13 as a chip select: {{{#!c /* off-board header */ &ecspi2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spi2>; cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>; status = "okay"; /* * SPI_CS0 goes to the off-board connector * compatible must match a string from drivers/spi/spidev.c's compatible list */ spidev0: spidev0@0 { compatible = "rohm,dh2228fv"; reg = <0>; spi-max-frequency = <10000000>; }; }; }}} * Newport: - GW620x/GW630x/GW640x which has a single SPI controller with 2 chip selects, with CS0 going to an off-board connector and CS1 used for a CAN controller (loaded on GW6204/GW6304/GW6404 boards). Change dts/gw620x-linux.dtsi, dts/gw630x-linux.dtsi dts/gw640x-linux.dtsi to: {{{#!c &spi_7_0 { /* * SPI_CS0 goes to the off-board connector * compatible must match a string from drivers/spi/spidev.c's compatible list */ spidev0: spidev0@0 { compatible = "rohm,dh2228fv"; reg = <0>; spi-max-frequency = <10000000>; }; /* * SPI_CS1 goes to the Microchip MCP2515 CAN controller (GW6204/GW6304/GW6404) */ can0: can@1 { compatible = "microchip,mcp2515","linux,spidev"; reg = <1>; clocks = <&can20m>; oscillator-frequency = <20000000>; interrupt-parent = <&gpio_6_0>; interrupts = <5 0x8>; /* IRQ_TYPE_LEVEL_LOW */ spi-max-frequency = <10000000>; }; }; }}} - GW610x which has a single SPI controller with 2 chip selects, with CS0 going to an off-board connector. Change dts/gw610x-linux.dtsi to add the following at the end: {{{#!c &spi_7_0 { /* * SPI_CS0 goes to the off-board connector * compatible must match a string from drivers/spi/spidev.c's compatible list */ spidev0: spidev0@0 { compatible = "rohm,dh2228fv"; reg = <0>; spi-max-frequency = <10000000>; }; }; }}} * Ventana: - GW54xx (arch/arm/boot/dts/imx6qdl-gw52xx.dtsi) which brings out the ecspi2 host interface to an off-board connector with GPIO2_IO26 as a chip select: {{{#!c &ecspi2 { cs-gpios = <&gpio2 26 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ecspi2>; status = "okay"; spidev0: spidev@0 { compatible = "rohm,dh2228fv"; reg = <0>; spi-max-frequency = <60000000>; }; }; }}} - GW52xx (arch/arm/boot/dts/imx6qdl-gw53xx.dtsi) which brings out the ecspi3 host interface to an off-board connector with GPIO4_IO24 as a chip select: {{{#!c &ecspi3 { cs-gpios = <&gpio4 24 GPIO_ACTIVE_HIGH>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_ecspi3>; status = "okay"; spidev0: spidev@0 { compatible = "rohm,dh2228fv"; reg = <0>; spi-max-frequency = <60000000>; }; }; }}} In the above examples, adjust 'spi-max-frequency' according to the max frequency your slave device can support. For instructions on compiling and updating a device-tree see [wiki:linux/devicetree linux/devicetree] An application using {{{spidev}}} would include the {{{}}} header file. For more info see: * [https://www.kernel.org/doc/Documentation/spi/spidev Kernel Documentation]