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