i2c驱动分析

234  * struct i2c_board_info - template for device creation
235  * @type: chip type, to initialize i2c_client.name
236  * @flags: to initialize i2c_client.flags
237  * @addr: stored in i2c_client.addr
238  * @platform_data: stored in i2c_client.dev.platform_data
239  * @archdata: copied into i2c_client.dev.archdata
240  * @of_node: pointer to OpenFirmware device node
241  * @irq: stored in i2c_client.irq
242  *
243  * I2C doesn't actually support hardware probing, although controllers and
244  * devices may be able to use I2C_SMBUS_QUICK to tell whether or not there's
245  * a device at a given address.  Drivers commonly need more information than
246  * 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 devices
249  * 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 address
266  * @dev_type: identifies the device type
267  * @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.  Optional
271  * 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 __init
i2c_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);
} 



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值