现在的位置: 首页 > 综合 > 正文

一 linux spi子系统(框架)

2013年08月03日 ⁄ 综合 ⁄ 共 16424字 ⁄ 字号 评论关闭

一.spi设备

struct spi_device {
	struct device	dev;	//设备文件
	struct spi_master	*master;	//spi主机
	u32	max_speed_hz;	//最大速率
	u8	chip_select;	//片选
	u8	mode;	//模式
	u8	bits_per_word;	//一个字有多少位
	int	irq;	//中断号
	void	*controller_state;	//控制器状态
	void	*controller_data;	//控制器数据
	char	modalias[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

struct spi_device *spi_new_device(struct spi_master *master,struct spi_board_info *chip)
{
	struct spi_device	*proxy;
	int	status;
	
	proxy = spi_alloc_device(master);	//3.1 spi设备初始化
	if (!proxy)
		return NULL;
	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设备引用计数
		return NULL;
	}
	return proxy;
}
EXPORT_SYMBOL_GPL(spi_new_device);

 

3.1.分配spi设备

struct spi_device *spi_alloc_device(struct spi_master *master)
{
	struct spi_device	*spi;
	struct device		*dev = master->dev.parent;

	if (!spi_master_get(master))	//判断spi主机是否存在
		return NULL;
	spi = kzalloc(sizeof *spi, GFP_KERNEL);	//分配内存
	if (!spi) {
		dev_err(dev, "cannot alloc spi_device\n");
		spi_master_put(master);	//增加主机引用计数
		return NULL;
	}
	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);	//设备初始化
	return spi;
}
EXPORT_SYMBOL_GPL(spi_alloc_device);

3.2 添加spi设备

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;

	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;
		goto done;
	}
	status = spi_setup(spi);	//调用spi主机 setup方法
	if (status < 0) {
		dev_err(dev, "can't setup %s, status %d\n",dev_name(&spi->dev), status);
		goto done;
	}
	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);
	return status;
}
EXPORT_SYMBOL_GPL(spi_add_device);

3.2.1 spi setup方法

int spi_setup(struct spi_device *spi)
{
	unsigned	bad_bits;
	int	status;
	bad_bits = spi->mode & ~spi->master->mode_bits;	//比较spi设备的模式和spi主机支持的模式
	if (bad_bits) {	//存在不支持的模式
		dev_err(&spi->dev, "setup: unsupported mode bits %x\n",bad_bits);
		return -EINVAL;
	}
	if (!spi->bits_per_word)	//若没设置设备的每个字含多少位
		spi->bits_per_word = 8;	//则默认设置为8

	status = spi->master->setup(spi);	//调用spi主机的setup方法

	dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s""%u bits/w, %u Hz max --> %d\n",
			(int) (spi->mode & (SPI_CPOL | SPI_CPHA)),(spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",
			(spi->mode & SPI_LSB_FIRST) ? "lsb, " : "",(spi->mode & SPI_3WIRE) ? "3wire, " : "",
			(spi->mode & SPI_LOOP) ? "loopback, " : "",spi->bits_per_word, spi->max_speed_hz,status);
	return status;
}
EXPORT_SYMBOL_GPL(spi_setup);

二.spi板级设备

1.板级设备结构体

struct spi_board_info {
	char	modalias[SPI_NAME_SIZE];	//名字
	const void	*platform_data;	//平台数据
	void	*controller_data;	//控制器数据
	int	irq;			//中断号
	u32	max_speed_hz;	//最大速率
	u16	bus_num;		//spi总线编号
	u16	chip_select;	//片选
	u8	mode;			//模式
};

 

2.板级设备注册(静态注册,一般在板级初始化函数中调用)

int __init spi_register_board_info(struct spi_board_info const *info, unsigned n)
{
	struct boardinfo *bi;
	int i;

	bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);	//分配内存
	if (!bi)
		return -ENOMEM;
	for (i = 0; i < n; i++, bi++, info++) {
		struct spi_master *master;
		memcpy(&bi->board_info, info, sizeof(*info));	//设置bi的板级信息
		mutex_lock(&board_lock);
		list_add_tail(&bi->list, &board_list);	//添加bi->list到全局board_list链表
		list_for_each_entry(master, &spi_master_list, list)	//遍历spi主机链表
			spi_match_master_to_boardinfo(master, &bi->board_info);
		mutex_unlock(&board_lock);
	}
	return 0;
}

2.1.spi板级设备与spi主机匹配

static void spi_match_master_to_boardinfo(struct spi_master *master,struct spi_board_info *bi)
{
	struct spi_device *dev;
	if (master->bus_num != bi->bus_num)
		return;
	dev = spi_new_device(master, bi);
	if (!dev)
		dev_err(master->dev.parent, "can't create new device for %s\n",bi->modalias);
}

三.spi设备驱动

1.spi设备驱动结构体

struct spi_driver {
	const struct spi_device_id *id_table;	//spi设备id表
	int		(*probe)(struct spi_device *spi);	//probe方法(探测到设备)
	int		(*remove)(struct spi_device *spi);	//remove方法(设备移除)
	void	(*shutdown)(struct spi_device *spi);	//shutdown方法(关闭设备)
	int		(*suspend)(struct spi_device *spi, pm_message_t mesg);	//suspend方法(挂起设备)
	int		(*resume)(struct spi_device *spi);	//resume方法(唤醒设备)
	struct device_driver	driver;	//设备驱动文件
};

2.spi设备驱动注册

int spi_register_driver(struct spi_driver *sdrv)
{
	sdrv->driver.bus = &spi_bus_type;	//总线类型
	if (sdrv->probe)	//若存在probe方法
		sdrv->driver.probe = spi_drv_probe;	//设置其设备驱动文件的probe方法为spi_drv_probe
	if (sdrv->remove)	//若存在remove方法
		sdrv->driver.remove = spi_drv_remove;	//设置其设备驱动文件的remove方法为spi_drv_remove
	if (sdrv->shutdown)	////若存在shutdown方法
		sdrv->driver.shutdown = spi_drv_shutdown;	//设置其设备驱动文件的shutdown方法为spi_drv_shutdown
	return driver_register(&sdrv->driver);	//注册设备驱动
}
EXPORT_SYMBOL_GPL(spi_register_driver);

这里的probe方法会在设备与驱动匹配的时候给调用
参看really_probe函数的部分代码

if (dev->bus->probe) {		//若总线有probe方法(spi子系统的没有)
	ret = dev->bus->probe(dev);	//则调用总线的probe方法
	if (ret)
		goto probe_failed;
} 
else if (drv->probe) {	//若存在设备驱动的probe方法
	ret = drv->probe(dev);		//则调用设备驱动的probe方法
	if (ret)
		goto probe_failed;
}

 

2.1 spi_drv_probe

static int spi_drv_probe(struct device *dev)
{
	const struct spi_driver	*sdrv = to_spi_driver(dev->driver);	//根据设备文件的设备驱动找到spi设备驱动
	return sdrv->probe(to_spi_device(dev));	//调用spi设备驱动的probe方法
}

3.spi设备驱动注销

static inline void spi_unregister_driver(struct spi_driver *sdrv)
{
	if (sdrv)
		driver_unregister(&sdrv->driver);	//注销设备驱动
}

四.spi主机

1.spi主机结构体

struct spi_master {
	struct device	dev;	//spi主机设备文件
	struct list_head list;
	s16	bus_num;	//spi总线号
	u16	num_chipselect;	//片选号
	u16	dma_alignment;	//dma算法
	u16	mode_bits;	//模式位
	u16	flags;	//传输类型标志
	spinlock_t	bus_lock_spinlock;	//spi总线自旋锁
	struct mutex	bus_lock_mutex;	//spi总线互斥锁
	bool	bus_lock_flag;	//上锁标志
	int	(*setup)(struct spi_device *spi);	//setup方法
	int	(*transfer)(struct spi_device *spi,struct spi_message *mesg);	//传输方法
	void 	(*cleanup)(struct spi_device *spi);	//cleanup方法
};

1.2.flags标志

#define SPI_MASTER_HALF_DUPLEX	BIT(0)	//半双工
#define SPI_MASTER_NO_RX	BIT(1)		//不读
#define SPI_MASTER_NO_TX	BIT(2)		//不写

2.spi主机初始化spi_alloc_master

struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
{
	struct spi_master	*master;
	if (!dev)
		return NULL;
	master = kzalloc(size + sizeof *master, GFP_KERNEL);	//分配内存
	if (!master)
		return NULL;
	device_initialize(&master->dev);	//初始化主机设备文件
	master->dev.class = &spi_master_class;	//指定设备类spi_master_class
	master->dev.parent = get_device(dev);	//设置spi主机设备的父设备
	spi_master_set_devdata(master, &master[1]);	//设置设备数据
	return master;
}
EXPORT_SYMBOL_GPL(spi_alloc_master);

3.注册spi主机

int spi_register_master(struct spi_master *master)
{
	static atomic_t	dyn_bus_id = ATOMIC_INIT((1<<15) - 1);
	struct device	*dev = master->dev.parent;	//获得spi主机设备的父设备
	struct boardinfo	*bi;
	int	status = -ENODEV;
	int	dynamic = 0;

	if (!dev)
		return -ENODEV;
	if (master->num_chipselect == 0)	//判断片选个数
		return -EINVAL;
	if (master->bus_num < 0) {	//验证spi总线编号
		master->bus_num = atomic_dec_return(&dyn_bus_id);
		dynamic = 1;
	}
	spin_lock_init(&master->bus_lock_spinlock);
	mutex_init(&master->bus_lock_mutex);
	
	master->bus_lock_flag = 0;
	dev_set_name(&master->dev, "spi%u", master->bus_num);	//设置spi主机设备名
	status = device_add(&master->dev);	//添加spi主机设备
	if (status < 0)
		goto done;
	dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),dynamic ? " (dynamic)" : "");
	mutex_lock(&board_lock);
	list_add_tail(&master->list, &spi_master_list);	//spi主机list链表添加进全局spi_master_list链表
	list_for_each_entry(bi, &board_list, list)		//遍历全局board_list查找bi结构体
		spi_match_master_to_boardinfo(master, &bi->board_info);	//找到匹配的板级spi设备
		
	mutex_unlock(&board_lock);
	status = 0;
	of_register_spi_devices(master);
done:
	return status;
}
EXPORT_SYMBOL_GPL(spi_register_master);

3.1 匹配spi主机和板级spi设备

static void spi_match_master_to_boardinfo(struct spi_master *master,struct spi_board_info *bi)
{
	struct spi_device *dev;
	if (master->bus_num != bi->bus_num)	//判断是否所属的spi总线
		return;
	dev = spi_new_device(master, bi);	//添加新的spi设备
	if (!dev)
		dev_err(master->dev.parent, "can't create new device for %s\n",bi->modalias);
}

在注册板级设备或主机设备的时候都会添加
spi板级设备添加进board_list链表,spi主机设备添加进spi_master_list链表
不管是先注册spi板级设备还是先注册spi主机设备
都会调用list_for_each_entry遍历对应的要匹配的设备的链表,查找是否有匹配的例子
若找到都会调用spi_match_master_to_boardinfo函数添加spi设备

4.注销spi主机

void spi_unregister_master(struct spi_master *master)
{
	int dummy;
	mutex_lock(&board_lock);
	list_del(&master->list);	//删除链表
	mutex_unlock(&board_lock);
	dummy = device_for_each_child(&master->dev, NULL, __unregister);	//调用__unregister函数注销子设备
	device_unregister(&master->dev);	//注销设备
}
EXPORT_SYMBOL_GPL(spi_unregister_master);

4.1 注销挂载该总线上的spi子设备

static int __unregister(struct device *dev, void *null)
{
	spi_unregister_device(to_spi_device(dev));
	return 0;
}

5.spi主机设备类

static struct class spi_master_class = {
	.name	= "spi_master",
	.owner	= THIS_MODULE,
	.dev_release	= spi_master_release,
};

五.spi总线

1.spi总线结构体

struct bus_type spi_bus_type = {
	.name		= "spi",
	.dev_attrs	= spi_dev_attrs,
	.match		= spi_match_device,	//匹配方法
	.uevent		= spi_uevent,
	.suspend	= spi_suspend,
	.resume		= spi_resume,
};
EXPORT_SYMBOL_GPL(spi_bus_type);

2.设备匹配方法spi_match_device

前面的匹配方法是spi板级设备与spi主机设备的匹配方法,匹配的结果是添加新spi设备spi_new_device
这里的匹配是spi设备和spi驱动的匹配,匹配的结果是会调用spi驱动的设备驱动文件probe方法,既spi_drv_probe

static int spi_match_device(struct device *dev, struct device_driver *drv)
{
	const struct spi_device	*spi = to_spi_device(dev);
	const struct spi_driver	*sdrv = to_spi_driver(drv);

	if (of_driver_match_device(dev, drv))	//设备文件驱动表的匹配
		return 1;
	if (sdrv->id_table)	//spi设备驱动存在支持id表
		return !!spi_match_id(sdrv->id_table, spi);	//spi设备驱动表的匹配
	return strcmp(spi->modalias, drv->name) == 0;	//比较spi设备的名字和spi设备驱动的名字
}

2.1 of_driver_match_device

static inline int of_driver_match_device(const struct device *dev,const struct device_driver *drv)
{
	return of_match_device(drv->of_match_table, dev) != NULL;	//调用of_match_device函数
}

2.1.1 of_match_device

const struct of_device_id *of_match_device(const struct of_device_id *matches,const struct device *dev)
{
	if ((!matches) || (!dev->of_node))	//id表和设备节点都不存在
		return NULL;	//则返回
	return of_match_node(matches, dev->of_node);	//调用of_match_node函数
}
EXPORT_SYMBOL(of_match_device);

2.1.1.1 of_match_node //drv->of_match_table,dev->of_node

const struct of_device_id *of_match_node(const struct of_device_id *matches,const struct device_node *node)
{
	while (matches->name[0] || matches->type[0] || matches->compatible[0]) {	//名字,类型,兼容方法有一个存在
		int match = 1;
		if (matches->name[0])	//判断名字
			match &= node->name && !strcmp(matches->name, node->name);
		if (matches->type[0])	//判断类型
			match &= node->type && !strcmp(matches->type, node->type);
		if (matches->compatible[0])	//兼容方法
			match &= of_device_is_compatible(node,matches->compatible);
		if (match)	//匹配
			return matches;	//返回匹配的id
		matches++;	//matches指针++,指向下一个id
	}
	return NULL;
}
EXPORT_SYMBOL(of_match_node);

2.2 spi_match_id

static const struct spi_device_id *spi_match_id(const struct spi_device_id *id,const struct spi_device *sdev)
{
	while (id->name[0]) {	//id表的成员的名字域不为空
		if (!strcmp(sdev->modalias, id->name))	//则判断其名字是否与spi设备的名字一样
			return id;	//一样则返回该id
		id++;	//id表指针++,指向下一个id
	}
	return NULL;
}

六 spi消息和spi传输

1.spi消息结构体

struct spi_message {
	struct list_head	transfers;	//spi传输事务链表头
	struct spi_device	*spi;	//所属spi设备
	unsigned	is_dma_mapped:1;
	void	(*complete)(void *context);	
	void	*context;
	unsigned	actual_length;
	int		status;	//传输状态
	struct list_head	queue;
	void	*state;
};

2.初始化spi消息

static inline void spi_message_init(struct spi_message *m)
{
	memset(m, 0, sizeof *m);
	INIT_LIST_HEAD(&m->transfers);	//初始化spi消息的事务链表头
}

3.添加传输事务到spi传输链表

static inline void spi_message_add_tail(struct spi_transfer *t, struct spi_message *m)
{
	list_add_tail(&t->transfer_list, &m->transfers);
}

4.spi传输结构体

struct spi_transfer {
	const void	*tx_buf;	//发送缓冲区指针
	void		*rx_buf;	//接收缓冲区指针
	unsigned	len;	//消息长度
	dma_addr_t	tx_dma;	//DMA发送地址
	dma_addr_t	rx_dma;	//DMA接收地址
	unsigned	cs_change:1;	
	u8		bits_per_word;	//一个字多少位
	u16		delay_usecs;	//毫秒级延时
	u32		speed_hz;	//速率
	struct list_head transfer_list;	//传输链表头
};

 

七.spi子系统的初始化spi_init

static int __init spi_init(void)
{
	int	status;
	buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);	//分配数据收发缓冲区
	if (!buf) {
		status = -ENOMEM;
		goto err0;
	}
	status = bus_register(&spi_bus_type);	//注册spi总线
	if (status < 0)
		goto err1;	
	status = class_register(&spi_master_class);	//注册spi主机类 "/sys/class/spi_master"
	if (status < 0)
		goto err2;
	return 0;
err2:
	bus_unregister(&spi_bus_type);
err1:
	kfree(buf);
	buf = NULL;
err0:
	return status;
}
postcore_initcall(spi_init);	//入口声明 #define postcore_initcall(fn)	__define_initcall("2",fn,2)	

八.spi子系统的API

1.spi读 spi_read

static inline int spi_read(struct spi_device *spi, u8 *buf, size_t len)
{
	struct spi_transfer	t = {
			.rx_buf		= buf,
			.len		= len,
		};
	struct spi_message	m;
	spi_message_init(&m);	//spi消息初始化(初始化传输事务链表头)
	spi_message_add_tail(&t, &m);	//添加spi传输到spi消息传输链表
	return spi_sync(spi, &m);	//spi同步传输
}

 

2.spi写 spi_write

static inline int spi_write(struct spi_device *spi, const u8 *buf, size_t len)
{
	struct spi_transfer	t = {
			.tx_buf		= buf,
			.len		= len,
		};
	struct spi_message	m;
	spi_message_init(&m);	//spi消息初始化(初始化传输事务链表头)
	spi_message_add_tail(&t, &m);	//添加spi传输到spi消息传输链表
	return spi_sync(spi, &m);	//spi同步传输
}

spi的读写操作都是初始化一个spi_transfer传输结构体,并将其添加进spi消息传输事务链表中
然后通过spi_sync来同步读写操作,接着看下spi_sync的具体代码

2.1 spi_sync

int spi_sync(struct spi_device *spi, struct spi_message *message)
{
	return __spi_sync(spi, message, 0);	//调用__spi_sync函数
}
EXPORT_SYMBOL_GPL(spi_sync);

2.1.1 __spi_sync函数

static int __spi_sync(struct spi_device *spi, struct spi_message *message,int bus_locked)
{
	DECLARE_COMPLETION_ONSTACK(done);	//声明一个工作队列
	int status;
	struct spi_master *master = spi->master;	//获取spi主机

	message->complete = spi_complete;	//设置spi消息的complete方法为spi_complete
	message->context = &done;	//设置spi消息的context
	if (!bus_locked)	
		mutex_lock(&master->bus_lock_mutex);	//上锁
	status = spi_async_locked(spi, message);
	if (!bus_locked)
		mutex_unlock(&master->bus_lock_mutex);	//解锁
	if (status == 0) {
		wait_for_completion(&done);	//等待完成
		status = message->status;	//设置spi消息传输状态
	}
	message->context = NULL;
	return status;
}

 

2.1.1.1 spi_async_locked 函数

int spi_async_locked(struct spi_device *spi, struct spi_message *message)
{
	struct spi_master *master = spi->master;	//获取spi主机
	int ret;
	unsigned long flags;
	spin_lock_irqsave(&master->bus_lock_spinlock, flags);	//上自旋锁
	ret = __spi_async(spi, message);	//调用了spi异步同步方法
	spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);	//解自旋锁
	return ret;
}
EXPORT_SYMBOL_GPL(spi_async_locked);

2.1.1.1.1 __spi_async函数(异步)

static int __spi_async(struct spi_device *spi, struct spi_message *message)
{
	struct spi_master *master = spi->master;
	//主机为半双工或spi设备为3线设备
	if ((master->flags & SPI_MASTER_HALF_DUPLEX)|| (spi->mode & SPI_3WIRE)) {
		struct spi_transfer *xfer;
		unsigned flags = master->flags;	
		list_for_each_entry(xfer, &message->transfers, transfer_list) {	//遍历spi消息的传输事务链表
			if (xfer->rx_buf && xfer->tx_buf)	//判断接收或发送缓冲区是否为空
				return -EINVAL;
			if ((flags & SPI_MASTER_NO_TX) && xfer->tx_buf)	//检验无spi数据发送的情况
				return -EINVAL;
			if ((flags & SPI_MASTER_NO_RX) && xfer->rx_buf)	//检验无spi数据接收的情况
				return -EINVAL;
		}
	}
	message->spi = spi;	//设置spi消息所属的spi设备
	message->status = -EINPROGRESS;	//设置spi消息的传输状态
	return master->transfer(spi, message);	//调用spi主机的transfer方法,收发spi信息给spi设备
}

3.spi先写后读 spi_write_then_read

int spi_write_then_read(struct spi_device *spi,const u8 *txbuf, unsigned n_tx,u8 *rxbuf, unsigned n_rx)
{
	static DEFINE_MUTEX(lock);
	int	status;
	struct spi_message	message;
	struct spi_transfer	x[2];	//声明两个spi传输结构体
	u8	*local_buf;
	
	if ((n_tx + n_rx) > SPI_BUFSIZ)	//验证发送和接收的数据总和是否溢出
		return -EINVAL;
	spi_message_init(&message);		//spi消息初始化(初始化传输事务链表头)
	memset(x, 0, sizeof x);	//
	if (n_tx) {
		x[0].len = n_tx;
		spi_message_add_tail(&x[0], &message);	//添加spi传输到spi消息传输链表
	}
	if (n_rx) {
		x[1].len = n_rx;
		spi_message_add_tail(&x[1], &message);	//添加spi传输到spi消息传输链表
	}
	if (!mutex_trylock(&lock)) {	//尝试上锁 失败
		local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);	//则分配local_buf内存
		if (!local_buf)
			return -ENOMEM;
	} else
		local_buf = buf;	//指向默认分配好内存的缓冲区(spi_init中初始化的)
	memcpy(local_buf, txbuf, n_tx);	//发送缓冲区的内容复制到local_buf中
	x[0].tx_buf = local_buf;		//发送的spi传输结构体
	x[1].rx_buf = local_buf + n_tx;	//接收的spi传输结构体
	status = spi_sync(spi, &message);	//spi同步传输--发送数据
	if (status == 0)
		memcpy(rxbuf, x[1].rx_buf, n_rx);	//接收返回的数据复制到rxbuf中
	if (x[0].tx_buf == buf)
		mutex_unlock(&lock);	//解锁
	else
		kfree(local_buf);	//释放内存
	return status;
}
EXPORT_SYMBOL_GPL(spi_write_then_read);

4.spi写8位后读8位数据 spi_w8r8 

static inline ssize_t spi_w8r8(struct spi_device *spi, u8 cmd)
{
	ssize_t status;
	u8	result;
	status = spi_write_then_read(spi, &cmd, 1, &result, 1);	//写8位读8位
	return (status < 0) ? status : result;
}

5.spi写8位数据后读16位数据 spi_w8r16

static inline ssize_t spi_w8r16(struct spi_device *spi, u8 cmd)
{
	ssize_t	status;
	u16	result;
	status = spi_write_then_read(spi, &cmd, 1, (u8 *) &result, 2);	//写8位读16位
	return (status < 0) ? status : result;
}

这里的API是内核空间使用的接口,设备驱动程序调用这些API直接操作spi的读写操作,来完成任务

spi用户空间的接口由spidev.c中的spi驱动提供,见

-->二 spi 子系统(spidev.c)

抱歉!评论已关闭.