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