linux i2c主机驱动,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[] = {

{

I2C_BOARD_INFO("twl4030", 0x48),

.flags = I2C_CLIENT_WAKE,

.irq = INT_34XX_SYS_NIRQ,

.platform_data = &omap3evm_twldata,

},

};在i2c driver驱动中通过以下代码将device和driver进行匹配

static const struct i2c_device_id twl_ids[] = {

{ "twl4030", TWL4030_VAUX2 },/* "Triton 2" */

{ "twl5030", 0 },/* T2 updated */

{ "twl5031", TWL5031 },/* TWL5030 updated */

{ "tps65950", 0 },/* catalog version of twl5030 */

{ "tps65930", TPS_SUBSET },/* fewer LDOs and DACs; no charger */

{ "tps65920", TPS_SUBSET },/* fewer LDOs; no codec or charger */

{ "twl6030", TWL6030_CLASS },/* "Phoenix power chip" */

{ /* end of list */ },

};

MODULE_DEVICE_TABLE(i2c, twl_ids);

/* One Client Driver , 4 Clients */

static struct i2c_driver twl_driver = {

.driver.name= DRIVER_NAME,

.id_table= twl_ids,

.probe= twl_probe,

.remove= twl_remove,

};

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应该怎么用呢?很简单,看一下代码。

static int __init

twl_probe(struct i2c_client *client, const struct i2c_device_id *id)

{

intstatus;

unsignedi;

struct twl4030_platform_data*pdata = client->dev.platform_data;

u8 temp;

if (!pdata) {

dev_dbg(&client->dev, "no platform data?\n");

return -EINVAL;

}

if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {

dev_dbg(&client->dev, "can't talk I2C?\n");

return -EIO;

}

if (inuse) {

dev_dbg(&client->dev, "driver is already in use\n");

return -EBUSY;

}

for (i = 0; i < TWL_NUM_SLAVES; i++) {

struct twl_client*twl = &twl_modules[i];

twl->address = client->addr + i;

if (i == 0)

twl->client = client;

else {

twl->client = i2c_new_dummy(client->adapter,

twl->address);

if (!twl->client) {

dev_err(&client->dev,

"can't attach client %d\n", i);

status = -ENOMEM;

goto fail;

}

}

mutex_init(&twl->xfer_lock);

}

inuse = true;

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];

}

/* setup clock framework */

clocks_init(&client->dev, pdata->clock);

/* load power event scripts */

if (twl_has_power() && pdata->power)

twl4030_power_init(pdata->power);

/* Maybe init the T2 Interrupt subsystem */

if (client->irq

&& pdata->irq_base

&& pdata->irq_end > pdata->irq_base) {

if (twl_class_is_4030()) {

twl4030_init_chip_irq(id->name);

status = twl4030_init_irq(client->irq, pdata->irq_base,

pdata->irq_end);

} else {

status = twl6030_init_irq(client->irq, pdata->irq_base,

pdata->irq_end);

}

if (status < 0)

goto fail;

}

/* Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.

* Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0,

* SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0.

*/

if (twl_class_is_4030()) {

twl_i2c_read_u8(TWL4030_MODULE_INTBR, &temp, REG_GPPUPDCTR1);

temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \

I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);

twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);

}

status = add_children(pdata, id->driver_data);

usb_gpio_settings();

fail:

if (status < 0)

twl_remove(client);

return status;

}再看看 TWL6030,它其实是一个宏定义。

#define TWL6030_CLASSBIT(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现在是在服务于哪个设备。

你可能感兴趣的:(linux,i2c主机驱动)