我的内核学习笔记12:linux i2c-gpio驱动应用实例
linux内核的i2c-gpio是使用GPIO模拟I2C协议的驱动,只需要配置2根GPIO即可使用。Linux的I2C子系统比较复杂,笔者暂时还没有研究。本着“实用”的目的,介绍一下如何使用这个驱动及一些注意事项。
一、概述
Linux内核很多驱动都使用到I2C子系统。如EEPROM、RTC等。
GPIO模拟I2C协议的驱动位于drivers/i2c/busses目录。驱动名称为“i2c-gpio”,驱动文件为drivers/i2c/busses/i2c-gpio.c。
二、内核配置
Device Drivers->I2C support --->I2C Hardware Bus support ---><*> GPIO-based bitbanging I2C
从配置中看到将驱动整合到内核中,而不是module形式。这样能保证在其它I2C板级信息注册之前,已经存在了i2c总线。另外,还需要GPIO库支持:
[*] GPIO Support --->
否则无法不会出现选项“GPIO-based bitbanging I2C”。
三、设备注册及使用
3.1 I2C相关结构体
本文不是深入I2C子系统的,所以抛开原理方面的描述。看一下i2c平台数据结构i2c_gpio_platform_data的声明:
/*** struct i2c_gpio_platform_data - Platform-dependent data for i2c-gpio* @sda_pin: GPIO pin ID to use for SDA* @scl_pin: GPIO pin ID to use for SCL* @udelay: signal toggle delay. SCL frequency is (500 / udelay) kHz* @timeout: clock stretching timeout in jiffies. If the slave keeps* SCL low for longer than this, the transfer will time out.* @sda_is_open_drain: SDA is configured as open drain, i.e. the pin* isn't actively driven high when setting the output value high.* gpio_get_value() must return the actual pin state even if the* pin is configured as an output.* @scl_is_open_drain: SCL is set up as open drain. Same requirements* as for sda_is_open_drain apply.* @scl_is_output_only: SCL output drivers cannot be turned off.*/
struct i2c_gpio_platform_data {unsigned int sda_pin;unsigned int scl_pin;int udelay;int timeout;unsigned int sda_is_open_drain:1;unsigned int scl_is_open_drain:1;unsigned int scl_is_output_only:1;
};
重要的是sda_pin和scl_pin,分别表示I2C的SDA、SCL信号引脚。udelay可控制SCL频率,计算公式为:500/udelay kHZ。timeout为超时时间,单位为jiffies。sda_is_open_drain和scl_is_open_drain分别表示SDA和SCL是否为开漏电路,对此方面研究不深,不再描述。
一个实例如下:
static struct i2c_gpio_platform_data i2c_gpio_data = {.sda_pin = 68,.scl_pin = 88,.timeout = 100,.udelay = 2,
};
例子中使用的引脚分别为68和88,是由主板硬件确定的。
3.2 平台设备
static struct platform_driver i2c_gpio_driver = {.driver = {.name = "i2c-gpio",.owner = THIS_MODULE,.of_match_table = of_match_ptr(i2c_gpio_dt_ids),},.probe = i2c_gpio_probe,.remove = i2c_gpio_remove,
};static int __init i2c_gpio_init(void)
{int ret;ret = platform_driver_register(&i2c_gpio_driver);if (ret)printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret);return ret;
}
subsys_initcall(i2c_gpio_init);
从代码分析知,这里将GPIO模拟I2C总线当作平台设备处理。而从i2c_gpio_driver结构体中可以看到驱动名称为i2c-gpio。因此要使用这个驱动,必须另外定义一个platform设备,并调用函数platform_device_register注册。本文实例如下
static struct platform_device i2c_gpio_device = {.name = "i2c-gpio",.id = 0, // first bus for "i2c-gpio", so --> 0.dev = {.platform_data = &i2c_gpio_data,.release = platformdev_release,},
};
其中name表示设备名称,这里必须为“leds-gpio”,platform_data即为前面定义的i2c_gpio_data。id表示i2c-gpio的第几条I2C总线。驱动正常工作后,将生成/sys/bus/platform/devices/i2c-gpio.id目录,里面有挂载在此总线上的设备地址。
最后,注册设备——建议在板子的GPIO正常工作之后再进行注册。
platform_device_register(&i2c_gpio_device);
四、I2C板级信息注册
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设备名称、标志、地址等等信息。
static struct at24_platform_data at24_eeprom = {.byte_len = 2 * 1024 / 8,.page_size = 16,.flags = 0,
};static struct i2c_board_info my_i2c_boardinfo[] = {{I2C_BOARD_INFO("lm75", 0x48),},{I2C_BOARD_INFO("24c02", 0x50), // 24c02 == at24 driver.platform_data = &at24_eeprom,},
};
#define I2C_BOARD_INFO(dev_type, dev_addr) \.type = dev_type, .addr = (dev_addr)
常见注册方法有分静态注册i2c_register_board_info和动态注册i2c_new_device。大部分ARM框架都使用静态注册,使用很简单,如下:
i2c_register_board_info(0, i2c_info, ARRAY_SIZE(i2c_info));
不过如果以modules形式编译,则会提示i2c_register_board_info未定义:
WARNING: "i2c_register_board_info" [drivers/gpio/gpio-misc.ko] undefined!
这里使用第二种动态注册的方式。先调用i2c_get_adapter获取适配器(参数为i2c总线,根据前面i2c_gpio_device定义的id确定),然后调用i2c_new_device添加到该适配器中。代码片段如下:
struct i2c_adapter* adap = NULL;
struct i2c_client* client = NULL;adap = i2c_get_adapter(i2c_gpio_device.id);
if (adap)
{for (i = 0; i < ARRAY_SIZE(my_i2c_boardinfo); i++){client = i2c_new_device(adap, &my_i2c_boardinfo[i]);pr_info("Add %s to adapter %s %s.\n", my_i2c_boardinfo[i].type, adap->name, client?"ok":"failed");}
}
else
{pr_info("i2c bus %d found no adapter...\n", i2c_gpio_device.id);
}
五、用户空间
注:目录出现的0-0050表示该I2C设备在第0条总线上的0x50地址。
六、总结
使用GPIO模拟I2C驱动前,最好保证系统的GPIO已能正常工作。
在驱动中可以注册多条i2c-gpio总线,驱动名称均为i2c-gpio,但根据id值来区别不的同总线。比如主板上有3条GPIO模拟总线,则可分别命名为0、1、2。
参考资源:
1、内核源码官网:https://www.kernel.org
2、内核源码查询:http://lxr.free-electrons.com/source/?v=3.17
我的内核学习笔记12:linux i2c-gpio驱动应用实例相关推荐
- 我的内核学习笔记10:Intel GPIO驱动源码分析
本文对Intel e3800的GPIO驱动源码进行分析. 一.概述 1.1 内核配置 Intel e3800的GPIO在Linux内核中使用的驱动名为gpio_ich(为了行文方便,将对应的设备称为& ...
- 我的内核学习笔记7:Intel LPC驱动lpc_ich分析
接触这么久的内核代码,还没有真正分析一个完整的驱动源码,都是零零散散写只言片字.本文就作一个尝试,写一写Linux内核源码分析层面的文章. 本文介绍基于Intel baytrail系列的e3800系列 ...
- Linux学习笔记12——配置ftp、squid、Tomcat、Samba、MySQL主从
Linux学习笔记12 Linux学习笔记12 配置FTP服务 配置pure-ftpd 开机启动 上传下载文件 配置vsftpd CentOS 70安装配置Vsftp服务器 搭好vsftp之后出现55 ...
- 操作系统进程学习(Linux 内核学习笔记)
操作系统进程学习(Linux 内核学习笔记) 进程优先级 并非所有进程都具有相同的重要性.除了大多数我们所熟悉的进程优先级之外,进程还有不同的关键度类别,以满足不同需求.首先进程比较粗糙的划分,进程可 ...
- Linux学习笔记:Linux常用命令总结
文章目录 前言 Linux学习笔记:Linux常用命令总结 1. 目录命令 1.1 Linux目录结构 1.2 cd命令 切换工作目录 1.3 ls命令 显示目录下文件 1.4 mkdir命令 创建目 ...
- Windows x64内核学习笔记(四)—— 9-9-9-9-12分页
Windows x64内核学习笔记(四)-- 9-9-9-9-12分页 前言 9-9-9-9-12分页 实验一:线性地址转物理地址 页表基址 定位基址 PTE to PXE 实验二:通过页表基址定位各 ...
- 我的内核学习笔记5:proc目录文件创建及读写
上一篇内核学习笔记<我的内核学习笔记4:sysfs学习>是2013年写的,彼时至今,随着工作的展开和安排,内核方面的知识可谓突飞猛进,当然,其它方面亦是如此.关于内核方面,积累的笔记大大小 ...
- linux系统管理学习笔记之八---linux文件与目录的管理及权限
linux系统管理学习笔记之八---linux文件与目录的管理及权限 2010-01-05 09:00:49 标签:权限 管理 文件目录 linx [推送到技术圈] 版权声明:原创作品,允许转载,转载 ...
- Linux中常用的文件目录,Linux学习笔记2——Linux中常用文件目录操作命令
ls 显示文件和目录列表 -l 列出文件的详细信息 -a 列出当前目录所有文件,包含隐藏文件 mkdir 创建目录 -p 父目录不存在情况下先生成父目录 cd 切换目录 touch 生成一个空文件 e ...
最新文章
- Qt中如何改变三角形图形项的包围盒
- Django 模板HTML转义和CSRF4.3
- Matlab学习笔记——find()函数
- 神策数据受邀参加全国 APP 个人信息保护监管会
- 数据库系统(五)——数据库设计
- php rmdir 返回值,php通过rmdir删除目录的简单用法
- 665. 非递减数列 golang 切片越界问题的探讨(二)
- ansible软件部署
- linux获取进程io,linux查看哪个进程占用磁盘IO
- 【UVA11795】 Mega Man's Mission
- [转]unresolved external symbol _main解决办法
- IOUtils工具类的依赖maven
- 【ElementUI样式优化】el-input带自定义查询删除图标 ==> 图标点击可实现对应功能 ==> 一个input实现查询重置功能
- Zookeeper分布式锁解决羊群效应的方案
- 闭关六个月整理出来的微机原理知识点(特别适用河北专接本)
- PowerPoint演示文档大瘦身
- 微信公众号里放XLS链接教程
- lua与c#交互篇 | 合理用好lua+unity,更省性能的方案整理
- WAF学习之一——Nginx与反向代理
- 怎样使用word模板?两分钟教你搞定!
热门文章
- 佳恩半导体完成数千万A轮融资
- 抖音测试快递服务“音尊达” 已接入中通、圆通等,可送货上门
- 杀入“果链”!闻泰科技取代台厂成苹果MacBook组装供应商
- 又上热搜!鸿星尔克悄悄给山西捐赠2000万物资!这些大厂也出手了...
- 滴!你的“十三香”已发货,iPhone 13系列今日正式发售
- 研究机构预计芯片短缺将导致全球轻型汽车今年减产502万辆
- 年轻人开始“反算法”
- 法院才是最童叟无欺的一元店
- keep公众号就“借鉴”原创文章致歉:将停更一周
- 疑似全新华为Mate X2折叠屏手机入网:麒麟9000重磅加持