mirror of https://gitee.com/openkylin/linux.git
i2c: core: add and export of_get_i2c_adapter_by_node() interface
of_find_i2c_adapter_by_node() call requires quite often missing put_device(), and i2c_put_adapter() releases a device locked by i2c_get_adapter() only. In general module_put(adapter->owner) and put_device(dev) are not interchangeable. This is a common error reproduction scenario as a result of the misusage described above (for clearness this is run on iMX6 platform with HDMI and I2C bus drivers compiled as kernel modules): root@mx6q:~# lsmod | grep i2c i2c_imx 10213 0 root@mx6q:~# lsmod | grep dw_hdmi_imx dw_hdmi_imx 3631 0 dw_hdmi 11846 1 dw_hdmi_imx imxdrm 8674 3 dw_hdmi_imx,imx_ipuv3_crtc,imx_ldb drm_kms_helper 113765 5 dw_hdmi,imxdrm,imx_ipuv3_crtc,imx_ldb root@mx6q:~# rmmod dw_hdmi_imx root@mx6q:~# lsmod | grep i2c i2c_imx 10213 -1 ^^^^^ root@mx6q:~# rmmod i2c_imx rmmod: ERROR: Module i2c_imx is in use To fix existing users of these interfaces and to avoid any further confusion and misusage in future, add one more interface of_get_i2c_adapter_by_node(), it is similar to i2c_get_adapter() in sense that an I2C bus device driver found and locked by user can be correctly unlocked by i2c_put_adapter(). Signed-off-by: Vladimir Zapolskiy <vladimir_zapolskiy@mentor.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
This commit is contained in:
parent
611e12ea0f
commit
48e9743dd6
|
@ -1371,6 +1371,24 @@ struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node)
|
|||
return adapter;
|
||||
}
|
||||
EXPORT_SYMBOL(of_find_i2c_adapter_by_node);
|
||||
|
||||
/* must call i2c_put_adapter() when done with returned i2c_adapter device */
|
||||
struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node *node)
|
||||
{
|
||||
struct i2c_adapter *adapter;
|
||||
|
||||
adapter = of_find_i2c_adapter_by_node(node);
|
||||
if (!adapter)
|
||||
return NULL;
|
||||
|
||||
if (!try_module_get(adapter->owner)) {
|
||||
put_device(&adapter->dev);
|
||||
adapter = NULL;
|
||||
}
|
||||
|
||||
return adapter;
|
||||
}
|
||||
EXPORT_SYMBOL(of_get_i2c_adapter_by_node);
|
||||
#else
|
||||
static void of_i2c_register_devices(struct i2c_adapter *adap) { }
|
||||
#endif /* CONFIG_OF */
|
||||
|
|
|
@ -638,6 +638,8 @@ extern struct i2c_client *of_find_i2c_device_by_node(struct device_node *node);
|
|||
/* must call put_device() when done with returned i2c_adapter device */
|
||||
extern struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node);
|
||||
|
||||
/* must call i2c_put_adapter() when done with returned i2c_adapter device */
|
||||
struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node *node);
|
||||
#else
|
||||
|
||||
static inline struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
|
||||
|
@ -649,6 +651,11 @@ static inline struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node
|
|||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node *node)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
#endif /* _LINUX_I2C_H */
|
||||
|
|
Loading…
Reference in New Issue