zoukankan      html  css  js  c++  java
  • linux之i2c子系统架构---总线驱动

    编写i2c设备驱动(从设备)一般有两种方式:

    1.用户自己编写独立的从设备驱动,应用程序直接使用即可。

    2.linux内核内部已经实现了一个通用的设备驱动,利用通用设备驱动编写一个应用程序(用户态驱动),在应用程序中用到大量设备驱动提供的接口,通过应用程序来控制从设备。

     总线驱动

    4.1 概述

    I2C总线驱动是I2C适配器的软件实现,提供I2C适配器与从设备间完成数据通信的能力,比如起始,停止,应答信号和master_xfer的实现函数。

    I2C总线驱动由i2c_adapter和i2c_algorithm来描述

    4.2 S3c2440I2C控制器的硬件描述

    S3c2440处理器内部集成了一个I2C控制器,通过四个寄存器来进行控制:

    IICCON     I2C控制寄存器

    IICSTAT     I2C状态寄存器

    IICDS       I2C收发数据移位寄存器

    IICADD     I2C地址寄存器

    通过IICCON,IICDS,IICADD寄存器操作,可在I2C总线上产生开始位、停止位、数据和地址,而传输的状态则通过IICSTAT寄存器来获取。

    4.3 i2c-s3c2410总线驱动分析(platform_driver)

    I2C总线驱动代码在drivers/i2c/busses/i2c-s3c2410.c,这个代码同样支持s3c2410,s3c6410,s5pc110等Samsung 系列的芯片。

    初始化模块和卸载模块

    [cpp] view plaincopy
     
    1. static int __init i2c_adap_s3c_init(void)  
    2. {  
    3.          returnplatform_driver_register(&s3c24xx_i2c_driver);  
    4. }  
    5.    
    6. static void __exit i2c_adap_s3c_exit(void)  
    7. {  
    8.          platform_driver_unregister(&s3c24xx_i2c_driver);  
    9. }  

    总线驱动是基于platform来实现的,很符合设备驱动模型的思想。

    [cpp] view plaincopy
     
    1. static struct platform_drivers3c24xx_i2c_driver = {  
    2.          .probe                = s3c24xx_i2c_probe,  
    3.          .remove            = s3c24xx_i2c_remove,  
    4.          .id_table  = s3c24xx_driver_ids,  
    5.          .driver                = {  
    6.                    .owner     = THIS_MODULE,  
    7.                    .name       = "s3c-i2c",  
    8.                    .pm  = S3C24XX_DEV_PM_OPS,  
    9.                    .of_match_table= s3c24xx_i2c_match,  
    10.          },  
    11. };  

    s3c24xx_i2c_probe函数

    当调用platform_driver_register函数注册platform_driver结构体时,如果platformdevice 和 platform driver匹配成功后,会调用probe函数,来初始化适配器硬件。

    [cpp] view plaincopy
     
    1. static int s3c24xx_i2c_probe(structplatform_device *pdev)  
    2. {  
    3.          ……  
    4.          /*初始化适配器信息 */  
    5.          strlcpy(i2c->adap.name,"s3c2410-i2c", sizeof(i2c->adap.name));  
    6.          i2c->adap.owner   = THIS_MODULE;  
    7.          i2c->adap.algo    = &s3c24xx_i2c_algorithm;  
    8.          i2c->adap.retries= 2;  
    9.          i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;  
    10.          i2c->tx_setup     = 50;  
    11.    
    12.          /*初始化自旋锁和等待队列头 */  
    13.          spin_lock_init(&i2c->lock);  
    14.          init_waitqueue_head(&i2c->wait);  
    15.    
    16.          /*映射寄存器 */  
    17.          res= platform_get_resource(pdev, IORESOURCE_MEM, 0);  
    18.          i2c->ioarea= request_mem_region(res->start, resource_size(res),  
    19.                                                 pdev->name);  
    20.          i2c->regs= ioremap(res->start, resource_size(res));  
    21.    
    22.          /*设置I2C核心需要的信息 */  
    23.          i2c->adap.algo_data= i2c;  
    24.          i2c->adap.dev.parent= &pdev->dev;  
    25.    
    26.          /*初始化I2C控制器 */  
    27.          ret= s3c24xx_i2c_init(i2c);  
    28.    
    29.          /*申请中断 */  
    30.          i2c->irq= ret = platform_get_irq(pdev, 0);  
    31.          ret= request_irq(i2c->irq, s3c24xx_i2c_irq, 0,  
    32.                               dev_name(&pdev->dev), i2c);  
    33.    
    34.    /* 注册I2C适配器 */  
    35.          ret= i2c_add_numbered_adapter(&i2c->adap);  
    36.          ……  
    37. }  

    Probe主要工作是时能硬件并申请I2C适配器使用的IO地址,中断号等,然后向I2C核心添加这个适配器。I2c_adapter注册过程i2c_add_numbered_adapter->i2c_register_adapter

    I2C总线通信方法

    [cpp] view plaincopy
     
    1. static const struct i2c_algorithms3c24xx_i2c_algorithm = {  
    2.          .master_xfer             = s3c24xx_i2c_xfer,  
    3.          .functionality             = s3c24xx_i2c_func,  
    4. };  

    s3c24xx_i2c_xfer函数是总线通信方式的具体实现,依赖于s3c24xx_i2c_doxfer和s3c24xx_i2c_message_start两个函数;

    [cpp] view plaincopy
     
    1. static int s3c24xx_i2c_doxfer(structs3c24xx_i2c *i2c,  
    2.                                   struct i2c_msg *msgs, int num)  
    3. {  
    4.          ret =s3c24xx_i2c_set_master(i2c);  
    5.    
    6.          i2c->msg     = msgs;  
    7.          i2c->msg_num= num;  
    8.          i2c->msg_ptr= 0;  
    9.          i2c->msg_idx= 0;  
    10.          i2c->state   = STATE_START;  
    11.    
    12.          s3c24xx_i2c_message_start(i2c,msgs);  
    13. }  

    首先设置s3c I2C设备器为主设备,然后调用s3c24xx_i2c_message_start函数启动I2C消息传输。

    s3c24xx_i2c_func函数返回适配器所支持的通信功能。

    4.4 适配器的设备资源(platform_device)

    S3c2440的I2C总线驱动是基于platform来实现,前面我们分析了platformdriver部分,再来看下platform device部分。

    在arch/arm/plat-samsung/dev-i2c0.c文件中定义了platform_device结构体以及I2C控制器的资源信息:

    [cpp] view plaincopy
     
    1. static struct resource s3c_i2c_resource[] ={  
    2.          [0]= {  
    3.                    .start= S3C_PA_IIC,  
    4.                    .end   = S3C_PA_IIC + SZ_4K - 1,  
    5.                    .flags= IORESOURCE_MEM,  
    6.          },  
    7.          [1]= {  
    8.                    .start= IRQ_IIC,  
    9.                   .end  = IRQ_IIC,  
    10.                    .flags= IORESOURCE_IRQ,  
    11.          },  
    12. };  
    13.    
    14. struct platform_device s3c_device_i2c0 = {  
    15.          .name                 = "s3c2410-i2c",   /* 设备名 */  
    16. #ifdef CONFIG_S3C_DEV_I2C1  
    17.          .id               = 0,  
    18. #else  
    19.          .id               = -1,  
    20. #endif  
    21.          .num_resources         =ARRAY_SIZE(s3c_i2c_resource),  
    22.          .resource   =s3c_i2c_resource,  
    23. };  
    24.    
    25. struct s3c2410_platform_i2cdefault_i2c_data __initdata = {  
    26.          .flags                  = 0,  
    27.          .slave_addr      = 0x10,  /* I2C适配器的地址 */  
    28.          .frequency        = 100*1000,  /* 总线频率 */  
    29.          .sda_delay        = 100,   /* SDA边沿延迟时间ns */  
    30. };  
    31.    
    32. void __init s3c_i2c0_set_platdata(structs3c2410_platform_i2c *pd)  
    33. {  
    34.          structs3c2410_platform_i2c *npd;  
    35.    
    36.          if(!pd)  
    37.                    pd= &default_i2c_data;  
    38.    
    39.          npd= s3c_set_platdata(pd, sizeof(struct s3c2410_platform_i2c),  
    40.                                    &s3c_device_i2c0);  
    41.    
    42.          if(!npd->cfg_gpio)  
    43.                    npd->cfg_gpio= s3c_i2c0_cfg_gpio;  
    44. }  

    在板文件中把platform_device注册进内核:

    [cpp] view plaincopy
     
    1. static struct platform_device*mini2440_devices[] __initdata = {  
    2.          ……  
    3.          &s3c_device_i2c0,  
    4. ……  
    5. };  

    调用s3c_i2c0_set_platdata 函数把适配器具体的数据赋值给dev.platform_data:

    [cpp] view plaincopy
     
    1. static void __init mini2440_init(void)  
    2. {  
    3.          ……  
    4. s3c_i2c0_set_platdata(NULL);  
    5. }  

    I2C总线驱动就分析到这里。

  • 相关阅读:
    Js计算时间差(天、小时、分钟、秒)
    [原创]chromium源码阅读-进程间通信IPC.消息的接收与应答
    loki之内存池SmallObj[原创]
    A Cross-Platform Memory Leak Detector
    UML Diagrams Using Graphviz Dot
    My Emacs Writing Setup
    Drawing Graphs using Dot and Graphviz
    SHFileOperation的用法
    latex中文模板
    C++ Design Pattern: What is a Design Pattern?
  • 原文地址:https://www.cnblogs.com/chd-zhangbo/p/5199224.html
Copyright © 2011-2022 走看看