linux驱动之i2c驱动

1i2c基础

     I2C(Inter-IntegratedCircuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。
简单的I2C协议理解
一.  技术性能:
      工作速率有100Kbit/s、400Kbit/s和3.4Mbit/s三种;(一般使用小于100Kbit/s)
      支持多主控模块,但同一时刻只允许有一个主控;(一般只有一个主控)
      由数据线SDA和时钟SCL构成的串行总线;
      每个电路和模块都有唯一的地址;(7位地址)                  
      连接到总线的接口数量由总线电容400pF的限制决定;
二. 基本工作原理:
        SDA和SCL都是双向线路,都通过一个电流源或上拉电阻连接到正的电源电压。当总线空闲时,这两条线路都是高电平。以启动信号START来掌管总线,以停止信号STOP来释放总线;
       启动信号START后紧接着发送一个地址字节,其中7位为被控器件的地址码,一位为读/写控制位R/W,每个数据字节在传送时都是高位在前; 

 三. 寻址约定
          高7位为地址码,其分为两部分:
    1. 固定部分,不可改变,由厂家固化的统一地址;
    2. 可编程部分,此部分由器件可使用的管脚决定。例如,如果器件有4个固定的和3个可编程的地址位,那么相同的总线上共可以连接8个相同的器件(并非所有器件都可以设定)。

 

2I2C驱动分析(只分析架构)

          内核i2c驱动的代码逻辑图,然后分析源码如何实现这个图

 

需要的源码kernel/drivers/i2c

 

           i2c-core.c这个文件实现了I2C核心层的功能

        i2c-dev实现了I2C适配器设备文件的功能 

           busses  包含了一些I2C总线的驱动(每个总线驱动代表一个adapter)

           algos   一些I2C总线适配器的algorithm.

           muxes  实现多路复用的代码(就是一个多路复用器,意义不大)

           (红色部分与具体的i2c硬件相关,不是固定的)

此外,还需要一个i2c_driver注册的实例,例如TP驱动(驱动注册i2c的过程都一样,这里只关注几个函数)

         结构含义:

                   i2c_adapter——一个i2c总线

                   i2c_client——一个挂在i2c的设备(外设)

                   i2c_driver——控制i2c设备(外设)的驱动

因此,一个i2c_ adapter可以对应多个i2c_client,而一个i2c_client与一个i2c_driver对应

 

先看一下一个实际设备如何注册,再看linux内核本身做了哪些工作

1、  注册一个i2c板文件(注册外设信息)

i2c_register_board_info(int busnum,struct i2c_board_info const*info, unsigned len)

   busnum——i2c总线号,代表挂在i2c-0,还是i2c-1,还是i2c-2…上面

   i2c_board_info——一般只定义设备名,设备地址(外设从设备信息)

   unsignedlen  ——i2c_board_info的个数(第二项可以定义i2c_board_info数组,即一次性的写入多个设备信息)

   在dts被引入后,可能没有这一步操作,但是效果相同,在dtb被解压的时候也会进行这一步操作

2、  i2c_add_driver(注册一个i2c设备)

i2c_add_driver(driver) ——注册i2c驱动

#define i2c_add_driver(driver) i2c_register_driver(THIS_MODULE,driver)---->

i2c_register_driver---->

    driver->driver.owner =owner;

    driver->driver.bus =&i2c_bus_type;

    driver_register(&driver->driver);                      //注册驱动,与设备匹配(从设备)

    i2c_for_each_dev(driver, __process_new_driver);---->

             //对每一个i2c_device使用__process_new_driver的操作

                 __process_new_driver ---->

                        i2c_do_add_adapter(data,to_i2c_adapter(dev));---->

      这一步执行的前提是i2c_adapter和i2c_client已经被注册了,这里只是得到他们,然后与他们联系起来。

      driver_register不多解释,关键是深入会执行drv->bus->match操作,就是i2c_bus_type的match操作。(他的目的是与i2c_client匹配,而且和设备匹配)

看源码:

static int i2c_device_match(structdevice *dev, struct device_driver *drv){

         structi2c_client       *client =i2c_verify_client(dev);

         if(of_driver_match_device(dev, drv))

         …… …

}

          因为i2c_client->dev就是i2c总线下的设备,所以driver与device匹配通过dev就可以与i2c_client关联到一起。

   同理i2c_adapter->dev也是如此把driver与adapter联系到一起,匹配过程就是match操作,match操作来源于板文件注册信息。

 

3、  看一下i2c_adapter是如何注册的(这里随便在i2c_buses目录下面找一份i2c代码来举例)

static int xxxxx_i2c_probe(struct platform_device *pdev){          //通过字符设备注册执行的

                  i2c->adap.algo    = &s3c24xx_i2c_algorithm;

                  i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;

                  ret =i2c_add_numbered_adapter(&i2c->adap);

                  …  …

                  of_i2c_register_devices(&i2c->adap);

}

看一下i2c_add_numbered_adapter代码:

__i2c_add_numbered_adapter(structi2c_adapter *adap)---- >      

   i2c_register_adapter(struct i2c_adapter*adap) ---- >

     dev_set_name(&adap->dev,"i2c-%d", adap->nr);                  //设备名

          adap->dev.bus= &i2c_bus_type;                                       //挂在i2c_bus下面

          adap->dev.type= &i2c_adapter_type;

          res= device_register(&adap->dev);                                   //注册设备

看一下of_i2c_register_devices(structi2c_adapter *adap)代码:

   ------> i2c_new_device(struct i2c_adapter*adap, struct i2c_board_info const *info) ---- >                     

                   client->adapter = adap;

                   client->addr = info->addr;                                         //板文件地址

                   strlcpy(client->name,info->type, sizeof(client->name));   //把板文件name给client->name

                   client->dev.parent= &client->adapter->dev;

                   client->dev.bus = &i2c_bus_type;

                   client->dev.type = &i2c_client_type;

                   client->dev.of_node = info->of_node; 

                   status =device_register(&client->dev);

       i2c-core.c里面全部都是上面操作的辅助接口函数

到此,一个整体的框架便完全分析完了(至于adapter如何通过algorithm来控制底层硬件,这里就不讨论了)

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值