既然知道了协议了,那么就可以开始去瞧瞧linux kenerl中的spi的驱动代码了,代码中有很多的结构体,还是对主要的结构体先做个了解吧,那样才可以很好的理解驱动。主要是include/linux/spi.h
首先是SPI的主机和从机通信接口,也就是SPI总线,
extern struct bus_type spi_bus_type;
bus_type定义在linux/device.h中
struct bus_type { const char *name; //总线的名字 struct bus_attribute *bus_attrs; struct device_attribute *dev_attrs; struct driver_attribute *drv_attrs; //总线上的device和driver的匹配,匹配成功返回非0值 int (*match)(struct device *dev, struct device_driver *drv); int (*uevent)(struct device *dev, struct kobj_uevent_env *env); //当新的device或driver加到总线上的时候,调用driver中的probe函数经行匹配 int (*probe)(struct device *dev); int (*remove)(struct device *dev); void (*shutdown)(struct device *dev); int (*suspend)(struct device *dev, pm_message_t state); int (*resume)(struct device *dev); const struct dev_pm_ops *pm; struct subsys_private *p; };
SPI设备
struct spi_device { struct device dev; struct spi_master *master; //SPI控制器 u32 max_speed_hz; //最大时钟频率 u8 chip_select; //片选 u8 mode; //SPI模式 #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; //一次传输的bits,可以是8、16、32,默认是8 int irq; void *controller_state; void *controller_data; char modalias[SPI_NAME_SIZE]; //别名,用于device和driver的匹配 };
SPI驱动
struct spi_driver { const struct spi_device_id *id_table; int (*probe)(struct spi_device *spi); //绑定驱动和SPI设备 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; };
SPI主控制器
struct spi_master { struct device dev; //驱动的设备接口 struct list_head list; //SPI控制器的链表头 s16 bus_num; //总线号 /* chipselects will be integral to many controllers; some others * might use board-specific GPIOs. */ u16 num_chipselect; //SPI设备的片选号 u16 dma_alignment; //dma模式 /* spi_device.mode flags understood by this controller driver */ u16 mode_bits; /* 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 */ /* lock and mutex for SPI bus locking */ spinlock_t bus_lock_spinlock; struct mutex bus_lock_mutex; bool bus_lock_flag; int (*setup)(struct spi_device *spi); //更新SPI设备的模式和SPI设备的采样时钟 int (*transfer)(struct spi_device *spi, //添加一个消息到控制器的传输队列 struct spi_message *mesg); void (*cleanup)(struct spi_device *spi); };
SPI传输
struct spi_transfer { /* it's ok if tx_buf == rx_buf (right?) * for MicroWire, one buffer must be null * buffers must work with dma_*map_single() calls, unless * spi_message.is_dma_mapped reports a pre-existing mapping */ const void *tx_buf; //要写的数据 void *rx_buf; //要读的数据 unsigned len; //数据长度 dma_addr_t tx_dma; //tx_buf的DMA地址 dma_addr_t rx_dma; //rx_buf的DMA地址 unsigned cs_change:1; u8 bits_per_word; //传输的bytes数,不选就用默认的 u16 delay_usecs; //微秒延时,用以传输数据后,改变片选信号前 u32 speed_hz; //传输速率,不选就用默认的 struct list_head transfer_list; //传输链表,用以传输spi_message };
SPI消息
struct spi_message { struct list_head transfers; // struct spi_device *spi; //加到传输队列中的spi设备 unsigned is_dma_mapped:1; //DMA传输控制位 /* completion is reported through a callback */ void (*complete)(void *context); //传输完成 void *context; //complete函数的参数 unsigned actual_length; //所有成功传输字段的总长度 int status; //传输成功返回0,否则返回错误 /* 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. */ struct list_head queue; void *state; };
SPI bitbang
struct spi_bitbang { struct workqueue_struct *workqueue; struct work_struct work; spinlock_t lock; struct list_head queue; u8 busy; u8 use_dma; u8 flags; /* extra spi->mode support */ struct spi_master *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); };
在SPI控制器里面最常用的用来处理传输的结构体spi_bitbang了。
SPI borad info
struct spi_board_info { /* the device name and module name are coupled, like platform_bus; * "modalias" is normally the driver name. * * platform_data goes to spi_device.dev.platform_data, * controller_data goes to spi_device.controller_data, * irq is copied too */ char modalias[SPI_NAME_SIZE]; const void *platform_data; void *controller_data; int irq; /* slower signaling on noisy or low voltage boards */ u32 max_speed_hz; /* bus_num is board specific and matches the bus_num of some * spi_master that will probably be registered later. * * chip_select reflects how this chip is wired to that master; * it's less than num_chipselect. */ u16 bus_num; u16 chip_select; /* mode becomes spi_device.mode, and is essential for chips * where the default of SPI_CS_HIGH = 0 is wrong. */ u8 mode; /* ... may need additional spi_device chip config data here. * avoid stuff protocol drivers can set; but include stuff * needed to behave without being bound to a driver: * - quirks like clock rate mattering when not selected */ };
控制器里会读取borad info里的参数
SPI gpio_platform_data
struct spi_gpio_platform_data { unsigned sck; unsigned mosi; unsigned miso; u16 num_chipselect; };
因为我用的比较多的是GPIO模拟的,所以还是记录下这个从platform传进来的管脚号。
OK,对于SPI用到的结构体基本上已经介绍完了,那么接下来就介绍其主要函数了。