diff options
author | Pantelis Antoniou <pantelis.antoniou@konsulko.com> | 2014-10-28 16:36:05 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@linaro.org> | 2014-11-25 10:36:24 -0500 |
commit | ce79d54ae447d65117303ca9f61ffe9dcbc2465d (patch) | |
tree | f06c2c60487f7d7d1d55c36750509b0f7b8dedf8 /drivers/spi | |
parent | aff5e3f89a0b07e7edf9243f913378cc27e4110d (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.c | 84 |
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) | ||
2321 | static 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 */ | ||
2327 | static 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 | |||
2334 | static 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 */ | ||
2340 | static 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 | |||
2353 | static 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 | |||
2393 | static struct notifier_block spi_of_notifier = { | ||
2394 | .notifier_call = of_spi_notify, | ||
2395 | }; | ||
2396 | #else /* IS_ENABLED(CONFIG_OF_DYNAMIC) */ | ||
2397 | extern struct notifier_block spi_of_notifier; | ||
2398 | #endif /* IS_ENABLED(CONFIG_OF_DYNAMIC) */ | ||
2399 | |||
2320 | static int __init spi_init(void) | 2400 | static 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 | ||
2339 | err2: | 2423 | err2: |