上一章节我们写了 client.c,并且我们已经成功地把它加载到内核里面。i2c 用非设备树实现,我们需要
用 i2c_board_info 这个结构体来描述我们的 i2c 设备,如果我们用设备树的方法来实现,我们直接在设备树
的节点下面添加创建对应设备的节点就可以了。后面的实验我们都用设备树的,非设备树的方法了解一下
就可以了,本章节我们来设计 i2c 驱动的 driver 部分。
我们在 Ubuntu 的/home/topeet/driver/imx6ull/40i2c 目录下新建一个 driver.c 文件,拷贝前面实验的
Makefile,driver.c 文件的代码如下所示:
/*
* @Author: topeet
* @Description: i2c 总线实现 driver 驱动
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
//与设备树的 compatible 匹配
static const struct of_device_id ft5x06_id[] = {
{.compatible = "edt,edt-ft5306", 0},
{.compatible = "edt,edt-ft5x06", 0},
{.compatible = "edt,edt-ft5406", 0},
{}};
// 无设备树的时候匹配 ID 表
static const struct i2c_device_id ft5x06_id_ts[] = {
{"xxxxx", 0},
{}};
/* i2c 驱动的 remove 函数 */
int ft5x06_remove(struct i2c_client *i2c_client)
{
return 0;
}
/* i2c 驱动的 probe 函数 */
int ft5x06_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id)
{
printk("This is ft5x06_probe\n");
return 0;
}
//定义一个 i2c_driver 的结构体
static struct i2c_driver ft5x06_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "ft5x06_test",
// 采用设备树的时候驱动使用的匹配表
.of_match_table = ft5x06_id,
},
.probe = ft5x06_probe,
.remove = ft5x06_remove,
.id_table = ft5x06_id_ts};
/* 驱动入口函数 */
static int ft5x06_driver_init(void)
{
int ret;
// 注册 i2c_driver
ret = i2c_add_driver(&ft5x06_driver);
if (ret < 0)
{
printk(" i2c_add_driver is error \n");
return ret;
}
printk("This is ft5x06_driver_init\n");
return 0;
}
/* 驱动出口函数 */
static void ft5x06_driver_exit(void)
{
// 将前面注册的 i2c_driver 也从 Linux 内核中注销掉
i2c_del_driver(&ft5x06_driver);
printk("This is ft5x06_driver_exit\n");
}
module_init(ft5x06_driver_init);
module_exit(ft5x06_driver_exit);
MODULE_LICENSE("GPL");
我们参考第三十九章 Linux 内核模块将刚刚编写的驱动代码编译为驱动模块,编译完如下图所示:
在加载驱动之前,我们要恢复设备树文件中我们之前章节注释掉的节点,重新编译设备树内核,然后再烧写镜像。
开发板启动后,我们进入到/sys/bus/i2c/devices/目录下查看是否有生成 I2C 节点,如下图所示:
我们进入共享目录并且加载驱动模块,共享目录的搭建请参考第三十七章 37.2.3 搭建 nfs 共享目录,
如下图所示: