一、i2c总线(i2c_bus_type)注册过程
路径:drivers\i2c\i2c-core.c
struct bus_type i2c_bus_type = {
.name = "i2c",
.match = i2c_device_match,
.probe = i2c_device_probe,
.remove = i2c_device_remove,
.shutdown = i2c_device_shutdown,
};
postcore_initcall(i2c_init); //kernel启动自动运行 i2c_init() 函数
static int __init i2c_init(void)
{
/* ... */
retval = bus_register(&i2c_bus_type); //注册i2c总线bus
/* ... */
}
二、i2c子系统框架分析
1、i2c_adapter、i2c_client 生成过程
整体过程:
设备树/i2c节点一般表示i2c控制器,它会被转换为platform_device,在内核中有对应的platform_driver,一般为厂商所配套的platform_driver文件。platform_driver的probe函数中会调用i2c_add_numbered_adapter,注册I2C适配器,然后将I2C子设备都转换为i2c_client。之后会将 i2c_client 和 所有i2c_driver做匹配, 如果匹配就调用 i2c_driver的 .probe 函数。.probe 函数就是注册字符设备的那一套流程了。
- i2c_adapter:dts中每个i2c节点对应一个i2c适配器(芯片厂商一般已经做好了)
- i2c_client:dts中i2c节点下的子设备(我们通过配置设备树添加i2c_client)
- i2c_driver:i2c的设备驱动,与i2c_client 的 compatible 需匹配上(由我们自己编写)
函数执行流程:
设备树i2c节点生成platform_device和厂商提供的platform_driver匹配后,调用probe函数,会注册i2c_adapter。
i2c_imx_probe
i2c_add_numbered_adapter /* 添加I2C控制器 */
__i2c_add_numbered_adapter
i2c_register_adapter /* 注册I2C控制器*/
device_register /* 注册 I2C控制器adapter,如 I2C-0 */
of_i2c_register_devices /* 查找注册设备树控制器下面的子设备节点 */
of_i2c_register_device /*解析注册设备树i2c子节点属性*/
i2c_new_device /* 设备树中的i2c子节点被转换为i2c_client */
client->dev.bus = &i2c_bus_type;
device_register /* 添加设备I2C从设备 */
device_add()
i2c_scan_static_board_info /* 查找静态表,有些I2C设备是在代码中写死的,不是通过设备树的形式 */
i2c_new_device
client->dev.bus = &i2c_bus_type;
device_register /* 添加设备I2C从设备 */
device_add()
i2c_new_device 注册i2c_client(放入i2c_bus_type的dev链表), 这会和i2c_driver的id_table比较,如果匹配,调用i2c_driver的.probe。
2、i2c_driver 生成过程
i2c_driver侧一般由我们自己编写,i2c_add_driver()调用driver_register()和 i2c_for_each_dev(driver, __process_new_driver)。
- driver_register():注册i2c_driver(添加到i2c_bus_type的drv链表),将i2c_bus_type的dev链表取出每一项i2c_client做匹配,匹配上则调用.probe。
- i2c_for_each_dev(driver, __process_new_driver):对于每一个适配器,调用它的函数确定address_list里的设备是否存在,如果存在,再调用i2c_driver的.detect函数进一步确定、设置,然后i2c_new_device()注册i2c_client。
i2c的发送函数在i2c_adapter中,下图很好的解释了它们的关系。
三、i2c子系统源码分析
以 imx6ull 为例
设备树文件
i2c1: i2c@021a0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,imx6ul-i2c", "fsl,imx21-i2c";
reg = <0x021a0000 0x4000>;
interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_I2C1>;
status = "disabled";
};
&i2c1 {
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
status = "okay";
mag3110@0e {
compatible = "fsl,mag3110";
reg = <0x0e>;
};
};
Linux内核I2C的platform_driver代码(drivers\i2c\busses\i2c-imx.c)
static const struct of_device_id i2c_imx_dt_ids[] = {
{ .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, },
{ .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, },
{ .compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, },
{ /* sentinel */ }
};
static struct platform_driver i2c_imx_driver = {
.probe = i2c_imx_probe,
.remove = i2c_imx_remove,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = i2c_imx_dt_ids,
.pm = IMX_I2C_PM,
},
.id_table = imx_i2c_devtype,
};
i2c1控制器转换为platform_device,它的 compatible 与 i2c_imx_driver 的 of_match_table 匹配,调用 .probe(i2c_imx_probe)。
i2c_imx_probe分析
static struct i2c_algorithm i2c_imx_algo = {
.master_xfer = i2c_imx_xfer, //i2c发送函数
.functionality = i2c_imx_func,
};
static int i2c_imx_probe(struct platform_device *pdev)
{
/* 根据 platform_device 内容配置硬件i2c */
/* ... */
i2c_imx->adapter.algo = &i2c_imx_algo;
/* ... */
ret = i2c_add_numbered_adapter(&i2c_imx->adapter);
/* ... */
}
i2c_add_numbered_adapter
int i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
/* i2c_add_adapter() 和 __i2c_add_numbered_adapter() 功能类似,
最终都是调用 i2c_register_adapter
*/
if (adap->nr == -1) /* -1 means dynamically assign bus id */
return i2c_add_adapter(adap);
return __i2c_add_numbered_adapter(adap);
}
__i2c_add_numbered_adapter
static int __i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
int id;
mutex_lock(&core_lock);
id = idr_alloc(&i2c_adapter_idr, adap, adap->nr, adap->nr + 1,
GFP_KERNEL);
mutex_unlock(&core_lock);
if (id < 0)
return id == -ENOSPC ? -EBUSY : id;
return i2c_register_adapter(adap);
}
i2c_register_adapter
static int i2c_register_adapter(struct i2c_adapter *adap)
{
/* ... */
/* 注册I2C适配器adapter设备到 i2c_bus_type */
/* 设置adap->dev.kobj.name 为 i2c-0,它将出现在sysfs */
dev_set_name(&adap->dev, "i2c-%d", adap->nr);
adap->dev.bus = &i2c_bus_type; //绑定到i2c总线i2c_bus_type
adap->dev.type = &i2c_adapter_type; //adapter类型
res = device_register(&adap->dev); //注册i2c适配器
/* ... */
of_i2c_register_devices(adap); /* 查找设备树控制器下面的子设备 */
/* ... */
/* 静态方式,循环必须 __i2c_board_list 中的设备,如果跟本适配器匹配。就注册 */
if (adap->nr < __i2c_first_dynamic_bus_num)
i2c_scan_static_board_info(adap);
/* ... */
}
of_i2c_register_devices
static void of_i2c_register_devices(struct i2c_adapter *adap)
{
/* adap->dev.of_node :i2c适配器节点
node :每次for循环指向i2c适配器下的子节点
*/
for_each_available_child_of_node(adap->dev.of_node, node)
of_i2c_register_device(adap, node); /*解析设备树属性*/
}
of_i2c_register_device函数,该函数主要用于解析i2c节点设备树内容。
static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
struct device_node *node)
{
struct i2c_client *result;
struct i2c_board_info info = {};
struct dev_archdata dev_ad = {};
const __be32 *addr_be;
u32 addr;
int len;
dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name);
//获取i2c节点中的compatible属性 拷贝到info.type中
if (of_modalias_node(node, info.type, sizeof(info.type)) < 0)
{
dev_err(&adap->dev, "of_i2c: modalias failure on %s\n",
node->full_name);
return ERR_PTR(-EINVAL);
}
//获取i2c节点中的reg属性(设备地址)
addr_be = of_get_property(node, "reg", &len);
if (!addr_be || (len < sizeof(*addr_be))) {
dev_err(&adap->dev, "of_i2c: invalid reg on %s\n",
node->full_name);
return ERR_PTR(-EINVAL);
}
//解析设备地址
addr = be32_to_cpup(addr_be);
if (addr & I2C_TEN_BIT_ADDRESS) {
addr &= ~I2C_TEN_BIT_ADDRESS;
info.flags |= I2C_CLIENT_TEN;
}
if (addr & I2C_OWN_SLAVE_ADDRESS) {
addr &= ~I2C_OWN_SLAVE_ADDRESS;
info.flags |= I2C_CLIENT_SLAVE;
}
//检查设备地址
if (i2c_check_addr_validity(addr, info.flags)) {
dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
addr, node->full_name);
return ERR_PTR(-EINVAL);
}
info.addr = addr;
info.of_node = of_node_get(node); //将设备树节点存入info.of_node
info.archdata = &dev_ad;
if (of_get_property(node, "wakeup-source", NULL))
info.flags |= I2C_CLIENT_WAKE;
//注册i2c子设备,生成i2c_client
result = i2c_new_device(adap, &info);
if (result == NULL) {
dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
node->full_name);
of_node_put(node);
return ERR_PTR(-EINVAL);
}
return result;
}
i2c_new_device函数
struct i2c_client *
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
{
struct i2c_client *client;
/* 将i2c适配器子设备节点转换为client */
client->adapter = adap; // 设定设备的适配器,之后会使用适配器的发送函数
client->addr = info->addr; // 地址
client->irq = info->irq; // 中断号
/* 设置 client->dev */
client->dev.parent = &client->adapter->dev;
client->dev.bus = &i2c_bus_type; // 绑定总线
client->dev.type = &i2c_client_type;
client->dev.of_node = info->of_node;
client->dev.fwnode = info->fwnode;
device_register(&client->dev); //向总线注册设备
return client;
}
下面分析device_register(driver/base/core.c)的过程
int device_register(struct device *dev)
{
/*初始化dev,为了在sys下生成节点,会先初始化kobj和kset*/
device_initialize(dev);
return device_add(dev);
}
int device_add(struct device *dev)
{
/* ... */
bus_add_device(dev);
/* ... */
bus_probe_device(dev);
/* ... */
}
int bus_add_device(struct device *dev)
{
/* 将设备添加到总线的设备链表中(bus->p->klist_devices) */
klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);
}
void bus_probe_device(struct device *dev)
{
device_attach(dev);
}
int device_attach(struct device *dev)
{
return __device_attach(dev, false);
}
int __device_attach(struct device *dev, bool allow_async)
{
ret = bus_for_each_drv(dev->bus, NULL, &data,
__device_attach_driver);
}
int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
void *data, int (*fn)(struct device_driver *, void *))
{
/* 遍历总线的驱动链表上的所有驱动,调用fn函数 */
while ((drv = next_driver(&i)) && !error)
error = fn(drv, data);
}
这里的fn函数指的是__device_attach_driver函数
static inline int driver_match_device(struct device_driver *drv,
struct device *dev)
{
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
int __device_attach_driver(struct device_driver *drv, void *_data)
{
ret = driver_match_device(drv, dev); //通过i2c总线的match比较device和driver是否匹配
if (ret == 0) {
/* no match */
return 0;
}
return driver_probe_device(drv, dev);
}
可以看到匹配成功后,会调用driver_probe_device函数,下面看一看这个函数
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
really_probe(dev, drv);
}
static int really_probe(struct device *dev, struct device_driver *drv)
{
/* 调用了i2c总线的probe函数 */
dev->bus->probe(dev);
}
i2c总线的probe为 i2c_device_probe
struct bus_type i2c_bus_type = {
.name = "i2c",
.match = i2c_device_match,
.probe = i2c_device_probe,
.remove = i2c_device_remove,
.shutdown = i2c_device_shutdown,
.pm = &i2c_device_pm_ops,
};
可以知道,总线的probe函数是i2c_device_probe
static int i2c_device_probe(struct device *dev)
{
/* 调用i2c_driver驱动的probe函数 */
driver->probe(client, i2c_match_id(driver->id_table, client));
}
最终调用i2c_dirver的.probe函数。