• i2c子系统



    linux内核的I2C驱动框架总览
    (1)I2C驱动框架的主要目标是:让驱动开发者可以在内核中方便的添加自己的I2C设备的驱动程序,从而可以更容易的在linux下驱动自己的I2C接口硬件
    (2)源码中I2C相关的驱动均位于:drivers/i2c目录下。linux系统提供2种I2C驱动实现方法:

    第一种叫i2c-dev,对应drivers/i2c/i2c-dev.c,这种方法只是封装了主机(I2C master,一般是SoC中内置的I2C控制器)的I2C基本操作,并且向应用层提供相应的操作接口,应用层代码需要自己去实现对slave的控制和操作,所以这种I2C驱动相当于只是提供给应用层可以访问slave硬件设备的接口,本身并未对硬件做任何操作,应用需要实现对硬件的操作,因此写应用的人必须对硬件非常了解,其实相当于传统的驱动中干的活儿丢给应用去做了,所以这种I2C驱动又叫做“应用层驱动”,这种方式并不主流,它的优势是把差异化都放在应用中,这样在设备比较难缠(尤其是slave是非标准I2C时)时不用动驱动,而只需要修改应用就可以实现对各种设备的驱动。这种驱动在驱动层很简单(就是i2c-dev.c)我们就不分析了。

    第二种I2C驱动是所有的代码都放在驱动层实现,直接向应用层提供最终结果。应用层甚至不需要知道这里面有I2C存在,譬如电容式触摸屏驱动,直接向应用层提供/dev/input/event1的操作接口,应用层编程的人根本不知道event1中涉及到了I2C。这种是我们后续分析的重点。


    I2C子系统的4个关键结构体
    (1)struct i2c_adapter                   I2C适配器,用来描述I2C控制器的
    (2)struct i2c_algorithm                I2C算法(时序)
    (3)struct i2c_client I2C              (从机)设备信息
    (4)struct i2c_driver I2C             (从机)设备驱动

    关键文件
    (1)i2c-core.c
    (2)busses目录
    (3)algos目录


    i2c-core.c初步分析
    (1)smbus代码略过
    (2)模块加载和卸载:bus_register(&i2c_bus_type);

    I2C总线的匹配机制
    (1)match函数
    (2)probe函数
    总结:I2C总线上有2条分支:i2c_client链和i2c_driver链,当任何一个driver或者client去注册时,I2C总线都会调用match函数去对client.name和driver.id_table.name进行循环匹配。如果driver.id_table中所有的id都匹配不上则说明client并没有找到一个对应的driver,没了;如果匹配上了则标明client和driver是适用的,那么I2C总线会调用自身的probe函数,自身的probe函数又会调用driver中提供的probe函数,driver中的probe函数会对设备进行硬件初始化和后续工作。

    核心层开放给其他部分的注册接口
    (1)i2c_add_adapter/i2c_add_numbered_adapter 注册adapter的
    (2)i2c_add_driver 注册driver的
    (3)i2c_new_device 注册client的

    adapter模块的注册(drivers/i2c/busses/i2c-s3c2410.c为例)
    (1)平台总线方式注册
    (2)找到driver和device,并且确认其配对过程
    (3)probe函数

    probe函数分析
    (1)填充一个i2c_adapter结构体,并且调用接口去注册之
    (2)从platform_device接收硬件信息,做必要的处理(request_mem_region & ioremap、request_irq等)
    (3)对硬件做初始化(直接操作soc内部I2C控制器的寄存器)

    i2c_algorithm
    (1)i2c->adap.algo = &s3c24xx_i2c_algorithm;
    (2)functionality
    (3)s3c24xx_i2c_doxfer


    i2c_driver的注册
    (1)以gslX680的驱动为例
    (2)i2c_driver的基本分析:name和probe

    i2c_client从哪里来
    (1)直接来源:i2c_register_board_info
    smdkc110_machine_init
    i2c_register_board_info

    struct i2c_board_info {
    char type[I2C_NAME_SIZE]; // 设备名
    unsigned short flags; // 属性
    unsigned short addr; // 设备从地址
    void *platform_data; // 设备私有数据
    struct dev_archdata *archdata;
    #ifdef CONFIG_OF
    struct device_node *of_node;
    #endif
    int irq; // 设备使用的IRQ号,对应CPU的EINT
    };

    (2)实现原理分析
    内核维护一个链表 __i2c_board_list,这个链表上链接的是I2C总线上挂接的所有硬件设备的信息结构体。也就是说这个链表维护的是一个struct i2c_board_info结构体链表。
    真正的需要的struct i2c_client在别的地方由__i2c_board_list链表中的各个节点内容来另外构建生成。

    函数调用层次:
    i2c_add_adapter/i2c_add_numbered_adapter
    i2c_register_adapter
    i2c_scan_static_board_info
    i2c_new_device
    device_register

    总结:I2C总线的i2c_client的提供是内核通过i2c_add_adapter/i2c_add_numbered_adapter接口调用时自动生成的。

    gslX680驱动的移植实践
    初步移植实验
    (1)源码获取
    (2)源码加入内核中
    (3)mach文件中添加board_info
    (4)编译后内核去启动
    在内核配置中添加CONFIG项
    (1)定义一个宏名,譬如CONFIG_TOUCHSCREEN_GSLX680
    (2)在代码中使用宏来条件编译
    (3)在Makefile中使用宏来条件配置
    (4)在Kconfig项目中添加宏的配置项
    (5)make menuconfig并选择Y或者N

  • 相关阅读:
    Oracle的rownum原理和使用
    ehcache 使用笔记
    @PostConstruct 注解
    Dubbo java.io.IOException: Can not lock the registry cache file
    java 学习 todoList
    因为本地没有配置 localhost 导致的 eclipse 的奇葩问题
    cheatsheet——mac 上的一款可以显示软件所有快捷键的小工具
    对象作为 map 的 key 时,需要重写 equals 方法和 hashCode 方法
    eclipse一直报An internal error occurred during: "Building workspace". GC overhead limit exceeded
    如何修改SVN客户端中保存的密码
  • 原文地址:https://www.cnblogs.com/zhangshuaifeng/p/10667065.html
Copyright © 2020-2023  润新知