I2C在Linux中是Bus下的一个子系统. 它由客户驱动(client driver),i2c-core核心,i2c适配器驱动(adapter driver) ,算法aglorithm组成。s3c2440中有两个i2c现适配器.作为platform_device设备在系统启动先时被注册和添加。下面我们分析i2c(设备,驱动,总线)的实现过程.
//填充设备资源
//struct resource结构体描述了挂接在cpu总线上的设备实体资源
//.start:i2c寄存器起始地址; .end:i2c寄存器结束地址; .flag:描述设备实体的共性和特性标志
- static struct resource s3c_i2c_resource[] = {
- [0] = {//i2c-0
- .start = S3C_PA_IIC,
- .end = S3C_PA_IIC + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {//i2c-1
- .start = IRQ_IIC,
- .end = IRQ_IIC,
- .flags = IORESOURCE_IRQ,
- },
- };
- static struct s3c2410_platform_i2c default_i2c_data0 __initdata = {
- .flags = 0,
- .slave_addr = 0x10,
- .frequency = 100*1000,
- .sda_delay = 100,
- };
//声明i2c适配器为platform_device
- struct platform_device s3c_device_i2c0 = {
- .name = "s3c2410-i2c",
- #ifdef CONFIG_S3C_DEV_I2C1
- .id = 0,
- #else
- .id = -1,
- #endif
- .num_resources = ARRAY_SIZE(s3c_i2c_resource),
- .resource = s3c_i2c_resource,
- };
- static struct s3c2410_platform_i2c default_i2c_data0 __initdata = {
- .flags = 0,
- .slave_addr = 0x10,
- .frequency = 100*1000,
- .sda_delay = 100,
- };
//添加i2c适配器:
- static struct platform_device *smdk2440_devices[] __initdata = {
- ...
- &s3c_device_i2c0,
- ...
- };
- void __init s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *pd)
- {
- struct s3c2410_platform_i2c *npd;
- if (!pd)
- pd = &default_i2c_data0;
- npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL);
- if (!npd)
- printk(KERN_ERR "%s: no memory for platform data\n", __func__);
- else if (!npd->cfg_gpio)
- npd->cfg_gpio = s3c_i2c0_cfg_gpio; //i2c引脚配置
- s3c_device_i2c0.dev.platform_data = npd; //挂接plat_form_data数据
- }
- static void __init smdk2440_machine_init(void)
- {
- s3c24xx_fb_set_platdata(&smdk2440_fb_info);
- s3c_i2c0_set_platdata(NULL);
- ...
- //注册和添加platform_device
- platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
- ...
- }
在start_kernel()-->setup_arch()时被调用,但值得注意的是i2c适配器并没有被初始化,因为还没有驱动!
通过下面可以知道platform_device_register()和device_register()的区别:
- platform_add_devices()-->platform_device_register()-->
- platform_device_add()--> device-->add()
- plat_form_bus_init()-->device_register()-->device_register()
- -->device-->add()
因为所有plaform_device 的父母亲都是platform_bus,是在platform_device_add()中
- if (!pdev->dev.parent)
- pdev->dev.parent = &platform_bus;
在reset_init()-->kernel_init()-->do_basic_setup()
-->driver_init()-->platform_bus_init()完成platform_bus总线的注册
但是现在i2c适配器并没有和驱动绑上,因为到系现在为止驱动还没有出现呢(初始化)
只有做好前面一些的准备功夫,i2c适配器驱动才能初始化,这个是需要按照顺序来的。
s3c2440-i2c适配器驱动的初始化在drivers/i2c/bus/i2c-s3c2410.c中实现
并且作为platform_driver注册。
//填充driver结构并完成相应probe,remove等函数
- static struct platform_driver s3c2440_i2c_driver = {
- .probe = s3c24xx_i2c_probe,
- .remove = s3c24xx_i2c_remove,
- .suspend_late = s3c24xx_i2c_suspend_late,
- .resume = s3c24xx_i2c_resume,
- .driver = {
- .owner = THIS_MODULE,
- .name = "s3c2440-i2c", //
- },
- };
//初始化并注册platform_driver
- static int __init i2c_adap_s3c_init(void)
- {
- int ret;
- ret = platform_driver_register(&s3c2410_i2c_driver);//
- if (ret == 0) {
- printk("register s3c2440_i2c_driver.....\n");
- ret = platform_driver_register(&s3c2440_i2c_driver);
- if (ret)
- {
- printk("register s3c2410_i2c_driver.....\n");
- platform_driver_unregister(&s3c2410_i2c_driver);
- }
- }
- return ret;
- }
- subsys_initcall(i2c_adap_s3c_init);
这样适配器就和驱动绑定上了,过程是这样的:
- platform_driver_register()-->driver_register()-->bus_add_driver()-->driver_attach()
- __driver_attach()-->driver_probe_device()-->s3c24xx_i2c_probe()
- i2c_add_numbered_adapter(&i2c->adap);
上一篇:ARMLinux s3c2440 之UART分析二
下一篇:ARM-Linux s3c2440 之UART分析(五)
推荐阅读最新更新时间:2024-03-16 14:56
设计资源 培训 开发板 精华推荐
- 工作需要半个月让我写四个驱动程序,Opc,DDE,MODBUS Tcp/Ip, 数据库驱动,以前都没接触过。时间紧,另外还有两个控件要调试。请各位前辈指教指教。
- wince6的问题
- 关于IIC通用读写程序问题
- 【学习Sitara™ AM335x】- cracking pdf-file passwords
- 物联网小课堂之NB-IoT黑科技——低功耗技术
- 关于屏幕旋转的处理
- MSP430 SPI 主机从机通信问题
- Synplify工具使用指南.pdf
- AltiumDesigner设计4层PCB一定要在层叠管理里设置层厚吗?
- at+cipstart="tcp","210.153.49.2","80" ERROR 请问是怎么回事?