Commit | Line | Data |
---|---|---|
de892dff WH |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * FPGA Bridge Driver for FPGA Management Engine (FME) | |
4 | * | |
5 | * Copyright (C) 2017-2018 Intel Corporation, Inc. | |
6 | * | |
7 | * Authors: | |
8 | * Wu Hao <hao.wu@intel.com> | |
9 | * Joseph Grecco <joe.grecco@intel.com> | |
10 | * Enno Luebbers <enno.luebbers@intel.com> | |
11 | * Tim Whisonant <tim.whisonant@intel.com> | |
12 | * Ananda Ravuri <ananda.ravuri@intel.com> | |
13 | * Henry Mitchel <henry.mitchel@intel.com> | |
14 | */ | |
15 | ||
16 | #include <linux/module.h> | |
17 | #include <linux/fpga/fpga-bridge.h> | |
18 | ||
19 | #include "dfl.h" | |
20 | #include "dfl-fme-pr.h" | |
21 | ||
22 | struct fme_br_priv { | |
23 | struct dfl_fme_br_pdata *pdata; | |
24 | struct dfl_fpga_port_ops *port_ops; | |
25 | struct platform_device *port_pdev; | |
26 | }; | |
27 | ||
28 | static int fme_bridge_enable_set(struct fpga_bridge *bridge, bool enable) | |
29 | { | |
30 | struct fme_br_priv *priv = bridge->priv; | |
31 | struct platform_device *port_pdev; | |
32 | struct dfl_fpga_port_ops *ops; | |
33 | ||
34 | if (!priv->port_pdev) { | |
35 | port_pdev = dfl_fpga_cdev_find_port(priv->pdata->cdev, | |
36 | &priv->pdata->port_id, | |
37 | dfl_fpga_check_port_id); | |
38 | if (!port_pdev) | |
39 | return -ENODEV; | |
40 | ||
41 | priv->port_pdev = port_pdev; | |
42 | } | |
43 | ||
44 | if (priv->port_pdev && !priv->port_ops) { | |
45 | ops = dfl_fpga_port_ops_get(priv->port_pdev); | |
46 | if (!ops || !ops->enable_set) | |
47 | return -ENOENT; | |
48 | ||
49 | priv->port_ops = ops; | |
50 | } | |
51 | ||
52 | return priv->port_ops->enable_set(priv->port_pdev, enable); | |
53 | } | |
54 | ||
55 | static const struct fpga_bridge_ops fme_bridge_ops = { | |
56 | .enable_set = fme_bridge_enable_set, | |
57 | }; | |
58 | ||
59 | static int fme_br_probe(struct platform_device *pdev) | |
60 | { | |
61 | struct device *dev = &pdev->dev; | |
62 | struct fme_br_priv *priv; | |
63 | struct fpga_bridge *br; | |
de892dff WH |
64 | |
65 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | |
66 | if (!priv) | |
67 | return -ENOMEM; | |
68 | ||
69 | priv->pdata = dev_get_platdata(dev); | |
70 | ||
213befe0 AT |
71 | br = devm_fpga_bridge_create(dev, "DFL FPGA FME Bridge", |
72 | &fme_bridge_ops, priv); | |
de892dff WH |
73 | if (!br) |
74 | return -ENOMEM; | |
75 | ||
76 | platform_set_drvdata(pdev, br); | |
77 | ||
213befe0 | 78 | return fpga_bridge_register(br); |
de892dff WH |
79 | } |
80 | ||
81 | static int fme_br_remove(struct platform_device *pdev) | |
82 | { | |
83 | struct fpga_bridge *br = platform_get_drvdata(pdev); | |
84 | struct fme_br_priv *priv = br->priv; | |
85 | ||
86 | fpga_bridge_unregister(br); | |
87 | ||
88 | if (priv->port_pdev) | |
89 | put_device(&priv->port_pdev->dev); | |
90 | if (priv->port_ops) | |
91 | dfl_fpga_port_ops_put(priv->port_ops); | |
92 | ||
93 | return 0; | |
94 | } | |
95 | ||
96 | static struct platform_driver fme_br_driver = { | |
97 | .driver = { | |
98 | .name = DFL_FPGA_FME_BRIDGE, | |
99 | }, | |
100 | .probe = fme_br_probe, | |
101 | .remove = fme_br_remove, | |
102 | }; | |
103 | ||
104 | module_platform_driver(fme_br_driver); | |
105 | ||
106 | MODULE_DESCRIPTION("FPGA Bridge for DFL FPGA Management Engine"); | |
107 | MODULE_AUTHOR("Intel Corporation"); | |
108 | MODULE_LICENSE("GPL v2"); | |
109 | MODULE_ALIAS("platform:dfl-fme-bridge"); |