diff options
Diffstat (limited to 'drivers/fsi/fsi-master-hub.c')
-rw-r--r-- | drivers/fsi/fsi-master-hub.c | 27 |
1 files changed, 23 insertions, 4 deletions
diff --git a/drivers/fsi/fsi-master-hub.c b/drivers/fsi/fsi-master-hub.c index 133b9bff1d65..5885fc4a1ef0 100644 --- a/drivers/fsi/fsi-master-hub.c +++ b/drivers/fsi/fsi-master-hub.c @@ -16,6 +16,7 @@ #include <linux/delay.h> #include <linux/fsi.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/slab.h> #include "fsi-master.h" @@ -253,7 +254,7 @@ static int hub_master_probe(struct device *dev) reg = be32_to_cpu(__reg); links = (reg >> 8) & 0xff; - dev_info(dev, "hub version %08x (%d links)\n", reg, links); + dev_dbg(dev, "hub version %08x (%d links)\n", reg, links); rc = fsi_slave_claim_range(fsi_dev->slave, FSI_HUB_LINK_OFFSET, FSI_HUB_LINK_SIZE * links); @@ -274,6 +275,7 @@ static int hub_master_probe(struct device *dev) hub->master.dev.parent = dev; hub->master.dev.release = hub_master_release; + hub->master.dev.of_node = of_node_get(dev_of_node(dev)); hub->master.n_links = links; hub->master.read = hub_master_read; @@ -286,10 +288,19 @@ static int hub_master_probe(struct device *dev) hub_master_init(hub); rc = fsi_master_register(&hub->master); - if (!rc) - return 0; + if (rc) + goto err_release; + + /* At this point, fsi_master_register performs the device_initialize(), + * and holds the sole reference on master.dev. This means the device + * will be freed (via ->release) during any subsequent call to + * fsi_master_unregister. We add our own reference to it here, so we + * can perform cleanup (in _remove()) without it being freed before + * we're ready. + */ + get_device(&hub->master.dev); + return 0; - kfree(hub); err_release: fsi_slave_release_range(fsi_dev->slave, FSI_HUB_LINK_OFFSET, FSI_HUB_LINK_SIZE * links); @@ -302,6 +313,14 @@ static int hub_master_remove(struct device *dev) fsi_master_unregister(&hub->master); fsi_slave_release_range(hub->upstream->slave, hub->addr, hub->size); + of_node_put(hub->master.dev.of_node); + + /* + * master.dev will likely be ->release()ed after this, which free()s + * the hub + */ + put_device(&hub->master.dev); + return 0; } |