xref: /openbmc/linux/drivers/mtd/chips/chipreg.c (revision 6aa12138)
109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Registration for chip drivers
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  */
61da177e4SLinus Torvalds 
71da177e4SLinus Torvalds #include <linux/kernel.h>
81da177e4SLinus Torvalds #include <linux/module.h>
91da177e4SLinus Torvalds #include <linux/kmod.h>
101da177e4SLinus Torvalds #include <linux/spinlock.h>
111da177e4SLinus Torvalds #include <linux/slab.h>
121da177e4SLinus Torvalds #include <linux/mtd/map.h>
131da177e4SLinus Torvalds #include <linux/mtd/mtd.h>
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds static DEFINE_SPINLOCK(chip_drvs_lock);
161da177e4SLinus Torvalds static LIST_HEAD(chip_drvs_list);
171da177e4SLinus Torvalds 
register_mtd_chip_driver(struct mtd_chip_driver * drv)181da177e4SLinus Torvalds void register_mtd_chip_driver(struct mtd_chip_driver *drv)
191da177e4SLinus Torvalds {
201da177e4SLinus Torvalds 	spin_lock(&chip_drvs_lock);
211da177e4SLinus Torvalds 	list_add(&drv->list, &chip_drvs_list);
221da177e4SLinus Torvalds 	spin_unlock(&chip_drvs_lock);
231da177e4SLinus Torvalds }
241da177e4SLinus Torvalds 
unregister_mtd_chip_driver(struct mtd_chip_driver * drv)251da177e4SLinus Torvalds void unregister_mtd_chip_driver(struct mtd_chip_driver *drv)
261da177e4SLinus Torvalds {
271da177e4SLinus Torvalds 	spin_lock(&chip_drvs_lock);
281da177e4SLinus Torvalds 	list_del(&drv->list);
291da177e4SLinus Torvalds 	spin_unlock(&chip_drvs_lock);
301da177e4SLinus Torvalds }
311da177e4SLinus Torvalds 
get_mtd_chip_driver(const char * name)321da177e4SLinus Torvalds static struct mtd_chip_driver *get_mtd_chip_driver (const char *name)
331da177e4SLinus Torvalds {
341da177e4SLinus Torvalds 	struct mtd_chip_driver *ret = NULL, *this;
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds 	spin_lock(&chip_drvs_lock);
371da177e4SLinus Torvalds 
38*6aa12138SZou Wei 	list_for_each_entry(this, &chip_drvs_list, list) {
391da177e4SLinus Torvalds 		if (!strcmp(this->name, name)) {
401da177e4SLinus Torvalds 			ret = this;
411da177e4SLinus Torvalds 			break;
421da177e4SLinus Torvalds 		}
431da177e4SLinus Torvalds 	}
441da177e4SLinus Torvalds 	if (ret && !try_module_get(ret->module))
451da177e4SLinus Torvalds 		ret = NULL;
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds 	spin_unlock(&chip_drvs_lock);
481da177e4SLinus Torvalds 
491da177e4SLinus Torvalds 	return ret;
501da177e4SLinus Torvalds }
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds 	/* Hide all the horrid details, like some silly person taking
531da177e4SLinus Torvalds 	   get_module_symbol() away from us, from the caller. */
541da177e4SLinus Torvalds 
do_map_probe(const char * name,struct map_info * map)551da177e4SLinus Torvalds struct mtd_info *do_map_probe(const char *name, struct map_info *map)
561da177e4SLinus Torvalds {
571da177e4SLinus Torvalds 	struct mtd_chip_driver *drv;
581da177e4SLinus Torvalds 	struct mtd_info *ret;
591da177e4SLinus Torvalds 
601da177e4SLinus Torvalds 	drv = get_mtd_chip_driver(name);
611da177e4SLinus Torvalds 
621da177e4SLinus Torvalds 	if (!drv && !request_module("%s", name))
631da177e4SLinus Torvalds 		drv = get_mtd_chip_driver(name);
641da177e4SLinus Torvalds 
651da177e4SLinus Torvalds 	if (!drv)
661da177e4SLinus Torvalds 		return NULL;
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds 	ret = drv->probe(map);
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds 	/* We decrease the use count here. It may have been a
711da177e4SLinus Torvalds 	   probe-only module, which is no longer required from this
721da177e4SLinus Torvalds 	   point, having given us a handle on (and increased the use
731da177e4SLinus Torvalds 	   count of) the actual driver code.
741da177e4SLinus Torvalds 	*/
751da177e4SLinus Torvalds 	module_put(drv->module);
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds 	return ret;
781da177e4SLinus Torvalds }
791da177e4SLinus Torvalds /*
801da177e4SLinus Torvalds  * Destroy an MTD device which was created for a map device.
811da177e4SLinus Torvalds  * Make sure the MTD device is already unregistered before calling this
821da177e4SLinus Torvalds  */
map_destroy(struct mtd_info * mtd)831da177e4SLinus Torvalds void map_destroy(struct mtd_info *mtd)
841da177e4SLinus Torvalds {
851da177e4SLinus Torvalds 	struct map_info *map = mtd->priv;
861da177e4SLinus Torvalds 
871da177e4SLinus Torvalds 	if (map->fldrv->destroy)
881da177e4SLinus Torvalds 		map->fldrv->destroy(mtd);
891da177e4SLinus Torvalds 
901da177e4SLinus Torvalds 	module_put(map->fldrv->module);
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds 	kfree(mtd);
931da177e4SLinus Torvalds }
941da177e4SLinus Torvalds 
951da177e4SLinus Torvalds EXPORT_SYMBOL(register_mtd_chip_driver);
961da177e4SLinus Torvalds EXPORT_SYMBOL(unregister_mtd_chip_driver);
971da177e4SLinus Torvalds EXPORT_SYMBOL(do_map_probe);
981da177e4SLinus Torvalds EXPORT_SYMBOL(map_destroy);
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds MODULE_LICENSE("GPL");
1011da177e4SLinus Torvalds MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
1021da177e4SLinus Torvalds MODULE_DESCRIPTION("Core routines for registering and invoking MTD chip drivers");
103