xref: /openbmc/linux/drivers/fpga/fpga-bridge.c (revision 7bb2d219)
1473f01f7SAlan Tull // SPDX-License-Identifier: GPL-2.0
221aeda95SAlan Tull /*
321aeda95SAlan Tull  * FPGA Bridge Framework Driver
421aeda95SAlan Tull  *
521aeda95SAlan Tull  *  Copyright (C) 2013-2016 Altera Corporation, All Rights Reserved.
69c1c4b27SAlan Tull  *  Copyright (C) 2017 Intel Corporation
721aeda95SAlan Tull  */
821aeda95SAlan Tull #include <linux/fpga/fpga-bridge.h>
921aeda95SAlan Tull #include <linux/idr.h>
1021aeda95SAlan Tull #include <linux/kernel.h>
1121aeda95SAlan Tull #include <linux/module.h>
1221aeda95SAlan Tull #include <linux/of_platform.h>
1321aeda95SAlan Tull #include <linux/slab.h>
1421aeda95SAlan Tull #include <linux/spinlock.h>
1521aeda95SAlan Tull 
1621aeda95SAlan Tull static DEFINE_IDA(fpga_bridge_ida);
17*7bb2d219SIvan Orlov static const struct class fpga_bridge_class;
1821aeda95SAlan Tull 
1921aeda95SAlan Tull /* Lock for adding/removing bridges to linked lists*/
20f5187329SZheng Yongjun static DEFINE_SPINLOCK(bridge_list_lock);
2121aeda95SAlan Tull 
2221aeda95SAlan Tull /**
2321aeda95SAlan Tull  * fpga_bridge_enable - Enable transactions on the bridge
2421aeda95SAlan Tull  *
2521aeda95SAlan Tull  * @bridge: FPGA bridge
2621aeda95SAlan Tull  *
2721aeda95SAlan Tull  * Return: 0 for success, error code otherwise.
2821aeda95SAlan Tull  */
fpga_bridge_enable(struct fpga_bridge * bridge)2921aeda95SAlan Tull int fpga_bridge_enable(struct fpga_bridge *bridge)
3021aeda95SAlan Tull {
3121aeda95SAlan Tull 	dev_dbg(&bridge->dev, "enable\n");
3221aeda95SAlan Tull 
3321aeda95SAlan Tull 	if (bridge->br_ops && bridge->br_ops->enable_set)
3421aeda95SAlan Tull 		return bridge->br_ops->enable_set(bridge, 1);
3521aeda95SAlan Tull 
3621aeda95SAlan Tull 	return 0;
3721aeda95SAlan Tull }
3821aeda95SAlan Tull EXPORT_SYMBOL_GPL(fpga_bridge_enable);
3921aeda95SAlan Tull 
4021aeda95SAlan Tull /**
4121aeda95SAlan Tull  * fpga_bridge_disable - Disable transactions on the bridge
4221aeda95SAlan Tull  *
4321aeda95SAlan Tull  * @bridge: FPGA bridge
4421aeda95SAlan Tull  *
4521aeda95SAlan Tull  * Return: 0 for success, error code otherwise.
4621aeda95SAlan Tull  */
fpga_bridge_disable(struct fpga_bridge * bridge)4721aeda95SAlan Tull int fpga_bridge_disable(struct fpga_bridge *bridge)
4821aeda95SAlan Tull {
4921aeda95SAlan Tull 	dev_dbg(&bridge->dev, "disable\n");
5021aeda95SAlan Tull 
5121aeda95SAlan Tull 	if (bridge->br_ops && bridge->br_ops->enable_set)
5221aeda95SAlan Tull 		return bridge->br_ops->enable_set(bridge, 0);
5321aeda95SAlan Tull 
5421aeda95SAlan Tull 	return 0;
5521aeda95SAlan Tull }
5621aeda95SAlan Tull EXPORT_SYMBOL_GPL(fpga_bridge_disable);
5721aeda95SAlan Tull 
__fpga_bridge_get(struct device * dev,struct fpga_image_info * info)589c1c4b27SAlan Tull static struct fpga_bridge *__fpga_bridge_get(struct device *dev,
5921aeda95SAlan Tull 					     struct fpga_image_info *info)
6021aeda95SAlan Tull {
6121aeda95SAlan Tull 	struct fpga_bridge *bridge;
6221aeda95SAlan Tull 	int ret = -ENODEV;
6321aeda95SAlan Tull 
6421aeda95SAlan Tull 	bridge = to_fpga_bridge(dev);
6521aeda95SAlan Tull 
6621aeda95SAlan Tull 	bridge->info = info;
6721aeda95SAlan Tull 
6821aeda95SAlan Tull 	if (!mutex_trylock(&bridge->mutex)) {
6921aeda95SAlan Tull 		ret = -EBUSY;
7021aeda95SAlan Tull 		goto err_dev;
7121aeda95SAlan Tull 	}
7221aeda95SAlan Tull 
7321aeda95SAlan Tull 	if (!try_module_get(dev->parent->driver->owner))
7421aeda95SAlan Tull 		goto err_ll_mod;
7521aeda95SAlan Tull 
7621aeda95SAlan Tull 	dev_dbg(&bridge->dev, "get\n");
7721aeda95SAlan Tull 
7821aeda95SAlan Tull 	return bridge;
7921aeda95SAlan Tull 
8021aeda95SAlan Tull err_ll_mod:
8121aeda95SAlan Tull 	mutex_unlock(&bridge->mutex);
8221aeda95SAlan Tull err_dev:
8321aeda95SAlan Tull 	put_device(dev);
8421aeda95SAlan Tull 	return ERR_PTR(ret);
8521aeda95SAlan Tull }
869c1c4b27SAlan Tull 
879c1c4b27SAlan Tull /**
88e7555cf6STom Rix  * of_fpga_bridge_get - get an exclusive reference to an fpga bridge
899c1c4b27SAlan Tull  *
908e665c9cSMarco Pagani  * @np: node pointer of an FPGA bridge.
918e665c9cSMarco Pagani  * @info: fpga image specific information.
929c1c4b27SAlan Tull  *
938e665c9cSMarco Pagani  * Return:
948e665c9cSMarco Pagani  * * fpga_bridge struct pointer if successful.
958e665c9cSMarco Pagani  * * -EBUSY if someone already has a reference to the bridge.
968e665c9cSMarco Pagani  * * -ENODEV if @np is not an FPGA Bridge or can't take parent driver refcount.
979c1c4b27SAlan Tull  */
of_fpga_bridge_get(struct device_node * np,struct fpga_image_info * info)989c1c4b27SAlan Tull struct fpga_bridge *of_fpga_bridge_get(struct device_node *np,
999c1c4b27SAlan Tull 				       struct fpga_image_info *info)
1009c1c4b27SAlan Tull {
1019c1c4b27SAlan Tull 	struct device *dev;
1029c1c4b27SAlan Tull 
103*7bb2d219SIvan Orlov 	dev = class_find_device_by_of_node(&fpga_bridge_class, np);
1049c1c4b27SAlan Tull 	if (!dev)
1059c1c4b27SAlan Tull 		return ERR_PTR(-ENODEV);
1069c1c4b27SAlan Tull 
1079c1c4b27SAlan Tull 	return __fpga_bridge_get(dev, info);
1089c1c4b27SAlan Tull }
10921aeda95SAlan Tull EXPORT_SYMBOL_GPL(of_fpga_bridge_get);
11021aeda95SAlan Tull 
fpga_bridge_dev_match(struct device * dev,const void * data)1119c1c4b27SAlan Tull static int fpga_bridge_dev_match(struct device *dev, const void *data)
1129c1c4b27SAlan Tull {
1139c1c4b27SAlan Tull 	return dev->parent == data;
1149c1c4b27SAlan Tull }
1159c1c4b27SAlan Tull 
1169c1c4b27SAlan Tull /**
117e7555cf6STom Rix  * fpga_bridge_get - get an exclusive reference to an fpga bridge
1189c1c4b27SAlan Tull  * @dev:	parent device that fpga bridge was registered with
1197ef1a2c1SMarco Pagani  * @info:	fpga image specific information
1209c1c4b27SAlan Tull  *
121e7555cf6STom Rix  * Given a device, get an exclusive reference to an fpga bridge.
1229c1c4b27SAlan Tull  *
123b4d9a0e5SAlan Tull  * Return: fpga bridge struct or IS_ERR() condition containing error code.
1249c1c4b27SAlan Tull  */
fpga_bridge_get(struct device * dev,struct fpga_image_info * info)1259c1c4b27SAlan Tull struct fpga_bridge *fpga_bridge_get(struct device *dev,
1269c1c4b27SAlan Tull 				    struct fpga_image_info *info)
1279c1c4b27SAlan Tull {
1289c1c4b27SAlan Tull 	struct device *bridge_dev;
1299c1c4b27SAlan Tull 
130*7bb2d219SIvan Orlov 	bridge_dev = class_find_device(&fpga_bridge_class, NULL, dev,
1319c1c4b27SAlan Tull 				       fpga_bridge_dev_match);
1329c1c4b27SAlan Tull 	if (!bridge_dev)
1339c1c4b27SAlan Tull 		return ERR_PTR(-ENODEV);
1349c1c4b27SAlan Tull 
1359c1c4b27SAlan Tull 	return __fpga_bridge_get(bridge_dev, info);
1369c1c4b27SAlan Tull }
1379c1c4b27SAlan Tull EXPORT_SYMBOL_GPL(fpga_bridge_get);
1389c1c4b27SAlan Tull 
13921aeda95SAlan Tull /**
14021aeda95SAlan Tull  * fpga_bridge_put - release a reference to a bridge
14121aeda95SAlan Tull  *
14221aeda95SAlan Tull  * @bridge: FPGA bridge
14321aeda95SAlan Tull  */
fpga_bridge_put(struct fpga_bridge * bridge)14421aeda95SAlan Tull void fpga_bridge_put(struct fpga_bridge *bridge)
14521aeda95SAlan Tull {
14621aeda95SAlan Tull 	dev_dbg(&bridge->dev, "put\n");
14721aeda95SAlan Tull 
14821aeda95SAlan Tull 	bridge->info = NULL;
14921aeda95SAlan Tull 	module_put(bridge->dev.parent->driver->owner);
15021aeda95SAlan Tull 	mutex_unlock(&bridge->mutex);
15121aeda95SAlan Tull 	put_device(&bridge->dev);
15221aeda95SAlan Tull }
15321aeda95SAlan Tull EXPORT_SYMBOL_GPL(fpga_bridge_put);
15421aeda95SAlan Tull 
15521aeda95SAlan Tull /**
15621aeda95SAlan Tull  * fpga_bridges_enable - enable bridges in a list
15721aeda95SAlan Tull  * @bridge_list: list of FPGA bridges
15821aeda95SAlan Tull  *
15921aeda95SAlan Tull  * Enable each bridge in the list. If list is empty, do nothing.
16021aeda95SAlan Tull  *
1618e665c9cSMarco Pagani  * Return: 0 for success or empty bridge list or an error code otherwise.
16221aeda95SAlan Tull  */
fpga_bridges_enable(struct list_head * bridge_list)16321aeda95SAlan Tull int fpga_bridges_enable(struct list_head *bridge_list)
16421aeda95SAlan Tull {
16521aeda95SAlan Tull 	struct fpga_bridge *bridge;
16621aeda95SAlan Tull 	int ret;
16721aeda95SAlan Tull 
168c37235ccSMoritz Fischer 	list_for_each_entry(bridge, bridge_list, node) {
16921aeda95SAlan Tull 		ret = fpga_bridge_enable(bridge);
17021aeda95SAlan Tull 		if (ret)
17121aeda95SAlan Tull 			return ret;
17221aeda95SAlan Tull 	}
17321aeda95SAlan Tull 
17421aeda95SAlan Tull 	return 0;
17521aeda95SAlan Tull }
17621aeda95SAlan Tull EXPORT_SYMBOL_GPL(fpga_bridges_enable);
17721aeda95SAlan Tull 
17821aeda95SAlan Tull /**
17921aeda95SAlan Tull  * fpga_bridges_disable - disable bridges in a list
18021aeda95SAlan Tull  *
18121aeda95SAlan Tull  * @bridge_list: list of FPGA bridges
18221aeda95SAlan Tull  *
18321aeda95SAlan Tull  * Disable each bridge in the list. If list is empty, do nothing.
18421aeda95SAlan Tull  *
1858e665c9cSMarco Pagani  * Return: 0 for success or empty bridge list or an error code otherwise.
18621aeda95SAlan Tull  */
fpga_bridges_disable(struct list_head * bridge_list)18721aeda95SAlan Tull int fpga_bridges_disable(struct list_head *bridge_list)
18821aeda95SAlan Tull {
18921aeda95SAlan Tull 	struct fpga_bridge *bridge;
19021aeda95SAlan Tull 	int ret;
19121aeda95SAlan Tull 
192c37235ccSMoritz Fischer 	list_for_each_entry(bridge, bridge_list, node) {
19321aeda95SAlan Tull 		ret = fpga_bridge_disable(bridge);
19421aeda95SAlan Tull 		if (ret)
19521aeda95SAlan Tull 			return ret;
19621aeda95SAlan Tull 	}
19721aeda95SAlan Tull 
19821aeda95SAlan Tull 	return 0;
19921aeda95SAlan Tull }
20021aeda95SAlan Tull EXPORT_SYMBOL_GPL(fpga_bridges_disable);
20121aeda95SAlan Tull 
20221aeda95SAlan Tull /**
20321aeda95SAlan Tull  * fpga_bridges_put - put bridges
20421aeda95SAlan Tull  *
20521aeda95SAlan Tull  * @bridge_list: list of FPGA bridges
20621aeda95SAlan Tull  *
20721aeda95SAlan Tull  * For each bridge in the list, put the bridge and remove it from the list.
20821aeda95SAlan Tull  * If list is empty, do nothing.
20921aeda95SAlan Tull  */
fpga_bridges_put(struct list_head * bridge_list)21021aeda95SAlan Tull void fpga_bridges_put(struct list_head *bridge_list)
21121aeda95SAlan Tull {
212c37235ccSMoritz Fischer 	struct fpga_bridge *bridge, *next;
21321aeda95SAlan Tull 	unsigned long flags;
21421aeda95SAlan Tull 
215c37235ccSMoritz Fischer 	list_for_each_entry_safe(bridge, next, bridge_list, node) {
21621aeda95SAlan Tull 		fpga_bridge_put(bridge);
21721aeda95SAlan Tull 
21821aeda95SAlan Tull 		spin_lock_irqsave(&bridge_list_lock, flags);
21921aeda95SAlan Tull 		list_del(&bridge->node);
22021aeda95SAlan Tull 		spin_unlock_irqrestore(&bridge_list_lock, flags);
22121aeda95SAlan Tull 	}
22221aeda95SAlan Tull }
22321aeda95SAlan Tull EXPORT_SYMBOL_GPL(fpga_bridges_put);
22421aeda95SAlan Tull 
22521aeda95SAlan Tull /**
2269c1c4b27SAlan Tull  * of_fpga_bridge_get_to_list - get a bridge, add it to a list
22721aeda95SAlan Tull  *
228e7555cf6STom Rix  * @np: node pointer of an FPGA bridge
22921aeda95SAlan Tull  * @info: fpga image specific information
23021aeda95SAlan Tull  * @bridge_list: list of FPGA bridges
23121aeda95SAlan Tull  *
2320a05cdf1SNavin Sankar Velliangiri  * Get an exclusive reference to the bridge and it to the list.
23321aeda95SAlan Tull  *
2348e665c9cSMarco Pagani  * Return: 0 for success, error code from of_fpga_bridge_get() otherwise.
23521aeda95SAlan Tull  */
of_fpga_bridge_get_to_list(struct device_node * np,struct fpga_image_info * info,struct list_head * bridge_list)2369c1c4b27SAlan Tull int of_fpga_bridge_get_to_list(struct device_node *np,
23721aeda95SAlan Tull 			       struct fpga_image_info *info,
23821aeda95SAlan Tull 			       struct list_head *bridge_list)
23921aeda95SAlan Tull {
24021aeda95SAlan Tull 	struct fpga_bridge *bridge;
24121aeda95SAlan Tull 	unsigned long flags;
24221aeda95SAlan Tull 
24321aeda95SAlan Tull 	bridge = of_fpga_bridge_get(np, info);
24421aeda95SAlan Tull 	if (IS_ERR(bridge))
24521aeda95SAlan Tull 		return PTR_ERR(bridge);
24621aeda95SAlan Tull 
24721aeda95SAlan Tull 	spin_lock_irqsave(&bridge_list_lock, flags);
24821aeda95SAlan Tull 	list_add(&bridge->node, bridge_list);
24921aeda95SAlan Tull 	spin_unlock_irqrestore(&bridge_list_lock, flags);
25021aeda95SAlan Tull 
25121aeda95SAlan Tull 	return 0;
25221aeda95SAlan Tull }
2539c1c4b27SAlan Tull EXPORT_SYMBOL_GPL(of_fpga_bridge_get_to_list);
2549c1c4b27SAlan Tull 
2559c1c4b27SAlan Tull /**
2569c1c4b27SAlan Tull  * fpga_bridge_get_to_list - given device, get a bridge, add it to a list
2579c1c4b27SAlan Tull  *
2589c1c4b27SAlan Tull  * @dev: FPGA bridge device
2599c1c4b27SAlan Tull  * @info: fpga image specific information
2609c1c4b27SAlan Tull  * @bridge_list: list of FPGA bridges
2619c1c4b27SAlan Tull  *
2620a05cdf1SNavin Sankar Velliangiri  * Get an exclusive reference to the bridge and it to the list.
2639c1c4b27SAlan Tull  *
2648e665c9cSMarco Pagani  * Return: 0 for success, error code from fpga_bridge_get() otherwise.
2659c1c4b27SAlan Tull  */
fpga_bridge_get_to_list(struct device * dev,struct fpga_image_info * info,struct list_head * bridge_list)2669c1c4b27SAlan Tull int fpga_bridge_get_to_list(struct device *dev,
2679c1c4b27SAlan Tull 			    struct fpga_image_info *info,
2689c1c4b27SAlan Tull 			    struct list_head *bridge_list)
2699c1c4b27SAlan Tull {
2709c1c4b27SAlan Tull 	struct fpga_bridge *bridge;
2719c1c4b27SAlan Tull 	unsigned long flags;
2729c1c4b27SAlan Tull 
2739c1c4b27SAlan Tull 	bridge = fpga_bridge_get(dev, info);
2749c1c4b27SAlan Tull 	if (IS_ERR(bridge))
2759c1c4b27SAlan Tull 		return PTR_ERR(bridge);
2769c1c4b27SAlan Tull 
2779c1c4b27SAlan Tull 	spin_lock_irqsave(&bridge_list_lock, flags);
2789c1c4b27SAlan Tull 	list_add(&bridge->node, bridge_list);
2799c1c4b27SAlan Tull 	spin_unlock_irqrestore(&bridge_list_lock, flags);
2809c1c4b27SAlan Tull 
2819c1c4b27SAlan Tull 	return 0;
2829c1c4b27SAlan Tull }
28321aeda95SAlan Tull EXPORT_SYMBOL_GPL(fpga_bridge_get_to_list);
28421aeda95SAlan Tull 
name_show(struct device * dev,struct device_attribute * attr,char * buf)28521aeda95SAlan Tull static ssize_t name_show(struct device *dev,
28621aeda95SAlan Tull 			 struct device_attribute *attr, char *buf)
28721aeda95SAlan Tull {
28821aeda95SAlan Tull 	struct fpga_bridge *bridge = to_fpga_bridge(dev);
28921aeda95SAlan Tull 
29021aeda95SAlan Tull 	return sprintf(buf, "%s\n", bridge->name);
29121aeda95SAlan Tull }
29221aeda95SAlan Tull 
state_show(struct device * dev,struct device_attribute * attr,char * buf)29321aeda95SAlan Tull static ssize_t state_show(struct device *dev,
29421aeda95SAlan Tull 			  struct device_attribute *attr, char *buf)
29521aeda95SAlan Tull {
29621aeda95SAlan Tull 	struct fpga_bridge *bridge = to_fpga_bridge(dev);
29748ca6e5fSMarco Pagani 	int state = 1;
29821aeda95SAlan Tull 
29948ca6e5fSMarco Pagani 	if (bridge->br_ops && bridge->br_ops->enable_show) {
30048ca6e5fSMarco Pagani 		state = bridge->br_ops->enable_show(bridge);
30148ca6e5fSMarco Pagani 		if (state < 0)
30248ca6e5fSMarco Pagani 			return state;
30348ca6e5fSMarco Pagani 	}
30421aeda95SAlan Tull 
30548ca6e5fSMarco Pagani 	return sysfs_emit(buf, "%s\n", state ? "enabled" : "disabled");
30621aeda95SAlan Tull }
30721aeda95SAlan Tull 
30821aeda95SAlan Tull static DEVICE_ATTR_RO(name);
30921aeda95SAlan Tull static DEVICE_ATTR_RO(state);
31021aeda95SAlan Tull 
31121aeda95SAlan Tull static struct attribute *fpga_bridge_attrs[] = {
31221aeda95SAlan Tull 	&dev_attr_name.attr,
31321aeda95SAlan Tull 	&dev_attr_state.attr,
31421aeda95SAlan Tull 	NULL,
31521aeda95SAlan Tull };
31621aeda95SAlan Tull ATTRIBUTE_GROUPS(fpga_bridge);
31721aeda95SAlan Tull 
31821aeda95SAlan Tull /**
3190d70af3cSRuss Weight  * fpga_bridge_register - create and register an FPGA Bridge device
320ceb8ab3cSRuss Weight  * @parent:	FPGA bridge device from pdev
32121aeda95SAlan Tull  * @name:	FPGA bridge name
32221aeda95SAlan Tull  * @br_ops:	pointer to structure of fpga bridge ops
32321aeda95SAlan Tull  * @priv:	FPGA bridge private data
32421aeda95SAlan Tull  *
3250d70af3cSRuss Weight  * Return: struct fpga_bridge pointer or ERR_PTR()
32621aeda95SAlan Tull  */
3270d70af3cSRuss Weight struct fpga_bridge *
fpga_bridge_register(struct device * parent,const char * name,const struct fpga_bridge_ops * br_ops,void * priv)3280d70af3cSRuss Weight fpga_bridge_register(struct device *parent, const char *name,
329371cd1b1SAlan Tull 		     const struct fpga_bridge_ops *br_ops,
330371cd1b1SAlan Tull 		     void *priv)
33121aeda95SAlan Tull {
33221aeda95SAlan Tull 	struct fpga_bridge *bridge;
333d3fbd739STom Rix 	int id, ret;
33421aeda95SAlan Tull 
3350d70af3cSRuss Weight 	if (!br_ops) {
3360d70af3cSRuss Weight 		dev_err(parent, "Attempt to register without fpga_bridge_ops\n");
3370d70af3cSRuss Weight 		return ERR_PTR(-EINVAL);
3380d70af3cSRuss Weight 	}
3390d70af3cSRuss Weight 
34021aeda95SAlan Tull 	if (!name || !strlen(name)) {
341ceb8ab3cSRuss Weight 		dev_err(parent, "Attempt to register with no name!\n");
3420d70af3cSRuss Weight 		return ERR_PTR(-EINVAL);
34321aeda95SAlan Tull 	}
34421aeda95SAlan Tull 
34521aeda95SAlan Tull 	bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
34621aeda95SAlan Tull 	if (!bridge)
3470d70af3cSRuss Weight 		return ERR_PTR(-ENOMEM);
34821aeda95SAlan Tull 
349a5e3d775Skeliu 	id = ida_alloc(&fpga_bridge_ida, GFP_KERNEL);
3500d70af3cSRuss Weight 	if (id < 0) {
3510d70af3cSRuss Weight 		ret = id;
35221aeda95SAlan Tull 		goto error_kfree;
3530d70af3cSRuss Weight 	}
35421aeda95SAlan Tull 
35521aeda95SAlan Tull 	mutex_init(&bridge->mutex);
35621aeda95SAlan Tull 	INIT_LIST_HEAD(&bridge->node);
35721aeda95SAlan Tull 
35821aeda95SAlan Tull 	bridge->name = name;
35921aeda95SAlan Tull 	bridge->br_ops = br_ops;
36021aeda95SAlan Tull 	bridge->priv = priv;
36121aeda95SAlan Tull 
362845089bbSAlan Tull 	bridge->dev.groups = br_ops->groups;
363*7bb2d219SIvan Orlov 	bridge->dev.class = &fpga_bridge_class;
364ceb8ab3cSRuss Weight 	bridge->dev.parent = parent;
365ceb8ab3cSRuss Weight 	bridge->dev.of_node = parent->of_node;
36621aeda95SAlan Tull 	bridge->dev.id = id;
36721aeda95SAlan Tull 
36821aeda95SAlan Tull 	ret = dev_set_name(&bridge->dev, "br%d", id);
36921aeda95SAlan Tull 	if (ret)
37021aeda95SAlan Tull 		goto error_device;
37121aeda95SAlan Tull 
3720d70af3cSRuss Weight 	ret = device_register(&bridge->dev);
3730d70af3cSRuss Weight 	if (ret) {
3740d70af3cSRuss Weight 		put_device(&bridge->dev);
3750d70af3cSRuss Weight 		return ERR_PTR(ret);
3760d70af3cSRuss Weight 	}
3770d70af3cSRuss Weight 
378dc70eb86SAlexis Lothoré 	of_platform_populate(bridge->dev.of_node, NULL, NULL, &bridge->dev);
379dc70eb86SAlexis Lothoré 
380371cd1b1SAlan Tull 	return bridge;
38121aeda95SAlan Tull 
38221aeda95SAlan Tull error_device:
383a5e3d775Skeliu 	ida_free(&fpga_bridge_ida, id);
38421aeda95SAlan Tull error_kfree:
38521aeda95SAlan Tull 	kfree(bridge);
38621aeda95SAlan Tull 
3870d70af3cSRuss Weight 	return ERR_PTR(ret);
38821aeda95SAlan Tull }
38921aeda95SAlan Tull EXPORT_SYMBOL_GPL(fpga_bridge_register);
39021aeda95SAlan Tull 
39121aeda95SAlan Tull /**
392e7555cf6STom Rix  * fpga_bridge_unregister - unregister an FPGA bridge
393213befe0SAlan Tull  *
394213befe0SAlan Tull  * @bridge: FPGA bridge struct
395213befe0SAlan Tull  *
396e7555cf6STom Rix  * This function is intended for use in an FPGA bridge driver's remove function.
39721aeda95SAlan Tull  */
fpga_bridge_unregister(struct fpga_bridge * bridge)398371cd1b1SAlan Tull void fpga_bridge_unregister(struct fpga_bridge *bridge)
39921aeda95SAlan Tull {
40021aeda95SAlan Tull 	/*
40121aeda95SAlan Tull 	 * If the low level driver provides a method for putting bridge into
40221aeda95SAlan Tull 	 * a desired state upon unregister, do it.
40321aeda95SAlan Tull 	 */
40421aeda95SAlan Tull 	if (bridge->br_ops && bridge->br_ops->fpga_bridge_remove)
40521aeda95SAlan Tull 		bridge->br_ops->fpga_bridge_remove(bridge);
40621aeda95SAlan Tull 
40721aeda95SAlan Tull 	device_unregister(&bridge->dev);
40821aeda95SAlan Tull }
40921aeda95SAlan Tull EXPORT_SYMBOL_GPL(fpga_bridge_unregister);
41021aeda95SAlan Tull 
fpga_bridge_dev_release(struct device * dev)41121aeda95SAlan Tull static void fpga_bridge_dev_release(struct device *dev)
41221aeda95SAlan Tull {
4130d70af3cSRuss Weight 	struct fpga_bridge *bridge = to_fpga_bridge(dev);
4140d70af3cSRuss Weight 
415a5e3d775Skeliu 	ida_free(&fpga_bridge_ida, bridge->dev.id);
4160d70af3cSRuss Weight 	kfree(bridge);
41721aeda95SAlan Tull }
41821aeda95SAlan Tull 
419*7bb2d219SIvan Orlov static const struct class fpga_bridge_class = {
420*7bb2d219SIvan Orlov 	.name = "fpga_bridge",
421*7bb2d219SIvan Orlov 	.dev_groups = fpga_bridge_groups,
422*7bb2d219SIvan Orlov 	.dev_release = fpga_bridge_dev_release,
423*7bb2d219SIvan Orlov };
424*7bb2d219SIvan Orlov 
fpga_bridge_dev_init(void)42521aeda95SAlan Tull static int __init fpga_bridge_dev_init(void)
42621aeda95SAlan Tull {
427*7bb2d219SIvan Orlov 	return class_register(&fpga_bridge_class);
42821aeda95SAlan Tull }
42921aeda95SAlan Tull 
fpga_bridge_dev_exit(void)43021aeda95SAlan Tull static void __exit fpga_bridge_dev_exit(void)
43121aeda95SAlan Tull {
432*7bb2d219SIvan Orlov 	class_unregister(&fpga_bridge_class);
43321aeda95SAlan Tull 	ida_destroy(&fpga_bridge_ida);
43421aeda95SAlan Tull }
43521aeda95SAlan Tull 
43621aeda95SAlan Tull MODULE_DESCRIPTION("FPGA Bridge Driver");
4379c1c4b27SAlan Tull MODULE_AUTHOR("Alan Tull <atull@kernel.org>");
43821aeda95SAlan Tull MODULE_LICENSE("GPL v2");
43921aeda95SAlan Tull 
44021aeda95SAlan Tull subsys_initcall(fpga_bridge_dev_init);
44121aeda95SAlan Tull module_exit(fpga_bridge_dev_exit);
442