Home | History | Annotate | Line # | Download | only in imx
      1 /*	$NetBSD: imxspi.c,v 1.15 2025/09/10 04:17:18 thorpej 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.15 2025/09/10 04:17:18 thorpej Exp $");
     36 
     37 #include "opt_imxspi.h"
     38 
     39 #include <sys/param.h>
     40 #include <sys/systm.h>
     41 #include <sys/kernel.h>
     42 #include <sys/device.h>
     43 #include <sys/errno.h>
     44 #include <sys/proc.h>
     45 #include <sys/intr.h>
     46 
     47 #include <sys/bus.h>
     48 #include <machine/cpu.h>
     49 #include <machine/intr.h>
     50 
     51 #include <arm/imx/imxspivar.h>
     52 #include <arm/imx/imxspireg.h>
     53 
     54 /* SPI service routines */
     55 static int imxspi_configure_enhanced(void *, int, int, int);
     56 static int imxspi_configure(void *, int, int, int);
     57 static int imxspi_transfer(void *, struct spi_transfer *);
     58 
     59 /* internal stuff */
     60 void imxspi_done(struct imxspi_softc *, int);
     61 void imxspi_send(struct imxspi_softc *);
     62 void imxspi_recv(struct imxspi_softc *);
     63 void imxspi_sched(struct imxspi_softc *);
     64 
     65 #define	IMXCSPI_TYPE(type, x)						      \
     66 	((sc->sc_type == IMX31_CSPI) ? __CONCAT(CSPI_IMX31_, x) :	      \
     67 	 (sc->sc_type == IMX35_CSPI) ? __CONCAT(CSPI_IMX35_, x) : 0)
     68 #define	IMXCSPI(x)	__CONCAT(CSPI_, x)
     69 #define	IMXESPI(x)	__CONCAT(ECSPI_, x)
     70 #define	IMXSPI(x)	((sc->sc_enhanced) ? IMXESPI(x) : IMXCSPI(x))
     71 #define	IMXSPI_TYPE(x)	((sc->sc_enhanced) ? IMXESPI(x) : IMXCSPI_TYPE(sc->sc_type, x))
     72 #define	READ_REG(sc, x)							      \
     73 	bus_space_read_4(sc->sc_iot, sc->sc_ioh, IMXSPI(x))
     74 #define	WRITE_REG(sc, x, v)						      \
     75 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXSPI(x), (v))
     76 
     77 #ifdef IMXSPI_DEBUG
     78 int imxspi_debug = IMXSPI_DEBUG;
     79 #define	DPRINTFN(n,x)   if (imxspi_debug>(n)) printf x;
     80 #else
     81 #define	DPRINTFN(n,x)
     82 #endif
     83 
     84 int
     85 imxspi_attach_common(device_t self)
     86 {
     87 	struct imxspi_softc * const sc = device_private(self);
     88 
     89 	aprint_normal("i.MX %sCSPI Controller (clock %ld Hz)\n",
     90 	    ((sc->sc_enhanced) ? "e" : ""), sc->sc_freq);
     91 
     92 	/* Initialize SPI controller */
     93 	sc->sc_dev = self;
     94 	sc->sc_spi.sct_cookie = sc;
     95 	if (sc->sc_enhanced)
     96 		sc->sc_spi.sct_configure = imxspi_configure_enhanced;
     97 	else
     98 		sc->sc_spi.sct_configure = imxspi_configure;
     99 	sc->sc_spi.sct_transfer = imxspi_transfer;
    100 
    101 	/* sc->sc_spi.sct_nslaves must have been initialized by machdep code */
    102 	sc->sc_spi.sct_nslaves = sc->sc_nslaves;
    103 	if (!sc->sc_spi.sct_nslaves)
    104 		aprint_error_dev(sc->sc_dev, "no slaves!\n");
    105 
    106 	/* initialize the queue */
    107 	SIMPLEQ_INIT(&sc->sc_q);
    108 
    109 	/* configure SPI */
    110 	/* Setup Control Register */
    111 	WRITE_REG(sc, CONREG,
    112 	    __SHIFTIN(0, IMXSPI_TYPE(CON_DRCTL)) |
    113 	    __SHIFTIN(8 - 1, IMXSPI_TYPE(CON_BITCOUNT)) |
    114 	    __SHIFTIN(0xf, IMXSPI(CON_MODE)) | IMXSPI(CON_ENABLE));
    115 	/* TC and RR interruption */
    116 	WRITE_REG(sc, INTREG, (IMXSPI_TYPE(INTR_TC_EN) | IMXSPI(INTR_RR_EN)));
    117 	WRITE_REG(sc, STATREG, IMXSPI_TYPE(STAT_CLR));
    118 
    119 	WRITE_REG(sc, PERIODREG, 0x0);
    120 
    121 	spibus_attach(self, &sc->sc_spi);
    122 
    123 	return 0;
    124 }
    125 
    126 static int
    127 imxspi_configure(void *arg, int slave, int mode, int speed)
    128 {
    129 	struct imxspi_softc *sc = arg;
    130 	uint32_t div_cnt = 0;
    131 	uint32_t div;
    132 	uint32_t contrl = 0;
    133 
    134 	div = (sc->sc_freq + (speed - 1)) / speed;
    135 	div = div - 1;
    136 	for (div_cnt = 0; div > 0; div_cnt++)
    137 		div >>= 1;
    138 
    139 	div_cnt = div_cnt - 2;
    140 	if (div_cnt >= 7)
    141 		div_cnt = 7;
    142 
    143 	contrl = READ_REG(sc, CONREG);
    144 	contrl &= ~CSPI_CON_DIV;
    145 	contrl |= __SHIFTIN(div_cnt, CSPI_CON_DIV);
    146 
    147 	contrl &= ~(CSPI_CON_POL | CSPI_CON_PHA);
    148 	switch (mode) {
    149 	case SPI_MODE_0:
    150 		/* CPHA = 0, CPOL = 0 */
    151 		break;
    152 	case SPI_MODE_1:
    153 		/* CPHA = 1, CPOL = 0 */
    154 		contrl |= CSPI_CON_PHA;
    155 		break;
    156 	case SPI_MODE_2:
    157 		/* CPHA = 0, CPOL = 1 */
    158 		contrl |= CSPI_CON_POL;
    159 		break;
    160 	case SPI_MODE_3:
    161 		/* CPHA = 1, CPOL = 1 */
    162 		contrl |= CSPI_CON_POL;
    163 		contrl |= CSPI_CON_PHA;
    164 		break;
    165 	default:
    166 		return EINVAL;
    167 	}
    168 	WRITE_REG(sc, CONREG, contrl);
    169 
    170 	DPRINTFN(3, ("%s: slave %d mode %d speed %d\n",
    171 		__func__, slave, mode, speed));
    172 
    173 	return 0;
    174 }
    175 
    176 static int
    177 imxspi_configure_enhanced(void *arg, int slave, int mode, int speed)
    178 {
    179 	struct imxspi_softc *sc = arg;
    180 	uint32_t div_cnt = 0;
    181 	uint32_t div;
    182 	uint32_t contrl = 0;
    183 	uint32_t config = 0;
    184 
    185 	div = (sc->sc_freq + (speed - 1)) / speed;
    186 	for (div_cnt = 0; div > 0; div_cnt++)
    187 		div >>= 1;
    188 
    189 	if (div_cnt >= 15)
    190 		div_cnt = 15;
    191 
    192 	contrl = READ_REG(sc, CONREG);
    193 	contrl |= __SHIFTIN(div_cnt, ECSPI_CON_DIV);
    194 	contrl |= __SHIFTIN(slave, ECSPI_CON_CS);
    195 	contrl |= __SHIFTIN(__BIT(slave), ECSPI_CON_MODE);
    196 	WRITE_REG(sc, CONREG, contrl);
    197 
    198 	config = bus_space_read_4(sc->sc_iot, sc->sc_ioh, ECSPI_CONFIGREG);
    199 	config &= ~(__SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_POL) |
    200 	    __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_CTL) |
    201 	    __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_PHA));
    202 	switch (mode) {
    203 	case SPI_MODE_0:
    204 		/* CPHA = 0, CPOL = 0 */
    205 		break;
    206 	case SPI_MODE_1:
    207 		/* CPHA = 1, CPOL = 0 */
    208 		config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_PHA);
    209 		break;
    210 	case SPI_MODE_2:
    211 		/* CPHA = 0, CPOL = 1 */
    212 		config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_POL);
    213 		config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_CTL);
    214 		break;
    215 	case SPI_MODE_3:
    216 		/* CPHA = 1, CPOL = 1 */
    217 		config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_PHA);
    218 		config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_POL);
    219 		config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_CTL);
    220 		break;
    221 	default:
    222 		return EINVAL;
    223 	}
    224 	config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SSB_CTL);
    225 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, ECSPI_CONFIGREG, config);
    226 
    227 	DPRINTFN(3, ("%s: slave %d mode %d speed %d\n",
    228 		__func__, slave, mode, speed));
    229 
    230 	return 0;
    231 }
    232 
    233 void
    234 imxspi_send(struct imxspi_softc *sc)
    235 {
    236 	uint32_t data;
    237 	struct spi_chunk *chunk;
    238 
    239 	/* fill the fifo */
    240 	while ((chunk = sc->sc_wchunk) != NULL) {
    241 		while (chunk->chunk_wresid) {
    242 			/* transmit fifo full? */
    243 			if (READ_REG(sc, STATREG) & IMXSPI(STAT_TF))
    244 				goto out;
    245 
    246 			if (chunk->chunk_wptr) {
    247 				data = *chunk->chunk_wptr;
    248 				chunk->chunk_wptr++;
    249 			} else {
    250 				data = 0xff;
    251 			}
    252 			chunk->chunk_wresid--;
    253 
    254 			WRITE_REG(sc, TXDATA, data);
    255 		}
    256 		/* advance to next transfer */
    257 		sc->sc_wchunk = sc->sc_wchunk->chunk_next;
    258 	}
    259 out:
    260 	if (!(READ_REG(sc, STATREG) & IMXSPI(INTR_TE_EN)))
    261 		WRITE_REG(sc, CONREG, READ_REG(sc, CONREG) | IMXSPI(CON_XCH));
    262 }
    263 
    264 void
    265 imxspi_recv(struct imxspi_softc *sc)
    266 {
    267 	uint32_t		data;
    268 	struct spi_chunk	*chunk;
    269 
    270 	while ((chunk = sc->sc_rchunk) != NULL) {
    271 		while (chunk->chunk_rresid) {
    272 			/* rx fifo empty? */
    273 			if ((!(READ_REG(sc, STATREG) & IMXSPI(STAT_RR))))
    274 				return;
    275 
    276 			/* collect rx data */
    277 			data = READ_REG(sc, RXDATA);
    278 			if (chunk->chunk_rptr) {
    279 				*chunk->chunk_rptr = data & 0xff;
    280 				chunk->chunk_rptr++;
    281 			}
    282 
    283 			chunk->chunk_rresid--;
    284 		}
    285 		/* advance next to next transfer */
    286 		sc->sc_rchunk = sc->sc_rchunk->chunk_next;
    287 	}
    288 }
    289 
    290 
    291 void
    292 imxspi_sched(struct imxspi_softc *sc)
    293 {
    294 	struct spi_transfer *st;
    295 	uint32_t chipselect;
    296 
    297 	while ((st = spi_transq_first(&sc->sc_q)) != NULL) {
    298 		/* remove the item */
    299 		spi_transq_dequeue(&sc->sc_q);
    300 
    301 		/* note that we are working on it */
    302 		sc->sc_transfer = st;
    303 
    304 		/* chip select */
    305 		if (sc->sc_tag->spi_cs_enable != NULL)
    306 			sc->sc_tag->spi_cs_enable(sc->sc_tag->cookie,
    307 			    st->st_slave);
    308 
    309 		/* chip select */
    310 		chipselect = READ_REG(sc, CONREG);
    311 		chipselect &= ~IMXSPI_TYPE(CON_CS);
    312 		chipselect |= __SHIFTIN(st->st_slave, IMXSPI_TYPE(CON_CS));
    313 		WRITE_REG(sc, CONREG, chipselect);
    314 
    315 		delay(1);
    316 
    317 		/* setup chunks */
    318 		sc->sc_rchunk = sc->sc_wchunk = st->st_chunks;
    319 
    320 		/* now kick the master start to get the chip running */
    321 		imxspi_send(sc);
    322 
    323 		sc->sc_running = TRUE;
    324 		return;
    325 	}
    326 
    327 	DPRINTFN(2, ("%s: nothing to do anymore\n", __func__));
    328 	sc->sc_running = FALSE;
    329 }
    330 
    331 void
    332 imxspi_done(struct imxspi_softc *sc, int err)
    333 {
    334 	struct spi_transfer *st;
    335 
    336 	/* called from interrupt handler */
    337 	if ((st = sc->sc_transfer) != NULL) {
    338 		if (sc->sc_tag->spi_cs_disable != NULL)
    339 			sc->sc_tag->spi_cs_disable(sc->sc_tag->cookie,
    340 			    st->st_slave);
    341 
    342 		sc->sc_transfer = NULL;
    343 		spi_done(st, err);
    344 	}
    345 	/* make sure we clear these bits out */
    346 	sc->sc_wchunk = sc->sc_rchunk = NULL;
    347 	imxspi_sched(sc);
    348 }
    349 
    350 int
    351 imxspi_intr(void *arg)
    352 {
    353 	struct imxspi_softc *sc = arg;
    354 	uint32_t intr, sr;
    355 	int err = 0;
    356 
    357 	if ((intr = READ_REG(sc, INTREG)) == 0) {
    358 		/* interrupts are not enabled, get out */
    359 		DPRINTFN(4, ("%s: interrupts are not enabled\n", __func__));
    360 		return 0;
    361 	}
    362 
    363 	sr = READ_REG(sc, STATREG);
    364 	if (!(sr & intr)) {
    365 		/* interrupt did not happen, get out */
    366 		DPRINTFN(3, ("%s: interrupts did not happen\n", __func__));
    367 		return 0;
    368 	}
    369 
    370 	/* RXFIFO ready? */
    371 	if (sr & IMXSPI(INTR_RR_EN)) {
    372 		imxspi_recv(sc);
    373 		if (sc->sc_wchunk == NULL && sc->sc_rchunk == NULL)
    374 			imxspi_done(sc, err);
    375 	}
    376 
    377 	/* Transfer Complete? */
    378 	if (sr & IMXSPI_TYPE(INTR_TC_EN))
    379 		imxspi_send(sc);
    380 
    381 	/* status register clear */
    382 	WRITE_REG(sc, STATREG, sr);
    383 
    384 	return 1;
    385 }
    386 
    387 int
    388 imxspi_transfer(void *arg, struct spi_transfer *st)
    389 {
    390 	struct imxspi_softc *sc = arg;
    391 	int s;
    392 
    393 	/* make sure we select the right chip */
    394 	s = splbio();
    395 	spi_transq_enqueue(&sc->sc_q, st);
    396 	if (sc->sc_running == FALSE)
    397 		imxspi_sched(sc);
    398 	splx(s);
    399 
    400 	return 0;
    401 }
    402 
    403