Blame view

drivers/spi/omap2_mcspi.c 33.7 KB
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
  /*
   * OMAP2 McSPI controller driver
   *
   * Copyright (C) 2005, 2006 Nokia Corporation
   * Author:	Samuel Ortiz <samuel.ortiz@nokia.com> and
   *		Juha Yrjölä <juha.yrjola@nokia.com>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   *
   */
  
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/interrupt.h>
  #include <linux/module.h>
  #include <linux/device.h>
  #include <linux/delay.h>
  #include <linux/dma-mapping.h>
  #include <linux/platform_device.h>
  #include <linux/err.h>
  #include <linux/clk.h>
  #include <linux/io.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
35
  #include <linux/slab.h>
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
36
37
  
  #include <linux/spi/spi.h>
ce491cf85   Tony Lindgren   omap: headers: Mo...
38
39
  #include <plat/dma.h>
  #include <plat/clock.h>
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
40
  #include <plat/mcspi.h>
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
41
42
  
  #define OMAP2_MCSPI_MAX_FREQ		48000000
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
43
44
  /* OMAP2 has 3 SPI controllers, while OMAP3 has 4 */
  #define OMAP2_MCSPI_MAX_CTRL 		4
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
  #define OMAP2_MCSPI_REVISION		0x00
  #define OMAP2_MCSPI_SYSCONFIG		0x10
  #define OMAP2_MCSPI_SYSSTATUS		0x14
  #define OMAP2_MCSPI_IRQSTATUS		0x18
  #define OMAP2_MCSPI_IRQENABLE		0x1c
  #define OMAP2_MCSPI_WAKEUPENABLE	0x20
  #define OMAP2_MCSPI_SYST		0x24
  #define OMAP2_MCSPI_MODULCTRL		0x28
  
  /* per-channel banks, 0x14 bytes each, first is: */
  #define OMAP2_MCSPI_CHCONF0		0x2c
  #define OMAP2_MCSPI_CHSTAT0		0x30
  #define OMAP2_MCSPI_CHCTRL0		0x34
  #define OMAP2_MCSPI_TX0			0x38
  #define OMAP2_MCSPI_RX0			0x3c
  
  /* per-register bitmasks: */
7a8fa725b   Jouni Hogander   spi: omap2_mcspi ...
62
63
64
65
  #define OMAP2_MCSPI_SYSCONFIG_SMARTIDLE	BIT(4)
  #define OMAP2_MCSPI_SYSCONFIG_ENAWAKEUP	BIT(2)
  #define OMAP2_MCSPI_SYSCONFIG_AUTOIDLE	BIT(0)
  #define OMAP2_MCSPI_SYSCONFIG_SOFTRESET	BIT(1)
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
66

7a8fa725b   Jouni Hogander   spi: omap2_mcspi ...
67
  #define OMAP2_MCSPI_SYSSTATUS_RESETDONE	BIT(0)
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
68

7a8fa725b   Jouni Hogander   spi: omap2_mcspi ...
69
70
71
  #define OMAP2_MCSPI_MODULCTRL_SINGLE	BIT(0)
  #define OMAP2_MCSPI_MODULCTRL_MS	BIT(2)
  #define OMAP2_MCSPI_MODULCTRL_STEST	BIT(3)
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
72

7a8fa725b   Jouni Hogander   spi: omap2_mcspi ...
73
74
  #define OMAP2_MCSPI_CHCONF_PHA		BIT(0)
  #define OMAP2_MCSPI_CHCONF_POL		BIT(1)
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
75
  #define OMAP2_MCSPI_CHCONF_CLKD_MASK	(0x0f << 2)
7a8fa725b   Jouni Hogander   spi: omap2_mcspi ...
76
  #define OMAP2_MCSPI_CHCONF_EPOL		BIT(6)
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
77
  #define OMAP2_MCSPI_CHCONF_WL_MASK	(0x1f << 7)
7a8fa725b   Jouni Hogander   spi: omap2_mcspi ...
78
79
  #define OMAP2_MCSPI_CHCONF_TRM_RX_ONLY	BIT(12)
  #define OMAP2_MCSPI_CHCONF_TRM_TX_ONLY	BIT(13)
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
80
  #define OMAP2_MCSPI_CHCONF_TRM_MASK	(0x03 << 12)
7a8fa725b   Jouni Hogander   spi: omap2_mcspi ...
81
82
83
84
85
86
87
  #define OMAP2_MCSPI_CHCONF_DMAW		BIT(14)
  #define OMAP2_MCSPI_CHCONF_DMAR		BIT(15)
  #define OMAP2_MCSPI_CHCONF_DPE0		BIT(16)
  #define OMAP2_MCSPI_CHCONF_DPE1		BIT(17)
  #define OMAP2_MCSPI_CHCONF_IS		BIT(18)
  #define OMAP2_MCSPI_CHCONF_TURBO	BIT(19)
  #define OMAP2_MCSPI_CHCONF_FORCE	BIT(20)
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
88

7a8fa725b   Jouni Hogander   spi: omap2_mcspi ...
89
90
91
  #define OMAP2_MCSPI_CHSTAT_RXS		BIT(0)
  #define OMAP2_MCSPI_CHSTAT_TXS		BIT(1)
  #define OMAP2_MCSPI_CHSTAT_EOT		BIT(2)
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
92

7a8fa725b   Jouni Hogander   spi: omap2_mcspi ...
93
  #define OMAP2_MCSPI_CHCTRL_EN		BIT(0)
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
94

7a8fa725b   Jouni Hogander   spi: omap2_mcspi ...
95
  #define OMAP2_MCSPI_WAKEUPENABLE_WKEN	BIT(0)
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
  
  /* We have 2 DMA channels per CS, one for RX and one for TX */
  struct omap2_mcspi_dma {
  	int dma_tx_channel;
  	int dma_rx_channel;
  
  	int dma_tx_sync_dev;
  	int dma_rx_sync_dev;
  
  	struct completion dma_tx_completion;
  	struct completion dma_rx_completion;
  };
  
  /* use PIO for small transfers, avoiding DMA setup/teardown overhead and
   * cache operations; better heuristics consider wordsize and bitrate.
   */
8b66c1347   Roman Tereshonkov   spi/omap2_mcspi: ...
112
  #define DMA_MIN_BYTES			160
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
113
114
115
116
117
118
119
120
121
122
123
124
  
  
  struct omap2_mcspi {
  	struct work_struct	work;
  	/* lock protects queue and registers */
  	spinlock_t		lock;
  	struct list_head	msg_queue;
  	struct spi_master	*master;
  	struct clk		*ick;
  	struct clk		*fck;
  	/* Virtual base address of the controller */
  	void __iomem		*base;
e5480b739   Russell King   [ARM] omap: remov...
125
  	unsigned long		phys;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
126
127
128
129
130
131
  	/* SPI1 has 4 channels, while SPI2 has 2 */
  	struct omap2_mcspi_dma	*dma_channels;
  };
  
  struct omap2_mcspi_cs {
  	void __iomem		*base;
e5480b739   Russell King   [ARM] omap: remov...
132
  	unsigned long		phys;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
133
  	int			word_len;
89c05372d   Tero Kristo   spi: McSPI saves ...
134
  	struct list_head	node;
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
135
136
137
138
139
140
141
142
143
144
145
  	/* Context save and restore shadow register */
  	u32			chconf0;
  };
  
  /* used for context save and restore, structure members to be updated whenever
   * corresponding registers are modified.
   */
  struct omap2_mcspi_regs {
  	u32 sysconfig;
  	u32 modulctrl;
  	u32 wakeupenable;
89c05372d   Tero Kristo   spi: McSPI saves ...
146
  	struct list_head cs;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
147
  };
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
148
  static struct omap2_mcspi_regs omap2_mcspi_ctx[OMAP2_MCSPI_MAX_CTRL];
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
  static struct workqueue_struct *omap2_mcspi_wq;
  
  #define MOD_REG_BIT(val, mask, set) do { \
  	if (set) \
  		val |= mask; \
  	else \
  		val &= ~mask; \
  } while (0)
  
  static inline void mcspi_write_reg(struct spi_master *master,
  		int idx, u32 val)
  {
  	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
  
  	__raw_writel(val, mcspi->base + idx);
  }
  
  static inline u32 mcspi_read_reg(struct spi_master *master, int idx)
  {
  	struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
  
  	return __raw_readl(mcspi->base + idx);
  }
  
  static inline void mcspi_write_cs_reg(const struct spi_device *spi,
  		int idx, u32 val)
  {
  	struct omap2_mcspi_cs	*cs = spi->controller_state;
  
  	__raw_writel(val, cs->base +  idx);
  }
  
  static inline u32 mcspi_read_cs_reg(const struct spi_device *spi, int idx)
  {
  	struct omap2_mcspi_cs	*cs = spi->controller_state;
  
  	return __raw_readl(cs->base + idx);
  }
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
187
188
189
190
191
192
193
194
195
196
197
198
199
  static inline u32 mcspi_cached_chconf0(const struct spi_device *spi)
  {
  	struct omap2_mcspi_cs *cs = spi->controller_state;
  
  	return cs->chconf0;
  }
  
  static inline void mcspi_write_chconf0(const struct spi_device *spi, u32 val)
  {
  	struct omap2_mcspi_cs *cs = spi->controller_state;
  
  	cs->chconf0 = val;
  	mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, val);
a330ce200   Roman Tereshonkov   omap2_mcspi: Flus...
200
  	mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
201
  }
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
202
203
204
205
  static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
  		int is_read, int enable)
  {
  	u32 l, rw;
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
206
  	l = mcspi_cached_chconf0(spi);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
207
208
209
210
211
212
213
  
  	if (is_read) /* 1 is read, 0 write */
  		rw = OMAP2_MCSPI_CHCONF_DMAR;
  	else
  		rw = OMAP2_MCSPI_CHCONF_DMAW;
  
  	MOD_REG_BIT(l, rw, enable);
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
214
  	mcspi_write_chconf0(spi, l);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
215
216
217
218
219
220
221
222
  }
  
  static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
  {
  	u32 l;
  
  	l = enable ? OMAP2_MCSPI_CHCTRL_EN : 0;
  	mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l);
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
223
224
  	/* Flash post-writes */
  	mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
225
226
227
228
229
  }
  
  static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active)
  {
  	u32 l;
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
230
  	l = mcspi_cached_chconf0(spi);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
231
  	MOD_REG_BIT(l, OMAP2_MCSPI_CHCONF_FORCE, cs_active);
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
232
  	mcspi_write_chconf0(spi, l);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
233
234
235
236
237
238
239
240
241
242
243
244
245
246
  }
  
  static void omap2_mcspi_set_master_mode(struct spi_master *master)
  {
  	u32 l;
  
  	/* setup when switching from (reset default) slave mode
  	 * to single-channel master mode
  	 */
  	l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL);
  	MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_STEST, 0);
  	MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_MS, 0);
  	MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_SINGLE, 1);
  	mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l);
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
247
248
249
250
251
252
253
  
  	omap2_mcspi_ctx[master->bus_num - 1].modulctrl = l;
  }
  
  static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi)
  {
  	struct spi_master *spi_cntrl;
89c05372d   Tero Kristo   spi: McSPI saves ...
254
  	struct omap2_mcspi_cs *cs;
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
255
256
257
258
259
260
261
262
263
264
265
  	spi_cntrl = mcspi->master;
  
  	/* McSPI: context restore */
  	mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_MODULCTRL,
  			omap2_mcspi_ctx[spi_cntrl->bus_num - 1].modulctrl);
  
  	mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_SYSCONFIG,
  			omap2_mcspi_ctx[spi_cntrl->bus_num - 1].sysconfig);
  
  	mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_WAKEUPENABLE,
  			omap2_mcspi_ctx[spi_cntrl->bus_num - 1].wakeupenable);
89c05372d   Tero Kristo   spi: McSPI saves ...
266
267
268
269
  
  	list_for_each_entry(cs, &omap2_mcspi_ctx[spi_cntrl->bus_num - 1].cs,
  			node)
  		__raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
  }
  static void omap2_mcspi_disable_clocks(struct omap2_mcspi *mcspi)
  {
  	clk_disable(mcspi->ick);
  	clk_disable(mcspi->fck);
  }
  
  static int omap2_mcspi_enable_clocks(struct omap2_mcspi *mcspi)
  {
  	if (clk_enable(mcspi->ick))
  		return -ENODEV;
  	if (clk_enable(mcspi->fck))
  		return -ENODEV;
  
  	omap2_mcspi_restore_ctx(mcspi);
  
  	return 0;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
287
  }
2764c500b   Ilkka Koskinen   spi/omap2_mcspi: ...
288
289
290
291
292
293
294
295
296
297
298
299
  static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
  {
  	unsigned long timeout;
  
  	timeout = jiffies + msecs_to_jiffies(1000);
  	while (!(__raw_readl(reg) & bit)) {
  		if (time_after(jiffies, timeout))
  			return -1;
  		cpu_relax();
  	}
  	return 0;
  }
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
300
301
302
303
304
305
306
307
308
  static unsigned
  omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
  {
  	struct omap2_mcspi	*mcspi;
  	struct omap2_mcspi_cs	*cs = spi->controller_state;
  	struct omap2_mcspi_dma  *mcspi_dma;
  	unsigned int		count, c;
  	unsigned long		base, tx_reg, rx_reg;
  	int			word_len, data_type, element_count;
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
309
310
  	int			elements;
  	u32			l;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
311
312
  	u8			* rx;
  	const u8		* tx;
2764c500b   Ilkka Koskinen   spi/omap2_mcspi: ...
313
  	void __iomem		*chstat_reg;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
314
315
316
  
  	mcspi = spi_master_get_devdata(spi->master);
  	mcspi_dma = &mcspi->dma_channels[spi->chip_select];
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
317
  	l = mcspi_cached_chconf0(spi);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
318

2764c500b   Ilkka Koskinen   spi/omap2_mcspi: ...
319
  	chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
320
321
322
  	count = xfer->len;
  	c = count;
  	word_len = cs->word_len;
e5480b739   Russell King   [ARM] omap: remov...
323
  	base = cs->phys;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
  	tx_reg = base + OMAP2_MCSPI_TX0;
  	rx_reg = base + OMAP2_MCSPI_RX0;
  	rx = xfer->rx_buf;
  	tx = xfer->tx_buf;
  
  	if (word_len <= 8) {
  		data_type = OMAP_DMA_DATA_TYPE_S8;
  		element_count = count;
  	} else if (word_len <= 16) {
  		data_type = OMAP_DMA_DATA_TYPE_S16;
  		element_count = count >> 1;
  	} else /* word_len <= 32 */ {
  		data_type = OMAP_DMA_DATA_TYPE_S32;
  		element_count = count >> 2;
  	}
  
  	if (tx != NULL) {
  		omap_set_dma_transfer_params(mcspi_dma->dma_tx_channel,
  				data_type, element_count, 1,
  				OMAP_DMA_SYNC_ELEMENT,
  				mcspi_dma->dma_tx_sync_dev, 0);
  
  		omap_set_dma_dest_params(mcspi_dma->dma_tx_channel, 0,
  				OMAP_DMA_AMODE_CONSTANT,
  				tx_reg, 0, 0);
  
  		omap_set_dma_src_params(mcspi_dma->dma_tx_channel, 0,
  				OMAP_DMA_AMODE_POST_INC,
  				xfer->tx_dma, 0, 0);
  	}
  
  	if (rx != NULL) {
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
356
357
358
  		elements = element_count - 1;
  		if (l & OMAP2_MCSPI_CHCONF_TURBO)
  			elements--;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
359
  		omap_set_dma_transfer_params(mcspi_dma->dma_rx_channel,
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
360
  				data_type, elements, 1,
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
  				OMAP_DMA_SYNC_ELEMENT,
  				mcspi_dma->dma_rx_sync_dev, 1);
  
  		omap_set_dma_src_params(mcspi_dma->dma_rx_channel, 0,
  				OMAP_DMA_AMODE_CONSTANT,
  				rx_reg, 0, 0);
  
  		omap_set_dma_dest_params(mcspi_dma->dma_rx_channel, 0,
  				OMAP_DMA_AMODE_POST_INC,
  				xfer->rx_dma, 0, 0);
  	}
  
  	if (tx != NULL) {
  		omap_start_dma(mcspi_dma->dma_tx_channel);
  		omap2_mcspi_set_dma_req(spi, 0, 1);
  	}
  
  	if (rx != NULL) {
  		omap_start_dma(mcspi_dma->dma_rx_channel);
  		omap2_mcspi_set_dma_req(spi, 1, 1);
  	}
  
  	if (tx != NULL) {
  		wait_for_completion(&mcspi_dma->dma_tx_completion);
07fe03517   Russell King - ARM Linux   spi/omap: Fix DMA...
385
  		dma_unmap_single(&spi->dev, xfer->tx_dma, count, DMA_TO_DEVICE);
2764c500b   Ilkka Koskinen   spi/omap2_mcspi: ...
386
387
388
389
390
391
392
393
394
395
396
397
  
  		/* for TX_ONLY mode, be sure all words have shifted out */
  		if (rx == NULL) {
  			if (mcspi_wait_for_reg_bit(chstat_reg,
  						OMAP2_MCSPI_CHSTAT_TXS) < 0)
  				dev_err(&spi->dev, "TXS timed out
  ");
  			else if (mcspi_wait_for_reg_bit(chstat_reg,
  						OMAP2_MCSPI_CHSTAT_EOT) < 0)
  				dev_err(&spi->dev, "EOT timed out
  ");
  		}
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
398
399
400
401
  	}
  
  	if (rx != NULL) {
  		wait_for_completion(&mcspi_dma->dma_rx_completion);
07fe03517   Russell King - ARM Linux   spi/omap: Fix DMA...
402
  		dma_unmap_single(&spi->dev, xfer->rx_dma, count, DMA_FROM_DEVICE);
57c5c28db   Eero Nurkkala   spi: omap2_mcspi ...
403
  		omap2_mcspi_set_enable(spi, 0);
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
  
  		if (l & OMAP2_MCSPI_CHCONF_TURBO) {
  
  			if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
  				   & OMAP2_MCSPI_CHSTAT_RXS)) {
  				u32 w;
  
  				w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
  				if (word_len <= 8)
  					((u8 *)xfer->rx_buf)[elements++] = w;
  				else if (word_len <= 16)
  					((u16 *)xfer->rx_buf)[elements++] = w;
  				else /* word_len <= 32 */
  					((u32 *)xfer->rx_buf)[elements++] = w;
  			} else {
  				dev_err(&spi->dev,
  					"DMA RX penultimate word empty");
  				count -= (word_len <= 8)  ? 2 :
  					(word_len <= 16) ? 4 :
  					/* word_len <= 32 */ 8;
  				omap2_mcspi_set_enable(spi, 1);
  				return count;
  			}
  		}
57c5c28db   Eero Nurkkala   spi: omap2_mcspi ...
428
429
430
431
432
433
  		if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
  				& OMAP2_MCSPI_CHSTAT_RXS)) {
  			u32 w;
  
  			w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
  			if (word_len <= 8)
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
434
  				((u8 *)xfer->rx_buf)[elements] = w;
57c5c28db   Eero Nurkkala   spi: omap2_mcspi ...
435
  			else if (word_len <= 16)
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
436
  				((u16 *)xfer->rx_buf)[elements] = w;
57c5c28db   Eero Nurkkala   spi: omap2_mcspi ...
437
  			else /* word_len <= 32 */
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
438
  				((u32 *)xfer->rx_buf)[elements] = w;
57c5c28db   Eero Nurkkala   spi: omap2_mcspi ...
439
440
441
442
443
444
445
  		} else {
  			dev_err(&spi->dev, "DMA RX last word empty");
  			count -= (word_len <= 8)  ? 1 :
  				 (word_len <= 16) ? 2 :
  			       /* word_len <= 32 */ 4;
  		}
  		omap2_mcspi_set_enable(spi, 1);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
446
447
448
  	}
  	return count;
  }
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
  static unsigned
  omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
  {
  	struct omap2_mcspi	*mcspi;
  	struct omap2_mcspi_cs	*cs = spi->controller_state;
  	unsigned int		count, c;
  	u32			l;
  	void __iomem		*base = cs->base;
  	void __iomem		*tx_reg;
  	void __iomem		*rx_reg;
  	void __iomem		*chstat_reg;
  	int			word_len;
  
  	mcspi = spi_master_get_devdata(spi->master);
  	count = xfer->len;
  	c = count;
  	word_len = cs->word_len;
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
466
  	l = mcspi_cached_chconf0(spi);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
  
  	/* We store the pre-calculated register addresses on stack to speed
  	 * up the transfer loop. */
  	tx_reg		= base + OMAP2_MCSPI_TX0;
  	rx_reg		= base + OMAP2_MCSPI_RX0;
  	chstat_reg	= base + OMAP2_MCSPI_CHSTAT0;
  
  	if (word_len <= 8) {
  		u8		*rx;
  		const u8	*tx;
  
  		rx = xfer->rx_buf;
  		tx = xfer->tx_buf;
  
  		do {
feed9bab7   Kalle Valo   spi: omap2_mcspi ...
482
  			c -= 1;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
483
484
485
486
487
488
489
  			if (tx != NULL) {
  				if (mcspi_wait_for_reg_bit(chstat_reg,
  						OMAP2_MCSPI_CHSTAT_TXS) < 0) {
  					dev_err(&spi->dev, "TXS timed out
  ");
  					goto out;
  				}
079a176d8   Felipe Balbi   spi: omap2_mcspi:...
490
491
  				dev_vdbg(&spi->dev, "write-%d %02x
  ",
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
492
  						word_len, *tx);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
493
494
495
496
497
498
499
500
501
  				__raw_writel(*tx++, tx_reg);
  			}
  			if (rx != NULL) {
  				if (mcspi_wait_for_reg_bit(chstat_reg,
  						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
  					dev_err(&spi->dev, "RXS timed out
  ");
  					goto out;
  				}
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
502
503
504
505
506
  
  				if (c == 1 && tx == NULL &&
  				    (l & OMAP2_MCSPI_CHCONF_TURBO)) {
  					omap2_mcspi_set_enable(spi, 0);
  					*rx++ = __raw_readl(rx_reg);
079a176d8   Felipe Balbi   spi: omap2_mcspi:...
507
508
  					dev_vdbg(&spi->dev, "read-%d %02x
  ",
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
509
  						    word_len, *(rx - 1));
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
510
511
512
513
514
515
516
517
518
519
520
  					if (mcspi_wait_for_reg_bit(chstat_reg,
  						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
  						dev_err(&spi->dev,
  							"RXS timed out
  ");
  						goto out;
  					}
  					c = 0;
  				} else if (c == 0 && tx == NULL) {
  					omap2_mcspi_set_enable(spi, 0);
  				}
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
521
  				*rx++ = __raw_readl(rx_reg);
079a176d8   Felipe Balbi   spi: omap2_mcspi:...
522
523
  				dev_vdbg(&spi->dev, "read-%d %02x
  ",
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
524
  						word_len, *(rx - 1));
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
525
  			}
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
526
527
528
529
530
531
532
533
  		} while (c);
  	} else if (word_len <= 16) {
  		u16		*rx;
  		const u16	*tx;
  
  		rx = xfer->rx_buf;
  		tx = xfer->tx_buf;
  		do {
feed9bab7   Kalle Valo   spi: omap2_mcspi ...
534
  			c -= 2;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
535
536
537
538
539
540
541
  			if (tx != NULL) {
  				if (mcspi_wait_for_reg_bit(chstat_reg,
  						OMAP2_MCSPI_CHSTAT_TXS) < 0) {
  					dev_err(&spi->dev, "TXS timed out
  ");
  					goto out;
  				}
079a176d8   Felipe Balbi   spi: omap2_mcspi:...
542
543
  				dev_vdbg(&spi->dev, "write-%d %04x
  ",
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
544
  						word_len, *tx);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
545
546
547
548
549
550
551
552
553
  				__raw_writel(*tx++, tx_reg);
  			}
  			if (rx != NULL) {
  				if (mcspi_wait_for_reg_bit(chstat_reg,
  						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
  					dev_err(&spi->dev, "RXS timed out
  ");
  					goto out;
  				}
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
554
555
556
557
558
  
  				if (c == 2 && tx == NULL &&
  				    (l & OMAP2_MCSPI_CHCONF_TURBO)) {
  					omap2_mcspi_set_enable(spi, 0);
  					*rx++ = __raw_readl(rx_reg);
079a176d8   Felipe Balbi   spi: omap2_mcspi:...
559
560
  					dev_vdbg(&spi->dev, "read-%d %04x
  ",
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
561
  						    word_len, *(rx - 1));
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
562
563
564
565
566
567
568
569
570
571
572
  					if (mcspi_wait_for_reg_bit(chstat_reg,
  						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
  						dev_err(&spi->dev,
  							"RXS timed out
  ");
  						goto out;
  					}
  					c = 0;
  				} else if (c == 0 && tx == NULL) {
  					omap2_mcspi_set_enable(spi, 0);
  				}
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
573
  				*rx++ = __raw_readl(rx_reg);
079a176d8   Felipe Balbi   spi: omap2_mcspi:...
574
575
  				dev_vdbg(&spi->dev, "read-%d %04x
  ",
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
576
  						word_len, *(rx - 1));
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
577
  			}
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
578
579
580
581
582
583
584
585
  		} while (c);
  	} else if (word_len <= 32) {
  		u32		*rx;
  		const u32	*tx;
  
  		rx = xfer->rx_buf;
  		tx = xfer->tx_buf;
  		do {
feed9bab7   Kalle Valo   spi: omap2_mcspi ...
586
  			c -= 4;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
587
588
589
590
591
592
593
  			if (tx != NULL) {
  				if (mcspi_wait_for_reg_bit(chstat_reg,
  						OMAP2_MCSPI_CHSTAT_TXS) < 0) {
  					dev_err(&spi->dev, "TXS timed out
  ");
  					goto out;
  				}
079a176d8   Felipe Balbi   spi: omap2_mcspi:...
594
595
  				dev_vdbg(&spi->dev, "write-%d %08x
  ",
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
596
  						word_len, *tx);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
597
598
599
600
601
602
603
604
605
  				__raw_writel(*tx++, tx_reg);
  			}
  			if (rx != NULL) {
  				if (mcspi_wait_for_reg_bit(chstat_reg,
  						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
  					dev_err(&spi->dev, "RXS timed out
  ");
  					goto out;
  				}
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
606
607
608
609
610
  
  				if (c == 4 && tx == NULL &&
  				    (l & OMAP2_MCSPI_CHCONF_TURBO)) {
  					omap2_mcspi_set_enable(spi, 0);
  					*rx++ = __raw_readl(rx_reg);
079a176d8   Felipe Balbi   spi: omap2_mcspi:...
611
612
  					dev_vdbg(&spi->dev, "read-%d %08x
  ",
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
613
  						    word_len, *(rx - 1));
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
614
615
616
617
618
619
620
621
622
623
624
  					if (mcspi_wait_for_reg_bit(chstat_reg,
  						OMAP2_MCSPI_CHSTAT_RXS) < 0) {
  						dev_err(&spi->dev,
  							"RXS timed out
  ");
  						goto out;
  					}
  					c = 0;
  				} else if (c == 0 && tx == NULL) {
  					omap2_mcspi_set_enable(spi, 0);
  				}
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
625
  				*rx++ = __raw_readl(rx_reg);
079a176d8   Felipe Balbi   spi: omap2_mcspi:...
626
627
  				dev_vdbg(&spi->dev, "read-%d %08x
  ",
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
628
  						word_len, *(rx - 1));
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
629
  			}
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
630
631
632
633
634
635
636
637
638
639
640
641
642
  		} while (c);
  	}
  
  	/* for TX_ONLY mode, be sure all words have shifted out */
  	if (xfer->rx_buf == NULL) {
  		if (mcspi_wait_for_reg_bit(chstat_reg,
  				OMAP2_MCSPI_CHSTAT_TXS) < 0) {
  			dev_err(&spi->dev, "TXS timed out
  ");
  		} else if (mcspi_wait_for_reg_bit(chstat_reg,
  				OMAP2_MCSPI_CHSTAT_EOT) < 0)
  			dev_err(&spi->dev, "EOT timed out
  ");
e1993ed64   Jason Wang   spi/omap2_mcspi: ...
643
644
645
646
647
648
  
  		/* disable chan to purge rx datas received in TX_ONLY transfer,
  		 * otherwise these rx datas will affect the direct following
  		 * RX_ONLY transfer.
  		 */
  		omap2_mcspi_set_enable(spi, 0);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
649
650
  	}
  out:
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
651
  	omap2_mcspi_set_enable(spi, 1);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
652
653
654
655
656
657
658
659
660
  	return count - c;
  }
  
  /* called only when no transfer is active to this device */
  static int omap2_mcspi_setup_transfer(struct spi_device *spi,
  		struct spi_transfer *t)
  {
  	struct omap2_mcspi_cs *cs = spi->controller_state;
  	struct omap2_mcspi *mcspi;
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
661
  	struct spi_master *spi_cntrl;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
662
663
  	u32 l = 0, div = 0;
  	u8 word_len = spi->bits_per_word;
9bd4517dd   Scott Ellis   spi/omap2_mcspi: ...
664
  	u32 speed_hz = spi->max_speed_hz;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
665
666
  
  	mcspi = spi_master_get_devdata(spi->master);
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
667
  	spi_cntrl = mcspi->master;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
668
669
670
671
672
  
  	if (t != NULL && t->bits_per_word)
  		word_len = t->bits_per_word;
  
  	cs->word_len = word_len;
9bd4517dd   Scott Ellis   spi/omap2_mcspi: ...
673
674
675
676
  	if (t && t->speed_hz)
  		speed_hz = t->speed_hz;
  
  	if (speed_hz) {
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
677
  		while (div <= 15 && (OMAP2_MCSPI_MAX_FREQ / (1 << div))
9bd4517dd   Scott Ellis   spi/omap2_mcspi: ...
678
  					> speed_hz)
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
679
680
681
  			div++;
  	} else
  		div = 15;
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
682
  	l = mcspi_cached_chconf0(spi);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
  
  	/* standard 4-wire master mode:  SCK, MOSI/out, MISO/in, nCS
  	 * REVISIT: this controller could support SPI_3WIRE mode.
  	 */
  	l &= ~(OMAP2_MCSPI_CHCONF_IS|OMAP2_MCSPI_CHCONF_DPE1);
  	l |= OMAP2_MCSPI_CHCONF_DPE0;
  
  	/* wordlength */
  	l &= ~OMAP2_MCSPI_CHCONF_WL_MASK;
  	l |= (word_len - 1) << 7;
  
  	/* set chipselect polarity; manage with FORCE */
  	if (!(spi->mode & SPI_CS_HIGH))
  		l |= OMAP2_MCSPI_CHCONF_EPOL;	/* active-low; normal */
  	else
  		l &= ~OMAP2_MCSPI_CHCONF_EPOL;
  
  	/* set clock divisor */
  	l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK;
  	l |= div << 2;
  
  	/* set SPI mode 0..3 */
  	if (spi->mode & SPI_CPOL)
  		l |= OMAP2_MCSPI_CHCONF_POL;
  	else
  		l &= ~OMAP2_MCSPI_CHCONF_POL;
  	if (spi->mode & SPI_CPHA)
  		l |= OMAP2_MCSPI_CHCONF_PHA;
  	else
  		l &= ~OMAP2_MCSPI_CHCONF_PHA;
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
713
  	mcspi_write_chconf0(spi, l);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
  
  	dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s
  ",
  			OMAP2_MCSPI_MAX_FREQ / (1 << div),
  			(spi->mode & SPI_CPHA) ? "trailing" : "leading",
  			(spi->mode & SPI_CPOL) ? "inverted" : "normal");
  
  	return 0;
  }
  
  static void omap2_mcspi_dma_rx_callback(int lch, u16 ch_status, void *data)
  {
  	struct spi_device	*spi = data;
  	struct omap2_mcspi	*mcspi;
  	struct omap2_mcspi_dma	*mcspi_dma;
  
  	mcspi = spi_master_get_devdata(spi->master);
  	mcspi_dma = &(mcspi->dma_channels[spi->chip_select]);
  
  	complete(&mcspi_dma->dma_rx_completion);
  
  	/* We must disable the DMA RX request */
  	omap2_mcspi_set_dma_req(spi, 1, 0);
  }
  
  static void omap2_mcspi_dma_tx_callback(int lch, u16 ch_status, void *data)
  {
  	struct spi_device	*spi = data;
  	struct omap2_mcspi	*mcspi;
  	struct omap2_mcspi_dma	*mcspi_dma;
  
  	mcspi = spi_master_get_devdata(spi->master);
  	mcspi_dma = &(mcspi->dma_channels[spi->chip_select]);
  
  	complete(&mcspi_dma->dma_tx_completion);
  
  	/* We must disable the DMA TX request */
  	omap2_mcspi_set_dma_req(spi, 0, 0);
  }
  
  static int omap2_mcspi_request_dma(struct spi_device *spi)
  {
  	struct spi_master	*master = spi->master;
  	struct omap2_mcspi	*mcspi;
  	struct omap2_mcspi_dma	*mcspi_dma;
  
  	mcspi = spi_master_get_devdata(master);
  	mcspi_dma = mcspi->dma_channels + spi->chip_select;
  
  	if (omap_request_dma(mcspi_dma->dma_rx_sync_dev, "McSPI RX",
  			omap2_mcspi_dma_rx_callback, spi,
  			&mcspi_dma->dma_rx_channel)) {
  		dev_err(&spi->dev, "no RX DMA channel for McSPI
  ");
  		return -EAGAIN;
  	}
  
  	if (omap_request_dma(mcspi_dma->dma_tx_sync_dev, "McSPI TX",
  			omap2_mcspi_dma_tx_callback, spi,
  			&mcspi_dma->dma_tx_channel)) {
  		omap_free_dma(mcspi_dma->dma_rx_channel);
  		mcspi_dma->dma_rx_channel = -1;
  		dev_err(&spi->dev, "no TX DMA channel for McSPI
  ");
  		return -EAGAIN;
  	}
  
  	init_completion(&mcspi_dma->dma_rx_completion);
  	init_completion(&mcspi_dma->dma_tx_completion);
  
  	return 0;
  }
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
786
787
788
789
790
791
  static int omap2_mcspi_setup(struct spi_device *spi)
  {
  	int			ret;
  	struct omap2_mcspi	*mcspi;
  	struct omap2_mcspi_dma	*mcspi_dma;
  	struct omap2_mcspi_cs	*cs = spi->controller_state;
7d0771970   David Brownell   spi: move common ...
792
  	if (spi->bits_per_word < 4 || spi->bits_per_word > 32) {
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
793
794
795
796
797
798
799
800
801
802
803
804
805
806
  		dev_dbg(&spi->dev, "setup: unsupported %d bit words
  ",
  			spi->bits_per_word);
  		return -EINVAL;
  	}
  
  	mcspi = spi_master_get_devdata(spi->master);
  	mcspi_dma = &mcspi->dma_channels[spi->chip_select];
  
  	if (!cs) {
  		cs = kzalloc(sizeof *cs, GFP_KERNEL);
  		if (!cs)
  			return -ENOMEM;
  		cs->base = mcspi->base + spi->chip_select * 0x14;
e5480b739   Russell King   [ARM] omap: remov...
807
  		cs->phys = mcspi->phys + spi->chip_select * 0x14;
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
808
  		cs->chconf0 = 0;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
809
  		spi->controller_state = cs;
89c05372d   Tero Kristo   spi: McSPI saves ...
810
811
812
  		/* Link this to context save list */
  		list_add_tail(&cs->node,
  			&omap2_mcspi_ctx[mcspi->master->bus_num - 1].cs);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
813
814
815
816
817
818
819
820
  	}
  
  	if (mcspi_dma->dma_rx_channel == -1
  			|| mcspi_dma->dma_tx_channel == -1) {
  		ret = omap2_mcspi_request_dma(spi);
  		if (ret < 0)
  			return ret;
  	}
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
821
822
  	if (omap2_mcspi_enable_clocks(mcspi))
  		return -ENODEV;
86eeb6fe7   Kyungmin Park   OMAP2 McSPI code ...
823
  	ret = omap2_mcspi_setup_transfer(spi, NULL);
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
824
  	omap2_mcspi_disable_clocks(mcspi);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
825
826
827
828
829
830
831
832
  
  	return ret;
  }
  
  static void omap2_mcspi_cleanup(struct spi_device *spi)
  {
  	struct omap2_mcspi	*mcspi;
  	struct omap2_mcspi_dma	*mcspi_dma;
89c05372d   Tero Kristo   spi: McSPI saves ...
833
  	struct omap2_mcspi_cs	*cs;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
834
835
  
  	mcspi = spi_master_get_devdata(spi->master);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
836

5e7749436   Scott Ellis   spi/omap2_mcspi: ...
837
838
839
840
  	if (spi->controller_state) {
  		/* Unlink controller state from context save list */
  		cs = spi->controller_state;
  		list_del(&cs->node);
89c05372d   Tero Kristo   spi: McSPI saves ...
841

5e7749436   Scott Ellis   spi/omap2_mcspi: ...
842
843
  		kfree(spi->controller_state);
  	}
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
844

99f1a43f4   Scott Ellis   spi/omap2_mcspi: ...
845
846
847
848
849
850
851
852
853
854
855
  	if (spi->chip_select < spi->master->num_chipselect) {
  		mcspi_dma = &mcspi->dma_channels[spi->chip_select];
  
  		if (mcspi_dma->dma_rx_channel != -1) {
  			omap_free_dma(mcspi_dma->dma_rx_channel);
  			mcspi_dma->dma_rx_channel = -1;
  		}
  		if (mcspi_dma->dma_tx_channel != -1) {
  			omap_free_dma(mcspi_dma->dma_tx_channel);
  			mcspi_dma->dma_tx_channel = -1;
  		}
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
856
857
858
859
860
861
862
863
864
  	}
  }
  
  static void omap2_mcspi_work(struct work_struct *work)
  {
  	struct omap2_mcspi	*mcspi;
  
  	mcspi = container_of(work, struct omap2_mcspi, work);
  	spin_lock_irq(&mcspi->lock);
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
865
866
  	if (omap2_mcspi_enable_clocks(mcspi))
  		goto out;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
867
868
869
870
871
872
873
874
875
876
877
878
  
  	/* We only enable one channel at a time -- the one whose message is
  	 * at the head of the queue -- although this controller would gladly
  	 * arbitrate among multiple channels.  This corresponds to "single
  	 * channel" master mode.  As a side effect, we need to manage the
  	 * chipselect with the FORCE bit ... CS != channel enable.
  	 */
  	while (!list_empty(&mcspi->msg_queue)) {
  		struct spi_message		*m;
  		struct spi_device		*spi;
  		struct spi_transfer		*t = NULL;
  		int				cs_active = 0;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
879
  		struct omap2_mcspi_cs		*cs;
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
880
  		struct omap2_mcspi_device_config *cd;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
881
882
883
884
885
886
887
888
889
890
891
  		int				par_override = 0;
  		int				status = 0;
  		u32				chconf;
  
  		m = container_of(mcspi->msg_queue.next, struct spi_message,
  				 queue);
  
  		list_del_init(&m->queue);
  		spin_unlock_irq(&mcspi->lock);
  
  		spi = m->spi;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
892
  		cs = spi->controller_state;
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
893
  		cd = spi->controller_data;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
  
  		omap2_mcspi_set_enable(spi, 1);
  		list_for_each_entry(t, &m->transfers, transfer_list) {
  			if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
  				status = -EINVAL;
  				break;
  			}
  			if (par_override || t->speed_hz || t->bits_per_word) {
  				par_override = 1;
  				status = omap2_mcspi_setup_transfer(spi, t);
  				if (status < 0)
  					break;
  				if (!t->speed_hz && !t->bits_per_word)
  					par_override = 0;
  			}
  
  			if (!cs_active) {
  				omap2_mcspi_force_cs(spi, 1);
  				cs_active = 1;
  			}
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
914
  			chconf = mcspi_cached_chconf0(spi);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
915
  			chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
916
  			chconf &= ~OMAP2_MCSPI_CHCONF_TURBO;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
917
918
919
920
  			if (t->tx_buf == NULL)
  				chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
  			else if (t->rx_buf == NULL)
  				chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
4743a0f88   Roman Tereshonkov   spi/omap2_mcspi: ...
921
922
923
924
925
926
  
  			if (cd && cd->turbo_mode && t->tx_buf == NULL) {
  				/* Turbo mode is for more than one word */
  				if (t->len > ((cs->word_len + 7) >> 3))
  					chconf |= OMAP2_MCSPI_CHCONF_TURBO;
  			}
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
927
  			mcspi_write_chconf0(spi, chconf);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
  
  			if (t->len) {
  				unsigned	count;
  
  				/* RX_ONLY mode needs dummy data in TX reg */
  				if (t->tx_buf == NULL)
  					__raw_writel(0, cs->base
  							+ OMAP2_MCSPI_TX0);
  
  				if (m->is_dma_mapped || t->len >= DMA_MIN_BYTES)
  					count = omap2_mcspi_txrx_dma(spi, t);
  				else
  					count = omap2_mcspi_txrx_pio(spi, t);
  				m->actual_length += count;
  
  				if (count != t->len) {
  					status = -EIO;
  					break;
  				}
  			}
  
  			if (t->delay_usecs)
  				udelay(t->delay_usecs);
  
  			/* ignore the "leave it on after last xfer" hint */
  			if (t->cs_change) {
  				omap2_mcspi_force_cs(spi, 0);
  				cs_active = 0;
  			}
  		}
  
  		/* Restore defaults if they were overriden */
  		if (par_override) {
  			par_override = 0;
  			status = omap2_mcspi_setup_transfer(spi, NULL);
  		}
  
  		if (cs_active)
  			omap2_mcspi_force_cs(spi, 0);
  
  		omap2_mcspi_set_enable(spi, 0);
  
  		m->status = status;
  		m->complete(m->context);
  
  		spin_lock_irq(&mcspi->lock);
  	}
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
975
  	omap2_mcspi_disable_clocks(mcspi);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
976

a41ae1ad9   Hemanth V   spi: McSPI off-mo...
977
  out:
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
  	spin_unlock_irq(&mcspi->lock);
  }
  
  static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
  {
  	struct omap2_mcspi	*mcspi;
  	unsigned long		flags;
  	struct spi_transfer	*t;
  
  	m->actual_length = 0;
  	m->status = 0;
  
  	/* reject invalid messages and transfers */
  	if (list_empty(&m->transfers) || !m->complete)
  		return -EINVAL;
  	list_for_each_entry(t, &m->transfers, transfer_list) {
  		const void	*tx_buf = t->tx_buf;
  		void		*rx_buf = t->rx_buf;
  		unsigned	len = t->len;
  
  		if (t->speed_hz > OMAP2_MCSPI_MAX_FREQ
  				|| (len && !(rx_buf || tx_buf))
  				|| (t->bits_per_word &&
  					(  t->bits_per_word < 4
  					|| t->bits_per_word > 32))) {
  			dev_dbg(&spi->dev, "transfer: %d Hz, %d %s%s, %d bpw
  ",
  					t->speed_hz,
  					len,
  					tx_buf ? "tx" : "",
  					rx_buf ? "rx" : "",
  					t->bits_per_word);
  			return -EINVAL;
  		}
  		if (t->speed_hz && t->speed_hz < OMAP2_MCSPI_MAX_FREQ/(1<<16)) {
  			dev_dbg(&spi->dev, "%d Hz max exceeds %d
  ",
  					t->speed_hz,
  					OMAP2_MCSPI_MAX_FREQ/(1<<16));
  			return -EINVAL;
  		}
  
  		if (m->is_dma_mapped || len < DMA_MIN_BYTES)
  			continue;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1022
1023
1024
  		if (tx_buf != NULL) {
  			t->tx_dma = dma_map_single(&spi->dev, (void *) tx_buf,
  					len, DMA_TO_DEVICE);
8d8bb39b9   FUJITA Tomonori   dma-mapping: add ...
1025
  			if (dma_mapping_error(&spi->dev, t->tx_dma)) {
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1026
1027
1028
1029
1030
1031
1032
1033
1034
  				dev_dbg(&spi->dev, "dma %cX %d bytes error
  ",
  						'T', len);
  				return -EINVAL;
  			}
  		}
  		if (rx_buf != NULL) {
  			t->rx_dma = dma_map_single(&spi->dev, rx_buf, t->len,
  					DMA_FROM_DEVICE);
8d8bb39b9   FUJITA Tomonori   dma-mapping: add ...
1035
  			if (dma_mapping_error(&spi->dev, t->rx_dma)) {
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1036
1037
1038
1039
  				dev_dbg(&spi->dev, "dma %cX %d bytes error
  ",
  						'R', len);
  				if (tx_buf != NULL)
07fe03517   Russell King - ARM Linux   spi/omap: Fix DMA...
1040
  					dma_unmap_single(&spi->dev, t->tx_dma,
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
  							len, DMA_TO_DEVICE);
  				return -EINVAL;
  			}
  		}
  	}
  
  	mcspi = spi_master_get_devdata(spi->master);
  
  	spin_lock_irqsave(&mcspi->lock, flags);
  	list_add_tail(&m->queue, &mcspi->msg_queue);
  	queue_work(omap2_mcspi_wq, &mcspi->work);
  	spin_unlock_irqrestore(&mcspi->lock, flags);
  
  	return 0;
  }
  
  static int __init omap2_mcspi_reset(struct omap2_mcspi *mcspi)
  {
  	struct spi_master	*master = mcspi->master;
  	u32			tmp;
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
1061
1062
  	if (omap2_mcspi_enable_clocks(mcspi))
  		return -1;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1063
1064
1065
1066
1067
1068
  
  	mcspi_write_reg(master, OMAP2_MCSPI_SYSCONFIG,
  			OMAP2_MCSPI_SYSCONFIG_SOFTRESET);
  	do {
  		tmp = mcspi_read_reg(master, OMAP2_MCSPI_SYSSTATUS);
  	} while (!(tmp & OMAP2_MCSPI_SYSSTATUS_RESETDONE));
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
1069
1070
1071
1072
1073
  	tmp = OMAP2_MCSPI_SYSCONFIG_AUTOIDLE |
  		OMAP2_MCSPI_SYSCONFIG_ENAWAKEUP |
  		OMAP2_MCSPI_SYSCONFIG_SMARTIDLE;
  	mcspi_write_reg(master, OMAP2_MCSPI_SYSCONFIG, tmp);
  	omap2_mcspi_ctx[master->bus_num - 1].sysconfig = tmp;
ddb22195c   Jouni Hogander   spi: omap2_mcspi ...
1074

a41ae1ad9   Hemanth V   spi: McSPI off-mo...
1075
1076
1077
  	tmp = OMAP2_MCSPI_WAKEUPENABLE_WKEN;
  	mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE, tmp);
  	omap2_mcspi_ctx[master->bus_num - 1].wakeupenable = tmp;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1078
1079
  
  	omap2_mcspi_set_master_mode(master);
a41ae1ad9   Hemanth V   spi: McSPI off-mo...
1080
  	omap2_mcspi_disable_clocks(mcspi);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
  	return 0;
  }
  
  static u8 __initdata spi1_rxdma_id [] = {
  	OMAP24XX_DMA_SPI1_RX0,
  	OMAP24XX_DMA_SPI1_RX1,
  	OMAP24XX_DMA_SPI1_RX2,
  	OMAP24XX_DMA_SPI1_RX3,
  };
  
  static u8 __initdata spi1_txdma_id [] = {
  	OMAP24XX_DMA_SPI1_TX0,
  	OMAP24XX_DMA_SPI1_TX1,
  	OMAP24XX_DMA_SPI1_TX2,
  	OMAP24XX_DMA_SPI1_TX3,
  };
  
  static u8 __initdata spi2_rxdma_id[] = {
  	OMAP24XX_DMA_SPI2_RX0,
  	OMAP24XX_DMA_SPI2_RX1,
  };
  
  static u8 __initdata spi2_txdma_id[] = {
  	OMAP24XX_DMA_SPI2_TX0,
  	OMAP24XX_DMA_SPI2_TX1,
  };
59b479e09   Tony Lindgren   omap: Start using...
1107
  #if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_ARCH_OMAP3) \
7869c0b9e   Syed Rafiuddin   spi: McSPI suppor...
1108
  	|| defined(CONFIG_ARCH_OMAP4)
ccc7baed1   Girish   spi: omap2_mcspi ...
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
  static u8 __initdata spi3_rxdma_id[] = {
  	OMAP24XX_DMA_SPI3_RX0,
  	OMAP24XX_DMA_SPI3_RX1,
  };
  
  static u8 __initdata spi3_txdma_id[] = {
  	OMAP24XX_DMA_SPI3_TX0,
  	OMAP24XX_DMA_SPI3_TX1,
  };
  #endif
7869c0b9e   Syed Rafiuddin   spi: McSPI suppor...
1119
  #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
ccc7baed1   Girish   spi: omap2_mcspi ...
1120
1121
1122
1123
1124
1125
1126
1127
  static u8 __initdata spi4_rxdma_id[] = {
  	OMAP34XX_DMA_SPI4_RX0,
  };
  
  static u8 __initdata spi4_txdma_id[] = {
  	OMAP34XX_DMA_SPI4_TX0,
  };
  #endif
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
  static int __init omap2_mcspi_probe(struct platform_device *pdev)
  {
  	struct spi_master	*master;
  	struct omap2_mcspi	*mcspi;
  	struct resource		*r;
  	int			status = 0, i;
  	const u8		*rxdma_id, *txdma_id;
  	unsigned		num_chipselect;
  
  	switch (pdev->id) {
  	case 1:
  		rxdma_id = spi1_rxdma_id;
  		txdma_id = spi1_txdma_id;
  		num_chipselect = 4;
  		break;
  	case 2:
  		rxdma_id = spi2_rxdma_id;
  		txdma_id = spi2_txdma_id;
  		num_chipselect = 2;
  		break;
59b479e09   Tony Lindgren   omap: Start using...
1148
  #if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_ARCH_OMAP3) \
7869c0b9e   Syed Rafiuddin   spi: McSPI suppor...
1149
  	|| defined(CONFIG_ARCH_OMAP4)
ccc7baed1   Girish   spi: omap2_mcspi ...
1150
1151
1152
1153
1154
1155
  	case 3:
  		rxdma_id = spi3_rxdma_id;
  		txdma_id = spi3_txdma_id;
  		num_chipselect = 2;
  		break;
  #endif
7869c0b9e   Syed Rafiuddin   spi: McSPI suppor...
1156
  #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
ccc7baed1   Girish   spi: omap2_mcspi ...
1157
1158
1159
1160
1161
1162
  	case 4:
  		rxdma_id = spi4_rxdma_id;
  		txdma_id = spi4_txdma_id;
  		num_chipselect = 1;
  		break;
  #endif
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
  	default:
  		return -EINVAL;
  	}
  
  	master = spi_alloc_master(&pdev->dev, sizeof *mcspi);
  	if (master == NULL) {
  		dev_dbg(&pdev->dev, "master allocation failed
  ");
  		return -ENOMEM;
  	}
e7db06b5d   David Brownell   spi: move more sp...
1173
1174
  	/* the spi->mode bits understood by this driver: */
  	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
  	if (pdev->id != -1)
  		master->bus_num = pdev->id;
  
  	master->setup = omap2_mcspi_setup;
  	master->transfer = omap2_mcspi_transfer;
  	master->cleanup = omap2_mcspi_cleanup;
  	master->num_chipselect = num_chipselect;
  
  	dev_set_drvdata(&pdev->dev, master);
  
  	mcspi = spi_master_get_devdata(master);
  	mcspi->master = master;
  
  	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	if (r == NULL) {
  		status = -ENODEV;
  		goto err1;
  	}
  	if (!request_mem_region(r->start, (r->end - r->start) + 1,
6c7377ab6   Kay Sievers   spi: struct devic...
1194
  			dev_name(&pdev->dev))) {
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1195
1196
1197
  		status = -EBUSY;
  		goto err1;
  	}
e5480b739   Russell King   [ARM] omap: remov...
1198
  	mcspi->phys = r->start;
55c381e48   Russell King   [ARM] omap: conve...
1199
1200
1201
1202
1203
1204
1205
  	mcspi->base = ioremap(r->start, r->end - r->start + 1);
  	if (!mcspi->base) {
  		dev_dbg(&pdev->dev, "can't ioremap MCSPI
  ");
  		status = -ENOMEM;
  		goto err1aa;
  	}
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1206
1207
1208
1209
1210
  
  	INIT_WORK(&mcspi->work, omap2_mcspi_work);
  
  	spin_lock_init(&mcspi->lock);
  	INIT_LIST_HEAD(&mcspi->msg_queue);
89c05372d   Tero Kristo   spi: McSPI saves ...
1211
  	INIT_LIST_HEAD(&omap2_mcspi_ctx[master->bus_num - 1].cs);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1212

1b5715ec4   Russell King   [ARM] omap: mcspi...
1213
  	mcspi->ick = clk_get(&pdev->dev, "ick");
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1214
1215
1216
1217
1218
1219
  	if (IS_ERR(mcspi->ick)) {
  		dev_dbg(&pdev->dev, "can't get mcspi_ick
  ");
  		status = PTR_ERR(mcspi->ick);
  		goto err1a;
  	}
1b5715ec4   Russell King   [ARM] omap: mcspi...
1220
  	mcspi->fck = clk_get(&pdev->dev, "fck");
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
  	if (IS_ERR(mcspi->fck)) {
  		dev_dbg(&pdev->dev, "can't get mcspi_fck
  ");
  		status = PTR_ERR(mcspi->fck);
  		goto err2;
  	}
  
  	mcspi->dma_channels = kcalloc(master->num_chipselect,
  			sizeof(struct omap2_mcspi_dma),
  			GFP_KERNEL);
  
  	if (mcspi->dma_channels == NULL)
  		goto err3;
  
  	for (i = 0; i < num_chipselect; i++) {
  		mcspi->dma_channels[i].dma_rx_channel = -1;
  		mcspi->dma_channels[i].dma_rx_sync_dev = rxdma_id[i];
  		mcspi->dma_channels[i].dma_tx_channel = -1;
  		mcspi->dma_channels[i].dma_tx_sync_dev = txdma_id[i];
  	}
  
  	if (omap2_mcspi_reset(mcspi) < 0)
  		goto err4;
  
  	status = spi_register_master(master);
  	if (status < 0)
  		goto err4;
  
  	return status;
  
  err4:
  	kfree(mcspi->dma_channels);
  err3:
  	clk_put(mcspi->fck);
  err2:
  	clk_put(mcspi->ick);
  err1a:
55c381e48   Russell King   [ARM] omap: conve...
1258
1259
  	iounmap(mcspi->base);
  err1aa:
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
  	release_mem_region(r->start, (r->end - r->start) + 1);
  err1:
  	spi_master_put(master);
  	return status;
  }
  
  static int __exit omap2_mcspi_remove(struct platform_device *pdev)
  {
  	struct spi_master	*master;
  	struct omap2_mcspi	*mcspi;
  	struct omap2_mcspi_dma	*dma_channels;
  	struct resource		*r;
55c381e48   Russell King   [ARM] omap: conve...
1272
  	void __iomem *base;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
  
  	master = dev_get_drvdata(&pdev->dev);
  	mcspi = spi_master_get_devdata(master);
  	dma_channels = mcspi->dma_channels;
  
  	clk_put(mcspi->fck);
  	clk_put(mcspi->ick);
  
  	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	release_mem_region(r->start, (r->end - r->start) + 1);
55c381e48   Russell King   [ARM] omap: conve...
1283
  	base = mcspi->base;
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1284
  	spi_unregister_master(master);
55c381e48   Russell King   [ARM] omap: conve...
1285
  	iounmap(base);
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1286
1287
1288
1289
  	kfree(dma_channels);
  
  	return 0;
  }
7e38c3c44   Kay Sievers   spi: fix platform...
1290
1291
  /* work with hotplug and coldplug */
  MODULE_ALIAS("platform:omap2_mcspi");
42ce7fd63   Gregory CLEMENT   spi/omap2_mcspi.c...
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
  #ifdef	CONFIG_SUSPEND
  /*
   * When SPI wake up from off-mode, CS is in activate state. If it was in
   * unactive state when driver was suspend, then force it to unactive state at
   * wake up.
   */
  static int omap2_mcspi_resume(struct device *dev)
  {
  	struct spi_master	*master = dev_get_drvdata(dev);
  	struct omap2_mcspi	*mcspi = spi_master_get_devdata(master);
  	struct omap2_mcspi_cs *cs;
  
  	omap2_mcspi_enable_clocks(mcspi);
  	list_for_each_entry(cs, &omap2_mcspi_ctx[master->bus_num - 1].cs,
  			    node) {
  		if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) {
  
  			/*
  			 * We need to toggle CS state for OMAP take this
  			 * change in account.
  			 */
  			MOD_REG_BIT(cs->chconf0, OMAP2_MCSPI_CHCONF_FORCE, 1);
  			__raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
  			MOD_REG_BIT(cs->chconf0, OMAP2_MCSPI_CHCONF_FORCE, 0);
  			__raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
  		}
  	}
  	omap2_mcspi_disable_clocks(mcspi);
  	return 0;
  }
  #else
  #define	omap2_mcspi_resume	NULL
  #endif
  
  static const struct dev_pm_ops omap2_mcspi_pm_ops = {
  	.resume = omap2_mcspi_resume,
  };
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1329
1330
1331
1332
  static struct platform_driver omap2_mcspi_driver = {
  	.driver = {
  		.name =		"omap2_mcspi",
  		.owner =	THIS_MODULE,
42ce7fd63   Gregory CLEMENT   spi/omap2_mcspi.c...
1333
  		.pm =		&omap2_mcspi_pm_ops
ccdc7bf92   Samuel Ortiz   SPI: omap2_mcspi ...
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
  	},
  	.remove =	__exit_p(omap2_mcspi_remove),
  };
  
  
  static int __init omap2_mcspi_init(void)
  {
  	omap2_mcspi_wq = create_singlethread_workqueue(
  				omap2_mcspi_driver.driver.name);
  	if (omap2_mcspi_wq == NULL)
  		return -1;
  	return platform_driver_probe(&omap2_mcspi_driver, omap2_mcspi_probe);
  }
  subsys_initcall(omap2_mcspi_init);
  
  static void __exit omap2_mcspi_exit(void)
  {
  	platform_driver_unregister(&omap2_mcspi_driver);
  
  	destroy_workqueue(omap2_mcspi_wq);
  }
  module_exit(omap2_mcspi_exit);
  
  MODULE_LICENSE("GPL");