开发板    :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来描述。

[cpp] view
plain
 copy

  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
控制器收发数据的方法。

[cpp] view
plain
 copy

  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

[cpp] view
plain
 copy

  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

[cpp] view
plain
 copy

  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 注册到 平台设备总线上去

[cpp] view
plain
 copy

  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,配置寄存器,注册中断等等

[cpp] view
plain
 copy

  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 函数分析

[cpp] view
plain
 copy

  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 中

[cpp] view
plain
 copy

  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 函数了。

[cpp] view
plain
 copy

  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设备必须都有个地址。空说无凭,看代码。

[cpp] view
plain
 copy

  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 的方式

[cpp] view
plain
 copy

  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 这个链表是哪里填充的。

[cpp] view
plain
 copy

  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 的方式

[cpp] view
plain
 copy

  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点,就不再分析了,后面直接看 代码更直接,这里再记录一下 我分析这里时遇到的一个小问题。

[cpp] view
plain
 copy

  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吧。

[cpp] view
plain
 copy

  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里,再写个驱动与它配对。

[cpp] view
plain
 copy

  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 即可。

[cpp] view
plain
 copy

  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驱动程序 放到下一篇文章里吧~







转自:http://blog.csdn.net/lizuobin2/article/details/51694574

i2c驱动程序全面分析,从adapter驱动程序到设备驱动程序的更多相关文章

  1. Linux内核入门到放弃-设备驱动程序-《深入Linux内核架构》笔记

    I/O体系结构 总线系统 PCI(Peripheral Component Interconnect) ISA(Industrial Standard Architecture) SBus IEEE1 ...

  2. 浅析Linux字符设备驱动程序内核机制

    前段时间在学习linux设备驱动的时候,看了陈学松著的<深入Linux设备驱动程序内核机制>一书. 说实话.这是一本非常好的书,作者不但给出了在设备驱动程序开发过程中的所须要的知识点(如对 ...

  3. linux设备驱动第一篇:设备驱动程序简介

    首先,我们知道驱动是内核的一部分,那么驱动在内核中到底扮演了什么角色呢? 设备驱动程序在内核中的角色:他们是一个个独立的“黑盒子”,使某个特定的硬件响应一个定义良好的内部编程接口,这些接口完全隐藏了设 ...

  4. 简单linux块设备驱动程序

    本文代码参考<LINUX设备驱动程序>第十六章 块设备驱动程序 本文中的“块设备”是一段大小为PAGE_SIZE的内存空间(两个扇区,每个扇区512字节) 功能:向块设备中输入内容,从块设 ...

  5. Linux设备驱动程序学习----1.设备驱动程序简介

    设备驱动程序简介 更多内容请参考Linux设备驱动程序学习----目录 1. 简介   Linux系统的优点是,系统内部实现细节对所有人都是公开的.Linux内核由大量复杂的代码组成,设备驱动程序可以 ...

  6. Linux设备驱动程序学习----目录

    目录 设备驱动程序简介 1.设备驱动程序简介 构造和运行模块 2.内核模块和应用程序的对比 3.模块编译和装载 4.模块的内核符号表  5.模块初始化和关闭  6.模块参数  7.用户空间编写驱动程序 ...

  7. linux设备驱动程序-i2c(2)-adapter和设备树的解析

    linux设备驱动程序-i2c(2)-adapter和设备树的解析 (注: 基于beagle bone green开发板,linux4.14内核版本) 在本系列linux内核i2c框架的前两篇,分别讲 ...

  8. 驱动13.i2c设备驱动程序

    1 分析i2c设备的识别过程i2c_add_driver    i2c_register_driver        driver->driver.bus = &i2c_bus_type ...

  9. linux设备驱动程序--串行通信驱动框架分析

    linux 串行通信接口驱动框架 在学习linux内核驱动时,不论是看linux相关的书籍,又或者是直接看linux的源码,总是能在linux中看到各种各样的框架,linux内核极其庞杂,linux各 ...

随机推荐

  1. java语言基础-进制

    一丶Java语言基础:进制 1.进制的四种表现形式 (1).二进制:0,1 满2进1. (2).八进制0-7 :满8进1,用0开头表示. (3).十进制:0-9 满10进1. (4).十六进制:0-9 ...

  2. PHP sessions that have already been started

    In my PHP code, if a session has already started, and I try to start a new one, I get the following ...

  3. 【OpenCV入门教程之二】 一览众山小:OpenCV 2.4.8 or OpenCV 2.4.9组件结构全解析

    本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/19925819 作者:毛星云 ...

  4. Buildroot构建指南——工具链

    Linux系统的交叉编译工具链用来将源代码变成bin文件或者库文件的一个软件.一般大家默认工具链等于gcc或者arm-linux-gcc,但是实际上,gcc只是工具链的编译器部分,不是全部,制作一个工 ...

  5. 熟悉linux命令

    <鸟哥的linux私房菜>这本书终于看到了敲命令行这块了,有点小激动,打开虚拟机,开始~~~敲!!! 登录界面,用户名密码~~~ 登录成功,下面开始熟悉一下,linux的常见命令了: li ...

  6. Shell 命令行求两个文件每行对比的相同内容

    Shell 命令行求两个文件每行对比的相同内容 遇到的一个实际问题是,2017年08月01日起,所有未经实名的域名,全部停止解析.而我手上有不少域名,其中很多都是没有实名的.但我不知道哪些实名了,哪些 ...

  7. 人生苦短之我用Python篇(列表list、字典dict、元组tuple、字符串str)

    列表 创建列表 sample_list = ['a',1,('a','b')] Python 列表操作 sample_list = ['a','b',0,1,3] 得到列表中的某一个值 value_s ...

  8. [转载][QT][SQL]sql学习记录4_sqlite约束

    转载自:定义以及示例请见 : http://www.runoob.com/sqlite/sqlite-constraints.html SQLite 约束 约束是在表的数据列上强制执行的规则.这些是用 ...

  9. confd与etcd的使用

    Add keys This guide assumes you have a working etcd, or consul server up and running and the ability ...

  10. cocos2d-x 3.17 jsb android运行报错

    编译成功,运行失败,提示如下: 2018-11-15 19:09:56.343 2820-2852/net.jd85.test D/cocos2d-x debug info: cocos2d: ful ...