1:配置管脚为SPI功能
在board-mx6q_sabresd.h的最后添加,复制被重定义
(以添加SPI2为例)
- <span style="font-size:18px;"> MX6Q_PAD_EIM_CS0__ECSPI2_SCLK,
- MX6Q_PAD_EIM_CS1__ECSPI2_MOSI,
- MX6Q_PAD_EIM_OE__ECSPI2_MISO,
- MX6Q_PAD_CSI0_DAT11__ECSPI2_SS0 ,
- </span>
之后再板级文件board-mx6q_sabresd.c中将有相关函数对管脚进行统一初始化。完成寄存器配置的工作。
- <span style="font-size:18px;"> mxc_iomux_v3_setup_multiple_pads(mx6q_sabresd_pads,
- ARRAY_SIZE(mx6q_sabresd_pads));
- mxc_iomux_v3_setup_multiple_pads(mx6q_sabresd_cstm_tq_pads,
- ARRAY_SIZE(mx6q_sabresd_cstm_tq_pads));</span>
2:在板级文件board-mx6q_sabresd.c中添加以下代码
将匹配到driver/spi/spidev.c文件中的驱动源码
2.1完成SPI master的注册
SPI2片选管脚宏定义:
- <span style="font-size:14px;">#define SABRESD_ECSPI2_CS0 IMX_GPIO_NR(5, 29)</span>
添加相关结构体
- <span style="font-size:14px;">static int mx6q_marsboard_spi1_cs[] = {
- SABRESD_ECSPI2_CS0,
- };
- </span>
- <span style="font-size:14px;">static const struct spi_imx_master mx6q_sabresd_spi2_data __initconst = {
- .chipselect = mx6q_marsboard_spi2_cs,
- .num_chipselect = ARRAY_SIZE(mx6q_marsboard_spi1_cs),
- };
- </span>
2.2在spi 总线上匹配spi2的驱动文件
mx6q平台有2路spi资源,0/1,其中的bus_num则为挂载驱动的总线选择。
- <span style="font-size:18px;"><span style="font-size:14px;">static struct mtd_partition imx6_sabrelite_spi_nor_partitions[] = {
- {
- .name = "bootloader",
- .offset = 0,
- .size = 0x00100000,
- },
- {
- .name = "kernel",
- .offset = MTDPART_OFS_APPEND,
- .size = MTDPART_SIZ_FULL,
- },
- };
- static struct flash_platform_data imx6_sabrelite__spi_flash_data = {
- .name = "spidev", / /匹配原则。
- .parts = imx6_sabrelite_spi_nor_partitions,
- .nr_parts = ARRAY_SIZE(imx6_sabrelite_spi_nor_partitions),
- .type = "sst25vf016b",
- };
- static struct spi_board_info imx6_sabrelite_spi_nor_device[] __initdata = {
- {
- .modalias = "spidev",
- .max_speed_hz = 20000000, /* max spi clock (SCK) speed in HZ */
- .bus_num = 1, //设备挂载第几号spi总线上
- .chip_select = 0,
- .platform_data = &imx6_sabrelite__spi_flash_data,
- },
- };
- spi_register_board_info(imx6_sabrelite_spi_nor_device,
- ARRAY_SIZE(imx6_sabrelite_spi_nor_device));
- imx6q_add_ecspi(0, &mx6q_sabrelite_spi2_data);
- </span>
- </span>
3:内核配置
查看spidev.c文件目录下的Kconfig以及Makefile得知内核驱动的添加方法
选择蓝色部分选项,将spidev.c文件添加到内核中。
4:查看开发板/sys/bus/spi/drivers/spidev目录
在/dev下生成设备文件/dev/spidev1.0
5:使用freescale官方的bsp包中的spi测试程序对接口进行测试
- <span style="font-size:12px;">/*
- * SPI testing utility (using spidev driver)
- *
- * Copyright (c) 2007 MontaVista Software, Inc.
- * Copyright (c) 2007 Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License.
- *
- * Cross-compile with cross-gcc -I/path/to/cross-kernel/include
- */
- #include <stdint.h>
- #include <unistd.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <getopt.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <linux/types.h>
- #include <linux/spi/spidev.h>
- #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
- static void pabort(const char *s)
- {
- perror(s);
- abort();
- }
- static const char *device = "/dev/spidev1.0";
- static uint8_t mode;
- static uint8_t bits = 8;
- static uint32_t speed = 500000;
- static uint16_t delay;
- static void transfer(int fd)
- {
- int ret;
- uint8_t tx[] = {
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD,
- 0xF0, 0x0D,
- };
- uint8_t rx[ARRAY_SIZE(tx)] = {0, };
- struct spi_ioc_transfer tr = {
- .tx_buf = (unsigned long)tx,
- .rx_buf = (unsigned long)rx,
- .len = ARRAY_SIZE(tx),
- .delay_usecs = delay,
- .speed_hz = speed,
- .bits_per_word = bits,
- };
- ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
- if (ret < 1)
- pabort("can't send spi message");
- for (ret = 0; ret < ARRAY_SIZE(tx); ret++) {
- if (!(ret % 6))
- puts("");
- printf("%.2X ", rx[ret]);
- }
- puts("");
- }
- int main(int argc, char *argv[])
- {
- int ret = 0;
- int fd;
- //parse_opts(argc, argv); /* for what ,unknow*/
- fd = open(device, O_RDWR);
- if (fd < 0)
- pabort("can't open device");
- /*
- * spi mode
- */
- ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
- if (ret == -1)
- pabort("can't set spi mode");
- ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
- if (ret == -1)
- pabort("can't get spi mode");
- /*
- * bits per word
- */
- ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
- if (ret == -1)
- pabort("can't set bits per word");
- ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
- if (ret == -1)
- pabort("can't get bits per word");
- /*
- * max speed hz
- */
- ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
- if (ret == -1)
- pabort("can't set max speed hz");
- ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
- if (ret == -1)
- pabort("can't get max speed hz");
- printf("spi mode: %d ", mode);
- printf("bits per word: %d ", bits);
- printf("max speed: %d Hz (%d KHz) ", speed, speed/1000);
- transfer(fd);
- close(fd);
- return ret;
- }
- </span>
执行应用程序,可以看到时序模式(spi 4种时序模式第0种),时钟频率等参数。
7 /* 8 * SPI testing utility (using spidev driver) 9 * 10 * Copyright (c) 2007 MontaVista Software, Inc. 11 * Copyright (c) 2007 Anton Vorontsov <avorontsov@ru.mvista.com> 12 * 13 * This program is free software; you can redistribute it and/or modify 14 * it under the terms of the GNU General Public License as published by 15 * the Free Software Foundation; either version 2 of the License. 16 * 17 * Cross-compile with cross-gcc -I/path/to/cross-kernel/include 18 */ 19 20 #include <stdint.h> 21 #include <unistd.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <getopt.h> 25 #include <fcntl.h> 26 #include <sys/ioctl.h> 27 #include <linux/types.h> 28 #include <linux/spi/spidev.h> 29 30 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 31 32 static void pabort(const char *s) 33 { 34 perror(s); 35 abort(); 36 } 37 38 static const char *device = "/dev/spidev1.0"; 39 static uint8_t mode; 40 static uint8_t bits = 8; 41 static uint32_t speed = 9000000; 42 static uint16_t delay=0; 43 44 static void transfer(int fd) 45 { 46 int ret; 47 uint8_t tx[] = { 48 0x11, 0x12, 0x18, 0x78, 0x24, 0xa2, 49 0x40, 0x00, 0x13, 0x00, 0x00, 0x95, 50 0x23, 0x56, 0x54, 0x34, 0x45, 0x65, 51 0x69, 0x78, 0x98, 0xFF, 0xFF, 0x36, 52 }; 53 uint8_t rx[ARRAY_SIZE(tx)] = {0, }; 54 struct spi_ioc_transfer tr = { 55 .tx_buf = (unsigned long)tx, 56 .rx_buf = (unsigned long)rx, 57 .len = ARRAY_SIZE(tx), 58 .delay_usecs = delay, 59 .speed_hz = speed, 60 .bits_per_word = bits, 61 .cs_change=1 62 }; 63 64 ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); 65 if (ret < 1) 66 pabort("can't send spi message"); 67 68 for (ret = 0; ret < ARRAY_SIZE(tx); ret++) { 69 if (!(ret % 6)) 70 puts(""); 71 printf("%.2X ", rx[ret]); 72 } 73 puts(""); 74 } 75 76 static void print_usage(const char *prog) 77 { 78 printf("Usage: %s [-DsbdlHOLC3] ", prog); 79 puts(" -D --device device to use (default /dev/spidev1.0) " 80 " -s --speed max speed (Hz) " 81 " -d --delay delay (usec) " 82 " -b --bpw bits per word " 83 " -l --loop loopback " 84 " -H --cpha clock phase " 85 " -O --cpol clock polarity " 86 " -L --lsb least significant bit first " 87 " -C --cs-high chip select active high " 88 " -3 --3wire SI/SO signals shared "); 89 exit(1); 90 } 91 92 static void parse_opts(int argc, char *argv[]) 93 { 94 while (1) { 95 static const struct option lopts[] = { 96 { "device", 1, 0, 'D' }, 97 { "speed", 1, 0, 's' }, 98 { "delay", 1, 0, 'd' }, 99 { "bpw", 1, 0, 'b' }, 100 { "loop", 0, 0, 'l' }, 101 { "cpha", 0, 0, 'H' }, 102 { "cpol", 0, 0, 'O' }, 103 { "lsb", 0, 0, 'L' }, 104 { "cs-high", 0, 0, 'C' }, 105 { "3wire", 0, 0, '3' }, 106 { "no-cs", 0, 0, 'N' }, 107 { "ready", 0, 0, 'R' }, 108 { NULL, 0, 0, 0 }, 109 }; 110 int c; 111 112 c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL); 113 114 if (c == -1) 115 break; 116 117 switch (c) { 118 case 'D': 119 device = optarg; 120 break; 121 case 's': 122 speed = atoi(optarg); 123 break; 124 case 'd': 125 delay = atoi(optarg); 126 break; 127 case 'b': 128 bits = atoi(optarg); 129 break; 130 case 'l': 131 mode |= SPI_LOOP; 132 break; 133 case 'H': 134 mode |= SPI_CPHA; 135 break; 136 case 'O': 137 mode |= SPI_CPOL; 138 break; 139 case 'L': 140 mode |= SPI_LSB_FIRST; 141 break; 142 case 'C': 143 mode |= SPI_CS_HIGH; 144 break; 145 case '3': 146 mode |= SPI_3WIRE; 147 break; 148 case 'N': 149 mode |= SPI_NO_CS; 150 break; 151 case 'R': 152 mode |= SPI_READY; 153 break; 154 default: 155 print_usage(argv[0]); 156 break; 157 } 158 } 159 } 160 161 int main(int argc, char *argv[]) 162 { 163 int ret = 0; 164 int fd; 165 166 parse_opts(argc, argv); 167 168 fd = open(device, O_RDWR); 169 if (fd < 0) 170 pabort("can't open device"); 171 172 /* 173 * spi mode 174 */ 175 ret = ioctl(fd, SPI_IOC_WR_MODE, &mode); 176 if (ret == -1) 177 pabort("can't set spi mode"); 178 179 ret = ioctl(fd, SPI_IOC_RD_MODE, &mode); 180 if (ret == -1) 181 pabort("can't get spi mode"); 182 183 /* 184 * bits per word 185 */ 186 ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); 187 if (ret == -1) 188 pabort("can't set bits per word"); 189 190 ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits); 191 if (ret == -1) 192 pabort("can't get bits per word"); 193 194 /* 195 * max speed hz 196 */ 197 ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); 198 if (ret == -1) 199 pabort("can't set max speed hz"); 200 201 ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed); 202 if (ret == -1) 203 pabort("can't get max speed hz"); 204 205 printf("spi mode: %d ", mode); 206 printf("bits per word: %d ", bits); 207 printf("max speed: %d Hz (%d KHz) ", speed, speed/1000); 208 209 transfer(fd); 210 211 close(fd); 212 213 return ret; 214 }