162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci// Copyright (c) 2018 Nuvoton Technology corporation.
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/kernel.h>
562306a36Sopenharmony_ci#include <linux/bitfield.h>
662306a36Sopenharmony_ci#include <linux/bitops.h>
762306a36Sopenharmony_ci#include <linux/clk.h>
862306a36Sopenharmony_ci#include <linux/interrupt.h>
962306a36Sopenharmony_ci#include <linux/io.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/platform_device.h>
1262306a36Sopenharmony_ci#include <linux/spi/spi.h>
1362306a36Sopenharmony_ci#include <linux/reset.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <asm/unaligned.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <linux/regmap.h>
1862306a36Sopenharmony_ci#include <linux/mfd/syscon.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistruct npcm_pspi {
2162306a36Sopenharmony_ci	struct completion xfer_done;
2262306a36Sopenharmony_ci	struct reset_control *reset;
2362306a36Sopenharmony_ci	struct spi_master *master;
2462306a36Sopenharmony_ci	unsigned int tx_bytes;
2562306a36Sopenharmony_ci	unsigned int rx_bytes;
2662306a36Sopenharmony_ci	void __iomem *base;
2762306a36Sopenharmony_ci	bool is_save_param;
2862306a36Sopenharmony_ci	u8 bits_per_word;
2962306a36Sopenharmony_ci	const u8 *tx_buf;
3062306a36Sopenharmony_ci	struct clk *clk;
3162306a36Sopenharmony_ci	u32 speed_hz;
3262306a36Sopenharmony_ci	u8 *rx_buf;
3362306a36Sopenharmony_ci	u16 mode;
3462306a36Sopenharmony_ci	u32 id;
3562306a36Sopenharmony_ci};
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define DRIVER_NAME "npcm-pspi"
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define NPCM_PSPI_DATA		0x00
4062306a36Sopenharmony_ci#define NPCM_PSPI_CTL1		0x02
4162306a36Sopenharmony_ci#define NPCM_PSPI_STAT		0x04
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/* definitions for control and status register */
4462306a36Sopenharmony_ci#define NPCM_PSPI_CTL1_SPIEN	BIT(0)
4562306a36Sopenharmony_ci#define NPCM_PSPI_CTL1_MOD	BIT(2)
4662306a36Sopenharmony_ci#define NPCM_PSPI_CTL1_EIR	BIT(5)
4762306a36Sopenharmony_ci#define NPCM_PSPI_CTL1_EIW	BIT(6)
4862306a36Sopenharmony_ci#define NPCM_PSPI_CTL1_SCM	BIT(7)
4962306a36Sopenharmony_ci#define NPCM_PSPI_CTL1_SCIDL	BIT(8)
5062306a36Sopenharmony_ci#define NPCM_PSPI_CTL1_SCDV6_0	GENMASK(15, 9)
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define NPCM_PSPI_STAT_BSY	BIT(0)
5362306a36Sopenharmony_ci#define NPCM_PSPI_STAT_RBF	BIT(1)
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/* general definitions */
5662306a36Sopenharmony_ci#define NPCM_PSPI_TIMEOUT_MS		2000
5762306a36Sopenharmony_ci#define NPCM_PSPI_MAX_CLK_DIVIDER	256
5862306a36Sopenharmony_ci#define NPCM_PSPI_MIN_CLK_DIVIDER	4
5962306a36Sopenharmony_ci#define NPCM_PSPI_DEFAULT_CLK		25000000
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic inline unsigned int bytes_per_word(unsigned int bits)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	return bits <= 8 ? 1 : 2;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic inline void npcm_pspi_irq_enable(struct npcm_pspi *priv, u16 mask)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	u16 val;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	val = ioread16(priv->base + NPCM_PSPI_CTL1);
7162306a36Sopenharmony_ci	val |= mask;
7262306a36Sopenharmony_ci	iowrite16(val, priv->base + NPCM_PSPI_CTL1);
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic inline void npcm_pspi_irq_disable(struct npcm_pspi *priv, u16 mask)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	u16 val;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	val = ioread16(priv->base + NPCM_PSPI_CTL1);
8062306a36Sopenharmony_ci	val &= ~mask;
8162306a36Sopenharmony_ci	iowrite16(val, priv->base + NPCM_PSPI_CTL1);
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic inline void npcm_pspi_enable(struct npcm_pspi *priv)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	u16 val;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	val = ioread16(priv->base + NPCM_PSPI_CTL1);
8962306a36Sopenharmony_ci	val |= NPCM_PSPI_CTL1_SPIEN;
9062306a36Sopenharmony_ci	iowrite16(val, priv->base + NPCM_PSPI_CTL1);
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic inline void npcm_pspi_disable(struct npcm_pspi *priv)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	u16 val;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	val = ioread16(priv->base + NPCM_PSPI_CTL1);
9862306a36Sopenharmony_ci	val &= ~NPCM_PSPI_CTL1_SPIEN;
9962306a36Sopenharmony_ci	iowrite16(val, priv->base + NPCM_PSPI_CTL1);
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic void npcm_pspi_set_mode(struct spi_device *spi)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	struct npcm_pspi *priv = spi_master_get_devdata(spi->master);
10562306a36Sopenharmony_ci	u16 regtemp;
10662306a36Sopenharmony_ci	u16 mode_val;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	switch (spi->mode & SPI_MODE_X_MASK) {
10962306a36Sopenharmony_ci	case SPI_MODE_0:
11062306a36Sopenharmony_ci		mode_val = 0;
11162306a36Sopenharmony_ci		break;
11262306a36Sopenharmony_ci	case SPI_MODE_1:
11362306a36Sopenharmony_ci		mode_val = NPCM_PSPI_CTL1_SCIDL;
11462306a36Sopenharmony_ci		break;
11562306a36Sopenharmony_ci	case SPI_MODE_2:
11662306a36Sopenharmony_ci		mode_val = NPCM_PSPI_CTL1_SCM;
11762306a36Sopenharmony_ci		break;
11862306a36Sopenharmony_ci	case SPI_MODE_3:
11962306a36Sopenharmony_ci		mode_val = NPCM_PSPI_CTL1_SCIDL | NPCM_PSPI_CTL1_SCM;
12062306a36Sopenharmony_ci		break;
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	regtemp = ioread16(priv->base + NPCM_PSPI_CTL1);
12462306a36Sopenharmony_ci	regtemp &= ~(NPCM_PSPI_CTL1_SCM | NPCM_PSPI_CTL1_SCIDL);
12562306a36Sopenharmony_ci	iowrite16(regtemp | mode_val, priv->base + NPCM_PSPI_CTL1);
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic void npcm_pspi_set_transfer_size(struct npcm_pspi *priv, int size)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	u16 regtemp;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	regtemp = ioread16(NPCM_PSPI_CTL1 + priv->base);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	switch (size) {
13562306a36Sopenharmony_ci	case 8:
13662306a36Sopenharmony_ci		regtemp &= ~NPCM_PSPI_CTL1_MOD;
13762306a36Sopenharmony_ci		break;
13862306a36Sopenharmony_ci	case 16:
13962306a36Sopenharmony_ci		regtemp |= NPCM_PSPI_CTL1_MOD;
14062306a36Sopenharmony_ci		break;
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	iowrite16(regtemp, NPCM_PSPI_CTL1 + priv->base);
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic void npcm_pspi_set_baudrate(struct npcm_pspi *priv, unsigned int speed)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	u32 ckdiv;
14962306a36Sopenharmony_ci	u16 regtemp;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	/* the supported rates are numbers from 4 to 256. */
15262306a36Sopenharmony_ci	ckdiv = DIV_ROUND_CLOSEST(clk_get_rate(priv->clk), (2 * speed)) - 1;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	regtemp = ioread16(NPCM_PSPI_CTL1 + priv->base);
15562306a36Sopenharmony_ci	regtemp &= ~NPCM_PSPI_CTL1_SCDV6_0;
15662306a36Sopenharmony_ci	iowrite16(regtemp | (ckdiv << 9), NPCM_PSPI_CTL1 + priv->base);
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic void npcm_pspi_setup_transfer(struct spi_device *spi,
16062306a36Sopenharmony_ci				     struct spi_transfer *t)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	struct npcm_pspi *priv = spi_master_get_devdata(spi->master);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	priv->tx_buf = t->tx_buf;
16562306a36Sopenharmony_ci	priv->rx_buf = t->rx_buf;
16662306a36Sopenharmony_ci	priv->tx_bytes = t->len;
16762306a36Sopenharmony_ci	priv->rx_bytes = t->len;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	if (!priv->is_save_param || priv->mode != spi->mode) {
17062306a36Sopenharmony_ci		npcm_pspi_set_mode(spi);
17162306a36Sopenharmony_ci		priv->mode = spi->mode;
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	/*
17562306a36Sopenharmony_ci	 * If transfer is even length, and 8 bits per word transfer,
17662306a36Sopenharmony_ci	 * then implement 16 bits-per-word transfer.
17762306a36Sopenharmony_ci	 */
17862306a36Sopenharmony_ci	if (priv->bits_per_word == 8 && !(t->len & 0x1))
17962306a36Sopenharmony_ci		t->bits_per_word = 16;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if (!priv->is_save_param || priv->bits_per_word != t->bits_per_word) {
18262306a36Sopenharmony_ci		npcm_pspi_set_transfer_size(priv, t->bits_per_word);
18362306a36Sopenharmony_ci		priv->bits_per_word = t->bits_per_word;
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (!priv->is_save_param || priv->speed_hz != t->speed_hz) {
18762306a36Sopenharmony_ci		npcm_pspi_set_baudrate(priv, t->speed_hz);
18862306a36Sopenharmony_ci		priv->speed_hz = t->speed_hz;
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	if (!priv->is_save_param)
19262306a36Sopenharmony_ci		priv->is_save_param = true;
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic void npcm_pspi_send(struct npcm_pspi *priv)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	int wsize;
19862306a36Sopenharmony_ci	u16 val;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	wsize = min(bytes_per_word(priv->bits_per_word), priv->tx_bytes);
20162306a36Sopenharmony_ci	priv->tx_bytes -= wsize;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	if (!priv->tx_buf)
20462306a36Sopenharmony_ci		return;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	switch (wsize) {
20762306a36Sopenharmony_ci	case 1:
20862306a36Sopenharmony_ci		val = *priv->tx_buf++;
20962306a36Sopenharmony_ci		iowrite8(val, NPCM_PSPI_DATA + priv->base);
21062306a36Sopenharmony_ci		break;
21162306a36Sopenharmony_ci	case 2:
21262306a36Sopenharmony_ci		val = *priv->tx_buf++;
21362306a36Sopenharmony_ci		val = *priv->tx_buf++ | (val << 8);
21462306a36Sopenharmony_ci		iowrite16(val, NPCM_PSPI_DATA + priv->base);
21562306a36Sopenharmony_ci		break;
21662306a36Sopenharmony_ci	default:
21762306a36Sopenharmony_ci		WARN_ON_ONCE(1);
21862306a36Sopenharmony_ci		return;
21962306a36Sopenharmony_ci	}
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistatic void npcm_pspi_recv(struct npcm_pspi *priv)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	int rsize;
22562306a36Sopenharmony_ci	u16 val;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	rsize = min(bytes_per_word(priv->bits_per_word), priv->rx_bytes);
22862306a36Sopenharmony_ci	priv->rx_bytes -= rsize;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	if (!priv->rx_buf)
23162306a36Sopenharmony_ci		return;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	switch (rsize) {
23462306a36Sopenharmony_ci	case 1:
23562306a36Sopenharmony_ci		*priv->rx_buf++ = ioread8(priv->base + NPCM_PSPI_DATA);
23662306a36Sopenharmony_ci		break;
23762306a36Sopenharmony_ci	case 2:
23862306a36Sopenharmony_ci		val = ioread16(priv->base + NPCM_PSPI_DATA);
23962306a36Sopenharmony_ci		*priv->rx_buf++ = (val >> 8);
24062306a36Sopenharmony_ci		*priv->rx_buf++ = val & 0xff;
24162306a36Sopenharmony_ci		break;
24262306a36Sopenharmony_ci	default:
24362306a36Sopenharmony_ci		WARN_ON_ONCE(1);
24462306a36Sopenharmony_ci		return;
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic int npcm_pspi_transfer_one(struct spi_master *master,
24962306a36Sopenharmony_ci				  struct spi_device *spi,
25062306a36Sopenharmony_ci				  struct spi_transfer *t)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	struct npcm_pspi *priv = spi_master_get_devdata(master);
25362306a36Sopenharmony_ci	int status;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	npcm_pspi_setup_transfer(spi, t);
25662306a36Sopenharmony_ci	reinit_completion(&priv->xfer_done);
25762306a36Sopenharmony_ci	npcm_pspi_enable(priv);
25862306a36Sopenharmony_ci	status = wait_for_completion_timeout(&priv->xfer_done,
25962306a36Sopenharmony_ci					     msecs_to_jiffies
26062306a36Sopenharmony_ci					     (NPCM_PSPI_TIMEOUT_MS));
26162306a36Sopenharmony_ci	if (status == 0) {
26262306a36Sopenharmony_ci		npcm_pspi_disable(priv);
26362306a36Sopenharmony_ci		return -ETIMEDOUT;
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	return 0;
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic int npcm_pspi_prepare_transfer_hardware(struct spi_master *master)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	struct npcm_pspi *priv = spi_master_get_devdata(master);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	npcm_pspi_irq_enable(priv, NPCM_PSPI_CTL1_EIR | NPCM_PSPI_CTL1_EIW);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	return 0;
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_cistatic int npcm_pspi_unprepare_transfer_hardware(struct spi_master *master)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	struct npcm_pspi *priv = spi_master_get_devdata(master);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	npcm_pspi_irq_disable(priv, NPCM_PSPI_CTL1_EIR | NPCM_PSPI_CTL1_EIW);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	return 0;
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic void npcm_pspi_reset_hw(struct npcm_pspi *priv)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci	reset_control_assert(priv->reset);
29062306a36Sopenharmony_ci	udelay(5);
29162306a36Sopenharmony_ci	reset_control_deassert(priv->reset);
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic irqreturn_t npcm_pspi_handler(int irq, void *dev_id)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	struct npcm_pspi *priv = dev_id;
29762306a36Sopenharmony_ci	u8 stat;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	stat = ioread8(priv->base + NPCM_PSPI_STAT);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (!priv->tx_buf && !priv->rx_buf)
30262306a36Sopenharmony_ci		return IRQ_NONE;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (priv->tx_buf) {
30562306a36Sopenharmony_ci		if (stat & NPCM_PSPI_STAT_RBF) {
30662306a36Sopenharmony_ci			ioread8(NPCM_PSPI_DATA + priv->base);
30762306a36Sopenharmony_ci			if (priv->tx_bytes == 0) {
30862306a36Sopenharmony_ci				npcm_pspi_disable(priv);
30962306a36Sopenharmony_ci				complete(&priv->xfer_done);
31062306a36Sopenharmony_ci				return IRQ_HANDLED;
31162306a36Sopenharmony_ci			}
31262306a36Sopenharmony_ci		}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci		if ((stat & NPCM_PSPI_STAT_BSY) == 0)
31562306a36Sopenharmony_ci			if (priv->tx_bytes)
31662306a36Sopenharmony_ci				npcm_pspi_send(priv);
31762306a36Sopenharmony_ci	}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	if (priv->rx_buf) {
32062306a36Sopenharmony_ci		if (stat & NPCM_PSPI_STAT_RBF) {
32162306a36Sopenharmony_ci			if (!priv->rx_bytes)
32262306a36Sopenharmony_ci				return IRQ_NONE;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci			npcm_pspi_recv(priv);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci			if (!priv->rx_bytes) {
32762306a36Sopenharmony_ci				npcm_pspi_disable(priv);
32862306a36Sopenharmony_ci				complete(&priv->xfer_done);
32962306a36Sopenharmony_ci				return IRQ_HANDLED;
33062306a36Sopenharmony_ci			}
33162306a36Sopenharmony_ci		}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci		if (((stat & NPCM_PSPI_STAT_BSY) == 0) && !priv->tx_buf)
33462306a36Sopenharmony_ci			iowrite8(0x0, NPCM_PSPI_DATA + priv->base);
33562306a36Sopenharmony_ci	}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	return IRQ_HANDLED;
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic int npcm_pspi_probe(struct platform_device *pdev)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	struct npcm_pspi *priv;
34362306a36Sopenharmony_ci	struct spi_master *master;
34462306a36Sopenharmony_ci	unsigned long clk_hz;
34562306a36Sopenharmony_ci	int irq;
34662306a36Sopenharmony_ci	int ret;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	master = spi_alloc_master(&pdev->dev, sizeof(*priv));
34962306a36Sopenharmony_ci	if (!master)
35062306a36Sopenharmony_ci		return -ENOMEM;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	platform_set_drvdata(pdev, master);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	priv = spi_master_get_devdata(master);
35562306a36Sopenharmony_ci	priv->master = master;
35662306a36Sopenharmony_ci	priv->is_save_param = false;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	priv->base = devm_platform_ioremap_resource(pdev, 0);
35962306a36Sopenharmony_ci	if (IS_ERR(priv->base)) {
36062306a36Sopenharmony_ci		ret = PTR_ERR(priv->base);
36162306a36Sopenharmony_ci		goto out_master_put;
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	priv->clk = devm_clk_get(&pdev->dev, NULL);
36562306a36Sopenharmony_ci	if (IS_ERR(priv->clk)) {
36662306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to get clock\n");
36762306a36Sopenharmony_ci		ret = PTR_ERR(priv->clk);
36862306a36Sopenharmony_ci		goto out_master_put;
36962306a36Sopenharmony_ci	}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	ret = clk_prepare_enable(priv->clk);
37262306a36Sopenharmony_ci	if (ret)
37362306a36Sopenharmony_ci		goto out_master_put;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
37662306a36Sopenharmony_ci	if (irq < 0) {
37762306a36Sopenharmony_ci		ret = irq;
37862306a36Sopenharmony_ci		goto out_disable_clk;
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	priv->reset = devm_reset_control_get(&pdev->dev, NULL);
38262306a36Sopenharmony_ci	if (IS_ERR(priv->reset)) {
38362306a36Sopenharmony_ci		ret = PTR_ERR(priv->reset);
38462306a36Sopenharmony_ci		goto out_disable_clk;
38562306a36Sopenharmony_ci	}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	/* reset SPI-HW block */
38862306a36Sopenharmony_ci	npcm_pspi_reset_hw(priv);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	ret = devm_request_irq(&pdev->dev, irq, npcm_pspi_handler, 0,
39162306a36Sopenharmony_ci			       "npcm-pspi", priv);
39262306a36Sopenharmony_ci	if (ret) {
39362306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to request IRQ\n");
39462306a36Sopenharmony_ci		goto out_disable_clk;
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	init_completion(&priv->xfer_done);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	clk_hz = clk_get_rate(priv->clk);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	master->max_speed_hz = DIV_ROUND_UP(clk_hz, NPCM_PSPI_MIN_CLK_DIVIDER);
40262306a36Sopenharmony_ci	master->min_speed_hz = DIV_ROUND_UP(clk_hz, NPCM_PSPI_MAX_CLK_DIVIDER);
40362306a36Sopenharmony_ci	master->mode_bits = SPI_CPHA | SPI_CPOL;
40462306a36Sopenharmony_ci	master->dev.of_node = pdev->dev.of_node;
40562306a36Sopenharmony_ci	master->bus_num = -1;
40662306a36Sopenharmony_ci	master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
40762306a36Sopenharmony_ci	master->transfer_one = npcm_pspi_transfer_one;
40862306a36Sopenharmony_ci	master->prepare_transfer_hardware =
40962306a36Sopenharmony_ci		npcm_pspi_prepare_transfer_hardware;
41062306a36Sopenharmony_ci	master->unprepare_transfer_hardware =
41162306a36Sopenharmony_ci		npcm_pspi_unprepare_transfer_hardware;
41262306a36Sopenharmony_ci	master->use_gpio_descriptors = true;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	/* set to default clock rate */
41562306a36Sopenharmony_ci	npcm_pspi_set_baudrate(priv, NPCM_PSPI_DEFAULT_CLK);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	ret = devm_spi_register_master(&pdev->dev, master);
41862306a36Sopenharmony_ci	if (ret)
41962306a36Sopenharmony_ci		goto out_disable_clk;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	pr_info("NPCM Peripheral SPI %d probed\n", master->bus_num);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	return 0;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ciout_disable_clk:
42662306a36Sopenharmony_ci	clk_disable_unprepare(priv->clk);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ciout_master_put:
42962306a36Sopenharmony_ci	spi_master_put(master);
43062306a36Sopenharmony_ci	return ret;
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_cistatic void npcm_pspi_remove(struct platform_device *pdev)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	struct spi_master *master = platform_get_drvdata(pdev);
43662306a36Sopenharmony_ci	struct npcm_pspi *priv = spi_master_get_devdata(master);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	npcm_pspi_reset_hw(priv);
43962306a36Sopenharmony_ci	clk_disable_unprepare(priv->clk);
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_cistatic const struct of_device_id npcm_pspi_match[] = {
44362306a36Sopenharmony_ci	{ .compatible = "nuvoton,npcm750-pspi", .data = NULL },
44462306a36Sopenharmony_ci	{ .compatible = "nuvoton,npcm845-pspi", .data = NULL },
44562306a36Sopenharmony_ci	{}
44662306a36Sopenharmony_ci};
44762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, npcm_pspi_match);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_cistatic struct platform_driver npcm_pspi_driver = {
45062306a36Sopenharmony_ci	.driver		= {
45162306a36Sopenharmony_ci		.name		= DRIVER_NAME,
45262306a36Sopenharmony_ci		.of_match_table	= npcm_pspi_match,
45362306a36Sopenharmony_ci	},
45462306a36Sopenharmony_ci	.probe		= npcm_pspi_probe,
45562306a36Sopenharmony_ci	.remove_new	= npcm_pspi_remove,
45662306a36Sopenharmony_ci};
45762306a36Sopenharmony_cimodule_platform_driver(npcm_pspi_driver);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ciMODULE_DESCRIPTION("NPCM peripheral SPI Controller driver");
46062306a36Sopenharmony_ciMODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
46162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
46262306a36Sopenharmony_ci
463