static int ar71xx_spi_transfer(device_t dev, device_t child, struct spi_command *cmd) { struct ar71xx_spi_softc *sc; uint32_t cs; uint8_t *buf_in, *buf_out; int i; sc = device_get_softc(dev); spibus_get_cs(child, &cs); cs &= ~SPIBUS_CS_HIGH; ar71xx_spi_chip_activate(sc, cs); KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz, ("TX/RX command sizes should be equal")); KASSERT(cmd->tx_data_sz == cmd->rx_data_sz, ("TX/RX data sizes should be equal")); /* * Transfer command */ buf_out = (uint8_t *)cmd->tx_cmd; buf_in = (uint8_t *)cmd->rx_cmd; for (i = 0; i < cmd->tx_cmd_sz; i++) buf_in[i] = ar71xx_spi_txrx(sc, cs, buf_out[i]); /* * Receive/transmit data (depends on command) */ buf_out = (uint8_t *)cmd->tx_data; buf_in = (uint8_t *)cmd->rx_data; for (i = 0; i < cmd->tx_data_sz; i++) buf_in[i] = ar71xx_spi_txrx(sc, cs, buf_out[i]); ar71xx_spi_chip_deactivate(sc, cs); return (0); }
static int spi_transfer(device_t dev, device_t child, struct spi_command *cmd) { struct spi_softc *sc; uint32_t cs; sc = device_get_softc(dev); KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz, ("%s: TX/RX command sizes should be equal", __func__)); KASSERT(cmd->tx_data_sz == cmd->rx_data_sz, ("%s: TX/RX data sizes should be equal", __func__)); /* get the proper chip select */ spibus_get_cs(child, &cs); /* Command */ spi_txrx(sc, cmd->tx_cmd, cmd->rx_cmd, cmd->tx_cmd_sz, cs); /* Data */ spi_txrx(sc, cmd->tx_data, cmd->rx_data, cmd->tx_data_sz, cs); return (0); }
static int bcm_spi_transfer(device_t dev, device_t child, struct spi_command *cmd) { struct bcm_spi_softc *sc; uint32_t cs; int err; sc = device_get_softc(dev); KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz, ("TX/RX command sizes should be equal")); KASSERT(cmd->tx_data_sz == cmd->rx_data_sz, ("TX/RX data sizes should be equal")); /* Get the proper chip select for this child. */ spibus_get_cs(child, &cs); cs &= ~SPIBUS_CS_HIGH; if (cs > 2) { device_printf(dev, "Invalid chip select %d requested by %s\n", cs, device_get_nameunit(child)); return (EINVAL); } BCM_SPI_LOCK(sc); /* If the controller is in use wait until it is available. */ while (sc->sc_flags & BCM_SPI_BUSY) mtx_sleep(dev, &sc->sc_mtx, 0, "bcm_spi", 0); /* Now we have control over SPI controller. */ sc->sc_flags = BCM_SPI_BUSY; /* Clear the FIFO. */ bcm_spi_modifyreg(sc, SPI_CS, SPI_CS_CLEAR_RXFIFO | SPI_CS_CLEAR_TXFIFO, SPI_CS_CLEAR_RXFIFO | SPI_CS_CLEAR_TXFIFO); /* Save a pointer to the SPI command. */ sc->sc_cmd = cmd; sc->sc_read = 0; sc->sc_written = 0; sc->sc_len = cmd->tx_cmd_sz + cmd->tx_data_sz; /* * Set the CS for this transaction, enable interrupts and announce * we're ready to tx. This will kick off the first interrupt. */ bcm_spi_modifyreg(sc, SPI_CS, SPI_CS_MASK | SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD, cs | SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD); /* Wait for the transaction to complete. */ err = mtx_sleep(dev, &sc->sc_mtx, 0, "bcm_spi", hz * 2); /* Make sure the SPI engine and interrupts are disabled. */ bcm_spi_modifyreg(sc, SPI_CS, SPI_CS_TA | SPI_CS_INTR | SPI_CS_INTD, 0); /* Release the controller and wakeup the next thread waiting for it. */ sc->sc_flags = 0; wakeup_one(dev); BCM_SPI_UNLOCK(sc); /* * Check for transfer timeout. The SPI controller doesn't * return errors. */ if (err == EWOULDBLOCK) { device_printf(sc->sc_dev, "SPI error\n"); err = EIO; } return (err); }
static int rt305x_spi_transfer(device_t dev, device_t child, struct spi_command *cmd) { struct rt305x_spi_softc *sc; uint32_t cs; uint8_t *buf, byte, *tx_buf; int i, sz, error = 0, write = 0; sc = device_get_softc(dev); spibus_get_cs(child, &cs); if (cs != 0) /* Only 1 CS */ return (ENXIO); /* There is always a command to transfer. */ tx_buf = (uint8_t *)(cmd->tx_cmd); /* Perform some fixup because RT305X dont support duplex SPI */ switch(tx_buf[0]) { case CMD_READ_IDENT: cmd->tx_cmd_sz = 1; cmd->rx_cmd_sz = 3; break; case CMD_WRITE_ENABLE: case CMD_WRITE_DISABLE: cmd->tx_cmd_sz = 1; cmd->rx_cmd_sz = 0; break; case CMD_READ_STATUS: cmd->tx_cmd_sz = 1; cmd->rx_cmd_sz = 1; break; case CMD_READ: cmd->tx_cmd_sz = 4; case CMD_FAST_READ: cmd->tx_cmd_sz = 5; cmd->rx_cmd_sz = cmd->tx_data_sz = 0; break; case CMD_SECTOR_ERASE: cmd->tx_cmd_sz = 4; cmd->rx_cmd_sz = cmd->tx_data_sz = 0; break; case CMD_PAGE_PROGRAM: cmd->tx_cmd_sz = 4; cmd->rx_cmd_sz = cmd->rx_data_sz = 0; break; } rt305x_spi_chip_activate(sc); if (cmd->tx_cmd_sz + cmd->rx_cmd_sz) { buf = (uint8_t *)(cmd->rx_cmd); tx_buf = (uint8_t *)(cmd->tx_cmd); sz = cmd->tx_cmd_sz + cmd->rx_cmd_sz; for (i = 0; i < sz; i++) { if(i < cmd->tx_cmd_sz) { byte = tx_buf[i]; error = rt305x_spi_txrx(sc, &byte, RT305X_SPI_WRITE); if (error) goto rt305x_spi_transfer_fail; continue; } error = rt305x_spi_txrx(sc, &byte, RT305X_SPI_READ); if (error) goto rt305x_spi_transfer_fail; buf[i] = byte; } } /* * Transfer/Receive data */ if (cmd->tx_data_sz + cmd->rx_data_sz) { write = (cmd->tx_data_sz > 0)?1:0; buf = (uint8_t *)(write ? cmd->tx_data : cmd->rx_data); sz = write ? cmd->tx_data_sz : cmd->rx_data_sz; for (i = 0; i < sz; i++) { byte = buf[i]; error = rt305x_spi_txrx(sc, &byte, write?RT305X_SPI_WRITE:RT305X_SPI_READ); if (error) goto rt305x_spi_transfer_fail; buf[i] = byte; } } rt305x_spi_transfer_fail: rt305x_spi_chip_deactivate(sc); return (error); }