微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM-Linux s3c2440 之I2C分析

ARM-Linux s3c2440 之I2C分析

时间:11-19 来源:互联网 点击:
内核版本linux-2.6.30.4
I2C在Linux中是Bus下的一个子系统. 它由客户驱动(client driver),i2c-core核心,i2c适配器驱动(adapter driver) ,算法aglorithm组成。s3c2440中有两个i2c现适配器.作为platform_device设备在系统启动先时被注册和添加。下面我们分析i2c(设备,驱动,总线)的实现过程.
//填充设备资源
//struct resource结构体描述了挂接在cpu总线上的设备实体资源
//.start:i2c寄存器起始地址; .end:i2c寄存器结束地址; .flag:描述设备实体的共性和特性标志

  1. staticstructresources3c_i2c_resource[]={
  2. [0]={//i2c-0
  3. .start=S3C_PA_IIC,
  4. .end=S3C_PA_IIC+SZ_4K-1,
  5. .flags=IORESOURCE_MEM,
  6. },
  7. [1]={//i2c-1
  8. .start=IRQ_IIC,
  9. .end=IRQ_IIC,
  10. .flags=IORESOURCE_IRQ,
  11. },
  12. };

/i2c适配器初始化时数据

  1. staticstructs3c2410_platform_i2cdefault_i2c_data0__initdata={
  2. .flags=0,
  3. .slave_addr=0x10,
  4. .frequency=100*1000,
  5. .sda_delay=100,
  6. };

//声明i2c适配器为platform_device

  1. structplatform_devices3c_device_i2c0={
  2. .name="s3c2410-i2c",
  3. #ifdefCONFIG_S3C_DEV_I2C1
  4. .id=0,
  5. #else
  6. .id=-1,
  7. #endif
  8. .num_resources=ARRAY_SIZE(s3c_i2c_resource),
  9. .resource=s3c_i2c_resource,
  10. };
  11. staticstructs3c2410_platform_i2cdefault_i2c_data0__initdata={
  12. .flags=0,
  13. .slave_addr=0x10,
  14. .frequency=100*1000,
  15. .sda_delay=100,
  16. };

//添加i2c适配器:

  1. staticstructplatform_device*smdk2440_devices[]__initdata={
  2. ...
  3. &s3c_device_i2c0,
  4. ...
  5. };

//添加plat_from_data

  1. void__inits3c_i2c0_set_platdata(structs3c2410_platform_i2c*pd)
  2. {
  3. structs3c2410_platform_i2c*npd;
  4. if(!pd)
  5. pd=&default_i2c_data0;
  6. npd=kmemdup(pd,sizeof(structs3c2410_platform_i2c),GFP_KERNEL);
  7. if(!npd)
  8. printk(KERN_ERR"%s:nomemoryforplatformdata\n",__func__);
  9. elseif(!npd->cfg_gpio)
  10. npd->cfg_gpio=s3c_i2c0_cfg_gpio;//i2c引脚配置
  11. s3c_device_i2c0.dev.platform_data=npd;//挂接plat_form_data数据
  12. }

//定义好上面相关结构后,在smdk2440_machine_init()中被注册和添加成platform_device

  1. staticvoid__initsmdk2440_machine_init(void)
  2. {
  3. s3c24xx_fb_set_platdata(&smdk2440_fb_info);
  4. s3c_i2c0_set_platdata(NULL);
  5. ...
  6. //注册和添加platform_device
  7. platform_add_devices(smdk2440_devices,ARRAY_SIZE(smdk2440_devices));
  8. ...
  9. }

其中 smdk2440_machine_init在被赋值在MACHINE_START中
在start_kernel()-->setup_arch()时被调用,但值得注意的是i2c适配器并没有被初始化,因为还没有驱动!
通过下面可以知道platform_device_register()和device_register()的区别:

  1. platform_add_devices()-->platform_device_register()-->
  2. platform_device_add()-->device-->add()

platfrom_bus_init()时也将添加一个名叫platform的设备(struct device platform_bus):

  1. plat_form_bus_init()-->device_register()-->device_register()
  2. -->device-->add()

但这个设备是虚拟的,所有platform_device_add()后的设备都是在/devices/platform/下
因为所有plaform_device 的父母亲都是platform_bus,是在platform_device_add()中

  1. if(!pdev->dev.parent)
  2. pdev->dev.parent=&platform_bus;

我想这也就是platform_device_register()和device_register()区别吧
在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等函数

  1. staticstructplatform_drivers3c2440_i2c_driver={
  2. .probe=s3c24xx_i2c_probe,
  3. .remove=s3c24xx_i2c_remove,
  4. .suspend_late=s3c24xx_i2c_suspend_late,
  5. .resume=s3c24xx_i2c_resume,
  6. .driver={
  7. .owner=THIS_MODULE,
  8. .name="s3c2440-i2c",//
  9. },
  10. };

//初始化并注册platform_driver

  1. staticint__initi2c_adap_s3c_init(void)
  2. {
  3. intret;
  4. ret=platform_driver_register(&s3c2410_i2c_driver);//
  5. if(ret==0){
  6. printk("registers3c2440_i2c_driver.....\n");
  7. ret=platform_driver_register(&s3c2440_i2c_driver);
  8. if(ret)
  9. {
  10. printk("registers3c2410_i2c_driver.....\n");
  11. platform_driver_unregister(&s3c2410_i2c_driver);
  12. }
  13. }
  14. retur

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top