18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// Copyright 2018 SiFive, Inc.
48c2ecf20Sopenharmony_ci//
58c2ecf20Sopenharmony_ci// SiFive SPI controller driver (master mode only)
68c2ecf20Sopenharmony_ci//
78c2ecf20Sopenharmony_ci// Author: SiFive, Inc.
88c2ecf20Sopenharmony_ci// sifive@sifive.com
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/clk.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
138c2ecf20Sopenharmony_ci#include <linux/of.h>
148c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
158c2ecf20Sopenharmony_ci#include <linux/spi/spi.h>
168c2ecf20Sopenharmony_ci#include <linux/io.h>
178c2ecf20Sopenharmony_ci#include <linux/log2.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define SIFIVE_SPI_DRIVER_NAME           "sifive_spi"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define SIFIVE_SPI_MAX_CS                32
228c2ecf20Sopenharmony_ci#define SIFIVE_SPI_DEFAULT_DEPTH         8
238c2ecf20Sopenharmony_ci#define SIFIVE_SPI_DEFAULT_MAX_BITS      8
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/* register offsets */
268c2ecf20Sopenharmony_ci#define SIFIVE_SPI_REG_SCKDIV            0x00 /* Serial clock divisor */
278c2ecf20Sopenharmony_ci#define SIFIVE_SPI_REG_SCKMODE           0x04 /* Serial clock mode */
288c2ecf20Sopenharmony_ci#define SIFIVE_SPI_REG_CSID              0x10 /* Chip select ID */
298c2ecf20Sopenharmony_ci#define SIFIVE_SPI_REG_CSDEF             0x14 /* Chip select default */
308c2ecf20Sopenharmony_ci#define SIFIVE_SPI_REG_CSMODE            0x18 /* Chip select mode */
318c2ecf20Sopenharmony_ci#define SIFIVE_SPI_REG_DELAY0            0x28 /* Delay control 0 */
328c2ecf20Sopenharmony_ci#define SIFIVE_SPI_REG_DELAY1            0x2c /* Delay control 1 */
338c2ecf20Sopenharmony_ci#define SIFIVE_SPI_REG_FMT               0x40 /* Frame format */
348c2ecf20Sopenharmony_ci#define SIFIVE_SPI_REG_TXDATA            0x48 /* Tx FIFO data */
358c2ecf20Sopenharmony_ci#define SIFIVE_SPI_REG_RXDATA            0x4c /* Rx FIFO data */
368c2ecf20Sopenharmony_ci#define SIFIVE_SPI_REG_TXMARK            0x50 /* Tx FIFO watermark */
378c2ecf20Sopenharmony_ci#define SIFIVE_SPI_REG_RXMARK            0x54 /* Rx FIFO watermark */
388c2ecf20Sopenharmony_ci#define SIFIVE_SPI_REG_FCTRL             0x60 /* SPI flash interface control */
398c2ecf20Sopenharmony_ci#define SIFIVE_SPI_REG_FFMT              0x64 /* SPI flash instruction format */
408c2ecf20Sopenharmony_ci#define SIFIVE_SPI_REG_IE                0x70 /* Interrupt Enable Register */
418c2ecf20Sopenharmony_ci#define SIFIVE_SPI_REG_IP                0x74 /* Interrupt Pendings Register */
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci/* sckdiv bits */
448c2ecf20Sopenharmony_ci#define SIFIVE_SPI_SCKDIV_DIV_MASK       0xfffU
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci/* sckmode bits */
478c2ecf20Sopenharmony_ci#define SIFIVE_SPI_SCKMODE_PHA           BIT(0)
488c2ecf20Sopenharmony_ci#define SIFIVE_SPI_SCKMODE_POL           BIT(1)
498c2ecf20Sopenharmony_ci#define SIFIVE_SPI_SCKMODE_MODE_MASK     (SIFIVE_SPI_SCKMODE_PHA | \
508c2ecf20Sopenharmony_ci					  SIFIVE_SPI_SCKMODE_POL)
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/* csmode bits */
538c2ecf20Sopenharmony_ci#define SIFIVE_SPI_CSMODE_MODE_AUTO      0U
548c2ecf20Sopenharmony_ci#define SIFIVE_SPI_CSMODE_MODE_HOLD      2U
558c2ecf20Sopenharmony_ci#define SIFIVE_SPI_CSMODE_MODE_OFF       3U
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci/* delay0 bits */
588c2ecf20Sopenharmony_ci#define SIFIVE_SPI_DELAY0_CSSCK(x)       ((u32)(x))
598c2ecf20Sopenharmony_ci#define SIFIVE_SPI_DELAY0_CSSCK_MASK     0xffU
608c2ecf20Sopenharmony_ci#define SIFIVE_SPI_DELAY0_SCKCS(x)       ((u32)(x) << 16)
618c2ecf20Sopenharmony_ci#define SIFIVE_SPI_DELAY0_SCKCS_MASK     (0xffU << 16)
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/* delay1 bits */
648c2ecf20Sopenharmony_ci#define SIFIVE_SPI_DELAY1_INTERCS(x)     ((u32)(x))
658c2ecf20Sopenharmony_ci#define SIFIVE_SPI_DELAY1_INTERCS_MASK   0xffU
668c2ecf20Sopenharmony_ci#define SIFIVE_SPI_DELAY1_INTERXFR(x)    ((u32)(x) << 16)
678c2ecf20Sopenharmony_ci#define SIFIVE_SPI_DELAY1_INTERXFR_MASK  (0xffU << 16)
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci/* fmt bits */
708c2ecf20Sopenharmony_ci#define SIFIVE_SPI_FMT_PROTO_SINGLE      0U
718c2ecf20Sopenharmony_ci#define SIFIVE_SPI_FMT_PROTO_DUAL        1U
728c2ecf20Sopenharmony_ci#define SIFIVE_SPI_FMT_PROTO_QUAD        2U
738c2ecf20Sopenharmony_ci#define SIFIVE_SPI_FMT_PROTO_MASK        3U
748c2ecf20Sopenharmony_ci#define SIFIVE_SPI_FMT_ENDIAN            BIT(2)
758c2ecf20Sopenharmony_ci#define SIFIVE_SPI_FMT_DIR               BIT(3)
768c2ecf20Sopenharmony_ci#define SIFIVE_SPI_FMT_LEN(x)            ((u32)(x) << 16)
778c2ecf20Sopenharmony_ci#define SIFIVE_SPI_FMT_LEN_MASK          (0xfU << 16)
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci/* txdata bits */
808c2ecf20Sopenharmony_ci#define SIFIVE_SPI_TXDATA_DATA_MASK      0xffU
818c2ecf20Sopenharmony_ci#define SIFIVE_SPI_TXDATA_FULL           BIT(31)
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci/* rxdata bits */
848c2ecf20Sopenharmony_ci#define SIFIVE_SPI_RXDATA_DATA_MASK      0xffU
858c2ecf20Sopenharmony_ci#define SIFIVE_SPI_RXDATA_EMPTY          BIT(31)
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci/* ie and ip bits */
888c2ecf20Sopenharmony_ci#define SIFIVE_SPI_IP_TXWM               BIT(0)
898c2ecf20Sopenharmony_ci#define SIFIVE_SPI_IP_RXWM               BIT(1)
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistruct sifive_spi {
928c2ecf20Sopenharmony_ci	void __iomem      *regs;        /* virt. address of control registers */
938c2ecf20Sopenharmony_ci	struct clk        *clk;         /* bus clock */
948c2ecf20Sopenharmony_ci	unsigned int      fifo_depth;   /* fifo depth in words */
958c2ecf20Sopenharmony_ci	u32               cs_inactive;  /* level of the CS pins when inactive */
968c2ecf20Sopenharmony_ci	struct completion done;         /* wake-up from interrupt */
978c2ecf20Sopenharmony_ci};
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic void sifive_spi_write(struct sifive_spi *spi, int offset, u32 value)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	iowrite32(value, spi->regs + offset);
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic u32 sifive_spi_read(struct sifive_spi *spi, int offset)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	return ioread32(spi->regs + offset);
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic void sifive_spi_init(struct sifive_spi *spi)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	/* Watermark interrupts are disabled by default */
1128c2ecf20Sopenharmony_ci	sifive_spi_write(spi, SIFIVE_SPI_REG_IE, 0);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	/* Default watermark FIFO threshold values */
1158c2ecf20Sopenharmony_ci	sifive_spi_write(spi, SIFIVE_SPI_REG_TXMARK, 1);
1168c2ecf20Sopenharmony_ci	sifive_spi_write(spi, SIFIVE_SPI_REG_RXMARK, 0);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	/* Set CS/SCK Delays and Inactive Time to defaults */
1198c2ecf20Sopenharmony_ci	sifive_spi_write(spi, SIFIVE_SPI_REG_DELAY0,
1208c2ecf20Sopenharmony_ci			 SIFIVE_SPI_DELAY0_CSSCK(1) |
1218c2ecf20Sopenharmony_ci			 SIFIVE_SPI_DELAY0_SCKCS(1));
1228c2ecf20Sopenharmony_ci	sifive_spi_write(spi, SIFIVE_SPI_REG_DELAY1,
1238c2ecf20Sopenharmony_ci			 SIFIVE_SPI_DELAY1_INTERCS(1) |
1248c2ecf20Sopenharmony_ci			 SIFIVE_SPI_DELAY1_INTERXFR(0));
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	/* Exit specialized memory-mapped SPI flash mode */
1278c2ecf20Sopenharmony_ci	sifive_spi_write(spi, SIFIVE_SPI_REG_FCTRL, 0);
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic int
1318c2ecf20Sopenharmony_cisifive_spi_prepare_message(struct spi_master *master, struct spi_message *msg)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	struct sifive_spi *spi = spi_master_get_devdata(master);
1348c2ecf20Sopenharmony_ci	struct spi_device *device = msg->spi;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	/* Update the chip select polarity */
1378c2ecf20Sopenharmony_ci	if (device->mode & SPI_CS_HIGH)
1388c2ecf20Sopenharmony_ci		spi->cs_inactive &= ~BIT(device->chip_select);
1398c2ecf20Sopenharmony_ci	else
1408c2ecf20Sopenharmony_ci		spi->cs_inactive |= BIT(device->chip_select);
1418c2ecf20Sopenharmony_ci	sifive_spi_write(spi, SIFIVE_SPI_REG_CSDEF, spi->cs_inactive);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	/* Select the correct device */
1448c2ecf20Sopenharmony_ci	sifive_spi_write(spi, SIFIVE_SPI_REG_CSID, device->chip_select);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	/* Set clock mode */
1478c2ecf20Sopenharmony_ci	sifive_spi_write(spi, SIFIVE_SPI_REG_SCKMODE,
1488c2ecf20Sopenharmony_ci			 device->mode & SIFIVE_SPI_SCKMODE_MODE_MASK);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return 0;
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic void sifive_spi_set_cs(struct spi_device *device, bool is_high)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	struct sifive_spi *spi = spi_master_get_devdata(device->master);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	/* Reverse polarity is handled by SCMR/CPOL. Not inverted CS. */
1588c2ecf20Sopenharmony_ci	if (device->mode & SPI_CS_HIGH)
1598c2ecf20Sopenharmony_ci		is_high = !is_high;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	sifive_spi_write(spi, SIFIVE_SPI_REG_CSMODE, is_high ?
1628c2ecf20Sopenharmony_ci			 SIFIVE_SPI_CSMODE_MODE_AUTO :
1638c2ecf20Sopenharmony_ci			 SIFIVE_SPI_CSMODE_MODE_HOLD);
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic int
1678c2ecf20Sopenharmony_cisifive_spi_prep_transfer(struct sifive_spi *spi, struct spi_device *device,
1688c2ecf20Sopenharmony_ci			 struct spi_transfer *t)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	u32 cr;
1718c2ecf20Sopenharmony_ci	unsigned int mode;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	/* Calculate and program the clock rate */
1748c2ecf20Sopenharmony_ci	cr = DIV_ROUND_UP(clk_get_rate(spi->clk) >> 1, t->speed_hz) - 1;
1758c2ecf20Sopenharmony_ci	cr &= SIFIVE_SPI_SCKDIV_DIV_MASK;
1768c2ecf20Sopenharmony_ci	sifive_spi_write(spi, SIFIVE_SPI_REG_SCKDIV, cr);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	mode = max_t(unsigned int, t->rx_nbits, t->tx_nbits);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	/* Set frame format */
1818c2ecf20Sopenharmony_ci	cr = SIFIVE_SPI_FMT_LEN(t->bits_per_word);
1828c2ecf20Sopenharmony_ci	switch (mode) {
1838c2ecf20Sopenharmony_ci	case SPI_NBITS_QUAD:
1848c2ecf20Sopenharmony_ci		cr |= SIFIVE_SPI_FMT_PROTO_QUAD;
1858c2ecf20Sopenharmony_ci		break;
1868c2ecf20Sopenharmony_ci	case SPI_NBITS_DUAL:
1878c2ecf20Sopenharmony_ci		cr |= SIFIVE_SPI_FMT_PROTO_DUAL;
1888c2ecf20Sopenharmony_ci		break;
1898c2ecf20Sopenharmony_ci	default:
1908c2ecf20Sopenharmony_ci		cr |= SIFIVE_SPI_FMT_PROTO_SINGLE;
1918c2ecf20Sopenharmony_ci		break;
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci	if (device->mode & SPI_LSB_FIRST)
1948c2ecf20Sopenharmony_ci		cr |= SIFIVE_SPI_FMT_ENDIAN;
1958c2ecf20Sopenharmony_ci	if (!t->rx_buf)
1968c2ecf20Sopenharmony_ci		cr |= SIFIVE_SPI_FMT_DIR;
1978c2ecf20Sopenharmony_ci	sifive_spi_write(spi, SIFIVE_SPI_REG_FMT, cr);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	/* We will want to poll if the time we need to wait is
2008c2ecf20Sopenharmony_ci	 * less than the context switching time.
2018c2ecf20Sopenharmony_ci	 * Let's call that threshold 5us. The operation will take:
2028c2ecf20Sopenharmony_ci	 *    (8/mode) * fifo_depth / hz <= 5 * 10^-6
2038c2ecf20Sopenharmony_ci	 *    1600000 * fifo_depth <= hz * mode
2048c2ecf20Sopenharmony_ci	 */
2058c2ecf20Sopenharmony_ci	return 1600000 * spi->fifo_depth <= t->speed_hz * mode;
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic irqreturn_t sifive_spi_irq(int irq, void *dev_id)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	struct sifive_spi *spi = dev_id;
2118c2ecf20Sopenharmony_ci	u32 ip = sifive_spi_read(spi, SIFIVE_SPI_REG_IP);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	if (ip & (SIFIVE_SPI_IP_TXWM | SIFIVE_SPI_IP_RXWM)) {
2148c2ecf20Sopenharmony_ci		/* Disable interrupts until next transfer */
2158c2ecf20Sopenharmony_ci		sifive_spi_write(spi, SIFIVE_SPI_REG_IE, 0);
2168c2ecf20Sopenharmony_ci		complete(&spi->done);
2178c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	return IRQ_NONE;
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic void sifive_spi_wait(struct sifive_spi *spi, u32 bit, int poll)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	if (poll) {
2268c2ecf20Sopenharmony_ci		u32 cr;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci		do {
2298c2ecf20Sopenharmony_ci			cr = sifive_spi_read(spi, SIFIVE_SPI_REG_IP);
2308c2ecf20Sopenharmony_ci		} while (!(cr & bit));
2318c2ecf20Sopenharmony_ci	} else {
2328c2ecf20Sopenharmony_ci		reinit_completion(&spi->done);
2338c2ecf20Sopenharmony_ci		sifive_spi_write(spi, SIFIVE_SPI_REG_IE, bit);
2348c2ecf20Sopenharmony_ci		wait_for_completion(&spi->done);
2358c2ecf20Sopenharmony_ci	}
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic void sifive_spi_tx(struct sifive_spi *spi, const u8 *tx_ptr)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	WARN_ON_ONCE((sifive_spi_read(spi, SIFIVE_SPI_REG_TXDATA)
2418c2ecf20Sopenharmony_ci				& SIFIVE_SPI_TXDATA_FULL) != 0);
2428c2ecf20Sopenharmony_ci	sifive_spi_write(spi, SIFIVE_SPI_REG_TXDATA,
2438c2ecf20Sopenharmony_ci			 *tx_ptr & SIFIVE_SPI_TXDATA_DATA_MASK);
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic void sifive_spi_rx(struct sifive_spi *spi, u8 *rx_ptr)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	u32 data = sifive_spi_read(spi, SIFIVE_SPI_REG_RXDATA);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	WARN_ON_ONCE((data & SIFIVE_SPI_RXDATA_EMPTY) != 0);
2518c2ecf20Sopenharmony_ci	*rx_ptr = data & SIFIVE_SPI_RXDATA_DATA_MASK;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic int
2558c2ecf20Sopenharmony_cisifive_spi_transfer_one(struct spi_master *master, struct spi_device *device,
2568c2ecf20Sopenharmony_ci			struct spi_transfer *t)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	struct sifive_spi *spi = spi_master_get_devdata(master);
2598c2ecf20Sopenharmony_ci	int poll = sifive_spi_prep_transfer(spi, device, t);
2608c2ecf20Sopenharmony_ci	const u8 *tx_ptr = t->tx_buf;
2618c2ecf20Sopenharmony_ci	u8 *rx_ptr = t->rx_buf;
2628c2ecf20Sopenharmony_ci	unsigned int remaining_words = t->len;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	while (remaining_words) {
2658c2ecf20Sopenharmony_ci		unsigned int n_words = min(remaining_words, spi->fifo_depth);
2668c2ecf20Sopenharmony_ci		unsigned int i;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci		/* Enqueue n_words for transmission */
2698c2ecf20Sopenharmony_ci		for (i = 0; i < n_words; i++)
2708c2ecf20Sopenharmony_ci			sifive_spi_tx(spi, tx_ptr++);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci		if (rx_ptr) {
2738c2ecf20Sopenharmony_ci			/* Wait for transmission + reception to complete */
2748c2ecf20Sopenharmony_ci			sifive_spi_write(spi, SIFIVE_SPI_REG_RXMARK,
2758c2ecf20Sopenharmony_ci					 n_words - 1);
2768c2ecf20Sopenharmony_ci			sifive_spi_wait(spi, SIFIVE_SPI_IP_RXWM, poll);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci			/* Read out all the data from the RX FIFO */
2798c2ecf20Sopenharmony_ci			for (i = 0; i < n_words; i++)
2808c2ecf20Sopenharmony_ci				sifive_spi_rx(spi, rx_ptr++);
2818c2ecf20Sopenharmony_ci		} else {
2828c2ecf20Sopenharmony_ci			/* Wait for transmission to complete */
2838c2ecf20Sopenharmony_ci			sifive_spi_wait(spi, SIFIVE_SPI_IP_TXWM, poll);
2848c2ecf20Sopenharmony_ci		}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci		remaining_words -= n_words;
2878c2ecf20Sopenharmony_ci	}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	return 0;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic int sifive_spi_probe(struct platform_device *pdev)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	struct sifive_spi *spi;
2958c2ecf20Sopenharmony_ci	int ret, irq, num_cs;
2968c2ecf20Sopenharmony_ci	u32 cs_bits, max_bits_per_word;
2978c2ecf20Sopenharmony_ci	struct spi_master *master;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	master = spi_alloc_master(&pdev->dev, sizeof(struct sifive_spi));
3008c2ecf20Sopenharmony_ci	if (!master) {
3018c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "out of memory\n");
3028c2ecf20Sopenharmony_ci		return -ENOMEM;
3038c2ecf20Sopenharmony_ci	}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	spi = spi_master_get_devdata(master);
3068c2ecf20Sopenharmony_ci	init_completion(&spi->done);
3078c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, master);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	spi->regs = devm_platform_ioremap_resource(pdev, 0);
3108c2ecf20Sopenharmony_ci	if (IS_ERR(spi->regs)) {
3118c2ecf20Sopenharmony_ci		ret = PTR_ERR(spi->regs);
3128c2ecf20Sopenharmony_ci		goto put_master;
3138c2ecf20Sopenharmony_ci	}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	spi->clk = devm_clk_get(&pdev->dev, NULL);
3168c2ecf20Sopenharmony_ci	if (IS_ERR(spi->clk)) {
3178c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Unable to find bus clock\n");
3188c2ecf20Sopenharmony_ci		ret = PTR_ERR(spi->clk);
3198c2ecf20Sopenharmony_ci		goto put_master;
3208c2ecf20Sopenharmony_ci	}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
3238c2ecf20Sopenharmony_ci	if (irq < 0) {
3248c2ecf20Sopenharmony_ci		ret = irq;
3258c2ecf20Sopenharmony_ci		goto put_master;
3268c2ecf20Sopenharmony_ci	}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	/* Optional parameters */
3298c2ecf20Sopenharmony_ci	ret =
3308c2ecf20Sopenharmony_ci	  of_property_read_u32(pdev->dev.of_node, "sifive,fifo-depth",
3318c2ecf20Sopenharmony_ci			       &spi->fifo_depth);
3328c2ecf20Sopenharmony_ci	if (ret < 0)
3338c2ecf20Sopenharmony_ci		spi->fifo_depth = SIFIVE_SPI_DEFAULT_DEPTH;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	ret =
3368c2ecf20Sopenharmony_ci	  of_property_read_u32(pdev->dev.of_node, "sifive,max-bits-per-word",
3378c2ecf20Sopenharmony_ci			       &max_bits_per_word);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (!ret && max_bits_per_word < 8) {
3408c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Only 8bit SPI words supported by the driver\n");
3418c2ecf20Sopenharmony_ci		ret = -EINVAL;
3428c2ecf20Sopenharmony_ci		goto put_master;
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	/* Spin up the bus clock before hitting registers */
3468c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(spi->clk);
3478c2ecf20Sopenharmony_ci	if (ret) {
3488c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Unable to enable bus clock\n");
3498c2ecf20Sopenharmony_ci		goto put_master;
3508c2ecf20Sopenharmony_ci	}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	/* probe the number of CS lines */
3538c2ecf20Sopenharmony_ci	spi->cs_inactive = sifive_spi_read(spi, SIFIVE_SPI_REG_CSDEF);
3548c2ecf20Sopenharmony_ci	sifive_spi_write(spi, SIFIVE_SPI_REG_CSDEF, 0xffffffffU);
3558c2ecf20Sopenharmony_ci	cs_bits = sifive_spi_read(spi, SIFIVE_SPI_REG_CSDEF);
3568c2ecf20Sopenharmony_ci	sifive_spi_write(spi, SIFIVE_SPI_REG_CSDEF, spi->cs_inactive);
3578c2ecf20Sopenharmony_ci	if (!cs_bits) {
3588c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Could not auto probe CS lines\n");
3598c2ecf20Sopenharmony_ci		ret = -EINVAL;
3608c2ecf20Sopenharmony_ci		goto disable_clk;
3618c2ecf20Sopenharmony_ci	}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	num_cs = ilog2(cs_bits) + 1;
3648c2ecf20Sopenharmony_ci	if (num_cs > SIFIVE_SPI_MAX_CS) {
3658c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Invalid number of spi slaves\n");
3668c2ecf20Sopenharmony_ci		ret = -EINVAL;
3678c2ecf20Sopenharmony_ci		goto disable_clk;
3688c2ecf20Sopenharmony_ci	}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	/* Define our master */
3718c2ecf20Sopenharmony_ci	master->dev.of_node = pdev->dev.of_node;
3728c2ecf20Sopenharmony_ci	master->bus_num = pdev->id;
3738c2ecf20Sopenharmony_ci	master->num_chipselect = num_cs;
3748c2ecf20Sopenharmony_ci	master->mode_bits = SPI_CPHA | SPI_CPOL
3758c2ecf20Sopenharmony_ci			  | SPI_CS_HIGH | SPI_LSB_FIRST
3768c2ecf20Sopenharmony_ci			  | SPI_TX_DUAL | SPI_TX_QUAD
3778c2ecf20Sopenharmony_ci			  | SPI_RX_DUAL | SPI_RX_QUAD;
3788c2ecf20Sopenharmony_ci	/* TODO: add driver support for bits_per_word < 8
3798c2ecf20Sopenharmony_ci	 * we need to "left-align" the bits (unless SPI_LSB_FIRST)
3808c2ecf20Sopenharmony_ci	 */
3818c2ecf20Sopenharmony_ci	master->bits_per_word_mask = SPI_BPW_MASK(8);
3828c2ecf20Sopenharmony_ci	master->flags = SPI_CONTROLLER_MUST_TX | SPI_MASTER_GPIO_SS;
3838c2ecf20Sopenharmony_ci	master->prepare_message = sifive_spi_prepare_message;
3848c2ecf20Sopenharmony_ci	master->set_cs = sifive_spi_set_cs;
3858c2ecf20Sopenharmony_ci	master->transfer_one = sifive_spi_transfer_one;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	pdev->dev.dma_mask = NULL;
3888c2ecf20Sopenharmony_ci	/* Configure the SPI master hardware */
3898c2ecf20Sopenharmony_ci	sifive_spi_init(spi);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	/* Register for SPI Interrupt */
3928c2ecf20Sopenharmony_ci	ret = devm_request_irq(&pdev->dev, irq, sifive_spi_irq, 0,
3938c2ecf20Sopenharmony_ci			       dev_name(&pdev->dev), spi);
3948c2ecf20Sopenharmony_ci	if (ret) {
3958c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Unable to bind to interrupt\n");
3968c2ecf20Sopenharmony_ci		goto disable_clk;
3978c2ecf20Sopenharmony_ci	}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	dev_info(&pdev->dev, "mapped; irq=%d, cs=%d\n",
4008c2ecf20Sopenharmony_ci		 irq, master->num_chipselect);
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	ret = devm_spi_register_master(&pdev->dev, master);
4038c2ecf20Sopenharmony_ci	if (ret < 0) {
4048c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "spi_register_master failed\n");
4058c2ecf20Sopenharmony_ci		goto disable_clk;
4068c2ecf20Sopenharmony_ci	}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	return 0;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_cidisable_clk:
4118c2ecf20Sopenharmony_ci	clk_disable_unprepare(spi->clk);
4128c2ecf20Sopenharmony_ciput_master:
4138c2ecf20Sopenharmony_ci	spi_master_put(master);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	return ret;
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic int sifive_spi_remove(struct platform_device *pdev)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	struct spi_master *master = platform_get_drvdata(pdev);
4218c2ecf20Sopenharmony_ci	struct sifive_spi *spi = spi_master_get_devdata(master);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	/* Disable all the interrupts just in case */
4248c2ecf20Sopenharmony_ci	sifive_spi_write(spi, SIFIVE_SPI_REG_IE, 0);
4258c2ecf20Sopenharmony_ci	clk_disable_unprepare(spi->clk);
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	return 0;
4288c2ecf20Sopenharmony_ci}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_cistatic const struct of_device_id sifive_spi_of_match[] = {
4318c2ecf20Sopenharmony_ci	{ .compatible = "sifive,spi0", },
4328c2ecf20Sopenharmony_ci	{}
4338c2ecf20Sopenharmony_ci};
4348c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sifive_spi_of_match);
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_cistatic struct platform_driver sifive_spi_driver = {
4378c2ecf20Sopenharmony_ci	.probe = sifive_spi_probe,
4388c2ecf20Sopenharmony_ci	.remove = sifive_spi_remove,
4398c2ecf20Sopenharmony_ci	.driver = {
4408c2ecf20Sopenharmony_ci		.name = SIFIVE_SPI_DRIVER_NAME,
4418c2ecf20Sopenharmony_ci		.of_match_table = sifive_spi_of_match,
4428c2ecf20Sopenharmony_ci	},
4438c2ecf20Sopenharmony_ci};
4448c2ecf20Sopenharmony_cimodule_platform_driver(sifive_spi_driver);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ciMODULE_AUTHOR("SiFive, Inc. <sifive@sifive.com>");
4478c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SiFive SPI driver");
4488c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
449