[PATCH v2 1/3] spi: xilinx: Remove bitbang and register with spi core
Naga Sureshkumar Relli
naga.sureshkumar.relli at xilinx.com
Mon May 30 02:46:49 PDT 2016
This patch removes the bitbang layer registration.
it directly register with spi core using spi_register_master and uses
the call backs provided by spi_master struct.
Signed-off-by: Naga Sureshkumar Relli <nagasure at xilinx.com>
---
changes for v2
- check the return value of of_property_read_u32 for fifo-size
and return if property is not found, since it is mandatory
---
drivers/spi/spi-xilinx.c | 733 +++++++++++++++++++++++++++--------------------
1 file changed, 418 insertions(+), 315 deletions(-)
diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c
index 3009121..d903857 100644
--- a/drivers/spi/spi-xilinx.c
+++ b/drivers/spi/spi-xilinx.c
@@ -18,10 +18,9 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
-#include <linux/spi/spi_bitbang.h>
#include <linux/spi/xilinx_spi.h>
#include <linux/io.h>
-
+#include <linux/delay.h>
#define XILINX_SPI_MAX_CS 32
#define XILINX_SPI_NAME "xilinx_spi"
@@ -29,8 +28,18 @@
/* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e)
* Product Specification", DS464
*/
-#define XSPI_CR_OFFSET 0x60 /* Control Register */
-
+/* Register Offsets */
+#define XSPI_CR_OFFSET 0x60
+#define XSPI_SR_OFFSET 0x64
+#define XSPI_TXD_OFFSET 0x68
+#define XSPI_RXD_OFFSET 0x6c
+#define XSPI_SSR_OFFSET 0x70
+#define XIPIF_V123B_DGIER_OFFSET 0x1c
+#define XIPIF_V123B_IISR_OFFSET 0x20
+#define XIPIF_V123B_IIER_OFFSET 0x28
+#define XIPIF_V123B_RESETR_OFFSET 0x40
+
+/* Register bit masks */
#define XSPI_CR_LOOP 0x01
#define XSPI_CR_ENABLE 0x02
#define XSPI_CR_MASTER_MODE 0x04
@@ -43,133 +52,188 @@
#define XSPI_CR_MANUAL_SSELECT 0x80
#define XSPI_CR_TRANS_INHIBIT 0x100
#define XSPI_CR_LSB_FIRST 0x200
-
-#define XSPI_SR_OFFSET 0x64 /* Status Register */
-
-#define XSPI_SR_RX_EMPTY_MASK 0x01 /* Receive FIFO is empty */
-#define XSPI_SR_RX_FULL_MASK 0x02 /* Receive FIFO is full */
-#define XSPI_SR_TX_EMPTY_MASK 0x04 /* Transmit FIFO is empty */
-#define XSPI_SR_TX_FULL_MASK 0x08 /* Transmit FIFO is full */
-#define XSPI_SR_MODE_FAULT_MASK 0x10 /* Mode fault error */
-
-#define XSPI_TXD_OFFSET 0x68 /* Data Transmit Register */
-#define XSPI_RXD_OFFSET 0x6c /* Data Receive Register */
-
-#define XSPI_SSR_OFFSET 0x70 /* 32-bit Slave Select Register */
-
-/* Register definitions as per "OPB IPIF (v3.01c) Product Specification", DS414
- * IPIF registers are 32 bit
- */
-#define XIPIF_V123B_DGIER_OFFSET 0x1c /* IPIF global int enable reg */
+#define XSPI_SR_RX_EMPTY_MASK 0x01
+#define XSPI_SR_RX_FULL_MASK 0x02
+#define XSPI_SR_TX_EMPTY_MASK 0x04
+#define XSPI_SR_TX_FULL_MASK 0x08
+#define XSPI_SR_MODE_FAULT_MASK 0x10
#define XIPIF_V123B_GINTR_ENABLE 0x80000000
-
-#define XIPIF_V123B_IISR_OFFSET 0x20 /* IPIF interrupt status reg */
-#define XIPIF_V123B_IIER_OFFSET 0x28 /* IPIF interrupt enable reg */
-
-#define XSPI_INTR_MODE_FAULT 0x01 /* Mode fault error */
-#define XSPI_INTR_SLAVE_MODE_FAULT 0x02 /* Selected as slave while
- * disabled */
-#define XSPI_INTR_TX_EMPTY 0x04 /* TxFIFO is empty */
-#define XSPI_INTR_TX_UNDERRUN 0x08 /* TxFIFO was underrun */
-#define XSPI_INTR_RX_FULL 0x10 /* RxFIFO is full */
-#define XSPI_INTR_RX_OVERRUN 0x20 /* RxFIFO was overrun */
-#define XSPI_INTR_TX_HALF_EMPTY 0x40 /* TxFIFO is half empty */
-
-#define XIPIF_V123B_RESETR_OFFSET 0x40 /* IPIF reset register */
-#define XIPIF_V123B_RESET_MASK 0x0a /* the value to write */
-
+#define XSPI_INTR_MODE_FAULT 0x01
+#define XSPI_INTR_SLAVE_MODE_FAULT 0x02
+#define XSPI_INTR_TX_EMPTY 0x04
+#define XSPI_INTR_TX_UNDERRUN 0x08
+#define XSPI_INTR_RX_FULL 0x10
+#define XSPI_INTR_RX_OVERRUN 0x20
+#define XSPI_INTR_TX_HALF_EMPTY 0x40
+#define XIPIF_V123B_RESET_MASK 0x0a
+
+/* Number of bits per word */
+#define XSPI_ONE_BITS_PER_WORD 1
+#define XSPI_TWO_BITS_PER_WORD 2
+#define XSPI_FOUR_BITS_PER_WORD 4
+
+/* Number of data lines used to receive */
+#define XSPI_RX_ONE_WIRE 1
+
+/**
+ * struct xilinx_spi - This definition define spi driver instance
+ * @regs: virt. address of the control registers
+ * @irq: IRQ number
+ * @rx_ptr: Pointer to the RX buffer
+ * @tx_ptr: Pointer to the TX buffer
+ * @bytes_per_word: Number of bytes in a word
+ * @buffer_size: Buffer size in words
+ * @cs_inactive: Level of the CS pins when inactive
+ * @read_fn: For reading data from SPI registers
+ * @write_fn: For writing data to SPI registers
+ * @bytes_to_transfer: Number of bytes left to transfer
+ * @bytes_to_receive: Number of bytes left to receive
+ * @rx_bus_width: Number of wires used to receive data
+ * @tx_fifo: For writing data to fifo
+ * @rx_fifo: For reading data from fifo
+ */
struct xilinx_spi {
- /* bitbang has to be first */
- struct spi_bitbang bitbang;
- struct completion done;
- void __iomem *regs; /* virt. address of the control registers */
-
- int irq;
-
- u8 *rx_ptr; /* pointer in the Tx buffer */
- const u8 *tx_ptr; /* pointer in the Rx buffer */
+ void __iomem *regs;
+ int irq;
+ u8 *rx_ptr;
+ const u8 *tx_ptr;
u8 bytes_per_word;
- int buffer_size; /* buffer size in words */
- u32 cs_inactive; /* Level of the CS pins when inactive*/
+ int buffer_size;
+ u32 cs_inactive;
unsigned int (*read_fn)(void __iomem *);
void (*write_fn)(u32, void __iomem *);
+ u32 bytes_to_transfer;
+ u32 bytes_to_receive;
+ u32 rx_bus_width;
+ void (*tx_fifo)(struct xilinx_spi *xqspi);
+ void (*rx_fifo)(struct xilinx_spi *xqspi);
};
+/**
+ * XSPI_FIFO_READ - Generate xspi_read_rx_fifo_* functions
+ * @size: bits_per_word that are read from RX FIFO
+ * @type: C type of value argument
+ *
+ * Generates xspi_read_rx_fifo_* functions used to write
+ * data into RX FIFO for different transaction widths.
+ */
+#define XSPI_FIFO_READ(size, type) \
+static void xspi_read_rx_fifo_##size(struct xilinx_spi *xqspi) \
+{ \
+ int i; \
+ int count = (xqspi->bytes_to_receive > xqspi->buffer_size) ? \
+ xqspi->buffer_size : xqspi->bytes_to_receive; \
+ u32 data; \
+ for (i = 0; i < count; i += (size/8)) { \
+ data = readl_relaxed(xqspi->regs + XSPI_RXD_OFFSET); \
+ if (xqspi->rx_ptr) \
+ ((type *)xqspi->rx_ptr)[i] = (type)data; \
+ } \
+ xqspi->bytes_to_receive -= count; \
+ if (xqspi->rx_ptr) \
+ xqspi->rx_ptr += count; \
+}
+
+/**
+ * XSPI_FIFO_WRITE - Generate xspi_fill_tx_fifo_* functions
+ * @size: bits_per_word that are written into TX FIFO
+ * @type: C type of value argument
+ *
+ * Generates xspi_fill_tx_fifo_* functions used to write
+ * data into TX FIFO for different transaction widths.
+ */
+#define XSPI_FIFO_WRITE(size, type) \
+static void xspi_fill_tx_fifo_##size(struct xilinx_spi *xqspi) \
+{ \
+ int i; \
+ int count = (xqspi->bytes_to_transfer > xqspi->buffer_size) ? \
+ xqspi->buffer_size : xqspi->bytes_to_transfer; \
+ u32 data = 0; \
+ for (i = 0; i < count; i += (size/8)) { \
+ if (xqspi->tx_ptr) \
+ data = (type)((u8 *)xqspi->tx_ptr)[i]; \
+ writel_relaxed(data, (xqspi->regs + XSPI_TXD_OFFSET)); \
+ } \
+ xqspi->bytes_to_transfer -= count; \
+ if (xqspi->tx_ptr) \
+ xqspi->tx_ptr += count; \
+}
+
+XSPI_FIFO_READ(8, u8)
+XSPI_FIFO_READ(16, u16)
+XSPI_FIFO_READ(32, u32)
+XSPI_FIFO_WRITE(8, u8)
+XSPI_FIFO_WRITE(16, u16)
+XSPI_FIFO_WRITE(32, u32)
+
+/**
+ * xspi_write32 - Write a value to the device register little endian
+ * @val: Value to write at the Register offset
+ * @addr: Register offset
+ *
+ * Write data to the paricular SPI register
+ */
static void xspi_write32(u32 val, void __iomem *addr)
{
iowrite32(val, addr);
}
+/**
+ * xspi_read32 - read a value from the device register little endian
+ * @addr: Register offset
+ *
+ * Read data from the paricular SPI register
+ *
+ * Return: return value from the SPI register.
+ */
static unsigned int xspi_read32(void __iomem *addr)
{
return ioread32(addr);
}
+/**
+ * xspi_write32_be - Write a value to the device register big endian
+ * @val: Value to write at the Register offset
+ * @addr: Register offset
+ *
+ * Write data to the paricular SPI register
+ */
static void xspi_write32_be(u32 val, void __iomem *addr)
{
iowrite32be(val, addr);
}
+/**
+ * xspi_read32_be - read a value from the device register big endian
+ * @addr: Register offset
+ *
+ * Read data from the paricular SPI register
+ *
+ * Return: return value from the SPI register.
+ */
static unsigned int xspi_read32_be(void __iomem *addr)
{
return ioread32be(addr);
}
-static void xilinx_spi_tx(struct xilinx_spi *xspi)
-{
- u32 data = 0;
-
- if (!xspi->tx_ptr) {
- xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET);
- return;
- }
-
- switch (xspi->bytes_per_word) {
- case 1:
- data = *(u8 *)(xspi->tx_ptr);
- break;
- case 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 xilinx_spi_rx(struct xilinx_spi *xspi)
-{
- u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET);
-
- 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;
- break;
- }
-
- xspi->rx_ptr += xspi->bytes_per_word;
-}
-
+/**
+ * xspi_init_hw - Initialize the hardware
+ * @xspi: Pointer to the zynqmp_qspi structure
+ *
+ * This function performs the following actions
+ * - Disable and clear all the interrupts
+ * - Enable manual slave select
+ * - Enable the SPI controller
+ */
static void xspi_init_hw(struct xilinx_spi *xspi)
{
void __iomem *regs_base = xspi->regs;
/* Reset the SPI device */
xspi->write_fn(XIPIF_V123B_RESET_MASK,
- regs_base + XIPIF_V123B_RESETR_OFFSET);
- /* Enable the transmit empty interrupt, which we use to determine
+ regs_base + XIPIF_V123B_RESETR_OFFSET);
+ /*
+ * Enable the transmit empty interrupt, which we use to determine
* progress on the transmission.
*/
xspi->write_fn(XSPI_INTR_TX_EMPTY,
@@ -178,203 +242,223 @@ static void xspi_init_hw(struct xilinx_spi *xspi)
xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET);
/* Deselect the slave on the SPI bus */
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 */
xspi->write_fn(XSPI_CR_MANUAL_SSELECT | XSPI_CR_MASTER_MODE |
XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET | XSPI_CR_RXFIFO_RESET,
regs_base + XSPI_CR_OFFSET);
}
-static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
+/**
+ * xspi_chipselect - Select or deselect the chip select line
+ * @qspi: Pointer to the spi_device structure
+ * @is_high: Select(0) or deselect (1) the chip select line
+ *
+ */
+static void xspi_chipselect(struct spi_device *qspi, bool is_high)
{
- struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
- u16 cr;
+ struct xilinx_spi *xqspi = spi_master_get_devdata(qspi->master);
u32 cs;
- if (is_on == BITBANG_CS_INACTIVE) {
- /* Deselect the slave on the SPI bus */
- xspi->write_fn(xspi->cs_inactive, xspi->regs + XSPI_SSR_OFFSET);
- return;
+ if (is_high) {
+ /* Deselect the slave */
+ xqspi->write_fn(xqspi->cs_inactive,
+ xqspi->regs + XSPI_SSR_OFFSET);
+ } else {
+ cs = xqspi->cs_inactive;
+ cs ^= BIT(qspi->chip_select);
+ /* Activate the chip select */
+ xqspi->write_fn(cs, xqspi->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)
- */
+/**
+ * xilinx_spi_irq - Interrupt service routine of the SPI controller
+ * @irq: IRQ number
+ * @dev_id: Pointer to the xspi structure
+ *
+ * This function handles TX empty only.
+ * On TX empty interrupt this function reads the received data from RX FIFO
+ * and fills the TX FIFO if there is any data remaining to be transferred.
+ *
+ * Return: IRQ_HANDLED when interrupt is handled
+ * IRQ_NONE otherwise.
+ */
+static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
+{
+ struct spi_master *master = dev_id;
+ struct xilinx_spi *xspi = spi_master_get_devdata(dev_id);
+ u32 ipif_isr;
+ int status = IRQ_NONE;
- cs = xspi->cs_inactive;
- cs ^= BIT(spi->chip_select);
+ /* Get the IPIF interrupts, and clear them immediately */
+ ipif_isr = xspi->read_fn(xspi->regs + XIPIF_V123B_IISR_OFFSET);
+ xspi->write_fn(ipif_isr, xspi->regs + XIPIF_V123B_IISR_OFFSET);
+ if (ipif_isr & XSPI_INTR_TX_EMPTY) {
+ /* Transmission completed */
+ xspi->rx_fifo(xspi);
+ if (xspi->bytes_to_transfer) {
+ /* There is more data to send */
+ xspi->tx_fifo(xspi);
+ }
+ status = IRQ_HANDLED;
+ }
+
+ if (!xspi->bytes_to_receive && !xspi->bytes_to_transfer) {
+ spi_finalize_current_transfer(master);
+ /* Disable the interrupts here. */
+ xspi->write_fn(0x0, xspi->regs + XIPIF_V123B_DGIER_OFFSET);
+ }
- /* Activate the chip select */
- xspi->write_fn(cs, xspi->regs + XSPI_SSR_OFFSET);
+ return status;
}
-/* spi_bitbang requires custom setup_transfer() to be defined if there is a
- * custom txrx_bufs().
+/**
+ * xspi_setup_transfer - Configure SPI controller for specified
+ * transfer
+ * @qspi: Pointer to the spi_device structure
+ * @transfer: Pointer to the spi_transfer structure which provides
+ * information about next transfer setup parameters
+ *
+ * Sets the operational mode of QSPI controller for the next QSPI
+ * transfer.
+ *
+ * Return: 0 always
*/
-static int xilinx_spi_setup_transfer(struct spi_device *spi,
- struct spi_transfer *t)
+static int xspi_setup_transfer(struct spi_device *qspi,
+ struct spi_transfer *transfer)
{
- struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
-
- if (spi->mode & SPI_CS_HIGH)
- xspi->cs_inactive &= ~BIT(spi->chip_select);
+ struct xilinx_spi *xqspi = spi_master_get_devdata(qspi->master);
+ u32 config_reg;
+
+ config_reg = xqspi->read_fn(xqspi->regs + XSPI_CR_OFFSET);
+ /* Set the QSPI clock phase and clock polarity */
+ config_reg &= ~(XSPI_CR_CPHA | XSPI_CR_CPOL);
+ if (qspi->mode & SPI_CPHA)
+ config_reg |= XSPI_CR_CPHA;
+ if (qspi->mode & SPI_CPOL)
+ config_reg |= XSPI_CR_CPOL;
+ if (qspi->mode & SPI_LSB_FIRST)
+ config_reg |= XSPI_CR_LSB_FIRST;
+ xqspi->write_fn(config_reg, xqspi->regs + XSPI_CR_OFFSET);
+
+ if (qspi->mode & SPI_CS_HIGH)
+ xqspi->cs_inactive &= ~BIT(qspi->chip_select);
else
- xspi->cs_inactive |= BIT(spi->chip_select);
+ xqspi->cs_inactive |= BIT(qspi->chip_select);
return 0;
}
-static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
+/**
+ * xspi_setup - Configure the SPI controller
+ * @qspi: Pointer to the spi_device structure
+ *
+ * Sets the operational mode of QSPI controller for the next QSPI
+ * transfer.
+ *
+ * Return: 0 on success; error value otherwise.
+ */
+static int xspi_setup(struct spi_device *qspi)
{
- struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
- int remaining_words; /* the number of words left to transfer */
- bool use_irq = false;
- u16 cr = 0;
-
- /* We get here with transmitter inhibited */
-
- xspi->tx_ptr = t->tx_buf;
- xspi->rx_ptr = t->rx_buf;
- remaining_words = t->len / xspi->bytes_per_word;
-
- if (xspi->irq >= 0 && remaining_words > xspi->buffer_size) {
- u32 isr;
- use_irq = true;
- /* 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);
- /* ACK old irqs (if any) */
- isr = xspi->read_fn(xspi->regs + XIPIF_V123B_IISR_OFFSET);
- if (isr)
- xspi->write_fn(isr,
- xspi->regs + XIPIF_V123B_IISR_OFFSET);
- /* Enable the global IPIF interrupt */
- xspi->write_fn(XIPIF_V123B_GINTR_ENABLE,
- xspi->regs + XIPIF_V123B_DGIER_OFFSET);
- reinit_completion(&xspi->done);
- }
-
- while (remaining_words) {
- int n_words, tx_words, rx_words;
- u32 sr;
-
- n_words = min(remaining_words, xspi->buffer_size);
-
- tx_words = n_words;
- while (tx_words--)
- xilinx_spi_tx(xspi);
-
- /* Start the transfer by not inhibiting the transmitter any
- * longer
- */
-
- if (use_irq) {
- xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
- wait_for_completion(&xspi->done);
- /* A transmit has just completed. Process received data
- * and check for more data to transmit. Always inhibit
- * the transmitter while the Isr refills the transmit
- * register/FIFO, or make sure it is stopped if we're
- * done.
- */
- xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
- xspi->regs + XSPI_CR_OFFSET);
- sr = XSPI_SR_TX_EMPTY_MASK;
- } else
- sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
-
- /* Read out all the data from the Rx FIFO */
- rx_words = n_words;
- while (rx_words) {
- if ((sr & XSPI_SR_TX_EMPTY_MASK) && (rx_words > 1)) {
- xilinx_spi_rx(xspi);
- rx_words--;
- continue;
- }
-
- sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
- if (!(sr & XSPI_SR_RX_EMPTY_MASK)) {
- xilinx_spi_rx(xspi);
- rx_words--;
- }
- }
+ if (qspi->master->busy)
+ return -EBUSY;
- remaining_words -= n_words;
- }
+ return xspi_setup_transfer(qspi, NULL);
+}
- if (use_irq) {
- xspi->write_fn(0, xspi->regs + XIPIF_V123B_DGIER_OFFSET);
- xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
- }
+/**
+ * xspi_start_transfer - Initiates the SPI transfer
+ * @master: Pointer to the spi_master structure which provides
+ * information about the controller.
+ * @qspi: Pointer to the spi_device structure
+ * @transfer: Pointer to the spi_transfer structure which provide information
+ * about next transfer parameters
+ *
+ * This function fills the TX FIFO, starts the SPI transfer, and waits for the
+ * transfer to be completed.
+ *
+ * Return: Number of bytes transferred in the last transfer
+ */
- return t->len;
+static int xspi_start_transfer(struct spi_master *master,
+ struct spi_device *qspi,
+ struct spi_transfer *transfer)
+{
+ struct xilinx_spi *xqspi = spi_master_get_devdata(master);
+ u32 cr;
+
+ xqspi->tx_ptr = transfer->tx_buf;
+ xqspi->rx_ptr = transfer->rx_buf;
+ xqspi->bytes_to_transfer = transfer->len;
+ xqspi->bytes_to_receive = transfer->len;
+
+ xspi_setup_transfer(qspi, transfer);
+ cr = xqspi->read_fn(xqspi->regs + XSPI_CR_OFFSET);
+ /* Enable master transaction inhibit */
+ cr |= XSPI_CR_TRANS_INHIBIT;
+ xqspi->write_fn(cr, xqspi->regs + XSPI_CR_OFFSET);
+ xqspi->tx_fifo(xqspi);
+ /* Disable master transaction inhibit */
+ cr &= ~XSPI_CR_TRANS_INHIBIT;
+ xqspi->write_fn(cr, xqspi->regs + XSPI_CR_OFFSET);
+ xqspi->write_fn(XIPIF_V123B_GINTR_ENABLE,
+ xqspi->regs + XIPIF_V123B_DGIER_OFFSET);
+
+ return transfer->len;
}
-
-/* This driver supports single master mode only. Hence Tx FIFO Empty
- * is the only interrupt we care about.
- * Receive FIFO Overrun, Transmit FIFO Underrun, Mode Fault, and Slave Mode
- * Fault are not to happen.
+/**
+ * xspi_prepare_transfer_hardware - Prepares hardware for transfer.
+ * @master: Pointer to the spi_master structure which provides
+ * information about the controller.
+ *
+ * This function enables SPI master controller.
+ *
+ * Return: 0 on success; error value otherwise
*/
-static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
+static int xspi_prepare_transfer_hardware(struct spi_master *master)
{
- struct xilinx_spi *xspi = dev_id;
- u32 ipif_isr;
+ struct xilinx_spi *xqspi = spi_master_get_devdata(master);
+ u32 cr;
- /* Get the IPIF interrupts, and clear them immediately */
- ipif_isr = xspi->read_fn(xspi->regs + XIPIF_V123B_IISR_OFFSET);
- xspi->write_fn(ipif_isr, xspi->regs + XIPIF_V123B_IISR_OFFSET);
+ cr = xqspi->read_fn(xqspi->regs + XSPI_CR_OFFSET);
+ cr |= XSPI_CR_ENABLE;
+ xqspi->write_fn(cr, xqspi->regs + XSPI_CR_OFFSET);
- if (ipif_isr & XSPI_INTR_TX_EMPTY) { /* Transmission completed */
- complete(&xspi->done);
- }
-
- return IRQ_HANDLED;
+ return 0;
}
-static int xilinx_spi_find_buffer_size(struct xilinx_spi *xspi)
+/**
+ * xspi_unprepare_transfer_hardware - Relaxes hardware after transfer
+ * @master: Pointer to the spi_master structure which provides
+ * information about the controller.
+ *
+ * This function disables the SPI master controller.
+ *
+ * Return: Always 0
+ */
+static int xspi_unprepare_transfer_hardware(struct spi_master *master)
{
- u8 sr;
- int n_words = 0;
+ struct xilinx_spi *xqspi = spi_master_get_devdata(master);
+ u32 cr;
- /*
- * 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);
+ cr = xqspi->read_fn(xqspi->regs + XSPI_CR_OFFSET);
+ cr &= ~XSPI_CR_ENABLE;
+ xqspi->write_fn(cr, xqspi->regs + XSPI_CR_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;
+ return 0;
}
-static const struct of_device_id xilinx_spi_of_match[] = {
- { .compatible = "xlnx,xps-spi-2.00.a", },
- { .compatible = "xlnx,xps-spi-2.00.b", },
- {}
-};
-MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
-
+/**
+ * xilinx_spi_probe - Probe method for the SPI driver
+ * @pdev: Pointer to the platform_device structure
+ *
+ * This function initializes the driver data structures and the hardware.
+ *
+ * Return: 0 on success; error value otherwise
+ */
static int xilinx_spi_probe(struct platform_device *pdev)
{
struct xilinx_spi *xspi;
@@ -382,23 +466,14 @@ static int xilinx_spi_probe(struct platform_device *pdev)
struct resource *res;
int ret, num_cs = 0, bits_per_word = 8;
struct spi_master *master;
- u32 tmp;
- u8 i;
+ struct device_node *nc;
+ u32 tmp, rx_bus_width, fifo_size;
pdata = dev_get_platdata(&pdev->dev);
- if (pdata) {
- num_cs = pdata->num_chipselect;
- bits_per_word = pdata->bits_per_word;
- } else {
- of_property_read_u32(pdev->dev.of_node, "xlnx,num-ss-bits",
- &num_cs);
- }
-
- if (!num_cs) {
- dev_err(&pdev->dev,
- "Missing slave select configuration data\n");
- return -EINVAL;
- }
+ of_property_read_u32(pdev->dev.of_node, "num-cs",
+ &num_cs);
+ if (!num_cs)
+ num_cs = 1;
if (num_cs > XILINX_SPI_MAX_CS) {
dev_err(&pdev->dev, "Invalid number of spi slaves\n");
@@ -409,18 +484,9 @@ static int xilinx_spi_probe(struct platform_device *pdev)
if (!master)
return -ENODEV;
- /* the spi->mode bits understood by this driver: */
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP |
- SPI_CS_HIGH;
-
xspi = spi_master_get_devdata(master);
- xspi->cs_inactive = 0xffffffff;
- xspi->bitbang.master = master;
- xspi->bitbang.chipselect = xilinx_spi_chipselect;
- xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer;
- xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs;
- init_completion(&xspi->done);
-
+ master->dev.of_node = pdev->dev.of_node;
+ platform_set_drvdata(pdev, master);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
xspi->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(xspi->regs)) {
@@ -428,20 +494,28 @@ static int xilinx_spi_probe(struct platform_device *pdev)
goto put_master;
}
- master->bus_num = pdev->id;
- master->num_chipselect = num_cs;
- master->dev.of_node = pdev->dev.of_node;
-
- /*
- * Detect endianess on the IP via loop bit in CR. Detection
- * must be done before reset is sent because incorrect reset
- * value generates error interrupt.
- * Setup little endian helper functions first and try to use them
- * and check if bit was correctly setup or not.
- */
+ ret = of_property_read_u32(pdev->dev.of_node, "fifo-size",
+ &fifo_size);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "Missing fifo size\n");
+ return -EINVAL;
+ }
+ of_property_read_u32(pdev->dev.of_node, "bits-per-word",
+ &bits_per_word);
+
+ xspi->rx_bus_width = XSPI_ONE_BITS_PER_WORD;
+ for_each_available_child_of_node(pdev->dev.of_node, nc) {
+ ret = of_property_read_u32(nc, "spi-rx-bus-width",
+ &rx_bus_width);
+ if (!ret) {
+ xspi->rx_bus_width = rx_bus_width;
+ break;
+ }
+ }
xspi->read_fn = xspi_read32;
xspi->write_fn = xspi_write32;
-
+ /* Detect endianness on the IP via loop bit in CR register*/
xspi->write_fn(XSPI_CR_LOOP, xspi->regs + XSPI_CR_OFFSET);
tmp = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
tmp &= XSPI_CR_LOOP;
@@ -450,15 +524,12 @@ static int xilinx_spi_probe(struct platform_device *pdev)
xspi->write_fn = xspi_write32_be;
}
- master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word);
- xspi->bytes_per_word = bits_per_word / 8;
- xspi->buffer_size = xilinx_spi_find_buffer_size(xspi);
-
+ xspi->buffer_size = fifo_size;
xspi->irq = platform_get_irq(pdev, 0);
if (xspi->irq >= 0) {
/* Register for SPI Interrupt */
- ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0,
- dev_name(&pdev->dev), xspi);
+ ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq,
+ 0, dev_name(&pdev->dev), master);
if (ret)
goto put_master;
}
@@ -466,22 +537,39 @@ static int xilinx_spi_probe(struct platform_device *pdev)
/* SPI controller initializations */
xspi_init_hw(xspi);
- ret = spi_bitbang_start(&xspi->bitbang);
- if (ret) {
- dev_err(&pdev->dev, "spi_bitbang_start FAILED\n");
+ master->bus_num = pdev->id;
+ master->num_chipselect = num_cs;
+ master->setup = xspi_setup;
+ master->set_cs = xspi_chipselect;
+ master->transfer_one = xspi_start_transfer;
+ master->prepare_transfer_hardware = xspi_prepare_transfer_hardware;
+ master->unprepare_transfer_hardware = xspi_unprepare_transfer_hardware;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+
+ xspi->bytes_per_word = bits_per_word / 8;
+ xspi->tx_fifo = xspi_fill_tx_fifo_8;
+ xspi->rx_fifo = xspi_read_rx_fifo_8;
+ if (xspi->rx_bus_width == XSPI_RX_ONE_WIRE) {
+ if (xspi->bytes_per_word == XSPI_TWO_BITS_PER_WORD) {
+ xspi->tx_fifo = xspi_fill_tx_fifo_16;
+ xspi->rx_fifo = xspi_read_rx_fifo_16;
+ } else if (xspi->bytes_per_word == XSPI_FOUR_BITS_PER_WORD) {
+ xspi->tx_fifo = xspi_fill_tx_fifo_32;
+ xspi->rx_fifo = xspi_read_rx_fifo_32;
+ }
+ } else {
+ dev_err(&pdev->dev, "Dual/Quad Modes are not supported\n");
goto put_master;
}
-
- dev_info(&pdev->dev, "at 0x%08llX mapped to 0x%p, irq=%d\n",
- (unsigned long long)res->start, xspi->regs, xspi->irq);
-
- if (pdata) {
- for (i = 0; i < pdata->num_devices; i++)
- spi_new_device(master, pdata->devices + i);
+ xspi->cs_inactive = 0xffffffff;
+ ret = spi_register_master(master);
+ if (ret) {
+ dev_err(&pdev->dev, "spi_register_master failed\n");
+ goto put_master;
}
- platform_set_drvdata(pdev, master);
- return 0;
+ return ret;
put_master:
spi_master_put(master);
@@ -489,20 +577,28 @@ put_master:
return ret;
}
+/**
+ * xilinx_spi_remove - Remove method for the SPI driver
+ * @pdev: Pointer to the platform_device structure
+ *
+ * This function is called if a device is physically removed from the system or
+ * if the driver module is being unloaded. It frees all resources allocated to
+ * the device.
+ *
+ * Return: 0 Always
+ */
static int xilinx_spi_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct xilinx_spi *xspi = spi_master_get_devdata(master);
void __iomem *regs_base = xspi->regs;
- spi_bitbang_stop(&xspi->bitbang);
-
/* Disable all the interrupts just in case */
xspi->write_fn(0, regs_base + XIPIF_V123B_IIER_OFFSET);
/* Disable the global IPIF interrupt */
xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET);
- spi_master_put(xspi->bitbang.master);
+ spi_unregister_master(master);
return 0;
}
@@ -510,6 +606,13 @@ static int xilinx_spi_remove(struct platform_device *pdev)
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:" XILINX_SPI_NAME);
+static const struct of_device_id xilinx_spi_of_match[] = {
+ { .compatible = "xlnx,xps-spi-2.00.a", },
+ { .compatible = "xlnx,xps-spi-2.00.b", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
+
static struct platform_driver xilinx_spi_driver = {
.probe = xilinx_spi_probe,
.remove = xilinx_spi_remove,
--
2.1.1
More information about the linux-arm-kernel
mailing list