xref: /openbsd-src/sys/dev/fdt/rkspi.c (revision 0f9e9ec23bb2b65cc62a3d17df12827a45dae80c)
1*0f9e9ec2Sjsg /* $OpenBSD: rkspi.c,v 1.2 2024/05/13 01:15:50 jsg Exp $ */
22e0a1eb9Skettenis /*
32e0a1eb9Skettenis  * Copyright (c) 2018,2023 Patrick Wildt <patrick@blueri.se>
42e0a1eb9Skettenis  * Copyright (c) 2024 Mark Kettenis <kettenis@openbsd.org>
52e0a1eb9Skettenis  *
62e0a1eb9Skettenis  * Permission to use, copy, modify, and distribute this software for any
72e0a1eb9Skettenis  * purpose with or without fee is hereby granted, provided that the above
82e0a1eb9Skettenis  * copyright notice and this permission notice appear in all copies.
92e0a1eb9Skettenis  *
102e0a1eb9Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
112e0a1eb9Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
122e0a1eb9Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
132e0a1eb9Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
142e0a1eb9Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
152e0a1eb9Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
162e0a1eb9Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
172e0a1eb9Skettenis  */
182e0a1eb9Skettenis 
192e0a1eb9Skettenis #include <sys/param.h>
202e0a1eb9Skettenis #include <sys/systm.h>
212e0a1eb9Skettenis #include <sys/device.h>
222e0a1eb9Skettenis 
232e0a1eb9Skettenis #include <machine/bus.h>
242e0a1eb9Skettenis #include <machine/fdt.h>
252e0a1eb9Skettenis 
262e0a1eb9Skettenis #include <dev/ofw/openfirm.h>
272e0a1eb9Skettenis #include <dev/ofw/ofw_clock.h>
282e0a1eb9Skettenis #include <dev/ofw/ofw_pinctrl.h>
292e0a1eb9Skettenis #include <dev/ofw/fdt.h>
302e0a1eb9Skettenis #include <dev/spi/spivar.h>
312e0a1eb9Skettenis 
322e0a1eb9Skettenis /* registers */
332e0a1eb9Skettenis #define SPI_CTRLR0			0x0000
342e0a1eb9Skettenis #define  SPI_CTRLR0_DFS_4BIT			(0x0 << 0)
352e0a1eb9Skettenis #define  SPI_CTRLR0_DFS_8BIT			(0x1 << 0)
362e0a1eb9Skettenis #define  SPI_CTRLR0_DFS_16BIT			(0x2 << 0)
372e0a1eb9Skettenis #define  SPI_CTRLR0_SCPH			(0x1 << 6)
382e0a1eb9Skettenis #define  SPI_CTRLR0_SCPOL			(0x1 << 7)
392e0a1eb9Skettenis #define  SPI_CTRLR0_CSM_KEEP			(0x0 << 8)
402e0a1eb9Skettenis #define  SPI_CTRLR0_CSM_HALF			(0x1 << 8)
412e0a1eb9Skettenis #define  SPI_CTRLR0_CSM_ONE			(0x2 << 8)
422e0a1eb9Skettenis #define  SPI_CTRLR0_SSD_HALF			(0x0 << 10)
432e0a1eb9Skettenis #define  SPI_CTRLR0_SSD_ONE			(0x1 << 10)
442e0a1eb9Skettenis #define  SPI_CTRLR0_EM_LITTLE			(0x0 << 11)
452e0a1eb9Skettenis #define  SPI_CTRLR0_EM_BIG			(0x1 << 11)
462e0a1eb9Skettenis #define  SPI_CTRLR0_FBM_MSB			(0x0 << 12)
472e0a1eb9Skettenis #define  SPI_CTRLR0_FBM_LSB			(0x1 << 12)
482e0a1eb9Skettenis #define  SPI_CTRLR0_BHT_16BIT			(0x0 << 13)
492e0a1eb9Skettenis #define  SPI_CTRLR0_BHT_8BIT			(0x1 << 13)
502e0a1eb9Skettenis #define  SPI_CTRLR0_RSD(x)			((x) << 14)
512e0a1eb9Skettenis #define  SPI_CTRLR0_FRF_SPI			(0x0 << 16)
522e0a1eb9Skettenis #define  SPI_CTRLR0_FRF_SSP			(0x1 << 16)
532e0a1eb9Skettenis #define  SPI_CTRLR0_FRF_MICROWIRE		(0x2 << 16)
542e0a1eb9Skettenis #define  SPI_CTRLR0_XFM_TR			(0x0 << 18)
552e0a1eb9Skettenis #define  SPI_CTRLR0_XFM_TO			(0x1 << 18)
562e0a1eb9Skettenis #define  SPI_CTRLR0_XFM_RO			(0x2 << 18)
572e0a1eb9Skettenis #define  SPI_CTRLR0_SOI(x)			((1 << (x)) << 23)
582e0a1eb9Skettenis #define SPI_CTRLR1			0x0004
592e0a1eb9Skettenis #define SPI_ENR				0x0008
602e0a1eb9Skettenis #define SPI_SER				0x000c
612e0a1eb9Skettenis #define  SPI_SER_CS(x)				((1 << (x)) << 0)
622e0a1eb9Skettenis #define SPI_BAUDR			0x0010
632e0a1eb9Skettenis #define SPI_TXFTLR			0x0014
642e0a1eb9Skettenis #define SPI_RXFTLR			0x0018
652e0a1eb9Skettenis #define SPI_TXFLR			0x001c
662e0a1eb9Skettenis #define SPI_RXFLR			0x0020
672e0a1eb9Skettenis #define SPI_SR				0x0024
682e0a1eb9Skettenis #define  SPI_SR_BSF				(1 << 0)
692e0a1eb9Skettenis #define  SPI_SR_TFF				(1 << 1)
702e0a1eb9Skettenis #define  SPI_SR_TFE				(1 << 2)
712e0a1eb9Skettenis #define  SPI_SR_RFE				(1 << 3)
722e0a1eb9Skettenis #define  SPI_SR_RFF				(1 << 4)
732e0a1eb9Skettenis #define SPI_IPR				0x0028
742e0a1eb9Skettenis #define SPI_IMR				0x002c
752e0a1eb9Skettenis #define SPI_ISR				0x0030
762e0a1eb9Skettenis #define SPI_RISR			0x0034
772e0a1eb9Skettenis #define SPI_ICR				0x0038
782e0a1eb9Skettenis #define  SPI_ICR_MASK				(0x7f << 0)
792e0a1eb9Skettenis #define SPI_DMACR			0x003c
802e0a1eb9Skettenis #define SPI_DMATDLR			0x0040
812e0a1eb9Skettenis #define SPI_DMARDLR			0x0044
822e0a1eb9Skettenis #define SPI_VERSION			0x0048
832e0a1eb9Skettenis #define SPI_TXDR			0x0400
842e0a1eb9Skettenis #define SPI_RXDR			0x0800
852e0a1eb9Skettenis 
862e0a1eb9Skettenis #define DEVNAME(sc)	((sc)->sc_dev.dv_xname)
872e0a1eb9Skettenis 
882e0a1eb9Skettenis struct rkspi_softc {
892e0a1eb9Skettenis 	struct device		 sc_dev;
902e0a1eb9Skettenis 	bus_space_tag_t		 sc_iot;
912e0a1eb9Skettenis 	bus_space_handle_t	 sc_ioh;
922e0a1eb9Skettenis 	bus_size_t		 sc_ios;
932e0a1eb9Skettenis 	int			 sc_node;
942e0a1eb9Skettenis 
952e0a1eb9Skettenis 	struct rwlock		 sc_buslock;
962e0a1eb9Skettenis 	struct spi_controller	 sc_tag;
972e0a1eb9Skettenis 
982e0a1eb9Skettenis 	int			 sc_ridx;
992e0a1eb9Skettenis 	int			 sc_widx;
1002e0a1eb9Skettenis 	int			 sc_cs;
1012e0a1eb9Skettenis 	u_int			 sc_cs_delay;
1022e0a1eb9Skettenis 	u_int			 sc_spi_freq;
1032e0a1eb9Skettenis };
1042e0a1eb9Skettenis 
1052e0a1eb9Skettenis int	 rkspi_match(struct device *, void *, void *);
1062e0a1eb9Skettenis void	 rkspi_attach(struct device *, struct device *, void *);
1072e0a1eb9Skettenis int	 rkspi_detach(struct device *, int);
1082e0a1eb9Skettenis 
1092e0a1eb9Skettenis void	 rkspi_config(void *, struct spi_config *);
1102e0a1eb9Skettenis int	 rkspi_transfer(void *, char *, char *, int, int);
1112e0a1eb9Skettenis int	 rkspi_acquire_bus(void *, int);
1122e0a1eb9Skettenis void	 rkspi_release_bus(void *, int);
1132e0a1eb9Skettenis 
1142e0a1eb9Skettenis int	 rkspi_wait_state(struct rkspi_softc *, uint32_t, uint32_t);
1152e0a1eb9Skettenis 
1162e0a1eb9Skettenis void	 rkspi_scan(struct rkspi_softc *);
1172e0a1eb9Skettenis 
1182e0a1eb9Skettenis #define HREAD4(sc, reg)							\
1192e0a1eb9Skettenis 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
1202e0a1eb9Skettenis #define HWRITE4(sc, reg, val)						\
1212e0a1eb9Skettenis 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
1222e0a1eb9Skettenis #define HSET4(sc, reg, bits)						\
1232e0a1eb9Skettenis 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
1242e0a1eb9Skettenis #define HCLR4(sc, reg, bits)						\
1252e0a1eb9Skettenis 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
1262e0a1eb9Skettenis 
1272e0a1eb9Skettenis const struct cfattach rkspi_ca = {
1282e0a1eb9Skettenis 	sizeof(struct rkspi_softc), rkspi_match, rkspi_attach,
1292e0a1eb9Skettenis 	rkspi_detach
1302e0a1eb9Skettenis };
1312e0a1eb9Skettenis 
1322e0a1eb9Skettenis struct cfdriver rkspi_cd = {
1332e0a1eb9Skettenis 	NULL, "rkspi", DV_DULL
1342e0a1eb9Skettenis };
1352e0a1eb9Skettenis 
1362e0a1eb9Skettenis int
rkspi_match(struct device * parent,void * match,void * aux)1372e0a1eb9Skettenis rkspi_match(struct device *parent, void *match, void *aux)
1382e0a1eb9Skettenis {
1392e0a1eb9Skettenis 	struct fdt_attach_args *faa = aux;
1402e0a1eb9Skettenis 
1412e0a1eb9Skettenis 	return OF_is_compatible(faa->fa_node, "rockchip,rk3066-spi");
1422e0a1eb9Skettenis }
1432e0a1eb9Skettenis 
1442e0a1eb9Skettenis void
rkspi_attach(struct device * parent,struct device * self,void * aux)1452e0a1eb9Skettenis rkspi_attach(struct device *parent, struct device *self, void *aux)
1462e0a1eb9Skettenis {
1472e0a1eb9Skettenis 	struct rkspi_softc *sc = (struct rkspi_softc *)self;
1482e0a1eb9Skettenis 	struct fdt_attach_args *faa = aux;
1492e0a1eb9Skettenis 
1502e0a1eb9Skettenis 	if (faa->fa_nreg < 1)
1512e0a1eb9Skettenis 		return;
1522e0a1eb9Skettenis 
1532e0a1eb9Skettenis 	sc->sc_iot = faa->fa_iot;
1542e0a1eb9Skettenis 	sc->sc_ios = faa->fa_reg[0].size;
1552e0a1eb9Skettenis 	sc->sc_node = faa->fa_node;
1562e0a1eb9Skettenis 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
1572e0a1eb9Skettenis 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
1582e0a1eb9Skettenis 		printf(": can't map registers\n");
1592e0a1eb9Skettenis 		return;
1602e0a1eb9Skettenis 	}
1612e0a1eb9Skettenis 
1622e0a1eb9Skettenis 	pinctrl_byname(sc->sc_node, "default");
1632e0a1eb9Skettenis 	clock_set_assigned(sc->sc_node);
1642e0a1eb9Skettenis 	clock_enable(sc->sc_node, "apb_pclk");
1652e0a1eb9Skettenis 	clock_enable(sc->sc_node, "spiclk");
1662e0a1eb9Skettenis 
1672e0a1eb9Skettenis 	sc->sc_spi_freq = clock_get_frequency(sc->sc_node, "spiclk");
1682e0a1eb9Skettenis 
1692e0a1eb9Skettenis 	printf("\n");
1702e0a1eb9Skettenis 
1712e0a1eb9Skettenis 	HWRITE4(sc, SPI_ENR, 0);
1722e0a1eb9Skettenis 	HWRITE4(sc, SPI_DMACR, 0);
1732e0a1eb9Skettenis 	HWRITE4(sc, SPI_DMATDLR, 0);
1742e0a1eb9Skettenis 	HWRITE4(sc, SPI_DMARDLR, 0);
1752e0a1eb9Skettenis 	HWRITE4(sc, SPI_IPR, 0);
1762e0a1eb9Skettenis 	HWRITE4(sc, SPI_IMR, 0);
1772e0a1eb9Skettenis 	HWRITE4(sc, SPI_ICR, SPI_ICR_MASK);
1782e0a1eb9Skettenis 
1792e0a1eb9Skettenis 	rw_init(&sc->sc_buslock, sc->sc_dev.dv_xname);
1802e0a1eb9Skettenis 
1812e0a1eb9Skettenis 	sc->sc_tag.sc_cookie = sc;
1822e0a1eb9Skettenis 	sc->sc_tag.sc_config = rkspi_config;
1832e0a1eb9Skettenis 	sc->sc_tag.sc_transfer = rkspi_transfer;
1842e0a1eb9Skettenis 	sc->sc_tag.sc_acquire_bus = rkspi_acquire_bus;
1852e0a1eb9Skettenis 	sc->sc_tag.sc_release_bus = rkspi_release_bus;
1862e0a1eb9Skettenis 
1872e0a1eb9Skettenis 	rkspi_scan(sc);
1882e0a1eb9Skettenis }
1892e0a1eb9Skettenis 
1902e0a1eb9Skettenis int
rkspi_detach(struct device * self,int flags)1912e0a1eb9Skettenis rkspi_detach(struct device *self, int flags)
1922e0a1eb9Skettenis {
1932e0a1eb9Skettenis 	struct rkspi_softc *sc = (struct rkspi_softc *)self;
1942e0a1eb9Skettenis 
1952e0a1eb9Skettenis 	HWRITE4(sc, SPI_ENR, 0);
1962e0a1eb9Skettenis 	HWRITE4(sc, SPI_IMR, 0);
1972e0a1eb9Skettenis 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
1982e0a1eb9Skettenis 	return 0;
1992e0a1eb9Skettenis }
2002e0a1eb9Skettenis 
2012e0a1eb9Skettenis void
rkspi_config(void * cookie,struct spi_config * conf)2022e0a1eb9Skettenis rkspi_config(void *cookie, struct spi_config *conf)
2032e0a1eb9Skettenis {
2042e0a1eb9Skettenis 	struct rkspi_softc *sc = cookie;
2052e0a1eb9Skettenis 	uint32_t ctrlr0;
2062e0a1eb9Skettenis 	uint16_t div;
2072e0a1eb9Skettenis 	int cs;
2082e0a1eb9Skettenis 
2092e0a1eb9Skettenis 	div = 2;
2102e0a1eb9Skettenis 	while ((sc->sc_spi_freq / div) > conf->sc_freq)
2112e0a1eb9Skettenis 		div++;
2122e0a1eb9Skettenis 	/* Clock divider needs to be even. */
2132e0a1eb9Skettenis 	if (div & 1)
2142e0a1eb9Skettenis 		div++;
2152e0a1eb9Skettenis 
2162e0a1eb9Skettenis 	cs = conf->sc_cs;
2172e0a1eb9Skettenis 	if (cs >= 2) {
2182e0a1eb9Skettenis 		printf("%s: invalid chip-select (%d)\n", DEVNAME(sc), cs);
2192e0a1eb9Skettenis 		return;
2202e0a1eb9Skettenis 	}
2212e0a1eb9Skettenis 	sc->sc_cs = cs;
2222e0a1eb9Skettenis 	sc->sc_cs_delay = conf->sc_cs_delay;
2232e0a1eb9Skettenis 
2242e0a1eb9Skettenis 	ctrlr0 = SPI_CTRLR0_BHT_8BIT | SPI_CTRLR0_SSD_ONE | SPI_CTRLR0_EM_BIG;
2252e0a1eb9Skettenis 	if (conf->sc_flags & SPI_CONFIG_CPHA)
2262e0a1eb9Skettenis 		ctrlr0 |= SPI_CTRLR0_SCPH;
2272e0a1eb9Skettenis 	if (conf->sc_flags & SPI_CONFIG_CPOL)
2282e0a1eb9Skettenis 		ctrlr0 |= SPI_CTRLR0_SCPOL;
2292e0a1eb9Skettenis 	switch (conf->sc_bpw) {
2302e0a1eb9Skettenis 	case 4:
2312e0a1eb9Skettenis 		ctrlr0 |= SPI_CTRLR0_DFS_4BIT;
2322e0a1eb9Skettenis 		break;
2332e0a1eb9Skettenis 	case 8:
2342e0a1eb9Skettenis 		ctrlr0 |= SPI_CTRLR0_DFS_8BIT;
2352e0a1eb9Skettenis 		break;
2362e0a1eb9Skettenis 	case 16:
2372e0a1eb9Skettenis 		ctrlr0 |= SPI_CTRLR0_DFS_16BIT;
2382e0a1eb9Skettenis 		break;
2392e0a1eb9Skettenis 	default:
2402e0a1eb9Skettenis 		printf("%s: invalid bits-per-word (%d)\n", DEVNAME(sc),
2412e0a1eb9Skettenis 		    conf->sc_bpw);
2422e0a1eb9Skettenis 		return;
2432e0a1eb9Skettenis 	}
2442e0a1eb9Skettenis 
2452e0a1eb9Skettenis 	HWRITE4(sc, SPI_ENR, 0);
2462e0a1eb9Skettenis 	HWRITE4(sc, SPI_SER, 0);
2472e0a1eb9Skettenis 	HWRITE4(sc, SPI_CTRLR0, ctrlr0);
2482e0a1eb9Skettenis 	HWRITE4(sc, SPI_BAUDR, div);
2492e0a1eb9Skettenis }
2502e0a1eb9Skettenis 
2512e0a1eb9Skettenis int
rkspi_wait_state(struct rkspi_softc * sc,uint32_t mask,uint32_t value)2522e0a1eb9Skettenis rkspi_wait_state(struct rkspi_softc *sc, uint32_t mask, uint32_t value)
2532e0a1eb9Skettenis {
2542e0a1eb9Skettenis 	int timeout;
2552e0a1eb9Skettenis 
2562e0a1eb9Skettenis 	for (timeout = 1000; timeout > 0; timeout--) {
2572e0a1eb9Skettenis 		if ((HREAD4(sc, SPI_SR) & mask) == value)
2582e0a1eb9Skettenis 			return 0;
2592e0a1eb9Skettenis 		delay(10);
2602e0a1eb9Skettenis 	}
2612e0a1eb9Skettenis 
2622e0a1eb9Skettenis 	return ETIMEDOUT;
2632e0a1eb9Skettenis }
2642e0a1eb9Skettenis 
2652e0a1eb9Skettenis int
rkspi_transfer(void * cookie,char * out,char * in,int len,int flags)2662e0a1eb9Skettenis rkspi_transfer(void *cookie, char *out, char *in, int len, int flags)
2672e0a1eb9Skettenis {
2682e0a1eb9Skettenis 	struct rkspi_softc *sc = cookie;
2692e0a1eb9Skettenis 	int i;
2702e0a1eb9Skettenis 
2712e0a1eb9Skettenis 	sc->sc_ridx = sc->sc_widx = 0;
2722e0a1eb9Skettenis 
2732e0a1eb9Skettenis 	/* drain input buffer */
2742e0a1eb9Skettenis 	while (!(HREAD4(sc, SPI_SR) & SPI_SR_RFE))
2752e0a1eb9Skettenis 		HREAD4(sc, SPI_RXDR);
2762e0a1eb9Skettenis 
2772e0a1eb9Skettenis 	if (out)
2782e0a1eb9Skettenis 		HCLR4(sc, SPI_CTRLR0, SPI_CTRLR0_XFM_RO);
2792e0a1eb9Skettenis 	else
2802e0a1eb9Skettenis 		HSET4(sc, SPI_CTRLR0, SPI_CTRLR0_XFM_RO);
2812e0a1eb9Skettenis 	HWRITE4(sc, SPI_CTRLR1, len - 1);
2822e0a1eb9Skettenis 
2832e0a1eb9Skettenis 	HSET4(sc, SPI_SER, SPI_SER_CS(sc->sc_cs));
2842e0a1eb9Skettenis 	delay(sc->sc_cs_delay);
2852e0a1eb9Skettenis 
2862e0a1eb9Skettenis 	HWRITE4(sc, SPI_ENR, 1);
2872e0a1eb9Skettenis 
2882e0a1eb9Skettenis 	while (sc->sc_ridx < len || sc->sc_widx < len) {
2892e0a1eb9Skettenis 		for (i = sc->sc_widx; i < len; i++) {
2902e0a1eb9Skettenis 			if (rkspi_wait_state(sc, SPI_SR_TFF, 0))
2912e0a1eb9Skettenis 				goto err;
2922e0a1eb9Skettenis 			if (out)
2932e0a1eb9Skettenis 				HWRITE4(sc, SPI_TXDR, out[i]);
2942e0a1eb9Skettenis 			sc->sc_widx++;
2952e0a1eb9Skettenis 		}
2962e0a1eb9Skettenis 
2972e0a1eb9Skettenis 		for (i = sc->sc_ridx; i < sc->sc_widx; i++) {
2982e0a1eb9Skettenis 			if (rkspi_wait_state(sc, SPI_SR_RFE, 0))
2992e0a1eb9Skettenis 				goto err;
3002e0a1eb9Skettenis 			if (in)
3012e0a1eb9Skettenis 				in[i] = HREAD4(sc, SPI_RXDR);
3022e0a1eb9Skettenis 			else
3032e0a1eb9Skettenis 				HREAD4(sc, SPI_RXDR);
3042e0a1eb9Skettenis 			sc->sc_ridx++;
3052e0a1eb9Skettenis 		}
3062e0a1eb9Skettenis 
3072e0a1eb9Skettenis 		if (rkspi_wait_state(sc, SPI_SR_BSF, 0))
3082e0a1eb9Skettenis 			goto err;
3092e0a1eb9Skettenis 	}
3102e0a1eb9Skettenis 
3112e0a1eb9Skettenis 	HWRITE4(sc, SPI_ENR, 0);
3122e0a1eb9Skettenis 
3132e0a1eb9Skettenis 	if (!ISSET(flags, SPI_KEEP_CS))
3142e0a1eb9Skettenis 		HCLR4(sc, SPI_SER, SPI_SER_CS(sc->sc_cs));
3152e0a1eb9Skettenis 	return 0;
3162e0a1eb9Skettenis 
3172e0a1eb9Skettenis err:
3182e0a1eb9Skettenis 	HWRITE4(sc, SPI_ENR, 0);
3192e0a1eb9Skettenis 
3202e0a1eb9Skettenis 	HCLR4(sc, SPI_SER, SPI_SER_CS(sc->sc_cs));
3212e0a1eb9Skettenis 	return ETIMEDOUT;
3222e0a1eb9Skettenis }
3232e0a1eb9Skettenis 
3242e0a1eb9Skettenis int
rkspi_acquire_bus(void * cookie,int flags)3252e0a1eb9Skettenis rkspi_acquire_bus(void *cookie, int flags)
3262e0a1eb9Skettenis {
3272e0a1eb9Skettenis 	struct rkspi_softc *sc = cookie;
3282e0a1eb9Skettenis 
3292e0a1eb9Skettenis 	rw_enter(&sc->sc_buslock, RW_WRITE);
3302e0a1eb9Skettenis 	return 0;
3312e0a1eb9Skettenis }
3322e0a1eb9Skettenis 
3332e0a1eb9Skettenis void
rkspi_release_bus(void * cookie,int flags)3342e0a1eb9Skettenis rkspi_release_bus(void *cookie, int flags)
3352e0a1eb9Skettenis {
3362e0a1eb9Skettenis 	struct rkspi_softc *sc = cookie;
3372e0a1eb9Skettenis 
3382e0a1eb9Skettenis 	rw_exit(&sc->sc_buslock);
3392e0a1eb9Skettenis }
3402e0a1eb9Skettenis 
3412e0a1eb9Skettenis void
rkspi_scan(struct rkspi_softc * sc)3422e0a1eb9Skettenis rkspi_scan(struct rkspi_softc *sc)
3432e0a1eb9Skettenis {
3442e0a1eb9Skettenis 	struct spi_attach_args sa;
3452e0a1eb9Skettenis 	uint32_t reg[1];
3462e0a1eb9Skettenis 	char name[32];
3472e0a1eb9Skettenis 	int node;
3482e0a1eb9Skettenis 
3492e0a1eb9Skettenis 	for (node = OF_child(sc->sc_node); node; node = OF_peer(node)) {
3502e0a1eb9Skettenis 		memset(name, 0, sizeof(name));
3512e0a1eb9Skettenis 		memset(reg, 0, sizeof(reg));
3522e0a1eb9Skettenis 
3532e0a1eb9Skettenis 		if (OF_getprop(node, "compatible", name, sizeof(name)) == -1)
3542e0a1eb9Skettenis 			continue;
3552e0a1eb9Skettenis 		if (name[0] == '\0')
3562e0a1eb9Skettenis 			continue;
3572e0a1eb9Skettenis 
3582e0a1eb9Skettenis 		if (OF_getprop(node, "reg", &reg, sizeof(reg)) != sizeof(reg))
3592e0a1eb9Skettenis 			continue;
3602e0a1eb9Skettenis 
3612e0a1eb9Skettenis 		memset(&sa, 0, sizeof(sa));
3622e0a1eb9Skettenis 		sa.sa_tag = &sc->sc_tag;
3632e0a1eb9Skettenis 		sa.sa_name = name;
3642e0a1eb9Skettenis 		sa.sa_cookie = &node;
3652e0a1eb9Skettenis 
3662e0a1eb9Skettenis 		config_found(&sc->sc_dev, &sa, NULL);
3672e0a1eb9Skettenis 	}
3682e0a1eb9Skettenis }
369