Linux2.6.25平台下的I2C驱动架构分析【摘要】本文以PowerPC+Linux2.6.25平台为例,详细分析了I2C总线的驱动架构。首先介绍了I2C的总体架构,从用户的角度将其分为三个层面,不同的开发者只需要关注相应的层面即可。然后分析了主要数据结构及其之间的相互关系,接着分析了不同层的具体实现,最后以一款EEPEOM为例讲述了如何在用户空间访问I2C驱动。对于ARM+Linux平台,只有平台依赖层即总线适配器驱动有差异。【关键字】PowerPC,I2C,i2c-core,adapter,i2c_algorithm,RTC,EEPROM目录1I2C概述32I2C总体架构32.1硬件抽象层32.2平台依赖层32.3用户接口层33主要的数据结构43.1Adapter43.2I2c_algorithm53.3i2c_driver53.4Client64平台依赖层-总线适配器驱动74.1platformdevice74.2platformdriver94.3Adapter及algorithm125硬件抽象层-I2Ccore135.1总线初始化135.2Adapter注册155.3驱动注册165.4数据传输176用户接口层-I2C设备驱动186.1统一的设备模型186.1.1关键数据结构186.1.2初始化196.1.3Open及release216.1.4数据收发226.2特定的设备驱动266.2.1关键数据结构266.2.2初始化276.2.3数据收发297驱动访问示例297.1.1写操作297.1.2读操作318参考鸣谢331I2C概述I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL。I2C是一种多主机控制总线,同一总线上可允许多个master,即总线上的设备都有主动发起数据传输的可能,依靠线与逻辑来实现无损仲裁。但通常情况是总线上有个带CPU的master,其他设备被master访问。2I2C总体架构在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.1AdapterAdapter是对某一条I2C总线的抽象,是特定总线的相关属性的集合。{313structmodule*owner;314unsignedintid;315unsignedintclass;316conststructi2c_algorithm*algo;/*thealgorithmtoaccessthebus*/317void*algo_data;318319/*---administrationstuff.*/320int(*client_register)(structi2c_client*);321int(*client_unregister)(structi2c_client*);322323/*datafieldsthatarevalidforalldevices*/324u8level;/*nestinglevelforlockdep*/325structmutexbus_lock;//326structmutexclist_lock;327328inttimeout;329intretries;330structdevicedev;/*theadapterdevice*/331332intnr;/*该成员描述了总线号*/333structlist_headclients;/*i2c_client结构链表,该结构包含device,driver和adapter结构*/334charname[48];335structcompletiondev_released;336};Algo是和底层硬件的接口,标识了具体的物理总线传输的实现。Clients为使用该总线的client链表。Nr为该适配器也就是某条I2C总线占据的全局编号。bus_lock总线的互斥锁,防止总线冲突。3.2I2c_algorithm{292/*Ifanadapteralgorithmcan'tdoI2C-levelaccess,setmaster_xfer293toNULL.IfanadapteralgorithmcandoSMBusaccess,set294smbus_xfer.IfsettoNULL,theSMBusprotocolissimulated295usingcommonI2Cmessages*/296/*master_xfershouldreturnthenumberofmessagessuccessfully297processed,oranegativevalueonerror*/298int(*master_xfer)(structi2c_adapter*adap,structi2c_msg*msgs,299intnum);300int(*smbus_xfer)(structi2c_adapter*adap,u16addr,301unsignedshortflags,charread_write,302u8command,intsize,unioni2c_smbus_data*data);303304/*Todeterminewhattheadaptersupports*/305u32(*functionality)(structi2c_adapter*);306};主要就是master_xfer方法,其和具体的总线控制器相关,不同的CPU在实现上可能有差异。3.3i2c_driver{106intid;107unsignedintclass;108109/*Notifiesthedriverthatanewbushasappeared.Thisroutine110*canbeusedbythedrivertotestifthebusmeetsitsconditions111*&seekforthepresenceofthechip(s)itsupports.Iffound,it112*registerstheclient(s)thatareonthebustothei2cadmin.via113*i2c_attach_client.(LEGACYI2CDRIVERSONLY)114*/115int(*attach_adapter)(structi2c_adapter*);116int(*detach_adapter)(structi2c_adapter*);117118/*tellsthedriverthataclientisabouttobedeleted&givesit119*thechancetoremoveitsprivatedata.Also,iftheclientstruct120*hasbeendynamicallyallocatedbythedriverinthefunctionabove,121*itmustbefreedhere.(LEGACYI2CDRIVERSONLY)122*/123int(*detach_client)(structi2c_client*);124125/*Standarddrivermodelinterfaces,fornewstylei2cdrivers.126*Withthedrivermodel,deviceenumerationisNEVERdonebydrivers;127*it'sdonebyinfrastructure.(NEWSTYLEDRIVERSONLY)128*/129int(*probe)(structi2c_client*);130int(*remove)(structi2c_client*);131132/*drivermodelinterfacesthatdon'trelatetoenumeration*/133void(*shutdown)(structi2c_client*);134int(*suspend)(structi2c_client*,pm_message_tmesg);135int(*resume)(structi2c_client*);136137/*aioctllikecommandthatcanbeusedtoperformspecificfunctions138*withthedevice.139*/140int(*command)(structi2c_client*client,unsignedintcmd,void*arg);141142structdevice_driverdriver;143};Driver是为device服务的,i2c_driver注册时会扫描i2cbus上的设备,进行驱动和设备的绑定。主要有两种接口attach_adapter和probe,二者分别针对旧的和新式的驱动。3.4Client{169unsignedshortflags;/*div.,seebelow*/170unsignedshortaddr;/*chipaddress-NOTE:7bit*/171/*addressesarestoredinthe*/172/*_LOWER_7bits*/173charname[I2C_NAME_SIZE];174structi2c_adapter*adapter;/*theadapterwesiton*/175structi2c_driver*driver;/*andouraccessroutines*/176structdevicedev;/*thedevicestructure*/177intirq;/*irqissuedbydevice(or-1)*/178chardriver_name[KOBJ_NAME_LEN];179structlist_headlist;/*DEPRECATED*/180structcompletionreleased;181};通常来说i2c_client对应着I2C总线上某个特定的slave或者是userspace的某个用户对应,而此时的slave可以动态变化。4平台依赖层-总线适配器驱动总线适配器驱动,本质上就是实现了具体的总线传输算法并向核心层注册了适配器