




已阅读5页,还剩26页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Linux2.6.25平台下的I2C驱动架构分析【摘要】本文以PowerPC+Linux 2.6.25 平台为例,详细分析了I2C总线的驱动架构。首先介绍了I2C的总体架构,从用户的角度将其分为三个层面,不同的开发者只需要关注相应的层面即可。然后分析了主要数据结构及其之间的相互关系,接着分析了不同层的具体实现,最后以一款EEPEOM为例讲述了如何在用户空间访问I2C驱动。对于ARM + Linux平台,只有平台依赖层即总线适配器驱动有差异。【关键字】PowerPC, I2C, i2c-core, adapter , i2c_algorithm, RTC, EEPROM目录1 I2C概述 32 I2C总体架构 32.1 硬件抽象层 32.2 平台依赖层 32.3 用户接口层 33 主要的数据结构 43.1 Adapter 43.2 I2c_algorithm 53.3 i2c_driver 53.4 Client 64 平台依赖层-总线适配器驱动 74.1 platform device 74.2 platform driver 94.3 Adapter及algorithm 125 硬件抽象层-I2C core 135.1 总线初始化 135.2 Adapter注册 155.3 驱动注册 165.4 数据传输 176 用户接口层-I2C设备驱动 186.1 统一的设备模型 186.1.1 关键数据结构 186.1.2 初始化 196.1.3 Open及release 216.1.4 数据收发 226.2 特定的设备驱动 266.2.1 关键数据结构 266.2.2 初始化 276.2.3 数据收发 297 驱动访问示例 297.1.1 写操作 297.1.2 读操作 318 参考鸣谢 33 1 I2C概述I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL。I2C是一种多主机控制总线,同一总线上可允许多个master,即总线上的设备都有主动发起数据传输的可能,依靠线与逻辑来实现无损仲裁。但通常情况是总线上有个带CPU的master,其他设备被master访问。2 I2C总体架构在2.6的Linux内核中,I2C的驱动架构分为如下三个层次:硬件抽象层、平台依赖层和用户接口层。2.1 硬件抽象层i2c-core.h和i2c-core.c为其主体框架代码,提供了核心数据结构的定义、i2c适配器驱动和设备驱动的注册、注销管理等API。其为硬件平台无关层,向下屏蔽了物理总线适配器的差异,定义了统一的访问策略和接口;其向上提供了统一的接口,以便I2C设备驱动通过总线适配器进行数据收发。2.2 平台依赖层i2c总线适配器(adapter)就是一条i2c总线的控制器(所谓控制是相对于本CPU来说的),在物理上连接若干i2c设备。在Linux驱动中,每种处理器平台有自己的适配器驱动,属于平台移植相关层。每一个特定的硬件平台在i2c/busses/目录下都有一个adapter的实现,对于PowerPC平台来说,其是i2c-mpc.c。其按照核心层定义的接口实现了i2c_adapter,提供了具体的访问方式i2c_algorithm。2.3 用户接口层设备驱动层为用户接口层,其为用户提供了通过I2C总线访问具体设备的接口。 3 主要的数据结构3.1 AdapterAdapter是对某一条I2C总线的抽象,是特定总线的相关属性的集合。http:/lxr.linux.no/#linux+v2.6.25/include/linux/i2c.h#L312 312struct i2c_adapter 313 struct module *owner; 314 unsigned int id; 315 unsigned int class; 316 const struct i2c_algorithm *algo; /* the algorithm to access the bus */ 317 void *algo_data; 318 319 /* - administration stuff. */ 320 int (*client_register)(struct i2c_client *); 321 int (*client_unregister)(struct i2c_client *); 322 323 /* data fields that are valid for all devices */ 324 u8 level; /* nesting level for lockdep */ 325 struct mutex bus_lock; / 326 struct mutex clist_lock; 327 328 int timeout; 329 int retries; 330 struct device dev; /* the adapter device */ 331 332 int nr; /*该成员描述了总线号*/ 333 struct list_head clients; /* i2c_client结构链表,该结构包含device,driver和 adapter结构*/ 334 char name48; 335 struct completion dev_released; 336; Algo是和底层硬件的接口,标识了具体的物理总线传输的实现。Clients为使用该总线的client链表。Nr为该适配器也就是某条I2C总线占据的全局编号。bus_lock总线的互斥锁,防止总线冲突。3.2 I2c_algorithmhttp:/lxr.linux.no/#linux+v2.6.25/include/linux/i2c.h#L291291struct i2c_algorithm 292 /* If an adapter algorithm cant do I2C-level access, set master_xfer 293 to NULL. If an adapter algorithm can do SMBus access, set 294 smbus_xfer. If set to NULL, the SMBus protocol is simulated 295 using common I2C messages */ 296 /* master_xfer should return the number of messages successfully 297 processed, or a negative value on error */ 298 int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs, 299 int num); 300 int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, 301 unsigned short flags, char read_write, 302 u8 command, int size, union i2c_smbus_data * data); 303 304 /* To determine what the adapter supports */ 305 u32 (*functionality) (struct i2c_adapter *); 306;主要就是master_xfer方法,其和具体的总线控制器相关,不同的CPU在实现上可能有差异。3.3 i2c_driverhttp:/lxr.linux.no/#linux+v2.6.25/include/linux/i2c.h#L105105struct i2c_driver 106 int id; 107 unsigned int class; 108 109 /* Notifies the driver that a new bus has appeared. This routine 110 * can be used by the driver to test if the bus meets its conditions 111 * & seek for the presence of the chip(s) it supports. If found, it 112 * registers the client(s) that are on the bus to the i2c admin. via 113 * i2c_attach_client. (LEGACY I2C DRIVERS ONLY) 114 */ 115 int (*attach_adapter)(struct i2c_adapter *); 116 int (*detach_adapter)(struct i2c_adapter *); 117 118 /* tells the driver that a client is about to be deleted & gives it 119 * the chance to remove its private data. Also, if the client struct 120 * has been dynamically allocated by the driver in the function above, 121 * it must be freed here. (LEGACY I2C DRIVERS ONLY) 122 */ 123 int (*detach_client)(struct i2c_client *); 124 125 /* Standard driver model interfaces, for new style i2c drivers. 126 * With the driver model, device enumeration is NEVER done by drivers; 127 * its done by infrastructure. (NEW STYLE DRIVERS ONLY) 128 */ 129 int (*probe)(struct i2c_client *); 130 int (*remove)(struct i2c_client *); 131 132 /* driver model interfaces that dont relate to enumeration */ 133 void (*shutdown)(struct i2c_client *); 134 int (*suspend)(struct i2c_client *, pm_message_t mesg); 135 int (*resume)(struct i2c_client *); 136 137 /* a ioctl like command that can be used to perform specific functions 138 * with the device. 139 */ 140 int (*command)(struct i2c_client *client,unsigned int cmd, void *arg); 141 142 struct device_driver driver; 143;Driver是为device服务的,i2c_driver注册时会扫描i2c bus上的设备,进行驱动和设备的绑定。主要有两种接口attach_adapter和probe,二者分别针对旧的和新式的驱动。3.4 Clienthttp:/lxr.linux.no/#linux+v2.6.25/include/linux/i2c.h#L168168struct i2c_client 169 unsigned short flags; /* div., see below */ 170 unsigned short addr; /* chip address - NOTE: 7bit */ 171 /* addresses are stored in the */ 172 /* _LOWER_ 7 bits */ 173 char nameI2C_NAME_SIZE; 174 struct i2c_adapter *adapter; /* the adapter we sit on */ 175 struct i2c_driver *driver; /* and our access routines */ 176 struct device dev; /* the device structure */ 177 int irq; /* irq issued by device (or -1) */ 178 char driver_nameKOBJ_NAME_LEN; 179 struct list_head list; /* DEPRECATED */ 180 struct completion released; 181;通常来说i2c_client对应着I2C总线上某个特定的slave或者是user space的某个用户对应,而此时的slave可以动态变化。4 平台依赖层-总线适配器驱动总线适配器驱动,本质上就是实现了具体的总线传输算法并向核心层注册了适配器。主要分为三个层面,platform device,platform driver及与I2C core的接口层。Linux内核的所有适配器驱动程序都在driver/i2c/busses/目录下, MPC8xxx驱动是i2c-mpc.c。4.1 platform device2.6内核中硬件资源的注册都采用了platform device的机制。对于PowerPC来说,其硬件资源是通过DTS来描述的。i2c3000 #address-cells = ; #size-cells = ; cell-index = ; compatible = fsl-i2c; reg = ; interrupts = ; interrupt-parent = ; dfsrr;i2c3100 #address-cells = ; #size-cells = ; cell-index = ; compatible = fsl-i2c; reg = ; interrupts = ; interrupt-parent = ; dfsrr; rtc51 /legacy I2C device,静态定义 device_type = rtc; compatible = Philips,8563; /设备类型 reg = ; /I2C地址 ;中断号及寄存器的基地址等信息会在设备树中描述了,此后只需利用platform_get_resource等标准接口自动获取即可,实现了驱动和资源的分离。cell-index标识了总线编号,也就是adapter的编号。随后在系统启动阶段会解析DTB文件,将相关资源注册到Platform bus上。http:/lxr.linux.no/#linux+v2.6.25/arch/powerpc/sysdev/fsl_soc.c#L454458static int _init fsl_i2c_of_init(void) 501 of_register_i2c_devices(np, i+); 429static void _init of_register_i2c_devices(struct device_node *adap_node, 430 int bus_num) 431 432 struct device_node *node = NULL; 433 434 while (node = of_get_next_child(adap_node, node) 435 struct i2c_board_info info = ; 436 const u32 *addr; 437 int len; 438 439 addr = of_get_property(node, reg, &len); 440 if (!addr | len (1 10) - 1) 441 printk(KERN_WARNING fsl_soc.c: invalid i2c device entryn); 442 continue; 443 444 445 info.irq = irq_of_parse_and_map(node, 0); 446 if (info.irq = NO_IRQ) 447 info.irq = -1; 448 449 if (of_find_i2c_driver(node, &info) 0) 450 continue; 451 452 info.addr = *addr; 453 454 i2c_register_board_info(bus_num, &info, 1); 455 456 397static struct i2c_driver_device i2c_devices _initdata = 398 ricoh,rs5c372a, rtc-rs5c372, rs5c372a, 399 ricoh,rs5c372b, rtc-rs5c372, rs5c372b, 400 ricoh,rv5c386, rtc-rs5c372, rv5c386, 401 ricoh,rv5c387a, rtc-rs5c372, rv5c387a, 402 dallas,ds1307, rtc-ds1307, ds1307, 403 dallas,ds1337, rtc-ds1307, ds1337, 404 dallas,ds1338, rtc-ds1307, ds1338, 405 dallas,ds1339, rtc-ds1307, ds1339, 406 dallas,ds1340, rtc-ds1307, ds1340, 407 stm,m41t00, rtc-ds1307, m41t00, 408 dallas,ds1374, rtc-ds1374, rtc-ds1374, 409; 410在i2c_devices列表里描述了那些采用传统的I2C驱动的设备列表。同时DTS文件中也需要描述,二者会利用of_find_i2c_driver进行匹配。 411static int _init of_find_i2c_driver(struct device_node *node, 412 struct i2c_board_info *info) 413 414 int i; 415 416 for (i = 0; i driver_name, i2c_devicesi.i2c_driver, 420 KOBJ_NAME_LEN) = KOBJ_NAME_LEN | 421 strlcpy(info-type, i2c_devicesi.i2c_type, 422 I2C_NAME_SIZE) = I2C_NAME_SIZE) 423 return -ENOMEM; 424 return 0; 425 426 return -ENODEV; 4274.2 platform driver394 395/* Structure for a device driver */ 396static struct platform_driver fsl_i2c_driver = 397 .probe = fsl_i2c_probe, 398 .remove = fsl_i2c_remove, 399 .driver = 400 .owner = THIS_MODULE, 401 .name = fsl-i2c, /匹配因子 402 , 403; 404 405static int _init fsl_i2c_init(void) 406 407 return platform_driver_register(&fsl_i2c_driver); 408 409 410static void _exit fsl_i2c_exit(void) 411 412 platform_driver_unregister(&fsl_i2c_driver); 413 414 415module_init(fsl_i2c_init); 416module_exit(fsl_i2c_exit);fsl_i2c_driver注册时会扫描platform bus上的所有设备,匹配因子是fsl-i2c,匹配成功后调用fsl_i2c_probe将设备和驱动绑定起来,具体过程参加详解Linux2.6内核中基于platform机制的驱动模型,随后向系统注册一个adapter。/sailor_8318/archive/2010/01/29/5267698.aspx318static int fsl_i2c_probe(struct platform_device *pdev) 319 320 int result = 0; 321 struct mpc_i2c *i2c; 322 struct fsl_i2c_platform_data *pdata; 323 struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 324 325 pdata = (struct fsl_i2c_platform_data *) pdev-dev.platform_data; 326 327 i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); 328 if (!i2c) 329 return -ENOMEM; 330 331 i2c-irq = platform_get_irq(pdev, 0); 332 if (i2c-irq flags = pdata-device_flags; 337 init_waitqueue_head(&i2c-queue); 338 339 i2c-base = ioremap(phys_addr_t)r-start, MPC_I2C_REGION); 340 341 if (!i2c-base) 342 printk(KERN_ERR i2c-mpc - failed to map controllern); 343 result = -ENOMEM; 344 goto fail_map; 345 346 347 if (i2c-irq != 0) 348 if (result = request_irq(i2c-irq, mpc_i2c_isr, 349 IRQF_SHARED, i2c-mpc, i2c) adap = mpc_ops; 359 i2c-adap.nr = pdev-id; 360 i2c_set_adapdata(&i2c-adap, i2c); 361 i2c-adap.dev.parent = &pdev-dev; 362 if (result = i2c_add_numbered_adapter(&i2c-adap) irq != 0) 371 free_irq(i2c-irq, i2c); 372 fail_irq: 373 iounmap(i2c-base); 374 fail_map: 375 fail_get_irq: 376 kfree(i2c); 377 return result; 378; 379 380static int fsl_i2c_remove(struct platform_device *pdev) 381 382 struct mpc_i2c *i2c = platform_get_drvdata(pdev); 383 384 i2c_del_adapter(&i2c-adap); 385 platform_set_drvdata(pdev, NULL); 386 387 if (i2c-irq != 0) 388 free_irq(i2c-irq, i2c); 389 390 iounmap(i2c-base); 391 kfree(i2c); 392 return 0; 393;pdev-id为platform data中的devid,为I2C的总线编号,其在设备树文件中描述。PowerPC的adapter驱动使用了i2c_add_numbered_adapter()注册,总线号最初保存在 platform_data中。4.3 Adapter及algorithm这一层主要是定义了关键的数据结构adapter和algorithm。http:/lxr.linux.no/#linux+v2.6.25/drivers/i2c/busses/i2c-mpc.c#L309309static struct i2c_adapter mpc_ops = 310 .owner = THIS_MODULE, 311 .name = MPC adapter, 312 .id = I2C_HW_MPC107, 313 .algo = &mpc_algo, 314 .class = I2C_CLASS_HWMON, 315 .timeout = 1, 316;304static const struct i2c_algorithm mpc_algo = 305 .master_xfer = mpc_xfer, 306 .functionality = mpc_functionality, 307; 308http:/lxr.linux.no/#linux+v2.6.25/drivers/i2c/busses/i2c-mpc.c#L256256static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 257 258 struct i2c_msg *pmsg; 259 int i; 260 int ret = 0; 261 unsigned long orig_jiffies = jiffies; 262 struct mpc_i2c *i2c = i2c_get_adapdata(adap); 263 264 mpc_i2c_start(i2c); 265 266 /* Allow bus up to 1s to become not busy */ /一定程度上避免总线冲突,收发数据前先查询总线状态 267 while (readb(i2c-base + MPC_I2C_SR) & CSR_MBB) 268 if (signal_pending(current) 269 p
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 机械设计试题及答案
- 郑州叉车考试试题及答案
- 2025年广汉市市直机关遴选考试笔试试题(含答案)
- 2025年大理州永平县博南镇卫生院岗招聘考试笔试试题(含答案)
- 2025宪法知识竞赛培训试题(含答案)
- 北京物业专业知识培训课件
- 手术室n1护士所有考试试题及答案
- 树枝花艺基础知识培训课件
- 2024年职业技能鉴定:信号司索工竞赛题库(附含答案)
- 2024下半年普安县事业单位招聘考试《审计基础知识》试题及答案
- 车辆竣工检验管理制度
- 脑出血知识讲课课件
- 教育行业合同管理风险及防范措施
- 民宿经营申请书模板
- 医院感染的病原体与传播途径
- 临床检验室间质评
- 《慢性肾脏病(CKD)的诊断与治疗》课件
- 中国红外瞄准镜行业分析报告:市场规模、供需态势、竞争格局及投融资动态分析报告
- 美团配送员岗前培训
- 人教版九年级全一册英语Unit 1~14各单元话题作文与范文
- 跨境电商跨境电商跨境电商物流清关手册
评论
0/150
提交评论