xref: /freebsd/sys/arm/xilinx/zy7_spi.c (revision 32100375a661c1e16588ddfa7b90ca8d26cb9786)
1 /*-
2  * Copyright (c) 2018 Thomas Skibo <thomasskibo@yahoo.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/conf.h>
35 #include <sys/kernel.h>
36 #include <sys/module.h>
37 #include <sys/sysctl.h>
38 #include <sys/lock.h>
39 #include <sys/mutex.h>
40 #include <sys/resource.h>
41 #include <sys/rman.h>
42 #include <sys/uio.h>
43 
44 #include <machine/bus.h>
45 #include <machine/resource.h>
46 #include <machine/stdarg.h>
47 
48 #include <dev/fdt/fdt_common.h>
49 #include <dev/ofw/ofw_bus.h>
50 #include <dev/ofw/ofw_bus_subr.h>
51 
52 #include <dev/spibus/spi.h>
53 #include <dev/spibus/spibusvar.h>
54 
55 #include "spibus_if.h"
56 
57 static struct ofw_compat_data compat_data[] = {
58 	{"xlnx,zy7_spi",		1},
59 	{"xlnx,zynq-spi-1.0",		1},
60 	{"cdns,spi-r1p6",		1},
61 	{NULL,				0}
62 };
63 
64 struct zy7_spi_softc {
65 	device_t		dev;
66 	device_t		child;
67 	struct mtx		sc_mtx;
68 	struct resource		*mem_res;
69 	struct resource		*irq_res;
70 	void			*intrhandle;
71 
72 	uint32_t		cfg_reg_shadow;
73 	uint32_t		spi_clock;
74 	uint32_t		ref_clock;
75 	unsigned int		spi_clk_real_freq;
76 	unsigned int		rx_overflows;
77 	unsigned int		tx_underflows;
78 	unsigned int		interrupts;
79 	unsigned int		stray_ints;
80 	struct spi_command	*cmd;
81 	int			tx_bytes;	/* tx_cmd_sz + tx_data_sz */
82 	int			tx_bytes_sent;
83 	int			rx_bytes;	/* rx_cmd_sz + rx_data_sz */
84 	int			rx_bytes_rcvd;
85 	int			busy;
86 };
87 
88 #define ZY7_SPI_DEFAULT_SPI_CLOCK	50000000
89 
90 #define SPI_SC_LOCK(sc)		mtx_lock(&(sc)->sc_mtx)
91 #define	SPI_SC_UNLOCK(sc)		mtx_unlock(&(sc)->sc_mtx)
92 #define SPI_SC_LOCK_INIT(sc) \
93 	mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev),	NULL, MTX_DEF)
94 #define SPI_SC_LOCK_DESTROY(sc)	mtx_destroy(&(sc)->sc_mtx)
95 #define SPI_SC_ASSERT_LOCKED(sc)	mtx_assert(&(sc)->sc_mtx, MA_OWNED)
96 
97 #define RD4(sc, off)		(bus_read_4((sc)->mem_res, (off)))
98 #define WR4(sc, off, val)	(bus_write_4((sc)->mem_res, (off), (val)))
99 
100 /*
101  * SPI device registers.
102  * Reference: Zynq-7000 All Programmable SoC Technical Reference Manual.
103  * (v1.12.1) December 6, 2017.  Xilinx doc UG585.
104  */
105 #define ZY7_SPI_CONFIG_REG		0x0000
106 #define   ZY7_SPI_CONFIG_MODEFAIL_GEN_EN	(1 << 17)
107 #define   ZY7_SPI_CONFIG_MAN_STRT		(1 << 16)
108 #define   ZY7_SPI_CONFIG_MAN_STRT_EN		(1 << 15)
109 #define   ZY7_SPI_CONFIG_MAN_CS			(1 << 14)
110 #define   ZY7_SPI_CONFIG_CS_MASK		(0xf << 10)
111 #define   ZY7_SPI_CONFIG_CS(x)			((0xf ^ (1 << (x))) << 10)
112 #define   ZY7_SPI_CONFIG_PERI_SEL		(1 << 9)
113 #define   ZY7_SPI_CONFIG_REF_CLK		(1 << 8)
114 #define   ZY7_SPI_CONFIG_BAUD_RATE_DIV_MASK	(7 << 3)
115 #define   ZY7_SPI_CONFIG_BAUD_RATE_DIV_SHIFT	3
116 #define   ZY7_SPI_CONFIG_BAUD_RATE_DIV(x)	((x) << 3) /* divide by 2<<x */
117 #define   ZY7_SPI_CONFIG_CLK_PH			(1 << 2)   /* clock phase */
118 #define   ZY7_SPI_CONFIG_CLK_POL		(1 << 1)   /* clock polatiry */
119 #define   ZY7_SPI_CONFIG_MODE_SEL		(1 << 0)   /* master enable */
120 
121 #define ZY7_SPI_INTR_STAT_REG		0x0004
122 #define ZY7_SPI_INTR_EN_REG		0x0008
123 #define ZY7_SPI_INTR_DIS_REG		0x000c
124 #define ZY7_SPI_INTR_MASK_REG		0x0010
125 #define   ZY7_SPI_INTR_TX_FIFO_UNDERFLOW	(1 << 6)
126 #define   ZY7_SPI_INTR_RX_FIFO_FULL		(1 << 5)
127 #define   ZY7_SPI_INTR_RX_FIFO_NOT_EMPTY	(1 << 4)
128 #define   ZY7_SPI_INTR_TX_FIFO_FULL		(1 << 3)
129 #define   ZY7_SPI_INTR_TX_FIFO_NOT_FULL		(1 << 2)
130 #define   ZY7_SPI_INTR_MODE_FAULT		(1 << 1)
131 #define   ZY7_SPI_INTR_RX_OVERFLOW		(1 << 0)
132 
133 #define ZY7_SPI_EN_REG			0x0014
134 #define   ZY7_SPI_ENABLE		(1 << 0)
135 
136 #define ZY7_SPI_DELAY_CTRL_REG		0x0018
137 #define   ZY7_SPI_DELAY_CTRL_BTWN_MASK		(0xff << 16)
138 #define   ZY7_SPI_DELAY_CTRL_BTWN_SHIFT		16
139 #define   ZY7_SPI_DELAY_CTRL_AFTER_MASK		(0xff << 8)
140 #define   ZY7_SPI_DELAY_CTRL_AFTER_SHIFT	8
141 #define   ZY7_SPI_DELAY_CTRL_INIT_MASK		(0xff << 0)
142 #define   ZY7_SPI_DELAY_CTRL_INIT_SHIFT		0
143 
144 #define ZY7_SPI_TX_DATA_REG		0x001c
145 #define ZY7_SPI_RX_DATA_REG		0x0020
146 
147 #define ZY7_SPI_SLV_IDLE_COUNT_REG	0x0024
148 
149 #define ZY7_SPI_TX_THRESH_REG		0x0028
150 #define ZY7_SPI_RX_THRESH_REG		0x002c
151 
152 
153 /* Fill hardware fifo with command and data bytes. */
154 static void
155 zy7_spi_write_fifo(struct zy7_spi_softc *sc, int nbytes)
156 {
157 	uint8_t byte;
158 
159 	while (nbytes > 0) {
160 		if (sc->tx_bytes_sent < sc->cmd->tx_cmd_sz)
161 			/* Writing command. */
162 			byte = *((uint8_t *)sc->cmd->tx_cmd +
163 				 sc->tx_bytes_sent);
164 		else
165 			/* Writing data. */
166 			byte = *((uint8_t *)sc->cmd->tx_data +
167 				 (sc->tx_bytes_sent - sc->cmd->tx_cmd_sz));
168 
169 		WR4(sc, ZY7_SPI_TX_DATA_REG, (uint32_t)byte);
170 
171 		sc->tx_bytes_sent++;
172 		nbytes--;
173 	}
174 }
175 
176 
177 /* Read hardware fifo data into command response and data buffers. */
178 static void
179 zy7_spi_read_fifo(struct zy7_spi_softc *sc)
180 {
181 	uint8_t byte;
182 
183 	do {
184 		byte = RD4(sc, ZY7_SPI_RX_DATA_REG) & 0xff;
185 
186 		if (sc->rx_bytes_rcvd < sc->cmd->rx_cmd_sz)
187 			/* Reading command. */
188 			*((uint8_t *)sc->cmd->rx_cmd + sc->rx_bytes_rcvd) =
189 			    byte;
190 		else
191 			/* Reading data. */
192 			*((uint8_t *)sc->cmd->rx_data +
193 			    (sc->rx_bytes_rcvd - sc->cmd->rx_cmd_sz)) =
194 			    byte;
195 
196 		sc->rx_bytes_rcvd++;
197 
198 	} while (sc->rx_bytes_rcvd < sc->rx_bytes &&
199 	    (RD4(sc, ZY7_SPI_INTR_STAT_REG) &
200 		ZY7_SPI_INTR_RX_FIFO_NOT_EMPTY) != 0);
201 }
202 
203 /* End a transfer early by draining rx fifo and disabling interrupts. */
204 static void
205 zy7_spi_abort_transfer(struct zy7_spi_softc *sc)
206 {
207 	/* Drain receive fifo. */
208 	while ((RD4(sc, ZY7_SPI_INTR_STAT_REG) &
209 		ZY7_SPI_INTR_RX_FIFO_NOT_EMPTY) != 0)
210 		(void)RD4(sc, ZY7_SPI_RX_DATA_REG);
211 
212 	/* Shut down interrupts. */
213 	WR4(sc, ZY7_SPI_INTR_DIS_REG,
214 	    ZY7_SPI_INTR_RX_OVERFLOW |
215 	    ZY7_SPI_INTR_RX_FIFO_NOT_EMPTY |
216 	    ZY7_SPI_INTR_TX_FIFO_NOT_FULL);
217 }
218 
219 
220 static void
221 zy7_spi_intr(void *arg)
222 {
223 	struct zy7_spi_softc *sc = (struct zy7_spi_softc *)arg;
224 	uint32_t istatus;
225 
226 	SPI_SC_LOCK(sc);
227 
228 	sc->interrupts++;
229 
230 	istatus = RD4(sc, ZY7_SPI_INTR_STAT_REG);
231 
232 	/* Stray interrupts can happen if a transfer gets interrupted. */
233 	if (!sc->busy) {
234 		sc->stray_ints++;
235 		SPI_SC_UNLOCK(sc);
236 		return;
237 	}
238 
239 	if ((istatus & ZY7_SPI_INTR_RX_OVERFLOW) != 0) {
240 		device_printf(sc->dev, "rx fifo overflow!\n");
241 		sc->rx_overflows++;
242 
243 		/* Clear status bit. */
244 		WR4(sc, ZY7_SPI_INTR_STAT_REG,
245 		    ZY7_SPI_INTR_RX_OVERFLOW);
246 	}
247 
248 	/* Empty receive fifo before any more transmit data is sent. */
249 	if (sc->rx_bytes_rcvd < sc->rx_bytes &&
250 	    (istatus & ZY7_SPI_INTR_RX_FIFO_NOT_EMPTY) != 0) {
251 		zy7_spi_read_fifo(sc);
252 		if (sc->rx_bytes_rcvd == sc->rx_bytes)
253 			/* Disable receive interrupts. */
254 			WR4(sc, ZY7_SPI_INTR_DIS_REG,
255 			    ZY7_SPI_INTR_RX_FIFO_NOT_EMPTY |
256 			    ZY7_SPI_INTR_RX_OVERFLOW);
257 	}
258 
259 	/* Count tx underflows.  They probably shouldn't happen. */
260 	if ((istatus & ZY7_SPI_INTR_TX_FIFO_UNDERFLOW) != 0) {
261 		sc->tx_underflows++;
262 
263 		/* Clear status bit. */
264 		WR4(sc, ZY7_SPI_INTR_STAT_REG,
265 		    ZY7_SPI_INTR_TX_FIFO_UNDERFLOW);
266 	}
267 
268 	/* Fill transmit fifo. */
269 	if (sc->tx_bytes_sent < sc->tx_bytes &&
270 	    (istatus & ZY7_SPI_INTR_TX_FIFO_NOT_FULL) != 0) {
271 		zy7_spi_write_fifo(sc, MIN(96, sc->tx_bytes -
272 			sc->tx_bytes_sent));
273 
274 		if (sc->tx_bytes_sent == sc->tx_bytes) {
275 			/* Disable transmit FIFO interrupt, enable receive
276 			 * FIFO interrupt.
277 			 */
278 			WR4(sc, ZY7_SPI_INTR_DIS_REG,
279 			    ZY7_SPI_INTR_TX_FIFO_NOT_FULL);
280 			WR4(sc, ZY7_SPI_INTR_EN_REG,
281 			    ZY7_SPI_INTR_RX_FIFO_NOT_EMPTY);
282 		}
283 	}
284 
285 	/* Finished with transfer? */
286 	if (sc->tx_bytes_sent == sc->tx_bytes &&
287 	    sc->rx_bytes_rcvd == sc->rx_bytes) {
288 
289 		/* De-assert CS. */
290 		sc->cfg_reg_shadow &=
291 		    ~(ZY7_SPI_CONFIG_CLK_PH | ZY7_SPI_CONFIG_CLK_POL);
292 		sc->cfg_reg_shadow |= ZY7_SPI_CONFIG_CS_MASK;
293 		WR4(sc, ZY7_SPI_CONFIG_REG, sc->cfg_reg_shadow);
294 
295 		wakeup(sc->dev);
296 	}
297 
298 	SPI_SC_UNLOCK(sc);
299 }
300 
301 /* Initialize hardware. */
302 static int
303 zy7_spi_init_hw(struct zy7_spi_softc *sc)
304 {
305 	uint32_t baud_div;
306 
307 	/* Find best clock divider. Divide by 2 not supported. */
308 	baud_div = 1;
309 	while ((sc->ref_clock >> (baud_div + 1)) > sc->spi_clock &&
310 	    baud_div < 8)
311 		baud_div++;
312 	if (baud_div >= 8) {
313 		device_printf(sc->dev, "cannot configure clock divider: ref=%d"
314 		    " spi=%d.\n", sc->ref_clock, sc->spi_clock);
315 		return (EINVAL);
316 	}
317 	sc->spi_clk_real_freq = sc->ref_clock >> (baud_div + 1);
318 
319 	/* Set up configuration register. */
320 	sc->cfg_reg_shadow =
321 	    ZY7_SPI_CONFIG_MAN_CS |
322 	    ZY7_SPI_CONFIG_CS_MASK |
323 	    ZY7_SPI_CONFIG_BAUD_RATE_DIV(baud_div) |
324 	    ZY7_SPI_CONFIG_MODE_SEL;
325 	WR4(sc, ZY7_SPI_CONFIG_REG, sc->cfg_reg_shadow);
326 
327 	/* Set thresholds. */
328 	WR4(sc, ZY7_SPI_TX_THRESH_REG, 32);
329 	WR4(sc, ZY7_SPI_RX_THRESH_REG, 1);
330 
331 	/* Clear and disable all interrupts. */
332 	WR4(sc, ZY7_SPI_INTR_STAT_REG, ~0);
333 	WR4(sc, ZY7_SPI_INTR_DIS_REG, ~0);
334 
335 	/* Enable SPI. */
336 	WR4(sc, ZY7_SPI_EN_REG, ZY7_SPI_ENABLE);
337 
338 	return (0);
339 }
340 
341 
342 static void
343 zy7_spi_add_sysctls(device_t dev)
344 {
345 	struct zy7_spi_softc *sc = device_get_softc(dev);
346 	struct sysctl_ctx_list *ctx;
347 	struct sysctl_oid_list *child;
348 
349 	ctx = device_get_sysctl_ctx(dev);
350 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
351 
352 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "spi_clk_real_freq", CTLFLAG_RD,
353 	    &sc->spi_clk_real_freq, 0, "SPI clock real frequency");
354 
355 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rx_overflows", CTLFLAG_RD,
356 	    &sc->rx_overflows, 0, "RX FIFO overflow events");
357 
358 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_underflows", CTLFLAG_RD,
359 	    &sc->tx_underflows, 0, "TX FIFO underflow events");
360 
361 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "interrupts", CTLFLAG_RD,
362 	    &sc->interrupts, 0, "interrupt calls");
363 
364 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "stray_ints", CTLFLAG_RD,
365 	    &sc->stray_ints, 0, "stray interrupts");
366 }
367 
368 
369 static int
370 zy7_spi_probe(device_t dev)
371 {
372 
373 	if (!ofw_bus_status_okay(dev))
374 		return (ENXIO);
375 
376 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
377 		return (ENXIO);
378 
379 	device_set_desc(dev, "Zynq SPI Controller");
380 
381 	return (BUS_PROBE_DEFAULT);
382 }
383 
384 
385 static int zy7_spi_detach(device_t);
386 
387 static int
388 zy7_spi_attach(device_t dev)
389 {
390 	struct zy7_spi_softc *sc;
391 	int rid, err;
392 	phandle_t node;
393 	pcell_t cell;
394 
395 	sc = device_get_softc(dev);
396 	sc->dev = dev;
397 
398 	SPI_SC_LOCK_INIT(sc);
399 
400 	/* Get ref-clock and spi-clock properties. */
401 	node = ofw_bus_get_node(dev);
402 	if (OF_getprop(node, "ref-clock", &cell, sizeof(cell)) > 0)
403 		sc->ref_clock = fdt32_to_cpu(cell);
404 	else {
405 		device_printf(dev, "must have ref-clock property\n");
406 		return (ENXIO);
407 	}
408 	if (OF_getprop(node, "spi-clock", &cell, sizeof(cell)) > 0)
409 		sc->spi_clock = fdt32_to_cpu(cell);
410 	else
411 		sc->spi_clock = ZY7_SPI_DEFAULT_SPI_CLOCK;
412 
413 	/* Get memory resource. */
414 	rid = 0;
415 	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
416 	    RF_ACTIVE);
417 	if (sc->mem_res == NULL) {
418 		device_printf(dev, "could not allocate memory resources.\n");
419 		zy7_spi_detach(dev);
420 		return (ENOMEM);
421 	}
422 
423 	/* Allocate IRQ. */
424 	rid = 0;
425 	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
426 	    RF_ACTIVE);
427 	if (sc->irq_res == NULL) {
428 		device_printf(dev, "could not allocate IRQ resource.\n");
429 		zy7_spi_detach(dev);
430 		return (ENOMEM);
431 	}
432 
433 	/* Activate the interrupt. */
434 	err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
435 	    NULL, zy7_spi_intr, sc, &sc->intrhandle);
436 	if (err) {
437 		device_printf(dev, "could not setup IRQ.\n");
438 		zy7_spi_detach(dev);
439 		return (err);
440 	}
441 
442 	/* Configure the device. */
443 	err = zy7_spi_init_hw(sc);
444 	if (err) {
445 		zy7_spi_detach(dev);
446 		return (err);
447 	}
448 
449 	sc->child = device_add_child(dev, "spibus", -1);
450 
451 	zy7_spi_add_sysctls(dev);
452 
453 	/* Attach spibus driver as a child later when interrupts work. */
454 	config_intrhook_oneshot((ich_func_t)bus_generic_attach, dev);
455 
456 	return (0);
457 }
458 
459 static int
460 zy7_spi_detach(device_t dev)
461 {
462 	struct zy7_spi_softc *sc = device_get_softc(dev);
463 
464 	if (device_is_attached(dev))
465 		bus_generic_detach(dev);
466 
467 	/* Delete child bus. */
468 	if (sc->child)
469 		device_delete_child(dev, sc->child);
470 
471 	/* Disable hardware. */
472 	if (sc->mem_res != NULL) {
473 		/* Disable SPI. */
474 		WR4(sc, ZY7_SPI_EN_REG, 0);
475 
476 		/* Clear and disable all interrupts. */
477 		WR4(sc, ZY7_SPI_INTR_STAT_REG, ~0);
478 		WR4(sc, ZY7_SPI_INTR_DIS_REG, ~0);
479 	}
480 
481 	/* Teardown and release interrupt. */
482 	if (sc->irq_res != NULL) {
483 		if (sc->intrhandle)
484 			bus_teardown_intr(dev, sc->irq_res, sc->intrhandle);
485 		bus_release_resource(dev, SYS_RES_IRQ,
486 		    rman_get_rid(sc->irq_res), sc->irq_res);
487 	}
488 
489 	/* Release memory resource. */
490 	if (sc->mem_res != NULL)
491 		bus_release_resource(dev, SYS_RES_MEMORY,
492 		    rman_get_rid(sc->mem_res), sc->mem_res);
493 
494 	SPI_SC_LOCK_DESTROY(sc);
495 
496 	return (0);
497 }
498 
499 
500 static phandle_t
501 zy7_spi_get_node(device_t bus, device_t dev)
502 {
503 
504 	return (ofw_bus_get_node(bus));
505 }
506 
507 
508 static int
509 zy7_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
510 {
511 	struct zy7_spi_softc *sc = device_get_softc(dev);
512 	uint32_t cs;
513 	uint32_t mode;
514 	int err = 0;
515 
516 	KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz,
517 	    ("TX/RX command sizes should be equal"));
518 	KASSERT(cmd->tx_data_sz == cmd->rx_data_sz,
519 	    ("TX/RX data sizes should be equal"));
520 
521 	/* Get chip select and mode for this child. */
522 	spibus_get_cs(child, &cs);
523 	cs &= ~SPIBUS_CS_HIGH;
524 	if (cs > 2) {
525 		device_printf(dev, "Invalid chip select %d requested by %s",
526 		    cs, device_get_nameunit(child));
527 		return (EINVAL);
528 	}
529 	spibus_get_mode(child, &mode);
530 
531 	SPI_SC_LOCK(sc);
532 
533 	/* Wait for controller available. */
534 	while (sc->busy != 0) {
535 		err = mtx_sleep(dev, &sc->sc_mtx, 0, "zspi0", 0);
536 		if (err) {
537 			SPI_SC_UNLOCK(sc);
538 			return (err);
539 		}
540 	}
541 
542 	/* Start transfer. */
543 	sc->busy = 1;
544 	sc->cmd = cmd;
545 	sc->tx_bytes = sc->cmd->tx_cmd_sz + sc->cmd->tx_data_sz;
546 	sc->tx_bytes_sent = 0;
547 	sc->rx_bytes = sc->cmd->rx_cmd_sz + sc->cmd->rx_data_sz;
548 	sc->rx_bytes_rcvd = 0;
549 
550 	/* Enable interrupts.  zy7_spi_intr() will handle transfer. */
551 	WR4(sc, ZY7_SPI_INTR_EN_REG,
552 	    ZY7_SPI_INTR_TX_FIFO_NOT_FULL |
553 	    ZY7_SPI_INTR_RX_OVERFLOW);
554 
555 	/* Handle polarity and phase. */
556 	if (mode == SPIBUS_MODE_CPHA || mode == SPIBUS_MODE_CPOL_CPHA)
557 		sc->cfg_reg_shadow |= ZY7_SPI_CONFIG_CLK_PH;
558 	if (mode == SPIBUS_MODE_CPOL || mode == SPIBUS_MODE_CPOL_CPHA)
559 		sc->cfg_reg_shadow |= ZY7_SPI_CONFIG_CLK_POL;
560 
561 	/* Assert CS. */
562 	sc->cfg_reg_shadow &= ~ZY7_SPI_CONFIG_CS_MASK;
563 	sc->cfg_reg_shadow |= ZY7_SPI_CONFIG_CS(cs);
564 	WR4(sc, ZY7_SPI_CONFIG_REG, sc->cfg_reg_shadow);
565 
566 	/* Wait for completion. */
567 	err = mtx_sleep(dev, &sc->sc_mtx, 0, "zspi1", hz * 2);
568 	if (err)
569 		zy7_spi_abort_transfer(sc);
570 
571 	/* Release controller. */
572 	sc->busy = 0;
573 	wakeup_one(dev);
574 
575 	SPI_SC_UNLOCK(sc);
576 
577 	return (err);
578 }
579 
580 static device_method_t zy7_spi_methods[] = {
581 	/* Device interface */
582 	DEVMETHOD(device_probe,		zy7_spi_probe),
583 	DEVMETHOD(device_attach,	zy7_spi_attach),
584 	DEVMETHOD(device_detach,	zy7_spi_detach),
585 
586 	/* SPI interface */
587 	DEVMETHOD(spibus_transfer,	zy7_spi_transfer),
588 
589 	/* ofw_bus interface */
590 	DEVMETHOD(ofw_bus_get_node,	zy7_spi_get_node),
591 
592 	DEVMETHOD_END
593 };
594 
595 
596 static driver_t zy7_spi_driver = {
597 	"zy7_spi",
598 	zy7_spi_methods,
599 	sizeof(struct zy7_spi_softc),
600 };
601 static devclass_t zy7_spi_devclass;
602 
603 DRIVER_MODULE(zy7_spi, simplebus, zy7_spi_driver, zy7_spi_devclass, 0, 0);
604 DRIVER_MODULE(ofw_spibus, zy7_spi, ofw_spibus_driver, ofw_spibus_devclass, 0, 0);
605 SIMPLEBUS_PNP_INFO(compat_data);
606 MODULE_DEPEND(zy7_spi, ofw_spibus, 1, 1, 1);
607