Linux下SPI设备驱动实验:SPI设备驱动框架编写

时间:2024-04-20 07:20:14

一.  简介

Linux下的SPI 驱动框架和 I2C 很类似,都分为主机控制器驱动和设备驱动,SPI主机控制器是半导体厂商编写的,我们只需要编写 SPI设备驱动代码。

本实验的最终目的就是驱动 I.MX6ULL-ALPHA 开发板上的 ICM-20608 这个 SPI 接口的六轴传感器,应用程序读取 ICM-20608 的原始传感器数据。

前一篇文章创建了SPI节点及SPI设备节点,文章如下:

Linux下SPI设备驱动实验:验证SPI节点及ICM20608设备子节点-****博客

SPI设备驱动实现思路:实现SPI设备驱动框架,加入字符设备驱动框架,再实现SPI数据读 / 写函数。

本文开始编写SPI设备驱动框架。

二.  Linux下SPI设备驱动实验:SPI设备驱动框架编写

1.  创建工程

(1)创建 18_spi 工程目录,将 17_i2c工程下的 .vscode 拷贝到 18_spi 工程:

wangtian@wangtian-virtual-machine:~/zhengdian_Linux/Linux_Drivers$ mkdir 18_spi
wangtian@wangtian-virtual-machine:~/zhengdian_Linux/Linux_Drivers$ cp ./17_i2c/.vscode/ ./18_spi/ -rf

注意:这里拷贝 .vscode目录及其下的文件,因为 .vscode目录下的文件设置了所调用的内核源码的路径。因为驱动代码会调用到内核源码中一些头文件或函数。

(2)  将 17_i2c工程下的 Makefile 拷贝到 18_spi工程:

wangtian@wangtian-virtual-machine:~/zhengdian_Linux/Linux_Drivers/18_spi$ cp ../17_i2c/Makefile ./

(3) 进入 18_spi工程下,创建 icm20608.h文件与spi_icm20608.c文件。

更改 Makefile文件中目标文件名,更改后如下:

obj-m := spi_icm20608.o

2.  SPI设备驱动框架编写

vscode打开 17_i2c工程目录,接下来开始编写 I2C设备驱动框架。

注意:构造 spi_driver结构体,注册 spi_driver与删除 spi_driver,SPI设备驱动框架代码的实现都可以参考内核源码中一些设备,因为内核源码中也有很多 spi设备驱动实现。找一个支持设备树匹配的结构体。

在 spi_icm20608.c文件中实现  SPI设备驱动框架,spi_icm20608.c文件如下:

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/of.h>
#include <linux/spi/spi.h>
#include <linux/delay.h>


static int icm20608_probe(struct spi_device* spi_dev)
{
    int ret = 0;
    printk("icm20608_probe!\n");
    return ret;
}

static int icm20608_remove(struct spi_device* spi_dev)
{
    printk("icm20608_remove!\n");
    return 0;
}

//传统驱动与设备匹配方法
static struct spi_device_id spi_device_id_table[] = {
    {"icm20608", 0},
    { }
};

//设备树匹配方法
static struct of_device_id of_device_table[] = {
    {.compatible = "alientek,icm20608"},  //必须与设备树中设备节点compatible值一致
    { }
};

/*SPI驱动结构体*/
struct spi_driver icm20608_driver = {
    .driver = {
        .name = "icm20608",
        .owner = THIS_MODULE,
        .of_match_table = of_match_ptr(of_device_table),
    },
    .id_table = spi_device_id_table,
    .probe = icm20608_probe,
    .remove = icm20608_remove,
};

/*模块加载 */
static int __init icm20608_init(void)
{
    return spi_register_driver(&icm20608_driver);
}

/*模块卸载 */
static void __exit icm20608_exit(void)
{
    spi_unregister_driver(&icm20608_driver);
}

/*驱动加载与卸载 */
module_init(icm20608_init);
module_exit(icm20608_exit);
MODULE_LICENSE("GPL"); //模块 Licence
MODULE_AUTHOR("WeiWuXian"); //作者

三. 编译驱动

对以上的驱动代码进行模块编译:

wangtian@wangtian-virtual-machine:~/zhengdian_Linux/Linux_Drivers/18_spi$ make
make -C /home/wangtian/zhengdian_Linux/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga M=/home/wangtian/zhengdian_Linux/Linux_Drivers/18_spi modules
make[1]: 进入目录“/home/wangtian/zhengdian_Linux/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga”
  CC [M]  /home/wangtian/zhengdian_Linux/Linux_Drivers/18_spi/spi_icm20608.o
  Building modules, stage 2.
  MODPOST 1 modules
  LD [M]  /home/wangtian/zhengdian_Linux/Linux_Drivers/18_spi/spi_icm20608.ko
make[1]: 离开目录“/home/wangtian/zhengdian_Linux/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga”

可以看出,驱动模块编译好。

接下来对驱动模块进行测试加载,确定SPI驱动是否与设备匹配成功。测试方法前面已经说过,验证驱动与设备是否匹配,其实与 I2C通信一样的,可以参考如下文章:

I2C驱动实验:测试I2C驱动是否与设备匹配-****博客