I2C驱动开发实例

上传人:夏** 文档编号:560032756 上传时间:2023-06-14 格式:DOC 页数:14 大小:296.50KB
返回 下载 相关 举报
I2C驱动开发实例_第1页
第1页 / 共14页
I2C驱动开发实例_第2页
第2页 / 共14页
I2C驱动开发实例_第3页
第3页 / 共14页
I2C驱动开发实例_第4页
第4页 / 共14页
I2C驱动开发实例_第5页
第5页 / 共14页
点击查看更多>>
资源描述

《I2C驱动开发实例》由会员分享,可在线阅读,更多相关《I2C驱动开发实例(14页珍藏版)》请在金锄头文库上搜索。

1、I2C 驱动开发 文档一、开发背景开发环境:DM355开发板内核版本: 2.6.10二、BQ27501 驱动开发的需求BQ27501是一个锂电池管理的芯片,可以向外提供锂电池的有关的信息。在用户空间用户不能直接访问 bq27501 的寄存器,所以要为其编写驱动,该驱动能够根据用户空间的命令,返回对应的电池信息。三、I2C 驱动的架构bq27501是通过I2C总线与DM355通信的,故bq27501的驱动实际上就是 bq27501的I2C读写的驱动Linux 内核中的 i2c 驱动程序可以分为三个层次,如下图所示:图1 Linux I2C 体系结构1) i2c 驱动框架i2c框架主要有i2c.h

2、和i2c-core.c 文件实现。它们定义驱动中使用的核心数据结构,完成i2c适配器和设备驱动的注册,注销,并且实现 i2c驱动的algorithm 。 i2c驱动中的algorithm 与适配器无关,它 属于上层代码,还包括探测设备、检测设备地址的上层代码。另外,i2c-dev.c 还用于对i2c设备节点的创建,并完成其访问方法的实现等。2) i2c 总线驱动总线驱动的职责,是为系统中每个I2C总线增加相应的读写方法。但是总线驱动本身并不会进行任何的通讯,它只是存在那里,等待设备驱动调用其函数。在系统开机时,首先装载的是I2C总线驱动。一个总线驱动用于支持一条特定的I2C总线的读写。这部分

3、主要定义i2c_adapter和i2c_algorithm数据结构,前者用来描述具体的i2c总线适配器,后者则描述i2c总线的通信方法。一般总线驱动由平台提供实现, davinci的i2c总线驱动在i2c-davinci.c文件中定义了,然后通过i2c_davinci_init函数调用i2c_add_adapter(i2c_davinci_adap)将这个两个模块注册到操作系统中,总线驱动就装上了。cpp view plaincopy1. static struct i2c_adapter i2c_davinci_adap = 2. .owner = THIS_MODULE,3. .name

4、= DAVINCI I2C adapter,4. .id = I2C_ALGO_EXP,5. .algo = &i2c_davinci_algo,6. .algo_data = NULL,7. .client_register = NULL,8. .client_unregister = NULL,9. ;10. static struct i2c_algorithm i2c_davinci_algo = 11. .name = DAVINCI I2Calgorithm,12. .id = I2C_ALGO_EXP,13. .master_xfer = i2c_davinci_xfer,14.

5、 .smbus_xfer = NULL,15. .slave_send = NULL,16. .slave_recv = NULL,17. .algo_control = NULL,18. .functionality = i2c_davinci_func,19. ;3) i2c设备驱动设备驱动则是与挂在I2C总线上的具体的设备通讯的驱动。通过I2C总线驱动提供的函数,设备驱动可以忽略不同总线控制器的差异,不考虑其实现细节地与硬件设备通讯。它实现对具体的i2c设备的描述,另 外还包括一些可能用到的数据结构。它借助i2c框架中的i2c_probe 函数实现设备的attach_adapter 方法

6、,完成设备检测成功后i2c_client数据结构回调函数的创建。实际操作过程中可以跳过i2c_probe函数直接调用实现i2c_client的函数,这样可以不必遵循调用i2c_probe固有的参数格式,从而可以提高效率和节省存储空间。bq27501的驱动加载流程如下图2所示。图2 bq27501的i2c驱动加载流程图bq27501_init()函数为该驱动模块的模块初始化函数,当在linux下使用insmod命令装载该模块时会执行该函数。在初始化函数中,对i2c_driver结构体变量初始化,然后调用register_chrdev()函数注册字符设备。接着调用i2c_add_driver()函

7、数添加一个i2c的driver。i2c_add_driver函数的执行会引发i2c_driver 中attach_adapter 指向的函数bq27501_i2c_probe_adapter()函数的执行,该函数是用来探测物理设备的。它需要通过调用_i2c_attach_client函数来实现探测,并且在 _i2c_attach_client 函数内调用i2c_attach_client函数在总线上附加一个新的client ;或者 调用i2c-core.c 中的i2c_probe 函数,由i2c_probe函数再调用探测物理设备的函数,bq27501驱动中是采用的第一种方式。四、实现I2C驱动

8、编写方式 最新的内核支持两种编写i2c驱动的方式,一个是“ Adapter方式(legacy )” ,另一个是“ Probe方式(newstyle )。两种方式的区别在于i2c_driver 结构体不同,“ Adapter方式”的i2c_driver 结构是:cpp view plaincopy1. struct i2c_driver 2. structmodule *owner;3. charname32;4. intid;5. unsignedint class;6. unsignedint flags;7. int(*attach_adapter)(struct i2c_adapter*

9、);8. int(*detach_adapter)(struct i2c_adapter*);9. int(*detach_client)(struct i2c_client*);10. int(*command)(struct i2c_client*client,unsigned int cmd, void *arg);11. structdevice_driver driver;12. structlist_head list;13. ;“Probe方式”的i2c_driver 结构是:cpp view plaincopy1. struct i2c_driver 2. unsignedin

10、t class;3. int(*attach_adapter)(struct i2c_adapter*);4. int(*detach_adapter)(struct i2c_adapter*);5. int (*probe)(struct i2c_client *, const struct i2c_device_id*);6. int (*remove)(struct i2c_client *);7. void(*shutdown)(struct i2c_client *);8. int(*suspend)(struct i2c_client *,pm_message_t mesg);9.

11、 int(*resume)(struct i2c_client *);10. int(*command)(struct i2c_client*client, unsignedint cmd, void *arg);11. structdevice_driver driver;12. const struct i2c_device_id *id_table;13. int(*detect)(struct i2c_client *,int kind, struct i2c_board_info*);14. conststruct i2c_client_address_data*address_da

12、ta;15. structlist_head clients;16. ;两种方式i2c_driver结构主要的不同是后者添加了probe和remove函数指针和id_table 。 bq27501使用的Ti- davinci内核是较早版本的,只支持Adapter方式,不支持Probe方式,所以bq27501采用的是Adapter 方式。Adapter方式编写的流程就是上节中所描述的i2c驱动加载的流程相同。至于Probe方式,在本次驱动编写中没有使用,所以在此不作详细的介绍。两种方式的对比可以参加网页资料http:/www.embedu.org/Column/Column213.htm 。五、

13、BQ27501的 I2C 驱动编写要使 bq27501 的 i2c 驱动模块能够运行,必须至少要编写两个文件,第一个是驱动的源文件,第二个是编 译源文件的 Makefile 文件。另外该驱动的两个关键点是 i2c 通信和与用户空间交互数据。1) Makefile 文件编写#如果已定义KERNELRELEASBW说明是从内核构造系统调用的,因此可以利用其内建语句。ifneq($(KERNELRELEASE),)obj-m := bq27501.o#否则,是直接从命令开始调用的,这时要调用内核构造系统。elseKDIR ?=/home/zl/ti-davinciPWD := $(shellpwd)

14、CROSS_COMPILE=arm-v5t-le-CC=$(CROSS_COMPILE)gccdefault:make -C $(KDIR) M=$(PWD) modulesendifclean:rm -rf *.o *.cmd *.mod.c *.sysmvers注:1. Makefile 文件的文件名中M定要大写。这是因为编译的时候首先看环境变量KERNELRELEASE否定义,如果没定义则调用 Linux 内核编 译 build 脚本。该脚本会首先编译内核,其间会创建环境变量 KERNELRELEASE着编译当前工作目录下的hello模块,此时会第二遍读取Makefile,再次判断环境变

15、量KERNELRELEAS是否定义,已经定义的情况下开始编译hello模块。2. Makefile 文件中的命令行,以 Tab 键开头(不能是空格),例如make, clean 。依赖条件顶格,例如default , clean 。3. KDIR :指向嵌入系统的 linux 内核,而不是正在运行的系统的内核。4. CR0SS_C0MPILE交叉编译环境,也就是安装的dvdsdk。5. CC :指明编译器,加上 CROSS_COMPI|_Et义了一个交叉编译器。6. clean :当时使用 makeclean 命令时清除编译的结果。7. default :当使用make命令后面不加任何参数时,默认执行的语句。将驱动代码的源文件和 Makefile文件放到同一个文件夹下面。在终端进入到目录下,使用make命令对其进行编译。2) 模块编程为了 bq27501 驱动测试的方便,所以采用模块编程的方式来实现。将 bq27501 驱动作为一个内核模 块动态加载到内核中,而不是采用在内核树中添加代码实现这种静态的方法实现的。

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 医学/心理学 > 基础医学

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号