I2C子系统之platform_driver初始化——I2C_adap_s3c_init()
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);
- }
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,
- },
- };
- 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,
- };
- 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,即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);
- }
- 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);
- }
调用此驱动的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的时候再分析。
相关阅读:
I2C子系统之at24c02读写测试
I2C子系统之ioctl()
I2C子系统之at24c02简介
I2C子系统之总结
I2C子系统之内核中I2C子系统的结构
I2C子系统之I2C bus初始化——I2C_init()
I2C子系统之platfor_device初始化——smdk2440_machine_init()
I2C子系统之platform_driver初始化——I2C_adap_s3c_init()
I2C子系统之I2C总线时钟频率设置
I2C子系统之adapter device和client device注册——I2C_add_number_adapter()
I2C子系统之__I2C_first_dynamic_bus_num变量的相关分析
I2C子系统之 adapter driver注册——I2C_dev_init()
I2C子系统之write()
评论暂时关闭