Linux的i2c驱动详解
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设备。
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协议正在不断发展,以满足新应用的需求。
Linux I2C(一)之常用的几种实例化(i2c_client )
* struct i2c_board_info - template for device creation * @type: chip type, to initialize i2c_ * @flags: to initialize i2c_client.flags * @addr: stored in i2c_client.addr * @platform_data: stored in i2c_client.dev.platform_data * @archdata: copied into i2c_client.dev.archdata * @of_node: pointer to OpenFirmware device node * @acpi_node: ACPI device node * @irq: stored in i2c_client.irq * * I2C doesn't actually support hardware probing, although controllers and * devices may be able to use I2C_SMBUS_QUICK to tell whether or not there's * a device at a given address. Drivers commonly need more information than * that, such as chip type, configuration, associated IRQ, and so on. * * i2c_board_info is used to build tables of information listing I2C devices * that are present. This information is used to grow the driver model tree. * For mainboards this is done statically using i2c_register_board_info(); * bus numbers identify adapters that aren't yet available. For add-on boards, * i2c_new_device() does this dynamically with the adapter already known. */ struct i2c_board_info { char type[I2C_NAME_SIZE]; unsigned short flags; unsigned short addr; void *platform_data; struct dev_archdata *archdata; struct device_node *of_node; struct acpi_dev_node acpi_node; int irq; }; i2c_register_board_info: /** * i2c_register_board_info - statically declare I2C devices * @busnum: identifies the bus to which these devices belong * @info: vector of i2c device descriptors * @len: how many descriptors in the vector; may be zero to reserve * the specified bus number. * * Systems using the Linux I2C driver stack can declare tables of board info * while they initialize. This should be done in board-specific init code * near arch_initcall() time, or equivalent, before any I2C adapter driver is * registered. For example, mainboard init code could define several devices,
Linux下基于I2C的电源管理芯片驱动设计
0 引 言
内部 集 成 电路 (ne—ne rtd crut 2 itritg ae i i c ,IC)
12 IC 总 线 信 号 时序 . 2
S DA 和 S L2条 信 号 线 都 处 于 高 电平 ,即 总 线 C 空 闲状 态 , 2条 信 号 线 各 自的 上 拉 电阻 把 电平 拉 高 ;
( tritgae i ut u d r iu . h 2 u miga dtese il rhtcueo eICb s nte n xk re ae i e— e rtdcr i n e n x T eICb s i n n p ca ac i tr fh 2 u u en l r n n c ) L t h e t i h Li
23 I C设 备 驱 动 . 2
CON Dn1 oN
图 1 IC总 线起 始 信 号 与结 束信 号【 2
定 义 描 述 具 体 设 备 的 IC cin 2 l t和 可 能 的私 有 e 数 据 结 构 、借 助 IC 框 架 的 IC pr be 函 数 实 现 注 2 2 o
S
‘ 、
.
源 转 换 输 出 的应 用 ,提 供 简 单 易 用 而 又 可 以灵 活 配 置 的完 整 电源 解 决 方 案 , 充 分 满 足 目前 日益 复 杂 的 应 用 处 理器 系 统 对 于 电源 相 对 复 杂 而 精 确 控 制 的要 求 。AXP 9 提 供 了一 个 与主 机 通 讯 的 两 线 串行 通 12
接 收 端 接 收 完 一 个 字 节 后 , 会 立 刻 在 AC 周 期 内 K
1 IC总线 概 述 与时序 2
11 IC 总 线 介 绍 . 2
将 S DA 由高 电平 翻 转 为低 电 平 ,这 便 产 生 了 一 个
LinuxI2C驱动--用户态驱动简单示例
LinuxI2C驱动--⽤户态驱动简单⽰例1. Linux内核⽀持I2C通⽤设备驱动(⽤户态驱动:由应⽤层实现对硬件的控制可以称之为⽤户态驱动),实现⽂件位于drivers/i2c/i2c-dev.c,设备⽂件为/dev/i2c-02. I2C通⽤设备驱动以字符设备注册进内核的static const struct file_operations i2cdev_fops = {.owner = THIS_MODULE,.llseek = no_llseek,.read = i2cdev_read,.write = i2cdev_write,.unlocked_ioctl = i2cdev_ioctl,.open = i2cdev_open,.release = i2cdev_release,};res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);3. 对设备⽂件进⾏读写时,可以调⽤read、write或者ioctl等⽅法,他们都是通过调⽤函数i2c_transfer来实现对I2C设备的操作的int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num){int ret;/* REVISIT the fault reporting model here is weak:** - When we get an error after receiving N bytes from a slave,* there is no way to report "N".** - When we get a NAK after transmitting N bytes to a slave,* there is no way to report "N" ... or to let the master* continue executing the rest of this combined message, if* that's the appropriate response.** - When for example "num" is two and we successfully complete* the first message but get an error part way through the* second, it's unclear whether that should be reported as* one (discarding status on the second message) or errno* (discarding status on the first one).*/if (adap->algo->master_xfer) {#ifdef DEBUGfor (ret = 0; ret < num; ret++) {dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, ""len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)'R' : 'W', msgs[ret].addr, msgs[ret].len,(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");}#endifif (in_atomic() || irqs_disabled()) {ret = mutex_trylock(&adap->bus_lock);if (!ret)/* I2C activity is ongoing. */return -EAGAIN;} else {mutex_lock_nested(&adap->bus_lock, adap->level);}ret = adap->algo->master_xfer(adap,msgs,num);mutex_unlock(&adap->bus_lock);return ret;} else {dev_dbg(&adap->dev, "I2C level transfers not supported\n");return -EOPNOTSUPP;}}4. i2c_transfer通过代码可以看出,i2c_transfer 通过调⽤相应的 adapter 的 master_xfer ⽅法实现的,⽽ master_xfer 主要是根据 struct i2c_msg 类型的msgs来进⾏处理的。
i2c驱动传入probe的参数解释
I2C驱动传入probe的参数解释在进行I2C设备的驱动开发过程中,常常会涉及到I2C驱动的probe 函数。
probe函数是Linux内核驱动中的一种特殊函数,它在驱动被加载并且设备被检测到时被调用,用于初始化设备并注册设备驱动。
在编写I2C驱动的probe函数时,通常需要传入不同的参数进行配置和初始化。
本文将对I2C驱动传入probe的参数进行解释和说明,帮助读者更好地理解和使用I2C设备驱动。
1. struct i2c_client *client在I2C驱动的probe函数中,通常需要传入一个指向structi2c_client结构体的指针作为参数。
这个结构体是I2C设备在内核中的表示,包含了I2C设备的位置区域、总线信息、驱动信息等。
通过这个参数,我们可以获取I2C设备的各种信息,并进行相应的初始化和配置。
2. const struct i2c_device_id *id另一个常见的参数是一个指向const struct i2c_device_id结构体的指针,用于指定要注册的设备驱动的ID信息。
这个结构体中通常包含了设备的厂商ID、设备类型、设备名称等信息,用于匹配加载指定的设备驱动。
在probe函数中,我们可以使用这个参数来判断当前检测到的I2C设备是否匹配当前的驱动,从而进行相应的初始化和注册操作。
3. int (*probe)(struct i2c_client *client, const struct i2c_device_id *id)最后一个重要的参数是probe函数本身。
这个参数是一个函数指针,用于指定实际的probe函数的位置区域。
在probe函数中,我们可以根据传入的client和id参数,进行设备的初始化、资源的申请、注册设备驱动等操作。
通过这个函数指针参数,内核可以在加载驱动并检测到设备时正确地调用对应的probe函数。
I2C驱动传入probe的参数包括指向I2C设备结构体的指针、指向设备ID信息的指针以及probe函数的函数指针。
I2C实例解析
实例解析linux内核I2C体系结构(1)一、概述谈到在linux系统下编写I2C驱动,目前主要有两种方式,一种是把I2C设备当作一个普通的字符设备来处理,另一种是利用linux I2C驱动体系结构来完成。
下面比较下这两种驱动。
第一种方法的好处(对应第二种方法的劣势)有:●思路比较直接,不需要花时间去了解linux内核中复杂的I2C子系统的操作方法。
第一种方法问题(对应第二种方法的好处)有:●要求工程师不仅要对I2C设备的操作熟悉,而且要熟悉I2C的适配器操作;●要求工程师对I2C的设备器及I2C的设备操作方法都比较熟悉,最重要的是写出的程序可移植性差;●对内核的资源无法直接使用。
因为内核提供的所有I2C设备器及设备驱动都是基于I2C子系统的格式。
I2C适配器的操作简单还好,如果遇到复杂的I2C适配器(如:基于PCI的I2C适配器),工作量就会大很多。
本文针对的对象是熟悉I2C协议,并且想使用linux内核子系统的开发人员。
网络和一些书籍上有介绍I2C子系统的源码结构。
但发现很多开发人员看了这些文章后,还是不清楚自己究竟该做些什么。
究其原因还是没弄清楚I2C子系统为我们做了些什么,以及我们怎样利用I2C子系统。
本文首先要解决是如何利用现有内核支持的I2C适配器,完成对I2C设备的操作,然后再过度到适配器代码的编写。
本文主要从解决问题的角度去写,不会涉及特别详细的代码跟踪。
二、I2C设备驱动程序编写首先要明确适配器驱动的作用是让我们能够通过它发出符合I2C标准协议的时序。
在Linux内核源代码中的drivers/i2c/busses目录下包含着一些适配器的驱动。
如S3C2410的驱动i2c-s3c2410.c。
当适配器加载到内核后,接下来的工作就要针对具体的设备编写设备驱动了。
编写I2C设备驱动也有两种方法。
一种是利用系统给我们提供的i2c-dev.c来实现一个i2c 适配器的设备文件。
然后通过在应用层操作i2c适配器来控制i2c设备。
i2c_register_driver函数详解
i2c_register_driver函数详解在嵌入式软件开发中,I2C(Inter-Integrated Circuit)总线是一种常用的串行通信接口,用于在微控制器和外部设备之间传输数据。
i2c_register_driver函数是Linux内核中一个重要的函数,用于注册I2C 驱动程序。
本文将详细解析i2c_register_driver函数的功能、参数和应用。
一、i2c_register_driver函数概述i2c_register_driver函数是在Linux内核中注册一个I2C驱动程序的函数。
它的作用是将驱动程序与对应的I2C适配器绑定,使得操作系统能够正确地识别和管理该驱动程序。
在驱动程序注册后,当相应的I2C设备连接到系统时,驱动程序将会自动加载并为该设备提供服务。
二、i2c_register_driver函数参数i2c_register_driver函数包含一个结构体参数,该结构体用于指定驱动程序的相关信息和功能。
1. struct i2c_driverstruct i2c_driver是一个定义I2C驱动程序的结构体,包含了以下重要的成员:- .driver:指向内核的struct device_driver结构体,用于描述驱动程序的信息,如名称、文件操作方法等。
- .probe:指向I2C设备探测函数的指针,用于在设备连接时进行初始化和配置。
- .remove:指向I2C设备移除函数的指针,用于在设备断开连接时进行清理和释放资源。
- .id_table:指向I2C设备ID表的指针,用于匹配设备和驱动程序。
2. I2C设备探测函数(probe函数)I2C设备探测函数是I2C驱动程序的核心功能之一,在I2C设备连接到系统时被调用。
该函数的作用是检测和初始化I2C设备,并将设备与驱动程序进行绑定。
在probe函数中,可以执行一系列必要的操作,如配置寄存器、分配内存、注册字符设备等。
Linux I2C设备驱动编写
Linux I2C设备驱动编写(一)在Linux驱动中I2C系统中主要包含以下几个成员:如果一个I2C适配器不支持I2C通道,那么就将master_xfer成员设为NULL。
如果适配器支持SMBUS 协议,那么需要去实现smbus_xfer,如果smbus_xfer指针被设为NULL,那么当使用SMBUS协议的时候将会通过I2C通道进行仿真。
master_xfer指向的函数的返回值应该是已经成功处理的消息数,或者返回负数表示出错了。
functionality指针很简单,告诉询问着这个I2C主控器都支持什么功能。
在内核的drivers/i2c/i2c-stub.c中实现了一个i2c adapter的例子,其中实现的是更为复杂的SMBUS。
SMBus 与I2C的区别通常情况下,I2C和SMBus是兼容的,但是还是有些微妙的区别的。
时钟速度对比:在电气特性上他们也有所不同,SMBus要求的电压范围更低。
I2C driver具体的I2C设备驱动,如相机、传感器、触摸屏、背光控制器常见硬件设备大多都有或都是通过I2C 协议与主机进行数据传输、控制。
结构体如下:如同普通设备的驱动能够驱动多个设备一样,一个I2C driver也可以对应多个I2C client。
以重力传感器AXLL34X为例,其实现的I2C驱动为:这里要说明一下module_i2c_driver宏定义(i2c.h):module_driver():理解上述宏定义后,将module_i2c_driver(adxl34x_driver)展开就可以得到:这一句宏就解决了模块module安装卸载的复杂代码。
这样驱动开发者在实现I2C驱动时只要将i2c_driver结构体填充进来就可以了,无需关心设备的注册与反注册过程。
I2C client即I2C设备。
I2C设备的注册一般在板级代码中,在解析实例前还是先熟悉几个定义:下面还是以adxl34x为例:这样ADXL34X的i2c设备就被注册到了系统中,当名字与i2c_driver中的id_table中的成员匹配时就能够出发probe匹配函数了。
嵌入式Linux中I2C总线驱动程序设计
Ke r s e e d d L n x I C b s I C d v c ; d v c r e ; AT 1 ywo d : mb d e ; i u ; 2 u ; 2 e i e e ie d i r v 9 RM 9 0 2 0
0 引 言
ICit - tga d i u ) 线 , 由菲利 浦 公 司开 发 的一 2 ( e i ert c ci总 n rn e r t 是 种 同步 串行 总 线 协 议 , 于 连 接 微 控 制 器 及 其 外 围 设 备 。最 用 初 是 为 音 频 和 视 频 设 备 开 发 的 ,如 今 IC在 各 种 电 子 设 备 中 2
中图法分类 号 : P9 T 3 T 3 ; P
文献标 识码 : A
文章编 号 :0 072 (0 8 1—570 10 —0 4 2 0 ) 02 1—3
De in o C u r e n e mb d e n x s se sg f 2 b s i ru d r I d v e e d dLiu y tm
IC总 线 在 传 送 数 据 过 程 中共 有 3 类 型 信 号 , 们 分 别 2 种 它 是 开 始 信 号 、 束 信 号 和 应 答 信 号( 图 l 图 2 示 ) 结 如 、 所 。
得 到 了 广 泛 的 应 用 。嵌 入 式 系 统 中 常 常 使 用 这 个 总 线 连 接
HEYa u , DE jn NGF i i e— q
( o ee f uo t nS i c n n ier g o t C ia iesyo T cn lg,G agh u 6 0 C ia C lg A tmao ce e d gn e n ,S u h v r t f eh oo y un z o 1 4 , hn) l o i n a E i h n Un i 50
i2c_register_driver函数详解 -回复
i2c_register_driver函数详解-回复标题:i2c_register_driver函数详解在嵌入式系统中,I2C(Inter-Integrated Circuit)是一种常用的通信协议,用于设备之间的数据交换。
在Linux内核中,i2c_register_driver函数是用于注册I2C驱动程序的核心函数。
本文将详细解析i2c_register_driver函数的使用方法和工作原理。
一、函数定义首先,我们来看一下i2c_register_driver函数的定义:cstruct i2c_driver *i2c_register_driver(struct i2c_driver *);该函数接受一个指向i2c_driver结构体的指针作为参数,返回一个指向同一结构体的指针。
这个结构体包含了驱动程序的相关信息,如名称、操作函数等。
二、i2c_driver结构体在深入理解i2c_register_driver函数之前,我们需要先了解i2c_driver 结构体。
以下是一个典型的i2c_driver结构体的例子:cstruct i2c_driver {const char *name;struct module *owner;const struct i2c_device_id *id_table;int (*probe)(struct i2c_client *, const struct i2c_device_id *);int (*remove)(struct i2c_client *);void (*shutdown)(struct i2c_client *);int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);};在这个结构体中,各个字段的含义如下:- name:驱动程序的名称。
- owner:模块的所有者,通常设置为THIS_MODULE。
linux i2c注册流程 -回复
linux i2c注册流程-回复Linux I2C 注册流程I2C (Inter-Integrated Circuit) 是一种常用于在嵌入式系统中连接多个设备的串行通信协议。
在Linux 操作系统中,内核提供了I2C Bus 管理子系统,允许开发人员通过I2C 接口与各种外部设备进行通信。
本篇文章将详细介绍Linux I2C 注册流程,为读者提供一步一步的指导。
1. 硬件准备首先,我们需要确保硬件上已经连接了I2C 设备。
通常,I2C 总线由一个主设备(通常是嵌入式系统中的MCU 或CPU),以及一个或多个从设备组成。
这些设备通过I2C 数据线(SDA)和时钟线(SCL)相连。
2. Linux 内核配置接下来,我们需要确保Linux 内核已经正确配置了I2C 支持。
可以通过检查内核配置文件(通常是`.config` 文件)来确认是否启用了I2C 支持。
需要确保以下配置项被设置为`y` 或`m`:CONFIG_I2C=yCONFIG_I2C_CHARDEV=y3. I2C 驱动程序加载在Linux 系统中,I2C 驱动程序被视为内核模块。
因此,在执行I2C 设备注册之前,需要加载适当的I2C 驱动程序。
可以使用`modprobe` 命令加载驱动程序,如下所示:modprobe i2c-dev4. 查找I2C 地址和设备ID每个I2C 设备都有一个独立的7 位地址,用于在总线上进行寻址。
在注册I2C 设备之前,我们需要确定要使用的I2C 地址。
可以通过执行以下命令来列出连接到I2C 总线的所有设备及其地址:i2cdetect -li2cdetect -y <i2c_bus_number>5. 创建I2C 客户端设备结构体在Linux 内核中,I2C 设备通常通过struct i2c_client 结构表示。
该结构体用于描述I2C 设备的各种属性和特征。
创建一个新的I2C 客户端结构体,并通过填充必要的字段来初始化它。
LinuxI2C驱动整理(以RK3399Pro+Kernel4.4为例)
LinuxI2C驱动整理(以RK3399Pro+Kernel4.4为例)⼀. Linux I2C驱动架构Linux内核⾥,I2C驱动框架可以分为两层,adapter驱动和deivce驱动。
Adapter驱动也可以理解为I2C总线驱动,指的是SOC⾥的I2C控制器驱动。
⼀个SOC可能包含多个I2C控制器,⽽每个控制器的使⽤⽅式是相同的(寄存器参数、收发数据的⽅法等),因此多个控制器可以共⽤⼀套adapter驱动;Deivce驱动,对应的是SOC外围的I2C设备,不同类型I2C设备需要开发不同的设备驱动,同⼀类型的I2C设备可以使⽤⼀种驱动,但是每⼀个I2C设备都由⼀个唯⼀的client来描述。
⼆. Adapter配置DTSI⽂件(kernel/arch/arm64/boot/dts/rockchip/rk3399.dtsi)描述了RK3399Pro所有的I2C控制器信息:i2c0: i2c@ff3c0000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff3c00000x00x1000>;clocks = <&pmucru SCLK_I2C0_PMU>, <&pmucru PCLK_I2C0_PMU>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c0_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c1: i2c@ff110000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1100000x00x1000>;clocks = <&cru SCLK_I2C1>, <&cru PCLK_I2C1>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c1_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c2: i2c@ff120000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1200000x00x1000>;clocks = <&cru SCLK_I2C2>, <&cru PCLK_I2C2>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c2_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c3: i2c@ff130000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1300000x00x1000>;clocks = <&cru SCLK_I2C3>, <&cru PCLK_I2C3>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c3_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c5: i2c@ff140000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1400000x00x1000>;clocks = <&cru SCLK_I2C5>, <&cru PCLK_I2C5>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c5_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c6: i2c@ff150000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1500000x00x1000>;clocks = <&cru SCLK_I2C6>, <&cru PCLK_I2C6>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c6_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c7: i2c@ff160000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff1600000x00x1000>;clocks = <&cru SCLK_I2C7>, <&cru PCLK_I2C7>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c7_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c4: i2c@ff3d0000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff3d00000x00x1000>;clocks = <&pmucru SCLK_I2C4_PMU>, <&pmucru PCLK_I2C4_PMU>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c4_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};i2c8: i2c@ff3e0000 {compatible = "rockchip,rk3399-i2c";reg = <0x00xff3e00000x00x1000>;clocks = <&pmucru SCLK_I2C8_PMU>, <&pmucru PCLK_I2C8_PMU>;clock-names = "i2c", "pclk";interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH 0>;pinctrl-names = "default";pinctrl-0 = <&i2c8_xfer>;#address-cells = <1>;#size-cells = <0>;status = "disabled";};可以看出,该SOC共有9个I2C控制器,分别为I2C0~I2C8, 每个控制器对应了不同的寄存器基地址(例如I2C0对应0xff3c0000),它们的compatible匹配属性都是"rockchip,rk3399-i2c",也就是对应了同⼀个adapter驱动。
linux下i2c接口的电容触摸屏驱动开发
原文地址:电容触摸屏2011-01-14 15:361.Kconfig文件增加宏定义2.Makefile文件增加编译处理3.添加程序源码Touch screen remote control design document2010年11月08日星期一 13:08Touch screen remote control design document1. 开发板环境a) Mini2440 开发板。
Arm9 处理器+64M SRAM + 64M Flash +3.5’触摸屏LCDb) Linux 2.6.32 kernel,支持多点触摸触摸屏+Qtopia 2.2.20 图形用户界面系统c) AVR 单片机+加速度传感器+红外一体化接收头+红外发射二极管2. 主机开发环境a) Vmware 6.0 安装 Fedora 10 系统,按照友善之臂mini2440 使用手册来建立开发环境。
最好在安装fedora 10的过程中将所有的可选项全部安装,以免后续开发过程中遇到不可预知的问题。
Fedora 10默认不能以root用户登陆图形用户界面,需要以普通用户登陆之后在命令终端中su切换到root用户,然后修改文件/etc/pam.d/gdm。
将auth required pam_succeed_if.so user != root quiet 这句注销。
b) 按照友善之臂用户手册建立交叉开发环境。
安装arm-linux-gcc4.3.2,arm-qtopia, x86-qtopia, root-qtopia, linux-2.6.32-friendlyarm 到系统中。
安装的过程中有一个问题是,不能够同时编译arm-qtopia和x86-qtopia,如果这样做,会发生不可预知的错误。
典型问题是qt2的designer打开后是透明的,无法操作。
c) 遥控器解码目前采用FPGA平台来完成的,所以主机具有FPGA开发环境(quartus9.0)d) 红外发射和加速度传感器的手势操作室通过AVR单片机完成的,所以主机具有AVR单片机开发环境(Keil 4)3. 图形界面编码a) Arm-qtopia 文件夹中安装了qt2,在qt2的bin目录下执行 designer 就可以进入qt的图形开发界面。
i2c_register_driver函数详解
i2c_register_driver函数详解一、概述i2c_register_driver函数是Linux内核中用于注册I2C设备驱动的函数之一。
它用于将设备驱动程序注册到内核,以便其他模块可以使用该驱动程序来与I2C设备进行通信。
二、函数原型int i2c_register_driver(struct i2c_driver *driver);三、函数参数说明* driver:指向i2c_driver结构体的指针,该结构体包含了设备驱动的相关信息,如设备名称、设备ID等。
四、函数返回值如果函数成功注册驱动程序,则返回0;否则返回-E...等错误代码。
五、函数功能详解i2c_register_driver函数将指定的i2c_driver结构体注册到内核中,使其成为可用的I2C设备驱动。
在注册驱动程序之前,需要确保驱动程序已经正确编译并包含在内核中。
在注册驱动程序时,i2c_register_driver函数会执行以下操作:1. 检查驱动程序是否符合内核的要求,如设备ID、设备名称等是否正确。
2. 将驱动程序的信息添加到内核的设备列表中,以便其他模块可以找到并使用该驱动程序。
3. 注册成功后,内核会为该驱动程序分配相应的资源,如内存、端口等,并建立与I2C总线的连接。
六、使用示例```c#include <linux/module.h>#include <linux/i2c.h>struct i2c_driver my_driver;int main(){int ret;ret = i2c_register_driver(&my_driver);if (ret) {printk(KERN_ERR "Failed to register driver: %d\n", ret);return ret;}// 其他操作...return 0;}```在上述示例中,首先定义了一个i2c_driver结构体变量my_driver,用于存储驱动程序的相关信息。
rk linux下i2c总线驱动读写原理
RK Linux下I2C总线驱动读写原理RK Linux,一个开源的、强大的、可定制的操作系统,广泛应用于各种嵌入式系统。
I2C总线是一种常用的通信协议,常用于连接低速外围设备,如传感器、EEPROM等。
在RK Linux下,I2C总线驱动的读写原理是什么呢?首先,我们来了解下I2C总线的基本概念。
I2C总线是一种双线串行通信总线,由数据线SDA和时钟线SCL组成。
通过这两根线,多个设备可以在同一总线上进行通信。
每个设备都有一个唯一的地址,主机可以通过发送设备的地址来选择与之通信的设备。
在RK Linux下,I2C总线驱动的读写操作主要依赖于内核提供的API。
这些API 包括i2c_read()、i2c_write()等,它们提供了与I2C设备通信的接口。
那么,这些API是如何实现读写操作的呢?在内核中,I2C驱动程序负责管理I2C总线上所有的设备和它们的通信。
当需要从设备读取数据时,驱动程序首先会向设备发送读请求。
设备接收到请求后,会将数据写入SDA线。
驱动程序会持续监听SDA线,一旦接收到数据,就会将其保存并通知应用程序。
同样地,当需要向设备写入数据时,驱动程序会向设备发送写请求。
设备接收到请求后,会准备好接收数据。
驱动程序会将数据写入SDA线,设备接收到数据后,会将数据保存到内部寄存器中。
需要注意的是,I2C总线的读写操作都是通过驱动程序来完成的。
应用程序只需要调用内核提供的API即可与I2C设备进行通信。
这样设计的好处是应用程序可以专注于自己的业务逻辑,而不需要关心底层的通信细节。
同时,这也使得应用程序与具体的I2C设备无关,具有更好的可移植性和扩展性。
Linux下读写芯片的I2C寄存器
Linux下读写芯⽚的I2C寄存器要想在Linux下读写芯⽚的I2C寄存器,⼀般需要在Linux编写⼀份该芯⽚的I2C驱动,关于Linux下如何编写I2C驱动,前⼀篇⽂章已经做了初步的介绍,并且留下了两个疑问尚未解决,第⼀个是如何对Linux提供的I2C操作函数进⾏进⼀步封装,实现对芯⽚寄存器的读写;另⼀个是如何在⽤户空间调⽤该I2C驱动代码。
本⽂将讨论前⼀个问题。
⾸先,我们要了解Linux系统提供的I2C操作函数怎么使⽤,上篇⽂章已经提到过,对I2C设备的读写,Linux系统提供了多种接⼝,这些接⼝可以在内核的 i2c.h 中找到,这⾥我主要介绍下⾯这组读写接⼝:extern int i2c_master_send(struct i2c_client *,const char* ,int);extern int i2c_master_recv(struct i2c_client *,char* ,int);第⼀个参数是 i2c_client 对象指针,第⼆个参数是要传输的数据buffer指针,第三个参数为buffer的⼤⼩。
接⼝函数已经有了,下⾯我们要解决的问题就是以何种形式/规则去使⽤这些接⼝才能正确地读写芯⽚的相关寄存器。
⾸先,我们需要查询芯⽚⼿册,找到芯⽚⼿册中,关于寄存器的I2C读写时序,其实,⼤多数芯⽚的I2C寄存器的读写时序都是⼀样的,下⾯我还是以⼿头的TVP5158芯⽚为例。
⾸先分析写操作,该芯⽚的⼿册中给出的I2C寄存器写时序图如下:从上图可以看出,真正需要执⾏写操作的有两处,Step4 和 Step6 ,Step4⾸先写⼊寄存器的偏移地址,⽽Step6则是写⼊到该寄存器的值。
由此已经很清楚了,对于写I2C寄存器,我们需要做的就是给 i2c_master_send 函数传⼊两个字节的数据即可,第⼀个字节为寄存器的地址,第⼆个字节为要写⼊寄存器的数据。
⽰例如下:static int tvp5158_i2c_write( struct i2c_client* client,uint8_t reg,uint8_t data){unsigned char buffer[2];buffer[0] = reg;buffer[1] = data;if( 2!= i2c_master_send(client,buffer,2) ) {printk( KERN_ERR " tvp5158_i2c_write fail! \n" );return -1;}return 0;}其实挺简单的,没有什么复杂的代码。
Linux I2C驱动源码分析
内核版本:2.6.31.6首先在S3C2440平台的初始化函数中,主要是将开发平台的设备注册进了系统,也就是将device注册到了platform虚拟的总线上,并进行了一些初始化的工作,这里我们只关注I2C的部分。
static void __init smdk2440_machine_init(void){s3c24xx_fb_set_platdata(&smdk2440_fb_info);s3c_i2c0_set_platdata(NULL);platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));smdk_machine_init();}s3c_i2c0_set_platdata()函数将S3C2440上的I2C控制器进行了一些初始化,但是并没有写入硬件寄存器,仅仅是保存在了s3c2410_platform_i2c结构体中。
void __init s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *pd){struct s3c2410_platform_i2c *npd;if (!pd)pd = &default_i2c_data0;npd = kmemdup(pd, sizeof(struct s3c2410_platform_i2c), GFP_KERNEL);if (!npd)printk(KERN_ERR "%s: no memory for platform data\n", __func__);else if (!npd->cfg_gpio)npd->cfg_gpio = s3c_i2c0_cfg_gpio;/* s3c_i2c0_cfg_gpio为配置I2C控制器GPIO函数指针 */s3c_device_i2c0.dev.platform_data = npd;/*最后将struct device 中的platform_data指针直指向了初始化后的s3c2410_platform_i2c结构体 */}函数s3c_i2c0_cfg_gpio()很简单,实际上就是配置GPIO为I2C的工作模式void s3c_i2c0_cfg_gpio(struct platform_device *dev){s3c2410_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPE15_IICSDA);s3c2410_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPE14_IICSCL);}s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *pd)函数实际上就是把初始化数据段中的default_i2c_data0结构体复制过来,然后对GPIO进行配置的函数指针进行了初始化。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
static int __init st_lis35de_init(void)
{
return i2c_add_driver(&st_lis35de_driver);//注册st_lis35de_driver
};
module_init(st_lis35de_init);
1 简介
I2C 总线仅仅使用 SCL 、 SDA 两根信号线就实现了设备之间的数据交互,极大地简化对硬件资源和 PCB 板布线空间的占用。因此, I2C 总线被非常广泛地应用在 EEPROM 、实时钟、小型 LCD 等设备与 CPU 的接口中。
Linux I2C GPIO驱动是在没有专用I2C芯片的情况下,用GPIO口来模拟I2C总线时序,完成Linux与I2C设备的通信过程。用两根GPIO,分别模拟SDA和SCL。它与使用i2c芯片的驱动有所不同的是传输算法的实现,GPIO模拟i2c驱动中有自己的一套传输算法。GPIO模拟I2C是要占用CPU资源的,而用I2C芯片是不占CPU资源的。使用i2c子系统,而不使用普通字符设备,有以下好处:
I2C总线驱动具体实现在/drivers/i2c目录下busses文件夹。例如:Linux I2C GPIO总线驱动为i2c_gpio.c. I2C总线算法在/drivers/i2c目录下algos文件夹。例如:Linux I2C GPIO总线驱动算法实现在i2c_algo_bit.c.
3) I2C 设备驱动
是对具体I2C硬件驱动的实现。I2C 设备驱动通过I2C适配器与CPU通信。其中主要包含i2c_driver和i2c_client数据结构,i2c_driver结构对应一套具体的驱动方法,例如:probe、remove、suspend等,需要自己申明。i2c_client数据结构由内核根据具体的设备注册信息自动生成,设备驱动根据硬件具体情况填充。具体使用下面介绍。
};
由于i2c_gpio驱动需要注册到platform总线上面,还需要在mach_xxx的板级文件中添加i2c-gpio的platform_device结构。
static struct platform_device i2c3_device = {
.name = "i2c-gpio", //必须和i2c-gpio驱动的名字相同
2 架构
Linux的I2C构架分为三个部分:
1)I2C core框架
提供了核心数据结构的定义和相关接口函数,用来实现I2C适配器
驱动和设备驱动的注册、注销管理,以及I2C通信方法上层的、与具体适配器无关的代码,为系统中每个I2C总线增加相应的读写方法。
I2C core框架具体实现在/drivers/i2c目录下的i2c-core.c和i2c-dev.c
.driver = {
.name = "lis35de", //驱动名字
},
};
最后调用static inline int i2c_add_driver(struct i2c_driver *driver)注册lis35de驱动到I2C总线,如下:
把i2c_gpio设备注册为平台设备,需要在mach_xxx的板级文件(devices.c)中添加i2c-gpio需要用到的资源定义,即将i2c总线设备封装成平台设备,下面首先定义总线占用的系统资源:
static struct i2c_gpio_platform_data i2c3_data = {
.remove = __devexit_p(i2c_gpio_remove),
};
static int __init i2c_gpio_init(void)
{
int ret;
ret = platform_driver_register(&i2c_gpio_driver);//注册成平台设备
1) i2c-gpio总线注册
/drivers/i2c/busses/i2c_gpio.c是i2c-gpio总线驱动源码。在这里可以看到i2c-gpio的注册:
static struct platform_driver i2c_gpio_driver = {
.driver = {
然后声明i2c_driver结构:
static struct i2c_driver st_lis35de_driver = {
.probe = st_lis35de_probe,
.remove = st_lis35de_remove,
.suspend = st_lis35de_suspend,
.resume = st_lis35de_resume,//上面4个函数根据具体情况取舍
.id_table = lis35de_id,
struct i2c_board_info const *info,//设备信息包括设备名,地址等
unsigned len)
例如:把lis35de驱动注册到i2c-gpio总线,总线ID为2。
static struct i2c_board_info i2c_devices_lis35de[] = {
if (ret)
printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret);
return ret;
}
module_init(i2c_gpio_init);
platform是linux虚拟的总线,称为platform总线,相应的设备称为platform_device,相应的驱动称为platform_driver。我们知道i2c总线也对应一个设备,在这里就是对应的i2c_adapte结构,这在后面会有详细介绍。在这里可以看到它将i2c总线驱动注册成平台设备驱动platform_driver_register(&i2c_gpio_driver)。
};
最后把i2c-gpio设备注册进platform总线。
platform_device_register(&i2c3_device);
Байду номын сангаас
2) 把i2c设备驱动注册到i2c-gpio总线
例如:设备驱动源码在/drivers/i2c/chips/lis35de.c,其注册到i2c总线需要的
.id = 2, //总线ID号
.dev = {
.platform_data = &i2c3_data,
},
};
注册i2c-gpio驱动前要有一个GPIO的设置过程,设置过程如下:
{
//SDA
I2C 设备驱动具体实现放在在/drivers/i2c目录下chips文件夹。
3 设备注册
下面以GPIO模拟i2c总线的驱动为例,来介绍设备注册,对于使用i2c芯片的驱动都是大同小异,主要在传输算法上的区别。首先make menuconfig把i2c-gpio选上,让它能编进内核。设备注册包括两种设备的注册,i2c-gpio总线和i2c设备驱动。
但是到目前还不知道注册到那根I2C总线,现在把lis35de设备驱动添加到我们想要的i2c-gpio总线上。使用内核提供的函数i2c_register_board_info,在mach_xxx的板级文件中把设备信息注册到需要注册的I2C总线上面。
int __init i2c_register_board_info(int busnum,//设备需要注册到的总线ID
.name = "i2c-gpio", //驱动名字
.owner = THIS_MODULE,
},
.probe = i2c_gpio_probe,
.sda_pin = CONFIG_SDA_PIN;
.scl_pin = CONFIG_SCL_PIN; //设置需要用到的gpio引脚
.udelay = 0, //设置I2C工作频率,如果没有默认值为50
.timeout = 0, //设置I2C工作超时,如果没有默认值为10
做法如下。首先定义设备ID:
static const struct i2c_device_id lis35de_id[] = {
{ "lis35de", 0 },//设备名和设备是有数据长度
{ }
};
2) I2C总线驱动
定义描述具体I2C总线适配器的i2c_adapter数据结构、实现在具体I2C适配器上的I2C总线通信方法,并由i2c_algorithm数据结构进行描述。 经过I2C总线驱动的的代码,可以为我们控制I2C产生开始位、停止位、读写周期以及从设备的读写、产生ACK等。
{
I2C_BOARD_INFO("lis35de", 0x1C), //设备名和地址
},
};
i2c_register_board_info(2,i2c_devices_lis35de,ARRAY_SIZE(i2c_devices_lis35de));
前面说了那么多,是不是有点乱了,这里我们在来理一下:
(一)i2c总线驱动
1)在那个devices.c文件中,声明平台设备占用的系统资源,然后定义一个平台设备,并注册这个平台设备到平台总线上
arch/arm/mach-pnx67xx/board_pnx67xx_wavex.c中unsigned int pnx_modem_gpio_reserved[]下注释掉GPIO_F7,GPIO_F8,防止内核认为F8,F7已经使用过了,至此已经把i2c-gpio总线注册到系统,把设备驱动注册到i2c-gpio总线。
1) 使用Linux I2C子系统,不需要去过于详细了解I2C操作。