Heng30的博客
搜索 分类 关于 订阅

Linux驱动使用I2C通信协议

2025-03-12

很好奇I2C设备是如何与驱动进行匹配的吧?一般是通过设备树文件来描述I2C从设备的信息,例如名称和地址等。驱动通过和名称与从设备进行匹配。不过下面的例子不使用设备树文件,而是手动匹配从设备。具体方法看测试章节。

驱动代码

// simple.c

#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>

struct my_data {
    char name[32];
    int i;
};

static struct my_data data_1 = {
    .name = "device a",
    .i = 1,
};

static struct my_data data_2 = {
    .name = "device b",
    .i = 2,
};

static struct i2c_device_id my_ids[] = {
    {"device-a", (size_t)&data_1},
    {"device-b", (size_t)&data_2},
    {},
};
MODULE_DEVICE_TABLE(i2c, my_ids);

static int _probe(struct i2c_client *client) {
    pr_info("simple_probe\n");

    const struct i2c_device_id *id = i2c_match_id(my_ids, client);
    if (!id) {
        pr_err("i2c_match_id found\n");
        return -ENODEV;
    }

    struct my_data *data = (struct my_data *)id->driver_data;
    if (data) {
        pr_info("%s data->i = %d\n", data->name, data->i);
    } else {
        pr_err("id->driver_data is null\n");
    }

    return 0;
}

static void _remove(struct i2c_client *client) { pr_info("simple_remove\n"); }

static struct i2c_driver my_driver = {
    .probe = _probe,
    .remove = _remove,
    .id_table = my_ids,
    .driver =
        {
            .name = "my-i2c-driver",
        },
};

module_i2c_driver(my_driver);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("heng30");
MODULE_VERSION("v0.0.1");
MODULE_DESCRIPTION("A simple kernel module");

编译脚本

#!/bin/sh

top-dir = $(shell pwd)
kernel-version = $(shell uname -r)
kernel-dir ?= /lib/modules/$(kernel-version)/build

obj-m += simple.o

all:
        make -C $(kernel-dir) modules M=$(top-dir)

clean:
        rm -f *.o *.ko *.mod *.mod.c *.order *.symvers *.dtbo
        make -C $(kernel-dir) clean m=$(top-dir)

测试

  • 编译程序:make

  • 安装驱动:insmod simple.ko

  • 查看i2c总线:i2cdetect -y 0

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- --
10: 10 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
  • 添加i2c从设备:echo device-a 0x10 > /sys/bus/i2c/devices/i2c-0/new_device

  • 查看输出:dmesg

[112662.497446] simple_probe
[112662.497457] device a data->i = 1
[112662.497477] i2c i2c-0: new_device: Instantiated device device-a at 0x10
  • 移除i2c从设备:echo 0x10 > /sys/bus/i2c/devices/i2c-0/delete_device

  • 移除驱动:rmmod simple.ko