RK3568驱动指南|第十五篇 I2C-第182章 使用Linux中默认的模拟I2C驱动程序

瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网网关、NVR 存储、工控平板、工业检测、工控盒、卡拉 OK、云终端、车载中控等行业。


【公众号】迅为电子

【粉丝群】258811263(加群获取驱动文档+例程)

【视频观看】嵌入式学习之Linux驱动(第十五篇 I2C_全新升级)_基于RK3568

【购买链接】迅为RK3568开发板瑞芯微Linux安卓鸿蒙ARM核心板人工智能AI主板


第182章 使用Linux中默认的模拟I2C驱动程序

在上一章中,从0编写了一个FT5X06触摸芯片的软件I2C驱动,而在实际使用中,并不需要完全从0开始编写软件I2C驱动,Linux内核中已经提供了软件I2C的驱动,在本章节中将会对Linux内核中的软件I2C驱动的使用进行讲解。

182.1 修改默认配置文件

默认情况下内核中并没有使能软件I2C,所以需要修改默认配置文件,勾选对应的配置,首先进入内核源码路径,使用以下命令进入menuconfig界面:

export ARCH=arm64

make rockchip_linux_defconfig

make menuconfig

进入menuconfig界面之后如下图所示: 

然后根据路径勾选软件I2C的配置选项,勾选完成如下图所示:

 > Device Drivers

> I2C support

> I2C Hardware Bus support

<*> GPIO-based bitbanging I2C

保存退出之后使用以下命令覆盖默认配置文件,覆盖完成如下图所示:

cp .config arch/arm64/configs/rockchip_linux_defconfig

 

至此,关于内核相关的配置就完成了。

182.2 完善设备树

i2c6:i2c6@gpio {
    compatible = "i2c-gpio";
    #address-cells = <1>;         
    #size-cells = <0>;             
    gpios = <&gpi00 RK PB4 GPIO ACTIVE_HIGH>;
             <&gpi00 RK PB3 GPIO ACTIVE_HIGH>;
    i2c-gpio,delay-us = <5>;    
    status = "disabled";        
};

内核配置修改完成之后,接下来完善该驱动对应的设备树,首先回到linux sdk根目录下,如下图所示:

然后使用以下命令对rk3568.dtsi进行修改,添加软件I2C的设备节点I2C6,添加内容如下所示:

vim kernel/arch/arm64/boot/dts/rockchip/rk3568.dtsi

 第2行的compatible属性指定了与驱动程序匹配的字符串,最终会匹配模拟GPIO驱动程序。

第5行和第6行定义了用于模拟I2C总线的两个GPIO,并设置为了高电平。

第7行的i2c-gpio,delay-us属性定义了在两个GPIO操作之间的延迟时间,以微秒为单位。这里设置为<5>表示5微秒的延迟。这在模拟I²C时序时是必需的,以确保时序符合I²C标准。

添加完成之后如下图所示:

然后使用以下命令对topeet_rk3568_lcds.dtsi进行修改,对I2C6节点进行追加,最佳FT5X06触摸芯片相关的内容,添加内容如下所示:

&i2c6 {
    status = "okay";         

    myft5x06: my-ft5x06@38 {
        compatible = "my-ft5x06"; 
        reg = <0x38>;            
    };
};

需要注意的是,由于之前编写的设备树节点名也叫myft5x06,会产生命名冲突,所以需要将之前编写的myft5x06设备树节点注释掉。修改添加完成如下图所示:

保存退出之后编译内核源码,得到boot.img镜像烧写到开发板上,为了方便,迅为已经将编译好的boot.img内核镜像放到了“iTOP-3568开发板\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动程序\112_soft_i2c_02\01_内核镜像”目录下,如下图所示:

182.3编写驱动程序

本小节使用的驱动程序模板为174.2小节完善I2C通信内容的代码,在该代码的基础上去掉了GPIO相关的内容,修改完成的驱动程序路径为“【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动程序\112_soft_i2c_02\02_module”,具体内容如下所示:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/delay.h>

// 保存 ft5x06 设备的 i2c 客户端对象指针
struct i2c_client *ft5x06_client;

// 读取 ft5x06 设备寄存器的函数
int ft5x06_read_reg(u8 reg_addr)
{
    u8 data;
    // 定义两个 i2c_msg 结构体,分别表示写操作和读操作
    struct i2c_msg msgs[2] = {
        [0] = {
            .addr = ft5x06_client->addr, // 设备地址
            .flags = 0,        // 写操作
            .len = sizeof(reg_addr),
            .buf = &reg_addr,  // 写入要读取的寄存器地址
        },
        [1] = {
            .addr = ft5x06_client->addr,
            .flags = I2C_M_RD, // 读操作
            .len = sizeof(data),
            .buf = &data,      // 读取到的数据存储位置
        },
    };

   // 使用 i2c_transfer 函数进行 i2c 总线读取操作
   // 如果读取失败,返回 -EIO 错误码
   if (i2c_transfer(ft5x06_client->adapter, msgs, ARRAY_SIZE(msgs)) != ARRAY_SIZE(msgs)){
        return -EIO;
    }

    return data; // 返回读取到的寄存器值
}

// 向 ft5x06 设备写入寄存器的函数
void ft5x06_write_reg(u8 reg_addr, u8 *data, u16 len)
{
    u8 buff[256];
    struct i2c_msg msgs[] = {
        [0] = {
            .addr = ft5x06_client->addr, // 设备地址
            .flags = 0,        // 写操作
            .len = len + 1,    // 数据长度 + 寄存器地址长度
            .buf = buff,       // 数据缓冲区
        },
    };

    buff[0] = reg_addr;       // 写入寄存器地址
    memcpy(&buff[1], data, len); // 写入数据

    // 使用 i2c_transfer 函数进行 i2c 总线写入操作
    // 如果写入失败,直接返回
    if (i2c_transfer(ft5x06_client->adapter, msgs, ARRAY_SIZE(msgs)) != ARRAY_SIZE(msgs)) {
        return;
    }
}

// ft5x06 设备的探测函数
int ft5x06_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int value;
    printk("This is ft5x06 probe\n");
    ft5x06_client = client; // 保存 i2c 客户端对象指针

    // 写寄存器
    ft5x06_write_reg(0x80, &(u8){0x4b}, 1);

    // 读寄存器
    value = ft5x06_read_reg(0x80);
    printk("reg 0x80 is %x\n", value);

    return 0;
}

// ft5x06 设备的移除函数
// 参数 client 是 i2c 客户端对象指针
int ft5x06_remove(struct i2c_client *client)
{
    // 释放中断
    return 0;
}

// 定义 i2c_device_id 结构体数组,用于标识 ft5x06 设备
static const struct i2c_device_id ft5x06_id[] = {
    { "my-ft5x06", 0 },
    { }
};

// 定义 i2c_driver 结构体,描述 ft5x06 设备驱动
static struct i2c_driver ft5x06_driver = {
    .driver = {
        .name = "my-ft5x06",
        .owner = THIS_MODULE,
    },
    .probe = ft5x06_probe,
    .remove = ft5x06_remove,
    .id_table = ft5x06_id,
};

// 驱动初始化函数
static int __init ft5x06_driver_init(void)
{
    int ret;
    // 注册 I2C 设备驱动
    ret = i2c_add_driver(&ft5x06_driver);
    if (ret < 0) {
        printk("i2c_add_driver is error\n");
        return ret;
    }
    return 0;
}

// 驱动退出函数
static void __exit ft5x06_driver_exit(void)
{
    // 注销 I2C 设备驱动
    i2c_del_driver(&ft5x06_driver);
}

module_init(ft5x06_driver_init);
module_exit(ft5x06_driver_exit);
MODULE_LICENSE("GPL");

182.4运行测试

182.4.1 编译驱动程序

首先在上一小节中的ft5x06_driver.c代码同一目录下创建 Makefile 文件,Makefile 文件内容如下所示:

export ARCH=arm64#设置平台架构
export CROSS_COMPILE=aarch64-linux-gnu-#交叉编译器前缀
obj-m += ft5x06_driver.o    #此处要和你的驱动源文件同名
KDIR :=/home/topeet/Linux/linux_sdk/kernel    #这里是你的内核目录                                                                                                                            
PWD ?= $(shell pwd)
all:
    make -C $(KDIR) M=$(PWD) modules    #make操作
clean:
    make -C $(KDIR) M=$(PWD) clean    #make clean操作

对于Makefile的内容注释已在上图添加,保存退出之后,来到存放platform_driver.c和Makefile文件目录下,如下图所示:

然后使用命令“make”进行驱动的编译,编译完成如下图所示:

编译完生成ft5x06_driver.ko目标文件,如下图所示:

182.4.2 运行测试

首先确保烧写的是182.2小节编译出来的内核镜像,然后启动开发板,开发板启动进入系统之后如下图所示:

然后查看I2C设备节点,如果存在i2c-6节点就证明内核配置正确,如下图所示:

然后将上一个小节编译完成的ko文件拷贝到开发板上,拷贝完成如下图所示:

然后使用以下命令加载驱动,加载完成如下图所示:

insmod ft5x06_driver.ko

 可以看到写入到0x80地址的0x4b数据就被成功读取了出来,证明I2C通信成功了,至此,使用内核默认的软件I2C驱动实验就测试完成。

  • 18
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值