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

    文章

    1362

    浏览量

    40224
  • Linux
    +关注

    关注

    87

    文章

    11222

    浏览量

    208890
  • I2C总线
    +关注

    关注

    8

    文章

    388

    浏览量

    60824
  • I2C驱动
    +关注

    关注

    0

    文章

    9

    浏览量

    7034

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

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

收藏 人收藏

    评论

    相关推荐

    Linux内核中描述I2C的四个核心结构体

    I2C核心维护了i2c_bus结构体,提供了I2C总线驱动和设备驱动的注册、注销方法,维护了I2C
    的头像 发表于 09-04 09:35 1251次阅读
    <b class='flag-5'>Linux</b>内核中描述<b class='flag-5'>I2C</b>的四个核心结构体

    基于I2C总线的EEPROM驱动程序

     I2C总线是由Philips公司开发的用于器件之间连接的2线式双向同步串行总线。Linux内核中针对I2C总线的特性,其设备驱动
    发表于 12-07 13:58 55次下载

    PSoC 1 I2C 入门-AN50987

    PSoC 1 I2C 入门-AN50987
    发表于 10-10 16:22 8次下载
    PSoC 1 <b class='flag-5'>I2C</b> <b class='flag-5'>入门</b>-AN50987

    Linux设备驱动开发详解》第15章、LinuxI2C核心、总线与设备驱动

    Linux设备驱动开发详解》第15章、LinuxI2C核心、总线与设备驱动
    发表于 10-27 11:19 8次下载
    《<b class='flag-5'>Linux</b>设备<b class='flag-5'>驱动</b>开发详解》第15章、<b class='flag-5'>Linux</b>的<b class='flag-5'>I2C</b>核心、总线与设备<b class='flag-5'>驱动</b>

    基于嵌入式Linux下的I2C设备驱动的总体思路与框架设计

    由于I2C总线的通用性,Linux作为一款优秀的嵌入式操作系统,也必须要对其要有很好的支持。在Linux内核源码中对I2C总线的驱动是基于
    发表于 08-20 09:04 3725次阅读
    基于嵌入式<b class='flag-5'>Linux</b>下的<b class='flag-5'>I2C</b>设备<b class='flag-5'>驱动</b>的总体思路与框架设计

    LinuxI2C驱动架构

    1.     LinuxI2C驱动架构LinuxI2C总线的驱动分为两个部分
    发表于 04-02 14:38 666次阅读

    Linux驱动中的I2C驱动架构详细分析

    其实I2C接口非常的简单,即使用51单片机的gpio来模拟I2C,编写一个e2prom或者其他I2C接口的驱动程序,也不是什么难事,几百行代
    发表于 08-01 17:35 3次下载
    <b class='flag-5'>Linux</b><b class='flag-5'>驱动</b>中的<b class='flag-5'>I2C</b><b class='flag-5'>驱动</b>架构详细分析

    如何在Linux下使用SAMA5D2 I2C

    本应用笔记介绍在 Linux 下使用 SAMA5D2 I2C入门信息。
    发表于 03-30 15:45 2次下载
    如何在<b class='flag-5'>Linux</b>下使用SAMA5D<b class='flag-5'>2</b> <b class='flag-5'>I2C</b>

    Linux驱动I2C设备驱动(基于Freescale i.MX6ULL平台了解I2C驱动框架,顺便写个简陋的MPU6050驱动

    文章目录1、简介2I2C总线、设备和驱动的结构体定义2.1 结构体定义--I2C总线2.2 结构体定义--I2C设备2.3 结构体定义--
    发表于 12-06 13:51 8次下载
    <b class='flag-5'>Linux</b><b class='flag-5'>驱动</b>:<b class='flag-5'>I2C</b>设备<b class='flag-5'>驱动</b>(基于Freescale <b class='flag-5'>i</b>.MX6ULL平台了解<b class='flag-5'>I2C</b>的<b class='flag-5'>驱动</b>框架,顺便写个简陋的MPU6050<b class='flag-5'>驱动</b>)

    linux移植MPU6050的I2C驱动

    有MPU6050的例程,测试后很好用,如下图(梦幻联动一下:树莓派PICO+freeRTOS)因为pico上有现成的能用的例程,所以改一改之后直接移植到linux上首先介绍一下linux下的I2C框架①、
    发表于 12-06 14:21 10次下载
    <b class='flag-5'>linux</b>移植MPU6050的<b class='flag-5'>I2C</b><b class='flag-5'>驱动</b>

    Linux应用开发【第十二章】I2C编程应用开发

    12.2.2 简述I2Clinux驱动 1) I2C核心层: 2) I2C总线
    的头像 发表于 12-10 19:28 870次阅读
    <b class='flag-5'>Linux</b>应用开发【第十二章】<b class='flag-5'>I2C</b>编程应用开发

    硬件I2C与模拟I2C

    硬件I2C对应芯片上的I2C外设,有相应I2C驱动电路,其所使用的I2C管脚也是专用的,因而效率要远高于软件模拟的
    发表于 12-28 19:14 81次下载
    硬件<b class='flag-5'>I2C</b>与模拟<b class='flag-5'>I2C</b>

    MSP MCU I2C入门指南

    MSP MCU I2C入门指南
    发表于 11-02 08:16 1次下载
    MSP MCU <b class='flag-5'>I2C</b><b class='flag-5'>入门</b>指南

    I2C控制器驱动介绍

    控制器驱动 I2C 总线驱动重点是 I2C 适配器驱动,这里要用到两个重要的数据结构:i2c_a
    的头像 发表于 07-22 15:38 1418次阅读
    <b class='flag-5'>I2C</b>控制器<b class='flag-5'>驱动</b>介绍

    I2C子系统SW Architecture

    I2C SW Architecture 【driver 驱动层】由普通驱动工程师负责,【i2c 核心层】由 Linux 提供,【
    的头像 发表于 07-22 16:01 909次阅读
    <b class='flag-5'>I2C</b>子系统SW Architecture