1*463dd43bSIvan Bornyakov // SPDX-License-Identifier: GPL-2.0
2*463dd43bSIvan Bornyakov /*
3*463dd43bSIvan Bornyakov  * Lattice FPGA sysCONFIG interface functions independent of port type.
4*463dd43bSIvan Bornyakov  */
5*463dd43bSIvan Bornyakov 
6*463dd43bSIvan Bornyakov #include <linux/delay.h>
7*463dd43bSIvan Bornyakov #include <linux/fpga/fpga-mgr.h>
8*463dd43bSIvan Bornyakov #include <linux/gpio/consumer.h>
9*463dd43bSIvan Bornyakov #include <linux/iopoll.h>
10*463dd43bSIvan Bornyakov 
11*463dd43bSIvan Bornyakov #include "lattice-sysconfig.h"
12*463dd43bSIvan Bornyakov 
sysconfig_cmd_write(struct sysconfig_priv * priv,const void * buf,size_t buf_len)13*463dd43bSIvan Bornyakov static int sysconfig_cmd_write(struct sysconfig_priv *priv, const void *buf,
14*463dd43bSIvan Bornyakov 			       size_t buf_len)
15*463dd43bSIvan Bornyakov {
16*463dd43bSIvan Bornyakov 	return priv->command_transfer(priv, buf, buf_len, NULL, 0);
17*463dd43bSIvan Bornyakov }
18*463dd43bSIvan Bornyakov 
sysconfig_cmd_read(struct sysconfig_priv * priv,const void * tx_buf,size_t tx_len,void * rx_buf,size_t rx_len)19*463dd43bSIvan Bornyakov static int sysconfig_cmd_read(struct sysconfig_priv *priv, const void *tx_buf,
20*463dd43bSIvan Bornyakov 			      size_t tx_len, void *rx_buf, size_t rx_len)
21*463dd43bSIvan Bornyakov {
22*463dd43bSIvan Bornyakov 	return priv->command_transfer(priv, tx_buf, tx_len, rx_buf, rx_len);
23*463dd43bSIvan Bornyakov }
24*463dd43bSIvan Bornyakov 
sysconfig_read_busy(struct sysconfig_priv * priv)25*463dd43bSIvan Bornyakov static int sysconfig_read_busy(struct sysconfig_priv *priv)
26*463dd43bSIvan Bornyakov {
27*463dd43bSIvan Bornyakov 	const u8 lsc_check_busy[] = SYSCONFIG_LSC_CHECK_BUSY;
28*463dd43bSIvan Bornyakov 	u8 busy;
29*463dd43bSIvan Bornyakov 	int ret;
30*463dd43bSIvan Bornyakov 
31*463dd43bSIvan Bornyakov 	ret = sysconfig_cmd_read(priv, lsc_check_busy, sizeof(lsc_check_busy),
32*463dd43bSIvan Bornyakov 				 &busy, sizeof(busy));
33*463dd43bSIvan Bornyakov 
34*463dd43bSIvan Bornyakov 	return ret ? : busy;
35*463dd43bSIvan Bornyakov }
36*463dd43bSIvan Bornyakov 
sysconfig_poll_busy(struct sysconfig_priv * priv)37*463dd43bSIvan Bornyakov static int sysconfig_poll_busy(struct sysconfig_priv *priv)
38*463dd43bSIvan Bornyakov {
39*463dd43bSIvan Bornyakov 	int ret, busy;
40*463dd43bSIvan Bornyakov 
41*463dd43bSIvan Bornyakov 	ret = read_poll_timeout(sysconfig_read_busy, busy, busy <= 0,
42*463dd43bSIvan Bornyakov 				SYSCONFIG_POLL_INTERVAL_US,
43*463dd43bSIvan Bornyakov 				SYSCONFIG_POLL_BUSY_TIMEOUT_US, false, priv);
44*463dd43bSIvan Bornyakov 
45*463dd43bSIvan Bornyakov 	return ret ? : busy;
46*463dd43bSIvan Bornyakov }
47*463dd43bSIvan Bornyakov 
sysconfig_read_status(struct sysconfig_priv * priv,u32 * status)48*463dd43bSIvan Bornyakov static int sysconfig_read_status(struct sysconfig_priv *priv, u32 *status)
49*463dd43bSIvan Bornyakov {
50*463dd43bSIvan Bornyakov 	const u8 lsc_read_status[] = SYSCONFIG_LSC_READ_STATUS;
51*463dd43bSIvan Bornyakov 	__be32 device_status;
52*463dd43bSIvan Bornyakov 	int ret;
53*463dd43bSIvan Bornyakov 
54*463dd43bSIvan Bornyakov 	ret = sysconfig_cmd_read(priv, lsc_read_status, sizeof(lsc_read_status),
55*463dd43bSIvan Bornyakov 				 &device_status, sizeof(device_status));
56*463dd43bSIvan Bornyakov 	if (ret)
57*463dd43bSIvan Bornyakov 		return ret;
58*463dd43bSIvan Bornyakov 
59*463dd43bSIvan Bornyakov 	*status = be32_to_cpu(device_status);
60*463dd43bSIvan Bornyakov 
61*463dd43bSIvan Bornyakov 	return 0;
62*463dd43bSIvan Bornyakov }
63*463dd43bSIvan Bornyakov 
sysconfig_poll_status(struct sysconfig_priv * priv,u32 * status)64*463dd43bSIvan Bornyakov static int sysconfig_poll_status(struct sysconfig_priv *priv, u32 *status)
65*463dd43bSIvan Bornyakov {
66*463dd43bSIvan Bornyakov 	int ret = sysconfig_poll_busy(priv);
67*463dd43bSIvan Bornyakov 
68*463dd43bSIvan Bornyakov 	if (ret)
69*463dd43bSIvan Bornyakov 		return ret;
70*463dd43bSIvan Bornyakov 
71*463dd43bSIvan Bornyakov 	return sysconfig_read_status(priv, status);
72*463dd43bSIvan Bornyakov }
73*463dd43bSIvan Bornyakov 
sysconfig_poll_gpio(struct gpio_desc * gpio,bool is_active)74*463dd43bSIvan Bornyakov static int sysconfig_poll_gpio(struct gpio_desc *gpio, bool is_active)
75*463dd43bSIvan Bornyakov {
76*463dd43bSIvan Bornyakov 	int ret, val;
77*463dd43bSIvan Bornyakov 
78*463dd43bSIvan Bornyakov 	ret = read_poll_timeout(gpiod_get_value, val,
79*463dd43bSIvan Bornyakov 				val < 0 || !!val == is_active,
80*463dd43bSIvan Bornyakov 				SYSCONFIG_POLL_INTERVAL_US,
81*463dd43bSIvan Bornyakov 				SYSCONFIG_POLL_GPIO_TIMEOUT_US, false, gpio);
82*463dd43bSIvan Bornyakov 
83*463dd43bSIvan Bornyakov 	if (val < 0)
84*463dd43bSIvan Bornyakov 		return val;
85*463dd43bSIvan Bornyakov 
86*463dd43bSIvan Bornyakov 	return ret;
87*463dd43bSIvan Bornyakov }
88*463dd43bSIvan Bornyakov 
sysconfig_gpio_refresh(struct sysconfig_priv * priv)89*463dd43bSIvan Bornyakov static int sysconfig_gpio_refresh(struct sysconfig_priv *priv)
90*463dd43bSIvan Bornyakov {
91*463dd43bSIvan Bornyakov 	struct gpio_desc *program = priv->program;
92*463dd43bSIvan Bornyakov 	struct gpio_desc *init = priv->init;
93*463dd43bSIvan Bornyakov 	struct gpio_desc *done = priv->done;
94*463dd43bSIvan Bornyakov 	int ret;
95*463dd43bSIvan Bornyakov 
96*463dd43bSIvan Bornyakov 	/* Enter init mode */
97*463dd43bSIvan Bornyakov 	gpiod_set_value(program, 1);
98*463dd43bSIvan Bornyakov 
99*463dd43bSIvan Bornyakov 	ret = sysconfig_poll_gpio(init, true);
100*463dd43bSIvan Bornyakov 	if (!ret)
101*463dd43bSIvan Bornyakov 		ret = sysconfig_poll_gpio(done, false);
102*463dd43bSIvan Bornyakov 
103*463dd43bSIvan Bornyakov 	if (ret)
104*463dd43bSIvan Bornyakov 		return ret;
105*463dd43bSIvan Bornyakov 
106*463dd43bSIvan Bornyakov 	/* Enter program mode */
107*463dd43bSIvan Bornyakov 	gpiod_set_value(program, 0);
108*463dd43bSIvan Bornyakov 
109*463dd43bSIvan Bornyakov 	return sysconfig_poll_gpio(init, false);
110*463dd43bSIvan Bornyakov }
111*463dd43bSIvan Bornyakov 
sysconfig_lsc_refresh(struct sysconfig_priv * priv)112*463dd43bSIvan Bornyakov static int sysconfig_lsc_refresh(struct sysconfig_priv *priv)
113*463dd43bSIvan Bornyakov {
114*463dd43bSIvan Bornyakov 	static const u8 lsc_refresh[] = SYSCONFIG_LSC_REFRESH;
115*463dd43bSIvan Bornyakov 	int ret;
116*463dd43bSIvan Bornyakov 
117*463dd43bSIvan Bornyakov 	ret = sysconfig_cmd_write(priv, lsc_refresh, sizeof(lsc_refresh));
118*463dd43bSIvan Bornyakov 	if (ret)
119*463dd43bSIvan Bornyakov 		return ret;
120*463dd43bSIvan Bornyakov 
121*463dd43bSIvan Bornyakov 	usleep_range(4000, 8000);
122*463dd43bSIvan Bornyakov 
123*463dd43bSIvan Bornyakov 	return 0;
124*463dd43bSIvan Bornyakov }
125*463dd43bSIvan Bornyakov 
sysconfig_refresh(struct sysconfig_priv * priv)126*463dd43bSIvan Bornyakov static int sysconfig_refresh(struct sysconfig_priv *priv)
127*463dd43bSIvan Bornyakov {
128*463dd43bSIvan Bornyakov 	struct gpio_desc *program = priv->program;
129*463dd43bSIvan Bornyakov 	struct gpio_desc *init = priv->init;
130*463dd43bSIvan Bornyakov 	struct gpio_desc *done = priv->done;
131*463dd43bSIvan Bornyakov 
132*463dd43bSIvan Bornyakov 	if (program && init && done)
133*463dd43bSIvan Bornyakov 		return sysconfig_gpio_refresh(priv);
134*463dd43bSIvan Bornyakov 
135*463dd43bSIvan Bornyakov 	return sysconfig_lsc_refresh(priv);
136*463dd43bSIvan Bornyakov }
137*463dd43bSIvan Bornyakov 
sysconfig_isc_enable(struct sysconfig_priv * priv)138*463dd43bSIvan Bornyakov static int sysconfig_isc_enable(struct sysconfig_priv *priv)
139*463dd43bSIvan Bornyakov {
140*463dd43bSIvan Bornyakov 	u8 isc_enable[] = SYSCONFIG_ISC_ENABLE;
141*463dd43bSIvan Bornyakov 	u32 status;
142*463dd43bSIvan Bornyakov 	int ret;
143*463dd43bSIvan Bornyakov 
144*463dd43bSIvan Bornyakov 	ret = sysconfig_cmd_write(priv, isc_enable, sizeof(isc_enable));
145*463dd43bSIvan Bornyakov 	if (ret)
146*463dd43bSIvan Bornyakov 		return ret;
147*463dd43bSIvan Bornyakov 
148*463dd43bSIvan Bornyakov 	ret = sysconfig_poll_status(priv, &status);
149*463dd43bSIvan Bornyakov 	if (ret)
150*463dd43bSIvan Bornyakov 		return ret;
151*463dd43bSIvan Bornyakov 
152*463dd43bSIvan Bornyakov 	if (status & SYSCONFIG_STATUS_FAIL)
153*463dd43bSIvan Bornyakov 		return -EFAULT;
154*463dd43bSIvan Bornyakov 
155*463dd43bSIvan Bornyakov 	return 0;
156*463dd43bSIvan Bornyakov }
157*463dd43bSIvan Bornyakov 
sysconfig_isc_erase(struct sysconfig_priv * priv)158*463dd43bSIvan Bornyakov static int sysconfig_isc_erase(struct sysconfig_priv *priv)
159*463dd43bSIvan Bornyakov {
160*463dd43bSIvan Bornyakov 	u8 isc_erase[] = SYSCONFIG_ISC_ERASE;
161*463dd43bSIvan Bornyakov 	u32 status;
162*463dd43bSIvan Bornyakov 	int ret;
163*463dd43bSIvan Bornyakov 
164*463dd43bSIvan Bornyakov 	ret = sysconfig_cmd_write(priv, isc_erase, sizeof(isc_erase));
165*463dd43bSIvan Bornyakov 	if (ret)
166*463dd43bSIvan Bornyakov 		return ret;
167*463dd43bSIvan Bornyakov 
168*463dd43bSIvan Bornyakov 	ret = sysconfig_poll_status(priv, &status);
169*463dd43bSIvan Bornyakov 	if (ret)
170*463dd43bSIvan Bornyakov 		return ret;
171*463dd43bSIvan Bornyakov 
172*463dd43bSIvan Bornyakov 	if (status & SYSCONFIG_STATUS_FAIL)
173*463dd43bSIvan Bornyakov 		return -EFAULT;
174*463dd43bSIvan Bornyakov 
175*463dd43bSIvan Bornyakov 	return 0;
176*463dd43bSIvan Bornyakov }
177*463dd43bSIvan Bornyakov 
sysconfig_isc_init(struct sysconfig_priv * priv)178*463dd43bSIvan Bornyakov static int sysconfig_isc_init(struct sysconfig_priv *priv)
179*463dd43bSIvan Bornyakov {
180*463dd43bSIvan Bornyakov 	int ret = sysconfig_isc_enable(priv);
181*463dd43bSIvan Bornyakov 
182*463dd43bSIvan Bornyakov 	if (ret)
183*463dd43bSIvan Bornyakov 		return ret;
184*463dd43bSIvan Bornyakov 
185*463dd43bSIvan Bornyakov 	return sysconfig_isc_erase(priv);
186*463dd43bSIvan Bornyakov }
187*463dd43bSIvan Bornyakov 
sysconfig_lsc_init_addr(struct sysconfig_priv * priv)188*463dd43bSIvan Bornyakov static int sysconfig_lsc_init_addr(struct sysconfig_priv *priv)
189*463dd43bSIvan Bornyakov {
190*463dd43bSIvan Bornyakov 	const u8 lsc_init_addr[] = SYSCONFIG_LSC_INIT_ADDR;
191*463dd43bSIvan Bornyakov 
192*463dd43bSIvan Bornyakov 	return sysconfig_cmd_write(priv, lsc_init_addr, sizeof(lsc_init_addr));
193*463dd43bSIvan Bornyakov }
194*463dd43bSIvan Bornyakov 
sysconfig_burst_write_init(struct sysconfig_priv * priv)195*463dd43bSIvan Bornyakov static int sysconfig_burst_write_init(struct sysconfig_priv *priv)
196*463dd43bSIvan Bornyakov {
197*463dd43bSIvan Bornyakov 	return priv->bitstream_burst_write_init(priv);
198*463dd43bSIvan Bornyakov }
199*463dd43bSIvan Bornyakov 
sysconfig_burst_write_complete(struct sysconfig_priv * priv)200*463dd43bSIvan Bornyakov static int sysconfig_burst_write_complete(struct sysconfig_priv *priv)
201*463dd43bSIvan Bornyakov {
202*463dd43bSIvan Bornyakov 	return priv->bitstream_burst_write_complete(priv);
203*463dd43bSIvan Bornyakov }
204*463dd43bSIvan Bornyakov 
sysconfig_bitstream_burst_write(struct sysconfig_priv * priv,const char * buf,size_t count)205*463dd43bSIvan Bornyakov static int sysconfig_bitstream_burst_write(struct sysconfig_priv *priv,
206*463dd43bSIvan Bornyakov 					   const char *buf, size_t count)
207*463dd43bSIvan Bornyakov {
208*463dd43bSIvan Bornyakov 	int ret = priv->bitstream_burst_write(priv, buf, count);
209*463dd43bSIvan Bornyakov 
210*463dd43bSIvan Bornyakov 	if (ret)
211*463dd43bSIvan Bornyakov 		sysconfig_burst_write_complete(priv);
212*463dd43bSIvan Bornyakov 
213*463dd43bSIvan Bornyakov 	return ret;
214*463dd43bSIvan Bornyakov }
215*463dd43bSIvan Bornyakov 
sysconfig_isc_disable(struct sysconfig_priv * priv)216*463dd43bSIvan Bornyakov static int sysconfig_isc_disable(struct sysconfig_priv *priv)
217*463dd43bSIvan Bornyakov {
218*463dd43bSIvan Bornyakov 	const u8 isc_disable[] = SYSCONFIG_ISC_DISABLE;
219*463dd43bSIvan Bornyakov 
220*463dd43bSIvan Bornyakov 	return sysconfig_cmd_write(priv, isc_disable, sizeof(isc_disable));
221*463dd43bSIvan Bornyakov }
222*463dd43bSIvan Bornyakov 
sysconfig_cleanup(struct sysconfig_priv * priv)223*463dd43bSIvan Bornyakov static void sysconfig_cleanup(struct sysconfig_priv *priv)
224*463dd43bSIvan Bornyakov {
225*463dd43bSIvan Bornyakov 	sysconfig_isc_erase(priv);
226*463dd43bSIvan Bornyakov 	sysconfig_refresh(priv);
227*463dd43bSIvan Bornyakov }
228*463dd43bSIvan Bornyakov 
sysconfig_isc_finish(struct sysconfig_priv * priv)229*463dd43bSIvan Bornyakov static int sysconfig_isc_finish(struct sysconfig_priv *priv)
230*463dd43bSIvan Bornyakov {
231*463dd43bSIvan Bornyakov 	struct gpio_desc *done_gpio = priv->done;
232*463dd43bSIvan Bornyakov 	u32 status;
233*463dd43bSIvan Bornyakov 	int ret;
234*463dd43bSIvan Bornyakov 
235*463dd43bSIvan Bornyakov 	if (done_gpio) {
236*463dd43bSIvan Bornyakov 		ret = sysconfig_isc_disable(priv);
237*463dd43bSIvan Bornyakov 		if (ret)
238*463dd43bSIvan Bornyakov 			return ret;
239*463dd43bSIvan Bornyakov 
240*463dd43bSIvan Bornyakov 		return sysconfig_poll_gpio(done_gpio, true);
241*463dd43bSIvan Bornyakov 	}
242*463dd43bSIvan Bornyakov 
243*463dd43bSIvan Bornyakov 	ret = sysconfig_poll_status(priv, &status);
244*463dd43bSIvan Bornyakov 	if (ret)
245*463dd43bSIvan Bornyakov 		return ret;
246*463dd43bSIvan Bornyakov 
247*463dd43bSIvan Bornyakov 	if ((status & SYSCONFIG_STATUS_DONE) &&
248*463dd43bSIvan Bornyakov 	    !(status & SYSCONFIG_STATUS_BUSY) &&
249*463dd43bSIvan Bornyakov 	    !(status & SYSCONFIG_STATUS_ERR))
250*463dd43bSIvan Bornyakov 		return sysconfig_isc_disable(priv);
251*463dd43bSIvan Bornyakov 
252*463dd43bSIvan Bornyakov 	return -EFAULT;
253*463dd43bSIvan Bornyakov }
254*463dd43bSIvan Bornyakov 
sysconfig_ops_state(struct fpga_manager * mgr)255*463dd43bSIvan Bornyakov static enum fpga_mgr_states sysconfig_ops_state(struct fpga_manager *mgr)
256*463dd43bSIvan Bornyakov {
257*463dd43bSIvan Bornyakov 	struct sysconfig_priv *priv = mgr->priv;
258*463dd43bSIvan Bornyakov 	struct gpio_desc *done = priv->done;
259*463dd43bSIvan Bornyakov 	u32 status;
260*463dd43bSIvan Bornyakov 	int ret;
261*463dd43bSIvan Bornyakov 
262*463dd43bSIvan Bornyakov 	if (done && (gpiod_get_value(done) > 0))
263*463dd43bSIvan Bornyakov 		return FPGA_MGR_STATE_OPERATING;
264*463dd43bSIvan Bornyakov 
265*463dd43bSIvan Bornyakov 	ret = sysconfig_read_status(priv, &status);
266*463dd43bSIvan Bornyakov 	if (!ret && (status & SYSCONFIG_STATUS_DONE))
267*463dd43bSIvan Bornyakov 		return FPGA_MGR_STATE_OPERATING;
268*463dd43bSIvan Bornyakov 
269*463dd43bSIvan Bornyakov 	return FPGA_MGR_STATE_UNKNOWN;
270*463dd43bSIvan Bornyakov }
271*463dd43bSIvan Bornyakov 
sysconfig_ops_write_init(struct fpga_manager * mgr,struct fpga_image_info * info,const char * buf,size_t count)272*463dd43bSIvan Bornyakov static int sysconfig_ops_write_init(struct fpga_manager *mgr,
273*463dd43bSIvan Bornyakov 				    struct fpga_image_info *info,
274*463dd43bSIvan Bornyakov 				    const char *buf, size_t count)
275*463dd43bSIvan Bornyakov {
276*463dd43bSIvan Bornyakov 	struct sysconfig_priv *priv = mgr->priv;
277*463dd43bSIvan Bornyakov 	struct device *dev = &mgr->dev;
278*463dd43bSIvan Bornyakov 	int ret;
279*463dd43bSIvan Bornyakov 
280*463dd43bSIvan Bornyakov 	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
281*463dd43bSIvan Bornyakov 		dev_err(dev, "Partial reconfiguration is not supported\n");
282*463dd43bSIvan Bornyakov 		return -EOPNOTSUPP;
283*463dd43bSIvan Bornyakov 	}
284*463dd43bSIvan Bornyakov 
285*463dd43bSIvan Bornyakov 	/* Enter program mode */
286*463dd43bSIvan Bornyakov 	ret = sysconfig_refresh(priv);
287*463dd43bSIvan Bornyakov 	if (ret) {
288*463dd43bSIvan Bornyakov 		dev_err(dev, "Failed to go to program mode\n");
289*463dd43bSIvan Bornyakov 		return ret;
290*463dd43bSIvan Bornyakov 	}
291*463dd43bSIvan Bornyakov 
292*463dd43bSIvan Bornyakov 	/* Enter ISC mode */
293*463dd43bSIvan Bornyakov 	ret = sysconfig_isc_init(priv);
294*463dd43bSIvan Bornyakov 	if (ret) {
295*463dd43bSIvan Bornyakov 		dev_err(dev, "Failed to go to ISC mode\n");
296*463dd43bSIvan Bornyakov 		return ret;
297*463dd43bSIvan Bornyakov 	}
298*463dd43bSIvan Bornyakov 
299*463dd43bSIvan Bornyakov 	/* Initialize the Address Shift Register */
300*463dd43bSIvan Bornyakov 	ret = sysconfig_lsc_init_addr(priv);
301*463dd43bSIvan Bornyakov 	if (ret) {
302*463dd43bSIvan Bornyakov 		dev_err(dev,
303*463dd43bSIvan Bornyakov 			"Failed to initialize the Address Shift Register\n");
304*463dd43bSIvan Bornyakov 		return ret;
305*463dd43bSIvan Bornyakov 	}
306*463dd43bSIvan Bornyakov 
307*463dd43bSIvan Bornyakov 	/* Prepare for bitstream burst write */
308*463dd43bSIvan Bornyakov 	ret = sysconfig_burst_write_init(priv);
309*463dd43bSIvan Bornyakov 	if (ret)
310*463dd43bSIvan Bornyakov 		dev_err(dev, "Failed to prepare for bitstream burst write\n");
311*463dd43bSIvan Bornyakov 
312*463dd43bSIvan Bornyakov 	return ret;
313*463dd43bSIvan Bornyakov }
314*463dd43bSIvan Bornyakov 
sysconfig_ops_write(struct fpga_manager * mgr,const char * buf,size_t count)315*463dd43bSIvan Bornyakov static int sysconfig_ops_write(struct fpga_manager *mgr, const char *buf,
316*463dd43bSIvan Bornyakov 			       size_t count)
317*463dd43bSIvan Bornyakov {
318*463dd43bSIvan Bornyakov 	return sysconfig_bitstream_burst_write(mgr->priv, buf, count);
319*463dd43bSIvan Bornyakov }
320*463dd43bSIvan Bornyakov 
sysconfig_ops_write_complete(struct fpga_manager * mgr,struct fpga_image_info * info)321*463dd43bSIvan Bornyakov static int sysconfig_ops_write_complete(struct fpga_manager *mgr,
322*463dd43bSIvan Bornyakov 					struct fpga_image_info *info)
323*463dd43bSIvan Bornyakov {
324*463dd43bSIvan Bornyakov 	struct sysconfig_priv *priv = mgr->priv;
325*463dd43bSIvan Bornyakov 	struct device *dev = &mgr->dev;
326*463dd43bSIvan Bornyakov 	int ret;
327*463dd43bSIvan Bornyakov 
328*463dd43bSIvan Bornyakov 	ret = sysconfig_burst_write_complete(priv);
329*463dd43bSIvan Bornyakov 	if (!ret)
330*463dd43bSIvan Bornyakov 		ret = sysconfig_poll_busy(priv);
331*463dd43bSIvan Bornyakov 
332*463dd43bSIvan Bornyakov 	if (ret) {
333*463dd43bSIvan Bornyakov 		dev_err(dev, "Error while waiting bitstream write to finish\n");
334*463dd43bSIvan Bornyakov 		goto fail;
335*463dd43bSIvan Bornyakov 	}
336*463dd43bSIvan Bornyakov 
337*463dd43bSIvan Bornyakov 	ret = sysconfig_isc_finish(priv);
338*463dd43bSIvan Bornyakov 
339*463dd43bSIvan Bornyakov fail:
340*463dd43bSIvan Bornyakov 	if (ret)
341*463dd43bSIvan Bornyakov 		sysconfig_cleanup(priv);
342*463dd43bSIvan Bornyakov 
343*463dd43bSIvan Bornyakov 	return ret;
344*463dd43bSIvan Bornyakov }
345*463dd43bSIvan Bornyakov 
346*463dd43bSIvan Bornyakov static const struct fpga_manager_ops sysconfig_fpga_mgr_ops = {
347*463dd43bSIvan Bornyakov 	.state = sysconfig_ops_state,
348*463dd43bSIvan Bornyakov 	.write_init = sysconfig_ops_write_init,
349*463dd43bSIvan Bornyakov 	.write = sysconfig_ops_write,
350*463dd43bSIvan Bornyakov 	.write_complete = sysconfig_ops_write_complete,
351*463dd43bSIvan Bornyakov };
352*463dd43bSIvan Bornyakov 
sysconfig_probe(struct sysconfig_priv * priv)353*463dd43bSIvan Bornyakov int sysconfig_probe(struct sysconfig_priv *priv)
354*463dd43bSIvan Bornyakov {
355*463dd43bSIvan Bornyakov 	struct gpio_desc *program, *init, *done;
356*463dd43bSIvan Bornyakov 	struct device *dev = priv->dev;
357*463dd43bSIvan Bornyakov 	struct fpga_manager *mgr;
358*463dd43bSIvan Bornyakov 
359*463dd43bSIvan Bornyakov 	if (!dev)
360*463dd43bSIvan Bornyakov 		return -ENODEV;
361*463dd43bSIvan Bornyakov 
362*463dd43bSIvan Bornyakov 	if (!priv->command_transfer ||
363*463dd43bSIvan Bornyakov 	    !priv->bitstream_burst_write_init ||
364*463dd43bSIvan Bornyakov 	    !priv->bitstream_burst_write ||
365*463dd43bSIvan Bornyakov 	    !priv->bitstream_burst_write_complete) {
366*463dd43bSIvan Bornyakov 		dev_err(dev, "Essential callback is missing\n");
367*463dd43bSIvan Bornyakov 		return -EINVAL;
368*463dd43bSIvan Bornyakov 	}
369*463dd43bSIvan Bornyakov 
370*463dd43bSIvan Bornyakov 	program = devm_gpiod_get_optional(dev, "program", GPIOD_OUT_LOW);
371*463dd43bSIvan Bornyakov 	if (IS_ERR(program))
372*463dd43bSIvan Bornyakov 		return dev_err_probe(dev, PTR_ERR(program),
373*463dd43bSIvan Bornyakov 				     "Failed to get PROGRAM GPIO\n");
374*463dd43bSIvan Bornyakov 
375*463dd43bSIvan Bornyakov 	init = devm_gpiod_get_optional(dev, "init", GPIOD_IN);
376*463dd43bSIvan Bornyakov 	if (IS_ERR(init))
377*463dd43bSIvan Bornyakov 		return dev_err_probe(dev, PTR_ERR(init),
378*463dd43bSIvan Bornyakov 				     "Failed to get INIT GPIO\n");
379*463dd43bSIvan Bornyakov 
380*463dd43bSIvan Bornyakov 	done = devm_gpiod_get_optional(dev, "done", GPIOD_IN);
381*463dd43bSIvan Bornyakov 	if (IS_ERR(done))
382*463dd43bSIvan Bornyakov 		return dev_err_probe(dev, PTR_ERR(done),
383*463dd43bSIvan Bornyakov 				     "Failed to get DONE GPIO\n");
384*463dd43bSIvan Bornyakov 
385*463dd43bSIvan Bornyakov 	priv->program = program;
386*463dd43bSIvan Bornyakov 	priv->init = init;
387*463dd43bSIvan Bornyakov 	priv->done = done;
388*463dd43bSIvan Bornyakov 
389*463dd43bSIvan Bornyakov 	mgr = devm_fpga_mgr_register(dev, "Lattice sysCONFIG FPGA Manager",
390*463dd43bSIvan Bornyakov 				     &sysconfig_fpga_mgr_ops, priv);
391*463dd43bSIvan Bornyakov 
392*463dd43bSIvan Bornyakov 	return PTR_ERR_OR_ZERO(mgr);
393*463dd43bSIvan Bornyakov }
394*463dd43bSIvan Bornyakov EXPORT_SYMBOL(sysconfig_probe);
395*463dd43bSIvan Bornyakov 
396*463dd43bSIvan Bornyakov MODULE_DESCRIPTION("Lattice sysCONFIG FPGA Manager Core");
397*463dd43bSIvan Bornyakov MODULE_LICENSE("GPL");
398