1*b68d413bShkenken /* $NetBSD: imxspi.c,v 1.5 2019/08/19 11:41:36 hkenken Exp $ */ 25f3c2fa2Shkenken 35f3c2fa2Shkenken /*- 45f3c2fa2Shkenken * Copyright (c) 2014 Genetec Corporation. All rights reserved. 55f3c2fa2Shkenken * Written by Hashimoto Kenichi for Genetec Corporation. 65f3c2fa2Shkenken * 75f3c2fa2Shkenken * Redistribution and use in source and binary forms, with or without 85f3c2fa2Shkenken * modification, are permitted provided that the following conditions 95f3c2fa2Shkenken * are met: 105f3c2fa2Shkenken * 1. Redistributions of source code must retain the above copyright 115f3c2fa2Shkenken * notice, this list of conditions and the following disclaimer. 125f3c2fa2Shkenken * 2. Redistributions in binary form must reproduce the above copyright 135f3c2fa2Shkenken * notice, this list of conditions and the following disclaimer in the 145f3c2fa2Shkenken * documentation and/or other materials provided with the distribution. 155f3c2fa2Shkenken * 165f3c2fa2Shkenken * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND 175f3c2fa2Shkenken * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 185f3c2fa2Shkenken * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 195f3c2fa2Shkenken * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION 205f3c2fa2Shkenken * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 215f3c2fa2Shkenken * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 225f3c2fa2Shkenken * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 235f3c2fa2Shkenken * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 245f3c2fa2Shkenken * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 255f3c2fa2Shkenken * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 265f3c2fa2Shkenken * POSSIBILITY OF SUCH DAMAGE. 275f3c2fa2Shkenken */ 285f3c2fa2Shkenken 295f3c2fa2Shkenken /* 305f3c2fa2Shkenken * this module support CSPI and eCSPI. 315f3c2fa2Shkenken * i.MX51 have 2 eCSPI and 1 CSPI modules. 325f3c2fa2Shkenken */ 335f3c2fa2Shkenken 345f3c2fa2Shkenken #include <sys/cdefs.h> 35*b68d413bShkenken __KERNEL_RCSID(0, "$NetBSD: imxspi.c,v 1.5 2019/08/19 11:41:36 hkenken Exp $"); 365f3c2fa2Shkenken 375f3c2fa2Shkenken #include "opt_imx.h" 385f3c2fa2Shkenken #include "opt_imxspi.h" 39*b68d413bShkenken #include "opt_fdt.h" 405f3c2fa2Shkenken 415f3c2fa2Shkenken #include <sys/param.h> 425f3c2fa2Shkenken #include <sys/systm.h> 435f3c2fa2Shkenken #include <sys/kernel.h> 445f3c2fa2Shkenken #include <sys/device.h> 455f3c2fa2Shkenken #include <sys/errno.h> 465f3c2fa2Shkenken #include <sys/proc.h> 475f3c2fa2Shkenken #include <sys/intr.h> 485f3c2fa2Shkenken 495f3c2fa2Shkenken #include <sys/bus.h> 505f3c2fa2Shkenken #include <machine/cpu.h> 515f3c2fa2Shkenken #include <machine/intr.h> 525f3c2fa2Shkenken 535f3c2fa2Shkenken #include <arm/imx/imxspivar.h> 545f3c2fa2Shkenken #include <arm/imx/imxspireg.h> 555f3c2fa2Shkenken 56*b68d413bShkenken #ifdef FDT 57*b68d413bShkenken #include <dev/fdt/fdtvar.h> 58*b68d413bShkenken #endif 59*b68d413bShkenken 605f3c2fa2Shkenken /* SPI service routines */ 615f3c2fa2Shkenken static int imxspi_configure_enhanced(void *, int, int, int); 625f3c2fa2Shkenken static int imxspi_configure(void *, int, int, int); 635f3c2fa2Shkenken static int imxspi_transfer(void *, struct spi_transfer *); 645f3c2fa2Shkenken 655f3c2fa2Shkenken /* internal stuff */ 665f3c2fa2Shkenken void imxspi_done(struct imxspi_softc *, int); 675f3c2fa2Shkenken void imxspi_send(struct imxspi_softc *); 685f3c2fa2Shkenken void imxspi_recv(struct imxspi_softc *); 695f3c2fa2Shkenken void imxspi_sched(struct imxspi_softc *); 705f3c2fa2Shkenken 715f3c2fa2Shkenken #define IMXSPI(x) \ 725f3c2fa2Shkenken ((sc->sc_enhanced) ? __CONCAT(ECSPI_, x) : __CONCAT(CSPI_, x)) 735f3c2fa2Shkenken #define READ_REG(sc, x) \ 745f3c2fa2Shkenken bus_space_read_4(sc->sc_iot, sc->sc_ioh, IMXSPI(x)) 755f3c2fa2Shkenken #define WRITE_REG(sc, x, v) \ 765f3c2fa2Shkenken bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXSPI(x), (v)) 775f3c2fa2Shkenken 785f3c2fa2Shkenken #ifdef IMXSPI_DEBUG 795f3c2fa2Shkenken int imxspi_debug = IMXSPI_DEBUG; 805f3c2fa2Shkenken #define DPRINTFN(n,x) if (imxspi_debug>(n)) printf x; 815f3c2fa2Shkenken #else 825f3c2fa2Shkenken #define DPRINTFN(n,x) 835f3c2fa2Shkenken #endif 845f3c2fa2Shkenken 85*b68d413bShkenken #ifdef FDT 86*b68d413bShkenken static struct spi_controller * 87*b68d413bShkenken imxspi_get_controller(device_t dev) 885f3c2fa2Shkenken { 89*b68d413bShkenken struct imxspi_softc * const sc = device_private(dev); 905f3c2fa2Shkenken 91*b68d413bShkenken return &sc->sc_spi; 925f3c2fa2Shkenken } 935f3c2fa2Shkenken 94*b68d413bShkenken static const struct fdtbus_spi_controller_func imxspi_funcs = { 95*b68d413bShkenken .get_controller = imxspi_get_controller 96*b68d413bShkenken }; 97*b68d413bShkenken #endif 98*b68d413bShkenken 99*b68d413bShkenken int 100*b68d413bShkenken imxspi_attach_common(device_t self) 101*b68d413bShkenken { 102*b68d413bShkenken struct imxspi_softc * const sc = device_private(self); 103*b68d413bShkenken 104*b68d413bShkenken aprint_normal("i.MX %sCSPI Controller (clock %ld Hz)\n", 1055f3c2fa2Shkenken ((sc->sc_enhanced) ? "e" : ""), sc->sc_freq); 1065f3c2fa2Shkenken 1075f3c2fa2Shkenken /* Initialize SPI controller */ 108*b68d413bShkenken sc->sc_dev = self; 1095f3c2fa2Shkenken sc->sc_spi.sct_cookie = sc; 1105f3c2fa2Shkenken if (sc->sc_enhanced) 1115f3c2fa2Shkenken sc->sc_spi.sct_configure = imxspi_configure_enhanced; 1125f3c2fa2Shkenken else 1135f3c2fa2Shkenken sc->sc_spi.sct_configure = imxspi_configure; 1145f3c2fa2Shkenken sc->sc_spi.sct_transfer = imxspi_transfer; 1155f3c2fa2Shkenken 1165f3c2fa2Shkenken /* sc->sc_spi.sct_nslaves must have been initialized by machdep code */ 117*b68d413bShkenken sc->sc_spi.sct_nslaves = sc->sc_nslaves; 1185f3c2fa2Shkenken if (!sc->sc_spi.sct_nslaves) 1195f3c2fa2Shkenken aprint_error_dev(sc->sc_dev, "no slaves!\n"); 1205f3c2fa2Shkenken 1215f3c2fa2Shkenken /* initialize the queue */ 1225f3c2fa2Shkenken SIMPLEQ_INIT(&sc->sc_q); 1235f3c2fa2Shkenken 1245f3c2fa2Shkenken /* configure SPI */ 1255f3c2fa2Shkenken /* Setup Control Register */ 1265f3c2fa2Shkenken WRITE_REG(sc, CONREG, __SHIFTIN(0, IMXSPI(CON_DRCTL)) | 1275f3c2fa2Shkenken __SHIFTIN(8 - 1, IMXSPI(CON_BITCOUNT)) | 1285f3c2fa2Shkenken __SHIFTIN(0xf, IMXSPI(CON_MODE)) | IMXSPI(CON_ENABLE)); 1295f3c2fa2Shkenken 1305f3c2fa2Shkenken /* TC and RR interruption */ 1315f3c2fa2Shkenken WRITE_REG(sc, INTREG, (IMXSPI(INTR_TC_EN) | IMXSPI(INTR_RR_EN))); 1325f3c2fa2Shkenken WRITE_REG(sc, STATREG, IMXSPI(STAT_CLR)); 1335f3c2fa2Shkenken 1345f3c2fa2Shkenken WRITE_REG(sc, PERIODREG, 0x0); 1355f3c2fa2Shkenken 136*b68d413bShkenken #ifdef FDT 137*b68d413bShkenken KASSERT(sc->sc_phandle != 0); 138*b68d413bShkenken 139*b68d413bShkenken fdtbus_register_spi_controller(self, sc->sc_phandle, &imxspi_funcs); 140*b68d413bShkenken (void) fdtbus_attach_spibus(self, sc->sc_phandle, spibus_print); 141*b68d413bShkenken #else 142*b68d413bShkenken struct spibus_attach_args sba; 143*b68d413bShkenken memset(&sba, 0, sizeof(sba)); 144*b68d413bShkenken sba.sba_controller = &sc->sc_spi; 1455f3c2fa2Shkenken 1465f3c2fa2Shkenken /* attach slave devices */ 1475f3c2fa2Shkenken (void)config_found_ia(sc->sc_dev, "spibus", &sba, spibus_print); 148*b68d413bShkenken #endif 1495f3c2fa2Shkenken 1505f3c2fa2Shkenken return 0; 1515f3c2fa2Shkenken } 1525f3c2fa2Shkenken 1535f3c2fa2Shkenken static int 1545f3c2fa2Shkenken imxspi_configure(void *arg, int slave, int mode, int speed) 1555f3c2fa2Shkenken { 1565f3c2fa2Shkenken struct imxspi_softc *sc = arg; 1575f3c2fa2Shkenken uint32_t div_cnt = 0; 1585f3c2fa2Shkenken uint32_t div; 1595f3c2fa2Shkenken uint32_t contrl = 0; 1605f3c2fa2Shkenken 1615f3c2fa2Shkenken div = (sc->sc_freq + (speed - 1)) / speed; 1625f3c2fa2Shkenken div = div - 1; 1635f3c2fa2Shkenken for (div_cnt = 0; div > 0; div_cnt++) 1645f3c2fa2Shkenken div >>= 1; 1655f3c2fa2Shkenken 1665f3c2fa2Shkenken div_cnt = div_cnt - 2; 1675f3c2fa2Shkenken if (div_cnt >= 7) 1685f3c2fa2Shkenken div_cnt = 7; 1695f3c2fa2Shkenken 1705f3c2fa2Shkenken contrl = READ_REG(sc, CONREG); 1715f3c2fa2Shkenken contrl &= ~CSPI_CON_DIV; 1725f3c2fa2Shkenken contrl |= __SHIFTIN(div_cnt, CSPI_CON_DIV); 1735f3c2fa2Shkenken 1745f3c2fa2Shkenken contrl &= ~(CSPI_CON_POL | CSPI_CON_PHA); 1755f3c2fa2Shkenken switch (mode) { 1765f3c2fa2Shkenken case SPI_MODE_0: 1775f3c2fa2Shkenken /* CPHA = 0, CPOL = 0 */ 1785f3c2fa2Shkenken break; 1795f3c2fa2Shkenken case SPI_MODE_1: 1805f3c2fa2Shkenken /* CPHA = 1, CPOL = 0 */ 1815f3c2fa2Shkenken contrl |= CSPI_CON_PHA; 1825f3c2fa2Shkenken break; 1835f3c2fa2Shkenken case SPI_MODE_2: 1845f3c2fa2Shkenken /* CPHA = 0, CPOL = 1 */ 1855f3c2fa2Shkenken contrl |= CSPI_CON_POL; 1865f3c2fa2Shkenken break; 1875f3c2fa2Shkenken case SPI_MODE_3: 1885f3c2fa2Shkenken /* CPHA = 1, CPOL = 1 */ 1895f3c2fa2Shkenken contrl |= CSPI_CON_POL; 1905f3c2fa2Shkenken contrl |= CSPI_CON_PHA; 1915f3c2fa2Shkenken break; 1925f3c2fa2Shkenken default: 1935f3c2fa2Shkenken return EINVAL; 1945f3c2fa2Shkenken } 1955f3c2fa2Shkenken WRITE_REG(sc, CONREG, contrl); 1965f3c2fa2Shkenken 1975f3c2fa2Shkenken DPRINTFN(3, ("%s: slave %d mode %d speed %d\n", 1985f3c2fa2Shkenken __func__, slave, mode, speed)); 1995f3c2fa2Shkenken 2005f3c2fa2Shkenken return 0; 2015f3c2fa2Shkenken } 2025f3c2fa2Shkenken 2035f3c2fa2Shkenken static int 2045f3c2fa2Shkenken imxspi_configure_enhanced(void *arg, int slave, int mode, int speed) 2055f3c2fa2Shkenken { 2065f3c2fa2Shkenken struct imxspi_softc *sc = arg; 2075f3c2fa2Shkenken uint32_t div_cnt = 0; 2085f3c2fa2Shkenken uint32_t div; 2095f3c2fa2Shkenken uint32_t contrl = 0; 2105f3c2fa2Shkenken uint32_t config = 0; 2115f3c2fa2Shkenken 2125f3c2fa2Shkenken div = (sc->sc_freq + (speed - 1)) / speed; 2135f3c2fa2Shkenken for (div_cnt = 0; div > 0; div_cnt++) 2145f3c2fa2Shkenken div >>= 1; 2155f3c2fa2Shkenken 2165f3c2fa2Shkenken if (div_cnt >= 15) 2175f3c2fa2Shkenken div_cnt = 15; 2185f3c2fa2Shkenken 2195f3c2fa2Shkenken contrl = READ_REG(sc, CONREG); 2205f3c2fa2Shkenken contrl |= __SHIFTIN(div_cnt, ECSPI_CON_DIV); 2215f3c2fa2Shkenken contrl |= __SHIFTIN(slave, ECSPI_CON_CS); 2225f3c2fa2Shkenken contrl |= __SHIFTIN(__BIT(slave), ECSPI_CON_MODE); 2235f3c2fa2Shkenken WRITE_REG(sc, CONREG, contrl); 2245f3c2fa2Shkenken 2255f3c2fa2Shkenken config = bus_space_read_4(sc->sc_iot, sc->sc_ioh, ECSPI_CONFIGREG); 2265f3c2fa2Shkenken config &= ~(__SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_POL) | 2275f3c2fa2Shkenken __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_PHA)); 2285f3c2fa2Shkenken switch (mode) { 2295f3c2fa2Shkenken case SPI_MODE_0: 2305f3c2fa2Shkenken /* CPHA = 0, CPOL = 0 */ 2315f3c2fa2Shkenken break; 2325f3c2fa2Shkenken case SPI_MODE_1: 2335f3c2fa2Shkenken /* CPHA = 1, CPOL = 0 */ 2345f3c2fa2Shkenken config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_PHA); 2355f3c2fa2Shkenken break; 2365f3c2fa2Shkenken case SPI_MODE_2: 2375f3c2fa2Shkenken /* CPHA = 0, CPOL = 1 */ 2385f3c2fa2Shkenken config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_POL); 2395f3c2fa2Shkenken break; 2405f3c2fa2Shkenken case SPI_MODE_3: 2415f3c2fa2Shkenken /* CPHA = 1, CPOL = 1 */ 2425f3c2fa2Shkenken config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_PHA); 2435f3c2fa2Shkenken config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_POL); 2445f3c2fa2Shkenken break; 2455f3c2fa2Shkenken default: 2465f3c2fa2Shkenken return EINVAL; 2475f3c2fa2Shkenken } 2485f3c2fa2Shkenken config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SSB_CTL); 2495f3c2fa2Shkenken bus_space_write_4(sc->sc_iot, sc->sc_ioh, ECSPI_CONFIGREG, config); 2505f3c2fa2Shkenken 2515f3c2fa2Shkenken DPRINTFN(3, ("%s: slave %d mode %d speed %d\n", 2525f3c2fa2Shkenken __func__, slave, mode, speed)); 2535f3c2fa2Shkenken 2545f3c2fa2Shkenken return 0; 2555f3c2fa2Shkenken } 2565f3c2fa2Shkenken 2575f3c2fa2Shkenken void 2585f3c2fa2Shkenken imxspi_send(struct imxspi_softc *sc) 2595f3c2fa2Shkenken { 2605f3c2fa2Shkenken uint32_t data; 2615f3c2fa2Shkenken struct spi_chunk *chunk; 2625f3c2fa2Shkenken 2635f3c2fa2Shkenken /* fill the fifo */ 2645f3c2fa2Shkenken while ((chunk = sc->sc_wchunk) != NULL) { 2655f3c2fa2Shkenken while (chunk->chunk_wresid) { 2665f3c2fa2Shkenken /* transmit fifo full? */ 2675f3c2fa2Shkenken if (READ_REG(sc, STATREG) & IMXSPI(STAT_TF)) 2685a40d812Shkenken goto out; 2695f3c2fa2Shkenken 2705f3c2fa2Shkenken if (chunk->chunk_wptr) { 2715f3c2fa2Shkenken data = *chunk->chunk_wptr; 2725f3c2fa2Shkenken chunk->chunk_wptr++; 2735f3c2fa2Shkenken } else { 2745f3c2fa2Shkenken data = 0xff; 2755f3c2fa2Shkenken } 2765f3c2fa2Shkenken chunk->chunk_wresid--; 2775f3c2fa2Shkenken 2785f3c2fa2Shkenken WRITE_REG(sc, TXDATA, data); 2795f3c2fa2Shkenken } 2805f3c2fa2Shkenken /* advance to next transfer */ 2815f3c2fa2Shkenken sc->sc_wchunk = sc->sc_wchunk->chunk_next; 2825f3c2fa2Shkenken } 2835a40d812Shkenken out: 2845f3c2fa2Shkenken if (!(READ_REG(sc, STATREG) & IMXSPI(INTR_TE_EN))) 2855f3c2fa2Shkenken WRITE_REG(sc, CONREG, READ_REG(sc, CONREG) | IMXSPI(CON_XCH)); 2865f3c2fa2Shkenken } 2875f3c2fa2Shkenken 2885f3c2fa2Shkenken void 2895f3c2fa2Shkenken imxspi_recv(struct imxspi_softc *sc) 2905f3c2fa2Shkenken { 2915f3c2fa2Shkenken uint32_t data; 2925f3c2fa2Shkenken struct spi_chunk *chunk; 2935f3c2fa2Shkenken 2945f3c2fa2Shkenken while ((chunk = sc->sc_rchunk) != NULL) { 2955f3c2fa2Shkenken while (chunk->chunk_rresid) { 2965f3c2fa2Shkenken /* rx fifo empty? */ 2975f3c2fa2Shkenken if ((!(READ_REG(sc, STATREG) & IMXSPI(STAT_RR)))) 2985f3c2fa2Shkenken return; 2995f3c2fa2Shkenken 3005f3c2fa2Shkenken /* collect rx data */ 3015f3c2fa2Shkenken data = READ_REG(sc, RXDATA); 3025f3c2fa2Shkenken if (chunk->chunk_rptr) { 3035f3c2fa2Shkenken *chunk->chunk_rptr = data & 0xff; 3045f3c2fa2Shkenken chunk->chunk_rptr++; 3055f3c2fa2Shkenken } 3065f3c2fa2Shkenken 3075f3c2fa2Shkenken chunk->chunk_rresid--; 3085f3c2fa2Shkenken } 3095f3c2fa2Shkenken /* advance next to next transfer */ 3105f3c2fa2Shkenken sc->sc_rchunk = sc->sc_rchunk->chunk_next; 3115f3c2fa2Shkenken } 3125f3c2fa2Shkenken } 3135f3c2fa2Shkenken 3145f3c2fa2Shkenken 3155f3c2fa2Shkenken void 3165f3c2fa2Shkenken imxspi_sched(struct imxspi_softc *sc) 3175f3c2fa2Shkenken { 3185f3c2fa2Shkenken struct spi_transfer *st; 3195f3c2fa2Shkenken uint32_t chipselect; 3205f3c2fa2Shkenken 3215f3c2fa2Shkenken while ((st = spi_transq_first(&sc->sc_q)) != NULL) { 3225f3c2fa2Shkenken /* remove the item */ 3235f3c2fa2Shkenken spi_transq_dequeue(&sc->sc_q); 3245f3c2fa2Shkenken 3255f3c2fa2Shkenken /* note that we are working on it */ 3265f3c2fa2Shkenken sc->sc_transfer = st; 3275f3c2fa2Shkenken 3285f3c2fa2Shkenken /* chip slect */ 3295f3c2fa2Shkenken if (sc->sc_tag->spi_cs_enable != NULL) 3305f3c2fa2Shkenken sc->sc_tag->spi_cs_enable(sc->sc_tag->cookie, 3315f3c2fa2Shkenken st->st_slave); 3325f3c2fa2Shkenken 3335f3c2fa2Shkenken /* chip slect */ 3345f3c2fa2Shkenken chipselect = READ_REG(sc, CONREG); 3355f3c2fa2Shkenken chipselect &= ~IMXSPI(CON_CS); 3365f3c2fa2Shkenken chipselect |= __SHIFTIN(st->st_slave, IMXSPI(CON_CS)); 3375f3c2fa2Shkenken WRITE_REG(sc, CONREG, chipselect); 3385f3c2fa2Shkenken 3395f3c2fa2Shkenken delay(1); 3405f3c2fa2Shkenken 3415f3c2fa2Shkenken /* setup chunks */ 3425f3c2fa2Shkenken sc->sc_rchunk = sc->sc_wchunk = st->st_chunks; 3435f3c2fa2Shkenken 3445f3c2fa2Shkenken /* now kick the master start to get the chip running */ 3455f3c2fa2Shkenken imxspi_send(sc); 3465f3c2fa2Shkenken 3475f3c2fa2Shkenken sc->sc_running = TRUE; 3485f3c2fa2Shkenken return; 3495f3c2fa2Shkenken } 3505f3c2fa2Shkenken 3515f3c2fa2Shkenken DPRINTFN(2, ("%s: nothing to do anymore\n", __func__)); 3525f3c2fa2Shkenken sc->sc_running = FALSE; 3535f3c2fa2Shkenken } 3545f3c2fa2Shkenken 3555f3c2fa2Shkenken void 3565f3c2fa2Shkenken imxspi_done(struct imxspi_softc *sc, int err) 3575f3c2fa2Shkenken { 3585f3c2fa2Shkenken struct spi_transfer *st; 3595f3c2fa2Shkenken 3605f3c2fa2Shkenken /* called from interrupt handler */ 3615f3c2fa2Shkenken if ((st = sc->sc_transfer) != NULL) { 3625f3c2fa2Shkenken if (sc->sc_tag->spi_cs_disable != NULL) 3635f3c2fa2Shkenken sc->sc_tag->spi_cs_disable(sc->sc_tag->cookie, 3645f3c2fa2Shkenken st->st_slave); 3655f3c2fa2Shkenken 3665f3c2fa2Shkenken sc->sc_transfer = NULL; 3675f3c2fa2Shkenken spi_done(st, err); 3685f3c2fa2Shkenken } 3695f3c2fa2Shkenken /* make sure we clear these bits out */ 3705f3c2fa2Shkenken sc->sc_wchunk = sc->sc_rchunk = NULL; 3715f3c2fa2Shkenken imxspi_sched(sc); 3725f3c2fa2Shkenken } 3735f3c2fa2Shkenken 374*b68d413bShkenken int 3755f3c2fa2Shkenken imxspi_intr(void *arg) 3765f3c2fa2Shkenken { 3775f3c2fa2Shkenken struct imxspi_softc *sc = arg; 3785f3c2fa2Shkenken uint32_t intr, sr; 3795f3c2fa2Shkenken int err = 0; 3805f3c2fa2Shkenken 3815f3c2fa2Shkenken if ((intr = READ_REG(sc, INTREG)) == 0) { 3825f3c2fa2Shkenken /* interrupts are not enabled, get out */ 3835f3c2fa2Shkenken DPRINTFN(4, ("%s: interrupts are not enabled\n", __func__)); 3845f3c2fa2Shkenken return 0; 3855f3c2fa2Shkenken } 3865f3c2fa2Shkenken 3875f3c2fa2Shkenken sr = READ_REG(sc, STATREG); 3885f3c2fa2Shkenken if (!(sr & intr)) { 3895f3c2fa2Shkenken /* interrupt did not happen, get out */ 3905f3c2fa2Shkenken DPRINTFN(3, ("%s: interrupts did not happen\n", __func__)); 3915f3c2fa2Shkenken return 0; 3925f3c2fa2Shkenken } 3935f3c2fa2Shkenken 3945a40d812Shkenken /* RXFIFO ready? */ 3955f3c2fa2Shkenken if (sr & IMXSPI(INTR_RR_EN)) { 3965f3c2fa2Shkenken imxspi_recv(sc); 3975f3c2fa2Shkenken if (sc->sc_wchunk == NULL && sc->sc_rchunk == NULL) 3985f3c2fa2Shkenken imxspi_done(sc, err); 3995f3c2fa2Shkenken } 4005f3c2fa2Shkenken 4015a40d812Shkenken /* Transfer Conplete? */ 4025a40d812Shkenken if (sr & IMXSPI(INTR_TC_EN)) { 4035a40d812Shkenken /* complete TX */ 4045a40d812Shkenken imxspi_send(sc); 4055a40d812Shkenken } 4065a40d812Shkenken 4075f3c2fa2Shkenken /* status register clear */ 4085f3c2fa2Shkenken WRITE_REG(sc, STATREG, sr); 4095f3c2fa2Shkenken 4105f3c2fa2Shkenken return 1; 4115f3c2fa2Shkenken } 4125f3c2fa2Shkenken 4135f3c2fa2Shkenken int 4145f3c2fa2Shkenken imxspi_transfer(void *arg, struct spi_transfer *st) 4155f3c2fa2Shkenken { 4165f3c2fa2Shkenken struct imxspi_softc *sc = arg; 4175f3c2fa2Shkenken int s; 4185f3c2fa2Shkenken 4195f3c2fa2Shkenken /* make sure we select the right chip */ 420459f2ce0Shkenken s = splbio(); 4215f3c2fa2Shkenken spi_transq_enqueue(&sc->sc_q, st); 4225f3c2fa2Shkenken if (sc->sc_running == FALSE) 4235f3c2fa2Shkenken imxspi_sched(sc); 4245f3c2fa2Shkenken splx(s); 4255f3c2fa2Shkenken 4265f3c2fa2Shkenken return 0; 4275f3c2fa2Shkenken } 4285f3c2fa2Shkenken 429