i2c相关知识点

0、 总线端:主要是mach-smdkc110.c和i2c_s3c2410.c两个文件,主要完成资源的注册,在s3c24xx_i2c_probe中创建adapter和client后总线端退出
      设备端:主要是用户写的部分,通过i2c_add_driver 匹配i2c_driver的id_table中的name和 client中的name后,进一步初始化client并调用i2c_driver的probe

1、 i2c_client是一开始初始化的时候就创建好的,每个adapter最大有10个client,但是一开始初始化的i2c_client是不完整的,i2c_client通过 i2c_new_device创建,但是没有初始化他的i2c_driver成员,直到设备端匹配成功时才调用i2c_bus_type的
i2c_device_probe把他的i2c_driver成员赋值

2、 调用I2c_new_device的地方有:
i2c_new_dummy               //这个是预留的接口没有使用
i2c_sysfs_new_device
i2c_scan_static_board_info  //扫描I2c_board_info  创建I2c_client
i2c_detect_address  
i2c_new_probed_device

3、 i2c_device_probe (i2c_bus_type的probe函数)跟用户驱动的probe函数不是同一个,i2c_device_probe 会调用用户定的probe函数(即:i2c_driver的probe函数)

4、i2c_dev.c文件完全可以被看做一个i2c设备驱动,不过,他实现的一个i2c_client是虚拟、临时的,随着设备文件的打开而产生,并随设备文件的关闭而撤销,并没有添加到i2c_adapter的client链表中。i2c-dev.c针对每个i2c适配器生成一个主设备号为89的设备文件,实现了i2c_driver的成员函数以及文件操作接口,所以i2c-dev.c的主体是“i2c_drvier成员函数+字符设备驱动”——详见《Linux设备驱动开发详解》P345用户空间的read、 write/ioctl函数直接调用此驱动文件 i2cdev_read/i2cdev_write/i2cdev_ioctl通过ioctl进行设备地址等的配置

5、s3c24XX_i2c_probe初始化硬件适配器,总线端匹配后会调用此函数

6、宏container_of(pointer, type, member),这个宏定义在linux/kernel.h里面,第一个参数就是指向kobject的指针,type是指嵌入kobject的结构体类型,member就是在结构体类型里 面kobject的成员名

7、Linux I2C驱动体系结构有相当的复杂度,它主要由3部分组成,即I2C核心、I2C总线驱动和I2C设备驱动。
I2C核心:I2C总线驱动和I2C设备驱动的中间枢纽,它以通用的、与平台无关的接口实现了I2C中设备与适配器的沟通。
I2C总线驱动:填充i2c_adapter和 i2c_algorithm结构体。
I2C设备驱动:填充i2c_driver结构体并实现其本身所对应设备类型的驱动。 
另外,系统中i2c-dev.c文件定义的主设备号为89的设备可以方便地给应用程序提供读写i2c设备寄存器的能力,使得工程师大多时候并不需要为具体的I2C设备驱动定义文件操作接口。

8、匹配platform_device和platform_driver主要看两者的name字段是否相同。 
platform_device有直接的name成员,platform_driver的name在它的device_driver成员内部

9、对platform_device的定义通常在 BSP包里面实现(即arch 目录下的),在 BSP 文件中,将platform_device归纳为一个数组,最终通过 platform_add_devices()函数统一注册。platform_add_devices()函数可以将平台设备添加到系统中。
调用platform_add_devices的地方:(init_machine)
①在common_smdk.c中smdk_machine_init的函数中
②mach-smdkv210.c的smdkv210_machine_init函数中
③mach-smdkc110.c的smdkc110_machine_init函数中、 smdkc100_machine_init  !!!
④mach-smdk2440.c的smdk2440_machine_init函数中
⑤mach-smdk2410.c的smdk2410_init函数中
⑥init.c (路径:arch/arm/plat-samsung)s3c_arch_init函数中

i2c_register_board_info 在i2c_boardinfo.c中定义
调用i2c_register_board_info的地方:
mach-smdkc110.c的smdkc100_machine_init函数路径:arch/arm/mach-s5pc110/
mach-smdkc110.c的smdkc110_machine_init函数路径:arch/arm/mach-s5pv210/
mach-vr1000.c  的vr1000_init 函数路径:arch/arm/mach-s3c2410/
即:mach-smdkc110.c 定义 并注册了i2c_board_info 

10、板级支持包(BSP)是介于主板硬件和操作系统中驱动层程序之间的一层,一般认为它属于操作系统一部分,主要是实现对操作系统的支持,为上层的驱动程序提供访问硬件设备寄存器的函数包,使之能够更好的运行于硬件主板。
BSP是系统用来管理外设的部分,由两部分组成:初始化、驱动程序。 所谓初始化是指从系统上电复位 开始直到wind kernel和usrRoot根任务启动的这段时间,系统的执行过程。 驱动程序就是一些包含I/O 操作的子函数。 初始化包括CPU Init、Board Init、System Init。CPU Init初始化CPU的内部寄存器。 Board Init初始化智能I/O的寄存器,将device打通。

11、总线驱动注册的流程主要就是: 
第一步:注册 platform_device
第二步:注册 platform_driver ,然后platform总线会让两者匹配在一起

12在驱动中使用platform总线大体有以下几个好处: 
a、platform机制将本身的资源注册进内核,有内核统一管理,在驱动程序中使用这些资源时通过platform_device提供的标准接口进行申请并使用,使得设备被挂接在一个总线上,使配套的sysfs节点、设备电源管理都成为可能。 
b、隔离了BSP和驱动。BSP 中定义platform 设备和设备使用的资源(可以使用platform_data的形式来包括platform 设备的设备),设备的具体配置信息。而在驱动中,只需要通过通用API去获取资源和数据,这样提高了驱动和资源管理的独立性,使得驱动具有更好的可扩展性、跨平台性和安全性。
c、在移植时,我们只需要在类似mach_smdkxxx.c的文件中修改驱动中可能要变化的资源即可。

13、分配、注册和注销SPI主机驱动结构体的API由SPI核心层提供: 
struct spi_master * spi_alloc_master(struct device *host, unsigned size); 
int spi_register_master(stru ct spi_master *master); 
void spi_unregister_master(struct spi_master *master); 
这里可能会有疑问,spi master controller注册对应的驱动框架里的哪一层?
按说spi主机控制器已经作为platform设备都注册过了。这里就需要用驱动设计里面的分层思想来解释。使用到platform总线API注册platform总线上的控制器设备和驱动,都是common的部分。specific的部分,会在platform driver注册后,在probe函数里面基于注册的common部分的资源信息来具体实现,称之为spi_master的注册部分。

14、bus_add_device
  * - Add device's bus attributes.
  * - Create links to device's bus.
  * - Add the device to its bus's list of devices.

15、 platform_driver_register中初始化s3c24xx_i2c_driver
总线端的 platform_devie和 platform_driver 要匹配
设备端的 i2c_client 和 i2c_driver 要匹配
具体参考bma150.c 这个就是我们要写的那部分驱动

16、i2c_add_driver  /i2c_adap_s3c_init(i2c-s3c2410.c)/smdkc100_machine_init(mach- smdkc110.c)开始  

17、i2c_bus_type 在i2c-core.c

18、i2c_adapter 在i2c-core.c

19、i2c_bus_type的 i2c_device_match 进行i2c_driver->id_table->name 与i2c_client->name 的匹配

20、i2c_driver与i2c_client是一对多的关系,一个i2c_driver上可以支持多个同等类型的i2c_client

21、i2c_client信息通常在BSP的板文件中通过i2c_board_info填充,如下面代码就定义了一个I2C设备“ID”为“ad7142 _ joystic k”、 地址为0x2C、中断号位IRQ_PF5的i2c_client: 
static  struct  i2c_board_info  __initdata  xxx_i2c_board_info[] = { 
#if defined(CONFIG _ JOYSTICK _ AD7142) || defined(CONFIG_ JOYSTICK _ AD7142 _ MODULE) 
        {  
                I2C_BOARD_INFO("ad7142_ joystick", 0x2C), 
                .irq = IRQ_PF5, 
        }, 
	...  
}  
在i2c总线驱动i2c_bus_type 的match()函数i2c_device_match() 中,会调用i2c_match_ id () 函数匹配板文件中定义的ID和i2c_driver 所支持的ID表。 

22、i2c_adapter中包括依附于它的i2c_client的链表

23、i2c核心(i2c-core.c)(drivers/i2c/i2c-core.c)中提供了一组不依赖于硬件平台的接口数, 这个文件一般不需要修改,但是理解其中的主要函数非常关键,因为i2c总线驱动和设备 驱动之间依赖于i2c核心作为纽带。

24、i2c_driver 所在的bus 为i2c_bus_type

25、i2c_bus_type的mach  i2c_device_match所做的匹配的是 id_table的name与client的name

26、i2c_register_driver 中的 driver_register调用过 bus_for_each_dev (drv->bus, NULL, drv, __driver_attach);
而i2c_register_driver 在后面又直接调用了一次 bus_for_each_dev (&i2c_bus_type, NULL, driver,__process_new_driver);

27、对于newstyle方式,需要通过i2c_register_board_info()函数注册i2c_board_info,向内核 提供i2c设备的相关信息。
(在mach-smdkc110.c中的smdkc110_machine_init中调用i2c_register_board_info注册 i2c_board_info)

28、i2c-dev.c文件完全可以看做一个i2c设备驱动,不过,它实现的一个i2c_client是虚拟的、临 时的,随着设备文件的打开而产生,随着设备文件的关闭而撤销,并没有添加到 i2c_adapter的client链表中。i2c-dev.c针对每个i2c适配器生成一个主设备号为89的设 备文件,实现了i2c_driver的成员函数以及文件操作接口,所以i2c-dev.c的主体 是“i2c_driver成员函数+字符设备驱动”

29、i2c核心提供的i2c_add_adapter(可能用i2c_add_numbered_adapter)函数添加这个适配器。当 处理器包含多个i2c控制器时,我们通过板文件定义的platform数据中的bus_num进行区分。

30、platform_device 和platform_drvier 匹配的这两者的匹配是不要用户去主动调用的,不管用户驱动有没有注册,只要系统起来后两者都会自动匹配, 
①i2c_s3c2410.c属于总线端驱动(2410、2440、A8 都用这个文件),这是个会被自动安装的驱动,里面的init函数是会被执行。
platform_drvier完成注册,会同时注册adapter并创建静态的client
②mach_smdkc110.c属于总线设备,这个也是会自动安装的驱动,通过 smdkc100_machine_init。   platform_device完成注册;
③这两个注册的时候会调用platform_bus_type里面的platform_mach 完成platform的匹 配(在platform_bus_type上完成匹配),即总线端的匹配,这里匹配并完成adapter的创 建之后platform的任务完成,并退出。
下一步就是用户的i2c_driver与i2c_clinet的匹配了(即设备端的匹配,他们在 i2c_bus_type上匹配)

31、例如s3c2410与i2c相关的platform_driver在文件i2c-s3c2410.c里面,s3c24xx_i2c_driver, 当platform_device与platform_driver匹配成功时,调用s3c24xx_i2c_probe在里面会, 拿到platform_device的资源,并创建adapter和client

32、s3c24xx_i2c_probe i2c_driver_register最终调用了i2c_new_device

33、注意总线级或设备级会共用很多函数,注意当前是platform在调用的还是i2c的在调用的,两者调用时回调的函数是不同的

34、i2c_driver里面有 probe ,device_driver里面也有probe ,两者有什么区别
这两个probe一般不会同时定义,像bma150里面之定义了i2c_driver的probe

35、i2c_driver的driver成员里面有name,id_table成员里面也有name,这是为什么?
通常总线在匹配的时候(总线的mach函数里面),如果id_table存在,则先拿id_table的 name去匹配,id_table不存在时才匹配driver的name,像spi_bus_type和 platform_bus_type的mach函数都是这样的,而现在的i2c_bus_type只拿id_table的name 进行匹配。但是还是会用到driver的name查看总线上是否已经注册过此驱动所以这两个name应该相同。

你可能感兴趣的:(驱动)