好贷网好贷款

spi子系统

发布时间:2016-12-3 21:38:00 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"spi子系统",主要涉及到spi子系统方面的内容,对于spi子系统感兴趣的同学可以参考一下。

ti8168驱动备份 queue_work调度执行一个指定workqueue中的任务。输入参数: @ workqueue_struct:指定的workqueue指针 @work_struct:具体任务对象指针 spi目录下Makefile: ccflags-$(CONFIG_SPI_DEBUG) := -DDEBUG 如果配置了SPI_DEBUG则添加DDEBUG宏定义;其中ccflags是指编译相应文件时使用的选项 obj-$(CONFIG_SPI_MASTER)        += spi.o 添加spi子系统,即master 有些时候,没有此对应的硬件上的SPI控制器,而还想要和SPI设备通信,那么就只能用GPIO端口去模拟对应的SPI接口的对应的pin:片选CS,数据输入Data In,数据输出Data Out, 始终Clock,去模拟SPI协议,和对应spi设备进行通信。所以,此时你对每个端口的操作,作为编程者,你自己要去负责信号的同步,保证timing符合协议规定,才能正常进行SPI通 信。这样的SPI的bit-bang。 通过GPIO引脚,用软件来模拟串行通信(SPI/I2C ) obj-$(CONFIG_SPI_BITBANG)       += spi_bitbang.o 这是ti81xx的master驱动选项,需要选择上 config SPI_OMAP24XX                                                           tristate "McSPI driver for OMAP/TI81XX"                               depends on ARCH_OMAP2PLUS || ARCH_TI81XX                                 help                                                                        SPI master controller for OMAP24XX and later Multichannel SPI             (McSPI) modules. spi dev是可以直接在应用层操作spi设备,在驱动层封装具体的设备应用程序 config SPI_SPIDEV tristate "User mode SPI device driver support" depends on EXPERIMENTAL help   This supports user mode SPI protocol drivers.   Note that this application programming interface is EXPERIMENTAL   and hence SUBJECT TO CHANGE WITHOUT NOTICE while it stabilizes. Makefile和Konfig分析完了,咱们再看看板文件的配置: 从board-ti8168evm.c中没有找到spi master设备的配置,最终在devices中找到了,如下: static int __init omap2_init_devices(void) { omap_init_mcspi();         。。。 } arch_initcall(omap2_init_devices); 在系统初始化时,会调用该函数,具体实现如下: static void omap_init_mcspi(void) {         //设置spi寄存器开始地址和结束地址 if (cpu_is_ti81xx()) ti81xx_mcspi_fixup();         //注册spi master设备 platform_device_register(&omap2_mcspi1); } static inline void ti81xx_mcspi_fixup(void) { omap2_mcspi1_resources[0].start = TI81XX_MCSPI1_BASE; omap2_mcspi1_resources[0].end = TI81XX_MCSPI1_BASE + 0xff; } 在分析platform_device_register()之前,我们先分析下设备结构体: 4个片选: static struct omap2_mcspi_platform_config omap2_mcspi1_config = { .num_cs = 4, }; io资源: static struct resource omap2_mcspi1_resources[] = { { .start = OMAP2_MCSPI1_BASE, .end = OMAP2_MCSPI1_BASE + 0xff, .flags = IORESOURCE_MEM, }, }; static struct platform_device omap2_mcspi1 = {         //设备名,会和master driver name比较 .name = "omap2_mcspi", .id = 1, .num_resources = ARRAY_SIZE(omap2_mcspi1_resources), .resource = omap2_mcspi1_resources, .dev = { .platform_data = &omap2_mcspi1_config, }, }; platform_device_register()注册过程: int platform_device_register(struct platform_device *pdev) { device_initialize(&pdev->dev); return platform_device_add(pdev); } void device_initialize(struct device *dev) { dev->kobj.kset = devices_kset; kobject_init(&dev->kobj, &device_ktype); INIT_LIST_HEAD(&dev->dma_pools); mutex_init(&dev->mutex); lockdep_set_novalidate_class(&dev->mutex); spin_lock_init(&dev->devres_lock); INIT_LIST_HEAD(&dev->devres_head); device_pm_init(dev); set_dev_node(dev, -1); } int platform_device_add(struct platform_device *pdev) { int i, ret = 0; if (!pdev->dev.parent) pdev->dev.parent = &platform_bus; pdev->dev.bus = &platform_bus_type; if (pdev->id != -1) dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id); for (i = 0; i < pdev->num_resources; i++) { struct resource *p, *r = &pdev->resource[i]; p = r->parent; if (!p) { if (resource_type(r) == IORESOURCE_MEM) p = &iomem_resource; else if (resource_type(r) == IORESOURCE_IO) p = &ioport_resource; } } ret = device_add(&pdev->dev); } 设备的添加就这些内容了,然后看下master驱动,上面分析过,对应的是omap2_mcspi.c, 首先初始化platform驱动: static int __init omap2_mcspi_init(void) {         //创建一个工作队列,名字为driver的名字 omap2_mcspi_wq = create_singlethread_workqueue( omap2_mcspi_driver.driver.name);         //设备不可热插拔,所以使用该函数,而不是platform_driver_register  return platform_driver_probe(&omap2_mcspi_driver, omap2_mcspi_probe); } 首先创建一个工作队列,在probe时初始化一个任务,该任务完成spi读写操作: INIT_WORK(&mcspi->work, omap2_mcspi_work); 然后在transfer时启动这个任务,也就是说,这个任务是用来发送接受的: queue_work(omap2_mcspi_wq, &mcspi->work); 1.驱动流程 在SPI子系统中,包含两类设备驱动: Controller driver,用于驱动SPI主控设备,以和SPI总线交互,读写通信数据; Protocol driver,解析Controller driver读取的数据,形成有意义的协议数据 根据上面的分析我们知道,SPI通信的数据流大致是: 用户请求=>Protocol driver分析请求,生成SPI通信帧=>Controller driver将通信帧发送到SPI总线上; SPI设备传回数据=>Controller driver从SPI总线上读回=>Protocol解析通信数据并上报; 2.重要数据结构 struct spi_master用来描述一个SPI主控制器   1 /*结构体master代表一个SPI接口,或者叫一个SPI主机控制器,一个接口对应一条SPI总线,master->bus_num则记录了这个总线号*/   2 struct spi_master {   3     struct device    dev;   5     struct list_head list;  13     s16            bus_num;/*总线编号,从零开始.系统会用这个值去和系统中board_list链表中加入的每一个boardinfo结构中的每一个  15     spi_board_info中的bus_num进行匹配,如果匹配上就说明这个spi_board_info描述的SPI(从)设备是链接在此总线上的,因  16     此就会调用spi_new_device去创建一个spi_device*/  21     u16            num_chipselect;//支持的片选的数量.从设备的片选号不能大于这个数.该值当然不能为0,否则会注册失败  50     int            (*setup)(struct spi_device *spi);//根据spi设备更新硬件配置  71     int            (*transfer)(struct spi_device *spi, struct spi_message *mesg);/*添加消息到队列的方法安排需要的传送,并且在适当的时候(传 送完成或者失败)调用spi_message中的complete方法,来将结果报告给用户*/  76     void            (*cleanup)(struct spi_device *spi);/*cleanup函数会在spidev_release函数中被调用*/ 102 }; struct spi_device用来描述一个SPI从设备.  1 /*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 */ 37 }; spi_board_info struct spi_board_info是板级信息,是在移植时就写好的,并且要将其注册.  1 /*该结构也是对SPI(从)设备(spi_device)的描述,只不过它是板级信息,最终该结构的所有字段都将用于初始化SPI设备结构体spi_device*/  2 struct spi_board_info { 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;/*中断号*/ 15     /* slower signaling on noisy or low voltage boards */ 16     u32        max_speed_hz;/*SPI设备工作时的波特率*/ 25     u16        bus_num;/*该SPI(从)设备所在总线的总线号,就记录了所属的spi_master之中的bus_num编号.一个spi_master就对应一条总线*/ 26     u16        chip_select;/*片选号.该SPI(从)设备在该条SPI总线上的设备号的唯一标识*/ 31     u8        mode;/*参考spi_device中的成员*/ 38 }; spi_transfer struct spi_transfer是对一次完整的数据传输的描述.每个spi_transfer总是读取和写入同样长度的比特数,但是可以很容易的使用空指针舍弃读或写.为spi_transfer和spi_message分配的内存应该在消息处理期间保证是完整的.  1 struct spi_transfer {  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地址*/ 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,使用默认值*/ 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)*/  4     struct spi_device    *spi;/*传输的目的设备,无论如何这里都是spi从设备,至于数据流向(是从主机到从设备还是从从设备到主机)这是由write/read  5     每个传输段(spi_transfer)内部的tx_buf或者是rx_buf决定的*/  7     unsigned        is_dma_mapped:1;/*如果为真,此次调用提供dma和cpu虚拟地址.spi主机提供了dma缓存池.如果此消息确定要使用dma(那当然更好  8     了).则从那个缓存池中申请高速缓存.替代传输段(spi_transfer)中的tx_buf/rx_buf*/ 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,否则是一个负的错误码*/ 32     /*下面两个成员是给拥有本消息的驱动选用的.spi_master会使用它们.自己最好不要使用*/ 33     struct list_head    queue;/*用于将该message链入bitbang等待队列*/ 34     void            *state; 35 }; struct spi_message {   struct list_head    transfers;   //此次消息的传输队列,一个消息可以包含多个传输段    struct spi_device *spi;        //传输的目的设备    unsigned      is_dma_mapped:1;  //如果为真,此次调用提供dma和cpu虚拟地址    void          (*complete)(void *context);  //异步调用完成后的回调函数    void         *context;                    //回调函数的参数    unsigned      actual_length;               //此次传输的实际长度    int         status;                      //执行的结果,成功被置0,否则是一个负的错误码    struct list_head   queue;   void          *state;   };      在有消息需要传递的时候,会将spi_transfer通过自己的transfer_list字段挂到spi_message的transfers链表头上。spi_message用来原子的执行spi_transfer表示的一串数组传输请求。这个传输队列是原子的,这意味着在这个消息完成之前不会有其他消息占用总线。消息的执行总是按照FIFO的顺序。 下面看一看spi_transfer: struct spi_transfer {   const void *tx_buf;  //要写入设备的数据(必须是dma_safe),或者为NULL    void       *rx_buf;  //要读取的数据缓冲(必须是dma_safe),或者为NULL    unsigned   len;      //tx和rx的大小(字节数),这里不是指它的和,而是各自的长度,他们总是相等的    dma_addr_t    tx_dma;   //如果spi_message.is_dma_mapped是真,这个是tx的dma地址    dma_addr_t rx_dma;   //如果spi_message.is_dma_mapped是真,这个是rx的dma地址    unsigned   cs_change:1;    //影响此次传输之后的片选,指示本次tranfer结束之后是否要重新片选并调用setup改变设置,这个标志可以较少系统开销u8        bits_per_word;  //每个字长的比特数,如果是0,使用默认值    u16        delay_usecs;    //此次传输结束和片选改变之间的延时,之后就会启动另一个传输或者结束整个消息    u32       speed_hz;       //通信时钟。如果是0,使用默认值    struct list_head transfer_list; //用来连接的双向链表节点    };   spi_bitbang struct spi_bitbang结构用于控制实际的数据传输.  1 struct spi_bitbang {  2     struct workqueue_struct    *workqueue;/*工作队列*/  3     struct work_struct    work; 11     struct spi_master    *master;/*bitbang所属的master*/ 16     int    (*setup_transfer)(struct spi_device *spi, 17             struct spi_transfer *t);/*用于设置设备传输时的时钟,字长等*/ 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 26     int    (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t); 29     u32    (*txrx_word[4])(struct spi_device *spi, 30             unsigned nsecs, 31             u32 word, u8 bits); 32 }; struct spi_bitbang {      int    (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t); 这是一个完成数据传输的重要结构体,数据传输是SPI接口的任务,结构体master代表了一个接口,当一个spi_message从上层函数传递下来时,master的成员函数bitbang->master->transfer将该数据传输任务添加到工作队列头。其中工作队列struct workqueue_struct *workqueue;的创建和 struct work_struct work的初始化都是在函数spi_bitbang_start()中进行的。 每次数据传输,都将要传输的数据分成多个数据段,这些数据段由数据管理结构体spi_transfer来管理。结构体spi_transfer又将挂在m->transfers。也就是说每次数据传输都将要传输的数据包装成一个结构体spi_message传输下来。 函数hw_txbyte()将要传输的数据段的第一个数据写入SPI数据寄存器XXXX_SPIDAT。即便是数据接收也得向数据寄存器写入数据才能触发一次数据的传输。只需将该数据段的第一个数据写入数据寄存器就可以触发数据传输结束中断,以后的数据就在中断处理函数中写入数据寄存器。 3.子系统初始化即match函数 SPI子系统初始化的第一步就是将SPI总线注册进内核,并且在/sys下创建一个spi_master的类,以后注册的从设备都将挂接在该总线下.  下列函数位于drivers/spi/spi.c中:  1 static int __init spi_init(void)  2 {  5     buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);/*初始化缓存*/ 11     status = bus_register(&spi_bus_type);/*注册spi总线,此步骤之后就会在/sys/bus目录下生成spi子目录*/ 15     status = class_register(&spi_master_class);/*注册spi类,此步骤之后就会在/sys/class目录下生成spi_master子目录*/ 27 } 我们来看spi_bus_type的定义: 16 struct bus_type spi_bus_type = { 17     .name        = "spi", 18     .dev_attrs    = spi_dev_attrs, 19     .match        = spi_match_device, 20     .uevent        = spi_uevent, 21     .pm        = &spi_pm,/*和电源管理相关的一些函数的结构封装*/ 22 }; 来看看spi_match_device函数都做了什么:  1 /* 名词解释of: OpenFirmware  2  * 调用层次spi_match_device-->of_driver_match_device-->of_match_device-->  3  * of_match_node  4  * 用于驱动程序检查platform_device是否在其支持列表里  5  */  6 static int spi_match_device(struct device *dev, struct device_driver *drv)  7 {  8     const struct spi_device    *spi = to_spi_device(dev);  9     const struct spi_driver    *sdrv = to_spi_driver(drv); 10  12     /* 不匹配返回0;匹配返回非0,指向struct of_device_id类型的指针 13      * dev:需要查找的设备; drv:驱动程序结构体 */ 15     if (of_driver_match_device(dev, drv)) 16         return 1; 17  22     /*在驱动查找设备ID,找到返回真,否则假*/ 23     if (sdrv->id_table) 24         return !!spi_match_id(sdrv->id_table, spi); 25  26     return strcmp(spi->modalias, drv->name) == 0;/*比较设备别名和驱动名称,匹配返回真*/ 27 } 4.master驱动  1 int spi_register_board_info(struct spi_board_info const *info, unsigned n)  2 {  3     struct boardinfo *bi;  4     int i;  5   6     bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);/*为结构体boardinfo分配内存空间*/ 10     for (i = 0; i < n; i++, bi++, info++) { 11         struct spi_master *master; 12  13         memcpy(&bi->board_info, info, sizeof(*info)); 14         mutex_lock(&board_lock); 15         list_add_tail(&bi->list, &board_list);/*添加到板级描述符链表*/ 16         list_for_each_entry(master, &spi_master_list, list)/*将SPI主机控制类链表所有的节点匹配板级信息的设备初始化*/ 17             spi_match_master_to_boardinfo(master, &bi->board_info);//根据boardinfo创建新设备 19     } 22 } 一个结构体spi_board_info对应着一个SPI设备spi_device.函数中出现的board_list和spi_master_list都是全局的链表,她们分别记录了系统中所有的boardinfo和所有的spi_master.  1 static struct platform_driver davinci_spi_driver = {  2     .driver = {  3         .name = "spi_davinci",  4         .owner = THIS_MODULE,  5         .of_match_table = davinci_spi_of_match,  6     },  7     .probe = davinci_spi_probe,  9 };   1 static int davinci_spi_probe(struct platform_device *pdev)   2 {  12     /*分配master结构体,其中包括davinci_spi结构的内存空间,使用master.dev.driver_data指向它*/  13     master = spi_alloc_master(&pdev->dev, sizeof(struct davinci_spi));  18   19     dev_set_drvdata(&pdev->dev, master);/*pdev->dev.device_private->driver_data = master*/  20   21     dspi = spi_master_get_devdata(master);/*就是获取上文master.dev.driver_data指向的对象地址,其实就是davinci_spi结构对象的空间地址,将  22     其赋给dspi*/  28     /*下面这几行就是填充dspi的pdata字段*/  29     if (pdev->dev.platform_data) {  30         pdata = pdev->dev.platform_data;/*具体到对于dm365来说就是dm365_spi0_pdata*/  31         dspi->pdata = *pdata;  32     }   39     /* pdata in dspi is now updated and point pdata to that */  40     pdata = &dspi->pdata;/*pdata指针再指向dspi->pdata*/  73     /*设置bitbang的所属master*/  74     dspi->bitbang.master = spi_master_get(master);  87     master->dev.of_node = pdev->dev.of_node;  88     master->bus_num = pdev->id;/*bus_num*/  89     master->num_chipselect = pdata->num_chipselect;/*保存SPI主机控制器支持的片选数量.具体到dm365可以看到dm365_spi0_pdata中将其定义为2*/  90     master->setup = davinci_spi_setup;  92     /*设置bitbang控制传输的相关函数*/  93     dspi->bitbang.chipselect = davinci_spi_chipselect;  94     dspi->bitbang.setup_transfer = davinci_spi_setup_transfer;  96     dspi->version = pdata->version;/*具体到dm365可以看到dm365_spi0_pdata中将其定义为0*/ 159     ret = spi_bitbang_start(&dspi->bitbang);/*注册我们的主机SPI控制器*/ 185 } 该函数首先为spi_master结构体以及davinci_spi结构体分配了空间,同时,spi_master.dev.driver_data指向了davinci_spi.接着执行了该条语句: pdata = pdev->dev.platform_data;/*具体到对于dm365来说就是dm365_spi0_pdata*/ dspi->pdata = *pdata; NOTE:在这里获取platform_device.dev.platform_data,也就是平台设备的相关数据,这是平台设备移植最需要关注的地方. 随后,为master定义了setup方法,为bitbang定义了3个方法.之后获取了一系列的资源,同时注册了中断服务程序.接着再初始化了completion,这个东东将用于实现同步I/O,他的伟大之处后面会体现出来的.最后调用spi_bitbang_start注册主机控制器.我们来看这个函数,在drivers/spi/spi_bitbang.c中:  1 int spi_bitbang_start(struct spi_bitbang *bitbang)  2 {  3     struct spi_master *master = bitbang->master;  4     int status;  9     INIT_WORK(&bitbang->work, bitbang_work);/*初始化一个struct work,处理函数为bitbang_work*/ 10     spin_lock_init(&bitbang->lock);/*初始化自旋锁*/ 11     INIT_LIST_HEAD(&bitbang->queue);/*初始化链表头,链表为双向循环链表*/ 16     /*检测bitbang中的函数是否都定义了,如果没定义,则默认使用spi_bitbang_xxx*/ 17     if (!master->transfer)/*master的transfer方法没有定义过*/ 18         master->transfer = spi_bitbang_transfer;/*使用默认的spi_bitbang_transfe方法*/ 19     if (!bitbang->txrx_bufs) /*如果bitbang没有txrx_bufs方法,其实对于davinci在davinci_spi_probe函数中定义过该方法*/ 20         bitbang->use_dma = 0; 21         bitbang->txrx_bufs = spi_bitbang_bufs; 35     /* this task is the only thing to touch the SPI bits */ 36     bitbang->busy = 0; 37     bitbang->workqueue = create_singlethread_workqueue( 38             dev_name(master->dev.parent));/*创建bitbang的工作队列*/ 47     status = spi_register_master(master);/*注册spi控制器*/ 57 } 定义了控制器的transfer方法为spi_bitbang_transfer.创建了一个工作队列和一个工作bitbang_work,同时创建了一个链表.最后,调用了spi_register_master函数,该函数将完成SPI控制器的注册,其中还牵涉到spi_device的注册.  1 int spi_register_master(struct spi_master *master)  2 { 19     if (master->num_chipselect == 0)/*SPI主控制器支持的片选数当然不能为0,否则还怎么挂接从设备啊.一个接口对应一个master,一个master对应 20     一条SPI总线,一条总线上可能挂有多个设备,num_chipselect就表示该总线上的设备数*/ 21         return -EINVAL; 27     if (master->bus_num < 0) {/*总线号从最大开始减*/ 28         /* FIXME switch to an IDR based scheme, something like 29          * I2C now uses, so we can't run out of "dynamic" IDs 30          */ 31         master->bus_num = atomic_dec_return(&dyn_bus_id); 32         dynamic = 1; 33     } 37     master->bus_lock_flag = 0;/*这个标志指示SPI总线是否被锁*/ 42     dev_set_name(&master->dev, "spi%u", master->bus_num); 43     status = device_add(&master->dev);/*向内核注册设备*/ 50     if (master->transfer)/*对于具体到davinci,此字段在spi_bitbang_start中被初始化为spi_bitbang_transfer*/ 51         dev_info(dev, "master is unqueued, this is deprecated\n"); 52     else { 53         status = spi_master_initialize_queue(master); 54         if (status) { 55             device_unregister(&master->dev); 56             goto done; 57         } 58     } 61     list_add_tail(&master->list, &spi_master_list);/*把这个SPI主机控制器添加进全局的spi_master_list链表*/ 62     list_for_each_entry(bi, &board_list, list)/*遍历全局的board_list链表,为每一个boardinfo结构节点查找其中的指向的spi_board_info结构,通过 63     对spi_board_info的bus_bum和SPI主机控制器(spi_master)的bus_num进行匹配,来确定SPI从设备是否由此SPI主机控制器来控制.如果匹配,则通 64     过调用spi_new_device函数创建spi_device从设备,并且将其注册进内核*/ 65         spi_match_master_to_boardinfo(master, &bi->board_info); 73 } 该函数注释一目了然,我们来看看spi_match_master_to_boardinfo这个函数吧.  1 /*使用SPI主控制类和板级信息匹配则添加一个新设备*/  2 static void spi_match_master_to_boardinfo(struct spi_master *master,  3                 struct spi_board_info *bi)  4 {  5     struct spi_device *dev;  6   7     if (master->bus_num != bi->bus_num)/*通过bus_num对spi设备和master进行匹配*/  8         return;  9  10     dev = spi_new_device(master, bi);/*执行到此,表示匹配完成,SPI设备由该SPI接口来控制,开始创建spi_device*/ 11     if (!dev) 12         dev_err(master->dev.parent, "can't create new device for %s\n", 13             bi->modalias); 14 } 地球人都知道这段代码什么意思,好了继续看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; 14     proxy = spi_alloc_device(master);/*分配spi_device结构,并初始化一些字段*/ 19  20     /*从spi_board_info获取SPI从设备的参数*/ 21     proxy->chip_select = chip->chip_select; 22     proxy->max_speed_hz = chip->max_speed_hz; 23     proxy->mode = chip->mode; 24     proxy->irq = chip->irq; 25     strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias)); 26     proxy->dev.platform_data = (void *) chip->platform_data; 27     proxy->controller_data = chip->controller_data; 28     proxy->controller_state = NULL; 29  30     status = spi_add_device(proxy);/*将新设备添加进内核*/ 38 } //先来看scan_boardinfo这个分支    static void scan_boardinfo(struct spi_master *master)   {       struct boardinfo    *bi;       mutex_lock(&board_lock);              //找到我们注册的spi相关的板级信息结构体        //还记得board_list吧        list_for_each_entry(bi, &board_list, list) {           struct spi_board_info   *chip = bi->board_info;           unsigned        n;              //因为可能存在多个spi总线,因此spi信息结构也会有        //多个,找到bus号匹配的就对了            for (n = bi->n_board_info; n > 0; n--, chip++) {               if (chip->bus_num != master->bus_num)                   continue;               /* NOTE: this relies on spi_new_device to               * issue diagnostics when given bogus inputs               */                              //找到了就要实例化它上面的设备了                (void) spi_new_device(master, chip);           }       }       mutex_unlock(&board_lock);   }  //继续spi_add_device函数    int spi_add_device(struct spi_device *spi)   {       static DEFINE_MUTEX(spi_add_lock);       struct device *dev = spi->master->dev.parent;       struct device *d;       int status;       /* Set the bus ID string */       //设备节点名字,形式:spi0.0        dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->master->dev),               spi->chip_select);     //确保设备不会重复注册        d = bus_find_device_by_name(&spi_bus_type, NULL, dev_name(&spi->dev));               //设置spi模式和时钟速率        //会调用spi->master->setup函数设置        status = spi_setup(spi);       //将该实例化的设备添加到总线        status = device_add(&spi->dev);   }   //最后看下spi_setup函数    int spi_setup(struct spi_device *spi)   {       unsigned    bad_bits;       int     status;       if (!spi->bits_per_word)           spi->bits_per_word = 8;                      //最后调用控制器平台相关的setup成员设置该spi设备        status = spi->master->setup(spi); }   //回头看下一开始下面的那个分支of_register_spi_devices    void of_register_spi_devices(struct spi_master *master)   {     //从控制器master->dev.of_node中去获取注册SPI设备spi_device的信息,然      //后分配结构体spi_device并注册        for_each_child_of_node(master->dev.of_node, nc) {           /* Alloc an spi_device */           spi = spi_alloc_device(master);           if (!spi) {               dev_err(&master->dev, "spi_device alloc error for %s/n",                   nc->full_name);               spi_dev_put(spi);               continue;           }         } }  

上一篇:Pie Chart 学习例子
下一篇:Apache CXF实战之六 创建安全的Web Service

相关文章

关键词: spi子系统

相关评论