博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
深入浅出spi驱动之数据结构(一)
阅读量:2256 次
发布时间:2019-05-09

本文共 6599 字,大约阅读时间需要 21 分钟。

Allein.Cao原创作品,转载请注明出处:

内核版本:2.6.32.2

硬件:S3C2440 

SPI总线是一种比较通用的数据传输总线,遵从主从模式,由主设备发起通讯请求,通常工作于全双工模式,由4条数据时钟线组成,下面这段话摘自s3c2440数据手册:

There are 4 I/O pin signals associated with SPItransfers: SCK (SPICLK0,1), MISO (SPIMISO0,1) data line, MOSI (SPIMOSI0,1) dataline and active low /SS (nSS0,1) pin (input).

  • 确定驱动文件

 SPI作为linux里面比较小的一个子系统,其驱动程序位于/drivers/spi/*目录,首先,我们可以通过Makefile及Kconfig来确定我们需要看的源文件:

Makefile:

## Makefile for kernel SPI drivers.#……………………………………………….# small core, mostly translating board-specific# config declarations into driver model codeobj-$(CONFIG_SPI_MASTER)		+= spi.o			# SPI master controller drivers (bus)…………………………………………………obj-$(CONFIG_SPI_BITBANG)		+= spi_bitbang.o…………………………………………………obj-$(CONFIG_SPI_S3C24XX_GPIO)		+= spi_s3c24xx_gpio.oobj-$(CONFIG_SPI_S3C24XX)		+= spi_s3c24xx.o…………………………………………………# 	... add above this line ...# SPI protocol drivers (device/link on bus)obj-$(CONFIG_SPI_SPIDEV)	+= spidev.o…………………………………………………# 	... add above this line ... 通过以上分析我们知道,spi驱动由三部分组成,分别是core(spi.c),master controller driver (spi_s3c24xx.c or spi_s3c24xx_gpio.)以及SPIprotocol drivers (spidev.c),这里spi_s3c24xx_gpio.c文件是用普通的io口来模拟spi时序,具体见Kconfig描述: config SPI_S3C24XX_GPIO	tristate "Samsung S3C24XX series SPI by GPIO"	depends on ARCH_S3C2410 && EXPERIMENTAL	select SPI_BITBANG	help	  SPI driver for Samsung S3C24XX series ARM SoCs using	  GPIO lines to provide the SPI bus. This can be used where	  the inbuilt hardware cannot provide the transfer mode, or	  where the board is using non hardware connected pins. 在此,我们以spi控制器方式进行分析。  
数据结构
Spi驱动涉及的数据结构主要位于/include/linux/spi.h,对各个结构有比较详细的解释,限于篇幅,简单介绍如下: 1、Spi_device代表一个外围spi设备,由master controller driver注册完成后扫描BSP中注册设备产生的设备链表并向spi_bus注册产生。 struct spi_device { struct device dev; //设备模型使用 struct spi_master *master; //设备使用的master结构 u32 max_speed_hz; //通讯时钟 u8 chip_select; //片选号,每个master支持多个spi_device u8 mode; //设备支持的模式,如片选是高or低?#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 */ u8 bits_per_word; //每个字长的比特数 int irq; //中断号 void *controller_state; //控制器寄存器状态 void *controller_data; char modalias[SPI_NAME_SIZE]; //设备名称}; 2、  spi_driver代表一个SPI protocol drivers,即外设驱动。 struct spi_driver { const struct spi_device_id *id_table; //支持的spi_device设备表 int (*probe)(struct spi_device *spi); //probe函数 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; //设备模型使用}; 3、spi_master代表一个主机控制器,此处即S3C2440中的SPI控制器 struct spi_master { struct device dev; //设备模型使用 s16 bus_num; //master编号,s3c2440有2个spi控制器,编号为0 1 u16 num_chipselect; //支持的片选的数量,从设备的片选号不能大于这个数量 u16 dma_alignment; /* spi_device.mode flags understood by this controller driver */ u16 mode_bits; //master支持的设备模式 /* 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 */ int (*setup)(struct spi_device *spi); //设置模式、时钟等 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); }; 4、spi_transfer代表一个读写缓冲对,包含接收缓冲区及发送缓冲区,其实,spi_transfer的发送是通过构建spi_message实现,通过将spi_transfer中的链表transfer_list链接到spi_message中的transfers,再以spi_message形势向底层发送数据。每个spi_transfer都可以对传输的一些参数进行设置,使得master controller按照它要求的参数进行数据发送。 struct spi_transfer { const void *tx_buf; //发送缓冲区 void *rx_buf; //接收缓冲区 unsigned len; //缓冲区长度 dma_addr_t tx_dma; dma_addr_t rx_dma; unsigned cs_change:1; // 当前spi_transfer发送完成之后重新片选? u8 bits_per_word; //每个字长的比特数,0代表使用Spi_device中的默认值 u16 delay_usecs; //发送完成一个spi_transfer后延时时间 u32 speed_hz; //速率 struct list_head transfer_list; //用于链接到spi_message}; 5、spi_message代表spi消息,由多个spi_ transfer段组成: struct spi_message {
struct list_head transfers; // spi_transfer链表队列 struct spi_device *spi; //该消息的目标设备 unsigned is_dma_mapped:1; /* completion is reported through a callback */ void (*complete)(void *context); //消息完成后调用的回调函数 void *context; //回调函数参数 unsigned actual_length; //实际传输的数据长度 int status; //该消息的发送结果,0:成功 struct list_head queue; //用于添加到bitbang的list void *state;}; 6、s3c24xx_spi代表具体的s3c2440中的spi控制器,包含了控制器的信息,如中断,寄存器等信息,定义于/drivers/spi/spi_s3c24xx.c(因为该结构与具体的硬件有关,属于linux里面的非通用代码)
struct s3c24xx_spi { /* bitbang has to be first */ struct spi_bitbang bitbang; //见下面分析 struct completion done; void __iomem *regs; int irq; int len; int count; void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol); /* data buffers */ const unsigned char *tx; unsigned char *rx; struct clk *clk; struct resource *ioarea; struct spi_master *master; struct spi_device *curdev; struct device *dev; struct s3c2410_spi_info *pdata;}; 7、struct spi_bitbang是具体的负责信息传输的数据结构,它维护一个workqueue_struct,每收到一个消息,都会向其中添加一个work_struct,由内核守护进程在将来的某个时间调用该work_struct中的function进行消息发送。 struct spi_bitbang { struct workqueue_struct *workqueue; //工作队列头,spi master初始化时建立 struct work_struct work; //spi master初始化时初始化 spinlock_t lock; struct list_head queue; //挂接spi_message u8 busy; //忙标志 u8 use_dma; u8 flags; /* extra spi->mode support */ struct spi_master *master; //对应的spi_master /* setup_transfer() changes clock and/or wordsize to match settings * for this transfer; zeroes restore defaults from spi_device. */ int (*setup_transfer)(struct spi_device *spi, //对数据传输进行设置 struct spi_transfer *t); void (*chipselect)(struct spi_device *spi, int is_on); //控制片选#define BITBANG_CS_ACTIVE 1 /* normally nCS, active low */#define BITBANG_CS_INACTIVE 0 /* txrx_bufs() may handle dma mapping for transfers that don't * already have one (transfer.{tx,rx}_dma is zero), or use PIO */ int (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t); //实际的数据传输函数 /* txrx_word[SPI_MODE_*]() just looks like a shift register */ u32 (*txrx_word[4])(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits);};
你可能感兴趣的文章
程序算法与人生选择
查看>>
bit rate / frame rate /sample rate等等
查看>>
nginx+php+mysql支持REST api
查看>>
软件的彼得原理"是什么
查看>>
delphi的Unsupported 16bit resource
查看>>
SVN版本冲突解决详解
查看>>
MySQL忘记密码(mysql5.5 for windows xp)
查看>>
远程访问VMware虚拟机Ubuntu的mysql
查看>>
禁止运行程序多个实例
查看>>
Unity直接渲染YUV几种格式
查看>>
可以下载专利文献的网址
查看>>
delphi写webservice服务会发生的一些问题
查看>>
apache下部署delphi写的cgi
查看>>
delphi TTcpClient TTcpServer分析
查看>>
svn的branch/tag
查看>>
网络传输中文本传输与二进制传输与字符集
查看>>
windows messagebox样式
查看>>
Delphi应用程序日志写入系统日志
查看>>
缺乏版本控制,软件测试易陷混乱风险
查看>>
C++中extern “C”含义深层探索
查看>>