资源描述
目录
声明
你可以自由地随意修改本文档的任何文字内容及图表,但是如果你在自己的文档中以任何形式直接引用了本文档的任何原有文字或图表并希望发布你的文档,那么你也得保证让所有得到你的文档的人同时享有你曾经享有过的权利。
i2c源代码情景分析(Beta2)
作者在上的ID为shrek2
欢迎补充,欢迎批评指正!
第1章 i2c核心数据结构之间的关系 4
第2章 i2c-core.c的初始化 10
i2c_init函数 10
i2cproc_init函数 11
第3章 安装、卸载pxa255的i2c适配器驱动程序 13
pxa_i2c数据结构 13
i2c_adap_pxa_init函数 15
i2c_add_adapter函数 16
i2c_del_adapter函数 18
i2c_adap_pxa_exit函数 20
第4章 安装、卸载ltc3445驱动程序 21
ltc3445_init函数 21
i2c_add_driver函数 22
i2c_probe函数 23
i2c_check_functionality函数 26
i2c_smbus_xfer函数 27
i2c_transfer函数 29
ltc3445_detect_client函数 30
i2c_attach_client函数 31
ltc3445_cleanup函数 32
i2c_del_driver函数 33
ltc3445_detach_client函数 35
i2c_detach_client函数 35
第5章 与pxa255的i2c适配器相关的代码 37
i2c_pxa_reset函数 37
i2c_pxa_abort函数 38
i2c_pxa_xfer函数 38
i2c_pxa_do_xfer函数 39
i2c_pxa_start_message函数 41
i2c_pxa_handler函数 42
i2c_pxa_irq_txempty函数 42
i2c_pxa_irq_rxfull函数 47
第6章 i2c-dev的初始化 49
i2c_dev_init函数 49
i2cdev_attach_adapter函数 50
第7章 i2c框架提供的设备访问方法 52
i2cdev_open函数 52
i2cdev_ioctl函数 53
i2cdev_read函数 54
i2c_master_recv函数 55
对i2cdev_read和i2c_master_recv的修改 56
i2cdev_release函数 59
第8章 编写i2c设备驱动程序模块的方法 61
第9章 用户进程访问i2c设备的步骤 64
讨论和总结 65
i2c操作中的同步问题 65
总结各个模块初始化函数的作用 65
对i2c框架代码的修改 66
有关i2c设备私有数据结构的讨论 68
遗留的问题 68
(注意:本文档中的源代码以i2c-2.9.1包及www.arm.linux.org.uk上下载的pxa的i2c适配器的补丁2360-2为准!)
67
第1章 i2c核心数据结构之间的关系
第1章 i2c核心数据结构之间的关系
i2c总线适配器(adapter)就是一条i2c总线的控制器,在物理连接上若干i2c设备并联于该i2c总线的SCL和SDA线上,如下图所示:
SDA
pxa255 I2C
LTC3445
other device
SCL
那么相应软件数据结构的设计、数据结构之间的关系就至少应该描述硬件物理连接的这种组织关系。Linux的i2c框架中各个部分的关系如下图所示:
内核中i2c相关代码可以分为三个层次:
1. i2c框架:i2c.h和i2c-core.c为i2c框架的主体,提供了核心数据结构的定义、i2c适配器驱动和设备驱动的注册、注销管理,i2c通信方法上层的、与具体适配器无关的代码、检测设备地址的上层代码等;i2c-dev.c用于创建i2c适配器的/dev/i2c/%d设备节点,提供i2c设备访问方法等。
2. i2c总线适配器驱动:定义描述具体i2c总线适配器的i2c_adapter数据结构、实现在具体i2c适配器上的i2c总线通信方法,并由i2c_algorithm数据结构进行描述。
3. i2c设备驱动:定义描述具体设备的i2c_client和可能的私有数据结构、借助i2c框架的i2c_probe函数实现注册设备的attach_adapter方法、提供设备可能使用的地址范围、以及设备地址检测成功后创建i2c_client数据结构的回调函数。
下面介绍i2c各核心数据结构的定义和它们之间的连接关系。
1. 一个i2c设备的驱动程序由i2c_driver数据结构描述,定义于include/linux/i2c.h:
struct i2c_driver {
char name[32];
int id;
unsigned int flags;
int (*attach_adapter)(struct i2c_adapter *);
int (*detach_client)(struct i2c_client *);
int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);
void (*inc_use)(struct i2c_client *client);
void (*dec_use)(struct i2c_client *client);
};
其中name为最大长度为32字节的字符串,id可选0xf000到0xffff中的任一数值,flags域可以直接设置为I2C_DF_NOTIFY。attach_adapter回调函数在安装i2c设备驱动程序模块时、或者在安装i2c适配器驱动程序模块时被调用,用于检测、认领设备并为设备分配i2c_client数据结构。detach_client方法在卸载适配器或设备驱动程序模块时被调用,用于从总线上注销设备、并释放i2c_client及相应的私有数据结构。
inc_use和dec_use所指向的函数用于改变i2c设备驱动程序模块的引用计数。注意不要直接调用i2c_driver数据结构中的这两个方法,而要通过如下函数调用路径:
i2c_use_client > i2c_inc_use_client > inc_use
i2c_release_client > i2c_dec_use_client > dec_use
通过最顶层的i2c_use/release_client函数来同时改变i2c设备和i2c适配器驱动程序模块的引用计数。另外,不能在attach_adapter函数检测到一个i2c设备时就增加驱动程序模块的引用计数,而应该在用户进程访问一个/dev/i2c/%d设备节点时增加模块的引用计数,则关闭设备节点时减少引用计数(但在当前的应用中,适配器和设备的驱动程序都是静态地链接入内核映像的,所以在pxa255的i2c补丁中并没有使用控制引用计数的函数)。
2. 一个i2c设备由i2c_client数据结构进行描述:
struct i2c_client {
char name[32];
int id;
unsigned int flags; /* div., see below */
unsigned int addr; /* chip address - NOTE: 7bit addresses are stored in the */
/* _LOWER_ 7 bits of this char */
struct i2c_adapter *adapter; /* the adapter we sit on */
struct i2c_driver *driver; /* and our access routines */
void *data; /* for the clients */
int usage_count; /* How many accesses currently to the client */
};
在安装适配器或者设备的驱动程序时通过设备驱动程序i2c_driver中的attach_adapter函数检测设备地址。如果检测成功则调用设备驱动程序提供的回调函数创建描述设备的i2c_client数据结构,并将其中的driver指针指向设备驱动程序的i2c_driver数据结构。这样将来就可以使用i2c_driver中的注销设备和控制引用计数的方法了。
由下文可见在描述i2c适配器的i2c_adapter数据结构中设计了指向该总线上所有i2c设备的i2c_client数据结构的指针数组clients,而每个i2c_client又通过adapter指针回指i2c_adapter。数据结构之间类似的组织关系在Linux内核中屡见不鲜,比如父子进程的PCB之间、父目录及子目录和子文件的dentry之间,等等。
每个i2c设备都有唯一的7位地址addr。由于设备可能支持多个地址,所以在设备驱动程序模块中要指出需要检测的地址范围(由i2c_client_address_data二维数组指定),而设备实际使用的地址在检测成功并为之分配i2c_client数据结构时填入。以i2c设备ltc3445为例,硬件支持的地址为1001011或者0101011,即7位地址的高2位由具体的布线方法决定(可以分别接到VCC或者GND)。如果ltc3445驱动程序的开发者知道具体的布线方法,那么在驱动程序中就可以直接指定。否则可以指定地址检测范围为这两个地址,而在加载驱动程序模块时由软件进行地址检测。
需要说明的是,i2c设备的7位地址是就当前i2c总线而言的,是“相对地址”。不同的i2c总线上的设备可以使用相同的7位地址,但是它们所在的i2c总线不同。所以在系统中一个i2c设备的“绝对地址”由二元组(i2c适配器的ID和设备在该总线上的7位地址)表示。
i2c_client数据结构为描述i2c设备的“模板”,而具体的i2c设备可能需要描述个性的私有数据。私有数据结构由i2c_client数据结构中的data域指向。设备驱动程序开发者可以设计合适的私有数据结构来描述硬件的特性。值得一提的是,目前在Linux内核中常用的表示与具体设备、对象等相关的私有数据结构的方法有两种,一种就是采用void类型的指针data来指向具体的私有数据结构,又比如file结构中的private_data域在设备驱动程序中往往被设置为指向具体的设备数据结构;第二种方法就是采用union域,比如VFS的super_block、inode数据结构。super_block和inode数据结构本身集中描述了各种文件系统的共性,而具体文件系统的个性则放到union中进行描述,在挂载具体的文件系统时实例化为具体的union对象,比如ext2_inode_union或者jffs2_inode_info。
有关设计私有数据的的讨论可参见本文末尾的讨论部分。
当不同进程访问同一i2c总线时,对i2c总线的互斥访问由i2c_adapter的lock信号量实现,系统调用执行流只有在获得该信号量期间才能调用master_xfer,并且在阻塞期间不释放信号量(类似在读写正规文件期间必须持有inode.i_sem,参见本文末尾的讨论部分)。而usage_count域为设备的使用引用计数,在i2c_use_client和i2c_release_client函数中控制usage_count域的值(但是当前pxa255的i2c补丁中并没有使用这两个函数,usage_count的值自初始化后就一直为0)。
3. 一个i2c适配器由i2c_adapter数据结构描述:
struct i2c_adapter {
char name[32];
unsigned int id; /* == is algo->id | hwdep.struct->id, for registered values see below */
struct i2c_algorithm *algo; /* the algorithm to access the bus */
void *algo_data;
void (*inc_use)(struct i2c_adapter *);
void (*dec_use)(struct i2c_adapter *);
int (*client_register)(struct i2c_client *);
int (*client_unregister)(struct i2c_client *);
void *data; /* private data for the adapter */
struct semaphore lock;
unsigned int flags; /* flags specifying div. data */
struct i2c_client *clients[I2C_CLIENT_MAX];
int client_count;
int timeout;
int retries;
#ifdef CONFIG_PROC_FS
/* No need to set this when you initialize the adapter */
int inode;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,29)
struct proc_dir_entry *proc_entry;
#endif
#endif /* def CONFIG_PROC_FS */
};
在i2c_adapter数据结构中设计了clients指针数组,指向该总线上每个设备的i2c_client数据结构。由于一条i2c总线上最多只有I2C_CLENT_MAX个设备,所以可以使用静态数组(题外话,如果相关数据结构的个数是未知的,链表显然是更好的选择)。lock信号量用于实现对i2c总线的互斥访问:在访问i2c总线上的任一设备期间当前进程必须首先获得该信号量,并且在阻塞等待i2c操作完成期间不释放。
一个i2c适配器上的i2c总线通信方法由其驱动程序提供的i2c_algorithm数据结构描述,由algo指针指向。i2c_algorithm数据结构即为i2c_adapter数据结构与具体i2c适配器的总线通信方法的中间层,由下文可见正是这个中间层使得上层的i2c框架代码与与具体i2c适配器的总线通信方法无关,从而实现了i2c框架的可移植性和重用性。当安装具体i2c适配器的驱动程序时由相应驱动程序实现具体的i2c_algorithm数据结构,其中的函数指针指向操作具体i2c适配器的代码(换用面向对象的语言,就是当创建子类对象时将基类中定义的函数调用接口实例化为与具体子类相关的代码。值得说明的是,在Linux内核层次中数据结构的设计大量地采用了面向对象的概念来实现框架的可移植性和重用性)。
inc_use和dec_use方法可以用来控制适配器驱动程序的引用计数;client_register和client_unregister函数可以用来完成适配器端的、额外的设备注册和注销工作。这些函数在当前pxa255的i2c补丁中都没有实现。最后timeout和retries用于超时重传机制。
4. 具体i2c适配器的通信方法由i2c_algorithm数据结构进行描述:
struct i2c_algorithm {
char name[32]; /* textual description */
unsigned int id;
int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg msgs[], int num);
int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data * data);
int (*slave_send)(struct i2c_adapter *,char*,int);
int (*slave_recv)(struct i2c_adapter *,char*,int);
int (*algo_control)(struct i2c_adapter *, unsigned int, unsigned long);
u32 (*functionality) (struct i2c_adapter *);
};
master_xfer/smbus_xfer指针指向i2c适配器驱动程序模块实现的i2c通信协议或者smbus通信协议。由下文分析可见在用户进程通过i2c-dev提供的/dev/i2c/%d设备节点访问i2c设备时,最终是通过调用master_xfer或者smbus_xfer指向的方法完成的。
slave_send/recv函数用于实现当i2c适配器扮演slave角色时的传输方法。由于在pxa255的现有应用中其i2c适配器始终为主导i2c通信的master,故补丁中这两个函数都没有实现。
i2c_algorithm提供了i2c适配器的驱动,而i2c设备的驱动为i2c_driver。内核中静态指针数组adapters和drivers分别记录所有已经注册的i2c总线设备和i2c设备驱动。从下文源代码分析可以看到,安装i2c总线驱动和i2c设备驱动的顺序不确定,因此在安装i2c设备驱动时必须遍历所有已注册的适配器上的i2c设备,以“认领”相应的设备;同理,在安装i2c适配器驱动时必须遍历所有已注册的i2c设备的驱动程序,让已有驱动程序“认领”新注册的适配器上的所有设备。
5. 假设一条i2c总线上有两个使用相同驱动程序的i2c设备,在打开该i2c总线的设备结点后相关数据结构之间的逻辑组织关系如下图所示。在阅读下文时请经常参照下图。
上层的i2c框架实现了控制策略,具体i2c适配器和设备的驱动实现了使具体设备可用的机制,上层策略和底层机制通过中间的函数调用接口联系。正是中间的函数调用接口使得上层策略与底层机制无关,从而使得上层策略具有良好的可移植性和重用性。阅读完全文后可以回过头来总结一下各数据结构的作用、创建时机、由谁创建等,品味这一点是如何通过这些数据结构实现的,进一步在自己的研发过程中积极实践这种思想并享受学以致用的乐趣:)
i2c_msg
i2c_algorithm
name
id
master_xfer
smbus_xfer
……
algo_control
functionality
name
id
flags
attach_adapter
detach_client
command
inc_use
dec_use
i2c_driver
name
id
flags
addr
adapter
driver
data
usage_count
i2c_client
name
id
flags
addr
adapter
driver
data
usage_count
i2c_client
lock
wait
msg
msg_num
msg_idx
msg_ptr
……
name
id
algo_data
algo
inc_use
dec_use
client_register
client_unregister
data
lock
flags
client_count
timeout
retries
clients
pxa_i2c
addr
flags
len
buf
i2c_pxa_xfer
ltc3445_attach_adapter
……
addr
adapter
driver
……
i2c_client
ltc3445_detach_adapter
adapters[ ]
drivers[ ]
file
……
f_op
private_data
i2cdev_open
i2cdev_read
i2cdev_write
i2cdev_ioctl
i2cdev_fops
第2章 i2c-core.c的初始化
第2章 i2c-core.c的初始化
i2c-core.c提供了i2c框架的主体代码,包括i2c适配器驱动和设备驱动的注册、注销管理的框架代码、i2c通信方法的上层、与具体适配器无关的代码和检测设备地址的上层代码等。
i2c_init函数
i2c-core模块的初始化函数如下:
static int __init i2c_init(void)
{
printk(KERN_DEBUG "i2c-core.o: i2c core module\n");
memset(adapters,0,sizeof(adapters));
memset(drivers,0,sizeof(drivers));
adap_count=0;
driver_count=0;
init_MUTEX(&adap_lock);
init_MUTEX(&driver_lock);
在i2c-core.c中定义了内核静态指针数组adapters和drivers,用于注册描述i2c适配器及其驱动程序的i2c_adapter数据结构和描述设备及其驱动程序的i2c_driver数据结构。同时也定义了保护这两个全局指针数组的信号量:
static struct i2c_adapter *adapters[I2C_ADAP_MAX];
static struct i2c_driver *drivers[I2C_DRIVER_MAX];
struct semaphore adap_lock;
struct semaphore driver_lock;
其中表示适配器和驱动程序最大数量的宏在linux/i2c.h中均被定义为16。由于安装i2c适配器驱动程序模块和i2c设备驱动程序模块的先后顺序不确定,所以必须通过全局数据结构(比如这里的指针数组或者链表等)来保存所有已安装的数据结构的地址,这样在后安装i2c适配器驱动程序时就可将drivers指针数组中记录的地址传递给i2c_add_adapter函数;在后安装i2c设备驱动程序时就可将adapters指针数组中记录的地址传递给i2c_add_driver函数(而这两个函数最终都是通过i2c_driver.的attach_adapter函数“认领”设备的)。
这里首先初始化adapters和drivers指针数组及相关信号量adap_lock和driver_lock,并将计数器清0。
i2cproc_init();
return 0;
}
然后通过i2cproc_init函数创建相应的/proc/bus/i2c文件,使得用户进程可以通过该文件得到当前系统上所有已注册的i2c总线信息。
i2cproc_init函数
该函数用于创建描述系统中所有i2c总线的/proc/bus/i2c文件。
int i2cproc_init(void)
{
struct proc_dir_entry *proc_bus_i2c;
i2cproc_initialized = 0;
if (! proc_bus) {
printk("i2c-core.o: /proc/bus/ does not exist");
i2cproc_cleanup();
return -ENOENT;
}
在i2c-core.c文件中定义了表示proc接口初始化程度的静态变量i2cproc_initialized,其初始值为0。内核全局变量proc_bus定义于fs/proc/root.c,声明于include/linux/proc_fs.h,在fs/proc/root.c的proc_root_init函数中初始化:
struct proc_dir_entry *proc_net, *proc_bus, ……
void __init proc_root_init(void)
{
int err = register_filesystem(&proc_fs_type);
if (err)
return;
proc_mnt = kern_mount(&proc_fs_type);
err = PTR_ERR(proc_mnt);
if (IS_ERR(proc_mnt)) {
unregister_filesystem(&proc_fs_type);
return;
}
……
proc_bus = proc_mkdir("bus", 0);
}
可见在proc_root_init函数中注册、挂载proc文件系统,而proc_bus指向代表“/proc/bus”目录的proc_dir_entry类型的变量。在确保proc_bus不为NULL后,接下来通过create_proc_entry函数在/proc/bus下创建文件/proc/bus/i2c,相应的读回调函数为read_bus_i2c。该函数很简单,就是遍历内核静态数组adapters,向用户空间返回所有已注册的i2c适配器的信息。在此不再赘述,可参见内核文档Documentation/i2c/proc-interface。函数的最后再增加i2cproc_initialized计数值。
proc_bus_i2c = create_proc_entry("i2c", /* name */
0, /* mode */
proc_bus); /* parent */
if (!proc_bus_i2c) {
printk("i2c-core.o: Could not create /proc/bus/i2c");
i2cproc_cleanup();
return -ENOENT;
}
proc_bus_i2c->read_proc = &read_bus_i2c;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27))
proc_bus_i2c->owner = THIS_MODULE;
#else
proc_bus_i2c->fill_inode = &monitor_bus_i2c;
#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27)) */
i2cproc_initialized += 2;
return 0;
}
第3章 安装、卸载pxa255的i2c适配器驱动程序
第3章 安装、卸载pxa255的i2c适配器驱动程序
pxa_i2c数据结构
linux/i2c.h中定义的i2c_adapter数据结构为描述各种i2c适配器的通用“模板”,它定义了注册总线上所有设备的clients指针数组、指向具体i2c适配器的总线通信方法i2c_algorithm的algo指针、实现i2c总线操作原子性的lock信号量等设施。但在适配器的驱动程序中可以根据具体适配器的需要“扩充”该数据结构。
在pxa255的i2c适配器驱动程序补丁中通过pxa_i2c数据结构来描述pxa255的i2c适配器:
struct pxa_i2c {
spinlock_t lock;
wait_queue_head_t wait;
struct i2c_msg *msg;
unsigned int msg_num;
unsigned int msg_idx;
unsigned int msg_ptr;
struct i2c_adapter adap;
int irqlogidx;
u32 isrlog[32];
u32 icrlog[32];
};
该数据结构扩展了已有的i2c_adapter数据结构,其主体为i2c_adapter类型的域adap。由于i2c操作为串行的,所以可以采用“阻塞-中断”的驱动模型,即读写i2c设备的用户进程在i2c操作期间进入阻塞状态,待i2c操作完成后总线适配器将引发中断,在相应的中断处理程序中唤醒受阻的用户进程。所以在pxa_i2c数据结构中设计了等待队列首部wait域。受阻的用户进程在阻塞期间仍然持有i2c_adapter中的lock信号量,从而实现上层用户进程对一条i2c总线访问的同步。
i2c总线的同步问题还包括另一个方面:在读写i2c设备的系统调用执行流中最终将通过i2c_pxa_do_xfer 函数初始化指向待传输信息的指针(msg,msg_idx,msg_ptr)并发起i2c通信(详见下文),而此期间可能发生i2c中断,而在i2c中断处理程序i2c_pxa_handler中也会步进指向待传输信息的指针。所以应该把i2c_pxa_do_xfer函数的相关操作放到中断禁区中执行,于是才设计lock自旋锁并通过spin_lock/unlock_irq函数来实现中断禁区。
自旋锁在嵌入式应用中往往都退化为实现中断禁区,另外当前应用所采用的2.4版本Linux中尚不支持内核态抢占,所以自旋锁的分配、释放操作也无需改变原子性计数preempt_count。于是可以通过spin_lock/unlock_irq函数同步中断处理程序,或者通过spin_lock/unlock_bh同步下半部分(一定要分析清楚竞争条件的双方究竟是谁,从而采用适宜的同步机制。比如,如果当前内核控制路径可能与下半部分发生竞争条件,那么使用spin_lock/unlock_irq函数就有“扩大打击面”之嫌了,呵呵)。
一次i2c操作可以包含若干次交互,一个交互的传输方向是确定的,由一个i2c_msg数据结构进行描述。由于在i2c操作的开始必须由master将slave设备的地址“上传”到i2c总线上,所以一次读操作就至少包两个交互:第一次为写操作,由master在发送START分节后发出slave的地址及WR位段,等待slave回送ACK分节,然后master写入的第2个字节可以为待读出的寄存器编号;第二次为读操作,master接收到slave回送的ACK分节后重新发送START分节,以告知slave设备可以开始发送数据了。所以一次读操作就至少需要两个i2c_msg数据结构进行描述,详见下文。
指针msg指向用于描述一组i2c交互的i2c_msg数据结构的数组:
struct i2c_msg {
__u16 addr; /* slave address */
unsigned short flags;
short len; /* msg length */
char *buf; /* pointer to msg data */
};
其中addr为设备的总线地址,buf指向与i2c设备交互的数据缓冲区,其长度为len。flags中的标志位描述该i2c操作的属性,比如是读还是写。
一次i2c总线操作的master在获得i2c总线后可能与同一个设备进行读、写交互,也可能与多个slave设备交互,这些情况即pxa255开发者手册9.3.3节图9-4中所述的“Repeated Start”情形,使得master可以连续进行多个i2c交互而不放弃总线。
每完成一次交互,msg指针和msg_idx计数器都会增加。而msg_ptr总是指向当前交互中要传送、接收的下一个字节在i2c_msg.buf中的偏移。最后icrlog和isrlog数组分别是i2c控制寄存器和状态寄存器的部分历史记录,可用作调试信息。
在pxa255的i2c适配器驱动程序模块中定义的pxa_i2c类型的变量为i2c_pxa,注意其algo指针指向模块中定义的i2c_algorithm类型的静态变量i2c_pxa_algorithm:
static struct pxa_i2c i2c_pxa = {
.lock = SPIN_LOCK_UNLOCKED,
.wait = __WAIT_QUEUE_HEAD_INITIALIZER(i2c_pxa.wait),
.adap = {
.name = "pxa2xx-i2c",
.id = I2C_ALGO_PXA,
.algo = &i2c_pxa_algorithm,
.retries = 5,
.inc_use = i2c_pxa_inc_use, /* Added by shrek2 */
.dec_use = i2c_pxa_dec_use, /* Added by shrek2 */
},
};
static struct i2c_algorithm i2c_pxa_algorithm = {
.name = "PXA-I2C-Algorithm",
.id = I2C_ALGO_PXA,
.master_xfer = i2c_pxa_xfer,
.smbus_xfer = NULL, /* Added by shrek2 */
.functionality = i2c_pxa_functionality, /* Added by shrek2 */
};
i2c_pxa_algorithm描述了pxa255的i2c适配器上的总线通信方法,其ID为I2C_ALGO_PXA,定义于linux/i2c-id.h。在pxa255上通过i2c_pxa_xfer函数全全执行i2c总线的通信任务。另外从这个数据结构也看到该pxa255的i2c驱动程序补丁尚不支持smbus协议,只支持i2c协议。
i2c_adap_pxa_init函数
(注:从www.arm.linux.org.uk上下载的有关PXA I2C 的补丁2360-2是针对linux2.6.1
展开阅读全文