Lines Matching +full:no +full:- +full:cs +full:- +full:readback

1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
31 * Driver for imx Enhanced Configurable SPI; master-mode only.
143 {"fsl,imx51-ecspi", true},
144 {"fsl,imx53-ecspi", true},
145 {"fsl,imx6dl-ecspi", true},
146 {"fsl,imx6q-ecspi", true},
147 {"fsl,imx6sx-ecspi", true},
148 {"fsl,imx6ul-ecspi", true},
156 return (bus_read_4(sc->memres, offset)); in RD4()
163 bus_write_4(sc->memres, offset, value); in WR4()
172 if (sc->basefreq <= busfreq) in spi_calc_clockdiv()
176 * Brute-force this; all real-world bus speeds are going to be found on in spi_calc_clockdiv()
180 pre = ((sc->basefreq >> post) / busfreq) - 1; in spi_calc_clockdiv()
190 if (sc->debug >= 2) { in spi_calc_clockdiv()
191 device_printf(sc->dev, in spi_calc_clockdiv()
193 sc->basefreq, busfreq, pre, post, in spi_calc_clockdiv()
194 (sc->basefreq / (pre + 1)) / (1 << post)); in spi_calc_clockdiv()
201 spi_set_chipsel(struct spi_softc *sc, u_int cs, bool active) in spi_set_chipsel() argument
207 * active-high in the dts, but are supposed to be treated as active-low in spi_set_chipsel()
210 * slave can say its chipsel is active-high, so if that option is in spi_set_chipsel()
213 pinactive = !active ^ (bool)(cs & SPIBUS_CS_HIGH); in spi_set_chipsel()
215 if (sc->debug >= 2) { in spi_set_chipsel()
216 device_printf(sc->dev, "chipsel %u changed to %u\n", in spi_set_chipsel()
217 (cs & ~SPIBUS_CS_HIGH), pinactive); in spi_set_chipsel()
224 gpio_pin_set_active(sc->cspins[cs & ~SPIBUS_CS_HIGH], pinactive); in spi_set_chipsel()
225 gpio_pin_is_active(sc->cspins[cs & ~SPIBUS_CS_HIGH], &pinactive); in spi_set_chipsel()
229 spi_hw_setup(struct spi_softc *sc, u_int cs, u_int mode, u_int freq) in spi_hw_setup() argument
237 sc->ctlreg = CTLREG_EN | CTLREG_CMODES_MASTER | CTLREG_SMC; in spi_hw_setup()
238 sc->ctlreg |= spi_calc_clockdiv(sc, freq); in spi_hw_setup()
239 sc->ctlreg |= 7 << CTLREG_BLEN_SHIFT; /* XXX byte at a time */ in spi_hw_setup()
240 WR4(sc, ECSPI_CTLREG, sc->ctlreg); in spi_hw_setup()
244 * SPI hardware's chip-select set to zero. The actual chip select is in spi_hw_setup()
248 if (cs & SPIBUS_CS_HIGH) in spi_hw_setup()
276 while (sc->rxidx < sc->rxlen && (RD4(sc, ECSPI_STATREG) & SREG_RR)) { in spi_empty_rxfifo()
277 sc->rxbuf[sc->rxidx++] = (uint8_t)RD4(sc, ECSPI_RXDATA); in spi_empty_rxfifo()
278 --sc->fifocnt; in spi_empty_rxfifo()
286 while (sc->txidx < sc->txlen && sc->fifocnt < FIFO_SIZE) { in spi_fill_txfifo()
287 WR4(sc, ECSPI_TXDATA, sc->txbuf[sc->txidx++]); in spi_fill_txfifo()
288 ++sc->fifocnt; in spi_fill_txfifo()
295 if (sc->txidx == sc->txlen) in spi_fill_txfifo()
296 sc->intreg = (sc->intreg & ~INTREG_TDREN) | INTREG_TEEN; in spi_fill_txfifo()
305 mtx_lock(&sc->mtx); in spi_intr()
308 intreg = sc->intreg; in spi_intr()
318 if (sc->debug || bootverbose) { in spi_intr()
319 device_printf(sc->dev, "rxoverflow rxidx %u txidx %u\n", in spi_intr()
320 sc->rxidx, sc->txidx); in spi_intr()
322 sc->intreg = 0; in spi_intr()
324 mtx_unlock(&sc->mtx); in spi_intr()
336 * - If Transfer Complete is set (shift register is empty) and we've in spi_intr()
338 * - Else if Tx Fifo Empty is set, we need to stop waiting for that and in spi_intr()
342 if (sc->txidx == sc->txlen) { in spi_intr()
343 if ((status & SREG_TC) && sc->fifocnt == 0) { in spi_intr()
344 sc->intreg = 0; in spi_intr()
347 sc->intreg &= ~(sc->intreg & ~INTREG_TEEN); in spi_intr()
348 sc->intreg |= INTREG_TCEN | INTREG_RREN; in spi_intr()
354 * do a dummy readback to ensure the changes reach the hardware before in spi_intr()
357 if (sc->intreg != intreg) { in spi_intr()
358 WR4(sc, ECSPI_INTREG, sc->intreg); in spi_intr()
362 if (sc->debug >= 3) { in spi_intr()
363 device_printf(sc->dev, in spi_intr()
365 status, intreg, sc->intreg); in spi_intr()
368 mtx_unlock(&sc->mtx); in spi_intr()
376 if (sc->debug >= 1) { in spi_xfer_buf()
377 device_printf(sc->dev, in spi_xfer_buf()
385 sc->rxbuf = rxbuf; in spi_xfer_buf()
386 sc->rxlen = len; in spi_xfer_buf()
387 sc->rxidx = 0; in spi_xfer_buf()
388 sc->txbuf = txbuf; in spi_xfer_buf()
389 sc->txlen = len; in spi_xfer_buf()
390 sc->txidx = 0; in spi_xfer_buf()
391 sc->intreg = INTREG_RDREN | INTREG_TDREN; in spi_xfer_buf()
394 /* Enable interrupts last; spi_fill_txfifo() can change sc->intreg */ in spi_xfer_buf()
395 WR4(sc, ECSPI_INTREG, sc->intreg); in spi_xfer_buf()
398 while (err == 0 && sc->intreg != 0) in spi_xfer_buf()
399 err = msleep(sc, &sc->mtx, 0, "imxspi", 10 * hz); in spi_xfer_buf()
401 if (sc->rxidx != sc->rxlen || sc->txidx != sc->txlen) in spi_xfer_buf()
411 uint32_t cs, mode, clock; in spi_transfer() local
414 spibus_get_cs(child, &cs); in spi_transfer()
418 if (cs > CS_MAX || sc->cspins[cs] == NULL) { in spi_transfer()
419 if (sc->debug || bootverbose) in spi_transfer()
420 device_printf(sc->dev, "Invalid chip select %u\n", cs); in spi_transfer()
424 mtx_lock(&sc->mtx); in spi_transfer()
425 device_busy(sc->dev); in spi_transfer()
427 if (sc->debug >= 1) { in spi_transfer()
428 device_printf(sc->dev, in spi_transfer()
429 "spi_transfer, cs 0x%x clock %u mode %u\n", in spi_transfer()
430 cs, clock, mode); in spi_transfer()
434 spi_hw_setup(sc, cs, mode, clock); in spi_transfer()
435 spi_set_chipsel(sc, cs, true); in spi_transfer()
439 if (cmd->tx_cmd_sz > 0) in spi_transfer()
440 err = spi_xfer_buf(sc, cmd->rx_cmd, cmd->tx_cmd, in spi_transfer()
441 cmd->tx_cmd_sz); in spi_transfer()
442 if (cmd->tx_data_sz > 0 && err == 0) in spi_transfer()
443 err = spi_xfer_buf(sc, cmd->rx_data, cmd->tx_data, in spi_transfer()
444 cmd->tx_data_sz); in spi_transfer()
447 spi_set_chipsel(sc, cs, false); in spi_transfer()
450 device_unbusy(sc->dev); in spi_transfer()
451 mtx_unlock(&sc->mtx); in spi_transfer()
473 if ((error = bus_generic_detach(sc->dev)) != 0) in spi_detach()
476 for (idx = 0; idx < nitems(sc->cspins); ++idx) { in spi_detach()
477 if (sc->cspins[idx] != NULL) in spi_detach()
478 gpio_pin_release(sc->cspins[idx]); in spi_detach()
481 if (sc->inthandle != NULL) in spi_detach()
482 bus_teardown_intr(sc->dev, sc->intres, sc->inthandle); in spi_detach()
483 if (sc->intres != NULL) in spi_detach()
484 bus_release_resource(sc->dev, SYS_RES_IRQ, 0, sc->intres); in spi_detach()
485 if (sc->memres != NULL) in spi_detach()
486 bus_release_resource(sc->dev, SYS_RES_MEMORY, 0, sc->memres); in spi_detach()
488 mtx_destroy(&sc->mtx); in spi_detach()
500 sc->dev = dev; in spi_attach()
501 sc->basefreq = imx_ccm_ecspi_hz(); in spi_attach()
503 mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); in spi_attach()
505 /* Set up debug-enable sysctl. */ in spi_attach()
506 SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->dev), in spi_attach()
507 SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)), in spi_attach()
508 OID_AUTO, "debug", CTLFLAG_RWTUN, &sc->debug, 0, in spi_attach()
513 sc->memres = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, &rid, in spi_attach()
515 if (sc->memres == NULL) { in spi_attach()
516 device_printf(sc->dev, "could not allocate registers\n"); in spi_attach()
517 spi_detach(sc->dev); in spi_attach()
523 sc->intres = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &rid, in spi_attach()
525 if (sc->intres == NULL) { in spi_attach()
526 device_printf(sc->dev, "could not allocate interrupt\n"); in spi_attach()
527 device_detach(sc->dev); in spi_attach()
530 err = bus_setup_intr(sc->dev, sc->intres, INTR_TYPE_MISC | INTR_MPSAFE, in spi_attach()
531 NULL, spi_intr, sc, &sc->inthandle); in spi_attach()
533 device_printf(sc->dev, "could not setup interrupt handler"); in spi_attach()
534 device_detach(sc->dev); in spi_attach()
539 node = ofw_bus_get_node(sc->dev); in spi_attach()
540 for (idx = 0; idx < nitems(sc->cspins); ++idx) { in spi_attach()
541 err = gpio_pin_get_by_ofw_propidx(sc->dev, node, "cs-gpios", in spi_attach()
542 idx, &sc->cspins[idx]); in spi_attach()
544 gpio_pin_setflags(sc->cspins[idx], GPIO_PIN_OUTPUT); in spi_attach()
545 } else if (sc->debug >= 2) { in spi_attach()
546 device_printf(sc->dev, in spi_attach()
558 * Add the spibus driver as a child, and setup a one-shot intrhook to in spi_attach()
563 sc->spibus = device_add_child(dev, "spibus", DEVICE_UNIT_ANY); in spi_attach()
575 if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) in spi_probe()