18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2012 - 2014 Allwinner Tech
48c2ecf20Sopenharmony_ci * Pan Nan <pannan@allwinnertech.com>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2014 Maxime Ripard
78c2ecf20Sopenharmony_ci * Maxime Ripard <maxime.ripard@free-electrons.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/clk.h>
118c2ecf20Sopenharmony_ci#include <linux/delay.h>
128c2ecf20Sopenharmony_ci#include <linux/device.h>
138c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
148c2ecf20Sopenharmony_ci#include <linux/io.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
178c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <linux/spi/spi.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define SUN4I_FIFO_DEPTH		64
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define SUN4I_RXDATA_REG		0x00
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define SUN4I_TXDATA_REG		0x04
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define SUN4I_CTL_REG			0x08
288c2ecf20Sopenharmony_ci#define SUN4I_CTL_ENABLE			BIT(0)
298c2ecf20Sopenharmony_ci#define SUN4I_CTL_MASTER			BIT(1)
308c2ecf20Sopenharmony_ci#define SUN4I_CTL_CPHA				BIT(2)
318c2ecf20Sopenharmony_ci#define SUN4I_CTL_CPOL				BIT(3)
328c2ecf20Sopenharmony_ci#define SUN4I_CTL_CS_ACTIVE_LOW			BIT(4)
338c2ecf20Sopenharmony_ci#define SUN4I_CTL_LMTF				BIT(6)
348c2ecf20Sopenharmony_ci#define SUN4I_CTL_TF_RST			BIT(8)
358c2ecf20Sopenharmony_ci#define SUN4I_CTL_RF_RST			BIT(9)
368c2ecf20Sopenharmony_ci#define SUN4I_CTL_XCH				BIT(10)
378c2ecf20Sopenharmony_ci#define SUN4I_CTL_CS_MASK			0x3000
388c2ecf20Sopenharmony_ci#define SUN4I_CTL_CS(cs)			(((cs) << 12) & SUN4I_CTL_CS_MASK)
398c2ecf20Sopenharmony_ci#define SUN4I_CTL_DHB				BIT(15)
408c2ecf20Sopenharmony_ci#define SUN4I_CTL_CS_MANUAL			BIT(16)
418c2ecf20Sopenharmony_ci#define SUN4I_CTL_CS_LEVEL			BIT(17)
428c2ecf20Sopenharmony_ci#define SUN4I_CTL_TP				BIT(18)
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#define SUN4I_INT_CTL_REG		0x0c
458c2ecf20Sopenharmony_ci#define SUN4I_INT_CTL_RF_F34			BIT(4)
468c2ecf20Sopenharmony_ci#define SUN4I_INT_CTL_TF_E34			BIT(12)
478c2ecf20Sopenharmony_ci#define SUN4I_INT_CTL_TC			BIT(16)
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#define SUN4I_INT_STA_REG		0x10
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#define SUN4I_DMA_CTL_REG		0x14
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define SUN4I_WAIT_REG			0x18
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#define SUN4I_CLK_CTL_REG		0x1c
568c2ecf20Sopenharmony_ci#define SUN4I_CLK_CTL_CDR2_MASK			0xff
578c2ecf20Sopenharmony_ci#define SUN4I_CLK_CTL_CDR2(div)			((div) & SUN4I_CLK_CTL_CDR2_MASK)
588c2ecf20Sopenharmony_ci#define SUN4I_CLK_CTL_CDR1_MASK			0xf
598c2ecf20Sopenharmony_ci#define SUN4I_CLK_CTL_CDR1(div)			(((div) & SUN4I_CLK_CTL_CDR1_MASK) << 8)
608c2ecf20Sopenharmony_ci#define SUN4I_CLK_CTL_DRS			BIT(12)
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci#define SUN4I_MAX_XFER_SIZE			0xffffff
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci#define SUN4I_BURST_CNT_REG		0x20
658c2ecf20Sopenharmony_ci#define SUN4I_BURST_CNT(cnt)			((cnt) & SUN4I_MAX_XFER_SIZE)
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#define SUN4I_XMIT_CNT_REG		0x24
688c2ecf20Sopenharmony_ci#define SUN4I_XMIT_CNT(cnt)			((cnt) & SUN4I_MAX_XFER_SIZE)
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci#define SUN4I_FIFO_STA_REG		0x28
728c2ecf20Sopenharmony_ci#define SUN4I_FIFO_STA_RF_CNT_MASK		0x7f
738c2ecf20Sopenharmony_ci#define SUN4I_FIFO_STA_RF_CNT_BITS		0
748c2ecf20Sopenharmony_ci#define SUN4I_FIFO_STA_TF_CNT_MASK		0x7f
758c2ecf20Sopenharmony_ci#define SUN4I_FIFO_STA_TF_CNT_BITS		16
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistruct sun4i_spi {
788c2ecf20Sopenharmony_ci	struct spi_master	*master;
798c2ecf20Sopenharmony_ci	void __iomem		*base_addr;
808c2ecf20Sopenharmony_ci	struct clk		*hclk;
818c2ecf20Sopenharmony_ci	struct clk		*mclk;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	struct completion	done;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	const u8		*tx_buf;
868c2ecf20Sopenharmony_ci	u8			*rx_buf;
878c2ecf20Sopenharmony_ci	int			len;
888c2ecf20Sopenharmony_ci};
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic inline u32 sun4i_spi_read(struct sun4i_spi *sspi, u32 reg)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	return readl(sspi->base_addr + reg);
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic inline void sun4i_spi_write(struct sun4i_spi *sspi, u32 reg, u32 value)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	writel(value, sspi->base_addr + reg);
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic inline u32 sun4i_spi_get_tx_fifo_count(struct sun4i_spi *sspi)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	u32 reg = sun4i_spi_read(sspi, SUN4I_FIFO_STA_REG);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	reg >>= SUN4I_FIFO_STA_TF_CNT_BITS;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	return reg & SUN4I_FIFO_STA_TF_CNT_MASK;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic inline void sun4i_spi_enable_interrupt(struct sun4i_spi *sspi, u32 mask)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	u32 reg = sun4i_spi_read(sspi, SUN4I_INT_CTL_REG);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	reg |= mask;
1148c2ecf20Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, reg);
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic inline void sun4i_spi_disable_interrupt(struct sun4i_spi *sspi, u32 mask)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	u32 reg = sun4i_spi_read(sspi, SUN4I_INT_CTL_REG);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	reg &= ~mask;
1228c2ecf20Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, reg);
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	u32 reg, cnt;
1288c2ecf20Sopenharmony_ci	u8 byte;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	/* See how much data is available */
1318c2ecf20Sopenharmony_ci	reg = sun4i_spi_read(sspi, SUN4I_FIFO_STA_REG);
1328c2ecf20Sopenharmony_ci	reg &= SUN4I_FIFO_STA_RF_CNT_MASK;
1338c2ecf20Sopenharmony_ci	cnt = reg >> SUN4I_FIFO_STA_RF_CNT_BITS;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	if (len > cnt)
1368c2ecf20Sopenharmony_ci		len = cnt;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	while (len--) {
1398c2ecf20Sopenharmony_ci		byte = readb(sspi->base_addr + SUN4I_RXDATA_REG);
1408c2ecf20Sopenharmony_ci		if (sspi->rx_buf)
1418c2ecf20Sopenharmony_ci			*sspi->rx_buf++ = byte;
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi, int len)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	u32 cnt;
1488c2ecf20Sopenharmony_ci	u8 byte;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	/* See how much data we can fit */
1518c2ecf20Sopenharmony_ci	cnt = SUN4I_FIFO_DEPTH - sun4i_spi_get_tx_fifo_count(sspi);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	len = min3(len, (int)cnt, sspi->len);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	while (len--) {
1568c2ecf20Sopenharmony_ci		byte = sspi->tx_buf ? *sspi->tx_buf++ : 0;
1578c2ecf20Sopenharmony_ci		writeb(byte, sspi->base_addr + SUN4I_TXDATA_REG);
1588c2ecf20Sopenharmony_ci		sspi->len--;
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic void sun4i_spi_set_cs(struct spi_device *spi, bool enable)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	struct sun4i_spi *sspi = spi_master_get_devdata(spi->master);
1658c2ecf20Sopenharmony_ci	u32 reg;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	reg &= ~SUN4I_CTL_CS_MASK;
1708c2ecf20Sopenharmony_ci	reg |= SUN4I_CTL_CS(spi->chip_select);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	/* We want to control the chip select manually */
1738c2ecf20Sopenharmony_ci	reg |= SUN4I_CTL_CS_MANUAL;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if (enable)
1768c2ecf20Sopenharmony_ci		reg |= SUN4I_CTL_CS_LEVEL;
1778c2ecf20Sopenharmony_ci	else
1788c2ecf20Sopenharmony_ci		reg &= ~SUN4I_CTL_CS_LEVEL;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	/*
1818c2ecf20Sopenharmony_ci	 * Even though this looks irrelevant since we are supposed to
1828c2ecf20Sopenharmony_ci	 * be controlling the chip select manually, this bit also
1838c2ecf20Sopenharmony_ci	 * controls the levels of the chip select for inactive
1848c2ecf20Sopenharmony_ci	 * devices.
1858c2ecf20Sopenharmony_ci	 *
1868c2ecf20Sopenharmony_ci	 * If we don't set it, the chip select level will go low by
1878c2ecf20Sopenharmony_ci	 * default when the device is idle, which is not really
1888c2ecf20Sopenharmony_ci	 * expected in the common case where the chip select is active
1898c2ecf20Sopenharmony_ci	 * low.
1908c2ecf20Sopenharmony_ci	 */
1918c2ecf20Sopenharmony_ci	if (spi->mode & SPI_CS_HIGH)
1928c2ecf20Sopenharmony_ci		reg &= ~SUN4I_CTL_CS_ACTIVE_LOW;
1938c2ecf20Sopenharmony_ci	else
1948c2ecf20Sopenharmony_ci		reg |= SUN4I_CTL_CS_ACTIVE_LOW;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic size_t sun4i_spi_max_transfer_size(struct spi_device *spi)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	return SUN4I_MAX_XFER_SIZE - 1;
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic int sun4i_spi_transfer_one(struct spi_master *master,
2058c2ecf20Sopenharmony_ci				  struct spi_device *spi,
2068c2ecf20Sopenharmony_ci				  struct spi_transfer *tfr)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	struct sun4i_spi *sspi = spi_master_get_devdata(master);
2098c2ecf20Sopenharmony_ci	unsigned int mclk_rate, div, timeout;
2108c2ecf20Sopenharmony_ci	unsigned int start, end, tx_time;
2118c2ecf20Sopenharmony_ci	unsigned int tx_len = 0;
2128c2ecf20Sopenharmony_ci	int ret = 0;
2138c2ecf20Sopenharmony_ci	u32 reg;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	/* We don't support transfer larger than the FIFO */
2168c2ecf20Sopenharmony_ci	if (tfr->len > SUN4I_MAX_XFER_SIZE)
2178c2ecf20Sopenharmony_ci		return -EMSGSIZE;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	if (tfr->tx_buf && tfr->len >= SUN4I_MAX_XFER_SIZE)
2208c2ecf20Sopenharmony_ci		return -EMSGSIZE;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	reinit_completion(&sspi->done);
2238c2ecf20Sopenharmony_ci	sspi->tx_buf = tfr->tx_buf;
2248c2ecf20Sopenharmony_ci	sspi->rx_buf = tfr->rx_buf;
2258c2ecf20Sopenharmony_ci	sspi->len = tfr->len;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	/* Clear pending interrupts */
2288c2ecf20Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_INT_STA_REG, ~0);
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	/* Reset FIFOs */
2348c2ecf20Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_CTL_REG,
2358c2ecf20Sopenharmony_ci			reg | SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	/*
2388c2ecf20Sopenharmony_ci	 * Setup the transfer control register: Chip Select,
2398c2ecf20Sopenharmony_ci	 * polarities, etc.
2408c2ecf20Sopenharmony_ci	 */
2418c2ecf20Sopenharmony_ci	if (spi->mode & SPI_CPOL)
2428c2ecf20Sopenharmony_ci		reg |= SUN4I_CTL_CPOL;
2438c2ecf20Sopenharmony_ci	else
2448c2ecf20Sopenharmony_ci		reg &= ~SUN4I_CTL_CPOL;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	if (spi->mode & SPI_CPHA)
2478c2ecf20Sopenharmony_ci		reg |= SUN4I_CTL_CPHA;
2488c2ecf20Sopenharmony_ci	else
2498c2ecf20Sopenharmony_ci		reg &= ~SUN4I_CTL_CPHA;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	if (spi->mode & SPI_LSB_FIRST)
2528c2ecf20Sopenharmony_ci		reg |= SUN4I_CTL_LMTF;
2538c2ecf20Sopenharmony_ci	else
2548c2ecf20Sopenharmony_ci		reg &= ~SUN4I_CTL_LMTF;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	/*
2588c2ecf20Sopenharmony_ci	 * If it's a TX only transfer, we don't want to fill the RX
2598c2ecf20Sopenharmony_ci	 * FIFO with bogus data
2608c2ecf20Sopenharmony_ci	 */
2618c2ecf20Sopenharmony_ci	if (sspi->rx_buf)
2628c2ecf20Sopenharmony_ci		reg &= ~SUN4I_CTL_DHB;
2638c2ecf20Sopenharmony_ci	else
2648c2ecf20Sopenharmony_ci		reg |= SUN4I_CTL_DHB;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	/* Ensure that we have a parent clock fast enough */
2698c2ecf20Sopenharmony_ci	mclk_rate = clk_get_rate(sspi->mclk);
2708c2ecf20Sopenharmony_ci	if (mclk_rate < (2 * tfr->speed_hz)) {
2718c2ecf20Sopenharmony_ci		clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
2728c2ecf20Sopenharmony_ci		mclk_rate = clk_get_rate(sspi->mclk);
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	/*
2768c2ecf20Sopenharmony_ci	 * Setup clock divider.
2778c2ecf20Sopenharmony_ci	 *
2788c2ecf20Sopenharmony_ci	 * We have two choices there. Either we can use the clock
2798c2ecf20Sopenharmony_ci	 * divide rate 1, which is calculated thanks to this formula:
2808c2ecf20Sopenharmony_ci	 * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1))
2818c2ecf20Sopenharmony_ci	 * Or we can use CDR2, which is calculated with the formula:
2828c2ecf20Sopenharmony_ci	 * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
2838c2ecf20Sopenharmony_ci	 * Wether we use the former or the latter is set through the
2848c2ecf20Sopenharmony_ci	 * DRS bit.
2858c2ecf20Sopenharmony_ci	 *
2868c2ecf20Sopenharmony_ci	 * First try CDR2, and if we can't reach the expected
2878c2ecf20Sopenharmony_ci	 * frequency, fall back to CDR1.
2888c2ecf20Sopenharmony_ci	 */
2898c2ecf20Sopenharmony_ci	div = mclk_rate / (2 * tfr->speed_hz);
2908c2ecf20Sopenharmony_ci	if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) {
2918c2ecf20Sopenharmony_ci		if (div > 0)
2928c2ecf20Sopenharmony_ci			div--;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci		reg = SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS;
2958c2ecf20Sopenharmony_ci	} else {
2968c2ecf20Sopenharmony_ci		div = ilog2(mclk_rate) - ilog2(tfr->speed_hz);
2978c2ecf20Sopenharmony_ci		reg = SUN4I_CLK_CTL_CDR1(div);
2988c2ecf20Sopenharmony_ci	}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_CLK_CTL_REG, reg);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	/* Setup the transfer now... */
3038c2ecf20Sopenharmony_ci	if (sspi->tx_buf)
3048c2ecf20Sopenharmony_ci		tx_len = tfr->len;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	/* Setup the counters */
3078c2ecf20Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_BURST_CNT_REG, SUN4I_BURST_CNT(tfr->len));
3088c2ecf20Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_XMIT_CNT_REG, SUN4I_XMIT_CNT(tx_len));
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	/*
3118c2ecf20Sopenharmony_ci	 * Fill the TX FIFO
3128c2ecf20Sopenharmony_ci	 * Filling the FIFO fully causes timeout for some reason
3138c2ecf20Sopenharmony_ci	 * at least on spi2 on A10s
3148c2ecf20Sopenharmony_ci	 */
3158c2ecf20Sopenharmony_ci	sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH - 1);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	/* Enable the interrupts */
3188c2ecf20Sopenharmony_ci	sun4i_spi_enable_interrupt(sspi, SUN4I_INT_CTL_TC |
3198c2ecf20Sopenharmony_ci					 SUN4I_INT_CTL_RF_F34);
3208c2ecf20Sopenharmony_ci	/* Only enable Tx FIFO interrupt if we really need it */
3218c2ecf20Sopenharmony_ci	if (tx_len > SUN4I_FIFO_DEPTH)
3228c2ecf20Sopenharmony_ci		sun4i_spi_enable_interrupt(sspi, SUN4I_INT_CTL_TF_E34);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	/* Start the transfer */
3258c2ecf20Sopenharmony_ci	reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
3268c2ecf20Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
3298c2ecf20Sopenharmony_ci	start = jiffies;
3308c2ecf20Sopenharmony_ci	timeout = wait_for_completion_timeout(&sspi->done,
3318c2ecf20Sopenharmony_ci					      msecs_to_jiffies(tx_time));
3328c2ecf20Sopenharmony_ci	end = jiffies;
3338c2ecf20Sopenharmony_ci	if (!timeout) {
3348c2ecf20Sopenharmony_ci		dev_warn(&master->dev,
3358c2ecf20Sopenharmony_ci			 "%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
3368c2ecf20Sopenharmony_ci			 dev_name(&spi->dev), tfr->len, tfr->speed_hz,
3378c2ecf20Sopenharmony_ci			 jiffies_to_msecs(end - start), tx_time);
3388c2ecf20Sopenharmony_ci		ret = -ETIMEDOUT;
3398c2ecf20Sopenharmony_ci		goto out;
3408c2ecf20Sopenharmony_ci	}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ciout:
3448c2ecf20Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, 0);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	return ret;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic irqreturn_t sun4i_spi_handler(int irq, void *dev_id)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	struct sun4i_spi *sspi = dev_id;
3528c2ecf20Sopenharmony_ci	u32 status = sun4i_spi_read(sspi, SUN4I_INT_STA_REG);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	/* Transfer complete */
3558c2ecf20Sopenharmony_ci	if (status & SUN4I_INT_CTL_TC) {
3568c2ecf20Sopenharmony_ci		sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TC);
3578c2ecf20Sopenharmony_ci		sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
3588c2ecf20Sopenharmony_ci		complete(&sspi->done);
3598c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	/* Receive FIFO 3/4 full */
3638c2ecf20Sopenharmony_ci	if (status & SUN4I_INT_CTL_RF_F34) {
3648c2ecf20Sopenharmony_ci		sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
3658c2ecf20Sopenharmony_ci		/* Only clear the interrupt _after_ draining the FIFO */
3668c2ecf20Sopenharmony_ci		sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_RF_F34);
3678c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
3688c2ecf20Sopenharmony_ci	}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	/* Transmit FIFO 3/4 empty */
3718c2ecf20Sopenharmony_ci	if (status & SUN4I_INT_CTL_TF_E34) {
3728c2ecf20Sopenharmony_ci		sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci		if (!sspi->len)
3758c2ecf20Sopenharmony_ci			/* nothing left to transmit */
3768c2ecf20Sopenharmony_ci			sun4i_spi_disable_interrupt(sspi, SUN4I_INT_CTL_TF_E34);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci		/* Only clear the interrupt _after_ re-seeding the FIFO */
3798c2ecf20Sopenharmony_ci		sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TF_E34);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	return IRQ_NONE;
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cistatic int sun4i_spi_runtime_resume(struct device *dev)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	struct spi_master *master = dev_get_drvdata(dev);
3908c2ecf20Sopenharmony_ci	struct sun4i_spi *sspi = spi_master_get_devdata(master);
3918c2ecf20Sopenharmony_ci	int ret;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(sspi->hclk);
3948c2ecf20Sopenharmony_ci	if (ret) {
3958c2ecf20Sopenharmony_ci		dev_err(dev, "Couldn't enable AHB clock\n");
3968c2ecf20Sopenharmony_ci		goto out;
3978c2ecf20Sopenharmony_ci	}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(sspi->mclk);
4008c2ecf20Sopenharmony_ci	if (ret) {
4018c2ecf20Sopenharmony_ci		dev_err(dev, "Couldn't enable module clock\n");
4028c2ecf20Sopenharmony_ci		goto err;
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_CTL_REG,
4068c2ecf20Sopenharmony_ci			SUN4I_CTL_ENABLE | SUN4I_CTL_MASTER | SUN4I_CTL_TP);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	return 0;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_cierr:
4118c2ecf20Sopenharmony_ci	clk_disable_unprepare(sspi->hclk);
4128c2ecf20Sopenharmony_ciout:
4138c2ecf20Sopenharmony_ci	return ret;
4148c2ecf20Sopenharmony_ci}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_cistatic int sun4i_spi_runtime_suspend(struct device *dev)
4178c2ecf20Sopenharmony_ci{
4188c2ecf20Sopenharmony_ci	struct spi_master *master = dev_get_drvdata(dev);
4198c2ecf20Sopenharmony_ci	struct sun4i_spi *sspi = spi_master_get_devdata(master);
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	clk_disable_unprepare(sspi->mclk);
4228c2ecf20Sopenharmony_ci	clk_disable_unprepare(sspi->hclk);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	return 0;
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistatic int sun4i_spi_probe(struct platform_device *pdev)
4288c2ecf20Sopenharmony_ci{
4298c2ecf20Sopenharmony_ci	struct spi_master *master;
4308c2ecf20Sopenharmony_ci	struct sun4i_spi *sspi;
4318c2ecf20Sopenharmony_ci	int ret = 0, irq;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	master = spi_alloc_master(&pdev->dev, sizeof(struct sun4i_spi));
4348c2ecf20Sopenharmony_ci	if (!master) {
4358c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
4368c2ecf20Sopenharmony_ci		return -ENOMEM;
4378c2ecf20Sopenharmony_ci	}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, master);
4408c2ecf20Sopenharmony_ci	sspi = spi_master_get_devdata(master);
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	sspi->base_addr = devm_platform_ioremap_resource(pdev, 0);
4438c2ecf20Sopenharmony_ci	if (IS_ERR(sspi->base_addr)) {
4448c2ecf20Sopenharmony_ci		ret = PTR_ERR(sspi->base_addr);
4458c2ecf20Sopenharmony_ci		goto err_free_master;
4468c2ecf20Sopenharmony_ci	}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
4498c2ecf20Sopenharmony_ci	if (irq < 0) {
4508c2ecf20Sopenharmony_ci		ret = -ENXIO;
4518c2ecf20Sopenharmony_ci		goto err_free_master;
4528c2ecf20Sopenharmony_ci	}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	ret = devm_request_irq(&pdev->dev, irq, sun4i_spi_handler,
4558c2ecf20Sopenharmony_ci			       0, "sun4i-spi", sspi);
4568c2ecf20Sopenharmony_ci	if (ret) {
4578c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Cannot request IRQ\n");
4588c2ecf20Sopenharmony_ci		goto err_free_master;
4598c2ecf20Sopenharmony_ci	}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	sspi->master = master;
4628c2ecf20Sopenharmony_ci	master->max_speed_hz = 100 * 1000 * 1000;
4638c2ecf20Sopenharmony_ci	master->min_speed_hz = 3 * 1000;
4648c2ecf20Sopenharmony_ci	master->set_cs = sun4i_spi_set_cs;
4658c2ecf20Sopenharmony_ci	master->transfer_one = sun4i_spi_transfer_one;
4668c2ecf20Sopenharmony_ci	master->num_chipselect = 4;
4678c2ecf20Sopenharmony_ci	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
4688c2ecf20Sopenharmony_ci	master->bits_per_word_mask = SPI_BPW_MASK(8);
4698c2ecf20Sopenharmony_ci	master->dev.of_node = pdev->dev.of_node;
4708c2ecf20Sopenharmony_ci	master->auto_runtime_pm = true;
4718c2ecf20Sopenharmony_ci	master->max_transfer_size = sun4i_spi_max_transfer_size;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
4748c2ecf20Sopenharmony_ci	if (IS_ERR(sspi->hclk)) {
4758c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
4768c2ecf20Sopenharmony_ci		ret = PTR_ERR(sspi->hclk);
4778c2ecf20Sopenharmony_ci		goto err_free_master;
4788c2ecf20Sopenharmony_ci	}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	sspi->mclk = devm_clk_get(&pdev->dev, "mod");
4818c2ecf20Sopenharmony_ci	if (IS_ERR(sspi->mclk)) {
4828c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Unable to acquire module clock\n");
4838c2ecf20Sopenharmony_ci		ret = PTR_ERR(sspi->mclk);
4848c2ecf20Sopenharmony_ci		goto err_free_master;
4858c2ecf20Sopenharmony_ci	}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	init_completion(&sspi->done);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	/*
4908c2ecf20Sopenharmony_ci	 * This wake-up/shutdown pattern is to be able to have the
4918c2ecf20Sopenharmony_ci	 * device woken up, even if runtime_pm is disabled
4928c2ecf20Sopenharmony_ci	 */
4938c2ecf20Sopenharmony_ci	ret = sun4i_spi_runtime_resume(&pdev->dev);
4948c2ecf20Sopenharmony_ci	if (ret) {
4958c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Couldn't resume the device\n");
4968c2ecf20Sopenharmony_ci		goto err_free_master;
4978c2ecf20Sopenharmony_ci	}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	pm_runtime_set_active(&pdev->dev);
5008c2ecf20Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
5018c2ecf20Sopenharmony_ci	pm_runtime_idle(&pdev->dev);
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	ret = devm_spi_register_master(&pdev->dev, master);
5048c2ecf20Sopenharmony_ci	if (ret) {
5058c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "cannot register SPI master\n");
5068c2ecf20Sopenharmony_ci		goto err_pm_disable;
5078c2ecf20Sopenharmony_ci	}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	return 0;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_cierr_pm_disable:
5128c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
5138c2ecf20Sopenharmony_ci	sun4i_spi_runtime_suspend(&pdev->dev);
5148c2ecf20Sopenharmony_cierr_free_master:
5158c2ecf20Sopenharmony_ci	spi_master_put(master);
5168c2ecf20Sopenharmony_ci	return ret;
5178c2ecf20Sopenharmony_ci}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_cistatic int sun4i_spi_remove(struct platform_device *pdev)
5208c2ecf20Sopenharmony_ci{
5218c2ecf20Sopenharmony_ci	pm_runtime_force_suspend(&pdev->dev);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	return 0;
5248c2ecf20Sopenharmony_ci}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_cistatic const struct of_device_id sun4i_spi_match[] = {
5278c2ecf20Sopenharmony_ci	{ .compatible = "allwinner,sun4i-a10-spi", },
5288c2ecf20Sopenharmony_ci	{}
5298c2ecf20Sopenharmony_ci};
5308c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sun4i_spi_match);
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_cistatic const struct dev_pm_ops sun4i_spi_pm_ops = {
5338c2ecf20Sopenharmony_ci	.runtime_resume		= sun4i_spi_runtime_resume,
5348c2ecf20Sopenharmony_ci	.runtime_suspend	= sun4i_spi_runtime_suspend,
5358c2ecf20Sopenharmony_ci};
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_cistatic struct platform_driver sun4i_spi_driver = {
5388c2ecf20Sopenharmony_ci	.probe	= sun4i_spi_probe,
5398c2ecf20Sopenharmony_ci	.remove	= sun4i_spi_remove,
5408c2ecf20Sopenharmony_ci	.driver	= {
5418c2ecf20Sopenharmony_ci		.name		= "sun4i-spi",
5428c2ecf20Sopenharmony_ci		.of_match_table	= sun4i_spi_match,
5438c2ecf20Sopenharmony_ci		.pm		= &sun4i_spi_pm_ops,
5448c2ecf20Sopenharmony_ci	},
5458c2ecf20Sopenharmony_ci};
5468c2ecf20Sopenharmony_cimodule_platform_driver(sun4i_spi_driver);
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ciMODULE_AUTHOR("Pan Nan <pannan@allwinnertech.com>");
5498c2ecf20Sopenharmony_ciMODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
5508c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Allwinner A1X/A20 SPI controller driver");
5518c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
552