I2C子系统知识(二)

I2C子系统 串行、半双工总线,主要用于低速、近距离的芯片之间的通信。 阅读详情

I2C总线驱动是对适配器端的实现,其含有适配器数据结构struct i2c_adapter,适配器算法数据结构struct i2c_algorithm。I2C设备驱动是对设备端的实现和控制,其含有设备驱动结构i2c_driver和设备客户端结构struct i2c_client。

以下为i2c_driver结构体,里面提供了通用的操作i2c设备的接口函数.


struct i2c_driver {
    unsigned int class;

    /* Notifies the driver that a new bus has appeared or is about to be
     * removed. You should avoid using this if you can, it will probably
     * be removed in a near future.
     */
    int (*attach_adapter)(struct i2c_adapter *); 
    int (*detach_adapter)(struct i2c_adapter *); 

    /* Standard driver model interfaces */
    int (*probe)(struct i2c_client *, const struct i2c_device_id *); 
    int (*remove)(struct i2c_client *); 

    /* driver model interfaces that don't relate to enumeration  */
    void (*shutdown)(struct i2c_client *); 
    int (*suspend)(struct i2c_client *, pm_message_t mesg);
    int (*resume)(struct i2c_client *); 

    /* Alert callback, for example for the SMBus alert protocol.
     * The format and meaning of the data value depends on the protocol.
     * For the SMBus alert protocol, there is a single bit of data passed
     * as the alert response's low bit ("event flag").
     */
    void (*alert)(struct i2c_client *, unsigned int data);

    /* a ioctl like command that can be used to perform specific functions
     * with the device.
     */
    int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);

    struct device_driver driver;
    const struct i2c_device_id *id_table;

    /* Device detection callback for automatic device creation */
    int (*detect)(struct i2c_client *, struct i2c_board_info *); 
    const unsigned short *address_list;
    struct list_head clients;
};



client端有一条全局链表,用于串联所有i2c的client设备,为__i2c_board_list,如何将client链接到__i2c_board_list上去呢?内核提供了另一个数据结构,静态注册挂接在该链表上的结构为:

struct i2c_devinfo {
    struct list_head    list;  /*连接指针指向前后设备*/
    int         busnum;    /*所在bus的编号*/
    struct i2c_board_info   board_info;  /*/板级平台信息*/
};

struct i2c_board_info { 
    char        type[I2C_NAME_SIZE];
    unsigned short  flags;  
    unsigned short  addr;
    void        *platform_data;
    struct dev_archdata *archdata;
#ifdef CONFIG_OF
    struct device_node *of_node;
#endif 
    int     irq;
};

i2c_devinfo结构静态注册的信息最后都会被整合集成到client中,形成一个标准的i2c_client设备并注册。



关于SMBus协议的说明:Intel制定了SMBus标准用于低速通讯。SMBus二线接口与I2C接口非常相似。SMBus也使用一条数据线(SMBDATA)和一条时钟线(SMBCLK)实现通讯。I2C接口和SMBus接口的主要区别是最大和最小时钟速度。SMBCLK必须在10kHz和100kHz之间。SMBCLK和SMBDATA线也需要上拉电阻。3V供电时上拉电阻大于8.5k ,5V供电时上拉电阻大于14k 。SMBus工作电压范围在3V和5V之间,大于2.1V为高电平,低于0.8V为低电平。struct i2c_adapter对应于物理上的一个适配器,而struct i2c_algorithm对应于一套通讯方法。i2c_algorithm提供一些控制适配器发送或接收函数,对于i2c总线需要初始化master_xfer函数,对于smbus总线需要初始化smbus_xfer函数。master_xfer函数是以i2c_msg为单位进行控制的,其结构如下:


struct i2c_msg {


 __u16 addr;  //从设备地址
 __u16 flags;  //动作标志:读或写
#define I2C_M_TEN 0x10 //器件地址是10Bit
#define I2C_M_RD 0x01
#define I2C_M_NOSTART 0x4000 //意味当前i2c_msg不发送start信号
#define I2C_M_REV_DIR_ADDR 0x2000 //把读写标志位反转
#define I2C_M_IGNORE_NAK 0x1000//当前i2c_msg忽略I2C器件的ack和nack信号。
#define I2C_M_NO_RD_ACK  0x0800 //表示在正行读操作时不去ACK
 __u16 len;  //信息长度
 __u8 *buf;  //信息缓冲区首地址

 

};
 
static int __init i2c_init(void)
{
    int retval;
    /*
    * 注册i2c_bus
    */
    retval = bus_register(&i2c_bus_type);
    if (retval)
    return retval;
#ifdef CONFIG_I2C_COMPAT
 /*

* 在sys/class下创建适配器目录
 */
    i2c_adapter_compat_class = class_compat_register("i2c-adapter");
    if (!i2c_adapter_compat_class) {
    retval = -ENOMEM;
    goto bus_err;
}

#endif
 /*
  * 增加一个虚拟的driver
  */
    retval = i2c_add_driver(&dummy_driver);
    if (retval)
    goto class_err;
    return 0;
class_err:
#ifdef CONFIG_I2C_COMPAT
    class_compat_unregister(i2c_adapter_compat_class);
bus_err:
#endif
    bus_unregister(&i2c_bus_type);
    return retval;
}
//其中的i2c_bus_type原型为:
struct bus_type i2c_bus_type = {
   .name = "i2c",
   .match = i2c_device_match,
   .probe = i2c_device_probe,
   .remove = i2c_device_remove,
   .shutdown = i2c_device_shutdown,
   .pm = &i2c_device_pm_ops,
};

适配器需要驱动,i2c设备也需要驱动。在驱动端提供统一的添加驱动接口为:i2c_add_driver

static inline int i2c_add_driver(struct i2c_driver *driver)
{
    return i2c_register_driver(THIS_MODULE, driver);
}


int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
    int res; 

    /* Can't register until after driver model init */
    if (unlikely(WARN_ON(!i2c_bus_type.p)))
        return -EAGAIN;

    /* add the driver to the list of i2c drivers in the driver core */
    driver->driver.owner = owner;
    driver->driver.bus = &i2c_bus_type;

    /* When registration returns, the driver core
     * will have called probe() for all matching-but-unbound devices.
     */
    res = driver_register(&driver->driver);
    if (res)
        return res; 

    pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);

    INIT_LIST_HEAD(&driver->clients);
    /* Walk the adapters that are already present */
    mutex_lock(&core_lock);
    bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);
    mutex_unlock(&core_lock);

    return 0;
}

driver_register函数注册后会去i2c_bus_type的设备链表上匹配设备,调用driver中的i2c_device_match,如果匹配成功将建立标准关联,并且将调用bus端的probe函数初始化这个设备,即函数i2c_device_probe.

bus_for_each_dev函数循环遍历挂接在i2c bus总线上的设备,并对每个设备调用__process_new_driver函数。




根据dev得到 i2c_client,根据drv得到i2c_driver,然后根据driver->id_table->name 与 client->name比较。匹配成功说明由设备找到了对应的驱动程序

static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
    struct i2c_client   *client = i2c_verify_client(dev);/*   检查是否为client类型,而不是adapter类型  */
    struct i2c_driver   *driver;

    if (!client)
        return 0;

    driver = to_i2c_driver(drv);  /*根据device_driver获得i2c_driver结构体指针*/
    /* match on an id table if there is one */
    if (driver->id_table)
        return i2c_match_id(driver->id_table, client) != NULL;

    return 0;
}


static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, 
                        const struct i2c_client *client)
{
    while (id->name[0]) {
        if (strcmp(client->name, id->name) == 0)
            return id;
        id++;
    }    
    return NULL;
}


接着调用初始化设备函数i2c_device_probe

static int i2c_device_probe(struct device *dev)
{
    struct i2c_client   *client = i2c_verify_client(dev);
    struct i2c_driver   *driver;
    int status;

    if (!client)
        return 0;
    /*dev->driver指向匹配完成的driver*/
    driver = to_i2c_driver(dev->driver);
    if (!driver->probe || !driver->id_table)
        return -ENODEV;
    client->driver = driver;
    /*唤醒该设备*/  
    if (!device_can_wakeup(&client->dev))
        device_init_wakeup(&client->dev,
                    client->flags & I2C_CLIENT_WAKE);
    dev_dbg(dev, "probe\n");
    /*跳到驱动里,执行驱动程序里的probe函数*/
    status = driver->probe(client, i2c_match_id(driver->id_table, client));
    if (status) {/*失败将清除client指定的driver内容*/
        client->driver = NULL;
        i2c_set_clientdata(client, NULL);
        return status;
    }
    /*电源管理中设置该设备有效*/
    pm_runtime_set_active(dev);
    return status;
}       



下面看一下当找到一个dev后调用的__process_new_driver函数 *
*************************************************************/
static int __process_new_driver(struct device *dev, void *data)
{
       /*
       * 设备的类型如果不是i2c_adapter类型就推出
       * 下面的代码是针对i2c适配器的代码
       */
       if (dev->type != &i2c_adapter_type)
       return 0;
      
      /*
        如果这个设备代表i2c适配器,则调用i2c_do_add_adapter
       此时的data类型为i2c_driver
      */
      return i2c_do_add_adapter(data, to_i2c_adapter(dev));//to_i2c_adapte根据设备得到他的适配器,第一个参数是i2c_driver

}


static int i2c_do_add_adapter(struct i2c_driver *driver,
                  struct i2c_adapter *adap)
{
    /* Detect supported devices on that bus, and instantiate them */
    i2c_detect(adap, driver);

    /* Let legacy drivers scan this bus for matching devices */
    if (driver->attach_adapter) {
        /* We ignore the return code; if it fails, too bad */
        driver->attach_adapter(adap);
    }
    return 0;
}


static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
{   
    const unsigned short *address_list;
    struct i2c_client *temp_client;
    int i, err = 0;
    int adap_id = i2c_adapter_id(adapter);

    address_list = driver->address_list;
    if (!driver->detect || !address_list)
        return 0;
    
    /* Set up a temporary client to help detect callback */
    temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
    if (!temp_client)
        return -ENOMEM;
    temp_client->adapter = adapter;
    
    /* Stop here if the classes do not match 适配器的类型可以为传感器,eeprom,driver类型必须与其匹配*/
    if (!(adapter->class & driver->class))
        goto exit_free;
    
    /* Stop here if the bus doesn't support probing */
    if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE)) {
        if (address_list[0] == I2C_CLIENT_END)
            goto exit_free;
    
        dev_warn(&adapter->dev, "Probing not supported\n");
        err = -EOPNOTSUPP;
        goto exit_free;
    }       
      /*根据地址列表匹配执行i2c_detect_address*/  
    for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) {
        dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
            "addr 0x%02x\n", adap_id, address_list[i]);
        temp_client->addr = address_list[i];
        err = i2c_detect_address(temp_client, driver);
        if (err)
            goto exit_free;
    }
exit_free: 
    kfree(temp_client);
    return err;
}   

static int i2c_detect_address(struct i2c_client *temp_client,
                  struct i2c_driver *driver)
{   
    struct i2c_board_info info;
    struct i2c_adapter *adapter = temp_client->adapter;
    int addr = temp_client->addr;
    int err;
             
    /* Make sure the address is valid */
    err = i2c_check_addr_validity(addr);/*地址有效*/
    if (err) {
        dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n",
             addr);
        return err;
    }
    
    /* Skip if already in use */
    if (i2c_check_addr_busy(adapter, addr))
        return 0;
    
    /* Make sure there is something at this address */
    if (!i2c_default_probe(adapter, addr))
        return 0;
    
    /* Finally call the custom detection function 调用驱动里的detect函数*/
    memset(&info, 0, sizeof(struct i2c_board_info));
    info.addr = addr; 
    err = driver->detect(temp_client, &info);
    if (err) {
        /* -ENODEV is returned if the detection fails. We catch it
           here as this isn't an error. */
        return err == -ENODEV ? 0 : err;
    }       
            
    /* Consistency check */
    if (info.type[0] == '\0') { /*类型为空*/
        dev_err(&adapter->dev, "%s detection function provided "
            "no name for 0x%x\n", driver->driver.name,
            addr);
    } else {
        struct i2c_client *client;
  
        /* Detection succeeded, instantiate the device */
        dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n",
            info.type, info.addr);
        client = i2c_new_device(adapter, &info);/**实例探测到的设备**/
        if (client)
            list_add_tail(&client->detected, &driver->clients);/*将当前新生成的client添加到driver->client链表的末尾*/
        else
            dev_err(&adapter->dev, "Failed creating %s at 0x%02x\n",
                info.type, info.addr);
    }   
    return 0;
}       




基于i2c子系统的驱动分析 和i2c有关的代码都在源码drivers/i2c目录下。内核提供了两种i2c的实现方法: 第一种叫i2c_dev,对应drivers/i2c/i2c-dev.c,这种方法仅仅封装了soc的i2c控制器操作,并向应用层提供操作接口。其本质是为应用层提供了一个库,驱动功能由应用层实现,不是主流的做法 第二种是驱动层实现所有驱动功能,是比较主流的做法 阅读详情

相关推荐

RK3399平台开发系列讲解(I2C子系统)4.19、I2C子系统之框架图解

1、Linux I2C子系统框架匹配注册i2c_client 平台 内核版本 安卓版本 RK3399 Linux4.4 Android7.1 1、Linux I2C子系统框架 Linux 下 I2C 子系统架构,主要分为三个部分: 核心层提供主机适配器驱动和设备驱动的管理并提供上层访问接口; 总线驱动层是 I2C 主机适配器驱动和通信算法的实现,可以产生满足I2C通信协议的电平序列; 最后 I2C 设备驱动是对子系统框架中外部设备的抽象,它通过核心层与适配器联系。 I2C .

内核笔记 3085

IIC驱动

IIC驱动

baidu_38310096的博客 990

手把手教你用Synopsys AHB VIP搭建验证环境:从SINGLE到WRAP16的完整波形分析与避坑指南

本文详细介绍了如何使用Synopsys AHB VIP搭建验证环境,从基础配置到复杂波形调试实战。重点解析了AHB协议中各种Burst类型的地址计算机制,包括INCR和WRAP类型,并提供了实际案例和避坑指南,帮助工程师快速掌握验证技巧。

weixin_42552716的博客 416

linux i2c_driver 结构体解析

转载自:http://blog.youkuaiyun.com/string19820108/article/details/7236854

liujiaoyage的专栏 4441

宏基因组功能注释实战:从CAZyme到VFDB的完整流程(含数据库下载与脚本优化)

本文详细介绍了宏基因组功能注释的完整流程,涵盖CAZyme、eggNOG、CARD和VFDB四大核心数据库的实战应用。从环境配置、数据库下载与预处理到注释流程执行与优化,提供了全面的操作指南和脚本优化建议,帮助研究人员高效完成宏基因组数据分析。特别针对CAZyme注释等关键步骤给出了参数优化方案和常见问题排查方法。

weixin_29289821的博客 298

【KBrowser】基于 Kiwi/chromium 制作全新外壳,将 chromium 代码当作 webview 使用,实现可控核替换

chromium 其实只需几步巧妙的架构,就能拿来“换核”,甚至可以插件化,实现类似webview.apk 的效果。重新设计界面,不再是差不多的回声。而 Kiwi 基于 chrome 77 ,只有 50 MB。优势是兼容好、可安装扩展。

sinat_27171121的博客 2030

SMBus与I2C的区别

本文转自网络 SMBus与I2C的区别 SMbus 最早是由 Intel 公司提出来的. 现在由 SBS 管理维护这一个规格. 此规格是用 Philips 的 I2C 简化而来. SMbus 是由两条讯号所组成的一种汇流排. 是为了在系统上较慢速的装置及电源管理装置之间

Yasin Lee 4402

告别手动打卡:逍遥模拟器+宥马运动自动跑步脚本配置全流程

本文详细介绍了如何利用逍遥模拟器和自动化脚本实现宥马运动的自动跑步功能,告别手动打卡的繁琐。从环境准备、脚本部署到定位配置和智能调度,全流程指导用户完成自动化设置,提升效率并确保运动数据的真实性。

weixin_42532473的博客 559

【技术】linux i2c_driver 结构体解析

转自:https://blog.youkuaiyun.com/liujiaoyage/article/details/36424573 驱动程序的主要工作就是定义并初始化一个i2c_driver结构体(定义于i2c.h中),i2c_driver的成员参考下面。 struct i2c_driver { unsigned int class; /* Notifies the driver that a ne...

攻城狮粥迪的专栏 6604

硬件手册——PT100精密测温电路

PT100精密测温电路 一、需求分析 根据题目要求为:测温范围为0-100℃、测温精度要求为±1℃。由于铂电阻具有精度高、性能可靠、稳定性好的特点,且铂电阻的电阻相对变化率与温度的关系曲线线性度最好,故选择铂电阻作为敏感元件。而在国标中,铂电阻有几种不同的标准,如PT100、PT1000。分别对应着0摄氏度下铂电阻的阻值为100R和1000R,由于需要考虑铂电阻的自发热问题,所以尽量选择阻值小的铂电阻,故选择PT100为最终型号。 二、电路设计 2.1 热电阻接法 热电阻测温电路有多种接法,其中三线制会导致

weixin_41655430的博客 5万+

AI工具 | 每个打工人必备的15款人工智能超级工具

不过,还是有一些靠谱的人工智能平台,它们可不只是营销噱头。有些AI公司正试图改变游戏规则。人工智能工具让人们能够更聪明地工作,而不是更辛苦地劳作。如果你想知道未来有什么,那就来看看这10款人工智能工具吧,它们将彻底改变我们的工作方式。

Vampire_2017的博客 5万+

Linux驱动_i2c驱动(ap3216c)

三、驱动编写测试 1、修改设备树 从原理图中可以看出,UART4_RXD作为I2C1_SDA,UART4_TXD作为I2C1_SCL。 因此需要修改对应的pinctrl节点信息,使管脚复用为I2C1功能 。修改后结果如下: 随后在设备树i2c1接口上添加AP3216C设备节点信息,添加结束后如下: 其中@后面的“1e”是 ap3216c 的器件地址,compatible属性用于驱动和设备的匹配,reg属性也用来保存ap3216c的器件地址。 ...

qq_42174306的博客 4834

AI产品经理面试宝典第94天:RAG知识库构建与预处理策略面试指南

本文深入解析RAG知识库构建的核心挑战与预处理策略,涵盖文档格式转换、问答对生成及自动化测试全流程,为AI产品经理提供面试必备的实战方法论与避坑指南,助你精准应对技术深度类问题。

打造全国最全的AI Agent开发知识领域的博客 314

linux内核I2C子系统详解

I2C子系统

weixin_42031299的博客 9694

预测股票价格趋势:使用MATLAB进行股票价格预测

通过收集股票数据、数据预处理、构建预测模型以及可视化结果,我们可以利用MATLAB强大的计算和分析功能来预测股票价格的走势。然而,需要注意的是,股票市场具有高度复杂性和不确定性,预测结果仅供参考,并不构成投资建议。然而,借助计算机编程和数据分析工具,我们可以利用历史股价数据来建立模型,并预测未来的股票价格走势。首先,我们需要获取股票的历史价格数据。完成模型的拟合后,我们可以使用该模型来进行未来股票价格的预测。最后,我们可以使用MATLAB的绘图功能将预测的股票价格与实际股票价格进行对比,并进行可视化展示。

2301_79326588的博客 1018

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

i2c子系统二

块可以调用i2c core提供的i2c_slave_register/i2c_slave_unregister来注册一个或者注销一个i2c的slave设备。一旦氵主册了slave。一般情况下:运行Linux kernel的设备,在i2C总线里面,都是i2C master,Linux kernel-3.19以后,增加slave的支持。设备,底层的adapter要切换到slave mode,该i2cslave设备可以响应来自对端i2c master设备的各种命令和数据了。

weixin_52849254的博客 1115

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

I2C子系统框架入门—i2c驱动示例

在这个流程中,驱动程序(即你的代码)负责发起I²C命令请求,而实际的数据传输和命令执行由I²C控制器完成。I²C控制器是硬件层面的存在,它通过I²C总线执行读写操作,将驱动程序的请求发送到物理设备上。

weixin_46999174的博客 1755

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

I2c子系统

总结一下数据传输的关键点:数据稳定性:在 SCL 的高电平期间,SDA 上的数据必须保持稳定,不发生变化。这是因为在 SCL 的高电平时,数据被接收方读取。数据变化时机:SDA 上的数据变化应在 SCL 的低电平期间进行,这样数据在 SCL 的下一个高电平到来之前已经稳定,确保数据的正确读取。数据有效性:数据在 SCL 为高电平时被视为有效,此时数据被从设备读取。每一次发送数据过后都需要收一个ack来确认数据是否收到在I2C中,0110这个数据是先发送最高位,然后再发送低位。

qq_46518045的博客 956

linux驱动之I2C子系统

目录一、I2C基本原理二、linux内核的I2C子系统详解1、linux内核的I2C驱动框架总览2、I2C子系统的4个关键结构体(kernel/include/linux/i2c.h)3、关键文件4、i2c-core.c初步分析(从后向前看)5、I2C总线的匹配机制(i2c-core.c)6、核心层开放给其他部分的注册接口7、adapter模块的注册8、s3c24xx_i2c_probe函数分析9、i2c_algorithm10、i2c_driver的注册 一、I2C基本原理 (1)三根通信线:SCL、SD

小嵌同学的博客 2512

Linux I2C子系统

I2C总线是一种常用的串行通信协议,由SDA(数据线)和SCL(时钟线)构成,通过上拉电阻保持高电平空闲状态。它具有多主从设备特性,支持7位/10位地址,传输速率可达100kbit/s至3.4Mbit/s。Linux内核将I2C子系统分为三层:设备驱动层、核心层和适配器驱动层,采用模块化设计提高移植性。关键数据结构包括i2c_driver(驱动方法)、i2c_client(设备信息)、i2c_adapter(总线适配器)等。

m0_67219632的博客 1479

【Linux】i2c子系统

pinctrl {&i2c4 {这是我们定义的设备树节点,是添加到i2c4节点中的,i2c4节点是平台DTS已经定义好的。我们自定义了haptics@68节点,节点中有两个属性比较关键。compatible:该属性中后面的haptics表示该设备的名称或者设备节点名称。格式为。reg:该属性表示该i2c设备的slave地址(7位的)。然后在内核启动过程中会解析该设备树并且注册I2c设备。

目标:MVP 1510

I2C子系统驱动框架及应用

I2C子系统框架: 应用程序层(app层) ——————————————————————————————————– i2c driver层: 从设备驱动层(TS Sensor等) 1. 需要和应用层交互(fops cdev) 2. 封装数据,但是不知道数据如何写入到硬件,需要调用adapter层的相关函数去写 —————

韩朋的博客 6778

I2C子系统简介

I2C子系统的作用:为屏蔽不同的I2C主机控制器驱动,可以使I2C设备驱动仅关心如何操作I2C设备,而不需要了解I2C主机控制器(主控芯片)的细节,从而使I2C设备驱动可以独立存在,适用于不同的硬件平台。 I2C驱动框架的主要目标是:让驱动开发者可以在内核中方便的添加自己的I2C设备的驱动程序,从而可以更容易的在linux下驱动自己的I2C接口硬件。 一、基本知识: 1、cpu一般只有一个iic_core,有几条IIC总线(比如IIC0、IIC1、IIC2),驱动内就会有几个i2c_adapter(适配器)

qq_31885403的博客 1443

I2C子系统详解

Linux I2C子系统采用三层架构:用户空间通过/dev/i2c-X访问;核心层(i2c-core)管理设备模型和总线,提供统一API;驱动层分为适配器驱动(i2c-adapter)实现硬件操作和设备驱动(i2c-driver)实现设备功能。关键数据结构包括i2c_adapter(控制器抽象)、i2c_client(设备表示)、i2c_driver和设备消息i2c_msg。适配器驱动通过实现master_xfer等核心函数完成底层通信,为上层提供统一接口。

无 741

I2C子系统-应用视角

i2c.h。

ObviouslyCheng的博客 850
上一篇: 板级文件中的struct resource结构体
下一篇: 快速简单理解i2c标准协议
karry_vcent
博客等级 码龄15年 93粉丝 45原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值