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: i2c@400a0000 {
/* ... master properties skipped ... */
clock-frequency = <100000>;
flash@50 {
compatible = "atmel,24c256";
reg = <0x50>;
};
pca9532: gpio@60 {
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
本文转自存储之厨51CTO博客,原文链接:http://blog.51cto.com/xiamachao/1704679 ,如需转载请自行联系原作者
I2C从驱动到应用(中篇)相关推荐
- linux下i2c设备驱动程序,Linux I2C 设备驱动
I2C 设备驱动要使用 i2c_driver 和 i2c_client 数据结构并填充其中的成员函数.i2c_client 一般被包含在设备的私有信息结构体yyy_data 中,而 i2c_drive ...
- SylixOS iMX6平台I2C总线驱动
原理概述 I2C总线驱动概述 I2C总线驱动是I2C适配器的软件实现,提供I2C适配器与从设备间完成数据通信的能力,比如起始,停止,应答信号和MasterXfer的实现函数.驱动程序包含初始化I2C总 ...
- Linux I2C子系统分析-I2C设备驱动
接下来以一个实际的例子来看I2C设备驱动,就以drivers/i2c/i2c-dev.c为例. 先看它的初始化和注销函数 [cpp] view plaincopy static int __init ...
- Linux I2C子系统分析-I2C总线驱动
在drivers/i2c/busses下包含各种I2C总线驱动,如S3C2440的I2C总线驱动i2c-s3c2410.c,使用GPIO模拟I2C总线的驱动i2c-gpio.c,这里只分析i2c-gp ...
- 用户空间访问I2C设备驱动
2012-01-11 15:33:43 标签:Linux I2C 字符设备 设备驱动 用户空间 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任. ...
- 手把手教你写Linux I2C设备驱动
手把手教你写Linux I2C设备驱动 标签:Linux 设备 驱动 详解 i2c 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http:/ ...
- RT-Thread I2C设备驱动框架的对接使用
I2C和SPI是MCU和板载芯片之间最常用的通讯方式,现在先介绍下I2C总线.I2C的基本原理也很简单,只需要两根线(时钟线SCL和信号线SDA)即可实现挂载在I2C总线上设备之间的相互通讯.I2C协 ...
- Linux的I2C 设备驱动 -- mini2440 上i2c接口触摸屏驱动
本篇记录在友善之臂 mini2440 平台上挂载I2C接口触摸屏的驱动开发过程. 内核版本linux-2.6.32.2, 平台是ARM9 S3C2440+I2C接口的触摸屏 如上篇 Linux的I2C ...
- linux探测i2c设备连接状态,手把手教你写Linux I2C设备驱动
Linux I2C驱动是嵌入式Linux驱动开发人员经常需要编写的一种驱动,因为凡是系统中使用到的I2C设备,几乎都需要编写相应的I2C驱动去配置和控制它,例如 RTC实时时钟芯片.音视频采集芯片.音 ...
最新文章
- springboot集成prometheus
- hdu 3579(中国剩余定理非互质)
- 09-对象的定义方式
- 后端技术:Nginx + Spring Boot 实现负载均衡
- 原来记录系统日志那么简单【Java】【SpringBoot】【Mybatis Plus】【AspcetJ】
- 影响索引的mysql函数_mysql索引对排序的影响实例分析
- Spring Boot使用hikari、druid、c3p0等数据库连接池详解
- html的table属性笔记
- React Native随笔 2--重要函数
- php.ini – 配置文件详解
- 35岁逃离北上广,40岁失业送外卖,中年人的“体面”在于投资自己
- 求助vmbox更新之后打不开了
- 启动kafka2.8报afka.common.KafkaException: No `meta.properties` found in /tmp/kraft-combined-logs
- InsightFace-Paddle实现人脸比对
- php下单声音提醒,拼多多商家怎么设置下单的声音?开启方法是什么?
- linux log file
- Edge浏览器的主页被360篡改的解决办法
- Data Integration - Kettle8.2使用(一)Kettle下载安装
- 阿里巴巴获得商品详情 API调用示例
- 互联网大资本是如何剥削你的?
热门文章
- 计算机基础知识应用文档,计算机基础知识与应用
- mac 下系统目录权限问题
- 【Java并发编程】—–“J.U.C”:ConcurrentLinkedQueue
- C#连接MySql数据库的方法
- innodb参数汇总
- AngularJS 学习笔记 - $http.post 跟后台交互
- java中各进制之间的转换(十进制转十六进制、十进制转二进制、二进制转十进制、二进制转十六进制)...
- iphone开发如何测试?
- “以史为鉴”-企业信息化的梳理-前言
- android 动态修改 selector,Android Selector 按下修改背景和文本颜色的实现代码