162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2012 - 2014 Allwinner Tech
462306a36Sopenharmony_ci * Pan Nan <pannan@allwinnertech.com>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2014 Maxime Ripard
762306a36Sopenharmony_ci * Maxime Ripard <maxime.ripard@free-electrons.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/clk.h>
1162306a36Sopenharmony_ci#include <linux/delay.h>
1262306a36Sopenharmony_ci#include <linux/device.h>
1362306a36Sopenharmony_ci#include <linux/interrupt.h>
1462306a36Sopenharmony_ci#include <linux/io.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/platform_device.h>
1762306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <linux/spi/spi.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define SUN4I_FIFO_DEPTH		64
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define SUN4I_RXDATA_REG		0x00
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define SUN4I_TXDATA_REG		0x04
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define SUN4I_CTL_REG			0x08
2862306a36Sopenharmony_ci#define SUN4I_CTL_ENABLE			BIT(0)
2962306a36Sopenharmony_ci#define SUN4I_CTL_MASTER			BIT(1)
3062306a36Sopenharmony_ci#define SUN4I_CTL_CPHA				BIT(2)
3162306a36Sopenharmony_ci#define SUN4I_CTL_CPOL				BIT(3)
3262306a36Sopenharmony_ci#define SUN4I_CTL_CS_ACTIVE_LOW			BIT(4)
3362306a36Sopenharmony_ci#define SUN4I_CTL_LMTF				BIT(6)
3462306a36Sopenharmony_ci#define SUN4I_CTL_TF_RST			BIT(8)
3562306a36Sopenharmony_ci#define SUN4I_CTL_RF_RST			BIT(9)
3662306a36Sopenharmony_ci#define SUN4I_CTL_XCH				BIT(10)
3762306a36Sopenharmony_ci#define SUN4I_CTL_CS_MASK			0x3000
3862306a36Sopenharmony_ci#define SUN4I_CTL_CS(cs)			(((cs) << 12) & SUN4I_CTL_CS_MASK)
3962306a36Sopenharmony_ci#define SUN4I_CTL_DHB				BIT(15)
4062306a36Sopenharmony_ci#define SUN4I_CTL_CS_MANUAL			BIT(16)
4162306a36Sopenharmony_ci#define SUN4I_CTL_CS_LEVEL			BIT(17)
4262306a36Sopenharmony_ci#define SUN4I_CTL_TP				BIT(18)
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define SUN4I_INT_CTL_REG		0x0c
4562306a36Sopenharmony_ci#define SUN4I_INT_CTL_RF_F34			BIT(4)
4662306a36Sopenharmony_ci#define SUN4I_INT_CTL_TF_E34			BIT(12)
4762306a36Sopenharmony_ci#define SUN4I_INT_CTL_TC			BIT(16)
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define SUN4I_INT_STA_REG		0x10
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define SUN4I_DMA_CTL_REG		0x14
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#define SUN4I_WAIT_REG			0x18
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define SUN4I_CLK_CTL_REG		0x1c
5662306a36Sopenharmony_ci#define SUN4I_CLK_CTL_CDR2_MASK			0xff
5762306a36Sopenharmony_ci#define SUN4I_CLK_CTL_CDR2(div)			((div) & SUN4I_CLK_CTL_CDR2_MASK)
5862306a36Sopenharmony_ci#define SUN4I_CLK_CTL_CDR1_MASK			0xf
5962306a36Sopenharmony_ci#define SUN4I_CLK_CTL_CDR1(div)			(((div) & SUN4I_CLK_CTL_CDR1_MASK) << 8)
6062306a36Sopenharmony_ci#define SUN4I_CLK_CTL_DRS			BIT(12)
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#define SUN4I_MAX_XFER_SIZE			0xffffff
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#define SUN4I_BURST_CNT_REG		0x20
6562306a36Sopenharmony_ci#define SUN4I_BURST_CNT(cnt)			((cnt) & SUN4I_MAX_XFER_SIZE)
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci#define SUN4I_XMIT_CNT_REG		0x24
6862306a36Sopenharmony_ci#define SUN4I_XMIT_CNT(cnt)			((cnt) & SUN4I_MAX_XFER_SIZE)
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#define SUN4I_FIFO_STA_REG		0x28
7262306a36Sopenharmony_ci#define SUN4I_FIFO_STA_RF_CNT_MASK		0x7f
7362306a36Sopenharmony_ci#define SUN4I_FIFO_STA_RF_CNT_BITS		0
7462306a36Sopenharmony_ci#define SUN4I_FIFO_STA_TF_CNT_MASK		0x7f
7562306a36Sopenharmony_ci#define SUN4I_FIFO_STA_TF_CNT_BITS		16
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistruct sun4i_spi {
7862306a36Sopenharmony_ci	struct spi_master	*master;
7962306a36Sopenharmony_ci	void __iomem		*base_addr;
8062306a36Sopenharmony_ci	struct clk		*hclk;
8162306a36Sopenharmony_ci	struct clk		*mclk;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	struct completion	done;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	const u8		*tx_buf;
8662306a36Sopenharmony_ci	u8			*rx_buf;
8762306a36Sopenharmony_ci	int			len;
8862306a36Sopenharmony_ci};
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic inline u32 sun4i_spi_read(struct sun4i_spi *sspi, u32 reg)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	return readl(sspi->base_addr + reg);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic inline void sun4i_spi_write(struct sun4i_spi *sspi, u32 reg, u32 value)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	writel(value, sspi->base_addr + reg);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic inline u32 sun4i_spi_get_tx_fifo_count(struct sun4i_spi *sspi)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	u32 reg = sun4i_spi_read(sspi, SUN4I_FIFO_STA_REG);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	reg >>= SUN4I_FIFO_STA_TF_CNT_BITS;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	return reg & SUN4I_FIFO_STA_TF_CNT_MASK;
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic inline void sun4i_spi_enable_interrupt(struct sun4i_spi *sspi, u32 mask)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	u32 reg = sun4i_spi_read(sspi, SUN4I_INT_CTL_REG);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	reg |= mask;
11462306a36Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, reg);
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic inline void sun4i_spi_disable_interrupt(struct sun4i_spi *sspi, u32 mask)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	u32 reg = sun4i_spi_read(sspi, SUN4I_INT_CTL_REG);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	reg &= ~mask;
12262306a36Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, reg);
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	u32 reg, cnt;
12862306a36Sopenharmony_ci	u8 byte;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	/* See how much data is available */
13162306a36Sopenharmony_ci	reg = sun4i_spi_read(sspi, SUN4I_FIFO_STA_REG);
13262306a36Sopenharmony_ci	reg &= SUN4I_FIFO_STA_RF_CNT_MASK;
13362306a36Sopenharmony_ci	cnt = reg >> SUN4I_FIFO_STA_RF_CNT_BITS;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	if (len > cnt)
13662306a36Sopenharmony_ci		len = cnt;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	while (len--) {
13962306a36Sopenharmony_ci		byte = readb(sspi->base_addr + SUN4I_RXDATA_REG);
14062306a36Sopenharmony_ci		if (sspi->rx_buf)
14162306a36Sopenharmony_ci			*sspi->rx_buf++ = byte;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi, int len)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	u32 cnt;
14862306a36Sopenharmony_ci	u8 byte;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	/* See how much data we can fit */
15162306a36Sopenharmony_ci	cnt = SUN4I_FIFO_DEPTH - sun4i_spi_get_tx_fifo_count(sspi);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	len = min3(len, (int)cnt, sspi->len);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	while (len--) {
15662306a36Sopenharmony_ci		byte = sspi->tx_buf ? *sspi->tx_buf++ : 0;
15762306a36Sopenharmony_ci		writeb(byte, sspi->base_addr + SUN4I_TXDATA_REG);
15862306a36Sopenharmony_ci		sspi->len--;
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic void sun4i_spi_set_cs(struct spi_device *spi, bool enable)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	struct sun4i_spi *sspi = spi_master_get_devdata(spi->master);
16562306a36Sopenharmony_ci	u32 reg;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	reg &= ~SUN4I_CTL_CS_MASK;
17062306a36Sopenharmony_ci	reg |= SUN4I_CTL_CS(spi_get_chipselect(spi, 0));
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	/* We want to control the chip select manually */
17362306a36Sopenharmony_ci	reg |= SUN4I_CTL_CS_MANUAL;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	if (enable)
17662306a36Sopenharmony_ci		reg |= SUN4I_CTL_CS_LEVEL;
17762306a36Sopenharmony_ci	else
17862306a36Sopenharmony_ci		reg &= ~SUN4I_CTL_CS_LEVEL;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	/*
18162306a36Sopenharmony_ci	 * Even though this looks irrelevant since we are supposed to
18262306a36Sopenharmony_ci	 * be controlling the chip select manually, this bit also
18362306a36Sopenharmony_ci	 * controls the levels of the chip select for inactive
18462306a36Sopenharmony_ci	 * devices.
18562306a36Sopenharmony_ci	 *
18662306a36Sopenharmony_ci	 * If we don't set it, the chip select level will go low by
18762306a36Sopenharmony_ci	 * default when the device is idle, which is not really
18862306a36Sopenharmony_ci	 * expected in the common case where the chip select is active
18962306a36Sopenharmony_ci	 * low.
19062306a36Sopenharmony_ci	 */
19162306a36Sopenharmony_ci	if (spi->mode & SPI_CS_HIGH)
19262306a36Sopenharmony_ci		reg &= ~SUN4I_CTL_CS_ACTIVE_LOW;
19362306a36Sopenharmony_ci	else
19462306a36Sopenharmony_ci		reg |= SUN4I_CTL_CS_ACTIVE_LOW;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic size_t sun4i_spi_max_transfer_size(struct spi_device *spi)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	return SUN4I_MAX_XFER_SIZE - 1;
20262306a36Sopenharmony_ci}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic int sun4i_spi_transfer_one(struct spi_master *master,
20562306a36Sopenharmony_ci				  struct spi_device *spi,
20662306a36Sopenharmony_ci				  struct spi_transfer *tfr)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct sun4i_spi *sspi = spi_master_get_devdata(master);
20962306a36Sopenharmony_ci	unsigned int mclk_rate, div, timeout;
21062306a36Sopenharmony_ci	unsigned int start, end, tx_time;
21162306a36Sopenharmony_ci	unsigned int tx_len = 0;
21262306a36Sopenharmony_ci	int ret = 0;
21362306a36Sopenharmony_ci	u32 reg;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	/* We don't support transfer larger than the FIFO */
21662306a36Sopenharmony_ci	if (tfr->len > SUN4I_MAX_XFER_SIZE)
21762306a36Sopenharmony_ci		return -EMSGSIZE;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	if (tfr->tx_buf && tfr->len >= SUN4I_MAX_XFER_SIZE)
22062306a36Sopenharmony_ci		return -EMSGSIZE;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	reinit_completion(&sspi->done);
22362306a36Sopenharmony_ci	sspi->tx_buf = tfr->tx_buf;
22462306a36Sopenharmony_ci	sspi->rx_buf = tfr->rx_buf;
22562306a36Sopenharmony_ci	sspi->len = tfr->len;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	/* Clear pending interrupts */
22862306a36Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_INT_STA_REG, ~0);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	/* Reset FIFOs */
23462306a36Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_CTL_REG,
23562306a36Sopenharmony_ci			reg | SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	/*
23862306a36Sopenharmony_ci	 * Setup the transfer control register: Chip Select,
23962306a36Sopenharmony_ci	 * polarities, etc.
24062306a36Sopenharmony_ci	 */
24162306a36Sopenharmony_ci	if (spi->mode & SPI_CPOL)
24262306a36Sopenharmony_ci		reg |= SUN4I_CTL_CPOL;
24362306a36Sopenharmony_ci	else
24462306a36Sopenharmony_ci		reg &= ~SUN4I_CTL_CPOL;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	if (spi->mode & SPI_CPHA)
24762306a36Sopenharmony_ci		reg |= SUN4I_CTL_CPHA;
24862306a36Sopenharmony_ci	else
24962306a36Sopenharmony_ci		reg &= ~SUN4I_CTL_CPHA;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	if (spi->mode & SPI_LSB_FIRST)
25262306a36Sopenharmony_ci		reg |= SUN4I_CTL_LMTF;
25362306a36Sopenharmony_ci	else
25462306a36Sopenharmony_ci		reg &= ~SUN4I_CTL_LMTF;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	/*
25862306a36Sopenharmony_ci	 * If it's a TX only transfer, we don't want to fill the RX
25962306a36Sopenharmony_ci	 * FIFO with bogus data
26062306a36Sopenharmony_ci	 */
26162306a36Sopenharmony_ci	if (sspi->rx_buf)
26262306a36Sopenharmony_ci		reg &= ~SUN4I_CTL_DHB;
26362306a36Sopenharmony_ci	else
26462306a36Sopenharmony_ci		reg |= SUN4I_CTL_DHB;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	/* Ensure that we have a parent clock fast enough */
26962306a36Sopenharmony_ci	mclk_rate = clk_get_rate(sspi->mclk);
27062306a36Sopenharmony_ci	if (mclk_rate < (2 * tfr->speed_hz)) {
27162306a36Sopenharmony_ci		clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
27262306a36Sopenharmony_ci		mclk_rate = clk_get_rate(sspi->mclk);
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	/*
27662306a36Sopenharmony_ci	 * Setup clock divider.
27762306a36Sopenharmony_ci	 *
27862306a36Sopenharmony_ci	 * We have two choices there. Either we can use the clock
27962306a36Sopenharmony_ci	 * divide rate 1, which is calculated thanks to this formula:
28062306a36Sopenharmony_ci	 * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1))
28162306a36Sopenharmony_ci	 * Or we can use CDR2, which is calculated with the formula:
28262306a36Sopenharmony_ci	 * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
28362306a36Sopenharmony_ci	 * Whether we use the former or the latter is set through the
28462306a36Sopenharmony_ci	 * DRS bit.
28562306a36Sopenharmony_ci	 *
28662306a36Sopenharmony_ci	 * First try CDR2, and if we can't reach the expected
28762306a36Sopenharmony_ci	 * frequency, fall back to CDR1.
28862306a36Sopenharmony_ci	 */
28962306a36Sopenharmony_ci	div = mclk_rate / (2 * tfr->speed_hz);
29062306a36Sopenharmony_ci	if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) {
29162306a36Sopenharmony_ci		if (div > 0)
29262306a36Sopenharmony_ci			div--;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci		reg = SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS;
29562306a36Sopenharmony_ci	} else {
29662306a36Sopenharmony_ci		div = ilog2(mclk_rate) - ilog2(tfr->speed_hz);
29762306a36Sopenharmony_ci		reg = SUN4I_CLK_CTL_CDR1(div);
29862306a36Sopenharmony_ci	}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_CLK_CTL_REG, reg);
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	/* Setup the transfer now... */
30362306a36Sopenharmony_ci	if (sspi->tx_buf)
30462306a36Sopenharmony_ci		tx_len = tfr->len;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	/* Setup the counters */
30762306a36Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_BURST_CNT_REG, SUN4I_BURST_CNT(tfr->len));
30862306a36Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_XMIT_CNT_REG, SUN4I_XMIT_CNT(tx_len));
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	/*
31162306a36Sopenharmony_ci	 * Fill the TX FIFO
31262306a36Sopenharmony_ci	 * Filling the FIFO fully causes timeout for some reason
31362306a36Sopenharmony_ci	 * at least on spi2 on A10s
31462306a36Sopenharmony_ci	 */
31562306a36Sopenharmony_ci	sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH - 1);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	/* Enable the interrupts */
31862306a36Sopenharmony_ci	sun4i_spi_enable_interrupt(sspi, SUN4I_INT_CTL_TC |
31962306a36Sopenharmony_ci					 SUN4I_INT_CTL_RF_F34);
32062306a36Sopenharmony_ci	/* Only enable Tx FIFO interrupt if we really need it */
32162306a36Sopenharmony_ci	if (tx_len > SUN4I_FIFO_DEPTH)
32262306a36Sopenharmony_ci		sun4i_spi_enable_interrupt(sspi, SUN4I_INT_CTL_TF_E34);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	/* Start the transfer */
32562306a36Sopenharmony_ci	reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
32662306a36Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
32962306a36Sopenharmony_ci	start = jiffies;
33062306a36Sopenharmony_ci	timeout = wait_for_completion_timeout(&sspi->done,
33162306a36Sopenharmony_ci					      msecs_to_jiffies(tx_time));
33262306a36Sopenharmony_ci	end = jiffies;
33362306a36Sopenharmony_ci	if (!timeout) {
33462306a36Sopenharmony_ci		dev_warn(&master->dev,
33562306a36Sopenharmony_ci			 "%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
33662306a36Sopenharmony_ci			 dev_name(&spi->dev), tfr->len, tfr->speed_hz,
33762306a36Sopenharmony_ci			 jiffies_to_msecs(end - start), tx_time);
33862306a36Sopenharmony_ci		ret = -ETIMEDOUT;
33962306a36Sopenharmony_ci		goto out;
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ciout:
34462306a36Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, 0);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	return ret;
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistatic irqreturn_t sun4i_spi_handler(int irq, void *dev_id)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	struct sun4i_spi *sspi = dev_id;
35262306a36Sopenharmony_ci	u32 status = sun4i_spi_read(sspi, SUN4I_INT_STA_REG);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	/* Transfer complete */
35562306a36Sopenharmony_ci	if (status & SUN4I_INT_CTL_TC) {
35662306a36Sopenharmony_ci		sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TC);
35762306a36Sopenharmony_ci		sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
35862306a36Sopenharmony_ci		complete(&sspi->done);
35962306a36Sopenharmony_ci		return IRQ_HANDLED;
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	/* Receive FIFO 3/4 full */
36362306a36Sopenharmony_ci	if (status & SUN4I_INT_CTL_RF_F34) {
36462306a36Sopenharmony_ci		sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
36562306a36Sopenharmony_ci		/* Only clear the interrupt _after_ draining the FIFO */
36662306a36Sopenharmony_ci		sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_RF_F34);
36762306a36Sopenharmony_ci		return IRQ_HANDLED;
36862306a36Sopenharmony_ci	}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	/* Transmit FIFO 3/4 empty */
37162306a36Sopenharmony_ci	if (status & SUN4I_INT_CTL_TF_E34) {
37262306a36Sopenharmony_ci		sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci		if (!sspi->len)
37562306a36Sopenharmony_ci			/* nothing left to transmit */
37662306a36Sopenharmony_ci			sun4i_spi_disable_interrupt(sspi, SUN4I_INT_CTL_TF_E34);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci		/* Only clear the interrupt _after_ re-seeding the FIFO */
37962306a36Sopenharmony_ci		sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TF_E34);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci		return IRQ_HANDLED;
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	return IRQ_NONE;
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cistatic int sun4i_spi_runtime_resume(struct device *dev)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	struct spi_master *master = dev_get_drvdata(dev);
39062306a36Sopenharmony_ci	struct sun4i_spi *sspi = spi_master_get_devdata(master);
39162306a36Sopenharmony_ci	int ret;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	ret = clk_prepare_enable(sspi->hclk);
39462306a36Sopenharmony_ci	if (ret) {
39562306a36Sopenharmony_ci		dev_err(dev, "Couldn't enable AHB clock\n");
39662306a36Sopenharmony_ci		goto out;
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	ret = clk_prepare_enable(sspi->mclk);
40062306a36Sopenharmony_ci	if (ret) {
40162306a36Sopenharmony_ci		dev_err(dev, "Couldn't enable module clock\n");
40262306a36Sopenharmony_ci		goto err;
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	sun4i_spi_write(sspi, SUN4I_CTL_REG,
40662306a36Sopenharmony_ci			SUN4I_CTL_ENABLE | SUN4I_CTL_MASTER | SUN4I_CTL_TP);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	return 0;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_cierr:
41162306a36Sopenharmony_ci	clk_disable_unprepare(sspi->hclk);
41262306a36Sopenharmony_ciout:
41362306a36Sopenharmony_ci	return ret;
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_cistatic int sun4i_spi_runtime_suspend(struct device *dev)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	struct spi_master *master = dev_get_drvdata(dev);
41962306a36Sopenharmony_ci	struct sun4i_spi *sspi = spi_master_get_devdata(master);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	clk_disable_unprepare(sspi->mclk);
42262306a36Sopenharmony_ci	clk_disable_unprepare(sspi->hclk);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	return 0;
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_cistatic int sun4i_spi_probe(struct platform_device *pdev)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	struct spi_master *master;
43062306a36Sopenharmony_ci	struct sun4i_spi *sspi;
43162306a36Sopenharmony_ci	int ret = 0, irq;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	master = spi_alloc_master(&pdev->dev, sizeof(struct sun4i_spi));
43462306a36Sopenharmony_ci	if (!master) {
43562306a36Sopenharmony_ci		dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
43662306a36Sopenharmony_ci		return -ENOMEM;
43762306a36Sopenharmony_ci	}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	platform_set_drvdata(pdev, master);
44062306a36Sopenharmony_ci	sspi = spi_master_get_devdata(master);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	sspi->base_addr = devm_platform_ioremap_resource(pdev, 0);
44362306a36Sopenharmony_ci	if (IS_ERR(sspi->base_addr)) {
44462306a36Sopenharmony_ci		ret = PTR_ERR(sspi->base_addr);
44562306a36Sopenharmony_ci		goto err_free_master;
44662306a36Sopenharmony_ci	}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
44962306a36Sopenharmony_ci	if (irq < 0) {
45062306a36Sopenharmony_ci		ret = -ENXIO;
45162306a36Sopenharmony_ci		goto err_free_master;
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	ret = devm_request_irq(&pdev->dev, irq, sun4i_spi_handler,
45562306a36Sopenharmony_ci			       0, "sun4i-spi", sspi);
45662306a36Sopenharmony_ci	if (ret) {
45762306a36Sopenharmony_ci		dev_err(&pdev->dev, "Cannot request IRQ\n");
45862306a36Sopenharmony_ci		goto err_free_master;
45962306a36Sopenharmony_ci	}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	sspi->master = master;
46262306a36Sopenharmony_ci	master->max_speed_hz = 100 * 1000 * 1000;
46362306a36Sopenharmony_ci	master->min_speed_hz = 3 * 1000;
46462306a36Sopenharmony_ci	master->set_cs = sun4i_spi_set_cs;
46562306a36Sopenharmony_ci	master->transfer_one = sun4i_spi_transfer_one;
46662306a36Sopenharmony_ci	master->num_chipselect = 4;
46762306a36Sopenharmony_ci	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
46862306a36Sopenharmony_ci	master->bits_per_word_mask = SPI_BPW_MASK(8);
46962306a36Sopenharmony_ci	master->dev.of_node = pdev->dev.of_node;
47062306a36Sopenharmony_ci	master->auto_runtime_pm = true;
47162306a36Sopenharmony_ci	master->max_transfer_size = sun4i_spi_max_transfer_size;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
47462306a36Sopenharmony_ci	if (IS_ERR(sspi->hclk)) {
47562306a36Sopenharmony_ci		dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
47662306a36Sopenharmony_ci		ret = PTR_ERR(sspi->hclk);
47762306a36Sopenharmony_ci		goto err_free_master;
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	sspi->mclk = devm_clk_get(&pdev->dev, "mod");
48162306a36Sopenharmony_ci	if (IS_ERR(sspi->mclk)) {
48262306a36Sopenharmony_ci		dev_err(&pdev->dev, "Unable to acquire module clock\n");
48362306a36Sopenharmony_ci		ret = PTR_ERR(sspi->mclk);
48462306a36Sopenharmony_ci		goto err_free_master;
48562306a36Sopenharmony_ci	}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	init_completion(&sspi->done);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	/*
49062306a36Sopenharmony_ci	 * This wake-up/shutdown pattern is to be able to have the
49162306a36Sopenharmony_ci	 * device woken up, even if runtime_pm is disabled
49262306a36Sopenharmony_ci	 */
49362306a36Sopenharmony_ci	ret = sun4i_spi_runtime_resume(&pdev->dev);
49462306a36Sopenharmony_ci	if (ret) {
49562306a36Sopenharmony_ci		dev_err(&pdev->dev, "Couldn't resume the device\n");
49662306a36Sopenharmony_ci		goto err_free_master;
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	pm_runtime_set_active(&pdev->dev);
50062306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
50162306a36Sopenharmony_ci	pm_runtime_idle(&pdev->dev);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	ret = devm_spi_register_master(&pdev->dev, master);
50462306a36Sopenharmony_ci	if (ret) {
50562306a36Sopenharmony_ci		dev_err(&pdev->dev, "cannot register SPI master\n");
50662306a36Sopenharmony_ci		goto err_pm_disable;
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	return 0;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cierr_pm_disable:
51262306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
51362306a36Sopenharmony_ci	sun4i_spi_runtime_suspend(&pdev->dev);
51462306a36Sopenharmony_cierr_free_master:
51562306a36Sopenharmony_ci	spi_master_put(master);
51662306a36Sopenharmony_ci	return ret;
51762306a36Sopenharmony_ci}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_cistatic void sun4i_spi_remove(struct platform_device *pdev)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	pm_runtime_force_suspend(&pdev->dev);
52262306a36Sopenharmony_ci}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_cistatic const struct of_device_id sun4i_spi_match[] = {
52562306a36Sopenharmony_ci	{ .compatible = "allwinner,sun4i-a10-spi", },
52662306a36Sopenharmony_ci	{}
52762306a36Sopenharmony_ci};
52862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sun4i_spi_match);
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cistatic const struct dev_pm_ops sun4i_spi_pm_ops = {
53162306a36Sopenharmony_ci	.runtime_resume		= sun4i_spi_runtime_resume,
53262306a36Sopenharmony_ci	.runtime_suspend	= sun4i_spi_runtime_suspend,
53362306a36Sopenharmony_ci};
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_cistatic struct platform_driver sun4i_spi_driver = {
53662306a36Sopenharmony_ci	.probe	= sun4i_spi_probe,
53762306a36Sopenharmony_ci	.remove_new = sun4i_spi_remove,
53862306a36Sopenharmony_ci	.driver	= {
53962306a36Sopenharmony_ci		.name		= "sun4i-spi",
54062306a36Sopenharmony_ci		.of_match_table	= sun4i_spi_match,
54162306a36Sopenharmony_ci		.pm		= &sun4i_spi_pm_ops,
54262306a36Sopenharmony_ci	},
54362306a36Sopenharmony_ci};
54462306a36Sopenharmony_cimodule_platform_driver(sun4i_spi_driver);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ciMODULE_AUTHOR("Pan Nan <pannan@allwinnertech.com>");
54762306a36Sopenharmony_ciMODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
54862306a36Sopenharmony_ciMODULE_DESCRIPTION("Allwinner A1X/A20 SPI controller driver");
54962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
550