您的位置:首页 > 运维架构 > Linux

spi 协议硬件分析以及在linux上的实现分析

2018-01-11 10:34 1426 查看
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

如下为示波器波形:



不好意思开个玩笑:



再来看看如果是传送 两个字节 16bit的数据呢,时序图是怎么样的, 此时我将CS也加上了[由于只有两个探头,故用两张图来描述]

图片一[ 黄色CH1 为 CS信号 蓝绿色CH2为 CLK信号]:



图片二[ 黄色CH1 为 CLK信号 蓝绿色CH2为 MOSI信号]:



可以看到此时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
4000
>
#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_
23ff8
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);
}
} else
pr_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;
else
dev_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 VERBOSE
dev_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_message
struct spi_transfer
struct 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 */
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: