I2C设备Linux驱动程序

9
如何为i2c设备制作字符设备,包括open、close、ioctl等功能?我在过去两周中一直在寻找相关信息,但没有找到可用的信息。在Essential Linux Device Drivers中找到了一些信息,但它是针对2.6内核编写的,而我使用的是3.4.79(我正在尝试为cubian distr上的cubieboard2编写此驱动程序),因此这本书有许多已弃用的函数。我试图按照那里的方式编写我的驱动程序,但仍然无法工作(当我尝试cat字符设备时会给我内核错误)。有人能解释一下该怎么做,或者至少给我一个可行的示例吗?
所以,这是我的代码: http://pastebin.com/T7PBTpym 我只是尝试使i2c总线正常工作,但在示波器上看不到i2c线上的任何东西,虽然编译时没有出现错误。另外,我找不到如何将设备驱动程序附加到i2c总线号码上,因为我在cubieboard2上有4个i2c总线,例如如何将设备驱动程序附加到i2c-1总线?

您可能不需要从头编写i2c内核驱动程序;现今的内核提供了i2c子系统,对于像Cubieboard2这样使用Allwinner SOC的设备而言,它可能得到良好的支持(尽管我也有可能被纠正!)您是否搜索过其他用例?问题可能在于如何打开它,然后从用户空间访问它... - 6EQUJ5
1
根据硬件情况,您可能需要在i2c线上添加上拉电阻。 - 6EQUJ5
Linux源代码采用了Copy-Left协议,因此您可以下载Linux源代码(它是免费的),然后找到现有的I2C驱动程序并查看其实现方式。也许只需修改配置文件并重新编译/配置/安装Linux操作系统即可。 - user3629249
  1. 如果您的I2C客户端设备使用低负载和单客户端,则选择i2c-gpio。不要为I2C主机控制器而苦苦挣扎。
  2. 请下载开源内核并参考/drivers/misc/fsa9480.c(它使用i2c-gpio驱动程序)。
- kzs
1个回答

15

谢谢大家,我几个小时前就找到了我想要的东西。所以我看到有三种类型的驱动程序。一种应该插入内核中,你需要重新构建内核才能使用它们。还有一些可以通过设备属性在sysfs中使用的驱动程序(它们出现在/sys/bus/i2c/driver/your_driver/中)。第三种是我这种类型的驱动程序,看起来像字符设备。实际上,你可以将它们组合起来。

因此,如果你想使用最后一种设备类型,会稍微难一些,因为几乎所有的例子都专门针对前两种类型的驱动程序。无论如何,如果你想创建一个字符设备,你需要描述file_operations结构中的函数。但是,所有像i2c_transferi2c_smbus_read_byte等的函数(完整列表)都需要struct i2c_adapterstruct i2c_client。那么就有两个问题,如何获取这些结构,以及如何将驱动程序连接到适当的i2c总线,例如i2c-2?

因此,有一个函数在这里没有描述:i2c_get_adapter。你需要传递i2c总线编号作为参数。它返回一个指向i2c_adapter结构的链接。可以使用i2c_new_dummy函数,通过将i2c_adapter和从设备地址作为参数传递给它来获取i2c_client结构。

之后,你就可以使用诸如i2c_transferi2c_smbus_read_byte等函数。最后,你可以描述file_operations结构中的函数,并释放代表你的i2c设备的驱动程序,而不使用sysfs和重新构建内核。

结果代码如下:

u8 ret; 
struct i2c_client * my_client; 
struct i2c_adapter * my_adap = i2c_get_adapter(1); // 1 means i2c-1 bus
my_client = i2c_new_dummy (my_adap, 0x69); // 0x69 - slave address on i2c bus
i2c_smbus_write_byte(my_client, 0x0f); 
ret = i2c_smbus_read_byte(my_client);
您可以直接在文件操作结构的函数中使用此代码。
希望这些信息对像我一样的初学者有用。

在您的示例中,从设备地址(0x69)是我们分配给计算机i2c驱动程序以在从模式下运行的地址吗?我想在从模式下使用SoC模块的i2c,但内核(3.14.77)不支持它。 - Rasoul
这不是正确的方法。请查看定义 struct i2c_driver 的任何驱动程序以获取答案。您需要定义一个.probe方法并给出名称或名称列表。内核将在与您的名称匹配的任何I2C设备上调用您的探测方法。探测方法看起来像my_probe(struct i2c_client *client, const struct i2c_device_id *id)。如您所见,i2c_client已经可以使用了。您不需要在硬编码的总线和地址处创建虚拟的客户端。 - TrentP
这实际上非常有用,因为它允许您开发一个可以动态加载的驱动程序;如果您使用“探测”方法来做得“正确”,则需要修改DTS并重新构建内核映像。对于快速迭代地启动原型,这是非常合适的 - 但确实,一旦工作正常,您将使用“探测”来正确初始化它。 - Den-Jason

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接