xref: /freebsd/sys/arm/freescale/vybrid/vf_spi.c (revision 7073d12c4da0fe9874543aff5ef48a85c99bb507)
12aaaabd4SRuslan Bukin /*-
22aaaabd4SRuslan Bukin  * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
32aaaabd4SRuslan Bukin  * All rights reserved.
42aaaabd4SRuslan Bukin  *
52aaaabd4SRuslan Bukin  * Redistribution and use in source and binary forms, with or without
62aaaabd4SRuslan Bukin  * modification, are permitted provided that the following conditions
72aaaabd4SRuslan Bukin  * are met:
82aaaabd4SRuslan Bukin  * 1. Redistributions of source code must retain the above copyright
92aaaabd4SRuslan Bukin  *    notice, this list of conditions and the following disclaimer.
102aaaabd4SRuslan Bukin  * 2. Redistributions in binary form must reproduce the above copyright
112aaaabd4SRuslan Bukin  *    notice, this list of conditions and the following disclaimer in the
122aaaabd4SRuslan Bukin  *    documentation and/or other materials provided with the distribution.
132aaaabd4SRuslan Bukin  *
142aaaabd4SRuslan Bukin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
152aaaabd4SRuslan Bukin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
162aaaabd4SRuslan Bukin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
172aaaabd4SRuslan Bukin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
182aaaabd4SRuslan Bukin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
192aaaabd4SRuslan Bukin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
202aaaabd4SRuslan Bukin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
212aaaabd4SRuslan Bukin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
222aaaabd4SRuslan Bukin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
232aaaabd4SRuslan Bukin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
242aaaabd4SRuslan Bukin  * SUCH DAMAGE.
252aaaabd4SRuslan Bukin  */
262aaaabd4SRuslan Bukin 
272aaaabd4SRuslan Bukin /*
282aaaabd4SRuslan Bukin  * Vybrid Family Serial Peripheral Interface (SPI)
292aaaabd4SRuslan Bukin  * Chapter 47, Vybrid Reference Manual, Rev. 5, 07/2013
302aaaabd4SRuslan Bukin  */
312aaaabd4SRuslan Bukin 
322aaaabd4SRuslan Bukin #include <sys/cdefs.h>
332aaaabd4SRuslan Bukin __FBSDID("$FreeBSD$");
342aaaabd4SRuslan Bukin 
352aaaabd4SRuslan Bukin #include <sys/param.h>
362aaaabd4SRuslan Bukin #include <sys/systm.h>
372aaaabd4SRuslan Bukin #include <sys/bus.h>
382aaaabd4SRuslan Bukin #include <sys/kernel.h>
392aaaabd4SRuslan Bukin #include <sys/module.h>
402aaaabd4SRuslan Bukin #include <sys/malloc.h>
412aaaabd4SRuslan Bukin #include <sys/rman.h>
422aaaabd4SRuslan Bukin #include <sys/timeet.h>
432aaaabd4SRuslan Bukin #include <sys/timetc.h>
442aaaabd4SRuslan Bukin #include <sys/watchdog.h>
452aaaabd4SRuslan Bukin 
462aaaabd4SRuslan Bukin #include <dev/spibus/spi.h>
472aaaabd4SRuslan Bukin #include <dev/spibus/spibusvar.h>
482aaaabd4SRuslan Bukin 
492aaaabd4SRuslan Bukin #include "spibus_if.h"
502aaaabd4SRuslan Bukin 
512aaaabd4SRuslan Bukin #include <dev/ofw/openfirm.h>
522aaaabd4SRuslan Bukin #include <dev/ofw/ofw_bus.h>
532aaaabd4SRuslan Bukin #include <dev/ofw/ofw_bus_subr.h>
542aaaabd4SRuslan Bukin 
552aaaabd4SRuslan Bukin #include <machine/bus.h>
562aaaabd4SRuslan Bukin #include <machine/cpu.h>
572aaaabd4SRuslan Bukin #include <machine/intr.h>
582aaaabd4SRuslan Bukin 
592aaaabd4SRuslan Bukin #include <arm/freescale/vybrid/vf_common.h>
602aaaabd4SRuslan Bukin 
612aaaabd4SRuslan Bukin #define	SPI_FIFO_SIZE	4
622aaaabd4SRuslan Bukin 
632aaaabd4SRuslan Bukin #define	SPI_MCR		0x00		/* Module Configuration */
642aaaabd4SRuslan Bukin #define	 MCR_MSTR	(1 << 31)	/* Master/Slave Mode Select */
652aaaabd4SRuslan Bukin #define	 MCR_CONT_SCKE	(1 << 30)	/* Continuous SCK Enable */
662aaaabd4SRuslan Bukin #define	 MCR_FRZ	(1 << 27)	/* Freeze */
672aaaabd4SRuslan Bukin #define	 MCR_PCSIS_S	16		/* Peripheral Chip Select */
682aaaabd4SRuslan Bukin #define	 MCR_PCSIS_M	0x3f
692aaaabd4SRuslan Bukin #define	 MCR_MDIS	(1 << 14)	/* Module Disable */
702aaaabd4SRuslan Bukin #define	 MCR_CLR_TXF	(1 << 11)	/* Clear TX FIFO */
712aaaabd4SRuslan Bukin #define	 MCR_CLR_RXF	(1 << 10)	/* Clear RX FIFO */
722aaaabd4SRuslan Bukin #define	 MCR_HALT	(1 << 0)	/* Starts and stops SPI transfers */
732aaaabd4SRuslan Bukin #define	SPI_TCR		0x08		/* Transfer Count */
742aaaabd4SRuslan Bukin #define	SPI_CTAR0	0x0C		/* Clock and Transfer Attributes */
752aaaabd4SRuslan Bukin #define	SPI_CTAR0_SLAVE	0x0C		/* Clock and Transfer Attributes */
762aaaabd4SRuslan Bukin #define	SPI_CTAR1	0x10		/* Clock and Transfer Attributes */
772aaaabd4SRuslan Bukin #define	SPI_CTAR2	0x14		/* Clock and Transfer Attributes */
782aaaabd4SRuslan Bukin #define	SPI_CTAR3	0x18		/* Clock and Transfer Attributes */
792aaaabd4SRuslan Bukin #define	 CTAR_FMSZ_M	0xf
802aaaabd4SRuslan Bukin #define	 CTAR_FMSZ_S	27		/* Frame Size */
812aaaabd4SRuslan Bukin #define	 CTAR_FMSZ_8	0x7		/* 8 bits */
822aaaabd4SRuslan Bukin #define	 CTAR_CPOL	(1 << 26)	/* Clock Polarity */
832aaaabd4SRuslan Bukin #define	 CTAR_CPHA	(1 << 25)	/* Clock Phase */
842aaaabd4SRuslan Bukin #define	 CTAR_LSBFE	(1 << 24)	/* Less significant bit first */
852aaaabd4SRuslan Bukin #define	 CTAR_PCSSCK_M	0x3
862aaaabd4SRuslan Bukin #define	 CTAR_PCSSCK_S	22		/* PCS to SCK Delay Prescaler */
872aaaabd4SRuslan Bukin #define	 CTAR_PBR_M	0x3
882aaaabd4SRuslan Bukin #define	 CTAR_PBR_S	16		/* Baud Rate Prescaler */
892aaaabd4SRuslan Bukin #define	 CTAR_PBR_7	0x3		/* Divide by 7 */
902aaaabd4SRuslan Bukin #define	 CTAR_CSSCK_M	0xf
912aaaabd4SRuslan Bukin #define	 CTAR_CSSCK_S	12		/* PCS to SCK Delay Scaler */
922aaaabd4SRuslan Bukin #define	 CTAR_BR_M	0xf
932aaaabd4SRuslan Bukin #define	 CTAR_BR_S	0		/* Baud Rate Scaler */
942aaaabd4SRuslan Bukin #define	SPI_SR		0x2C		/* Status Register */
952aaaabd4SRuslan Bukin #define	 SR_TCF		(1 << 31)	/* Transfer Complete Flag */
962aaaabd4SRuslan Bukin #define	 SR_EOQF	(1 << 28)	/* End of Queue Flag */
972aaaabd4SRuslan Bukin #define	 SR_TFFF	(1 << 25)	/* Transmit FIFO Fill Flag */
982aaaabd4SRuslan Bukin #define	 SR_RFDF	(1 << 17)	/* Receive FIFO Drain Flag */
992aaaabd4SRuslan Bukin #define	SPI_RSER	0x30		/* DMA/Interrupt Select */
1002aaaabd4SRuslan Bukin #define	 RSER_EOQF_RE	(1 << 28)	/* Finished Request Enable */
1012aaaabd4SRuslan Bukin #define	SPI_PUSHR	0x34		/* PUSH TX FIFO In Master Mode */
1022aaaabd4SRuslan Bukin #define	 PUSHR_CONT	(1 << 31)	/* Continuous Peripheral CS */
1032aaaabd4SRuslan Bukin #define	 PUSHR_EOQ	(1 << 27)	/* End Of Queue */
1042aaaabd4SRuslan Bukin #define	 PUSHR_CTCNT	(1 << 26)	/* Clear Transfer Counter */
1052aaaabd4SRuslan Bukin #define	 PUSHR_PCS_M	0x3f
1062aaaabd4SRuslan Bukin #define	 PUSHR_PCS_S	16		/* Select PCS signals */
1072aaaabd4SRuslan Bukin 
1082aaaabd4SRuslan Bukin #define	SPI_PUSHR_SLAVE	0x34	/* PUSH TX FIFO Register In Slave Mode */
1092aaaabd4SRuslan Bukin #define	SPI_POPR	0x38	/* POP RX FIFO Register */
1102aaaabd4SRuslan Bukin #define	SPI_TXFR0	0x3C	/* Transmit FIFO Registers */
1112aaaabd4SRuslan Bukin #define	SPI_TXFR1	0x40
1122aaaabd4SRuslan Bukin #define	SPI_TXFR2	0x44
1132aaaabd4SRuslan Bukin #define	SPI_TXFR3	0x48
1142aaaabd4SRuslan Bukin #define	SPI_RXFR0	0x7C	/* Receive FIFO Registers */
1152aaaabd4SRuslan Bukin #define	SPI_RXFR1	0x80
1162aaaabd4SRuslan Bukin #define	SPI_RXFR2	0x84
1172aaaabd4SRuslan Bukin #define	SPI_RXFR3	0x88
1182aaaabd4SRuslan Bukin 
1192aaaabd4SRuslan Bukin struct spi_softc {
1202aaaabd4SRuslan Bukin 	struct resource		*res[2];
1212aaaabd4SRuslan Bukin 	bus_space_tag_t		bst;
1222aaaabd4SRuslan Bukin 	bus_space_handle_t	bsh;
1232aaaabd4SRuslan Bukin 	void			*ih;
1242aaaabd4SRuslan Bukin };
1252aaaabd4SRuslan Bukin 
1262aaaabd4SRuslan Bukin static struct resource_spec spi_spec[] = {
1272aaaabd4SRuslan Bukin 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
1282aaaabd4SRuslan Bukin 	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
1292aaaabd4SRuslan Bukin 	{ -1, 0 }
1302aaaabd4SRuslan Bukin };
1312aaaabd4SRuslan Bukin 
1322aaaabd4SRuslan Bukin static int
1332aaaabd4SRuslan Bukin spi_probe(device_t dev)
1342aaaabd4SRuslan Bukin {
1352aaaabd4SRuslan Bukin 
1362aaaabd4SRuslan Bukin 	if (!ofw_bus_status_okay(dev))
1372aaaabd4SRuslan Bukin 		return (ENXIO);
1382aaaabd4SRuslan Bukin 
1392aaaabd4SRuslan Bukin 	if (!ofw_bus_is_compatible(dev, "fsl,mvf600-spi"))
1402aaaabd4SRuslan Bukin 		return (ENXIO);
1412aaaabd4SRuslan Bukin 
1422aaaabd4SRuslan Bukin 	device_set_desc(dev, "Vybrid Family Serial Peripheral Interface");
1432aaaabd4SRuslan Bukin 	return (BUS_PROBE_DEFAULT);
1442aaaabd4SRuslan Bukin }
1452aaaabd4SRuslan Bukin 
1462aaaabd4SRuslan Bukin static int
1472aaaabd4SRuslan Bukin spi_attach(device_t dev)
1482aaaabd4SRuslan Bukin {
1492aaaabd4SRuslan Bukin 	struct spi_softc *sc;
1502aaaabd4SRuslan Bukin 	uint32_t reg;
1512aaaabd4SRuslan Bukin 
1522aaaabd4SRuslan Bukin 	sc = device_get_softc(dev);
1532aaaabd4SRuslan Bukin 
1542aaaabd4SRuslan Bukin 	if (bus_alloc_resources(dev, spi_spec, sc->res)) {
1552aaaabd4SRuslan Bukin 		device_printf(dev, "could not allocate resources\n");
1562aaaabd4SRuslan Bukin 		return (ENXIO);
1572aaaabd4SRuslan Bukin 	}
1582aaaabd4SRuslan Bukin 
1592aaaabd4SRuslan Bukin 	/* Memory interface */
1602aaaabd4SRuslan Bukin 	sc->bst = rman_get_bustag(sc->res[0]);
1612aaaabd4SRuslan Bukin 	sc->bsh = rman_get_bushandle(sc->res[0]);
1622aaaabd4SRuslan Bukin 
1632aaaabd4SRuslan Bukin 	reg = READ4(sc, SPI_MCR);
1642aaaabd4SRuslan Bukin 	reg |= MCR_MSTR;
1652aaaabd4SRuslan Bukin 	reg &= ~(MCR_CONT_SCKE | MCR_MDIS | MCR_FRZ);
1662aaaabd4SRuslan Bukin 	reg &= ~(MCR_PCSIS_M << MCR_PCSIS_S);
1672aaaabd4SRuslan Bukin 	reg |= (MCR_PCSIS_M << MCR_PCSIS_S);	/* PCS Active low */
1682aaaabd4SRuslan Bukin 	reg |= (MCR_CLR_TXF | MCR_CLR_RXF);
1692aaaabd4SRuslan Bukin 	WRITE4(sc, SPI_MCR, reg);
1702aaaabd4SRuslan Bukin 
1712aaaabd4SRuslan Bukin 	reg = READ4(sc, SPI_RSER);
1722aaaabd4SRuslan Bukin 	reg |= RSER_EOQF_RE;
1732aaaabd4SRuslan Bukin 	WRITE4(sc, SPI_RSER, reg);
1742aaaabd4SRuslan Bukin 
1752aaaabd4SRuslan Bukin 	reg = READ4(sc, SPI_MCR);
1762aaaabd4SRuslan Bukin 	reg &= ~MCR_HALT;
1772aaaabd4SRuslan Bukin 	WRITE4(sc, SPI_MCR, reg);
1782aaaabd4SRuslan Bukin 
1792aaaabd4SRuslan Bukin 	reg = READ4(sc, SPI_CTAR0);
1802aaaabd4SRuslan Bukin 	reg &= ~(CTAR_FMSZ_M << CTAR_FMSZ_S);
1812aaaabd4SRuslan Bukin 	reg |= (CTAR_FMSZ_8 << CTAR_FMSZ_S);
1822aaaabd4SRuslan Bukin 	/*
1832aaaabd4SRuslan Bukin 	 * TODO: calculate BR
1842aaaabd4SRuslan Bukin 	 * SCK baud rate = ( fsys / PBR ) * (1 + DBR) / BR
1852aaaabd4SRuslan Bukin 	 *
1862aaaabd4SRuslan Bukin 	 * reg &= ~(CTAR_BR_M << CTAR_BR_S);
1872aaaabd4SRuslan Bukin 	 */
1882aaaabd4SRuslan Bukin 	reg &= ~CTAR_CPOL; /* Polarity */
1892aaaabd4SRuslan Bukin 	reg |= CTAR_CPHA;
1902aaaabd4SRuslan Bukin 	/*
1912aaaabd4SRuslan Bukin 	 * Set LSB (Less significant bit first)
1922aaaabd4SRuslan Bukin 	 * must be used for some applications, e.g. some LCDs
1932aaaabd4SRuslan Bukin 	 */
1942aaaabd4SRuslan Bukin 	reg |= CTAR_LSBFE;
1952aaaabd4SRuslan Bukin 	WRITE4(sc, SPI_CTAR0, reg);
1962aaaabd4SRuslan Bukin 
1972aaaabd4SRuslan Bukin 	reg = READ4(sc, SPI_CTAR0);
1982aaaabd4SRuslan Bukin 	reg &= ~(CTAR_PBR_M << CTAR_PBR_S);
1992aaaabd4SRuslan Bukin 	reg |= (CTAR_PBR_7 << CTAR_PBR_S);
2002aaaabd4SRuslan Bukin 	WRITE4(sc, SPI_CTAR0, reg);
2012aaaabd4SRuslan Bukin 
2022aaaabd4SRuslan Bukin 	device_add_child(dev, "spibus", 0);
2032aaaabd4SRuslan Bukin 	return (bus_generic_attach(dev));
2042aaaabd4SRuslan Bukin }
2052aaaabd4SRuslan Bukin 
2062aaaabd4SRuslan Bukin static int
2072aaaabd4SRuslan Bukin spi_txrx(struct spi_softc *sc, uint8_t *out_buf,
2082aaaabd4SRuslan Bukin     uint8_t *in_buf, int bufsz, int cs)
2092aaaabd4SRuslan Bukin {
2102aaaabd4SRuslan Bukin 	uint32_t reg, wreg;
2112aaaabd4SRuslan Bukin 	uint32_t txcnt;
2122aaaabd4SRuslan Bukin 	uint32_t i;
2132aaaabd4SRuslan Bukin 
2142aaaabd4SRuslan Bukin 	txcnt = 0;
2152aaaabd4SRuslan Bukin 
2162aaaabd4SRuslan Bukin 	for (i = 0; i < bufsz; i++) {
2172aaaabd4SRuslan Bukin 		txcnt++;
2182aaaabd4SRuslan Bukin 		wreg = out_buf[i];
2192aaaabd4SRuslan Bukin 		wreg |= PUSHR_CONT;
2202aaaabd4SRuslan Bukin 		wreg |= (cs << PUSHR_PCS_S);
2212aaaabd4SRuslan Bukin 		if (i == 0)
2222aaaabd4SRuslan Bukin 			wreg |= PUSHR_CTCNT;
2232aaaabd4SRuslan Bukin 		if (i == (bufsz - 1) || txcnt == SPI_FIFO_SIZE)
2242aaaabd4SRuslan Bukin 			wreg |= PUSHR_EOQ;
2252aaaabd4SRuslan Bukin 		WRITE4(sc, SPI_PUSHR, wreg);
2262aaaabd4SRuslan Bukin 
2272aaaabd4SRuslan Bukin 		if (i == (bufsz - 1) || txcnt == SPI_FIFO_SIZE) {
2282aaaabd4SRuslan Bukin 			txcnt = 0;
2292aaaabd4SRuslan Bukin 
2302aaaabd4SRuslan Bukin 			/* Wait last entry in a queue to be transmitted */
2312aaaabd4SRuslan Bukin 			while((READ4(sc, SPI_SR) & SR_EOQF) == 0)
2322aaaabd4SRuslan Bukin 				continue;
2332aaaabd4SRuslan Bukin 
2342aaaabd4SRuslan Bukin 			reg = READ4(sc, SPI_SR);
2352aaaabd4SRuslan Bukin 			reg |= (SR_TCF | SR_EOQF);
2362aaaabd4SRuslan Bukin 			WRITE4(sc, SPI_SR, reg);
2372aaaabd4SRuslan Bukin 		}
2382aaaabd4SRuslan Bukin 
2392aaaabd4SRuslan Bukin 		/* Wait until RX FIFO is empty */
2402aaaabd4SRuslan Bukin 		while((READ4(sc, SPI_SR) & SR_RFDF) == 0)
2412aaaabd4SRuslan Bukin 			continue;
2422aaaabd4SRuslan Bukin 
2432aaaabd4SRuslan Bukin 		in_buf[i] = READ1(sc, SPI_POPR);
2442aaaabd4SRuslan Bukin 	}
2452aaaabd4SRuslan Bukin 
2462aaaabd4SRuslan Bukin 	return (0);
2472aaaabd4SRuslan Bukin }
2482aaaabd4SRuslan Bukin 
2492aaaabd4SRuslan Bukin static int
2502aaaabd4SRuslan Bukin spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
2512aaaabd4SRuslan Bukin {
2522aaaabd4SRuslan Bukin 	struct spi_softc *sc;
2532aaaabd4SRuslan Bukin 	uint32_t cs;
2542aaaabd4SRuslan Bukin 
2552aaaabd4SRuslan Bukin 	sc = device_get_softc(dev);
2562aaaabd4SRuslan Bukin 
2572aaaabd4SRuslan Bukin 	KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz,
2582aaaabd4SRuslan Bukin 	    ("%s: TX/RX command sizes should be equal", __func__));
2592aaaabd4SRuslan Bukin 	KASSERT(cmd->tx_data_sz == cmd->rx_data_sz,
2602aaaabd4SRuslan Bukin 	    ("%s: TX/RX data sizes should be equal", __func__));
2612aaaabd4SRuslan Bukin 
2622aaaabd4SRuslan Bukin 	/* get the proper chip select */
2632aaaabd4SRuslan Bukin 	spibus_get_cs(child, &cs);
2642aaaabd4SRuslan Bukin 
265*7073d12cSEmmanuel Vadot 	cs &= ~SPIBUS_CS_HIGH;
266*7073d12cSEmmanuel Vadot 
2672aaaabd4SRuslan Bukin 	/* Command */
2682aaaabd4SRuslan Bukin 	spi_txrx(sc, cmd->tx_cmd, cmd->rx_cmd, cmd->tx_cmd_sz, cs);
2692aaaabd4SRuslan Bukin 
2702aaaabd4SRuslan Bukin 	/* Data */
2712aaaabd4SRuslan Bukin 	spi_txrx(sc, cmd->tx_data, cmd->rx_data, cmd->tx_data_sz, cs);
2722aaaabd4SRuslan Bukin 
2732aaaabd4SRuslan Bukin 	return (0);
2742aaaabd4SRuslan Bukin }
2752aaaabd4SRuslan Bukin 
2762aaaabd4SRuslan Bukin static device_method_t spi_methods[] = {
2772aaaabd4SRuslan Bukin 	/* Device interface */
2782aaaabd4SRuslan Bukin 	DEVMETHOD(device_probe,		spi_probe),
2792aaaabd4SRuslan Bukin 	DEVMETHOD(device_attach,	spi_attach),
2802aaaabd4SRuslan Bukin 	/* SPI interface */
2812aaaabd4SRuslan Bukin 	DEVMETHOD(spibus_transfer,	spi_transfer),
2822aaaabd4SRuslan Bukin 	{ 0, 0 }
2832aaaabd4SRuslan Bukin };
2842aaaabd4SRuslan Bukin 
2852aaaabd4SRuslan Bukin static driver_t spi_driver = {
2862aaaabd4SRuslan Bukin 	"spi",
2872aaaabd4SRuslan Bukin 	spi_methods,
2882aaaabd4SRuslan Bukin 	sizeof(struct spi_softc),
2892aaaabd4SRuslan Bukin };
2902aaaabd4SRuslan Bukin 
2912aaaabd4SRuslan Bukin static devclass_t spi_devclass;
2922aaaabd4SRuslan Bukin 
2932aaaabd4SRuslan Bukin DRIVER_MODULE(spi, simplebus, spi_driver, spi_devclass, 0, 0);
294