xref: /linux/drivers/spi/spi-omap2-mcspi.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
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
76328caf0SMauro Carvalho Chehab  *		Juha Yrjola <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 
306361b4e4SAndy Shevchenko #include "internals.h"
316361b4e4SAndy Shevchenko 
322203747cSArnd Bergmann #include <linux/platform_data/spi-omap2-mcspi.h>
33ca632f55SGrant Likely 
34ca632f55SGrant Likely #define OMAP2_MCSPI_MAX_FREQ		48000000
35faee9b05SStefan Sørensen #define OMAP2_MCSPI_MAX_DIVIDER		4096
36d33f473dSIllia Smyrnov #define OMAP2_MCSPI_MAX_FIFODEPTH	64
37d33f473dSIllia Smyrnov #define OMAP2_MCSPI_MAX_FIFOWCNT	0xFFFF
3827b5284cSShubhrajyoti D #define SPI_AUTOSUSPEND_TIMEOUT		2000
39ca632f55SGrant Likely 
40ca632f55SGrant Likely #define OMAP2_MCSPI_REVISION		0x00
41ca632f55SGrant Likely #define OMAP2_MCSPI_SYSSTATUS		0x14
42ca632f55SGrant Likely #define OMAP2_MCSPI_IRQSTATUS		0x18
43ca632f55SGrant Likely #define OMAP2_MCSPI_IRQENABLE		0x1c
44ca632f55SGrant Likely #define OMAP2_MCSPI_WAKEUPENABLE	0x20
45ca632f55SGrant Likely #define OMAP2_MCSPI_SYST		0x24
46ca632f55SGrant Likely #define OMAP2_MCSPI_MODULCTRL		0x28
47d33f473dSIllia Smyrnov #define OMAP2_MCSPI_XFERLEVEL		0x7c
48ca632f55SGrant Likely 
49ca632f55SGrant Likely /* per-channel banks, 0x14 bytes each, first is: */
50ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF0		0x2c
51ca632f55SGrant Likely #define OMAP2_MCSPI_CHSTAT0		0x30
52ca632f55SGrant Likely #define OMAP2_MCSPI_CHCTRL0		0x34
53ca632f55SGrant Likely #define OMAP2_MCSPI_TX0			0x38
54ca632f55SGrant Likely #define OMAP2_MCSPI_RX0			0x3c
55ca632f55SGrant Likely 
56ca632f55SGrant Likely /* per-register bitmasks: */
57d33f473dSIllia Smyrnov #define OMAP2_MCSPI_IRQSTATUS_EOW	BIT(17)
58ca632f55SGrant Likely 
59ca632f55SGrant Likely #define OMAP2_MCSPI_MODULCTRL_SINGLE	BIT(0)
60ca632f55SGrant Likely #define OMAP2_MCSPI_MODULCTRL_MS	BIT(2)
61ca632f55SGrant Likely #define OMAP2_MCSPI_MODULCTRL_STEST	BIT(3)
62ca632f55SGrant Likely 
63ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_PHA		BIT(0)
64ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_POL		BIT(1)
65ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_CLKD_MASK	(0x0f << 2)
66ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_EPOL		BIT(6)
67ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_WL_MASK	(0x1f << 7)
68ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_TRM_RX_ONLY	BIT(12)
69ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_TRM_TX_ONLY	BIT(13)
70ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_TRM_MASK	(0x03 << 12)
71ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_DMAW		BIT(14)
72ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_DMAR		BIT(15)
73ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_DPE0		BIT(16)
74ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_DPE1		BIT(17)
75ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_IS		BIT(18)
76ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_TURBO	BIT(19)
77ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_FORCE	BIT(20)
78d33f473dSIllia Smyrnov #define OMAP2_MCSPI_CHCONF_FFET		BIT(27)
79d33f473dSIllia Smyrnov #define OMAP2_MCSPI_CHCONF_FFER		BIT(28)
80faee9b05SStefan Sørensen #define OMAP2_MCSPI_CHCONF_CLKG		BIT(29)
81ca632f55SGrant Likely 
82ca632f55SGrant Likely #define OMAP2_MCSPI_CHSTAT_RXS		BIT(0)
83ca632f55SGrant Likely #define OMAP2_MCSPI_CHSTAT_TXS		BIT(1)
84ca632f55SGrant Likely #define OMAP2_MCSPI_CHSTAT_EOT		BIT(2)
85d33f473dSIllia Smyrnov #define OMAP2_MCSPI_CHSTAT_TXFFE	BIT(3)
86ca632f55SGrant Likely 
87ca632f55SGrant Likely #define OMAP2_MCSPI_CHCTRL_EN		BIT(0)
88faee9b05SStefan Sørensen #define OMAP2_MCSPI_CHCTRL_EXTCLK_MASK	(0xff << 8)
89ca632f55SGrant Likely 
90ca632f55SGrant Likely #define OMAP2_MCSPI_WAKEUPENABLE_WKEN	BIT(0)
91ca632f55SGrant Likely 
92ca632f55SGrant Likely /* We have 2 DMA channels per CS, one for RX and one for TX */
93ca632f55SGrant Likely struct omap2_mcspi_dma {
9453741ed8SRussell King 	struct dma_chan *dma_tx;
9553741ed8SRussell King 	struct dma_chan *dma_rx;
96ca632f55SGrant Likely 
97ca632f55SGrant Likely 	struct completion dma_tx_completion;
98ca632f55SGrant Likely 	struct completion dma_rx_completion;
9974f3aaadSMatt Porter 
10074f3aaadSMatt Porter 	char dma_rx_ch_name[14];
10174f3aaadSMatt Porter 	char dma_tx_ch_name[14];
102ca632f55SGrant Likely };
103ca632f55SGrant Likely 
104ca632f55SGrant Likely /* use PIO for small transfers, avoiding DMA setup/teardown overhead and
105ca632f55SGrant Likely  * cache operations; better heuristics consider wordsize and bitrate.
106ca632f55SGrant Likely  */
107ca632f55SGrant Likely #define DMA_MIN_BYTES			160
108ca632f55SGrant Likely 
109ca632f55SGrant Likely 
1101bd897f8SBenoit Cousson /*
1111bd897f8SBenoit Cousson  * Used for context save and restore, structure members to be updated whenever
1121bd897f8SBenoit Cousson  * corresponding registers are modified.
1131bd897f8SBenoit Cousson  */
1141bd897f8SBenoit Cousson struct omap2_mcspi_regs {
1151bd897f8SBenoit Cousson 	u32 modulctrl;
1161bd897f8SBenoit Cousson 	u32 wakeupenable;
1171bd897f8SBenoit Cousson 	struct list_head cs;
1181bd897f8SBenoit Cousson };
1191bd897f8SBenoit Cousson 
120ca632f55SGrant Likely struct omap2_mcspi {
12189e8b9cbSVignesh R 	struct completion	txdone;
122ee0f793cSYang Yingliang 	struct spi_controller	*ctlr;
123ca632f55SGrant Likely 	/* Virtual base address of the controller */
124ca632f55SGrant Likely 	void __iomem		*base;
125ca632f55SGrant Likely 	unsigned long		phys;
126ca632f55SGrant Likely 	/* SPI1 has 4 channels, while SPI2 has 2 */
127ca632f55SGrant Likely 	struct omap2_mcspi_dma	*dma_channels;
128ca632f55SGrant Likely 	struct device		*dev;
1291bd897f8SBenoit Cousson 	struct omap2_mcspi_regs ctx;
1302d9f4877SVaishnav Achath 	struct clk		*ref_clk;
131d33f473dSIllia Smyrnov 	int			fifo_depth;
132ee0f793cSYang Yingliang 	bool			target_aborted;
1330384e90bSDaniel Mack 	unsigned int		pin_dir:1;
134e4e8276aSVignesh Raghavendra 	size_t			max_xfer_len;
1352d9f4877SVaishnav Achath 	u32			ref_clk_hz;
136d153ff40SLouis Chauvet 	bool			use_multi_mode;
137ca632f55SGrant Likely };
138ca632f55SGrant Likely 
139ca632f55SGrant Likely struct omap2_mcspi_cs {
140ca632f55SGrant Likely 	void __iomem		*base;
141ca632f55SGrant Likely 	unsigned long		phys;
142ca632f55SGrant Likely 	int			word_len;
14397ca0d6cSMark A. Greer 	u16			mode;
144ca632f55SGrant Likely 	struct list_head	node;
145ca632f55SGrant Likely 	/* Context save and restore shadow register */
146faee9b05SStefan Sørensen 	u32			chconf0, chctrl0;
147ca632f55SGrant Likely };
148ca632f55SGrant Likely 
mcspi_write_reg(struct spi_controller * ctlr,int idx,u32 val)149ee0f793cSYang Yingliang static inline void mcspi_write_reg(struct spi_controller *ctlr,
150ca632f55SGrant Likely 		int idx, u32 val)
151ca632f55SGrant Likely {
152ee0f793cSYang Yingliang 	struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr);
153ca632f55SGrant Likely 
15421b2ce5eSVictor Kamensky 	writel_relaxed(val, mcspi->base + idx);
155ca632f55SGrant Likely }
156ca632f55SGrant Likely 
mcspi_read_reg(struct spi_controller * ctlr,int idx)157ee0f793cSYang Yingliang static inline u32 mcspi_read_reg(struct spi_controller *ctlr, int idx)
158ca632f55SGrant Likely {
159ee0f793cSYang Yingliang 	struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr);
160ca632f55SGrant Likely 
16121b2ce5eSVictor Kamensky 	return readl_relaxed(mcspi->base + idx);
162ca632f55SGrant Likely }
163ca632f55SGrant Likely 
mcspi_write_cs_reg(const struct spi_device * spi,int idx,u32 val)164ca632f55SGrant Likely static inline void mcspi_write_cs_reg(const struct spi_device *spi,
165ca632f55SGrant Likely 		int idx, u32 val)
166ca632f55SGrant Likely {
167ca632f55SGrant Likely 	struct omap2_mcspi_cs	*cs = spi->controller_state;
168ca632f55SGrant Likely 
16921b2ce5eSVictor Kamensky 	writel_relaxed(val, cs->base +  idx);
170ca632f55SGrant Likely }
171ca632f55SGrant Likely 
mcspi_read_cs_reg(const struct spi_device * spi,int idx)172ca632f55SGrant Likely static inline u32 mcspi_read_cs_reg(const struct spi_device *spi, int idx)
173ca632f55SGrant Likely {
174ca632f55SGrant Likely 	struct omap2_mcspi_cs	*cs = spi->controller_state;
175ca632f55SGrant Likely 
17621b2ce5eSVictor Kamensky 	return readl_relaxed(cs->base + idx);
177ca632f55SGrant Likely }
178ca632f55SGrant Likely 
mcspi_cached_chconf0(const struct spi_device * spi)179ca632f55SGrant Likely static inline u32 mcspi_cached_chconf0(const struct spi_device *spi)
180ca632f55SGrant Likely {
181ca632f55SGrant Likely 	struct omap2_mcspi_cs *cs = spi->controller_state;
182ca632f55SGrant Likely 
183ca632f55SGrant Likely 	return cs->chconf0;
184ca632f55SGrant Likely }
185ca632f55SGrant Likely 
mcspi_write_chconf0(const struct spi_device * spi,u32 val)186ca632f55SGrant Likely static inline void mcspi_write_chconf0(const struct spi_device *spi, u32 val)
187ca632f55SGrant Likely {
188ca632f55SGrant Likely 	struct omap2_mcspi_cs *cs = spi->controller_state;
189ca632f55SGrant Likely 
190ca632f55SGrant Likely 	cs->chconf0 = val;
191ca632f55SGrant Likely 	mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, val);
192ca632f55SGrant Likely 	mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
193ca632f55SGrant Likely }
194ca632f55SGrant Likely 
mcspi_bytes_per_word(int word_len)19556cd5c15SIllia Smyrnov static inline int mcspi_bytes_per_word(int word_len)
19656cd5c15SIllia Smyrnov {
19756cd5c15SIllia Smyrnov 	if (word_len <= 8)
19856cd5c15SIllia Smyrnov 		return 1;
19956cd5c15SIllia Smyrnov 	else if (word_len <= 16)
20056cd5c15SIllia Smyrnov 		return 2;
20156cd5c15SIllia Smyrnov 	else /* word_len <= 32 */
20256cd5c15SIllia Smyrnov 		return 4;
20356cd5c15SIllia Smyrnov }
20456cd5c15SIllia Smyrnov 
omap2_mcspi_set_dma_req(const struct spi_device * spi,int is_read,int enable)205ca632f55SGrant Likely static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
206ca632f55SGrant Likely 		int is_read, int enable)
207ca632f55SGrant Likely {
208ca632f55SGrant Likely 	u32 l, rw;
209ca632f55SGrant Likely 
210ca632f55SGrant Likely 	l = mcspi_cached_chconf0(spi);
211ca632f55SGrant Likely 
212ca632f55SGrant Likely 	if (is_read) /* 1 is read, 0 write */
213ca632f55SGrant Likely 		rw = OMAP2_MCSPI_CHCONF_DMAR;
214ca632f55SGrant Likely 	else
215ca632f55SGrant Likely 		rw = OMAP2_MCSPI_CHCONF_DMAW;
216ca632f55SGrant Likely 
217af4e944dSShubhrajyoti D 	if (enable)
218af4e944dSShubhrajyoti D 		l |= rw;
219af4e944dSShubhrajyoti D 	else
220af4e944dSShubhrajyoti D 		l &= ~rw;
221af4e944dSShubhrajyoti D 
222ca632f55SGrant Likely 	mcspi_write_chconf0(spi, l);
223ca632f55SGrant Likely }
224ca632f55SGrant Likely 
omap2_mcspi_set_enable(const struct spi_device * spi,int enable)225ca632f55SGrant Likely static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
226ca632f55SGrant Likely {
227faee9b05SStefan Sørensen 	struct omap2_mcspi_cs *cs = spi->controller_state;
228ca632f55SGrant Likely 	u32 l;
229ca632f55SGrant Likely 
230faee9b05SStefan Sørensen 	l = cs->chctrl0;
231faee9b05SStefan Sørensen 	if (enable)
232faee9b05SStefan Sørensen 		l |= OMAP2_MCSPI_CHCTRL_EN;
233faee9b05SStefan Sørensen 	else
234faee9b05SStefan Sørensen 		l &= ~OMAP2_MCSPI_CHCTRL_EN;
235faee9b05SStefan Sørensen 	cs->chctrl0 = l;
236faee9b05SStefan Sørensen 	mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0);
237ca632f55SGrant Likely 	/* Flash post-writes */
238ca632f55SGrant Likely 	mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0);
239ca632f55SGrant Likely }
240ca632f55SGrant Likely 
omap2_mcspi_set_cs(struct spi_device * spi,bool enable)241ddcad7e9SMichael Welling static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable)
242ca632f55SGrant Likely {
243ee0f793cSYang Yingliang 	struct omap2_mcspi *mcspi = spi_controller_get_devdata(spi->controller);
244ca632f55SGrant Likely 	u32 l;
245ca632f55SGrant Likely 
2464373f8b6SMichael Welling 	/* The controller handles the inverted chip selects
2474373f8b6SMichael Welling 	 * using the OMAP2_MCSPI_CHCONF_EPOL bit so revert
2484373f8b6SMichael Welling 	 * the inversion from the core spi_set_cs function.
2494373f8b6SMichael Welling 	 */
2504373f8b6SMichael Welling 	if (spi->mode & SPI_CS_HIGH)
2514373f8b6SMichael Welling 		enable = !enable;
2524373f8b6SMichael Welling 
253ddcad7e9SMichael Welling 	if (spi->controller_state) {
25440b6a137SMinghao Chi 		int err = pm_runtime_resume_and_get(mcspi->dev);
2555f74db10SSebastian Reichel 		if (err < 0) {
2565f74db10SSebastian Reichel 			dev_err(mcspi->dev, "failed to get sync: %d\n", err);
2575f74db10SSebastian Reichel 			return;
2585f74db10SSebastian Reichel 		}
2595f74db10SSebastian Reichel 
260ca632f55SGrant Likely 		l = mcspi_cached_chconf0(spi);
261ddcad7e9SMichael Welling 
262d153ff40SLouis Chauvet 		/* Only enable chip select manually if single mode is used */
263d153ff40SLouis Chauvet 		if (mcspi->use_multi_mode) {
264d153ff40SLouis Chauvet 			l &= ~OMAP2_MCSPI_CHCONF_FORCE;
265d153ff40SLouis Chauvet 		} else {
266ddcad7e9SMichael Welling 			if (enable)
267af4e944dSShubhrajyoti D 				l &= ~OMAP2_MCSPI_CHCONF_FORCE;
268ddcad7e9SMichael Welling 			else
269ddcad7e9SMichael Welling 				l |= OMAP2_MCSPI_CHCONF_FORCE;
270d153ff40SLouis Chauvet 		}
271af4e944dSShubhrajyoti D 
272ca632f55SGrant Likely 		mcspi_write_chconf0(spi, l);
2735f74db10SSebastian Reichel 
2745f74db10SSebastian Reichel 		pm_runtime_mark_last_busy(mcspi->dev);
2755f74db10SSebastian Reichel 		pm_runtime_put_autosuspend(mcspi->dev);
276ca632f55SGrant Likely 	}
277ddcad7e9SMichael Welling }
278ca632f55SGrant Likely 
omap2_mcspi_set_mode(struct spi_controller * ctlr)279ee0f793cSYang Yingliang static void omap2_mcspi_set_mode(struct spi_controller *ctlr)
280ca632f55SGrant Likely {
281ee0f793cSYang Yingliang 	struct omap2_mcspi	*mcspi = spi_controller_get_devdata(ctlr);
2821bd897f8SBenoit Cousson 	struct omap2_mcspi_regs	*ctx = &mcspi->ctx;
283ca632f55SGrant Likely 	u32 l;
284ca632f55SGrant Likely 
2851bd897f8SBenoit Cousson 	/*
286ee0f793cSYang Yingliang 	 * Choose host or target mode
287ca632f55SGrant Likely 	 */
288ee0f793cSYang Yingliang 	l = mcspi_read_reg(ctlr, OMAP2_MCSPI_MODULCTRL);
28989e8b9cbSVignesh R 	l &= ~(OMAP2_MCSPI_MODULCTRL_STEST);
290ee0f793cSYang Yingliang 	if (spi_controller_is_target(ctlr)) {
29189e8b9cbSVignesh R 		l |= (OMAP2_MCSPI_MODULCTRL_MS);
29289e8b9cbSVignesh R 	} else {
29389e8b9cbSVignesh R 		l &= ~(OMAP2_MCSPI_MODULCTRL_MS);
294d153ff40SLouis Chauvet 
295d153ff40SLouis Chauvet 		/* Enable single mode if needed */
296d153ff40SLouis Chauvet 		if (mcspi->use_multi_mode)
297d153ff40SLouis Chauvet 			l &= ~OMAP2_MCSPI_MODULCTRL_SINGLE;
298d153ff40SLouis Chauvet 		else
299af4e944dSShubhrajyoti D 			l |= OMAP2_MCSPI_MODULCTRL_SINGLE;
30089e8b9cbSVignesh R 	}
301ee0f793cSYang Yingliang 	mcspi_write_reg(ctlr, OMAP2_MCSPI_MODULCTRL, l);
302ca632f55SGrant Likely 
3031bd897f8SBenoit Cousson 	ctx->modulctrl = l;
304ca632f55SGrant Likely }
305ca632f55SGrant Likely 
omap2_mcspi_set_fifo(const struct spi_device * spi,struct spi_transfer * t,int enable)306d33f473dSIllia Smyrnov static void omap2_mcspi_set_fifo(const struct spi_device *spi,
307e56c671cSVaishnav Achath 				struct spi_transfer *t, int enable)
308d33f473dSIllia Smyrnov {
309ee0f793cSYang Yingliang 	struct spi_controller *ctlr = spi->controller;
310d33f473dSIllia Smyrnov 	struct omap2_mcspi_cs *cs = spi->controller_state;
311d33f473dSIllia Smyrnov 	struct omap2_mcspi *mcspi;
312d33f473dSIllia Smyrnov 	unsigned int wcnt;
313b682cffaSVignesh R 	int max_fifo_depth, bytes_per_word;
314d33f473dSIllia Smyrnov 	u32 chconf, xferlevel;
315d33f473dSIllia Smyrnov 
316ee0f793cSYang Yingliang 	mcspi = spi_controller_get_devdata(ctlr);
317d33f473dSIllia Smyrnov 
318d33f473dSIllia Smyrnov 	chconf = mcspi_cached_chconf0(spi);
319d33f473dSIllia Smyrnov 	if (enable) {
320d33f473dSIllia Smyrnov 		bytes_per_word = mcspi_bytes_per_word(cs->word_len);
321d33f473dSIllia Smyrnov 		if (t->len % bytes_per_word != 0)
322d33f473dSIllia Smyrnov 			goto disable_fifo;
323d33f473dSIllia Smyrnov 
3245db542edSIllia Smyrnov 		if (t->rx_buf != NULL && t->tx_buf != NULL)
3255db542edSIllia Smyrnov 			max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH / 2;
3265db542edSIllia Smyrnov 		else
3275db542edSIllia Smyrnov 			max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH;
328e56c671cSVaishnav Achath 
329d33f473dSIllia Smyrnov 		wcnt = t->len / bytes_per_word;
330d33f473dSIllia Smyrnov 		if (wcnt > OMAP2_MCSPI_MAX_FIFOWCNT)
331d33f473dSIllia Smyrnov 			goto disable_fifo;
332d33f473dSIllia Smyrnov 
333d33f473dSIllia Smyrnov 		xferlevel = wcnt << 16;
334d33f473dSIllia Smyrnov 		if (t->rx_buf != NULL) {
335d33f473dSIllia Smyrnov 			chconf |= OMAP2_MCSPI_CHCONF_FFER;
336b682cffaSVignesh R 			xferlevel |= (bytes_per_word - 1) << 8;
3375db542edSIllia Smyrnov 		}
338b682cffaSVignesh R 
3395db542edSIllia Smyrnov 		if (t->tx_buf != NULL) {
340d33f473dSIllia Smyrnov 			chconf |= OMAP2_MCSPI_CHCONF_FFET;
341b682cffaSVignesh R 			xferlevel |= bytes_per_word - 1;
342d33f473dSIllia Smyrnov 		}
343d33f473dSIllia Smyrnov 
344ee0f793cSYang Yingliang 		mcspi_write_reg(ctlr, OMAP2_MCSPI_XFERLEVEL, xferlevel);
345d33f473dSIllia Smyrnov 		mcspi_write_chconf0(spi, chconf);
346b682cffaSVignesh R 		mcspi->fifo_depth = max_fifo_depth;
347d33f473dSIllia Smyrnov 
348d33f473dSIllia Smyrnov 		return;
349d33f473dSIllia Smyrnov 	}
350d33f473dSIllia Smyrnov 
351d33f473dSIllia Smyrnov disable_fifo:
352d33f473dSIllia Smyrnov 	if (t->rx_buf != NULL)
353d33f473dSIllia Smyrnov 		chconf &= ~OMAP2_MCSPI_CHCONF_FFER;
3543d0763c0SJorge A. Ventura 
3553d0763c0SJorge A. Ventura 	if (t->tx_buf != NULL)
356d33f473dSIllia Smyrnov 		chconf &= ~OMAP2_MCSPI_CHCONF_FFET;
357d33f473dSIllia Smyrnov 
358d33f473dSIllia Smyrnov 	mcspi_write_chconf0(spi, chconf);
359d33f473dSIllia Smyrnov 	mcspi->fifo_depth = 0;
360d33f473dSIllia Smyrnov }
361d33f473dSIllia Smyrnov 
mcspi_wait_for_reg_bit(void __iomem * reg,unsigned long bit)362ca632f55SGrant Likely static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
363ca632f55SGrant Likely {
3647b1d9681SAswath Govindraju 	unsigned long timeout;
365ca632f55SGrant Likely 
3667b1d9681SAswath Govindraju 	timeout = jiffies + msecs_to_jiffies(1000);
3677b1d9681SAswath Govindraju 	while (!(readl_relaxed(reg) & bit)) {
3687b1d9681SAswath Govindraju 		if (time_after(jiffies, timeout)) {
3697b1d9681SAswath Govindraju 			if (!(readl_relaxed(reg) & bit))
3707b1d9681SAswath Govindraju 				return -ETIMEDOUT;
3717b1d9681SAswath Govindraju 			else
3727b1d9681SAswath Govindraju 				return 0;
3737b1d9681SAswath Govindraju 		}
3747b1d9681SAswath Govindraju 		cpu_relax();
3757b1d9681SAswath Govindraju 	}
3767b1d9681SAswath Govindraju 	return 0;
377ca632f55SGrant Likely }
378ca632f55SGrant Likely 
mcspi_wait_for_completion(struct omap2_mcspi * mcspi,struct completion * x)37989e8b9cbSVignesh R static int mcspi_wait_for_completion(struct  omap2_mcspi *mcspi,
38089e8b9cbSVignesh R 				     struct completion *x)
38189e8b9cbSVignesh R {
382ee0f793cSYang Yingliang 	if (spi_controller_is_target(mcspi->ctlr)) {
38389e8b9cbSVignesh R 		if (wait_for_completion_interruptible(x) ||
384ee0f793cSYang Yingliang 		    mcspi->target_aborted)
38589e8b9cbSVignesh R 			return -EINTR;
38689e8b9cbSVignesh R 	} else {
38789e8b9cbSVignesh R 		wait_for_completion(x);
38889e8b9cbSVignesh R 	}
38989e8b9cbSVignesh R 
39089e8b9cbSVignesh R 	return 0;
39189e8b9cbSVignesh R }
39289e8b9cbSVignesh R 
omap2_mcspi_rx_callback(void * data)39353741ed8SRussell King static void omap2_mcspi_rx_callback(void *data)
39453741ed8SRussell King {
39553741ed8SRussell King 	struct spi_device *spi = data;
396ee0f793cSYang Yingliang 	struct omap2_mcspi *mcspi = spi_controller_get_devdata(spi->controller);
3979e264f3fSAmit Kumar Mahapatra via Alsa-devel 	struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi_get_chipselect(spi, 0)];
39853741ed8SRussell King 
39953741ed8SRussell King 	/* We must disable the DMA RX request */
40053741ed8SRussell King 	omap2_mcspi_set_dma_req(spi, 1, 0);
401830379e0SFelipe Balbi 
402830379e0SFelipe Balbi 	complete(&mcspi_dma->dma_rx_completion);
40353741ed8SRussell King }
40453741ed8SRussell King 
omap2_mcspi_tx_callback(void * data)40553741ed8SRussell King static void omap2_mcspi_tx_callback(void *data)
40653741ed8SRussell King {
40753741ed8SRussell King 	struct spi_device *spi = data;
408ee0f793cSYang Yingliang 	struct omap2_mcspi *mcspi = spi_controller_get_devdata(spi->controller);
4099e264f3fSAmit Kumar Mahapatra via Alsa-devel 	struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi_get_chipselect(spi, 0)];
41053741ed8SRussell King 
41153741ed8SRussell King 	/* We must disable the DMA TX request */
41253741ed8SRussell King 	omap2_mcspi_set_dma_req(spi, 0, 0);
413830379e0SFelipe Balbi 
414830379e0SFelipe Balbi 	complete(&mcspi_dma->dma_tx_completion);
41553741ed8SRussell King }
41653741ed8SRussell King 
omap2_mcspi_tx_dma(struct spi_device * spi,struct spi_transfer * xfer,struct dma_slave_config cfg)417d7b4394eSShubhrajyoti D static void omap2_mcspi_tx_dma(struct spi_device *spi,
418d7b4394eSShubhrajyoti D 				struct spi_transfer *xfer,
419d7b4394eSShubhrajyoti D 				struct dma_slave_config cfg)
420ca632f55SGrant Likely {
421ca632f55SGrant Likely 	struct omap2_mcspi	*mcspi;
422ca632f55SGrant Likely 	struct omap2_mcspi_dma  *mcspi_dma;
4238d858491SVignesh Raghavendra 	struct dma_async_tx_descriptor *tx;
424ca632f55SGrant Likely 
425ee0f793cSYang Yingliang 	mcspi = spi_controller_get_devdata(spi->controller);
4269e264f3fSAmit Kumar Mahapatra via Alsa-devel 	mcspi_dma = &mcspi->dma_channels[spi_get_chipselect(spi, 0)];
427ca632f55SGrant Likely 
42853741ed8SRussell King 	dmaengine_slave_config(mcspi_dma->dma_tx, &cfg);
42953741ed8SRussell King 
4300ba1870fSFranklin S Cooper Jr 	tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, xfer->tx_sg.sgl,
4310ba1870fSFranklin S Cooper Jr 				     xfer->tx_sg.nents,
4320ba1870fSFranklin S Cooper Jr 				     DMA_MEM_TO_DEV,
4330ba1870fSFranklin S Cooper Jr 				     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
43453741ed8SRussell King 	if (tx) {
43553741ed8SRussell King 		tx->callback = omap2_mcspi_tx_callback;
43653741ed8SRussell King 		tx->callback_param = spi;
43753741ed8SRussell King 		dmaengine_submit(tx);
43853741ed8SRussell King 	} else {
43953741ed8SRussell King 		/* FIXME: fall back to PIO? */
44053741ed8SRussell King 	}
44153741ed8SRussell King 	dma_async_issue_pending(mcspi_dma->dma_tx);
442ca632f55SGrant Likely 	omap2_mcspi_set_dma_req(spi, 0, 1);
443ca632f55SGrant Likely }
444ca632f55SGrant Likely 
445d7b4394eSShubhrajyoti D static unsigned
omap2_mcspi_rx_dma(struct spi_device * spi,struct spi_transfer * xfer,struct dma_slave_config cfg,unsigned es)446d7b4394eSShubhrajyoti D omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
447d7b4394eSShubhrajyoti D 				struct dma_slave_config cfg,
448d7b4394eSShubhrajyoti D 				unsigned es)
449d7b4394eSShubhrajyoti D {
450d7b4394eSShubhrajyoti D 	struct omap2_mcspi	*mcspi;
451d7b4394eSShubhrajyoti D 	struct omap2_mcspi_dma  *mcspi_dma;
4520ba1870fSFranklin S Cooper Jr 	unsigned int		count, transfer_reduction = 0;
4530ba1870fSFranklin S Cooper Jr 	struct scatterlist	*sg_out[2];
4540ba1870fSFranklin S Cooper Jr 	int			nb_sizes = 0, out_mapped_nents[2], ret, x;
4550ba1870fSFranklin S Cooper Jr 	size_t			sizes[2];
456d7b4394eSShubhrajyoti D 	u32			l;
457d7b4394eSShubhrajyoti D 	int			elements = 0;
458d7b4394eSShubhrajyoti D 	int			word_len, element_count;
459d7b4394eSShubhrajyoti D 	struct omap2_mcspi_cs	*cs = spi->controller_state;
46081261359SAkinobu Mita 	void __iomem		*chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
4618d858491SVignesh Raghavendra 	struct dma_async_tx_descriptor *tx;
46281261359SAkinobu Mita 
463ee0f793cSYang Yingliang 	mcspi = spi_controller_get_devdata(spi->controller);
4649e264f3fSAmit Kumar Mahapatra via Alsa-devel 	mcspi_dma = &mcspi->dma_channels[spi_get_chipselect(spi, 0)];
465d7b4394eSShubhrajyoti D 	count = xfer->len;
466d33f473dSIllia Smyrnov 
4674bd00413SFranklin S Cooper Jr 	/*
4684bd00413SFranklin S Cooper Jr 	 *  In the "End-of-Transfer Procedure" section for DMA RX in OMAP35x TRM
469ee0f793cSYang Yingliang 	 *  it mentions reducing DMA transfer length by one element in host
4704bd00413SFranklin S Cooper Jr 	 *  normal mode.
4714bd00413SFranklin S Cooper Jr 	 */
472d33f473dSIllia Smyrnov 	if (mcspi->fifo_depth == 0)
4730ba1870fSFranklin S Cooper Jr 		transfer_reduction = es;
474d33f473dSIllia Smyrnov 
475d7b4394eSShubhrajyoti D 	word_len = cs->word_len;
476d7b4394eSShubhrajyoti D 	l = mcspi_cached_chconf0(spi);
477d7b4394eSShubhrajyoti D 
478d7b4394eSShubhrajyoti D 	if (word_len <= 8)
479d7b4394eSShubhrajyoti D 		element_count = count;
480d7b4394eSShubhrajyoti D 	else if (word_len <= 16)
481d7b4394eSShubhrajyoti D 		element_count = count >> 1;
482d7b4394eSShubhrajyoti D 	else /* word_len <= 32 */
483d7b4394eSShubhrajyoti D 		element_count = count >> 2;
484d7b4394eSShubhrajyoti D 
485d7b4394eSShubhrajyoti D 
486d7b4394eSShubhrajyoti D 	dmaengine_slave_config(mcspi_dma->dma_rx, &cfg);
487d7b4394eSShubhrajyoti D 
4884bd00413SFranklin S Cooper Jr 	/*
4894bd00413SFranklin S Cooper Jr 	 *  Reduce DMA transfer length by one more if McSPI is
4904bd00413SFranklin S Cooper Jr 	 *  configured in turbo mode.
4914bd00413SFranklin S Cooper Jr 	 */
492d33f473dSIllia Smyrnov 	if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0)
4930ba1870fSFranklin S Cooper Jr 		transfer_reduction += es;
494d7b4394eSShubhrajyoti D 
4950ba1870fSFranklin S Cooper Jr 	if (transfer_reduction) {
4960ba1870fSFranklin S Cooper Jr 		/* Split sgl into two. The second sgl won't be used. */
4970ba1870fSFranklin S Cooper Jr 		sizes[0] = count - transfer_reduction;
4980ba1870fSFranklin S Cooper Jr 		sizes[1] = transfer_reduction;
4990ba1870fSFranklin S Cooper Jr 		nb_sizes = 2;
5000ba1870fSFranklin S Cooper Jr 	} else {
5010ba1870fSFranklin S Cooper Jr 		/*
5020ba1870fSFranklin S Cooper Jr 		 * Don't bother splitting the sgl. This essentially
5030ba1870fSFranklin S Cooper Jr 		 * clones the original sgl.
5040ba1870fSFranklin S Cooper Jr 		 */
5050ba1870fSFranklin S Cooper Jr 		sizes[0] = count;
5060ba1870fSFranklin S Cooper Jr 		nb_sizes = 1;
5070ba1870fSFranklin S Cooper Jr 	}
508d7b4394eSShubhrajyoti D 
5098d858491SVignesh Raghavendra 	ret = sg_split(xfer->rx_sg.sgl, xfer->rx_sg.nents, 0, nb_sizes,
5108d858491SVignesh Raghavendra 		       sizes, sg_out, out_mapped_nents, GFP_KERNEL);
5110ba1870fSFranklin S Cooper Jr 
5120ba1870fSFranklin S Cooper Jr 	if (ret < 0) {
5130ba1870fSFranklin S Cooper Jr 		dev_err(&spi->dev, "sg_split failed\n");
5140ba1870fSFranklin S Cooper Jr 		return 0;
5150ba1870fSFranklin S Cooper Jr 	}
5160ba1870fSFranklin S Cooper Jr 
5178d858491SVignesh Raghavendra 	tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, sg_out[0],
5188d858491SVignesh Raghavendra 				     out_mapped_nents[0], DMA_DEV_TO_MEM,
5190ba1870fSFranklin S Cooper Jr 				     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
520d7b4394eSShubhrajyoti D 	if (tx) {
521d7b4394eSShubhrajyoti D 		tx->callback = omap2_mcspi_rx_callback;
522d7b4394eSShubhrajyoti D 		tx->callback_param = spi;
523d7b4394eSShubhrajyoti D 		dmaengine_submit(tx);
524d7b4394eSShubhrajyoti D 	} else {
525d7b4394eSShubhrajyoti D 		/* FIXME: fall back to PIO? */
526d7b4394eSShubhrajyoti D 	}
527d7b4394eSShubhrajyoti D 
528d7b4394eSShubhrajyoti D 	dma_async_issue_pending(mcspi_dma->dma_rx);
529d7b4394eSShubhrajyoti D 	omap2_mcspi_set_dma_req(spi, 1, 1);
530d7b4394eSShubhrajyoti D 
53189e8b9cbSVignesh R 	ret = mcspi_wait_for_completion(mcspi, &mcspi_dma->dma_rx_completion);
532ee0f793cSYang Yingliang 	if (ret || mcspi->target_aborted) {
53389e8b9cbSVignesh R 		dmaengine_terminate_sync(mcspi_dma->dma_rx);
53489e8b9cbSVignesh R 		omap2_mcspi_set_dma_req(spi, 1, 0);
53589e8b9cbSVignesh R 		return 0;
53689e8b9cbSVignesh R 	}
5370ba1870fSFranklin S Cooper Jr 
5380ba1870fSFranklin S Cooper Jr 	for (x = 0; x < nb_sizes; x++)
5390ba1870fSFranklin S Cooper Jr 		kfree(sg_out[x]);
540d33f473dSIllia Smyrnov 
541d33f473dSIllia Smyrnov 	if (mcspi->fifo_depth > 0)
542d33f473dSIllia Smyrnov 		return count;
543d33f473dSIllia Smyrnov 
5444bd00413SFranklin S Cooper Jr 	/*
5454bd00413SFranklin S Cooper Jr 	 *  Due to the DMA transfer length reduction the missing bytes must
5464bd00413SFranklin S Cooper Jr 	 *  be read manually to receive all of the expected data.
5474bd00413SFranklin S Cooper Jr 	 */
548ca632f55SGrant Likely 	omap2_mcspi_set_enable(spi, 0);
549ca632f55SGrant Likely 
55053741ed8SRussell King 	elements = element_count - 1;
55153741ed8SRussell King 
552ca632f55SGrant Likely 	if (l & OMAP2_MCSPI_CHCONF_TURBO) {
55353741ed8SRussell King 		elements--;
554ca632f55SGrant Likely 
55581261359SAkinobu Mita 		if (!mcspi_wait_for_reg_bit(chstat_reg,
55681261359SAkinobu Mita 					    OMAP2_MCSPI_CHSTAT_RXS)) {
557ca632f55SGrant Likely 			u32 w;
558ca632f55SGrant Likely 
559ca632f55SGrant Likely 			w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
560ca632f55SGrant Likely 			if (word_len <= 8)
561ca632f55SGrant Likely 				((u8 *)xfer->rx_buf)[elements++] = w;
562ca632f55SGrant Likely 			else if (word_len <= 16)
563ca632f55SGrant Likely 				((u16 *)xfer->rx_buf)[elements++] = w;
564ca632f55SGrant Likely 			else /* word_len <= 32 */
565ca632f55SGrant Likely 				((u32 *)xfer->rx_buf)[elements++] = w;
566ca632f55SGrant Likely 		} else {
56756cd5c15SIllia Smyrnov 			int bytes_per_word = mcspi_bytes_per_word(word_len);
568a1829d2bSJarkko Nikula 			dev_err(&spi->dev, "DMA RX penultimate word empty\n");
56956cd5c15SIllia Smyrnov 			count -= (bytes_per_word << 1);
570ca632f55SGrant Likely 			omap2_mcspi_set_enable(spi, 1);
571ca632f55SGrant Likely 			return count;
572ca632f55SGrant Likely 		}
573ca632f55SGrant Likely 	}
57481261359SAkinobu Mita 	if (!mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_RXS)) {
575ca632f55SGrant Likely 		u32 w;
576ca632f55SGrant Likely 
577ca632f55SGrant Likely 		w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
578ca632f55SGrant Likely 		if (word_len <= 8)
579ca632f55SGrant Likely 			((u8 *)xfer->rx_buf)[elements] = w;
580ca632f55SGrant Likely 		else if (word_len <= 16)
581ca632f55SGrant Likely 			((u16 *)xfer->rx_buf)[elements] = w;
582ca632f55SGrant Likely 		else /* word_len <= 32 */
583ca632f55SGrant Likely 			((u32 *)xfer->rx_buf)[elements] = w;
584ca632f55SGrant Likely 	} else {
585a1829d2bSJarkko Nikula 		dev_err(&spi->dev, "DMA RX last word empty\n");
58656cd5c15SIllia Smyrnov 		count -= mcspi_bytes_per_word(word_len);
587ca632f55SGrant Likely 	}
588ca632f55SGrant Likely 	omap2_mcspi_set_enable(spi, 1);
589d7b4394eSShubhrajyoti D 	return count;
590ca632f55SGrant Likely }
591d7b4394eSShubhrajyoti D 
592d7b4394eSShubhrajyoti D static unsigned
omap2_mcspi_txrx_dma(struct spi_device * spi,struct spi_transfer * xfer)593d7b4394eSShubhrajyoti D omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
594d7b4394eSShubhrajyoti D {
595d7b4394eSShubhrajyoti D 	struct omap2_mcspi	*mcspi;
596d7b4394eSShubhrajyoti D 	struct omap2_mcspi_cs	*cs = spi->controller_state;
597d7b4394eSShubhrajyoti D 	struct omap2_mcspi_dma  *mcspi_dma;
598d7b4394eSShubhrajyoti D 	unsigned int		count;
599d7b4394eSShubhrajyoti D 	u8			*rx;
600d7b4394eSShubhrajyoti D 	const u8		*tx;
601d7b4394eSShubhrajyoti D 	struct dma_slave_config	cfg;
602d7b4394eSShubhrajyoti D 	enum dma_slave_buswidth width;
603d7b4394eSShubhrajyoti D 	unsigned es;
604e47a682aSShubhrajyoti D 	void __iomem		*chstat_reg;
605d33f473dSIllia Smyrnov 	void __iomem            *irqstat_reg;
606d33f473dSIllia Smyrnov 	int			wait_res;
607d7b4394eSShubhrajyoti D 
608ee0f793cSYang Yingliang 	mcspi = spi_controller_get_devdata(spi->controller);
6099e264f3fSAmit Kumar Mahapatra via Alsa-devel 	mcspi_dma = &mcspi->dma_channels[spi_get_chipselect(spi, 0)];
610d7b4394eSShubhrajyoti D 
611d7b4394eSShubhrajyoti D 	if (cs->word_len <= 8) {
612d7b4394eSShubhrajyoti D 		width = DMA_SLAVE_BUSWIDTH_1_BYTE;
613d7b4394eSShubhrajyoti D 		es = 1;
614d7b4394eSShubhrajyoti D 	} else if (cs->word_len <= 16) {
615d7b4394eSShubhrajyoti D 		width = DMA_SLAVE_BUSWIDTH_2_BYTES;
616d7b4394eSShubhrajyoti D 		es = 2;
617d7b4394eSShubhrajyoti D 	} else {
618d7b4394eSShubhrajyoti D 		width = DMA_SLAVE_BUSWIDTH_4_BYTES;
619d7b4394eSShubhrajyoti D 		es = 4;
620d7b4394eSShubhrajyoti D 	}
621d7b4394eSShubhrajyoti D 
622d33f473dSIllia Smyrnov 	count = xfer->len;
623d33f473dSIllia Smyrnov 
624d7b4394eSShubhrajyoti D 	memset(&cfg, 0, sizeof(cfg));
625d7b4394eSShubhrajyoti D 	cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0;
626d7b4394eSShubhrajyoti D 	cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0;
627d7b4394eSShubhrajyoti D 	cfg.src_addr_width = width;
628d7b4394eSShubhrajyoti D 	cfg.dst_addr_width = width;
629baf8b9f8SVignesh R 	cfg.src_maxburst = 1;
630baf8b9f8SVignesh R 	cfg.dst_maxburst = 1;
631d7b4394eSShubhrajyoti D 
632d7b4394eSShubhrajyoti D 	rx = xfer->rx_buf;
633d7b4394eSShubhrajyoti D 	tx = xfer->tx_buf;
634d7b4394eSShubhrajyoti D 
635ee0f793cSYang Yingliang 	mcspi->target_aborted = false;
63689e8b9cbSVignesh R 	reinit_completion(&mcspi_dma->dma_tx_completion);
63789e8b9cbSVignesh R 	reinit_completion(&mcspi_dma->dma_rx_completion);
63889e8b9cbSVignesh R 	reinit_completion(&mcspi->txdone);
63989e8b9cbSVignesh R 	if (tx) {
640ee0f793cSYang Yingliang 		/* Enable EOW IRQ to know end of tx in target mode */
641ee0f793cSYang Yingliang 		if (spi_controller_is_target(spi->controller))
642ee0f793cSYang Yingliang 			mcspi_write_reg(spi->controller,
64389e8b9cbSVignesh R 					OMAP2_MCSPI_IRQENABLE,
64489e8b9cbSVignesh R 					OMAP2_MCSPI_IRQSTATUS_EOW);
645d7b4394eSShubhrajyoti D 		omap2_mcspi_tx_dma(spi, xfer, cfg);
64689e8b9cbSVignesh R 	}
647d7b4394eSShubhrajyoti D 
648d7b4394eSShubhrajyoti D 	if (rx != NULL)
649e47a682aSShubhrajyoti D 		count = omap2_mcspi_rx_dma(spi, xfer, cfg, es);
650d7b4394eSShubhrajyoti D 
651e47a682aSShubhrajyoti D 	if (tx != NULL) {
65289e8b9cbSVignesh R 		int ret;
65389e8b9cbSVignesh R 
65489e8b9cbSVignesh R 		ret = mcspi_wait_for_completion(mcspi, &mcspi_dma->dma_tx_completion);
655ee0f793cSYang Yingliang 		if (ret || mcspi->target_aborted) {
65689e8b9cbSVignesh R 			dmaengine_terminate_sync(mcspi_dma->dma_tx);
65789e8b9cbSVignesh R 			omap2_mcspi_set_dma_req(spi, 0, 0);
65889e8b9cbSVignesh R 			return 0;
65989e8b9cbSVignesh R 		}
66089e8b9cbSVignesh R 
661ee0f793cSYang Yingliang 		if (spi_controller_is_target(mcspi->ctlr)) {
66289e8b9cbSVignesh R 			ret = mcspi_wait_for_completion(mcspi, &mcspi->txdone);
663ee0f793cSYang Yingliang 			if (ret || mcspi->target_aborted)
66489e8b9cbSVignesh R 				return 0;
66589e8b9cbSVignesh R 		}
666e47a682aSShubhrajyoti D 
667d33f473dSIllia Smyrnov 		if (mcspi->fifo_depth > 0) {
668d33f473dSIllia Smyrnov 			irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS;
669d33f473dSIllia Smyrnov 
670d33f473dSIllia Smyrnov 			if (mcspi_wait_for_reg_bit(irqstat_reg,
671d33f473dSIllia Smyrnov 						OMAP2_MCSPI_IRQSTATUS_EOW) < 0)
672d33f473dSIllia Smyrnov 				dev_err(&spi->dev, "EOW timed out\n");
673d33f473dSIllia Smyrnov 
674ee0f793cSYang Yingliang 			mcspi_write_reg(mcspi->ctlr, OMAP2_MCSPI_IRQSTATUS,
675d33f473dSIllia Smyrnov 					OMAP2_MCSPI_IRQSTATUS_EOW);
676d33f473dSIllia Smyrnov 		}
677d33f473dSIllia Smyrnov 
678e47a682aSShubhrajyoti D 		/* for TX_ONLY mode, be sure all words have shifted out */
679e47a682aSShubhrajyoti D 		if (rx == NULL) {
680d33f473dSIllia Smyrnov 			chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
681d33f473dSIllia Smyrnov 			if (mcspi->fifo_depth > 0) {
682d33f473dSIllia Smyrnov 				wait_res = mcspi_wait_for_reg_bit(chstat_reg,
683d33f473dSIllia Smyrnov 						OMAP2_MCSPI_CHSTAT_TXFFE);
684d33f473dSIllia Smyrnov 				if (wait_res < 0)
685d33f473dSIllia Smyrnov 					dev_err(&spi->dev, "TXFFE timed out\n");
686d33f473dSIllia Smyrnov 			} else {
687d33f473dSIllia Smyrnov 				wait_res = mcspi_wait_for_reg_bit(chstat_reg,
688d33f473dSIllia Smyrnov 						OMAP2_MCSPI_CHSTAT_TXS);
689d33f473dSIllia Smyrnov 				if (wait_res < 0)
690e47a682aSShubhrajyoti D 					dev_err(&spi->dev, "TXS timed out\n");
691d33f473dSIllia Smyrnov 			}
692d33f473dSIllia Smyrnov 			if (wait_res >= 0 &&
693d33f473dSIllia Smyrnov 				(mcspi_wait_for_reg_bit(chstat_reg,
694d33f473dSIllia Smyrnov 					OMAP2_MCSPI_CHSTAT_EOT) < 0))
695e47a682aSShubhrajyoti D 				dev_err(&spi->dev, "EOT timed out\n");
696e47a682aSShubhrajyoti D 		}
697e47a682aSShubhrajyoti D 	}
698ca632f55SGrant Likely 	return count;
699ca632f55SGrant Likely }
700ca632f55SGrant Likely 
701ca632f55SGrant Likely static unsigned
omap2_mcspi_txrx_pio(struct spi_device * spi,struct spi_transfer * xfer)702ca632f55SGrant Likely omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
703ca632f55SGrant Likely {
704ca632f55SGrant Likely 	struct omap2_mcspi_cs	*cs = spi->controller_state;
705ca632f55SGrant Likely 	unsigned int		count, c;
706ca632f55SGrant Likely 	u32			l;
707ca632f55SGrant Likely 	void __iomem		*base = cs->base;
708ca632f55SGrant Likely 	void __iomem		*tx_reg;
709ca632f55SGrant Likely 	void __iomem		*rx_reg;
710ca632f55SGrant Likely 	void __iomem		*chstat_reg;
711ca632f55SGrant Likely 	int			word_len;
712ca632f55SGrant Likely 
713ca632f55SGrant Likely 	count = xfer->len;
714ca632f55SGrant Likely 	c = count;
715ca632f55SGrant Likely 	word_len = cs->word_len;
716ca632f55SGrant Likely 
717ca632f55SGrant Likely 	l = mcspi_cached_chconf0(spi);
718ca632f55SGrant Likely 
719ca632f55SGrant Likely 	/* We store the pre-calculated register addresses on stack to speed
720ca632f55SGrant Likely 	 * up the transfer loop. */
721ca632f55SGrant Likely 	tx_reg		= base + OMAP2_MCSPI_TX0;
722ca632f55SGrant Likely 	rx_reg		= base + OMAP2_MCSPI_RX0;
723ca632f55SGrant Likely 	chstat_reg	= base + OMAP2_MCSPI_CHSTAT0;
724ca632f55SGrant Likely 
725ca632f55SGrant Likely 	if (c < (word_len>>3))
726ca632f55SGrant Likely 		return 0;
727ca632f55SGrant Likely 
728ca632f55SGrant Likely 	if (word_len <= 8) {
729ca632f55SGrant Likely 		u8		*rx;
730ca632f55SGrant Likely 		const u8	*tx;
731ca632f55SGrant Likely 
732ca632f55SGrant Likely 		rx = xfer->rx_buf;
733ca632f55SGrant Likely 		tx = xfer->tx_buf;
734ca632f55SGrant Likely 
735ca632f55SGrant Likely 		do {
736ca632f55SGrant Likely 			c -= 1;
737ca632f55SGrant Likely 			if (tx != NULL) {
738ca632f55SGrant Likely 				if (mcspi_wait_for_reg_bit(chstat_reg,
739ca632f55SGrant Likely 						OMAP2_MCSPI_CHSTAT_TXS) < 0) {
740ca632f55SGrant Likely 					dev_err(&spi->dev, "TXS timed out\n");
741ca632f55SGrant Likely 					goto out;
742ca632f55SGrant Likely 				}
743ca632f55SGrant Likely 				dev_vdbg(&spi->dev, "write-%d %02x\n",
744ca632f55SGrant Likely 						word_len, *tx);
74521b2ce5eSVictor Kamensky 				writel_relaxed(*tx++, tx_reg);
746ca632f55SGrant Likely 			}
747ca632f55SGrant Likely 			if (rx != NULL) {
748ca632f55SGrant Likely 				if (mcspi_wait_for_reg_bit(chstat_reg,
749ca632f55SGrant Likely 						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
750ca632f55SGrant Likely 					dev_err(&spi->dev, "RXS timed out\n");
751ca632f55SGrant Likely 					goto out;
752ca632f55SGrant Likely 				}
753ca632f55SGrant Likely 
754ca632f55SGrant Likely 				if (c == 1 && tx == NULL &&
755ca632f55SGrant Likely 				    (l & OMAP2_MCSPI_CHCONF_TURBO)) {
756ca632f55SGrant Likely 					omap2_mcspi_set_enable(spi, 0);
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 					if (mcspi_wait_for_reg_bit(chstat_reg,
761ca632f55SGrant Likely 						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
762ca632f55SGrant Likely 						dev_err(&spi->dev,
763ca632f55SGrant Likely 							"RXS timed out\n");
764ca632f55SGrant Likely 						goto out;
765ca632f55SGrant Likely 					}
766ca632f55SGrant Likely 					c = 0;
767ca632f55SGrant Likely 				} else if (c == 0 && tx == NULL) {
768ca632f55SGrant Likely 					omap2_mcspi_set_enable(spi, 0);
769ca632f55SGrant Likely 				}
770ca632f55SGrant Likely 
77121b2ce5eSVictor Kamensky 				*rx++ = readl_relaxed(rx_reg);
772ca632f55SGrant Likely 				dev_vdbg(&spi->dev, "read-%d %02x\n",
773ca632f55SGrant Likely 						word_len, *(rx - 1));
774ca632f55SGrant Likely 			}
7752cd757e6SAndrea Zanotti 			/* Add word delay between each word */
7762cd757e6SAndrea Zanotti 			spi_delay_exec(&xfer->word_delay, xfer);
777ca632f55SGrant Likely 		} while (c);
778ca632f55SGrant Likely 	} else if (word_len <= 16) {
779ca632f55SGrant Likely 		u16		*rx;
780ca632f55SGrant Likely 		const u16	*tx;
781ca632f55SGrant Likely 
782ca632f55SGrant Likely 		rx = xfer->rx_buf;
783ca632f55SGrant Likely 		tx = xfer->tx_buf;
784ca632f55SGrant Likely 		do {
785ca632f55SGrant Likely 			c -= 2;
786ca632f55SGrant Likely 			if (tx != NULL) {
787ca632f55SGrant Likely 				if (mcspi_wait_for_reg_bit(chstat_reg,
788ca632f55SGrant Likely 						OMAP2_MCSPI_CHSTAT_TXS) < 0) {
789ca632f55SGrant Likely 					dev_err(&spi->dev, "TXS timed out\n");
790ca632f55SGrant Likely 					goto out;
791ca632f55SGrant Likely 				}
792ca632f55SGrant Likely 				dev_vdbg(&spi->dev, "write-%d %04x\n",
793ca632f55SGrant Likely 						word_len, *tx);
79421b2ce5eSVictor Kamensky 				writel_relaxed(*tx++, tx_reg);
795ca632f55SGrant Likely 			}
796ca632f55SGrant Likely 			if (rx != NULL) {
797ca632f55SGrant Likely 				if (mcspi_wait_for_reg_bit(chstat_reg,
798ca632f55SGrant Likely 						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
799ca632f55SGrant Likely 					dev_err(&spi->dev, "RXS timed out\n");
800ca632f55SGrant Likely 					goto out;
801ca632f55SGrant Likely 				}
802ca632f55SGrant Likely 
803ca632f55SGrant Likely 				if (c == 2 && tx == NULL &&
804ca632f55SGrant Likely 				    (l & OMAP2_MCSPI_CHCONF_TURBO)) {
805ca632f55SGrant Likely 					omap2_mcspi_set_enable(spi, 0);
80621b2ce5eSVictor Kamensky 					*rx++ = readl_relaxed(rx_reg);
807ca632f55SGrant Likely 					dev_vdbg(&spi->dev, "read-%d %04x\n",
808ca632f55SGrant Likely 						    word_len, *(rx - 1));
809ca632f55SGrant Likely 					if (mcspi_wait_for_reg_bit(chstat_reg,
810ca632f55SGrant Likely 						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
811ca632f55SGrant Likely 						dev_err(&spi->dev,
812ca632f55SGrant Likely 							"RXS timed out\n");
813ca632f55SGrant Likely 						goto out;
814ca632f55SGrant Likely 					}
815ca632f55SGrant Likely 					c = 0;
816ca632f55SGrant Likely 				} else if (c == 0 && tx == NULL) {
817ca632f55SGrant Likely 					omap2_mcspi_set_enable(spi, 0);
818ca632f55SGrant Likely 				}
819ca632f55SGrant Likely 
82021b2ce5eSVictor Kamensky 				*rx++ = readl_relaxed(rx_reg);
821ca632f55SGrant Likely 				dev_vdbg(&spi->dev, "read-%d %04x\n",
822ca632f55SGrant Likely 						word_len, *(rx - 1));
823ca632f55SGrant Likely 			}
8242cd757e6SAndrea Zanotti 			/* Add word delay between each word */
8252cd757e6SAndrea Zanotti 			spi_delay_exec(&xfer->word_delay, xfer);
826ca632f55SGrant Likely 		} while (c >= 2);
827ca632f55SGrant Likely 	} else if (word_len <= 32) {
828ca632f55SGrant Likely 		u32		*rx;
829ca632f55SGrant Likely 		const u32	*tx;
830ca632f55SGrant Likely 
831ca632f55SGrant Likely 		rx = xfer->rx_buf;
832ca632f55SGrant Likely 		tx = xfer->tx_buf;
833ca632f55SGrant Likely 		do {
834ca632f55SGrant Likely 			c -= 4;
835ca632f55SGrant Likely 			if (tx != NULL) {
836ca632f55SGrant Likely 				if (mcspi_wait_for_reg_bit(chstat_reg,
837ca632f55SGrant Likely 						OMAP2_MCSPI_CHSTAT_TXS) < 0) {
838ca632f55SGrant Likely 					dev_err(&spi->dev, "TXS timed out\n");
839ca632f55SGrant Likely 					goto out;
840ca632f55SGrant Likely 				}
841ca632f55SGrant Likely 				dev_vdbg(&spi->dev, "write-%d %08x\n",
842ca632f55SGrant Likely 						word_len, *tx);
84321b2ce5eSVictor Kamensky 				writel_relaxed(*tx++, tx_reg);
844ca632f55SGrant Likely 			}
845ca632f55SGrant Likely 			if (rx != NULL) {
846ca632f55SGrant Likely 				if (mcspi_wait_for_reg_bit(chstat_reg,
847ca632f55SGrant Likely 						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
848ca632f55SGrant Likely 					dev_err(&spi->dev, "RXS timed out\n");
849ca632f55SGrant Likely 					goto out;
850ca632f55SGrant Likely 				}
851ca632f55SGrant Likely 
852ca632f55SGrant Likely 				if (c == 4 && tx == NULL &&
853ca632f55SGrant Likely 				    (l & OMAP2_MCSPI_CHCONF_TURBO)) {
854ca632f55SGrant Likely 					omap2_mcspi_set_enable(spi, 0);
85521b2ce5eSVictor Kamensky 					*rx++ = readl_relaxed(rx_reg);
856ca632f55SGrant Likely 					dev_vdbg(&spi->dev, "read-%d %08x\n",
857ca632f55SGrant Likely 						    word_len, *(rx - 1));
858ca632f55SGrant Likely 					if (mcspi_wait_for_reg_bit(chstat_reg,
859ca632f55SGrant Likely 						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
860ca632f55SGrant Likely 						dev_err(&spi->dev,
861ca632f55SGrant Likely 							"RXS timed out\n");
862ca632f55SGrant Likely 						goto out;
863ca632f55SGrant Likely 					}
864ca632f55SGrant Likely 					c = 0;
865ca632f55SGrant Likely 				} else if (c == 0 && tx == NULL) {
866ca632f55SGrant Likely 					omap2_mcspi_set_enable(spi, 0);
867ca632f55SGrant Likely 				}
868ca632f55SGrant Likely 
86921b2ce5eSVictor Kamensky 				*rx++ = readl_relaxed(rx_reg);
870ca632f55SGrant Likely 				dev_vdbg(&spi->dev, "read-%d %08x\n",
871ca632f55SGrant Likely 						word_len, *(rx - 1));
872ca632f55SGrant Likely 			}
8732cd757e6SAndrea Zanotti 			/* Add word delay between each word */
8742cd757e6SAndrea Zanotti 			spi_delay_exec(&xfer->word_delay, xfer);
875ca632f55SGrant Likely 		} while (c >= 4);
876ca632f55SGrant Likely 	}
877ca632f55SGrant Likely 
878ca632f55SGrant Likely 	/* for TX_ONLY mode, be sure all words have shifted out */
879ca632f55SGrant Likely 	if (xfer->rx_buf == NULL) {
880ca632f55SGrant Likely 		if (mcspi_wait_for_reg_bit(chstat_reg,
881ca632f55SGrant Likely 				OMAP2_MCSPI_CHSTAT_TXS) < 0) {
882ca632f55SGrant Likely 			dev_err(&spi->dev, "TXS timed out\n");
883ca632f55SGrant Likely 		} else if (mcspi_wait_for_reg_bit(chstat_reg,
884ca632f55SGrant Likely 				OMAP2_MCSPI_CHSTAT_EOT) < 0)
885ca632f55SGrant Likely 			dev_err(&spi->dev, "EOT timed out\n");
886ca632f55SGrant Likely 
887ca632f55SGrant Likely 		/* disable chan to purge rx datas received in TX_ONLY transfer,
888ca632f55SGrant Likely 		 * otherwise these rx datas will affect the direct following
889ca632f55SGrant Likely 		 * RX_ONLY transfer.
890ca632f55SGrant Likely 		 */
891ca632f55SGrant Likely 		omap2_mcspi_set_enable(spi, 0);
892ca632f55SGrant Likely 	}
893ca632f55SGrant Likely out:
894ca632f55SGrant Likely 	omap2_mcspi_set_enable(spi, 1);
895ca632f55SGrant Likely 	return count - c;
896ca632f55SGrant Likely }
897ca632f55SGrant Likely 
omap2_mcspi_calc_divisor(u32 speed_hz,u32 ref_clk_hz)8982d9f4877SVaishnav Achath static u32 omap2_mcspi_calc_divisor(u32 speed_hz, u32 ref_clk_hz)
899ca632f55SGrant Likely {
900ca632f55SGrant Likely 	u32 div;
901ca632f55SGrant Likely 
902ca632f55SGrant Likely 	for (div = 0; div < 15; div++)
9032d9f4877SVaishnav Achath 		if (speed_hz >= (ref_clk_hz >> div))
904ca632f55SGrant Likely 			return div;
905ca632f55SGrant Likely 
906ca632f55SGrant Likely 	return 15;
907ca632f55SGrant Likely }
908ca632f55SGrant Likely 
909ca632f55SGrant Likely /* called only when no transfer is active to this device */
omap2_mcspi_setup_transfer(struct spi_device * spi,struct spi_transfer * t)910ca632f55SGrant Likely static int omap2_mcspi_setup_transfer(struct spi_device *spi,
911ca632f55SGrant Likely 		struct spi_transfer *t)
912ca632f55SGrant Likely {
913ca632f55SGrant Likely 	struct omap2_mcspi_cs *cs = spi->controller_state;
914ca632f55SGrant Likely 	struct omap2_mcspi *mcspi;
9152d9f4877SVaishnav Achath 	u32 ref_clk_hz, l = 0, clkd = 0, div, extclk = 0, clkg = 0;
916ca632f55SGrant Likely 	u8 word_len = spi->bits_per_word;
917ca632f55SGrant Likely 	u32 speed_hz = spi->max_speed_hz;
918ca632f55SGrant Likely 
919ee0f793cSYang Yingliang 	mcspi = spi_controller_get_devdata(spi->controller);
920ca632f55SGrant Likely 
921ca632f55SGrant Likely 	if (t != NULL && t->bits_per_word)
922ca632f55SGrant Likely 		word_len = t->bits_per_word;
923ca632f55SGrant Likely 
924ca632f55SGrant Likely 	cs->word_len = word_len;
925ca632f55SGrant Likely 
926ca632f55SGrant Likely 	if (t && t->speed_hz)
927ca632f55SGrant Likely 		speed_hz = t->speed_hz;
928ca632f55SGrant Likely 
9292d9f4877SVaishnav Achath 	ref_clk_hz = mcspi->ref_clk_hz;
9302d9f4877SVaishnav Achath 	speed_hz = min_t(u32, speed_hz, ref_clk_hz);
9312d9f4877SVaishnav Achath 	if (speed_hz < (ref_clk_hz / OMAP2_MCSPI_MAX_DIVIDER)) {
9322d9f4877SVaishnav Achath 		clkd = omap2_mcspi_calc_divisor(speed_hz, ref_clk_hz);
9332d9f4877SVaishnav Achath 		speed_hz = ref_clk_hz >> clkd;
934faee9b05SStefan Sørensen 		clkg = 0;
935faee9b05SStefan Sørensen 	} else {
9362d9f4877SVaishnav Achath 		div = (ref_clk_hz + speed_hz - 1) / speed_hz;
9372d9f4877SVaishnav Achath 		speed_hz = ref_clk_hz / div;
938faee9b05SStefan Sørensen 		clkd = (div - 1) & 0xf;
939faee9b05SStefan Sørensen 		extclk = (div - 1) >> 4;
940faee9b05SStefan Sørensen 		clkg = OMAP2_MCSPI_CHCONF_CLKG;
941faee9b05SStefan Sørensen 	}
942ca632f55SGrant Likely 
943ca632f55SGrant Likely 	l = mcspi_cached_chconf0(spi);
944ca632f55SGrant Likely 
945ee0f793cSYang Yingliang 	/* standard 4-wire host mode:  SCK, MOSI/out, MISO/in, nCS
946ca632f55SGrant Likely 	 * REVISIT: this controller could support SPI_3WIRE mode.
947ca632f55SGrant Likely 	 */
9482cd45179SDaniel Mack 	if (mcspi->pin_dir == MCSPI_PINDIR_D0_IN_D1_OUT) {
9490384e90bSDaniel Mack 		l &= ~OMAP2_MCSPI_CHCONF_IS;
9500384e90bSDaniel Mack 		l &= ~OMAP2_MCSPI_CHCONF_DPE1;
951ca632f55SGrant Likely 		l |= OMAP2_MCSPI_CHCONF_DPE0;
9520384e90bSDaniel Mack 	} else {
9530384e90bSDaniel Mack 		l |= OMAP2_MCSPI_CHCONF_IS;
9540384e90bSDaniel Mack 		l |= OMAP2_MCSPI_CHCONF_DPE1;
9550384e90bSDaniel Mack 		l &= ~OMAP2_MCSPI_CHCONF_DPE0;
9560384e90bSDaniel Mack 	}
957ca632f55SGrant Likely 
958ca632f55SGrant Likely 	/* wordlength */
959ca632f55SGrant Likely 	l &= ~OMAP2_MCSPI_CHCONF_WL_MASK;
960ca632f55SGrant Likely 	l |= (word_len - 1) << 7;
961ca632f55SGrant Likely 
962ca632f55SGrant Likely 	/* set chipselect polarity; manage with FORCE */
963ca632f55SGrant Likely 	if (!(spi->mode & SPI_CS_HIGH))
964ca632f55SGrant Likely 		l |= OMAP2_MCSPI_CHCONF_EPOL;	/* active-low; normal */
965ca632f55SGrant Likely 	else
966ca632f55SGrant Likely 		l &= ~OMAP2_MCSPI_CHCONF_EPOL;
967ca632f55SGrant Likely 
968ca632f55SGrant Likely 	/* set clock divisor */
969ca632f55SGrant Likely 	l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK;
970faee9b05SStefan Sørensen 	l |= clkd << 2;
971faee9b05SStefan Sørensen 
972faee9b05SStefan Sørensen 	/* set clock granularity */
973faee9b05SStefan Sørensen 	l &= ~OMAP2_MCSPI_CHCONF_CLKG;
974faee9b05SStefan Sørensen 	l |= clkg;
975faee9b05SStefan Sørensen 	if (clkg) {
976faee9b05SStefan Sørensen 		cs->chctrl0 &= ~OMAP2_MCSPI_CHCTRL_EXTCLK_MASK;
977faee9b05SStefan Sørensen 		cs->chctrl0 |= extclk << 8;
978faee9b05SStefan Sørensen 		mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0);
979faee9b05SStefan Sørensen 	}
980ca632f55SGrant Likely 
981ca632f55SGrant Likely 	/* set SPI mode 0..3 */
982ca632f55SGrant Likely 	if (spi->mode & SPI_CPOL)
983ca632f55SGrant Likely 		l |= OMAP2_MCSPI_CHCONF_POL;
984ca632f55SGrant Likely 	else
985ca632f55SGrant Likely 		l &= ~OMAP2_MCSPI_CHCONF_POL;
986ca632f55SGrant Likely 	if (spi->mode & SPI_CPHA)
987ca632f55SGrant Likely 		l |= OMAP2_MCSPI_CHCONF_PHA;
988ca632f55SGrant Likely 	else
989ca632f55SGrant Likely 		l &= ~OMAP2_MCSPI_CHCONF_PHA;
990ca632f55SGrant Likely 
991ca632f55SGrant Likely 	mcspi_write_chconf0(spi, l);
992ca632f55SGrant Likely 
99397ca0d6cSMark A. Greer 	cs->mode = spi->mode;
99497ca0d6cSMark A. Greer 
995ca632f55SGrant Likely 	dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s\n",
996faee9b05SStefan Sørensen 			speed_hz,
997ca632f55SGrant Likely 			(spi->mode & SPI_CPHA) ? "trailing" : "leading",
998ca632f55SGrant Likely 			(spi->mode & SPI_CPOL) ? "inverted" : "normal");
999ca632f55SGrant Likely 
1000ca632f55SGrant Likely 	return 0;
1001ca632f55SGrant Likely }
1002ca632f55SGrant Likely 
1003ddc5cdf1STony Lindgren /*
1004ddc5cdf1STony Lindgren  * Note that we currently allow DMA only if we get a channel
1005ddc5cdf1STony Lindgren  * for both rx and tx. Otherwise we'll do PIO for both rx and tx.
1006ddc5cdf1STony Lindgren  */
omap2_mcspi_request_dma(struct omap2_mcspi * mcspi,struct omap2_mcspi_dma * mcspi_dma)100732f2fc5dSVignesh Raghavendra static int omap2_mcspi_request_dma(struct omap2_mcspi *mcspi,
100832f2fc5dSVignesh Raghavendra 				   struct omap2_mcspi_dma *mcspi_dma)
1009ca632f55SGrant Likely {
1010b085c612SPeter Ujfalusi 	int ret = 0;
1011ca632f55SGrant Likely 
101232f2fc5dSVignesh Raghavendra 	mcspi_dma->dma_rx = dma_request_chan(mcspi->dev,
101374f3aaadSMatt Porter 					     mcspi_dma->dma_rx_ch_name);
1014b085c612SPeter Ujfalusi 	if (IS_ERR(mcspi_dma->dma_rx)) {
1015b085c612SPeter Ujfalusi 		ret = PTR_ERR(mcspi_dma->dma_rx);
101653741ed8SRussell King 		mcspi_dma->dma_rx = NULL;
1017ddc5cdf1STony Lindgren 		goto no_dma;
101853741ed8SRussell King 	}
1019ca632f55SGrant Likely 
102032f2fc5dSVignesh Raghavendra 	mcspi_dma->dma_tx = dma_request_chan(mcspi->dev,
1021b085c612SPeter Ujfalusi 					     mcspi_dma->dma_tx_ch_name);
1022b085c612SPeter Ujfalusi 	if (IS_ERR(mcspi_dma->dma_tx)) {
1023b085c612SPeter Ujfalusi 		ret = PTR_ERR(mcspi_dma->dma_tx);
1024b085c612SPeter Ujfalusi 		mcspi_dma->dma_tx = NULL;
1025b085c612SPeter Ujfalusi 		dma_release_channel(mcspi_dma->dma_rx);
1026b085c612SPeter Ujfalusi 		mcspi_dma->dma_rx = NULL;
1027b085c612SPeter Ujfalusi 	}
1028ddc5cdf1STony Lindgren 
102932f2fc5dSVignesh Raghavendra 	init_completion(&mcspi_dma->dma_rx_completion);
103032f2fc5dSVignesh Raghavendra 	init_completion(&mcspi_dma->dma_tx_completion);
103132f2fc5dSVignesh Raghavendra 
1032ddc5cdf1STony Lindgren no_dma:
1033b085c612SPeter Ujfalusi 	return ret;
1034ca632f55SGrant Likely }
1035ca632f55SGrant Likely 
omap2_mcspi_release_dma(struct spi_controller * ctlr)1036ee0f793cSYang Yingliang static void omap2_mcspi_release_dma(struct spi_controller *ctlr)
103732f2fc5dSVignesh Raghavendra {
1038ee0f793cSYang Yingliang 	struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr);
103932f2fc5dSVignesh Raghavendra 	struct omap2_mcspi_dma	*mcspi_dma;
104032f2fc5dSVignesh Raghavendra 	int i;
104132f2fc5dSVignesh Raghavendra 
1042ee0f793cSYang Yingliang 	for (i = 0; i < ctlr->num_chipselect; i++) {
104332f2fc5dSVignesh Raghavendra 		mcspi_dma = &mcspi->dma_channels[i];
104432f2fc5dSVignesh Raghavendra 
104532f2fc5dSVignesh Raghavendra 		if (mcspi_dma->dma_rx) {
104632f2fc5dSVignesh Raghavendra 			dma_release_channel(mcspi_dma->dma_rx);
104732f2fc5dSVignesh Raghavendra 			mcspi_dma->dma_rx = NULL;
104832f2fc5dSVignesh Raghavendra 		}
104932f2fc5dSVignesh Raghavendra 		if (mcspi_dma->dma_tx) {
105032f2fc5dSVignesh Raghavendra 			dma_release_channel(mcspi_dma->dma_tx);
105132f2fc5dSVignesh Raghavendra 			mcspi_dma->dma_tx = NULL;
105232f2fc5dSVignesh Raghavendra 		}
105332f2fc5dSVignesh Raghavendra 	}
105432f2fc5dSVignesh Raghavendra }
105532f2fc5dSVignesh Raghavendra 
omap2_mcspi_cleanup(struct spi_device * spi)10562ec6f20bSLukas Wunner static void omap2_mcspi_cleanup(struct spi_device *spi)
10572ec6f20bSLukas Wunner {
10582ec6f20bSLukas Wunner 	struct omap2_mcspi_cs	*cs;
10592ec6f20bSLukas Wunner 
10602ec6f20bSLukas Wunner 	if (spi->controller_state) {
10612ec6f20bSLukas Wunner 		/* Unlink controller state from context save list */
10622ec6f20bSLukas Wunner 		cs = spi->controller_state;
10632ec6f20bSLukas Wunner 		list_del(&cs->node);
10642ec6f20bSLukas Wunner 
10652ec6f20bSLukas Wunner 		kfree(cs);
10662ec6f20bSLukas Wunner 	}
10672ec6f20bSLukas Wunner }
10682ec6f20bSLukas Wunner 
omap2_mcspi_setup(struct spi_device * spi)1069ca632f55SGrant Likely static int omap2_mcspi_setup(struct spi_device *spi)
1070ca632f55SGrant Likely {
10712ec6f20bSLukas Wunner 	bool			initial_setup = false;
1072ca632f55SGrant Likely 	int			ret;
1073ee0f793cSYang Yingliang 	struct omap2_mcspi	*mcspi = spi_controller_get_devdata(spi->controller);
10741bd897f8SBenoit Cousson 	struct omap2_mcspi_regs	*ctx = &mcspi->ctx;
1075ca632f55SGrant Likely 	struct omap2_mcspi_cs	*cs = spi->controller_state;
1076ca632f55SGrant Likely 
1077ca632f55SGrant Likely 	if (!cs) {
10788267dc6dSZhiqi Song 		cs = kzalloc(sizeof(*cs), GFP_KERNEL);
1079ca632f55SGrant Likely 		if (!cs)
1080ca632f55SGrant Likely 			return -ENOMEM;
10819e264f3fSAmit Kumar Mahapatra via Alsa-devel 		cs->base = mcspi->base + spi_get_chipselect(spi, 0) * 0x14;
10829e264f3fSAmit Kumar Mahapatra via Alsa-devel 		cs->phys = mcspi->phys + spi_get_chipselect(spi, 0) * 0x14;
108397ca0d6cSMark A. Greer 		cs->mode = 0;
1084ca632f55SGrant Likely 		cs->chconf0 = 0;
1085faee9b05SStefan Sørensen 		cs->chctrl0 = 0;
1086ca632f55SGrant Likely 		spi->controller_state = cs;
1087ca632f55SGrant Likely 		/* Link this to context save list */
10881bd897f8SBenoit Cousson 		list_add_tail(&cs->node, &ctx->cs);
10892ec6f20bSLukas Wunner 		initial_setup = true;
10902f538c01SMichael Welling 	}
10912f538c01SMichael Welling 
109240b6a137SMinghao Chi 	ret = pm_runtime_resume_and_get(mcspi->dev);
10935a686b2cSTony Lindgren 	if (ret < 0) {
10942ec6f20bSLukas Wunner 		if (initial_setup)
10952ec6f20bSLukas Wunner 			omap2_mcspi_cleanup(spi);
10965a686b2cSTony Lindgren 
1097ca632f55SGrant Likely 		return ret;
10985a686b2cSTony Lindgren 	}
1099ca632f55SGrant Likely 
1100ca632f55SGrant Likely 	ret = omap2_mcspi_setup_transfer(spi, NULL);
11012ec6f20bSLukas Wunner 	if (ret && initial_setup)
11022ec6f20bSLukas Wunner 		omap2_mcspi_cleanup(spi);
11032ec6f20bSLukas Wunner 
1104034d3dc9SShubhrajyoti D 	pm_runtime_mark_last_busy(mcspi->dev);
1105034d3dc9SShubhrajyoti D 	pm_runtime_put_autosuspend(mcspi->dev);
1106ca632f55SGrant Likely 
1107ca632f55SGrant Likely 	return ret;
1108ca632f55SGrant Likely }
1109ca632f55SGrant Likely 
omap2_mcspi_irq_handler(int irq,void * data)111089e8b9cbSVignesh R static irqreturn_t omap2_mcspi_irq_handler(int irq, void *data)
111189e8b9cbSVignesh R {
111289e8b9cbSVignesh R 	struct omap2_mcspi *mcspi = data;
111389e8b9cbSVignesh R 	u32 irqstat;
111489e8b9cbSVignesh R 
1115ee0f793cSYang Yingliang 	irqstat	= mcspi_read_reg(mcspi->ctlr, OMAP2_MCSPI_IRQSTATUS);
111689e8b9cbSVignesh R 	if (!irqstat)
111789e8b9cbSVignesh R 		return IRQ_NONE;
111889e8b9cbSVignesh R 
1119ee0f793cSYang Yingliang 	/* Disable IRQ and wakeup target xfer task */
1120ee0f793cSYang Yingliang 	mcspi_write_reg(mcspi->ctlr, OMAP2_MCSPI_IRQENABLE, 0);
112189e8b9cbSVignesh R 	if (irqstat & OMAP2_MCSPI_IRQSTATUS_EOW)
112289e8b9cbSVignesh R 		complete(&mcspi->txdone);
112389e8b9cbSVignesh R 
112489e8b9cbSVignesh R 	return IRQ_HANDLED;
112589e8b9cbSVignesh R }
112689e8b9cbSVignesh R 
omap2_mcspi_target_abort(struct spi_controller * ctlr)1127ee0f793cSYang Yingliang static int omap2_mcspi_target_abort(struct spi_controller *ctlr)
112889e8b9cbSVignesh R {
1129ee0f793cSYang Yingliang 	struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr);
113089e8b9cbSVignesh R 	struct omap2_mcspi_dma *mcspi_dma = mcspi->dma_channels;
113189e8b9cbSVignesh R 
1132ee0f793cSYang Yingliang 	mcspi->target_aborted = true;
113389e8b9cbSVignesh R 	complete(&mcspi_dma->dma_rx_completion);
113489e8b9cbSVignesh R 	complete(&mcspi_dma->dma_tx_completion);
113589e8b9cbSVignesh R 	complete(&mcspi->txdone);
113689e8b9cbSVignesh R 
113789e8b9cbSVignesh R 	return 0;
113889e8b9cbSVignesh R }
113989e8b9cbSVignesh R 
omap2_mcspi_transfer_one(struct spi_controller * ctlr,struct spi_device * spi,struct spi_transfer * t)1140ee0f793cSYang Yingliang static int omap2_mcspi_transfer_one(struct spi_controller *ctlr,
11410ba1870fSFranklin S Cooper Jr 				    struct spi_device *spi,
11420ba1870fSFranklin S Cooper Jr 				    struct spi_transfer *t)
1143ca632f55SGrant Likely {
1144ca632f55SGrant Likely 
1145ca632f55SGrant Likely 	/* We only enable one channel at a time -- the one whose message is
11465fda88f5SShubhrajyoti D 	 * -- although this controller would gladly
1147ca632f55SGrant Likely 	 * arbitrate among multiple channels.  This corresponds to "single
1148ee0f793cSYang Yingliang 	 * channel" host mode.  As a side effect, we need to manage the
1149ca632f55SGrant Likely 	 * chipselect with the FORCE bit ... CS != channel enable.
1150ca632f55SGrant Likely 	 */
11515fda88f5SShubhrajyoti D 
11520ba1870fSFranklin S Cooper Jr 	struct omap2_mcspi		*mcspi;
1153ddc5cdf1STony Lindgren 	struct omap2_mcspi_dma		*mcspi_dma;
1154ca632f55SGrant Likely 	struct omap2_mcspi_cs		*cs;
1155ca632f55SGrant Likely 	struct omap2_mcspi_device_config *cd;
1156ca632f55SGrant Likely 	int				par_override = 0;
1157ca632f55SGrant Likely 	int				status = 0;
1158ca632f55SGrant Likely 	u32				chconf;
1159ca632f55SGrant Likely 
1160ee0f793cSYang Yingliang 	mcspi = spi_controller_get_devdata(ctlr);
11619e264f3fSAmit Kumar Mahapatra via Alsa-devel 	mcspi_dma = mcspi->dma_channels + spi_get_chipselect(spi, 0);
1162ca632f55SGrant Likely 	cs = spi->controller_state;
1163ca632f55SGrant Likely 	cd = spi->controller_data;
1164ca632f55SGrant Likely 
116597ca0d6cSMark A. Greer 	/*
1166ee0f793cSYang Yingliang 	 * The target driver could have changed spi->mode in which case
116797ca0d6cSMark A. Greer 	 * it will be different from cs->mode (the current hardware setup).
116897ca0d6cSMark A. Greer 	 * If so, set par_override (even though its not a parity issue) so
116997ca0d6cSMark A. Greer 	 * omap2_mcspi_setup_transfer will be called to configure the hardware
117097ca0d6cSMark A. Greer 	 * with the correct mode on the first iteration of the loop below.
117197ca0d6cSMark A. Greer 	 */
117297ca0d6cSMark A. Greer 	if (spi->mode != cs->mode)
117397ca0d6cSMark A. Greer 		par_override = 1;
117497ca0d6cSMark A. Greer 
1175d33f473dSIllia Smyrnov 	omap2_mcspi_set_enable(spi, 0);
1176b28cb941SMichael Welling 
11779e264f3fSAmit Kumar Mahapatra via Alsa-devel 	if (spi_get_csgpiod(spi, 0))
1178a06b430fSMichael Welling 		omap2_mcspi_set_cs(spi, spi->mode & SPI_CS_HIGH);
1179a06b430fSMichael Welling 
11802bd16e3eSStefan Sørensen 	if (par_override ||
11812bd16e3eSStefan Sørensen 	    (t->speed_hz != spi->max_speed_hz) ||
11822bd16e3eSStefan Sørensen 	    (t->bits_per_word != spi->bits_per_word)) {
1183ca632f55SGrant Likely 		par_override = 1;
1184ca632f55SGrant Likely 		status = omap2_mcspi_setup_transfer(spi, t);
1185ca632f55SGrant Likely 		if (status < 0)
1186b28cb941SMichael Welling 			goto out;
11872bd16e3eSStefan Sørensen 		if (t->speed_hz == spi->max_speed_hz &&
11882bd16e3eSStefan Sørensen 		    t->bits_per_word == spi->bits_per_word)
1189ca632f55SGrant Likely 			par_override = 0;
1190ca632f55SGrant Likely 	}
11915cbc7ca9SMatthias Brugger 
1192ca632f55SGrant Likely 	chconf = mcspi_cached_chconf0(spi);
1193ca632f55SGrant Likely 	chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
1194ca632f55SGrant Likely 	chconf &= ~OMAP2_MCSPI_CHCONF_TURBO;
1195ca632f55SGrant Likely 
1196ca632f55SGrant Likely 	if (t->tx_buf == NULL)
1197ca632f55SGrant Likely 		chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
1198ca632f55SGrant Likely 	else if (t->rx_buf == NULL)
1199ca632f55SGrant Likely 		chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
1200ca632f55SGrant Likely 
1201ca632f55SGrant Likely 	if (cd && cd->turbo_mode && t->tx_buf == NULL) {
1202ca632f55SGrant Likely 		/* Turbo mode is for more than one word */
1203ca632f55SGrant Likely 		if (t->len > ((cs->word_len + 7) >> 3))
1204ca632f55SGrant Likely 			chconf |= OMAP2_MCSPI_CHCONF_TURBO;
1205ca632f55SGrant Likely 	}
1206ca632f55SGrant Likely 
1207ca632f55SGrant Likely 	mcspi_write_chconf0(spi, chconf);
1208ca632f55SGrant Likely 
1209ca632f55SGrant Likely 	if (t->len) {
1210ca632f55SGrant Likely 		unsigned	count;
1211ca632f55SGrant Likely 
1212d33f473dSIllia Smyrnov 		if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
12136361b4e4SAndy Shevchenko 		    spi_xfer_is_dma_mapped(ctlr, spi, t))
1214e56c671cSVaishnav Achath 			omap2_mcspi_set_fifo(spi, t, 1);
1215d33f473dSIllia Smyrnov 
1216d33f473dSIllia Smyrnov 		omap2_mcspi_set_enable(spi, 1);
1217d33f473dSIllia Smyrnov 
1218ca632f55SGrant Likely 		/* RX_ONLY mode needs dummy data in TX reg */
1219ca632f55SGrant Likely 		if (t->tx_buf == NULL)
122021b2ce5eSVictor Kamensky 			writel_relaxed(0, cs->base
1221ca632f55SGrant Likely 					+ OMAP2_MCSPI_TX0);
1222ca632f55SGrant Likely 
1223ddc5cdf1STony Lindgren 		if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) &&
12246361b4e4SAndy Shevchenko 		    spi_xfer_is_dma_mapped(ctlr, spi, t))
1225ca632f55SGrant Likely 			count = omap2_mcspi_txrx_dma(spi, t);
1226ca632f55SGrant Likely 		else
1227ca632f55SGrant Likely 			count = omap2_mcspi_txrx_pio(spi, t);
1228ca632f55SGrant Likely 
1229ca632f55SGrant Likely 		if (count != t->len) {
1230ca632f55SGrant Likely 			status = -EIO;
1231b28cb941SMichael Welling 			goto out;
1232ca632f55SGrant Likely 		}
1233ca632f55SGrant Likely 	}
1234ca632f55SGrant Likely 
1235d33f473dSIllia Smyrnov 	omap2_mcspi_set_enable(spi, 0);
1236d33f473dSIllia Smyrnov 
1237d33f473dSIllia Smyrnov 	if (mcspi->fifo_depth > 0)
1238e56c671cSVaishnav Achath 		omap2_mcspi_set_fifo(spi, t, 0);
1239b28cb941SMichael Welling 
1240b28cb941SMichael Welling out:
1241ca632f55SGrant Likely 	/* Restore defaults if they were overriden */
1242ca632f55SGrant Likely 	if (par_override) {
1243ca632f55SGrant Likely 		par_override = 0;
1244ca632f55SGrant Likely 		status = omap2_mcspi_setup_transfer(spi, NULL);
1245ca632f55SGrant Likely 	}
1246ca632f55SGrant Likely 
1247ca632f55SGrant Likely 	omap2_mcspi_set_enable(spi, 0);
1248ca632f55SGrant Likely 
12499e264f3fSAmit Kumar Mahapatra via Alsa-devel 	if (spi_get_csgpiod(spi, 0))
1250a06b430fSMichael Welling 		omap2_mcspi_set_cs(spi, !(spi->mode & SPI_CS_HIGH));
1251a06b430fSMichael Welling 
1252d33f473dSIllia Smyrnov 	if (mcspi->fifo_depth > 0 && t)
1253e56c671cSVaishnav Achath 		omap2_mcspi_set_fifo(spi, t, 0);
1254ca632f55SGrant Likely 
1255b28cb941SMichael Welling 	return status;
1256ca632f55SGrant Likely }
1257ca632f55SGrant Likely 
omap2_mcspi_prepare_message(struct spi_controller * ctlr,struct spi_message * msg)1258ee0f793cSYang Yingliang static int omap2_mcspi_prepare_message(struct spi_controller *ctlr,
1259468a3208SNeil Armstrong 				       struct spi_message *msg)
1260468a3208SNeil Armstrong {
1261ee0f793cSYang Yingliang 	struct omap2_mcspi	*mcspi = spi_controller_get_devdata(ctlr);
1262468a3208SNeil Armstrong 	struct omap2_mcspi_regs	*ctx = &mcspi->ctx;
1263468a3208SNeil Armstrong 	struct omap2_mcspi_cs	*cs;
1264d153ff40SLouis Chauvet 	struct spi_transfer	*tr;
1265d153ff40SLouis Chauvet 	u8 bits_per_word;
1266468a3208SNeil Armstrong 
1267d153ff40SLouis Chauvet 	/*
1268d153ff40SLouis Chauvet 	 * The conditions are strict, it is mandatory to check each transfer of the list to see if
1269d153ff40SLouis Chauvet 	 * multi-mode is applicable.
1270d153ff40SLouis Chauvet 	 */
1271d153ff40SLouis Chauvet 	mcspi->use_multi_mode = true;
1272d153ff40SLouis Chauvet 	list_for_each_entry(tr, &msg->transfers, transfer_list) {
1273d153ff40SLouis Chauvet 		if (!tr->bits_per_word)
1274d153ff40SLouis Chauvet 			bits_per_word = msg->spi->bits_per_word;
1275d153ff40SLouis Chauvet 		else
1276d153ff40SLouis Chauvet 			bits_per_word = tr->bits_per_word;
1277d153ff40SLouis Chauvet 
1278d153ff40SLouis Chauvet 		/*
1279d153ff40SLouis Chauvet 		 * Check if this transfer contains only one word;
1280d153ff40SLouis Chauvet 		 */
1281d153ff40SLouis Chauvet 		if (bits_per_word < 8 && tr->len == 1) {
1282d153ff40SLouis Chauvet 			/* multi-mode is applicable, only one word (1..7 bits) */
1283d153ff40SLouis Chauvet 		} else if (bits_per_word >= 8 && tr->len == bits_per_word / 8) {
12848221545cSMark Brown 			/* multi-mode is applicable, only one word (8..32 bits) */
1285d153ff40SLouis Chauvet 		} else {
1286d153ff40SLouis Chauvet 			/* multi-mode is not applicable: more than one word in the transfer */
1287d153ff40SLouis Chauvet 			mcspi->use_multi_mode = false;
1288d153ff40SLouis Chauvet 		}
1289d153ff40SLouis Chauvet 
1290d153ff40SLouis Chauvet 		/* Check if transfer asks to change the CS status after the transfer */
1291d153ff40SLouis Chauvet 		if (!tr->cs_change)
1292d153ff40SLouis Chauvet 			mcspi->use_multi_mode = false;
1293d153ff40SLouis Chauvet 
1294d153ff40SLouis Chauvet 		/*
1295d153ff40SLouis Chauvet 		 * If at least one message is not compatible, switch back to single mode
1296d153ff40SLouis Chauvet 		 *
1297d153ff40SLouis Chauvet 		 * The bits_per_word of certain transfer can be different, but it will have no
1298d153ff40SLouis Chauvet 		 * impact on the signal itself.
1299d153ff40SLouis Chauvet 		 */
1300d153ff40SLouis Chauvet 		if (!mcspi->use_multi_mode)
1301d153ff40SLouis Chauvet 			break;
1302d153ff40SLouis Chauvet 	}
1303d153ff40SLouis Chauvet 
1304d153ff40SLouis Chauvet 	omap2_mcspi_set_mode(ctlr);
1305d153ff40SLouis Chauvet 
1306d153ff40SLouis Chauvet 	/* In single mode only a single channel can have the FORCE bit enabled
1307468a3208SNeil Armstrong 	 * in its chconf0 register.
1308468a3208SNeil Armstrong 	 * Scan all channels and disable them except the current one.
1309468a3208SNeil Armstrong 	 * A FORCE can remain from a last transfer having cs_change enabled
1310d153ff40SLouis Chauvet 	 *
1311d153ff40SLouis Chauvet 	 * In multi mode all FORCE bits must be disabled.
1312468a3208SNeil Armstrong 	 */
1313468a3208SNeil Armstrong 	list_for_each_entry(cs, &ctx->cs, node) {
1314d153ff40SLouis Chauvet 		if (msg->spi->controller_state == cs && !mcspi->use_multi_mode) {
1315468a3208SNeil Armstrong 			continue;
1316d153ff40SLouis Chauvet 		}
1317468a3208SNeil Armstrong 
1318468a3208SNeil Armstrong 		if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE)) {
1319468a3208SNeil Armstrong 			cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE;
1320468a3208SNeil Armstrong 			writel_relaxed(cs->chconf0,
1321468a3208SNeil Armstrong 					cs->base + OMAP2_MCSPI_CHCONF0);
1322468a3208SNeil Armstrong 			readl_relaxed(cs->base + OMAP2_MCSPI_CHCONF0);
1323468a3208SNeil Armstrong 		}
1324468a3208SNeil Armstrong 	}
1325468a3208SNeil Armstrong 
1326468a3208SNeil Armstrong 	return 0;
1327468a3208SNeil Armstrong }
1328468a3208SNeil Armstrong 
omap2_mcspi_can_dma(struct spi_controller * ctlr,struct spi_device * spi,struct spi_transfer * xfer)1329ee0f793cSYang Yingliang static bool omap2_mcspi_can_dma(struct spi_controller *ctlr,
13300ba1870fSFranklin S Cooper Jr 				struct spi_device *spi,
13310ba1870fSFranklin S Cooper Jr 				struct spi_transfer *xfer)
1332ca632f55SGrant Likely {
1333ee0f793cSYang Yingliang 	struct omap2_mcspi *mcspi = spi_controller_get_devdata(spi->controller);
133489e8b9cbSVignesh R 	struct omap2_mcspi_dma *mcspi_dma =
13359e264f3fSAmit Kumar Mahapatra via Alsa-devel 		&mcspi->dma_channels[spi_get_chipselect(spi, 0)];
133689e8b9cbSVignesh R 
133789e8b9cbSVignesh R 	if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx)
133889e8b9cbSVignesh R 		return false;
133989e8b9cbSVignesh R 
1340ee0f793cSYang Yingliang 	if (spi_controller_is_target(ctlr))
134189e8b9cbSVignesh R 		return true;
134289e8b9cbSVignesh R 
1343ee0f793cSYang Yingliang 	ctlr->dma_rx = mcspi_dma->dma_rx;
1344ee0f793cSYang Yingliang 	ctlr->dma_tx = mcspi_dma->dma_tx;
134532f2fc5dSVignesh Raghavendra 
13460ba1870fSFranklin S Cooper Jr 	return (xfer->len >= DMA_MIN_BYTES);
1347ca632f55SGrant Likely }
1348ca632f55SGrant Likely 
omap2_mcspi_max_xfer_size(struct spi_device * spi)1349e4e8276aSVignesh Raghavendra static size_t omap2_mcspi_max_xfer_size(struct spi_device *spi)
1350e4e8276aSVignesh Raghavendra {
1351ee0f793cSYang Yingliang 	struct omap2_mcspi *mcspi = spi_controller_get_devdata(spi->controller);
1352e4e8276aSVignesh Raghavendra 	struct omap2_mcspi_dma *mcspi_dma =
13539e264f3fSAmit Kumar Mahapatra via Alsa-devel 		&mcspi->dma_channels[spi_get_chipselect(spi, 0)];
1354e4e8276aSVignesh Raghavendra 
1355e4e8276aSVignesh Raghavendra 	if (mcspi->max_xfer_len && mcspi_dma->dma_rx)
1356e4e8276aSVignesh Raghavendra 		return mcspi->max_xfer_len;
1357e4e8276aSVignesh Raghavendra 
1358e4e8276aSVignesh Raghavendra 	return SIZE_MAX;
1359e4e8276aSVignesh Raghavendra }
1360e4e8276aSVignesh Raghavendra 
omap2_mcspi_controller_setup(struct omap2_mcspi * mcspi)136189e8b9cbSVignesh R static int omap2_mcspi_controller_setup(struct omap2_mcspi *mcspi)
1362ca632f55SGrant Likely {
1363ee0f793cSYang Yingliang 	struct spi_controller	*ctlr = mcspi->ctlr;
13641bd897f8SBenoit Cousson 	struct omap2_mcspi_regs	*ctx = &mcspi->ctx;
1365ca632f55SGrant Likely 	int			ret = 0;
1366ca632f55SGrant Likely 
136740b6a137SMinghao Chi 	ret = pm_runtime_resume_and_get(mcspi->dev);
136840b6a137SMinghao Chi 	if (ret < 0)
1369ca632f55SGrant Likely 		return ret;
1370ca632f55SGrant Likely 
1371ee0f793cSYang Yingliang 	mcspi_write_reg(ctlr, OMAP2_MCSPI_WAKEUPENABLE,
137239f8052dSShubhrajyoti D 			OMAP2_MCSPI_WAKEUPENABLE_WKEN);
137339f8052dSShubhrajyoti D 	ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN;
1374ca632f55SGrant Likely 
1375ee0f793cSYang Yingliang 	omap2_mcspi_set_mode(ctlr);
1376034d3dc9SShubhrajyoti D 	pm_runtime_mark_last_busy(mcspi->dev);
1377034d3dc9SShubhrajyoti D 	pm_runtime_put_autosuspend(mcspi->dev);
1378ca632f55SGrant Likely 	return 0;
1379ca632f55SGrant Likely }
1380ca632f55SGrant Likely 
omap_mcspi_runtime_suspend(struct device * dev)1381abdc5db3SAlexander Sverdlin static int omap_mcspi_runtime_suspend(struct device *dev)
1382abdc5db3SAlexander Sverdlin {
1383abdc5db3SAlexander Sverdlin 	int error;
1384abdc5db3SAlexander Sverdlin 
1385abdc5db3SAlexander Sverdlin 	error = pinctrl_pm_select_idle_state(dev);
1386abdc5db3SAlexander Sverdlin 	if (error)
1387abdc5db3SAlexander Sverdlin 		dev_warn(dev, "%s: failed to set pins: %i\n", __func__, error);
1388abdc5db3SAlexander Sverdlin 
1389abdc5db3SAlexander Sverdlin 	return 0;
1390abdc5db3SAlexander Sverdlin }
1391abdc5db3SAlexander Sverdlin 
139252e9a5bbSTony Lindgren /*
139352e9a5bbSTony Lindgren  * When SPI wake up from off-mode, CS is in activate state. If it was in
139452e9a5bbSTony Lindgren  * inactive state when driver was suspend, then force it to inactive state at
139552e9a5bbSTony Lindgren  * wake up.
139652e9a5bbSTony Lindgren  */
omap_mcspi_runtime_resume(struct device * dev)1397ca632f55SGrant Likely static int omap_mcspi_runtime_resume(struct device *dev)
1398ca632f55SGrant Likely {
1399ee0f793cSYang Yingliang 	struct spi_controller *ctlr = dev_get_drvdata(dev);
1400ee0f793cSYang Yingliang 	struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr);
140152e9a5bbSTony Lindgren 	struct omap2_mcspi_regs *ctx = &mcspi->ctx;
140252e9a5bbSTony Lindgren 	struct omap2_mcspi_cs *cs;
1403abdc5db3SAlexander Sverdlin 	int error;
1404abdc5db3SAlexander Sverdlin 
1405abdc5db3SAlexander Sverdlin 	error = pinctrl_pm_select_default_state(dev);
1406abdc5db3SAlexander Sverdlin 	if (error)
1407abdc5db3SAlexander Sverdlin 		dev_warn(dev, "%s: failed to set pins: %i\n", __func__, error);
1408ca632f55SGrant Likely 
140952e9a5bbSTony Lindgren 	/* McSPI: context restore */
1410ee0f793cSYang Yingliang 	mcspi_write_reg(ctlr, OMAP2_MCSPI_MODULCTRL, ctx->modulctrl);
1411ee0f793cSYang Yingliang 	mcspi_write_reg(ctlr, OMAP2_MCSPI_WAKEUPENABLE, ctx->wakeupenable);
141252e9a5bbSTony Lindgren 
141352e9a5bbSTony Lindgren 	list_for_each_entry(cs, &ctx->cs, node) {
141452e9a5bbSTony Lindgren 		/*
141552e9a5bbSTony Lindgren 		 * We need to toggle CS state for OMAP take this
141652e9a5bbSTony Lindgren 		 * change in account.
141752e9a5bbSTony Lindgren 		 */
141852e9a5bbSTony Lindgren 		if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) {
141952e9a5bbSTony Lindgren 			cs->chconf0 |= OMAP2_MCSPI_CHCONF_FORCE;
142052e9a5bbSTony Lindgren 			writel_relaxed(cs->chconf0,
142152e9a5bbSTony Lindgren 				       cs->base + OMAP2_MCSPI_CHCONF0);
142252e9a5bbSTony Lindgren 			cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE;
142352e9a5bbSTony Lindgren 			writel_relaxed(cs->chconf0,
142452e9a5bbSTony Lindgren 				       cs->base + OMAP2_MCSPI_CHCONF0);
142552e9a5bbSTony Lindgren 		} else {
142652e9a5bbSTony Lindgren 			writel_relaxed(cs->chconf0,
142752e9a5bbSTony Lindgren 				       cs->base + OMAP2_MCSPI_CHCONF0);
142852e9a5bbSTony Lindgren 		}
142952e9a5bbSTony Lindgren 	}
1430ca632f55SGrant Likely 
1431ca632f55SGrant Likely 	return 0;
1432ca632f55SGrant Likely }
1433ca632f55SGrant Likely 
1434d5a80031SBenoit Cousson static struct omap2_mcspi_platform_config omap2_pdata = {
1435d5a80031SBenoit Cousson 	.regs_offset = 0,
1436d5a80031SBenoit Cousson };
1437d5a80031SBenoit Cousson 
1438d5a80031SBenoit Cousson static struct omap2_mcspi_platform_config omap4_pdata = {
1439d5a80031SBenoit Cousson 	.regs_offset = OMAP4_MCSPI_REG_OFFSET,
1440d5a80031SBenoit Cousson };
1441d5a80031SBenoit Cousson 
1442e4e8276aSVignesh Raghavendra static struct omap2_mcspi_platform_config am654_pdata = {
1443e4e8276aSVignesh Raghavendra 	.regs_offset = OMAP4_MCSPI_REG_OFFSET,
1444e4e8276aSVignesh Raghavendra 	.max_xfer_len = SZ_4K - 1,
1445e4e8276aSVignesh Raghavendra };
1446e4e8276aSVignesh Raghavendra 
1447d5a80031SBenoit Cousson static const struct of_device_id omap_mcspi_of_match[] = {
1448d5a80031SBenoit Cousson 	{
1449d5a80031SBenoit Cousson 		.compatible = "ti,omap2-mcspi",
1450d5a80031SBenoit Cousson 		.data = &omap2_pdata,
1451d5a80031SBenoit Cousson 	},
1452d5a80031SBenoit Cousson 	{
1453d5a80031SBenoit Cousson 		.compatible = "ti,omap4-mcspi",
1454d5a80031SBenoit Cousson 		.data = &omap4_pdata,
1455d5a80031SBenoit Cousson 	},
1456e4e8276aSVignesh Raghavendra 	{
1457e4e8276aSVignesh Raghavendra 		.compatible = "ti,am654-mcspi",
1458e4e8276aSVignesh Raghavendra 		.data = &am654_pdata,
1459e4e8276aSVignesh Raghavendra 	},
1460d5a80031SBenoit Cousson 	{ },
1461d5a80031SBenoit Cousson };
1462d5a80031SBenoit Cousson MODULE_DEVICE_TABLE(of, omap_mcspi_of_match);
1463ca632f55SGrant Likely 
omap2_mcspi_probe(struct platform_device * pdev)1464fd4a319bSGrant Likely static int omap2_mcspi_probe(struct platform_device *pdev)
1465ca632f55SGrant Likely {
1466ee0f793cSYang Yingliang 	struct spi_controller	*ctlr;
146783a01e72SUwe Kleine-König 	const struct omap2_mcspi_platform_config *pdata;
1468ca632f55SGrant Likely 	struct omap2_mcspi	*mcspi;
1469ca632f55SGrant Likely 	struct resource		*r;
1470ca632f55SGrant Likely 	int			status = 0, i;
1471d5a80031SBenoit Cousson 	u32			regs_offset = 0;
1472d5a80031SBenoit Cousson 	struct device_node	*node = pdev->dev.of_node;
1473d5a80031SBenoit Cousson 	const struct of_device_id *match;
1474ca632f55SGrant Likely 
147589e8b9cbSVignesh R 	if (of_property_read_bool(node, "spi-slave"))
1476ee0f793cSYang Yingliang 		ctlr = spi_alloc_target(&pdev->dev, sizeof(*mcspi));
147789e8b9cbSVignesh R 	else
1478ee0f793cSYang Yingliang 		ctlr = spi_alloc_host(&pdev->dev, sizeof(*mcspi));
1479ee0f793cSYang Yingliang 	if (!ctlr)
1480ca632f55SGrant Likely 		return -ENOMEM;
1481ca632f55SGrant Likely 
1482ca632f55SGrant Likely 	/* the spi->mode bits understood by this driver: */
1483ee0f793cSYang Yingliang 	ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
1484ee0f793cSYang Yingliang 	ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
1485ee0f793cSYang Yingliang 	ctlr->setup = omap2_mcspi_setup;
1486ee0f793cSYang Yingliang 	ctlr->auto_runtime_pm = true;
1487ee0f793cSYang Yingliang 	ctlr->prepare_message = omap2_mcspi_prepare_message;
1488ee0f793cSYang Yingliang 	ctlr->can_dma = omap2_mcspi_can_dma;
1489ee0f793cSYang Yingliang 	ctlr->transfer_one = omap2_mcspi_transfer_one;
1490ee0f793cSYang Yingliang 	ctlr->set_cs = omap2_mcspi_set_cs;
1491ee0f793cSYang Yingliang 	ctlr->cleanup = omap2_mcspi_cleanup;
1492ee0f793cSYang Yingliang 	ctlr->target_abort = omap2_mcspi_target_abort;
1493ee0f793cSYang Yingliang 	ctlr->dev.of_node = node;
1494ee0f793cSYang Yingliang 	ctlr->use_gpio_descriptors = true;
1495d5a80031SBenoit Cousson 
1496ee0f793cSYang Yingliang 	platform_set_drvdata(pdev, ctlr);
14970384e90bSDaniel Mack 
1498ee0f793cSYang Yingliang 	mcspi = spi_controller_get_devdata(ctlr);
1499ee0f793cSYang Yingliang 	mcspi->ctlr = ctlr;
15000384e90bSDaniel Mack 
1501d5a80031SBenoit Cousson 	match = of_match_device(omap_mcspi_of_match, &pdev->dev);
1502d5a80031SBenoit Cousson 	if (match) {
1503d5a80031SBenoit Cousson 		u32 num_cs = 1; /* default number of chipselect */
1504d5a80031SBenoit Cousson 		pdata = match->data;
1505d5a80031SBenoit Cousson 
1506d5a80031SBenoit Cousson 		of_property_read_u32(node, "ti,spi-num-cs", &num_cs);
1507ee0f793cSYang Yingliang 		ctlr->num_chipselect = num_cs;
150803adaa40SRob Herring 		if (of_property_read_bool(node, "ti,pindir-d0-out-d1-in"))
15092cd45179SDaniel Mack 			mcspi->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN;
1510d5a80031SBenoit Cousson 	} else {
15118074cf06SJingoo Han 		pdata = dev_get_platdata(&pdev->dev);
1512ee0f793cSYang Yingliang 		ctlr->num_chipselect = pdata->num_cs;
15130384e90bSDaniel Mack 		mcspi->pin_dir = pdata->pin_dir;
1514d5a80031SBenoit Cousson 	}
1515d5a80031SBenoit Cousson 	regs_offset = pdata->regs_offset;
1516e4e8276aSVignesh Raghavendra 	if (pdata->max_xfer_len) {
1517e4e8276aSVignesh Raghavendra 		mcspi->max_xfer_len = pdata->max_xfer_len;
1518ee0f793cSYang Yingliang 		ctlr->max_transfer_size = omap2_mcspi_max_xfer_size;
1519e4e8276aSVignesh Raghavendra 	}
1520ca632f55SGrant Likely 
15215e726201SYang Li 	mcspi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r);
1522b0ee5605SThierry Reding 	if (IS_ERR(mcspi->base)) {
1523b0ee5605SThierry Reding 		status = PTR_ERR(mcspi->base);
1524ee0f793cSYang Yingliang 		goto free_ctlr;
1525ca632f55SGrant Likely 	}
1526af9e53feSVikram N 	mcspi->phys = r->start + regs_offset;
1527af9e53feSVikram N 	mcspi->base += regs_offset;
1528ca632f55SGrant Likely 
1529ca632f55SGrant Likely 	mcspi->dev = &pdev->dev;
1530ca632f55SGrant Likely 
15311bd897f8SBenoit Cousson 	INIT_LIST_HEAD(&mcspi->ctx.cs);
1532ca632f55SGrant Likely 
1533ee0f793cSYang Yingliang 	mcspi->dma_channels = devm_kcalloc(&pdev->dev, ctlr->num_chipselect,
1534ca632f55SGrant Likely 					   sizeof(struct omap2_mcspi_dma),
1535ca632f55SGrant Likely 					   GFP_KERNEL);
1536a6f936dbSAxel Lin 	if (mcspi->dma_channels == NULL) {
1537a6f936dbSAxel Lin 		status = -ENOMEM;
1538ee0f793cSYang Yingliang 		goto free_ctlr;
1539a6f936dbSAxel Lin 	}
1540ca632f55SGrant Likely 
1541ee0f793cSYang Yingliang 	for (i = 0; i < ctlr->num_chipselect; i++) {
1542b085c612SPeter Ujfalusi 		sprintf(mcspi->dma_channels[i].dma_rx_ch_name, "rx%d", i);
1543b085c612SPeter Ujfalusi 		sprintf(mcspi->dma_channels[i].dma_tx_ch_name, "tx%d", i);
154432f2fc5dSVignesh Raghavendra 
154532f2fc5dSVignesh Raghavendra 		status = omap2_mcspi_request_dma(mcspi,
154632f2fc5dSVignesh Raghavendra 						 &mcspi->dma_channels[i]);
154732f2fc5dSVignesh Raghavendra 		if (status == -EPROBE_DEFER)
1548ee0f793cSYang Yingliang 			goto free_ctlr;
1549ca632f55SGrant Likely 	}
1550ca632f55SGrant Likely 
155189e8b9cbSVignesh R 	status = platform_get_irq(pdev, 0);
1552142c61a5SZhu Wang 	if (status < 0)
1553ee0f793cSYang Yingliang 		goto free_ctlr;
155489e8b9cbSVignesh R 	init_completion(&mcspi->txdone);
155589e8b9cbSVignesh R 	status = devm_request_irq(&pdev->dev, status,
155689e8b9cbSVignesh R 				  omap2_mcspi_irq_handler, 0, pdev->name,
155789e8b9cbSVignesh R 				  mcspi);
155889e8b9cbSVignesh R 	if (status) {
155989e8b9cbSVignesh R 		dev_err(&pdev->dev, "Cannot request IRQ");
1560ee0f793cSYang Yingliang 		goto free_ctlr;
156189e8b9cbSVignesh R 	}
156289e8b9cbSVignesh R 
15632d9f4877SVaishnav Achath 	mcspi->ref_clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);
15642d9f4877SVaishnav Achath 	if (mcspi->ref_clk)
15652d9f4877SVaishnav Achath 		mcspi->ref_clk_hz = clk_get_rate(mcspi->ref_clk);
15662d9f4877SVaishnav Achath 	else
15672d9f4877SVaishnav Achath 		mcspi->ref_clk_hz = OMAP2_MCSPI_MAX_FREQ;
15682d9f4877SVaishnav Achath 	ctlr->max_speed_hz = mcspi->ref_clk_hz;
15692d9f4877SVaishnav Achath 	ctlr->min_speed_hz = mcspi->ref_clk_hz >> 15;
15702d9f4877SVaishnav Achath 
157127b5284cSShubhrajyoti D 	pm_runtime_use_autosuspend(&pdev->dev);
157227b5284cSShubhrajyoti D 	pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
1573ca632f55SGrant Likely 	pm_runtime_enable(&pdev->dev);
1574ca632f55SGrant Likely 
157589e8b9cbSVignesh R 	status = omap2_mcspi_controller_setup(mcspi);
1576142e07beSWei Yongjun 	if (status < 0)
157739f1b565SShubhrajyoti D 		goto disable_pm;
1578ca632f55SGrant Likely 
1579ee0f793cSYang Yingliang 	status = devm_spi_register_controller(&pdev->dev, ctlr);
1580ca632f55SGrant Likely 	if (status < 0)
158137a2d84aSShubhrajyoti D 		goto disable_pm;
1582ca632f55SGrant Likely 
1583ca632f55SGrant Likely 	return status;
1584ca632f55SGrant Likely 
158539f1b565SShubhrajyoti D disable_pm:
15860e6f357aSTony Lindgren 	pm_runtime_dont_use_autosuspend(&pdev->dev);
15870e6f357aSTony Lindgren 	pm_runtime_put_sync(&pdev->dev);
1588751c925cSShubhrajyoti D 	pm_runtime_disable(&pdev->dev);
1589ee0f793cSYang Yingliang free_ctlr:
1590ee0f793cSYang Yingliang 	omap2_mcspi_release_dma(ctlr);
1591ee0f793cSYang Yingliang 	spi_controller_put(ctlr);
1592ca632f55SGrant Likely 	return status;
1593ca632f55SGrant Likely }
1594ca632f55SGrant Likely 
omap2_mcspi_remove(struct platform_device * pdev)15950a4192a5SUwe Kleine-König static void omap2_mcspi_remove(struct platform_device *pdev)
1596ca632f55SGrant Likely {
1597ee0f793cSYang Yingliang 	struct spi_controller *ctlr = platform_get_drvdata(pdev);
1598ee0f793cSYang Yingliang 	struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr);
1599ca632f55SGrant Likely 
1600ee0f793cSYang Yingliang 	omap2_mcspi_release_dma(ctlr);
160132f2fc5dSVignesh Raghavendra 
16020e6f357aSTony Lindgren 	pm_runtime_dont_use_autosuspend(mcspi->dev);
1603a93a2029SShubhrajyoti D 	pm_runtime_put_sync(mcspi->dev);
1604751c925cSShubhrajyoti D 	pm_runtime_disable(&pdev->dev);
1605ca632f55SGrant Likely }
1606ca632f55SGrant Likely 
1607ca632f55SGrant Likely /* work with hotplug and coldplug */
1608ca632f55SGrant Likely MODULE_ALIAS("platform:omap2_mcspi");
1609ca632f55SGrant Likely 
omap2_mcspi_suspend(struct device * dev)161091b9deefSTony Lindgren static int __maybe_unused omap2_mcspi_suspend(struct device *dev)
1611ca632f55SGrant Likely {
1612ee0f793cSYang Yingliang 	struct spi_controller *ctlr = dev_get_drvdata(dev);
1613ee0f793cSYang Yingliang 	struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr);
161491b9deefSTony Lindgren 	int error;
161591b9deefSTony Lindgren 
161691b9deefSTony Lindgren 	error = pinctrl_pm_select_sleep_state(dev);
161791b9deefSTony Lindgren 	if (error)
161891b9deefSTony Lindgren 		dev_warn(mcspi->dev, "%s: failed to set pins: %i\n",
161991b9deefSTony Lindgren 			 __func__, error);
162091b9deefSTony Lindgren 
1621ee0f793cSYang Yingliang 	error = spi_controller_suspend(ctlr);
162291b9deefSTony Lindgren 	if (error)
1623ee0f793cSYang Yingliang 		dev_warn(mcspi->dev, "%s: controller suspend failed: %i\n",
162491b9deefSTony Lindgren 			 __func__, error);
162591b9deefSTony Lindgren 
162691b9deefSTony Lindgren 	return pm_runtime_force_suspend(dev);
1627beca3655SPascal Huerst }
1628beca3655SPascal Huerst 
omap2_mcspi_resume(struct device * dev)162991b9deefSTony Lindgren static int __maybe_unused omap2_mcspi_resume(struct device *dev)
16305a686b2cSTony Lindgren {
1631ee0f793cSYang Yingliang 	struct spi_controller *ctlr = dev_get_drvdata(dev);
1632ee0f793cSYang Yingliang 	struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr);
16335a686b2cSTony Lindgren 	int error;
16345a686b2cSTony Lindgren 
1635ee0f793cSYang Yingliang 	error = spi_controller_resume(ctlr);
163691b9deefSTony Lindgren 	if (error)
1637ee0f793cSYang Yingliang 		dev_warn(mcspi->dev, "%s: controller resume failed: %i\n",
163891b9deefSTony Lindgren 			 __func__, error);
163991b9deefSTony Lindgren 
164091b9deefSTony Lindgren 	return pm_runtime_force_resume(dev);
16415a686b2cSTony Lindgren }
16425a686b2cSTony Lindgren 
1643ca632f55SGrant Likely static const struct dev_pm_ops omap2_mcspi_pm_ops = {
164491b9deefSTony Lindgren 	SET_SYSTEM_SLEEP_PM_OPS(omap2_mcspi_suspend,
164591b9deefSTony Lindgren 				omap2_mcspi_resume)
1646abdc5db3SAlexander Sverdlin 	.runtime_suspend	= omap_mcspi_runtime_suspend,
1647ca632f55SGrant Likely 	.runtime_resume		= omap_mcspi_runtime_resume,
1648ca632f55SGrant Likely };
1649ca632f55SGrant Likely 
1650ca632f55SGrant Likely static struct platform_driver omap2_mcspi_driver = {
1651ca632f55SGrant Likely 	.driver = {
1652ca632f55SGrant Likely 		.name =		"omap2_mcspi",
1653d5a80031SBenoit Cousson 		.pm =		&omap2_mcspi_pm_ops,
1654d5a80031SBenoit Cousson 		.of_match_table = omap_mcspi_of_match,
1655ca632f55SGrant Likely 	},
16567d6b6d83SFelipe Balbi 	.probe =	omap2_mcspi_probe,
16570a4192a5SUwe Kleine-König 	.remove_new =	omap2_mcspi_remove,
1658ca632f55SGrant Likely };
1659ca632f55SGrant Likely 
16609fdca9dfSFelipe Balbi module_platform_driver(omap2_mcspi_driver);
1661*8a71710bSJeff Johnson MODULE_DESCRIPTION("OMAP2 McSPI controller driver");
1662ca632f55SGrant Likely MODULE_LICENSE("GPL");
1663