162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * PIC32 Quad SPI controller driver.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Purna Chandra Mandal <purna.mandal@microchip.com>
662306a36Sopenharmony_ci * Copyright (c) 2016, Microchip Technology Inc.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/clk.h>
1062306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1162306a36Sopenharmony_ci#include <linux/interrupt.h>
1262306a36Sopenharmony_ci#include <linux/io.h>
1362306a36Sopenharmony_ci#include <linux/iopoll.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/of.h>
1662306a36Sopenharmony_ci#include <linux/platform_device.h>
1762306a36Sopenharmony_ci#include <linux/slab.h>
1862306a36Sopenharmony_ci#include <linux/spi/spi.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* SQI registers */
2162306a36Sopenharmony_ci#define PESQI_XIP_CONF1_REG	0x00
2262306a36Sopenharmony_ci#define PESQI_XIP_CONF2_REG	0x04
2362306a36Sopenharmony_ci#define PESQI_CONF_REG		0x08
2462306a36Sopenharmony_ci#define PESQI_CTRL_REG		0x0C
2562306a36Sopenharmony_ci#define PESQI_CLK_CTRL_REG	0x10
2662306a36Sopenharmony_ci#define PESQI_CMD_THRES_REG	0x14
2762306a36Sopenharmony_ci#define PESQI_INT_THRES_REG	0x18
2862306a36Sopenharmony_ci#define PESQI_INT_ENABLE_REG	0x1C
2962306a36Sopenharmony_ci#define PESQI_INT_STAT_REG	0x20
3062306a36Sopenharmony_ci#define PESQI_TX_DATA_REG	0x24
3162306a36Sopenharmony_ci#define PESQI_RX_DATA_REG	0x28
3262306a36Sopenharmony_ci#define PESQI_STAT1_REG		0x2C
3362306a36Sopenharmony_ci#define PESQI_STAT2_REG		0x30
3462306a36Sopenharmony_ci#define PESQI_BD_CTRL_REG	0x34
3562306a36Sopenharmony_ci#define PESQI_BD_CUR_ADDR_REG	0x38
3662306a36Sopenharmony_ci#define PESQI_BD_BASE_ADDR_REG	0x40
3762306a36Sopenharmony_ci#define PESQI_BD_STAT_REG	0x44
3862306a36Sopenharmony_ci#define PESQI_BD_POLL_CTRL_REG	0x48
3962306a36Sopenharmony_ci#define PESQI_BD_TX_DMA_STAT_REG	0x4C
4062306a36Sopenharmony_ci#define PESQI_BD_RX_DMA_STAT_REG	0x50
4162306a36Sopenharmony_ci#define PESQI_THRES_REG		0x54
4262306a36Sopenharmony_ci#define PESQI_INT_SIGEN_REG	0x58
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/* PESQI_CONF_REG fields */
4562306a36Sopenharmony_ci#define PESQI_MODE		0x7
4662306a36Sopenharmony_ci#define  PESQI_MODE_BOOT	0
4762306a36Sopenharmony_ci#define  PESQI_MODE_PIO		1
4862306a36Sopenharmony_ci#define  PESQI_MODE_DMA		2
4962306a36Sopenharmony_ci#define  PESQI_MODE_XIP		3
5062306a36Sopenharmony_ci#define PESQI_MODE_SHIFT	0
5162306a36Sopenharmony_ci#define PESQI_CPHA		BIT(3)
5262306a36Sopenharmony_ci#define PESQI_CPOL		BIT(4)
5362306a36Sopenharmony_ci#define PESQI_LSBF		BIT(5)
5462306a36Sopenharmony_ci#define PESQI_RXLATCH		BIT(7)
5562306a36Sopenharmony_ci#define PESQI_SERMODE		BIT(8)
5662306a36Sopenharmony_ci#define PESQI_WP_EN		BIT(9)
5762306a36Sopenharmony_ci#define PESQI_HOLD_EN		BIT(10)
5862306a36Sopenharmony_ci#define PESQI_BURST_EN		BIT(12)
5962306a36Sopenharmony_ci#define PESQI_CS_CTRL_HW	BIT(15)
6062306a36Sopenharmony_ci#define PESQI_SOFT_RESET	BIT(16)
6162306a36Sopenharmony_ci#define PESQI_LANES_SHIFT	20
6262306a36Sopenharmony_ci#define  PESQI_SINGLE_LANE	0
6362306a36Sopenharmony_ci#define  PESQI_DUAL_LANE	1
6462306a36Sopenharmony_ci#define  PESQI_QUAD_LANE	2
6562306a36Sopenharmony_ci#define PESQI_CSEN_SHIFT	24
6662306a36Sopenharmony_ci#define PESQI_EN		BIT(23)
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/* PESQI_CLK_CTRL_REG fields */
6962306a36Sopenharmony_ci#define PESQI_CLK_EN		BIT(0)
7062306a36Sopenharmony_ci#define PESQI_CLK_STABLE	BIT(1)
7162306a36Sopenharmony_ci#define PESQI_CLKDIV_SHIFT	8
7262306a36Sopenharmony_ci#define PESQI_CLKDIV		0xff
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/* PESQI_INT_THR/CMD_THR_REG */
7562306a36Sopenharmony_ci#define PESQI_TXTHR_MASK	0x1f
7662306a36Sopenharmony_ci#define PESQI_TXTHR_SHIFT	8
7762306a36Sopenharmony_ci#define PESQI_RXTHR_MASK	0x1f
7862306a36Sopenharmony_ci#define PESQI_RXTHR_SHIFT	0
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci/* PESQI_INT_EN/INT_STAT/INT_SIG_EN_REG */
8162306a36Sopenharmony_ci#define PESQI_TXEMPTY		BIT(0)
8262306a36Sopenharmony_ci#define PESQI_TXFULL		BIT(1)
8362306a36Sopenharmony_ci#define PESQI_TXTHR		BIT(2)
8462306a36Sopenharmony_ci#define PESQI_RXEMPTY		BIT(3)
8562306a36Sopenharmony_ci#define PESQI_RXFULL		BIT(4)
8662306a36Sopenharmony_ci#define PESQI_RXTHR		BIT(5)
8762306a36Sopenharmony_ci#define PESQI_BDDONE		BIT(9)  /* BD processing complete */
8862306a36Sopenharmony_ci#define PESQI_PKTCOMP		BIT(10) /* packet processing complete */
8962306a36Sopenharmony_ci#define PESQI_DMAERR		BIT(11) /* error */
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/* PESQI_BD_CTRL_REG */
9262306a36Sopenharmony_ci#define PESQI_DMA_EN		BIT(0) /* enable DMA engine */
9362306a36Sopenharmony_ci#define PESQI_POLL_EN		BIT(1) /* enable polling */
9462306a36Sopenharmony_ci#define PESQI_BDP_START		BIT(2) /* start BD processor */
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/* PESQI controller buffer descriptor */
9762306a36Sopenharmony_cistruct buf_desc {
9862306a36Sopenharmony_ci	u32 bd_ctrl;	/* control */
9962306a36Sopenharmony_ci	u32 bd_status;	/* reserved */
10062306a36Sopenharmony_ci	u32 bd_addr;	/* DMA buffer addr */
10162306a36Sopenharmony_ci	u32 bd_nextp;	/* next item in chain */
10262306a36Sopenharmony_ci};
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/* bd_ctrl */
10562306a36Sopenharmony_ci#define BD_BUFLEN		0x1ff
10662306a36Sopenharmony_ci#define BD_CBD_INT_EN		BIT(16)	/* Current BD is processed */
10762306a36Sopenharmony_ci#define BD_PKT_INT_EN		BIT(17) /* All BDs of PKT processed */
10862306a36Sopenharmony_ci#define BD_LIFM			BIT(18) /* last data of pkt */
10962306a36Sopenharmony_ci#define BD_LAST			BIT(19) /* end of list */
11062306a36Sopenharmony_ci#define BD_DATA_RECV		BIT(20) /* receive data */
11162306a36Sopenharmony_ci#define BD_DDR			BIT(21) /* DDR mode */
11262306a36Sopenharmony_ci#define BD_DUAL			BIT(22)	/* Dual SPI */
11362306a36Sopenharmony_ci#define BD_QUAD			BIT(23) /* Quad SPI */
11462306a36Sopenharmony_ci#define BD_LSBF			BIT(25)	/* LSB First */
11562306a36Sopenharmony_ci#define BD_STAT_CHECK		BIT(27) /* Status poll */
11662306a36Sopenharmony_ci#define BD_DEVSEL_SHIFT		28	/* CS */
11762306a36Sopenharmony_ci#define BD_CS_DEASSERT		BIT(30) /* de-assert CS after current BD */
11862306a36Sopenharmony_ci#define BD_EN			BIT(31) /* BD owned by H/W */
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci/**
12162306a36Sopenharmony_ci * struct ring_desc - Representation of SQI ring descriptor
12262306a36Sopenharmony_ci * @list:	list element to add to free or used list.
12362306a36Sopenharmony_ci * @bd:		PESQI controller buffer descriptor
12462306a36Sopenharmony_ci * @bd_dma:	DMA address of PESQI controller buffer descriptor
12562306a36Sopenharmony_ci * @xfer_len:	transfer length
12662306a36Sopenharmony_ci */
12762306a36Sopenharmony_cistruct ring_desc {
12862306a36Sopenharmony_ci	struct list_head list;
12962306a36Sopenharmony_ci	struct buf_desc *bd;
13062306a36Sopenharmony_ci	dma_addr_t bd_dma;
13162306a36Sopenharmony_ci	u32 xfer_len;
13262306a36Sopenharmony_ci};
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci/* Global constants */
13562306a36Sopenharmony_ci#define PESQI_BD_BUF_LEN_MAX	256
13662306a36Sopenharmony_ci#define PESQI_BD_COUNT		256 /* max 64KB data per spi message */
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistruct pic32_sqi {
13962306a36Sopenharmony_ci	void __iomem		*regs;
14062306a36Sopenharmony_ci	struct clk		*sys_clk;
14162306a36Sopenharmony_ci	struct clk		*base_clk; /* drives spi clock */
14262306a36Sopenharmony_ci	struct spi_controller	*host;
14362306a36Sopenharmony_ci	int			irq;
14462306a36Sopenharmony_ci	struct completion	xfer_done;
14562306a36Sopenharmony_ci	struct ring_desc	*ring;
14662306a36Sopenharmony_ci	void			*bd;
14762306a36Sopenharmony_ci	dma_addr_t		bd_dma;
14862306a36Sopenharmony_ci	struct list_head	bd_list_free; /* free */
14962306a36Sopenharmony_ci	struct list_head	bd_list_used; /* allocated */
15062306a36Sopenharmony_ci	struct spi_device	*cur_spi;
15162306a36Sopenharmony_ci	u32			cur_speed;
15262306a36Sopenharmony_ci	u8			cur_mode;
15362306a36Sopenharmony_ci};
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic inline void pic32_setbits(void __iomem *reg, u32 set)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	writel(readl(reg) | set, reg);
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic inline void pic32_clrbits(void __iomem *reg, u32 clr)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	writel(readl(reg) & ~clr, reg);
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic int pic32_sqi_set_clk_rate(struct pic32_sqi *sqi, u32 sck)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	u32 val, div;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	/* div = base_clk / (2 * spi_clk) */
17062306a36Sopenharmony_ci	div = clk_get_rate(sqi->base_clk) / (2 * sck);
17162306a36Sopenharmony_ci	div &= PESQI_CLKDIV;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	val = readl(sqi->regs + PESQI_CLK_CTRL_REG);
17462306a36Sopenharmony_ci	/* apply new divider */
17562306a36Sopenharmony_ci	val &= ~(PESQI_CLK_STABLE | (PESQI_CLKDIV << PESQI_CLKDIV_SHIFT));
17662306a36Sopenharmony_ci	val |= div << PESQI_CLKDIV_SHIFT;
17762306a36Sopenharmony_ci	writel(val, sqi->regs + PESQI_CLK_CTRL_REG);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	/* wait for stability */
18062306a36Sopenharmony_ci	return readl_poll_timeout(sqi->regs + PESQI_CLK_CTRL_REG, val,
18162306a36Sopenharmony_ci				  val & PESQI_CLK_STABLE, 1, 5000);
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic inline void pic32_sqi_enable_int(struct pic32_sqi *sqi)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	u32 mask = PESQI_DMAERR | PESQI_BDDONE | PESQI_PKTCOMP;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	writel(mask, sqi->regs + PESQI_INT_ENABLE_REG);
18962306a36Sopenharmony_ci	/* INT_SIGEN works as interrupt-gate to INTR line */
19062306a36Sopenharmony_ci	writel(mask, sqi->regs + PESQI_INT_SIGEN_REG);
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic inline void pic32_sqi_disable_int(struct pic32_sqi *sqi)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	writel(0, sqi->regs + PESQI_INT_ENABLE_REG);
19662306a36Sopenharmony_ci	writel(0, sqi->regs + PESQI_INT_SIGEN_REG);
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_cistatic irqreturn_t pic32_sqi_isr(int irq, void *dev_id)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct pic32_sqi *sqi = dev_id;
20262306a36Sopenharmony_ci	u32 enable, status;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	enable = readl(sqi->regs + PESQI_INT_ENABLE_REG);
20562306a36Sopenharmony_ci	status = readl(sqi->regs + PESQI_INT_STAT_REG);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	/* check spurious interrupt */
20862306a36Sopenharmony_ci	if (!status)
20962306a36Sopenharmony_ci		return IRQ_NONE;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	if (status & PESQI_DMAERR) {
21262306a36Sopenharmony_ci		enable = 0;
21362306a36Sopenharmony_ci		goto irq_done;
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	if (status & PESQI_TXTHR)
21762306a36Sopenharmony_ci		enable &= ~(PESQI_TXTHR | PESQI_TXFULL | PESQI_TXEMPTY);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	if (status & PESQI_RXTHR)
22062306a36Sopenharmony_ci		enable &= ~(PESQI_RXTHR | PESQI_RXFULL | PESQI_RXEMPTY);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	if (status & PESQI_BDDONE)
22362306a36Sopenharmony_ci		enable &= ~PESQI_BDDONE;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	/* packet processing completed */
22662306a36Sopenharmony_ci	if (status & PESQI_PKTCOMP) {
22762306a36Sopenharmony_ci		/* mask all interrupts */
22862306a36Sopenharmony_ci		enable = 0;
22962306a36Sopenharmony_ci		/* complete trasaction */
23062306a36Sopenharmony_ci		complete(&sqi->xfer_done);
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ciirq_done:
23462306a36Sopenharmony_ci	/* interrupts are sticky, so mask when handled */
23562306a36Sopenharmony_ci	writel(enable, sqi->regs + PESQI_INT_ENABLE_REG);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	return IRQ_HANDLED;
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic struct ring_desc *ring_desc_get(struct pic32_sqi *sqi)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	struct ring_desc *rdesc;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	if (list_empty(&sqi->bd_list_free))
24562306a36Sopenharmony_ci		return NULL;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	rdesc = list_first_entry(&sqi->bd_list_free, struct ring_desc, list);
24862306a36Sopenharmony_ci	list_move_tail(&rdesc->list, &sqi->bd_list_used);
24962306a36Sopenharmony_ci	return rdesc;
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic void ring_desc_put(struct pic32_sqi *sqi, struct ring_desc *rdesc)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	list_move(&rdesc->list, &sqi->bd_list_free);
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic int pic32_sqi_one_transfer(struct pic32_sqi *sqi,
25862306a36Sopenharmony_ci				  struct spi_message *mesg,
25962306a36Sopenharmony_ci				  struct spi_transfer *xfer)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	struct spi_device *spi = mesg->spi;
26262306a36Sopenharmony_ci	struct scatterlist *sg, *sgl;
26362306a36Sopenharmony_ci	struct ring_desc *rdesc;
26462306a36Sopenharmony_ci	struct buf_desc *bd;
26562306a36Sopenharmony_ci	int nents, i;
26662306a36Sopenharmony_ci	u32 bd_ctrl;
26762306a36Sopenharmony_ci	u32 nbits;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	/* Device selection */
27062306a36Sopenharmony_ci	bd_ctrl = spi_get_chipselect(spi, 0) << BD_DEVSEL_SHIFT;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	/* half-duplex: select transfer buffer, direction and lane */
27362306a36Sopenharmony_ci	if (xfer->rx_buf) {
27462306a36Sopenharmony_ci		bd_ctrl |= BD_DATA_RECV;
27562306a36Sopenharmony_ci		nbits = xfer->rx_nbits;
27662306a36Sopenharmony_ci		sgl = xfer->rx_sg.sgl;
27762306a36Sopenharmony_ci		nents = xfer->rx_sg.nents;
27862306a36Sopenharmony_ci	} else {
27962306a36Sopenharmony_ci		nbits = xfer->tx_nbits;
28062306a36Sopenharmony_ci		sgl = xfer->tx_sg.sgl;
28162306a36Sopenharmony_ci		nents = xfer->tx_sg.nents;
28262306a36Sopenharmony_ci	}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	if (nbits & SPI_NBITS_QUAD)
28562306a36Sopenharmony_ci		bd_ctrl |= BD_QUAD;
28662306a36Sopenharmony_ci	else if (nbits & SPI_NBITS_DUAL)
28762306a36Sopenharmony_ci		bd_ctrl |= BD_DUAL;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	/* LSB first */
29062306a36Sopenharmony_ci	if (spi->mode & SPI_LSB_FIRST)
29162306a36Sopenharmony_ci		bd_ctrl |= BD_LSBF;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	/* ownership to hardware */
29462306a36Sopenharmony_ci	bd_ctrl |= BD_EN;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	for_each_sg(sgl, sg, nents, i) {
29762306a36Sopenharmony_ci		/* get ring descriptor */
29862306a36Sopenharmony_ci		rdesc = ring_desc_get(sqi);
29962306a36Sopenharmony_ci		if (!rdesc)
30062306a36Sopenharmony_ci			break;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci		bd = rdesc->bd;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci		/* BD CTRL: length */
30562306a36Sopenharmony_ci		rdesc->xfer_len = sg_dma_len(sg);
30662306a36Sopenharmony_ci		bd->bd_ctrl = bd_ctrl;
30762306a36Sopenharmony_ci		bd->bd_ctrl |= rdesc->xfer_len;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci		/* BD STAT */
31062306a36Sopenharmony_ci		bd->bd_status = 0;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci		/* BD BUFFER ADDRESS */
31362306a36Sopenharmony_ci		bd->bd_addr = sg->dma_address;
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	return 0;
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistatic int pic32_sqi_prepare_hardware(struct spi_controller *host)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	struct pic32_sqi *sqi = spi_controller_get_devdata(host);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	/* enable spi interface */
32462306a36Sopenharmony_ci	pic32_setbits(sqi->regs + PESQI_CONF_REG, PESQI_EN);
32562306a36Sopenharmony_ci	/* enable spi clk */
32662306a36Sopenharmony_ci	pic32_setbits(sqi->regs + PESQI_CLK_CTRL_REG, PESQI_CLK_EN);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	return 0;
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic bool pic32_sqi_can_dma(struct spi_controller *host,
33262306a36Sopenharmony_ci			      struct spi_device *spi,
33362306a36Sopenharmony_ci			      struct spi_transfer *x)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	/* Do DMA irrespective of transfer size */
33662306a36Sopenharmony_ci	return true;
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic int pic32_sqi_one_message(struct spi_controller *host,
34062306a36Sopenharmony_ci				 struct spi_message *msg)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	struct spi_device *spi = msg->spi;
34362306a36Sopenharmony_ci	struct ring_desc *rdesc, *next;
34462306a36Sopenharmony_ci	struct spi_transfer *xfer;
34562306a36Sopenharmony_ci	struct pic32_sqi *sqi;
34662306a36Sopenharmony_ci	int ret = 0, mode;
34762306a36Sopenharmony_ci	unsigned long timeout;
34862306a36Sopenharmony_ci	u32 val;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	sqi = spi_controller_get_devdata(host);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	reinit_completion(&sqi->xfer_done);
35362306a36Sopenharmony_ci	msg->actual_length = 0;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	/* We can't handle spi_transfer specific "speed_hz", "bits_per_word"
35662306a36Sopenharmony_ci	 * and "delay_usecs". But spi_device specific speed and mode change
35762306a36Sopenharmony_ci	 * can be handled at best during spi chip-select switch.
35862306a36Sopenharmony_ci	 */
35962306a36Sopenharmony_ci	if (sqi->cur_spi != spi) {
36062306a36Sopenharmony_ci		/* set spi speed */
36162306a36Sopenharmony_ci		if (sqi->cur_speed != spi->max_speed_hz) {
36262306a36Sopenharmony_ci			sqi->cur_speed = spi->max_speed_hz;
36362306a36Sopenharmony_ci			ret = pic32_sqi_set_clk_rate(sqi, spi->max_speed_hz);
36462306a36Sopenharmony_ci			if (ret)
36562306a36Sopenharmony_ci				dev_warn(&spi->dev, "set_clk, %d\n", ret);
36662306a36Sopenharmony_ci		}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci		/* set spi mode */
36962306a36Sopenharmony_ci		mode = spi->mode & (SPI_MODE_3 | SPI_LSB_FIRST);
37062306a36Sopenharmony_ci		if (sqi->cur_mode != mode) {
37162306a36Sopenharmony_ci			val = readl(sqi->regs + PESQI_CONF_REG);
37262306a36Sopenharmony_ci			val &= ~(PESQI_CPOL | PESQI_CPHA | PESQI_LSBF);
37362306a36Sopenharmony_ci			if (mode & SPI_CPOL)
37462306a36Sopenharmony_ci				val |= PESQI_CPOL;
37562306a36Sopenharmony_ci			if (mode & SPI_LSB_FIRST)
37662306a36Sopenharmony_ci				val |= PESQI_LSBF;
37762306a36Sopenharmony_ci			val |= PESQI_CPHA;
37862306a36Sopenharmony_ci			writel(val, sqi->regs + PESQI_CONF_REG);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci			sqi->cur_mode = mode;
38162306a36Sopenharmony_ci		}
38262306a36Sopenharmony_ci		sqi->cur_spi = spi;
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	/* prepare hardware desc-list(BD) for transfer(s) */
38662306a36Sopenharmony_ci	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
38762306a36Sopenharmony_ci		ret = pic32_sqi_one_transfer(sqi, msg, xfer);
38862306a36Sopenharmony_ci		if (ret) {
38962306a36Sopenharmony_ci			dev_err(&spi->dev, "xfer %p err\n", xfer);
39062306a36Sopenharmony_ci			goto xfer_out;
39162306a36Sopenharmony_ci		}
39262306a36Sopenharmony_ci	}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	/* BDs are prepared and chained. Now mark LAST_BD, CS_DEASSERT at last
39562306a36Sopenharmony_ci	 * element of the list.
39662306a36Sopenharmony_ci	 */
39762306a36Sopenharmony_ci	rdesc = list_last_entry(&sqi->bd_list_used, struct ring_desc, list);
39862306a36Sopenharmony_ci	rdesc->bd->bd_ctrl |= BD_LAST | BD_CS_DEASSERT |
39962306a36Sopenharmony_ci			      BD_LIFM | BD_PKT_INT_EN;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	/* set base address BD list for DMA engine */
40262306a36Sopenharmony_ci	rdesc = list_first_entry(&sqi->bd_list_used, struct ring_desc, list);
40362306a36Sopenharmony_ci	writel(rdesc->bd_dma, sqi->regs + PESQI_BD_BASE_ADDR_REG);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	/* enable interrupt */
40662306a36Sopenharmony_ci	pic32_sqi_enable_int(sqi);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	/* enable DMA engine */
40962306a36Sopenharmony_ci	val = PESQI_DMA_EN | PESQI_POLL_EN | PESQI_BDP_START;
41062306a36Sopenharmony_ci	writel(val, sqi->regs + PESQI_BD_CTRL_REG);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	/* wait for xfer completion */
41362306a36Sopenharmony_ci	timeout = wait_for_completion_timeout(&sqi->xfer_done, 5 * HZ);
41462306a36Sopenharmony_ci	if (timeout == 0) {
41562306a36Sopenharmony_ci		dev_err(&sqi->host->dev, "wait timedout/interrupted\n");
41662306a36Sopenharmony_ci		ret = -ETIMEDOUT;
41762306a36Sopenharmony_ci		msg->status = ret;
41862306a36Sopenharmony_ci	} else {
41962306a36Sopenharmony_ci		/* success */
42062306a36Sopenharmony_ci		msg->status = 0;
42162306a36Sopenharmony_ci		ret = 0;
42262306a36Sopenharmony_ci	}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	/* disable DMA */
42562306a36Sopenharmony_ci	writel(0, sqi->regs + PESQI_BD_CTRL_REG);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	pic32_sqi_disable_int(sqi);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cixfer_out:
43062306a36Sopenharmony_ci	list_for_each_entry_safe_reverse(rdesc, next,
43162306a36Sopenharmony_ci					 &sqi->bd_list_used, list) {
43262306a36Sopenharmony_ci		/* Update total byte transferred */
43362306a36Sopenharmony_ci		msg->actual_length += rdesc->xfer_len;
43462306a36Sopenharmony_ci		/* release ring descr */
43562306a36Sopenharmony_ci		ring_desc_put(sqi, rdesc);
43662306a36Sopenharmony_ci	}
43762306a36Sopenharmony_ci	spi_finalize_current_message(spi->controller);
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	return ret;
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_cistatic int pic32_sqi_unprepare_hardware(struct spi_controller *host)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	struct pic32_sqi *sqi = spi_controller_get_devdata(host);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	/* disable clk */
44762306a36Sopenharmony_ci	pic32_clrbits(sqi->regs + PESQI_CLK_CTRL_REG, PESQI_CLK_EN);
44862306a36Sopenharmony_ci	/* disable spi */
44962306a36Sopenharmony_ci	pic32_clrbits(sqi->regs + PESQI_CONF_REG, PESQI_EN);
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	return 0;
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_cistatic int ring_desc_ring_alloc(struct pic32_sqi *sqi)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	struct ring_desc *rdesc;
45762306a36Sopenharmony_ci	struct buf_desc *bd;
45862306a36Sopenharmony_ci	int i;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	/* allocate coherent DMAable memory for hardware buffer descriptors. */
46162306a36Sopenharmony_ci	sqi->bd = dma_alloc_coherent(&sqi->host->dev,
46262306a36Sopenharmony_ci				     sizeof(*bd) * PESQI_BD_COUNT,
46362306a36Sopenharmony_ci				     &sqi->bd_dma, GFP_KERNEL);
46462306a36Sopenharmony_ci	if (!sqi->bd) {
46562306a36Sopenharmony_ci		dev_err(&sqi->host->dev, "failed allocating dma buffer\n");
46662306a36Sopenharmony_ci		return -ENOMEM;
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	/* allocate software ring descriptors */
47062306a36Sopenharmony_ci	sqi->ring = kcalloc(PESQI_BD_COUNT, sizeof(*rdesc), GFP_KERNEL);
47162306a36Sopenharmony_ci	if (!sqi->ring) {
47262306a36Sopenharmony_ci		dma_free_coherent(&sqi->host->dev,
47362306a36Sopenharmony_ci				  sizeof(*bd) * PESQI_BD_COUNT,
47462306a36Sopenharmony_ci				  sqi->bd, sqi->bd_dma);
47562306a36Sopenharmony_ci		return -ENOMEM;
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	bd = (struct buf_desc *)sqi->bd;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	INIT_LIST_HEAD(&sqi->bd_list_free);
48162306a36Sopenharmony_ci	INIT_LIST_HEAD(&sqi->bd_list_used);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	/* initialize ring-desc */
48462306a36Sopenharmony_ci	for (i = 0, rdesc = sqi->ring; i < PESQI_BD_COUNT; i++, rdesc++) {
48562306a36Sopenharmony_ci		INIT_LIST_HEAD(&rdesc->list);
48662306a36Sopenharmony_ci		rdesc->bd = &bd[i];
48762306a36Sopenharmony_ci		rdesc->bd_dma = sqi->bd_dma + (void *)&bd[i] - (void *)bd;
48862306a36Sopenharmony_ci		list_add_tail(&rdesc->list, &sqi->bd_list_free);
48962306a36Sopenharmony_ci	}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	/* Prepare BD: chain to next BD(s) */
49262306a36Sopenharmony_ci	for (i = 0, rdesc = sqi->ring; i < PESQI_BD_COUNT - 1; i++)
49362306a36Sopenharmony_ci		bd[i].bd_nextp = rdesc[i + 1].bd_dma;
49462306a36Sopenharmony_ci	bd[PESQI_BD_COUNT - 1].bd_nextp = 0;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	return 0;
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_cistatic void ring_desc_ring_free(struct pic32_sqi *sqi)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	dma_free_coherent(&sqi->host->dev,
50262306a36Sopenharmony_ci			  sizeof(struct buf_desc) * PESQI_BD_COUNT,
50362306a36Sopenharmony_ci			  sqi->bd, sqi->bd_dma);
50462306a36Sopenharmony_ci	kfree(sqi->ring);
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_cistatic void pic32_sqi_hw_init(struct pic32_sqi *sqi)
50862306a36Sopenharmony_ci{
50962306a36Sopenharmony_ci	unsigned long flags;
51062306a36Sopenharmony_ci	u32 val;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	/* Soft-reset of PESQI controller triggers interrupt.
51362306a36Sopenharmony_ci	 * We are not yet ready to handle them so disable CPU
51462306a36Sopenharmony_ci	 * interrupt for the time being.
51562306a36Sopenharmony_ci	 */
51662306a36Sopenharmony_ci	local_irq_save(flags);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	/* assert soft-reset */
51962306a36Sopenharmony_ci	writel(PESQI_SOFT_RESET, sqi->regs + PESQI_CONF_REG);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	/* wait until clear */
52262306a36Sopenharmony_ci	readl_poll_timeout_atomic(sqi->regs + PESQI_CONF_REG, val,
52362306a36Sopenharmony_ci				  !(val & PESQI_SOFT_RESET), 1, 5000);
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	/* disable all interrupts */
52662306a36Sopenharmony_ci	pic32_sqi_disable_int(sqi);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	/* Now it is safe to enable back CPU interrupt */
52962306a36Sopenharmony_ci	local_irq_restore(flags);
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	/* tx and rx fifo interrupt threshold */
53262306a36Sopenharmony_ci	val = readl(sqi->regs + PESQI_CMD_THRES_REG);
53362306a36Sopenharmony_ci	val &= ~(PESQI_TXTHR_MASK << PESQI_TXTHR_SHIFT);
53462306a36Sopenharmony_ci	val &= ~(PESQI_RXTHR_MASK << PESQI_RXTHR_SHIFT);
53562306a36Sopenharmony_ci	val |= (1U << PESQI_TXTHR_SHIFT) | (1U << PESQI_RXTHR_SHIFT);
53662306a36Sopenharmony_ci	writel(val, sqi->regs + PESQI_CMD_THRES_REG);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	val = readl(sqi->regs + PESQI_INT_THRES_REG);
53962306a36Sopenharmony_ci	val &= ~(PESQI_TXTHR_MASK << PESQI_TXTHR_SHIFT);
54062306a36Sopenharmony_ci	val &= ~(PESQI_RXTHR_MASK << PESQI_RXTHR_SHIFT);
54162306a36Sopenharmony_ci	val |= (1U << PESQI_TXTHR_SHIFT) | (1U << PESQI_RXTHR_SHIFT);
54262306a36Sopenharmony_ci	writel(val, sqi->regs + PESQI_INT_THRES_REG);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	/* default configuration */
54562306a36Sopenharmony_ci	val = readl(sqi->regs + PESQI_CONF_REG);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	/* set mode: DMA */
54862306a36Sopenharmony_ci	val &= ~PESQI_MODE;
54962306a36Sopenharmony_ci	val |= PESQI_MODE_DMA << PESQI_MODE_SHIFT;
55062306a36Sopenharmony_ci	writel(val, sqi->regs + PESQI_CONF_REG);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	/* DATAEN - SQIID0-ID3 */
55362306a36Sopenharmony_ci	val |= PESQI_QUAD_LANE << PESQI_LANES_SHIFT;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	/* burst/INCR4 enable */
55662306a36Sopenharmony_ci	val |= PESQI_BURST_EN;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	/* CSEN - all CS */
55962306a36Sopenharmony_ci	val |= 3U << PESQI_CSEN_SHIFT;
56062306a36Sopenharmony_ci	writel(val, sqi->regs + PESQI_CONF_REG);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	/* write poll count */
56362306a36Sopenharmony_ci	writel(0, sqi->regs + PESQI_BD_POLL_CTRL_REG);
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	sqi->cur_speed = 0;
56662306a36Sopenharmony_ci	sqi->cur_mode = -1;
56762306a36Sopenharmony_ci}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_cistatic int pic32_sqi_probe(struct platform_device *pdev)
57062306a36Sopenharmony_ci{
57162306a36Sopenharmony_ci	struct spi_controller *host;
57262306a36Sopenharmony_ci	struct pic32_sqi *sqi;
57362306a36Sopenharmony_ci	int ret;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	host = spi_alloc_host(&pdev->dev, sizeof(*sqi));
57662306a36Sopenharmony_ci	if (!host)
57762306a36Sopenharmony_ci		return -ENOMEM;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	sqi = spi_controller_get_devdata(host);
58062306a36Sopenharmony_ci	sqi->host = host;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	sqi->regs = devm_platform_ioremap_resource(pdev, 0);
58362306a36Sopenharmony_ci	if (IS_ERR(sqi->regs)) {
58462306a36Sopenharmony_ci		ret = PTR_ERR(sqi->regs);
58562306a36Sopenharmony_ci		goto err_free_host;
58662306a36Sopenharmony_ci	}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	/* irq */
58962306a36Sopenharmony_ci	sqi->irq = platform_get_irq(pdev, 0);
59062306a36Sopenharmony_ci	if (sqi->irq < 0) {
59162306a36Sopenharmony_ci		ret = sqi->irq;
59262306a36Sopenharmony_ci		goto err_free_host;
59362306a36Sopenharmony_ci	}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	/* clocks */
59662306a36Sopenharmony_ci	sqi->sys_clk = devm_clk_get(&pdev->dev, "reg_ck");
59762306a36Sopenharmony_ci	if (IS_ERR(sqi->sys_clk)) {
59862306a36Sopenharmony_ci		ret = PTR_ERR(sqi->sys_clk);
59962306a36Sopenharmony_ci		dev_err(&pdev->dev, "no sys_clk ?\n");
60062306a36Sopenharmony_ci		goto err_free_host;
60162306a36Sopenharmony_ci	}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	sqi->base_clk = devm_clk_get(&pdev->dev, "spi_ck");
60462306a36Sopenharmony_ci	if (IS_ERR(sqi->base_clk)) {
60562306a36Sopenharmony_ci		ret = PTR_ERR(sqi->base_clk);
60662306a36Sopenharmony_ci		dev_err(&pdev->dev, "no base clk ?\n");
60762306a36Sopenharmony_ci		goto err_free_host;
60862306a36Sopenharmony_ci	}
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	ret = clk_prepare_enable(sqi->sys_clk);
61162306a36Sopenharmony_ci	if (ret) {
61262306a36Sopenharmony_ci		dev_err(&pdev->dev, "sys clk enable failed\n");
61362306a36Sopenharmony_ci		goto err_free_host;
61462306a36Sopenharmony_ci	}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	ret = clk_prepare_enable(sqi->base_clk);
61762306a36Sopenharmony_ci	if (ret) {
61862306a36Sopenharmony_ci		dev_err(&pdev->dev, "base clk enable failed\n");
61962306a36Sopenharmony_ci		clk_disable_unprepare(sqi->sys_clk);
62062306a36Sopenharmony_ci		goto err_free_host;
62162306a36Sopenharmony_ci	}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	init_completion(&sqi->xfer_done);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	/* initialize hardware */
62662306a36Sopenharmony_ci	pic32_sqi_hw_init(sqi);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	/* allocate buffers & descriptors */
62962306a36Sopenharmony_ci	ret = ring_desc_ring_alloc(sqi);
63062306a36Sopenharmony_ci	if (ret) {
63162306a36Sopenharmony_ci		dev_err(&pdev->dev, "ring alloc failed\n");
63262306a36Sopenharmony_ci		goto err_disable_clk;
63362306a36Sopenharmony_ci	}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	/* install irq handlers */
63662306a36Sopenharmony_ci	ret = request_irq(sqi->irq, pic32_sqi_isr, 0,
63762306a36Sopenharmony_ci			  dev_name(&pdev->dev), sqi);
63862306a36Sopenharmony_ci	if (ret < 0) {
63962306a36Sopenharmony_ci		dev_err(&pdev->dev, "request_irq(%d), failed\n", sqi->irq);
64062306a36Sopenharmony_ci		goto err_free_ring;
64162306a36Sopenharmony_ci	}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	/* register host */
64462306a36Sopenharmony_ci	host->num_chipselect	= 2;
64562306a36Sopenharmony_ci	host->max_speed_hz	= clk_get_rate(sqi->base_clk);
64662306a36Sopenharmony_ci	host->dma_alignment	= 32;
64762306a36Sopenharmony_ci	host->max_dma_len	= PESQI_BD_BUF_LEN_MAX;
64862306a36Sopenharmony_ci	host->dev.of_node	= pdev->dev.of_node;
64962306a36Sopenharmony_ci	host->mode_bits		= SPI_MODE_3 | SPI_MODE_0 | SPI_TX_DUAL |
65062306a36Sopenharmony_ci				  SPI_RX_DUAL | SPI_TX_QUAD | SPI_RX_QUAD;
65162306a36Sopenharmony_ci	host->flags		= SPI_CONTROLLER_HALF_DUPLEX;
65262306a36Sopenharmony_ci	host->can_dma		= pic32_sqi_can_dma;
65362306a36Sopenharmony_ci	host->bits_per_word_mask	= SPI_BPW_RANGE_MASK(8, 32);
65462306a36Sopenharmony_ci	host->transfer_one_message	= pic32_sqi_one_message;
65562306a36Sopenharmony_ci	host->prepare_transfer_hardware	= pic32_sqi_prepare_hardware;
65662306a36Sopenharmony_ci	host->unprepare_transfer_hardware	= pic32_sqi_unprepare_hardware;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	ret = devm_spi_register_controller(&pdev->dev, host);
65962306a36Sopenharmony_ci	if (ret) {
66062306a36Sopenharmony_ci		dev_err(&host->dev, "failed registering spi host\n");
66162306a36Sopenharmony_ci		free_irq(sqi->irq, sqi);
66262306a36Sopenharmony_ci		goto err_free_ring;
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	platform_set_drvdata(pdev, sqi);
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	return 0;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_cierr_free_ring:
67062306a36Sopenharmony_ci	ring_desc_ring_free(sqi);
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_cierr_disable_clk:
67362306a36Sopenharmony_ci	clk_disable_unprepare(sqi->base_clk);
67462306a36Sopenharmony_ci	clk_disable_unprepare(sqi->sys_clk);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_cierr_free_host:
67762306a36Sopenharmony_ci	spi_controller_put(host);
67862306a36Sopenharmony_ci	return ret;
67962306a36Sopenharmony_ci}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_cistatic void pic32_sqi_remove(struct platform_device *pdev)
68262306a36Sopenharmony_ci{
68362306a36Sopenharmony_ci	struct pic32_sqi *sqi = platform_get_drvdata(pdev);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	/* release resources */
68662306a36Sopenharmony_ci	free_irq(sqi->irq, sqi);
68762306a36Sopenharmony_ci	ring_desc_ring_free(sqi);
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	/* disable clk */
69062306a36Sopenharmony_ci	clk_disable_unprepare(sqi->base_clk);
69162306a36Sopenharmony_ci	clk_disable_unprepare(sqi->sys_clk);
69262306a36Sopenharmony_ci}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_cistatic const struct of_device_id pic32_sqi_of_ids[] = {
69562306a36Sopenharmony_ci	{.compatible = "microchip,pic32mzda-sqi",},
69662306a36Sopenharmony_ci	{},
69762306a36Sopenharmony_ci};
69862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, pic32_sqi_of_ids);
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_cistatic struct platform_driver pic32_sqi_driver = {
70162306a36Sopenharmony_ci	.driver = {
70262306a36Sopenharmony_ci		.name = "sqi-pic32",
70362306a36Sopenharmony_ci		.of_match_table = of_match_ptr(pic32_sqi_of_ids),
70462306a36Sopenharmony_ci	},
70562306a36Sopenharmony_ci	.probe = pic32_sqi_probe,
70662306a36Sopenharmony_ci	.remove_new = pic32_sqi_remove,
70762306a36Sopenharmony_ci};
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_cimodule_platform_driver(pic32_sqi_driver);
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ciMODULE_AUTHOR("Purna Chandra Mandal <purna.mandal@microchip.com>");
71262306a36Sopenharmony_ciMODULE_DESCRIPTION("Microchip SPI driver for PIC32 SQI controller.");
71362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
714