i2c驱动分析

来源:互联网 发布:数据分析师有哪些证书 编辑:程序博客网 时间:2024/04/28 11:55

234  * struct i2c_board_info - template for device creation235  * @type: chip type, to initialize i2c_client.name236  * @flags: to initialize i2c_client.flags237  * @addr: stored in i2c_client.addr238  * @platform_data: stored in i2c_client.dev.platform_data239  * @archdata: copied into i2c_client.dev.archdata240  * @of_node: pointer to OpenFirmware device node241  * @irq: stored in i2c_client.irq242  *243  * I2C doesn't actually support hardware probing, although controllers and244  * devices may be able to use I2C_SMBUS_QUICK to tell whether or not there's245  * a device at a given address.  Drivers commonly need more information than246  * that, such as chip type, configuration, associated IRQ, and so on.247  *248  * i2c_board_info is used to build tables of information listing I2C devices249  * that are present.  This information is used to grow the driver model tree.250  * For mainboards this is done statically using i2c_register_board_info();251  * bus numbers identify adapters that aren't yet available.  For add-on boards,252  * i2c_new_device() does this dynamically with the adapter already known.253  */254 struct i2c_board_info {255         char            type[I2C_NAME_SIZE];256         unsigned short  flags;257         unsigned short  addr;258         void            *platform_data;259         struct dev_archdata     *archdata;260         struct device_node *of_node;261         int             irq;262 };263 264 /**265  * I2C_BOARD_INFO - macro used to list an i2c device and its address266  * @dev_type: identifies the device type267  * @dev_addr: the device's address on the bus.268  *269  * This macro initializes essential fields of a struct i2c_board_info,270  * declaring what has been provided on a particular board.  Optional271  * fields (such as associated irq, or device-specific platform_data)272  * are provided using conventional syntax.273  */274 #define I2C_BOARD_INFO(dev_type, dev_addr) \275         .type = dev_type, .addr = (dev_addr)


Probe方式(new style)

●    构建i2c_driver

和LEGACY方式一样,也需要构建i2c_driver,但是内容有所不同。

static struct i2c_driver pca953x_driver = {
                .driver = {
                        .name= "pca953x",
                        },
                        .probe= pca953x_probe, //当有i2c_client和i2c_driver匹配时调用
                        .remove= pca953x_remove,//注销时调用
                        .id_table= pca953x_id,//匹配规则
        };

●    注册i2c_driver

static int __init pca953x_init(void)
        {
                return i2c_add_driver(&pca953x_driver);
        }
        module_init(pca953x_init);

在注册i2c_driver的过程中,是将driver注册到了i2c_bus_type的总线上。此总线的匹配规则是:

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_client的名称和id_table中的名称做匹配的。本驱动中的id_table为

static const  struct i2c_device_id pca953x_id[] = {
                { "pca9534", 8, },
                { "pca9535", 16, },
                { "pca9536", 4, },
                { "pca9537", 4, },
                { "pca9538", 8, },
                { "pca9539", 16, },
                { "pca9554", 8, },
                { "pca9555", 16, },
                { "pca9557", 8, },
                { "max7310", 8, },
                { }
        };

看到现在我们应该会有这样的疑问,在Adapter模式中,i2c_client是我们自己构造出来的,而现在的i2c_client是从哪来的呢?看看下面的解释

●    注册i2c_board_info

对于Probe模式,通常在平台代码中要完成i2c_board_info的注册。方法如下:

static struct i2c_board_info__initdata test_i2c_devices[] = {
                {
                        I2C_BOARD_INFO("pca9555", 0x27),//pca9555为芯片名称,0x27为芯片地址
                        .platform_data = &pca9555_data,
                }, 

     {
                        I2C_BOARD_INFO("mt9v022", 0x48),
                        .platform_data = &iclink[0], /* With extender */
                }, 

     {
                        I2C_BOARD_INFO("mt9m001", 0x5d),
                        .platform_data = &iclink[0], /* With extender */
                },
        };
        i2c_register_board_info(0, test_i2c_devices,ARRAY_SIZE(test_i2c_devices)); //注册

上面申请这个数组表示i2c总线上面有这么些设备,包含驱动名称,从地址地址,中断号什么的,还有私有数据结构

i2c_client就是在注册过程中构建的。但有一点需要注意的是i2c_register_board_info并没有EXPORT_SYMBOL给模块使用。

●    字符驱动注册

在Probe方式下,添加字符驱动的位置在pca953x_probe中。

static int __devinit pca953x_probe(struct i2c_client *client,const struct i2c_device_id *id)
        {
                        ……
                        /****字符设备驱动注册位置****/
                        ……
                        return 0;
        }

●    注销i2c_driver

static void __exit pca953x_exit(void)
        {
                i2c_del_driver(&pca953x_driver);
        }
        module_exit(pca953x_exit);

●    注销字符设备驱动

在Probe方式下,注销字符驱动的位置在pca953x_remove中。

static int __devinit pca953x_remove (struct i2c_client *client)
        {
                ……
                /****字符设备驱动注销的位置****/
                ……
                return 0;
        }

●    I2C设备的数据交互方法(即:调用适配器操作设备的方法)和Adapter方式下相同。


函数初始化函数i2c_register_board_info(0, msm_i2c_board_info,ARRAY_SIZE(msm_i2c_board_info));这个函数相当于就会去注册i2c设备信息实现如下int __initi2c_register_board_info(int busnum,    struct i2c_board_info const *info, unsigned len){    int status;    mutex_lock(&__i2c_board_lock);    /* dynamic bus numbers will be assigned after the last static one */    if (busnum >= __i2c_first_dynamic_bus_num)        __i2c_first_dynamic_bus_num = busnum + 1;    for (status = 0; len; len--, info++) {        struct i2c_devinfo  *devinfo;        devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);        if (!devinfo) {            pr_debug("i2c-core: can't register boardinfo!\n");            status = -ENOMEM;            break;        }        devinfo->busnum = busnum;        devinfo->board_info = *info;        list_add_tail(&devinfo->list, &__i2c_board_list);    }    mutex_unlock(&__i2c_board_lock);    return status;}  

现在回到函数i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)中
list_add_tail(&devinfo->list, &__i2c_board_list);
这句话会将i2c设备添加到全局链表__i2c_board_list上面去

实际上到这里如果我们在arch这边的board——info里面定义了设备的话,那么这是i2c设别在这条链表上面了,

static void i2c_scan_static_board_info(struct i2c_adapter *adapter){    struct i2c_devinfo  *devinfo;    mutex_lock(&__i2c_board_lock);    list_for_each_entry(devinfo, &__i2c_board_list, list) {                                                                                                                            if (devinfo->busnum == adapter->nr                && !i2c_new_device(adapter,                        &devinfo->board_info))            printk(KERN_ERR "i2c-core: can't create i2c%d-%04x\n",                i2c_adapter_id(adapter),                devinfo->board_info.addr);    }       mutex_unlock(&__i2c_board_lock);} 



原创粉丝点击