17876981aSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
217f84b79SHauke Mehrtens /*
317f84b79SHauke Mehrtens * Copyright (C) 2011-2015 Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
417f84b79SHauke Mehrtens * Copyright (C) 2016 Hauke Mehrtens <hauke@hauke-m.de>
517f84b79SHauke Mehrtens */
617f84b79SHauke Mehrtens
717f84b79SHauke Mehrtens #include <linux/kernel.h>
817f84b79SHauke Mehrtens #include <linux/module.h>
9749396cbSRob Herring #include <linux/of.h>
10749396cbSRob Herring #include <linux/platform_device.h>
1117f84b79SHauke Mehrtens #include <linux/clk.h>
1217f84b79SHauke Mehrtens #include <linux/io.h>
1317f84b79SHauke Mehrtens #include <linux/delay.h>
1417f84b79SHauke Mehrtens #include <linux/interrupt.h>
1517f84b79SHauke Mehrtens #include <linux/sched.h>
1617f84b79SHauke Mehrtens #include <linux/completion.h>
1717f84b79SHauke Mehrtens #include <linux/spinlock.h>
1817f84b79SHauke Mehrtens #include <linux/err.h>
1917f84b79SHauke Mehrtens #include <linux/pm_runtime.h>
2017f84b79SHauke Mehrtens #include <linux/spi/spi.h>
2117f84b79SHauke Mehrtens
2217f84b79SHauke Mehrtens #ifdef CONFIG_LANTIQ
2317f84b79SHauke Mehrtens #include <lantiq_soc.h>
2417f84b79SHauke Mehrtens #endif
2517f84b79SHauke Mehrtens
26ad2fca07SHauke Mehrtens #define LTQ_SPI_RX_IRQ_NAME "spi_rx"
27ad2fca07SHauke Mehrtens #define LTQ_SPI_TX_IRQ_NAME "spi_tx"
28ad2fca07SHauke Mehrtens #define LTQ_SPI_ERR_IRQ_NAME "spi_err"
29ad2fca07SHauke Mehrtens #define LTQ_SPI_FRM_IRQ_NAME "spi_frm"
3017f84b79SHauke Mehrtens
31ad2fca07SHauke Mehrtens #define LTQ_SPI_CLC 0x00
32ad2fca07SHauke Mehrtens #define LTQ_SPI_PISEL 0x04
33ad2fca07SHauke Mehrtens #define LTQ_SPI_ID 0x08
34ad2fca07SHauke Mehrtens #define LTQ_SPI_CON 0x10
35ad2fca07SHauke Mehrtens #define LTQ_SPI_STAT 0x14
36ad2fca07SHauke Mehrtens #define LTQ_SPI_WHBSTATE 0x18
37ad2fca07SHauke Mehrtens #define LTQ_SPI_TB 0x20
38ad2fca07SHauke Mehrtens #define LTQ_SPI_RB 0x24
39ad2fca07SHauke Mehrtens #define LTQ_SPI_RXFCON 0x30
40ad2fca07SHauke Mehrtens #define LTQ_SPI_TXFCON 0x34
41ad2fca07SHauke Mehrtens #define LTQ_SPI_FSTAT 0x38
42ad2fca07SHauke Mehrtens #define LTQ_SPI_BRT 0x40
43ad2fca07SHauke Mehrtens #define LTQ_SPI_BRSTAT 0x44
44ad2fca07SHauke Mehrtens #define LTQ_SPI_SFCON 0x60
45ad2fca07SHauke Mehrtens #define LTQ_SPI_SFSTAT 0x64
46ad2fca07SHauke Mehrtens #define LTQ_SPI_GPOCON 0x70
47ad2fca07SHauke Mehrtens #define LTQ_SPI_GPOSTAT 0x74
48ad2fca07SHauke Mehrtens #define LTQ_SPI_FPGO 0x78
49ad2fca07SHauke Mehrtens #define LTQ_SPI_RXREQ 0x80
50ad2fca07SHauke Mehrtens #define LTQ_SPI_RXCNT 0x84
51ad2fca07SHauke Mehrtens #define LTQ_SPI_DMACON 0xec
52ad2fca07SHauke Mehrtens #define LTQ_SPI_IRNEN 0xf4
5317f84b79SHauke Mehrtens
54ad2fca07SHauke Mehrtens #define LTQ_SPI_CLC_SMC_S 16 /* Clock divider for sleep mode */
55ad2fca07SHauke Mehrtens #define LTQ_SPI_CLC_SMC_M (0xFF << LTQ_SPI_CLC_SMC_S)
56ad2fca07SHauke Mehrtens #define LTQ_SPI_CLC_RMC_S 8 /* Clock divider for normal run mode */
57ad2fca07SHauke Mehrtens #define LTQ_SPI_CLC_RMC_M (0xFF << LTQ_SPI_CLC_RMC_S)
58ad2fca07SHauke Mehrtens #define LTQ_SPI_CLC_DISS BIT(1) /* Disable status bit */
59ad2fca07SHauke Mehrtens #define LTQ_SPI_CLC_DISR BIT(0) /* Disable request bit */
6017f84b79SHauke Mehrtens
61ad2fca07SHauke Mehrtens #define LTQ_SPI_ID_TXFS_S 24 /* Implemented TX FIFO size */
62ad2fca07SHauke Mehrtens #define LTQ_SPI_ID_RXFS_S 16 /* Implemented RX FIFO size */
63ad2fca07SHauke Mehrtens #define LTQ_SPI_ID_MOD_S 8 /* Module ID */
64ad2fca07SHauke Mehrtens #define LTQ_SPI_ID_MOD_M (0xff << LTQ_SPI_ID_MOD_S)
65ad2fca07SHauke Mehrtens #define LTQ_SPI_ID_CFG_S 5 /* DMA interface support */
66ad2fca07SHauke Mehrtens #define LTQ_SPI_ID_CFG_M (1 << LTQ_SPI_ID_CFG_S)
67ad2fca07SHauke Mehrtens #define LTQ_SPI_ID_REV_M 0x1F /* Hardware revision number */
6817f84b79SHauke Mehrtens
69ad2fca07SHauke Mehrtens #define LTQ_SPI_CON_BM_S 16 /* Data width selection */
70ad2fca07SHauke Mehrtens #define LTQ_SPI_CON_BM_M (0x1F << LTQ_SPI_CON_BM_S)
71ad2fca07SHauke Mehrtens #define LTQ_SPI_CON_EM BIT(24) /* Echo mode */
72ad2fca07SHauke Mehrtens #define LTQ_SPI_CON_IDLE BIT(23) /* Idle bit value */
73ad2fca07SHauke Mehrtens #define LTQ_SPI_CON_ENBV BIT(22) /* Enable byte valid control */
74ad2fca07SHauke Mehrtens #define LTQ_SPI_CON_RUEN BIT(12) /* Receive underflow error enable */
75ad2fca07SHauke Mehrtens #define LTQ_SPI_CON_TUEN BIT(11) /* Transmit underflow error enable */
76ad2fca07SHauke Mehrtens #define LTQ_SPI_CON_AEN BIT(10) /* Abort error enable */
77ad2fca07SHauke Mehrtens #define LTQ_SPI_CON_REN BIT(9) /* Receive overflow error enable */
78ad2fca07SHauke Mehrtens #define LTQ_SPI_CON_TEN BIT(8) /* Transmit overflow error enable */
79ad2fca07SHauke Mehrtens #define LTQ_SPI_CON_LB BIT(7) /* Loopback control */
80ad2fca07SHauke Mehrtens #define LTQ_SPI_CON_PO BIT(6) /* Clock polarity control */
81ad2fca07SHauke Mehrtens #define LTQ_SPI_CON_PH BIT(5) /* Clock phase control */
82ad2fca07SHauke Mehrtens #define LTQ_SPI_CON_HB BIT(4) /* Heading control */
83ad2fca07SHauke Mehrtens #define LTQ_SPI_CON_RXOFF BIT(1) /* Switch receiver off */
84ad2fca07SHauke Mehrtens #define LTQ_SPI_CON_TXOFF BIT(0) /* Switch transmitter off */
8517f84b79SHauke Mehrtens
86ad2fca07SHauke Mehrtens #define LTQ_SPI_STAT_RXBV_S 28
87ad2fca07SHauke Mehrtens #define LTQ_SPI_STAT_RXBV_M (0x7 << LTQ_SPI_STAT_RXBV_S)
88ad2fca07SHauke Mehrtens #define LTQ_SPI_STAT_BSY BIT(13) /* Busy flag */
89ad2fca07SHauke Mehrtens #define LTQ_SPI_STAT_RUE BIT(12) /* Receive underflow error flag */
90ad2fca07SHauke Mehrtens #define LTQ_SPI_STAT_TUE BIT(11) /* Transmit underflow error flag */
91ad2fca07SHauke Mehrtens #define LTQ_SPI_STAT_AE BIT(10) /* Abort error flag */
92ad2fca07SHauke Mehrtens #define LTQ_SPI_STAT_RE BIT(9) /* Receive error flag */
93ad2fca07SHauke Mehrtens #define LTQ_SPI_STAT_TE BIT(8) /* Transmit error flag */
94ad2fca07SHauke Mehrtens #define LTQ_SPI_STAT_ME BIT(7) /* Mode error flag */
95*ea11a8bbSYang Yingliang #define LTQ_SPI_STAT_MS BIT(1) /* Host/target select bit */
96ad2fca07SHauke Mehrtens #define LTQ_SPI_STAT_EN BIT(0) /* Enable bit */
97ad2fca07SHauke Mehrtens #define LTQ_SPI_STAT_ERRORS (LTQ_SPI_STAT_ME | LTQ_SPI_STAT_TE | \
98ad2fca07SHauke Mehrtens LTQ_SPI_STAT_RE | LTQ_SPI_STAT_AE | \
99ad2fca07SHauke Mehrtens LTQ_SPI_STAT_TUE | LTQ_SPI_STAT_RUE)
10017f84b79SHauke Mehrtens
101ad2fca07SHauke Mehrtens #define LTQ_SPI_WHBSTATE_SETTUE BIT(15) /* Set transmit underflow error flag */
102ad2fca07SHauke Mehrtens #define LTQ_SPI_WHBSTATE_SETAE BIT(14) /* Set abort error flag */
103ad2fca07SHauke Mehrtens #define LTQ_SPI_WHBSTATE_SETRE BIT(13) /* Set receive error flag */
104ad2fca07SHauke Mehrtens #define LTQ_SPI_WHBSTATE_SETTE BIT(12) /* Set transmit error flag */
105ad2fca07SHauke Mehrtens #define LTQ_SPI_WHBSTATE_CLRTUE BIT(11) /* Clear transmit underflow error flag */
106ad2fca07SHauke Mehrtens #define LTQ_SPI_WHBSTATE_CLRAE BIT(10) /* Clear abort error flag */
107ad2fca07SHauke Mehrtens #define LTQ_SPI_WHBSTATE_CLRRE BIT(9) /* Clear receive error flag */
108ad2fca07SHauke Mehrtens #define LTQ_SPI_WHBSTATE_CLRTE BIT(8) /* Clear transmit error flag */
109ad2fca07SHauke Mehrtens #define LTQ_SPI_WHBSTATE_SETME BIT(7) /* Set mode error flag */
110ad2fca07SHauke Mehrtens #define LTQ_SPI_WHBSTATE_CLRME BIT(6) /* Clear mode error flag */
111ad2fca07SHauke Mehrtens #define LTQ_SPI_WHBSTATE_SETRUE BIT(5) /* Set receive underflow error flag */
112ad2fca07SHauke Mehrtens #define LTQ_SPI_WHBSTATE_CLRRUE BIT(4) /* Clear receive underflow error flag */
113*ea11a8bbSYang Yingliang #define LTQ_SPI_WHBSTATE_SETMS BIT(3) /* Set host select bit */
114*ea11a8bbSYang Yingliang #define LTQ_SPI_WHBSTATE_CLRMS BIT(2) /* Clear host select bit */
115ad2fca07SHauke Mehrtens #define LTQ_SPI_WHBSTATE_SETEN BIT(1) /* Set enable bit (operational mode) */
116ad2fca07SHauke Mehrtens #define LTQ_SPI_WHBSTATE_CLREN BIT(0) /* Clear enable bit (config mode */
117ad2fca07SHauke Mehrtens #define LTQ_SPI_WHBSTATE_CLR_ERRORS (LTQ_SPI_WHBSTATE_CLRRUE | \
118ad2fca07SHauke Mehrtens LTQ_SPI_WHBSTATE_CLRME | \
119ad2fca07SHauke Mehrtens LTQ_SPI_WHBSTATE_CLRTE | \
120ad2fca07SHauke Mehrtens LTQ_SPI_WHBSTATE_CLRRE | \
121ad2fca07SHauke Mehrtens LTQ_SPI_WHBSTATE_CLRAE | \
122ad2fca07SHauke Mehrtens LTQ_SPI_WHBSTATE_CLRTUE)
12317f84b79SHauke Mehrtens
124ad2fca07SHauke Mehrtens #define LTQ_SPI_RXFCON_RXFITL_S 8 /* FIFO interrupt trigger level */
125ad2fca07SHauke Mehrtens #define LTQ_SPI_RXFCON_RXFLU BIT(1) /* FIFO flush */
126ad2fca07SHauke Mehrtens #define LTQ_SPI_RXFCON_RXFEN BIT(0) /* FIFO enable */
12717f84b79SHauke Mehrtens
128ad2fca07SHauke Mehrtens #define LTQ_SPI_TXFCON_TXFITL_S 8 /* FIFO interrupt trigger level */
129ad2fca07SHauke Mehrtens #define LTQ_SPI_TXFCON_TXFLU BIT(1) /* FIFO flush */
130ad2fca07SHauke Mehrtens #define LTQ_SPI_TXFCON_TXFEN BIT(0) /* FIFO enable */
13117f84b79SHauke Mehrtens
132ad2fca07SHauke Mehrtens #define LTQ_SPI_FSTAT_RXFFL_S 0
133ad2fca07SHauke Mehrtens #define LTQ_SPI_FSTAT_TXFFL_S 8
13417f84b79SHauke Mehrtens
135ad2fca07SHauke Mehrtens #define LTQ_SPI_GPOCON_ISCSBN_S 8
136ad2fca07SHauke Mehrtens #define LTQ_SPI_GPOCON_INVOUTN_S 0
13717f84b79SHauke Mehrtens
138ad2fca07SHauke Mehrtens #define LTQ_SPI_FGPO_SETOUTN_S 8
139ad2fca07SHauke Mehrtens #define LTQ_SPI_FGPO_CLROUTN_S 0
14017f84b79SHauke Mehrtens
141ad2fca07SHauke Mehrtens #define LTQ_SPI_RXREQ_RXCNT_M 0xFFFF /* Receive count value */
142ad2fca07SHauke Mehrtens #define LTQ_SPI_RXCNT_TODO_M 0xFFFF /* Recevie to-do value */
14317f84b79SHauke Mehrtens
144ad2fca07SHauke Mehrtens #define LTQ_SPI_IRNEN_TFI BIT(4) /* TX finished interrupt */
145ad2fca07SHauke Mehrtens #define LTQ_SPI_IRNEN_F BIT(3) /* Frame end interrupt request */
146ad2fca07SHauke Mehrtens #define LTQ_SPI_IRNEN_E BIT(2) /* Error end interrupt request */
147ad2fca07SHauke Mehrtens #define LTQ_SPI_IRNEN_T_XWAY BIT(1) /* Transmit end interrupt request */
148ad2fca07SHauke Mehrtens #define LTQ_SPI_IRNEN_R_XWAY BIT(0) /* Receive end interrupt request */
149ad2fca07SHauke Mehrtens #define LTQ_SPI_IRNEN_R_XRX BIT(1) /* Transmit end interrupt request */
150ad2fca07SHauke Mehrtens #define LTQ_SPI_IRNEN_T_XRX BIT(0) /* Receive end interrupt request */
151ad2fca07SHauke Mehrtens #define LTQ_SPI_IRNEN_ALL 0x1F
15217f84b79SHauke Mehrtens
153744cd0f2SDilip Kota struct lantiq_ssc_spi;
154744cd0f2SDilip Kota
15517f84b79SHauke Mehrtens struct lantiq_ssc_hwcfg {
156744cd0f2SDilip Kota int (*cfg_irq)(struct platform_device *pdev, struct lantiq_ssc_spi *spi);
15717f84b79SHauke Mehrtens unsigned int irnen_r;
15817f84b79SHauke Mehrtens unsigned int irnen_t;
1598d19d665SDilip Kota unsigned int irncr;
1608d19d665SDilip Kota unsigned int irnicr;
16194eca904SDilip Kota bool irq_ack;
1628743d215SDilip Kota u32 fifo_size_mask;
16317f84b79SHauke Mehrtens };
16417f84b79SHauke Mehrtens
16517f84b79SHauke Mehrtens struct lantiq_ssc_spi {
166*ea11a8bbSYang Yingliang struct spi_controller *host;
16717f84b79SHauke Mehrtens struct device *dev;
16817f84b79SHauke Mehrtens void __iomem *regbase;
16917f84b79SHauke Mehrtens struct clk *spi_clk;
17017f84b79SHauke Mehrtens struct clk *fpi_clk;
17117f84b79SHauke Mehrtens const struct lantiq_ssc_hwcfg *hwcfg;
17217f84b79SHauke Mehrtens
17317f84b79SHauke Mehrtens spinlock_t lock;
17417f84b79SHauke Mehrtens struct workqueue_struct *wq;
17517f84b79SHauke Mehrtens struct work_struct work;
17617f84b79SHauke Mehrtens
17717f84b79SHauke Mehrtens const u8 *tx;
17817f84b79SHauke Mehrtens u8 *rx;
17917f84b79SHauke Mehrtens unsigned int tx_todo;
18017f84b79SHauke Mehrtens unsigned int rx_todo;
18117f84b79SHauke Mehrtens unsigned int bits_per_word;
18217f84b79SHauke Mehrtens unsigned int speed_hz;
18317f84b79SHauke Mehrtens unsigned int tx_fifo_size;
18417f84b79SHauke Mehrtens unsigned int rx_fifo_size;
18517f84b79SHauke Mehrtens unsigned int base_cs;
186661ccf2bSDilip Kota unsigned int fdx_tx_level;
18717f84b79SHauke Mehrtens };
18817f84b79SHauke Mehrtens
lantiq_ssc_readl(const struct lantiq_ssc_spi * spi,u32 reg)18917f84b79SHauke Mehrtens static u32 lantiq_ssc_readl(const struct lantiq_ssc_spi *spi, u32 reg)
19017f84b79SHauke Mehrtens {
19117f84b79SHauke Mehrtens return __raw_readl(spi->regbase + reg);
19217f84b79SHauke Mehrtens }
19317f84b79SHauke Mehrtens
lantiq_ssc_writel(const struct lantiq_ssc_spi * spi,u32 val,u32 reg)19417f84b79SHauke Mehrtens static void lantiq_ssc_writel(const struct lantiq_ssc_spi *spi, u32 val,
19517f84b79SHauke Mehrtens u32 reg)
19617f84b79SHauke Mehrtens {
19717f84b79SHauke Mehrtens __raw_writel(val, spi->regbase + reg);
19817f84b79SHauke Mehrtens }
19917f84b79SHauke Mehrtens
lantiq_ssc_maskl(const struct lantiq_ssc_spi * spi,u32 clr,u32 set,u32 reg)20017f84b79SHauke Mehrtens static void lantiq_ssc_maskl(const struct lantiq_ssc_spi *spi, u32 clr,
20117f84b79SHauke Mehrtens u32 set, u32 reg)
20217f84b79SHauke Mehrtens {
20317f84b79SHauke Mehrtens u32 val = __raw_readl(spi->regbase + reg);
20417f84b79SHauke Mehrtens
20517f84b79SHauke Mehrtens val &= ~clr;
20617f84b79SHauke Mehrtens val |= set;
20717f84b79SHauke Mehrtens __raw_writel(val, spi->regbase + reg);
20817f84b79SHauke Mehrtens }
20917f84b79SHauke Mehrtens
tx_fifo_level(const struct lantiq_ssc_spi * spi)21017f84b79SHauke Mehrtens static unsigned int tx_fifo_level(const struct lantiq_ssc_spi *spi)
21117f84b79SHauke Mehrtens {
2128743d215SDilip Kota const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg;
213ad2fca07SHauke Mehrtens u32 fstat = lantiq_ssc_readl(spi, LTQ_SPI_FSTAT);
21417f84b79SHauke Mehrtens
2158743d215SDilip Kota return (fstat >> LTQ_SPI_FSTAT_TXFFL_S) & hwcfg->fifo_size_mask;
21617f84b79SHauke Mehrtens }
21717f84b79SHauke Mehrtens
rx_fifo_level(const struct lantiq_ssc_spi * spi)21817f84b79SHauke Mehrtens static unsigned int rx_fifo_level(const struct lantiq_ssc_spi *spi)
21917f84b79SHauke Mehrtens {
2208743d215SDilip Kota const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg;
221ad2fca07SHauke Mehrtens u32 fstat = lantiq_ssc_readl(spi, LTQ_SPI_FSTAT);
22217f84b79SHauke Mehrtens
2238743d215SDilip Kota return (fstat >> LTQ_SPI_FSTAT_RXFFL_S) & hwcfg->fifo_size_mask;
22417f84b79SHauke Mehrtens }
22517f84b79SHauke Mehrtens
tx_fifo_free(const struct lantiq_ssc_spi * spi)22617f84b79SHauke Mehrtens static unsigned int tx_fifo_free(const struct lantiq_ssc_spi *spi)
22717f84b79SHauke Mehrtens {
22817f84b79SHauke Mehrtens return spi->tx_fifo_size - tx_fifo_level(spi);
22917f84b79SHauke Mehrtens }
23017f84b79SHauke Mehrtens
rx_fifo_reset(const struct lantiq_ssc_spi * spi)23117f84b79SHauke Mehrtens static void rx_fifo_reset(const struct lantiq_ssc_spi *spi)
23217f84b79SHauke Mehrtens {
233ad2fca07SHauke Mehrtens u32 val = spi->rx_fifo_size << LTQ_SPI_RXFCON_RXFITL_S;
23417f84b79SHauke Mehrtens
235ad2fca07SHauke Mehrtens val |= LTQ_SPI_RXFCON_RXFEN | LTQ_SPI_RXFCON_RXFLU;
236ad2fca07SHauke Mehrtens lantiq_ssc_writel(spi, val, LTQ_SPI_RXFCON);
23717f84b79SHauke Mehrtens }
23817f84b79SHauke Mehrtens
tx_fifo_reset(const struct lantiq_ssc_spi * spi)23917f84b79SHauke Mehrtens static void tx_fifo_reset(const struct lantiq_ssc_spi *spi)
24017f84b79SHauke Mehrtens {
241ad2fca07SHauke Mehrtens u32 val = 1 << LTQ_SPI_TXFCON_TXFITL_S;
24217f84b79SHauke Mehrtens
243ad2fca07SHauke Mehrtens val |= LTQ_SPI_TXFCON_TXFEN | LTQ_SPI_TXFCON_TXFLU;
244ad2fca07SHauke Mehrtens lantiq_ssc_writel(spi, val, LTQ_SPI_TXFCON);
24517f84b79SHauke Mehrtens }
24617f84b79SHauke Mehrtens
rx_fifo_flush(const struct lantiq_ssc_spi * spi)24717f84b79SHauke Mehrtens static void rx_fifo_flush(const struct lantiq_ssc_spi *spi)
24817f84b79SHauke Mehrtens {
249ad2fca07SHauke Mehrtens lantiq_ssc_maskl(spi, 0, LTQ_SPI_RXFCON_RXFLU, LTQ_SPI_RXFCON);
25017f84b79SHauke Mehrtens }
25117f84b79SHauke Mehrtens
tx_fifo_flush(const struct lantiq_ssc_spi * spi)25217f84b79SHauke Mehrtens static void tx_fifo_flush(const struct lantiq_ssc_spi *spi)
25317f84b79SHauke Mehrtens {
254ad2fca07SHauke Mehrtens lantiq_ssc_maskl(spi, 0, LTQ_SPI_TXFCON_TXFLU, LTQ_SPI_TXFCON);
25517f84b79SHauke Mehrtens }
25617f84b79SHauke Mehrtens
hw_enter_config_mode(const struct lantiq_ssc_spi * spi)25717f84b79SHauke Mehrtens static void hw_enter_config_mode(const struct lantiq_ssc_spi *spi)
25817f84b79SHauke Mehrtens {
259ad2fca07SHauke Mehrtens lantiq_ssc_writel(spi, LTQ_SPI_WHBSTATE_CLREN, LTQ_SPI_WHBSTATE);
26017f84b79SHauke Mehrtens }
26117f84b79SHauke Mehrtens
hw_enter_active_mode(const struct lantiq_ssc_spi * spi)26217f84b79SHauke Mehrtens static void hw_enter_active_mode(const struct lantiq_ssc_spi *spi)
26317f84b79SHauke Mehrtens {
264ad2fca07SHauke Mehrtens lantiq_ssc_writel(spi, LTQ_SPI_WHBSTATE_SETEN, LTQ_SPI_WHBSTATE);
26517f84b79SHauke Mehrtens }
26617f84b79SHauke Mehrtens
hw_setup_speed_hz(const struct lantiq_ssc_spi * spi,unsigned int max_speed_hz)26717f84b79SHauke Mehrtens static void hw_setup_speed_hz(const struct lantiq_ssc_spi *spi,
26817f84b79SHauke Mehrtens unsigned int max_speed_hz)
26917f84b79SHauke Mehrtens {
27017f84b79SHauke Mehrtens u32 spi_clk, brt;
27117f84b79SHauke Mehrtens
27217f84b79SHauke Mehrtens /*
27317f84b79SHauke Mehrtens * SPI module clock is derived from FPI bus clock dependent on
27417f84b79SHauke Mehrtens * divider value in CLC.RMS which is always set to 1.
27517f84b79SHauke Mehrtens *
27617f84b79SHauke Mehrtens * f_SPI
27717f84b79SHauke Mehrtens * baudrate = --------------
27817f84b79SHauke Mehrtens * 2 * (BR + 1)
27917f84b79SHauke Mehrtens */
28017f84b79SHauke Mehrtens spi_clk = clk_get_rate(spi->fpi_clk) / 2;
28117f84b79SHauke Mehrtens
28217f84b79SHauke Mehrtens if (max_speed_hz > spi_clk)
28317f84b79SHauke Mehrtens brt = 0;
28417f84b79SHauke Mehrtens else
28517f84b79SHauke Mehrtens brt = spi_clk / max_speed_hz - 1;
28617f84b79SHauke Mehrtens
28717f84b79SHauke Mehrtens if (brt > 0xFFFF)
28817f84b79SHauke Mehrtens brt = 0xFFFF;
28917f84b79SHauke Mehrtens
29017f84b79SHauke Mehrtens dev_dbg(spi->dev, "spi_clk %u, max_speed_hz %u, brt %u\n",
29117f84b79SHauke Mehrtens spi_clk, max_speed_hz, brt);
29217f84b79SHauke Mehrtens
293ad2fca07SHauke Mehrtens lantiq_ssc_writel(spi, brt, LTQ_SPI_BRT);
29417f84b79SHauke Mehrtens }
29517f84b79SHauke Mehrtens
hw_setup_bits_per_word(const struct lantiq_ssc_spi * spi,unsigned int bits_per_word)29617f84b79SHauke Mehrtens static void hw_setup_bits_per_word(const struct lantiq_ssc_spi *spi,
29717f84b79SHauke Mehrtens unsigned int bits_per_word)
29817f84b79SHauke Mehrtens {
29917f84b79SHauke Mehrtens u32 bm;
30017f84b79SHauke Mehrtens
30117f84b79SHauke Mehrtens /* CON.BM value = bits_per_word - 1 */
302ad2fca07SHauke Mehrtens bm = (bits_per_word - 1) << LTQ_SPI_CON_BM_S;
30317f84b79SHauke Mehrtens
304ad2fca07SHauke Mehrtens lantiq_ssc_maskl(spi, LTQ_SPI_CON_BM_M, bm, LTQ_SPI_CON);
30517f84b79SHauke Mehrtens }
30617f84b79SHauke Mehrtens
hw_setup_clock_mode(const struct lantiq_ssc_spi * spi,unsigned int mode)30717f84b79SHauke Mehrtens static void hw_setup_clock_mode(const struct lantiq_ssc_spi *spi,
30817f84b79SHauke Mehrtens unsigned int mode)
30917f84b79SHauke Mehrtens {
31017f84b79SHauke Mehrtens u32 con_set = 0, con_clr = 0;
31117f84b79SHauke Mehrtens
31217f84b79SHauke Mehrtens /*
31317f84b79SHauke Mehrtens * SPI mode mapping in CON register:
31417f84b79SHauke Mehrtens * Mode CPOL CPHA CON.PO CON.PH
31517f84b79SHauke Mehrtens * 0 0 0 0 1
31617f84b79SHauke Mehrtens * 1 0 1 0 0
31717f84b79SHauke Mehrtens * 2 1 0 1 1
31817f84b79SHauke Mehrtens * 3 1 1 1 0
31917f84b79SHauke Mehrtens */
32017f84b79SHauke Mehrtens if (mode & SPI_CPHA)
321ad2fca07SHauke Mehrtens con_clr |= LTQ_SPI_CON_PH;
32217f84b79SHauke Mehrtens else
323ad2fca07SHauke Mehrtens con_set |= LTQ_SPI_CON_PH;
32417f84b79SHauke Mehrtens
32517f84b79SHauke Mehrtens if (mode & SPI_CPOL)
326ad2fca07SHauke Mehrtens con_set |= LTQ_SPI_CON_PO | LTQ_SPI_CON_IDLE;
32717f84b79SHauke Mehrtens else
328ad2fca07SHauke Mehrtens con_clr |= LTQ_SPI_CON_PO | LTQ_SPI_CON_IDLE;
32917f84b79SHauke Mehrtens
33017f84b79SHauke Mehrtens /* Set heading control */
33117f84b79SHauke Mehrtens if (mode & SPI_LSB_FIRST)
332ad2fca07SHauke Mehrtens con_clr |= LTQ_SPI_CON_HB;
33317f84b79SHauke Mehrtens else
334ad2fca07SHauke Mehrtens con_set |= LTQ_SPI_CON_HB;
33517f84b79SHauke Mehrtens
33617f84b79SHauke Mehrtens /* Set loopback mode */
33717f84b79SHauke Mehrtens if (mode & SPI_LOOP)
338ad2fca07SHauke Mehrtens con_set |= LTQ_SPI_CON_LB;
33917f84b79SHauke Mehrtens else
340ad2fca07SHauke Mehrtens con_clr |= LTQ_SPI_CON_LB;
34117f84b79SHauke Mehrtens
342ad2fca07SHauke Mehrtens lantiq_ssc_maskl(spi, con_clr, con_set, LTQ_SPI_CON);
34317f84b79SHauke Mehrtens }
34417f84b79SHauke Mehrtens
lantiq_ssc_hw_init(const struct lantiq_ssc_spi * spi)34517f84b79SHauke Mehrtens static void lantiq_ssc_hw_init(const struct lantiq_ssc_spi *spi)
34617f84b79SHauke Mehrtens {
34717f84b79SHauke Mehrtens const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg;
34817f84b79SHauke Mehrtens
34917f84b79SHauke Mehrtens /*
35017f84b79SHauke Mehrtens * Set clock divider for run mode to 1 to
35117f84b79SHauke Mehrtens * run at same frequency as FPI bus
35217f84b79SHauke Mehrtens */
353ad2fca07SHauke Mehrtens lantiq_ssc_writel(spi, 1 << LTQ_SPI_CLC_RMC_S, LTQ_SPI_CLC);
35417f84b79SHauke Mehrtens
35517f84b79SHauke Mehrtens /* Put controller into config mode */
35617f84b79SHauke Mehrtens hw_enter_config_mode(spi);
35717f84b79SHauke Mehrtens
35817f84b79SHauke Mehrtens /* Clear error flags */
359ad2fca07SHauke Mehrtens lantiq_ssc_maskl(spi, 0, LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE);
36017f84b79SHauke Mehrtens
36117f84b79SHauke Mehrtens /* Enable error checking, disable TX/RX */
362ad2fca07SHauke Mehrtens lantiq_ssc_writel(spi, LTQ_SPI_CON_RUEN | LTQ_SPI_CON_AEN |
363ad2fca07SHauke Mehrtens LTQ_SPI_CON_TEN | LTQ_SPI_CON_REN | LTQ_SPI_CON_TXOFF |
364ad2fca07SHauke Mehrtens LTQ_SPI_CON_RXOFF, LTQ_SPI_CON);
36517f84b79SHauke Mehrtens
36617f84b79SHauke Mehrtens /* Setup default SPI mode */
36717f84b79SHauke Mehrtens hw_setup_bits_per_word(spi, spi->bits_per_word);
36817f84b79SHauke Mehrtens hw_setup_clock_mode(spi, SPI_MODE_0);
36917f84b79SHauke Mehrtens
370*ea11a8bbSYang Yingliang /* Enable host mode and clear error flags */
371ad2fca07SHauke Mehrtens lantiq_ssc_writel(spi, LTQ_SPI_WHBSTATE_SETMS |
372ad2fca07SHauke Mehrtens LTQ_SPI_WHBSTATE_CLR_ERRORS,
373ad2fca07SHauke Mehrtens LTQ_SPI_WHBSTATE);
37417f84b79SHauke Mehrtens
37517f84b79SHauke Mehrtens /* Reset GPIO/CS registers */
376ad2fca07SHauke Mehrtens lantiq_ssc_writel(spi, 0, LTQ_SPI_GPOCON);
377ad2fca07SHauke Mehrtens lantiq_ssc_writel(spi, 0xFF00, LTQ_SPI_FPGO);
37817f84b79SHauke Mehrtens
37917f84b79SHauke Mehrtens /* Enable and flush FIFOs */
38017f84b79SHauke Mehrtens rx_fifo_reset(spi);
38117f84b79SHauke Mehrtens tx_fifo_reset(spi);
38217f84b79SHauke Mehrtens
38317f84b79SHauke Mehrtens /* Enable interrupts */
384ad2fca07SHauke Mehrtens lantiq_ssc_writel(spi, hwcfg->irnen_t | hwcfg->irnen_r |
385ad2fca07SHauke Mehrtens LTQ_SPI_IRNEN_E, LTQ_SPI_IRNEN);
38617f84b79SHauke Mehrtens }
38717f84b79SHauke Mehrtens
lantiq_ssc_setup(struct spi_device * spidev)38817f84b79SHauke Mehrtens static int lantiq_ssc_setup(struct spi_device *spidev)
38917f84b79SHauke Mehrtens {
390*ea11a8bbSYang Yingliang struct spi_controller *host = spidev->controller;
391*ea11a8bbSYang Yingliang struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host);
3929e264f3fSAmit Kumar Mahapatra via Alsa-devel unsigned int cs = spi_get_chipselect(spidev, 0);
39317f84b79SHauke Mehrtens u32 gpocon;
39417f84b79SHauke Mehrtens
39517f84b79SHauke Mehrtens /* GPIOs are used for CS */
3969e264f3fSAmit Kumar Mahapatra via Alsa-devel if (spi_get_csgpiod(spidev, 0))
39717f84b79SHauke Mehrtens return 0;
39817f84b79SHauke Mehrtens
39917f84b79SHauke Mehrtens dev_dbg(spi->dev, "using internal chipselect %u\n", cs);
40017f84b79SHauke Mehrtens
40117f84b79SHauke Mehrtens if (cs < spi->base_cs) {
40217f84b79SHauke Mehrtens dev_err(spi->dev,
40317f84b79SHauke Mehrtens "chipselect %i too small (min %i)\n", cs, spi->base_cs);
40417f84b79SHauke Mehrtens return -EINVAL;
40517f84b79SHauke Mehrtens }
40617f84b79SHauke Mehrtens
40717f84b79SHauke Mehrtens /* set GPO pin to CS mode */
408ad2fca07SHauke Mehrtens gpocon = 1 << ((cs - spi->base_cs) + LTQ_SPI_GPOCON_ISCSBN_S);
40917f84b79SHauke Mehrtens
41017f84b79SHauke Mehrtens /* invert GPO pin */
41117f84b79SHauke Mehrtens if (spidev->mode & SPI_CS_HIGH)
41217f84b79SHauke Mehrtens gpocon |= 1 << (cs - spi->base_cs);
41317f84b79SHauke Mehrtens
414ad2fca07SHauke Mehrtens lantiq_ssc_maskl(spi, 0, gpocon, LTQ_SPI_GPOCON);
41517f84b79SHauke Mehrtens
41617f84b79SHauke Mehrtens return 0;
41717f84b79SHauke Mehrtens }
41817f84b79SHauke Mehrtens
lantiq_ssc_prepare_message(struct spi_controller * host,struct spi_message * message)419*ea11a8bbSYang Yingliang static int lantiq_ssc_prepare_message(struct spi_controller *host,
42017f84b79SHauke Mehrtens struct spi_message *message)
42117f84b79SHauke Mehrtens {
422*ea11a8bbSYang Yingliang struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host);
42317f84b79SHauke Mehrtens
42417f84b79SHauke Mehrtens hw_enter_config_mode(spi);
42517f84b79SHauke Mehrtens hw_setup_clock_mode(spi, message->spi->mode);
42617f84b79SHauke Mehrtens hw_enter_active_mode(spi);
42717f84b79SHauke Mehrtens
42817f84b79SHauke Mehrtens return 0;
42917f84b79SHauke Mehrtens }
43017f84b79SHauke Mehrtens
hw_setup_transfer(struct lantiq_ssc_spi * spi,struct spi_device * spidev,struct spi_transfer * t)43117f84b79SHauke Mehrtens static void hw_setup_transfer(struct lantiq_ssc_spi *spi,
43217f84b79SHauke Mehrtens struct spi_device *spidev, struct spi_transfer *t)
43317f84b79SHauke Mehrtens {
43417f84b79SHauke Mehrtens unsigned int speed_hz = t->speed_hz;
43517f84b79SHauke Mehrtens unsigned int bits_per_word = t->bits_per_word;
43617f84b79SHauke Mehrtens u32 con;
43717f84b79SHauke Mehrtens
43817f84b79SHauke Mehrtens if (bits_per_word != spi->bits_per_word ||
43917f84b79SHauke Mehrtens speed_hz != spi->speed_hz) {
44017f84b79SHauke Mehrtens hw_enter_config_mode(spi);
44117f84b79SHauke Mehrtens hw_setup_speed_hz(spi, speed_hz);
44217f84b79SHauke Mehrtens hw_setup_bits_per_word(spi, bits_per_word);
44317f84b79SHauke Mehrtens hw_enter_active_mode(spi);
44417f84b79SHauke Mehrtens
44517f84b79SHauke Mehrtens spi->speed_hz = speed_hz;
44617f84b79SHauke Mehrtens spi->bits_per_word = bits_per_word;
44717f84b79SHauke Mehrtens }
44817f84b79SHauke Mehrtens
44917f84b79SHauke Mehrtens /* Configure transmitter and receiver */
450ad2fca07SHauke Mehrtens con = lantiq_ssc_readl(spi, LTQ_SPI_CON);
45117f84b79SHauke Mehrtens if (t->tx_buf)
452ad2fca07SHauke Mehrtens con &= ~LTQ_SPI_CON_TXOFF;
45317f84b79SHauke Mehrtens else
454ad2fca07SHauke Mehrtens con |= LTQ_SPI_CON_TXOFF;
45517f84b79SHauke Mehrtens
45617f84b79SHauke Mehrtens if (t->rx_buf)
457ad2fca07SHauke Mehrtens con &= ~LTQ_SPI_CON_RXOFF;
45817f84b79SHauke Mehrtens else
459ad2fca07SHauke Mehrtens con |= LTQ_SPI_CON_RXOFF;
46017f84b79SHauke Mehrtens
461ad2fca07SHauke Mehrtens lantiq_ssc_writel(spi, con, LTQ_SPI_CON);
46217f84b79SHauke Mehrtens }
46317f84b79SHauke Mehrtens
lantiq_ssc_unprepare_message(struct spi_controller * host,struct spi_message * message)464*ea11a8bbSYang Yingliang static int lantiq_ssc_unprepare_message(struct spi_controller *host,
46517f84b79SHauke Mehrtens struct spi_message *message)
46617f84b79SHauke Mehrtens {
467*ea11a8bbSYang Yingliang struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host);
46817f84b79SHauke Mehrtens
46917f84b79SHauke Mehrtens flush_workqueue(spi->wq);
47017f84b79SHauke Mehrtens
47117f84b79SHauke Mehrtens /* Disable transmitter and receiver while idle */
472ad2fca07SHauke Mehrtens lantiq_ssc_maskl(spi, 0, LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF,
473ad2fca07SHauke Mehrtens LTQ_SPI_CON);
47417f84b79SHauke Mehrtens
47517f84b79SHauke Mehrtens return 0;
47617f84b79SHauke Mehrtens }
47717f84b79SHauke Mehrtens
tx_fifo_write(struct lantiq_ssc_spi * spi)47817f84b79SHauke Mehrtens static void tx_fifo_write(struct lantiq_ssc_spi *spi)
47917f84b79SHauke Mehrtens {
48017f84b79SHauke Mehrtens const u8 *tx8;
48117f84b79SHauke Mehrtens const u16 *tx16;
48217f84b79SHauke Mehrtens const u32 *tx32;
48317f84b79SHauke Mehrtens u32 data;
48417f84b79SHauke Mehrtens unsigned int tx_free = tx_fifo_free(spi);
48517f84b79SHauke Mehrtens
486661ccf2bSDilip Kota spi->fdx_tx_level = 0;
48717f84b79SHauke Mehrtens while (spi->tx_todo && tx_free) {
48817f84b79SHauke Mehrtens switch (spi->bits_per_word) {
48917f84b79SHauke Mehrtens case 2 ... 8:
49017f84b79SHauke Mehrtens tx8 = spi->tx;
49117f84b79SHauke Mehrtens data = *tx8;
49217f84b79SHauke Mehrtens spi->tx_todo--;
49317f84b79SHauke Mehrtens spi->tx++;
49417f84b79SHauke Mehrtens break;
49517f84b79SHauke Mehrtens case 16:
49617f84b79SHauke Mehrtens tx16 = (u16 *) spi->tx;
49717f84b79SHauke Mehrtens data = *tx16;
49817f84b79SHauke Mehrtens spi->tx_todo -= 2;
49917f84b79SHauke Mehrtens spi->tx += 2;
50017f84b79SHauke Mehrtens break;
50117f84b79SHauke Mehrtens case 32:
50217f84b79SHauke Mehrtens tx32 = (u32 *) spi->tx;
50317f84b79SHauke Mehrtens data = *tx32;
50417f84b79SHauke Mehrtens spi->tx_todo -= 4;
50517f84b79SHauke Mehrtens spi->tx += 4;
50617f84b79SHauke Mehrtens break;
50717f84b79SHauke Mehrtens default:
50817f84b79SHauke Mehrtens WARN_ON(1);
50917f84b79SHauke Mehrtens data = 0;
51017f84b79SHauke Mehrtens break;
51117f84b79SHauke Mehrtens }
51217f84b79SHauke Mehrtens
513ad2fca07SHauke Mehrtens lantiq_ssc_writel(spi, data, LTQ_SPI_TB);
51417f84b79SHauke Mehrtens tx_free--;
515661ccf2bSDilip Kota spi->fdx_tx_level++;
51617f84b79SHauke Mehrtens }
51717f84b79SHauke Mehrtens }
51817f84b79SHauke Mehrtens
rx_fifo_read_full_duplex(struct lantiq_ssc_spi * spi)51917f84b79SHauke Mehrtens static void rx_fifo_read_full_duplex(struct lantiq_ssc_spi *spi)
52017f84b79SHauke Mehrtens {
52117f84b79SHauke Mehrtens u8 *rx8;
52217f84b79SHauke Mehrtens u16 *rx16;
52317f84b79SHauke Mehrtens u32 *rx32;
52417f84b79SHauke Mehrtens u32 data;
52517f84b79SHauke Mehrtens unsigned int rx_fill = rx_fifo_level(spi);
52617f84b79SHauke Mehrtens
527661ccf2bSDilip Kota /*
528661ccf2bSDilip Kota * Wait until all expected data to be shifted in.
529661ccf2bSDilip Kota * Otherwise, rx overrun may occur.
530661ccf2bSDilip Kota */
531661ccf2bSDilip Kota while (rx_fill != spi->fdx_tx_level)
532661ccf2bSDilip Kota rx_fill = rx_fifo_level(spi);
533661ccf2bSDilip Kota
53417f84b79SHauke Mehrtens while (rx_fill) {
535ad2fca07SHauke Mehrtens data = lantiq_ssc_readl(spi, LTQ_SPI_RB);
53617f84b79SHauke Mehrtens
53717f84b79SHauke Mehrtens switch (spi->bits_per_word) {
53817f84b79SHauke Mehrtens case 2 ... 8:
53917f84b79SHauke Mehrtens rx8 = spi->rx;
54017f84b79SHauke Mehrtens *rx8 = data;
54117f84b79SHauke Mehrtens spi->rx_todo--;
54217f84b79SHauke Mehrtens spi->rx++;
54317f84b79SHauke Mehrtens break;
54417f84b79SHauke Mehrtens case 16:
54517f84b79SHauke Mehrtens rx16 = (u16 *) spi->rx;
54617f84b79SHauke Mehrtens *rx16 = data;
54717f84b79SHauke Mehrtens spi->rx_todo -= 2;
54817f84b79SHauke Mehrtens spi->rx += 2;
54917f84b79SHauke Mehrtens break;
55017f84b79SHauke Mehrtens case 32:
55117f84b79SHauke Mehrtens rx32 = (u32 *) spi->rx;
55217f84b79SHauke Mehrtens *rx32 = data;
55317f84b79SHauke Mehrtens spi->rx_todo -= 4;
55417f84b79SHauke Mehrtens spi->rx += 4;
55517f84b79SHauke Mehrtens break;
55617f84b79SHauke Mehrtens default:
55717f84b79SHauke Mehrtens WARN_ON(1);
55817f84b79SHauke Mehrtens break;
55917f84b79SHauke Mehrtens }
56017f84b79SHauke Mehrtens
56117f84b79SHauke Mehrtens rx_fill--;
56217f84b79SHauke Mehrtens }
56317f84b79SHauke Mehrtens }
56417f84b79SHauke Mehrtens
rx_fifo_read_half_duplex(struct lantiq_ssc_spi * spi)56517f84b79SHauke Mehrtens static void rx_fifo_read_half_duplex(struct lantiq_ssc_spi *spi)
56617f84b79SHauke Mehrtens {
56717f84b79SHauke Mehrtens u32 data, *rx32;
56817f84b79SHauke Mehrtens u8 *rx8;
56917f84b79SHauke Mehrtens unsigned int rxbv, shift;
57017f84b79SHauke Mehrtens unsigned int rx_fill = rx_fifo_level(spi);
57117f84b79SHauke Mehrtens
57217f84b79SHauke Mehrtens /*
57317f84b79SHauke Mehrtens * In RX-only mode the bits per word value is ignored by HW. A value
57417f84b79SHauke Mehrtens * of 32 is used instead. Thus all 4 bytes per FIFO must be read.
57517f84b79SHauke Mehrtens * If remaining RX bytes are less than 4, the FIFO must be read
57617f84b79SHauke Mehrtens * differently. The amount of received and valid bytes is indicated
57717f84b79SHauke Mehrtens * by STAT.RXBV register value.
57817f84b79SHauke Mehrtens */
57917f84b79SHauke Mehrtens while (rx_fill) {
58017f84b79SHauke Mehrtens if (spi->rx_todo < 4) {
581ad2fca07SHauke Mehrtens rxbv = (lantiq_ssc_readl(spi, LTQ_SPI_STAT) &
582ad2fca07SHauke Mehrtens LTQ_SPI_STAT_RXBV_M) >> LTQ_SPI_STAT_RXBV_S;
583ad2fca07SHauke Mehrtens data = lantiq_ssc_readl(spi, LTQ_SPI_RB);
58417f84b79SHauke Mehrtens
58517f84b79SHauke Mehrtens shift = (rxbv - 1) * 8;
58617f84b79SHauke Mehrtens rx8 = spi->rx;
58717f84b79SHauke Mehrtens
58817f84b79SHauke Mehrtens while (rxbv) {
58917f84b79SHauke Mehrtens *rx8++ = (data >> shift) & 0xFF;
59017f84b79SHauke Mehrtens rxbv--;
59117f84b79SHauke Mehrtens shift -= 8;
59217f84b79SHauke Mehrtens spi->rx_todo--;
59317f84b79SHauke Mehrtens spi->rx++;
59417f84b79SHauke Mehrtens }
59517f84b79SHauke Mehrtens } else {
596ad2fca07SHauke Mehrtens data = lantiq_ssc_readl(spi, LTQ_SPI_RB);
59717f84b79SHauke Mehrtens rx32 = (u32 *) spi->rx;
59817f84b79SHauke Mehrtens
59917f84b79SHauke Mehrtens *rx32++ = data;
60017f84b79SHauke Mehrtens spi->rx_todo -= 4;
60117f84b79SHauke Mehrtens spi->rx += 4;
60217f84b79SHauke Mehrtens }
60317f84b79SHauke Mehrtens rx_fill--;
60417f84b79SHauke Mehrtens }
60517f84b79SHauke Mehrtens }
60617f84b79SHauke Mehrtens
rx_request(struct lantiq_ssc_spi * spi)60717f84b79SHauke Mehrtens static void rx_request(struct lantiq_ssc_spi *spi)
60817f84b79SHauke Mehrtens {
60917f84b79SHauke Mehrtens unsigned int rxreq, rxreq_max;
61017f84b79SHauke Mehrtens
61117f84b79SHauke Mehrtens /*
61217f84b79SHauke Mehrtens * To avoid receive overflows at high clocks it is better to request
61317f84b79SHauke Mehrtens * only the amount of bytes that fits into all FIFOs. This value
61417f84b79SHauke Mehrtens * depends on the FIFO size implemented in hardware.
61517f84b79SHauke Mehrtens */
61617f84b79SHauke Mehrtens rxreq = spi->rx_todo;
61717f84b79SHauke Mehrtens rxreq_max = spi->rx_fifo_size * 4;
61817f84b79SHauke Mehrtens if (rxreq > rxreq_max)
61917f84b79SHauke Mehrtens rxreq = rxreq_max;
62017f84b79SHauke Mehrtens
621ad2fca07SHauke Mehrtens lantiq_ssc_writel(spi, rxreq, LTQ_SPI_RXREQ);
62217f84b79SHauke Mehrtens }
62317f84b79SHauke Mehrtens
lantiq_ssc_xmit_interrupt(int irq,void * data)62417f84b79SHauke Mehrtens static irqreturn_t lantiq_ssc_xmit_interrupt(int irq, void *data)
62517f84b79SHauke Mehrtens {
62617f84b79SHauke Mehrtens struct lantiq_ssc_spi *spi = data;
62794eca904SDilip Kota const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg;
62894eca904SDilip Kota u32 val = lantiq_ssc_readl(spi, hwcfg->irncr);
62917f84b79SHauke Mehrtens
6307349201dSBarry Song spin_lock(&spi->lock);
63194eca904SDilip Kota if (hwcfg->irq_ack)
63294eca904SDilip Kota lantiq_ssc_writel(spi, val, hwcfg->irncr);
63394eca904SDilip Kota
63417f84b79SHauke Mehrtens if (spi->tx) {
63517f84b79SHauke Mehrtens if (spi->rx && spi->rx_todo)
63617f84b79SHauke Mehrtens rx_fifo_read_full_duplex(spi);
63717f84b79SHauke Mehrtens
63817f84b79SHauke Mehrtens if (spi->tx_todo)
63917f84b79SHauke Mehrtens tx_fifo_write(spi);
64017f84b79SHauke Mehrtens else if (!tx_fifo_level(spi))
64117f84b79SHauke Mehrtens goto completed;
64217f84b79SHauke Mehrtens } else if (spi->rx) {
64317f84b79SHauke Mehrtens if (spi->rx_todo) {
64417f84b79SHauke Mehrtens rx_fifo_read_half_duplex(spi);
64517f84b79SHauke Mehrtens
64617f84b79SHauke Mehrtens if (spi->rx_todo)
64717f84b79SHauke Mehrtens rx_request(spi);
64817f84b79SHauke Mehrtens else
64917f84b79SHauke Mehrtens goto completed;
65017f84b79SHauke Mehrtens } else {
65117f84b79SHauke Mehrtens goto completed;
65217f84b79SHauke Mehrtens }
65317f84b79SHauke Mehrtens }
65417f84b79SHauke Mehrtens
6557349201dSBarry Song spin_unlock(&spi->lock);
65617f84b79SHauke Mehrtens return IRQ_HANDLED;
65717f84b79SHauke Mehrtens
65817f84b79SHauke Mehrtens completed:
65917f84b79SHauke Mehrtens queue_work(spi->wq, &spi->work);
6607349201dSBarry Song spin_unlock(&spi->lock);
66117f84b79SHauke Mehrtens
66217f84b79SHauke Mehrtens return IRQ_HANDLED;
66317f84b79SHauke Mehrtens }
66417f84b79SHauke Mehrtens
lantiq_ssc_err_interrupt(int irq,void * data)66517f84b79SHauke Mehrtens static irqreturn_t lantiq_ssc_err_interrupt(int irq, void *data)
66617f84b79SHauke Mehrtens {
66717f84b79SHauke Mehrtens struct lantiq_ssc_spi *spi = data;
66894eca904SDilip Kota const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg;
669ad2fca07SHauke Mehrtens u32 stat = lantiq_ssc_readl(spi, LTQ_SPI_STAT);
67094eca904SDilip Kota u32 val = lantiq_ssc_readl(spi, hwcfg->irncr);
67117f84b79SHauke Mehrtens
672ad2fca07SHauke Mehrtens if (!(stat & LTQ_SPI_STAT_ERRORS))
67317f84b79SHauke Mehrtens return IRQ_NONE;
67417f84b79SHauke Mehrtens
6757349201dSBarry Song spin_lock(&spi->lock);
67694eca904SDilip Kota if (hwcfg->irq_ack)
67794eca904SDilip Kota lantiq_ssc_writel(spi, val, hwcfg->irncr);
67894eca904SDilip Kota
679ad2fca07SHauke Mehrtens if (stat & LTQ_SPI_STAT_RUE)
68017f84b79SHauke Mehrtens dev_err(spi->dev, "receive underflow error\n");
681ad2fca07SHauke Mehrtens if (stat & LTQ_SPI_STAT_TUE)
68217f84b79SHauke Mehrtens dev_err(spi->dev, "transmit underflow error\n");
683ad2fca07SHauke Mehrtens if (stat & LTQ_SPI_STAT_AE)
68417f84b79SHauke Mehrtens dev_err(spi->dev, "abort error\n");
685ad2fca07SHauke Mehrtens if (stat & LTQ_SPI_STAT_RE)
68617f84b79SHauke Mehrtens dev_err(spi->dev, "receive overflow error\n");
687ad2fca07SHauke Mehrtens if (stat & LTQ_SPI_STAT_TE)
68817f84b79SHauke Mehrtens dev_err(spi->dev, "transmit overflow error\n");
689ad2fca07SHauke Mehrtens if (stat & LTQ_SPI_STAT_ME)
69017f84b79SHauke Mehrtens dev_err(spi->dev, "mode error\n");
69117f84b79SHauke Mehrtens
69217f84b79SHauke Mehrtens /* Clear error flags */
693ad2fca07SHauke Mehrtens lantiq_ssc_maskl(spi, 0, LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE);
69417f84b79SHauke Mehrtens
69517f84b79SHauke Mehrtens /* set bad status so it can be retried */
696*ea11a8bbSYang Yingliang if (spi->host->cur_msg)
697*ea11a8bbSYang Yingliang spi->host->cur_msg->status = -EIO;
69817f84b79SHauke Mehrtens queue_work(spi->wq, &spi->work);
6997349201dSBarry Song spin_unlock(&spi->lock);
70017f84b79SHauke Mehrtens
70117f84b79SHauke Mehrtens return IRQ_HANDLED;
70217f84b79SHauke Mehrtens }
70317f84b79SHauke Mehrtens
intel_lgm_ssc_isr(int irq,void * data)704040f7f97SDilip Kota static irqreturn_t intel_lgm_ssc_isr(int irq, void *data)
705040f7f97SDilip Kota {
706040f7f97SDilip Kota struct lantiq_ssc_spi *spi = data;
707040f7f97SDilip Kota const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg;
708040f7f97SDilip Kota u32 val = lantiq_ssc_readl(spi, hwcfg->irncr);
709040f7f97SDilip Kota
710040f7f97SDilip Kota if (!(val & LTQ_SPI_IRNEN_ALL))
711040f7f97SDilip Kota return IRQ_NONE;
712040f7f97SDilip Kota
713040f7f97SDilip Kota if (val & LTQ_SPI_IRNEN_E)
714040f7f97SDilip Kota return lantiq_ssc_err_interrupt(irq, data);
715040f7f97SDilip Kota
716040f7f97SDilip Kota if ((val & hwcfg->irnen_t) || (val & hwcfg->irnen_r))
717040f7f97SDilip Kota return lantiq_ssc_xmit_interrupt(irq, data);
718040f7f97SDilip Kota
719040f7f97SDilip Kota return IRQ_HANDLED;
720040f7f97SDilip Kota }
721040f7f97SDilip Kota
transfer_start(struct lantiq_ssc_spi * spi,struct spi_device * spidev,struct spi_transfer * t)72217f84b79SHauke Mehrtens static int transfer_start(struct lantiq_ssc_spi *spi, struct spi_device *spidev,
72317f84b79SHauke Mehrtens struct spi_transfer *t)
72417f84b79SHauke Mehrtens {
72517f84b79SHauke Mehrtens unsigned long flags;
72617f84b79SHauke Mehrtens
72717f84b79SHauke Mehrtens spin_lock_irqsave(&spi->lock, flags);
72817f84b79SHauke Mehrtens
72917f84b79SHauke Mehrtens spi->tx = t->tx_buf;
73017f84b79SHauke Mehrtens spi->rx = t->rx_buf;
73117f84b79SHauke Mehrtens
73217f84b79SHauke Mehrtens if (t->tx_buf) {
73317f84b79SHauke Mehrtens spi->tx_todo = t->len;
73417f84b79SHauke Mehrtens
73517f84b79SHauke Mehrtens /* initially fill TX FIFO */
73617f84b79SHauke Mehrtens tx_fifo_write(spi);
73717f84b79SHauke Mehrtens }
73817f84b79SHauke Mehrtens
73917f84b79SHauke Mehrtens if (spi->rx) {
74017f84b79SHauke Mehrtens spi->rx_todo = t->len;
74117f84b79SHauke Mehrtens
74217f84b79SHauke Mehrtens /* start shift clock in RX-only mode */
74317f84b79SHauke Mehrtens if (!spi->tx)
74417f84b79SHauke Mehrtens rx_request(spi);
74517f84b79SHauke Mehrtens }
74617f84b79SHauke Mehrtens
74717f84b79SHauke Mehrtens spin_unlock_irqrestore(&spi->lock, flags);
74817f84b79SHauke Mehrtens
74917f84b79SHauke Mehrtens return t->len;
75017f84b79SHauke Mehrtens }
75117f84b79SHauke Mehrtens
75217f84b79SHauke Mehrtens /*
75317f84b79SHauke Mehrtens * The driver only gets an interrupt when the FIFO is empty, but there
75417f84b79SHauke Mehrtens * is an additional shift register from which the data is written to
75517f84b79SHauke Mehrtens * the wire. We get the last interrupt when the controller starts to
75617f84b79SHauke Mehrtens * write the last word to the wire, not when it is finished. Do busy
75717f84b79SHauke Mehrtens * waiting till it finishes.
75817f84b79SHauke Mehrtens */
lantiq_ssc_bussy_work(struct work_struct * work)75917f84b79SHauke Mehrtens static void lantiq_ssc_bussy_work(struct work_struct *work)
76017f84b79SHauke Mehrtens {
76117f84b79SHauke Mehrtens struct lantiq_ssc_spi *spi;
76217f84b79SHauke Mehrtens unsigned long long timeout = 8LL * 1000LL;
76317f84b79SHauke Mehrtens unsigned long end;
76417f84b79SHauke Mehrtens
76517f84b79SHauke Mehrtens spi = container_of(work, typeof(*spi), work);
76617f84b79SHauke Mehrtens
76717f84b79SHauke Mehrtens do_div(timeout, spi->speed_hz);
76817f84b79SHauke Mehrtens timeout += timeout + 100; /* some tolerance */
76917f84b79SHauke Mehrtens
77017f84b79SHauke Mehrtens end = jiffies + msecs_to_jiffies(timeout);
77117f84b79SHauke Mehrtens do {
772ad2fca07SHauke Mehrtens u32 stat = lantiq_ssc_readl(spi, LTQ_SPI_STAT);
77317f84b79SHauke Mehrtens
774ad2fca07SHauke Mehrtens if (!(stat & LTQ_SPI_STAT_BSY)) {
775*ea11a8bbSYang Yingliang spi_finalize_current_transfer(spi->host);
77617f84b79SHauke Mehrtens return;
77717f84b79SHauke Mehrtens }
77817f84b79SHauke Mehrtens
77917f84b79SHauke Mehrtens cond_resched();
78017f84b79SHauke Mehrtens } while (!time_after_eq(jiffies, end));
78117f84b79SHauke Mehrtens
782*ea11a8bbSYang Yingliang if (spi->host->cur_msg)
783*ea11a8bbSYang Yingliang spi->host->cur_msg->status = -EIO;
784*ea11a8bbSYang Yingliang spi_finalize_current_transfer(spi->host);
78517f84b79SHauke Mehrtens }
78617f84b79SHauke Mehrtens
lantiq_ssc_handle_err(struct spi_controller * host,struct spi_message * message)787*ea11a8bbSYang Yingliang static void lantiq_ssc_handle_err(struct spi_controller *host,
78817f84b79SHauke Mehrtens struct spi_message *message)
78917f84b79SHauke Mehrtens {
790*ea11a8bbSYang Yingliang struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host);
79117f84b79SHauke Mehrtens
79217f84b79SHauke Mehrtens /* flush FIFOs on timeout */
79317f84b79SHauke Mehrtens rx_fifo_flush(spi);
79417f84b79SHauke Mehrtens tx_fifo_flush(spi);
79517f84b79SHauke Mehrtens }
79617f84b79SHauke Mehrtens
lantiq_ssc_set_cs(struct spi_device * spidev,bool enable)79717f84b79SHauke Mehrtens static void lantiq_ssc_set_cs(struct spi_device *spidev, bool enable)
79817f84b79SHauke Mehrtens {
799*ea11a8bbSYang Yingliang struct lantiq_ssc_spi *spi = spi_controller_get_devdata(spidev->controller);
8009e264f3fSAmit Kumar Mahapatra via Alsa-devel unsigned int cs = spi_get_chipselect(spidev, 0);
80117f84b79SHauke Mehrtens u32 fgpo;
80217f84b79SHauke Mehrtens
80317f84b79SHauke Mehrtens if (!!(spidev->mode & SPI_CS_HIGH) == enable)
80417f84b79SHauke Mehrtens fgpo = (1 << (cs - spi->base_cs));
80517f84b79SHauke Mehrtens else
806ad2fca07SHauke Mehrtens fgpo = (1 << (cs - spi->base_cs + LTQ_SPI_FGPO_SETOUTN_S));
80717f84b79SHauke Mehrtens
808ad2fca07SHauke Mehrtens lantiq_ssc_writel(spi, fgpo, LTQ_SPI_FPGO);
80917f84b79SHauke Mehrtens }
81017f84b79SHauke Mehrtens
lantiq_ssc_transfer_one(struct spi_controller * host,struct spi_device * spidev,struct spi_transfer * t)811*ea11a8bbSYang Yingliang static int lantiq_ssc_transfer_one(struct spi_controller *host,
81217f84b79SHauke Mehrtens struct spi_device *spidev,
81317f84b79SHauke Mehrtens struct spi_transfer *t)
81417f84b79SHauke Mehrtens {
815*ea11a8bbSYang Yingliang struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host);
81617f84b79SHauke Mehrtens
81717f84b79SHauke Mehrtens hw_setup_transfer(spi, spidev, t);
81817f84b79SHauke Mehrtens
81917f84b79SHauke Mehrtens return transfer_start(spi, spidev, t);
82017f84b79SHauke Mehrtens }
82117f84b79SHauke Mehrtens
intel_lgm_cfg_irq(struct platform_device * pdev,struct lantiq_ssc_spi * spi)822040f7f97SDilip Kota static int intel_lgm_cfg_irq(struct platform_device *pdev, struct lantiq_ssc_spi *spi)
823040f7f97SDilip Kota {
824040f7f97SDilip Kota int irq;
825040f7f97SDilip Kota
826040f7f97SDilip Kota irq = platform_get_irq(pdev, 0);
827040f7f97SDilip Kota if (irq < 0)
828040f7f97SDilip Kota return irq;
829040f7f97SDilip Kota
830040f7f97SDilip Kota return devm_request_irq(&pdev->dev, irq, intel_lgm_ssc_isr, 0, "spi", spi);
831040f7f97SDilip Kota }
832040f7f97SDilip Kota
lantiq_cfg_irq(struct platform_device * pdev,struct lantiq_ssc_spi * spi)833744cd0f2SDilip Kota static int lantiq_cfg_irq(struct platform_device *pdev, struct lantiq_ssc_spi *spi)
834744cd0f2SDilip Kota {
835744cd0f2SDilip Kota int irq, err;
836744cd0f2SDilip Kota
837744cd0f2SDilip Kota irq = platform_get_irq_byname(pdev, LTQ_SPI_RX_IRQ_NAME);
838744cd0f2SDilip Kota if (irq < 0)
839744cd0f2SDilip Kota return irq;
840744cd0f2SDilip Kota
841744cd0f2SDilip Kota err = devm_request_irq(&pdev->dev, irq, lantiq_ssc_xmit_interrupt,
842744cd0f2SDilip Kota 0, LTQ_SPI_RX_IRQ_NAME, spi);
843744cd0f2SDilip Kota if (err)
844744cd0f2SDilip Kota return err;
845744cd0f2SDilip Kota
846744cd0f2SDilip Kota irq = platform_get_irq_byname(pdev, LTQ_SPI_TX_IRQ_NAME);
847744cd0f2SDilip Kota if (irq < 0)
848744cd0f2SDilip Kota return irq;
849744cd0f2SDilip Kota
850744cd0f2SDilip Kota err = devm_request_irq(&pdev->dev, irq, lantiq_ssc_xmit_interrupt,
851744cd0f2SDilip Kota 0, LTQ_SPI_TX_IRQ_NAME, spi);
852744cd0f2SDilip Kota
853744cd0f2SDilip Kota if (err)
854744cd0f2SDilip Kota return err;
855744cd0f2SDilip Kota
856744cd0f2SDilip Kota irq = platform_get_irq_byname(pdev, LTQ_SPI_ERR_IRQ_NAME);
857744cd0f2SDilip Kota if (irq < 0)
858744cd0f2SDilip Kota return irq;
859744cd0f2SDilip Kota
860744cd0f2SDilip Kota err = devm_request_irq(&pdev->dev, irq, lantiq_ssc_err_interrupt,
861744cd0f2SDilip Kota 0, LTQ_SPI_ERR_IRQ_NAME, spi);
862744cd0f2SDilip Kota return err;
863744cd0f2SDilip Kota }
864744cd0f2SDilip Kota
86517f84b79SHauke Mehrtens static const struct lantiq_ssc_hwcfg lantiq_ssc_xway = {
866744cd0f2SDilip Kota .cfg_irq = lantiq_cfg_irq,
867ad2fca07SHauke Mehrtens .irnen_r = LTQ_SPI_IRNEN_R_XWAY,
868ad2fca07SHauke Mehrtens .irnen_t = LTQ_SPI_IRNEN_T_XWAY,
8698d19d665SDilip Kota .irnicr = 0xF8,
8708d19d665SDilip Kota .irncr = 0xFC,
8718743d215SDilip Kota .fifo_size_mask = GENMASK(5, 0),
87294eca904SDilip Kota .irq_ack = false,
87317f84b79SHauke Mehrtens };
87417f84b79SHauke Mehrtens
87517f84b79SHauke Mehrtens static const struct lantiq_ssc_hwcfg lantiq_ssc_xrx = {
876744cd0f2SDilip Kota .cfg_irq = lantiq_cfg_irq,
877ad2fca07SHauke Mehrtens .irnen_r = LTQ_SPI_IRNEN_R_XRX,
878ad2fca07SHauke Mehrtens .irnen_t = LTQ_SPI_IRNEN_T_XRX,
8798d19d665SDilip Kota .irnicr = 0xF8,
8808d19d665SDilip Kota .irncr = 0xFC,
8818743d215SDilip Kota .fifo_size_mask = GENMASK(5, 0),
88294eca904SDilip Kota .irq_ack = false,
88317f84b79SHauke Mehrtens };
88417f84b79SHauke Mehrtens
885040f7f97SDilip Kota static const struct lantiq_ssc_hwcfg intel_ssc_lgm = {
886040f7f97SDilip Kota .cfg_irq = intel_lgm_cfg_irq,
887040f7f97SDilip Kota .irnen_r = LTQ_SPI_IRNEN_R_XRX,
888040f7f97SDilip Kota .irnen_t = LTQ_SPI_IRNEN_T_XRX,
889040f7f97SDilip Kota .irnicr = 0xFC,
890040f7f97SDilip Kota .irncr = 0xF8,
891040f7f97SDilip Kota .fifo_size_mask = GENMASK(7, 0),
892040f7f97SDilip Kota .irq_ack = true,
893040f7f97SDilip Kota };
894040f7f97SDilip Kota
89517f84b79SHauke Mehrtens static const struct of_device_id lantiq_ssc_match[] = {
89617f84b79SHauke Mehrtens { .compatible = "lantiq,ase-spi", .data = &lantiq_ssc_xway, },
89717f84b79SHauke Mehrtens { .compatible = "lantiq,falcon-spi", .data = &lantiq_ssc_xrx, },
89817f84b79SHauke Mehrtens { .compatible = "lantiq,xrx100-spi", .data = &lantiq_ssc_xrx, },
899040f7f97SDilip Kota { .compatible = "intel,lgm-spi", .data = &intel_ssc_lgm, },
90017f84b79SHauke Mehrtens {},
90117f84b79SHauke Mehrtens };
90217f84b79SHauke Mehrtens MODULE_DEVICE_TABLE(of, lantiq_ssc_match);
90317f84b79SHauke Mehrtens
lantiq_ssc_probe(struct platform_device * pdev)90417f84b79SHauke Mehrtens static int lantiq_ssc_probe(struct platform_device *pdev)
90517f84b79SHauke Mehrtens {
90617f84b79SHauke Mehrtens struct device *dev = &pdev->dev;
907*ea11a8bbSYang Yingliang struct spi_controller *host;
90817f84b79SHauke Mehrtens struct lantiq_ssc_spi *spi;
90917f84b79SHauke Mehrtens const struct lantiq_ssc_hwcfg *hwcfg;
91017f84b79SHauke Mehrtens u32 id, supports_dma, revision;
91117f84b79SHauke Mehrtens unsigned int num_cs;
912744cd0f2SDilip Kota int err;
91317f84b79SHauke Mehrtens
914c5a3106aSMinghao Chi (CGEL ZTE) hwcfg = of_device_get_match_data(dev);
91517f84b79SHauke Mehrtens
916*ea11a8bbSYang Yingliang host = spi_alloc_host(dev, sizeof(struct lantiq_ssc_spi));
917*ea11a8bbSYang Yingliang if (!host)
91817f84b79SHauke Mehrtens return -ENOMEM;
91917f84b79SHauke Mehrtens
920*ea11a8bbSYang Yingliang spi = spi_controller_get_devdata(host);
921*ea11a8bbSYang Yingliang spi->host = host;
92217f84b79SHauke Mehrtens spi->dev = dev;
92317f84b79SHauke Mehrtens spi->hwcfg = hwcfg;
92417f84b79SHauke Mehrtens platform_set_drvdata(pdev, spi);
92522262695SMarkus Elfring spi->regbase = devm_platform_ioremap_resource(pdev, 0);
92617f84b79SHauke Mehrtens if (IS_ERR(spi->regbase)) {
92717f84b79SHauke Mehrtens err = PTR_ERR(spi->regbase);
928*ea11a8bbSYang Yingliang goto err_host_put;
92917f84b79SHauke Mehrtens }
93017f84b79SHauke Mehrtens
931744cd0f2SDilip Kota err = hwcfg->cfg_irq(pdev, spi);
93217f84b79SHauke Mehrtens if (err)
933*ea11a8bbSYang Yingliang goto err_host_put;
93417f84b79SHauke Mehrtens
93517f84b79SHauke Mehrtens spi->spi_clk = devm_clk_get(dev, "gate");
93617f84b79SHauke Mehrtens if (IS_ERR(spi->spi_clk)) {
93717f84b79SHauke Mehrtens err = PTR_ERR(spi->spi_clk);
938*ea11a8bbSYang Yingliang goto err_host_put;
93917f84b79SHauke Mehrtens }
94017f84b79SHauke Mehrtens err = clk_prepare_enable(spi->spi_clk);
94117f84b79SHauke Mehrtens if (err)
942*ea11a8bbSYang Yingliang goto err_host_put;
94317f84b79SHauke Mehrtens
94417f84b79SHauke Mehrtens /*
94517f84b79SHauke Mehrtens * Use the old clk_get_fpi() function on Lantiq platform, till it
94617f84b79SHauke Mehrtens * supports common clk.
94717f84b79SHauke Mehrtens */
94817f84b79SHauke Mehrtens #if defined(CONFIG_LANTIQ) && !defined(CONFIG_COMMON_CLK)
94917f84b79SHauke Mehrtens spi->fpi_clk = clk_get_fpi();
95017f84b79SHauke Mehrtens #else
95117f84b79SHauke Mehrtens spi->fpi_clk = clk_get(dev, "freq");
95217f84b79SHauke Mehrtens #endif
95317f84b79SHauke Mehrtens if (IS_ERR(spi->fpi_clk)) {
95417f84b79SHauke Mehrtens err = PTR_ERR(spi->fpi_clk);
95517f84b79SHauke Mehrtens goto err_clk_disable;
95617f84b79SHauke Mehrtens }
95717f84b79SHauke Mehrtens
95817f84b79SHauke Mehrtens num_cs = 8;
95917f84b79SHauke Mehrtens of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs);
96017f84b79SHauke Mehrtens
96117f84b79SHauke Mehrtens spi->base_cs = 1;
96217f84b79SHauke Mehrtens of_property_read_u32(pdev->dev.of_node, "base-cs", &spi->base_cs);
96317f84b79SHauke Mehrtens
96417f84b79SHauke Mehrtens spin_lock_init(&spi->lock);
96517f84b79SHauke Mehrtens spi->bits_per_word = 8;
96617f84b79SHauke Mehrtens spi->speed_hz = 0;
96717f84b79SHauke Mehrtens
968*ea11a8bbSYang Yingliang host->dev.of_node = pdev->dev.of_node;
969*ea11a8bbSYang Yingliang host->num_chipselect = num_cs;
970*ea11a8bbSYang Yingliang host->use_gpio_descriptors = true;
971*ea11a8bbSYang Yingliang host->setup = lantiq_ssc_setup;
972*ea11a8bbSYang Yingliang host->set_cs = lantiq_ssc_set_cs;
973*ea11a8bbSYang Yingliang host->handle_err = lantiq_ssc_handle_err;
974*ea11a8bbSYang Yingliang host->prepare_message = lantiq_ssc_prepare_message;
975*ea11a8bbSYang Yingliang host->unprepare_message = lantiq_ssc_unprepare_message;
976*ea11a8bbSYang Yingliang host->transfer_one = lantiq_ssc_transfer_one;
977*ea11a8bbSYang Yingliang host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH |
97817f84b79SHauke Mehrtens SPI_LOOP;
979*ea11a8bbSYang Yingliang host->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 8) |
98017f84b79SHauke Mehrtens SPI_BPW_MASK(16) | SPI_BPW_MASK(32);
98117f84b79SHauke Mehrtens
982ba3548cfSHauke Mehrtens spi->wq = alloc_ordered_workqueue(dev_name(dev), WQ_MEM_RECLAIM);
98317f84b79SHauke Mehrtens if (!spi->wq) {
98417f84b79SHauke Mehrtens err = -ENOMEM;
98517f84b79SHauke Mehrtens goto err_clk_put;
98617f84b79SHauke Mehrtens }
98717f84b79SHauke Mehrtens INIT_WORK(&spi->work, lantiq_ssc_bussy_work);
98817f84b79SHauke Mehrtens
989ad2fca07SHauke Mehrtens id = lantiq_ssc_readl(spi, LTQ_SPI_ID);
9908743d215SDilip Kota spi->tx_fifo_size = (id >> LTQ_SPI_ID_TXFS_S) & hwcfg->fifo_size_mask;
9918743d215SDilip Kota spi->rx_fifo_size = (id >> LTQ_SPI_ID_RXFS_S) & hwcfg->fifo_size_mask;
992ad2fca07SHauke Mehrtens supports_dma = (id & LTQ_SPI_ID_CFG_M) >> LTQ_SPI_ID_CFG_S;
993ad2fca07SHauke Mehrtens revision = id & LTQ_SPI_ID_REV_M;
99417f84b79SHauke Mehrtens
99517f84b79SHauke Mehrtens lantiq_ssc_hw_init(spi);
99617f84b79SHauke Mehrtens
99717f84b79SHauke Mehrtens dev_info(dev,
99817f84b79SHauke Mehrtens "Lantiq SSC SPI controller (Rev %i, TXFS %u, RXFS %u, DMA %u)\n",
99917f84b79SHauke Mehrtens revision, spi->tx_fifo_size, spi->rx_fifo_size, supports_dma);
100017f84b79SHauke Mehrtens
1001*ea11a8bbSYang Yingliang err = devm_spi_register_controller(dev, host);
100217f84b79SHauke Mehrtens if (err) {
1003*ea11a8bbSYang Yingliang dev_err(dev, "failed to register spi host\n");
100417f84b79SHauke Mehrtens goto err_wq_destroy;
100517f84b79SHauke Mehrtens }
100617f84b79SHauke Mehrtens
100717f84b79SHauke Mehrtens return 0;
100817f84b79SHauke Mehrtens
100917f84b79SHauke Mehrtens err_wq_destroy:
101017f84b79SHauke Mehrtens destroy_workqueue(spi->wq);
101117f84b79SHauke Mehrtens err_clk_put:
101217f84b79SHauke Mehrtens clk_put(spi->fpi_clk);
101317f84b79SHauke Mehrtens err_clk_disable:
101417f84b79SHauke Mehrtens clk_disable_unprepare(spi->spi_clk);
1015*ea11a8bbSYang Yingliang err_host_put:
1016*ea11a8bbSYang Yingliang spi_controller_put(host);
101717f84b79SHauke Mehrtens
101817f84b79SHauke Mehrtens return err;
101917f84b79SHauke Mehrtens }
102017f84b79SHauke Mehrtens
lantiq_ssc_remove(struct platform_device * pdev)10211f85ed7dSUwe Kleine-König static void lantiq_ssc_remove(struct platform_device *pdev)
102217f84b79SHauke Mehrtens {
102317f84b79SHauke Mehrtens struct lantiq_ssc_spi *spi = platform_get_drvdata(pdev);
102417f84b79SHauke Mehrtens
1025ad2fca07SHauke Mehrtens lantiq_ssc_writel(spi, 0, LTQ_SPI_IRNEN);
1026ad2fca07SHauke Mehrtens lantiq_ssc_writel(spi, 0, LTQ_SPI_CLC);
102717f84b79SHauke Mehrtens rx_fifo_flush(spi);
102817f84b79SHauke Mehrtens tx_fifo_flush(spi);
102917f84b79SHauke Mehrtens hw_enter_config_mode(spi);
103017f84b79SHauke Mehrtens
103117f84b79SHauke Mehrtens destroy_workqueue(spi->wq);
103217f84b79SHauke Mehrtens clk_disable_unprepare(spi->spi_clk);
103317f84b79SHauke Mehrtens clk_put(spi->fpi_clk);
103417f84b79SHauke Mehrtens }
103517f84b79SHauke Mehrtens
103617f84b79SHauke Mehrtens static struct platform_driver lantiq_ssc_driver = {
103717f84b79SHauke Mehrtens .probe = lantiq_ssc_probe,
10381f85ed7dSUwe Kleine-König .remove_new = lantiq_ssc_remove,
103917f84b79SHauke Mehrtens .driver = {
104017f84b79SHauke Mehrtens .name = "spi-lantiq-ssc",
104117f84b79SHauke Mehrtens .of_match_table = lantiq_ssc_match,
104217f84b79SHauke Mehrtens },
104317f84b79SHauke Mehrtens };
104417f84b79SHauke Mehrtens module_platform_driver(lantiq_ssc_driver);
104517f84b79SHauke Mehrtens
104617f84b79SHauke Mehrtens MODULE_DESCRIPTION("Lantiq SSC SPI controller driver");
104717f84b79SHauke Mehrtens MODULE_AUTHOR("Daniel Schwierzeck <daniel.schwierzeck@gmail.com>");
104817f84b79SHauke Mehrtens MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
104917f84b79SHauke Mehrtens MODULE_LICENSE("GPL");
105017f84b79SHauke Mehrtens MODULE_ALIAS("platform:spi-lantiq-ssc");
1051