Skip to content

Commit

Permalink
i2c/of: Add OF_RECONFIG notifier handler
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Pantelis Antoniou authored and Grant Likely committed Nov 25, 2014
1 parent a430a34 commit ea7513b
Showing 1 changed file with 52 additions and 0 deletions.
52 changes: 52 additions & 0 deletions drivers/i2c/i2c-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1951,6 +1951,52 @@ void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg)
}
EXPORT_SYMBOL(i2c_clients_command);

#if IS_ENABLED(CONFIG_OF_DYNAMIC)
static int of_i2c_notify(struct notifier_block *nb, unsigned long action,
void *arg)
{
struct of_reconfig_data *rd = arg;
struct i2c_adapter *adap;
struct i2c_client *client;

switch (of_reconfig_get_state_change(action, rd)) {
case OF_RECONFIG_CHANGE_ADD:
adap = of_find_i2c_adapter_by_node(rd->dn->parent);
if (adap == NULL)
return NOTIFY_OK; /* not for us */

client = of_i2c_register_device(adap, rd->dn);
put_device(&adap->dev);

if (IS_ERR(client)) {
pr_err("%s: failed to create for '%s'\n",
__func__, rd->dn->full_name);
return notifier_from_errno(PTR_ERR(client));
}
break;
case OF_RECONFIG_CHANGE_REMOVE:
/* find our device by node */
client = of_find_i2c_device_by_node(rd->dn);
if (client == NULL)
return NOTIFY_OK; /* no? not meant for us */

/* unregister takes one ref away */
i2c_unregister_device(client);

/* and put the reference of the find */
put_device(&client->dev);
break;
}

return NOTIFY_OK;
}
static struct notifier_block i2c_of_notifier = {
.notifier_call = of_i2c_notify,
};
#else
extern struct notifier_block i2c_of_notifier;
#endif /* CONFIG_OF_DYNAMIC */

static int __init i2c_init(void)
{
int retval;
Expand All @@ -1968,6 +2014,10 @@ static int __init i2c_init(void)
retval = i2c_add_driver(&dummy_driver);
if (retval)
goto class_err;

if (IS_ENABLED(CONFIG_OF_DYNAMIC))
WARN_ON(of_reconfig_notifier_register(&i2c_of_notifier));

return 0;

class_err:
Expand All @@ -1981,6 +2031,8 @@ static int __init i2c_init(void)

static void __exit i2c_exit(void)
{
if (IS_ENABLED(CONFIG_OF_DYNAMIC))
WARN_ON(of_reconfig_notifier_unregister(&i2c_of_notifier));
i2c_del_driver(&dummy_driver);
#ifdef CONFIG_I2C_COMPAT
class_compat_unregister(i2c_adapter_compat_class);
Expand Down

0 comments on commit ea7513b

Please sign in to comment.