linux spi驱动开发学习(一)-----spi子系统架构
一.spi设备(各定义在include/linux/spi.h)
structspi_device {
structdevice dev;//设备文件
structspi_master *master;//spi主机
u32 max_speed_hz; //最大速率
u8 chip_select; //片选
u8 mode; //模式
u8 bits_per_word; //一个字有多少位
intirq;//中断号
void*controller_state;//控制器状态
void*controller_data;//控制器数据
charmodalias[SPI_NAME_SIZE];//名字
};
2.spi传输模式:
#define SPI_CPHA 0x01 //时钟相位
#define SPI_CPOL 0x02 //时钟继续
#define SPI_MODE_0 (0|0) //模式0
#define SPI_MODE_1 (0|SPI_CPHA) //模式1
#define SPI_MODE_2 (SPI_CPOL|0) //模式2
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) //模式3
#define SPI_CS_HIGH 0x04 //片选高电平
#define SPI_LSB_FIRST 0x08 //LSB
#define SPI_3WIRE 0x10 //3线模式 SI和SO同一根线
#define SPI_LOOP 0x20 //回送模式
#define SPI_NO_CS 0x40 //单个设备占用一根SPI总线,所以没片选
#define SPI_READY 0x80 //从机拉低电平停止数据传输
3.spi设备的添加spi_new_device
structspi_device *spi_new_device(structspi_master *master,structspi_board_info *chip)
{
structspi_device *proxy;
intstatus;
proxy = spi_alloc_device(master); //3.1 spi设备初始化
if(!proxy)
returnNULL;
WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
proxy->chip_select = chip->chip_select; //片选
proxy->max_speed_hz = chip->max_speed_hz; //最大速率
proxy->mode = chip->mode; //模式
proxy->irq = chip->irq; //中断号
strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
proxy->dev.platform_data = (void*) chip->platform_data;
proxy->controller_data = chip->controller_data;
proxy->controller_state = NULL;
status = spi_add_device(proxy); //3.2 添加spi设备
if(status < 0) {
spi_dev_put(proxy); //增加spi设备引用计数
returnNULL;
}
returnproxy;
}
EXPORT_SYMBOL_GPL(spi_new_device);
3.1.分配spi设备
structspi_device *spi_alloc_device(structspi_master *master)
{
structspi_device *spi;
structdevice *dev = master->dev.parent;
if(!spi_master_get(master))//判断spi主机是否存在
returnNULL;
spi = kzalloc(sizeof*spi, GFP_KERNEL);//分配内存
if(!spi) {
dev_err(dev, "cannot alloc spi_device\n");
spi_master_put(master); //增加主机引用计数
returnNULL;
}
spi->master = master; //设置spi主机
spi->dev.parent = dev; //spi设备文件的父设备为spi主机设备文件的父设备
spi->dev.bus = &spi_bus_type; //总线类型
spi->dev.release = spidev_release; //释放方法
device_initialize(&spi->dev); //设备初始化
returnspi;
}
EXPORT_SYMBOL_GPL(spi_alloc_device);
3.2 添加spi设备
intspi_add_device(structspi_device *spi)
{
staticDEFINE_MUTEX(spi_add_lock);
structdevice *dev = spi->master->dev.parent;
structdevice *d;
intstatus;
if(spi->chip_select >= spi->master->num_chipselect) {
dev_err(dev, "cs%d >= max %d\n",spi->chip_select,spi->master->num_chipselect);
return-EINVAL;
}
dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->master->dev),spi->chip_select);
mutex_lock(&spi_add_lock);
d = bus_find_device_by_name(&spi_bus_type, NULL, dev_name(&spi->dev)); //查找总线上的spi设备
if(d != NULL) {//判断是否已经在使用了
dev_err(dev, "chipselect %d already in use\n",spi->chip_select);
put_device(d);
status = -EBUSY;
gotodone;
}
status = spi_setup(spi); //调用spi主机 setup方法
if(status < 0) {
dev_err(dev, "can't setup %s, status %d\n",dev_name(&spi->dev), status);
gotodone;
}
status = device_add(&spi->dev); //添加设备
if(status < 0)
dev_err(dev, "can't add %s, status %d\n",dev_name(&spi->dev), status);
else
dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));
done:
mutex_unlock(&spi_add_lock);
returnstatus;
}
EXPORT_SYMBOL_GPL(spi_add_device);
3.2.1 spi setup方法
intspi_setup(structspi_device *spi)
{
unsigned bad_bits;
intstatus;
bad_bits = spi->mode & ~spi->master->mode_bits; //比较spi设备的模式和spi主机支持的模式
if(bad_bits) {//存在不支持的模式
dev_err(&spi->dev,