dtb文件中的i2c节点
&i2c2 {
clock-frequency = <100000>; //时钟频率
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c2>; //i2c使用的引脚
status = "okay"; //默认状态为使能状态
codec: wm8904@1a {
compatible = "wlf,wm8904";
reg = <0x1a>; //高7位设备地址
clocks = <&clk IMX8MQ_CLK_SAI2_SRC>; //使用的时钟
clock-names = "mclk";
};
....
}
dtsi文件中的i2c节点
i2c2: i2c@30a30000 {
#address-cells = <1>; //表示用一个32位的数来描述地址
#size-cells = <0>; //表示用0个32位的数来描述该地址的大小
compatible = "fsl,imx21-i2c"; //匹配的platform_driver
//起始地址0x30a30000 长度0x10000
reg = <0x0 0x30a30000 0x0 0x10000>;
//使用的中断 以及触发方式
interrupts = ;
clocks = <&clk IMX8MQ_CLK_I2C2_ROOT>;
status = "disabled";
};
/i2c节点一般表示i2c控制器, 它会被转换为platform_device, 在内核中有对应的platform_driver;一般为厂商所配套的platform_driver文件(freescale的处理文件为i2c-imx.c)。platform_driver的probe函数中会调用i2c_add_numbered_adapter():
/* 将设备树转换成platform_device后i2c_imx_probe函数被调用 */
i2c_imx_probe
i2c_add_numbered_adapter /* 添加I2C控制器 */
__i2c_add_numbered_adapter
i2c_register_adapter /* 注册I2C控制器 */
device_register /* I2C控制器设备注册 */
of_i2c_register_devices /* 查找设备树控制器下面的从设备 */
of_i2c_register_device /*解析设备树属性*/
i2c_new_device
client->dev.bus = &i2c_bus_type;
device_register /* 添加设备I2C从设备 */
i2c_scan_static_board_info /* 查找静态表,有些I2C设备是在代码中写死的,不是通过设备树的形式 */
i2c_new_device
client->dev.bus = &i2c_bus_type;
device_register /* 添加设备I2C从设备 */
下面我们来看一下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 设备
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设备注册后,将通过i2c_bus_type.i2c_device_match匹配驱动程序。
i2c设备匹配的过程中会调用到i2c_device_probe(),位于driver/i2c/i2c-core.c。此函数中也有设备树相关的处理。
static int i2c_device_probe(struct device *dev)
{
struct i2c_client *client = i2c_verify_client(dev);
struct i2c_driver *driver;
int status;
if (!client)
return 0;
if (!client->irq && dev->of_node) {
int irq = of_irq_get(dev->of_node, 0); //得到节点中的中断号
if (irq == -EPROBE_DEFER)
return irq;
if (irq < 0)
irq = 0;
client->irq = irq;
}
driver = to_i2c_driver(dev->driver);
if (!driver->probe || !driver->id_table)
return -ENODEV;
if (!device_can_wakeup(&client->dev))
device_init_wakeup(&client->dev,
client->flags & I2C_CLIENT_WAKE);
dev_dbg(dev, "probe\n");
status = of_clk_set_defaults(dev->of_node, false);
if (status < 0)
return status;
status = dev_pm_domain_attach(&client->dev, true);
if (status != -EPROBE_DEFER) {
status = driver->probe(client, i2c_match_id(driver->id_table,
client));
if (status)
dev_pm_domain_detach(&client->dev, true);
}
return status;
}