in spi-synquacer.c [228:351]
static int synquacer_spi_config(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
{
struct synquacer_spi *sspi = spi_master_get_devdata(master);
unsigned int speed, mode, bpw, cs, bus_width, transfer_mode;
u32 rate, val, div;
/* Full Duplex only on 1-bit wide bus */
if (xfer->rx_buf && xfer->tx_buf &&
(xfer->rx_nbits != 1 || xfer->tx_nbits != 1)) {
dev_err(sspi->dev,
"RX and TX bus widths must be 1-bit for Full-Duplex!\n");
return -EINVAL;
}
if (xfer->tx_buf) {
bus_width = xfer->tx_nbits;
transfer_mode = SYNQUACER_HSSPI_TRANSFER_MODE_TX;
} else {
bus_width = xfer->rx_nbits;
transfer_mode = SYNQUACER_HSSPI_TRANSFER_MODE_RX;
}
mode = spi->mode;
cs = spi->chip_select;
speed = xfer->speed_hz;
bpw = xfer->bits_per_word;
/* return if nothing to change */
if (speed == sspi->speed &&
bus_width == sspi->bus_width && bpw == sspi->bpw &&
mode == sspi->mode && cs == sspi->cs &&
transfer_mode == sspi->transfer_mode) {
return 0;
}
sspi->transfer_mode = transfer_mode;
rate = master->max_speed_hz;
div = DIV_ROUND_UP(rate, speed);
if (div > 254) {
dev_err(sspi->dev, "Requested rate too low (%u)\n",
sspi->speed);
return -EINVAL;
}
val = readl(sspi->regs + SYNQUACER_HSSPI_REG_PCC(cs));
val &= ~SYNQUACER_HSSPI_PCC_SAFESYNC;
if (bpw == 8 && (mode & (SPI_TX_DUAL | SPI_RX_DUAL)) && div < 3)
val |= SYNQUACER_HSSPI_PCC_SAFESYNC;
if (bpw == 8 && (mode & (SPI_TX_QUAD | SPI_RX_QUAD)) && div < 6)
val |= SYNQUACER_HSSPI_PCC_SAFESYNC;
if (bpw == 16 && (mode & (SPI_TX_QUAD | SPI_RX_QUAD)) && div < 3)
val |= SYNQUACER_HSSPI_PCC_SAFESYNC;
if (mode & SPI_CPHA)
val |= SYNQUACER_HSSPI_PCC_CPHA;
else
val &= ~SYNQUACER_HSSPI_PCC_CPHA;
if (mode & SPI_CPOL)
val |= SYNQUACER_HSSPI_PCC_CPOL;
else
val &= ~SYNQUACER_HSSPI_PCC_CPOL;
if (mode & SPI_CS_HIGH)
val |= SYNQUACER_HSSPI_PCC_SSPOL;
else
val &= ~SYNQUACER_HSSPI_PCC_SSPOL;
if (mode & SPI_LSB_FIRST)
val |= SYNQUACER_HSSPI_PCC_SDIR;
else
val &= ~SYNQUACER_HSSPI_PCC_SDIR;
if (sspi->aces)
val |= SYNQUACER_HSSPI_PCC_ACES;
else
val &= ~SYNQUACER_HSSPI_PCC_ACES;
if (sspi->rtm)
val |= SYNQUACER_HSSPI_PCC_RTM;
else
val &= ~SYNQUACER_HSSPI_PCC_RTM;
val |= (3 << SYNQUACER_HSSPI_PCC_SS2CD_SHIFT);
val |= SYNQUACER_HSSPI_PCC_SENDIAN;
val &= ~(SYNQUACER_HSSPI_PCC_CDRS_MASK <<
SYNQUACER_HSSPI_PCC_CDRS_SHIFT);
val |= ((div >> 1) << SYNQUACER_HSSPI_PCC_CDRS_SHIFT);
writel(val, sspi->regs + SYNQUACER_HSSPI_REG_PCC(cs));
val = readl(sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG);
val &= ~(SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_MASK <<
SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT);
val |= ((bpw / 8 - 1) << SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT);
writel(val, sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG);
val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
val &= ~(SYNQUACER_HSSPI_DMTRP_DATA_MASK <<
SYNQUACER_HSSPI_DMTRP_DATA_SHIFT);
if (xfer->rx_buf)
val |= (SYNQUACER_HSSPI_DMTRP_DATA_RX <<
SYNQUACER_HSSPI_DMTRP_DATA_SHIFT);
else
val |= (SYNQUACER_HSSPI_DMTRP_DATA_TX <<
SYNQUACER_HSSPI_DMTRP_DATA_SHIFT);
val &= ~(3 << SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT);
val |= ((bus_width >> 1) << SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT);
writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
sspi->bpw = bpw;
sspi->mode = mode;
sspi->speed = speed;
sspi->cs = spi->chip_select;
sspi->bus_width = bus_width;
return 0;
}