blob: bdcfe951d939c99e6de146bba3c4c880a8ce25c9 [file] [log] [blame]
Kang Luwei322ddeb2018-06-30 08:53:21 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Driver for FPGA Management Engine (FME)
4 *
5 * Copyright (C) 2017-2018 Intel Corporation, Inc.
6 *
7 * Authors:
8 * Kang Luwei <luwei.kang@intel.com>
9 * Xiao Guangrong <guangrong.xiao@linux.intel.com>
10 * Joseph Grecco <joe.grecco@intel.com>
11 * Enno Luebbers <enno.luebbers@intel.com>
12 * Tim Whisonant <tim.whisonant@intel.com>
13 * Ananda Ravuri <ananda.ravuri@intel.com>
14 * Henry Mitchel <henry.mitchel@intel.com>
15 */
16
17#include <linux/kernel.h>
18#include <linux/module.h>
19
20#include "dfl.h"
21
22static int fme_hdr_init(struct platform_device *pdev,
23 struct dfl_feature *feature)
24{
25 dev_dbg(&pdev->dev, "FME HDR Init.\n");
26
27 return 0;
28}
29
30static void fme_hdr_uinit(struct platform_device *pdev,
31 struct dfl_feature *feature)
32{
33 dev_dbg(&pdev->dev, "FME HDR UInit.\n");
34}
35
36static const struct dfl_feature_ops fme_hdr_ops = {
37 .init = fme_hdr_init,
38 .uinit = fme_hdr_uinit,
39};
40
41static struct dfl_feature_driver fme_feature_drvs[] = {
42 {
43 .id = FME_FEATURE_ID_HEADER,
44 .ops = &fme_hdr_ops,
45 },
46 {
47 .ops = NULL,
48 },
49};
50
51static int fme_open(struct inode *inode, struct file *filp)
52{
53 struct platform_device *fdev = dfl_fpga_inode_to_feature_dev(inode);
54 struct dfl_feature_platform_data *pdata = dev_get_platdata(&fdev->dev);
55 int ret;
56
57 if (WARN_ON(!pdata))
58 return -ENODEV;
59
60 ret = dfl_feature_dev_use_begin(pdata);
61 if (ret)
62 return ret;
63
64 dev_dbg(&fdev->dev, "Device File Open\n");
65 filp->private_data = pdata;
66
67 return 0;
68}
69
70static int fme_release(struct inode *inode, struct file *filp)
71{
72 struct dfl_feature_platform_data *pdata = filp->private_data;
73 struct platform_device *pdev = pdata->dev;
74
75 dev_dbg(&pdev->dev, "Device File Release\n");
76 dfl_feature_dev_use_end(pdata);
77
78 return 0;
79}
80
81static long fme_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
82{
83 struct dfl_feature_platform_data *pdata = filp->private_data;
84 struct platform_device *pdev = pdata->dev;
85 struct dfl_feature *f;
86 long ret;
87
88 dev_dbg(&pdev->dev, "%s cmd 0x%x\n", __func__, cmd);
89
90 switch (cmd) {
91 default:
92 /*
93 * Let sub-feature's ioctl function to handle the cmd.
94 * Sub-feature's ioctl returns -ENODEV when cmd is not
95 * handled in this sub feature, and returns 0 or other
96 * error code if cmd is handled.
97 */
98 dfl_fpga_dev_for_each_feature(pdata, f) {
99 if (f->ops && f->ops->ioctl) {
100 ret = f->ops->ioctl(pdev, f, cmd, arg);
101 if (ret != -ENODEV)
102 return ret;
103 }
104 }
105 }
106
107 return -EINVAL;
108}
109
110static const struct file_operations fme_fops = {
111 .owner = THIS_MODULE,
112 .open = fme_open,
113 .release = fme_release,
114 .unlocked_ioctl = fme_ioctl,
115};
116
117static int fme_probe(struct platform_device *pdev)
118{
119 int ret;
120
121 ret = dfl_fpga_dev_feature_init(pdev, fme_feature_drvs);
122 if (ret)
123 goto exit;
124
125 ret = dfl_fpga_dev_ops_register(pdev, &fme_fops, THIS_MODULE);
126 if (ret)
127 goto feature_uinit;
128
129 return 0;
130
131feature_uinit:
132 dfl_fpga_dev_feature_uinit(pdev);
133exit:
134 return ret;
135}
136
137static int fme_remove(struct platform_device *pdev)
138{
139 dfl_fpga_dev_ops_unregister(pdev);
140 dfl_fpga_dev_feature_uinit(pdev);
141
142 return 0;
143}
144
145static struct platform_driver fme_driver = {
146 .driver = {
147 .name = DFL_FPGA_FEATURE_DEV_FME,
148 },
149 .probe = fme_probe,
150 .remove = fme_remove,
151};
152
153module_platform_driver(fme_driver);
154
155MODULE_DESCRIPTION("FPGA Management Engine driver");
156MODULE_AUTHOR("Intel Corporation");
157MODULE_LICENSE("GPL v2");
158MODULE_ALIAS("platform:dfl-fme");