前言
写文章的目的是想通过记录自己的学习过程,以便以后使用到相关的知识点可以回顾和参考。
一、简介
SPI 驱动框架和 I2C 很类似,都分为主机控制器驱动和设备驱动:
1、SPI 主机驱动,SPI 主机驱动就是 SOC 的 SPI 控制器驱动,也叫做 SPI 适配器驱动。
2、SPI 设备驱动,SPI 设备驱动就是针对具体的 SPI 设备而编写的驱动。
.
.
.
二、SPI主机驱动
1、spi_master 结构体
SPI 主机驱动就是 SOC 的 SPI 控制器驱动,类似 I2C 驱动里面的适配器驱动。Linux 内核使用 spi_master 表示 SPI 主机驱动,spi_master 是个结构体,定义在 include/linux/spi/spi.h 文件中,SPI主机驱动程序中会完善 spi_master 的成员,然后通过函数注册spi_master 。
2、spi_master 申请与释放
spi_alloc_master 函数用于申请 spi_master,返回一个 spi_master 类型的指针。
spi_master_put 函数用于释放spi_master。
这两个函数都由drivers/spi/spi.c 核心层提供。
3、spi_master 的注册与注销
当 spi_master 初始化完成以后就需要将其注册到 Linux 内核,spi_register_master 函数用于注册spi_master 。
spi_unregister_master 函数用于注销spi_master 。
这两个函数也都由drivers/spi/spi.c 核心层提供。
.
.
.
三、SPI设备驱动
1、spi_driver 结构体
本次实践的主要内容是编写spi设备驱动,spi 设备驱动也和 i2c 设备驱动也很类似,Linux 内核使用 spi_driver 结构体来表示 spi 设备驱动,我们在编写 SPI 设备驱动的时候需要实现 spi_driver。spi_driver 结构体定义在include/linux/spi/spi.h 文件中,结构体内容如下:
struct spi_driver {
const struct spi_device_id *id_table; //id配对表
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; //需要设置里面的name成员,用于配对
};
可以看出,spi_driver 和 i2c_driver、platform_driver 基本一样,当 SPI 设备和驱动匹配成功以后 probe 函数就会执行。
2、spi_driver 的注册和注销
同样的,spi_driver 初始化完成以后需要向 Linux 内核注册,spi_driver 注册函数为spi_register_driver,函数原型如下:
int spi_register_driver(struct spi_driver sdrv)
函数参数和返回值含义如下:
sdrv:要注册的 spi_driver。
返回值:0,注册成功;赋值,注册失败。
注销 SPI 设备驱动以后也需要注销掉前面注册的 spi_driver,使用 spi_unregister_driver 函数完成 spi_driver 的注销,函数原型如下:
void spi_unregister_driver(struct spi_driver sdrv)
函数参数和返回值含义如下:
sdrv:要注销的 spi_driver。
返回值:无。
3、驱动的整体框架
字符设备spi驱动框架如下:
static int xxx_open(struct inode *inode, struct file *filp)
{
..........
}
static int xxx_release(struct inode *inode, struct file *filp)
{
...........
}
/* 接口函数集合 */
static struct file_operations xxx_fops = {
.owner = THIS_MODULE,
.open = xxx_open,
.release = xxx_release,
};
/* misc设备结构体 */
static struct miscdevice xxx_miscdev = {
.minor = MISC_DYNAMIC_MINOR, // 动态分配子设备号
.name = LEDDEV_NAME, //设备节点的名字 /dev/xxx
.fops = &xxx_fops ,
};
/* probe函数 */
static int xxx_probe(struct spi_device *spi)
{
/* 注册misc设备驱动 */
ret = misc_register(&xxx_miscdev );
............
}
/* remove函数 */
static int xxx_remove(struct spi_device *spi)
{
.........
}
/* 传统匹配方式 ID 列表 */
static const struct spi_device_id xxx_id[]={
{"xxx-名字", 0}, //设备类型(名字),id号
{},
};
/* 添加到内核spi设备列表 */
MODULE_DEVICE_TABLE(spi, xxx_id);
/* spi 驱动结构体 */
static struct spi_driver xxx_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "xxx-名字",
},
.probe = xxx_probe,
.remove = xxx_remove,
.id_table = xxx_id,
};
/* 驱动入口函数 */
static int __init xxx_init(void)
{
return spi_register_driver(&xxx_driver);
}
/* 驱动出口函数 */
static void __exit xxx_exit(void)
{
spi_unregister_driver(&xxx_driver);
}
module_init(xxx_init);
module_exit(xxx_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xzj");