xref: /linux/drivers/spi/spi-omap2-mcspi.c (revision abdc5db39d7202a4038bf9041ee8b3e1ea03bc0d)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2ca632f55SGrant Likely /*
3ca632f55SGrant Likely  * OMAP2 McSPI controller driver
4ca632f55SGrant Likely  *
5ca632f55SGrant Likely  * Copyright (C) 2005, 2006 Nokia Corporation
6ca632f55SGrant Likely  * Author:	Samuel Ortiz <samuel.ortiz@nokia.com> and
7ca632f55SGrant Likely  *		Juha Yrj�l� <juha.yrjola@nokia.com>
8ca632f55SGrant Likely  */
9ca632f55SGrant Likely 
10ca632f55SGrant Likely #include <linux/kernel.h>
11ca632f55SGrant Likely #include <linux/interrupt.h>
12ca632f55SGrant Likely #include <linux/module.h>
13ca632f55SGrant Likely #include <linux/device.h>
14ca632f55SGrant Likely #include <linux/delay.h>
15ca632f55SGrant Likely #include <linux/dma-mapping.h>
1653741ed8SRussell King #include <linux/dmaengine.h>
17beca3655SPascal Huerst #include <linux/pinctrl/consumer.h>
18ca632f55SGrant Likely #include <linux/platform_device.h>
19ca632f55SGrant Likely #include <linux/err.h>
20ca632f55SGrant Likely #include <linux/clk.h>
21ca632f55SGrant Likely #include <linux/io.h>
22ca632f55SGrant Likely #include <linux/slab.h>
23ca632f55SGrant Likely #include <linux/pm_runtime.h>
24d5a80031SBenoit Cousson #include <linux/of.h>
25d5a80031SBenoit Cousson #include <linux/of_device.h>
26d33f473dSIllia Smyrnov #include <linux/gcd.h>
27ca632f55SGrant Likely 
28ca632f55SGrant Likely #include <linux/spi/spi.h>
29ca632f55SGrant Likely 
302203747cSArnd Bergmann #include <linux/platform_data/spi-omap2-mcspi.h>
31ca632f55SGrant Likely 
32ca632f55SGrant Likely #define OMAP2_MCSPI_MAX_FREQ		48000000
33faee9b05SStefan Sørensen #define OMAP2_MCSPI_MAX_DIVIDER		4096
34d33f473dSIllia Smyrnov #define OMAP2_MCSPI_MAX_FIFODEPTH	64
35d33f473dSIllia Smyrnov #define OMAP2_MCSPI_MAX_FIFOWCNT	0xFFFF
3627b5284cSShubhrajyoti D #define SPI_AUTOSUSPEND_TIMEOUT		2000
37ca632f55SGrant Likely 
38ca632f55SGrant Likely #define OMAP2_MCSPI_REVISION		0x00
39ca632f55SGrant Likely #define OMAP2_MCSPI_SYSSTATUS		0x14
40ca632f55SGrant Likely #define OMAP2_MCSPI_IRQSTATUS		0x18
41ca632f55SGrant Likely #define OMAP2_MCSPI_IRQENABLE		0x1c
42ca632f55SGrant Likely #define OMAP2_MCSPI_WAKEUPENABLE	0x20
43ca632f55SGrant Likely #define OMAP2_MCSPI_SYST		0x24
44ca632f55SGrant Likely #define OMAP2_MCSPI_MODULCTRL		0x28
45d33f473dSIllia Smyrnov #define OMAP2_MCSPI_XFERLEVEL		0x7c
46ca632f55SGrant Likely 
47ca632f55SGrant Likely /* per-channel banks, 0x14 bytes each, first is: */
48ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF0		0x2c
49ca632f55SGrant Likely #define OMAP2_MCSPI_CHSTAT0		0x30
50ca632f55SGrant Likely #define OMAP2_MCSPI_CHCTRL0		0x34
51ca632f55SGrant Likely #define OMAP2_MCSPI_TX0			0x38
52ca632f55SGrant Likely #define OMAP2_MCSPI_RX0			0x3c
53ca632f55SGrant Likely 
54ca632f55SGrant Likely /* per-register bitmasks: */
55d33f473dSIllia Smyrnov #define OMAP2_MCSPI_IRQSTATUS_EOW	BIT(17)
56ca632f55SGrant Likely 
57ca632f55SGrant Likely #define OMAP2_MCSPI_MODULCTRL_SINGLE	BIT(0)
58ca632f55SGrant Likely #define OMAP2_MCSPI_MODULCTRL_MS	BIT(2)
59ca632f55SGrant Likely #define OMAP2_MCSPI_MODULCTRL_STEST	BIT(3)
60ca632f55SGrant Likely 
61ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_PHA		BIT(0)
62ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_POL		BIT(1)
63ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_CLKD_MASK	(0x0f << 2)
64ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_EPOL		BIT(6)
65ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_WL_MASK	(0x1f << 7)
66ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_TRM_RX_ONLY	BIT(12)
67ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_TRM_TX_ONLY	BIT(13)
68ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_TRM_MASK	(0x03 << 12)
69ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_DMAW		BIT(14)
70ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_DMAR		BIT(15)
71ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_DPE0		BIT(16)
72ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_DPE1		BIT(17)
73ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_IS		BIT(18)
74ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_TURBO	BIT(19)
75ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_FORCE	BIT(20)
76d33f473dSIllia Smyrnov #define OMAP2_MCSPI_CHCONF_FFET		BIT(27)
77d33f473dSIllia Smyrnov #define OMAP2_MCSPI_CHCONF_FFER		BIT(28)
78faee9b05SStefan Sørensen #define OMAP2_MCSPI_CHCONF_CLKG		BIT(29)
79ca632f55SGrant Likely 
80ca632f55SGrant Likely #define OMAP2_MCSPI_CHSTAT_RXS		BIT(0)
81ca632f55SGrant Likely #define OMAP2_MCSPI_CHSTAT_TXS		BIT(1)
82ca632f55SGrant Likely #define OMAP2_MCSPI_CHSTAT_EOT		BIT(2)
83d33f473dSIllia Smyrnov #define OMAP2_MCSPI_CHSTAT_TXFFE	BIT(3)
84ca632f55SGrant Likely 
85ca632f55SGrant Likely #define OMAP2_MCSPI_CHCTRL_EN		BIT(0)
86faee9b05SStefan Sørensen #define OMAP2_MCSPI_CHCTRL_EXTCLK_MASK	(0xff << 8)
87ca632f55SGrant Likely 
88ca632f55SGrant Likely #define OMAP2_MCSPI_WAKEUPENABLE_WKEN	BIT(0)
89ca632f55SGrant Likely 
90ca632f55SGrant Likely /* We have 2 DMA channels per CS, one for RX and one for TX */
91ca632f55SGrant Likely struct omap2_mcspi_dma {
9253741ed8SRussell King 	struct dma_chan *dma_tx;
9353741ed8SRussell King 	struct dma_chan *dma_rx;
94ca632f55SGrant Likely 
95ca632f55SGrant Likely 	struct completion dma_tx_completion;
96ca632f55SGrant Likely 	struct completion dma_rx_completion;
9774f3aaadSMatt Porter 
9874f3aaadSMatt Porter 	char dma_rx_ch_name[14];
9974f3aaadSMatt Porter 	char dma_tx_ch_name[14];
100ca632f55SGrant Likely };
101ca632f55SGrant Likely 
102ca632f55SGrant Likely /* use PIO for small transfers, avoiding DMA setup/teardown overhead and
103ca632f55SGrant Likely  * cache operations; better heuristics consider wordsize and bitrate.
104ca632f55SGrant Likely  */
105ca632f55SGrant Likely #define DMA_MIN_BYTES			160
106ca632f55SGrant Likely 
107ca632f55SGrant Likely 
1081bd897f8SBenoit Cousson /*
1091bd897f8SBenoit Cousson  * Used for context save and restore, structure members to be updated whenever
1101bd897f8SBenoit Cousson  * corresponding registers are modified.
1111bd897f8SBenoit Cousson  */
1121bd897f8SBenoit Cousson struct omap2_mcspi_regs {
1131bd897f8SBenoit Cousson 	u32 modulctrl;
1141bd897f8SBenoit Cousson 	u32 wakeupenable;
1151bd897f8SBenoit Cousson 	struct list_head cs;
1161bd897f8SBenoit Cousson };
1171bd897f8SBenoit Cousson 
118ca632f55SGrant Likely struct omap2_mcspi {
11989e8b9cbSVignesh R 	struct completion	txdone;
120ca632f55SGrant Likely 	struct spi_master	*master;
121ca632f55SGrant Likely 	/* Virtual base address of the controller */
122ca632f55SGrant Likely 	void __iomem		*base;
123ca632f55SGrant Likely 	unsigned long		phys;
124ca632f55SGrant Likely 	/* SPI1 has 4 channels, while SPI2 has 2 */
125ca632f55SGrant Likely 	struct omap2_mcspi_dma	*dma_channels;
126ca632f55SGrant Likely 	struct device		*dev;
1271bd897f8SBenoit Cousson 	struct omap2_mcspi_regs ctx;
128d33f473dSIllia Smyrnov 	int			fifo_depth;
12989e8b9cbSVignesh R 	bool			slave_aborted;
1300384e90bSDaniel Mack 	unsigned int		pin_dir:1;
131e4e8276aSVignesh Raghavendra 	size_t			max_xfer_len;
132ca632f55SGrant Likely };
133ca632f55SGrant Likely 
134ca632f55SGrant Likely struct omap2_mcspi_cs {
135ca632f55SGrant Likely 	void __iomem		*base;
136ca632f55SGrant Likely 	unsigned long		phys;
137ca632f55SGrant Likely 	int			word_len;
13897ca0d6cSMark A. Greer 	u16			mode;
139ca632f55SGrant Likely 	struct list_head	node;
140ca632f55SGrant Likely 	/* Context save and restore shadow register */
141faee9b05SStefan Sørensen 	u32			chconf0, chctrl0;
142ca632f55SGrant Likely };
143ca632f55SGrant Likely 
144ca632f55SGrant Likely static inline void mcspi_write_reg(struct spi_master *master,
145ca632f55SGrant Likely 		int idx, u32 val)
146ca632f55SGrant Likely {
147ca632f55SGrant Likely 	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
148ca632f55SGrant Likely 
14921b2ce5eSVictor Kamensky 	writel_relaxed(val, mcspi->base + idx);
150ca632f55SGrant Likely }
151ca632f55SGrant Likely 
152ca632f55SGrant Likely static inline u32 mcspi_read_reg(struct spi_master *master, int idx)
153ca632f55SGrant Likely {
154ca632f55SGrant Likely 	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
155ca632f55SGrant Likely 
15621b2ce5eSVictor Kamensky 	return readl_relaxed(mcspi->base + idx);
157ca632f55SGrant Likely }
158ca632f55SGrant Likely 
159ca632f55SGrant Likely static inline void mcspi_write_cs_reg(const struct spi_device *spi,
160ca632f55SGrant Likely 		int idx, u32 val)
161ca632f55SGrant Likely {
162ca632f55SGrant Likely 	struct omap2_mcspi_cs	*cs = spi->controller_state;
163ca632f55SGrant Likely 
16421b2ce5eSVictor Kamensky 	writel_relaxed(val, cs->base +  idx);
165ca632f55SGrant Likely }
166ca632f55SGrant Likely 
167ca632f55SGrant Likely static inline u32 mcspi_read_cs_reg(const struct spi_device *spi, int idx)
168ca632f55SGrant Likely {
169ca632f55SGrant Likely 	struct omap2_mcspi_cs	*cs = spi->controller_state;
170ca632f55SGrant Likely 
17121b2ce5eSVictor Kamensky 	return readl_relaxed(cs->base + idx);
172ca632f55SGrant Likely }
173ca632f55SGrant Likely 
174ca632f55SGrant Likely static inline u32 mcspi_cached_chconf0(const struct spi_device *spi)
175ca632f55SGrant Likely {
176ca632f55SGrant Likely 	struct omap2_mcspi_cs *cs = spi->controller_state;
177ca632f55SGrant Likely 
178ca632f55SGrant Likely 	return cs->chconf0;
179ca632f55SGrant Likely }
180ca632f55SGrant Likely 
181ca632f55SGrant Likely static inline void mcspi_write_chconf0(const struct spi_device *spi, u32 val)
182ca632f55SGrant Likely {
183ca632f55SGrant Likely 	struct omap2_mcspi_cs *cs = spi->controller_state;
184ca632f55SGrant Likely 
185ca632f55SGrant Likely 	cs->chconf0 = val;
186ca632f55SGrant Likely 	mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, val);
187ca632f55SGrant Likely 	mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
188ca632f55SGrant Likely }
189ca632f55SGrant Likely 
19056cd5c15SIllia Smyrnov static inline int mcspi_bytes_per_word(int word_len)
19156cd5c15SIllia Smyrnov {
19256cd5c15SIllia Smyrnov 	if (word_len <= 8)
19356cd5c15SIllia Smyrnov 		return 1;
19456cd5c15SIllia Smyrnov 	else if (word_len <= 16)
19556cd5c15SIllia Smyrnov 		return 2;
19656cd5c15SIllia Smyrnov 	else /* word_len <= 32 */
19756cd5c15SIllia Smyrnov 		return 4;
19856cd5c15SIllia Smyrnov }
19956cd5c15SIllia Smyrnov 
200ca632f55SGrant Likely static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
201ca632f55SGrant Likely 		int is_read, int enable)
202ca632f55SGrant Likely {
203ca632f55SGrant Likely 	u32 l, rw;
204ca632f55SGrant Likely 
205ca632f55SGrant Likely 	l = mcspi_cached_chconf0(spi);
206ca632f55SGrant Likely 
207ca632f55SGrant Likely 	if (is_read) /* 1 is read, 0 write */
208ca632f55SGrant Likely 		rw = OMAP2_MCSPI_CHCONF_DMAR;
209ca632f55SGrant Likely 	else
210ca632f55SGrant Likely 		rw = OMAP2_MCSPI_CHCONF_DMAW;
211ca632f55SGrant Likely 
212af4e944dSShubhrajyoti D 	if (enable)
213af4e944dSShubhrajyoti D 		l |= rw;
214af4e944dSShubhrajyoti D 	else
215af4e944dSShubhrajyoti D 		l &= ~rw;
216af4e944dSShubhrajyoti D 
217ca632f55SGrant Likely 	mcspi_write_chconf0(spi, l);
218ca632f55SGrant Likely }
219ca632f55SGrant Likely 
220ca632f55SGrant Likely static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
221ca632f55SGrant Likely {
222faee9b05SStefan Sørensen 	struct omap2_mcspi_cs *cs = spi->controller_state;
223ca632f55SGrant Likely 	u32 l;
224ca632f55SGrant Likely 
225faee9b05SStefan Sørensen 	l = cs->chctrl0;
226faee9b05SStefan Sørensen 	if (enable)
227faee9b05SStefan Sørensen 		l |= OMAP2_MCSPI_CHCTRL_EN;
228faee9b05SStefan Sørensen 	else
229faee9b05SStefan Sørensen 		l &= ~OMAP2_MCSPI_CHCTRL_EN;
230faee9b05SStefan Sørensen 	cs->chctrl0 = l;
231faee9b05SStefan Sørensen 	mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0);
232ca632f55SGrant Likely 	/* Flash post-writes */
233ca632f55SGrant Likely 	mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0);
234ca632f55SGrant Likely }
235ca632f55SGrant Likely 
236ddcad7e9SMichael Welling static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
237ca632f55SGrant Likely {
2385f74db10SSebastian Reichel 	struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
239ca632f55SGrant Likely 	u32 l;
240ca632f55SGrant Likely 
2414373f8b6SMichael Welling 	/* The controller handles the inverted chip selects
2424373f8b6SMichael Welling 	 * using the OMAP2_MCSPI_CHCONF_EPOL bit so revert
2434373f8b6SMichael Welling 	 * the inversion from the core spi_set_cs function.
2444373f8b6SMichael Welling 	 */
2454373f8b6SMichael Welling 	if (spi->mode & SPI_CS_HIGH)
2464373f8b6SMichael Welling 		enable = !enable;
2474373f8b6SMichael Welling 
248ddcad7e9SMichael Welling 	if (spi->controller_state) {
2495f74db10SSebastian Reichel 		int err = pm_runtime_get_sync(mcspi->dev);
2505f74db10SSebastian Reichel 		if (err < 0) {
2515a686b2cSTony Lindgren 			pm_runtime_put_noidle(mcspi->dev);
2525f74db10SSebastian Reichel 			dev_err(mcspi->dev, "failed to get sync: %d\n", err);
2535f74db10SSebastian Reichel 			return;
2545f74db10SSebastian Reichel 		}
2555f74db10SSebastian Reichel 
256ca632f55SGrant Likely 		l = mcspi_cached_chconf0(spi);
257ddcad7e9SMichael Welling 
258ddcad7e9SMichael Welling 		if (enable)
259af4e944dSShubhrajyoti D 			l &= ~OMAP2_MCSPI_CHCONF_FORCE;
260ddcad7e9SMichael Welling 		else
261ddcad7e9SMichael Welling 			l |= OMAP2_MCSPI_CHCONF_FORCE;
262af4e944dSShubhrajyoti D 
263ca632f55SGrant Likely 		mcspi_write_chconf0(spi, l);
2645f74db10SSebastian Reichel 
2655f74db10SSebastian Reichel 		pm_runtime_mark_last_busy(mcspi->dev);
2665f74db10SSebastian Reichel 		pm_runtime_put_autosuspend(mcspi->dev);
267ca632f55SGrant Likely 	}
268ddcad7e9SMichael Welling }
269ca632f55SGrant Likely 
27089e8b9cbSVignesh R static void omap2_mcspi_set_mode(struct spi_master *master)
271ca632f55SGrant Likely {
2721bd897f8SBenoit Cousson 	struct omap2_mcspi	*mcspi = spi_master_get_devdata(master);
2731bd897f8SBenoit Cousson 	struct omap2_mcspi_regs	*ctx = &mcspi->ctx;
274ca632f55SGrant Likely 	u32 l;
275ca632f55SGrant Likely 
2761bd897f8SBenoit Cousson 	/*
27789e8b9cbSVignesh R 	 * Choose master or slave mode
278ca632f55SGrant Likely 	 */
279ca632f55SGrant Likely 	l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL);
28089e8b9cbSVignesh R 	l &= ~(OMAP2_MCSPI_MODULCTRL_STEST);
28189e8b9cbSVignesh R 	if (spi_controller_is_slave(master)) {
28289e8b9cbSVignesh R 		l |= (OMAP2_MCSPI_MODULCTRL_MS);
28389e8b9cbSVignesh R 	} else {
28489e8b9cbSVignesh R 		l &= ~(OMAP2_MCSPI_MODULCTRL_MS);
285af4e944dSShubhrajyoti D 		l |= OMAP2_MCSPI_MODULCTRL_SINGLE;
28689e8b9cbSVignesh R 	}
287ca632f55SGrant Likely 	mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l);
288ca632f55SGrant Likely 
2891bd897f8SBenoit Cousson 	ctx->modulctrl = l;
290ca632f55SGrant Likely }
291ca632f55SGrant Likely 
292d33f473dSIllia Smyrnov static void omap2_mcspi_set_fifo(const struct spi_device *spi,
293d33f473dSIllia Smyrnov 				struct spi_transfer *t, int enable)
294d33f473dSIllia Smyrnov {
295d33f473dSIllia Smyrnov 	struct spi_master *master = spi->master;
296d33f473dSIllia Smyrnov 	struct omap2_mcspi_cs *cs = spi->controller_state;
297d33f473dSIllia Smyrnov 	struct omap2_mcspi *mcspi;
298d33f473dSIllia Smyrnov 	unsigned int wcnt;
299b682cffaSVignesh R 	int max_fifo_depth, bytes_per_word;
300d33f473dSIllia Smyrnov 	u32 chconf, xferlevel;
301d33f473dSIllia Smyrnov 
302d33f473dSIllia Smyrnov 	mcspi = spi_master_get_devdata(master);
303d33f473dSIllia Smyrnov 
304d33f473dSIllia Smyrnov 	chconf = mcspi_cached_chconf0(spi);
305d33f473dSIllia Smyrnov 	if (enable) {
306d33f473dSIllia Smyrnov 		bytes_per_word = mcspi_bytes_per_word(cs->word_len);
307d33f473dSIllia Smyrnov 		if (t->len % bytes_per_word != 0)
308d33f473dSIllia Smyrnov 			goto disable_fifo;
309d33f473dSIllia Smyrnov 
3105db542edSIllia Smyrnov 		if (t->rx_buf != NULL && t->tx_buf != NULL)
3115db542edSIllia Smyrnov 			max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH / 2;
3125db542edSIllia Smyrnov 		else
3135db542edSIllia Smyrnov 			max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH;
3145db542edSIllia Smyrnov 
315d33f473dSIllia Smyrnov 		wcnt = t->len / bytes_per_word;
316d33f473dSIllia Smyrnov 		if (wcnt > OMAP2_MCSPI_MAX_FIFOWCNT)
317d33f473dSIllia Smyrnov 			goto disable_fifo;
318d33f473dSIllia Smyrnov 
319d33f473dSIllia Smyrnov 		xferlevel = wcnt << 16;
320d33f473dSIllia Smyrnov 		if (t->rx_buf != NULL) {
321d33f473dSIllia Smyrnov 			chconf |= OMAP2_MCSPI_CHCONF_FFER;
322b682cffaSVignesh R 			xferlevel |= (bytes_per_word - 1) << 8;
3235db542edSIllia Smyrnov 		}
324b682cffaSVignesh R 
3255db542edSIllia Smyrnov 		if (t->tx_buf != NULL) {
326d33f473dSIllia Smyrnov 			chconf |= OMAP2_MCSPI_CHCONF_FFET;
327b682cffaSVignesh R 			xferlevel |= bytes_per_word - 1;
328d33f473dSIllia Smyrnov 		}
329d33f473dSIllia Smyrnov 
330d33f473dSIllia Smyrnov 		mcspi_write_reg(master, OMAP2_MCSPI_XFERLEVEL, xferlevel);
331d33f473dSIllia Smyrnov 		mcspi_write_chconf0(spi, chconf);
332b682cffaSVignesh R 		mcspi->fifo_depth = max_fifo_depth;
333d33f473dSIllia Smyrnov 
334d33f473dSIllia Smyrnov 		return;
335d33f473dSIllia Smyrnov 	}
336d33f473dSIllia Smyrnov 
337d33f473dSIllia Smyrnov disable_fifo:
338d33f473dSIllia Smyrnov 	if (t->rx_buf != NULL)
339d33f473dSIllia Smyrnov 		chconf &= ~OMAP2_MCSPI_CHCONF_FFER;
3403d0763c0SJorge A. Ventura 
3413d0763c0SJorge A. Ventura 	if (t->tx_buf != NULL)
342d33f473dSIllia Smyrnov 		chconf &= ~OMAP2_MCSPI_CHCONF_FFET;
343d33f473dSIllia Smyrnov 
344d33f473dSIllia Smyrnov 	mcspi_write_chconf0(spi, chconf);
345d33f473dSIllia Smyrnov 	mcspi->fifo_depth = 0;
346d33f473dSIllia Smyrnov }
347d33f473dSIllia Smyrnov 
348ca632f55SGrant Likely static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
349ca632f55SGrant Likely {
3507b1d9681SAswath Govindraju 	unsigned long timeout;
351ca632f55SGrant Likely 
3527b1d9681SAswath Govindraju 	timeout = jiffies + msecs_to_jiffies(1000);
3537b1d9681SAswath Govindraju 	while (!(readl_relaxed(reg) & bit)) {
3547b1d9681SAswath Govindraju 		if (time_after(jiffies, timeout)) {
3557b1d9681SAswath Govindraju 			if (!(readl_relaxed(reg) & bit))
3567b1d9681SAswath Govindraju 				return -ETIMEDOUT;
3577b1d9681SAswath Govindraju 			else
3587b1d9681SAswath Govindraju 				return 0;
3597b1d9681SAswath Govindraju 		}
3607b1d9681SAswath Govindraju 		cpu_relax();
3617b1d9681SAswath Govindraju 	}
3627b1d9681SAswath Govindraju 	return 0;
363ca632f55SGrant Likely }
364ca632f55SGrant Likely 
36589e8b9cbSVignesh R static int mcspi_wait_for_completion(struct  omap2_mcspi *mcspi,
36689e8b9cbSVignesh R 				     struct completion *x)
36789e8b9cbSVignesh R {
36889e8b9cbSVignesh R 	if (spi_controller_is_slave(mcspi->master)) {
36989e8b9cbSVignesh R 		if (wait_for_completion_interruptible(x) ||
37089e8b9cbSVignesh R 		    mcspi->slave_aborted)
37189e8b9cbSVignesh R 			return -EINTR;
37289e8b9cbSVignesh R 	} else {
37389e8b9cbSVignesh R 		wait_for_completion(x);
37489e8b9cbSVignesh R 	}
37589e8b9cbSVignesh R 
37689e8b9cbSVignesh R 	return 0;
37789e8b9cbSVignesh R }
37889e8b9cbSVignesh R 
37953741ed8SRussell King static void omap2_mcspi_rx_callback(void *data)
38053741ed8SRussell King {
38153741ed8SRussell King 	struct spi_device *spi = data;
38253741ed8SRussell King 	struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
38353741ed8SRussell King 	struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select];
38453741ed8SRussell King 
38553741ed8SRussell King 	/* We must disable the DMA RX request */
38653741ed8SRussell King 	omap2_mcspi_set_dma_req(spi, 1, 0);
387830379e0SFelipe Balbi 
388830379e0SFelipe Balbi 	complete(&mcspi_dma->dma_rx_completion);
38953741ed8SRussell King }
39053741ed8SRussell King 
39153741ed8SRussell King static void omap2_mcspi_tx_callback(void *data)
39253741ed8SRussell King {
39353741ed8SRussell King 	struct spi_device *spi = data;
39453741ed8SRussell King 	struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
39553741ed8SRussell King 	struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select];
39653741ed8SRussell King 
39753741ed8SRussell King 	/* We must disable the DMA TX request */
39853741ed8SRussell King 	omap2_mcspi_set_dma_req(spi, 0, 0);
399830379e0SFelipe Balbi 
400830379e0SFelipe Balbi 	complete(&mcspi_dma->dma_tx_completion);
40153741ed8SRussell King }
40253741ed8SRussell King 
403d7b4394eSShubhrajyoti D static void omap2_mcspi_tx_dma(struct spi_device *spi,
404d7b4394eSShubhrajyoti D 				struct spi_transfer *xfer,
405d7b4394eSShubhrajyoti D 				struct dma_slave_config cfg)
406ca632f55SGrant Likely {
407ca632f55SGrant Likely 	struct omap2_mcspi	*mcspi;
408ca632f55SGrant Likely 	struct omap2_mcspi_dma  *mcspi_dma;
4098d858491SVignesh Raghavendra 	struct dma_async_tx_descriptor *tx;
410ca632f55SGrant Likely 
411ca632f55SGrant Likely 	mcspi = spi_master_get_devdata(spi->master);
412ca632f55SGrant Likely 	mcspi_dma = &mcspi->dma_channels[spi->chip_select];
413ca632f55SGrant Likely 
41453741ed8SRussell King 	dmaengine_slave_config(mcspi_dma->dma_tx, &cfg);
41553741ed8SRussell King 
4160ba1870fSFranklin S Cooper Jr 	tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, xfer->tx_sg.sgl,
4170ba1870fSFranklin S Cooper Jr 				     xfer->tx_sg.nents,
4180ba1870fSFranklin S Cooper Jr 				     DMA_MEM_TO_DEV,
4190ba1870fSFranklin S Cooper Jr 				     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
42053741ed8SRussell King 	if (tx) {
42153741ed8SRussell King 		tx->callback = omap2_mcspi_tx_callback;
42253741ed8SRussell King 		tx->callback_param = spi;
42353741ed8SRussell King 		dmaengine_submit(tx);
42453741ed8SRussell King 	} else {
42553741ed8SRussell King 		/* FIXME: fall back to PIO? */
42653741ed8SRussell King 	}
42753741ed8SRussell King 	dma_async_issue_pending(mcspi_dma->dma_tx);
428ca632f55SGrant Likely 	omap2_mcspi_set_dma_req(spi, 0, 1);
429ca632f55SGrant Likely }
430ca632f55SGrant Likely 
431d7b4394eSShubhrajyoti D static unsigned
432d7b4394eSShubhrajyoti D omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
433d7b4394eSShubhrajyoti D 				struct dma_slave_config cfg,
434d7b4394eSShubhrajyoti D 				unsigned es)
435d7b4394eSShubhrajyoti D {
436d7b4394eSShubhrajyoti D 	struct omap2_mcspi	*mcspi;
437d7b4394eSShubhrajyoti D 	struct omap2_mcspi_dma  *mcspi_dma;
4380ba1870fSFranklin S Cooper Jr 	unsigned int		count, transfer_reduction = 0;
4390ba1870fSFranklin S Cooper Jr 	struct scatterlist	*sg_out[2];
4400ba1870fSFranklin S Cooper Jr 	int			nb_sizes = 0, out_mapped_nents[2], ret, x;
4410ba1870fSFranklin S Cooper Jr 	size_t			sizes[2];
442d7b4394eSShubhrajyoti D 	u32			l;
443d7b4394eSShubhrajyoti D 	int			elements = 0;
444d7b4394eSShubhrajyoti D 	int			word_len, element_count;
445d7b4394eSShubhrajyoti D 	struct omap2_mcspi_cs	*cs = spi->controller_state;
44681261359SAkinobu Mita 	void __iomem		*chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
4478d858491SVignesh Raghavendra 	struct dma_async_tx_descriptor *tx;
44881261359SAkinobu Mita 
449d7b4394eSShubhrajyoti D 	mcspi = spi_master_get_devdata(spi->master);
450d7b4394eSShubhrajyoti D 	mcspi_dma = &mcspi->dma_channels[spi->chip_select];
451d7b4394eSShubhrajyoti D 	count = xfer->len;
452d33f473dSIllia Smyrnov 
4534bd00413SFranklin S Cooper Jr 	/*
4544bd00413SFranklin S Cooper Jr 	 *  In the "End-of-Transfer Procedure" section for DMA RX in OMAP35x TRM
4554bd00413SFranklin S Cooper Jr 	 *  it mentions reducing DMA transfer length by one element in master
4564bd00413SFranklin S Cooper Jr 	 *  normal mode.
4574bd00413SFranklin S Cooper Jr 	 */
458d33f473dSIllia Smyrnov 	if (mcspi->fifo_depth == 0)
4590ba1870fSFranklin S Cooper Jr 		transfer_reduction = es;
460d33f473dSIllia Smyrnov 
461d7b4394eSShubhrajyoti D 	word_len = cs->word_len;
462d7b4394eSShubhrajyoti D 	l = mcspi_cached_chconf0(spi);
463d7b4394eSShubhrajyoti D 
464d7b4394eSShubhrajyoti D 	if (word_len <= 8)
465d7b4394eSShubhrajyoti D 		element_count = count;
466d7b4394eSShubhrajyoti D 	else if (word_len <= 16)
467d7b4394eSShubhrajyoti D 		element_count = count >> 1;
468d7b4394eSShubhrajyoti D 	else /* word_len <= 32 */
469d7b4394eSShubhrajyoti D 		element_count = count >> 2;
470d7b4394eSShubhrajyoti D 
471d7b4394eSShubhrajyoti D 
472d7b4394eSShubhrajyoti D 	dmaengine_slave_config(mcspi_dma->dma_rx, &cfg);
473d7b4394eSShubhrajyoti D 
4744bd00413SFranklin S Cooper Jr 	/*
4754bd00413SFranklin S Cooper Jr 	 *  Reduce DMA transfer length by one more if McSPI is
4764bd00413SFranklin S Cooper Jr 	 *  configured in turbo mode.
4774bd00413SFranklin S Cooper Jr 	 */
478d33f473dSIllia Smyrnov 	if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0)
4790ba1870fSFranklin S Cooper Jr 		transfer_reduction += es;
480d7b4394eSShubhrajyoti D 
4810ba1870fSFranklin S Cooper Jr 	if (transfer_reduction) {
4820ba1870fSFranklin S Cooper Jr 		/* Split sgl into two. The second sgl won't be used. */
4830ba1870fSFranklin S Cooper Jr 		sizes[0] = count - transfer_reduction;
4840ba1870fSFranklin S Cooper Jr 		sizes[1] = transfer_reduction;
4850ba1870fSFranklin S Cooper Jr 		nb_sizes = 2;
4860ba1870fSFranklin S Cooper Jr 	} else {
4870ba1870fSFranklin S Cooper Jr 		/*
4880ba1870fSFranklin S Cooper Jr 		 * Don't bother splitting the sgl. This essentially
4890ba1870fSFranklin S Cooper Jr 		 * clones the original sgl.
4900ba1870fSFranklin S Cooper Jr 		 */
4910ba1870fSFranklin S Cooper Jr 		sizes[0] = count;
4920ba1870fSFranklin S Cooper Jr 		nb_sizes = 1;
4930ba1870fSFranklin S Cooper Jr 	}
494d7b4394eSShubhrajyoti D 
4958d858491SVignesh Raghavendra 	ret = sg_split(xfer->rx_sg.sgl, xfer->rx_sg.nents, 0, nb_sizes,
4968d858491SVignesh Raghavendra 		       sizes, sg_out, out_mapped_nents, GFP_KERNEL);
4970ba1870fSFranklin S Cooper Jr 
4980ba1870fSFranklin S Cooper Jr 	if (ret < 0) {
4990ba1870fSFranklin S Cooper Jr 		dev_err(&spi->dev, "sg_split failed\n");
5000ba1870fSFranklin S Cooper Jr 		return 0;
5010ba1870fSFranklin S Cooper Jr 	}
5020ba1870fSFranklin S Cooper Jr 
5038d858491SVignesh Raghavendra 	tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, sg_out[0],
5048d858491SVignesh Raghavendra 				     out_mapped_nents[0], DMA_DEV_TO_MEM,
5050ba1870fSFranklin S Cooper Jr 				     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
506d7b4394eSShubhrajyoti D 	if (tx) {
507d7b4394eSShubhrajyoti D 		tx->callback = omap2_mcspi_rx_callback;
508d7b4394eSShubhrajyoti D 		tx->callback_param = spi;
509d7b4394eSShubhrajyoti D 		dmaengine_submit(tx);
510d7b4394eSShubhrajyoti D 	} else {
511d7b4394eSShubhrajyoti D 		/* FIXME: fall back to PIO? */
512d7b4394eSShubhrajyoti D 	}
513d7b4394eSShubhrajyoti D 
514d7b4394eSShubhrajyoti D 	dma_async_issue_pending(mcspi_dma->dma_rx);
515d7b4394eSShubhrajyoti D 	omap2_mcspi_set_dma_req(spi, 1, 1);
516d7b4394eSShubhrajyoti D 
51789e8b9cbSVignesh R 	ret = mcspi_wait_for_completion(mcspi, &mcspi_dma->dma_rx_completion);
51889e8b9cbSVignesh R 	if (ret || mcspi->slave_aborted) {
51989e8b9cbSVignesh R 		dmaengine_terminate_sync(mcspi_dma->dma_rx);
52089e8b9cbSVignesh R 		omap2_mcspi_set_dma_req(spi, 1, 0);
52189e8b9cbSVignesh R 		return 0;
52289e8b9cbSVignesh R 	}
5230ba1870fSFranklin S Cooper Jr 
5240ba1870fSFranklin S Cooper Jr 	for (x = 0; x < nb_sizes; x++)
5250ba1870fSFranklin S Cooper Jr 		kfree(sg_out[x]);
526d33f473dSIllia Smyrnov 
527d33f473dSIllia Smyrnov 	if (mcspi->fifo_depth > 0)
528d33f473dSIllia Smyrnov 		return count;
529d33f473dSIllia Smyrnov 
5304bd00413SFranklin S Cooper Jr 	/*
5314bd00413SFranklin S Cooper Jr 	 *  Due to the DMA transfer length reduction the missing bytes must
5324bd00413SFranklin S Cooper Jr 	 *  be read manually to receive all of the expected data.
5334bd00413SFranklin S Cooper Jr 	 */
534ca632f55SGrant Likely 	omap2_mcspi_set_enable(spi, 0);
535ca632f55SGrant Likely 
53653741ed8SRussell King 	elements = element_count - 1;
53753741ed8SRussell King 
538ca632f55SGrant Likely 	if (l & OMAP2_MCSPI_CHCONF_TURBO) {
53953741ed8SRussell King 		elements--;
540ca632f55SGrant Likely 
54181261359SAkinobu Mita 		if (!mcspi_wait_for_reg_bit(chstat_reg,
54281261359SAkinobu Mita 					    OMAP2_MCSPI_CHSTAT_RXS)) {
543ca632f55SGrant Likely 			u32 w;
544ca632f55SGrant Likely 
545ca632f55SGrant Likely 			w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
546ca632f55SGrant Likely 			if (word_len <= 8)
547ca632f55SGrant Likely 				((u8 *)xfer->rx_buf)[elements++] = w;
548ca632f55SGrant Likely 			else if (word_len <= 16)
549ca632f55SGrant Likely 				((u16 *)xfer->rx_buf)[elements++] = w;
550ca632f55SGrant Likely 			else /* word_len <= 32 */
551ca632f55SGrant Likely 				((u32 *)xfer->rx_buf)[elements++] = w;
552ca632f55SGrant Likely 		} else {
55356cd5c15SIllia Smyrnov 			int bytes_per_word = mcspi_bytes_per_word(word_len);
554a1829d2bSJarkko Nikula 			dev_err(&spi->dev, "DMA RX penultimate word empty\n");
55556cd5c15SIllia Smyrnov 			count -= (bytes_per_word << 1);
556ca632f55SGrant Likely 			omap2_mcspi_set_enable(spi, 1);
557ca632f55SGrant Likely 			return count;
558ca632f55SGrant Likely 		}
559ca632f55SGrant Likely 	}
56081261359SAkinobu Mita 	if (!mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_RXS)) {
561ca632f55SGrant Likely 		u32 w;
562ca632f55SGrant Likely 
563ca632f55SGrant Likely 		w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
564ca632f55SGrant Likely 		if (word_len <= 8)
565ca632f55SGrant Likely 			((u8 *)xfer->rx_buf)[elements] = w;
566ca632f55SGrant Likely 		else if (word_len <= 16)
567ca632f55SGrant Likely 			((u16 *)xfer->rx_buf)[elements] = w;
568ca632f55SGrant Likely 		else /* word_len <= 32 */
569ca632f55SGrant Likely 			((u32 *)xfer->rx_buf)[elements] = w;
570ca632f55SGrant Likely 	} else {
571a1829d2bSJarkko Nikula 		dev_err(&spi->dev, "DMA RX last word empty\n");
57256cd5c15SIllia Smyrnov 		count -= mcspi_bytes_per_word(word_len);
573ca632f55SGrant Likely 	}
574ca632f55SGrant Likely 	omap2_mcspi_set_enable(spi, 1);
575d7b4394eSShubhrajyoti D 	return count;
576ca632f55SGrant Likely }
577d7b4394eSShubhrajyoti D 
578d7b4394eSShubhrajyoti D static unsigned
579d7b4394eSShubhrajyoti D omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
580d7b4394eSShubhrajyoti D {
581d7b4394eSShubhrajyoti D 	struct omap2_mcspi	*mcspi;
582d7b4394eSShubhrajyoti D 	struct omap2_mcspi_cs	*cs = spi->controller_state;
583d7b4394eSShubhrajyoti D 	struct omap2_mcspi_dma  *mcspi_dma;
584d7b4394eSShubhrajyoti D 	unsigned int		count;
585d7b4394eSShubhrajyoti D 	u8			*rx;
586d7b4394eSShubhrajyoti D 	const u8		*tx;
587d7b4394eSShubhrajyoti D 	struct dma_slave_config	cfg;
588d7b4394eSShubhrajyoti D 	enum dma_slave_buswidth width;
589d7b4394eSShubhrajyoti D 	unsigned es;
590e47a682aSShubhrajyoti D 	void __iomem		*chstat_reg;
591d33f473dSIllia Smyrnov 	void __iomem            *irqstat_reg;
592d33f473dSIllia Smyrnov 	int			wait_res;
593d7b4394eSShubhrajyoti D 
594d7b4394eSShubhrajyoti D 	mcspi = spi_master_get_devdata(spi->master);
595d7b4394eSShubhrajyoti D 	mcspi_dma = &mcspi->dma_channels[spi->chip_select];
596d7b4394eSShubhrajyoti D 
597d7b4394eSShubhrajyoti D 	if (cs->word_len <= 8) {
598d7b4394eSShubhrajyoti D 		width = DMA_SLAVE_BUSWIDTH_1_BYTE;
599d7b4394eSShubhrajyoti D 		es = 1;
600d7b4394eSShubhrajyoti D 	} else if (cs->word_len <= 16) {
601d7b4394eSShubhrajyoti D 		width = DMA_SLAVE_BUSWIDTH_2_BYTES;
602d7b4394eSShubhrajyoti D 		es = 2;
603d7b4394eSShubhrajyoti D 	} else {
604d7b4394eSShubhrajyoti D 		width = DMA_SLAVE_BUSWIDTH_4_BYTES;
605d7b4394eSShubhrajyoti D 		es = 4;
606d7b4394eSShubhrajyoti D 	}
607d7b4394eSShubhrajyoti D 
608d33f473dSIllia Smyrnov 	count = xfer->len;
609d33f473dSIllia Smyrnov 
610d7b4394eSShubhrajyoti D 	memset(&cfg, 0, sizeof(cfg));
611d7b4394eSShubhrajyoti D 	cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0;
612d7b4394eSShubhrajyoti D 	cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0;
613d7b4394eSShubhrajyoti D 	cfg.src_addr_width = width;
614d7b4394eSShubhrajyoti D 	cfg.dst_addr_width = width;
615baf8b9f8SVignesh R 	cfg.src_maxburst = 1;
616baf8b9f8SVignesh R 	cfg.dst_maxburst = 1;
617d7b4394eSShubhrajyoti D 
618d7b4394eSShubhrajyoti D 	rx = xfer->rx_buf;
619d7b4394eSShubhrajyoti D 	tx = xfer->tx_buf;
620d7b4394eSShubhrajyoti D 
62189e8b9cbSVignesh R 	mcspi->slave_aborted = false;
62289e8b9cbSVignesh R 	reinit_completion(&mcspi_dma->dma_tx_completion);
62389e8b9cbSVignesh R 	reinit_completion(&mcspi_dma->dma_rx_completion);
62489e8b9cbSVignesh R 	reinit_completion(&mcspi->txdone);
62589e8b9cbSVignesh R 	if (tx) {
62689e8b9cbSVignesh R 		/* Enable EOW IRQ to know end of tx in slave mode */
62789e8b9cbSVignesh R 		if (spi_controller_is_slave(spi->master))
62889e8b9cbSVignesh R 			mcspi_write_reg(spi->master,
62989e8b9cbSVignesh R 					OMAP2_MCSPI_IRQENABLE,
63089e8b9cbSVignesh R 					OMAP2_MCSPI_IRQSTATUS_EOW);
631d7b4394eSShubhrajyoti D 		omap2_mcspi_tx_dma(spi, xfer, cfg);
63289e8b9cbSVignesh R 	}
633d7b4394eSShubhrajyoti D 
634d7b4394eSShubhrajyoti D 	if (rx != NULL)
635e47a682aSShubhrajyoti D 		count = omap2_mcspi_rx_dma(spi, xfer, cfg, es);
636d7b4394eSShubhrajyoti D 
637e47a682aSShubhrajyoti D 	if (tx != NULL) {
63889e8b9cbSVignesh R 		int ret;
63989e8b9cbSVignesh R 
64089e8b9cbSVignesh R 		ret = mcspi_wait_for_completion(mcspi, &mcspi_dma->dma_tx_completion);
64189e8b9cbSVignesh R 		if (ret || mcspi->slave_aborted) {
64289e8b9cbSVignesh R 			dmaengine_terminate_sync(mcspi_dma->dma_tx);
64389e8b9cbSVignesh R 			omap2_mcspi_set_dma_req(spi, 0, 0);
64489e8b9cbSVignesh R 			return 0;
64589e8b9cbSVignesh R 		}
64689e8b9cbSVignesh R 
64789e8b9cbSVignesh R 		if (spi_controller_is_slave(mcspi->master)) {
64889e8b9cbSVignesh R 			ret = mcspi_wait_for_completion(mcspi, &mcspi->txdone);
64989e8b9cbSVignesh R 			if (ret || mcspi->slave_aborted)
65089e8b9cbSVignesh R 				return 0;
65189e8b9cbSVignesh R 		}
652e47a682aSShubhrajyoti D 
653d33f473dSIllia Smyrnov 		if (mcspi->fifo_depth > 0) {
654d33f473dSIllia Smyrnov 			irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS;
655d33f473dSIllia Smyrnov 
656d33f473dSIllia Smyrnov 			if (mcspi_wait_for_reg_bit(irqstat_reg,
657d33f473dSIllia Smyrnov 						OMAP2_MCSPI_IRQSTATUS_EOW) < 0)
658d33f473dSIllia Smyrnov 				dev_err(&spi->dev, "EOW timed out\n");
659d33f473dSIllia Smyrnov 
660d33f473dSIllia Smyrnov 			mcspi_write_reg(mcspi->master, OMAP2_MCSPI_IRQSTATUS,
661d33f473dSIllia Smyrnov 					OMAP2_MCSPI_IRQSTATUS_EOW);
662d33f473dSIllia Smyrnov 		}
663d33f473dSIllia Smyrnov 
664e47a682aSShubhrajyoti D 		/* for TX_ONLY mode, be sure all words have shifted out */
665e47a682aSShubhrajyoti D 		if (rx == NULL) {
666d33f473dSIllia Smyrnov 			chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
667d33f473dSIllia Smyrnov 			if (mcspi->fifo_depth > 0) {
668d33f473dSIllia Smyrnov 				wait_res = mcspi_wait_for_reg_bit(chstat_reg,
669d33f473dSIllia Smyrnov 						OMAP2_MCSPI_CHSTAT_TXFFE);
670d33f473dSIllia Smyrnov 				if (wait_res < 0)
671d33f473dSIllia Smyrnov 					dev_err(&spi->dev, "TXFFE timed out\n");
672d33f473dSIllia Smyrnov 			} else {
673d33f473dSIllia Smyrnov 				wait_res = mcspi_wait_for_reg_bit(chstat_reg,
674d33f473dSIllia Smyrnov 						OMAP2_MCSPI_CHSTAT_TXS);
675d33f473dSIllia Smyrnov 				if (wait_res < 0)
676e47a682aSShubhrajyoti D 					dev_err(&spi->dev, "TXS timed out\n");
677d33f473dSIllia Smyrnov 			}
678d33f473dSIllia Smyrnov 			if (wait_res >= 0 &&
679d33f473dSIllia Smyrnov 				(mcspi_wait_for_reg_bit(chstat_reg,
680d33f473dSIllia Smyrnov 					OMAP2_MCSPI_CHSTAT_EOT) < 0))
681e47a682aSShubhrajyoti D 				dev_err(&spi->dev, "EOT timed out\n");
682e47a682aSShubhrajyoti D 		}
683e47a682aSShubhrajyoti D 	}
684ca632f55SGrant Likely 	return count;
685ca632f55SGrant Likely }
686ca632f55SGrant Likely 
687ca632f55SGrant Likely static unsigned
688ca632f55SGrant Likely omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
689ca632f55SGrant Likely {
690ca632f55SGrant Likely 	struct omap2_mcspi_cs	*cs = spi->controller_state;
691ca632f55SGrant Likely 	unsigned int		count, c;
692ca632f55SGrant Likely 	u32			l;
693ca632f55SGrant Likely 	void __iomem		*base = cs->base;
694ca632f55SGrant Likely 	void __iomem		*tx_reg;
695ca632f55SGrant Likely 	void __iomem		*rx_reg;
696ca632f55SGrant Likely 	void __iomem		*chstat_reg;
697ca632f55SGrant Likely 	int			word_len;
698ca632f55SGrant Likely 
699ca632f55SGrant Likely 	count = xfer->len;
700ca632f55SGrant Likely 	c = count;
701ca632f55SGrant Likely 	word_len = cs->word_len;
702ca632f55SGrant Likely 
703ca632f55SGrant Likely 	l = mcspi_cached_chconf0(spi);
704ca632f55SGrant Likely 
705ca632f55SGrant Likely 	/* We store the pre-calculated register addresses on stack to speed
706ca632f55SGrant Likely 	 * up the transfer loop. */
707ca632f55SGrant Likely 	tx_reg		= base + OMAP2_MCSPI_TX0;
708ca632f55SGrant Likely 	rx_reg		= base + OMAP2_MCSPI_RX0;
709ca632f55SGrant Likely 	chstat_reg	= base + OMAP2_MCSPI_CHSTAT0;
710ca632f55SGrant Likely 
711ca632f55SGrant Likely 	if (c < (word_len>>3))
712ca632f55SGrant Likely 		return 0;
713ca632f55SGrant Likely 
714ca632f55SGrant Likely 	if (word_len <= 8) {
715ca632f55SGrant Likely 		u8		*rx;
716ca632f55SGrant Likely 		const u8	*tx;
717ca632f55SGrant Likely 
718ca632f55SGrant Likely 		rx = xfer->rx_buf;
719ca632f55SGrant Likely 		tx = xfer->tx_buf;
720ca632f55SGrant Likely 
721ca632f55SGrant Likely 		do {
722ca632f55SGrant Likely 			c -= 1;
723ca632f55SGrant Likely 			if (tx != NULL) {
724ca632f55SGrant Likely 				if (mcspi_wait_for_reg_bit(chstat_reg,
725ca632f55SGrant Likely 						OMAP2_MCSPI_CHSTAT_TXS) < 0) {
726ca632f55SGrant Likely 					dev_err(&spi->dev, "TXS timed out\n");
727ca632f55SGrant Likely 					goto out;
728ca632f55SGrant Likely 				}
729ca632f55SGrant Likely 				dev_vdbg(&spi->dev, "write-%d %02x\n",
730ca632f55SGrant Likely 						word_len, *tx);
73121b2ce5eSVictor Kamensky 				writel_relaxed(*tx++, tx_reg);
732ca632f55SGrant Likely 			}
733ca632f55SGrant Likely 			if (rx != NULL) {
734ca632f55SGrant Likely 				if (mcspi_wait_for_reg_bit(chstat_reg,
735ca632f55SGrant Likely 						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
736ca632f55SGrant Likely 					dev_err(&spi->dev, "RXS timed out\n");
737ca632f55SGrant Likely 					goto out;
738ca632f55SGrant Likely 				}
739ca632f55SGrant Likely 
740ca632f55SGrant Likely 				if (c == 1 && tx == NULL &&
741ca632f55SGrant Likely 				    (l & OMAP2_MCSPI_CHCONF_TURBO)) {
742ca632f55SGrant Likely 					omap2_mcspi_set_enable(spi, 0);
74321b2ce5eSVictor Kamensky 					*rx++ = readl_relaxed(rx_reg);
744ca632f55SGrant Likely 					dev_vdbg(&spi->dev, "read-%d %02x\n",
745ca632f55SGrant Likely 						    word_len, *(rx - 1));
746ca632f55SGrant Likely 					if (mcspi_wait_for_reg_bit(chstat_reg,
747ca632f55SGrant Likely 						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
748ca632f55SGrant Likely 						dev_err(&spi->dev,
749ca632f55SGrant Likely 							"RXS timed out\n");
750ca632f55SGrant Likely 						goto out;
751ca632f55SGrant Likely 					}
752ca632f55SGrant Likely 					c = 0;
753ca632f55SGrant Likely 				} else if (c == 0 && tx == NULL) {
754ca632f55SGrant Likely 					omap2_mcspi_set_enable(spi, 0);
755ca632f55SGrant Likely 				}
756ca632f55SGrant Likely 
75721b2ce5eSVictor Kamensky 				*rx++ = readl_relaxed(rx_reg);
758ca632f55SGrant Likely 				dev_vdbg(&spi->dev, "read-%d %02x\n",
759ca632f55SGrant Likely 						word_len, *(rx - 1));
760ca632f55SGrant Likely 			}
761ca632f55SGrant Likely 		} while (c);
762ca632f55SGrant Likely 	} else if (word_len <= 16) {
763ca632f55SGrant Likely 		u16		*rx;
764ca632f55SGrant Likely 		const u16	*tx;
765ca632f55SGrant Likely 
766ca632f55SGrant Likely 		rx = xfer->rx_buf;
767ca632f55SGrant Likely 		tx = xfer->tx_buf;
768ca632f55SGrant Likely 		do {
769ca632f55SGrant Likely 			c -= 2;
770ca632f55SGrant Likely 			if (tx != NULL) {
771ca632f55SGrant Likely 				if (mcspi_wait_for_reg_bit(chstat_reg,
772ca632f55SGrant Likely 						OMAP2_MCSPI_CHSTAT_TXS) < 0) {
773ca632f55SGrant Likely 					dev_err(&spi->dev, "TXS timed out\n");
774ca632f55SGrant Likely 					goto out;
775ca632f55SGrant Likely 				}
776ca632f55SGrant Likely 				dev_vdbg(&spi->dev, "write-%d %04x\n",
777ca632f55SGrant Likely 						word_len, *tx);
77821b2ce5eSVictor Kamensky 				writel_relaxed(*tx++, tx_reg);
779ca632f55SGrant Likely 			}
780ca632f55SGrant Likely 			if (rx != NULL) {
781ca632f55SGrant Likely 				if (mcspi_wait_for_reg_bit(chstat_reg,
782ca632f55SGrant Likely 						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
783ca632f55SGrant Likely 					dev_err(&spi->dev, "RXS timed out\n");
784ca632f55SGrant Likely 					goto out;
785ca632f55SGrant Likely 				}
786ca632f55SGrant Likely 
787ca632f55SGrant Likely 				if (c == 2 && tx == NULL &&
788ca632f55SGrant Likely 				    (l & OMAP2_MCSPI_CHCONF_TURBO)) {
789ca632f55SGrant Likely 					omap2_mcspi_set_enable(spi, 0);
79021b2ce5eSVictor Kamensky 					*rx++ = readl_relaxed(rx_reg);
791ca632f55SGrant Likely 					dev_vdbg(&spi->dev, "read-%d %04x\n",
792ca632f55SGrant Likely 						    word_len, *(rx - 1));
793ca632f55SGrant Likely 					if (mcspi_wait_for_reg_bit(chstat_reg,
794ca632f55SGrant Likely 						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
795ca632f55SGrant Likely 						dev_err(&spi->dev,
796ca632f55SGrant Likely 							"RXS timed out\n");
797ca632f55SGrant Likely 						goto out;
798ca632f55SGrant Likely 					}
799ca632f55SGrant Likely 					c = 0;
800ca632f55SGrant Likely 				} else if (c == 0 && tx == NULL) {
801ca632f55SGrant Likely 					omap2_mcspi_set_enable(spi, 0);
802ca632f55SGrant Likely 				}
803ca632f55SGrant Likely 
80421b2ce5eSVictor Kamensky 				*rx++ = readl_relaxed(rx_reg);
805ca632f55SGrant Likely 				dev_vdbg(&spi->dev, "read-%d %04x\n",
806ca632f55SGrant Likely 						word_len, *(rx - 1));
807ca632f55SGrant Likely 			}
808ca632f55SGrant Likely 		} while (c >= 2);
809ca632f55SGrant Likely 	} else if (word_len <= 32) {
810ca632f55SGrant Likely 		u32		*rx;
811ca632f55SGrant Likely 		const u32	*tx;
812ca632f55SGrant Likely 
813ca632f55SGrant Likely 		rx = xfer->rx_buf;
814ca632f55SGrant Likely 		tx = xfer->tx_buf;
815ca632f55SGrant Likely 		do {
816ca632f55SGrant Likely 			c -= 4;
817ca632f55SGrant Likely 			if (tx != NULL) {
818ca632f55SGrant Likely 				if (mcspi_wait_for_reg_bit(chstat_reg,
819ca632f55SGrant Likely 						OMAP2_MCSPI_CHSTAT_TXS) < 0) {
820ca632f55SGrant Likely 					dev_err(&spi->dev, "TXS timed out\n");
821ca632f55SGrant Likely 					goto out;
822ca632f55SGrant Likely 				}
823ca632f55SGrant Likely 				dev_vdbg(&spi->dev, "write-%d %08x\n",
824ca632f55SGrant Likely 						word_len, *tx);
82521b2ce5eSVictor Kamensky 				writel_relaxed(*tx++, tx_reg);
826ca632f55SGrant Likely 			}
827ca632f55SGrant Likely 			if (rx != NULL) {
828ca632f55SGrant Likely 				if (mcspi_wait_for_reg_bit(chstat_reg,
829ca632f55SGrant Likely 						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
830ca632f55SGrant Likely 					dev_err(&spi->dev, "RXS timed out\n");
831ca632f55SGrant Likely 					goto out;
832ca632f55SGrant Likely 				}
833ca632f55SGrant Likely 
834ca632f55SGrant Likely 				if (c == 4 && tx == NULL &&
835ca632f55SGrant Likely 				    (l & OMAP2_MCSPI_CHCONF_TURBO)) {
836ca632f55SGrant Likely 					omap2_mcspi_set_enable(spi, 0);
83721b2ce5eSVictor Kamensky 					*rx++ = readl_relaxed(rx_reg);
838ca632f55SGrant Likely 					dev_vdbg(&spi->dev, "read-%d %08x\n",
839ca632f55SGrant Likely 						    word_len, *(rx - 1));
840ca632f55SGrant Likely 					if (mcspi_wait_for_reg_bit(chstat_reg,
841ca632f55SGrant Likely 						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
842ca632f55SGrant Likely 						dev_err(&spi->dev,
843ca632f55SGrant Likely 							"RXS timed out\n");
844ca632f55SGrant Likely 						goto out;
845ca632f55SGrant Likely 					}
846ca632f55SGrant Likely 					c = 0;
847ca632f55SGrant Likely 				} else if (c == 0 && tx == NULL) {
848ca632f55SGrant Likely 					omap2_mcspi_set_enable(spi, 0);
849ca632f55SGrant Likely 				}
850ca632f55SGrant Likely 
85121b2ce5eSVictor Kamensky 				*rx++ = readl_relaxed(rx_reg);
852ca632f55SGrant Likely 				dev_vdbg(&spi->dev, "read-%d %08x\n",
853ca632f55SGrant Likely 						word_len, *(rx - 1));
854ca632f55SGrant Likely 			}
855ca632f55SGrant Likely 		} while (c >= 4);
856ca632f55SGrant Likely 	}
857ca632f55SGrant Likely 
858ca632f55SGrant Likely 	/* for TX_ONLY mode, be sure all words have shifted out */
859ca632f55SGrant Likely 	if (xfer->rx_buf == NULL) {
860ca632f55SGrant Likely 		if (mcspi_wait_for_reg_bit(chstat_reg,
861ca632f55SGrant Likely 				OMAP2_MCSPI_CHSTAT_TXS) < 0) {
862ca632f55SGrant Likely 			dev_err(&spi->dev, "TXS timed out\n");
863ca632f55SGrant Likely 		} else if (mcspi_wait_for_reg_bit(chstat_reg,
864ca632f55SGrant Likely 				OMAP2_MCSPI_CHSTAT_EOT) < 0)
865ca632f55SGrant Likely 			dev_err(&spi->dev, "EOT timed out\n");
866ca632f55SGrant Likely 
867ca632f55SGrant Likely 		/* disable chan to purge rx datas received in TX_ONLY transfer,
868ca632f55SGrant Likely 		 * otherwise these rx datas will affect the direct following
869ca632f55SGrant Likely 		 * RX_ONLY transfer.
870ca632f55SGrant Likely 		 */
871ca632f55SGrant Likely 		omap2_mcspi_set_enable(spi, 0);
872ca632f55SGrant Likely 	}
873ca632f55SGrant Likely out:
874ca632f55SGrant Likely 	omap2_mcspi_set_enable(spi, 1);
875ca632f55SGrant Likely 	return count - c;
876ca632f55SGrant Likely }
877ca632f55SGrant Likely 
878ca632f55SGrant Likely static u32 omap2_mcspi_calc_divisor(u32 speed_hz)
879ca632f55SGrant Likely {
880ca632f55SGrant Likely 	u32 div;
881ca632f55SGrant Likely 
882ca632f55SGrant Likely 	for (div = 0; div < 15; div++)
883ca632f55SGrant Likely 		if (speed_hz >= (OMAP2_MCSPI_MAX_FREQ >> div))
884ca632f55SGrant Likely 			return div;
885ca632f55SGrant Likely 
886ca632f55SGrant Likely 	return 15;
887ca632f55SGrant Likely }
888ca632f55SGrant Likely 
889ca632f55SGrant Likely /* called only when no transfer is active to this device */
890ca632f55SGrant Likely static int omap2_mcspi_setup_transfer(struct spi_device *spi,
891ca632f55SGrant Likely 		struct spi_transfer *t)
892ca632f55SGrant Likely {
893ca632f55SGrant Likely 	struct omap2_mcspi_cs *cs = spi->controller_state;
894ca632f55SGrant Likely 	struct omap2_mcspi *mcspi;
895faee9b05SStefan Sørensen 	u32 l = 0, clkd = 0, div, extclk = 0, clkg = 0;
896ca632f55SGrant Likely 	u8 word_len = spi->bits_per_word;
897ca632f55SGrant Likely 	u32 speed_hz = spi->max_speed_hz;
898ca632f55SGrant Likely 
899ca632f55SGrant Likely 	mcspi = spi_master_get_devdata(spi->master);
900ca632f55SGrant Likely 
901ca632f55SGrant Likely 	if (t != NULL && t->bits_per_word)
902ca632f55SGrant Likely 		word_len = t->bits_per_word;
903ca632f55SGrant Likely 
904ca632f55SGrant Likely 	cs->word_len = word_len;
905ca632f55SGrant Likely 
906ca632f55SGrant Likely 	if (t && t->speed_hz)
907ca632f55SGrant Likely 		speed_hz = t->speed_hz;
908ca632f55SGrant Likely 
909ca632f55SGrant Likely 	speed_hz = min_t(u32, speed_hz, OMAP2_MCSPI_MAX_FREQ);
910faee9b05SStefan Sørensen 	if (speed_hz < (OMAP2_MCSPI_MAX_FREQ / OMAP2_MCSPI_MAX_DIVIDER)) {
911faee9b05SStefan Sørensen 		clkd = omap2_mcspi_calc_divisor(speed_hz);
912faee9b05SStefan Sørensen 		speed_hz = OMAP2_MCSPI_MAX_FREQ >> clkd;
913faee9b05SStefan Sørensen 		clkg = 0;
914faee9b05SStefan Sørensen 	} else {
915faee9b05SStefan Sørensen 		div = (OMAP2_MCSPI_MAX_FREQ + speed_hz - 1) / speed_hz;
916faee9b05SStefan Sørensen 		speed_hz = OMAP2_MCSPI_MAX_FREQ / div;
917faee9b05SStefan Sørensen 		clkd = (div - 1) & 0xf;
918faee9b05SStefan Sørensen 		extclk = (div - 1) >> 4;
919faee9b05SStefan Sørensen 		clkg = OMAP2_MCSPI_CHCONF_CLKG;
920faee9b05SStefan Sørensen 	}
921ca632f55SGrant Likely 
922ca632f55SGrant Likely 	l = mcspi_cached_chconf0(spi);
923ca632f55SGrant Likely 
924ca632f55SGrant Likely 	/* standard 4-wire master mode:  SCK, MOSI/out, MISO/in, nCS
925ca632f55SGrant Likely 	 * REVISIT: this controller could support SPI_3WIRE mode.
926ca632f55SGrant Likely 	 */
9272cd45179SDaniel Mack 	if (mcspi->pin_dir == MCSPI_PINDIR_D0_IN_D1_OUT) {
9280384e90bSDaniel Mack 		l &= ~OMAP2_MCSPI_CHCONF_IS;
9290384e90bSDaniel Mack 		l &= ~OMAP2_MCSPI_CHCONF_DPE1;
930ca632f55SGrant Likely 		l |= OMAP2_MCSPI_CHCONF_DPE0;
9310384e90bSDaniel Mack 	} else {
9320384e90bSDaniel Mack 		l |= OMAP2_MCSPI_CHCONF_IS;
9330384e90bSDaniel Mack 		l |= OMAP2_MCSPI_CHCONF_DPE1;
9340384e90bSDaniel Mack 		l &= ~OMAP2_MCSPI_CHCONF_DPE0;
9350384e90bSDaniel Mack 	}
936ca632f55SGrant Likely 
937ca632f55SGrant Likely 	/* wordlength */
938ca632f55SGrant Likely 	l &= ~OMAP2_MCSPI_CHCONF_WL_MASK;
939ca632f55SGrant Likely 	l |= (word_len - 1) << 7;
940ca632f55SGrant Likely 
941ca632f55SGrant Likely 	/* set chipselect polarity; manage with FORCE */
942ca632f55SGrant Likely 	if (!(spi->mode & SPI_CS_HIGH))
943ca632f55SGrant Likely 		l |= OMAP2_MCSPI_CHCONF_EPOL;	/* active-low; normal */
944ca632f55SGrant Likely 	else
945ca632f55SGrant Likely 		l &= ~OMAP2_MCSPI_CHCONF_EPOL;
946ca632f55SGrant Likely 
947ca632f55SGrant Likely 	/* set clock divisor */
948ca632f55SGrant Likely 	l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK;
949faee9b05SStefan Sørensen 	l |= clkd << 2;
950faee9b05SStefan Sørensen 
951faee9b05SStefan Sørensen 	/* set clock granularity */
952faee9b05SStefan Sørensen 	l &= ~OMAP2_MCSPI_CHCONF_CLKG;
953faee9b05SStefan Sørensen 	l |= clkg;
954faee9b05SStefan Sørensen 	if (clkg) {
955faee9b05SStefan Sørensen 		cs->chctrl0 &= ~OMAP2_MCSPI_CHCTRL_EXTCLK_MASK;
956faee9b05SStefan Sørensen 		cs->chctrl0 |= extclk << 8;
957faee9b05SStefan Sørensen 		mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0);
958faee9b05SStefan Sørensen 	}
959ca632f55SGrant Likely 
960ca632f55SGrant Likely 	/* set SPI mode 0..3 */
961ca632f55SGrant Likely 	if (spi->mode & SPI_CPOL)
962ca632f55SGrant Likely 		l |= OMAP2_MCSPI_CHCONF_POL;
963ca632f55SGrant Likely 	else
964ca632f55SGrant Likely 		l &= ~OMAP2_MCSPI_CHCONF_POL;
965ca632f55SGrant Likely 	if (spi->mode & SPI_CPHA)
966ca632f55SGrant Likely 		l |= OMAP2_MCSPI_CHCONF_PHA;
967ca632f55SGrant Likely 	else
968ca632f55SGrant Likely 		l &= ~OMAP2_MCSPI_CHCONF_PHA;
969ca632f55SGrant Likely 
970ca632f55SGrant Likely 	mcspi_write_chconf0(spi, l);
971ca632f55SGrant Likely 
97297ca0d6cSMark A. Greer 	cs->mode = spi->mode;
97397ca0d6cSMark A. Greer 
974ca632f55SGrant Likely 	dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s\n",
975faee9b05SStefan Sørensen 			speed_hz,
976ca632f55SGrant Likely 			(spi->mode & SPI_CPHA) ? "trailing" : "leading",
977ca632f55SGrant Likely 			(spi->mode & SPI_CPOL) ? "inverted" : "normal");
978ca632f55SGrant Likely 
979ca632f55SGrant Likely 	return 0;
980ca632f55SGrant Likely }
981ca632f55SGrant Likely 
982ddc5cdf1STony Lindgren /*
983ddc5cdf1STony Lindgren  * Note that we currently allow DMA only if we get a channel
984ddc5cdf1STony Lindgren  * for both rx and tx. Otherwise we'll do PIO for both rx and tx.
985ddc5cdf1STony Lindgren  */
98632f2fc5dSVignesh Raghavendra static int omap2_mcspi_request_dma(struct omap2_mcspi *mcspi,
98732f2fc5dSVignesh Raghavendra 				   struct omap2_mcspi_dma *mcspi_dma)
988ca632f55SGrant Likely {
989b085c612SPeter Ujfalusi 	int ret = 0;
990ca632f55SGrant Likely 
99132f2fc5dSVignesh Raghavendra 	mcspi_dma->dma_rx = dma_request_chan(mcspi->dev,
99274f3aaadSMatt Porter 					     mcspi_dma->dma_rx_ch_name);
993b085c612SPeter Ujfalusi 	if (IS_ERR(mcspi_dma->dma_rx)) {
994b085c612SPeter Ujfalusi 		ret = PTR_ERR(mcspi_dma->dma_rx);
99553741ed8SRussell King 		mcspi_dma->dma_rx = NULL;
996ddc5cdf1STony Lindgren 		goto no_dma;
99753741ed8SRussell King 	}
998ca632f55SGrant Likely 
99932f2fc5dSVignesh Raghavendra 	mcspi_dma->dma_tx = dma_request_chan(mcspi->dev,
1000b085c612SPeter Ujfalusi 					     mcspi_dma->dma_tx_ch_name);
1001b085c612SPeter Ujfalusi 	if (IS_ERR(mcspi_dma->dma_tx)) {
1002b085c612SPeter Ujfalusi 		ret = PTR_ERR(mcspi_dma->dma_tx);
1003b085c612SPeter Ujfalusi 		mcspi_dma->dma_tx = NULL;
1004b085c612SPeter Ujfalusi 		dma_release_channel(mcspi_dma->dma_rx);
1005b085c612SPeter Ujfalusi 		mcspi_dma->dma_rx = NULL;
1006b085c612SPeter Ujfalusi 	}
1007ddc5cdf1STony Lindgren 
100832f2fc5dSVignesh Raghavendra 	init_completion(&mcspi_dma->dma_rx_completion);
100932f2fc5dSVignesh Raghavendra 	init_completion(&mcspi_dma->dma_tx_completion);
101032f2fc5dSVignesh Raghavendra 
1011ddc5cdf1STony Lindgren no_dma:
1012b085c612SPeter Ujfalusi 	return ret;
1013ca632f55SGrant Likely }
1014ca632f55SGrant Likely 
101532f2fc5dSVignesh Raghavendra static void omap2_mcspi_release_dma(struct spi_master *master)
101632f2fc5dSVignesh Raghavendra {
101732f2fc5dSVignesh Raghavendra 	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
101832f2fc5dSVignesh Raghavendra 	struct omap2_mcspi_dma	*mcspi_dma;
101932f2fc5dSVignesh Raghavendra 	int i;
102032f2fc5dSVignesh Raghavendra 
102132f2fc5dSVignesh Raghavendra 	for (i = 0; i < master->num_chipselect; i++) {
102232f2fc5dSVignesh Raghavendra 		mcspi_dma = &mcspi->dma_channels[i];
102332f2fc5dSVignesh Raghavendra 
102432f2fc5dSVignesh Raghavendra 		if (mcspi_dma->dma_rx) {
102532f2fc5dSVignesh Raghavendra 			dma_release_channel(mcspi_dma->dma_rx);
102632f2fc5dSVignesh Raghavendra 			mcspi_dma->dma_rx = NULL;
102732f2fc5dSVignesh Raghavendra 		}
102832f2fc5dSVignesh Raghavendra 		if (mcspi_dma->dma_tx) {
102932f2fc5dSVignesh Raghavendra 			dma_release_channel(mcspi_dma->dma_tx);
103032f2fc5dSVignesh Raghavendra 			mcspi_dma->dma_tx = NULL;
103132f2fc5dSVignesh Raghavendra 		}
103232f2fc5dSVignesh Raghavendra 	}
103332f2fc5dSVignesh Raghavendra }
103432f2fc5dSVignesh Raghavendra 
1035ca632f55SGrant Likely static int omap2_mcspi_setup(struct spi_device *spi)
1036ca632f55SGrant Likely {
1037ca632f55SGrant Likely 	int			ret;
10381bd897f8SBenoit Cousson 	struct omap2_mcspi	*mcspi = spi_master_get_devdata(spi->master);
10391bd897f8SBenoit Cousson 	struct omap2_mcspi_regs	*ctx = &mcspi->ctx;
1040ca632f55SGrant Likely 	struct omap2_mcspi_cs	*cs = spi->controller_state;
1041ca632f55SGrant Likely 
1042ca632f55SGrant Likely 	if (!cs) {
104310aa5a35SRussell King 		cs = kzalloc(sizeof *cs, GFP_KERNEL);
1044ca632f55SGrant Likely 		if (!cs)
1045ca632f55SGrant Likely 			return -ENOMEM;
1046ca632f55SGrant Likely 		cs->base = mcspi->base + spi->chip_select * 0x14;
1047ca632f55SGrant Likely 		cs->phys = mcspi->phys + spi->chip_select * 0x14;
104897ca0d6cSMark A. Greer 		cs->mode = 0;
1049ca632f55SGrant Likely 		cs->chconf0 = 0;
1050faee9b05SStefan Sørensen 		cs->chctrl0 = 0;
1051ca632f55SGrant Likely 		spi->controller_state = cs;
1052ca632f55SGrant Likely 		/* Link this to context save list */
10531bd897f8SBenoit Cousson 		list_add_tail(&cs->node, &ctx->cs);
10542f538c01SMichael Welling 	}
10552f538c01SMichael Welling 
1056034d3dc9SShubhrajyoti D 	ret = pm_runtime_get_sync(mcspi->dev);
10575a686b2cSTony Lindgren 	if (ret < 0) {
10585a686b2cSTony Lindgren 		pm_runtime_put_noidle(mcspi->dev);
10595a686b2cSTony Lindgren 
1060ca632f55SGrant Likely 		return ret;
10615a686b2cSTony Lindgren 	}
1062ca632f55SGrant Likely 
1063ca632f55SGrant Likely 	ret = omap2_mcspi_setup_transfer(spi, NULL);
1064034d3dc9SShubhrajyoti D 	pm_runtime_mark_last_busy(mcspi->dev);
1065034d3dc9SShubhrajyoti D 	pm_runtime_put_autosuspend(mcspi->dev);
1066ca632f55SGrant Likely 
1067ca632f55SGrant Likely 	return ret;
1068ca632f55SGrant Likely }
1069ca632f55SGrant Likely 
1070ca632f55SGrant Likely static void omap2_mcspi_cleanup(struct spi_device *spi)
1071ca632f55SGrant Likely {
1072ca632f55SGrant Likely 	struct omap2_mcspi_cs	*cs;
1073ca632f55SGrant Likely 
1074ca632f55SGrant Likely 	if (spi->controller_state) {
1075ca632f55SGrant Likely 		/* Unlink controller state from context save list */
1076ca632f55SGrant Likely 		cs = spi->controller_state;
1077ca632f55SGrant Likely 		list_del(&cs->node);
1078ca632f55SGrant Likely 
107910aa5a35SRussell King 		kfree(cs);
1080ca632f55SGrant Likely 	}
1081ca632f55SGrant Likely }
1082ca632f55SGrant Likely 
108389e8b9cbSVignesh R static irqreturn_t omap2_mcspi_irq_handler(int irq, void *data)
108489e8b9cbSVignesh R {
108589e8b9cbSVignesh R 	struct omap2_mcspi *mcspi = data;
108689e8b9cbSVignesh R 	u32 irqstat;
108789e8b9cbSVignesh R 
108889e8b9cbSVignesh R 	irqstat	= mcspi_read_reg(mcspi->master, OMAP2_MCSPI_IRQSTATUS);
108989e8b9cbSVignesh R 	if (!irqstat)
109089e8b9cbSVignesh R 		return IRQ_NONE;
109189e8b9cbSVignesh R 
109289e8b9cbSVignesh R 	/* Disable IRQ and wakeup slave xfer task */
109389e8b9cbSVignesh R 	mcspi_write_reg(mcspi->master, OMAP2_MCSPI_IRQENABLE, 0);
109489e8b9cbSVignesh R 	if (irqstat & OMAP2_MCSPI_IRQSTATUS_EOW)
109589e8b9cbSVignesh R 		complete(&mcspi->txdone);
109689e8b9cbSVignesh R 
109789e8b9cbSVignesh R 	return IRQ_HANDLED;
109889e8b9cbSVignesh R }
109989e8b9cbSVignesh R 
110089e8b9cbSVignesh R static int omap2_mcspi_slave_abort(struct spi_master *master)
110189e8b9cbSVignesh R {
110289e8b9cbSVignesh R 	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
110389e8b9cbSVignesh R 	struct omap2_mcspi_dma *mcspi_dma = mcspi->dma_channels;
110489e8b9cbSVignesh R 
110589e8b9cbSVignesh R 	mcspi->slave_aborted = true;
110689e8b9cbSVignesh R 	complete(&mcspi_dma->dma_rx_completion);
110789e8b9cbSVignesh R 	complete(&mcspi_dma->dma_tx_completion);
110889e8b9cbSVignesh R 	complete(&mcspi->txdone);
110989e8b9cbSVignesh R 
111089e8b9cbSVignesh R 	return 0;
111189e8b9cbSVignesh R }
111289e8b9cbSVignesh R 
11130ba1870fSFranklin S Cooper Jr static int omap2_mcspi_transfer_one(struct spi_master *master,
11140ba1870fSFranklin S Cooper Jr 				    struct spi_device *spi,
11150ba1870fSFranklin S Cooper Jr 				    struct spi_transfer *t)
1116ca632f55SGrant Likely {
1117ca632f55SGrant Likely 
1118ca632f55SGrant Likely 	/* We only enable one channel at a time -- the one whose message is
11195fda88f5SShubhrajyoti D 	 * -- although this controller would gladly
1120ca632f55SGrant Likely 	 * arbitrate among multiple channels.  This corresponds to "single
1121ca632f55SGrant Likely 	 * channel" master mode.  As a side effect, we need to manage the
1122ca632f55SGrant Likely 	 * chipselect with the FORCE bit ... CS != channel enable.
1123ca632f55SGrant Likely 	 */
11245fda88f5SShubhrajyoti D 
11250ba1870fSFranklin S Cooper Jr 	struct omap2_mcspi		*mcspi;
1126ddc5cdf1STony Lindgren 	struct omap2_mcspi_dma		*mcspi_dma;
1127ca632f55SGrant Likely 	struct omap2_mcspi_cs		*cs;
1128ca632f55SGrant Likely 	struct omap2_mcspi_device_config *cd;
1129ca632f55SGrant Likely 	int				par_override = 0;
1130ca632f55SGrant Likely 	int				status = 0;
1131ca632f55SGrant Likely 	u32				chconf;
1132ca632f55SGrant Likely 
11330ba1870fSFranklin S Cooper Jr 	mcspi = spi_master_get_devdata(master);
1134ddc5cdf1STony Lindgren 	mcspi_dma = mcspi->dma_channels + spi->chip_select;
1135ca632f55SGrant Likely 	cs = spi->controller_state;
1136ca632f55SGrant Likely 	cd = spi->controller_data;
1137ca632f55SGrant Likely 
113897ca0d6cSMark A. Greer 	/*
113997ca0d6cSMark A. Greer 	 * The slave driver could have changed spi->mode in which case
114097ca0d6cSMark A. Greer 	 * it will be different from cs->mode (the current hardware setup).
114197ca0d6cSMark A. Greer 	 * If so, set par_override (even though its not a parity issue) so
114297ca0d6cSMark A. Greer 	 * omap2_mcspi_setup_transfer will be called to configure the hardware
114397ca0d6cSMark A. Greer 	 * with the correct mode on the first iteration of the loop below.
114497ca0d6cSMark A. Greer 	 */
114597ca0d6cSMark A. Greer 	if (spi->mode != cs->mode)
114697ca0d6cSMark A. Greer 		par_override = 1;
114797ca0d6cSMark A. Greer 
1148d33f473dSIllia Smyrnov 	omap2_mcspi_set_enable(spi, 0);
1149b28cb941SMichael Welling 
1150f27b1dc6SLinus Walleij 	if (spi->cs_gpiod)
1151a06b430fSMichael Welling 		omap2_mcspi_set_cs(spi, spi->mode & SPI_CS_HIGH);
1152a06b430fSMichael Welling 
11532bd16e3eSStefan Sørensen 	if (par_override ||
11542bd16e3eSStefan Sørensen 	    (t->speed_hz != spi->max_speed_hz) ||
11552bd16e3eSStefan Sørensen 	    (t->bits_per_word != spi->bits_per_word)) {
1156ca632f55SGrant Likely 		par_override = 1;
1157ca632f55SGrant Likely 		status = omap2_mcspi_setup_transfer(spi, t);
1158ca632f55SGrant Likely 		if (status < 0)
1159b28cb941SMichael Welling 			goto out;
11602bd16e3eSStefan Sørensen 		if (t->speed_hz == spi->max_speed_hz &&
11612bd16e3eSStefan Sørensen 		    t->bits_per_word == spi->bits_per_word)
1162ca632f55SGrant Likely 			par_override = 0;
1163ca632f55SGrant Likely 	}
11645cbc7ca9SMatthias Brugger 	if (cd && cd->cs_per_word) {
11655cbc7ca9SMatthias Brugger 		chconf = mcspi->ctx.modulctrl;
11665cbc7ca9SMatthias Brugger 		chconf &= ~OMAP2_MCSPI_MODULCTRL_SINGLE;
11675cbc7ca9SMatthias Brugger 		mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf);
11685cbc7ca9SMatthias Brugger 		mcspi->ctx.modulctrl =
11695cbc7ca9SMatthias Brugger 			mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
11705cbc7ca9SMatthias Brugger 	}
11715cbc7ca9SMatthias Brugger 
1172ca632f55SGrant Likely 	chconf = mcspi_cached_chconf0(spi);
1173ca632f55SGrant Likely 	chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
1174ca632f55SGrant Likely 	chconf &= ~OMAP2_MCSPI_CHCONF_TURBO;
1175ca632f55SGrant Likely 
1176ca632f55SGrant Likely 	if (t->tx_buf == NULL)
1177ca632f55SGrant Likely 		chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
1178ca632f55SGrant Likely 	else if (t->rx_buf == NULL)
1179ca632f55SGrant Likely 		chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
1180ca632f55SGrant Likely 
1181ca632f55SGrant Likely 	if (cd && cd->turbo_mode && t->tx_buf == NULL) {
1182ca632f55SGrant Likely 		/* Turbo mode is for more than one word */
1183ca632f55SGrant Likely 		if (t->len > ((cs->word_len + 7) >> 3))
1184ca632f55SGrant Likely 			chconf |= OMAP2_MCSPI_CHCONF_TURBO;
1185ca632f55SGrant Likely 	}
1186ca632f55SGrant Likely 
1187ca632f55SGrant Likely 	mcspi_write_chconf0(spi, chconf);
1188ca632f55SGrant Likely 
1189ca632f55SGrant Likely 	if (t->len) {
1190ca632f55SGrant Likely 		unsigned	count;
1191ca632f55SGrant Likely 
1192d33f473dSIllia Smyrnov 		if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
11930ba1870fSFranklin S Cooper Jr 		    master->cur_msg_mapped &&
11940ba1870fSFranklin S Cooper Jr 		    master->can_dma(master, spi, t))
1195d33f473dSIllia Smyrnov 			omap2_mcspi_set_fifo(spi, t, 1);
1196d33f473dSIllia Smyrnov 
1197d33f473dSIllia Smyrnov 		omap2_mcspi_set_enable(spi, 1);
1198d33f473dSIllia Smyrnov 
1199ca632f55SGrant Likely 		/* RX_ONLY mode needs dummy data in TX reg */
1200ca632f55SGrant Likely 		if (t->tx_buf == NULL)
120121b2ce5eSVictor Kamensky 			writel_relaxed(0, cs->base
1202ca632f55SGrant Likely 					+ OMAP2_MCSPI_TX0);
1203ca632f55SGrant Likely 
1204ddc5cdf1STony Lindgren 		if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
12050ba1870fSFranklin S Cooper Jr 		    master->cur_msg_mapped &&
12060ba1870fSFranklin S Cooper Jr 		    master->can_dma(master, spi, t))
1207ca632f55SGrant Likely 			count = omap2_mcspi_txrx_dma(spi, t);
1208ca632f55SGrant Likely 		else
1209ca632f55SGrant Likely 			count = omap2_mcspi_txrx_pio(spi, t);
1210ca632f55SGrant Likely 
1211ca632f55SGrant Likely 		if (count != t->len) {
1212ca632f55SGrant Likely 			status = -EIO;
1213b28cb941SMichael Welling 			goto out;
1214ca632f55SGrant Likely 		}
1215ca632f55SGrant Likely 	}
1216ca632f55SGrant Likely 
1217d33f473dSIllia Smyrnov 	omap2_mcspi_set_enable(spi, 0);
1218d33f473dSIllia Smyrnov 
1219d33f473dSIllia Smyrnov 	if (mcspi->fifo_depth > 0)
1220d33f473dSIllia Smyrnov 		omap2_mcspi_set_fifo(spi, t, 0);
1221b28cb941SMichael Welling 
1222b28cb941SMichael Welling out:
1223ca632f55SGrant Likely 	/* Restore defaults if they were overriden */
1224ca632f55SGrant Likely 	if (par_override) {
1225ca632f55SGrant Likely 		par_override = 0;
1226ca632f55SGrant Likely 		status = omap2_mcspi_setup_transfer(spi, NULL);
1227ca632f55SGrant Likely 	}
1228ca632f55SGrant Likely 
12295cbc7ca9SMatthias Brugger 	if (cd && cd->cs_per_word) {
12305cbc7ca9SMatthias Brugger 		chconf = mcspi->ctx.modulctrl;
12315cbc7ca9SMatthias Brugger 		chconf |= OMAP2_MCSPI_MODULCTRL_SINGLE;
12325cbc7ca9SMatthias Brugger 		mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf);
12335cbc7ca9SMatthias Brugger 		mcspi->ctx.modulctrl =
12345cbc7ca9SMatthias Brugger 			mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL);
12355cbc7ca9SMatthias Brugger 	}
12365cbc7ca9SMatthias Brugger 
1237ca632f55SGrant Likely 	omap2_mcspi_set_enable(spi, 0);
1238ca632f55SGrant Likely 
1239f27b1dc6SLinus Walleij 	if (spi->cs_gpiod)
1240a06b430fSMichael Welling 		omap2_mcspi_set_cs(spi, !(spi->mode & SPI_CS_HIGH));
1241a06b430fSMichael Welling 
1242d33f473dSIllia Smyrnov 	if (mcspi->fifo_depth > 0 && t)
1243d33f473dSIllia Smyrnov 		omap2_mcspi_set_fifo(spi, t, 0);
1244ca632f55SGrant Likely 
1245b28cb941SMichael Welling 	return status;
1246ca632f55SGrant Likely }
1247ca632f55SGrant Likely 
1248468a3208SNeil Armstrong static int omap2_mcspi_prepare_message(struct spi_master *master,
1249468a3208SNeil Armstrong 				       struct spi_message *msg)
1250468a3208SNeil Armstrong {
1251468a3208SNeil Armstrong 	struct omap2_mcspi	*mcspi = spi_master_get_devdata(master);
1252468a3208SNeil Armstrong 	struct omap2_mcspi_regs	*ctx = &mcspi->ctx;
1253468a3208SNeil Armstrong 	struct omap2_mcspi_cs	*cs;
1254468a3208SNeil Armstrong 
1255468a3208SNeil Armstrong 	/* Only a single channel can have the FORCE bit enabled
1256468a3208SNeil Armstrong 	 * in its chconf0 register.
1257468a3208SNeil Armstrong 	 * Scan all channels and disable them except the current one.
1258468a3208SNeil Armstrong 	 * A FORCE can remain from a last transfer having cs_change enabled
1259468a3208SNeil Armstrong 	 */
1260468a3208SNeil Armstrong 	list_for_each_entry(cs, &ctx->cs, node) {
1261468a3208SNeil Armstrong 		if (msg->spi->controller_state == cs)
1262468a3208SNeil Armstrong 			continue;
1263468a3208SNeil Armstrong 
1264468a3208SNeil Armstrong 		if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE)) {
1265468a3208SNeil Armstrong 			cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE;
1266468a3208SNeil Armstrong 			writel_relaxed(cs->chconf0,
1267468a3208SNeil Armstrong 					cs->base + OMAP2_MCSPI_CHCONF0);
1268468a3208SNeil Armstrong 			readl_relaxed(cs->base + OMAP2_MCSPI_CHCONF0);
1269468a3208SNeil Armstrong 		}
1270468a3208SNeil Armstrong 	}
1271468a3208SNeil Armstrong 
1272468a3208SNeil Armstrong 	return 0;
1273468a3208SNeil Armstrong }
1274468a3208SNeil Armstrong 
12750ba1870fSFranklin S Cooper Jr static bool omap2_mcspi_can_dma(struct spi_master *master,
12760ba1870fSFranklin S Cooper Jr 				struct spi_device *spi,
12770ba1870fSFranklin S Cooper Jr 				struct spi_transfer *xfer)
1278ca632f55SGrant Likely {
127989e8b9cbSVignesh R 	struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
128089e8b9cbSVignesh R 	struct omap2_mcspi_dma *mcspi_dma =
128189e8b9cbSVignesh R 		&mcspi->dma_channels[spi->chip_select];
128289e8b9cbSVignesh R 
128389e8b9cbSVignesh R 	if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx)
128489e8b9cbSVignesh R 		return false;
128589e8b9cbSVignesh R 
128689e8b9cbSVignesh R 	if (spi_controller_is_slave(master))
128789e8b9cbSVignesh R 		return true;
128889e8b9cbSVignesh R 
128932f2fc5dSVignesh Raghavendra 	master->dma_rx = mcspi_dma->dma_rx;
129032f2fc5dSVignesh Raghavendra 	master->dma_tx = mcspi_dma->dma_tx;
129132f2fc5dSVignesh Raghavendra 
12920ba1870fSFranklin S Cooper Jr 	return (xfer->len >= DMA_MIN_BYTES);
1293ca632f55SGrant Likely }
1294ca632f55SGrant Likely 
1295e4e8276aSVignesh Raghavendra static size_t omap2_mcspi_max_xfer_size(struct spi_device *spi)
1296e4e8276aSVignesh Raghavendra {
1297e4e8276aSVignesh Raghavendra 	struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
1298e4e8276aSVignesh Raghavendra 	struct omap2_mcspi_dma *mcspi_dma =
1299e4e8276aSVignesh Raghavendra 		&mcspi->dma_channels[spi->chip_select];
1300e4e8276aSVignesh Raghavendra 
1301e4e8276aSVignesh Raghavendra 	if (mcspi->max_xfer_len && mcspi_dma->dma_rx)
1302e4e8276aSVignesh Raghavendra 		return mcspi->max_xfer_len;
1303e4e8276aSVignesh Raghavendra 
1304e4e8276aSVignesh Raghavendra 	return SIZE_MAX;
1305e4e8276aSVignesh Raghavendra }
1306e4e8276aSVignesh Raghavendra 
130789e8b9cbSVignesh R static int omap2_mcspi_controller_setup(struct omap2_mcspi *mcspi)
1308ca632f55SGrant Likely {
1309ca632f55SGrant Likely 	struct spi_master	*master = mcspi->master;
13101bd897f8SBenoit Cousson 	struct omap2_mcspi_regs	*ctx = &mcspi->ctx;
1311ca632f55SGrant Likely 	int			ret = 0;
1312ca632f55SGrant Likely 
1313034d3dc9SShubhrajyoti D 	ret = pm_runtime_get_sync(mcspi->dev);
13145a686b2cSTony Lindgren 	if (ret < 0) {
13155a686b2cSTony Lindgren 		pm_runtime_put_noidle(mcspi->dev);
13165a686b2cSTony Lindgren 
1317ca632f55SGrant Likely 		return ret;
13185a686b2cSTony Lindgren 	}
1319ca632f55SGrant Likely 
132039f8052dSShubhrajyoti D 	mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE,
132139f8052dSShubhrajyoti D 			OMAP2_MCSPI_WAKEUPENABLE_WKEN);
132239f8052dSShubhrajyoti D 	ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN;
1323ca632f55SGrant Likely 
132489e8b9cbSVignesh R 	omap2_mcspi_set_mode(master);
1325034d3dc9SShubhrajyoti D 	pm_runtime_mark_last_busy(mcspi->dev);
1326034d3dc9SShubhrajyoti D 	pm_runtime_put_autosuspend(mcspi->dev);
1327ca632f55SGrant Likely 	return 0;
1328ca632f55SGrant Likely }
1329ca632f55SGrant Likely 
1330*abdc5db3SAlexander Sverdlin static int omap_mcspi_runtime_suspend(struct device *dev)
1331*abdc5db3SAlexander Sverdlin {
1332*abdc5db3SAlexander Sverdlin 	int error;
1333*abdc5db3SAlexander Sverdlin 
1334*abdc5db3SAlexander Sverdlin 	error = pinctrl_pm_select_idle_state(dev);
1335*abdc5db3SAlexander Sverdlin 	if (error)
1336*abdc5db3SAlexander Sverdlin 		dev_warn(dev, "%s: failed to set pins: %i\n", __func__, error);
1337*abdc5db3SAlexander Sverdlin 
1338*abdc5db3SAlexander Sverdlin 	return 0;
1339*abdc5db3SAlexander Sverdlin }
1340*abdc5db3SAlexander Sverdlin 
134152e9a5bbSTony Lindgren /*
134252e9a5bbSTony Lindgren  * When SPI wake up from off-mode, CS is in activate state. If it was in
134352e9a5bbSTony Lindgren  * inactive state when driver was suspend, then force it to inactive state at
134452e9a5bbSTony Lindgren  * wake up.
134552e9a5bbSTony Lindgren  */
1346ca632f55SGrant Likely static int omap_mcspi_runtime_resume(struct device *dev)
1347ca632f55SGrant Likely {
134852e9a5bbSTony Lindgren 	struct spi_master *master = dev_get_drvdata(dev);
134952e9a5bbSTony Lindgren 	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
135052e9a5bbSTony Lindgren 	struct omap2_mcspi_regs *ctx = &mcspi->ctx;
135152e9a5bbSTony Lindgren 	struct omap2_mcspi_cs *cs;
1352*abdc5db3SAlexander Sverdlin 	int error;
1353*abdc5db3SAlexander Sverdlin 
1354*abdc5db3SAlexander Sverdlin 	error = pinctrl_pm_select_default_state(dev);
1355*abdc5db3SAlexander Sverdlin 	if (error)
1356*abdc5db3SAlexander Sverdlin 		dev_warn(dev, "%s: failed to set pins: %i\n", __func__, error);
1357ca632f55SGrant Likely 
135852e9a5bbSTony Lindgren 	/* McSPI: context restore */
135952e9a5bbSTony Lindgren 	mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, ctx->modulctrl);
136052e9a5bbSTony Lindgren 	mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE, ctx->wakeupenable);
136152e9a5bbSTony Lindgren 
136252e9a5bbSTony Lindgren 	list_for_each_entry(cs, &ctx->cs, node) {
136352e9a5bbSTony Lindgren 		/*
136452e9a5bbSTony Lindgren 		 * We need to toggle CS state for OMAP take this
136552e9a5bbSTony Lindgren 		 * change in account.
136652e9a5bbSTony Lindgren 		 */
136752e9a5bbSTony Lindgren 		if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) {
136852e9a5bbSTony Lindgren 			cs->chconf0 |= OMAP2_MCSPI_CHCONF_FORCE;
136952e9a5bbSTony Lindgren 			writel_relaxed(cs->chconf0,
137052e9a5bbSTony Lindgren 				       cs->base + OMAP2_MCSPI_CHCONF0);
137152e9a5bbSTony Lindgren 			cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE;
137252e9a5bbSTony Lindgren 			writel_relaxed(cs->chconf0,
137352e9a5bbSTony Lindgren 				       cs->base + OMAP2_MCSPI_CHCONF0);
137452e9a5bbSTony Lindgren 		} else {
137552e9a5bbSTony Lindgren 			writel_relaxed(cs->chconf0,
137652e9a5bbSTony Lindgren 				       cs->base + OMAP2_MCSPI_CHCONF0);
137752e9a5bbSTony Lindgren 		}
137852e9a5bbSTony Lindgren 	}
1379ca632f55SGrant Likely 
1380ca632f55SGrant Likely 	return 0;
1381ca632f55SGrant Likely }
1382ca632f55SGrant Likely 
1383d5a80031SBenoit Cousson static struct omap2_mcspi_platform_config omap2_pdata = {
1384d5a80031SBenoit Cousson 	.regs_offset = 0,
1385d5a80031SBenoit Cousson };
1386d5a80031SBenoit Cousson 
1387d5a80031SBenoit Cousson static struct omap2_mcspi_platform_config omap4_pdata = {
1388d5a80031SBenoit Cousson 	.regs_offset = OMAP4_MCSPI_REG_OFFSET,
1389d5a80031SBenoit Cousson };
1390d5a80031SBenoit Cousson 
1391e4e8276aSVignesh Raghavendra static struct omap2_mcspi_platform_config am654_pdata = {
1392e4e8276aSVignesh Raghavendra 	.regs_offset = OMAP4_MCSPI_REG_OFFSET,
1393e4e8276aSVignesh Raghavendra 	.max_xfer_len = SZ_4K - 1,
1394e4e8276aSVignesh Raghavendra };
1395e4e8276aSVignesh Raghavendra 
1396d5a80031SBenoit Cousson static const struct of_device_id omap_mcspi_of_match[] = {
1397d5a80031SBenoit Cousson 	{
1398d5a80031SBenoit Cousson 		.compatible = "ti,omap2-mcspi",
1399d5a80031SBenoit Cousson 		.data = &omap2_pdata,
1400d5a80031SBenoit Cousson 	},
1401d5a80031SBenoit Cousson 	{
1402d5a80031SBenoit Cousson 		.compatible = "ti,omap4-mcspi",
1403d5a80031SBenoit Cousson 		.data = &omap4_pdata,
1404d5a80031SBenoit Cousson 	},
1405e4e8276aSVignesh Raghavendra 	{
1406e4e8276aSVignesh Raghavendra 		.compatible = "ti,am654-mcspi",
1407e4e8276aSVignesh Raghavendra 		.data = &am654_pdata,
1408e4e8276aSVignesh Raghavendra 	},
1409d5a80031SBenoit Cousson 	{ },
1410d5a80031SBenoit Cousson };
1411d5a80031SBenoit Cousson MODULE_DEVICE_TABLE(of, omap_mcspi_of_match);
1412ca632f55SGrant Likely 
1413fd4a319bSGrant Likely static int omap2_mcspi_probe(struct platform_device *pdev)
1414ca632f55SGrant Likely {
1415ca632f55SGrant Likely 	struct spi_master	*master;
141683a01e72SUwe Kleine-König 	const struct omap2_mcspi_platform_config *pdata;
1417ca632f55SGrant Likely 	struct omap2_mcspi	*mcspi;
1418ca632f55SGrant Likely 	struct resource		*r;
1419ca632f55SGrant Likely 	int			status = 0, i;
1420d5a80031SBenoit Cousson 	u32			regs_offset = 0;
1421d5a80031SBenoit Cousson 	struct device_node	*node = pdev->dev.of_node;
1422d5a80031SBenoit Cousson 	const struct of_device_id *match;
1423ca632f55SGrant Likely 
142489e8b9cbSVignesh R 	if (of_property_read_bool(node, "spi-slave"))
142589e8b9cbSVignesh R 		master = spi_alloc_slave(&pdev->dev, sizeof(*mcspi));
142689e8b9cbSVignesh R 	else
142789e8b9cbSVignesh R 		master = spi_alloc_master(&pdev->dev, sizeof(*mcspi));
142889e8b9cbSVignesh R 	if (!master)
1429ca632f55SGrant Likely 		return -ENOMEM;
1430ca632f55SGrant Likely 
1431ca632f55SGrant Likely 	/* the spi->mode bits understood by this driver: */
1432ca632f55SGrant Likely 	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
143324778be2SStephen Warren 	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
1434ca632f55SGrant Likely 	master->setup = omap2_mcspi_setup;
1435f0278a1aSMark Brown 	master->auto_runtime_pm = true;
1436468a3208SNeil Armstrong 	master->prepare_message = omap2_mcspi_prepare_message;
14370ba1870fSFranklin S Cooper Jr 	master->can_dma = omap2_mcspi_can_dma;
1438b28cb941SMichael Welling 	master->transfer_one = omap2_mcspi_transfer_one;
1439ddcad7e9SMichael Welling 	master->set_cs = omap2_mcspi_set_cs;
1440ca632f55SGrant Likely 	master->cleanup = omap2_mcspi_cleanup;
144189e8b9cbSVignesh R 	master->slave_abort = omap2_mcspi_slave_abort;
1442d5a80031SBenoit Cousson 	master->dev.of_node = node;
1443aca0924bSAxel Lin 	master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ;
1444aca0924bSAxel Lin 	master->min_speed_hz = OMAP2_MCSPI_MAX_FREQ >> 15;
1445f27b1dc6SLinus Walleij 	master->use_gpio_descriptors = true;
1446d5a80031SBenoit Cousson 
144724b5a82cSJingoo Han 	platform_set_drvdata(pdev, master);
14480384e90bSDaniel Mack 
14490384e90bSDaniel Mack 	mcspi = spi_master_get_devdata(master);
14500384e90bSDaniel Mack 	mcspi->master = master;
14510384e90bSDaniel Mack 
1452d5a80031SBenoit Cousson 	match = of_match_device(omap_mcspi_of_match, &pdev->dev);
1453d5a80031SBenoit Cousson 	if (match) {
1454d5a80031SBenoit Cousson 		u32 num_cs = 1; /* default number of chipselect */
1455d5a80031SBenoit Cousson 		pdata = match->data;
1456d5a80031SBenoit Cousson 
1457d5a80031SBenoit Cousson 		of_property_read_u32(node, "ti,spi-num-cs", &num_cs);
1458d5a80031SBenoit Cousson 		master->num_chipselect = num_cs;
14592cd45179SDaniel Mack 		if (of_get_property(node, "ti,pindir-d0-out-d1-in", NULL))
14602cd45179SDaniel Mack 			mcspi->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN;
1461d5a80031SBenoit Cousson 	} else {
14628074cf06SJingoo Han 		pdata = dev_get_platdata(&pdev->dev);
1463ca632f55SGrant Likely 		master->num_chipselect = pdata->num_cs;
14640384e90bSDaniel Mack 		mcspi->pin_dir = pdata->pin_dir;
1465d5a80031SBenoit Cousson 	}
1466d5a80031SBenoit Cousson 	regs_offset = pdata->regs_offset;
1467e4e8276aSVignesh Raghavendra 	if (pdata->max_xfer_len) {
1468e4e8276aSVignesh Raghavendra 		mcspi->max_xfer_len = pdata->max_xfer_len;
1469e4e8276aSVignesh Raghavendra 		master->max_transfer_size = omap2_mcspi_max_xfer_size;
1470e4e8276aSVignesh Raghavendra 	}
1471ca632f55SGrant Likely 
1472ca632f55SGrant Likely 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1473b0ee5605SThierry Reding 	mcspi->base = devm_ioremap_resource(&pdev->dev, r);
1474b0ee5605SThierry Reding 	if (IS_ERR(mcspi->base)) {
1475b0ee5605SThierry Reding 		status = PTR_ERR(mcspi->base);
14761a77b127SShubhrajyoti D 		goto free_master;
1477ca632f55SGrant Likely 	}
1478af9e53feSVikram N 	mcspi->phys = r->start + regs_offset;
1479af9e53feSVikram N 	mcspi->base += regs_offset;
1480ca632f55SGrant Likely 
1481ca632f55SGrant Likely 	mcspi->dev = &pdev->dev;
1482ca632f55SGrant Likely 
14831bd897f8SBenoit Cousson 	INIT_LIST_HEAD(&mcspi->ctx.cs);
1484ca632f55SGrant Likely 
1485a6f936dbSAxel Lin 	mcspi->dma_channels = devm_kcalloc(&pdev->dev, master->num_chipselect,
1486ca632f55SGrant Likely 					   sizeof(struct omap2_mcspi_dma),
1487ca632f55SGrant Likely 					   GFP_KERNEL);
1488a6f936dbSAxel Lin 	if (mcspi->dma_channels == NULL) {
1489a6f936dbSAxel Lin 		status = -ENOMEM;
14901a77b127SShubhrajyoti D 		goto free_master;
1491a6f936dbSAxel Lin 	}
1492ca632f55SGrant Likely 
1493ca632f55SGrant Likely 	for (i = 0; i < master->num_chipselect; i++) {
1494b085c612SPeter Ujfalusi 		sprintf(mcspi->dma_channels[i].dma_rx_ch_name, "rx%d", i);
1495b085c612SPeter Ujfalusi 		sprintf(mcspi->dma_channels[i].dma_tx_ch_name, "tx%d", i);
149632f2fc5dSVignesh Raghavendra 
149732f2fc5dSVignesh Raghavendra 		status = omap2_mcspi_request_dma(mcspi,
149832f2fc5dSVignesh Raghavendra 						 &mcspi->dma_channels[i]);
149932f2fc5dSVignesh Raghavendra 		if (status == -EPROBE_DEFER)
150032f2fc5dSVignesh Raghavendra 			goto free_master;
1501ca632f55SGrant Likely 	}
1502ca632f55SGrant Likely 
150389e8b9cbSVignesh R 	status = platform_get_irq(pdev, 0);
150489e8b9cbSVignesh R 	if (status == -EPROBE_DEFER)
150589e8b9cbSVignesh R 		goto free_master;
150689e8b9cbSVignesh R 	if (status < 0) {
150789e8b9cbSVignesh R 		dev_err(&pdev->dev, "no irq resource found\n");
150889e8b9cbSVignesh R 		goto free_master;
150989e8b9cbSVignesh R 	}
151089e8b9cbSVignesh R 	init_completion(&mcspi->txdone);
151189e8b9cbSVignesh R 	status = devm_request_irq(&pdev->dev, status,
151289e8b9cbSVignesh R 				  omap2_mcspi_irq_handler, 0, pdev->name,
151389e8b9cbSVignesh R 				  mcspi);
151489e8b9cbSVignesh R 	if (status) {
151589e8b9cbSVignesh R 		dev_err(&pdev->dev, "Cannot request IRQ");
151689e8b9cbSVignesh R 		goto free_master;
151789e8b9cbSVignesh R 	}
151889e8b9cbSVignesh R 
151927b5284cSShubhrajyoti D 	pm_runtime_use_autosuspend(&pdev->dev);
152027b5284cSShubhrajyoti D 	pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
1521ca632f55SGrant Likely 	pm_runtime_enable(&pdev->dev);
1522ca632f55SGrant Likely 
152389e8b9cbSVignesh R 	status = omap2_mcspi_controller_setup(mcspi);
1524142e07beSWei Yongjun 	if (status < 0)
152539f1b565SShubhrajyoti D 		goto disable_pm;
1526ca632f55SGrant Likely 
152789e8b9cbSVignesh R 	status = devm_spi_register_controller(&pdev->dev, master);
1528ca632f55SGrant Likely 	if (status < 0)
152937a2d84aSShubhrajyoti D 		goto disable_pm;
1530ca632f55SGrant Likely 
1531ca632f55SGrant Likely 	return status;
1532ca632f55SGrant Likely 
153339f1b565SShubhrajyoti D disable_pm:
15340e6f357aSTony Lindgren 	pm_runtime_dont_use_autosuspend(&pdev->dev);
15350e6f357aSTony Lindgren 	pm_runtime_put_sync(&pdev->dev);
1536751c925cSShubhrajyoti D 	pm_runtime_disable(&pdev->dev);
153739f1b565SShubhrajyoti D free_master:
153832f2fc5dSVignesh Raghavendra 	omap2_mcspi_release_dma(master);
153937a2d84aSShubhrajyoti D 	spi_master_put(master);
1540ca632f55SGrant Likely 	return status;
1541ca632f55SGrant Likely }
1542ca632f55SGrant Likely 
1543fd4a319bSGrant Likely static int omap2_mcspi_remove(struct platform_device *pdev)
1544ca632f55SGrant Likely {
1545a6f936dbSAxel Lin 	struct spi_master *master = platform_get_drvdata(pdev);
1546a6f936dbSAxel Lin 	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
1547ca632f55SGrant Likely 
154832f2fc5dSVignesh Raghavendra 	omap2_mcspi_release_dma(master);
154932f2fc5dSVignesh Raghavendra 
15500e6f357aSTony Lindgren 	pm_runtime_dont_use_autosuspend(mcspi->dev);
1551a93a2029SShubhrajyoti D 	pm_runtime_put_sync(mcspi->dev);
1552751c925cSShubhrajyoti D 	pm_runtime_disable(&pdev->dev);
1553ca632f55SGrant Likely 
1554ca632f55SGrant Likely 	return 0;
1555ca632f55SGrant Likely }
1556ca632f55SGrant Likely 
1557ca632f55SGrant Likely /* work with hotplug and coldplug */
1558ca632f55SGrant Likely MODULE_ALIAS("platform:omap2_mcspi");
1559ca632f55SGrant Likely 
156091b9deefSTony Lindgren static int __maybe_unused omap2_mcspi_suspend(struct device *dev)
1561ca632f55SGrant Likely {
156291b9deefSTony Lindgren 	struct spi_master *master = dev_get_drvdata(dev);
156391b9deefSTony Lindgren 	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
156491b9deefSTony Lindgren 	int error;
156591b9deefSTony Lindgren 
156691b9deefSTony Lindgren 	error = pinctrl_pm_select_sleep_state(dev);
156791b9deefSTony Lindgren 	if (error)
156891b9deefSTony Lindgren 		dev_warn(mcspi->dev, "%s: failed to set pins: %i\n",
156991b9deefSTony Lindgren 			 __func__, error);
157091b9deefSTony Lindgren 
157191b9deefSTony Lindgren 	error = spi_master_suspend(master);
157291b9deefSTony Lindgren 	if (error)
157391b9deefSTony Lindgren 		dev_warn(mcspi->dev, "%s: master suspend failed: %i\n",
157491b9deefSTony Lindgren 			 __func__, error);
157591b9deefSTony Lindgren 
157691b9deefSTony Lindgren 	return pm_runtime_force_suspend(dev);
1577beca3655SPascal Huerst }
1578beca3655SPascal Huerst 
157991b9deefSTony Lindgren static int __maybe_unused omap2_mcspi_resume(struct device *dev)
15805a686b2cSTony Lindgren {
15815a686b2cSTony Lindgren 	struct spi_master *master = dev_get_drvdata(dev);
15825a686b2cSTony Lindgren 	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
15835a686b2cSTony Lindgren 	int error;
15845a686b2cSTony Lindgren 
158591b9deefSTony Lindgren 	error = spi_master_resume(master);
158691b9deefSTony Lindgren 	if (error)
158791b9deefSTony Lindgren 		dev_warn(mcspi->dev, "%s: master resume failed: %i\n",
158891b9deefSTony Lindgren 			 __func__, error);
158991b9deefSTony Lindgren 
159091b9deefSTony Lindgren 	return pm_runtime_force_resume(dev);
15915a686b2cSTony Lindgren }
15925a686b2cSTony Lindgren 
1593ca632f55SGrant Likely static const struct dev_pm_ops omap2_mcspi_pm_ops = {
159491b9deefSTony Lindgren 	SET_SYSTEM_SLEEP_PM_OPS(omap2_mcspi_suspend,
159591b9deefSTony Lindgren 				omap2_mcspi_resume)
1596*abdc5db3SAlexander Sverdlin 	.runtime_suspend	= omap_mcspi_runtime_suspend,
1597ca632f55SGrant Likely 	.runtime_resume		= omap_mcspi_runtime_resume,
1598ca632f55SGrant Likely };
1599ca632f55SGrant Likely 
1600ca632f55SGrant Likely static struct platform_driver omap2_mcspi_driver = {
1601ca632f55SGrant Likely 	.driver = {
1602ca632f55SGrant Likely 		.name =		"omap2_mcspi",
1603d5a80031SBenoit Cousson 		.pm =		&omap2_mcspi_pm_ops,
1604d5a80031SBenoit Cousson 		.of_match_table = omap_mcspi_of_match,
1605ca632f55SGrant Likely 	},
16067d6b6d83SFelipe Balbi 	.probe =	omap2_mcspi_probe,
1607fd4a319bSGrant Likely 	.remove =	omap2_mcspi_remove,
1608ca632f55SGrant Likely };
1609ca632f55SGrant Likely 
16109fdca9dfSFelipe Balbi module_platform_driver(omap2_mcspi_driver);
1611ca632f55SGrant Likely MODULE_LICENSE("GPL");
1612