Linux驱动-spi设备驱动

前言

写文章的目的是想通过记录自己的学习过程,以便以后使用到相关的知识点可以回顾和参考。

一、简介

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");
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值