1*ec2b0ccdSEmmanuel Vadot /*- 2*ec2b0ccdSEmmanuel Vadot * Copyright (c) 2018 Emmanuel Vadot <manu@FreeBSD.org> 3*ec2b0ccdSEmmanuel Vadot * 4*ec2b0ccdSEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 5*ec2b0ccdSEmmanuel Vadot * modification, are permitted provided that the following conditions 6*ec2b0ccdSEmmanuel Vadot * are met: 7*ec2b0ccdSEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 8*ec2b0ccdSEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 9*ec2b0ccdSEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 10*ec2b0ccdSEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the 11*ec2b0ccdSEmmanuel Vadot * documentation and/or other materials provided with the distribution. 12*ec2b0ccdSEmmanuel Vadot * 13*ec2b0ccdSEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14*ec2b0ccdSEmmanuel Vadot * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15*ec2b0ccdSEmmanuel Vadot * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16*ec2b0ccdSEmmanuel Vadot * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17*ec2b0ccdSEmmanuel Vadot * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 18*ec2b0ccdSEmmanuel Vadot * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19*ec2b0ccdSEmmanuel Vadot * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 20*ec2b0ccdSEmmanuel Vadot * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 21*ec2b0ccdSEmmanuel Vadot * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22*ec2b0ccdSEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23*ec2b0ccdSEmmanuel Vadot * SUCH DAMAGE. 24*ec2b0ccdSEmmanuel Vadot */ 25*ec2b0ccdSEmmanuel Vadot 26*ec2b0ccdSEmmanuel Vadot #include <sys/param.h> 27*ec2b0ccdSEmmanuel Vadot #include <sys/systm.h> 28*ec2b0ccdSEmmanuel Vadot #include <sys/bus.h> 29*ec2b0ccdSEmmanuel Vadot #include <sys/kernel.h> 30*ec2b0ccdSEmmanuel Vadot #include <sys/lock.h> 31*ec2b0ccdSEmmanuel Vadot #include <sys/module.h> 32*ec2b0ccdSEmmanuel Vadot #include <sys/mutex.h> 33*ec2b0ccdSEmmanuel Vadot #include <sys/rman.h> 34*ec2b0ccdSEmmanuel Vadot #include <sys/resource.h> 35*ec2b0ccdSEmmanuel Vadot #include <machine/bus.h> 36*ec2b0ccdSEmmanuel Vadot 37*ec2b0ccdSEmmanuel Vadot #include <dev/ofw/ofw_bus.h> 38*ec2b0ccdSEmmanuel Vadot #include <dev/ofw/ofw_bus_subr.h> 39*ec2b0ccdSEmmanuel Vadot 40*ec2b0ccdSEmmanuel Vadot #include <dev/spibus/spi.h> 41*ec2b0ccdSEmmanuel Vadot #include <dev/spibus/spibusvar.h> 42*ec2b0ccdSEmmanuel Vadot 43*ec2b0ccdSEmmanuel Vadot #include <dev/extres/clk/clk.h> 44*ec2b0ccdSEmmanuel Vadot #include <dev/extres/hwreset/hwreset.h> 45*ec2b0ccdSEmmanuel Vadot 46*ec2b0ccdSEmmanuel Vadot #include "spibus_if.h" 47*ec2b0ccdSEmmanuel Vadot 48*ec2b0ccdSEmmanuel Vadot #define AW_SPI_GCR 0x04 /* Global Control Register */ 49*ec2b0ccdSEmmanuel Vadot #define AW_SPI_GCR_EN (1 << 0) /* ENable */ 50*ec2b0ccdSEmmanuel Vadot #define AW_SPI_GCR_MODE_MASTER (1 << 1) /* 1 = Master, 0 = Slave */ 51*ec2b0ccdSEmmanuel Vadot #define AW_SPI_GCR_TP_EN (1 << 7) /* 1 = Stop transmit when FIFO is full */ 52*ec2b0ccdSEmmanuel Vadot #define AW_SPI_GCR_SRST (1 << 31) /* Soft Reset */ 53*ec2b0ccdSEmmanuel Vadot 54*ec2b0ccdSEmmanuel Vadot #define AW_SPI_TCR 0x08 /* Transfer Control register */ 55*ec2b0ccdSEmmanuel Vadot #define AW_SPI_TCR_XCH (1 << 31) /* Initiate transfer */ 56*ec2b0ccdSEmmanuel Vadot #define AW_SPI_TCR_SDDM (1 << 14) /* Sending Delay Data Mode */ 57*ec2b0ccdSEmmanuel Vadot #define AW_SPI_TCR_SDM (1 << 13) /* Master Sample Data Mode */ 58*ec2b0ccdSEmmanuel Vadot #define AW_SPI_TCR_FBS (1 << 12) /* First Transmit Bit Select (1 == LSB) */ 59*ec2b0ccdSEmmanuel Vadot #define AW_SPI_TCR_SDC (1 << 11) /* Master Sample Data Control */ 60*ec2b0ccdSEmmanuel Vadot #define AW_SPI_TCR_RPSM (1 << 10) /* Rapid Mode Select */ 61*ec2b0ccdSEmmanuel Vadot #define AW_SPI_TCR_DDB (1 << 9) /* Dummy Burst Type */ 62*ec2b0ccdSEmmanuel Vadot #define AW_SPI_TCR_SSSEL_MASK 0x30 /* Chip select */ 63*ec2b0ccdSEmmanuel Vadot #define AW_SPI_TCR_SSSEL_SHIFT 4 64*ec2b0ccdSEmmanuel Vadot #define AW_SPI_TCR_SS_LEVEL (1 << 7) /* 1 == CS High */ 65*ec2b0ccdSEmmanuel Vadot #define AW_SPI_TCR_SS_OWNER (1 << 6) /* 1 == Software controlled */ 66*ec2b0ccdSEmmanuel Vadot #define AW_SPI_TCR_SPOL (1 << 2) /* 1 == Active low */ 67*ec2b0ccdSEmmanuel Vadot #define AW_SPI_TCR_CPOL (1 << 1) /* 1 == Active low */ 68*ec2b0ccdSEmmanuel Vadot #define AW_SPI_TCR_CPHA (1 << 0) /* 1 == Phase 1 */ 69*ec2b0ccdSEmmanuel Vadot 70*ec2b0ccdSEmmanuel Vadot #define AW_SPI_IER 0x10 /* Interrupt Control Register */ 71*ec2b0ccdSEmmanuel Vadot #define AW_SPI_IER_SS (1 << 13) /* Chip select went from valid to invalid */ 72*ec2b0ccdSEmmanuel Vadot #define AW_SPI_IER_TC (1 << 12) /* Transfer complete */ 73*ec2b0ccdSEmmanuel Vadot #define AW_SPI_IER_TF_UDR (1 << 11) /* TXFIFO underrun */ 74*ec2b0ccdSEmmanuel Vadot #define AW_SPI_IER_TF_OVF (1 << 10) /* TXFIFO overrun */ 75*ec2b0ccdSEmmanuel Vadot #define AW_SPI_IER_RF_UDR (1 << 9) /* RXFIFO underrun */ 76*ec2b0ccdSEmmanuel Vadot #define AW_SPI_IER_RF_OVF (1 << 8) /* RXFIFO overrun */ 77*ec2b0ccdSEmmanuel Vadot #define AW_SPI_IER_TF_FULL (1 << 6) /* TXFIFO Full */ 78*ec2b0ccdSEmmanuel Vadot #define AW_SPI_IER_TF_EMP (1 << 5) /* TXFIFO Empty */ 79*ec2b0ccdSEmmanuel Vadot #define AW_SPI_IER_TF_ERQ (1 << 4) /* TXFIFO Empty Request */ 80*ec2b0ccdSEmmanuel Vadot #define AW_SPI_IER_RF_FULL (1 << 2) /* RXFIFO Full */ 81*ec2b0ccdSEmmanuel Vadot #define AW_SPI_IER_RF_EMP (1 << 1) /* RXFIFO Empty */ 82*ec2b0ccdSEmmanuel Vadot #define AW_SPI_IER_RF_RDY (1 << 0) /* RXFIFO Ready Request */ 83*ec2b0ccdSEmmanuel Vadot 84*ec2b0ccdSEmmanuel Vadot #define AW_SPI_ISR 0x14 /* Interrupt Status Register */ 85*ec2b0ccdSEmmanuel Vadot 86*ec2b0ccdSEmmanuel Vadot #define AW_SPI_FCR 0x18 /* FIFO Control Register */ 87*ec2b0ccdSEmmanuel Vadot #define AW_SPI_FCR_TX_RST (1 << 31) /* Reset TX FIFO */ 88*ec2b0ccdSEmmanuel Vadot #define AW_SPI_FCR_TX_TRIG_MASK 0xFF0000 /* TX FIFO Trigger level */ 89*ec2b0ccdSEmmanuel Vadot #define AW_SPI_FCR_TX_TRIG_SHIFT 16 90*ec2b0ccdSEmmanuel Vadot #define AW_SPI_FCR_RX_RST (1 << 15) /* Reset RX FIFO */ 91*ec2b0ccdSEmmanuel Vadot #define AW_SPI_FCR_RX_TRIG_MASK 0xFF /* RX FIFO Trigger level */ 92*ec2b0ccdSEmmanuel Vadot #define AW_SPI_FCR_RX_TRIG_SHIFT 0 93*ec2b0ccdSEmmanuel Vadot 94*ec2b0ccdSEmmanuel Vadot #define AW_SPI_FSR 0x1C /* FIFO Status Register */ 95*ec2b0ccdSEmmanuel Vadot #define AW_SPI_FSR_TB_WR (1 << 31) 96*ec2b0ccdSEmmanuel Vadot #define AW_SPI_FSR_TB_CNT_MASK 0x70000000 97*ec2b0ccdSEmmanuel Vadot #define AW_SPI_FSR_TB_CNT_SHIFT 28 98*ec2b0ccdSEmmanuel Vadot #define AW_SPI_FSR_TF_CNT_MASK 0xFF0000 99*ec2b0ccdSEmmanuel Vadot #define AW_SPI_FSR_TF_CNT_SHIFT 16 100*ec2b0ccdSEmmanuel Vadot #define AW_SPI_FSR_RB_WR (1 << 15) 101*ec2b0ccdSEmmanuel Vadot #define AW_SPI_FSR_RB_CNT_MASK 0x7000 102*ec2b0ccdSEmmanuel Vadot #define AW_SPI_FSR_RB_CNT_SHIFT 12 103*ec2b0ccdSEmmanuel Vadot #define AW_SPI_FSR_RF_CNT_MASK 0xFF 104*ec2b0ccdSEmmanuel Vadot #define AW_SPI_FSR_RF_CNT_SHIFT 0 105*ec2b0ccdSEmmanuel Vadot 106*ec2b0ccdSEmmanuel Vadot #define AW_SPI_WCR 0x20 /* Wait Clock Counter Register */ 107*ec2b0ccdSEmmanuel Vadot 108*ec2b0ccdSEmmanuel Vadot #define AW_SPI_CCR 0x24 /* Clock Rate Control Register */ 109*ec2b0ccdSEmmanuel Vadot #define AW_SPI_CCR_DRS (1 << 12) /* Clock divider select */ 110*ec2b0ccdSEmmanuel Vadot #define AW_SPI_CCR_CDR1_MASK 0xF00 111*ec2b0ccdSEmmanuel Vadot #define AW_SPI_CCR_CDR1_SHIFT 8 112*ec2b0ccdSEmmanuel Vadot #define AW_SPI_CCR_CDR2_MASK 0xFF 113*ec2b0ccdSEmmanuel Vadot #define AW_SPI_CCR_CDR2_SHIFT 0 114*ec2b0ccdSEmmanuel Vadot 115*ec2b0ccdSEmmanuel Vadot #define AW_SPI_MBC 0x30 /* Burst Counter Register */ 116*ec2b0ccdSEmmanuel Vadot #define AW_SPI_MTC 0x34 /* Transmit Counter Register */ 117*ec2b0ccdSEmmanuel Vadot #define AW_SPI_BCC 0x38 /* Burst Control Register */ 118*ec2b0ccdSEmmanuel Vadot #define AW_SPI_MDMA_CTL 0x88 /* Normal DMA Control Register */ 119*ec2b0ccdSEmmanuel Vadot #define AW_SPI_TXD 0x200 /* TX Data Register */ 120*ec2b0ccdSEmmanuel Vadot #define AW_SPI_RDX 0x300 /* RX Data Register */ 121*ec2b0ccdSEmmanuel Vadot 122*ec2b0ccdSEmmanuel Vadot #define AW_SPI_MAX_CS 4 123*ec2b0ccdSEmmanuel Vadot #define AW_SPI_FIFO_SIZE 64 124*ec2b0ccdSEmmanuel Vadot 125*ec2b0ccdSEmmanuel Vadot static struct ofw_compat_data compat_data[] = { 126*ec2b0ccdSEmmanuel Vadot { "allwinner,sun8i-h3-spi", 1 }, 127*ec2b0ccdSEmmanuel Vadot { NULL, 0 } 128*ec2b0ccdSEmmanuel Vadot }; 129*ec2b0ccdSEmmanuel Vadot 130*ec2b0ccdSEmmanuel Vadot static struct resource_spec aw_spi_spec[] = { 131*ec2b0ccdSEmmanuel Vadot { SYS_RES_MEMORY, 0, RF_ACTIVE }, 132*ec2b0ccdSEmmanuel Vadot { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE }, 133*ec2b0ccdSEmmanuel Vadot { -1, 0 } 134*ec2b0ccdSEmmanuel Vadot }; 135*ec2b0ccdSEmmanuel Vadot 136*ec2b0ccdSEmmanuel Vadot struct aw_spi_softc { 137*ec2b0ccdSEmmanuel Vadot device_t dev; 138*ec2b0ccdSEmmanuel Vadot device_t spibus; 139*ec2b0ccdSEmmanuel Vadot struct resource *res[2]; 140*ec2b0ccdSEmmanuel Vadot struct mtx mtx; 141*ec2b0ccdSEmmanuel Vadot clk_t clk_ahb; 142*ec2b0ccdSEmmanuel Vadot clk_t clk_mod; 143*ec2b0ccdSEmmanuel Vadot uint64_t mod_freq; 144*ec2b0ccdSEmmanuel Vadot hwreset_t rst_ahb; 145*ec2b0ccdSEmmanuel Vadot void * intrhand; 146*ec2b0ccdSEmmanuel Vadot int transfer; 147*ec2b0ccdSEmmanuel Vadot 148*ec2b0ccdSEmmanuel Vadot uint8_t *rxbuf; 149*ec2b0ccdSEmmanuel Vadot uint32_t rxcnt; 150*ec2b0ccdSEmmanuel Vadot uint8_t *txbuf; 151*ec2b0ccdSEmmanuel Vadot uint32_t txcnt; 152*ec2b0ccdSEmmanuel Vadot uint32_t txlen; 153*ec2b0ccdSEmmanuel Vadot uint32_t rxlen; 154*ec2b0ccdSEmmanuel Vadot }; 155*ec2b0ccdSEmmanuel Vadot 156*ec2b0ccdSEmmanuel Vadot #define AW_SPI_LOCK(sc) mtx_lock(&(sc)->mtx) 157*ec2b0ccdSEmmanuel Vadot #define AW_SPI_UNLOCK(sc) mtx_unlock(&(sc)->mtx) 158*ec2b0ccdSEmmanuel Vadot #define AW_SPI_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED) 159*ec2b0ccdSEmmanuel Vadot #define AW_SPI_READ_1(sc, reg) bus_read_1((sc)->res[0], (reg)) 160*ec2b0ccdSEmmanuel Vadot #define AW_SPI_WRITE_1(sc, reg, val) bus_write_1((sc)->res[0], (reg), (val)) 161*ec2b0ccdSEmmanuel Vadot #define AW_SPI_READ_4(sc, reg) bus_read_4((sc)->res[0], (reg)) 162*ec2b0ccdSEmmanuel Vadot #define AW_SPI_WRITE_4(sc, reg, val) bus_write_4((sc)->res[0], (reg), (val)) 163*ec2b0ccdSEmmanuel Vadot 164*ec2b0ccdSEmmanuel Vadot static int aw_spi_probe(device_t dev); 165*ec2b0ccdSEmmanuel Vadot static int aw_spi_attach(device_t dev); 166*ec2b0ccdSEmmanuel Vadot static int aw_spi_detach(device_t dev); 167*ec2b0ccdSEmmanuel Vadot static int aw_spi_intr(void *arg); 168*ec2b0ccdSEmmanuel Vadot 169*ec2b0ccdSEmmanuel Vadot static int 170*ec2b0ccdSEmmanuel Vadot aw_spi_probe(device_t dev) 171*ec2b0ccdSEmmanuel Vadot { 172*ec2b0ccdSEmmanuel Vadot if (!ofw_bus_status_okay(dev)) 173*ec2b0ccdSEmmanuel Vadot return (ENXIO); 174*ec2b0ccdSEmmanuel Vadot 175*ec2b0ccdSEmmanuel Vadot if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 176*ec2b0ccdSEmmanuel Vadot return (ENXIO); 177*ec2b0ccdSEmmanuel Vadot 178*ec2b0ccdSEmmanuel Vadot device_set_desc(dev, "Allwinner SPI"); 179*ec2b0ccdSEmmanuel Vadot return (BUS_PROBE_DEFAULT); 180*ec2b0ccdSEmmanuel Vadot } 181*ec2b0ccdSEmmanuel Vadot 182*ec2b0ccdSEmmanuel Vadot static int 183*ec2b0ccdSEmmanuel Vadot aw_spi_attach(device_t dev) 184*ec2b0ccdSEmmanuel Vadot { 185*ec2b0ccdSEmmanuel Vadot struct aw_spi_softc *sc; 186*ec2b0ccdSEmmanuel Vadot int error; 187*ec2b0ccdSEmmanuel Vadot 188*ec2b0ccdSEmmanuel Vadot sc = device_get_softc(dev); 189*ec2b0ccdSEmmanuel Vadot sc->dev = dev; 190*ec2b0ccdSEmmanuel Vadot 191*ec2b0ccdSEmmanuel Vadot mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); 192*ec2b0ccdSEmmanuel Vadot 193*ec2b0ccdSEmmanuel Vadot if (bus_alloc_resources(dev, aw_spi_spec, sc->res) != 0) { 194*ec2b0ccdSEmmanuel Vadot device_printf(dev, "cannot allocate resources for device\n"); 195*ec2b0ccdSEmmanuel Vadot error = ENXIO; 196*ec2b0ccdSEmmanuel Vadot goto fail; 197*ec2b0ccdSEmmanuel Vadot } 198*ec2b0ccdSEmmanuel Vadot 199*ec2b0ccdSEmmanuel Vadot if (bus_setup_intr(dev, sc->res[1], 200*ec2b0ccdSEmmanuel Vadot INTR_TYPE_MISC | INTR_MPSAFE, aw_spi_intr, NULL, sc, 201*ec2b0ccdSEmmanuel Vadot &sc->intrhand)) { 202*ec2b0ccdSEmmanuel Vadot bus_release_resources(dev, aw_spi_spec, sc->res); 203*ec2b0ccdSEmmanuel Vadot device_printf(dev, "cannot setup interrupt handler\n"); 204*ec2b0ccdSEmmanuel Vadot return (ENXIO); 205*ec2b0ccdSEmmanuel Vadot } 206*ec2b0ccdSEmmanuel Vadot 207*ec2b0ccdSEmmanuel Vadot /* De-assert reset */ 208*ec2b0ccdSEmmanuel Vadot if (hwreset_get_by_ofw_idx(dev, 0, 0, &sc->rst_ahb) == 0) { 209*ec2b0ccdSEmmanuel Vadot error = hwreset_deassert(sc->rst_ahb); 210*ec2b0ccdSEmmanuel Vadot if (error != 0) { 211*ec2b0ccdSEmmanuel Vadot device_printf(dev, "cannot de-assert reset\n"); 212*ec2b0ccdSEmmanuel Vadot goto fail; 213*ec2b0ccdSEmmanuel Vadot } 214*ec2b0ccdSEmmanuel Vadot } 215*ec2b0ccdSEmmanuel Vadot 216*ec2b0ccdSEmmanuel Vadot /* Activate the module clock. */ 217*ec2b0ccdSEmmanuel Vadot error = clk_get_by_ofw_name(dev, 0, "ahb", &sc->clk_ahb); 218*ec2b0ccdSEmmanuel Vadot if (error != 0) { 219*ec2b0ccdSEmmanuel Vadot device_printf(dev, "cannot get ahb clock\n"); 220*ec2b0ccdSEmmanuel Vadot goto fail; 221*ec2b0ccdSEmmanuel Vadot } 222*ec2b0ccdSEmmanuel Vadot error = clk_get_by_ofw_name(dev, 0, "mod", &sc->clk_mod); 223*ec2b0ccdSEmmanuel Vadot if (error != 0) { 224*ec2b0ccdSEmmanuel Vadot device_printf(dev, "cannot get mod clock\n"); 225*ec2b0ccdSEmmanuel Vadot goto fail; 226*ec2b0ccdSEmmanuel Vadot } 227*ec2b0ccdSEmmanuel Vadot error = clk_enable(sc->clk_ahb); 228*ec2b0ccdSEmmanuel Vadot if (error != 0) { 229*ec2b0ccdSEmmanuel Vadot device_printf(dev, "cannot enable ahb clock\n"); 230*ec2b0ccdSEmmanuel Vadot goto fail; 231*ec2b0ccdSEmmanuel Vadot } 232*ec2b0ccdSEmmanuel Vadot error = clk_enable(sc->clk_mod); 233*ec2b0ccdSEmmanuel Vadot if (error != 0) { 234*ec2b0ccdSEmmanuel Vadot device_printf(dev, "cannot enable mod clock\n"); 235*ec2b0ccdSEmmanuel Vadot goto fail; 236*ec2b0ccdSEmmanuel Vadot } 237*ec2b0ccdSEmmanuel Vadot 238*ec2b0ccdSEmmanuel Vadot sc->spibus = device_add_child(dev, "spibus", -1); 239*ec2b0ccdSEmmanuel Vadot 240*ec2b0ccdSEmmanuel Vadot return (bus_generic_attach(dev)); 241*ec2b0ccdSEmmanuel Vadot 242*ec2b0ccdSEmmanuel Vadot fail: 243*ec2b0ccdSEmmanuel Vadot aw_spi_detach(dev); 244*ec2b0ccdSEmmanuel Vadot return (error); 245*ec2b0ccdSEmmanuel Vadot } 246*ec2b0ccdSEmmanuel Vadot 247*ec2b0ccdSEmmanuel Vadot static int 248*ec2b0ccdSEmmanuel Vadot aw_spi_detach(device_t dev) 249*ec2b0ccdSEmmanuel Vadot { 250*ec2b0ccdSEmmanuel Vadot struct aw_spi_softc *sc; 251*ec2b0ccdSEmmanuel Vadot 252*ec2b0ccdSEmmanuel Vadot sc = device_get_softc(dev); 253*ec2b0ccdSEmmanuel Vadot 254*ec2b0ccdSEmmanuel Vadot bus_generic_detach(sc->dev); 255*ec2b0ccdSEmmanuel Vadot if (sc->spibus != NULL) 256*ec2b0ccdSEmmanuel Vadot device_delete_child(dev, sc->spibus); 257*ec2b0ccdSEmmanuel Vadot 258*ec2b0ccdSEmmanuel Vadot if (sc->clk_mod != NULL) 259*ec2b0ccdSEmmanuel Vadot clk_release(sc->clk_mod); 260*ec2b0ccdSEmmanuel Vadot if (sc->clk_ahb) 261*ec2b0ccdSEmmanuel Vadot clk_release(sc->clk_ahb); 262*ec2b0ccdSEmmanuel Vadot if (sc->rst_ahb) 263*ec2b0ccdSEmmanuel Vadot hwreset_assert(sc->rst_ahb); 264*ec2b0ccdSEmmanuel Vadot 265*ec2b0ccdSEmmanuel Vadot if (sc->intrhand != NULL) 266*ec2b0ccdSEmmanuel Vadot bus_teardown_intr(sc->dev, sc->res[1], sc->intrhand); 267*ec2b0ccdSEmmanuel Vadot 268*ec2b0ccdSEmmanuel Vadot bus_release_resources(dev, aw_spi_spec, sc->res); 269*ec2b0ccdSEmmanuel Vadot mtx_destroy(&sc->mtx); 270*ec2b0ccdSEmmanuel Vadot 271*ec2b0ccdSEmmanuel Vadot return (0); 272*ec2b0ccdSEmmanuel Vadot } 273*ec2b0ccdSEmmanuel Vadot 274*ec2b0ccdSEmmanuel Vadot static phandle_t 275*ec2b0ccdSEmmanuel Vadot aw_spi_get_node(device_t bus, device_t dev) 276*ec2b0ccdSEmmanuel Vadot { 277*ec2b0ccdSEmmanuel Vadot 278*ec2b0ccdSEmmanuel Vadot return ofw_bus_get_node(bus); 279*ec2b0ccdSEmmanuel Vadot } 280*ec2b0ccdSEmmanuel Vadot 281*ec2b0ccdSEmmanuel Vadot static void 282*ec2b0ccdSEmmanuel Vadot aw_spi_setup_mode(struct aw_spi_softc *sc, uint32_t mode) 283*ec2b0ccdSEmmanuel Vadot { 284*ec2b0ccdSEmmanuel Vadot uint32_t reg; 285*ec2b0ccdSEmmanuel Vadot 286*ec2b0ccdSEmmanuel Vadot /* We only support master mode */ 287*ec2b0ccdSEmmanuel Vadot reg = AW_SPI_READ_4(sc, AW_SPI_GCR); 288*ec2b0ccdSEmmanuel Vadot reg |= AW_SPI_GCR_MODE_MASTER; 289*ec2b0ccdSEmmanuel Vadot AW_SPI_WRITE_4(sc, AW_SPI_GCR, reg); 290*ec2b0ccdSEmmanuel Vadot 291*ec2b0ccdSEmmanuel Vadot /* Setup the modes */ 292*ec2b0ccdSEmmanuel Vadot reg = AW_SPI_READ_4(sc, AW_SPI_TCR); 293*ec2b0ccdSEmmanuel Vadot if (mode & SPIBUS_MODE_CPHA) 294*ec2b0ccdSEmmanuel Vadot reg |= AW_SPI_TCR_CPHA; 295*ec2b0ccdSEmmanuel Vadot if (mode & SPIBUS_MODE_CPOL) 296*ec2b0ccdSEmmanuel Vadot reg |= AW_SPI_TCR_CPOL; 297*ec2b0ccdSEmmanuel Vadot 298*ec2b0ccdSEmmanuel Vadot AW_SPI_WRITE_4(sc, AW_SPI_TCR, reg); 299*ec2b0ccdSEmmanuel Vadot } 300*ec2b0ccdSEmmanuel Vadot 301*ec2b0ccdSEmmanuel Vadot static void 302*ec2b0ccdSEmmanuel Vadot aw_spi_setup_cs(struct aw_spi_softc *sc, uint32_t cs, bool low) 303*ec2b0ccdSEmmanuel Vadot { 304*ec2b0ccdSEmmanuel Vadot uint32_t reg; 305*ec2b0ccdSEmmanuel Vadot 306*ec2b0ccdSEmmanuel Vadot /* Setup CS */ 307*ec2b0ccdSEmmanuel Vadot reg = AW_SPI_READ_4(sc, AW_SPI_TCR); 308*ec2b0ccdSEmmanuel Vadot reg &= ~(AW_SPI_TCR_SSSEL_MASK); 309*ec2b0ccdSEmmanuel Vadot reg |= cs << AW_SPI_TCR_SSSEL_SHIFT; 310*ec2b0ccdSEmmanuel Vadot reg |= AW_SPI_TCR_SS_OWNER; 311*ec2b0ccdSEmmanuel Vadot if (low) 312*ec2b0ccdSEmmanuel Vadot reg &= ~(AW_SPI_TCR_SS_LEVEL); 313*ec2b0ccdSEmmanuel Vadot else 314*ec2b0ccdSEmmanuel Vadot reg |= AW_SPI_TCR_SS_LEVEL; 315*ec2b0ccdSEmmanuel Vadot 316*ec2b0ccdSEmmanuel Vadot AW_SPI_WRITE_4(sc, AW_SPI_TCR, reg); 317*ec2b0ccdSEmmanuel Vadot } 318*ec2b0ccdSEmmanuel Vadot 319*ec2b0ccdSEmmanuel Vadot static uint64_t 320*ec2b0ccdSEmmanuel Vadot aw_spi_clock_test_cdr1(struct aw_spi_softc *sc, uint64_t clock, uint32_t *ccr) 321*ec2b0ccdSEmmanuel Vadot { 322*ec2b0ccdSEmmanuel Vadot uint64_t cur, best = 0; 323*ec2b0ccdSEmmanuel Vadot int i, max, best_div; 324*ec2b0ccdSEmmanuel Vadot 325*ec2b0ccdSEmmanuel Vadot max = AW_SPI_CCR_CDR1_MASK >> AW_SPI_CCR_CDR1_SHIFT; 326*ec2b0ccdSEmmanuel Vadot for (i = 0; i < max; i++) { 327*ec2b0ccdSEmmanuel Vadot cur = sc->mod_freq / (1 << i); 328*ec2b0ccdSEmmanuel Vadot if ((clock - cur) < (clock - best)) { 329*ec2b0ccdSEmmanuel Vadot best = cur; 330*ec2b0ccdSEmmanuel Vadot best_div = i; 331*ec2b0ccdSEmmanuel Vadot } 332*ec2b0ccdSEmmanuel Vadot } 333*ec2b0ccdSEmmanuel Vadot 334*ec2b0ccdSEmmanuel Vadot *ccr = (best_div << AW_SPI_CCR_CDR1_SHIFT); 335*ec2b0ccdSEmmanuel Vadot return (best); 336*ec2b0ccdSEmmanuel Vadot } 337*ec2b0ccdSEmmanuel Vadot 338*ec2b0ccdSEmmanuel Vadot static uint64_t 339*ec2b0ccdSEmmanuel Vadot aw_spi_clock_test_cdr2(struct aw_spi_softc *sc, uint64_t clock, uint32_t *ccr) 340*ec2b0ccdSEmmanuel Vadot { 341*ec2b0ccdSEmmanuel Vadot uint64_t cur, best = 0; 342*ec2b0ccdSEmmanuel Vadot int i, max, best_div; 343*ec2b0ccdSEmmanuel Vadot 344*ec2b0ccdSEmmanuel Vadot max = ((AW_SPI_CCR_CDR2_MASK) >> AW_SPI_CCR_CDR2_SHIFT); 345*ec2b0ccdSEmmanuel Vadot for (i = 0; i < max; i++) { 346*ec2b0ccdSEmmanuel Vadot cur = sc->mod_freq / (2 * i + 1); 347*ec2b0ccdSEmmanuel Vadot if ((clock - cur) < (clock - best)) { 348*ec2b0ccdSEmmanuel Vadot best = cur; 349*ec2b0ccdSEmmanuel Vadot best_div = i; 350*ec2b0ccdSEmmanuel Vadot } 351*ec2b0ccdSEmmanuel Vadot } 352*ec2b0ccdSEmmanuel Vadot 353*ec2b0ccdSEmmanuel Vadot *ccr = AW_SPI_CCR_DRS | (best_div << AW_SPI_CCR_CDR2_SHIFT); 354*ec2b0ccdSEmmanuel Vadot return (best); 355*ec2b0ccdSEmmanuel Vadot } 356*ec2b0ccdSEmmanuel Vadot 357*ec2b0ccdSEmmanuel Vadot static void 358*ec2b0ccdSEmmanuel Vadot aw_spi_setup_clock(struct aw_spi_softc *sc, uint64_t clock) 359*ec2b0ccdSEmmanuel Vadot { 360*ec2b0ccdSEmmanuel Vadot uint64_t best_ccr1, best_ccr2; 361*ec2b0ccdSEmmanuel Vadot uint32_t ccr, ccr1, ccr2; 362*ec2b0ccdSEmmanuel Vadot 363*ec2b0ccdSEmmanuel Vadot best_ccr1 = aw_spi_clock_test_cdr1(sc, clock, &ccr1); 364*ec2b0ccdSEmmanuel Vadot best_ccr2 = aw_spi_clock_test_cdr2(sc, clock, &ccr2); 365*ec2b0ccdSEmmanuel Vadot 366*ec2b0ccdSEmmanuel Vadot if (best_ccr1 == clock) { 367*ec2b0ccdSEmmanuel Vadot ccr = ccr1; 368*ec2b0ccdSEmmanuel Vadot } else if (best_ccr2 == clock) { 369*ec2b0ccdSEmmanuel Vadot ccr = ccr2; 370*ec2b0ccdSEmmanuel Vadot } else { 371*ec2b0ccdSEmmanuel Vadot if ((clock - best_ccr1) < (clock - best_ccr2)) 372*ec2b0ccdSEmmanuel Vadot ccr = ccr1; 373*ec2b0ccdSEmmanuel Vadot else 374*ec2b0ccdSEmmanuel Vadot ccr = ccr2; 375*ec2b0ccdSEmmanuel Vadot } 376*ec2b0ccdSEmmanuel Vadot 377*ec2b0ccdSEmmanuel Vadot AW_SPI_WRITE_4(sc, AW_SPI_CCR, ccr); 378*ec2b0ccdSEmmanuel Vadot } 379*ec2b0ccdSEmmanuel Vadot 380*ec2b0ccdSEmmanuel Vadot static inline void 381*ec2b0ccdSEmmanuel Vadot aw_spi_fill_txfifo(struct aw_spi_softc *sc) 382*ec2b0ccdSEmmanuel Vadot { 383*ec2b0ccdSEmmanuel Vadot uint32_t reg, txcnt; 384*ec2b0ccdSEmmanuel Vadot int i; 385*ec2b0ccdSEmmanuel Vadot 386*ec2b0ccdSEmmanuel Vadot if (sc->txcnt == sc->txlen) 387*ec2b0ccdSEmmanuel Vadot return; 388*ec2b0ccdSEmmanuel Vadot 389*ec2b0ccdSEmmanuel Vadot reg = AW_SPI_READ_4(sc, AW_SPI_FSR); 390*ec2b0ccdSEmmanuel Vadot reg &= AW_SPI_FSR_TF_CNT_MASK; 391*ec2b0ccdSEmmanuel Vadot txcnt = reg >> AW_SPI_FSR_TF_CNT_SHIFT; 392*ec2b0ccdSEmmanuel Vadot 393*ec2b0ccdSEmmanuel Vadot for (i = 0; i < (AW_SPI_FIFO_SIZE - txcnt); i++) { 394*ec2b0ccdSEmmanuel Vadot AW_SPI_WRITE_1(sc, AW_SPI_TXD, sc->txbuf[sc->txcnt++]); 395*ec2b0ccdSEmmanuel Vadot if (sc->txcnt == sc->txlen) 396*ec2b0ccdSEmmanuel Vadot break; 397*ec2b0ccdSEmmanuel Vadot } 398*ec2b0ccdSEmmanuel Vadot 399*ec2b0ccdSEmmanuel Vadot return; 400*ec2b0ccdSEmmanuel Vadot } 401*ec2b0ccdSEmmanuel Vadot 402*ec2b0ccdSEmmanuel Vadot static inline void 403*ec2b0ccdSEmmanuel Vadot aw_spi_read_rxfifo(struct aw_spi_softc *sc) 404*ec2b0ccdSEmmanuel Vadot { 405*ec2b0ccdSEmmanuel Vadot uint32_t reg; 406*ec2b0ccdSEmmanuel Vadot uint8_t val; 407*ec2b0ccdSEmmanuel Vadot int i; 408*ec2b0ccdSEmmanuel Vadot 409*ec2b0ccdSEmmanuel Vadot if (sc->rxcnt == sc->rxlen) 410*ec2b0ccdSEmmanuel Vadot return; 411*ec2b0ccdSEmmanuel Vadot 412*ec2b0ccdSEmmanuel Vadot reg = AW_SPI_READ_4(sc, AW_SPI_FSR); 413*ec2b0ccdSEmmanuel Vadot reg = (reg & AW_SPI_FSR_RF_CNT_MASK) >> AW_SPI_FSR_RF_CNT_SHIFT; 414*ec2b0ccdSEmmanuel Vadot 415*ec2b0ccdSEmmanuel Vadot for (i = 0; i < reg; i++) { 416*ec2b0ccdSEmmanuel Vadot val = AW_SPI_READ_1(sc, AW_SPI_RDX); 417*ec2b0ccdSEmmanuel Vadot if (sc->rxcnt < sc->rxlen) 418*ec2b0ccdSEmmanuel Vadot sc->rxbuf[sc->rxcnt++] = val; 419*ec2b0ccdSEmmanuel Vadot } 420*ec2b0ccdSEmmanuel Vadot } 421*ec2b0ccdSEmmanuel Vadot 422*ec2b0ccdSEmmanuel Vadot static int 423*ec2b0ccdSEmmanuel Vadot aw_spi_intr(void *arg) 424*ec2b0ccdSEmmanuel Vadot { 425*ec2b0ccdSEmmanuel Vadot struct aw_spi_softc *sc; 426*ec2b0ccdSEmmanuel Vadot uint32_t intr; 427*ec2b0ccdSEmmanuel Vadot 428*ec2b0ccdSEmmanuel Vadot sc = (struct aw_spi_softc *)arg; 429*ec2b0ccdSEmmanuel Vadot 430*ec2b0ccdSEmmanuel Vadot intr = AW_SPI_READ_4(sc, AW_SPI_ISR); 431*ec2b0ccdSEmmanuel Vadot 432*ec2b0ccdSEmmanuel Vadot if (intr & AW_SPI_IER_RF_RDY) 433*ec2b0ccdSEmmanuel Vadot aw_spi_read_rxfifo(sc); 434*ec2b0ccdSEmmanuel Vadot 435*ec2b0ccdSEmmanuel Vadot if (intr & AW_SPI_IER_TF_ERQ) { 436*ec2b0ccdSEmmanuel Vadot aw_spi_fill_txfifo(sc); 437*ec2b0ccdSEmmanuel Vadot 438*ec2b0ccdSEmmanuel Vadot /* 439*ec2b0ccdSEmmanuel Vadot * If we don't have anything else to write 440*ec2b0ccdSEmmanuel Vadot * disable TXFifo interrupts 441*ec2b0ccdSEmmanuel Vadot */ 442*ec2b0ccdSEmmanuel Vadot if (sc->txcnt == sc->txlen) 443*ec2b0ccdSEmmanuel Vadot AW_SPI_WRITE_4(sc, AW_SPI_IER, AW_SPI_IER_TC | 444*ec2b0ccdSEmmanuel Vadot AW_SPI_IER_RF_RDY); 445*ec2b0ccdSEmmanuel Vadot } 446*ec2b0ccdSEmmanuel Vadot 447*ec2b0ccdSEmmanuel Vadot if (intr & AW_SPI_IER_TC) { 448*ec2b0ccdSEmmanuel Vadot /* read the rest of the data from the fifo */ 449*ec2b0ccdSEmmanuel Vadot aw_spi_read_rxfifo(sc); 450*ec2b0ccdSEmmanuel Vadot 451*ec2b0ccdSEmmanuel Vadot /* Disable the interrupts */ 452*ec2b0ccdSEmmanuel Vadot AW_SPI_WRITE_4(sc, AW_SPI_IER, 0); 453*ec2b0ccdSEmmanuel Vadot sc->transfer = 0; 454*ec2b0ccdSEmmanuel Vadot wakeup(sc); 455*ec2b0ccdSEmmanuel Vadot } 456*ec2b0ccdSEmmanuel Vadot 457*ec2b0ccdSEmmanuel Vadot /* Clear Interrupts */ 458*ec2b0ccdSEmmanuel Vadot AW_SPI_WRITE_4(sc, AW_SPI_ISR, intr); 459*ec2b0ccdSEmmanuel Vadot return (intr != 0 ? FILTER_HANDLED : FILTER_STRAY); 460*ec2b0ccdSEmmanuel Vadot } 461*ec2b0ccdSEmmanuel Vadot 462*ec2b0ccdSEmmanuel Vadot static int 463*ec2b0ccdSEmmanuel Vadot aw_spi_xfer(struct aw_spi_softc *sc, void *rxbuf, void *txbuf, uint32_t txlen, uint32_t rxlen) 464*ec2b0ccdSEmmanuel Vadot { 465*ec2b0ccdSEmmanuel Vadot uint32_t reg; 466*ec2b0ccdSEmmanuel Vadot int error = 0, timeout; 467*ec2b0ccdSEmmanuel Vadot 468*ec2b0ccdSEmmanuel Vadot sc->rxbuf = rxbuf; 469*ec2b0ccdSEmmanuel Vadot sc->rxcnt = 0; 470*ec2b0ccdSEmmanuel Vadot sc->txbuf = txbuf; 471*ec2b0ccdSEmmanuel Vadot sc->txcnt = 0; 472*ec2b0ccdSEmmanuel Vadot sc->txlen = txlen; 473*ec2b0ccdSEmmanuel Vadot sc->rxlen = rxlen; 474*ec2b0ccdSEmmanuel Vadot 475*ec2b0ccdSEmmanuel Vadot /* Reset the FIFOs */ 476*ec2b0ccdSEmmanuel Vadot AW_SPI_WRITE_4(sc, AW_SPI_FCR, AW_SPI_FCR_TX_RST | AW_SPI_FCR_RX_RST); 477*ec2b0ccdSEmmanuel Vadot 478*ec2b0ccdSEmmanuel Vadot for (timeout = 1000; timeout > 0; timeout--) { 479*ec2b0ccdSEmmanuel Vadot reg = AW_SPI_READ_4(sc, AW_SPI_FCR); 480*ec2b0ccdSEmmanuel Vadot if (reg == 0) 481*ec2b0ccdSEmmanuel Vadot break; 482*ec2b0ccdSEmmanuel Vadot } 483*ec2b0ccdSEmmanuel Vadot if (timeout == 0) { 484*ec2b0ccdSEmmanuel Vadot device_printf(sc->dev, "Cannot reset the FIFOs\n"); 485*ec2b0ccdSEmmanuel Vadot return (EIO); 486*ec2b0ccdSEmmanuel Vadot } 487*ec2b0ccdSEmmanuel Vadot 488*ec2b0ccdSEmmanuel Vadot /* 489*ec2b0ccdSEmmanuel Vadot * Set the TX FIFO threshold to 3/4-th the size and 490*ec2b0ccdSEmmanuel Vadot * the RX FIFO one to 1/4-th. 491*ec2b0ccdSEmmanuel Vadot */ 492*ec2b0ccdSEmmanuel Vadot AW_SPI_WRITE_4(sc, AW_SPI_FCR, 493*ec2b0ccdSEmmanuel Vadot ((3 * AW_SPI_FIFO_SIZE / 4) << AW_SPI_FCR_TX_TRIG_SHIFT) | 494*ec2b0ccdSEmmanuel Vadot ((AW_SPI_FIFO_SIZE / 4) << AW_SPI_FCR_RX_TRIG_SHIFT)); 495*ec2b0ccdSEmmanuel Vadot 496*ec2b0ccdSEmmanuel Vadot /* Write the counters */ 497*ec2b0ccdSEmmanuel Vadot AW_SPI_WRITE_4(sc, AW_SPI_MBC, txlen); 498*ec2b0ccdSEmmanuel Vadot AW_SPI_WRITE_4(sc, AW_SPI_MTC, txlen); 499*ec2b0ccdSEmmanuel Vadot AW_SPI_WRITE_4(sc, AW_SPI_BCC, txlen); 500*ec2b0ccdSEmmanuel Vadot 501*ec2b0ccdSEmmanuel Vadot /* First fill */ 502*ec2b0ccdSEmmanuel Vadot aw_spi_fill_txfifo(sc); 503*ec2b0ccdSEmmanuel Vadot 504*ec2b0ccdSEmmanuel Vadot /* Start transmit */ 505*ec2b0ccdSEmmanuel Vadot reg = AW_SPI_READ_4(sc, AW_SPI_TCR); 506*ec2b0ccdSEmmanuel Vadot reg |= AW_SPI_TCR_XCH; 507*ec2b0ccdSEmmanuel Vadot AW_SPI_WRITE_4(sc, AW_SPI_TCR, reg); 508*ec2b0ccdSEmmanuel Vadot 509*ec2b0ccdSEmmanuel Vadot /* 510*ec2b0ccdSEmmanuel Vadot * Enable interrupts for : 511*ec2b0ccdSEmmanuel Vadot * Transmit complete 512*ec2b0ccdSEmmanuel Vadot * TX Fifo is below its trigger threshold 513*ec2b0ccdSEmmanuel Vadot * RX Fifo is above its trigger threshold 514*ec2b0ccdSEmmanuel Vadot */ 515*ec2b0ccdSEmmanuel Vadot AW_SPI_WRITE_4(sc, AW_SPI_IER, AW_SPI_IER_TC | 516*ec2b0ccdSEmmanuel Vadot AW_SPI_IER_TF_ERQ | AW_SPI_IER_RF_RDY); 517*ec2b0ccdSEmmanuel Vadot 518*ec2b0ccdSEmmanuel Vadot sc->transfer = 1; 519*ec2b0ccdSEmmanuel Vadot 520*ec2b0ccdSEmmanuel Vadot while (error == 0 && sc->transfer != 0) 521*ec2b0ccdSEmmanuel Vadot error = msleep(sc, &sc->mtx, 0, "aw_spi", 10 * hz); 522*ec2b0ccdSEmmanuel Vadot 523*ec2b0ccdSEmmanuel Vadot return (0); 524*ec2b0ccdSEmmanuel Vadot } 525*ec2b0ccdSEmmanuel Vadot 526*ec2b0ccdSEmmanuel Vadot static int 527*ec2b0ccdSEmmanuel Vadot aw_spi_transfer(device_t dev, device_t child, struct spi_command *cmd) 528*ec2b0ccdSEmmanuel Vadot { 529*ec2b0ccdSEmmanuel Vadot struct aw_spi_softc *sc; 530*ec2b0ccdSEmmanuel Vadot uint32_t cs, mode, clock, reg; 531*ec2b0ccdSEmmanuel Vadot int err = 0; 532*ec2b0ccdSEmmanuel Vadot 533*ec2b0ccdSEmmanuel Vadot sc = device_get_softc(dev); 534*ec2b0ccdSEmmanuel Vadot 535*ec2b0ccdSEmmanuel Vadot spibus_get_cs(child, &cs); 536*ec2b0ccdSEmmanuel Vadot spibus_get_clock(child, &clock); 537*ec2b0ccdSEmmanuel Vadot spibus_get_mode(child, &mode); 538*ec2b0ccdSEmmanuel Vadot 539*ec2b0ccdSEmmanuel Vadot /* The minimum divider is 2 so set the clock at twice the needed speed */ 540*ec2b0ccdSEmmanuel Vadot clk_set_freq(sc->clk_mod, 2 * clock, CLK_SET_ROUND_DOWN); 541*ec2b0ccdSEmmanuel Vadot clk_get_freq(sc->clk_mod, &sc->mod_freq); 542*ec2b0ccdSEmmanuel Vadot if (cs >= AW_SPI_MAX_CS) { 543*ec2b0ccdSEmmanuel Vadot device_printf(dev, "Invalid cs %d\n", cs); 544*ec2b0ccdSEmmanuel Vadot return (EINVAL); 545*ec2b0ccdSEmmanuel Vadot } 546*ec2b0ccdSEmmanuel Vadot 547*ec2b0ccdSEmmanuel Vadot mtx_lock(&sc->mtx); 548*ec2b0ccdSEmmanuel Vadot 549*ec2b0ccdSEmmanuel Vadot /* Enable and reset the module */ 550*ec2b0ccdSEmmanuel Vadot reg = AW_SPI_READ_4(sc, AW_SPI_GCR); 551*ec2b0ccdSEmmanuel Vadot reg |= AW_SPI_GCR_EN | AW_SPI_GCR_SRST; 552*ec2b0ccdSEmmanuel Vadot AW_SPI_WRITE_4(sc, AW_SPI_GCR, reg); 553*ec2b0ccdSEmmanuel Vadot 554*ec2b0ccdSEmmanuel Vadot /* Setup clock, CS and mode */ 555*ec2b0ccdSEmmanuel Vadot aw_spi_setup_clock(sc, clock); 556*ec2b0ccdSEmmanuel Vadot aw_spi_setup_mode(sc, mode); 557*ec2b0ccdSEmmanuel Vadot if (cs & SPIBUS_CS_HIGH) 558*ec2b0ccdSEmmanuel Vadot aw_spi_setup_cs(sc, cs, false); 559*ec2b0ccdSEmmanuel Vadot else 560*ec2b0ccdSEmmanuel Vadot aw_spi_setup_cs(sc, cs, true); 561*ec2b0ccdSEmmanuel Vadot 562*ec2b0ccdSEmmanuel Vadot /* xfer */ 563*ec2b0ccdSEmmanuel Vadot err = 0; 564*ec2b0ccdSEmmanuel Vadot if (cmd->tx_cmd_sz > 0) 565*ec2b0ccdSEmmanuel Vadot err = aw_spi_xfer(sc, cmd->rx_cmd, cmd->tx_cmd, 566*ec2b0ccdSEmmanuel Vadot cmd->tx_cmd_sz, cmd->rx_cmd_sz); 567*ec2b0ccdSEmmanuel Vadot if (cmd->tx_data_sz > 0 && err == 0) 568*ec2b0ccdSEmmanuel Vadot err = aw_spi_xfer(sc, cmd->rx_data, cmd->tx_data, 569*ec2b0ccdSEmmanuel Vadot cmd->tx_data_sz, cmd->rx_data_sz); 570*ec2b0ccdSEmmanuel Vadot 571*ec2b0ccdSEmmanuel Vadot if (cs & SPIBUS_CS_HIGH) 572*ec2b0ccdSEmmanuel Vadot aw_spi_setup_cs(sc, cs, true); 573*ec2b0ccdSEmmanuel Vadot else 574*ec2b0ccdSEmmanuel Vadot aw_spi_setup_cs(sc, cs, false); 575*ec2b0ccdSEmmanuel Vadot 576*ec2b0ccdSEmmanuel Vadot /* Disable the module */ 577*ec2b0ccdSEmmanuel Vadot reg = AW_SPI_READ_4(sc, AW_SPI_GCR); 578*ec2b0ccdSEmmanuel Vadot reg &= ~AW_SPI_GCR_EN; 579*ec2b0ccdSEmmanuel Vadot AW_SPI_WRITE_4(sc, AW_SPI_GCR, reg); 580*ec2b0ccdSEmmanuel Vadot 581*ec2b0ccdSEmmanuel Vadot mtx_unlock(&sc->mtx); 582*ec2b0ccdSEmmanuel Vadot 583*ec2b0ccdSEmmanuel Vadot return (err); 584*ec2b0ccdSEmmanuel Vadot } 585*ec2b0ccdSEmmanuel Vadot 586*ec2b0ccdSEmmanuel Vadot static device_method_t aw_spi_methods[] = { 587*ec2b0ccdSEmmanuel Vadot /* Device interface */ 588*ec2b0ccdSEmmanuel Vadot DEVMETHOD(device_probe, aw_spi_probe), 589*ec2b0ccdSEmmanuel Vadot DEVMETHOD(device_attach, aw_spi_attach), 590*ec2b0ccdSEmmanuel Vadot DEVMETHOD(device_detach, aw_spi_detach), 591*ec2b0ccdSEmmanuel Vadot 592*ec2b0ccdSEmmanuel Vadot /* spibus_if */ 593*ec2b0ccdSEmmanuel Vadot DEVMETHOD(spibus_transfer, aw_spi_transfer), 594*ec2b0ccdSEmmanuel Vadot 595*ec2b0ccdSEmmanuel Vadot /* ofw_bus_if */ 596*ec2b0ccdSEmmanuel Vadot DEVMETHOD(ofw_bus_get_node, aw_spi_get_node), 597*ec2b0ccdSEmmanuel Vadot 598*ec2b0ccdSEmmanuel Vadot DEVMETHOD_END 599*ec2b0ccdSEmmanuel Vadot }; 600*ec2b0ccdSEmmanuel Vadot 601*ec2b0ccdSEmmanuel Vadot static driver_t aw_spi_driver = { 602*ec2b0ccdSEmmanuel Vadot "aw_spi", 603*ec2b0ccdSEmmanuel Vadot aw_spi_methods, 604*ec2b0ccdSEmmanuel Vadot sizeof(struct aw_spi_softc), 605*ec2b0ccdSEmmanuel Vadot }; 606*ec2b0ccdSEmmanuel Vadot 607*ec2b0ccdSEmmanuel Vadot DRIVER_MODULE(aw_spi, simplebus, aw_spi_driver, 0, 0); 608*ec2b0ccdSEmmanuel Vadot DRIVER_MODULE(ofw_spibus, aw_spi, ofw_spibus_driver, 0, 0); 609*ec2b0ccdSEmmanuel Vadot MODULE_DEPEND(aw_spi, ofw_spibus, 1, 1, 1); 610*ec2b0ccdSEmmanuel Vadot SIMPLEBUS_PNP_INFO(compat_data); 611