linux驱动:i2c驱动(二)

来源:互联网 发布:妖尾之数据换装番茄 编辑:程序博客网 时间:2024/06/05 11:35

3、驱动源码分析

IPNC_RDK_V3.8.0.1/Source/ti_tools/ipnc_psp_arago/kernel/sound/soc/codecs/tlv320aic3x.c

 

3.1 注册模块

module_init(aic3x_modinit);

 

3.2 在初始化函数中添加i2c驱动

static int __init aic3x_modinit(void)

{

       intret = 0;

#if defined(CONFIG_I2C) ||defined(CONFIG_I2C_MODULE)

       ret= i2c_add_driver(&aic3x_i2c_driver);

       if(ret != 0) {

              printk(KERN_ERR "Failed to registerTLV320AIC3x I2C driver: %d\n",

                    ret);

       }

#endif

       returnret;

}

 

3.3 【驱动】

static struct i2c_driver aic3x_i2c_driver = {

       .driver= {

              .name = "tlv320aic3x-codec",

              .owner = THIS_MODULE,

       },

       .probe     = aic3x_i2c_probe,

       .remove= aic3x_i2c_remove,

       .id_table= aic3x_i2c_id,

};

 

3.4 probe

static int aic3x_i2c_probe(structi2c_client *i2c,

                        const struct i2c_device_id *id)

{

       structaic3x_pdata *pdata = i2c->dev.platform_data;

       structaic3x_priv *aic3x;

       intret;

       conststruct i2c_device_id *tbl;

 

       aic3x= kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);

       if(aic3x == NULL) {

              dev_err(&i2c->dev, "failed tocreate private data\n");

              return -ENOMEM;

       }

 

       aic3x->control_data= i2c;

       aic3x->control_type= SND_SOC_I2C;

 

       i2c_set_clientdata(i2c, aic3x);

       if(pdata) {

              aic3x->gpio_reset =pdata->gpio_reset;

              aic3x->setup = pdata->setup;

       }else {

              aic3x->gpio_reset = -1;

       }

 

       for(tbl = aic3x_i2c_id; tbl->name[0]; tbl++) {

              if (!strcmp(tbl->name, id->name))

                     break;

       }

       aic3x->model= tbl - aic3x_i2c_id;

 

       ret= snd_soc_register_codec(&i2c->dev,

                     &soc_codec_dev_aic3x,&aic3x_dai, 1);

       if(ret < 0)

              kfree(aic3x);

       returnret;

}

 

3.5 remove

static int aic3x_i2c_remove(structi2c_client *client)

{

       snd_soc_unregister_codec(&client->dev);

       kfree(i2c_get_clientdata(client));

       return0;

}

 

3.6 i2c_device_id

static const struct i2c_device_id aic3x_i2c_id[] = {

       [AIC3X_MODEL_3X]= { "tlv320aic3x", 0 },

       [AIC3X_MODEL_33]= { "tlv320aic33", 0 },

       [AIC3X_MODEL_3007]= { "tlv320aic3007", 0 },

       [AIC3X_MODEL_3104]= { "tlv320aic3104", 0 },

       {}

};

 

3.7 模块注销

static void __exit aic3x_exit(void)

{

#if defined(CONFIG_I2C) ||defined(CONFIG_I2C_MODULE)

       i2c_del_driver(&aic3x_i2c_driver);

#endif

}

module_exit(aic3x_exit);

 

3、与i2c相关的函数

 

Include/linux/i2c.h中

4.1 i2c_add_driver

static inline int i2c_add_driver(structi2c_driver *driver)

{

       returni2c_register_driver(THIS_MODULE,driver);

}

 

Drivers/i2c/i2c-core.c中

4.2 i2c_del_driver

/**

 *i2c_del_driver - unregister I2C driver

 *@driver: the driver being unregistered

 *Context: can sleep

 */

void i2c_del_driver(structi2c_driver *driver)

{

       mutex_lock(&core_lock);

       bus_for_each_dev(&i2c_bus_type,NULL, driver, __process_removed_driver);

       mutex_unlock(&core_lock);

 

       driver_unregister(&driver->driver);

       pr_debug("i2c-core:driver [%s] unregistered\n", driver->driver.name);

}

 

 

Include/linux/i2c.h中

4.3 i2c_set_clientdata

static inline void i2c_set_clientdata(structi2c_client *dev, void *data)

{

       dev_set_drvdata(&dev->dev,data);

}

 

4、【设备】

Arch/arm/mach-omap2/board-ti8148ipnc.c

5.1 static struct i2c_board_info __initdatati814x_i2c_boardinfo[] = {

#ifdef CONFIG_SND_SOC_TLV320AIC3X

       {

              I2C_BOARD_INFO("tlv320aic3104", 0x18),

              .platform_data =&dm8148ipnc_aic3x_data,

       },

#endif

       {

              I2C_BOARD_INFO("tps65911", 0x2D),

              .platform_data = &tps65911_pdata,

       },

};

static void __init ti814x_evm_i2c_init(void)

{

       /*There are 4 instances of I2C in TI814X but currently only one

        * instance is being used on the TI8148 EVM

        */

#ifndef CONFIG_TI8148_EVM_OPTIMIZED

       omap_register_i2c_bus(1,100, ti814x_i2c_boardinfo,

                            ARRAY_SIZE(ti814x_i2c_boardinfo));

#else

       omap_register_i2c_bus(1,100, ti814x_i2c_boardinfo,

                            ARRAY_SIZE(ti814x_i2c_boardinfo));

#endif

}

 

5.2 int __init omap_register_i2c_bus(int bus_id, u32clkrate,

                       struct i2c_board_info const *info,

                       unsigned len)

{

       interr;

 

       BUG_ON(bus_id< 1 || bus_id > omap_i2c_nr_ports());

 

       if(info) {

              err = i2c_register_board_info(bus_id,info, len);

              if (err)

                     returnerr;

       }

 

       if(!i2c_pdata[bus_id - 1].clkrate)

              i2c_pdata[bus_id - 1].clkrate = clkrate;

 

       i2c_pdata[bus_id- 1].clkrate &= ~OMAP_I2C_CMDLINE_SETUP;

 

       returnomap_i2c_add_bus(bus_id);

}

 

【TI i2c适配器驱动】

 

Arch/arm/plat-omap/i2c.c中

1、static int __init omap_i2c_add_bus(intbus_id)

{

       if(cpu_class_is_omap1())

              return omap1_i2c_add_bus(bus_id);

       else

              return omap2_i2c_add_bus(bus_id);

}

 

Arch/arm/plat-omap/i2c.c中

2、static inline int omap2_i2c_add_bus(intbus_id)

{

       intl;

       structomap_hwmod *oh;

       structomap_device *od;

       charoh_name[MAX_OMAP_I2C_HWMOD_NAME_LEN];

       structomap_i2c_bus_platform_data *pdata;

 

       omap2_i2c_mux_pins(bus_id);

 

       l= snprintf(oh_name, MAX_OMAP_I2C_HWMOD_NAME_LEN, "i2c%d", bus_id);

       WARN(l>= MAX_OMAP_I2C_HWMOD_NAME_LEN,

              "String buffer overflow in I2C%ddevice setup\n", bus_id);

       oh= omap_hwmod_lookup(oh_name);

       if(!oh) {

                     pr_err("Couldnot look up %s\n", oh_name);

                     return-EEXIST;

       }

 

       pdata= &i2c_pdata[bus_id - 1];

       /*

        * When waiting for completion of a i2ctransfer, we need to

        * set a wake up latency constraint for theMPU. This is to

        * ensure quick enough wakeup from idle, whentransfer

        * completes.

        * Only omap3 has support for constraints

        */

       if(cpu_is_omap34xx())

              pdata->set_mpu_wkup_lat =omap_pm_set_max_mpu_wakeup_lat_compat;

       od= omap_device_build(name, bus_id, oh, pdata,

                     sizeof(structomap_i2c_bus_platform_data),

                     omap_i2c_latency,ARRAY_SIZE(omap_i2c_latency), 0);

       WARN(IS_ERR(od),"Could not build omap_device for %s\n", name);

 

       returnPTR_ERR(od);

}

3、omap_hwmod_lookup(oh_name) 获取之前注册到omap_hwmod_list中的“i2c1”

 

Arch/arm/plat-omap/omap_device.c中

4、struct omap_device *omap_device_build(constchar *pdev_name, int pdev_id,

                                 struct omap_hwmod *oh, void *pdata,

                                 int pdata_len,

                                 struct omap_device_pm_latency *pm_lats,

                                 int pm_lats_cnt, int is_early_device)

{

       structomap_hwmod *ohs[] = { oh };

 

       if(!oh)

              return ERR_PTR(-EINVAL);

 

       returnomap_device_build_ss(pdev_name,pdev_id, ohs, 1, pdata,

                               pdata_len, pm_lats, pm_lats_cnt,

                               is_early_device);

}

 

5、struct omap_device *omap_device_build_ss(const char *pdev_name, int pdev_id,

                                    struct omap_hwmod **ohs, int oh_cnt,

                                    void *pdata, int pdata_len,

                                    struct omap_device_pm_latency *pm_lats,

                                    int pm_lats_cnt, int is_early_device)

{。。。。。。

ret = omap_device_register(od);

。。。。。。}

6、int omap_device_register(structomap_device *od)

{

       pr_debug("omap_device:%s: registering\n", od->pdev.name);

 

       od->pdev.dev.parent= &omap_device_parent;

       returnplatform_device_register(&od->pdev);

}

7、int platform_device_register(structplatform_device *pdev)

{

       device_initialize(&pdev->dev);

       returnplatform_device_add(pdev);

}

8、int platform_device_add(struct platform_device *pdev)

{。。。。。。

ret = device_add(&pdev->dev);

。。。。。。}

 

0 0
原创粉丝点击