上·志

上下求索,志在千里。
随笔 - 18, 文章 - 25, 评论 - 4, 阅读 - 42403

导航

< 2025年2月 >
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 1
2 3 4 5 6 7 8

Linux I2C驱动:i2c_device_id

Posted on   Shangzhi  阅读(4722)  评论(1编辑  收藏  举报

Linux I2C驱动:i2c_device_id

Linux I2C设备驱动中,是通过i2c device id名字进行i2c device和i2c driver匹配的。

例如以下在板级代码定义"twl4030"作为device名字信息。

static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {

 

 
  1.     {  
  2.         I2C_BOARD_INFO("twl4030", 0x48),  
  3.         .flags = I2C_CLIENT_WAKE,  
  4.         .irq = INT_34XX_SYS_NIRQ,  
  5.         .platform_data = &omap3evm_twldata,  
  6.     },  
  7. };  
在i2c driver驱动中通过以下代码将device和driver进行匹配
 
  1. static const struct i2c_device_id twl_ids[] = {  
  2.     { "twl4030", TWL4030_VAUX2 },   /* "Triton 2" */  
  3.     { "twl5030", 0 },       /* T2 updated */  
  4.     { "twl5031", TWL5031 },     /* TWL5030 updated */  
  5.     { "tps65950", 0 },      /* catalog version of twl5030 */  
  6.     { "tps65930", TPS_SUBSET }, /* fewer LDOs and DACs; no charger */  
  7.     { "tps65920", TPS_SUBSET }, /* fewer LDOs; no codec or charger */  
  8.     { "twl6030", TWL6030_CLASS },   /* "Phoenix power chip" */  
  9.     { /* end of list */ },  
  10. };  
  11. MODULE_DEVICE_TABLE(i2c, twl_ids);  
  12.   
  13. /* One Client Driver , 4 Clients */  
  14. static struct i2c_driver twl_driver = {  
  15.     .driver.name    = DRIVER_NAME,  
  16.     .id_table   = twl_ids,  
  17.     .probe      = twl_probe,  
  18.     .remove     = twl_remove,  
  19. };  

 

i2c_device_id的原型是:

 

struct i2c_device_id {
	char name[I2C_NAME_SIZE];
	kernel_ulong_t driver_data	/* Data private to the driver */
			__attribute__((aligned(sizeof(kernel_ulong_t))));
};
那么通过看twl_ids和i2c_device_id原型可试想i2c_device_id结构中的第二个成员有什么作用?
为什么twl_ids有些明确使用了"driver_data",有些确默认赋值为0?

 

通过twl_ids看到,这个驱动和可以适用于多种设备,那么对于驱动开发着来说,要使得此驱动能和多种设备(twl4030/twl630等)兼容,那么就需要知道驱动和哪个设备匹配了。怎么知道呢?就是通过i2c_device_id的第二个成员了,driver_data可以用来方便快捷指示设备的一些特定属性。至于怎么指示则由驱动开发者来设定。

例如应该可以将i2c_device_id twl_ids定义为如果下形势:

 

static const struct i2c_device_id twl_ids[] = {
	{ "twl4030", 1},	/* "Triton 2" */
	{ "twl5030", 2 },		/* T2 updated */
	{ "twl5031", 3},		/* TWL5030 updated */
	{ "tps65950", 4 },		/* catalog version of twl5030 */
	{ "tps65930", 5},	/* fewer LDOs and DACs; no charger */
	{ "tps65920", 6},	/* fewer LDOs; no codec or charger */
	{ "twl6030", 7},	/* "Phoenix power chip" */
	{ /* end of list */ },
};
那么driver_data为1表示”twl4030“,driver_data为2表示”twl5030“等等。。

 

回到i2c_device_id twl_ids的原始定义,driver_data应该怎么用呢?很简单,看一下代码。

 

  1. static int __init  
  2. twl_probe(struct i2c_client *client, const struct i2c_device_id *id)  
  3. {  
  4.     int             status;  
  5.     unsigned            i;  
  6.     struct twl4030_platform_data    *pdata = client->dev.platform_data;  
  7.     u8 temp;  
  8.   
  9.     if (!pdata) {  
  10.         dev_dbg(&client->dev, "no platform data?\n");  
  11.         return -EINVAL;  
  12.     }  
  13.   
  14.     if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {  
  15.         dev_dbg(&client->dev, "can't talk I2C?\n");  
  16.         return -EIO;  
  17.     }  
  18.   
  19.     if (inuse) {  
  20.         dev_dbg(&client->dev, "driver is already in use\n");  
  21.         return -EBUSY;  
  22.     }  
  23.   
  24.     for (i = 0; i < TWL_NUM_SLAVES; i++) {  
  25.         struct twl_client   *twl = &twl_modules[i];  
  26.   
  27.         twl->address = client->addr + i;  
  28.         if (i == 0)  
  29.             twl->client = client;  
  30.         else {  
  31.             twl->client = i2c_new_dummy(client->adapter,  
  32.                     twl->address);  
  33.             if (!twl->client) {  
  34.                 dev_err(&client->dev,  
  35.                     "can't attach client %d\n", i);  
  36.                 status = -ENOMEM;  
  37.                 goto fail;  
  38.             }  
  39.         }  
  40.         mutex_init(&twl->xfer_lock);  
  41.     }  
  42.     inuse = true;  
  43.     if ((id->driver_data) & TWL6030_CLASS) {  
  44.         twl_id = TWL6030_CLASS_ID;  
  45.         twl_map = &twl6030_map[0];  
  46.     } else {  
  47.         twl_id = TWL4030_CLASS_ID;  
  48.         twl_map = &twl4030_map[0];  
  49.     }  
  50.   
  51.     /* setup clock framework */  
  52.     clocks_init(&client->dev, pdata->clock);  
  53.   
  54.     /* load power event scripts */  
  55.     if (twl_has_power() && pdata->power)  
  56.         twl4030_power_init(pdata->power);  
  57.   
  58.     /* Maybe init the T2 Interrupt subsystem */  
  59.     if (client->irq  
  60.             && pdata->irq_base  
  61.             && pdata->irq_end > pdata->irq_base) {  
  62.         if (twl_class_is_4030()) {  
  63.             twl4030_init_chip_irq(id->name);  
  64.             status = twl4030_init_irq(client->irq, pdata->irq_base,  
  65.             pdata->irq_end);  
  66.         } else {  
  67.             status = twl6030_init_irq(client->irq, pdata->irq_base,  
  68.             pdata->irq_end);  
  69.         }  
  70.   
  71.         if (status < 0)  
  72.             goto fail;  
  73.     }  
  74.   
  75.     /* Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface. 
  76.      * Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0, 
  77.      * SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0. 
  78.      */  
  79.   
  80.     if (twl_class_is_4030()) {  
  81.         twl_i2c_read_u8(TWL4030_MODULE_INTBR, &temp, REG_GPPUPDCTR1);  
  82.         temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \  
  83.         I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);  
  84.         twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);  
  85.     }  
  86.   
  87.     status = add_children(pdata, id->driver_data);  
  88.   
  89.     usb_gpio_settings();  
  90. fail:  
  91.     if (status < 0)  
  92.         twl_remove(client);  
  93.     return status;  
  94. }  
再看看 TWL6030,它其实是一个宏定义。
 
  1. #define TWL6030_CLASS       BIT(3)  /* TWL6030 class */  

找i2c driver的probe函数中,以下代码:

 

	if ((id->driver_data) & TWL6030_CLASS) {
		twl_id = TWL6030_CLASS_ID;
		twl_map = &twl6030_map[0];
	} else {
		twl_id = TWL4030_CLASS_ID;
		twl_map = &twl4030_map[0];
	}

 

就通过 driver_data 来判断driver现在是在服务于哪个设备。

努力加载评论中...
点击右上角即可分享
微信分享提示