代码编织梦想

开发板    :mini2440
内核版本:linux2.6.32.2
驱动程序参考:韦东山老师毕业班i2c


内容概括:

   1、adapter client 简介
   2、adapter 驱动框架
      2.1 设备侧
      2.2 驱动侧
         2.2.1 probe 函数
         2.2.1.1 注册adapter
            new_device del_device
            board_info
            i2c_detect
            i2c_new_device
   3、i2c 设备驱动框架
      3.1 i2c_bus_type
      3.2 i2c_driver
      3.3 i2c_device
   4、写设备驱动程序

   5、写adapter驱动程序


1、adapter client 简介
  在内核里,i2c 驱动框架大概分为两层,adapter 驱动 和 设备驱动,adapter 英文翻译过来为 “适配器”,适配器并不恰当,根据我的理解,adapter 指的是我们 mcu 里的 i2c 控制模块,就是那堆寄存器,因为一个 mcu 里的i2c控制模块是固定的(寄存器参数、以及收发数据的方法),因此大多数情况下,它们都有芯片厂商写好了,然而我们学习的过程中自己动手写一写也并不困难。对于s3c2440仅仅有一个i2c_adapter,但是别的Mcu可能有多个。至于Client,它对应于muc外围的I2c设备,每一个i2c设备都由一个唯一的client来描述。


  1. struct i2c_adapter {
  2. struct module *owner;
  3. unsigned int id;
  4. unsigned int class; /* classes to allow probing for */
  5. const struct i2c_algorithm *algo; /* the algorithm to access the bus */
  6. void *algo_data;
  7. /* data fields that are valid for all devices */
  8. u8 level; /* nesting level for lockdep */
  9. struct mutex bus_lock;
  10. int timeout; /* in jiffies */
  11. int retries;
  12. struct device dev; /* the adapter device */
  13. int nr;
  14. char name[ 48];
  15. struct completion dev_released;
  16. };
    简单扫一眼,i2c_adapter 封装了 struct device ,因此它是作为一个设备注册到内核中去的(稍后我们会知道,它是注册到i2c_bus_type里),此外非常重要的一个成员struct i2c_algorithm *algo ,这就是我们上边提到的 i2c 控制器收发数据的方法。
  1. struct i2c_algorithm {
  2. int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
  3. int num);
  4. int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
  5. unsigned short flags, char read_write,
  6. u8 command, int size, union i2c_smbus_data *data);
  7. /* To determine what the adapter supports */
  8. u32 (*functionality) (struct i2c_adapter *);
  9. };

    master_xfer 对应于i2c协议子集 smbus ,有些设备只支持这个协议

    smbus_xfer 对应于普通的 i2c 传输协议

    functionality 用来描述,adapter 所具有的功能,比如是否支持 smbus

  1. struct i2c_client {
  2. unsigned short flags; /* div., see below */
  3. unsigned short addr; /* chip address - NOTE: 7bit */
  4. /* addresses are stored in the */
  5. /* _LOWER_ 7 bits */
  6. char name[I2C_NAME_SIZE];
  7. struct i2c_adapter *adapter; /* the adapter we sit on */
  8. struct i2c_driver *driver; /* and our access routines */
  9. struct device dev; /* the device structure */
  10. int irq; /* irq issued by device */
  11. struct list_head detected;
  12. };
    i2c_client 本质上是一个 i2c_"dev", 它包含了与它配对的 driver ,以及它所在的 adapter(i2c设备在物理连接上,连接到了哪个adapter),后面分析时会看到,它也是作为设备注册到i2c_bus_type


2、adapter 驱动框架
    在我所使用的这个内核里,2440的i2c_adapter框架是基于 platform_bus_type 的,关于 platform_bus_type 别的文章已经分析过了,这里不做赘述,只简单提一下,当设备或驱动注册到 platform_bus_type 时,首先会查找驱动是否有id_table,如果有根据id_table进行匹配(就是看id_table里有无设备的名字),否则匹配设备名字和驱动名字。匹配成功则调用驱动里的probe函数。
    2.1 设备侧
        根据设备总线驱动模型的分层思想,将一个驱动程序分为 device 和 driver 两层,那么 device 里提供底层的硬件资源,在 driver 中取出这些资源进行使用。那么我们就可以猜测到 i2c_adapter 驱动的设备侧 至少应该含有哪些资源?

        1、存器地址必须有吧,因为我们要使用这些寄存器,不然怎么传输。
        2、中断必须有吧,i2c传输过程中可是离不开中断的。
        下面,我们就开详细的看一看,i2c_adapter 驱动的设备侧提供了哪些设备资源。
        mach-smdk2410.c (arch\arm\mach-s3c2410) 中定义了个指针数组,这里面有我们想要的 s3c_device_i2c0

  1. static struct platform_device *smdk2410_devices[] __initdata = {
  2. &s3c_device_usb,
  3. &s3c_device_lcd,
  4. &s3c_device_wdt,
  5. &s3c_device_i2c0,
  6. &s3c_device_iis,
  7. };
  8. dev-i2c0.c (arch\arm\plat-s3c)
  9. struct platform_device s3c_device_i2c0 = {
  10. .name = "s3c2410-i2c",
  11. #ifdef CONFIG_S3C_DEV_I2C1
  12. .id = 0,
  13. # else
  14. .id = -1,
  15. #endif
  16. .num_resources = ARRAY_SIZE(s3c_i2c_resource),
  17. .resource = s3c_i2c_resource,
  18. };
  19. static struct resource s3c_i2c_resource[] = {
  20. [ 0] = {
  21. .start = S3C_PA_IIC1,
  22. .end = S3C_PA_IIC1 + SZ_4K - 1,
  23. .flags = IORESOURCE_MEM,
  24. },
  25. [ 1] = {
  26. .start = IRQ_IIC1,
  27. .end = IRQ_IIC1,
  28. .flags = IORESOURCE_IRQ,
  29. },
  30. };
    是不是正如我们所料,在资源文件中提供了 物理寄存器 以及 中断资源。
    Mach-smdk2410.c (arch\arm\mach-s3c2410),将 s3c_device_i2c0 注册到 平台设备总线上去
  1. static void __init smdk2410_init(void)
  2. {
  3. s3c_i2c0_set_platdata( NULL);
  4. platform_add_devices(smdk2410_devices, ARRAY_SIZE(smdk2410_devices));
  5. smdk_machine_init();
  6. }
  7. dev-i2c0.c (arch\arm\plat-s3c)
  8. static struct s3c2410_platform_i2c default_i2c_data0 __initdata = {
  9. .flags = 0,
  10. .slave_addr = 0x10,
  11. .frequency = 100* 1000,
  12. .sda_delay = 100,
  13. };
  14. void __init s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *pd)
  15. {
  16. struct s3c2410_platform_i2c *npd;
  17. if (!pd)
  18. pd = &default_i2c_data0;
  19. npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL);
  20. if (!npd)
  21. printk(KERN_ERR "%s: no memory for platform data\n", __func__);
  22. else if (!npd->cfg_gpio)
  23. npd->cfg_gpio = s3c_i2c0_cfg_gpio;
  24. s3c_device_i2c0.dev.platform_data = npd;
  25. }
  26. setup-i2c.c (arch\arm\plat-s3c24xx)
  27. void s3c_i2c0_cfg_gpio(struct platform_device *dev)
  28. {
  29. s3c2410_gpio_cfgpin(S3C2410_GPE( 15), S3C2410_GPE15_IICSDA);
  30. s3c2410_gpio_cfgpin(S3C2410_GPE( 14), S3C2410_GPE14_IICSCL);
  31. }
  32. S3c244x.c (arch\arm\plat-s3c24xx)
  33. void __init s3c244x_map_io(void)
  34. {
  35. /* register our io-tables */
  36. iotable_init(s3c244x_iodesc, ARRAY_SIZE(s3c244x_iodesc));
  37. /* rename any peripherals used differing from the s3c2410 */
  38. s3c_device_sdi.name = "s3c2440-sdi";
  39. s3c_device_i2c0.name = "s3c2440-i2c";
  40. s3c_device_nand.name = "s3c2440-nand";
  41. s3c_device_usbgadget.name = "s3c2440-usbgadget";
  42. }
    在将 s3c_device_i2c0 注册到 平台设备总线上去之前,还提供了以上的其它信息,包括i2c控制器作为从机的默认slave_addr等,以及引脚的配置函数。注意,s3c_device_i2c0.name  = "s3c2440-i2c";
    

    2.2 驱动侧
        驱动侧的工作大概是取出设备侧的资源进行利用,比如Ioremap,配置寄存器,注册中断等等

  1. i2c-s3c2410.c (drivers\i2c\busses)
  2. static struct platform_driver s3c24xx_i2c_driver = {
  3. .probe = s3c24xx_i2c_probe,
  4. .remove = s3c24xx_i2c_remove,
  5. .id_table = s3c24xx_driver_ids,
  6. .driver = {
  7. .owner = THIS_MODULE,
  8. .name = "s3c-i2c",
  9. .pm = S3C24XX_DEV_PM_OPS,
  10. },
  11. };
  12. static struct platform_device_id s3c24xx_driver_ids[] = {
  13. {
  14. .name = "s3c2410-i2c",
  15. .driver_data = TYPE_S3C2410,
  16. }, {
  17. .name = "s3c2440-i2c",
  18. .driver_data = TYPE_S3C2440,
  19. }, { },
  20. };
  21. static int __init i2c_adap_s3c_init(void)
  22. {
  23. return platform_driver_register(&s3c24xx_i2c_driver);
  24. }
  25. subsys_initcall(i2c_adap_s3c_init);
        我们在分析platform总线模型的时候,我们知道platform_bus_type->match函数是首先根据 driver->id_table 来进行匹配device的,前面讲了s3c_device_i2c0.name  = "s3c2440-i2c",因此,匹配成功会调用 s3c24xx_i2c_driver->probe 函数,也就是 s3c24xx_i2c_probe ,它是个重点。

    2.3 probe 函数分析

  1. i2c-s3c2410.c (drivers\i2c\busses)
  2. static int s3c24xx_i2c_probe(struct platform_device *pdev)
  3. {
  4. struct s3c24xx_i2c *i2c;
  5. struct s3c2410_platform_i2c *pdata;
  6. struct resource *res;
  7. int ret;
  8. // 还记得,我们在 device 里放的platform_data么,是时候取出来使用了
  9. pdata = pdev->dev.platform_data;
  10. i2c = kzalloc( sizeof(struct s3c24xx_i2c), GFP_KERNEL);
  11. /* 1、使能 i2c 时钟 */
  12. i2c->dev = &pdev->dev;
  13. i2c->clk = clk_get(&pdev->dev, "i2c");
  14. clk_enable(i2c->clk);
  15. /* 2、io内存映射 */
  16. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  17. i2c->ioarea = request_mem_region(res->start, resource_size(res),
  18. pdev->name);
  19. i2c->regs = ioremap(res->start, resource_size(res));
  20. /* 3、设置adap的相关信息 */
  21. strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
  22. i2c->adap.owner = THIS_MODULE;
  23. i2c->adap.algo = &s3c24xx_i2c_algorithm; // i2c控制器的收发函数
  24. i2c->adap.retries = 2;
  25. i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
  26. i2c->tx_setup = 50;
  27. i2c->adap.algo_data = i2c;
  28. i2c->adap.dev.parent = &pdev->dev;
  29. /* 4、初始化 i2c controller */
  30. ret = s3c24xx_i2c_init(i2c);
  31. i2c->irq = ret = platform_get_irq(pdev, 0);
  32. /* 5、注册中断 */
  33. ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,
  34. dev_name(&pdev->dev), i2c);
  35. ret = s3c24xx_i2c_register_cpufreq(i2c);
  36. /* Note, previous versions of the driver used i2c_add_adapter()
  37. * to add the bus at any number. We now pass the bus number via
  38. * the platform data, so if unset it will now default to always
  39. * being bus 0.
  40. */
  41. /* 6、适配器编号 */
  42. i2c->adap.nr = pdata->bus_num; //阅读上面的英文,大概意思就是device侧pdata中没设置bus_num,那么就默认为0,显然这里是0
  43. /* 7、注册 adapter */
  44. ret = i2c_add_numbered_adapter(&i2c->adap); // i2c_register_adapter(&i2c->adap);
  45. platform_set_drvdata(pdev, i2c);
  46. return 0;
  47. }
  48. i2c-core.c (drivers\i2c)
  49. static int i2c_register_adapter(struct i2c_adapter *adap)
  50. {
  51. int res = 0, dummy;
  52. mutex_init(&adap->bus_lock);
  53. /* Set default timeout to 1 second if not already set */
  54. if (adap->timeout == 0)
  55. adap->timeout = HZ;
  56. /* 设置 adap->dev.kobj.name 为 i2c-0 ,它将出现在 sysfs 中 */
  57. dev_set_name(&adap->dev, "i2c-%d", adap->nr);
  58. /* 设置它所属的总线 i2c_bus_type */
  59. adap->dev.bus = &i2c_bus_type;
  60. /* 重点: 设置属性,用户空间创建 device 就靠它了 */
  61. adap->dev.type = &i2c_adapter_type;
  62. /* 将 adap->dev注册到 i2c_bus_type */
  63. res = device_register(&adap->dev);
  64. /* 大概是创建 devices 目录 到class 目录的符号连接 */
  65. #ifdef CONFIG_I2C_COMPAT
  66. res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
  67. adap->dev.parent);
  68. if (res)
  69. dev_warn(&adap->dev,
  70. "Failed to create compatibility class link\n");
  71. #endif
  72. /* 重点: 扫描 __i2c_board_list 链表里的设备信息,自动创建 client ,并注册到 i2c_bus_type */
  73. if (adap->nr < __i2c_first_dynamic_bus_num)
  74. i2c_scan_static_board_info(adap);
  75. /* 重点: 遍历 i2c_bus_type的driver 链表,取出每一个driver 调用 i2c_do_add_adapter */
  76. mutex_lock(&core_lock);
  77. dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
  78. i2c_do_add_adapter);
  79. mutex_unlock(&core_lock);
  80. return 0;
  81. }

        这一个 probe 函数的内容是在是太多了,慢慢来吧,至于 ioremap 申请中断啥的就不讲了,上个图


        在内核帮助文档 instantiating-devices 中说,有4种方法可以创建 i2c_device ,其中第四种是在用户空间创建的:
        Example:
                # echo eeprom 0x50 > /sys/bus/i2c/devices/i2c-0/new_device
                分析过设备模型的都知道,i2c-0 是我们上面设置的 dev_set_name(&adap->dev, "i2c-%d", adap->nr),new_device 就是它的一个属性了,这个属性在哪里?在i2c_adapter_type 中

  1. static struct device_type i2c_adapter_type = {
  2. .groups = i2c_adapter_attr_groups,
  3. .release = i2c_adapter_dev_release,
  4. };
  5. static const struct attribute_group *i2c_adapter_attr_groups[] = {
  6. &i2c_adapter_attr_group,
  7. NULL
  8. };
  9. static struct attribute_group i2c_adapter_attr_group = {
  10. .attrs = i2c_adapter_attrs,
  11. };
  12. static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device);
  13. static DEVICE_ATTR(delete_device, S_IWUSR, NULL, i2c_sysfs_delete_device);
  14. static struct attribute *i2c_adapter_attrs[] = {
  15. &dev_attr_name.attr,
  16. &dev_attr_new_device.attr,
  17. &dev_attr_delete_device.attr,
  18. NULL
  19. };
        这里,我就不将宏展开了,大概说一下,当 device_register 注册 device 时,会设置dev.kobj.ktype = device_ktype, device_ktype 提供通用的属性show 与 store函数,当用户空间访问属性文件时,通用的 show 与 store 就会 调用具体的show 与 store。
        DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device),就会创建一个device_attribute结构体,
                name = “new_device”,.mode = S_IWUSR , show = NULL ,store = i2c_sysfs_new_device 
        显然上面 echo eeprom 0x50 > /sys/bus/i2c/devices/i2c-0/new_device ,就会调用 i2c_sysfs_new_device 函数了。

  1. static ssize_t
  2. i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr,
  3. const char *buf, size_t count)
  4. {
  5. struct i2c_adapter *adap = to_i2c_adapter(dev);
  6. struct i2c_board_info info;
  7. struct i2c_client *client;
  8. char *blank, end;
  9. int res;
  10. memset(&info, 0, sizeof(struct i2c_board_info));
  11. blank = strchr(buf, ' ');
  12. memcpy(info.type, buf, blank - buf);
  13. /* Parse remaining parameters, reject extra parameters */
  14. res = sscanf(++blank, "%hi%c", &info.addr, &end);
  15. client = i2c_new_device(adap, &info);
  16. return count;
  17. }
  18. struct i2c_client * i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
  19. {
  20. struct i2c_client *client;
  21. int status;
  22. client = kzalloc( sizeof *client, GFP_KERNEL);
  23. client->adapter = adap;
  24. client->dev.platform_data = info->platform_data;
  25. if (info->archdata)
  26. client->dev.archdata = *info->archdata;
  27. client->flags = info->flags;
  28. client->addr = info->addr; // 设备地址
  29. client->irq = info->irq;
  30. strlcpy(client->name, info->type, sizeof(client->name)); // 名字很重要
  31. /* Check for address business */
  32. status = i2c_check_addr(adap, client->addr);
  33. client->dev.parent = &client->adapter->dev;
  34. client->dev.bus = &i2c_bus_type;
  35. client->dev.type = &i2c_client_type;
  36. dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
  37. client->addr);
  38. status = device_register(&client->dev);
  39. return client;
  40. }
        i2c_sysfs_new_device 函数,将用户空间传递进来的命令进行解析 生成info结构体(addr ,type),然后调用 i2c_new_device, 在 i2c_new_device 中构造client ,设置它的属性并将它注册到 i2c_bus_type,其中两个必须提的属性 client->name = info->type ,为什么说名字重要,如果看i2c_bus_type的match函数就可以知道,driver是根据client的名字是否在其idtable中判断是否支持这个client的。另外一个就是addr了,不用多说,每一个i2c设备必须都有个地址。空说无凭,看代码。

  1. static int i2c_device_match(struct device *dev, struct device_driver *drv)
  2. {
  3. struct i2c_client *client = i2c_verify_client(dev);
  4. struct i2c_driver *driver;
  5. if (!client)
  6. return 0;
  7. driver = to_i2c_driver(drv);
  8. /* match on an id table if there is one */
  9. if (driver->id_table)
  10. return i2c_match_id(driver->id_table, client) != NULL;
  11. return 0;
  12. }
  13. static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
  14. const struct i2c_client *client)
  15. {
  16. while (id->name[ 0]) {
  17. if ( strcmp(client->name, id->name) == 0)
  18. return id;
  19. id++;
  20. }
  21. return NULL;
  22. }

    分析一下 i2c_scan_static_board_info 第二种创建 device 的方式 

  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. /* 遍历__i2c_board_list链表 取出每一个 devinfo */
  6. list_for_each_entry(devinfo, &__i2c_board_list, list) {
  7. /* adapter->nr == 0 devinfo->busnum 还不知道,如果相等
  8. 取出 devinfo->board_info 调用 i2c_new_device ,前面分析过了哦 */
  9. if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter, &devinfo->board_info))
  10. dev_err(&adapter->dev,
  11. "Can't create device at 0x%02x\n",
  12. devinfo->board_info.addr);
  13. }
  14. up_read(&__i2c_board_lock);
  15. }

    来看一下 __i2c_board_list 这个链表是哪里填充的。
  1. mach-mini2440.c (arch\arm\mach-s3c2440)
  2. static struct i2c_board_info i2c_devs[] __initdata = {
  3. { I2C_BOARD_INFO( "eeprom", 0x50), },
  4. };
  5. #define I2C_BOARD_INFO(dev_type, dev_addr) \
  6. .type = dev_type, .addr = (dev_addr)
  7. static void __init mini2440_machine_init(void)
  8. {
  9. i2c_register_board_info( 0, i2c_devs, ARRAY_SIZE(i2c_devs));
  10. ....
  11. }
  12. int __init i2c_register_board_info(int busnum,
  13. struct i2c_board_info const *info, unsigned len)
  14. {
  15. int status;
  16. down_write(&__i2c_board_lock);
  17. if (busnum >= __i2c_first_dynamic_bus_num)
  18. __i2c_first_dynamic_bus_num = busnum + 1;
  19. for (status = 0; len; len--, info++) {
  20. struct i2c_devinfo *devinfo;
  21. devinfo = kzalloc( sizeof(*devinfo), GFP_KERNEL);
  22. devinfo->busnum = busnum; // busnum == 0
  23. devinfo->board_info = *info;
  24. list_add_tail(&devinfo-> list, &__i2c_board_list); // 添加到 __i2c_board_list 链表中
  25. }
  26. up_write(&__i2c_board_lock);
  27. return status;
  28. }

        这种方法与第一种用户空间创建device的方法相类似,都是提供一个addr 和 名字,只不过这种方法还有一个限制,前面看代码的时候我们知道,在注册adapter的时候,它会去访问__i2c_board_list链表,那么如果想成功创建,你必须在注册adater之前i2c_register_board_info

        第二种创建 device 的方式 

  1. bus_for_each_drv(&i2c_bus_type, NULL, adap, i2c_do_add_adapter) 分析
  2. 取出 i2c_bus_type 每一个driver 调用 i2c_do_add_adapter
  3. static int i2c_do_add_adapter(struct device_driver *d, void *data)
  4. {
  5. struct i2c_driver *driver = to_i2c_driver(d);
  6. struct i2c_adapter *adap = data;
  7. /* Detect supported devices on that bus, and instantiate them */
  8. i2c_detect(adap, driver);
  9. /* Let legacy drivers scan this bus for matching devices */
  10. if (driver->attach_adapter) {
  11. /* We ignore the return code; if it fails, too bad */
  12. driver->attach_adapter(adap);
  13. }
  14. return 0;
  15. }
  16. static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
  17. {
  18. const struct i2c_client_address_data *address_data;
  19. struct i2c_client *temp_client;
  20. int i, err = 0;
  21. int adap_id = i2c_adapter_id(adapter);
  22. // driver中 设置了 address_data 是创建device的前提,因为 address_data 中保存了设备的addr 与 名字,看设备驱动的时候会知道
  23. address_data = driver->address_data;
  24. if (!driver->detect || !address_data)
  25. return 0;
  26. /* Set up a temporary client to help detect callback */
  27. temp_client = kzalloc( sizeof(struct i2c_client), GFP_KERNEL);
  28. if (!temp_client)
  29. return -ENOMEM;
  30. temp_client->adapter = adapter;
  31. /* Force entries are done first, and are not affected by ignore
  32. entries */
  33. if (address_data->forces) {
  34. .....
  35. }
  36. /* Stop here if the classes do not match */
  37. if (!(adapter->class & driver->class))
  38. goto exit_free;
  39. /* Stop here if we can't use SMBUS_QUICK */
  40. if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) {
  41. ......
  42. }
  43. /* Probe entries are done second, and are not affected by ignore
  44. entries either */
  45. for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) {
  46. ......
  47. }
  48. /* Normal entries are done last, unless shadowed by an ignore entry */
  49. for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) {
  50. int j, ignore;
  51. ignore = 0;
  52. ......
  53. temp_client->addr = address_data->normal_i2c[i];
  54. err = i2c_detect_address(temp_client, -1, driver);
  55. }
  56. }
  57. static int i2c_detect_address(struct i2c_client *temp_client, int kind,
  58. struct i2c_driver *driver)
  59. {
  60. struct i2c_board_info info;
  61. struct i2c_adapter *adapter = temp_client->adapter;
  62. int addr = temp_client->addr;
  63. int err;
  64. /* 发送 start 信号 以及 i2c设备地址,看是否能收到 ack 信号,判断设备是否存在,不存在返回 */
  65. if (kind < 0) {
  66. if (i2c_smbus_xfer(adapter, addr, 0, 0, 0,
  67. I2C_SMBUS_QUICK, NULL) < 0) // 最终就会调用到adapter驱动中我们设置的 i2c_algorithm
  68. return 0;
  69. }
  70. /* Finally call the custom detection function */
  71. memset(&info, 0, sizeof(struct i2c_board_info));
  72. info.addr = addr;
  73. // 要在 driver->detect 设置 info->type
  74. err = driver->detect(temp_client, kind, &info);
  75. /* 如果设置了 info.type,创建 client 调用 i2c_new_device */
  76. if (info.type[ 0] == '\0') {
  77. ......
  78. } else {
  79. struct i2c_client *client;
  80. /* Detection succeeded, instantiate the device */
  81. client = i2c_new_device(adapter, &info);
  82. if (client)
  83. list_add_tail(&client->detected, &driver->clients);
  84. }
  85. return 0;
  86. }
        我们在 向i2c_bus_type 注册driver时,与上面的方法是一样的,因此,我们可以动态加载driver时,创建对应的device,但是并不推荐这样做。
        i2c_add_driver-》i2c_register_driver-》bus_for_each_dev(&i2c_bus_type, NULL, driver, __attach_adapter);
        __attach_adapter 和 i2c_do_add_adapter 内容是同理的。

3、i2c 设备驱动框架
  3.1 i2c_bus_type
            前面已经分析过了它的 match 函数,稍后我们会注意一下它的probe函数。
  3.2 i2c_driver
            注册driver的过程,创建 device 前面也分析过了
  3.3 i2c_device
            device 就更不用提了,前面讲了3中创建它的方法,还有第四种 直接 i2c_new_device ,岂不是更来得痛快。
            关于以上3点,就不再分析了,后面直接看 代码更直接,这里再记录一下 我分析这里时遇到的一个小问题。

  1. static struct i2c_driver eeprom_driver = {
  2. .driver = {
  3. .name = "eeprom",
  4. },
  5. .probe = eeprom_probe,
  6. .remove = eeprom_remove,
  7. .id_table = eeprom_id,
  8. .class = I2C_CLASS_DDC | I2C_CLASS_SPD,
  9. .detect = eeprom_detect,
  10. .address_data = &addr_data, // 由I2C_CLIENT_INSMOD_1(eeprom)宏定义
  11. };

        我们在写i2c_driver时,在 .driver 中没有指定 probe函数,那么配对成功后是如何调用到 eeprom_probe 的,对于platform平台,它是在注册platform_driver时,给.driver设置了通用的probe接口,platform_probe,使用它跳转到 上层的 probe 也就类似于这里的 eeprom_probe。但是搜遍代码 i2c_bus_type 并没有这样做呀,奇怪奇怪。回想在分析设备总线驱动模型,设备与驱动的配对过程,在调用probe函数时,首先会看bus->probe有没有,有就调用,没有才会调用driver->probe,platform_bus_type 是没有Probe函数的,但是i2c_bus_type有!!!所以,来看看 i2c_bus_type->probe吧。

  1. static int i2c_device_probe(struct device *dev)
  2. {
  3. struct i2c_client *client = i2c_verify_client(dev);
  4. struct i2c_driver *driver;
  5. int status;
  6. if (!client)
  7. return 0;
  8. driver = to_i2c_driver(dev->driver);
  9. if (!driver->probe || !driver->id_table)
  10. return -ENODEV;
  11. client->driver = driver;
  12. if (!device_can_wakeup(&client->dev))
  13. device_init_wakeup(&client->dev,
  14. client->flags & I2C_CLIENT_WAKE);
  15. dev_dbg(dev, "probe\n");
  16. status = driver->probe(client, i2c_match_id(driver->id_table, client));
  17. if (status)
  18. client->driver = NULL;
  19. return status;
  20. }
        不难分析,原来是通过 Bus->probe 函数进行了跳转,以后分析别的总线模型又涨知识了。

4、写设备驱动程序

        我们使用最简单粗暴的方法,直接在设备侧使用 i2c_new_device 创建一个设备注册到 i2c_bus_type里,再写个驱动与它配对。

  1. #include <linux/kernel.h>
  2. #include <linux/module.h>
  3. #include <linux/platform_device.h>
  4. #include <linux/i2c.h>
  5. #include <linux/err.h>
  6. #include <linux/regmap.h>
  7. #include <linux/slab.h>
  8. static struct i2c_board_info at24cxx_info = {
  9. I2C_BOARD_INFO( "at24c08", 0x50),
  10. };
  11. static struct i2c_client *at24cxx_client;
  12. static int at24cxx_dev_init(void)
  13. {
  14. struct i2c_adapter *i2c_adap;
  15. // 获取设备号为 0 的adpter ,也就是adapter->nr == 0
  16. i2c_adap = i2c_get_adapter( 0);
  17. // 直接使用 i2c_new_device 创建 client 自动注册到i2c_bus_type 中去,client->name == "at24c08" ,client->addr = 0x50
  18. at24cxx_client = i2c_new_device(i2c_adap, &at24cxx_info);
  19. // 释放掉 adapter
  20. i2c_put_adapter(i2c_adap);
  21. return 0;
  22. }
  23. static void at24cxx_dev_exit(void)
  24. {
  25. i2c_unregister_device(at24cxx_client);
  26. }
  27. module_init(at24cxx_dev_init);
  28. module_exit(at24cxx_dev_exit);
  29. MODULE_LICENSE( "GPL");
    设备侧的程序相对简单,我们只需要构造一个board_info结构体,设置名字Info->type 以及 地址 info->addr,然后使用 i2c_new_device 将其注册到I2c_bus_type 即可。

  1. #include <linux/kernel.h>
  2. #include <linux/module.h>
  3. #include <linux/platform_device.h>
  4. #include <linux/i2c.h>
  5. #include <linux/err.h>
  6. #include <linux/regmap.h>
  7. #include <linux/slab.h>
  8. #include <linux/fs.h>
  9. #include <asm/uaccess.h>
  10. static int major;
  11. static struct class *class;
  12. static struct i2c_client *at24cxx_client;
  13. /* 传入: buf[0] : addr
  14. * 输出: buf[0] : data
  15. */
  16. static ssize_t at24cxx_read(struct file * file, char __user *buf, size_t count, loff_t *off)
  17. {
  18. unsigned char addr, data;
  19. copy_from_user(&addr, buf, 1);
  20. data = i2c_smbus_read_byte_data(at24cxx_client, addr);
  21. copy_to_user(buf, &data, 1);
  22. return 1;
  23. }
  24. /* buf[0] : addr
  25. * buf[1] : data
  26. */
  27. static ssize_t at24cxx_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
  28. {
  29. unsigned char ker_buf[ 2];
  30. unsigned char addr, data;
  31. copy_from_user(ker_buf, buf, 2);
  32. addr = ker_buf[ 0];
  33. data = ker_buf[ 1];
  34. printk( "addr = 0x%02x, data = 0x%02x\n", addr, data);
  35. if (!i2c_smbus_write_byte_data(at24cxx_client, addr, data))
  36. return 2;
  37. else
  38. return -EIO;
  39. }
  40. static struct file_operations at24cxx_fops = {
  41. .owner = THIS_MODULE,
  42. .read = at24cxx_read,
  43. .write = at24cxx_write,
  44. };
  45. static int __devinit at24cxx_probe(struct i2c_client *client,
  46. const struct i2c_device_id *id)
  47. {
  48. at24cxx_client = client;
  49. //printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
  50. major = register_chrdev( 0, "at24cxx", &at24cxx_fops);
  51. class = class_create(THIS_MODULE, "at24cxx");
  52. device_create(class, NULL, MKDEV(major, 0), NULL, "at24cxx"); /* /dev/at24cxx */
  53. return 0;
  54. }
  55. static int __devexit at24cxx_remove(struct i2c_client *client)
  56. {
  57. //printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
  58. device_destroy(class, MKDEV(major, 0));
  59. class_destroy(class);
  60. unregister_chrdev(major, "at24cxx");
  61. return 0;
  62. }
  63. static const struct i2c_device_id at24cxx_id_table[] = {
  64. { "at24c08", 0 },
  65. {}
  66. };
  67. /* 1. 分配/设置i2c_driver */
  68. static struct i2c_driver at24cxx_driver = {
  69. .driver = {
  70. .name = "100ask",
  71. .owner = THIS_MODULE,
  72. },
  73. .probe = at24cxx_probe,
  74. .remove = __devexit_p(at24cxx_remove),
  75. .id_table = at24cxx_id_table,
  76. };
  77. static int at24cxx_drv_init(void)
  78. {
  79. /* 2. 注册i2c_driver */
  80. i2c_add_driver(&at24cxx_driver);
  81. return 0;
  82. }
  83. static void at24cxx_drv_exit(void)
  84. {
  85. i2c_del_driver(&at24cxx_driver);
  86. }
  87. module_init(at24cxx_drv_init);
  88. module_exit(at24cxx_drv_exit);
  89. MODULE_LICENSE( "GPL");
    驱动侧的程序,思路:

        1、分配一个 i2c_driver 结构体

        2、设置它的名字,仅仅是出现在 sysfs 的目录名

        3、设置 id_table ,根据 id_table 与 client 的名字进行匹配

        4、设置 probe 函数,配对成功后调用它,我们往往在这里面创建类,在类下面创建设备,让Mdev自动帮我们创建设备节点。

        5、设备 remove 函数  ,与 i2c_add_driver 相反,我们在remove函数里 将driver删除掉,使用 i2c_del_driver 。

    还有需要注意的是,我们在Probe函数里,注册了一个字符设备驱动,在它的 read 和 write 函数里,用到了两个简单的函数,i2c_smbus_read_byte_data 与 i2c_smbus_write_byte_data,这两个函数是什么东西,我们之前用过 i2c_transfer 使用 mesg 结构体进行传输过,i2c_transfer 最终会调用到 adapter 里我们设置的传输函数。这里就不再分析代码了,根据我个人的理解,我们现在使用的 i2c_smbus_read_byte_data 等函数,是对 i2c_transfer 与 meag 进行了更深层次的封装,我们以前向读数据时,需要用两个mesg 结构体,因为要先发送地址,再读取数据,i2c_smbus_read_byte_data 函数我们只需要提供一个要读取的地址,它就会帮我们去构造那两个Mesg 结构体,总而言之,我们写程序更方便了。那么,i2c_smbus_read_byte_data 等函数对应的时序是怎样的,是否符合我们的要求,如何选取?看帮助文档 smbus-protocol 

---------------------------------------------------------------------------------------------------------------------------------

SMBus Protocol Summary

======================

The following is a summary of the SMBus protocol. It applies to
all revisions of the protocol (1.0, 1.1, and 2.0).
Certain protocol features which are not supported by
this package are briefly described at the end of this document.

Some adapters understand only the SMBus (System Management Bus) protocol,
which is a subset from the I2C protocol. Fortunately, many devices use
only the same subset, which makes it possible to put them on an SMBus.

If you write a driver for some I2C device, please try to use the SMBus
commands if at all possible (if the device uses only that subset of the
I2C protocol). This makes it possible to use the device driver on both
SMBus adapters and I2C adapters (the SMBus command set is automatically
translated to I2C on I2C adapters, but plain I2C commands can not be
handled at all on most pure SMBus adapters).

Below is a list of SMBus protocol operations, and the functions executing
them.  Note that the names used in the SMBus protocol specifications usually
don't match these function names.  For some of the operations which pass a
single data byte, the functions using SMBus protocol operation names execute
a different protocol operation entirely.

Key to symbols
==============

S     (1 bit) : Start bit
P     (1 bit) : Stop bit
Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.
A, NA (1 bit) : Accept and reverse accept bit. 
Addr  (7 bits): I2C 7 bit address. Note that this can be expanded as usual to 
                get a 10 bit I2C address.
Comm  (8 bits): Command byte, a data byte which often selects a register on
                the device.
Data  (8 bits): A plain data byte. Sometimes, I write DataLow, DataHigh
                for 16 bit data.
Count (8 bits): A data byte containing the length of a block operation.

[..]: Data sent by I2C device, as opposed to data sent by the host adapter.

SMBus Quick Command
===================

This sends a single bit to the device, at the place of the Rd/Wr bit.

A Addr Rd/Wr [A] P

SMBus Receive Byte:  i2c_smbus_read_byte()
==========================================

This reads a single byte from a device, without specifying a device
register. Some devices are so simple that this interface is enough; for
others, it is a shorthand if you want to read the same register as in
the previous SMBus command.

S Addr Rd [A] [Data] NA P

SMBus Send Byte:  i2c_smbus_write_byte()
========================================

This operation is the reverse of Receive Byte: it sends a single byte
to a device.  See Receive Byte for more information.

S Addr Wr [A] Data [A] P

SMBus Read Byte:  i2c_smbus_read_byte_data()
============================================

This reads a single byte from a device, from a designated register.
The register is specified through the Comm byte.


S Addr Wr [A] Comm [A] S Addr Rd [A] [Data] NA P

SMBus Read Word:  i2c_smbus_read_word_data()
============================================

This operation is very like Read Byte; again, data is read from a
device, from a designated register that is specified through the Comm
byte. But this time, the data is a complete word (16 bits).

S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P

SMBus Write Byte:  i2c_smbus_write_byte_data()
==============================================

This writes a single byte to a device, to a designated register. The
register is specified through the Comm byte. This is the opposite of
the Read Byte operation.

S Addr Wr [A] Comm [A] Data [A] P

SMBus Write Word:  i2c_smbus_write_word_data()
==============================================

This is the opposite of the Read Word operation. 16 bits
of data is written to a device, to the designated register that is
specified through the Comm byte. 

S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P

SMBus Process Call:  i2c_smbus_process_call()
=============================================

This command selects a device register (through the Comm byte), sends
16 bits of data to it, and reads 16 bits of data in return.

S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] 
                             S Addr Rd [A] [DataLow] A [DataHigh] NA P


SMBus Block Read:  i2c_smbus_read_block_data()
==============================================

This command reads a block of up to 32 bytes from a device, from a 
designated register that is specified through the Comm byte. The amount
of data is specified by the device in the Count byte.

S Addr Wr [A] Comm [A] 
           S Addr Rd [A] [Count] A [Data] A [Data] A ... A [Data] NA P


SMBus Block Write:  i2c_smbus_write_block_data()
================================================

The opposite of the Block Read command, this writes up to 32 bytes to 
a device, to a designated register that is specified through the
Comm byte. The amount of data is specified in the Count byte.

S Addr Wr [A] Comm [A] Count [A] Data [A] Data [A] ... [A] Data [A] P

SMBus Block Write - Block Read Process Call
===========================================

SMBus Block Write - Block Read Process Call was introduced in
Revision 2.0 of the specification.

This command selects a device register (through the Comm byte), sends
1 to 31 bytes of data to it, and reads 1 to 31 bytes of data in return.

S Addr Wr [A] Comm [A] Count [A] Data [A] ...
                             S Addr Rd [A] [Count] A [Data] ... A P


SMBus Host Notify
=================

This command is sent from a SMBus device acting as a master to the
SMBus host acting as a slave.
It is the same form as Write Word, with the command code replaced by the
alerting device's address.

[S] [HostAddr] [Wr] A [DevAddr] A [DataLow] A [DataHigh] A [P]

Packet Error Checking (PEC)
===========================

Packet Error Checking was introduced in Revision 1.1 of the specification.

PEC adds a CRC-8 error-checking byte to transfers using it, immediately
before the terminating STOP.

Address Resolution Protocol (ARP)
=================================

The Address Resolution Protocol was introduced in Revision 2.0 of
the specification. It is a higher-layer protocol which uses the
messages above.

ARP adds device enumeration and dynamic address assignment to
the protocol. All ARP communications use slave address 0x61 and
require PEC checksums.

I2C Block Transactions
======================

The following I2C block transactions are supported by the
SMBus layer and are described here for completeness.
They are *NOT* defined by the SMBus specification.

I2C block transactions do not limit the number of bytes transferred
but the SMBus layer places a limit of 32 bytes.

I2C Block Read:  i2c_smbus_read_i2c_block_data()
================================================

This command reads a block of bytes from a device, from a 
designated register that is specified through the Comm byte.


S Addr Wr [A] Comm [A] 
           S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P





I2C Block Read (2 Comm bytes)
=============================


This command reads a block of bytes from a device, from a 
designated register that is specified through the two Comm bytes.


S Addr Wr [A] Comm1 [A] Comm2 [A] 
           S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P





I2C Block Write:  i2c_smbus_write_i2c_block_data()
==================================================


The opposite of the Block Read command, this writes bytes to 
a device, to a designated register that is specified through the
Comm byte. Note that command lengths of 0, 2, or more bytes are
supported as they are indistinguishable from data.


S Addr Wr [A] Comm [A] Data [A] Data [A] ... [A] Data [A] P


5、写adapter驱动程序

        i2c协议的简单介绍,以及手写 adapter驱动程序 放到下一篇文章里吧~

i2c设备驱动的四种构造方法-爱代码爱编程

i2c设备驱动属于字符设备驱动,其构造自然是跟字符设备的结构一样了,字符设备:1、 分配字符设备号(主次设备号),设置为0,表示自动分配设备号  2、构造file_operatios 3、注册设备,register_chrdev(1,2,3),三个参数分别是设备号,名称(不重要,随便起),构造的file_operations。 i2c总线驱动:核心

基于linux的i2c入门教程·(待周末)_丶apache的博客-爱代码爱编程_i2c_get_adapter

        对于i2c的理解与讲解,大家可以百度一下。网上的东西杂乱,而且可能是错的,不过那些错误不会阻碍我们掌握i2c的运用与理解。当然,理解归理解,我在这里将i2c的使用方法给自己做了一个“标准”,仅供大家参考。(i2c子系统驱动编写有多种方法)        大家可以先理解一下i2c子系统的架构:https://blog.csdn.net/h

linux i2c 设备驱动程序框架详解_酸菜鱼的鱼的博客-爱代码爱编程_linux i2c设备驱动

I2C子系统由上到下分为3层:,这一层需要客户实现。I2C设备驱动层、I2C核心层和I2C适配器驱动层。 I2C设备驱动层:真正实现具体设备的时序的代码。使用核心层提供API接口写,有特定编写框架。 I2C核心层:由内核提供,代码不用修改,提供了设备驱动层和适配器驱动层需要API接口,以及实现收发数据管理功能。起到一个连接上下两的作用。 I2C适

devm_regmap_init_i2c-爱代码爱编程

内核在3.1版本加入了regmap模块,主要是给I2C,SPI总线的读写提供一个统一的接口,后来陆续添加了以下接口的支持: 1. 支持SPMI,MMIO 2.Spinlock和客制化lock机制 3.Cache支持 4.字节序转换 5.寄存器范围检查 6.IRQ支持 7.只读和只写寄存器 8.Precious寄存器和volatile寄存器 9.寄存器页

Linux驱动之I2C创建实例-爱代码爱编程

在上一节中,简单的介绍了Linux-3.4内核中的i2c驱动框架,那么,接下来,就来实际的创建i2c的驱动实例,加深对Linux内核中的i2c驱动的理解 1、方法一 第一中方法其实就是上节内容中所说的方法,现在来简单回顾一下,上节的内容最后的出来的结论是 在系统开始运行之后,和架构相关的mach-xxxx.c文件先运行起来,这个文件中定义有i2c_b

Linux驱动框架之i2c驱动框架解析-爱代码爱编程

一、引言        本文会通过简要的文字描述和源码分析,为大家分析梳理出Linux下的I2C驱动框架。       (文本所有代码都是经过删减的,所以不要纠结和源代码有出入的地方)。 二、I2C总线        I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。        它只需要两根线(时钟线和数据线)即可在连接于总

Linux regmap机制浅析-爱代码爱编程

kernel version:4.9.186 software platform:Qualcomm android 10 文章目录 一、regmap初始化二、regmap读写接口三、regmap释放四、wm8988驱动中regmap的使用五、ragmap中的cache使用cache同步 regmap机制引入屏蔽了I2C、SPI读写的细节,提高

linux应用层读设备树,linux设备驱动程序-i2c(2)-adapter和设备树的解析-爱代码爱编程

linux设备驱动程序-i2c(2)-adapter和设备树的解析 (注: 基于beagle bone green开发板,linux4.14内核版本) 在本系列linux内核i2c框架的前两篇,分别讲了: linux设备驱动程序-i2c(0)-i2c设备驱动源码实现 linux设备驱动程序-i2c(1):i2c总线的添加与实现 而在linux

linux i2c触摸屏驱动程序,触摸屏i2c设备和驱动的创建流程及方法-爱代码爱编程

添加i2c设备的流程: 1. 初始化 i2c_board_info 结构信息 和 i2c_driver 结构 //设备驱动结构体 static struct i2c_driver goodix_ts_driver = { .probe      = goodix_ts_probe, .remove     = goodix_ts_remove

【linux iic子系统】i2c设备与驱动匹配过程(三)-爱代码爱编程

本文讲解基于linux4.18内核。 重要 根据前面内容我们可以知道i2c子系统有几个重要的东西: I2C总线:i2c总线主要就是维护着两个链表——驱动、设备。i2c驱动注册时候,通过i2c_driver结构体内部driver成员挂载到总线上。i2c设备注册时候,通过i2c_client结构体内部device成员挂

具体芯片的I2C_Adapter驱动分析-爱代码爱编程

参考资料 Linux内核真正的I2C驱动控制器驱动程序。drivers\i2c\busses\i2c-imx.c芯片手册:IMX6ULL:Chapter 31: I2C Controller (I2C)一、I2C控制器内部结构 I2C单独控制的话,占用CPU的时间非常高,这样不利于系统高效运转,所以一般的芯片里面都会有I2C控制器。 1.1 通用的简

Linux驱动之i2c驱动-爱代码爱编程

一、I2C简介 ​ I2C是很常用的总线协议。它使用两条线在主控制器与从机直接进行数据通信。一条是时钟线,一条是数据线,两条数据线都要接4.7K的上拉电阻,空闲的时候处于高电平。I2C总线的标准模式下传输速度可以达到100k/s,快速模式达到400k/s。 ​ 常见的I2C驱动从设备有电容触摸屏,CMOS camera ,重力传感器,EEPROM,HD

Linux驱动开发的IIC设备驱动的投机取巧-爱代码爱编程

前言 Linux的IIC驱动想必大家都耳熟能详,网上也有很多相关的教程。网上的教程总结,比如:方法问题描述Linux 3.X.X版本之后,设备树+驱动此方法是比较符合linux驱动的写法的。当对于不熟悉设备树的小伙伴,写起来比较棘手使用 i2c-tools,并通过脚本或者应用程序编写设备驱动(简单粗暴)此方法是将设备驱动丢到用户态中,对于一些的设备

Linux I2C驱动-爱代码爱编程

介绍:I2C是常见的一个串行通信接口,用于连接各种外设、传感器等。I2C 总线仅仅使用 SCL、SDA 这两根信号线就实现了设备之间的数据交互。 I2C的体系架构:由I2C核心,I2C总线驱动,I2C设备驱动三部分构成。 I2C核心:提供I2C总线驱动和设备驱动的注册,注销。 I2C总线驱动:I2C总线驱动是对硬件中适配器的实现,适配器可让CPU控制