I2C子系统知识(二)

来源:互联网 发布:酶标仪检测数据怎么看 编辑:程序博客网 时间:2024/06/06 04:19

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;}