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总线驱动就分析到这里。

  • 相关阅读:
    Android 按键消息处理Android 按键消息处理
    objcopy
    SQLite多线程读写实践及常见问题总结
    android动画坐标定义
    Android动画效果translate、scale、alpha、rotate
    Android公共库(缓存 下拉ListView 下载管理Pro 静默安装 root运行 Java公共类)
    Flatten Binary Tree to Linked List
    Distinct Subsequences
    Populating Next Right Pointers in Each Node II
    Populating Next Right Pointers in Each Node
  • 原文地址:https://www.cnblogs.com/chd-zhangbo/p/5199224.html
Copyright © 2011-2022 走看看