xref: /linux/drivers/spi/spi-mpfs.c (revision f2161d5f1aae21a42b0a64d87e10cb31db423f42)
171c814e9SPrajna Rajendra Kumar // SPDX-License-Identifier: (GPL-2.0)
271c814e9SPrajna Rajendra Kumar /*
371c814e9SPrajna Rajendra Kumar  * Microchip CoreSPI SPI controller driver
471c814e9SPrajna Rajendra Kumar  *
571c814e9SPrajna Rajendra Kumar  * Copyright (c) 2018-2022 Microchip Technology Inc. and its subsidiaries
671c814e9SPrajna Rajendra Kumar  *
771c814e9SPrajna Rajendra Kumar  * Author: Daire McNamara <daire.mcnamara@microchip.com>
871c814e9SPrajna Rajendra Kumar  * Author: Conor Dooley <conor.dooley@microchip.com>
971c814e9SPrajna Rajendra Kumar  *
1071c814e9SPrajna Rajendra Kumar  */
1171c814e9SPrajna Rajendra Kumar 
1271c814e9SPrajna Rajendra Kumar #include <linux/clk.h>
1371c814e9SPrajna Rajendra Kumar #include <linux/delay.h>
1471c814e9SPrajna Rajendra Kumar #include <linux/err.h>
1571c814e9SPrajna Rajendra Kumar #include <linux/init.h>
1671c814e9SPrajna Rajendra Kumar #include <linux/interrupt.h>
1771c814e9SPrajna Rajendra Kumar #include <linux/io.h>
1871c814e9SPrajna Rajendra Kumar #include <linux/module.h>
1971c814e9SPrajna Rajendra Kumar #include <linux/of.h>
2071c814e9SPrajna Rajendra Kumar #include <linux/platform_device.h>
2171c814e9SPrajna Rajendra Kumar #include <linux/spi/spi.h>
2271c814e9SPrajna Rajendra Kumar 
2371c814e9SPrajna Rajendra Kumar #define MAX_LEN				(0xffff)
2471c814e9SPrajna Rajendra Kumar #define MAX_CS				(1)
2571c814e9SPrajna Rajendra Kumar #define DEFAULT_FRAMESIZE		(8)
2671c814e9SPrajna Rajendra Kumar #define FIFO_DEPTH			(32)
2771c814e9SPrajna Rajendra Kumar #define CLK_GEN_MODE1_MAX		(255)
2871c814e9SPrajna Rajendra Kumar #define CLK_GEN_MODE0_MAX		(15)
2971c814e9SPrajna Rajendra Kumar #define CLK_GEN_MIN			(0)
3071c814e9SPrajna Rajendra Kumar #define MODE_X_MASK_SHIFT		(24)
3171c814e9SPrajna Rajendra Kumar 
3271c814e9SPrajna Rajendra Kumar #define CONTROL_ENABLE			BIT(0)
3371c814e9SPrajna Rajendra Kumar #define CONTROL_MASTER			BIT(1)
3471c814e9SPrajna Rajendra Kumar #define CONTROL_RX_DATA_INT		BIT(4)
3571c814e9SPrajna Rajendra Kumar #define CONTROL_TX_DATA_INT		BIT(5)
3671c814e9SPrajna Rajendra Kumar #define CONTROL_RX_OVER_INT		BIT(6)
3771c814e9SPrajna Rajendra Kumar #define CONTROL_TX_UNDER_INT		BIT(7)
3871c814e9SPrajna Rajendra Kumar #define CONTROL_SPO			BIT(24)
3971c814e9SPrajna Rajendra Kumar #define CONTROL_SPH			BIT(25)
4071c814e9SPrajna Rajendra Kumar #define CONTROL_SPS			BIT(26)
4171c814e9SPrajna Rajendra Kumar #define CONTROL_FRAMEURUN		BIT(27)
4271c814e9SPrajna Rajendra Kumar #define CONTROL_CLKMODE			BIT(28)
4371c814e9SPrajna Rajendra Kumar #define CONTROL_BIGFIFO			BIT(29)
4471c814e9SPrajna Rajendra Kumar #define CONTROL_OENOFF			BIT(30)
4571c814e9SPrajna Rajendra Kumar #define CONTROL_RESET			BIT(31)
4671c814e9SPrajna Rajendra Kumar 
4771c814e9SPrajna Rajendra Kumar #define CONTROL_MODE_MASK		GENMASK(3, 2)
4871c814e9SPrajna Rajendra Kumar #define  MOTOROLA_MODE			(0)
4971c814e9SPrajna Rajendra Kumar #define CONTROL_FRAMECNT_MASK		GENMASK(23, 8)
5071c814e9SPrajna Rajendra Kumar #define CONTROL_FRAMECNT_SHIFT		(8)
5171c814e9SPrajna Rajendra Kumar 
5271c814e9SPrajna Rajendra Kumar #define STATUS_ACTIVE			BIT(14)
5371c814e9SPrajna Rajendra Kumar #define STATUS_SSEL			BIT(13)
5471c814e9SPrajna Rajendra Kumar #define STATUS_FRAMESTART		BIT(12)
5571c814e9SPrajna Rajendra Kumar #define STATUS_TXFIFO_EMPTY_NEXT_READ	BIT(11)
5671c814e9SPrajna Rajendra Kumar #define STATUS_TXFIFO_EMPTY		BIT(10)
5771c814e9SPrajna Rajendra Kumar #define STATUS_TXFIFO_FULL_NEXT_WRITE	BIT(9)
5871c814e9SPrajna Rajendra Kumar #define STATUS_TXFIFO_FULL		BIT(8)
5971c814e9SPrajna Rajendra Kumar #define STATUS_RXFIFO_EMPTY_NEXT_READ	BIT(7)
6071c814e9SPrajna Rajendra Kumar #define STATUS_RXFIFO_EMPTY		BIT(6)
6171c814e9SPrajna Rajendra Kumar #define STATUS_RXFIFO_FULL_NEXT_WRITE	BIT(5)
6271c814e9SPrajna Rajendra Kumar #define STATUS_RXFIFO_FULL		BIT(4)
6371c814e9SPrajna Rajendra Kumar #define STATUS_TX_UNDERRUN		BIT(3)
6471c814e9SPrajna Rajendra Kumar #define STATUS_RX_OVERFLOW		BIT(2)
6571c814e9SPrajna Rajendra Kumar #define STATUS_RXDAT_RXED		BIT(1)
6671c814e9SPrajna Rajendra Kumar #define STATUS_TXDAT_SENT		BIT(0)
6771c814e9SPrajna Rajendra Kumar 
6871c814e9SPrajna Rajendra Kumar #define INT_TXDONE			BIT(0)
6971c814e9SPrajna Rajendra Kumar #define INT_RXRDY			BIT(1)
7071c814e9SPrajna Rajendra Kumar #define INT_RX_CHANNEL_OVERFLOW		BIT(2)
7171c814e9SPrajna Rajendra Kumar #define INT_TX_CHANNEL_UNDERRUN		BIT(3)
7271c814e9SPrajna Rajendra Kumar 
7371c814e9SPrajna Rajendra Kumar #define INT_ENABLE_MASK (CONTROL_RX_OVER_INT | CONTROL_TX_UNDER_INT)
7471c814e9SPrajna Rajendra Kumar 
7571c814e9SPrajna Rajendra Kumar #define REG_CONTROL		(0x00)
7671c814e9SPrajna Rajendra Kumar #define REG_FRAME_SIZE		(0x04)
7771c814e9SPrajna Rajendra Kumar #define  FRAME_SIZE_MASK	GENMASK(5, 0)
7871c814e9SPrajna Rajendra Kumar #define REG_STATUS		(0x08)
7971c814e9SPrajna Rajendra Kumar #define REG_INT_CLEAR		(0x0c)
8071c814e9SPrajna Rajendra Kumar #define REG_RX_DATA		(0x10)
8171c814e9SPrajna Rajendra Kumar #define REG_TX_DATA		(0x14)
8271c814e9SPrajna Rajendra Kumar #define REG_CLK_GEN		(0x18)
8371c814e9SPrajna Rajendra Kumar #define REG_SLAVE_SELECT	(0x1c)
8471c814e9SPrajna Rajendra Kumar #define  SSEL_MASK		GENMASK(7, 0)
8571c814e9SPrajna Rajendra Kumar #define  SSEL_DIRECT		BIT(8)
8671c814e9SPrajna Rajendra Kumar #define  SSELOUT_SHIFT		9
8771c814e9SPrajna Rajendra Kumar #define  SSELOUT		BIT(SSELOUT_SHIFT)
8871c814e9SPrajna Rajendra Kumar #define REG_MIS			(0x20)
8971c814e9SPrajna Rajendra Kumar #define REG_RIS			(0x24)
9071c814e9SPrajna Rajendra Kumar #define REG_CONTROL2		(0x28)
9171c814e9SPrajna Rajendra Kumar #define REG_COMMAND		(0x2c)
9271c814e9SPrajna Rajendra Kumar #define  COMMAND_CLRFRAMECNT	BIT(4)
9371c814e9SPrajna Rajendra Kumar #define  COMMAND_TXFIFORST		BIT(3)
9471c814e9SPrajna Rajendra Kumar #define  COMMAND_RXFIFORST		BIT(2)
9571c814e9SPrajna Rajendra Kumar #define REG_PKTSIZE		(0x30)
9671c814e9SPrajna Rajendra Kumar #define REG_CMD_SIZE		(0x34)
9771c814e9SPrajna Rajendra Kumar #define REG_HWSTATUS		(0x38)
9871c814e9SPrajna Rajendra Kumar #define REG_STAT8		(0x3c)
9971c814e9SPrajna Rajendra Kumar #define REG_CTRL2		(0x48)
10071c814e9SPrajna Rajendra Kumar #define REG_FRAMESUP		(0x50)
10171c814e9SPrajna Rajendra Kumar 
10271c814e9SPrajna Rajendra Kumar struct mpfs_spi {
10371c814e9SPrajna Rajendra Kumar 	void __iomem *regs;
10471c814e9SPrajna Rajendra Kumar 	struct clk *clk;
10571c814e9SPrajna Rajendra Kumar 	const u8 *tx_buf;
10671c814e9SPrajna Rajendra Kumar 	u8 *rx_buf;
10771c814e9SPrajna Rajendra Kumar 	u32 clk_gen; /* divider for spi output clock generated by the controller */
10871c814e9SPrajna Rajendra Kumar 	u32 clk_mode;
10971c814e9SPrajna Rajendra Kumar 	u32 pending_slave_select;
11071c814e9SPrajna Rajendra Kumar 	int irq;
11171c814e9SPrajna Rajendra Kumar 	int tx_len;
11271c814e9SPrajna Rajendra Kumar 	int rx_len;
11371c814e9SPrajna Rajendra Kumar 	int n_bytes;
11471c814e9SPrajna Rajendra Kumar };
11571c814e9SPrajna Rajendra Kumar 
mpfs_spi_read(struct mpfs_spi * spi,unsigned int reg)11671c814e9SPrajna Rajendra Kumar static inline u32 mpfs_spi_read(struct mpfs_spi *spi, unsigned int reg)
11771c814e9SPrajna Rajendra Kumar {
11871c814e9SPrajna Rajendra Kumar 	return readl(spi->regs + reg);
11971c814e9SPrajna Rajendra Kumar }
12071c814e9SPrajna Rajendra Kumar 
mpfs_spi_write(struct mpfs_spi * spi,unsigned int reg,u32 val)12171c814e9SPrajna Rajendra Kumar static inline void mpfs_spi_write(struct mpfs_spi *spi, unsigned int reg, u32 val)
12271c814e9SPrajna Rajendra Kumar {
12371c814e9SPrajna Rajendra Kumar 	writel(val, spi->regs + reg);
12471c814e9SPrajna Rajendra Kumar }
12571c814e9SPrajna Rajendra Kumar 
mpfs_spi_disable(struct mpfs_spi * spi)12671c814e9SPrajna Rajendra Kumar static inline void mpfs_spi_disable(struct mpfs_spi *spi)
12771c814e9SPrajna Rajendra Kumar {
12871c814e9SPrajna Rajendra Kumar 	u32 control = mpfs_spi_read(spi, REG_CONTROL);
12971c814e9SPrajna Rajendra Kumar 
13071c814e9SPrajna Rajendra Kumar 	control &= ~CONTROL_ENABLE;
13171c814e9SPrajna Rajendra Kumar 
13271c814e9SPrajna Rajendra Kumar 	mpfs_spi_write(spi, REG_CONTROL, control);
13371c814e9SPrajna Rajendra Kumar }
13471c814e9SPrajna Rajendra Kumar 
mpfs_spi_read_fifo(struct mpfs_spi * spi,int fifo_max)13571c814e9SPrajna Rajendra Kumar static inline void mpfs_spi_read_fifo(struct mpfs_spi *spi, int fifo_max)
13671c814e9SPrajna Rajendra Kumar {
13771c814e9SPrajna Rajendra Kumar 	for (int i = 0; i < fifo_max; i++) {
13871c814e9SPrajna Rajendra Kumar 		u32 data;
13971c814e9SPrajna Rajendra Kumar 
14071c814e9SPrajna Rajendra Kumar 		while (mpfs_spi_read(spi, REG_STATUS) & STATUS_RXFIFO_EMPTY)
14171c814e9SPrajna Rajendra Kumar 			;
14271c814e9SPrajna Rajendra Kumar 
14371c814e9SPrajna Rajendra Kumar 		data = mpfs_spi_read(spi, REG_RX_DATA);
14471c814e9SPrajna Rajendra Kumar 
14571c814e9SPrajna Rajendra Kumar 		spi->rx_len -= spi->n_bytes;
14671c814e9SPrajna Rajendra Kumar 
14771c814e9SPrajna Rajendra Kumar 		if (!spi->rx_buf)
14871c814e9SPrajna Rajendra Kumar 			continue;
14971c814e9SPrajna Rajendra Kumar 
15071c814e9SPrajna Rajendra Kumar 		if (spi->n_bytes == 4)
15171c814e9SPrajna Rajendra Kumar 			*((u32 *)spi->rx_buf) = data;
15271c814e9SPrajna Rajendra Kumar 		else if (spi->n_bytes == 2)
15371c814e9SPrajna Rajendra Kumar 			*((u16 *)spi->rx_buf) = data;
15471c814e9SPrajna Rajendra Kumar 		else
15571c814e9SPrajna Rajendra Kumar 			*spi->rx_buf = data;
15671c814e9SPrajna Rajendra Kumar 
15771c814e9SPrajna Rajendra Kumar 		spi->rx_buf += spi->n_bytes;
15871c814e9SPrajna Rajendra Kumar 	}
15971c814e9SPrajna Rajendra Kumar }
16071c814e9SPrajna Rajendra Kumar 
mpfs_spi_enable_ints(struct mpfs_spi * spi)16171c814e9SPrajna Rajendra Kumar static void mpfs_spi_enable_ints(struct mpfs_spi *spi)
16271c814e9SPrajna Rajendra Kumar {
16371c814e9SPrajna Rajendra Kumar 	u32 control = mpfs_spi_read(spi, REG_CONTROL);
16471c814e9SPrajna Rajendra Kumar 
16571c814e9SPrajna Rajendra Kumar 	control |= INT_ENABLE_MASK;
16671c814e9SPrajna Rajendra Kumar 	mpfs_spi_write(spi, REG_CONTROL, control);
16771c814e9SPrajna Rajendra Kumar }
16871c814e9SPrajna Rajendra Kumar 
mpfs_spi_disable_ints(struct mpfs_spi * spi)16971c814e9SPrajna Rajendra Kumar static void mpfs_spi_disable_ints(struct mpfs_spi *spi)
17071c814e9SPrajna Rajendra Kumar {
17171c814e9SPrajna Rajendra Kumar 	u32 control = mpfs_spi_read(spi, REG_CONTROL);
17271c814e9SPrajna Rajendra Kumar 
17371c814e9SPrajna Rajendra Kumar 	control &= ~INT_ENABLE_MASK;
17471c814e9SPrajna Rajendra Kumar 	mpfs_spi_write(spi, REG_CONTROL, control);
17571c814e9SPrajna Rajendra Kumar }
17671c814e9SPrajna Rajendra Kumar 
mpfs_spi_set_xfer_size(struct mpfs_spi * spi,int len)17771c814e9SPrajna Rajendra Kumar static inline void mpfs_spi_set_xfer_size(struct mpfs_spi *spi, int len)
17871c814e9SPrajna Rajendra Kumar {
17971c814e9SPrajna Rajendra Kumar 	u32 control;
18071c814e9SPrajna Rajendra Kumar 	u32 lenpart;
18171c814e9SPrajna Rajendra Kumar 	u32 frames = mpfs_spi_read(spi, REG_FRAMESUP);
18271c814e9SPrajna Rajendra Kumar 
18371c814e9SPrajna Rajendra Kumar 	/*
18471c814e9SPrajna Rajendra Kumar 	 * Writing to FRAMECNT in REG_CONTROL will reset the frame count, taking
18571c814e9SPrajna Rajendra Kumar 	 * a shortcut requires an explicit clear.
18671c814e9SPrajna Rajendra Kumar 	 */
18771c814e9SPrajna Rajendra Kumar 	if (frames == len) {
18871c814e9SPrajna Rajendra Kumar 		mpfs_spi_write(spi, REG_COMMAND, COMMAND_CLRFRAMECNT);
18971c814e9SPrajna Rajendra Kumar 		return;
19071c814e9SPrajna Rajendra Kumar 	}
19171c814e9SPrajna Rajendra Kumar 
19271c814e9SPrajna Rajendra Kumar 	/*
19371c814e9SPrajna Rajendra Kumar 	 * The lower 16 bits of the frame count are stored in the control reg
19471c814e9SPrajna Rajendra Kumar 	 * for legacy reasons, but the upper 16 written to a different register:
19571c814e9SPrajna Rajendra Kumar 	 * FRAMESUP. While both the upper and lower bits can be *READ* from the
19671c814e9SPrajna Rajendra Kumar 	 * FRAMESUP register, writing to the lower 16 bits is (supposedly) a NOP.
19771c814e9SPrajna Rajendra Kumar 	 *
19871c814e9SPrajna Rajendra Kumar 	 * The driver used to disable the controller while modifying the frame
19971c814e9SPrajna Rajendra Kumar 	 * count, and mask off the lower 16 bits of len while writing to
20071c814e9SPrajna Rajendra Kumar 	 * FRAMES_UP. When the driver was changed to disable the controller as
20171c814e9SPrajna Rajendra Kumar 	 * infrequently as possible, it was discovered that the logic of
20271c814e9SPrajna Rajendra Kumar 	 * lenpart = len & 0xffff_0000
20371c814e9SPrajna Rajendra Kumar 	 * write(REG_FRAMESUP, lenpart)
20471c814e9SPrajna Rajendra Kumar 	 * would actually write zeros into the lower 16 bits on an mpfs250t-es,
20571c814e9SPrajna Rajendra Kumar 	 * despite documentation stating these bits were read-only.
20671c814e9SPrajna Rajendra Kumar 	 * Writing len unmasked into FRAMES_UP ensures those bits aren't zeroed
20771c814e9SPrajna Rajendra Kumar 	 * on an mpfs250t-es and will be a NOP for the lower 16 bits on hardware
20871c814e9SPrajna Rajendra Kumar 	 * that matches the documentation.
20971c814e9SPrajna Rajendra Kumar 	 */
21071c814e9SPrajna Rajendra Kumar 	lenpart = len & 0xffff;
21171c814e9SPrajna Rajendra Kumar 	control = mpfs_spi_read(spi, REG_CONTROL);
21271c814e9SPrajna Rajendra Kumar 	control &= ~CONTROL_FRAMECNT_MASK;
21371c814e9SPrajna Rajendra Kumar 	control |= lenpart << CONTROL_FRAMECNT_SHIFT;
21471c814e9SPrajna Rajendra Kumar 	mpfs_spi_write(spi, REG_CONTROL, control);
21571c814e9SPrajna Rajendra Kumar 	mpfs_spi_write(spi, REG_FRAMESUP, len);
21671c814e9SPrajna Rajendra Kumar }
21771c814e9SPrajna Rajendra Kumar 
mpfs_spi_write_fifo(struct mpfs_spi * spi,int fifo_max)21871c814e9SPrajna Rajendra Kumar static inline void mpfs_spi_write_fifo(struct mpfs_spi *spi, int fifo_max)
21971c814e9SPrajna Rajendra Kumar {
22071c814e9SPrajna Rajendra Kumar 	int i = 0;
22171c814e9SPrajna Rajendra Kumar 
22271c814e9SPrajna Rajendra Kumar 	mpfs_spi_set_xfer_size(spi, fifo_max);
22371c814e9SPrajna Rajendra Kumar 
22471c814e9SPrajna Rajendra Kumar 	while ((i < fifo_max) && !(mpfs_spi_read(spi, REG_STATUS) & STATUS_TXFIFO_FULL)) {
22571c814e9SPrajna Rajendra Kumar 		u32 word;
22671c814e9SPrajna Rajendra Kumar 
22771c814e9SPrajna Rajendra Kumar 		if (spi->n_bytes == 4)
22871c814e9SPrajna Rajendra Kumar 			word = spi->tx_buf ? *((u32 *)spi->tx_buf) : 0xaa;
22971c814e9SPrajna Rajendra Kumar 		else if (spi->n_bytes == 2)
23071c814e9SPrajna Rajendra Kumar 			word = spi->tx_buf ? *((u16 *)spi->tx_buf) : 0xaa;
23171c814e9SPrajna Rajendra Kumar 		else
23271c814e9SPrajna Rajendra Kumar 			word = spi->tx_buf ? *spi->tx_buf : 0xaa;
23371c814e9SPrajna Rajendra Kumar 
23471c814e9SPrajna Rajendra Kumar 		mpfs_spi_write(spi, REG_TX_DATA, word);
23571c814e9SPrajna Rajendra Kumar 		if (spi->tx_buf)
23671c814e9SPrajna Rajendra Kumar 			spi->tx_buf += spi->n_bytes;
23771c814e9SPrajna Rajendra Kumar 		i++;
23871c814e9SPrajna Rajendra Kumar 	}
23971c814e9SPrajna Rajendra Kumar 
24071c814e9SPrajna Rajendra Kumar 	spi->tx_len -= i * spi->n_bytes;
24171c814e9SPrajna Rajendra Kumar }
24271c814e9SPrajna Rajendra Kumar 
mpfs_spi_set_framesize(struct mpfs_spi * spi,int bt)24371c814e9SPrajna Rajendra Kumar static inline void mpfs_spi_set_framesize(struct mpfs_spi *spi, int bt)
24471c814e9SPrajna Rajendra Kumar {
24571c814e9SPrajna Rajendra Kumar 	u32 frame_size = mpfs_spi_read(spi, REG_FRAME_SIZE);
24671c814e9SPrajna Rajendra Kumar 	u32 control;
24771c814e9SPrajna Rajendra Kumar 
24871c814e9SPrajna Rajendra Kumar 	if ((frame_size & FRAME_SIZE_MASK) == bt)
24971c814e9SPrajna Rajendra Kumar 		return;
25071c814e9SPrajna Rajendra Kumar 
25171c814e9SPrajna Rajendra Kumar 	/*
25271c814e9SPrajna Rajendra Kumar 	 * Disable the SPI controller. Writes to the frame size have
25371c814e9SPrajna Rajendra Kumar 	 * no effect when the controller is enabled.
25471c814e9SPrajna Rajendra Kumar 	 */
25571c814e9SPrajna Rajendra Kumar 	control = mpfs_spi_read(spi, REG_CONTROL);
25671c814e9SPrajna Rajendra Kumar 	control &= ~CONTROL_ENABLE;
25771c814e9SPrajna Rajendra Kumar 	mpfs_spi_write(spi, REG_CONTROL, control);
25871c814e9SPrajna Rajendra Kumar 
25971c814e9SPrajna Rajendra Kumar 	mpfs_spi_write(spi, REG_FRAME_SIZE, bt);
26071c814e9SPrajna Rajendra Kumar 
26171c814e9SPrajna Rajendra Kumar 	control |= CONTROL_ENABLE;
26271c814e9SPrajna Rajendra Kumar 	mpfs_spi_write(spi, REG_CONTROL, control);
26371c814e9SPrajna Rajendra Kumar }
26471c814e9SPrajna Rajendra Kumar 
mpfs_spi_set_cs(struct spi_device * spi,bool disable)26571c814e9SPrajna Rajendra Kumar static void mpfs_spi_set_cs(struct spi_device *spi, bool disable)
26671c814e9SPrajna Rajendra Kumar {
26771c814e9SPrajna Rajendra Kumar 	u32 reg;
26871c814e9SPrajna Rajendra Kumar 	struct mpfs_spi *mspi = spi_controller_get_devdata(spi->controller);
26971c814e9SPrajna Rajendra Kumar 
27071c814e9SPrajna Rajendra Kumar 	reg = mpfs_spi_read(mspi, REG_SLAVE_SELECT);
27171c814e9SPrajna Rajendra Kumar 	reg &= ~BIT(spi_get_chipselect(spi, 0));
27271c814e9SPrajna Rajendra Kumar 	reg |= !disable << spi_get_chipselect(spi, 0);
27371c814e9SPrajna Rajendra Kumar 	mspi->pending_slave_select = reg;
27471c814e9SPrajna Rajendra Kumar 
27571c814e9SPrajna Rajendra Kumar 	/*
27671c814e9SPrajna Rajendra Kumar 	 * Only deassert chip select immediately. Writing to some registers
27771c814e9SPrajna Rajendra Kumar 	 * requires the controller to be disabled, which results in the
27871c814e9SPrajna Rajendra Kumar 	 * output pins being tristated and can cause the SCLK and MOSI lines
27971c814e9SPrajna Rajendra Kumar 	 * to transition. Therefore asserting the chip select is deferred
28071c814e9SPrajna Rajendra Kumar 	 * until just before writing to the TX FIFO, to ensure the device
28171c814e9SPrajna Rajendra Kumar 	 * doesn't see any spurious clock transitions whilst CS is enabled.
28271c814e9SPrajna Rajendra Kumar 	 */
28371c814e9SPrajna Rajendra Kumar 	if (((spi->mode & SPI_CS_HIGH) == 0) == disable)
28471c814e9SPrajna Rajendra Kumar 		mpfs_spi_write(mspi, REG_SLAVE_SELECT, reg);
28571c814e9SPrajna Rajendra Kumar }
28671c814e9SPrajna Rajendra Kumar 
mpfs_spi_setup(struct spi_device * spi)28771c814e9SPrajna Rajendra Kumar static int mpfs_spi_setup(struct spi_device *spi)
28871c814e9SPrajna Rajendra Kumar {
28971c814e9SPrajna Rajendra Kumar 	struct mpfs_spi *mspi = spi_controller_get_devdata(spi->controller);
29071c814e9SPrajna Rajendra Kumar 	u32 reg;
29171c814e9SPrajna Rajendra Kumar 
29271c814e9SPrajna Rajendra Kumar 	if (spi_is_csgpiod(spi))
29371c814e9SPrajna Rajendra Kumar 		return 0;
29471c814e9SPrajna Rajendra Kumar 
29571c814e9SPrajna Rajendra Kumar 	/*
29671c814e9SPrajna Rajendra Kumar 	 * Active high targets need to be specifically set to their inactive
29771c814e9SPrajna Rajendra Kumar 	 * states during probe by adding them to the "control group" & thus
29871c814e9SPrajna Rajendra Kumar 	 * driving their select line low.
29971c814e9SPrajna Rajendra Kumar 	 */
30071c814e9SPrajna Rajendra Kumar 	if (spi->mode & SPI_CS_HIGH) {
30171c814e9SPrajna Rajendra Kumar 		reg = mpfs_spi_read(mspi, REG_SLAVE_SELECT);
30271c814e9SPrajna Rajendra Kumar 		reg |= BIT(spi_get_chipselect(spi, 0));
30371c814e9SPrajna Rajendra Kumar 		mspi->pending_slave_select = reg;
30471c814e9SPrajna Rajendra Kumar 		mpfs_spi_write(mspi, REG_SLAVE_SELECT, reg);
30571c814e9SPrajna Rajendra Kumar 	}
30671c814e9SPrajna Rajendra Kumar 	return 0;
30771c814e9SPrajna Rajendra Kumar }
30871c814e9SPrajna Rajendra Kumar 
mpfs_spi_init(struct spi_controller * host,struct mpfs_spi * spi)30971c814e9SPrajna Rajendra Kumar static void mpfs_spi_init(struct spi_controller *host, struct mpfs_spi *spi)
31071c814e9SPrajna Rajendra Kumar {
31171c814e9SPrajna Rajendra Kumar 	unsigned long clk_hz;
31271c814e9SPrajna Rajendra Kumar 	u32 control = mpfs_spi_read(spi, REG_CONTROL);
31371c814e9SPrajna Rajendra Kumar 
31471c814e9SPrajna Rajendra Kumar 	control &= ~CONTROL_ENABLE;
31571c814e9SPrajna Rajendra Kumar 	mpfs_spi_write(spi, REG_CONTROL, control);
31671c814e9SPrajna Rajendra Kumar 
31771c814e9SPrajna Rajendra Kumar 	control |= CONTROL_MASTER;
31871c814e9SPrajna Rajendra Kumar 	control &= ~CONTROL_MODE_MASK;
31971c814e9SPrajna Rajendra Kumar 	control |= MOTOROLA_MODE;
32071c814e9SPrajna Rajendra Kumar 
32171c814e9SPrajna Rajendra Kumar 	/*
32271c814e9SPrajna Rajendra Kumar 	 * The controller must be configured so that it doesn't remove Chip
32371c814e9SPrajna Rajendra Kumar 	 * Select until the entire message has been transferred, even if at
32471c814e9SPrajna Rajendra Kumar 	 * some points TX FIFO becomes empty.
32571c814e9SPrajna Rajendra Kumar 	 *
32671c814e9SPrajna Rajendra Kumar 	 * BIGFIFO mode is also enabled, which sets the fifo depth to 32 frames
32771c814e9SPrajna Rajendra Kumar 	 * for the 8 bit transfers that this driver uses.
32871c814e9SPrajna Rajendra Kumar 	 */
32971c814e9SPrajna Rajendra Kumar 	control |= CONTROL_SPS | CONTROL_BIGFIFO;
33071c814e9SPrajna Rajendra Kumar 
33171c814e9SPrajna Rajendra Kumar 	mpfs_spi_write(spi, REG_CONTROL, control);
33271c814e9SPrajna Rajendra Kumar 
33371c814e9SPrajna Rajendra Kumar 	mpfs_spi_set_framesize(spi, DEFAULT_FRAMESIZE);
33471c814e9SPrajna Rajendra Kumar 
33571c814e9SPrajna Rajendra Kumar 	/* max. possible spi clock rate is the apb clock rate */
33671c814e9SPrajna Rajendra Kumar 	clk_hz = clk_get_rate(spi->clk);
33771c814e9SPrajna Rajendra Kumar 	host->max_speed_hz = clk_hz;
33871c814e9SPrajna Rajendra Kumar 
33971c814e9SPrajna Rajendra Kumar 	mpfs_spi_enable_ints(spi);
34071c814e9SPrajna Rajendra Kumar 
34171c814e9SPrajna Rajendra Kumar 	/*
34271c814e9SPrajna Rajendra Kumar 	 * It is required to enable direct mode, otherwise control over the chip
34371c814e9SPrajna Rajendra Kumar 	 * select is relinquished to the hardware. SSELOUT is enabled too so we
34471c814e9SPrajna Rajendra Kumar 	 * can deal with active high targets.
34571c814e9SPrajna Rajendra Kumar 	 */
34671c814e9SPrajna Rajendra Kumar 	spi->pending_slave_select = SSELOUT | SSEL_DIRECT;
34771c814e9SPrajna Rajendra Kumar 	mpfs_spi_write(spi, REG_SLAVE_SELECT, spi->pending_slave_select);
34871c814e9SPrajna Rajendra Kumar 
34971c814e9SPrajna Rajendra Kumar 	control = mpfs_spi_read(spi, REG_CONTROL);
35071c814e9SPrajna Rajendra Kumar 
35171c814e9SPrajna Rajendra Kumar 	control &= ~CONTROL_RESET;
35271c814e9SPrajna Rajendra Kumar 	control |= CONTROL_ENABLE;
35371c814e9SPrajna Rajendra Kumar 
35471c814e9SPrajna Rajendra Kumar 	mpfs_spi_write(spi, REG_CONTROL, control);
35571c814e9SPrajna Rajendra Kumar }
35671c814e9SPrajna Rajendra Kumar 
mpfs_spi_set_clk_gen(struct mpfs_spi * spi)35771c814e9SPrajna Rajendra Kumar static inline void mpfs_spi_set_clk_gen(struct mpfs_spi *spi)
35871c814e9SPrajna Rajendra Kumar {
35971c814e9SPrajna Rajendra Kumar 	u32 control;
36071c814e9SPrajna Rajendra Kumar 
36171c814e9SPrajna Rajendra Kumar 	control = mpfs_spi_read(spi, REG_CONTROL);
36271c814e9SPrajna Rajendra Kumar 	if (spi->clk_mode)
36371c814e9SPrajna Rajendra Kumar 		control |= CONTROL_CLKMODE;
36471c814e9SPrajna Rajendra Kumar 	else
36571c814e9SPrajna Rajendra Kumar 		control &= ~CONTROL_CLKMODE;
36671c814e9SPrajna Rajendra Kumar 
36771c814e9SPrajna Rajendra Kumar 	mpfs_spi_write(spi, REG_CLK_GEN, spi->clk_gen);
36871c814e9SPrajna Rajendra Kumar 	mpfs_spi_write(spi, REG_CONTROL, control);
36971c814e9SPrajna Rajendra Kumar }
37071c814e9SPrajna Rajendra Kumar 
mpfs_spi_set_mode(struct mpfs_spi * spi,unsigned int mode)37171c814e9SPrajna Rajendra Kumar static inline void mpfs_spi_set_mode(struct mpfs_spi *spi, unsigned int mode)
37271c814e9SPrajna Rajendra Kumar {
37371c814e9SPrajna Rajendra Kumar 	u32 mode_val;
37471c814e9SPrajna Rajendra Kumar 	u32 control = mpfs_spi_read(spi, REG_CONTROL);
37571c814e9SPrajna Rajendra Kumar 
37671c814e9SPrajna Rajendra Kumar 	switch (mode & SPI_MODE_X_MASK) {
37771c814e9SPrajna Rajendra Kumar 	case SPI_MODE_0:
37871c814e9SPrajna Rajendra Kumar 		mode_val = 0;
37971c814e9SPrajna Rajendra Kumar 		break;
38071c814e9SPrajna Rajendra Kumar 	case SPI_MODE_1:
38171c814e9SPrajna Rajendra Kumar 		mode_val = CONTROL_SPH;
38271c814e9SPrajna Rajendra Kumar 		break;
38371c814e9SPrajna Rajendra Kumar 	case SPI_MODE_2:
38471c814e9SPrajna Rajendra Kumar 		mode_val = CONTROL_SPO;
38571c814e9SPrajna Rajendra Kumar 		break;
38671c814e9SPrajna Rajendra Kumar 	case SPI_MODE_3:
38771c814e9SPrajna Rajendra Kumar 		mode_val = CONTROL_SPH | CONTROL_SPO;
38871c814e9SPrajna Rajendra Kumar 		break;
38971c814e9SPrajna Rajendra Kumar 	}
39071c814e9SPrajna Rajendra Kumar 
39171c814e9SPrajna Rajendra Kumar 	/*
39271c814e9SPrajna Rajendra Kumar 	 * Disable the SPI controller. Writes to the frame protocol have
39371c814e9SPrajna Rajendra Kumar 	 * no effect when the controller is enabled.
39471c814e9SPrajna Rajendra Kumar 	 */
39571c814e9SPrajna Rajendra Kumar 
39671c814e9SPrajna Rajendra Kumar 	control &= ~CONTROL_ENABLE;
39771c814e9SPrajna Rajendra Kumar 	mpfs_spi_write(spi, REG_CONTROL, control);
39871c814e9SPrajna Rajendra Kumar 
39971c814e9SPrajna Rajendra Kumar 	control &= ~(SPI_MODE_X_MASK << MODE_X_MASK_SHIFT);
40071c814e9SPrajna Rajendra Kumar 	control |= mode_val;
40171c814e9SPrajna Rajendra Kumar 
40271c814e9SPrajna Rajendra Kumar 	mpfs_spi_write(spi, REG_CONTROL, control);
40371c814e9SPrajna Rajendra Kumar 
40471c814e9SPrajna Rajendra Kumar 	control |= CONTROL_ENABLE;
40571c814e9SPrajna Rajendra Kumar 	mpfs_spi_write(spi, REG_CONTROL, control);
40671c814e9SPrajna Rajendra Kumar }
40771c814e9SPrajna Rajendra Kumar 
mpfs_spi_interrupt(int irq,void * dev_id)40871c814e9SPrajna Rajendra Kumar static irqreturn_t mpfs_spi_interrupt(int irq, void *dev_id)
40971c814e9SPrajna Rajendra Kumar {
41071c814e9SPrajna Rajendra Kumar 	struct spi_controller *host = dev_id;
41171c814e9SPrajna Rajendra Kumar 	struct mpfs_spi *spi = spi_controller_get_devdata(host);
41271c814e9SPrajna Rajendra Kumar 	u32 intfield = mpfs_spi_read(spi, REG_MIS) & 0xf;
41371c814e9SPrajna Rajendra Kumar 	bool finalise = false;
41471c814e9SPrajna Rajendra Kumar 
41571c814e9SPrajna Rajendra Kumar 	/* Interrupt line may be shared and not for us at all */
41671c814e9SPrajna Rajendra Kumar 	if (intfield == 0)
41771c814e9SPrajna Rajendra Kumar 		return IRQ_NONE;
41871c814e9SPrajna Rajendra Kumar 
41971c814e9SPrajna Rajendra Kumar 	if (intfield & INT_RX_CHANNEL_OVERFLOW) {
42071c814e9SPrajna Rajendra Kumar 		mpfs_spi_write(spi, REG_INT_CLEAR, INT_RX_CHANNEL_OVERFLOW);
42171c814e9SPrajna Rajendra Kumar 		finalise = true;
42271c814e9SPrajna Rajendra Kumar 		dev_err(&host->dev,
42371c814e9SPrajna Rajendra Kumar 			"%s: RX OVERFLOW: rxlen: %d, txlen: %d\n", __func__,
42471c814e9SPrajna Rajendra Kumar 			spi->rx_len, spi->tx_len);
42571c814e9SPrajna Rajendra Kumar 	}
42671c814e9SPrajna Rajendra Kumar 
42771c814e9SPrajna Rajendra Kumar 	if (intfield & INT_TX_CHANNEL_UNDERRUN) {
42871c814e9SPrajna Rajendra Kumar 		mpfs_spi_write(spi, REG_INT_CLEAR, INT_TX_CHANNEL_UNDERRUN);
42971c814e9SPrajna Rajendra Kumar 		finalise = true;
43071c814e9SPrajna Rajendra Kumar 		dev_err(&host->dev,
43171c814e9SPrajna Rajendra Kumar 			"%s: TX UNDERFLOW: rxlen: %d, txlen: %d\n", __func__,
43271c814e9SPrajna Rajendra Kumar 			spi->rx_len, spi->tx_len);
43371c814e9SPrajna Rajendra Kumar 	}
43471c814e9SPrajna Rajendra Kumar 
43571c814e9SPrajna Rajendra Kumar 	if (finalise)
43671c814e9SPrajna Rajendra Kumar 		spi_finalize_current_transfer(host);
43771c814e9SPrajna Rajendra Kumar 
43871c814e9SPrajna Rajendra Kumar 	return IRQ_HANDLED;
43971c814e9SPrajna Rajendra Kumar }
44071c814e9SPrajna Rajendra Kumar 
mpfs_spi_calculate_clkgen(struct mpfs_spi * spi,unsigned long target_hz)44171c814e9SPrajna Rajendra Kumar static int mpfs_spi_calculate_clkgen(struct mpfs_spi *spi,
44271c814e9SPrajna Rajendra Kumar 				     unsigned long target_hz)
44371c814e9SPrajna Rajendra Kumar {
44471c814e9SPrajna Rajendra Kumar 	unsigned long clk_hz, spi_hz, clk_gen;
44571c814e9SPrajna Rajendra Kumar 
44671c814e9SPrajna Rajendra Kumar 	clk_hz = clk_get_rate(spi->clk);
44771c814e9SPrajna Rajendra Kumar 	if (!clk_hz)
44871c814e9SPrajna Rajendra Kumar 		return -EINVAL;
44971c814e9SPrajna Rajendra Kumar 	spi_hz = min(target_hz, clk_hz);
45071c814e9SPrajna Rajendra Kumar 
45171c814e9SPrajna Rajendra Kumar 	/*
45271c814e9SPrajna Rajendra Kumar 	 * There are two possible clock modes for the controller generated
45371c814e9SPrajna Rajendra Kumar 	 * clock's division ratio:
45471c814e9SPrajna Rajendra Kumar 	 * CLK_MODE = 0: 1 / (2^(CLK_GEN + 1)) where CLK_GEN = 0 to 15.
45571c814e9SPrajna Rajendra Kumar 	 * CLK_MODE = 1: 1 / (2 * CLK_GEN + 1) where CLK_GEN = 0 to 255.
45671c814e9SPrajna Rajendra Kumar 	 * First try mode 1, fall back to 0 and if we have tried both modes and
45771c814e9SPrajna Rajendra Kumar 	 * we /still/ can't get a good setting, we then throw the toys out of
45871c814e9SPrajna Rajendra Kumar 	 * the pram and give up
45971c814e9SPrajna Rajendra Kumar 	 * clk_gen is the register name for the clock divider on MPFS.
46071c814e9SPrajna Rajendra Kumar 	 */
46171c814e9SPrajna Rajendra Kumar 	clk_gen = DIV_ROUND_UP(clk_hz, 2 * spi_hz) - 1;
46271c814e9SPrajna Rajendra Kumar 	if (clk_gen > CLK_GEN_MODE1_MAX || clk_gen <= CLK_GEN_MIN) {
46371c814e9SPrajna Rajendra Kumar 		clk_gen = DIV_ROUND_UP(clk_hz, spi_hz);
46471c814e9SPrajna Rajendra Kumar 		clk_gen = fls(clk_gen) - 1;
46571c814e9SPrajna Rajendra Kumar 
46671c814e9SPrajna Rajendra Kumar 		if (clk_gen > CLK_GEN_MODE0_MAX)
46771c814e9SPrajna Rajendra Kumar 			return -EINVAL;
46871c814e9SPrajna Rajendra Kumar 
46971c814e9SPrajna Rajendra Kumar 		spi->clk_mode = 0;
47071c814e9SPrajna Rajendra Kumar 	} else {
47171c814e9SPrajna Rajendra Kumar 		spi->clk_mode = 1;
47271c814e9SPrajna Rajendra Kumar 	}
47371c814e9SPrajna Rajendra Kumar 
47471c814e9SPrajna Rajendra Kumar 	spi->clk_gen = clk_gen;
47571c814e9SPrajna Rajendra Kumar 	return 0;
47671c814e9SPrajna Rajendra Kumar }
47771c814e9SPrajna Rajendra Kumar 
mpfs_spi_transfer_one(struct spi_controller * host,struct spi_device * spi_dev,struct spi_transfer * xfer)47871c814e9SPrajna Rajendra Kumar static int mpfs_spi_transfer_one(struct spi_controller *host,
47971c814e9SPrajna Rajendra Kumar 				 struct spi_device *spi_dev,
48071c814e9SPrajna Rajendra Kumar 				 struct spi_transfer *xfer)
48171c814e9SPrajna Rajendra Kumar {
48271c814e9SPrajna Rajendra Kumar 	struct mpfs_spi *spi = spi_controller_get_devdata(host);
48371c814e9SPrajna Rajendra Kumar 	int ret;
48471c814e9SPrajna Rajendra Kumar 
48571c814e9SPrajna Rajendra Kumar 	ret = mpfs_spi_calculate_clkgen(spi, (unsigned long)xfer->speed_hz);
48671c814e9SPrajna Rajendra Kumar 	if (ret) {
48771c814e9SPrajna Rajendra Kumar 		dev_err(&host->dev, "failed to set clk_gen for target %u Hz\n", xfer->speed_hz);
48871c814e9SPrajna Rajendra Kumar 		return ret;
48971c814e9SPrajna Rajendra Kumar 	}
49071c814e9SPrajna Rajendra Kumar 
49171c814e9SPrajna Rajendra Kumar 	mpfs_spi_set_clk_gen(spi);
49271c814e9SPrajna Rajendra Kumar 
49371c814e9SPrajna Rajendra Kumar 	spi->tx_buf = xfer->tx_buf;
49471c814e9SPrajna Rajendra Kumar 	spi->rx_buf = xfer->rx_buf;
49571c814e9SPrajna Rajendra Kumar 	spi->tx_len = xfer->len;
49671c814e9SPrajna Rajendra Kumar 	spi->rx_len = xfer->len;
49771c814e9SPrajna Rajendra Kumar 	spi->n_bytes = roundup_pow_of_two(DIV_ROUND_UP(xfer->bits_per_word, BITS_PER_BYTE));
49871c814e9SPrajna Rajendra Kumar 
49971c814e9SPrajna Rajendra Kumar 	mpfs_spi_set_framesize(spi, xfer->bits_per_word);
50071c814e9SPrajna Rajendra Kumar 
50171c814e9SPrajna Rajendra Kumar 	mpfs_spi_write(spi, REG_COMMAND, COMMAND_RXFIFORST | COMMAND_TXFIFORST);
50271c814e9SPrajna Rajendra Kumar 
50371c814e9SPrajna Rajendra Kumar 	mpfs_spi_write(spi, REG_SLAVE_SELECT, spi->pending_slave_select);
50471c814e9SPrajna Rajendra Kumar 
50571c814e9SPrajna Rajendra Kumar 	while (spi->tx_len) {
50671c814e9SPrajna Rajendra Kumar 		int fifo_max = DIV_ROUND_UP(min(spi->tx_len, FIFO_DEPTH), spi->n_bytes);
50771c814e9SPrajna Rajendra Kumar 
50871c814e9SPrajna Rajendra Kumar 		mpfs_spi_write_fifo(spi, fifo_max);
50971c814e9SPrajna Rajendra Kumar 		mpfs_spi_read_fifo(spi, fifo_max);
51071c814e9SPrajna Rajendra Kumar 	}
51171c814e9SPrajna Rajendra Kumar 
51271c814e9SPrajna Rajendra Kumar 	spi_finalize_current_transfer(host);
51371c814e9SPrajna Rajendra Kumar 	return 1;
51471c814e9SPrajna Rajendra Kumar }
51571c814e9SPrajna Rajendra Kumar 
mpfs_spi_prepare_message(struct spi_controller * host,struct spi_message * msg)51671c814e9SPrajna Rajendra Kumar static int mpfs_spi_prepare_message(struct spi_controller *host,
51771c814e9SPrajna Rajendra Kumar 				    struct spi_message *msg)
51871c814e9SPrajna Rajendra Kumar {
51971c814e9SPrajna Rajendra Kumar 	struct spi_device *spi_dev = msg->spi;
52071c814e9SPrajna Rajendra Kumar 	struct mpfs_spi *spi = spi_controller_get_devdata(host);
52171c814e9SPrajna Rajendra Kumar 
52271c814e9SPrajna Rajendra Kumar 	mpfs_spi_set_mode(spi, spi_dev->mode);
52371c814e9SPrajna Rajendra Kumar 
52471c814e9SPrajna Rajendra Kumar 	return 0;
52571c814e9SPrajna Rajendra Kumar }
52671c814e9SPrajna Rajendra Kumar 
mpfs_spi_probe(struct platform_device * pdev)52771c814e9SPrajna Rajendra Kumar static int mpfs_spi_probe(struct platform_device *pdev)
52871c814e9SPrajna Rajendra Kumar {
52971c814e9SPrajna Rajendra Kumar 	struct spi_controller *host;
53071c814e9SPrajna Rajendra Kumar 	struct mpfs_spi *spi;
53171c814e9SPrajna Rajendra Kumar 	struct resource *res;
53271c814e9SPrajna Rajendra Kumar 	u32 num_cs;
53371c814e9SPrajna Rajendra Kumar 	int ret = 0;
53471c814e9SPrajna Rajendra Kumar 
53571c814e9SPrajna Rajendra Kumar 	host = devm_spi_alloc_host(&pdev->dev, sizeof(*spi));
53671c814e9SPrajna Rajendra Kumar 	if (!host)
53771c814e9SPrajna Rajendra Kumar 		return dev_err_probe(&pdev->dev, -ENOMEM,
53871c814e9SPrajna Rajendra Kumar 				     "unable to allocate host for SPI controller\n");
53971c814e9SPrajna Rajendra Kumar 
54071c814e9SPrajna Rajendra Kumar 	platform_set_drvdata(pdev, host);
54171c814e9SPrajna Rajendra Kumar 
54271c814e9SPrajna Rajendra Kumar 	if (of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs))
54371c814e9SPrajna Rajendra Kumar 		num_cs = MAX_CS;
54471c814e9SPrajna Rajendra Kumar 
54571c814e9SPrajna Rajendra Kumar 	host->num_chipselect = num_cs;
54671c814e9SPrajna Rajendra Kumar 	host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
54771c814e9SPrajna Rajendra Kumar 	host->use_gpio_descriptors = true;
54871c814e9SPrajna Rajendra Kumar 	host->setup = mpfs_spi_setup;
54971c814e9SPrajna Rajendra Kumar 	host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
55071c814e9SPrajna Rajendra Kumar 	host->transfer_one = mpfs_spi_transfer_one;
55171c814e9SPrajna Rajendra Kumar 	host->prepare_message = mpfs_spi_prepare_message;
55271c814e9SPrajna Rajendra Kumar 	host->set_cs = mpfs_spi_set_cs;
55371c814e9SPrajna Rajendra Kumar 	host->dev.of_node = pdev->dev.of_node;
55471c814e9SPrajna Rajendra Kumar 
55571c814e9SPrajna Rajendra Kumar 	spi = spi_controller_get_devdata(host);
55671c814e9SPrajna Rajendra Kumar 
55771c814e9SPrajna Rajendra Kumar 	spi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
55871c814e9SPrajna Rajendra Kumar 	if (IS_ERR(spi->regs))
55971c814e9SPrajna Rajendra Kumar 		return PTR_ERR(spi->regs);
56071c814e9SPrajna Rajendra Kumar 
56171c814e9SPrajna Rajendra Kumar 	spi->irq = platform_get_irq(pdev, 0);
56271c814e9SPrajna Rajendra Kumar 	if (spi->irq < 0)
56371c814e9SPrajna Rajendra Kumar 		return spi->irq;
56471c814e9SPrajna Rajendra Kumar 
56571c814e9SPrajna Rajendra Kumar 	ret = devm_request_irq(&pdev->dev, spi->irq, mpfs_spi_interrupt,
56671c814e9SPrajna Rajendra Kumar 			       IRQF_SHARED, dev_name(&pdev->dev), host);
56771c814e9SPrajna Rajendra Kumar 	if (ret)
56871c814e9SPrajna Rajendra Kumar 		return dev_err_probe(&pdev->dev, ret,
56971c814e9SPrajna Rajendra Kumar 				     "could not request irq\n");
57071c814e9SPrajna Rajendra Kumar 
57171c814e9SPrajna Rajendra Kumar 	spi->clk = devm_clk_get_enabled(&pdev->dev, NULL);
57271c814e9SPrajna Rajendra Kumar 	if (IS_ERR(spi->clk))
57371c814e9SPrajna Rajendra Kumar 		return dev_err_probe(&pdev->dev, PTR_ERR(spi->clk),
57471c814e9SPrajna Rajendra Kumar 				     "could not get clk\n");
57571c814e9SPrajna Rajendra Kumar 
57671c814e9SPrajna Rajendra Kumar 	mpfs_spi_init(host, spi);
57771c814e9SPrajna Rajendra Kumar 
57871c814e9SPrajna Rajendra Kumar 	ret = devm_spi_register_controller(&pdev->dev, host);
57971c814e9SPrajna Rajendra Kumar 	if (ret) {
580*a8a31361SChristophe JAILLET 		mpfs_spi_disable_ints(spi);
58171c814e9SPrajna Rajendra Kumar 		mpfs_spi_disable(spi);
58271c814e9SPrajna Rajendra Kumar 		return dev_err_probe(&pdev->dev, ret,
58371c814e9SPrajna Rajendra Kumar 				     "unable to register host for SPI controller\n");
58471c814e9SPrajna Rajendra Kumar 	}
58571c814e9SPrajna Rajendra Kumar 
58671c814e9SPrajna Rajendra Kumar 	dev_info(&pdev->dev, "Registered SPI controller %d\n", host->bus_num);
58771c814e9SPrajna Rajendra Kumar 
58871c814e9SPrajna Rajendra Kumar 	return 0;
58971c814e9SPrajna Rajendra Kumar }
59071c814e9SPrajna Rajendra Kumar 
mpfs_spi_remove(struct platform_device * pdev)59171c814e9SPrajna Rajendra Kumar static void mpfs_spi_remove(struct platform_device *pdev)
59271c814e9SPrajna Rajendra Kumar {
59371c814e9SPrajna Rajendra Kumar 	struct spi_controller *host  = platform_get_drvdata(pdev);
59471c814e9SPrajna Rajendra Kumar 	struct mpfs_spi *spi = spi_controller_get_devdata(host);
59571c814e9SPrajna Rajendra Kumar 
59671c814e9SPrajna Rajendra Kumar 	mpfs_spi_disable_ints(spi);
59771c814e9SPrajna Rajendra Kumar 	mpfs_spi_disable(spi);
59871c814e9SPrajna Rajendra Kumar }
59971c814e9SPrajna Rajendra Kumar 
60071c814e9SPrajna Rajendra Kumar #define MICROCHIP_SPI_PM_OPS (NULL)
60171c814e9SPrajna Rajendra Kumar 
60271c814e9SPrajna Rajendra Kumar /*
60371c814e9SPrajna Rajendra Kumar  * Platform driver data structure
60471c814e9SPrajna Rajendra Kumar  */
60571c814e9SPrajna Rajendra Kumar 
60671c814e9SPrajna Rajendra Kumar #if defined(CONFIG_OF)
60771c814e9SPrajna Rajendra Kumar static const struct of_device_id mpfs_spi_dt_ids[] = {
60871c814e9SPrajna Rajendra Kumar 	{ .compatible = "microchip,mpfs-spi" },
60971c814e9SPrajna Rajendra Kumar 	{ /* sentinel */ }
61071c814e9SPrajna Rajendra Kumar };
61171c814e9SPrajna Rajendra Kumar MODULE_DEVICE_TABLE(of, mpfs_spi_dt_ids);
61271c814e9SPrajna Rajendra Kumar #endif
61371c814e9SPrajna Rajendra Kumar 
61471c814e9SPrajna Rajendra Kumar static struct platform_driver mpfs_spi_driver = {
61571c814e9SPrajna Rajendra Kumar 	.probe = mpfs_spi_probe,
61671c814e9SPrajna Rajendra Kumar 	.driver = {
61771c814e9SPrajna Rajendra Kumar 		.name = "microchip-spi",
61871c814e9SPrajna Rajendra Kumar 		.pm = MICROCHIP_SPI_PM_OPS,
61971c814e9SPrajna Rajendra Kumar 		.of_match_table = of_match_ptr(mpfs_spi_dt_ids),
62071c814e9SPrajna Rajendra Kumar 	},
62171c814e9SPrajna Rajendra Kumar 	.remove = mpfs_spi_remove,
62271c814e9SPrajna Rajendra Kumar };
62371c814e9SPrajna Rajendra Kumar module_platform_driver(mpfs_spi_driver);
62471c814e9SPrajna Rajendra Kumar MODULE_DESCRIPTION("Microchip coreSPI SPI controller driver");
62571c814e9SPrajna Rajendra Kumar MODULE_AUTHOR("Daire McNamara <daire.mcnamara@microchip.com>");
62671c814e9SPrajna Rajendra Kumar MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");
62771c814e9SPrajna Rajendra Kumar MODULE_LICENSE("GPL");
628