xref: /kernel/linux/linux-6.6/drivers/spi/spi-imx.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci// Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
362306a36Sopenharmony_ci// Copyright (C) 2008 Juergen Beisert
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/bits.h>
662306a36Sopenharmony_ci#include <linux/clk.h>
762306a36Sopenharmony_ci#include <linux/completion.h>
862306a36Sopenharmony_ci#include <linux/delay.h>
962306a36Sopenharmony_ci#include <linux/dmaengine.h>
1062306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1162306a36Sopenharmony_ci#include <linux/err.h>
1262306a36Sopenharmony_ci#include <linux/interrupt.h>
1362306a36Sopenharmony_ci#include <linux/io.h>
1462306a36Sopenharmony_ci#include <linux/irq.h>
1562306a36Sopenharmony_ci#include <linux/kernel.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h>
1862306a36Sopenharmony_ci#include <linux/platform_device.h>
1962306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2062306a36Sopenharmony_ci#include <linux/slab.h>
2162306a36Sopenharmony_ci#include <linux/spi/spi.h>
2262306a36Sopenharmony_ci#include <linux/types.h>
2362306a36Sopenharmony_ci#include <linux/of.h>
2462306a36Sopenharmony_ci#include <linux/property.h>
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#include <linux/dma/imx-dma.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define DRIVER_NAME "spi_imx"
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic bool use_dma = true;
3162306a36Sopenharmony_cimodule_param(use_dma, bool, 0644);
3262306a36Sopenharmony_ciMODULE_PARM_DESC(use_dma, "Enable usage of DMA when available (default)");
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* define polling limits */
3562306a36Sopenharmony_cistatic unsigned int polling_limit_us = 30;
3662306a36Sopenharmony_cimodule_param(polling_limit_us, uint, 0664);
3762306a36Sopenharmony_ciMODULE_PARM_DESC(polling_limit_us,
3862306a36Sopenharmony_ci		 "time in us to run a transfer in polling mode\n");
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define MXC_RPM_TIMEOUT		2000 /* 2000ms */
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define MXC_CSPIRXDATA		0x00
4362306a36Sopenharmony_ci#define MXC_CSPITXDATA		0x04
4462306a36Sopenharmony_ci#define MXC_CSPICTRL		0x08
4562306a36Sopenharmony_ci#define MXC_CSPIINT		0x0c
4662306a36Sopenharmony_ci#define MXC_RESET		0x1c
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* generic defines to abstract from the different register layouts */
4962306a36Sopenharmony_ci#define MXC_INT_RR	(1 << 0) /* Receive data ready interrupt */
5062306a36Sopenharmony_ci#define MXC_INT_TE	(1 << 1) /* Transmit FIFO empty interrupt */
5162306a36Sopenharmony_ci#define MXC_INT_RDR	BIT(4) /* Receive date threshold interrupt */
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* The maximum bytes that a sdma BD can transfer. */
5462306a36Sopenharmony_ci#define MAX_SDMA_BD_BYTES (1 << 15)
5562306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_MAX_BURST	512
5662306a36Sopenharmony_ci/* The maximum bytes that IMX53_ECSPI can transfer in target mode.*/
5762306a36Sopenharmony_ci#define MX53_MAX_TRANSFER_BYTES		512
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cienum spi_imx_devtype {
6062306a36Sopenharmony_ci	IMX1_CSPI,
6162306a36Sopenharmony_ci	IMX21_CSPI,
6262306a36Sopenharmony_ci	IMX27_CSPI,
6362306a36Sopenharmony_ci	IMX31_CSPI,
6462306a36Sopenharmony_ci	IMX35_CSPI,	/* CSPI on all i.mx except above */
6562306a36Sopenharmony_ci	IMX51_ECSPI,	/* ECSPI on i.mx51 */
6662306a36Sopenharmony_ci	IMX53_ECSPI,	/* ECSPI on i.mx53 and later */
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistruct spi_imx_data;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistruct spi_imx_devtype_data {
7262306a36Sopenharmony_ci	void (*intctrl)(struct spi_imx_data *spi_imx, int enable);
7362306a36Sopenharmony_ci	int (*prepare_message)(struct spi_imx_data *spi_imx, struct spi_message *msg);
7462306a36Sopenharmony_ci	int (*prepare_transfer)(struct spi_imx_data *spi_imx, struct spi_device *spi);
7562306a36Sopenharmony_ci	void (*trigger)(struct spi_imx_data *spi_imx);
7662306a36Sopenharmony_ci	int (*rx_available)(struct spi_imx_data *spi_imx);
7762306a36Sopenharmony_ci	void (*reset)(struct spi_imx_data *spi_imx);
7862306a36Sopenharmony_ci	void (*setup_wml)(struct spi_imx_data *spi_imx);
7962306a36Sopenharmony_ci	void (*disable)(struct spi_imx_data *spi_imx);
8062306a36Sopenharmony_ci	bool has_dmamode;
8162306a36Sopenharmony_ci	bool has_targetmode;
8262306a36Sopenharmony_ci	unsigned int fifo_size;
8362306a36Sopenharmony_ci	bool dynamic_burst;
8462306a36Sopenharmony_ci	/*
8562306a36Sopenharmony_ci	 * ERR009165 fixed or not:
8662306a36Sopenharmony_ci	 * https://www.nxp.com/docs/en/errata/IMX6DQCE.pdf
8762306a36Sopenharmony_ci	 */
8862306a36Sopenharmony_ci	bool tx_glitch_fixed;
8962306a36Sopenharmony_ci	enum spi_imx_devtype devtype;
9062306a36Sopenharmony_ci};
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistruct spi_imx_data {
9362306a36Sopenharmony_ci	struct spi_controller *controller;
9462306a36Sopenharmony_ci	struct device *dev;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	struct completion xfer_done;
9762306a36Sopenharmony_ci	void __iomem *base;
9862306a36Sopenharmony_ci	unsigned long base_phys;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	struct clk *clk_per;
10162306a36Sopenharmony_ci	struct clk *clk_ipg;
10262306a36Sopenharmony_ci	unsigned long spi_clk;
10362306a36Sopenharmony_ci	unsigned int spi_bus_clk;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	unsigned int bits_per_word;
10662306a36Sopenharmony_ci	unsigned int spi_drctl;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	unsigned int count, remainder;
10962306a36Sopenharmony_ci	void (*tx)(struct spi_imx_data *spi_imx);
11062306a36Sopenharmony_ci	void (*rx)(struct spi_imx_data *spi_imx);
11162306a36Sopenharmony_ci	void *rx_buf;
11262306a36Sopenharmony_ci	const void *tx_buf;
11362306a36Sopenharmony_ci	unsigned int txfifo; /* number of words pushed in tx FIFO */
11462306a36Sopenharmony_ci	unsigned int dynamic_burst;
11562306a36Sopenharmony_ci	bool rx_only;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	/* Target mode */
11862306a36Sopenharmony_ci	bool target_mode;
11962306a36Sopenharmony_ci	bool target_aborted;
12062306a36Sopenharmony_ci	unsigned int target_burst;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	/* DMA */
12362306a36Sopenharmony_ci	bool usedma;
12462306a36Sopenharmony_ci	u32 wml;
12562306a36Sopenharmony_ci	struct completion dma_rx_completion;
12662306a36Sopenharmony_ci	struct completion dma_tx_completion;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	const struct spi_imx_devtype_data *devtype_data;
12962306a36Sopenharmony_ci};
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic inline int is_imx27_cspi(struct spi_imx_data *d)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	return d->devtype_data->devtype == IMX27_CSPI;
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic inline int is_imx35_cspi(struct spi_imx_data *d)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	return d->devtype_data->devtype == IMX35_CSPI;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic inline int is_imx51_ecspi(struct spi_imx_data *d)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	return d->devtype_data->devtype == IMX51_ECSPI;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic inline int is_imx53_ecspi(struct spi_imx_data *d)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	return d->devtype_data->devtype == IMX53_ECSPI;
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci#define MXC_SPI_BUF_RX(type)						\
15262306a36Sopenharmony_cistatic void spi_imx_buf_rx_##type(struct spi_imx_data *spi_imx)		\
15362306a36Sopenharmony_ci{									\
15462306a36Sopenharmony_ci	unsigned int val = readl(spi_imx->base + MXC_CSPIRXDATA);	\
15562306a36Sopenharmony_ci									\
15662306a36Sopenharmony_ci	if (spi_imx->rx_buf) {						\
15762306a36Sopenharmony_ci		*(type *)spi_imx->rx_buf = val;				\
15862306a36Sopenharmony_ci		spi_imx->rx_buf += sizeof(type);			\
15962306a36Sopenharmony_ci	}								\
16062306a36Sopenharmony_ci									\
16162306a36Sopenharmony_ci	spi_imx->remainder -= sizeof(type);				\
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci#define MXC_SPI_BUF_TX(type)						\
16562306a36Sopenharmony_cistatic void spi_imx_buf_tx_##type(struct spi_imx_data *spi_imx)		\
16662306a36Sopenharmony_ci{									\
16762306a36Sopenharmony_ci	type val = 0;							\
16862306a36Sopenharmony_ci									\
16962306a36Sopenharmony_ci	if (spi_imx->tx_buf) {						\
17062306a36Sopenharmony_ci		val = *(type *)spi_imx->tx_buf;				\
17162306a36Sopenharmony_ci		spi_imx->tx_buf += sizeof(type);			\
17262306a36Sopenharmony_ci	}								\
17362306a36Sopenharmony_ci									\
17462306a36Sopenharmony_ci	spi_imx->count -= sizeof(type);					\
17562306a36Sopenharmony_ci									\
17662306a36Sopenharmony_ci	writel(val, spi_imx->base + MXC_CSPITXDATA);			\
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ciMXC_SPI_BUF_RX(u8)
18062306a36Sopenharmony_ciMXC_SPI_BUF_TX(u8)
18162306a36Sopenharmony_ciMXC_SPI_BUF_RX(u16)
18262306a36Sopenharmony_ciMXC_SPI_BUF_TX(u16)
18362306a36Sopenharmony_ciMXC_SPI_BUF_RX(u32)
18462306a36Sopenharmony_ciMXC_SPI_BUF_TX(u32)
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci/* First entry is reserved, second entry is valid only if SDHC_SPIEN is set
18762306a36Sopenharmony_ci * (which is currently not the case in this driver)
18862306a36Sopenharmony_ci */
18962306a36Sopenharmony_cistatic int mxc_clkdivs[] = {0, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192,
19062306a36Sopenharmony_ci	256, 384, 512, 768, 1024};
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci/* MX21, MX27 */
19362306a36Sopenharmony_cistatic unsigned int spi_imx_clkdiv_1(unsigned int fin,
19462306a36Sopenharmony_ci		unsigned int fspi, unsigned int max, unsigned int *fres)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	int i;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	for (i = 2; i < max; i++)
19962306a36Sopenharmony_ci		if (fspi * mxc_clkdivs[i] >= fin)
20062306a36Sopenharmony_ci			break;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	*fres = fin / mxc_clkdivs[i];
20362306a36Sopenharmony_ci	return i;
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci/* MX1, MX31, MX35, MX51 CSPI */
20762306a36Sopenharmony_cistatic unsigned int spi_imx_clkdiv_2(unsigned int fin,
20862306a36Sopenharmony_ci		unsigned int fspi, unsigned int *fres)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	int i, div = 4;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	for (i = 0; i < 7; i++) {
21362306a36Sopenharmony_ci		if (fspi * div >= fin)
21462306a36Sopenharmony_ci			goto out;
21562306a36Sopenharmony_ci		div <<= 1;
21662306a36Sopenharmony_ci	}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ciout:
21962306a36Sopenharmony_ci	*fres = fin / div;
22062306a36Sopenharmony_ci	return i;
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_cistatic int spi_imx_bytes_per_word(const int bits_per_word)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	if (bits_per_word <= 8)
22662306a36Sopenharmony_ci		return 1;
22762306a36Sopenharmony_ci	else if (bits_per_word <= 16)
22862306a36Sopenharmony_ci		return 2;
22962306a36Sopenharmony_ci	else
23062306a36Sopenharmony_ci		return 4;
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device *spi,
23462306a36Sopenharmony_ci			 struct spi_transfer *transfer)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	if (!use_dma || controller->fallback)
23962306a36Sopenharmony_ci		return false;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	if (!controller->dma_rx)
24262306a36Sopenharmony_ci		return false;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	if (spi_imx->target_mode)
24562306a36Sopenharmony_ci		return false;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	if (transfer->len < spi_imx->devtype_data->fifo_size)
24862306a36Sopenharmony_ci		return false;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	spi_imx->dynamic_burst = 0;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	return true;
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci/*
25662306a36Sopenharmony_ci * Note the number of natively supported chip selects for MX51 is 4. Some
25762306a36Sopenharmony_ci * devices may have less actual SS pins but the register map supports 4. When
25862306a36Sopenharmony_ci * using gpio chip selects the cs values passed into the macros below can go
25962306a36Sopenharmony_ci * outside the range 0 - 3. We therefore need to limit the cs value to avoid
26062306a36Sopenharmony_ci * corrupting bits outside the allocated locations.
26162306a36Sopenharmony_ci *
26262306a36Sopenharmony_ci * The simplest way to do this is to just mask the cs bits to 2 bits. This
26362306a36Sopenharmony_ci * still allows all 4 native chip selects to work as well as gpio chip selects
26462306a36Sopenharmony_ci * (which can use any of the 4 chip select configurations).
26562306a36Sopenharmony_ci */
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci#define MX51_ECSPI_CTRL		0x08
26862306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_ENABLE		(1 <<  0)
26962306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_XCH		(1 <<  2)
27062306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_SMC		(1 << 3)
27162306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_MODE_MASK	(0xf << 4)
27262306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_DRCTL(drctl)	((drctl) << 16)
27362306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_POSTDIV_OFFSET	8
27462306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_PREDIV_OFFSET	12
27562306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_CS(cs)		((cs & 3) << 18)
27662306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_BL_OFFSET	20
27762306a36Sopenharmony_ci#define MX51_ECSPI_CTRL_BL_MASK		(0xfff << 20)
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci#define MX51_ECSPI_CONFIG	0x0c
28062306a36Sopenharmony_ci#define MX51_ECSPI_CONFIG_SCLKPHA(cs)	(1 << ((cs & 3) +  0))
28162306a36Sopenharmony_ci#define MX51_ECSPI_CONFIG_SCLKPOL(cs)	(1 << ((cs & 3) +  4))
28262306a36Sopenharmony_ci#define MX51_ECSPI_CONFIG_SBBCTRL(cs)	(1 << ((cs & 3) +  8))
28362306a36Sopenharmony_ci#define MX51_ECSPI_CONFIG_SSBPOL(cs)	(1 << ((cs & 3) + 12))
28462306a36Sopenharmony_ci#define MX51_ECSPI_CONFIG_DATACTL(cs)	(1 << ((cs & 3) + 16))
28562306a36Sopenharmony_ci#define MX51_ECSPI_CONFIG_SCLKCTL(cs)	(1 << ((cs & 3) + 20))
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci#define MX51_ECSPI_INT		0x10
28862306a36Sopenharmony_ci#define MX51_ECSPI_INT_TEEN		(1 <<  0)
28962306a36Sopenharmony_ci#define MX51_ECSPI_INT_RREN		(1 <<  3)
29062306a36Sopenharmony_ci#define MX51_ECSPI_INT_RDREN		(1 <<  4)
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci#define MX51_ECSPI_DMA		0x14
29362306a36Sopenharmony_ci#define MX51_ECSPI_DMA_TX_WML(wml)	((wml) & 0x3f)
29462306a36Sopenharmony_ci#define MX51_ECSPI_DMA_RX_WML(wml)	(((wml) & 0x3f) << 16)
29562306a36Sopenharmony_ci#define MX51_ECSPI_DMA_RXT_WML(wml)	(((wml) & 0x3f) << 24)
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci#define MX51_ECSPI_DMA_TEDEN		(1 << 7)
29862306a36Sopenharmony_ci#define MX51_ECSPI_DMA_RXDEN		(1 << 23)
29962306a36Sopenharmony_ci#define MX51_ECSPI_DMA_RXTDEN		(1 << 31)
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci#define MX51_ECSPI_STAT		0x18
30262306a36Sopenharmony_ci#define MX51_ECSPI_STAT_RR		(1 <<  3)
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci#define MX51_ECSPI_TESTREG	0x20
30562306a36Sopenharmony_ci#define MX51_ECSPI_TESTREG_LBC	BIT(31)
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_cistatic void spi_imx_buf_rx_swap_u32(struct spi_imx_data *spi_imx)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	unsigned int val = readl(spi_imx->base + MXC_CSPIRXDATA);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	if (spi_imx->rx_buf) {
31262306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN
31362306a36Sopenharmony_ci		unsigned int bytes_per_word;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci		bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
31662306a36Sopenharmony_ci		if (bytes_per_word == 1)
31762306a36Sopenharmony_ci			swab32s(&val);
31862306a36Sopenharmony_ci		else if (bytes_per_word == 2)
31962306a36Sopenharmony_ci			swahw32s(&val);
32062306a36Sopenharmony_ci#endif
32162306a36Sopenharmony_ci		*(u32 *)spi_imx->rx_buf = val;
32262306a36Sopenharmony_ci		spi_imx->rx_buf += sizeof(u32);
32362306a36Sopenharmony_ci	}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	spi_imx->remainder -= sizeof(u32);
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic void spi_imx_buf_rx_swap(struct spi_imx_data *spi_imx)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	int unaligned;
33162306a36Sopenharmony_ci	u32 val;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	unaligned = spi_imx->remainder % 4;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	if (!unaligned) {
33662306a36Sopenharmony_ci		spi_imx_buf_rx_swap_u32(spi_imx);
33762306a36Sopenharmony_ci		return;
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (spi_imx_bytes_per_word(spi_imx->bits_per_word) == 2) {
34162306a36Sopenharmony_ci		spi_imx_buf_rx_u16(spi_imx);
34262306a36Sopenharmony_ci		return;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	val = readl(spi_imx->base + MXC_CSPIRXDATA);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	while (unaligned--) {
34862306a36Sopenharmony_ci		if (spi_imx->rx_buf) {
34962306a36Sopenharmony_ci			*(u8 *)spi_imx->rx_buf = (val >> (8 * unaligned)) & 0xff;
35062306a36Sopenharmony_ci			spi_imx->rx_buf++;
35162306a36Sopenharmony_ci		}
35262306a36Sopenharmony_ci		spi_imx->remainder--;
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic void spi_imx_buf_tx_swap_u32(struct spi_imx_data *spi_imx)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	u32 val = 0;
35962306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN
36062306a36Sopenharmony_ci	unsigned int bytes_per_word;
36162306a36Sopenharmony_ci#endif
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	if (spi_imx->tx_buf) {
36462306a36Sopenharmony_ci		val = *(u32 *)spi_imx->tx_buf;
36562306a36Sopenharmony_ci		spi_imx->tx_buf += sizeof(u32);
36662306a36Sopenharmony_ci	}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	spi_imx->count -= sizeof(u32);
36962306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN
37062306a36Sopenharmony_ci	bytes_per_word = spi_imx_bytes_per_word(spi_imx->bits_per_word);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (bytes_per_word == 1)
37362306a36Sopenharmony_ci		swab32s(&val);
37462306a36Sopenharmony_ci	else if (bytes_per_word == 2)
37562306a36Sopenharmony_ci		swahw32s(&val);
37662306a36Sopenharmony_ci#endif
37762306a36Sopenharmony_ci	writel(val, spi_imx->base + MXC_CSPITXDATA);
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	int unaligned;
38362306a36Sopenharmony_ci	u32 val = 0;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	unaligned = spi_imx->count % 4;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	if (!unaligned) {
38862306a36Sopenharmony_ci		spi_imx_buf_tx_swap_u32(spi_imx);
38962306a36Sopenharmony_ci		return;
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	if (spi_imx_bytes_per_word(spi_imx->bits_per_word) == 2) {
39362306a36Sopenharmony_ci		spi_imx_buf_tx_u16(spi_imx);
39462306a36Sopenharmony_ci		return;
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	while (unaligned--) {
39862306a36Sopenharmony_ci		if (spi_imx->tx_buf) {
39962306a36Sopenharmony_ci			val |= *(u8 *)spi_imx->tx_buf << (8 * unaligned);
40062306a36Sopenharmony_ci			spi_imx->tx_buf++;
40162306a36Sopenharmony_ci		}
40262306a36Sopenharmony_ci		spi_imx->count--;
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	writel(val, spi_imx->base + MXC_CSPITXDATA);
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cistatic void mx53_ecspi_rx_target(struct spi_imx_data *spi_imx)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	u32 val = be32_to_cpu(readl(spi_imx->base + MXC_CSPIRXDATA));
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	if (spi_imx->rx_buf) {
41362306a36Sopenharmony_ci		int n_bytes = spi_imx->target_burst % sizeof(val);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci		if (!n_bytes)
41662306a36Sopenharmony_ci			n_bytes = sizeof(val);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci		memcpy(spi_imx->rx_buf,
41962306a36Sopenharmony_ci		       ((u8 *)&val) + sizeof(val) - n_bytes, n_bytes);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci		spi_imx->rx_buf += n_bytes;
42262306a36Sopenharmony_ci		spi_imx->target_burst -= n_bytes;
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	spi_imx->remainder -= sizeof(u32);
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_cistatic void mx53_ecspi_tx_target(struct spi_imx_data *spi_imx)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	u32 val = 0;
43162306a36Sopenharmony_ci	int n_bytes = spi_imx->count % sizeof(val);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	if (!n_bytes)
43462306a36Sopenharmony_ci		n_bytes = sizeof(val);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	if (spi_imx->tx_buf) {
43762306a36Sopenharmony_ci		memcpy(((u8 *)&val) + sizeof(val) - n_bytes,
43862306a36Sopenharmony_ci		       spi_imx->tx_buf, n_bytes);
43962306a36Sopenharmony_ci		val = cpu_to_be32(val);
44062306a36Sopenharmony_ci		spi_imx->tx_buf += n_bytes;
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	spi_imx->count -= n_bytes;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	writel(val, spi_imx->base + MXC_CSPITXDATA);
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci/* MX51 eCSPI */
44962306a36Sopenharmony_cistatic unsigned int mx51_ecspi_clkdiv(struct spi_imx_data *spi_imx,
45062306a36Sopenharmony_ci				      unsigned int fspi, unsigned int *fres)
45162306a36Sopenharmony_ci{
45262306a36Sopenharmony_ci	/*
45362306a36Sopenharmony_ci	 * there are two 4-bit dividers, the pre-divider divides by
45462306a36Sopenharmony_ci	 * $pre, the post-divider by 2^$post
45562306a36Sopenharmony_ci	 */
45662306a36Sopenharmony_ci	unsigned int pre, post;
45762306a36Sopenharmony_ci	unsigned int fin = spi_imx->spi_clk;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	fspi = min(fspi, fin);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	post = fls(fin) - fls(fspi);
46262306a36Sopenharmony_ci	if (fin > fspi << post)
46362306a36Sopenharmony_ci		post++;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	/* now we have: (fin <= fspi << post) with post being minimal */
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	post = max(4U, post) - 4;
46862306a36Sopenharmony_ci	if (unlikely(post > 0xf)) {
46962306a36Sopenharmony_ci		dev_err(spi_imx->dev, "cannot set clock freq: %u (base freq: %u)\n",
47062306a36Sopenharmony_ci				fspi, fin);
47162306a36Sopenharmony_ci		return 0xff;
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	pre = DIV_ROUND_UP(fin, fspi << post) - 1;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	dev_dbg(spi_imx->dev, "%s: fin: %u, fspi: %u, post: %u, pre: %u\n",
47762306a36Sopenharmony_ci			__func__, fin, fspi, post, pre);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	/* Resulting frequency for the SCLK line. */
48062306a36Sopenharmony_ci	*fres = (fin / (pre + 1)) >> post;
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	return (pre << MX51_ECSPI_CTRL_PREDIV_OFFSET) |
48362306a36Sopenharmony_ci		(post << MX51_ECSPI_CTRL_POSTDIV_OFFSET);
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_cistatic void mx51_ecspi_intctrl(struct spi_imx_data *spi_imx, int enable)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	unsigned int val = 0;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (enable & MXC_INT_TE)
49162306a36Sopenharmony_ci		val |= MX51_ECSPI_INT_TEEN;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	if (enable & MXC_INT_RR)
49462306a36Sopenharmony_ci		val |= MX51_ECSPI_INT_RREN;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	if (enable & MXC_INT_RDR)
49762306a36Sopenharmony_ci		val |= MX51_ECSPI_INT_RDREN;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	writel(val, spi_imx->base + MX51_ECSPI_INT);
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_cistatic void mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	u32 reg;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	reg = readl(spi_imx->base + MX51_ECSPI_CTRL);
50762306a36Sopenharmony_ci	reg |= MX51_ECSPI_CTRL_XCH;
50862306a36Sopenharmony_ci	writel(reg, spi_imx->base + MX51_ECSPI_CTRL);
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cistatic void mx51_ecspi_disable(struct spi_imx_data *spi_imx)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	u32 ctrl;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
51662306a36Sopenharmony_ci	ctrl &= ~MX51_ECSPI_CTRL_ENABLE;
51762306a36Sopenharmony_ci	writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistatic int mx51_ecspi_channel(const struct spi_device *spi)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	if (!spi_get_csgpiod(spi, 0))
52362306a36Sopenharmony_ci		return spi_get_chipselect(spi, 0);
52462306a36Sopenharmony_ci	return spi->controller->unused_native_cs;
52562306a36Sopenharmony_ci}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_cistatic int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
52862306a36Sopenharmony_ci				      struct spi_message *msg)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	struct spi_device *spi = msg->spi;
53162306a36Sopenharmony_ci	struct spi_transfer *xfer;
53262306a36Sopenharmony_ci	u32 ctrl = MX51_ECSPI_CTRL_ENABLE;
53362306a36Sopenharmony_ci	u32 min_speed_hz = ~0U;
53462306a36Sopenharmony_ci	u32 testreg, delay;
53562306a36Sopenharmony_ci	u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG);
53662306a36Sopenharmony_ci	u32 current_cfg = cfg;
53762306a36Sopenharmony_ci	int channel = mx51_ecspi_channel(spi);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	/* set Host or Target mode */
54062306a36Sopenharmony_ci	if (spi_imx->target_mode)
54162306a36Sopenharmony_ci		ctrl &= ~MX51_ECSPI_CTRL_MODE_MASK;
54262306a36Sopenharmony_ci	else
54362306a36Sopenharmony_ci		ctrl |= MX51_ECSPI_CTRL_MODE_MASK;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	/*
54662306a36Sopenharmony_ci	 * Enable SPI_RDY handling (falling edge/level triggered).
54762306a36Sopenharmony_ci	 */
54862306a36Sopenharmony_ci	if (spi->mode & SPI_READY)
54962306a36Sopenharmony_ci		ctrl |= MX51_ECSPI_CTRL_DRCTL(spi_imx->spi_drctl);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	/* set chip select to use */
55262306a36Sopenharmony_ci	ctrl |= MX51_ECSPI_CTRL_CS(channel);
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	/*
55562306a36Sopenharmony_ci	 * The ctrl register must be written first, with the EN bit set other
55662306a36Sopenharmony_ci	 * registers must not be written to.
55762306a36Sopenharmony_ci	 */
55862306a36Sopenharmony_ci	writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	testreg = readl(spi_imx->base + MX51_ECSPI_TESTREG);
56162306a36Sopenharmony_ci	if (spi->mode & SPI_LOOP)
56262306a36Sopenharmony_ci		testreg |= MX51_ECSPI_TESTREG_LBC;
56362306a36Sopenharmony_ci	else
56462306a36Sopenharmony_ci		testreg &= ~MX51_ECSPI_TESTREG_LBC;
56562306a36Sopenharmony_ci	writel(testreg, spi_imx->base + MX51_ECSPI_TESTREG);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	/*
56862306a36Sopenharmony_ci	 * eCSPI burst completion by Chip Select signal in Target mode
56962306a36Sopenharmony_ci	 * is not functional for imx53 Soc, config SPI burst completed when
57062306a36Sopenharmony_ci	 * BURST_LENGTH + 1 bits are received
57162306a36Sopenharmony_ci	 */
57262306a36Sopenharmony_ci	if (spi_imx->target_mode && is_imx53_ecspi(spi_imx))
57362306a36Sopenharmony_ci		cfg &= ~MX51_ECSPI_CONFIG_SBBCTRL(channel);
57462306a36Sopenharmony_ci	else
57562306a36Sopenharmony_ci		cfg |= MX51_ECSPI_CONFIG_SBBCTRL(channel);
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	if (spi->mode & SPI_CPOL) {
57862306a36Sopenharmony_ci		cfg |= MX51_ECSPI_CONFIG_SCLKPOL(channel);
57962306a36Sopenharmony_ci		cfg |= MX51_ECSPI_CONFIG_SCLKCTL(channel);
58062306a36Sopenharmony_ci	} else {
58162306a36Sopenharmony_ci		cfg &= ~MX51_ECSPI_CONFIG_SCLKPOL(channel);
58262306a36Sopenharmony_ci		cfg &= ~MX51_ECSPI_CONFIG_SCLKCTL(channel);
58362306a36Sopenharmony_ci	}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	if (spi->mode & SPI_MOSI_IDLE_LOW)
58662306a36Sopenharmony_ci		cfg |= MX51_ECSPI_CONFIG_DATACTL(channel);
58762306a36Sopenharmony_ci	else
58862306a36Sopenharmony_ci		cfg &= ~MX51_ECSPI_CONFIG_DATACTL(channel);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	if (spi->mode & SPI_CS_HIGH)
59162306a36Sopenharmony_ci		cfg |= MX51_ECSPI_CONFIG_SSBPOL(channel);
59262306a36Sopenharmony_ci	else
59362306a36Sopenharmony_ci		cfg &= ~MX51_ECSPI_CONFIG_SSBPOL(channel);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	if (cfg == current_cfg)
59662306a36Sopenharmony_ci		return 0;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	/*
60162306a36Sopenharmony_ci	 * Wait until the changes in the configuration register CONFIGREG
60262306a36Sopenharmony_ci	 * propagate into the hardware. It takes exactly one tick of the
60362306a36Sopenharmony_ci	 * SCLK clock, but we will wait two SCLK clock just to be sure. The
60462306a36Sopenharmony_ci	 * effect of the delay it takes for the hardware to apply changes
60562306a36Sopenharmony_ci	 * is noticable if the SCLK clock run very slow. In such a case, if
60662306a36Sopenharmony_ci	 * the polarity of SCLK should be inverted, the GPIO ChipSelect might
60762306a36Sopenharmony_ci	 * be asserted before the SCLK polarity changes, which would disrupt
60862306a36Sopenharmony_ci	 * the SPI communication as the device on the other end would consider
60962306a36Sopenharmony_ci	 * the change of SCLK polarity as a clock tick already.
61062306a36Sopenharmony_ci	 *
61162306a36Sopenharmony_ci	 * Because spi_imx->spi_bus_clk is only set in prepare_message
61262306a36Sopenharmony_ci	 * callback, iterate over all the transfers in spi_message, find the
61362306a36Sopenharmony_ci	 * one with lowest bus frequency, and use that bus frequency for the
61462306a36Sopenharmony_ci	 * delay calculation. In case all transfers have speed_hz == 0, then
61562306a36Sopenharmony_ci	 * min_speed_hz is ~0 and the resulting delay is zero.
61662306a36Sopenharmony_ci	 */
61762306a36Sopenharmony_ci	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
61862306a36Sopenharmony_ci		if (!xfer->speed_hz)
61962306a36Sopenharmony_ci			continue;
62062306a36Sopenharmony_ci		min_speed_hz = min(xfer->speed_hz, min_speed_hz);
62162306a36Sopenharmony_ci	}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	delay = (2 * 1000000) / min_speed_hz;
62462306a36Sopenharmony_ci	if (likely(delay < 10))	/* SCLK is faster than 200 kHz */
62562306a36Sopenharmony_ci		udelay(delay);
62662306a36Sopenharmony_ci	else			/* SCLK is _very_ slow */
62762306a36Sopenharmony_ci		usleep_range(delay, delay + 10);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	return 0;
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_cistatic void mx51_configure_cpha(struct spi_imx_data *spi_imx,
63362306a36Sopenharmony_ci				struct spi_device *spi)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	bool cpha = (spi->mode & SPI_CPHA);
63662306a36Sopenharmony_ci	bool flip_cpha = (spi->mode & SPI_RX_CPHA_FLIP) && spi_imx->rx_only;
63762306a36Sopenharmony_ci	u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG);
63862306a36Sopenharmony_ci	int channel = mx51_ecspi_channel(spi);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	/* Flip cpha logical value iff flip_cpha */
64162306a36Sopenharmony_ci	cpha ^= flip_cpha;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	if (cpha)
64462306a36Sopenharmony_ci		cfg |= MX51_ECSPI_CONFIG_SCLKPHA(channel);
64562306a36Sopenharmony_ci	else
64662306a36Sopenharmony_ci		cfg &= ~MX51_ECSPI_CONFIG_SCLKPHA(channel);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG);
64962306a36Sopenharmony_ci}
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_cistatic int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx,
65262306a36Sopenharmony_ci				       struct spi_device *spi)
65362306a36Sopenharmony_ci{
65462306a36Sopenharmony_ci	u32 ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
65562306a36Sopenharmony_ci	u32 clk;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	/* Clear BL field and set the right value */
65862306a36Sopenharmony_ci	ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
65962306a36Sopenharmony_ci	if (spi_imx->target_mode && is_imx53_ecspi(spi_imx))
66062306a36Sopenharmony_ci		ctrl |= (spi_imx->target_burst * 8 - 1)
66162306a36Sopenharmony_ci			<< MX51_ECSPI_CTRL_BL_OFFSET;
66262306a36Sopenharmony_ci	else {
66362306a36Sopenharmony_ci		if (spi_imx->usedma) {
66462306a36Sopenharmony_ci			ctrl |= (spi_imx->bits_per_word - 1)
66562306a36Sopenharmony_ci				<< MX51_ECSPI_CTRL_BL_OFFSET;
66662306a36Sopenharmony_ci		} else {
66762306a36Sopenharmony_ci			if (spi_imx->count >= MX51_ECSPI_CTRL_MAX_BURST)
66862306a36Sopenharmony_ci				ctrl |= (MX51_ECSPI_CTRL_MAX_BURST * BITS_PER_BYTE - 1)
66962306a36Sopenharmony_ci						<< MX51_ECSPI_CTRL_BL_OFFSET;
67062306a36Sopenharmony_ci			else
67162306a36Sopenharmony_ci				ctrl |= (spi_imx->count / DIV_ROUND_UP(spi_imx->bits_per_word,
67262306a36Sopenharmony_ci						BITS_PER_BYTE) * spi_imx->bits_per_word - 1)
67362306a36Sopenharmony_ci						<< MX51_ECSPI_CTRL_BL_OFFSET;
67462306a36Sopenharmony_ci		}
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	/* set clock speed */
67862306a36Sopenharmony_ci	ctrl &= ~(0xf << MX51_ECSPI_CTRL_POSTDIV_OFFSET |
67962306a36Sopenharmony_ci		  0xf << MX51_ECSPI_CTRL_PREDIV_OFFSET);
68062306a36Sopenharmony_ci	ctrl |= mx51_ecspi_clkdiv(spi_imx, spi_imx->spi_bus_clk, &clk);
68162306a36Sopenharmony_ci	spi_imx->spi_bus_clk = clk;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	mx51_configure_cpha(spi_imx, spi);
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	/*
68662306a36Sopenharmony_ci	 * ERR009165: work in XHC mode instead of SMC as PIO on the chips
68762306a36Sopenharmony_ci	 * before i.mx6ul.
68862306a36Sopenharmony_ci	 */
68962306a36Sopenharmony_ci	if (spi_imx->usedma && spi_imx->devtype_data->tx_glitch_fixed)
69062306a36Sopenharmony_ci		ctrl |= MX51_ECSPI_CTRL_SMC;
69162306a36Sopenharmony_ci	else
69262306a36Sopenharmony_ci		ctrl &= ~MX51_ECSPI_CTRL_SMC;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	return 0;
69762306a36Sopenharmony_ci}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_cistatic void mx51_setup_wml(struct spi_imx_data *spi_imx)
70062306a36Sopenharmony_ci{
70162306a36Sopenharmony_ci	u32 tx_wml = 0;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	if (spi_imx->devtype_data->tx_glitch_fixed)
70462306a36Sopenharmony_ci		tx_wml = spi_imx->wml;
70562306a36Sopenharmony_ci	/*
70662306a36Sopenharmony_ci	 * Configure the DMA register: setup the watermark
70762306a36Sopenharmony_ci	 * and enable DMA request.
70862306a36Sopenharmony_ci	 */
70962306a36Sopenharmony_ci	writel(MX51_ECSPI_DMA_RX_WML(spi_imx->wml - 1) |
71062306a36Sopenharmony_ci		MX51_ECSPI_DMA_TX_WML(tx_wml) |
71162306a36Sopenharmony_ci		MX51_ECSPI_DMA_RXT_WML(spi_imx->wml) |
71262306a36Sopenharmony_ci		MX51_ECSPI_DMA_TEDEN | MX51_ECSPI_DMA_RXDEN |
71362306a36Sopenharmony_ci		MX51_ECSPI_DMA_RXTDEN, spi_imx->base + MX51_ECSPI_DMA);
71462306a36Sopenharmony_ci}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_cistatic int mx51_ecspi_rx_available(struct spi_imx_data *spi_imx)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	return readl(spi_imx->base + MX51_ECSPI_STAT) & MX51_ECSPI_STAT_RR;
71962306a36Sopenharmony_ci}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_cistatic void mx51_ecspi_reset(struct spi_imx_data *spi_imx)
72262306a36Sopenharmony_ci{
72362306a36Sopenharmony_ci	/* drain receive buffer */
72462306a36Sopenharmony_ci	while (mx51_ecspi_rx_available(spi_imx))
72562306a36Sopenharmony_ci		readl(spi_imx->base + MXC_CSPIRXDATA);
72662306a36Sopenharmony_ci}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci#define MX31_INTREG_TEEN	(1 << 0)
72962306a36Sopenharmony_ci#define MX31_INTREG_RREN	(1 << 3)
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci#define MX31_CSPICTRL_ENABLE	(1 << 0)
73262306a36Sopenharmony_ci#define MX31_CSPICTRL_HOST	(1 << 1)
73362306a36Sopenharmony_ci#define MX31_CSPICTRL_XCH	(1 << 2)
73462306a36Sopenharmony_ci#define MX31_CSPICTRL_SMC	(1 << 3)
73562306a36Sopenharmony_ci#define MX31_CSPICTRL_POL	(1 << 4)
73662306a36Sopenharmony_ci#define MX31_CSPICTRL_PHA	(1 << 5)
73762306a36Sopenharmony_ci#define MX31_CSPICTRL_SSCTL	(1 << 6)
73862306a36Sopenharmony_ci#define MX31_CSPICTRL_SSPOL	(1 << 7)
73962306a36Sopenharmony_ci#define MX31_CSPICTRL_BC_SHIFT	8
74062306a36Sopenharmony_ci#define MX35_CSPICTRL_BL_SHIFT	20
74162306a36Sopenharmony_ci#define MX31_CSPICTRL_CS_SHIFT	24
74262306a36Sopenharmony_ci#define MX35_CSPICTRL_CS_SHIFT	12
74362306a36Sopenharmony_ci#define MX31_CSPICTRL_DR_SHIFT	16
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci#define MX31_CSPI_DMAREG	0x10
74662306a36Sopenharmony_ci#define MX31_DMAREG_RH_DEN	(1<<4)
74762306a36Sopenharmony_ci#define MX31_DMAREG_TH_DEN	(1<<1)
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci#define MX31_CSPISTATUS		0x14
75062306a36Sopenharmony_ci#define MX31_STATUS_RR		(1 << 3)
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci#define MX31_CSPI_TESTREG	0x1C
75362306a36Sopenharmony_ci#define MX31_TEST_LBC		(1 << 14)
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci/* These functions also work for the i.MX35, but be aware that
75662306a36Sopenharmony_ci * the i.MX35 has a slightly different register layout for bits
75762306a36Sopenharmony_ci * we do not use here.
75862306a36Sopenharmony_ci */
75962306a36Sopenharmony_cistatic void mx31_intctrl(struct spi_imx_data *spi_imx, int enable)
76062306a36Sopenharmony_ci{
76162306a36Sopenharmony_ci	unsigned int val = 0;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	if (enable & MXC_INT_TE)
76462306a36Sopenharmony_ci		val |= MX31_INTREG_TEEN;
76562306a36Sopenharmony_ci	if (enable & MXC_INT_RR)
76662306a36Sopenharmony_ci		val |= MX31_INTREG_RREN;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	writel(val, spi_imx->base + MXC_CSPIINT);
76962306a36Sopenharmony_ci}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_cistatic void mx31_trigger(struct spi_imx_data *spi_imx)
77262306a36Sopenharmony_ci{
77362306a36Sopenharmony_ci	unsigned int reg;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	reg = readl(spi_imx->base + MXC_CSPICTRL);
77662306a36Sopenharmony_ci	reg |= MX31_CSPICTRL_XCH;
77762306a36Sopenharmony_ci	writel(reg, spi_imx->base + MXC_CSPICTRL);
77862306a36Sopenharmony_ci}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_cistatic int mx31_prepare_message(struct spi_imx_data *spi_imx,
78162306a36Sopenharmony_ci				struct spi_message *msg)
78262306a36Sopenharmony_ci{
78362306a36Sopenharmony_ci	return 0;
78462306a36Sopenharmony_ci}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_cistatic int mx31_prepare_transfer(struct spi_imx_data *spi_imx,
78762306a36Sopenharmony_ci				 struct spi_device *spi)
78862306a36Sopenharmony_ci{
78962306a36Sopenharmony_ci	unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_HOST;
79062306a36Sopenharmony_ci	unsigned int clk;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, spi_imx->spi_bus_clk, &clk) <<
79362306a36Sopenharmony_ci		MX31_CSPICTRL_DR_SHIFT;
79462306a36Sopenharmony_ci	spi_imx->spi_bus_clk = clk;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	if (is_imx35_cspi(spi_imx)) {
79762306a36Sopenharmony_ci		reg |= (spi_imx->bits_per_word - 1) << MX35_CSPICTRL_BL_SHIFT;
79862306a36Sopenharmony_ci		reg |= MX31_CSPICTRL_SSCTL;
79962306a36Sopenharmony_ci	} else {
80062306a36Sopenharmony_ci		reg |= (spi_imx->bits_per_word - 1) << MX31_CSPICTRL_BC_SHIFT;
80162306a36Sopenharmony_ci	}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	if (spi->mode & SPI_CPHA)
80462306a36Sopenharmony_ci		reg |= MX31_CSPICTRL_PHA;
80562306a36Sopenharmony_ci	if (spi->mode & SPI_CPOL)
80662306a36Sopenharmony_ci		reg |= MX31_CSPICTRL_POL;
80762306a36Sopenharmony_ci	if (spi->mode & SPI_CS_HIGH)
80862306a36Sopenharmony_ci		reg |= MX31_CSPICTRL_SSPOL;
80962306a36Sopenharmony_ci	if (!spi_get_csgpiod(spi, 0))
81062306a36Sopenharmony_ci		reg |= (spi_get_chipselect(spi, 0)) <<
81162306a36Sopenharmony_ci			(is_imx35_cspi(spi_imx) ? MX35_CSPICTRL_CS_SHIFT :
81262306a36Sopenharmony_ci						  MX31_CSPICTRL_CS_SHIFT);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	if (spi_imx->usedma)
81562306a36Sopenharmony_ci		reg |= MX31_CSPICTRL_SMC;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	writel(reg, spi_imx->base + MXC_CSPICTRL);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	reg = readl(spi_imx->base + MX31_CSPI_TESTREG);
82062306a36Sopenharmony_ci	if (spi->mode & SPI_LOOP)
82162306a36Sopenharmony_ci		reg |= MX31_TEST_LBC;
82262306a36Sopenharmony_ci	else
82362306a36Sopenharmony_ci		reg &= ~MX31_TEST_LBC;
82462306a36Sopenharmony_ci	writel(reg, spi_imx->base + MX31_CSPI_TESTREG);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	if (spi_imx->usedma) {
82762306a36Sopenharmony_ci		/*
82862306a36Sopenharmony_ci		 * configure DMA requests when RXFIFO is half full and
82962306a36Sopenharmony_ci		 * when TXFIFO is half empty
83062306a36Sopenharmony_ci		 */
83162306a36Sopenharmony_ci		writel(MX31_DMAREG_RH_DEN | MX31_DMAREG_TH_DEN,
83262306a36Sopenharmony_ci			spi_imx->base + MX31_CSPI_DMAREG);
83362306a36Sopenharmony_ci	}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	return 0;
83662306a36Sopenharmony_ci}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_cistatic int mx31_rx_available(struct spi_imx_data *spi_imx)
83962306a36Sopenharmony_ci{
84062306a36Sopenharmony_ci	return readl(spi_imx->base + MX31_CSPISTATUS) & MX31_STATUS_RR;
84162306a36Sopenharmony_ci}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_cistatic void mx31_reset(struct spi_imx_data *spi_imx)
84462306a36Sopenharmony_ci{
84562306a36Sopenharmony_ci	/* drain receive buffer */
84662306a36Sopenharmony_ci	while (readl(spi_imx->base + MX31_CSPISTATUS) & MX31_STATUS_RR)
84762306a36Sopenharmony_ci		readl(spi_imx->base + MXC_CSPIRXDATA);
84862306a36Sopenharmony_ci}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci#define MX21_INTREG_RR		(1 << 4)
85162306a36Sopenharmony_ci#define MX21_INTREG_TEEN	(1 << 9)
85262306a36Sopenharmony_ci#define MX21_INTREG_RREN	(1 << 13)
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci#define MX21_CSPICTRL_POL	(1 << 5)
85562306a36Sopenharmony_ci#define MX21_CSPICTRL_PHA	(1 << 6)
85662306a36Sopenharmony_ci#define MX21_CSPICTRL_SSPOL	(1 << 8)
85762306a36Sopenharmony_ci#define MX21_CSPICTRL_XCH	(1 << 9)
85862306a36Sopenharmony_ci#define MX21_CSPICTRL_ENABLE	(1 << 10)
85962306a36Sopenharmony_ci#define MX21_CSPICTRL_HOST	(1 << 11)
86062306a36Sopenharmony_ci#define MX21_CSPICTRL_DR_SHIFT	14
86162306a36Sopenharmony_ci#define MX21_CSPICTRL_CS_SHIFT	19
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_cistatic void mx21_intctrl(struct spi_imx_data *spi_imx, int enable)
86462306a36Sopenharmony_ci{
86562306a36Sopenharmony_ci	unsigned int val = 0;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	if (enable & MXC_INT_TE)
86862306a36Sopenharmony_ci		val |= MX21_INTREG_TEEN;
86962306a36Sopenharmony_ci	if (enable & MXC_INT_RR)
87062306a36Sopenharmony_ci		val |= MX21_INTREG_RREN;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	writel(val, spi_imx->base + MXC_CSPIINT);
87362306a36Sopenharmony_ci}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_cistatic void mx21_trigger(struct spi_imx_data *spi_imx)
87662306a36Sopenharmony_ci{
87762306a36Sopenharmony_ci	unsigned int reg;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	reg = readl(spi_imx->base + MXC_CSPICTRL);
88062306a36Sopenharmony_ci	reg |= MX21_CSPICTRL_XCH;
88162306a36Sopenharmony_ci	writel(reg, spi_imx->base + MXC_CSPICTRL);
88262306a36Sopenharmony_ci}
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_cistatic int mx21_prepare_message(struct spi_imx_data *spi_imx,
88562306a36Sopenharmony_ci				struct spi_message *msg)
88662306a36Sopenharmony_ci{
88762306a36Sopenharmony_ci	return 0;
88862306a36Sopenharmony_ci}
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_cistatic int mx21_prepare_transfer(struct spi_imx_data *spi_imx,
89162306a36Sopenharmony_ci				 struct spi_device *spi)
89262306a36Sopenharmony_ci{
89362306a36Sopenharmony_ci	unsigned int reg = MX21_CSPICTRL_ENABLE | MX21_CSPICTRL_HOST;
89462306a36Sopenharmony_ci	unsigned int max = is_imx27_cspi(spi_imx) ? 16 : 18;
89562306a36Sopenharmony_ci	unsigned int clk;
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, spi_imx->spi_bus_clk, max, &clk)
89862306a36Sopenharmony_ci		<< MX21_CSPICTRL_DR_SHIFT;
89962306a36Sopenharmony_ci	spi_imx->spi_bus_clk = clk;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	reg |= spi_imx->bits_per_word - 1;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	if (spi->mode & SPI_CPHA)
90462306a36Sopenharmony_ci		reg |= MX21_CSPICTRL_PHA;
90562306a36Sopenharmony_ci	if (spi->mode & SPI_CPOL)
90662306a36Sopenharmony_ci		reg |= MX21_CSPICTRL_POL;
90762306a36Sopenharmony_ci	if (spi->mode & SPI_CS_HIGH)
90862306a36Sopenharmony_ci		reg |= MX21_CSPICTRL_SSPOL;
90962306a36Sopenharmony_ci	if (!spi_get_csgpiod(spi, 0))
91062306a36Sopenharmony_ci		reg |= spi_get_chipselect(spi, 0) << MX21_CSPICTRL_CS_SHIFT;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	writel(reg, spi_imx->base + MXC_CSPICTRL);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	return 0;
91562306a36Sopenharmony_ci}
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_cistatic int mx21_rx_available(struct spi_imx_data *spi_imx)
91862306a36Sopenharmony_ci{
91962306a36Sopenharmony_ci	return readl(spi_imx->base + MXC_CSPIINT) & MX21_INTREG_RR;
92062306a36Sopenharmony_ci}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_cistatic void mx21_reset(struct spi_imx_data *spi_imx)
92362306a36Sopenharmony_ci{
92462306a36Sopenharmony_ci	writel(1, spi_imx->base + MXC_RESET);
92562306a36Sopenharmony_ci}
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci#define MX1_INTREG_RR		(1 << 3)
92862306a36Sopenharmony_ci#define MX1_INTREG_TEEN		(1 << 8)
92962306a36Sopenharmony_ci#define MX1_INTREG_RREN		(1 << 11)
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci#define MX1_CSPICTRL_POL	(1 << 4)
93262306a36Sopenharmony_ci#define MX1_CSPICTRL_PHA	(1 << 5)
93362306a36Sopenharmony_ci#define MX1_CSPICTRL_XCH	(1 << 8)
93462306a36Sopenharmony_ci#define MX1_CSPICTRL_ENABLE	(1 << 9)
93562306a36Sopenharmony_ci#define MX1_CSPICTRL_HOST	(1 << 10)
93662306a36Sopenharmony_ci#define MX1_CSPICTRL_DR_SHIFT	13
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_cistatic void mx1_intctrl(struct spi_imx_data *spi_imx, int enable)
93962306a36Sopenharmony_ci{
94062306a36Sopenharmony_ci	unsigned int val = 0;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	if (enable & MXC_INT_TE)
94362306a36Sopenharmony_ci		val |= MX1_INTREG_TEEN;
94462306a36Sopenharmony_ci	if (enable & MXC_INT_RR)
94562306a36Sopenharmony_ci		val |= MX1_INTREG_RREN;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	writel(val, spi_imx->base + MXC_CSPIINT);
94862306a36Sopenharmony_ci}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_cistatic void mx1_trigger(struct spi_imx_data *spi_imx)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	unsigned int reg;
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	reg = readl(spi_imx->base + MXC_CSPICTRL);
95562306a36Sopenharmony_ci	reg |= MX1_CSPICTRL_XCH;
95662306a36Sopenharmony_ci	writel(reg, spi_imx->base + MXC_CSPICTRL);
95762306a36Sopenharmony_ci}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_cistatic int mx1_prepare_message(struct spi_imx_data *spi_imx,
96062306a36Sopenharmony_ci			       struct spi_message *msg)
96162306a36Sopenharmony_ci{
96262306a36Sopenharmony_ci	return 0;
96362306a36Sopenharmony_ci}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_cistatic int mx1_prepare_transfer(struct spi_imx_data *spi_imx,
96662306a36Sopenharmony_ci				struct spi_device *spi)
96762306a36Sopenharmony_ci{
96862306a36Sopenharmony_ci	unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_HOST;
96962306a36Sopenharmony_ci	unsigned int clk;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, spi_imx->spi_bus_clk, &clk) <<
97262306a36Sopenharmony_ci		MX1_CSPICTRL_DR_SHIFT;
97362306a36Sopenharmony_ci	spi_imx->spi_bus_clk = clk;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	reg |= spi_imx->bits_per_word - 1;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	if (spi->mode & SPI_CPHA)
97862306a36Sopenharmony_ci		reg |= MX1_CSPICTRL_PHA;
97962306a36Sopenharmony_ci	if (spi->mode & SPI_CPOL)
98062306a36Sopenharmony_ci		reg |= MX1_CSPICTRL_POL;
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	writel(reg, spi_imx->base + MXC_CSPICTRL);
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	return 0;
98562306a36Sopenharmony_ci}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_cistatic int mx1_rx_available(struct spi_imx_data *spi_imx)
98862306a36Sopenharmony_ci{
98962306a36Sopenharmony_ci	return readl(spi_imx->base + MXC_CSPIINT) & MX1_INTREG_RR;
99062306a36Sopenharmony_ci}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_cistatic void mx1_reset(struct spi_imx_data *spi_imx)
99362306a36Sopenharmony_ci{
99462306a36Sopenharmony_ci	writel(1, spi_imx->base + MXC_RESET);
99562306a36Sopenharmony_ci}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_cistatic struct spi_imx_devtype_data imx1_cspi_devtype_data = {
99862306a36Sopenharmony_ci	.intctrl = mx1_intctrl,
99962306a36Sopenharmony_ci	.prepare_message = mx1_prepare_message,
100062306a36Sopenharmony_ci	.prepare_transfer = mx1_prepare_transfer,
100162306a36Sopenharmony_ci	.trigger = mx1_trigger,
100262306a36Sopenharmony_ci	.rx_available = mx1_rx_available,
100362306a36Sopenharmony_ci	.reset = mx1_reset,
100462306a36Sopenharmony_ci	.fifo_size = 8,
100562306a36Sopenharmony_ci	.has_dmamode = false,
100662306a36Sopenharmony_ci	.dynamic_burst = false,
100762306a36Sopenharmony_ci	.has_targetmode = false,
100862306a36Sopenharmony_ci	.devtype = IMX1_CSPI,
100962306a36Sopenharmony_ci};
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_cistatic struct spi_imx_devtype_data imx21_cspi_devtype_data = {
101262306a36Sopenharmony_ci	.intctrl = mx21_intctrl,
101362306a36Sopenharmony_ci	.prepare_message = mx21_prepare_message,
101462306a36Sopenharmony_ci	.prepare_transfer = mx21_prepare_transfer,
101562306a36Sopenharmony_ci	.trigger = mx21_trigger,
101662306a36Sopenharmony_ci	.rx_available = mx21_rx_available,
101762306a36Sopenharmony_ci	.reset = mx21_reset,
101862306a36Sopenharmony_ci	.fifo_size = 8,
101962306a36Sopenharmony_ci	.has_dmamode = false,
102062306a36Sopenharmony_ci	.dynamic_burst = false,
102162306a36Sopenharmony_ci	.has_targetmode = false,
102262306a36Sopenharmony_ci	.devtype = IMX21_CSPI,
102362306a36Sopenharmony_ci};
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_cistatic struct spi_imx_devtype_data imx27_cspi_devtype_data = {
102662306a36Sopenharmony_ci	/* i.mx27 cspi shares the functions with i.mx21 one */
102762306a36Sopenharmony_ci	.intctrl = mx21_intctrl,
102862306a36Sopenharmony_ci	.prepare_message = mx21_prepare_message,
102962306a36Sopenharmony_ci	.prepare_transfer = mx21_prepare_transfer,
103062306a36Sopenharmony_ci	.trigger = mx21_trigger,
103162306a36Sopenharmony_ci	.rx_available = mx21_rx_available,
103262306a36Sopenharmony_ci	.reset = mx21_reset,
103362306a36Sopenharmony_ci	.fifo_size = 8,
103462306a36Sopenharmony_ci	.has_dmamode = false,
103562306a36Sopenharmony_ci	.dynamic_burst = false,
103662306a36Sopenharmony_ci	.has_targetmode = false,
103762306a36Sopenharmony_ci	.devtype = IMX27_CSPI,
103862306a36Sopenharmony_ci};
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_cistatic struct spi_imx_devtype_data imx31_cspi_devtype_data = {
104162306a36Sopenharmony_ci	.intctrl = mx31_intctrl,
104262306a36Sopenharmony_ci	.prepare_message = mx31_prepare_message,
104362306a36Sopenharmony_ci	.prepare_transfer = mx31_prepare_transfer,
104462306a36Sopenharmony_ci	.trigger = mx31_trigger,
104562306a36Sopenharmony_ci	.rx_available = mx31_rx_available,
104662306a36Sopenharmony_ci	.reset = mx31_reset,
104762306a36Sopenharmony_ci	.fifo_size = 8,
104862306a36Sopenharmony_ci	.has_dmamode = false,
104962306a36Sopenharmony_ci	.dynamic_burst = false,
105062306a36Sopenharmony_ci	.has_targetmode = false,
105162306a36Sopenharmony_ci	.devtype = IMX31_CSPI,
105262306a36Sopenharmony_ci};
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_cistatic struct spi_imx_devtype_data imx35_cspi_devtype_data = {
105562306a36Sopenharmony_ci	/* i.mx35 and later cspi shares the functions with i.mx31 one */
105662306a36Sopenharmony_ci	.intctrl = mx31_intctrl,
105762306a36Sopenharmony_ci	.prepare_message = mx31_prepare_message,
105862306a36Sopenharmony_ci	.prepare_transfer = mx31_prepare_transfer,
105962306a36Sopenharmony_ci	.trigger = mx31_trigger,
106062306a36Sopenharmony_ci	.rx_available = mx31_rx_available,
106162306a36Sopenharmony_ci	.reset = mx31_reset,
106262306a36Sopenharmony_ci	.fifo_size = 8,
106362306a36Sopenharmony_ci	.has_dmamode = true,
106462306a36Sopenharmony_ci	.dynamic_burst = false,
106562306a36Sopenharmony_ci	.has_targetmode = false,
106662306a36Sopenharmony_ci	.devtype = IMX35_CSPI,
106762306a36Sopenharmony_ci};
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_cistatic struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
107062306a36Sopenharmony_ci	.intctrl = mx51_ecspi_intctrl,
107162306a36Sopenharmony_ci	.prepare_message = mx51_ecspi_prepare_message,
107262306a36Sopenharmony_ci	.prepare_transfer = mx51_ecspi_prepare_transfer,
107362306a36Sopenharmony_ci	.trigger = mx51_ecspi_trigger,
107462306a36Sopenharmony_ci	.rx_available = mx51_ecspi_rx_available,
107562306a36Sopenharmony_ci	.reset = mx51_ecspi_reset,
107662306a36Sopenharmony_ci	.setup_wml = mx51_setup_wml,
107762306a36Sopenharmony_ci	.fifo_size = 64,
107862306a36Sopenharmony_ci	.has_dmamode = true,
107962306a36Sopenharmony_ci	.dynamic_burst = true,
108062306a36Sopenharmony_ci	.has_targetmode = true,
108162306a36Sopenharmony_ci	.disable = mx51_ecspi_disable,
108262306a36Sopenharmony_ci	.devtype = IMX51_ECSPI,
108362306a36Sopenharmony_ci};
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_cistatic struct spi_imx_devtype_data imx53_ecspi_devtype_data = {
108662306a36Sopenharmony_ci	.intctrl = mx51_ecspi_intctrl,
108762306a36Sopenharmony_ci	.prepare_message = mx51_ecspi_prepare_message,
108862306a36Sopenharmony_ci	.prepare_transfer = mx51_ecspi_prepare_transfer,
108962306a36Sopenharmony_ci	.trigger = mx51_ecspi_trigger,
109062306a36Sopenharmony_ci	.rx_available = mx51_ecspi_rx_available,
109162306a36Sopenharmony_ci	.reset = mx51_ecspi_reset,
109262306a36Sopenharmony_ci	.fifo_size = 64,
109362306a36Sopenharmony_ci	.has_dmamode = true,
109462306a36Sopenharmony_ci	.has_targetmode = true,
109562306a36Sopenharmony_ci	.disable = mx51_ecspi_disable,
109662306a36Sopenharmony_ci	.devtype = IMX53_ECSPI,
109762306a36Sopenharmony_ci};
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_cistatic struct spi_imx_devtype_data imx6ul_ecspi_devtype_data = {
110062306a36Sopenharmony_ci	.intctrl = mx51_ecspi_intctrl,
110162306a36Sopenharmony_ci	.prepare_message = mx51_ecspi_prepare_message,
110262306a36Sopenharmony_ci	.prepare_transfer = mx51_ecspi_prepare_transfer,
110362306a36Sopenharmony_ci	.trigger = mx51_ecspi_trigger,
110462306a36Sopenharmony_ci	.rx_available = mx51_ecspi_rx_available,
110562306a36Sopenharmony_ci	.reset = mx51_ecspi_reset,
110662306a36Sopenharmony_ci	.setup_wml = mx51_setup_wml,
110762306a36Sopenharmony_ci	.fifo_size = 64,
110862306a36Sopenharmony_ci	.has_dmamode = true,
110962306a36Sopenharmony_ci	.dynamic_burst = true,
111062306a36Sopenharmony_ci	.has_targetmode = true,
111162306a36Sopenharmony_ci	.tx_glitch_fixed = true,
111262306a36Sopenharmony_ci	.disable = mx51_ecspi_disable,
111362306a36Sopenharmony_ci	.devtype = IMX51_ECSPI,
111462306a36Sopenharmony_ci};
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_cistatic const struct of_device_id spi_imx_dt_ids[] = {
111762306a36Sopenharmony_ci	{ .compatible = "fsl,imx1-cspi", .data = &imx1_cspi_devtype_data, },
111862306a36Sopenharmony_ci	{ .compatible = "fsl,imx21-cspi", .data = &imx21_cspi_devtype_data, },
111962306a36Sopenharmony_ci	{ .compatible = "fsl,imx27-cspi", .data = &imx27_cspi_devtype_data, },
112062306a36Sopenharmony_ci	{ .compatible = "fsl,imx31-cspi", .data = &imx31_cspi_devtype_data, },
112162306a36Sopenharmony_ci	{ .compatible = "fsl,imx35-cspi", .data = &imx35_cspi_devtype_data, },
112262306a36Sopenharmony_ci	{ .compatible = "fsl,imx51-ecspi", .data = &imx51_ecspi_devtype_data, },
112362306a36Sopenharmony_ci	{ .compatible = "fsl,imx53-ecspi", .data = &imx53_ecspi_devtype_data, },
112462306a36Sopenharmony_ci	{ .compatible = "fsl,imx6ul-ecspi", .data = &imx6ul_ecspi_devtype_data, },
112562306a36Sopenharmony_ci	{ /* sentinel */ }
112662306a36Sopenharmony_ci};
112762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, spi_imx_dt_ids);
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_cistatic void spi_imx_set_burst_len(struct spi_imx_data *spi_imx, int n_bits)
113062306a36Sopenharmony_ci{
113162306a36Sopenharmony_ci	u32 ctrl;
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
113462306a36Sopenharmony_ci	ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
113562306a36Sopenharmony_ci	ctrl |= ((n_bits - 1) << MX51_ECSPI_CTRL_BL_OFFSET);
113662306a36Sopenharmony_ci	writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
113762306a36Sopenharmony_ci}
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_cistatic void spi_imx_push(struct spi_imx_data *spi_imx)
114062306a36Sopenharmony_ci{
114162306a36Sopenharmony_ci	unsigned int burst_len;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	/*
114462306a36Sopenharmony_ci	 * Reload the FIFO when the remaining bytes to be transferred in the
114562306a36Sopenharmony_ci	 * current burst is 0. This only applies when bits_per_word is a
114662306a36Sopenharmony_ci	 * multiple of 8.
114762306a36Sopenharmony_ci	 */
114862306a36Sopenharmony_ci	if (!spi_imx->remainder) {
114962306a36Sopenharmony_ci		if (spi_imx->dynamic_burst) {
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci			/* We need to deal unaligned data first */
115262306a36Sopenharmony_ci			burst_len = spi_imx->count % MX51_ECSPI_CTRL_MAX_BURST;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci			if (!burst_len)
115562306a36Sopenharmony_ci				burst_len = MX51_ECSPI_CTRL_MAX_BURST;
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci			spi_imx_set_burst_len(spi_imx, burst_len * 8);
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci			spi_imx->remainder = burst_len;
116062306a36Sopenharmony_ci		} else {
116162306a36Sopenharmony_ci			spi_imx->remainder = spi_imx_bytes_per_word(spi_imx->bits_per_word);
116262306a36Sopenharmony_ci		}
116362306a36Sopenharmony_ci	}
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	while (spi_imx->txfifo < spi_imx->devtype_data->fifo_size) {
116662306a36Sopenharmony_ci		if (!spi_imx->count)
116762306a36Sopenharmony_ci			break;
116862306a36Sopenharmony_ci		if (spi_imx->dynamic_burst &&
116962306a36Sopenharmony_ci		    spi_imx->txfifo >= DIV_ROUND_UP(spi_imx->remainder, 4))
117062306a36Sopenharmony_ci			break;
117162306a36Sopenharmony_ci		spi_imx->tx(spi_imx);
117262306a36Sopenharmony_ci		spi_imx->txfifo++;
117362306a36Sopenharmony_ci	}
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	if (!spi_imx->target_mode)
117662306a36Sopenharmony_ci		spi_imx->devtype_data->trigger(spi_imx);
117762306a36Sopenharmony_ci}
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_cistatic irqreturn_t spi_imx_isr(int irq, void *dev_id)
118062306a36Sopenharmony_ci{
118162306a36Sopenharmony_ci	struct spi_imx_data *spi_imx = dev_id;
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	while (spi_imx->txfifo &&
118462306a36Sopenharmony_ci	       spi_imx->devtype_data->rx_available(spi_imx)) {
118562306a36Sopenharmony_ci		spi_imx->rx(spi_imx);
118662306a36Sopenharmony_ci		spi_imx->txfifo--;
118762306a36Sopenharmony_ci	}
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	if (spi_imx->count) {
119062306a36Sopenharmony_ci		spi_imx_push(spi_imx);
119162306a36Sopenharmony_ci		return IRQ_HANDLED;
119262306a36Sopenharmony_ci	}
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	if (spi_imx->txfifo) {
119562306a36Sopenharmony_ci		/* No data left to push, but still waiting for rx data,
119662306a36Sopenharmony_ci		 * enable receive data available interrupt.
119762306a36Sopenharmony_ci		 */
119862306a36Sopenharmony_ci		spi_imx->devtype_data->intctrl(
119962306a36Sopenharmony_ci				spi_imx, MXC_INT_RR);
120062306a36Sopenharmony_ci		return IRQ_HANDLED;
120162306a36Sopenharmony_ci	}
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	spi_imx->devtype_data->intctrl(spi_imx, 0);
120462306a36Sopenharmony_ci	complete(&spi_imx->xfer_done);
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	return IRQ_HANDLED;
120762306a36Sopenharmony_ci}
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_cistatic int spi_imx_dma_configure(struct spi_controller *controller)
121062306a36Sopenharmony_ci{
121162306a36Sopenharmony_ci	int ret;
121262306a36Sopenharmony_ci	enum dma_slave_buswidth buswidth;
121362306a36Sopenharmony_ci	struct dma_slave_config rx = {}, tx = {};
121462306a36Sopenharmony_ci	struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller);
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	switch (spi_imx_bytes_per_word(spi_imx->bits_per_word)) {
121762306a36Sopenharmony_ci	case 4:
121862306a36Sopenharmony_ci		buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
121962306a36Sopenharmony_ci		break;
122062306a36Sopenharmony_ci	case 2:
122162306a36Sopenharmony_ci		buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
122262306a36Sopenharmony_ci		break;
122362306a36Sopenharmony_ci	case 1:
122462306a36Sopenharmony_ci		buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
122562306a36Sopenharmony_ci		break;
122662306a36Sopenharmony_ci	default:
122762306a36Sopenharmony_ci		return -EINVAL;
122862306a36Sopenharmony_ci	}
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	tx.direction = DMA_MEM_TO_DEV;
123162306a36Sopenharmony_ci	tx.dst_addr = spi_imx->base_phys + MXC_CSPITXDATA;
123262306a36Sopenharmony_ci	tx.dst_addr_width = buswidth;
123362306a36Sopenharmony_ci	tx.dst_maxburst = spi_imx->wml;
123462306a36Sopenharmony_ci	ret = dmaengine_slave_config(controller->dma_tx, &tx);
123562306a36Sopenharmony_ci	if (ret) {
123662306a36Sopenharmony_ci		dev_err(spi_imx->dev, "TX dma configuration failed with %d\n", ret);
123762306a36Sopenharmony_ci		return ret;
123862306a36Sopenharmony_ci	}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	rx.direction = DMA_DEV_TO_MEM;
124162306a36Sopenharmony_ci	rx.src_addr = spi_imx->base_phys + MXC_CSPIRXDATA;
124262306a36Sopenharmony_ci	rx.src_addr_width = buswidth;
124362306a36Sopenharmony_ci	rx.src_maxburst = spi_imx->wml;
124462306a36Sopenharmony_ci	ret = dmaengine_slave_config(controller->dma_rx, &rx);
124562306a36Sopenharmony_ci	if (ret) {
124662306a36Sopenharmony_ci		dev_err(spi_imx->dev, "RX dma configuration failed with %d\n", ret);
124762306a36Sopenharmony_ci		return ret;
124862306a36Sopenharmony_ci	}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	return 0;
125162306a36Sopenharmony_ci}
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_cistatic int spi_imx_setupxfer(struct spi_device *spi,
125462306a36Sopenharmony_ci				 struct spi_transfer *t)
125562306a36Sopenharmony_ci{
125662306a36Sopenharmony_ci	struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller);
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	if (!t)
125962306a36Sopenharmony_ci		return 0;
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	if (!t->speed_hz) {
126262306a36Sopenharmony_ci		if (!spi->max_speed_hz) {
126362306a36Sopenharmony_ci			dev_err(&spi->dev, "no speed_hz provided!\n");
126462306a36Sopenharmony_ci			return -EINVAL;
126562306a36Sopenharmony_ci		}
126662306a36Sopenharmony_ci		dev_dbg(&spi->dev, "using spi->max_speed_hz!\n");
126762306a36Sopenharmony_ci		spi_imx->spi_bus_clk = spi->max_speed_hz;
126862306a36Sopenharmony_ci	} else
126962306a36Sopenharmony_ci		spi_imx->spi_bus_clk = t->speed_hz;
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	spi_imx->bits_per_word = t->bits_per_word;
127262306a36Sopenharmony_ci	spi_imx->count = t->len;
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	/*
127562306a36Sopenharmony_ci	 * Initialize the functions for transfer. To transfer non byte-aligned
127662306a36Sopenharmony_ci	 * words, we have to use multiple word-size bursts, we can't use
127762306a36Sopenharmony_ci	 * dynamic_burst in that case.
127862306a36Sopenharmony_ci	 */
127962306a36Sopenharmony_ci	if (spi_imx->devtype_data->dynamic_burst && !spi_imx->target_mode &&
128062306a36Sopenharmony_ci	    !(spi->mode & SPI_CS_WORD) &&
128162306a36Sopenharmony_ci	    (spi_imx->bits_per_word == 8 ||
128262306a36Sopenharmony_ci	    spi_imx->bits_per_word == 16 ||
128362306a36Sopenharmony_ci	    spi_imx->bits_per_word == 32)) {
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci		spi_imx->rx = spi_imx_buf_rx_swap;
128662306a36Sopenharmony_ci		spi_imx->tx = spi_imx_buf_tx_swap;
128762306a36Sopenharmony_ci		spi_imx->dynamic_burst = 1;
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	} else {
129062306a36Sopenharmony_ci		if (spi_imx->bits_per_word <= 8) {
129162306a36Sopenharmony_ci			spi_imx->rx = spi_imx_buf_rx_u8;
129262306a36Sopenharmony_ci			spi_imx->tx = spi_imx_buf_tx_u8;
129362306a36Sopenharmony_ci		} else if (spi_imx->bits_per_word <= 16) {
129462306a36Sopenharmony_ci			spi_imx->rx = spi_imx_buf_rx_u16;
129562306a36Sopenharmony_ci			spi_imx->tx = spi_imx_buf_tx_u16;
129662306a36Sopenharmony_ci		} else {
129762306a36Sopenharmony_ci			spi_imx->rx = spi_imx_buf_rx_u32;
129862306a36Sopenharmony_ci			spi_imx->tx = spi_imx_buf_tx_u32;
129962306a36Sopenharmony_ci		}
130062306a36Sopenharmony_ci		spi_imx->dynamic_burst = 0;
130162306a36Sopenharmony_ci	}
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	if (spi_imx_can_dma(spi_imx->controller, spi, t))
130462306a36Sopenharmony_ci		spi_imx->usedma = true;
130562306a36Sopenharmony_ci	else
130662306a36Sopenharmony_ci		spi_imx->usedma = false;
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	spi_imx->rx_only = ((t->tx_buf == NULL)
130962306a36Sopenharmony_ci			|| (t->tx_buf == spi->controller->dummy_tx));
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	if (is_imx53_ecspi(spi_imx) && spi_imx->target_mode) {
131262306a36Sopenharmony_ci		spi_imx->rx = mx53_ecspi_rx_target;
131362306a36Sopenharmony_ci		spi_imx->tx = mx53_ecspi_tx_target;
131462306a36Sopenharmony_ci		spi_imx->target_burst = t->len;
131562306a36Sopenharmony_ci	}
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	spi_imx->devtype_data->prepare_transfer(spi_imx, spi);
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	return 0;
132062306a36Sopenharmony_ci}
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_cistatic void spi_imx_sdma_exit(struct spi_imx_data *spi_imx)
132362306a36Sopenharmony_ci{
132462306a36Sopenharmony_ci	struct spi_controller *controller = spi_imx->controller;
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	if (controller->dma_rx) {
132762306a36Sopenharmony_ci		dma_release_channel(controller->dma_rx);
132862306a36Sopenharmony_ci		controller->dma_rx = NULL;
132962306a36Sopenharmony_ci	}
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	if (controller->dma_tx) {
133262306a36Sopenharmony_ci		dma_release_channel(controller->dma_tx);
133362306a36Sopenharmony_ci		controller->dma_tx = NULL;
133462306a36Sopenharmony_ci	}
133562306a36Sopenharmony_ci}
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_cistatic int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
133862306a36Sopenharmony_ci			     struct spi_controller *controller)
133962306a36Sopenharmony_ci{
134062306a36Sopenharmony_ci	int ret;
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	spi_imx->wml = spi_imx->devtype_data->fifo_size / 2;
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	/* Prepare for TX DMA: */
134562306a36Sopenharmony_ci	controller->dma_tx = dma_request_chan(dev, "tx");
134662306a36Sopenharmony_ci	if (IS_ERR(controller->dma_tx)) {
134762306a36Sopenharmony_ci		ret = PTR_ERR(controller->dma_tx);
134862306a36Sopenharmony_ci		dev_dbg(dev, "can't get the TX DMA channel, error %d!\n", ret);
134962306a36Sopenharmony_ci		controller->dma_tx = NULL;
135062306a36Sopenharmony_ci		goto err;
135162306a36Sopenharmony_ci	}
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	/* Prepare for RX : */
135462306a36Sopenharmony_ci	controller->dma_rx = dma_request_chan(dev, "rx");
135562306a36Sopenharmony_ci	if (IS_ERR(controller->dma_rx)) {
135662306a36Sopenharmony_ci		ret = PTR_ERR(controller->dma_rx);
135762306a36Sopenharmony_ci		dev_dbg(dev, "can't get the RX DMA channel, error %d\n", ret);
135862306a36Sopenharmony_ci		controller->dma_rx = NULL;
135962306a36Sopenharmony_ci		goto err;
136062306a36Sopenharmony_ci	}
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	init_completion(&spi_imx->dma_rx_completion);
136362306a36Sopenharmony_ci	init_completion(&spi_imx->dma_tx_completion);
136462306a36Sopenharmony_ci	controller->can_dma = spi_imx_can_dma;
136562306a36Sopenharmony_ci	controller->max_dma_len = MAX_SDMA_BD_BYTES;
136662306a36Sopenharmony_ci	spi_imx->controller->flags = SPI_CONTROLLER_MUST_RX |
136762306a36Sopenharmony_ci					 SPI_CONTROLLER_MUST_TX;
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	return 0;
137062306a36Sopenharmony_cierr:
137162306a36Sopenharmony_ci	spi_imx_sdma_exit(spi_imx);
137262306a36Sopenharmony_ci	return ret;
137362306a36Sopenharmony_ci}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_cistatic void spi_imx_dma_rx_callback(void *cookie)
137662306a36Sopenharmony_ci{
137762306a36Sopenharmony_ci	struct spi_imx_data *spi_imx = (struct spi_imx_data *)cookie;
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	complete(&spi_imx->dma_rx_completion);
138062306a36Sopenharmony_ci}
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_cistatic void spi_imx_dma_tx_callback(void *cookie)
138362306a36Sopenharmony_ci{
138462306a36Sopenharmony_ci	struct spi_imx_data *spi_imx = (struct spi_imx_data *)cookie;
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	complete(&spi_imx->dma_tx_completion);
138762306a36Sopenharmony_ci}
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_cistatic int spi_imx_calculate_timeout(struct spi_imx_data *spi_imx, int size)
139062306a36Sopenharmony_ci{
139162306a36Sopenharmony_ci	unsigned long timeout = 0;
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	/* Time with actual data transfer and CS change delay related to HW */
139462306a36Sopenharmony_ci	timeout = (8 + 4) * size / spi_imx->spi_bus_clk;
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	/* Add extra second for scheduler related activities */
139762306a36Sopenharmony_ci	timeout += 1;
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	/* Double calculated timeout */
140062306a36Sopenharmony_ci	return msecs_to_jiffies(2 * timeout * MSEC_PER_SEC);
140162306a36Sopenharmony_ci}
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_cistatic int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
140462306a36Sopenharmony_ci				struct spi_transfer *transfer)
140562306a36Sopenharmony_ci{
140662306a36Sopenharmony_ci	struct dma_async_tx_descriptor *desc_tx, *desc_rx;
140762306a36Sopenharmony_ci	unsigned long transfer_timeout;
140862306a36Sopenharmony_ci	unsigned long timeout;
140962306a36Sopenharmony_ci	struct spi_controller *controller = spi_imx->controller;
141062306a36Sopenharmony_ci	struct sg_table *tx = &transfer->tx_sg, *rx = &transfer->rx_sg;
141162306a36Sopenharmony_ci	struct scatterlist *last_sg = sg_last(rx->sgl, rx->nents);
141262306a36Sopenharmony_ci	unsigned int bytes_per_word, i;
141362306a36Sopenharmony_ci	int ret;
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	/* Get the right burst length from the last sg to ensure no tail data */
141662306a36Sopenharmony_ci	bytes_per_word = spi_imx_bytes_per_word(transfer->bits_per_word);
141762306a36Sopenharmony_ci	for (i = spi_imx->devtype_data->fifo_size / 2; i > 0; i--) {
141862306a36Sopenharmony_ci		if (!(sg_dma_len(last_sg) % (i * bytes_per_word)))
141962306a36Sopenharmony_ci			break;
142062306a36Sopenharmony_ci	}
142162306a36Sopenharmony_ci	/* Use 1 as wml in case no available burst length got */
142262306a36Sopenharmony_ci	if (i == 0)
142362306a36Sopenharmony_ci		i = 1;
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	spi_imx->wml =  i;
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	ret = spi_imx_dma_configure(controller);
142862306a36Sopenharmony_ci	if (ret)
142962306a36Sopenharmony_ci		goto dma_failure_no_start;
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	if (!spi_imx->devtype_data->setup_wml) {
143262306a36Sopenharmony_ci		dev_err(spi_imx->dev, "No setup_wml()?\n");
143362306a36Sopenharmony_ci		ret = -EINVAL;
143462306a36Sopenharmony_ci		goto dma_failure_no_start;
143562306a36Sopenharmony_ci	}
143662306a36Sopenharmony_ci	spi_imx->devtype_data->setup_wml(spi_imx);
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	/*
143962306a36Sopenharmony_ci	 * The TX DMA setup starts the transfer, so make sure RX is configured
144062306a36Sopenharmony_ci	 * before TX.
144162306a36Sopenharmony_ci	 */
144262306a36Sopenharmony_ci	desc_rx = dmaengine_prep_slave_sg(controller->dma_rx,
144362306a36Sopenharmony_ci				rx->sgl, rx->nents, DMA_DEV_TO_MEM,
144462306a36Sopenharmony_ci				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
144562306a36Sopenharmony_ci	if (!desc_rx) {
144662306a36Sopenharmony_ci		ret = -EINVAL;
144762306a36Sopenharmony_ci		goto dma_failure_no_start;
144862306a36Sopenharmony_ci	}
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	desc_rx->callback = spi_imx_dma_rx_callback;
145162306a36Sopenharmony_ci	desc_rx->callback_param = (void *)spi_imx;
145262306a36Sopenharmony_ci	dmaengine_submit(desc_rx);
145362306a36Sopenharmony_ci	reinit_completion(&spi_imx->dma_rx_completion);
145462306a36Sopenharmony_ci	dma_async_issue_pending(controller->dma_rx);
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	desc_tx = dmaengine_prep_slave_sg(controller->dma_tx,
145762306a36Sopenharmony_ci				tx->sgl, tx->nents, DMA_MEM_TO_DEV,
145862306a36Sopenharmony_ci				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
145962306a36Sopenharmony_ci	if (!desc_tx) {
146062306a36Sopenharmony_ci		dmaengine_terminate_all(controller->dma_tx);
146162306a36Sopenharmony_ci		dmaengine_terminate_all(controller->dma_rx);
146262306a36Sopenharmony_ci		return -EINVAL;
146362306a36Sopenharmony_ci	}
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	desc_tx->callback = spi_imx_dma_tx_callback;
146662306a36Sopenharmony_ci	desc_tx->callback_param = (void *)spi_imx;
146762306a36Sopenharmony_ci	dmaengine_submit(desc_tx);
146862306a36Sopenharmony_ci	reinit_completion(&spi_imx->dma_tx_completion);
146962306a36Sopenharmony_ci	dma_async_issue_pending(controller->dma_tx);
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len);
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	/* Wait SDMA to finish the data transfer.*/
147462306a36Sopenharmony_ci	timeout = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
147562306a36Sopenharmony_ci						transfer_timeout);
147662306a36Sopenharmony_ci	if (!timeout) {
147762306a36Sopenharmony_ci		dev_err(spi_imx->dev, "I/O Error in DMA TX\n");
147862306a36Sopenharmony_ci		dmaengine_terminate_all(controller->dma_tx);
147962306a36Sopenharmony_ci		dmaengine_terminate_all(controller->dma_rx);
148062306a36Sopenharmony_ci		return -ETIMEDOUT;
148162306a36Sopenharmony_ci	}
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	timeout = wait_for_completion_timeout(&spi_imx->dma_rx_completion,
148462306a36Sopenharmony_ci					      transfer_timeout);
148562306a36Sopenharmony_ci	if (!timeout) {
148662306a36Sopenharmony_ci		dev_err(&controller->dev, "I/O Error in DMA RX\n");
148762306a36Sopenharmony_ci		spi_imx->devtype_data->reset(spi_imx);
148862306a36Sopenharmony_ci		dmaengine_terminate_all(controller->dma_rx);
148962306a36Sopenharmony_ci		return -ETIMEDOUT;
149062306a36Sopenharmony_ci	}
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	return 0;
149362306a36Sopenharmony_ci/* fallback to pio */
149462306a36Sopenharmony_cidma_failure_no_start:
149562306a36Sopenharmony_ci	transfer->error |= SPI_TRANS_FAIL_NO_START;
149662306a36Sopenharmony_ci	return ret;
149762306a36Sopenharmony_ci}
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_cistatic int spi_imx_pio_transfer(struct spi_device *spi,
150062306a36Sopenharmony_ci				struct spi_transfer *transfer)
150162306a36Sopenharmony_ci{
150262306a36Sopenharmony_ci	struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller);
150362306a36Sopenharmony_ci	unsigned long transfer_timeout;
150462306a36Sopenharmony_ci	unsigned long timeout;
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	spi_imx->tx_buf = transfer->tx_buf;
150762306a36Sopenharmony_ci	spi_imx->rx_buf = transfer->rx_buf;
150862306a36Sopenharmony_ci	spi_imx->count = transfer->len;
150962306a36Sopenharmony_ci	spi_imx->txfifo = 0;
151062306a36Sopenharmony_ci	spi_imx->remainder = 0;
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci	reinit_completion(&spi_imx->xfer_done);
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	spi_imx_push(spi_imx);
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	spi_imx->devtype_data->intctrl(spi_imx, MXC_INT_TE);
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	transfer_timeout = spi_imx_calculate_timeout(spi_imx, transfer->len);
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	timeout = wait_for_completion_timeout(&spi_imx->xfer_done,
152162306a36Sopenharmony_ci					      transfer_timeout);
152262306a36Sopenharmony_ci	if (!timeout) {
152362306a36Sopenharmony_ci		dev_err(&spi->dev, "I/O Error in PIO\n");
152462306a36Sopenharmony_ci		spi_imx->devtype_data->reset(spi_imx);
152562306a36Sopenharmony_ci		return -ETIMEDOUT;
152662306a36Sopenharmony_ci	}
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	return 0;
152962306a36Sopenharmony_ci}
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_cistatic int spi_imx_poll_transfer(struct spi_device *spi,
153262306a36Sopenharmony_ci				 struct spi_transfer *transfer)
153362306a36Sopenharmony_ci{
153462306a36Sopenharmony_ci	struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller);
153562306a36Sopenharmony_ci	unsigned long timeout;
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	spi_imx->tx_buf = transfer->tx_buf;
153862306a36Sopenharmony_ci	spi_imx->rx_buf = transfer->rx_buf;
153962306a36Sopenharmony_ci	spi_imx->count = transfer->len;
154062306a36Sopenharmony_ci	spi_imx->txfifo = 0;
154162306a36Sopenharmony_ci	spi_imx->remainder = 0;
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	/* fill in the fifo before timeout calculations if we are
154462306a36Sopenharmony_ci	 * interrupted here, then the data is getting transferred by
154562306a36Sopenharmony_ci	 * the HW while we are interrupted
154662306a36Sopenharmony_ci	 */
154762306a36Sopenharmony_ci	spi_imx_push(spi_imx);
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	timeout = spi_imx_calculate_timeout(spi_imx, transfer->len) + jiffies;
155062306a36Sopenharmony_ci	while (spi_imx->txfifo) {
155162306a36Sopenharmony_ci		/* RX */
155262306a36Sopenharmony_ci		while (spi_imx->txfifo &&
155362306a36Sopenharmony_ci		       spi_imx->devtype_data->rx_available(spi_imx)) {
155462306a36Sopenharmony_ci			spi_imx->rx(spi_imx);
155562306a36Sopenharmony_ci			spi_imx->txfifo--;
155662306a36Sopenharmony_ci		}
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci		/* TX */
155962306a36Sopenharmony_ci		if (spi_imx->count) {
156062306a36Sopenharmony_ci			spi_imx_push(spi_imx);
156162306a36Sopenharmony_ci			continue;
156262306a36Sopenharmony_ci		}
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci		if (spi_imx->txfifo &&
156562306a36Sopenharmony_ci		    time_after(jiffies, timeout)) {
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci			dev_err_ratelimited(&spi->dev,
156862306a36Sopenharmony_ci					    "timeout period reached: jiffies: %lu- falling back to interrupt mode\n",
156962306a36Sopenharmony_ci					    jiffies - timeout);
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci			/* fall back to interrupt mode */
157262306a36Sopenharmony_ci			return spi_imx_pio_transfer(spi, transfer);
157362306a36Sopenharmony_ci		}
157462306a36Sopenharmony_ci	}
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	return 0;
157762306a36Sopenharmony_ci}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_cistatic int spi_imx_pio_transfer_target(struct spi_device *spi,
158062306a36Sopenharmony_ci				       struct spi_transfer *transfer)
158162306a36Sopenharmony_ci{
158262306a36Sopenharmony_ci	struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller);
158362306a36Sopenharmony_ci	int ret = 0;
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	if (is_imx53_ecspi(spi_imx) &&
158662306a36Sopenharmony_ci	    transfer->len > MX53_MAX_TRANSFER_BYTES) {
158762306a36Sopenharmony_ci		dev_err(&spi->dev, "Transaction too big, max size is %d bytes\n",
158862306a36Sopenharmony_ci			MX53_MAX_TRANSFER_BYTES);
158962306a36Sopenharmony_ci		return -EMSGSIZE;
159062306a36Sopenharmony_ci	}
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	spi_imx->tx_buf = transfer->tx_buf;
159362306a36Sopenharmony_ci	spi_imx->rx_buf = transfer->rx_buf;
159462306a36Sopenharmony_ci	spi_imx->count = transfer->len;
159562306a36Sopenharmony_ci	spi_imx->txfifo = 0;
159662306a36Sopenharmony_ci	spi_imx->remainder = 0;
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	reinit_completion(&spi_imx->xfer_done);
159962306a36Sopenharmony_ci	spi_imx->target_aborted = false;
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	spi_imx_push(spi_imx);
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	spi_imx->devtype_data->intctrl(spi_imx, MXC_INT_TE | MXC_INT_RDR);
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	if (wait_for_completion_interruptible(&spi_imx->xfer_done) ||
160662306a36Sopenharmony_ci	    spi_imx->target_aborted) {
160762306a36Sopenharmony_ci		dev_dbg(&spi->dev, "interrupted\n");
160862306a36Sopenharmony_ci		ret = -EINTR;
160962306a36Sopenharmony_ci	}
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	/* ecspi has a HW issue when works in Target mode,
161262306a36Sopenharmony_ci	 * after 64 words writtern to TXFIFO, even TXFIFO becomes empty,
161362306a36Sopenharmony_ci	 * ECSPI_TXDATA keeps shift out the last word data,
161462306a36Sopenharmony_ci	 * so we have to disable ECSPI when in target mode after the
161562306a36Sopenharmony_ci	 * transfer completes
161662306a36Sopenharmony_ci	 */
161762306a36Sopenharmony_ci	if (spi_imx->devtype_data->disable)
161862306a36Sopenharmony_ci		spi_imx->devtype_data->disable(spi_imx);
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	return ret;
162162306a36Sopenharmony_ci}
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_cistatic int spi_imx_transfer_one(struct spi_controller *controller,
162462306a36Sopenharmony_ci				struct spi_device *spi,
162562306a36Sopenharmony_ci				struct spi_transfer *transfer)
162662306a36Sopenharmony_ci{
162762306a36Sopenharmony_ci	struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller);
162862306a36Sopenharmony_ci	unsigned long hz_per_byte, byte_limit;
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	spi_imx_setupxfer(spi, transfer);
163162306a36Sopenharmony_ci	transfer->effective_speed_hz = spi_imx->spi_bus_clk;
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	/* flush rxfifo before transfer */
163462306a36Sopenharmony_ci	while (spi_imx->devtype_data->rx_available(spi_imx))
163562306a36Sopenharmony_ci		readl(spi_imx->base + MXC_CSPIRXDATA);
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	if (spi_imx->target_mode)
163862306a36Sopenharmony_ci		return spi_imx_pio_transfer_target(spi, transfer);
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci	/*
164162306a36Sopenharmony_ci	 * If we decided in spi_imx_can_dma() that we want to do a DMA
164262306a36Sopenharmony_ci	 * transfer, the SPI transfer has already been mapped, so we
164362306a36Sopenharmony_ci	 * have to do the DMA transfer here.
164462306a36Sopenharmony_ci	 */
164562306a36Sopenharmony_ci	if (spi_imx->usedma)
164662306a36Sopenharmony_ci		return spi_imx_dma_transfer(spi_imx, transfer);
164762306a36Sopenharmony_ci	/*
164862306a36Sopenharmony_ci	 * Calculate the estimated time in us the transfer runs. Find
164962306a36Sopenharmony_ci	 * the number of Hz per byte per polling limit.
165062306a36Sopenharmony_ci	 */
165162306a36Sopenharmony_ci	hz_per_byte = polling_limit_us ? ((8 + 4) * USEC_PER_SEC) / polling_limit_us : 0;
165262306a36Sopenharmony_ci	byte_limit = hz_per_byte ? transfer->effective_speed_hz / hz_per_byte : 1;
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	/* run in polling mode for short transfers */
165562306a36Sopenharmony_ci	if (transfer->len < byte_limit)
165662306a36Sopenharmony_ci		return spi_imx_poll_transfer(spi, transfer);
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci	return spi_imx_pio_transfer(spi, transfer);
165962306a36Sopenharmony_ci}
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_cistatic int spi_imx_setup(struct spi_device *spi)
166262306a36Sopenharmony_ci{
166362306a36Sopenharmony_ci	dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n", __func__,
166462306a36Sopenharmony_ci		 spi->mode, spi->bits_per_word, spi->max_speed_hz);
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	return 0;
166762306a36Sopenharmony_ci}
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_cistatic void spi_imx_cleanup(struct spi_device *spi)
167062306a36Sopenharmony_ci{
167162306a36Sopenharmony_ci}
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_cistatic int
167462306a36Sopenharmony_cispi_imx_prepare_message(struct spi_controller *controller, struct spi_message *msg)
167562306a36Sopenharmony_ci{
167662306a36Sopenharmony_ci	struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller);
167762306a36Sopenharmony_ci	int ret;
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(spi_imx->dev);
168062306a36Sopenharmony_ci	if (ret < 0) {
168162306a36Sopenharmony_ci		dev_err(spi_imx->dev, "failed to enable clock\n");
168262306a36Sopenharmony_ci		return ret;
168362306a36Sopenharmony_ci	}
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	ret = spi_imx->devtype_data->prepare_message(spi_imx, msg);
168662306a36Sopenharmony_ci	if (ret) {
168762306a36Sopenharmony_ci		pm_runtime_mark_last_busy(spi_imx->dev);
168862306a36Sopenharmony_ci		pm_runtime_put_autosuspend(spi_imx->dev);
168962306a36Sopenharmony_ci	}
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	return ret;
169262306a36Sopenharmony_ci}
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_cistatic int
169562306a36Sopenharmony_cispi_imx_unprepare_message(struct spi_controller *controller, struct spi_message *msg)
169662306a36Sopenharmony_ci{
169762306a36Sopenharmony_ci	struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller);
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	pm_runtime_mark_last_busy(spi_imx->dev);
170062306a36Sopenharmony_ci	pm_runtime_put_autosuspend(spi_imx->dev);
170162306a36Sopenharmony_ci	return 0;
170262306a36Sopenharmony_ci}
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_cistatic int spi_imx_target_abort(struct spi_controller *controller)
170562306a36Sopenharmony_ci{
170662306a36Sopenharmony_ci	struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller);
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	spi_imx->target_aborted = true;
170962306a36Sopenharmony_ci	complete(&spi_imx->xfer_done);
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ci	return 0;
171262306a36Sopenharmony_ci}
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_cistatic int spi_imx_probe(struct platform_device *pdev)
171562306a36Sopenharmony_ci{
171662306a36Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
171762306a36Sopenharmony_ci	struct spi_controller *controller;
171862306a36Sopenharmony_ci	struct spi_imx_data *spi_imx;
171962306a36Sopenharmony_ci	struct resource *res;
172062306a36Sopenharmony_ci	int ret, irq, spi_drctl;
172162306a36Sopenharmony_ci	const struct spi_imx_devtype_data *devtype_data =
172262306a36Sopenharmony_ci			of_device_get_match_data(&pdev->dev);
172362306a36Sopenharmony_ci	bool target_mode;
172462306a36Sopenharmony_ci	u32 val;
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	target_mode = devtype_data->has_targetmode &&
172762306a36Sopenharmony_ci		      of_property_read_bool(np, "spi-slave");
172862306a36Sopenharmony_ci	if (target_mode)
172962306a36Sopenharmony_ci		controller = spi_alloc_target(&pdev->dev,
173062306a36Sopenharmony_ci					      sizeof(struct spi_imx_data));
173162306a36Sopenharmony_ci	else
173262306a36Sopenharmony_ci		controller = spi_alloc_host(&pdev->dev,
173362306a36Sopenharmony_ci					    sizeof(struct spi_imx_data));
173462306a36Sopenharmony_ci	if (!controller)
173562306a36Sopenharmony_ci		return -ENOMEM;
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci	ret = of_property_read_u32(np, "fsl,spi-rdy-drctl", &spi_drctl);
173862306a36Sopenharmony_ci	if ((ret < 0) || (spi_drctl >= 0x3)) {
173962306a36Sopenharmony_ci		/* '11' is reserved */
174062306a36Sopenharmony_ci		spi_drctl = 0;
174162306a36Sopenharmony_ci	}
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	platform_set_drvdata(pdev, controller);
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	controller->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
174662306a36Sopenharmony_ci	controller->bus_num = np ? -1 : pdev->id;
174762306a36Sopenharmony_ci	controller->use_gpio_descriptors = true;
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci	spi_imx = spi_controller_get_devdata(controller);
175062306a36Sopenharmony_ci	spi_imx->controller = controller;
175162306a36Sopenharmony_ci	spi_imx->dev = &pdev->dev;
175262306a36Sopenharmony_ci	spi_imx->target_mode = target_mode;
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	spi_imx->devtype_data = devtype_data;
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	/*
175762306a36Sopenharmony_ci	 * Get number of chip selects from device properties. This can be
175862306a36Sopenharmony_ci	 * coming from device tree or boardfiles, if it is not defined,
175962306a36Sopenharmony_ci	 * a default value of 3 chip selects will be used, as all the legacy
176062306a36Sopenharmony_ci	 * board files have <= 3 chip selects.
176162306a36Sopenharmony_ci	 */
176262306a36Sopenharmony_ci	if (!device_property_read_u32(&pdev->dev, "num-cs", &val))
176362306a36Sopenharmony_ci		controller->num_chipselect = val;
176462306a36Sopenharmony_ci	else
176562306a36Sopenharmony_ci		controller->num_chipselect = 3;
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	controller->transfer_one = spi_imx_transfer_one;
176862306a36Sopenharmony_ci	controller->setup = spi_imx_setup;
176962306a36Sopenharmony_ci	controller->cleanup = spi_imx_cleanup;
177062306a36Sopenharmony_ci	controller->prepare_message = spi_imx_prepare_message;
177162306a36Sopenharmony_ci	controller->unprepare_message = spi_imx_unprepare_message;
177262306a36Sopenharmony_ci	controller->target_abort = spi_imx_target_abort;
177362306a36Sopenharmony_ci	controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_NO_CS |
177462306a36Sopenharmony_ci				SPI_MOSI_IDLE_LOW;
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx) ||
177762306a36Sopenharmony_ci	    is_imx53_ecspi(spi_imx))
177862306a36Sopenharmony_ci		controller->mode_bits |= SPI_LOOP | SPI_READY;
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	if (is_imx51_ecspi(spi_imx) || is_imx53_ecspi(spi_imx))
178162306a36Sopenharmony_ci		controller->mode_bits |= SPI_RX_CPHA_FLIP;
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	if (is_imx51_ecspi(spi_imx) &&
178462306a36Sopenharmony_ci	    device_property_read_u32(&pdev->dev, "cs-gpios", NULL))
178562306a36Sopenharmony_ci		/*
178662306a36Sopenharmony_ci		 * When using HW-CS implementing SPI_CS_WORD can be done by just
178762306a36Sopenharmony_ci		 * setting the burst length to the word size. This is
178862306a36Sopenharmony_ci		 * considerably faster than manually controlling the CS.
178962306a36Sopenharmony_ci		 */
179062306a36Sopenharmony_ci		controller->mode_bits |= SPI_CS_WORD;
179162306a36Sopenharmony_ci
179262306a36Sopenharmony_ci	if (is_imx51_ecspi(spi_imx) || is_imx53_ecspi(spi_imx)) {
179362306a36Sopenharmony_ci		controller->max_native_cs = 4;
179462306a36Sopenharmony_ci		controller->flags |= SPI_CONTROLLER_GPIO_SS;
179562306a36Sopenharmony_ci	}
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	spi_imx->spi_drctl = spi_drctl;
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci	init_completion(&spi_imx->xfer_done);
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci	spi_imx->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
180262306a36Sopenharmony_ci	if (IS_ERR(spi_imx->base)) {
180362306a36Sopenharmony_ci		ret = PTR_ERR(spi_imx->base);
180462306a36Sopenharmony_ci		goto out_controller_put;
180562306a36Sopenharmony_ci	}
180662306a36Sopenharmony_ci	spi_imx->base_phys = res->start;
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
180962306a36Sopenharmony_ci	if (irq < 0) {
181062306a36Sopenharmony_ci		ret = irq;
181162306a36Sopenharmony_ci		goto out_controller_put;
181262306a36Sopenharmony_ci	}
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	ret = devm_request_irq(&pdev->dev, irq, spi_imx_isr, 0,
181562306a36Sopenharmony_ci			       dev_name(&pdev->dev), spi_imx);
181662306a36Sopenharmony_ci	if (ret) {
181762306a36Sopenharmony_ci		dev_err(&pdev->dev, "can't get irq%d: %d\n", irq, ret);
181862306a36Sopenharmony_ci		goto out_controller_put;
181962306a36Sopenharmony_ci	}
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	spi_imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
182262306a36Sopenharmony_ci	if (IS_ERR(spi_imx->clk_ipg)) {
182362306a36Sopenharmony_ci		ret = PTR_ERR(spi_imx->clk_ipg);
182462306a36Sopenharmony_ci		goto out_controller_put;
182562306a36Sopenharmony_ci	}
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci	spi_imx->clk_per = devm_clk_get(&pdev->dev, "per");
182862306a36Sopenharmony_ci	if (IS_ERR(spi_imx->clk_per)) {
182962306a36Sopenharmony_ci		ret = PTR_ERR(spi_imx->clk_per);
183062306a36Sopenharmony_ci		goto out_controller_put;
183162306a36Sopenharmony_ci	}
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci	ret = clk_prepare_enable(spi_imx->clk_per);
183462306a36Sopenharmony_ci	if (ret)
183562306a36Sopenharmony_ci		goto out_controller_put;
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	ret = clk_prepare_enable(spi_imx->clk_ipg);
183862306a36Sopenharmony_ci	if (ret)
183962306a36Sopenharmony_ci		goto out_put_per;
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(spi_imx->dev, MXC_RPM_TIMEOUT);
184262306a36Sopenharmony_ci	pm_runtime_use_autosuspend(spi_imx->dev);
184362306a36Sopenharmony_ci	pm_runtime_get_noresume(spi_imx->dev);
184462306a36Sopenharmony_ci	pm_runtime_set_active(spi_imx->dev);
184562306a36Sopenharmony_ci	pm_runtime_enable(spi_imx->dev);
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci	spi_imx->spi_clk = clk_get_rate(spi_imx->clk_per);
184862306a36Sopenharmony_ci	/*
184962306a36Sopenharmony_ci	 * Only validated on i.mx35 and i.mx6 now, can remove the constraint
185062306a36Sopenharmony_ci	 * if validated on other chips.
185162306a36Sopenharmony_ci	 */
185262306a36Sopenharmony_ci	if (spi_imx->devtype_data->has_dmamode) {
185362306a36Sopenharmony_ci		ret = spi_imx_sdma_init(&pdev->dev, spi_imx, controller);
185462306a36Sopenharmony_ci		if (ret == -EPROBE_DEFER)
185562306a36Sopenharmony_ci			goto out_runtime_pm_put;
185662306a36Sopenharmony_ci
185762306a36Sopenharmony_ci		if (ret < 0)
185862306a36Sopenharmony_ci			dev_dbg(&pdev->dev, "dma setup error %d, use pio\n",
185962306a36Sopenharmony_ci				ret);
186062306a36Sopenharmony_ci	}
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	spi_imx->devtype_data->reset(spi_imx);
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci	spi_imx->devtype_data->intctrl(spi_imx, 0);
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	controller->dev.of_node = pdev->dev.of_node;
186762306a36Sopenharmony_ci	ret = spi_register_controller(controller);
186862306a36Sopenharmony_ci	if (ret) {
186962306a36Sopenharmony_ci		dev_err_probe(&pdev->dev, ret, "register controller failed\n");
187062306a36Sopenharmony_ci		goto out_register_controller;
187162306a36Sopenharmony_ci	}
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	pm_runtime_mark_last_busy(spi_imx->dev);
187462306a36Sopenharmony_ci	pm_runtime_put_autosuspend(spi_imx->dev);
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	return ret;
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ciout_register_controller:
187962306a36Sopenharmony_ci	if (spi_imx->devtype_data->has_dmamode)
188062306a36Sopenharmony_ci		spi_imx_sdma_exit(spi_imx);
188162306a36Sopenharmony_ciout_runtime_pm_put:
188262306a36Sopenharmony_ci	pm_runtime_dont_use_autosuspend(spi_imx->dev);
188362306a36Sopenharmony_ci	pm_runtime_set_suspended(&pdev->dev);
188462306a36Sopenharmony_ci	pm_runtime_disable(spi_imx->dev);
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci	clk_disable_unprepare(spi_imx->clk_ipg);
188762306a36Sopenharmony_ciout_put_per:
188862306a36Sopenharmony_ci	clk_disable_unprepare(spi_imx->clk_per);
188962306a36Sopenharmony_ciout_controller_put:
189062306a36Sopenharmony_ci	spi_controller_put(controller);
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	return ret;
189362306a36Sopenharmony_ci}
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_cistatic void spi_imx_remove(struct platform_device *pdev)
189662306a36Sopenharmony_ci{
189762306a36Sopenharmony_ci	struct spi_controller *controller = platform_get_drvdata(pdev);
189862306a36Sopenharmony_ci	struct spi_imx_data *spi_imx = spi_controller_get_devdata(controller);
189962306a36Sopenharmony_ci	int ret;
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci	spi_unregister_controller(controller);
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	ret = pm_runtime_get_sync(spi_imx->dev);
190462306a36Sopenharmony_ci	if (ret >= 0)
190562306a36Sopenharmony_ci		writel(0, spi_imx->base + MXC_CSPICTRL);
190662306a36Sopenharmony_ci	else
190762306a36Sopenharmony_ci		dev_warn(spi_imx->dev, "failed to enable clock, skip hw disable\n");
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	pm_runtime_dont_use_autosuspend(spi_imx->dev);
191062306a36Sopenharmony_ci	pm_runtime_put_sync(spi_imx->dev);
191162306a36Sopenharmony_ci	pm_runtime_disable(spi_imx->dev);
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	spi_imx_sdma_exit(spi_imx);
191462306a36Sopenharmony_ci}
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_cistatic int __maybe_unused spi_imx_runtime_resume(struct device *dev)
191762306a36Sopenharmony_ci{
191862306a36Sopenharmony_ci	struct spi_controller *controller = dev_get_drvdata(dev);
191962306a36Sopenharmony_ci	struct spi_imx_data *spi_imx;
192062306a36Sopenharmony_ci	int ret;
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	spi_imx = spi_controller_get_devdata(controller);
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	ret = clk_prepare_enable(spi_imx->clk_per);
192562306a36Sopenharmony_ci	if (ret)
192662306a36Sopenharmony_ci		return ret;
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ci	ret = clk_prepare_enable(spi_imx->clk_ipg);
192962306a36Sopenharmony_ci	if (ret) {
193062306a36Sopenharmony_ci		clk_disable_unprepare(spi_imx->clk_per);
193162306a36Sopenharmony_ci		return ret;
193262306a36Sopenharmony_ci	}
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci	return 0;
193562306a36Sopenharmony_ci}
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_cistatic int __maybe_unused spi_imx_runtime_suspend(struct device *dev)
193862306a36Sopenharmony_ci{
193962306a36Sopenharmony_ci	struct spi_controller *controller = dev_get_drvdata(dev);
194062306a36Sopenharmony_ci	struct spi_imx_data *spi_imx;
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	spi_imx = spi_controller_get_devdata(controller);
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	clk_disable_unprepare(spi_imx->clk_per);
194562306a36Sopenharmony_ci	clk_disable_unprepare(spi_imx->clk_ipg);
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	return 0;
194862306a36Sopenharmony_ci}
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_cistatic int __maybe_unused spi_imx_suspend(struct device *dev)
195162306a36Sopenharmony_ci{
195262306a36Sopenharmony_ci	pinctrl_pm_select_sleep_state(dev);
195362306a36Sopenharmony_ci	return 0;
195462306a36Sopenharmony_ci}
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_cistatic int __maybe_unused spi_imx_resume(struct device *dev)
195762306a36Sopenharmony_ci{
195862306a36Sopenharmony_ci	pinctrl_pm_select_default_state(dev);
195962306a36Sopenharmony_ci	return 0;
196062306a36Sopenharmony_ci}
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_cistatic const struct dev_pm_ops imx_spi_pm = {
196362306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(spi_imx_runtime_suspend,
196462306a36Sopenharmony_ci				spi_imx_runtime_resume, NULL)
196562306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(spi_imx_suspend, spi_imx_resume)
196662306a36Sopenharmony_ci};
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_cistatic struct platform_driver spi_imx_driver = {
196962306a36Sopenharmony_ci	.driver = {
197062306a36Sopenharmony_ci		   .name = DRIVER_NAME,
197162306a36Sopenharmony_ci		   .of_match_table = spi_imx_dt_ids,
197262306a36Sopenharmony_ci		   .pm = &imx_spi_pm,
197362306a36Sopenharmony_ci	},
197462306a36Sopenharmony_ci	.probe = spi_imx_probe,
197562306a36Sopenharmony_ci	.remove_new = spi_imx_remove,
197662306a36Sopenharmony_ci};
197762306a36Sopenharmony_cimodule_platform_driver(spi_imx_driver);
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_ciMODULE_DESCRIPTION("i.MX SPI Controller driver");
198062306a36Sopenharmony_ciMODULE_AUTHOR("Sascha Hauer, Pengutronix");
198162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
198262306a36Sopenharmony_ciMODULE_ALIAS("platform:" DRIVER_NAME);
1983