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

    参考:I2C子系统之platform_device初始化——smdk2440_machine_init()

    I2C驱动框架还应用了另一种总线-设备-驱动模型,平台设备总线platform_bus_type。内核已经注册好了平台总线,驱动程序只需向平台总线添加平台设备和平台驱动。这节主要介绍如何添加平台设备。

    /*********"/arch/arm/mach-s3c64xx/mach-smdk6410.c"**********************/
    //2./arch/arm/mach-s3c2440/mach-smdk2440.c中的函数:smdk2440_machine_init()      arch_initcall级别
    static void __init smdk6410_machine_init(void)
            -->s3c_i2c0_set_platdata(NULL);
            -->i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
            -->i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
            -->platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));
                    -->platform_device_register(&s3c_device_i2c0); /*注册平台设备*/

    s3c_device_i2c0定义如下:

    /*********"/arch/arm/plat-samsung/dev-i2c0.c"**********************/
    static struct resource s3c_i2c_resource[] = {
        [0] = {
            .start = S3C_PA_IIC,
            .end   = S3C_PA_IIC + SZ_4K - 1,
            .flags = IORESOURCE_MEM,
        },
        [1] = {
            .start = IRQ_IIC,
            .end   = IRQ_IIC,
            .flags = IORESOURCE_IRQ,
        },
    };
    /*
    内核用adapter来表示主机,I2C驱动框架中的adapter就是指s3c6410的i2c控制器。
    内核中通过platform_device来描述。具体如下:
    */
    struct platform_device s3c_device_i2c0 = {
        .name          = "s3c2410-i2c",
        .id          = 0,
        .num_resources      = ARRAY_SIZE(s3c_i2c_resource),
        .resource      = s3c_i2c_resource,
        /*s3c_device_i2c0.dev.platform_data = &default_i2c_data0;*/
    };

    通过s3c_set_platdata(NULL)进一步设置s3c_device_i2c0的成员变量

    static struct s3c2410_platform_i2c default_i2c_data0 __initdata = {
        .flags        = 0,
        .slave_addr    = 0x10,
        .frequency    = 100*1000,
        .sda_delay    = 100,
    };
    
    void s3c_i2c0_cfg_gpio(struct platform_device *dev)
    {
        s3c_gpio_cfgpin(S3C64XX_GPB(5), S3C64XX_GPB5_I2C_SCL0);
        s3c_gpio_cfgpin(S3C64XX_GPB(6), S3C64XX_GPB6_I2C_SDA0);
        s3c_gpio_setpull(S3C64XX_GPB(5), S3C_GPIO_PULL_UP);
        s3c_gpio_setpull(S3C64XX_GPB(6), S3C_GPIO_PULL_UP);
    }
    
    void __init s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *pd)
    {
        struct s3c2410_platform_i2c *npd;
        if (!pd)
            pd = &default_i2c_data0;
        npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL);
        if (!npd->cfg_gpio)
            npd->cfg_gpio = s3c_i2c0_cfg_gpio;
        s3c_device_i2c0.dev.platform_data = npd;
    }

    最后调用platform_device_register(&s3c_device_i2c0)注册平台设备,其中s3c_device_i2c0包含了s3c6410上i2c相关寄存器的地址,以及地址资源,还包括i2c时钟线所需的时钟频率,i2c设备的从地址等信息,即获取了系统i2c控制器的信息,后面需要使用这些信息去初始化i2c adapter结构体。具体描述如下图所示:

    smdk6410_machine_init(void)中做的另一项工作是通过i2c_register_board_info()函数将i2c从设备的信息收集起来。

    int __init i2c_register_board_info(int busnum,struct i2c_board_info const *info, unsigned len)
    {
        int status;
    
        down_write(&__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++) {
            
            /*
            #include <linux/rwsem.h>
            */
            struct i2c_devinfo    *devinfo;
    
            devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
            if (!devinfo) {
                pr_debug("i2c-core: can't register boardinfo!
    ");
                status = -ENOMEM;
                break;
            }
    
            devinfo->busnum = busnum;
            devinfo->board_info = *info;
            list_add_tail(&devinfo->list, &__i2c_board_list);
        }
    
        up_write(&__i2c_board_lock);
    
        return status;
    }
     /*
    i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
    i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
     */
    struct i2c_board_info {
        char        type[I2C_NAME_SIZE];
        unsigned short    flags;
        unsigned short    addr;
        void        *platform_data;
        struct dev_archdata    *archdata;
        struct device_node *of_node;
        int        irq;
    };
    struct i2c_devinfo {
            struct list_head    list;
            int            busnum;
            struct i2c_board_info    board_info;
        };
    #define I2C_BOARD_INFO(dev_type, dev_addr)      .type = dev_type, .addr = (dev_addr)
    static struct i2c_board_info i2c_devs0[] __initdata = {
        { I2C_BOARD_INFO("24c08", 0x50), },
        { I2C_BOARD_INFO("wm8580", 0x1b), },
    
        { I2C_BOARD_INFO("ov965x", 0x30), }, // gjl
    };
    
    static struct i2c_board_info i2c_devs1[] __initdata = {
        { I2C_BOARD_INFO("24c128", 0x57), },    /* Samsung S524AD0XD1 */
    };

    执行完i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));这两个函数后,建立起如下的一个i2c_devinfo结构体类型的链表,链表头为__i2c_board_list,创建i2c_client结构体时会使用这些信息,每一个i2c_devinfo结构体对应一个i2c_client设备:

  • 相关阅读:
    常见数据结构和算法 的可视化
    JSON与XML
    JavaScript 中的陷阱
    C++ primer(十三)--类继承、构造函数成员初始化、虚函数、抽象基类
    mongodb学习(二)
    再谈怎样以最简单的方法将泛型为String类型的集合或String类型的数组转化为逗号间隔字符串形式
    LaTeX Subfigure 中间加入垂直线
    JAVA基础针对自己薄弱环节总结02(循环)
    软考之路--用文字记录这个漂亮的进程
    mysql异常Lock wait timeout exceeded; try restarting transaction
  • 原文地址:https://www.cnblogs.com/yangjiguang/p/6219464.html
Copyright © 2011-2022 走看看