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; 64 int ret; 65 66 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 67 if (!priv) 68 return -ENOMEM; 69 70 priv->pdata = dev_get_platdata(dev); 71 72 br = fpga_bridge_create(dev, "DFL FPGA FME Bridge", 73 &fme_bridge_ops, priv); 74 if (!br) 75 return -ENOMEM; 76 77 platform_set_drvdata(pdev, br); 78 79 ret = fpga_bridge_register(br); 80 if (ret) 81 fpga_bridge_free(br); 82 83 return ret; 84 } 85 86 static int fme_br_remove(struct platform_device *pdev) 87 { 88 struct fpga_bridge *br = platform_get_drvdata(pdev); 89 struct fme_br_priv *priv = br->priv; 90 91 fpga_bridge_unregister(br); 92 93 if (priv->port_pdev) 94 put_device(&priv->port_pdev->dev); 95 if (priv->port_ops) 96 dfl_fpga_port_ops_put(priv->port_ops); 97 98 return 0; 99 } 100 101 static struct platform_driver fme_br_driver = { 102 .driver = { 103 .name = DFL_FPGA_FME_BRIDGE, 104 }, 105 .probe = fme_br_probe, 106 .remove = fme_br_remove, 107 }; 108 109 module_platform_driver(fme_br_driver); 110 111 MODULE_DESCRIPTION("FPGA Bridge for DFL FPGA Management Engine"); 112 MODULE_AUTHOR("Intel Corporation"); 113 MODULE_LICENSE("GPL v2"); 114 MODULE_ALIAS("platform:dfl-fme-bridge"); 115