Paltform总线与其它总线框架的关系探究

    在学习驱动的过程中,学习过Platform、I2C、SPI、USB等总线架构,对于Platform总线的理解是在书藉(宋宝华的《Linux设备驱动详解》)上所述的“一个现实的Linux设备和驱动通常需要挂接在一种总线上,对于本身依附于PCI、USB、I2C、SPI等的设备而言,这自然不是问题。但是在嵌入式系统里面,在SOC系统中集成的独立控制器、挂接在SOC内存空间的外设等却不依附于此类总线。基于这一背景Linux发明了一种虚拟的总线,称为platform总线,相应的设备称为platform_device,而驱动成为platform_driver”。

    对于这几句话,可能是我的误解以为PCI、USB这种设备的驱动程序有自己总线的框架,而与Platform并没有一丝关联,完全是相互独立的框架。而Platform只适用于GPIO这种没有总线协议的外设。

但是最近回顾仔细分析内核源码后,发现完全理解错误了。由其是那段话中的后半句(标红),根本被我直接忽略了。简单的说,一个完整的I2C框架或者其它框架是依赖于Platform总线的。下面以基于Linux2.6.22内核的S3C2440关于I2C驱动为例。

    下图所列的就是在各种博客上都能看到的I2C框架。



    第一次看这个图的时候,以为这就是I2C驱动的全部,可是我意外地I2C_S3C2410.c文件的adapter驱动入口函数i2c_adap_s3c_init中发现了platform_driver_register函数,(其实很明显,想不通为什么现在才发现),这个明明是platform框架才会用到的啊,在这里是什么意思。而且adapter又作为了platform的driver端(对platform的理解,三个部分组成,driver端是无关于硬件的驱动,而dev端则是定义了一堆资源,最后的核心Bus只是构造了连接driver和dev的纽扣并没有太多的核心代码),那么与之对应的platform的dev端在哪儿呢,经过搜索.id成员(至少linux2.6.22是通过id字符串构建联系的)发现平台资源在devs.c(arch\arm\plat-s3c24xx)中定义了,如下表所示。

<span style="font-size:18px;">static struct resource s3c_i2c_resource[] = {
	[0] = {
		.start = S3C24XX_PA_IIC,
		.end   = S3C24XX_PA_IIC + S3C24XX_SZ_IIC - 1,
		.flags = IORESOURCE_MEM,
	},
	[1] = {
		.start = IRQ_IIC,
		.end   = IRQ_IIC,
		.flags = IORESOURCE_IRQ,
	}

};

struct platform_device s3c_device_i2c = {
	.name		  = "s3c2410-i2c",
	.id		  = -1,
	.num_resources	  = ARRAY_SIZE(s3c_i2c_resource),
	.resource	  = s3c_i2c_resource,
};

EXPORT_SYMBOL(s3c_device_i2c);
</span>

    使用该资源的地方在mach-smdk2440.c(arch\arm\mach-s3c2440)中,如下表所示。

<span style="font-size:18px;">static struct platform_device *smdk2440_devices[] __initdata = {
	&s3c_device_usb,
	&s3c_device_lcd,
	&s3c_device_wdt,
	&s3c_device_i2c,
	&s3c_device_iis,
};

static void __init smdk2440_map_io(void)
{
	s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));
	s3c24xx_init_clocks(16934400);
	s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));
}

static void __init smdk2440_machine_init(void)
{
	s3c24xx_fb_set_platdata(&smdk2440_lcd_cfg);

	platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));  //依次添加
	smdk_machine_init();
}
</span>

    至此,根据如上代码及所在内核的路径,不难可以总结如下。

    一个I2C完整的驱动,应该至少包括两个方面:一个是基于Platform总线(dev-bus-drv)的驱动。另外一个是基于I2C固有的框架。

    从硬件架构上分析,两者作用不相同。将一个I2C插入一个自带I2C控制器的处理器平台,这一过程从硬件上分析,包含了1处理器2平台3 I2C设备。

    处理器和平台的关系,可以说平台定制了处理器,比如定制使用处理器的哪些资源,例如哪些GPIO作为输出连接LED设备,哪些GPIO作为输入连接了按键,另外一个处理器可能有多个I2C控制器,而且与其它资源如GPIO复用,因此,平台也需要定制哪个I2C控制器作为与外设连接的端口。而Platform总线就是起到这个作用,在某个文件(通常是mach-xxx)中确定该开发板所使用的资源,而对应的控制器驱动方面,则专注于与硬件无关的驱动,如i2c-s3c24xx.c。一旦匹配后,会调用drv端定义的probe函数,对于i2c而言,probe函数,主要完成了注册一个adapter的作用,至此完成了处理器I2C内部控制器驱动的初始化,同时也注册了adapter,为i2c设备驱动层面起到了铺垫。

    平台和I2C设备的关系,就是指一个I2C设备与处理器相连接的过程,上述过程,只是专注于提供一个适用于该处理器也可以说是平台的传输I2C正确的方法,但是不同的I2C设备传输的数据含义是不相同的,因此,还需要一个设备驱动,设备驱动就是基于I2C固有的框架(adapter-bus-drv)驱动完成的。即一旦向BUS注册一个DRV,BUS会从ADAPTER链表中轮询每一个,去调用DRV的attach_adapter函数,(内容基本上就是利用i2c_probe函数根据地址向设备发送查询信号,一旦成功就会调用i2c_probe指定的接口函数)。

综上,完整的框架粗略如下图所示。基于上述,再次去理解本文开头引用的那段话相信会有全新的感悟。


  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值