Chinaunix首页 | 论坛 | 博客
  • 博客访问: 7547
  • 博文数量: 1
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 15
  • 用 户 组: 普通用户
  • 注册时间: 2019-11-20 11:46
文章分类
文章存档

2019年(1)

我的朋友

分类: Android平台

2019-11-20 11:46:55

0. i2c的一些说明
0.1 关于i2c驱动上的一些术语自己理解
i2c_adapter    --> i2c 总线控制器  (板子上有5个i2c总线控制器,即有5个adapter)
 i2c_algorithm  --> i2c 总线控制器的核心通信算法数据传输方法 (1个algroithm)
 i2c_client       -->  挂在i2c总线上的一个个设备     (如:bma2x2, sp0a19)
0.2 i2c控制器的目录结构
cong@ubuntu:/rk/rk3188/kernel/drivers/i2c$ tree
├── busses
│   ├── i2c-rk30-adapter.c
│   ├── i2c-rk30.c
│   └── i2c-rk30.h
├── i2c-boardinfo.c
├── i2c-core.c
├── i2c-core.h
├── i2c-dev.c
├── i2c-mux.c
└── i2c-smbus.c
i2c控制器的初始化包括以下三个方面:
    a. i2c-rk30.c  --> rk30_i2c_probe 
         这个是rk3188中i2c控制器的初始化,主要是形成一个i2c_adapter结构体并与i2c_algorithm关联起来
    b. i2c-dev.c  --> i2c_dev_init --> i2cdev_attach_adapter
    c. i2c-rk30.c --> i2c_detect_rk610
一. i2c控制器的初始化
1. i2c 控制器硬件设备的定义及注册过程
在arch/arm/mach-rk30/devices.c中
一共定义了5个i2c的设备
  1. static struct rk30_i2c_platform_data default_i2c0_data = {
  2.     .bus_num = 0,                  //0-4 共5个adapter
  3.     .is_div_from_arm = 1,
  4.     .adap_type = I2C0_ADAP_TYPE,
  5.     .sda_mode = I2C0_SDA,
  6.     .scl_mode = I2C0_SCL,
  7. };

  8. static struct resource resources_i2c0[] = {
  9.     {
  10.         .start    = IRQ_I2C0,
  11.         .end    = IRQ_I2C0,
  12.         .flags    = IORESOURCE_IRQ,
  13.     },
  14.     {
  15.         .start    = I2C0_START,
  16.         .end = I2C0_END,
  17.         .flags    = IORESOURCE_MEM,
  18.     },
  19. };

  20. static struct platform_device device_i2c0 = {
  21.     .name    = "rk30_i2c",
  22.     .id    = 0,               //id从0-4
  23.     .num_resources    = ARRAY_SIZE(resources_i2c0),
  24.     .resource    = resources_i2c0,
  25.     .dev         = {
  26.         .platform_data = &default_i2c0_data,
  27.     },
  28. }

2. i2c 驱动器驱动的初始化
在drivers/i2c/busses/i2c-rk30.c中
  1. static struct platform_driver rk30_i2c_driver = {
  2.     .probe        = rk30_i2c_probe,
  3.     .remove        = rk30_i2c_remove,
  4.     .driver        = {
  5.         .owner    = THIS_MODULE,
  6.         .name    = "rk30_i2c",        //这个name跟i2c_devices的name是一样的
  7.         .pm    = rk30_DEV_PM_OPS,
  8.     },
  9. };

  10. static int __init i2c_adap_init(void)
  11. {
  12.     return platform_driver_register(&rk30_i2c_driver);
  13. }
  14. subsys_initcall(i2c_adap_init);
根据arch/arm/mach-rk30/devices.c中名为rk30-i2c的设备,为每一个i2c设备创建一个i2c_adapter结构体,
这儿一共是5个i2c 设备,所以这个rk30_i2c_probe要调用5次
  1. static int rk30_i2c_probe(struct platform_device *pdev)
  2. {
  3.     struct rk30_i2c *i2c = NULL;
  4.     struct rk30_i2c_platform_data *pdata = NULL;
  5.     struct resource *res;
  6.     int ret;
  7.     //读取i2c dvices中的读取
  8.     pdata = pdev->dev.platform_data;
  9.     i2c = kzalloc(sizeof(struct rk30_i2c), GFP_KERNEL);
  10.     i2c->con_base = (void __iomem *)GRF_I2C_CON_BASE;
  11.     i2c_adap_sel(i2c, pdata->bus_num, pdata->adap_type);
  12.     i2c->sda_mode = pdata->sda_mode;
  13.     i2c->scl_mode = pdata->scl_mode;
  14.    
  15.     //初始化结构体i2c
  16.     strlcpy(i2c->adap.name, "rk30_i2c", sizeof(i2c->adap.name));
  17.     i2c->adap.owner = THIS_MODULE;
  18.     i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
  19.     i2c->tx_setup = TX_SETUP;
  20.     i2c->adap.retries = 2;
  21.     i2c->adap.timeout = msecs_to_jiffies(100);

  22.     spin_lock_init(&i2c->lock);
  23.     init_waitqueue_head(&i2c->wait);
  24.     mutex_init(&i2c->m_lock);

  25.     //使能i2c时钟
  26.     i2c->dev = &pdev->dev;
  27.     i2c->clk = clk_get(&pdev->dev, "i2c");
  28.     clk_enable(i2c->clk);

  29.     //ioreamp i2c控制器寄存器
  30.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  31.     i2c->ioarea = request_mem_region(res->start, resource_size(res), pdev->name);
  32.     i2c->regs = ioremap(res->start, resource_size(res));
  33.     i2c->adap.algo_data = i2c;
  34.     i2c->adap.dev.parent = &pdev->dev;
  35.     i2c->adap.nr = pdata->bus_num;
  36.    
  37.     //将i2c adapter与i2c algorithm关联起来
  38.     i2c_add_rk30_adapter(&i2c->adap);
  39.         --> i2c_add_numbered_adapter
  40.           -->i2c_register_adapter   
  41.                  //此处设置了adapter的name为:i2c-0,i2c-1,i2c-2 ..
  42.                  //然后通过 device_register创建了设备结点 /dev/i2c-0 /dev-i2c-1 ..
  43.                     //class_create 是在 drivers/i2c/i2c_dev.c中
  44.             --> i2c_scan_static_board_info 
  45.                  //将i2c_board_list上的设备用i2c_new_devices添加到i2c总线上去.
  46.                  //这也年出为什么i2c_client的注册一定要先于i2c_adapter的注册,
  47.                //因为只有i2c_client都注册过了,i2c_adapter才可以在注册时搜到i2c_client.
    1. static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
    2. {
    3.     struct i2c_devinfo    *devinfo;
    4.     down_read(&__i2c_board_lock);
    5.     list_for_each_entry(devinfo, &__i2c_board_list, list) {
    6.         //dbmsg("boad_info.type=%s", devinfo->board_info.type);
    7.         //将i2c_board_list上的设备用i2c_new_devices添加到i2c总线上去.
    8.         if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter, &devinfo->board_info))
    9.             dev_err(&adapter->dev, "Can't create device at 0x%02x\n", devinfo->board_info.addr);
    10.     }
    11.     up_read(&__i2c_board_lock);
    12. }
        //申请i2c中断,因为每次进入probe时pdev都不一样,所以这儿的中断号也不会重复
  48.     i2c->irq = ret = platform_get_irq(pdev, 0);   
  49.     request_irq(i2c->irq, i2c->i2c_irq, IRQF_DISABLED,  dev_name(&pdev->dev), i2c);

  50.     ret = rk30_i2c_register_cpufreq(i2c);   
  51.     platform_set_drvdata(pdev, i2c);
  52.     i2c->is_div_from_arm[i2c->adap.nr] = pdata->is_div_from_arm;
  53.     i2c->i2c_init_hw(i2c, 100 * 1000);
  54.     i2c_max_adap++;   
  55.     return 0;   
  56. }


二.I2c设备的初始化
2.1 i2c设备的静态注册
    注册过程如下:
         a. 初始化 i2c_board_info结构体,即声明i2c_client
         b. 调用i2c_register_board_info将i2c_board_info结构体添加到i2c_board_list中
         c. 在i2c_add_adapter的最后,即添加完成i2c_adapter之后对i2c_board_list进行遍历,将找到的i2c_client添加
a.定义i2c_board_info结构体
在arch/arm/mach-rk3188/board-rk3188-ds1006h.c中,
  1. static struct i2c_board_info __initdata i2c0_info[] = {
  2.      {
  3.         .type     = "gs_mma8452",
  4.         .addr     = 0x1d,
  5.         .flags     = 0,
  6.         .irq     = MMA8452_INT_PIN,
  7.         .platform_data = &mma8452_info,
  8.     },
  9. }
b.将i2c_board_info添加到i2c_board_list中去
在arch/arm/mach-rk3188/board-rk3188-ds1006h.c中
machine_rk30_board_init     //在平台的初始化函数中调用register
    --> rk30_i2c_register_board_info
  1. static void __init rk30_i2c_register_board_info(void)
  2. {
  3.     i2c_register_board_info(0, i2c0_info, ARRAY_SIZE(i2c0_info));   
    1. int __init i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)
    2. {
    3.     //这个函数的作用就是把定义的i2c_board_info添加到i2c_board_list中去
    4.     for (status = 0; len; len--, info++) {
    5.         struct i2c_devinfo    *devinfo;
    6.         devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
    7.         devinfo->busnum = busnum;
    8.         devinfo->board_info = *info;
    9.         list_add_tail(&devinfo->list, &__i2c_board_list);
    10.     }
    11.     return status;
    12. }
        i2c_register_board_info(1, i2c1_info, ARRAY_SIZE(i2c1_info));
  4.     i2c_register_board_info(2, i2c2_info, ARRAY_SIZE(i2c2_info));
  5.     i2c_register_board_info(3, i2c3_info, ARRAY_SIZE(i2c3_info));
  6.     i2c_register_board_info(4, i2c4_info, ARRAY_SIZE(i2c4_info));
  7.     i2c_register_board_info(5, i2c_gpio_info, ARRAY_SIZE(i2c_gpio_info));
  8. }
利用函数i2c_register_board_info将i2c_board_info结构体添加到i2c设备列表中.
这一步要先于i2c_adapter的注册,因为只有i2c_client都注册过了,i2c_adapter才可以在注册时搜到i2c_client.
c. 调用i2c_new_device添加i2c_client
然后在i2c_adapter的注册最后,调用i2c_scan_static_board_info遍历i2c_board_list添加i2c_client.
  1. static int i2c_register_adapter(struct i2c_adapter *adap)
  2. { 
  3.     rt_mutex_init(&adap->bus_lock);
  4.     mutex_init(&adap->userspace_clients_lock);
  5.     INIT_LIST_HEAD(&adap->userspace_clients);

  6.     dev_set_name(&adap->dev, "i2c-%d", adap->nr);
  7.     adap->dev.bus = &i2c_bus_type;
  8.     adap->dev.type = &i2c_adapter_type;
  9.     res = device_register(&adap->dev);            //注册完i2c_adapter之后
  10.     if (adap->nr < __i2c_first_dynamic_bus_num)
  11.         i2c_scan_static_board_info(adap);         //对i2c_register_board_info添加到i2c_board_list的设备
  12.                                                   //调用i2c_new_device添加设备

  13.     mutex_lock(&core_lock);
  14.     bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
  15.     mutex_unlock(&core_lock);

  16.     return 0;
  17. }
调用i2c_scan_static_board_info遍历i2c_board_list添加i2c_client.
  1. static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
  2. {
  3.     struct i2c_devinfo    *devinfo;
  4.     down_read(&__i2c_board_lock);
  5.     list_for_each_entry(devinfo, &__i2c_board_list, list) {
  6.         if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter, &devinfo->board_info))
  7.             dev_err(&adapter->dev, "Can't create device at 0x%02x\n", devinfo->board_info.addr);
  8.     }
  9.     up_read(&__i2c_board_lock);
  10. }

2.2 i2c设备的动态注册
     一个问题:    不知道camera 的 i2c 设备是哪儿定义的.
     a. 我在看sp0a19 camera驱动的时候发现在i2c0_info, i2c1_info, ... , i2c4_info的时候没有发现sp0a19
     b. 在注册i2c 设备的时候 i2c_register_board_info中 ARRAY_SIZE(i2c3_info) =0;
     c. 但是在 sp0a19的i2c_driver_probe函数中 adapter->nr==3;
然后在 drivers/media/video/sp0a19.c中的i2c_driver_probe加上dump_stack();发现打印如下
  1. <5>[ 3.604848] cong:drivers/media/video/sp0a19.c:sensor_probe[2921]: in i2c->probe sp0a19:adapter->nr = 3
  2. <4>[ 3.604910] [<c043e3b0>] (unwind_backtrace+0x0/0xf8) from [<c06f9a7c>] (sensor_probe+0x38/0x384)
  3. <4>[ 3.604960] [<c06f9a7c>] (sensor_probe+0x38/0x384) from [<c06ddf74>] (i2c_device_probe+0xc0/0xfc)
  4. <4>[ 3.605009] [<c06ddf74>] (i2c_device_probe+0xc0/0xfc) from [<c063f5a8>] (driver_probe_device+0x90/0x1ac)
  5. <4>[ 3.605059] [<c063f5a8>] (driver_probe_device+0x90/0x1ac) from [<c063e384>] (bus_for_each_drv+0x118/0x278)
  6. <4>[ 3.605108] [<c063e384>] (bus_for_each_drv+0x118/0x278) from [<c063f4d8>] (device_attach+0x94/0xb8)
  7. <4>[ 3.605153] [<c063f4d8>] (device_attach+0x94/0xb8) from [<c063ed28>] (bus_probe_device+0x24/0x40)
  8. <4>[ 3.605198] [<c063ed28>] (bus_probe_device+0x24/0x40) from [<c063d2ec>] (device_add+0x4bc/0x588)
  9. <4>[ 3.605244] [<c063d2ec>] (device_add+0x4bc/0x588) from [<c06dea0c>] (i2c_new_device+0x104/0x1e4)
  10. <4>[ 3.605294] [<c06dea0c>] (i2c_new_device+0x104/0x1e4) from [<c06f4ae0>] (v4l2_i2c_new_subdev_board+0x22c/0x268)
  11. <4>[ 3.605348] [<c06f4ae0>] (v4l2_i2c_new_subdev_board+0x22c/0x268) from [<c0700f5c>] (soc_camera_probe+0x2cc/0x8d4)
  12. <4>[ 3.605401] [<c0700f5c>] (soc_camera_probe+0x2cc/0x8d4) from [<c063f5a8>] (driver_probe_device+0x90/0x1ac)
  13. <4>[ 3.605449] [<c063f5a8>] (driver_probe_device+0x90/0x1ac) from [<c063e384>] (bus_for_each_drv+0x118/0x278)
  14. <4>[ 3.605497] [<c063e384>] (bus_for_each_drv+0x118/0x278) from [<c063f4d8>] (device_attach+0x94/0xb8)
  15. <4>[ 3.605543] [<c063f4d8>] (device_attach+0x94/0xb8) from [<c063ed28>] (bus_probe_device+0x24/0x40)
  16. <4>[ 3.605587] [<c063ed28>] (bus_probe_device+0x24/0x40) from [<c063d2ec>] (device_add+0x4bc/0x588)
  17. <4>[ 3.605631] [<c063d2ec>] (device_add+0x4bc/0x588) from [<c070082c>] (soc_camera_host_register+0x268/0x2d0)
  18. <4>[ 3.605682] [<c070082c>] (soc_camera_host_register+0x268/0x2d0) from [<c0705588>] (rk_camera_probe+0x488/0x7ec)
  19. <4>[ 3.605733] [<c0705588>] (rk_camera_probe+0x488/0x7ec) from [<c06407c0>] (platform_drv_probe+0x18/0x1c)
  20. <4>[ 3.605781] [<c06407c0>] (platform_drv_probe+0x18/0x1c) from [<c063f5a8>] (driver_probe_device+0x90/0x1ac)
  21. <4>[ 3.605829] [<c063f5a8>] (driver_probe_device+0x90/0x1ac) from [<c063f750>] (__driver_attach+0x8c/0x90)
  22. <4>[ 3.605876] [<c063f750>] (__driver_attach+0x8c/0x90) from [<c063e7b4>] (bus_for_each_dev+0x5c/0x88)
  23. <4>[ 3.605921] [<c063e7b4>] (bus_for_each_dev+0x5c/0x88) from [<c063ef80>] (bus_add_driver+0x180/0x254)
  24. <4>[ 3.605967] [<c063ef80>] (bus_add_driver+0x180/0x254) from [<c063fbfc>] (driver_register+0x78/0x13c)
  25. <4>[ 3.606014] [<c063fbfc>] (driver_register+0x78/0x13c) from [<c0701b98>] (rk_camera_init_async+0x10/0x18)
  26. <4>[ 3.606061] [<c0701b98>] (rk_camera_init_async+0x10/0x18) from [<c048c8c4>] (kthread+0x80/0x88)
最终发现i2c的设备注册还有另外一种方式---> i2c设备的动态注册
2.2.1 I2C camera 的定义
在arch/arm/plat-rk/rk_camera.c中
  1. static struct rk29camera_platform_data rk_camera_platform_data = {
  2.     .io_init = rk_sensor_io_init,
  3.     .io_deinit = rk_sensor_io_deinit,
  4.     .iomux = rk_sensor_iomux,
  5.     .sensor_ioctrl = rk_sensor_ioctrl,
  6.     .sensor_register = rk_sensor_register,
  7.     .register_dev = {
  8.         {
  9.             .i2c_cam_info = {
  10.                 I2C_BOARD_INFO(SENSOR_NAME_1, CONFIG_SENSOR_IIC_ADDR_1>>1)   //sp0a19,
  11.             },
  12.             .device_info = {
  13.                 .name    = "soc-camera-pdrv",
  14.                 .dev    = {
  15.                     .init_name = SENSOR_DEVICE_NAME_1,
  16.                 }
  17.             }
  18.         },
  19.     },
  20.     .register_dev_new = new_camera,
  21. };
在module_init(rk_register_camera_devices)中定义了I2C_BOARD_INFO,但是没有像静态注册一样调用i2c_register_board_info.
那动态注册时的i2c_register_board_info是如何实现的呢?
  
在drivers/media/video/soc_camera.c中
  1. static int soc_camera_probe(struct device *dev)
  2. {
  3.     if (icl->board_info) {
  4.         soc_camera_init_i2c(icd, icl);
  5.     }
  6. }

在drivers/media/video/soc_camera.c中
  1. static int soc_camera_init_i2c(struct soc_camera_device *icd,
  2.              struct soc_camera_link *icl)
  3. {
  4.     struct i2c_client *client;
  5.     struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
  6.     struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id);
  7.     struct v4l2_subdev *subdev;

  8.     icl->board_info->platform_data = icd;

  9.     subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap, icl->board_info, NULL);

  10.     client = v4l2_get_subdevdata(subdev);

  11.     dev_set_drvdata(&icd->dev, &client->dev);

  12.     return 0;
  13. }

soc_camera_probe
    --> soc_camera_init_i2c(icd, icl);
       --> v4l2_i2c_new_subdev_board
在drivers/media/video/v4l2-common.c中
  1. struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
  2.         struct i2c_adapter *adapter, struct i2c_board_info *info,
  3.         const unsigned short *probe_addrs)
  4. {
  5.     struct v4l2_subdev *sd = NULL;
  6.     struct i2c_client *client;

  7.     request_module(I2C_MODULE_PREFIX "%s", info->type);

  8.     if (info->addr == 0 && probe_addrs)
  9.         client = i2c_new_probed_device(adapter, info, probe_addrs, NULL);
  10.     else
  11.         client = i2c_new_device(adapter, info);                 //终于又出来i2c_new_device了
  12.    
  13.     sd = i2c_get_clientdata(client);

  14.     v4l2_device_register_subdev(v4l2_dev, sd))

  15.     module_put(client->driver->driver.owner);
  16.     return sd;
  17. }
  18. EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board);




三. 传输过程

ret = sensor_read(client, 0x02, &pid);
  1. static int sensor_read(struct i2c_client *client, u8 reg, u8 *val)
  2. {
  3.     
阅读(5295) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:没有了

给主人留下些什么吧!~~