临沂住房和城乡建设局网站打不开,wordpress中文菜单,网站设计市场价,wordpress中文标签404I2C 子系统I2C 子系统使用的概率非常大#xff0c;我之前有做过手机的经验#xff0c; 手机跑的安卓系统#xff0c;内核是Linux#xff0c;手机的很多器件都是用I2C通信的#xff0c;我经历过从板级设备到dts设备树的阶段#xff0c;知道I2C在整个系统的举足轻重#x… I2C 子系统I2C 子系统使用的概率非常大我之前有做过手机的经验 手机跑的安卓系统内核是Linux手机的很多器件都是用I2C通信的我经历过从板级设备到dts设备树的阶段知道I2C在整个系统的举足轻重正常的TPCamera,sonser等等都是使用I2C进行控制的。吹牛逼这么多就是让大家知道理解I2C子系统的重要性不过这篇文章就写一个小细节I2C驱动的probe是如何被触发的如果你不知道其中的原理可能在写驱动的时候不能成功执行probe也是有可能的。static const struct i2c_device_id goodix_ts_id[] { { GTP_I2C_NAME, 0 }, { }
}; static struct of_device_id goodix_ts_dt_ids[] { { .compatible goodix,gt9xx }, { }
}; static struct i2c_driver goodix_ts_driver { .probe goodix_ts_probe, .remove goodix_ts_remove, .id_table goodix_ts_id, .driver { .name GTP_I2C_NAME, .owner THIS_MODULE, .of_match_table of_match_ptr(goodix_ts_dt_ids), },
}; /*******************************************************
Function: Driver Install function.
Input: None.
Output: Executive Outcomes. 0---succeed.
********************************************************/
static int goodix_ts_init(void)
{ s32 ret; /* ...... */ ret i2c_add_driver(goodix_ts_driver); return ret;
}i2c_add_driver 驱动和设备匹配i2c_add_driver()i2c_register_driver driver_register driver_find bus_add_driver driver_attach bus_for_each_dev next_device__driver_attachdriver_match_devicei2c_device_match acpi_driver_match_devicei2c_match_id of_driver_match_device of_match_device of_match_node__of_match_node__of_device_is_compatible这个要说明的一个点是我提出来一下可能大家看代码的时候就不会那么困惑了Linux 下的指针那么多你每次如果调用都要追根溯源那可能需要花费非常多的时间。总线上的device和driver进行匹配的时候会调用 bus 对应的 match函数对于i2c bus而言就是i2c_match如果是platform_bus 那么就会回调到platform_match里面去执行。static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, const struct i2c_client *client)
{ while (id-name[0]) { if (strcmp(client-name, id-name) 0) return id; id; } return NULL;
} static int i2c_device_match(struct device *dev, struct device_driver *drv)
{ struct i2c_client *client i2c_verify_client(dev); struct i2c_driver *driver; if (!client) return 0; /* Attempt an OF style match */ if (of_driver_match_device(dev, drv)) return 1; /* Then ACPI style match */ if (acpi_driver_match_device(dev, drv)) return 1; driver to_i2c_driver(drv); /* match on an id table if there is one */ if (driver-id_table) return i2c_match_id(driver-id_table, client) ! NULL; return 0;
}里面有三种 match 的函数最后才会调用 i2c_match_id 这个函数这个也是低版本内核还没有使用dts的时候使用的方式也就是匹配dev和driver的name。看下面新的 compatible 匹配方式/** * __of_device_is_compatible() - Check if the node matches given constraints * device: pointer to node * compat: required compatible string, NULL or for any match * type: required device_type value, NULL or for any match * name: required node name, NULL or for any match * * Checks if the given compat, type and name strings match the * properties of the given device. A constraints can be skipped by * passing NULL or an empty string as the constraint. * * Returns 0 for no match, and a positive integer on match. The return * value is a relative score with larger values indicating better * matches. The score is weighted for the most specific compatible value * to get the highest score. Matching type is next, followed by matching * name. Practically speaking, this results in the following priority * order for matches: * * 1. specific compatible type name * 2. specific compatible type * 3. specific compatible name * 4. specific compatible * 5. general compatible type name * 6. general compatible type * 7. general compatible name * 8. general compatible * 9. type name * 10. type * 11. name */
static int __of_device_is_compatible(const struct device_node *device, const char *compat, const char *type, const char *name)
{ struct property *prop; const char *cp; int index 0, score 0; /* Compatible match has highest priority */ if (compat compat[0]) { /*获取dts里面该节点的值*/ prop __of_find_property(device, compatible, NULL); for (cp of_prop_next_string(prop, NULL); cp; cp of_prop_next_string(prop, cp), index) { /*字符串比较*/ if (of_compat_cmp(cp, compat, strlen(compat)) 0) { score INT_MAX/2 - (index 2); break; } } /*返回成功*/ if (!score) return 0; } /* Matching type is better than matching name */ if (type type[0]) { if (!device-type || of_node_cmp(type, device-type)) return 0; score 2; } /* Matching name is a bit better than not */ if (name name[0]) { if (!device-name || of_node_cmp(name, device-name)) return 0; score; } return score;
}代码里面我们看到是同时比较 name typecompatible 这三个属性的但是我们使用dts进行设置的时候name和type的属性很多时候都是空的。i2c1 { status okay; /* ...... */ gt9xx: gt9xx14 { compatible goodix,gt9xx; reg 0x14; touch-gpio gpio1 0 IRQ_TYPE_EDGE_RISING; reset-gpio gpio0 11 GPIO_ACTIVE_HIGH; max-x 800; max-y 1280; tp-size 89; configfile-num 1; status okay; tp-supply vcc3v0_tp; };
}; i2c probe被探测 执行的流程i2c_add_driver()i2c_register_driver driver_register driver_find kset_find_obj kobject_put to_driverbus_add_driverdriver_attach bus_for_each_dev next_device__driver_attachdriver_match_device driver_probe_device really_probei2c_device_probei2c_match_id你以为上面设置就好了吗我们看到static struct i2c_driver goodix_ts_driver { .probe goodix_ts_probe, .remove goodix_ts_remove, .id_table goodix_ts_id, .driver { .name GTP_I2C_NAME, .owner THIS_MODULE, .of_match_table of_match_ptr(goodix_ts_dt_ids), },
};里面有一个 id_tabel和一个 of_match_table 两个东西既然probe探测只需要 of_match_tabel就可以了是不是可以去掉id_tabel了呢这感觉是一个遗留问题在i2c_probe函数里面有一个判断不知道历史原因还是为何不能做到完全兼容看代码如下static int i2c_device_probe(struct device *dev)
{ /* ...... */ driver to_i2c_driver(dev-driver); /* 判断id_table为空就退出 */ if (!driver-probe || !driver-id_table) return -ENODEV; /* ...... */
}扫码或长按关注回复「 加群 」进入技术群聊