xref: /freebsd/sys/arm/xilinx/zy7_spi.c (revision 64d1a02e4e1a5f561d03b2bbc9c20dad255e79e8)
13f9309e5SEmmanuel Vadot /*-
23f9309e5SEmmanuel Vadot  * Copyright (c) 2018 Thomas Skibo <thomasskibo@yahoo.com>
33f9309e5SEmmanuel Vadot  * All rights reserved.
43f9309e5SEmmanuel Vadot  *
53f9309e5SEmmanuel Vadot  * Redistribution and use in source and binary forms, with or without
63f9309e5SEmmanuel Vadot  * modification, are permitted provided that the following conditions
73f9309e5SEmmanuel Vadot  * are met:
83f9309e5SEmmanuel Vadot  * 1. Redistributions of source code must retain the above copyright
93f9309e5SEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer.
103f9309e5SEmmanuel Vadot  * 2. Redistributions in binary form must reproduce the above copyright
113f9309e5SEmmanuel Vadot  *    notice, this list of conditions and the following disclaimer in the
123f9309e5SEmmanuel Vadot  *    documentation and/or other materials provided with the distribution.
133f9309e5SEmmanuel Vadot  *
143f9309e5SEmmanuel Vadot  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
153f9309e5SEmmanuel Vadot  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
163f9309e5SEmmanuel Vadot  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
173f9309e5SEmmanuel Vadot  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
183f9309e5SEmmanuel Vadot  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
193f9309e5SEmmanuel Vadot  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
203f9309e5SEmmanuel Vadot  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
213f9309e5SEmmanuel Vadot  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
223f9309e5SEmmanuel Vadot  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
233f9309e5SEmmanuel Vadot  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
243f9309e5SEmmanuel Vadot  * SUCH DAMAGE.
253f9309e5SEmmanuel Vadot  */
263f9309e5SEmmanuel Vadot 
273f9309e5SEmmanuel Vadot #include <sys/param.h>
283f9309e5SEmmanuel Vadot #include <sys/systm.h>
293f9309e5SEmmanuel Vadot #include <sys/conf.h>
303f9309e5SEmmanuel Vadot #include <sys/kernel.h>
313f9309e5SEmmanuel Vadot #include <sys/module.h>
323f9309e5SEmmanuel Vadot #include <sys/sysctl.h>
333f9309e5SEmmanuel Vadot #include <sys/lock.h>
343f9309e5SEmmanuel Vadot #include <sys/mutex.h>
353f9309e5SEmmanuel Vadot #include <sys/resource.h>
363f9309e5SEmmanuel Vadot #include <sys/rman.h>
373f9309e5SEmmanuel Vadot #include <sys/uio.h>
383f9309e5SEmmanuel Vadot 
393f9309e5SEmmanuel Vadot #include <machine/bus.h>
403f9309e5SEmmanuel Vadot #include <machine/resource.h>
413f9309e5SEmmanuel Vadot #include <machine/stdarg.h>
423f9309e5SEmmanuel Vadot 
433f9309e5SEmmanuel Vadot #include <dev/fdt/fdt_common.h>
443f9309e5SEmmanuel Vadot #include <dev/ofw/ofw_bus.h>
453f9309e5SEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h>
463f9309e5SEmmanuel Vadot 
473f9309e5SEmmanuel Vadot #include <dev/spibus/spi.h>
483f9309e5SEmmanuel Vadot #include <dev/spibus/spibusvar.h>
493f9309e5SEmmanuel Vadot 
503f9309e5SEmmanuel Vadot #include "spibus_if.h"
513f9309e5SEmmanuel Vadot 
523f9309e5SEmmanuel Vadot static struct ofw_compat_data compat_data[] = {
533f9309e5SEmmanuel Vadot 	{"xlnx,zy7_spi",		1},
543f9309e5SEmmanuel Vadot 	{"xlnx,zynq-spi-1.0",		1},
553f9309e5SEmmanuel Vadot 	{"cdns,spi-r1p6",		1},
563f9309e5SEmmanuel Vadot 	{NULL,				0}
573f9309e5SEmmanuel Vadot };
583f9309e5SEmmanuel Vadot 
593f9309e5SEmmanuel Vadot struct zy7_spi_softc {
603f9309e5SEmmanuel Vadot 	device_t		dev;
613f9309e5SEmmanuel Vadot 	device_t		child;
623f9309e5SEmmanuel Vadot 	struct mtx		sc_mtx;
633f9309e5SEmmanuel Vadot 	struct resource		*mem_res;
643f9309e5SEmmanuel Vadot 	struct resource		*irq_res;
653f9309e5SEmmanuel Vadot 	void			*intrhandle;
663f9309e5SEmmanuel Vadot 
673f9309e5SEmmanuel Vadot 	uint32_t		cfg_reg_shadow;
683f9309e5SEmmanuel Vadot 	uint32_t		spi_clock;
693f9309e5SEmmanuel Vadot 	uint32_t		ref_clock;
703f9309e5SEmmanuel Vadot 	unsigned int		spi_clk_real_freq;
713f9309e5SEmmanuel Vadot 	unsigned int		rx_overflows;
723f9309e5SEmmanuel Vadot 	unsigned int		tx_underflows;
733f9309e5SEmmanuel Vadot 	unsigned int		interrupts;
743f9309e5SEmmanuel Vadot 	unsigned int		stray_ints;
753f9309e5SEmmanuel Vadot 	struct spi_command	*cmd;
763f9309e5SEmmanuel Vadot 	int			tx_bytes;	/* tx_cmd_sz + tx_data_sz */
773f9309e5SEmmanuel Vadot 	int			tx_bytes_sent;
783f9309e5SEmmanuel Vadot 	int			rx_bytes;	/* rx_cmd_sz + rx_data_sz */
793f9309e5SEmmanuel Vadot 	int			rx_bytes_rcvd;
803f9309e5SEmmanuel Vadot 	int			busy;
813f9309e5SEmmanuel Vadot };
823f9309e5SEmmanuel Vadot 
833f9309e5SEmmanuel Vadot #define ZY7_SPI_DEFAULT_SPI_CLOCK	50000000
843f9309e5SEmmanuel Vadot 
853f9309e5SEmmanuel Vadot #define SPI_SC_LOCK(sc)		mtx_lock(&(sc)->sc_mtx)
863f9309e5SEmmanuel Vadot #define	SPI_SC_UNLOCK(sc)		mtx_unlock(&(sc)->sc_mtx)
873f9309e5SEmmanuel Vadot #define SPI_SC_LOCK_INIT(sc) \
883f9309e5SEmmanuel Vadot 	mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev),	NULL, MTX_DEF)
893f9309e5SEmmanuel Vadot #define SPI_SC_LOCK_DESTROY(sc)	mtx_destroy(&(sc)->sc_mtx)
903f9309e5SEmmanuel Vadot #define SPI_SC_ASSERT_LOCKED(sc)	mtx_assert(&(sc)->sc_mtx, MA_OWNED)
913f9309e5SEmmanuel Vadot 
923f9309e5SEmmanuel Vadot #define RD4(sc, off)		(bus_read_4((sc)->mem_res, (off)))
933f9309e5SEmmanuel Vadot #define WR4(sc, off, val)	(bus_write_4((sc)->mem_res, (off), (val)))
943f9309e5SEmmanuel Vadot 
953f9309e5SEmmanuel Vadot /*
963f9309e5SEmmanuel Vadot  * SPI device registers.
973f9309e5SEmmanuel Vadot  * Reference: Zynq-7000 All Programmable SoC Technical Reference Manual.
983f9309e5SEmmanuel Vadot  * (v1.12.1) December 6, 2017.  Xilinx doc UG585.
993f9309e5SEmmanuel Vadot  */
1003f9309e5SEmmanuel Vadot #define ZY7_SPI_CONFIG_REG		0x0000
1013f9309e5SEmmanuel Vadot #define   ZY7_SPI_CONFIG_MODEFAIL_GEN_EN	(1 << 17)
1023f9309e5SEmmanuel Vadot #define   ZY7_SPI_CONFIG_MAN_STRT		(1 << 16)
1033f9309e5SEmmanuel Vadot #define   ZY7_SPI_CONFIG_MAN_STRT_EN		(1 << 15)
1043f9309e5SEmmanuel Vadot #define   ZY7_SPI_CONFIG_MAN_CS			(1 << 14)
1053f9309e5SEmmanuel Vadot #define   ZY7_SPI_CONFIG_CS_MASK		(0xf << 10)
1063f9309e5SEmmanuel Vadot #define   ZY7_SPI_CONFIG_CS(x)			((0xf ^ (1 << (x))) << 10)
1073f9309e5SEmmanuel Vadot #define   ZY7_SPI_CONFIG_PERI_SEL		(1 << 9)
1083f9309e5SEmmanuel Vadot #define   ZY7_SPI_CONFIG_REF_CLK		(1 << 8)
1093f9309e5SEmmanuel Vadot #define   ZY7_SPI_CONFIG_BAUD_RATE_DIV_MASK	(7 << 3)
1103f9309e5SEmmanuel Vadot #define   ZY7_SPI_CONFIG_BAUD_RATE_DIV_SHIFT	3
1113f9309e5SEmmanuel Vadot #define   ZY7_SPI_CONFIG_BAUD_RATE_DIV(x)	((x) << 3) /* divide by 2<<x */
1123f9309e5SEmmanuel Vadot #define   ZY7_SPI_CONFIG_CLK_PH			(1 << 2)   /* clock phase */
1133f9309e5SEmmanuel Vadot #define   ZY7_SPI_CONFIG_CLK_POL		(1 << 1)   /* clock polatiry */
1143f9309e5SEmmanuel Vadot #define   ZY7_SPI_CONFIG_MODE_SEL		(1 << 0)   /* master enable */
1153f9309e5SEmmanuel Vadot 
1163f9309e5SEmmanuel Vadot #define ZY7_SPI_INTR_STAT_REG		0x0004
1173f9309e5SEmmanuel Vadot #define ZY7_SPI_INTR_EN_REG		0x0008
1183f9309e5SEmmanuel Vadot #define ZY7_SPI_INTR_DIS_REG		0x000c
1193f9309e5SEmmanuel Vadot #define ZY7_SPI_INTR_MASK_REG		0x0010
1203f9309e5SEmmanuel Vadot #define   ZY7_SPI_INTR_TX_FIFO_UNDERFLOW	(1 << 6)
1213f9309e5SEmmanuel Vadot #define   ZY7_SPI_INTR_RX_FIFO_FULL		(1 << 5)
1223f9309e5SEmmanuel Vadot #define   ZY7_SPI_INTR_RX_FIFO_NOT_EMPTY	(1 << 4)
1233f9309e5SEmmanuel Vadot #define   ZY7_SPI_INTR_TX_FIFO_FULL		(1 << 3)
1243f9309e5SEmmanuel Vadot #define   ZY7_SPI_INTR_TX_FIFO_NOT_FULL		(1 << 2)
1253f9309e5SEmmanuel Vadot #define   ZY7_SPI_INTR_MODE_FAULT		(1 << 1)
1263f9309e5SEmmanuel Vadot #define   ZY7_SPI_INTR_RX_OVERFLOW		(1 << 0)
1273f9309e5SEmmanuel Vadot 
1283f9309e5SEmmanuel Vadot #define ZY7_SPI_EN_REG			0x0014
1293f9309e5SEmmanuel Vadot #define   ZY7_SPI_ENABLE		(1 << 0)
1303f9309e5SEmmanuel Vadot 
1313f9309e5SEmmanuel Vadot #define ZY7_SPI_DELAY_CTRL_REG		0x0018
1323f9309e5SEmmanuel Vadot #define   ZY7_SPI_DELAY_CTRL_BTWN_MASK		(0xff << 16)
1333f9309e5SEmmanuel Vadot #define   ZY7_SPI_DELAY_CTRL_BTWN_SHIFT		16
1343f9309e5SEmmanuel Vadot #define   ZY7_SPI_DELAY_CTRL_AFTER_MASK		(0xff << 8)
1353f9309e5SEmmanuel Vadot #define   ZY7_SPI_DELAY_CTRL_AFTER_SHIFT	8
1363f9309e5SEmmanuel Vadot #define   ZY7_SPI_DELAY_CTRL_INIT_MASK		(0xff << 0)
1373f9309e5SEmmanuel Vadot #define   ZY7_SPI_DELAY_CTRL_INIT_SHIFT		0
1383f9309e5SEmmanuel Vadot 
1393f9309e5SEmmanuel Vadot #define ZY7_SPI_TX_DATA_REG		0x001c
1403f9309e5SEmmanuel Vadot #define ZY7_SPI_RX_DATA_REG		0x0020
1413f9309e5SEmmanuel Vadot 
1423f9309e5SEmmanuel Vadot #define ZY7_SPI_SLV_IDLE_COUNT_REG	0x0024
1433f9309e5SEmmanuel Vadot 
1443f9309e5SEmmanuel Vadot #define ZY7_SPI_TX_THRESH_REG		0x0028
1453f9309e5SEmmanuel Vadot #define ZY7_SPI_RX_THRESH_REG		0x002c
1463f9309e5SEmmanuel Vadot 
1473f9309e5SEmmanuel Vadot /* Fill hardware fifo with command and data bytes. */
1483f9309e5SEmmanuel Vadot static void
zy7_spi_write_fifo(struct zy7_spi_softc * sc,int nbytes)1493f9309e5SEmmanuel Vadot zy7_spi_write_fifo(struct zy7_spi_softc *sc, int nbytes)
1503f9309e5SEmmanuel Vadot {
1513f9309e5SEmmanuel Vadot 	uint8_t byte;
1523f9309e5SEmmanuel Vadot 
1533f9309e5SEmmanuel Vadot 	while (nbytes > 0) {
1543f9309e5SEmmanuel Vadot 		if (sc->tx_bytes_sent < sc->cmd->tx_cmd_sz)
1553f9309e5SEmmanuel Vadot 			/* Writing command. */
1563f9309e5SEmmanuel Vadot 			byte = *((uint8_t *)sc->cmd->tx_cmd +
1573f9309e5SEmmanuel Vadot 				 sc->tx_bytes_sent);
1583f9309e5SEmmanuel Vadot 		else
1593f9309e5SEmmanuel Vadot 			/* Writing data. */
1603f9309e5SEmmanuel Vadot 			byte = *((uint8_t *)sc->cmd->tx_data +
1613f9309e5SEmmanuel Vadot 				 (sc->tx_bytes_sent - sc->cmd->tx_cmd_sz));
1623f9309e5SEmmanuel Vadot 
1633f9309e5SEmmanuel Vadot 		WR4(sc, ZY7_SPI_TX_DATA_REG, (uint32_t)byte);
1643f9309e5SEmmanuel Vadot 
1653f9309e5SEmmanuel Vadot 		sc->tx_bytes_sent++;
1663f9309e5SEmmanuel Vadot 		nbytes--;
1673f9309e5SEmmanuel Vadot 	}
1683f9309e5SEmmanuel Vadot }
1693f9309e5SEmmanuel Vadot 
1703f9309e5SEmmanuel Vadot /* Read hardware fifo data into command response and data buffers. */
1713f9309e5SEmmanuel Vadot static void
zy7_spi_read_fifo(struct zy7_spi_softc * sc)1723f9309e5SEmmanuel Vadot zy7_spi_read_fifo(struct zy7_spi_softc *sc)
1733f9309e5SEmmanuel Vadot {
1743f9309e5SEmmanuel Vadot 	uint8_t byte;
1753f9309e5SEmmanuel Vadot 
1763f9309e5SEmmanuel Vadot 	do {
1773f9309e5SEmmanuel Vadot 		byte = RD4(sc, ZY7_SPI_RX_DATA_REG) & 0xff;
1783f9309e5SEmmanuel Vadot 
1793f9309e5SEmmanuel Vadot 		if (sc->rx_bytes_rcvd < sc->cmd->rx_cmd_sz)
1803f9309e5SEmmanuel Vadot 			/* Reading command. */
1813f9309e5SEmmanuel Vadot 			*((uint8_t *)sc->cmd->rx_cmd + sc->rx_bytes_rcvd) =
1823f9309e5SEmmanuel Vadot 			    byte;
1833f9309e5SEmmanuel Vadot 		else
1843f9309e5SEmmanuel Vadot 			/* Reading data. */
1853f9309e5SEmmanuel Vadot 			*((uint8_t *)sc->cmd->rx_data +
1863f9309e5SEmmanuel Vadot 			    (sc->rx_bytes_rcvd - sc->cmd->rx_cmd_sz)) =
1873f9309e5SEmmanuel Vadot 			    byte;
1883f9309e5SEmmanuel Vadot 
1893f9309e5SEmmanuel Vadot 		sc->rx_bytes_rcvd++;
1903f9309e5SEmmanuel Vadot 
1913f9309e5SEmmanuel Vadot 	} while (sc->rx_bytes_rcvd < sc->rx_bytes &&
1923f9309e5SEmmanuel Vadot 	    (RD4(sc, ZY7_SPI_INTR_STAT_REG) &
1933f9309e5SEmmanuel Vadot 		ZY7_SPI_INTR_RX_FIFO_NOT_EMPTY) != 0);
1943f9309e5SEmmanuel Vadot }
1953f9309e5SEmmanuel Vadot 
1963f9309e5SEmmanuel Vadot /* End a transfer early by draining rx fifo and disabling interrupts. */
1973f9309e5SEmmanuel Vadot static void
zy7_spi_abort_transfer(struct zy7_spi_softc * sc)1983f9309e5SEmmanuel Vadot zy7_spi_abort_transfer(struct zy7_spi_softc *sc)
1993f9309e5SEmmanuel Vadot {
2003f9309e5SEmmanuel Vadot 	/* Drain receive fifo. */
2013f9309e5SEmmanuel Vadot 	while ((RD4(sc, ZY7_SPI_INTR_STAT_REG) &
2023f9309e5SEmmanuel Vadot 		ZY7_SPI_INTR_RX_FIFO_NOT_EMPTY) != 0)
2033f9309e5SEmmanuel Vadot 		(void)RD4(sc, ZY7_SPI_RX_DATA_REG);
2043f9309e5SEmmanuel Vadot 
2053f9309e5SEmmanuel Vadot 	/* Shut down interrupts. */
2063f9309e5SEmmanuel Vadot 	WR4(sc, ZY7_SPI_INTR_DIS_REG,
2073f9309e5SEmmanuel Vadot 	    ZY7_SPI_INTR_RX_OVERFLOW |
2083f9309e5SEmmanuel Vadot 	    ZY7_SPI_INTR_RX_FIFO_NOT_EMPTY |
2093f9309e5SEmmanuel Vadot 	    ZY7_SPI_INTR_TX_FIFO_NOT_FULL);
2103f9309e5SEmmanuel Vadot }
2113f9309e5SEmmanuel Vadot 
2123f9309e5SEmmanuel Vadot static void
zy7_spi_intr(void * arg)2133f9309e5SEmmanuel Vadot zy7_spi_intr(void *arg)
2143f9309e5SEmmanuel Vadot {
2153f9309e5SEmmanuel Vadot 	struct zy7_spi_softc *sc = (struct zy7_spi_softc *)arg;
2163f9309e5SEmmanuel Vadot 	uint32_t istatus;
2173f9309e5SEmmanuel Vadot 
2183f9309e5SEmmanuel Vadot 	SPI_SC_LOCK(sc);
2193f9309e5SEmmanuel Vadot 
2203f9309e5SEmmanuel Vadot 	sc->interrupts++;
2213f9309e5SEmmanuel Vadot 
2223f9309e5SEmmanuel Vadot 	istatus = RD4(sc, ZY7_SPI_INTR_STAT_REG);
2233f9309e5SEmmanuel Vadot 
2243f9309e5SEmmanuel Vadot 	/* Stray interrupts can happen if a transfer gets interrupted. */
2253f9309e5SEmmanuel Vadot 	if (!sc->busy) {
2263f9309e5SEmmanuel Vadot 		sc->stray_ints++;
2273f9309e5SEmmanuel Vadot 		SPI_SC_UNLOCK(sc);
2283f9309e5SEmmanuel Vadot 		return;
2293f9309e5SEmmanuel Vadot 	}
2303f9309e5SEmmanuel Vadot 
2313f9309e5SEmmanuel Vadot 	if ((istatus & ZY7_SPI_INTR_RX_OVERFLOW) != 0) {
2323f9309e5SEmmanuel Vadot 		device_printf(sc->dev, "rx fifo overflow!\n");
2333f9309e5SEmmanuel Vadot 		sc->rx_overflows++;
2343f9309e5SEmmanuel Vadot 
2353f9309e5SEmmanuel Vadot 		/* Clear status bit. */
2363f9309e5SEmmanuel Vadot 		WR4(sc, ZY7_SPI_INTR_STAT_REG,
2373f9309e5SEmmanuel Vadot 		    ZY7_SPI_INTR_RX_OVERFLOW);
2383f9309e5SEmmanuel Vadot 	}
2393f9309e5SEmmanuel Vadot 
2403f9309e5SEmmanuel Vadot 	/* Empty receive fifo before any more transmit data is sent. */
2413f9309e5SEmmanuel Vadot 	if (sc->rx_bytes_rcvd < sc->rx_bytes &&
2423f9309e5SEmmanuel Vadot 	    (istatus & ZY7_SPI_INTR_RX_FIFO_NOT_EMPTY) != 0) {
2433f9309e5SEmmanuel Vadot 		zy7_spi_read_fifo(sc);
2443f9309e5SEmmanuel Vadot 		if (sc->rx_bytes_rcvd == sc->rx_bytes)
2453f9309e5SEmmanuel Vadot 			/* Disable receive interrupts. */
2463f9309e5SEmmanuel Vadot 			WR4(sc, ZY7_SPI_INTR_DIS_REG,
2473f9309e5SEmmanuel Vadot 			    ZY7_SPI_INTR_RX_FIFO_NOT_EMPTY |
2483f9309e5SEmmanuel Vadot 			    ZY7_SPI_INTR_RX_OVERFLOW);
2493f9309e5SEmmanuel Vadot 	}
2503f9309e5SEmmanuel Vadot 
2513f9309e5SEmmanuel Vadot 	/* Count tx underflows.  They probably shouldn't happen. */
2523f9309e5SEmmanuel Vadot 	if ((istatus & ZY7_SPI_INTR_TX_FIFO_UNDERFLOW) != 0) {
2533f9309e5SEmmanuel Vadot 		sc->tx_underflows++;
2543f9309e5SEmmanuel Vadot 
2553f9309e5SEmmanuel Vadot 		/* Clear status bit. */
2563f9309e5SEmmanuel Vadot 		WR4(sc, ZY7_SPI_INTR_STAT_REG,
2573f9309e5SEmmanuel Vadot 		    ZY7_SPI_INTR_TX_FIFO_UNDERFLOW);
2583f9309e5SEmmanuel Vadot 	}
2593f9309e5SEmmanuel Vadot 
2603f9309e5SEmmanuel Vadot 	/* Fill transmit fifo. */
2613f9309e5SEmmanuel Vadot 	if (sc->tx_bytes_sent < sc->tx_bytes &&
2623f9309e5SEmmanuel Vadot 	    (istatus & ZY7_SPI_INTR_TX_FIFO_NOT_FULL) != 0) {
2633f9309e5SEmmanuel Vadot 		zy7_spi_write_fifo(sc, MIN(96, sc->tx_bytes -
2643f9309e5SEmmanuel Vadot 			sc->tx_bytes_sent));
2653f9309e5SEmmanuel Vadot 
2663f9309e5SEmmanuel Vadot 		if (sc->tx_bytes_sent == sc->tx_bytes) {
2673f9309e5SEmmanuel Vadot 			/* Disable transmit FIFO interrupt, enable receive
2683f9309e5SEmmanuel Vadot 			 * FIFO interrupt.
2693f9309e5SEmmanuel Vadot 			 */
2703f9309e5SEmmanuel Vadot 			WR4(sc, ZY7_SPI_INTR_DIS_REG,
2713f9309e5SEmmanuel Vadot 			    ZY7_SPI_INTR_TX_FIFO_NOT_FULL);
2723f9309e5SEmmanuel Vadot 			WR4(sc, ZY7_SPI_INTR_EN_REG,
2733f9309e5SEmmanuel Vadot 			    ZY7_SPI_INTR_RX_FIFO_NOT_EMPTY);
2743f9309e5SEmmanuel Vadot 		}
2753f9309e5SEmmanuel Vadot 	}
2763f9309e5SEmmanuel Vadot 
2773f9309e5SEmmanuel Vadot 	/* Finished with transfer? */
2783f9309e5SEmmanuel Vadot 	if (sc->tx_bytes_sent == sc->tx_bytes &&
2793f9309e5SEmmanuel Vadot 	    sc->rx_bytes_rcvd == sc->rx_bytes) {
2803f9309e5SEmmanuel Vadot 		/* De-assert CS. */
2813f9309e5SEmmanuel Vadot 		sc->cfg_reg_shadow &=
2823f9309e5SEmmanuel Vadot 		    ~(ZY7_SPI_CONFIG_CLK_PH | ZY7_SPI_CONFIG_CLK_POL);
2833f9309e5SEmmanuel Vadot 		sc->cfg_reg_shadow |= ZY7_SPI_CONFIG_CS_MASK;
2843f9309e5SEmmanuel Vadot 		WR4(sc, ZY7_SPI_CONFIG_REG, sc->cfg_reg_shadow);
2853f9309e5SEmmanuel Vadot 
2863f9309e5SEmmanuel Vadot 		wakeup(sc->dev);
2873f9309e5SEmmanuel Vadot 	}
2883f9309e5SEmmanuel Vadot 
2893f9309e5SEmmanuel Vadot 	SPI_SC_UNLOCK(sc);
2903f9309e5SEmmanuel Vadot }
2913f9309e5SEmmanuel Vadot 
2923f9309e5SEmmanuel Vadot /* Initialize hardware. */
2933f9309e5SEmmanuel Vadot static int
zy7_spi_init_hw(struct zy7_spi_softc * sc)2943f9309e5SEmmanuel Vadot zy7_spi_init_hw(struct zy7_spi_softc *sc)
2953f9309e5SEmmanuel Vadot {
2963f9309e5SEmmanuel Vadot 	uint32_t baud_div;
2973f9309e5SEmmanuel Vadot 
2983f9309e5SEmmanuel Vadot 	/* Find best clock divider. Divide by 2 not supported. */
2993f9309e5SEmmanuel Vadot 	baud_div = 1;
3003f9309e5SEmmanuel Vadot 	while ((sc->ref_clock >> (baud_div + 1)) > sc->spi_clock &&
3013f9309e5SEmmanuel Vadot 	    baud_div < 8)
3023f9309e5SEmmanuel Vadot 		baud_div++;
3033f9309e5SEmmanuel Vadot 	if (baud_div >= 8) {
3043f9309e5SEmmanuel Vadot 		device_printf(sc->dev, "cannot configure clock divider: ref=%d"
3053f9309e5SEmmanuel Vadot 		    " spi=%d.\n", sc->ref_clock, sc->spi_clock);
3063f9309e5SEmmanuel Vadot 		return (EINVAL);
3073f9309e5SEmmanuel Vadot 	}
3083f9309e5SEmmanuel Vadot 	sc->spi_clk_real_freq = sc->ref_clock >> (baud_div + 1);
3093f9309e5SEmmanuel Vadot 
3103f9309e5SEmmanuel Vadot 	/* Set up configuration register. */
3113f9309e5SEmmanuel Vadot 	sc->cfg_reg_shadow =
3123f9309e5SEmmanuel Vadot 	    ZY7_SPI_CONFIG_MAN_CS |
3133f9309e5SEmmanuel Vadot 	    ZY7_SPI_CONFIG_CS_MASK |
3143f9309e5SEmmanuel Vadot 	    ZY7_SPI_CONFIG_BAUD_RATE_DIV(baud_div) |
3153f9309e5SEmmanuel Vadot 	    ZY7_SPI_CONFIG_MODE_SEL;
3163f9309e5SEmmanuel Vadot 	WR4(sc, ZY7_SPI_CONFIG_REG, sc->cfg_reg_shadow);
3173f9309e5SEmmanuel Vadot 
3183f9309e5SEmmanuel Vadot 	/* Set thresholds. */
3193f9309e5SEmmanuel Vadot 	WR4(sc, ZY7_SPI_TX_THRESH_REG, 32);
3203f9309e5SEmmanuel Vadot 	WR4(sc, ZY7_SPI_RX_THRESH_REG, 1);
3213f9309e5SEmmanuel Vadot 
3223f9309e5SEmmanuel Vadot 	/* Clear and disable all interrupts. */
3233f9309e5SEmmanuel Vadot 	WR4(sc, ZY7_SPI_INTR_STAT_REG, ~0);
3243f9309e5SEmmanuel Vadot 	WR4(sc, ZY7_SPI_INTR_DIS_REG, ~0);
3253f9309e5SEmmanuel Vadot 
3263f9309e5SEmmanuel Vadot 	/* Enable SPI. */
3273f9309e5SEmmanuel Vadot 	WR4(sc, ZY7_SPI_EN_REG, ZY7_SPI_ENABLE);
3283f9309e5SEmmanuel Vadot 
3293f9309e5SEmmanuel Vadot 	return (0);
3303f9309e5SEmmanuel Vadot }
3313f9309e5SEmmanuel Vadot 
3323f9309e5SEmmanuel Vadot static void
zy7_spi_add_sysctls(device_t dev)3333f9309e5SEmmanuel Vadot zy7_spi_add_sysctls(device_t dev)
3343f9309e5SEmmanuel Vadot {
3353f9309e5SEmmanuel Vadot 	struct zy7_spi_softc *sc = device_get_softc(dev);
3363f9309e5SEmmanuel Vadot 	struct sysctl_ctx_list *ctx;
3373f9309e5SEmmanuel Vadot 	struct sysctl_oid_list *child;
3383f9309e5SEmmanuel Vadot 
3393f9309e5SEmmanuel Vadot 	ctx = device_get_sysctl_ctx(dev);
3403f9309e5SEmmanuel Vadot 	child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
3413f9309e5SEmmanuel Vadot 
3423f9309e5SEmmanuel Vadot 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "spi_clk_real_freq", CTLFLAG_RD,
3433f9309e5SEmmanuel Vadot 	    &sc->spi_clk_real_freq, 0, "SPI clock real frequency");
3443f9309e5SEmmanuel Vadot 
3453f9309e5SEmmanuel Vadot 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "rx_overflows", CTLFLAG_RD,
3463f9309e5SEmmanuel Vadot 	    &sc->rx_overflows, 0, "RX FIFO overflow events");
3473f9309e5SEmmanuel Vadot 
3483f9309e5SEmmanuel Vadot 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "tx_underflows", CTLFLAG_RD,
3493f9309e5SEmmanuel Vadot 	    &sc->tx_underflows, 0, "TX FIFO underflow events");
3503f9309e5SEmmanuel Vadot 
3513f9309e5SEmmanuel Vadot 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "interrupts", CTLFLAG_RD,
3523f9309e5SEmmanuel Vadot 	    &sc->interrupts, 0, "interrupt calls");
3533f9309e5SEmmanuel Vadot 
3543f9309e5SEmmanuel Vadot 	SYSCTL_ADD_UINT(ctx, child, OID_AUTO, "stray_ints", CTLFLAG_RD,
3553f9309e5SEmmanuel Vadot 	    &sc->stray_ints, 0, "stray interrupts");
3563f9309e5SEmmanuel Vadot }
3573f9309e5SEmmanuel Vadot 
3583f9309e5SEmmanuel Vadot static int
zy7_spi_probe(device_t dev)3593f9309e5SEmmanuel Vadot zy7_spi_probe(device_t dev)
3603f9309e5SEmmanuel Vadot {
3613f9309e5SEmmanuel Vadot 
3623f9309e5SEmmanuel Vadot 	if (!ofw_bus_status_okay(dev))
3633f9309e5SEmmanuel Vadot 		return (ENXIO);
3643f9309e5SEmmanuel Vadot 
3653f9309e5SEmmanuel Vadot 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
3663f9309e5SEmmanuel Vadot 		return (ENXIO);
3673f9309e5SEmmanuel Vadot 
3683f9309e5SEmmanuel Vadot 	device_set_desc(dev, "Zynq SPI Controller");
3693f9309e5SEmmanuel Vadot 
3703f9309e5SEmmanuel Vadot 	return (BUS_PROBE_DEFAULT);
3713f9309e5SEmmanuel Vadot }
3723f9309e5SEmmanuel Vadot 
3733f9309e5SEmmanuel Vadot static int zy7_spi_detach(device_t);
3743f9309e5SEmmanuel Vadot 
3753f9309e5SEmmanuel Vadot static int
zy7_spi_attach(device_t dev)3763f9309e5SEmmanuel Vadot zy7_spi_attach(device_t dev)
3773f9309e5SEmmanuel Vadot {
3783f9309e5SEmmanuel Vadot 	struct zy7_spi_softc *sc;
3793f9309e5SEmmanuel Vadot 	int rid, err;
3803f9309e5SEmmanuel Vadot 	phandle_t node;
3813f9309e5SEmmanuel Vadot 	pcell_t cell;
3823f9309e5SEmmanuel Vadot 
3833f9309e5SEmmanuel Vadot 	sc = device_get_softc(dev);
3843f9309e5SEmmanuel Vadot 	sc->dev = dev;
3853f9309e5SEmmanuel Vadot 
3863f9309e5SEmmanuel Vadot 	SPI_SC_LOCK_INIT(sc);
3873f9309e5SEmmanuel Vadot 
3883f9309e5SEmmanuel Vadot 	/* Get ref-clock and spi-clock properties. */
3893f9309e5SEmmanuel Vadot 	node = ofw_bus_get_node(dev);
3903f9309e5SEmmanuel Vadot 	if (OF_getprop(node, "ref-clock", &cell, sizeof(cell)) > 0)
3913f9309e5SEmmanuel Vadot 		sc->ref_clock = fdt32_to_cpu(cell);
3923f9309e5SEmmanuel Vadot 	else {
3933f9309e5SEmmanuel Vadot 		device_printf(dev, "must have ref-clock property\n");
3943f9309e5SEmmanuel Vadot 		return (ENXIO);
3953f9309e5SEmmanuel Vadot 	}
3963f9309e5SEmmanuel Vadot 	if (OF_getprop(node, "spi-clock", &cell, sizeof(cell)) > 0)
3973f9309e5SEmmanuel Vadot 		sc->spi_clock = fdt32_to_cpu(cell);
3983f9309e5SEmmanuel Vadot 	else
3993f9309e5SEmmanuel Vadot 		sc->spi_clock = ZY7_SPI_DEFAULT_SPI_CLOCK;
4003f9309e5SEmmanuel Vadot 
4013f9309e5SEmmanuel Vadot 	/* Get memory resource. */
4023f9309e5SEmmanuel Vadot 	rid = 0;
4033f9309e5SEmmanuel Vadot 	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
4043f9309e5SEmmanuel Vadot 	    RF_ACTIVE);
4053f9309e5SEmmanuel Vadot 	if (sc->mem_res == NULL) {
4063f9309e5SEmmanuel Vadot 		device_printf(dev, "could not allocate memory resources.\n");
4073f9309e5SEmmanuel Vadot 		zy7_spi_detach(dev);
4083f9309e5SEmmanuel Vadot 		return (ENOMEM);
4093f9309e5SEmmanuel Vadot 	}
4103f9309e5SEmmanuel Vadot 
4113f9309e5SEmmanuel Vadot 	/* Allocate IRQ. */
4123f9309e5SEmmanuel Vadot 	rid = 0;
4133f9309e5SEmmanuel Vadot 	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
4143f9309e5SEmmanuel Vadot 	    RF_ACTIVE);
4153f9309e5SEmmanuel Vadot 	if (sc->irq_res == NULL) {
4163f9309e5SEmmanuel Vadot 		device_printf(dev, "could not allocate IRQ resource.\n");
4173f9309e5SEmmanuel Vadot 		zy7_spi_detach(dev);
4183f9309e5SEmmanuel Vadot 		return (ENOMEM);
4193f9309e5SEmmanuel Vadot 	}
4203f9309e5SEmmanuel Vadot 
4213f9309e5SEmmanuel Vadot 	/* Activate the interrupt. */
4223f9309e5SEmmanuel Vadot 	err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
4233f9309e5SEmmanuel Vadot 	    NULL, zy7_spi_intr, sc, &sc->intrhandle);
4243f9309e5SEmmanuel Vadot 	if (err) {
4253f9309e5SEmmanuel Vadot 		device_printf(dev, "could not setup IRQ.\n");
4263f9309e5SEmmanuel Vadot 		zy7_spi_detach(dev);
4273f9309e5SEmmanuel Vadot 		return (err);
4283f9309e5SEmmanuel Vadot 	}
4293f9309e5SEmmanuel Vadot 
4303f9309e5SEmmanuel Vadot 	/* Configure the device. */
4313f9309e5SEmmanuel Vadot 	err = zy7_spi_init_hw(sc);
4323f9309e5SEmmanuel Vadot 	if (err) {
4333f9309e5SEmmanuel Vadot 		zy7_spi_detach(dev);
4343f9309e5SEmmanuel Vadot 		return (err);
4353f9309e5SEmmanuel Vadot 	}
4363f9309e5SEmmanuel Vadot 
4375b56413dSWarner Losh 	sc->child = device_add_child(dev, "spibus", DEVICE_UNIT_ANY);
4383f9309e5SEmmanuel Vadot 
4393f9309e5SEmmanuel Vadot 	zy7_spi_add_sysctls(dev);
4403f9309e5SEmmanuel Vadot 
4413f9309e5SEmmanuel Vadot 	/* Attach spibus driver as a child later when interrupts work. */
4425201deccSJohn Baldwin 	bus_delayed_attach_children(dev);
4433f9309e5SEmmanuel Vadot 
4443f9309e5SEmmanuel Vadot 	return (0);
4453f9309e5SEmmanuel Vadot }
4463f9309e5SEmmanuel Vadot 
4473f9309e5SEmmanuel Vadot static int
zy7_spi_detach(device_t dev)4483f9309e5SEmmanuel Vadot zy7_spi_detach(device_t dev)
4493f9309e5SEmmanuel Vadot {
4503f9309e5SEmmanuel Vadot 	struct zy7_spi_softc *sc = device_get_softc(dev);
451*64d1a02eSJohn Baldwin 	int error;
4523f9309e5SEmmanuel Vadot 
453*64d1a02eSJohn Baldwin 	error = bus_generic_detach(dev);
454*64d1a02eSJohn Baldwin 	if (error != 0)
455*64d1a02eSJohn Baldwin 		return (error);
4563f9309e5SEmmanuel Vadot 
4573f9309e5SEmmanuel Vadot 	/* Disable hardware. */
4583f9309e5SEmmanuel Vadot 	if (sc->mem_res != NULL) {
4593f9309e5SEmmanuel Vadot 		/* Disable SPI. */
4603f9309e5SEmmanuel Vadot 		WR4(sc, ZY7_SPI_EN_REG, 0);
4613f9309e5SEmmanuel Vadot 
4623f9309e5SEmmanuel Vadot 		/* Clear and disable all interrupts. */
4633f9309e5SEmmanuel Vadot 		WR4(sc, ZY7_SPI_INTR_STAT_REG, ~0);
4643f9309e5SEmmanuel Vadot 		WR4(sc, ZY7_SPI_INTR_DIS_REG, ~0);
4653f9309e5SEmmanuel Vadot 	}
4663f9309e5SEmmanuel Vadot 
4673f9309e5SEmmanuel Vadot 	/* Teardown and release interrupt. */
4683f9309e5SEmmanuel Vadot 	if (sc->irq_res != NULL) {
4693f9309e5SEmmanuel Vadot 		if (sc->intrhandle)
4703f9309e5SEmmanuel Vadot 			bus_teardown_intr(dev, sc->irq_res, sc->intrhandle);
4713f9309e5SEmmanuel Vadot 		bus_release_resource(dev, SYS_RES_IRQ,
4723f9309e5SEmmanuel Vadot 		    rman_get_rid(sc->irq_res), sc->irq_res);
4733f9309e5SEmmanuel Vadot 	}
4743f9309e5SEmmanuel Vadot 
4753f9309e5SEmmanuel Vadot 	/* Release memory resource. */
4763f9309e5SEmmanuel Vadot 	if (sc->mem_res != NULL)
4773f9309e5SEmmanuel Vadot 		bus_release_resource(dev, SYS_RES_MEMORY,
4783f9309e5SEmmanuel Vadot 		    rman_get_rid(sc->mem_res), sc->mem_res);
4793f9309e5SEmmanuel Vadot 
4803f9309e5SEmmanuel Vadot 	SPI_SC_LOCK_DESTROY(sc);
4813f9309e5SEmmanuel Vadot 
4823f9309e5SEmmanuel Vadot 	return (0);
4833f9309e5SEmmanuel Vadot }
4843f9309e5SEmmanuel Vadot 
4853f9309e5SEmmanuel Vadot static phandle_t
zy7_spi_get_node(device_t bus,device_t dev)4863f9309e5SEmmanuel Vadot zy7_spi_get_node(device_t bus, device_t dev)
4873f9309e5SEmmanuel Vadot {
4883f9309e5SEmmanuel Vadot 
4893f9309e5SEmmanuel Vadot 	return (ofw_bus_get_node(bus));
4903f9309e5SEmmanuel Vadot }
4913f9309e5SEmmanuel Vadot 
4923f9309e5SEmmanuel Vadot static int
zy7_spi_transfer(device_t dev,device_t child,struct spi_command * cmd)4933f9309e5SEmmanuel Vadot zy7_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
4943f9309e5SEmmanuel Vadot {
4953f9309e5SEmmanuel Vadot 	struct zy7_spi_softc *sc = device_get_softc(dev);
4963f9309e5SEmmanuel Vadot 	uint32_t cs;
4973f9309e5SEmmanuel Vadot 	uint32_t mode;
4983f9309e5SEmmanuel Vadot 	int err = 0;
4993f9309e5SEmmanuel Vadot 
5003f9309e5SEmmanuel Vadot 	KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz,
5013f9309e5SEmmanuel Vadot 	    ("TX/RX command sizes should be equal"));
5023f9309e5SEmmanuel Vadot 	KASSERT(cmd->tx_data_sz == cmd->rx_data_sz,
5033f9309e5SEmmanuel Vadot 	    ("TX/RX data sizes should be equal"));
5043f9309e5SEmmanuel Vadot 
5053f9309e5SEmmanuel Vadot 	/* Get chip select and mode for this child. */
5063f9309e5SEmmanuel Vadot 	spibus_get_cs(child, &cs);
5073f9309e5SEmmanuel Vadot 	cs &= ~SPIBUS_CS_HIGH;
5083f9309e5SEmmanuel Vadot 	if (cs > 2) {
5093f9309e5SEmmanuel Vadot 		device_printf(dev, "Invalid chip select %d requested by %s",
5103f9309e5SEmmanuel Vadot 		    cs, device_get_nameunit(child));
5113f9309e5SEmmanuel Vadot 		return (EINVAL);
5123f9309e5SEmmanuel Vadot 	}
5133f9309e5SEmmanuel Vadot 	spibus_get_mode(child, &mode);
5143f9309e5SEmmanuel Vadot 
5153f9309e5SEmmanuel Vadot 	SPI_SC_LOCK(sc);
5163f9309e5SEmmanuel Vadot 
5173f9309e5SEmmanuel Vadot 	/* Wait for controller available. */
5183f9309e5SEmmanuel Vadot 	while (sc->busy != 0) {
5193f9309e5SEmmanuel Vadot 		err = mtx_sleep(dev, &sc->sc_mtx, 0, "zspi0", 0);
5203f9309e5SEmmanuel Vadot 		if (err) {
5213f9309e5SEmmanuel Vadot 			SPI_SC_UNLOCK(sc);
5223f9309e5SEmmanuel Vadot 			return (err);
5233f9309e5SEmmanuel Vadot 		}
5243f9309e5SEmmanuel Vadot 	}
5253f9309e5SEmmanuel Vadot 
5263f9309e5SEmmanuel Vadot 	/* Start transfer. */
5273f9309e5SEmmanuel Vadot 	sc->busy = 1;
5283f9309e5SEmmanuel Vadot 	sc->cmd = cmd;
5293f9309e5SEmmanuel Vadot 	sc->tx_bytes = sc->cmd->tx_cmd_sz + sc->cmd->tx_data_sz;
5303f9309e5SEmmanuel Vadot 	sc->tx_bytes_sent = 0;
5313f9309e5SEmmanuel Vadot 	sc->rx_bytes = sc->cmd->rx_cmd_sz + sc->cmd->rx_data_sz;
5323f9309e5SEmmanuel Vadot 	sc->rx_bytes_rcvd = 0;
5333f9309e5SEmmanuel Vadot 
5343f9309e5SEmmanuel Vadot 	/* Enable interrupts.  zy7_spi_intr() will handle transfer. */
5353f9309e5SEmmanuel Vadot 	WR4(sc, ZY7_SPI_INTR_EN_REG,
5363f9309e5SEmmanuel Vadot 	    ZY7_SPI_INTR_TX_FIFO_NOT_FULL |
5373f9309e5SEmmanuel Vadot 	    ZY7_SPI_INTR_RX_OVERFLOW);
5383f9309e5SEmmanuel Vadot 
5393f9309e5SEmmanuel Vadot 	/* Handle polarity and phase. */
5403f9309e5SEmmanuel Vadot 	if (mode == SPIBUS_MODE_CPHA || mode == SPIBUS_MODE_CPOL_CPHA)
5413f9309e5SEmmanuel Vadot 		sc->cfg_reg_shadow |= ZY7_SPI_CONFIG_CLK_PH;
5423f9309e5SEmmanuel Vadot 	if (mode == SPIBUS_MODE_CPOL || mode == SPIBUS_MODE_CPOL_CPHA)
5433f9309e5SEmmanuel Vadot 		sc->cfg_reg_shadow |= ZY7_SPI_CONFIG_CLK_POL;
5443f9309e5SEmmanuel Vadot 
5453f9309e5SEmmanuel Vadot 	/* Assert CS. */
5463f9309e5SEmmanuel Vadot 	sc->cfg_reg_shadow &= ~ZY7_SPI_CONFIG_CS_MASK;
5473f9309e5SEmmanuel Vadot 	sc->cfg_reg_shadow |= ZY7_SPI_CONFIG_CS(cs);
5483f9309e5SEmmanuel Vadot 	WR4(sc, ZY7_SPI_CONFIG_REG, sc->cfg_reg_shadow);
5493f9309e5SEmmanuel Vadot 
5503f9309e5SEmmanuel Vadot 	/* Wait for completion. */
5513f9309e5SEmmanuel Vadot 	err = mtx_sleep(dev, &sc->sc_mtx, 0, "zspi1", hz * 2);
5523f9309e5SEmmanuel Vadot 	if (err)
5533f9309e5SEmmanuel Vadot 		zy7_spi_abort_transfer(sc);
5543f9309e5SEmmanuel Vadot 
5553f9309e5SEmmanuel Vadot 	/* Release controller. */
5563f9309e5SEmmanuel Vadot 	sc->busy = 0;
5573f9309e5SEmmanuel Vadot 	wakeup_one(dev);
5583f9309e5SEmmanuel Vadot 
5593f9309e5SEmmanuel Vadot 	SPI_SC_UNLOCK(sc);
5603f9309e5SEmmanuel Vadot 
5613f9309e5SEmmanuel Vadot 	return (err);
5623f9309e5SEmmanuel Vadot }
5633f9309e5SEmmanuel Vadot 
5643f9309e5SEmmanuel Vadot static device_method_t zy7_spi_methods[] = {
5653f9309e5SEmmanuel Vadot 	/* Device interface */
5663f9309e5SEmmanuel Vadot 	DEVMETHOD(device_probe,		zy7_spi_probe),
5673f9309e5SEmmanuel Vadot 	DEVMETHOD(device_attach,	zy7_spi_attach),
5683f9309e5SEmmanuel Vadot 	DEVMETHOD(device_detach,	zy7_spi_detach),
5693f9309e5SEmmanuel Vadot 
5703f9309e5SEmmanuel Vadot 	/* SPI interface */
5713f9309e5SEmmanuel Vadot 	DEVMETHOD(spibus_transfer,	zy7_spi_transfer),
5723f9309e5SEmmanuel Vadot 
5733f9309e5SEmmanuel Vadot 	/* ofw_bus interface */
5743f9309e5SEmmanuel Vadot 	DEVMETHOD(ofw_bus_get_node,	zy7_spi_get_node),
5753f9309e5SEmmanuel Vadot 
5763f9309e5SEmmanuel Vadot 	DEVMETHOD_END
5773f9309e5SEmmanuel Vadot };
5783f9309e5SEmmanuel Vadot 
5793f9309e5SEmmanuel Vadot static driver_t zy7_spi_driver = {
5803f9309e5SEmmanuel Vadot 	"zy7_spi",
5813f9309e5SEmmanuel Vadot 	zy7_spi_methods,
5823f9309e5SEmmanuel Vadot 	sizeof(struct zy7_spi_softc),
5833f9309e5SEmmanuel Vadot };
5843f9309e5SEmmanuel Vadot 
585680ccae3SJohn Baldwin DRIVER_MODULE(zy7_spi, simplebus, zy7_spi_driver, 0, 0);
5865f31d14aSJohn Baldwin DRIVER_MODULE(ofw_spibus, zy7_spi, ofw_spibus_driver, 0, 0);
5873f9309e5SEmmanuel Vadot SIMPLEBUS_PNP_INFO(compat_data);
5883f9309e5SEmmanuel Vadot MODULE_DEPEND(zy7_spi, ofw_spibus, 1, 1, 1);
589