Spi几种模式:
模式0: CPOL=0 CPHA=0
模式1: CPOL=0 CPHA=1
模式2: CPOL=1 CPHA=0
模式3: CPOL=1 CPHA=1

现在看看3模式 1.CLK空闲的时候为高电平 [CPOL = 1]
2.在第二个边沿采样 [CPHA = 1]

发送一字节 8bit数据 0xF
如下为示波器波形:
spi 协议硬件分析以及在linux上的实现分析-编程知识网

不好意思开个玩笑:

spi 协议硬件分析以及在linux上的实现分析-编程知识网

再来看看如果是传送 两个字节 16bit的数据呢,时序图是怎么样的, 此时我将CS也加上了[由于只有两个探头,故用两张图来描述]
图片一[ 黄色CH1 为 CS信号 蓝绿色CH2为 CLK信号]:
spi 协议硬件分析以及在linux上的实现分析-编程知识网

图片二[ 黄色CH1 为 CLK信号 蓝绿色CH2为 MOSI信号]:
spi 协议硬件分析以及在linux上的实现分析-编程知识网

可以看到此时16bit 的数据 较之于 8bit 的数据

相同点是:他们同一个CS周期内完成的, 紧跟在连续的8个时钟周期之后 开始下一个连续的8个时钟周期.

关于linux c 内核里有例程,相信很多博客都有提及 [ 里面有相关的API使用说明以及设备树, 设备驱动的配置说明 ]
路径: 内核根目录下的Documentation/spi目录中:

~/base/code/s905x-karaoke/s912_0907/common/Documentation/spi $ ls
00-INDEX   ep93xx_spi  pxa2xx  spidev_fdx.c   spi-lm70llp    spi-summary
butterfly  Makefile    spidev  spidev_test.c  spi-sc18is602

以下是spidev_test.c的源码:

 * 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.1";
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("");
}static void print_usage(const char *prog)
{printf("Usage: %s [-DsbdlHOLC3]\n", prog);puts("  -D --device   device to use (default /dev/spidev1.1)\n""  -s --speed    max speed (Hz)\n""  -d --delay    delay (usec)\n""  -b --bpw      bits per word \n""  -l --loop     loopback\n""  -H --cpha     clock phase\n""  -O --cpol     clock polarity\n""  -L --lsb      least significant bit first\n""  -C --cs-high  chip select active high\n""  -3 --3wire    SI/SO signals shared\n");exit(1);
}static void parse_opts(int argc, char *argv[])
{while (1) {static const struct option lopts[] = {{ "device",  1, 0, 'D' },{ "speed",   1, 0, 's' },{ "delay",   1, 0, 'd' },{ "bpw",     1, 0, 'b' },{ "loop",    0, 0, 'l' },{ "cpha",    0, 0, 'H' },{ "cpol",    0, 0, 'O' },{ "lsb",     0, 0, 'L' },{ "cs-high", 0, 0, 'C' },{ "3wire",   0, 0, '3' },{ "no-cs",   0, 0, 'N' },{ "ready",   0, 0, 'R' },{ NULL, 0, 0, 0 },};int c;c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL);if (c == -1)break;switch (c) {case 'D':device = optarg;break;case 's':speed = atoi(optarg);break;case 'd':delay = atoi(optarg);break;case 'b':bits = atoi(optarg);break;case 'l':mode |= SPI_LOOP;break;case 'H':mode |= SPI_CPHA;break;case 'O':mode |= SPI_CPOL;break;case 'L':mode |= SPI_LSB_FIRST;break;case 'C':mode |= SPI_CS_HIGH;break;case '3':mode |= SPI_3WIRE;break;case 'N':mode |= SPI_NO_CS;break;case 'R':mode |= SPI_READY;break;default:print_usage(argv[0]);break;}}
}int main(int argc, char *argv[])
{int ret = 0;int fd;parse_opts(argc, argv);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;
}                        

1.void parse_opts(int argc, char *argv[])
parse_opts用于处理 运行linux c 时带参解析 [ speed mode CPOL CPHA等等都可以通过这个设置]

2.一系列ioctl检测和设置数值
读写检测 SPI_IOC_WR_MODE SPI_IOC_RD_MODE
设置读写每字节的bit数 我设置的都是8bits/w SPI_IOC_WR_BITS_PER_WORD SPI_IOC_RD_BITS_PER_WORD
设置读写最大速率 SPI_IOC_WR_MAX_SPEED_HZ SPI_IOC_RD_MAX_SPEED_HZ

3.demo的最后通过一个简单的transfer传输了一个数组

构建一个spi_ioc_transfer:

    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,};

使用ioctl 通过 SPI_IOC_MESSAGE(1) 发送这个MESSAGE!

当然这只是用户空间的一个demo而已,
其中的ioctl相关操作当然是通过

我们打开的设备

fd = open(device, O_RDWR);

通过文件句柄进行的相关操作,包括读写, ioctl这些.

关于用户空间是如何调用到内核空间的方法, 详细请看LDD3

在设备驱动注册进内核的时候,相关的文件操作接口方法表 file_opration 等的地址其实是包含在特定驱动的数据结构中的.

下面分析下设备和驱动之间的关系,中间可以穿插spidev驱动的设计模式来说明:

第一步应该是设备的创建
通过热插拔,动态插入设备模块注册,设备树等将模块信息注册进内核了.

第二步是驱动程序的注册
[ 驱动程序可编入内核,也可动态插入模块]

[[
1.spidev中在driver模块插入的时候,采用老的静态方法指定设备号, 注册[register_chrdev]了字符驱动并且
2.通过class_create在sysfs中创建了一个spi目录
3.然后spi_register_driver注册了spi-dev的驱动
]]

第三步是设备与驱动的匹配,

首先是驱动中要将感兴趣的设备特征陈列出来,这就需要构建一个of_match_table
其中compatible是关键识别码

static const struct of_device_id spidev_dt_ids[] = {{ .compatible = "amlogic, spidev" },{},
};
MODULE_DEVICE_TABLE(of, spidev_dt_ids);

在特定驱动数据结构的driver成员中填充好of_match_table [*必须项]

static struct spi_driver spidev_spi_driver = {.driver = {.name =     "spidev",.owner =    THIS_MODULE,.of_match_table = of_match_ptr(spidev_dt_ids),},.probe =    spidev_probe,.remove =   spidev_remove,/* NOTE:  suspend/resume methods are not necessary here.* We don't do anything except pass the requests to/from                                                                                                  * the underlying controller.  The refrigerator handles* most issues; the controller driver handles the rest.*/
};

通过probe函数,
一般会先初始化driver相关的数据结构
然后在driver的数据结构中可以将包含device的相关信息导入进driver数据结构中
,此时亦可在文件系统中大展身手,通常情况下,匹配的过程中都会在sysfs中通过class_attribute创建DBG的节点
举个例子:

 #define SPI_READ_ATTR S_IRUGO#define SPI_WRITE_ATTR S_IWUGO//S_IRUGO = (S_IRUSR | S_IRGRP | S_IRUGO)static struct class_attribute hello_class_attrs[] = {__ATTR(test_store,  SPI_WRITE_ATTR, NULL,    store_test),__ATTR(test_show,  SPI_READ_ATTR, show_test, NULL),                                                                          __ATTR_NULL         };   然后在probe函数中:
struct hellodev_data  *hellodev_data;
hellodev_data = kzalloc(sizeof(*hellodev_data), GFP_KERNEL);
...
hellodev_data->cls.name = kzalloc(10, GFP_KERNEL);
sprintf((char *)hellodev_data->cls.name, "hello%d", (int)0);hellodev_data->cls.class_attrs = hello_class_attrs;
ret = class_register(&hellodev_data->cls);

此时在设计与设备信息相关的结构体的时候,也注意要将class放入

struct hellodev_data {        dev_t           devt;   spinlock_t      spi_lock;struct spi_device   *spi;struct list_head    device_entry;                                                                                                /* buffer is NULL unless this device is open (users > 0) */struct mutex        buf_lock;  unsigned        users;  u8          *buffer; struct class cls;    };   

[[
1.spidev在probe函数开始的地方也未能幸免,同样落入俗套
先初始化了一个类型为spidev_data 的数据结构,其中保存probe传过来的spi_device信息
2.为设备找到一个空闲的次设备号, 并且使用device_create创建设备节点
(1)minor = find_first_zero_bit(minors, N_SPI_MINORS);

(2)spidev->devt = MKDEV(SPIDEV_MAJOR, minor);
dev = device_create(spidev_class, &spi->dev, spidev->devt,
spidev, “spidev%d.%d”,
spi->master->bus_num, spi->chip_select);


/dev/spi0.0 /dev/spi0.1 …. /dev/spi1.0 /dev/spi1.1 …..

“/dev/spi%d.%d”, spi->master->bus_num, spi->chip_select
3.set_bit(minor, minors); 将当前已经用过的minor次设备号 告知minors
3.将描述该设备数据结构的spidev_data加入到链表中
4.将spidev_data 设置为设备的驱动数据.
]]

第四部是分析open函数:

static int spidev_open(struct inode *inode, struct file *filp)
{struct spidev_data  *spidev;   int         status = -ENXIO;   mutex_lock(&device_list_lock); list_for_each_entry(spidev, &device_list, device_entry) {if (spidev->devt == inode->i_rdev) {status = 0;       break;}}  if (status == 0) {if (!spidev->buffer) {spidev->buffer = kmalloc(bufsiz, GFP_KERNEL); if (!spidev->buffer) {         dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");status = -ENOMEM;              }                 }if (status == 0) {spidev->users++;filp->private_data = spidev;   nonseekable_open(inode, filp); }} elsepr_debug("spidev: nothing for minor %d\n", iminor(inode));mutex_unlock(&device_list_lock);return status;
}

open函数中参数列表是 inode 和 filp.
关于这两个参数:
inode 是节点, kdev_t i_rdev字段中保存了device的信息, 节点中保存了当用户空间操作设备文件, 所对应的底层处理, 底层处理包括以什么样的驱动处理 字符 块设备?
filp 是文件描述符 用户空间通过fp和inode相互联系 通过inode又可以找到对应的cdev 或者其它类型设备描述结构 通过其指定的驱动就可以对文件系统中的文件进行底层相应.

1.首先遍历device_list链表 通过成员spidev->devt  找到那个次设备号是inode->i_rdev 的 spidev_data类型数据的spidev节点.
2.分配spidev->buffer 定义的是4096个字节.
3.将spidev保存到filp->private_data中.
4.调用nonseekable_open(inode, filp); 通知内核该设备驱动不支持lseek操作.

当然在方法表中也已经声明成了no_llseek

 static const struct file_operations spidev_fops = {.owner =    THIS_MODULE,/* REVISIT switch to aio primitives, so that userspace* gets more complete API coverage.  It'll simplify things* too, except for the locking.*/.write =    spidev_write,.read =     spidev_read,.unlocked_ioctl = spidev_ioctl,.compat_ioctl = spidev_compat_ioctl, .open =     spidev_open,.release =  spidev_release,    .llseek =   no_llseek,  };   

使用数据区时,可以使用 lseek 来往上往下地定位数据。但像串口或键盘一类设备,使用的是数据流,所以定位这些设备没有意义;在这种情况下,不能简单地不声明 llseek 操作,因为默认方法是允许定位的。


在 open 方法中调用 nonseekable_open() 时,它会通知内核设备不支持 llseek,nonseekable_open() 函数的实现定义在 fs/open.c 中

关于nonseekable_open 具体可以参考这篇博文(http://blog.csdn.net/gongmin856/article/details/8273545)

第五部分是分析下ioctl
众所周知在linux 2.6 file_operation中旧的 ioctl就已经被干掉了 而取而代之的是 unlocked_ioctl

1.ioctl的常规检查
包括检查幻数 或者啊 根据cmd是读写操作而检查文件系统中该设备的可读写性.
(1)检查幻数

/* Check type and command number */if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)return -ENOTTY;  spidev = filp->private_data;   

(2)读写检查

 if (_IOC_DIR(cmd) & _IOC_READ)err = !access_ok(VERIFY_WRITE,(void __user *)arg, _IOC_SIZE(cmd));if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)err = !access_ok(VERIFY_READ,(void __user *)arg, _IOC_SIZE(cmd));if (err)return -EFAULT;

(3)取出设备相关的数据
很常规的操作, 拿到文件描述符存储的私有数据 filp->private_data
spidev = filp->private_data;
然后通过设备封装的方法拿出device相关的数据
spi = spi_dev_get(spidev->spi);

    /* guard against device removal before, or while,* we issue this ioctl.*/spidev = filp->private_data;spin_lock_irq(&spidev->spi_lock);spi = spi_dev_get(spidev->spi);spin_unlock_irq(&spidev->spi_lock);if (spi == NULL)return -ESHUTDOWN;

需要注意下这两个数据结构 spidev_data 和 spi_device
下面先把这两个数据结构的原型丢出来
接下来我还会把这个重要的头文件spi.h源码贴出来.

 struct spidev_data  *spidev;struct spi_device   *spi;

spi_device

  struct spi_device {struct device       dev;struct spi_master   *master;u32         max_speed_hz;u8          chip_select;u8          bits_per_word;u16         mode;int         irq;void            *controller_state;void            *controller_data;char            modalias[SPI_NAME_SIZE];int         cs_gpio;    /* chip select gpio */

spidev_data

struct spidev_data {                                                                                                                 
>>    dev_t           devt;
>>    spinlock_t      spi_lock;struct spi_device   *spi;
>>    struct list_head    device_entry;/* buffer is NULL unless this device is open (users > 0) */
>>    struct mutex        buf_lock;unsigned        users;
>>    u8          *buffer;};

spi_device 是probe 时内核传递过来的描述设备信息的数据结构,可以从数据结构中清晰看出他的意图
每一个设备模型都有的再熟悉不过的数据结构 struct device !
第二个是struct spi_master 看起来很陌生 因为它完完全全跟我们的设备驱动扯不上关系, 甚至是抽象的, 甚至像我们设备驱动从未谋面的亲生父母?
回头一想,如果接触过i2c系统的老表们, spi_master 是不是和i2c_adapter这些有异曲同工之妙呢?
如果是的话, 他们为何都这样设计呢?

答案就是 不管是i2c 还是spi 我们驱动编写人员都只是在编写他们的设备驱动而已
而该类协议i2c 抑或 spi 都是已经固定不变的协议了

所谓协议就是 玩家甲 与玩家乙 甲是中国人 乙是老美 
两个玩家联机玩游戏 他们虽然不是一个国家的人 但是他们都知道玩石头剪刀布
只能一次出一个 只能出石头 剪刀或者布

这就是协议
有了协议就可以避免很多沟通之间的误会与误解. 甲乙事先不需要沟通或者只需要简单沟通[如确认对方四肢健全 没有少手指 或者不是智障?这样真的好吗 问号脸]

所以spi_master 和i2c_adapter就做了这部分工作.
可以说他们是内核中的协议层

具体表现在设备驱动中的就是 当我们去实现某些接口时,比如file_operation中的读写操作
我们只需要给出要传输的数据, 然后设置好传输的模式,速率,每字节bit数等,将数据封装成 协议层给出的标准数据结构
然后以spi_transfer 与spi_message的成员与链表形式 将自己的封装数据spi_ioc_message发出去就行了.
至于协议层如何提取message,然后将message中的数据解析出来,再根据与设备信息相关的寄存器
将内存映射,进行setb操作等等, 都是协议层去做的事情.

我们只是做了驱动层的应用部分,其实不然,使用的大多是内核提供的数据结构, 调用的大部分是内核提供的接口.

所以驱动人员比起LINUX内核主线维护人员不知要轻松多少倍!!!!

(4)大case
在硕大无比的case中,包裹了很多内涵信息,现在举两个例子
<1> case SPI_IOC_RD_MAX_SPEED_HZ:

case SPI_IOC_RD_MAX_SPEED_HZ:retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg);break;

这里使用了__put_user这个接口, 自然而然就是直接从内核空间put 到用户空间的接口, 一系列调用之后将spi中保存的最大速度传递给用户空间地址的arg变量.
特别要注意的是 这个__user 修饰, 这应该是个内核的关键字, 表明arg是表示的用户空间地址.
<2> case SPI_IOC_WR_MAX_SPEED_HZ:

case SPI_IOC_WR_MAX_SPEED_HZ:retval = __get_user(tmp, (__u32 __user *)arg);if (retval == 0) {u32 save = spi->max_speed_hz;spi->max_speed_hz = tmp;retval = spi_setup(spi);if (retval < 0)spi->max_speed_hz = save;elsedev_dbg(&spi->dev, "%d Hz (max)\n", tmp);}break;

这个使用了__get_user和__put_user作用相反, 原理都一样.

同时注意:
在重新设置了spi通讯相关的参数之后, spi_setup了一次.这也是通用的master-slava设备模型所需要的.

(3)接下来是默认操作了

    default:/* segmented and/or full-duplex I/O request */if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))|| _IOC_DIR(cmd) != _IOC_WRITE) {retval = -ENOTTY;break;}tmp = _IOC_SIZE(cmd);if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) {retval = -EINVAL;break;}n_ioc = tmp / sizeof(struct spi_ioc_transfer);if (n_ioc == 0)break;/* copy into scratch area */ioc = kmalloc(tmp, GFP_KERNEL);if (!ioc) {retval = -ENOMEM;break;}if (__copy_from_user(ioc, (void __user *)arg, tmp)) {kfree(ioc);retval = -EFAULT;break;}/* translate to spi_message, execute */retval = spidev_message(spidev, ioc, n_ioc);kfree(ioc);break;}                  

记得我们是这样发送的:ioctl(fd, SPI_IOC_MESSAGE(1), &argv)
那么这里就是创建了一个spi_ioc_transfer

 tmp = _IOC_SIZE(cmd);if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) {retval = -EINVAL;break;}n_ioc = tmp / sizeof(struct spi_ioc_transfer);if (n_ioc == 0)break;

然后在内核分配空间,将参数列表拷贝到ioc中,

 /* copy into scratch area */ioc = kmalloc(tmp, GFP_KERNEL);if (!ioc) {retval = -ENOMEM;break;}if (__copy_from_user(ioc, (void __user *)arg, tmp)) {kfree(ioc);retval = -EFAULT;break;}

(5)最后launch发送message

     /* translate to spi_message, execute */retval = spidev_message(spidev, ioc, n_ioc); 

接下来就是分析spidev_message了,代码比前面的要稍微长一点点而已.

  static int spidev_message(struct spidev_data *spidev,struct spi_ioc_transfer *u_xfers, unsigned n_xfers){struct spi_message  msg;struct spi_transfer *k_xfers;struct spi_transfer *k_tmp;struct spi_ioc_transfer *u_tmp;unsigned        n, total;u8          *buf;int         status = -EFAULT;spi_message_init(&msg);k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL);if (k_xfers == NULL)return -ENOMEM;/* Construct spi_message, copying any tx data to bounce buffer.* We walk the array of user-provided transfers, using each one* to initialize a kernel version of the same transfer.*/ buf = spidev->buffer;total = 0;for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;n;n--, k_tmp++, u_tmp++) {k_tmp->len = u_tmp->len;total += k_tmp->len;if (total > bufsiz) {status = -EMSGSIZE;goto done;}if (u_tmp->rx_buf) {k_tmp->rx_buf = buf;if (!access_ok(VERIFY_WRITE, (u8 __user *)(uintptr_t) u_tmp->rx_buf,u_tmp->len))goto done;}if (u_tmp->tx_buf) {k_tmp->tx_buf = buf;if (copy_from_user(buf, (const u8 __user *)(uintptr_t) u_tmp->tx_buf,u_tmp->len))goto done;}buf += k_tmp->len;k_tmp->cs_change = !!u_tmp->cs_change;k_tmp->bits_per_word = u_tmp->bits_per_word;k_tmp->delay_usecs = u_tmp->delay_usecs;k_tmp->speed_hz = u_tmp->speed_hz;#ifdef VERBOSEdev_dbg(&spidev->spi->dev,"  xfer len %zd %s%s%s%dbits %u usec %uHz\n",u_tmp->len,u_tmp->rx_buf ? "rx " : "",u_tmp->tx_buf ? "tx " : "",u_tmp->cs_change ? "cs " : "",u_tmp->bits_per_word ? : spidev->spi->bits_per_word,u_tmp->delay_usecs, u_tmp->speed_hz ? : spidev->spi->max_speed_hz);#endif  spi_message_add_tail(k_tmp, &msg);}status = spidev_sync(spidev, &msg);if (status < 0)goto done;/* copy any rx data out of bounce buffer */buf = spidev->buffer;for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {if (u_tmp->rx_buf) {if (__copy_to_user((u8 __user *)(uintptr_t) u_tmp->rx_buf, buf,u_tmp->len)) {status = -EFAULT;goto done;}}buf += u_tmp->len;}status = total;done:kfree(k_xfers);return status;}

1.这部分关键的就是三个数据结构

 struct spi_messagestruct spi_transferstruct spi_ioc_transfer

原型在下面:

spi_message原型:

  struct spi_message {struct list_head    transfers;struct spi_device   *spi;unsigned        is_dma_mapped:1;/* completion is reported through a callback */void            (*complete)(void *context);void            *context;unsigned        frame_length;unsigned        actual_length;int         status;struct list_head    queue;void            *state;

spi_transfer原型

  struct spi_transfer {       /* it's ok if tx_buf == rx_buf (right?)* for MicroWire, one buffer must be null* buffers must work with dma_*map_single() calls, unless*   spi_message.is_dma_mapped reports a pre-existing mapping                                                                    */const void  *tx_buf;    void        *rx_buf;unsigned    len;        dma_addr_t  tx_dma;     dma_addr_t  rx_dma;     unsigned    cs_change:1;unsigned    tx_nbits:3; unsigned    rx_nbits:3; #define SPI_NBITS_SINGLE    0x01 /* 1bit transfer */#define SPI_NBITS_DUAL      0x02 /* 2bits transfer */#define SPI_NBITS_QUAD      0x04 /* 4bits transfer */u8      bits_per_word;  u16     delay_usecs;    u32     speed_hz;       struct list_head transfer_list;                                                                                                  };   

spi_ioc_transfer

struct spi_ioc_transfer {__u64 tx_buf;__u64 rx_buf;__u32 len;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */__u32 speed_hz;__u16 delay_usecs;__u8 bits_per_word;__u8 cs_change;
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */__u32 pad;
};

2.开始首先以spi_message->transfers链表头初始化链表.
spi_message_init实际就是封装了初始链表的内核接口.

static inline void spi_message_init(struct spi_message *m){memset(m, 0, sizeof *m);INIT_LIST_HEAD(&m->transfers);                                                                                                   }

然后初始化需要多个spi_transfer
说白了就是填充spi_transfer这个数据结构 包括从 spi_ioc_transfer结构中tx_buf所指向的用户空间地址拷贝数据到 spi_transfer 所指向的tx_buf内核地址空间.

然后将device相关的参数都拷贝一份到spi_transfer中.

接着也是链表操作,把这个spi_transfer插入到链表尾部

spi_message_add_tail(k_tmp, &msg);

然后还有一步:

  /* copy any rx data out of bounce buffer */                                                                                      buf = spidev->buffer;for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {if (u_tmp->rx_buf) {if (__copy_to_user((u8 __user *)(uintptr_t) u_tmp->rx_buf, buf,u_tmp->len)) {status = -EFAULT;goto done;}}buf += u_tmp->len;}status = total;

这里是拷贝spi_transfer->rx_buf的数据到用户空间的spi_ioc_message->rx_buf中.

我们也可以管中窥豹,在spidev_test的 transfer函数中我们就看到put spi_ioc_transfer->rx_buf的数据.

不过我目前打印出的rx_buf都是0.
tx_buf是我要发送的数据.

剩下的接口没什么分析的价值了,如果有时间还会写写关于spi_master 控制器层也称协议层的代码,看看底层实现如何!

向上吧,少年!!!!
!!




下面的内容是spi.h的简单列出, 方便查询API和数据结构.

在<linux/spi.h>中,可以看到
Linux C中的定义:#define SPI_CPHA    0x01            /* clock phase */#define SPI_CPOL    0x02            /* clock polarity */#define SPI_MODE_0  (0|0)           /* (original MicroWire) */#define SPI_MODE_1  (0|SPI_CPHA)#define SPI_MODE_2  (SPI_CPOL|0)

还有如下的宏定义:

#define SPI_CPHA    0x01            /* clock phase */
#define SPI_CPOL    0x02            /* clock polarity */
#define SPI_MODE_0  (0|0)           /* (original MicroWire) */
#define SPI_MODE_1  (0|SPI_CPHA)
#define SPI_MODE_2  (SPI_CPOL|0)
#define SPI_MODE_3  (SPI_CPOL|SPI_CPHA)
#define SPI_CS_HIGH 0x04            /* chipselect active high? */
#define SPI_LSB_FIRST   0x08            /* per-word bits-on-wire */
#define SPI_3WIRE   0x10            /* SI/SO signals shared */
#define SPI_LOOP    0x20            /* loopback mode */
#define SPI_NO_CS   0x40            /* 1 dev/bus, no chipselect */
#define SPI_READY   0x80            /* slave pulls low to pause */
#define SPI_TX_DUAL 0x100           /* transmit with 2 wires */
#define SPI_TX_QUAD 0x200           /* transmit with 4 wires */
#define SPI_RX_DUAL 0x400           /* receive with 2 wires */
#define SPI_RX_QUAD 0x800           /* receive with 4 wires */

下面我们来详细看看spi.h中的数据结构以及 常用的操作函数.

#ifndef __LINUX_SPI_H
#define __LINUX_SPI_H#include <linux/device.h>
#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/completion.h>/** INTERFACES between SPI master-side drivers and SPI infrastructure.* (There's no SPI slave support for Linux yet...)*/
extern struct bus_type spi_bus_type;

spi_device结构的原型

   /*** struct spi_device - Master side proxy for an SPI slave device* @dev: Driver model representation of the device.* @master: SPI controller used with the device.* @max_speed_hz: Maximum clock rate to be used with this chip*  (on this board); may be changed by the device's driver.*  The spi_transfer.speed_hz can override this for each transfer.* @chip_select: Chipselect, distinguishing chips handled by @master.* @mode: The spi mode defines how data is clocked out and in.*  This may be changed by the device's driver.*  The "active low" default for chipselect mode can be overridden*  (by specifying SPI_CS_HIGH) as can the "MSB first" default for*  each word in a transfer (by specifying SPI_LSB_FIRST).* @bits_per_word: Data transfers involve one or more words; word sizes*  like eight or 12 bits are common.  In-memory wordsizes are*  powers of two bytes (e.g. 20 bit samples use 32 bits).*  This may be changed by the device's driver, or left at the*  default (0) indicating protocol words are eight bit bytes.*  The spi_transfer.bits_per_word can override this for each transfer.* @irq: Negative, or the number passed to request_irq() to receive*  interrupts from this device.* @controller_state: Controller's runtime state* @controller_data: Board-specific definitions for controller, such as*  FIFO initialization parameters; from board_info.controller_data* @modalias: Name of the driver to use with this device, or an alias*  for that name.  This appears in the sysfs "modalias" attribute*  for driver coldplugging, and in uevents used for hotplugging* @cs_gpio: gpio number of the chipselect line (optional, -ENOENT when*  when not using a GPIO line)** A @spi_device is used to interchange data between an SPI slave* (usually a discrete chip) and CPU memory.               ** In @dev, the platform_data is used to hold information about this* device that's meaningful to the device's protocol driver, but not* to its controller.  One example might be an identifier for a chip* variant with slightly different functionality; another might be* information about how this particular board wires the chip's pins.*/struct spi_device {struct device       dev;struct spi_master   *master;u32         max_speed_hz;u8          chip_select;u8          bits_per_word;u16         mode;int         irq;void            *controller_state;void            *controller_data;char            modalias[SPI_NAME_SIZE];int         cs_gpio;    /* chip select gpio *//** likely need more hooks for more protocol options affecting how* the controller talks to each chip, like:*  - memory packing (12 bit samples into low bits, others zeroed)*  - priority*  - drop chipselect after each word*  - chipselect delays*  - ...*/
#define SPI_CPHA    0x01            /* clock phase */
#define SPI_CPOL    0x02            /* clock polarity */
#define SPI_MODE_0  (0|0)           /* (original MicroWire) */
#define SPI_MODE_1  (0|SPI_CPHA)
#define SPI_MODE_2  (SPI_CPOL|0)
#define SPI_MODE_3  (SPI_CPOL|SPI_CPHA)
#define SPI_CS_HIGH 0x04            /* chipselect active high? */
#define SPI_LSB_FIRST   0x08            /* per-word bits-on-wire */
#define SPI_3WIRE   0x10            /* SI/SO signals shared */
#define SPI_LOOP    0x20            /* loopback mode */
#define SPI_NO_CS   0x40            /* 1 dev/bus, no chipselect */
#define SPI_READY   0x80            /* slave pulls low to pause */
#define SPI_TX_DUAL 0x100           /* transmit with 2 wires */
#define SPI_TX_QUAD 0x200           /* transmit with 4 wires */
#define SPI_RX_DUAL 0x400           /* receive with 2 wires */
#define SPI_RX_QUAD 0x800           /* receive with 4 wires */};

spi_device 相关的操作

static inline struct spi_device *to_spi_device(struct device *dev)
{return dev ? container_of(dev, struct spi_device, dev) : NULL;
}/* most drivers won't need to care about device refcounting */
static inline struct spi_device *spi_dev_get(struct spi_device *spi)
{return (spi && get_device(&spi->dev)) ? spi : NULL;
}static inline void spi_dev_put(struct spi_device *spi)
{if (spi)put_device(&spi->dev);
}/* ctldata is for the bus_master driver's runtime state */
static inline void *spi_get_ctldata(struct spi_device *spi)
{return spi->controller_state;
}static inline void spi_set_ctldata(struct spi_device *spi, void *state)
{spi->controller_state = state;
}/* device driver data */
static inline void spi_set_drvdata(struct spi_device *spi, void *data)
{dev_set_drvdata(&spi->dev, data);
}static inline void *spi_get_drvdata(struct spi_device *spi)
{return dev_get_drvdata(&spi->dev);
}struct spi_message;
struct spi_transfer;

spi_driver结构和相关的:

/*** struct spi_driver - Host side "protocol" driver* @id_table: List of SPI devices supported by this driver* @probe: Binds this driver to the spi device.  Drivers can verify*  that the device is actually present, and may need to configure*  characteristics (such as bits_per_word) which weren't needed for*  the initial configuration done during system setup.* @remove: Unbinds this driver from the spi device* @shutdown: Standard shutdown callback used during system state*  transitions such as powerdown/halt and kexec* @suspend: Standard suspend callback used during system state transitions* @resume: Standard resume callback used during system state transitions* @driver: SPI device drivers should initialize the name and owner*  field of this structure.** This represents the kind of device driver that uses SPI messages to* interact with the hardware at the other end of a SPI link.  It's called* a "protocol" driver because it works through messages rather than talking* directly to SPI hardware (which is what the underlying SPI controller* driver does to pass those messages).  These protocols are defined in the* specification for the device(s) supported by the driver.** As a rule, those device protocols represent the lowest level interface* supported by a driver, and it will support upper level interfaces too.* Examples of such upper levels include frameworks like MTD, networking,* MMC, RTC, filesystem character device nodes, and hardware monitoring.*/
struct spi_driver {const struct spi_device_id *id_table;int         (*probe)(struct spi_device *spi);int         (*remove)(struct spi_device *spi);void            (*shutdown)(struct spi_device *spi);int         (*suspend)(struct spi_device *spi, pm_message_t mesg);int         (*resume)(struct spi_device *spi); struct device_driver driver; }; static inline struct spi_driver *to_spi_driver(struct device_driver *drv) { return drv ? container_of(drv, struct spi_driver, driver) : NULL; } extern int spi_register_driver(struct spi_driver *sdrv); /** * spi_unregister_driver - reverse effect of spi_register_driver * @sdrv: the driver to unregister * Context: can sleep */ static inline void spi_unregister_driver(struct spi_driver *sdrv) { if (sdrv) driver_unregister(&sdrv->driver); } /** * module_spi_driver() - Helper macro for registering a SPI driver * @__spi_driver: spi_driver struct * * Helper macro for SPI drivers which do not do anything special in module * init/exit. This eliminates a lot of boilerplate. Each module may only * use this macro once, and calling it replaces module_init() and module_exit() */ #define module_spi_driver(__spi_driver) \ module_driver(__spi_driver, spi_register_driver, \ spi_unregister_driver)

spi_master结构体

/*** struct spi_master - interface to SPI master controller* @dev: device interface to this driver* @list: link with the global spi_master list* @bus_num: board-specific (and often SOC-specific) identifier for a*  given SPI controller.* @num_chipselect: chipselects are used to distinguish individual*  SPI slaves, and are numbered from zero to num_chipselects.*  each slave has a chipselect signal, but it's common that not*  every chipselect is connected to a slave.* @dma_alignment: SPI controller constraint on DMA buffers alignment.* @mode_bits: flags understood by this controller driver* @bits_per_word_mask: A mask indicating which values of bits_per_word are*  supported by the driver. Bit n indicates that a bits_per_word n+1 is*  suported. If set, the SPI core will reject any transfer with an*  unsupported bits_per_word. If not set, this value is simply ignored,*  and it's up to the individual driver to perform any validation.* @min_speed_hz: Lowest supported transfer speed* @max_speed_hz: Highest supported transfer speed* @flags: other constraints relevant to this driver* @bus_lock_spinlock: spinlock for SPI bus locking* @bus_lock_mutex: mutex for SPI bus locking* @bus_lock_flag: indicates that the SPI bus is locked for exclusive use* @setup: updates the device mode and clocking records used by a*  device's SPI controller; protocol code may call this.  This*  must fail if an unrecognized or unsupported mode is requested.*  It's always safe to call this unless transfers are pending on*  the device whose settings are being modified.* @transfer: adds a message to the controller's transfer queue.* @cleanup: frees controller-specific state* @queued: whether this master is providing an internal message queue* @kworker: thread struct for message pump* @kworker_task: pointer to task for message pump kworker thread* @pump_messages: work struct for scheduling work to the message pump* @queue_lock: spinlock to syncronise access to message queue* @queue: message queue* @cur_msg: the currently in-flight message* @cur_msg_prepared: spi_prepare_message was called for the currently*                    in-flight message* @xfer_completion: used by core tranfer_one_message()* @busy: message pump is busy* @running: message pump is running* @rt: whether this queue is set to run as a realtime task* @auto_runtime_pm: the core should ensure a runtime PM reference is held*                   while the hardware is prepared, using the parent*                   device for the spidev* @prepare_transfer_hardware: a message will soon arrive from the queue*  so the subsystem requests the driver to prepare the transfer hardware*  by issuing this call* @transfer_one_message: the subsystem calls the driver to transfer a single*  message while queuing transfers that arrive in the meantime. When the*  driver is finished with this message, it must call*  spi_finalize_current_message() so the subsystem can issue the next*  message* @unprepare_transfer_hardware: there are currently no more messages on the*  queue so the subsystem notifies the driver that it may relax the*  hardware by issuing this call* @set_cs: set the logic level of the chip select line.  May be called*          from interrupt context.* @prepare_message: set up the controller to transfer a single message,*                   for example doing DMA mapping.  Called from threaded*                   context.* @transfer_one: transfer a single spi_transfer.*                  - return 0 if the transfer is finished,*                  - return 1 if the transfer is still in progress. When*                    the driver is finished with this transfer it must*                    call spi_finalize_current_transfer() so the subsystem*                    can issue the next transfer. Note: transfer_one and*                    transfer_one_message are mutually exclusive; when both*                    are set, the generic subsystem does not call your*                    transfer_one callback.* @unprepare_message: undo any work done by prepare_message().* @cs_gpios: Array of GPIOs to use as chip select lines; one per CS*  number. Any individual value may be -ENOENT for CS lines that*  are not GPIOs (driven by the SPI controller itself).** Each SPI master controller can communicate with one or more @spi_device* children.  These make a small bus, sharing MOSI, MISO and SCK signals* but not chip select signals.  Each device may be configured to use a* different clock rate, since those shared signals are ignored unless* the chip is selected.** The driver for an SPI controller manages access to those devices through* a queue of spi_message transactions, copying data between CPU memory and* an SPI slave device.  For each such message it queues, it calls the* message's completion function when the transaction completes.*/
struct spi_master {struct device   dev;struct list_head list;/* other than negative (== assign one dynamically), bus_num is fully* board-specific.  usually that simplifies to being SOC-specific.* example:  one SOC has three SPI controllers, numbered 0..2,* and one board's schematics might show it using SPI-2.  software* would normally use bus_num=2 for that controller.*/s16         bus_num;/* chipselects will be integral to many controllers; some others* might use board-specific GPIOs.*/u16         num_chipselect;/* some SPI controllers pose alignment requirements on DMAable* buffers; let protocol drivers know about these requirements.*/u16         dma_alignment;/* spi_device.mode flags understood by this controller driver */u16         mode_bits;/* bitmask of supported bits_per_word for transfers */u32         bits_per_word_mask;
#define SPI_BPW_MASK(bits) BIT((bits) - 1)
#define SPI_BIT_MASK(bits) (((bits) == 32) ? ~0U : (BIT(bits) - 1))
#define SPI_BPW_RANGE_MASK(min, max) (SPI_BIT_MASK(max) - SPI_BIT_MASK(min - 1))/* limits on transfer speed */u32         min_speed_hz;u32         max_speed_hz;/* other constraints relevant to this driver */u16         flags;
#define SPI_MASTER_HALF_DUPLEX  BIT(0)      /* can't do full duplex */
#define SPI_MASTER_NO_RX    BIT(1)      /* can't do buffer read */
#define SPI_MASTER_NO_TX    BIT(2)      /* can't do buffer write *//* lock and mutex for SPI bus locking */spinlock_t      bus_lock_spinlock;struct mutex        bus_lock_mutex;/* flag indicating that the SPI bus is locked for exclusive use */bool            bus_lock_flag;/* Setup mode and clock, etc (spi driver may call many times).** IMPORTANT:  this may be called when transfers to another* device are active.  DO NOT UPDATE SHARED REGISTERS in ways* which could break those transfers.*/int         (*setup)(struct spi_device *spi);/* bidirectional bulk transfers** + The transfer() method may not sleep; its main role is*   just to add the message to the queue.* + For now there's no remove-from-queue operation, or*   any other request management* + To a given spi_device, message queueing is pure fifo*    *      ** + The master's main job is to process its message queue,*   selecting a chip then transferring data* + If there are multiple spi_device children, the i/o queue*   arbitration algorithm is unspecified (round robin, fifo,*   priority, reservations, preemption, etc)** + Chipselect stays active during the entire message*   (unless modified by spi_transfer.cs_change != 0).* + The message transfers use clock and SPI mode parameters*   previously established by setup() for this device*/int         (*transfer)(struct spi_device *spi,struct spi_message *mesg);/* called on release() to free memory provided by spi_master */void            (*cleanup)(struct spi_device *spi);/** These hooks are for drivers that want to use the generic* master transfer queueing mechanism. If these are used, the* transfer() function above must NOT be specified by the driver.* Over time we expect SPI drivers to be phased over to this API.*/bool                queued;struct kthread_worker       kworker;struct task_struct      *kworker_task;struct kthread_work     pump_messages;spinlock_t          queue_lock;struct list_head        queue;struct spi_message      *cur_msg;bool                busy;bool                running;bool                rt;bool                auto_runtime_pm;bool                            cur_msg_prepared;struct completion               xfer_completion;int (*prepare_transfer_hardware)(struct spi_master *master);int (*transfer_one_message)(struct spi_master *master, struct spi_message *mesg); int (*unprepare_transfer_hardware)(struct spi_master *master); int (*prepare_message)(struct spi_master *master, struct spi_message *message); int (*unprepare_message)(struct spi_master *master, struct spi_message *message); /* * These hooks are for drivers that use a generic implementation * of transfer_one_message() provied by the core. */ void (*set_cs)(struct spi_device *spi, bool enable); int (*transfer_one)(struct spi_master *master, struct spi_device *spi, struct spi_transfer *transfer); /* gpio chip select */ int *cs_gpios; }; 

spi_master相关函数:

static inline void *spi_master_get_devdata(struct spi_master *master)
{return dev_get_drvdata(&master->dev);
}static inline void spi_master_set_devdata(struct spi_master *master, void *data)
{dev_set_drvdata(&master->dev, data);
}static inline struct spi_master *spi_master_get(struct spi_master *master)
{if (!master || !get_device(&master->dev))return NULL;return master;
}static inline void spi_master_put(struct spi_master *master)
{if (master)put_device(&master->dev);
}/* PM calls that need to be issued by the driver */
extern int spi_master_suspend(struct spi_master *master);
extern int spi_master_resume(struct spi_master *master);/* Calls the driver make to interact with the message queue */
extern struct spi_message *spi_get_next_queued_message(struct spi_master *master);
extern void spi_finalize_current_message(struct spi_master *master);
extern void spi_finalize_current_transfer(struct spi_master *master);/* the spi driver core manages memory for the spi_master classdev */
extern struct spi_master *
spi_alloc_master(struct device *host, unsigned size);extern int spi_register_master(struct spi_master *master);
extern int devm_spi_register_master(struct device *dev,struct spi_master *master);
extern void spi_unregister_master(struct spi_master *master);extern struct spi_master *spi_busnum_to_master(u16 busnum);

spi_transfer和spi_message是一对

/** I/O INTERFACE between SPI controller and protocol drivers** Protocol drivers use a queue of spi_messages, each transferring data* between the controller and memory buffers.** The spi_messages themselves consist of a series of read+write transfer* segments.  Those segments always read the same number of bits as they* write; but one or the other is easily ignored by passing a null buffer* pointer.  (This is unlike most types of I/O API, because SPI hardware* is full duplex.)** NOTE:  Allocation of spi_transfer and spi_message memory is entirely* up to the protocol driver, which guarantees the integrity of both (as* well as the data buffers) for as long as the message is queued.*//*** struct spi_transfer - a read/write buffer pair* @tx_buf: data to be written (dma-safe memory), or NULL* @rx_buf: data to be read (dma-safe memory), or NULL* @tx_dma: DMA address of tx_buf, if @spi_message.is_dma_mapped* @rx_dma: DMA address of rx_buf, if @spi_message.is_dma_mapped* @tx_nbits: number of bits used for writting. If 0 the default*      (SPI_NBITS_SINGLE) is used.* @rx_nbits: number of bits used for reading. If 0 the default*      (SPI_NBITS_SINGLE) is used.* @len: size of rx and tx buffers (in bytes)* @speed_hz: Select a speed other than the device default for this*      transfer. If 0 the default (from @spi_device) is used.* @bits_per_word: select a bits_per_word other than the device default*      for this transfer. If 0 the default (from @spi_device) is used.* @cs_change: affects chipselect after this transfer completes* @delay_usecs: microseconds to delay after this transfer before*  (optionally) changing the chipselect status, then starting*  the next transfer or completing this @spi_message.* @transfer_list: transfers are sequenced through @spi_message.transfers** SPI transfers always write the same number of bytes as they read.* Protocol drivers should always provide @rx_buf and/or @tx_buf.* In some cases, they may also want to provide DMA addresses for* the data being transferred; that may reduce overhead, when the* underlying driver uses dma.** If the transmit buffer is null, zeroes will be shifted out* while filling @rx_buf.  If the receive buffer is null, the data* shifted in will be discarded.  Only "len" bytes shift out (or in).                                                                                                                                              * It's an error to try to shift out a partial word.  (For example, by* shifting out three bytes with word size of sixteen or twenty bits;* the former uses two bytes per word, the latter uses four bytes.)** In-memory data values are always in native CPU byte order, translated* from the wire byte order (big-endian except with SPI_LSB_FIRST).  So*  * for example when bits_per_word is sixteen, buffers are 2N bytes long* (@len = 2N) and hold N sixteen bit words in CPU byte order.** When the word size of the SPI transfer is not a power-of-two multiple* of eight bits, those in-memory words include extra bits.  In-memory* words are always seen by protocol drivers as right-justified, so the* undefined (rx) or unused (tx) bits are always the most significant bits.** All SPI transfers start with the relevant chipselect active.  Normally* it stays selected until after the last transfer in a message.  Drivers* can affect the chipselect signal using cs_change.** (i) If the transfer isn't the last one in the message, this flag is* used to make the chipselect briefly go inactive in the middle of the* message.  Toggling chipselect in this way may be needed to terminate* a chip command, letting a single spi_message perform all of group of* chip transactions together.** (ii) When the transfer is the last one in the message, the chip may* stay selected until the next transfer.  On multi-device SPI busses* with nothing blocking messages going to other devices, this is just* a performance hint; starting a message to another device deselects* this one.  But in other cases, this can be used to ensure correctness.* Some devices need protocol transactions to be built from a series of* spi_message submissions, where the content of one message is determined* by the results of previous messages and where the whole transaction* ends when the chipselect goes intactive.** When SPI can transfer in 1x,2x or 4x. It can get this tranfer information* from device through @tx_nbits and @rx_nbits. In Bi-direction, these* two should both be set. User can set transfer mode with SPI_NBITS_SINGLE(1x)* SPI_NBITS_DUAL(2x) and SPI_NBITS_QUAD(4x) to support these three transfer.** The code that submits an spi_message (and its spi_transfers)* to the lower layers is responsible for managing its memory.* Zero-initialize every field you don't set up explicitly, to* insulate against future API updates.  After you submit a message* and its transfers, ignore them until its completion callback.*/struct spi_transfer {/* it's ok if tx_buf == rx_buf (right?)* for MicroWire, one buffer must be null* buffers must work with dma_*map_single() calls, unless*   spi_message.is_dma_mapped reports a pre-existing mapping*/const void  *tx_buf;void        *rx_buf;unsigned    len;dma_addr_t  tx_dma;dma_addr_t  rx_dma;unsigned    cs_change:1;unsigned    tx_nbits:3;unsigned    rx_nbits:3;
#define SPI_NBITS_SINGLE    0x01 /* 1bit transfer */
#define SPI_NBITS_DUAL      0x02 /* 2bits transfer */
#define SPI_NBITS_QUAD      0x04 /* 4bits transfer */u8      bits_per_word;u16     delay_usecs;u32     speed_hz;struct list_head transfer_list;
};

spi_message结构以及结构相关操作[初始化 链表维护]

/*** struct spi_message - one multi-segment SPI transaction* @transfers: list of transfer segments in this transaction* @spi: SPI device to which the transaction is queued* @is_dma_mapped: if true, the caller provided both dma and cpu virtual*  addresses for each transfer buffer* @complete: called to report transaction completions* @context: the argument to complete() when it's called* @actual_length: the total number of bytes that were transferred in all*  successful segments* @status: zero for success, else negative errno* @queue: for use by whichever driver currently owns the message* @state: for use by whichever driver currently owns the message** A @spi_message is used to execute an atomic sequence of data transfers,* each represented by a struct spi_transfer.  The sequence is "atomic"* in the sense that no other spi_message may use that SPI bus until that* sequence completes.  On some systems, many such sequences can execute as* as single programmed DMA transfer.  On all systems, these messages are* queued, and might complete after transactions to other devices.  Messages* sent to a given spi_device are alway executed in FIFO order.** The code that submits an spi_message (and its spi_transfers)* to the lower layers is responsible for managing its memory.* Zero-initialize every field you don't set up explicitly, to* insulate against future API updates.  After you submit a message* and its transfers, ignore them until its completion callback.*/
struct spi_message {struct list_head    transfers;struct spi_device   *spi;unsigned        is_dma_mapped:1;/* REVISIT:  we might want a flag affecting the behavior of the* last transfer ... allowing things like "read 16 bit length L"* immediately followed by "read L bytes".  Basically imposing* a specific message scheduling algorithm.** Some controller drivers (message-at-a-time queue processing)* could provide that as their default scheduling algorithm.  But* others (with multi-message pipelines) could need a flag to* tell them about such special cases.*//* completion is reported through a callback */void            (*complete)(void *context);void            *context;unsigned        frame_length;unsigned        actual_length;int         status;/* for optional use by whatever driver currently owns the* spi_message ...  between calls to spi_async and then later* complete(), that's the spi_master controller driver.*/struct list_head    queue;void            *state;
};static inline void spi_message_init(struct spi_message *m)
{memset(m, 0, sizeof *m);INIT_LIST_HEAD(&m->transfers);
}static inline void
spi_message_add_tail(struct spi_transfer *t, struct spi_message *m)
{list_add_tail(&t->transfer_list, &m->transfers);
}static inline void
spi_transfer_del(struct spi_transfer *t)
{list_del(&t->transfer_list);
}/*** spi_message_init_with_transfers - Initialize spi_message and append transfers* @m: spi_message to be initialized* @xfers: An array of spi transfers* @num_xfers: Number of items in the xfer array** This function initializes the given spi_message and adds each spi_transfer in* the given array to the message.*/
static inline void
spi_message_init_with_transfers(struct spi_message *m,
struct spi_transfer *xfers, unsigned int num_xfers)
{unsigned int i;spi_message_init(m);for (i = 0; i < num_xfers; ++i)spi_message_add_tail(&xfers[i], m);
}
/* It's fine to embed message and transaction structures in other data* structures so long as you don't free them while they're in use.*/static inline struct spi_message *spi_message_alloc(unsigned ntrans, gfp_t flags)
{struct spi_message *m;m = kzalloc(sizeof(struct spi_message)+ ntrans * sizeof(struct spi_transfer),flags);if (m) {unsigned i;struct spi_transfer *t = (struct spi_transfer *)(m + 1);INIT_LIST_HEAD(&m->transfers);for (i = 0; i < ntrans; i++, t++)spi_message_add_tail(t, m);}
    return m;
}static inline void spi_message_free(struct spi_message *m)
{kfree(m);
}extern int spi_setup(struct spi_device *spi);
extern int spi_async(struct spi_device *spi, struct spi_message *message);
extern int spi_async_locked(struct spi_device *spi,struct spi_message *message);/*---------------------------------------------------------------------------*//* All these synchronous SPI transfer routines are utilities layered                                                                                                                                               * over the core async transfer primitive.  Here, "synchronous" means* they will sleep uninterruptibly until the async transfer completes.*/
extern int spi_sync(struct spi_device *spi, struct spi_message *message);
extern int spi_sync_locked(struct spi_device *spi, struct spi_message *message);
extern int spi_bus_lock(struct spi_master *master);
extern int spi_bus_unlock(struct spi_master *master);

spi_read 和 spi_write


/*** spi_write - SPI synchronous write* @spi: device to which data will be written* @buf: data buffer* @len: data buffer size* Context: can sleep** This writes the buffer and returns zero or a negative error code.* Callable only from contexts that can sleep.*/
static inline int
spi_write(struct spi_device *spi, const void *buf, size_t len)
{struct spi_transfer t = {.tx_buf     = buf,.len        = len,};struct spi_message  m;spi_message_init(&m);spi_message_add_tail(&t, &m);return spi_sync(spi, &m);
}/*** spi_read - SPI synchronous read* @spi: device from which data will be read* @buf: data buffer* @len: data buffer size* Context: can sleep** This reads the buffer and returns zero or a negative error code.* Callable only from contexts that can sleep.*/
static inline int
spi_read(struct spi_device *spi, void *buf, size_t len)
{struct spi_transfer t = {.rx_buf     = buf,.len        = len,};struct spi_message  m;spi_message_init(&m);spi_message_add_tail(&t, &m);return spi_sync(spi, &m);
}

凌乱的读写函数,主要是封装了对不同的数据结构的读写

/*** spi_sync_transfer - synchronous SPI data transfer* @spi: device with which data will be exchanged* @xfers: An array of spi_transfers* @num_xfers: Number of items in the xfer array* Context: can sleep** Does a synchronous SPI data transfer of the given spi_transfer array.** For more specific semantics see spi_sync().** It returns zero on success, else a negative error code.*/
static inline int
spi_sync_transfer(struct spi_device *spi, struct spi_transfer *xfers,unsigned int num_xfers)
{struct spi_message msg;spi_message_init_with_transfers(&msg, xfers, num_xfers);
return spi_sync(spi, &msg);
}/* this copies txbuf and rxbuf data; for small transfers only! */
extern int spi_write_then_read(struct spi_device *spi,const void *txbuf, unsigned n_tx,void *rxbuf, unsigned n_rx);/*** spi_w8r8 - SPI synchronous 8 bit write followed by 8 bit read* @spi: device with which data will be exchanged* @cmd: command to be written before data is read back* Context: can sleep** This returns the (unsigned) eight bit number returned by the* device, or else a negative error code.  Callable only from* contexts that can sleep.*/
static inline ssize_t spi_w8r8(struct spi_device *spi, u8 cmd)
{ssize_t         status;u8          result;status = spi_write_then_read(spi, &cmd, 1, &result, 1);/* return negative errno or unsigned value */
    return (status < 0) ? status : result;
}/*** spi_w8r16 - SPI synchronous 8 bit write followed by 16 bit read* @spi: device with which data will be exchanged* @cmd: command to be written before data is read back* Context: can sleep** This returns the (unsigned) sixteen bit number returned by the* device, or else a negative error code.  Callable only from* contexts that can sleep.** The number is returned in wire-order, which is at least sometimes* big-endian.*/
static inline ssize_t spi_w8r16(struct spi_device *spi, u8 cmd)
{ssize_t         status;u16         result;status = spi_write_then_read(spi, &cmd, 1, &result, 2);/* return negative errno or unsigned value */
    return (status < 0) ? status : result;
}/*** spi_w8r16be - SPI synchronous 8 bit write followed by 16 bit big-endian read* @spi: device with which data will be exchanged* @cmd: command to be written before data is read back* Context: can sleep** This returns the (unsigned) sixteen bit number returned by the device in cpu* endianness, or else a negative error code. Callable only from contexts that* can sleep.** This function is similar to spi_w8r16, with the exception that it will* convert the read 16 bit data word from big-endian to native endianness.**/
static inline ssize_t spi_w8r16be(struct spi_device *spi, u8 cmd){ssize_t status;__be16 result;status = spi_write_then_read(spi, &cmd, 1, &result, 2);if (status < 0)
        return status;
return be16_to_cpu(result);
}

spi_borad_info结构体

/*---------------------------------------------------------------------------*/                                                                                                                                    /** INTERFACE between board init code and SPI infrastructure.** No SPI driver ever sees these SPI device table segments, but* it's how the SPI core (or adapters that get hotplugged) grows* the driver model tree.** As a rule, SPI devices can't be probed.  Instead, board init code* provides a table listing the devices which are present, with enough* information to bind and set up the device's driver.  There's basic* support for nonstatic configurations too; enough to handle adding* parport adapters, or microcontrollers acting as USB-to-SPI bridges.*//*** struct spi_board_info - board-specific template for a SPI device* @modalias: Initializes spi_device.modalias; identifies the driver.* @platform_data: Initializes spi_device.platform_data; the particular*  data stored there is driver-specific.* @controller_data: Initializes spi_device.controller_data; some*  controllers need hints about hardware setup, e.g. for DMA.* @irq: Initializes spi_device.irq; depends on how the board is wired.* @max_speed_hz: Initializes spi_device.max_speed_hz; based on limits*  from the chip datasheet and board-specific signal quality issues.* @bus_num: Identifies which spi_master parents the spi_device; unused*  by spi_new_device(), and otherwise depends on board wiring.* @chip_select: Initializes spi_device.chip_select; depends on how*  the board is wired.* @mode: Initializes spi_device.mode; based on the chip datasheet, board*  wiring (some devices support both 3WIRE and standard modes), and*  possibly presence of an inverter in the chipselect path.** When adding new SPI devices to the device tree, these structures serve* as a partial device template.  They hold information which can't always* be determined by drivers.  Information that probe() can establish (such* as the default transfer wordsize) is not included here.** These structures are used in two places.  Their primary role is to* be stored in tables of board-specific device descriptors, which are* declared early in board initialization and then used (much later) to* populate a controller's device tree after the that controller's driver* initializes.  A secondary (and atypical) role is as a parameter to* spi_new_device() call, which happens after those controller drivers* are active in some dynamic board configuration models.*/
struct spi_board_info {/* the device name and module name are coupled, like platform_bus;* "modalias" is normally the driver name.** platform_data goes to spi_device.dev.platform_data,* controller_data goes to spi_device.controller_data,* irq is copied too*/char        modalias[SPI_NAME_SIZE];const void  *platform_data;void        *controller_data;int     irq;/* slower signaling on noisy or low voltage boards */u32     max_speed_hz;/* bus_num is board specific and matches the bus_num of some* spi_master that will probably be registered later.** chip_select reflects how this chip is wired to that master;* it's less than num_chipselect.*/u16     bus_num;u16     chip_select;/* mode becomes spi_device.mode, and is essential for chips* where the default of SPI_CS_HIGH = 0 is wrong.*/u16     mode;/* ... may need additional spi_device chip config data here.* avoid stuff protocol drivers can set; but include stuff* needed to behave without being bound to a driver:*  - quirks like clock rate mattering when not selected*/
};

板载信息的填充,spi相关数据结构的创建 

以及相关设备在系统中的注册 注销

#ifdef  CONFIG_SPI
extern int
spi_register_board_info(struct spi_board_info const *info, unsigned n);
#else
/* board init code may ignore whether SPI is configured or not */
static inline int
spi_register_board_info(struct spi_board_info const *info, unsigned n){ return 0; }
#endif/* If you're hotplugging an adapter with devices (parport, usb, etc)* use spi_new_device() to describe each device.  You can also call* spi_unregister_device() to start making that device vanish, but* normally that would be handled by spi_unregister_master().** You can also use spi_alloc_device() and spi_add_device() to use a two* stage registration sequence for each spi_device.  This gives the caller* some more control over the spi_device structure before it is registered,* but requires that caller to initialize fields that would otherwise* be defined using the board info.*/
extern struct spi_device *
spi_alloc_device(struct spi_master *master);extern int
spi_add_device(struct spi_device *spi);extern struct spi_device *
spi_new_device(struct spi_master *, struct spi_board_info *);static inline void
spi_unregister_device(struct spi_device *spi)
{if (spi)device_unregister(&spi->dev);
}extern const struct spi_device_id *
spi_get_device_id(const struct spi_device *sdev);

至此, spi.h所有内容都结束了.

#endif /* __LINUX_SPI_H */