本文分析 mpu6050_drv.c 中 I2C 驱动部分的

 

module_i2c_driver()

 

这个宏来注册i2c_driver,这个宏在/include/linux/i2c.h定义,注释上说用它来注册一个i2c_driver,并通过调用它代替module_init() 

我们可以看下它的原形:

#define module_i2c_driver(__i2c_driver) \

module_driver(__i2c_driver, i2c_add_driver, \

i2c_del_driver)



#define module_driver(__driver, __register, __unregister, ...) \

static int __init __driver##_init(void) \

{ \

return __register(&(__driver) , ##__VA_ARGS__); \

} \

module_init(__driver##_init); \

static void __exit __driver##_exit(void) \

{ \

__unregister(&(__driver) , ##__VA_ARGS__); \

} \

module_exit(__driver##_exit);

 

事实上它就是注册了一个I2C设备驱动 i2c_driver

看下它的原形:

 

i2c_driver

中间很多细节被省略了。

struct i2c_driver {

unsigned int class;



int (*attach_adapter)(struct i2c_adapter *) __deprecated;

//匹配时会调用如下函数

int (*probe)(struct i2c_client *, const struct i2c_device_id *);

int (*remove)(struct i2c_client *);



//前面说了,我们事实上就是一个驱动,需要如下结构

struct device_driver driver;

const struct i2c_device_id *id_table;



struct list_head clients;

};

 

 

probe 函数原形

int (*probe)(struct i2c_client *, const struct i2c_device_id *);

事实上,i2c_client 对应了一个实际I2C设备,我们再 probe 中要把它保存起来。

 

这里我们要转换一个概念,前面是I2C设备驱动的框架,在这里,我们有时候需要把我们的

I2C设备当做一个字符设备去处理,例如 mpu6050

例如:

static int mpu6050_probe(struct i2c_client * client, const struct i2c_device_id * id)

{

//把I2C设备保存下来

dev.client = client;

printk(KERN_INFO "xj_match ok\n");

cdev_init(&dev.dev,&fops);

alloc_chrdev_region(&dev_no,DEV_MI,DEV_CNT,DEV_MAME);

cdev_add(&dev.dev,dev_no,DEV_CNT);

mpu6050_init(client);



/*自动创建设备文件*/

cls = class_create(THIS_MODULE,DEV_MAME);

device_create(cls,NULL,dev_no,NULL,"%s%d",DEV_MAME,DEV_MI);

printk(KERN_INFO "probe\n");

return 0;

}

 

 

i2c_client 的用处

我们在使用i2c_transfer 的时候需要用到 i2c_client

事实上,我们的 i2c_driver 只负责驱动,但是实际 I2C设备的相关信息都在 i2c_client 中

static char mpu6050_read_byte(struct i2c_client *client,const unsigned char reg)

{

char txbuf[1] = {reg};

char rxbuf[1] = {0};

struct i2c_msg msg[2] = {

[0] = {

.addr = client->addr,

.flags = W_FLG,

.len = sizeof(txbuf),

.buf = txbuf,

},

[1] = {

.addr = client->addr,

.flags = I2C_M_RD,

.len = sizeof(rxbuf),

.buf = rxbuf,

},

};



i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));

return rxbuf[0];

}