zoukankan      html  css  js  c++  java
  • SPI子系统分析之二:数据结构【转】

    转自:http://www.cnblogs.com/jason-lu/articles/3164901.html

    内核版本:3.9.5

    spi_master

    struct spi_master用来描述一个SPI主控制器,我们一般不需要自己编写spi控制器驱动.

    复制代码
      1 /*结构体master代表一个SPI接口,或者叫一个SPI主机控制器,一个接口对应一条SPI总线,master->bus_num则记录了这个总线号*/
      2 struct spi_master {
      3     struct device    dev;
      4 
      5     struct list_head list;
      6 
      7     /* other than negative (== assign one dynamically), bus_num is fully
      8      * board-specific.  usually that simplifies to being SOC-specific.
      9      * example:  one SOC has three SPI controllers, numbered 0..2,
     10      * and one board's schematics might show it using SPI-2.  software
     11      * would normally use bus_num=2 for that controller.
     12      */
     13     s16            bus_num;/*总线编号,从零开始.系统会用这个值去和系统中board_list链表中加入的每一个boardinfo结构
     14     (每个boardinfo结构都是一个spi_board_info的集合,每一个spi_board_info都是对应一个SPI(从)设备的描述)中的每一个
     15     spi_board_info中的bus_num进行匹配,如果匹配上就说明这个spi_board_info描述的SPI(从)设备是链接在此总线上的,因
     16     此就会调用spi_new_device去创建一个spi_device*/
     17 
     18     /* chipselects will be integral to many controllers; some others
     19      * might use board-specific GPIOs.
     20      */
     21     u16            num_chipselect;//支持的片选的数量.从设备的片选号不能大于这个数.该值当然不能为0,否则会注册失败
     22 
     23     /* some SPI controllers pose alignment requirements on DMAable
     24      * buffers; let protocol drivers know about these requirements.
     25      */
     26     u16            dma_alignment;
     27 
     28     /* spi_device.mode flags understood by this controller driver */
     29     u16            mode_bits;
     30 
     31     /* other constraints relevant to this driver */
     32     u16            flags;
     33 #define SPI_MASTER_HALF_DUPLEX    BIT(0)        /* can't do full duplex */
     34 #define SPI_MASTER_NO_RX    BIT(1)        /* can't do buffer read */
     35 #define SPI_MASTER_NO_TX    BIT(2)        /* can't do buffer write */
     36 
     37     /* lock and mutex for SPI bus locking */
     38     spinlock_t        bus_lock_spinlock;
     39     struct mutex        bus_lock_mutex;
     40 
     41     /* flag indicating that the SPI bus is locked for exclusive use */
     42     bool            bus_lock_flag;
     43 
     44     /* Setup mode and clock, etc (spi driver may call many times).
     45      *
     46      * IMPORTANT:  this may be called when transfers to another
     47      * device are active.  DO NOT UPDATE SHARED REGISTERS in ways
     48      * which could break those transfers.
     49      */
     50     int            (*setup)(struct spi_device *spi);//根据spi设备更新硬件配置
     51 
     52     /* bidirectional bulk transfers
     53      *
     54      * + The transfer() method may not sleep; its main role is
     55      *   just to add the message to the queue.
     56      * + For now there's no remove-from-queue operation, or
     57      *   any other request management
     58      * + To a given spi_device, message queueing is pure fifo
     59      *
     60      * + The master's main job is to process its message queue,
     61      *   selecting a chip then transferring data
     62      * + If there are multiple spi_device children, the i/o queue
     63      *   arbitration algorithm is unspecified (round robin, fifo,
     64      *   priority, reservations, preemption, etc)
     65      *
     66      * + Chipselect stays active during the entire message
     67      *   (unless modified by spi_transfer.cs_change != 0).
     68      * + The message transfers use clock and SPI mode parameters
     69      *   previously established by setup() for this device
     70      */
     71     int            (*transfer)(struct spi_device *spi,
     72                         struct spi_message *mesg);/*添加消息到队列的方法.此函数不可睡眠,其作用只是安排需要的传送,并且在适当的时候(传
     73     送完成或者失败)调用spi_message中的complete方法,来将结果报告给用户*/
     74 
     75     /* called on release() to free memory provided by spi_master */
     76     void            (*cleanup)(struct spi_device *spi);/*cleanup函数会在spidev_release函数中被调用,spidev_release被登记为spi dev的release
     77     函数*/
     78 
     79     /*
     80      * These hooks are for drivers that want to use the generic
     81      * master transfer queueing mechanism. If these are used, the
     82      * transfer() function above must NOT be specified by the driver.
     83      * Over time we expect SPI drivers to be phased over to this API.
     84      */
     85     bool                queued;
     86     struct kthread_worker        kworker;
     87     struct task_struct        *kworker_task;
     88     struct kthread_work        pump_messages;
     89     spinlock_t            queue_lock;
     90     struct list_head        queue;
     91     struct spi_message        *cur_msg;
     92     bool                busy;
     93     bool                running;
     94     bool                rt;
     95 
     96     int (*prepare_transfer_hardware)(struct spi_master *master);
     97     int (*transfer_one_message)(struct spi_master *master,
     98                     struct spi_message *mesg);
     99     int (*unprepare_transfer_hardware)(struct spi_master *master);
    100     /* gpio chip select */
    101     int            *cs_gpios;
    102 };
    复制代码

    spi控制器的驱动一般在arch/.../mach-*/board-*.c声明,注册一个平台设备,然后在driver/spi下面建立一个平台驱动.spi_master注册过程中会扫描arch/.../mach-*/board-*.c 中调用spi_register_board_info注册的信息,为每一个与本总线编号相同的信息建立一个spi_device.根据Linux内核的驱动模型,注册在同一总线下的驱动和设备会进行匹配.spi_bus_type总线匹配的依据是名字.这样当自己编写的spi_driver和spi_device同名的时候,spi_driver的probe方法就会被调用.spi_driver就能看到与自己匹配的spi_device了.

    spi_device

    struct spi_device用来描述一个SPI从设备.

    复制代码
     1 /*该结构用于描述SPI设备,也就是从设备的相关信息.
     2 NOTE:SPI子系统只支持主模式,也就是说SOC上的SPI只能工作在master模式,外围设备只能为slave模式*/
     3 struct spi_device {
     4     struct device        dev;
     5     struct spi_master    *master;//对应的控制器指针
     6     u32            max_speed_hz;//spi传输时钟
     7     u8            chip_select;//片选号,用来区分同一主控制器上的设备
     8     u8            mode;//各bit的定义如下,主要是传输模式/片选极性
     9 #define    SPI_CPHA    0x01            /* clock phase */
    10 #define    SPI_CPOL    0x02            /* clock polarity */
    11 #define    SPI_MODE_0    (0|0)            /* (original MicroWire) */
    12 #define    SPI_MODE_1    (0|SPI_CPHA)
    13 #define    SPI_MODE_2    (SPI_CPOL|0)
    14 #define    SPI_MODE_3    (SPI_CPOL|SPI_CPHA)
    15 #define    SPI_CS_HIGH    0x04            /* chipselect active high? *//*片选电位为高*/
    16 #define    SPI_LSB_FIRST    0x08            /* per-word bits-on-wire *//*先输出低比特*/
    17 #define    SPI_3WIRE    0x10            /* SI/SO signals shared *//*输入输出共享接口,此时只能做半双工*/
    18 #define    SPI_LOOP    0x20            /* loopback mode *//*回写/回显模式*/
    19 #define    SPI_NO_CS    0x40            /* 1 dev/bus, no chipselect */
    20 #define    SPI_READY    0x80            /* slave pulls low to pause */
    21     u8            bits_per_word;/*每个字长的比特数*/
    22     int            irq;/*使用到的中断号*/
    23     void            *controller_state;
    24     void            *controller_data;
    25     char            modalias[SPI_NAME_SIZE];/*spi设备的名字*/
    26     int            cs_gpio;    /* chip select gpio */
    27 
    28     /*
    29      * likely need more hooks for more protocol options affecting how
    30      * the controller talks to each chip, like:
    31      *  - memory packing (12 bit samples into low bits, others zeroed)
    32      *  - priority
    33      *  - drop chipselect after each word
    34      *  - chipselect delays
    35      *  - ...
    36      */
    37 };
    复制代码

    spi_driver

    struct spi_driver用于描述SPI(从)设备驱动.驱动核心将根据driver.name和spi_board_info的modalias进行匹配,如过modalia和name相等,则绑定驱动程序和arch/.../mach-xxx/board-xxx.c中调用spi_register_board_info注册的信息对应的spi_device设备.它的形式和struct platform_driver是一致的.

    复制代码
    1 struct spi_driver {
    2     const struct spi_device_id *id_table;
    3     int            (*probe)(struct spi_device *spi);/*和spi_device匹配成功之后会调用这个方法.因此这个方法需要对设备和私有数据进行初始化*/
    4     int            (*remove)(struct spi_device *spi);/*解除spi_device和spi_driver的绑定,释放probe申请的资源*/
    5     void            (*shutdown)(struct spi_device *spi);/*一般牵扯到电源管理会用到,关闭*/
    6     int            (*suspend)(struct spi_device *spi, pm_message_t mesg);/*一般牵扯到电源管理会用到,挂起*/
    7     int            (*resume)(struct spi_device *spi);/*一般牵扯到电源管理会用到,恢复*/
    8     struct device_driver    driver;
    9 };
    复制代码

    spi_board_info

    struct spi_board_info是板级信息,是在移植时就写好的,并且要将其注册.

    复制代码
     1 /*该结构也是对SPI(从)设备(spi_device)的描述,只不过它是板级信息,最终该结构的所有字段都将用于初始化SPI设备结构体spi_device*/
     2 struct spi_board_info {
     3     /* the device name and module name are coupled, like platform_bus;
     4      * "modalias" is normally the driver name.
     5      *
     6      * platform_data goes to spi_device.dev.platform_data,
     7      * controller_data goes to spi_device.controller_data,
     8      * irq is copied too
     9      */
    10     char        modalias[SPI_NAME_SIZE];/*spi设备名,会拷贝到spi_device的相应字段中.这是设备spi_device在SPI总线spi_bus_type上匹配驱动的唯一标识*/
    11     const void    *platform_data;/*平台数据*/
    12     void        *controller_data;
    13     int        irq;/*中断号*/
    14 
    15     /* slower signaling on noisy or low voltage boards */
    16     u32        max_speed_hz;/*SPI设备工作时的波特率*/
    17 
    18 
    19     /* bus_num is board specific and matches the bus_num of some
    20      * spi_master that will probably be registered later.
    21      *
    22      * chip_select reflects how this chip is wired to that master;
    23      * it's less than num_chipselect.
    24      */
    25     u16        bus_num;/*该SPI(从)设备所在总线的总线号,就记录了所属的spi_master之中的bus_num编号.一个spi_master就对应一条总线*/
    26     u16        chip_select;/*片选号.该SPI(从)设备在该条SPI总线上的设备号的唯一标识*/
    27 
    28     /* mode becomes spi_device.mode, and is essential for chips
    29      * where the default of SPI_CS_HIGH = 0 is wrong.
    30      */
    31     u8        mode;/*参考spi_device中的成员*/
    32 
    33     /* ... may need additional spi_device chip config data here.
    34      * avoid stuff protocol drivers can set; but include stuff
    35      * needed to behave without being bound to a driver:
    36      *  - quirks like clock rate mattering when not selected
    37      */
    38 };
    复制代码

    spi_transfer

    struct spi_transfer是对一次完整的数据传输的描述.每个spi_transfer总是读取和写入同样长度的比特数,但是可以很容易的使用空指针舍弃读或写.为spi_transfer和spi_message分配的内存应该在消息处理期间保证是完整的.

    复制代码
     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;/*发送缓冲区地址,这里存放要写入设备的数据(必须是dma_safe),或者为NULL*/
     8     void        *rx_buf;/*接收缓冲区地址,从设备中读取的数据(必须是dma_safe)就放在这里,或者为NULL*/
     9     unsigned    len;/*传输数据的长度.记录了tx和rx的大小(字节数),这里不是指它的和,而是各自的长度,他们总是相等的*/
    10 
    11     dma_addr_t    tx_dma;/*如果spi_message.is_dma_mapped是真,这个是tx的dma地址*/
    12     dma_addr_t    rx_dma;/*如果spi_message.is_dma_mapped是真,这个是rx的dma地址*/
    13 
    14     unsigned    cs_change:1;/*影响此次传输之后的片选.指示本次transfer结束之后是否要重新片选并调用setup改变设置.若为1则表示当该transfer
    15     传输完后,改变片选信号.这个标志可以减少系统开销*/
    16     u8        bits_per_word;/*每个字长的比特数.如果是0,使用默认值*/
    17     u16        delay_usecs;/*此次传输结束和片选改变之间的延时,之后就会启动另一个传输或者结束整个消息*/
    18     u32        speed_hz;/*通信时钟.如果是0,使用默认值*/
    19 
    20     struct list_head transfer_list;/*用来连接的双向链表节点,用于将该transfer链入message*/
    21 };
    复制代码

    再说一下:cs_change影响此transfer完成后是否禁用片选线并调用setup改变配置.(这个标志量就是chip select change片选改变的意思).没有特殊情况,一个spi_message因该只在最后一个transfer置位该标志量.

    spi_message

    struct spi_message就是对多个spi_transfer的封装.spi_message用来原子的执行spi_transfer表示的一串数组传输请求.这个传输队列是原子的,这意味着在这个消息完成之前不会有其它消息占用总线.消息的执行总是按照FIFO的顺序.向底层提交spi_message的代码要负责管理它的内存空间.未显示初始化的内存需要使用0来初始化.为spi_transfer和spi_message分配的内存应该在消息处理期间保证是完整的.

    复制代码
     1 struct spi_message {
     2     struct list_head    transfers;/*此次消息的传输段(spi_transfer)队列,一个消息可以包含多个传输段(spi_transfer)*/
     3 
     4     struct spi_device    *spi;/*传输的目的设备,无论如何这里都是spi从设备,至于数据流向(是从主机到从设备还是从从设备到主机)这是由write/read
     5     每个传输段(spi_transfer)内部的tx_buf或者是rx_buf决定的*/
     6 
     7     unsigned        is_dma_mapped:1;/*如果为真,此次调用提供dma和cpu虚拟地址.spi主机提供了dma缓存池.如果此消息确定要使用dma(那当然更好
     8     了).则从那个缓存池中申请高速缓存.替代传输段(spi_transfer)中的tx_buf/rx_buf*/
     9 
    10     /* REVISIT:  we might want a flag affecting the behavior of the
    11      * last transfer ... allowing things like "read 16 bit length L"
    12      * immediately followed by "read L bytes".  Basically imposing
    13      * a specific message scheduling algorithm.
    14      *
    15      * Some controller drivers (message-at-a-time queue processing)
    16      * could provide that as their default scheduling algorithm.  But
    17      * others (with multi-message pipelines) could need a flag to
    18      * tell them about such special cases.
    19      */
    20 
    21     /* completion is reported through a callback */
    22     void            (*complete)(void *context);/*用于异步传输完成时调用的回调函数*/
    23     void            *context;/*回调函数的参数*/
    24     unsigned        actual_length;/*此次传输的实际长度,这个长度包括了此消息spi_message中所有传输段spi_transfer传输的长度之和(不管每个传
    25     输段spi_transfer到底是输入还是输出,因为本来具体的传输就是针对每一个传输段spi_transfer来进行的)*/
    26     int            status;/*执行的结果.成功被置0,否则是一个负的错误码*/
    27 
    28     /* for optional use by whatever driver currently owns the
    29      * spi_message ...  between calls to spi_async and then later
    30      * complete(), that's the spi_master controller driver.
    31      */
    32     /*下面两个成员是给拥有本消息的驱动选用的.spi_master会使用它们.自己最好不要使用*/
    33     struct list_head    queue;/*用于将该message链入bitbang等待队列*/
    34     void            *state;
    35 };
    复制代码

    spi_bitbang

    struct spi_bitbang结构用于控制实际的数据传输.

    复制代码
     1 struct spi_bitbang {
     2     struct workqueue_struct    *workqueue;/*工作队列*/
     3     struct work_struct    work;
     4 
     5     spinlock_t        lock;
     6     struct list_head    queue;
     7     u8            busy;
     8     u8            use_dma;
     9     u8            flags;        /* extra spi->mode support */
    10 
    11     struct spi_master    *master;/*bitbang所属的master*/
    12 
    13     /* setup_transfer() changes clock and/or wordsize to match settings
    14      * for this transfer; zeroes restore defaults from spi_device.
    15      */
    16     int    (*setup_transfer)(struct spi_device *spi,
    17             struct spi_transfer *t);/*用于设置设备传输时的时钟,字长等*/
    18 
    19     void    (*chipselect)(struct spi_device *spi, int is_on);
    20 #define    BITBANG_CS_ACTIVE    1    /* normally nCS, active low */
    21 #define    BITBANG_CS_INACTIVE    0
    22 
    23     /* txrx_bufs() may handle dma mapping for transfers that don't
    24      * already have one (transfer.{tx,rx}_dma is zero), or use PIO
    25      */
    26     int    (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t);
    27 
    28     /* txrx_word[SPI_MODE_*]() just looks like a shift register */
    29     u32    (*txrx_word[4])(struct spi_device *spi,
    30             unsigned nsecs,
    31             u32 word, u8 bits);
    32 };
    复制代码

    本文引用:http://blog.csdn.net/yuanlulu/article/details/6318165

    http://blog.csdn.net/vanbreaker/article/details/7733476

    http://blog.csdn.net/wuhzossibility/article/details/7868000

  • 相关阅读:
    django filefield
    django HttpResponseRedirect
    Django 自定义 error_messages={} 返回错误信息
    Django validators 官方文档
    djnago 官方关系反向查询案例
    django logging settings.py
    分页 restframe work 排序,分页,自定义过滤
    论文阅读笔记六十三:DeNet: Scalable Real-time Object Detection with Directed Sparse Sampling(CVPR2017)
    基于Distiller的模型压缩工具简介
    基于Intel OpenVINO的搭建及应用,包含分类,目标检测,及分割,超分辨
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/8472803.html
Copyright © 2011-2022 走看看