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