diff options
author | Vladimir Zapolskiy <vladimir_zapolskiy@mentor.com> | 2015-07-27 10:30:50 -0400 |
---|---|---|
committer | Wolfram Sang <wsa@the-dreams.de> | 2015-08-10 02:37:36 -0400 |
commit | 48e9743dd6483c5fd3f10c8e42c60d52d64b0e27 (patch) | |
tree | d657778ce50ddf4a3f088842c0d18d1b29fdd5b3 /drivers/i2c/i2c-core.c | |
parent | 611e12ea0f121a31d9e9c4ce2a18a77abc2f28d6 (diff) |
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>
Diffstat (limited to 'drivers/i2c/i2c-core.c')
-rw-r--r-- | drivers/i2c/i2c-core.c | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index f80992d0a608..07a83f34ed58 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
@@ -1371,6 +1371,24 @@ struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node) | |||
1371 | return adapter; | 1371 | return adapter; |
1372 | } | 1372 | } |
1373 | EXPORT_SYMBOL(of_find_i2c_adapter_by_node); | 1373 | EXPORT_SYMBOL(of_find_i2c_adapter_by_node); |
1374 | |||
1375 | /* must call i2c_put_adapter() when done with returned i2c_adapter device */ | ||
1376 | struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node *node) | ||
1377 | { | ||
1378 | struct i2c_adapter *adapter; | ||
1379 | |||
1380 | adapter = of_find_i2c_adapter_by_node(node); | ||
1381 | if (!adapter) | ||
1382 | return NULL; | ||
1383 | |||
1384 | if (!try_module_get(adapter->owner)) { | ||
1385 | put_device(&adapter->dev); | ||
1386 | adapter = NULL; | ||
1387 | } | ||
1388 | |||
1389 | return adapter; | ||
1390 | } | ||
1391 | EXPORT_SYMBOL(of_get_i2c_adapter_by_node); | ||
1374 | #else | 1392 | #else |
1375 | static void of_i2c_register_devices(struct i2c_adapter *adap) { } | 1393 | static void of_i2c_register_devices(struct i2c_adapter *adap) { } |
1376 | #endif /* CONFIG_OF */ | 1394 | #endif /* CONFIG_OF */ |