I2C子系统详解1——I2C总线设备的驱动框架

以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。

参考博客

I2C总线驱动框架详解

linux内核I2C子系统详解

一、I2C总线的物理特征

这部分内容的简介可见博客:SPI、I2C、UART(即串口)三种串行总线详解。

(1)通信线数目:两根,即SCL、SDA。

(2)通信的特点:同步、串行、电平、低速(几百k)、近距离。

(3)总线式结构:支持多个设备挂接在同一条总线上。

(4)主从式结构:通信双方必须一个为主设备,一个为从设备,主设备掌握通信的主动权,从设备按照主设备的节奏被动响应。每个从设备在总线中有唯一的地址,主设备通过从地址找到自己要通信的从设备(本质是广播)。

(5)I2C总线的用途:用于主SoC和外围设备之间的通信。常见的各种物联网传感器芯片(如gsensor、温度、湿度、光强度、酸碱度、烟雾浓度、压力等)均使用I2C接口和主SoC进行连接。

(6)I2C总线的最大优势:支持在总线上扩展多个外围设备。

(7)举例,电容触摸屏芯片的I2C接口:电容触摸屏芯片的多个引脚构成2个接口。其中一个接口是I2C接口,电容触摸屏芯片通过该接口与主SoC连接,此时触摸屏作为从设备。主SoC通过该接口初始化及控制电容触摸屏芯片,而芯片通过该接口向SoC汇报触摸事件的信息。我们使用电容触摸屏时重点关注的是这个接口。另一个接口是电容触摸屏的管理接口,电容触摸屏芯片通过该接口来控制触摸板硬件。该接口是电容触摸屏公司关心的,触摸屏芯片内部固件编程要处理这部分。我们使用电容触摸屏的人不需要关心这些内容。

二、I2C总线设备的驱动框架

I2C总线设备的驱动框架,或者说“I2C子系统”,其设计目的是让驱动开发者可以在内核中方便地添加自己的I2C设备的驱动程序,从而可以更容易地在linux下驱动I2C设备。

I2C总线设备的驱动框架内部关系如下:

1、驱动框架的组成部分

(1)I2C设备驱动层(I2C_client,I2C_driver)

和具体I2C接口的外设相关,每种外设都有自己的专属I2C驱动代码。

包括两部分:I2C从设备的注册、I2C设备驱动的注册。

(2)I2C核心层(I2C_core)

I2C核心提供了I2C总线驱动和I2C设备驱动的注册、匹配与注销方法,I2C通信方法,上层中与具体硬件无关的代码,以及探测设备检测设备地址的上层代码等。换言之,管理I2C驱动和I2C设备的注册、匹配,实现I2C的通信方法,是对I2C通信的抽象框架,与具体硬件无关。

(3)I2C总线驱动层(I2C_adapter、I2C_algorithm)

或者说I2C适配器层。这里说的I2C适配器,也就是I2C主设备,对应着Soc的I2C控制器,把I2C控制器看做一个设备,实现I2C控制器的驱动代码,和具体的Soc相关。

I2C总线驱动是I2C适配器的软件实现,或者说是SoC中内置的I2C控制器的软件抽象,可以将其理解为I2C主设备,它提供了I2C适配器与从设备间数据通信的功能。

I2C总线驱动用 I2C_adapter 和 I2C_algorithm 来描述I2C适配器。

2、I2C相关的驱动文件

源码中与I2C相关的驱动均位于drivers/i2c目录,包括的内容如下:

 (1)I2C设备驱动层相关的文件

x210开发板的电容触摸屏gslX680采用I2C接口,因此以这个I2C设备为例进行分析。其对应的驱动源代码文件是x210_kernel\drivers\input\touchscreen\gslX680.c文件。它由触摸屏IC原厂工程师提供,代码中涉及到很多触摸屏专业方面的知识,但无需理会。

gslX680.c文件进行了I2C设备驱动的注册,相应的I2C设备注册是在mach-x210.c文件中。

(2)I2C核心层相关的文件

I2C核心层相关的文件是i2c-core.c文件,它由内核开发者提供,和具体的硬件操作无关。

(3)I2C总线驱动层相关的文件

algos目录:存放的是I2C通信的算法(主要是时序等内容)。

busses目录:存放的是各种已经编写好的、将来要向i2c核心层注册的适配器文件。

我们主要分析drivers\i2c\busses\i2c-s3c2410.c文件

3、驱动实现的两种方式

I2C驱动有两种实现方法:

(1)第一种方式对应于drivers/i2c/i2c-dev.c文件

这种方法只是对主设备(一般是SoC中内置的I2C控制器)的I2C基本操作进行封装,并且向应用层提供相应的操作接口,应用层需要编写代码来实现对从设备的控制和操作。

这种I2C驱动,只是给应用层提供了可以访问从设备的接口,本身没有对硬件做任何操作。应用需要实现对硬件的操作,因此写应用的人必须对硬件非常了解。其实实这就相当于在应用层完成传统的驱动的工作内容,所以这种I2C驱动又叫做“应用层驱动”。

它的优势是把差异化都放在应用中,这样在设备比较难缠(尤其是slave是非标准I2C时)时不用修改驱动,只需要修改应用就可以实现对各种设备的驱动。这种驱动在驱动层很简单,但并不主流这里不进行分析

(2)第二种方式将I2C驱动的所有代码都放在驱动层实现(直接向应用层提供最终结果)

这种实现方法中,应用层不需要知道这里面有I2C存在。比如电容式触摸屏驱动,直接向应用层提供了/dev/input/event1的操作接口,应用层编程的人根本不知道event1中涉及到I2C。这种实现方法是我们后续分析的重点。

4、相关的结构体

(1)struct i2c_adapter(I2C适配器)

struct i2c_adapter结构体用来描述一个 I2C适配器,在SoC中指的就是I2C控制器。

当向I2C核心层注册一个I2C适配器时,就需要提供这样的一个结构体变量,换另外一颗SoC则需要修改该结构体变量。

struct i2c_adapter {struct module *owner;             // 所有者unsigned int id;unsigned int class;               // 该适配器支持的从设备的类型const struct i2c_algorithm *algo; // 该适配器与从设备的通信算法void *algo_data;/* data fields that are valid for all devices    */struct rt_mutex bus_lock;int timeout;              // 超时时间int retries;struct device dev;        // 该适配器设备对应的deviceint nr;                   // 适配器的编号char name[48];            // 适配器的名字struct completion dev_released;//用来挂接(与适配器匹配成功的)从设备i2c_client的一个链表头struct list_head userspace_clients;  };

(2)struct i2c_algorithm结构体

struct i2c_algorithm结构体用来描述主设备和从设备通信的算法(主要是时序等内容),它与主设备、从设备都有关系。在构建i2c_adapter结构体变量的时候会去填充这个元素。

struct i2c_algorithm {/* If an adapter algorithm can't do I2C-level access, set master_xferto NULL. If an adapter algorithm can do SMBus access, setsmbus_xfer. If set to NULL, the SMBus protocol is simulatedusing common I2C messages *//* master_xfer should return the number of messages successfullyprocessed, or a negative value on error */int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,int num);int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,unsigned short flags, char read_write,u8 command, int size, union i2c_smbus_data *data);/* To determine what the adapter supports */u32 (*functionality) (struct i2c_adapter *);
};

注意,smbus协议是从I2C协议的基础上发展而来的,他们之间有很大的相似度,SMBus与I2C总线之间在时序特性上存在一些差别,应用于移动PC和桌面PC系统中的低速率通讯。

(3)struct i2c_client结构体

该结构体用来描述一个I2C从设备。

​struct i2c_client {    //  用来描述一个i2c从设备unsigned short flags;        //  描述i2c从设备特性的标志位unsigned short addr;         //  i2c 从设备的地址char name[I2C_NAME_SIZE];    //  i2c从设备的名字struct i2c_adapter *adapter; //  指向与从设备匹配成功的适配器struct i2c_driver *driver;   //  指向与从设备匹配成功的设备驱动struct device dev;           //  该从设备对应的deviceint irq;                     //  从设备的中断引脚struct list_head detected;   //  作为一个链表节点挂接到(与它匹配成功的)i2c_driver 相应的链表头上
};​

(4)struct i2c_driver结构体

该结构体代表一个I2C从设备的驱动。

struct i2c_driver {    // 代表一个i2c设备驱动unsigned int class;      // i2c设备驱动所支持的i2c设备的类型/* Notifies the driver that a new bus has appeared or is about to be* removed. You should avoid using this if you can, it will probably* be removed in a near future.*/int (*attach_adapter)(struct i2c_adapter *);   // 用来匹配适配器的函数int (*detach_adapter)(struct i2c_adapter *);/* Standard driver model interfaces */
// 设备驱动层的probe函数int (*probe)(struct i2c_client *, const struct i2c_device_id *); int (*remove)(struct i2c_client *);       // 设备驱动层卸载函数/* driver model interfaces that don't relate to enumeration  */void (*shutdown)(struct i2c_client *);int (*suspend)(struct i2c_client *, pm_message_t mesg);int (*resume)(struct i2c_client *);/* Alert callback, for example for the SMBus alert protocol.* The format and meaning of the data value depends on the protocol.* For the SMBus alert protocol, there is a single bit of data passed* as the alert response's low bit ("event flag").*/void (*alert)(struct i2c_client *, unsigned int data);/* a ioctl like command that can be used to perform specific functions* with the device.*/int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);struct device_driver driver;      //  该i2c设备驱动所对应的device_driverconst struct i2c_device_id *id_table;  //设备驱动层用来匹配设备的id_table/* Device detection callback for automatic device creation */int (*detect)(struct i2c_client *, struct i2c_board_info *);const unsigned short *address_list;    //  该设备驱动支持的所有次设备的地址数组//  用来挂接与该i2c_driver匹配成功的i2c_client (次设备)的一个链表头struct list_head clients;                
};

(5)struct i2c_board_info结构体

这个结构体用来描述板子上的一个i2c设备的信息,一般用来对struct i2c_client结构体变量的成员进行赋值?

struct i2c_board_info {      //  这个结构体是用来描述板子上的一个i2c设备的信息char        type[I2C_NAME_SIZE];    //  i2c 设备的名字,用来初始化i2c_client.nameunsigned short    flags;            //  用来初始化i2c_client.flagsunsigned short    addr;             //  用来初始化 i2c_client.addrvoid        *platform_data;         //  用来初始化 i2c_client.dev.platform_datastruct dev_archdata    *archdata;   //  用来初始化i2c_client.dev.archdata
#ifdef CONFIG_OFstruct device_node *of_node;
#endifint        irq;                     //  用来初始化i2c_client.irq
};

(6)struct i2c_devinfo结构体

struct i2c_devinfo {struct list_head    list;   // 作为一个链表节点挂接到__i2c_board_list 链表上去int            busnum;       // 适配器的编号struct i2c_board_info    board_info; //  内置的i2c_board_info 结构体
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/461139.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

神经网络编程入门

本文主要内容包括: (1) 介绍神经网络基本原理, (2) AForge.NET实现前向神经网络的方法, (3) Matlab实现前向神经网络的方法 。 第0节、引例 本文以Fisher的Iris数据集作为神经网络程序的测试数据集。Iris数据集可以在http://en.wikipedia.or…

软考复习之路—组成原理

计算机系统的基础知识应该是作为一个编程人员必备的一门课程,仅仅有了解了计算机的组成,程序在计算 机中的存储状态,运算等基本内容,我们才干继续对计算机有更深层次的认识,更easy学习与上手。比方说要 想学习操作系统…

python内存管理机制错误_Python内存管理机制和垃圾回收机制的简单理解

一、内存管理机制1.由c开发出来的cpython2.include / objests3.需要下载python源码包4.Pyobject:floatPyVarObject:5.在python中所有东西创建对象的时候,内部都会存储一个数据// 维护双向链表struct _object *_ob_next;struct _object *_ob_p…

求背包问题所有解(C++实现)

这是我学习数据结构时的一道上机作业&#xff0c;那时还没养成写注释的习惯&#xff0c;所以各位得受点苦了。 只是简易背包问题。 代码&#xff1a; 展开 1 // 背包问题所有解2 // 作者:王锦 3 // 邮箱:jinkswvip.qq.com4 5 #include "stdafx.h"6 #include <iost…

JAVA--自制斐波那契数列输出

累了&#xff0c;写点简单的。 1 public class hello {2 3 /**4 * param args5 */6 public static void main(String[] args) {7 int Fabnum 10;8 int sum 0;9 System.out.print("Serial:\t"); 10 for(int i 1…

9、C语言 —— 指针的用处

为什么80%的码农都做不了架构师&#xff1f;>>> 1、用函数实现两个数的交换 ‍‍在没用函数之前&#xff0c;可以这样实现‍‍#include <stdio.h>int main() {int a 3;int b 7;int c;printf("交换前&#xff0c;a%d&#xff0c;b%d\n", a, b); …

java动态代理二cglib

2019独角兽企业重金招聘Python工程师标准>>> java动态代理 转载于:https://my.oschina.net/u/1430510/blog/290215

中断的上下半部

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 前言 因为输入类设备的输入都是异步事件&#xff0c;因此一般使用中断来处理和响应。 中断处理程序处于中断上下文中&#xff0c;不能和用户空间数据交互&#xff08;不能使用copy_to(from)_usr函数…

图片播放器小项目(详解)

以下内容源于朱有鹏《物联网大讲堂》课程的学习整理&#xff0c;如有侵权&#xff0c;请告知删除。一、开始动手写代码 1、Makefile介绍 &#xff08;1&#xff09;这是一个通用的项目管理的Makefile体系&#xff0c;自己写的&#xff08;有子文件夹组织的&#xff09;项目可以…

Telnet远程访问思科交换机、路由器

一、实验目的Telnet远程访问思科交换机、路由器二、实验拓扑三、实验步骤1、PC1远程管理S11&#xff09;配置交换机的管理IPS1(config)#int vlan 1S1(config-if)#ip add 192.168.1.100 255.255.255.0S1(config-if)#no shu2&#xff09;开启S1的telnet远程管理服务S1(config)#li…

[置顶]       cocos2d-x 手游源码站

尊重开发者的劳动成果&#xff0c;转载的时候请务必注明出处&#xff1a;http://blog.csdn.net/haomengzhu/article/details/37829061 1、魔幻方块 链接&#xff1a;魔幻方块源码关键词&#xff1a;魔幻方块源码 源代码 Cocos2d-x2.0 游戏源码 益智 休闲 游戏 游戏类型&#xf…

Android SDK开发包国内下载地址

原帖地址&#xff1a;http://www.cnblogs.com/bjzhanghao/archive/2012/11/14/2769409.html 不知道是因为最近kaihui还是怎么的&#xff0c;打开android sdk官方网站特别的慢&#xff0c;想下载最新版本的platform几乎变成不可能完成的任务&#xff0c;不知道为什么Google不像…

SharePoint 2013 Workflow - Advanced Workflow Debugging with Fiddler

来自&#xff1a;Andrew Connell [MVP SharePoint] | 时间&#xff1a;2012-07-18 19:26:30 原文链接&#xff1a; http://www.andrewconnell.com/blog/archive/2012/07/18/sharepoint-2013-workflow-advanced-workflow-debugging-with-fiddler.aspx In previous posts Iv…

java sheet 打印区域设定,如何使用Java设置电子表格的打印区域。(How to set the print area of a spreadsheet using Java.)...

如何使用Java设置电子表格的打印区域。(How to set the print area of a spreadsheet using Java.)问题描述 (Problem Description)如何使用Java设置电子表格的打印区域。解决方案 (Solution)以下是使用Java设置电子表格打印区域的程序。import java.io.File;import java.io.Fi…

RedHat6.2 x86手动配置LNMP环境

为什么80%的码农都做不了架构师&#xff1f;>>> 因为公司要求用RedHat配&#xff0c;顺便让我练习一下Linux里面的操作什么的。 折腾来折腾去终于搞好了&#xff0c;其实也没那么难嘛。但是也要记录一下。 首先&#xff0c;是在服务器里面用VMware搭建的RedHat6.2 …

《c语言深度剖析》读书笔记

一、注意点 1、 2、 3、 4、 5、 6、 7、 8、 9、 10、 11、 二、问题 1、 2、 3、 4、 5、 6、 7、

androidpn的一次亲密接触(二)

简单看了一下源码的实现&#xff0c;这里贴一点个人觉得比叫重要的代码。 XmppManager.java 构造方法&#xff1a;Java代码public XmppManager(NotificationService notificationService) 在这里主要是从共享引用中取得xmpp服务器地址和端口号、用户名和密码。 内部类Java代码…

指针知识学习[总]

printf("p %p.\n", p); // %p打印指针和%x打印指针&#xff0c;打印出的值是一样的 printf("p 0x%x.\n", p); 一、指针是什么&#xff1f; 1、指针变量和普通变量的区别 指针的实质就是个变量&#xff0c;它跟普通变量没有任何本质区别。指针完整的名字…

php excel 分页,excel分页线怎么增加

增加excel分页线的方法&#xff1a;首先依次点击“工作簿视图-分页预览”&#xff1b;然后点击要在其下方插入分页符的这一行&#xff1b;最后在“页面布局”选项卡上的“页面设置”组中&#xff0c;单击“分隔符”即可。本文操作环境&#xff1a;Windows7系统&#xff0c;Micr…

C# 中的委托和事件

PDF 浏览&#xff1a;http://www.tracefact.net/Document/Delegates-and-Events-in-CSharp.pdf文中代码在VS2005下通过&#xff0c;由于VS2003(.Net Framework 1.1)不支持隐式的委托变量&#xff0c;所以如果在一个接受委托类型的位置直接赋予方法名&#xff0c;在VS2003下会报…