Linux SPI驱动学习——注册匹配

本文介绍了Linux SPI驱动的基本概念,包括SPI驱动框架、SPI设备与驱动的注册匹配过程。通过分析代码和内核配置,阐述了如何注册spi_driver和spi_device,并讲解了如何在内核中进行SPI设备和驱动的自动匹配,最终实现设备的探测与驱动的绑定。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

博客说明

撰写日期 2019.10.22
完稿日期 2019.10.23
最近维护 暂无
本文作者 multimicro
联系方式 multimicro@qq.com
资料链接 本文无附件资料
GitHub https://github.com/wifialan/drivers/
原文链接 https://blog.csdn.net/multimicro/article/details/102685871

开发环境

环境说明 详细信息 备注信息
操作系统 Ubunut 18.04
开发板 JZ2440-V3
Linux内核 linux-3.4.2

1. Linux SPI概述

鄙人通过查看宋宝华《Linux设备驱动开发详解–基于最新的Linux 4.0内核》 第12章:Linux设备驱动的软件架构思想,初步了解了总线设备驱动这三个名词:
总线:比如4线SPI的总线是四条线,这四条线就构成了SPI总线,但不知道这样解释合不合适,保留疑问
设备:对应的是spi_device——外设设备的抽象
驱动:对应的是spi_drivce——外设端驱动
以上解释暂保留疑问。

先知道有这三个名词吧。

下面的内容只是对SPI驱动的初步实现进行感性的认识,先实现,后谈理论分析。

1.1 SPI驱动框架

如下图所示
在这里插入图片描述
设备驱动(外设端驱动)抽象出来一个spi_driver,用外设模块所规定的传输协议收发数据,具体实现就是调用主机端的spi收发函数进行排列组合实现外设协议所规定的波形。
控制器驱动(主机端驱动)抽象出来一个spi_master,用于产生总线上的波形。比如调用spi_transfer函数发送一个16位的数据,那么在总线上就会生成一个16位的SPI波形,主机端只产生波形不干别的。

2. SPI 注册匹配

2.1 spi_drive注册

再看韦东山SPI视频时,他说参考内核中的其他代码进行编写,如sound/soc/codecs/ad1936.c文件中第374-388c行:

static struct spi_driver ad1836_spi_driver = {
   
   
	.driver = {
   
   
		.name	= "ad1836",
		.owner	= THIS_MODULE,
	},
	.probe		= ad1836_spi_probe,
	.remove		= __devexit_p(ad1836_spi_remove),
	.id_table	= ad1836_ids,
};

static int __init ad1836_init(void)
{
   
   
	return spi_register_driver(&ad1836_spi_driver);
}
module_init(ad1836_init);

Tips:在source inside中采用快捷键ctrl + ?调出Lookup References框框,然后输如spi_driver,在生成的搜索结果里面第一项展开即可直接定位至文件中的spi_driver所在行。
在这里插入图片描述


注册spi_driver的步骤为:

首先应在arch/arm/mach-s3c24xx/mach-smdk2440.c第341的大概的位置增加:

static struct platform_device *smdk2440_devices[] __initdata = {
   
   
	&s3c_device_ohci,
	&s3c_device_lcd,
	&s3c_device_wdt,
	&s3c_device_i2c0,
	&s3c_device_iis,
	&s3c_device_spi0,	//Add
	&s3c_device_spi1,	//Add
//	&smdk2440_audio,
	&samsung_asoc_dma,
	&smdk2440_device_eth,
};

Step 1:
我仿照编写的spi_driver程序为如下:
路径:drivers/char/w25q16_spi.c

static struct spi_driver w25q16_spi_driver =
{
   
   
    .driver     =
    {
   
   
        .name   = "w25q16",	/* spi_driver注册成功后,会在/sys/bus/spi/drivers/目录下面显示出该name字段的名字,见下图 */
        .owner  = THIS_MODULE,
    },
    .probe      = w25q16_bus_spi_probe,
    .remove     = __devexit_p(w25q16_bus_spi_remove),
};

module_init(w25q16_driver_init);

在这里插入图片描述
该程序所在文件的位置为:drives/char/w25q16_spi.c
我把这个flash定为字符驱动进行编写了,所以该文件在char这个文件夹里面。
按照驱动在内核模块中的加载方式,还需要同步修改KconfigMakefile
Step 2:
Kconfig中增添信息
在这里插入图片描述
Step 3:
Makefile中增添信息

### 如何在 Linux SPI 节点上实现设备驱动程序的编写与集成 #### 设备树中的SPI节点配置 为了使新的SPI设备能够被Linux识别并加载相应的驱动,在设备树源文件(DTS)中定义新设备是必要的。对于RK3568平台而言,这涉及到修改特定于该SoC的DTS文件以包含目标SPI外设的信息[^1]。 ```dts spi@ff0c0000 { compatible = "rockchip,rk3568-spi"; reg = <0xff0c0000 0x100>; interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>; spidev@0 { /* 新增子节点 */ compatible = "spidev"; spi-max-frequency = <5000000>; // 设置最大频率为5MHz reg = <0>; // CS线编号 }; }; ``` 上述代码片段展示了如何向已存在的SPI控制器下挂接一个新的`spidev`兼容型设备实例,并指定了其工作参数如CS号以及通信速率上限等特性设置。 #### 编写对应的字符设备驱动框架 接下来就是创建实际用于控制这个虚拟SPI设备的应用层接口——即所谓的“字符设备”。这里给出一个简化版的例子来说明基本结构: ```c #include <linux/module.h> #include <linux/spi/spi.h> static int my_spi_probe(struct spi_device *spi) { printk(KERN_INFO "My SPI device driver probed\n"); return 0; } static void my_spi_remove(struct spi_device *spi) { printk(KERN_INFO "My SPI device driver removed\n"); } static struct of_device_id my_spi_of_match[] = { {.compatible = "mycompany,myspidevice"}, {}}; MODULE_DEVICE_TABLE(of, my_spi_of_match); static struct spi_driver my_spi_driver = { .driver = { .name = "my_spidev", .of_match_table = my_spi_of_match, }, .probe = my_spi_probe, .remove = my_spi_remove, }; module_spi_driver(my_spi_driver); MODULE_LICENSE("GPL"); ``` 这段C语言编写的模块实现了最基本的探测(`probe`)和移除(`remove`)回调函数;更重要的是声明了一个匹配表项用来关联之前提到过的DTB里的`compatible`字段值,从而建立起硬件实体同本驱动之间的映射关系[^2]。 #### 加载自定义驱动并与用户空间交互 完成以上两步之后,当系统启动时如果检测到了符合描述符条件的新组件,则会自动调用注册好的探针方法尝试建立连接。与此同时也可以通过/sys/class/spidev路径访问到由内核暴露出来的伪文件系统入口以便应用程序读取/写入数据流或下发命令给底层物理层执行具体动作[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值