pmbus

最主要是 module_i2c_driver(mpc42013_driver); ,其 struct 定義:

  • static struct i2c_driver mpc42013_driver
    • .driver
    • .probe_new
    • .remove
    • .id_table
欄位名稱 類型 作用 什麼時候會被呼叫
.driver struct device_driver 提供「驅動的基本資訊」與「配對資訊」,像是名字、支援哪些 Device Tree 相容字串等 核心 driver model 用來做比對與註冊
.probe_new int (*)(struct i2c_client *client) 驅動成功匹配裝置時會執行的初始化函式(新 API,建議使用) 有相容裝置註冊時由 i2c_device_probe() 呼叫
.remove void (*)(struct i2c_client *client) 當裝置被移除時(例如 hotplug 拔除、模組卸載),這個函式會負責做清理 在驅動卸載、裝置移除時由 i2c_device_remove() 呼叫
.id_table const struct i2c_device_id * 用於 legacy 比對(非 Device Tree 的平台),像 x86 上的硬體 傳統平台配對用,會傳入 probe() 的第二參數

這是來自 include/linux/i2c.h 的 marco

module_i2c_driver

  • module_i2c_driver marc
    ​#define module_i2c_driver(__i2c_driver) \
    ​	module_driver(__i2c_driver, i2c_add_driver, i2c_del_driver)
    
    • 再展開在include/linux/device.hmodule_driver
    ​#define module_driver(__driver, __register, __unregister) \
    ​static int __init __driver##_init(void) \
    ​{ return __register(&(__driver)); } \
    ​static void __exit __driver##_exit(void) \
    ​{ __unregister(&(__driver)); } \
    ​module_init(__driver##_init); \
    ​module_exit(__driver##_exit);
    

裡面的要填寫的結構定義在 include/linux/i2c.h

struct i2c_driver {
    unsigned int class;

    // 當 kernel 找到匹配的 I2C 裝置後會呼叫 probe()
    int (*probe)(struct i2c_client *client);

    // 裝置移除時呼叫
    void (*remove)(struct i2c_client *client);

    // 系統關機或重新啟動時會呼叫
    void (*shutdown)(struct i2c_client *client);

    // SMBus alert 機制(可選)
    void (*alert)(struct i2c_client *client,
                  enum i2c_alert_protocol protocol,
                  unsigned int data);

    // 可選:如 ioctl 介面給使用者空間
    int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);

    // 核心的 generic driver model 結構
    struct device_driver driver;

    // 用來匹配 I2C 裝置 ID(legacy)
    const struct i2c_device_id *id_table;

    // 若是 Device Tree 平台,這是用來 match 的 DT compatible list
    const struct of_device_id *of_match_table;

    // 用於非 OF 平台上的 auto-detect(常用於 hwmon)
    int (*detect)(struct i2c_client *client, struct i2c_board_info *info);
    const unsigned short *address_list;

    // 核心維護的 device list
    struct list_head clients;

    u32 flags;  // enum i2c_driver_flags 中的位元旗標
};

其中 .driver 是在 include/linux/device.hstruct device_driver

  • include/linux/device.h
/**
 * struct device_driver - The basic device driver structure
 * @name:   Name of the device driver.
 * @bus:    The bus which the device of this driver belongs to.
 * @probe:  Callback to check if the driver can handle a given device.
 * @remove: Callback to remove the device.
 * ...
 */
struct device_driver {
	const char		*name;
	struct bus_type		*bus;

	struct module		*owner;

	const struct of_device_id	*of_match_table;
	const struct acpi_device_id	*acpi_match_table;

	int (*probe)	(struct device *dev);
	void (*remove)	(struct device *dev);
	void (*shutdown) (struct device *dev);
	int (*suspend)	(struct device *dev, pm_message_t state);
	int (*resume)	(struct device *dev);
	...
};

欄位 說明
name 驅動名稱,用於 sysfs (/sys/bus/.../drivers/)
bus 所屬的 bus(如 i2c_bus_type, pci_bus_type
owner 通常填入 THIS_MODULE,讓 kernel 知道這個 driver 的 module 是誰
probe() 當有裝置與此驅動匹配時,會被呼叫
remove() 裝置移除時呼叫
of_match_table Device Tree 的 compatible 比對表
acpi_match_table ACPI 裝置比對表(在 x86 平台常用)

.driver

  • name
  • of_match_table:
    • .compatible : 會去找對應在 Device Tree 中的 compatible 欄位
    • .data (optional)

.probe

  • 定義在 include/linux/i2c.h 裡的 struct i2c_driver 中:
struct i2c_driver {
    ...
    int (*probe)(struct i2c_client *client, const struct i2c_device_id *id);
    ...
};
// drivers/i2c/i2c-core-base.c
// 函式名稱:i2c_device_probe()

static int i2c_device_probe(struct device *dev)
{
    ...
    const struct i2c_device_id *id;

    // 把 driver 轉成 i2c_driver 型別
    struct i2c_driver *driver = to_i2c_driver(dev->driver);

    ...

    if (driver->probe_new) {
        // 如果你實作的是 probe_new,就用這個
        status = driver->probe_new(client);
    } else {
        // 否則使用傳統的 probe(),這時還會找 id_table
        id = i2c_match_id(driver->id_table, client);
        if (!id)
            return -ENODEV;
        status = driver->probe(client, id);
    }

    ...
} 

I2C Core

系統事件

match

Device Tree/ACPI 宣告一個 I2C device

或是手動呼叫 i2c_new_client_device()

i2c-core 建立 struct device

呼叫 bus_type.match: i2c_device_match

match 成功 → 呼叫 bus_type.probe: i2c_device_probe

進入驅動的 probe() or probe_new()

driver->probe_new 存在?

否 → 找 id_table 比對

Device Tree / Platform 裝置註冊

i2c-core-base.c

i2c_device_probe()

是 → 呼叫 probe_new()

呼叫 probe(client, id)

名稱 傳統 API 新 API(建議用)
probe() id_table
probe_new() 不帶 id_table ✅ 較簡單現代寫法
差異 probe() probe_new()
參數 struct i2c_client *, const struct i2c_device_id * struct i2c_client *
匹配來源 傳統 I2C core 用 .id_table 傳入 Device Tree / ACPI 直接用 .of_match_table
適用平台 非 OF、非 ACPI 系統 現代嵌入式系統(使用 Device Tree 或 ACPI)
哪個比較新? ✅ 比較舊 ✅ 建議使用的新式方式

.id_table

legacy 平台(非 Device Tree)配對用

  • 用於非 Device Tree 的平台(例如 x86 BIOS 平台)
  • 比對方式是透過 client->name 比對 mychip 字串
  • probe_new 的時候不一定要寫

debug

  • dev_info(&client->dev, "Using probe_new() for device %s\n", dev_name(&client->dev));

TODO