static void tiny_spi_chipselect(struct spi_device *spi, int is_active) { struct tiny_spi *hw = tiny_spi_to_hw(spi); if (hw->gpio_cs_count > 0) { gpio_set_value(hw->gpio_cs[spi->chip_select], (spi->mode & SPI_CS_HIGH) ? is_active : !is_active); } }
static int tiny_spi_setup(struct spi_device *spi) { struct tiny_spi *hw = tiny_spi_to_hw(spi); if (spi->max_speed_hz != hw->speed_hz) { hw->speed_hz = spi->max_speed_hz; hw->baud = tiny_spi_baud(spi, hw->speed_hz); } hw->mode = spi->mode & (SPI_CPOL | SPI_CPHA); return 0; }
static int tiny_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) { struct tiny_spi *hw = tiny_spi_to_hw(spi); unsigned int baud = hw->baud; if (t) { if (t->speed_hz && t->speed_hz != hw->speed_hz) baud = tiny_spi_baud(spi, t->speed_hz); } writel(baud, hw->base + TINY_SPI_BAUD); writel(hw->mode, hw->base + TINY_SPI_CONTROL); return 0; }
static int tiny_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) { struct tiny_spi *hw = tiny_spi_to_hw(spi); const u8 *txp = t->tx_buf; u8 *rxp = t->rx_buf; unsigned int i; if (hw->irq >= 0) { /* use interrupt driven data transfer */ hw->len = t->len; hw->txp = t->tx_buf; hw->rxp = t->rx_buf; hw->txc = 0; hw->rxc = 0; /* send the first byte */ if (t->len > 1) { writeb(hw->txp ? *hw->txp++ : 0, hw->base + TINY_SPI_TXDATA); hw->txc++; writeb(hw->txp ? *hw->txp++ : 0, hw->base + TINY_SPI_TXDATA); hw->txc++; writeb(TINY_SPI_STATUS_TXR, hw->base + TINY_SPI_STATUS); } else { writeb(hw->txp ? *hw->txp++ : 0, hw->base + TINY_SPI_TXDATA); hw->txc++; writeb(TINY_SPI_STATUS_TXE, hw->base + TINY_SPI_STATUS); } wait_for_completion(&hw->done); } else { /* we need to tighten the transfer loop */ writeb(txp ? *txp++ : 0, hw->base + TINY_SPI_TXDATA); for (i = 1; i < t->len; i++) { writeb(txp ? *txp++ : 0, hw->base + TINY_SPI_TXDATA); if (rxp || (i != t->len - 1)) tiny_spi_wait_txr(hw); if (rxp) *rxp++ = readb(hw->base + TINY_SPI_TXDATA); } tiny_spi_wait_txe(hw); if (rxp) *rxp++ = readb(hw->base + TINY_SPI_RXDATA); } return t->len; }
static unsigned int tiny_spi_baud(struct spi_device *spi, unsigned int hz) { struct tiny_spi *hw = tiny_spi_to_hw(spi); return min(DIV_ROUND_UP(hw->freq, hz * 2), (1U << hw->baudwidth)) - 1; }
static int tiny_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) { struct tiny_spi *hw = tiny_spi_to_hw(spi); const u8 *txp = t->tx_buf; u8 *rxp = t->rx_buf; unsigned int i; if (hw->irq >= 0) { hw->len = t->len; hw->txp = t->tx_buf; hw->rxp = t->rx_buf; hw->txc = 0; hw->rxc = 0; if (t->len > 1) { writeb(hw->txp ? *hw->txp++ : 0, hw->base + TINY_SPI_TXDATA); hw->txc++; writeb(hw->txp ? *hw->txp++ : 0, hw->base + TINY_SPI_TXDATA); hw->txc++; writeb(TINY_SPI_STATUS_TXR, hw->base + TINY_SPI_STATUS); } else { writeb(hw->txp ? *hw->txp++ : 0, hw->base + TINY_SPI_TXDATA); hw->txc++; writeb(TINY_SPI_STATUS_TXE, hw->base + TINY_SPI_STATUS); } wait_for_completion(&hw->done); } else if (txp && rxp) { writeb(*txp++, hw->base + TINY_SPI_TXDATA); if (t->len > 1) { writeb(*txp++, hw->base + TINY_SPI_TXDATA); for (i = 2; i < t->len; i++) { u8 rx, tx = *txp++; tiny_spi_wait_txr(hw); rx = readb(hw->base + TINY_SPI_TXDATA); writeb(tx, hw->base + TINY_SPI_TXDATA); *rxp++ = rx; } tiny_spi_wait_txr(hw); *rxp++ = readb(hw->base + TINY_SPI_TXDATA); } tiny_spi_wait_txe(hw); *rxp++ = readb(hw->base + TINY_SPI_RXDATA); } else if (rxp) { writeb(0, hw->base + TINY_SPI_TXDATA); if (t->len > 1) { writeb(0, hw->base + TINY_SPI_TXDATA); for (i = 2; i < t->len; i++) { u8 rx; tiny_spi_wait_txr(hw); rx = readb(hw->base + TINY_SPI_TXDATA); writeb(0, hw->base + TINY_SPI_TXDATA); *rxp++ = rx; } tiny_spi_wait_txr(hw); *rxp++ = readb(hw->base + TINY_SPI_TXDATA); } tiny_spi_wait_txe(hw); *rxp++ = readb(hw->base + TINY_SPI_RXDATA); } else if (txp) { writeb(*txp++, hw->base + TINY_SPI_TXDATA); if (t->len > 1) { writeb(*txp++, hw->base + TINY_SPI_TXDATA); for (i = 2; i < t->len; i++) { u8 tx = *txp++; tiny_spi_wait_txr(hw); writeb(tx, hw->base + TINY_SPI_TXDATA); } } tiny_spi_wait_txe(hw); } else { writeb(0, hw->base + TINY_SPI_TXDATA); if (t->len > 1) { writeb(0, hw->base + TINY_SPI_TXDATA); for (i = 2; i < t->len; i++) { tiny_spi_wait_txr(hw); writeb(0, hw->base + TINY_SPI_TXDATA); } } tiny_spi_wait_txe(hw); } return t->len; }