本文分析 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];
}