linux驱动之i2c总线驱动调用分析【基于linux4.4】

平台:RK3399

使用设备树描述板级资源;

框架:

linux i2c框架同样采用分层、分离的模式设计;从上到下分为  app调用层、i2c core层、驱动层;驱动层又分为 cpu平台 i2c控制器相关的驱动层以及 i2c总线上挂接的设备驱动程序;而分离的思想则体现在板级相关的信息放在设备树上实现,而通用的读写、初始化流程、操作流程等则放到驱动里面实现(类似platform总线驱动);

具体分析:

1. cpu i2c控制器驱动(adpter)

 

static struct platform_driver rk3x_i2c_driver = {
    .probe   = rk3x_i2c_probe,
    .remove  = rk3x_i2c_remove,
    .driver  = {
        .name  = "rk3x-i2c",
        .of_match_table = rk3x_i2c_match,
        .pm = &rk3x_i2c_pm_ops,
    },
};module_platform_driver(rk3x_i2c_driver)

RK3399采用以上方法向内核定义了一个platform driver,内核启动的时候,会再设备树里面I2C节点找到对应的设备节点定义compatible = "rockchip,rk3399-i2c"; ,由于 of_match_table 里面可以找到rockchip,rk3399-i2c,所以紧接着会调用 rk3x_i2c_probe 函数;rk3x_i2c_probe 函数主要是向内核注册了cpu i2c控制器驱动,并且扫描设备树里面i2c所有节点的设备信息(包括I2C根节点的信息),然后将添加扫描到的i2c设备信息加入i2c bus总线维护的链表里面 (bus->p->klist_devices),然后再用设备的名称和 i2c设备驱动里面的设备名称匹配,如果匹配成功,则调用i2c设备的probe函数:

具体分析如下:

ret = i2c_add_adapter(&i2c->adap);

adpter注册及device注册调用流程如下:

ret = i2c_add_adapter(&i2c->adap);
    i2c_register_adapter(adapter);
        of_i2c_register_devices(adap); //扫描设备树I2C总线子节点信息;包括挂接的设备名称及地址!
            for_each_available_child_of_node(adap->dev.of_node, node) {
            if (of_node_test_and_set_flag(node, OF_POPULATED))
                continue;
            of_i2c_register_device(adap, node);
          }

再深入 of_i2c_register_device(adap, node) 函数调用分析:

of_i2c_register_device(adap, node)
    i2c_new_device(adap, &info); // info里面便包含了i2c总线挂接设备的名称及地址
        status = device_register(&client->dev); // 完成 client 设备的创建
            return device_add(dev);
                error = bus_add_device(dev); // 将设备加入bus总线
                bus_probe_device(dev); // 开始设备的匹配

再深入看下 bus_probe_device(dev); // 开始设备的匹配

void bus_probe_device(struct device *dev)
{
    struct bus_type *bus = dev->bus;
    struct subsys_interface *sif;

    if (!bus)
        return;

    if (bus->p->drivers_autoprobe) // 在i2c_core初始化的时候已经置一
        device_initial_probe(dev);  

    mutex_lock(&bus->p->mutex);
    list_for_each_entry(sif, &bus->p->interfaces, node)
        if (sif->add_dev)
            sif->add_dev(dev, sif);
    mutex_unlock(&bus->p->mutex);
}

关注以上代码里面的  device_initial_probe(dev); 函数,其调用流程如下

device_initial_probe(dev);
    __device_attach(dev, true);
        ret = bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver);      if (!driver_match_device(drv, dev))  // 开始调用 i2c bus总线的match函数,匹配设备和设备驱动      return driver_probe_device(drv, dev); // 匹配成功,则调用设备驱动的probe函数

至此, adpter及设备端的注册匹配基本结束;

另外还有设备驱动部分,拿声卡 es8316来分析;

先分配一个 i2c driver结构体

static struct i2c_driver es8316_i2c_driver = {
    .driver = {
        .name        = "es8316",
        .of_match_table = es8316_of_match,
    },
    .probe    = es8316_i2c_probe,
    .remove   = es8316_i2c_remove,
    .shutdown = es8316_i2c_shutdown,
    .id_table = es8316_i2c_id,
};

module_i2c_driver(es8316_i2c_driver);
module_i2c_driver(es8316_i2c_driver)向内核注册i2c driver;主要完成了设备驱动的注册,及跟设备的匹配,如果匹配成功,则调用probe函数 es8316_i2c_probe, 具体流程如下
i2c_register_driver
    res = driver_register(&driver->driver);
        ret = bus_add_driver(drv);
            klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
            error = driver_attach(drv);

从上面流程可以看出,已经完成了把驱动放入 bus 总线维护的 drivers 链表  klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);

再具体深入下 driver_attach(drv);

driver_attach(drv);
    return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
        if (!driver_match_device(drv, dev))
        driver_probe_device(drv, dev);

至此,便完成了设备驱动与设备的匹配和设备驱动probe的调用

至此,i2c驱动基本完成,而其余跟设备相关操作,均可在probe函数里实现,比如声卡的初始化等;

 

  

原文地址:https://www.cnblogs.com/weishengzhong/p/12183182.html

时间: 2024-07-30 08:18:24

linux驱动之i2c总线驱动调用分析【基于linux4.4】的相关文章

SylixOS iMX6平台I2C总线驱动

原理概述 I2C总线驱动概述 I2C总线驱动是I2C适配器的软件实现,提供I2C适配器与从设备间完成数据通信的能力,比如起始,停止,应答信号和MasterXfer的实现函数.驱动程序包含初始化I2C总线控制器__i2cHwInit函数,操作函数集(总线传输__i2cTransfer函数,总线控制__i2cMasterCtl函数). Imx6ul控制器的硬件描述 imx6ul处理器内部集成了一个I2C控制器,通过五个寄存器来进行控制. I2Cx_IADR I2C地址寄存器 I2Cx_IFDR I2

I2C总线驱动代码

通过上篇对I2C总线的介绍,那面,接下来就需要软件部分针对I2C总线的编程实现. 具体细细道来,(前提是,已经找好两个IO口分别为SDA SCL) 1.1st function: I2c start void IIC_Start(void) { SDA_OUTPUT(); SET_SDA(); usleep(4); SET_SCL(); usleep(6); CLR_SDA(); usleep(4); } 2. 2nd :I2c stop void IIC_Stop (void) { uslee

驱动04.平台总线驱动模型——点亮LED灯

1 平台总线的简介 平台总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver.总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动:相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成. 我们可以把一个驱动程序抽出来分为两部分,一部分是硬件相关的dev,另一部分则是稳定的纯软件部分driver.而总线只是一种机制,把dev和driver这两部分建立"联系"的机制. eg: ①dev部分 a.

乾坤合一~Linux设备驱动之I2C核心、总线以及设备驱动

我思念的城市已是黄昏 为何我总对你一往情深 曾经给我快乐 也给我创伤 曾经给我希望 也给我绝望 我在遥远的城市 陌生的人群 感觉着你遥远的忧伤 我的幻想 你的忧伤,像我的的绝望,那样漫长,,,,,这是今天的旋律,直入心底~~~~~~~~~~~~~~~~ 在Linux 系统中,I2C 驱动由3 部分组成,即I2C 核心.I2C 总线驱动和I2C 设备驱动,I2C 总线仅仅使用SCL.SDA 这两根信号线就实现了设备之间的数据交互,极大地简化了对硬件资源和PCB 板布线空间的占用 1 Linux的I

linux驱动之I2C

include/linux/i2c.h struct i2c_msg;struct i2c_algorithm;struct i2c_adapter;struct i2c_client;struct i2c_driver;union i2c_smbus_data; I2C驱动主要包含三部分:I2C核心.I2C总线驱动.I2C设备驱动,它们主要的数据结构在目录:/include/linux/i2c.h struct i2c_driver 1 /* 2 * A driver is capable o

Linux+I2C总线分析(主要是probe的方式)

Linux I2C 总线浅析 ㈠ Overview Linux的I2C体系结构分为3个组成部分: ·I2C核心: I2C核心提供了I2C总线驱动和设备驱动的注册.注销方法,I2C通信方法(即“algorithm”)上层的.与具体适配器无关的代码以及探测设备.检测设备地址的上层代码等.这部分是与平台无关的. ·I2C总线驱动: I2C总线驱动是对I2C硬件体系结构中适配器端的实现.I2C总线驱动主要包含了I2C适配器数据结构i2c_adapter.I2C适配器的algorithm数据结构i2c_a

Exynos4412 IIC总线驱动开发(一)—— IIC 基础概念及驱动架构分析

关于Exynos4412 IIC 裸机开发请看 :Exynos4412 裸机开发 -- IIC总线 ,下面回顾下 IIC 基础概念 一.IIC 基础概念 IIC(Inter-Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备.IIC总线产生于在80年代,最初为音频和视频设备开发,如今主要在服务器管理中使用,其中包括单个组件状态的通信.例如管理员可对各个组件进行查询,以管理系统的配置或掌握组件的功能状态,如电源和系统风扇.可随时监

驱动开发之I2C总线

驱动开发之I2C总线: I2C:数据线和时钟线. 起始信号:时钟线为高电平,数据线由高到低跳变. 结束信号:时钟线为高电平,数据线由低到高跳变. 应答信号:第九个时钟周期,时钟线保持为高电平,数据线为低电平,此时为成功应答. 读写位:站在主机的角度考虑. 0代表主机给从机发送数据. 1代表主机接收从机的数据. 硬件原理: 数据帧的封装:主机给从机发送数据: 起始信号 + 7位从机地址 写位 + 从机给主机应答 + 主机给从机发送8位数据 + 从机给主机应答 ... + 主机给从机发送8位数据 +

Linux的操作系统I2C驱动架构解说

Linux的操作系统I2C驱动架构解说 发布时间:2006.10.16 04:52 来源:赛迪网技术社区 作者:LoneStar 最近因为工作需要涉及到了I2C总线.虽然我过去用过I2c,但看了 Linux kernel 后才发现,一个 layer 能被做到这样完善. 1.Linux的I2C驱动架 Linux中I2C总线的驱动分为两个部分,总线驱动(BUS)和设备驱动(DEVICE).其中总线驱动的职责,是为系统中每个I2C总线增加相应的读写方法.但是总线驱动本身并不会进行任何的通讯,它只是存在