6. SPI Operation Guide

This documentDescriptionin CV184x on the platformUse SPI Bus Read/writeOperation、Loopback TestwithandKernel space/User space ofFlow。

PlatformDescription :CV184x onof SPI Controller Support (Master)Mode,notSupportConfigurationisfrom (Slave)Mode。 Platform is SPI Busof Device 、 Flash/ etc.fromDevice, isfromDevice Through SPI Access。 Platform SPI Support 46.8MHz,Device TreeandDriverin spi-max-frequency canConfiguration 46800000(Hz), Valuecan ornotSupport。

6.1. Preparation

Use SPI The following conditions must be met first:

  • Use of SDK BuildafterkernelImage(DefaultalreadyInclude SPI RelatedDriver)。

6.1.1. EnableKernel SPI and DMA Configuration

Steps is :inBoard-levelKernel Configurationin SPI and DMA RelatedOption;inDevice Treeinis SPI1 DMA;IfneedUse DMA Channel , inBoard-level DTS NodeunderConfiguration sysdma_remap。Pathinof”Board Name”PleaseReplaceisActualUseofBoard-levelDirectory Name(If cv1842hp_wevb_0014a_spinor), with SDK is 。

(1)Kerneland DMA RelatedConfiguration

inBoard-levelKernel ConfigurationFileinEnsurefollowingOptionalready 。Configuration FilePathusually build/boards/cv184x/Board Name/linux/Board Name_defconfig

CONFIG_DMADEVICES=y
CONFIG_DW_DMAC_CVITEK=y
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_SPIDEV=y
CONFIG_SPI_DESIGNWARE=y
CONFIG_SPI_DW_DMA=y
CONFIG_SPI_DW_MMIO=y

IfnotNeed to DMA (for example 、 or not DMA),canwill CONFIG_SPI_DW_DMA , SPI Controller to PIO(Interrupt/ )Mode:

CONFIG_DMADEVICES=y
CONFIG_DW_DMAC_CVITEK=y
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_SPIDEV=y
CONFIG_SPI_DESIGNWARE=y
# CONFIG_SPI_DW_DMA is not set
CONFIG_SPI_DW_MMIO=y

needinDevice Treeinwill SPI Nodeof #if 1 is #if 0,Disable DMA Attribute( under (2)inofExample)。ModifyafterRebuildKernelandDevice TreeandBurning can。

(2)inDevice Treeinis SPI1 DMA

inBoard-level DTS or Includeof DTSI in, to SPI1 Node(If spi1@04190000),will inof #if Build is 1dmasdma-namescapability etc. DMA RelatedAttribute Build Device Tree,from SPI1 of DMA Function。If #if is 0 or Definition , SPI1 Use PIO Mode。

spi1: spi1@04190000 {
   compatible = "snps,dw-apb-ssi";
   reg = <0x0 0x04190000 0x0 0x10000>;
   clocks = <&clk CV184X_CLK_APB_SPI1>;
   #address-cells = <1>;
   #size-cells = <0>;
   #if 1
   dmas = <&dmac 2 1 1
          &dmac 3 1 1>;
   dma-names = "rx", "tx";
   capability = "txrx";
   #endif
   status = "okay";
   num-cs = <1>;
   spidev@0 {
      compatible = "rohm,dh2228fv";
      spi-max-frequency = <1000000>;   /*  Support 46.8MHz,can is 46800000 */
      reg = <0>;
   };
};

spi-max-frequency Unitis Hz, Platform SPI IP Support 46.8MHz,Do notConfiguration 46800000。

(3)DMA Channel

IfBoard-levelNeed to DMA Channeland ofCorrespondence,caninBoard-level DTS of Node / underAddor and sysdma_remap Node。Board-level DTS Pathusually build/boards/cv184x/Board Name/dts_arm/Board Name.dts 。under in CVI_SPI1_RXCVI_SPI1_TX and SPI1 Devicein the nodeof DMA Channel 2 and 3 , Channel Actualneed Configuration。

/ {
   sysdma_remap {
      ch-remap = <CVI_I2S0_RX CVI_I2S2_TX CVI_SPI1_RX CVI_SPI1_TX
                  CVI_SPI_NOR_RX CVI_SPI_NOR_TX CVI_I2S2_RX CVI_I2S3_TX>;
   };
};

6.1.2. Enable SPI1 in the Device Tree

inBoard-level DTS inwill SPI1 set the node to status = "okay", notUseof SPI set the node to status = "disabled"

6.1.3. SPI1 Pin Switching

Description :following”need PinFunction” is SPI1 of ( to MUX to Function)。 SPI Controlleror of Pinmux Operate according to the actual board schematic and pin definitions,can need ornot ,with pinout is 。

Steps 1. will PAD_MIPIRX3P MUX_SPI1_MOSI

cvi_pinmux -w PAD_MIPIRX3P/MUX_SPI1_MOSI

Steps 2. will MUX_SPI1_MOSI SPI1_SDO

cvi_pinmux -w MUX_SPI1_MOSI/SPI1_SDO

Steps 3. MISO Pin

Method ( to MUX_SPI1_MISO, to SPI1_SDI , withBoard-levelPinDefinitionis )。

cvi_pinmux -w PAD_MIPIRX3N/MUX_SPI1_MISO

cvi_pinmux -w MUX_SPI1_MISO/SPI1_SDI

6.2. Operation Procedure

  1. System SPI RelatedDriveralready Kernel,No need to LoadModule; after canUse SPI。

  2. SPI Read/write inSerial Portor SSH TerminalinRun SPI Read/writeCommands,orinKernel space/User space Program, in SPI ControlleronoffromDevice Read/write。

6.3. SPI Loopback Test

Loopback Test Verification SPI ControllerandPin :will SPI1 of MOSI and MISO , Dataafter , 。

Steps 1: SPI1 of MOSI and MISO Pin

Steps 2:Complete SPI1 Kernel ConfigurationandDevice TreeEnable

on 「Preparation」inof「EnableKernel SPI and DMA Configuration」and「Enable SPI1 in the Device Tree」 CompleteConfiguration,RebuildKernelandDevice TreeandBurning 。

Steps 3:Confirm spidev Node

ls /dev/spidev*
# ExampleOutput:/dev/spidev1.0,after CommandsinofDeviceNodeneedandOutput 

Steps 4:Execute cvi_pinmux

following「need PinFunction」 is SPI1 of ( to MUX to Function)。 SPI Controlleror of Pinmux Operate according to the actual board schematic and pin definitions,can need ornot ,with pinout is 。

Steps 4.1 will PAD_MIPIRX3P MUX_SPI1_MOSI

cvi_pinmux -w PAD_MIPIRX3P/MUX_SPI1_MOSI

Steps 4.2 will MUX_SPI1_MOSI SPI1_SDO

cvi_pinmux -w MUX_SPI1_MOSI/SPI1_SDO

Steps 4.3 MISO Pin

Method ( to MUX_SPI1_MISO, to SPI1_SDI, withBoard-levelPinDefinitionis )。

cvi_pinmux -w PAD_MIPIRX3N/MUX_SPI1_MISO

cvi_pinmux -w MUX_SPI1_MISO/SPI1_SDI

Steps 5:Buildand spidev_test

in SDK oflinux_5.10/tools/spi under the directoryExecute make,willGenerateof spidev_test Copyto 。

Steps 6:GenerateTestsData

dd if=/dev/urandom of=data.bin bs=2k count=1

Steps 7:ExecuteLoopback Test

./spidev_test -D /dev/spidev1.0 -s 10000000 -i data.bin -o data_out.bin
# -D isDeviceNode,-s isRate(Hz),-i isInputFile,-o isOutputFile

Steps 8: Data

diff data.bin data_out.bin
#  OutputIndicates File ,Loopback TestThrough

Loopback TestThroughafter,can Actual SPI fromDevice Read/writeOperation。

6.4. Operation Example

6.5. Kernel-Space SPI Read/Write Program Example

followingDescriptioninKernelDriverinThrough SPI SystemAccessfromDeviceof FlowandExampleCode。

FlowOverview:

  1. Use spi_busnum_to_master(bus_num) Get SPI Controller(spi_master),bus_num is Device inofBus 。

  2. Bus and to spi_device``(IfThrough ``bus_find_device_by_name etc.)。

  3. spi_transfer and spi_messagespi_sync or spi_async Execute or 。

Steps 1:Get SPI Controller

master = spi_busnum_to_master(bus_num);
/* bus_num:Device in SPI Bus ;master:spi_master   */

Steps 2:Get SPI fromDevice

snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), cs);
dev = bus_find_device_by_name(&spi_bus_type, NULL, str);
spi = to_spi_device(dev);
/* cs: ;spi:spi_device   */

Steps 3: spi_message

spi_message_init(&m);
spi_message_add_tail(&t, &m);
/* t:spi_transfer;m:spi_message */

Steps 4:

status = spi_sync(spi, &m);   /*   */
/* or status = spi_async(spi, &m);    */

CompleteExampleCode( Refer to, can RunofCompleteModule):

 1#include <linux/spi/spi.h>
 2
 3static unsigned int busnum;
 4module_param(busnum, uint, 0);
 5MODULE_PARM_DESC(busnum, "SPI bus number (default=0)");
 6
 7static unsigned int cs;
 8module_param(cs, uint, 0);
 9MODULE_PARM_DESC(cs, "SPI chip select (default=0)");
10
11extern struct bus_type spi_bus_type;
12static struct spi_master *master;
13static struct spi_device *spi_device;
14
15static int __init spidev_init(void)
16{
17    char *spi_name;
18    struct device *dev;
19
20    master = spi_busnum_to_master(busnum);
21    if (!master)
22        return -ENODEV;
23
24    spi_name = kzalloc(strlen(dev_name(&master->dev)) + 8, GFP_KERNEL);
25    if (!spi_name)
26        return -ENOMEM;
27
28    snprintf(spi_name, strlen(dev_name(&master->dev)) + 8,
29             "%s.%u", dev_name(&master->dev), cs);
30    dev = bus_find_device_by_name(&spi_bus_type, NULL, spi_name);
31    kfree(spi_name);
32    if (!dev)
33        return -ENODEV;
34
35    spi_device = to_spi_device(dev);
36    put_device(dev);
37    if (!spi_device)
38        return -ENODEV;
39
40    return 0;
41}
42
43static int spi_dev_write(void *buf, unsigned long len, int buswidth)
44{
45    struct spi_transfer t = {
46        .speed_hz = 2000000,
47        .tx_buf = buf,
48        .len = len,
49    };
50    struct spi_message m;
51
52    if (!spi_device)
53        return -ENODEV;
54
55    spi_device->mode = SPI_MODE_0;
56    t.bits_per_word = (buswidth == 16) ? 16 : 8;
57
58    spi_message_init(&m);
59    spi_message_add_tail(&t, &m);
60    return spi_sync(spi_device, &m);
61}
62
63static int spi_dev_read(unsigned char devaddr, unsigned char reg_addr,
64                        void *buf, size_t len)
65{
66    u8 txbuf[4] = { devaddr, 0, reg_addr, 0 };
67    struct spi_transfer t = {
68        .speed_hz = 2000000,
69        .tx_buf = txbuf,
70        .rx_buf = buf,
71        .len = len,
72    };
73    struct spi_message m;
74
75    if (!spi_device)
76        return -ENODEV;
77
78    spi_device->mode = SPI_MODE_0;
79    /* txbuf  and need fromDevice , isExample */
80    spi_message_init(&m);
81    spi_message_add_tail(&t, &m);
82    return spi_sync(spi_device, &m);
83}

6.6. User-Space SPI Read/Write Program Example

followingDescriptioninUser Through spidev DeviceNodeand ioctl SPI Read/writeofSteps。CompleteImplementationcanRefer to SDK in tools/spi/spidev_test.c。

Steps 1:EnableDeviceNode

static const char *device = "/dev/spidev1.0";
int fd = open(device, O_RDWR);
if (fd < 0)
    /* Error Handling */;

Note

DeviceNodeand SPI ControllerCorrespondence(withActual ls /dev/spidev* is ):

  • :SPI Controller 0 Defaultis /dev/spidev1.0,SPI Controller 1 is /dev/spidev2.0,with (Controller N spidev(N+1).0)。

  • IfDisable SPI Controller(IfDisableController 0), afterControllerNode before : SPI Controller 1 is /dev/spidev1.0,Controller 2 is /dev/spidev2.0,with 。

OperationandController 0 。

Steps 2:Settings SPI Mode

ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
if (ret == -1)
    /* Error Handling */;
ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);

mode Value Kernel File include/linux/spi/spi.h,for example:

#define SPI_CPHA  0x01  /*   */
#define SPI_CPOL  0x02  /*   */
#define SPI_MODE_0  (0|0)
#define SPI_MODE_1  (0|SPI_CPHA)
#define SPI_MODE_2  (SPI_CPOL|0)
#define SPI_MODE_3  (SPI_CPOL|SPI_CPHA)
/* Example:mode = SPI_MODE_3 | SPI_LSB_FIRST; */

Steps 3:Settings (bits per word)

ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
    /* Error Handling */;
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);

Steps 4:Settings Rate

ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
    /* Error Handling */;
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);

speed not 25MHz, withfromDevice is 。

Steps 5: / Data

ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
    /* Error Handling */;

tr is struct spi_ioc_transfer Address, Description of and 。

CompletecanRunExample

willon Steps ,and on File、struct spi_ioc_transfer of and , can tocan BuildRunofProgram(needKernelProvide /dev/spidev* and File):

 1#include <stdio.h>
 2#include <stdlib.h>
 3#include <string.h>
 4#include <errno.h>
 5#include <fcntl.h>
 6#include <unistd.h>
 7#include <sys/ioctl.h>
 8#include <linux/spi/spidev.h>
 9
10#define SPI_DEV   "/dev/spidev1.0"
11#define SPI_SPEED 10000000
12#define SPI_BITS  8
13
14int main(void)
15{
16    int fd;
17    int ret;
18    __u8 mode = SPI_MODE_0;
19    __u8 bits = SPI_BITS;
20    __u32 speed = SPI_SPEED;
21    __u8 tx_buf[4] = { 0x01, 0x02, 0x03, 0x04 };
22    __u8 rx_buf[4] = { 0 };
23
24    struct spi_ioc_transfer tr = {
25        .tx_buf = (unsigned long)tx_buf,
26        .rx_buf = (unsigned long)rx_buf,
27        .len = 4,
28        .speed_hz = speed,
29        .bits_per_word = bits,
30    };
31
32    fd = open(SPI_DEV, O_RDWR);
33    if (fd < 0) {
34        perror("open " SPI_DEV);
35        return EXIT_FAILURE;
36    }
37
38    ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
39    if (ret == -1) {
40        perror("SPI_IOC_WR_MODE");
41        close(fd);
42        return EXIT_FAILURE;
43    }
44
45    ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
46    if (ret == -1) {
47        perror("SPI_IOC_WR_BITS_PER_WORD");
48        close(fd);
49        return EXIT_FAILURE;
50    }
51
52    ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
53    if (ret == -1) {
54        perror("SPI_IOC_WR_MAX_SPEED_HZ");
55        close(fd);
56        return EXIT_FAILURE;
57    }
58
59    ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
60    if (ret < 1) {
61        perror("SPI_IOC_MESSAGE");
62        close(fd);
63        return EXIT_FAILURE;
64    }
65
66    printf("TX: %02x %02x %02x %02x\n", tx_buf[0], tx_buf[1], tx_buf[2], tx_buf[3]);
67    printf("RX: %02x %02x %02x %02x\n", rx_buf[0], rx_buf[1], rx_buf[2], rx_buf[3]);
68
69    close(fd);
70    return EXIT_SUCCESS;
71}

BuildandRun:arm-none-linux-uclibcgnueabihf-gcc -o spidev_demo spidev_demo.c -static,inon the target boardExecute ./spidev_demo。DeviceNodeand SPI ControllerCorrespondence on Note;Rate、Mode、 can fromDevice Modify。