0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux I2C驱动入门知识科普

jf_BxU6dNQb 来源:混说Linux 2022-12-29 13:59 次阅读

Linux内核将 I2C 驱动分为两部分:

I2C 总线驱动, I2C总线驱动就是SOC的 I2C控制器驱动,也叫做 I2C适配器驱动。

I2C 设备驱动, I2C设备驱动就是针对具体的 I2C设备而编写的驱动。

I2C框架下的几个重要成员

1. I2C总线

I2C总线结构体在driversi2ci2c-core.c中定义如下:

structbus_typei2c_bus_type={
.name="i2c",
.match=i2c_device_match,
.probe=i2c_device_probe,
.remove=i2c_device_remove,
.shutdown=i2c_device_shutdown,
};

I2C总线对应着/bus下的一条总线,这个i2c总线结构体管理着i2c设备与I2C驱动的匹配,删除等操作,I2C总线会调用i2c_device_match函数看I2C设备和I2C驱动是否匹配,如果匹配就调用i2c_device_probe函数,进而调用I2C驱动的probe函数。

形如:

464fcfe2-8732-11ed-bfe3-dac502259ad0.png

i2c_device_match会管理I2C设备和I2C总线匹配规则,这将和如何编写I2C驱动程序息息相关。

2. I2C驱动

i2c_driver 类似 platform_driver,是我们编写 I2C 设备驱动重点要处理的内容, i2c_driver 结构体定义在 include/linux/i2c.h 文件中,内容如下:

structi2c_driver{
unsignedintclass;

/*Notifiesthedriverthatanewbushasappeared.Youshouldavoid
*usingthis,itwillberemovedinanearfuture.
*/
int(*attach_adapter)(structi2c_adapter*)__deprecated;

/*Standarddrivermodelinterfaces*/
int(*probe)(structi2c_client*,conststructi2c_device_id*);
int(*remove)(structi2c_client*);


/*drivermodelinterfacesthatdon'trelatetoenumeration*/
void(*shutdown)(structi2c_client*);

/*Alertcallback,forexamplefortheSMBusalertprotocol.
*Theformatandmeaningofthedatavaluedependsontheprotocol.
*FortheSMBusalertprotocol,thereisasinglebitofdatapassed
*asthealertresponse'slowbit("eventflag").
*/
void(*alert)(structi2c_client*,unsignedintdata);

/*aioctllikecommandthatcanbeusedtoperformspecificfunctions
*withthedevice.
*/
int(*command)(structi2c_client*client,unsignedintcmd,void*arg);

structdevice_driverdriver;
conststructi2c_device_id*id_table;

/*Devicedetectioncallbackforautomaticdevicecreation*/
int(*detect)(structi2c_client*,structi2c_board_info*);
constunsignedshort*address_list;
structlist_headclients;
};

重点成员如下:

int(*probe)(structi2c_client*,conststructi2c_device_id*)

当 I2C设备和驱动匹配成功以后 probe函数就会执行。

structdevice_driverdriverdevice_driver

驱动结构体,如果使用设备树的话,需要设置device_driver的of_match_table成员变量,也就是驱动的兼容(compatible)属性。

conststructi2c_device_id*id_table

id_table 是传统的、未使用设备树的设备匹配 ID表

3. I2C设备

I2C设备结构体i2c_client 结构体定义在 include/linux/i2c.h 文件中,内容如下:

structi2c_client{
unsignedshortflags;/*div.,seebelow*/
unsignedshortaddr;/*chipaddress-NOTE:7bit*/
/*addressesarestoredinthe_LOWER_7bits*/
charname[I2C_NAME_SIZE];
structi2c_adapter*adapter;/*theadapterwesiton*/
structdevicedev;/*thedevicestructure*/
intirq;/*irqissuedbydevice*/
structlist_headdetected;
#ifIS_ENABLED(CONFIG_I2C_SLAVE)
i2c_slave_cb_tslave_cb;/*callbackforslavemode*/
#endif
};

重点成员如下:

flags:标志

addr芯片地址,7 位,存在低 7 位

flagsname[I2C_NAME_SIZE]:名字

adapter:对应的 I2C 适配器

dev:设备结构体

irq:中断

一个设备对应一个 i2c_client,每检测到一个 I2C 设备就会给这个 I2C 设备分配一个i2c_client。

4. I2C适配器

经过上面的介绍,知道有I2C驱动和I2C设备,我们需要通过I2C驱动去和I2C设备通讯,这其中就需要一个I2C设配器,I2C设配器对应的就是SOC上的I2C控制器。

Linux 内核将 SOC 的 I2C 适配器(控制器)抽象成 i2c_adapter, i2c_adapter 结构体定义在 include/linux/i2c.h 文件中,结构体内容如下:

/*
*i2c_adapteristhestructureusedtoidentifyaphysicali2cbusalong
*withtheaccessalgorithmsnecessarytoaccessit.
*/
structi2c_adapter{
structmodule*owner;
unsignedintclass;/*classestoallowprobingfor*/
conststructi2c_algorithm*algo;/*thealgorithmtoaccessthebus*//*总线访问算法*/
void*algo_data;

/*datafieldsthatarevalidforalldevices*/
structrt_mutexbus_lock;

inttimeout;/*injiffies*/
intretries;
structdevicedev;/*theadapterdevice*/

intnr;
charname[48];
structcompletiondev_released;

structmutexuserspace_clients_lock;
structlist_headuserspace_clients;

structi2c_bus_recovery_info*bus_recovery_info;
conststructi2c_adapter_quirks*quirks;
};

重点成员如下:

conststructi2c_algorithm*algo

I2C 适配器与 IIC 设备进行通信的方法。

i2c_algorithm 结构体定义在 include/linux/i2c.h 文件中,内容如下:

structi2c_algorithm{
/*Ifanadapteralgorithmcan'tdoI2C-levelaccess,setmaster_xfer
toNULL.IfanadapteralgorithmcandoSMBusaccess,set
smbus_xfer.IfsettoNULL,theSMBusprotocolissimulated
usingcommonI2Cmessages*/
/*master_xfershouldreturnthenumberofmessagessuccessfully
processed,oranegativevalueonerror*/
int(*master_xfer)(structi2c_adapter*adap,structi2c_msg*msgs,
intnum);
int(*smbus_xfer)(structi2c_adapter*adap,u16addr,
unsignedshortflags,charread_write,
u8command,intsize,unioni2c_smbus_data*data);

/*Todeterminewhattheadaptersupports*/
u32(*functionality)(structi2c_adapter*);

#ifIS_ENABLED(CONFIG_I2C_SLAVE)
int(*reg_slave)(structi2c_client*client);
int(*unreg_slave)(structi2c_client*client);
#endif
};

重点成员如下:

master_xfer:I2C 适配器的传输函数,可以通过此函数来完成与 IIC 设备之间的通信。

smbus_xfer:SMBUS 总线的传输函数

I2C 适配器驱动的主要工作就是初始化 i2c_adapter 结构体变量,然后设置 i2c_algorithm中的master_xfer函数。完成以后通过 i2c_add_numbered_adapter或 i2c_add_adapter这两个函数向系统注册设置好的 i2c_adapter。

这两个函数的区别在于 i2c_add_adapter 使用动态的总线号,而 i2c_add_numbered_adapter使用静态总线号。

5. 小结

I2C驱动有4个重要的东西:I2C总线、I2C驱动、I2C设备、I2C设备器。

I2C总线:维护着两个链表(I2C驱动、I2C设备),管理I2C设备和I2C驱动的匹配和删除等。

I2C驱动:对应的就是I2C设备的驱动程序。

I2C设备:是具体硬件设备的一个抽象。

I2C适配器:用于I2C驱动和I2C设备间的通用,是SOC上I2C控制器的一个抽象。

Linux I2C总线的运行机制:

注册I2C驱动

将I2C驱动添加到I2C总线的驱动链表中

遍历I2C总线上的设备链表,根据i2c_device_match函数进行匹配,如果匹配调用i2c_device_probe函数

i2c_device_probe函数会调用I2C驱动的probe函数

I2C驱动简单编写流程

一般 SOC 的 I2C总线驱动都是由半导体厂商编写的,这个不需要用户去编写。因此 I2C 总线驱动对于 SOC使用者来说是被屏蔽掉的,我们只要专注于 I2C 设备驱动即可。除非你是在半导体公司上班,工作内容就是写 I2C 适配器驱动。

i2c_driver类似platform_driver,是我们编写I2C设备驱动重点要处理的内容,i2c_driver在上面已经介绍了其结构体的具体内容。

对于我们 I2C 设备驱动编写人来说,重点工作就是构建i2c_driver,构建完成以后需要向Linux内核注册这个i2c_driver。

那么如何注册呢?

使用下面的这个函数:

inti2c_register_driver(structmodule*owner,structi2c_driver*driver)
函数参数和返回值含义如下:

owner:一般为 THIS_MODULE。

driver:要注册的 i2c_driver。

返回值:0,成功;负值,失败。

另外 i2c_add_driver 也常常用于注册 i2c_driver, i2c_add_driver 是一个宏,定义如下:

#definei2c_add_driver(driver)
i2c_register_driver(THIS_MODULE,driver)

i2c_add_driver 就是对 i2c_register_driver 做了一个简单的封装,只有一个参数,就是要注册的 i2c_driver。

设备驱动的时候需要将前面注册的 i2c_driver 从 Linux 内核中注销掉,需要用到i2c_del_driver 函数,此函数原型如下:

voidi2c_del_driver(structi2c_driver*driver);
函数参数和返回值含义如下:

driver:要注销的 i2c_driver。

返回值:无。

例程框架:

/*i2c驱动的probe函数*/
staticintxxx_probe(structi2c_client*client,
{
/*函数具体程序*/
return0;
}

/*i2c驱动的remove函数*/
staticintxxx_remove(structi2c_client*client)
{
/*函数具体程序*/
return0;
}

/*传统匹配方式ID列表*/
staticconststructi2c_device_idxxx_id[]={
{"xxx",0},
{}
};

/*设备树匹配列表*/
staticconststructof_device_idxxx_of_match[]={
{.compatible="xxx"},
{/*Sentinel*/}
};

/*i2c驱动结构体*/
staticstructi2c_driverxxx_driver={
.probe=xxx_probe,
.remove=xxx_remove,
.driver={
.owner=THIS_MODULE,
.name="xxx",
.of_match_table=xxx_of_match,
},
.id_table=xxx_id,
};

/*驱动入口函数*/
staticint__initxxx_init(void)
{
intret=0;
ret=i2c_add_driver(&xxx_driver);
returnret;
}

/*驱动出口函数*/
staticvoid__exitxxx_exit(void)
{
i2c_del_driver(&xxx_driver);
}

module_init(xxx_init);
module_exit(xxx_exit);

当I2C设备和I2C驱动匹配成功以后probe函数就会执行,这些和platform驱动一样,probe函数里面基本就是标准的字符设备驱动那一套了。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 内核
    +关注

    关注

    3

    文章

    1316

    浏览量

    39948
  • Linux
    +关注

    关注

    87

    文章

    11030

    浏览量

    207263
  • I2C总线
    +关注

    关注

    8

    文章

    375

    浏览量

    60536
  • I2C驱动
    +关注

    关注

    0

    文章

    9

    浏览量

    7009

原文标题:Linux I2C 驱动入门,建议收藏!!!

文章出处:【微信号:混说Linux,微信公众号:混说Linux】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    【Z-turn Board试用体验】+ Zynq linuxI2C驱动学习笔记(一)

    时间。三、Linux I2C总线驱动1、I2C适配器的加载和卸除加载:申请硬件资源,比如IO地址,中断号,调用i2c_add_adapter
    发表于 06-21 22:10

    【Z-turn Board试用体验】+ Zynq linuxI2C驱动学习笔记(二)

    ;id->adap.dev.parent = &pdev->dev;四、linux i2c从设备驱动硬件方面,I2C主设备已经集成在主芯片内,软件方面,
    发表于 06-21 22:25

    I2C从设备驱动的开发

    linux3.2内核提供的I2C驱动都是主设备的,想让I2C做从设备,请教哪位大神做过I2C从设备驱动
    发表于 08-21 12:05

    [分享]4412开发板学习教程,新增I2C驱动、SPI总线视频教程

    I2C驱动、SPI总线视频教程)09-迅为电子Java 教程10-uboot教程 01-烧写、编译以及基础知识视频: 02-嵌入式Linux 视频: 03-iTOP-4412 开
    发表于 08-25 10:18

    LinuxI2C体系结构

     在Linux 系统中,I2C 驱动由3 部分组成,即I2C 核心、I2C 总线驱动
    发表于 08-06 06:53

    什么是基于嵌入式LinuxI2C设备驱动程序?

    由于I2C总线的通用性,Linux作为一款优秀的嵌入式操作系统,也必须要对其要有很好的支持。在Linux内核源码中对I2C总线的驱动是基于总
    发表于 09-02 08:04

    「正点原子Linux连载」第六十一章Linux I2C驱动实验(一)

    1)实验平台:正点原子Linux开发板2)摘自《正点原子I.MX6U嵌入式Linux驱动开发指南》关注官方微信号公众号,获取更多资料:正点原
    发表于 03-23 09:54

    如何仿照Linux内核去编写I2C驱动

    仿照Linux内核编写MCU的I2C驱动I2C是很常用的串行通信接口,用于连接各种外设,传感器等器件。在单片机开发中,I2C
    发表于 08-23 08:03

    I2C总线是如何去定义的

    I2C总线编辑本词条由“科普中国”科学百科词条编写与应用工作项目审核 。I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。主
    发表于 12-29 06:30

    linux I2C子系统的相关资料分享

    文章目录linux I2C子系统框架在设备树中添加从设备信息,mpu5060I2C driver 程序的编写mpu6050 I2C程序具体实现lin
    发表于 02-10 06:06

    I2C设备驱动的相关资料下载

    文章目录1、简介2I2C总线、设备和驱动的结构体定义2.1 结构体定义--I2C总线2.2 结构体定义--I2C设备2.3 结构体定义--
    发表于 02-10 06:39

    linux移植MPU6050的I2C驱动过程分享

    有MPU6050的例程,测试后很好用,如下图(梦幻联动一下:树莓派PICO+freeRTOS)因为pico上有现成的能用的例程,所以改一改之后直接移植到linux上首先介绍一下linux下的I2C框架①、
    发表于 02-10 06:48

    Linux驱动程序支持通过I2C和SPI总线进行通信吗

    Linux驱动程序支持哪些设备呢?Linux驱动程序支持通过I2C和SPI总线进行通信吗?
    发表于 03-09 06:33

    CH341 linux驱动编译安装后无法识别到i2c设备怎么处理?

    我想在ubuntu18.04上用ch341的i2c转usb功能,需要安装驱动。我下载了CH341的linux驱动,如图:可是在编译它们的时候报错了。我修改了报错的源码,编译安装后还是无
    发表于 07-12 06:53

    OpenHarmony:如何使用HDF平台驱动控制I2C

    驱动调试。 我们以///drivers/hdf_core/adapter/khdf/linux/platform/i2c/i2c_adapter.c为例(该
    发表于 09-12 15:18