linux设备驱动 spi详解2-通用接口层

SPI通用接口层用于把具体SPI设备的协议驱动和SPI控制器驱动联接在一起,通用接口层除了为协议驱动和控制器驱动提供一系列的标准接口API,同时还为这些接口API定义了相应的数据结构,这些数据结构一部分是SPI设备、SPI协议驱动和SPI控制器的数据抽象,一部分是为了协助数据传输而定义的数据结构。另外,通用接口层还负责SPI系统与Linux设备模型相关的初始化工作。

source定义位于:drivers/spi/spi.c和include\linux\spi\spi.h

1 spi_device

对应某个特定的slave,即spi从机

 1 struct spi_device {
 2     struct device        dev;//代表该spi设备的device结构
 3     struct spi_master    *master;//指向该spi设备所使用的控制器
 4     u32            max_speed_hz;//该设备的最大工作时钟频率
 5     u8            chip_select;//在控制器中的片选引脚
 6     u8            mode;//设备的工作模式,包括时钟格式,片选信号的有效电平等等,针对时钟相位CPHA(0或1)和时钟极性CPOL(0或1)的不同组合,将spi分成四种模式,如linux 设备驱动SPI详解1时序图所示
/*spi传输模式*/
7 #define SPI_CPHA 0x01 /* clock phase */时钟相位 8 #define SPI_CPOL 0x02 /* clock polarity */时钟极性 9 #define SPI_MODE_0 (0|0) /* (original MicroWire) */模式0 10 #define SPI_MODE_1 (0|SPI_CPHA) //模式1 11 #define SPI_MODE_2 (SPI_CPOL|0) //模式2 12 #define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) //模式3 13 #define SPI_CS_HIGH 0x04 /* chipselect active high*/片选高电平 14 #define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */ 15 #define SPI_3WIRE 0x10 /* SI/SO signals shared */ 16 #define SPI_LOOP 0x20 /* loopback mode */ 17 #define SPI_NO_CS 0x40 /* 1 dev/bus, no chipselect */单个设备占用一根SPI总线,所以没片选  18 #define SPI_READY 0x80 /* slave pulls low to pause */ 19 u8 bits_per_word;//设备每个单位数据所需要的比特数,如果传输是以字节为单位的话就设置为8,相应地,如果是以2个字节为单位则设置为16。 20 int irq;//设备使用的irq编号 21 void *controller_state;//控制器状态 22 void *controller_data;//控制器数据 23 char modalias[SPI_NAME_SIZE];//该设备的名字,用于spi总线和驱动进行配对 24 int cs_gpio; /* chip select gpio */片选信号的gpio编号,通常不用我们自己设置,接口层会根据上面的chip_select字段在spi_master结构中进行查找并赋值 25 26 /* 27 * likely need more hooks for more protocol options affecting how 28 * the controller talks to each chip, like: 29 * - memory packing (12 bit samples into low bits, others zeroed) 30 * - priority 31 * - drop chipselect after each word 32 * - chipselect delays 33 * - ... 34 */ 35 }

 1.1 spi设备的添加spi_new_device

1 struct spi_device *spi_new_device(struct spi_master *master,
 2                   struct spi_board_info *chip)
 3 {
 4     struct spi_device    *proxy;
 5     int            status;
 6 
 7     /* NOTE:  caller did any chip->bus_num checks necessary.
 8      *
 9      * Also, unless we change the return value convention to use
10      * error-or-pointer (not NULL-or-pointer), troubleshootability
11      * suggests syslogged diagnostics are best here (ugh).
12      */
13 
14     proxy = spi_alloc_device(master);//分配spi_device
15     if (!proxy)
16         return NULL;
17 
18     WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
19 
20     proxy->chip_select = chip->chip_select;//片选
21     proxy->max_speed_hz = chip->max_speed_hz;//最大速率
22     proxy->mode = chip->mode;//模式
23     proxy->irq = chip->irq;//中断号
24     strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
25     proxy->dev.platform_data = (void *) chip->platform_data;
26     proxy->controller_data = chip->controller_data;
27     proxy->controller_state = NULL;
28 
29     status = spi_add_device(proxy);//添加spi_device
30     if (status < 0) {
31         spi_dev_put(proxy);//增加引用计数
32         return NULL;
33     }
34 
35     return proxy;
36 }

1.2 首先调用函数spi_alloc_device,分配一个spi_device,并通过device_initialize初始化。

 1 struct spi_device *spi_alloc_device(struct spi_master *master)
 2 {
 3     struct spi_device    *spi;
 4     struct device        *dev = master->dev.parent;
 5 
 6     if (!spi_master_get(master))//判断spi主机是否存在
 7         return NULL;
 8 
 9     spi = kzalloc(sizeof *spi, GFP_KERNEL);//分配内存
10     if (!spi) {
11         dev_err(dev, "cannot alloc spi_device\n");
12         spi_master_put(master);//增加spi主机引用计数
13         return NULL;
14     }
15 
16     spi->master = master;//设置spi主机
17     spi->dev.parent = &master->dev;//spi主机设备文件设置为spi设备的父设备
18     spi->dev.bus = &spi_bus_type;//总线类型为spi_bus_type
19     spi->dev.release = spidev_release;//释放函数
20     spi->cs_gpio = -ENOENT;
21     device_initialize(&spi->dev);//初始化spi设备
22     return spi;
23 }

在spi.c中kernel定义的

1 struct bus_type spi_bus_type = {
2     .name        = "spi",
3     .dev_attrs    = spi_dev_attrs,
4     .match        = spi_match_device,
5     .uevent        = spi_uevent,
6     .pm        = &spi_pm,
7 };

1.3然后调用spi_add_device通过device_add向总线上添加设备,最终在bus下生成相应的设备

 1 int spi_add_device(struct spi_device *spi)
 2 {
 3     static DEFINE_MUTEX(spi_add_lock);
 4     struct spi_master *master = spi->master;
 5     struct device *dev = master->dev.parent;
 6     struct device *d;
 7     int status;
 8 
 9     /* Chipselects are numbered 0..max; validate. */
10     if (spi->chip_select >= master->num_chipselect) {//片选信号的判定,即从机个数不能超过主机可挂载个数限制
11         dev_err(dev, "cs%d >= max %d\n",
12             spi->chip_select,
13             master->num_chipselect);
14         return -EINVAL;
15     }
16 
17     /* Set the bus ID string */
18     dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->master->dev),
19             spi->chip_select);
20 
21 
22     /* We need to make sure there's no other device with this
23      * chipselect **BEFORE** we call setup(), else we'll trash
24      * its configuration.  Lock against concurrent add() calls.
25      */
26     mutex_lock(&spi_add_lock);
27 
28     d = bus_find_device_by_name(&spi_bus_type, NULL, dev_name(&spi->dev));//查找总线上的spi设备
29     if (d != NULL) {//判断是否已经在使用了
30         dev_err(dev, "chipselect %d already in use\n",
31                 spi->chip_select);
32         put_device(d);
33         status = -EBUSY;
34         goto done;
35     }
36 
37     if (master->cs_gpios)
38         spi->cs_gpio = master->cs_gpios[spi->chip_select];
39 
40     /* Drivers may modify this initial i/o setup, but will
41      * normally rely on the device being setup.  Devices
42      * using SPI_CS_HIGH can't coexist well otherwise...
43      */
44     status = spi_setup(spi);//调用spi主机 setup方法 
45     if (status < 0) {
46         dev_err(dev, "can't setup %s, status %d\n",
47                 dev_name(&spi->dev), status);
48         goto done;
49     }
50 
51     /* Device may be bound to an active driver when this returns */
52     status = device_add(&spi->dev);
53     if (status < 0)
54         dev_err(dev, "can't add %s, status %d\n",
55                 dev_name(&spi->dev), status);
56     else
57         dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));
58 
59 done:
60     mutex_unlock(&spi_add_lock);
61     return status;
62 }

1.4 spi_setup

 1 int spi_setup(struct spi_device *spi)
 2 {
 3     unsigned    bad_bits;
 4     int        status = 0;
 5 
 6     /* help drivers fail *cleanly* when they need options
 7      * that aren't supported with their current master
 8      */
 9     bad_bits = spi->mode & ~spi->master->mode_bits;//比较spi设备的模式和spi主机支持的模式
10     if (bad_bits) {//存在不支持的模式  
11         dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
12             bad_bits);
13         return -EINVAL;
14     }
15 
16     if (!spi->bits_per_word)//若没设置设备的每个字含多少位
17         spi->bits_per_word = 8;//则默认设置为8
18 
19     if (spi->master->setup)
20         status = spi->master->setup(spi);//调用spi主机的setup方法,对于2440来说,driver/spi/spi-s3c24xx.c中有定义master->setup
21 
22     dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s"
23                 "%u bits/w, %u Hz max --> %d\n",
24             (int) (spi->mode & (SPI_CPOL | SPI_CPHA)),
25             (spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",
26             (spi->mode & SPI_LSB_FIRST) ? "lsb, " : "",
27             (spi->mode & SPI_3WIRE) ? "3wire, " : "",
28             (spi->mode & SPI_LOOP) ? "loopback, " : "",
29             spi->bits_per_word, spi->max_speed_hz,
30             status);
31 
32     return status;
33 }

2 spi 板机设备

2.1 板级设备结构体

 1 struct spi_board_info {
 2     /* the device name and module name are coupled, like platform_bus;
 3      * "modalias" is normally the driver name.
 4      *
 5      * platform_data goes to spi_device.dev.platform_data,
 6      * controller_data goes to spi_device.controller_data,
 7      * irq is copied too
 8      */
 9     char        modalias[SPI_NAME_SIZE];//名字
10     const void    *platform_data;//平台数据
11     void        *controller_data;//控制器数据
12     int        irq;//中断号
13 
14     /* slower signaling on noisy or low voltage boards */
15     u32        max_speed_hz;//最大速率
16 
17 
18     /* bus_num is board specific and matches the bus_num of some
19      * spi_master that will probably be registered later.
20      *
21      * chip_select reflects how this chip is wired to that master;
22      * it's less than num_chipselect.
23      */
24     u16        bus_num;//总线编号
25     u16        chip_select;//片选
26 
27     /* mode becomes spi_device.mode, and is essential for chips
28      * where the default of SPI_CS_HIGH = 0 is wrong.
29      */
30     u8        mode;//模式
31 
32     /* ... may need additional spi_device chip config data here.
33      * avoid stuff protocol drivers can set; but include stuff
34      * needed to behave without being bound to a driver:
35      *  - quirks like clock rate mattering when not selected
36      */
37 }

spi_board_info结构大部分字段和spi_device结构相对应,通过spi_board_info结构,我们可以有两种方式向系统增加spi设备:

2.2 板级设备注册

第一种方式是在SPI控制器驱动已经被加载后,使用通用接口层的API spi_new_device 来完成:

 1 /**
 2  * spi_register_board_info - register SPI devices for a given board
 3  * @info: array of chip descriptors
 4  * @n: how many descriptors are provided
 5  * Context: can sleep
 6  *
 7  * Board-specific early init code calls this (probably during arch_initcall)
 8  * with segments of the SPI device table.  Any device nodes are created later,
 9  * after the relevant parent SPI controller (bus_num) is defined.  We keep
10  * this table of devices forever, so that reloading a controller driver will
11  * not make Linux forget about these hard-wired devices.
12  *
13  * Other code can also call this, e.g. a particular add-on board might provide
14  * SPI devices through its expansion connector, so code initializing that board
15  * would naturally declare its SPI devices.
16  *
17  * The board info passed can safely be __initdata ... but be careful of
18  * any embedded pointers (platform_data, etc), they're copied as-is.
19  */
20 int spi_register_board_info(struct spi_board_info const *info, unsigned n)
21 {
22     struct boardinfo *bi;
23     int i;
24 
25     bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);//分配内存
26     if (!bi)
27         return -ENOMEM;
28 
29     for (i = 0; i < n; i++, bi++, info++) {
30         struct spi_master *master;
31 
32         memcpy(&bi->board_info, info, sizeof(*info));//设置bi的板级信息
33         mutex_lock(&board_lock);
34         list_add_tail(&bi->list, &board_list);//添加bi->list到全局board_list链表
35         list_for_each_entry(master, &spi_master_list, list)遍历spi主机链表和板机设备匹配
36             spi_match_master_to_boardinfo(master, &bi->board_info);
37         mutex_unlock(&board_lock);
38     }
39 
40     return 0;
41 }

2.3 spi板级设备与spi主机匹配

最终通过spi_match_master_to_boardinfo 调用函数spi_match_master_to_boardinfo,还是调用1.1中的api spi_new_device

 1 static void spi_match_master_to_boardinfo(struct spi_master *master,
 2                 struct spi_board_info *bi)
 3 {
 4     struct spi_device *dev;
 5 
 6     if (master->bus_num != bi->bus_num)
 7         return;
 8 
 9     dev = spi_new_device(master, bi);
10     if (!dev)
11         dev_err(master->dev.parent, "can't create new device for %s\n",
12             bi->modalias);
13 }

spi_register_board_info  会把每个spi_board_info挂在全局链表变量board_list上,并且遍历已经在系统中注册了的控制器,匹配上相应的控制器并取得它们的spi_master结构指针,最终也会通过spi_new_device函数添加SPI设备。

因为spi_register_board_info可以在板子的初始化代码中调用,可能这时控制器驱动尚未加载,此刻无法取得相应的spi_master指针。

不过不要担心,控制器驱动被加载时,一定会调用spi_register_master函数来注册spi_master结构,而spi_register_master函数会反过来遍历全局链表board_list上的spi_board_info,然后通过spi_new_device函数添加SPI设备。

3 spi设备驱动 spi_driver

既然有spi_device,那就必然也有spi_driver与之对应。

spi_driver就是我们编写spi驱动是需要编写的,其他spi_devcie 、spi platform_device和spi platform_driver linux kernel已经帮我们做好。

1 struct spi_driver {
2     const struct spi_device_id *id_table;//spi设备id表
3     int            (*probe)(struct spi_device *spi);//probe方法(探测到设备)
4     int            (*remove)(struct spi_device *spi);//remove方法(设备移除)  
5     void            (*shutdown)(struct spi_device *spi); //shutdown方法(关闭设备)
6     int            (*suspend)(struct spi_device *spi, pm_message_t mesg);//进入待机
7     int            (*resume)(struct spi_device *spi);//退出待机
8     struct device_driver    driver;//设备驱动文件 
9 }

id_table字段用于指定该驱动可以驱动的设备名称,总线的匹配函数会把id_table中指定的名字和spi_device结构中的modalias字段进行比较,两者相符即表示匹配成功,然后出发spi_driver的probe回调函数被调用,从而完成驱动程序的初始化工作。

需要注意的是,这里的spi_driver结构代表的是具体的SPI协议驱动程序。

通用接口层提供如下API来完成spi_driver的注册:

 1 /**
 2  * spi_register_driver - register a SPI driver
 3  * @sdrv: the driver to register
 4  * Context: can sleep
 5  */
 6 int spi_register_driver(struct spi_driver *sdrv)
 7 {
 8     sdrv->driver.bus = &spi_bus_type;//总线类型 
 9     if (sdrv->probe)//若存在probe方法
10         sdrv->driver.probe = spi_drv_probe;//赋值probe回调函数
11     if (sdrv->remove)
12         sdrv->driver.remove = spi_drv_remove;
13     if (sdrv->shutdown)
14         sdrv->driver.shutdown = spi_drv_shutdown;
15     return driver_register(&sdrv->driver);//调用driver的注册函数
16 }

 

4 spi总线

4.1 spi 总线结构体定义

 1 struct bus_type spi_bus_type = {
 2     .name        = "spi",
 3     .dev_attrs    = spi_dev_attrs,
 4     .match        = spi_match_device,
 5     .uevent        = spi_uevent,
 6     .pm        = &spi_pm,
 7 };
 8 static struct class spi_master_class = {
 9     .name        = "spi_master",
10     .owner        = THIS_MODULE,
11     .dev_release    = spi_master_release,
12 };

可见,在初始化阶段,spi_init函数向系统注册了一个名为spi的总线类型,同时也为SPI控制器注册了一个名为spi_master的设备类。这样,以后在sys目录下就会出现两个文件节点。
sys/bus/spi 和sys/class/spi_master 

4.2 spi_match_device
代表spi总线的spi_bus_type结构的match字段指向了spi_match_device函数,该函数用于匹配spi总线上的设备和驱动:

 1 static int spi_match_device(struct device *dev, struct device_driver *drv)
 2 {
 3     const struct spi_device    *spi = to_spi_device(dev);
 4     const struct spi_driver    *sdrv = to_spi_driver(drv);
 5 
 6     /* Attempt an OF style match */
 7     if (of_driver_match_device(dev, drv))
 8         return 1;
 9 
10     /* Then try ACPI */
11     if (acpi_driver_match_device(dev, drv))//设备文件驱动表的匹配
12         return 1;
13 
14     if (sdrv->id_table)//spi设备驱动存在支持id表
15         return !!spi_match_id(sdrv->id_table, spi);//spi设备驱动表的匹配 
16 
17     return strcmp(spi->modalias, drv->name) == 0;//比较spi设备的名字和spi设备驱动的名字
18 }

4.2.1 of_driver_match_device

1 static inline int of_driver_match_device(const struct device *dev,const struct device_driver *drv)  
2 {  
3     return of_match_device(drv->of_match_table, dev) != NULL;    //调用of_match_device函数  
4 } 

4.2.1.1 of_match_device

1 const struct of_device_id *of_match_device(const struct of_device_id *matches,const struct device *dev)  
2 {  
3     if ((!matches) || (!dev->of_node))   //id表和设备节点都不存在  
4         return NULL;    //则返回  
5     return of_match_node(matches, dev->of_node); //调用of_match_node函数  
6 }  
7 EXPORT_SYMBOL(of_match_device);  

4.2.1.1.1 of_match_node

 1 const struct of_device_id *of_match_node(const struct of_device_id *matches,const struct device_node *node)  
 2 {  
 3     while (matches->name[0] || matches->type[0] || matches->compatible[0]) {   //名字,类型,兼容方法有一个存在  
 4         int match = 1;  
 5         if (matches->name[0])    //判断名字  
 6             match &= node->name && !strcmp(matches->name, node->name);  
 7         if (matches->type[0])    //判断类型  
 8             match &= node->type && !strcmp(matches->type, node->type);  
 9         if (matches->compatible[0])  //兼容方法  
10             match &= of_device_is_compatible(node,matches->compatible);  
11         if (match)  //匹配  
12             return matches; //返回匹配的id  
13         matches++;  //matches指针++,指向下一个id  
14     }  
15     return NULL;  
16 }  
17 EXPORT_SYMBOL(of_match_node); 

4.2.2 spi_match_id

1 static const struct spi_device_id *spi_match_id(const struct spi_device_id *id,const struct spi_device *sdev)  
2 {  
3     while (id->name[0]) {    //id表的成员的名字域不为空  
4         if (!strcmp(sdev->modalias, id->name))    //则判断其名字是否与spi设备的名字一样  
5             return id;  //一样则返回该id  
6         id++;   //id表指针++,指向下一个id  
7     }  
8     return NULL;  
9 }  

5 spi 设备模型初始化

一般,根据linux设备模型的组织方式,各种设备会挂在合适的总线上,设备驱动和设备通过总线互相进行匹配,使得设备能够找到正确的驱动程序进行控制和驱动。同时,性质相似的设备可以归为某一个类的设备,它们具有某些共同的设备属性,在设备模型上就是所谓的class。SPI设备也不例外,它们也遵循linux的设备模型的规则:

 1 static int __init spi_init(void)
 2 {
 3     int    status;
 4 
 5     buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);//分配数据收发缓冲区 
 6     if (!buf) {
 7         status = -ENOMEM;
 8         goto err0;
 9     }
10 
11     status = bus_register(&spi_bus_type);//注册spi总线
12     if (status < 0)
13         goto err1;
14 
15     status = class_register(&spi_master_class);//注册spi主机类 "/sys/class/spi_master"  
16     if (status < 0)
17         goto err2;
18     return 0;
19 
20 err2:
21     bus_unregister(&spi_bus_type);
22 err1:
23     kfree(buf);
24     buf = NULL;
25 err0:
26     return status;
27 }
28 postcore_initcall(spi_init);

postcore_initcall(spi_init);  指定驱动入口函数。

6 spi_message 和spi_transfer 即spi消息和spi传输列表

完成和SPI设备的数据传输工作,我们还需要另外两个数据结构:spi_message和spi_transfer。spi_message包含了一个的spi_transfer结构序列,一旦控制器接收了一个spi_message,其中的spi_transfer应该按顺序被发送,并且不能被其它spi_message打断,所以我们认为spi_message就是一次SPI数据交换的原子操作。下面我们看看这两个数据结构的定义:

6.1  spi_message 

 1 struct spi_message {
 2     struct list_head    transfers;//用于链接挂在本message下的spi_tranfer结构
 3 
 4     struct spi_device    *spi;//所属spi设备
 5 
 6     unsigned        is_dma_mapped:1;
 7 
 8     /* REVISIT:  we might want a flag affecting the behavior of the
 9      * last transfer ... allowing things like "read 16 bit length L"
10      * immediately followed by "read L bytes".  Basically imposing
11      * a specific message scheduling algorithm.
12      *
13      * Some controller drivers (message-at-a-time queue processing)
14      * could provide that as their default scheduling algorithm.  But
15      * others (with multi-message pipelines) could need a flag to
16      * tell them about such special cases.
17      */
18 
19     /* completion is reported through a callback */
20     void            (*complete)(void *context);
21     void            *context;
22     unsigned        actual_length;
23     int            status;//传输状态 
24 
25     /* for optional use by whatever driver currently owns the
26      * spi_message ...  between calls to spi_async and then later
27      * complete(), that's the spi_master controller driver.
28      */
29     struct list_head    queue;//将该message挂在代表控制器的spi_master结构的queue字段上
30     void            *state;
31 }

链表字段queue用于把该结构挂在代表控制器的spi_master结构的queue字段上,控制器上可以同时被加入多个spi_message进行排队。另一个链表字段transfers则用于链接挂在本message下的spi_tranfer结构。complete回调函数则会在该message下的所有spi_transfer都被传输完成时被调用,以便通知协议驱动处理接收到的数据以及准备下一批需要发送的数据。

6.2 spi_transfer结构:

 1 struct spi_transfer {
 2     /* it's ok if tx_buf == rx_buf (right?)
 3      * for MicroWire, one buffer must be null
 4      * buffers must work with dma_*map_single() calls, unless
 5      *   spi_message.is_dma_mapped reports a pre-existing mapping
 6      */
 7     const void    *tx_buf;//发送缓冲区指针
 8     void        *rx_buf;//接收缓冲区指针
 9     unsigned    len;//消息长度  
10 
11     dma_addr_t    tx_dma;//DMA发送地址
12     dma_addr_t    rx_dma;//DMA接收地址
13 
14     unsigned    cs_change:1;//一个字多少位
15     u8        bits_per_word;//毫秒级延时  
16     u16        delay_usecs;
17     u32        speed_hz;
18 
19     struct list_head transfer_list;//把该transfer挂在一个spi_message结构中
20 }

首先,transfer_list链表字段用于把该transfer挂在一个spi_message结构中,tx_buf和rx_buf提供了非dma模式下的数据缓冲区地址,len则是需要传输数据的长度,tx_dma和rx_dma则给出了dma模式下的缓冲区地址。原则来讲,spi_transfer才是传输的最小单位,之所以又引进了spi_message进行打包,我觉得原因是:有时候希望往spi设备的多个不连续的地址(或寄存器)一次性写入,如果没有spi_message进行把这样的多个spi_transfer打包,因为通常真正的数据传送工作是在另一个内核线程(工作队列)中完成的,不打包的后果就是会造成更多的进程切换,效率降低,延迟增加,尤其对于多个不连续地址的小规模数据传送而言就更为明显。

6.3. 用于初始化spi_message结构,位于spi.h中

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

6.4 把一个spi_transfer加入到一个spi_message中(注意,只是加入,未启动传输过程),和移除一个spi_transfer:

 1 static inline void
 2 spi_message_add_tail(struct spi_transfer *t, struct spi_message *m)
 3 {
 4     list_add_tail(&t->transfer_list, &m->transfers);
 5 }
 6 
 7 static inline void
 8 spi_transfer_del(struct spi_transfer *t)
 9 {
10     list_del(&t->transfer_list);
11 }

以上两个API的组合,初始化一个spi_message并添加数个spi_transfer结构:

 1 /**
 2  * spi_message_init_with_transfers - Initialize spi_message and append transfers
 3  * @m: spi_message to be initialized
 4  * @xfers: An array of spi transfers
 5  * @num_xfers: Number of items in the xfer array
 6  *
 7  * This function initializes the given spi_message and adds each spi_transfer in
 8  * the given array to the message.
 9  */
10 static inline void
11 spi_message_init_with_transfers(struct spi_message *m,
12 struct spi_transfer *xfers, unsigned int num_xfers)
13 {
14     unsigned int i;
15 
16     spi_message_init(m);
17     for (i = 0; i < num_xfers; ++i)
18         spi_message_add_tail(&xfers[i], m);
19 }

6.5 分配一个自带数个spi_transfer机构的spi_message:

 1 /* It's fine to embed message and transaction structures in other data
 2  * structures so long as you don't free them while they're in use.
 3  */
 4 
 5 static inline struct spi_message *spi_message_alloc(unsigned ntrans, gfp_t flags)
 6 {
 7     struct spi_message *m;
 8 
 9     m = kzalloc(sizeof(struct spi_message)
10             + ntrans * sizeof(struct spi_transfer),
11             flags);
12     if (m) {
13         unsigned i;
14         struct spi_transfer *t = (struct spi_transfer *)(m + 1);
15 
16         INIT_LIST_HEAD(&m->transfers);
17         for (i = 0; i < ntrans; i++, t++)
18             spi_message_add_tail(t, m);
19     }
20     return m;
21 }

6.6 spi_master,spi_message,spi_transfer这几个数据结构的关系可以用下图来描述

7 spi 子系统API

通用接口层也为一些简单的数据传输提供了独立的API来完成上述的组合过程:

1 int spi_write(struct spi_device *spi, const void *buf, size_t len);//同步方式发送数据。
2 int spi_read(struct spi_device *spi, void *buf, size_t len); //同步方式接收数据。
3 int spi_sync_transfer(struct spi_device *spi, struct spi_transfer *xfers, unsigned int num_xfers);//同步方式,直接传送数个spi_transfer,接收和发送。
4 int spi_write_then_read(struct spi_device *spi, const void *txbuf, unsigned n_tx, void *rxbuf, unsigned n_rx); //先写后读。
5 ssize_t spi_w8r8(struct spi_device *spi, u8 cmd);  //写8位,然后读8位。
6 ssize_t spi_w8r16(struct spi_device *spi, u8 cmd); //写8位,然后读16位。

7.1 spi读 spi_read

定义spi.h

 1 static inline int spi_read(struct spi_device *spi, u8 *buf, size_t len)  
 2 {  
 3     struct spi_transfer t = {  
 4             .rx_buf     = buf,  
 5             .len        = len,  
 6         };  
 7     struct spi_message  m;  
 8     spi_message_init(&m);   //spi消息初始化(初始化传输事务链表头)  
 9     spi_message_add_tail(&t, &m);   //添加spi传输到spi消息传输链表  
10     return spi_sync(spi, &m);   //spi同步传输  
11 }  

7.2 spi写 spi_write

 1 static inline int spi_write(struct spi_device *spi, const u8 *buf, size_t len)  
 2 {  
 3     struct spi_transfer t = {  
 4             .tx_buf     = buf,  
 5             .len        = len,  
 6         };  
 7     struct spi_message  m;  
 8     spi_message_init(&m);   //spi消息初始化(初始化传输事务链表头)  
 9     spi_message_add_tail(&t, &m);   //添加spi传输到spi消息传输链表  
10     return spi_sync(spi, &m);   //spi同步传输  
11 } 

spi的读写操作都是初始化一个spi_transfer传输结构体,并将其添加进spi消息传输事务链表中。

然后通过spi_sync来同步读写操作,接着看下spi_sync的具体代码

 7.3 同步传输spi_sync

1 int spi_sync(struct spi_device *spi, struct spi_message *message)  
2 {  
3     return __spi_sync(spi, message, 0); //调用__spi_sync函数  
4 }  
5 EXPORT_SYMBOL_GPL(spi_sync); 

__spi_sync函数

 1 static int __spi_sync(struct spi_device *spi, struct spi_message *message,int bus_locked)  
 2 {  
 3     DECLARE_COMPLETION_ONSTACK(done);   //声明一个工作队列  
 4     int status;  
 5     struct spi_master *master = spi->master; //获取spi主机  
 6   
 7     message->complete = spi_complete;    //设置spi消息的complete方法为spi_complete  
 8     message->context = &done;    //设置spi消息的context  
 9     if (!bus_locked)      
10         mutex_lock(&master->bus_lock_mutex); //上锁  
11     status = spi_async_locked(spi, message);  
12     if (!bus_locked)  
13         mutex_unlock(&master->bus_lock_mutex);   //解锁  
14     if (status == 0) {  
15         wait_for_completion(&done); //等待完成  
16         status = message->status;    //设置spi消息传输状态  
17     }  
18     message->context = NULL;  
19     return status;  
20 }  

spi_async_locked 函数

 1 int spi_async_locked(struct spi_device *spi, struct spi_message *message)  
 2 {  
 3     struct spi_master *master = spi->master; //获取spi主机  
 4     int ret;  
 5     unsigned long flags;  
 6     spin_lock_irqsave(&master->bus_lock_spinlock, flags);    //上自旋锁  
 7     ret = __spi_async(spi, message);    //调用了spi异步同步方法  
 8     spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);   //解自旋锁  
 9     return ret;  
10 }  

7.3 __spi_async函数,异步

 1 static int __spi_async(struct spi_device *spi, struct spi_message *message)  
 2 {  
 3     struct spi_master *master = spi->master;  
 4     //主机为半双工或spi设备为3线设备  
 5     if ((master->flags & SPI_MASTER_HALF_DUPLEX)|| (spi->mode & SPI_3WIRE)) {  
 6         struct spi_transfer *xfer;  
 7         unsigned flags = master->flags;    
 8         list_for_each_entry(xfer, &message->transfers, transfer_list) {  //遍历spi消息的传输事务链表  
 9             if (xfer->rx_buf && xfer->tx_buf) //判断接收或发送缓冲区是否为空  
10                 return -EINVAL;  
11             if ((flags & SPI_MASTER_NO_TX) && xfer->tx_buf)  //检验无spi数据发送的情况  
12                 return -EINVAL;  
13             if ((flags & SPI_MASTER_NO_RX) && xfer->rx_buf)  //检验无spi数据接收的情况  
14                 return -EINVAL;  
15         }  
16     }  
17     message->spi = spi;  //设置spi消息所属的spi设备  
18     message->status = -EINPROGRESS;  //设置spi消息的传输状态  
19     return master->transfer(spi, message);   //调用spi主机的transfer方法,收发spi信息给spi设备  
20 }  

spi 主机的transfer函数分析见:linux设备驱动 spi详解5-应用到驱动的完整流程

7.4 spi先写后读 spi_write_then_read

 1 int spi_write_then_read(struct spi_device *spi,const u8 *txbuf, unsigned n_tx,u8 *rxbuf, unsigned n_rx)  
 2 {  
 3     static DEFINE_MUTEX(lock);  
 4     int status;  
 5     struct spi_message  message;  
 6     struct spi_transfer x[2];   //声明两个spi传输结构体  
 7     u8  *local_buf;  
 8       
 9     if ((n_tx + n_rx) > SPI_BUFSIZ)  //验证发送和接收的数据总和是否溢出  
10         return -EINVAL;  
11     spi_message_init(&message);     //spi消息初始化(初始化传输事务链表头)  
12     memset(x, 0, sizeof x); //  
13     if (n_tx) {  
14         x[0].len = n_tx;  
15         spi_message_add_tail(&x[0], &message);  //添加spi传输到spi消息传输链表  
16     }  
17     if (n_rx) {  
18         x[1].len = n_rx;  
19         spi_message_add_tail(&x[1], &message);  //添加spi传输到spi消息传输链表  
20     }  
21     if (!mutex_trylock(&lock)) {    //尝试上锁 失败  
22         local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);    //则分配local_buf内存  
23         if (!local_buf)  
24             return -ENOMEM;  
25     } else  
26         local_buf = buf;    //指向默认分配好内存的缓冲区(spi_init中初始化的)  
27     memcpy(local_buf, txbuf, n_tx); //发送缓冲区的内容复制到local_buf中  
28     x[0].tx_buf = local_buf;        //发送的spi传输结构体  
29     x[1].rx_buf = local_buf + n_tx; //接收的spi传输结构体  
30     status = spi_sync(spi, &message);   //spi同步传输--发送数据  
31     if (status == 0)  
32         memcpy(rxbuf, x[1].rx_buf, n_rx);   //接收返回的数据复制到rxbuf中  
33     if (x[0].tx_buf == buf)  
34         mutex_unlock(&lock);    //解锁  
35     else  
36         kfree(local_buf);   //释放内存  
37     return status;  
38 }  

7.5 spi写8位后读8位数据 spi_w8r8 

1 static inline ssize_t spi_w8r8(struct spi_device *spi, u8 cmd)  
2 {  
3     ssize_t status;  
4     u8  result;  
5     status = spi_write_then_read(spi, &cmd, 1, &result, 1); //写8位读8位  
6     return (status < 0) ? status : result;  
7 } 

7.6 spi写8位数据后读16位数据 spi_w8r16

1 static inline ssize_t spi_w8r16(struct spi_device *spi, u8 cmd)  
2 {  
3     ssize_t status;  
4     u16 result;  
5     status = spi_write_then_read(spi, &cmd, 1, (u8 *) &result, 2);  //写8位读16位  
6     return (status < 0) ? status : result;  
7 } 

以上这些API都是内核空间使用的接口,设备驱动程序调用这些API直接操作spi的读写操作,来完成任务

8 总结

总结一下,协议驱动发送数据的流程大致是这样的:

(1)定义一个spi_message结构;

(2)用spi_message_init函数初始化spi_message;

(3)定义一个或数个spi_transfer结构,初始化并为数据准备缓冲区并赋值给spi_transfer相应的字段(tx_buf,rx_buf等);

(4)通过spi_message_init函数把这些spi_transfer挂在spi_message结构下;

(5)如果使用同步方式,调用spi_sync(),如果使用异步方式,调用spi_async();

参考博文:

https://blog.csdn.net/DroidPhone/java/article/details/23932447

http://dainh.blog.chinaunix.net/uid-26765074-id-3510487.html

posted @ 2020-05-30 17:54  Action_er  阅读(5390)  评论(0编辑  收藏  举报