Linux驱动-IIC完善FT5X06设备节点和驱动

提示:完善设备IIC设备节点和驱动

文章目录


前言

如前面Linux驱动-i2c 驱动框架编写,自定了节点,描述自定义的IIC 设备树来描述硬件实验。 这里我们完善设备节点并写驱动。

一、参考资料

Linux驱动-i2c 驱动框架编写

最基本的一定要了解gpio 基本知识点和pinctrl基本知识点:配置和相关API

GPIO 控制和操作-使用命令通过sysfs文件系统控制GPIO

使用C程序通过sysfs文件系统控制gpio

将原理图中的一个引脚复用为gpio功能

驱动GPIO-获取单个gpio描述符

Linux驱动-GPIO基本函数api

Linux 驱动-GPIO 三级节点获取和控制相关API

Linux驱动-GPIO子系统与pinctrl子系统相结合

总结-平台总线-中断-gpio-pinctrl-设备树

驱动设备数-of函数-获取中断资源

二、设备树-设备节点描述

MIPI屏-FT5X06 原理图

如图,mipi 对应的地板原理图描述,我们要做的就是根据地板原理图来进行设备树修改,也就是进行硬件描述,最终目的是给驱动调用。

AI-参考根据原理图自动生成相关配置

最初,我是根据经验和以前总结知识点进行配AI-置,后来发现AI 能完成大部分工作,至少帮助理解特别有用。

原理图引脚对应关系(先锁定硬件)

1. 触摸中断引脚 TP_INT_L_GPIO3_A5
  • 板上信号名:TP_INT_L_GPIO3_A5
  • RK3568 GPIO 编号:GPIO3_A5
  • FPC 座引脚:J8 Pin25 TP_INT
  • 电平特性:后缀_L = 低电平有效,触摸按下时拉低触发中断
2. 触摸复位引脚 TP_RST_L_GPIO0_B6
  • 板上信号名:TP_RST_L_GPIO0_B6
  • RK3568 GPIO 编号:GPIO0_B6
  • FPC 座引脚:J8 Pin26 TP_RST
  • 电平特性:后缀_L = 低电平复位,正常工作拉高
3、补充 I2C 总线复用引脚(配套参考)
  • I2C1_SCL_TP → GPIO0_B4(硬件 I2C 复用功能)
  • I2C1_SDA_TP → GPIO0_B5(硬件 I2C 复用功能)

GPIO 基础配置(设备树 dts 语法)

1. 中断引脚 TP_INT_L_GPIO3_A5
设备树触摸节点属性(对应你的 my-ft5x06@38)
java 复制代码
my-ft5x06: my-ft5x06@38 {
    compatible = "my-ft5x06";
    reg = <0x38>;

    // 中断配置:父控制器是gpio3
    interrupt-parent = <&gpio3>;
    // RK_PA5 = GPIO3_A5,低电平触发
    interrupts = <RK_PA5 IRQ_TYPE_LEVEL_LOW>;
    // 触摸驱动标准属性,传递中断gpio
    touch-gpio = <&gpio3 RK_PA5 IRQ_TYPE_EDGE_RISING>;

    // 复位引脚配置
    reset-gpio = <&gpio0 RK_PB6 GPIO_ACTIVE_LOW>;
};
参数拆解
  • interrupt-parent = <&gpio3>:中断控制器挂载在 GPIO3 组;
  • RK_PA5:GPIO3_A5 宏定义;
  • IRQ_TYPE_LEVEL_LOW:低电平触发中断(匹配原理图TP_INT_L);
  • touch-gpio:ft5x06 驱动专用属性,读取中断引脚;
  • reset-gpio = <&gpio0 RK_PB6 GPIO_ACTIVE_LOW>:
java 复制代码
&gpio0:复位引脚属于 GPIO0 组;
RK_PB6:GPIO0_B6;
GPIO_ACTIVE_LOW:低电平有效复位。
2. 复位引脚 TP_RST_L_GPIO0_B6

驱动内部逻辑:

上电 probe 时,内核驱动自动拉低该 GPIO 一段时间,拉高释放复位,完成 FT5x06 初始化。

Pinctrl 引脚复用核心规则(RK 平台重点)

java 复制代码
gpio3_int_tp: gpio3-int-tp {
    gpios = <&gpio3 RK_PA5 GPIO_INPUT>;
    status = "okay";
};

gpio0_rst_tp: gpio0-rst-tp {
    gpios = <&gpio0 RK_PB6 GPIO_OUTPUT_HIGH>;
    status = "okay";
};

设备树配置复位和终端硬件连接信息

配置复位脚

java 复制代码
reset-gpio =<&gpio0 RK_PB6 GPIO_ACTIVE_LOW>; 
  • 复位引脚的属性reset-gpio 是可以随便写的,这个最终是驱动里面自己去匹配的。
  • 原理图上面是:GPIO0_B6

配置中断脚

java 复制代码
# 描述中断的属性名称可不能随便写
# 描述中断类型
interrupt-parent= <&gpio3>      描述中断控制器用的是哪一个类型  TP_INT_L_GPIO3_A5
# 描述中断gpio 信息
interrupts-gpio = <&gpio3 RK_PA5 GPIO_ACTIVE_LOW>   描述gpio io 口,设置低电平有效
# 描述中断方式
interrupts = <RK_PA5 IRO_TYPE_LEVEL_LOW>
  • 其实这里有三个必备属性:中断类型、中断信息、中断方式
  • 宏定义:RK_PA5 这个是宏定义,不要问为什么。

配置pinctrl复用

配置pinctrl 复用,就是配置这个GPIO 口就是给我用的,实际还需要检查一下系统里面有没有默认给其它功能用。

java 复制代码
就需要pin-ctrl 子系统
pinctrl-names = "default";
pinctrl-0 = <&myft5x06_pins>

然后在pinctrl 里面配置好复用功能:

java 复制代码
myft5x06{

   myft5x06_pins:myft5x06-pins{ 
    // 在这里写复用功能
	rockchip,pins = <0 RK_PB6 RK_FUNC_GPIO &pcfg_pull_up>, <3 RK_PA5 R K_FUNC_GPIO &pcfg_pull_up>
	
   }

}
疑难解惑 myft5x06_pins:myft5x06-pins 配置符号
① 冒号前 myft5x06_pins:节点 Label(标签)
  • 规则:只能用字母、数字、下划线 _,不能用横杠 -;
  • 作用:全局唯一别名,别处用 &myft5x06_pins 引用这个 pinctrl 配置。
② 冒号后 myft5x06-pins:节点名称 name
  • 规则:设备树节点名允许下划线、横杠 -,只是语义标识,无引用作用;
  • 行业习惯:pinctrl 节点名字统一用 - 分隔,可读性更好。
一句话解释两者横线区别
  • Label(标签):只能 _ 下划线,不能 -;
  • Node Name(节点名):可用 - 横杠,仅做标识;
    所以标准写法:
java 复制代码
myft5x06_pins: myft5x06-pins {
    ...
};

设备树中复位和中断完整配置

基于以上基本知识点,配置如下:

路径:

java 复制代码
&i2c1 {
    status = "okay";

    myft5x06: my-ft5x06@38 {
        compatible = "my-ft5x06";
        reg = <0x38>;
        reset-gpios = <&gpio0 RK_PB6 GPIO_ACTIVE_LOW>;
        interrupt-parent = <&gpio3>;
        interrupts-gpio = <&gpio3 RK_PA5 GPIO_ACTIVE_LOW>;
        interrupts = <RK_PA5 IRQ_TYPE_LEVEL_LOW>;
        pinctrl-names = "default";
        pinctrl-0 = <&myft5x06_pins>;
    };
};

&pinctrl {
	myft5x06 {
   	 	myft5x06_pins: myft5x06-pins {
   	     	rockchip,pins =
   	     	    <0 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>,
   	     	    <3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_up>;
    		};
	};
};

三、驱动编写-完善FT5X06驱动

基本API 参考: Linux驱动-GPIO基本函数api

我们目标就是通过驱动程序去获取、操作 gpio 硬件,然后看中断是否触发

驱动程序编写

java 复制代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/of_device.h>
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <linux/interrupt.h>

struct gpio_desc *reset_gpio;
struct gpio_desc *irq_gpio;

irqreturn_t ft5x06_handler(int irq,void *args){

    printk("==========ft5x06_handler==========\n");
    return IRQ_RETVAL(IRQ_HANDLED);
}


int ft5x06_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    int ret=0;
    printk(KERN_INFO "###### This is ft5x06 probe ######\n");
    
    // 获取复位GPIO描述符
    reset_gpio =  gpiod_get_optional(&client->dev, "reset", 0);  // 第二个参数是属性(reset-gpios)前缀reset 

    if (reset_gpio == NULL)
    {
        printk("gpiod_get_optional  reset_gpio error\n");
        return -1;
    }

    // 获取中断GPIO描述符
    irq_gpio =  gpiod_get_optional(&client->dev, "interrupts", 0);  // 第二个参数是属性(interrupts-gpio)前缀interrupts

    if (irq_gpio == NULL)
    {
        printk("gpiod_get_optional  irq_gpio error\n");
        return -1;
    }

    gpiod_direction_output(reset_gpio, 0);
    ssleep(5);
    gpiod_direction_output(reset_gpio, 1);


    ret = request_irq(client->irq,ft5x06_handler,IRQF_TRIGGER_FALLING | IRQF_ONESHOT,"ft5x06_irq",NULL);

    if (ret < 0)
    {
        printk("request_irq  request error\n");
        return -1;
    }



    return 0;
}

int ft5x06_remove(struct i2c_client *client)
{
    printk(KERN_INFO "###### This is ft5x06_remove ######\n");
    return 0;
}

static const struct of_device_id ft5x06_id[] = {
    { .compatible = "my-ft5x06" },
    { /* Sentinel */ },
};
// 关键补充
MODULE_DEVICE_TABLE(of, ft5x06_id);

static struct i2c_driver ft5x06_driver = {
    .driver = {
        .owner = THIS_MODULE,
        .name = "my-ft5x06",
        .of_match_table = ft5x06_id,
    },
    .probe = ft5x06_probe,
    .remove = ft5x06_remove,
};

static int __init ft5x06_driver_init(void)
{
    int ret;
    ret = i2c_add_driver(&ft5x06_driver);
    if (ret < 0) {
        printk(KERN_ERR "i2c_add_driver failed ret=%d\n", ret);
        return ret;
    }
    printk(KERN_INFO "###### ft5x06 driver register success ######\n");
    return 0;
}

static void __exit ft5x06_driver_exit(void)
{
    i2c_del_driver(&ft5x06_driver);
    printk(KERN_INFO "###### ft5x06 driver unregister ######\n");
}

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

驱动程序实验

编译驱动文件,然后push 到目录下,加载驱动并触摸屏幕看打印日志:

编译驱动

java 复制代码
#!/bin/bash
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
obj-m += ft5x06_driver.o
KDIR :=/home/topeet/wfc/RK3568Linux/rk356x_linux/kernel
PWD ?= $(shell pwd)
all:
	make -C $(KDIR) M=$(PWD) modules

clean:
	make -C $(KDIR) M=$(PWD) clean

生成 ft5x06_driver.ko 驱动文件

执行驱动-看日志打印

加载驱动 insmod ft5x06_driver.ko ,看内核日志

日志如下,说明中断配置和驱动代码没有问题的。

总结

  • 这里在i2c 基础框架上加了复位和终端,并实际操作验证。
  • 框架方法,里面用到了基本都是之前的gpio、pinctrl 复用、中断、平台总线思想等基础知识,需要融汇贯通,涉及到的知识点需要了解并掌握。
相关推荐
阿拉斯攀登11 天前
I2C 设备驱动开发
linux·驱动开发·嵌入式硬件·嵌入式·linux驱动·i2c·字符设备驱动
ALINX技术博客1 个月前
【黑金云课堂】FPGA技术教程FPGA基础:I2C 总线通信技术
fpga开发·i2c
硬件工程师宝典1 个月前
I2C从入门到精通之一:I2C的历史起源和综合简介
服务器·嵌入式硬件·硬件架构·i2c
fffzd1 个月前
STM32:IIC与温湿度传感器(轮询模式)
stm32·单片机·嵌入式硬件·iic·通信·嵌入式软件·i2c
大阳1232 个月前
ARM.7(UART,I2C)
arm开发·单片机·嵌入式硬件·i2c·at24c02
都在酒里2 个月前
STM32 I2C通信协议详解——标准库函数实现(通讯协议总结一)
stm32·嵌入式硬件·i2c
Y多了个想法2 个月前
RK3576 android14 I2C总线,硬件I2C 与 GPIO模拟I2C 比对
经验分享·嵌入式硬件·i2c·rk·rk3576
熬夜有啥好3 个月前
基于IMXULL的SHT3X 温湿度传感器 I2C 驱动开发调试记录
驱动开发·imx6ull·i2c·sht3x温湿度传感器
zmj3203243 个月前
I2C总线协议详细介绍
单片机·嵌入式硬件·i2c·总线协议