[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