加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 黄冈站长网 (http://www.0713zz.com/)- 数据应用、建站、人体识别、智能机器人、语音技术!
当前位置: 首页 > 教程 > 正文

借助Linux中IIC子系统做IIC驱动

发布时间:2021-11-24 17:42:04 所属栏目:教程 来源:互联网
导读:背景描述 IIC总线在嵌入式系统中应用十分广泛,常见的有eeprom,rtc。一般的处理器会包含IIC的控制器,用来完成IIC时序的控制;另外一方面,由于IIC的时序简单,使用GPIO口来模拟时序也是常见的做法。面对不同的IIC控制器,各种各样的芯片以及linux源码,如

背景描述
 
IIC总线在嵌入式系统中应用十分广泛,常见的有eeprom,rtc。一般的处理器会包含IIC的控制器,用来完成IIC时序的控制;另外一方面,由于IIC的时序简单,使用GPIO口来模拟时序也是常见的做法。面对不同的IIC控制器,各种各样的芯片以及linux源码,如何更快做好IIC设备驱动。
 
问题描述
 
在我们的方案中,我们会用到eeprom,rtc以及tw2865。由于Hi3520的IIC控制器设计有问题,无法正常使用。而IIC控制器的SDA和SCL管脚正好是和两个GPIO管脚复用的。Hisi将控制gpio来实现IIC的时序,从而对IIC设备进行操作。这种设计方式简单明了,但使用IIC子系统,可以更方便的移植和维护其他的设备驱动。
 
问题分析
 
Hisi对于gpio口,rtc芯片以及tw2865的处理方式如下:将gpio口做成一个模块化的驱动,该驱动模拟IIC时序,并向外提供一些函数接口,比如:EXPORT_SYMBOL(gpio_i2c_read_tw2815);等。对于具体的rtc芯片,将其注册为一个misc设备,并利用gpio模块导出的函数进行rtc芯片的配置操作。
 
其实对于linux-2.6.24driversi2c目录下代码,我们可以加以利用。
 
Linux的IIC字结构分为三个组成部分:
 
IIC核心
 
IIC核心提供了IIC总线驱动和设备驱动的注册、注销方法,IICalgorithm上层的、与具体适配器无关的代码以及探测设备、检测设备地址的上层代码。
 
IIC总线驱动
 
IIC总线驱动是对IIC硬件体系结构中适配器端的实现。
 
IIC设备驱动
 
IIC设备驱动是对IIC硬件体系总设备端的实现。
 
 
 
我们查看下该目录下的makefile和kconfig:
 
obj-$(CONFIG_I2C_BOARDINFO) +=i2c-boardinfo.o
 
obj-$(CONFIG_I2C) += i2c-core.o
 
obj-$(CONFIG_I2C_CHARDEV) +=i2c-dev.o
 
obj-y +=busses/ chips/ algos/
 
i2c-core.c就是IIC核心,buses中的文件是主流处理器中IIC总线的总线驱动,而chips中的文件就是常用芯片的驱动,algos中的文件实现了一些总线适配器的algorithm,其中就包括我们要用到的i2c-algo-bit.c文件。
 
我们首先利用i2c-gpio.c和i2c-algo-bit.c做好总线驱动。
 
 
 
在i2c-gpio.c中,module_initài2c_gpio_initàplatform_driver_probe(&i2c_gpio_driver,i2c_gpio_probe);
 
将其注册为platform虚拟总线的驱动。
 
在staticint __init i2c_gpio_probe(struct platform_device *pdev)中,
 
定义了如下三个结构体:
 
structi2c_gpio_platform_data *pdata;//平台相关的gpio的设置
 
structi2c_algo_bit_data *bit_data;//包含algorithm的具体函数,setor get SDA和SCL
 
structi2c_adapter *adap;//适配器
 
i2c_gpio_probe主要做了下面几件事:
 
填充bit_data结构的各个函数指针,关联到具体的操作SDA和SCl函数。
 
填充adap结构,adap->algo_data= bit_data;
 
pdata= pdev->dev.platform_data;
 
bit_data->data= pdata;
 
pdev->dev->driver_data= adap;
 
在i2c-core中注册适配器类型。
 
inti2c_bit_add_numbered_bus(struct i2c_adapter *adap)
 
在staticint i2c_bit_prepare_bus(struct i2c_adapter *adap)中
 
adap->algo= &i2c_bit_algo;
 
将i2c_bit_algo与adap关联上。
 
static const structi2c_algorithm i2c_bit_algo = {
 
.master_xfer = bit_xfer,
 
.functionality = bit_func,
 
};
 
其中,master_xfer函数指针就是IIC传输函数指针。
 
I2c-algo-bit.c还实现了IIC开始条件,结束条件的模拟,发送字节,接收字节以及应答位的处理。
 
 
 
i2c-gpio.c中的i2c_gpio_setsda_val等函数是与具体平台gpio相关的。
 
修改对应arch-hi3520v100目录下的gpio.h中的各个函数,这些函数是通过操作寄存器来控制gpio的方向和值。
 
 
 
 
 
在对应mach-hi3520v100中的platform-devices.c中添加如下:
 
static structi2c_gpio_platform_data pdata = {
 
.sda_pin = 1<<0,
 
.sda_is_open_drain = 1,
 
.scl_pin = 1<<1,
 
.scl_is_open_drain = 1,
 
.udelay = 4, /* ~100 kHz */
 
};
 
 
 
static struct platform_devicehisilicon_i2c_gpio_device = {
 
.name = "i2c-gpio",
 
.id = -1,
 
.dev.platform_data = &pdata,
 
};
 
 
 
 
 
 
 
static struct platform_device*hisilicon_plat_devs[] __initdata = {
 
 
 
&hisilicon_i2c_gpio_device,
 
};
 
 
 
 
 
int __inithisilicon_register_platform_devices(void)
 
{
 
platform_add_devices(hisilicon_plat_devs,ARRAY_SIZE (hisilicon_plat_devs));
 
return 0;
 
}
 
通过platform添加devices和driver,使得pdev->dev.platform_data=pdata
 
 
 
综合上面的过程,我们完成了adapter的注册,并将用gpio口模拟的algorithm与adapter完成了关联。
 
 
 
这样,在rtc-x1205.c中,x1205_attach函数利用i2c核心完成client和adap的关联。
 
在x1205_probe函数中填充i2c_client结构体,并调用i2c_attach_client通知iic核心。
 
接着注册rtc驱动。
 
 
 
最后我们要读取时间,就需要构造i2c_msg结构体,如下所示:
 
struct i2c_msg msgs[] = {
 
{ client->addr, 0, 2,dt_addr }, /* setup read ptr */
 
{ client->addr, I2C_M_RD,8, buf }, /* read date */
 
};
 
 
 
/* read date registers */
 
if((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
 
dev_err(&client->dev,"%s: read errorn", __FUNCTION__);
 
return -EIO;
 
}
 
dt_addr是寄存器的地址,I2C_M_RD表示iicread。
 
 
 
经验总结
 
IIC总线虽然并不复杂,但linux下的IIC子系统却有相当的复杂度。做了很多的抽象工作,代码变得得难理解,但为后续移植驱动工作提供了很多便利条件。在调试gpio的adap时,最关键的是对于busdevice driver设备模型的理解。对sysfs和proc文件系统很熟悉的话,在调试驱动和后期维护方面大有益处。

(编辑:PHP编程网 - 黄冈站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读