Merge remote-tracking branch 'spi/topic/xilinx' into spi-next

This commit is contained in:
Mark Brown 2015-02-08 11:17:01 +08:00
commit 66886337bf

View file

@ -22,6 +22,8 @@
#include <linux/spi/xilinx_spi.h> #include <linux/spi/xilinx_spi.h>
#include <linux/io.h> #include <linux/io.h>
#define XILINX_SPI_MAX_CS 32
#define XILINX_SPI_NAME "xilinx_spi" #define XILINX_SPI_NAME "xilinx_spi"
/* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e) /* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e)
@ -34,7 +36,8 @@
#define XSPI_CR_MASTER_MODE 0x04 #define XSPI_CR_MASTER_MODE 0x04
#define XSPI_CR_CPOL 0x08 #define XSPI_CR_CPOL 0x08
#define XSPI_CR_CPHA 0x10 #define XSPI_CR_CPHA 0x10
#define XSPI_CR_MODE_MASK (XSPI_CR_CPHA | XSPI_CR_CPOL) #define XSPI_CR_MODE_MASK (XSPI_CR_CPHA | XSPI_CR_CPOL | \
XSPI_CR_LSB_FIRST | XSPI_CR_LOOP)
#define XSPI_CR_TXFIFO_RESET 0x20 #define XSPI_CR_TXFIFO_RESET 0x20
#define XSPI_CR_RXFIFO_RESET 0x40 #define XSPI_CR_RXFIFO_RESET 0x40
#define XSPI_CR_MANUAL_SSELECT 0x80 #define XSPI_CR_MANUAL_SSELECT 0x80
@ -85,12 +88,11 @@ struct xilinx_spi {
u8 *rx_ptr; /* pointer in the Tx buffer */ u8 *rx_ptr; /* pointer in the Tx buffer */
const u8 *tx_ptr; /* pointer in the Rx buffer */ const u8 *tx_ptr; /* pointer in the Rx buffer */
int remaining_bytes; /* the number of bytes left to transfer */ u8 bytes_per_word;
u8 bits_per_word; int buffer_size; /* buffer size in words */
u32 cs_inactive; /* Level of the CS pins when inactive*/
unsigned int (*read_fn)(void __iomem *); unsigned int (*read_fn)(void __iomem *);
void (*write_fn)(u32, void __iomem *); void (*write_fn)(u32, void __iomem *);
void (*tx_fn)(struct xilinx_spi *);
void (*rx_fn)(struct xilinx_spi *);
}; };
static void xspi_write32(u32 val, void __iomem *addr) static void xspi_write32(u32 val, void __iomem *addr)
@ -113,49 +115,51 @@ static unsigned int xspi_read32_be(void __iomem *addr)
return ioread32be(addr); return ioread32be(addr);
} }
static void xspi_tx8(struct xilinx_spi *xspi) static void xilinx_spi_tx(struct xilinx_spi *xspi)
{ {
xspi->write_fn(*xspi->tx_ptr, xspi->regs + XSPI_TXD_OFFSET); u32 data = 0;
xspi->tx_ptr++;
}
static void xspi_tx16(struct xilinx_spi *xspi) if (!xspi->tx_ptr) {
{ xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET);
xspi->write_fn(*(u16 *)(xspi->tx_ptr), xspi->regs + XSPI_TXD_OFFSET); return;
xspi->tx_ptr += 2;
}
static void xspi_tx32(struct xilinx_spi *xspi)
{
xspi->write_fn(*(u32 *)(xspi->tx_ptr), xspi->regs + XSPI_TXD_OFFSET);
xspi->tx_ptr += 4;
}
static void xspi_rx8(struct xilinx_spi *xspi)
{
u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET);
if (xspi->rx_ptr) {
*xspi->rx_ptr = data & 0xff;
xspi->rx_ptr++;
} }
}
static void xspi_rx16(struct xilinx_spi *xspi) switch (xspi->bytes_per_word) {
{ case 1:
u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET); data = *(u8 *)(xspi->tx_ptr);
if (xspi->rx_ptr) { break;
*(u16 *)(xspi->rx_ptr) = data & 0xffff; case 2:
xspi->rx_ptr += 2; data = *(u16 *)(xspi->tx_ptr);
break;
case 4:
data = *(u32 *)(xspi->tx_ptr);
break;
} }
xspi->write_fn(data, xspi->regs + XSPI_TXD_OFFSET);
xspi->tx_ptr += xspi->bytes_per_word;
} }
static void xspi_rx32(struct xilinx_spi *xspi) static void xilinx_spi_rx(struct xilinx_spi *xspi)
{ {
u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET); u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET);
if (xspi->rx_ptr) {
if (!xspi->rx_ptr)
return;
switch (xspi->bytes_per_word) {
case 1:
*(u8 *)(xspi->rx_ptr) = data;
break;
case 2:
*(u16 *)(xspi->rx_ptr) = data;
break;
case 4:
*(u32 *)(xspi->rx_ptr) = data; *(u32 *)(xspi->rx_ptr) = data;
xspi->rx_ptr += 4; break;
} }
xspi->rx_ptr += xspi->bytes_per_word;
} }
static void xspi_init_hw(struct xilinx_spi *xspi) static void xspi_init_hw(struct xilinx_spi *xspi)
@ -165,46 +169,56 @@ static void xspi_init_hw(struct xilinx_spi *xspi)
/* Reset the SPI device */ /* Reset the SPI device */
xspi->write_fn(XIPIF_V123B_RESET_MASK, xspi->write_fn(XIPIF_V123B_RESET_MASK,
regs_base + XIPIF_V123B_RESETR_OFFSET); regs_base + XIPIF_V123B_RESETR_OFFSET);
/* Disable all the interrupts just in case */ /* Enable the transmit empty interrupt, which we use to determine
xspi->write_fn(0, regs_base + XIPIF_V123B_IIER_OFFSET); * progress on the transmission.
/* Enable the global IPIF interrupt */ */
xspi->write_fn(XIPIF_V123B_GINTR_ENABLE, xspi->write_fn(XSPI_INTR_TX_EMPTY,
regs_base + XIPIF_V123B_DGIER_OFFSET); regs_base + XIPIF_V123B_IIER_OFFSET);
/* Disable the global IPIF interrupt */
xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET);
/* Deselect the slave on the SPI bus */ /* Deselect the slave on the SPI bus */
xspi->write_fn(0xffff, regs_base + XSPI_SSR_OFFSET); xspi->write_fn(0xffff, regs_base + XSPI_SSR_OFFSET);
/* Disable the transmitter, enable Manual Slave Select Assertion, /* Disable the transmitter, enable Manual Slave Select Assertion,
* put SPI controller into master mode, and enable it */ * put SPI controller into master mode, and enable it */
xspi->write_fn(XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT | xspi->write_fn(XSPI_CR_MANUAL_SSELECT | XSPI_CR_MASTER_MODE |
XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET | XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET | XSPI_CR_RXFIFO_RESET,
XSPI_CR_RXFIFO_RESET, regs_base + XSPI_CR_OFFSET); regs_base + XSPI_CR_OFFSET);
} }
static void xilinx_spi_chipselect(struct spi_device *spi, int is_on) static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
{ {
struct xilinx_spi *xspi = spi_master_get_devdata(spi->master); struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
u16 cr;
u32 cs;
if (is_on == BITBANG_CS_INACTIVE) { if (is_on == BITBANG_CS_INACTIVE) {
/* Deselect the slave on the SPI bus */ /* Deselect the slave on the SPI bus */
xspi->write_fn(0xffff, xspi->regs + XSPI_SSR_OFFSET); xspi->write_fn(xspi->cs_inactive, xspi->regs + XSPI_SSR_OFFSET);
} else if (is_on == BITBANG_CS_ACTIVE) { return;
/* Set the SPI clock phase and polarity */
u16 cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET)
& ~XSPI_CR_MODE_MASK;
if (spi->mode & SPI_CPHA)
cr |= XSPI_CR_CPHA;
if (spi->mode & SPI_CPOL)
cr |= XSPI_CR_CPOL;
xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
/* We do not check spi->max_speed_hz here as the SPI clock
* frequency is not software programmable (the IP block design
* parameter)
*/
/* Activate the chip select */
xspi->write_fn(~(0x0001 << spi->chip_select),
xspi->regs + XSPI_SSR_OFFSET);
} }
/* Set the SPI clock phase and polarity */
cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) & ~XSPI_CR_MODE_MASK;
if (spi->mode & SPI_CPHA)
cr |= XSPI_CR_CPHA;
if (spi->mode & SPI_CPOL)
cr |= XSPI_CR_CPOL;
if (spi->mode & SPI_LSB_FIRST)
cr |= XSPI_CR_LSB_FIRST;
if (spi->mode & SPI_LOOP)
cr |= XSPI_CR_LOOP;
xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
/* We do not check spi->max_speed_hz here as the SPI clock
* frequency is not software programmable (the IP block design
* parameter)
*/
cs = xspi->cs_inactive;
cs ^= BIT(spi->chip_select);
/* Activate the chip select */
xspi->write_fn(cs, xspi->regs + XSPI_SSR_OFFSET);
} }
/* spi_bitbang requires custom setup_transfer() to be defined if there is a /* spi_bitbang requires custom setup_transfer() to be defined if there is a
@ -213,85 +227,85 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
static int xilinx_spi_setup_transfer(struct spi_device *spi, static int xilinx_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t) struct spi_transfer *t)
{ {
struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
if (spi->mode & SPI_CS_HIGH)
xspi->cs_inactive &= ~BIT(spi->chip_select);
else
xspi->cs_inactive |= BIT(spi->chip_select);
return 0; return 0;
} }
static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
{
u8 sr;
/* Fill the Tx FIFO with as many bytes as possible */
sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
while ((sr & XSPI_SR_TX_FULL_MASK) == 0 && xspi->remaining_bytes > 0) {
if (xspi->tx_ptr)
xspi->tx_fn(xspi);
else
xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET);
xspi->remaining_bytes -= xspi->bits_per_word / 8;
sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
}
}
static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
{ {
struct xilinx_spi *xspi = spi_master_get_devdata(spi->master); struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
u32 ipif_ier; int remaining_words; /* the number of words left to transfer */
bool use_irq = false;
u16 cr = 0;
/* We get here with transmitter inhibited */ /* We get here with transmitter inhibited */
xspi->tx_ptr = t->tx_buf; xspi->tx_ptr = t->tx_buf;
xspi->rx_ptr = t->rx_buf; xspi->rx_ptr = t->rx_buf;
xspi->remaining_bytes = t->len; remaining_words = t->len / xspi->bytes_per_word;
reinit_completion(&xspi->done); reinit_completion(&xspi->done);
if (xspi->irq >= 0 && remaining_words > xspi->buffer_size) {
use_irq = true;
xspi->write_fn(XSPI_INTR_TX_EMPTY,
xspi->regs + XIPIF_V123B_IISR_OFFSET);
/* Enable the global IPIF interrupt */
xspi->write_fn(XIPIF_V123B_GINTR_ENABLE,
xspi->regs + XIPIF_V123B_DGIER_OFFSET);
/* Inhibit irq to avoid spurious irqs on tx_empty*/
cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
xspi->regs + XSPI_CR_OFFSET);
}
/* Enable the transmit empty interrupt, which we use to determine while (remaining_words) {
* progress on the transmission. int n_words, tx_words, rx_words;
*/
ipif_ier = xspi->read_fn(xspi->regs + XIPIF_V123B_IIER_OFFSET);
xspi->write_fn(ipif_ier | XSPI_INTR_TX_EMPTY,
xspi->regs + XIPIF_V123B_IIER_OFFSET);
for (;;) { n_words = min(remaining_words, xspi->buffer_size);
u16 cr;
u8 sr;
xilinx_spi_fill_tx_fifo(xspi); tx_words = n_words;
while (tx_words--)
xilinx_spi_tx(xspi);
/* Start the transfer by not inhibiting the transmitter any /* Start the transfer by not inhibiting the transmitter any
* longer * longer
*/ */
cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) &
~XSPI_CR_TRANS_INHIBIT;
xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
wait_for_completion(&xspi->done); if (use_irq) {
xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
wait_for_completion(&xspi->done);
} else
while (!(xspi->read_fn(xspi->regs + XSPI_SR_OFFSET) &
XSPI_SR_TX_EMPTY_MASK))
;
/* A transmit has just completed. Process received data and /* A transmit has just completed. Process received data and
* check for more data to transmit. Always inhibit the * check for more data to transmit. Always inhibit the
* transmitter while the Isr refills the transmit register/FIFO, * transmitter while the Isr refills the transmit register/FIFO,
* or make sure it is stopped if we're done. * or make sure it is stopped if we're done.
*/ */
cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET); if (use_irq)
xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT, xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
xspi->regs + XSPI_CR_OFFSET); xspi->regs + XSPI_CR_OFFSET);
/* Read out all the data from the Rx FIFO */ /* Read out all the data from the Rx FIFO */
sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET); rx_words = n_words;
while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) { while (rx_words--)
xspi->rx_fn(xspi); xilinx_spi_rx(xspi);
sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
}
/* See if there is more data to send */ remaining_words -= n_words;
if (xspi->remaining_bytes <= 0)
break;
} }
/* Disable the transmit empty interrupt */ if (use_irq)
xspi->write_fn(ipif_ier, xspi->regs + XIPIF_V123B_IIER_OFFSET); xspi->write_fn(0, xspi->regs + XIPIF_V123B_DGIER_OFFSET);
return t->len - xspi->remaining_bytes; return t->len;
} }
@ -316,6 +330,28 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int xilinx_spi_find_buffer_size(struct xilinx_spi *xspi)
{
u8 sr;
int n_words = 0;
/*
* Before the buffer_size detection we reset the core
* to make sure we start with a clean state.
*/
xspi->write_fn(XIPIF_V123B_RESET_MASK,
xspi->regs + XIPIF_V123B_RESETR_OFFSET);
/* Fill the Tx FIFO with as many words as possible */
do {
xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET);
sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
n_words++;
} while (!(sr & XSPI_SR_TX_FULL_MASK));
return n_words;
}
static const struct of_device_id xilinx_spi_of_match[] = { static const struct of_device_id xilinx_spi_of_match[] = {
{ .compatible = "xlnx,xps-spi-2.00.a", }, { .compatible = "xlnx,xps-spi-2.00.a", },
{ .compatible = "xlnx,xps-spi-2.00.b", }, { .compatible = "xlnx,xps-spi-2.00.b", },
@ -348,14 +384,21 @@ static int xilinx_spi_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
} }
if (num_cs > XILINX_SPI_MAX_CS) {
dev_err(&pdev->dev, "Invalid number of spi slaves\n");
return -EINVAL;
}
master = spi_alloc_master(&pdev->dev, sizeof(struct xilinx_spi)); master = spi_alloc_master(&pdev->dev, sizeof(struct xilinx_spi));
if (!master) if (!master)
return -ENODEV; return -ENODEV;
/* the spi->mode bits understood by this driver: */ /* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP |
SPI_CS_HIGH;
xspi = spi_master_get_devdata(master); xspi = spi_master_get_devdata(master);
xspi->cs_inactive = 0xffffffff;
xspi->bitbang.master = master; xspi->bitbang.master = master;
xspi->bitbang.chipselect = xilinx_spi_chipselect; xspi->bitbang.chipselect = xilinx_spi_chipselect;
xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer; xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer;
@ -392,36 +435,21 @@ static int xilinx_spi_probe(struct platform_device *pdev)
} }
master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word); master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word);
xspi->bits_per_word = bits_per_word; xspi->bytes_per_word = bits_per_word / 8;
if (xspi->bits_per_word == 8) { xspi->buffer_size = xilinx_spi_find_buffer_size(xspi);
xspi->tx_fn = xspi_tx8;
xspi->rx_fn = xspi_rx8; xspi->irq = platform_get_irq(pdev, 0);
} else if (xspi->bits_per_word == 16) { if (xspi->irq >= 0) {
xspi->tx_fn = xspi_tx16; /* Register for SPI Interrupt */
xspi->rx_fn = xspi_rx16; ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0,
} else if (xspi->bits_per_word == 32) { dev_name(&pdev->dev), xspi);
xspi->tx_fn = xspi_tx32; if (ret)
xspi->rx_fn = xspi_rx32; goto put_master;
} else {
ret = -EINVAL;
goto put_master;
} }
/* SPI controller initializations */ /* SPI controller initializations */
xspi_init_hw(xspi); xspi_init_hw(xspi);
xspi->irq = platform_get_irq(pdev, 0);
if (xspi->irq < 0) {
ret = xspi->irq;
goto put_master;
}
/* Register for SPI Interrupt */
ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0,
dev_name(&pdev->dev), xspi);
if (ret)
goto put_master;
ret = spi_bitbang_start(&xspi->bitbang); ret = spi_bitbang_start(&xspi->bitbang);
if (ret) { if (ret) {
dev_err(&pdev->dev, "spi_bitbang_start FAILED\n"); dev_err(&pdev->dev, "spi_bitbang_start FAILED\n");