实例解析linux内核I2C体系结构(2)
Linux下I2C驱动介绍

1、I2C概述I2C是philips公司提供的外设总线,I2C有两条数据线,一条是串行数据线SDA、一条是时钟线SCL,使用SDA和SCL实现了数据的交换,便于布线。
I2C总线方便用在EEPROM、实时钟、小型LCD等与CPU外部的接口上。
2、Linux下的驱动思路Linux系统下编写I2c驱动主要有两种方法:一种是把I2C当做普通字符设备来使用;另一种利用Linux下驱动的体系结构来实现。
第一种方法:优点:思路比较直接,不用花费大量时间去了解Linux系统下I2C体系结构缺点:不仅对I2C设备操作要了解,还有了解I2C的适配器操作不仅对I2C设备器和设备操作需要了解,编写的驱动移植性差,内核提供的I2C设备器都没有用上。
第二种方法:第一种的优点就是第二种的缺点,第一种的缺点就是第二种的优点。
3、I2C框架概述Linux的I2C体系结构分为3部分:1)I2C核心I2C核心提供了I2C总线驱动和设备驱动的注册和注销的方法,I2C 通信方法(algorithm)上层,与具体适配器无关的代码,检测设备上层的代码等。
2)I2C总线驱动I2C总线驱动是对I2C硬件体系结构中适配器端的实现,适配器可以直接受CPU来控制。
3)I2C设备驱动I2C设备驱动是对I2C硬件体系结构中设备端的实现,设备端挂在受CPU控制的适配器上,通过I2C适配器与CPU交换数据。
Linux下的I2C体系结构:1)Linux下的I2C体系结构4、I2C设备驱动编写方法首先让我们明白适配器驱动的作用是让我们能够通过它发出标准的I2C时序,在linux内核源代码中driver/I2C/buss包含一些适配器的驱动,例如s3c2410的驱动I2C-s3c2410.c,适配器被加载到内核中,接下的任务就是实现设备驱动的编写。
编写设备驱动的方法主要分为两种方法:第一种:利用设备提供的I2C-dev.c来实现I2C适配器设备文件,然后通过上层应用程序来操作I2C设备器来控制I2C设备。
I2C详解——精选推荐

I2C详解1、基本概念主机初始化发送,产⽣时钟信号和终⽌发送的器件从机被主机寻址的器件发送器发送数据到总线的器件接收器从总线接收数据的器件多主机同时有多于⼀个主机尝试控制总线但不破坏报⽂仲裁是⼀个在有多个主机同时尝试控制总线,但只允许其中⼀个控制总线并使报⽂不被破坏的过程同步两个或多个器件同步时钟信号的过程2、硬件结构每⼀个I2C总线器件内部的SDA、SCL引脚电路结构都是⼀样的,引脚的输出驱动与输⼊缓冲连在⼀起。
其中输出为漏极开路的场效应管、输⼊缓冲为⼀只⾼输⼊阻抗的同相器。
这种电路具有两个特点:(1)由于SDA、SCL 为漏极开路结构,借助于外部的上拉电阻实现了信号的“线与”逻辑;(2)引脚在输出信号的同时还将引脚上的电平进⾏检测,检测是否与刚才输出⼀致。
为“时钟同步”和“总线仲裁”提供硬件基础。
3、时钟同步如果从机希望主机降低传送速度可以通过将SCL主动拉低延长其低电平时间的⽅法来通知主机,当主机在准备下⼀次传送发现SCL的电平被拉低时就进⾏等待,直⾄从机完成操作并释放SCL线的控制控制权。
这样以来,主机实际上受到从机的时钟同步控制。
可见SCL 线上的低电平是由时钟低电平最长的器件决定;⾼电平的时间由⾼电平时间最短的器件决定。
这就是时钟同步,它解决了I2C总线的速度同步问题。
4、主机发送数据流程(1)主机在检测到总线为“空闲状态”(即SDA、SCL 线均为⾼电平)时,发送⼀个启动信号“S”,开始⼀次通信的开始(2)主机接着发送⼀个命令字节。
该字节由7 位的外围器件地址和1 位读写控制位R/W 组成(此时R/W=0)(3)相对应的从机收到命令字节后向主机回馈应答信号ACK(ACK=0)(4)主机收到从机的应答信号后开始发送第⼀个字节的数据(5)从机收到数据后返回⼀个应答信号ACK(6)主机收到应答信号后再发送下⼀个数据字节(7)当主机发送最后⼀个数据字节并收到从机的ACK 后,通过向从机发送⼀个停⽌信号P结束本次通信并释放总线。
linux下iic(i2c)读写AT24C02

/jammy_lee/linux下iic(i2c)读写AT24C02linux驱动2010-02-09 16:02:03 阅读955 评论3 字号:大中小订阅linux内核上已有iic的驱动,因此只需要对该iic设备文件进行读写则能够控制外围的iic器件。
这里以AT24C02为对象,编写一个简单的读写应用程序。
iic设备文件在我的开发板上/dev/i2c/0 ,打开文件为可读写。
AT24C02的器件地址为0x50 ,既是iic总线上从器件的地址,每次只读写一字节数据。
/************************************************************///文件名:app_at24c02.c//功能:测试linux下iic读写at24c02程序//使用说明: (1)// (2)// (3)// (4)//作者:jammy-lee//日期:2010-02-08/************************************************************///包含头文件#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/ioctl.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <sys/select.h>#include <sys/time.h>#include <errno.h>//宏定义#define Address 0x50 //at24c02地址#define I2C_RETRIES 0x0701#define I2C_TIMEOUT 0x0702#define I2C_SLAVE 0x0703 //IIC从器件的地址设置#define I2C_BUS_MODE 0x0780typedef unsigned char uint8;uint8 rbuf[8] = {0x00}; //读出缓存uint8 wbuf[8] = {0x01,0x05,0x06,0x04,0x01,0x01,0x03,0x0d}; //写入缓存int fd = -1;//函数声明static uint8 AT24C02_Init(void);static uint8 i2c_write(int fd, uint8 reg, uint8 val);static uint8 i2c_read(int fd, uint8 reg, uint8 *val);static uint8 printarray(uint8 Array[], uint8 Num);//at24c02初始化static uint8 AT24C02_Init(void){fd = open("/dev/i2c/0", O_RDWR); //允许读写if(fd < 0){perror("Can't open /dev/nrf24l01 \n"); //打开iic设备文件失败exit(1);}printf("open /dev/i2c/0 success !\n"); //打开iic设备文件成功if(ioctl(fd, I2C_SLAVE, Address)<0) { //设置iic从器件地址printf("fail to set i2c device slave address!\n");close(fd);return -1;}printf("set slave address to 0x%x success!\n", Address);if(ioctl(fd, I2C_BUS_MODE, 1)<0) //设置iic总线模式printf("set bus mode fail!\n");elseprintf("set bus mode ok!\n");return(1);}/*uint8 AT24C02_Write(uint8 *nData, uint8 Reg, uint8 Num){write(fd, &Reg, 1); //usleep(100); //延时100uswrite(fd, nData, Num);usleep(1000*4); //延时4msreturn(1);}uint8 AT24C02_Read(uint8 nData[], uint8 Reg, uint8 Num) {write(fd, &Reg, 1);usleep(100); //延时100usread(fd, nData, Num);usleep(1000*4); //延时4msreturn(1);}*///at24c02写入一字节static uint8 i2c_write(int fd, uint8 reg, uint8 val){int retries;uint8 data[2];data[0] = reg;data[1] = val;for(retries=5; retries; retries--) {if(write(fd, data, 2)==2)return 0;usleep(1000*10);}return -1;}//at24c02读取一字节static uint8 i2c_read(int fd, uint8 reg, uint8 *val){int retries;for(retries=5; retries; retries--)if(write(fd, ®, 1)==1)if(read(fd, val, 1)==1)return 0;return -1;}//输出数组static uint8 printarray(uint8 Array[], uint8 Num) {uint8 i;for(i=0;i<Num;i++){printf("Data [%d] is %d \n", i ,Array[i]);}return(1);}//主函数int main(int argc, char *argv[]){int i;AT24C02_Init();usleep(1000*100);for(i=0; i<sizeof(rbuf); i++)if(i2c_read(fd, i, &rbuf[i]))break;printarray(rbuf ,8);printf("Before Write Data \n"); sleep(1);for(i=0; i<sizeof(rbuf); i++)if(i2c_write(fd, i, wbuf[i]))break;printarray(wbuf ,8);printf("Writing Data \n");sleep(1);for(i=0; i<sizeof(rbuf); i++)if(i2c_read(fd, i, &rbuf[i]))break;printarray(rbuf ,8);printf("After Write Data \n");close(fd);}。
I2C总线原理及应用实例

I2C总线原理及应用实例I2C总线是一种串行通信总线,全称为Inter-Integrated Circuit,是Philips(飞利浦)公司在1982年推出的一种通信协议。
它可以用于连接各种集成电路(Integrated Circuits,ICs),如处理器、传感器、存储器等。
I2C总线的原理是基于主从架构。
主设备(Master)负责生成时钟信号,并发送和接收数据,从设备(Slave)通过地址识别和响应主设备的命令。
I2C总线使用两根线来传输数据,一根是时钟线(SCL),用于主设备生成的时钟信号;另一根是数据线(SDA),用于双向传输数据。
1. 主设备发送起始位(Start)信号,将SDA线从高电平拉低;然后通过SCL线发送时钟信号,用于同步通信。
2.主设备发送从设备的地址,从设备通过地址识别确定是否响应。
3.主设备发送要传输的数据到从设备,从设备响应确认信号。
4. 主设备可以继续发送数据,或者发送停止位(Stop)信号结束通信。
停止位是将SDA线从低电平拉高。
1.温度监测器:I2C总线可以连接到温度传感器上,通过读取传感器的输出数据,进行温度的监测和控制。
主设备可以设置警报阈值,当温度超过阈值时,可以触发相应的措施。
2.显示屏:很多智能设备上的显示屏都采用了I2C总线,如液晶显示屏(LCD)或有机发光二极管(OLED)等。
主设备通过I2C总线发送要显示的信息,并控制显示效果,如亮度、对比度、清晰度等参数。
3.扩展存储器:I2C总线可以用于连接外部存储器,如电子存储器(EEPROM)。
通过I2C总线,可以读取和写入存储器中的数据,实现数据的存储和传输。
4.触摸屏控制器:许多触摸屏控制器也使用了I2C总线,主要用于将触摸信号传输给主设备,并接收主设备的命令。
通过I2C总线,可以实现对触摸屏的操作,如单击、滑动、缩放等。
5.电源管理器:一些电源管理器也采用了I2C总线,用于控制和监测电池电量、充电状态、电压、电流等参数。
i2c的基本工作原理

I2C(Inter-Integrated Circuit)是一种串行通信协议,用于在芯片之间进行数据传输。
它由飞利浦半导体(现在的恩智浦半导体)于1982年开发,并广泛应用于各种电子设备中。
I2C具有简单、高效和可靠的特点,成为众多芯片和模块之间常用的通信接口之一。
本文将详细介绍I2C的基本工作原理。
一、总线架构I2C采用了主从结构的总线架构,其中主设备(Master)负责发起数据传输请求,而从设备(Slave)则在接收到请求后进行响应。
一个I2C总线上可以连接多个从设备,每个从设备都有一个唯一的地址。
主设备通过发送起始信号(Start)来启动通信,然后选择要与之通信的从设备地址,最后发送停止信号(Stop)结束通信。
二、物理层I2C使用双线制进行数据传输,包括数据线(SDA)和时钟线(SCL)。
数据线上的信号是双向的,用于传输数据。
时钟线则由主设备控制,用于同步数据传输。
三、起始和停止信号I2C通信以起始信号(Start)和停止信号(Stop)来标识通信的开始和结束。
起始信号由主设备产生,它表示将要发起一次新的通信。
停止信号同样由主设备产生,表示一次通信的结束。
四、数据传输格式I2C采用了基于字节的数据传输格式。
每个字节都由8位二进制数据组成,包括7位数据位和1位数据方向位。
数据方向位为0表示发送数据,为1表示接收数据。
在每个字节的传输过程中,都会先发送数据方向位,然后再发送数据位。
五、时钟同步I2C使用时钟同步机制来确保通信的准确性。
时钟线由主设备产生,并控制整个数据传输过程的时序。
在每个时钟周期中,数据线上的数据必须稳定,并且只有在时钟线为低电平时才能改变。
六、地址传输在I2C通信中,每个从设备都有一个唯一的7位地址。
主设备通过发送地址来选择要与之通信的从设备。
地址由8个位组成,最高位是固定的0或1,用于表示读(1)或写(0)操作。
其余的7位用于指定从设备的地址。
七、数据传输流程I2C通信的数据传输流程如下:1. 主设备发送起始信号(Start)。
linux系统i2c协议详解

linux系统i2c协议详解I2C总线概述I2C(两线接口)是一种串行通信协议,用于连接嵌入式系统中的集成电路(IC)。
它以其低成本、低功耗和高可靠性著称。
I2C总线需要两条双向信号线:串行数据线(SDA)和串行时钟线(SCL)。
这些信号线由一个主设备控制,可以与多个从设备通信。
I2C通信I2C通信由以下步骤组成:起始条件:主设备将SDA线下拉至低电平,同时保持SCL线为高电平。
设备地址:主设备发送7位或10位从设备地址,后跟一个读/写位。
数据传输:主设备和从设备交换数据。
停止条件:主设备将SDA线拉至高电平,同时保持SCL线为高电平。
主设备和从设备I2C总线上的设备分为两种:主设备和从设备。
主设备:发起通信并控制总线。
通常是主微控制器或处理器。
从设备:响应主设备请求并提供或接收数据。
可以是传感器、执行器或其他外围设备。
I2C寻址从设备通过唯一的7位或10位地址进行寻址。
地址的最高位表示是否可读/写,0表示写,1表示读。
I2C模式I2C协议支持以下模式:主写从读:主设备向从设备写入数据,然后从从设备读取数据。
主读从写:主设备从从设备读取数据,然后向从设备写入数据。
从读从写:两个从设备在主设备的监督下进行通信。
I2C传输速率I2C传输速率通常在10kbps到400kbps之间。
速率由主设备设置。
I2C错误检测I2C协议包含几个错误检测机制,例如校验和和超时。
这些机制有助于确保数据的可靠传输。
I2C应用I2C总线用于各种应用,包括:传感器和执行器接口EEPROM和闪存编程LED和LCD控制模拟-数字转换器(ADC)和数字-模拟转换器(DAC)接口电源管理时钟同步I2C优点I2C协议的优点包括:低成本:无需额外的硬件接口低功耗:仅使用两根信号线高可靠性:错误检测机制确保数据完整性容易使用:简单的协议易于实施广泛采用:支持广泛的设备和库I2C缺点I2C协议的缺点包括:数据速率低:与其他串行接口相比,数据速率较低主机限制:总线上只能有一个主设备总线无仲裁:在总线冲突的情况下,没有内置的仲裁机制有限的寻址范围:仅支持有限数量的设备地址I2C技术演进I2C协议正在不断发展,以满足新应用的需求。
I2C通信原理及程序详细讲解

I2C通信原理及程序详细讲解I2C(Inter-Integrated Circuit)是一种串行通信协议,常用于连接微控制器、传感器和其他外部设备。
I2C通信协议由荷兰飞利浦公司于1982年开发,它使用两根信号线(SDA和SCL)进行数据传输。
I2C通信协议采用主从结构,一个主设备(如微控制器)可以连接多个从设备(如传感器)。
主从设备之间通过SDA和SCL线进行数据传输。
SDA线是双向数据线,用于传输数据,SCL线是时钟线,用于同步数据传输。
I2C通信协议中,设备的地址是一个重要概念。
每个设备都有一个唯一的地址,通过该地址可以选择和通信特定的设备。
地址由7个位组成,其中最高位是固定的,并取决于设备是主设备还是从设备。
如果最高位为0,则表示该设备是主设备;如果最高位为1,则表示该设备是从设备。
通过以下步骤,让我们详细了解如何在I2C总线上进行通信。
1.初始化I2C总线:在程序开始时,需要初始化I2C总线。
这通常包括初始化SDA和SCL引脚,设置时钟频率等。
具体的初始化步骤取决于使用的硬件和软件环境。
2.发送开始信号:开始信号表示I2C数据传输的开始。
它由主设备发送,并且SDA线从高电平转为低电平时发出。
发送开始信号后,SDA线上的数据将被解释为地址数据。
3.发送设备地址:主设备发送一个包含设备地址和读/写位(R/W)的数据字节。
设备地址是唯一的,并且由主设备选择。
读/写位指示从设备是要读取数据还是写入数据。
4.等待从设备响应:主设备发送设备地址后,会等待从设备的响应。
从设备将响应一个应答位(ACK)来确认地址接收成功。
如果收到ACK位,则继续进行下一步,否则可能是设备未连接或通信错误。
5.发送数据:主设备发送数据给从设备。
数据可以是命令、配置或实际数据,具体取决于应用场景。
发送数据的方式是将每个数据字节传输到SDA线上,并在每个数据字节后发送一个ACK位。
6.接收数据:从设备将数据发送给主设备。
数据可以是传感器读数、存储器数据等。
I2C工作原理

文化在交流中传播高考频度:★★★★☆难易程度:★★★☆☆被誉为中芬文明交流互鉴“架桥人”的赫尔辛基大学孔子学院,作为芬兰认识中国、中国与芬兰深化友谊和合作的重要窗口,在推动汉语在芬兰的发展方面取得了丰硕的成果,已成为芬兰最大的汉语教学、汉语水平考试及中国问题研究中心,孔子学院还在芬兰多所大学的五个语言中心设立了汉语教学点。
赫尔辛基大学孔子学院的创建①扩大了中华文化的国际影响力②表明了中华优秀传统文化是中华文明的重要标志③见证了中华优秀传统文化能够推动芬兰社会发展④为中华文化的传播和中芬文化的交流作出了贡献A.①② B.①④ C.②③ D.③④1.文化交流促进世界文化的发展文化传播的意义——既促进本民族文化的繁荣,又促进世界文化的发展。
2.做传播中外文化交流的友好使者我们既要更加热情地欢迎世界各地优秀文化在中国传播,又要更加主动地推动中华文化走向世界。
做中外文化交流的友好使者,是时代赋予我们的使命。
文化传播的途径和文化传播的手段1.秦国攻灭楚国后,为了加强对南方地区的控制,派50万官兵驻扎岭南地区。
这使得相当一部分中原人留在了粤东北地区,对当地文化产生了深远的影响。
秦统一中国后,为了戍边和开发新区,组织了一系列大规模的人口迁徙。
其中最著名的北戍五原、云中,南戍五岭,人数近百万,对长城沿线和华南的开发起了重要作用。
上述材料体现的文化传播途径是A.教育是文化传播的重要途径B.人口迁徙是文化传播的重要途径C.战争是文化传播的根本途径D.古代商贸活动是文化传播的重要途径2.中央电视台“一带一路”的特别报道《数说命运共同体》,通过讲述贸易、投资、中国制造、基础设旅、饮食文化、人员往来等方面的故事,呈现出“一带一路”沿线国家“命运共同体”图景。
该节目通过最新视频技术,使主持人“走出”演播室,在不同国家之间“穿越”,和观众一起认识“一带一路”沿线国家各方面的情况。
茶叶、丝绸伴随着中国口音旅行到了世界各地,而远方的特产来到中国的同时也把海外“乡音”带进了汉语词典,阿拉伯神话传说在中国家喻户晓,中国的电影海报也张贴在外国的电影院里……这表明A.大众传媒具有文化传递、沟通、感召的强大功能B.文化既是民族的,又是世界的C.大众传媒是古今文化传播的主要途径D.文化与经济相互交融,相互影响3.2017年,中国在德国举办贯穿全年、覆盖全德的系列文化庆祝活动。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实例解析linux内核I2C体系结构(2)华清远见刘洪涛四、在内核里写i2c设备驱动的两种方式前文介绍了利用/dev/i2c-0在应用层完成对i2c设备的操作,但很多时候我们还是习惯为i2c设备在内核层编写驱动程序。
目前内核支持两种编写i2c驱动程序的方式。
下面分别介绍这两种方式的实现。
这里分别称这两种方式为“Adapter方式(LEGACY)”和“Probe方式(new style)”。
(1)Adapter方式(LEGACY)(下面的实例代码是在2.6.27内核的pca953x.c基础上修改的,原始代码采用的是本文将要讨论的第2种方式,即Probe方式)●构建i2c_driverstatic struct i2c_driver pca953x_driver = {.driver = {.name= "pca953x", //名称},.id= ID_PCA9555,//id号.attach_adapter= pca953x_attach_adapter, //调用适配器连接设备.detach_client= pca953x_detach_client,//让设备脱离适配器};●注册i2c_driverstatic int __init pca953x_init(void){return i2c_add_driver(&pca953x_driver);}module_init(pca953x_init);●attach_adapter动作执行i2c_add_driver(&pca953x_driver)后会,如果内核中已经注册了i2c适配器,则顺序调用这些适配器来连接我们的i2c设备。
此过程是通过调用i2c_driver中的attach_adapter方法完成的。
具体实现形式如下:static int pca953x_attach_adapter(struct i2c_adapter *adapter){return i2c_probe(adapter, &addr_data, pca953x_detect);/*adapter:适配器addr_data:地址信息pca953x_detect:探测到设备后调用的函数*/}地址信息addr_data是由下面代码指定的。
/* Addresses to scan */static unsigned short normal_i2c[] ={0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,I2C_CLIENT_END};I2C_CLIENT_INSMOD;注意:normal_i2c里的地址必须是你i2c芯片的地址。
否则将无法正确探测到设备。
而I2C_ CLIENT_INSMOD是一个宏,它会利用normal_i2c构建addr_data。
构建i2c_client,并注册字符设备驱动i2c_probe在探测到目标设备后,后调用pca953x_detect,并把当时的探测地址address 作为参数传入。
static int pca953x_detect(struct i2c_adapter *adapter, int address, int kind){struct i2c_client *new_client;struct pca953x_chip *chip; //设备结构体int err = 0,result;dev_t pca953x_dev=MKDEV(pca953x_major,0);//构建设备号,根据具体情况设定,这里我只考虑了normal_i2c中只有一个地址匹配的情况。
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA|I2C_FUNC_SMBUS_WORD_DA TA))//判定适配器能力goto exit;if (!(chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL))) {err = -ENOMEM;goto exit;}/****构建i2c-client****/chip->client=kzalloc(sizeof(struct i2c_client),GFP_KERNEL);new_client = chip->client;i2c_set_clientdata(new_client, chip);new_client->addr = address;new_client->adapter = adapter;new_client->driver = &pca953x_driver;new_client->flags = 0;strlcpy(new_client->name, "pca953x", I2C_NAME_SIZE);if ((err = i2c_attach_client(new_client)))//注册i2c_clientgoto exit_kfree;if (err)goto exit_detach;if(pca953x_major){result=register_chrdev_region(pca953x_dev,1,"pca953x");}else{result=alloc_chrdev_region(&pca953x_dev,0,1,"pca953x");pca953x_major=MAJOR(pca953x_dev);}if (result < 0) {printk(KERN_NOTICE "Unable to get pca953x region, error %d\n", result);return result;}pca953x_setup_cdev(chip,0); //注册字符设备,此处不详解return 0;exit_detach:i2c_detach_client(new_client);exit_kfree:kfree(chip);exit:return err;}i2c_check_functionality用来判定设配器的能力,这一点非常重要。
你也可以直接查看对应设配器的能力,如static const struct i2c_algorithm smbus_algorithm = {.smbus_xfer= i801_access,.functionality= i801_func,};static u32 i801_func(struct i2c_adapter *adapter){return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |I2C_FUNC_SMBUS_BYTE_DA TA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DA TA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK| (isich4 ? I2C_FUNC_SMBUS_HWPEC_CALC : 0);}字符驱动的具体实现struct file_operations pca953x_fops = {.owner = THIS_MODULE,.ioctl= pca953x_ioctl,.open= pca953x_open,.release =pca953x_release,};字符设备驱动本身没有什么好说的,这里主要想说一下,如何在驱动中调用i2c设配器帮我们完成数据传输。
目前设配器主要支持两种传输方法:smbus_xfer和master_xfer。
一般来说,如果设配器支持了master_xfer那么它也可以模拟支持smbus的传输。
但如果只实现smbus_xfer,则不支持一些i2c的传输。
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);master_xfer中的参数设置,和前面的用户空间编程一致。
现在只是要在驱动中构建相关的参数然后调用i2c_transfer来完成传输既可。
int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num) smbus_xfer中的参数设置及调用方法如下:static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val){int ret;ret = i2c_smbus_write_word_data(chip->client, reg << 1, val);if (ret < 0) {dev_err(&chip->client->dev, "failed writing register\n");return -EIO;}return 0;}上面函数完成向芯片的地址为reg的寄存器写一个16bit的数据。
i2c_smbus_write_word_data的实现如下:s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value){union i2c_smbus_data data;data.word = value;return i2c_smbus_xfer(client->adapter,client->addr,client->flags,I2C_SMBUS_WRITE,command,I2C_SMBUS_WORD_DATA,&data);}从中可以看出smbus传输一个16位数据的方法。
其它操作如:字符写、字符读、字读、块操作等,可以参考内核的i2c-core.c中提供的方法。
●注销i2c_driverstatic void __exit pca953x_exit(void){i2c_del_driver(&pca953x_driver);}module_exit(pca953x_exit);●detach_client动作顺序调用内核中注册的适配器来断开我们注册过的i2c设备。