]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/xilinx/zy7_spi.c
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / sys / arm / xilinx / zy7_spi.c
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);