162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2011-2015 Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
462306a36Sopenharmony_ci * Copyright (C) 2016 Hauke Mehrtens <hauke@hauke-m.de>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/kernel.h>
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/of.h>
1062306a36Sopenharmony_ci#include <linux/platform_device.h>
1162306a36Sopenharmony_ci#include <linux/clk.h>
1262306a36Sopenharmony_ci#include <linux/io.h>
1362306a36Sopenharmony_ci#include <linux/delay.h>
1462306a36Sopenharmony_ci#include <linux/interrupt.h>
1562306a36Sopenharmony_ci#include <linux/sched.h>
1662306a36Sopenharmony_ci#include <linux/completion.h>
1762306a36Sopenharmony_ci#include <linux/spinlock.h>
1862306a36Sopenharmony_ci#include <linux/err.h>
1962306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2062306a36Sopenharmony_ci#include <linux/spi/spi.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#ifdef CONFIG_LANTIQ
2362306a36Sopenharmony_ci#include <lantiq_soc.h>
2462306a36Sopenharmony_ci#endif
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define LTQ_SPI_RX_IRQ_NAME	"spi_rx"
2762306a36Sopenharmony_ci#define LTQ_SPI_TX_IRQ_NAME	"spi_tx"
2862306a36Sopenharmony_ci#define LTQ_SPI_ERR_IRQ_NAME	"spi_err"
2962306a36Sopenharmony_ci#define LTQ_SPI_FRM_IRQ_NAME	"spi_frm"
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define LTQ_SPI_CLC		0x00
3262306a36Sopenharmony_ci#define LTQ_SPI_PISEL		0x04
3362306a36Sopenharmony_ci#define LTQ_SPI_ID		0x08
3462306a36Sopenharmony_ci#define LTQ_SPI_CON		0x10
3562306a36Sopenharmony_ci#define LTQ_SPI_STAT		0x14
3662306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE	0x18
3762306a36Sopenharmony_ci#define LTQ_SPI_TB		0x20
3862306a36Sopenharmony_ci#define LTQ_SPI_RB		0x24
3962306a36Sopenharmony_ci#define LTQ_SPI_RXFCON		0x30
4062306a36Sopenharmony_ci#define LTQ_SPI_TXFCON		0x34
4162306a36Sopenharmony_ci#define LTQ_SPI_FSTAT		0x38
4262306a36Sopenharmony_ci#define LTQ_SPI_BRT		0x40
4362306a36Sopenharmony_ci#define LTQ_SPI_BRSTAT		0x44
4462306a36Sopenharmony_ci#define LTQ_SPI_SFCON		0x60
4562306a36Sopenharmony_ci#define LTQ_SPI_SFSTAT		0x64
4662306a36Sopenharmony_ci#define LTQ_SPI_GPOCON		0x70
4762306a36Sopenharmony_ci#define LTQ_SPI_GPOSTAT		0x74
4862306a36Sopenharmony_ci#define LTQ_SPI_FPGO		0x78
4962306a36Sopenharmony_ci#define LTQ_SPI_RXREQ		0x80
5062306a36Sopenharmony_ci#define LTQ_SPI_RXCNT		0x84
5162306a36Sopenharmony_ci#define LTQ_SPI_DMACON		0xec
5262306a36Sopenharmony_ci#define LTQ_SPI_IRNEN		0xf4
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define LTQ_SPI_CLC_SMC_S	16	/* Clock divider for sleep mode */
5562306a36Sopenharmony_ci#define LTQ_SPI_CLC_SMC_M	(0xFF << LTQ_SPI_CLC_SMC_S)
5662306a36Sopenharmony_ci#define LTQ_SPI_CLC_RMC_S	8	/* Clock divider for normal run mode */
5762306a36Sopenharmony_ci#define LTQ_SPI_CLC_RMC_M	(0xFF << LTQ_SPI_CLC_RMC_S)
5862306a36Sopenharmony_ci#define LTQ_SPI_CLC_DISS	BIT(1)	/* Disable status bit */
5962306a36Sopenharmony_ci#define LTQ_SPI_CLC_DISR	BIT(0)	/* Disable request bit */
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#define LTQ_SPI_ID_TXFS_S	24	/* Implemented TX FIFO size */
6262306a36Sopenharmony_ci#define LTQ_SPI_ID_RXFS_S	16	/* Implemented RX FIFO size */
6362306a36Sopenharmony_ci#define LTQ_SPI_ID_MOD_S	8	/* Module ID */
6462306a36Sopenharmony_ci#define LTQ_SPI_ID_MOD_M	(0xff << LTQ_SPI_ID_MOD_S)
6562306a36Sopenharmony_ci#define LTQ_SPI_ID_CFG_S	5	/* DMA interface support */
6662306a36Sopenharmony_ci#define LTQ_SPI_ID_CFG_M	(1 << LTQ_SPI_ID_CFG_S)
6762306a36Sopenharmony_ci#define LTQ_SPI_ID_REV_M	0x1F	/* Hardware revision number */
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#define LTQ_SPI_CON_BM_S	16	/* Data width selection */
7062306a36Sopenharmony_ci#define LTQ_SPI_CON_BM_M	(0x1F << LTQ_SPI_CON_BM_S)
7162306a36Sopenharmony_ci#define LTQ_SPI_CON_EM		BIT(24)	/* Echo mode */
7262306a36Sopenharmony_ci#define LTQ_SPI_CON_IDLE	BIT(23)	/* Idle bit value */
7362306a36Sopenharmony_ci#define LTQ_SPI_CON_ENBV	BIT(22)	/* Enable byte valid control */
7462306a36Sopenharmony_ci#define LTQ_SPI_CON_RUEN	BIT(12)	/* Receive underflow error enable */
7562306a36Sopenharmony_ci#define LTQ_SPI_CON_TUEN	BIT(11)	/* Transmit underflow error enable */
7662306a36Sopenharmony_ci#define LTQ_SPI_CON_AEN		BIT(10)	/* Abort error enable */
7762306a36Sopenharmony_ci#define LTQ_SPI_CON_REN		BIT(9)	/* Receive overflow error enable */
7862306a36Sopenharmony_ci#define LTQ_SPI_CON_TEN		BIT(8)	/* Transmit overflow error enable */
7962306a36Sopenharmony_ci#define LTQ_SPI_CON_LB		BIT(7)	/* Loopback control */
8062306a36Sopenharmony_ci#define LTQ_SPI_CON_PO		BIT(6)	/* Clock polarity control */
8162306a36Sopenharmony_ci#define LTQ_SPI_CON_PH		BIT(5)	/* Clock phase control */
8262306a36Sopenharmony_ci#define LTQ_SPI_CON_HB		BIT(4)	/* Heading control */
8362306a36Sopenharmony_ci#define LTQ_SPI_CON_RXOFF	BIT(1)	/* Switch receiver off */
8462306a36Sopenharmony_ci#define LTQ_SPI_CON_TXOFF	BIT(0)	/* Switch transmitter off */
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci#define LTQ_SPI_STAT_RXBV_S	28
8762306a36Sopenharmony_ci#define LTQ_SPI_STAT_RXBV_M	(0x7 << LTQ_SPI_STAT_RXBV_S)
8862306a36Sopenharmony_ci#define LTQ_SPI_STAT_BSY	BIT(13)	/* Busy flag */
8962306a36Sopenharmony_ci#define LTQ_SPI_STAT_RUE	BIT(12)	/* Receive underflow error flag */
9062306a36Sopenharmony_ci#define LTQ_SPI_STAT_TUE	BIT(11)	/* Transmit underflow error flag */
9162306a36Sopenharmony_ci#define LTQ_SPI_STAT_AE		BIT(10)	/* Abort error flag */
9262306a36Sopenharmony_ci#define LTQ_SPI_STAT_RE		BIT(9)	/* Receive error flag */
9362306a36Sopenharmony_ci#define LTQ_SPI_STAT_TE		BIT(8)	/* Transmit error flag */
9462306a36Sopenharmony_ci#define LTQ_SPI_STAT_ME		BIT(7)	/* Mode error flag */
9562306a36Sopenharmony_ci#define LTQ_SPI_STAT_MS		BIT(1)	/* Host/target select bit */
9662306a36Sopenharmony_ci#define LTQ_SPI_STAT_EN		BIT(0)	/* Enable bit */
9762306a36Sopenharmony_ci#define LTQ_SPI_STAT_ERRORS	(LTQ_SPI_STAT_ME | LTQ_SPI_STAT_TE | \
9862306a36Sopenharmony_ci				 LTQ_SPI_STAT_RE | LTQ_SPI_STAT_AE | \
9962306a36Sopenharmony_ci				 LTQ_SPI_STAT_TUE | LTQ_SPI_STAT_RUE)
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_SETTUE	BIT(15)	/* Set transmit underflow error flag */
10262306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_SETAE	BIT(14)	/* Set abort error flag */
10362306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_SETRE	BIT(13)	/* Set receive error flag */
10462306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_SETTE	BIT(12)	/* Set transmit error flag */
10562306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_CLRTUE	BIT(11)	/* Clear transmit underflow error flag */
10662306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_CLRAE	BIT(10)	/* Clear abort error flag */
10762306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_CLRRE	BIT(9)	/* Clear receive error flag */
10862306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_CLRTE	BIT(8)	/* Clear transmit error flag */
10962306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_SETME	BIT(7)	/* Set mode error flag */
11062306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_CLRME	BIT(6)	/* Clear mode error flag */
11162306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_SETRUE	BIT(5)	/* Set receive underflow error flag */
11262306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_CLRRUE	BIT(4)	/* Clear receive underflow error flag */
11362306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_SETMS	BIT(3)	/* Set host select bit */
11462306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_CLRMS	BIT(2)	/* Clear host select bit */
11562306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_SETEN	BIT(1)	/* Set enable bit (operational mode) */
11662306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_CLREN	BIT(0)	/* Clear enable bit (config mode */
11762306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_CLR_ERRORS	(LTQ_SPI_WHBSTATE_CLRRUE | \
11862306a36Sopenharmony_ci					 LTQ_SPI_WHBSTATE_CLRME | \
11962306a36Sopenharmony_ci					 LTQ_SPI_WHBSTATE_CLRTE | \
12062306a36Sopenharmony_ci					 LTQ_SPI_WHBSTATE_CLRRE | \
12162306a36Sopenharmony_ci					 LTQ_SPI_WHBSTATE_CLRAE | \
12262306a36Sopenharmony_ci					 LTQ_SPI_WHBSTATE_CLRTUE)
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci#define LTQ_SPI_RXFCON_RXFITL_S	8	/* FIFO interrupt trigger level */
12562306a36Sopenharmony_ci#define LTQ_SPI_RXFCON_RXFLU	BIT(1)	/* FIFO flush */
12662306a36Sopenharmony_ci#define LTQ_SPI_RXFCON_RXFEN	BIT(0)	/* FIFO enable */
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci#define LTQ_SPI_TXFCON_TXFITL_S	8	/* FIFO interrupt trigger level */
12962306a36Sopenharmony_ci#define LTQ_SPI_TXFCON_TXFLU	BIT(1)	/* FIFO flush */
13062306a36Sopenharmony_ci#define LTQ_SPI_TXFCON_TXFEN	BIT(0)	/* FIFO enable */
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci#define LTQ_SPI_FSTAT_RXFFL_S	0
13362306a36Sopenharmony_ci#define LTQ_SPI_FSTAT_TXFFL_S	8
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci#define LTQ_SPI_GPOCON_ISCSBN_S	8
13662306a36Sopenharmony_ci#define LTQ_SPI_GPOCON_INVOUTN_S	0
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci#define LTQ_SPI_FGPO_SETOUTN_S	8
13962306a36Sopenharmony_ci#define LTQ_SPI_FGPO_CLROUTN_S	0
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci#define LTQ_SPI_RXREQ_RXCNT_M	0xFFFF	/* Receive count value */
14262306a36Sopenharmony_ci#define LTQ_SPI_RXCNT_TODO_M	0xFFFF	/* Recevie to-do value */
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci#define LTQ_SPI_IRNEN_TFI	BIT(4)	/* TX finished interrupt */
14562306a36Sopenharmony_ci#define LTQ_SPI_IRNEN_F		BIT(3)	/* Frame end interrupt request */
14662306a36Sopenharmony_ci#define LTQ_SPI_IRNEN_E		BIT(2)	/* Error end interrupt request */
14762306a36Sopenharmony_ci#define LTQ_SPI_IRNEN_T_XWAY	BIT(1)	/* Transmit end interrupt request */
14862306a36Sopenharmony_ci#define LTQ_SPI_IRNEN_R_XWAY	BIT(0)	/* Receive end interrupt request */
14962306a36Sopenharmony_ci#define LTQ_SPI_IRNEN_R_XRX	BIT(1)	/* Transmit end interrupt request */
15062306a36Sopenharmony_ci#define LTQ_SPI_IRNEN_T_XRX	BIT(0)	/* Receive end interrupt request */
15162306a36Sopenharmony_ci#define LTQ_SPI_IRNEN_ALL	0x1F
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistruct lantiq_ssc_spi;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistruct lantiq_ssc_hwcfg {
15662306a36Sopenharmony_ci	int (*cfg_irq)(struct platform_device *pdev, struct lantiq_ssc_spi *spi);
15762306a36Sopenharmony_ci	unsigned int	irnen_r;
15862306a36Sopenharmony_ci	unsigned int	irnen_t;
15962306a36Sopenharmony_ci	unsigned int	irncr;
16062306a36Sopenharmony_ci	unsigned int	irnicr;
16162306a36Sopenharmony_ci	bool		irq_ack;
16262306a36Sopenharmony_ci	u32		fifo_size_mask;
16362306a36Sopenharmony_ci};
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistruct lantiq_ssc_spi {
16662306a36Sopenharmony_ci	struct spi_controller		*host;
16762306a36Sopenharmony_ci	struct device			*dev;
16862306a36Sopenharmony_ci	void __iomem			*regbase;
16962306a36Sopenharmony_ci	struct clk			*spi_clk;
17062306a36Sopenharmony_ci	struct clk			*fpi_clk;
17162306a36Sopenharmony_ci	const struct lantiq_ssc_hwcfg	*hwcfg;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	spinlock_t			lock;
17462306a36Sopenharmony_ci	struct workqueue_struct		*wq;
17562306a36Sopenharmony_ci	struct work_struct		work;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	const u8			*tx;
17862306a36Sopenharmony_ci	u8				*rx;
17962306a36Sopenharmony_ci	unsigned int			tx_todo;
18062306a36Sopenharmony_ci	unsigned int			rx_todo;
18162306a36Sopenharmony_ci	unsigned int			bits_per_word;
18262306a36Sopenharmony_ci	unsigned int			speed_hz;
18362306a36Sopenharmony_ci	unsigned int			tx_fifo_size;
18462306a36Sopenharmony_ci	unsigned int			rx_fifo_size;
18562306a36Sopenharmony_ci	unsigned int			base_cs;
18662306a36Sopenharmony_ci	unsigned int			fdx_tx_level;
18762306a36Sopenharmony_ci};
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic u32 lantiq_ssc_readl(const struct lantiq_ssc_spi *spi, u32 reg)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	return __raw_readl(spi->regbase + reg);
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistatic void lantiq_ssc_writel(const struct lantiq_ssc_spi *spi, u32 val,
19562306a36Sopenharmony_ci			      u32 reg)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	__raw_writel(val, spi->regbase + reg);
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic void lantiq_ssc_maskl(const struct lantiq_ssc_spi *spi, u32 clr,
20162306a36Sopenharmony_ci			     u32 set, u32 reg)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	u32 val = __raw_readl(spi->regbase + reg);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	val &= ~clr;
20662306a36Sopenharmony_ci	val |= set;
20762306a36Sopenharmony_ci	__raw_writel(val, spi->regbase + reg);
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic unsigned int tx_fifo_level(const struct lantiq_ssc_spi *spi)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg;
21362306a36Sopenharmony_ci	u32 fstat = lantiq_ssc_readl(spi, LTQ_SPI_FSTAT);
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	return (fstat >> LTQ_SPI_FSTAT_TXFFL_S) & hwcfg->fifo_size_mask;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic unsigned int rx_fifo_level(const struct lantiq_ssc_spi *spi)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg;
22162306a36Sopenharmony_ci	u32 fstat = lantiq_ssc_readl(spi, LTQ_SPI_FSTAT);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	return (fstat >> LTQ_SPI_FSTAT_RXFFL_S) & hwcfg->fifo_size_mask;
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistatic unsigned int tx_fifo_free(const struct lantiq_ssc_spi *spi)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	return spi->tx_fifo_size - tx_fifo_level(spi);
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic void rx_fifo_reset(const struct lantiq_ssc_spi *spi)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	u32 val = spi->rx_fifo_size << LTQ_SPI_RXFCON_RXFITL_S;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	val |= LTQ_SPI_RXFCON_RXFEN | LTQ_SPI_RXFCON_RXFLU;
23662306a36Sopenharmony_ci	lantiq_ssc_writel(spi, val, LTQ_SPI_RXFCON);
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic void tx_fifo_reset(const struct lantiq_ssc_spi *spi)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	u32 val = 1 << LTQ_SPI_TXFCON_TXFITL_S;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	val |= LTQ_SPI_TXFCON_TXFEN | LTQ_SPI_TXFCON_TXFLU;
24462306a36Sopenharmony_ci	lantiq_ssc_writel(spi, val, LTQ_SPI_TXFCON);
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic void rx_fifo_flush(const struct lantiq_ssc_spi *spi)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	lantiq_ssc_maskl(spi, 0, LTQ_SPI_RXFCON_RXFLU, LTQ_SPI_RXFCON);
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic void tx_fifo_flush(const struct lantiq_ssc_spi *spi)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	lantiq_ssc_maskl(spi, 0, LTQ_SPI_TXFCON_TXFLU, LTQ_SPI_TXFCON);
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic void hw_enter_config_mode(const struct lantiq_ssc_spi *spi)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	lantiq_ssc_writel(spi, LTQ_SPI_WHBSTATE_CLREN, LTQ_SPI_WHBSTATE);
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic void hw_enter_active_mode(const struct lantiq_ssc_spi *spi)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	lantiq_ssc_writel(spi, LTQ_SPI_WHBSTATE_SETEN, LTQ_SPI_WHBSTATE);
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic void hw_setup_speed_hz(const struct lantiq_ssc_spi *spi,
26862306a36Sopenharmony_ci			      unsigned int max_speed_hz)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	u32 spi_clk, brt;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	/*
27362306a36Sopenharmony_ci	 * SPI module clock is derived from FPI bus clock dependent on
27462306a36Sopenharmony_ci	 * divider value in CLC.RMS which is always set to 1.
27562306a36Sopenharmony_ci	 *
27662306a36Sopenharmony_ci	 *                 f_SPI
27762306a36Sopenharmony_ci	 * baudrate = --------------
27862306a36Sopenharmony_ci	 *             2 * (BR + 1)
27962306a36Sopenharmony_ci	 */
28062306a36Sopenharmony_ci	spi_clk = clk_get_rate(spi->fpi_clk) / 2;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	if (max_speed_hz > spi_clk)
28362306a36Sopenharmony_ci		brt = 0;
28462306a36Sopenharmony_ci	else
28562306a36Sopenharmony_ci		brt = spi_clk / max_speed_hz - 1;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	if (brt > 0xFFFF)
28862306a36Sopenharmony_ci		brt = 0xFFFF;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	dev_dbg(spi->dev, "spi_clk %u, max_speed_hz %u, brt %u\n",
29162306a36Sopenharmony_ci		spi_clk, max_speed_hz, brt);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	lantiq_ssc_writel(spi, brt, LTQ_SPI_BRT);
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic void hw_setup_bits_per_word(const struct lantiq_ssc_spi *spi,
29762306a36Sopenharmony_ci				   unsigned int bits_per_word)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	u32 bm;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	/* CON.BM value = bits_per_word - 1 */
30262306a36Sopenharmony_ci	bm = (bits_per_word - 1) << LTQ_SPI_CON_BM_S;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	lantiq_ssc_maskl(spi, LTQ_SPI_CON_BM_M, bm, LTQ_SPI_CON);
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_cistatic void hw_setup_clock_mode(const struct lantiq_ssc_spi *spi,
30862306a36Sopenharmony_ci				unsigned int mode)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	u32 con_set = 0, con_clr = 0;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	/*
31362306a36Sopenharmony_ci	 * SPI mode mapping in CON register:
31462306a36Sopenharmony_ci	 * Mode CPOL CPHA CON.PO CON.PH
31562306a36Sopenharmony_ci	 *  0    0    0      0      1
31662306a36Sopenharmony_ci	 *  1    0    1      0      0
31762306a36Sopenharmony_ci	 *  2    1    0      1      1
31862306a36Sopenharmony_ci	 *  3    1    1      1      0
31962306a36Sopenharmony_ci	 */
32062306a36Sopenharmony_ci	if (mode & SPI_CPHA)
32162306a36Sopenharmony_ci		con_clr |= LTQ_SPI_CON_PH;
32262306a36Sopenharmony_ci	else
32362306a36Sopenharmony_ci		con_set |= LTQ_SPI_CON_PH;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	if (mode & SPI_CPOL)
32662306a36Sopenharmony_ci		con_set |= LTQ_SPI_CON_PO | LTQ_SPI_CON_IDLE;
32762306a36Sopenharmony_ci	else
32862306a36Sopenharmony_ci		con_clr |= LTQ_SPI_CON_PO | LTQ_SPI_CON_IDLE;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	/* Set heading control */
33162306a36Sopenharmony_ci	if (mode & SPI_LSB_FIRST)
33262306a36Sopenharmony_ci		con_clr |= LTQ_SPI_CON_HB;
33362306a36Sopenharmony_ci	else
33462306a36Sopenharmony_ci		con_set |= LTQ_SPI_CON_HB;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	/* Set loopback mode */
33762306a36Sopenharmony_ci	if (mode & SPI_LOOP)
33862306a36Sopenharmony_ci		con_set |= LTQ_SPI_CON_LB;
33962306a36Sopenharmony_ci	else
34062306a36Sopenharmony_ci		con_clr |= LTQ_SPI_CON_LB;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	lantiq_ssc_maskl(spi, con_clr, con_set, LTQ_SPI_CON);
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_cistatic void lantiq_ssc_hw_init(const struct lantiq_ssc_spi *spi)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	/*
35062306a36Sopenharmony_ci	 * Set clock divider for run mode to 1 to
35162306a36Sopenharmony_ci	 * run at same frequency as FPI bus
35262306a36Sopenharmony_ci	 */
35362306a36Sopenharmony_ci	lantiq_ssc_writel(spi, 1 << LTQ_SPI_CLC_RMC_S, LTQ_SPI_CLC);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	/* Put controller into config mode */
35662306a36Sopenharmony_ci	hw_enter_config_mode(spi);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	/* Clear error flags */
35962306a36Sopenharmony_ci	lantiq_ssc_maskl(spi, 0, LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	/* Enable error checking, disable TX/RX */
36262306a36Sopenharmony_ci	lantiq_ssc_writel(spi, LTQ_SPI_CON_RUEN | LTQ_SPI_CON_AEN |
36362306a36Sopenharmony_ci		LTQ_SPI_CON_TEN | LTQ_SPI_CON_REN | LTQ_SPI_CON_TXOFF |
36462306a36Sopenharmony_ci		LTQ_SPI_CON_RXOFF, LTQ_SPI_CON);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/* Setup default SPI mode */
36762306a36Sopenharmony_ci	hw_setup_bits_per_word(spi, spi->bits_per_word);
36862306a36Sopenharmony_ci	hw_setup_clock_mode(spi, SPI_MODE_0);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	/* Enable host mode and clear error flags */
37162306a36Sopenharmony_ci	lantiq_ssc_writel(spi, LTQ_SPI_WHBSTATE_SETMS |
37262306a36Sopenharmony_ci			       LTQ_SPI_WHBSTATE_CLR_ERRORS,
37362306a36Sopenharmony_ci			       LTQ_SPI_WHBSTATE);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	/* Reset GPIO/CS registers */
37662306a36Sopenharmony_ci	lantiq_ssc_writel(spi, 0, LTQ_SPI_GPOCON);
37762306a36Sopenharmony_ci	lantiq_ssc_writel(spi, 0xFF00, LTQ_SPI_FPGO);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	/* Enable and flush FIFOs */
38062306a36Sopenharmony_ci	rx_fifo_reset(spi);
38162306a36Sopenharmony_ci	tx_fifo_reset(spi);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	/* Enable interrupts */
38462306a36Sopenharmony_ci	lantiq_ssc_writel(spi, hwcfg->irnen_t | hwcfg->irnen_r |
38562306a36Sopenharmony_ci			  LTQ_SPI_IRNEN_E, LTQ_SPI_IRNEN);
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_cistatic int lantiq_ssc_setup(struct spi_device *spidev)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	struct spi_controller *host = spidev->controller;
39162306a36Sopenharmony_ci	struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host);
39262306a36Sopenharmony_ci	unsigned int cs = spi_get_chipselect(spidev, 0);
39362306a36Sopenharmony_ci	u32 gpocon;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	/* GPIOs are used for CS */
39662306a36Sopenharmony_ci	if (spi_get_csgpiod(spidev, 0))
39762306a36Sopenharmony_ci		return 0;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	dev_dbg(spi->dev, "using internal chipselect %u\n", cs);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	if (cs < spi->base_cs) {
40262306a36Sopenharmony_ci		dev_err(spi->dev,
40362306a36Sopenharmony_ci			"chipselect %i too small (min %i)\n", cs, spi->base_cs);
40462306a36Sopenharmony_ci		return -EINVAL;
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	/* set GPO pin to CS mode */
40862306a36Sopenharmony_ci	gpocon = 1 << ((cs - spi->base_cs) + LTQ_SPI_GPOCON_ISCSBN_S);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	/* invert GPO pin */
41162306a36Sopenharmony_ci	if (spidev->mode & SPI_CS_HIGH)
41262306a36Sopenharmony_ci		gpocon |= 1 << (cs - spi->base_cs);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	lantiq_ssc_maskl(spi, 0, gpocon, LTQ_SPI_GPOCON);
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	return 0;
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_cistatic int lantiq_ssc_prepare_message(struct spi_controller *host,
42062306a36Sopenharmony_ci				      struct spi_message *message)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	hw_enter_config_mode(spi);
42562306a36Sopenharmony_ci	hw_setup_clock_mode(spi, message->spi->mode);
42662306a36Sopenharmony_ci	hw_enter_active_mode(spi);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	return 0;
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_cistatic void hw_setup_transfer(struct lantiq_ssc_spi *spi,
43262306a36Sopenharmony_ci			      struct spi_device *spidev, struct spi_transfer *t)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	unsigned int speed_hz = t->speed_hz;
43562306a36Sopenharmony_ci	unsigned int bits_per_word = t->bits_per_word;
43662306a36Sopenharmony_ci	u32 con;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	if (bits_per_word != spi->bits_per_word ||
43962306a36Sopenharmony_ci		speed_hz != spi->speed_hz) {
44062306a36Sopenharmony_ci		hw_enter_config_mode(spi);
44162306a36Sopenharmony_ci		hw_setup_speed_hz(spi, speed_hz);
44262306a36Sopenharmony_ci		hw_setup_bits_per_word(spi, bits_per_word);
44362306a36Sopenharmony_ci		hw_enter_active_mode(spi);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci		spi->speed_hz = speed_hz;
44662306a36Sopenharmony_ci		spi->bits_per_word = bits_per_word;
44762306a36Sopenharmony_ci	}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	/* Configure transmitter and receiver */
45062306a36Sopenharmony_ci	con = lantiq_ssc_readl(spi, LTQ_SPI_CON);
45162306a36Sopenharmony_ci	if (t->tx_buf)
45262306a36Sopenharmony_ci		con &= ~LTQ_SPI_CON_TXOFF;
45362306a36Sopenharmony_ci	else
45462306a36Sopenharmony_ci		con |= LTQ_SPI_CON_TXOFF;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	if (t->rx_buf)
45762306a36Sopenharmony_ci		con &= ~LTQ_SPI_CON_RXOFF;
45862306a36Sopenharmony_ci	else
45962306a36Sopenharmony_ci		con |= LTQ_SPI_CON_RXOFF;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	lantiq_ssc_writel(spi, con, LTQ_SPI_CON);
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_cistatic int lantiq_ssc_unprepare_message(struct spi_controller *host,
46562306a36Sopenharmony_ci					struct spi_message *message)
46662306a36Sopenharmony_ci{
46762306a36Sopenharmony_ci	struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	flush_workqueue(spi->wq);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	/* Disable transmitter and receiver while idle */
47262306a36Sopenharmony_ci	lantiq_ssc_maskl(spi, 0, LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF,
47362306a36Sopenharmony_ci			 LTQ_SPI_CON);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	return 0;
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic void tx_fifo_write(struct lantiq_ssc_spi *spi)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	const u8 *tx8;
48162306a36Sopenharmony_ci	const u16 *tx16;
48262306a36Sopenharmony_ci	const u32 *tx32;
48362306a36Sopenharmony_ci	u32 data;
48462306a36Sopenharmony_ci	unsigned int tx_free = tx_fifo_free(spi);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	spi->fdx_tx_level = 0;
48762306a36Sopenharmony_ci	while (spi->tx_todo && tx_free) {
48862306a36Sopenharmony_ci		switch (spi->bits_per_word) {
48962306a36Sopenharmony_ci		case 2 ... 8:
49062306a36Sopenharmony_ci			tx8 = spi->tx;
49162306a36Sopenharmony_ci			data = *tx8;
49262306a36Sopenharmony_ci			spi->tx_todo--;
49362306a36Sopenharmony_ci			spi->tx++;
49462306a36Sopenharmony_ci			break;
49562306a36Sopenharmony_ci		case 16:
49662306a36Sopenharmony_ci			tx16 = (u16 *) spi->tx;
49762306a36Sopenharmony_ci			data = *tx16;
49862306a36Sopenharmony_ci			spi->tx_todo -= 2;
49962306a36Sopenharmony_ci			spi->tx += 2;
50062306a36Sopenharmony_ci			break;
50162306a36Sopenharmony_ci		case 32:
50262306a36Sopenharmony_ci			tx32 = (u32 *) spi->tx;
50362306a36Sopenharmony_ci			data = *tx32;
50462306a36Sopenharmony_ci			spi->tx_todo -= 4;
50562306a36Sopenharmony_ci			spi->tx += 4;
50662306a36Sopenharmony_ci			break;
50762306a36Sopenharmony_ci		default:
50862306a36Sopenharmony_ci			WARN_ON(1);
50962306a36Sopenharmony_ci			data = 0;
51062306a36Sopenharmony_ci			break;
51162306a36Sopenharmony_ci		}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci		lantiq_ssc_writel(spi, data, LTQ_SPI_TB);
51462306a36Sopenharmony_ci		tx_free--;
51562306a36Sopenharmony_ci		spi->fdx_tx_level++;
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_cistatic void rx_fifo_read_full_duplex(struct lantiq_ssc_spi *spi)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	u8 *rx8;
52262306a36Sopenharmony_ci	u16 *rx16;
52362306a36Sopenharmony_ci	u32 *rx32;
52462306a36Sopenharmony_ci	u32 data;
52562306a36Sopenharmony_ci	unsigned int rx_fill = rx_fifo_level(spi);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	/*
52862306a36Sopenharmony_ci	 * Wait until all expected data to be shifted in.
52962306a36Sopenharmony_ci	 * Otherwise, rx overrun may occur.
53062306a36Sopenharmony_ci	 */
53162306a36Sopenharmony_ci	while (rx_fill != spi->fdx_tx_level)
53262306a36Sopenharmony_ci		rx_fill = rx_fifo_level(spi);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	while (rx_fill) {
53562306a36Sopenharmony_ci		data = lantiq_ssc_readl(spi, LTQ_SPI_RB);
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci		switch (spi->bits_per_word) {
53862306a36Sopenharmony_ci		case 2 ... 8:
53962306a36Sopenharmony_ci			rx8 = spi->rx;
54062306a36Sopenharmony_ci			*rx8 = data;
54162306a36Sopenharmony_ci			spi->rx_todo--;
54262306a36Sopenharmony_ci			spi->rx++;
54362306a36Sopenharmony_ci			break;
54462306a36Sopenharmony_ci		case 16:
54562306a36Sopenharmony_ci			rx16 = (u16 *) spi->rx;
54662306a36Sopenharmony_ci			*rx16 = data;
54762306a36Sopenharmony_ci			spi->rx_todo -= 2;
54862306a36Sopenharmony_ci			spi->rx += 2;
54962306a36Sopenharmony_ci			break;
55062306a36Sopenharmony_ci		case 32:
55162306a36Sopenharmony_ci			rx32 = (u32 *) spi->rx;
55262306a36Sopenharmony_ci			*rx32 = data;
55362306a36Sopenharmony_ci			spi->rx_todo -= 4;
55462306a36Sopenharmony_ci			spi->rx += 4;
55562306a36Sopenharmony_ci			break;
55662306a36Sopenharmony_ci		default:
55762306a36Sopenharmony_ci			WARN_ON(1);
55862306a36Sopenharmony_ci			break;
55962306a36Sopenharmony_ci		}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci		rx_fill--;
56262306a36Sopenharmony_ci	}
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_cistatic void rx_fifo_read_half_duplex(struct lantiq_ssc_spi *spi)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	u32 data, *rx32;
56862306a36Sopenharmony_ci	u8 *rx8;
56962306a36Sopenharmony_ci	unsigned int rxbv, shift;
57062306a36Sopenharmony_ci	unsigned int rx_fill = rx_fifo_level(spi);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	/*
57362306a36Sopenharmony_ci	 * In RX-only mode the bits per word value is ignored by HW. A value
57462306a36Sopenharmony_ci	 * of 32 is used instead. Thus all 4 bytes per FIFO must be read.
57562306a36Sopenharmony_ci	 * If remaining RX bytes are less than 4, the FIFO must be read
57662306a36Sopenharmony_ci	 * differently. The amount of received and valid bytes is indicated
57762306a36Sopenharmony_ci	 * by STAT.RXBV register value.
57862306a36Sopenharmony_ci	 */
57962306a36Sopenharmony_ci	while (rx_fill) {
58062306a36Sopenharmony_ci		if (spi->rx_todo < 4)  {
58162306a36Sopenharmony_ci			rxbv = (lantiq_ssc_readl(spi, LTQ_SPI_STAT) &
58262306a36Sopenharmony_ci				LTQ_SPI_STAT_RXBV_M) >> LTQ_SPI_STAT_RXBV_S;
58362306a36Sopenharmony_ci			data = lantiq_ssc_readl(spi, LTQ_SPI_RB);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci			shift = (rxbv - 1) * 8;
58662306a36Sopenharmony_ci			rx8 = spi->rx;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci			while (rxbv) {
58962306a36Sopenharmony_ci				*rx8++ = (data >> shift) & 0xFF;
59062306a36Sopenharmony_ci				rxbv--;
59162306a36Sopenharmony_ci				shift -= 8;
59262306a36Sopenharmony_ci				spi->rx_todo--;
59362306a36Sopenharmony_ci				spi->rx++;
59462306a36Sopenharmony_ci			}
59562306a36Sopenharmony_ci		} else {
59662306a36Sopenharmony_ci			data = lantiq_ssc_readl(spi, LTQ_SPI_RB);
59762306a36Sopenharmony_ci			rx32 = (u32 *) spi->rx;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci			*rx32++ = data;
60062306a36Sopenharmony_ci			spi->rx_todo -= 4;
60162306a36Sopenharmony_ci			spi->rx += 4;
60262306a36Sopenharmony_ci		}
60362306a36Sopenharmony_ci		rx_fill--;
60462306a36Sopenharmony_ci	}
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic void rx_request(struct lantiq_ssc_spi *spi)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	unsigned int rxreq, rxreq_max;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	/*
61262306a36Sopenharmony_ci	 * To avoid receive overflows at high clocks it is better to request
61362306a36Sopenharmony_ci	 * only the amount of bytes that fits into all FIFOs. This value
61462306a36Sopenharmony_ci	 * depends on the FIFO size implemented in hardware.
61562306a36Sopenharmony_ci	 */
61662306a36Sopenharmony_ci	rxreq = spi->rx_todo;
61762306a36Sopenharmony_ci	rxreq_max = spi->rx_fifo_size * 4;
61862306a36Sopenharmony_ci	if (rxreq > rxreq_max)
61962306a36Sopenharmony_ci		rxreq = rxreq_max;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	lantiq_ssc_writel(spi, rxreq, LTQ_SPI_RXREQ);
62262306a36Sopenharmony_ci}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_cistatic irqreturn_t lantiq_ssc_xmit_interrupt(int irq, void *data)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	struct lantiq_ssc_spi *spi = data;
62762306a36Sopenharmony_ci	const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg;
62862306a36Sopenharmony_ci	u32 val = lantiq_ssc_readl(spi, hwcfg->irncr);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	spin_lock(&spi->lock);
63162306a36Sopenharmony_ci	if (hwcfg->irq_ack)
63262306a36Sopenharmony_ci		lantiq_ssc_writel(spi, val, hwcfg->irncr);
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	if (spi->tx) {
63562306a36Sopenharmony_ci		if (spi->rx && spi->rx_todo)
63662306a36Sopenharmony_ci			rx_fifo_read_full_duplex(spi);
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci		if (spi->tx_todo)
63962306a36Sopenharmony_ci			tx_fifo_write(spi);
64062306a36Sopenharmony_ci		else if (!tx_fifo_level(spi))
64162306a36Sopenharmony_ci			goto completed;
64262306a36Sopenharmony_ci	} else if (spi->rx) {
64362306a36Sopenharmony_ci		if (spi->rx_todo) {
64462306a36Sopenharmony_ci			rx_fifo_read_half_duplex(spi);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci			if (spi->rx_todo)
64762306a36Sopenharmony_ci				rx_request(spi);
64862306a36Sopenharmony_ci			else
64962306a36Sopenharmony_ci				goto completed;
65062306a36Sopenharmony_ci		} else {
65162306a36Sopenharmony_ci			goto completed;
65262306a36Sopenharmony_ci		}
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	spin_unlock(&spi->lock);
65662306a36Sopenharmony_ci	return IRQ_HANDLED;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_cicompleted:
65962306a36Sopenharmony_ci	queue_work(spi->wq, &spi->work);
66062306a36Sopenharmony_ci	spin_unlock(&spi->lock);
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	return IRQ_HANDLED;
66362306a36Sopenharmony_ci}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_cistatic irqreturn_t lantiq_ssc_err_interrupt(int irq, void *data)
66662306a36Sopenharmony_ci{
66762306a36Sopenharmony_ci	struct lantiq_ssc_spi *spi = data;
66862306a36Sopenharmony_ci	const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg;
66962306a36Sopenharmony_ci	u32 stat = lantiq_ssc_readl(spi, LTQ_SPI_STAT);
67062306a36Sopenharmony_ci	u32 val = lantiq_ssc_readl(spi, hwcfg->irncr);
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	if (!(stat & LTQ_SPI_STAT_ERRORS))
67362306a36Sopenharmony_ci		return IRQ_NONE;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	spin_lock(&spi->lock);
67662306a36Sopenharmony_ci	if (hwcfg->irq_ack)
67762306a36Sopenharmony_ci		lantiq_ssc_writel(spi, val, hwcfg->irncr);
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	if (stat & LTQ_SPI_STAT_RUE)
68062306a36Sopenharmony_ci		dev_err(spi->dev, "receive underflow error\n");
68162306a36Sopenharmony_ci	if (stat & LTQ_SPI_STAT_TUE)
68262306a36Sopenharmony_ci		dev_err(spi->dev, "transmit underflow error\n");
68362306a36Sopenharmony_ci	if (stat & LTQ_SPI_STAT_AE)
68462306a36Sopenharmony_ci		dev_err(spi->dev, "abort error\n");
68562306a36Sopenharmony_ci	if (stat & LTQ_SPI_STAT_RE)
68662306a36Sopenharmony_ci		dev_err(spi->dev, "receive overflow error\n");
68762306a36Sopenharmony_ci	if (stat & LTQ_SPI_STAT_TE)
68862306a36Sopenharmony_ci		dev_err(spi->dev, "transmit overflow error\n");
68962306a36Sopenharmony_ci	if (stat & LTQ_SPI_STAT_ME)
69062306a36Sopenharmony_ci		dev_err(spi->dev, "mode error\n");
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	/* Clear error flags */
69362306a36Sopenharmony_ci	lantiq_ssc_maskl(spi, 0, LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE);
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	/* set bad status so it can be retried */
69662306a36Sopenharmony_ci	if (spi->host->cur_msg)
69762306a36Sopenharmony_ci		spi->host->cur_msg->status = -EIO;
69862306a36Sopenharmony_ci	queue_work(spi->wq, &spi->work);
69962306a36Sopenharmony_ci	spin_unlock(&spi->lock);
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	return IRQ_HANDLED;
70262306a36Sopenharmony_ci}
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_cistatic irqreturn_t intel_lgm_ssc_isr(int irq, void *data)
70562306a36Sopenharmony_ci{
70662306a36Sopenharmony_ci	struct lantiq_ssc_spi *spi = data;
70762306a36Sopenharmony_ci	const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg;
70862306a36Sopenharmony_ci	u32 val = lantiq_ssc_readl(spi, hwcfg->irncr);
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	if (!(val & LTQ_SPI_IRNEN_ALL))
71162306a36Sopenharmony_ci		return IRQ_NONE;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	if (val & LTQ_SPI_IRNEN_E)
71462306a36Sopenharmony_ci		return lantiq_ssc_err_interrupt(irq, data);
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	if ((val & hwcfg->irnen_t) || (val & hwcfg->irnen_r))
71762306a36Sopenharmony_ci		return lantiq_ssc_xmit_interrupt(irq, data);
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	return IRQ_HANDLED;
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_cistatic int transfer_start(struct lantiq_ssc_spi *spi, struct spi_device *spidev,
72362306a36Sopenharmony_ci			  struct spi_transfer *t)
72462306a36Sopenharmony_ci{
72562306a36Sopenharmony_ci	unsigned long flags;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	spin_lock_irqsave(&spi->lock, flags);
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	spi->tx = t->tx_buf;
73062306a36Sopenharmony_ci	spi->rx = t->rx_buf;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	if (t->tx_buf) {
73362306a36Sopenharmony_ci		spi->tx_todo = t->len;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci		/* initially fill TX FIFO */
73662306a36Sopenharmony_ci		tx_fifo_write(spi);
73762306a36Sopenharmony_ci	}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	if (spi->rx) {
74062306a36Sopenharmony_ci		spi->rx_todo = t->len;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci		/* start shift clock in RX-only mode */
74362306a36Sopenharmony_ci		if (!spi->tx)
74462306a36Sopenharmony_ci			rx_request(spi);
74562306a36Sopenharmony_ci	}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	spin_unlock_irqrestore(&spi->lock, flags);
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	return t->len;
75062306a36Sopenharmony_ci}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci/*
75362306a36Sopenharmony_ci * The driver only gets an interrupt when the FIFO is empty, but there
75462306a36Sopenharmony_ci * is an additional shift register from which the data is written to
75562306a36Sopenharmony_ci * the wire. We get the last interrupt when the controller starts to
75662306a36Sopenharmony_ci * write the last word to the wire, not when it is finished. Do busy
75762306a36Sopenharmony_ci * waiting till it finishes.
75862306a36Sopenharmony_ci */
75962306a36Sopenharmony_cistatic void lantiq_ssc_bussy_work(struct work_struct *work)
76062306a36Sopenharmony_ci{
76162306a36Sopenharmony_ci	struct lantiq_ssc_spi *spi;
76262306a36Sopenharmony_ci	unsigned long long timeout = 8LL * 1000LL;
76362306a36Sopenharmony_ci	unsigned long end;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	spi = container_of(work, typeof(*spi), work);
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	do_div(timeout, spi->speed_hz);
76862306a36Sopenharmony_ci	timeout += timeout + 100; /* some tolerance */
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	end = jiffies + msecs_to_jiffies(timeout);
77162306a36Sopenharmony_ci	do {
77262306a36Sopenharmony_ci		u32 stat = lantiq_ssc_readl(spi, LTQ_SPI_STAT);
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci		if (!(stat & LTQ_SPI_STAT_BSY)) {
77562306a36Sopenharmony_ci			spi_finalize_current_transfer(spi->host);
77662306a36Sopenharmony_ci			return;
77762306a36Sopenharmony_ci		}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci		cond_resched();
78062306a36Sopenharmony_ci	} while (!time_after_eq(jiffies, end));
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	if (spi->host->cur_msg)
78362306a36Sopenharmony_ci		spi->host->cur_msg->status = -EIO;
78462306a36Sopenharmony_ci	spi_finalize_current_transfer(spi->host);
78562306a36Sopenharmony_ci}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_cistatic void lantiq_ssc_handle_err(struct spi_controller *host,
78862306a36Sopenharmony_ci				  struct spi_message *message)
78962306a36Sopenharmony_ci{
79062306a36Sopenharmony_ci	struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host);
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	/* flush FIFOs on timeout */
79362306a36Sopenharmony_ci	rx_fifo_flush(spi);
79462306a36Sopenharmony_ci	tx_fifo_flush(spi);
79562306a36Sopenharmony_ci}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_cistatic void lantiq_ssc_set_cs(struct spi_device *spidev, bool enable)
79862306a36Sopenharmony_ci{
79962306a36Sopenharmony_ci	struct lantiq_ssc_spi *spi = spi_controller_get_devdata(spidev->controller);
80062306a36Sopenharmony_ci	unsigned int cs = spi_get_chipselect(spidev, 0);
80162306a36Sopenharmony_ci	u32 fgpo;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	if (!!(spidev->mode & SPI_CS_HIGH) == enable)
80462306a36Sopenharmony_ci		fgpo = (1 << (cs - spi->base_cs));
80562306a36Sopenharmony_ci	else
80662306a36Sopenharmony_ci		fgpo = (1 << (cs - spi->base_cs + LTQ_SPI_FGPO_SETOUTN_S));
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	lantiq_ssc_writel(spi, fgpo, LTQ_SPI_FPGO);
80962306a36Sopenharmony_ci}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_cistatic int lantiq_ssc_transfer_one(struct spi_controller *host,
81262306a36Sopenharmony_ci				   struct spi_device *spidev,
81362306a36Sopenharmony_ci				   struct spi_transfer *t)
81462306a36Sopenharmony_ci{
81562306a36Sopenharmony_ci	struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host);
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	hw_setup_transfer(spi, spidev, t);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	return transfer_start(spi, spidev, t);
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_cistatic int intel_lgm_cfg_irq(struct platform_device *pdev, struct lantiq_ssc_spi *spi)
82362306a36Sopenharmony_ci{
82462306a36Sopenharmony_ci	int irq;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
82762306a36Sopenharmony_ci	if (irq < 0)
82862306a36Sopenharmony_ci		return irq;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	return devm_request_irq(&pdev->dev, irq, intel_lgm_ssc_isr, 0, "spi", spi);
83162306a36Sopenharmony_ci}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_cistatic int lantiq_cfg_irq(struct platform_device *pdev, struct lantiq_ssc_spi *spi)
83462306a36Sopenharmony_ci{
83562306a36Sopenharmony_ci	int irq, err;
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	irq = platform_get_irq_byname(pdev, LTQ_SPI_RX_IRQ_NAME);
83862306a36Sopenharmony_ci	if (irq < 0)
83962306a36Sopenharmony_ci		return irq;
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	err = devm_request_irq(&pdev->dev, irq, lantiq_ssc_xmit_interrupt,
84262306a36Sopenharmony_ci			       0, LTQ_SPI_RX_IRQ_NAME, spi);
84362306a36Sopenharmony_ci	if (err)
84462306a36Sopenharmony_ci		return err;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	irq = platform_get_irq_byname(pdev, LTQ_SPI_TX_IRQ_NAME);
84762306a36Sopenharmony_ci	if (irq < 0)
84862306a36Sopenharmony_ci		return irq;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	err = devm_request_irq(&pdev->dev, irq, lantiq_ssc_xmit_interrupt,
85162306a36Sopenharmony_ci			       0, LTQ_SPI_TX_IRQ_NAME, spi);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	if (err)
85462306a36Sopenharmony_ci		return err;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	irq = platform_get_irq_byname(pdev, LTQ_SPI_ERR_IRQ_NAME);
85762306a36Sopenharmony_ci	if (irq < 0)
85862306a36Sopenharmony_ci		return irq;
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	err = devm_request_irq(&pdev->dev, irq, lantiq_ssc_err_interrupt,
86162306a36Sopenharmony_ci			       0, LTQ_SPI_ERR_IRQ_NAME, spi);
86262306a36Sopenharmony_ci	return err;
86362306a36Sopenharmony_ci}
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_cistatic const struct lantiq_ssc_hwcfg lantiq_ssc_xway = {
86662306a36Sopenharmony_ci	.cfg_irq	= lantiq_cfg_irq,
86762306a36Sopenharmony_ci	.irnen_r	= LTQ_SPI_IRNEN_R_XWAY,
86862306a36Sopenharmony_ci	.irnen_t	= LTQ_SPI_IRNEN_T_XWAY,
86962306a36Sopenharmony_ci	.irnicr		= 0xF8,
87062306a36Sopenharmony_ci	.irncr		= 0xFC,
87162306a36Sopenharmony_ci	.fifo_size_mask	= GENMASK(5, 0),
87262306a36Sopenharmony_ci	.irq_ack	= false,
87362306a36Sopenharmony_ci};
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_cistatic const struct lantiq_ssc_hwcfg lantiq_ssc_xrx = {
87662306a36Sopenharmony_ci	.cfg_irq	= lantiq_cfg_irq,
87762306a36Sopenharmony_ci	.irnen_r	= LTQ_SPI_IRNEN_R_XRX,
87862306a36Sopenharmony_ci	.irnen_t	= LTQ_SPI_IRNEN_T_XRX,
87962306a36Sopenharmony_ci	.irnicr		= 0xF8,
88062306a36Sopenharmony_ci	.irncr		= 0xFC,
88162306a36Sopenharmony_ci	.fifo_size_mask	= GENMASK(5, 0),
88262306a36Sopenharmony_ci	.irq_ack	= false,
88362306a36Sopenharmony_ci};
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_cistatic const struct lantiq_ssc_hwcfg intel_ssc_lgm = {
88662306a36Sopenharmony_ci	.cfg_irq	= intel_lgm_cfg_irq,
88762306a36Sopenharmony_ci	.irnen_r	= LTQ_SPI_IRNEN_R_XRX,
88862306a36Sopenharmony_ci	.irnen_t	= LTQ_SPI_IRNEN_T_XRX,
88962306a36Sopenharmony_ci	.irnicr		= 0xFC,
89062306a36Sopenharmony_ci	.irncr		= 0xF8,
89162306a36Sopenharmony_ci	.fifo_size_mask	= GENMASK(7, 0),
89262306a36Sopenharmony_ci	.irq_ack	= true,
89362306a36Sopenharmony_ci};
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_cistatic const struct of_device_id lantiq_ssc_match[] = {
89662306a36Sopenharmony_ci	{ .compatible = "lantiq,ase-spi", .data = &lantiq_ssc_xway, },
89762306a36Sopenharmony_ci	{ .compatible = "lantiq,falcon-spi", .data = &lantiq_ssc_xrx, },
89862306a36Sopenharmony_ci	{ .compatible = "lantiq,xrx100-spi", .data = &lantiq_ssc_xrx, },
89962306a36Sopenharmony_ci	{ .compatible = "intel,lgm-spi", .data = &intel_ssc_lgm, },
90062306a36Sopenharmony_ci	{},
90162306a36Sopenharmony_ci};
90262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, lantiq_ssc_match);
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_cistatic int lantiq_ssc_probe(struct platform_device *pdev)
90562306a36Sopenharmony_ci{
90662306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
90762306a36Sopenharmony_ci	struct spi_controller *host;
90862306a36Sopenharmony_ci	struct lantiq_ssc_spi *spi;
90962306a36Sopenharmony_ci	const struct lantiq_ssc_hwcfg *hwcfg;
91062306a36Sopenharmony_ci	u32 id, supports_dma, revision;
91162306a36Sopenharmony_ci	unsigned int num_cs;
91262306a36Sopenharmony_ci	int err;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	hwcfg = of_device_get_match_data(dev);
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	host = spi_alloc_host(dev, sizeof(struct lantiq_ssc_spi));
91762306a36Sopenharmony_ci	if (!host)
91862306a36Sopenharmony_ci		return -ENOMEM;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	spi = spi_controller_get_devdata(host);
92162306a36Sopenharmony_ci	spi->host = host;
92262306a36Sopenharmony_ci	spi->dev = dev;
92362306a36Sopenharmony_ci	spi->hwcfg = hwcfg;
92462306a36Sopenharmony_ci	platform_set_drvdata(pdev, spi);
92562306a36Sopenharmony_ci	spi->regbase = devm_platform_ioremap_resource(pdev, 0);
92662306a36Sopenharmony_ci	if (IS_ERR(spi->regbase)) {
92762306a36Sopenharmony_ci		err = PTR_ERR(spi->regbase);
92862306a36Sopenharmony_ci		goto err_host_put;
92962306a36Sopenharmony_ci	}
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	err = hwcfg->cfg_irq(pdev, spi);
93262306a36Sopenharmony_ci	if (err)
93362306a36Sopenharmony_ci		goto err_host_put;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	spi->spi_clk = devm_clk_get(dev, "gate");
93662306a36Sopenharmony_ci	if (IS_ERR(spi->spi_clk)) {
93762306a36Sopenharmony_ci		err = PTR_ERR(spi->spi_clk);
93862306a36Sopenharmony_ci		goto err_host_put;
93962306a36Sopenharmony_ci	}
94062306a36Sopenharmony_ci	err = clk_prepare_enable(spi->spi_clk);
94162306a36Sopenharmony_ci	if (err)
94262306a36Sopenharmony_ci		goto err_host_put;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci	/*
94562306a36Sopenharmony_ci	 * Use the old clk_get_fpi() function on Lantiq platform, till it
94662306a36Sopenharmony_ci	 * supports common clk.
94762306a36Sopenharmony_ci	 */
94862306a36Sopenharmony_ci#if defined(CONFIG_LANTIQ) && !defined(CONFIG_COMMON_CLK)
94962306a36Sopenharmony_ci	spi->fpi_clk = clk_get_fpi();
95062306a36Sopenharmony_ci#else
95162306a36Sopenharmony_ci	spi->fpi_clk = clk_get(dev, "freq");
95262306a36Sopenharmony_ci#endif
95362306a36Sopenharmony_ci	if (IS_ERR(spi->fpi_clk)) {
95462306a36Sopenharmony_ci		err = PTR_ERR(spi->fpi_clk);
95562306a36Sopenharmony_ci		goto err_clk_disable;
95662306a36Sopenharmony_ci	}
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	num_cs = 8;
95962306a36Sopenharmony_ci	of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs);
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	spi->base_cs = 1;
96262306a36Sopenharmony_ci	of_property_read_u32(pdev->dev.of_node, "base-cs", &spi->base_cs);
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	spin_lock_init(&spi->lock);
96562306a36Sopenharmony_ci	spi->bits_per_word = 8;
96662306a36Sopenharmony_ci	spi->speed_hz = 0;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	host->dev.of_node = pdev->dev.of_node;
96962306a36Sopenharmony_ci	host->num_chipselect = num_cs;
97062306a36Sopenharmony_ci	host->use_gpio_descriptors = true;
97162306a36Sopenharmony_ci	host->setup = lantiq_ssc_setup;
97262306a36Sopenharmony_ci	host->set_cs = lantiq_ssc_set_cs;
97362306a36Sopenharmony_ci	host->handle_err = lantiq_ssc_handle_err;
97462306a36Sopenharmony_ci	host->prepare_message = lantiq_ssc_prepare_message;
97562306a36Sopenharmony_ci	host->unprepare_message = lantiq_ssc_unprepare_message;
97662306a36Sopenharmony_ci	host->transfer_one = lantiq_ssc_transfer_one;
97762306a36Sopenharmony_ci	host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH |
97862306a36Sopenharmony_ci			  SPI_LOOP;
97962306a36Sopenharmony_ci	host->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 8) |
98062306a36Sopenharmony_ci				   SPI_BPW_MASK(16) | SPI_BPW_MASK(32);
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	spi->wq = alloc_ordered_workqueue(dev_name(dev), WQ_MEM_RECLAIM);
98362306a36Sopenharmony_ci	if (!spi->wq) {
98462306a36Sopenharmony_ci		err = -ENOMEM;
98562306a36Sopenharmony_ci		goto err_clk_put;
98662306a36Sopenharmony_ci	}
98762306a36Sopenharmony_ci	INIT_WORK(&spi->work, lantiq_ssc_bussy_work);
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	id = lantiq_ssc_readl(spi, LTQ_SPI_ID);
99062306a36Sopenharmony_ci	spi->tx_fifo_size = (id >> LTQ_SPI_ID_TXFS_S) & hwcfg->fifo_size_mask;
99162306a36Sopenharmony_ci	spi->rx_fifo_size = (id >> LTQ_SPI_ID_RXFS_S) & hwcfg->fifo_size_mask;
99262306a36Sopenharmony_ci	supports_dma = (id & LTQ_SPI_ID_CFG_M) >> LTQ_SPI_ID_CFG_S;
99362306a36Sopenharmony_ci	revision = id & LTQ_SPI_ID_REV_M;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	lantiq_ssc_hw_init(spi);
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	dev_info(dev,
99862306a36Sopenharmony_ci		"Lantiq SSC SPI controller (Rev %i, TXFS %u, RXFS %u, DMA %u)\n",
99962306a36Sopenharmony_ci		revision, spi->tx_fifo_size, spi->rx_fifo_size, supports_dma);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	err = devm_spi_register_controller(dev, host);
100262306a36Sopenharmony_ci	if (err) {
100362306a36Sopenharmony_ci		dev_err(dev, "failed to register spi host\n");
100462306a36Sopenharmony_ci		goto err_wq_destroy;
100562306a36Sopenharmony_ci	}
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	return 0;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_cierr_wq_destroy:
101062306a36Sopenharmony_ci	destroy_workqueue(spi->wq);
101162306a36Sopenharmony_cierr_clk_put:
101262306a36Sopenharmony_ci	clk_put(spi->fpi_clk);
101362306a36Sopenharmony_cierr_clk_disable:
101462306a36Sopenharmony_ci	clk_disable_unprepare(spi->spi_clk);
101562306a36Sopenharmony_cierr_host_put:
101662306a36Sopenharmony_ci	spi_controller_put(host);
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci	return err;
101962306a36Sopenharmony_ci}
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_cistatic void lantiq_ssc_remove(struct platform_device *pdev)
102262306a36Sopenharmony_ci{
102362306a36Sopenharmony_ci	struct lantiq_ssc_spi *spi = platform_get_drvdata(pdev);
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	lantiq_ssc_writel(spi, 0, LTQ_SPI_IRNEN);
102662306a36Sopenharmony_ci	lantiq_ssc_writel(spi, 0, LTQ_SPI_CLC);
102762306a36Sopenharmony_ci	rx_fifo_flush(spi);
102862306a36Sopenharmony_ci	tx_fifo_flush(spi);
102962306a36Sopenharmony_ci	hw_enter_config_mode(spi);
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	destroy_workqueue(spi->wq);
103262306a36Sopenharmony_ci	clk_disable_unprepare(spi->spi_clk);
103362306a36Sopenharmony_ci	clk_put(spi->fpi_clk);
103462306a36Sopenharmony_ci}
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_cistatic struct platform_driver lantiq_ssc_driver = {
103762306a36Sopenharmony_ci	.probe = lantiq_ssc_probe,
103862306a36Sopenharmony_ci	.remove_new = lantiq_ssc_remove,
103962306a36Sopenharmony_ci	.driver = {
104062306a36Sopenharmony_ci		.name = "spi-lantiq-ssc",
104162306a36Sopenharmony_ci		.of_match_table = lantiq_ssc_match,
104262306a36Sopenharmony_ci	},
104362306a36Sopenharmony_ci};
104462306a36Sopenharmony_cimodule_platform_driver(lantiq_ssc_driver);
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ciMODULE_DESCRIPTION("Lantiq SSC SPI controller driver");
104762306a36Sopenharmony_ciMODULE_AUTHOR("Daniel Schwierzeck <daniel.schwierzeck@gmail.com>");
104862306a36Sopenharmony_ciMODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
104962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
105062306a36Sopenharmony_ciMODULE_ALIAS("platform:spi-lantiq-ssc");
1051