我的内核学习笔记12:linux i2c-gpio驱动应用实例
来源:互联网 发布:sl会员商城源码 编辑:程序博客网 时间:2024/05/17 05:56
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(0, i2c_info, ARRAY_SIZE(i2c_info));
不过如果以modules形式编译,则会提示i2c_register_board_info未定义:
WARNING: "i2c_register_board_info" [drivers/gpio/gpio-misc.ko] undefined!
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);}
五、用户空间
六、总结
使用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驱动应用实例
- 我的内核学习笔记11:linux leds-gpio驱动应用实例
- linux内核GPIO模拟I2C实例
- linux内核GPIO模拟I2C实例
- linux GPIO-i2c驱动
- 我的内核学习笔记10:Intel GPIO驱动源码分析
- I2C学习笔记--linux内核下的I2C
- 55 linux内核里基于GPIO口的I2C控制器驱动
- linux I2C驱动学习笔记
- Linux 内核gpio模拟I2C
- linux 内核GPIO 模拟 I2C
- linux的GPIO应用实例
- Linux 内核GPIO的学习
- Linux内核驱动GPIO的使用
- Linux内核驱动GPIO的使用
- Linux内核驱动GPIO的使用
- Linux内核驱动GPIO的使用
- Linux内核驱动GPIO的使用
- 压缩感知入门--论文解读 1.Compressive Sensing by Richard G. Baraniuk
- [读书笔记]30 天自制操作系统 day7 FIFO与鼠标控制
- KMP算法
- 如何使用JMX监控Kafka
- openwrt uci api续: 找出匿名节点的"名字"
- 我的内核学习笔记12:linux i2c-gpio驱动应用实例
- poj 3233 Matrix Power Series 构造矩阵求等比矩阵和
- [AHK]同花顺treeview树状控件控制(点击资金股票)
- 项目中的常见控件popupWindow
- 小学生算数题
- MySQL数据库(二)
- angular下载文件数据流:乱谈 Blob 与 Object URL
- 【Codeforces Round #383 (Div. 2)】 (A,B,C)
- 堆栈