xref: /openbmc/linux/drivers/spi/spi-npcm-pspi.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
12a22f1b3STomer Maimon // SPDX-License-Identifier: GPL-2.0
22a22f1b3STomer Maimon // Copyright (c) 2018 Nuvoton Technology corporation.
32a22f1b3STomer Maimon 
42a22f1b3STomer Maimon #include <linux/kernel.h>
52a22f1b3STomer Maimon #include <linux/bitfield.h>
62a22f1b3STomer Maimon #include <linux/bitops.h>
72a22f1b3STomer Maimon #include <linux/clk.h>
82a22f1b3STomer Maimon #include <linux/interrupt.h>
92a22f1b3STomer Maimon #include <linux/io.h>
102a22f1b3STomer Maimon #include <linux/module.h>
112a22f1b3STomer Maimon #include <linux/platform_device.h>
122a22f1b3STomer Maimon #include <linux/spi/spi.h>
13b5df0b2eSTomer Maimon #include <linux/reset.h>
142a22f1b3STomer Maimon 
152a22f1b3STomer Maimon #include <asm/unaligned.h>
162a22f1b3STomer Maimon 
172a22f1b3STomer Maimon #include <linux/regmap.h>
182a22f1b3STomer Maimon #include <linux/mfd/syscon.h>
192a22f1b3STomer Maimon 
202a22f1b3STomer Maimon struct npcm_pspi {
212a22f1b3STomer Maimon 	struct completion xfer_done;
22b5df0b2eSTomer Maimon 	struct reset_control *reset;
232a22f1b3STomer Maimon 	struct spi_master *master;
242a22f1b3STomer Maimon 	unsigned int tx_bytes;
252a22f1b3STomer Maimon 	unsigned int rx_bytes;
262a22f1b3STomer Maimon 	void __iomem *base;
272a22f1b3STomer Maimon 	bool is_save_param;
282a22f1b3STomer Maimon 	u8 bits_per_word;
292a22f1b3STomer Maimon 	const u8 *tx_buf;
302a22f1b3STomer Maimon 	struct clk *clk;
312a22f1b3STomer Maimon 	u32 speed_hz;
322a22f1b3STomer Maimon 	u8 *rx_buf;
332a22f1b3STomer Maimon 	u16 mode;
342a22f1b3STomer Maimon 	u32 id;
352a22f1b3STomer Maimon };
362a22f1b3STomer Maimon 
372a22f1b3STomer Maimon #define DRIVER_NAME "npcm-pspi"
382a22f1b3STomer Maimon 
392a22f1b3STomer Maimon #define NPCM_PSPI_DATA		0x00
402a22f1b3STomer Maimon #define NPCM_PSPI_CTL1		0x02
412a22f1b3STomer Maimon #define NPCM_PSPI_STAT		0x04
422a22f1b3STomer Maimon 
432a22f1b3STomer Maimon /* definitions for control and status register */
442a22f1b3STomer Maimon #define NPCM_PSPI_CTL1_SPIEN	BIT(0)
452a22f1b3STomer Maimon #define NPCM_PSPI_CTL1_MOD	BIT(2)
462a22f1b3STomer Maimon #define NPCM_PSPI_CTL1_EIR	BIT(5)
472a22f1b3STomer Maimon #define NPCM_PSPI_CTL1_EIW	BIT(6)
482a22f1b3STomer Maimon #define NPCM_PSPI_CTL1_SCM	BIT(7)
492a22f1b3STomer Maimon #define NPCM_PSPI_CTL1_SCIDL	BIT(8)
502a22f1b3STomer Maimon #define NPCM_PSPI_CTL1_SCDV6_0	GENMASK(15, 9)
512a22f1b3STomer Maimon 
522a22f1b3STomer Maimon #define NPCM_PSPI_STAT_BSY	BIT(0)
532a22f1b3STomer Maimon #define NPCM_PSPI_STAT_RBF	BIT(1)
542a22f1b3STomer Maimon 
552a22f1b3STomer Maimon /* general definitions */
562a22f1b3STomer Maimon #define NPCM_PSPI_TIMEOUT_MS		2000
572a22f1b3STomer Maimon #define NPCM_PSPI_MAX_CLK_DIVIDER	256
582a22f1b3STomer Maimon #define NPCM_PSPI_MIN_CLK_DIVIDER	4
592a22f1b3STomer Maimon #define NPCM_PSPI_DEFAULT_CLK		25000000
602a22f1b3STomer Maimon 
bytes_per_word(unsigned int bits)612a22f1b3STomer Maimon static inline unsigned int bytes_per_word(unsigned int bits)
622a22f1b3STomer Maimon {
632a22f1b3STomer Maimon 	return bits <= 8 ? 1 : 2;
642a22f1b3STomer Maimon }
652a22f1b3STomer Maimon 
npcm_pspi_irq_enable(struct npcm_pspi * priv,u16 mask)662a22f1b3STomer Maimon static inline void npcm_pspi_irq_enable(struct npcm_pspi *priv, u16 mask)
672a22f1b3STomer Maimon {
682a22f1b3STomer Maimon 	u16 val;
692a22f1b3STomer Maimon 
702a22f1b3STomer Maimon 	val = ioread16(priv->base + NPCM_PSPI_CTL1);
712a22f1b3STomer Maimon 	val |= mask;
722a22f1b3STomer Maimon 	iowrite16(val, priv->base + NPCM_PSPI_CTL1);
732a22f1b3STomer Maimon }
742a22f1b3STomer Maimon 
npcm_pspi_irq_disable(struct npcm_pspi * priv,u16 mask)752a22f1b3STomer Maimon static inline void npcm_pspi_irq_disable(struct npcm_pspi *priv, u16 mask)
762a22f1b3STomer Maimon {
772a22f1b3STomer Maimon 	u16 val;
782a22f1b3STomer Maimon 
792a22f1b3STomer Maimon 	val = ioread16(priv->base + NPCM_PSPI_CTL1);
802a22f1b3STomer Maimon 	val &= ~mask;
812a22f1b3STomer Maimon 	iowrite16(val, priv->base + NPCM_PSPI_CTL1);
822a22f1b3STomer Maimon }
832a22f1b3STomer Maimon 
npcm_pspi_enable(struct npcm_pspi * priv)842a22f1b3STomer Maimon static inline void npcm_pspi_enable(struct npcm_pspi *priv)
852a22f1b3STomer Maimon {
862a22f1b3STomer Maimon 	u16 val;
872a22f1b3STomer Maimon 
882a22f1b3STomer Maimon 	val = ioread16(priv->base + NPCM_PSPI_CTL1);
892a22f1b3STomer Maimon 	val |= NPCM_PSPI_CTL1_SPIEN;
902a22f1b3STomer Maimon 	iowrite16(val, priv->base + NPCM_PSPI_CTL1);
912a22f1b3STomer Maimon }
922a22f1b3STomer Maimon 
npcm_pspi_disable(struct npcm_pspi * priv)932a22f1b3STomer Maimon static inline void npcm_pspi_disable(struct npcm_pspi *priv)
942a22f1b3STomer Maimon {
952a22f1b3STomer Maimon 	u16 val;
962a22f1b3STomer Maimon 
972a22f1b3STomer Maimon 	val = ioread16(priv->base + NPCM_PSPI_CTL1);
982a22f1b3STomer Maimon 	val &= ~NPCM_PSPI_CTL1_SPIEN;
992a22f1b3STomer Maimon 	iowrite16(val, priv->base + NPCM_PSPI_CTL1);
1002a22f1b3STomer Maimon }
1012a22f1b3STomer Maimon 
npcm_pspi_set_mode(struct spi_device * spi)1022a22f1b3STomer Maimon static void npcm_pspi_set_mode(struct spi_device *spi)
1032a22f1b3STomer Maimon {
1042a22f1b3STomer Maimon 	struct npcm_pspi *priv = spi_master_get_devdata(spi->master);
1052a22f1b3STomer Maimon 	u16 regtemp;
1062a22f1b3STomer Maimon 	u16 mode_val;
1072a22f1b3STomer Maimon 
10856f47edfSAndy Shevchenko 	switch (spi->mode & SPI_MODE_X_MASK) {
1092a22f1b3STomer Maimon 	case SPI_MODE_0:
1102a22f1b3STomer Maimon 		mode_val = 0;
1112a22f1b3STomer Maimon 		break;
1122a22f1b3STomer Maimon 	case SPI_MODE_1:
1132a22f1b3STomer Maimon 		mode_val = NPCM_PSPI_CTL1_SCIDL;
1142a22f1b3STomer Maimon 		break;
1152a22f1b3STomer Maimon 	case SPI_MODE_2:
1162a22f1b3STomer Maimon 		mode_val = NPCM_PSPI_CTL1_SCM;
1172a22f1b3STomer Maimon 		break;
1182a22f1b3STomer Maimon 	case SPI_MODE_3:
1192a22f1b3STomer Maimon 		mode_val = NPCM_PSPI_CTL1_SCIDL | NPCM_PSPI_CTL1_SCM;
1202a22f1b3STomer Maimon 		break;
1212a22f1b3STomer Maimon 	}
1222a22f1b3STomer Maimon 
1232a22f1b3STomer Maimon 	regtemp = ioread16(priv->base + NPCM_PSPI_CTL1);
1242a22f1b3STomer Maimon 	regtemp &= ~(NPCM_PSPI_CTL1_SCM | NPCM_PSPI_CTL1_SCIDL);
1252a22f1b3STomer Maimon 	iowrite16(regtemp | mode_val, priv->base + NPCM_PSPI_CTL1);
1262a22f1b3STomer Maimon }
1272a22f1b3STomer Maimon 
npcm_pspi_set_transfer_size(struct npcm_pspi * priv,int size)1282a22f1b3STomer Maimon static void npcm_pspi_set_transfer_size(struct npcm_pspi *priv, int size)
1292a22f1b3STomer Maimon {
1302a22f1b3STomer Maimon 	u16 regtemp;
1312a22f1b3STomer Maimon 
1322a22f1b3STomer Maimon 	regtemp = ioread16(NPCM_PSPI_CTL1 + priv->base);
1332a22f1b3STomer Maimon 
1342a22f1b3STomer Maimon 	switch (size) {
1352a22f1b3STomer Maimon 	case 8:
1362a22f1b3STomer Maimon 		regtemp &= ~NPCM_PSPI_CTL1_MOD;
1372a22f1b3STomer Maimon 		break;
1382a22f1b3STomer Maimon 	case 16:
1392a22f1b3STomer Maimon 		regtemp |= NPCM_PSPI_CTL1_MOD;
1402a22f1b3STomer Maimon 		break;
1412a22f1b3STomer Maimon 	}
1422a22f1b3STomer Maimon 
1432a22f1b3STomer Maimon 	iowrite16(regtemp, NPCM_PSPI_CTL1 + priv->base);
1442a22f1b3STomer Maimon }
1452a22f1b3STomer Maimon 
npcm_pspi_set_baudrate(struct npcm_pspi * priv,unsigned int speed)1462a22f1b3STomer Maimon static void npcm_pspi_set_baudrate(struct npcm_pspi *priv, unsigned int speed)
1472a22f1b3STomer Maimon {
1482a22f1b3STomer Maimon 	u32 ckdiv;
1492a22f1b3STomer Maimon 	u16 regtemp;
1502a22f1b3STomer Maimon 
1512a22f1b3STomer Maimon 	/* the supported rates are numbers from 4 to 256. */
1522a22f1b3STomer Maimon 	ckdiv = DIV_ROUND_CLOSEST(clk_get_rate(priv->clk), (2 * speed)) - 1;
1532a22f1b3STomer Maimon 
1542a22f1b3STomer Maimon 	regtemp = ioread16(NPCM_PSPI_CTL1 + priv->base);
1552a22f1b3STomer Maimon 	regtemp &= ~NPCM_PSPI_CTL1_SCDV6_0;
1562a22f1b3STomer Maimon 	iowrite16(regtemp | (ckdiv << 9), NPCM_PSPI_CTL1 + priv->base);
1572a22f1b3STomer Maimon }
1582a22f1b3STomer Maimon 
npcm_pspi_setup_transfer(struct spi_device * spi,struct spi_transfer * t)1592a22f1b3STomer Maimon static void npcm_pspi_setup_transfer(struct spi_device *spi,
1602a22f1b3STomer Maimon 				     struct spi_transfer *t)
1612a22f1b3STomer Maimon {
1622a22f1b3STomer Maimon 	struct npcm_pspi *priv = spi_master_get_devdata(spi->master);
1632a22f1b3STomer Maimon 
1642a22f1b3STomer Maimon 	priv->tx_buf = t->tx_buf;
1652a22f1b3STomer Maimon 	priv->rx_buf = t->rx_buf;
1662a22f1b3STomer Maimon 	priv->tx_bytes = t->len;
1672a22f1b3STomer Maimon 	priv->rx_bytes = t->len;
1682a22f1b3STomer Maimon 
1692a22f1b3STomer Maimon 	if (!priv->is_save_param || priv->mode != spi->mode) {
1702a22f1b3STomer Maimon 		npcm_pspi_set_mode(spi);
1712a22f1b3STomer Maimon 		priv->mode = spi->mode;
1722a22f1b3STomer Maimon 	}
1732a22f1b3STomer Maimon 
174b4adf5b2STomer Maimon 	/*
175b4adf5b2STomer Maimon 	 * If transfer is even length, and 8 bits per word transfer,
176b4adf5b2STomer Maimon 	 * then implement 16 bits-per-word transfer.
177b4adf5b2STomer Maimon 	 */
178b4adf5b2STomer Maimon 	if (priv->bits_per_word == 8 && !(t->len & 0x1))
179b4adf5b2STomer Maimon 		t->bits_per_word = 16;
180b4adf5b2STomer Maimon 
1812a22f1b3STomer Maimon 	if (!priv->is_save_param || priv->bits_per_word != t->bits_per_word) {
1822a22f1b3STomer Maimon 		npcm_pspi_set_transfer_size(priv, t->bits_per_word);
1832a22f1b3STomer Maimon 		priv->bits_per_word = t->bits_per_word;
1842a22f1b3STomer Maimon 	}
1852a22f1b3STomer Maimon 
1862a22f1b3STomer Maimon 	if (!priv->is_save_param || priv->speed_hz != t->speed_hz) {
1872a22f1b3STomer Maimon 		npcm_pspi_set_baudrate(priv, t->speed_hz);
1882a22f1b3STomer Maimon 		priv->speed_hz = t->speed_hz;
1892a22f1b3STomer Maimon 	}
1902a22f1b3STomer Maimon 
1912a22f1b3STomer Maimon 	if (!priv->is_save_param)
1922a22f1b3STomer Maimon 		priv->is_save_param = true;
1932a22f1b3STomer Maimon }
1942a22f1b3STomer Maimon 
npcm_pspi_send(struct npcm_pspi * priv)1952a22f1b3STomer Maimon static void npcm_pspi_send(struct npcm_pspi *priv)
1962a22f1b3STomer Maimon {
1972a22f1b3STomer Maimon 	int wsize;
19847416a5fSTomer Maimon 	u16 val;
1992a22f1b3STomer Maimon 
2002a22f1b3STomer Maimon 	wsize = min(bytes_per_word(priv->bits_per_word), priv->tx_bytes);
2012a22f1b3STomer Maimon 	priv->tx_bytes -= wsize;
2022a22f1b3STomer Maimon 
2031fa33be3STomer Maimon 	if (!priv->tx_buf)
2041fa33be3STomer Maimon 		return;
2051fa33be3STomer Maimon 
2061fa33be3STomer Maimon 	switch (wsize) {
2071fa33be3STomer Maimon 	case 1:
20847416a5fSTomer Maimon 		val = *priv->tx_buf++;
20947416a5fSTomer Maimon 		iowrite8(val, NPCM_PSPI_DATA + priv->base);
2101fa33be3STomer Maimon 		break;
2111fa33be3STomer Maimon 	case 2:
21247416a5fSTomer Maimon 		val = *priv->tx_buf++;
21347416a5fSTomer Maimon 		val = *priv->tx_buf++ | (val << 8);
21447416a5fSTomer Maimon 		iowrite16(val, NPCM_PSPI_DATA + priv->base);
2151fa33be3STomer Maimon 		break;
2161fa33be3STomer Maimon 	default:
2171fa33be3STomer Maimon 		WARN_ON_ONCE(1);
2181fa33be3STomer Maimon 		return;
2191fa33be3STomer Maimon 	}
2202a22f1b3STomer Maimon }
2212a22f1b3STomer Maimon 
npcm_pspi_recv(struct npcm_pspi * priv)2222a22f1b3STomer Maimon static void npcm_pspi_recv(struct npcm_pspi *priv)
2232a22f1b3STomer Maimon {
2242a22f1b3STomer Maimon 	int rsize;
2252a22f1b3STomer Maimon 	u16 val;
2262a22f1b3STomer Maimon 
2272a22f1b3STomer Maimon 	rsize = min(bytes_per_word(priv->bits_per_word), priv->rx_bytes);
2282a22f1b3STomer Maimon 	priv->rx_bytes -= rsize;
2292a22f1b3STomer Maimon 
2301d2319efSOlof Johansson 	if (!priv->rx_buf)
2311d2319efSOlof Johansson 		return;
2321d2319efSOlof Johansson 
2331d2319efSOlof Johansson 	switch (rsize) {
2341d2319efSOlof Johansson 	case 1:
23547416a5fSTomer Maimon 		*priv->rx_buf++ = ioread8(priv->base + NPCM_PSPI_DATA);
2361d2319efSOlof Johansson 		break;
2371d2319efSOlof Johansson 	case 2:
2382a22f1b3STomer Maimon 		val = ioread16(priv->base + NPCM_PSPI_DATA);
23947416a5fSTomer Maimon 		*priv->rx_buf++ = (val >> 8);
24047416a5fSTomer Maimon 		*priv->rx_buf++ = val & 0xff;
2411d2319efSOlof Johansson 		break;
2421d2319efSOlof Johansson 	default:
2431d2319efSOlof Johansson 		WARN_ON_ONCE(1);
2441d2319efSOlof Johansson 		return;
2451d2319efSOlof Johansson 	}
2462a22f1b3STomer Maimon }
2472a22f1b3STomer Maimon 
npcm_pspi_transfer_one(struct spi_master * master,struct spi_device * spi,struct spi_transfer * t)2482a22f1b3STomer Maimon static int npcm_pspi_transfer_one(struct spi_master *master,
2492a22f1b3STomer Maimon 				  struct spi_device *spi,
2502a22f1b3STomer Maimon 				  struct spi_transfer *t)
2512a22f1b3STomer Maimon {
2522a22f1b3STomer Maimon 	struct npcm_pspi *priv = spi_master_get_devdata(master);
2532a22f1b3STomer Maimon 	int status;
2542a22f1b3STomer Maimon 
2552a22f1b3STomer Maimon 	npcm_pspi_setup_transfer(spi, t);
2562a22f1b3STomer Maimon 	reinit_completion(&priv->xfer_done);
2572a22f1b3STomer Maimon 	npcm_pspi_enable(priv);
2582a22f1b3STomer Maimon 	status = wait_for_completion_timeout(&priv->xfer_done,
2592a22f1b3STomer Maimon 					     msecs_to_jiffies
2602a22f1b3STomer Maimon 					     (NPCM_PSPI_TIMEOUT_MS));
2612a22f1b3STomer Maimon 	if (status == 0) {
2622a22f1b3STomer Maimon 		npcm_pspi_disable(priv);
2632a22f1b3STomer Maimon 		return -ETIMEDOUT;
2642a22f1b3STomer Maimon 	}
2652a22f1b3STomer Maimon 
2662a22f1b3STomer Maimon 	return 0;
2672a22f1b3STomer Maimon }
2682a22f1b3STomer Maimon 
npcm_pspi_prepare_transfer_hardware(struct spi_master * master)2692a22f1b3STomer Maimon static int npcm_pspi_prepare_transfer_hardware(struct spi_master *master)
2702a22f1b3STomer Maimon {
2712a22f1b3STomer Maimon 	struct npcm_pspi *priv = spi_master_get_devdata(master);
2722a22f1b3STomer Maimon 
2732a22f1b3STomer Maimon 	npcm_pspi_irq_enable(priv, NPCM_PSPI_CTL1_EIR | NPCM_PSPI_CTL1_EIW);
2742a22f1b3STomer Maimon 
2752a22f1b3STomer Maimon 	return 0;
2762a22f1b3STomer Maimon }
2772a22f1b3STomer Maimon 
npcm_pspi_unprepare_transfer_hardware(struct spi_master * master)2782a22f1b3STomer Maimon static int npcm_pspi_unprepare_transfer_hardware(struct spi_master *master)
2792a22f1b3STomer Maimon {
2802a22f1b3STomer Maimon 	struct npcm_pspi *priv = spi_master_get_devdata(master);
2812a22f1b3STomer Maimon 
2822a22f1b3STomer Maimon 	npcm_pspi_irq_disable(priv, NPCM_PSPI_CTL1_EIR | NPCM_PSPI_CTL1_EIW);
2832a22f1b3STomer Maimon 
2842a22f1b3STomer Maimon 	return 0;
2852a22f1b3STomer Maimon }
2862a22f1b3STomer Maimon 
npcm_pspi_reset_hw(struct npcm_pspi * priv)2872a22f1b3STomer Maimon static void npcm_pspi_reset_hw(struct npcm_pspi *priv)
2882a22f1b3STomer Maimon {
289b5df0b2eSTomer Maimon 	reset_control_assert(priv->reset);
290b5df0b2eSTomer Maimon 	udelay(5);
291b5df0b2eSTomer Maimon 	reset_control_deassert(priv->reset);
2922a22f1b3STomer Maimon }
2932a22f1b3STomer Maimon 
npcm_pspi_handler(int irq,void * dev_id)2942a22f1b3STomer Maimon static irqreturn_t npcm_pspi_handler(int irq, void *dev_id)
2952a22f1b3STomer Maimon {
2962a22f1b3STomer Maimon 	struct npcm_pspi *priv = dev_id;
2972a22f1b3STomer Maimon 	u8 stat;
2982a22f1b3STomer Maimon 
2992a22f1b3STomer Maimon 	stat = ioread8(priv->base + NPCM_PSPI_STAT);
3002a22f1b3STomer Maimon 
3012a22f1b3STomer Maimon 	if (!priv->tx_buf && !priv->rx_buf)
3022a22f1b3STomer Maimon 		return IRQ_NONE;
3032a22f1b3STomer Maimon 
3042a22f1b3STomer Maimon 	if (priv->tx_buf) {
3052a22f1b3STomer Maimon 		if (stat & NPCM_PSPI_STAT_RBF) {
306c46652eeSzhengbin 			ioread8(NPCM_PSPI_DATA + priv->base);
3072a22f1b3STomer Maimon 			if (priv->tx_bytes == 0) {
3082a22f1b3STomer Maimon 				npcm_pspi_disable(priv);
3092a22f1b3STomer Maimon 				complete(&priv->xfer_done);
3102a22f1b3STomer Maimon 				return IRQ_HANDLED;
3112a22f1b3STomer Maimon 			}
3122a22f1b3STomer Maimon 		}
3132a22f1b3STomer Maimon 
3142a22f1b3STomer Maimon 		if ((stat & NPCM_PSPI_STAT_BSY) == 0)
3152a22f1b3STomer Maimon 			if (priv->tx_bytes)
3162a22f1b3STomer Maimon 				npcm_pspi_send(priv);
3172a22f1b3STomer Maimon 	}
3182a22f1b3STomer Maimon 
3192a22f1b3STomer Maimon 	if (priv->rx_buf) {
3202a22f1b3STomer Maimon 		if (stat & NPCM_PSPI_STAT_RBF) {
3212a22f1b3STomer Maimon 			if (!priv->rx_bytes)
3222a22f1b3STomer Maimon 				return IRQ_NONE;
3232a22f1b3STomer Maimon 
3242a22f1b3STomer Maimon 			npcm_pspi_recv(priv);
3252a22f1b3STomer Maimon 
3262a22f1b3STomer Maimon 			if (!priv->rx_bytes) {
3272a22f1b3STomer Maimon 				npcm_pspi_disable(priv);
3282a22f1b3STomer Maimon 				complete(&priv->xfer_done);
3292a22f1b3STomer Maimon 				return IRQ_HANDLED;
3302a22f1b3STomer Maimon 			}
3312a22f1b3STomer Maimon 		}
3322a22f1b3STomer Maimon 
3332a22f1b3STomer Maimon 		if (((stat & NPCM_PSPI_STAT_BSY) == 0) && !priv->tx_buf)
3342a22f1b3STomer Maimon 			iowrite8(0x0, NPCM_PSPI_DATA + priv->base);
3352a22f1b3STomer Maimon 	}
3362a22f1b3STomer Maimon 
3372a22f1b3STomer Maimon 	return IRQ_HANDLED;
3382a22f1b3STomer Maimon }
3392a22f1b3STomer Maimon 
npcm_pspi_probe(struct platform_device * pdev)3402a22f1b3STomer Maimon static int npcm_pspi_probe(struct platform_device *pdev)
3412a22f1b3STomer Maimon {
3422a22f1b3STomer Maimon 	struct npcm_pspi *priv;
3432a22f1b3STomer Maimon 	struct spi_master *master;
3442a22f1b3STomer Maimon 	unsigned long clk_hz;
3452a22f1b3STomer Maimon 	int irq;
3462a22f1b3STomer Maimon 	int ret;
3472a22f1b3STomer Maimon 
3482a22f1b3STomer Maimon 	master = spi_alloc_master(&pdev->dev, sizeof(*priv));
3492a22f1b3STomer Maimon 	if (!master)
3502a22f1b3STomer Maimon 		return -ENOMEM;
3512a22f1b3STomer Maimon 
3522a22f1b3STomer Maimon 	platform_set_drvdata(pdev, master);
3532a22f1b3STomer Maimon 
3542a22f1b3STomer Maimon 	priv = spi_master_get_devdata(master);
3552a22f1b3STomer Maimon 	priv->master = master;
3562a22f1b3STomer Maimon 	priv->is_save_param = false;
3572a22f1b3STomer Maimon 
358dcbceb6dSYueHaibing 	priv->base = devm_platform_ioremap_resource(pdev, 0);
3592a22f1b3STomer Maimon 	if (IS_ERR(priv->base)) {
3602a22f1b3STomer Maimon 		ret = PTR_ERR(priv->base);
3612a22f1b3STomer Maimon 		goto out_master_put;
3622a22f1b3STomer Maimon 	}
3632a22f1b3STomer Maimon 
3642a22f1b3STomer Maimon 	priv->clk = devm_clk_get(&pdev->dev, NULL);
3652a22f1b3STomer Maimon 	if (IS_ERR(priv->clk)) {
3662a22f1b3STomer Maimon 		dev_err(&pdev->dev, "failed to get clock\n");
3672a22f1b3STomer Maimon 		ret = PTR_ERR(priv->clk);
3682a22f1b3STomer Maimon 		goto out_master_put;
3692a22f1b3STomer Maimon 	}
3702a22f1b3STomer Maimon 
3712a22f1b3STomer Maimon 	ret = clk_prepare_enable(priv->clk);
3722a22f1b3STomer Maimon 	if (ret)
3732a22f1b3STomer Maimon 		goto out_master_put;
3742a22f1b3STomer Maimon 
3752a22f1b3STomer Maimon 	irq = platform_get_irq(pdev, 0);
3762a22f1b3STomer Maimon 	if (irq < 0) {
3772a22f1b3STomer Maimon 		ret = irq;
3782a22f1b3STomer Maimon 		goto out_disable_clk;
3792a22f1b3STomer Maimon 	}
3802a22f1b3STomer Maimon 
381b5df0b2eSTomer Maimon 	priv->reset = devm_reset_control_get(&pdev->dev, NULL);
382b5df0b2eSTomer Maimon 	if (IS_ERR(priv->reset)) {
383b5df0b2eSTomer Maimon 		ret = PTR_ERR(priv->reset);
384b5df0b2eSTomer Maimon 		goto out_disable_clk;
3852a22f1b3STomer Maimon 	}
3862a22f1b3STomer Maimon 
3872a22f1b3STomer Maimon 	/* reset SPI-HW block */
3882a22f1b3STomer Maimon 	npcm_pspi_reset_hw(priv);
3892a22f1b3STomer Maimon 
3902a22f1b3STomer Maimon 	ret = devm_request_irq(&pdev->dev, irq, npcm_pspi_handler, 0,
3912a22f1b3STomer Maimon 			       "npcm-pspi", priv);
3922a22f1b3STomer Maimon 	if (ret) {
3932a22f1b3STomer Maimon 		dev_err(&pdev->dev, "failed to request IRQ\n");
3942a22f1b3STomer Maimon 		goto out_disable_clk;
3952a22f1b3STomer Maimon 	}
3962a22f1b3STomer Maimon 
3972a22f1b3STomer Maimon 	init_completion(&priv->xfer_done);
3982a22f1b3STomer Maimon 
3992a22f1b3STomer Maimon 	clk_hz = clk_get_rate(priv->clk);
4002a22f1b3STomer Maimon 
4012a22f1b3STomer Maimon 	master->max_speed_hz = DIV_ROUND_UP(clk_hz, NPCM_PSPI_MIN_CLK_DIVIDER);
4022a22f1b3STomer Maimon 	master->min_speed_hz = DIV_ROUND_UP(clk_hz, NPCM_PSPI_MAX_CLK_DIVIDER);
4032a22f1b3STomer Maimon 	master->mode_bits = SPI_CPHA | SPI_CPOL;
4042a22f1b3STomer Maimon 	master->dev.of_node = pdev->dev.of_node;
405b5df0b2eSTomer Maimon 	master->bus_num = -1;
4062a22f1b3STomer Maimon 	master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
4072a22f1b3STomer Maimon 	master->transfer_one = npcm_pspi_transfer_one;
4082a22f1b3STomer Maimon 	master->prepare_transfer_hardware =
4092a22f1b3STomer Maimon 		npcm_pspi_prepare_transfer_hardware;
4102a22f1b3STomer Maimon 	master->unprepare_transfer_hardware =
4112a22f1b3STomer Maimon 		npcm_pspi_unprepare_transfer_hardware;
412a2f234fcSLinus Walleij 	master->use_gpio_descriptors = true;
4132a22f1b3STomer Maimon 
4142a22f1b3STomer Maimon 	/* set to default clock rate */
4152a22f1b3STomer Maimon 	npcm_pspi_set_baudrate(priv, NPCM_PSPI_DEFAULT_CLK);
4162a22f1b3STomer Maimon 
4172a22f1b3STomer Maimon 	ret = devm_spi_register_master(&pdev->dev, master);
4182a22f1b3STomer Maimon 	if (ret)
4192a22f1b3STomer Maimon 		goto out_disable_clk;
4202a22f1b3STomer Maimon 
421b5df0b2eSTomer Maimon 	pr_info("NPCM Peripheral SPI %d probed\n", master->bus_num);
4222a22f1b3STomer Maimon 
4232a22f1b3STomer Maimon 	return 0;
4242a22f1b3STomer Maimon 
4252a22f1b3STomer Maimon out_disable_clk:
4262a22f1b3STomer Maimon 	clk_disable_unprepare(priv->clk);
4272a22f1b3STomer Maimon 
4282a22f1b3STomer Maimon out_master_put:
4292a22f1b3STomer Maimon 	spi_master_put(master);
4302a22f1b3STomer Maimon 	return ret;
4312a22f1b3STomer Maimon }
4322a22f1b3STomer Maimon 
npcm_pspi_remove(struct platform_device * pdev)433*445534b5SUwe Kleine-König static void npcm_pspi_remove(struct platform_device *pdev)
4342a22f1b3STomer Maimon {
43508253144SAxel Lin 	struct spi_master *master = platform_get_drvdata(pdev);
43608253144SAxel Lin 	struct npcm_pspi *priv = spi_master_get_devdata(master);
4372a22f1b3STomer Maimon 
4382a22f1b3STomer Maimon 	npcm_pspi_reset_hw(priv);
4392a22f1b3STomer Maimon 	clk_disable_unprepare(priv->clk);
4402a22f1b3STomer Maimon }
4412a22f1b3STomer Maimon 
4422a22f1b3STomer Maimon static const struct of_device_id npcm_pspi_match[] = {
4432a22f1b3STomer Maimon 	{ .compatible = "nuvoton,npcm750-pspi", .data = NULL },
4446db8595aSTomer Maimon 	{ .compatible = "nuvoton,npcm845-pspi", .data = NULL },
4452a22f1b3STomer Maimon 	{}
4462a22f1b3STomer Maimon };
4472a22f1b3STomer Maimon MODULE_DEVICE_TABLE(of, npcm_pspi_match);
4482a22f1b3STomer Maimon 
4492a22f1b3STomer Maimon static struct platform_driver npcm_pspi_driver = {
4502a22f1b3STomer Maimon 	.driver		= {
4512a22f1b3STomer Maimon 		.name		= DRIVER_NAME,
4522a22f1b3STomer Maimon 		.of_match_table	= npcm_pspi_match,
4532a22f1b3STomer Maimon 	},
4542a22f1b3STomer Maimon 	.probe		= npcm_pspi_probe,
455*445534b5SUwe Kleine-König 	.remove_new	= npcm_pspi_remove,
4562a22f1b3STomer Maimon };
4572a22f1b3STomer Maimon module_platform_driver(npcm_pspi_driver);
4582a22f1b3STomer Maimon 
4592a22f1b3STomer Maimon MODULE_DESCRIPTION("NPCM peripheral SPI Controller driver");
4602a22f1b3STomer Maimon MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
4612a22f1b3STomer Maimon MODULE_LICENSE("GPL v2");
4622a22f1b3STomer Maimon 
463