二、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到内核中
所以实现了上述的几个字段,然后调用函数i2c_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设备。
相关文章推荐
- lwn拾遗:[sn3218 led driver]-api解释-2
- lwn拾遗:[sn3218 led drivers]-api解释-1
- 新注册
- 四大漏洞入侵博客
- 在Ubuntu系统上安装Ghost博客平台的教程
- PHP多用户博客系统分析[想做多用户博客的朋友,需要了解]第1/3页
- 基于CakePHP实现的简单博客系统实例
- 基于jsp+servlet实现的简单博客系统实例(附源码)
- csdn 博客的css样式 v3
- 如何使用Gitblog和Markdown建自己的博客
- 利用JS生成博文目录及CSS定制博客
- Flask入门教程实例:搭建一个静态博客
- 让写博客成为一种习惯
- linux下的i2c与时钟芯片pcf8563通信
- 使用微信快捷登录Wordpress博客
- 博客之前在网易安家,现在迁移到了自己开发的blog http://blog.tongbor.com
- OpenAPI 之 开源软件信息预览 ProjectTips
- 自己对博客的计划
- 温度传感器+I2C+串口+PC上位机(pyserial)例子