1:配置管脚为SPI功能
在board-mx6q_sabresd.h的最后添加,复制被重定义
(以添加SPI2为例)
MX6Q_PAD_EIM_CS0__ECSPI2_SCLK, MX6Q_PAD_EIM_CS1__ECSPI2_MOSI, MX6Q_PAD_EIM_OE__ECSPI2_MISO, MX6Q_PAD_CSI0_DAT11__ECSPI2_SS0 ,
之后再板级文件board-mx6q_sabresd.c中将有相关函数对管脚进行统一初始化。完成寄存器配置的工作。
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));
2:在板级文件board-mx6q_sabresd.c中添加以下代码
将匹配到driver/spi/spidev.c文件中的驱动源码
2.1完成SPI master的注册
SPI2片选管脚宏定义:
#define SABRESD_ECSPI2_CS0 IMX_GPIO_NR(5, 29)
添加相关结构体static int mx6q_marsboard_spi1_cs[] = { SABRESD_ECSPI2_CS0, };
static const struct spi_imx_master mx6q_sabresd_spi2_data __initconst = { .chipselect = mx6q_marsboard_spi2_cs, .num_chipselect = ARRAY_SIZE(mx6q_marsboard_spi1_cs), };
2.2在spi 总线上匹配spi2的驱动文件
mx6q平台有2路spi资源,0/1,其中的bus_num则为挂载驱动的总线选择。
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);
3:内核配置
查看spidev.c文件目录下的Kconfig以及Makefile得知内核驱动的添加方法
选择蓝色部分选项,将spidev.c文件添加到内核中。
4:查看开发板/sys/bus/spi/drivers/spidev目录
在/dev下生成设备文件/dev/spidev1.0
5:使用freescale官方的bsp包中的spi测试程序对接口进行测试
/* * 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\n", mode); printf("bits per word: %d\n", bits); printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); transfer(fd); close(fd); return ret; }
执行应用程序,可以看到时序模式(spi 4种时序模式第0种),时钟频率等参数。