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 65 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 66 if (!priv) 67 return -ENOMEM; 68 69 priv->pdata = dev_get_platdata(dev); 70 71 br = devm_fpga_bridge_create(dev, "DFL FPGA FME Bridge", 72 &fme_bridge_ops, priv); 73 if (!br) 74 return -ENOMEM; 75 76 platform_set_drvdata(pdev, br); 77 78 return fpga_bridge_register(br); 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"); 110