I2C从驱动到应用(中篇)

Linux中对I2C的支持非常全面,既提供了内核态的访问方式,也提供了用户态的访问方法。

Linux中对I2C的支持可以分为两个层面,一个是adapter和algorithm,对应的是i2c控制器;再一个是driver和client.Linux内核提供了丰富的接口来实添加i2c设备驱动。要添加一个i2c设备驱动,需要几个固定的步骤。首先,需要往i2c设备列表里添加一组设备ID
foo_idtable:

static
struct i2c_device_id foo_idtable[] = {

{
"foo", my_id_for_foo },

{
"bar", my_id_for_bar },

{
}

};

MODULE_DEVICE_TABLE(i2c,
foo_idtable);

然后填充i2c
driver的数据结构:

static
struct i2c_driver foo_driver = {

.driver = {

.name   =
"foo",

.pm =
&foo_pm_ops,  /* optional */

},

.id_table   =
foo_idtable,

.probe      =
foo_probe,

.remove     =
foo_remove,

/*
if device autodetection is needed: */

.class      =
I2C_CLASS_SOMETHING,

.detect     =
foo_detect,

.address_list
 = normal_i2c,

.shutdown   =
foo_shutdown, /* optional */

.command    =
foo_command,  /* optional, deprecated */

}

剩下的就是逐一初始化foo_probe()、foo_remove()、foo_detect()等函数。一旦准备好了相应的client结构,就可以实现foo_read_valule()和foo_write_value()函数,当然这两者都是基于底层公共的i2c/smbus读写函数:i2c_smbus_read/write_byte_data/word()去实现。

如果确实有i2c设备挂载在某个i2c总线上,可以通过填充i2c_board_info数据结构来构造这个设备的实例,然后调用i2c_new_device()来探测实际接入的i2c设备。当然也可能事先无法确认系统上有什么类型的i2c设备,这个时候需要定义一个call
back函数,放在probe()后面,让它去确认是否有指定类型的i2c设备挂在系统上。使用完设备后,可以调用i2c_unregister_device()来注销之前注册的设备。当然执行这些所有操作的前提是设备对应的驱动已经被初始化好并且加载到内核,可以参考下面的代码来实现初始化和退出操作:

static
int __init foo_init(void)

{

return
i2c_add_driver(&foo_driver);

}

module_init(foo_init);

static
void __exit foo_cleanup(void)

{

i2c_del_driver(&foo_driver);

}

module_exit(foo_cleanup);

The
module_i2c_driver() macro can be used to reduce above code.

module_i2c_driver(foo_driver);

如果驱动中,需要向设备发送或者从设备接受数据,可以调用:

int
i2c_master_send(struct i2c_client *client, const char *buf, int
count);

int
i2c_master_recv(struct i2c_client *client, char *buf, int count);

这两组函数来实现,更多的函数在linux/i2c.h中有说明。

当然linux内核中也提供了设备作为从设备的驱动,这中情况下的系统层次图如下所示:

e.g. sysfs  
   I2C slave events        I/O registers

+-----------+
 v    +---------+     v     +--------+  v  +------------+

|
Userspace +........+ Backend +-----------+ Driver +-----+ Controller
|

+-----------+
      +---------+           +--------+     +------------+

|
|

----------------------------------------------------------------+--
I2C

--------------------------------------------------------------+----
Bus

不同于PCI/USB设备,I2C没有提供硬件上自动枚举的能力,因此在初始化i2c设备之前需要显式地指定设备的地址。内核提供了多个显式初始化一个i2c设备的方法:

1、通过bus
number声明一个i2c设备:

这种情况尤其适用于i2c作为系统总线的嵌入式系统,以omp2
h4为例,用户需要注册i2c
board info:

Example
(from omap2 h4):

static
struct i2c_board_info h4_i2c_board_info[] __initdata = {

{

I2C_BOARD_INFO("isp1301_omap",
0x2d),

.irq        =
OMAP_GPIO_IRQ(125),

},

{
 /* EEPROM on mainboard */

I2C_BOARD_INFO("24c01",
0x52),

.platform_data
= &m24c01,

},

{
 /* EEPROM on cpu card */

I2C_BOARD_INFO("24c01",
0x57),

.platform_data
= &m24c01,

},

};

static
void __init omap_h4_init(void)

{

(...)

i2c_register_board_info(1,
h4_i2c_board_info,

ARRAY_SIZE(h4_i2c_board_info));

(...)

}

2、通过设备树申明一个i2c设备:

这种方式需要把心建的设备节点挂在master
conrollor对应的设备树上,也就是说它必须是master
controller的子节点,如下面的例子所示:

i2c1:
[email protected] {

/* ... master
properties skipped ... */

clock-frequency
= <100000>;

[email protected] {

compatible
= "atmel,24c256";

reg =
<0x50>;

};

pca9532:
[email protected] {

compatible
= "nxp,pca9532";

gpio-controller;

#gpio-cells
= <2>;

reg =
<0x60>;

};

};

3、通过ACPI申明一个I2C设备:

ACPI表里能够申明I2C设备:Documentation/acpi/enumeration.txt。

4、显式地实例化i2c设备:

这也是通过填充i2c_board_info数据结构,然后调用i2c_new_device()实现的,如下面的代码所示:

static
struct i2c_board_info sfe4001_hwmon_info = {

I2C_BOARD_INFO("max6647",
0x4e),

};

int
sfe4001_init(struct efx_nic *efx)

{

(...)

efx->board_info.hwmon_client
=

i2c_new_device(&efx->i2c_adap,
&sfe4001_hwmon_info);

(...)

}

上面的代码在i2c
bus上实例化了一个i2c设备。

5、对一些特殊的设备进行自动探测

有的系统上并没有提供足够多的关于i2c设备和拓扑信息,这个时候就需要依赖i2c-core去探测设备,这就要求:

  • i2c设备驱动必须实现detect()函数;
  • 只有挂载了这种设备的i2c总线能够且允许被探测。

6、利用/sysfs通过用户态初始化i2c设备

比如我们需要把位于i2c地址0x50的eerom添加到设备当中去,可以直接操作sysfs实现:

echo
eeprom 0x50 > /sys/bus/i2c/devices/i2c-3/new_device

时间: 2024-08-23 11:45:48

I2C从驱动到应用(中篇)的相关文章

I2C设备驱动的编写

前面我们说了如何I2C用户模式驱动,这种驱动基于I2C子系统,但是他对于应用程序开发人员的要求较高,需要应用程序开发人员了解硬件的一些东西,比如时序,地址等等,而多数时候应用程序开发人员是按照操作文件的方法操作设备,所以我们更希望用一些更简单的接口去访问.也就是我们今天的内容——基于I2C子系统的字符驱动. I2C子系统的代码分为三部分如图:  Host:主机控制器驱动 Device:设备驱动代码 Core: 核心代码,提供设备与控制器的接口 一.主机控制器驱动 Linux下主机控制器驱动,大多

SylixOS iMX6平台I2C总线驱动

原理概述 I2C总线驱动概述 I2C总线驱动是I2C适配器的软件实现,提供I2C适配器与从设备间完成数据通信的能力,比如起始,停止,应答信号和MasterXfer的实现函数.驱动程序包含初始化I2C总线控制器__i2cHwInit函数,操作函数集(总线传输__i2cTransfer函数,总线控制__i2cMasterCtl函数). Imx6ul控制器的硬件描述 imx6ul处理器内部集成了一个I2C控制器,通过五个寄存器来进行控制. I2Cx_IADR I2C地址寄存器 I2Cx_IFDR I2

Linux I2C设备驱动编写(二)

在(一)中简述了Linux I2C子系统的三个主要成员i2c_adapter.i2c_driver.i2c_client.三者的关系也在上一节进行了描述.应该已经算是对Linux I2C子系统有了初步的了解.下面再对他们之间的关系进行代码层的深入分析,我认为对他们的关系了解的越好,越有助于I2C设备的驱动开发及调试. 带着问题去分析可能会更有帮助吧,通过对(一)的了解后,可能会产生以下的几点疑问: i2c_adapter驱动如何添加? i2c_client与i2c_board_info究竟是什么

Linux I2C设备驱动编写(一)

在Linux驱动中I2C系统中主要包含以下几个成员: I2C adapter 即I2C适配器 I2C driver 某个I2C设备的设备驱动,可以以driver理解. I2C client 某个I2C设备的设备声明,可以以device理解. I2C adapter 是CPU集成或外接的I2C适配器,用来控制各种I2C从设备,其驱动需要完成对适配器的完整描述,最主要的工作是需要完成i2c_algorithm结构体.这个结构体包含了此I2C控制器的数据传输具体实现,以及对外上报此设备所支持的功能类型

【转】Linux I2C设备驱动编写(三)-实例分析AM3359

原文网址:http://www.cnblogs.com/biglucky/p/4059586.html TI-AM3359 I2C适配器实例分析 I2C Spec简述 特性: 兼容飞利浦I2C 2.1版本规格 支持标准模式(100K bits/s)和快速模式(400K bits/s) 多路接收.发送模式 支持7bit.10bit设备地址模式 32字节FIFO缓冲区 可编程时钟发生器 双DMA通道,一条中断线 三个I2C模块实例I2C0\I2C1\I2C2 时钟信号能够达到最高48MHz,来自PR

【转】Linux I2C设备驱动编写(一)

原文网址:http://www.cnblogs.com/biglucky/p/4059576.html 在Linux驱动中I2C系统中主要包含以下几个成员: I2C adapter 即I2C适配器 I2C driver 某个I2C设备的设备驱动,可以以driver理解. I2C client 某个I2C设备的设备声明,可以以device理解. I2C adapter 是CPU集成或外接的I2C适配器,用来控制各种I2C从设备,其驱动需要完成对适配器的完整描述,最主要的工作是需要完成i2c_alg

【转】Linux I2C设备驱动编写(二)

原文网址:http://www.cnblogs.com/biglucky/p/4059582.html 在(一)中简述了Linux I2C子系统的三个主要成员i2c_adapter.i2c_driver.i2c_client.三者的关系也在上一节进行了描述.应该已经算是对Linux I2C子系统有了初步的了解.下面再对他们之间的关系进行代码层的深入分析,我认为对他们的关系了解的越好,越有助于I2C设备的驱动开发及调试. 带着问题去分析可能会更有帮助吧,通过对(一)的了解后,可能会产生以下的几点疑

Linux I2C设备驱动编写(三)-实例分析AM3359

TI-AM3359 I2C适配器实例分析 I2C Spec简述 特性: 兼容飞利浦I2C 2.1版本规格 支持标准模式(100K bits/s)和快速模式(400K bits/s) 多路接收.发送模式 支持7bit.10bit设备地址模式 32字节FIFO缓冲区 可编程时钟发生器 双DMA通道,一条中断线 三个I2C模块实例I2C0\I2C1\I2C2 时钟信号能够达到最高48MHz,来自PRCM 不支持 SCCB协议 高速模式(3.4MBPS) 管脚 管脚 类型 描述 I2Cx_SCL I/O

linux驱动之i2c总线驱动调用分析【基于linux4.4】

平台:RK3399 使用设备树描述板级资源: 框架: linux i2c框架同样采用分层.分离的模式设计:从上到下分为  app调用层.i2c core层.驱动层:驱动层又分为 cpu平台 i2c控制器相关的驱动层以及 i2c总线上挂接的设备驱动程序:而分离的思想则体现在板级相关的信息放在设备树上实现,而通用的读写.初始化流程.操作流程等则放到驱动里面实现(类似platform总线驱动): 具体分析: 1. cpu i2c控制器驱动(adpter) static struct platform_