Blame view

drivers/spi/spi-atmel.c 45.5 KB
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1
2
3
4
5
6
7
8
9
10
11
  /*
   * Driver for Atmel AT32 and AT91 SPI Controllers
   *
   * Copyright (C) 2006 Atmel Corporation
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
  
  #include <linux/kernel.h>
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
12
13
14
15
16
  #include <linux/clk.h>
  #include <linux/module.h>
  #include <linux/platform_device.h>
  #include <linux/delay.h>
  #include <linux/dma-mapping.h>
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
17
  #include <linux/dmaengine.h>
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
18
19
20
  #include <linux/err.h>
  #include <linux/interrupt.h>
  #include <linux/spi/spi.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
21
  #include <linux/slab.h>
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
22
  #include <linux/platform_data/dma-atmel.h>
850a5b670   Jean-Christophe PLAGNIOL-VILLARD   spi/atmel: add DT...
23
  #include <linux/of.h>
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
24

d4820b749   Wenyou Yang   spi/spi-atmel: de...
25
26
  #include <linux/io.h>
  #include <linux/gpio.h>
961062007   Nicolas Ferre   spi: atmel: use m...
27
  #include <linux/of_gpio.h>
5bdfd491a   Wenyou Yang   spi: atmel: adopt...
28
  #include <linux/pinctrl/consumer.h>
ce0c4caf2   Wenyou Yang   spi/atmel: add su...
29
  #include <linux/pm_runtime.h>
bb2d1c36c   David Brownell   [PATCH] SPI contr...
30

ca632f556   Grant Likely   spi: reorganize d...
31
32
33
34
35
36
37
38
39
40
41
42
43
  /* SPI register offsets */
  #define SPI_CR					0x0000
  #define SPI_MR					0x0004
  #define SPI_RDR					0x0008
  #define SPI_TDR					0x000c
  #define SPI_SR					0x0010
  #define SPI_IER					0x0014
  #define SPI_IDR					0x0018
  #define SPI_IMR					0x001c
  #define SPI_CSR0				0x0030
  #define SPI_CSR1				0x0034
  #define SPI_CSR2				0x0038
  #define SPI_CSR3				0x003c
11f2764fe   Cyrille Pitchen   spi: atmel: add s...
44
45
  #define SPI_FMR					0x0040
  #define SPI_FLR					0x0044
d4820b749   Wenyou Yang   spi/spi-atmel: de...
46
  #define SPI_VERSION				0x00fc
ca632f556   Grant Likely   spi: reorganize d...
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
  #define SPI_RPR					0x0100
  #define SPI_RCR					0x0104
  #define SPI_TPR					0x0108
  #define SPI_TCR					0x010c
  #define SPI_RNPR				0x0110
  #define SPI_RNCR				0x0114
  #define SPI_TNPR				0x0118
  #define SPI_TNCR				0x011c
  #define SPI_PTCR				0x0120
  #define SPI_PTSR				0x0124
  
  /* Bitfields in CR */
  #define SPI_SPIEN_OFFSET			0
  #define SPI_SPIEN_SIZE				1
  #define SPI_SPIDIS_OFFSET			1
  #define SPI_SPIDIS_SIZE				1
  #define SPI_SWRST_OFFSET			7
  #define SPI_SWRST_SIZE				1
  #define SPI_LASTXFER_OFFSET			24
  #define SPI_LASTXFER_SIZE			1
11f2764fe   Cyrille Pitchen   spi: atmel: add s...
67
68
69
70
71
72
73
74
  #define SPI_TXFCLR_OFFSET			16
  #define SPI_TXFCLR_SIZE				1
  #define SPI_RXFCLR_OFFSET			17
  #define SPI_RXFCLR_SIZE				1
  #define SPI_FIFOEN_OFFSET			30
  #define SPI_FIFOEN_SIZE				1
  #define SPI_FIFODIS_OFFSET			31
  #define SPI_FIFODIS_SIZE			1
ca632f556   Grant Likely   spi: reorganize d...
75
76
77
78
79
80
81
82
83
84
85
86
  
  /* Bitfields in MR */
  #define SPI_MSTR_OFFSET				0
  #define SPI_MSTR_SIZE				1
  #define SPI_PS_OFFSET				1
  #define SPI_PS_SIZE				1
  #define SPI_PCSDEC_OFFSET			2
  #define SPI_PCSDEC_SIZE				1
  #define SPI_FDIV_OFFSET				3
  #define SPI_FDIV_SIZE				1
  #define SPI_MODFDIS_OFFSET			4
  #define SPI_MODFDIS_SIZE			1
d4820b749   Wenyou Yang   spi/spi-atmel: de...
87
88
  #define SPI_WDRBT_OFFSET			5
  #define SPI_WDRBT_SIZE				1
ca632f556   Grant Likely   spi: reorganize d...
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
  #define SPI_LLB_OFFSET				7
  #define SPI_LLB_SIZE				1
  #define SPI_PCS_OFFSET				16
  #define SPI_PCS_SIZE				4
  #define SPI_DLYBCS_OFFSET			24
  #define SPI_DLYBCS_SIZE				8
  
  /* Bitfields in RDR */
  #define SPI_RD_OFFSET				0
  #define SPI_RD_SIZE				16
  
  /* Bitfields in TDR */
  #define SPI_TD_OFFSET				0
  #define SPI_TD_SIZE				16
  
  /* Bitfields in SR */
  #define SPI_RDRF_OFFSET				0
  #define SPI_RDRF_SIZE				1
  #define SPI_TDRE_OFFSET				1
  #define SPI_TDRE_SIZE				1
  #define SPI_MODF_OFFSET				2
  #define SPI_MODF_SIZE				1
  #define SPI_OVRES_OFFSET			3
  #define SPI_OVRES_SIZE				1
  #define SPI_ENDRX_OFFSET			4
  #define SPI_ENDRX_SIZE				1
  #define SPI_ENDTX_OFFSET			5
  #define SPI_ENDTX_SIZE				1
  #define SPI_RXBUFF_OFFSET			6
  #define SPI_RXBUFF_SIZE				1
  #define SPI_TXBUFE_OFFSET			7
  #define SPI_TXBUFE_SIZE				1
  #define SPI_NSSR_OFFSET				8
  #define SPI_NSSR_SIZE				1
  #define SPI_TXEMPTY_OFFSET			9
  #define SPI_TXEMPTY_SIZE			1
  #define SPI_SPIENS_OFFSET			16
  #define SPI_SPIENS_SIZE				1
11f2764fe   Cyrille Pitchen   spi: atmel: add s...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
  #define SPI_TXFEF_OFFSET			24
  #define SPI_TXFEF_SIZE				1
  #define SPI_TXFFF_OFFSET			25
  #define SPI_TXFFF_SIZE				1
  #define SPI_TXFTHF_OFFSET			26
  #define SPI_TXFTHF_SIZE				1
  #define SPI_RXFEF_OFFSET			27
  #define SPI_RXFEF_SIZE				1
  #define SPI_RXFFF_OFFSET			28
  #define SPI_RXFFF_SIZE				1
  #define SPI_RXFTHF_OFFSET			29
  #define SPI_RXFTHF_SIZE				1
  #define SPI_TXFPTEF_OFFSET			30
  #define SPI_TXFPTEF_SIZE			1
  #define SPI_RXFPTEF_OFFSET			31
  #define SPI_RXFPTEF_SIZE			1
ca632f556   Grant Likely   spi: reorganize d...
143
144
145
146
147
148
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
  
  /* Bitfields in CSR0 */
  #define SPI_CPOL_OFFSET				0
  #define SPI_CPOL_SIZE				1
  #define SPI_NCPHA_OFFSET			1
  #define SPI_NCPHA_SIZE				1
  #define SPI_CSAAT_OFFSET			3
  #define SPI_CSAAT_SIZE				1
  #define SPI_BITS_OFFSET				4
  #define SPI_BITS_SIZE				4
  #define SPI_SCBR_OFFSET				8
  #define SPI_SCBR_SIZE				8
  #define SPI_DLYBS_OFFSET			16
  #define SPI_DLYBS_SIZE				8
  #define SPI_DLYBCT_OFFSET			24
  #define SPI_DLYBCT_SIZE				8
  
  /* Bitfields in RCR */
  #define SPI_RXCTR_OFFSET			0
  #define SPI_RXCTR_SIZE				16
  
  /* Bitfields in TCR */
  #define SPI_TXCTR_OFFSET			0
  #define SPI_TXCTR_SIZE				16
  
  /* Bitfields in RNCR */
  #define SPI_RXNCR_OFFSET			0
  #define SPI_RXNCR_SIZE				16
  
  /* Bitfields in TNCR */
  #define SPI_TXNCR_OFFSET			0
  #define SPI_TXNCR_SIZE				16
  
  /* Bitfields in PTCR */
  #define SPI_RXTEN_OFFSET			0
  #define SPI_RXTEN_SIZE				1
  #define SPI_RXTDIS_OFFSET			1
  #define SPI_RXTDIS_SIZE				1
  #define SPI_TXTEN_OFFSET			8
  #define SPI_TXTEN_SIZE				1
  #define SPI_TXTDIS_OFFSET			9
  #define SPI_TXTDIS_SIZE				1
11f2764fe   Cyrille Pitchen   spi: atmel: add s...
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
  /* Bitfields in FMR */
  #define SPI_TXRDYM_OFFSET			0
  #define SPI_TXRDYM_SIZE				2
  #define SPI_RXRDYM_OFFSET			4
  #define SPI_RXRDYM_SIZE				2
  #define SPI_TXFTHRES_OFFSET			16
  #define SPI_TXFTHRES_SIZE			6
  #define SPI_RXFTHRES_OFFSET			24
  #define SPI_RXFTHRES_SIZE			6
  
  /* Bitfields in FLR */
  #define SPI_TXFL_OFFSET				0
  #define SPI_TXFL_SIZE				6
  #define SPI_RXFL_OFFSET				16
  #define SPI_RXFL_SIZE				6
ca632f556   Grant Likely   spi: reorganize d...
200
201
202
203
204
205
206
207
208
209
  /* Constants for BITS */
  #define SPI_BITS_8_BPT				0
  #define SPI_BITS_9_BPT				1
  #define SPI_BITS_10_BPT				2
  #define SPI_BITS_11_BPT				3
  #define SPI_BITS_12_BPT				4
  #define SPI_BITS_13_BPT				5
  #define SPI_BITS_14_BPT				6
  #define SPI_BITS_15_BPT				7
  #define SPI_BITS_16_BPT				8
11f2764fe   Cyrille Pitchen   spi: atmel: add s...
210
211
212
  #define SPI_ONE_DATA				0
  #define SPI_TWO_DATA				1
  #define SPI_FOUR_DATA				2
ca632f556   Grant Likely   spi: reorganize d...
213
214
215
216
  
  /* Bit manipulation macros */
  #define SPI_BIT(name) \
  	(1 << SPI_##name##_OFFSET)
a536d7654   Sachin Kamat   spi: atmel: Silen...
217
  #define SPI_BF(name, value) \
ca632f556   Grant Likely   spi: reorganize d...
218
  	(((value) & ((1 << SPI_##name##_SIZE) - 1)) << SPI_##name##_OFFSET)
a536d7654   Sachin Kamat   spi: atmel: Silen...
219
  #define SPI_BFEXT(name, value) \
ca632f556   Grant Likely   spi: reorganize d...
220
  	(((value) >> SPI_##name##_OFFSET) & ((1 << SPI_##name##_SIZE) - 1))
a536d7654   Sachin Kamat   spi: atmel: Silen...
221
222
223
  #define SPI_BFINS(name, value, old) \
  	(((old) & ~(((1 << SPI_##name##_SIZE) - 1) << SPI_##name##_OFFSET)) \
  	  | SPI_BF(name, value))
ca632f556   Grant Likely   spi: reorganize d...
224
225
  
  /* Register access macros */
ea467326e   Ben Dooks   spi: atmel: use e...
226
  #ifdef CONFIG_AVR32
a536d7654   Sachin Kamat   spi: atmel: Silen...
227
  #define spi_readl(port, reg) \
ca632f556   Grant Likely   spi: reorganize d...
228
  	__raw_readl((port)->regs + SPI_##reg)
a536d7654   Sachin Kamat   spi: atmel: Silen...
229
  #define spi_writel(port, reg, value) \
ca632f556   Grant Likely   spi: reorganize d...
230
  	__raw_writel((value), (port)->regs + SPI_##reg)
11f2764fe   Cyrille Pitchen   spi: atmel: add s...
231
232
233
234
235
236
237
238
239
240
  
  #define spi_readw(port, reg) \
  	__raw_readw((port)->regs + SPI_##reg)
  #define spi_writew(port, reg, value) \
  	__raw_writew((value), (port)->regs + SPI_##reg)
  
  #define spi_readb(port, reg) \
  	__raw_readb((port)->regs + SPI_##reg)
  #define spi_writeb(port, reg, value) \
  	__raw_writeb((value), (port)->regs + SPI_##reg)
ea467326e   Ben Dooks   spi: atmel: use e...
241
242
243
244
245
  #else
  #define spi_readl(port, reg) \
  	readl_relaxed((port)->regs + SPI_##reg)
  #define spi_writel(port, reg, value) \
  	writel_relaxed((value), (port)->regs + SPI_##reg)
11f2764fe   Cyrille Pitchen   spi: atmel: add s...
246
247
248
249
250
251
252
253
254
255
  
  #define spi_readw(port, reg) \
  	readw_relaxed((port)->regs + SPI_##reg)
  #define spi_writew(port, reg, value) \
  	writew_relaxed((value), (port)->regs + SPI_##reg)
  
  #define spi_readb(port, reg) \
  	readb_relaxed((port)->regs + SPI_##reg)
  #define spi_writeb(port, reg, value) \
  	writeb_relaxed((value), (port)->regs + SPI_##reg)
ea467326e   Ben Dooks   spi: atmel: use e...
256
  #endif
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
257
258
259
260
  /* use PIO for small transfers, avoiding DMA setup/teardown overhead and
   * cache operations; better heuristics consider wordsize and bitrate.
   */
  #define DMA_MIN_BYTES	16
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
261
  #define SPI_DMA_TIMEOUT		(msecs_to_jiffies(1000))
ce0c4caf2   Wenyou Yang   spi/atmel: add su...
262
  #define AUTOSUSPEND_TIMEOUT	2000
d4820b749   Wenyou Yang   spi/spi-atmel: de...
263
264
265
266
  struct atmel_spi_caps {
  	bool	is_spi2;
  	bool	has_wdrbt;
  	bool	has_dma_support;
7094576cc   Cyrille Pitchen   spi: atmel: fix c...
267
  	bool	has_pdc_support;
d4820b749   Wenyou Yang   spi/spi-atmel: de...
268
  };
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
269
270
271
272
273
  
  /*
   * The core SPI transfer engine just talks to a register bank to set up
   * DMA transfers; transfer queue progress is driven by IRQs.  The clock
   * framework provides the base clock, subdivided for each spi_device.
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
274
275
276
   */
  struct atmel_spi {
  	spinlock_t		lock;
8aad7924b   Nicolas Ferre   spi/spi-atmel: ad...
277
  	unsigned long		flags;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
278

dfab30ee6   Nicolas Ferre   spi/spi-atmel: ad...
279
  	phys_addr_t		phybase;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
280
281
282
283
  	void __iomem		*regs;
  	int			irq;
  	struct clk		*clk;
  	struct platform_device	*pdev;
39fe33f98   Ben Whitten   spi: atmel: Fix s...
284
  	unsigned long		spi_clk;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
285

754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
286
  	struct spi_transfer	*current_transfer;
0c3b97487   Axel Lin   spi: atmel: Make ...
287
  	int			current_remaining_bytes;
823cd0454   Nicolas Ferre   spi/spi-atmel: st...
288
  	int			done_status;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
289

8090d6d1a   Wenyou Yang   spi: atmel: Refac...
290
  	struct completion	xfer_completion;
d4820b749   Wenyou Yang   spi/spi-atmel: de...
291
  	struct atmel_spi_caps	caps;
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
292
293
294
  
  	bool			use_dma;
  	bool			use_pdc;
482030348   Cyrille Pitchen   spi: atmel: add s...
295
  	bool			use_cs_gpios;
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
296
297
298
  
  	bool			keep_cs;
  	bool			cs_active;
11f2764fe   Cyrille Pitchen   spi: atmel: add s...
299
300
  
  	u32			fifo_size;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
301
  };
5ee36c989   Haavard Skinnemoen   spi: atmel_spi up...
302
303
304
305
306
  /* Controller-specific per-slave state */
  struct atmel_spi_device {
  	unsigned int		npcs_pin;
  	u32			csr;
  };
7910d9af0   Nicolas Ferre   spi: atmel: Use c...
307
  #define SPI_MAX_DMA_XFER	65535 /* true for both PDC and DMA */
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
308
309
310
  #define INVALID_DMA_ADDRESS	0xffffffff
  
  /*
5bfa26ca1   Haavard Skinnemoen   atmel_spi: clean ...
311
312
313
314
315
316
   * Version 2 of the SPI controller has
   *  - CR.LASTXFER
   *  - SPI_MR.DIV32 may become FDIV or must-be-zero (here: always zero)
   *  - SPI_SR.TXEMPTY, SPI_SR.NSSR (and corresponding irqs)
   *  - SPI_CSRx.CSAAT
   *  - SPI_CSRx.SBCR allows faster clocking
5bfa26ca1   Haavard Skinnemoen   atmel_spi: clean ...
317
   */
d4820b749   Wenyou Yang   spi/spi-atmel: de...
318
  static bool atmel_spi_is_v2(struct atmel_spi *as)
5bfa26ca1   Haavard Skinnemoen   atmel_spi: clean ...
319
  {
d4820b749   Wenyou Yang   spi/spi-atmel: de...
320
  	return as->caps.is_spi2;
5bfa26ca1   Haavard Skinnemoen   atmel_spi: clean ...
321
322
323
  }
  
  /*
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
324
325
   * Earlier SPI controllers (e.g. on at91rm9200) have a design bug whereby
   * they assume that spi slave device state will not change on deselect, so
defbd3b4b   David Brownell   atmel_spi: don't ...
326
327
328
   * that automagic deselection is OK.  ("NPCSx rises if no data is to be
   * transmitted")  Not so!  Workaround uses nCSx pins as GPIOs; or newer
   * controllers have CSAAT and friends.
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
329
   *
defbd3b4b   David Brownell   atmel_spi: don't ...
330
331
332
333
334
335
336
337
338
339
340
   * Since the CSAAT functionality is a bit weird on newer controllers as
   * well, we use GPIO to control nCSx pins on all controllers, updating
   * MR.PCS to avoid confusing the controller.  Using GPIOs also lets us
   * support active-high chipselects despite the controller's belief that
   * only active-low devices/systems exists.
   *
   * However, at91rm9200 has a second erratum whereby nCS0 doesn't work
   * right when driven with GPIO.  ("Mode Fault does not allow more than one
   * Master on Chip Select 0.")  No workaround exists for that ... so for
   * nCS0 on that chip, we (a) don't use the GPIO, (b) can't support CS_HIGH,
   * and (c) will trigger that first erratum in some cases.
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
341
   */
defbd3b4b   David Brownell   atmel_spi: don't ...
342
  static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
343
  {
5ee36c989   Haavard Skinnemoen   spi: atmel_spi up...
344
  	struct atmel_spi_device *asd = spi->controller_state;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
345
  	unsigned active = spi->mode & SPI_CS_HIGH;
defbd3b4b   David Brownell   atmel_spi: don't ...
346
  	u32 mr;
d4820b749   Wenyou Yang   spi/spi-atmel: de...
347
  	if (atmel_spi_is_v2(as)) {
97ed465b4   Wenyou Yang   spi/spi-atmel: ad...
348
349
350
  		spi_writel(as, CSR0 + 4 * spi->chip_select, asd->csr);
  		/* For the low SPI version, there is a issue that PDC transfer
  		 * on CS1,2,3 needs SPI_CSR0.BITS config as SPI_CSR1,2,3.BITS
5ee36c989   Haavard Skinnemoen   spi: atmel_spi up...
351
352
  		 */
  		spi_writel(as, CSR0, asd->csr);
d4820b749   Wenyou Yang   spi/spi-atmel: de...
353
  		if (as->caps.has_wdrbt) {
97ed465b4   Wenyou Yang   spi/spi-atmel: ad...
354
355
356
357
358
  			spi_writel(as, MR,
  					SPI_BF(PCS, ~(0x01 << spi->chip_select))
  					| SPI_BIT(WDRBT)
  					| SPI_BIT(MODFDIS)
  					| SPI_BIT(MSTR));
d4820b749   Wenyou Yang   spi/spi-atmel: de...
359
  		} else {
97ed465b4   Wenyou Yang   spi/spi-atmel: ad...
360
361
362
363
  			spi_writel(as, MR,
  					SPI_BF(PCS, ~(0x01 << spi->chip_select))
  					| SPI_BIT(MODFDIS)
  					| SPI_BIT(MSTR));
d4820b749   Wenyou Yang   spi/spi-atmel: de...
364
  		}
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
365

5ee36c989   Haavard Skinnemoen   spi: atmel_spi up...
366
  		mr = spi_readl(as, MR);
482030348   Cyrille Pitchen   spi: atmel: add s...
367
368
  		if (as->use_cs_gpios)
  			gpio_set_value(asd->npcs_pin, active);
5ee36c989   Haavard Skinnemoen   spi: atmel_spi up...
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
  	} else {
  		u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0;
  		int i;
  		u32 csr;
  
  		/* Make sure clock polarity is correct */
  		for (i = 0; i < spi->master->num_chipselect; i++) {
  			csr = spi_readl(as, CSR0 + 4 * i);
  			if ((csr ^ cpol) & SPI_BIT(CPOL))
  				spi_writel(as, CSR0 + 4 * i,
  						csr ^ SPI_BIT(CPOL));
  		}
  
  		mr = spi_readl(as, MR);
  		mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr);
482030348   Cyrille Pitchen   spi: atmel: add s...
384
  		if (as->use_cs_gpios && spi->chip_select != 0)
5ee36c989   Haavard Skinnemoen   spi: atmel_spi up...
385
386
387
  			gpio_set_value(asd->npcs_pin, active);
  		spi_writel(as, MR, mr);
  	}
defbd3b4b   David Brownell   atmel_spi: don't ...
388
389
390
  
  	dev_dbg(&spi->dev, "activate %u%s, mr %08x
  ",
5ee36c989   Haavard Skinnemoen   spi: atmel_spi up...
391
  			asd->npcs_pin, active ? " (high)" : "",
defbd3b4b   David Brownell   atmel_spi: don't ...
392
  			mr);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
393
  }
defbd3b4b   David Brownell   atmel_spi: don't ...
394
  static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
395
  {
5ee36c989   Haavard Skinnemoen   spi: atmel_spi up...
396
  	struct atmel_spi_device *asd = spi->controller_state;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
397
  	unsigned active = spi->mode & SPI_CS_HIGH;
defbd3b4b   David Brownell   atmel_spi: don't ...
398
399
400
401
402
403
404
405
406
407
  	u32 mr;
  
  	/* only deactivate *this* device; sometimes transfers to
  	 * another device may be active when this routine is called.
  	 */
  	mr = spi_readl(as, MR);
  	if (~SPI_BFEXT(PCS, mr) & (1 << spi->chip_select)) {
  		mr = SPI_BFINS(PCS, 0xf, mr);
  		spi_writel(as, MR, mr);
  	}
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
408

defbd3b4b   David Brownell   atmel_spi: don't ...
409
410
  	dev_dbg(&spi->dev, "DEactivate %u%s, mr %08x
  ",
5ee36c989   Haavard Skinnemoen   spi: atmel_spi up...
411
  			asd->npcs_pin, active ? " (low)" : "",
defbd3b4b   David Brownell   atmel_spi: don't ...
412
  			mr);
482030348   Cyrille Pitchen   spi: atmel: add s...
413
414
415
  	if (!as->use_cs_gpios)
  		spi_writel(as, CR, SPI_BIT(LASTXFER));
  	else if (atmel_spi_is_v2(as) || spi->chip_select != 0)
5ee36c989   Haavard Skinnemoen   spi: atmel_spi up...
416
  		gpio_set_value(asd->npcs_pin, !active);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
417
  }
6c07ef298   Mark Brown   spi/atmel: Annota...
418
  static void atmel_spi_lock(struct atmel_spi *as) __acquires(&as->lock)
8aad7924b   Nicolas Ferre   spi/spi-atmel: ad...
419
420
421
  {
  	spin_lock_irqsave(&as->lock, as->flags);
  }
6c07ef298   Mark Brown   spi/atmel: Annota...
422
  static void atmel_spi_unlock(struct atmel_spi *as) __releases(&as->lock)
8aad7924b   Nicolas Ferre   spi/spi-atmel: ad...
423
424
425
  {
  	spin_unlock_irqrestore(&as->lock, as->flags);
  }
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
426
427
428
429
430
  static inline bool atmel_spi_use_dma(struct atmel_spi *as,
  				struct spi_transfer *xfer)
  {
  	return as->use_dma && xfer->len >= DMA_MIN_BYTES;
  }
04242ca4e   Cyrille Pitchen   spi: atmel: Use S...
431
432
433
434
435
436
437
438
  static bool atmel_spi_can_dma(struct spi_master *master,
  			      struct spi_device *spi,
  			      struct spi_transfer *xfer)
  {
  	struct atmel_spi *as = spi_master_get_devdata(master);
  
  	return atmel_spi_use_dma(as, xfer);
  }
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
439
440
441
442
  static int atmel_spi_dma_slave_config(struct atmel_spi *as,
  				struct dma_slave_config *slave_config,
  				u8 bits_per_word)
  {
768f3d9d8   Nicolas Ferre   spi: atmel: remov...
443
  	struct spi_master *master = platform_get_drvdata(as->pdev);
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
  	int err = 0;
  
  	if (bits_per_word > 8) {
  		slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
  		slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
  	} else {
  		slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
  		slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
  	}
  
  	slave_config->dst_addr = (dma_addr_t)as->phybase + SPI_TDR;
  	slave_config->src_addr = (dma_addr_t)as->phybase + SPI_RDR;
  	slave_config->src_maxburst = 1;
  	slave_config->dst_maxburst = 1;
  	slave_config->device_fc = false;
11f2764fe   Cyrille Pitchen   spi: atmel: add s...
459
460
461
462
463
464
465
466
467
468
469
470
471
472
  	/*
  	 * This driver uses fixed peripheral select mode (PS bit set to '0' in
  	 * the Mode Register).
  	 * So according to the datasheet, when FIFOs are available (and
  	 * enabled), the Transmit FIFO operates in Multiple Data Mode.
  	 * In this mode, up to 2 data, not 4, can be written into the Transmit
  	 * Data Register in a single access.
  	 * However, the first data has to be written into the lowest 16 bits and
  	 * the second data into the highest 16 bits of the Transmit
  	 * Data Register. For 8bit data (the most frequent case), it would
  	 * require to rework tx_buf so each data would actualy fit 16 bits.
  	 * So we'd rather write only one data at the time. Hence the transmit
  	 * path works the same whether FIFOs are available (and enabled) or not.
  	 */
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
473
  	slave_config->direction = DMA_MEM_TO_DEV;
768f3d9d8   Nicolas Ferre   spi: atmel: remov...
474
  	if (dmaengine_slave_config(master->dma_tx, slave_config)) {
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
475
476
477
478
479
  		dev_err(&as->pdev->dev,
  			"failed to configure tx dma channel
  ");
  		err = -EINVAL;
  	}
11f2764fe   Cyrille Pitchen   spi: atmel: add s...
480
481
482
483
484
485
486
487
  	/*
  	 * This driver configures the spi controller for master mode (MSTR bit
  	 * set to '1' in the Mode Register).
  	 * So according to the datasheet, when FIFOs are available (and
  	 * enabled), the Receive FIFO operates in Single Data Mode.
  	 * So the receive path works the same whether FIFOs are available (and
  	 * enabled) or not.
  	 */
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
488
  	slave_config->direction = DMA_DEV_TO_MEM;
768f3d9d8   Nicolas Ferre   spi: atmel: remov...
489
  	if (dmaengine_slave_config(master->dma_rx, slave_config)) {
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
490
491
492
493
494
495
496
497
  		dev_err(&as->pdev->dev,
  			"failed to configure rx dma channel
  ");
  		err = -EINVAL;
  	}
  
  	return err;
  }
768f3d9d8   Nicolas Ferre   spi: atmel: remov...
498
499
  static int atmel_spi_configure_dma(struct spi_master *master,
  				   struct atmel_spi *as)
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
500
  {
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
501
  	struct dma_slave_config	slave_config;
2f767a9f6   Richard Genoud   spi: atmel: conve...
502
  	struct device *dev = &as->pdev->dev;
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
503
  	int err;
2f767a9f6   Richard Genoud   spi: atmel: conve...
504
505
506
  	dma_cap_mask_t mask;
  	dma_cap_zero(mask);
  	dma_cap_set(DMA_SLAVE, mask);
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
507

768f3d9d8   Nicolas Ferre   spi: atmel: remov...
508
509
510
  	master->dma_tx = dma_request_slave_channel_reason(dev, "tx");
  	if (IS_ERR(master->dma_tx)) {
  		err = PTR_ERR(master->dma_tx);
5e9af37e4   Ludovic Desroches   spi: atmel: intro...
511
512
513
  		if (err == -EPROBE_DEFER) {
  			dev_warn(dev, "no DMA channel available at the moment
  ");
768f3d9d8   Nicolas Ferre   spi: atmel: remov...
514
  			goto error_clear;
5e9af37e4   Ludovic Desroches   spi: atmel: intro...
515
  		}
2f767a9f6   Richard Genoud   spi: atmel: conve...
516
517
518
519
  		dev_err(dev,
  			"DMA TX channel not available, SPI unable to use DMA
  ");
  		err = -EBUSY;
768f3d9d8   Nicolas Ferre   spi: atmel: remov...
520
  		goto error_clear;
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
521
  	}
2f767a9f6   Richard Genoud   spi: atmel: conve...
522

5e9af37e4   Ludovic Desroches   spi: atmel: intro...
523
524
525
526
  	/*
  	 * No reason to check EPROBE_DEFER here since we have already requested
  	 * tx channel. If it fails here, it's for another reason.
  	 */
768f3d9d8   Nicolas Ferre   spi: atmel: remov...
527
  	master->dma_rx = dma_request_slave_channel(dev, "rx");
2f767a9f6   Richard Genoud   spi: atmel: conve...
528

768f3d9d8   Nicolas Ferre   spi: atmel: remov...
529
  	if (!master->dma_rx) {
2f767a9f6   Richard Genoud   spi: atmel: conve...
530
531
532
  		dev_err(dev,
  			"DMA RX channel not available, SPI unable to use DMA
  ");
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
533
534
535
536
537
538
539
540
541
542
543
  		err = -EBUSY;
  		goto error;
  	}
  
  	err = atmel_spi_dma_slave_config(as, &slave_config, 8);
  	if (err)
  		goto error;
  
  	dev_info(&as->pdev->dev,
  			"Using %s (tx) and %s (rx) for DMA transfers
  ",
768f3d9d8   Nicolas Ferre   spi: atmel: remov...
544
545
  			dma_chan_name(master->dma_tx),
  			dma_chan_name(master->dma_rx));
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
546
547
  	return 0;
  error:
768f3d9d8   Nicolas Ferre   spi: atmel: remov...
548
549
550
551
552
553
  	if (master->dma_rx)
  		dma_release_channel(master->dma_rx);
  	if (!IS_ERR(master->dma_tx))
  		dma_release_channel(master->dma_tx);
  error_clear:
  	master->dma_tx = master->dma_rx = NULL;
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
554
555
  	return err;
  }
768f3d9d8   Nicolas Ferre   spi: atmel: remov...
556
  static void atmel_spi_stop_dma(struct spi_master *master)
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
557
  {
768f3d9d8   Nicolas Ferre   spi: atmel: remov...
558
559
560
561
  	if (master->dma_rx)
  		dmaengine_terminate_all(master->dma_rx);
  	if (master->dma_tx)
  		dmaengine_terminate_all(master->dma_tx);
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
562
  }
768f3d9d8   Nicolas Ferre   spi: atmel: remov...
563
  static void atmel_spi_release_dma(struct spi_master *master)
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
564
  {
768f3d9d8   Nicolas Ferre   spi: atmel: remov...
565
566
567
568
569
570
571
572
  	if (master->dma_rx) {
  		dma_release_channel(master->dma_rx);
  		master->dma_rx = NULL;
  	}
  	if (master->dma_tx) {
  		dma_release_channel(master->dma_tx);
  		master->dma_tx = NULL;
  	}
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
573
574
575
576
577
578
579
  }
  
  /* This function is called by the DMA driver from tasklet context */
  static void dma_callback(void *data)
  {
  	struct spi_master	*master = data;
  	struct atmel_spi	*as = spi_master_get_devdata(master);
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
580
  	complete(&as->xfer_completion);
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
581
582
583
  }
  
  /*
11f2764fe   Cyrille Pitchen   spi: atmel: add s...
584
   * Next transfer using PIO without FIFO.
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
585
   */
11f2764fe   Cyrille Pitchen   spi: atmel: add s...
586
587
  static void atmel_spi_next_xfer_single(struct spi_master *master,
  				       struct spi_transfer *xfer)
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
588
589
  {
  	struct atmel_spi	*as = spi_master_get_devdata(master);
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
590
  	unsigned long xfer_pos = xfer->len - as->current_remaining_bytes;
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
591
592
593
  
  	dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_pio
  ");
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
594
595
596
597
598
599
  	/* Make sure data is not remaining in RDR */
  	spi_readl(as, RDR);
  	while (spi_readl(as, SR) & SPI_BIT(RDRF)) {
  		spi_readl(as, RDR);
  		cpu_relax();
  	}
7910d9af0   Nicolas Ferre   spi: atmel: Use c...
600
601
602
603
  	if (xfer->bits_per_word > 8)
  		spi_writel(as, TDR, *(u16 *)(xfer->tx_buf + xfer_pos));
  	else
  		spi_writel(as, TDR, *(u8 *)(xfer->tx_buf + xfer_pos));
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
604
605
  
  	dev_dbg(master->dev.parent,
f557c98b1   Richard Genoud   spi/spi-atmel: BU...
606
607
608
609
  		"  start pio xfer %p: len %u tx %p rx %p bitpw %d
  ",
  		xfer, xfer->len, xfer->tx_buf, xfer->rx_buf,
  		xfer->bits_per_word);
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
610
611
612
613
614
615
  
  	/* Enable relevant interrupts */
  	spi_writel(as, IER, SPI_BIT(RDRF) | SPI_BIT(OVRES));
  }
  
  /*
11f2764fe   Cyrille Pitchen   spi: atmel: add s...
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
   * Next transfer using PIO with FIFO.
   */
  static void atmel_spi_next_xfer_fifo(struct spi_master *master,
  				     struct spi_transfer *xfer)
  {
  	struct atmel_spi *as = spi_master_get_devdata(master);
  	u32 current_remaining_data, num_data;
  	u32 offset = xfer->len - as->current_remaining_bytes;
  	const u16 *words = (const u16 *)((u8 *)xfer->tx_buf + offset);
  	const u8  *bytes = (const u8  *)((u8 *)xfer->tx_buf + offset);
  	u16 td0, td1;
  	u32 fifomr;
  
  	dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_fifo
  ");
  
  	/* Compute the number of data to transfer in the current iteration */
  	current_remaining_data = ((xfer->bits_per_word > 8) ?
  				  ((u32)as->current_remaining_bytes >> 1) :
  				  (u32)as->current_remaining_bytes);
  	num_data = min(current_remaining_data, as->fifo_size);
  
  	/* Flush RX and TX FIFOs */
  	spi_writel(as, CR, SPI_BIT(RXFCLR) | SPI_BIT(TXFCLR));
  	while (spi_readl(as, FLR))
  		cpu_relax();
  
  	/* Set RX FIFO Threshold to the number of data to transfer */
  	fifomr = spi_readl(as, FMR);
  	spi_writel(as, FMR, SPI_BFINS(RXFTHRES, num_data, fifomr));
  
  	/* Clear FIFO flags in the Status Register, especially RXFTHF */
  	(void)spi_readl(as, SR);
  
  	/* Fill TX FIFO */
  	while (num_data >= 2) {
7910d9af0   Nicolas Ferre   spi: atmel: Use c...
652
653
654
  		if (xfer->bits_per_word > 8) {
  			td0 = *words++;
  			td1 = *words++;
11f2764fe   Cyrille Pitchen   spi: atmel: add s...
655
  		} else {
7910d9af0   Nicolas Ferre   spi: atmel: Use c...
656
657
  			td0 = *bytes++;
  			td1 = *bytes++;
11f2764fe   Cyrille Pitchen   spi: atmel: add s...
658
659
660
661
662
663
664
  		}
  
  		spi_writel(as, TDR, (td1 << 16) | td0);
  		num_data -= 2;
  	}
  
  	if (num_data) {
7910d9af0   Nicolas Ferre   spi: atmel: Use c...
665
666
667
668
  		if (xfer->bits_per_word > 8)
  			td0 = *words++;
  		else
  			td0 = *bytes++;
11f2764fe   Cyrille Pitchen   spi: atmel: add s...
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
  
  		spi_writew(as, TDR, td0);
  		num_data--;
  	}
  
  	dev_dbg(master->dev.parent,
  		"  start fifo xfer %p: len %u tx %p rx %p bitpw %d
  ",
  		xfer, xfer->len, xfer->tx_buf, xfer->rx_buf,
  		xfer->bits_per_word);
  
  	/*
  	 * Enable RX FIFO Threshold Flag interrupt to be notified about
  	 * transfer completion.
  	 */
  	spi_writel(as, IER, SPI_BIT(RXFTHF) | SPI_BIT(OVRES));
  }
  
  /*
   * Next transfer using PIO.
   */
  static void atmel_spi_next_xfer_pio(struct spi_master *master,
  				    struct spi_transfer *xfer)
  {
  	struct atmel_spi *as = spi_master_get_devdata(master);
  
  	if (as->fifo_size)
  		atmel_spi_next_xfer_fifo(master, xfer);
  	else
  		atmel_spi_next_xfer_single(master, xfer);
  }
  
  /*
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
702
   * Submit next transfer for DMA.
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
703
704
705
706
707
708
   */
  static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,
  				struct spi_transfer *xfer,
  				u32 *plen)
  {
  	struct atmel_spi	*as = spi_master_get_devdata(master);
768f3d9d8   Nicolas Ferre   spi: atmel: remov...
709
710
  	struct dma_chan		*rxchan = master->dma_rx;
  	struct dma_chan		*txchan = master->dma_tx;
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
711
712
713
714
  	struct dma_async_tx_descriptor *rxdesc;
  	struct dma_async_tx_descriptor *txdesc;
  	struct dma_slave_config	slave_config;
  	dma_cookie_t		cookie;
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
715
716
717
718
719
720
721
722
723
724
  
  	dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_dma_submit
  ");
  
  	/* Check that the channels are available */
  	if (!rxchan || !txchan)
  		return -ENODEV;
  
  	/* release lock for DMA operations */
  	atmel_spi_unlock(as);
04242ca4e   Cyrille Pitchen   spi: atmel: Use S...
725
  	*plen = xfer->len;
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
726

06515f839   David Mosberger-Tang   spi: atmel: Fix D...
727
728
  	if (atmel_spi_dma_slave_config(as, &slave_config,
  				       xfer->bits_per_word))
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
729
730
731
  		goto err_exit;
  
  	/* Send both scatterlists */
04242ca4e   Cyrille Pitchen   spi: atmel: Use S...
732
733
  	rxdesc = dmaengine_prep_slave_sg(rxchan,
  					 xfer->rx_sg.sgl, xfer->rx_sg.nents,
ef40eb39e   Geert Uytterhoeven   spi: atmel: Use d...
734
735
  					 DMA_FROM_DEVICE,
  					 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
736
737
  	if (!rxdesc)
  		goto err_dma;
04242ca4e   Cyrille Pitchen   spi: atmel: Use S...
738
739
  	txdesc = dmaengine_prep_slave_sg(txchan,
  					 xfer->tx_sg.sgl, xfer->tx_sg.nents,
ef40eb39e   Geert Uytterhoeven   spi: atmel: Use d...
740
741
  					 DMA_TO_DEVICE,
  					 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
742
743
744
745
  	if (!txdesc)
  		goto err_dma;
  
  	dev_dbg(master->dev.parent,
2de024b76   Emil Goode   spi/atmel: Fix fo...
746
747
748
749
  		"  start dma xfer %p: len %u tx %p/%08llx rx %p/%08llx
  ",
  		xfer, xfer->len, xfer->tx_buf, (unsigned long long)xfer->tx_dma,
  		xfer->rx_buf, (unsigned long long)xfer->rx_dma);
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
  
  	/* Enable relevant interrupts */
  	spi_writel(as, IER, SPI_BIT(OVRES));
  
  	/* Put the callback on the RX transfer only, that should finish last */
  	rxdesc->callback = dma_callback;
  	rxdesc->callback_param = master;
  
  	/* Submit and fire RX and TX with TX last so we're ready to read! */
  	cookie = rxdesc->tx_submit(rxdesc);
  	if (dma_submit_error(cookie))
  		goto err_dma;
  	cookie = txdesc->tx_submit(txdesc);
  	if (dma_submit_error(cookie))
  		goto err_dma;
  	rxchan->device->device_issue_pending(rxchan);
  	txchan->device->device_issue_pending(txchan);
  
  	/* take back lock */
  	atmel_spi_lock(as);
  	return 0;
  
  err_dma:
  	spi_writel(as, IDR, SPI_BIT(OVRES));
768f3d9d8   Nicolas Ferre   spi: atmel: remov...
774
  	atmel_spi_stop_dma(master);
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
775
776
777
778
  err_exit:
  	atmel_spi_lock(as);
  	return -ENOMEM;
  }
154443c72   Silvester Erdeg   atmel_spi: chain ...
779
780
781
782
783
784
  static void atmel_spi_next_xfer_data(struct spi_master *master,
  				struct spi_transfer *xfer,
  				dma_addr_t *tx_dma,
  				dma_addr_t *rx_dma,
  				u32 *plen)
  {
7910d9af0   Nicolas Ferre   spi: atmel: Use c...
785
786
  	*rx_dma = xfer->rx_dma + xfer->len - *plen;
  	*tx_dma = xfer->tx_dma + xfer->len - *plen;
04242ca4e   Cyrille Pitchen   spi: atmel: Use S...
787
788
  	if (*plen > master->max_dma_len)
  		*plen = master->max_dma_len;
154443c72   Silvester Erdeg   atmel_spi: chain ...
789
  }
d3b72c7e6   Richard Genoud   spi: atmel: add s...
790
791
792
793
794
795
796
797
  static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
  				    struct spi_device *spi,
  				    struct spi_transfer *xfer)
  {
  	u32			scbr, csr;
  	unsigned long		bus_hz;
  
  	/* v1 chips start out at half the peripheral bus speed. */
39fe33f98   Ben Whitten   spi: atmel: Fix s...
798
  	bus_hz = as->spi_clk;
d3b72c7e6   Richard Genoud   spi: atmel: add s...
799
800
801
802
803
804
805
  	if (!atmel_spi_is_v2(as))
  		bus_hz /= 2;
  
  	/*
  	 * Calculate the lowest divider that satisfies the
  	 * constraint, assuming div32/fdiv/mbz == 0.
  	 */
e8646580c   Jarkko Nikula   spi: atmel: Remov...
806
  	scbr = DIV_ROUND_UP(bus_hz, xfer->speed_hz);
d3b72c7e6   Richard Genoud   spi: atmel: add s...
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
  
  	/*
  	 * If the resulting divider doesn't fit into the
  	 * register bitfield, we can't satisfy the constraint.
  	 */
  	if (scbr >= (1 << SPI_SCBR_SIZE)) {
  		dev_err(&spi->dev,
  			"setup: %d Hz too slow, scbr %u; min %ld Hz
  ",
  			xfer->speed_hz, scbr, bus_hz/255);
  		return -EINVAL;
  	}
  	if (scbr == 0) {
  		dev_err(&spi->dev,
  			"setup: %d Hz too high, scbr %u; max %ld Hz
  ",
  			xfer->speed_hz, scbr, bus_hz);
  		return -EINVAL;
  	}
  	csr = spi_readl(as, CSR0 + 4 * spi->chip_select);
  	csr = SPI_BFINS(SCBR, scbr, csr);
  	spi_writel(as, CSR0 + 4 * spi->chip_select, csr);
  
  	return 0;
  }
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
832
  /*
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
833
   * Submit next transfer for PDC.
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
834
835
   * lock is held, spi irq is blocked
   */
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
836
  static void atmel_spi_pdc_next_xfer(struct spi_master *master,
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
837
838
  					struct spi_message *msg,
  					struct spi_transfer *xfer)
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
839
840
  {
  	struct atmel_spi	*as = spi_master_get_devdata(master);
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
841
  	u32			len;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
842
  	dma_addr_t		tx_dma, rx_dma;
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
843
  	spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
844

8090d6d1a   Wenyou Yang   spi: atmel: Refac...
845
846
847
  	len = as->current_remaining_bytes;
  	atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
  	as->current_remaining_bytes -= len;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
848

8090d6d1a   Wenyou Yang   spi: atmel: Refac...
849
850
  	spi_writel(as, RPR, rx_dma);
  	spi_writel(as, TPR, tx_dma);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
851

8090d6d1a   Wenyou Yang   spi: atmel: Refac...
852
853
854
855
  	if (msg->spi->bits_per_word > 8)
  		len >>= 1;
  	spi_writel(as, RCR, len);
  	spi_writel(as, TCR, len);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
856

8090d6d1a   Wenyou Yang   spi: atmel: Refac...
857
858
859
860
861
862
  	dev_dbg(&msg->spi->dev,
  		"  start xfer %p: len %u tx %p/%08llx rx %p/%08llx
  ",
  		xfer, xfer->len, xfer->tx_buf,
  		(unsigned long long)xfer->tx_dma, xfer->rx_buf,
  		(unsigned long long)xfer->rx_dma);
dc329442b   Gerard Kam   atmel_spi: fix ha...
863

8090d6d1a   Wenyou Yang   spi: atmel: Refac...
864
865
  	if (as->current_remaining_bytes) {
  		len = as->current_remaining_bytes;
154443c72   Silvester Erdeg   atmel_spi: chain ...
866
  		atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len);
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
867
  		as->current_remaining_bytes -= len;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
868

154443c72   Silvester Erdeg   atmel_spi: chain ...
869
870
  		spi_writel(as, RNPR, rx_dma);
  		spi_writel(as, TNPR, tx_dma);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
871

154443c72   Silvester Erdeg   atmel_spi: chain ...
872
873
874
875
  		if (msg->spi->bits_per_word > 8)
  			len >>= 1;
  		spi_writel(as, RNCR, len);
  		spi_writel(as, TNCR, len);
8bacb2190   Haavard Skinnemoen   atmel_spi: fix dm...
876
877
  
  		dev_dbg(&msg->spi->dev,
2de024b76   Emil Goode   spi/atmel: Fix fo...
878
879
880
881
882
  			"  next xfer %p: len %u tx %p/%08llx rx %p/%08llx
  ",
  			xfer, xfer->len, xfer->tx_buf,
  			(unsigned long long)xfer->tx_dma, xfer->rx_buf,
  			(unsigned long long)xfer->rx_dma);
154443c72   Silvester Erdeg   atmel_spi: chain ...
883
  	}
76e1d14b3   Torsten Fleischer   spi: atmel: Fix i...
884
  	/* REVISIT: We're waiting for RXBUFF before we start the next
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
885
  	 * transfer because we need to handle some difficult timing
76e1d14b3   Torsten Fleischer   spi: atmel: Fix i...
886
887
888
889
  	 * issues otherwise. If we wait for TXBUFE in one transfer and
  	 * then starts waiting for RXBUFF in the next, it's difficult
  	 * to tell the difference between the RXBUFF interrupt we're
  	 * actually waiting for and the RXBUFF interrupt of the
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
890
891
892
893
  	 * previous transfer.
  	 *
  	 * It should be doable, though. Just not now...
  	 */
76e1d14b3   Torsten Fleischer   spi: atmel: Fix i...
894
  	spi_writel(as, IER, SPI_BIT(RXBUFF) | SPI_BIT(OVRES));
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
895
896
  	spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));
  }
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
897
  /*
8da0859a2   David Brownell   atmel_spi: minor ...
898
899
   * For DMA, tx_buf/tx_dma have the same relationship as rx_buf/rx_dma:
   *  - The buffer is either valid for CPU access, else NULL
b595076a1   Uwe Kleine-König   tree-wide: fix co...
900
   *  - If the buffer is valid, so is its DMA address
8da0859a2   David Brownell   atmel_spi: minor ...
901
   *
b595076a1   Uwe Kleine-König   tree-wide: fix co...
902
   * This driver manages the dma address unless message->is_dma_mapped.
8da0859a2   David Brownell   atmel_spi: minor ...
903
904
   */
  static int
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
905
906
  atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer)
  {
8da0859a2   David Brownell   atmel_spi: minor ...
907
  	struct device	*dev = &as->pdev->dev;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
908
  	xfer->tx_dma = xfer->rx_dma = INVALID_DMA_ADDRESS;
8da0859a2   David Brownell   atmel_spi: minor ...
909
  	if (xfer->tx_buf) {
214b574ab   Jean-Christophe PLAGNIOL-VILLARD   atmel_spi: fix wa...
910
911
912
  		/* tx_buf is a const void* where we need a void * for the dma
  		 * mapping */
  		void *nonconst_tx = (void *)xfer->tx_buf;
8da0859a2   David Brownell   atmel_spi: minor ...
913
  		xfer->tx_dma = dma_map_single(dev,
214b574ab   Jean-Christophe PLAGNIOL-VILLARD   atmel_spi: fix wa...
914
  				nonconst_tx, xfer->len,
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
915
  				DMA_TO_DEVICE);
8d8bb39b9   FUJITA Tomonori   dma-mapping: add ...
916
  		if (dma_mapping_error(dev, xfer->tx_dma))
8da0859a2   David Brownell   atmel_spi: minor ...
917
918
919
920
  			return -ENOMEM;
  	}
  	if (xfer->rx_buf) {
  		xfer->rx_dma = dma_map_single(dev,
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
921
922
  				xfer->rx_buf, xfer->len,
  				DMA_FROM_DEVICE);
8d8bb39b9   FUJITA Tomonori   dma-mapping: add ...
923
  		if (dma_mapping_error(dev, xfer->rx_dma)) {
8da0859a2   David Brownell   atmel_spi: minor ...
924
925
926
927
928
929
930
931
  			if (xfer->tx_buf)
  				dma_unmap_single(dev,
  						xfer->tx_dma, xfer->len,
  						DMA_TO_DEVICE);
  			return -ENOMEM;
  		}
  	}
  	return 0;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
932
933
934
935
936
937
  }
  
  static void atmel_spi_dma_unmap_xfer(struct spi_master *master,
  				     struct spi_transfer *xfer)
  {
  	if (xfer->tx_dma != INVALID_DMA_ADDRESS)
49dce689a   Tony Jones   spi doesn't need ...
938
  		dma_unmap_single(master->dev.parent, xfer->tx_dma,
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
939
940
  				 xfer->len, DMA_TO_DEVICE);
  	if (xfer->rx_dma != INVALID_DMA_ADDRESS)
49dce689a   Tony Jones   spi doesn't need ...
941
  		dma_unmap_single(master->dev.parent, xfer->rx_dma,
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
942
943
  				 xfer->len, DMA_FROM_DEVICE);
  }
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
944
945
946
947
  static void atmel_spi_disable_pdc_transfer(struct atmel_spi *as)
  {
  	spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
  }
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
948
  static void
11f2764fe   Cyrille Pitchen   spi: atmel: add s...
949
  atmel_spi_pump_single_data(struct atmel_spi *as, struct spi_transfer *xfer)
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
950
  {
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
951
  	u8		*rxp;
f557c98b1   Richard Genoud   spi/spi-atmel: BU...
952
  	u16		*rxp16;
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
953
  	unsigned long	xfer_pos = xfer->len - as->current_remaining_bytes;
7910d9af0   Nicolas Ferre   spi: atmel: Use c...
954
955
956
  	if (xfer->bits_per_word > 8) {
  		rxp16 = (u16 *)(((u8 *)xfer->rx_buf) + xfer_pos);
  		*rxp16 = spi_readl(as, RDR);
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
957
  	} else {
7910d9af0   Nicolas Ferre   spi: atmel: Use c...
958
959
  		rxp = ((u8 *)xfer->rx_buf) + xfer_pos;
  		*rxp = spi_readl(as, RDR);
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
960
  	}
f557c98b1   Richard Genoud   spi/spi-atmel: BU...
961
  	if (xfer->bits_per_word > 8) {
b112f0585   Alexandre Belloni   spi: atmel: fix i...
962
963
964
  		if (as->current_remaining_bytes > 2)
  			as->current_remaining_bytes -= 2;
  		else
f557c98b1   Richard Genoud   spi/spi-atmel: BU...
965
966
967
968
  			as->current_remaining_bytes = 0;
  	} else {
  		as->current_remaining_bytes--;
  	}
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
969
  }
11f2764fe   Cyrille Pitchen   spi: atmel: add s...
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
  static void
  atmel_spi_pump_fifo_data(struct atmel_spi *as, struct spi_transfer *xfer)
  {
  	u32 fifolr = spi_readl(as, FLR);
  	u32 num_bytes, num_data = SPI_BFEXT(RXFL, fifolr);
  	u32 offset = xfer->len - as->current_remaining_bytes;
  	u16 *words = (u16 *)((u8 *)xfer->rx_buf + offset);
  	u8  *bytes = (u8  *)((u8 *)xfer->rx_buf + offset);
  	u16 rd; /* RD field is the lowest 16 bits of RDR */
  
  	/* Update the number of remaining bytes to transfer */
  	num_bytes = ((xfer->bits_per_word > 8) ?
  		     (num_data << 1) :
  		     num_data);
  
  	if (as->current_remaining_bytes > num_bytes)
  		as->current_remaining_bytes -= num_bytes;
  	else
  		as->current_remaining_bytes = 0;
  
  	/* Handle odd number of bytes when data are more than 8bit width */
  	if (xfer->bits_per_word > 8)
  		as->current_remaining_bytes &= ~0x1;
  
  	/* Read data */
  	while (num_data) {
  		rd = spi_readl(as, RDR);
7910d9af0   Nicolas Ferre   spi: atmel: Use c...
997
998
999
1000
  		if (xfer->bits_per_word > 8)
  			*words++ = rd;
  		else
  			*bytes++ = rd;
11f2764fe   Cyrille Pitchen   spi: atmel: add s...
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
  		num_data--;
  	}
  }
  
  /* Called from IRQ
   *
   * Must update "current_remaining_bytes" to keep track of data
   * to transfer.
   */
  static void
  atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer)
  {
  	if (as->fifo_size)
  		atmel_spi_pump_fifo_data(as, xfer);
  	else
  		atmel_spi_pump_single_data(as, xfer);
  }
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
1018
1019
1020
  /* Interrupt
   *
   * No need for locking in this Interrupt handler: done_status is the
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1021
   * only information modified.
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
   */
  static irqreturn_t
  atmel_spi_pio_interrupt(int irq, void *dev_id)
  {
  	struct spi_master	*master = dev_id;
  	struct atmel_spi	*as = spi_master_get_devdata(master);
  	u32			status, pending, imr;
  	struct spi_transfer	*xfer;
  	int			ret = IRQ_NONE;
  
  	imr = spi_readl(as, IMR);
  	status = spi_readl(as, SR);
  	pending = status & imr;
  
  	if (pending & SPI_BIT(OVRES)) {
  		ret = IRQ_HANDLED;
  		spi_writel(as, IDR, SPI_BIT(OVRES));
  		dev_warn(master->dev.parent, "overrun
  ");
  
  		/*
  		 * When we get an overrun, we disregard the current
  		 * transfer. Data will not be copied back from any
  		 * bounce buffer and msg->actual_len will not be
  		 * updated with the last xfer.
  		 *
  		 * We will also not process any remaning transfers in
  		 * the message.
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
1050
1051
1052
1053
1054
1055
  		 */
  		as->done_status = -EIO;
  		smp_wmb();
  
  		/* Clear any overrun happening while cleaning up */
  		spi_readl(as, SR);
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1056
  		complete(&as->xfer_completion);
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
1057

11f2764fe   Cyrille Pitchen   spi: atmel: add s...
1058
  	} else if (pending & (SPI_BIT(RDRF) | SPI_BIT(RXFTHF))) {
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
1059
1060
1061
1062
1063
1064
  		atmel_spi_lock(as);
  
  		if (as->current_remaining_bytes) {
  			ret = IRQ_HANDLED;
  			xfer = as->current_transfer;
  			atmel_spi_pump_pio_data(as, xfer);
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1065
  			if (!as->current_remaining_bytes)
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
1066
  				spi_writel(as, IDR, pending);
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1067
1068
  
  			complete(&as->xfer_completion);
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
  		}
  
  		atmel_spi_unlock(as);
  	} else {
  		WARN_ONCE(pending, "IRQ not handled, pending = %x
  ", pending);
  		ret = IRQ_HANDLED;
  		spi_writel(as, IDR, pending);
  	}
  
  	return ret;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1080
1081
1082
  }
  
  static irqreturn_t
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
1083
  atmel_spi_pdc_interrupt(int irq, void *dev_id)
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1084
1085
1086
  {
  	struct spi_master	*master = dev_id;
  	struct atmel_spi	*as = spi_master_get_devdata(master);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1087
1088
  	u32			status, pending, imr;
  	int			ret = IRQ_NONE;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1089
1090
1091
1092
1093
  	imr = spi_readl(as, IMR);
  	status = spi_readl(as, SR);
  	pending = status & imr;
  
  	if (pending & SPI_BIT(OVRES)) {
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1094
1095
  
  		ret = IRQ_HANDLED;
dc329442b   Gerard Kam   atmel_spi: fix ha...
1096
  		spi_writel(as, IDR, (SPI_BIT(RXBUFF) | SPI_BIT(ENDRX)
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1097
  				     | SPI_BIT(OVRES)));
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1098
1099
  		/* Clear any overrun happening while cleaning up */
  		spi_readl(as, SR);
823cd0454   Nicolas Ferre   spi/spi-atmel: st...
1100
  		as->done_status = -EIO;
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1101
1102
  
  		complete(&as->xfer_completion);
dc329442b   Gerard Kam   atmel_spi: fix ha...
1103
  	} else if (pending & (SPI_BIT(RXBUFF) | SPI_BIT(ENDRX))) {
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1104
1105
1106
  		ret = IRQ_HANDLED;
  
  		spi_writel(as, IDR, pending);
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1107
  		complete(&as->xfer_completion);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1108
  	}
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1109
1110
  	return ret;
  }
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1111
1112
1113
  static int atmel_spi_setup(struct spi_device *spi)
  {
  	struct atmel_spi	*as;
5ee36c989   Haavard Skinnemoen   spi: atmel_spi up...
1114
  	struct atmel_spi_device	*asd;
d3b72c7e6   Richard Genoud   spi: atmel: add s...
1115
  	u32			csr;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1116
  	unsigned int		bits = spi->bits_per_word;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1117
  	unsigned int		npcs_pin;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1118
1119
  
  	as = spi_master_get_devdata(spi->master);
defbd3b4b   David Brownell   atmel_spi: don't ...
1120
  	/* see notes above re chipselect */
d4820b749   Wenyou Yang   spi/spi-atmel: de...
1121
  	if (!atmel_spi_is_v2(as)
defbd3b4b   David Brownell   atmel_spi: don't ...
1122
1123
1124
1125
1126
1127
  			&& spi->chip_select == 0
  			&& (spi->mode & SPI_CS_HIGH)) {
  		dev_dbg(&spi->dev, "setup: can't be active-high
  ");
  		return -EINVAL;
  	}
d3b72c7e6   Richard Genoud   spi: atmel: add s...
1128
  	csr = SPI_BF(BITS, bits - 8);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1129
1130
1131
1132
  	if (spi->mode & SPI_CPOL)
  		csr |= SPI_BIT(CPOL);
  	if (!(spi->mode & SPI_CPHA))
  		csr |= SPI_BIT(NCPHA);
482030348   Cyrille Pitchen   spi: atmel: add s...
1133
1134
  	if (!as->use_cs_gpios)
  		csr |= SPI_BIT(CSAAT);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1135

1eed29df4   Haavard Skinnemoen   atmel_spi through...
1136
1137
1138
1139
1140
1141
1142
1143
  	/* DLYBS is mostly irrelevant since we manage chipselect using GPIOs.
  	 *
  	 * DLYBCT would add delays between words, slowing down transfers.
  	 * It could potentially be useful to cope with DMA bottlenecks, but
  	 * in those cases it's probably best to just use a lower bitrate.
  	 */
  	csr |= SPI_BF(DLYBS, 0);
  	csr |= SPI_BF(DLYBCT, 0);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1144
1145
  
  	/* chipselect must have been muxed as GPIO (e.g. in board setup) */
67f08d690   Mark Brown   spi/atmel: Fix po...
1146
  	npcs_pin = (unsigned long)spi->controller_data;
850a5b670   Jean-Christophe PLAGNIOL-VILLARD   spi/atmel: add DT...
1147

482030348   Cyrille Pitchen   spi: atmel: add s...
1148
1149
1150
  	if (!as->use_cs_gpios)
  		npcs_pin = spi->chip_select;
  	else if (gpio_is_valid(spi->cs_gpio))
850a5b670   Jean-Christophe PLAGNIOL-VILLARD   spi/atmel: add DT...
1151
  		npcs_pin = spi->cs_gpio;
5ee36c989   Haavard Skinnemoen   spi: atmel_spi up...
1152
1153
1154
1155
1156
  	asd = spi->controller_state;
  	if (!asd) {
  		asd = kzalloc(sizeof(struct atmel_spi_device), GFP_KERNEL);
  		if (!asd)
  			return -ENOMEM;
961062007   Nicolas Ferre   spi: atmel: use m...
1157
  		if (as->use_cs_gpios)
482030348   Cyrille Pitchen   spi: atmel: add s...
1158
1159
  			gpio_direction_output(npcs_pin,
  					      !(spi->mode & SPI_CS_HIGH));
5ee36c989   Haavard Skinnemoen   spi: atmel_spi up...
1160
1161
1162
  
  		asd->npcs_pin = npcs_pin;
  		spi->controller_state = asd;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1163
  	}
5ee36c989   Haavard Skinnemoen   spi: atmel_spi up...
1164
  	asd->csr = csr;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1165
  	dev_dbg(&spi->dev,
d3b72c7e6   Richard Genoud   spi: atmel: add s...
1166
1167
1168
  		"setup: bpw %u mode 0x%x -> csr%d %08x
  ",
  		bits, spi->mode, spi->chip_select, csr);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1169

d4820b749   Wenyou Yang   spi/spi-atmel: de...
1170
  	if (!atmel_spi_is_v2(as))
5ee36c989   Haavard Skinnemoen   spi: atmel_spi up...
1171
  		spi_writel(as, CSR0 + 4 * spi->chip_select, csr);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1172
1173
1174
  
  	return 0;
  }
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1175
1176
1177
  static int atmel_spi_one_transfer(struct spi_master *master,
  					struct spi_message *msg,
  					struct spi_transfer *xfer)
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1178
1179
  {
  	struct atmel_spi	*as;
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1180
  	struct spi_device	*spi = msg->spi;
b9d228f9e   Matthias Brugger   spi/atmel: let tr...
1181
  	u8			bits;
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1182
  	u32			len;
b9d228f9e   Matthias Brugger   spi/atmel: let tr...
1183
  	struct atmel_spi_device	*asd;
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1184
1185
  	int			timeout;
  	int			ret;
1369dea64   Nicholas Mc Guire   spi: atmel: clean...
1186
  	unsigned long		dma_timeout;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1187

8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1188
  	as = spi_master_get_devdata(master);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1189

8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1190
1191
1192
  	if (!(xfer->tx_buf || xfer->rx_buf) && xfer->len) {
  		dev_dbg(&spi->dev, "missing rx or tx buf
  ");
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1193
  		return -EINVAL;
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1194
  	}
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1195

e8646580c   Jarkko Nikula   spi: atmel: Remov...
1196
1197
1198
1199
  	asd = spi->controller_state;
  	bits = (asd->csr >> 4) & 0xf;
  	if (bits != xfer->bits_per_word - 8) {
  		dev_dbg(&spi->dev,
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1200
1201
  			"you can't yet change bits_per_word in transfers
  ");
e8646580c   Jarkko Nikula   spi: atmel: Remov...
1202
  		return -ENOPROTOOPT;
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1203
  	}
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1204

8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1205
1206
1207
1208
1209
  	/*
  	 * DMA map early, for performance (empties dcache ASAP) and
  	 * better fault reporting.
  	 */
  	if ((!msg->is_dma_mapped)
04242ca4e   Cyrille Pitchen   spi: atmel: Use S...
1210
  		&& as->use_pdc) {
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1211
1212
1213
1214
1215
  		if (atmel_spi_dma_map_xfer(as, xfer) < 0)
  			return -ENOMEM;
  	}
  
  	atmel_spi_set_xfer_speed(as, msg->spi, xfer);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1216

8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
  	as->done_status = 0;
  	as->current_transfer = xfer;
  	as->current_remaining_bytes = xfer->len;
  	while (as->current_remaining_bytes) {
  		reinit_completion(&as->xfer_completion);
  
  		if (as->use_pdc) {
  			atmel_spi_pdc_next_xfer(master, msg, xfer);
  		} else if (atmel_spi_use_dma(as, xfer)) {
  			len = as->current_remaining_bytes;
  			ret = atmel_spi_next_xfer_dma_submit(master,
  								xfer, &len);
  			if (ret) {
  				dev_err(&spi->dev,
  					"unable to use DMA, fallback to PIO
  ");
  				atmel_spi_next_xfer_pio(master, xfer);
  			} else {
  				as->current_remaining_bytes -= len;
0c3b97487   Axel Lin   spi: atmel: Make ...
1236
1237
  				if (as->current_remaining_bytes < 0)
  					as->current_remaining_bytes = 0;
b9d228f9e   Matthias Brugger   spi/atmel: let tr...
1238
  			}
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1239
1240
  		} else {
  			atmel_spi_next_xfer_pio(master, xfer);
b9d228f9e   Matthias Brugger   spi/atmel: let tr...
1241
  		}
1676014ef   Alexander Stein   spi: atmel: Fix s...
1242
1243
  		/* interrupts are disabled, so free the lock for schedule */
  		atmel_spi_unlock(as);
1369dea64   Nicholas Mc Guire   spi: atmel: clean...
1244
1245
  		dma_timeout = wait_for_completion_timeout(&as->xfer_completion,
  							  SPI_DMA_TIMEOUT);
1676014ef   Alexander Stein   spi: atmel: Fix s...
1246
  		atmel_spi_lock(as);
1369dea64   Nicholas Mc Guire   spi: atmel: clean...
1247
1248
1249
  		if (WARN_ON(dma_timeout == 0)) {
  			dev_err(&spi->dev, "spi transfer timeout
  ");
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1250
  			as->done_status = -EIO;
f557c98b1   Richard Genoud   spi/spi-atmel: BU...
1251
  		}
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
  		if (as->done_status)
  			break;
  	}
  
  	if (as->done_status) {
  		if (as->use_pdc) {
  			dev_warn(master->dev.parent,
  				"overrun (%u/%u remaining)
  ",
  				spi_readl(as, TCR), spi_readl(as, RCR));
  
  			/*
  			 * Clean up DMA registers and make sure the data
  			 * registers are empty.
  			 */
  			spi_writel(as, RNCR, 0);
  			spi_writel(as, TNCR, 0);
  			spi_writel(as, RCR, 0);
  			spi_writel(as, TCR, 0);
  			for (timeout = 1000; timeout; timeout--)
  				if (spi_readl(as, SR) & SPI_BIT(TXEMPTY))
  					break;
  			if (!timeout)
  				dev_warn(master->dev.parent,
  					 "timeout waiting for TXEMPTY");
  			while (spi_readl(as, SR) & SPI_BIT(RDRF))
  				spi_readl(as, RDR);
  
  			/* Clear any overrun happening while cleaning up */
  			spi_readl(as, SR);
  
  		} else if (atmel_spi_use_dma(as, xfer)) {
768f3d9d8   Nicolas Ferre   spi: atmel: remov...
1284
  			atmel_spi_stop_dma(master);
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1285
1286
1287
  		}
  
  		if (!msg->is_dma_mapped
04242ca4e   Cyrille Pitchen   spi: atmel: Use S...
1288
  			&& as->use_pdc)
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
  			atmel_spi_dma_unmap_xfer(master, xfer);
  
  		return 0;
  
  	} else {
  		/* only update length if no error */
  		msg->actual_length += xfer->len;
  	}
  
  	if (!msg->is_dma_mapped
04242ca4e   Cyrille Pitchen   spi: atmel: Use S...
1299
  		&& as->use_pdc)
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
  		atmel_spi_dma_unmap_xfer(master, xfer);
  
  	if (xfer->delay_usecs)
  		udelay(xfer->delay_usecs);
  
  	if (xfer->cs_change) {
  		if (list_is_last(&xfer->transfer_list,
  				 &msg->transfers)) {
  			as->keep_cs = true;
  		} else {
  			as->cs_active = !as->cs_active;
  			if (as->cs_active)
  				cs_activate(as, msg->spi);
  			else
  				cs_deactivate(as, msg->spi);
8da0859a2   David Brownell   atmel_spi: minor ...
1315
  		}
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1316
  	}
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
  	return 0;
  }
  
  static int atmel_spi_transfer_one_message(struct spi_master *master,
  						struct spi_message *msg)
  {
  	struct atmel_spi *as;
  	struct spi_transfer *xfer;
  	struct spi_device *spi = msg->spi;
  	int ret = 0;
  
  	as = spi_master_get_devdata(master);
  
  	dev_dbg(&spi->dev, "new message %p submitted for %s
  ",
  					msg, dev_name(&spi->dev));
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
  	atmel_spi_lock(as);
  	cs_activate(as, spi);
  
  	as->cs_active = true;
  	as->keep_cs = false;
  
  	msg->status = 0;
  	msg->actual_length = 0;
  
  	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
  		ret = atmel_spi_one_transfer(master, msg, xfer);
  		if (ret)
  			goto msg_done;
  	}
  
  	if (as->use_pdc)
  		atmel_spi_disable_pdc_transfer(as);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1350
  	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1351
  		dev_dbg(&spi->dev,
54f4c51cc   Randy Dunlap   spi: atmel: fix p...
1352
1353
  			"  xfer %p: len %u tx %p/%pad rx %p/%pad
  ",
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1354
  			xfer, xfer->len,
54f4c51cc   Randy Dunlap   spi: atmel: fix p...
1355
1356
  			xfer->tx_buf, &xfer->tx_dma,
  			xfer->rx_buf, &xfer->rx_dma);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1357
  	}
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1358
1359
1360
  msg_done:
  	if (!as->keep_cs)
  		cs_deactivate(as, msg->spi);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1361

8aad7924b   Nicolas Ferre   spi/spi-atmel: ad...
1362
  	atmel_spi_unlock(as);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1363

8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1364
1365
1366
1367
  	msg->status = as->done_status;
  	spi_finalize_current_message(spi->master);
  
  	return ret;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1368
  }
bb2d1c36c   David Brownell   [PATCH] SPI contr...
1369
  static void atmel_spi_cleanup(struct spi_device *spi)
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1370
  {
5ee36c989   Haavard Skinnemoen   spi: atmel_spi up...
1371
  	struct atmel_spi_device	*asd = spi->controller_state;
defbd3b4b   David Brownell   atmel_spi: don't ...
1372

5ee36c989   Haavard Skinnemoen   spi: atmel_spi up...
1373
  	if (!asd)
defbd3b4b   David Brownell   atmel_spi: don't ...
1374
  		return;
5ee36c989   Haavard Skinnemoen   spi: atmel_spi up...
1375
  	spi->controller_state = NULL;
5ee36c989   Haavard Skinnemoen   spi: atmel_spi up...
1376
  	kfree(asd);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1377
  }
d4820b749   Wenyou Yang   spi/spi-atmel: de...
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
  static inline unsigned int atmel_get_version(struct atmel_spi *as)
  {
  	return spi_readl(as, VERSION) & 0x00000fff;
  }
  
  static void atmel_get_caps(struct atmel_spi *as)
  {
  	unsigned int version;
  
  	version = atmel_get_version(as);
d4820b749   Wenyou Yang   spi/spi-atmel: de...
1388
1389
1390
  
  	as->caps.is_spi2 = version > 0x121;
  	as->caps.has_wdrbt = version >= 0x210;
7094576cc   Cyrille Pitchen   spi: atmel: fix c...
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
  #ifdef CONFIG_SOC_SAM_V4_V5
  	/*
  	 * Atmel SoCs based on ARM9 (SAM9x) cores should not use spi_map_buf()
  	 * since this later function tries to map buffers with dma_map_sg()
  	 * even if they have not been allocated inside DMA-safe areas.
  	 * On SoCs based on Cortex A5 (SAMA5Dx), it works anyway because for
  	 * those ARM cores, the data cache follows the PIPT model.
  	 * Also the L2 cache controller of SAMA5D2 uses the PIPT model too.
  	 * In case of PIPT caches, there cannot be cache aliases.
  	 * However on ARM9 cores, the data cache follows the VIVT model, hence
  	 * the cache aliases issue can occur when buffers are allocated from
  	 * DMA-unsafe areas, by vmalloc() for instance, where cache coherency is
  	 * not taken into account or at least not handled completely (cache
  	 * lines of aliases are not invalidated).
  	 * This is not a theorical issue: it was reproduced when trying to mount
  	 * a UBI file-system on a at91sam9g35ek board.
  	 */
  	as->caps.has_dma_support = false;
  #else
d4820b749   Wenyou Yang   spi/spi-atmel: de...
1410
  	as->caps.has_dma_support = version >= 0x212;
7094576cc   Cyrille Pitchen   spi: atmel: fix c...
1411
1412
  #endif
  	as->caps.has_pdc_support = version < 0x212;
d4820b749   Wenyou Yang   spi/spi-atmel: de...
1413
  }
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1414
  /*-------------------------------------------------------------------------*/
961062007   Nicolas Ferre   spi: atmel: use m...
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
  static int atmel_spi_gpio_cs(struct platform_device *pdev)
  {
  	struct spi_master	*master = platform_get_drvdata(pdev);
  	struct atmel_spi	*as = spi_master_get_devdata(master);
  	struct device_node	*np = master->dev.of_node;
  	int			i;
  	int			ret = 0;
  	int			nb = 0;
  
  	if (!as->use_cs_gpios)
  		return 0;
  
  	if (!np)
  		return 0;
  
  	nb = of_gpio_named_count(np, "cs-gpios");
  	for (i = 0; i < nb; i++) {
  		int cs_gpio = of_get_named_gpio(pdev->dev.of_node,
  						"cs-gpios", i);
b52b3484e   Dan Carpenter   spi: atmel: fix i...
1434
1435
  		if (cs_gpio == -EPROBE_DEFER)
  			return cs_gpio;
961062007   Nicolas Ferre   spi: atmel: use m...
1436

b52b3484e   Dan Carpenter   spi: atmel: fix i...
1437
1438
1439
1440
1441
1442
  		if (gpio_is_valid(cs_gpio)) {
  			ret = devm_gpio_request(&pdev->dev, cs_gpio,
  						dev_name(&pdev->dev));
  			if (ret)
  				return ret;
  		}
961062007   Nicolas Ferre   spi: atmel: use m...
1443
1444
1445
1446
  	}
  
  	return 0;
  }
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1447

05514c869   Quentin Schulz   spi: atmel: facto...
1448
1449
1450
1451
  static void atmel_spi_init(struct atmel_spi *as)
  {
  	spi_writel(as, CR, SPI_BIT(SWRST));
  	spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
faddb1768   Eugen Hristev   spi: atmel: init ...
1452
1453
1454
1455
  
  	/* It is recommended to enable FIFOs first thing after reset */
  	if (as->fifo_size)
  		spi_writel(as, CR, SPI_BIT(FIFOEN));
05514c869   Quentin Schulz   spi: atmel: facto...
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
  	if (as->caps.has_wdrbt) {
  		spi_writel(as, MR, SPI_BIT(WDRBT) | SPI_BIT(MODFDIS)
  				| SPI_BIT(MSTR));
  	} else {
  		spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS));
  	}
  
  	if (as->use_pdc)
  		spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
  	spi_writel(as, CR, SPI_BIT(SPIEN));
05514c869   Quentin Schulz   spi: atmel: facto...
1466
  }
fd4a319bc   Grant Likely   spi: Remove HOTPL...
1467
  static int atmel_spi_probe(struct platform_device *pdev)
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1468
1469
1470
1471
1472
1473
1474
  {
  	struct resource		*regs;
  	int			irq;
  	struct clk		*clk;
  	int			ret;
  	struct spi_master	*master;
  	struct atmel_spi	*as;
5bdfd491a   Wenyou Yang   spi: atmel: adopt...
1475
1476
  	/* Select default pin state */
  	pinctrl_pm_select_default_state(&pdev->dev);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1477
1478
1479
1480
1481
1482
1483
  	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	if (!regs)
  		return -ENXIO;
  
  	irq = platform_get_irq(pdev, 0);
  	if (irq < 0)
  		return irq;
9f87d6f26   Jingoo Han   spi: atmel: Use d...
1484
  	clk = devm_clk_get(&pdev->dev, "spi_clk");
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1485
1486
1487
1488
1489
  	if (IS_ERR(clk))
  		return PTR_ERR(clk);
  
  	/* setup spi core then atmel-specific driver state */
  	ret = -ENOMEM;
a536d7654   Sachin Kamat   spi: atmel: Silen...
1490
  	master = spi_alloc_master(&pdev->dev, sizeof(*as));
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1491
1492
  	if (!master)
  		goto out_free;
e7db06b5d   David Brownell   spi: move more sp...
1493
1494
  	/* the spi->mode bits understood by this driver: */
  	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
24778be20   Stephen Warren   spi: convert driv...
1495
  	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16);
850a5b670   Jean-Christophe PLAGNIOL-VILLARD   spi/atmel: add DT...
1496
  	master->dev.of_node = pdev->dev.of_node;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1497
  	master->bus_num = pdev->id;
850a5b670   Jean-Christophe PLAGNIOL-VILLARD   spi/atmel: add DT...
1498
  	master->num_chipselect = master->dev.of_node ? 0 : 4;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1499
  	master->setup = atmel_spi_setup;
7910d9af0   Nicolas Ferre   spi: atmel: Use c...
1500
  	master->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX);
8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1501
  	master->transfer_one_message = atmel_spi_transfer_one_message;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1502
  	master->cleanup = atmel_spi_cleanup;
ce0c4caf2   Wenyou Yang   spi/atmel: add su...
1503
  	master->auto_runtime_pm = true;
7910d9af0   Nicolas Ferre   spi: atmel: Use c...
1504
  	master->max_dma_len = SPI_MAX_DMA_XFER;
04242ca4e   Cyrille Pitchen   spi: atmel: Use S...
1505
  	master->can_dma = atmel_spi_can_dma;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1506
1507
1508
  	platform_set_drvdata(pdev, master);
  
  	as = spi_master_get_devdata(master);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1509
  	spin_lock_init(&as->lock);
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
1510

754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1511
  	as->pdev = pdev;
31407478a   Mark Brown   spi/atmel: Conver...
1512
  	as->regs = devm_ioremap_resource(&pdev->dev, regs);
543c954d6   Wei Yongjun   spi: atmel: fix r...
1513
1514
  	if (IS_ERR(as->regs)) {
  		ret = PTR_ERR(as->regs);
7910d9af0   Nicolas Ferre   spi: atmel: Use c...
1515
  		goto out_unmap_regs;
543c954d6   Wei Yongjun   spi: atmel: fix r...
1516
  	}
dfab30ee6   Nicolas Ferre   spi/spi-atmel: ad...
1517
  	as->phybase = regs->start;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1518
1519
  	as->irq = irq;
  	as->clk = clk;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1520

8090d6d1a   Wenyou Yang   spi: atmel: Refac...
1521
  	init_completion(&as->xfer_completion);
d4820b749   Wenyou Yang   spi/spi-atmel: de...
1522
  	atmel_get_caps(as);
482030348   Cyrille Pitchen   spi: atmel: add s...
1523
1524
  	as->use_cs_gpios = true;
  	if (atmel_spi_is_v2(as) &&
70f340df2   Cyrille Pitchen   spi: atmel: fix g...
1525
  	    pdev->dev.of_node &&
482030348   Cyrille Pitchen   spi: atmel: add s...
1526
1527
1528
1529
  	    !of_get_property(pdev->dev.of_node, "cs-gpios", NULL)) {
  		as->use_cs_gpios = false;
  		master->num_chipselect = 4;
  	}
961062007   Nicolas Ferre   spi: atmel: use m...
1530
1531
1532
  	ret = atmel_spi_gpio_cs(pdev);
  	if (ret)
  		goto out_unmap_regs;
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
1533
1534
1535
  	as->use_dma = false;
  	as->use_pdc = false;
  	if (as->caps.has_dma_support) {
768f3d9d8   Nicolas Ferre   spi: atmel: remov...
1536
  		ret = atmel_spi_configure_dma(master, as);
04242ca4e   Cyrille Pitchen   spi: atmel: Use S...
1537
  		if (ret == 0) {
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
1538
  			as->use_dma = true;
04242ca4e   Cyrille Pitchen   spi: atmel: Use S...
1539
  		} else if (ret == -EPROBE_DEFER) {
5e9af37e4   Ludovic Desroches   spi: atmel: intro...
1540
  			return ret;
04242ca4e   Cyrille Pitchen   spi: atmel: Use S...
1541
  		}
7094576cc   Cyrille Pitchen   spi: atmel: fix c...
1542
  	} else if (as->caps.has_pdc_support) {
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
1543
1544
1545
1546
1547
1548
1549
1550
  		as->use_pdc = true;
  	}
  
  	if (as->caps.has_dma_support && !as->use_dma)
  		dev_info(&pdev->dev, "Atmel SPI Controller using PIO only
  ");
  
  	if (as->use_pdc) {
9f87d6f26   Jingoo Han   spi: atmel: Use d...
1551
1552
  		ret = devm_request_irq(&pdev->dev, irq, atmel_spi_pdc_interrupt,
  					0, dev_name(&pdev->dev), master);
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
1553
  	} else {
9f87d6f26   Jingoo Han   spi: atmel: Use d...
1554
1555
  		ret = devm_request_irq(&pdev->dev, irq, atmel_spi_pio_interrupt,
  					0, dev_name(&pdev->dev), master);
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
1556
  	}
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1557
1558
1559
1560
  	if (ret)
  		goto out_unmap_regs;
  
  	/* Initialize the hardware */
dfec4a6e4   Boris BREZILLON   spi: atmel: prepa...
1561
1562
  	ret = clk_prepare_enable(clk);
  	if (ret)
de8cc234a   Sachin Kamat   spi: atmel: Fix i...
1563
  		goto out_free_irq;
39fe33f98   Ben Whitten   spi: atmel: Fix s...
1564
1565
  
  	as->spi_clk = clk_get_rate(clk);
11f2764fe   Cyrille Pitchen   spi: atmel: add s...
1566
1567
1568
1569
1570
  	as->fifo_size = 0;
  	if (!of_property_read_u32(pdev->dev.of_node, "atmel,fifo-size",
  				  &as->fifo_size)) {
  		dev_info(&pdev->dev, "Using FIFO (%u data)
  ", as->fifo_size);
11f2764fe   Cyrille Pitchen   spi: atmel: add s...
1571
  	}
05514c869   Quentin Schulz   spi: atmel: facto...
1572
  	atmel_spi_init(as);
ce0c4caf2   Wenyou Yang   spi/atmel: add su...
1573
1574
1575
1576
  	pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT);
  	pm_runtime_use_autosuspend(&pdev->dev);
  	pm_runtime_set_active(&pdev->dev);
  	pm_runtime_enable(&pdev->dev);
9f87d6f26   Jingoo Han   spi: atmel: Use d...
1577
  	ret = devm_spi_register_master(&pdev->dev, master);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1578
  	if (ret)
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
1579
  		goto out_free_dma;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1580

ce24a513f   Nicolas Ferre   spi: atmel: trivi...
1581
  	/* go! */
6aba9c656   Baruch Siach   spi: atmel: print...
1582
1583
1584
1585
  	dev_info(&pdev->dev, "Atmel SPI Controller version 0x%x at 0x%08lx (irq %d)
  ",
  			atmel_get_version(as), (unsigned long)regs->start,
  			irq);
ce24a513f   Nicolas Ferre   spi: atmel: trivi...
1586

754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1587
  	return 0;
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
1588
  out_free_dma:
ce0c4caf2   Wenyou Yang   spi/atmel: add su...
1589
1590
  	pm_runtime_disable(&pdev->dev);
  	pm_runtime_set_suspended(&pdev->dev);
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
1591
  	if (as->use_dma)
768f3d9d8   Nicolas Ferre   spi: atmel: remov...
1592
  		atmel_spi_release_dma(master);
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
1593

754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1594
  	spi_writel(as, CR, SPI_BIT(SWRST));
50d7d5bf3   Jean-Christophe Lallemand   atmel_spi: work-a...
1595
  	spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
dfec4a6e4   Boris BREZILLON   spi: atmel: prepa...
1596
  	clk_disable_unprepare(clk);
de8cc234a   Sachin Kamat   spi: atmel: Fix i...
1597
  out_free_irq:
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1598
  out_unmap_regs:
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1599
  out_free:
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1600
1601
1602
  	spi_master_put(master);
  	return ret;
  }
fd4a319bc   Grant Likely   spi: Remove HOTPL...
1603
  static int atmel_spi_remove(struct platform_device *pdev)
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1604
1605
1606
  {
  	struct spi_master	*master = platform_get_drvdata(pdev);
  	struct atmel_spi	*as = spi_master_get_devdata(master);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1607

ce0c4caf2   Wenyou Yang   spi/atmel: add su...
1608
  	pm_runtime_get_sync(&pdev->dev);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1609
  	/* reset the hardware and block queue progress */
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
1610
  	if (as->use_dma) {
768f3d9d8   Nicolas Ferre   spi: atmel: remov...
1611
1612
  		atmel_spi_stop_dma(master);
  		atmel_spi_release_dma(master);
1ccc404a7   Nicolas Ferre   spi/spi-atmel: ad...
1613
  	}
3cf652bed   Radu Pirea   spi: atmel: fixed...
1614
  	spin_lock_irq(&as->lock);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1615
  	spi_writel(as, CR, SPI_BIT(SWRST));
50d7d5bf3   Jean-Christophe Lallemand   atmel_spi: work-a...
1616
  	spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1617
1618
  	spi_readl(as, SR);
  	spin_unlock_irq(&as->lock);
dfec4a6e4   Boris BREZILLON   spi: atmel: prepa...
1619
  	clk_disable_unprepare(as->clk);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1620

ce0c4caf2   Wenyou Yang   spi/atmel: add su...
1621
1622
  	pm_runtime_put_noidle(&pdev->dev);
  	pm_runtime_disable(&pdev->dev);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1623
1624
  	return 0;
  }
ce0c4caf2   Wenyou Yang   spi/atmel: add su...
1625
  #ifdef CONFIG_PM
c1ee8f3fd   Wenyou Yang   spi/atmel: improv...
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
  static int atmel_spi_runtime_suspend(struct device *dev)
  {
  	struct spi_master *master = dev_get_drvdata(dev);
  	struct atmel_spi *as = spi_master_get_devdata(master);
  
  	clk_disable_unprepare(as->clk);
  	pinctrl_pm_select_sleep_state(dev);
  
  	return 0;
  }
  
  static int atmel_spi_runtime_resume(struct device *dev)
  {
  	struct spi_master *master = dev_get_drvdata(dev);
  	struct atmel_spi *as = spi_master_get_devdata(master);
  
  	pinctrl_pm_select_default_state(dev);
  
  	return clk_prepare_enable(as->clk);
  }
d630526d0   Alexandre Belloni   spi: atmel: remov...
1646
  #ifdef CONFIG_PM_SLEEP
ec60dd37e   Jingoo Han   spi: atmel: conve...
1647
  static int atmel_spi_suspend(struct device *dev)
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1648
  {
c1ee8f3fd   Wenyou Yang   spi/atmel: improv...
1649
  	struct spi_master *master = dev_get_drvdata(dev);
ba938f3a2   Wenyou Yang   spi: atmel: add m...
1650
1651
1652
1653
1654
1655
1656
1657
1658
  	int ret;
  
  	/* Stop the queue running */
  	ret = spi_master_suspend(master);
  	if (ret) {
  		dev_warn(dev, "cannot suspend master
  ");
  		return ret;
  	}
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1659

c1ee8f3fd   Wenyou Yang   spi/atmel: improv...
1660
1661
  	if (!pm_runtime_suspended(dev))
  		atmel_spi_runtime_suspend(dev);
5bdfd491a   Wenyou Yang   spi: atmel: adopt...
1662

754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1663
1664
  	return 0;
  }
ec60dd37e   Jingoo Han   spi: atmel: conve...
1665
  static int atmel_spi_resume(struct device *dev)
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1666
  {
c1ee8f3fd   Wenyou Yang   spi/atmel: improv...
1667
  	struct spi_master *master = dev_get_drvdata(dev);
e53800787   Quentin Schulz   spi: atmel: add d...
1668
  	struct atmel_spi *as = spi_master_get_devdata(master);
ba938f3a2   Wenyou Yang   spi: atmel: add m...
1669
  	int ret;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1670

e53800787   Quentin Schulz   spi: atmel: add d...
1671
1672
1673
1674
1675
1676
1677
  	ret = clk_prepare_enable(as->clk);
  	if (ret)
  		return ret;
  
  	atmel_spi_init(as);
  
  	clk_disable_unprepare(as->clk);
ce0c4caf2   Wenyou Yang   spi/atmel: add su...
1678
  	if (!pm_runtime_suspended(dev)) {
c1ee8f3fd   Wenyou Yang   spi/atmel: improv...
1679
  		ret = atmel_spi_runtime_resume(dev);
ce0c4caf2   Wenyou Yang   spi/atmel: add su...
1680
1681
1682
  		if (ret)
  			return ret;
  	}
ba938f3a2   Wenyou Yang   spi: atmel: add m...
1683
1684
1685
1686
1687
1688
1689
1690
  
  	/* Start the queue running */
  	ret = spi_master_resume(master);
  	if (ret)
  		dev_err(dev, "problem starting queue (%d)
  ", ret);
  
  	return ret;
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1691
  }
d630526d0   Alexandre Belloni   spi: atmel: remov...
1692
  #endif
ce0c4caf2   Wenyou Yang   spi/atmel: add su...
1693
1694
1695
1696
1697
1698
  
  static const struct dev_pm_ops atmel_spi_pm_ops = {
  	SET_SYSTEM_SLEEP_PM_OPS(atmel_spi_suspend, atmel_spi_resume)
  	SET_RUNTIME_PM_OPS(atmel_spi_runtime_suspend,
  			   atmel_spi_runtime_resume, NULL)
  };
ec60dd37e   Jingoo Han   spi: atmel: conve...
1699
  #define ATMEL_SPI_PM_OPS	(&atmel_spi_pm_ops)
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1700
  #else
ec60dd37e   Jingoo Han   spi: atmel: conve...
1701
  #define ATMEL_SPI_PM_OPS	NULL
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1702
  #endif
850a5b670   Jean-Christophe PLAGNIOL-VILLARD   spi/atmel: add DT...
1703
1704
1705
1706
1707
1708
1709
1710
  #if defined(CONFIG_OF)
  static const struct of_device_id atmel_spi_dt_ids[] = {
  	{ .compatible = "atmel,at91rm9200-spi" },
  	{ /* sentinel */ }
  };
  
  MODULE_DEVICE_TABLE(of, atmel_spi_dt_ids);
  #endif
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1711
1712
1713
1714
  
  static struct platform_driver atmel_spi_driver = {
  	.driver		= {
  		.name	= "atmel_spi",
ec60dd37e   Jingoo Han   spi: atmel: conve...
1715
  		.pm	= ATMEL_SPI_PM_OPS,
850a5b670   Jean-Christophe PLAGNIOL-VILLARD   spi/atmel: add DT...
1716
  		.of_match_table	= of_match_ptr(atmel_spi_dt_ids),
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1717
  	},
1cb201af6   Jean-Christophe PLAGNIOL-VILLARD   atmel/spi: fix mi...
1718
  	.probe		= atmel_spi_probe,
2deff8d60   Grant Likely   spi: Remove erron...
1719
  	.remove		= atmel_spi_remove,
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1720
  };
940ab8896   Grant Likely   drivercore: Add h...
1721
  module_platform_driver(atmel_spi_driver);
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1722
1723
  
  MODULE_DESCRIPTION("Atmel AT32/AT91 SPI Controller driver");
e05503ef1   Jean Delvare   Haavard Skinnemoe...
1724
  MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
754ce4f29   Haavard Skinnemoen   [PATCH] SPI: atme...
1725
  MODULE_LICENSE("GPL");
7e38c3c44   Kay Sievers   spi: fix platform...
1726
  MODULE_ALIAS("platform:atmel_spi");