]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/broadcom/bcm2835/bcm2835_spi.c
MFV: r361597
[FreeBSD/FreeBSD.git] / sys / arm / broadcom / bcm2835 / bcm2835_spi.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
5  * Copyright (c) 2013 Luiz Otavio O Souza <loos@freebsd.org>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/bus.h>
36
37 #include <sys/kernel.h>
38 #include <sys/module.h>
39 #include <sys/rman.h>
40 #include <sys/lock.h>
41 #include <sys/mutex.h>
42 #include <sys/sysctl.h>
43
44 #include <machine/bus.h>
45 #include <machine/resource.h>
46 #include <machine/intr.h>
47
48 #include <dev/ofw/ofw_bus.h>
49 #include <dev/ofw/ofw_bus_subr.h>
50
51 #include <dev/spibus/spi.h>
52 #include <dev/spibus/spibusvar.h>
53
54 #include <arm/broadcom/bcm2835/bcm2835_spireg.h>
55 #include <arm/broadcom/bcm2835/bcm2835_spivar.h>
56
57 #include "spibus_if.h"
58
59 static struct ofw_compat_data compat_data[] = {
60         {"broadcom,bcm2835-spi",        1},
61         {"brcm,bcm2835-spi",            1},
62         {NULL,                          0}
63 };
64
65 static void bcm_spi_intr(void *);
66
67 #ifdef  BCM_SPI_DEBUG
68 static void
69 bcm_spi_printr(device_t dev)
70 {
71         struct bcm_spi_softc *sc;
72         uint32_t reg;
73
74         sc = device_get_softc(dev);
75         reg = BCM_SPI_READ(sc, SPI_CS);
76         device_printf(dev, "CS=%b\n", reg,
77             "\20\1CS0\2CS1\3CPHA\4CPOL\7CSPOL"
78             "\10TA\11DMAEN\12INTD\13INTR\14ADCS\15REN\16LEN"
79             "\21DONE\22RXD\23TXD\24RXR\25RXF\26CSPOL0\27CSPOL1"
80             "\30CSPOL2\31DMA_LEN\32LEN_LONG");
81         reg = BCM_SPI_READ(sc, SPI_CLK) & SPI_CLK_MASK;
82         if (reg % 2)
83                 reg--;
84         if (reg == 0)
85                 reg = 65536;
86         device_printf(dev, "CLK=%uMhz/%d=%luhz\n",
87             SPI_CORE_CLK / 1000000, reg, SPI_CORE_CLK / reg);
88         reg = BCM_SPI_READ(sc, SPI_DLEN) & SPI_DLEN_MASK;
89         device_printf(dev, "DLEN=%d\n", reg);
90         reg = BCM_SPI_READ(sc, SPI_LTOH) & SPI_LTOH_MASK;
91         device_printf(dev, "LTOH=%d\n", reg);
92         reg = BCM_SPI_READ(sc, SPI_DC);
93         device_printf(dev, "DC=RPANIC=%#x RDREQ=%#x TPANIC=%#x TDREQ=%#x\n",
94             (reg & SPI_DC_RPANIC_MASK) >> SPI_DC_RPANIC_SHIFT,
95             (reg & SPI_DC_RDREQ_MASK) >> SPI_DC_RDREQ_SHIFT,
96             (reg & SPI_DC_TPANIC_MASK) >> SPI_DC_TPANIC_SHIFT,
97             (reg & SPI_DC_TDREQ_MASK) >> SPI_DC_TDREQ_SHIFT);
98 }
99 #endif
100
101 static void
102 bcm_spi_modifyreg(struct bcm_spi_softc *sc, uint32_t off, uint32_t mask,
103         uint32_t value)
104 {
105         uint32_t reg;
106
107         mtx_assert(&sc->sc_mtx, MA_OWNED);
108         reg = BCM_SPI_READ(sc, off);
109         reg &= ~mask;
110         reg |= value;
111         BCM_SPI_WRITE(sc, off, reg);
112 }
113
114 static int
115 bcm_spi_clock_proc(SYSCTL_HANDLER_ARGS)
116 {
117         struct bcm_spi_softc *sc;
118         uint32_t clk;
119         int error;
120
121         sc = (struct bcm_spi_softc *)arg1;
122
123         BCM_SPI_LOCK(sc);
124         clk = BCM_SPI_READ(sc, SPI_CLK);
125         BCM_SPI_UNLOCK(sc);
126         clk &= 0xffff;
127         if (clk == 0)
128                 clk = 65536;
129         clk = SPI_CORE_CLK / clk;
130
131         error = sysctl_handle_int(oidp, &clk, sizeof(clk), req);
132         if (error != 0 || req->newptr == NULL)
133                 return (error);
134
135         return (0);
136 }
137
138 static int
139 bcm_spi_cs_bit_proc(SYSCTL_HANDLER_ARGS, uint32_t bit)
140 {
141         struct bcm_spi_softc *sc;
142         uint32_t reg;
143         int error;
144
145         sc = (struct bcm_spi_softc *)arg1;
146         BCM_SPI_LOCK(sc);
147         reg = BCM_SPI_READ(sc, SPI_CS);
148         BCM_SPI_UNLOCK(sc);
149         reg = (reg & bit) ? 1 : 0;
150
151         error = sysctl_handle_int(oidp, &reg, sizeof(reg), req);
152         if (error != 0 || req->newptr == NULL)
153                 return (error);
154
155         return (0);
156 }
157
158 static int
159 bcm_spi_cpol_proc(SYSCTL_HANDLER_ARGS)
160 {
161
162         return (bcm_spi_cs_bit_proc(oidp, arg1, arg2, req, SPI_CS_CPOL));
163 }
164
165 static int
166 bcm_spi_cpha_proc(SYSCTL_HANDLER_ARGS)
167 {
168
169         return (bcm_spi_cs_bit_proc(oidp, arg1, arg2, req, SPI_CS_CPHA));
170 }
171
172 static int
173 bcm_spi_cspol0_proc(SYSCTL_HANDLER_ARGS)
174 {
175
176         return (bcm_spi_cs_bit_proc(oidp, arg1, arg2, req, SPI_CS_CSPOL0));
177 }
178
179 static int
180 bcm_spi_cspol1_proc(SYSCTL_HANDLER_ARGS)
181 {
182
183         return (bcm_spi_cs_bit_proc(oidp, arg1, arg2, req, SPI_CS_CSPOL1));
184 }
185
186 static int
187 bcm_spi_cspol2_proc(SYSCTL_HANDLER_ARGS)
188 {
189
190         return (bcm_spi_cs_bit_proc(oidp, arg1, arg2, req, SPI_CS_CSPOL2));
191 }
192
193 static void
194 bcm_spi_sysctl_init(struct bcm_spi_softc *sc)
195 {
196         struct sysctl_ctx_list *ctx;
197         struct sysctl_oid *tree_node;
198         struct sysctl_oid_list *tree;
199
200         /*
201          * Add system sysctl tree/handlers.
202          */
203         ctx = device_get_sysctl_ctx(sc->sc_dev);
204         tree_node = device_get_sysctl_tree(sc->sc_dev);
205         tree = SYSCTL_CHILDREN(tree_node);
206         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "clock",
207             CTLFLAG_RD | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, sizeof(*sc),
208             bcm_spi_clock_proc, "IU", "SPI BUS clock frequency");
209         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "cpol",
210             CTLFLAG_RD | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, sizeof(*sc),
211             bcm_spi_cpol_proc, "IU", "SPI BUS clock polarity");
212         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "cpha",
213             CTLFLAG_RD | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, sizeof(*sc),
214             bcm_spi_cpha_proc, "IU", "SPI BUS clock phase");
215         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "cspol0",
216             CTLFLAG_RD | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, sizeof(*sc),
217             bcm_spi_cspol0_proc, "IU", "SPI BUS chip select 0 polarity");
218         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "cspol1",
219             CTLFLAG_RD | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, sizeof(*sc),
220             bcm_spi_cspol1_proc, "IU", "SPI BUS chip select 1 polarity");
221         SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "cspol2",
222             CTLFLAG_RD | CTLTYPE_UINT | CTLFLAG_NEEDGIANT, sc, sizeof(*sc),
223             bcm_spi_cspol2_proc, "IU", "SPI BUS chip select 2 polarity");
224 }
225
226 static int
227 bcm_spi_probe(device_t dev)
228 {
229
230         if (!ofw_bus_status_okay(dev))
231                 return (ENXIO);
232
233         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
234                 return (ENXIO);
235
236         device_set_desc(dev, "BCM2708/2835 SPI controller");
237
238         return (BUS_PROBE_DEFAULT);
239 }
240
241 static int
242 bcm_spi_attach(device_t dev)
243 {
244         struct bcm_spi_softc *sc;
245         int rid;
246
247         if (device_get_unit(dev) != 0) {
248                 device_printf(dev, "only one SPI controller supported\n");
249                 return (ENXIO);
250         }
251
252         sc = device_get_softc(dev);
253         sc->sc_dev = dev;
254
255         rid = 0;
256         sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
257             RF_ACTIVE);
258         if (!sc->sc_mem_res) {
259                 device_printf(dev, "cannot allocate memory window\n");
260                 return (ENXIO);
261         }
262
263         sc->sc_bst = rman_get_bustag(sc->sc_mem_res);
264         sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res);
265
266         rid = 0;
267         sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
268             RF_ACTIVE);
269         if (!sc->sc_irq_res) {
270                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
271                 device_printf(dev, "cannot allocate interrupt\n");
272                 return (ENXIO);
273         }
274
275         /* Hook up our interrupt handler. */
276         if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
277             NULL, bcm_spi_intr, sc, &sc->sc_intrhand)) {
278                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
279                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
280                 device_printf(dev, "cannot setup the interrupt handler\n");
281                 return (ENXIO);
282         }
283
284         mtx_init(&sc->sc_mtx, "bcm_spi", NULL, MTX_DEF);
285
286         /* Add sysctl nodes. */
287         bcm_spi_sysctl_init(sc);
288
289 #ifdef  BCM_SPI_DEBUG
290         bcm_spi_printr(dev);
291 #endif
292
293         /*
294          * Enable the SPI controller.  Clear the rx and tx FIFO.
295          * Defaults to SPI mode 0.
296          */
297         BCM_SPI_WRITE(sc, SPI_CS, SPI_CS_CLEAR_RXFIFO | SPI_CS_CLEAR_TXFIFO);
298
299 #ifdef  BCM_SPI_DEBUG
300         bcm_spi_printr(dev);
301 #endif
302
303         device_add_child(dev, "spibus", -1);
304
305         return (bus_generic_attach(dev));
306 }
307
308 static int
309 bcm_spi_detach(device_t dev)
310 {
311         struct bcm_spi_softc *sc;
312
313         bus_generic_detach(dev);
314
315         sc = device_get_softc(dev);
316         mtx_destroy(&sc->sc_mtx);
317         if (sc->sc_intrhand)
318                 bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand);
319         if (sc->sc_irq_res)
320                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
321         if (sc->sc_mem_res)
322                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
323
324         return (0);
325 }
326
327 static void
328 bcm_spi_fill_fifo(struct bcm_spi_softc *sc)
329 {
330         struct spi_command *cmd;
331         uint32_t cs, written;
332         uint8_t *data;
333
334         cmd = sc->sc_cmd;
335         cs = BCM_SPI_READ(sc, SPI_CS) & (SPI_CS_TA | SPI_CS_TXD);
336         while (sc->sc_written < sc->sc_len &&
337             cs == (SPI_CS_TA | SPI_CS_TXD)) {
338                 data = (uint8_t *)cmd->tx_cmd;
339                 written = sc->sc_written++;
340                 if (written >= cmd->tx_cmd_sz) {
341                         data = (uint8_t *)cmd->tx_data;
342                         written -= cmd->tx_cmd_sz;
343                 }
344                 BCM_SPI_WRITE(sc, SPI_FIFO, data[written]);
345                 cs = BCM_SPI_READ(sc, SPI_CS) & (SPI_CS_TA | SPI_CS_TXD);
346         }
347 }
348
349 static void
350 bcm_spi_drain_fifo(struct bcm_spi_softc *sc)
351 {
352         struct spi_command *cmd;
353         uint32_t cs, read;
354         uint8_t *data;
355
356         cmd = sc->sc_cmd;
357         cs = BCM_SPI_READ(sc, SPI_CS) & SPI_CS_RXD;
358         while (sc->sc_read < sc->sc_len && cs == SPI_CS_RXD) {
359                 data = (uint8_t *)cmd->rx_cmd;
360                 read = sc->sc_read++;
361                 if (read >= cmd->rx_cmd_sz) {
362                         data = (uint8_t *)cmd->rx_data;
363                         read -= cmd->rx_cmd_sz;
364                 }
365                 data[read] = BCM_SPI_READ(sc, SPI_FIFO) & 0xff;
366                 cs = BCM_SPI_READ(sc, SPI_CS) & SPI_CS_RXD;
367         }
368 }
369
370 static void
371 bcm_spi_intr(void *arg)
372 {
373         struct bcm_spi_softc *sc;
374
375         sc = (struct bcm_spi_softc *)arg;
376         BCM_SPI_LOCK(sc);
377
378         /* Filter stray interrupts. */
379         if ((sc->sc_flags & BCM_SPI_BUSY) == 0) {
380                 BCM_SPI_UNLOCK(sc);
381                 return;
382         }
383
384         /* TX - Fill up the FIFO. */
385         bcm_spi_fill_fifo(sc);
386
387         /* RX - Drain the FIFO. */
388         bcm_spi_drain_fifo(sc);
389
390         /* Check for end of transfer. */
391         if (sc->sc_written == sc->sc_len && sc->sc_read == sc->sc_len) {
392                 /* Disable interrupts and the SPI engine. */
393                 bcm_spi_modifyreg(sc, SPI_CS,
394                     SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD, 0);
395                 wakeup(sc->sc_dev);
396         }
397
398         BCM_SPI_UNLOCK(sc);
399 }
400
401 static int
402 bcm_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
403 {
404         struct bcm_spi_softc *sc;
405         uint32_t cs, mode, clock;
406         int err;
407
408         sc = device_get_softc(dev);
409
410         KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz, 
411             ("TX/RX command sizes should be equal"));
412         KASSERT(cmd->tx_data_sz == cmd->rx_data_sz, 
413             ("TX/RX data sizes should be equal"));
414
415         /* Get the bus speed, mode, and chip select for this child. */
416
417         spibus_get_cs(child, &cs);
418         if ((cs & (~SPIBUS_CS_HIGH)) > 2) {
419                 device_printf(dev,
420                     "Invalid chip select %u requested by %s\n", cs,
421                     device_get_nameunit(child));
422                 return (EINVAL);
423         }
424
425         spibus_get_clock(child, &clock);
426         if (clock == 0) {
427                 device_printf(dev,
428                     "Invalid clock %uHz requested by %s\n", clock,
429                     device_get_nameunit(child));
430                 return (EINVAL);
431         }
432
433         spibus_get_mode(child, &mode);
434         if (mode > 3) {
435                 device_printf(dev,
436                     "Invalid mode %u requested by %s\n", mode,
437                     device_get_nameunit(child));
438                 return (EINVAL);
439         }
440
441         /* If the controller is in use wait until it is available. */
442         BCM_SPI_LOCK(sc);
443         while (sc->sc_flags & BCM_SPI_BUSY)
444                 mtx_sleep(dev, &sc->sc_mtx, 0, "bcm_spi", 0);
445
446         /* Now we have control over SPI controller. */
447         sc->sc_flags = BCM_SPI_BUSY;
448
449         /* Clear the FIFO. */
450         bcm_spi_modifyreg(sc, SPI_CS,
451             SPI_CS_CLEAR_RXFIFO | SPI_CS_CLEAR_TXFIFO,
452             SPI_CS_CLEAR_RXFIFO | SPI_CS_CLEAR_TXFIFO);
453
454         /* Save a pointer to the SPI command. */
455         sc->sc_cmd = cmd;
456         sc->sc_read = 0;
457         sc->sc_written = 0;
458         sc->sc_len = cmd->tx_cmd_sz + cmd->tx_data_sz;
459
460 #ifdef  BCM2835_SPI_USE_CS_HIGH /* TODO: for when behavior is correct */
461         /*
462          * Assign CS polarity first, while the CS indicates 'inactive'.
463          * This will need to set the correct polarity bit based on the 'cs', and
464          * the polarity bit will remain in this state, even after the transaction
465          * is complete.
466          */
467         if((cs & ~SPIBUS_CS_HIGH) == 0) {
468                 bcm_spi_modifyreg(sc, SPI_CS,
469                     SPI_CS_CSPOL0,
470                     ((cs & (SPIBUS_CS_HIGH)) ? SPI_CS_CSPOL0 : 0));
471         }
472         else if((cs & ~SPIBUS_CS_HIGH) == 1) {
473                 bcm_spi_modifyreg(sc, SPI_CS,
474                     SPI_CS_CSPOL1,
475                     ((cs & (SPIBUS_CS_HIGH)) ? SPI_CS_CSPOL1 : 0));
476         }
477         else if((cs & ~SPIBUS_CS_HIGH) == 2) {
478                 bcm_spi_modifyreg(sc, SPI_CS,
479                     SPI_CS_CSPOL2,
480                     ((cs & (SPIBUS_CS_HIGH)) ? SPI_CS_CSPOL2 : 0));
481         }
482 #endif
483
484         /*
485          * Set the mode in 'SPI_CS' (clock phase and polarity bits).
486          * This must happen before CS output pin is active.
487          * Otherwise, you might glitch and drop the first bit.
488          */
489         bcm_spi_modifyreg(sc, SPI_CS,
490             SPI_CS_CPOL | SPI_CS_CPHA,
491             ((mode & SPIBUS_MODE_CPHA) ? SPI_CS_CPHA : 0) |
492             ((mode & SPIBUS_MODE_CPOL) ? SPI_CS_CPOL : 0));
493
494         /*
495          * Set the clock divider in 'SPI_CLK - see 'bcm_spi_clock_proc()'.
496          */
497
498         /* calculate 'clock' as a divider value from freq */
499         clock = SPI_CORE_CLK / clock;
500         if (clock <= 1)
501                 clock = 2;
502         else if (clock % 2)
503                 clock--;
504         if (clock > 0xffff)
505                 clock = 0;
506
507         BCM_SPI_WRITE(sc, SPI_CLK, clock);
508
509         /*
510          * Set the CS for this transaction, enable interrupts and announce
511          * we're ready to tx.  This will kick off the first interrupt.
512          */
513         bcm_spi_modifyreg(sc, SPI_CS,
514             SPI_CS_MASK | SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD,
515             (cs & (~SPIBUS_CS_HIGH)) | /* cs is the lower 2 bits of the reg */
516             SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD);
517
518         /* Wait for the transaction to complete. */
519         err = mtx_sleep(dev, &sc->sc_mtx, 0, "bcm_spi", hz * 2);
520
521         /* Make sure the SPI engine and interrupts are disabled. */
522         bcm_spi_modifyreg(sc, SPI_CS, SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD, 0);
523
524         /* Release the controller and wakeup the next thread waiting for it. */
525         sc->sc_flags = 0;
526         wakeup_one(dev);
527         BCM_SPI_UNLOCK(sc);
528
529         /*
530          * Check for transfer timeout.  The SPI controller doesn't
531          * return errors.
532          */
533         if (err == EWOULDBLOCK) {
534                 device_printf(sc->sc_dev, "SPI error (timeout)\n");
535                 err = EIO;
536         }
537
538         return (err);
539 }
540
541 static phandle_t
542 bcm_spi_get_node(device_t bus, device_t dev)
543 {
544
545         /* We only have one child, the SPI bus, which needs our own node. */
546         return (ofw_bus_get_node(bus));
547 }
548
549 static device_method_t bcm_spi_methods[] = {
550         /* Device interface */
551         DEVMETHOD(device_probe,         bcm_spi_probe),
552         DEVMETHOD(device_attach,        bcm_spi_attach),
553         DEVMETHOD(device_detach,        bcm_spi_detach),
554
555         /* SPI interface */
556         DEVMETHOD(spibus_transfer,      bcm_spi_transfer),
557
558         /* ofw_bus interface */
559         DEVMETHOD(ofw_bus_get_node,     bcm_spi_get_node),
560
561         DEVMETHOD_END
562 };
563
564 static devclass_t bcm_spi_devclass;
565
566 static driver_t bcm_spi_driver = {
567         "spi",
568         bcm_spi_methods,
569         sizeof(struct bcm_spi_softc),
570 };
571
572 DRIVER_MODULE(bcm2835_spi, simplebus, bcm_spi_driver, bcm_spi_devclass, 0, 0);