您的位置:首页 > 运维架构 > Linux

二、Linux i2c adapter 驱动

2016-03-29 23:02 477 查看

1、概览

之前的博客中说过,
struct i2c_adapter
在i2c子系统中就代表了一个i2c控制器,也就是一条i2c总线。其实实现i2c总线或控制器驱动,其实就是实现一个struct i2c_adapter结构以及结构中的与平台相关的发送数据的接口,这些接口涉及到操作具体的寄存器。下面简单看一下struct i2c_adapter这个结构。

struct i2c_adapter {
struct module *owner;
unsigned int class;
const struct i2c_algorithm *algo;
struct rt_mutexbus_lock;
int timeout;
int retries;
struct device dev;
int nr;
char name[48];
struct completion dev_released;
struct mutex userspace_client_lock;
struct list_head userspace_clients;
struct i2c_bus_recovery_info *bus_recovery_info;
};


2、struct i2c_adapter中各个字段的含义

2.1) algo:

驱动作者需要实现这个字段中的接口,主要是传输数据的接口。

struct i2c_algorithm {
int (*master_xfer) (struct i2c_adapter *adap, struct i2c_msg *msg, intnum);
int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, unsigned long flags, char read_write,
u8 command, int size, union i2c_bus_data *data);
u32 (*functionality) (struct i2c_adapter *);
}


其中
master_xfer()
是i2c协议的发送和接收数据的接口,
smbus_xfer()
是smbus协议的传输数据的接口。而
functionality()
是检查该i2c总线支持的功能。这里面的接口在实现i2c client驱动的时候会间接的用到。

2.2)timeout和retries

timeout指的是传输数据的时间限制,超过这个时间就认为传输数据失败。

retries字段记录的是当传输数据失败重试的次数。

3、注册struct i2c_adapter到内核中

所以实现了上述的几个字段,然后调用函数i
2c_add_adapter()
i2c_add_numbered_adapter()
就可以将这个i2c总线注册到i2c子系统中了。

下面来看看s3c24xx系列cpu的i2c总线的驱动是如何实现的。首先i2c控制器是个平台设备,所以驱动从注册平台设备开始。

static struct platform_driver s3c24xx_i2c_driver = {
.probe   = s3c24xx_i2c_probe,
.remove  = s3c24xx_i2c_remove,
.driver = {
.owner  = THIS_MODULE,
.name   = "s3c-i2c",
.pm=S3C24XX_DEV_PM_OPS,
},
};

static int __init i2c_adap_s3c_init(void)
{
return platform_driver_register(&s3c24xx_i2c_driver);
}
subsys_initcall(i2c_adap_s3c_init);

static void __exit i2c_adap_s3c_exit(void)
{
platform_driver_unregister(&s3c24xx_i2c_driver);
}
module_exit(i2c_adap_s3c_exit);


struct i2c_adapter
这个结构是在平台驱动probe的过程中被创建和注册的。

下面看看
s3c24xx_i2c_probe()
这个函数。

首先是
struct s3c24xx_i2c
这个结构,这个结构中包含很多平台相关的信息,不过最主要的还是包含了
struct i2c_adapter adap


struct s3c24xx_i2c {
…...
struct i2c_msg          *msg;
……
struct i2c_adapter      adap;
……
};


probe()
函数中的第一步就是构建
structs3c24xx_i2c
结构的一个变量。然后接下来就是设置
struct s3c24xx_i2c
的内嵌结构
adap
的相关字段。

/* 设置adapter的名字*/
strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
i2c->adap.owner   = THIS_MODULE;
/* 设置algo字段,主要包含传输数据的算法*/
i2c->adap.algo    = &s3c24xx_i2c_algorithm;
/* 发送失败重试次数*/
i2c->adap.retries = 2;
/* 何种类型的i2c, 主要说明这个接口的用途*/
i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;


/*然后是设置总线的编号和device tree node的一些信息*/
i2c->adap.nr = i2c->pdata->bus_num;
i2c->adap.dev.of_node = pdev->dev.of_node;


最后一步就是注册这个
struct i2c_adapter
的这个结构到i2c子系统中:

ret = i2c_add_numbered_adapter(&i2c->adap);


其实到这一步,整个i2c adapter的驱动就已经完成了。不过为了兼容现在device tree,最后还调用了
of_i2c_register_devices()
函数将连接在该i2c_adapter上的设备注册到系统中。以前的做法是在平台的代码中注册i2c_board_info结构。关于这两种方法注册i2c设备,将在下篇博客中详细讲解。

4、总结

下面来总结一下写一个i2c控制器的驱动大致需要的步骤:

1、 编写与i2c控制器相关的平台驱动(struct platform_driver),这一步不是必须的,但是通用的做法是这样的;

2、 在平台驱动的probe()函数中构建struct i2c_adapter结构,可以使直接创建这个结构,也可以将这个结构内嵌到一个表示某个平台的i2c控制器的一个结构体中。

3、 实现struct i2c_algorithm中的传输数据的函数和functionality()函数;

4、 设置struct i2c_adapter结构的一些信息,包括.algo、.retries、.class等;

5、 注册struct i2c_adapter结构到i2c子系统中;

6、 如果要支持device tree那么就要调用of_i2c_register_devices()注册连接在该总线上的i2c设备。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Linux-驱动 i2c 博客