linux i2c模型


2012/02/09 下午 3:49

i2c驱动用gpio模拟也可,当然用linux模型才是趋势。(api应用笔记)

  

维基百科,自由的百科全书

        I2C内部整合电路的称呼,是一种串行通讯总线,使用多主从架构,由飞利浦公司在1980年代为了让主板嵌入式系统手机用以连接低速周边装置而发展。I2C的正确读法为"I-squared-C" ,而"I-two-C"则是另一种错误但被广泛使用的读法,在中国则多以"I方C"称之。截至2006年11月1日为止,使用I2C协定不需要为其专利付费,但制造商仍然需要付费以获得I2C从属装置位址。



IIC总线

一般串行数据通讯都有

       时钟和数据之分,

       异步和同步之别.

       单线,双线和三线等.

I2C肯定是2线的(不算地线).

I2C协议确实很科学,比3/4线的SPI要好,   当然线多通讯速率相对就快了.

I2C的原则是:

       在SCL=1(高 电平 )时 ,  SDA千万别忽悠!!!
 
                     否则,SDA下跳则"判罚"为"起始信号S",SDA上跳则"判罚"为"停止信号P".

        在SCL=0(低电平)时,SDA随便忽悠!!!(可别忽悠 过火 到SCL跳高)

                    每个字节后应该由对方回送一个应答信号ACK做为对方在线的标志.



        非应答信号一般在所有字节的最后一个字节后. 一般要由双方协议签定.

       SCL必须由主机发送, 否则天下大乱.
 
       首字节是"片选信号",即7位从机地址加1位方向(读写)控制.

       从机收到(听到)自己的地址才能发送应答信号(必须应答!!!)表示自己在线.

       其他地址的从机不允许忽悠!!!(当然群呼可以忽悠但只能听不许说话)

        读写是站在主机的立场上定义的.

        "读"是主机接收从机数据,"写"是主机发送数据给从机.

        重复位主要用于主机从发送模式到接收模式的转换"信号",由于只有2线,

        所以收发转换肯定要比SPI复杂,因为SPI可用不同的边沿来收发数据,而I2C不行.

        在硬件I2C模块,特别是MCU/ARM/DSP等每个阶段都会得到一个准确的状态码,

        根据这个状态码可以很容易知道现在在什么状态和什么出错信息.

        7位I2C总线可以挂接127个不同地址的I2C设备,0号"设备"作为群呼地址.

        10位I2C总线可以挂接更多的10位I2C设备.

        总之,只要掌握I2C的忽悠记,一般很容易掌控... 第一个字节(为slave address)由7位地址和一位R/W读写位组成的,这字节是个器件地址。
        首先,你要知道:常用IIC接口通用器件的器件地址是由种类型号,及寻址码组成的,共7位。
        如格式如下: 

       D7 D6 D5 D4 D3 D2 D1 D0


1-器件类型由 :D7-D4 共4位决定的。这是由半导公司生产时就已固定此类型的了,也就是说这4位已是固定的。

2-用户自定义地址码 :D3-D1共3位。这是由用户自己设置的,通常的作法如EEPROM这些器件是 由外部IC的3个引脚所组合电平决定的 (用常用的名字如A0,A1,A2)。这也就是寻址码。
所以为什么同一IIC总线上同一型号的IC只能最多共挂8片同种类芯片的原因了。

3-最低一位就是R/W位。这位不用我多说了。


        在现代电子系统中,有为数众多的IC需要进行相互之间以及与外界的通信。为了提供硬件的效率和简化电路的设计,PHILIPS开发了一种用于内部IC控制的简单的双向两线串行总线I2C。I2C总线支持任何一种IC 制造工艺 ,并且PHILIPS和其他厂商提供了种类非常丰富的I2C兼容芯片。作为一个专利的控制总线,I2C已经成为世界性的工业标准。

        每个器件都有一个唯一的地址,而且可以是单接收的器件(例如:LCD 驱动器 )或者可以接收也可以发送的器件(例如: 存储器 )。发送器或接收器可以在主模式或从模式下操作,这取决于芯片是否必须启动数据的传输还是仅仅被寻址。I2C是一个多主总线,即它可以由多个连接的器件控制。
        基本的I2C总线规范于20年前发布,其 数据传输 速率最高为100Kbits/s,采用7位寻址。但是由于数据传输速率和应用功能的迅速增加,I2C总线也增强为快速模式(400Kbits/s)和10位寻址以满足更高速度和更大寻址空间的需求。
        I2C总线始终和先进技术保持同步,但仍然保持其向下兼容性。并且最近还增加了高速模式,其速度可达3.4Mbits/s。它使得I2C总线能够支持现有以及将来的高速串行传输应用,例如EEPROM和Flash存储器。 在现代电子系统中,有为数众多的IC需要进行相互之间以及与外界的通信。为了提供硬件的效率和简化电路的设计,PHILIPS开发了一种用于内部IC控制的简单的双向两线串行总线I2C。I2C总线支持任何一种IC制造工艺,并且PHILIPS和其他厂商提供了种类非常丰富的I2C兼容芯片。作为一个专利的控制总线,I2C已经成为世界性的工业标准。

        每个器件都有一个唯一的地址,而且可以是单接收的器件(例如:LCD驱动器)或者可以接收也可以发送的器件(例如:存储器)。发送器或接收器可以在主模式或从模式下操作,这取决于芯片是否必须启动数据的传输还是仅仅被寻址。I2C是一个多主总线,即它可以由多个连接的器件控制。
        基本的I2C总线规范于20年前发布,其数据传输速率最高为100Kbits/s,采用7位寻址。但是由于数据传输速率和应用功能的迅速增加,I2C总线也增强为快速模式(400Kbits/s)和10位寻址以满足更高速度和更大寻址空间的需求。
        I2C总线始终和先进技术保持同步,但仍然保持其向下兼容性。并且最近还增加了高速模式,其速度可达3.4Mbits/s。它使得I2C总线能够支持现有以及将来的高速串行传输应用,例如EEPROM和Flash存储器


----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

“ 先简单的做些了解,关键是对图中层次的理解。”

I2C bus 是multi-master 总线,单条bus上也可以有多个slave(device)。

一个host系统中可能存在多个这样的bus 和 bus adaptor。

图例:有 2个adaptor 和 3 个device(分别挂在两个adaptor 上)



总线适配器Adaptor
       Adaptor 是I2C 总线适配器,也就是Master Controller,一般是SoC中的一个接口,也可以是GPIO模拟的。

       struct i2c_adaptor



I2C Core
       是Linux内核用来维护和管理的I2C的核心部分,其中维护了两个静态的List: I2C driver结构,   I2C adapter结构

       i2c-core对设备驱动屏蔽了不同adaptor 硬件的细节,也就是对设备驱动完全透明.

Kernel API
       I2C core提供kernel API,允许一个I2C adatper,I2C driver和I2C client初始化时在I2C core中进行注册,以及退出时进行注销。同时还提供了I2C总线读写访问的一般接口,主要应用在I2C设备驱动中。


增加Adaptor
       int i2c_add_adapter(struct i2c_adapter *adapter) 或 int i2c_add_numbered_adapter(struct i2c_adapter *adap)


删除Adaptor
       static int i2c_do_del_adapter(struct device_driver *d, void *data)


注册 Driver
       int i2c_register_driver(struct module *owner,struct i2c_driver *driver)


删除 Driver
       void i2c_del_driver(struct i2c_driver *driver)


注册Client
       int i2c_attach_client(struct i2c_client *client)


删除Client
       int i2c_detach_client(struct i2c_client *client)


http://www.embexperts.com/viewthread.php?tid=186&extra=page%3D1

一般关注core层以上,作为基础设施的adapter驱动应该已注册,所以重点关注i2c_add_driver

453 #define i2c_add_driver(driver) \

454         i2c_register_driver(THIS_MODULE, driver)

也就是i2c_register_driver

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

一些硬件知识:

http://blog.csdn.net/sirzjp/article/details

串行总线I2C由数据线SDA、时钟线SCL 构成,双工同步数据传输。

       如果在系统中同时存在2个或2个以上的主器件节点企图控制总线,则形成总线冲突状态

      由于I2C引入了同步时钟和总线仲裁机制,即使出现总线冲突也不会造成信息丢失。

发生总线冲突时,为了避免信息丢失,需要进行总线仲裁以决定谁是主控器。总线仲裁是通过裁定SDA线上的控制权来解决的。

时钟同步是连接到SCL线上的所有器件进行“线与”实现的。只要有一个器件向SCL输出低电平,SCL就为低电平。因此SCL线的低电平时间由时钟低电平期最长的器件决定,而高电平时间由时钟高电平期最短的器件决定,由此形成了时钟的同步。

从设备地址也支持7位和10位方式,但大多数设备都是使用7位地址。


在通信过程应注意以下6点:
    1 进行数据传送时,在SCL为高电平期间,SDA线上电平必须保持稳定,只有SCL为低时,才允许SDA线上电平改变状态。并且每个字节传送时都是高位在前。
    2 对于应答信号,ACK=0时为有效应答位,说明接收器已经成功接收到该字节,若为1则说明接受不成功。
    3 如果被控器需要延迟下一个数据字节开始传送的时间,可以通过把SCL电平拉低并保持来强制主控器进入等待状态。
    4 主控器完成一次通信后还想继续占用总线在进行一次通信,而又不释放总线,就要利用重启动信号Sr。它既作为前一次数据传输的结束,又作为后一次传输的开始。
    5 总线冲突时,按“低电平优先”的仲裁原则,把总线判给在数据线上先发送低电平的主器件
    6 在特殊情况下,若需禁止所有发生在I2C总线上的通信,可采用封锁或关闭总线,具体操作为挂接在总线上的任一器件将SCL锁定在低电平即可。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

http://blog.csdn.net/sdustliyang/article/details/6743453

I2C的设备驱动是通过i2c_add_driver(&my_driver)向i2c-core注册

 

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 */

     

    /*

     * i2c_driver内嵌的标准driver赋值,其bus指定为i2c_bus_type

     */

    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.

     */

      

    /*注册标准的driver,driver注册后会去i2c_bus_type的设备链表上匹配

     *设备,匹配函数用的是bus端的,也就是i2c_device_match,如果匹配成功

     *将建立标准关联,并且将调用bus端的probe函数初始化这个设备,即

     *函数i2c_device_probe,下面会逐个分析

     */

    res = driver_register(&driver->driver);

    if (res)

        return res;

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

  /*

   * 把该driver的clients初始化,该成员连接着这个driver可以操作的具

   * 体设备

   */

    INIT_LIST_HEAD(&driver->clients);

    /* Walk the adapters that are already present */

    mutex_lock(&core_lock);

     

  /* 

   * 遍历挂接在该i2c设备链表上的设备,并对其都调用__process_new_driver

   * 函数

   */

    bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver);

    mutex_unlock(&core_lock);

    return 0;

}

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


" 注册的i2c_board_info数组中的信息没有生成i2c_client.? "

i2c_register_board_info的传统用法是在内核初始化时,在i2c_adapter注册之前


/**
 * i2c_register_board_info - statically declare I2C devices
 * @busnum: identifies the bus to which these devices belong
 * @info: vector of i2c device descriptors
 * @len: how many descriptors in the vector; may be zero to reserve
 * the specified bus number.
 *
 * Systems using the Linux I2C driver stack can declare tables of board info
 * while they initialize. This should be done in board-specific init code
 *near arch_initcall() time, or equivalent, before any I2C adapter driver is
 *registered.For example, mainboard init code could define several devices,
 * as could the init code for each daughtercard in a board stack.
 *
 * The I2C devices will be created later, after the adapter for the relevant
 * bus has been registered. After that moment, standard driver model tools
 * are used to bind "new style" I2C drivers to the devices. The bus number
 * for any device declared using this routine is not available for dynamic
 * allocation.
 *
 * The board info passed can safely be __initdata, but be careful of embedded
 * pointers (for platform_data, functions, etc) since that won't be copied.
 */

这点注释中已经说明了。查看i2c_adapter的注册代码可以发现,

i2c_adapter注册的时候 --> 扫描已经注册的board_info的链表 -->为每一个注册的信息调用i2c_new_device函数生成i2c_client

这样在i2c_driver注册的时候,设备和驱动就能匹配并调用probe.

如果在adapter注册之后调用i2c_register_board_info,注册的信息没有机会生成i2c_client,从而无法与i2c_driver匹配,就不会调用probe。


----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

关于i2c_client的生成,是i2c_new_device的功劳,将平台资源 i2c_board_info配置的内容转移到驱动代码。

 

426 /**

427  * i2c_new_device - instantiate an i2c device

428  * @adap: the adapter managing the device

429  * @info: describes one I2C device; bus_num is ignored

430  * Context: can sleep

431  *

432  * Create an i2c device. Binding is handled through driver model

433  * probe()/remove() methods.  A driver may be bound to this device when we

434  * return from this function, or any later moment (e.g. maybe hotplugging will

435  * load the driver module).  This call is not appropriate for use by mainboard

436  * initialization logic, which usually runs during an arch_initcall() long

437  * before any i2c_adapter could exist.

438  *

439  * This returns the new i2c client, which may be saved for later use with

440  * i2c_unregister_device(); or NULL to indicate an error.

441  */

442 struct i2c_client *

443 i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)

444 {

445         struct i2c_client       *client;

446         int                            status;

447 

448         client = kzalloc(sizeof *client, GFP_KERNEL);

449         if (!client)

450                 return NULL;

451 

452         client->adapter = adap;

453 

454        client->dev.platform_data  =  info->platform_data;

455 

456         if (info->archdata)

457                 client->dev.archdata = *info->archdata;

458 

459         client->flags   = info->flags;

460         client->addr   = info->addr;

461         client->irq      = info->irq;

462 

463         strlcpy(client->name, info->type, sizeof(client->name));

464 

465         /* Check for address validity */

466         status = i2c_check_client_addr_validity(client);

467         if (status) {

468                 dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n",

469                         client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr);

470                 goto out_err_silent;

471         }

472 

473         /* Check for address business */

474         status = i2c_check_addr_busy(adap, client->addr);

475         if (status)

476                 goto out_err;

477 

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

479         client->dev.bus = &i2c_bus_type;

480         client->dev.type = &i2c_client_type;

481 #ifdef CONFIG_OF

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

483 #endif

484 

485         dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),

486                      client->addr);

487         status = device_register(&client->dev);

488         if (status)

489                 goto out_err;

490 

491         dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",

492                 client->name, dev_name(&client->dev));

493 

494         return client;

495 

496 out_err:

497         dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x "

498                 "(%d)\n", client->name, client->addr, status);

499 out_err_silent:

500         kfree(client);

501         return NULL;

502 }

503 EXPORT_SYMBOL_GPL(i2c_new_device);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值