i2c

来源:互联网 发布:数据库程序设计 编辑:程序博客网 时间:2024/04/30 06:20
在介绍I2C总线结构之前。要搞清楚两个概念:I2C总线控制器和I2C设备。I2C总线控制器为微控制器或微处理器提供控制I2C总线的接口,它控制所有I2C总线的特殊序列、协议、仲裁、时序,这里指MPC8250提供的I2C总线控制接口。I2C设备是指通过I2C总线与微控制器或微处理器相连的设备,如EEPROM、LCD驱动器等,这里指EEPROM。    在一个串行数据通道中.I2C总线控制器可以配置成主模式或从模式。开发过程中,MPC8250的I2C总线控制器工作在主模式,作为主设备;与总线相连的I2C设备为AT24C01A型EEPROM,作为从设备。主设备和从设备都可以工作于接收和发送状态。总线必须由主设备控制,主设备产生串行时钟控制总线的传输方向,并产生起始和停止条件。
i2c adapter是软件上抽象出来的i2c总线控制器接口物理上一条i2c总线可以挂接多个硬件设备(slave),一个CPU可以挂接多条i2c总线(想象一下PCI总线)i2c总线控制器就是CPU访问I2C总线的硬件接口,也就是你说的那几个寄存器。

简单点了, 你的开发板上有几个I2C接口,就有几个adapter , 也就是有几条I2C bus,  I2C CLIENT 对应的就是你的外围I2C 设备,有几个就有几个CLIENT ,

把这些设备插入开发板, 对应其中的一条BUS, 那么相应的就对应了其中的一个ADAPTER , 接下来的就是  CLIENT 与 ADAPTER 勾搭成对了, 后面就是做该做的事了。

数据在主机与从机间同步于SCL时钟线,在SDA数据线上一字节一字节的传输,每个字节为8位长度,一个SCL时钟脉冲传输一个数据位,数据由最高位MSB首先传输,每个传输字节后跟随一个应答位,每个位在SCL为高电平期间采样;因此,SDA线只有在SCL为低时才可以改变,在SCL为高时SDA必须保持稳定。当SCL为高时,SDA线上的跳变视为一个命令(START 或 STOP),当SDA从低到高时为停止位,当从高到低时位起始位。

I2c_driver: 是子设备的struct device_driveri2c_client :是子设备对应的 struct devicei2c_adapter :是总线对应的设备struct device_driver总线驱动调用i2c_add_adapter 或者i2c_add_numbered_adapter 来注册一个总线设备到内核 流程是:i2c_register_adapter() ->device_register()注册住设备到内核                                        ->i2c_scan_static_board_info()->i2c_new_device()->device_register(&client->dev)  /*到此处已经构建了i2c_client且把板级子设备注册进了内核。*/  板级子设备信息是通过i2c_register_board_info()函数注册的。I2c_register_board_info函数会把I2C从设备硬件特性信息注册到全局链表__i2c_board_list,在调用i2c_add_adapter函数时,会遍历__i2c_board_list获得从设备信息来构造i2c_client。i2c_add_driver用来注册子设备驱动到内核。会先注册i2c_driver到I2C总线上,然后调用I2C BUS注册的match函数进行匹配,如果匹配成功,则先调用I2C BUS中注册的probe函数,在调用i2c_driver中实现的probe函数,完成相应的工作。i2c_add_driver->i2c_register_driver->driver_register 接下来重点看driver_register是怎样的逻辑
int driver_register(struct device_driver * drv){        klist_init(&drv->klist_devices, klist_devices_get, klist_devices_put);        init_completion(&drv->unloaded);        return bus_add_driver(drv);}
主要跳转到bus_add_driver
bus_add_driver() -> driver_attach() ->bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)bus_for_each_dev遍历该总线上所有的device,执行一次__driver_attach(),看能不能将驱动关联(attach)到某个设备上去。_driver_attach()  ->drv->bus->match(dev, drv), /* 调用bus的match函数,看device和driver匹不匹配。实际调用的是i2c_bus_type里的i2c_device_match来匹配*/  ->driver_probe_device()          ->really_probe()  /*如果驱动有注册probe函数就直接调用到了。*/
看看i2c_device_match函数是怎么匹配的
i2c_device_match{                driver = to_i2c_driver(drv);                if (driver->id_table)                    return i2c_match_id(driver->id_table, client) != NULL;}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;}
可以看出其实比较的就是id_table里的名字。


每个bus都有一个drivers_autoprobe变量,用于控制是否在device或者driver注册时,自动probe。该变量默认为1(即自动probe).在device_register函数里也会调用

bus_probe_device来对设备和驱动进行匹配,逻辑和上面类似。


                                             
0 0