转载于:http://blog.csdn.net/liuhaoyutz
内核版本:3.10.1
编写一个I2C设备驱动程序的工作可分为两部分,一是定义和注册I2C设备,即i2c_client;二是定义和注册I2C设备驱动,即i2c_driver。下面我们就以mini2440的I2C设备at24c08 EEPROM为例,介绍如何完成这两个工作。
一、定义和注册I2C设备
步骤1:用i2c_board_info保存I2C设备相关信息
在Linux中,struct i2c_client代表一个I2C设备,该结构体定义在include/linux/i2c.h文件中:
- 200
- 218struct i2c_client {
- 219 unsigned short flags;
- 220 unsigned short addr;
- 221
- 222
- 223 char name[I2C_NAME_SIZE];
- 224 struct i2c_adapter *adapter;
- 225 struct i2c_driver *driver;
- 226 struct device dev;
- 227 int irq;
- 228 struct list_head detected;
- 229};
我们不用直接定义一个i2c_client结构,Linux会根据I2C设备的相关信息自动创建i2c_client。所以,我们需要提供I2C设备的相关信息。对于Mini2440的I2C设备at24c08 EEPROM,其相关信息保存在arch/arm/mach-s3c24xx/mach-mini2440.c文件中:
- 485
- 488static struct at24_platform_data at24c08= {
- 489 .byte_len = SZ_8K / 8,
- 490 .page_size = 16,
- 491};
- 492
- 493static struct i2c_board_infomini2440_i2c_devs[] __initdata = {
- 494 {
- 495 I2C_BOARD_INFO("24c08", 0x50),
- 496 .platform_data = &at24c08,
- 497 },
- 498};
struct i2c_board_info是创建i2c设备的模板,该结构体定义在include/linux/i2c.h文件中:
- 251
- 273struct i2c_board_info {
- 274 char type[I2C_NAME_SIZE];
- 275 unsigned short flags;
- 276 unsigned short addr;
- 277 void *platform_data;
- 278 struct dev_archdata *archdata;
- 279 struct device_node *of_node;
- 280 struct acpi_dev_node acpi_node;
- 281 int irq;
- 282};
从注释可以看到,i2c_board_info结构体用来保存I2C设备的相关信息,Linux根据这些信息创建I2C设备相关的设备模型树。对于mainboards,通过调用i2c_register_board_info()静态完成。对于add-on boards,通过调用i2c_new_device()动态完成。
i2c_board_info结构体有两个成员必须初始化,一个是type,用来初始化i2c_client.name;另一个是addr,用来初始化i2c_client.addr。其它i2c_board_info结构体成员根据需要赋值或保持为空。
宏I2C_BOARD_INFO定义在include/linux/i2c.h文件中,其内容如下:
- 284
- 294#define I2C_BOARD_INFO(dev_type,dev_addr) \
- 295 .type = dev_type, .addr = (dev_addr)
从注释可以看到,I2C_BOARD_INFO宏用来初始化i2c_board_info结构体的两个必须初始化的成员变量type和addr。i2c_board_info结构体的其它成员变量使用常规的初始化语法。
struct at24_platform_data定义在include/linux/i2c/at24.h文件中:
1
- 4
- 41
- 42struct at24_platform_data {
- 43 u32 byte_len;
- 44 u16 page_size;
- 45 u8 flags;
- 46#define AT24_FLAG_ADDR16 0x80
- 47#define AT24_FLAG_READONLY 0x40
- 48#define AT24_FLAG_IRUGO 0x20
- 49#define AT24_FLAG_TAKE8ADDR 0x10
- 50
- 51 void (*setup)(structmemory_accessor *, void *context);
- 52 void *context;
- 53};
该结构体用来保存at24系列EEPROM的platform data。byte_len成员变量保存EEPROM的大小,以byte为单位。page_size成员变量用来指定一次最多能写多少个byte。对于Mini2440,定义at24_platform_data结构体变量at24c08:
- 488static struct at24_platform_data at24c08= {
- 489 .byte_len = SZ_8K / 8,
- 490 .page_size = 16,
- 491};
SZ_8K宏即8K,定义在include/linux/sizes.h文件中:
- 25#define SZ_8K 0x00002000
步骤2:调用i2c_register_board_info注册i2c设备相关信息
对于Mini2440的I2C设备at24c08 EEPROM,由arch/arm/mach-s3c24xx/mach-mini2440.c文件中的mini2440_init函数调用i2c_register_board_info注册i2c设备相关信息,mini2440_init函数内容如下:
- 622static void __init mini2440_init(void)
- 623{
- 624 struct mini2440_features_t features = { 0 };
- 625 int i;
- 626
- 627 printk(KERN_INFO "MINI2440: Option string mini2440=%s\n",
- 628 mini2440_features_str);
- 629
- 630
- 631 mini2440_parse_features(&features, mini2440_features_str);
- 632
- 633
- 634 s3c_gpio_cfgpin(S3C2410_GPC(0), S3C2410_GPC0_LEND);
- 635
- 636
- 637 WARN_ON(gpio_request_one(S3C2410_GPG(4), GPIOF_OUT_INIT_HIGH, NULL));
- 638 gpio_free(S3C2410_GPG(4));
- 639
- 640
- 641 gpio_request_one(S3C2410_GPB(1), GPIOF_IN, NULL);
- 642 s3c_gpio_setpull(S3C2410_GPB(1), S3C_GPIO_PULL_UP);
- 643 gpio_free(S3C2410_GPB(1));
- 644
- 645
- 646 for (i = 0; i < ARRAY_SIZE(mini2440_buttons); i++) {
- 647 s3c_gpio_setpull(mini2440_buttons[i].gpio, S3C_GPIO_PULL_UP);
- 648 s3c_gpio_cfgpin(mini2440_buttons[i].gpio, S3C2410_GPIO_INPUT);
- 649 }
- 650 if (features.lcd_index != -1) {
- 651 int li;
- 652
- 653 mini2440_fb_info.displays =
- 654 &mini2440_lcd_cfg[features.lcd_index];
- 655
- 656 printk(KERN_INFO "MINI2440: LCD");
- 657 for (li = 0; li < ARRAY_SIZE(mini2440_lcd_cfg); li++)
- 658 if (li == features.lcd_index)
- 659 printk(" [%d:%dx%d]",li,
- 660 mini2440_lcd_cfg[li].width,
- 661 mini2440_lcd_cfg[li].height);
- 662 else
- 663 printk(" %d:%dx%d",li,
- 664 mini2440_lcd_cfg[li].width,
- 665 mini2440_lcd_cfg[li].height);
- 666 printk("\n");
- 667 s3c24xx_fb_set_platdata(&mini2440_fb_info);
- 668 }
- 669
- 670 s3c24xx_udc_set_platdata(&mini2440_udc_cfg);
- 671 s3c24xx_mci_set_platdata(&mini2440_mmc_cfg);
- 672 s3c_nand_set_platdata(&mini2440_nand_info);
- 673 s3c_i2c0_set_platdata(NULL);
- 674
- 675 i2c_register_board_info(0, mini2440_i2c_devs,
- 676 ARRAY_SIZE(mini2440_i2c_devs));
- 677
- 678 platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));
- 679
- 680 if (features.count)
- 681 platform_add_devices(features.optional, features.count);
- 682
- 683}
这个函数我们这里只需要关注675行,调用i2c_register_board_info注册mini2440_i2c_devs。mini2440_i2c_devs就是上面定义的i2c_board_info结构体数组,其中定义了at24c08相关信息。
i2c_register_board_info函数定义在drivers/i2c/i2c-boardinfo.c文件中,其内容如下:
- 42
- 64int __init
- 65i2c_register_board_info(int busnum,
- 66 struct i2c_board_info const *info, unsigned len)
- 67{
- 68 int status;
- 69
- 70 down_write(&__i2c_board_lock);
- 71
- 72
- 73 if (busnum >= __i2c_first_dynamic_bus_num)
- 74 __i2c_first_dynamic_bus_num = busnum + 1;
- 75
- 76 for (status = 0; len; len--, info++) {
- 77 struct i2c_devinfo *devinfo;
- 78
- 79 devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
- 80 if (!devinfo) {
- 81 pr_debug("i2c-core: can'tregister boardinfo!\n");
- 82 status = -ENOMEM;
- 83 break;
- 84 }
- 85
- 86 devinfo->busnum = busnum;
- 87 devinfo->board_info = *info;
- 88 list_add_tail(&devinfo->list, &__i2c_board_list);
- 89 }
- 90
- 91 up_write(&__i2c_board_lock);
- 92
- 93 return status;
- 94}
第一个参数busnum表明I2C设备所依附的I2C总线的总线号。
72-74行,如果参数传递进来的busnum 大于等于__i2c_first_dynamic_bus_num,则将__i2c_first_dynamic_bus_num设置为busnum+1。__i2c_first_dynamic_bus_num代表第一个动态分配的I2C总线号,所以,动态分配的I2C总线号总是大于静态分配的I2C总线号。
__i2c_first_dynamic_bus_num定义在drivers/i2c/i2c-boardinfo.c文件中:
- 38int __i2c_first_dynamic_bus_num;
因为__i2c_first_dynamic_bus_num是一个全局变量,所以其值被自动初始化为0。所以73行的if判断是成立的。
76-89行,循环遍历info数组,用i2c_board_info变量初始化structi2c_devinfo指针变量devinfo,然后将devinfo放入__i2c_board_list链表中。
i2c_devinfo变量定义在drivers/i2c/i2c-core.h文件中:
- 22struct i2c_devinfo {
- 23 struct list_head list;
- 24 int busnum;
- 25 struct i2c_board_info board_info;
- 26};
可以看到i2c_devinfo结构体只有三个成员变量,busnum用来保存I2C设备所依附的I2C总线号。board_info用来保存I2C设备相关信息。list用于链接到全局链表__i2c_board_list中。
__i2c_board_list 链表定义在drivers/i2c/i2c-boardinfo.c文件中:
- 35LIST_HEAD(__i2c_board_list);
- 36EXPORT_SYMBOL_GPL(__i2c_board_list);
全局变量__i2c_board_list上挂载着所有的I2C设备的信息,包括I2C设备所在的I2C总线的总线号。
所以,i2c_register_board_info函数并没有创建i2c_client,只是将i2c_devinfo变量放入__i2c_board_list链表中。那么,什么时候才会创建i2c_client呢?这个就与创建I2C设备驱动程序无关了,而是跟I2C adapter驱动程序有关:
注册一个I2C adapter有两种方法,一是调用i2c_add_adapter函数,二是调用i2c_add_numbered_adapter函数。
先来看i2c_add_adapter函数,它定义在drivers/i2c/i2c-core.c文件中:
- 1099
- 1113int i2c_add_adapter(struct i2c_adapter*adapter)
- 1114{
- 1115 struct device *dev = &adapter->dev;
- 1116 int id;
- 1117
- 1118 if (dev->of_node) {
- 1119 id = of_alias_get_id(dev->of_node, "i2c");
- 1120 if (id >= 0) {
- 1121 adapter->nr = id;
- 1122 return__i2c_add_numbered_adapter(adapter);
- 1123 }
- 1124 }
- 1125
- 1126 mutex_lock(&core_lock);
- 1127 id = idr_alloc(&i2c_adapter_idr, adapter,
- 1128 __i2c_first_dynamic_bus_num, 0,GFP_KERNEL);
- 1129 mutex_unlock(&core_lock);
- 1130 if (id < 0)
- 1131 return id;
- 1132
- 1133 adapter->nr = id;
- 1134
- 1135 return i2c_register_adapter(adapter);
- 1136}
该函数为参数指定的i2c_adapter动态分配的个I2C总线号,并注册该i2c_adapter。
1118-1124行,忽略。
1127-1133行,调用idr_alloc,动态分配一个id号,并将该id号做为i2c_adapter的I2C总线号。
关于idr机制,我们不详细分析,只需要知道它是一种快速索引机制,它将一个整数ID与一个需要被索引的指针建立联系,方便进行查找。例如,这里idr_alloc返回的id与i2c_adapter建立了索引。idr_alloc的第三个参数指定返回ID的最小值(闭区间),第四个参数指定返回ID的最大值(开区间),即idr_alloc返回的ID大于等于第三个参数,而且必须小于第四个参数。在这个函数中,第三个参数为__i2c_first_dynamic_bus_num,所以返回的id必然是大于等于__i2c_first_dynamic_bus_num的,即动态分配的I2C总线号必然大于__i2c_first_dynamic_bus_num。
1135行,调用i2c_register_adapter注册i2c_adapter。
下面我们来看i2c_add_numbered_adapter,该函数定义在drivers/i2c/i2c-core.c文件中:
- 1139
- 1162int i2c_add_numbered_adapter(structi2c_adapter *adap)
- 1163{
- 1164 if (adap->nr == -1)
- 1165 return i2c_add_adapter(adap);
- 1166
- 1167 return __i2c_add_numbered_adapter(adap);
- 1168}
该函数用于注册参数指定的i2c_adapter,该i2c_adapter的I2C总线号即i2c_adapter.nr必须已经静态设置好了。如果adap->nr为-1,则调用i2c_add_adapter动态分配I2C总线号,再注册。否则,调用__i2c_add_numbered_adapter函数。
__i2c_add_numbered_adapter函数定义在drivers/i2c/i2c-core.c文件中:
- 1078
- 1085static int__i2c_add_numbered_adapter(struct i2c_adapter *adap)
- 1086{
- 1087 int id;
- 1088
- 1089 mutex_lock(&core_lock);
- 1090 id = idr_alloc(&i2c_adapter_idr, adap, adap->nr, adap->nr + 1,
- 1091 GFP_KERNEL);
- 1092 mutex_unlock(&core_lock);
- 1093 if (id < 0)
- 1094 return id == -ENOSPC ? -EBUSY : id;
- 1095
- 1096 return i2c_register_adapter(adap);
- 1097}
1090-1091行,调用idr_alloc函数,建立idr索引关系。返回的id必须大于等于第三个参数adap->nr,同时必须小于第四个参数adap->nr+1,所以返回的id必然等于adap->nr,即静态指定的I2C总线号。
1096行,调用i2c_register_adapter注册i2c_adapter。
到这里,我们就知道了注册一个i2c_adapter可以调用i2c_add_numbered_adapter函数静态指定一个I2C总线号,也可以调用i2c_add_adapter函数动态分配一个I2C总线号。但是不论哪种方法,最后的注册工作都必须通过调用i2c_register_adapter函数完成。
i2c_register_adapter函数定义在drivers/i2c/i2c-core.c文件中,其内容如下:
- 980staticint i2c_register_adapter(struct i2c_adapter *adap)
- 981{
- 982 int res = 0;
- 983
- 984
- 985 if (unlikely(WARN_ON(!i2c_bus_type.p))) {
- 986 res = -EAGAIN;
- 987 goto out_list;
- 988 }
- 989
- 990
- 991 if (unlikely(adap->name[0] == '\0')) {
- 992 pr_err("i2c-core: Attempt to register an adapter with "
- 993 "no name!\n");
- 994 return -EINVAL;
- 995 }
- 996 if (unlikely(!adap->algo)) {
- 997 pr_err("i2c-core: Attempt to register adapter '%s' with "
- 998 "no algo!\n",adap->name);
- 999 return -EINVAL;
- 1000 }
- 1001
- 1002 rt_mutex_init(&adap->bus_lock);
- 1003 mutex_init(&adap->userspace_clients_lock);
- 1004 INIT_LIST_HEAD(&adap->userspace_clients);
- 1005
- 1006
- 1007 if (adap->timeout == 0)
- 1008 adap->timeout = HZ;
- 1009
- 1010 dev_set_name(&adap->dev, "i2c-%d", adap->nr);
- 1011 adap->dev.bus = &i2c_bus_type;
- 1012 adap->dev.type = &i2c_adapter_type;
- 1013 res = device_register(&adap->dev);
- 1014 if (res)
- 1015 goto out_list;
- 1016
- 1017 dev_dbg(&adap->dev, "adapter [%s] registered\n",adap->name);
- 1018
- 1019#ifdef CONFIG_I2C_COMPAT
- 1020 res = class_compat_create_link(i2c_adapter_compat_class,&adap->dev,
- 1021 adap->dev.parent);
- 1022 if (res)
- 1023 dev_warn(&adap->dev,
- 1024 "Failed to createcompatibility class link\n");
- 1025#endif
- 1026
- 1027
- 1028 if (adap->bus_recovery_info) {
- 1029 struct i2c_bus_recovery_info*bri = adap->bus_recovery_info;
- 1030
- 1031 if (!bri->recover_bus) {
- 1032 dev_err(&adap->dev, "Norecover_bus() found, not using recovery\n");
- 1033 adap->bus_recovery_info = NULL;
- 1034 goto exit_recovery;
- 1035 }
- 1036
- 1037
- 1038 if (bri->recover_bus == i2c_generic_gpio_recovery) {
- 1039 if(!gpio_is_valid(bri->scl_gpio)) {
- 1040 dev_err(&adap->dev,"Invalid SCL gpio, not using recovery\n");
- 1041 adap->bus_recovery_info =NULL;
- 1042 goto exit_recovery;
- 1043 }
- 1044
- 1045 if(gpio_is_valid(bri->sda_gpio))
- 1046 bri->get_sda =get_sda_gpio_value;
- 1047 else
- 1048 bri->get_sda = NULL;
- 1049
- 1050 bri->get_scl =get_scl_gpio_value;
- 1051 bri->set_scl =set_scl_gpio_value;
- 1052 } else if (!bri->set_scl || !bri->get_scl) {
- 1053
- 1054 dev_err(&adap->dev, "No{get|set}_gpio() found, not using recovery\n");
- 1055 adap->bus_recovery_info = NULL;
- 1056 }
- 1057 }
- 1058
- 1059exit_recovery:
- 1060
- 1061 if (adap->nr < __i2c_first_dynamic_bus_num)
- 1062 i2c_scan_static_board_info(adap);
- 1063
- 1064
- 1065 mutex_lock(&core_lock);
- 1066 bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
- 1067 mutex_unlock(&core_lock);
- 1068
- 1069 return 0;
- 1070
- 1071out_list:
- 1072 mutex_lock(&core_lock);
- 1073 idr_remove(&i2c_adapter_idr, adap->nr);
- 1074 mutex_unlock(&core_lock);
- 1075 return res;
- 1076}
984-1000行,做一些必要的检查工作。
1002-1008行,做一些简单的i2c_adapter成员变量初始化工作。
1010-1013行,初始化i2c_adapter.dev,并调用device_register注册i2c_adapter.dev。
1028-1057行,I2C总线恢复时相关的初始化工作。
1060-1062行,因为动态分析的I2C总线号必须大于或等于__i2c_first_dynamic_bus_num,所以,如果adap->nr< __i2c_first_dynamic_bus_num,说明是静态指定的I2C总线号,此时,要调用i2c_scan_static_board_info函数探测I2C总线上静态注册的I2C设备。
i2c_scan_static_board_info函数定义在drivers/i2c/i2c-core.c文件中,其内容如下:
- 941staticvoid i2c_scan_static_board_info(struct i2c_adapter *adapter)
- 942{
- 943 struct i2c_devinfo *devinfo;
- 944
- 945 down_read(&__i2c_board_lock);
- 946 list_for_each_entry(devinfo, &__i2c_board_list, list) {
- 947 if (devinfo->busnum == adapter->nr
- 948 &&!i2c_new_device(adapter,
- 949 &devinfo->board_info))
- 950 dev_err(&adapter->dev,
- 951 "Can't create device at0x%02x\n",
- 952 devinfo->board_info.addr);
- 953 }
- 954 up_read(&__i2c_board_lock);
- 955}
946-953行,遍历__i2c_board_list链表,如果devinfo->busnum等于adapter->nr,即链表节点所代表的I2C设备的I2C总线号等于i2c_adapter的I2C总线号,则调用i2c_new_device创建并注册I2C设备对应的i2c_client结构体。
到这里,就和我们在本文开始部分介绍的静态注册的i2c_board_info信息联系起来了。回忆一下我们通过调用i2c_register_board_info函数将将包含所有I2C设备的i2c_board_info信息的i2c_devinfo变量加入到__i2c_board_list链表中。现在在注册i2c_adater时,又通过调用i2c_scan_static_board_info函数遍历__i2c_board_list链表,查找属于对应i2c_adapter的I2C设备,如果找到,调用i2c_new_device创建对应的i2c_client结构体。
i2c_new_device函数定义在drivers/i2c/i2c-core.c文件中,其内容如下:
- 612
- 628struct i2c_client *
- 629i2c_new_device(struct i2c_adapter *adap,struct i2c_board_info const *info)
- 630{
- 631 struct i2c_client *client;
- 632 int status;
- 633
- 634 client = kzalloc(sizeof *client, GFP_KERNEL);
- 635 if (!client)
- 636 return NULL;
- 637
- 638 client->adapter = adap;
- 639
- 640 client->dev.platform_data = info->platform_data;
- 641
- 642 if (info->archdata)
- 643 client->dev.archdata = *info->archdata;
- 644
- 645 client->flags = info->flags;
- 646 client->addr = info->addr;
- 647 client->irq = info->irq;
- 648
- 649 strlcpy(client->name, info->type, sizeof(client->name));
- 650
- 651
- 652 status = i2c_check_client_addr_validity(client);
- 653 if (status) {
- 654 dev_err(&adap->dev,"Invalid %d-bit I2C address 0x%02hx\n",
- 655 client->flags & I2C_CLIENT_TEN ?10 : 7, client->addr);
- 656 goto out_err_silent;
- 657 }
- 658
- 659
- 660 status = i2c_check_addr_busy(adap, client->addr);
- 661 if (status)
- 662 goto out_err;
- 663
- 664 client->dev.parent = &client->adapter->dev;
- 665 client->dev.bus = &i2c_bus_type;
- 666 client->dev.type = &i2c_client_type;
- 667 client->dev.of_node = info->of_node;
- 668 ACPI_HANDLE_SET(&client->dev, info->acpi_node.handle);
- 669
- 670
- 671 dev_set_name(&client->dev, "%d-%04x",i2c_adapter_id(adap),
- 672 client->addr | ((client->flags & I2C_CLIENT_TEN)
- 673 ? 0xa000 : 0));
- 674 status =device_register(&client->dev);
- 675 if (status)
- 676 goto out_err;
- 677
- 678 dev_dbg(&adap->dev, "client [%s] registered with bus id%s\n",
- 679 client->name, dev_name(&client->dev));
- 680
- 681 return client;
- 682
- 683out_err:
- 684 dev_err(&adap->dev, "Failed to register i2c client %s at0x%02x "
- 685 "(%d)\n", client->name, client->addr, status);
- 686out_err_silent:
- 687 kfree(client);
- 688 return NULL;
请发表评论