zoukankan      html  css  js  c++  java
  • I2C驱动框架(四)

    参考:I2C子系统之platform_driver初始化——I2C_adap_s3c_init()

    在完成platform_device的添加之后,i2c子系统将进行platform_driver的注册过程。platform_driver的注册通过调用初始化函数i2c_adapter_s3c_init函数来完成。

    static struct platform_device_id s3c24xx_driver_ids[] = {
        {
            .name        = "s3c2410-i2c",
            .driver_data    = TYPE_S3C2410,
        }, {
            .name        = "s3c2440-i2c",
            .driver_data    = TYPE_S3C2440,
        }, { },
    };
    MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
    static struct platform_driver s3c24xx_i2c_driver = {
        .probe        = s3c24xx_i2c_probe,
        .remove        = s3c24xx_i2c_remove,
        .id_table    = s3c24xx_driver_ids,
        .driver        = {
            .owner    = THIS_MODULE,
            .name    = "s3c-i2c",
            .pm    = S3C24XX_DEV_PM_OPS,
        },
    };
    
    static int __init i2c_adap_s3c_init(void)
    {
        return platform_driver_register(&s3c24xx_i2c_driver);
    }
     subsys_initcall(i2c_adap_s3c_init);

    这里先说一下MODULE_DEVICE_TABLE宏的作用:

    MODULE_DEVICE_TABLE(platform, xx_driver_ids);

    MODULE_DEVICE_TABLE一般用在热插拔的设备驱动中。
    上述xx_driver_ids结构,是此驱动所支持的设备列表。
    作用是:将xx_driver_ids结构输出到用户空间,这样模块加载系统在加载模块时,就知道了什么模块对应什么硬件设备。
    用法是:MODULE_DEVICE_TABLE(设备类型,设备表),其中,设备类型,包括USB,PCI等,也可以自己起名字,
    上述代码中是针对不同的平台分的类;设备表也是自己定义的,它的最后一项必须是空,用来标识结束。

    平台驱动匹配到平台设备后,调用s3c24xx_i2c_driver.probe函数,即static int s3c24xx_i2c_probe(struct platform_device *pdev)。

    static int s3c24xx_i2c_probe(struct platform_device *pdev)
        -->struct s3c24xx_i2c *i2c;//分配s3c24xx_i2c结构体并初始化
        -->ret = s3c24xx_i2c_init(i2c);//S3C6410 I2C控制器初始化
        -->ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,
                  dev_name(&pdev->dev), i2c);//设置中断
        -->ret = i2c_add_numbered_adapter(&i2c->adap);

    分配一个s3c24xx_i2c结构体,并根据平台设备的内容填充该结构体,如下图

    下面具体分析i2c_add_numbered_adapter()函数,该函数根据传入的i2c_adapter结构体的内容分别在i2c_bus_type总线上注册adapter设备和client设备。

    该函数执行后在/sys/bus/i2c/devices目录下生成如下图示文件

    i2c_add_numbered_adapter(&i2c->adap);    
        -->i2c_register_adapter(adap);
            -->dev_set_name(&adap->dev, "i2c-%d", adap->nr);
            -->adap->dev.bus = &i2c_bus_type;
            -->adap->dev.type = &i2c_adapter_type;
            -->res = device_register(&adap->dev);//注释1,注册i2c总线 adapter设备
            -->i2c_scan_static_board_info(adap);
                -->list_for_each_entry(devinfo, &__i2c_board_list, list)
                    -->i2c_new_device(adapter,&devinfo->board_info))
                        -->struct i2c_client    *client;//分配i2c_client结构体并初始化
                        -->client->adapter = adap;
                        -->client->dev.parent = &client->adapter->dev;
                        -->client->dev.bus = &i2c_bus_type;
                        -->client->dev.type = &i2c_client_type;
                        -->client->dev.of_node = info->of_node;
                        -->strlcpy(client->name, info->type, sizeof(client->name));
                        -->dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),client->addr);
                        -->status = device_register(&client->dev); //注释2,注册i2c总线 client设备
            -->bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);

    list_for_each_entry(devinfo, &__i2c_board_list, list)遍历I2C驱动框架(三)中最后图示的链表,以adapter结构体和找到的devinfo结构体中的i2c_board_info结构体为参数在i2c_bus_type总线上添加client设备。

    最后还调用bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter)来扫描i2c总线,检测刚注册到i2c总线的adapter是否有对应的驱动。不过目前肯定失败,因为到目前为止还未注册adapter driver。

     bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter)与I2C驱动框架(二)中分析的

    bus_for_each_dev(&i2c_bus_type, NULL, &dummy_driver, __process_new_driver)相似。

    bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);//遍历i2c_bus_type总线上的驱动
        //以找到的驱动和i2c_adapter结构体为参数调用__process_new_driver函数
        -->__process_new_adapter(struct device_driver *d, void *data)
            -->i2c_do_add_adapter(to_i2c_driver(d), data);
                -->i2c_detect(adap, driver);
    static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
        -->int adap_id = i2c_adapter_id(adapter);//获取adapter的序列号,即处理器的第几个I2C控制器
        -->const unsigned short *address_list = driver->address_list; //获取I2C从设备的地址数组
        -->if (!(adapter->class & driver->class)) return 0; //类型匹配后才继续执行
        -->struct i2c_client *temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);//分配i2c_client结构体
        -->temp_client->adapter = adapter;
        -->for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) //遍历address_list里的i2c地址
            -->temp_client->addr = address_list[i];//设置从地址到i2c_client结构体
            -->i2c_detect_address(temp_client, driver);//检测该从地址对应的设备是否存在
    
    
    static int i2c_detect_address(struct i2c_client *temp_client,struct i2c_driver *driver)
        -->int addr = temp_client->addr;
        -->i2c_check_addr_validity(addr);//检测地址有效性
        -->i2c_check_addr_busy(adapter, addr);//检测设备是否正在使用,同一条物理I2Cbus上不能有两个相同address的器件
        -->i2c_default_probe(adapter, addr);//检测i2c物理总线上是否有设备应答
        -->struct i2c_board_info info.addr=temp_client->addr
        -->driver->detect(temp_client, &info);//调用i2c_driver的detect函数检测设备,并经info.type赋值
        -->struct i2c_client *client = i2c_new_device(adapter, &info);//在i2b_bus_type总线上创建i2c_client设备
        -->list_add_tail(&client->detected, &driver->clients);//创建设备成功则将该i2c_client挂到i2c_driver的链表上
  • 相关阅读:
    [DB2]删除大数据量数据及57011错误处理
    [DB2]DB2日常维护——REORG TABLE命令优化数据库性能
    [转]解读DIV CSS网页布局中CSS无效十个原因
    [DB2]DB2 sqlstate 57016 原因码 "7"错误
    [翻译]15个最常见的WCF问题
    [DB2]DB2数据库备份与恢复和导出表结构与导入导出表数据
    [转]网站(bs系统)怎样实现即时消息思路总结
    【摘抄】DB2字符集问题
    [转]jQuery必知必熟基础知识
    sql 2005/2008 订阅与发布的几个概念
  • 原文地址:https://www.cnblogs.com/yangjiguang/p/6220451.html
Copyright © 2011-2022 走看看