SPI体系结构
主要由三部分组成:
(1) SPI核心
(2) SPI控制器驱动
(3) SPI设备驱动
基本和I2C的架构差不多
重要结构体
内核版本:3.7.6
- spi_master
//SPI控制器structspi_master { structdevicedev; structlist_headlist; //控制器链表//控制器对应的SPI总线号 SPI-2 对应bus_num= 2s16bus_num; u16num_chipselect;//控制器支持的片选数量,即能支持多少个spi设备 u16dma_alignment;//DMA缓冲区对齐方式u16mode_bits;// mode标志/* other constraints relevant to this driver */u16flags; /* can't do full duplex *//* can't do buffer read *//* can't do buffer write */// 并发同步时使用spinlock_tbus_lock_spinlock; structmutexbus_lock_mutex; /* flag indicating that the SPI bus is locked for exclusive use */boolbus_lock_flag; //设置SPI mode和时钟, 在spi_add_device中调用int (*setup)(structspi_device*spi); //传输数据函数, 实现数据的双向传输int (*transfer)(structspi_device*spi, structspi_message*mesg); //注销时回调void (*cleanup)(structspi_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.*/boolqueued; structkthread_workerkworker; structtask_struct*kworker_task; structkthread_workpump_messages; spinlock_tqueue_lock; structlist_headqueue; structspi_message*cur_msg; boolbusy; boolrunning; boolrt; int (*prepare_transfer_hardware)(structspi_master*master); int (*transfer_one_message)(structspi_master*master, structspi_message*mesg); int (*unprepare_transfer_hardware)(structspi_master*master); }
- spi_driver
//SPI驱动,和platform_driver,i2c_driver类似structspi_driver { conststructspi_device_id*id_table; int (*probe)(structspi_device*spi); int (*remove)(structspi_device*spi); void (*shutdown)(structspi_device*spi); int (*suspend)(structspi_device*spi, pm_message_tmesg); int (*resume)(structspi_device*spi); structdevice_driverdriver; };
- spi_device
//SPI 设备structspi_device { structdevicedev; structspi_master*master; //指向SPI控制器u32max_speed_hz; //最大速率u8chip_select; //片选u8mode; //SPI设备模式,使用下面的宏/* clock phase *//* clock polarity *//* (original MicroWire) *//* chipselect active high? *//* per-word bits-on-wire *//* SI/SO signals shared *//* loopback mode *//* 1 dev/bus, no chipselect *//* slave pulls low to pause */u8bits_per_word; intirq; void*controller_state; //控制器运行状态void*controller_data; //特定板子为控制器定义的数据charmodalias[SPI_NAME_SIZE]; };
- spi_message
//SPI传输数据结构体structspi_message { structlist_headtransfers; // spi_transfer链表头structspi_device*spi; //spi设备unsignedis_dma_mapped:1; //发送完成回调void (*complete)(void*context); void*context; unsignedactual_length; intstatus; /* 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.*/structlist_headqueue; void*state; };
- spi_transfer
// 该结构体是spi_message下的子单元,structspi_transfer { constvoid*tx_buf;// 发送的数据缓存区void*rx_buf;// 接收的数据缓存区unsignedlen; dma_addr_ttx_dma; //tx_buf的DMA地址dma_addr_trx_dma; //rx_buf的DMA地址unsignedcs_change:1; u8bits_per_word; u16delay_usecs; u32speed_hz; structlist_headtransfer_list; };
总结上面结构体关系:
1. spi_driver和spi_device
spi_driver对应一套驱动方法,包含probe,remove等方法。spi_device对应真实的物理设备,每个spi设备都需要一个spi_device来描述。spi_driver与spi_device是一对多的关系,一个spi_driver上可以支持多个同类型的spi_device。
2. spi_master和spi_device
spi_master 与 spi_device 的关系和硬件上控制器与设备的关系一致,即spi_device依附于spi_master。
3. spi_message和spi_transfer
spi传输数据是以 spi_message 为单位的,我们需要传输的内容在 spi_transfer 中。spi_transfer是spi_message的子单元。
1 . 将本次需要传输的 spi_transfer 以 spi_transfer->transfer_list 为链表项,连接成一个transfer_list链表,挂接在本次传输的spi_message spi_message->transfers链表下。
2 . 将所有等待传输的 spi_message 以 spi_message->queue 为链表项,连接成个链表挂接在queue下。
API函数
//分配一个spi_masterstructspi_master*spi_alloc_master(structdevice*dev, unsignedsize) //注册和注销spi_masterintspi_register_master(structspi_master*master) voidspi_unregister_master(structspi_master*master) //注册和注销spi_driverintspi_register_driver(structspi_driver*sdrv) voidspi_unregister_driver(structspi_driver*sdrv) //初始化spi_messagevoidspi_message_init(structspi_message*m) //向spi_message添加transfersvoidspi_message_add_tail(structspi_transfer*t, structspi_message*m) //异步发送spi_messageintspi_async(structspi_device*spi, structspi_message*message) //同步发送spi_messageintspi_sync(structspi_device*spi, structspi_message*message) //spi同步写(封装了上面的函数)intspi_write(structspi_device*spi, constvoid*buf, size_tlen) //spi同步读(封装了上面的函数)intspi_read(structspi_device*spi, void*buf, size_tlen) //同步写并读取(封装了上面的函数)intspi_write_then_read(structspi_device*spi, constvoid*txbuf, unsignedn_tx, void*rxbuf, unsignedn_rx)
使用spi_async()需要注意的是,在complete未返回前不要轻易访问你一提交的spi_transfer中的buffer。也不能释放SPI系统正在使用的buffer。一旦你的complete返回了,这些buffer就又是你的了。
spi_sync是同步的,spi_sync提交完spi_message后不会立即返回,会一直等待其被处理。一旦返回就可以重新使用buffer了。spi_sync()调用了spi_async(),并休眠直至complete返回。
上面的传输函数最终都是调用spi_master的transfer()函数。
总结
SPI的架构和之前的I2C的结构基本差不多,我们会发现其实驱动中大量的结构体都是对参数和数据的封装。站在宏观的角度看,就是填充结构体,调用函数注册或发送。
上面是对Linux中SPI相关架构的分析,后面依然会拿出一些相对应的驱动来进行具体分析。希望能做到理论和实践相结合!