• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

i2cdrivers

原作者: [db:作者] 来自: [db:来源] 收藏 邀请
 
 

转载于: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文件中:

 

  1. 200/** 
  2. 201 * struct i2c_client - represent an I2Cslave device 
  3. 202 * @flags: I2C_CLIENT_TEN indicates thedevice uses a ten bit chip address; 
  4. 203 * I2C_CLIENT_PEC indicates it uses SMBus Packet Error Checking 
  5. 204 * @addr: Address used on the I2C busconnected to the parent adapter. 
  6. 205 * @name: Indicates the type of thedevice, usually a chip name that's 
  7. 206 * generic enough to hide second-sourcing and compatible revisions. 
  8. 207 * @adapter: manages the bus segmenthosting this I2C device 
  9. 208 * @driver: device's driver, hencepointer to access routines 
  10. 209 * @dev: Driver model device node forthe slave. 
  11. 210 * @irq: indicates the IRQ generated bythis device (if any) 
  12. 211 * @detected: member of ani2c_driver.clients list or i2c-core's 
  13. 212 * userspace_devices list 
  14. 213 * 
  15. 214 * An i2c_client identifies a singledevice (i.e. chip) connected to an 
  16. 215 * i2c bus. The behaviour exposed to Linuxis defined by the driver 
  17. 216 * managing the device. 
  18. 217 */  
  19. 218struct i2c_client {  
  20. 219   unsigned short flags;       /*div., see below      */  
  21. 220   unsigned short addr;        /*chip address - NOTE: 7bit    */  
  22. 221                    /* addresses are stored inthe  */  
  23. 222                    /* _LOWER_ 7 bits       */  
  24. 223   char name[I2C_NAME_SIZE];  
  25. 224   struct i2c_adapter *adapter;    /*the adapter we sit on    */  
  26. 225   struct i2c_driver *driver;  /* andour access routines  */  
  27. 226   struct device dev;      /* thedevice structure     */  
  28. 227   int irq;            /* irq issuedby device     */  
  29. 228   struct list_head detected;  
  30. 229};  


 

我们不用直接定义一个i2c_client结构,Linux会根据I2C设备的相关信息自动创建i2c_client。所以,我们需要提供I2C设备的相关信息。对于Mini2440的I2C设备at24c08 EEPROM,其相关信息保存在arch/arm/mach-s3c24xx/mach-mini2440.c文件中:

 

  1. 485/* 
  2. 486 * I2C devices 
  3. 487 */  
  4. 488static struct at24_platform_data at24c08= {  
  5. 489   .byte_len   = SZ_8K / 8,  
  6. 490   .page_size  = 16,  
  7. 491};  
  8. 492  
  9. 493static struct i2c_board_infomini2440_i2c_devs[] __initdata = {  
  10. 494   {  
  11. 495       I2C_BOARD_INFO("24c08", 0x50),  
  12. 496       .platform_data = &at24c08,  
  13. 497   },  
  14. 498};  


 

struct i2c_board_info是创建i2c设备的模板,该结构体定义在include/linux/i2c.h文件中:

 

  1. 251/** 
  2. 252 * struct i2c_board_info - template fordevice creation 
  3. 253 * @type: chip type, to initializei2c_client.name 
  4. 254 * @flags: to initializei2c_client.flags 
  5. 255 * @addr: stored in i2c_client.addr 
  6. 256 * @platform_data: stored ini2c_client.dev.platform_data 
  7. 257 * @archdata: copied intoi2c_client.dev.archdata 
  8. 258 * @of_node: pointer to OpenFirmwaredevice node 
  9. 259 * @acpi_node: ACPI device node 
  10. 260 * @irq: stored in i2c_client.irq 
  11. 261 * 
  12. 262 * I2C doesn't actually support hardwareprobing, although controllers and 
  13. 263 * devices may be able to useI2C_SMBUS_QUICK to tell whether or not there's 
  14. 264 * a device at a given address.  Drivers commonly need more information than 
  15. 265 * that, such as chip type,configuration, associated IRQ, and so on. 
  16. 266 * 
  17. 267 * i2c_board_info is used to buildtables of information listing I2C devices 
  18. 268 * that are present.  This information is used to grow the drivermodel tree. 
  19. 269 * For mainboards this is donestatically using i2c_register_board_info(); 
  20. 270 * bus numbers identify adapters thataren't yet available.  For add-on boards, 
  21. 271 * i2c_new_device() does thisdynamically with the adapter already known. 
  22. 272 */  
  23. 273struct i2c_board_info {  
  24. 274   char        type[I2C_NAME_SIZE];  
  25. 275   unsigned short  flags;  
  26. 276   unsigned short  addr;  
  27. 277   void        *platform_data;  
  28. 278   struct dev_archdata *archdata;  
  29. 279   struct device_node *of_node;  
  30. 280   struct acpi_dev_node acpi_node;  
  31. 281   int     irq;  
  32. 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文件中,其内容如下:

 

  1. 284/** 
  2. 285 * I2C_BOARD_INFO - macro used to listan i2c device and its address 
  3. 286 * @dev_type: identifies the device type 
  4. 287 * @dev_addr: the device's address onthe bus. 
  5. 288 * 
  6. 289 * This macro initializes essentialfields of a struct i2c_board_info, 
  7. 290 * declaring what has been provided on aparticular board.  Optional 
  8. 291 * fields (such as associated irq, ordevice-specific platform_data) 
  9. 292 * are provided using conventionalsyntax. 
  10. 293 */  
  11. 294#define I2C_BOARD_INFO(dev_type,dev_addr) \  
  12. 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

  1. 4/** 
  2. 15 * struct at24_platform_data - data toset up at24 (generic eeprom) driver 
  3. 16 * @byte_len: size of eeprom in byte 
  4. 17 * @page_size: number of byte which canbe written in one go 
  5. 18 * @flags: tunable options, checkAT24_FLAG_* defines 
  6. 19 * @setup: an optional callback invokedafter eeprom is probed; enables kernel 
  7. 20   code to access eeprom via memory_accessor, see example 
  8. 21 * @context: optional parameter passed tosetup() 
  9. 22 * 
  10. 23 * If you set up a custom eeprom type,please double-check the parameters. 
  11. 24 * Especially page_size needs extra care,as you risk data loss if your value 
  12. 25 * is bigger than what the chip actuallysupports! 
  13. 26 * 
  14. 27 * An example in pseudo code for asetup() callback: 
  15. 28 * 
  16. 29 * void get_mac_addr(structmemory_accessor *mem_acc, void *context) 
  17. 30 * { 
  18. 31 * u8 *mac_addr = ethernet_pdata->mac_addr; 
  19. 32 * off_t offset = context; 
  20. 33 * 
  21. 34 * // Read MAC addr from EEPROM 
  22. 35 * if (mem_acc->read(mem_acc, mac_addr, offset, ETH_ALEN) == ETH_ALEN) 
  23. 36 *     pr_info("Read MAC addr from EEPROM: %pM\n", mac_addr); 
  24. 37 * } 
  25. 38 * 
  26. 39 * This function pointer and context cannow be set up in at24_platform_data. 
  27. 40 */  
  28. 41  
  29. 42struct at24_platform_data {  
  30. 43   u32     byte_len;       /* size (sum of all addr) */  
  31. 44   u16     page_size;      /* for writes */  
  32. 45   u8      flags;  
  33. 46#define AT24_FLAG_ADDR16    0x80   /* address pointer is 16 bit */  
  34. 47#define AT24_FLAG_READONLY  0x40   /* sysfs-entry will be read-only */  
  35. 48#define AT24_FLAG_IRUGO     0x20   /* sysfs-entry will be world-readable */  
  36. 49#define AT24_FLAG_TAKE8ADDR 0x10    /* take always 8 addresses (24c00) */  
  37. 50  
  38. 51   void        (*setup)(structmemory_accessor *, void *context);  
  39. 52   void        *context;  
  40. 53};  

 

该结构体用来保存at24系列EEPROM的platform data。byte_len成员变量保存EEPROM的大小,以byte为单位。page_size成员变量用来指定一次最多能写多少个byte。对于Mini2440,定义at24_platform_data结构体变量at24c08:

 

  1. 488static struct at24_platform_data at24c08= {  
  2. 489   .byte_len   = SZ_8K / 8,  
  3. 490   .page_size  = 16,  
  4. 491};  


 

SZ_8K宏即8K,定义在include/linux/sizes.h文件中:

 

  1. 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函数内容如下:

 

  1. 622static void __init mini2440_init(void)  
  2. 623{  
  3. 624   struct mini2440_features_t features = { 0 };  
  4. 625   int i;  
  5. 626  
  6. 627   printk(KERN_INFO "MINI2440: Option string mini2440=%s\n",  
  7. 628            mini2440_features_str);  
  8. 629  
  9. 630   /* Parse the feature string */  
  10. 631   mini2440_parse_features(&features, mini2440_features_str);  
  11. 632  
  12. 633   /* turn LCD on */  
  13. 634   s3c_gpio_cfgpin(S3C2410_GPC(0), S3C2410_GPC0_LEND);  
  14. 635  
  15. 636   /* Turn the backlight early on */  
  16. 637   WARN_ON(gpio_request_one(S3C2410_GPG(4), GPIOF_OUT_INIT_HIGH, NULL));  
  17. 638   gpio_free(S3C2410_GPG(4));  
  18. 639  
  19. 640   /* remove pullup on optional PWM backlight -- unused on 3.5 and 7"s*/  
  20. 641   gpio_request_one(S3C2410_GPB(1), GPIOF_IN, NULL);  
  21. 642   s3c_gpio_setpull(S3C2410_GPB(1), S3C_GPIO_PULL_UP);  
  22. 643   gpio_free(S3C2410_GPB(1));  
  23. 644  
  24. 645   /* mark the key as input, without pullups (there is one on the board) */  
  25. 646   for (i = 0; i < ARRAY_SIZE(mini2440_buttons); i++) {  
  26. 647       s3c_gpio_setpull(mini2440_buttons[i].gpio, S3C_GPIO_PULL_UP);  
  27. 648       s3c_gpio_cfgpin(mini2440_buttons[i].gpio, S3C2410_GPIO_INPUT);  
  28. 649   }  
  29. 650   if (features.lcd_index != -1) {  
  30. 651       int li;  
  31. 652  
  32. 653       mini2440_fb_info.displays =  
  33. 654           &mini2440_lcd_cfg[features.lcd_index];  
  34. 655  
  35. 656       printk(KERN_INFO "MINI2440: LCD");  
  36. 657       for (li = 0; li < ARRAY_SIZE(mini2440_lcd_cfg); li++)  
  37. 658            if (li == features.lcd_index)  
  38. 659                printk(" [%d:%dx%d]",li,  
  39. 660                   mini2440_lcd_cfg[li].width,  
  40. 661                   mini2440_lcd_cfg[li].height);  
  41. 662            else  
  42. 663                printk(" %d:%dx%d",li,  
  43. 664                    mini2440_lcd_cfg[li].width,  
  44. 665                    mini2440_lcd_cfg[li].height);  
  45. 666       printk("\n");  
  46. 667       s3c24xx_fb_set_platdata(&mini2440_fb_info);  
  47. 668   }  
  48. 669  
  49. 670   s3c24xx_udc_set_platdata(&mini2440_udc_cfg);  
  50. 671   s3c24xx_mci_set_platdata(&mini2440_mmc_cfg);  
  51. 672   s3c_nand_set_platdata(&mini2440_nand_info);  
  52. 673   s3c_i2c0_set_platdata(NULL);  
  53. 674  
  54. 675   i2c_register_board_info(0, mini2440_i2c_devs,  
  55. 676                ARRAY_SIZE(mini2440_i2c_devs));  
  56. 677  
  57. 678   platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));  
  58. 679  
  59. 680   if (features.count) /* the optional features */  
  60. 681       platform_add_devices(features.optional, features.count);  
  61. 682  
  62. 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文件中,其内容如下:

 

  1. 42/** 
  2. 43 * i2c_register_board_info - staticallydeclare I2C devices 
  3. 44 * @busnum: identifies the bus to whichthese devices belong 
  4. 45 * @info: vector of i2c devicedescriptors 
  5. 46 * @len: how many descriptors in the vector;may be zero to reserve 
  6. 47 * the specified bus number. 
  7. 48 * 
  8. 49 * Systems using the Linux I2C driverstack can declare tables of board info 
  9. 50 * while they initialize.  This should be done in board-specific initcode 
  10. 51 * near arch_initcall() time, orequivalent, before any I2C adapter driver is 
  11. 52 * registered.  For example, mainboard init code could defineseveral devices, 
  12. 53 * as could the init code for eachdaughtercard in a board stack. 
  13. 54 * 
  14. 55 * The I2C devices will be created later,after the adapter for the relevant 
  15. 56 * bus has been registered.  After that moment, standard driver modeltools 
  16. 57 * are used to bind "new style"I2C drivers to the devices.  The busnumber 
  17. 58 * for any device declared using thisroutine is not available for dynamic 
  18. 59 * allocation. 
  19. 60 * 
  20. 61 * The board info passed can safely be__initdata, but be careful of embedded 
  21. 62 * pointers (for platform_data,functions, etc) since that won't be copied. 
  22. 63 */  
  23. 64int __init  
  24. 65i2c_register_board_info(int busnum,  
  25. 66   struct i2c_board_info const *info, unsigned len)  
  26. 67{  
  27. 68   int status;  
  28. 69  
  29. 70   down_write(&__i2c_board_lock);  
  30. 71  
  31. 72   /* dynamic bus numbers will be assigned after the last static one */  
  32. 73   if (busnum >= __i2c_first_dynamic_bus_num)  
  33. 74       __i2c_first_dynamic_bus_num = busnum + 1;  
  34. 75  
  35. 76   for (status = 0; len; len--, info++) {  
  36. 77       struct i2c_devinfo  *devinfo;  
  37. 78  
  38. 79       devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);  
  39. 80       if (!devinfo) {  
  40. 81            pr_debug("i2c-core: can'tregister boardinfo!\n");  
  41. 82            status = -ENOMEM;  
  42. 83            break;  
  43. 84       }  
  44. 85  
  45. 86       devinfo->busnum = busnum;  
  46. 87       devinfo->board_info = *info;  
  47. 88       list_add_tail(&devinfo->list, &__i2c_board_list);  
  48. 89   }  
  49. 90  
  50. 91   up_write(&__i2c_board_lock);  
  51. 92  
  52. 93   return status;  
  53. 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文件中:

 

  1. 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文件中:

 

  1. 22struct i2c_devinfo {  
  2. 23   struct list_head    list;  
  3. 24   int         busnum;  
  4. 25   struct i2c_board_info  board_info;  
  5. 26};  


 

可以看到i2c_devinfo结构体只有三个成员变量,busnum用来保存I2C设备所依附的I2C总线号。board_info用来保存I2C设备相关信息。list用于链接到全局链表__i2c_board_list中。

__i2c_board_list 链表定义在drivers/i2c/i2c-boardinfo.c文件中:

 

  1. 35LIST_HEAD(__i2c_board_list);  
  2. 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文件中:

 

  1. 1099/** 
  2. 1100 * i2c_add_adapter - declare i2cadapter, use dynamic bus number 
  3. 1101 * @adapter: the adapter to add 
  4. 1102 * Context: can sleep 
  5. 1103 * 
  6. 1104 * This routine is used to declare anI2C adapter when its bus number 
  7. 1105 * doesn't matter or when its busnumber is specified by an dt alias. 
  8. 1106 * Examples of bases when the busnumber doesn't matter: I2C adapters 
  9. 1107 * dynamically added by USB links orPCI plugin cards. 
  10. 1108 * 
  11. 1109 * When this returns zero, a new busnumber was allocated and stored 
  12. 1110 * in adap->nr, and the specifiedadapter became available for clients. 
  13. 1111 * Otherwise, a negative errno value isreturned. 
  14. 1112 */  
  15. 1113int i2c_add_adapter(struct i2c_adapter*adapter)  
  16. 1114{  
  17. 1115   struct device *dev = &adapter->dev;  
  18. 1116   int id;  
  19. 1117  
  20. 1118   if (dev->of_node) {  
  21. 1119       id = of_alias_get_id(dev->of_node, "i2c");  
  22. 1120       if (id >= 0) {  
  23. 1121            adapter->nr = id;  
  24. 1122            return__i2c_add_numbered_adapter(adapter);  
  25. 1123       }  
  26. 1124   }  
  27. 1125  
  28. 1126   mutex_lock(&core_lock);  
  29. 1127   id = idr_alloc(&i2c_adapter_idr, adapter,  
  30. 1128               __i2c_first_dynamic_bus_num, 0,GFP_KERNEL);  
  31. 1129   mutex_unlock(&core_lock);  
  32. 1130   if (id < 0)  
  33. 1131       return id;  
  34. 1132  
  35. 1133   adapter->nr = id;  
  36. 1134  
  37. 1135   return i2c_register_adapter(adapter);  
  38. 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文件中:

 

  1. 1139/** 
  2. 1140 * i2c_add_numbered_adapter - declarei2c adapter, use static bus number 
  3. 1141 * @adap: the adapter to register (withadap->nr initialized) 
  4. 1142 * Context: can sleep 
  5. 1143 * 
  6. 1144 * This routine is used to declare anI2C adapter when its bus number 
  7. 1145 * matters.  For example, use it for I2C adapters fromsystem-on-chip CPUs, 
  8. 1146 * or otherwise built in to thesystem's mainboard, and where i2c_board_info 
  9. 1147 * is used to properly configure I2Cdevices. 
  10. 1148 * 
  11. 1149 * If the requested bus number is setto -1, then this function will behave 
  12. 1150 * identically to i2c_add_adapter, andwill dynamically assign a bus number. 
  13. 1151 * 
  14. 1152 * If no devices have pre-been declaredfor this bus, then be sure to 
  15. 1153 * register the adapter before anydynamically allocated ones.  Otherwise 
  16. 1154 * the required bus ID may not beavailable. 
  17. 1155 * 
  18. 1156 * When this returns zero, thespecified adapter became available for 
  19. 1157 * clients using the bus numberprovided in adap->nr.  Also, the table 
  20. 1158 * of I2C devices pre-declared usingi2c_register_board_info() is scanned, 
  21. 1159 * and the appropriate driver modeldevice nodes are created.  Otherwise, a 
  22. 1160 * negative errno value is returned. 
  23. 1161 */  
  24. 1162int i2c_add_numbered_adapter(structi2c_adapter *adap)  
  25. 1163{  
  26. 1164   if (adap->nr == -1) /* -1 means dynamically assign bus id */  
  27. 1165       return i2c_add_adapter(adap);  
  28. 1166  
  29. 1167   return __i2c_add_numbered_adapter(adap);  
  30. 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文件中:

 

  1. 1078/** 
  2. 1079 * __i2c_add_numbered_adapter -i2c_add_numbered_adapter where nr is never -1 
  3. 1080 * @adap: the adapter to register (withadap->nr initialized) 
  4. 1081 * Context: can sleep 
  5. 1082 * 
  6. 1083 * See i2c_add_numbered_adapter() fordetails. 
  7. 1084 */  
  8. 1085static int__i2c_add_numbered_adapter(struct i2c_adapter *adap)  
  9. 1086{  
  10. 1087   int id;  
  11. 1088  
  12. 1089   mutex_lock(&core_lock);  
  13. 1090   id = idr_alloc(&i2c_adapter_idr, adap, adap->nr, adap->nr + 1,  
  14. 1091               GFP_KERNEL);  
  15. 1092   mutex_unlock(&core_lock);  
  16. 1093   if (id < 0)  
  17. 1094       return id == -ENOSPC ? -EBUSY : id;  
  18. 1095  
  19. 1096   return i2c_register_adapter(adap);  
  20. 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文件中,其内容如下:

 

  1.  980staticint i2c_register_adapter(struct i2c_adapter *adap)  
  2.  981{  
  3.  982   int res = 0;  
  4.  983  
  5.  984   /* Can't register until after driver model init */  
  6.  985   if (unlikely(WARN_ON(!i2c_bus_type.p))) {  
  7.  986       res = -EAGAIN;  
  8.  987       goto out_list;  
  9.  988    }  
  10.  989  
  11.  990   /* Sanity checks */  
  12.  991   if (unlikely(adap->name[0] == '\0')) {  
  13.  992       pr_err("i2c-core: Attempt to register an adapter with "  
  14.  993               "no name!\n");  
  15.  994       return -EINVAL;  
  16.  995    }  
  17.  996   if (unlikely(!adap->algo)) {  
  18.  997       pr_err("i2c-core: Attempt to register adapter '%s' with "  
  19.  998               "no algo!\n",adap->name);  
  20.  999       return -EINVAL;  
  21. 1000   }  
  22. 1001  
  23. 1002   rt_mutex_init(&adap->bus_lock);  
  24. 1003   mutex_init(&adap->userspace_clients_lock);  
  25. 1004   INIT_LIST_HEAD(&adap->userspace_clients);  
  26. 1005  
  27. 1006   /* Set default timeout to 1 second if not already set */  
  28. 1007   if (adap->timeout == 0)  
  29. 1008       adap->timeout = HZ;  
  30. 1009  
  31. 1010   dev_set_name(&adap->dev, "i2c-%d", adap->nr);  
  32. 1011   adap->dev.bus = &i2c_bus_type;  
  33. 1012   adap->dev.type = &i2c_adapter_type;  
  34. 1013   res = device_register(&adap->dev);  
  35. 1014   if (res)  
  36. 1015       goto out_list;  
  37. 1016  
  38. 1017   dev_dbg(&adap->dev, "adapter [%s] registered\n",adap->name);  
  39. 1018  
  40. 1019#ifdef CONFIG_I2C_COMPAT  
  41. 1020   res = class_compat_create_link(i2c_adapter_compat_class,&adap->dev,  
  42. 1021                       adap->dev.parent);  
  43. 1022   if (res)  
  44. 1023       dev_warn(&adap->dev,  
  45. 1024             "Failed to createcompatibility class link\n");  
  46. 1025#endif  
  47. 1026  
  48. 1027   /* bus recovery specific initialization */  
  49. 1028   if (adap->bus_recovery_info) {  
  50. 1029       struct i2c_bus_recovery_info*bri = adap->bus_recovery_info;  
  51. 1030  
  52. 1031       if (!bri->recover_bus) {  
  53. 1032            dev_err(&adap->dev, "Norecover_bus() found, not using recovery\n");  
  54. 1033            adap->bus_recovery_info = NULL;  
  55. 1034            goto exit_recovery;  
  56. 1035       }  
  57. 1036  
  58. 1037       /* Generic GPIO recovery */  
  59. 1038       if (bri->recover_bus == i2c_generic_gpio_recovery) {  
  60. 1039            if(!gpio_is_valid(bri->scl_gpio)) {  
  61. 1040                dev_err(&adap->dev,"Invalid SCL gpio, not using recovery\n");  
  62. 1041                adap->bus_recovery_info =NULL;  
  63. 1042                goto exit_recovery;  
  64. 1043            }  
  65. 1044  
  66. 1045            if(gpio_is_valid(bri->sda_gpio))  
  67. 1046                bri->get_sda =get_sda_gpio_value;  
  68. 1047           else  
  69. 1048                bri->get_sda = NULL;  
  70. 1049  
  71. 1050            bri->get_scl =get_scl_gpio_value;  
  72. 1051            bri->set_scl =set_scl_gpio_value;  
  73. 1052       } else if (!bri->set_scl || !bri->get_scl) {  
  74. 1053            /* Generic SCL recovery */  
  75. 1054            dev_err(&adap->dev, "No{get|set}_gpio() found, not using recovery\n");  
  76. 1055            adap->bus_recovery_info = NULL;  
  77. 1056       }  
  78. 1057   }  
  79. 1058  
  80. 1059exit_recovery:  
  81. 1060   /* create pre-declared device nodes */  
  82. 1061   if (adap->nr < __i2c_first_dynamic_bus_num)  
  83. 1062       i2c_scan_static_board_info(adap);  
  84. 1063  
  85. 1064   /* Notify drivers */  
  86. 1065   mutex_lock(&core_lock);  
  87. 1066   bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);  
  88. 1067   mutex_unlock(&core_lock);  
  89. 1068  
  90. 1069   return 0;  
  91. 1070  
  92. 1071out_list:  
  93. 1072   mutex_lock(&core_lock);  
  94. 1073   idr_remove(&i2c_adapter_idr, adap->nr);  
  95. 1074   mutex_unlock(&core_lock);  
  96. 1075   return res;  
  97. 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文件中,其内容如下:

 

  1. 941staticvoid i2c_scan_static_board_info(struct i2c_adapter *adapter)  
  2. 942{  
  3. 943   struct i2c_devinfo  *devinfo;  
  4. 944  
  5. 945   down_read(&__i2c_board_lock);  
  6. 946   list_for_each_entry(devinfo, &__i2c_board_list, list) {  
  7. 947       if (devinfo->busnum == adapter->nr  
  8. 948                &&!i2c_new_device(adapter,  
  9. 949                       &devinfo->board_info))  
  10. 950           dev_err(&adapter->dev,  
  11. 951                "Can't create device at0x%02x\n",  
  12. 952                devinfo->board_info.addr);  
  13. 953    }  
  14. 954   up_read(&__i2c_board_lock);  
  15. 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文件中,其内容如下:

 

  1. 612/** 
  2. 613* i2c_new_device - instantiate an i2c device 
  3. 614* @adap: the adapter managing the device 
  4. 615* @info: describes one I2C device; bus_num is ignored 
  5. 616* Context: can sleep 
  6. 617* 
  7. 618* Create an i2c device. Binding is handled through driver model 
  8. 619* probe()/remove() methods.  A driver maybe bound to this device when we 
  9. 620* return from this function, or any later moment (e.g. maybe hotplugging will 
  10. 621* load the driver module).  This call isnot appropriate for use by mainboard 
  11. 622* initialization logic, which usually runs during an arch_initcall() long 
  12. 623* before any i2c_adapter could exist. 
  13. 624* 
  14. 625* This returns the new i2c client, which may be saved for later use with 
  15. 626* i2c_unregister_device(); or NULL to indicate an error. 
  16. 627*/  
  17. 628struct i2c_client *  
  18. 629i2c_new_device(struct i2c_adapter *adap,struct i2c_board_info const *info)  
  19. 630{  
  20. 631   struct i2c_client   *client;  
  21. 632   int         status;  
  22. 633  
  23. 634   client = kzalloc(sizeof *client, GFP_KERNEL);  
  24. 635   if (!client)  
  25. 636       return NULL;  
  26. 637  
  27. 638   client->adapter = adap;  
  28. 639  
  29. 640   client->dev.platform_data = info->platform_data;  
  30. 641  
  31. 642   if (info->archdata)  
  32. 643       client->dev.archdata = *info->archdata;  
  33. 644  
  34. 645   client->flags = info->flags;  
  35. 646   client->addr = info->addr;  
  36. 647   client->irq = info->irq;  
  37. 648  
  38. 649   strlcpy(client->name, info->type, sizeof(client->name));  
  39. 650  
  40. 651   /* Check for address validity */  
  41. 652   status = i2c_check_client_addr_validity(client);  
  42. 653   if (status) {  
  43. 654        dev_err(&adap->dev,"Invalid %d-bit I2C address 0x%02hx\n",  
  44. 655            client->flags & I2C_CLIENT_TEN ?10 : 7, client->addr);  
  45. 656       goto out_err_silent;  
  46. 657    }  
  47. 658  
  48. 659   /* Check for address business */  
  49. 660   status = i2c_check_addr_busy(adap, client->addr);  
  50. 661   if (status)  
  51. 662       goto out_err;  
  52. 663  
  53. 664   client->dev.parent = &client->adapter->dev;  
  54. 665   client->dev.bus = &i2c_bus_type;  
  55. 666   client->dev.type = &i2c_client_type;  
  56. 667   client->dev.of_node = info->of_node;  
  57. 668   ACPI_HANDLE_SET(&client->dev, info->acpi_node.handle);  
  58. 669  
  59. 670   /* For 10-bit clients, add an arbitrary offset to avoid collisions */  
  60. 671   dev_set_name(&client->dev, "%d-%04x",i2c_adapter_id(adap),  
  61. 672            client->addr | ((client->flags & I2C_CLIENT_TEN)  
  62. 673                     ? 0xa000 : 0));  
  63. 674    status =device_register(&client->dev);  
  64. 675   if (status)  
  65. 676       goto out_err;  
  66. 677  
  67. 678   dev_dbg(&adap->dev, "client [%s] registered with bus id%s\n",  
  68. 679       client->name, dev_name(&client->dev));  
  69. 680  
  70. 681   return client;  
  71. 682  
  72. 683out_err:  
  73. 684   dev_err(&adap->dev, "Failed to register i2c client %s at0x%02x "  
  74. 685       "(%d)\n", client->name, client->addr, status);  
  75. 686out_err_silent:  
  76. 687   kfree(client);  
  77. 688   return NULL;  

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
C++实现邻接表发布时间:2022-07-14
下一篇:
[转][C#]HttpClient代码示例发布时间:2022-07-14
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap