diff options
author | Pantelis Antoniou <pantelis.antoniou@konsulko.com> | 2014-10-28 16:36:03 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@linaro.org> | 2014-11-25 10:35:35 -0500 |
commit | ea7513bbc04170f1cbf42953187a4d8b731c71c4 (patch) | |
tree | eae2d5fe9a96b50e45c447249b82f55983df8094 | |
parent | a430a3455f2c48995e06b359a82a1109a419e9ef (diff) |
i2c/of: Add OF_RECONFIG notifier handler
CONFIG_OF_DYNAMIC enables runtime changes to the device tree which in
turn may trigger addition or removal of devices from Linux. Add an
OF_RECONFIG notifier handler to receive tree change events and to
creating or destroy i2c devices as required.
Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
[grant.likely: clean up #ifdefs and drop unneeded error handling]
Signed-off-by: Grant Likely <grant.likely@linaro.org>
Reviewed-by: Wolfram Sang <wsa@the-dreams.de>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: linux-i2c@vger.kernel.org
-rw-r--r-- | drivers/i2c/i2c-core.c | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 15ba6185dba5..d8afd3f28ca4 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
@@ -1951,6 +1951,52 @@ void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg) | |||
1951 | } | 1951 | } |
1952 | EXPORT_SYMBOL(i2c_clients_command); | 1952 | EXPORT_SYMBOL(i2c_clients_command); |
1953 | 1953 | ||
1954 | #if IS_ENABLED(CONFIG_OF_DYNAMIC) | ||
1955 | static int of_i2c_notify(struct notifier_block *nb, unsigned long action, | ||
1956 | void *arg) | ||
1957 | { | ||
1958 | struct of_reconfig_data *rd = arg; | ||
1959 | struct i2c_adapter *adap; | ||
1960 | struct i2c_client *client; | ||
1961 | |||
1962 | switch (of_reconfig_get_state_change(action, rd)) { | ||
1963 | case OF_RECONFIG_CHANGE_ADD: | ||
1964 | adap = of_find_i2c_adapter_by_node(rd->dn->parent); | ||
1965 | if (adap == NULL) | ||
1966 | return NOTIFY_OK; /* not for us */ | ||
1967 | |||
1968 | client = of_i2c_register_device(adap, rd->dn); | ||
1969 | put_device(&adap->dev); | ||
1970 | |||
1971 | if (IS_ERR(client)) { | ||
1972 | pr_err("%s: failed to create for '%s'\n", | ||
1973 | __func__, rd->dn->full_name); | ||
1974 | return notifier_from_errno(PTR_ERR(client)); | ||
1975 | } | ||
1976 | break; | ||
1977 | case OF_RECONFIG_CHANGE_REMOVE: | ||
1978 | /* find our device by node */ | ||
1979 | client = of_find_i2c_device_by_node(rd->dn); | ||
1980 | if (client == NULL) | ||
1981 | return NOTIFY_OK; /* no? not meant for us */ | ||
1982 | |||
1983 | /* unregister takes one ref away */ | ||
1984 | i2c_unregister_device(client); | ||
1985 | |||
1986 | /* and put the reference of the find */ | ||
1987 | put_device(&client->dev); | ||
1988 | break; | ||
1989 | } | ||
1990 | |||
1991 | return NOTIFY_OK; | ||
1992 | } | ||
1993 | static struct notifier_block i2c_of_notifier = { | ||
1994 | .notifier_call = of_i2c_notify, | ||
1995 | }; | ||
1996 | #else | ||
1997 | extern struct notifier_block i2c_of_notifier; | ||
1998 | #endif /* CONFIG_OF_DYNAMIC */ | ||
1999 | |||
1954 | static int __init i2c_init(void) | 2000 | static int __init i2c_init(void) |
1955 | { | 2001 | { |
1956 | int retval; | 2002 | int retval; |
@@ -1968,6 +2014,10 @@ static int __init i2c_init(void) | |||
1968 | retval = i2c_add_driver(&dummy_driver); | 2014 | retval = i2c_add_driver(&dummy_driver); |
1969 | if (retval) | 2015 | if (retval) |
1970 | goto class_err; | 2016 | goto class_err; |
2017 | |||
2018 | if (IS_ENABLED(CONFIG_OF_DYNAMIC)) | ||
2019 | WARN_ON(of_reconfig_notifier_register(&i2c_of_notifier)); | ||
2020 | |||
1971 | return 0; | 2021 | return 0; |
1972 | 2022 | ||
1973 | class_err: | 2023 | class_err: |
@@ -1981,6 +2031,8 @@ bus_err: | |||
1981 | 2031 | ||
1982 | static void __exit i2c_exit(void) | 2032 | static void __exit i2c_exit(void) |
1983 | { | 2033 | { |
2034 | if (IS_ENABLED(CONFIG_OF_DYNAMIC)) | ||
2035 | WARN_ON(of_reconfig_notifier_unregister(&i2c_of_notifier)); | ||
1984 | i2c_del_driver(&dummy_driver); | 2036 | i2c_del_driver(&dummy_driver); |
1985 | #ifdef CONFIG_I2C_COMPAT | 2037 | #ifdef CONFIG_I2C_COMPAT |
1986 | class_compat_unregister(i2c_adapter_compat_class); | 2038 | class_compat_unregister(i2c_adapter_compat_class); |