1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2017, National Instruments Corp.
4 * Copyright (c) 2017, Xilix Inc
6 * FPGA Bridge Driver for the Xilinx LogiCORE Partial Reconfiguration
10 #include <linux/clk.h>
12 #include <linux/kernel.h>
13 #include <linux/of_device.h>
14 #include <linux/module.h>
15 #include <linux/fpga/fpga-bridge.h>
17 #define CTRL_CMD_DECOUPLE BIT(0)
18 #define CTRL_CMD_COUPLE 0
21 struct xlnx_pr_decoupler_data
{
22 void __iomem
*io_base
;
26 static inline void xlnx_pr_decoupler_write(struct xlnx_pr_decoupler_data
*d
,
29 writel(val
, d
->io_base
+ offset
);
32 static inline u32
xlnx_pr_decouple_read(const struct xlnx_pr_decoupler_data
*d
,
35 return readl(d
->io_base
+ offset
);
38 static int xlnx_pr_decoupler_enable_set(struct fpga_bridge
*bridge
, bool enable
)
41 struct xlnx_pr_decoupler_data
*priv
= bridge
->priv
;
43 err
= clk_enable(priv
->clk
);
48 xlnx_pr_decoupler_write(priv
, CTRL_OFFSET
, CTRL_CMD_COUPLE
);
50 xlnx_pr_decoupler_write(priv
, CTRL_OFFSET
, CTRL_CMD_DECOUPLE
);
52 clk_disable(priv
->clk
);
57 static int xlnx_pr_decoupler_enable_show(struct fpga_bridge
*bridge
)
59 const struct xlnx_pr_decoupler_data
*priv
= bridge
->priv
;
63 err
= clk_enable(priv
->clk
);
67 status
= readl(priv
->io_base
);
69 clk_disable(priv
->clk
);
74 static const struct fpga_bridge_ops xlnx_pr_decoupler_br_ops
= {
75 .enable_set
= xlnx_pr_decoupler_enable_set
,
76 .enable_show
= xlnx_pr_decoupler_enable_show
,
79 static const struct of_device_id xlnx_pr_decoupler_of_match
[] = {
80 { .compatible
= "xlnx,pr-decoupler-1.00", },
81 { .compatible
= "xlnx,pr-decoupler", },
84 MODULE_DEVICE_TABLE(of
, xlnx_pr_decoupler_of_match
);
86 static int xlnx_pr_decoupler_probe(struct platform_device
*pdev
)
88 struct xlnx_pr_decoupler_data
*priv
;
89 struct fpga_bridge
*br
;
93 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
97 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
98 priv
->io_base
= devm_ioremap_resource(&pdev
->dev
, res
);
99 if (IS_ERR(priv
->io_base
))
100 return PTR_ERR(priv
->io_base
);
102 priv
->clk
= devm_clk_get(&pdev
->dev
, "aclk");
103 if (IS_ERR(priv
->clk
)) {
104 if (PTR_ERR(priv
->clk
) != -EPROBE_DEFER
)
105 dev_err(&pdev
->dev
, "input clock not found\n");
106 return PTR_ERR(priv
->clk
);
109 err
= clk_prepare_enable(priv
->clk
);
111 dev_err(&pdev
->dev
, "unable to enable clock\n");
115 clk_disable(priv
->clk
);
117 br
= devm_fpga_bridge_create(&pdev
->dev
, "Xilinx PR Decoupler",
118 &xlnx_pr_decoupler_br_ops
, priv
);
124 platform_set_drvdata(pdev
, br
);
126 err
= fpga_bridge_register(br
);
128 dev_err(&pdev
->dev
, "unable to register Xilinx PR Decoupler");
135 clk_unprepare(priv
->clk
);
140 static int xlnx_pr_decoupler_remove(struct platform_device
*pdev
)
142 struct fpga_bridge
*bridge
= platform_get_drvdata(pdev
);
143 struct xlnx_pr_decoupler_data
*p
= bridge
->priv
;
145 fpga_bridge_unregister(bridge
);
147 clk_unprepare(p
->clk
);
152 static struct platform_driver xlnx_pr_decoupler_driver
= {
153 .probe
= xlnx_pr_decoupler_probe
,
154 .remove
= xlnx_pr_decoupler_remove
,
156 .name
= "xlnx_pr_decoupler",
157 .of_match_table
= of_match_ptr(xlnx_pr_decoupler_of_match
),
161 module_platform_driver(xlnx_pr_decoupler_driver
);
163 MODULE_DESCRIPTION("Xilinx Partial Reconfiguration Decoupler");
164 MODULE_AUTHOR("Moritz Fischer <mdf@kernel.org>");
165 MODULE_AUTHOR("Michal Simek <michal.simek@xilinx.com>");
166 MODULE_LICENSE("GPL v2");