我已经编写了一个i2c驱动程序,仅用于测试目的。
我正在使用Rasperry Pi 3,并且已将两个ssd1306 OLED displays连接到GPIO引脚接头上的I2C引脚。我可以使用i2c-tools使用地址0x3c和0x3d连接到它。
我可以使用i2c-set将数据发送到显示器:
i2cset -y 1 0x3c [data]
i2cset -y 1 0x3d [data]
命令
i2cdetect -y 1
给我以下输出:
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- 3c 3d -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
我正在使用以下驱动程序来查看它的作用以及Linux中的I2C如何工作:
#include "i2c_test.h"
#include <linux/module.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/i2c.h>
#include <linux/mod_devicetable.h>
#define print_client(c) printk("%s: Client (Name: %s), (Flags: %x), (Addr: %x), (Adapter: ), (Device: ), (IRQ: %d)\n",\
__FUNCTION__, c->name, c->flags, c->addr, c->irq)
#define print_board(b) printk("%s: Board (Type: %s), (Flags: %x), (Addr: %x), (IRQ: %d)\n",\
__FUNCTION__, b->type, (unsigned int)b->flags, (unsigned int)b->addr, b->irq)
static struct i2c_device_id ssd1306_idtable[] = {
{ "ssd1306", 0 },
{}
};
const unsigned short ssd1306_address_list[] = {
0x3c,
0x3d,
0x7a,
0x78,
};
MODULE_DEVICE_TABLE(i2c, ssd1306_idtable);
struct dev_pm_ops ssd1306_pm_ops = {
// Don't know how to use
};
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)
int ssd1306_probe(struct i2c_client* client, const struct i2c_device_id * dev_id)
{
print_client(client);
return 0;
}
#else //LINUX_VERSION_CODE > KERNEL_VERSION(4,10,0)
int ssd1306_probe_new(struct i2c_client* client)
{
print_client(client);
return 0;
}
#endif // Kernel version
int ssd1306_remove(struct i2c_client* client)
{
print_client(client);
return 0;
}
void ssd1306_shutdown(struct i2c_client* client)
{
print_client(client);
}
int ssd1306_detect(struct i2c_client* client, struct i2c_board_info* board_info)
{
print_client(client);
print_board(board_info);
return 0;
}
static struct i2c_driver ssd1306_driver = {
.driver = {
.name = "i2c_test",
.pm = &ssd1306_pm_ops
},
.id_table = ssd1306_idtable,
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)
.probe = ssd1306_probe,
#else //LINUX_VERSION_CODE > KERNEL_VERSION(4,10,0)
.probe_new = ssd1306_probe_new, //needs Kernel 4.10 or later
#endif //Kernel Version
.remove = ssd1306_remove,
.class = I2C_CLASS_HWMON, // correct??
.detect = ssd1306_detect,
.address_list = ssd1306_address_list,
//.command = ssd1306_command,
.shutdown = ssd1306_shutdown
};
static int __init mod_init(void)
{
printk("init " __FILE__ "\n");
i2c_add_driver(&ssd1306_driver);
printk("driver added!\n");
return 0;
}
static void __exit mod_exit(void)
{
printk("remove driver\n");
i2c_del_driver(&ssd1306_driver);
printk("driver removed\n");
printk("exit " __FILE__ "\n");
}
module_init( mod_init );
module_exit( mod_exit );
MODULE_LICENSE("GPL");
我通过dmesg获得以下输出:
[ 1676.649683] init /home/pi/projects/playground/i2c_test/i2c_test.c
[ 1676.649790] driver added!
[ 1812.043182] remove driver
[ 1812.043301] driver removed
[ 1812.043306] exit /home/pi/projects/playground/i2c_test/i2c_test.c
如果有人知道该做什么或我做错了什么并且可以帮助我,那就太好了。
由于
p0kR
答案 0 :(得分:1)
首先,I2C设备不像USB设备那样动态枚举。 如果您的驱动程序是内置的,显然您的驱动程序将被调用。无需通过sysfs接口访问它。 如果您正在使用设备树,请在.dts中添加您的i2c设备详细信息,并在启动期间调用您的驱动程序。
答案 1 :(得分:0)
模块加载时不会自动探测I2C器件(I2C不提供任何标准方法)。因此,要调用驱动程序的探测函数,您需要告诉内核驱动程序应该处理哪个I2C地址。使用sysfs的简单方法是:
# echo [your_device_name] [your_device_i2c_addr] > /sys/bus/i2c/devices/i2c-[i2c_bus_number]/new_device
(用适当的数字和名称替换方括号中的部分)
在您的特定情况下,它将是
# echo ssd1306 0x3c > /sys/bus/i2c/devices/i2c-1/new_device
请注意,内核不会对您进行任何检查,因此无论是否连接了I2C设备,都会调用probe
函数。
其他方法包括,例如,在设备树数据中指定您的设备和驱动程序。有关详细信息,请参阅linux kernel documentation。
编辑:实际上在某些情况下存在自动检测(然后调用detect
函数),但I2C总线必须同意它(并且设备类必须匹配,等等) 。但据我所知,此方法不适用于一般设备,而是用于PC等内部监控传感器。在大多数情况下,明确指定设备是首选方法。