设备树中的i2c设备以及内核对i2c节点的处理过程
程序员文章站
2022-03-07 19:38:13
dtb文件中的i2c节点&i2c2 {clock-frequency = <100000>; //时钟频率pinctrl-names = "default";pinctrl-0 = <&pinctrl_i2c2>; //i2c使用的引脚status = "okay"; //默认状态为使能状态codec: wm8904@1a {compatible = "wlf,wm8904"; //...
dtb文件中的i2c节点
&i2c2 {
clock-frequency = <100000>; //时钟频率
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c2>; //i2c使用的引脚
status = "okay"; //默认状态为使能状态
codec: wm8904@1a {
compatible = "wlf,wm8904";
reg = <0x1a>; //设备地址
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 = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
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匹配驱动程序。
本文地址:https://blog.csdn.net/qq_17270067/article/details/107233760