i2c子系统之platform_driver初始化——i2c_adap_s3c_init()

在完成platform_device的添加之后,i2c子系统将进行platform_driver的注册过程。

platform_driver的注册通过调用初始化函数i2c_adapter_s3c_init函

数来完成。

i2c_adap_s3c_init()函数体如下:

static int __init i2c_adap_s3c_init(void)
{
	return platform_driver_register(&s3c24xx_i2c_driver);
}
platform_driver_register(&s3c24xx_i2c_driver),将完成向platform_bus总线注册platform_driver类型驱动

s3c24xx_i2c_driver的工作。s3c24xx_i2c_driver如下:

static struct platform_driver s3c24xx_i2c_driver = {
	.probe		= s3c24xx_i2c_probe,
	.remove		= s3c24xx_i2c_remove,
	.id_table	= s3c24xx_driver_ids,
	.driver		= {
		.owner	= THIS_MODULE,
		.name	= "s3c-i2c",
		.pm	= S3C24XX_DEV_PM_OPS,
	},
};
id_table被初始化为s3c24xx_driver_ids:
static struct platform_device_id s3c24xx_driver_ids[] = {
	{
		.name		= "s3c2410-i2c",
		.driver_data	= TYPE_S3C2410,
	}, {
		.name		= "s3c2440-i2c",
		.driver_data	= TYPE_S3C2440,
	}, { },
};

platform_driver在注册到platform_bus总线的过程中会尝试将已注册的platform_driver

与已注册到platform_bus上的所有platform_device进行配对。

platform_bus总线的相关操作如下:

struct bus_type platform_bus_type = {
	.name		= "platform",
	.dev_attrs	= platform_dev_attrs,
	.match		= platform_match,
	.uevent		= platform_uevent,
	.pm		= &platform_dev_pm_ops,
};

配对过程通过调用总线的match方法实现,即platform_match函数。如下:
static int platform_match(struct device *dev, struct device_driver *drv)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct platform_driver *pdrv = to_platform_driver(drv);

	/* Attempt an OF style match first */
	if (of_driver_match_device(dev, drv))
		return 1;

	/* Then try to match against the id table */
	if (pdrv->id_table)
		return platform_match_id(pdrv->id_table, pdev) != NULL;

	/* fall-back to driver name match */
	return (strcmp(pdev->name, drv->name) == 0);
}
可以看到函数中有
if (pdrv->id_table)
		return platform_match_id(pdrv->id_table, pdev) != NULL;
相关语句。

此处就是根据platfor_device和platform_driver的名字来实现配对。但是platform_driver有好几个名字

可以选择,通过id_table来实现配对。执行到此处,之前已注册到platform_bus的platform_device

型设备s3c_devicei2c0和现在刚注册到platform_bus总线的platfor_drver型驱动s3c24xx_i2c_drive将

实现配对成功。

成功配对之后将尝试进行probe

static int really_probe(struct device *dev, struct device_driver *drv)
{     
        。。。 。。。

	if (dev->bus->probe) {
		ret = dev->bus->probe(dev);
		if (ret)
			goto probe_failed;
	} else if (drv->probe) {
		ret = drv->probe(dev);
		if (ret)
			goto probe_failed;
	}
        。。。 。。。
} 
有上述代码可知,成功配对后首先调用的是总线的probe,假如总线未初始化probe方法才会去

调用驱动中的probe,即platform_driver.drv->probe,而platform_bus本身未初始化probe方法,

所以此处调用驱动的probe方法,驱动的probe在注册过程中已被初始化

int platform_driver_register(struct platform_driver *drv)
{
	drv->driver.bus = &platform_bus_type;
	if (drv->probe)
		drv->driver.probe = platform_drv_probe;
	if (drv->remove)
		drv->driver.remove = platform_drv_remove;
	if (drv->shutdown)
		drv->driver.shutdown = platform_drv_shutdown;

	return driver_register(&drv->driver);
}
即直接调用函数platform_drv_probe,函数如下:

static int platform_drv_probe(struct device *_dev)
{
	struct platform_driver *drv = to_platform_driver(_dev->driver);
	struct platform_device *dev = to_platform_device(_dev);

	return drv->probe(dev);
}
函数的工作很简单,即通过_dev->driver找到包含它的platform_driver型驱动,然后再

调用此驱动的probe方法,即s3c24xx_i2c_probe函数。

probe函数的功能如下:

1.首先创建struct s3c24xx_i2c  *i2c。

i2c相关数据的初始化来源于s3c2_device_i2c0.dev.platdata。

2.通过i2c->adap.algo    = &s3c24xx_i2c_algorithm;初始化algo方法。

在write系统调用的时候会调用到s3c24xx_i2c_algorithm函数。

3.init_waitqueue_head(&i2c->wait); 初始化一个等待队列

4.s3c24xx_i2c_init (i2c);初始化i2c控制器,主要是对s3c24xx的i2c控制

寄存器进行一些操作,比如配置s3c2440i/o功能,设置从机地址,以及

设置i2c时钟频率等相关操作。时钟频率的设置参见博文。

5.request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,
              dev_name(&pdev->dev), i2c);
申请中断,内核中的i2c读写是通过中断来实现的,具体稍后分析

6.i2c_add_numbered_adapter(&i2c->adap);最后向系统注册一个i2c adapter

这里需要着重注意第2、5、6点。

下面先分析第6点。第2、5点待到后面读写at24c02的时候再分析。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值