18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Xilinx SPI controller driver (master mode only)
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author: MontaVista Software, Inc.
68c2ecf20Sopenharmony_ci *	source@mvista.com
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Copyright (c) 2010 Secret Lab Technologies, Ltd.
98c2ecf20Sopenharmony_ci * Copyright (c) 2009 Intel Corporation
108c2ecf20Sopenharmony_ci * 2002-2007 (c) MontaVista Software, Inc.
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
168c2ecf20Sopenharmony_ci#include <linux/of.h>
178c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
188c2ecf20Sopenharmony_ci#include <linux/spi/spi.h>
198c2ecf20Sopenharmony_ci#include <linux/spi/spi_bitbang.h>
208c2ecf20Sopenharmony_ci#include <linux/spi/xilinx_spi.h>
218c2ecf20Sopenharmony_ci#include <linux/io.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define XILINX_SPI_MAX_CS	32
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define XILINX_SPI_NAME "xilinx_spi"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e)
288c2ecf20Sopenharmony_ci * Product Specification", DS464
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_ci#define XSPI_CR_OFFSET		0x60	/* Control Register */
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define XSPI_CR_LOOP		0x01
338c2ecf20Sopenharmony_ci#define XSPI_CR_ENABLE		0x02
348c2ecf20Sopenharmony_ci#define XSPI_CR_MASTER_MODE	0x04
358c2ecf20Sopenharmony_ci#define XSPI_CR_CPOL		0x08
368c2ecf20Sopenharmony_ci#define XSPI_CR_CPHA		0x10
378c2ecf20Sopenharmony_ci#define XSPI_CR_MODE_MASK	(XSPI_CR_CPHA | XSPI_CR_CPOL | \
388c2ecf20Sopenharmony_ci				 XSPI_CR_LSB_FIRST | XSPI_CR_LOOP)
398c2ecf20Sopenharmony_ci#define XSPI_CR_TXFIFO_RESET	0x20
408c2ecf20Sopenharmony_ci#define XSPI_CR_RXFIFO_RESET	0x40
418c2ecf20Sopenharmony_ci#define XSPI_CR_MANUAL_SSELECT	0x80
428c2ecf20Sopenharmony_ci#define XSPI_CR_TRANS_INHIBIT	0x100
438c2ecf20Sopenharmony_ci#define XSPI_CR_LSB_FIRST	0x200
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#define XSPI_SR_OFFSET		0x64	/* Status Register */
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define XSPI_SR_RX_EMPTY_MASK	0x01	/* Receive FIFO is empty */
488c2ecf20Sopenharmony_ci#define XSPI_SR_RX_FULL_MASK	0x02	/* Receive FIFO is full */
498c2ecf20Sopenharmony_ci#define XSPI_SR_TX_EMPTY_MASK	0x04	/* Transmit FIFO is empty */
508c2ecf20Sopenharmony_ci#define XSPI_SR_TX_FULL_MASK	0x08	/* Transmit FIFO is full */
518c2ecf20Sopenharmony_ci#define XSPI_SR_MODE_FAULT_MASK	0x10	/* Mode fault error */
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define XSPI_TXD_OFFSET		0x68	/* Data Transmit Register */
548c2ecf20Sopenharmony_ci#define XSPI_RXD_OFFSET		0x6c	/* Data Receive Register */
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#define XSPI_SSR_OFFSET		0x70	/* 32-bit Slave Select Register */
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/* Register definitions as per "OPB IPIF (v3.01c) Product Specification", DS414
598c2ecf20Sopenharmony_ci * IPIF registers are 32 bit
608c2ecf20Sopenharmony_ci */
618c2ecf20Sopenharmony_ci#define XIPIF_V123B_DGIER_OFFSET	0x1c	/* IPIF global int enable reg */
628c2ecf20Sopenharmony_ci#define XIPIF_V123B_GINTR_ENABLE	0x80000000
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci#define XIPIF_V123B_IISR_OFFSET		0x20	/* IPIF interrupt status reg */
658c2ecf20Sopenharmony_ci#define XIPIF_V123B_IIER_OFFSET		0x28	/* IPIF interrupt enable reg */
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#define XSPI_INTR_MODE_FAULT		0x01	/* Mode fault error */
688c2ecf20Sopenharmony_ci#define XSPI_INTR_SLAVE_MODE_FAULT	0x02	/* Selected as slave while
698c2ecf20Sopenharmony_ci						 * disabled */
708c2ecf20Sopenharmony_ci#define XSPI_INTR_TX_EMPTY		0x04	/* TxFIFO is empty */
718c2ecf20Sopenharmony_ci#define XSPI_INTR_TX_UNDERRUN		0x08	/* TxFIFO was underrun */
728c2ecf20Sopenharmony_ci#define XSPI_INTR_RX_FULL		0x10	/* RxFIFO is full */
738c2ecf20Sopenharmony_ci#define XSPI_INTR_RX_OVERRUN		0x20	/* RxFIFO was overrun */
748c2ecf20Sopenharmony_ci#define XSPI_INTR_TX_HALF_EMPTY		0x40	/* TxFIFO is half empty */
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci#define XIPIF_V123B_RESETR_OFFSET	0x40	/* IPIF reset register */
778c2ecf20Sopenharmony_ci#define XIPIF_V123B_RESET_MASK		0x0a	/* the value to write */
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistruct xilinx_spi {
808c2ecf20Sopenharmony_ci	/* bitbang has to be first */
818c2ecf20Sopenharmony_ci	struct spi_bitbang bitbang;
828c2ecf20Sopenharmony_ci	struct completion done;
838c2ecf20Sopenharmony_ci	void __iomem	*regs;	/* virt. address of the control registers */
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	int		irq;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	u8 *rx_ptr;		/* pointer in the Tx buffer */
888c2ecf20Sopenharmony_ci	const u8 *tx_ptr;	/* pointer in the Rx buffer */
898c2ecf20Sopenharmony_ci	u8 bytes_per_word;
908c2ecf20Sopenharmony_ci	int buffer_size;	/* buffer size in words */
918c2ecf20Sopenharmony_ci	u32 cs_inactive;	/* Level of the CS pins when inactive*/
928c2ecf20Sopenharmony_ci	unsigned int (*read_fn)(void __iomem *);
938c2ecf20Sopenharmony_ci	void (*write_fn)(u32, void __iomem *);
948c2ecf20Sopenharmony_ci};
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic void xspi_write32(u32 val, void __iomem *addr)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	iowrite32(val, addr);
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic unsigned int xspi_read32(void __iomem *addr)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	return ioread32(addr);
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic void xspi_write32_be(u32 val, void __iomem *addr)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	iowrite32be(val, addr);
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic unsigned int xspi_read32_be(void __iomem *addr)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	return ioread32be(addr);
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic void xilinx_spi_tx(struct xilinx_spi *xspi)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	u32 data = 0;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	if (!xspi->tx_ptr) {
1218c2ecf20Sopenharmony_ci		xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET);
1228c2ecf20Sopenharmony_ci		return;
1238c2ecf20Sopenharmony_ci	}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	switch (xspi->bytes_per_word) {
1268c2ecf20Sopenharmony_ci	case 1:
1278c2ecf20Sopenharmony_ci		data = *(u8 *)(xspi->tx_ptr);
1288c2ecf20Sopenharmony_ci		break;
1298c2ecf20Sopenharmony_ci	case 2:
1308c2ecf20Sopenharmony_ci		data = *(u16 *)(xspi->tx_ptr);
1318c2ecf20Sopenharmony_ci		break;
1328c2ecf20Sopenharmony_ci	case 4:
1338c2ecf20Sopenharmony_ci		data = *(u32 *)(xspi->tx_ptr);
1348c2ecf20Sopenharmony_ci		break;
1358c2ecf20Sopenharmony_ci	}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	xspi->write_fn(data, xspi->regs + XSPI_TXD_OFFSET);
1388c2ecf20Sopenharmony_ci	xspi->tx_ptr += xspi->bytes_per_word;
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic void xilinx_spi_rx(struct xilinx_spi *xspi)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	if (!xspi->rx_ptr)
1468c2ecf20Sopenharmony_ci		return;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	switch (xspi->bytes_per_word) {
1498c2ecf20Sopenharmony_ci	case 1:
1508c2ecf20Sopenharmony_ci		*(u8 *)(xspi->rx_ptr) = data;
1518c2ecf20Sopenharmony_ci		break;
1528c2ecf20Sopenharmony_ci	case 2:
1538c2ecf20Sopenharmony_ci		*(u16 *)(xspi->rx_ptr) = data;
1548c2ecf20Sopenharmony_ci		break;
1558c2ecf20Sopenharmony_ci	case 4:
1568c2ecf20Sopenharmony_ci		*(u32 *)(xspi->rx_ptr) = data;
1578c2ecf20Sopenharmony_ci		break;
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	xspi->rx_ptr += xspi->bytes_per_word;
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic void xspi_init_hw(struct xilinx_spi *xspi)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	void __iomem *regs_base = xspi->regs;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	/* Reset the SPI device */
1688c2ecf20Sopenharmony_ci	xspi->write_fn(XIPIF_V123B_RESET_MASK,
1698c2ecf20Sopenharmony_ci		regs_base + XIPIF_V123B_RESETR_OFFSET);
1708c2ecf20Sopenharmony_ci	/* Enable the transmit empty interrupt, which we use to determine
1718c2ecf20Sopenharmony_ci	 * progress on the transmission.
1728c2ecf20Sopenharmony_ci	 */
1738c2ecf20Sopenharmony_ci	xspi->write_fn(XSPI_INTR_TX_EMPTY,
1748c2ecf20Sopenharmony_ci			regs_base + XIPIF_V123B_IIER_OFFSET);
1758c2ecf20Sopenharmony_ci	/* Disable the global IPIF interrupt */
1768c2ecf20Sopenharmony_ci	xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET);
1778c2ecf20Sopenharmony_ci	/* Deselect the slave on the SPI bus */
1788c2ecf20Sopenharmony_ci	xspi->write_fn(0xffff, regs_base + XSPI_SSR_OFFSET);
1798c2ecf20Sopenharmony_ci	/* Disable the transmitter, enable Manual Slave Select Assertion,
1808c2ecf20Sopenharmony_ci	 * put SPI controller into master mode, and enable it */
1818c2ecf20Sopenharmony_ci	xspi->write_fn(XSPI_CR_MANUAL_SSELECT |	XSPI_CR_MASTER_MODE |
1828c2ecf20Sopenharmony_ci		XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET |	XSPI_CR_RXFIFO_RESET,
1838c2ecf20Sopenharmony_ci		regs_base + XSPI_CR_OFFSET);
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistatic void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
1898c2ecf20Sopenharmony_ci	u16 cr;
1908c2ecf20Sopenharmony_ci	u32 cs;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	if (is_on == BITBANG_CS_INACTIVE) {
1938c2ecf20Sopenharmony_ci		/* Deselect the slave on the SPI bus */
1948c2ecf20Sopenharmony_ci		xspi->write_fn(xspi->cs_inactive, xspi->regs + XSPI_SSR_OFFSET);
1958c2ecf20Sopenharmony_ci		return;
1968c2ecf20Sopenharmony_ci	}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	/* Set the SPI clock phase and polarity */
1998c2ecf20Sopenharmony_ci	cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET)	& ~XSPI_CR_MODE_MASK;
2008c2ecf20Sopenharmony_ci	if (spi->mode & SPI_CPHA)
2018c2ecf20Sopenharmony_ci		cr |= XSPI_CR_CPHA;
2028c2ecf20Sopenharmony_ci	if (spi->mode & SPI_CPOL)
2038c2ecf20Sopenharmony_ci		cr |= XSPI_CR_CPOL;
2048c2ecf20Sopenharmony_ci	if (spi->mode & SPI_LSB_FIRST)
2058c2ecf20Sopenharmony_ci		cr |= XSPI_CR_LSB_FIRST;
2068c2ecf20Sopenharmony_ci	if (spi->mode & SPI_LOOP)
2078c2ecf20Sopenharmony_ci		cr |= XSPI_CR_LOOP;
2088c2ecf20Sopenharmony_ci	xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	/* We do not check spi->max_speed_hz here as the SPI clock
2118c2ecf20Sopenharmony_ci	 * frequency is not software programmable (the IP block design
2128c2ecf20Sopenharmony_ci	 * parameter)
2138c2ecf20Sopenharmony_ci	 */
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	cs = xspi->cs_inactive;
2168c2ecf20Sopenharmony_ci	cs ^= BIT(spi->chip_select);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	/* Activate the chip select */
2198c2ecf20Sopenharmony_ci	xspi->write_fn(cs, xspi->regs + XSPI_SSR_OFFSET);
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci/* spi_bitbang requires custom setup_transfer() to be defined if there is a
2238c2ecf20Sopenharmony_ci * custom txrx_bufs().
2248c2ecf20Sopenharmony_ci */
2258c2ecf20Sopenharmony_cistatic int xilinx_spi_setup_transfer(struct spi_device *spi,
2268c2ecf20Sopenharmony_ci		struct spi_transfer *t)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	if (spi->mode & SPI_CS_HIGH)
2318c2ecf20Sopenharmony_ci		xspi->cs_inactive &= ~BIT(spi->chip_select);
2328c2ecf20Sopenharmony_ci	else
2338c2ecf20Sopenharmony_ci		xspi->cs_inactive |= BIT(spi->chip_select);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	return 0;
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
2418c2ecf20Sopenharmony_ci	int remaining_words;	/* the number of words left to transfer */
2428c2ecf20Sopenharmony_ci	bool use_irq = false;
2438c2ecf20Sopenharmony_ci	u16 cr = 0;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	/* We get here with transmitter inhibited */
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	xspi->tx_ptr = t->tx_buf;
2488c2ecf20Sopenharmony_ci	xspi->rx_ptr = t->rx_buf;
2498c2ecf20Sopenharmony_ci	remaining_words = t->len / xspi->bytes_per_word;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	if (xspi->irq >= 0 &&  remaining_words > xspi->buffer_size) {
2528c2ecf20Sopenharmony_ci		u32 isr;
2538c2ecf20Sopenharmony_ci		use_irq = true;
2548c2ecf20Sopenharmony_ci		/* Inhibit irq to avoid spurious irqs on tx_empty*/
2558c2ecf20Sopenharmony_ci		cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
2568c2ecf20Sopenharmony_ci		xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
2578c2ecf20Sopenharmony_ci			       xspi->regs + XSPI_CR_OFFSET);
2588c2ecf20Sopenharmony_ci		/* ACK old irqs (if any) */
2598c2ecf20Sopenharmony_ci		isr = xspi->read_fn(xspi->regs + XIPIF_V123B_IISR_OFFSET);
2608c2ecf20Sopenharmony_ci		if (isr)
2618c2ecf20Sopenharmony_ci			xspi->write_fn(isr,
2628c2ecf20Sopenharmony_ci				       xspi->regs + XIPIF_V123B_IISR_OFFSET);
2638c2ecf20Sopenharmony_ci		/* Enable the global IPIF interrupt */
2648c2ecf20Sopenharmony_ci		xspi->write_fn(XIPIF_V123B_GINTR_ENABLE,
2658c2ecf20Sopenharmony_ci				xspi->regs + XIPIF_V123B_DGIER_OFFSET);
2668c2ecf20Sopenharmony_ci		reinit_completion(&xspi->done);
2678c2ecf20Sopenharmony_ci	}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	while (remaining_words) {
2708c2ecf20Sopenharmony_ci		int n_words, tx_words, rx_words;
2718c2ecf20Sopenharmony_ci		u32 sr;
2728c2ecf20Sopenharmony_ci		int stalled;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci		n_words = min(remaining_words, xspi->buffer_size);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci		tx_words = n_words;
2778c2ecf20Sopenharmony_ci		while (tx_words--)
2788c2ecf20Sopenharmony_ci			xilinx_spi_tx(xspi);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci		/* Start the transfer by not inhibiting the transmitter any
2818c2ecf20Sopenharmony_ci		 * longer
2828c2ecf20Sopenharmony_ci		 */
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci		if (use_irq) {
2858c2ecf20Sopenharmony_ci			xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
2868c2ecf20Sopenharmony_ci			wait_for_completion(&xspi->done);
2878c2ecf20Sopenharmony_ci			/* A transmit has just completed. Process received data
2888c2ecf20Sopenharmony_ci			 * and check for more data to transmit. Always inhibit
2898c2ecf20Sopenharmony_ci			 * the transmitter while the Isr refills the transmit
2908c2ecf20Sopenharmony_ci			 * register/FIFO, or make sure it is stopped if we're
2918c2ecf20Sopenharmony_ci			 * done.
2928c2ecf20Sopenharmony_ci			 */
2938c2ecf20Sopenharmony_ci			xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
2948c2ecf20Sopenharmony_ci				       xspi->regs + XSPI_CR_OFFSET);
2958c2ecf20Sopenharmony_ci			sr = XSPI_SR_TX_EMPTY_MASK;
2968c2ecf20Sopenharmony_ci		} else
2978c2ecf20Sopenharmony_ci			sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci		/* Read out all the data from the Rx FIFO */
3008c2ecf20Sopenharmony_ci		rx_words = n_words;
3018c2ecf20Sopenharmony_ci		stalled = 10;
3028c2ecf20Sopenharmony_ci		while (rx_words) {
3038c2ecf20Sopenharmony_ci			if (rx_words == n_words && !(stalled--) &&
3048c2ecf20Sopenharmony_ci			    !(sr & XSPI_SR_TX_EMPTY_MASK) &&
3058c2ecf20Sopenharmony_ci			    (sr & XSPI_SR_RX_EMPTY_MASK)) {
3068c2ecf20Sopenharmony_ci				dev_err(&spi->dev,
3078c2ecf20Sopenharmony_ci					"Detected stall. Check C_SPI_MODE and C_SPI_MEMORY\n");
3088c2ecf20Sopenharmony_ci				xspi_init_hw(xspi);
3098c2ecf20Sopenharmony_ci				return -EIO;
3108c2ecf20Sopenharmony_ci			}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci			if ((sr & XSPI_SR_TX_EMPTY_MASK) && (rx_words > 1)) {
3138c2ecf20Sopenharmony_ci				xilinx_spi_rx(xspi);
3148c2ecf20Sopenharmony_ci				rx_words--;
3158c2ecf20Sopenharmony_ci				continue;
3168c2ecf20Sopenharmony_ci			}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci			sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
3198c2ecf20Sopenharmony_ci			if (!(sr & XSPI_SR_RX_EMPTY_MASK)) {
3208c2ecf20Sopenharmony_ci				xilinx_spi_rx(xspi);
3218c2ecf20Sopenharmony_ci				rx_words--;
3228c2ecf20Sopenharmony_ci			}
3238c2ecf20Sopenharmony_ci		}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci		remaining_words -= n_words;
3268c2ecf20Sopenharmony_ci	}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	if (use_irq) {
3298c2ecf20Sopenharmony_ci		xspi->write_fn(0, xspi->regs + XIPIF_V123B_DGIER_OFFSET);
3308c2ecf20Sopenharmony_ci		xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
3318c2ecf20Sopenharmony_ci	}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	return t->len;
3348c2ecf20Sopenharmony_ci}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci/* This driver supports single master mode only. Hence Tx FIFO Empty
3388c2ecf20Sopenharmony_ci * is the only interrupt we care about.
3398c2ecf20Sopenharmony_ci * Receive FIFO Overrun, Transmit FIFO Underrun, Mode Fault, and Slave Mode
3408c2ecf20Sopenharmony_ci * Fault are not to happen.
3418c2ecf20Sopenharmony_ci */
3428c2ecf20Sopenharmony_cistatic irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	struct xilinx_spi *xspi = dev_id;
3458c2ecf20Sopenharmony_ci	u32 ipif_isr;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	/* Get the IPIF interrupts, and clear them immediately */
3488c2ecf20Sopenharmony_ci	ipif_isr = xspi->read_fn(xspi->regs + XIPIF_V123B_IISR_OFFSET);
3498c2ecf20Sopenharmony_ci	xspi->write_fn(ipif_isr, xspi->regs + XIPIF_V123B_IISR_OFFSET);
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	if (ipif_isr & XSPI_INTR_TX_EMPTY) {	/* Transmission completed */
3528c2ecf20Sopenharmony_ci		complete(&xspi->done);
3538c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	return IRQ_NONE;
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic int xilinx_spi_find_buffer_size(struct xilinx_spi *xspi)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	u8 sr;
3628c2ecf20Sopenharmony_ci	int n_words = 0;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	/*
3658c2ecf20Sopenharmony_ci	 * Before the buffer_size detection we reset the core
3668c2ecf20Sopenharmony_ci	 * to make sure we start with a clean state.
3678c2ecf20Sopenharmony_ci	 */
3688c2ecf20Sopenharmony_ci	xspi->write_fn(XIPIF_V123B_RESET_MASK,
3698c2ecf20Sopenharmony_ci		xspi->regs + XIPIF_V123B_RESETR_OFFSET);
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	/* Fill the Tx FIFO with as many words as possible */
3728c2ecf20Sopenharmony_ci	do {
3738c2ecf20Sopenharmony_ci		xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET);
3748c2ecf20Sopenharmony_ci		sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
3758c2ecf20Sopenharmony_ci		n_words++;
3768c2ecf20Sopenharmony_ci	} while (!(sr & XSPI_SR_TX_FULL_MASK));
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	return n_words;
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_cistatic const struct of_device_id xilinx_spi_of_match[] = {
3828c2ecf20Sopenharmony_ci	{ .compatible = "xlnx,axi-quad-spi-1.00.a", },
3838c2ecf20Sopenharmony_ci	{ .compatible = "xlnx,xps-spi-2.00.a", },
3848c2ecf20Sopenharmony_ci	{ .compatible = "xlnx,xps-spi-2.00.b", },
3858c2ecf20Sopenharmony_ci	{}
3868c2ecf20Sopenharmony_ci};
3878c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_cistatic int xilinx_spi_probe(struct platform_device *pdev)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	struct xilinx_spi *xspi;
3928c2ecf20Sopenharmony_ci	struct xspi_platform_data *pdata;
3938c2ecf20Sopenharmony_ci	struct resource *res;
3948c2ecf20Sopenharmony_ci	int ret, num_cs = 0, bits_per_word;
3958c2ecf20Sopenharmony_ci	struct spi_master *master;
3968c2ecf20Sopenharmony_ci	u32 tmp;
3978c2ecf20Sopenharmony_ci	u8 i;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	pdata = dev_get_platdata(&pdev->dev);
4008c2ecf20Sopenharmony_ci	if (pdata) {
4018c2ecf20Sopenharmony_ci		num_cs = pdata->num_chipselect;
4028c2ecf20Sopenharmony_ci		bits_per_word = pdata->bits_per_word;
4038c2ecf20Sopenharmony_ci	} else {
4048c2ecf20Sopenharmony_ci		of_property_read_u32(pdev->dev.of_node, "xlnx,num-ss-bits",
4058c2ecf20Sopenharmony_ci					  &num_cs);
4068c2ecf20Sopenharmony_ci		ret = of_property_read_u32(pdev->dev.of_node,
4078c2ecf20Sopenharmony_ci					   "xlnx,num-transfer-bits",
4088c2ecf20Sopenharmony_ci					   &bits_per_word);
4098c2ecf20Sopenharmony_ci		if (ret)
4108c2ecf20Sopenharmony_ci			bits_per_word = 8;
4118c2ecf20Sopenharmony_ci	}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	if (!num_cs) {
4148c2ecf20Sopenharmony_ci		dev_err(&pdev->dev,
4158c2ecf20Sopenharmony_ci			"Missing slave select configuration data\n");
4168c2ecf20Sopenharmony_ci		return -EINVAL;
4178c2ecf20Sopenharmony_ci	}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	if (num_cs > XILINX_SPI_MAX_CS) {
4208c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Invalid number of spi slaves\n");
4218c2ecf20Sopenharmony_ci		return -EINVAL;
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	master = spi_alloc_master(&pdev->dev, sizeof(struct xilinx_spi));
4258c2ecf20Sopenharmony_ci	if (!master)
4268c2ecf20Sopenharmony_ci		return -ENODEV;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	/* the spi->mode bits understood by this driver: */
4298c2ecf20Sopenharmony_ci	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP |
4308c2ecf20Sopenharmony_ci			    SPI_CS_HIGH;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	xspi = spi_master_get_devdata(master);
4338c2ecf20Sopenharmony_ci	xspi->cs_inactive = 0xffffffff;
4348c2ecf20Sopenharmony_ci	xspi->bitbang.master = master;
4358c2ecf20Sopenharmony_ci	xspi->bitbang.chipselect = xilinx_spi_chipselect;
4368c2ecf20Sopenharmony_ci	xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer;
4378c2ecf20Sopenharmony_ci	xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs;
4388c2ecf20Sopenharmony_ci	init_completion(&xspi->done);
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4418c2ecf20Sopenharmony_ci	xspi->regs = devm_ioremap_resource(&pdev->dev, res);
4428c2ecf20Sopenharmony_ci	if (IS_ERR(xspi->regs)) {
4438c2ecf20Sopenharmony_ci		ret = PTR_ERR(xspi->regs);
4448c2ecf20Sopenharmony_ci		goto put_master;
4458c2ecf20Sopenharmony_ci	}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	master->bus_num = pdev->id;
4488c2ecf20Sopenharmony_ci	master->num_chipselect = num_cs;
4498c2ecf20Sopenharmony_ci	master->dev.of_node = pdev->dev.of_node;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	/*
4528c2ecf20Sopenharmony_ci	 * Detect endianess on the IP via loop bit in CR. Detection
4538c2ecf20Sopenharmony_ci	 * must be done before reset is sent because incorrect reset
4548c2ecf20Sopenharmony_ci	 * value generates error interrupt.
4558c2ecf20Sopenharmony_ci	 * Setup little endian helper functions first and try to use them
4568c2ecf20Sopenharmony_ci	 * and check if bit was correctly setup or not.
4578c2ecf20Sopenharmony_ci	 */
4588c2ecf20Sopenharmony_ci	xspi->read_fn = xspi_read32;
4598c2ecf20Sopenharmony_ci	xspi->write_fn = xspi_write32;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	xspi->write_fn(XSPI_CR_LOOP, xspi->regs + XSPI_CR_OFFSET);
4628c2ecf20Sopenharmony_ci	tmp = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
4638c2ecf20Sopenharmony_ci	tmp &= XSPI_CR_LOOP;
4648c2ecf20Sopenharmony_ci	if (tmp != XSPI_CR_LOOP) {
4658c2ecf20Sopenharmony_ci		xspi->read_fn = xspi_read32_be;
4668c2ecf20Sopenharmony_ci		xspi->write_fn = xspi_write32_be;
4678c2ecf20Sopenharmony_ci	}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word);
4708c2ecf20Sopenharmony_ci	xspi->bytes_per_word = bits_per_word / 8;
4718c2ecf20Sopenharmony_ci	xspi->buffer_size = xilinx_spi_find_buffer_size(xspi);
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	xspi->irq = platform_get_irq(pdev, 0);
4748c2ecf20Sopenharmony_ci	if (xspi->irq < 0 && xspi->irq != -ENXIO) {
4758c2ecf20Sopenharmony_ci		ret = xspi->irq;
4768c2ecf20Sopenharmony_ci		goto put_master;
4778c2ecf20Sopenharmony_ci	} else if (xspi->irq >= 0) {
4788c2ecf20Sopenharmony_ci		/* Register for SPI Interrupt */
4798c2ecf20Sopenharmony_ci		ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0,
4808c2ecf20Sopenharmony_ci				dev_name(&pdev->dev), xspi);
4818c2ecf20Sopenharmony_ci		if (ret)
4828c2ecf20Sopenharmony_ci			goto put_master;
4838c2ecf20Sopenharmony_ci	}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	/* SPI controller initializations */
4868c2ecf20Sopenharmony_ci	xspi_init_hw(xspi);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	ret = spi_bitbang_start(&xspi->bitbang);
4898c2ecf20Sopenharmony_ci	if (ret) {
4908c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "spi_bitbang_start FAILED\n");
4918c2ecf20Sopenharmony_ci		goto put_master;
4928c2ecf20Sopenharmony_ci	}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	dev_info(&pdev->dev, "at %pR, irq=%d\n", res, xspi->irq);
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	if (pdata) {
4978c2ecf20Sopenharmony_ci		for (i = 0; i < pdata->num_devices; i++)
4988c2ecf20Sopenharmony_ci			spi_new_device(master, pdata->devices + i);
4998c2ecf20Sopenharmony_ci	}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, master);
5028c2ecf20Sopenharmony_ci	return 0;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ciput_master:
5058c2ecf20Sopenharmony_ci	spi_master_put(master);
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	return ret;
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_cistatic int xilinx_spi_remove(struct platform_device *pdev)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	struct spi_master *master = platform_get_drvdata(pdev);
5138c2ecf20Sopenharmony_ci	struct xilinx_spi *xspi = spi_master_get_devdata(master);
5148c2ecf20Sopenharmony_ci	void __iomem *regs_base = xspi->regs;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	spi_bitbang_stop(&xspi->bitbang);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	/* Disable all the interrupts just in case */
5198c2ecf20Sopenharmony_ci	xspi->write_fn(0, regs_base + XIPIF_V123B_IIER_OFFSET);
5208c2ecf20Sopenharmony_ci	/* Disable the global IPIF interrupt */
5218c2ecf20Sopenharmony_ci	xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	spi_master_put(xspi->bitbang.master);
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	return 0;
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci/* work with hotplug and coldplug */
5298c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:" XILINX_SPI_NAME);
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_cistatic struct platform_driver xilinx_spi_driver = {
5328c2ecf20Sopenharmony_ci	.probe = xilinx_spi_probe,
5338c2ecf20Sopenharmony_ci	.remove = xilinx_spi_remove,
5348c2ecf20Sopenharmony_ci	.driver = {
5358c2ecf20Sopenharmony_ci		.name = XILINX_SPI_NAME,
5368c2ecf20Sopenharmony_ci		.of_match_table = xilinx_spi_of_match,
5378c2ecf20Sopenharmony_ci	},
5388c2ecf20Sopenharmony_ci};
5398c2ecf20Sopenharmony_cimodule_platform_driver(xilinx_spi_driver);
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ciMODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
5428c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Xilinx SPI driver");
5438c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
544