xref: /freebsd/sys/dev/intel/spi.c (revision 3ddaf8200bc90b1410755ebac7b5c979ea90a2f6)
1d786719dSOleksandr Tymoshenko /*-
21f40866fSVal Packett  * SPDX-License-Identifier: BSD-2-Clause
31f40866fSVal Packett  *
4d786719dSOleksandr Tymoshenko  * Copyright (c) 2016 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
5d786719dSOleksandr Tymoshenko  * All rights reserved.
6d786719dSOleksandr Tymoshenko  *
7d786719dSOleksandr Tymoshenko  * Redistribution and use in source and binary forms, with or without
8d786719dSOleksandr Tymoshenko  * modification, are permitted provided that the following conditions
9d786719dSOleksandr Tymoshenko  * are met:
10d786719dSOleksandr Tymoshenko  * 1. Redistributions of source code must retain the above copyright
11d786719dSOleksandr Tymoshenko  *    notice, this list of conditions and the following disclaimer.
12d786719dSOleksandr Tymoshenko  * 2. Redistributions in binary form must reproduce the above copyright
13d786719dSOleksandr Tymoshenko  *    notice, this list of conditions and the following disclaimer in the
14d786719dSOleksandr Tymoshenko  *    documentation and/or other materials provided with the distribution.
15d786719dSOleksandr Tymoshenko  *
16d786719dSOleksandr Tymoshenko  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17d786719dSOleksandr Tymoshenko  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18d786719dSOleksandr Tymoshenko  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19d786719dSOleksandr Tymoshenko  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20d786719dSOleksandr Tymoshenko  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21d786719dSOleksandr Tymoshenko  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22d786719dSOleksandr Tymoshenko  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23d786719dSOleksandr Tymoshenko  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24d786719dSOleksandr Tymoshenko  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25d786719dSOleksandr Tymoshenko  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26d786719dSOleksandr Tymoshenko  * SUCH DAMAGE.
27d786719dSOleksandr Tymoshenko  */
28d786719dSOleksandr Tymoshenko 
29d786719dSOleksandr Tymoshenko #include "opt_acpi.h"
30d786719dSOleksandr Tymoshenko 
31d786719dSOleksandr Tymoshenko #include <sys/param.h>
32d786719dSOleksandr Tymoshenko #include <sys/bus.h>
335adcec04SVladimir Kondratyev #include <sys/kdb.h>
34d786719dSOleksandr Tymoshenko #include <sys/kernel.h>
35d786719dSOleksandr Tymoshenko #include <sys/module.h>
36d786719dSOleksandr Tymoshenko #include <sys/proc.h>
37d786719dSOleksandr Tymoshenko #include <sys/rman.h>
38d786719dSOleksandr Tymoshenko 
39d786719dSOleksandr Tymoshenko #include <machine/bus.h>
40d786719dSOleksandr Tymoshenko #include <machine/resource.h>
41d786719dSOleksandr Tymoshenko 
42d786719dSOleksandr Tymoshenko #include <dev/spibus/spi.h>
43d786719dSOleksandr Tymoshenko #include <dev/spibus/spibusvar.h>
44d786719dSOleksandr Tymoshenko 
451f40866fSVal Packett #include <dev/intel/spi.h>
46d786719dSOleksandr Tymoshenko 
47d786719dSOleksandr Tymoshenko /**
48d786719dSOleksandr Tymoshenko  *	Macros for driver mutex locking
49d786719dSOleksandr Tymoshenko  */
505adcec04SVladimir Kondratyev #define	INTELSPI_IN_POLLING_MODE()	(SCHEDULER_STOPPED() || kdb_active)
515adcec04SVladimir Kondratyev #define	INTELSPI_LOCK(_sc)		do {		\
525adcec04SVladimir Kondratyev 	if(!INTELSPI_IN_POLLING_MODE())			\
535adcec04SVladimir Kondratyev 		mtx_lock(&(_sc)->sc_mtx);		\
545adcec04SVladimir Kondratyev } while (0)
555adcec04SVladimir Kondratyev #define	INTELSPI_UNLOCK(_sc)		do {		\
565adcec04SVladimir Kondratyev 	if(!INTELSPI_IN_POLLING_MODE())			\
575adcec04SVladimir Kondratyev 		mtx_unlock(&(_sc)->sc_mtx);		\
585adcec04SVladimir Kondratyev } while (0)
59d786719dSOleksandr Tymoshenko #define	INTELSPI_LOCK_INIT(_sc)		\
60d786719dSOleksandr Tymoshenko 	mtx_init(&_sc->sc_mtx, device_get_nameunit((_sc)->sc_dev), \
61d786719dSOleksandr Tymoshenko 	    "intelspi", MTX_DEF)
62d786719dSOleksandr Tymoshenko #define	INTELSPI_LOCK_DESTROY(_sc)	mtx_destroy(&(_sc)->sc_mtx)
635adcec04SVladimir Kondratyev #define	INTELSPI_ASSERT_LOCKED(_sc)	do {		\
645adcec04SVladimir Kondratyev 	if(!INTELSPI_IN_POLLING_MODE())			\
655adcec04SVladimir Kondratyev 		mtx_assert(&(_sc)->sc_mtx, MA_OWNED);	\
665adcec04SVladimir Kondratyev } while (0)
675adcec04SVladimir Kondratyev #define	INTELSPI_ASSERT_UNLOCKED(_sc)	do {		\
685adcec04SVladimir Kondratyev 	if(!INTELSPI_IN_POLLING_MODE())			\
695adcec04SVladimir Kondratyev 		mtx_assert(&(_sc)->sc_mtx, MA_NOTOWNED);\
705adcec04SVladimir Kondratyev } while (0)
71d786719dSOleksandr Tymoshenko 
72d786719dSOleksandr Tymoshenko #define INTELSPI_WRITE(_sc, _off, _val)		\
73d786719dSOleksandr Tymoshenko     bus_write_4((_sc)->sc_mem_res, (_off), (_val))
74d786719dSOleksandr Tymoshenko #define INTELSPI_READ(_sc, _off)			\
75d786719dSOleksandr Tymoshenko     bus_read_4((_sc)->sc_mem_res, (_off))
76d786719dSOleksandr Tymoshenko 
77d786719dSOleksandr Tymoshenko #define	INTELSPI_BUSY		0x1
78d786719dSOleksandr Tymoshenko #define	TX_FIFO_THRESHOLD	2
79d786719dSOleksandr Tymoshenko #define	RX_FIFO_THRESHOLD	2
80d786719dSOleksandr Tymoshenko #define	CLOCK_DIV_10MHZ		5
81d786719dSOleksandr Tymoshenko #define	DATA_SIZE_8BITS		8
821f40866fSVal Packett #define	MAX_CLOCK_RATE		50000000
83d786719dSOleksandr Tymoshenko 
84d786719dSOleksandr Tymoshenko #define	CS_LOW		0
85d786719dSOleksandr Tymoshenko #define	CS_HIGH		1
86d786719dSOleksandr Tymoshenko 
87d786719dSOleksandr Tymoshenko #define	INTELSPI_SSPREG_SSCR0	 	0x0
881f40866fSVal Packett #define	 SSCR0_SCR(n)				((((n) - 1) & 0xfff) << 8)
89d786719dSOleksandr Tymoshenko #define	 SSCR0_SSE				(1 << 7)
90d786719dSOleksandr Tymoshenko #define	 SSCR0_FRF_SPI				(0 << 4)
91d786719dSOleksandr Tymoshenko #define	 SSCR0_DSS(n)				(((n) - 1) << 0)
92d786719dSOleksandr Tymoshenko #define	INTELSPI_SSPREG_SSCR1	 	0x4
93d786719dSOleksandr Tymoshenko #define	 SSCR1_TINTE				(1 << 19)
94d786719dSOleksandr Tymoshenko #define	 SSCR1_RFT(n)				(((n) - 1) << 10)
95d786719dSOleksandr Tymoshenko #define	 SSCR1_RFT_MASK				(0xf << 10)
96d786719dSOleksandr Tymoshenko #define	 SSCR1_TFT(n)				(((n) - 1) << 6)
97d786719dSOleksandr Tymoshenko #define	 SSCR1_SPI_SPH				(1 << 4)
98d786719dSOleksandr Tymoshenko #define	 SSCR1_SPI_SPO				(1 << 3)
99d786719dSOleksandr Tymoshenko #define	 SSCR1_MODE_MASK				(SSCR1_SPI_SPO | SSCR1_SPI_SPH)
100d786719dSOleksandr Tymoshenko #define	 SSCR1_TIE				(1 << 1)
101d786719dSOleksandr Tymoshenko #define	 SSCR1_RIE				(1 << 0)
102d786719dSOleksandr Tymoshenko #define	INTELSPI_SSPREG_SSSR	 	0x8
103d786719dSOleksandr Tymoshenko #define	 SSSR_RFL_MASK				(0xf << 12)
104d786719dSOleksandr Tymoshenko #define	 SSSR_TFL_MASK				(0xf << 8)
105d786719dSOleksandr Tymoshenko #define	 SSSR_RNE				(1 << 3)
106d786719dSOleksandr Tymoshenko #define	 SSSR_TNF				(1 << 2)
107d786719dSOleksandr Tymoshenko #define	INTELSPI_SSPREG_SSITR	 	0xC
108d786719dSOleksandr Tymoshenko #define	INTELSPI_SSPREG_SSDR	 	0x10
109d786719dSOleksandr Tymoshenko #define	INTELSPI_SSPREG_SSTO	 	0x28
110d786719dSOleksandr Tymoshenko #define	INTELSPI_SSPREG_SSPSP	 	0x2C
111d786719dSOleksandr Tymoshenko #define	INTELSPI_SSPREG_SSTSA	 	0x30
112d786719dSOleksandr Tymoshenko #define	INTELSPI_SSPREG_SSRSA	 	0x34
113d786719dSOleksandr Tymoshenko #define	INTELSPI_SSPREG_SSTSS	 	0x38
114d786719dSOleksandr Tymoshenko #define	INTELSPI_SSPREG_SSACD	 	0x3C
115d786719dSOleksandr Tymoshenko #define	INTELSPI_SSPREG_ITF	 	0x40
116d786719dSOleksandr Tymoshenko #define	INTELSPI_SSPREG_SITF	 	0x44
117d786719dSOleksandr Tymoshenko #define	INTELSPI_SSPREG_SIRF	 	0x48
1181f40866fSVal Packett #define SPI_CS_CTRL(sc) \
1191f40866fSVal Packett 	(intelspi_infos[sc->sc_vers].reg_lpss_base + \
1201f40866fSVal Packett 	 intelspi_infos[sc->sc_vers].reg_cs_ctrl)
121d786719dSOleksandr Tymoshenko #define	 SPI_CS_CTRL_CS_MASK			(3)
122d786719dSOleksandr Tymoshenko #define	 SPI_CS_CTRL_SW_MODE			(1 << 0)
123d786719dSOleksandr Tymoshenko #define	 SPI_CS_CTRL_HW_MODE			(1 << 0)
124d786719dSOleksandr Tymoshenko #define	 SPI_CS_CTRL_CS_HIGH			(1 << 1)
125d786719dSOleksandr Tymoshenko 
126b109946dSVladimir Kondratyev #define	INTELSPI_RESETS			0x204
127b109946dSVladimir Kondratyev #define	 INTELSPI_RESET_HOST			(1 << 0) | (1 << 1)
128b109946dSVladimir Kondratyev #define	 INTELSPI_RESET_DMA			(1 << 2)
129b109946dSVladimir Kondratyev 
130f56dbe7aSVladimir Kondratyev /* Same order as intelspi_vers */
131f56dbe7aSVladimir Kondratyev static const struct intelspi_info {
132f56dbe7aSVladimir Kondratyev 	uint32_t reg_lpss_base;
133f56dbe7aSVladimir Kondratyev 	uint32_t reg_cs_ctrl;
134f56dbe7aSVladimir Kondratyev } intelspi_infos[] = {
135f56dbe7aSVladimir Kondratyev 	[SPI_BAYTRAIL] = {
136f56dbe7aSVladimir Kondratyev 		.reg_lpss_base = 0x400,
137f56dbe7aSVladimir Kondratyev 		.reg_cs_ctrl = 0x18,
138f56dbe7aSVladimir Kondratyev 	},
139f56dbe7aSVladimir Kondratyev 	[SPI_BRASWELL] = {
140f56dbe7aSVladimir Kondratyev 		.reg_lpss_base = 0x400,
141f56dbe7aSVladimir Kondratyev 		.reg_cs_ctrl = 0x18,
142f56dbe7aSVladimir Kondratyev 	},
143f56dbe7aSVladimir Kondratyev 	[SPI_LYNXPOINT] = {
144f56dbe7aSVladimir Kondratyev 		.reg_lpss_base = 0x800,
145f56dbe7aSVladimir Kondratyev 		.reg_cs_ctrl = 0x18,
146f56dbe7aSVladimir Kondratyev 	},
147f56dbe7aSVladimir Kondratyev 	[SPI_SUNRISEPOINT] = {
148f56dbe7aSVladimir Kondratyev 		.reg_lpss_base = 0x200,
149f56dbe7aSVladimir Kondratyev 		.reg_cs_ctrl = 0x24,
150f56dbe7aSVladimir Kondratyev 	},
151f56dbe7aSVladimir Kondratyev };
152f56dbe7aSVladimir Kondratyev 
153d786719dSOleksandr Tymoshenko static void	intelspi_intr(void *);
154d786719dSOleksandr Tymoshenko 
155d786719dSOleksandr Tymoshenko static int
intelspi_txfifo_full(struct intelspi_softc * sc)156d786719dSOleksandr Tymoshenko intelspi_txfifo_full(struct intelspi_softc *sc)
157d786719dSOleksandr Tymoshenko {
158d786719dSOleksandr Tymoshenko 	uint32_t sssr;
159d786719dSOleksandr Tymoshenko 
160d786719dSOleksandr Tymoshenko 	INTELSPI_ASSERT_LOCKED(sc);
161d786719dSOleksandr Tymoshenko 
162d786719dSOleksandr Tymoshenko 	sssr = INTELSPI_READ(sc, INTELSPI_SSPREG_SSSR);
163d786719dSOleksandr Tymoshenko 	if (sssr & SSSR_TNF)
164d786719dSOleksandr Tymoshenko 		return (0);
165d786719dSOleksandr Tymoshenko 
166d786719dSOleksandr Tymoshenko 	return (1);
167d786719dSOleksandr Tymoshenko }
168d786719dSOleksandr Tymoshenko 
169d786719dSOleksandr Tymoshenko static int
intelspi_rxfifo_empty(struct intelspi_softc * sc)170d786719dSOleksandr Tymoshenko intelspi_rxfifo_empty(struct intelspi_softc *sc)
171d786719dSOleksandr Tymoshenko {
172d786719dSOleksandr Tymoshenko 	uint32_t sssr;
173d786719dSOleksandr Tymoshenko 
174d786719dSOleksandr Tymoshenko 	INTELSPI_ASSERT_LOCKED(sc);
175d786719dSOleksandr Tymoshenko 
176d786719dSOleksandr Tymoshenko 	sssr = INTELSPI_READ(sc, INTELSPI_SSPREG_SSSR);
177d786719dSOleksandr Tymoshenko 	if (sssr & SSSR_RNE)
178d786719dSOleksandr Tymoshenko 		return (0);
179d786719dSOleksandr Tymoshenko 	else
180d786719dSOleksandr Tymoshenko 		return (1);
181d786719dSOleksandr Tymoshenko }
182d786719dSOleksandr Tymoshenko 
183d786719dSOleksandr Tymoshenko static void
intelspi_fill_tx_fifo(struct intelspi_softc * sc)184d786719dSOleksandr Tymoshenko intelspi_fill_tx_fifo(struct intelspi_softc *sc)
185d786719dSOleksandr Tymoshenko {
186d786719dSOleksandr Tymoshenko 	struct spi_command *cmd;
187d786719dSOleksandr Tymoshenko 	uint32_t written;
188d786719dSOleksandr Tymoshenko 	uint8_t *data;
189d786719dSOleksandr Tymoshenko 
190d786719dSOleksandr Tymoshenko 	INTELSPI_ASSERT_LOCKED(sc);
191d786719dSOleksandr Tymoshenko 
192d786719dSOleksandr Tymoshenko 	cmd = sc->sc_cmd;
193d786719dSOleksandr Tymoshenko 	while (sc->sc_written < sc->sc_len &&
194d786719dSOleksandr Tymoshenko 	    !intelspi_txfifo_full(sc)) {
195d786719dSOleksandr Tymoshenko 		data = (uint8_t *)cmd->tx_cmd;
196d786719dSOleksandr Tymoshenko 		written = sc->sc_written++;
197d786719dSOleksandr Tymoshenko 
198d786719dSOleksandr Tymoshenko 		if (written >= cmd->tx_cmd_sz) {
199d786719dSOleksandr Tymoshenko 			data = (uint8_t *)cmd->tx_data;
200d786719dSOleksandr Tymoshenko 			written -= cmd->tx_cmd_sz;
201d786719dSOleksandr Tymoshenko 		}
202d786719dSOleksandr Tymoshenko 		INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSDR, data[written]);
203d786719dSOleksandr Tymoshenko 	}
204d786719dSOleksandr Tymoshenko }
205d786719dSOleksandr Tymoshenko 
206d786719dSOleksandr Tymoshenko static void
intelspi_drain_rx_fifo(struct intelspi_softc * sc)207d786719dSOleksandr Tymoshenko intelspi_drain_rx_fifo(struct intelspi_softc *sc)
208d786719dSOleksandr Tymoshenko {
209d786719dSOleksandr Tymoshenko 	struct spi_command *cmd;
210d786719dSOleksandr Tymoshenko 	uint32_t  read;
211d786719dSOleksandr Tymoshenko 	uint8_t *data;
212d786719dSOleksandr Tymoshenko 
213d786719dSOleksandr Tymoshenko 	INTELSPI_ASSERT_LOCKED(sc);
214d786719dSOleksandr Tymoshenko 
215d786719dSOleksandr Tymoshenko 	cmd = sc->sc_cmd;
216d786719dSOleksandr Tymoshenko 	while (sc->sc_read < sc->sc_len &&
217d786719dSOleksandr Tymoshenko 	    !intelspi_rxfifo_empty(sc)) {
218d786719dSOleksandr Tymoshenko 		data = (uint8_t *)cmd->rx_cmd;
219d786719dSOleksandr Tymoshenko 		read = sc->sc_read++;
220d786719dSOleksandr Tymoshenko 		if (read >= cmd->rx_cmd_sz) {
221d786719dSOleksandr Tymoshenko 			data = (uint8_t *)cmd->rx_data;
222d786719dSOleksandr Tymoshenko 			read -= cmd->rx_cmd_sz;
223d786719dSOleksandr Tymoshenko 		}
224d786719dSOleksandr Tymoshenko 		data[read] = INTELSPI_READ(sc, INTELSPI_SSPREG_SSDR) & 0xff;
225d786719dSOleksandr Tymoshenko 	}
226d786719dSOleksandr Tymoshenko }
227d786719dSOleksandr Tymoshenko 
228d786719dSOleksandr Tymoshenko static int
intelspi_transaction_done(struct intelspi_softc * sc)229d786719dSOleksandr Tymoshenko intelspi_transaction_done(struct intelspi_softc *sc)
230d786719dSOleksandr Tymoshenko {
231d786719dSOleksandr Tymoshenko 	int txfifo_empty;
232d786719dSOleksandr Tymoshenko 	uint32_t sssr;
233d786719dSOleksandr Tymoshenko 
234d786719dSOleksandr Tymoshenko 	INTELSPI_ASSERT_LOCKED(sc);
235d786719dSOleksandr Tymoshenko 
236d786719dSOleksandr Tymoshenko 	if (sc->sc_written != sc->sc_len ||
237d786719dSOleksandr Tymoshenko 	    sc->sc_read != sc->sc_len)
238d786719dSOleksandr Tymoshenko 		return (0);
239d786719dSOleksandr Tymoshenko 
240d786719dSOleksandr Tymoshenko 	sssr = INTELSPI_READ(sc, INTELSPI_SSPREG_SSSR);
241d786719dSOleksandr Tymoshenko 	txfifo_empty = ((sssr & SSSR_TFL_MASK) == 0) &&
242d786719dSOleksandr Tymoshenko 		(sssr & SSSR_TNF);
243d786719dSOleksandr Tymoshenko 
244d786719dSOleksandr Tymoshenko 	if (txfifo_empty && !(sssr & SSSR_RNE))
245d786719dSOleksandr Tymoshenko 		return (1);
246d786719dSOleksandr Tymoshenko 
247d786719dSOleksandr Tymoshenko 	return (0);
248d786719dSOleksandr Tymoshenko }
249d786719dSOleksandr Tymoshenko 
250d786719dSOleksandr Tymoshenko static int
intelspi_transact(struct intelspi_softc * sc)251d786719dSOleksandr Tymoshenko intelspi_transact(struct intelspi_softc *sc)
252d786719dSOleksandr Tymoshenko {
253d786719dSOleksandr Tymoshenko 
254d786719dSOleksandr Tymoshenko 	INTELSPI_ASSERT_LOCKED(sc);
255d786719dSOleksandr Tymoshenko 
256d786719dSOleksandr Tymoshenko 	/* TX - Fill up the FIFO. */
257d786719dSOleksandr Tymoshenko 	intelspi_fill_tx_fifo(sc);
258d786719dSOleksandr Tymoshenko 
259d786719dSOleksandr Tymoshenko 	/* RX - Drain the FIFO. */
260d786719dSOleksandr Tymoshenko 	intelspi_drain_rx_fifo(sc);
261d786719dSOleksandr Tymoshenko 
262d786719dSOleksandr Tymoshenko 	/* Check for end of transfer. */
263d786719dSOleksandr Tymoshenko 	return intelspi_transaction_done(sc);
264d786719dSOleksandr Tymoshenko }
265d786719dSOleksandr Tymoshenko 
266d786719dSOleksandr Tymoshenko static void
intelspi_intr(void * arg)267d786719dSOleksandr Tymoshenko intelspi_intr(void *arg)
268d786719dSOleksandr Tymoshenko {
269d786719dSOleksandr Tymoshenko 	struct intelspi_softc *sc;
270d786719dSOleksandr Tymoshenko 	uint32_t reg;
271d786719dSOleksandr Tymoshenko 
272d786719dSOleksandr Tymoshenko 	sc = (struct intelspi_softc *)arg;
273d786719dSOleksandr Tymoshenko 
274d786719dSOleksandr Tymoshenko 	INTELSPI_LOCK(sc);
275d786719dSOleksandr Tymoshenko 	if ((sc->sc_flags & INTELSPI_BUSY) == 0) {
276d786719dSOleksandr Tymoshenko 		INTELSPI_UNLOCK(sc);
277d786719dSOleksandr Tymoshenko 		return;
278d786719dSOleksandr Tymoshenko 	}
279d786719dSOleksandr Tymoshenko 
280d786719dSOleksandr Tymoshenko 	/* Check if SSP if off */
281d786719dSOleksandr Tymoshenko 	reg = INTELSPI_READ(sc, INTELSPI_SSPREG_SSSR);
282d786719dSOleksandr Tymoshenko 	if (reg == 0xffffffffU) {
283d786719dSOleksandr Tymoshenko 		INTELSPI_UNLOCK(sc);
284d786719dSOleksandr Tymoshenko 		return;
285d786719dSOleksandr Tymoshenko 	}
286d786719dSOleksandr Tymoshenko 
287d786719dSOleksandr Tymoshenko 	/* Check for end of transfer. */
288d786719dSOleksandr Tymoshenko 	if (intelspi_transact(sc)) {
289d786719dSOleksandr Tymoshenko 		/* Disable interrupts */
290d786719dSOleksandr Tymoshenko 		reg = INTELSPI_READ(sc, INTELSPI_SSPREG_SSCR1);
291d786719dSOleksandr Tymoshenko 		reg &= ~(SSCR1_TIE | SSCR1_RIE | SSCR1_TINTE);
292d786719dSOleksandr Tymoshenko 		INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSCR1, reg);
293d786719dSOleksandr Tymoshenko 		wakeup(sc->sc_dev);
294d786719dSOleksandr Tymoshenko 	}
295d786719dSOleksandr Tymoshenko 
296d786719dSOleksandr Tymoshenko 	INTELSPI_UNLOCK(sc);
297d786719dSOleksandr Tymoshenko }
298d786719dSOleksandr Tymoshenko 
299d786719dSOleksandr Tymoshenko static void
intelspi_init(struct intelspi_softc * sc)300d786719dSOleksandr Tymoshenko intelspi_init(struct intelspi_softc *sc)
301d786719dSOleksandr Tymoshenko {
302d786719dSOleksandr Tymoshenko 	uint32_t reg;
303d786719dSOleksandr Tymoshenko 
304d786719dSOleksandr Tymoshenko 	INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSCR0, 0);
305d786719dSOleksandr Tymoshenko 
306d786719dSOleksandr Tymoshenko 	/* Manual CS control */
3071f40866fSVal Packett 	reg = INTELSPI_READ(sc, SPI_CS_CTRL(sc));
308d786719dSOleksandr Tymoshenko 	reg &= ~(SPI_CS_CTRL_CS_MASK);
309d786719dSOleksandr Tymoshenko 	reg |= (SPI_CS_CTRL_SW_MODE | SPI_CS_CTRL_CS_HIGH);
3101f40866fSVal Packett 	INTELSPI_WRITE(sc, SPI_CS_CTRL(sc), reg);
311d786719dSOleksandr Tymoshenko 
312d786719dSOleksandr Tymoshenko 	/* Set TX/RX FIFO IRQ threshold levels */
313d786719dSOleksandr Tymoshenko 	reg = SSCR1_TFT(TX_FIFO_THRESHOLD) | SSCR1_RFT(RX_FIFO_THRESHOLD);
314d786719dSOleksandr Tymoshenko 	INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSCR1, reg);
315d786719dSOleksandr Tymoshenko 
316d786719dSOleksandr Tymoshenko 	reg = SSCR0_SCR(CLOCK_DIV_10MHZ);
317d786719dSOleksandr Tymoshenko 	/* Put SSP in SPI mode */
318d786719dSOleksandr Tymoshenko 	reg |= SSCR0_FRF_SPI;
319d786719dSOleksandr Tymoshenko 	/* Data size */
320d786719dSOleksandr Tymoshenko 	reg |= SSCR0_DSS(DATA_SIZE_8BITS);
321d786719dSOleksandr Tymoshenko 	/* Enable SSP */
322d786719dSOleksandr Tymoshenko 	reg |= SSCR0_SSE;
323d786719dSOleksandr Tymoshenko 	INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSCR0, reg);
324d786719dSOleksandr Tymoshenko }
325d786719dSOleksandr Tymoshenko 
326d786719dSOleksandr Tymoshenko static void
intelspi_set_cs(struct intelspi_softc * sc,int level)327d786719dSOleksandr Tymoshenko intelspi_set_cs(struct intelspi_softc *sc, int level)
328d786719dSOleksandr Tymoshenko {
329d786719dSOleksandr Tymoshenko 	uint32_t reg;
330d786719dSOleksandr Tymoshenko 
3311f40866fSVal Packett 	reg = INTELSPI_READ(sc, SPI_CS_CTRL(sc));
332d786719dSOleksandr Tymoshenko 	reg &= ~(SPI_CS_CTRL_CS_MASK);
333d786719dSOleksandr Tymoshenko 	reg |= SPI_CS_CTRL_SW_MODE;
334d786719dSOleksandr Tymoshenko 
335d786719dSOleksandr Tymoshenko 	if (level == CS_HIGH)
336d786719dSOleksandr Tymoshenko 		reg |= SPI_CS_CTRL_CS_HIGH;
337d786719dSOleksandr Tymoshenko 
3381f40866fSVal Packett 	INTELSPI_WRITE(sc, SPI_CS_CTRL(sc), reg);
339d786719dSOleksandr Tymoshenko }
340d786719dSOleksandr Tymoshenko 
3411f40866fSVal Packett int
intelspi_transfer(device_t dev,device_t child,struct spi_command * cmd)342d786719dSOleksandr Tymoshenko intelspi_transfer(device_t dev, device_t child, struct spi_command *cmd)
343d786719dSOleksandr Tymoshenko {
344d786719dSOleksandr Tymoshenko 	struct intelspi_softc *sc;
3451f40866fSVal Packett 	int err, poll_limit;
3461f40866fSVal Packett 	uint32_t sscr0, sscr1, mode, clock, cs_delay;
3471f40866fSVal Packett 	bool restart = false;
348d786719dSOleksandr Tymoshenko 
349d786719dSOleksandr Tymoshenko 	sc = device_get_softc(dev);
350d786719dSOleksandr Tymoshenko 	err = 0;
351d786719dSOleksandr Tymoshenko 
352d786719dSOleksandr Tymoshenko 	KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz,
353d786719dSOleksandr Tymoshenko 	    ("TX/RX command sizes should be equal"));
354d786719dSOleksandr Tymoshenko 	KASSERT(cmd->tx_data_sz == cmd->rx_data_sz,
355d786719dSOleksandr Tymoshenko 	    ("TX/RX data sizes should be equal"));
356d786719dSOleksandr Tymoshenko 
357d786719dSOleksandr Tymoshenko 	INTELSPI_LOCK(sc);
358d786719dSOleksandr Tymoshenko 
3595adcec04SVladimir Kondratyev 	if (!INTELSPI_IN_POLLING_MODE()) {
360d786719dSOleksandr Tymoshenko 		/* If the controller is in use wait until it is available. */
361d786719dSOleksandr Tymoshenko 		while (sc->sc_flags & INTELSPI_BUSY) {
3625adcec04SVladimir Kondratyev 			if ((cmd->flags & SPI_FLAG_NO_SLEEP) != 0) {
363d101156eSVladimir Kondratyev 				INTELSPI_UNLOCK(sc);
3641f40866fSVal Packett 				return (EBUSY);
365d101156eSVladimir Kondratyev 			}
366d786719dSOleksandr Tymoshenko 			err = mtx_sleep(dev, &sc->sc_mtx, 0, "intelspi", 0);
367d786719dSOleksandr Tymoshenko 			if (err == EINTR) {
368d786719dSOleksandr Tymoshenko 				INTELSPI_UNLOCK(sc);
369d786719dSOleksandr Tymoshenko 				return (err);
370d786719dSOleksandr Tymoshenko 			}
371d786719dSOleksandr Tymoshenko 		}
3725adcec04SVladimir Kondratyev 	} else {
3735adcec04SVladimir Kondratyev 		/*
3745adcec04SVladimir Kondratyev 		 * Now we are in the middle of other transfer. Try to reset
3755adcec04SVladimir Kondratyev 		 * controller state to get predictable context.
3765adcec04SVladimir Kondratyev 		 */
3775adcec04SVladimir Kondratyev 		if ((sc->sc_flags & INTELSPI_BUSY) != 0)
3785adcec04SVladimir Kondratyev 			intelspi_init(sc);
3795adcec04SVladimir Kondratyev 	}
380d786719dSOleksandr Tymoshenko 
381d786719dSOleksandr Tymoshenko 	/* Now we have control over SPI controller. */
382d786719dSOleksandr Tymoshenko 	sc->sc_flags = INTELSPI_BUSY;
383d786719dSOleksandr Tymoshenko 
3841f40866fSVal Packett 	/* Configure the clock rate and SPI mode. */
3851f40866fSVal Packett 	spibus_get_clock(child, &clock);
3861f40866fSVal Packett 	spibus_get_mode(child, &mode);
3871f40866fSVal Packett 
3881f40866fSVal Packett 	if (clock != sc->sc_clock || mode != sc->sc_mode) {
3891f40866fSVal Packett 		sscr0 = INTELSPI_READ(sc, INTELSPI_SSPREG_SSCR0);
3901f40866fSVal Packett 		sscr0 &= ~SSCR0_SSE;
3911f40866fSVal Packett 		INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSCR0, sscr0);
3921f40866fSVal Packett 		restart = true;
3931f40866fSVal Packett 	}
3941f40866fSVal Packett 
3951f40866fSVal Packett 	if (clock != sc->sc_clock) {
3961f40866fSVal Packett 		sscr0 = INTELSPI_READ(sc, INTELSPI_SSPREG_SSCR0);
3971f40866fSVal Packett 		sscr0 &= ~SSCR0_SCR(0xfff);
3981f40866fSVal Packett 		if (clock == 0)
3991f40866fSVal Packett 			sscr0 |= SSCR0_SCR(CLOCK_DIV_10MHZ);
4001f40866fSVal Packett 		else
4011f40866fSVal Packett 			sscr0 |= SSCR0_SCR(howmany(MAX_CLOCK_RATE, min(MAX_CLOCK_RATE, clock)));
4021f40866fSVal Packett 		INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSCR0, sscr0);
4031f40866fSVal Packett 		sc->sc_clock = clock;
4041f40866fSVal Packett 	}
4051f40866fSVal Packett 
4061f40866fSVal Packett 	if (mode != sc->sc_mode) {
4071f40866fSVal Packett 		sscr1 = INTELSPI_READ(sc, INTELSPI_SSPREG_SSCR1);
4081f40866fSVal Packett 		sscr1 &= ~SSCR1_MODE_MASK;
4091f40866fSVal Packett 		if (mode & SPIBUS_MODE_CPHA)
4101f40866fSVal Packett 			sscr1 |= SSCR1_SPI_SPH;
4111f40866fSVal Packett 		if (mode & SPIBUS_MODE_CPOL)
4121f40866fSVal Packett 			sscr1 |= SSCR1_SPI_SPO;
4131f40866fSVal Packett 		INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSCR1, sscr1);
4141f40866fSVal Packett 		sc->sc_mode = mode;
4151f40866fSVal Packett 	}
4161f40866fSVal Packett 
4171f40866fSVal Packett 	if (restart) {
4181f40866fSVal Packett 		sscr0 = INTELSPI_READ(sc, INTELSPI_SSPREG_SSCR0);
4191f40866fSVal Packett 		sscr0 |= SSCR0_SSE;
4201f40866fSVal Packett 		INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSCR0, sscr0);
4211f40866fSVal Packett 	}
4221f40866fSVal Packett 
423d786719dSOleksandr Tymoshenko 	/* Save a pointer to the SPI command. */
424d786719dSOleksandr Tymoshenko 	sc->sc_cmd = cmd;
425d786719dSOleksandr Tymoshenko 	sc->sc_read = 0;
426d786719dSOleksandr Tymoshenko 	sc->sc_written = 0;
427d786719dSOleksandr Tymoshenko 	sc->sc_len = cmd->tx_cmd_sz + cmd->tx_data_sz;
428d786719dSOleksandr Tymoshenko 
429d786719dSOleksandr Tymoshenko 	/* Enable CS */
430d786719dSOleksandr Tymoshenko 	intelspi_set_cs(sc, CS_LOW);
4311f40866fSVal Packett 
4321f40866fSVal Packett 	/* Wait the CS delay */
4331f40866fSVal Packett 	spibus_get_cs_delay(child, &cs_delay);
4341f40866fSVal Packett 	DELAY(cs_delay);
4351f40866fSVal Packett 
436d786719dSOleksandr Tymoshenko 	/* Transfer as much as possible to FIFOs */
4375adcec04SVladimir Kondratyev 	if ((cmd->flags & SPI_FLAG_NO_SLEEP) != 0 ||
4385adcec04SVladimir Kondratyev 	     INTELSPI_IN_POLLING_MODE() || cold) {
4391f40866fSVal Packett 		/* We cannot wait with mtx_sleep if we're called from e.g. an ithread */
4401f40866fSVal Packett 		poll_limit = 2000;
4411f40866fSVal Packett 		while (!intelspi_transact(sc) && poll_limit-- > 0)
4421f40866fSVal Packett 			DELAY(1000);
4431f40866fSVal Packett 		if (poll_limit == 0) {
4441f40866fSVal Packett 			device_printf(dev, "polling was stuck, transaction not finished\n");
4451f40866fSVal Packett 			err = EIO;
4461f40866fSVal Packett 		}
4471f40866fSVal Packett 	} else {
448d786719dSOleksandr Tymoshenko 		if (!intelspi_transact(sc)) {
449d786719dSOleksandr Tymoshenko 			/* If FIFO is not large enough - enable interrupts */
450d786719dSOleksandr Tymoshenko 			sscr1 = INTELSPI_READ(sc, INTELSPI_SSPREG_SSCR1);
451d786719dSOleksandr Tymoshenko 			sscr1 |= (SSCR1_TIE | SSCR1_RIE | SSCR1_TINTE);
452d786719dSOleksandr Tymoshenko 			INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSCR1, sscr1);
453d786719dSOleksandr Tymoshenko 
454d786719dSOleksandr Tymoshenko 			/* and wait for transaction to complete */
455d786719dSOleksandr Tymoshenko 			err = mtx_sleep(dev, &sc->sc_mtx, 0, "intelspi", hz * 2);
456d786719dSOleksandr Tymoshenko 		}
4571f40866fSVal Packett 	}
458d786719dSOleksandr Tymoshenko 
4591f40866fSVal Packett 	/* De-assert CS */
4601f40866fSVal Packett 	if ((cmd->flags & SPI_FLAG_KEEP_CS) == 0)
461d786719dSOleksandr Tymoshenko 		intelspi_set_cs(sc, CS_HIGH);
462d786719dSOleksandr Tymoshenko 
463d786719dSOleksandr Tymoshenko 	/* Clear transaction details */
464d786719dSOleksandr Tymoshenko 	sc->sc_cmd = NULL;
465d786719dSOleksandr Tymoshenko 	sc->sc_read = 0;
466d786719dSOleksandr Tymoshenko 	sc->sc_written = 0;
467d786719dSOleksandr Tymoshenko 	sc->sc_len = 0;
468d786719dSOleksandr Tymoshenko 
469d786719dSOleksandr Tymoshenko 	/* Make sure the SPI engine and interrupts are disabled. */
470d786719dSOleksandr Tymoshenko 	sscr1 = INTELSPI_READ(sc, INTELSPI_SSPREG_SSCR1);
471d786719dSOleksandr Tymoshenko 	sscr1 &= ~(SSCR1_TIE | SSCR1_RIE | SSCR1_TINTE);
472d786719dSOleksandr Tymoshenko 	INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSCR1, sscr1);
473d786719dSOleksandr Tymoshenko 
474d786719dSOleksandr Tymoshenko 	/* Release the controller and wakeup the next thread waiting for it. */
475d786719dSOleksandr Tymoshenko 	sc->sc_flags = 0;
4765adcec04SVladimir Kondratyev 	if (!INTELSPI_IN_POLLING_MODE())
477d786719dSOleksandr Tymoshenko 		wakeup_one(dev);
478d786719dSOleksandr Tymoshenko 	INTELSPI_UNLOCK(sc);
479d786719dSOleksandr Tymoshenko 
480d786719dSOleksandr Tymoshenko 	/*
481d786719dSOleksandr Tymoshenko 	 * Check for transfer timeout.  The SPI controller doesn't
482d786719dSOleksandr Tymoshenko 	 * return errors.
483d786719dSOleksandr Tymoshenko 	 */
484d786719dSOleksandr Tymoshenko 	if (err == EWOULDBLOCK) {
485d786719dSOleksandr Tymoshenko 		device_printf(sc->sc_dev, "transfer timeout\n");
486d786719dSOleksandr Tymoshenko 		err = EIO;
487d786719dSOleksandr Tymoshenko 	}
488d786719dSOleksandr Tymoshenko 
489d786719dSOleksandr Tymoshenko 	return (err);
490d786719dSOleksandr Tymoshenko }
491d786719dSOleksandr Tymoshenko 
4921f40866fSVal Packett int
intelspi_attach(device_t dev)493d786719dSOleksandr Tymoshenko intelspi_attach(device_t dev)
494d786719dSOleksandr Tymoshenko {
495d786719dSOleksandr Tymoshenko 	struct intelspi_softc	*sc;
496d786719dSOleksandr Tymoshenko 
497d786719dSOleksandr Tymoshenko 	sc = device_get_softc(dev);
498d786719dSOleksandr Tymoshenko 	sc->sc_dev = dev;
499d786719dSOleksandr Tymoshenko 
500d786719dSOleksandr Tymoshenko 	INTELSPI_LOCK_INIT(sc);
501d786719dSOleksandr Tymoshenko 
502d786719dSOleksandr Tymoshenko 	sc->sc_mem_res = bus_alloc_resource_any(sc->sc_dev,
503d786719dSOleksandr Tymoshenko 	    SYS_RES_MEMORY, &sc->sc_mem_rid, RF_ACTIVE);
504d786719dSOleksandr Tymoshenko 	if (sc->sc_mem_res == NULL) {
505d786719dSOleksandr Tymoshenko 		device_printf(dev, "can't allocate memory resource\n");
506d786719dSOleksandr Tymoshenko 		goto error;
507d786719dSOleksandr Tymoshenko 	}
508d786719dSOleksandr Tymoshenko 
509b109946dSVladimir Kondratyev 	/* Release LPSS reset */
510b109946dSVladimir Kondratyev 	if (sc->sc_vers == SPI_SUNRISEPOINT)
511b109946dSVladimir Kondratyev 		INTELSPI_WRITE(sc, INTELSPI_RESETS,
512b109946dSVladimir Kondratyev 		    (INTELSPI_RESET_HOST | INTELSPI_RESET_DMA));
513b109946dSVladimir Kondratyev 
514d786719dSOleksandr Tymoshenko 	sc->sc_irq_res = bus_alloc_resource_any(sc->sc_dev,
5151f40866fSVal Packett 	    SYS_RES_IRQ, &sc->sc_irq_rid, RF_ACTIVE | RF_SHAREABLE);
516d786719dSOleksandr Tymoshenko 	if (sc->sc_irq_res == NULL) {
517d786719dSOleksandr Tymoshenko 		device_printf(dev, "can't allocate IRQ resource\n");
518d786719dSOleksandr Tymoshenko 		goto error;
519d786719dSOleksandr Tymoshenko 	}
520d786719dSOleksandr Tymoshenko 
521d786719dSOleksandr Tymoshenko 	/* Hook up our interrupt handler. */
522d786719dSOleksandr Tymoshenko 	if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
523d786719dSOleksandr Tymoshenko 	    NULL, intelspi_intr, sc, &sc->sc_irq_ih)) {
524d786719dSOleksandr Tymoshenko 		device_printf(dev, "cannot setup the interrupt handler\n");
525d786719dSOleksandr Tymoshenko 		goto error;
526d786719dSOleksandr Tymoshenko 	}
527d786719dSOleksandr Tymoshenko 
528d786719dSOleksandr Tymoshenko 	intelspi_init(sc);
529d786719dSOleksandr Tymoshenko 
5305b56413dSWarner Losh 	device_add_child(dev, "spibus", DEVICE_UNIT_ANY);
531d786719dSOleksandr Tymoshenko 
53234f5de82SJohn Baldwin 	bus_delayed_attach_children(dev);
53334f5de82SJohn Baldwin 	return (0);
534d786719dSOleksandr Tymoshenko 
535d786719dSOleksandr Tymoshenko error:
536d786719dSOleksandr Tymoshenko 	INTELSPI_LOCK_DESTROY(sc);
537d786719dSOleksandr Tymoshenko 
538d786719dSOleksandr Tymoshenko 	if (sc->sc_mem_res != NULL)
539d786719dSOleksandr Tymoshenko 		bus_release_resource(dev, SYS_RES_MEMORY,
540d786719dSOleksandr Tymoshenko 		    sc->sc_mem_rid, sc->sc_mem_res);
541d786719dSOleksandr Tymoshenko 
542d786719dSOleksandr Tymoshenko 	if (sc->sc_irq_res != NULL)
5439ef958c7SMark Johnston 		bus_release_resource(dev, SYS_RES_IRQ,
544d786719dSOleksandr Tymoshenko 		    sc->sc_irq_rid, sc->sc_irq_res);
545d786719dSOleksandr Tymoshenko 
546d786719dSOleksandr Tymoshenko 	return (ENXIO);
547d786719dSOleksandr Tymoshenko }
548d786719dSOleksandr Tymoshenko 
5491f40866fSVal Packett int
intelspi_detach(device_t dev)550d786719dSOleksandr Tymoshenko intelspi_detach(device_t dev)
551d786719dSOleksandr Tymoshenko {
552d786719dSOleksandr Tymoshenko 	struct intelspi_softc	*sc;
553*3ddaf820SJohn Baldwin 	int error;
554d786719dSOleksandr Tymoshenko 
555d786719dSOleksandr Tymoshenko 	sc = device_get_softc(dev);
556d786719dSOleksandr Tymoshenko 
557*3ddaf820SJohn Baldwin 	error = bus_generic_detach(dev);
558*3ddaf820SJohn Baldwin 	if (error != 0)
559*3ddaf820SJohn Baldwin 		return (error);
560*3ddaf820SJohn Baldwin 
561d786719dSOleksandr Tymoshenko 	INTELSPI_LOCK_DESTROY(sc);
562d786719dSOleksandr Tymoshenko 
563d786719dSOleksandr Tymoshenko 	if (sc->sc_irq_ih)
564d786719dSOleksandr Tymoshenko 		bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_ih);
565d786719dSOleksandr Tymoshenko 
566d786719dSOleksandr Tymoshenko 	if (sc->sc_mem_res != NULL)
567d786719dSOleksandr Tymoshenko 		bus_release_resource(dev, SYS_RES_MEMORY,
568d786719dSOleksandr Tymoshenko 		    sc->sc_mem_rid, sc->sc_mem_res);
569d786719dSOleksandr Tymoshenko 
570d786719dSOleksandr Tymoshenko 	if (sc->sc_irq_res != NULL)
5719ef958c7SMark Johnston 		bus_release_resource(dev, SYS_RES_IRQ,
572d786719dSOleksandr Tymoshenko 		    sc->sc_irq_rid, sc->sc_irq_res);
573d786719dSOleksandr Tymoshenko 
574*3ddaf820SJohn Baldwin 	return (0);
575d786719dSOleksandr Tymoshenko }
576d786719dSOleksandr Tymoshenko 
5771f40866fSVal Packett int
intelspi_suspend(device_t dev)5781f40866fSVal Packett intelspi_suspend(device_t dev)
5791f40866fSVal Packett {
5801f40866fSVal Packett 	struct intelspi_softc        *sc;
5811f40866fSVal Packett 	int err, i;
582d786719dSOleksandr Tymoshenko 
5831f40866fSVal Packett 	sc = device_get_softc(dev);
584d786719dSOleksandr Tymoshenko 
5851f40866fSVal Packett 	err = bus_generic_suspend(dev);
5861f40866fSVal Packett 	if (err)
5871f40866fSVal Packett 		return (err);
588d786719dSOleksandr Tymoshenko 
5891f40866fSVal Packett 	for (i = 0; i < 9; i++) {
5901f40866fSVal Packett 		unsigned long offset = i * sizeof(uint32_t);
5911f40866fSVal Packett 		sc->sc_regs[i] = INTELSPI_READ(sc,
5921f40866fSVal Packett 		    intelspi_infos[sc->sc_vers].reg_lpss_base + offset);
5931f40866fSVal Packett 	}
594d786719dSOleksandr Tymoshenko 
5951f40866fSVal Packett 	/* Shutdown just in case */
5961f40866fSVal Packett 	INTELSPI_WRITE(sc, INTELSPI_SSPREG_SSCR0, 0);
5971f40866fSVal Packett 
5981f40866fSVal Packett 	return (0);
5991f40866fSVal Packett }
6001f40866fSVal Packett 
6011f40866fSVal Packett int
intelspi_resume(device_t dev)6021f40866fSVal Packett intelspi_resume(device_t dev)
6031f40866fSVal Packett {
6041f40866fSVal Packett 	struct intelspi_softc   *sc;
6051f40866fSVal Packett 	int i;
6061f40866fSVal Packett 
6071f40866fSVal Packett 	sc = device_get_softc(dev);
6081f40866fSVal Packett 
6091f40866fSVal Packett 	for (i = 0; i < 9; i++) {
6101f40866fSVal Packett 		unsigned long offset = i * sizeof(uint32_t);
6111f40866fSVal Packett 		INTELSPI_WRITE(sc,
6121f40866fSVal Packett 		    intelspi_infos[sc->sc_vers].reg_lpss_base + offset,
6131f40866fSVal Packett 		    sc->sc_regs[i]);
6141f40866fSVal Packett 	}
6151f40866fSVal Packett 
6161f40866fSVal Packett 	intelspi_init(sc);
6171f40866fSVal Packett 
6181f40866fSVal Packett 	/* Ensure the next transfer would reconfigure these */
6191f40866fSVal Packett 	sc->sc_clock = 0;
6201f40866fSVal Packett 	sc->sc_mode = 0;
6211f40866fSVal Packett 
6221f40866fSVal Packett 	return (bus_generic_resume(dev));
6231f40866fSVal Packett }
624