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