162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2015 MediaTek Inc.
462306a36Sopenharmony_ci * Author: Leilk Liu <leilk.liu@mediatek.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/clk.h>
862306a36Sopenharmony_ci#include <linux/device.h>
962306a36Sopenharmony_ci#include <linux/err.h>
1062306a36Sopenharmony_ci#include <linux/interrupt.h>
1162306a36Sopenharmony_ci#include <linux/io.h>
1262306a36Sopenharmony_ci#include <linux/ioport.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/of.h>
1562306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
1662306a36Sopenharmony_ci#include <linux/platform_device.h>
1762306a36Sopenharmony_ci#include <linux/platform_data/spi-mt65xx.h>
1862306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1962306a36Sopenharmony_ci#include <linux/spi/spi.h>
2062306a36Sopenharmony_ci#include <linux/spi/spi-mem.h>
2162306a36Sopenharmony_ci#include <linux/dma-mapping.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define SPI_CFG0_REG			0x0000
2462306a36Sopenharmony_ci#define SPI_CFG1_REG			0x0004
2562306a36Sopenharmony_ci#define SPI_TX_SRC_REG			0x0008
2662306a36Sopenharmony_ci#define SPI_RX_DST_REG			0x000c
2762306a36Sopenharmony_ci#define SPI_TX_DATA_REG			0x0010
2862306a36Sopenharmony_ci#define SPI_RX_DATA_REG			0x0014
2962306a36Sopenharmony_ci#define SPI_CMD_REG			0x0018
3062306a36Sopenharmony_ci#define SPI_STATUS0_REG			0x001c
3162306a36Sopenharmony_ci#define SPI_PAD_SEL_REG			0x0024
3262306a36Sopenharmony_ci#define SPI_CFG2_REG			0x0028
3362306a36Sopenharmony_ci#define SPI_TX_SRC_REG_64		0x002c
3462306a36Sopenharmony_ci#define SPI_RX_DST_REG_64		0x0030
3562306a36Sopenharmony_ci#define SPI_CFG3_IPM_REG		0x0040
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define SPI_CFG0_SCK_HIGH_OFFSET	0
3862306a36Sopenharmony_ci#define SPI_CFG0_SCK_LOW_OFFSET		8
3962306a36Sopenharmony_ci#define SPI_CFG0_CS_HOLD_OFFSET		16
4062306a36Sopenharmony_ci#define SPI_CFG0_CS_SETUP_OFFSET	24
4162306a36Sopenharmony_ci#define SPI_ADJUST_CFG0_CS_HOLD_OFFSET	0
4262306a36Sopenharmony_ci#define SPI_ADJUST_CFG0_CS_SETUP_OFFSET	16
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define SPI_CFG1_CS_IDLE_OFFSET		0
4562306a36Sopenharmony_ci#define SPI_CFG1_PACKET_LOOP_OFFSET	8
4662306a36Sopenharmony_ci#define SPI_CFG1_PACKET_LENGTH_OFFSET	16
4762306a36Sopenharmony_ci#define SPI_CFG1_GET_TICK_DLY_OFFSET	29
4862306a36Sopenharmony_ci#define SPI_CFG1_GET_TICK_DLY_OFFSET_V1	30
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#define SPI_CFG1_GET_TICK_DLY_MASK	0xe0000000
5162306a36Sopenharmony_ci#define SPI_CFG1_GET_TICK_DLY_MASK_V1	0xc0000000
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#define SPI_CFG1_CS_IDLE_MASK		0xff
5462306a36Sopenharmony_ci#define SPI_CFG1_PACKET_LOOP_MASK	0xff00
5562306a36Sopenharmony_ci#define SPI_CFG1_PACKET_LENGTH_MASK	0x3ff0000
5662306a36Sopenharmony_ci#define SPI_CFG1_IPM_PACKET_LENGTH_MASK	GENMASK(31, 16)
5762306a36Sopenharmony_ci#define SPI_CFG2_SCK_HIGH_OFFSET	0
5862306a36Sopenharmony_ci#define SPI_CFG2_SCK_LOW_OFFSET		16
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#define SPI_CMD_ACT			BIT(0)
6162306a36Sopenharmony_ci#define SPI_CMD_RESUME			BIT(1)
6262306a36Sopenharmony_ci#define SPI_CMD_RST			BIT(2)
6362306a36Sopenharmony_ci#define SPI_CMD_PAUSE_EN		BIT(4)
6462306a36Sopenharmony_ci#define SPI_CMD_DEASSERT		BIT(5)
6562306a36Sopenharmony_ci#define SPI_CMD_SAMPLE_SEL		BIT(6)
6662306a36Sopenharmony_ci#define SPI_CMD_CS_POL			BIT(7)
6762306a36Sopenharmony_ci#define SPI_CMD_CPHA			BIT(8)
6862306a36Sopenharmony_ci#define SPI_CMD_CPOL			BIT(9)
6962306a36Sopenharmony_ci#define SPI_CMD_RX_DMA			BIT(10)
7062306a36Sopenharmony_ci#define SPI_CMD_TX_DMA			BIT(11)
7162306a36Sopenharmony_ci#define SPI_CMD_TXMSBF			BIT(12)
7262306a36Sopenharmony_ci#define SPI_CMD_RXMSBF			BIT(13)
7362306a36Sopenharmony_ci#define SPI_CMD_RX_ENDIAN		BIT(14)
7462306a36Sopenharmony_ci#define SPI_CMD_TX_ENDIAN		BIT(15)
7562306a36Sopenharmony_ci#define SPI_CMD_FINISH_IE		BIT(16)
7662306a36Sopenharmony_ci#define SPI_CMD_PAUSE_IE		BIT(17)
7762306a36Sopenharmony_ci#define SPI_CMD_IPM_NONIDLE_MODE	BIT(19)
7862306a36Sopenharmony_ci#define SPI_CMD_IPM_SPIM_LOOP		BIT(21)
7962306a36Sopenharmony_ci#define SPI_CMD_IPM_GET_TICKDLY_OFFSET	22
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#define SPI_CMD_IPM_GET_TICKDLY_MASK	GENMASK(24, 22)
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci#define PIN_MODE_CFG(x)	((x) / 2)
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#define SPI_CFG3_IPM_HALF_DUPLEX_DIR	BIT(2)
8662306a36Sopenharmony_ci#define SPI_CFG3_IPM_HALF_DUPLEX_EN	BIT(3)
8762306a36Sopenharmony_ci#define SPI_CFG3_IPM_XMODE_EN		BIT(4)
8862306a36Sopenharmony_ci#define SPI_CFG3_IPM_NODATA_FLAG	BIT(5)
8962306a36Sopenharmony_ci#define SPI_CFG3_IPM_CMD_BYTELEN_OFFSET	8
9062306a36Sopenharmony_ci#define SPI_CFG3_IPM_ADDR_BYTELEN_OFFSET 12
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci#define SPI_CFG3_IPM_CMD_PIN_MODE_MASK	GENMASK(1, 0)
9362306a36Sopenharmony_ci#define SPI_CFG3_IPM_CMD_BYTELEN_MASK	GENMASK(11, 8)
9462306a36Sopenharmony_ci#define SPI_CFG3_IPM_ADDR_BYTELEN_MASK	GENMASK(15, 12)
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci#define MT8173_SPI_MAX_PAD_SEL		3
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci#define MTK_SPI_PAUSE_INT_STATUS	0x2
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#define MTK_SPI_MAX_FIFO_SIZE		32U
10162306a36Sopenharmony_ci#define MTK_SPI_PACKET_SIZE		1024
10262306a36Sopenharmony_ci#define MTK_SPI_IPM_PACKET_SIZE		SZ_64K
10362306a36Sopenharmony_ci#define MTK_SPI_IPM_PACKET_LOOP		SZ_256
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci#define MTK_SPI_IDLE			0
10662306a36Sopenharmony_ci#define MTK_SPI_PAUSED			1
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci#define MTK_SPI_32BITS_MASK		(0xffffffff)
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci#define DMA_ADDR_EXT_BITS		(36)
11162306a36Sopenharmony_ci#define DMA_ADDR_DEF_BITS		(32)
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci/**
11462306a36Sopenharmony_ci * struct mtk_spi_compatible - device data structure
11562306a36Sopenharmony_ci * @need_pad_sel:	Enable pad (pins) selection in SPI controller
11662306a36Sopenharmony_ci * @must_tx:		Must explicitly send dummy TX bytes to do RX only transfer
11762306a36Sopenharmony_ci * @enhance_timing:	Enable adjusting cfg register to enhance time accuracy
11862306a36Sopenharmony_ci * @dma_ext:		DMA address extension supported
11962306a36Sopenharmony_ci * @no_need_unprepare:	Don't unprepare the SPI clk during runtime
12062306a36Sopenharmony_ci * @ipm_design:		Adjust/extend registers to support IPM design IP features
12162306a36Sopenharmony_ci */
12262306a36Sopenharmony_cistruct mtk_spi_compatible {
12362306a36Sopenharmony_ci	bool need_pad_sel;
12462306a36Sopenharmony_ci	bool must_tx;
12562306a36Sopenharmony_ci	bool enhance_timing;
12662306a36Sopenharmony_ci	bool dma_ext;
12762306a36Sopenharmony_ci	bool no_need_unprepare;
12862306a36Sopenharmony_ci	bool ipm_design;
12962306a36Sopenharmony_ci};
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci/**
13262306a36Sopenharmony_ci * struct mtk_spi - SPI driver instance
13362306a36Sopenharmony_ci * @base:		Start address of the SPI controller registers
13462306a36Sopenharmony_ci * @state:		SPI controller state
13562306a36Sopenharmony_ci * @pad_num:		Number of pad_sel entries
13662306a36Sopenharmony_ci * @pad_sel:		Groups of pins to select
13762306a36Sopenharmony_ci * @parent_clk:		Parent of sel_clk
13862306a36Sopenharmony_ci * @sel_clk:		SPI master mux clock
13962306a36Sopenharmony_ci * @spi_clk:		Peripheral clock
14062306a36Sopenharmony_ci * @spi_hclk:		AHB bus clock
14162306a36Sopenharmony_ci * @cur_transfer:	Currently processed SPI transfer
14262306a36Sopenharmony_ci * @xfer_len:		Number of bytes to transfer
14362306a36Sopenharmony_ci * @num_xfered:		Number of transferred bytes
14462306a36Sopenharmony_ci * @tx_sgl:		TX transfer scatterlist
14562306a36Sopenharmony_ci * @rx_sgl:		RX transfer scatterlist
14662306a36Sopenharmony_ci * @tx_sgl_len:		Size of TX DMA transfer
14762306a36Sopenharmony_ci * @rx_sgl_len:		Size of RX DMA transfer
14862306a36Sopenharmony_ci * @dev_comp:		Device data structure
14962306a36Sopenharmony_ci * @spi_clk_hz:		Current SPI clock in Hz
15062306a36Sopenharmony_ci * @spimem_done:	SPI-MEM operation completion
15162306a36Sopenharmony_ci * @use_spimem:		Enables SPI-MEM
15262306a36Sopenharmony_ci * @dev:		Device pointer
15362306a36Sopenharmony_ci * @tx_dma:		DMA start for SPI-MEM TX
15462306a36Sopenharmony_ci * @rx_dma:		DMA start for SPI-MEM RX
15562306a36Sopenharmony_ci */
15662306a36Sopenharmony_cistruct mtk_spi {
15762306a36Sopenharmony_ci	void __iomem *base;
15862306a36Sopenharmony_ci	u32 state;
15962306a36Sopenharmony_ci	int pad_num;
16062306a36Sopenharmony_ci	u32 *pad_sel;
16162306a36Sopenharmony_ci	struct clk *parent_clk, *sel_clk, *spi_clk, *spi_hclk;
16262306a36Sopenharmony_ci	struct spi_transfer *cur_transfer;
16362306a36Sopenharmony_ci	u32 xfer_len;
16462306a36Sopenharmony_ci	u32 num_xfered;
16562306a36Sopenharmony_ci	struct scatterlist *tx_sgl, *rx_sgl;
16662306a36Sopenharmony_ci	u32 tx_sgl_len, rx_sgl_len;
16762306a36Sopenharmony_ci	const struct mtk_spi_compatible *dev_comp;
16862306a36Sopenharmony_ci	u32 spi_clk_hz;
16962306a36Sopenharmony_ci	struct completion spimem_done;
17062306a36Sopenharmony_ci	bool use_spimem;
17162306a36Sopenharmony_ci	struct device *dev;
17262306a36Sopenharmony_ci	dma_addr_t tx_dma;
17362306a36Sopenharmony_ci	dma_addr_t rx_dma;
17462306a36Sopenharmony_ci};
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic const struct mtk_spi_compatible mtk_common_compat;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic const struct mtk_spi_compatible mt2712_compat = {
17962306a36Sopenharmony_ci	.must_tx = true,
18062306a36Sopenharmony_ci};
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic const struct mtk_spi_compatible mtk_ipm_compat = {
18362306a36Sopenharmony_ci	.enhance_timing = true,
18462306a36Sopenharmony_ci	.dma_ext = true,
18562306a36Sopenharmony_ci	.ipm_design = true,
18662306a36Sopenharmony_ci};
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic const struct mtk_spi_compatible mt6765_compat = {
18962306a36Sopenharmony_ci	.need_pad_sel = true,
19062306a36Sopenharmony_ci	.must_tx = true,
19162306a36Sopenharmony_ci	.enhance_timing = true,
19262306a36Sopenharmony_ci	.dma_ext = true,
19362306a36Sopenharmony_ci};
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic const struct mtk_spi_compatible mt7622_compat = {
19662306a36Sopenharmony_ci	.must_tx = true,
19762306a36Sopenharmony_ci	.enhance_timing = true,
19862306a36Sopenharmony_ci};
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic const struct mtk_spi_compatible mt8173_compat = {
20162306a36Sopenharmony_ci	.need_pad_sel = true,
20262306a36Sopenharmony_ci	.must_tx = true,
20362306a36Sopenharmony_ci};
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic const struct mtk_spi_compatible mt8183_compat = {
20662306a36Sopenharmony_ci	.need_pad_sel = true,
20762306a36Sopenharmony_ci	.must_tx = true,
20862306a36Sopenharmony_ci	.enhance_timing = true,
20962306a36Sopenharmony_ci};
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistatic const struct mtk_spi_compatible mt6893_compat = {
21262306a36Sopenharmony_ci	.need_pad_sel = true,
21362306a36Sopenharmony_ci	.must_tx = true,
21462306a36Sopenharmony_ci	.enhance_timing = true,
21562306a36Sopenharmony_ci	.dma_ext = true,
21662306a36Sopenharmony_ci	.no_need_unprepare = true,
21762306a36Sopenharmony_ci};
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci/*
22062306a36Sopenharmony_ci * A piece of default chip info unless the platform
22162306a36Sopenharmony_ci * supplies it.
22262306a36Sopenharmony_ci */
22362306a36Sopenharmony_cistatic const struct mtk_chip_config mtk_default_chip_info = {
22462306a36Sopenharmony_ci	.sample_sel = 0,
22562306a36Sopenharmony_ci	.tick_delay = 0,
22662306a36Sopenharmony_ci};
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic const struct of_device_id mtk_spi_of_match[] = {
22962306a36Sopenharmony_ci	{ .compatible = "mediatek,spi-ipm",
23062306a36Sopenharmony_ci		.data = (void *)&mtk_ipm_compat,
23162306a36Sopenharmony_ci	},
23262306a36Sopenharmony_ci	{ .compatible = "mediatek,mt2701-spi",
23362306a36Sopenharmony_ci		.data = (void *)&mtk_common_compat,
23462306a36Sopenharmony_ci	},
23562306a36Sopenharmony_ci	{ .compatible = "mediatek,mt2712-spi",
23662306a36Sopenharmony_ci		.data = (void *)&mt2712_compat,
23762306a36Sopenharmony_ci	},
23862306a36Sopenharmony_ci	{ .compatible = "mediatek,mt6589-spi",
23962306a36Sopenharmony_ci		.data = (void *)&mtk_common_compat,
24062306a36Sopenharmony_ci	},
24162306a36Sopenharmony_ci	{ .compatible = "mediatek,mt6765-spi",
24262306a36Sopenharmony_ci		.data = (void *)&mt6765_compat,
24362306a36Sopenharmony_ci	},
24462306a36Sopenharmony_ci	{ .compatible = "mediatek,mt7622-spi",
24562306a36Sopenharmony_ci		.data = (void *)&mt7622_compat,
24662306a36Sopenharmony_ci	},
24762306a36Sopenharmony_ci	{ .compatible = "mediatek,mt7629-spi",
24862306a36Sopenharmony_ci		.data = (void *)&mt7622_compat,
24962306a36Sopenharmony_ci	},
25062306a36Sopenharmony_ci	{ .compatible = "mediatek,mt8135-spi",
25162306a36Sopenharmony_ci		.data = (void *)&mtk_common_compat,
25262306a36Sopenharmony_ci	},
25362306a36Sopenharmony_ci	{ .compatible = "mediatek,mt8173-spi",
25462306a36Sopenharmony_ci		.data = (void *)&mt8173_compat,
25562306a36Sopenharmony_ci	},
25662306a36Sopenharmony_ci	{ .compatible = "mediatek,mt8183-spi",
25762306a36Sopenharmony_ci		.data = (void *)&mt8183_compat,
25862306a36Sopenharmony_ci	},
25962306a36Sopenharmony_ci	{ .compatible = "mediatek,mt8192-spi",
26062306a36Sopenharmony_ci		.data = (void *)&mt6765_compat,
26162306a36Sopenharmony_ci	},
26262306a36Sopenharmony_ci	{ .compatible = "mediatek,mt6893-spi",
26362306a36Sopenharmony_ci		.data = (void *)&mt6893_compat,
26462306a36Sopenharmony_ci	},
26562306a36Sopenharmony_ci	{}
26662306a36Sopenharmony_ci};
26762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, mtk_spi_of_match);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic void mtk_spi_reset(struct mtk_spi *mdata)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	u32 reg_val;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	/* set the software reset bit in SPI_CMD_REG. */
27462306a36Sopenharmony_ci	reg_val = readl(mdata->base + SPI_CMD_REG);
27562306a36Sopenharmony_ci	reg_val |= SPI_CMD_RST;
27662306a36Sopenharmony_ci	writel(reg_val, mdata->base + SPI_CMD_REG);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	reg_val = readl(mdata->base + SPI_CMD_REG);
27962306a36Sopenharmony_ci	reg_val &= ~SPI_CMD_RST;
28062306a36Sopenharmony_ci	writel(reg_val, mdata->base + SPI_CMD_REG);
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic int mtk_spi_set_hw_cs_timing(struct spi_device *spi)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
28662306a36Sopenharmony_ci	struct spi_delay *cs_setup = &spi->cs_setup;
28762306a36Sopenharmony_ci	struct spi_delay *cs_hold = &spi->cs_hold;
28862306a36Sopenharmony_ci	struct spi_delay *cs_inactive = &spi->cs_inactive;
28962306a36Sopenharmony_ci	u32 setup, hold, inactive;
29062306a36Sopenharmony_ci	u32 reg_val;
29162306a36Sopenharmony_ci	int delay;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	delay = spi_delay_to_ns(cs_setup, NULL);
29462306a36Sopenharmony_ci	if (delay < 0)
29562306a36Sopenharmony_ci		return delay;
29662306a36Sopenharmony_ci	setup = (delay * DIV_ROUND_UP(mdata->spi_clk_hz, 1000000)) / 1000;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	delay = spi_delay_to_ns(cs_hold, NULL);
29962306a36Sopenharmony_ci	if (delay < 0)
30062306a36Sopenharmony_ci		return delay;
30162306a36Sopenharmony_ci	hold = (delay * DIV_ROUND_UP(mdata->spi_clk_hz, 1000000)) / 1000;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	delay = spi_delay_to_ns(cs_inactive, NULL);
30462306a36Sopenharmony_ci	if (delay < 0)
30562306a36Sopenharmony_ci		return delay;
30662306a36Sopenharmony_ci	inactive = (delay * DIV_ROUND_UP(mdata->spi_clk_hz, 1000000)) / 1000;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	if (hold || setup) {
30962306a36Sopenharmony_ci		reg_val = readl(mdata->base + SPI_CFG0_REG);
31062306a36Sopenharmony_ci		if (mdata->dev_comp->enhance_timing) {
31162306a36Sopenharmony_ci			if (hold) {
31262306a36Sopenharmony_ci				hold = min_t(u32, hold, 0x10000);
31362306a36Sopenharmony_ci				reg_val &= ~(0xffff << SPI_ADJUST_CFG0_CS_HOLD_OFFSET);
31462306a36Sopenharmony_ci				reg_val |= (((hold - 1) & 0xffff)
31562306a36Sopenharmony_ci					<< SPI_ADJUST_CFG0_CS_HOLD_OFFSET);
31662306a36Sopenharmony_ci			}
31762306a36Sopenharmony_ci			if (setup) {
31862306a36Sopenharmony_ci				setup = min_t(u32, setup, 0x10000);
31962306a36Sopenharmony_ci				reg_val &= ~(0xffff << SPI_ADJUST_CFG0_CS_SETUP_OFFSET);
32062306a36Sopenharmony_ci				reg_val |= (((setup - 1) & 0xffff)
32162306a36Sopenharmony_ci					<< SPI_ADJUST_CFG0_CS_SETUP_OFFSET);
32262306a36Sopenharmony_ci			}
32362306a36Sopenharmony_ci		} else {
32462306a36Sopenharmony_ci			if (hold) {
32562306a36Sopenharmony_ci				hold = min_t(u32, hold, 0x100);
32662306a36Sopenharmony_ci				reg_val &= ~(0xff << SPI_CFG0_CS_HOLD_OFFSET);
32762306a36Sopenharmony_ci				reg_val |= (((hold - 1) & 0xff) << SPI_CFG0_CS_HOLD_OFFSET);
32862306a36Sopenharmony_ci			}
32962306a36Sopenharmony_ci			if (setup) {
33062306a36Sopenharmony_ci				setup = min_t(u32, setup, 0x100);
33162306a36Sopenharmony_ci				reg_val &= ~(0xff << SPI_CFG0_CS_SETUP_OFFSET);
33262306a36Sopenharmony_ci				reg_val |= (((setup - 1) & 0xff)
33362306a36Sopenharmony_ci					<< SPI_CFG0_CS_SETUP_OFFSET);
33462306a36Sopenharmony_ci			}
33562306a36Sopenharmony_ci		}
33662306a36Sopenharmony_ci		writel(reg_val, mdata->base + SPI_CFG0_REG);
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (inactive) {
34062306a36Sopenharmony_ci		inactive = min_t(u32, inactive, 0x100);
34162306a36Sopenharmony_ci		reg_val = readl(mdata->base + SPI_CFG1_REG);
34262306a36Sopenharmony_ci		reg_val &= ~SPI_CFG1_CS_IDLE_MASK;
34362306a36Sopenharmony_ci		reg_val |= (((inactive - 1) & 0xff) << SPI_CFG1_CS_IDLE_OFFSET);
34462306a36Sopenharmony_ci		writel(reg_val, mdata->base + SPI_CFG1_REG);
34562306a36Sopenharmony_ci	}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	return 0;
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_cistatic int mtk_spi_hw_init(struct spi_master *master,
35162306a36Sopenharmony_ci			   struct spi_device *spi)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	u16 cpha, cpol;
35462306a36Sopenharmony_ci	u32 reg_val;
35562306a36Sopenharmony_ci	struct mtk_chip_config *chip_config = spi->controller_data;
35662306a36Sopenharmony_ci	struct mtk_spi *mdata = spi_master_get_devdata(master);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	cpha = spi->mode & SPI_CPHA ? 1 : 0;
35962306a36Sopenharmony_ci	cpol = spi->mode & SPI_CPOL ? 1 : 0;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	reg_val = readl(mdata->base + SPI_CMD_REG);
36262306a36Sopenharmony_ci	if (mdata->dev_comp->ipm_design) {
36362306a36Sopenharmony_ci		/* SPI transfer without idle time until packet length done */
36462306a36Sopenharmony_ci		reg_val |= SPI_CMD_IPM_NONIDLE_MODE;
36562306a36Sopenharmony_ci		if (spi->mode & SPI_LOOP)
36662306a36Sopenharmony_ci			reg_val |= SPI_CMD_IPM_SPIM_LOOP;
36762306a36Sopenharmony_ci		else
36862306a36Sopenharmony_ci			reg_val &= ~SPI_CMD_IPM_SPIM_LOOP;
36962306a36Sopenharmony_ci	}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	if (cpha)
37262306a36Sopenharmony_ci		reg_val |= SPI_CMD_CPHA;
37362306a36Sopenharmony_ci	else
37462306a36Sopenharmony_ci		reg_val &= ~SPI_CMD_CPHA;
37562306a36Sopenharmony_ci	if (cpol)
37662306a36Sopenharmony_ci		reg_val |= SPI_CMD_CPOL;
37762306a36Sopenharmony_ci	else
37862306a36Sopenharmony_ci		reg_val &= ~SPI_CMD_CPOL;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	/* set the mlsbx and mlsbtx */
38162306a36Sopenharmony_ci	if (spi->mode & SPI_LSB_FIRST) {
38262306a36Sopenharmony_ci		reg_val &= ~SPI_CMD_TXMSBF;
38362306a36Sopenharmony_ci		reg_val &= ~SPI_CMD_RXMSBF;
38462306a36Sopenharmony_ci	} else {
38562306a36Sopenharmony_ci		reg_val |= SPI_CMD_TXMSBF;
38662306a36Sopenharmony_ci		reg_val |= SPI_CMD_RXMSBF;
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	/* set the tx/rx endian */
39062306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN
39162306a36Sopenharmony_ci	reg_val &= ~SPI_CMD_TX_ENDIAN;
39262306a36Sopenharmony_ci	reg_val &= ~SPI_CMD_RX_ENDIAN;
39362306a36Sopenharmony_ci#else
39462306a36Sopenharmony_ci	reg_val |= SPI_CMD_TX_ENDIAN;
39562306a36Sopenharmony_ci	reg_val |= SPI_CMD_RX_ENDIAN;
39662306a36Sopenharmony_ci#endif
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	if (mdata->dev_comp->enhance_timing) {
39962306a36Sopenharmony_ci		/* set CS polarity */
40062306a36Sopenharmony_ci		if (spi->mode & SPI_CS_HIGH)
40162306a36Sopenharmony_ci			reg_val |= SPI_CMD_CS_POL;
40262306a36Sopenharmony_ci		else
40362306a36Sopenharmony_ci			reg_val &= ~SPI_CMD_CS_POL;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci		if (chip_config->sample_sel)
40662306a36Sopenharmony_ci			reg_val |= SPI_CMD_SAMPLE_SEL;
40762306a36Sopenharmony_ci		else
40862306a36Sopenharmony_ci			reg_val &= ~SPI_CMD_SAMPLE_SEL;
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	/* set finish and pause interrupt always enable */
41262306a36Sopenharmony_ci	reg_val |= SPI_CMD_FINISH_IE | SPI_CMD_PAUSE_IE;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	/* disable dma mode */
41562306a36Sopenharmony_ci	reg_val &= ~(SPI_CMD_TX_DMA | SPI_CMD_RX_DMA);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	/* disable deassert mode */
41862306a36Sopenharmony_ci	reg_val &= ~SPI_CMD_DEASSERT;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	writel(reg_val, mdata->base + SPI_CMD_REG);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	/* pad select */
42362306a36Sopenharmony_ci	if (mdata->dev_comp->need_pad_sel)
42462306a36Sopenharmony_ci		writel(mdata->pad_sel[spi_get_chipselect(spi, 0)],
42562306a36Sopenharmony_ci		       mdata->base + SPI_PAD_SEL_REG);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	/* tick delay */
42862306a36Sopenharmony_ci	if (mdata->dev_comp->enhance_timing) {
42962306a36Sopenharmony_ci		if (mdata->dev_comp->ipm_design) {
43062306a36Sopenharmony_ci			reg_val = readl(mdata->base + SPI_CMD_REG);
43162306a36Sopenharmony_ci			reg_val &= ~SPI_CMD_IPM_GET_TICKDLY_MASK;
43262306a36Sopenharmony_ci			reg_val |= ((chip_config->tick_delay & 0x7)
43362306a36Sopenharmony_ci				    << SPI_CMD_IPM_GET_TICKDLY_OFFSET);
43462306a36Sopenharmony_ci			writel(reg_val, mdata->base + SPI_CMD_REG);
43562306a36Sopenharmony_ci		} else {
43662306a36Sopenharmony_ci			reg_val = readl(mdata->base + SPI_CFG1_REG);
43762306a36Sopenharmony_ci			reg_val &= ~SPI_CFG1_GET_TICK_DLY_MASK;
43862306a36Sopenharmony_ci			reg_val |= ((chip_config->tick_delay & 0x7)
43962306a36Sopenharmony_ci				    << SPI_CFG1_GET_TICK_DLY_OFFSET);
44062306a36Sopenharmony_ci			writel(reg_val, mdata->base + SPI_CFG1_REG);
44162306a36Sopenharmony_ci		}
44262306a36Sopenharmony_ci	} else {
44362306a36Sopenharmony_ci		reg_val = readl(mdata->base + SPI_CFG1_REG);
44462306a36Sopenharmony_ci		reg_val &= ~SPI_CFG1_GET_TICK_DLY_MASK_V1;
44562306a36Sopenharmony_ci		reg_val |= ((chip_config->tick_delay & 0x3)
44662306a36Sopenharmony_ci			    << SPI_CFG1_GET_TICK_DLY_OFFSET_V1);
44762306a36Sopenharmony_ci		writel(reg_val, mdata->base + SPI_CFG1_REG);
44862306a36Sopenharmony_ci	}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	/* set hw cs timing */
45162306a36Sopenharmony_ci	mtk_spi_set_hw_cs_timing(spi);
45262306a36Sopenharmony_ci	return 0;
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_cistatic int mtk_spi_prepare_message(struct spi_master *master,
45662306a36Sopenharmony_ci				   struct spi_message *msg)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	return mtk_spi_hw_init(master, msg->spi);
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cistatic void mtk_spi_set_cs(struct spi_device *spi, bool enable)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	u32 reg_val;
46462306a36Sopenharmony_ci	struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	if (spi->mode & SPI_CS_HIGH)
46762306a36Sopenharmony_ci		enable = !enable;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	reg_val = readl(mdata->base + SPI_CMD_REG);
47062306a36Sopenharmony_ci	if (!enable) {
47162306a36Sopenharmony_ci		reg_val |= SPI_CMD_PAUSE_EN;
47262306a36Sopenharmony_ci		writel(reg_val, mdata->base + SPI_CMD_REG);
47362306a36Sopenharmony_ci	} else {
47462306a36Sopenharmony_ci		reg_val &= ~SPI_CMD_PAUSE_EN;
47562306a36Sopenharmony_ci		writel(reg_val, mdata->base + SPI_CMD_REG);
47662306a36Sopenharmony_ci		mdata->state = MTK_SPI_IDLE;
47762306a36Sopenharmony_ci		mtk_spi_reset(mdata);
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_cistatic void mtk_spi_prepare_transfer(struct spi_master *master,
48262306a36Sopenharmony_ci				     u32 speed_hz)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	u32 div, sck_time, reg_val;
48562306a36Sopenharmony_ci	struct mtk_spi *mdata = spi_master_get_devdata(master);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	if (speed_hz < mdata->spi_clk_hz / 2)
48862306a36Sopenharmony_ci		div = DIV_ROUND_UP(mdata->spi_clk_hz, speed_hz);
48962306a36Sopenharmony_ci	else
49062306a36Sopenharmony_ci		div = 1;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	sck_time = (div + 1) / 2;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	if (mdata->dev_comp->enhance_timing) {
49562306a36Sopenharmony_ci		reg_val = readl(mdata->base + SPI_CFG2_REG);
49662306a36Sopenharmony_ci		reg_val &= ~(0xffff << SPI_CFG2_SCK_HIGH_OFFSET);
49762306a36Sopenharmony_ci		reg_val |= (((sck_time - 1) & 0xffff)
49862306a36Sopenharmony_ci			   << SPI_CFG2_SCK_HIGH_OFFSET);
49962306a36Sopenharmony_ci		reg_val &= ~(0xffff << SPI_CFG2_SCK_LOW_OFFSET);
50062306a36Sopenharmony_ci		reg_val |= (((sck_time - 1) & 0xffff)
50162306a36Sopenharmony_ci			   << SPI_CFG2_SCK_LOW_OFFSET);
50262306a36Sopenharmony_ci		writel(reg_val, mdata->base + SPI_CFG2_REG);
50362306a36Sopenharmony_ci	} else {
50462306a36Sopenharmony_ci		reg_val = readl(mdata->base + SPI_CFG0_REG);
50562306a36Sopenharmony_ci		reg_val &= ~(0xff << SPI_CFG0_SCK_HIGH_OFFSET);
50662306a36Sopenharmony_ci		reg_val |= (((sck_time - 1) & 0xff)
50762306a36Sopenharmony_ci			   << SPI_CFG0_SCK_HIGH_OFFSET);
50862306a36Sopenharmony_ci		reg_val &= ~(0xff << SPI_CFG0_SCK_LOW_OFFSET);
50962306a36Sopenharmony_ci		reg_val |= (((sck_time - 1) & 0xff) << SPI_CFG0_SCK_LOW_OFFSET);
51062306a36Sopenharmony_ci		writel(reg_val, mdata->base + SPI_CFG0_REG);
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_cistatic void mtk_spi_setup_packet(struct spi_master *master)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	u32 packet_size, packet_loop, reg_val;
51762306a36Sopenharmony_ci	struct mtk_spi *mdata = spi_master_get_devdata(master);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	if (mdata->dev_comp->ipm_design)
52062306a36Sopenharmony_ci		packet_size = min_t(u32,
52162306a36Sopenharmony_ci				    mdata->xfer_len,
52262306a36Sopenharmony_ci				    MTK_SPI_IPM_PACKET_SIZE);
52362306a36Sopenharmony_ci	else
52462306a36Sopenharmony_ci		packet_size = min_t(u32,
52562306a36Sopenharmony_ci				    mdata->xfer_len,
52662306a36Sopenharmony_ci				    MTK_SPI_PACKET_SIZE);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	packet_loop = mdata->xfer_len / packet_size;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	reg_val = readl(mdata->base + SPI_CFG1_REG);
53162306a36Sopenharmony_ci	if (mdata->dev_comp->ipm_design)
53262306a36Sopenharmony_ci		reg_val &= ~SPI_CFG1_IPM_PACKET_LENGTH_MASK;
53362306a36Sopenharmony_ci	else
53462306a36Sopenharmony_ci		reg_val &= ~SPI_CFG1_PACKET_LENGTH_MASK;
53562306a36Sopenharmony_ci	reg_val |= (packet_size - 1) << SPI_CFG1_PACKET_LENGTH_OFFSET;
53662306a36Sopenharmony_ci	reg_val &= ~SPI_CFG1_PACKET_LOOP_MASK;
53762306a36Sopenharmony_ci	reg_val |= (packet_loop - 1) << SPI_CFG1_PACKET_LOOP_OFFSET;
53862306a36Sopenharmony_ci	writel(reg_val, mdata->base + SPI_CFG1_REG);
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic void mtk_spi_enable_transfer(struct spi_master *master)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	u32 cmd;
54462306a36Sopenharmony_ci	struct mtk_spi *mdata = spi_master_get_devdata(master);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	cmd = readl(mdata->base + SPI_CMD_REG);
54762306a36Sopenharmony_ci	if (mdata->state == MTK_SPI_IDLE)
54862306a36Sopenharmony_ci		cmd |= SPI_CMD_ACT;
54962306a36Sopenharmony_ci	else
55062306a36Sopenharmony_ci		cmd |= SPI_CMD_RESUME;
55162306a36Sopenharmony_ci	writel(cmd, mdata->base + SPI_CMD_REG);
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_cistatic int mtk_spi_get_mult_delta(struct mtk_spi *mdata, u32 xfer_len)
55562306a36Sopenharmony_ci{
55662306a36Sopenharmony_ci	u32 mult_delta = 0;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	if (mdata->dev_comp->ipm_design) {
55962306a36Sopenharmony_ci		if (xfer_len > MTK_SPI_IPM_PACKET_SIZE)
56062306a36Sopenharmony_ci			mult_delta = xfer_len % MTK_SPI_IPM_PACKET_SIZE;
56162306a36Sopenharmony_ci	} else {
56262306a36Sopenharmony_ci		if (xfer_len > MTK_SPI_PACKET_SIZE)
56362306a36Sopenharmony_ci			mult_delta = xfer_len % MTK_SPI_PACKET_SIZE;
56462306a36Sopenharmony_ci	}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	return mult_delta;
56762306a36Sopenharmony_ci}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_cistatic void mtk_spi_update_mdata_len(struct spi_master *master)
57062306a36Sopenharmony_ci{
57162306a36Sopenharmony_ci	int mult_delta;
57262306a36Sopenharmony_ci	struct mtk_spi *mdata = spi_master_get_devdata(master);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	if (mdata->tx_sgl_len && mdata->rx_sgl_len) {
57562306a36Sopenharmony_ci		if (mdata->tx_sgl_len > mdata->rx_sgl_len) {
57662306a36Sopenharmony_ci			mult_delta = mtk_spi_get_mult_delta(mdata, mdata->rx_sgl_len);
57762306a36Sopenharmony_ci			mdata->xfer_len = mdata->rx_sgl_len - mult_delta;
57862306a36Sopenharmony_ci			mdata->rx_sgl_len = mult_delta;
57962306a36Sopenharmony_ci			mdata->tx_sgl_len -= mdata->xfer_len;
58062306a36Sopenharmony_ci		} else {
58162306a36Sopenharmony_ci			mult_delta = mtk_spi_get_mult_delta(mdata, mdata->tx_sgl_len);
58262306a36Sopenharmony_ci			mdata->xfer_len = mdata->tx_sgl_len - mult_delta;
58362306a36Sopenharmony_ci			mdata->tx_sgl_len = mult_delta;
58462306a36Sopenharmony_ci			mdata->rx_sgl_len -= mdata->xfer_len;
58562306a36Sopenharmony_ci		}
58662306a36Sopenharmony_ci	} else if (mdata->tx_sgl_len) {
58762306a36Sopenharmony_ci		mult_delta = mtk_spi_get_mult_delta(mdata, mdata->tx_sgl_len);
58862306a36Sopenharmony_ci		mdata->xfer_len = mdata->tx_sgl_len - mult_delta;
58962306a36Sopenharmony_ci		mdata->tx_sgl_len = mult_delta;
59062306a36Sopenharmony_ci	} else if (mdata->rx_sgl_len) {
59162306a36Sopenharmony_ci		mult_delta = mtk_spi_get_mult_delta(mdata, mdata->rx_sgl_len);
59262306a36Sopenharmony_ci		mdata->xfer_len = mdata->rx_sgl_len - mult_delta;
59362306a36Sopenharmony_ci		mdata->rx_sgl_len = mult_delta;
59462306a36Sopenharmony_ci	}
59562306a36Sopenharmony_ci}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_cistatic void mtk_spi_setup_dma_addr(struct spi_master *master,
59862306a36Sopenharmony_ci				   struct spi_transfer *xfer)
59962306a36Sopenharmony_ci{
60062306a36Sopenharmony_ci	struct mtk_spi *mdata = spi_master_get_devdata(master);
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	if (mdata->tx_sgl) {
60362306a36Sopenharmony_ci		writel((u32)(xfer->tx_dma & MTK_SPI_32BITS_MASK),
60462306a36Sopenharmony_ci		       mdata->base + SPI_TX_SRC_REG);
60562306a36Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
60662306a36Sopenharmony_ci		if (mdata->dev_comp->dma_ext)
60762306a36Sopenharmony_ci			writel((u32)(xfer->tx_dma >> 32),
60862306a36Sopenharmony_ci			       mdata->base + SPI_TX_SRC_REG_64);
60962306a36Sopenharmony_ci#endif
61062306a36Sopenharmony_ci	}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	if (mdata->rx_sgl) {
61362306a36Sopenharmony_ci		writel((u32)(xfer->rx_dma & MTK_SPI_32BITS_MASK),
61462306a36Sopenharmony_ci		       mdata->base + SPI_RX_DST_REG);
61562306a36Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
61662306a36Sopenharmony_ci		if (mdata->dev_comp->dma_ext)
61762306a36Sopenharmony_ci			writel((u32)(xfer->rx_dma >> 32),
61862306a36Sopenharmony_ci			       mdata->base + SPI_RX_DST_REG_64);
61962306a36Sopenharmony_ci#endif
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_cistatic int mtk_spi_fifo_transfer(struct spi_master *master,
62462306a36Sopenharmony_ci				 struct spi_device *spi,
62562306a36Sopenharmony_ci				 struct spi_transfer *xfer)
62662306a36Sopenharmony_ci{
62762306a36Sopenharmony_ci	int cnt, remainder;
62862306a36Sopenharmony_ci	u32 reg_val;
62962306a36Sopenharmony_ci	struct mtk_spi *mdata = spi_master_get_devdata(master);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	mdata->cur_transfer = xfer;
63262306a36Sopenharmony_ci	mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, xfer->len);
63362306a36Sopenharmony_ci	mdata->num_xfered = 0;
63462306a36Sopenharmony_ci	mtk_spi_prepare_transfer(master, xfer->speed_hz);
63562306a36Sopenharmony_ci	mtk_spi_setup_packet(master);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	if (xfer->tx_buf) {
63862306a36Sopenharmony_ci		cnt = xfer->len / 4;
63962306a36Sopenharmony_ci		iowrite32_rep(mdata->base + SPI_TX_DATA_REG, xfer->tx_buf, cnt);
64062306a36Sopenharmony_ci		remainder = xfer->len % 4;
64162306a36Sopenharmony_ci		if (remainder > 0) {
64262306a36Sopenharmony_ci			reg_val = 0;
64362306a36Sopenharmony_ci			memcpy(&reg_val, xfer->tx_buf + (cnt * 4), remainder);
64462306a36Sopenharmony_ci			writel(reg_val, mdata->base + SPI_TX_DATA_REG);
64562306a36Sopenharmony_ci		}
64662306a36Sopenharmony_ci	}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	mtk_spi_enable_transfer(master);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	return 1;
65162306a36Sopenharmony_ci}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_cistatic int mtk_spi_dma_transfer(struct spi_master *master,
65462306a36Sopenharmony_ci				struct spi_device *spi,
65562306a36Sopenharmony_ci				struct spi_transfer *xfer)
65662306a36Sopenharmony_ci{
65762306a36Sopenharmony_ci	int cmd;
65862306a36Sopenharmony_ci	struct mtk_spi *mdata = spi_master_get_devdata(master);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	mdata->tx_sgl = NULL;
66162306a36Sopenharmony_ci	mdata->rx_sgl = NULL;
66262306a36Sopenharmony_ci	mdata->tx_sgl_len = 0;
66362306a36Sopenharmony_ci	mdata->rx_sgl_len = 0;
66462306a36Sopenharmony_ci	mdata->cur_transfer = xfer;
66562306a36Sopenharmony_ci	mdata->num_xfered = 0;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	mtk_spi_prepare_transfer(master, xfer->speed_hz);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	cmd = readl(mdata->base + SPI_CMD_REG);
67062306a36Sopenharmony_ci	if (xfer->tx_buf)
67162306a36Sopenharmony_ci		cmd |= SPI_CMD_TX_DMA;
67262306a36Sopenharmony_ci	if (xfer->rx_buf)
67362306a36Sopenharmony_ci		cmd |= SPI_CMD_RX_DMA;
67462306a36Sopenharmony_ci	writel(cmd, mdata->base + SPI_CMD_REG);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	if (xfer->tx_buf)
67762306a36Sopenharmony_ci		mdata->tx_sgl = xfer->tx_sg.sgl;
67862306a36Sopenharmony_ci	if (xfer->rx_buf)
67962306a36Sopenharmony_ci		mdata->rx_sgl = xfer->rx_sg.sgl;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	if (mdata->tx_sgl) {
68262306a36Sopenharmony_ci		xfer->tx_dma = sg_dma_address(mdata->tx_sgl);
68362306a36Sopenharmony_ci		mdata->tx_sgl_len = sg_dma_len(mdata->tx_sgl);
68462306a36Sopenharmony_ci	}
68562306a36Sopenharmony_ci	if (mdata->rx_sgl) {
68662306a36Sopenharmony_ci		xfer->rx_dma = sg_dma_address(mdata->rx_sgl);
68762306a36Sopenharmony_ci		mdata->rx_sgl_len = sg_dma_len(mdata->rx_sgl);
68862306a36Sopenharmony_ci	}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	mtk_spi_update_mdata_len(master);
69162306a36Sopenharmony_ci	mtk_spi_setup_packet(master);
69262306a36Sopenharmony_ci	mtk_spi_setup_dma_addr(master, xfer);
69362306a36Sopenharmony_ci	mtk_spi_enable_transfer(master);
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	return 1;
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_cistatic int mtk_spi_transfer_one(struct spi_master *master,
69962306a36Sopenharmony_ci				struct spi_device *spi,
70062306a36Sopenharmony_ci				struct spi_transfer *xfer)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
70362306a36Sopenharmony_ci	u32 reg_val = 0;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	/* prepare xfer direction and duplex mode */
70662306a36Sopenharmony_ci	if (mdata->dev_comp->ipm_design) {
70762306a36Sopenharmony_ci		if (!xfer->tx_buf || !xfer->rx_buf) {
70862306a36Sopenharmony_ci			reg_val |= SPI_CFG3_IPM_HALF_DUPLEX_EN;
70962306a36Sopenharmony_ci			if (xfer->rx_buf)
71062306a36Sopenharmony_ci				reg_val |= SPI_CFG3_IPM_HALF_DUPLEX_DIR;
71162306a36Sopenharmony_ci		}
71262306a36Sopenharmony_ci		writel(reg_val, mdata->base + SPI_CFG3_IPM_REG);
71362306a36Sopenharmony_ci	}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	if (master->can_dma(master, spi, xfer))
71662306a36Sopenharmony_ci		return mtk_spi_dma_transfer(master, spi, xfer);
71762306a36Sopenharmony_ci	else
71862306a36Sopenharmony_ci		return mtk_spi_fifo_transfer(master, spi, xfer);
71962306a36Sopenharmony_ci}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_cistatic bool mtk_spi_can_dma(struct spi_master *master,
72262306a36Sopenharmony_ci			    struct spi_device *spi,
72362306a36Sopenharmony_ci			    struct spi_transfer *xfer)
72462306a36Sopenharmony_ci{
72562306a36Sopenharmony_ci	/* Buffers for DMA transactions must be 4-byte aligned */
72662306a36Sopenharmony_ci	return (xfer->len > MTK_SPI_MAX_FIFO_SIZE &&
72762306a36Sopenharmony_ci		(unsigned long)xfer->tx_buf % 4 == 0 &&
72862306a36Sopenharmony_ci		(unsigned long)xfer->rx_buf % 4 == 0);
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_cistatic int mtk_spi_setup(struct spi_device *spi)
73262306a36Sopenharmony_ci{
73362306a36Sopenharmony_ci	struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	if (!spi->controller_data)
73662306a36Sopenharmony_ci		spi->controller_data = (void *)&mtk_default_chip_info;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	if (mdata->dev_comp->need_pad_sel && spi_get_csgpiod(spi, 0))
73962306a36Sopenharmony_ci		/* CS de-asserted, gpiolib will handle inversion */
74062306a36Sopenharmony_ci		gpiod_direction_output(spi_get_csgpiod(spi, 0), 0);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	return 0;
74362306a36Sopenharmony_ci}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_cistatic irqreturn_t mtk_spi_interrupt(int irq, void *dev_id)
74662306a36Sopenharmony_ci{
74762306a36Sopenharmony_ci	u32 cmd, reg_val, cnt, remainder, len;
74862306a36Sopenharmony_ci	struct spi_master *master = dev_id;
74962306a36Sopenharmony_ci	struct mtk_spi *mdata = spi_master_get_devdata(master);
75062306a36Sopenharmony_ci	struct spi_transfer *trans = mdata->cur_transfer;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	reg_val = readl(mdata->base + SPI_STATUS0_REG);
75362306a36Sopenharmony_ci	if (reg_val & MTK_SPI_PAUSE_INT_STATUS)
75462306a36Sopenharmony_ci		mdata->state = MTK_SPI_PAUSED;
75562306a36Sopenharmony_ci	else
75662306a36Sopenharmony_ci		mdata->state = MTK_SPI_IDLE;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	/* SPI-MEM ops */
75962306a36Sopenharmony_ci	if (mdata->use_spimem) {
76062306a36Sopenharmony_ci		complete(&mdata->spimem_done);
76162306a36Sopenharmony_ci		return IRQ_HANDLED;
76262306a36Sopenharmony_ci	}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	if (!master->can_dma(master, NULL, trans)) {
76562306a36Sopenharmony_ci		if (trans->rx_buf) {
76662306a36Sopenharmony_ci			cnt = mdata->xfer_len / 4;
76762306a36Sopenharmony_ci			ioread32_rep(mdata->base + SPI_RX_DATA_REG,
76862306a36Sopenharmony_ci				     trans->rx_buf + mdata->num_xfered, cnt);
76962306a36Sopenharmony_ci			remainder = mdata->xfer_len % 4;
77062306a36Sopenharmony_ci			if (remainder > 0) {
77162306a36Sopenharmony_ci				reg_val = readl(mdata->base + SPI_RX_DATA_REG);
77262306a36Sopenharmony_ci				memcpy(trans->rx_buf +
77362306a36Sopenharmony_ci					mdata->num_xfered +
77462306a36Sopenharmony_ci					(cnt * 4),
77562306a36Sopenharmony_ci					&reg_val,
77662306a36Sopenharmony_ci					remainder);
77762306a36Sopenharmony_ci			}
77862306a36Sopenharmony_ci		}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci		mdata->num_xfered += mdata->xfer_len;
78162306a36Sopenharmony_ci		if (mdata->num_xfered == trans->len) {
78262306a36Sopenharmony_ci			spi_finalize_current_transfer(master);
78362306a36Sopenharmony_ci			return IRQ_HANDLED;
78462306a36Sopenharmony_ci		}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci		len = trans->len - mdata->num_xfered;
78762306a36Sopenharmony_ci		mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, len);
78862306a36Sopenharmony_ci		mtk_spi_setup_packet(master);
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci		if (trans->tx_buf) {
79162306a36Sopenharmony_ci			cnt = mdata->xfer_len / 4;
79262306a36Sopenharmony_ci			iowrite32_rep(mdata->base + SPI_TX_DATA_REG,
79362306a36Sopenharmony_ci					trans->tx_buf + mdata->num_xfered, cnt);
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci			remainder = mdata->xfer_len % 4;
79662306a36Sopenharmony_ci			if (remainder > 0) {
79762306a36Sopenharmony_ci				reg_val = 0;
79862306a36Sopenharmony_ci				memcpy(&reg_val,
79962306a36Sopenharmony_ci					trans->tx_buf + (cnt * 4) + mdata->num_xfered,
80062306a36Sopenharmony_ci					remainder);
80162306a36Sopenharmony_ci				writel(reg_val, mdata->base + SPI_TX_DATA_REG);
80262306a36Sopenharmony_ci			}
80362306a36Sopenharmony_ci		}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci		mtk_spi_enable_transfer(master);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci		return IRQ_HANDLED;
80862306a36Sopenharmony_ci	}
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	if (mdata->tx_sgl)
81162306a36Sopenharmony_ci		trans->tx_dma += mdata->xfer_len;
81262306a36Sopenharmony_ci	if (mdata->rx_sgl)
81362306a36Sopenharmony_ci		trans->rx_dma += mdata->xfer_len;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	if (mdata->tx_sgl && (mdata->tx_sgl_len == 0)) {
81662306a36Sopenharmony_ci		mdata->tx_sgl = sg_next(mdata->tx_sgl);
81762306a36Sopenharmony_ci		if (mdata->tx_sgl) {
81862306a36Sopenharmony_ci			trans->tx_dma = sg_dma_address(mdata->tx_sgl);
81962306a36Sopenharmony_ci			mdata->tx_sgl_len = sg_dma_len(mdata->tx_sgl);
82062306a36Sopenharmony_ci		}
82162306a36Sopenharmony_ci	}
82262306a36Sopenharmony_ci	if (mdata->rx_sgl && (mdata->rx_sgl_len == 0)) {
82362306a36Sopenharmony_ci		mdata->rx_sgl = sg_next(mdata->rx_sgl);
82462306a36Sopenharmony_ci		if (mdata->rx_sgl) {
82562306a36Sopenharmony_ci			trans->rx_dma = sg_dma_address(mdata->rx_sgl);
82662306a36Sopenharmony_ci			mdata->rx_sgl_len = sg_dma_len(mdata->rx_sgl);
82762306a36Sopenharmony_ci		}
82862306a36Sopenharmony_ci	}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	if (!mdata->tx_sgl && !mdata->rx_sgl) {
83162306a36Sopenharmony_ci		/* spi disable dma */
83262306a36Sopenharmony_ci		cmd = readl(mdata->base + SPI_CMD_REG);
83362306a36Sopenharmony_ci		cmd &= ~SPI_CMD_TX_DMA;
83462306a36Sopenharmony_ci		cmd &= ~SPI_CMD_RX_DMA;
83562306a36Sopenharmony_ci		writel(cmd, mdata->base + SPI_CMD_REG);
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci		spi_finalize_current_transfer(master);
83862306a36Sopenharmony_ci		return IRQ_HANDLED;
83962306a36Sopenharmony_ci	}
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	mtk_spi_update_mdata_len(master);
84262306a36Sopenharmony_ci	mtk_spi_setup_packet(master);
84362306a36Sopenharmony_ci	mtk_spi_setup_dma_addr(master, trans);
84462306a36Sopenharmony_ci	mtk_spi_enable_transfer(master);
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	return IRQ_HANDLED;
84762306a36Sopenharmony_ci}
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_cistatic int mtk_spi_mem_adjust_op_size(struct spi_mem *mem,
85062306a36Sopenharmony_ci				      struct spi_mem_op *op)
85162306a36Sopenharmony_ci{
85262306a36Sopenharmony_ci	int opcode_len;
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	if (op->data.dir != SPI_MEM_NO_DATA) {
85562306a36Sopenharmony_ci		opcode_len = 1 + op->addr.nbytes + op->dummy.nbytes;
85662306a36Sopenharmony_ci		if (opcode_len + op->data.nbytes > MTK_SPI_IPM_PACKET_SIZE) {
85762306a36Sopenharmony_ci			op->data.nbytes = MTK_SPI_IPM_PACKET_SIZE - opcode_len;
85862306a36Sopenharmony_ci			/* force data buffer dma-aligned. */
85962306a36Sopenharmony_ci			op->data.nbytes -= op->data.nbytes % 4;
86062306a36Sopenharmony_ci		}
86162306a36Sopenharmony_ci	}
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	return 0;
86462306a36Sopenharmony_ci}
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_cistatic bool mtk_spi_mem_supports_op(struct spi_mem *mem,
86762306a36Sopenharmony_ci				    const struct spi_mem_op *op)
86862306a36Sopenharmony_ci{
86962306a36Sopenharmony_ci	if (!spi_mem_default_supports_op(mem, op))
87062306a36Sopenharmony_ci		return false;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	if (op->addr.nbytes && op->dummy.nbytes &&
87362306a36Sopenharmony_ci	    op->addr.buswidth != op->dummy.buswidth)
87462306a36Sopenharmony_ci		return false;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	if (op->addr.nbytes + op->dummy.nbytes > 16)
87762306a36Sopenharmony_ci		return false;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	if (op->data.nbytes > MTK_SPI_IPM_PACKET_SIZE) {
88062306a36Sopenharmony_ci		if (op->data.nbytes / MTK_SPI_IPM_PACKET_SIZE >
88162306a36Sopenharmony_ci		    MTK_SPI_IPM_PACKET_LOOP ||
88262306a36Sopenharmony_ci		    op->data.nbytes % MTK_SPI_IPM_PACKET_SIZE != 0)
88362306a36Sopenharmony_ci			return false;
88462306a36Sopenharmony_ci	}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	return true;
88762306a36Sopenharmony_ci}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_cistatic void mtk_spi_mem_setup_dma_xfer(struct spi_master *master,
89062306a36Sopenharmony_ci				       const struct spi_mem_op *op)
89162306a36Sopenharmony_ci{
89262306a36Sopenharmony_ci	struct mtk_spi *mdata = spi_master_get_devdata(master);
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	writel((u32)(mdata->tx_dma & MTK_SPI_32BITS_MASK),
89562306a36Sopenharmony_ci	       mdata->base + SPI_TX_SRC_REG);
89662306a36Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
89762306a36Sopenharmony_ci	if (mdata->dev_comp->dma_ext)
89862306a36Sopenharmony_ci		writel((u32)(mdata->tx_dma >> 32),
89962306a36Sopenharmony_ci		       mdata->base + SPI_TX_SRC_REG_64);
90062306a36Sopenharmony_ci#endif
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	if (op->data.dir == SPI_MEM_DATA_IN) {
90362306a36Sopenharmony_ci		writel((u32)(mdata->rx_dma & MTK_SPI_32BITS_MASK),
90462306a36Sopenharmony_ci		       mdata->base + SPI_RX_DST_REG);
90562306a36Sopenharmony_ci#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
90662306a36Sopenharmony_ci		if (mdata->dev_comp->dma_ext)
90762306a36Sopenharmony_ci			writel((u32)(mdata->rx_dma >> 32),
90862306a36Sopenharmony_ci			       mdata->base + SPI_RX_DST_REG_64);
90962306a36Sopenharmony_ci#endif
91062306a36Sopenharmony_ci	}
91162306a36Sopenharmony_ci}
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_cistatic int mtk_spi_transfer_wait(struct spi_mem *mem,
91462306a36Sopenharmony_ci				 const struct spi_mem_op *op)
91562306a36Sopenharmony_ci{
91662306a36Sopenharmony_ci	struct mtk_spi *mdata = spi_master_get_devdata(mem->spi->master);
91762306a36Sopenharmony_ci	/*
91862306a36Sopenharmony_ci	 * For each byte we wait for 8 cycles of the SPI clock.
91962306a36Sopenharmony_ci	 * Since speed is defined in Hz and we want milliseconds,
92062306a36Sopenharmony_ci	 * so it should be 8 * 1000.
92162306a36Sopenharmony_ci	 */
92262306a36Sopenharmony_ci	u64 ms = 8000LL;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	if (op->data.dir == SPI_MEM_NO_DATA)
92562306a36Sopenharmony_ci		ms *= 32; /* prevent we may get 0 for short transfers. */
92662306a36Sopenharmony_ci	else
92762306a36Sopenharmony_ci		ms *= op->data.nbytes;
92862306a36Sopenharmony_ci	ms = div_u64(ms, mem->spi->max_speed_hz);
92962306a36Sopenharmony_ci	ms += ms + 1000; /* 1s tolerance */
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	if (ms > UINT_MAX)
93262306a36Sopenharmony_ci		ms = UINT_MAX;
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	if (!wait_for_completion_timeout(&mdata->spimem_done,
93562306a36Sopenharmony_ci					 msecs_to_jiffies(ms))) {
93662306a36Sopenharmony_ci		dev_err(mdata->dev, "spi-mem transfer timeout\n");
93762306a36Sopenharmony_ci		return -ETIMEDOUT;
93862306a36Sopenharmony_ci	}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	return 0;
94162306a36Sopenharmony_ci}
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_cistatic int mtk_spi_mem_exec_op(struct spi_mem *mem,
94462306a36Sopenharmony_ci			       const struct spi_mem_op *op)
94562306a36Sopenharmony_ci{
94662306a36Sopenharmony_ci	struct mtk_spi *mdata = spi_master_get_devdata(mem->spi->master);
94762306a36Sopenharmony_ci	u32 reg_val, nio, tx_size;
94862306a36Sopenharmony_ci	char *tx_tmp_buf, *rx_tmp_buf;
94962306a36Sopenharmony_ci	int ret = 0;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	mdata->use_spimem = true;
95262306a36Sopenharmony_ci	reinit_completion(&mdata->spimem_done);
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	mtk_spi_reset(mdata);
95562306a36Sopenharmony_ci	mtk_spi_hw_init(mem->spi->master, mem->spi);
95662306a36Sopenharmony_ci	mtk_spi_prepare_transfer(mem->spi->master, mem->spi->max_speed_hz);
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	reg_val = readl(mdata->base + SPI_CFG3_IPM_REG);
95962306a36Sopenharmony_ci	/* opcode byte len */
96062306a36Sopenharmony_ci	reg_val &= ~SPI_CFG3_IPM_CMD_BYTELEN_MASK;
96162306a36Sopenharmony_ci	reg_val |= 1 << SPI_CFG3_IPM_CMD_BYTELEN_OFFSET;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	/* addr & dummy byte len */
96462306a36Sopenharmony_ci	reg_val &= ~SPI_CFG3_IPM_ADDR_BYTELEN_MASK;
96562306a36Sopenharmony_ci	if (op->addr.nbytes || op->dummy.nbytes)
96662306a36Sopenharmony_ci		reg_val |= (op->addr.nbytes + op->dummy.nbytes) <<
96762306a36Sopenharmony_ci			    SPI_CFG3_IPM_ADDR_BYTELEN_OFFSET;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	/* data byte len */
97062306a36Sopenharmony_ci	if (op->data.dir == SPI_MEM_NO_DATA) {
97162306a36Sopenharmony_ci		reg_val |= SPI_CFG3_IPM_NODATA_FLAG;
97262306a36Sopenharmony_ci		writel(0, mdata->base + SPI_CFG1_REG);
97362306a36Sopenharmony_ci	} else {
97462306a36Sopenharmony_ci		reg_val &= ~SPI_CFG3_IPM_NODATA_FLAG;
97562306a36Sopenharmony_ci		mdata->xfer_len = op->data.nbytes;
97662306a36Sopenharmony_ci		mtk_spi_setup_packet(mem->spi->master);
97762306a36Sopenharmony_ci	}
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	if (op->addr.nbytes || op->dummy.nbytes) {
98062306a36Sopenharmony_ci		if (op->addr.buswidth == 1 || op->dummy.buswidth == 1)
98162306a36Sopenharmony_ci			reg_val |= SPI_CFG3_IPM_XMODE_EN;
98262306a36Sopenharmony_ci		else
98362306a36Sopenharmony_ci			reg_val &= ~SPI_CFG3_IPM_XMODE_EN;
98462306a36Sopenharmony_ci	}
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	if (op->addr.buswidth == 2 ||
98762306a36Sopenharmony_ci	    op->dummy.buswidth == 2 ||
98862306a36Sopenharmony_ci	    op->data.buswidth == 2)
98962306a36Sopenharmony_ci		nio = 2;
99062306a36Sopenharmony_ci	else if (op->addr.buswidth == 4 ||
99162306a36Sopenharmony_ci		 op->dummy.buswidth == 4 ||
99262306a36Sopenharmony_ci		 op->data.buswidth == 4)
99362306a36Sopenharmony_ci		nio = 4;
99462306a36Sopenharmony_ci	else
99562306a36Sopenharmony_ci		nio = 1;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	reg_val &= ~SPI_CFG3_IPM_CMD_PIN_MODE_MASK;
99862306a36Sopenharmony_ci	reg_val |= PIN_MODE_CFG(nio);
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	reg_val |= SPI_CFG3_IPM_HALF_DUPLEX_EN;
100162306a36Sopenharmony_ci	if (op->data.dir == SPI_MEM_DATA_IN)
100262306a36Sopenharmony_ci		reg_val |= SPI_CFG3_IPM_HALF_DUPLEX_DIR;
100362306a36Sopenharmony_ci	else
100462306a36Sopenharmony_ci		reg_val &= ~SPI_CFG3_IPM_HALF_DUPLEX_DIR;
100562306a36Sopenharmony_ci	writel(reg_val, mdata->base + SPI_CFG3_IPM_REG);
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	tx_size = 1 + op->addr.nbytes + op->dummy.nbytes;
100862306a36Sopenharmony_ci	if (op->data.dir == SPI_MEM_DATA_OUT)
100962306a36Sopenharmony_ci		tx_size += op->data.nbytes;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	tx_size = max_t(u32, tx_size, 32);
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	tx_tmp_buf = kzalloc(tx_size, GFP_KERNEL | GFP_DMA);
101462306a36Sopenharmony_ci	if (!tx_tmp_buf) {
101562306a36Sopenharmony_ci		mdata->use_spimem = false;
101662306a36Sopenharmony_ci		return -ENOMEM;
101762306a36Sopenharmony_ci	}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	tx_tmp_buf[0] = op->cmd.opcode;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	if (op->addr.nbytes) {
102262306a36Sopenharmony_ci		int i;
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci		for (i = 0; i < op->addr.nbytes; i++)
102562306a36Sopenharmony_ci			tx_tmp_buf[i + 1] = op->addr.val >>
102662306a36Sopenharmony_ci					(8 * (op->addr.nbytes - i - 1));
102762306a36Sopenharmony_ci	}
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	if (op->dummy.nbytes)
103062306a36Sopenharmony_ci		memset(tx_tmp_buf + op->addr.nbytes + 1,
103162306a36Sopenharmony_ci		       0xff,
103262306a36Sopenharmony_ci		       op->dummy.nbytes);
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT)
103562306a36Sopenharmony_ci		memcpy(tx_tmp_buf + op->dummy.nbytes + op->addr.nbytes + 1,
103662306a36Sopenharmony_ci		       op->data.buf.out,
103762306a36Sopenharmony_ci		       op->data.nbytes);
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	mdata->tx_dma = dma_map_single(mdata->dev, tx_tmp_buf,
104062306a36Sopenharmony_ci				       tx_size, DMA_TO_DEVICE);
104162306a36Sopenharmony_ci	if (dma_mapping_error(mdata->dev, mdata->tx_dma)) {
104262306a36Sopenharmony_ci		ret = -ENOMEM;
104362306a36Sopenharmony_ci		goto err_exit;
104462306a36Sopenharmony_ci	}
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	if (op->data.dir == SPI_MEM_DATA_IN) {
104762306a36Sopenharmony_ci		if (!IS_ALIGNED((size_t)op->data.buf.in, 4)) {
104862306a36Sopenharmony_ci			rx_tmp_buf = kzalloc(op->data.nbytes,
104962306a36Sopenharmony_ci					     GFP_KERNEL | GFP_DMA);
105062306a36Sopenharmony_ci			if (!rx_tmp_buf) {
105162306a36Sopenharmony_ci				ret = -ENOMEM;
105262306a36Sopenharmony_ci				goto unmap_tx_dma;
105362306a36Sopenharmony_ci			}
105462306a36Sopenharmony_ci		} else {
105562306a36Sopenharmony_ci			rx_tmp_buf = op->data.buf.in;
105662306a36Sopenharmony_ci		}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci		mdata->rx_dma = dma_map_single(mdata->dev,
105962306a36Sopenharmony_ci					       rx_tmp_buf,
106062306a36Sopenharmony_ci					       op->data.nbytes,
106162306a36Sopenharmony_ci					       DMA_FROM_DEVICE);
106262306a36Sopenharmony_ci		if (dma_mapping_error(mdata->dev, mdata->rx_dma)) {
106362306a36Sopenharmony_ci			ret = -ENOMEM;
106462306a36Sopenharmony_ci			goto kfree_rx_tmp_buf;
106562306a36Sopenharmony_ci		}
106662306a36Sopenharmony_ci	}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	reg_val = readl(mdata->base + SPI_CMD_REG);
106962306a36Sopenharmony_ci	reg_val |= SPI_CMD_TX_DMA;
107062306a36Sopenharmony_ci	if (op->data.dir == SPI_MEM_DATA_IN)
107162306a36Sopenharmony_ci		reg_val |= SPI_CMD_RX_DMA;
107262306a36Sopenharmony_ci	writel(reg_val, mdata->base + SPI_CMD_REG);
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	mtk_spi_mem_setup_dma_xfer(mem->spi->master, op);
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	mtk_spi_enable_transfer(mem->spi->master);
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	/* Wait for the interrupt. */
107962306a36Sopenharmony_ci	ret = mtk_spi_transfer_wait(mem, op);
108062306a36Sopenharmony_ci	if (ret)
108162306a36Sopenharmony_ci		goto unmap_rx_dma;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	/* spi disable dma */
108462306a36Sopenharmony_ci	reg_val = readl(mdata->base + SPI_CMD_REG);
108562306a36Sopenharmony_ci	reg_val &= ~SPI_CMD_TX_DMA;
108662306a36Sopenharmony_ci	if (op->data.dir == SPI_MEM_DATA_IN)
108762306a36Sopenharmony_ci		reg_val &= ~SPI_CMD_RX_DMA;
108862306a36Sopenharmony_ci	writel(reg_val, mdata->base + SPI_CMD_REG);
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ciunmap_rx_dma:
109162306a36Sopenharmony_ci	if (op->data.dir == SPI_MEM_DATA_IN) {
109262306a36Sopenharmony_ci		dma_unmap_single(mdata->dev, mdata->rx_dma,
109362306a36Sopenharmony_ci				 op->data.nbytes, DMA_FROM_DEVICE);
109462306a36Sopenharmony_ci		if (!IS_ALIGNED((size_t)op->data.buf.in, 4))
109562306a36Sopenharmony_ci			memcpy(op->data.buf.in, rx_tmp_buf, op->data.nbytes);
109662306a36Sopenharmony_ci	}
109762306a36Sopenharmony_cikfree_rx_tmp_buf:
109862306a36Sopenharmony_ci	if (op->data.dir == SPI_MEM_DATA_IN &&
109962306a36Sopenharmony_ci	    !IS_ALIGNED((size_t)op->data.buf.in, 4))
110062306a36Sopenharmony_ci		kfree(rx_tmp_buf);
110162306a36Sopenharmony_ciunmap_tx_dma:
110262306a36Sopenharmony_ci	dma_unmap_single(mdata->dev, mdata->tx_dma,
110362306a36Sopenharmony_ci			 tx_size, DMA_TO_DEVICE);
110462306a36Sopenharmony_cierr_exit:
110562306a36Sopenharmony_ci	kfree(tx_tmp_buf);
110662306a36Sopenharmony_ci	mdata->use_spimem = false;
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	return ret;
110962306a36Sopenharmony_ci}
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_cistatic const struct spi_controller_mem_ops mtk_spi_mem_ops = {
111262306a36Sopenharmony_ci	.adjust_op_size = mtk_spi_mem_adjust_op_size,
111362306a36Sopenharmony_ci	.supports_op = mtk_spi_mem_supports_op,
111462306a36Sopenharmony_ci	.exec_op = mtk_spi_mem_exec_op,
111562306a36Sopenharmony_ci};
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_cistatic int mtk_spi_probe(struct platform_device *pdev)
111862306a36Sopenharmony_ci{
111962306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
112062306a36Sopenharmony_ci	struct spi_master *master;
112162306a36Sopenharmony_ci	struct mtk_spi *mdata;
112262306a36Sopenharmony_ci	int i, irq, ret, addr_bits;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	master = devm_spi_alloc_master(dev, sizeof(*mdata));
112562306a36Sopenharmony_ci	if (!master)
112662306a36Sopenharmony_ci		return dev_err_probe(dev, -ENOMEM, "failed to alloc spi master\n");
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	master->auto_runtime_pm = true;
112962306a36Sopenharmony_ci	master->dev.of_node = dev->of_node;
113062306a36Sopenharmony_ci	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	master->set_cs = mtk_spi_set_cs;
113362306a36Sopenharmony_ci	master->prepare_message = mtk_spi_prepare_message;
113462306a36Sopenharmony_ci	master->transfer_one = mtk_spi_transfer_one;
113562306a36Sopenharmony_ci	master->can_dma = mtk_spi_can_dma;
113662306a36Sopenharmony_ci	master->setup = mtk_spi_setup;
113762306a36Sopenharmony_ci	master->set_cs_timing = mtk_spi_set_hw_cs_timing;
113862306a36Sopenharmony_ci	master->use_gpio_descriptors = true;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	mdata = spi_master_get_devdata(master);
114162306a36Sopenharmony_ci	mdata->dev_comp = device_get_match_data(dev);
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	if (mdata->dev_comp->enhance_timing)
114462306a36Sopenharmony_ci		master->mode_bits |= SPI_CS_HIGH;
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	if (mdata->dev_comp->must_tx)
114762306a36Sopenharmony_ci		master->flags = SPI_CONTROLLER_MUST_TX;
114862306a36Sopenharmony_ci	if (mdata->dev_comp->ipm_design)
114962306a36Sopenharmony_ci		master->mode_bits |= SPI_LOOP | SPI_RX_DUAL | SPI_TX_DUAL |
115062306a36Sopenharmony_ci				     SPI_RX_QUAD | SPI_TX_QUAD;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	if (mdata->dev_comp->ipm_design) {
115362306a36Sopenharmony_ci		mdata->dev = dev;
115462306a36Sopenharmony_ci		master->mem_ops = &mtk_spi_mem_ops;
115562306a36Sopenharmony_ci		init_completion(&mdata->spimem_done);
115662306a36Sopenharmony_ci	}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	if (mdata->dev_comp->need_pad_sel) {
115962306a36Sopenharmony_ci		mdata->pad_num = of_property_count_u32_elems(dev->of_node,
116062306a36Sopenharmony_ci			"mediatek,pad-select");
116162306a36Sopenharmony_ci		if (mdata->pad_num < 0)
116262306a36Sopenharmony_ci			return dev_err_probe(dev, -EINVAL,
116362306a36Sopenharmony_ci				"No 'mediatek,pad-select' property\n");
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci		mdata->pad_sel = devm_kmalloc_array(dev, mdata->pad_num,
116662306a36Sopenharmony_ci						    sizeof(u32), GFP_KERNEL);
116762306a36Sopenharmony_ci		if (!mdata->pad_sel)
116862306a36Sopenharmony_ci			return -ENOMEM;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci		for (i = 0; i < mdata->pad_num; i++) {
117162306a36Sopenharmony_ci			of_property_read_u32_index(dev->of_node,
117262306a36Sopenharmony_ci						   "mediatek,pad-select",
117362306a36Sopenharmony_ci						   i, &mdata->pad_sel[i]);
117462306a36Sopenharmony_ci			if (mdata->pad_sel[i] > MT8173_SPI_MAX_PAD_SEL)
117562306a36Sopenharmony_ci				return dev_err_probe(dev, -EINVAL,
117662306a36Sopenharmony_ci						     "wrong pad-sel[%d]: %u\n",
117762306a36Sopenharmony_ci						     i, mdata->pad_sel[i]);
117862306a36Sopenharmony_ci		}
117962306a36Sopenharmony_ci	}
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	platform_set_drvdata(pdev, master);
118262306a36Sopenharmony_ci	mdata->base = devm_platform_ioremap_resource(pdev, 0);
118362306a36Sopenharmony_ci	if (IS_ERR(mdata->base))
118462306a36Sopenharmony_ci		return PTR_ERR(mdata->base);
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
118762306a36Sopenharmony_ci	if (irq < 0)
118862306a36Sopenharmony_ci		return irq;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	if (!dev->dma_mask)
119162306a36Sopenharmony_ci		dev->dma_mask = &dev->coherent_dma_mask;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	if (mdata->dev_comp->ipm_design)
119462306a36Sopenharmony_ci		dma_set_max_seg_size(dev, SZ_16M);
119562306a36Sopenharmony_ci	else
119662306a36Sopenharmony_ci		dma_set_max_seg_size(dev, SZ_256K);
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	mdata->parent_clk = devm_clk_get(dev, "parent-clk");
119962306a36Sopenharmony_ci	if (IS_ERR(mdata->parent_clk))
120062306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(mdata->parent_clk),
120162306a36Sopenharmony_ci				     "failed to get parent-clk\n");
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	mdata->sel_clk = devm_clk_get(dev, "sel-clk");
120462306a36Sopenharmony_ci	if (IS_ERR(mdata->sel_clk))
120562306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(mdata->sel_clk), "failed to get sel-clk\n");
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	mdata->spi_clk = devm_clk_get(dev, "spi-clk");
120862306a36Sopenharmony_ci	if (IS_ERR(mdata->spi_clk))
120962306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(mdata->spi_clk), "failed to get spi-clk\n");
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	mdata->spi_hclk = devm_clk_get_optional(dev, "hclk");
121262306a36Sopenharmony_ci	if (IS_ERR(mdata->spi_hclk))
121362306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(mdata->spi_hclk), "failed to get hclk\n");
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	ret = clk_set_parent(mdata->sel_clk, mdata->parent_clk);
121662306a36Sopenharmony_ci	if (ret < 0)
121762306a36Sopenharmony_ci		return dev_err_probe(dev, ret, "failed to clk_set_parent\n");
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	ret = clk_prepare_enable(mdata->spi_hclk);
122062306a36Sopenharmony_ci	if (ret < 0)
122162306a36Sopenharmony_ci		return dev_err_probe(dev, ret, "failed to enable hclk\n");
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	ret = clk_prepare_enable(mdata->spi_clk);
122462306a36Sopenharmony_ci	if (ret < 0) {
122562306a36Sopenharmony_ci		clk_disable_unprepare(mdata->spi_hclk);
122662306a36Sopenharmony_ci		return dev_err_probe(dev, ret, "failed to enable spi_clk\n");
122762306a36Sopenharmony_ci	}
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	mdata->spi_clk_hz = clk_get_rate(mdata->spi_clk);
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	if (mdata->dev_comp->no_need_unprepare) {
123262306a36Sopenharmony_ci		clk_disable(mdata->spi_clk);
123362306a36Sopenharmony_ci		clk_disable(mdata->spi_hclk);
123462306a36Sopenharmony_ci	} else {
123562306a36Sopenharmony_ci		clk_disable_unprepare(mdata->spi_clk);
123662306a36Sopenharmony_ci		clk_disable_unprepare(mdata->spi_hclk);
123762306a36Sopenharmony_ci	}
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	if (mdata->dev_comp->need_pad_sel) {
124062306a36Sopenharmony_ci		if (mdata->pad_num != master->num_chipselect)
124162306a36Sopenharmony_ci			return dev_err_probe(dev, -EINVAL,
124262306a36Sopenharmony_ci				"pad_num does not match num_chipselect(%d != %d)\n",
124362306a36Sopenharmony_ci				mdata->pad_num, master->num_chipselect);
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci		if (!master->cs_gpiods && master->num_chipselect > 1)
124662306a36Sopenharmony_ci			return dev_err_probe(dev, -EINVAL,
124762306a36Sopenharmony_ci				"cs_gpios not specified and num_chipselect > 1\n");
124862306a36Sopenharmony_ci	}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	if (mdata->dev_comp->dma_ext)
125162306a36Sopenharmony_ci		addr_bits = DMA_ADDR_EXT_BITS;
125262306a36Sopenharmony_ci	else
125362306a36Sopenharmony_ci		addr_bits = DMA_ADDR_DEF_BITS;
125462306a36Sopenharmony_ci	ret = dma_set_mask(dev, DMA_BIT_MASK(addr_bits));
125562306a36Sopenharmony_ci	if (ret)
125662306a36Sopenharmony_ci		dev_notice(dev, "SPI dma_set_mask(%d) failed, ret:%d\n",
125762306a36Sopenharmony_ci			   addr_bits, ret);
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	ret = devm_request_irq(dev, irq, mtk_spi_interrupt,
126062306a36Sopenharmony_ci			       IRQF_TRIGGER_NONE, dev_name(dev), master);
126162306a36Sopenharmony_ci	if (ret)
126262306a36Sopenharmony_ci		return dev_err_probe(dev, ret, "failed to register irq\n");
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	pm_runtime_enable(dev);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	ret = devm_spi_register_master(dev, master);
126762306a36Sopenharmony_ci	if (ret) {
126862306a36Sopenharmony_ci		pm_runtime_disable(dev);
126962306a36Sopenharmony_ci		return dev_err_probe(dev, ret, "failed to register master\n");
127062306a36Sopenharmony_ci	}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	return 0;
127362306a36Sopenharmony_ci}
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_cistatic void mtk_spi_remove(struct platform_device *pdev)
127662306a36Sopenharmony_ci{
127762306a36Sopenharmony_ci	struct spi_master *master = platform_get_drvdata(pdev);
127862306a36Sopenharmony_ci	struct mtk_spi *mdata = spi_master_get_devdata(master);
127962306a36Sopenharmony_ci	int ret;
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	if (mdata->use_spimem && !completion_done(&mdata->spimem_done))
128262306a36Sopenharmony_ci		complete(&mdata->spimem_done);
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	ret = pm_runtime_get_sync(&pdev->dev);
128562306a36Sopenharmony_ci	if (ret < 0) {
128662306a36Sopenharmony_ci		dev_warn(&pdev->dev, "Failed to resume hardware (%pe)\n", ERR_PTR(ret));
128762306a36Sopenharmony_ci	} else {
128862306a36Sopenharmony_ci		/*
128962306a36Sopenharmony_ci		 * If pm runtime resume failed, clks are disabled and
129062306a36Sopenharmony_ci		 * unprepared. So don't access the hardware and skip clk
129162306a36Sopenharmony_ci		 * unpreparing.
129262306a36Sopenharmony_ci		 */
129362306a36Sopenharmony_ci		mtk_spi_reset(mdata);
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci		if (mdata->dev_comp->no_need_unprepare) {
129662306a36Sopenharmony_ci			clk_unprepare(mdata->spi_clk);
129762306a36Sopenharmony_ci			clk_unprepare(mdata->spi_hclk);
129862306a36Sopenharmony_ci		}
129962306a36Sopenharmony_ci	}
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	pm_runtime_put_noidle(&pdev->dev);
130262306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
130362306a36Sopenharmony_ci}
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
130662306a36Sopenharmony_cistatic int mtk_spi_suspend(struct device *dev)
130762306a36Sopenharmony_ci{
130862306a36Sopenharmony_ci	int ret;
130962306a36Sopenharmony_ci	struct spi_master *master = dev_get_drvdata(dev);
131062306a36Sopenharmony_ci	struct mtk_spi *mdata = spi_master_get_devdata(master);
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	ret = spi_master_suspend(master);
131362306a36Sopenharmony_ci	if (ret)
131462306a36Sopenharmony_ci		return ret;
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	if (!pm_runtime_suspended(dev)) {
131762306a36Sopenharmony_ci		clk_disable_unprepare(mdata->spi_clk);
131862306a36Sopenharmony_ci		clk_disable_unprepare(mdata->spi_hclk);
131962306a36Sopenharmony_ci	}
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	return 0;
132262306a36Sopenharmony_ci}
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_cistatic int mtk_spi_resume(struct device *dev)
132562306a36Sopenharmony_ci{
132662306a36Sopenharmony_ci	int ret;
132762306a36Sopenharmony_ci	struct spi_master *master = dev_get_drvdata(dev);
132862306a36Sopenharmony_ci	struct mtk_spi *mdata = spi_master_get_devdata(master);
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	if (!pm_runtime_suspended(dev)) {
133162306a36Sopenharmony_ci		ret = clk_prepare_enable(mdata->spi_clk);
133262306a36Sopenharmony_ci		if (ret < 0) {
133362306a36Sopenharmony_ci			dev_err(dev, "failed to enable spi_clk (%d)\n", ret);
133462306a36Sopenharmony_ci			return ret;
133562306a36Sopenharmony_ci		}
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci		ret = clk_prepare_enable(mdata->spi_hclk);
133862306a36Sopenharmony_ci		if (ret < 0) {
133962306a36Sopenharmony_ci			dev_err(dev, "failed to enable spi_hclk (%d)\n", ret);
134062306a36Sopenharmony_ci			clk_disable_unprepare(mdata->spi_clk);
134162306a36Sopenharmony_ci			return ret;
134262306a36Sopenharmony_ci		}
134362306a36Sopenharmony_ci	}
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	ret = spi_master_resume(master);
134662306a36Sopenharmony_ci	if (ret < 0) {
134762306a36Sopenharmony_ci		clk_disable_unprepare(mdata->spi_clk);
134862306a36Sopenharmony_ci		clk_disable_unprepare(mdata->spi_hclk);
134962306a36Sopenharmony_ci	}
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	return ret;
135262306a36Sopenharmony_ci}
135362306a36Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci#ifdef CONFIG_PM
135662306a36Sopenharmony_cistatic int mtk_spi_runtime_suspend(struct device *dev)
135762306a36Sopenharmony_ci{
135862306a36Sopenharmony_ci	struct spi_master *master = dev_get_drvdata(dev);
135962306a36Sopenharmony_ci	struct mtk_spi *mdata = spi_master_get_devdata(master);
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	if (mdata->dev_comp->no_need_unprepare) {
136262306a36Sopenharmony_ci		clk_disable(mdata->spi_clk);
136362306a36Sopenharmony_ci		clk_disable(mdata->spi_hclk);
136462306a36Sopenharmony_ci	} else {
136562306a36Sopenharmony_ci		clk_disable_unprepare(mdata->spi_clk);
136662306a36Sopenharmony_ci		clk_disable_unprepare(mdata->spi_hclk);
136762306a36Sopenharmony_ci	}
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	return 0;
137062306a36Sopenharmony_ci}
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_cistatic int mtk_spi_runtime_resume(struct device *dev)
137362306a36Sopenharmony_ci{
137462306a36Sopenharmony_ci	struct spi_master *master = dev_get_drvdata(dev);
137562306a36Sopenharmony_ci	struct mtk_spi *mdata = spi_master_get_devdata(master);
137662306a36Sopenharmony_ci	int ret;
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	if (mdata->dev_comp->no_need_unprepare) {
137962306a36Sopenharmony_ci		ret = clk_enable(mdata->spi_clk);
138062306a36Sopenharmony_ci		if (ret < 0) {
138162306a36Sopenharmony_ci			dev_err(dev, "failed to enable spi_clk (%d)\n", ret);
138262306a36Sopenharmony_ci			return ret;
138362306a36Sopenharmony_ci		}
138462306a36Sopenharmony_ci		ret = clk_enable(mdata->spi_hclk);
138562306a36Sopenharmony_ci		if (ret < 0) {
138662306a36Sopenharmony_ci			dev_err(dev, "failed to enable spi_hclk (%d)\n", ret);
138762306a36Sopenharmony_ci			clk_disable(mdata->spi_clk);
138862306a36Sopenharmony_ci			return ret;
138962306a36Sopenharmony_ci		}
139062306a36Sopenharmony_ci	} else {
139162306a36Sopenharmony_ci		ret = clk_prepare_enable(mdata->spi_clk);
139262306a36Sopenharmony_ci		if (ret < 0) {
139362306a36Sopenharmony_ci			dev_err(dev, "failed to prepare_enable spi_clk (%d)\n", ret);
139462306a36Sopenharmony_ci			return ret;
139562306a36Sopenharmony_ci		}
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci		ret = clk_prepare_enable(mdata->spi_hclk);
139862306a36Sopenharmony_ci		if (ret < 0) {
139962306a36Sopenharmony_ci			dev_err(dev, "failed to prepare_enable spi_hclk (%d)\n", ret);
140062306a36Sopenharmony_ci			clk_disable_unprepare(mdata->spi_clk);
140162306a36Sopenharmony_ci			return ret;
140262306a36Sopenharmony_ci		}
140362306a36Sopenharmony_ci	}
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	return 0;
140662306a36Sopenharmony_ci}
140762306a36Sopenharmony_ci#endif /* CONFIG_PM */
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_cistatic const struct dev_pm_ops mtk_spi_pm = {
141062306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(mtk_spi_suspend, mtk_spi_resume)
141162306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(mtk_spi_runtime_suspend,
141262306a36Sopenharmony_ci			   mtk_spi_runtime_resume, NULL)
141362306a36Sopenharmony_ci};
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_cistatic struct platform_driver mtk_spi_driver = {
141662306a36Sopenharmony_ci	.driver = {
141762306a36Sopenharmony_ci		.name = "mtk-spi",
141862306a36Sopenharmony_ci		.pm	= &mtk_spi_pm,
141962306a36Sopenharmony_ci		.of_match_table = mtk_spi_of_match,
142062306a36Sopenharmony_ci	},
142162306a36Sopenharmony_ci	.probe = mtk_spi_probe,
142262306a36Sopenharmony_ci	.remove_new = mtk_spi_remove,
142362306a36Sopenharmony_ci};
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_cimodule_platform_driver(mtk_spi_driver);
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ciMODULE_DESCRIPTION("MTK SPI Controller driver");
142862306a36Sopenharmony_ciMODULE_AUTHOR("Leilk Liu <leilk.liu@mediatek.com>");
142962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
143062306a36Sopenharmony_ciMODULE_ALIAS("platform:mtk-spi");
1431