aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
authorPantelis Antoniou <pantelis.antoniou@konsulko.com>2014-10-28 16:36:05 -0400
committerGrant Likely <grant.likely@linaro.org>2014-11-25 10:36:24 -0500
commitce79d54ae447d65117303ca9f61ffe9dcbc2465d (patch)
treef06c2c60487f7d7d1d55c36750509b0f7b8dedf8 /drivers/spi
parentaff5e3f89a0b07e7edf9243f913378cc27e4110d (diff)
spi/of: Add OF notifier handler
Add OF notifier handler needed for creating/destroying spi devices according to dynamic runtime changes in the DT live tree. This code is enabled when CONFIG_OF_DYNAMIC is selected. Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com> Signed-off-by: Grant Likely <grant.likely@linaro.org> Reviewed-by: Mark Brown <broonie@kernel.org> Cc: <linux-spi@vger.kernel.org>
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/spi.c84
1 files changed, 84 insertions, 0 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index a3557c57d4f7..bf1cab0fad66 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -2317,6 +2317,86 @@ EXPORT_SYMBOL_GPL(spi_write_then_read);
2317 2317
2318/*-------------------------------------------------------------------------*/ 2318/*-------------------------------------------------------------------------*/
2319 2319
2320#if IS_ENABLED(CONFIG_OF_DYNAMIC)
2321static int __spi_of_device_match(struct device *dev, void *data)
2322{
2323 return dev->of_node == data;
2324}
2325
2326/* must call put_device() when done with returned spi_device device */
2327static struct spi_device *of_find_spi_device_by_node(struct device_node *node)
2328{
2329 struct device *dev = bus_find_device(&spi_bus_type, NULL, node,
2330 __spi_of_device_match);
2331 return dev ? to_spi_device(dev) : NULL;
2332}
2333
2334static int __spi_of_master_match(struct device *dev, const void *data)
2335{
2336 return dev->of_node == data;
2337}
2338
2339/* the spi masters are not using spi_bus, so we find it with another way */
2340static struct spi_master *of_find_spi_master_by_node(struct device_node *node)
2341{
2342 struct device *dev;
2343
2344 dev = class_find_device(&spi_master_class, NULL, node,
2345 __spi_of_master_match);
2346 if (!dev)
2347 return NULL;
2348
2349 /* reference got in class_find_device */
2350 return container_of(dev, struct spi_master, dev);
2351}
2352
2353static int of_spi_notify(struct notifier_block *nb, unsigned long action,
2354 void *arg)
2355{
2356 struct of_reconfig_data *rd = arg;
2357 struct spi_master *master;
2358 struct spi_device *spi;
2359
2360 switch (of_reconfig_get_state_change(action, arg)) {
2361 case OF_RECONFIG_CHANGE_ADD:
2362 master = of_find_spi_master_by_node(rd->dn->parent);
2363 if (master == NULL)
2364 return NOTIFY_OK; /* not for us */
2365
2366 spi = of_register_spi_device(master, rd->dn);
2367 put_device(&master->dev);
2368
2369 if (IS_ERR(spi)) {
2370 pr_err("%s: failed to create for '%s'\n",
2371 __func__, rd->dn->full_name);
2372 return notifier_from_errno(PTR_ERR(spi));
2373 }
2374 break;
2375
2376 case OF_RECONFIG_CHANGE_REMOVE:
2377 /* find our device by node */
2378 spi = of_find_spi_device_by_node(rd->dn);
2379 if (spi == NULL)
2380 return NOTIFY_OK; /* no? not meant for us */
2381
2382 /* unregister takes one ref away */
2383 spi_unregister_device(spi);
2384
2385 /* and put the reference of the find */
2386 put_device(&spi->dev);
2387 break;
2388 }
2389
2390 return NOTIFY_OK;
2391}
2392
2393static struct notifier_block spi_of_notifier = {
2394 .notifier_call = of_spi_notify,
2395};
2396#else /* IS_ENABLED(CONFIG_OF_DYNAMIC) */
2397extern struct notifier_block spi_of_notifier;
2398#endif /* IS_ENABLED(CONFIG_OF_DYNAMIC) */
2399
2320static int __init spi_init(void) 2400static int __init spi_init(void)
2321{ 2401{
2322 int status; 2402 int status;
@@ -2334,6 +2414,10 @@ static int __init spi_init(void)
2334 status = class_register(&spi_master_class); 2414 status = class_register(&spi_master_class);
2335 if (status < 0) 2415 if (status < 0)
2336 goto err2; 2416 goto err2;
2417
2418 if (IS_ENABLED(CONFIG_OF))
2419 WARN_ON(of_reconfig_notifier_register(&spi_of_notifier));
2420
2337 return 0; 2421 return 0;
2338 2422
2339err2: 2423err2: