Linux内核编程(十四)IIC总线驱动FT5X06触摸屏

news2024/11/16 1:42:24

本文目录

  • 前述:
  • 一、IIC子系统框架
  • 二、I2C设备驱动层
    • 1. i2c_client编写(C语言版-旧内核)
    • 2. i2c_client编写(设备树版-新内核)

  

前述:

对于IIC的基础知识,这里不做过多的介绍,详细情况查看下面的两篇文章。
文章一:超详细!新手必看!STM32基础-IIC串行通信协议-IO口模拟IIC操作BMP180。
文章二:Linux应用编程(四)IIC(获取BMP180温度/气压数据)。

一、IIC子系统框架

在这里插入图片描述

二、I2C设备驱动层

1. i2c_client编写(C语言版-旧内核)

这里的i2c_client相当于平台总线的设备层,即描述硬件资源,使用如下:

i2c_client.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/i2c.h>

struct i2c_adapter *i2c_ada;
struct i2c_board_info ft5x06[] = {
    { I2C_BOARD_INFO("my-ft5x06", 0x38) },
};

static int __init ft5x06_client_init(void) {
    struct i2c_client *client;

    i2c_ada = i2c_get_adapter(1);   //获取i2c1的控制器
    if (!i2c_ada) {
        printk(KERN_ERR "Failed to get i2c adapter\n");
        return -ENODEV;
    }
    
    client = i2c_new_device(i2c_ada, ft5x06); //创建一个新设备
    if (!client) {
        printk(KERN_ERR "Failed to create new i2c device\n");
        i2c_put_adapter(i2c_ada);
        return -ENODEV;
    }
    return 0;
}

static void __exit ft5x06_client_exit(void) {
    // Put the adapter back after use
    i2c_put_adapter(i2c_ada);
}

module_init(ft5x06_client_init);
module_exit(ft5x06_client_exit);
MODULE_LICENSE("GPL");

i2c_driver.c
这里是一个简单示例,为了演示如何匹配。

#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>

// Probe function
static int ft5x06_probe(struct i2c_client *client, const struct i2c_device_id *id) {
    printk(KERN_INFO "This is ft5x06_probe\n");
    return 0;  // Return 0 to indicate successful probing
}

// Remove function
static int ft5x06_remove(struct i2c_client *client) {
    return 0;
}

const struct i2c_device_id table[] = {
	{"my-ft5x06", 0},
	{}
};

static struct i2c_driver ft5x06_driver = {
    .driver = {
        .owner = THIS_MODULE,
        .name = "my-ft5x06",
    },
    .probe = ft5x06_probe,
    .remove = ft5x06_remove,
    .id_table = table,	//匹配的设备列表
};

static int __init ft5x06_driver_init(void) {
    int ret;
    ret = i2c_add_driver(&ft5x06_driver);
    if (ret < 0) {
        printk(KERN_ERR "i2c_add_driver is error\n");
        return ret;
    }
    return 0;
}

// Module exit function
static void __exit ft5x06_driver_exit(void) 
{
    i2c_del_driver(&ft5x06_driver);
}

module_init(ft5x06_driver_init);
module_exit(ft5x06_driver_exit);

MODULE_LICENSE("GPL");

2. i2c_client编写(设备树版-新内核)

   这部分相当于平台总线的设备层代码,即用于描述硬件。当然可以使用设备树来替代。那么我们在使用设备树描述时该怎么写呢?
   答:首先我们确定使用哪个I2C控制器,每个控制器都在设备树通用文件中对应一个节点(内核以有)。假设我们使用i2c控制器1。使用如下所示。

i2c_client设备树节点。

&i2c{     //相当于在i2c1节点下添加节点。
	  status = "okay";     //使能i2c1控制器
      myft5x06:my-ft5x06@38{
	      compatible="my-ft5x06";
	      reg=<0x38>;
	      //下面的内容主要为了演示而添加的,实际并不存在。
	      //复位引脚
		  reset-gpio==<&gpio0 RX_PB5 0>;  //gpio0 PB5 引脚,初始为低电平。
		  //中断引脚
		  interrupt-parent=<&gpio3>;   //使用gpio_c中断控制器。
		  interrupts-gpio = <&gpio3 RX_PA2  0>;  //gpio3 PA2引脚,初始为低电平。
		  interrupts=<36 IRQF_TRIGGER_FALLING>;   //中断号为36,触发方式为下降沿触发。

	  	  pinctrl-names = "default";  //固定属性名称,这个属性定义了引脚控制器配置的名称,default 表示默认配置。
		  pinctrl-0 = <&ft5x06_pinctrl>;
	};
};



&pinctrl{
	ft5x06_pinctrl:ft5x06-pinctrl{  //将两个引脚都复用为GPIO功能。
   		rockchip,pins = <0 RK_PB5 RK_FUNC_GPIO  &pcfg_pull_none>,<3 RK_PA2 RK_FUNC_GPIO  &pcfg_pull_none>; 
  }}


i2c_driver.c

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

struct gpio_desc *reset_gpio;
struct gpio_desc *irq_gpio;

extern struct i2c_client *ft5x06_client;
extern int ft5x06_read_reg(u8 addr);
extern void ft5x06_write_reg(u8 addr, u8 data, u16 len);

irqreturn_t interrupt_handler1(int irq, void *arg)
{
    printk("interrupt_handler1!\n");
    return IRQ_HANDLED;
}

static int ft5x06_probe(struct i2c_client *client, const struct i2c_device_id *id) 
{
    int value;
    int ret;
    printk(KERN_INFO "This is ft5x06_probe\n");
    ft5x06_client = client;
    
//获取硬件gpio资源
    reset_gpio = gpiod_get_optional(&client->dev, "reset", 0);
    if (IS_ERR(reset_gpio)) {
        dev_err(&client->dev, "Failed to get GPIO for reset\n");
        return PTR_ERR(reset_gpio);
    }

    irq_gpio = gpiod_get_optional(&client->dev, "interrupts", 0);
    if (IS_ERR(irq_gpio)) {
        dev_err(&client->dev, "Failed to get GPIO for interrupts\n");
        return PTR_ERR(irq_gpio);
    }

//复位一次
    gpiod_direction_output(reset_gpio, 0);
    mdelay(5);
    gpiod_direction_output(reset_gpio, 1);
    
//申请中断
    ret = request_irq(client->irq, interrupt_handler1, IRQF_TRIGGER_FALLING, "test_interrupt", client);  //这里触发方式要和设备树一致!
    if (ret < 0) {
        printk("request_irq error!\n");
        return ret;
    }
//测试iic读写函数
    ft5x06_write_reg(0x80, 0x4b, 1);
    value = ft5x06_read_reg(0x80);
    printk("reg0x80的值:%x\n", value);
    
    return 0;
}

static int ft5x06_remove(struct i2c_client *client) 
{
    free_irq(client->irq, client);
    return 0;
}

static const struct of_device_id ft5x06_table[] = {
    { .compatible = "my-ft5x06" },
    {}
};

static struct i2c_driver ft5x06_driver = {
    .driver = {
        .owner = THIS_MODULE,
        .name = "my-ft5x06",
        .of_match_table = ft5x06_table,   //用于与设备树匹配。
    },
    .probe = ft5x06_probe,
    .remove = ft5x06_remove,
};

static int __init ft5x06_driver_init(void) 
{
    return i2c_add_driver(&ft5x06_driver);
}

static void __exit ft5x06_driver_exit(void) 
{
    i2c_del_driver(&ft5x06_driver);
}

module_init(ft5x06_driver_init);
module_exit(ft5x06_driver_exit);

MODULE_LICENSE("GPL");

msg.c

#include <linux/i2c.h>
struct i2c_client *ft5x06_client;

int ft5x06_read_reg(u8 addr)
{
    u8 data;
    struct i2c_msg msgs[] = {
        [0] = {
            .addr  = ft5x06_client->addr,
            .flags = 0,
            .buf   = &addr,
            .len   = sizeof(addr),
        },
        [1] = {
            .addr  = ft5x06_client->addr,
            .flags = I2C_M_RD,
            .buf   = &data,
            .len   = sizeof(data),
        },
    };

    i2c_transfer(ft5x06_client->adapter, msgs, 2);
    return data;
}

void ft5x06_write_reg(u8 addr, u8 data, u16 len)
{
    u8 buff[256];
    struct i2c_msg msgs[] = {
        [0] = {
            .addr  = ft5x06_client->addr,
            .flags = 0,
            .buf   = buff,
            .len   = len + 1, // len + 1 to include the addr byte
        },
    };
    
    buff[0] = addr;
    memcpy(&buff[1], &data ,len);
    i2c_transfer(ft5x06_client->adapter, msgs, 1);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2088635.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智能地理信息系统平台应该是什么样子?

现在GIS平台除了三维GIS属于重大突破&#xff0c;这些年基本上都属于蹭热点概念&#xff0c;并在这些热点概念之间左右逢源&#xff0c;究其本质&#xff0c;还是在于没有把握好GIS的立足之本与用户之间的巨大鸿沟。回归到题目上&#xff0c;智能地理信息系统平台&#xff0c;从…

钣金展开计算工具【机械设计工具集】

一款非常实用的计算器工具&#xff0c;它可以帮助用户计算直角弯曲展开长度的工具&#xff0c;无需直角弯曲展开长度计算公式&#xff0c;选择对应的图形&#xff0c;输入已知的数据、查询α系数并输入&#xff0c;就可以快速计算出长度了&#xff01; 方便钣金件下料长度的计算…

Uniapp:WebSocket 重连之后累加触发 uni.onSocketOpen()

省流 不要用 uni.xxx 那一套&#xff0c;用 socketTask await uni.connectSocket({}) 的 socketTask 去控制 业务逻辑描述 第一次进入应用主页&#xff0c;连接 WebSocket手机熄屏之后&#xff0c;断开当前连接的 WebSocket手机亮屏之后&#xff0c;再次进入应用后&#x…

SpringBoot异常处理原理分析

springboot默认机制 错误处理的自动配置都在ErrorMvcAutoConfiguration中&#xff0c;两大核心机制&#xff1a; SpringBoot 会自适应处理错误&#xff0c;响应页面或JSON数据 SpringMVC的错误处理机制依然保留&#xff0c;MVC处理不了&#xff0c;才会交给boot进行处理 发生…

《黑神话:悟空》一只横扫全球的中国“猴子”,这里也有!

这个夏天&#xff0c;除了火辣辣的太阳让人燥热难耐&#xff0c;还有一只横空出世的“猴子”让众多网友热血沸腾——8月20日&#xff0c;筹谋7年的首款国产现象级3A游戏大作《黑神话&#xff1a;悟空》&#xff0c;准时登录各大平台&#xff0c;期待已久的玩家们一饱“猴瘾”。…

2024年第四届《英语世界》杯全国大学生翻译大赛

2024年第四届《英语世界》杯全国大学生翻译大赛 第一场下周日开考&#xff01; 一、参赛福利&#xff1a; 1、报名即可获得大赛专属题库、《英语世界》数字刊阅读权限、《英语世界》杯系列赛事公开课珍贵资料&#xff1b; 2、开展线上公开课邀请名师讲解&#xff1b; 3、获…

linux之网络子系统-MAC帧、数据报、段 的头部信息

一、MAC帧 格式 MAC帧是属于链路层&#xff0c;网卡发送数据的格式。 MAC帧主要有两种格式&#xff0c;一种是以太网V2标准&#xff0c;一种是IEEE 802.3&#xff0c;常用的是前者。 DMAC&#xff08;Destination MAC&#xff09;是目的MAC地址。DMAC字段长度为6个字节&#…

突破速度障碍:探索25MBd数字光耦合器在工业自动化中的作用

在快节奏的工业自动化世界中&#xff0c;对能够跟上高速运行同时保持可靠性和安全性的组件的需求至关重要。这些系统中最关键的组件之一是光耦合器&#xff0c;它在机器的不同部分或机器之间传输信号时提供电气隔离。25MBd数字光耦合器的推出代表了该领域的重大进步&#xff0c…

18959 二叉树的之字形遍历

### 思路 1. **输入读取**&#xff1a; - 读取输入字符串&#xff0c;表示完全二叉树的顺序存储结构。 2. **构建二叉树**&#xff1a; - 使用队列构建二叉树&#xff0c;按层次顺序插入节点。 3. **之字形层序遍历**&#xff1a; - 使用双端队列进行层序遍历&…

为何要引入服务注册组件及组件对比

我的后端学习大纲 SpringCloud学习大纲 1.为什么要引入服务注册中心&#xff1a; 1.1.原因说明 1.微服务所在的IP地址和端口号硬编码到订单微服务中&#xff0c;属于硬编码&#xff0c;会存在非常多的问题 如果订单微服务和支付微服务的IP地址或者端口号发生了变化&#xff…

idea配置FTP文件上传

idea配置FTP 连接测试 打开 工具拦打开 maven依赖 <!-- FTP --> <dependency><groupId>commons-net</groupId><artifactId>commons-net</artifactId><version>3.8.0</version> </dependency>FTP-配置 /*** FTP-配置*/ …

数字时代的内容安全治理:审核与管理的艺术

《互联网内容审核与信息安全管理》提供了全面实施互联网内容审核与信息安全管理的方法&#xff0c;主要包括三部分内容。 第一部分&#xff1a;阐释什么是互联网内容审核与信息安全管理&#xff0c;为什么要进行互联网内容审核与信息安全管理&#xff1b;重点分析互联网内容…

vs 项目.gitignore设置过滤某个文件夹无效

问题描述 项目使用tfs进行管理&#xff0c;在使用uniapp开发小程序的时候&#xff0c;每次vs中的更改都会出现99的更改&#xff0c;查看详情发现都是uniapp下面的unpackage文件夹下面的内容。原因是每次重新运行该下面的文件都会重新生成。后来在该项目下面的.gitignore中配置…

【Vue】Echart渲染数据时页面不显示内容

背景 做的一个对话交互的功能&#xff0c;根据后台返回的数据&#xff0c;渲染成Echart图表展示因为图表种类多&#xff0c;因此根据不同图表单独做了一个个vue组件&#xff0c;将数据根据展示类型传到这些子组件中进行渲染无论哪种图表&#xff0c;第一次展示时都能正常展示&…

2024实战指南:四款全免费的数据恢复工具盘点!

在这个数字化的时代里&#xff0c;数据的安全至关重要。如果一不小心删除或丢失了重要数据应该怎么办呢&#xff1f;这几个全免费的数据恢复工具可以帮你解决问题&#xff0c;亲测好用哦&#xff01; 第一款&#xff1a;福昕数据恢复 直达链接&#xff1a;www.pdf365.cn/foxi…

跨系统备忘录迁移有哪些方法?备忘录内容如何跨平台转移?

备忘录作为我们日常生活中常用的软件&#xff0c;帮助我们随时记录重要事项和灵感。然而&#xff0c;随着科技的发展&#xff0c;我们可能会更换不同系统的设备&#xff0c;这时就需要将备忘录内容进行迁移。特别是跨系统的迁移&#xff0c;往往让人感到不便。那么&#xff0c;…

探索挪车小程序源码开发:构建便捷社区生活的智慧桥梁

随着城市化进程的加速&#xff0c;车辆保有量不断增加&#xff0c;停车难、挪车难成为了许多城市居民日常生活中的一大痛点。为了解决这一难题&#xff0c;挪车小程序应运而生&#xff0c;它利用移动互联网的便捷性&#xff0c;为车主之间搭建起一个高效、便捷的沟通平台。本文…

【Python 千题 —— 基础篇】身份证隐藏的信息

Python 千题持续更新中 …… 脑图地址 👉:⭐https://twilight-fanyi.gitee.io/mind-map/Python千题.html⭐ 题目描述 题目描述 在一个用户信息管理系统中,你需要处理和验证用户提供的身份证号。编写一个程序来从用户信息字符串中提取和验证身份证号,并提供相应的处理方式…

LLM论文研读: MindSearch

1. 背景 近日中科大与上海人工智能实验室联合推出的MindSearch思索&#xff0c;引起了不小的关注&#xff0c;github上的星标&#xff0c;短短几周时间&#xff0c;已经飙到了4.2K。看来确实有些内容&#xff0c;因此本qiang~研读了论文及代码&#xff0c;针对其中的原理与创新…

自动化测试的使用场景有哪些?

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 本文将通过介绍 自动化测试是什么&#xff1f;哪些场景适用于自动化测试&#xff1f;自动化测试的好处&#xff1f;以及通过 具体的自动化测试工具应用实例来对自动…