imxspi.c revision 1.4
1/*	$NetBSD: imxspi.c,v 1.4 2019/08/13 17:03:10 tnn Exp $	*/
2
3/*-
4 * Copyright (c) 2014  Genetec Corporation.  All rights reserved.
5 * Written by Hashimoto Kenichi for Genetec Corporation.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORPORATION
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/*
30 * this module support CSPI and eCSPI.
31 * i.MX51 have 2 eCSPI and 1 CSPI modules.
32 */
33
34#include <sys/cdefs.h>
35__KERNEL_RCSID(0, "$NetBSD: imxspi.c,v 1.4 2019/08/13 17:03:10 tnn Exp $");
36
37#include "opt_imx.h"
38#include "opt_imxspi.h"
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/kernel.h>
43#include <sys/device.h>
44#include <sys/errno.h>
45#include <sys/proc.h>
46#include <sys/intr.h>
47
48#include <sys/bus.h>
49#include <machine/cpu.h>
50#include <machine/intr.h>
51
52#include <arm/imx/imxspivar.h>
53#include <arm/imx/imxspireg.h>
54
55/* SPI service routines */
56static int imxspi_configure_enhanced(void *, int, int, int);
57static int imxspi_configure(void *, int, int, int);
58static int imxspi_transfer(void *, struct spi_transfer *);
59static int imxspi_intr(void *);
60
61/* internal stuff */
62void imxspi_done(struct imxspi_softc *, int);
63void imxspi_send(struct imxspi_softc *);
64void imxspi_recv(struct imxspi_softc *);
65void imxspi_sched(struct imxspi_softc *);
66
67#define	IMXSPI(x)							      \
68	((sc->sc_enhanced) ? __CONCAT(ECSPI_, x) : __CONCAT(CSPI_, x))
69#define	READ_REG(sc, x)							      \
70	bus_space_read_4(sc->sc_iot, sc->sc_ioh, IMXSPI(x))
71#define	WRITE_REG(sc, x, v)						      \
72	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXSPI(x), (v))
73
74#ifdef IMXSPI_DEBUG
75int imxspi_debug = IMXSPI_DEBUG;
76#define	DPRINTFN(n,x)   if (imxspi_debug>(n)) printf x;
77#else
78#define	DPRINTFN(n,x)
79#endif
80
81int
82imxspi_attach_common(device_t parent, struct imxspi_softc *sc, void *aux)
83{
84	struct imxspi_attach_args *saa = aux;
85	struct spibus_attach_args sba;
86	bus_addr_t addr = saa->saa_addr;
87	bus_size_t size = saa->saa_size;
88
89	sc->sc_iot = saa->saa_iot;
90	sc->sc_freq = saa->saa_freq;
91	sc->sc_tag = saa->saa_tag;
92	sc->sc_enhanced = saa->saa_enhanced;
93	if (size <= 0)
94		size = SPI_SIZE;
95
96	if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh)) {
97		aprint_error_dev(sc->sc_dev, "couldn't map registers\n");
98		return 1;
99	}
100
101	aprint_normal(": i.MX %sCSPI Controller (clock %ld Hz)\n",
102	    ((sc->sc_enhanced) ? "e" : ""), sc->sc_freq);
103
104	/* Initialize SPI controller */
105	sc->sc_spi.sct_cookie = sc;
106	if (sc->sc_enhanced)
107		sc->sc_spi.sct_configure = imxspi_configure_enhanced;
108	else
109		sc->sc_spi.sct_configure = imxspi_configure;
110	sc->sc_spi.sct_transfer = imxspi_transfer;
111
112	/* sc->sc_spi.sct_nslaves must have been initialized by machdep code */
113	sc->sc_spi.sct_nslaves = saa->saa_nslaves;
114	if (!sc->sc_spi.sct_nslaves)
115		aprint_error_dev(sc->sc_dev, "no slaves!\n");
116
117	memset(&sba, 0, sizeof(sba));
118	sba.sba_controller = &sc->sc_spi;
119
120	/* initialize the queue */
121	SIMPLEQ_INIT(&sc->sc_q);
122
123	/* configure SPI */
124	/* Setup Control Register */
125	WRITE_REG(sc, CONREG, __SHIFTIN(0, IMXSPI(CON_DRCTL)) |
126	    __SHIFTIN(8 - 1, IMXSPI(CON_BITCOUNT)) |
127	    __SHIFTIN(0xf, IMXSPI(CON_MODE)) | IMXSPI(CON_ENABLE));
128
129	/* TC and RR interruption */
130	WRITE_REG(sc, INTREG,  (IMXSPI(INTR_TC_EN) | IMXSPI(INTR_RR_EN)));
131	WRITE_REG(sc, STATREG, IMXSPI(STAT_CLR));
132
133	WRITE_REG(sc, PERIODREG, 0x0);
134
135	/* enable device interrupts */
136	sc->sc_ih = intr_establish(saa->saa_irq, IPL_BIO, IST_LEVEL,
137	    imxspi_intr, sc);
138
139	/* attach slave devices */
140	(void)config_found_ia(sc->sc_dev, "spibus", &sba, spibus_print);
141
142	return 0;
143}
144
145static int
146imxspi_configure(void *arg, int slave, int mode, int speed)
147{
148	struct imxspi_softc *sc = arg;
149	uint32_t div_cnt = 0;
150	uint32_t div;
151	uint32_t contrl = 0;
152
153	div = (sc->sc_freq + (speed - 1)) / speed;
154	div = div - 1;
155	for (div_cnt = 0; div > 0; div_cnt++)
156		div >>= 1;
157
158	div_cnt = div_cnt - 2;
159	if (div_cnt >= 7)
160		div_cnt = 7;
161
162	contrl = READ_REG(sc, CONREG);
163	contrl &= ~CSPI_CON_DIV;
164	contrl |= __SHIFTIN(div_cnt, CSPI_CON_DIV);
165
166	contrl &= ~(CSPI_CON_POL | CSPI_CON_PHA);
167	switch (mode) {
168	case SPI_MODE_0:
169		/* CPHA = 0, CPOL = 0 */
170		break;
171	case SPI_MODE_1:
172		/* CPHA = 1, CPOL = 0 */
173		contrl |= CSPI_CON_PHA;
174		break;
175	case SPI_MODE_2:
176		/* CPHA = 0, CPOL = 1 */
177		contrl |= CSPI_CON_POL;
178		break;
179	case SPI_MODE_3:
180		/* CPHA = 1, CPOL = 1 */
181		contrl |= CSPI_CON_POL;
182		contrl |= CSPI_CON_PHA;
183		break;
184	default:
185		return EINVAL;
186	}
187	WRITE_REG(sc, CONREG, contrl);
188
189	DPRINTFN(3, ("%s: slave %d mode %d speed %d\n",
190		__func__, slave, mode, speed));
191
192	return 0;
193}
194
195static int
196imxspi_configure_enhanced(void *arg, int slave, int mode, int speed)
197{
198	struct imxspi_softc *sc = arg;
199	uint32_t div_cnt = 0;
200	uint32_t div;
201	uint32_t contrl = 0;
202	uint32_t config = 0;
203
204	div = (sc->sc_freq + (speed - 1)) / speed;
205	for (div_cnt = 0; div > 0; div_cnt++)
206		div >>= 1;
207
208	if (div_cnt >= 15)
209		div_cnt = 15;
210
211	contrl = READ_REG(sc, CONREG);
212	contrl |= __SHIFTIN(div_cnt, ECSPI_CON_DIV);
213	contrl |= __SHIFTIN(slave, ECSPI_CON_CS);
214	contrl |= __SHIFTIN(__BIT(slave), ECSPI_CON_MODE);
215	WRITE_REG(sc, CONREG, contrl);
216
217	config = bus_space_read_4(sc->sc_iot, sc->sc_ioh, ECSPI_CONFIGREG);
218	config &= ~(__SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_POL) |
219	    __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_PHA));
220	switch (mode) {
221	case SPI_MODE_0:
222		/* CPHA = 0, CPOL = 0 */
223		break;
224	case SPI_MODE_1:
225		/* CPHA = 1, CPOL = 0 */
226		config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_PHA);
227		break;
228	case SPI_MODE_2:
229		/* CPHA = 0, CPOL = 1 */
230		config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_POL);
231		break;
232	case SPI_MODE_3:
233		/* CPHA = 1, CPOL = 1 */
234		config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_PHA);
235		config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_POL);
236		break;
237	default:
238		return EINVAL;
239	}
240	config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SSB_CTL);
241	bus_space_write_4(sc->sc_iot, sc->sc_ioh, ECSPI_CONFIGREG, config);
242
243	DPRINTFN(3, ("%s: slave %d mode %d speed %d\n",
244		__func__, slave, mode, speed));
245
246	return 0;
247}
248
249void
250imxspi_send(struct imxspi_softc *sc)
251{
252	uint32_t data;
253	struct spi_chunk *chunk;
254
255	/* fill the fifo */
256	while ((chunk = sc->sc_wchunk) != NULL) {
257		while (chunk->chunk_wresid) {
258			/* transmit fifo full? */
259			if (READ_REG(sc, STATREG) & IMXSPI(STAT_TF))
260				goto out;
261
262			if (chunk->chunk_wptr) {
263				data = *chunk->chunk_wptr;
264				chunk->chunk_wptr++;
265			} else {
266				data = 0xff;
267			}
268			chunk->chunk_wresid--;
269
270			WRITE_REG(sc, TXDATA, data);
271		}
272		/* advance to next transfer */
273		sc->sc_wchunk = sc->sc_wchunk->chunk_next;
274	}
275out:
276	if (!(READ_REG(sc, STATREG) & IMXSPI(INTR_TE_EN)))
277		WRITE_REG(sc, CONREG, READ_REG(sc, CONREG) | IMXSPI(CON_XCH));
278}
279
280void
281imxspi_recv(struct imxspi_softc *sc)
282{
283	uint32_t		data;
284	struct spi_chunk	*chunk;
285
286	while ((chunk = sc->sc_rchunk) != NULL) {
287		while (chunk->chunk_rresid) {
288			/* rx fifo empty? */
289			if ((!(READ_REG(sc, STATREG) & IMXSPI(STAT_RR))))
290				return;
291
292			/* collect rx data */
293			data = READ_REG(sc, RXDATA);
294			if (chunk->chunk_rptr) {
295				*chunk->chunk_rptr = data & 0xff;
296				chunk->chunk_rptr++;
297			}
298
299			chunk->chunk_rresid--;
300		}
301		/* advance next to next transfer */
302		sc->sc_rchunk = sc->sc_rchunk->chunk_next;
303	}
304}
305
306
307void
308imxspi_sched(struct imxspi_softc *sc)
309{
310	struct spi_transfer *st;
311	uint32_t chipselect;
312
313	while ((st = spi_transq_first(&sc->sc_q)) != NULL) {
314		/* remove the item */
315		spi_transq_dequeue(&sc->sc_q);
316
317		/* note that we are working on it */
318		sc->sc_transfer = st;
319
320		/* chip slect */
321		if (sc->sc_tag->spi_cs_enable != NULL)
322			sc->sc_tag->spi_cs_enable(sc->sc_tag->cookie,
323			    st->st_slave);
324
325		/* chip slect */
326		chipselect = READ_REG(sc, CONREG);
327		chipselect &= ~IMXSPI(CON_CS);
328		chipselect |= __SHIFTIN(st->st_slave, IMXSPI(CON_CS));
329		WRITE_REG(sc, CONREG, chipselect);
330
331		delay(1);
332
333		/* setup chunks */
334		sc->sc_rchunk = sc->sc_wchunk = st->st_chunks;
335
336		/* now kick the master start to get the chip running */
337		imxspi_send(sc);
338
339		sc->sc_running = TRUE;
340		return;
341	}
342
343	DPRINTFN(2, ("%s: nothing to do anymore\n", __func__));
344	sc->sc_running = FALSE;
345}
346
347void
348imxspi_done(struct imxspi_softc *sc, int err)
349{
350	struct spi_transfer *st;
351
352	/* called from interrupt handler */
353	if ((st = sc->sc_transfer) != NULL) {
354		if (sc->sc_tag->spi_cs_disable != NULL)
355			sc->sc_tag->spi_cs_disable(sc->sc_tag->cookie,
356			    st->st_slave);
357
358		sc->sc_transfer = NULL;
359		spi_done(st, err);
360	}
361	/* make sure we clear these bits out */
362	sc->sc_wchunk = sc->sc_rchunk = NULL;
363	imxspi_sched(sc);
364}
365
366static int
367imxspi_intr(void *arg)
368{
369	struct imxspi_softc *sc = arg;
370	uint32_t intr, sr;
371	int err = 0;
372
373	if ((intr = READ_REG(sc, INTREG)) == 0) {
374		/* interrupts are not enabled, get out */
375		DPRINTFN(4, ("%s: interrupts are not enabled\n", __func__));
376		return 0;
377	}
378
379	sr = READ_REG(sc, STATREG);
380	if (!(sr & intr)) {
381		/* interrupt did not happen, get out */
382		DPRINTFN(3, ("%s: interrupts did not happen\n", __func__));
383		return 0;
384	}
385
386	/* RXFIFO ready? */
387	if (sr & IMXSPI(INTR_RR_EN)) {
388		imxspi_recv(sc);
389		if (sc->sc_wchunk == NULL && sc->sc_rchunk == NULL)
390			imxspi_done(sc, err);
391	}
392
393	/* Transfer Conplete? */
394	if (sr & IMXSPI(INTR_TC_EN)) {
395		/* complete TX */
396		imxspi_send(sc);
397	}
398
399	/* status register clear */
400	WRITE_REG(sc, STATREG, sr);
401
402	return 1;
403}
404
405int
406imxspi_transfer(void *arg, struct spi_transfer *st)
407{
408	struct imxspi_softc *sc = arg;
409	int s;
410
411	/* make sure we select the right chip */
412	s = splbio();
413	spi_transq_enqueue(&sc->sc_q, st);
414	if (sc->sc_running == FALSE)
415		imxspi_sched(sc);
416	splx(s);
417
418	return 0;
419}
420
421